diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hid/hid-wiimote-core.c | 24 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote.h | 19 |
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 | ||
61 | static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, | 61 | static 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 | |||
150 | out_error: | ||
151 | wiimote_cmd_abort(wdata); | ||
152 | out_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 */ | ||
199 | static 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 | |||
198 | static inline int wiimote_cmd_acquire(struct wiimote_data *wdata) | 208 | static 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 | } |