Commit 586e8fed authored by Bastien Nocera's avatar Bastien Nocera Committed by Benjamin Tissoires

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: default avatarBastien Nocera <hadess@hadess.net>
Link: https://lore.kernel.org/r/20230209154916.462158-1-hadess@hadess.netSigned-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
parent a47a3b7a
...@@ -283,6 +283,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, ...@@ -283,6 +283,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
struct hidpp_report *response) struct hidpp_report *response)
{ {
int ret; int ret;
int max_retries = 3;
mutex_lock(&hidpp->send_mutex); mutex_lock(&hidpp->send_mutex);
...@@ -295,34 +296,39 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, ...@@ -295,34 +296,39 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
*/ */
*response = *message; *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) { if (ret) {
dbg_hid("__hidpp_send_report returned err: %d\n", ret); dbg_hid("__hidpp_send_report returned err: %d\n", ret);
memset(response, 0, sizeof(struct hidpp_report)); memset(response, 0, sizeof(struct hidpp_report));
goto exit; goto exit;
} }
if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
5*HZ)) { 5*HZ)) {
dbg_hid("%s:timeout waiting for response\n", __func__); dbg_hid("%s:timeout waiting for response\n", __func__);
memset(response, 0, sizeof(struct hidpp_report)); memset(response, 0, sizeof(struct hidpp_report));
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} }
if (response->report_id == REPORT_ID_HIDPP_SHORT && if (response->report_id == REPORT_ID_HIDPP_SHORT &&
response->rap.sub_id == HIDPP_ERROR) { response->rap.sub_id == HIDPP_ERROR) {
ret = response->rap.params[1]; ret = response->rap.params[1];
dbg_hid("%s:got hidpp error %02X\n", __func__, ret); dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
goto exit; goto exit;
} }
if ((response->report_id == REPORT_ID_HIDPP_LONG || if ((response->report_id == REPORT_ID_HIDPP_LONG ||
response->report_id == REPORT_ID_HIDPP_VERY_LONG) && response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
response->fap.feature_index == HIDPP20_ERROR) { response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1]; ret = response->fap.params[1];
dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); if (ret != HIDPP20_ERROR_BUSY) {
goto exit; 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: exit:
......
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