Merge branch 'for-6.6/logitech' into for-linus
authorBenjamin Tissoires <bentiss@kernel.org>
Thu, 31 Aug 2023 08:40:46 +0000 (10:40 +0200)
committerBenjamin Tissoires <bentiss@kernel.org>
Thu, 31 Aug 2023 08:41:52 +0000 (10:41 +0200)
Various new device ID addition and a couple of HID++
fixes to tackle the last few opened bugs (Nikita Zhandarovich
and Benjamin Tissoires)

drivers/hid/hid-ids.h
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-hidpp.c

index 42c43d3..7e49999 100644 (file)
 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2         0xc534
 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1      0xc539
 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1    0xc53f
+#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2    0xc547
 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
 #define USB_DEVICE_ID_SPACETRAVELLER   0xc623
 #define USB_DEVICE_ID_SPACENAVIGATOR   0xc626
index 6218041..8afe3be 100644 (file)
@@ -1285,6 +1285,9 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
                 * 50 msec should gives enough time to the receiver to be ready.
                 */
                msleep(50);
+
+               if (retval)
+                       return retval;
        }
 
        /*
@@ -1306,7 +1309,7 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
        buf[5] = 0x09;
        buf[6] = 0x00;
 
-       hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf,
+       retval = hid_hw_raw_request(hdev, REPORT_ID_HIDPP_SHORT, buf,
                        HIDPP_REPORT_SHORT_LENGTH, HID_OUTPUT_REPORT,
                        HID_REQ_SET_REPORT);
 
@@ -1692,11 +1695,12 @@ static int logi_dj_raw_event(struct hid_device *hdev,
                }
                /*
                 * Mouse-only receivers send unnumbered mouse data. The 27 MHz
-                * receiver uses 6 byte packets, the nano receiver 8 bytes.
+                * receiver uses 6 byte packets, the nano receiver 8 bytes,
+                * the lightspeed receiver (Pro X Superlight) 13 bytes.
                 */
                if (djrcv_dev->unnumbered_application == HID_GD_MOUSE &&
-                   size <= 8) {
-                       u8 mouse_report[9];
+                   size <= 13){
+                       u8 mouse_report[14];
 
                        /* Prepend report id */
                        mouse_report[0] = REPORT_TYPE_MOUSE;
@@ -1980,6 +1984,10 @@ static const struct hid_device_id logi_dj_receivers[] = {
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
                USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1),
         .driver_data = recvr_type_gaming_hidpp},
+       { /* Logitech lightspeed receiver (0xc547) */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+               USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2),
+        .driver_data = recvr_type_gaming_hidpp},
 
        { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
index 129b01b..05f5b5f 100644 (file)
@@ -228,7 +228,7 @@ struct hidpp_device {
 #define HIDPP20_ERROR_INVALID_ARGS             0x02
 #define HIDPP20_ERROR_OUT_OF_RANGE             0x03
 #define HIDPP20_ERROR_HW_ERROR                 0x04
-#define HIDPP20_ERROR_LOGITECH_INTERNAL                0x05
+#define HIDPP20_ERROR_NOT_ALLOWED              0x05
 #define HIDPP20_ERROR_INVALID_FEATURE_INDEX    0x06
 #define HIDPP20_ERROR_INVALID_FUNCTION_ID      0x07
 #define HIDPP20_ERROR_BUSY                     0x08
@@ -275,21 +275,22 @@ static int __hidpp_send_report(struct hid_device *hdev,
 }
 
 /*
- * hidpp_send_message_sync() returns 0 in case of success, and something else
- * in case of a failure.
- * - If ' something else' is positive, that means that an error has been raised
- *   by the protocol itself.
- * - If ' something else' is negative, that means that we had a classic error
- *   (-ENOMEM, -EPIPE, etc...)
+ * Effectively send the message to the device, waiting for its answer.
+ *
+ * Must be called with hidpp->send_mutex locked
+ *
+ * Same return protocol than hidpp_send_message_sync():
+ * - success on 0
+ * - negative error means transport error
+ * - positive value means protocol error
  */
-static int hidpp_send_message_sync(struct hidpp_device *hidpp,
+static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp,
        struct hidpp_report *message,
        struct hidpp_report *response)
 {
-       int ret = -1;
-       int max_retries = 3;
+       int ret;
 
-       mutex_lock(&hidpp->send_mutex);
+       __must_hold(&hidpp->send_mutex);
 
        hidpp->send_receive_buf = response;
        hidpp->answer_available = false;
@@ -300,47 +301,74 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
         */
        *response = *message;
 
-       for (; max_retries != 0 && ret; max_retries--) {
-               ret = __hidpp_send_report(hidpp->hid_dev, message);
+       ret = __hidpp_send_report(hidpp->hid_dev, message);
+       if (ret) {
+               dbg_hid("__hidpp_send_report returned err: %d\n", ret);
+               memset(response, 0, sizeof(struct hidpp_report));
+               return ret;
+       }
 
-               if (ret) {
-                       dbg_hid("__hidpp_send_report returned err: %d\n", ret);
-                       memset(response, 0, sizeof(struct hidpp_report));
-                       break;
-               }
+       if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
+                               5*HZ)) {
+               dbg_hid("%s:timeout waiting for response\n", __func__);
+               memset(response, 0, sizeof(struct hidpp_report));
+               return -ETIMEDOUT;
+       }
 
-               if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
-                                       5*HZ)) {
-                       dbg_hid("%s:timeout waiting for response\n", __func__);
-                       memset(response, 0, sizeof(struct hidpp_report));
-                       ret = -ETIMEDOUT;
-                       break;
-               }
+       if (response->report_id == REPORT_ID_HIDPP_SHORT &&
+           response->rap.sub_id == HIDPP_ERROR) {
+               ret = response->rap.params[1];
+               dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
+               return ret;
+       }
 
