diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 84 |
1 files changed, 42 insertions, 42 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index be6b93c20f60..ab4b2d9b5327 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -30,6 +30,7 @@ struct evdev { | |||
30 | wait_queue_head_t wait; | 30 | wait_queue_head_t wait; |
31 | struct evdev_client *grab; | 31 | struct evdev_client *grab; |
32 | struct list_head client_list; | 32 | struct list_head client_list; |
33 | struct device dev; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct evdev_client { | 36 | struct evdev_client { |
@@ -94,8 +95,10 @@ static int evdev_flush(struct file *file, fl_owner_t id) | |||
94 | return input_flush_device(&evdev->handle, file); | 95 | return input_flush_device(&evdev->handle, file); |
95 | } | 96 | } |
96 | 97 | ||
97 | static void evdev_free(struct evdev *evdev) | 98 | static void evdev_free(struct device *dev) |
98 | { | 99 | { |
100 | struct evdev *evdev = container_of(dev, struct evdev, dev); | ||
101 | |||
99 | evdev_table[evdev->minor] = NULL; | 102 | evdev_table[evdev->minor] = NULL; |
100 | kfree(evdev); | 103 | kfree(evdev); |
101 | } | 104 | } |
@@ -114,12 +117,10 @@ static int evdev_release(struct inode *inode, struct file *file) | |||
114 | list_del(&client->node); | 117 | list_del(&client->node); |
115 | kfree(client); | 118 | kfree(client); |
116 | 119 | ||
117 | if (!--evdev->open) { | 120 | if (!--evdev->open && evdev->exist) |
118 | if (evdev->exist) | 121 | input_close_device(&evdev->handle); |
119 | input_close_device(&evdev->handle); | 122 | |
120 | else | 123 | put_device(&evdev->dev); |
121 | evdev_free(evdev); | ||
122 | } | ||
123 | 124 | ||
124 | return 0; | 125 | return 0; |
125 | } | 126 | } |
@@ -139,24 +140,32 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
139 | if (!evdev || !evdev->exist) | 140 | if (!evdev || !evdev->exist) |
140 | return -ENODEV; | 141 | return -ENODEV; |
141 | 142 | ||
143 | get_device(&evdev->dev); | ||
144 | |||
142 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); | 145 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); |
143 | if (!client) | 146 | if (!client) { |
144 | return -ENOMEM; | 147 | error = -ENOMEM; |
148 | goto err_put_evdev; | ||
149 | } | ||
145 | 150 | ||
146 | client->evdev = evdev; | 151 | client->evdev = evdev; |
147 | list_add_tail(&client->node, &evdev->client_list); | 152 | list_add_tail(&client->node, &evdev->client_list); |
148 | 153 | ||
149 | if (!evdev->open++ && evdev->exist) { | 154 | if (!evdev->open++ && evdev->exist) { |
150 | error = input_open_device(&evdev->handle); | 155 | error = input_open_device(&evdev->handle); |
151 | if (error) { | 156 | if (error) |
152 | list_del(&client->node); | 157 | goto err_free_client; |
153 | kfree(client); | ||
154 | return error; | ||
155 | } | ||
156 | } | 158 | } |
157 | 159 | ||
158 | file->private_data = client; | 160 | file->private_data = client; |
159 | return 0; | 161 | return 0; |
162 | |||
163 | err_free_client: | ||
164 | list_del(&client->node); | ||
165 | kfree(client); | ||
166 | err_put_evdev: | ||
167 | put_device(&evdev->dev); | ||
168 | return error; | ||
160 | } | 169 | } |
161 | 170 | ||
162 | #ifdef CONFIG_COMPAT | 171 | #ifdef CONFIG_COMPAT |
@@ -625,8 +634,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
625 | const struct input_device_id *id) | 634 | const struct input_device_id *id) |
626 | { | 635 | { |
627 | struct evdev *evdev; | 636 | struct evdev *evdev; |
628 | struct class_device *cdev; | ||
629 | dev_t devt; | ||
630 | int minor; | 637 | int minor; |
631 | int error; | 638 | int error; |
632 | 639 | ||
@@ -649,38 +656,32 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
649 | evdev->handle.name = evdev->name; | 656 | evdev->handle.name = evdev->name; |
650 | evdev->handle.handler = handler; | 657 | evdev->handle.handler = handler; |
651 | evdev->handle.private = evdev; | 658 | evdev->handle.private = evdev; |
652 | sprintf(evdev->name, "event%d", minor); | 659 | snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); |
653 | |||
654 | evdev_table[minor] = evdev; | ||
655 | 660 | ||
656 | devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), | 661 | snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id), |
662 | "event%d", minor); | ||
663 | evdev->dev.class = &input_class; | ||
664 | evdev->dev.parent = &dev->dev; | ||
665 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); | ||
666 | evdev->dev.release = evdev_free; | ||
667 | device_initialize(&evdev->dev); | ||
657 | 668 | ||
658 | cdev = class_device_create(&input_class, &dev->cdev, devt, | 669 | evdev_table[minor] = evdev; |
659 | dev->cdev.dev, evdev->name); | ||
660 | if (IS_ERR(cdev)) { | ||
661 | error = PTR_ERR(cdev); | ||
662 | goto err_free_evdev; | ||
663 | } | ||
664 | 670 | ||
665 | /* temporary symlink to keep userspace happy */ | 671 | error = device_add(&evdev->dev); |
666 | error = sysfs_create_link(&input_class.subsys.kobj, | ||
667 | &cdev->kobj, evdev->name); | ||
668 | if (error) | 672 | if (error) |
669 | goto err_cdev_destroy; | 673 | goto err_free_evdev; |
670 | 674 | ||
671 | error = input_register_handle(&evdev->handle); | 675 | error = input_register_handle(&evdev->handle); |
672 | if (error) | 676 | if (error) |
673 | goto err_remove_link; | 677 | goto err_delete_evdev; |
674 | 678 | ||
675 | return 0; | 679 | return 0; |
676 | 680 | ||
677 | err_remove_link: | 681 | err_delete_evdev: |
678 | sysfs_remove_link(&input_class.subsys.kobj, evdev->name); | 682 | device_del(&evdev->dev); |
679 | err_cdev_destroy: | ||
680 | class_device_destroy(&input_class, devt); | ||
681 | err_free_evdev: | 683 | err_free_evdev: |
682 | kfree(evdev); | 684 | put_device(&evdev->dev); |
683 | evdev_table[minor] = NULL; | ||
684 | return error; | 685 | return error; |
685 | } | 686 | } |
686 | 687 | ||
@@ -690,10 +691,8 @@ static void evdev_disconnect(struct input_handle *handle) | |||
690 | struct evdev_client *client; | 691 | struct evdev_client *client; |
691 | 692 | ||
692 | input_unregister_handle(handle); | 693 | input_unregister_handle(handle); |
694 | device_del(&evdev->dev); | ||
693 | 695 | ||
694 | sysfs_remove_link(&input_class.subsys.kobj, evdev->name); | ||
695 | class_device_destroy(&input_class, | ||
696 | MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); | ||
697 | evdev->exist = 0; | 696 | evdev->exist = 0; |
698 | 697 | ||
699 | if (evdev->open) { | 698 | if (evdev->open) { |
@@ -702,8 +701,9 @@ static void evdev_disconnect(struct input_handle *handle) | |||
702 | list_for_each_entry(client, &evdev->client_list, node) | 701 | list_for_each_entry(client, &evdev->client_list, node) |
703 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 702 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
704 | wake_up_interruptible(&evdev->wait); | 703 | wake_up_interruptible(&evdev->wait); |
705 | } else | 704 | } |
706 | evdev_free(evdev); | 705 | |
706 | put_device(&evdev->dev); | ||
707 | } | 707 | } |
708 | 708 | ||
709 | static const struct input_device_id evdev_ids[] = { | 709 | static const struct input_device_id evdev_ids[] = { |