Skip to content

Commit 434f770

Browse files
jwrdegoedeJiri Kosina
authored andcommitted
HID: logitech-dj: Handle newer quad/bt2.0 receivers in HID proxy mode
The Dinovo Edge and Dinovo Mini keyboards with builtin touchpad come with a different version of the quad/bt2.0 combo receivers shipped with the MX5000 and MX5500 keyboards. These receivers are compatible with one another, e.g. the Dinovo Edge keyboard can be paired with the MX5000 receiver. Like the MX5x00 receivers in HID proxy mode these receivers present themselves as a hub with multiple USB-HID devices, one for the keyboard and one for the mouse. Where they differ is that the mouse USB-device has 2 input reports for reporting mice events. It has the exact same INPUT(2) report as the MX5x00 receivers, but it also has a second INPUT(5) mouse report which is different; and when the Dinovo receivers are paired with the Dinovo keyboards the second INPUT(5) mouse report is actually used for events on the builtin touchpad. Add support for handling the Dinovo quad/bluetooth-2.0 combo receivers in HID proxy mode to logitech-dj, like we already do for the similar MX5000 and MX5500 receivers. This adds battery monitoring functionality (through logitech-hidpp) and fixes the Phone (Fn + F1) and "[A]" - "[D]" (Fn + F9 - F12) hotkeys not working on the Dinovo Edge. Note these receivers present themselves as a hub with 2 separate USB devices for the keyboard and mouse; and the logitech-dj code needs to bind to both devices (just as with the MX5x00 receivers). Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 751cb65 commit 434f770

File tree

4 files changed

+92
-31
lines changed

4 files changed

+92
-31
lines changed

drivers/hid/hid-ids.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,12 +815,14 @@
815815
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
816816
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
817817
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
818-
#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
819-
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
820818
#define USB_DEVICE_ID_MX5000_RECEIVER_MOUSE_DEV 0xc70a
821819
#define USB_DEVICE_ID_MX5000_RECEIVER_KBD_DEV 0xc70e
820+
#define USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_KBD_DEV 0xc713
821+
#define USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_MOUSE_DEV 0xc714
822822
#define USB_DEVICE_ID_MX5500_RECEIVER_KBD_DEV 0xc71b
823823
#define USB_DEVICE_ID_MX5500_RECEIVER_MOUSE_DEV 0xc71c
824+
#define USB_DEVICE_ID_DINOVO_MINI_RECEIVER_KBD_DEV 0xc71e
825+
#define USB_DEVICE_ID_DINOVO_MINI_RECEIVER_MOUSE_DEV 0xc71f
824826
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03
825827
#define USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL 0xca04
826828

drivers/hid/hid-lg.c

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -568,22 +568,6 @@ static int lg_ultrax_remote_mapping(struct hid_input *hi,
568568
return 1;
569569
}
570570

571-
static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
572-
unsigned long **bit, int *max)
573-
{
574-
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
575-
return 0;
576-
577-
switch (usage->hid & HID_USAGE) {
578-
579-
case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
580-
default:
581-
return 0;
582-
583-
}
584-
return 1;
585-
}
586-
587571
static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
588572
unsigned long **bit, int *max)
589573
{
@@ -668,10 +652,6 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
668652
lg_ultrax_remote_mapping(hi, usage, bit, max))
669653
return 1;
670654

671-
if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
672-
lg_dinovo_mapping(hi, usage, bit, max))
673-
return 1;
674-
675655
if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
676656
return 1;
677657

@@ -879,10 +859,6 @@ static const struct hid_device_id lg_devices[] = {
879859

880860
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
881861
.driver_data = LG_DUPLICATE_USAGES },
882-
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
883-
.driver_data = LG_DUPLICATE_USAGES },
884-
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
885-
.driver_data = LG_DUPLICATE_USAGES },
886862

887863
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
888864
.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },

drivers/hid/hid-logitech-dj.c

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#define STD_MOUSE BIT(2)
8585
#define MULTIMEDIA BIT(3)
8686
#define POWER_KEYS BIT(4)
87+
#define KBD_MOUSE BIT(5)
8788
#define MEDIA_CENTER BIT(8)
8889
#define KBD_LEDS BIT(14)
8990
/* Fake (bitnr > NUMBER_OF_HID_REPORTS) bit to track HID++ capability */
@@ -117,6 +118,7 @@ enum recvr_type {
117118
recvr_type_mouse_only,
118119
recvr_type_27mhz,
119120
recvr_type_bluetooth,
121+
recvr_type_dinovo,
120122
};
121123

