Skip to content

Commit

Permalink
Input: add getkeycode and setkeycode methods
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marvin Raaijmakers authored and Dmitry Torokhov committed Mar 15, 2007
1 parent 55e3d92 commit c8e4c77
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 96 deletions.
71 changes: 23 additions & 48 deletions drivers/char/keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,76 +159,51 @@ 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;
}

/*
* Making beeps and bells.
*/
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);
Expand Down
29 changes: 9 additions & 20 deletions drivers/input/evdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down
87 changes: 87 additions & 0 deletions drivers/input/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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),
Expand Down
31 changes: 3 additions & 28 deletions include/linux/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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)

Expand Down

0 comments on commit c8e4c77

Please sign in to comment.