Input: handlers - handle errors from input_open_device()

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 8a4cce5..6cff809 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -130,6 +130,7 @@
 	struct evdev_client *client;
 	struct evdev *evdev;
 	int i = iminor(inode) - EVDEV_MINOR_BASE;
+	int error;
 
 	if (i >= EVDEV_MINORS)
 		return -ENODEV;
@@ -146,8 +147,14 @@
 	client->evdev = evdev;
 	list_add_tail(&client->node, &evdev->client_list);
 
-	if (!evdev->open++ && evdev->exist)
-		input_open_device(&evdev->handle);
+	if (!evdev->open++ && evdev->exist) {
+		error = input_open_device(&evdev->handle);
+		if (error) {
+			list_del(&client->node);
+			kfree(client);
+			return error;
+		}
+	}
 
 	file->private_data = client;
 	return 0;
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 09b8223..4f37224 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -170,6 +170,7 @@
 	struct joydev_client *client;
 	struct joydev *joydev;
 	int i = iminor(inode) - JOYDEV_MINOR_BASE;
+	int error;
 
 	if (i >= JOYDEV_MINORS)
 		return -ENODEV;
@@ -185,8 +186,14 @@
 	client->joydev = joydev;
 	list_add_tail(&client->node, &joydev->client_list);
 
-	if (!joydev->open++ && joydev->exist)
-		input_open_device(&joydev->handle);
+	if (!joydev->open++ && joydev->exist) {
+		error = input_open_device(&joydev->handle);
+		if (error) {
+			list_del(&client->node);
+			kfree(client);
+			return error;
+		}
+	}
 
 	file->private_data = client;
 	return 0;
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index f6a6268..764970f 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -66,6 +66,9 @@
 	struct list_head client_list;
 	struct input_handle handle;
 
+	struct list_head mixdev_node;
+	int mixdev_open;
+
 	struct mousedev_hw_data packet;
 	unsigned int pkt_count;
 	int old_x[4], old_y[4];
@@ -111,6 +114,7 @@
 
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
+static LIST_HEAD(mousedev_mix_list);
 
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
@@ -364,18 +368,63 @@
 	kfree(mousedev);
 }
 
-static void mixdev_release(void)
+static int mixdev_add_device(struct mousedev *mousedev)
 {
-	struct input_handle *handle;
+	int error;
 
-	list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
-		struct mousedev *mousedev = handle->private;
+	if (mousedev_mix.open) {
+		error = input_open_device(&mousedev->handle);
+		if (error)
+			return error;
 
-		if (!mousedev->open) {
-			if (mousedev->exist)
-				input_close_device(&mousedev->handle);
-			else
-				mousedev_free(mousedev);
+		mousedev->open++;
+		mousedev->mixdev_open++;
+	}
+
+	list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
+
+	return 0;
+}
+
+static void mixdev_remove_device(struct mousedev *mousedev)
+{
+	if (mousedev->mixdev_open) {
+		mousedev->mixdev_open = 0;
+		if (!--mousedev->open && mousedev->exist)
+			input_close_device(&mousedev->handle);
+	}
+
+	list_del_init(&mousedev->mixdev_node);
+}
+
+static void mixdev_open_devices(void)
+{
+	struct mousedev *mousedev;
+
+	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+		if (mousedev->exist && !mousedev->open) {
+			if (input_open_device(&mousedev->handle))
+				continue;
+
+			mousedev->open++;
+			mousedev->mixdev_open++;
+		}
+	}
+}
+
+static void mixdev_close_devices(void)
+{
+	struct mousedev *mousedev, *next;
+
+	list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) {
+		if (mousedev->mixdev_open) {
+			mousedev->mixdev_open = 0;
+			if (!--mousedev->open) {
+				if (mousedev->exist)
+					input_close_device(&mousedev->handle);
+				else
+					mousedev_free(mousedev);
+			}
 		}
 	}
 }
@@ -392,23 +441,22 @@
 
 	if (!--mousedev->open) {
 		if (mousedev->minor == MOUSEDEV_MIX)
-			mixdev_release();
-		else if (!mousedev_mix.open) {
-			if (mousedev->exist)
-				input_close_device(&mousedev->handle);
-			else
-				mousedev_free(mousedev);
-		}
+			mixdev_close_devices();
+		else if (mousedev->exist)
+			input_close_device(&mousedev->handle);
+		else
+			mousedev_free(mousedev);
 	}
 
 	return 0;
 }
 
+
 static int mousedev_open(struct inode *inode, struct file *file)
 {
 	struct mousedev_client *client;
-	struct input_handle *handle;
 	struct mousedev *mousedev;
+	int error;
 	int i;
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
@@ -436,15 +484,16 @@
 	list_add_tail(&client->node, &mousedev->client_list);
 
 	if (!mousedev->open++) {
-		if (mousedev->minor == MOUSEDEV_MIX) {
-			list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
-				struct mousedev *md = handle->private;
-				if (!md->open && md->exist)
-					input_open_device(handle);
+		if (mousedev->minor == MOUSEDEV_MIX)
+			mixdev_open_devices();
+		else if (mousedev->exist) {
+			error = input_open_device(&mousedev->handle);
+			if (error) {
+				list_del(&client->node);
+				kfree(client);
+				return error;
 			}
-		} else
-			if (!mousedev_mix.open && mousedev->exist)
-				input_open_device(&mousedev->handle);
+		}
 	}
 
 	file->private_data = client;
@@ -683,11 +732,9 @@
 	if (error)
 		goto err_remove_link;
 
-	if (mousedev_mix.open) {
-		error = input_open_device(&mousedev->handle);
-		if (error)
-			goto err_unregister_handle;
-	}
+	error = mixdev_add_device(mousedev);
+	if (error)
+		goto err_unregister_handle;
 
 	return 0;
 
@@ -715,16 +762,15 @@
 			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
 	mousedev->exist = 0;
 
+	mixdev_remove_device(mousedev);
+
 	if (mousedev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&mousedev->wait);
 		list_for_each_entry(client, &mousedev->client_list, node)
 			kill_fasync(&client->fasync, SIGIO, POLL_HUP);
-	} else {
-		if (mousedev_mix.open)
-			input_close_device(handle);
+	} else
 		mousedev_free(mousedev);
-	}
 }
 
 static const struct input_device_id mousedev_ids[] = {
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index fbef35d..8e2d2c9 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -151,6 +151,7 @@
 	int i = iminor(inode) - TSDEV_MINOR_BASE;
 	struct tsdev_client *client;
 	struct tsdev *tsdev;
+	int error;
 
 	printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
 		"for removal.\nSee Documentation/feature-removal-schedule.txt "
@@ -171,8 +172,14 @@
 	client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
 	list_add_tail(&client->node, &tsdev->client_list);
 
-	if (!tsdev->open++ && tsdev->exist)
-		input_open_device(&tsdev->handle);
+	if (!tsdev->open++ && tsdev->exist) {
+		error = input_open_device(&tsdev->handle);
+		if (error) {
+			list_del(&client->node);
+			kfree(client);
+			return error;
+		}
+	}
 
 	file->private_data = client;
 	return 0;