Input: gpio_event: Allow multiple input devices per gpio_event device

This is needed to support devices that put non-keyboard buttons in
the keyboard matrix. For instance several devices put the trackball
button in the keyboard matrix. In this case BTN_MOUSE should be
reported from the same input device as REL_X/Y.

It is also useful for devices that have multiple logical keyboard in
the same matrix. The HTC dream has a menu key on the external keyboard
and another menu key on the slide-out keyboard. With a single input
device only one of these menu keys can be mapped to KEY_MENU.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
diff --git a/drivers/input/misc/gpio_axis.c b/drivers/input/misc/gpio_axis.c
index 6178220..0acf4a5 100644
--- a/drivers/input/misc/gpio_axis.c
+++ b/drivers/input/misc/gpio_axis.c
@@ -20,7 +20,7 @@
 #include <linux/slab.h>
 
 struct gpio_axis_state {
-	struct input_dev *input_dev;
+	struct gpio_event_input_devs *input_devs;
 	struct gpio_event_axis_info *info;
 	uint32_t pos;
 };
@@ -88,14 +88,16 @@
 			if (ai->flags & GPIOEAF_PRINT_EVENT)
 				pr_info("axis %d-%d change %d\n",
 					ai->type, ai->code, change);
-			input_report_rel(as->input_dev, ai->code, change);
+			input_report_rel(as->input_devs->dev[ai->dev],
+						ai->code, change);
 		} else {
 			if (ai->flags & GPIOEAF_PRINT_EVENT)
 				pr_info("axis %d-%d now %d\n",
 					ai->type, ai->code, pos);
-			input_event(as->input_dev, ai->type, ai->code, pos);
+			input_event(as->input_devs->dev[ai->dev],
+					ai->type, ai->code, pos);
 		}
-		input_sync(as->input_dev);
+		input_sync(as->input_devs->dev[ai->dev]);
 	}
 	as->pos = pos;
 }
@@ -107,7 +109,7 @@
 	return IRQ_HANDLED;
 }
 
-int gpio_event_axis_func(struct input_dev *input_dev,
+int gpio_event_axis_func(struct gpio_event_input_devs *input_devs,
 			 struct gpio_event_info *info, void **data, int func)
 {
 	int ret;
@@ -134,13 +136,21 @@
 			ret = -ENOMEM;
 			goto err_alloc_axis_state_failed;
 		}
-		as->input_dev = input_dev;
+		as->input_devs = input_devs;
 		as->info = ai;
+		if (ai->dev >= input_devs->count) {
+			pr_err("gpio_event_axis: bad device index %d >= %d "
+				"for %d:%d\n", ai->dev, input_devs->count,
+				ai->type, ai->code);
+			ret = -EINVAL;
+			goto err_bad_device_index;
+		}
 
-		input_set_capability(input_dev, ai->type, ai->code);
+		input_set_capability(input_devs->dev[ai->dev],
+				     ai->type, ai->code);
 		if (ai->type == EV_ABS) {
-			input_set_abs_params(input_dev, ai->code, 0,
-					     ai->decoded_size - 1, 0, 0);
+			input_set_abs_params(input_devs->dev[ai->dev], ai->code,
+					     0, ai->decoded_size - 1, 0, 0);
 		}
 		for (i = 0; i < ai->count; i++) {
 			ret = gpio_request(ai->gpio[i], "gpio_event_axis");
@@ -174,6 +184,7 @@
 err_request_gpio_failed:
 		;
 	}
+err_bad_device_index:
 	kfree(as);
 	*data = NULL;
 err_alloc_axis_state_failed:
diff --git a/drivers/input/misc/gpio_event.c b/drivers/input/misc/gpio_event.c
index 7be0cb5..15939e5 100644
--- a/drivers/input/misc/gpio_event.c
+++ b/drivers/input/misc/gpio_event.c
@@ -22,7 +22,7 @@
 #include <linux/slab.h>
 
 struct gpio_event {
-	struct input_dev *input_dev;
+	struct gpio_event_input_devs *input_devs;
 	const struct gpio_event_platform_data *info;
 	struct early_suspend early_suspend;
 	void *state[0];
@@ -32,15 +32,25 @@
 	struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	int i;
+	int devnr;
 	int ret = 0;
 	int tmp_ret;
 	struct gpio_event_info **ii;
 	struct gpio_event *ip = input_get_drvdata(dev);
 
+	for (devnr = 0; devnr < ip->input_devs->count; devnr++)
+		if (ip->input_devs->dev[devnr] == dev)
+			break;
+	if (devnr == ip->input_devs->count) {
+		pr_err("gpio_input_event: unknown device %p\n", dev);
+		return -EIO;
+	}
+
 	for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) {
 		if ((*ii)->event) {
-			tmp_ret = (*ii)->event(ip->input_dev, *ii,
-					&ip->state[i], type, code, value);
+			tmp_ret = (*ii)->event(ip->input_devs, *ii,
+						&ip->state[i],
+						devnr, type, code, value);
 			if (tmp_ret)
 				ret = tmp_ret;
 		}
@@ -63,7 +73,9 @@
 					"no function\n");
 				goto err_no_func;
 			}
