aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2014-09-30 13:18:30 -0400
committerJiri Kosina <jkosina@suse.cz>2014-10-29 05:51:40 -0400
commit33797820af98cde5c7cee00d00f0d8e255ea199f (patch)
tree2d85919e568b520986c52fed4af86d077f755bf9 /drivers/hid
parent925f0f3ed24f98b40c28627e74ff3e7f9d1e28bc (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.c24
-rw-r--r--drivers/hid/hid-logitech-hidpp.c80
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
670static u8 unifying_name_query[] = {0x10, 0xff, 0x83, 0xb5, 0x40, 0x00, 0x00};
671static u8 unifying_name_answer[] = {0x11, 0xff, 0x83, 0xb5};
672
670static int logi_dj_ll_raw_request(struct hid_device *hid, 673static 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
208static 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
208static inline bool hidpp_match_answer(struct hidpp_report *question, 233static 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
260static 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
729static void hidpp_overwrite_name(struct hid_device *hdev) 793static 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)