diff options
Diffstat (limited to 'drivers/input/sparse-keymap.c')
| -rw-r--r-- | drivers/input/sparse-keymap.c | 99 |
1 files changed, 82 insertions, 17 deletions
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 01424834476..e7409c45bdd 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -15,6 +15,7 @@ #include <linux/input.h> #include <linux/input/sparse-keymap.h> +#include <linux/module.h> #include <linux/slab.h> MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); @@ -22,6 +23,37 @@ MODULE_DESCRIPTION("Generic support for sparse keymaps"); MODULE_LICENSE("GPL v2"); MODULE_VERSION("0.1"); +static unsigned int sparse_keymap_get_key_index(struct input_dev *dev, + const struct key_entry *k) +{ + struct key_entry *key; + unsigned int idx = 0; + + for (key = dev->keycode; key->type != KE_END; key++) { + if (key->type == KE_KEY) { + if (key == k) + break; + idx++; + } + } + + return idx; +} + +static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev, + unsigned int index) +{ + struct key_entry *key; + unsigned int key_cnt = 0; + + for (key = dev->keycode; key->type != KE_END; key++) + if (key->type == KE_KEY) + if (key_cnt++ == index) + return key; + + return NULL; +} + /** * sparse_keymap_entry_from_scancode - perform sparse keymap lookup * @dev: Input device using sparse keymap @@ -64,16 +96,36 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, } EXPORT_SYMBOL(sparse_keymap_entry_from_keycode); +static struct key_entry *sparse_keymap_locate(struct input_dev *dev, + const struct input_keymap_entry *ke) +{ + struct key_entry *key; + unsigned int scancode; + + if (ke->flags & INPUT_KEYMAP_BY_INDEX) + key = sparse_keymap_entry_by_index(dev, ke->index); + else if (input_scancode_to_scalar(ke, &scancode) == 0) + key = sparse_keymap_entry_from_scancode(dev, scancode); + else + key = NULL; + + return key; +} + static int sparse_keymap_getkeycode(struct input_dev *dev, - unsigned int scancode, - unsigned int *keycode) + struct input_keymap_entry *ke) { const struct key_entry *key; if (dev->keycode) { - key = sparse_keymap_entry_from_scancode(dev, scancode); + key = sparse_keymap_locate(dev, ke); if (key && key->type == KE_KEY) { - *keycode = key->keycode; + ke->keycode = key->keycode; + if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) + ke->index = + sparse_keymap_get_key_index(dev, key); + ke->len = sizeof(key->code); + memcpy(ke->scancode, &key->code, sizeof(key->code)); return 0; } } @@ -82,20 +134,19 @@ static int sparse_keymap_getkeycode(struct input_dev *dev, } static int sparse_keymap_setkeycode(struct input_dev *dev, - unsigned int scancode, - unsigned int keycode) + const struct input_keymap_entry *ke, + unsigned int *old_keycode) { struct key_entry *key; - int old_keycode; if (dev->keycode) { - key = sparse_keymap_entry_from_scancode(dev, scancode); + key = sparse_keymap_locate(dev, ke); if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!sparse_keymap_entry_from_keycode(dev, old_keycode)) - clear_bit(old_keycode, dev->keybit); + *old_keycode = key->keycode; + key->keycode = ke->keycode; + set_bit(ke->keycode, dev->keybit); + if (!sparse_keymap_entry_from_keycode(dev, *old_keycode)) + clear_bit(*old_keycode, dev->keybit); return 0; } } @@ -129,11 +180,11 @@ int sparse_keymap_setup(struct input_dev *dev, for (e = keymap; e->type != KE_END; e++) map_size++; - map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL); + map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL); if (!map) return -ENOMEM; - memcpy(map, keymap, map_size * sizeof (struct key_entry)); + memcpy(map, keymap, map_size * sizeof(struct key_entry)); for (i = 0; i < map_size; i++) { entry = &map[i]; @@ -151,12 +202,19 @@ int sparse_keymap_setup(struct input_dev *dev, break; case KE_SW: + case KE_VSW: __set_bit(EV_SW, dev->evbit); __set_bit(entry->sw.code, dev->swbit); break; } } + if (test_bit(EV_KEY, dev->evbit)) { + __set_bit(KEY_UNKNOWN, dev->keybit); + __set_bit(EV_MSC, dev->evbit); + __set_bit(MSC_SCAN, dev->mscbit); + } + dev->keycode = map; dev->keycodemax = map_size; dev->getkeycode = sparse_keymap_getkeycode; @@ -167,7 +225,6 @@ int sparse_keymap_setup(struct input_dev *dev, err_out: kfree(map); return error; - } EXPORT_SYMBOL(sparse_keymap_setup); @@ -179,7 +236,7 @@ EXPORT_SYMBOL(sparse_keymap_setup); * in an input device that was set up by sparse_keymap_setup(). * NOTE: It is safe to cal this function while input device is * still registered (however the drivers should care not to try to - * use freed keymap and thus have to shut off interrups/polling + * use freed keymap and thus have to shut off interrupts/polling * before freeing the keymap). */ void sparse_keymap_free(struct input_dev *dev) @@ -218,6 +275,7 @@ void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *k { switch (ke->type) { case KE_KEY: + input_event(dev, EV_MSC, MSC_SCAN, ke->code); input_report_key(dev, ke->keycode, value); input_sync(dev); if (value && autorelease) { @@ -255,12 +313,19 @@ bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, { const struct key_entry *ke = sparse_keymap_entry_from_scancode(dev, code); + struct key_entry unknown_ke; if (ke) { sparse_keymap_report_entry(dev, ke, value, autorelease); return true; } + /* Report an unknown key event as a debugging aid */ + unknown_ke.type = KE_KEY; + unknown_ke.code = code; + unknown_ke.keycode = KEY_UNKNOWN; + sparse_keymap_report_entry(dev, &unknown_ke, value, true); + return false; } EXPORT_SYMBOL(sparse_keymap_report_event); |
