+ revert-input-make-input_openclose_device-more-robust.patch added to -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch titled

     revert input-make-input_openclose_device-more-robust

has been added to the -mm tree.  Its filename is

     revert-input-make-input_openclose_device-more-robust.patch

See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find
out what to do about this

------------------------------------------------------
Subject: revert input-make-input_openclose_device-more-robust
From: Andrew Morton <akpm@xxxxxxxx>

Make my mouse go again.

Cc: Dmitry Torokhov <dtor@xxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxx>
---

 drivers/input/evdev.c    |   63 +++++++++++++++--------------
 drivers/input/input.c    |   59 +++++++--------------------
 drivers/input/joydev.c   |   52 +++++++++++-------------
 drivers/input/mousedev.c |   78 ++++++++++++++++++-------------------
 drivers/input/tsdev.c    |   61 ++++++++++++++--------------
 include/linux/input.h    |    3 -
 6 files changed, 143 insertions(+), 173 deletions(-)

diff -puN drivers/input/evdev.c~revert-input-make-input_openclose_device-more-robust drivers/input/evdev.c
--- a/drivers/input/evdev.c~revert-input-make-input_openclose_device-more-robust
+++ a/drivers/input/evdev.c
@@ -23,7 +23,8 @@
 #include <linux/compat.h>
 
 struct evdev {
-	int dead;
+	int exist;
+	int open;
 	int minor;
 	char name[16];
 	struct input_handle handle;
@@ -89,6 +90,9 @@ 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);
 }
 
@@ -115,7 +119,9 @@ static int evdev_release(struct inode *i
 	list_del(&list->node);
 	kfree(list);
 
-	input_close_device(&evdev->handle);
+	if (!--evdev->open && evdev->exist)
+		input_close_device(&evdev->handle);
+
 	kref_put(&evdev->kref, evdev_free);
 
 	return 0;
@@ -125,14 +131,13 @@ 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->dead)
+	if (!evdev || !evdev->exist)
 		return -ENODEV;
 
 	list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL);
@@ -145,16 +150,10 @@ static int evdev_open(struct inode *inod
 	list_add_tail(&list->node, &evdev->list);
 	file->private_data = list;
 
-	error = input_open_device(&evdev->handle);
-	if (error)
-		goto fail;
+	if (!evdev->open++ && evdev->exist)
+		input_open_device(&evdev->handle);
 
 	return 0;
-
- fail:	list_del(&list->node);
-	kfree(list);
-	kref_put(&evdev->kref, evdev_free);
-	return error;
 }
 
 #ifdef CONFIG_COMPAT
@@ -255,46 +254,44 @@ 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 (evdev->dead)
+	if (!list->evdev->exist)
 		return -ENODEV;
 
 	while (retval < count) {
 
 		if (evdev_event_from_user(buffer + retval, &event))
 			return -EFAULT;
-		input_inject_event(&evdev->handle, event.type, event.code, event.value);
+		input_inject_event(&list->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 && !evdev->dead && (file->f_flags & O_NONBLOCK))
+	if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
-	retval = wait_event_interruptible(evdev->wait,
-			list->head != list->tail || evdev->dead);
+	retval = wait_event_interruptible(list->evdev->wait,
+		list->head != list->tail || (!list->evdev->exist));
 
 	if (retval)
 		return retval;
 
-	if (evdev->dead)
+	if (!list->evdev->exist)
 		return -ENODEV;
 
 	while (list->head != list->tail && retval + evdev_event_size() <= count) {
@@ -315,11 +312,10 @@ static ssize_t evdev_read(struct file *f
 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, &evdev->wait, wait);
-	return (list->head != list->tail ? POLLIN | POLLRDNORM : 0) |
-		(evdev->dead ? POLLHUP | POLLERR : 0);
+	poll_wait(file, &list->evdev->wait, wait);
+	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 #ifdef CONFIG_COMPAT
@@ -411,7 +407,7 @@ static long evdev_ioctl_handler(struct f
 	int i, t, u, v;
 	int error;
 
-	if (evdev->dead)
+	if (!evdev->exist)
 		return -ENODEV;
 
 	switch (cmd) {
@@ -654,6 +650,7 @@ 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;
@@ -701,11 +698,15 @@ 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;
 
-	evdev->dead = 1;
-	wake_up_interruptible(&evdev->wait);
-	list_for_each_entry(list, &evdev->list, node)
-		kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+	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);
+	}
 
 	kref_put(&evdev->kref, evdev_free);
 }
diff -puN drivers/input/input.c~revert-input-make-input_openclose_device-more-robust drivers/input/input.c
--- a/drivers/input/input.c~revert-input-make-input_openclose_device-more-robust
+++ a/drivers/input/input.c
@@ -261,43 +261,26 @@ 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--;
-		}
-	}
 
