diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2014-09-30 13:18:30 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-10-29 05:51:40 -0400 |
commit | 33797820af98cde5c7cee00d00f0d8e255ea199f (patch) | |
tree | 2d85919e568b520986c52fed4af86d077f755bf9 /drivers/hid | |
parent | 925f0f3ed24f98b40c28627e74ff3e7f9d1e28bc (diff) |
HID: logitech: allow the DJ device to request the unifying name
The names of the DJ devices are stored in the receiver. These names
can be retrieved through a HID++ command. However, the protocol says
that you have to ask the receiver for that, not the device iteself.
Introduce a special case in the DJ handling where a device can request
its unifying name, and when such a name is given, forward it also to
the corresponding device.
On the HID++ side, the receiver talks only HID++ 1.0, so we need to
implement this part of the protocol in the module.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Tested-by: Andrew de los Reyes <adlr@chromium.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-logitech-dj.c | 24 | ||||
-rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 80 |
2 files changed, 97 insertions, 7 deletions
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index feddacd87b8b..9bc39421627f 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c | |||
@@ -667,6 +667,9 @@ static void logi_dj_ll_close(struct hid_device *hid) | |||
667 | dbg_hid("%s:%s\n", __func__, hid->phys); | 667 | dbg_hid("%s:%s\n", __func__, hid->phys); |
668 | } | 668 | } |
669 | 669 | ||
670 | static u8 unifying_name_query[] = {0x10, 0xff, 0x83, 0xb5, 0x40, 0x00, 0x00}; | ||
671 | static u8 unifying_name_answer[] = {0x11, 0xff, 0x83, 0xb5}; | ||
672 | |||
670 | static int logi_dj_ll_raw_request(struct hid_device *hid, | 673 | static int logi_dj_ll_raw_request(struct hid_device *hid, |
671 | unsigned char reportnum, __u8 *buf, | 674 | unsigned char reportnum, __u8 *buf, |
672 | size_t count, unsigned char report_type, | 675 | size_t count, unsigned char report_type, |
@@ -682,7 +685,13 @@ static int logi_dj_ll_raw_request(struct hid_device *hid, | |||
682 | if (count < 2) | 685 | if (count < 2) |
683 | return -EINVAL; | 686 | return -EINVAL; |
684 | 687 | ||
685 | buf[1] = djdev->device_index; | 688 | /* special case where we should not overwrite |
689 | * the device_index */ | ||
690 | if (count == 7 && !memcmp(buf, unifying_name_query, | ||
691 | sizeof(unifying_name_query))) | ||
692 | buf[4] |= djdev->device_index - 1; | ||
693 | else | ||
694 | buf[1] = djdev->device_index; | ||
686 | return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf, | 695 | return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf, |
687 | count, report_type, reqtype); | 696 | count, report_type, reqtype); |
688 | } | 697 | } |
@@ -873,8 +882,17 @@ static int logi_dj_hidpp_event(struct hid_device *hdev, | |||
873 | unsigned long flags; | 882 | unsigned long flags; |
874 | u8 device_index = dj_report->device_index; | 883 | u8 device_index = dj_report->device_index; |
875 | 884 | ||
876 | if (device_index == HIDPP_RECEIVER_INDEX) | 885 | if (device_index == HIDPP_RECEIVER_INDEX) { |
877 | return false; | 886 | /* special case were the device wants to know its unifying |
887 | * name */ | ||
888 | if (size == HIDPP_REPORT_LONG_LENGTH && | ||
889 | !memcmp(data, unifying_name_answer, | ||
890 | sizeof(unifying_name_answer)) && | ||
891 | ((data[4] & 0xF0) == 0x40)) | ||
892 | device_index = (data[4] & 0x0F) + 1; | ||
893 | else | ||
894 | return false; | ||
895 | } | ||
878 | 896 | ||
879 | /* | 897 | /* |
880 | * Data is from the HID++ collection, in this case, we forward the | 898 | * Data is from the HID++ collection, in this case, we forward the |
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 48dec394dd38..e748e45b5b2f 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c | |||
@@ -205,6 +205,31 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp, | |||
205 | return ret; | 205 | return ret; |
206 | } | 206 | } |
207 | 207 | ||
208 | static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev, | ||
209 | u8 report_id, u8 sub_id, u8 reg_address, u8 *params, int param_count, | ||
210 | struct hidpp_report *response) | ||
211 | { | ||
212 | struct hidpp_report *message = kzalloc(sizeof(struct hidpp_report), | ||
213 | GFP_KERNEL); | ||
214 | int ret; | ||
215 | |||
216 | if ((report_id != REPORT_ID_HIDPP_SHORT) && | ||
217 | (report_id != REPORT_ID_HIDPP_LONG)) | ||
218 | return -EINVAL; | ||
219 | |||
220 | if (param_count > sizeof(message->rap.params)) | ||
221 | return -EINVAL; | ||
222 | |||
223 | message->report_id = report_id; | ||
224 | message->rap.sub_id = sub_id; | ||
225 | message->rap.reg_address = reg_address; | ||
226 | memcpy(&message->rap.params, params, param_count); | ||
227 | |||
228 | ret = hidpp_send_message_sync(hidpp_dev, message, response); | ||
229 | kfree(message); | ||
230 | return ret; | ||
231 | } | ||
232 | |||
208 | static inline bool hidpp_match_answer(struct hidpp_report *question, | 233 | static inline bool hidpp_match_answer(struct hidpp_report *question, |
209 | struct hidpp_report *answer) | 234 | struct hidpp_report *answer) |
210 | { | 235 | { |
@@ -221,6 +246,45 @@ static inline bool hidpp_match_error(struct hidpp_report *question, | |||
221 | } | 246 | } |
222 | 247 | ||
223 | /* -------------------------------------------------------------------------- */ | 248 | /* -------------------------------------------------------------------------- */ |
249 | /* HIDP++ 1.0 commands */ | ||
250 | /* -------------------------------------------------------------------------- */ | ||
251 | |||
252 | #define HIDPP_SET_REGISTER 0x80 | ||
253 | #define HIDPP_GET_REGISTER 0x81 | ||
254 | #define HIDPP_SET_LONG_REGISTER 0x82 | ||
255 | #define HIDPP_GET_LONG_REGISTER 0x83 | ||
256 | |||
257 | #define HIDPP_REG_PAIRING_INFORMATION 0xB5 | ||
258 | #define DEVICE_NAME 0x40 | ||
259 | |||
260 | static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev) | ||
261 | { | ||
262 | struct hidpp_report response; | ||
263 | int ret; | ||
264 | /* hid-logitech-dj is in charge of setting the right device index */ | ||
265 | u8 params[1] = { DEVICE_NAME }; | ||
266 | char *name; | ||
267 | int len; | ||
268 | |||
269 | ret = hidpp_send_rap_command_sync(hidpp_dev, | ||
270 | REPORT_ID_HIDPP_SHORT, | ||
271 | HIDPP_GET_LONG_REGISTER, | ||
272 | HIDPP_REG_PAIRING_INFORMATION, | ||
273 | params, 1, &response); | ||
274 | if (ret) | ||
275 | return NULL; | ||
276 | |||
277 | len = response.rap.params[1]; | ||
278 | |||
279 | name = kzalloc(len + 1, GFP_KERNEL); | ||
280 | if (!name) | ||
281 | return NULL; | ||
282 | |||
283 | memcpy(name, &response.rap.params[2], len); | ||
284 | return name; | ||
285 | } | ||
286 | |||
287 | /* -------------------------------------------------------------------------- */ | ||
224 | /* 0x0000: Root */ | 288 | /* 0x0000: Root */ |
225 | /* -------------------------------------------------------------------------- */ | 289 | /* -------------------------------------------------------------------------- */ |
226 | 290 | ||
@@ -726,13 +790,21 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
726 | return 0; | 790 | return 0; |
727 | } | 791 | } |
728 | 792 | ||
729 | static void hidpp_overwrite_name(struct hid_device *hdev) | 793 | static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying) |
730 | { | 794 | { |
731 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | 795 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
732 | char *name; | 796 | char *name; |
733 | u8 name_length; | 797 | u8 name_length; |
734 | 798 | ||
735 | name = hidpp_get_device_name(hidpp, &name_length); | 799 | if (use_unifying) |
800 | /* | ||
801 | * the device is connected through an Unifying receiver, and | ||
802 | * might not be already connected. | ||
803 | * Ask the receiver for its name. | ||
804 | */ | ||
805 | name = hidpp_get_unifying_name(hidpp); | ||
806 | else | ||
807 | name = hidpp_get_device_name(hidpp, &name_length); | ||
736 | 808 | ||
737 | if (!name) | 809 | if (!name) |
738 | hid_err(hdev, "unable to retrieve the name of the device"); | 810 | hid_err(hdev, "unable to retrieve the name of the device"); |
@@ -783,12 +855,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
783 | goto hid_parse_fail; | 855 | goto hid_parse_fail; |
784 | } | 856 | } |
785 | 857 | ||
786 | /* the device is connected, we can ask for its name */ | ||
787 | hid_info(hdev, "HID++ %u.%u device connected.\n", | 858 | hid_info(hdev, "HID++ %u.%u device connected.\n", |
788 | hidpp->protocol_major, hidpp->protocol_minor); | 859 | hidpp->protocol_major, hidpp->protocol_minor); |
789 | hidpp_overwrite_name(hdev); | ||
790 | } | 860 | } |
791 | 861 | ||
862 | hidpp_overwrite_name(hdev, id->group == HID_GROUP_LOGITECH_DJ_DEVICE); | ||
863 | |||
792 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { | 864 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { |
793 | ret = wtp_get_config(hidpp); | 865 | ret = wtp_get_config(hidpp); |
794 | if (ret) | 866 | if (ret) |