Input: add getkeycode and setkeycode methods
Marvin Raaijmakers [Thu, 15 Mar 2007 02:50:42 +0000 (22:50 -0400)]
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>

drivers/char/keyboard.c
drivers/input/evdev.c
drivers/input/input.c
include/linux/input.h

index cb8d691..3d211e8 100644 (file)
@@ -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);
index 6439f37..64b47de 100644 (file)
@@ -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)))
index 4486402..26393a6 100644 (file)
@@ -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),
index bde65c8..3a8b8c6 100644 (file)
@@ -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)