- out:
+	if (err)
+		handle->open--;
+
 	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)
 {
-	struct input_dev *dev = handle->dev;
-	int ret;
-
-	mutex_lock(&dev->mutex);
+	if (handle->dev->flush)
+		return handle->dev->flush(handle->dev, file);
 
-	if (dev->dead)
-		ret = -ENODEV;
-	else if (dev->flush)
-		ret = dev->flush(dev, file);
-	else
-		ret = 0;
-
-	mutex_unlock(&dev->mutex);
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(input_flush_device);
 
@@ -309,14 +292,9 @@ void input_close_device(struct input_han
 
 	mutex_lock(&dev->mutex);
 
-	if (handle->open) {
-		if (dev->users) {
-			if (dev->close && !dev->dead)
-				dev->close(dev);
-			dev->users--;
-		}
-		handle->open--;
-	}
+	if (!--dev->users && dev->close)
+		dev->close(dev);
+	handle->open--;
 
 	mutex_unlock(&dev->mutex);
 }
@@ -1051,19 +1029,14 @@ void input_unregister_device(struct inpu
 
 	list_del_init(&dev->node);
 
-	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);
 
+	mutex_lock(&dev->mutex);
+	dev->name = dev->phys = dev->uniq = NULL;
+	mutex_unlock(&dev->mutex);
+
 	class_device_unregister(&dev->cdev);
 
 	input_wakeup_procfs_readers();
diff -puN drivers/input/joydev.c~revert-input-make-input_openclose_device-more-robust drivers/input/joydev.c
--- a/drivers/input/joydev.c~revert-input-make-input_openclose_device-more-robust
+++ a/drivers/input/joydev.c
@@ -37,7 +37,8 @@ MODULE_LICENSE("GPL");
 #define JOYDEV_BUFFER_SIZE	64
 
 struct joydev {
-	int dead;
+	int exist;
+	int open;
 	int minor;
 	char name[16];
 	struct input_handle handle;
@@ -158,7 +159,9 @@ static int joydev_release(struct inode *
 	list_del(&list->node);
 	kfree(list);
 
-	input_close_device(&joydev->handle);
+	if (!--joydev->open && joydev->exist)
+		input_close_device(&list->joydev->handle);
+
 	kref_put(&joydev->kref, joydev_free);
 
 	return 0;
@@ -168,14 +171,13 @@ 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->dead)
+	if (!joydev || !joydev->exist)
 		return -ENODEV;
 
 	list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL);
@@ -188,16 +190,10 @@ static int joydev_open(struct inode *ino
 	list_add_tail(&list->node, &joydev->list);
 	file->private_data = list;
 
-	error = input_open_device(&joydev->handle);
-	if (error)
-		goto fail;
+	if (!joydev->open++ && joydev->exist)
+		input_open_device(&list->joydev->handle);
 
 	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)
@@ -212,7 +208,7 @@ static ssize_t joydev_read(struct file *
 	struct input_dev *input = joydev->handle.dev;
 	int retval = 0;
 
-	if (joydev->dead)
+	if (!joydev->exist)
 		return -ENODEV;
 
 	if (count < sizeof(struct js_event))
@@ -241,15 +237,15 @@ static ssize_t joydev_read(struct file *
 	    list->head == list->tail && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
-	retval = wait_event_interruptible(joydev->wait,
-					  joydev->dead ||
+	retval = wait_event_interruptible(list->joydev->wait,
+					  !list->joydev->exist ||
 					  list->startup < joydev->nabs + joydev->nkey ||
 					  list->head != list->tail);
 
 	if (retval)
 		return retval;
 
-	if (joydev->dead)
+	if (!list->joydev->exist)
 		return -ENODEV;
 
 	while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
@@ -291,12 +287,10 @@ 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, &joydev->wait, wait);
-	return (list->head != list->tail ||
-		list->startup < joydev->nabs + joydev->nkey ? POLLIN | POLLRDNORM : 0) |
-	       (joydev->dead ? POLLHUP | POLLERR : 0);
+	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));
 }
 
 static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
