summaryrefslogtreecommitdiffstats
path: root/drivers/char/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/keyboard.c')
-rw-r--r--drivers/char/keyboard.c103
1 files changed, 45 insertions, 58 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index cb8d691..1b09450 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -41,7 +41,6 @@
#include <linux/input.h>
#include <linux/reboot.h>
-static void kbd_disconnect(struct input_handle *handle);
extern void ctrl_alt_del(void);
/*
@@ -110,7 +109,7 @@ struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table;
struct vt_spawn_console vt_spawn_con = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
.pid = NULL,
.sig = 0,
};
@@ -159,65 +158,41 @@ static int sysrq_alt_use;
static int sysrq_alt;
/*
- * Translation of scancodes to keycodes. We set them on only the first attached
- * keyboard - for per-keyboard setting, /dev/input/event is more useful.
+ * Translation of scancodes to keycodes. We set them on only the first
+ * keyboard in the list that accepts the scancode and keycode.
+ * Explanation for not choosing the first attached keyboard anymore:
+ * USB keyboards for example have two event devices: one for all "normal"
+ * keys and one for extra function keys (like "volume up", "make coffee",
+ * etc.). So this means that scancodes for the extra function keys won't
+ * be valid for the first event device, but will be for the second.
*/
int getkeycode(unsigned int scancode)
{
- struct list_head *node;
- struct input_dev *dev = NULL;
+ struct input_handle *handle;
+ int keycode;
+ int error = -ENODEV;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
- break;
- }
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+ error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
+ if (!error)
+ return keycode;
}
- if (!dev)
- return -ENODEV;
-
- if (scancode >= dev->keycodemax)
- return -EINVAL;
-
- return INPUT_KEYCODE(dev, scancode);
+ return error;
}
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- struct list_head *node;
- struct input_dev *dev = NULL;
- unsigned int i, oldkey;
+ struct input_handle *handle;
+ int error = -ENODEV;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+ error = handle->dev->setkeycode(handle->dev, scancode, keycode);
+ if (!error)
break;
- }
}
- if (!dev)
- return -ENODEV;
-
- if (scancode >= dev->keycodemax)
- return -EINVAL;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
- return -EINVAL;
-
- oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode);
-
- clear_bit(oldkey, dev->keybit);
- set_bit(keycode, dev->keybit);
-
- for (i = 0; i < dev->keycodemax; i++)
- if (INPUT_KEYCODE(dev,i) == oldkey)
- set_bit(oldkey, dev->keybit);
-
- return 0;
+ return error;
}
/*
@@ -225,10 +200,9 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
*/
static void kd_nosound(unsigned long ignored)
{
- struct list_head *node;
+ struct input_handle *handle;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit))
input_inject_event(handle, EV_SND, SND_TONE, 0);
@@ -1161,7 +1135,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
if (emulate_raw(vc, keycode, !down << 7))
- if (keycode < BTN_MISC)
+ if (keycode < BTN_MISC && printk_ratelimit())
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
@@ -1285,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
* likes it, it can open it and get events from it. In this (kbd_connect)
* function, we should decide which VT to bind that keyboard to initially.
*/
-static struct input_handle *kbd_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct input_handle *handle;
+ int error;
int i;
for (i = KEY_RESERVED; i < BTN_MISC; i++)
@@ -1297,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
break;
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
- return NULL;
+ return -ENODEV;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
- return NULL;
+ return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "kbd";
- input_open_device(handle);
+ error = input_register_handle(handle);
+ if (error)
+ goto err_free_handle;
+
+ error = input_open_device(handle);
+ if (error)
+ goto err_unregister_handle;
+
+ return 0;
- return handle;
+ err_unregister_handle:
+ input_unregister_handle(handle);
+ err_free_handle:
+ kfree(handle);
+ return error;
}
static void kbd_disconnect(struct input_handle *handle)
{
input_close_device(handle);
+ input_unregister_handle(handle);
kfree(handle);
}
OpenPOWER on IntegriCloud