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