1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
236203c4fSDmitry Torokhov /*
336203c4fSDmitry Torokhov * Generic support for sparse keymaps
436203c4fSDmitry Torokhov *
536203c4fSDmitry Torokhov * Copyright (c) 2009 Dmitry Torokhov
636203c4fSDmitry Torokhov *
736203c4fSDmitry Torokhov * Derived from wistron button driver:
836203c4fSDmitry Torokhov * Copyright (C) 2005 Miloslav Trmac <[email protected]>
936203c4fSDmitry Torokhov * Copyright (C) 2005 Bernhard Rosenkraenzer <[email protected]>
1036203c4fSDmitry Torokhov * Copyright (C) 2005 Dmitry Torokhov <[email protected]>
1136203c4fSDmitry Torokhov */
1236203c4fSDmitry Torokhov
1336203c4fSDmitry Torokhov #include <linux/input.h>
1436203c4fSDmitry Torokhov #include <linux/input/sparse-keymap.h>
15d2d8442dSPaul Gortmaker #include <linux/module.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
1736203c4fSDmitry Torokhov
1836203c4fSDmitry Torokhov MODULE_AUTHOR("Dmitry Torokhov <[email protected]>");
1936203c4fSDmitry Torokhov MODULE_DESCRIPTION("Generic support for sparse keymaps");
2036203c4fSDmitry Torokhov MODULE_LICENSE("GPL v2");
2136203c4fSDmitry Torokhov
sparse_keymap_get_key_index(struct input_dev * dev,const struct key_entry * k)2267127f30SDmitry Torokhov static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
2367127f30SDmitry Torokhov const struct key_entry *k)
2467127f30SDmitry Torokhov {
2567127f30SDmitry Torokhov struct key_entry *key;
2667127f30SDmitry Torokhov unsigned int idx = 0;
2767127f30SDmitry Torokhov
2867127f30SDmitry Torokhov for (key = dev->keycode; key->type != KE_END; key++) {
2967127f30SDmitry Torokhov if (key->type == KE_KEY) {
3067127f30SDmitry Torokhov if (key == k)
3167127f30SDmitry Torokhov break;
3267127f30SDmitry Torokhov idx++;
3367127f30SDmitry Torokhov }
3467127f30SDmitry Torokhov }
3567127f30SDmitry Torokhov
3667127f30SDmitry Torokhov return idx;
3767127f30SDmitry Torokhov }
3867127f30SDmitry Torokhov
sparse_keymap_entry_by_index(struct input_dev * dev,unsigned int index)3967127f30SDmitry Torokhov static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
4067127f30SDmitry Torokhov unsigned int index)
4167127f30SDmitry Torokhov {
4267127f30SDmitry Torokhov struct key_entry *key;
4367127f30SDmitry Torokhov unsigned int key_cnt = 0;
4467127f30SDmitry Torokhov
4567127f30SDmitry Torokhov for (key = dev->keycode; key->type != KE_END; key++)
4667127f30SDmitry Torokhov if (key->type == KE_KEY)
4767127f30SDmitry Torokhov if (key_cnt++ == index)
4867127f30SDmitry Torokhov return key;
4967127f30SDmitry Torokhov
5067127f30SDmitry Torokhov return NULL;
5167127f30SDmitry Torokhov }
5267127f30SDmitry Torokhov
5336203c4fSDmitry Torokhov /**
5436203c4fSDmitry Torokhov * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
5536203c4fSDmitry Torokhov * @dev: Input device using sparse keymap
5636203c4fSDmitry Torokhov * @code: Scan code
5736203c4fSDmitry Torokhov *
5836203c4fSDmitry Torokhov * This function is used to perform &struct key_entry lookup in an
5936203c4fSDmitry Torokhov * input device using sparse keymap.
6036203c4fSDmitry Torokhov */
sparse_keymap_entry_from_scancode(struct input_dev * dev,unsigned int code)6136203c4fSDmitry Torokhov struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
6236203c4fSDmitry Torokhov unsigned int code)
6336203c4fSDmitry Torokhov {
6436203c4fSDmitry Torokhov struct key_entry *key;
6536203c4fSDmitry Torokhov
6636203c4fSDmitry Torokhov for (key = dev->keycode; key->type != KE_END; key++)
6736203c4fSDmitry Torokhov if (code == key->code)
6836203c4fSDmitry Torokhov return key;
6936203c4fSDmitry Torokhov
7036203c4fSDmitry Torokhov return NULL;
7136203c4fSDmitry Torokhov }
7236203c4fSDmitry Torokhov EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
7336203c4fSDmitry Torokhov
7436203c4fSDmitry Torokhov /**
7536203c4fSDmitry Torokhov * sparse_keymap_entry_from_keycode - perform sparse keymap lookup
7636203c4fSDmitry Torokhov * @dev: Input device using sparse keymap
7736203c4fSDmitry Torokhov * @keycode: Key code
7836203c4fSDmitry Torokhov *
7936203c4fSDmitry Torokhov * This function is used to perform &struct key_entry lookup in an
8036203c4fSDmitry Torokhov * input device using sparse keymap.
8136203c4fSDmitry Torokhov */
sparse_keymap_entry_from_keycode(struct input_dev * dev,unsigned int keycode)8236203c4fSDmitry Torokhov struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
8336203c4fSDmitry Torokhov unsigned int keycode)
8436203c4fSDmitry Torokhov {
8536203c4fSDmitry Torokhov struct key_entry *key;
8636203c4fSDmitry Torokhov
8736203c4fSDmitry Torokhov for (key = dev->keycode; key->type != KE_END; key++)
8836203c4fSDmitry Torokhov if (key->type == KE_KEY && keycode == key->keycode)
8936203c4fSDmitry Torokhov return key;
9036203c4fSDmitry Torokhov
9136203c4fSDmitry Torokhov return NULL;
9236203c4fSDmitry Torokhov }
9336203c4fSDmitry Torokhov EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
9436203c4fSDmitry Torokhov
sparse_keymap_locate(struct input_dev * dev,const struct input_keymap_entry * ke)9567127f30SDmitry Torokhov static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
9667127f30SDmitry Torokhov const struct input_keymap_entry *ke)
9767127f30SDmitry Torokhov {
9867127f30SDmitry Torokhov struct key_entry *key;
9967127f30SDmitry Torokhov unsigned int scancode;
10067127f30SDmitry Torokhov
10167127f30SDmitry Torokhov if (ke->flags & INPUT_KEYMAP_BY_INDEX)
10267127f30SDmitry Torokhov key = sparse_keymap_entry_by_index(dev, ke->index);
10367127f30SDmitry Torokhov else if (input_scancode_to_scalar(ke, &scancode) == 0)
10467127f30SDmitry Torokhov key = sparse_keymap_entry_from_scancode(dev, scancode);
10567127f30SDmitry Torokhov else
10667127f30SDmitry Torokhov key = NULL;
10767127f30SDmitry Torokhov
10867127f30SDmitry Torokhov return key;
10967127f30SDmitry Torokhov }
11067127f30SDmitry Torokhov
sparse_keymap_getkeycode(struct input_dev * dev,struct input_keymap_entry * ke)11136203c4fSDmitry Torokhov static int sparse_keymap_getkeycode(struct input_dev *dev,
11267127f30SDmitry Torokhov struct input_keymap_entry *ke)
11336203c4fSDmitry Torokhov {
1142e2e3b96SDmitry Torokhov const struct key_entry *key;
11536203c4fSDmitry Torokhov
1162e2e3b96SDmitry Torokhov if (dev->keycode) {
11767127f30SDmitry Torokhov key = sparse_keymap_locate(dev, ke);
11836203c4fSDmitry Torokhov if (key && key->type == KE_KEY) {
11967127f30SDmitry Torokhov ke->keycode = key->keycode;
12067127f30SDmitry Torokhov if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
12167127f30SDmitry Torokhov ke->index =
12267127f30SDmitry Torokhov sparse_keymap_get_key_index(dev, key);
12367127f30SDmitry Torokhov ke->len = sizeof(key->code);
12467127f30SDmitry Torokhov memcpy(ke->scancode, &key->code, sizeof(key->code));
12536203c4fSDmitry Torokhov return 0;
12636203c4fSDmitry Torokhov }
1272e2e3b96SDmitry Torokhov }
12836203c4fSDmitry Torokhov
12936203c4fSDmitry Torokhov return -EINVAL;
13036203c4fSDmitry Torokhov }
13136203c4fSDmitry Torokhov
sparse_keymap_setkeycode(struct input_dev * dev,const struct input_keymap_entry * ke,unsigned int * old_keycode)13236203c4fSDmitry Torokhov static int sparse_keymap_setkeycode(struct input_dev *dev,
13367127f30SDmitry Torokhov const struct input_keymap_entry *ke,
13467127f30SDmitry Torokhov unsigned int *old_keycode)
13536203c4fSDmitry Torokhov {
13636203c4fSDmitry Torokhov struct key_entry *key;
13736203c4fSDmitry Torokhov
1382e2e3b96SDmitry Torokhov if (dev->keycode) {
13967127f30SDmitry Torokhov key = sparse_keymap_locate(dev, ke);
14036203c4fSDmitry Torokhov if (key && key->type == KE_KEY) {
14167127f30SDmitry Torokhov *old_keycode = key->keycode;
14267127f30SDmitry Torokhov key->keycode = ke->keycode;
14367127f30SDmitry Torokhov set_bit(ke->keycode, dev->keybit);
14467127f30SDmitry Torokhov if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
14567127f30SDmitry Torokhov clear_bit(*old_keycode, dev->keybit);
14636203c4fSDmitry Torokhov return 0;
14736203c4fSDmitry Torokhov }
1482e2e3b96SDmitry Torokhov }
14936203c4fSDmitry Torokhov
15036203c4fSDmitry Torokhov return -EINVAL;
15136203c4fSDmitry Torokhov }
15236203c4fSDmitry Torokhov
15336203c4fSDmitry Torokhov /**
15436203c4fSDmitry Torokhov * sparse_keymap_setup - set up sparse keymap for an input device
15536203c4fSDmitry Torokhov * @dev: Input device
15636203c4fSDmitry Torokhov * @keymap: Keymap in form of array of &key_entry structures ending
15736203c4fSDmitry Torokhov * with %KE_END type entry
15836203c4fSDmitry Torokhov * @setup: Function that can be used to adjust keymap entries
159fabeb165SMichał Kępień * depending on device's needs, may be %NULL
16036203c4fSDmitry Torokhov *
16136203c4fSDmitry Torokhov * The function calculates size and allocates copy of the original
16236203c4fSDmitry Torokhov * keymap after which sets up input device event bits appropriately.
163fabeb165SMichał Kępień * The allocated copy of the keymap is automatically freed when it
164fabeb165SMichał Kępień * is no longer needed.
16536203c4fSDmitry Torokhov */
sparse_keymap_setup(struct input_dev * dev,const struct key_entry * keymap,int (* setup)(struct input_dev *,struct key_entry *))16636203c4fSDmitry Torokhov int sparse_keymap_setup(struct input_dev *dev,
16736203c4fSDmitry Torokhov const struct key_entry *keymap,
16836203c4fSDmitry Torokhov int (*setup)(struct input_dev *, struct key_entry *))
16936203c4fSDmitry Torokhov {
17036203c4fSDmitry Torokhov size_t map_size = 1; /* to account for the last KE_END entry */
17136203c4fSDmitry Torokhov const struct key_entry *e;
17236203c4fSDmitry Torokhov struct key_entry *map, *entry;
17336203c4fSDmitry Torokhov int i;
17436203c4fSDmitry Torokhov int error;
17536203c4fSDmitry Torokhov
17636203c4fSDmitry Torokhov for (e = keymap; e->type != KE_END; e++)
17736203c4fSDmitry Torokhov map_size++;
17836203c4fSDmitry Torokhov
179*cdcc09a4SRaag Jadav map = devm_kmemdup_array(&dev->dev, keymap, map_size, sizeof(*keymap), GFP_KERNEL);
18036203c4fSDmitry Torokhov if (!map)
18136203c4fSDmitry Torokhov return -ENOMEM;
18236203c4fSDmitry Torokhov
18336203c4fSDmitry Torokhov for (i = 0; i < map_size; i++) {
18436203c4fSDmitry Torokhov entry = &map[i];
18536203c4fSDmitry Torokhov
18636203c4fSDmitry Torokhov if (setup) {
18736203c4fSDmitry Torokhov error = setup(dev, entry);
18836203c4fSDmitry Torokhov if (error)
189fabeb165SMichał Kępień return error;
19036203c4fSDmitry Torokhov }
19136203c4fSDmitry Torokhov
19236203c4fSDmitry Torokhov switch (entry->type) {
19336203c4fSDmitry Torokhov case KE_KEY:
19436203c4fSDmitry Torokhov __set_bit(EV_KEY, dev->evbit);
19536203c4fSDmitry Torokhov __set_bit(entry->keycode, dev->keybit);
19636203c4fSDmitry Torokhov break;
19736203c4fSDmitry Torokhov
19836203c4fSDmitry Torokhov case KE_SW:
199cb1b1459SDmitry Torokhov case KE_VSW:
20036203c4fSDmitry Torokhov __set_bit(EV_SW, dev->evbit);
20136203c4fSDmitry Torokhov __set_bit(entry->sw.code, dev->swbit);
20236203c4fSDmitry Torokhov break;
20336203c4fSDmitry Torokhov }
20436203c4fSDmitry Torokhov }
20536203c4fSDmitry Torokhov
206f3cf5c4fSSeth Forshee if (test_bit(EV_KEY, dev->evbit)) {
207170531baSSeth Forshee __set_bit(KEY_UNKNOWN, dev->keybit);
208f3cf5c4fSSeth Forshee __set_bit(EV_MSC, dev->evbit);
209f3cf5c4fSSeth Forshee __set_bit(MSC_SCAN, dev->mscbit);
210f3cf5c4fSSeth Forshee }
211f3cf5c4fSSeth Forshee
21236203c4fSDmitry Torokhov dev->keycode = map;
21336203c4fSDmitry Torokhov dev->keycodemax = map_size;
214aebd636bSDmitry Torokhov dev->getkeycode = sparse_keymap_getkeycode;
215aebd636bSDmitry Torokhov dev->setkeycode = sparse_keymap_setkeycode;
21636203c4fSDmitry Torokhov
21736203c4fSDmitry Torokhov return 0;
21836203c4fSDmitry Torokhov }
21936203c4fSDmitry Torokhov EXPORT_SYMBOL(sparse_keymap_setup);
22036203c4fSDmitry Torokhov
22136203c4fSDmitry Torokhov /**
22236203c4fSDmitry Torokhov * sparse_keymap_report_entry - report event corresponding to given key entry
22336203c4fSDmitry Torokhov * @dev: Input device for which event should be reported
22436203c4fSDmitry Torokhov * @ke: key entry describing event
22536203c4fSDmitry Torokhov * @value: Value that should be reported (ignored by %KE_SW entries)
22636203c4fSDmitry Torokhov * @autorelease: Signals whether release event should be emitted for %KE_KEY
22736203c4fSDmitry Torokhov * entries right after reporting press event, ignored by all other
22836203c4fSDmitry Torokhov * entries
22936203c4fSDmitry Torokhov *
23036203c4fSDmitry Torokhov * This function is used to report input event described by given
23136203c4fSDmitry Torokhov * &struct key_entry.
23236203c4fSDmitry Torokhov */
sparse_keymap_report_entry(struct input_dev * dev,const struct key_entry * ke,unsigned int value,bool autorelease)23336203c4fSDmitry Torokhov void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
23436203c4fSDmitry Torokhov unsigned int value, bool autorelease)
23536203c4fSDmitry Torokhov {
23636203c4fSDmitry Torokhov switch (ke->type) {
23736203c4fSDmitry Torokhov case KE_KEY:
238f3cf5c4fSSeth Forshee input_event(dev, EV_MSC, MSC_SCAN, ke->code);
23936203c4fSDmitry Torokhov input_report_key(dev, ke->keycode, value);
24036203c4fSDmitry Torokhov input_sync(dev);
24136203c4fSDmitry Torokhov if (value && autorelease) {
24236203c4fSDmitry Torokhov input_report_key(dev, ke->keycode, 0);
24336203c4fSDmitry Torokhov input_sync(dev);
24436203c4fSDmitry Torokhov }
24536203c4fSDmitry Torokhov break;
24636203c4fSDmitry Torokhov
24736203c4fSDmitry Torokhov case KE_SW:
24836203c4fSDmitry Torokhov value = ke->sw.value;
2496f49c4f5SGustavo A. R. Silva fallthrough;
25036203c4fSDmitry Torokhov
25136203c4fSDmitry Torokhov case KE_VSW:
25236203c4fSDmitry Torokhov input_report_switch(dev, ke->sw.code, value);
2536f29c244SStefan Brüns input_sync(dev);
25436203c4fSDmitry Torokhov break;
25536203c4fSDmitry Torokhov }
25636203c4fSDmitry Torokhov }
25736203c4fSDmitry Torokhov EXPORT_SYMBOL(sparse_keymap_report_entry);
25836203c4fSDmitry Torokhov
25936203c4fSDmitry Torokhov /**
26036203c4fSDmitry Torokhov * sparse_keymap_report_event - report event corresponding to given scancode
26136203c4fSDmitry Torokhov * @dev: Input device using sparse keymap
26236203c4fSDmitry Torokhov * @code: Scan code
26336203c4fSDmitry Torokhov * @value: Value that should be reported (ignored by %KE_SW entries)
26436203c4fSDmitry Torokhov * @autorelease: Signals whether release event should be emitted for %KE_KEY
26536203c4fSDmitry Torokhov * entries right after reporting press event, ignored by all other
26636203c4fSDmitry Torokhov * entries
26736203c4fSDmitry Torokhov *
26836203c4fSDmitry Torokhov * This function is used to perform lookup in an input device using sparse
26936203c4fSDmitry Torokhov * keymap and report corresponding event. Returns %true if lookup was
27036203c4fSDmitry Torokhov * successful and %false otherwise.
27136203c4fSDmitry Torokhov */
sparse_keymap_report_event(struct input_dev * dev,unsigned int code,unsigned int value,bool autorelease)27236203c4fSDmitry Torokhov bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
27336203c4fSDmitry Torokhov unsigned int value, bool autorelease)
27436203c4fSDmitry Torokhov {
27536203c4fSDmitry Torokhov const struct key_entry *ke =
27636203c4fSDmitry Torokhov sparse_keymap_entry_from_scancode(dev, code);
277170531baSSeth Forshee struct key_entry unknown_ke;
27836203c4fSDmitry Torokhov
27936203c4fSDmitry Torokhov if (ke) {
28036203c4fSDmitry Torokhov sparse_keymap_report_entry(dev, ke, value, autorelease);
28136203c4fSDmitry Torokhov return true;
28236203c4fSDmitry Torokhov }
28336203c4fSDmitry Torokhov
284170531baSSeth Forshee /* Report an unknown key event as a debugging aid */
285170531baSSeth Forshee unknown_ke.type = KE_KEY;
286170531baSSeth Forshee unknown_ke.code = code;
287170531baSSeth Forshee unknown_ke.keycode = KEY_UNKNOWN;
288170531baSSeth Forshee sparse_keymap_report_entry(dev, &unknown_ke, value, true);
289170531baSSeth Forshee
29036203c4fSDmitry Torokhov return false;
29136203c4fSDmitry Torokhov }
29236203c4fSDmitry Torokhov EXPORT_SYMBOL(sparse_keymap_report_event);
29336203c4fSDmitry Torokhov
294