summaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2014-09-30 13:18:29 -0400
committerJiri Kosina <jkosina@suse.cz>2014-10-29 05:51:40 -0400
commit925f0f3ed24f98b40c28627e74ff3e7f9d1e28bc (patch)
treeed39744f58c2f57393194db8dcd29dff1dbbe78d /drivers/hid
parentab94e562ed45c99914fe874b7feaf75b80ceea84 (diff)
HID: logitech-dj: allow transfer of HID++ reports from/to the correct dj device
HID++ is a Logitech-specific protocol for communicating with HID devices. DJ devices implement HID++, and so we can add the HID++ collection in the report descriptor and forward the incoming reports from the receiver to the appropriate DJ device. The same can be done in the other way, if someone calls a .raw_request(), we can forward it to the correct dj device by overriding the device_index in the HID++ report. Signed-off-by: Benjamin Tisssoires <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.c188
1 files changed, 160 insertions, 28 deletions
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 45a7eacdfe98..feddacd87b8b 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -42,6 +42,15 @@
42#define REPORT_ID_DJ_SHORT 0x20 42#define REPORT_ID_DJ_SHORT 0x20
43#define REPORT_ID_DJ_LONG 0x21 43#define REPORT_ID_DJ_LONG 0x21
44 44
45#define REPORT_ID_HIDPP_SHORT 0x10
46#define REPORT_ID_HIDPP_LONG 0x11
47
48#define HIDPP_REPORT_SHORT_LENGTH 7
49#define HIDPP_REPORT_LONG_LENGTH 20
50
51#define HIDPP_RECEIVER_INDEX 0xff
52
53#define REPORT_TYPE_RFREPORT_FIRST 0x01
45#define REPORT_TYPE_RFREPORT_LAST 0x1F 54#define REPORT_TYPE_RFREPORT_LAST 0x1F
46 55
47/* Command Switch to DJ mode */ 56/* Command Switch to DJ mode */
@@ -242,6 +251,57 @@ static const char media_descriptor[] = {
242 0xc0, /* EndCollection */ 251 0xc0, /* EndCollection */
243}; /* */ 252}; /* */
244 253
254/* HIDPP descriptor */
255static const char hidpp_descriptor[] = {
256 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
257 0x09, 0x01, /* Usage (Vendor Usage 1) */
258 0xa1, 0x01, /* Collection (Application) */
259 0x85, 0x10, /* Report ID (16) */
260 0x75, 0x08, /* Report Size (8) */
261 0x95, 0x06, /* Report Count (6) */
262 0x15, 0x00, /* Logical Minimum (0) */
263 0x26, 0xff, 0x00, /* Logical Maximum (255) */
264 0x09, 0x01, /* Usage (Vendor Usage 1) */
265 0x81, 0x00, /* Input (Data,Arr,Abs) */
266 0x09, 0x01, /* Usage (Vendor Usage 1) */
267 0x91, 0x00, /* Output (Data,Arr,Abs) */
268 0xc0, /* End Collection */
269 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
270 0x09, 0x02, /* Usage (Vendor Usage 2) */
271 0xa1, 0x01, /* Collection (Application) */
272 0x85, 0x11, /* Report ID (17) */
273 0x75, 0x08, /* Report Size (8) */
274 0x95, 0x13, /* Report Count (19) */
275 0x15, 0x00, /* Logical Minimum (0) */
276 0x26, 0xff, 0x00, /* Logical Maximum (255) */
277 0x09, 0x02, /* Usage (Vendor Usage 2) */
278 0x81, 0x00, /* Input (Data,Arr,Abs) */
279 0x09, 0x02, /* Usage (Vendor Usage 2) */
280 0x91, 0x00, /* Output (Data,Arr,Abs) */
281 0xc0, /* End Collection */
282 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
283 0x09, 0x04, /* Usage (Vendor Usage 0x04) */
284 0xa1, 0x01, /* Collection (Application) */
285 0x85, 0x20, /* Report ID (32) */
286 0x75, 0x08, /* Report Size (8) */
287 0x95, 0x0e, /* Report Count (14) */
288 0x15, 0x00, /* Logical Minimum (0) */
289 0x26, 0xff, 0x00, /* Logical Maximum (255) */
290 0x09, 0x41, /* Usage (Vendor Usage 0x41) */
291 0x81, 0x00, /* Input (Data,Arr,Abs) */
292 0x09, 0x41, /* Usage (Vendor Usage 0x41) */
293 0x91, 0x00, /* Output (Data,Arr,Abs) */
294 0x85, 0x21, /* Report ID (33) */
295 0x95, 0x1f, /* Report Count (31) */
296 0x15, 0x00, /* Logical Minimum (0) */
297 0x26, 0xff, 0x00, /* Logical Maximum (255) */
298 0x09, 0x42, /* Usage (Vendor Usage 0x42) */
299 0x81, 0x00, /* Input (Data,Arr,Abs) */
300 0x09, 0x42, /* Usage (Vendor Usage 0x42) */
301 0x91, 0x00, /* Output (Data,Arr,Abs) */
302 0xc0, /* End Collection */
303};
304
245/* Maximum size of all defined hid reports in bytes (including report id) */ 305/* Maximum size of all defined hid reports in bytes (including report id) */
246#define MAX_REPORT_SIZE 8 306#define MAX_REPORT_SIZE 8
247 307
@@ -251,7 +311,8 @@ static const char media_descriptor[] = {
251 sizeof(mse_descriptor) + \ 311 sizeof(mse_descriptor) + \
252 sizeof(consumer_descriptor) + \ 312 sizeof(consumer_descriptor) + \
253 sizeof(syscontrol_descriptor) + \ 313 sizeof(syscontrol_descriptor) + \
254 sizeof(media_descriptor)) 314 sizeof(media_descriptor) + \
315 sizeof(hidpp_descriptor))
255 316
256/* Number of possible hid report types that can be created by this driver. 317/* Number of possible hid report types that can be created by this driver.
257 * 318 *
@@ -512,6 +573,13 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
512 } 573 }
513} 574}
514 575
576static void logi_dj_recv_forward_hidpp(struct dj_device *dj_dev, u8 *data,
577 int size)
578{
579 /* We are called from atomic context (tasklet && djrcv->lock held) */
580 if (hid_input_report(dj_dev->hdev, HID_INPUT_REPORT, data, size, 1))
581 dbg_hid("hid_input_report error\n");
582}
515 583
516static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, 584static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
517 struct dj_report *dj_report) 585 struct dj_report *dj_report)
@@ -609,6 +677,16 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
609 u8 *out_buf; 677 u8 *out_buf;
610 int ret; 678 int ret;
611 679
680 if ((buf[0] == REPORT_ID_HIDPP_SHORT) ||
681 (buf[0] == REPORT_ID_HIDPP_LONG)) {
682 if (count < 2)
683 return -EINVAL;
684
685 buf[1] = djdev->device_index;
686 return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf,
687 count, report_type, reqtype);
688 }
689
612 if (buf[0] != REPORT_TYPE_LEDS) 690 if (buf[0] != REPORT_TYPE_LEDS)
613 return -EINVAL; 691 return -EINVAL;
614 692
@@ -687,6 +765,8 @@ static int logi_dj_ll_parse(struct hid_device *hid)
687 __func__, djdev->reports_supported); 765 __func__, djdev->reports_supported);
688 } 766 }
689 767
768 rdcat(rdesc, &rsize, hidpp_descriptor, sizeof(hidpp_descriptor));
769
690 retval = hid_parse_report(hid, rdesc, rsize); 770 retval = hid_parse_report(hid, rdesc, rsize);
691 kfree(rdesc); 771 kfree(rdesc);
692 772
@@ -714,8 +794,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
714 .raw_request = logi_dj_ll_raw_request, 794 .raw_request = logi_dj_ll_raw_request,
715}; 795};
716 796
717 797static int logi_dj_dj_event(struct hid_device *hdev,
718static int logi_dj_raw_event(struct hid_device *hdev,
719 struct hid_report *report, u8 *data, 798 struct hid_report *report, u8 *data,
720 int size) 799 int size)
721{ 800{
@@ -723,36 +802,24 @@ static int logi_dj_raw_event(struct hid_device *hdev,
723 struct dj_report *dj_report = (struct dj_report *) data; 802 struct dj_report *dj_report = (struct dj_report *) data;
724 unsigned long flags; 803 unsigned long flags;
725 804
726 dbg_hid("%s, size:%d\n", __func__, size); 805 /*
727 806 * Here we receive all data coming from iface 2, there are 3 cases:
728 /* Here we receive all data coming from iface 2, there are 4 cases:
729 *
730 * 1) Data should continue its normal processing i.e. data does not
731 * come from the DJ collection, in which case we do nothing and
732 * return 0, so hid-core can continue normal processing (will forward
733 * to associated hidraw device)
734 * 807 *
735 * 2) Data is from DJ collection, and is intended for this driver i. e. 808 * 1) Data is intended for this driver i. e. data contains arrival,
736 * data contains arrival, departure, etc notifications, in which case 809 * departure, etc notifications, in which case we queue them for delayed
737 * we queue them for delayed processing by the work queue. We return 1 810 * processing by the work queue. We return 1 to hid-core as no further
738 * to hid-core as no further processing is required from it. 811 * processing is required from it.
739 * 812 *
740 * 3) Data is from DJ collection, and informs a connection change, 813 * 2) Data informs a connection change, if the change means rf link
741 * if the change means rf link loss, then we must send a null report 814 * loss, then we must send a null report to the upper layer to discard
742 * to the upper layer to discard potentially pressed keys that may be 815 * potentially pressed keys that may be repeated forever by the input
743 * repeated forever by the input layer. Return 1 to hid-core as no 816 * layer. Return 1 to hid-core as no further processing is required.
744 * further processing is required.
745 * 817 *
746 * 4) Data is from DJ collection and is an actual input event from 818 * 3) Data is an actual input event from a paired DJ device in which
747 * a paired DJ device in which case we forward it to the correct hid 819 * case we forward it to the correct hid device (via hid_input_report()
748 * device (via hid_input_report() ) and return 1 so hid-core does not do 820 * ) and return 1 so hid-core does not anything else with it.
749 * anything else with it.
750 */ 821 */
751 822
752 /* case 1) */
753 if (data[0] != REPORT_ID_DJ_SHORT)
754 return false;
755
756 if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || 823 if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
757 (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { 824 (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
758 /* 825 /*
@@ -797,6 +864,71 @@ out:
797 return true; 864 return true;
798} 865}
799 866
867static int logi_dj_hidpp_event(struct hid_device *hdev,
868 struct hid_report *report, u8 *data,
869 int size)
870{
871 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
872 struct dj_report *dj_report = (struct dj_report *) data;
873 unsigned long flags;
874 u8 device_index = dj_report->device_index;
875
876 if (device_index == HIDPP_RECEIVER_INDEX)
877 return false;
878
879 /*
880 * Data is from the HID++ collection, in this case, we forward the
881 * data to the corresponding child dj device and return 0 to hid-core
882 * so he data also goes to the hidraw device of the receiver. This
883 * allows a user space application to implement the full HID++ routing
884 * via the receiver.
885 */
886
887 if ((device_index < DJ_DEVICE_INDEX_MIN) ||
888 (device_index > DJ_DEVICE_INDEX_MAX)) {
889 /*
890 * Device index is wrong, bail out.
891 * This driver can ignore safely the receiver notifications,
892 * so ignore those reports too.
893 */
894 dev_err(&hdev->dev, "%s: invalid device index:%d\n",
895 __func__, dj_report->device_index);
896 return false;
897 }
898
899 spin_lock_irqsave(&djrcv_dev->lock, flags);
900
901 if (!djrcv_dev->paired_dj_devices[device_index])
902 /* received an event for an unknown device, bail out */
903 goto out;
904
905 logi_dj_recv_forward_hidpp(djrcv_dev->paired_dj_devices[device_index],
906 data, size);
907
908out:
909 spin_unlock_irqrestore(&djrcv_dev->lock, flags);
910
911 return false;
912}
913
914static int logi_dj_raw_event(struct hid_device *hdev,
915 struct hid_report *report, u8 *data,
916 int size)
917{
918 dbg_hid("%s, size:%d\n", __func__, size);
919
920 switch (data[0]) {
921 case REPORT_ID_DJ_SHORT:
922 return logi_dj_dj_event(hdev, report, data, size);
923 case REPORT_ID_HIDPP_SHORT:
924 /* intentional fallthrough */
925 case REPORT_ID_HIDPP_LONG:
926 return logi_dj_hidpp_event(hdev, report, data, size);
927 }
928
929 return false;
930}
931
800static int logi_dj_probe(struct hid_device *hdev, 932static int logi_dj_probe(struct hid_device *hdev,
801 const struct hid_device_id *id) 933 const struct hid_device_id *id)
802{ 934{