Input: rework handle creation code
authorDmitry Torokhov <dtor@insightbb.com>
Thu, 12 Apr 2007 05:29:46 +0000 (01:29 -0400)
committerDmitry Torokhov <dtor@insightbb.com>
Thu, 12 Apr 2007 05:29:46 +0000 (01:29 -0400)
 - 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>
drivers/char/keyboard.c
drivers/input/evbug.c
drivers/input/evdev.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/mousedev.c
drivers/input/power.c
drivers/input/tsdev.c
include/linux/input.h

index 3d211e8553f775c3166ab436db9830d97a9a2b74..59712546f9113d0029803a2afd1a55e69c85bf69 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/input.h>
 #include <linux/reboot.h>
 
-static void kbd_disconnect(struct input_handle *handle);
 extern void ctrl_alt_del(void);
 
 /*
@@ -1260,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
  * likes it, it can open it and get events from it. In this (kbd_connect)
  * function, we should decide which VT to bind that keyboard to initially.
  */
-static struct input_handle *kbd_connect(struct input_handler *handler,
-                                       struct input_dev *dev,
-                                       const struct input_device_id *id)
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+                       const struct input_device_id *id)
 {
        struct input_handle *handle;
+       int error;
        int i;
 
        for (i = KEY_RESERVED; i < BTN_MISC; i++)
@@ -1272,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
                        break;
 
        if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
-               return NULL;
+               return -ENODEV;
 
        handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
        if (!handle)
-               return NULL;
+               return -ENOMEM;
 
        handle->dev = dev;
        handle->handler = handler;
        handle->name = "kbd";
 
-       input_open_device(handle);
+       error = input_register_handle(handle);
+       if (error)
+               goto err_free_handle;
+
+       error = input_open_device(handle);
+       if (error)
+               goto err_unregister_handle;
+
+       return 0;
 
-       return handle;
+ err_unregister_handle:
+       input_unregister_handle(handle);
+ err_free_handle:
+       kfree(handle);
+       return error;
 }
 
 static void kbd_disconnect(struct input_handle *handle)
 {
        input_close_device(handle);
+       input_unregister_handle(handle);
        kfree(handle);
 }
 
index 5a9653c3128a0d90308e632683f2a2c9a6e077ec..c21f2f1272345b6f56a79fb396af2d1e894ef90a 100644 (file)
@@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Input driver event debug module");
 MODULE_LICENSE("GPL");
 
-static char evbug_name[] = "evbug";
-
 static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
        printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
                handle->dev->phys, type, code, value);
 }
 
-static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
-                                         const struct input_device_id *id)
+static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
+                        const struct input_device_id *id)
 {
        struct input_handle *handle;
+       int error;
 
-       if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
-               return NULL;
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
 
        handle->dev = dev;
        handle->handler = handler;
-       handle->name = evbug_name;
+       handle->name = "evbug";
+
+       error = input_register_handle(handle);
+       if (error)
+               goto err_free_handle;
 
-       input_open_device(handle);
+       error = input_open_device(handle);
+       if (error)
+               goto err_unregister_handle;
 
        printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
 
-       return handle;
+       return 0;
+
+ err_unregister_handle:
+       input_unregister_handle(handle);
+ err_free_handle:
+       kfree(handle);
+       return error;
 }
 
 static void evbug_disconnect(struct input_handle *handle)
@@ -70,7 +82,7 @@ static void evbug_disconnect(struct input_handle *handle)
        printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
 
        input_close_device(handle);
-
+       input_unregister_handle(handle);
        kfree(handle);
 }
 
index 64b47de052bbe12d58845cb5130143330e3ef917..840fa198652736b126c1e3221987119f2daf87ee 100644 (file)
@@ -605,21 +605,24 @@ static const struct file_operations evdev_fops = {
        .flush =        evdev_flush
 };
 
