Skip to content

Commit 5329fc3

Browse files
MavChtzJiri Kosina
authored andcommitted
HID: logitech-dj: Add support for a new lightspeed receiver iteration
This lightspeed receiver uses 13 byte mouse reports without an ID. There are 5 additional vendor defined bytes appended to the report. The workaround for such cases has been adjusted to handle these larger reports. The keyboard reports have a distinct layout with differing minimums and maximums. Additionally, the LED reports now require a report ID of 1. New keyboard and mouse descriptors have been added to reflect these changes. The devices attached to this receiver now report the status of their battery in wireless mode, libratbag communicates with them and they can be configured with Piper. Fixes: 9d1bd93 ("HID: logitech-dj: Add support for a new lightspeed receiver iteration") Link: https://bugzilla.kernel.org/show_bug.cgi?id=218172 Link: https://bugzilla.kernel.org/show_bug.cgi?id=218094 Co-developed-by: Filipe Laíns <lains@riseup.net> Signed-off-by: Filipe Laíns <lains@riseup.net> Signed-off-by: Mavroudis Chatzilazaridis <mavchatz@protonmail.com> Tested-by: Stuart Hayhurst <stuart.a.hayhurst@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
1 parent 8c09e8b commit 5329fc3

2 files changed

Lines changed: 112 additions & 7 deletions

File tree

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@
912912
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539
913913
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f
914914
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc543
915+
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_3 0xc547
915916
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
916917
#define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548
917918
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623

drivers/hid/hid-logitech-dj.c

