Commit 3ed224e2 authored by Hans de Goede's avatar Hans de Goede Committed by Benjamin Tissoires

HID: logitech-dj: Fix 064d:c52f receiver support

The c52f nano receiver is a mouse only receiver. This means that it needs
some special handling compared to the c534 nano receiver:

1) It sends unnumbered mouse reports with a size of 8 bytes, so we need
   to extend the unnumbered mouse report handling to support reports upto
   8 bytes large

2) It mouse reports have the same high-resolution format as those from the
   gaming mouse receivers

3) It can report consumer/multimedia buttons on its second interface, since
   this is a mouse-only receiver these must be forwarded to the mouse child
   device and not to the keyboard child-device (which will not exist)

Link: https://bugzilla.kernel.org/show_bug.cgi?id=203619Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Acked-by: default avatarJiri Kosina <jkosina@suse.cz>
Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
parent f9482dab
...@@ -128,6 +128,7 @@ enum recvr_type { ...@@ -128,6 +128,7 @@ enum recvr_type {
recvr_type_dj, recvr_type_dj,
recvr_type_hidpp, recvr_type_hidpp,
recvr_type_gaming_hidpp, recvr_type_gaming_hidpp,
recvr_type_mouse_only,
recvr_type_27mhz, recvr_type_27mhz,
recvr_type_bluetooth, recvr_type_bluetooth,
}; };
...@@ -879,9 +880,12 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev, ...@@ -879,9 +880,12 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
schedule_work(&djrcv_dev->work); schedule_work(&djrcv_dev->work);
} }
static void logi_hidpp_dev_conn_notif_equad(struct hidpp_event *hidpp_report, static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
struct hidpp_event *hidpp_report,
struct dj_workitem *workitem) struct dj_workitem *workitem)
{ {
struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
workitem->type = WORKITEM_TYPE_PAIRED; workitem->type = WORKITEM_TYPE_PAIRED;
workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] &
HIDPP_DEVICE_TYPE_MASK; HIDPP_DEVICE_TYPE_MASK;
...@@ -895,6 +899,8 @@ static void logi_hidpp_dev_conn_notif_equad(struct hidpp_event *hidpp_report, ...@@ -895,6 +899,8 @@ static void logi_hidpp_dev_conn_notif_equad(struct hidpp_event *hidpp_report,
break; break;
case REPORT_TYPE_MOUSE: case REPORT_TYPE_MOUSE:
workitem->reports_supported |= STD_MOUSE | HIDPP; workitem->reports_supported |= STD_MOUSE | HIDPP;
if (djrcv_dev->type == recvr_type_mouse_only)
workitem->reports_supported |= MULTIMEDIA;
break; break;
} }
} }
...@@ -938,7 +944,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -938,7 +944,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
case 0x01: case 0x01:
device_type = "Bluetooth"; device_type = "Bluetooth";
/* Bluetooth connect packet contents is the same as (e)QUAD */ /* Bluetooth connect packet contents is the same as (e)QUAD */
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
if (!(hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & if (!(hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] &
HIDPP_MANUFACTURER_MASK)) { HIDPP_MANUFACTURER_MASK)) {
hid_info(hdev, "Non Logitech device connected on slot %d\n", hid_info(hdev, "Non Logitech device connected on slot %d\n",
...@@ -952,18 +958,18 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -952,18 +958,18 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
break; break;
case 0x03: case 0x03:
device_type = "QUAD or eQUAD"; device_type = "QUAD or eQUAD";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x04: case 0x04:
device_type = "eQUAD step 4 DJ"; device_type = "eQUAD step 4 DJ";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x05: case 0x05:
device_type = "DFU Lite"; device_type = "DFU Lite";
break; break;
case 0x06: case 0x06:
device_type = "eQUAD step 4 Lite"; device_type = "eQUAD step 4 Lite";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x07: case 0x07:
device_type = "eQUAD step 4 Gaming"; device_type = "eQUAD step 4 Gaming";
...@@ -973,11 +979,11 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -973,11 +979,11 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
break; break;
case 0x0a: case 0x0a:
device_type = "eQUAD nano Lite"; device_type = "eQUAD nano Lite";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x0c: case 0x0c:
device_type = "eQUAD Lightspeed"; device_type = "eQUAD Lightspeed";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
workitem.reports_supported |= STD_KEYBOARD; workitem.reports_supported |= STD_KEYBOARD;
break; break;
} }
...@@ -1328,7 +1334,8 @@ static int logi_dj_ll_parse(struct hid_device *hid) ...@@ -1328,7 +1334,8 @@ static int logi_dj_ll_parse(struct hid_device *hid)
if (djdev->reports_supported & STD_MOUSE) { if (djdev->reports_supported & STD_MOUSE) {
dbg_hid("%s: sending a mouse descriptor, reports_supported: %llx\n", dbg_hid("%s: sending a mouse descriptor, reports_supported: %llx\n",
__func__, djdev->reports_supported); __func__, djdev->reports_supported);
if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp) if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp ||
djdev->dj_receiver_dev->type == recvr_type_mouse_only)
rdcat(rdesc, &rsize, mse_high_res_descriptor, rdcat(rdesc, &rsize, mse_high_res_descriptor,
sizeof(mse_high_res_descriptor)); sizeof(mse_high_res_descriptor));
else if (djdev->dj_receiver_dev->type == recvr_type_27mhz) else if (djdev->dj_receiver_dev->type == recvr_type_27mhz)
...@@ -1571,15 +1578,19 @@ static int logi_dj_raw_event(struct hid_device *hdev, ...@@ -1571,15 +1578,19 @@ static int logi_dj_raw_event(struct hid_device *hdev,
data[0] = data[1]; data[0] = data[1];
data[1] = 0; data[1] = 0;
} }
/* The 27 MHz mouse-only receiver sends unnumbered mouse data */ /*
* Mouse-only receivers send unnumbered mouse data. The 27 MHz
* receiver uses 6 byte packets, the nano receiver 8 bytes.
*/
if (djrcv_dev->unnumbered_application == HID_GD_MOUSE && if (djrcv_dev->unnumbered_application == HID_GD_MOUSE &&
size == 6) { size <= 8) {
u8 mouse_report[7]; u8 mouse_report[9];
/* Prepend report id */ /* Prepend report id */
mouse_report[0] = REPORT_TYPE_MOUSE; mouse_report[0] = REPORT_TYPE_MOUSE;
memcpy(mouse_report + 1, data, 6); memcpy(mouse_report + 1, data, size);
logi_dj_recv_forward_input_report(hdev, mouse_report, 7); logi_dj_recv_forward_input_report(hdev, mouse_report,
size + 1);
} }
return false; return false;
...@@ -1650,6 +1661,7 @@ static int logi_dj_probe(struct hid_device *hdev, ...@@ -1650,6 +1661,7 @@ static int logi_dj_probe(struct hid_device *hdev,
case recvr_type_dj: no_dj_interfaces = 3; break; case recvr_type_dj: no_dj_interfaces = 3; break;
case recvr_type_hidpp: no_dj_interfaces = 2; break; case recvr_type_hidpp: no_dj_interfaces = 2; break;
case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break; case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break;
case recvr_type_mouse_only: no_dj_interfaces = 2; break;
case recvr_type_27mhz: no_dj_interfaces = 2; break; case recvr_type_27mhz: no_dj_interfaces = 2; break;
case recvr_type_bluetooth: no_dj_interfaces = 2; break; case recvr_type_bluetooth: no_dj_interfaces = 2; break;
} }
...@@ -1823,10 +1835,10 @@ static const struct hid_device_id logi_dj_receivers[] = { ...@@ -1823,10 +1835,10 @@ static const struct hid_device_id logi_dj_receivers[] = {
{HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2), USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2),
.driver_data = recvr_type_dj}, .driver_data = recvr_type_dj},
{ /* Logitech Nano (non DJ) receiver */ { /* Logitech Nano mouse only receiver */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER),
.driver_data = recvr_type_hidpp}, .driver_data = recvr_type_mouse_only},
{ /* Logitech Nano (non DJ) receiver */ { /* Logitech Nano (non DJ) receiver */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment