Commit 464b241575f3700e14492e34f26bcd1794280f55
1 parent
6addb1d6de
Exists in
master
and in
20 other branches
Input: mousedev - implement proper locking
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 1 changed file with 470 additions and 272 deletions Side-by-side Diff
drivers/input/mousedev.c
Changes suppressed. Click to show
... | ... | @@ -61,9 +61,11 @@ |
61 | 61 | int open; |
62 | 62 | int minor; |
63 | 63 | char name[16]; |
64 | + struct input_handle handle; | |
64 | 65 | wait_queue_head_t wait; |
65 | 66 | struct list_head client_list; |
66 | - struct input_handle handle; | |
67 | + spinlock_t client_lock; /* protects client_list */ | |
68 | + struct mutex mutex; | |
67 | 69 | struct device dev; |
68 | 70 | |
69 | 71 | struct list_head mixdev_node; |
70 | 72 | |
71 | 73 | |
72 | 74 | |
73 | 75 | |
74 | 76 | |
75 | 77 | |
76 | 78 | |
77 | 79 | |
78 | 80 | |
79 | 81 | |
80 | 82 | |
... | ... | @@ -113,108 +115,137 @@ |
113 | 115 | static struct input_handler mousedev_handler; |
114 | 116 | |
115 | 117 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; |
118 | +static DEFINE_MUTEX(mousedev_table_mutex); | |
116 | 119 | static struct mousedev *mousedev_mix; |
117 | 120 | static LIST_HEAD(mousedev_mix_list); |
118 | 121 | |
122 | +static void mixdev_open_devices(void); | |
123 | +static void mixdev_close_devices(void); | |
124 | + | |
119 | 125 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) |
120 | 126 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) |
121 | 127 | |
122 | -static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) | |
128 | +static void mousedev_touchpad_event(struct input_dev *dev, | |
129 | + struct mousedev *mousedev, | |
130 | + unsigned int code, int value) | |
123 | 131 | { |
124 | 132 | int size, tmp; |
125 | 133 | enum { FRACTION_DENOM = 128 }; |
126 | 134 | |
127 | 135 | switch (code) { |
128 | - case ABS_X: | |
129 | - fx(0) = value; | |
130 | - if (mousedev->touch && mousedev->pkt_count >= 2) { | |
131 | - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | |
132 | - if (size == 0) | |
133 | - size = 256 * 2; | |
134 | - tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; | |
135 | - tmp += mousedev->frac_dx; | |
136 | - mousedev->packet.dx = tmp / FRACTION_DENOM; | |
137 | - mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; | |
138 | - } | |
139 | - break; | |
140 | 136 | |
141 | - case ABS_Y: | |
142 | - fy(0) = value; | |
143 | - if (mousedev->touch && mousedev->pkt_count >= 2) { | |
144 | - /* use X size to keep the same scale */ | |
145 | - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | |
146 | - if (size == 0) | |
147 | - size = 256 * 2; | |
148 | - tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; | |
149 | - tmp += mousedev->frac_dy; | |
150 | - mousedev->packet.dy = tmp / FRACTION_DENOM; | |
151 | - mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; | |
152 | - } | |
153 | - break; | |
137 | + case ABS_X: | |
138 | + fx(0) = value; | |
139 | + if (mousedev->touch && mousedev->pkt_count >= 2) { | |
140 | + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | |
141 | + if (size == 0) | |
142 | + size = 256 * 2; | |
143 | + tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; | |
144 | + tmp += mousedev->frac_dx; | |
145 | + mousedev->packet.dx = tmp / FRACTION_DENOM; | |
146 | + mousedev->frac_dx = | |
147 | + tmp - mousedev->packet.dx * FRACTION_DENOM; | |
148 | + } | |
149 | + break; | |
150 | + | |
151 | + case ABS_Y: | |
152 | + fy(0) = value; | |
153 | + if (mousedev->touch && mousedev->pkt_count >= 2) { | |
154 | + /* use X size to keep the same scale */ | |
155 | + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | |
156 | + if (size == 0) | |
157 | + size = 256 * 2; | |
158 | + tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size; | |
159 | + tmp += mousedev->frac_dy; | |
160 | + mousedev->packet.dy = tmp / FRACTION_DENOM; | |
161 | + mousedev->frac_dy = tmp - | |
162 | + mousedev->packet.dy * FRACTION_DENOM; | |
163 | + } | |
164 | + break; | |
154 | 165 | } |
155 | 166 | } |
156 | 167 | |
157 | -static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) | |
168 | +static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, | |
169 | + unsigned int code, int value) | |
158 | 170 | { |
159 | 171 | int size; |
160 | 172 | |
161 | 173 | switch (code) { |
162 | - case ABS_X: | |
163 | - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | |
164 | - if (size == 0) | |
165 | - size = xres ? : 1; | |
166 | - if (value > dev->absmax[ABS_X]) | |
167 | - value = dev->absmax[ABS_X]; | |
168 | - if (value < dev->absmin[ABS_X]) | |
169 | - value = dev->absmin[ABS_X]; | |
170 | - mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; | |
171 | - mousedev->packet.abs_event = 1; | |
172 | - break; | |
173 | 174 | |
174 | - case ABS_Y: | |
175 | - size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | |
176 | - if (size == 0) | |
177 | - size = yres ? : 1; | |
178 | - if (value > dev->absmax[ABS_Y]) | |
179 | - value = dev->absmax[ABS_Y]; | |
180 | - if (value < dev->absmin[ABS_Y]) | |
181 | - value = dev->absmin[ABS_Y]; | |
182 | - mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; | |
183 | - mousedev->packet.abs_event = 1; | |
184 | - break; | |
175 | + case ABS_X: | |
176 | + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | |
177 | + if (size == 0) | |
178 | + size = xres ? : 1; | |
179 | + if (value > dev->absmax[ABS_X]) | |
180 | + value = dev->absmax[ABS_X]; | |
181 | + if (value < dev->absmin[ABS_X]) | |
182 | + value = dev->absmin[ABS_X]; | |
183 | + mousedev->packet.x = | |
184 | + ((value - dev->absmin[ABS_X]) * xres) / size; | |
185 | + mousedev->packet.abs_event = 1; | |
186 | + break; | |
187 | + | |
188 | + case ABS_Y: | |
189 | + size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | |
190 | + if (size == 0) | |
191 | + size = yres ? : 1; | |
192 | + if (value > dev->absmax[ABS_Y]) | |
193 | + value = dev->absmax[ABS_Y]; | |
194 | + if (value < dev->absmin[ABS_Y]) | |
195 | + value = dev->absmin[ABS_Y]; | |
196 | + mousedev->packet.y = yres - | |
197 | + ((value - dev->absmin[ABS_Y]) * yres) / size; | |
198 | + mousedev->packet.abs_event = 1; | |
199 | + break; | |
185 | 200 | } |
186 | 201 | } |
187 | 202 | |
188 | -static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value) | |
203 | +static void mousedev_rel_event(struct mousedev *mousedev, | |
204 | + unsigned int code, int value) | |
189 | 205 | { |
190 | 206 | switch (code) { |
191 | - case REL_X: mousedev->packet.dx += value; break; | |
192 | - case REL_Y: mousedev->packet.dy -= value; break; | |
193 | - case REL_WHEEL: mousedev->packet.dz -= value; break; | |
207 | + case REL_X: | |
208 | + mousedev->packet.dx += value; | |
209 | + break; | |
210 | + | |
211 | + case REL_Y: | |
212 | + mousedev->packet.dy -= value; | |
213 | + break; | |
214 | + | |
215 | + case REL_WHEEL: | |
216 | + mousedev->packet.dz -= value; | |
217 | + break; | |
194 | 218 | } |
195 | 219 | } |
196 | 220 | |
197 | -static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value) | |
221 | +static void mousedev_key_event(struct mousedev *mousedev, | |
222 | + unsigned int code, int value) | |
198 | 223 | { |
199 | 224 | int index; |
200 | 225 | |
201 | 226 | switch (code) { |
202 | - case BTN_TOUCH: | |
203 | - case BTN_0: | |
204 | - case BTN_LEFT: index = 0; break; | |
205 | - case BTN_STYLUS: | |
206 | - case BTN_1: | |
207 | - case BTN_RIGHT: index = 1; break; | |
208 | - case BTN_2: | |
209 | - case BTN_FORWARD: | |
210 | - case BTN_STYLUS2: | |
211 | - case BTN_MIDDLE: index = 2; break; | |
212 | - case BTN_3: | |
213 | - case BTN_BACK: | |
214 | - case BTN_SIDE: index = 3; break; | |
215 | - case BTN_4: | |
216 | - case BTN_EXTRA: index = 4; break; | |
217 | - default: return; | |
227 | + | |
228 | + case BTN_TOUCH: | |
229 | + case BTN_0: | |
230 | + case BTN_LEFT: index = 0; break; | |
231 | + | |
232 | + case BTN_STYLUS: | |
233 | + case BTN_1: | |
234 | + case BTN_RIGHT: index = 1; break; | |
235 | + | |
236 | + case BTN_2: | |
237 | + case BTN_FORWARD: | |
238 | + case BTN_STYLUS2: | |
239 | + case BTN_MIDDLE: index = 2; break; | |
240 | + | |
241 | + case BTN_3: | |
242 | + case BTN_BACK: | |
243 | + case BTN_SIDE: index = 3; break; | |
244 | + | |
245 | + case BTN_4: | |
246 | + case BTN_EXTRA: index = 4; break; | |
247 | + | |
248 | + default: return; | |
218 | 249 | } |
219 | 250 | |
220 | 251 | if (value) { |
221 | 252 | |
222 | 253 | |
223 | 254 | |
224 | 255 | |
... | ... | @@ -226,19 +257,22 @@ |
226 | 257 | } |
227 | 258 | } |
228 | 259 | |
229 | -static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) | |
260 | +static void mousedev_notify_readers(struct mousedev *mousedev, | |
261 | + struct mousedev_hw_data *packet) | |
230 | 262 | { |
231 | 263 | struct mousedev_client *client; |
232 | 264 | struct mousedev_motion *p; |
233 | - unsigned long flags; | |
265 | + unsigned int new_head; | |
234 | 266 | int wake_readers = 0; |
235 | 267 | |
236 | - list_for_each_entry(client, &mousedev->client_list, node) { | |
237 | - spin_lock_irqsave(&client->packet_lock, flags); | |
268 | + list_for_each_entry_rcu(client, &mousedev->client_list, node) { | |
238 | 269 | |
270 | + /* Just acquire the lock, interrupts already disabled */ | |
271 | + spin_lock(&client->packet_lock); | |
272 | + | |
239 | 273 | p = &client->packets[client->head]; |
240 | 274 | if (client->ready && p->buttons != mousedev->packet.buttons) { |
241 | - unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN; | |
275 | + new_head = (client->head + 1) % PACKET_QUEUE_LEN; | |
242 | 276 | if (new_head != client->tail) { |
243 | 277 | p = &client->packets[client->head = new_head]; |
244 | 278 | memset(p, 0, sizeof(struct mousedev_motion)); |
245 | 279 | |
246 | 280 | |
247 | 281 | |
... | ... | @@ -253,19 +287,22 @@ |
253 | 287 | } |
254 | 288 | |
255 | 289 | client->pos_x += packet->dx; |
256 | - client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x); | |
290 | + client->pos_x = client->pos_x < 0 ? | |
291 | + 0 : (client->pos_x >= xres ? xres : client->pos_x); | |
257 | 292 | client->pos_y += packet->dy; |
258 | - client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y); | |
293 | + client->pos_y = client->pos_y < 0 ? | |
294 | + 0 : (client->pos_y >= yres ? yres : client->pos_y); | |
259 | 295 | |
260 | 296 | p->dx += packet->dx; |
261 | 297 | p->dy += packet->dy; |
262 | 298 | p->dz += packet->dz; |
263 | 299 | p->buttons = mousedev->packet.buttons; |
264 | 300 | |
265 | - if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons) | |
301 | + if (p->dx || p->dy || p->dz || | |
302 | + p->buttons != client->last_buttons) | |
266 | 303 | client->ready = 1; |
267 | 304 | |
268 | - spin_unlock_irqrestore(&client->packet_lock, flags); | |
305 | + spin_unlock(&client->packet_lock); | |
269 | 306 | |
270 | 307 | if (client->ready) { |
271 | 308 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
... | ... | @@ -281,7 +318,8 @@ |
281 | 318 | { |
282 | 319 | if (!value) { |
283 | 320 | if (mousedev->touch && |
284 | - time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { | |
321 | + time_before(jiffies, | |
322 | + mousedev->touch + msecs_to_jiffies(tap_time))) { | |
285 | 323 | /* |
286 | 324 | * Toggle left button to emulate tap. |
287 | 325 | * We rely on the fact that mousedev_mix always has 0 |
... | ... | @@ -290,7 +328,8 @@ |
290 | 328 | set_bit(0, &mousedev->packet.buttons); |
291 | 329 | set_bit(0, &mousedev_mix->packet.buttons); |
292 | 330 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); |
293 | - mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet); | |
331 | + mousedev_notify_readers(mousedev_mix, | |
332 | + &mousedev_mix->packet); | |
294 | 333 | clear_bit(0, &mousedev->packet.buttons); |
295 | 334 | clear_bit(0, &mousedev_mix->packet.buttons); |
296 | 335 | } |
297 | 336 | |
298 | 337 | |
299 | 338 | |
300 | 339 | |
301 | 340 | |
302 | 341 | |
303 | 342 | |
304 | 343 | |
... | ... | @@ -302,54 +341,61 @@ |
302 | 341 | mousedev->touch = jiffies; |
303 | 342 | } |
304 | 343 | |
305 | -static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | |
344 | +static void mousedev_event(struct input_handle *handle, | |
345 | + unsigned int type, unsigned int code, int value) | |
306 | 346 | { |
307 | 347 | struct mousedev *mousedev = handle->private; |
308 | 348 | |
309 | 349 | switch (type) { |
310 | - case EV_ABS: | |
311 | - /* Ignore joysticks */ | |
312 | - if (test_bit(BTN_TRIGGER, handle->dev->keybit)) | |
313 | - return; | |
314 | 350 | |
315 | - if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | |
316 | - mousedev_touchpad_event(handle->dev, mousedev, code, value); | |
317 | - else | |
318 | - mousedev_abs_event(handle->dev, mousedev, code, value); | |
351 | + case EV_ABS: | |
352 | + /* Ignore joysticks */ | |
353 | + if (test_bit(BTN_TRIGGER, handle->dev->keybit)) | |
354 | + return; | |
319 | 355 | |
320 | - break; | |
356 | + if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | |
357 | + mousedev_touchpad_event(handle->dev, | |
358 | + mousedev, code, value); | |
359 | + else | |
360 | + mousedev_abs_event(handle->dev, mousedev, code, value); | |
321 | 361 | |
322 | - case EV_REL: | |
323 | - mousedev_rel_event(mousedev, code, value); | |
324 | - break; | |
362 | + break; | |
325 | 363 | |
326 | - case EV_KEY: | |
327 | - if (value != 2) { | |
328 | - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | |
329 | - mousedev_touchpad_touch(mousedev, value); | |
330 | - else | |
331 | - mousedev_key_event(mousedev, code, value); | |
332 | - } | |
333 | - break; | |
364 | + case EV_REL: | |
365 | + mousedev_rel_event(mousedev, code, value); | |
366 | + break; | |
334 | 367 | |
335 | - case EV_SYN: | |
336 | - if (code == SYN_REPORT) { | |
337 | - if (mousedev->touch) { | |
338 | - mousedev->pkt_count++; | |
339 | - /* Input system eats duplicate events, but we need all of them | |
340 | - * to do correct averaging so apply present one forward | |
341 | - */ | |
342 | - fx(0) = fx(1); | |
343 | - fy(0) = fy(1); | |
344 | - } | |
368 | + case EV_KEY: | |
369 | + if (value != 2) { | |
370 | + if (code == BTN_TOUCH && | |
371 | + test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | |
372 | + mousedev_touchpad_touch(mousedev, value); | |
373 | + else | |
374 | + mousedev_key_event(mousedev, code, value); | |
375 | + } | |
376 | + break; | |
345 | 377 | |
346 | - mousedev_notify_readers(mousedev, &mousedev->packet); | |
347 | - mousedev_notify_readers(mousedev_mix, &mousedev->packet); | |
348 | - | |
349 | - mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; | |
350 | - mousedev->packet.abs_event = 0; | |
378 | + case EV_SYN: | |
379 | + if (code == SYN_REPORT) { | |
380 | + if (mousedev->touch) { | |
381 | + mousedev->pkt_count++; | |
382 | + /* | |
383 | + * Input system eats duplicate events, | |
384 | + * but we need all of them to do correct | |
385 | + * averaging so apply present one forward | |
386 | + */ | |
387 | + fx(0) = fx(1); | |
388 | + fy(0) = fy(1); | |
351 | 389 | } |
352 | - break; | |
390 | + | |
391 | + mousedev_notify_readers(mousedev, &mousedev->packet); | |
392 | + mousedev_notify_readers(mousedev_mix, &mousedev->packet); | |
393 | + | |
394 | + mousedev->packet.dx = mousedev->packet.dy = | |
395 | + mousedev->packet.dz = 0; | |
396 | + mousedev->packet.abs_event = 0; | |
397 | + } | |
398 | + break; | |
353 | 399 | } |
354 | 400 | } |
355 | 401 | |
356 | 402 | |
357 | 403 | |
358 | 404 | |
359 | 405 | |
360 | 406 | |
361 | 407 | |
362 | 408 | |
363 | 409 | |
364 | 410 | |
... | ... | @@ -367,41 +413,45 @@ |
367 | 413 | { |
368 | 414 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); |
369 | 415 | |
370 | - mousedev_table[mousedev->minor] = NULL; | |
371 | 416 | kfree(mousedev); |
372 | 417 | } |
373 | 418 | |
374 | -static int mixdev_add_device(struct mousedev *mousedev) | |
419 | +static int mousedev_open_device(struct mousedev *mousedev) | |
375 | 420 | { |
376 | - int error; | |
421 | + int retval; | |
377 | 422 | |
378 | - if (mousedev_mix->open) { | |
379 | - error = input_open_device(&mousedev->handle); | |
380 | - if (error) | |
381 | - return error; | |
423 | + retval = mutex_lock_interruptible(&mousedev->mutex); | |
424 | + if (retval) | |
425 | + return retval; | |
382 | 426 | |
383 | - mousedev->open++; | |
384 | - mousedev->mixdev_open = 1; | |
385 | - } | |
427 | + if (mousedev->minor == MOUSEDEV_MIX) | |
428 | + mixdev_open_devices(); | |
429 | + else if (!mousedev->exist) | |
430 | + retval = -ENODEV; | |
431 | + else if (!mousedev->open++) | |
432 | + retval = input_open_device(&mousedev->handle); | |
386 | 433 | |
387 | - get_device(&mousedev->dev); | |
388 | - list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | |
389 | - | |
390 | - return 0; | |
434 | + mutex_unlock(&mousedev->mutex); | |
435 | + return retval; | |
391 | 436 | } |
392 | 437 | |
393 | -static void mixdev_remove_device(struct mousedev *mousedev) | |
438 | +static void mousedev_close_device(struct mousedev *mousedev) | |
394 | 439 | { |
395 | - if (mousedev->mixdev_open) { | |
396 | - mousedev->mixdev_open = 0; | |
397 | - if (!--mousedev->open && mousedev->exist) | |
398 | - input_close_device(&mousedev->handle); | |
399 | - } | |
440 | + mutex_lock(&mousedev->mutex); | |
400 | 441 | |
401 | - list_del_init(&mousedev->mixdev_node); | |
402 | - put_device(&mousedev->dev); | |
442 | + if (mousedev->minor == MOUSEDEV_MIX) | |
443 | + mixdev_close_devices(); | |
444 | + else if (mousedev->exist && !--mousedev->open) | |
445 | + input_close_device(&mousedev->handle); | |
446 | + | |
447 | + mutex_unlock(&mousedev->mutex); | |
403 | 448 | } |
404 | 449 | |
450 | +/* | |
451 | + * Open all available devices so they can all be multiplexed in one. | |
452 | + * stream. Note that this function is called with mousedev_mix->mutex | |
453 | + * held. | |
454 | + */ | |
405 | 455 | static void mixdev_open_devices(void) |
406 | 456 | { |
407 | 457 | struct mousedev *mousedev; |
408 | 458 | |
409 | 459 | |
... | ... | @@ -411,16 +461,19 @@ |
411 | 461 | |
412 | 462 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
413 | 463 | if (!mousedev->mixdev_open) { |
414 | - if (!mousedev->open && mousedev->exist) | |
415 | - if (input_open_device(&mousedev->handle)) | |
416 | - continue; | |
464 | + if (mousedev_open_device(mousedev)) | |
465 | + continue; | |
417 | 466 | |
418 | - mousedev->open++; | |
419 | 467 | mousedev->mixdev_open = 1; |
420 | 468 | } |
421 | 469 | } |
422 | 470 | } |
423 | 471 | |
472 | +/* | |
473 | + * Close all devices that were opened as part of multiplexed | |
474 | + * device. Note that this function is called with mousedev_mix->mutex | |
475 | + * held. | |
476 | + */ | |
424 | 477 | static void mixdev_close_devices(void) |
425 | 478 | { |
426 | 479 | struct mousedev *mousedev; |
427 | 480 | |
428 | 481 | |
429 | 482 | |
430 | 483 | |
... | ... | @@ -431,33 +484,50 @@ |
431 | 484 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
432 | 485 | if (mousedev->mixdev_open) { |
433 | 486 | mousedev->mixdev_open = 0; |
434 | - if (!--mousedev->open && mousedev->exist) | |
435 | - input_close_device(&mousedev->handle); | |
487 | + mousedev_close_device(mousedev); | |
436 | 488 | } |
437 | 489 | } |
438 | 490 | } |
439 | 491 | |
492 | + | |
493 | +static void mousedev_attach_client(struct mousedev *mousedev, | |
494 | + struct mousedev_client *client) | |
495 | +{ | |
496 | + spin_lock(&mousedev->client_lock); | |
497 | + list_add_tail_rcu(&client->node, &mousedev->client_list); | |
498 | + spin_unlock(&mousedev->client_lock); | |
499 | + /* | |
500 | + * We don't use synchronize_rcu() here because read-side | |
501 | + * critical section is protected by a spinlock (dev->event_lock) | |
502 | + * instead of rcu_read_lock(). | |
503 | + */ | |
504 | + synchronize_sched(); | |
505 | +} | |
506 | + | |
507 | +static void mousedev_detach_client(struct mousedev *mousedev, | |
508 | + struct mousedev_client *client) | |
509 | +{ | |
510 | + spin_lock(&mousedev->client_lock); | |
511 | + list_del_rcu(&client->node); | |
512 | + spin_unlock(&mousedev->client_lock); | |
513 | + synchronize_sched(); | |
514 | +} | |
515 | + | |
440 | 516 | static int mousedev_release(struct inode *inode, struct file *file) |
441 | 517 | { |
442 | 518 | struct mousedev_client *client = file->private_data; |
443 | 519 | struct mousedev *mousedev = client->mousedev; |
444 | 520 | |
445 | 521 | mousedev_fasync(-1, file, 0); |
446 | - | |
447 | - list_del(&client->node); | |
522 | + mousedev_detach_client(mousedev, client); | |
448 | 523 | kfree(client); |
449 | 524 | |
450 | - if (mousedev->minor == MOUSEDEV_MIX) | |
451 | - mixdev_close_devices(); | |
452 | - else if (!--mousedev->open && mousedev->exist) | |
453 | - input_close_device(&mousedev->handle); | |
454 | - | |
525 | + mousedev_close_device(mousedev); | |
455 | 526 | put_device(&mousedev->dev); |
456 | 527 | |
457 | 528 | return 0; |
458 | 529 | } |
459 | 530 | |
460 | - | |
461 | 531 | static int mousedev_open(struct inode *inode, struct file *file) |
462 | 532 | { |
463 | 533 | struct mousedev_client *client; |
464 | 534 | |
465 | 535 | |
... | ... | @@ -475,12 +545,17 @@ |
475 | 545 | if (i >= MOUSEDEV_MINORS) |
476 | 546 | return -ENODEV; |
477 | 547 | |
548 | + error = mutex_lock_interruptible(&mousedev_table_mutex); | |
549 | + if (error) | |
550 | + return error; | |
478 | 551 | mousedev = mousedev_table[i]; |
552 | + if (mousedev) | |
553 | + get_device(&mousedev->dev); | |
554 | + mutex_unlock(&mousedev_table_mutex); | |
555 | + | |
479 | 556 | if (!mousedev) |
480 | 557 | return -ENODEV; |
481 | 558 | |
482 | - get_device(&mousedev->dev); | |
483 | - | |
484 | 559 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
485 | 560 | if (!client) { |
486 | 561 | error = -ENOMEM; |
487 | 562 | |
488 | 563 | |
... | ... | @@ -491,21 +566,17 @@ |
491 | 566 | client->pos_x = xres / 2; |
492 | 567 | client->pos_y = yres / 2; |
493 | 568 | client->mousedev = mousedev; |
494 | - list_add_tail(&client->node, &mousedev->client_list); | |
569 | + mousedev_attach_client(mousedev, client); | |
495 | 570 | |
496 | - if (mousedev->minor == MOUSEDEV_MIX) | |
497 | - mixdev_open_devices(); | |
498 | - else if (!mousedev->open++ && mousedev->exist) { | |
499 | - error = input_open_device(&mousedev->handle); | |
500 | - if (error) | |
501 | - goto err_free_client; | |
502 | - } | |
571 | + error = mousedev_open_device(mousedev); | |
572 | + if (error) | |
573 | + goto err_free_client; | |
503 | 574 | |
504 | 575 | file->private_data = client; |
505 | 576 | return 0; |
506 | 577 | |
507 | 578 | err_free_client: |
508 | - list_del(&client->node); | |
579 | + mousedev_detach_client(mousedev, client); | |
509 | 580 | kfree(client); |
510 | 581 | err_put_mousedev: |
511 | 582 | put_device(&mousedev->dev); |
512 | 583 | |
513 | 584 | |
514 | 585 | |
515 | 586 | |
516 | 587 | |
... | ... | @@ -517,41 +588,41 @@ |
517 | 588 | return delta > limit ? limit : (delta < -limit ? -limit : delta); |
518 | 589 | } |
519 | 590 | |
520 | -static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data) | |
591 | +static void mousedev_packet(struct mousedev_client *client, | |
592 | + signed char *ps2_data) | |
521 | 593 | { |
522 | - struct mousedev_motion *p; | |
523 | - unsigned long flags; | |
594 | + struct mousedev_motion *p = &client->packets[client->tail]; | |
524 | 595 | |
525 | - spin_lock_irqsave(&client->packet_lock, flags); | |
526 | - p = &client->packets[client->tail]; | |
527 | - | |
528 | - ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); | |
596 | + ps2_data[0] = 0x08 | | |
597 | + ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); | |
529 | 598 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); |
530 | 599 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); |
531 | 600 | p->dx -= ps2_data[1]; |
532 | 601 | p->dy -= ps2_data[2]; |
533 | 602 | |
534 | 603 | switch (client->mode) { |
535 | - case MOUSEDEV_EMUL_EXPS: | |
536 | - ps2_data[3] = mousedev_limit_delta(p->dz, 7); | |
537 | - p->dz -= ps2_data[3]; | |
538 | - ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); | |
539 | - client->bufsiz = 4; | |
540 | - break; | |
604 | + case MOUSEDEV_EMUL_EXPS: | |
605 | + ps2_data[3] = mousedev_limit_delta(p->dz, 7); | |
606 | + p->dz -= ps2_data[3]; | |
607 | + ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); | |
608 | + client->bufsiz = 4; | |
609 | + break; | |
541 | 610 | |
542 | - case MOUSEDEV_EMUL_IMPS: | |
543 | - ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | |
544 | - ps2_data[3] = mousedev_limit_delta(p->dz, 127); | |
545 | - p->dz -= ps2_data[3]; | |
546 | - client->bufsiz = 4; | |
547 | - break; | |
611 | + case MOUSEDEV_EMUL_IMPS: | |
612 | + ps2_data[0] |= | |
613 | + ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | |
614 | + ps2_data[3] = mousedev_limit_delta(p->dz, 127); | |
615 | + p->dz -= ps2_data[3]; | |
616 | + client->bufsiz = 4; | |
617 | + break; | |
548 | 618 | |
549 | - case MOUSEDEV_EMUL_PS2: | |
550 | - default: | |
551 | - ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | |
552 | - p->dz = 0; | |
553 | - client->bufsiz = 3; | |
554 | - break; | |
619 | + case MOUSEDEV_EMUL_PS2: | |
620 | + default: | |
621 | + ps2_data[0] |= | |
622 | + ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | |
623 | + p->dz = 0; | |
624 | + client->bufsiz = 3; | |
625 | + break; | |
555 | 626 | } |
556 | 627 | |
557 | 628 | if (!p->dx && !p->dy && !p->dz) { |
558 | 629 | |
559 | 630 | |
... | ... | @@ -561,12 +632,56 @@ |
561 | 632 | } else |
562 | 633 | client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; |
563 | 634 | } |
564 | - | |
565 | - spin_unlock_irqrestore(&client->packet_lock, flags); | |
566 | 635 | } |
567 | 636 | |
637 | +static void mousedev_generate_response(struct mousedev_client *client, | |
638 | + int command) | |
639 | +{ | |
640 | + client->ps2[0] = 0xfa; /* ACK */ | |
568 | 641 | |
569 | -static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | |
642 | + switch (command) { | |
643 | + | |
644 | + case 0xeb: /* Poll */ | |
645 | + mousedev_packet(client, &client->ps2[1]); | |
646 | + client->bufsiz++; /* account for leading ACK */ | |
647 | + break; | |
648 | + | |
649 | + case 0xf2: /* Get ID */ | |
650 | + switch (client->mode) { | |
651 | + case MOUSEDEV_EMUL_PS2: | |
652 | + client->ps2[1] = 0; | |
653 | + break; | |
654 | + case MOUSEDEV_EMUL_IMPS: | |
655 | + client->ps2[1] = 3; | |
656 | + break; | |
657 | + case MOUSEDEV_EMUL_EXPS: | |
658 | + client->ps2[1] = 4; | |
659 | + break; | |
660 | + } | |
661 | + client->bufsiz = 2; | |
662 | + break; | |
663 | + | |
664 | + case 0xe9: /* Get info */ | |
665 | + client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; | |
666 | + client->bufsiz = 4; | |
667 | + break; | |
668 | + | |
669 | + case 0xff: /* Reset */ | |
670 | + client->impsseq = client->imexseq = 0; | |
671 | + client->mode = MOUSEDEV_EMUL_PS2; | |
672 | + client->ps2[1] = 0xaa; client->ps2[2] = 0x00; | |
673 | + client->bufsiz = 3; | |
674 | + break; | |
675 | + | |
676 | + default: | |
677 | + client->bufsiz = 1; | |
678 | + break; | |
679 | + } | |
680 | + client->buffer = client->bufsiz; | |
681 | +} | |
682 | + | |
683 | +static ssize_t mousedev_write(struct file *file, const char __user *buffer, | |
684 | + size_t count, loff_t *ppos) | |
570 | 685 | { |
571 | 686 | struct mousedev_client *client = file->private_data; |
572 | 687 | unsigned char c; |
... | ... | @@ -577,6 +692,8 @@ |
577 | 692 | if (get_user(c, buffer + i)) |
578 | 693 | return -EFAULT; |
579 | 694 | |
695 | + spin_lock_irq(&client->packet_lock); | |
696 | + | |
580 | 697 | if (c == mousedev_imex_seq[client->imexseq]) { |
581 | 698 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { |
582 | 699 | client->imexseq = 0; |
583 | 700 | |
584 | 701 | |
585 | 702 | |
586 | 703 | |
587 | 704 | |
588 | 705 | |
589 | 706 | |
590 | 707 | |
... | ... | @@ -593,68 +710,39 @@ |
593 | 710 | } else |
594 | 711 | client->impsseq = 0; |
595 | 712 | |
596 | - client->ps2[0] = 0xfa; | |
713 | + mousedev_generate_response(client, c); | |
597 | 714 | |
598 | - switch (c) { | |
599 | - | |
600 | - case 0xeb: /* Poll */ | |
601 | - mousedev_packet(client, &client->ps2[1]); | |
602 | - client->bufsiz++; /* account for leading ACK */ | |
603 | - break; | |
604 | - | |
605 | - case 0xf2: /* Get ID */ | |
606 | - switch (client->mode) { | |
607 | - case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break; | |
608 | - case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break; | |
609 | - case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break; | |
610 | - } | |
611 | - client->bufsiz = 2; | |
612 | - break; | |
613 | - | |
614 | - case 0xe9: /* Get info */ | |
615 | - client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; | |
616 | - client->bufsiz = 4; | |
617 | - break; | |
618 | - | |
619 | - case 0xff: /* Reset */ | |
620 | - client->impsseq = client->imexseq = 0; | |
621 | - client->mode = MOUSEDEV_EMUL_PS2; | |
622 | - client->ps2[1] = 0xaa; client->ps2[2] = 0x00; | |
623 | - client->bufsiz = 3; | |
624 | - break; | |
625 | - | |
626 | - default: | |
627 | - client->bufsiz = 1; | |
628 | - break; | |
629 | - } | |
630 | - | |
631 | - client->buffer = client->bufsiz; | |
715 | + spin_unlock_irq(&client->packet_lock); | |
632 | 716 | } |
633 | 717 | |
634 | 718 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
635 | - | |
636 | 719 | wake_up_interruptible(&client->mousedev->wait); |
637 | 720 | |
638 | 721 | return count; |
639 | 722 | } |
640 | 723 | |
641 | -static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | |
724 | +static ssize_t mousedev_read(struct file *file, char __user *buffer, | |
725 | + size_t count, loff_t *ppos) | |
642 | 726 | { |
643 | 727 | struct mousedev_client *client = file->private_data; |
728 | + struct mousedev *mousedev = client->mousedev; | |
729 | + signed char data[sizeof(client->ps2)]; | |
644 | 730 | int retval = 0; |
645 | 731 | |
646 | - if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK)) | |
732 | + if (!client->ready && !client->buffer && mousedev->exist && | |
733 | + (file->f_flags & O_NONBLOCK)) | |
647 | 734 | return -EAGAIN; |
648 | 735 | |
649 | - retval = wait_event_interruptible(client->mousedev->wait, | |
650 | - !client->mousedev->exist || client->ready || client->buffer); | |
651 | - | |
736 | + retval = wait_event_interruptible(mousedev->wait, | |
737 | + !mousedev->exist || client->ready || client->buffer); | |
652 | 738 | if (retval) |
653 | 739 | return retval; |
654 | 740 | |
655 | - if (!client->mousedev->exist) | |
741 | + if (!mousedev->exist) | |
656 | 742 | return -ENODEV; |
657 | 743 | |
744 | + spin_lock_irq(&client->packet_lock); | |
745 | + | |
658 | 746 | if (!client->buffer && client->ready) { |
659 | 747 | mousedev_packet(client, client->ps2); |
660 | 748 | client->buffer = client->bufsiz; |
661 | 749 | |
... | ... | @@ -663,9 +751,12 @@ |
663 | 751 | if (count > client->buffer) |
664 | 752 | count = client->buffer; |
665 | 753 | |
754 | + memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); | |
666 | 755 | client->buffer -= count; |
667 | 756 | |
668 | - if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count)) | |
757 | + spin_unlock_irq(&client->packet_lock); | |
758 | + | |
759 | + if (copy_to_user(buffer, data, count)) | |
669 | 760 | return -EFAULT; |
670 | 761 | |
671 | 762 | return count; |
... | ... | @@ -692,6 +783,60 @@ |
692 | 783 | .fasync = mousedev_fasync, |
693 | 784 | }; |
694 | 785 | |
786 | +static int mousedev_install_chrdev(struct mousedev *mousedev) | |
787 | +{ | |
788 | + mousedev_table[mousedev->minor] = mousedev; | |
789 | + return 0; | |
790 | +} | |
791 | + | |
792 | +static void mousedev_remove_chrdev(struct mousedev *mousedev) | |
793 | +{ | |
794 | + mutex_lock(&mousedev_table_mutex); | |
795 | + mousedev_table[mousedev->minor] = NULL; | |
796 | + mutex_unlock(&mousedev_table_mutex); | |
797 | +} | |
798 | + | |
799 | +/* | |
800 | + * Mark device non-existent. This disables writes, ioctls and | |
801 | + * prevents new users from opening the device. Already posted | |
802 | + * blocking reads will stay, however new ones will fail. | |
803 | + */ | |
804 | +static void mousedev_mark_dead(struct mousedev *mousedev) | |
805 | +{ | |
806 | + mutex_lock(&mousedev->mutex); | |
807 | + mousedev->exist = 0; | |
808 | + mutex_unlock(&mousedev->mutex); | |
809 | +} | |
810 | + | |
811 | +/* | |
812 | + * Wake up users waiting for IO so they can disconnect from | |
813 | + * dead device. | |
814 | + */ | |
815 | +static void mousedev_hangup(struct mousedev *mousedev) | |
816 | +{ | |
817 | + struct mousedev_client *client; | |
818 | + | |
819 | + spin_lock(&mousedev->client_lock); | |
820 | + list_for_each_entry(client, &mousedev->client_list, node) | |
821 | + kill_fasync(&client->fasync, SIGIO, POLL_HUP); | |
822 | + spin_unlock(&mousedev->client_lock); | |
823 | + | |
824 | + wake_up_interruptible(&mousedev->wait); | |
825 | +} | |
826 | + | |
827 | +static void mousedev_cleanup(struct mousedev *mousedev) | |
828 | +{ | |
829 | + struct input_handle *handle = &mousedev->handle; | |
830 | + | |
831 | + mousedev_mark_dead(mousedev); | |
832 | + mousedev_hangup(mousedev); | |
833 | + mousedev_remove_chrdev(mousedev); | |
834 | + | |
835 | + /* mousedev is marked dead so no one else accesses mousedev->open */ | |
836 | + if (mousedev->open) | |
837 | + input_close_device(handle); | |
838 | +} | |
839 | + | |
695 | 840 | static struct mousedev *mousedev_create(struct input_dev *dev, |
696 | 841 | struct input_handler *handler, |
697 | 842 | int minor) |
... | ... | @@ -707,6 +852,10 @@ |
707 | 852 | |
708 | 853 | INIT_LIST_HEAD(&mousedev->client_list); |
709 | 854 | INIT_LIST_HEAD(&mousedev->mixdev_node); |
855 | + spin_lock_init(&mousedev->client_lock); | |
856 | + mutex_init(&mousedev->mutex); | |
857 | + lockdep_set_subclass(&mousedev->mutex, | |
858 | + minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0); | |
710 | 859 | init_waitqueue_head(&mousedev->wait); |
711 | 860 | |
712 | 861 | if (minor == MOUSEDEV_MIX) |
713 | 862 | |
714 | 863 | |
715 | 864 | |
... | ... | @@ -731,14 +880,27 @@ |
731 | 880 | mousedev->dev.release = mousedev_free; |
732 | 881 | device_initialize(&mousedev->dev); |
733 | 882 | |
734 | - mousedev_table[minor] = mousedev; | |
883 | + if (minor != MOUSEDEV_MIX) { | |
884 | + error = input_register_handle(&mousedev->handle); | |
885 | + if (error) | |
886 | + goto err_free_mousedev; | |
887 | + } | |
735 | 888 | |
889 | + error = mousedev_install_chrdev(mousedev); | |
890 | + if (error) | |
891 | + goto err_unregister_handle; | |
892 | + | |
736 | 893 | error = device_add(&mousedev->dev); |
737 | 894 | if (error) |
738 | - goto err_free_mousedev; | |
895 | + goto err_cleanup_mousedev; | |
739 | 896 | |
740 | 897 | return mousedev; |
741 | 898 | |
899 | + err_cleanup_mousedev: | |
900 | + mousedev_cleanup(mousedev); | |
901 | + err_unregister_handle: | |
902 | + if (minor != MOUSEDEV_MIX) | |
903 | + input_unregister_handle(&mousedev->handle); | |
742 | 904 | err_free_mousedev: |
743 | 905 | put_device(&mousedev->dev); |
744 | 906 | err_out: |
745 | 907 | |
746 | 908 | |
747 | 909 | |
748 | 910 | |
749 | 911 | |
... | ... | @@ -747,29 +909,64 @@ |
747 | 909 | |
748 | 910 | static void mousedev_destroy(struct mousedev *mousedev) |
749 | 911 | { |
750 | - struct mousedev_client *client; | |
751 | - | |
752 | 912 | device_del(&mousedev->dev); |
753 | - mousedev->exist = 0; | |
913 | + mousedev_cleanup(mousedev); | |
914 | + if (mousedev->minor != MOUSEDEV_MIX) | |
915 | + input_unregister_handle(&mousedev->handle); | |
916 | + put_device(&mousedev->dev); | |
917 | +} | |
754 | 918 | |
755 | - if (mousedev->open) { | |
756 | - input_close_device(&mousedev->handle); | |
757 | - list_for_each_entry(client, &mousedev->client_list, node) | |
758 | - kill_fasync(&client->fasync, SIGIO, POLL_HUP); | |
759 | - wake_up_interruptible(&mousedev->wait); | |
919 | +static int mixdev_add_device(struct mousedev *mousedev) | |
920 | +{ | |
921 | + int retval; | |
922 | + | |
923 | + retval = mutex_lock_interruptible(&mousedev_mix->mutex); | |
924 | + if (retval) | |
925 | + return retval; | |
926 | + | |
927 | + if (mousedev_mix->open) { | |
928 | + retval = mousedev_open_device(mousedev); | |
929 | + if (retval) | |
930 | + goto out; | |
931 | + | |
932 | + mousedev->mixdev_open = 1; | |
760 | 933 | } |
761 | 934 | |
935 | + get_device(&mousedev->dev); | |
936 | + list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | |
937 | + | |
938 | + out: | |
939 | + mutex_unlock(&mousedev_mix->mutex); | |
940 | + return retval; | |
941 | +} | |
942 | + | |
943 | +static void mixdev_remove_device(struct mousedev *mousedev) | |
944 | +{ | |
945 | + mutex_lock(&mousedev_mix->mutex); | |
946 | + | |
947 | + if (mousedev->mixdev_open) { | |
948 | + mousedev->mixdev_open = 0; | |
949 | + mousedev_close_device(mousedev); | |
950 | + } | |
951 | + | |
952 | + list_del_init(&mousedev->mixdev_node); | |
953 | + mutex_unlock(&mousedev_mix->mutex); | |
954 | + | |
762 | 955 | put_device(&mousedev->dev); |
763 | 956 | } |
764 | 957 | |
765 | -static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, | |
958 | +static int mousedev_connect(struct input_handler *handler, | |
959 | + struct input_dev *dev, | |
766 | 960 | const struct input_device_id *id) |
767 | 961 | { |
768 | 962 | struct mousedev *mousedev; |
769 | 963 | int minor; |
770 | 964 | int error; |
771 | 965 | |
772 | - for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | |
966 | + for (minor = 0; minor < MOUSEDEV_MINORS; minor++) | |
967 | + if (!mousedev_table[minor]) | |
968 | + break; | |
969 | + | |
773 | 970 | if (minor == MOUSEDEV_MINORS) { |
774 | 971 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); |
775 | 972 | return -ENFILE; |
776 | 973 | |
777 | 974 | |
... | ... | @@ -779,21 +976,13 @@ |
779 | 976 | if (IS_ERR(mousedev)) |
780 | 977 | return PTR_ERR(mousedev); |
781 | 978 | |
782 | - error = input_register_handle(&mousedev->handle); | |
783 | - if (error) | |
784 | - goto err_delete_mousedev; | |
785 | - | |
786 | 979 | error = mixdev_add_device(mousedev); |
787 | - if (error) | |
788 | - goto err_unregister_handle; | |
980 | + if (error) { | |
981 | + mousedev_destroy(mousedev); | |
982 | + return error; | |
983 | + } | |
789 | 984 | |
790 | 985 | return 0; |
791 | - | |
792 | - err_unregister_handle: | |
793 | - input_unregister_handle(&mousedev->handle); | |
794 | - err_delete_mousedev: | |
795 | - device_unregister(&mousedev->dev); | |
796 | - return error; | |
797 | 986 | } |
798 | 987 | |
799 | 988 | static void mousedev_disconnect(struct input_handle *handle) |
800 | 989 | |
801 | 990 | |
802 | 991 | |
803 | 992 | |
804 | 993 | |
805 | 994 | |
806 | 995 | |
... | ... | @@ -801,33 +990,42 @@ |
801 | 990 | struct mousedev *mousedev = handle->private; |
802 | 991 | |
803 | 992 | mixdev_remove_device(mousedev); |
804 | - input_unregister_handle(handle); | |
805 | 993 | mousedev_destroy(mousedev); |
806 | 994 | } |
807 | 995 | |
808 | 996 | static const struct input_device_id mousedev_ids[] = { |
809 | 997 | { |
810 | - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | |
998 | + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | |
999 | + INPUT_DEVICE_ID_MATCH_KEYBIT | | |
1000 | + INPUT_DEVICE_ID_MATCH_RELBIT, | |
811 | 1001 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
812 | 1002 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, |
813 | 1003 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, |
814 | - }, /* A mouse like device, at least one button, two relative axes */ | |
1004 | + }, /* A mouse like device, at least one button, | |
1005 | + two relative axes */ | |
815 | 1006 | { |
816 | - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | |
1007 | + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | |
1008 | + INPUT_DEVICE_ID_MATCH_RELBIT, | |
817 | 1009 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
818 | 1010 | .relbit = { BIT(REL_WHEEL) }, |
819 | 1011 | }, /* A separate scrollwheel */ |
820 | 1012 | { |
821 | - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | |
1013 | + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | |
1014 | + INPUT_DEVICE_ID_MATCH_KEYBIT | | |
1015 | + INPUT_DEVICE_ID_MATCH_ABSBIT, | |
822 | 1016 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
823 | 1017 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
824 | 1018 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, |
825 | - }, /* A tablet like device, at least touch detection, two absolute axes */ | |
1019 | + }, /* A tablet like device, at least touch detection, | |
1020 | + two absolute axes */ | |
826 | 1021 | { |
827 | - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | |
1022 | + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | |
1023 | + INPUT_DEVICE_ID_MATCH_KEYBIT | | |
1024 | + INPUT_DEVICE_ID_MATCH_ABSBIT, | |
828 | 1025 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
829 | 1026 | .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, |
830 | - .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) }, | |
1027 | + .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | | |
1028 | + BIT(ABS_TOOL_WIDTH) }, | |
831 | 1029 | }, /* A touchpad */ |
832 | 1030 | |
833 | 1031 | { }, /* Terminating entry */ |