diff options
Diffstat (limited to 'drivers/input/joydev.c')
-rw-r--r-- | drivers/input/joydev.c | 84 |
1 files changed, 43 insertions, 41 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 10e3b7bc925f..a9a0180bfd46 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
@@ -43,6 +43,8 @@ struct joydev { | |||
43 | struct input_handle handle; | 43 | struct input_handle handle; |
44 | wait_queue_head_t wait; | 44 | wait_queue_head_t wait; |
45 | struct list_head client_list; | 45 | struct list_head client_list; |
46 | struct device dev; | ||
47 | |||
46 | struct js_corr corr[ABS_MAX + 1]; | 48 | struct js_corr corr[ABS_MAX + 1]; |
47 | struct JS_DATA_SAVE_TYPE glue; | 49 | struct JS_DATA_SAVE_TYPE glue; |
48 | int nabs; | 50 | int nabs; |
@@ -138,8 +140,10 @@ static int joydev_fasync(int fd, struct file *file, int on) | |||
138 | return retval < 0 ? retval : 0; | 140 | return retval < 0 ? retval : 0; |
139 | } | 141 | } |
140 | 142 | ||
141 | static void joydev_free(struct joydev *joydev) | 143 | static void joydev_free(struct device *dev) |
142 | { | 144 | { |
145 | struct joydev *joydev = container_of(dev, struct joydev, dev); | ||
146 | |||
143 | joydev_table[joydev->minor] = NULL; | 147 | joydev_table[joydev->minor] = NULL; |
144 | kfree(joydev); | 148 | kfree(joydev); |
145 | } | 149 | } |
@@ -154,12 +158,10 @@ static int joydev_release(struct inode *inode, struct file *file) | |||
154 | list_del(&client->node); | 158 | list_del(&client->node); |
155 | kfree(client); | 159 | kfree(client); |
156 | 160 | ||
157 | if (!--joydev->open) { | 161 | if (!--joydev->open && joydev->exist) |
158 | if (joydev->exist) | 162 | input_close_device(&joydev->handle); |
159 | input_close_device(&joydev->handle); | 163 | |
160 | else | 164 | put_device(&joydev->dev); |
161 | joydev_free(joydev); | ||
162 | } | ||
163 | 165 | ||
164 | return 0; | 166 | return 0; |
165 | } | 167 | } |
@@ -178,24 +180,32 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
178 | if (!joydev || !joydev->exist) | 180 | if (!joydev || !joydev->exist) |
179 | return -ENODEV; | 181 | return -ENODEV; |
180 | 182 | ||
183 | get_device(&joydev->dev); | ||
184 | |||
181 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); | 185 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
182 | if (!client) | 186 | if (!client) { |
183 | return -ENOMEM; | 187 | error = -ENOMEM; |
188 | goto err_put_joydev; | ||
189 | } | ||
184 | 190 | ||
185 | client->joydev = joydev; | 191 | client->joydev = joydev; |
186 | list_add_tail(&client->node, &joydev->client_list); | 192 | list_add_tail(&client->node, &joydev->client_list); |
187 | 193 | ||
188 | if (!joydev->open++ && joydev->exist) { | 194 | if (!joydev->open++ && joydev->exist) { |
189 | error = input_open_device(&joydev->handle); | 195 | error = input_open_device(&joydev->handle); |
190 | if (error) { | 196 | if (error) |
191 | list_del(&client->node); | 197 | goto err_free_client; |
192 | kfree(client); | ||
193 | return error; | ||
194 | } | ||
195 | } | 198 | } |
196 | 199 | ||
197 | file->private_data = client; | 200 | file->private_data = client; |
198 | return 0; | 201 | return 0; |
202 | |||
203 | err_free_client: | ||
204 | list_del(&client->node); | ||
205 | kfree(client); | ||
206 | err_put_joydev: | ||
207 | put_device(&joydev->dev); | ||
208 | return error; | ||
199 | } | 209 | } |
200 | 210 | ||
201 | static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 211 | static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
@@ -481,8 +491,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
481 | const struct input_device_id *id) | 491 | const struct input_device_id *id) |
482 | { | 492 | { |
483 | struct joydev *joydev; | 493 | struct joydev *joydev; |
484 | struct class_device *cdev; | ||
485 | dev_t devt; | ||
486 | int i, j, t, minor; | 494 | int i, j, t, minor; |
487 | int error; | 495 | int error; |
488 | 496 | ||
@@ -505,7 +513,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
505 | joydev->handle.name = joydev->name; | 513 | joydev->handle.name = joydev->name; |
506 | joydev->handle.handler = handler; | 514 | joydev->handle.handler = handler; |
507 | joydev->handle.private = joydev; | 515 | joydev->handle.private = joydev; |
508 | sprintf(joydev->name, "js%d", minor); | 516 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); |
509 | 517 | ||
510 | for (i = 0; i < ABS_MAX + 1; i++) | 518 | for (i = 0; i < ABS_MAX + 1; i++) |
511 | if (test_bit(i, dev->absbit)) { | 519 | if (test_bit(i, dev->absbit)) { |
@@ -547,36 +555,30 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
547 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | 555 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); |
548 | } | 556 | } |
549 | 557 | ||
550 | joydev_table[minor] = joydev; | 558 | snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id), |
551 | 559 | "js%d", minor); | |
552 | devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), | 560 | joydev->dev.class = &input_class; |
561 | joydev->dev.parent = &dev->dev; | ||
562 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); | ||
563 | joydev->dev.release = joydev_free; | ||
564 | device_initialize(&joydev->dev); | ||
553 | 565 | ||
554 | cdev = class_device_create(&input_class, &dev->cdev, devt, | 566 | joydev_table[minor] = joydev; |
555 | dev->cdev.dev, joydev->name); | ||
556 | if (IS_ERR(cdev)) { | ||
557 | error = PTR_ERR(cdev); | ||
558 | goto err_free_joydev; | ||
559 | } | ||
560 | 567 | ||
561 | /* temporary symlink to keep userspace happy */ | 568 | error = device_add(&joydev->dev); |
562 | error = sysfs_create_link(&input_class.subsys.kobj, | ||
563 | &cdev->kobj, joydev->name); | ||
564 | if (error) | 569 | if (error) |
565 | goto err_cdev_destroy; | 570 | goto err_free_joydev; |
566 | 571 | ||
567 | error = input_register_handle(&joydev->handle); | 572 | error = input_register_handle(&joydev->handle); |
568 | if (error) | 573 | if (error) |
569 | goto err_remove_link; | 574 | goto err_delete_joydev; |
570 | 575 | ||
571 | return 0; | 576 | return 0; |
572 | 577 | ||
573 | err_remove_link: | 578 | err_delete_joydev: |
574 | sysfs_remove_link(&input_class.subsys.kobj, joydev->name); | 579 | device_del(&joydev->dev); |
575 | err_cdev_destroy: | ||
576 | class_device_destroy(&input_class, devt); | ||
577 | err_free_joydev: | 580 | err_free_joydev: |
578 | joydev_table[minor] = NULL; | 581 | put_device(&joydev->dev); |
579 | kfree(joydev); | ||
580 | return error; | 582 | return error; |
581 | } | 583 | } |
582 | 584 | ||
@@ -587,9 +589,8 @@ static void joydev_disconnect(struct input_handle *handle) | |||
587 | struct joydev_client *client; | 589 | struct joydev_client *client; |
588 | 590 | ||
589 | input_unregister_handle(handle); | 591 | input_unregister_handle(handle); |
592 | device_del(&joydev->dev); | ||
590 | 593 | ||
591 | sysfs_remove_link(&input_class.subsys.kobj, joydev->name); | ||
592 | class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); | ||
593 | joydev->exist = 0; | 594 | joydev->exist = 0; |
594 | 595 | ||
595 | if (joydev->open) { | 596 | if (joydev->open) { |
@@ -597,8 +598,9 @@ static void joydev_disconnect(struct input_handle *handle) | |||
597 | list_for_each_entry(client, &joydev->client_list, node) | 598 | list_for_each_entry(client, &joydev->client_list, node) |
598 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 599 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
599 | wake_up_interruptible(&joydev->wait); | 600 | wake_up_interruptible(&joydev->wait); |
600 | } else | 601 | } |
601 | joydev_free(joydev); | 602 | |
603 | put_device(&joydev->dev); | ||
602 | } | 604 | } |
603 | 605 | ||
604 | static const struct input_device_id joydev_blacklist[] = { | 606 | static const struct input_device_id joydev_blacklist[] = { |