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>
This commit is contained in:
Marvin Raaijmakers 2007-03-14 22:50:42 -04:00 committed by Dmitry Torokhov
parent 55e3d9224b
commit c8e4c77277
4 changed files with 122 additions and 96 deletions

View 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);

View 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))
if (get_user(t, ip) || get_user(v, ip + 1))
return -EFAULT;
if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
return -EINVAL;
if (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)))

View 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),

View 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)