122124
struct dj_report {
@@ -333,6 +335,47 @@ static const char mse_bluetooth_descriptor[] = {
333335
0xC0, /* END_COLLECTION */
334336
};
335337

338+
/* Mouse descriptor (5) for Bluetooth receiver, normal-res hwheel, 8 buttons */
339+
static const char mse5_bluetooth_descriptor[] = {
340+
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
341+
0x09, 0x02, /* Usage (Mouse) */
342+
0xa1, 0x01, /* Collection (Application) */
343+
0x85, 0x05, /* Report ID (5) */
344+
0x09, 0x01, /* Usage (Pointer) */
345+
0xa1, 0x00, /* Collection (Physical) */
346+
0x05, 0x09, /* Usage Page (Button) */
347+
0x19, 0x01, /* Usage Minimum (1) */
348+
0x29, 0x08, /* Usage Maximum (8) */
349+
0x15, 0x00, /* Logical Minimum (0) */
350+
0x25, 0x01, /* Logical Maximum (1) */
351+
0x95, 0x08, /* Report Count (8) */
352+
0x75, 0x01, /* Report Size (1) */
353+
0x81, 0x02, /* Input (Data,Var,Abs) */
354+
0x05, 0x01, /* Usage Page (Generic Desktop) */
355+
0x16, 0x01, 0xf8, /* Logical Minimum (-2047) */
356+
0x26, 0xff, 0x07, /* Logical Maximum (2047) */
357+
0x75, 0x0c, /* Report Size (12) */
358+
0x95, 0x02, /* Report Count (2) */
359+
0x09, 0x30, /* Usage (X) */
360+
0x09, 0x31, /* Usage (Y) */
361+
0x81, 0x06, /* Input (Data,Var,Rel) */
362+
0x15, 0x81, /* Logical Minimum (-127) */
363+
0x25, 0x7f, /* Logical Maximum (127) */
364+
0x75, 0x08, /* Report Size (8) */
365+
0x95, 0x01, /* Report Count (1) */
366+
0x09, 0x38, /* Usage (Wheel) */
367+
0x81, 0x06, /* Input (Data,Var,Rel) */
368+
0x05, 0x0c, /* Usage Page (Consumer Devices) */
369+
0x0a, 0x38, 0x02, /* Usage (AC Pan) */
370+
0x15, 0x81, /* Logical Minimum (-127) */
371+
0x25, 0x7f, /* Logical Maximum (127) */
372+
0x75, 0x08, /* Report Size (8) */
373+
0x95, 0x01, /* Report Count (1) */
374+
0x81, 0x06, /* Input (Data,Var,Rel) */
375+
0xc0, /* End Collection */
376+
0xc0, /* End Collection */
377+
};
378+
336379
/* Gaming Mouse descriptor (2) */
337380
static const char mse_high_res_descriptor[] = {
338381
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
@@ -480,6 +523,7 @@ static const char hidpp_descriptor[] = {
480523
#define MAX_RDESC_SIZE \
481524
(sizeof(kbd_descriptor) + \
482525
sizeof(mse_bluetooth_descriptor) + \
526+
sizeof(mse5_bluetooth_descriptor) + \
483527
sizeof(consumer_descriptor) + \
484528
sizeof(syscontrol_descriptor) + \
485529
sizeof(media_descriptor) + \
@@ -517,6 +561,11 @@ static void delayedwork_callback(struct work_struct *work);
517561
static LIST_HEAD(dj_hdev_list);
518562
static DEFINE_MUTEX(dj_hdev_list_lock);
519563

564+
static bool recvr_type_is_bluetooth(enum recvr_type type)
565+
{
566+
return type == recvr_type_bluetooth || type == recvr_type_dinovo;
567+
}
568+
520569
/*
521570
* dj/HID++ receivers are really a single logical entity, but for BIOS/Windows
522571
* compatibility they have multiple USB interfaces. On HID++ receivers we need
@@ -534,7 +583,7 @@ static struct dj_receiver_dev *dj_find_receiver_dev(struct hid_device *hdev,
534583
* The bluetooth receiver contains a built-in hub and has separate
535584
* USB-devices for the keyboard and mouse interfaces.
536585
*/
537-
sep = (type == recvr_type_bluetooth) ? '.' : '/';
586+
sep = recvr_type_is_bluetooth(type) ? '.' : '/';
538587

539588
/* Try to find an already-probed interface from the same device */
540589
list_for_each_entry(djrcv_dev, &dj_hdev_list, list) {
@@ -872,6 +921,14 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
872921
* touchpad to work we must also forward mouse input reports to the dj_hiddev
873922
* created for the keyboard (instead of forwarding them to a second paired
874923
* device with a device_type of REPORT_TYPE_MOUSE as we normally would).
924+
*
925+
* On Dinovo receivers the keyboard's touchpad and an optional paired actual
926+
* mouse send separate input reports, INPUT(2) aka STD_MOUSE for the mouse
927+
* and INPUT(5) aka KBD_MOUSE for the keyboard's touchpad.
928+
*
929+
* On MX5x00 receivers (which can also be paired with a Dinovo keyboard)
930+
* INPUT(2) is used for both an optional paired actual mouse and for the
931+
* keyboard's touchpad.
875932
*/
876933
static const u16 kbd_builtin_touchpad_ids[] = {
877934
0xb309, /* Dinovo Edge */
@@ -898,7 +955,10 @@ static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
898955
id = (workitem->quad_id_msb << 8) | workitem->quad_id_lsb;
899956
for (i = 0; i < ARRAY_SIZE(kbd_builtin_touchpad_ids); i++) {
900957
if (id == kbd_builtin_touchpad_ids[i]) {
901-
workitem->reports_supported |= STD_MOUSE;
958+
if (djrcv_dev->type == recvr_type_dinovo)
959+
workitem->reports_supported |= KBD_MOUSE;
960+
else
961+
workitem->reports_supported |= STD_MOUSE;
902962
break;
903963
}
904964
}
@@ -1367,14 +1427,21 @@ static int logi_dj_ll_parse(struct hid_device *hid)
13671427
else if (djdev->dj_receiver_dev->type == recvr_type_27mhz)
13681428
rdcat(rdesc, &rsize, mse_27mhz_descriptor,
13691429
sizeof(mse_27mhz_descriptor));
1370-
else if (djdev->dj_receiver_dev->type == recvr_type_bluetooth)
1430+
else if (recvr_type_is_bluetooth(djdev->dj_receiver_dev->type))
13711431
rdcat(rdesc, &rsize, mse_bluetooth_descriptor,
13721432
sizeof(mse_bluetooth_descriptor));
13731433
else
13741434
rdcat(rdesc, &rsize, mse_descriptor,
13751435
sizeof(mse_descriptor));
13761436
}
13771437

1438+
if (djdev->reports_supported & KBD_MOUSE) {
1439+
dbg_hid("%s: sending a kbd-mouse descriptor, reports_supported: %llx\n",
1440+
__func__, djdev->reports_supported);
1441+
rdcat(rdesc, &rsize, mse5_bluetooth_descriptor,
1442+
sizeof(mse5_bluetooth_descriptor));
1443+
}
1444+
13781445
if (djdev->reports_supported & MULTIMEDIA) {
13791446
dbg_hid("%s: sending a multimedia report descriptor: %llx\n",
13801447
__func__, djdev->reports_supported);
@@ -1692,6 +1759,7 @@ static int logi_dj_probe(struct hid_device *hdev,
16921759
case recvr_type_mouse_only: no_dj_interfaces = 2; break;
16931760
case recvr_type_27mhz: no_dj_interfaces = 2; break;
16941761
case recvr_type_bluetooth: no_dj_interfaces = 2; break;
1762+
case recvr_type_dinovo: no_dj_interfaces = 2; break;
16951763
}
16961764
if (hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
16971765
intf = to_usb_interface(hdev->dev.parent);
@@ -1924,6 +1992,23 @@ static const struct hid_device_id logi_dj_receivers[] = {
19241992
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
19251993
USB_DEVICE_ID_MX5500_RECEIVER_MOUSE_DEV),
19261994
.driver_data = recvr_type_bluetooth},
1995+
1996+
{ /* Logitech Dinovo Edge HID++ / bluetooth receiver keyboard intf. (0xc713) */
1997+
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
1998+
USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_KBD_DEV),
1999+
.driver_data = recvr_type_dinovo},
2000+
{ /* Logitech Dinovo Edge HID++ / bluetooth receiver mouse intf. (0xc714) */
2001+
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
2002+
USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_MOUSE_DEV),
2003+
.driver_data = recvr_type_dinovo},
2004+
{ /* Logitech DiNovo Mini HID++ / bluetooth receiver mouse intf. (0xc71e) */
2005+
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
2006+
USB_DEVICE_ID_DINOVO_MINI_RECEIVER_KBD_DEV),
2007+
.driver_data = recvr_type_dinovo},
2008+
{ /* Logitech DiNovo Mini HID++ / bluetooth receiver keyboard intf. (0xc71f) */
2009+
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
2010+
USB_DEVICE_ID_DINOVO_MINI_RECEIVER_MOUSE_DEV),
2011+
.driver_data = recvr_type_dinovo},
19272012
{}
19282013
};
19292014

drivers/hid/hid-quirks.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
445445
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
446446
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
447447
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
448-
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
449-
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
450448
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
451449
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
452450
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },

0 commit comments

Comments
 (0)