diff options
Diffstat (limited to 'drivers/input/mousedev.c')
| -rw-r--r-- | drivers/input/mousedev.c | 132 |
1 files changed, 62 insertions, 70 deletions
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 88b962aeef13..a1b4c37956b2 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/random.h> | 24 | #include <linux/random.h> |
| 25 | #include <linux/major.h> | 25 | #include <linux/major.h> |
| 26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
| 27 | #include <linux/cdev.h> | ||
| 27 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
| 28 | 29 | ||
| 29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 30 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
| @@ -58,14 +59,15 @@ struct mousedev_hw_data { | |||
| 58 | 59 | ||
| 59 | struct mousedev { | 60 | struct mousedev { |
| 60 | int open; | 61 | int open; |
| 61 | int minor; | ||
| 62 | struct input_handle handle; | 62 | struct input_handle handle; |
| 63 | wait_queue_head_t wait; | 63 | wait_queue_head_t wait; |
| 64 | struct list_head client_list; | 64 | struct list_head client_list; |
| 65 | spinlock_t client_lock; /* protects client_list */ | 65 | spinlock_t client_lock; /* protects client_list */ |
| 66 | struct mutex mutex; | 66 | struct mutex mutex; |
| 67 | struct device dev; | 67 | struct device dev; |
| 68 | struct cdev cdev; | ||
| 68 | bool exist; | 69 | bool exist; |
| 70 | bool is_mixdev; | ||
| 69 | 71 | ||
| 70 | struct list_head mixdev_node; | 72 | struct list_head mixdev_node; |
| 71 | bool opened_by_mixdev; | 73 | bool opened_by_mixdev; |
| @@ -111,10 +113,6 @@ struct mousedev_client { | |||
| 111 | static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; | 113 | static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; |
| 112 | static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | 114 | static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; |
| 113 | 115 | ||
| 114 | static struct input_handler mousedev_handler; | ||
| 115 | |||
| 116 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | ||
| 117 | static DEFINE_MUTEX(mousedev_table_mutex); | ||
| 118 | static struct mousedev *mousedev_mix; | 116 | static struct mousedev *mousedev_mix; |
| 119 | static LIST_HEAD(mousedev_mix_list); | 117 | static LIST_HEAD(mousedev_mix_list); |
| 120 | 118 | ||
| @@ -430,7 +428,7 @@ static int mousedev_open_device(struct mousedev *mousedev) | |||
| 430 | if (retval) | 428 | if (retval) |
| 431 | return retval; | 429 | return retval; |
| 432 | 430 | ||
| 433 | if (mousedev->minor == MOUSEDEV_MIX) | 431 | if (mousedev->is_mixdev) |
| 434 | mixdev_open_devices(); | 432 | mixdev_open_devices(); |
| 435 | else if (!mousedev->exist) | 433 | else if (!mousedev->exist) |
| 436 | retval = -ENODEV; | 434 | retval = -ENODEV; |
| @@ -448,7 +446,7 @@ static void mousedev_close_device(struct mousedev *mousedev) | |||
| 448 | { | 446 | { |
| 449 | mutex_lock(&mousedev->mutex); | 447 | mutex_lock(&mousedev->mutex); |
| 450 | 448 | ||
| 451 | if (mousedev->minor == MOUSEDEV_MIX) | 449 | if (mousedev->is_mixdev) |
| 452 | mixdev_close_devices(); | 450 | mixdev_close_devices(); |
| 453 | else if (mousedev->exist && !--mousedev->open) | 451 | else if (mousedev->exist && !--mousedev->open) |
| 454 | input_close_device(&mousedev->handle); | 452 | input_close_device(&mousedev->handle); |
| @@ -535,35 +533,17 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
| 535 | struct mousedev_client *client; | 533 | struct mousedev_client *client; |
| 536 | struct mousedev *mousedev; | 534 | struct mousedev *mousedev; |
| 537 | int error; | 535 | int error; |
| 538 | int i; | ||
| 539 | 536 | ||
| 540 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 537 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
| 541 | if (imajor(inode) == MISC_MAJOR) | 538 | if (imajor(inode) == MISC_MAJOR) |
| 542 | i = MOUSEDEV_MIX; | 539 | mousedev = mousedev_mix; |
| 543 | else | 540 | else |
| 544 | #endif | 541 | #endif |
| 545 | i = iminor(inode) - MOUSEDEV_MINOR_BASE; | 542 | mousedev = container_of(inode->i_cdev, struct mousedev, cdev); |
| 546 | |||
| 547 | if (i >= MOUSEDEV_MINORS) | ||
| 548 | return -ENODEV; | ||
| 549 | |||
| 550 | error = mutex_lock_interruptible(&mousedev_table_mutex); | ||
| 551 | if (error) | ||
| 552 | return error; | ||
| 553 | |||
| 554 | mousedev = mousedev_table[i]; | ||
| 555 | if (mousedev) | ||
| 556 | get_device(&mousedev->dev); | ||
| 557 | mutex_unlock(&mousedev_table_mutex); | ||
| 558 | |||
| 559 | if (!mousedev) | ||
| 560 | return -ENODEV; | ||
| 561 | 543 | ||
| 562 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | 544 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
| 563 | if (!client) { | 545 | if (!client) |
| 564 | error = -ENOMEM; | 546 | return -ENOMEM; |
| 565 | goto err_put_mousedev; | ||
| 566 | } | ||
| 567 | 547 | ||
| 568 | spin_lock_init(&client->packet_lock); | 548 | spin_lock_init(&client->packet_lock); |
| 569 | client->pos_x = xres / 2; | 549 | client->pos_x = xres / 2; |
| @@ -577,13 +557,13 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
| 577 | 557 | ||
| 578 | file->private_data = client; | 558 | file->private_data = client; |
| 579 | nonseekable_open(inode, file); | 559 | nonseekable_open(inode, file); |
| 560 | |||
| 561 | get_device(&mousedev->dev); | ||
| 580 | return 0; | 562 | return 0; |
| 581 | 563 | ||
| 582 | err_free_client: | 564 | err_free_client: |
| 583 | mousedev_detach_client(mousedev, client); | 565 | mousedev_detach_client(mousedev, client); |
| 584 | kfree(client); | 566 | kfree(client); |
| 585 | err_put_mousedev: | ||
| 586 | put_device(&mousedev->dev); | ||
| 587 | return error; | 567 | return error; |
| 588 | } | 568 | } |
| 589 | 569 | ||
| @@ -793,19 +773,6 @@ static const struct file_operations mousedev_fops = { | |||
| 793 | .llseek = noop_llseek, | 773 | .llseek = noop_llseek, |
| 794 | }; | 774 | }; |
| 795 | 775 | ||
| 796 | static int mousedev_install_chrdev(struct mousedev *mousedev) | ||
| 797 | { | ||
| 798 | mousedev_table[mousedev->minor] = mousedev; | ||
| 799 | return 0; | ||
| 800 | } | ||
| 801 | |||
| 802 | static void mousedev_remove_chrdev(struct mousedev *mousedev) | ||
| 803 | { | ||
| 804 | mutex_lock(&mousedev_table_mutex); | ||
| 805 | mousedev_table[mousedev->minor] = NULL; | ||
| 806 | mutex_unlock(&mousedev_table_mutex); | ||
| 807 | } | ||
| 808 | |||
| 809 | /* | 776 | /* |
| 810 | * Mark device non-existent. This disables writes, ioctls and | 777 | * Mark device non-existent. This disables writes, ioctls and |
| 811 | * prevents new users from opening the device. Already posted | 778 | * prevents new users from opening the device. Already posted |
| @@ -840,24 +807,50 @@ static void mousedev_cleanup(struct mousedev *mousedev) | |||
| 840 | 807 | ||
| 841 | mousedev_mark_dead(mousedev); | 808 | mousedev_mark_dead(mousedev); |
| 842 | mousedev_hangup(mousedev); | 809 | mousedev_hangup(mousedev); |
| 843 | mousedev_remove_chrdev(mousedev); | 810 | |
| 811 | cdev_del(&mousedev->cdev); | ||
| 844 | 812 | ||
| 845 | /* mousedev is marked dead so no one else accesses mousedev->open */ | 813 | /* mousedev is marked dead so no one else accesses mousedev->open */ |
| 846 | if (mousedev->open) | 814 | if (mousedev->open) |
| 847 | input_close_device(handle); | 815 | input_close_device(handle); |
| 848 | } | 816 | } |
| 849 | 817 | ||
| 818 | static int mousedev_reserve_minor(bool mixdev) | ||
| 819 | { | ||
| 820 | int minor; | ||
| 821 | |||
| 822 | if (mixdev) { | ||
| 823 | minor = input_get_new_minor(MOUSEDEV_MIX, 1, false); | ||
| 824 | if (minor < 0) | ||
| 825 | pr_err("failed to reserve mixdev minor: %d\n", minor); | ||
| 826 | } else { | ||
| 827 | minor = input_get_new_minor(MOUSEDEV_MINOR_BASE, | ||
| 828 | MOUSEDEV_MINORS, true); | ||
| 829 | if (minor < 0) | ||
| 830 | pr_err("failed to reserve new minor: %d\n", minor); | ||
| 831 | } | ||
| 832 | |||
| 833 | return minor; | ||
| 834 | } | ||
| 835 | |||
| 850 | static struct mousedev *mousedev_create(struct input_dev *dev, | 836 | static struct mousedev *mousedev_create(struct input_dev *dev, |
| 851 | struct input_handler *handler, | 837 | struct input_handler *handler, |
| 852 | int minor) | 838 | bool mixdev) |
| 853 | { | 839 | { |
| 854 | struct mousedev *mousedev; | 840 | struct mousedev *mousedev; |
| 841 | int minor; | ||
| 855 | int error; | 842 | int error; |
| 856 | 843 | ||
| 844 | minor = mousedev_reserve_minor(mixdev); | ||
| 845 | if (minor < 0) { | ||
| 846 | error = minor; | ||
| 847 | goto err_out; | ||
| 848 | } | ||
| 849 | |||
| 857 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); | 850 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); |
| 858 | if (!mousedev) { | 851 | if (!mousedev) { |
| 859 | error = -ENOMEM; | 852 | error = -ENOMEM; |
| 860 | goto err_out; | 853 | goto err_free_minor; |
| 861 | } | 854 | } |
| 862 | 855 | ||
| 863 | INIT_LIST_HEAD(&mousedev->client_list); | 856 | INIT_LIST_HEAD(&mousedev->client_list); |
| @@ -865,16 +858,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 865 | spin_lock_init(&mousedev->client_lock); | 858 | spin_lock_init(&mousedev->client_lock); |
| 866 | mutex_init(&mousedev->mutex); | 859 | mutex_init(&mousedev->mutex); |
| 867 | lockdep_set_subclass(&mousedev->mutex, | 860 | lockdep_set_subclass(&mousedev->mutex, |
| 868 | minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0); | 861 | mixdev ? SINGLE_DEPTH_NESTING : 0); |
| 869 | init_waitqueue_head(&mousedev->wait); | 862 | init_waitqueue_head(&mousedev->wait); |
| 870 | 863 | ||
| 871 | if (minor == MOUSEDEV_MIX) | 864 | if (mixdev) { |
| 872 | dev_set_name(&mousedev->dev, "mice"); | 865 | dev_set_name(&mousedev->dev, "mice"); |
| 873 | else | 866 | } else { |
| 874 | dev_set_name(&mousedev->dev, "mouse%d", minor); | 867 | int dev_no = minor; |
| 868 | /* Normalize device number if it falls into legacy range */ | ||
| 869 | if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS) | ||
| 870 | dev_no -= MOUSEDEV_MINOR_BASE; | ||
| 871 | dev_set_name(&mousedev->dev, "mouse%d", dev_no); | ||
| 872 | } | ||
| 875 | 873 | ||
| 876 | mousedev->minor = minor; | ||
| 877 | mousedev->exist = true; | 874 | mousedev->exist = true; |
| 875 | mousedev->is_mixdev = mixdev; | ||
| 878 | mousedev->handle.dev = input_get_device(dev); | 876 | mousedev->handle.dev = input_get_device(dev); |
| 879 | mousedev->handle.name = dev_name(&mousedev->dev); | 877 | mousedev->handle.name = dev_name(&mousedev->dev); |
| 880 | mousedev->handle.handler = handler; | 878 | mousedev->handle.handler = handler; |
| @@ -883,17 +881,18 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 883 | mousedev->dev.class = &input_class; | 881 | mousedev->dev.class = &input_class; |
| 884 | if (dev) | 882 | if (dev) |
| 885 | mousedev->dev.parent = &dev->dev; | 883 | mousedev->dev.parent = &dev->dev; |
| 886 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); | 884 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor); |
| 887 | mousedev->dev.release = mousedev_free; | 885 | mousedev->dev.release = mousedev_free; |
| 888 | device_initialize(&mousedev->dev); | 886 | device_initialize(&mousedev->dev); |
| 889 | 887 | ||
| 890 | if (minor != MOUSEDEV_MIX) { | 888 | if (!mixdev) { |
| 891 | error = input_register_handle(&mousedev->handle); | 889 | error = input_register_handle(&mousedev->handle); |
| 892 | if (error) | 890 | if (error) |
| 893 | goto err_free_mousedev; | 891 | goto err_free_mousedev; |
| 894 | } | 892 | } |
| 895 | 893 | ||
| 896 | error = mousedev_install_chrdev(mousedev); | 894 | cdev_init(&mousedev->cdev, &mousedev_fops); |
| 895 | error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1); | ||
| 897 | if (error) | 896 | if (error) |
| 898 | goto err_unregister_handle; | 897 | goto err_unregister_handle; |
| 899 | 898 | ||
| @@ -906,10 +905,12 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 906 | err_cleanup_mousedev: | 905 | err_cleanup_mousedev: |
| 907 | mousedev_cleanup(mousedev); | 906 | mousedev_cleanup(mousedev); |
| 908 | err_unregister_handle: | 907 | err_unregister_handle: |
| 909 | if (minor != MOUSEDEV_MIX) | 908 | if (!mixdev) |
| 910 | input_unregister_handle(&mousedev->handle); | 909 | input_unregister_handle(&mousedev->handle); |
| 911 | err_free_mousedev: | 910 | err_free_mousedev: |
| 912 | put_device(&mousedev->dev); | 911 | put_device(&mousedev->dev); |
| 912 | err_free_minor: | ||
| 913 | input_free_minor(minor); | ||
| 913 | err_out: | 914 | err_out: |
| 914 | return ERR_PTR(error); | 915 | return ERR_PTR(error); |
| 915 | } | 916 | } |
| @@ -918,7 +919,8 @@ static void mousedev_destroy(struct mousedev *mousedev) | |||
| 918 | { | 919 | { |
| 919 | device_del(&mousedev->dev); | 920 | device_del(&mousedev->dev); |
| 920 | mousedev_cleanup(mousedev); | 921 | mousedev_cleanup(mousedev); |
| 921 | if (mousedev->minor != MOUSEDEV_MIX) | 922 | input_free_minor(MINOR(mousedev->dev.devt)); |
| 923 | if (!mousedev->is_mixdev) | ||
| 922 | input_unregister_handle(&mousedev->handle); | 924 | input_unregister_handle(&mousedev->handle); |
| 923 | put_device(&mousedev->dev); | 925 | put_device(&mousedev->dev); |
| 924 | } | 926 | } |
| @@ -967,19 +969,9 @@ static int mousedev_connect(struct input_handler *handler, | |||
| 967 | const struct input_device_id *id) | 969 | const struct input_device_id *id) |
| 968 | { | 970 | { |
| 969 | struct mousedev *mousedev; | 971 | struct mousedev *mousedev; |
| 970 | int minor; | ||
| 971 | int error; | 972 | int error; |
| 972 | 973 | ||
| 973 | for (minor = 0; minor < MOUSEDEV_MINORS; minor++) | 974 | mousedev = mousedev_create(dev, handler, false); |
| 974 | if (!mousedev_table[minor]) | ||
| 975 | break; | ||
| 976 | |||
| 977 | if (minor == MOUSEDEV_MINORS) { | ||
| 978 | pr_err("no more free mousedev devices\n"); | ||
| 979 | return -ENFILE; | ||
| 980 | } | ||
| 981 | |||
| 982 | mousedev = mousedev_create(dev, handler, minor); | ||
| 983 | if (IS_ERR(mousedev)) | 975 | if (IS_ERR(mousedev)) |
| 984 | return PTR_ERR(mousedev); | 976 | return PTR_ERR(mousedev); |
| 985 | 977 | ||
| @@ -1055,7 +1047,7 @@ static struct input_handler mousedev_handler = { | |||
| 1055 | .event = mousedev_event, | 1047 | .event = mousedev_event, |
| 1056 | .connect = mousedev_connect, | 1048 | .connect = mousedev_connect, |
| 1057 | .disconnect = mousedev_disconnect, | 1049 | .disconnect = mousedev_disconnect, |
| 1058 | .fops = &mousedev_fops, | 1050 | .legacy_minors = true, |
| 1059 | .minor = MOUSEDEV_MINOR_BASE, | 1051 | .minor = MOUSEDEV_MINOR_BASE, |
| 1060 | .name = "mousedev", | 1052 | .name = "mousedev", |
| 1061 | .id_table = mousedev_ids, | 1053 | .id_table = mousedev_ids, |
| @@ -1098,7 +1090,7 @@ static int __init mousedev_init(void) | |||
| 1098 | { | 1090 | { |
| 1099 | int error; | 1091 | int error; |
| 1100 | 1092 | ||
| 1101 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); | 1093 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, true); |
| 1102 | if (IS_ERR(mousedev_mix)) | 1094 | if (IS_ERR(mousedev_mix)) |
| 1103 | return PTR_ERR(mousedev_mix); | 1095 | return PTR_ERR(mousedev_mix); |
| 1104 | 1096 | ||