-static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
-                                         const struct input_device_id *id)
+static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
+                        const struct input_device_id *id)
 {
        struct evdev *evdev;
        struct class_device *cdev;
+       dev_t devt;
        int minor;
+       int error;
 
        for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
        if (minor == EVDEV_MINORS) {
                printk(KERN_ERR "evdev: no more free evdev devices\n");
-               return NULL;
+               return -ENFILE;
        }
 
-       if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
-               return NULL;
+       evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
+       if (!evdev)
+               return -ENOMEM;
 
        INIT_LIST_HEAD(&evdev->list);
        init_waitqueue_head(&evdev->wait);
@@ -634,15 +637,35 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
 
        evdev_table[minor] = evdev;
 
-       cdev = class_device_create(&input_class, &dev->cdev,
-                       MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
-                       dev->cdev.dev, evdev->name);
+       devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
+
+       cdev = class_device_create(&input_class, &dev->cdev, devt,
+                                  dev->cdev.dev, evdev->name);
+       if (IS_ERR(cdev)) {
+               error = PTR_ERR(cdev);
+               goto err_free_evdev;
+       }
 
        /* temporary symlink to keep userspace happy */
-       sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-                         evdev->name);
+       error = sysfs_create_link(&input_class.subsys.kset.kobj,
+                                 &cdev->kobj, evdev->name);
+       if (error)
+               goto err_cdev_destroy;
+
+       error = input_register_handle(&evdev->handle);
+       if (error)
+               goto err_remove_link;
 
-       return &evdev->handle;
+       return 0;
+
+ err_remove_link:
+       sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
+ err_cdev_destroy:
+       class_device_destroy(&input_class, devt);
+ err_free_evdev:
+       kfree(evdev);
+       evdev_table[minor] = NULL;
+       return error;
 }
 
 static void evdev_disconnect(struct input_handle *handle)
@@ -650,6 +673,8 @@ static void evdev_disconnect(struct input_handle *handle)
        struct evdev *evdev = handle->private;
        struct evdev_list *list;
 
