On Tue, 26 Sep 2006 23:37:29 -0700
Andrew Morton <[EMAIL PROTECTED]> wrote:

> With git-input.patch applied, my wireless USB mouse doesn't work.

OK, I did a round of restesting.  I haven't seen the oopses again,
but I didn't try terribly hard.

The mouse-dies-after-one-second bug is still there.  Bisection shows
that it's caused by this:

commit 0bfb22b4308bea5e7afd9434ac7e937b12fc5915
Author: Dmitry Torokhov <[EMAIL PROTECTED]>
Date:   Sun Oct 1 23:50:26 2006 -0400

    Input: make input_{open|close}_device() more robust
    
    - add "dead" flag to input_dev structure and check the flag when
      opening, closing or trying to flush input device
    - fix error handling in input_open_device (was leaving device "used")
    - allow input_close_device() to be safely called for already closed
      devices
    
    Signed-off-by: Dmitry Torokhov <[EMAIL PROTECTED]>

diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 7f87c4b..b71e2f3 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -23,8 +23,7 @@ #include <linux/device.h>
 #include <linux/compat.h>
 
 struct evdev {
-       int exist;
-       int open;
+       int dead;
        int minor;
        char name[16];
        struct input_handle handle;
@@ -90,9 +89,6 @@ static int evdev_flush(struct file *file
 {
        struct evdev_list *list = file->private_data;
 
-       if (!list->evdev->exist)
-               return -ENODEV;
-
        return input_flush_device(&list->evdev->handle, file);
 }
 
@@ -119,9 +115,7 @@ static int evdev_release(struct inode *i
        list_del(&list->node);
        kfree(list);
 
-       if (!--evdev->open && evdev->exist)
-               input_close_device(&evdev->handle);
-
+       input_close_device(&evdev->handle);
        kref_put(&evdev->kref, evdev_free);
 
        return 0;
@@ -131,13 +125,14 @@ static int evdev_open(struct inode *inod
 {
        struct evdev_list *list;
        struct evdev *evdev;
+       int error;
        int i = iminor(inode) - EVDEV_MINOR_BASE;
 
        if (i >= EVDEV_MINORS)
                return -ENODEV;
 
        evdev = evdev_table[i];
-       if (!evdev || !evdev->exist)
+       if (!evdev || evdev->dead)
                return -ENODEV;
 
        list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL);
@@ -150,10 +145,16 @@ static int evdev_open(struct inode *inod
        list_add_tail(&list->node, &evdev->list);
        file->private_data = list;
 
-       if (!evdev->open++ && evdev->exist)
-               input_open_device(&evdev->handle);
+       error = input_open_device(&evdev->handle);
+       if (error)
+               goto fail;
 
        return 0;
+
+ fail: list_del(&list->node);
+       kfree(list);
+       kref_put(&evdev->kref, evdev_free);
+       return error;
 }
 
 #ifdef CONFIG_COMPAT
@@ -254,44 +255,46 @@ static int evdev_event_to_user(char __us
 
 #endif /* CONFIG_COMPAT */
 
-static ssize_t evdev_write(struct file * file, const char __user * buffer, 
size_t count, loff_t *ppos)
+static ssize_t evdev_write(struct file *file, const char __user *buffer, 
size_t count, loff_t *ppos)
 {
        struct evdev_list *list = file->private_data;
+       struct evdev *evdev = list->evdev;
        struct input_event event;
        int retval = 0;
 
-       if (!list->evdev->exist)
+       if (evdev->dead)
                return -ENODEV;
 
        while (retval < count) {
 
                if (evdev_event_from_user(buffer + retval, &event))
                        return -EFAULT;
-               input_inject_event(&list->evdev->handle, event.type, 
event.code, event.value);
+               input_inject_event(&evdev->handle, event.type, event.code, 
event.value);
                retval += evdev_event_size();
        }
 
        return retval;
 }
 
-static ssize_t evdev_read(struct file * file, char __user * buffer, size_t 
count, loff_t *ppos)
+static ssize_t evdev_read(struct file *file, char __user *buffer, size_t 
count, loff_t *ppos)
 {
        struct evdev_list *list = file->private_data;
+       struct evdev *evdev = list->evdev;
        int retval;
 
        if (count < evdev_event_size())
                return -EINVAL;
 
-       if (list->head == list->tail && list->evdev->exist && (file->f_flags & 
O_NONBLOCK))
+       if (list->head == list->tail && !evdev->dead && (file->f_flags & 
O_NONBLOCK))
                return -EAGAIN;
 
-       retval = wait_event_interruptible(list->evdev->wait,
-               list->head != list->tail || (!list->evdev->exist));
+       retval = wait_event_interruptible(evdev->wait,
+                       list->head != list->tail || evdev->dead);
 
        if (retval)
                return retval;
 
-       if (!list->evdev->exist)
+       if (evdev->dead)
                return -ENODEV;
 
        while (list->head != list->tail && retval + evdev_event_size() <= 
count) {
@@ -312,10 +315,11 @@ static ssize_t evdev_read(struct file * 
 static unsigned int evdev_poll(struct file *file, poll_table *wait)
 {
        struct evdev_list *list = file->private_data;
+       struct evdev *evdev = list->evdev;
 
-       poll_wait(file, &list->evdev->wait, wait);
-       return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
-               (list->evdev->exist ? 0 : (POLLHUP | POLLERR));
+       poll_wait(file, &evdev->wait, wait);
+       return (list->head != list->tail ? POLLIN | POLLRDNORM : 0) |
+               (evdev->dead ? POLLHUP | POLLERR : 0);
 }
 
 #ifdef CONFIG_COMPAT
@@ -407,7 +411,7 @@ static long evdev_ioctl_handler(struct f
        int i, t, u, v;
        int error;
 
-       if (!evdev->exist)
+       if (evdev->dead)
                return -ENODEV;
 
        switch (cmd) {
@@ -650,7 +654,6 @@ static int evdev_connect(struct input_ha
        INIT_LIST_HEAD(&evdev->list);
        init_waitqueue_head(&evdev->wait);
 
-       evdev->exist = 1;
        evdev->minor = minor;
        evdev->handle.dev = dev;
        evdev->handle.name = evdev->name;
@@ -698,15 +701,11 @@ static void evdev_disconnect(struct inpu
        sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
        class_device_destroy(&input_class,
                        MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
-       evdev->exist = 0;
-
-       if (evdev->open) {
-               input_flush_device(handle, NULL);
-               input_close_device(handle);
-               wake_up_interruptible(&evdev->wait);
-               list_for_each_entry(list, &evdev->list, node)
-                       kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-       }
+
+       evdev->dead = 1;
+       wake_up_interruptible(&evdev->wait);
+       list_for_each_entry(list, &evdev->list, node)
+               kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 
        kref_put(&evdev->kref, evdev_free);
 }
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 5ac4a28..6ff85ca 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -261,26 +261,43 @@ int input_open_device(struct input_handl
        if (err)
                return err;
 
+       if (dev->dead) {
+               err = -ENODEV;
+               goto out;
+       }
+
        handle->open++;
 
-       if (!dev->users++ && dev->open)
+       if (!dev->users++ && dev->open) {
                err = dev->open(dev);
+               if (err) {
+                       dev->users--;
+                       handle->open--;
+               }
+       }
 
-       if (err)
-               handle->open--;
-
+ out:
        mutex_unlock(&dev->mutex);
-
        return err;
 }
 EXPORT_SYMBOL(input_open_device);
 
-int input_flush_device(struct input_handle* handle, struct file* file)
+int input_flush_device(struct input_handle *handle, struct file *file)
 {
-       if (handle->dev->flush)
-               return handle->dev->flush(handle->dev, file);
+       struct input_dev *dev = handle->dev;
+       int ret;
 
-       return 0;
+       mutex_lock(&dev->mutex);
+
+       if (dev->dead)
+               ret = -ENODEV;
+       else if (dev->flush)
+               ret = dev->flush(dev, file);
+       else
+               ret = 0;
+
+       mutex_unlock(&dev->mutex);
+       return ret;
 }
 EXPORT_SYMBOL(input_flush_device);
 
@@ -292,9 +309,14 @@ void input_close_device(struct input_han
 
        mutex_lock(&dev->mutex);
 
-       if (!--dev->users && dev->close)
-               dev->close(dev);
-       handle->open--;
+       if (handle->open) {
+               if (dev->users) {
+                       if (dev->close && !dev->dead)
+                               dev->close(dev);
+                       dev->users--;
+               }
+               handle->open--;
+       }
 
        mutex_unlock(&dev->mutex);
 }
@@ -1029,14 +1051,19 @@ void input_unregister_device(struct inpu
 
        list_del_init(&dev->node);
 
-       sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
-       sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
-       sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
-
        mutex_lock(&dev->mutex);
+       if (dev->flush)
+               dev->flush(dev, NULL);
+       if (dev->users && dev->close)
+               dev->close(dev);
        dev->name = dev->phys = dev->uniq = NULL;
+       dev->dead = 1;
        mutex_unlock(&dev->mutex);
 
+       sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
+       sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
+       sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
+
        class_device_unregister(&dev->cdev);
 
        input_wakeup_procfs_readers();
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index aa5ddef..67a3c68 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -37,8 +37,7 @@ #define JOYDEV_MINORS         16
 #define JOYDEV_BUFFER_SIZE     64
 
 struct joydev {
-       int exist;
-       int open;
+       int dead;
        int minor;
        char name[16];
        struct input_handle handle;
@@ -159,9 +158,7 @@ static int joydev_release(struct inode *
        list_del(&list->node);
        kfree(list);
 
-       if (!--joydev->open && joydev->exist)
-               input_close_device(&list->joydev->handle);
-
+       input_close_device(&joydev->handle);
        kref_put(&joydev->kref, joydev_free);
 
        return 0;
@@ -171,13 +168,14 @@ static int joydev_open(struct inode *ino
 {
        struct joydev_list *list;
        struct joydev *joydev;
+       int error;
        int i = iminor(inode) - JOYDEV_MINOR_BASE;
 
        if (i >= JOYDEV_MINORS)
                return -ENODEV;
 
        joydev = joydev_table[i];
-       if (!joydev || !joydev->exist)
+       if (!joydev || joydev->dead)
                return -ENODEV;
 
        list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL);
@@ -190,10 +188,16 @@ static int joydev_open(struct inode *ino
        list_add_tail(&list->node, &joydev->list);
        file->private_data = list;
 
-       if (!joydev->open++ && joydev->exist)
-               input_open_device(&list->joydev->handle);
+       error = input_open_device(&joydev->handle);
+       if (error)
+               goto fail;
 
        return 0;
+
+ fail: list_del(&list->node);
+       kfree(list);
+       kref_put(&joydev->kref, joydev_free);
+       return error;
 }
 
 static ssize_t joydev_write(struct file * file, const char __user * buffer, 
size_t count, loff_t *ppos)
@@ -208,7 +212,7 @@ static ssize_t joydev_read(struct file *
        struct input_dev *input = joydev->handle.dev;
        int retval = 0;
 
-       if (!joydev->exist)
+       if (joydev->dead)
                return -ENODEV;
 
        if (count < sizeof(struct js_event))
@@ -237,15 +241,15 @@ static ssize_t joydev_read(struct file *
            list->head == list->tail && (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
 
-       retval = wait_event_interruptible(list->joydev->wait,
-                                         !list->joydev->exist ||
+       retval = wait_event_interruptible(joydev->wait,
+                                         joydev->dead ||
                                          list->startup < joydev->nabs + 
joydev->nkey ||
                                          list->head != list->tail);
 
        if (retval)
                return retval;
 
-       if (!list->joydev->exist)
+       if (joydev->dead)
                return -ENODEV;
 
        while (list->startup < joydev->nabs + joydev->nkey && retval + 
sizeof(struct js_event) <= count) {
@@ -287,10 +291,12 @@ static ssize_t joydev_read(struct file *
 static unsigned int joydev_poll(struct file *file, poll_table *wait)
 {
        struct joydev_list *list = file->private_data;
+       struct joydev *joydev = list->joydev;
 
-       poll_wait(file, &list->joydev->wait, wait);
-       return ((list->head != list->tail || list->startup < list->joydev->nabs 
+ list->joydev->nkey) ?
-               (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : 
(POLLHUP | POLLERR));
+       poll_wait(file, &joydev->wait, wait);
+       return (list->head != list->tail ||
+               list->startup < joydev->nabs + joydev->nkey ? POLLIN | 
POLLRDNORM : 0) |
+              (joydev->dead ? POLLHUP | POLLERR : 0);
 }
 
 static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void 
__user *argp)
@@ -391,7 +397,7 @@ static long joydev_compat_ioctl(struct f
        struct JS_DATA_SAVE_TYPE_32 ds32;
        int err;
 
-       if (!joydev->exist)
+       if (joydev->dead)
                return -ENODEV;
 
        switch(cmd) {
@@ -442,7 +448,7 @@ static int joydev_ioctl(struct inode *in
        struct joydev *joydev = list->joydev;
        void __user *argp = (void __user *)arg;
 
-       if (!joydev->exist)
+       if (joydev->dead)
                return -ENODEV;
 
        switch(cmd) {
@@ -499,7 +505,6 @@ static int joydev_connect(struct input_h
        init_waitqueue_head(&joydev->wait);
 
        joydev->minor = minor;
-       joydev->exist = 1;
        joydev->handle.dev = dev;
        joydev->handle.name = joydev->name;
        joydev->handle.handler = handler;
@@ -586,14 +591,11 @@ static void joydev_disconnect(struct inp
 
        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;
 
-       if (joydev->open) {
-               input_close_device(handle);
-               wake_up_interruptible(&joydev->wait);
-               list_for_each_entry(list, &joydev->list, node)
-                       kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-       }
+       joydev->dead = 1;
+       wake_up_interruptible(&joydev->wait);
+       list_for_each_entry(list, &joydev->list, node)
+               kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 
        kref_put(&joydev->kref, joydev_free);
 }
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 685a622..3c3ff63 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -58,8 +58,7 @@ struct mousedev_hw_data {
 };
 
 struct mousedev {
-       int exist;
-       int open;
+       int dead;
        int minor;
        char name[16];
        struct input_handle handle;
@@ -112,6 +111,7 @@ static struct input_handler mousedev_han
 
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
+static int mousedev_mix_open;
 
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
@@ -371,11 +371,12 @@ static void mixdev_release(void)
 {
        struct input_handle *handle;
 
+       mousedev_mix_open--;
+
        list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
                struct mousedev *mousedev = handle->private;
 
-               if (!mousedev->open && mousedev->exist)
-                       input_close_device(&mousedev->handle);
+               input_close_device(handle);
                kref_put(&mousedev->kref, mousedev_free);
        }
 }
@@ -390,12 +391,10 @@ static int mousedev_release(struct inode
        list_del(&list->node);
        kfree(list);
 
-       if (!--mousedev->open) {
-               if (mousedev->minor == MOUSEDEV_MIX)
-                       mixdev_release();
-               else if (!mousedev_mix.open && mousedev->exist)
-                       input_close_device(&mousedev->handle);
-       }
+       if (mousedev->minor == MOUSEDEV_MIX)
+               mixdev_release();
+       else
+               input_close_device(&mousedev->handle);
 
        kref_put(&mousedev->kref, mousedev_free);
 
@@ -407,6 +406,7 @@ static int mousedev_open(struct inode *i
        struct mousedev_list *list;
        struct input_handle *handle;
        struct mousedev *mousedev, *md;
+       int error;
        int i;
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
@@ -420,7 +420,7 @@ #endif
                return -ENODEV;
 
        mousedev =  mousedev_table[i];
-       if (!mousedev || !mousedev->exist)
+       if (!mousedev || mousedev->dead)
                return -ENODEV;
 
        list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL);
@@ -436,17 +436,21 @@ #endif
        list_add_tail(&list->node, &mousedev->list);
        file->private_data = list;
 
-       if (!mousedev->open++) {
-               if (mousedev->minor == MOUSEDEV_MIX) {
-                       list_for_each_entry(handle, &mousedev_handler.h_list, 
h_node) {
-                               md = handle->private;
-                               kref_get(&md->kref);
-                               if (!md->open && md->exist)
-                                       input_open_device(handle);
-                       }
-               } else
-                       if (!mousedev_mix.open && mousedev->exist)
-                               input_open_device(&mousedev->handle);
+       if (mousedev->minor == MOUSEDEV_MIX) {
+               mousedev_mix_open++;
+               list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
+                       md = handle->private;
+                       kref_get(&md->kref);
+                       input_open_device(handle);
+               }
+       } else {
+               error = input_open_device(&mousedev->handle);
+               if (error) {
+                       list_del(&list->node);
+                       kfree(list);
+                       kref_put(&mousedev->kref, mousedev_free);
+                       return error;
+               }
        }
 
        return 0;
@@ -581,18 +585,19 @@ static ssize_t mousedev_write(struct fil
 static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t 
count, loff_t *ppos)
 {
        struct mousedev_list *list = file->private_data;
+       struct mousedev *mousedev = list->mousedev;
        int retval = 0;
 
        if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
 
-       retval = wait_event_interruptible(list->mousedev->wait,
-                                         !list->mousedev->exist || list->ready 
|| list->buffer);
+       retval = wait_event_interruptible(mousedev->wait,
+                                         mousedev->dead || list->ready || 
list->buffer);
 
        if (retval)
                return retval;
 
-       if (!list->mousedev->exist)
+       if (mousedev->dead)
                return -ENODEV;
 
        if (!list->buffer && list->ready) {
@@ -615,10 +620,11 @@ static ssize_t mousedev_read(struct file
 static unsigned int mousedev_poll(struct file *file, poll_table *wait)
 {
        struct mousedev_list *list = file->private_data;
+       struct mousedev *mousedev = list->mousedev;
 
-       poll_wait(file, &list->mousedev->wait, wait);
-       return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
-               (list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
+       poll_wait(file, &mousedev->wait, wait);
+       return (list->ready || list->buffer ? POLLIN | POLLRDNORM : 0) |
+              (mousedev->dead ? POLLHUP | POLLERR : 0);
 }
 
 static const struct file_operations mousedev_fops = {
@@ -655,7 +661,6 @@ static int mousedev_connect(struct input
        init_waitqueue_head(&mousedev->wait);
 
        mousedev->minor = minor;
-       mousedev->exist = 1;
        mousedev->handle.dev = dev;
        mousedev->handle.name = mousedev->name;
        mousedev->handle.handler = handler;
@@ -681,7 +686,7 @@ static int mousedev_connect(struct input
        if (error)
                goto err_remove_link;
 
-       if (mousedev_mix.open) {
+       if (mousedev_mix_open) {
                error = input_open_device(&mousedev->handle);
                if (error)
                        goto err_unlink_handle;
@@ -711,15 +716,11 @@ static void mousedev_disconnect(struct i
        sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
        class_device_destroy(&input_class,
                        MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + 
mousedev->minor));
-       mousedev->exist = 0;
 
-       if (mousedev->open) {
-               input_close_device(handle);
-               wake_up_interruptible(&mousedev->wait);
-               list_for_each_entry(list, &mousedev->list, node)
-                       kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-       } else if (mousedev_mix.open)
-               input_close_device(handle);
+       mousedev->dead = 1;
+       wake_up_interruptible(&mousedev->wait);
+       list_for_each_entry(list, &mousedev->list, node)
+               kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 
        kref_put(&mousedev->kref, mousedev_free);
 }
@@ -783,7 +784,6 @@ static int __init mousedev_init(void)
        kref_init(&mousedev_mix.kref);
        INIT_LIST_HEAD(&mousedev_mix.list);
        init_waitqueue_head(&mousedev_mix.wait);
-       mousedev_mix.exist = 1;
        mousedev_mix.minor = MOUSEDEV_MIX;
 
        mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index 123bbe7..d61da4b 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -106,8 +106,7 @@ struct ts_calibration {
 };
 
 struct tsdev {
-       int exist;
-       int open;
+       int dead;
        int minor;
        char name[8];
        struct input_handle handle;
@@ -148,17 +147,26 @@ static int tsdev_fasync(int fd, struct f
        return retval < 0 ? retval : 0;
 }
 
+static void tsdev_free(struct kref *kref)
+{
+       struct tsdev *tsdev = container_of(kref, struct tsdev, kref);
+
+       tsdev_table[tsdev->minor] = NULL;
+       kfree(tsdev);
+}
+
 static int tsdev_open(struct inode *inode, struct file *file)
 {
-       int i = iminor(inode) - TSDEV_MINOR_BASE;
        struct tsdev_list *list;
        struct tsdev *tsdev;
+       int error;
+       int i = iminor(inode) - TSDEV_MINOR_BASE;
 
        if (i >= TSDEV_MINORS)
                return -ENODEV;
 
        tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
-       if (!tsdev || !tsdev->exist)
+       if (!tsdev || tsdev->dead)
                return -ENODEV;
 
        list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL);
@@ -172,18 +180,16 @@ static int tsdev_open(struct inode *inod
        list_add_tail(&list->node, &tsdev->list);
        file->private_data = list;
 
-       if (!tsdev->open++ && tsdev->exist)
-               input_open_device(&list->tsdev->handle);
+       error = input_open_device(&tsdev->handle);
+       if (error)
+               goto fail;
 
        return 0;
-}
 
-static void tsdev_free(struct kref *kref)
-{
-       struct tsdev *tsdev = container_of(kref, struct tsdev, kref);
-
-       tsdev_table[tsdev->minor] = NULL;
-       kfree(tsdev);
+ fail: list_del(&list->node);
+       kfree(list);
+       kref_put(&tsdev->kref, tsdev_free);
+       return error;
 }
 
 static int tsdev_release(struct inode *inode, struct file *file)
@@ -196,9 +202,7 @@ static int tsdev_release(struct inode *i
        list_del(&list->node);
        kfree(list);
 
-       if (!--tsdev->open && tsdev->exist)
-               input_close_device(&tsdev->handle);
-
+       input_close_device(&tsdev->handle);
        kref_put(&tsdev->kref, tsdev_free);
 
        return 0;
@@ -211,16 +215,16 @@ static ssize_t tsdev_read(struct file *f
        struct tsdev *tsdev = list->tsdev;
        int retval = 0;
 
-       if (list->head == list->tail && tsdev->exist && (file->f_flags & 
O_NONBLOCK))
+       if (list->head == list->tail && !tsdev->dead && (file->f_flags & 
O_NONBLOCK))
                return -EAGAIN;
 
        retval = wait_event_interruptible(tsdev->wait,
-                       list->head != list->tail || !tsdev->exist);
+                       list->head != list->tail || tsdev->dead);
 
        if (retval)
                return retval;
 
-       if (!tsdev->exist)
+       if (tsdev->dead)
                return -ENODEV;
 
        while (list->head != list->tail &&
@@ -239,10 +243,11 @@ static ssize_t tsdev_read(struct file *f
 static unsigned int tsdev_poll(struct file *file, poll_table * wait)
 {
        struct tsdev_list *list = file->private_data;
+       struct tsdev *tsdev = list->tsdev;
 
-       poll_wait(file, &list->tsdev->wait, wait);
-       return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
-               (list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
+       poll_wait(file, &tsdev->wait, wait);
+       return (list->head != list->tail ? POLLIN | POLLRDNORM : 0) |
+              (tsdev->dead ? POLLHUP | POLLERR : 0);
 }
 
 static int tsdev_ioctl(struct inode *inode, struct file *file,
@@ -404,7 +409,6 @@ static int tsdev_connect(struct input_ha
 
        sprintf(tsdev->name, "ts%d", minor);
 
-       tsdev->exist = 1;
        tsdev->minor = minor;
        tsdev->handle.dev = dev;
        tsdev->handle.name = tsdev->name;
@@ -464,14 +468,11 @@ static void tsdev_disconnect(struct inpu
        sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name);
        class_device_destroy(&input_class,
                        MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
-       tsdev->exist = 0;
 
-       if (tsdev->open) {
-               input_close_device(handle);
-               wake_up_interruptible(&tsdev->wait);
-               list_for_each_entry(list, &tsdev->list, node)
-                       kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-       }
+       tsdev->dead = 1;
+       wake_up_interruptible(&tsdev->wait);
+       list_for_each_entry(list, &tsdev->list, node)
+               kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 
        kref_put(&tsdev->kref, tsdev_free);
 }
diff --git a/include/linux/input.h b/include/linux/input.h
index 3c42ef9..a5799e7 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -954,7 +954,8 @@ struct input_dev {
        struct timer_list timer;
 
        struct pt_regs *regs;
-       int state;
+
+       int dead;
 
        int sync;
 


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to