Lines changed: 111 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ enum recvr_type {
116116
recvr_type_dj,
117117
recvr_type_hidpp,
118118
recvr_type_gaming_hidpp,
119+
recvr_type_gaming_hidpp_ls_1_3,
119120
recvr_type_mouse_only,
120121
recvr_type_27mhz,
121122
recvr_type_bluetooth,
@@ -211,6 +212,44 @@ static const char kbd_descriptor[] = {
211212
0xC0
212213
};
213214

215+
/* Gaming Keyboard descriptor (1) */
216+
static const char kbd_lightspeed_1_3_descriptor[] = {
217+
0x05, 0x01, /* Usage Page (Generic Desktop) */
218+
0x09, 0x06, /* Usage (Keyboard) */
219+
0xA1, 0x01, /* Collection (Application) */
220+
0x85, 0x01, /* Report ID (1) */
221+
0x05, 0x07, /* Usage Page (Kbrd/Keypad) */
222+
0x19, 0xE0, /* Usage Minimum (0xE0) */
223+
0x29, 0xE7, /* Usage Maximum (0xE7) */
224+
0x15, 0x00, /* Logical Minimum (0) */
225+
0x25, 0x01, /* Logical Maximum (1) */
226+
0x75, 0x01, /* Report Size (1) */
227+
0x95, 0x08, /* Report Count (8) */
228+
0x81, 0x02, /* Input (Data,Var) */
229+
0x95, 0x70, /* Report Count (112) */
230+
0x19, 0x04, /* Usage Minimum (0x04) */
231+
0x29, 0x73, /* Usage Maximum (0x73) */
232+
0x81, 0x02, /* Input (Data,Var,Abs) */
233+
0x95, 0x05, /* Report Count (5) */
234+
0x19, 0x87, /* Usage Minimum (0x87) */
235+
0x29, 0x8B, /* Usage Maximum (0x8B) */
236+
0x81, 0x02, /* Input (Data,Var,Abs) */
237+
0x95, 0x03, /* Report Count (3) */
238+
0x19, 0x90, /* Usage Minimum (0x90) */
239+
0x29, 0x92, /* Usage Maximum (0x92) */
240+
0x81, 0x02, /* Input (Data,Var,Abs) */
241+
0x95, 0x05, /* Report Count (5) */
242+
0x85, 0x0E, /* Report ID (14) */
243+
0x05, 0x08, /* Usage Page (LEDs) */
244+
0x19, 0x01, /* Usage Minimum (Num Lock) */
245+
0x29, 0x05, /* Usage Maximum (Kana) */
246+
0x91, 0x02, /* Output (Data,Var,Abs) */
247+
0x95, 0x01, /* Report Count (1) */
248+
0x75, 0x03, /* Report Size (3) */
249+
0x91, 0x03, /* Output (Const,Var,Abs) */
250+
0xC0, /* End Collection */
251+
};
252+
214253
/* Mouse descriptor (2) */
215254
static const char mse_descriptor[] = {
216255
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
@@ -415,6 +454,51 @@ static const char mse_high_res_descriptor[] = {
415454
0xC0, /* END_COLLECTION */
416455
};
417456

457+
/* Gaming Mouse descriptor with vendor data (2) */
458+
static const char mse_high_res_ls_1_3_descriptor[] = {
459+
0x05, 0x01, /* Usage Page (Generic Desktop) */
460+
0x09, 0x02, /* Usage (Mouse) */
461+
0xA1, 0x01, /* Collection (Application) */
462+
0x85, 0x02, /* Report ID (2) */
463+
0x09, 0x01, /* Usage (Pointer) */
464+
0xA1, 0x00, /* Collection (Physical) */
465+
0x95, 0x10, /* Report Count (16) */
466+
0x75, 0x01, /* Report Size (1) */
467+
0x15, 0x00, /* Logical Minimum (0) */
468+
0x25, 0x01, /* Logical Maximum (1) */
469+
0x05, 0x09, /* Usage Page (Button) */
470+
0x19, 0x01, /* Usage Minimum (0x01) */
471+
0x29, 0x10, /* Usage Maximum (0x10) */
472+
0x81, 0x02, /* Input (Data,Var,Abs) */
473+
0x95, 0x02, /* Report Count (2) */
474+
0x75, 0x10, /* Report Size (16) */
475+
0x16, 0x01, 0x80, /* Logical Minimum (-32767) */
476+
0x26, 0xFF, 0x7F, /* Logical Maximum (32767) */
477+
0x05, 0x01, /* Usage Page (Generic Desktop) */
478+
0x09, 0x30, /* Usage (X) */
479+
0x09, 0x31, /* Usage (Y) */
480+
0x81, 0x06, /* Input (Data,Var,Rel) */
481+
0x95, 0x01, /* Report Count (1) */
482+
0x75, 0x08, /* Report Size (8) */
483+
0x15, 0x81, /* Logical Minimum (-127) */
484+
0x25, 0x7F, /* Logical Maximum (127) */
485+
0x09, 0x38, /* Usage (Wheel) */
486+
0x81, 0x06, /* Input (Data,Var,Rel) */
487+
0x95, 0x01, /* Report Count (1) */
488+
0x05, 0x0C, /* Usage Page (Consumer) */
489+
0x0A, 0x38, 0x02, /* Usage (AC Pan) */
490+
0x81, 0x06, /* Input (Data,Var,Rel) */
491+
0xC0, /* End Collection */
492+
0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */
493+
0x09, 0xF1, /* Usage (0xF1) */
494+
0x75, 0x08, /* Report Size (8) */
495+
0x95, 0x05, /* Report Count (5) */
496+
0x15, 0x00, /* Logical Minimum (0) */
497+
0x26, 0xFF, 0x00, /* Logical Maximum (255) */
498+
0x81, 0x00, /* Input (Data,Array,Abs) */
499+
0xC0, /* End Collection */
500+
};
501+
418502
/* Consumer Control descriptor (3) */
419503
static const char consumer_descriptor[] = {
420504
0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
@@ -520,9 +604,9 @@ static const char hidpp_descriptor[] = {
520604
/* Maximum size of all defined hid reports in bytes (including report id) */
521605
#define MAX_REPORT_SIZE 8
522606

523-
/* Make sure all descriptors are present here */
607+
/* Make sure the largest of each descriptor type is present here */
524608
#define MAX_RDESC_SIZE \
525-
(sizeof(kbd_descriptor) + \
609+
(sizeof(kbd_lightspeed_1_3_descriptor) +\
526610
sizeof(mse_bluetooth_descriptor) + \
527611
sizeof(mse5_bluetooth_descriptor) + \
528612
sizeof(consumer_descriptor) + \
@@ -1374,12 +1458,19 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
13741458
return -EINVAL;
13751459

13761460
if (djrcv_dev->type != recvr_type_dj && count >= 2) {
1461+
unsigned char led_report_id = 0;
1462+
13771463
if (!djrcv_dev->keyboard) {
13781464
hid_warn(hid, "Received REPORT_TYPE_LEDS request before the keyboard interface was enumerated\n");
13791465
return 0;
13801466
}
1467+
1468+
/* This Lightspeed receiver expects LED reports with report ID 1 */
1469+
if (djrcv_dev->type == recvr_type_gaming_hidpp_ls_1_3)
1470+
led_report_id = 1;
1471+
13811472
/* usbhid overrides the report ID and ignores the first byte */
1382-
return hid_hw_raw_request(djrcv_dev->keyboard, 0, buf, count,
1473+
return hid_hw_raw_request(djrcv_dev->keyboard, led_report_id, buf, count,
13831474
report_type, reqtype);
13841475
}
13851476

@@ -1426,7 +1517,11 @@ static int logi_dj_ll_parse(struct hid_device *hid)
14261517
if (djdev->reports_supported & STD_KEYBOARD) {
14271518
dbg_hid("%s: sending a kbd descriptor, reports_supported: %llx\n",
14281519
__func__, djdev->reports_supported);
1429-
rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
1520+
if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp_ls_1_3)
1521+
rdcat(rdesc, &rsize, kbd_lightspeed_1_3_descriptor,
1522+
sizeof(kbd_lightspeed_1_3_descriptor));
1523+
else
1524+
rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
14301525
}
14311526

14321527
if (djdev->reports_supported & STD_MOUSE) {
@@ -1436,6 +1531,9 @@ static int logi_dj_ll_parse(struct hid_device *hid)
14361531
djdev->dj_receiver_dev->type == recvr_type_mouse_only)
14371532
rdcat(rdesc, &rsize, mse_high_res_descriptor,
14381533
sizeof(mse_high_res_descriptor));
1534+
else if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp_ls_1_3)
1535+
rdcat(rdesc, &rsize, mse_high_res_ls_1_3_descriptor,
1536+
sizeof(mse_high_res_ls_1_3_descriptor));
14391537
else if (djdev->dj_receiver_dev->type == recvr_type_27mhz)
14401538
rdcat(rdesc, &rsize, mse_27mhz_descriptor,
14411539
sizeof(mse_27mhz_descriptor));
@@ -1695,11 +1793,12 @@ static int logi_dj_raw_event(struct hid_device *hdev,
16951793
}
16961794
/*
16971795
* Mouse-only receivers send unnumbered mouse data. The 27 MHz
1698-
* receiver uses 6 byte packets, the nano receiver 8 bytes.
1796+
* receiver uses 6 byte packets, the nano receiver 8 bytes,
1797+
* the lightspeed receiver (Pro X Superlight) 13 bytes.
16991798
*/
17001799
if (djrcv_dev->unnumbered_application == HID_GD_MOUSE &&
1701-
size <= 8) {
1702-
u8 mouse_report[9];
1800+
size <= 13){
1801+
u8 mouse_report[14];
17031802

17041803
/* Prepend report id */
17051804
mouse_report[0] = REPORT_TYPE_MOUSE;
@@ -1776,6 +1875,7 @@ static int logi_dj_probe(struct hid_device *hdev,
17761875
case recvr_type_dj: no_dj_interfaces = 3; break;
17771876
case recvr_type_hidpp: no_dj_interfaces = 2; break;
17781877
case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break;
1878+
case recvr_type_gaming_hidpp_ls_1_3: no_dj_interfaces = 3; break;
17791879
case recvr_type_mouse_only: no_dj_interfaces = 2; break;
17801880
case recvr_type_27mhz: no_dj_interfaces = 2; break;
17811881
case recvr_type_bluetooth: no_dj_interfaces = 2; break;
@@ -1987,6 +2087,10 @@ static const struct hid_device_id logi_dj_receivers[] = {
19872087
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
19882088
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2),
19892089
.driver_data = recvr_type_gaming_hidpp},
2090+
{ /* Logitech lightspeed receiver (0xc547) */
2091+
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
2092+
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_3),
2093+
.driver_data = recvr_type_gaming_hidpp_ls_1_3},
19902094

19912095
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
19922096
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),

0 commit comments

Comments
 (0)