+       input_unregister_handle(handle);
+
        sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
        class_device_destroy(&input_class,
                        MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
index 5629e397520ddfe2ee4a4777efe3235089f632e4..86b27079004a79697d25fae8f31b792d147ecf1a 100644 (file)
@@ -380,12 +380,6 @@ static int input_default_setkeycode(struct input_dev *dev,
 }
 
 
-static void input_link_handle(struct input_handle *handle)
-{
-       list_add_tail(&handle->d_node, &handle->dev->h_list);
-       list_add_tail(&handle->h_node, &handle->handler->h_list);
-}
-
 #define MATCH_BIT(bit, max) \
                for (i = 0; i < NBITS(max); i++) \
                        if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
@@ -432,6 +426,29 @@ static const struct input_device_id *input_match_device(const struct input_devic
        return NULL;
 }
 
+static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
+{
+       const struct input_device_id *id;
+       int error;
+
+       if (handler->blacklist && input_match_device(handler->blacklist, dev))
+               return -ENODEV;
+
+       id = input_match_device(handler->id_table, dev);
+       if (!id)
+               return -ENODEV;
+
+       error = handler->connect(handler, dev, id);
+       if (error && error != -ENODEV)
+               printk(KERN_ERR
+                       "input: failed to attach handler %s to device %s, "
+                       "error: %d\n",
+                       handler->name, kobject_name(&dev->cdev.kobj), error);
+
+       return error;
+}
+
+
 #ifdef CONFIG_PROC_FS
 
 static struct proc_dir_entry *proc_bus_input_dir;
@@ -1032,9 +1049,7 @@ EXPORT_SYMBOL(input_free_device);
 int input_register_device(struct input_dev *dev)
 {
        static atomic_t input_no = ATOMIC_INIT(0);
-       struct input_handle *handle;
        struct input_handler *handler;
-       const struct input_device_id *id;
        const char *path;
        int error;
 
@@ -1074,13 +1089,7 @@ int input_register_device(struct input_dev *dev)
        kfree(path);
 
        list_for_each_entry(handler, &input_handler_list, node)
-               if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
-                       if ((id = input_match_device(handler->id_table, dev)))
-                               if ((handle = handler->connect(handler, dev, id))) {
-                                       input_link_handle(handle);
-                                       if (handler->start)
-                                               handler->start(handle);
-                               }
+               input_attach_handler(dev, handler);
 
        input_wakeup_procfs_readers();
 
@@ -1090,7 +1099,7 @@ EXPORT_SYMBOL(input_register_device);
 
 void input_unregister_device(struct input_dev *dev)
 {
-       struct list_head *node, *next;
+       struct input_handle *handle, *next;
        int code;
 
        for (code = 0; code <= KEY_MAX; code++)
@@ -1100,12 +1109,9 @@ void input_unregister_device(struct input_dev *dev)
 
        del_timer_sync(&dev->timer);
 
-       list_for_each_safe(node, next, &dev->h_list) {
-               struct input_handle * handle = to_handle(node);
-               list_del_init(&handle->d_node);
-               list_del_init(&handle->h_node);
+       list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
                handle->handler->disconnect(handle);
-       }
+       WARN_ON(!list_empty(&dev->h_list));
 
        list_del_init(&dev->node);
 
@@ -1118,8 +1124,6 @@ EXPORT_SYMBOL(input_unregister_device);
 int input_register_handler(struct input_handler *handler)
 {
        struct input_dev *dev;
-       struct input_handle *handle;
-       const struct input_device_id *id;
 
        INIT_LIST_HEAD(&handler->h_list);
 
@@ -1133,13 +1137,7 @@ int input_register_handler(struct input_handler *handler)
        list_add_tail(&handler->node, &input_handler_list);
 
        list_for_each_entry(dev, &input_dev_list, node)
-               if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
-                       if ((id = input_match_device(handler->id_table, dev)))
-                               if ((handle = handler->connect(handler, dev, id))) {
-                                       input_link_handle(handle);
-                                       if (handler->start)
-                                               handler->start(handle);
-                               }
+               input_attach_handler(dev, handler);
 
        input_wakeup_procfs_readers();
        return 0;
@@ -1148,14 +1146,11 @@ EXPORT_SYMBOL(input_register_handler);
 
 void input_unregister_handler(struct input_handler *handler)
 {
-       struct list_head *node, *next;
+       struct input_handle *handle, *next;
 
-       list_for_each_safe(node, next, &handler->h_list) {
-               struct input_handle * handle = to_handle_h(node);
-               list_del_init(&handle->h_node);
-               list_del_init(&handle->d_node);
+       list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
                handler->disconnect(handle);
-       }
+       WARN_ON(!list_empty(&handler->h_list));
 
        list_del_init(&handler->node);
 
@@ -1166,6 +1161,27 @@ void input_unregister_handler(struct input_handler *handler)
 }
 EXPORT_SYMBOL(input_unregister_handler);
 
+int input_register_handle(struct input_handle *handle)
+{
+       struct input_handler *handler = handle->handler;
+
+       list_add_tail(&handle->d_node, &handle->dev->h_list);
+       list_add_tail(&handle->h_node, &handler->h_list);
+
+       if (handler->start)
+               handler->start(handle);
+
+       return 0;
+}
+EXPORT_SYMBOL(input_register_handle);
+
+void input_unregister_handle(struct input_handle *handle)
+{
+       list_del_init(&handle->h_node);
+       list_del_init(&handle->d_node);
+}
+EXPORT_SYMBOL(input_unregister_handle);
+
 static int input_open_file(struct inode *inode, struct file *file)
 {
        struct input_handler *handler = input_table[iminor(inode) >> 5];
index 9f3529ad3fdab5b149cf7c835fc32e413e6c5109..cf24a5bde53932fe8fbd7c788f069445d35ed0c4 100644 (file)
@@ -465,21 +465,24 @@ static const struct file_operations joydev_fops = {
        .fasync =       joydev_fasync,
 };
 
-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
-                                          const struct input_device_id *id)
+static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
+                         const struct input_device_id *id)
 {
        struct joydev *joydev;
        struct class_device *cdev;
+       dev_t devt;
        int i, j, t, minor;
+       int error;
 
        for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
        if (minor == JOYDEV_MINORS) {
                printk(KERN_ERR "joydev: no more free joydev devices\n");
-               return NULL;
+               return -ENFILE;
        }
 
-       if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
-               return NULL;
+       joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
+       if (!joydev)
+               return -ENOMEM;
 
        INIT_LIST_HEAD(&joydev->list);
        init_waitqueue_head(&joydev->wait);
@@ -534,22 +537,45 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
 
        joydev_table[minor] = joydev;
 
-       cdev = class_device_create(&input_class, &dev->cdev,
-                       MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
-                       dev->cdev.dev, joydev->name);
+       devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
+
+       cdev = class_device_create(&input_class, &dev->cdev, devt,
+                                  dev->cdev.dev, joydev->name);
+       if (IS_ERR(cdev)) {
+               error = PTR_ERR(cdev);
+               goto err_free_joydev;
+       }
 
        /* temporary symlink to keep userspace happy */
-       sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-                         joydev->name);
+       error = sysfs_create_link(&input_class.subsys.kset.kobj,
+                                 &cdev->kobj, joydev->name);
+       if (error)
+               goto err_cdev_destroy;
+
+       error = input_register_handle(&joydev->handle);
+       if (error)
+               goto err_remove_link;
+
+       return 0;
 
-       return &joydev->handle;
+ err_remove_link:
+       sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name);
+ err_cdev_destroy:
+       class_device_destroy(&input_class, devt);
+ err_free_joydev:
+       joydev_table[minor] = NULL;
+       kfree(joydev);
+       return error;
 }
 
+
 static void joydev_disconnect(struct input_handle *handle)
 {
        struct joydev *joydev = handle->private;
        struct joydev_list *list;
 
+       input_unregister_handle(handle);
+
        sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name);
        class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
        joydev->exist = 0;
index 664bcc8116fc7676d159b2e035015f212ad5f357..007e72f802517eea0bea069cc7ba2db3ed899b44 100644 (file)
@@ -624,23 +624,27 @@ static const struct file_operations mousedev_fops = {
        .fasync =       mousedev_fasync,
 };
 
-static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev,
-                                            const struct input_device_id *id)
+static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
+                           const struct input_device_id *id)
 {
        struct mousedev *mousedev;
        struct class_device *cdev;
-       int minor = 0;
+       dev_t devt;
+       int minor;
+       int error;
 
        for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
        if (minor == MOUSEDEV_MINORS) {
                printk(KERN_ERR "mousedev: no more free mousedev devices\n");
-               return NULL;
+               return -ENFILE;
        }
 
-       if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL)))
-               return NULL;
+       mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
+       if (!mousedev)
+               return -ENOMEM;
 
        INIT_LIST_HEAD(&mousedev->list);
