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 18 MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 19 MODULE_DESCRIPTION("Generic support for sparse keymaps"); 20 MODULE_LICENSE("GPL v2"); 21 22 static 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 39 static 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 */ 61 struct 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 } 72 EXPORT_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 */ 82 struct 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 } 93 EXPORT_SYMBOL(sparse_keymap_entry_from_keycode); 94 95 static 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 111 static 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 132 static 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 */ 166 int 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 } 220 EXPORT_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 */ 234 void 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 } 258 EXPORT_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 */ 273 bool 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 } 293 EXPORT_SYMBOL(sparse_keymap_report_event); 294 295