@@ -397,7 +391,7 @@ static long joydev_compat_ioctl(struct f
 	struct JS_DATA_SAVE_TYPE_32 ds32;
 	int err;
 
-	if (joydev->dead)
+	if (!joydev->exist)
 		return -ENODEV;
 
 	switch(cmd) {
@@ -448,7 +442,7 @@ static int joydev_ioctl(struct inode *in
 	struct joydev *joydev = list->joydev;
 	void __user *argp = (void __user *)arg;
 
-	if (joydev->dead)
+	if (!joydev->exist)
 		return -ENODEV;
 
 	switch(cmd) {
@@ -505,6 +499,7 @@ 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;
@@ -591,11 +586,14 @@ 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;
 
-	joydev->dead = 1;
-	wake_up_interruptible(&joydev->wait);
-	list_for_each_entry(list, &joydev->list, node)
-		kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+	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);
+	}
 
 	kref_put(&joydev->kref, joydev_free);
 }
diff -puN drivers/input/mousedev.c~revert-input-make-input_openclose_device-more-robust drivers/input/mousedev.c
--- a/drivers/input/mousedev.c~revert-input-make-input_openclose_device-more-robust
+++ a/drivers/input/mousedev.c
@@ -58,7 +58,8 @@ struct mousedev_hw_data {
 };
 
 struct mousedev {
-	int dead;
+	int exist;
+	int open;
 	int minor;
 	char name[16];
 	struct input_handle handle;
@@ -111,7 +112,6 @@ 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,12 +371,11 @@ 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;
 
-		input_close_device(handle);
+		if (!mousedev->open && mousedev->exist)
+			input_close_device(&mousedev->handle);
 		kref_put(&mousedev->kref, mousedev_free);
 	}
 }
@@ -391,10 +390,12 @@ static int mousedev_release(struct inode
 	list_del(&list->node);
 	kfree(list);
 
-	if (mousedev->minor == MOUSEDEV_MIX)
-		mixdev_release();
-	else
-		input_close_device(&mousedev->handle);
+	if (!--mousedev->open) {
+		if (mousedev->minor == MOUSEDEV_MIX)
+			mixdev_release();
+		else if (!mousedev_mix.open && mousedev->exist)
+			input_close_device(&mousedev->handle);
+	}
 
 	kref_put(&mousedev->kref, mousedev_free);
 
@@ -406,7 +407,6 @@ 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 @@ static int mousedev_open(struct inode *i
 		return -ENODEV;
 
 	mousedev =  mousedev_table[i];
-	if (!mousedev || mousedev->dead)
+	if (!mousedev || !mousedev->exist)
 		return -ENODEV;
 
 	list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL);
@@ -436,21 +436,17 @@ static int mousedev_open(struct inode *i
 	list_add_tail(&list->node, &mousedev->list);
 	file->private_data = list;
 
-	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;
-		}
+	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);
 	}
 
 	return 0;
@@ -585,19 +581,18 @@ 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(mousedev->wait,
-					  mousedev->dead || list->ready || list->buffer);
+	retval = wait_event_interruptible(list->mousedev->wait,
+					  !list->mousedev->exist || list->ready || list->buffer);
 
 	if (retval)
 		return retval;
 
-	if (mousedev->dead)
+	if (!list->mousedev->exist)
 		return -ENODEV;
 
 	if (!list->buffer && list->ready) {
@@ -620,11 +615,10 @@ 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, &mousedev->wait, wait);
-	return (list->ready || list->buffer ? POLLIN | POLLRDNORM : 0) |
-	       (mousedev->dead ? POLLHUP | POLLERR : 0);
+	poll_wait(file, &list->mousedev->wait, wait);
+	return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
+		(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static const struct file_operations mousedev_fops = {
@@ -661,6 +655,7 @@ 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;
@@ -686,7 +681,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;
@@ -716,11 +711,15 @@ 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;
 
-	mousedev->dead = 1;
-	wake_up_interruptible(&mousedev->wait);
-	list_for_each_entry(list, &mousedev->list, node)
-		kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+	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);
 
 	kref_put(&mousedev->kref, mousedev_free);
 }
@@ -784,6 +783,7 @@ 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 -puN drivers/input/tsdev.c~revert-input-make-input_openclose_device-more-robust drivers/input/tsdev.c
--- a/drivers/input/tsdev.c~revert-input-make-input_openclose_device-more-robust
+++ a/drivers/input/tsdev.c
@@ -106,7 +106,8 @@ struct ts_calibration {
 };
 
 struct tsdev {
-	int dead;
+	int exist;
+	int open;
 	int minor;
 	char name[8];
 	struct input_handle handle;
@@ -147,26 +148,17 @@ 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->dead)
+	if (!tsdev || !tsdev->exist)
 		return -ENODEV;
 
 	list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL);
