diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-11-27 20:01:23 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-12-05 15:42:19 -0500 |
commit | ef53a1159dfcdc1fecf5adb5b8d26803f194c09b (patch) | |
tree | 34e477e3db2a69c6cfa6607933f552c2c89d952b /drivers/media | |
parent | 4e89217b943cfb26f88f04920d44f2077931f0e7 (diff) |
V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table
V4L drivers use an static keycode vector with 128 entries, where the scancode
indexes the keycode. While this works, it limits the scancodes to have only
7 bits, not allowing for example full RC5 codes.
Instead of implementing the same code on every V4L driver, provide a common
infrastructure to handle the bigger tables, minimizing the changes inside
each driver.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/common/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/common/ir-keytable.c | 156 |
2 files changed, 157 insertions, 1 deletions
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 351b98b9b302..169b337b7c9d 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | saa7146-objs := saa7146_i2c.o saa7146_core.o | 1 | saa7146-objs := saa7146_i2c.o saa7146_core.o |
2 | saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o | 2 | saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o |
3 | ir-common-objs := ir-functions.o ir-keymaps.o | 3 | ir-common-objs := ir-functions.o ir-keymaps.o ir-keytable.o |
4 | 4 | ||
5 | obj-y += tuners/ | 5 | obj-y += tuners/ |
6 | obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o | 6 | obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o |
diff --git a/drivers/media/common/ir-keytable.c b/drivers/media/common/ir-keytable.c new file mode 100644 index 000000000000..2de7caeef437 --- /dev/null +++ b/drivers/media/common/ir-keytable.c | |||
@@ -0,0 +1,156 @@ | |||
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); | ||