-			ret = (*ii)->func(ip->input_dev, *ii, &ip->state[i],
+			if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend)
+				continue;
+			ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i],
 					  func);
 			if (ret) {
 				pr_err("gpio_event_probe: function failed\n");
@@ -79,7 +91,9 @@
 	while (i > 0) {
 		i--;
 		ii--;
-		(*ii)->func(ip->input_dev, *ii, &ip->state[i], func & ~1);
+		if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend)
+			continue;
+		(*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1);
 err_func_failed:
 err_no_func:
 		;
@@ -109,37 +123,51 @@
 {
 	int err;
 	struct gpio_event *ip;
-	struct input_dev *input_dev;
 	struct gpio_event_platform_data *event_info;
+	int dev_count = 1;
+	int i;
+	int registered = 0;
 
 	event_info = pdev->dev.platform_data;
 	if (event_info == NULL) {
 		pr_err("gpio_event_probe: No pdata\n");
 		return -ENODEV;
 	}
-	if (event_info->name == NULL ||
-	   event_info->info == NULL ||
-	   event_info->info_count == 0) {
+	if ((!event_info->name && !event_info->names[0]) ||
+	    !event_info->info || !event_info->info_count) {
 		pr_err("gpio_event_probe: Incomplete pdata\n");
 		return -ENODEV;
 	}
+	if (!event_info->name)
+		while (event_info->names[dev_count])
+			dev_count++;
 	ip = kzalloc(sizeof(*ip) +
-		     sizeof(ip->state[0]) * event_info->info_count, GFP_KERNEL);
+		     sizeof(ip->state[0]) * event_info->info_count +
+		     sizeof(*ip->input_devs) +
+		     sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL);
 	if (ip == NULL) {
 		err = -ENOMEM;
 		pr_err("gpio_event_probe: Failed to allocate private data\n");
 		goto err_kp_alloc_failed;
 	}
+	ip->input_devs = (void*)&ip->state[event_info->info_count];
 	platform_set_drvdata(pdev, ip);
 
-	input_dev = input_allocate_device();
-	if (input_dev == NULL) {
-		err = -ENOMEM;
-		pr_err("gpio_event_probe: Failed to allocate input device\n");
-		goto err_input_dev_alloc_failed;
+	for (i = 0; i < dev_count; i++) {
+		struct input_dev *input_dev = input_allocate_device();
+		if (input_dev == NULL) {
+			err = -ENOMEM;
+			pr_err("gpio_event_probe: "
+				"Failed to allocate input device\n");
+			goto err_input_dev_alloc_failed;
+		}
+		input_set_drvdata(input_dev, ip);
+		input_dev->name = event_info->name ?
+					event_info->name : event_info->names[i];
+		input_dev->event = gpio_input_event;
+		ip->input_devs->dev[i] = input_dev;
 	}
-	input_set_drvdata(input_dev, ip);
-	ip->input_dev = input_dev;
+	ip->input_devs->count = dev_count;
 	ip->info = event_info;
 	if (event_info->power) {
 #ifdef CONFIG_HAS_EARLYSUSPEND
@@ -151,18 +179,18 @@
 		ip->info->power(ip->info, 1);
 	}
 
-	input_dev->name = ip->info->name;
-	input_dev->event = gpio_input_event;
-
 	err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);
 	if (err)
 		goto err_call_all_func_failed;
 
-	err = input_register_device(input_dev);
-	if (err) {
-		pr_err("gpio_event_probe: Unable to register %s input device\n",
-			input_dev->name);
-		goto err_input_register_device_failed;
+	for (i = 0; i < dev_count; i++) {
+		err = input_register_device(ip->input_devs->dev[i]);
+		if (err) {
+			pr_err("gpio_event_probe: Unable to register %s "
+				"input device\n", ip->input_devs->dev[i]->name);
+			goto err_input_register_device_failed;
+		}
+		registered++;
 	}
 
 	return 0;
@@ -176,8 +204,13 @@
 #endif
 		ip->info->power(ip->info, 0);
 	}
-	input_free_device(input_dev);
+	for (i = 0; i < registered; i++)
+		input_unregister_device(ip->input_devs->dev[i]);
+	for (i = dev_count - 1; i >= registered; i--) {
+		input_free_device(ip->input_devs->dev[i]);
 err_input_dev_alloc_failed:
+		;
+	}
 	kfree(ip);
 err_kp_alloc_failed:
 	return err;
@@ -186,6 +219,7 @@
 static int gpio_event_remove(struct platform_device *pdev)
 {
 	struct gpio_event *ip = platform_get_drvdata(pdev);
+	int i;
 
 	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
 	if (ip->info->power) {
@@ -194,7 +228,8 @@
 #endif
 		ip->info->power(ip->info, 0);
 	}
-	input_unregister_device(ip->input_dev);
+	for (i = 0; i < ip->input_devs->count; i++)
+		input_unregister_device(ip->input_devs->dev[i]);
 	kfree(ip);
 	return 0;
 }
diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c
index 15c89ec..6aef289 100644
--- a/drivers/input/misc/gpio_input.c
+++ b/drivers/input/misc/gpio_input.c
@@ -39,7 +39,7 @@
 };
 
 struct gpio_input_state {
-	struct input_dev *input_dev;
+	struct gpio_event_input_devs *input_devs;
 	const struct gpio_event_input_info *info;
 	struct hrtimer timer;
 	int use_irq;
@@ -127,7 +127,7 @@
 			pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) "
 				"changed to %d\n", ds->info->type,
 				key_entry->code, i, key_entry->gpio, pressed);