@@ -180,16 +172,18 @@ static int tsdev_open(struct inode *inod
 	list_add_tail(&list->node, &tsdev->list);
 	file->private_data = list;
 
-	error = input_open_device(&tsdev->handle);
-	if (error)
-		goto fail;
+	if (!tsdev->open++ && tsdev->exist)
+		input_open_device(&list->tsdev->handle);
 
 	return 0;
+}
 
- fail:	list_del(&list->node);
-	kfree(list);
-	kref_put(&tsdev->kref, tsdev_free);
-	return error;
+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_release(struct inode *inode, struct file *file)
@@ -202,7 +196,9 @@ static int tsdev_release(struct inode *i
 	list_del(&list->node);
 	kfree(list);
 
-	input_close_device(&tsdev->handle);
+	if (!--tsdev->open && tsdev->exist)
+		input_close_device(&tsdev->handle);
+
 	kref_put(&tsdev->kref, tsdev_free);
 
 	return 0;
@@ -215,16 +211,16 @@ static ssize_t tsdev_read(struct file *f
 	struct tsdev *tsdev = list->tsdev;
 	int retval = 0;
 
-	if (list->head == list->tail && !tsdev->dead && (file->f_flags & O_NONBLOCK))
+	if (list->head == list->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
 	retval = wait_event_interruptible(tsdev->wait,
-			list->head != list->tail || tsdev->dead);
+			list->head != list->tail || !tsdev->exist);
 
 	if (retval)
 		return retval;
 
-	if (tsdev->dead)
+	if (!tsdev->exist)
 		return -ENODEV;
 
 	while (list->head != list->tail &&
@@ -243,11 +239,10 @@ 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, &tsdev->wait, wait);
-	return (list->head != list->tail ? POLLIN | POLLRDNORM : 0) |
-	       (tsdev->dead ? POLLHUP | POLLERR : 0);
+	poll_wait(file, &list->tsdev->wait, wait);
+	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int tsdev_ioctl(struct inode *inode, struct file *file,
@@ -409,6 +404,7 @@ 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;
@@ -468,11 +464,14 @@ 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;
 
-	tsdev->dead = 1;
-	wake_up_interruptible(&tsdev->wait);
-	list_for_each_entry(list, &tsdev->list, node)
-		kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+	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);
+	}
 
 	kref_put(&tsdev->kref, tsdev_free);
 }