+       INIT_LIST_HEAD(&mousedev->mixdev_node);
        init_waitqueue_head(&mousedev->wait);
 
        mousedev->minor = minor;
@@ -651,20 +655,45 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
        mousedev->handle.private = mousedev;
        sprintf(mousedev->name, "mouse%d", minor);
 
-       if (mousedev_mix.open)
-               input_open_device(&mousedev->handle);
-
        mousedev_table[minor] = mousedev;
 
-       cdev = class_device_create(&input_class, &dev->cdev,
-                       MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
-                       dev->cdev.dev, mousedev->name);
+       devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
+
+       cdev = class_device_create(&input_class, &dev->cdev, devt,
+                                  dev->cdev.dev, mousedev->name);
+       if (IS_ERR(cdev)) {
+               error = PTR_ERR(cdev);
+               goto err_free_mousedev;
+       }
 
        /* temporary symlink to keep userspace happy */
-       sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-                         mousedev->name);
+       error = sysfs_create_link(&input_class.subsys.kset.kobj,
+                                 &cdev->kobj, mousedev->name);
+       if (error)
+               goto err_cdev_destroy;
 
-       return &mousedev->handle;
+       error = input_register_handle(&mousedev->handle);
+       if (error)
+               goto err_remove_link;
+
+       if (mousedev_mix.open) {
+               error = input_open_device(&mousedev->handle);
+               if (error)
+                       goto err_unregister_handle;
+       }
+
+       return 0;
+
+ err_unregister_handle:
+       input_unregister_handle(&mousedev->handle);
+ err_remove_link:
+       sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
+ err_cdev_destroy:
+       class_device_destroy(&input_class, devt);
+ err_free_mousedev:
+       mousedev_table[minor] = NULL;
+       kfree(mousedev);
+       return error;
 }
 
 static void mousedev_disconnect(struct input_handle *handle)
