Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/sparse-keymap.c
15109 views
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 <[email protected]>
8
* Copyright (C) 2005 Bernhard Rosenkraenzer <[email protected]>
9
* Copyright (C) 2005 Dmitry Torokhov <[email protected]>
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/slab.h>
19
20
MODULE_AUTHOR("Dmitry Torokhov <[email protected]>");
21
MODULE_DESCRIPTION("Generic support for sparse keymaps");
22
MODULE_LICENSE("GPL v2");
23
MODULE_VERSION("0.1");
24
25
static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
26
const struct key_entry *k)
27
{
28
struct key_entry *key;
29
unsigned int idx = 0;
30
31
for (key = dev->keycode; key->type != KE_END; key++) {
32
if (key->type == KE_KEY) {
33
if (key == k)
34
break;
35
idx++;
36
}
37
}
38
39
return idx;
40
}
41
42
static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
43
unsigned int index)
44
{
45
struct key_entry *key;
46
unsigned int key_cnt = 0;
47
48
for (key = dev->keycode; key->type != KE_END; key++)
49
if (key->type == KE_KEY)
50
if (key_cnt++ == index)
51
return key;
52
53
return NULL;
54
}
55
56
/**
57
* sparse_keymap_entry_from_scancode - perform sparse keymap lookup
58
* @dev: Input device using sparse keymap
59
* @code: Scan code
60
*
61
* This function is used to perform &struct key_entry lookup in an
62
* input device using sparse keymap.
63
*/
64
struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
65
unsigned int code)
66
{
67
struct key_entry *key;
68
69
for (key = dev->keycode; key->type != KE_END; key++)
70
if (code == key->code)
71
return key;
72
73
return NULL;
74
}
75
EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
76
77
/**
78
* sparse_keymap_entry_from_keycode - perform sparse keymap lookup
79
* @dev: Input device using sparse keymap
80
* @keycode: Key code
81
*
82
* This function is used to perform &struct key_entry lookup in an
83
* input device using sparse keymap.
84
*/
85
struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
86
unsigned int keycode)
87
{
88
struct key_entry *key;
89
90
for (key = dev->keycode; key->type != KE_END; key++)
91
if (key->type == KE_KEY && keycode == key->keycode)
92
return key;
93
94
return NULL;
95
}
96
EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
97
98
static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
99
const struct input_keymap_entry *ke)
100
{
101
struct key_entry *key;
102
unsigned int scancode;
103
104
if (ke->flags & INPUT_KEYMAP_BY_INDEX)
105
key = sparse_keymap_entry_by_index(dev, ke->index);
106
else if (input_scancode_to_scalar(ke, &scancode) == 0)
107
key = sparse_keymap_entry_from_scancode(dev, scancode);
108
else
109
key = NULL;
110
111
return key;
112
}
113
114
static int sparse_keymap_getkeycode(struct input_dev *dev,
115
struct input_keymap_entry *ke)
116
{
117
const struct key_entry *key;
118
119
if (dev->keycode) {
120
key = sparse_keymap_locate(dev, ke);
121
if (key && key->type == KE_KEY) {
122
ke->keycode = key->keycode;
123
if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
124
ke->index =
125
sparse_keymap_get_key_index(dev, key);
126
ke->len = sizeof(key->code);
127
memcpy(ke->scancode, &key->code, sizeof(key->code));
128
return 0;
129
}
130
}
131
132
return -EINVAL;
133
}
134
135
static int sparse_keymap_setkeycode(struct input_dev *dev,
136
const struct input_keymap_entry *ke,
137
unsigned int *old_keycode)
138
{
139
struct key_entry *key;
140
141
if (dev->keycode) {
142
key = sparse_keymap_locate(dev, ke);
143
if (key && key->type == KE_KEY) {
144
*old_keycode = key->keycode;
145
key->keycode = ke->keycode;
146
set_bit(ke->keycode, dev->keybit);
147
if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
148
clear_bit(*old_keycode, dev->keybit);
149
return 0;
150
}
151
}
152
153
return -EINVAL;
154
}
155
156
/**
157
* sparse_keymap_setup - set up sparse keymap for an input device
158
* @dev: Input device
159
* @keymap: Keymap in form of array of &key_entry structures ending
160
* with %KE_END type entry
161
* @setup: Function that can be used to adjust keymap entries
162
* depending on device's deeds, may be %NULL
163
*
164
* The function calculates size and allocates copy of the original
165
* keymap after which sets up input device event bits appropriately.
166
* Before destroying input device allocated keymap should be freed
167
* with a call to sparse_keymap_free().
168
*/
169
int sparse_keymap_setup(struct input_dev *dev,
170
const struct key_entry *keymap,
171
int (*setup)(struct input_dev *, struct key_entry *))
172
{
173
size_t map_size = 1; /* to account for the last KE_END entry */
174
const struct key_entry *e;
175
struct key_entry *map, *entry;
176
int i;
177
int error;
178
179
for (e = keymap; e->type != KE_END; e++)
180
map_size++;
181
182
map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
183
if (!map)
184
return -ENOMEM;
185
186
memcpy(map, keymap, map_size * sizeof (struct key_entry));
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
goto err_out;
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
err_out:
225
kfree(map);
226
return error;
227
}
228
EXPORT_SYMBOL(sparse_keymap_setup);
229
230
/**
231
* sparse_keymap_free - free memory allocated for sparse keymap
232
* @dev: Input device using sparse keymap
233
*
234
* This function is used to free memory allocated by sparse keymap
235
* in an input device that was set up by sparse_keymap_setup().
236
* NOTE: It is safe to cal this function while input device is
237
* still registered (however the drivers should care not to try to
238
* use freed keymap and thus have to shut off interrups/polling
239
* before freeing the keymap).
240
*/
241
void sparse_keymap_free(struct input_dev *dev)
242
{
243
unsigned long flags;
244
245
/*
246
* Take event lock to prevent racing with input_get_keycode()
247
* and input_set_keycode() if we are called while input device
248
* is still registered.
249
*/
250
spin_lock_irqsave(&dev->event_lock, flags);
251
252
kfree(dev->keycode);
253
dev->keycode = NULL;
254
dev->keycodemax = 0;
255
256
spin_unlock_irqrestore(&dev->event_lock, flags);
257
}
258
EXPORT_SYMBOL(sparse_keymap_free);
259
260
/**
261
* sparse_keymap_report_entry - report event corresponding to given key entry
262
* @dev: Input device for which event should be reported
263
* @ke: key entry describing event
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 report input event described by given
270
* &struct key_entry.
271
*/
272
void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
273
unsigned int value, bool autorelease)
274
{
275
switch (ke->type) {
276
case KE_KEY:
277
input_event(dev, EV_MSC, MSC_SCAN, ke->code);
278
input_report_key(dev, ke->keycode, value);
279
input_sync(dev);
280
if (value && autorelease) {
281
input_report_key(dev, ke->keycode, 0);
282
input_sync(dev);
283
}
284
break;
285
286
case KE_SW:
287
value = ke->sw.value;
288
/* fall through */
289
290
case KE_VSW:
291
input_report_switch(dev, ke->sw.code, value);
292
break;
293
}
294
}
295
EXPORT_SYMBOL(sparse_keymap_report_entry);
296
297
/**
298
* sparse_keymap_report_event - report event corresponding to given scancode
299
* @dev: Input device using sparse keymap
300
* @code: Scan code
301
* @value: Value that should be reported (ignored by %KE_SW entries)
302
* @autorelease: Signals whether release event should be emitted for %KE_KEY
303
* entries right after reporting press event, ignored by all other
304
* entries
305
*
306
* This function is used to perform lookup in an input device using sparse
307
* keymap and report corresponding event. Returns %true if lookup was
308
* successful and %false otherwise.
309
*/
310
bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
311
unsigned int value, bool autorelease)
312
{
313
const struct key_entry *ke =
314
sparse_keymap_entry_from_scancode(dev, code);
315
struct key_entry unknown_ke;
316
317
if (ke) {
318
sparse_keymap_report_entry(dev, ke, value, autorelease);
319
return true;
320
}
321
322
/* Report an unknown key event as a debugging aid */
323
unknown_ke.type = KE_KEY;
324
unknown_ke.code = code;
325
unknown_ke.keycode = KEY_UNKNOWN;
326
sparse_keymap_report_entry(dev, &unknown_ke, value, true);
327
328
return false;
329
}
330
EXPORT_SYMBOL(sparse_keymap_report_event);
331
332
333