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
122124struct 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) */
337380static 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);
517561static LIST_HEAD (dj_hdev_list );
518562static 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 */
876933static 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
0 commit comments