diff options
Diffstat (limited to 'drivers/input/mousedev.c')
-rw-r--r-- | drivers/input/mousedev.c | 439 |
1 files changed, 262 insertions, 177 deletions
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 074fee429d1..7678e987655 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
@@ -63,9 +63,12 @@ struct mousedev { | |||
63 | int minor; | 63 | int minor; |
64 | char name[16]; | 64 | char name[16]; |
65 | wait_queue_head_t wait; | 65 | wait_queue_head_t wait; |
66 | struct list_head list; | 66 | struct list_head client_list; |
67 | struct input_handle handle; | 67 | struct input_handle handle; |
68 | 68 | ||
69 | struct list_head mixdev_node; | ||
70 | int mixdev_open; | ||
71 | |||
69 | struct mousedev_hw_data packet; | 72 | struct mousedev_hw_data packet; |
70 | unsigned int pkt_count; | 73 | unsigned int pkt_count; |
71 | int old_x[4], old_y[4]; | 74 | int old_x[4], old_y[4]; |
@@ -85,7 +88,7 @@ struct mousedev_motion { | |||
85 | }; | 88 | }; |
86 | 89 | ||
87 | #define PACKET_QUEUE_LEN 16 | 90 | #define PACKET_QUEUE_LEN 16 |
88 | struct mousedev_list { | 91 | struct mousedev_client { |
89 | struct fasync_struct *fasync; | 92 | struct fasync_struct *fasync; |
90 | struct mousedev *mousedev; | 93 | struct mousedev *mousedev; |
91 | struct list_head node; | 94 | struct list_head node; |
@@ -111,6 +114,7 @@ static struct input_handler mousedev_handler; | |||
111 | 114 | ||
112 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | 115 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; |
113 | static struct mousedev mousedev_mix; | 116 | static struct mousedev mousedev_mix; |
117 | static LIST_HEAD(mousedev_mix_list); | ||
114 | 118 | ||
115 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) | 119 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) |
116 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) | 120 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) |
@@ -120,32 +124,33 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous | |||
120 | int size, tmp; | 124 | int size, tmp; |
121 | enum { FRACTION_DENOM = 128 }; | 125 | enum { FRACTION_DENOM = 128 }; |
122 | 126 | ||
123 | if (mousedev->touch) { | 127 | switch (code) { |
124 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 128 | case ABS_X: |
125 | if (size == 0) | 129 | fx(0) = value; |
126 | size = 256 * 2; | 130 | if (mousedev->touch && mousedev->pkt_count >= 2) { |
127 | 131 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | |
128 | switch (code) { | 132 | if (size == 0) |
129 | case ABS_X: | 133 | size = 256 * 2; |
130 | fx(0) = value; | 134 | tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; |
131 | if (mousedev->pkt_count >= 2) { | 135 | tmp += mousedev->frac_dx; |
132 | tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; | 136 | mousedev->packet.dx = tmp / FRACTION_DENOM; |
133 | tmp += mousedev->frac_dx; | 137 | mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; |
134 | mousedev->packet.dx = tmp / FRACTION_DENOM; | 138 | } |
135 | mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; | 139 | break; |
136 | } | ||
137 | break; | ||
138 | 140 | ||
139 | case ABS_Y: | 141 | case ABS_Y: |
140 | fy(0) = value; | 142 | fy(0) = value; |
141 | if (mousedev->pkt_count >= 2) { | 143 | if (mousedev->touch && mousedev->pkt_count >= 2) { |
142 | tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; | 144 | /* use X size to keep the same scale */ |
143 | tmp += mousedev->frac_dy; | 145 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
144 | mousedev->packet.dy = tmp / FRACTION_DENOM; | 146 | if (size == 0) |
145 | mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; | 147 | size = 256 * 2; |
146 | } | 148 | tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; |
147 | break; | 149 | tmp += mousedev->frac_dy; |
148 | } | 150 | mousedev->packet.dy = tmp / FRACTION_DENOM; |
151 | mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; | ||
152 | } | ||
153 | break; | ||
149 | } | 154 | } |
150 | } | 155 | } |
151 | 156 | ||
@@ -223,47 +228,47 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int | |||
223 | 228 | ||
224 | static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) | 229 | static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) |
225 | { | 230 | { |
226 | struct mousedev_list *list; | 231 | struct mousedev_client *client; |
227 | struct mousedev_motion *p; | 232 | struct mousedev_motion *p; |
228 | unsigned long flags; | 233 | unsigned long flags; |
229 | int wake_readers = 0; | 234 | int wake_readers = 0; |
230 | 235 | ||
231 | list_for_each_entry(list, &mousedev->list, node) { | 236 | list_for_each_entry(client, &mousedev->client_list, node) { |
232 | spin_lock_irqsave(&list->packet_lock, flags); | 237 | spin_lock_irqsave(&client->packet_lock, flags); |
233 | 238 | ||
234 | p = &list->packets[list->head]; | 239 | p = &client->packets[client->head]; |
235 | if (list->ready && p->buttons != mousedev->packet.buttons) { | 240 | if (client->ready && p->buttons != mousedev->packet.buttons) { |
236 | unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; | 241 | unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN; |
237 | if (new_head != list->tail) { | 242 | if (new_head != client->tail) { |
238 | p = &list->packets[list->head = new_head]; | 243 | p = &client->packets[client->head = new_head]; |
239 | memset(p, 0, sizeof(struct mousedev_motion)); | 244 | memset(p, 0, sizeof(struct mousedev_motion)); |
240 | } | 245 | } |
241 | } | 246 | } |
242 | 247 | ||
243 | if (packet->abs_event) { | 248 | if (packet->abs_event) { |
244 | p->dx += packet->x - list->pos_x; | 249 | p->dx += packet->x - client->pos_x; |
245 | p->dy += packet->y - list->pos_y; | 250 | p->dy += packet->y - client->pos_y; |
246 | list->pos_x = packet->x; | 251 | client->pos_x = packet->x; |
247 | list->pos_y = packet->y; | 252 | client->pos_y = packet->y; |
248 | } | 253 | } |
249 | 254 | ||
250 | list->pos_x += packet->dx; | 255 | client->pos_x += packet->dx; |
251 | list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x); | 256 | client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x); |
252 | list->pos_y += packet->dy; | 257 | client->pos_y += packet->dy; |
253 | list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y); | 258 | client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y); |
254 | 259 | ||
255 | p->dx += packet->dx; | 260 | p->dx += packet->dx; |
256 | p->dy += packet->dy; | 261 | p->dy += packet->dy; |
257 | p->dz += packet->dz; | 262 | p->dz += packet->dz; |
258 | p->buttons = mousedev->packet.buttons; | 263 | p->buttons = mousedev->packet.buttons; |
259 | 264 | ||
260 | if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons) | 265 | if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons) |
261 | list->ready = 1; | 266 | client->ready = 1; |
262 | 267 | ||
263 | spin_unlock_irqrestore(&list->packet_lock, flags); | 268 | spin_unlock_irqrestore(&client->packet_lock, flags); |
264 | 269 | ||
265 | if (list->ready) { | 270 | if (client->ready) { |
266 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | 271 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
267 | wake_readers = 1; | 272 | wake_readers = 1; |
268 | } | 273 | } |
269 | } | 274 | } |
@@ -351,9 +356,9 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig | |||
351 | static int mousedev_fasync(int fd, struct file *file, int on) | 356 | static int mousedev_fasync(int fd, struct file *file, int on) |
352 | { | 357 | { |
353 | int retval; | 358 | int retval; |
354 | struct mousedev_list *list = file->private_data; | 359 | struct mousedev_client *client = file->private_data; |
355 | 360 | ||
356 | retval = fasync_helper(fd, file, on, &list->fasync); | 361 | retval = fasync_helper(fd, file, on, &client->fasync); |
357 | 362 | ||
358 | return retval < 0 ? retval : 0; | 363 | return retval < 0 ? retval : 0; |
359 | } | 364 | } |
@@ -364,50 +369,95 @@ static void mousedev_free(struct mousedev *mousedev) | |||
364 | kfree(mousedev); | 369 | kfree(mousedev); |
365 | } | 370 | } |
366 | 371 | ||
367 | static void mixdev_release(void) | 372 | static int mixdev_add_device(struct mousedev *mousedev) |
368 | { | 373 | { |
369 | struct input_handle *handle; | 374 | int error; |
370 | 375 | ||
371 | list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { | 376 | if (mousedev_mix.open) { |
372 | struct mousedev *mousedev = handle->private; | 377 | error = input_open_device(&mousedev->handle); |
378 | if (error) | ||
379 | return error; | ||
373 | 380 | ||
374 | if (!mousedev->open) { | 381 | mousedev->open++; |
375 | if (mousedev->exist) | 382 | mousedev->mixdev_open++; |
376 | input_close_device(&mousedev->handle); | 383 | } |
377 | else | 384 | |
378 | mousedev_free(mousedev); | 385 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); |
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static void mixdev_remove_device(struct mousedev *mousedev) | ||
391 | { | ||
392 | if (mousedev->mixdev_open) { | ||
393 | mousedev->mixdev_open = 0; | ||
394 | if (!--mousedev->open && mousedev->exist) | ||
395 | input_close_device(&mousedev->handle); | ||
396 | } | ||
397 | |||
398 | list_del_init(&mousedev->mixdev_node); | ||
399 | } | ||
400 | |||
401 | static void mixdev_open_devices(void) | ||
402 | { | ||
403 | struct mousedev *mousedev; | ||
404 | |||
405 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | ||
406 | if (mousedev->exist && !mousedev->open) { | ||
407 | if (input_open_device(&mousedev->handle)) | ||
408 | continue; | ||
409 | |||
410 | mousedev->open++; | ||
411 | mousedev->mixdev_open++; | ||
379 | } | 412 | } |
380 | } | 413 | } |
381 | } | 414 | } |
382 | 415 | ||
383 | static int mousedev_release(struct inode * inode, struct file * file) | 416 | static void mixdev_close_devices(void) |
384 | { | 417 | { |
385 | struct mousedev_list *list = file->private_data; | 418 | struct mousedev *mousedev, *next; |
419 | |||
420 | list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) { | ||
421 | if (mousedev->mixdev_open) { | ||
422 | mousedev->mixdev_open = 0; | ||
423 | if (!--mousedev->open) { | ||
424 | if (mousedev->exist) | ||
425 | input_close_device(&mousedev->handle); | ||
426 | else | ||
427 | mousedev_free(mousedev); | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
433 | static int mousedev_release(struct inode *inode, struct file *file) | ||
434 | { | ||
435 | struct mousedev_client *client = file->private_data; | ||
436 | struct mousedev *mousedev = client->mousedev; | ||
386 | 437 | ||
387 | mousedev_fasync(-1, file, 0); | 438 | mousedev_fasync(-1, file, 0); |
388 | 439 | ||
389 | list_del(&list->node); | 440 | list_del(&client->node); |
441 | kfree(client); | ||
390 | 442 | ||
391 | if (!--list->mousedev->open) { | 443 | if (!--mousedev->open) { |
392 | if (list->mousedev->minor == MOUSEDEV_MIX) | 444 | if (mousedev->minor == MOUSEDEV_MIX) |
393 | mixdev_release(); | 445 | mixdev_close_devices(); |
394 | else if (!mousedev_mix.open) { | 446 | else if (mousedev->exist) |
395 | if (list->mousedev->exist) | 447 | input_close_device(&mousedev->handle); |
396 | input_close_device(&list->mousedev->handle); | 448 | else |
397 | else | 449 | mousedev_free(mousedev); |
398 | mousedev_free(list->mousedev); | ||
399 | } | ||
400 | } | 450 | } |
401 | 451 | ||
402 | kfree(list); | ||
403 | return 0; | 452 | return 0; |
404 | } | 453 | } |
405 | 454 | ||
406 | static int mousedev_open(struct inode * inode, struct file * file) | 455 | |
456 | static int mousedev_open(struct inode *inode, struct file *file) | ||
407 | { | 457 | { |
408 | struct mousedev_list *list; | 458 | struct mousedev_client *client; |
409 | struct input_handle *handle; | ||
410 | struct mousedev *mousedev; | 459 | struct mousedev *mousedev; |
460 | int error; | ||
411 | int i; | 461 | int i; |
412 | 462 | ||
413 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 463 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
@@ -417,31 +467,37 @@ static int mousedev_open(struct inode * inode, struct file * file) | |||
417 | #endif | 467 | #endif |
418 | i = iminor(inode) - MOUSEDEV_MINOR_BASE; | 468 | i = iminor(inode) - MOUSEDEV_MINOR_BASE; |
419 | 469 | ||
420 | if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) | 470 | if (i >= MOUSEDEV_MINORS) |
421 | return -ENODEV; | 471 | return -ENODEV; |
422 | 472 | ||
423 | if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL))) | 473 | mousedev = mousedev_table[i]; |
474 | if (!mousedev) | ||
475 | return -ENODEV; | ||
476 | |||
477 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | ||
478 | if (!client) | ||
424 | return -ENOMEM; | 479 | return -ENOMEM; |
425 | 480 | ||
426 | spin_lock_init(&list->packet_lock); | 481 | spin_lock_init(&client->packet_lock); |
427 | list->pos_x = xres / 2; | 482 | client->pos_x = xres / 2; |
428 | list->pos_y = yres / 2; | 483 | client->pos_y = yres / 2; |
429 | list->mousedev = mousedev_table[i]; | 484 | client->mousedev = mousedev; |
430 | list_add_tail(&list->node, &mousedev_table[i]->list); | 485 | list_add_tail(&client->node, &mousedev->client_list); |
431 | file->private_data = list; | 486 | |
432 | 487 | if (!mousedev->open++) { | |
433 | if (!list->mousedev->open++) { | 488 | if (mousedev->minor == MOUSEDEV_MIX) |
434 | if (list->mousedev->minor == MOUSEDEV_MIX) { | 489 | mixdev_open_devices(); |
435 | list_for_each_entry(handle, &mousedev_handler.h_list, h_node) { | 490 | else if (mousedev->exist) { |
436 | mousedev = handle->private; | 491 | error = input_open_device(&mousedev->handle); |
437 | if (!mousedev->open && mousedev->exist) | 492 | if (error) { |
438 | input_open_device(handle); | 493 | list_del(&client->node); |
494 | kfree(client); | ||
495 | return error; | ||
439 | } | 496 | } |
440 | } else | 497 | } |
441 | if (!mousedev_mix.open && list->mousedev->exist) | ||
442 | input_open_device(&list->mousedev->handle); | ||
443 | } | 498 | } |
444 | 499 | ||
500 | file->private_data = client; | ||
445 | return 0; | 501 | return 0; |
446 | } | 502 | } |
447 | 503 | ||
@@ -450,13 +506,13 @@ static inline int mousedev_limit_delta(int delta, int limit) | |||
450 | return delta > limit ? limit : (delta < -limit ? -limit : delta); | 506 | return delta > limit ? limit : (delta < -limit ? -limit : delta); |
451 | } | 507 | } |
452 | 508 | ||
453 | static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) | 509 | static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data) |
454 | { | 510 | { |
455 | struct mousedev_motion *p; | 511 | struct mousedev_motion *p; |
456 | unsigned long flags; | 512 | unsigned long flags; |
457 | 513 | ||
458 | spin_lock_irqsave(&list->packet_lock, flags); | 514 | spin_lock_irqsave(&client->packet_lock, flags); |
459 | p = &list->packets[list->tail]; | 515 | p = &client->packets[client->tail]; |
460 | 516 | ||
461 | ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); | 517 | ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); |
462 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); | 518 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); |
@@ -464,44 +520,44 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) | |||
464 | p->dx -= ps2_data[1]; | 520 | p->dx -= ps2_data[1]; |
465 | p->dy -= ps2_data[2]; | 521 | p->dy -= ps2_data[2]; |
466 | 522 | ||
467 | switch (list->mode) { | 523 | switch (client->mode) { |
468 | case MOUSEDEV_EMUL_EXPS: | 524 | case MOUSEDEV_EMUL_EXPS: |
469 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); | 525 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); |
470 | p->dz -= ps2_data[3]; | 526 | p->dz -= ps2_data[3]; |
471 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); | 527 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); |
472 | list->bufsiz = 4; | 528 | client->bufsiz = 4; |
473 | break; | 529 | break; |
474 | 530 | ||
475 | case MOUSEDEV_EMUL_IMPS: | 531 | case MOUSEDEV_EMUL_IMPS: |
476 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 532 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
477 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); | 533 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); |
478 | p->dz -= ps2_data[3]; | 534 | p->dz -= ps2_data[3]; |
479 | list->bufsiz = 4; | 535 | client->bufsiz = 4; |
480 | break; | 536 | break; |
481 | 537 | ||
482 | case MOUSEDEV_EMUL_PS2: | 538 | case MOUSEDEV_EMUL_PS2: |
483 | default: | 539 | default: |
484 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 540 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
485 | p->dz = 0; | 541 | p->dz = 0; |
486 | list->bufsiz = 3; | 542 | client->bufsiz = 3; |
487 | break; | 543 | break; |
488 | } | 544 | } |
489 | 545 | ||
490 | if (!p->dx && !p->dy && !p->dz) { | 546 | if (!p->dx && !p->dy && !p->dz) { |
491 | if (list->tail == list->head) { | 547 | if (client->tail == client->head) { |
492 | list->ready = 0; | 548 | client->ready = 0; |
493 | list->last_buttons = p->buttons; | 549 | client->last_buttons = p->buttons; |
494 | } else | 550 | } else |
495 | list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; | 551 | client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; |
496 | } | 552 | } |
497 | 553 | ||
498 | spin_unlock_irqrestore(&list->packet_lock, flags); | 554 | spin_unlock_irqrestore(&client->packet_lock, flags); |
499 | } | 555 | } |
500 | 556 | ||
501 | 557 | ||
502 | static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | 558 | static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
503 | { | 559 | { |
504 | struct mousedev_list *list = file->private_data; | 560 | struct mousedev_client *client = file->private_data; |
505 | unsigned char c; | 561 | unsigned char c; |
506 | unsigned int i; | 562 | unsigned int i; |
507 | 563 | ||
@@ -510,95 +566,95 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si | |||
510 | if (get_user(c, buffer + i)) | 566 | if (get_user(c, buffer + i)) |
511 | return -EFAULT; | 567 | return -EFAULT; |
512 | 568 | ||
513 | if (c == mousedev_imex_seq[list->imexseq]) { | 569 | if (c == mousedev_imex_seq[client->imexseq]) { |
514 | if (++list->imexseq == MOUSEDEV_SEQ_LEN) { | 570 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { |
515 | list->imexseq = 0; | 571 | client->imexseq = 0; |
516 | list->mode = MOUSEDEV_EMUL_EXPS; | 572 | client->mode = MOUSEDEV_EMUL_EXPS; |
517 | } | 573 | } |
518 | } else | 574 | } else |
519 | list->imexseq = 0; | 575 | client->imexseq = 0; |
520 | 576 | ||
521 | if (c == mousedev_imps_seq[list->impsseq]) { | 577 | if (c == mousedev_imps_seq[client->impsseq]) { |
522 | if (++list->impsseq == MOUSEDEV_SEQ_LEN) { | 578 | if (++client->impsseq == MOUSEDEV_SEQ_LEN) { |
523 | list->impsseq = 0; | 579 | client->impsseq = 0; |
524 | list->mode = MOUSEDEV_EMUL_IMPS; | 580 | client->mode = MOUSEDEV_EMUL_IMPS; |
525 | } | 581 | } |
526 | } else | 582 | } else |
527 | list->impsseq = 0; | 583 | client->impsseq = 0; |
528 | 584 | ||
529 | list->ps2[0] = 0xfa; | 585 | client->ps2[0] = 0xfa; |
530 | 586 | ||
531 | switch (c) { | 587 | switch (c) { |
532 | 588 | ||
533 | case 0xeb: /* Poll */ | 589 | case 0xeb: /* Poll */ |
534 | mousedev_packet(list, &list->ps2[1]); | 590 | mousedev_packet(client, &client->ps2[1]); |
535 | list->bufsiz++; /* account for leading ACK */ | 591 | client->bufsiz++; /* account for leading ACK */ |
536 | break; | 592 | break; |
537 | 593 | ||
538 | case 0xf2: /* Get ID */ | 594 | case 0xf2: /* Get ID */ |
539 | switch (list->mode) { | 595 | switch (client->mode) { |
540 | case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break; | 596 | case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break; |
541 | case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break; | 597 | case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break; |
542 | case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break; | 598 | case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break; |
543 | } | 599 | } |
544 | list->bufsiz = 2; | 600 | client->bufsiz = 2; |
545 | break; | 601 | break; |
546 | 602 | ||
547 | case 0xe9: /* Get info */ | 603 | case 0xe9: /* Get info */ |
548 | list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; | 604 | client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; |
549 | list->bufsiz = 4; | 605 | client->bufsiz = 4; |
550 | break; | 606 | break; |
551 | 607 | ||
552 | case 0xff: /* Reset */ | 608 | case 0xff: /* Reset */ |
553 | list->impsseq = list->imexseq = 0; | 609 | client->impsseq = client->imexseq = 0; |
554 | list->mode = MOUSEDEV_EMUL_PS2; | 610 | client->mode = MOUSEDEV_EMUL_PS2; |
555 | list->ps2[1] = 0xaa; list->ps2[2] = 0x00; | 611 | client->ps2[1] = 0xaa; client->ps2[2] = 0x00; |
556 | list->bufsiz = 3; | 612 | client->bufsiz = 3; |
557 | break; | 613 | break; |
558 | 614 | ||
559 | default: | 615 | default: |
560 | list->bufsiz = 1; | 616 | client->bufsiz = 1; |
561 | break; | 617 | break; |
562 | } | 618 | } |
563 | 619 | ||
564 | list->buffer = list->bufsiz; | 620 | client->buffer = client->bufsiz; |
565 | } | 621 | } |
566 | 622 | ||
567 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | 623 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
568 | 624 | ||
569 | wake_up_interruptible(&list->mousedev->wait); | 625 | wake_up_interruptible(&client->mousedev->wait); |
570 | 626 | ||
571 | return count; | 627 | return count; |
572 | } | 628 | } |
573 | 629 | ||
574 | static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) | 630 | static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) |
575 | { | 631 | { |
576 | struct mousedev_list *list = file->private_data; | 632 | struct mousedev_client *client = file->private_data; |
577 | int retval = 0; | 633 | int retval = 0; |
578 | 634 | ||
579 | if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK)) | 635 | if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK)) |
580 | return -EAGAIN; | 636 | return -EAGAIN; |
581 | 637 | ||
582 | retval = wait_event_interruptible(list->mousedev->wait, | 638 | retval = wait_event_interruptible(client->mousedev->wait, |
583 | !list->mousedev->exist || list->ready || list->buffer); | 639 | !client->mousedev->exist || client->ready || client->buffer); |
584 | 640 | ||
585 | if (retval) | 641 | if (retval) |
586 | return retval; | 642 | return retval; |
587 | 643 | ||
588 | if (!list->mousedev->exist) | 644 | if (!client->mousedev->exist) |
589 | return -ENODEV; | 645 | return -ENODEV; |
590 | 646 | ||
591 | if (!list->buffer && list->ready) { | 647 | if (!client->buffer && client->ready) { |
592 | mousedev_packet(list, list->ps2); | 648 | mousedev_packet(client, client->ps2); |
593 | list->buffer = list->bufsiz; | 649 | client->buffer = client->bufsiz; |
594 | } | 650 | } |
595 | 651 | ||
596 | if (count > list->buffer) | 652 | if (count > client->buffer) |
597 | count = list->buffer; | 653 | count = client->buffer; |
598 | 654 | ||
599 | list->buffer -= count; | 655 | client->buffer -= count; |
600 | 656 | ||
601 | if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count)) | 657 | if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count)) |
602 | return -EFAULT; | 658 | return -EFAULT; |
603 | 659 | ||
604 | return count; | 660 | return count; |
@@ -607,11 +663,12 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co | |||
607 | /* No kernel lock - fine */ | 663 | /* No kernel lock - fine */ |
608 | static unsigned int mousedev_poll(struct file *file, poll_table *wait) | 664 | static unsigned int mousedev_poll(struct file *file, poll_table *wait) |
609 | { | 665 | { |
610 | struct mousedev_list *list = file->private_data; | 666 | struct mousedev_client *client = file->private_data; |
667 | struct mousedev *mousedev = client->mousedev; | ||
611 | 668 | ||
612 | poll_wait(file, &list->mousedev->wait, wait); | 669 | poll_wait(file, &mousedev->wait, wait); |
613 | return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) | | 670 | return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) | |
614 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); | 671 | (mousedev->exist ? 0 : (POLLHUP | POLLERR)); |
615 | } | 672 | } |
616 | 673 | ||
617 | static const struct file_operations mousedev_fops = { | 674 | static const struct file_operations mousedev_fops = { |
@@ -624,23 +681,27 @@ static const struct file_operations mousedev_fops = { | |||
624 | .fasync = mousedev_fasync, | 681 | .fasync = mousedev_fasync, |
625 | }; | 682 | }; |
626 | 683 | ||
627 | static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, | 684 | static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, |
628 | const struct input_device_id *id) | 685 | const struct input_device_id *id) |
629 | { | 686 | { |
630 | struct mousedev *mousedev; | 687 | struct mousedev *mousedev; |
631 | struct class_device *cdev; | 688 | struct class_device *cdev; |
632 | int minor = 0; | 689 | dev_t devt; |
690 | int minor; | ||
691 | int error; | ||
633 | 692 | ||
634 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | 693 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); |
635 | if (minor == MOUSEDEV_MINORS) { | 694 | if (minor == MOUSEDEV_MINORS) { |
636 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | 695 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); |
637 | return NULL; | 696 | return -ENFILE; |
638 | } | 697 | } |
639 | 698 | ||
640 | if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL))) | 699 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); |
641 | return NULL; | 700 | if (!mousedev) |
701 | return -ENOMEM; | ||
642 | 702 | ||
643 | INIT_LIST_HEAD(&mousedev->list); | 703 | INIT_LIST_HEAD(&mousedev->client_list); |
704 | INIT_LIST_HEAD(&mousedev->mixdev_node); | ||
644 | init_waitqueue_head(&mousedev->wait); | 705 | init_waitqueue_head(&mousedev->wait); |
645 | 706 | ||
646 | mousedev->minor = minor; | 707 | mousedev->minor = minor; |
@@ -651,42 +712,66 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru | |||
651 | mousedev->handle.private = mousedev; | 712 | mousedev->handle.private = mousedev; |
652 | sprintf(mousedev->name, "mouse%d", minor); | 713 | sprintf(mousedev->name, "mouse%d", minor); |
653 | 714 | ||
654 | if (mousedev_mix.open) | ||
655 | input_open_device(&mousedev->handle); | ||
656 | |||
657 | mousedev_table[minor] = mousedev; | 715 | mousedev_table[minor] = mousedev; |
658 | 716 | ||
659 | cdev = class_device_create(&input_class, &dev->cdev, | 717 | devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), |
660 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), | 718 | |
661 | dev->cdev.dev, mousedev->name); | 719 | cdev = class_device_create(&input_class, &dev->cdev, devt, |
720 | dev->cdev.dev, mousedev->name); | ||
721 | if (IS_ERR(cdev)) { | ||
722 | error = PTR_ERR(cdev); | ||
723 | goto err_free_mousedev; | ||
724 | } | ||
662 | 725 | ||
663 | /* temporary symlink to keep userspace happy */ | 726 | /* temporary symlink to keep userspace happy */ |
664 | sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj, | 727 | error = sysfs_create_link(&input_class.subsys.kobj, |
665 | mousedev->name); | 728 | &cdev->kobj, mousedev->name); |
729 | if (error) | ||
730 | goto err_cdev_destroy; | ||
731 | |||
732 | error = input_register_handle(&mousedev->handle); | ||
733 | if (error) | ||
734 | goto err_remove_link; | ||
735 | |||
736 | error = mixdev_add_device(mousedev); | ||
737 | if (error) | ||
738 | goto err_unregister_handle; | ||
666 | 739 | ||
667 | return &mousedev->handle; | 740 | return 0; |
741 | |||
742 | err_unregister_handle: | ||
743 | input_unregister_handle(&mousedev->handle); | ||
744 | err_remove_link: | ||
745 | sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); | ||
746 | err_cdev_destroy: | ||
747 | class_device_destroy(&input_class, devt); | ||
748 | err_free_mousedev: | ||
749 | mousedev_table[minor] = NULL; | ||
750 | kfree(mousedev); | ||
751 | return error; | ||
668 | } | 752 | } |
669 | 753 | ||
670 | static void mousedev_disconnect(struct input_handle *handle) | 754 | static void mousedev_disconnect(struct input_handle *handle) |
671 | { | 755 | { |
672 | struct mousedev *mousedev = handle->private; | 756 | struct mousedev *mousedev = handle->private; |
673 | struct mousedev_list *list; | 757 | struct mousedev_client *client; |
758 | |||
759 | input_unregister_handle(handle); | ||
674 | 760 | ||
675 | sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); | 761 | sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); |
676 | class_device_destroy(&input_class, | 762 | class_device_destroy(&input_class, |
677 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); | 763 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); |
678 | mousedev->exist = 0; | 764 | mousedev->exist = 0; |
679 | 765 | ||
766 | mixdev_remove_device(mousedev); | ||
767 | |||
680 | if (mousedev->open) { | 768 | if (mousedev->open) { |
681 | input_close_device(handle); | 769 | input_close_device(handle); |
682 | wake_up_interruptible(&mousedev->wait); | 770 | wake_up_interruptible(&mousedev->wait); |
683 | list_for_each_entry(list, &mousedev->list, node) | 771 | list_for_each_entry(client, &mousedev->client_list, node) |
684 | kill_fasync(&list->fasync, SIGIO, POLL_HUP); | 772 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
685 | } else { | 773 | } else |
686 | if (mousedev_mix.open) | ||
687 | input_close_device(handle); | ||
688 | mousedev_free(mousedev); | 774 | mousedev_free(mousedev); |
689 | } | ||
690 | } | 775 | } |
691 | 776 | ||
692 | static const struct input_device_id mousedev_ids[] = { | 777 | static const struct input_device_id mousedev_ids[] = { |
@@ -714,7 +799,7 @@ static const struct input_device_id mousedev_ids[] = { | |||
714 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) }, | 799 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) }, |
715 | }, /* A touchpad */ | 800 | }, /* A touchpad */ |
716 | 801 | ||
717 | { }, /* Terminating entry */ | 802 | { }, /* Terminating entry */ |
718 | }; | 803 | }; |
719 | 804 | ||
720 | MODULE_DEVICE_TABLE(input, mousedev_ids); | 805 | MODULE_DEVICE_TABLE(input, mousedev_ids); |
@@ -746,7 +831,7 @@ static int __init mousedev_init(void) | |||
746 | return error; | 831 | return error; |
747 | 832 | ||
748 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); | 833 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); |
749 | INIT_LIST_HEAD(&mousedev_mix.list); | 834 | INIT_LIST_HEAD(&mousedev_mix.client_list); |
750 | init_waitqueue_head(&mousedev_mix.wait); | 835 | init_waitqueue_head(&mousedev_mix.wait); |
751 | mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; | 836 | mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; |
752 | mousedev_mix.exist = 1; | 837 | mousedev_mix.exist = 1; |