-		input_event(ds->input_dev, ds->info->type,
+		input_event(ds->input_devs->dev[key_entry->dev], ds->info->type,
 			    key_entry->code, pressed);
 	}
 
@@ -194,7 +194,7 @@
 				"(%d) changed to %d\n",
 				ds->info->type, key_entry->code, keymap_index,
 				key_entry->gpio, pressed);
-		input_event(ds->input_dev, ds->info->type,
+		input_event(ds->input_devs->dev[key_entry->dev], ds->info->type,
 			    key_entry->code, pressed);
 	}
 	return IRQ_HANDLED;
@@ -233,7 +233,7 @@
 	return err;
 }
 
-int gpio_event_input_func(struct input_dev *input_dev,
+int gpio_event_input_func(struct gpio_event_input_devs *input_devs,
 			struct gpio_event_info *info, void **data, int func)
 {
 	int ret;
@@ -276,13 +276,22 @@
 			goto err_ds_alloc_failed;
 		}
 		ds->debounce_count = di->keymap_size;
-		ds->input_dev = input_dev;
+		ds->input_devs = input_devs;
 		ds->info = di;
 		wake_lock_init(&ds->wake_lock, WAKE_LOCK_SUSPEND, "gpio_input");
 		spin_lock_init(&ds->irq_lock);
 
 		for (i = 0; i < di->keymap_size; i++) {
-			input_set_capability(input_dev, di->type,
+			int dev = di->keymap[i].dev;
+			if (dev >= input_devs->count) {
+				pr_err("gpio_event_input_func: bad device "
+					"index %d >= %d for key code %d\n",
+					dev, input_devs->count,
+					di->keymap[i].code);
+				ret = -EINVAL;
+				goto err_bad_keymap;
+			}
+			input_set_capability(input_devs->dev[dev], di->type,
 					     di->keymap[i].code);
 			ds->key_state[i].ds = ds;
 			ds->key_state[i].debounce = DEBOUNCE_UNKNOWN;
@@ -309,9 +318,10 @@
 		spin_lock_irqsave(&ds->irq_lock, irqflags);
 		ds->use_irq = ret == 0;
 
-		pr_info("GPIO Input Driver: Start gpio inputs for %s in %s "
-			"mode\n",
-			input_dev->name, ret == 0 ? "interrupt" : "polling");
+		pr_info("GPIO Input Driver: Start gpio inputs for %s%s in %s "
+			"mode\n", input_devs->dev[0]->name,
+			(input_devs->count > 1) ? "..." : "",
+			ret == 0 ? "interrupt" : "polling");
 
 		hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 		ds->timer.function = gpio_event_input_timer_func;
@@ -337,6 +347,7 @@
 err_gpio_request_failed:
 		;
 	}
+err_bad_keymap:
 	wake_lock_destroy(&ds->wake_lock);
 	kfree(ds);
 err_ds_alloc_failed:
diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c
index 10b4411..adb00ab 100644
--- a/drivers/input/misc/gpio_matrix.c
+++ b/drivers/input/misc/gpio_matrix.c
@@ -22,7 +22,7 @@
 #include <linux/wakelock.h>
 
 struct gpio_kp {
-	struct input_dev *input_dev;
+	struct gpio_event_input_devs *input_devs;
 	struct gpio_event_matrix_info *keypad_info;
 	struct hrtimer timer;
 	struct wake_lock wake_lock;
@@ -38,9 +38,11 @@
 {
 	struct gpio_event_matrix_info *mi = kp->keypad_info;
 	int key_index = out * mi->ninputs + in;
-	unsigned short keycode = mi->keymap[key_index];;
+	unsigned short keyentry = mi->keymap[key_index];
+	unsigned short keycode = keyentry & MATRIX_KEY_MASK;
+	unsigned short dev = keyentry >> MATRIX_CODE_BITS;
 
-	if (!test_bit(keycode, kp->input_dev->key)) {
+	if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) {
 		if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
 			pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
 				"cleared\n", keycode, out, in,
@@ -105,8 +107,11 @@
 {
 	struct gpio_event_matrix_info *mi = kp->keypad_info;
 	int pressed = test_bit(key_index, kp->keys_pressed);
-	unsigned short keycode = mi->keymap[key_index];
-	if (pressed != test_bit(keycode, kp->input_dev->key)) {
+	unsigned short keyentry = mi->keymap[key_index];
+	unsigned short keycode = keyentry & MATRIX_KEY_MASK;
+	unsigned short dev = keyentry >> MATRIX_CODE_BITS;
+
+	if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) {
 		if (keycode == KEY_RESERVED) {
 			if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS)
 				pr_info("gpiomatrix: unmapped key, %d-%d "
@@ -119,7 +124,7 @@
 					"changed to %d\n", keycode,
 					out, in, mi->output_gpios[out],
 					mi->input_gpios[in], pressed);
-			input_report_key(kp->input_dev, keycode, pressed);
+			input_report_key(kp->input_devs->dev[dev], keycode, pressed);
 		}
 	}
 }
@@ -280,7 +285,7 @@
 	return err;
 }
 
-int gpio_event_matrix_func(struct input_dev *input_dev,
+int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs,
 	struct gpio_event_info *info, void **data, int func)
 {
 	int i;
@@ -312,12 +317,22 @@
 			pr_err("gpiomatrix: Failed to allocate private data\n");
 			goto err_kp_alloc_failed;
 		}
-		kp->input_dev = input_dev;
+		kp->input_devs = input_devs;
 		kp->keypad_info = mi;
-		set_bit(EV_KEY, input_dev->evbit);
 		for (i = 0; i < key_count; i++) {
-			if (mi->keymap[i] && mi->keymap[i] <= KEY_MAX)
-				set_bit(mi->keymap[i], input_dev->keybit);
+			unsigned short keyentry = mi->keymap[i];
+			unsigned short keycode = keyentry & MATRIX_KEY_MASK;
+			unsigned short dev = keyentry >> MATRIX_CODE_BITS;
+			if (dev >= input_devs->count) {
+				pr_err("gpiomatrix: bad device index %d >= "
+					"%d for key code %d\n",
+					dev, input_devs->count, keycode);
+				err = -EINVAL;
+				goto err_bad_keymap;
+			}
+			if (keycode && keycode <= KEY_MAX)
+				input_set_capability(input_devs->dev[dev],
+							EV_KEY, keycode);
 		}
 
 		for (i = 0; i < mi->noutputs; i++) {
@@ -367,8 +382,9 @@
 		err = gpio_keypad_request_irqs(kp);
 		kp->use_irq = err == 0;
 
-		pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for %s "
-			"in %s mode\n", input_dev->name,
+		pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for "
+			"%s%s in %s mode\n", input_devs->dev[0]->name,
+			(input_devs->count > 1) ? "..." : "",
 			kp->use_irq ? "interrupt" : "polling");
 
 		if (kp->use_irq)
@@ -399,6 +415,7 @@
 err_request_output_gpio_failed:
 		;
 	}
+err_bad_keymap:
 	kfree(kp);
 err_kp_alloc_failed:
 err_invalid_platform_data:
diff --git a/drivers/input/misc/gpio_output.c b/drivers/input/misc/gpio_output.c
index 6f8453c..2aac2fa 100644
--- a/drivers/input/misc/gpio_output.c
+++ b/drivers/input/misc/gpio_output.c
@@ -18,8 +18,9 @@
 #include <linux/gpio_event.h>
 
 int gpio_event_output_event(
-	struct input_dev *input_dev, struct gpio_event_info *info, void **data,
-	unsigned int type, unsigned int code, int value)
+	struct gpio_event_input_devs *input_devs, struct gpio_event_info *info,
+	void **data, unsigned int dev, unsigned int type,
+	unsigned int code, int value)
 {
 	int i;
 	struct gpio_event_output_info *oi;
@@ -29,14 +30,14 @@
 	if (!(oi->flags & GPIOEDF_ACTIVE_HIGH))
 		value = !value;
 	for (i = 0; i < oi->keymap_size; i++)
-		if (code == oi->keymap[i].code)
+		if (dev == oi->keymap[i].dev && code == oi->keymap[i].code)
 			gpio_set_value(oi->keymap[i].gpio, value);
 	return 0;
 }
 
 int gpio_event_output_func(
-	struct input_dev *input_dev, struct gpio_event_info *info, void **data,
-	int func)
+	struct gpio_event_input_devs *input_devs, struct gpio_event_info *info,
+	void **data, int func)
 {
 	int ret;
 	int i;
@@ -48,9 +49,20 @@
 
 	if (func == GPIO_EVENT_FUNC_INIT) {
 		int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH);
-		for (i = 0; i < oi->keymap_size; i++)
-			input_set_capability(input_dev, oi->type,
+
+		for (i = 0; i < oi->keymap_size; i++) {
+			int dev = oi->keymap[i].dev;
+			if (dev >= input_devs->count) {
+				pr_err("gpio_event_output_func: bad device "
+					"index %d >= %d for key code %d\n",
+					dev, input_devs->count,
+					oi->keymap[i].code);
+				ret = -EINVAL;
+				goto err_bad_keymap;
+			}
+			input_set_capability(input_devs->dev[dev], oi->type,
 					     oi->keymap[i].code);
+		}
 
 		for (i = 0; i < oi->keymap_size; i++) {
 			ret = gpio_request(oi->keymap[i].gpio,
@@ -79,6 +91,7 @@
 err_gpio_request_failed:
 		;
 	}
+err_bad_keymap:
 	return ret;
 }