18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Generic support for sparse keymaps 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009 Dmitry Torokhov 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Derived from wistron button driver: 88c2ecf20Sopenharmony_ci * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 98c2ecf20Sopenharmony_ci * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> 108c2ecf20Sopenharmony_ci * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/input.h> 148c2ecf20Sopenharmony_ci#include <linux/input/sparse-keymap.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Generic support for sparse keymaps"); 208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic unsigned int sparse_keymap_get_key_index(struct input_dev *dev, 238c2ecf20Sopenharmony_ci const struct key_entry *k) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct key_entry *key; 268c2ecf20Sopenharmony_ci unsigned int idx = 0; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci for (key = dev->keycode; key->type != KE_END; key++) { 298c2ecf20Sopenharmony_ci if (key->type == KE_KEY) { 308c2ecf20Sopenharmony_ci if (key == k) 318c2ecf20Sopenharmony_ci break; 328c2ecf20Sopenharmony_ci idx++; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return idx; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev, 408c2ecf20Sopenharmony_ci unsigned int index) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct key_entry *key; 438c2ecf20Sopenharmony_ci unsigned int key_cnt = 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci for (key = dev->keycode; key->type != KE_END; key++) 468c2ecf20Sopenharmony_ci if (key->type == KE_KEY) 478c2ecf20Sopenharmony_ci if (key_cnt++ == index) 488c2ecf20Sopenharmony_ci return key; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return NULL; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * sparse_keymap_entry_from_scancode - perform sparse keymap lookup 558c2ecf20Sopenharmony_ci * @dev: Input device using sparse keymap 568c2ecf20Sopenharmony_ci * @code: Scan code 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * This function is used to perform &struct key_entry lookup in an 598c2ecf20Sopenharmony_ci * input device using sparse keymap. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistruct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev, 628c2ecf20Sopenharmony_ci unsigned int code) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct key_entry *key; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci for (key = dev->keycode; key->type != KE_END; key++) 678c2ecf20Sopenharmony_ci if (code == key->code) 688c2ecf20Sopenharmony_ci return key; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return NULL; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sparse_keymap_entry_from_scancode); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/** 758c2ecf20Sopenharmony_ci * sparse_keymap_entry_from_keycode - perform sparse keymap lookup 768c2ecf20Sopenharmony_ci * @dev: Input device using sparse keymap 778c2ecf20Sopenharmony_ci * @keycode: Key code 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * This function is used to perform &struct key_entry lookup in an 808c2ecf20Sopenharmony_ci * input device using sparse keymap. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistruct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, 838c2ecf20Sopenharmony_ci unsigned int keycode) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct key_entry *key; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (key = dev->keycode; key->type != KE_END; key++) 888c2ecf20Sopenharmony_ci if (key->type == KE_KEY && keycode == key->keycode) 898c2ecf20Sopenharmony_ci return key; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return NULL; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sparse_keymap_entry_from_keycode); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic struct key_entry *sparse_keymap_locate(struct input_dev *dev, 968c2ecf20Sopenharmony_ci const struct input_keymap_entry *ke) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct key_entry *key; 998c2ecf20Sopenharmony_ci unsigned int scancode; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (ke->flags & INPUT_KEYMAP_BY_INDEX) 1028c2ecf20Sopenharmony_ci key = sparse_keymap_entry_by_index(dev, ke->index); 1038c2ecf20Sopenharmony_ci else if (input_scancode_to_scalar(ke, &scancode) == 0) 1048c2ecf20Sopenharmony_ci key = sparse_keymap_entry_from_scancode(dev, scancode); 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci key = NULL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return key; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int sparse_keymap_getkeycode(struct input_dev *dev, 1128c2ecf20Sopenharmony_ci struct input_keymap_entry *ke) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci const struct key_entry *key; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (dev->keycode) { 1178c2ecf20Sopenharmony_ci key = sparse_keymap_locate(dev, ke); 1188c2ecf20Sopenharmony_ci if (key && key->type == KE_KEY) { 1198c2ecf20Sopenharmony_ci ke->keycode = key->keycode; 1208c2ecf20Sopenharmony_ci if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) 1218c2ecf20Sopenharmony_ci ke->index = 1228c2ecf20Sopenharmony_ci sparse_keymap_get_key_index(dev, key); 1238c2ecf20Sopenharmony_ci ke->len = sizeof(key->code); 1248c2ecf20Sopenharmony_ci memcpy(ke->scancode, &key->code, sizeof(key->code)); 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int sparse_keymap_setkeycode(struct input_dev *dev, 1338c2ecf20Sopenharmony_ci const struct input_keymap_entry *ke, 1348c2ecf20Sopenharmony_ci unsigned int *old_keycode) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct key_entry *key; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (dev->keycode) { 1398c2ecf20Sopenharmony_ci key = sparse_keymap_locate(dev, ke); 1408c2ecf20Sopenharmony_ci if (key && key->type == KE_KEY) { 1418c2ecf20Sopenharmony_ci *old_keycode = key->keycode; 1428c2ecf20Sopenharmony_ci key->keycode = ke->keycode; 1438c2ecf20Sopenharmony_ci set_bit(ke->keycode, dev->keybit); 1448c2ecf20Sopenharmony_ci if (!sparse_keymap_entry_from_keycode(dev, *old_keycode)) 1458c2ecf20Sopenharmony_ci clear_bit(*old_keycode, dev->keybit); 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return -EINVAL; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/** 1548c2ecf20Sopenharmony_ci * sparse_keymap_setup - set up sparse keymap for an input device 1558c2ecf20Sopenharmony_ci * @dev: Input device 1568c2ecf20Sopenharmony_ci * @keymap: Keymap in form of array of &key_entry structures ending 1578c2ecf20Sopenharmony_ci * with %KE_END type entry 1588c2ecf20Sopenharmony_ci * @setup: Function that can be used to adjust keymap entries 1598c2ecf20Sopenharmony_ci * depending on device's needs, may be %NULL 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * The function calculates size and allocates copy of the original 1628c2ecf20Sopenharmony_ci * keymap after which sets up input device event bits appropriately. 1638c2ecf20Sopenharmony_ci * The allocated copy of the keymap is automatically freed when it 1648c2ecf20Sopenharmony_ci * is no longer needed. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ciint sparse_keymap_setup(struct input_dev *dev, 1678c2ecf20Sopenharmony_ci const struct key_entry *keymap, 1688c2ecf20Sopenharmony_ci int (*setup)(struct input_dev *, struct key_entry *)) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci size_t map_size = 1; /* to account for the last KE_END entry */ 1718c2ecf20Sopenharmony_ci const struct key_entry *e; 1728c2ecf20Sopenharmony_ci struct key_entry *map, *entry; 1738c2ecf20Sopenharmony_ci int i; 1748c2ecf20Sopenharmony_ci int error; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci for (e = keymap; e->type != KE_END; e++) 1778c2ecf20Sopenharmony_ci map_size++; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map), 1808c2ecf20Sopenharmony_ci GFP_KERNEL); 1818c2ecf20Sopenharmony_ci if (!map) 1828c2ecf20Sopenharmony_ci return -ENOMEM; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci for (i = 0; i < map_size; i++) { 1858c2ecf20Sopenharmony_ci entry = &map[i]; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (setup) { 1888c2ecf20Sopenharmony_ci error = setup(dev, entry); 1898c2ecf20Sopenharmony_ci if (error) 1908c2ecf20Sopenharmony_ci return error; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci switch (entry->type) { 1948c2ecf20Sopenharmony_ci case KE_KEY: 1958c2ecf20Sopenharmony_ci __set_bit(EV_KEY, dev->evbit); 1968c2ecf20Sopenharmony_ci __set_bit(entry->keycode, dev->keybit); 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci case KE_SW: 2008c2ecf20Sopenharmony_ci case KE_VSW: 2018c2ecf20Sopenharmony_ci __set_bit(EV_SW, dev->evbit); 2028c2ecf20Sopenharmony_ci __set_bit(entry->sw.code, dev->swbit); 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (test_bit(EV_KEY, dev->evbit)) { 2088c2ecf20Sopenharmony_ci __set_bit(KEY_UNKNOWN, dev->keybit); 2098c2ecf20Sopenharmony_ci __set_bit(EV_MSC, dev->evbit); 2108c2ecf20Sopenharmony_ci __set_bit(MSC_SCAN, dev->mscbit); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci dev->keycode = map; 2148c2ecf20Sopenharmony_ci dev->keycodemax = map_size; 2158c2ecf20Sopenharmony_ci dev->getkeycode = sparse_keymap_getkeycode; 2168c2ecf20Sopenharmony_ci dev->setkeycode = sparse_keymap_setkeycode; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sparse_keymap_setup); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/** 2238c2ecf20Sopenharmony_ci * sparse_keymap_report_entry - report event corresponding to given key entry 2248c2ecf20Sopenharmony_ci * @dev: Input device for which event should be reported 2258c2ecf20Sopenharmony_ci * @ke: key entry describing event 2268c2ecf20Sopenharmony_ci * @value: Value that should be reported (ignored by %KE_SW entries) 2278c2ecf20Sopenharmony_ci * @autorelease: Signals whether release event should be emitted for %KE_KEY 2288c2ecf20Sopenharmony_ci * entries right after reporting press event, ignored by all other 2298c2ecf20Sopenharmony_ci * entries 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * This function is used to report input event described by given 2328c2ecf20Sopenharmony_ci * &struct key_entry. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_civoid sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, 2358c2ecf20Sopenharmony_ci unsigned int value, bool autorelease) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci switch (ke->type) { 2388c2ecf20Sopenharmony_ci case KE_KEY: 2398c2ecf20Sopenharmony_ci input_event(dev, EV_MSC, MSC_SCAN, ke->code); 2408c2ecf20Sopenharmony_ci input_report_key(dev, ke->keycode, value); 2418c2ecf20Sopenharmony_ci input_sync(dev); 2428c2ecf20Sopenharmony_ci if (value && autorelease) { 2438c2ecf20Sopenharmony_ci input_report_key(dev, ke->keycode, 0); 2448c2ecf20Sopenharmony_ci input_sync(dev); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci case KE_SW: 2498c2ecf20Sopenharmony_ci value = ke->sw.value; 2508c2ecf20Sopenharmony_ci fallthrough; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci case KE_VSW: 2538c2ecf20Sopenharmony_ci input_report_switch(dev, ke->sw.code, value); 2548c2ecf20Sopenharmony_ci input_sync(dev); 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sparse_keymap_report_entry); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/** 2618c2ecf20Sopenharmony_ci * sparse_keymap_report_event - report event corresponding to given scancode 2628c2ecf20Sopenharmony_ci * @dev: Input device using sparse keymap 2638c2ecf20Sopenharmony_ci * @code: Scan code 2648c2ecf20Sopenharmony_ci * @value: Value that should be reported (ignored by %KE_SW entries) 2658c2ecf20Sopenharmony_ci * @autorelease: Signals whether release event should be emitted for %KE_KEY 2668c2ecf20Sopenharmony_ci * entries right after reporting press event, ignored by all other 2678c2ecf20Sopenharmony_ci * entries 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * This function is used to perform lookup in an input device using sparse 2708c2ecf20Sopenharmony_ci * keymap and report corresponding event. Returns %true if lookup was 2718c2ecf20Sopenharmony_ci * successful and %false otherwise. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cibool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, 2748c2ecf20Sopenharmony_ci unsigned int value, bool autorelease) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci const struct key_entry *ke = 2778c2ecf20Sopenharmony_ci sparse_keymap_entry_from_scancode(dev, code); 2788c2ecf20Sopenharmony_ci struct key_entry unknown_ke; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (ke) { 2818c2ecf20Sopenharmony_ci sparse_keymap_report_entry(dev, ke, value, autorelease); 2828c2ecf20Sopenharmony_ci return true; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Report an unknown key event as a debugging aid */ 2868c2ecf20Sopenharmony_ci unknown_ke.type = KE_KEY; 2878c2ecf20Sopenharmony_ci unknown_ke.code = code; 2888c2ecf20Sopenharmony_ci unknown_ke.keycode = KEY_UNKNOWN; 2898c2ecf20Sopenharmony_ci sparse_keymap_report_entry(dev, &unknown_ke, value, true); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return false; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sparse_keymap_report_event); 2948c2ecf20Sopenharmony_ci 295