aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-05-05 17:12:50 -0400
committerJiri Kosina <jkosina@suse.cz>2013-06-03 05:07:00 -0400
commitd758b1f0c527aedc5e83a565a0737d9ac21ea46a (patch)
tree20707221091b2e594df2e18a164d94ccf2e05490 /drivers
parent6b80bb94dc61a7f702df13c6c7e8edee331d0a9a (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/hid-wiimote-core.c24
-rw-r--r--drivers/hid/hid-wiimote.h19
2 files changed, 38 insertions, 5 deletions
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 00a9b6fa5189..a025d2104d3c 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -58,11 +58,11 @@ static enum power_supply_property wiimote_battery_props[] = {
58 58
59/* output queue handling */ 59/* output queue handling */
60 60
61static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, 61static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
62 size_t count) 62 size_t count)
63{ 63{
64 __u8 *buf; 64 __u8 *buf;
65 ssize_t ret; 65 int ret;
66 66
67 if (!hdev->hid_output_raw_report) 67 if (!hdev->hid_output_raw_report)
68 return -ENODEV; 68 return -ENODEV;
@@ -84,14 +84,20 @@ static void wiimote_queue_worker(struct work_struct *work)
84 struct wiimote_data *wdata = container_of(queue, struct wiimote_data, 84 struct wiimote_data *wdata = container_of(queue, struct wiimote_data,
85 queue); 85 queue);
86 unsigned long flags; 86 unsigned long flags;
87 int ret;
87 88
88 spin_lock_irqsave(&wdata->queue.lock, flags); 89 spin_lock_irqsave(&wdata->queue.lock, flags);
89 90
90 while (wdata->queue.head != wdata->queue.tail) { 91 while (wdata->queue.head != wdata->queue.tail) {
91 spin_unlock_irqrestore(&wdata->queue.lock, flags); 92 spin_unlock_irqrestore(&wdata->queue.lock, flags);
92 wiimote_hid_send(wdata->hdev, 93 ret = wiimote_hid_send(wdata->hdev,
93 wdata->queue.outq[wdata->queue.tail].data, 94 wdata->queue.outq[wdata->queue.tail].data,
94 wdata->queue.outq[wdata->queue.tail].size); 95 wdata->queue.outq[wdata->queue.tail].size);
96 if (ret < 0) {
97 spin_lock_irqsave(&wdata->state.lock, flags);
98 wiimote_cmd_abort(wdata);
99 spin_unlock_irqrestore(&wdata->state.lock, flags);
100 }
95 spin_lock_irqsave(&wdata->queue.lock, flags); 101 spin_lock_irqsave(&wdata->queue.lock, flags);
96 102
97 wdata->queue.tail = (wdata->queue.tail + 1) % WIIMOTE_BUFSIZE; 103 wdata->queue.tail = (wdata->queue.tail + 1) % WIIMOTE_BUFSIZE;
@@ -108,7 +114,9 @@ static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
108 114
109 if (count > HID_MAX_BUFFER_SIZE) { 115 if (count > HID_MAX_BUFFER_SIZE) {
110 hid_warn(wdata->hdev, "Sending too large output report\n"); 116 hid_warn(wdata->hdev, "Sending too large output report\n");
111 return; 117
118 spin_lock_irqsave(&wdata->queue.lock, flags);
119 goto out_error;
112 } 120 }
113 121
114 /* 122 /*
@@ -134,8 +142,14 @@ static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
134 wdata->queue.head = newhead; 142 wdata->queue.head = newhead;
135 } else { 143 } else {
136 hid_warn(wdata->hdev, "Output queue is full"); 144 hid_warn(wdata->hdev, "Output queue is full");
145 goto out_error;
137 } 146 }
138 147
148 goto out_unlock;
149
150out_error:
151 wiimote_cmd_abort(wdata);
152out_unlock:
139 spin_unlock_irqrestore(&wdata->queue.lock, flags); 153 spin_unlock_irqrestore(&wdata->queue.lock, flags);
140} 154}
141 155
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 301607da7715..34417021606e 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -195,6 +195,16 @@ static inline void wiimote_cmd_complete(struct wiimote_data *wdata)
195 complete(&wdata->state.ready); 195 complete(&wdata->state.ready);
196} 196}
197 197
198/* requires the state.lock spinlock to be held */
199static inline void wiimote_cmd_abort(struct wiimote_data *wdata)
200{
201 /* Abort synchronous request by waking up the sleeping caller. But
202 * reset the state.cmd field to an invalid value so no further event
203 * handlers will work with it. */
204 wdata->state.cmd = WIIPROTO_REQ_MAX;
205 complete(&wdata->state.ready);
206}
207
198static inline int wiimote_cmd_acquire(struct wiimote_data *wdata) 208static inline int wiimote_cmd_acquire(struct wiimote_data *wdata)
199{ 209{
200 return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0; 210 return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0;
@@ -223,11 +233,17 @@ static inline int wiimote_cmd_wait(struct wiimote_data *wdata)
223{ 233{
224 int ret; 234 int ret;
225 235
236 /* The completion acts as implicit memory barrier so we can safely
237 * assume that state.cmd is set on success/failure and isn't accessed
238 * by any other thread, anymore. */
239
226 ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ); 240 ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ);
227 if (ret < 0) 241 if (ret < 0)
228 return -ERESTARTSYS; 242 return -ERESTARTSYS;
229 else if (ret == 0) 243 else if (ret == 0)
230 return -EIO; 244 return -EIO;
245 else if (wdata->state.cmd != WIIPROTO_REQ_NULL)
246 return -EIO;
231 else 247 else
232 return 0; 248 return 0;
233} 249}
@@ -236,9 +252,12 @@ static inline int wiimote_cmd_wait_noint(struct wiimote_data *wdata)
236{ 252{
237 unsigned long ret; 253 unsigned long ret;
238 254
255 /* no locking needed; see wiimote_cmd_wait() */
239 ret = wait_for_completion_timeout(&wdata->state.ready, HZ); 256 ret = wait_for_completion_timeout(&wdata->state.ready, HZ);
240 if (!ret) 257 if (!ret)
241 return -EIO; 258 return -EIO;
259 else if (wdata->state.cmd != WIIPROTO_REQ_NULL)
260 return -EIO;
242 else 261 else
243 return 0; 262 return 0;
244} 263}