HID: wiimote: wake up if output queue failed
Our output queue is asynchronous but synchronous reports may wait for a
response to their request. Therefore, wake them up unconditionally if an
output report couldn't be sent. But keep the report ID intact so we don't
incorrectly assume our request succeeded.
Note that the underlying connection is required to be reliable and does
retransmission itself. So it is safe to assume that if the transmission
fails, the device is in inconsistent state. Hence, we abort every request
if any output report fails. No need to verify which report failed.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 00a9b6f..a025d21 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -58,11 +58,11 @@
/* output queue handling */
-static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
- size_t count)
+static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
+ size_t count)
{
__u8 *buf;
- ssize_t ret;
+ int ret;
if (!hdev->hid_output_raw_report)
return -ENODEV;
@@ -84,14 +84,20 @@
struct wiimote_data *wdata = container_of(queue, struct wiimote_data,
queue);
unsigned long flags;
+ int ret;
spin_lock_irqsave(&wdata->queue.lock, flags);
while (wdata->queue.head != wdata->queue.tail) {
spin_unlock_irqrestore(&wdata->queue.lock, flags);
- wiimote_hid_send(wdata->hdev,
+ ret = wiimote_hid_send(wdata->hdev,
wdata->queue.outq[wdata->queue.tail].data,
wdata->queue.outq[wdata->queue.tail].size);
+ if (ret < 0) {
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_abort(wdata);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ }
spin_lock_irqsave(&wdata->queue.lock, flags);
wdata->queue.tail = (wdata->queue.tail + 1) % WIIMOTE_BUFSIZE;
@@ -108,7 +114,9 @@
if (count > HID_MAX_BUFFER_SIZE) {
hid_warn(wdata->hdev, "Sending too large output report\n");
- return;
+
+ spin_lock_irqsave(&wdata->queue.lock, flags);
+ goto out_error;
}
/*
@@ -134,8 +142,14 @@
wdata->queue.head = newhead;
} else {
hid_warn(wdata->hdev, "Output queue is full");
+ goto out_error;
}
+ goto out_unlock;
+
+out_error:
+ wiimote_cmd_abort(wdata);
+out_unlock:
spin_unlock_irqrestore(&wdata->queue.lock, flags);
}