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_array(&dev->dev, keymap, map_size, sizeof(*keymap), GFP_KERNEL); 180 if (!map) 181 return -ENOMEM; 182 183 for (i = 0; i < map_size; i++) { 184 entry = &map[i]; 185 186 if (setup) { 187 error = setup(dev, entry); 188 if (error) 189 return error; 190 } 191 192 switch (entry->type) { 193 case KE_KEY: 194 __set_bit(EV_KEY, dev->evbit); 195 __set_bit(entry->keycode, dev->keybit); 196 break; 197 198 case KE_SW: 199 case KE_VSW: 200 __set_bit(EV_SW, dev->evbit); 201 __set_bit(entry->sw.code, dev->swbit); 202 break; 203 } 204 } 205 206 if (test_bit(EV_KEY, dev->evbit)) { 207 __set_bit(KEY_UNKNOWN, dev->keybit); 208 __set_bit(EV_MSC, dev->evbit); 209 __set_bit(MSC_SCAN, dev->mscbit); 210 } 211 212 dev->keycode = map; 213 dev->keycodemax = map_size; 214 dev->getkeycode = sparse_keymap_getkeycode; 215 dev->setkeycode = sparse_keymap_setkeycode; 216 217 return 0; 218 } 219 EXPORT_SYMBOL(sparse_keymap_setup); 220 221 /** 222 * sparse_keymap_report_entry - report event corresponding to given key entry 223 * @dev: Input device for which event should be reported 224 * @ke: key entry describing event 225 * @value: Value that should be reported (ignored by %KE_SW entries) 226 * @autorelease: Signals whether release event should be emitted for %KE_KEY 227 * entries right after reporting press event, ignored by all other 228 * entries 229 * 230 * This function is used to report input event described by given 231 * &struct key_entry. 232 */ 233 void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, 234 unsigned int value, bool autorelease) 235 { 236 switch (ke->type) { 237 case KE_KEY: 238 input_event(dev, EV_MSC, MSC_SCAN, ke->code); 239 input_report_key(dev, ke->keycode, value); 240 input_sync(dev); 241 if (value && autorelease) { 242 input_report_key(dev, ke->keycode, 0); 243 input_sync(dev); 244 } 245 break; 246 247 case KE_SW: 248 value = ke->sw.value; 249 fallthrough; 250 251 case KE_VSW: 252 input_report_switch(dev, ke->sw.code, value); 253 input_sync(dev); 254 break; 255 } 256 } 257 EXPORT_SYMBOL(sparse_keymap_report_entry); 258 259 /** 260 * sparse_keymap_report_event - report event corresponding to given scancode 261 * @dev: Input device using sparse keymap 262 * @code: Scan code 263 * @value: Value that should be reported (ignored by %KE_SW entries) 264 * @autorelease: Signals whether release event should be emitted for %KE_KEY 265 * entries right after reporting press event, ignored by all other 266 * entries 267 * 268 * This function is used to perform lookup in an input device using sparse 269 * keymap and report corresponding event. Returns %true if lookup was 270 * successful and %false otherwise. 271 */ 272 bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, 273 unsigned int value, bool autorelease) 274 { 275 const struct key_entry *ke = 276 sparse_keymap_entry_from_scancode(dev, code); 277 struct key_entry unknown_ke; 278 279 if (ke) { 280 sparse_keymap_report_entry(dev, ke, value, autorelease); 281 return true; 282 } 283 284 /* Report an unknown key event as a debugging aid */ 285 unknown_ke.type = KE_KEY; 286 unknown_ke.code = code; 287 unknown_ke.keycode = KEY_UNKNOWN; 288 sparse_keymap_report_entry(dev, &unknown_ke, value, true); 289 290 return false; 291 } 292 EXPORT_SYMBOL(sparse_keymap_report_event); 293 294