112112#define HIDPP_PARAM_27MHZ_DEVID 0x03
113113#define HIDPP_DEVICE_TYPE_MASK GENMASK(3, 0)
114114#define HIDPP_LINK_STATUS_MASK BIT(6)
115+ #define HIDPP_MANUFACTURER_MASK BIT(7)
115116
116117#define HIDPP_DEVICE_TYPE_KEYBOARD 1
117118#define HIDPP_DEVICE_TYPE_MOUSE 2
@@ -128,6 +129,7 @@ enum recvr_type {
128129 recvr_type_hidpp ,
129130 recvr_type_gaming_hidpp ,
130131 recvr_type_27mhz ,
132+ recvr_type_bluetooth ,
131133};
132134
133135struct dj_report {
@@ -295,6 +297,55 @@ static const char mse_27mhz_descriptor[] = {
295297 0xC0 , /* END_COLLECTION */
296298};
297299
300+ /* Mouse descriptor (2) for Bluetooth receiver, low-res hwheel, 12 buttons */
301+ static const char mse_bluetooth_descriptor [] = {
302+ 0x05 , 0x01 , /* USAGE_PAGE (Generic Desktop) */
303+ 0x09 , 0x02 , /* USAGE (Mouse) */
304+ 0xA1 , 0x01 , /* COLLECTION (Application) */
305+ 0x85 , 0x02 , /* REPORT_ID = 2 */
306+ 0x09 , 0x01 , /* USAGE (pointer) */
307+ 0xA1 , 0x00 , /* COLLECTION (physical) */
308+ 0x05 , 0x09 , /* USAGE_PAGE (buttons) */
309+ 0x19 , 0x01 , /* USAGE_MIN (1) */
310+ 0x29 , 0x08 , /* USAGE_MAX (8) */
311+ 0x15 , 0x00 , /* LOGICAL_MIN (0) */
312+ 0x25 , 0x01 , /* LOGICAL_MAX (1) */
313+ 0x95 , 0x08 , /* REPORT_COUNT (8) */
314+ 0x75 , 0x01 , /* REPORT_SIZE (1) */
315+ 0x81 , 0x02 , /* INPUT (data var abs) */
316+ 0x05 , 0x01 , /* USAGE_PAGE (generic desktop) */
317+ 0x16 , 0x01 , 0xF8 , /* LOGICAL_MIN (-2047) */
318+ 0x26 , 0xFF , 0x07 , /* LOGICAL_MAX (2047) */
319+ 0x75 , 0x0C , /* REPORT_SIZE (12) */
320+ 0x95 , 0x02 , /* REPORT_COUNT (2) */
321+ 0x09 , 0x30 , /* USAGE (X) */
322+ 0x09 , 0x31 , /* USAGE (Y) */
323+ 0x81 , 0x06 , /* INPUT */
324+ 0x15 , 0x81 , /* LOGICAL_MIN (-127) */
325+ 0x25 , 0x7F , /* LOGICAL_MAX (127) */
326+ 0x75 , 0x08 , /* REPORT_SIZE (8) */
327+ 0x95 , 0x01 , /* REPORT_COUNT (1) */
328+ 0x09 , 0x38 , /* USAGE (wheel) */
329+ 0x81 , 0x06 , /* INPUT */
330+ 0x05 , 0x0C , /* USAGE_PAGE(consumer) */
331+ 0x0A , 0x38 , 0x02 , /* USAGE(AC Pan) */
332+ 0x15 , 0xF9 , /* LOGICAL_MIN (-7) */
333+ 0x25 , 0x07 , /* LOGICAL_MAX (7) */
334+ 0x75 , 0x04 , /* REPORT_SIZE (4) */
335+ 0x95 , 0x01 , /* REPORT_COUNT (1) */
336+ 0x81 , 0x06 , /* INPUT */
337+ 0x05 , 0x09 , /* USAGE_PAGE (buttons) */
338+ 0x19 , 0x09 , /* USAGE_MIN (9) */
339+ 0x29 , 0x0C , /* USAGE_MAX (12) */
340+ 0x15 , 0x00 , /* LOGICAL_MIN (0) */
341+ 0x25 , 0x01 , /* LOGICAL_MAX (1) */
342+ 0x75 , 0x01 , /* REPORT_SIZE (1) */
343+ 0x95 , 0x04 , /* REPORT_COUNT (4) */
344+ 0x81 , 0x06 , /* INPUT */
345+ 0xC0 , /* END_COLLECTION */
346+ 0xC0 , /* END_COLLECTION */
347+ };
348+
298349/* Gaming Mouse descriptor (2) */
299350static const char mse_high_res_descriptor [] = {
300351 0x05 , 0x01 , /* USAGE_PAGE (Generic Desktop) */
@@ -441,7 +492,7 @@ static const char hidpp_descriptor[] = {
441492/* Make sure all descriptors are present here */
442493#define MAX_RDESC_SIZE \
443494 (sizeof(kbd_descriptor) + \
444- sizeof(mse_descriptor ) + \
495+ sizeof(mse_bluetooth_descriptor ) + \
445496 sizeof(consumer_descriptor) + \
446497 sizeof(syscontrol_descriptor) + \
447498 sizeof(media_descriptor) + \
@@ -486,24 +537,32 @@ static DEFINE_MUTEX(dj_hdev_list_lock);
486537 * to create a single struct dj_receiver_dev for all interfaces belonging to
487538 * a single USB-device / receiver.
488539 */
489- static struct dj_receiver_dev * dj_find_receiver_dev (struct hid_device * hdev )
540+ static struct dj_receiver_dev * dj_find_receiver_dev (struct hid_device * hdev ,
541+ enum recvr_type type )
490542{
491543 struct dj_receiver_dev * djrcv_dev ;
544+ char sep ;
545+
546+ /*
547+ * The bluetooth receiver contains a built-in hub and has separate
548+ * USB-devices for the keyboard and mouse interfaces.
549+ */
550+ sep = (type == recvr_type_bluetooth ) ? '.' : '/' ;
492551
493552 /* Try to find an already-probed interface from the same device */
494553 list_for_each_entry (djrcv_dev , & dj_hdev_list , list ) {
495554 if (djrcv_dev -> mouse &&
496- hid_compare_device_paths (hdev , djrcv_dev -> mouse , '/' )) {
555+ hid_compare_device_paths (hdev , djrcv_dev -> mouse , sep )) {
497556 kref_get (& djrcv_dev -> kref );
498557 return djrcv_dev ;
499558 }
500559 if (djrcv_dev -> keyboard &&
501- hid_compare_device_paths (hdev , djrcv_dev -> keyboard , '/' )) {
560+ hid_compare_device_paths (hdev , djrcv_dev -> keyboard , sep )) {
502561 kref_get (& djrcv_dev -> kref );
503562 return djrcv_dev ;
504563 }
505564 if (djrcv_dev -> hidpp &&
506- hid_compare_device_paths (hdev , djrcv_dev -> hidpp , '/' )) {
565+ hid_compare_device_paths (hdev , djrcv_dev -> hidpp , sep )) {
507566 kref_get (& djrcv_dev -> kref );
508567 return djrcv_dev ;
509568 }
@@ -548,7 +607,7 @@ static struct dj_receiver_dev *dj_get_receiver_dev(struct hid_device *hdev,
548607
549608 mutex_lock (& dj_hdev_list_lock );
550609
551- djrcv_dev = dj_find_receiver_dev (hdev );
610+ djrcv_dev = dj_find_receiver_dev (hdev , type );
552611 if (!djrcv_dev ) {
553612 djrcv_dev = kzalloc (sizeof (* djrcv_dev ), GFP_KERNEL );
554613 if (!djrcv_dev )
@@ -878,6 +937,14 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
878937 switch (hidpp_report -> params [HIDPP_PARAM_PROTO_TYPE ]) {
879938 case 0x01 :
880939 device_type = "Bluetooth" ;
940+ /* Bluetooth connect packet contents is the same as (e)QUAD */
941+ logi_hidpp_dev_conn_notif_equad (hidpp_report , & workitem );
942+ if (!(hidpp_report -> params [HIDPP_PARAM_DEVICE_INFO ] &
943+ HIDPP_MANUFACTURER_MASK )) {
944+ hid_info (hdev , "Non Logitech device connected on slot %d\n" ,
945+ hidpp_report -> device_index );
946+ workitem .reports_supported &= ~HIDPP ;
947+ }
881948 break ;
882949 case 0x02 :
883950 device_type = "27 Mhz" ;
@@ -1267,6 +1334,9 @@ static int logi_dj_ll_parse(struct hid_device *hid)
12671334 else if (djdev -> dj_receiver_dev -> type == recvr_type_27mhz )
12681335 rdcat (rdesc , & rsize , mse_27mhz_descriptor ,
12691336 sizeof (mse_27mhz_descriptor ));
1337+ else if (djdev -> dj_receiver_dev -> type == recvr_type_bluetooth )
1338+ rdcat (rdesc , & rsize , mse_bluetooth_descriptor ,
1339+ sizeof (mse_bluetooth_descriptor ));
12701340 else
12711341 rdcat (rdesc , & rsize , mse_descriptor ,
12721342 sizeof (mse_descriptor ));
@@ -1581,6 +1651,7 @@ static int logi_dj_probe(struct hid_device *hdev,
15811651 case recvr_type_hidpp : no_dj_interfaces = 2 ; break ;
15821652 case recvr_type_gaming_hidpp : no_dj_interfaces = 3 ; break ;
15831653 case recvr_type_27mhz : no_dj_interfaces = 2 ; break ;
1654+ case recvr_type_bluetooth : no_dj_interfaces = 2 ; break ;
15841655 }
15851656 if (hid_is_using_ll_driver (hdev , & usb_hid_driver )) {
15861657 intf = to_usb_interface (hdev -> dev .parent );
@@ -1772,6 +1843,14 @@ static const struct hid_device_id logi_dj_receivers[] = {
17721843 HID_USB_DEVICE (USB_VENDOR_ID_LOGITECH ,
17731844 USB_DEVICE_ID_LOGITECH_27MHZ_MOUSE_RECEIVER ),
17741845 .driver_data = recvr_type_27mhz },
1846+ { /* Logitech MX5000 HID++ / bluetooth receiver keyboard intf. */
1847+ HID_USB_DEVICE (USB_VENDOR_ID_LOGITECH ,
1848+ 0xc70e ),
1849+ .driver_data = recvr_type_bluetooth },
1850+ { /* Logitech MX5000 HID++ / bluetooth receiver mouse intf. */
1851+ HID_USB_DEVICE (USB_VENDOR_ID_LOGITECH ,
1852+ 0xc70a ),
1853+ .driver_data = recvr_type_bluetooth },
17751854 {}
17761855};
17771856
0 commit comments