@@ -672,6 +701,8 @@ static void mousedev_disconnect(struct input_handle *handle)
        struct mousedev *mousedev = handle->private;
        struct mousedev_list *list;
 
+       input_unregister_handle(handle);
+
        sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
        class_device_destroy(&input_class,
                        MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
index ee82464a2fa73c5bfd2b203fdfe68a8cd6ccfb61..e28d264b9e066b74ce6e84872d921d5da667cef1 100644 (file)
@@ -41,14 +41,14 @@ static struct input_handler power_handler;
  * Power management can't be done in a interrupt context. So we have to
  * use keventd.
  */
-static int suspend_button_pushed = 0;
-static void suspend_button_task_handler(void *data)
+static int suspend_button_pushed;
+static void suspend_button_task_handler(struct work_struct *work)
 {
         udelay(200); /* debounce */
         suspend_button_pushed = 0;
 }
 
-static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL);
+static DECLARE_WORK(suspend_button_task, suspend_button_task_handler);
 
 static void power_event(struct input_handle *handle, unsigned int type,
                        unsigned int code, int down)
@@ -63,9 +63,9 @@ static void power_event(struct input_handle *handle, unsigned int type,
                                printk("Powering down entire device\n");
 
                                if (!suspend_button_pushed) {
-                                       suspend_button_pushed = 1;
-                                       schedule_work(&suspend_button_task);
-                               }
+                                       suspend_button_pushed = 1;
+                                       schedule_work(&suspend_button_task);
+                               }
                                break;
                        case KEY_POWER:
                                /* Hum power down the machine. */
