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 19 MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 20 MODULE_DESCRIPTION("Generic support for sparse keymaps"); 21 MODULE_LICENSE("GPL v2"); 22 23 static 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 40 static 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 */ 62 struct 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 } 73 EXPORT_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 */ 83 struct 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 } 94 EXPORT_SYMBOL(sparse_keymap_entry_from_keycode); 95 96 static 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 112 static 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 133 static 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 */ 167 int 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 } 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