diff -puN include/linux/input.h~revert-input-make-input_openclose_device-more-robust include/linux/input.h
--- a/include/linux/input.h~revert-input-make-input_openclose_device-more-robust
+++ a/include/linux/input.h
@@ -954,8 +954,7 @@ struct input_dev {
 	struct timer_list timer;
 
 	struct pt_regs *regs;
-
-	int dead;
+	int state;
 
 	int sync;
 
_

Patches currently in -mm which might be from akpm@xxxxxxxx are

origin.patch
pidh-cleanup.patch
revert-insert-ioapics-and-local-apic-into-resource-map.patch
git-acpi.patch
acpi-preserve-correct-battery-state-through-suspend-resume-cycles-tidy.patch
acpi-asus-s3-resume-fix.patch
sony_apci-resume.patch
kauditd_thread-warning-fix.patch
git-cifs-fixup.patch
git-dvb.patch
git-geode-fixup.patch
git-gfs2.patch
revert-input-make-input_openclose_device-more-robust.patch
revert-input-rework-handle-creation-code.patch
revert-input-use-krefs-for-refcounting-in-input-handlers.patch
hdrcheck-permission-fix.patch
git-libata-all.patch
libata-return-sense-data-in-hdio_drive_cmd-ioctl-tidy.patch
mmc-driver-for-ti-flashmedia-card-reader-source.patch
forcedeth-power-management-support-tidy.patch
drivers-net-ns83820c-add-paramter-to-disable-auto.patch
git-parisc.patch
git-parisc-powerpc-fix.patch
git-pcmcia-fixup.patch
git-serial.patch
git-serial-fixup.patch
serial-fix-uart_bug_txen-test.patch
revert-gregkh-pci-altix-rom-shadowing.patch
revert-gregkh-pci-altix-sn-acpi-hotplug-support.patch
revert-gregkh-pci-altix-add-initial-acpi-io-support.patch
pci-optionally-sort-device-lists-breadth-first-tweaks.patch
pci-optionally-sort-device-lists-breadth-first-force-on.patch
revert-pci-assign-ioapic-resource-at-hotplug.patch
git-scsi-misc.patch
git-scsi-target-fixup.patch
git-scsi-target-vs-git-block.patch
xpad-dance-pad-support-tidy.patch
git-watchdog.patch
git-watchdog-fixup.patch
fix-x86_64-mm-kernel-stack-termination.patch
x86_64-dump_trace-atomicity-fix.patch
spinlock-debug-all-cpu-backtrace.patch
spinlock-debug-all-cpu-backtrace-fix.patch
spinlock-debug-all-cpu-backtrace-fix-2.patch
spinlock-debug-all-cpu-backtrace-fix-3.patch
xfs-rename-uio_read.patch
get-rid-of-zone_table-fix.patch
kmemdup-introduce-vs-slab-clean-up-leak-tracking-ifdefs-a-little-bit.patch
slab-reduce-numa-text-size-tidy.patch
swap-token-new-scheme-to-preempt-token-tidy.patch
radix-tree-rcu-lockless-readside.patch
acx1xx-wireless-driver.patch
tiacx-pci-build-fix.patch
tiacx-ia64-fix.patch
tiacx-build-fix.patch
swsusp-add-resume_offset-command-line-parameter-rev-2-fix.patch
deprecate-smbfs-in-favour-of-cifs.patch
edac-new-opteron-athlon64-memory-controller-driver.patch
edac-new-opteron-athlon64-memory-controller-driver-tidy.patch
add-address_space_operationsbatch_write-fix.patch
add-config_headers_check-option-to-automatically-run-make-headers_check-nobble.patch
generic-bug-handling.patch
use-generic-bug-for-i386.patch
use-generic-bug-for-x86-64.patch
use-generic-bug-for-powerpc.patch
use-generic-bug-for-powerpc-fix-2.patch
use-generic-bug-for-powerpc-fix-infinite-loop-on-bug.patch
bug-test-1.patch
ipmi-allow-user-to-override-the-kernel-ipmi-daemon-enable-tidy.patch
fs-cache-make-kafs-use-fs-cache-fix.patch
fs-cache-make-kafs-use-fs-cache-vs-streamline-generic_file_-interfaces-and-filemap.patch
nfs-use-local-caching-12-fix.patch
sched-remove-unnecessary-sched-group-allocations.patch
swap_prefetch-vs-zoned-counters.patch
ecryptfs-mmap-operations.patch
ecryptfs-alpha-build-fix.patch
ecryptfs-more-elegant-aes-key-size-manipulation.patch
ecryptfs-get_sb_dev-fix.patch
make-kmem_cache_destroy-return-void-ecryptfs.patch
ecryptfs-versioning-fixes-tidy.patch
readahead-sysctl-parameters-fix.patch
make-copy_from_user_inatomic-not-zero-the-tail-on-i386-vs-reiser4.patch
make-kmem_cache_destroy-return-void-reiser4.patch
reiser4-hardirq-include-fix.patch
reiser4-run-truncate_inode_pages-in-reiser4_delete_inode.patch
reiser4-get_sb_dev-fix.patch
reiser4-vs-zoned-allocator.patch
reiser4-rename-generic_sounding_globalspatch-fix.patch
hpt3xx-rework-rate-filtering-tidy.patch
genirq-convert-the-i386-architecture-to-irq-chips.patch
genirq-x86_64-irq-reenable-migrating-irqs-to-other-cpus.patch
genirq-msi-simplify-msi-enable-and-disable.patch
genirq-ia64-irq-dynamic-irq-support.patch
genirq-msi-only-build-msi-apicc-on-ia64-fix.patch
genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector.patch
genirq-x86_64-irq-make-vector_irq-per-cpu-fix.patch
genirq-x86_64-irq-make-vector_irq-per-cpu-warning-fix.patch
add-hypertransport-capability-defines-fix.patch
initial-generic-hypertransport-interrupt-support-Kconfig-fix.patch
srcu-report-out-of-memory-errors-fixlet.patch
isdn-debug-build-fix.patch
isdn-more-pr_debug-fixes.patch
kevent-core-files-fix.patch
kevent-socket-notifications-fix-2.patch
kevent-socket-notifications-fix-4.patch
nr_blockdev_pages-in_interrupt-warning.patch
device-suspend-debug.patch
slab-leaks3-default-y.patch
x86-kmap_atomic-debugging.patch
restore-rogue-readahead-printk.patch
put_bh-debug.patch
acpi_format_exception-debug.patch
jmicron-warning-fix.patch
squash-ipc-warnings.patch
squash-transmeta-warnings.patch
squash-tcp-warnings.patch
squash-udf-warnings.patch

-
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux