]> git.karo-electronics.de Git - linux-beck.git/blob - drivers/media/common/ir-keytable.c
V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table
[linux-beck.git] / drivers / media / common / ir-keytable.c
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 /**
11  * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
12  * @dev:        the struct input_dev device descriptor
13  * @scancode:   the desired scancode
14  * @keycode:    the keycode to be retorned.
15  *
16  * This routine is used to handle evdev EVIOCGKEY ioctl.
17  * If the key is not found, returns -EINVAL, otherwise, returns 0.
18  */
19 static int ir_getkeycode(struct input_dev *dev,
20                          int scancode, int *keycode)
21 {
22         int i;
23         struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
24         struct ir_scancode *keymap = rc_tab->scan;
25
26         /* See if we can match the raw key code. */
27         for (i = 0; i < rc_tab->size; i++)
28                 if (keymap[i].scancode == scancode) {
29                         *keycode = keymap[i].keycode;
30                         return 0;
31                 }
32
33         /*
34          * If is there extra space, returns KEY_RESERVED,
35          * otherwise, input core won't let ir_setkeycode
36          * to work
37          */
38         for (i = 0; i < rc_tab->size; i++)
39                 if (keymap[i].keycode == KEY_RESERVED ||
40                     keymap[i].keycode == KEY_UNKNOWN) {
41                         *keycode = KEY_RESERVED;
42                         return 0;
43                 }
44
45         return -EINVAL;
46 }
47
48 /**
49  * ir_setkeycode() - set a keycode at the evdev scancode ->keycode table
50  * @dev:        the struct input_dev device descriptor
51  * @scancode:   the desired scancode
52  * @keycode:    the keycode to be retorned.
53  *
54  * This routine is used to handle evdev EVIOCSKEY ioctl.
55  * There's one caveat here: how can we increase the size of the table?
56  * If the key is not found, returns -EINVAL, otherwise, returns 0.
57  */
58 static int ir_setkeycode(struct input_dev *dev,
59                          int scancode, int keycode)
60 {
61         int i;
62         struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
63         struct ir_scancode *keymap = rc_tab->scan;
64
65         /* Search if it is replacing an existing keycode */
66         for (i = 0; i < rc_tab->size; i++)
67                 if (keymap[i].scancode == scancode) {
68                         keymap[i].keycode = keycode;
69                         return 0;
70                 }
71
72         /* Search if is there a clean entry. If so, use it */
73         for (i = 0; i < rc_tab->size; i++)
74                 if (keymap[i].keycode == KEY_RESERVED ||
75                     keymap[i].keycode == KEY_UNKNOWN) {
76                         keymap[i].scancode = scancode;
77                         keymap[i].keycode = keycode;
78                         return 0;
79                 }
80
81         /*
82          * FIXME: Currently, it is not possible to increase the size of
83          * scancode table. For it to happen, one possibility
84          * would be to allocate a table with key_map_size + 1,
85          * copying data, appending the new key on it, and freeing
86          * the old one - or maybe just allocating some spare space
87          */
88
89         return -EINVAL;
90 }
91
92 /**
93  * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
94  * @rc_tab:     the ir_scancode_table with the keymap to be used
95  * @scancode:   the scancode that we're seeking
96  *
97  * This routine is used by the input routines when a key is pressed at the
98  * IR. The scancode is received and needs to be converted into a keycode.
99  * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
100  * corresponding keycode from the table.
101  */
102 u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
103 {
104         int i;
105         struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
106         struct ir_scancode *keymap = rc_tab->scan;
107
108         for (i = 0; i < rc_tab->size; i++)
109                 if (keymap[i].scancode == scancode) {
110                         IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
111                                 dev->name, scancode, keymap[i].keycode);
112
113                         return keymap[i].keycode;
114                 }
115
116         printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n",
117                dev->name, scancode);
118
119         return KEY_UNKNOWN;
120 }
121 EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
122
123 /**
124  * ir_set_keycode_table() - sets the IR keycode table and add the handlers
125  *                          for keymap table get/set
126  * @input_dev:  the struct input_dev descriptor of the device
127  * @rc_tab:     the struct ir_scancode_table table of scancode/keymap
128  *
129  * This routine is used to initialize the input infrastructure to work with
130  * an IR. It requires that the caller initializes the input_dev struct with
131  * some fields: name,
132  */
133 int ir_set_keycode_table(struct input_dev *input_dev,
134                          struct ir_scancode_table *rc_tab)
135 {
136         struct ir_scancode *keymap = rc_tab->scan;
137         int i;
138
139         if (rc_tab->scan == NULL || !rc_tab->size)
140                 return -EINVAL;
141
142         /* set the bits for the keys */
143         IR_dprintk(1, "key map size: %d\n", rc_tab->size);
144         for (i = 0; i < rc_tab->size; i++) {
145                 IR_dprintk(1, "#%d: setting bit for keycode 0x%04x\n",
146                         i, keymap[i].keycode);
147                 set_bit(keymap[i].keycode, input_dev->keybit);
148         }
149
150         input_dev->getkeycode = ir_getkeycode;
151         input_dev->setkeycode = ir_setkeycode;
152         input_set_drvdata(input_dev, rc_tab);
153
154         return 0;
155 }
156 EXPORT_SYMBOL_GPL(ir_set_keycode_table);