at master 7.6 kB view raw
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/export.h> 14#include <linux/input.h> 15#include <linux/input/sparse-keymap.h> 16#include <linux/module.h> 17#include <linux/slab.h> 18 19MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 20MODULE_DESCRIPTION("Generic support for sparse keymaps"); 21MODULE_LICENSE("GPL v2"); 22 23static unsigned int sparse_keymap_get_key_index(struct input_dev *dev, 24 const struct key_entry *k) 25{ 26 struct key_entry *key; 27 unsigned int idx = 0; 28 29 for (key = dev->keycode; key->type != KE_END; key++) { 30 if (key->type == KE_KEY) { 31 if (key == k) 32 break; 33 idx++; 34 } 35 } 36 37 return idx; 38} 39 40static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev, 41 unsigned int index) 42{ 43 struct key_entry *key; 44 unsigned int key_cnt = 0; 45 46 for (key = dev->keycode; key->type != KE_END; key++) 47 if (key->type == KE_KEY) 48 if (key_cnt++ == index) 49 return key; 50 51 return NULL; 52} 53 54/** 55 * sparse_keymap_entry_from_scancode - perform sparse keymap lookup 56 * @dev: Input device using sparse keymap 57 * @code: Scan code 58 * 59 * This function is used to perform &struct key_entry lookup in an 60 * input device using sparse keymap. 61 */ 62struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev, 63 unsigned int code) 64{ 65 struct key_entry *key; 66 67 for (key = dev->keycode; key->type != KE_END; key++) 68 if (code == key->code) 69 return key; 70 71 return NULL; 72} 73EXPORT_SYMBOL(sparse_keymap_entry_from_scancode); 74 75/** 76 * sparse_keymap_entry_from_keycode - perform sparse keymap lookup 77 * @dev: Input device using sparse keymap 78 * @keycode: Key code 79 * 80 * This function is used to perform &struct key_entry lookup in an 81 * input device using sparse keymap. 82 */ 83struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, 84 unsigned int keycode) 85{ 86 struct key_entry *key; 87 88 for (key = dev->keycode; key->type != KE_END; key++) 89 if (key->type == KE_KEY && keycode == key->keycode) 90 return key; 91 92 return NULL; 93} 94EXPORT_SYMBOL(sparse_keymap_entry_from_keycode); 95 96static struct key_entry *sparse_keymap_locate(struct input_dev *dev, 97 const struct input_keymap_entry *ke) 98{ 99 struct key_entry *key; 100 unsigned int scancode; 101 102 if (ke->flags & INPUT_KEYMAP_BY_INDEX) 103 key = sparse_keymap_entry_by_index(dev, ke->index); 104 else if (input_scancode_to_scalar(ke, &scancode) == 0) 105 key = sparse_keymap_entry_from_scancode(dev, scancode); 106 else 107 key = NULL; 108 109 return key; 110} 111 112static int sparse_keymap_getkeycode(struct input_dev *dev, 113 struct input_keymap_entry *ke) 114{ 115 const struct key_entry *key; 116 117 if (dev->keycode) { 118 key = sparse_keymap_locate(dev, ke); 119 if (key && key->type == KE_KEY) { 120 ke->keycode = key->keycode; 121 if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) 122 ke->index = 123 sparse_keymap_get_key_index(dev, key); 124 ke->len = sizeof(key->code); 125 memcpy(ke->scancode, &key->code, sizeof(key->code)); 126 return 0; 127 } 128 } 129 130 return -EINVAL; 131} 132 133static int sparse_keymap_setkeycode(struct input_dev *dev, 134 const struct input_keymap_entry *ke, 135 unsigned int *old_keycode) 136{ 137 struct key_entry *key; 138 139 if (dev->keycode) { 140 key = sparse_keymap_locate(dev, ke); 141 if (key && key->type == KE_KEY) { 142 *old_keycode = key->keycode; 143 key->keycode = ke->keycode; 144 set_bit(ke->keycode, dev->keybit); 145 if (!sparse_keymap_entry_from_keycode(dev, *old_keycode)) 146 clear_bit(*old_keycode, dev->keybit); 147 return 0; 148 } 149 } 150 151 return -EINVAL; 152} 153 154/** 155 * sparse_keymap_setup - set up sparse keymap for an input device 156 * @dev: Input device 157 * @keymap: Keymap in form of array of &key_entry structures ending 158 * with %KE_END type entry 159 * @setup: Function that can be used to adjust keymap entries 160 * depending on device's needs, may be %NULL 161 * 162 * The function calculates size and allocates copy of the original 163 * keymap after which sets up input device event bits appropriately. 164 * The allocated copy of the keymap is automatically freed when it 165 * is no longer needed. 166 */ 167int sparse_keymap_setup(struct input_dev *dev, 168 const struct key_entry *keymap, 169 int (*setup)(struct input_dev *, struct key_entry *)) 170{ 171 size_t map_size = 1; /* to account for the last KE_END entry */ 172 const struct key_entry *e; 173 struct key_entry *map, *entry; 174 int i; 175 int error; 176 177 for (e = keymap; e->type != KE_END; e++) 178 map_size++; 179 180 map = devm_kmemdup_array(&dev->dev, keymap, map_size, sizeof(*keymap), 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