From 8613e4c2872a87cc309a42de2c7091744dc54d0e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 9 Sep 2010 21:54:22 -0700 Subject: Input: add support for large scancodes Several devices use a high number of bits for scancodes. One important group is the Remote Controllers. Some new protocols like RC-6 define a scancode space of 64 bits. The current EVIO[CS]GKEYCODE ioctls allow replace the scancode/keycode translation tables, but it is limited to up to 32 bits for scancode. Also, if userspace wants to clean the existing table, replacing it by a new one, it needs to run a loop calling the ioctls over the entire sparse scancode space. To solve those problems, this patch extends the ioctls to allow drivers handle scancodes up to 32 bytes long (the length could be extended in the future should such need arise) and allow userspace to query and set scancode to keycode mappings not only by scancode but also by index. Compatibility code were also added to handle the old format of EVIO[CS]GKEYCODE ioctls. Folded fixes by: - Dan Carpenter: locking fixes for the original implementation - Jarod Wilson: fix crash when setting keycode and wiring up get/set handlers in original implementation. - Dmitry Torokhov: rework to consolidate old and new scancode handling, provide options to act either by index or scancode. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Dan Carpenter Signed-off-by: Jarod Wilson Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index a7ca75212bfe..e95d7876ca6b 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -175,8 +175,7 @@ EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); */ struct getset_keycode_data { - unsigned int scancode; - unsigned int keycode; + struct input_keymap_entry ke; int error; }; @@ -184,32 +183,50 @@ static int getkeycode_helper(struct input_handle *handle, void *data) { struct getset_keycode_data *d = data; - d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode); + d->error = input_get_keycode(handle->dev, &d->ke); return d->error == 0; /* stop as soon as we successfully get one */ } int getkeycode(unsigned int scancode) { - struct getset_keycode_data d = { scancode, 0, -ENODEV }; + struct getset_keycode_data d = { + .ke = { + .flags = 0, + .len = sizeof(scancode), + .keycode = 0, + }, + .error = -ENODEV, + }; + + memcpy(d.ke.scancode, &scancode, sizeof(scancode)); input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper); - return d.error ?: d.keycode; + return d.error ?: d.ke.keycode; } static int setkeycode_helper(struct input_handle *handle, void *data) { struct getset_keycode_data *d = data; - d->error = input_set_keycode(handle->dev, d->scancode, d->keycode); + d->error = input_set_keycode(handle->dev, &d->ke); return d->error == 0; /* stop as soon as we successfully set one */ } int setkeycode(unsigned int scancode, unsigned int keycode) { - struct getset_keycode_data d = { scancode, keycode, -ENODEV }; + struct getset_keycode_data d = { + .ke = { + .flags = 0, + .len = sizeof(scancode), + .keycode = keycode, + }, + .error = -ENODEV, + }; + + memcpy(d.ke.scancode, &scancode, sizeof(scancode)); input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper); -- cgit v1.2.3 From 1966cb225c6f9040ca163802cbd052c393d4448f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 29 Sep 2010 18:04:21 -0700 Subject: Input: sysrq - add locking to sysrq_filter() Similarly to the keyboard handler, we are called by different input devices and thus need to add spinlock if we want to maintain our state properly. Signed-off-by: Dmitry Torokhov --- drivers/char/sysrq.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index ef31bb81e843..f0ad694cc2eb 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -566,10 +566,16 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] = static bool sysrq_down; static int sysrq_alt_use; static int sysrq_alt; +static DEFINE_SPINLOCK(sysrq_event_lock); static bool sysrq_filter(struct input_handle *handle, unsigned int type, unsigned int code, int value) { + bool suppress; + + /* We are called with interrupts disabled, just take the lock */ + spin_lock(&sysrq_event_lock); + if (type != EV_KEY) goto out; @@ -601,7 +607,10 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type, } out: - return sysrq_down; + suppress = sysrq_down; + spin_unlock(&sysrq_event_lock); + + return suppress; } static int sysrq_connect(struct input_handler *handler, @@ -652,8 +661,8 @@ static void sysrq_disconnect(struct input_handle *handle) } /* - * We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all - * keyboards have SysRq ikey predefined and so user may add it to keymap + * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all + * keyboards have SysRq key predefined and so user may add it to keymap * later, but we expect all such keyboards to have left alt. */ static const struct input_device_id sysrq_ids[] = { -- cgit v1.2.3