HID: logitech-hidpp: Retry commands when device is busy
authorBastien Nocera <hadess@hadess.net>
Thu, 9 Feb 2023 15:49:15 +0000 (16:49 +0100)
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>
Wed, 15 Feb 2023 10:43:48 +0000 (11:43 +0100)
Handle the busy error coming from the device or receiver. The
documentation says a busy error can be returned when:
"
Device (or receiver) cannot answer immediately to this request
for any reason i.e:
- already processing a request from the same or another SW
- pipe full
"

Signed-off-by: Bastien Nocera <hadess@hadess.net>
Link: https://lore.kernel.org/r/20230209154916.462158-1-hadess@hadess.net
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
drivers/hid/hid-logitech-hidpp.c

index ef90252cf1ae594e78a9881819f41074bb81e85f..845920465d83e88b21038977725241a075c5d01a 100644 (file)
@@ -283,6 +283,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
        struct hidpp_report *response)
 {
        int ret;
+       int max_retries = 3;
 
        mutex_lock(&hidpp->send_mutex);
 
@@ -295,34 +296,39 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
         */
        *response = *message;
 
-       ret = __hidpp_send_report(hidpp->hid_dev, message);
+       for (; max_retries != 0; max_retries--) {
+               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));
-               goto exit;
-       }
+               if (ret) {
+                       dbg_hid("__hidpp_send_report returned err: %d\n", ret);
+                       memset(response, 0, sizeof(struct hidpp_report));
+                       goto exit;
+               }
 
-       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;
-       }
+               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;
+               }
 
-       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);
-               goto exit;
-       }
+               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);
+                       goto exit;
+               }
 
-       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);
-               goto exit;
+               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);
+                               goto exit;
+                       }
+                       dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret);
+               }
        }
 
 exit: