Input: gpio_event: Allow multiple input devices per gpio_event device
authorArve Hjønnevåg <arve@android.com>
Fri, 24 Jul 2009 22:19:56 +0000 (15:19 -0700)
committerColin Cross <ccross@android.com>
Tue, 14 Jun 2011 16:08:48 +0000 (09:08 -0700)
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>
drivers/input/misc/gpio_axis.c
drivers/input/misc/gpio_event.c
drivers/input/misc/gpio_input.c
drivers/input/misc/gpio_matrix.c
drivers/input/misc/gpio_output.c
include/linux/gpio_event.h

index 61782207bce18cc163975cd25a1a4228f051bda8..0acf4a576f53a2df35c0574dfda4019d6ebaa2e1 100644 (file)
@@ -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 @@ static void gpio_event_update_axis(struct gpio_axis_state *as, int report)
                        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 @@ static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id)
        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 @@ int gpio_event_axis_func(struct input_dev *input_dev,
                        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_gpio_direction_input_failed:
 err_request_gpio_failed:
                ;
        }
+err_bad_device_index:
        kfree(as);
        *data = NULL;
 err_alloc_axis_state_failed:
index 7be0cb5214bbc03b43d960f221d54c074abab468..15939e5e23039bbacf3e389ec959cfd8b133a58e 100644 (file)
@@ -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 @@ static int gpio_input_event(
        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 @@ static int gpio_event_call_all_func(struct gpio_event *ip, int func)
                                        "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 @@ static int gpio_event_call_all_func(struct gpio_event *ip, int func)
        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 @@ static int __init gpio_event_probe(struct platform_device *pdev)
 {
        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 @@ static int __init gpio_event_probe(struct platform_device *pdev)
                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 @@ err_call_all_func_failed:
 #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 @@ err_kp_alloc_failed:
 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 @@ static int gpio_event_remove(struct platform_device *pdev)
 #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;
 }
index 15c89ec5083be48ff5840b03483fe0aa007ef7ff..6aef289e6e146cd6b7edac173e2a17b02283fdee 100644 (file)
@@ -39,7 +39,7 @@ struct gpio_key_state {
 };
 
 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 @@ static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer)
                        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 @@ static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id)
                                "(%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 @@ err_gpio_get_irq_num_failed:
        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 @@ int gpio_event_input_func(struct input_dev *input_dev,
                        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 @@ int gpio_event_input_func(struct input_dev *input_dev,
                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_configure_failed:
 err_gpio_request_failed:
                ;
        }
+err_bad_keymap:
        wake_lock_destroy(&ds->wake_lock);
        kfree(ds);
 err_ds_alloc_failed:
index 10b441101668a94b95ead237eaecfb5aecc6c902..adb00ab47b6bf97af42deb167cd7e15e1287b054 100644 (file)
@@ -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 @@ static void clear_phantom_key(struct gpio_kp *kp, int out, int in)
 {
        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 @@ static void report_key(struct gpio_kp *kp, int key_index, int out, int in)
 {
        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 @@ static void report_key(struct gpio_kp *kp, int key_index, int out, int in)
                                        "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 @@ err_gpio_get_irq_num_failed:
        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 @@ int gpio_event_matrix_func(struct input_dev *input_dev,
                        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 @@ int gpio_event_matrix_func(struct input_dev *input_dev,
                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_output_gpio_configure_failed:
 err_request_output_gpio_failed:
                ;
        }
+err_bad_keymap:
        kfree(kp);
 err_kp_alloc_failed:
 err_invalid_platform_data:
index 6f8453c97bd2f4838317b70523bd00b9699475c9..2aac2fad0a17bff7773bb68d9a04f726f180db5a 100644 (file)
@@ -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 @@ int gpio_event_output_event(
        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 @@ int gpio_event_output_func(
 
        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_direction_output_failed:
 err_gpio_request_failed:
                ;
        }
+err_bad_keymap:
        return ret;
 }
 
index 5ff828bcb6bc7301cf63137daf5dd63c36201dfe..360b4ddb46a6b8a4010754ed6f4edb102b9015a5 100644 (file)
 
 #include <linux/input.h>
 
+struct gpio_event_input_devs {
+       int count;
+       struct input_dev *dev[];
+};
 enum {
        GPIO_EVENT_FUNC_UNINIT  = 0x0,
        GPIO_EVENT_FUNC_INIT    = 0x1,
@@ -25,13 +29,14 @@ enum {
        GPIO_EVENT_FUNC_RESUME  = 0x3,
 };
 struct gpio_event_info {
-       int (*func)(struct input_dev *input_dev,
+       int (*func)(struct gpio_event_input_devs *input_devs,
                    struct gpio_event_info *info,
                    void **data, int func);
-       int (*event)(struct input_dev *input_dev,
+       int (*event)(struct gpio_event_input_devs *input_devs,
                     struct gpio_event_info *info,
-                    void **data, unsigned int type,
+                    void **data, unsigned int dev, unsigned int type,
                     unsigned int code, int value); /* out events */
+       bool no_suspend;
 };
 
 struct gpio_event_platform_data {
@@ -39,6 +44,8 @@ struct gpio_event_platform_data {
        struct gpio_event_info **info;
        size_t info_count;
        int (*power)(const struct gpio_event_platform_data *pdata, bool on);
+       const char *names[]; /* If name is NULL, names contain a NULL */
+                            /* terminated list of input devices to create */
 };
 
 #define GPIO_EVENT_DEV_NAME "gpio-event"
@@ -59,7 +66,12 @@ enum gpio_event_matrix_flags {
        GPIOKPF_PRINT_PHANTOM_KEYS       = 1U << 18,
 };
 
-extern int gpio_event_matrix_func(struct input_dev *input_dev,
+#define MATRIX_CODE_BITS (10)
+#define MATRIX_KEY_MASK ((1U << MATRIX_CODE_BITS) - 1)
+#define MATRIX_KEY(dev, code) \
+       (((dev) << MATRIX_CODE_BITS) | (code & MATRIX_KEY_MASK))
+
+extern int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs,
                        struct gpio_event_info *info, void **data, int func);
 struct gpio_event_matrix_info {
        /* initialize to gpio_event_matrix_func */
@@ -89,12 +101,13 @@ enum gpio_event_direct_flags {
 };
 
 struct gpio_event_direct_entry {
-       uint32_t gpio:23;
-       uint32_t code:9;
+       uint32_t gpio:16;
+       uint32_t code:10;
+       uint32_t dev:6;
 };
 
 /* inputs */
-extern int gpio_event_input_func(struct input_dev *input_dev,
+extern int gpio_event_input_func(struct gpio_event_input_devs *input_devs,
                        struct gpio_event_info *info, void **data, int func);
 struct gpio_event_input_info {
        /* initialize to gpio_event_input_func */
@@ -108,11 +121,12 @@ struct gpio_event_input_info {
 };
 
 /* outputs */
-extern int gpio_event_output_func(struct input_dev *input_dev,
+extern int gpio_event_output_func(struct gpio_event_input_devs *input_devs,
                        struct gpio_event_info *info, void **data, int func);
-extern int gpio_event_output_event(struct input_dev *input_dev,
+extern int gpio_event_output_event(struct gpio_event_input_devs *input_devs,
                        struct gpio_event_info *info, void **data,
-                       unsigned int type, unsigned int code, int value);
+                       unsigned int dev, unsigned int type,
+                       unsigned int code, int value);
 struct gpio_event_output_info {
        /* initialize to gpio_event_output_func and gpio_event_output_event */
        struct gpio_event_info info;
@@ -131,12 +145,13 @@ enum gpio_event_axis_flags {
        GPIOEAF_PRINT_EVENT              = 1U << 18,
 };
 
-extern int gpio_event_axis_func(struct input_dev *input_dev,
+extern int gpio_event_axis_func(struct gpio_event_input_devs *input_devs,
                        struct gpio_event_info *info, void **data, int func);
 struct gpio_event_axis_info {
        /* initialize to gpio_event_axis_func */
        struct gpio_event_info info;
-       uint8_t  count;
+       uint8_t  count; /* number of gpios for this axis */
+       uint8_t  dev; /* device index when using multiple input devices */
        uint8_t  type; /* EV_REL or EV_ABS */
        uint16_t code;
        uint16_t decoded_size;