diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-08-30 00:22:24 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-08-30 00:22:24 -0400 |
commit | 464b241575f3700e14492e34f26bcd1794280f55 (patch) | |
tree | acbc48b7b7d440b3224b56edcafb7170a33c42e8 /drivers/input | |
parent | 6addb1d6de1968b84852f54561cc9a999909b5a9 (diff) |
Input: mousedev - implement proper locking
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/mousedev.c | 742 |
1 files changed, 470 insertions, 272 deletions
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 9173916b8be5..715def79390c 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
@@ -61,9 +61,11 @@ struct mousedev { | |||
61 | int open; | 61 | int open; |
62 | int minor; | 62 | int minor; |
63 | char name[16]; | 63 | char name[16]; |
64 | struct input_handle handle; | ||
64 | wait_queue_head_t wait; | 65 | wait_queue_head_t wait; |
65 | struct list_head client_list; | 66 | struct list_head client_list; |
66 | struct input_handle handle; | 67 | spinlock_t client_lock; /* protects client_list */ |
68 | struct mutex mutex; | ||
67 | struct device dev; | 69 | struct device dev; |
68 | 70 | ||
69 | struct list_head mixdev_node; | 71 | struct list_head mixdev_node; |
@@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | |||
113 | static struct input_handler mousedev_handler; | 115 | static struct input_handler mousedev_handler; |
114 | 116 | ||
115 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | 117 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; |
118 | static DEFINE_MUTEX(mousedev_table_mutex); | ||
116 | static struct mousedev *mousedev_mix; | 119 | static struct mousedev *mousedev_mix; |
117 | static LIST_HEAD(mousedev_mix_list); | 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 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) | 125 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) |
120 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) | 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 | int size, tmp; | 132 | int size, tmp; |
125 | enum { FRACTION_DENOM = 128 }; | 133 | enum { FRACTION_DENOM = 128 }; |
126 | 134 | ||
127 | switch (code) { | 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: | 137 | case ABS_X: |
142 | fy(0) = value; | 138 | fx(0) = value; |
143 | if (mousedev->touch && mousedev->pkt_count >= 2) { | 139 | if (mousedev->touch && mousedev->pkt_count >= 2) { |
144 | /* use X size to keep the same scale */ | 140 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
145 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 141 | if (size == 0) |
146 | if (size == 0) | 142 | size = 256 * 2; |
147 | size = 256 * 2; | 143 | tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; |
148 | tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; | 144 | tmp += mousedev->frac_dx; |
149 | tmp += mousedev->frac_dy; | 145 | mousedev->packet.dx = tmp / FRACTION_DENOM; |
150 | mousedev->packet.dy = tmp / FRACTION_DENOM; | 146 | mousedev->frac_dx = |
151 | mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; | 147 | tmp - mousedev->packet.dx * FRACTION_DENOM; |
152 | } | 148 | } |
153 | break; | 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 | int size; | 171 | int size; |
160 | 172 | ||
161 | switch (code) { | 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 | case ABS_X: |
175 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | 176 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
176 | if (size == 0) | 177 | if (size == 0) |
177 | size = yres ? : 1; | 178 | size = xres ? : 1; |
178 | if (value > dev->absmax[ABS_Y]) | 179 | if (value > dev->absmax[ABS_X]) |
179 | value = dev->absmax[ABS_Y]; | 180 | value = dev->absmax[ABS_X]; |
180 | if (value < dev->absmin[ABS_Y]) | 181 | if (value < dev->absmin[ABS_X]) |
181 | value = dev->absmin[ABS_Y]; | 182 | value = dev->absmin[ABS_X]; |
182 | mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; | 183 | mousedev->packet.x = |
183 | mousedev->packet.abs_event = 1; | 184 | ((value - dev->absmin[ABS_X]) * xres) / size; |
184 | break; | 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 | switch (code) { | 206 | switch (code) { |
191 | case REL_X: mousedev->packet.dx += value; break; | 207 | case REL_X: |
192 | case REL_Y: mousedev->packet.dy -= value; break; | 208 | mousedev->packet.dx += value; |
193 | case REL_WHEEL: mousedev->packet.dz -= value; break; | 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 | int index; | 224 | int index; |
200 | 225 | ||
201 | switch (code) { | 226 | switch (code) { |
202 | case BTN_TOUCH: | 227 | |
203 | case BTN_0: | 228 | case BTN_TOUCH: |
204 | case BTN_LEFT: index = 0; break; | 229 | case BTN_0: |
205 | case BTN_STYLUS: | 230 | case BTN_LEFT: index = 0; break; |
206 | case BTN_1: | 231 | |
207 | case BTN_RIGHT: index = 1; break; | 232 | case BTN_STYLUS: |
208 | case BTN_2: | 233 | case BTN_1: |
209 | case BTN_FORWARD: | 234 | case BTN_RIGHT: index = 1; break; |
210 | case BTN_STYLUS2: | 235 | |
211 | case BTN_MIDDLE: index = 2; break; | 236 | case BTN_2: |
212 | case BTN_3: | 237 | case BTN_FORWARD: |
213 | case BTN_BACK: | 238 | case BTN_STYLUS2: |
214 | case BTN_SIDE: index = 3; break; | 239 | case BTN_MIDDLE: index = 2; break; |
215 | case BTN_4: | 240 | |
216 | case BTN_EXTRA: index = 4; break; | 241 | case BTN_3: |
217 | default: return; | 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 | if (value) { | 251 | if (value) { |
@@ -226,19 +257,22 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int | |||
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 | struct mousedev_client *client; | 263 | struct mousedev_client *client; |
232 | struct mousedev_motion *p; | 264 | struct mousedev_motion *p; |
233 | unsigned long flags; | 265 | unsigned int new_head; |
234 | int wake_readers = 0; | 266 | int wake_readers = 0; |
235 | 267 | ||
236 | list_for_each_entry(client, &mousedev->client_list, node) { | 268 | list_for_each_entry_rcu(client, &mousedev->client_list, node) { |
237 | spin_lock_irqsave(&client->packet_lock, flags); | 269 | |
270 | /* Just acquire the lock, interrupts already disabled */ | ||
271 | spin_lock(&client->packet_lock); | ||
238 | 272 | ||
239 | p = &client->packets[client->head]; | 273 | p = &client->packets[client->head]; |
240 | if (client->ready && p->buttons != mousedev->packet.buttons) { | 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 | if (new_head != client->tail) { | 276 | if (new_head != client->tail) { |
243 | p = &client->packets[client->head = new_head]; | 277 | p = &client->packets[client->head = new_head]; |
244 | memset(p, 0, sizeof(struct mousedev_motion)); | 278 | memset(p, 0, sizeof(struct mousedev_motion)); |
@@ -253,19 +287,22 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h | |||
253 | } | 287 | } |
254 | 288 | ||
255 | client->pos_x += packet->dx; | 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 | client->pos_y += packet->dy; | 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 | p->dx += packet->dx; | 296 | p->dx += packet->dx; |
261 | p->dy += packet->dy; | 297 | p->dy += packet->dy; |
262 | p->dz += packet->dz; | 298 | p->dz += packet->dz; |
263 | p->buttons = mousedev->packet.buttons; | 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 | client->ready = 1; | 303 | client->ready = 1; |
267 | 304 | ||
268 | spin_unlock_irqrestore(&client->packet_lock, flags); | 305 | spin_unlock(&client->packet_lock); |
269 | 306 | ||
270 | if (client->ready) { | 307 | if (client->ready) { |
271 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 308 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
@@ -281,7 +318,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
281 | { | 318 | { |
282 | if (!value) { | 319 | if (!value) { |
283 | if (mousedev->touch && | 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 | * Toggle left button to emulate tap. | 324 | * Toggle left button to emulate tap. |
287 | * We rely on the fact that mousedev_mix always has 0 | 325 | * We rely on the fact that mousedev_mix always has 0 |
@@ -290,7 +328,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
290 | set_bit(0, &mousedev->packet.buttons); | 328 | set_bit(0, &mousedev->packet.buttons); |
291 | set_bit(0, &mousedev_mix->packet.buttons); | 329 | set_bit(0, &mousedev_mix->packet.buttons); |
292 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); | 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 | clear_bit(0, &mousedev->packet.buttons); | 333 | clear_bit(0, &mousedev->packet.buttons); |
295 | clear_bit(0, &mousedev_mix->packet.buttons); | 334 | clear_bit(0, &mousedev_mix->packet.buttons); |
296 | } | 335 | } |
@@ -302,54 +341,61 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
302 | mousedev->touch = jiffies; | 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 | struct mousedev *mousedev = handle->private; | 347 | struct mousedev *mousedev = handle->private; |
308 | 348 | ||
309 | switch (type) { | 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)) | 351 | case EV_ABS: |
316 | mousedev_touchpad_event(handle->dev, mousedev, code, value); | 352 | /* Ignore joysticks */ |
317 | else | 353 | if (test_bit(BTN_TRIGGER, handle->dev->keybit)) |
318 | mousedev_abs_event(handle->dev, mousedev, code, value); | 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: | 362 | break; |
323 | mousedev_rel_event(mousedev, code, value); | ||
324 | break; | ||
325 | 363 | ||
326 | case EV_KEY: | 364 | case EV_REL: |
327 | if (value != 2) { | 365 | mousedev_rel_event(mousedev, code, value); |
328 | if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | 366 | break; |
329 | mousedev_touchpad_touch(mousedev, value); | ||
330 | else | ||
331 | mousedev_key_event(mousedev, code, value); | ||
332 | } | ||
333 | break; | ||
334 | 367 | ||
335 | case EV_SYN: | 368 | case EV_KEY: |
336 | if (code == SYN_REPORT) { | 369 | if (value != 2) { |
337 | if (mousedev->touch) { | 370 | if (code == BTN_TOUCH && |
338 | mousedev->pkt_count++; | 371 | test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) |
339 | /* Input system eats duplicate events, but we need all of them | 372 | mousedev_touchpad_touch(mousedev, value); |
340 | * to do correct averaging so apply present one forward | 373 | else |
341 | */ | 374 | mousedev_key_event(mousedev, code, value); |
342 | fx(0) = fx(1); | 375 | } |
343 | fy(0) = fy(1); | 376 | break; |
344 | } | 377 | |
345 | 378 | case EV_SYN: | |
346 | mousedev_notify_readers(mousedev, &mousedev->packet); | 379 | if (code == SYN_REPORT) { |
347 | mousedev_notify_readers(mousedev_mix, &mousedev->packet); | 380 | if (mousedev->touch) { |
348 | 381 | mousedev->pkt_count++; | |
349 | mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; | 382 | /* |
350 | mousedev->packet.abs_event = 0; | 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 | ||
@@ -367,41 +413,45 @@ static void mousedev_free(struct device *dev) | |||
367 | { | 413 | { |
368 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); | 414 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); |
369 | 415 | ||
370 | mousedev_table[mousedev->minor] = NULL; | ||
371 | kfree(mousedev); | 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 | |||
378 | if (mousedev_mix->open) { | ||
379 | error = input_open_device(&mousedev->handle); | ||
380 | if (error) | ||
381 | return error; | ||
382 | 422 | ||
383 | mousedev->open++; | 423 | retval = mutex_lock_interruptible(&mousedev->mutex); |
384 | mousedev->mixdev_open = 1; | 424 | if (retval) |
385 | } | 425 | return retval; |
386 | 426 | ||
387 | get_device(&mousedev->dev); | 427 | if (mousedev->minor == MOUSEDEV_MIX) |
388 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | 428 | mixdev_open_devices(); |
429 | else if (!mousedev->exist) | ||
430 | retval = -ENODEV; | ||
431 | else if (!mousedev->open++) | ||
432 | retval = input_open_device(&mousedev->handle); | ||
389 | 433 | ||
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) { | 440 | mutex_lock(&mousedev->mutex); |
396 | mousedev->mixdev_open = 0; | ||
397 | if (!--mousedev->open && mousedev->exist) | ||
398 | input_close_device(&mousedev->handle); | ||
399 | } | ||
400 | 441 | ||
401 | list_del_init(&mousedev->mixdev_node); | 442 | if (mousedev->minor == MOUSEDEV_MIX) |
402 | put_device(&mousedev->dev); | 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 | static void mixdev_open_devices(void) | 455 | static void mixdev_open_devices(void) |
406 | { | 456 | { |
407 | struct mousedev *mousedev; | 457 | struct mousedev *mousedev; |
@@ -411,16 +461,19 @@ static void mixdev_open_devices(void) | |||
411 | 461 | ||
412 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 462 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
413 | if (!mousedev->mixdev_open) { | 463 | if (!mousedev->mixdev_open) { |
414 | if (!mousedev->open && mousedev->exist) | 464 | if (mousedev_open_device(mousedev)) |
415 | if (input_open_device(&mousedev->handle)) | 465 | continue; |
416 | continue; | ||
417 | 466 | ||
418 | mousedev->open++; | ||
419 | mousedev->mixdev_open = 1; | 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 | static void mixdev_close_devices(void) | 477 | static void mixdev_close_devices(void) |
425 | { | 478 | { |
426 | struct mousedev *mousedev; | 479 | struct mousedev *mousedev; |
@@ -431,33 +484,50 @@ static void mixdev_close_devices(void) | |||
431 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 484 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
432 | if (mousedev->mixdev_open) { | 485 | if (mousedev->mixdev_open) { |
433 | mousedev->mixdev_open = 0; | 486 | mousedev->mixdev_open = 0; |
434 | if (!--mousedev->open && mousedev->exist) | 487 | mousedev_close_device(mousedev); |
435 | input_close_device(&mousedev->handle); | ||
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 | static int mousedev_release(struct inode *inode, struct file *file) | 516 | static int mousedev_release(struct inode *inode, struct file *file) |
441 | { | 517 | { |
442 | struct mousedev_client *client = file->private_data; | 518 | struct mousedev_client *client = file->private_data; |
443 | struct mousedev *mousedev = client->mousedev; | 519 | struct mousedev *mousedev = client->mousedev; |
444 | 520 | ||
445 | mousedev_fasync(-1, file, 0); | 521 | mousedev_fasync(-1, file, 0); |
446 | 522 | mousedev_detach_client(mousedev, client); | |
447 | list_del(&client->node); | ||
448 | kfree(client); | 523 | kfree(client); |
449 | 524 | ||
450 | if (mousedev->minor == MOUSEDEV_MIX) | 525 | mousedev_close_device(mousedev); |
451 | mixdev_close_devices(); | ||
452 | else if (!--mousedev->open && mousedev->exist) | ||
453 | input_close_device(&mousedev->handle); | ||
454 | |||
455 | put_device(&mousedev->dev); | 526 | put_device(&mousedev->dev); |
456 | 527 | ||
457 | return 0; | 528 | return 0; |
458 | } | 529 | } |
459 | 530 | ||
460 | |||
461 | static int mousedev_open(struct inode *inode, struct file *file) | 531 | static int mousedev_open(struct inode *inode, struct file *file) |
462 | { | 532 | { |
463 | struct mousedev_client *client; | 533 | struct mousedev_client *client; |
@@ -475,12 +545,17 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
475 | if (i >= MOUSEDEV_MINORS) | 545 | if (i >= MOUSEDEV_MINORS) |
476 | return -ENODEV; | 546 | return -ENODEV; |
477 | 547 | ||
548 | error = mutex_lock_interruptible(&mousedev_table_mutex); | ||
549 | if (error) | ||
550 | return error; | ||
478 | mousedev = mousedev_table[i]; | 551 | mousedev = mousedev_table[i]; |
552 | if (mousedev) | ||
553 | get_device(&mousedev->dev); | ||
554 | mutex_unlock(&mousedev_table_mutex); | ||
555 | |||
479 | if (!mousedev) | 556 | if (!mousedev) |
480 | return -ENODEV; | 557 | return -ENODEV; |
481 | 558 | ||
482 | get_device(&mousedev->dev); | ||
483 | |||
484 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | 559 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
485 | if (!client) { | 560 | if (!client) { |
486 | error = -ENOMEM; | 561 | error = -ENOMEM; |
@@ -491,21 +566,17 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
491 | client->pos_x = xres / 2; | 566 | client->pos_x = xres / 2; |
492 | client->pos_y = yres / 2; | 567 | client->pos_y = yres / 2; |
493 | client->mousedev = mousedev; | 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) | 571 | error = mousedev_open_device(mousedev); |
497 | mixdev_open_devices(); | 572 | if (error) |
498 | else if (!mousedev->open++ && mousedev->exist) { | 573 | goto err_free_client; |
499 | error = input_open_device(&mousedev->handle); | ||
500 | if (error) | ||
501 | goto err_free_client; | ||
502 | } | ||
503 | 574 | ||
504 | file->private_data = client; | 575 | file->private_data = client; |
505 | return 0; | 576 | return 0; |
506 | 577 | ||
507 | err_free_client: | 578 | err_free_client: |
508 | list_del(&client->node); | 579 | mousedev_detach_client(mousedev, client); |
509 | kfree(client); | 580 | kfree(client); |
510 | err_put_mousedev: | 581 | err_put_mousedev: |
511 | put_device(&mousedev->dev); | 582 | put_device(&mousedev->dev); |
@@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(int delta, int limit) | |||
517 | return delta > limit ? limit : (delta < -limit ? -limit : delta); | 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; | 594 | struct mousedev_motion *p = &client->packets[client->tail]; |
523 | unsigned long flags; | ||
524 | |||
525 | spin_lock_irqsave(&client->packet_lock, flags); | ||
526 | p = &client->packets[client->tail]; | ||
527 | 595 | ||
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 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); | 598 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); |
530 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); | 599 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); |
531 | p->dx -= ps2_data[1]; | 600 | p->dx -= ps2_data[1]; |
532 | p->dy -= ps2_data[2]; | 601 | p->dy -= ps2_data[2]; |
533 | 602 | ||
534 | switch (client->mode) { | 603 | switch (client->mode) { |
535 | case MOUSEDEV_EMUL_EXPS: | 604 | case MOUSEDEV_EMUL_EXPS: |
536 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); | 605 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); |
537 | p->dz -= ps2_data[3]; | 606 | p->dz -= ps2_data[3]; |
538 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); | 607 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); |
539 | client->bufsiz = 4; | 608 | client->bufsiz = 4; |
540 | break; | 609 | break; |
541 | 610 | ||
542 | case MOUSEDEV_EMUL_IMPS: | 611 | case MOUSEDEV_EMUL_IMPS: |
543 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 612 | ps2_data[0] |= |
544 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); | 613 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
545 | p->dz -= ps2_data[3]; | 614 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); |
546 | client->bufsiz = 4; | 615 | p->dz -= ps2_data[3]; |
547 | break; | 616 | client->bufsiz = 4; |
548 | 617 | break; | |
549 | case MOUSEDEV_EMUL_PS2: | 618 | |
550 | default: | 619 | case MOUSEDEV_EMUL_PS2: |
551 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 620 | default: |
552 | p->dz = 0; | 621 | ps2_data[0] |= |
553 | client->bufsiz = 3; | 622 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
554 | break; | 623 | p->dz = 0; |
624 | client->bufsiz = 3; | ||
625 | break; | ||
555 | } | 626 | } |
556 | 627 | ||
557 | if (!p->dx && !p->dy && !p->dz) { | 628 | if (!p->dx && !p->dy && !p->dz) { |
@@ -561,12 +632,56 @@ static void mousedev_packet(struct mousedev_client *client, signed char *ps2_dat | |||
561 | } else | 632 | } else |
562 | client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; | 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 | struct mousedev_client *client = file->private_data; | 686 | struct mousedev_client *client = file->private_data; |
572 | unsigned char c; | 687 | unsigned char c; |
@@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size | |||
577 | if (get_user(c, buffer + i)) | 692 | if (get_user(c, buffer + i)) |
578 | return -EFAULT; | 693 | return -EFAULT; |
579 | 694 | ||
695 | spin_lock_irq(&client->packet_lock); | ||
696 | |||
580 | if (c == mousedev_imex_seq[client->imexseq]) { | 697 | if (c == mousedev_imex_seq[client->imexseq]) { |
581 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { | 698 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { |
582 | client->imexseq = 0; | 699 | client->imexseq = 0; |
@@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size | |||
593 | } else | 710 | } else |
594 | client->impsseq = 0; | 711 | client->impsseq = 0; |
595 | 712 | ||
596 | client->ps2[0] = 0xfa; | 713 | mousedev_generate_response(client, c); |
597 | |||
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 | 714 | ||
631 | client->buffer = client->bufsiz; | 715 | spin_unlock_irq(&client->packet_lock); |
632 | } | 716 | } |
633 | 717 | ||
634 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 718 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
635 | |||
636 | wake_up_interruptible(&client->mousedev->wait); | 719 | wake_up_interruptible(&client->mousedev->wait); |
637 | 720 | ||
638 | return count; | 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 | struct mousedev_client *client = file->private_data; | 727 | struct mousedev_client *client = file->private_data; |
728 | struct mousedev *mousedev = client->mousedev; | ||
729 | signed char data[sizeof(client->ps2)]; | ||
644 | int retval = 0; | 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 | return -EAGAIN; | 734 | return -EAGAIN; |
648 | 735 | ||
649 | retval = wait_event_interruptible(client->mousedev->wait, | 736 | retval = wait_event_interruptible(mousedev->wait, |
650 | !client->mousedev->exist || client->ready || client->buffer); | 737 | !mousedev->exist || client->ready || client->buffer); |
651 | |||
652 | if (retval) | 738 | if (retval) |
653 | return retval; | 739 | return retval; |
654 | 740 | ||
655 | if (!client->mousedev->exist) | 741 | if (!mousedev->exist) |
656 | return -ENODEV; | 742 | return -ENODEV; |
657 | 743 | ||
744 | spin_lock_irq(&client->packet_lock); | ||
745 | |||
658 | if (!client->buffer && client->ready) { | 746 | if (!client->buffer && client->ready) { |
659 | mousedev_packet(client, client->ps2); | 747 | mousedev_packet(client, client->ps2); |
660 | client->buffer = client->bufsiz; | 748 | client->buffer = client->bufsiz; |
@@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t coun | |||
663 | if (count > client->buffer) | 751 | if (count > client->buffer) |
664 | count = client->buffer; | 752 | count = client->buffer; |
665 | 753 | ||
754 | memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); | ||
666 | client->buffer -= count; | 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 | return -EFAULT; | 760 | return -EFAULT; |
670 | 761 | ||
671 | return count; | 762 | return count; |
@@ -692,6 +783,60 @@ static const struct file_operations mousedev_fops = { | |||
692 | .fasync = mousedev_fasync, | 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 | static struct mousedev *mousedev_create(struct input_dev *dev, | 840 | static struct mousedev *mousedev_create(struct input_dev *dev, |
696 | struct input_handler *handler, | 841 | struct input_handler *handler, |
697 | int minor) | 842 | int minor) |
@@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
707 | 852 | ||
708 | INIT_LIST_HEAD(&mousedev->client_list); | 853 | INIT_LIST_HEAD(&mousedev->client_list); |
709 | INIT_LIST_HEAD(&mousedev->mixdev_node); | 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 | init_waitqueue_head(&mousedev->wait); | 859 | init_waitqueue_head(&mousedev->wait); |
711 | 860 | ||
712 | if (minor == MOUSEDEV_MIX) | 861 | if (minor == MOUSEDEV_MIX) |
@@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
731 | mousedev->dev.release = mousedev_free; | 880 | mousedev->dev.release = mousedev_free; |
732 | device_initialize(&mousedev->dev); | 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 | } | ||
888 | |||
889 | error = mousedev_install_chrdev(mousedev); | ||
890 | if (error) | ||
891 | goto err_unregister_handle; | ||
735 | 892 | ||
736 | error = device_add(&mousedev->dev); | 893 | error = device_add(&mousedev->dev); |
737 | if (error) | 894 | if (error) |
738 | goto err_free_mousedev; | 895 | goto err_cleanup_mousedev; |
739 | 896 | ||
740 | return mousedev; | 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 | err_free_mousedev: | 904 | err_free_mousedev: |
743 | put_device(&mousedev->dev); | 905 | put_device(&mousedev->dev); |
744 | err_out: | 906 | err_out: |
@@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
747 | 909 | ||
748 | static void mousedev_destroy(struct mousedev *mousedev) | 910 | static void mousedev_destroy(struct mousedev *mousedev) |
749 | { | 911 | { |
750 | struct mousedev_client *client; | ||
751 | |||
752 | device_del(&mousedev->dev); | 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) { | 919 | static int mixdev_add_device(struct mousedev *mousedev) |
756 | input_close_device(&mousedev->handle); | 920 | { |
757 | list_for_each_entry(client, &mousedev->client_list, node) | 921 | int retval; |
758 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 922 | |
759 | wake_up_interruptible(&mousedev->wait); | 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; | ||
933 | } | ||
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); | ||
760 | } | 950 | } |
761 | 951 | ||
952 | list_del_init(&mousedev->mixdev_node); | ||
953 | mutex_unlock(&mousedev_mix->mutex); | ||
954 | |||
762 | put_device(&mousedev->dev); | 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 | const struct input_device_id *id) | 960 | const struct input_device_id *id) |
767 | { | 961 | { |
768 | struct mousedev *mousedev; | 962 | struct mousedev *mousedev; |
769 | int minor; | 963 | int minor; |
770 | int error; | 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 | if (minor == MOUSEDEV_MINORS) { | 970 | if (minor == MOUSEDEV_MINORS) { |
774 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | 971 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); |
775 | return -ENFILE; | 972 | return -ENFILE; |
@@ -779,21 +976,13 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev | |||
779 | if (IS_ERR(mousedev)) | 976 | if (IS_ERR(mousedev)) |
780 | return PTR_ERR(mousedev); | 977 | return PTR_ERR(mousedev); |
781 | 978 | ||
782 | error = input_register_handle(&mousedev->handle); | ||
783 | if (error) | ||
784 | goto err_delete_mousedev; | ||
785 | |||
786 | error = mixdev_add_device(mousedev); | 979 | error = mixdev_add_device(mousedev); |
787 | if (error) | 980 | if (error) { |
788 | goto err_unregister_handle; | 981 | mousedev_destroy(mousedev); |
982 | return error; | ||
983 | } | ||
789 | 984 | ||
790 | return 0; | 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 | static void mousedev_disconnect(struct input_handle *handle) | 988 | static void mousedev_disconnect(struct input_handle *handle) |
@@ -801,33 +990,42 @@ static void mousedev_disconnect(struct input_handle *handle) | |||
801 | struct mousedev *mousedev = handle->private; | 990 | struct mousedev *mousedev = handle->private; |
802 | 991 | ||
803 | mixdev_remove_device(mousedev); | 992 | mixdev_remove_device(mousedev); |
804 | input_unregister_handle(handle); | ||
805 | mousedev_destroy(mousedev); | 993 | mousedev_destroy(mousedev); |
806 | } | 994 | } |
807 | 995 | ||
808 | static const struct input_device_id mousedev_ids[] = { | 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 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 1001 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
812 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | 1002 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, |
813 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | 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 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 1009 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
818 | .relbit = { BIT(REL_WHEEL) }, | 1010 | .relbit = { BIT(REL_WHEEL) }, |
819 | }, /* A separate scrollwheel */ | 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 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 1016 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
823 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 1017 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
824 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | 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 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 1025 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
829 | .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, | 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 | }, /* A touchpad */ | 1029 | }, /* A touchpad */ |
832 | 1030 | ||
833 | { }, /* Terminating entry */ | 1031 | { }, /* Terminating entry */ |