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_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: