aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-12-04 13:22:23 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-12-07 12:26:35 -0500
commit36203c4f3d091b5f6c082663bd1f74273798043a (patch)
treebf5b6efee8f15aae253155263038ac538f7482e9 /drivers/input
parent6a47081c37b7dd7810ce19e156c1a3bf11987e9a (diff)
Input: add generic support for sparse keymaps
More and more devices choose to reimplement support for sparse keymaps first introduced by wistron driver. Move it into a library module so it can be easily used by interested parties. Reviewed-by: Anisse Astier <anisse@astier.eu> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Kconfig28
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/input-polldev.c14
-rw-r--r--drivers/input/sparse-keymap.c250
4 files changed, 281 insertions, 12 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index cd50c00ab20f..50af91ebd075 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -8,7 +8,7 @@ menu "Input device support"
8config INPUT 8config INPUT
9 tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED 9 tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
10 default y 10 default y
11 ---help--- 11 help
12 Say Y here if you have any input device (mouse, keyboard, tablet, 12 Say Y here if you have any input device (mouse, keyboard, tablet,
13 joystick, steering wheel ...) connected to your system and want 13 joystick, steering wheel ...) connected to your system and want
14 it to be available to applications. This includes standard PS/2 14 it to be available to applications. This includes standard PS/2
@@ -27,8 +27,7 @@ if INPUT
27 27
28config INPUT_FF_MEMLESS 28config INPUT_FF_MEMLESS
29 tristate "Support for memoryless force-feedback devices" 29 tristate "Support for memoryless force-feedback devices"
30 default n 30 help
31 ---help---
32 Say Y here if you have memoryless force-feedback input device 31 Say Y here if you have memoryless force-feedback input device
33 such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual 32 such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual
34 Power 2, or similar. You will also need to enable hardware-specific 33 Power 2, or similar. You will also need to enable hardware-specific
@@ -52,12 +51,25 @@ config INPUT_POLLDEV
52 To compile this driver as a module, choose M here: the 51 To compile this driver as a module, choose M here: the
53 module will be called input-polldev. 52 module will be called input-polldev.
54 53
54config INPUT_SPARSEKMAP
55 tristate "Sparse keymap support library"
56 help
57 Say Y here if you are using a driver for an input
58 device that uses sparse keymap. This option is only
59 useful for out-of-tree drivers since in-tree drivers
60 select it automatically.
61
62 If unsure, say N.
63
64 To compile this driver as a module, choose M here: the
65 module will be called sparse-keymap.
66
55comment "Userland interfaces" 67comment "Userland interfaces"
56 68
57config INPUT_MOUSEDEV 69config INPUT_MOUSEDEV
58 tristate "Mouse interface" if EMBEDDED 70 tristate "Mouse interface" if EMBEDDED
59 default y 71 default y
60 ---help--- 72 help
61 Say Y here if you want your mouse to be accessible as char devices 73 Say Y here if you want your mouse to be accessible as char devices
62 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an 74 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
63 emulated IntelliMouse Explorer PS/2 mouse. That way, all user space 75 emulated IntelliMouse Explorer PS/2 mouse. That way, all user space
@@ -73,7 +85,7 @@ config INPUT_MOUSEDEV_PSAUX
73 bool "Provide legacy /dev/psaux device" 85 bool "Provide legacy /dev/psaux device"
74 default y 86 default y
75 depends on INPUT_MOUSEDEV 87 depends on INPUT_MOUSEDEV
76 ---help--- 88 help
77 Say Y here if you want your mouse also be accessible as char device 89 Say Y here if you want your mouse also be accessible as char device
78 10:1 - /dev/psaux. The data available through /dev/psaux is exactly 90 10:1 - /dev/psaux. The data available through /dev/psaux is exactly
79 the same as the data from /dev/input/mice. 91 the same as the data from /dev/input/mice.
@@ -103,7 +115,7 @@ config INPUT_MOUSEDEV_SCREEN_Y
103 115
104config INPUT_JOYDEV 116config INPUT_JOYDEV
105 tristate "Joystick interface" 117 tristate "Joystick interface"
106 ---help--- 118 help
107 Say Y here if you want your joystick or gamepad to be 119 Say Y here if you want your joystick or gamepad to be
108 accessible as char device 13:0+ - /dev/input/jsX device. 120 accessible as char device 13:0+ - /dev/input/jsX device.
109 121
@@ -125,7 +137,7 @@ config INPUT_EVDEV
125 137
126config INPUT_EVBUG 138config INPUT_EVBUG
127 tristate "Event debugging" 139 tristate "Event debugging"
128 ---help--- 140 help
129 Say Y here if you have a problem with the input subsystem and 141 Say Y here if you have a problem with the input subsystem and
130 want all events (keypresses, mouse movements), to be output to 142 want all events (keypresses, mouse movements), to be output to
131 the system log. While this is useful for debugging, it's also 143 the system log. While this is useful for debugging, it's also
@@ -140,7 +152,7 @@ config INPUT_EVBUG
140config INPUT_APMPOWER 152config INPUT_APMPOWER
141 tristate "Input Power Event -> APM Bridge" if EMBEDDED 153 tristate "Input Power Event -> APM Bridge" if EMBEDDED
142 depends on INPUT && APM_EMULATION 154 depends on INPUT && APM_EMULATION
143 ---help--- 155 help
144 Say Y here if you want suspend key events to trigger a user 156 Say Y here if you want suspend key events to trigger a user
145 requested suspend through APM. This is useful on embedded 157 requested suspend through APM. This is useful on embedded
146 systems where such behaviour is desired without userspace 158 systems where such behaviour is desired without userspace
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 4c9c745a7020..7ad212d31f99 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -9,6 +9,7 @@ input-core-objs := input.o input-compat.o ff-core.o
9 9
10obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o 10obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
11obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o 11obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
12obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
12 13
13obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o 14obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
14obj-$(CONFIG_INPUT_JOYDEV) += joydev.o 15obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 6a2eb399b988..aa6713b4a988 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -212,7 +212,7 @@ EXPORT_SYMBOL(input_allocate_polled_device);
212 * @dev: device to free 212 * @dev: device to free
213 * 213 *
214 * The function frees memory allocated for polling device and drops 214 * The function frees memory allocated for polling device and drops
215 * reference to the associated input device (if present). 215 * reference to the associated input device.
216 */ 216 */
217void input_free_polled_device(struct input_polled_dev *dev) 217void input_free_polled_device(struct input_polled_dev *dev)
218{ 218{
@@ -258,6 +258,15 @@ int input_register_polled_device(struct input_polled_dev *dev)
258 return error; 258 return error;
259 } 259 }
260 260
261 /*
262 * Take extra reference to the underlying input device so
263 * that it survives call to input_unregister_polled_device()
264 * and is deleted only after input_free_polled_device()
265 * has been invoked. This is needed to ease task of freeing
266 * sparse keymaps.
267 */
268 input_get_device(input);
269
261 return 0; 270 return 0;
262} 271}
263EXPORT_SYMBOL(input_register_polled_device); 272EXPORT_SYMBOL(input_register_polled_device);
@@ -269,8 +278,6 @@ EXPORT_SYMBOL(input_register_polled_device);
269 * The function unregisters previously registered polled input 278 * The function unregisters previously registered polled input
270 * device from input layer. Polling is stopped and device is 279 * device from input layer. Polling is stopped and device is
271 * ready to be freed with call to input_free_polled_device(). 280 * ready to be freed with call to input_free_polled_device().
272 * Callers should not attempt to access dev->input pointer
273 * after calling this function.
274 */ 281 */
275void input_unregister_polled_device(struct input_polled_dev *dev) 282void input_unregister_polled_device(struct input_polled_dev *dev)
276{ 283{
@@ -278,7 +285,6 @@ void input_unregister_polled_device(struct input_polled_dev *dev)
278 &input_polldev_attribute_group); 285 &input_polldev_attribute_group);
279 286
280 input_unregister_device(dev->input); 287 input_unregister_device(dev->input);
281 dev->input = NULL;
282} 288}
283EXPORT_SYMBOL(input_unregister_polled_device); 289EXPORT_SYMBOL(input_unregister_polled_device);
284 290
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
new file mode 100644
index 000000000000..fbd3987af57f
--- /dev/null
+++ b/drivers/input/sparse-keymap.c
@@ -0,0 +1,250 @@
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 <mitr@volny.cz>
8 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
9 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
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
19MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
20MODULE_DESCRIPTION("Generic support for sparse keymaps");
21MODULE_LICENSE("GPL v2");
22MODULE_VERSION("0.1");
23
24/**
25 * sparse_keymap_entry_from_scancode - perform sparse keymap lookup
26 * @dev: Input device using sparse keymap
27 * @code: Scan code
28 *
29 * This function is used to perform &struct key_entry lookup in an
30 * input device using sparse keymap.
31 */
32struct key_entry *sparse_keymap_entry_from_scancode(struct input_dev *dev,
33 unsigned int code)
34{
35 struct key_entry *key;
36
37 for (key = dev->keycode; key->type != KE_END; key++)
38 if (code == key->code)
39 return key;
40
41 return NULL;
42}
43EXPORT_SYMBOL(sparse_keymap_entry_from_scancode);
44
45/**
46 * sparse_keymap_entry_from_keycode - perform sparse keymap lookup
47 * @dev: Input device using sparse keymap
48 * @keycode: Key code
49 *
50 * This function is used to perform &struct key_entry lookup in an
51 * input device using sparse keymap.
52 */
53struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
54 unsigned int keycode)
55{
56 struct key_entry *key;
57
58 for (key = dev->keycode; key->type != KE_END; key++)
59 if (key->type == KE_KEY && keycode == key->keycode)
60 return key;
61
62 return NULL;
63}
64EXPORT_SYMBOL(sparse_keymap_entry_from_keycode);
65
66static int sparse_keymap_getkeycode(struct input_dev *dev,
67 int scancode, int *keycode)
68{
69 const struct key_entry *key =
70 sparse_keymap_entry_from_scancode(dev, scancode);
71
72 if (key && key->type == KE_KEY) {
73 *keycode = key->keycode;
74 return 0;
75 }
76
77 return -EINVAL;
78}
79
80static int sparse_keymap_setkeycode(struct input_dev *dev,
81 int scancode, int keycode)
82{
83 struct key_entry *key;
84 int old_keycode;
85
86 if (keycode < 0 || keycode > KEY_MAX)
87 return -EINVAL;
88
89 key = sparse_keymap_entry_from_scancode(dev, scancode);
90 if (key && key->type == KE_KEY) {
91 old_keycode = key->keycode;
92 key->keycode = keycode;
93 set_bit(keycode, dev->keybit);
94 if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
95 clear_bit(old_keycode, dev->keybit);
96 return 0;
97 }
98
99 return -EINVAL;
100}
101
102/**
103 * sparse_keymap_setup - set up sparse keymap for an input device
104 * @dev: Input device
105 * @keymap: Keymap in form of array of &key_entry structures ending
106 * with %KE_END type entry
107 * @setup: Function that can be used to adjust keymap entries
108 * depending on device's deeds, may be %NULL
109 *
110 * The function calculates size and allocates copy of the original
111 * keymap after which sets up input device event bits appropriately.
112 * Before destroying input device allocated keymap should be freed
113 * with a call to sparse_keymap_free().
114 */
115int sparse_keymap_setup(struct input_dev *dev,
116 const struct key_entry *keymap,
117 int (*setup)(struct input_dev *, struct key_entry *))
118{
119 size_t map_size = 1; /* to account for the last KE_END entry */
120 const struct key_entry *e;
121 struct key_entry *map, *entry;
122 int i;
123 int error;
124
125 for (e = keymap; e->type != KE_END; e++)
126 map_size++;
127
128 map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
129 if (!map)
130 return -ENOMEM;
131
132 memcpy(map, keymap, map_size * sizeof (struct key_entry));
133
134 for (i = 0; i < map_size; i++) {
135 entry = &map[i];
136
137 if (setup) {
138 error = setup(dev, entry);
139 if (error)
140 goto err_out;
141 }
142
143 switch (entry->type) {
144 case KE_KEY:
145 __set_bit(EV_KEY, dev->evbit);
146 __set_bit(entry->keycode, dev->keybit);
147 break;
148
149 case KE_SW:
150 __set_bit(EV_SW, dev->evbit);
151 __set_bit(entry->sw.code, dev->swbit);
152 break;
153 }
154 }
155
156 dev->keycode = map;
157 dev->keycodemax = map_size;
158 dev->getkeycode = sparse_keymap_getkeycode;
159 dev->setkeycode = sparse_keymap_setkeycode;
160
161 return 0;
162
163 err_out:
164 kfree(keymap);
165 return error;
166
167}
168EXPORT_SYMBOL(sparse_keymap_setup);
169
170/**
171 * sparse_keymap_free - free memory allocated for sparse keymap
172 * @dev: Input device using sparse keymap
173 *
174 * This function is used to free memory allocated by sparse keymap
175 * in an input device that was set up by sparse_keymap_setup().
176 */
177void sparse_keymap_free(struct input_dev *dev)
178{
179 kfree(dev->keycode);
180 dev->keycode = NULL;
181 dev->keycodemax = 0;
182 dev->getkeycode = NULL;
183 dev->setkeycode = NULL;
184}
185EXPORT_SYMBOL(sparse_keymap_free);
186
187/**
188 * sparse_keymap_report_entry - report event corresponding to given key entry
189 * @dev: Input device for which event should be reported
190 * @ke: key entry describing event
191 * @value: Value that should be reported (ignored by %KE_SW entries)
192 * @autorelease: Signals whether release event should be emitted for %KE_KEY
193 * entries right after reporting press event, ignored by all other
194 * entries
195 *
196 * This function is used to report input event described by given
197 * &struct key_entry.
198 */
199void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
200 unsigned int value, bool autorelease)
201{
202 switch (ke->type) {
203 case KE_KEY:
204 input_report_key(dev, ke->keycode, value);
205 input_sync(dev);
206 if (value && autorelease) {
207 input_report_key(dev, ke->keycode, 0);
208 input_sync(dev);
209 }
210 break;
211
212 case KE_SW:
213 value = ke->sw.value;
214 /* fall through */
215
216 case KE_VSW:
217 input_report_switch(dev, ke->sw.code, value);
218 break;
219 }
220}
221EXPORT_SYMBOL(sparse_keymap_report_entry);
222
223/**
224 * sparse_keymap_report_event - report event corresponding to given scancode
225 * @dev: Input device using sparse keymap
226 * @code: Scan code
227 * @value: Value that should be reported (ignored by %KE_SW entries)
228 * @autorelease: Signals whether release event should be emitted for %KE_KEY
229 * entries right after reporting press event, ignored by all other
230 * entries
231 *
232 * This function is used to perform lookup in an input device using sparse
233 * keymap and report corresponding event. Returns %true if lookup was
234 * successful and %false otherwise.
235 */
236bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code,
237 unsigned int value, bool autorelease)
238{
239 const struct key_entry *ke =
240 sparse_keymap_entry_from_scancode(dev, code);
241
242 if (ke) {
243 sparse_keymap_report_entry(dev, ke, value, autorelease);
244 return true;
245 }
246
247 return false;
248}
249EXPORT_SYMBOL(sparse_keymap_report_event);
250