From: Marvin Raaijmakers <[EMAIL PROTECTED]> Currently it isn't possible to assign keycodes to keys of USB keyboards by usign a userspace application. This is because USB keyboards do not send scancodes, but HID usage codes. I have modified the hid-input driver so that keycodes can be set to HID usage codes in exactly the same way as keycodes are set to scancodes. To make this possible I had to modify the input_dev structure (in <linux/input.h>) by adding a "setkeycodes" member to it. This member is a pointer to a function that sets the keycodes to scancodes (and HID usage codes). Each driver has its own "setkeycodes" function and if a driver does not provide the functionality to set keycodes, the pointer will be NULL. The evdev_ioctl function will call the "setkeycode" function if its cmd parameter is equal to EVIOCSKEYCODE. All keyboard drivers now have a setkeycode function, including the hid-input driver. Note that hid-usage codes are handled the same way as scancodes. The keycodemax, keycodesize and keycode member are not removed from the input_dev structure so that the old way of setting a keycode (by using the setkeycodes program) can still be used.
Below you can see a simple application for setting keycodes: - - - - - - - - - - - - - - - - - - - #include <linux/input.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char **argv) { int fd; struct input_keycode2scancode scan2key; if (argc < 4) { printf ("Usage: %s /dev/input/eventX scancode keycode\n", argv[0]); printf ("Where X = input device number\n"); return 1; } if ((fd = open(argv[1], O_RDONLY)) < 0) { perror (argv[0]); return 1; } scan2key.scancode = (unsigned) strtol(argv[2], NULL, 0); scan2key.keycode = (unsigned) strtol(argv[3], NULL, 0); ioctl (fd, EVIOCSKEYCODE, &scan2key); return 0; } - - - - - - - - - - - - - - - - - - - I hope my code will be implemented in the kernel, because with the current code a lot of extra function keys on USB keyboards do not work because they do not have a keycode. My code makes it possible to set a keycode to such key, so that it will work. Signed-off-by: Marvin Raaijmakers <[EMAIL PROTECTED]> --- diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/evdev.c linux-source-2.6.15/drivers/input/evdev.c --- linux-source-2.6.15-vanilla/drivers/input/evdev.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/evdev.c 2006-06-04 17:17:16.000000000 +0200 @@ -7,6 +7,12 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ + +/* + * 04 June 2006, Marvin Raaijmakers: + * The setkeycode member function (of the input_dev struct) will be used in + * the EVIOCSKEYCODE case in evdev_ioctl(). + */ #define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 @@ -22,6 +28,8 @@ #include <linux/device.h> #include <linux/compat.h> +#define DEBUG + struct evdev { int exist; int open; @@ -296,6 +304,7 @@ static long evdev_ioctl(struct file *fil struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; + struct input_keycode2scancode keycode2scancode; void __user *p = (void __user *)arg; int __user *ip = (int __user *)arg; int i, t, u, v; @@ -317,7 +326,16 @@ static long evdev_ioctl(struct file *fil return 0; case EVIOCSKEYCODE: - if (get_user(t, ip)) return -EFAULT; + if (copy_from_user (&keycode2scancode, (const void __user *) arg, sizeof(struct input_keycode2scancode))) + { + return -EFAULT; + } + if (dev->setkeycode) + { + return EINVAL * (*dev->setkeycode)(dev, &keycode2scancode); + } + return 0; + /*if (get_user(t, ip)) 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; @@ -328,7 +346,7 @@ static long evdev_ioctl(struct file *fil for (i = 0; i < dev->keycodemax; i++) if (INPUT_KEYCODE(dev,i) == u) set_bit(u, dev->keybit); - return 0; + return 0;*/ case EVIOCSFF: if (dev->upload_effect) { diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/amikbd.c linux-source-2.6.15/drivers/input/keyboard/amikbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/amikbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/amikbd.c 2006-06-04 17:06:05.000000000 +0200 @@ -8,6 +8,10 @@ */ /* + * 04 June 2006, Marvin Raaijmakers: added amikbd_setkeycode() + */ + +/* * Amiga keyboard driver for Linux/m68k */ @@ -157,6 +161,41 @@ static const char *amikbd_messages[8] = static struct input_dev *amikbd_dev; + +static int +amikbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + unsigned char *keycode = dev->private; + unsigned int keycode_max = ARRAY_SIZE(amikbd_keycode), + i; + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= keycode_max || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keycode[keycode2scancode->scancode]; + keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < keycode_max; i++) + { + if (keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) { unsigned char scancode, down; @@ -217,6 +256,8 @@ static int __init amikbd_init(void) amikbd_dev->keycode = amikbd_keycode; amikbd_dev->keycodesize = sizeof(unsigned char); amikbd_dev->keycodemax = ARRAY_SIZE(amikbd_keycode); + amikbd_dev->private = amikbd_keycode; + amikbd_dev->setkeycode = amikbd_setkeycode; for (i = 0; i < 0x78; i++) if (amikbd_keycode[i]) diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/atkbd.c linux-source-2.6.15/drivers/input/keyboard/atkbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/atkbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/atkbd.c 2006-06-04 17:05:44.000000000 +0200 @@ -5,6 +5,10 @@ */ /* + * 04 June 2006, Marvin Raaijmakers: added atkbd_setkeycode() + */ + +/* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. @@ -187,6 +191,7 @@ static struct { */ struct atkbd { + struct default_keytable keytable; struct ps2dev ps2dev; struct input_dev *dev; @@ -245,6 +250,40 @@ ATKBD_DEFINE_ATTR(softrepeat); ATKBD_DEFINE_ATTR(softraw); +static int +atkbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct atkbd *keyboard = dev->private; + unsigned int keycode_max = ARRAY_SIZE(atkbd_set2_keycode), + i; + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= keycode_max || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < keycode_max; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) { input_regs(dev, regs); @@ -819,6 +858,12 @@ static void atkbd_set_device_attrs(struc input_dev->keycode = atkbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); + + atkbd->keytable.keycode = atkbd->keycode; + atkbd->keytable.keycodesize = sizeof(unsigned char); + atkbd->keytable.keycodemax = ARRAY_SIZE(atkbd_set2_keycode); + + input_dev->setkeycode = atkbd_setkeycode; for (i = 0; i < 512; i++) if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/corgikbd.c linux-source-2.6.15/drivers/input/keyboard/corgikbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/corgikbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/corgikbd.c 2006-06-04 17:06:37.000000000 +0200 @@ -11,6 +11,10 @@ * */ +/* + * 04 June 2006, Marvin Raaijmakers: added corgikbd_setkeycode() + */ + #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/init.h> @@ -83,6 +87,41 @@ struct corgikbd { #define KB_DISCHARGE_DELAY 10 #define KB_ACTIVATE_DELAY 10 + +static int +corgikbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct corgikbd *keyboard = dev->private; + unsigned int keycode_max = ARRAY_SIZE(corgikbd_keycode), + i; + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= keycode_max || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < keycode_max; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + /* Helper functions for reading the keyboard matrix * Note: We should really be using pxa_gpio_mode to alter GPDR but it * requires a function call per GPIO bit which is excessive @@ -328,6 +367,7 @@ static int __init corgikbd_probe(struct input_dev->keycode = corgikbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(corgikbd_keycode); + input_dev->setkeycode = corgikbd_setkeycode; for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++) set_bit(corgikbd->keycode[i], input_dev->keybit); diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/hil_kbd.c linux-source-2.6.15/drivers/input/keyboard/hil_kbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/hil_kbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/hil_kbd.c 2006-06-04 17:07:24.000000000 +0200 @@ -31,6 +31,10 @@ * */ +/* + * 04 June 2006, Marvin Raaijmakers: added hil_kbd_setkeycode() + */ + #include <linux/hil.h> #include <linux/input.h> #include <linux/serio.h> @@ -69,6 +73,7 @@ struct hil_kbd { struct input_dev dev; struct serio *serio; + unsigned int *keycode; /* Input buffer and index for packets from HIL bus. */ hil_packet data[HIL_KBD_MAX_LENGTH]; int idx4; /* four counts per packet */ @@ -83,6 +88,39 @@ struct hil_kbd { struct semaphore sem; }; + +static int +hil_kbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct hil_kbd *keyboard = dev->private; + unsigned int i, old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= HIL_KEYCODES_SET1_TBLSIZE || + keycode2scancode->keycode > KEY_MAX) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + /* Process a complete packet after transfer from the HIL */ static void hil_kbd_process_record(struct hil_kbd *kbd) { @@ -316,6 +354,9 @@ static int hil_kbd_connect(struct serio kbd->dev.keycodemax = HIL_KEYCODES_SET1_TBLSIZE; kbd->dev.keycodesize = sizeof(hil_kbd_set1[0]); kbd->dev.keycode = hil_kbd_set1; + kbd->keycode = hil_kbd_set1; + kbd->setkeycode = hil_kbd_setkeycode; + kbd->dev.name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; kbd->dev.phys = "hpkbd/input0"; /* XXX */ diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/lkkbd.c linux-source-2.6.15/drivers/input/keyboard/lkkbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/lkkbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/lkkbd.c 2006-06-04 17:09:35.000000000 +0200 @@ -7,6 +7,10 @@ */ /* + * 04 June 2006, Marvin Raaijmakers: added lkkbd_setkeycode() + */ + +/* * DEC LK201 and LK401 keyboard driver for Linux (primary for DECstations * and VAXstations, but can also be used on any standard RS232 with an * adaptor). @@ -334,6 +338,40 @@ response_name (unsigned char value) } #endif /* LKKBD_DEBUG */ + +static int +lkkbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct lkkbd *keyboard = dev->private; + unsigned int i; + lk_keycode_t old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= LK_NUM_KEYCODES || + keycode2scancode->keycode > KEY_MAX) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < LK_NUM_KEYCODES; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + /* * Calculate volume parameter byte for a given volume. */ @@ -689,6 +727,7 @@ lkkbd_connect (struct serio *serio, stru input_dev->keycode = lk->keycode; input_dev->keycodesize = sizeof (lk_keycode_t); input_dev->keycodemax = LK_NUM_KEYCODES; + input_dev->setkeycode = lkkbd_setkeycode; for (i = 0; i < LK_NUM_KEYCODES; i++) set_bit (lk->keycode[i], input_dev->keybit); diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/locomokbd.c linux-source-2.6.15/drivers/input/keyboard/locomokbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/locomokbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/locomokbd.c 2006-06-04 17:10:01.000000000 +0200 @@ -5,6 +5,10 @@ */ /* + * 04 June 2006, Marvin Raaijmakers: added locomokbd_setkeycode() + */ + +/* * LoCoMo keyboard driver for Linux/ARM */ @@ -86,6 +90,39 @@ struct locomokbd { struct timer_list timer; }; + +static int +locomokbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct locomokbd *keyboard = dev->private; + unsigned int i; + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= LOCOMOKBD_NUMKEYS || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + /* helper functions for reading the keyboard matrix */ static inline void locomokbd_charge_all(unsigned long membase) { @@ -240,6 +277,7 @@ static int locomokbd_probe(struct locomo input_dev->keycode = locomokbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(locomokbd_keycode); + input_dev->setkeycode = locomokbd_setkeycode; memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode)); for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/maple_keyb.c linux-source-2.6.15/drivers/input/keyboard/maple_keyb.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/maple_keyb.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/maple_keyb.c 2006-06-04 14:58:40.000000000 +0200 @@ -112,6 +112,8 @@ static int dc_kbd_connect(struct maple_d for (i = 0; i < 255; i++) set_bit(dc_kbd_keycode[i], input_dev->keybit); clear_bit(0, input_dev->keybit); + + input_dev->setkeycode = NULL; /* There is no function to keycodes */ input_register_device(kbd->dev); diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/newtonkbd.c linux-source-2.6.15/drivers/input/keyboard/newtonkbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/newtonkbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/newtonkbd.c 2006-06-04 17:10:38.000000000 +0200 @@ -3,6 +3,10 @@ */ /* + * 04 June 2006, Marvin Raaijmakers: added nkbd_setkeycode() + */ + +/* * Newton keyboard driver for Linux */ @@ -64,6 +68,40 @@ struct nkbd { char phys[32]; }; + +static int +nkbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct nkbd *keyboard = dev->private; + unsigned int i, keycode_max = ARRAY_SIZE(nkbd_keycode); + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= keycode_max || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < keycode_max; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + static irqreturn_t nkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs) { @@ -112,6 +150,7 @@ static int nkbd_connect(struct serio *se input_dev->keycode = nkbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(nkbd_keycode); + input_dev->setkeycode = nkbd_setkeycode; for (i = 0; i < 128; i++) set_bit(nkbd->keycode[i], input_dev->keybit); clear_bit(0, input_dev->keybit); diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/spitzkbd.c linux-source-2.6.15/drivers/input/keyboard/spitzkbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/spitzkbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/spitzkbd.c 2006-06-04 17:10:58.000000000 +0200 @@ -11,6 +11,10 @@ * */ +/* + * 04 June 2006, Marvin Raaijmakers: added spitzkbd_setkeycode() + */ + #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/init.h> @@ -99,6 +103,41 @@ struct spitzkbd { #define KB_DISCHARGE_DELAY 10 #define KB_ACTIVATE_DELAY 10 + +static int +spitzkbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct spitzkbd *keyboard = dev->private; + unsigned int keycode_max = ARRAY_SIZE(spitzkbd_keycode), + i; + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= keycode_max || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < keycode_max; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + /* Helper functions for reading the keyboard matrix * Note: We should really be using pxa_gpio_mode to alter GPDR but it * requires a function call per GPIO bit which is excessive @@ -391,6 +430,7 @@ static int __init spitzkbd_probe(struct input_dev->keycode = spitzkbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(spitzkbd_keycode); + input_dev->setkeycode = spitzkbd_setkeycode; memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode)); for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++) diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/sunkbd.c linux-source-2.6.15/drivers/input/keyboard/sunkbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/sunkbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/sunkbd.c 2006-06-04 17:11:18.000000000 +0200 @@ -5,6 +5,10 @@ */ /* + * 04 June 2006, Marvin Raaijmakers: added sunkbd_setkeycode() + */ + +/* * Sun keyboard driver for Linux */ @@ -88,6 +92,41 @@ struct sunkbd { volatile s8 layout; }; + +static int +sunkbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct sunkbd *keyboard = dev->private; + unsigned int keycode_max = ARRAY_SIZE(sunkbd_keycode), + i; + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= keycode_max || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < keycode_max; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + /* * sunkbd_interrupt() is called by the low level driver when a character * is received. @@ -283,6 +322,7 @@ static int sunkbd_connect(struct serio * input_dev->keycode = sunkbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode); + input_dev->setkeycode = sunkbd_setkeycode; for (i = 0; i < 128; i++) set_bit(sunkbd->keycode[i], input_dev->keybit); clear_bit(0, input_dev->keybit); diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/input/keyboard/xtkbd.c linux-source-2.6.15/drivers/input/keyboard/xtkbd.c --- linux-source-2.6.15-vanilla/drivers/input/keyboard/xtkbd.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/input/keyboard/xtkbd.c 2006-06-04 17:11:30.000000000 +0200 @@ -5,6 +5,10 @@ */ /* + * 04 June 2006, Marvin Raaijmakers: added xtkbd_setkeycode() + */ + +/* * XT keyboard driver for Linux */ @@ -63,6 +67,41 @@ struct xtkbd { char phys[32]; }; + +static int +xtkbd_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +{ + struct xtkbd *keyboard = dev->private; + unsigned int keycode_max = ARRAY_SIZE(xtkbd_keycode), + i; + unsigned char old_keycode; + + if (keycode2scancode->scancode < 0 || + keycode2scancode->scancode >= keycode_max || + keycode2scancode->keycode > 0xFF) + { + return -1; + } + old_keycode = keyboard->keycode[keycode2scancode->scancode]; + keyboard->keycode[keycode2scancode->scancode] = keycode2scancode->keycode; +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to scancode %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + clear_bit (old_keycode, dev->keybit); + set_bit (keycode2scancode->keycode, dev->keybit); + for (i = 0; i < keycode_max; i++) + { + if (keyboard->keycode[i] == old_keycode) + { + set_bit(old_keycode, dev->keybit); + break; + } + } + return 0; +} + + static irqreturn_t xtkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs) { @@ -116,6 +155,7 @@ static int xtkbd_connect(struct serio *s input_dev->keycode = xtkbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(xtkbd_keycode); + input_dev->setkeycode = xtkbd_setkeycode; for (i = 0; i < 255; i++) set_bit(xtkbd->keycode[i], input_dev->keybit); diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/drivers/usb/input/hid-input.c linux-source-2.6.15/drivers/usb/input/hid-input.c --- linux-source-2.6.15-vanilla/drivers/usb/input/hid-input.c 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/drivers/usb/input/hid-input.c 2006-06-04 17:21:30.000000000 +0200 @@ -26,6 +26,10 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +/* + * Marvin Raaijmakers March 2006: Added hidinput_setkeycode() + */ + #include <linux/module.h> #include <linux/slab.h> #include <linux/kernel.h> @@ -73,6 +77,90 @@ static struct { #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) #define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0) + +/* The for_each_hid_usage() marco can be used for iteration over all + * hid usages in all fields in all reports of the hid_device pointed + * to by hid_ptr. + * usage_ptr - hid_usage to use as a loop counter. Type: struct hid_usage * + * hid_ptr - Points to the hid_device to read the usages from. + * Type: struct hid_device * + * i,j,k - Integers that will be used internally by this macro. Type: int + * report_ptr - A pointer that will be used internally by this macro. + * Type: struct hid_report * + */ +#define for_each_hid_usage(usage_ptr, hid_ptr, i, j, k, report_ptr) \ + for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) \ + list_for_each_entry (report, &hid_ptr->report_enum[k].report_list, list)\ + for (i = 0; i < report->maxfield; i++) \ + for ( j = 0, usage_ptr = report->field[i]->usage; j < report->field[i]->maxusage; j++, usage_ptr++) + + + +static int +hidinput_setkeycode (struct input_dev *dev, struct input_keycode2scancode *keycode2scancode) +/* +Input: + dev - Must point to a input_dev structure of an HID + device + keycode2scancode - The address of the structure that contains the + scancode and the keycode +Output: + dev->private - The keycode will be set to the hid_usage with the + correct scancode. +Returns: + -1 whe no matching key was found, keycode2scancode->keycode >= KEY_MAX or + the matching key is not of type EV_KEY (so it is not really a key). 0 is + returned when the keycode was successfully set. +Description: + The keycode in the structure, pointed to by keycode2scancode, will be set to + the key of the hid_device, pointed to by dev->private, from which the hid + usage code is equal to keycode2scancode->scancode. +*/ +{ + struct hid_device *hid = dev->private; + struct hid_report *report; + struct hid_usage *usage; + int i, j, k; + _KEYCODE old_keycode; + + if (keycode2scancode->keycode >= KEY_MAX) + { + return -1; + } + for_each_hid_usage (usage, hid, i, j, k, report) + { + if ((usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == keycode2scancode->scancode) + { + if (usage->type != EV_KEY) + { + return -1; + } + old_keycode = usage->code; + usage->code = keycode2scancode->keycode; + + clear_bit (old_keycode, dev->keybit); + set_bit (usage->code, dev->keybit); +#ifdef DEBUG + printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", + keycode2scancode->keycode, keycode2scancode->scancode); +#endif + /* Set the keybit for the old keycode if the old keycode is used + * by another key */ + for_each_hid_usage (usage, hid, i, j, k, report) + { + if (usage->type == EV_KEY && usage->code == old_keycode) + { + set_bit (old_keycode, dev->keybit); + return (0); + } + } + return 0; + } + } + return -1; +} + + static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage) { @@ -643,7 +731,9 @@ int hidinput_connect(struct hid_device * input_dev->uniq = hid->uniq; usb_to_input_id(dev, &input_dev->id); input_dev->cdev.dev = &hid->intf->dev; - + + input_dev->setkeycode = hidinput_setkeycode; + hidinput->input = input_dev; list_add_tail(&hidinput->list, &hid->inputs); } diff -uprN -X linux-source-2.6.15-vanilla/Documentation/dontdiff linux-source-2.6.15-vanilla/include/linux/input.h linux-source-2.6.15/include/linux/input.h --- linux-source-2.6.15-vanilla/include/linux/input.h 2006-01-03 04:21:10.000000000 +0100 +++ linux-source-2.6.15/include/linux/input.h 2006-06-04 15:12:55.000000000 +0200 @@ -55,6 +55,16 @@ struct input_absinfo { __s32 flat; }; +/* begin new */ +typedef unsigned int _KEYCODE; +typedef unsigned int _SCANCODE; + +struct input_keycode2scancode { + _KEYCODE keycode; + _SCANCODE scancode; +}; +/* end new */ + #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ @@ -833,6 +843,13 @@ struct ff_effect { } \ __old; }) + +struct default_keytable { + unsigned int keycodemax; + unsigned int keycodesize; + void *keycode; +}; + struct input_dev { void *private; @@ -856,6 +873,7 @@ struct input_dev { unsigned int keycodemax; unsigned int keycodesize; void *keycode; + int (*setkeycode)(struct input_dev *dev, struct input_keycode2scancode *keycode2scancode); /* new */ unsigned int repeat_key; struct timer_list timer; ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel