aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/IR/ir-keytable.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-12-11 06:00:00 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-15 21:18:42 -0500
commite27d38112eb727df189a9ebf560aa104cb102253 (patch)
tree454d8cff41ebe8027ecd74d809ed415e427782b3 /drivers/media/IR/ir-keytable.c
parent909d15a70d6a269ba599c539c55a574482355ff1 (diff)
V4L/DVB (13612): IR: Move common IR code to drivers/media/IR
This is the first step of creating a common code for IR that can be used by other input devices. For now, keep IR dir at drivers/media, to easy the movement of the IR files, but later patches may move it to drivers/IR or drivers/input/IR. No functional changes is done on this patch. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/ir-keytable.c')
-rw-r--r--drivers/media/IR/ir-keytable.c433
1 files changed, 433 insertions, 0 deletions
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
new file mode 100644
index 000000000000..99ed2deceef3
--- /dev/null
+++ b/drivers/media/IR/ir-keytable.c
@@ -0,0 +1,433 @@
1/* ir-register.c - handle IR scancode->keycode tables
2 *
3 * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 */
5
6#include <linux/usb/input.h>
7
8#include <media/ir-common.h>
9
10#define IR_TAB_MIN_SIZE 32
11#define IR_TAB_MAX_SIZE 1024
12
13
14/**
15 * ir_seek_table() - returns the element order on the table
16 * @rc_tab: the ir_scancode_table with the keymap to be used
17 * @scancode: the scancode that we're seeking
18 *
19 * This routine is used by the input routines when a key is pressed at the
20 * IR. The scancode is received and needs to be converted into a keycode.
21 * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
22 * corresponding keycode from the table.
23 */
24static int ir_seek_table(struct ir_scancode_table *rc_tab, u32 scancode)
25{
26 int rc;
27 unsigned long flags;
28 struct ir_scancode *keymap = rc_tab->scan;
29
30 spin_lock_irqsave(&rc_tab->lock, flags);
31
32 /* FIXME: replace it by a binary search */
33
34 for (rc = 0; rc < rc_tab->size; rc++)
35 if (keymap[rc].scancode == scancode)
36 goto exit;
37
38 /* Not found */
39 rc = -EINVAL;
40
41exit:
42 spin_unlock_irqrestore(&rc_tab->lock, flags);
43 return rc;
44}
45
46/**
47 * ir_roundup_tablesize() - gets an optimum value for the table size
48 * @n_elems: minimum number of entries to store keycodes
49 *
50 * This routine is used to choose the keycode table size.
51 *
52 * In order to have some empty space for new keycodes,
53 * and knowing in advance that kmalloc allocates only power of two
54 * segments, it optimizes the allocated space to have some spare space
55 * for those new keycodes by using the maximum number of entries that
56 * will be effectively be allocated by kmalloc.
57 * In order to reduce the quantity of table resizes, it has a minimum
58 * table size of IR_TAB_MIN_SIZE.
59 */
60int ir_roundup_tablesize(int n_elems)
61{
62 size_t size;
63
64 if (n_elems < IR_TAB_MIN_SIZE)
65 n_elems = IR_TAB_MIN_SIZE;
66
67 /*
68 * As kmalloc only allocates sizes of power of two, get as
69 * much entries as possible for the allocated memory segment
70 */
71 size = roundup_pow_of_two(n_elems * sizeof(struct ir_scancode));
72 n_elems = size / sizeof(struct ir_scancode);
73
74 return n_elems;
75}
76
77/**
78 * ir_copy_table() - copies a keytable, discarding the unused entries
79 * @destin: destin table
80 * @origin: origin table
81 *
82 * Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED
83 */
84
85int ir_copy_table(struct ir_scancode_table *destin,
86 const struct ir_scancode_table *origin)
87{
88 int i, j = 0;
89
90 for (i = 0; i < origin->size; i++) {
91 if (origin->scan[i].keycode == KEY_UNKNOWN ||
92 origin->scan[i].keycode == KEY_RESERVED)
93 continue;
94
95 memcpy(&destin->scan[j], &origin->scan[i], sizeof(struct ir_scancode));
96 j++;
97 }
98 destin->size = j;
99
100 IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
101
102 return 0;
103}
104
105/**
106 * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
107 * @dev: the struct input_dev device descriptor
108 * @scancode: the desired scancode
109 * @keycode: the keycode to be retorned.
110 *
111 * This routine is used to handle evdev EVIOCGKEY ioctl.
112 * If the key is not found, returns -EINVAL, otherwise, returns 0.
113 */
114static int ir_getkeycode(struct input_dev *dev,
115 int scancode, int *keycode)
116{
117 int elem;
118 struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
119
120 elem = ir_seek_table(rc_tab, scancode);
121 if (elem >= 0) {
122 *keycode = rc_tab->scan[elem].keycode;
123 return 0;
124 }
125
126 /*
127 * Scancode not found and table can't be expanded
128 */
129 if (elem < 0 && rc_tab->size == IR_TAB_MAX_SIZE)
130 return -EINVAL;
131
132 /*
133 * If is there extra space, returns KEY_RESERVED,
134 * otherwise, input core won't let ir_setkeycode to work
135 */
136 *keycode = KEY_RESERVED;
137 return 0;
138}
139
140
141/**
142 * ir_is_resize_needed() - Check if the table needs rezise
143 * @table: keycode table that may need to resize
144 * @n_elems: minimum number of entries to store keycodes
145 *
146 * Considering that kmalloc uses power of two storage areas, this
147 * routine detects if the real alloced size will change. If not, it
148 * just returns without doing nothing. Otherwise, it will extend or
149 * reduce the table size to meet the new needs.
150 *
151 * It returns 0 if no resize is needed, 1 otherwise.
152 */
153static int ir_is_resize_needed(struct ir_scancode_table *table, int n_elems)
154{
155 int cur_size = ir_roundup_tablesize(table->size);
156 int new_size = ir_roundup_tablesize(n_elems);
157
158 if (cur_size == new_size)
159 return 0;
160
161 /* Resize is needed */
162 return 1;
163}
164
165/**
166 * ir_delete_key() - remove a keycode from the table
167 * @rc_tab: keycode table
168 * @elem: element to be removed
169 *
170 */
171static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem)
172{
173 unsigned long flags = 0;
174 int newsize = rc_tab->size - 1;
175 int resize = ir_is_resize_needed(rc_tab, newsize);
176 struct ir_scancode *oldkeymap = rc_tab->scan;
177 struct ir_scancode *newkeymap;
178
179 if (resize) {
180 newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
181 sizeof(*newkeymap), GFP_ATOMIC);
182
183 /* There's no memory for resize. Keep the old table */
184 if (!newkeymap)
185 resize = 0;
186 }
187
188 if (!resize) {
189 newkeymap = oldkeymap;
190
191 /* We'll modify the live table. Lock it */
192 spin_lock_irqsave(&rc_tab->lock, flags);
193 }
194
195 /*
196 * Copy the elements before the one that will be deleted
197 * if (!resize), both oldkeymap and newkeymap points
198 * to the same place, so, there's no need to copy
199 */
200 if (resize && elem > 0)
201 memcpy(newkeymap, oldkeymap,
202 elem * sizeof(*newkeymap));
203
204 /*
205 * Copy the other elements overwriting the element to be removed
206 * This operation applies to both resize and non-resize case
207 */
208 if (elem < newsize)
209 memcpy(&newkeymap[elem], &oldkeymap[elem + 1],
210 (newsize - elem) * sizeof(*newkeymap));
211
212 if (resize) {
213 /*
214 * As the copy happened to a temporary table, only here
215 * it needs to lock while replacing the table pointers
216 * to use the new table
217 */
218 spin_lock_irqsave(&rc_tab->lock, flags);
219 rc_tab->size = newsize;
220 rc_tab->scan = newkeymap;
221 spin_unlock_irqrestore(&rc_tab->lock, flags);
222
223 /* Frees the old keytable */
224 kfree(oldkeymap);
225 } else {
226 rc_tab->size = newsize;
227 spin_unlock_irqrestore(&rc_tab->lock, flags);
228 }
229}
230
231/**
232 * ir_insert_key() - insert a keycode at the table
233 * @rc_tab: keycode table
234 * @scancode: the desired scancode
235 * @keycode: the keycode to be retorned.
236 *
237 */
238static int ir_insert_key(struct ir_scancode_table *rc_tab,
239 int scancode, int keycode)
240{
241 unsigned long flags;
242 int elem = rc_tab->size;
243 int newsize = rc_tab->size + 1;
244 int resize = ir_is_resize_needed(rc_tab, newsize);
245 struct ir_scancode *oldkeymap = rc_tab->scan;
246 struct ir_scancode *newkeymap;
247
248 if (resize) {
249 newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
250 sizeof(*newkeymap), GFP_ATOMIC);
251 if (!newkeymap)
252 return -ENOMEM;
253
254 memcpy(newkeymap, oldkeymap,
255 rc_tab->size * sizeof(*newkeymap));
256 } else
257 newkeymap = oldkeymap;
258
259 /* Stores the new code at the table */
260 IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
261 rc_tab->size, scancode, keycode);
262
263 spin_lock_irqsave(&rc_tab->lock, flags);
264 rc_tab->size = newsize;
265 if (resize) {
266 rc_tab->scan = newkeymap;
267 kfree(oldkeymap);
268 }
269 newkeymap[elem].scancode = scancode;
270 newkeymap[elem].keycode = keycode;
271 spin_unlock_irqrestore(&rc_tab->lock, flags);
272
273 return 0;
274}
275
276/**
277 * ir_setkeycode() - set a keycode at the evdev scancode ->keycode table
278 * @dev: the struct input_dev device descriptor
279 * @scancode: the desired scancode
280 * @keycode: the keycode to be retorned.
281 *
282 * This routine is used to handle evdev EVIOCSKEY ioctl.
283 * There's one caveat here: how can we increase the size of the table?
284 * If the key is not found, returns -EINVAL, otherwise, returns 0.
285 */
286static int ir_setkeycode(struct input_dev *dev,
287 int scancode, int keycode)
288{
289 int rc = 0;
290 struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
291 struct ir_scancode *keymap = rc_tab->scan;
292 unsigned long flags;
293
294 /*
295 * Handle keycode table deletions
296 *
297 * If userspace is adding a KEY_UNKNOWN or KEY_RESERVED,
298 * deal as a trial to remove an existing scancode attribution
299 * if table become too big, reduce it to save space
300 */
301 if (keycode == KEY_UNKNOWN || keycode == KEY_RESERVED) {
302 rc = ir_seek_table(rc_tab, scancode);
303 if (rc < 0)
304 return 0;
305
306 IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", rc, scancode);
307 clear_bit(keymap[rc].keycode, dev->keybit);
308 ir_delete_key(rc_tab, rc);
309
310 return 0;
311 }
312
313 /*
314 * Handle keycode replacements
315 *
316 * If the scancode exists, just replace by the new value
317 */
318 rc = ir_seek_table(rc_tab, scancode);
319 if (rc >= 0) {
320 IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
321 rc, scancode, keycode);
322
323 clear_bit(keymap[rc].keycode, dev->keybit);
324
325 spin_lock_irqsave(&rc_tab->lock, flags);
326 keymap[rc].keycode = keycode;
327 spin_unlock_irqrestore(&rc_tab->lock, flags);
328
329 set_bit(keycode, dev->keybit);
330
331 return 0;
332 }
333
334 /*
335 * Handle new scancode inserts
336 *
337 * reallocate table if needed and insert a new keycode
338 */
339
340 /* Avoid growing the table indefinitely */
341 if (rc_tab->size + 1 > IR_TAB_MAX_SIZE)
342 return -EINVAL;
343
344 rc = ir_insert_key(rc_tab, scancode, keycode);
345 if (rc < 0)
346 return rc;
347 set_bit(keycode, dev->keybit);
348
349 return 0;
350}
351
352/**
353 * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
354 * @input_dev: the struct input_dev descriptor of the device
355 * @scancode: the scancode that we're seeking
356 *
357 * This routine is used by the input routines when a key is pressed at the
358 * IR. The scancode is received and needs to be converted into a keycode.
359 * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
360 * corresponding keycode from the table.
361 */
362u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
363{
364 struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
365 struct ir_scancode *keymap = rc_tab->scan;
366 int elem;
367
368 elem = ir_seek_table(rc_tab, scancode);
369 if (elem >= 0) {
370 IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
371 dev->name, scancode, keymap[elem].keycode);
372
373 return rc_tab->scan[elem].keycode;
374 }
375
376 printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n",
377 dev->name, scancode);
378
379 /* Reports userspace that an unknown keycode were got */
380 return KEY_RESERVED;
381}
382
383/**
384 * ir_set_keycode_table() - sets the IR keycode table and add the handlers
385 * for keymap table get/set
386 * @input_dev: the struct input_dev descriptor of the device
387 * @rc_tab: the struct ir_scancode_table table of scancode/keymap
388 *
389 * This routine is used to initialize the input infrastructure to work with
390 * an IR.
391 * It should be called before registering the IR device.
392 */
393int ir_set_keycode_table(struct input_dev *input_dev,
394 struct ir_scancode_table *rc_tab)
395{
396 struct ir_scancode *keymap = rc_tab->scan;
397 int i;
398
399 spin_lock_init(&rc_tab->lock);
400
401 if (rc_tab->scan == NULL || !rc_tab->size)
402 return -EINVAL;
403
404 /* set the bits for the keys */
405 IR_dprintk(1, "key map size: %d\n", rc_tab->size);
406 for (i = 0; i < rc_tab->size; i++) {
407 IR_dprintk(1, "#%d: setting bit for keycode 0x%04x\n",
408 i, keymap[i].keycode);
409 set_bit(keymap[i].keycode, input_dev->keybit);
410 }
411
412 input_dev->getkeycode = ir_getkeycode;
413 input_dev->setkeycode = ir_setkeycode;
414 input_set_drvdata(input_dev, rc_tab);
415
416 return 0;
417}
418
419void ir_input_free(struct input_dev *dev)
420{
421 struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
422
423 if (!rc_tab)
424 return;
425
426 IR_dprintk(1, "Freed keycode table\n");
427
428 rc_tab->size = 0;
429 kfree(rc_tab->scan);
430 rc_tab->scan = NULL;
431}
432EXPORT_SYMBOL_GPL(ir_input_free);
433