cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sparse-keymap.c (7618B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Generic support for sparse keymaps
      4 *
      5 * Copyright (c) 2009 Dmitry Torokhov
      6 *
      7 * Derived from wistron button driver:
      8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
      9 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
     10 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
     11 */
     12
     13#include <linux/input.h>
     14#include <linux/input/sparse-keymap.h>
     15#include <linux/module.h>
     16#include <linux/slab.h>
     17
     18MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
     19MODULE_DESCRIPTION("Generic support for sparse keymaps");
     20MODULE_LICENSE("GPL v2");
     21
     22static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
     23						const struct key_entry *k)
     24{
     25	struct key_entry *key;
     26	unsigned int idx = 0;
     27
     28	for (key = dev->keycode; key->type != KE_END; key++) {
     29		if (key->type == KE_KEY) {
     30			if (key == k)
     31				break;
     32			idx++;
     33		}
     34	}
     35
     36	return idx;
     37}
     38
     39static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
     40						      unsigned int index)
     41{
     42	struct key_entry *key;
     43	unsigned int key_cnt = 0;
     44
     45	for (key = dev->keycode; key->type != KE_END; key++)
     46		if (key->type == KE_KEY)
     47			if (key_cnt++ == index)
     48				return key;
     49
     50	return NULL;
     51}
     52
     53/**
     54 * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
     55 * @dev: Input device using sparse keymap
     56 * @code: Scan code
     57 *
     58 * This function is used to perform &struct key_entry lookup in an
     59 * input device using sparse keymap.
     60 */
     61struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
     62						    unsigned int code)
     63{
     64	struct key_entry *key;
     65
     66	for (key = dev->keycode; key->type != KE_END; key++)
     67		if (code == key->code)
     68			return key;
     69
     70	return NULL;
     71}
     72EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
     73
     74/**
     75 * sparse_keymap_entry_from_keycode - perform sparse keymap lookup
     76 * @dev: Input device using sparse keymap
     77 * @keycode: Key code
     78 *
     79 * This function is used to perform &struct key_entry lookup in an
     80 * input device using sparse keymap.
     81 */
     82struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
     83						   unsigned int keycode)
     84{
     85	struct key_entry *key;
     86
     87	for (key = dev->keycode; key->type != KE_END; key++)
     88		if (key->type == KE_KEY && keycode == key->keycode)
     89			return key;
     90
     91	return NULL;
     92}
     93EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
     94
     95static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
     96					const struct input_keymap_entry *ke)
     97{
     98	struct key_entry *key;
     99	unsigned int scancode;
    100
    101	if (ke->flags & INPUT_KEYMAP_BY_INDEX)
    102		key = sparse_keymap_entry_by_index(dev, ke->index);
    103	else if (input_scancode_to_scalar(ke, &scancode) == 0)
    104		key = sparse_keymap_entry_from_scancode(dev, scancode);
    105	else
    106		key = NULL;
    107
    108	return key;
    109}
    110
    111static int sparse_keymap_getkeycode(struct input_dev *dev,
    112				    struct input_keymap_entry *ke)
    113{
    114	const struct key_entry *key;
    115
    116	if (dev->keycode) {
    117		key = sparse_keymap_locate(dev, ke);
    118		if (key && key->type == KE_KEY) {
    119			ke->keycode = key->keycode;
    120			if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
    121				ke->index =
    122					sparse_keymap_get_key_index(dev, key);
    123			ke->len = sizeof(key->code);
    124			memcpy(ke->scancode, &key->code, sizeof(key->code));
    125			return 0;
    126		}
    127	}
    128
    129	return -EINVAL;
    130}
    131
    132static int sparse_keymap_setkeycode(struct input_dev *dev,
    133				    const struct input_keymap_entry *ke,
    134				    unsigned int *old_keycode)
    135{
    136	struct key_entry *key;
    137
    138	if (dev->keycode) {
    139		key = sparse_keymap_locate(dev, ke);
    140		if (key && key->type == KE_KEY) {
    141			*old_keycode = key->keycode;
    142			key->keycode = ke->keycode;
    143			set_bit(ke->keycode, dev->keybit);
    144			if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
    145				clear_bit(*old_keycode, dev->keybit);
    146			return 0;
    147		}
    148	}
    149
    150	return -EINVAL;
    151}
    152
    153/**
    154 * sparse_keymap_setup - set up sparse keymap for an input device
    155 * @dev: Input device
    156 * @keymap: Keymap in form of array of &key_entry structures ending
    157 *	with %KE_END type entry
    158 * @setup: Function that can be used to adjust keymap entries
    159 *	depending on device's needs, may be %NULL
    160 *
    161 * The function calculates size and allocates copy of the original
    162 * keymap after which sets up input device event bits appropriately.
    163 * The allocated copy of the keymap is automatically freed when it
    164 * is no longer needed.
    165 */
    166int sparse_keymap_setup(struct input_dev *dev,
    167			const struct key_entry *keymap,
    168			int (*setup)(struct input_dev *, struct key_entry *))
    169{
    170	size_t map_size = 1; /* to account for the last KE_END entry */
    171	const struct key_entry *e;
    172	struct key_entry *map, *entry;
    173	int i;
    174	int error;
    175
    176	for (e = keymap; e->type != KE_END; e++)
    177		map_size++;
    178
    179	map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map),
    180			   GFP_KERNEL);
    181	if (!map)
    182		return -ENOMEM;
    183
    184	for (i = 0; i < map_size; i++) {
    185		entry = &map[i];
    186
    187		if (setup) {
    188			error = setup(dev, entry);
    189			if (error)
    190				return error;
    191		}
    192
    193		switch (entry->type) {
    194		case KE_KEY:
    195			__set_bit(EV_KEY, dev->evbit);
    196			__set_bit(entry->keycode, dev->keybit);
    197			break;
    198
    199		case KE_SW:
    200		case KE_VSW:
    201			__set_bit(EV_SW, dev->evbit);
    202			__set_bit(entry->sw.code, dev->swbit);
    203			break;
    204		}
    205	}
    206
    207	if (test_bit(EV_KEY, dev->evbit)) {
    208		__set_bit(KEY_UNKNOWN, dev->keybit);
    209		__set_bit(EV_MSC, dev->evbit);
    210		__set_bit(MSC_SCAN, dev->mscbit);
    211	}
    212
    213	dev->keycode = map;
    214	dev->keycodemax = map_size;
    215	dev->getkeycode = sparse_keymap_getkeycode;
    216	dev->setkeycode = sparse_keymap_setkeycode;
    217
    218	return 0;
    219}
    220EXPORT_SYMBOL(sparse_keymap_setup);
    221
    222/**
    223 * sparse_keymap_report_entry - report event corresponding to given key entry
    224 * @dev: Input device for which event should be reported
    225 * @ke: key entry describing event
    226 * @value: Value that should be reported (ignored by %KE_SW entries)
    227 * @autorelease: Signals whether release event should be emitted for %KE_KEY
    228 *	entries right after reporting press event, ignored by all other
    229 *	entries
    230 *
    231 * This function is used to report input event described by given
    232 * &struct key_entry.
    233 */
    234void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
    235				unsigned int value, bool autorelease)
    236{
    237	switch (ke->type) {
    238	case KE_KEY:
    239		input_event(dev, EV_MSC, MSC_SCAN, ke->code);
    240		input_report_key(dev, ke->keycode, value);
    241		input_sync(dev);
    242		if (value && autorelease) {
    243			input_report_key(dev, ke->keycode, 0);
    244			input_sync(dev);
    245		}
    246		break;
    247
    248	case KE_SW:
    249		value = ke->sw.value;
    250		fallthrough;
    251
    252	case KE_VSW:
    253		input_report_switch(dev, ke->sw.code, value);
    254		input_sync(dev);
    255		break;
    256	}
    257}
    258EXPORT_SYMBOL(sparse_keymap_report_entry);
    259
    260/**
    261 * sparse_keymap_report_event - report event corresponding to given scancode
    262 * @dev: Input device using sparse keymap
    263 * @code: Scan code
    264 * @value: Value that should be reported (ignored by %KE_SW entries)
    265 * @autorelease: Signals whether release event should be emitted for %KE_KEY
    266 *	entries right after reporting press event, ignored by all other
    267 *	entries
    268 *
    269 * This function is used to perform lookup in an input device using sparse
    270 * keymap and report corresponding event. Returns %true if lookup was
    271 * successful and %false otherwise.
    272 */
    273bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
    274				unsigned int value, bool autorelease)
    275{
    276	const struct key_entry *ke =
    277		sparse_keymap_entry_from_scancode(dev, code);
    278	struct key_entry unknown_ke;
    279
    280	if (ke) {
    281		sparse_keymap_report_entry(dev, ke, value, autorelease);
    282		return true;
    283	}
    284
    285	/* Report an unknown key event as a debugging aid */
    286	unknown_ke.type = KE_KEY;
    287	unknown_ke.code = code;
    288	unknown_ke.keycode = KEY_UNKNOWN;
    289	sparse_keymap_report_entry(dev, &unknown_ke, value, true);
    290
    291	return false;
    292}
    293EXPORT_SYMBOL(sparse_keymap_report_event);
    294