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