@@ -84,7 +84,7 @@ static void power_event(struct input_handle *handle, unsigned int type,
                                        dev->state = PM_RESUME;
                                else
                                        dev->state = PM_SUSPEND;
-                               pm_send(dev->pm_dev, dev->state, dev);
+                                /* pm_send(dev->pm_dev, dev->state, dev); */
                                break;
                        case KEY_POWER:
                                /* Turn the input device off completely ? */
@@ -96,27 +96,41 @@ static void power_event(struct input_handle *handle, unsigned int type,
        return;
 }
 
-static struct input_handle *power_connect(struct input_handler *handler,
-                                         struct input_dev *dev,
-                                         const struct input_device_id *id)
+static int power_connect(struct input_handler *handler, struct input_dev *dev,
+                        const struct input_device_id *id)
 {
        struct input_handle *handle;
+       int error;
 
-       if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
-               return NULL;
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
 
        handle->dev = dev;
        handle->handler = handler;
+       handle->name = "power";
 
-       input_open_device(handle);
+       error = input_register_handle(handle);
+       if (error)
+               goto err_free_handle;
 
-       printk(KERN_INFO "power.c: Adding power management to input layer\n");
-       return handle;
+       error = input_open_device(handle);
+       if (error)
+               goto err_unregister_handle;
+
+       return 0;
+
+ err_unregister_handle:
+       input_unregister_handle(handle);
+ err_free_handle:
+       kfree(handle);
+       return error;
 }
 
 static void power_disconnect(struct input_handle *handle)
 {
        input_close_device(handle);
+       input_unregister_handle(handle);
        kfree(handle);
 }
 
@@ -135,7 +149,7 @@ static const struct input_device_id power_ids[] = {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
                .evbit = { BIT(EV_PWR) },
        },
-       { },    /* Terminating entry */
+       { },    /* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(input, power_ids);
index 0300dca8591d9cdb076f0413eee62a6b56823fc8..a23aedc64ab1648b741cec70faab5e53d4a1b71a 100644 (file)
@@ -155,7 +155,7 @@ static int tsdev_open(struct inode *inode, struct file *file)
                "for removal.\nSee Documentation/feature-removal-schedule.txt "
                "for details.\n");
 
-       if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
+       if (i >= TSDEV_MINORS)
                return -ENODEV;
 
        if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
@@ -246,14 +246,14 @@ static int tsdev_ioctl(struct inode *inode, struct file *file,
 
        switch (cmd) {
        case TS_GET_CAL:
-               if (copy_to_user ((void __user *)arg, &tsdev->cal,
-                                 sizeof (struct ts_calibration)))
+               if (copy_to_user((void __user *)arg, &tsdev->cal,
+                                sizeof (struct ts_calibration)))
                        retval = -EFAULT;
                break;
 
        case TS_SET_CAL:
-               if (copy_from_user (&tsdev->cal, (void __user *)arg,
-                                   sizeof (struct ts_calibration)))
+               if (copy_from_user(&tsdev->cal, (void __user *)arg,
+                                  sizeof (struct ts_calibration)))
                        retval = -EFAULT;
                break;
 
@@ -370,23 +370,25 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
        wake_up_interruptible(&tsdev->wait);
 }
 
-static struct input_handle *tsdev_connect(struct input_handler *handler,
-                                         struct input_dev *dev,
-                                         const struct input_device_id *id)
+static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
+                        const struct input_device_id *id)
 {
        struct tsdev *tsdev;
        struct class_device *cdev;
+       dev_t devt;
        int minor, delta;
+       int error;
 
        for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
        if (minor >= TSDEV_MINORS / 2) {
                printk(KERN_ERR
                       "tsdev: You have way too many touchscreens\n");
-               return NULL;
+               return -ENFILE;
        }
 
-       if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL)))
-               return NULL;
+       tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
+       if (!tsdev)
+               return -ENOMEM;
 
        INIT_LIST_HEAD(&tsdev->list);
        init_waitqueue_head(&tsdev->wait);
@@ -415,15 +417,35 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
 
        tsdev_table[minor] = tsdev;
 
-       cdev = class_device_create(&input_class, &dev->cdev,
-                       MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
-                       dev->cdev.dev, tsdev->name);
+       devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
+
+       cdev = class_device_create(&input_class, &dev->cdev, devt,
+                                  dev->cdev.dev, tsdev->name);
+       if (IS_ERR(cdev)) {
+               error = PTR_ERR(cdev);
+               goto err_free_tsdev;
+       }
 
        /* temporary symlink to keep userspace happy */
-       sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-                         tsdev->name);
+       error = sysfs_create_link(&input_class.subsys.kset.kobj,
+                                 &cdev->kobj, tsdev->name);
+       if (error)
+               goto err_cdev_destroy;
 
-       return &tsdev->handle;
+       error = input_register_handle(&tsdev->handle);
+       if (error)
+               goto err_remove_link;
+
+       return 0;
+
+ err_remove_link:
+       sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name);
+ err_cdev_destroy:
+       class_device_destroy(&input_class, devt);
+ err_free_tsdev:
+       tsdev_table[minor] = NULL;
+       kfree(tsdev);
+       return error;
 }
 
 static void tsdev_disconnect(struct input_handle *handle)
@@ -431,6 +453,8 @@ static void tsdev_disconnect(struct input_handle *handle)
        struct tsdev *tsdev = handle->private;
        struct tsdev_list *list;
 
+       input_unregister_handle(handle);
+
        sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name);
        class_device_destroy(&input_class,
                        MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
index 3a8b8c6f0ab5343e16911146b4770293e88bed74..a51d6cf6824cc67d1d6612e81e9124dff260f6dc 100644 (file)
@@ -1049,7 +1049,7 @@ struct input_handler {
        void *private;
 
        void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-       struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
+       int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
        void (*disconnect)(struct input_handle *handle);
        void (*start)(struct input_handle *handle);
 
@@ -1102,6 +1102,9 @@ void input_unregister_device(struct input_dev *);
 int input_register_handler(struct input_handler *);
 void input_unregister_handler(struct input_handler *);
 
+int input_register_handle(struct input_handle *);
+void input_unregister_handle(struct input_handle *);
+
 int input_grab_device(struct input_handle *);
 void input_release_device(struct input_handle *);