Blame view

drivers/input/sparse-keymap.c 8.58 KB
36203c4f3   Dmitry Torokhov   Input: add generi...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * Generic support for sparse keymaps
   *
   * Copyright (c) 2009 Dmitry Torokhov
   *
   * Derived from wistron button driver:
   * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
   * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
   * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published by
   * the Free Software Foundation.
   */
  
  #include <linux/input.h>
  #include <linux/input/sparse-keymap.h>
d2d8442d0   Paul Gortmaker   drivers/input: Ad...
18
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
36203c4f3   Dmitry Torokhov   Input: add generi...
20
21
22
23
24
  
  MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
  MODULE_DESCRIPTION("Generic support for sparse keymaps");
  MODULE_LICENSE("GPL v2");
  MODULE_VERSION("0.1");
67127f306   Dmitry Torokhov   Input: sparse-key...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  static unsigned int sparse_keymap_get_key_index(struct input_dev *dev,
  						const struct key_entry *k)
  {
  	struct key_entry *key;
  	unsigned int idx = 0;
  
  	for (key = dev->keycode; key->type != KE_END; key++) {
  		if (key->type == KE_KEY) {
  			if (key == k)
  				break;
  			idx++;
  		}
  	}
  
  	return idx;
  }
  
  static struct key_entry *sparse_keymap_entry_by_index(struct input_dev *dev,
  						      unsigned int index)
  {
  	struct key_entry *key;
  	unsigned int key_cnt = 0;
  
  	for (key = dev->keycode; key->type != KE_END; key++)
  		if (key->type == KE_KEY)
  			if (key_cnt++ == index)
  				return key;
  
  	return NULL;
  }
36203c4f3   Dmitry Torokhov   Input: add generi...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  /**
   * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
   * @dev: Input device using sparse keymap
   * @code: Scan code
   *
   * This function is used to perform &struct key_entry lookup in an
   * input device using sparse keymap.
   */
  struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
  						    unsigned int code)
  {
  	struct key_entry *key;
  
  	for (key = dev->keycode; key->type != KE_END; key++)
  		if (code == key->code)
  			return key;
  
  	return NULL;
  }
  EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
  
  /**
   * sparse_keymap_entry_from_keycode - perform sparse keymap lookup
   * @dev: Input device using sparse keymap
   * @keycode: Key code
   *
   * This function is used to perform &struct key_entry lookup in an
   * input device using sparse keymap.
   */
  struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
  						   unsigned int keycode)
  {
  	struct key_entry *key;
  
  	for (key = dev->keycode; key->type != KE_END; key++)
  		if (key->type == KE_KEY && keycode == key->keycode)
  			return key;
  
  	return NULL;
  }
  EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
67127f306   Dmitry Torokhov   Input: sparse-key...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  static struct key_entry *sparse_keymap_locate(struct input_dev *dev,
  					const struct input_keymap_entry *ke)
  {
  	struct key_entry *key;
  	unsigned int scancode;
  
  	if (ke->flags & INPUT_KEYMAP_BY_INDEX)
  		key = sparse_keymap_entry_by_index(dev, ke->index);
  	else if (input_scancode_to_scalar(ke, &scancode) == 0)
  		key = sparse_keymap_entry_from_scancode(dev, scancode);
  	else
  		key = NULL;
  
  	return key;
  }
36203c4f3   Dmitry Torokhov   Input: add generi...
111
  static int sparse_keymap_getkeycode(struct input_dev *dev,
67127f306   Dmitry Torokhov   Input: sparse-key...
112
  				    struct input_keymap_entry *ke)
36203c4f3   Dmitry Torokhov   Input: add generi...
113
  {
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
114
  	const struct key_entry *key;
36203c4f3   Dmitry Torokhov   Input: add generi...
115

2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
116
  	if (dev->keycode) {
67127f306   Dmitry Torokhov   Input: sparse-key...
117
  		key = sparse_keymap_locate(dev, ke);
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
118
  		if (key && key->type == KE_KEY) {
67127f306   Dmitry Torokhov   Input: sparse-key...
119
120
121
122
123
124
  			ke->keycode = key->keycode;
  			if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
  				ke->index =
  					sparse_keymap_get_key_index(dev, key);
  			ke->len = sizeof(key->code);
  			memcpy(ke->scancode, &key->code, sizeof(key->code));
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
125
126
  			return 0;
  		}
36203c4f3   Dmitry Torokhov   Input: add generi...
127
128
129
130
131
132
  	}
  
  	return -EINVAL;
  }
  
  static int sparse_keymap_setkeycode(struct input_dev *dev,
67127f306   Dmitry Torokhov   Input: sparse-key...
133
134
  				    const struct input_keymap_entry *ke,
  				    unsigned int *old_keycode)
