diff options
Diffstat (limited to 'drivers/input/mousedev.c')
-rw-r--r-- | drivers/input/mousedev.c | 242 |
1 files changed, 132 insertions, 110 deletions
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 3f4866d8d18c..9173916b8be5 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
@@ -64,6 +64,7 @@ struct mousedev { | |||
64 | wait_queue_head_t wait; | 64 | wait_queue_head_t wait; |
65 | struct list_head client_list; | 65 | struct list_head client_list; |
66 | struct input_handle handle; | 66 | struct input_handle handle; |
67 | struct device dev; | ||
67 | 68 | ||
68 | struct list_head mixdev_node; | 69 | struct list_head mixdev_node; |
69 | int mixdev_open; | 70 | int mixdev_open; |
@@ -112,7 +113,7 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | |||
112 | static struct input_handler mousedev_handler; | 113 | static struct input_handler mousedev_handler; |
113 | 114 | ||
114 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | 115 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; |
115 | static struct mousedev mousedev_mix; | 116 | static struct mousedev *mousedev_mix; |
116 | static LIST_HEAD(mousedev_mix_list); | 117 | static LIST_HEAD(mousedev_mix_list); |
117 | 118 | ||
118 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) | 119 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) |
@@ -218,10 +219,10 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int | |||
218 | 219 | ||
219 | if (value) { | 220 | if (value) { |
220 | set_bit(index, &mousedev->packet.buttons); | 221 | set_bit(index, &mousedev->packet.buttons); |
221 | set_bit(index, &mousedev_mix.packet.buttons); | 222 | set_bit(index, &mousedev_mix->packet.buttons); |
222 | } else { | 223 | } else { |
223 | clear_bit(index, &mousedev->packet.buttons); | 224 | clear_bit(index, &mousedev->packet.buttons); |
224 | clear_bit(index, &mousedev_mix.packet.buttons); | 225 | clear_bit(index, &mousedev_mix->packet.buttons); |
225 | } | 226 | } |
226 | } | 227 | } |
227 | 228 | ||
@@ -287,11 +288,11 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
287 | * motion packet so we won't mess current position. | 288 | * motion packet so we won't mess current position. |
288 | */ | 289 | */ |
289 | set_bit(0, &mousedev->packet.buttons); | 290 | set_bit(0, &mousedev->packet.buttons); |
290 | set_bit(0, &mousedev_mix.packet.buttons); | 291 | set_bit(0, &mousedev_mix->packet.buttons); |
291 | mousedev_notify_readers(mousedev, &mousedev_mix.packet); | 292 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); |
292 | mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet); | 293 | mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet); |
293 | clear_bit(0, &mousedev->packet.buttons); | 294 | clear_bit(0, &mousedev->packet.buttons); |
294 | clear_bit(0, &mousedev_mix.packet.buttons); | 295 | clear_bit(0, &mousedev_mix->packet.buttons); |
295 | } | 296 | } |
296 | mousedev->touch = mousedev->pkt_count = 0; | 297 | mousedev->touch = mousedev->pkt_count = 0; |
297 | mousedev->frac_dx = 0; | 298 | mousedev->frac_dx = 0; |
@@ -343,7 +344,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig | |||
343 | } | 344 | } |
344 | 345 | ||
345 | mousedev_notify_readers(mousedev, &mousedev->packet); | 346 | mousedev_notify_readers(mousedev, &mousedev->packet); |
346 | mousedev_notify_readers(&mousedev_mix, &mousedev->packet); | 347 | mousedev_notify_readers(mousedev_mix, &mousedev->packet); |
347 | 348 | ||
348 | mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; | 349 | mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; |
349 | mousedev->packet.abs_event = 0; | 350 | mousedev->packet.abs_event = 0; |
@@ -362,8 +363,10 @@ static int mousedev_fasync(int fd, struct file *file, int on) | |||
362 | return retval < 0 ? retval : 0; | 363 | return retval < 0 ? retval : 0; |
363 | } | 364 | } |
364 | 365 | ||
365 | static void mousedev_free(struct mousedev *mousedev) | 366 | static void mousedev_free(struct device *dev) |
366 | { | 367 | { |
368 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); | ||
369 | |||
367 | mousedev_table[mousedev->minor] = NULL; | 370 | mousedev_table[mousedev->minor] = NULL; |
368 | kfree(mousedev); | 371 | kfree(mousedev); |
369 | } | 372 | } |
@@ -372,15 +375,16 @@ static int mixdev_add_device(struct mousedev *mousedev) | |||
372 | { | 375 | { |
373 | int error; | 376 | int error; |
374 | 377 | ||
375 | if (mousedev_mix.open) { | 378 | if (mousedev_mix->open) { |
376 | error = input_open_device(&mousedev->handle); | 379 | error = input_open_device(&mousedev->handle); |
377 | if (error) | 380 | if (error) |
378 | return error; | 381 | return error; |
379 | 382 | ||
380 | mousedev->open++; | 383 | mousedev->open++; |
381 | mousedev->mixdev_open++; | 384 | mousedev->mixdev_open = 1; |
382 | } | 385 | } |
383 | 386 | ||
387 | get_device(&mousedev->dev); | ||
384 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | 388 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); |
385 | 389 | ||
386 | return 0; | 390 | return 0; |
@@ -395,36 +399,40 @@ static void mixdev_remove_device(struct mousedev *mousedev) | |||
395 | } | 399 | } |
396 | 400 | ||
397 | list_del_init(&mousedev->mixdev_node); | 401 | list_del_init(&mousedev->mixdev_node); |
402 | put_device(&mousedev->dev); | ||
398 | } | 403 | } |
399 | 404 | ||
400 | static void mixdev_open_devices(void) | 405 | static void mixdev_open_devices(void) |
401 | { | 406 | { |
402 | struct mousedev *mousedev; | 407 | struct mousedev *mousedev; |
403 | 408 | ||
409 | if (mousedev_mix->open++) | ||
410 | return; | ||
411 | |||
404 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 412 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
405 | if (mousedev->exist && !mousedev->open) { | 413 | if (!mousedev->mixdev_open) { |
406 | if (input_open_device(&mousedev->handle)) | 414 | if (!mousedev->open && mousedev->exist) |
407 | continue; | 415 | if (input_open_device(&mousedev->handle)) |
416 | continue; | ||
408 | 417 | ||
409 | mousedev->open++; | 418 | mousedev->open++; |
410 | mousedev->mixdev_open++; | 419 | mousedev->mixdev_open = 1; |
411 | } | 420 | } |
412 | } | 421 | } |
413 | } | 422 | } |
414 | 423 | ||
415 | static void mixdev_close_devices(void) | 424 | static void mixdev_close_devices(void) |
416 | { | 425 | { |
417 | struct mousedev *mousedev, *next; | 426 | struct mousedev *mousedev; |
418 | 427 | ||
419 | list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) { | 428 | if (--mousedev_mix->open) |
429 | return; | ||
430 | |||
431 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | ||
420 | if (mousedev->mixdev_open) { | 432 | if (mousedev->mixdev_open) { |
421 | mousedev->mixdev_open = 0; | 433 | mousedev->mixdev_open = 0; |
422 | if (!--mousedev->open) { | 434 | if (!--mousedev->open && mousedev->exist) |
423 | if (mousedev->exist) | 435 | input_close_device(&mousedev->handle); |
424 | input_close_device(&mousedev->handle); | ||
425 | else | ||
426 | mousedev_free(mousedev); | ||
427 | } | ||
428 | } | 436 | } |
429 | } | 437 | } |
430 | } | 438 | } |
@@ -439,14 +447,12 @@ static int mousedev_release(struct inode *inode, struct file *file) | |||
439 | list_del(&client->node); | 447 | list_del(&client->node); |
440 | kfree(client); | 448 | kfree(client); |
441 | 449 | ||
442 | if (!--mousedev->open) { | 450 | if (mousedev->minor == MOUSEDEV_MIX) |
443 | if (mousedev->minor == MOUSEDEV_MIX) | 451 | mixdev_close_devices(); |
444 | mixdev_close_devices(); | 452 | else if (!--mousedev->open && mousedev->exist) |
445 | else if (mousedev->exist) | 453 | input_close_device(&mousedev->handle); |
446 | input_close_device(&mousedev->handle); | 454 | |
447 | else | 455 | put_device(&mousedev->dev); |
448 | mousedev_free(mousedev); | ||
449 | } | ||
450 | 456 | ||
451 | return 0; | 457 | return 0; |
452 | } | 458 | } |
@@ -473,9 +479,13 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
473 | if (!mousedev) | 479 | if (!mousedev) |
474 | return -ENODEV; | 480 | return -ENODEV; |
475 | 481 | ||
482 | get_device(&mousedev->dev); | ||
483 | |||
476 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | 484 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
477 | if (!client) | 485 | if (!client) { |
478 | return -ENOMEM; | 486 | error = -ENOMEM; |
487 | goto err_put_mousedev; | ||
488 | } | ||
479 | 489 | ||
480 | spin_lock_init(&client->packet_lock); | 490 | spin_lock_init(&client->packet_lock); |
481 | client->pos_x = xres / 2; | 491 | client->pos_x = xres / 2; |
@@ -483,21 +493,23 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
483 | client->mousedev = mousedev; | 493 | client->mousedev = mousedev; |
484 | list_add_tail(&client->node, &mousedev->client_list); | 494 | list_add_tail(&client->node, &mousedev->client_list); |
485 | 495 | ||
486 | if (!mousedev->open++) { | 496 | if (mousedev->minor == MOUSEDEV_MIX) |
487 | if (mousedev->minor == MOUSEDEV_MIX) | 497 | mixdev_open_devices(); |
488 | mixdev_open_devices(); | 498 | else if (!mousedev->open++ && mousedev->exist) { |
489 | else if (mousedev->exist) { | 499 | error = input_open_device(&mousedev->handle); |
490 | error = input_open_device(&mousedev->handle); | 500 | if (error) |
491 | if (error) { | 501 | goto err_free_client; |
492 | list_del(&client->node); | ||
493 | kfree(client); | ||
494 | return error; | ||
495 | } | ||
496 | } | ||
497 | } | 502 | } |
498 | 503 | ||
499 | file->private_data = client; | 504 | file->private_data = client; |
500 | return 0; | 505 | return 0; |
506 | |||
507 | err_free_client: | ||
508 | list_del(&client->node); | ||
509 | kfree(client); | ||
510 | err_put_mousedev: | ||
511 | put_device(&mousedev->dev); | ||
512 | return error; | ||
501 | } | 513 | } |
502 | 514 | ||
503 | static inline int mousedev_limit_delta(int delta, int limit) | 515 | static inline int mousedev_limit_delta(int delta, int limit) |
@@ -680,57 +692,96 @@ static const struct file_operations mousedev_fops = { | |||
680 | .fasync = mousedev_fasync, | 692 | .fasync = mousedev_fasync, |
681 | }; | 693 | }; |
682 | 694 | ||
683 | static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, | 695 | static struct mousedev *mousedev_create(struct input_dev *dev, |
684 | const struct input_device_id *id) | 696 | struct input_handler *handler, |
697 | int minor) | ||
685 | { | 698 | { |
686 | struct mousedev *mousedev; | 699 | struct mousedev *mousedev; |
687 | struct class_device *cdev; | ||
688 | dev_t devt; | ||
689 | int minor; | ||
690 | int error; | 700 | int error; |
691 | 701 | ||
692 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | ||
693 | if (minor == MOUSEDEV_MINORS) { | ||
694 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | ||
695 | return -ENFILE; | ||
696 | } | ||
697 | |||
698 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); | 702 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); |
699 | if (!mousedev) | 703 | if (!mousedev) { |
700 | return -ENOMEM; | 704 | error = -ENOMEM; |
705 | goto err_out; | ||
706 | } | ||
701 | 707 | ||
702 | INIT_LIST_HEAD(&mousedev->client_list); | 708 | INIT_LIST_HEAD(&mousedev->client_list); |
703 | INIT_LIST_HEAD(&mousedev->mixdev_node); | 709 | INIT_LIST_HEAD(&mousedev->mixdev_node); |
704 | init_waitqueue_head(&mousedev->wait); | 710 | init_waitqueue_head(&mousedev->wait); |
705 | 711 | ||
712 | if (minor == MOUSEDEV_MIX) | ||
713 | strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); | ||
714 | else | ||
715 | snprintf(mousedev->name, sizeof(mousedev->name), | ||
716 | "mouse%d", minor); | ||
717 | |||
706 | mousedev->minor = minor; | 718 | mousedev->minor = minor; |
707 | mousedev->exist = 1; | 719 | mousedev->exist = 1; |
708 | mousedev->handle.dev = dev; | 720 | mousedev->handle.dev = dev; |
709 | mousedev->handle.name = mousedev->name; | 721 | mousedev->handle.name = mousedev->name; |
710 | mousedev->handle.handler = handler; | 722 | mousedev->handle.handler = handler; |
711 | mousedev->handle.private = mousedev; | 723 | mousedev->handle.private = mousedev; |
712 | sprintf(mousedev->name, "mouse%d", minor); | ||
713 | 724 | ||
714 | mousedev_table[minor] = mousedev; | 725 | strlcpy(mousedev->dev.bus_id, mousedev->name, |
726 | sizeof(mousedev->dev.bus_id)); | ||
727 | mousedev->dev.class = &input_class; | ||
728 | if (dev) | ||
729 | mousedev->dev.parent = &dev->dev; | ||
730 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); | ||
731 | mousedev->dev.release = mousedev_free; | ||
732 | device_initialize(&mousedev->dev); | ||
715 | 733 | ||
716 | devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), | 734 | mousedev_table[minor] = mousedev; |
717 | 735 | ||
718 | cdev = class_device_create(&input_class, &dev->cdev, devt, | 736 | error = device_add(&mousedev->dev); |
719 | dev->cdev.dev, mousedev->name); | 737 | if (error) |
720 | if (IS_ERR(cdev)) { | ||
721 | error = PTR_ERR(cdev); | ||
722 | goto err_free_mousedev; | 738 | goto err_free_mousedev; |
739 | |||
740 | return mousedev; | ||
741 | |||
742 | err_free_mousedev: | ||
743 | put_device(&mousedev->dev); | ||
744 | err_out: | ||
745 | return ERR_PTR(error); | ||
746 | } | ||
747 | |||
748 | static void mousedev_destroy(struct mousedev *mousedev) | ||
749 | { | ||
750 | struct mousedev_client *client; | ||
751 | |||
752 | device_del(&mousedev->dev); | ||
753 | mousedev->exist = 0; | ||
754 | |||
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); | ||
723 | } | 760 | } |
724 | 761 | ||
725 | /* temporary symlink to keep userspace happy */ | 762 | put_device(&mousedev->dev); |
726 | error = sysfs_create_link(&input_class.subsys.kobj, | 763 | } |
727 | &cdev->kobj, mousedev->name); | 764 | |
728 | if (error) | 765 | static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, |
729 | goto err_cdev_destroy; | 766 | const struct input_device_id *id) |
767 | { | ||
768 | struct mousedev *mousedev; | ||
769 | int minor; | ||
770 | int error; | ||
771 | |||
772 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | ||
773 | if (minor == MOUSEDEV_MINORS) { | ||
774 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | ||
775 | return -ENFILE; | ||
776 | } | ||
777 | |||
778 | mousedev = mousedev_create(dev, handler, minor); | ||
779 | if (IS_ERR(mousedev)) | ||
780 | return PTR_ERR(mousedev); | ||
730 | 781 | ||
731 | error = input_register_handle(&mousedev->handle); | 782 | error = input_register_handle(&mousedev->handle); |
732 | if (error) | 783 | if (error) |
733 | goto err_remove_link; | 784 | goto err_delete_mousedev; |
734 | 785 | ||
735 | error = mixdev_add_device(mousedev); | 786 | error = mixdev_add_device(mousedev); |
736 | if (error) | 787 | if (error) |
@@ -740,37 +791,18 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev | |||
740 | 791 | ||
741 | err_unregister_handle: | 792 | err_unregister_handle: |
742 | input_unregister_handle(&mousedev->handle); | 793 | input_unregister_handle(&mousedev->handle); |
743 | err_remove_link: | 794 | err_delete_mousedev: |
744 | sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); | 795 | device_unregister(&mousedev->dev); |
745 | err_cdev_destroy: | ||
746 | class_device_destroy(&input_class, devt); | ||
747 | err_free_mousedev: | ||
748 | mousedev_table[minor] = NULL; | ||
749 | kfree(mousedev); | ||
750 | return error; | 796 | return error; |
751 | } | 797 | } |
752 | 798 | ||
753 | static void mousedev_disconnect(struct input_handle *handle) | 799 | static void mousedev_disconnect(struct input_handle *handle) |
754 | { | 800 | { |
755 | struct mousedev *mousedev = handle->private; | 801 | struct mousedev *mousedev = handle->private; |
756 | struct mousedev_client *client; | ||
757 | |||
758 | input_unregister_handle(handle); | ||
759 | |||
760 | sysfs_remove_link(&input_class.subsys.kobj, mousedev->name); | ||
761 | class_device_destroy(&input_class, | ||
762 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); | ||
763 | mousedev->exist = 0; | ||
764 | 802 | ||
765 | mixdev_remove_device(mousedev); | 803 | mixdev_remove_device(mousedev); |
766 | 804 | input_unregister_handle(handle); | |
767 | if (mousedev->open) { | 805 | mousedev_destroy(mousedev); |
768 | input_close_device(handle); | ||
769 | list_for_each_entry(client, &mousedev->client_list, node) | ||
770 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
771 | wake_up_interruptible(&mousedev->wait); | ||
772 | } else | ||
773 | mousedev_free(mousedev); | ||
774 | } | 806 | } |
775 | 807 | ||
776 | static const struct input_device_id mousedev_ids[] = { | 808 | static const struct input_device_id mousedev_ids[] = { |
@@ -822,25 +854,16 @@ static int psaux_registered; | |||
822 | 854 | ||
823 | static int __init mousedev_init(void) | 855 | static int __init mousedev_init(void) |
824 | { | 856 | { |
825 | struct class_device *cdev; | ||
826 | int error; | 857 | int error; |
827 | 858 | ||
859 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); | ||
860 | if (IS_ERR(mousedev_mix)) | ||
861 | return PTR_ERR(mousedev_mix); | ||
862 | |||
828 | error = input_register_handler(&mousedev_handler); | 863 | error = input_register_handler(&mousedev_handler); |
829 | if (error) | 864 | if (error) { |
865 | mousedev_destroy(mousedev_mix); | ||
830 | return error; | 866 | return error; |
831 | |||
832 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); | ||
833 | INIT_LIST_HEAD(&mousedev_mix.client_list); | ||
834 | init_waitqueue_head(&mousedev_mix.wait); | ||
835 | mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; | ||
836 | mousedev_mix.exist = 1; | ||
837 | mousedev_mix.minor = MOUSEDEV_MIX; | ||
838 | |||
839 | cdev = class_device_create(&input_class, NULL, | ||
840 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); | ||
841 | if (IS_ERR(cdev)) { | ||
842 | input_unregister_handler(&mousedev_handler); | ||
843 | return PTR_ERR(cdev); | ||
844 | } | 867 | } |
845 | 868 | ||
846 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 869 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
@@ -863,9 +886,8 @@ static void __exit mousedev_exit(void) | |||
863 | if (psaux_registered) | 886 | if (psaux_registered) |
864 | misc_deregister(&psaux_mouse); | 887 | misc_deregister(&psaux_mouse); |
865 | #endif | 888 | #endif |
866 | class_device_destroy(&input_class, | ||
867 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); | ||
868 | input_unregister_handler(&mousedev_handler); | 889 | input_unregister_handler(&mousedev_handler); |
890 | mousedev_destroy(mousedev_mix); | ||
869 | } | 891 | } |
870 | 892 | ||
871 | module_init(mousedev_init); | 893 | module_init(mousedev_init); |