summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarvin Raaijmakers <marvin_raaijmakers@linux-box.nl>2007-03-14 22:50:42 -0400
committerDmitry Torokhov <dtor@insightbb.com>2007-03-14 22:50:42 -0400
commitc8e4c77277ca5db0c4ddbfb4bc628b8abad585b0 (patch)
tree07bebb34767c8c3bd0902d6c2be3f4819b30a7bf
parent55e3d9224b60df0fd2dc36bff9b538ce40fd9586 (diff)
Input: add getkeycode and setkeycode methods
Allow drivers to implement their own get and set keycode methods. This will allow drivers to change their keymaps without allocating huge tables covering entire range of possible scancodes. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/char/keyboard.c71
-rw-r--r--drivers/input/evdev.c29
-rw-r--r--drivers/input/input.c87
-rw-r--r--include/linux/input.h31
4 files changed, 122 insertions, 96 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index cb8d691576d..3d211e8553f 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -159,65 +159,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 +201,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);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 6439f378f6c..64b47de052b 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -434,32 +434,21 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
case EVIOCGKEYCODE:
if (get_user(t, ip))
return -EFAULT;
- if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
- return -EINVAL;
- if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
+
+ error = dev->getkeycode(dev, t, &v);
+ if (error)
+ return error;
+
+ if (put_user(v, ip + 1))
return -EFAULT;
+
return 0;
case EVIOCSKEYCODE:
- if (get_user(t, ip))
- return -EFAULT;
- if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
- return -EINVAL;
- if (get_user(v, ip + 1))
+ if (get_user(t, ip) || get_user(v, ip + 1))
return -EFAULT;
- if (v < 0 || v > KEY_MAX)
- return -EINVAL;
- if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8)))
- return -EINVAL;
-
- u = SET_INPUT_KEYCODE(dev, t, v);
- clear_bit(u, dev->keybit);
- set_bit(v, dev->keybit);
- for (i = 0; i < dev->keycodemax; i++)
- if (INPUT_KEYCODE(dev, i) == u)
- set_bit(u, dev->keybit);
- return 0;
+ return dev->setkeycode(dev, t, v);
case EVIOCSFF:
if (copy_from_user(&effect, p, sizeof(effect)))
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 4486402fbf5..26393a606e6 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -299,6 +299,87 @@ void input_close_device(struct input_handle *handle)
}
EXPORT_SYMBOL(input_close_device);
+static int input_fetch_keycode(struct input_dev *dev, int scancode)
+{
+ switch (dev->keycodesize) {
+ case 1:
+ return ((u8 *)dev->keycode)[scancode];
+
+ case 2:
+ return ((u16 *)dev->keycode)[scancode];
+
+ default:
+ return ((u32 *)dev->keycode)[scancode];
+ }
+}
+
+static int input_default_getkeycode(struct input_dev *dev,
+ int scancode, int *keycode)
+{
+ if (!dev->keycodesize)
+ return -EINVAL;
+
+ if (scancode < 0 || scancode >= dev->keycodemax)
+ return -EINVAL;
+
+ *keycode = input_fetch_keycode(dev, scancode);
+
+ return 0;
+}
+
+static int input_default_setkeycode(struct input_dev *dev,
+ int scancode, int keycode)
+{
+ int old_keycode;
+ int i;
+
+ if (scancode < 0 || scancode >= dev->keycodemax)
+ return -EINVAL;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ if (!dev->keycodesize)
+ return -EINVAL;
+
+ if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
+ return -EINVAL;
+
+ switch (dev->keycodesize) {
+ case 1: {
+ u8 *k = (u8 *)dev->keycode;
+ old_keycode = k[scancode];
+ k[scancode] = keycode;
+ break;
+ }
+ case 2: {
+ u16 *k = (u16 *)dev->keycode;
+ old_keycode = k[scancode];
+ k[scancode] = keycode;
+ break;
+ }
+ default: {
+ u32 *k = (u32 *)dev->keycode;
+ old_keycode = k[scancode];
+ k[scancode] = keycode;
+ break;
+ }
+ }
+
+ clear_bit(old_keycode, dev->keybit);
+ set_bit(keycode, dev->keybit);
+
+ for (i = 0; i < dev->keycodemax; i++) {
+ if (input_fetch_keycode(dev, i) == old_keycode) {
+ set_bit(old_keycode, dev->keybit);
+ break; /* Setting the bit twice is useless, so break */
+ }
+ }
+
+ return 0;
+}
+
+
static void input_link_handle(struct input_handle *handle)
{
list_add_tail(&handle->d_node, &handle->dev->h_list);
@@ -978,6 +1059,12 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33;
}
+ if (!dev->getkeycode)
+ dev->getkeycode = input_default_getkeycode;
+
+ if (!dev->setkeycode)
+ dev->setkeycode = input_default_setkeycode;
+
list_add_tail(&dev->node, &input_dev_list);
snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
diff --git a/include/linux/input.h b/include/linux/input.h
index bde65c8a351..3a8b8c6f0ab 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -913,33 +913,6 @@ struct ff_effect {
#define BIT(x) (1UL<<((x)%BITS_PER_LONG))
#define LONG(x) ((x)/BITS_PER_LONG)
-#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
- ((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
-
-#define SET_INPUT_KEYCODE(dev, scancode, val) \
- ({ unsigned __old; \
- switch (dev->keycodesize) { \
- case 1: { \
- u8 *k = (u8 *)dev->keycode; \
- __old = k[scancode]; \
- k[scancode] = val; \
- break; \
- } \
- case 2: { \
- u16 *k = (u16 *)dev->keycode; \
- __old = k[scancode]; \
- k[scancode] = val; \
- break; \
- } \
- default: { \
- u32 *k = (u32 *)dev->keycode; \
- __old = k[scancode]; \
- k[scancode] = val; \
- break; \
- } \
- } \
- __old; })
-
struct input_dev {
void *private;
@@ -962,6 +935,8 @@ struct input_dev {
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
+ int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
+ int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
@@ -1104,7 +1079,7 @@ struct input_handle {
};
#define to_dev(n) container_of(n,struct input_dev,node)
-#define to_handler(n) container_of(n,struct input_handler,node);
+#define to_handler(n) container_of(n,struct input_handler,node)
#define to_handle(n) container_of(n,struct input_handle,d_node)
#define to_handle_h(n) container_of(n,struct input_handle,h_node)