Commit 5b2a08262a8c952fef008154933953f083ca5766
1 parent
6e782584e0
Input: rework handle creation code
- consolidate code for binding handlers to a device - return error codes from handlers connect() methods back to input core and log failures Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 9 changed files with 288 additions and 125 deletions Side-by-side Diff
drivers/char/keyboard.c
... | ... | @@ -41,7 +41,6 @@ |
41 | 41 | #include <linux/input.h> |
42 | 42 | #include <linux/reboot.h> |
43 | 43 | |
44 | -static void kbd_disconnect(struct input_handle *handle); | |
45 | 44 | extern void ctrl_alt_del(void); |
46 | 45 | |
47 | 46 | /* |
48 | 47 | |
... | ... | @@ -1260,11 +1259,11 @@ |
1260 | 1259 | * likes it, it can open it and get events from it. In this (kbd_connect) |
1261 | 1260 | * function, we should decide which VT to bind that keyboard to initially. |
1262 | 1261 | */ |
1263 | -static struct input_handle *kbd_connect(struct input_handler *handler, | |
1264 | - struct input_dev *dev, | |
1265 | - const struct input_device_id *id) | |
1262 | +static int kbd_connect(struct input_handler *handler, struct input_dev *dev, | |
1263 | + const struct input_device_id *id) | |
1266 | 1264 | { |
1267 | 1265 | struct input_handle *handle; |
1266 | + int error; | |
1268 | 1267 | int i; |
1269 | 1268 | |
1270 | 1269 | for (i = KEY_RESERVED; i < BTN_MISC; i++) |
1271 | 1270 | |
1272 | 1271 | |
1273 | 1272 | |
1274 | 1273 | |
... | ... | @@ -1272,24 +1271,37 @@ |
1272 | 1271 | break; |
1273 | 1272 | |
1274 | 1273 | if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) |
1275 | - return NULL; | |
1274 | + return -ENODEV; | |
1276 | 1275 | |
1277 | 1276 | handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); |
1278 | 1277 | if (!handle) |
1279 | - return NULL; | |
1278 | + return -ENOMEM; | |
1280 | 1279 | |
1281 | 1280 | handle->dev = dev; |
1282 | 1281 | handle->handler = handler; |
1283 | 1282 | handle->name = "kbd"; |
1284 | 1283 | |
1285 | - input_open_device(handle); | |
1284 | + error = input_register_handle(handle); | |
1285 | + if (error) | |
1286 | + goto err_free_handle; | |
1286 | 1287 | |
1287 | - return handle; | |
1288 | + error = input_open_device(handle); | |
1289 | + if (error) | |
1290 | + goto err_unregister_handle; | |
1291 | + | |
1292 | + return 0; | |
1293 | + | |
1294 | + err_unregister_handle: | |
1295 | + input_unregister_handle(handle); | |
1296 | + err_free_handle: | |
1297 | + kfree(handle); | |
1298 | + return error; | |
1288 | 1299 | } |
1289 | 1300 | |
1290 | 1301 | static void kbd_disconnect(struct input_handle *handle) |
1291 | 1302 | { |
1292 | 1303 | input_close_device(handle); |
1304 | + input_unregister_handle(handle); | |
1293 | 1305 | kfree(handle); |
1294 | 1306 | } |
1295 | 1307 |
drivers/input/evbug.c
... | ... | @@ -38,31 +38,43 @@ |
38 | 38 | MODULE_DESCRIPTION("Input driver event debug module"); |
39 | 39 | MODULE_LICENSE("GPL"); |
40 | 40 | |
41 | -static char evbug_name[] = "evbug"; | |
42 | - | |
43 | 41 | static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) |
44 | 42 | { |
45 | 43 | printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", |
46 | 44 | handle->dev->phys, type, code, value); |
47 | 45 | } |
48 | 46 | |
49 | -static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, | |
50 | - const struct input_device_id *id) | |
47 | +static int evbug_connect(struct input_handler *handler, struct input_dev *dev, | |
48 | + const struct input_device_id *id) | |
51 | 49 | { |
52 | 50 | struct input_handle *handle; |
51 | + int error; | |
53 | 52 | |
54 | - if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) | |
55 | - return NULL; | |
53 | + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); | |
54 | + if (!handle) | |
55 | + return -ENOMEM; | |
56 | 56 | |
57 | 57 | handle->dev = dev; |
58 | 58 | handle->handler = handler; |
59 | - handle->name = evbug_name; | |
59 | + handle->name = "evbug"; | |
60 | 60 | |
61 | - input_open_device(handle); | |
61 | + error = input_register_handle(handle); | |
62 | + if (error) | |
63 | + goto err_free_handle; | |
62 | 64 | |
65 | + error = input_open_device(handle); | |
66 | + if (error) | |
67 | + goto err_unregister_handle; | |
68 | + | |
63 | 69 | printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys); |
64 | 70 | |
65 | - return handle; | |
71 | + return 0; | |
72 | + | |
73 | + err_unregister_handle: | |
74 | + input_unregister_handle(handle); | |
75 | + err_free_handle: | |
76 | + kfree(handle); | |
77 | + return error; | |
66 | 78 | } |
67 | 79 | |
68 | 80 | static void evbug_disconnect(struct input_handle *handle) |
... | ... | @@ -70,7 +82,7 @@ |
70 | 82 | printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys); |
71 | 83 | |
72 | 84 | input_close_device(handle); |
73 | - | |
85 | + input_unregister_handle(handle); | |
74 | 86 | kfree(handle); |
75 | 87 | } |
76 | 88 |
drivers/input/evdev.c
... | ... | @@ -605,21 +605,24 @@ |
605 | 605 | .flush = evdev_flush |
606 | 606 | }; |
607 | 607 | |
608 | -static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, | |
609 | - const struct input_device_id *id) | |
608 | +static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |
609 | + const struct input_device_id *id) | |
610 | 610 | { |
611 | 611 | struct evdev *evdev; |
612 | 612 | struct class_device *cdev; |
613 | + dev_t devt; | |
613 | 614 | int minor; |
615 | + int error; | |
614 | 616 | |
615 | 617 | for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); |
616 | 618 | if (minor == EVDEV_MINORS) { |
617 | 619 | printk(KERN_ERR "evdev: no more free evdev devices\n"); |
618 | - return NULL; | |
620 | + return -ENFILE; | |
619 | 621 | } |
620 | 622 | |
621 | - if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL))) | |
622 | - return NULL; | |
623 | + evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); | |
624 | + if (!evdev) | |
625 | + return -ENOMEM; | |
623 | 626 | |
624 | 627 | INIT_LIST_HEAD(&evdev->list); |
625 | 628 | init_waitqueue_head(&evdev->wait); |
626 | 629 | |
627 | 630 | |
628 | 631 | |
629 | 632 | |
... | ... | @@ -634,21 +637,43 @@ |
634 | 637 | |
635 | 638 | evdev_table[minor] = evdev; |
636 | 639 | |
637 | - cdev = class_device_create(&input_class, &dev->cdev, | |
638 | - MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), | |
639 | - dev->cdev.dev, evdev->name); | |
640 | + devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), | |
640 | 641 | |
642 | + cdev = class_device_create(&input_class, &dev->cdev, devt, | |
643 | + dev->cdev.dev, evdev->name); | |
644 | + if (IS_ERR(cdev)) { | |
645 | + error = PTR_ERR(cdev); | |
646 | + goto err_free_evdev; | |
647 | + } | |
648 | + | |
641 | 649 | /* temporary symlink to keep userspace happy */ |
642 | - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, | |
643 | - evdev->name); | |
650 | + error = sysfs_create_link(&input_class.subsys.kset.kobj, | |
651 | + &cdev->kobj, evdev->name); | |
652 | + if (error) | |
653 | + goto err_cdev_destroy; | |
644 | 654 | |
645 | - return &evdev->handle; | |
655 | + error = input_register_handle(&evdev->handle); | |
656 | + if (error) | |
657 | + goto err_remove_link; | |
658 | + | |
659 | + return 0; | |
660 | + | |
661 | + err_remove_link: | |
662 | + sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); | |
663 | + err_cdev_destroy: | |
664 | + class_device_destroy(&input_class, devt); | |
665 | + err_free_evdev: | |
666 | + kfree(evdev); | |
667 | + evdev_table[minor] = NULL; | |
668 | + return error; | |
646 | 669 | } |
647 | 670 | |
648 | 671 | static void evdev_disconnect(struct input_handle *handle) |
649 | 672 | { |
650 | 673 | struct evdev *evdev = handle->private; |
651 | 674 | struct evdev_list *list; |
675 | + | |
676 | + input_unregister_handle(handle); | |
652 | 677 | |
653 | 678 | sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); |
654 | 679 | class_device_destroy(&input_class, |
drivers/input/input.c
... | ... | @@ -380,12 +380,6 @@ |
380 | 380 | } |
381 | 381 | |
382 | 382 | |
383 | -static void input_link_handle(struct input_handle *handle) | |
384 | -{ | |
385 | - list_add_tail(&handle->d_node, &handle->dev->h_list); | |
386 | - list_add_tail(&handle->h_node, &handle->handler->h_list); | |
387 | -} | |
388 | - | |
389 | 383 | #define MATCH_BIT(bit, max) \ |
390 | 384 | for (i = 0; i < NBITS(max); i++) \ |
391 | 385 | if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ |
... | ... | @@ -432,6 +426,29 @@ |
432 | 426 | return NULL; |
433 | 427 | } |
434 | 428 | |
429 | +static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) | |
430 | +{ | |
431 | + const struct input_device_id *id; | |
432 | + int error; | |
433 | + | |
434 | + if (handler->blacklist && input_match_device(handler->blacklist, dev)) | |
435 | + return -ENODEV; | |
436 | + | |
437 | + id = input_match_device(handler->id_table, dev); | |
438 | + if (!id) | |
439 | + return -ENODEV; | |
440 | + | |
441 | + error = handler->connect(handler, dev, id); | |
442 | + if (error && error != -ENODEV) | |
443 | + printk(KERN_ERR | |
444 | + "input: failed to attach handler %s to device %s, " | |
445 | + "error: %d\n", | |
446 | + handler->name, kobject_name(&dev->cdev.kobj), error); | |
447 | + | |
448 | + return error; | |
449 | +} | |
450 | + | |
451 | + | |
435 | 452 | #ifdef CONFIG_PROC_FS |
436 | 453 | |
437 | 454 | static struct proc_dir_entry *proc_bus_input_dir; |
438 | 455 | |
... | ... | @@ -1032,9 +1049,7 @@ |
1032 | 1049 | int input_register_device(struct input_dev *dev) |
1033 | 1050 | { |
1034 | 1051 | static atomic_t input_no = ATOMIC_INIT(0); |
1035 | - struct input_handle *handle; | |
1036 | 1052 | struct input_handler *handler; |
1037 | - const struct input_device_id *id; | |
1038 | 1053 | const char *path; |
1039 | 1054 | int error; |
1040 | 1055 | |
... | ... | @@ -1074,13 +1089,7 @@ |
1074 | 1089 | kfree(path); |
1075 | 1090 | |
1076 | 1091 | list_for_each_entry(handler, &input_handler_list, node) |
1077 | - if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) | |
1078 | - if ((id = input_match_device(handler->id_table, dev))) | |
1079 | - if ((handle = handler->connect(handler, dev, id))) { | |
1080 | - input_link_handle(handle); | |
1081 | - if (handler->start) | |
1082 | - handler->start(handle); | |
1083 | - } | |
1092 | + input_attach_handler(dev, handler); | |
1084 | 1093 | |
1085 | 1094 | input_wakeup_procfs_readers(); |
1086 | 1095 | |
... | ... | @@ -1090,7 +1099,7 @@ |
1090 | 1099 | |
1091 | 1100 | void input_unregister_device(struct input_dev *dev) |
1092 | 1101 | { |
1093 | - struct list_head *node, *next; | |
1102 | + struct input_handle *handle, *next; | |
1094 | 1103 | int code; |
1095 | 1104 | |
1096 | 1105 | for (code = 0; code <= KEY_MAX; code++) |
1097 | 1106 | |
... | ... | @@ -1100,12 +1109,9 @@ |
1100 | 1109 | |
1101 | 1110 | del_timer_sync(&dev->timer); |
1102 | 1111 | |
1103 | - list_for_each_safe(node, next, &dev->h_list) { | |
1104 | - struct input_handle * handle = to_handle(node); | |
1105 | - list_del_init(&handle->d_node); | |
1106 | - list_del_init(&handle->h_node); | |
1112 | + list_for_each_entry_safe(handle, next, &dev->h_list, d_node) | |
1107 | 1113 | handle->handler->disconnect(handle); |
1108 | - } | |
1114 | + WARN_ON(!list_empty(&dev->h_list)); | |
1109 | 1115 | |
1110 | 1116 | list_del_init(&dev->node); |
1111 | 1117 | |
... | ... | @@ -1118,8 +1124,6 @@ |
1118 | 1124 | int input_register_handler(struct input_handler *handler) |
1119 | 1125 | { |
1120 | 1126 | struct input_dev *dev; |
1121 | - struct input_handle *handle; | |
1122 | - const struct input_device_id *id; | |
1123 | 1127 | |
1124 | 1128 | INIT_LIST_HEAD(&handler->h_list); |
1125 | 1129 | |
... | ... | @@ -1133,13 +1137,7 @@ |
1133 | 1137 | list_add_tail(&handler->node, &input_handler_list); |
1134 | 1138 | |
1135 | 1139 | list_for_each_entry(dev, &input_dev_list, node) |
1136 | - if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) | |
1137 | - if ((id = input_match_device(handler->id_table, dev))) | |
1138 | - if ((handle = handler->connect(handler, dev, id))) { | |
1139 | - input_link_handle(handle); | |
1140 | - if (handler->start) | |
1141 | - handler->start(handle); | |
1142 | - } | |
1140 | + input_attach_handler(dev, handler); | |
1143 | 1141 | |
1144 | 1142 | input_wakeup_procfs_readers(); |
1145 | 1143 | return 0; |
1146 | 1144 | |
1147 | 1145 | |
... | ... | @@ -1148,14 +1146,11 @@ |
1148 | 1146 | |
1149 | 1147 | void input_unregister_handler(struct input_handler *handler) |
1150 | 1148 | { |
1151 | - struct list_head *node, *next; | |
1149 | + struct input_handle *handle, *next; | |
1152 | 1150 | |
1153 | - list_for_each_safe(node, next, &handler->h_list) { | |
1154 | - struct input_handle * handle = to_handle_h(node); | |
1155 | - list_del_init(&handle->h_node); | |
1156 | - list_del_init(&handle->d_node); | |
1151 | + list_for_each_entry_safe(handle, next, &handler->h_list, h_node) | |
1157 | 1152 | handler->disconnect(handle); |
1158 | - } | |
1153 | + WARN_ON(!list_empty(&handler->h_list)); | |
1159 | 1154 | |
1160 | 1155 | list_del_init(&handler->node); |
1161 | 1156 | |
... | ... | @@ -1165,6 +1160,27 @@ |
1165 | 1160 | input_wakeup_procfs_readers(); |
1166 | 1161 | } |
1167 | 1162 | EXPORT_SYMBOL(input_unregister_handler); |
1163 | + | |
1164 | +int input_register_handle(struct input_handle *handle) | |
1165 | +{ | |
1166 | + struct input_handler *handler = handle->handler; | |
1167 | + | |
1168 | + list_add_tail(&handle->d_node, &handle->dev->h_list); | |
1169 | + list_add_tail(&handle->h_node, &handler->h_list); | |
1170 | + | |
1171 | + if (handler->start) | |
1172 | + handler->start(handle); | |
1173 | + | |
1174 | + return 0; | |
1175 | +} | |
1176 | +EXPORT_SYMBOL(input_register_handle); | |
1177 | + | |
1178 | +void input_unregister_handle(struct input_handle *handle) | |
1179 | +{ | |
1180 | + list_del_init(&handle->h_node); | |
1181 | + list_del_init(&handle->d_node); | |
1182 | +} | |
1183 | +EXPORT_SYMBOL(input_unregister_handle); | |
1168 | 1184 | |
1169 | 1185 | static int input_open_file(struct inode *inode, struct file *file) |
1170 | 1186 | { |
drivers/input/joydev.c
... | ... | @@ -465,21 +465,24 @@ |
465 | 465 | .fasync = joydev_fasync, |
466 | 466 | }; |
467 | 467 | |
468 | -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, | |
469 | - const struct input_device_id *id) | |
468 | +static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |
469 | + const struct input_device_id *id) | |
470 | 470 | { |
471 | 471 | struct joydev *joydev; |
472 | 472 | struct class_device *cdev; |
473 | + dev_t devt; | |
473 | 474 | int i, j, t, minor; |
475 | + int error; | |
474 | 476 | |
475 | 477 | for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); |
476 | 478 | if (minor == JOYDEV_MINORS) { |
477 | 479 | printk(KERN_ERR "joydev: no more free joydev devices\n"); |
478 | - return NULL; | |
480 | + return -ENFILE; | |
479 | 481 | } |
480 | 482 | |
481 | - if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL))) | |
482 | - return NULL; | |
483 | + joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); | |
484 | + if (!joydev) | |
485 | + return -ENOMEM; | |
483 | 486 | |
484 | 487 | INIT_LIST_HEAD(&joydev->list); |
485 | 488 | init_waitqueue_head(&joydev->wait); |
486 | 489 | |
487 | 490 | |
488 | 491 | |
489 | 492 | |
490 | 493 | |
... | ... | @@ -534,21 +537,44 @@ |
534 | 537 | |
535 | 538 | joydev_table[minor] = joydev; |
536 | 539 | |
537 | - cdev = class_device_create(&input_class, &dev->cdev, | |
538 | - MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), | |
539 | - dev->cdev.dev, joydev->name); | |
540 | + devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), | |
540 | 541 | |
542 | + cdev = class_device_create(&input_class, &dev->cdev, devt, | |
543 | + dev->cdev.dev, joydev->name); | |
544 | + if (IS_ERR(cdev)) { | |
545 | + error = PTR_ERR(cdev); | |
546 | + goto err_free_joydev; | |
547 | + } | |
548 | + | |
541 | 549 | /* temporary symlink to keep userspace happy */ |
542 | - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, | |
543 | - joydev->name); | |
550 | + error = sysfs_create_link(&input_class.subsys.kset.kobj, | |
551 | + &cdev->kobj, joydev->name); | |
552 | + if (error) | |
553 | + goto err_cdev_destroy; | |
544 | 554 | |
545 | - return &joydev->handle; | |
555 | + error = input_register_handle(&joydev->handle); | |
556 | + if (error) | |
557 | + goto err_remove_link; | |
558 | + | |
559 | + return 0; | |
560 | + | |
561 | + err_remove_link: | |
562 | + sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); | |
563 | + err_cdev_destroy: | |
564 | + class_device_destroy(&input_class, devt); | |
565 | + err_free_joydev: | |
566 | + joydev_table[minor] = NULL; | |
567 | + kfree(joydev); | |
568 | + return error; | |
546 | 569 | } |
547 | 570 | |
571 | + | |
548 | 572 | static void joydev_disconnect(struct input_handle *handle) |
549 | 573 | { |
550 | 574 | struct joydev *joydev = handle->private; |
551 | 575 | struct joydev_list *list; |
576 | + | |
577 | + input_unregister_handle(handle); | |
552 | 578 | |
553 | 579 | sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); |
554 | 580 | class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); |
drivers/input/mousedev.c
... | ... | @@ -624,23 +624,27 @@ |
624 | 624 | .fasync = mousedev_fasync, |
625 | 625 | }; |
626 | 626 | |
627 | -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, | |
628 | - const struct input_device_id *id) | |
627 | +static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, | |
628 | + const struct input_device_id *id) | |
629 | 629 | { |
630 | 630 | struct mousedev *mousedev; |
631 | 631 | struct class_device *cdev; |
632 | - int minor = 0; | |
632 | + dev_t devt; | |
633 | + int minor; | |
634 | + int error; | |
633 | 635 | |
634 | 636 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); |
635 | 637 | if (minor == MOUSEDEV_MINORS) { |
636 | 638 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); |
637 | - return NULL; | |
639 | + return -ENFILE; | |
638 | 640 | } |
639 | 641 | |
640 | - if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL))) | |
641 | - return NULL; | |
642 | + mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); | |
643 | + if (!mousedev) | |
644 | + return -ENOMEM; | |
642 | 645 | |
643 | 646 | INIT_LIST_HEAD(&mousedev->list); |
647 | + INIT_LIST_HEAD(&mousedev->mixdev_node); | |
644 | 648 | init_waitqueue_head(&mousedev->wait); |
645 | 649 | |
646 | 650 | mousedev->minor = minor; |
647 | 651 | |
648 | 652 | |
649 | 653 | |
650 | 654 | |
651 | 655 | |
... | ... | @@ -651,26 +655,53 @@ |
651 | 655 | mousedev->handle.private = mousedev; |
652 | 656 | sprintf(mousedev->name, "mouse%d", minor); |
653 | 657 | |
654 | - if (mousedev_mix.open) | |
655 | - input_open_device(&mousedev->handle); | |
656 | - | |
657 | 658 | mousedev_table[minor] = mousedev; |
658 | 659 | |
659 | - cdev = class_device_create(&input_class, &dev->cdev, | |
660 | - MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), | |
661 | - dev->cdev.dev, mousedev->name); | |
660 | + devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), | |
662 | 661 | |
662 | + cdev = class_device_create(&input_class, &dev->cdev, devt, | |
663 | + dev->cdev.dev, mousedev->name); | |
664 | + if (IS_ERR(cdev)) { | |
665 | + error = PTR_ERR(cdev); | |
666 | + goto err_free_mousedev; | |
667 | + } | |
668 | + | |
663 | 669 | /* temporary symlink to keep userspace happy */ |
664 | - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, | |
665 | - mousedev->name); | |
670 | + error = sysfs_create_link(&input_class.subsys.kset.kobj, | |
671 | + &cdev->kobj, mousedev->name); | |
672 | + if (error) | |
673 | + goto err_cdev_destroy; | |
666 | 674 | |
667 | - return &mousedev->handle; | |
675 | + error = input_register_handle(&mousedev->handle); | |
676 | + if (error) | |
677 | + goto err_remove_link; | |
678 | + | |
679 | + if (mousedev_mix.open) { | |
680 | + error = input_open_device(&mousedev->handle); | |
681 | + if (error) | |
682 | + goto err_unregister_handle; | |
683 | + } | |
684 | + | |
685 | + return 0; | |
686 | + | |
687 | + err_unregister_handle: | |
688 | + input_unregister_handle(&mousedev->handle); | |
689 | + err_remove_link: | |
690 | + sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); | |
691 | + err_cdev_destroy: | |
692 | + class_device_destroy(&input_class, devt); | |
693 | + err_free_mousedev: | |
694 | + mousedev_table[minor] = NULL; | |
695 | + kfree(mousedev); | |
696 | + return error; | |
668 | 697 | } |
669 | 698 | |
670 | 699 | static void mousedev_disconnect(struct input_handle *handle) |
671 | 700 | { |
672 | 701 | struct mousedev *mousedev = handle->private; |
673 | 702 | struct mousedev_list *list; |
703 | + | |
704 | + input_unregister_handle(handle); | |
674 | 705 | |
675 | 706 | sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); |
676 | 707 | class_device_destroy(&input_class, |
drivers/input/power.c
... | ... | @@ -41,14 +41,14 @@ |
41 | 41 | * Power management can't be done in a interrupt context. So we have to |
42 | 42 | * use keventd. |
43 | 43 | */ |
44 | -static int suspend_button_pushed = 0; | |
45 | -static void suspend_button_task_handler(void *data) | |
44 | +static int suspend_button_pushed; | |
45 | +static void suspend_button_task_handler(struct work_struct *work) | |
46 | 46 | { |
47 | 47 | udelay(200); /* debounce */ |
48 | 48 | suspend_button_pushed = 0; |
49 | 49 | } |
50 | 50 | |
51 | -static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); | |
51 | +static DECLARE_WORK(suspend_button_task, suspend_button_task_handler); | |
52 | 52 | |
53 | 53 | static void power_event(struct input_handle *handle, unsigned int type, |
54 | 54 | unsigned int code, int down) |
... | ... | @@ -63,9 +63,9 @@ |
63 | 63 | printk("Powering down entire device\n"); |
64 | 64 | |
65 | 65 | if (!suspend_button_pushed) { |
66 | - suspend_button_pushed = 1; | |
67 | - schedule_work(&suspend_button_task); | |
68 | - } | |
66 | + suspend_button_pushed = 1; | |
67 | + schedule_work(&suspend_button_task); | |
68 | + } | |
69 | 69 | break; |
70 | 70 | case KEY_POWER: |
71 | 71 | /* Hum power down the machine. */ |
... | ... | @@ -84,7 +84,7 @@ |
84 | 84 | dev->state = PM_RESUME; |
85 | 85 | else |
86 | 86 | dev->state = PM_SUSPEND; |
87 | - pm_send(dev->pm_dev, dev->state, dev); | |
87 | + /* pm_send(dev->pm_dev, dev->state, dev); */ | |
88 | 88 | break; |
89 | 89 | case KEY_POWER: |
90 | 90 | /* Turn the input device off completely ? */ |
91 | 91 | |
92 | 92 | |
93 | 93 | |
94 | 94 | |
95 | 95 | |
96 | 96 | |
... | ... | @@ -96,27 +96,41 @@ |
96 | 96 | return; |
97 | 97 | } |
98 | 98 | |
99 | -static struct input_handle *power_connect(struct input_handler *handler, | |
100 | - struct input_dev *dev, | |
101 | - const struct input_device_id *id) | |
99 | +static int power_connect(struct input_handler *handler, struct input_dev *dev, | |
100 | + const struct input_device_id *id) | |
102 | 101 | { |
103 | 102 | struct input_handle *handle; |
103 | + int error; | |
104 | 104 | |
105 | - if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) | |
106 | - return NULL; | |
105 | + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); | |
106 | + if (!handle) | |
107 | + return -ENOMEM; | |
107 | 108 | |
108 | 109 | handle->dev = dev; |
109 | 110 | handle->handler = handler; |
111 | + handle->name = "power"; | |
110 | 112 | |
111 | - input_open_device(handle); | |
113 | + error = input_register_handle(handle); | |
114 | + if (error) | |
115 | + goto err_free_handle; | |
112 | 116 | |
113 | - printk(KERN_INFO "power.c: Adding power management to input layer\n"); | |
114 | - return handle; | |
117 | + error = input_open_device(handle); | |
118 | + if (error) | |
119 | + goto err_unregister_handle; | |
120 | + | |
121 | + return 0; | |
122 | + | |
123 | + err_unregister_handle: | |
124 | + input_unregister_handle(handle); | |
125 | + err_free_handle: | |
126 | + kfree(handle); | |
127 | + return error; | |
115 | 128 | } |
116 | 129 | |
117 | 130 | static void power_disconnect(struct input_handle *handle) |
118 | 131 | { |
119 | 132 | input_close_device(handle); |
133 | + input_unregister_handle(handle); | |
120 | 134 | kfree(handle); |
121 | 135 | } |
122 | 136 | |
... | ... | @@ -135,7 +149,7 @@ |
135 | 149 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, |
136 | 150 | .evbit = { BIT(EV_PWR) }, |
137 | 151 | }, |
138 | - { }, /* Terminating entry */ | |
152 | + { }, /* Terminating entry */ | |
139 | 153 | }; |
140 | 154 | |
141 | 155 | MODULE_DEVICE_TABLE(input, power_ids); |
drivers/input/tsdev.c
... | ... | @@ -155,7 +155,7 @@ |
155 | 155 | "for removal.\nSee Documentation/feature-removal-schedule.txt " |
156 | 156 | "for details.\n"); |
157 | 157 | |
158 | - if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) | |
158 | + if (i >= TSDEV_MINORS) | |
159 | 159 | return -ENODEV; |
160 | 160 | |
161 | 161 | if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL))) |
162 | 162 | |
... | ... | @@ -246,14 +246,14 @@ |
246 | 246 | |
247 | 247 | switch (cmd) { |
248 | 248 | case TS_GET_CAL: |
249 | - if (copy_to_user ((void __user *)arg, &tsdev->cal, | |
250 | - sizeof (struct ts_calibration))) | |
249 | + if (copy_to_user((void __user *)arg, &tsdev->cal, | |
250 | + sizeof (struct ts_calibration))) | |
251 | 251 | retval = -EFAULT; |
252 | 252 | break; |
253 | 253 | |
254 | 254 | case TS_SET_CAL: |
255 | - if (copy_from_user (&tsdev->cal, (void __user *)arg, | |
256 | - sizeof (struct ts_calibration))) | |
255 | + if (copy_from_user(&tsdev->cal, (void __user *)arg, | |
256 | + sizeof (struct ts_calibration))) | |
257 | 257 | retval = -EFAULT; |
258 | 258 | break; |
259 | 259 | |
260 | 260 | |
261 | 261 | |
262 | 262 | |
263 | 263 | |
... | ... | @@ -370,23 +370,25 @@ |
370 | 370 | wake_up_interruptible(&tsdev->wait); |
371 | 371 | } |
372 | 372 | |
373 | -static struct input_handle *tsdev_connect(struct input_handler *handler, | |
374 | - struct input_dev *dev, | |
375 | - const struct input_device_id *id) | |
373 | +static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | |
374 | + const struct input_device_id *id) | |
376 | 375 | { |
377 | 376 | struct tsdev *tsdev; |
378 | 377 | struct class_device *cdev; |
378 | + dev_t devt; | |
379 | 379 | int minor, delta; |
380 | + int error; | |
380 | 381 | |
381 | 382 | for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); |
382 | 383 | if (minor >= TSDEV_MINORS / 2) { |
383 | 384 | printk(KERN_ERR |
384 | 385 | "tsdev: You have way too many touchscreens\n"); |
385 | - return NULL; | |
386 | + return -ENFILE; | |
386 | 387 | } |
387 | 388 | |
388 | - if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL))) | |
389 | - return NULL; | |
389 | + tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL); | |
390 | + if (!tsdev) | |
391 | + return -ENOMEM; | |
390 | 392 | |
391 | 393 | INIT_LIST_HEAD(&tsdev->list); |
392 | 394 | init_waitqueue_head(&tsdev->wait); |
393 | 395 | |
394 | 396 | |
395 | 397 | |
396 | 398 | |
... | ... | @@ -415,21 +417,43 @@ |
415 | 417 | |
416 | 418 | tsdev_table[minor] = tsdev; |
417 | 419 | |
418 | - cdev = class_device_create(&input_class, &dev->cdev, | |
419 | - MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), | |
420 | - dev->cdev.dev, tsdev->name); | |
420 | + devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), | |
421 | 421 | |
422 | + cdev = class_device_create(&input_class, &dev->cdev, devt, | |
423 | + dev->cdev.dev, tsdev->name); | |
424 | + if (IS_ERR(cdev)) { | |
425 | + error = PTR_ERR(cdev); | |
426 | + goto err_free_tsdev; | |
427 | + } | |
428 | + | |
422 | 429 | /* temporary symlink to keep userspace happy */ |
423 | - sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, | |
424 | - tsdev->name); | |
430 | + error = sysfs_create_link(&input_class.subsys.kset.kobj, | |
431 | + &cdev->kobj, tsdev->name); | |
432 | + if (error) | |
433 | + goto err_cdev_destroy; | |
425 | 434 | |
426 | - return &tsdev->handle; | |
435 | + error = input_register_handle(&tsdev->handle); | |
436 | + if (error) | |
437 | + goto err_remove_link; | |
438 | + | |
439 | + return 0; | |
440 | + | |
441 | + err_remove_link: | |
442 | + sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); | |
443 | + err_cdev_destroy: | |
444 | + class_device_destroy(&input_class, devt); | |
445 | + err_free_tsdev: | |
446 | + tsdev_table[minor] = NULL; | |
447 | + kfree(tsdev); | |
448 | + return error; | |
427 | 449 | } |
428 | 450 | |
429 | 451 | static void tsdev_disconnect(struct input_handle *handle) |
430 | 452 | { |
431 | 453 | struct tsdev *tsdev = handle->private; |
432 | 454 | struct tsdev_list *list; |
455 | + | |
456 | + input_unregister_handle(handle); | |
433 | 457 | |
434 | 458 | sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); |
435 | 459 | class_device_destroy(&input_class, |
include/linux/input.h
... | ... | @@ -1049,7 +1049,7 @@ |
1049 | 1049 | void *private; |
1050 | 1050 | |
1051 | 1051 | void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); |
1052 | - struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); | |
1052 | + int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); | |
1053 | 1053 | void (*disconnect)(struct input_handle *handle); |
1054 | 1054 | void (*start)(struct input_handle *handle); |
1055 | 1055 | |
... | ... | @@ -1101,6 +1101,9 @@ |
1101 | 1101 | |
1102 | 1102 | int input_register_handler(struct input_handler *); |
1103 | 1103 | void input_unregister_handler(struct input_handler *); |
1104 | + | |
1105 | +int input_register_handle(struct input_handle *); | |
1106 | +void input_unregister_handle(struct input_handle *); | |
1104 | 1107 | |
1105 | 1108 | int input_grab_device(struct input_handle *); |
1106 | 1109 | void input_release_device(struct input_handle *); |