-               if (response->report_id == REPORT_ID_HIDPP_SHORT &&
-                   response->rap.sub_id == HIDPP_ERROR) {
-                       ret = response->rap.params[1];
-                       dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
+       if ((response->report_id == REPORT_ID_HIDPP_LONG ||
+            response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
+           response->fap.feature_index == HIDPP20_ERROR) {
+               ret = response->fap.params[1];
+               dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * hidpp_send_message_sync() returns 0 in case of success, and something else
+ * in case of a failure.
+ *
+ * See __do_hidpp_send_message_sync() for a detailed explanation of the returned
+ * value.
+ */
+static int hidpp_send_message_sync(struct hidpp_device *hidpp,
+       struct hidpp_report *message,
+       struct hidpp_report *response)
+{
+       int ret;
+       int max_retries = 3;
+
+       mutex_lock(&hidpp->send_mutex);
+
+       do {
+               ret = __do_hidpp_send_message_sync(hidpp, message, response);
+               if (ret != HIDPP20_ERROR_BUSY)
                        break;
-               }
 
-               if ((response->report_id == REPORT_ID_HIDPP_LONG ||
-                    response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
-                   response->fap.feature_index == HIDPP20_ERROR) {
-                       ret = response->fap.params[1];
-                       if (ret != HIDPP20_ERROR_BUSY) {
-                               dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
-                               break;
-                       }
-                       dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret);
-               }
-       }
+               dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret);
+       } while (--max_retries);
 
        mutex_unlock(&hidpp->send_mutex);
        return ret;
 
 }
 
+/*
+ * hidpp_send_fap_command_sync() returns 0 in case of success, and something else
+ * in case of a failure.
+ *
+ * See __do_hidpp_send_message_sync() for a detailed explanation of the returned
+ * value.
+ */
 static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
        u8 feat_index, u8 funcindex_clientid, u8 *params, int param_count,
        struct hidpp_report *response)
@@ -373,6 +401,13 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
        return ret;
 }
 
+/*
+ * hidpp_send_rap_command_sync() returns 0 in case of success, and something else
+ * in case of a failure.
+ *
+ * See __do_hidpp_send_message_sync() for a detailed explanation of the returned
+ * value.
+ */
 static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
        u8 report_id, u8 sub_id, u8 reg_address, u8 *params, int param_count,
        struct hidpp_report *response)
@@ -4620,6 +4655,8 @@ static const struct hid_device_id hidpp_devices[] = {
                .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS },
        { /* Logitech G Pro Gaming Mouse over USB */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
+       { /* Logitech G Pro X Superlight Gaming Mouse over USB */
+         HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) },
 
        { /* G935 Gaming Headset */
          HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87),
@@ -4647,6 +4684,8 @@ static const struct hid_device_id hidpp_devices[] = {
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) },
        { /* MX Master 3 mouse over Bluetooth */
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) },
+       { /* MX Anywhere 3 mouse over Bluetooth */
+         HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb025) },
        { /* MX Master 3S mouse over Bluetooth */
          HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) },
        {}