36203c4f3   Dmitry Torokhov   Input: add generi...
135
136
  {
  	struct key_entry *key;
36203c4f3   Dmitry Torokhov   Input: add generi...
137

2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
138
  	if (dev->keycode) {
67127f306   Dmitry Torokhov   Input: sparse-key...
139
  		key = sparse_keymap_locate(dev, ke);
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
140
  		if (key && key->type == KE_KEY) {
67127f306   Dmitry Torokhov   Input: sparse-key...
141
142
143
144
145
  			*old_keycode = key->keycode;
  			key->keycode = ke->keycode;
  			set_bit(ke->keycode, dev->keybit);
  			if (!sparse_keymap_entry_from_keycode(dev, *old_keycode))
  				clear_bit(*old_keycode, dev->keybit);
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
146
147
  			return 0;
  		}
36203c4f3   Dmitry Torokhov   Input: add generi...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  	}
  
  	return -EINVAL;
  }
  
  /**
   * sparse_keymap_setup - set up sparse keymap for an input device
   * @dev: Input device
   * @keymap: Keymap in form of array of &key_entry structures ending
   *	with %KE_END type entry
   * @setup: Function that can be used to adjust keymap entries
   *	depending on device's deeds, may be %NULL
   *
   * The function calculates size and allocates copy of the original
   * keymap after which sets up input device event bits appropriately.
   * Before destroying input device allocated keymap should be freed
   * with a call to sparse_keymap_free().
   */
  int sparse_keymap_setup(struct input_dev *dev,
  			const struct key_entry *keymap,
  			int (*setup)(struct input_dev *, struct key_entry *))
  {
  	size_t map_size = 1; /* to account for the last KE_END entry */
  	const struct key_entry *e;
  	struct key_entry *map, *entry;
  	int i;
  	int error;
  
  	for (e = keymap; e->type != KE_END; e++)
  		map_size++;
  
  	map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
  	if (!map)
  		return -ENOMEM;
  
  	memcpy(map, keymap, map_size * sizeof (struct key_entry));
  
  	for (i = 0; i < map_size; i++) {
  		entry = &map[i];
  
  		if (setup) {
  			error = setup(dev, entry);
  			if (error)
  				goto err_out;
  		}
  
  		switch (entry->type) {
  		case KE_KEY:
  			__set_bit(EV_KEY, dev->evbit);
  			__set_bit(entry->keycode, dev->keybit);
  			break;
  
  		case KE_SW:
cb1b14592   Dmitry Torokhov   Input: sparse-key...
201
  		case KE_VSW:
36203c4f3   Dmitry Torokhov   Input: add generi...
202
203
204
205
206
  			__set_bit(EV_SW, dev->evbit);
  			__set_bit(entry->sw.code, dev->swbit);
  			break;
  		}
  	}
f3cf5c4fe   Seth Forshee   Input: sparse-key...
207
  	if (test_bit(EV_KEY, dev->evbit)) {
170531bae   Seth Forshee   Input: sparse-key...
208
  		__set_bit(KEY_UNKNOWN, dev->keybit);
f3cf5c4fe   Seth Forshee   Input: sparse-key...
209
210
211
  		__set_bit(EV_MSC, dev->evbit);
  		__set_bit(MSC_SCAN, dev->mscbit);
  	}
36203c4f3   Dmitry Torokhov   Input: add generi...
212
213
  	dev->keycode = map;
  	dev->keycodemax = map_size;
aebd636bd   Dmitry Torokhov   Input: switch com...
214
215
  	dev->getkeycode = sparse_keymap_getkeycode;
  	dev->setkeycode = sparse_keymap_setkeycode;
36203c4f3   Dmitry Torokhov   Input: add generi...
216
217
218
219
  
  	return 0;
  
   err_out:
88fcf710c   Yong Wang   Input: sparse-key...
220
  	kfree(map);
36203c4f3   Dmitry Torokhov   Input: add generi...
221
  	return error;
36203c4f3   Dmitry Torokhov   Input: add generi...
222
223
224
225
226
227
228
229
230
  }
  EXPORT_SYMBOL(sparse_keymap_setup);
  
  /**
   * sparse_keymap_free - free memory allocated for sparse keymap
   * @dev: Input device using sparse keymap
   *
   * This function is used to free memory allocated by sparse keymap
   * in an input device that was set up by sparse_keymap_setup().
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
231
232
233
234
   * NOTE: It is safe to cal this function while input device is
   * still registered (however the drivers should care not to try to
   * use freed keymap and thus have to shut off interrups/polling
   * before freeing the keymap).
36203c4f3   Dmitry Torokhov   Input: add generi...
235
236
237
   */
  void sparse_keymap_free(struct input_dev *dev)
  {
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
238
239
240
241
242
243
244
245
  	unsigned long flags;
  
  	/*
  	 * Take event lock to prevent racing with input_get_keycode()
  	 * and input_set_keycode() if we are called while input device
  	 * is still registered.
  	 */
  	spin_lock_irqsave(&dev->event_lock, flags);
36203c4f3   Dmitry Torokhov   Input: add generi...
246
247
248
  	kfree(dev->keycode);
  	dev->keycode = NULL;
  	dev->keycodemax = 0;
2e2e3b96d   Dmitry Torokhov   Input: sparse-key...
249
250
  
  	spin_unlock_irqrestore(&dev->event_lock, flags);
36203c4f3   Dmitry Torokhov   Input: add generi...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  }
  EXPORT_SYMBOL(sparse_keymap_free);
  
  /**
   * sparse_keymap_report_entry - report event corresponding to given key entry
   * @dev: Input device for which event should be reported
   * @ke: key entry describing event
   * @value: Value that should be reported (ignored by %KE_SW entries)
   * @autorelease: Signals whether release event should be emitted for %KE_KEY
   *	entries right after reporting press event, ignored by all other
   *	entries
   *
   * This function is used to report input event described by given
   * &struct key_entry.
   */
  void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
  				unsigned int value, bool autorelease)
  {
  	switch (ke->type) {
  	case KE_KEY:
f3cf5c4fe   Seth Forshee   Input: sparse-key...
271
  		input_event(dev, EV_MSC, MSC_SCAN, ke->code);
36203c4f3   Dmitry Torokhov   Input: add generi...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  		input_report_key(dev, ke->keycode, value);
  		input_sync(dev);
  		if (value && autorelease) {
  			input_report_key(dev, ke->keycode, 0);
  			input_sync(dev);
  		}
  		break;
  
  	case KE_SW:
  		value = ke->sw.value;
  		/* fall through */
  
  	case KE_VSW:
  		input_report_switch(dev, ke->sw.code, value);
  		break;
  	}
  }
  EXPORT_SYMBOL(sparse_keymap_report_entry);
  
  /**
   * sparse_keymap_report_event - report event corresponding to given scancode
   * @dev: Input device using sparse keymap
   * @code: Scan code
   * @value: Value that should be reported (ignored by %KE_SW entries)
   * @autorelease: Signals whether release event should be emitted for %KE_KEY
   *	entries right after reporting press event, ignored by all other
   *	entries
   *
   * This function is used to perform lookup in an input device using sparse
   * keymap and report corresponding event. Returns %true if lookup was
   * successful and %false otherwise.
   */
  bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
  				unsigned int value, bool autorelease)
  {
  	const struct key_entry *ke =
  		sparse_keymap_entry_from_scancode(dev, code);
170531bae   Seth Forshee   Input: sparse-key...
309
  	struct key_entry unknown_ke;
36203c4f3   Dmitry Torokhov   Input: add generi...
310
311
312
313
314
  
  	if (ke) {
  		sparse_keymap_report_entry(dev, ke, value, autorelease);
  		return true;
  	}
170531bae   Seth Forshee   Input: sparse-key...
315
316
317
318
319
  	/* Report an unknown key event as a debugging aid */
  	unknown_ke.type = KE_KEY;
  	unknown_ke.code = code;
  	unknown_ke.keycode = KEY_UNKNOWN;
  	sparse_keymap_report_entry(dev, &unknown_ke, value, true);
36203c4f3   Dmitry Torokhov   Input: add generi...
320
321
322
  	return false;
  }
  EXPORT_SYMBOL(sparse_keymap_report_event);