summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2023-02-09 18:49:15 +0300
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>2023-02-15 13:43:48 +0300
commit586e8fede7953b1695b5ccc6112eff9b052e79ac (patch)
tree0600259980615ea64eee9520d5331b152be216aa /drivers/hid
parenta47a3b7af7501c3b6cee6621ccc4a7dd3de52631 (diff)
downloadlinux-586e8fede7953b1695b5ccc6112eff9b052e79ac.tar.xz
HID: logitech-hidpp: Retry commands when device is busy
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>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-logitech-hidpp.c54
1 files changed, 30 insertions, 24 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index ef90252cf1ae..845920465d83 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -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: