Parent repository is bk://kernel.bkbits.net/vojtech/input James.Bottomley@SteelEye.com|ChangeSet|20040314215032|19484 James.Bottomley diff -Nru a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt --- a/Documentation/input/joystick-parport.txt Sun Mar 14 14:11:43 2004 +++ b/Documentation/input/joystick-parport.txt Sun Mar 14 14:11:43 2004 @@ -434,7 +434,7 @@ Using gamecon.c you can connect up to five devices to one parallel port. It uses the following kernel/module command line: - gc=port,pad1,pad2,pad3,pad4,pad5 + gamecon.map=port,pad1,pad2,pad3,pad4,pad5 Where 'port' the number of the parport interface (eg. 0 for parport0). @@ -457,15 +457,15 @@ your controller plugged in before initializing. Should you want to use more than one of parallel ports at once, you can use -gc_2 and gc_3 as additional command line parameters for two more parallel -ports. +gamecon.map2 and gamecon.map3 as additional command line parameters for two +more parallel ports. 3.2 db9.c ~~~~~~~~~ Apart from making an interface, there is nothing difficult on using the db9.c driver. It uses the following kernel/module command line: - db9=port,type + db9.dev=port,type Where 'port' is the number of the parport interface (eg. 0 for parport0). @@ -489,14 +489,14 @@ 10 | Amiga CD32 pad Should you want to use more than one of these joysticks/pads at once, you -can use db9_2 and db9_3 as additional command line parameters for two +can use db9.dev2 and db9.dev3 as additional command line parameters for two more joysticks/pads. 3.3 turbografx.c ~~~~~~~~~~~~~~~~ The turbografx.c driver uses a very simple kernel/module command line: - tgfx=port,js1,js2,js3,js4,js5,js6,js7 + turbografx.map=port,js1,js2,js3,js4,js5,js6,js7 Where 'port' is the number of the parport interface (eg. 0 for parport0). @@ -504,8 +504,8 @@ interface ports 1-7 have. For a standard multisystem joystick, this is 1. Should you want to use more than one of these interfaces at once, you can -use tgfx_2 and tgfx_3 as additional command line parameters for two more -interfaces. +use turbografx.map2 and turbografx.map3 as additional command line parameters +for two more interfaces. 3.4 PC parallel port pinout ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -Nru a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt --- a/Documentation/input/joystick.txt Sun Mar 14 14:11:43 2004 +++ b/Documentation/input/joystick.txt Sun Mar 14 14:11:43 2004 @@ -111,7 +111,7 @@ alias tty-ldisc-2 serport alias char-major-13 input above input joydev ns558 analog - options analog js=gamepad + options analog map=gamepad,none,2btn 2.5 Verifying that it works ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -185,7 +185,7 @@ module command line, when inserting analog.o into the kernel. The parameters are: - js=type,type,type,.... + analog.map=,,,.... 'type' is type of the joystick from the table below, defining joysticks present on gameports in the system, starting with gameport0, second 'type' @@ -419,7 +419,7 @@ Amiga joysticks, connected to an Amiga, are supported by the amijoy.c driver. Since they can't be autodetected, the driver has a command line. - amijoy=a,b + amijoy.map=, a and b define the joysticks connected to the JOY0DAT and JOY1DAT ports of the Amiga. diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt Sun Mar 14 14:11:43 2004 +++ b/Documentation/kernel-parameters.txt Sun Mar 14 14:11:43 2004 @@ -158,7 +158,15 @@ Format: ,,, See also header of drivers/scsi/AM53C974.c. - amijoy= [HW,JOY] Amiga joystick support + amijoy.map= [HW,JOY] Amiga joystick support + Map of devices attached to JOY0DAT and JOY1DAT + Format: , + See also Documentation/kernel/input/joystick.txt + + analog.map= [HW,JOY] Analog joystick and gamepad support + Specifies type or capabilities of an analog joystick + connected to one of 16 gameports + Format: ,,.. apc= [HW,SPARC] Power management functions (SPARCstation-4/5 + deriv.) Format: noidle @@ -181,11 +189,18 @@ atascsi= [HW,SCSI] Atari SCSI - atkbd.set= [HW] Select keyboard code set - Format: + atkbd.extra= [HW] Enable extra LEDs and keys on IBM RapidAccess, EzKey + and similar keyboards + + atkbd.reset= [HW] Reset keyboard during initialization + + atkbd.set= [HW] Select keyboard code set + Format: (2 = AT (default) 3 = PS/2) + + atkbd.scroll= [HW] Enable scroll wheel on MS Office and similar keyboards + atkbd.softrepeat= [HW] Use software keyboard repeat - atkbd.reset= [HW] Reset keyboard during initialization autotest [IA64] @@ -287,10 +302,11 @@ dasd= [HW,NET] See header of drivers/s390/block/dasd_devmap.c. - db9= [HW,JOY] - db9_2= - db9_3= - + db9.dev[2|3]= [HW,JOY] Multisystem joystick support via parallel port + (one device per port) + Format: , + See also Documentation/input/joystick-parport.txt + debug [KNL] Enable kernel debugging (events log level). decnet= [HW,NET] @@ -384,12 +400,14 @@ ftape= [HW] Floppy Tape subsystem debugging options. See Documentation/ftape.txt. + gamecon.map[2|3]= + [HW,JOY] Multisystem joystick and NES/SNES/PSX pad + support via parallel port (up to 5 devices per port) + Format: ,,,,, + See also Documentation/input/joystick-parport.txt + gamma= [HW,DRM] - gc= [HW,JOY] - gc_2= See Documentation/input/joystick-parport.txt. - gc_3= - gdth= [HW,SCSI] See header of drivers/scsi/gdth.c. @@ -616,9 +634,9 @@ mga= [HW,DRM] - mousedev.xres [MOUSE] Horizontal screen resolution, used for devices + mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices reporting absolute coordinates, such as tablets - mousedev.yres [MOUSE] Vertical screen resolution, used for devices + mousedev.yres= [MOUSE] Vertical screen resolution, used for devices reporting absolute coordinates, such as tablets mpu401= [HW,OSS] @@ -1163,10 +1181,6 @@ See header of drivers/scsi/t128.c. tdfx= [HW,DRM] - - tgfx= [HW,JOY] TurboGraFX parallel port interface - tgfx_2= See Documentation/input/joystick-parport.txt. - tgfx_3= thash_entries= [KNL,NET] Set number of hash buckets for TCP connection @@ -1189,8 +1203,13 @@ trix= [HW,OSS] MediaTrix AudioTrix Pro Format: ,,,,,,,, - tsdev.xres [TS] Horizontal screen resolution. - tsdev.yres [TS] Vertical screen resolution. + tsdev.xres= [TS] Horizontal screen resolution. + tsdev.yres= [TS] Vertical screen resolution. + + turbografx.map[2|3]= + [HW,JOY] TurboGraFX parallel port interface + Format: ,,,,,,, + See also Documentation/input/joystick-parport.txt u14-34f= [HW,SCSI] UltraStor 14F/34F SCSI host adapter See header of drivers/scsi/u14-34f.c. diff -Nru a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt --- a/Documentation/usb/acm.txt Sun Mar 14 14:11:43 2004 +++ b/Documentation/usb/acm.txt Sun Mar 14 14:11:43 2004 @@ -28,7 +28,7 @@ 1. Usage ~~~~~~~~ - The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal + The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal adapters that conform to the Universal Serial Bus Communication Device Class Abstract Control Model (USB CDC ACM) specification. @@ -65,9 +65,9 @@ To use the modems you need these modules loaded: - usbcore.o - usb-[uo]hci.o or uhci.o - acm.o + usbcore.ko + uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko + cdc-acm.ko After that, the modem[s] should be accessible. You should be able to use minicom, ppp and mgetty with them. diff -Nru a/arch/arm26/Kconfig b/arch/arm26/Kconfig --- a/arch/arm26/Kconfig Sun Mar 14 14:11:43 2004 +++ b/arch/arm26/Kconfig Sun Mar 14 14:11:43 2004 @@ -198,11 +198,6 @@ source "drivers/char/Kconfig" -config KBDMOUSE - bool - depends on ARCH_ACORN && BUSMOUSE=y - default y - source "drivers/media/Kconfig" source "fs/Kconfig" diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig --- a/drivers/char/Kconfig Sun Mar 14 14:11:43 2004 +++ b/drivers/char/Kconfig Sun Mar 14 14:11:43 2004 @@ -599,30 +599,6 @@ bool "Support for console on line printer" depends on PC9800_OLDLP - -menu "Mice" - -config BUSMOUSE - tristate "Bus Mouse Support" - ---help--- - Say Y here if your machine has a bus mouse as opposed to a serial - mouse. Most people have a regular serial MouseSystem or - Microsoft mouse (made by Logitech) that plugs into a COM port - (rectangular with 9 or 25 pins). These people say N here. - - If you have a laptop, you either have to check the documentation or - experiment a bit to find out whether the trackball is a serial mouse - or not; it's best to say Y here for you. - - This is the generic bus mouse driver code. If you have a bus mouse, - you will have to say Y here and also to the specific driver for your - mouse below. - - To compile this driver as a module, choose M here: the - module will be called busmouse. - -endmenu - config QIC02_TAPE tristate "QIC-02 tape support" help diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Sun Mar 14 14:11:43 2004 +++ b/drivers/char/Makefile Sun Mar 14 14:11:43 2004 @@ -49,7 +49,6 @@ obj-$(CONFIG_TIPAR) += tipar.o obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o -obj-$(CONFIG_BUSMOUSE) += busmouse.o obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c --- a/drivers/input/evdev.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/evdev.c Sun Mar 14 14:11:43 2004 @@ -209,7 +209,7 @@ struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; - int t, u, v; + int i, t, u, v; if (!evdev->exist) return -ENODEV; @@ -234,6 +234,9 @@ 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; case EVIOCSFF: diff -Nru a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c --- a/drivers/input/gameport/ns558.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/gameport/ns558.c Sun Mar 14 14:11:43 2004 @@ -77,7 +77,7 @@ * No one should be using this address. */ - if (check_region(io, 1)) + if (!request_region(io, 1, "ns558-isa")) return; /* @@ -89,7 +89,8 @@ outb(~c & ~3, io); if (~(u = v = inb(io)) & 3) { outb(c, io); - return; + i = 0; + goto out; } /* * After a trigger, there must be at least some bits changing. @@ -99,7 +100,8 @@ if (u == v) { outb(c, io); - return; + i = 0; + goto out; } wait_ms(3); /* @@ -110,7 +112,8 @@ for (i = 0; i < 1000; i++) if ((u ^ inb(io)) & 0xf) { outb(c, io); - return; + i = 0; + goto out; } /* * And now find the number of mirrors of the port. @@ -118,7 +121,9 @@ for (i = 1; i < 5; i++) { - if (check_region(io & (-1 << i), (1 << i))) /* Don't disturb anyone */ + release_region(io & (-1 << (i-1)), (1 << (i-1))); + + if (!request_region(io & (-1 << i), (1 << i), "ns558-isa")) /* Don't disturb anyone */ break; outb(0xff, io & (-1 << i)); @@ -126,18 +131,25 @@ if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++; wait_ms(3); - if (b > 300) /* We allow 30% difference */ + if (b > 300) { /* We allow 30% difference */ + release_region(io & (-1 << i), (1 << i)); break; + } } i--; + if (i != 4) { + if (!request_region(io & (-1 << i), (1 << i), "ns558-isa")) + return; + } + if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) { printk(KERN_ERR "ns558: Memory allocation failed.\n"); - return; + goto out; } - memset(port, 0, sizeof(struct ns558)); - + memset(port, 0, sizeof(struct ns558)); + port->type = NS558_ISA; port->size = (1 << i); port->gameport.io = io; @@ -148,8 +160,6 @@ sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i)); sprintf(port->name, "NS558 ISA"); - request_region(io & (-1 << i), (1 << i), "ns558-isa"); - gameport_register_port(&port->gameport); printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io); @@ -157,6 +167,9 @@ printk(" speed %d kHz\n", port->gameport.speed); list_add(&port->node, &ns558_list); + return; +out: + release_region(io & (-1 << i), (1 << i)); } #ifdef CONFIG_PNP @@ -276,6 +289,7 @@ #endif case NS558_ISA: release_region(port->gameport.io & ~(port->size - 1), port->size); + kfree(port); break; default: diff -Nru a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c --- a/drivers/input/joystick/amijoy.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/joystick/amijoy.c Sun Mar 14 14:11:43 2004 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -42,10 +43,15 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Driver for Amiga joysticks"); -MODULE_PARM(amijoy, "1-2i"); MODULE_LICENSE("GPL"); static int amijoy[2] = { 0, 1 }; +static int amijoy_nargs; +module_param_array_named(map, amijoy, uint, amijoy_nargs, 0); +MODULE_PARM_DESC(map, "Map of attached joysticks in form of , (default is 0,1)"); + +__obsolete_setup("amijoy="); + static int amijoy_used[2] = { 0, 0 }; static struct input_dev amijoy_dev[2]; static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; @@ -100,17 +106,6 @@ if (!--(*used)) free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); } - -static int __init amijoy_setup(char *str) -{ - int i; - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1]; - return 1; -} -__setup("amijoy=", amijoy_setup); static int __init amijoy_init(void) { diff -Nru a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c --- a/drivers/input/joystick/analog.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/joystick/analog.c Sun Mar 14 14:11:43 2004 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -50,9 +51,12 @@ #define ANALOG_PORTS 16 static char *js[ANALOG_PORTS]; +static int js_nargs; static int analog_options[ANALOG_PORTS]; -MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s"); -MODULE_PARM_DESC(js, "Analog joystick options"); +module_param_array_named(map, js, charp, js_nargs, 0); +MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities"); + +__obsolete_setup("js="); /* * Times, feature definitions. @@ -711,7 +715,7 @@ int i, j; char *end; - for (i = 0; i < ANALOG_PORTS && js[i]; i++) { + for (i = 0; i < js_nargs; i++) { for (j = 0; analog_types[j].name; j++) if (!strcmp(analog_types[j].name, js[i])) { @@ -741,24 +745,6 @@ .connect = analog_connect, .disconnect = analog_disconnect, }; - -#ifndef MODULE -static int __init analog_setup(char *str) -{ - char *s = str; - int i = 0; - - if (!str || !*str) return 0; - - while ((str = s) && (i < ANALOG_PORTS)) { - if ((s = strchr(str,','))) *s++ = 0; - js[i++] = str; - } - - return 1; -} -__setup("js=", analog_setup); -#endif int __init analog_init(void) { diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c --- a/drivers/input/joystick/db9.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/joystick/db9.c Sun Mar 14 14:11:43 2004 @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -42,9 +43,24 @@ MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(db9, "2i"); -MODULE_PARM(db9_2, "2i"); -MODULE_PARM(db9_3, "2i"); +static int db9[] __initdata = { -1, 0 }; +static int db9_nargs __initdata = 0; +module_param_array_named(dev, db9, int, db9_nargs, 0); +MODULE_PARM_DESC(dev, "Describes first attached device (,)"); + +static int db9_2[] __initdata = { -1, 0 }; +static int db9_nargs_2 __initdata = 0; +module_param_array_named(dev2, db9_2, int, db9_nargs_2, 0); +MODULE_PARM_DESC(dev2, "Describes second attached device (,)"); + +static int db9_3[] __initdata = { -1, 0 }; +static int db9_nargs_3 __initdata = 0; +module_param_array_named(dev3, db9_3, int, db9_nargs_3, 0); +MODULE_PARM_DESC(dev3, "Describes third attached device (,)"); + +__obsolete_setup("db9="); +__obsolete_setup("db9_2="); +__obsolete_setup("db9_3="); #define DB9_MULTI_STICK 0x01 #define DB9_MULTI2_STICK 0x02 @@ -76,10 +92,6 @@ #define DB9_GENESIS6_DELAY 14 #define DB9_REFRESH_TIME HZ/100 -static int db9[] __initdata = { -1, 0 }; -static int db9_2[] __initdata = { -1, 0 }; -static int db9_3[] __initdata = { -1, 0 }; - struct db9 { struct input_dev dev[DB9_MAX_DEVICES]; struct timer_list timer; @@ -518,7 +530,7 @@ } } -static struct db9 __init *db9_probe(int *config) +static struct db9 __init *db9_probe(int *config, int nargs) { struct db9 *db9; struct parport *pp; @@ -526,6 +538,12 @@ if (config[0] < 0) return NULL; + + if (nargs < 2) { + printk(KERN_ERR "db9.c: Device type must be specified.\n"); + return NULL; + } + if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) { printk(KERN_ERR "db9.c: bad config\n"); return NULL; @@ -601,38 +619,11 @@ return db9; } -#ifndef MODULE -static int __init db9_setup(char *str) -{ - int i, ints[3]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1]; - return 1; -} -static int __init db9_setup_2(char *str) -{ - int i, ints[3]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1]; - return 1; -} -static int __init db9_setup_3(char *str) -{ - int i, ints[3]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1]; - return 1; -} -__setup("db9=", db9_setup); -__setup("db9_2=", db9_setup_2); -__setup("db9_3=", db9_setup_3); -#endif - int __init db9_init(void) { - db9_base[0] = db9_probe(db9); - db9_base[1] = db9_probe(db9_2); - db9_base[2] = db9_probe(db9_3); + db9_base[0] = db9_probe(db9, db9_nargs); + db9_base[1] = db9_probe(db9_2, db9_nargs_2); + db9_base[2] = db9_probe(db9_3, db9_nargs_3); if (db9_base[0] || db9_base[1] || db9_base[2]) return 0; diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c --- a/drivers/input/joystick/gamecon.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/joystick/gamecon.c Sun Mar 14 14:11:43 2004 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -43,10 +44,26 @@ MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(gc, "2-6i"); -MODULE_PARM(gc_2,"2-6i"); -MODULE_PARM(gc_3,"2-6i"); -MODULE_PARM(gc_psx_delay, "i"); +static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_nargs __initdata = 0; +module_param_array_named(map, gc, int, gc_nargs, 0); +MODULE_PARM_DESC(map, "Describers first set of devices (,,,..)"); + +static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_nargs_2 __initdata = 0; +module_param_array_named(map2, gc_2, int, gc_nargs_2, 0); +MODULE_PARM_DESC(map2, "Describers second set of devices"); + +static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; +static int gc_nargs_3 __initdata = 0; +module_param_array_named(map3, gc_3, int, gc_nargs_3, 0); +MODULE_PARM_DESC(map3, "Describers third set of devices"); + +__obsolete_setup("gc="); +__obsolete_setup("gc_2="); +__obsolete_setup("gc_3="); + +/* see also gs_psx_delay parameter in PSX support section */ #define GC_SNES 1 #define GC_NES 2 @@ -71,10 +88,6 @@ static struct gc *gc_base[3]; -static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 }; -static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 }; - static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", @@ -232,6 +245,11 @@ #define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */ static int gc_psx_delay = GC_PSX_DELAY; +module_param_named(psx_delay, gc_psx_delay, uint, 0); +MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)"); + +__obsolete_setup("gc_psx_delay="); + static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; @@ -468,7 +486,7 @@ } } -static struct gc __init *gc_probe(int *config) +static struct gc __init *gc_probe(int *config, int nargs) { struct gc *gc; struct parport *pp; @@ -478,6 +496,11 @@ if (config[0] < 0) return NULL; + if (nargs < 2) { + printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); + return NULL; + } + pp = parport_find_number(config[0]); if (!pp) { @@ -507,7 +530,7 @@ gc->timer.data = (long) gc; gc->timer.function = gc_timer; - for (i = 0; i < 5; i++) { + for (i = 0; i < nargs - 1; i++) { if (!config[i + 1]) continue; @@ -632,44 +655,11 @@ return gc; } -#ifndef MODULE -static int __init gc_setup(char *str) -{ - int i, ints[7]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1]; - return 1; -} -static int __init gc_setup_2(char *str) -{ - int i, ints[7]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1]; - return 1; -} -static int __init gc_setup_3(char *str) -{ - int i, ints[7]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1]; - return 1; -} -static int __init gc_psx_setup(char *str) -{ - get_option(&str, &gc_psx_delay); - return 1; -} -__setup("gc=", gc_setup); -__setup("gc_2=", gc_setup_2); -__setup("gc_3=", gc_setup_3); -__setup("gc_psx_delay=", gc_psx_setup); -#endif - int __init gc_init(void) { - gc_base[0] = gc_probe(gc); - gc_base[1] = gc_probe(gc_2); - gc_base[2] = gc_probe(gc_3); + gc_base[0] = gc_probe(gc, gc_nargs); + gc_base[1] = gc_probe(gc_2, gc_nargs_2); + gc_base[2] = gc_probe(gc_3, gc_nargs_3); if (gc_base[0] || gc_base[1] || gc_base[2]) return 0; diff -Nru a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c --- a/drivers/input/joystick/turbografx.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/joystick/turbografx.c Sun Mar 14 14:11:43 2004 @@ -35,15 +35,31 @@ #include #include #include +#include #include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(tgfx, "2-8i"); -MODULE_PARM(tgfx_2, "2-8i"); -MODULE_PARM(tgfx_3, "2-8i"); +static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_nargs __initdata = 0; +module_param_array_named(map, tgfx, int, tgfx_nargs, 0); +MODULE_PARM_DESC(map, "Describes first set of devices (,,,.."); + +static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_nargs_2 __initdata = 0; +module_param_array_named(map2, tgfx_2, int, tgfx_nargs_2, 0); +MODULE_PARM_DESC(map2, "Describes second set of devices"); + +static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; +static int tgfx_nargs_3 __initdata = 0; +module_param_array_named(map3, tgfx_3, int, tgfx_nargs_3, 0); +MODULE_PARM_DESC(map3, "Describes third set of devices"); + +__obsolete_setup("tgfx="); +__obsolete_setup("tgfx_2="); +__obsolete_setup("tgfx_3="); #define TGFX_REFRESH_TIME HZ/100 /* 10 ms */ @@ -58,10 +74,6 @@ #define TGFX_TOP 0x01 #define TGFX_TOP2 0x08 -static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; -static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 }; - static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 }; static char *tgfx_name = "TurboGraFX Multisystem joystick"; @@ -133,7 +145,7 @@ * tgfx_probe() probes for tg gamepads. */ -static struct tgfx __init *tgfx_probe(int *config) +static struct tgfx __init *tgfx_probe(int *config, int nargs) { struct tgfx *tgfx; struct parport *pp; @@ -142,6 +154,11 @@ if (config[0] < 0) return NULL; + if (nargs < 2) { + printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); + return NULL; + } + pp = parport_find_number(config[0]); if (!pp) { @@ -171,7 +188,7 @@ tgfx->sticks = 0; - for (i = 0; i < 7; i++) + for (i = 0; i < nargs - 1; i++) if (config[i+1] > 0 && config[i+1] < 6) { tgfx->sticks |= (1 << i); @@ -212,38 +229,11 @@ return tgfx; } -#ifndef MODULE -static int __init tgfx_setup(char *str) -{ - int i, ints[9]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1]; - return 1; -} -static int __init tgfx_setup_2(char *str) -{ - int i, ints[9]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1]; - return 1; -} -static int __init tgfx_setup_3(char *str) -{ - int i, ints[9]; - get_options(str, ARRAY_SIZE(ints), ints); - for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1]; - return 1; -} -__setup("tgfx=", tgfx_setup); -__setup("tgfx_2=", tgfx_setup_2); -__setup("tgfx_3=", tgfx_setup_3); -#endif - int __init tgfx_init(void) { - tgfx_base[0] = tgfx_probe(tgfx); - tgfx_base[1] = tgfx_probe(tgfx_2); - tgfx_base[2] = tgfx_probe(tgfx_3); + tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs); + tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2); + tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3); if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2]) return 0; diff -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig --- a/drivers/input/keyboard/Kconfig Sun Mar 14 14:11:43 2004 +++ b/drivers/input/keyboard/Kconfig Sun Mar 14 14:11:43 2004 @@ -17,6 +17,7 @@ depends on INPUT && INPUT_KEYBOARD select SERIO select SERIO_I8042 if PC + select SERIO_GSCPS2 if GSC help Say Y here if you want to use a standard AT or PS/2 keyboard. Usually you'll need this, unless you have a different type keyboard (USB, ADB @@ -39,6 +40,19 @@ To compile this driver as a module, choose M here: the module will be called sunkbd. + +config KEYBOARD_LKKBD + tristate "DECstation/VAXstation LK201/LK401 keyboard support" + depends on INPUT && INPUT_KEYBOARD + select SERIO + help + Say Y here if you want to use a LK201 or LK401 style serial + keyboard. This keyboard is also useable on PCs if you attach + it with the inputattach program. The connector pinout is + described within lkkbd.c. + + To compile this driver as a module, choose M here: the + module will be called lkkbd. config KEYBOARD_XTKBD tristate "XT Keyboard support" diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile --- a/drivers/input/keyboard/Makefile Sun Mar 14 14:11:43 2004 +++ b/drivers/input/keyboard/Makefile Sun Mar 14 14:11:43 2004 @@ -7,6 +7,7 @@ obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o +obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c --- a/drivers/input/keyboard/atkbd.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/keyboard/atkbd.c Sun Mar 14 14:11:43 2004 @@ -30,21 +30,17 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); -MODULE_PARM(atkbd_set, "1i"); -MODULE_PARM(atkbd_reset, "1i"); -MODULE_PARM(atkbd_softrepeat, "1i"); MODULE_LICENSE("GPL"); static int atkbd_set = 2; module_param_named(set, atkbd_set, int, 0); -MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3, 4)"); +MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); + #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) static int atkbd_reset; #else static int atkbd_reset = 1; #endif -static int atkbd_softrepeat; - module_param_named(reset, atkbd_reset, bool, 0); MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); @@ -52,6 +48,18 @@ module_param_named(softrepeat, atkbd_softrepeat, bool, 0); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); +static int atkbd_scroll; +module_param_named(scroll, atkbd_scroll, bool, 0); +MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); + +static int atkbd_extra; +module_param_named(extra, atkbd_extra, bool, 0); +MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); + +__obsolete_setup("atkbd_set="); +__obsolete_setup("atkbd_reset"); +__obsolete_setup("atkbd_softrepeat="); + /* * Scancode to keycode tables. These are just the default setting, and * are loadable via an userland utility. @@ -127,11 +135,11 @@ #define ATKBD_CMD_EX_SETLEDS 0x20eb #define ATKBD_CMD_OK_GETID 0x02e8 + #define ATKBD_RET_ACK 0xfa #define ATKBD_RET_NAK 0xfe #define ATKBD_RET_BAT 0xaa #define ATKBD_RET_EMUL0 0xe0 -#define ATKBD_RET_EMULX 0x80 #define ATKBD_RET_EMUL1 0xe1 #define ATKBD_RET_RELEASE 0xf0 #define ATKBD_RET_HANGUEL 0xf1 @@ -141,6 +149,22 @@ #define ATKBD_KEY_UNKNOWN 0 #define ATKBD_KEY_NULL 255 +#define ATKBD_SCR_1 254 +#define ATKBD_SCR_2 253 +#define ATKBD_SCR_4 252 +#define ATKBD_SCR_8 251 +#define ATKBD_SCR_CLICK 250 + +#define ATKBD_SPECIAL 250 + +static unsigned char atkbd_scroll_keys[5][2] = { + { ATKBD_SCR_1, 0x45 }, + { ATKBD_SCR_2, 0x29 }, + { ATKBD_SCR_4, 0x36 }, + { ATKBD_SCR_8, 0x27 }, + { ATKBD_SCR_CLICK, 0x60 }, +}; + /* * The atkbd control structure */ @@ -155,6 +179,7 @@ unsigned char cmdbuf[4]; unsigned char cmdcnt; unsigned char set; + unsigned char extra; unsigned char release; int lastkey; volatile signed char ack; @@ -189,6 +214,7 @@ { struct atkbd *atkbd = serio->private; unsigned int code = data; + int scroll = 0, click = -1; int value; #ifdef ATKBD_DEBUG @@ -202,7 +228,7 @@ atkbd->resend = 1; goto out; } - + if (!flags && data == ATKBD_RET_ACK) atkbd->resend = 0; #endif @@ -276,7 +302,7 @@ case ATKBD_KEY_UNKNOWN: printk(KERN_WARNING "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n", atkbd->release ? "released" : "pressed", - atkbd->translated ? "translated" : "raw", + atkbd->translated ? "translated" : "raw", atkbd->set, code, serio->phys); if (atkbd->translated && atkbd->set == 2 && code == 0x7a) printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access" @@ -284,6 +310,21 @@ else printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x ' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f); break; + case ATKBD_SCR_1: + scroll = 1 - atkbd->release * 2; + break; + case ATKBD_SCR_2: + scroll = 2 - atkbd->release * 4; + break; + case ATKBD_SCR_4: + scroll = 4 - atkbd->release * 8; + break; + case ATKBD_SCR_8: + scroll = 8 - atkbd->release * 16; + break; + case ATKBD_SCR_CLICK: + click = !atkbd->release; + break; default: value = atkbd->release ? 0 : (1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); @@ -305,6 +346,13 @@ atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); } + if (scroll || click != -1) { + input_regs(&atkbd->dev, regs); + input_report_key(&atkbd->dev, BTN_MIDDLE, click); + input_report_rel(&atkbd->dev, REL_WHEEL, scroll); + input_sync(&atkbd->dev); + } + atkbd->release = 0; out: return IRQ_HANDLED; @@ -353,7 +401,7 @@ if (receive && param) for (i = 0; i < receive; i++) atkbd->cmdbuf[(receive - 1) - i] = param[i]; - + if (command & 0xff) if (atkbd_sendbyte(atkbd, command & 0xff)) return (atkbd->cmdcnt = 0) - 1; @@ -373,7 +421,7 @@ atkbd->cmdcnt = 0; break; } - + udelay(1); } @@ -420,7 +468,7 @@ | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); - if (atkbd->set == 4) { + if (atkbd->extra) { param[0] = 0; param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) @@ -466,7 +514,7 @@ */ if (atkbd_reset) - if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) + if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys); /* @@ -529,20 +577,21 @@ return 3; } - if (atkbd_set != 2) - if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) { - atkbd->id = param[0] << 8 | param[1]; + if (atkbd_extra) { + param[0] = 0x71; + if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) { + atkbd->extra = 1; return 2; } - - if (atkbd_set == 4) { - param[0] = 0x71; - if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) - return 4; } - if (atkbd_set != 3) + if (atkbd_set != 3) + return 2; + + if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) { + atkbd->id = param[0] << 8 | param[1]; return 2; + } param[0] = 3; if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET)) @@ -637,7 +686,7 @@ switch (serio->type & SERIO_TYPE) { - case SERIO_8042_XL: + case SERIO_8042_XL: atkbd->translated = 1; case SERIO_8042: if (serio->write) @@ -650,7 +699,7 @@ kfree(atkbd); return; } - + if (atkbd->write) { atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); @@ -687,7 +736,7 @@ kfree(atkbd); return; } - + atkbd->set = atkbd_set_3(atkbd); atkbd_enable(atkbd); @@ -696,24 +745,32 @@ atkbd->id = 0xab00; } - if (atkbd->set == 4) { + if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); - sprintf(atkbd->name, "AT Set 2 Extended keyboard"); + sprintf(atkbd->name, "AT Set 2 Extra keyboard"); } else sprintf(atkbd->name, "AT %s Set %d keyboard", atkbd->translated ? "Translated" : "Raw", atkbd->set); sprintf(atkbd->phys, "%s/input0", serio->phys); + if (atkbd_scroll) { + for (i = 0; i < 5; i++) + atkbd_set2_keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0]; + atkbd->dev.evbit[0] |= BIT(EV_REL); + atkbd->dev.relbit[0] = BIT(REL_WHEEL); + set_bit(BTN_MIDDLE, atkbd->dev.keybit); + } + if (atkbd->translated) { for (i = 0; i < 128; i++) { atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; } - } else if (atkbd->set == 2) { - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); - } else { + } else if (atkbd->set == 3) { memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); + } else { + memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); } atkbd->dev.name = atkbd->name; @@ -724,7 +781,7 @@ atkbd->dev.id.version = atkbd->id; for (i = 0; i < 512; i++) - if (atkbd->keycode[i] && atkbd->keycode[i] < 255) + if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) set_bit(atkbd->keycode[i], atkbd->dev.keybit); input_register_device(&atkbd->dev); @@ -741,45 +798,28 @@ { struct atkbd *atkbd = serio->private; struct serio_dev *dev = serio->dev; - int i; + unsigned char param[1]; - if (!dev) { - printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); - return -1; - } + if (!dev) { + printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); + return -1; + } if (atkbd->write) { + param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) + | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) + | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0); + if (atkbd_probe(atkbd)) return -1; - - atkbd->set = atkbd_set_3(atkbd); + if (atkbd->set != atkbd_set_3(atkbd)) + return -1; + atkbd_enable(atkbd); - } else { - atkbd->set = 2; - atkbd->id = 0xab00; - } - /* - * Here we probably should check if the keyboard has the same set that - * it had before and bail out if it's different. But this will most likely - * cause new keyboard device be created... and for the user it will look - * like keyboard is lost - */ - - if (atkbd->translated) { - for (i = 0; i < 128; i++) { - atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; - atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; - } - } else if (atkbd->set == 2) { - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); - } else { - memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); + if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS)) + return -1; } - - for (i = 0; i < 512; i++) - if (atkbd->keycode[i] && atkbd->keycode[i] < 255) - set_bit(atkbd->keycode[i], atkbd->dev.keybit); return 0; } diff -Nru a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h --- a/drivers/input/keyboard/hpps2atkbd.h Sun Mar 14 14:11:43 2004 +++ b/drivers/input/keyboard/hpps2atkbd.h Sun Mar 14 14:11:43 2004 @@ -4,14 +4,9 @@ * Copyright (c) 2004 Helge Deller * Copyright (c) 2002 Laurent Canet * Copyright (c) 2002 Thibaut Varene + * Copyright (c) 2000 Xavier Debacker * - * based on linux-2.4's hp_mouse.c & hp_keyb.c - * Copyright (c) 1999 Alex deVries - * Copyright (c) 1999-2000 Philipp Rumpf - * Copyright (c) 2000 Xavier Debacker - * Copyright (c) 2000-2001 Thomas Marteau - * - * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations + * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -19,87 +14,100 @@ */ -#define KBD_UNKNOWN 0 - -/* Raw SET 2 scancode table */ +/* undefine if you have a RDI PRECISIONBOOK */ +#define STANDARD_KEYBOARD -#if 0 - /* conflicting keys between a RDI Precisionbook keyboard and a normal HP keyboard */ - keytable[0x07] = KEY_F1; /* KEY_F12 */ - keytable[0x11] = KEY_LEFTCTRL; /* KEY_LEFTALT */ - keytable[0x14] = KEY_CAPSLOCK; /* KEY_LEFTCTRL */ - keytable[0x61] = KEY_LEFT; /* KEY_102ND */ +#if defined(STANDARD_KEYBOARD) +# define CONFLICT(x,y) x +#else +# define CONFLICT(x,y) y #endif +/* sadly RDI (Tadpole) decided to ship a different keyboard layout + than HP for their PS/2 laptop keyboard which leads to conflicting + keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook. + HP: RDI: */ +#define C_07 CONFLICT( KEY_F12, KEY_F1 ) +#define C_11 CONFLICT( KEY_LEFTALT, KEY_LEFTCTRL ) +#define C_14 CONFLICT( KEY_LEFTCTRL, KEY_CAPSLOCK ) +#define C_58 CONFLICT( KEY_CAPSLOCK, KEY_RIGHTCTRL ) +#define C_61 CONFLICT( KEY_102ND, KEY_LEFT ) -static unsigned char atkbd_set2_keycode[512] = { +/* Raw SET 2 scancode table */ - /* 00 */ KBD_UNKNOWN, KEY_F9, KBD_UNKNOWN, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F1, - /* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2, - /* 10 */ KBD_UNKNOWN, KEY_LEFTCTRL, KEY_LEFTSHIFT, KBD_UNKNOWN, KEY_CAPSLOCK, KEY_Q, KEY_1, KEY_F3, - /* 18 */ KBD_UNKNOWN, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4, - /* 20 */ KBD_UNKNOWN, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5, - /* 28 */ KBD_UNKNOWN, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6, - /* 30 */ KBD_UNKNOWN, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7, - /* 38 */ KBD_UNKNOWN, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8, - /* 40 */ KBD_UNKNOWN, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9, - /* 48 */ KBD_UNKNOWN, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_APOSTROPHE,KBD_UNKNOWN, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ, - /* 58 */ KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK, - /* 60 */ KEY_DOWN, KEY_LEFT, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT, - /* 68 */ KBD_UNKNOWN, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP, - /* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, - /* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - - /* These are offset for escaped keycodes: */ - - /* 00 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_F7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 08 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_LEFTMETA, KEY_RIGHTMETA, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 10 */ KBD_UNKNOWN, KEY_RIGHTALT, KBD_UNKNOWN, KBD_UNKNOWN, KEY_RIGHTCTRL, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 20 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 28 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 30 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 40 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 48 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPSLASH, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 58 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPENTER, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 68 */ KBD_UNKNOWN, KEY_END, KBD_UNKNOWN, KEY_LEFT, KEY_HOME, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 70 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KBD_UNKNOWN, KEY_RIGHT, KEY_UP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 78 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_PAGEDOWN, KBD_UNKNOWN, KEY_SYSRQ, KEY_PAGEUP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN +/* 00 */ KEY_RESERVED, KEY_F9, KEY_RESERVED, KEY_F5, KEY_F3, KEY_F1, KEY_F2, C_07, +/* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2, +/* 10 */ KEY_RESERVED, C_11, KEY_LEFTSHIFT, KEY_RESERVED, C_14, KEY_Q, KEY_1, KEY_F3, +/* 18 */ KEY_RESERVED, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4, +/* 20 */ KEY_RESERVED, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5, +/* 28 */ KEY_RESERVED, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6, +/* 30 */ KEY_RESERVED, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7, +/* 38 */ KEY_RESERVED, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8, +/* 40 */ KEY_RESERVED, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9, +/* 48 */ KEY_RESERVED, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10, +/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_APOSTROPHE,KEY_RESERVED, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ, +/* 58 */ C_58, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK, +/* 60 */ KEY_DOWN, C_61, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT, +/* 68 */ KEY_RESERVED, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP, +/* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, +/* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD, +/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 90 */ KEY_RESERVED, KEY_RIGHTALT, KEY_SYSRQ, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_CAPSLOCK, KEY_RESERVED, KEY_LEFTMETA, +/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTMETA, +/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_COMPOSE, +/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPSLASH, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPENTER, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e8 */ KEY_RESERVED, KEY_END, KEY_RESERVED, KEY_LEFT, KEY_HOME, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* f0 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_RESERVED, KEY_RIGHT, KEY_UP, KEY_RESERVED, KEY_PAUSE, +/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_PAGEDOWN, KEY_RESERVED, KEY_SYSRQ, KEY_PAGEUP, KEY_RESERVED, KEY_RESERVED, + +/* These are offset for escaped keycodes: */ + +/* 00 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_F7, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 08 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 10 */ KEY_RESERVED, KEY_RIGHTALT, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 18 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 20 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 28 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 30 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 38 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 40 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 48 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 58 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 60 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 68 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 70 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 78 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 90 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* e8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* f0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, +/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED + +#undef STANDARD_KEYBOARD +#undef CONFLICT +#undef C_07 +#undef C_11 +#undef C_14 +#undef C_58 +#undef C_61 -}; diff -Nru a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/keyboard/lkkbd.c Sun Mar 14 14:11:43 2004 @@ -0,0 +1,625 @@ +/* + * Copyright (C) 2004 by Jan-Benedict Glaw + */ + +/* + * LK keyboard driver for Linux, based on sunkbd.c (C) by Vojtech Pavlik + */ + +/* + * 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). + * + * DISCLAUNER: This works for _me_. If you break anything by using the + * information given below, I will _not_ be lieable! + * + * RJ11 pinout: To DB9: Or DB25: + * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) + * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND) + * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD) + * 3 - +12V (from HDD drive connector), DON'T connect to DB9 or DB25!!! + * + * Pin numbers for DB9 and DB25 are noted on the plug (quite small:). For + * RJ11, it's like this: + * + * __=__ Hold the plug in front of you, cable downwards, + * /___/| nose is hidden behind the plug. Now, pin 1 is at + * |1234|| the left side, pin 4 at the right and 2 and 3 are + * |IIII|| in between, of course:) + * | || + * |____|/ + * || So the adaptor consists of three connected cables + * || for data transmission (RxD and TxD) and signal ground. + * Additionally, you have to get +12V from somewhere. + * Most easily, you'll get that from a floppy or HDD power connector. + * It's the yellow cable there (black is ground and red is +5V). + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * email or by paper mail: + * Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.), + * Germany. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR ("Jan-Benedict Glaw "); +MODULE_DESCRIPTION ("LK keyboard driver"); +MODULE_LICENSE ("GPL"); + +/* + * Known parameters: + * bell_volume + * keyclick_volume + * ctrlclick_volume + * + * Please notice that there's not yet an API to set these at runtime. + */ +static int bell_volume = 100; /* % */ +module_param (bell_volume, int, 0); +MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%"); + +static int keyclick_volume = 100; /* % */ +module_param (keyclick_volume, int, 0); +MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%"); + +static int ctrlclick_volume = 100; /* % */ +module_param (ctrlclick_volume, int, 0); +MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%"); + + + +#undef LKKBD_DEBUG +#ifdef LKKBD_DEBUG +#define DBG(x...) printk (x) +#else +#define DBG(x...) do {} while (0) +#endif + +/* LED control */ +#define LK_LED_WAIT 0x81 +#define LK_LED_COMPOSE 0x82 +#define LK_LED_SHIFTLOCK 0x84 +#define LK_LED_SCROLLLOCK 0x88 +#define LK_CMD_LED_ON 0x13 +#define LK_CMD_LED_OFF 0x11 + +/* Mode control */ +#define LK_MODE_DOWN 0x80 +#define LK_MODE_AUTODOWN 0x82 +#define LK_MODE_UPDOWN 0x86 +#define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3)) + +/* Misc commands */ +#define LK_CMD_ENABLE_KEYCLICK 0x1b +#define LK_CMD_DISABLE_KEYCLICK 0x99 +#define LK_CMD_DISABLE_BELL 0xa1 +#define LK_CMD_SOUND_BELL 0xa7 +#define LK_CMD_ENABLE_BELL 0x23 +#define LK_CMD_DISABLE_CTRCLICK 0xb9 +#define LK_CMD_ENABLE_CTRCLICK 0xbb +#define LK_CMD_SET_DEFAULTS 0xd3 +#define LK_CMD_POWERCYCLE_RESET 0xfd +#define LK_CMD_ENABLE_LK401 0xe9 + +/* Misc responses from keyboard */ +#define LK_ALL_KEYS_UP 0xb3 +#define LK_METRONOME 0xb4 +#define LK_OUTPUT_ERROR 0xb5 +#define LK_INPUT_ERROR 0xb6 +#define LK_KBD_LOCKED 0xb7 +#define LK_KBD_TEST_MODE_ACK 0xb8 +#define LK_PREFIX_KEY_DOWN 0xb9 +#define LK_MODE_CHANGE_ACK 0xba +#define LK_RESPONSE_RESERVED 0xbb + +#define LK_NUM_KEYCODES 256 +typedef u_int16_t lk_keycode_t; + + + +static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { + [0x56] = KEY_F1, + [0x57] = KEY_F2, + [0x58] = KEY_F3, + [0x59] = KEY_F4, + [0x5a] = KEY_F5, + [0x64] = KEY_F6, + [0x65] = KEY_F7, + [0x66] = KEY_F8, + [0x67] = KEY_F9, + [0x68] = KEY_F10, + [0x71] = KEY_F11, + [0x72] = KEY_F12, + [0x73] = KEY_F13, + [0x74] = KEY_F14, + [0x7c] = KEY_F15, + [0x7d] = KEY_F16, + [0x80] = KEY_F17, + [0x81] = KEY_F18, + [0x82] = KEY_F19, + [0x83] = KEY_F20, + [0x8a] = KEY_FIND, + [0x8b] = KEY_INSERT, + [0x8c] = KEY_DELETE, + [0x8d] = KEY_SELECT, + [0x8e] = KEY_PAGEUP, + [0x8f] = KEY_PAGEDOWN, + [0x92] = KEY_KP0, + [0x94] = KEY_KPDOT, + [0x95] = KEY_KPENTER, + [0x96] = KEY_KP1, + [0x97] = KEY_KP2, + [0x98] = KEY_KP3, + [0x99] = KEY_KP4, + [0x9a] = KEY_KP5, + [0x9b] = KEY_KP6, + [0x9c] = KEY_KPCOMMA, + [0x9d] = KEY_KP7, + [0x9e] = KEY_KP8, + [0x9f] = KEY_KP9, + [0xa0] = KEY_KPMINUS, + [0xa1] = KEY_PROG1, + [0xa2] = KEY_PROG2, + [0xa3] = KEY_PROG3, + [0xa4] = KEY_PROG4, + [0xa7] = KEY_LEFT, + [0xa8] = KEY_RIGHT, + [0xa9] = KEY_DOWN, + [0xaa] = KEY_UP, + [0xab] = KEY_RIGHTSHIFT, + [0xac] = KEY_LEFTALT, + [0xad] = KEY_COMPOSE, /* Right Compose, that is. */ + [0xae] = KEY_LEFTSHIFT, /* Same as KEY_RIGHTSHIFT on LK201 */ + [0xaf] = KEY_LEFTCTRL, + [0xb0] = KEY_CAPSLOCK, + [0xb1] = KEY_COMPOSE, /* Left Compose, that is. */ + [0xb2] = KEY_RIGHTALT, + [0xbc] = KEY_BACKSPACE, + [0xbd] = KEY_ENTER, + [0xbe] = KEY_TAB, + [0xbf] = KEY_ESC, + [0xc0] = KEY_1, + [0xc1] = KEY_Q, + [0xc2] = KEY_A, + [0xc3] = KEY_Z, + [0xc5] = KEY_2, + [0xc6] = KEY_W, + [0xc7] = KEY_S, + [0xc8] = KEY_X, + [0xc9] = KEY_102ND, + [0xcb] = KEY_3, + [0xcc] = KEY_E, + [0xcd] = KEY_D, + [0xce] = KEY_C, + [0xd0] = KEY_4, + [0xd1] = KEY_R, + [0xd2] = KEY_F, + [0xd3] = KEY_V, + [0xd4] = KEY_SPACE, + [0xd6] = KEY_5, + [0xd7] = KEY_T, + [0xd8] = KEY_G, + [0xd9] = KEY_B, + [0xdb] = KEY_6, + [0xdc] = KEY_Y, + [0xdd] = KEY_H, + [0xde] = KEY_N, + [0xe0] = KEY_7, + [0xe1] = KEY_U, + [0xe2] = KEY_J, + [0xe3] = KEY_M, + [0xe5] = KEY_8, + [0xe6] = KEY_I, + [0xe7] = KEY_K, + [0xe8] = KEY_COMMA, + [0xea] = KEY_9, + [0xeb] = KEY_O, + [0xec] = KEY_L, + [0xed] = KEY_DOT, + [0xef] = KEY_0, + [0xf0] = KEY_P, + [0xf2] = KEY_SEMICOLON, + [0xf3] = KEY_SLASH, + [0xf5] = KEY_EQUAL, + [0xf6] = KEY_RIGHTBRACE, + [0xf7] = KEY_BACKSLASH, + [0xf9] = KEY_MINUS, + [0xfa] = KEY_LEFTBRACE, + [0xfb] = KEY_APOSTROPHE, +}; + +#define CHECK_LED(LED, BITS) do { \ + if (test_bit (LED, lk->dev.led)) \ + leds_on |= BITS; \ + else \ + leds_off |= BITS; \ + } while (0) + +/* + * Per-keyboard data + */ +struct lkkbd { + lk_keycode_t keycode[LK_NUM_KEYCODES]; + int ignore_bytes; + struct input_dev dev; + struct serio *serio; + struct work_struct tq; + char name[64]; + char phys[32]; + char type; + int bell_volume; + int keyclick_volume; + int ctrlclick_volume; +}; + +/* + * Calculate volume parameter byte for a given volume. + */ +static unsigned char +volume_to_hw (int volume_percent) +{ + unsigned char ret = 0; + + if (volume_percent < 0) + volume_percent = 0; + if (volume_percent > 100) + volume_percent = 100; + + if (volume_percent >= 0) + ret = 7; + if (volume_percent >= 13) /* 12.5 */ + ret = 6; + if (volume_percent >= 25) + ret = 5; + if (volume_percent >= 38) /* 37.5 */ + ret = 4; + if (volume_percent >= 50) + ret = 3; + if (volume_percent >= 63) /* 62.5 */ + ret = 2; /* This is the default volume */ + if (volume_percent >= 75) + ret = 1; + if (volume_percent >= 88) /* 87.5 */ + ret = 0; + + ret |= 0x80; + + return ret; +} + +/* + * lkkbd_interrupt() is called by the low level driver when a character + * is received. + */ +static irqreturn_t +lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, + struct pt_regs *regs) +{ + struct lkkbd *lk = serio->private; + int i; + + DBG (KERN_INFO "Got byte 0x%02x\n", data); + + if (lk->ignore_bytes > 0) { + DBG (KERN_INFO "Ignoring a byte on %s\n", + lk->name); + lk->ignore_bytes--; + return IRQ_HANDLED; + } + + switch (data) { + case LK_ALL_KEYS_UP: + input_regs (&lk->dev, regs); + for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) + if (lk->keycode[i] != KEY_RESERVED) + input_report_key (&lk->dev, lk->keycode[i], 0); + input_sync (&lk->dev); + break; + case LK_METRONOME: + DBG (KERN_INFO "Got LK_METRONOME and don't " + "know how to handle...\n"); + break; + case LK_OUTPUT_ERROR: + DBG (KERN_INFO "Got LK_OUTPUT_ERROR and don't " + "know how to handle...\n"); + break; + case LK_INPUT_ERROR: + DBG (KERN_INFO "Got LK_INPUT_ERROR and don't " + "know how to handle...\n"); + break; + case LK_KBD_LOCKED: + DBG (KERN_INFO "Got LK_KBD_LOCKED and don't " + "know how to handle...\n"); + break; + case LK_KBD_TEST_MODE_ACK: + DBG (KERN_INFO "Got LK_KBD_TEST_MODE_ACK and don't " + "know how to handle...\n"); + break; + case LK_PREFIX_KEY_DOWN: + DBG (KERN_INFO "Got LK_PREFIX_KEY_DOWN and don't " + "know how to handle...\n"); + break; + case LK_MODE_CHANGE_ACK: + DBG (KERN_INFO "Got LK_MODE_CHANGE_ACK and ignored " + "it properly...\n"); + break; + case LK_RESPONSE_RESERVED: + DBG (KERN_INFO "Got LK_RESPONSE_RESERVED and don't " + "know how to handle...\n"); + break; + case 0x01: + DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); + lk->ignore_bytes = 3; + schedule_work (&lk->tq); + break; + + default: + if (lk->keycode[data] != KEY_RESERVED) { + input_regs (&lk->dev, regs); + if (!test_bit (lk->keycode[data], lk->dev.key)) + input_report_key (&lk->dev, lk->keycode[data], 1); + else + input_report_key (&lk->dev, lk->keycode[data], 0); + input_sync (&lk->dev); + } else + printk (KERN_WARNING "%s: Unknown key with " + "scancode %02x on %s.\n", + __FILE__, data, lk->name); + } + + return IRQ_HANDLED; +} + +/* + * lkkbd_event() handles events from the input module. + */ +static int +lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, + int value) +{ + struct lkkbd *lk = dev->private; + unsigned char leds_on = 0; + unsigned char leds_off = 0; + + switch (type) { + case EV_LED: + CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED (LED_SLEEP, LK_LED_WAIT); + if (leds_on != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_ON); + lk->serio->write (lk->serio, leds_on); + } + if (leds_off != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_OFF); + lk->serio->write (lk->serio, leds_off); + } + return 0; + + case EV_SND: + switch (code) { + case SND_CLICK: + if (value == 0) { + DBG ("%s: Deactivating key clicks\n", __FUNCTION__); + lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); + lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); + } else { + DBG ("%s: Activating key clicks\n", __FUNCTION__); + lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); + lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); + } + return 0; + + case SND_BELL: + if (value != 0) + lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); + + return 0; + } + break; + + default: + printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", + __FUNCTION__, type, code, value); + } + + return -1; +} + +/* + * lkkbd_reinit() sets leds and beeps to a state the computer remembers they + * were in. + */ +static void +lkkbd_reinit (void *data) +{ + struct lkkbd *lk = data; + int division; + unsigned char leds_on = 0; + unsigned char leds_off = 0; + + /* Reset parameters */ + lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); + + /* Set LEDs */ + CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED (LED_SLEEP, LK_LED_WAIT); + if (leds_on != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_ON); + lk->serio->write (lk->serio, leds_on); + } + if (leds_off != 0) { + lk->serio->write (lk->serio, LK_CMD_LED_OFF); + lk->serio->write (lk->serio, leds_off); + } + + /* + * Try to activate extended LK401 mode. This command will + * only work with a LK401 keyboard and grants access to + * LAlt, RAlt, RCompose and RShift. + */ + lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401); + + /* Set all keys to UPDOWN mode */ + for (division = 1; division <= 14; division++) + lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, + division)); + + /* Enable bell and set volume */ + lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL); + lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); + + /* Enable/disable keyclick (and possibly set volume) */ + if (test_bit (SND_CLICK, lk->dev.snd)) { + lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); + lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); + lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); + } else { + lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); + lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); + } + + /* Sound the bell if needed */ + if (test_bit (SND_BELL, lk->dev.snd)) + lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); +} + +/* + * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. + */ +static void +lkkbd_connect (struct serio *serio, struct serio_dev *dev) +{ + struct lkkbd *lk; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + if (!(serio->type & SERIO_PROTO)) + return; + if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_LKKBD) + return; + + if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL))) + return; + memset (lk, 0, sizeof (struct lkkbd)); + + init_input_dev (&lk->dev); + + lk->dev.evbit[0] = BIT (EV_KEY) | BIT (EV_LED) | BIT (EV_SND) | BIT (EV_REP); + lk->dev.ledbit[0] = BIT (LED_CAPSL) | BIT (LED_COMPOSE) | BIT (LED_SCROLLL) | BIT (LED_SLEEP); + lk->dev.sndbit[0] = BIT (SND_CLICK) | BIT (SND_BELL); + + lk->serio = serio; + + INIT_WORK (&lk->tq, lkkbd_reinit, lk); + + lk->bell_volume = bell_volume; + lk->keyclick_volume = keyclick_volume; + lk->ctrlclick_volume = ctrlclick_volume; + + lk->dev.keycode = lk->keycode; + lk->dev.keycodesize = sizeof (lk_keycode_t); + lk->dev.keycodemax = LK_NUM_KEYCODES; + + lk->dev.event = lkkbd_event; + lk->dev.private = lk; + + serio->private = lk; + + if (serio_open (serio, dev)) { + kfree (lk); + return; + } + + sprintf (lk->name, "LK keyboard"); + + memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); + for (i = 0; i < LK_NUM_KEYCODES; i++) + set_bit (lk->keycode[i], lk->dev.keybit); + + sprintf (lk->name, "%s/input0", serio->phys); + + lk->dev.name = lk->name; + lk->dev.phys = lk->phys; + lk->dev.id.bustype = BUS_RS232; + lk->dev.id.vendor = SERIO_LKKBD; + lk->dev.id.product = 0; + lk->dev.id.version = 0x0100; + + input_register_device (&lk->dev); + + printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys); + lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); +} + +/* + * lkkbd_disconnect() unregisters and closes behind us. + */ +static void +lkkbd_disconnect (struct serio *serio) +{ + struct lkkbd *lk = serio->private; + + input_unregister_device (&lk->dev); + serio_close (serio); + kfree (lk); +} + +static struct serio_dev lkkbd_dev = { + .interrupt = lkkbd_interrupt, + .connect = lkkbd_connect, + .disconnect = lkkbd_disconnect, +}; + +/* + * The functions for insering/removing us as a module. + */ +int __init +lkkbd_init (void) +{ + serio_register_device (&lkkbd_dev); + return 0; +} + +void __exit +lkkbd_exit (void) +{ + serio_unregister_device (&lkkbd_dev); +} + +module_init (lkkbd_init); +module_exit (lkkbd_exit); + diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c --- a/drivers/input/keyboard/sunkbd.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/keyboard/sunkbd.c Sun Mar 14 14:11:43 2004 @@ -77,6 +77,7 @@ struct input_dev dev; struct serio *serio; struct work_struct tq; + wait_queue_head_t wait; char name[64]; char phys[32]; char type; @@ -96,11 +97,13 @@ if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ + wake_up_interruptible(&sunkbd->wait); goto out; } if (sunkbd->layout == -1) { sunkbd->layout = data; + wake_up_interruptible(&sunkbd->wait); goto out; } @@ -176,22 +179,19 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) { - int t; - - t = 1000; sunkbd->reset = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); - while (sunkbd->reset < 0 && --t) mdelay(1); - if (!t) return -1; + wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); + if (sunkbd->reset <0) + return -1; sunkbd->type = sunkbd->reset; if (sunkbd->type == 4) { /* Type 4 keyboard */ - t = 250; sunkbd->layout = -2; sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); - while (sunkbd->layout < 0 && --t) mdelay(1); - if (!t) return -1; + wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); + if (sunkbd->layout < 0) return -1; if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; } @@ -206,9 +206,8 @@ static void sunkbd_reinit(void *data) { struct sunkbd *sunkbd = data; - int t = 1000; - while (sunkbd->reset < 0 && --t) mdelay(1); + wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); sunkbd->serio->write(sunkbd->serio, @@ -239,6 +238,7 @@ memset(sunkbd, 0, sizeof(struct sunkbd)); init_input_dev(&sunkbd->dev); + init_waitqueue_head(&sunkbd->wait); sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); @@ -275,7 +275,7 @@ set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); clear_bit(0, sunkbd->dev.keybit); - sprintf(sunkbd->name, "%s/input", serio->phys); + sprintf(sunkbd->phys, "%s/input0", serio->phys); sunkbd->dev.name = sunkbd->name; sunkbd->dev.phys = sunkbd->phys; diff -Nru a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig --- a/drivers/input/misc/Kconfig Sun Mar 14 14:11:43 2004 +++ b/drivers/input/misc/Kconfig Sun Mar 14 14:11:43 2004 @@ -54,12 +54,3 @@ To compile this driver as a module, choose M here: the module will be called uinput. -config INPUT_GSC - tristate "PA-RISC GSC PS/2 keyboard/mouse support" - depends on GSC && INPUT && INPUT_MISC - help - Say Y here if you have a PS/2 keyboard and/or mouse attached - to your PA-RISC box. HP run the keyboard in AT mode rather than - XT mode like everyone else, so we need our own driver. - Furthermore, the GSC PS/2 controller shares IRQ between mouse and - keyboard. diff -Nru a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile --- a/drivers/input/misc/Makefile Sun Mar 14 14:11:43 2004 +++ b/drivers/input/misc/Makefile Sun Mar 14 14:11:43 2004 @@ -9,4 +9,3 @@ obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_98SPKR) += 98spkr.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o -obj-$(CONFIG_INPUT_GSC) += gsc_ps2.o diff -Nru a/drivers/input/misc/gsc_ps2.c b/drivers/input/misc/gsc_ps2.c --- a/drivers/input/misc/gsc_ps2.c Sun Mar 14 14:11:43 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,712 +0,0 @@ -/* - * drivers/input/misc/gsc_ps2.c - * - * Copyright (c) 2002 Laurent Canet - * Copyright (c) 2002 Thibaut Varene - * - * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c - * Copyright (c) 1999 Alex deVries - * Copyright (c) 1999-2000 Philipp Rumpf - * Copyright (c) 2000 Xavier Debacker - * Copyright (c) 2000-2001 Thomas Marteau - * - * HP PS/2 Keyboard, found in PA/RISC Workstations - * very similar to AT keyboards, but without i8042 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * STATUS: - * 11/09: lc: Only basic keyboard is supported, mouse still needs to be done. - * 11/12: tv: switching iomapping; cleaning code; improving module stuff. - * 11/13: lc & tv: leds aren't working. auto_repeat/meta are. Generaly good behavior. - * 11/15: tv: 2AM: leds ARE working ! - * 11/16: tv: 3AM: escaped keycodes emulation *handled*, some keycodes are - * still deliberately ignored (18), what are they used for ? - * 11/21: lc: mouse is now working - * 11/29: tv: first try for error handling in init sequence - * - * TODO: - * Error handling in init sequence - * SysRq handling - * Pause key handling - * Intellimouse & other rodents handling (at least send an error when - * such a mouse is plugged : it will totally fault) - * Mouse: set scaling / Dino testing - * Bug chasing... - * - */ - -#include -#include -#include -#include /* interrupt.h wants struct pt_regs defined */ -#include -#include /* for request_irq/free_irq */ -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Debugging stuff */ -#undef KBD_DEBUG -#ifdef KBD_DEBUG - #define DPRINTK(fmt,args...) printk(KERN_DEBUG __FILE__ ":" fmt, ##args) -#else - #define DPRINTK(x,...) -#endif - - -/* - * Driver constants - */ - -/* PS/2 keyboard and mouse constants */ -#define AUX_RECONNECT 0xAA /* PS/2 Mouse end of test successful */ -#define AUX_REPLY_ACK 0xFA -#define AUX_ENABLE_DEV 0xF4 /* Enables aux device */ - -/* Order of the mouse bytes coming to the host */ -#define PACKET_X 1 -#define PACKET_Y 2 -#define PACKET_CTRL 0 - -#define GSC_MOUSE_OFFSET 0x0100 /* offset from keyboard to mouse port */ -#define GSC_DINO_OFFSET 0x800 /* offset for DINO controller versus LASI one */ - -#define GSC_ID 0x00 /* ID and reset port offsets */ -#define GSC_RESET 0x00 -#define GSC_RCVDATA 0x04 /* receive and transmit port offsets */ -#define GSC_XMTDATA 0x04 -#define GSC_CONTROL 0x08 /* see: control register bits */ -#define GSC_STATUS 0x0C /* see: status register bits */ - -/* Control register bits */ -#define GSC_CTRL_ENBL 0x01 /* enable interface */ -#define GSC_CTRL_LPBXR 0x02 /* loopback operation */ -#define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */ -#define GSC_CTRL_DATDIR 0x40 /* data line direct control */ -#define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */ - -/* Status register bits */ -#define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */ -#define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */ -#define GSC_STAT_TERR 0x04 /* Timeout Error */ -#define GSC_STAT_PERR 0x08 /* Parity Error */ -#define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt */ -#define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */ -#define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */ - -/* Keycode map */ -#define KBD_ESCAPE0 0xe0 -#define KBD_ESCAPE1 0xe1 -#define KBD_RELEASE 0xf0 -#define KBD_ACK 0xfa -#define KBD_RESEND 0xfe -#define KBD_UNKNOWN 0 - -#define KBD_TBLSIZE 512 - -/* Mouse */ -#define MOUSE_LEFTBTN 0x1 -#define MOUSE_MIDBTN 0x4 -#define MOUSE_RIGHTBTN 0x2 -#define MOUSE_ALWAYS1 0x8 -#define MOUSE_XSIGN 0x10 -#define MOUSE_YSIGN 0x20 -#define MOUSE_XOVFLOW 0x40 -#define MOUSE_YOVFLOW 0x80 - -/* Remnant of pc_keyb.h */ -#define KBD_CMD_SET_LEDS 0xED /* Sets keyboard leds */ -#define KBD_CMD_SET_RATE 0xF3 /* Sets typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enables scanning */ -#define KBD_CMD_DISABLE 0xF5 -#define KBD_CMD_RESET 0xFF - -static unsigned char hpkeyb_keycode[KBD_TBLSIZE] = -{ - /* 00 */ KBD_UNKNOWN, KEY_F9, KBD_UNKNOWN, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12, - /* 08 */ KBD_UNKNOWN, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KBD_UNKNOWN, - /* 10 */ KBD_UNKNOWN, KEY_LEFTALT, KEY_LEFTSHIFT, KBD_UNKNOWN, KEY_LEFTCTRL, KEY_Q, KEY_1, KBD_UNKNOWN, - /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KBD_UNKNOWN, - /* 20 */ KBD_UNKNOWN, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KBD_UNKNOWN, - /* 28 */ KBD_UNKNOWN, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KBD_UNKNOWN, - /* 30 */ KBD_UNKNOWN, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KBD_UNKNOWN, - /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KBD_UNKNOWN, - /* 40 */ KBD_UNKNOWN, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KBD_UNKNOWN, - /* 48 */ KBD_UNKNOWN, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KBD_UNKNOWN, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_APOSTROPHE,KBD_UNKNOWN, KEY_LEFTBRACE, KEY_EQUAL, KBD_UNKNOWN, KBD_UNKNOWN, - /* 58 */ KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KBD_UNKNOWN, KEY_BACKSLASH,KBD_UNKNOWN, KBD_UNKNOWN, - /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_BACKSPACE, KBD_UNKNOWN, - /* 68 */ KBD_UNKNOWN, KEY_KP1, KBD_UNKNOWN, KEY_KP4, KEY_KP7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, - /* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_F7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_ESCAPE0, KBD_ESCAPE1, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_RELEASE, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_ACK, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_RESEND, KBD_UNKNOWN, -/* These are offset for escaped keycodes */ - /* 00 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 08 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 10 */ KBD_UNKNOWN, KEY_RIGHTALT, KBD_UNKNOWN, KBD_UNKNOWN, KEY_RIGHTCTRL, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 20 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 28 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 30 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 40 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 48 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPSLASH, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 58 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPENTER, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 68 */ KBD_UNKNOWN, KEY_END, KBD_UNKNOWN, KEY_LEFT, KEY_HOME, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 70 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KBD_UNKNOWN, KEY_RIGHT, KEY_UP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 78 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_PAGEDOWN, KBD_UNKNOWN, KEY_SYSRQ, KEY_PAGEUP, KBD_UNKNOWN, KBD_UNKNOWN, - /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f0 */ KBD_RELEASE, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, - /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN -}; - - -/* Keyboard struct */ -static struct { - struct input_dev dev; - char * addr; - unsigned int irq; - unsigned int scancode; - unsigned int escaped; - unsigned int released; - unsigned int initialized; -} -hpkeyb = { - .escaped = 0, - .released = 0, - .initialized = 0 -}; - -/* Mouse struct */ -static struct { - struct input_dev dev; - char * addr; - unsigned long irq; - unsigned long initialized; - int nbread; - unsigned char bytes[3]; - unsigned long last; -} -hpmouse = { - .initialized = 0, - .nbread = 0 -}; - -static spinlock_t gscps2_lock = SPIN_LOCK_UNLOCKED; - - -/* - * Various HW level routines - */ - -#define gscps2_readb_input(x) readb(x+GSC_RCVDATA) -#define gscps2_readb_control(x) readb(x+GSC_CONTROL) -#define gscps2_readb_status(x) readb(x+GSC_STATUS) -#define gscps2_writeb_control(x, y) writeb(x, y+GSC_CONTROL) - -static inline void gscps2_writeb_output(u8 val, char * addr) -{ - int wait = 250; /* Keyboard is expected to react within 250ms */ - - while (gscps2_readb_status(addr) & GSC_STAT_TBNE) { - if (!--wait) - return; /* This should not happen */ - mdelay(1); - } - writeb(val, addr+GSC_XMTDATA); -} - -static inline unsigned char gscps2_wait_input(char * addr) -{ - int wait = 250; /* Keyboard is expected to react within 250ms */ - - while (!(gscps2_readb_status(addr) & GSC_STAT_RBNE)) { - if (!--wait) - return 0; /* This should not happen */ - mdelay(1); - } - return gscps2_readb_input(addr); -} - -static int gscps2_writeb_safe_output(u8 val) -{ - /* This function waits for keyboard's ACK */ - u8 scanread = KBD_UNKNOWN; - int loop = 5; - - while (hpkeyb_keycode[scanread]!=KBD_ACK && --loop > 0) { - gscps2_writeb_output(val, hpkeyb.addr); - mdelay(5); - scanread = gscps2_wait_input(hpkeyb.addr); - } - - if (loop <= 0) - return -1; - - return 0; -} - -/* Reset the PS2 port */ -static void __init gscps2_reset(char * addr) -{ - /* reset the interface */ - writeb(0xff, addr+GSC_RESET); - writeb(0x0 , addr+GSC_RESET); - - /* enable it */ - gscps2_writeb_control(gscps2_readb_control(addr) | GSC_CTRL_ENBL, addr); -} - - -/** - * gscps2_kbd_docode() - PS2 Keyboard basic handler - * - * Receives a keyboard scancode, analyses it and sends it to the input layer. - */ - -static void gscps2_kbd_docode(struct pt_regs *regs) -{ - int scancode = gscps2_readb_input(hpkeyb.addr); - DPRINTK("rel=%d scancode=%d, esc=%d ", hpkeyb.released, scancode, hpkeyb.escaped); - - /* Handle previously escaped scancodes */ - if (hpkeyb.escaped == KBD_ESCAPE0) - scancode |= 0x100; /* jump to the next 256 chars of the table */ - - switch (hpkeyb_keycode[scancode]) { - case KBD_RELEASE: - DPRINTK("release\n"); - hpkeyb.released = 1; - break; - case KBD_RESEND: - DPRINTK("resend request\n"); - break; - case KBD_ACK: - DPRINTK("ACK\n"); - break; - case KBD_ESCAPE0: - case KBD_ESCAPE1: - DPRINTK("escape code %d\n", hpkeyb_keycode[scancode]); - hpkeyb.escaped = hpkeyb_keycode[scancode]; - break; - case KBD_UNKNOWN: - DPRINTK("received unknown scancode %d, escape %d.\n", - scancode, hpkeyb.escaped); /* This is a DPRINTK atm since we do not handle escaped scancodes cleanly */ - if (hpkeyb.escaped) - hpkeyb.escaped = 0; - if (hpkeyb.released) - hpkeyb.released = 0; - return; - default: - hpkeyb.scancode = scancode; - DPRINTK("sent=%d, rel=%d\n",hpkeyb.scancode, hpkeyb.released); - /*input_regs(regs);*/ - input_report_key(&hpkeyb.dev, hpkeyb_keycode[hpkeyb.scancode], !hpkeyb.released); - input_sync(&hpkeyb.dev); - if (hpkeyb.escaped) - hpkeyb.escaped = 0; - if (hpkeyb.released) - hpkeyb.released = 0; - break; - } -} - - -/** - * gscps2_mouse_docode() - PS2 Mouse basic handler - * - * Receives mouse codes, processes them by packets of three, and sends - * correct events to the input layer. - */ - -static void gscps2_mouse_docode(struct pt_regs *regs) -{ - int xrel, yrel; - - /* process BAT (end of basic tests) command */ - if ((hpmouse.nbread == 1) && (hpmouse.bytes[0] == AUX_RECONNECT)) - hpmouse.nbread--; - - /* stolen from psmouse.c */ - if (hpmouse.nbread && time_after(jiffies, hpmouse.last + HZ/2)) { - printk(KERN_DEBUG "%s:%d : Lost mouse synchronization, throwing %d bytes away.\n", __FILE__, __LINE__, - hpmouse.nbread); - hpmouse.nbread = 0; - } - - hpmouse.last = jiffies; - hpmouse.bytes[hpmouse.nbread++] = gscps2_readb_input(hpmouse.addr); - - /* process packet */ - if (hpmouse.nbread == 3) { - - if (!(hpmouse.bytes[PACKET_CTRL] & MOUSE_ALWAYS1)) - DPRINTK("Mouse: error on packet always1 bit checking\n"); - /* XXX should exit now, bad data on the line! */ - - if ((hpmouse.bytes[PACKET_CTRL] & (MOUSE_XOVFLOW | MOUSE_YOVFLOW))) - DPRINTK("Mouse: position overflow\n"); - - /*input_regs(regs);*/ - - input_report_key(&hpmouse.dev, BTN_LEFT, hpmouse.bytes[PACKET_CTRL] & MOUSE_LEFTBTN); - input_report_key(&hpmouse.dev, BTN_MIDDLE, hpmouse.bytes[PACKET_CTRL] & MOUSE_MIDBTN); - input_report_key(&hpmouse.dev, BTN_RIGHT, hpmouse.bytes[PACKET_CTRL] & MOUSE_RIGHTBTN); - - xrel = hpmouse.bytes[PACKET_X]; - yrel = hpmouse.bytes[PACKET_Y]; - - /* Data sent by mouse are 9-bit signed, the sign bit is in the control packet */ - if (xrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_XSIGN)) - xrel = xrel - 0x100; - if (yrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_YSIGN)) - yrel = yrel - 0x100; - - input_report_rel(&hpmouse.dev, REL_X, xrel); - input_report_rel(&hpmouse.dev, REL_Y, -yrel); /* Y axis is received upside-down */ - - input_sync(&hpmouse.dev); - - hpmouse.nbread = 0; - } -} - - -/** - * gscps2_interrupt() - Interruption service routine - * - * This processes the list of scancodes queued and sends appropriate - * key value to the system. - */ - -static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *reg) -{ - /* process mouse actions */ - while (gscps2_readb_status(hpmouse.addr) & GSC_STAT_RBNE) - gscps2_mouse_docode(reg); - - /* process keyboard scancode */ - while (gscps2_readb_status(hpkeyb.addr) & GSC_STAT_RBNE) - gscps2_kbd_docode(reg); - - return IRQ_HANDLED; -} - - -/** - * gscps2_hpkeyb_event() - Event handler - * @return: success/error report - * - * Currently only updates leds on keyboard - */ - -int gscps2_hpkeyb_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - DPRINTK("Calling %s, type=%d, code=%d, value=%d\n", - __FUNCTION__, type, code, value); - - if (!hpkeyb.initialized) - return -1; - - if (type == EV_LED) { - u8 leds[2]; - - if (gscps2_writeb_safe_output(KBD_CMD_SET_LEDS)) { - printk(KERN_ERR "gsckbd_leds: timeout\n"); - return -1; - } - DPRINTK("KBD_CMD_SET_LEDS\n"); - - *leds = (test_bit(LED_SCROLLL, dev->led) ? LED_SCR : 0) - | (test_bit(LED_NUML, dev->led) ? LED_NUM : 0) - | (test_bit(LED_CAPSL, dev->led) ? LED_CAP : 0); - DPRINTK("Sending leds=%x\n", *leds); - - if (gscps2_writeb_safe_output(*leds)) { - printk(KERN_ERR "gsckbd_leds: timeout\n"); - return -1; - } - DPRINTK("leds sent\n"); - - if (gscps2_writeb_safe_output(KBD_CMD_ENABLE)) { - printk(KERN_ERR "gsckbd_leds: timeout\n"); - return -1; - } - DPRINTK("End\n"); - - return 0; - - } - return -1; -} - - -/** - * gscps2_kbd_probe() - Probes keyboard device and init input_dev structure - * @return: number of device initialized (1, 0 on error) - */ - -static int __init gscps2_kbd_probe(void) -{ - int i, res = 0; - unsigned long flags; - - if (hpkeyb.initialized) { - printk(KERN_ERR "GSC PS/2 keyboard driver already registered\n"); - return 0; - } - - spin_lock_irqsave(&gscps2_lock, flags); - - if (!gscps2_writeb_safe_output(KBD_CMD_SET_LEDS) && - !gscps2_writeb_safe_output(0) && - !gscps2_writeb_safe_output(KBD_CMD_ENABLE)) - res = 1; - - spin_unlock_irqrestore(&gscps2_lock, flags); - - if (!res) - printk(KERN_ERR "Keyboard initialization sequence failled\n"); - - init_input_dev(&hpkeyb.dev); - - for (i = 0; i < KBD_TBLSIZE; i++) - if (hpkeyb_keycode[i] != KBD_UNKNOWN) - set_bit(hpkeyb_keycode[i], hpkeyb.dev.keybit); - - hpkeyb.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - hpkeyb.dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - hpkeyb.dev.keycode = hpkeyb_keycode; - hpkeyb.dev.keycodesize = sizeof(unsigned char); - hpkeyb.dev.keycodemax = KBD_TBLSIZE; - hpkeyb.dev.name = "GSC Keyboard"; - hpkeyb.dev.phys = "hpkbd/input0"; - - hpkeyb.dev.event = gscps2_hpkeyb_event; - - /* TODO These need some adjustement, are they really useful ? */ - hpkeyb.dev.id.bustype = BUS_GSC; - hpkeyb.dev.id.vendor = PCI_VENDOR_ID_HP; - hpkeyb.dev.id.product = 0x0001; - hpkeyb.dev.id.version = 0x0010; - hpkeyb.initialized = 1; - - return 1; -} - - -/** - * gscps2_mouse_probe() - Probes mouse device and init input_dev structure - * @return: number of device initialized (1, 0 on error) - * - * Currently no check on initialization is performed - */ - -static int __init gscps2_mouse_probe(void) -{ - if (hpmouse.initialized) { - printk(KERN_ERR "GSC PS/2 Mouse driver already registered\n"); - return 0; - } - - init_input_dev(&hpmouse.dev); - - hpmouse.dev.name = "GSC Mouse"; - hpmouse.dev.phys = "hpmouse/input0"; - hpmouse.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - hpmouse.dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - hpmouse.dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - hpmouse.last = 0; - - gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr); - /* Try it a second time, this will give status if the device is available */ - gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr); - - /* TODO These need some adjustement, are they really useful ? */ - hpmouse.dev.id.bustype = BUS_GSC; - hpmouse.dev.id.vendor = 0x0001; - hpmouse.dev.id.product = 0x0001; - hpmouse.dev.id.version = 0x0010; - hpmouse.initialized = 1; - return 1; /* XXX: we don't check if initialization failed */ -} - - -/** - * gscps2_probe() - Probes PS2 devices - * @return: success/error report - */ - -static int __init gscps2_probe(struct parisc_device *dev) -{ - u8 id; - char *addr, *name; - int ret = 0, device_found = 0; - unsigned long hpa = dev->hpa; - - if (!dev->irq) - goto fail_pitifully; - - /* Offset for DINO PS/2. Works with LASI even */ - if (dev->id.sversion == 0x96) - hpa += GSC_DINO_OFFSET; - - addr = ioremap(hpa, 256); - - if (!hpmouse.initialized || !hpkeyb.initialized) - gscps2_reset(addr); - - ret = -EINVAL; - id = readb(addr+GSC_ID) & 0x0f; - switch (id) { - case 0: /* keyboard */ - hpkeyb.addr = addr; - name = "keyboard"; - device_found = gscps2_kbd_probe(); - break; - case 1: /* mouse */ - hpmouse.addr = addr; - name = "mouse"; - device_found = gscps2_mouse_probe(); - break; - default: - printk(KERN_WARNING "%s: Unsupported PS/2 port (id=%d) ignored\n", - __FUNCTION__, id); - goto fail_miserably; - } - - /* No valid device found */ - ret = -ENODEV; - if (!device_found) - goto fail_miserably; - - /* Here we claim only if we have a device attached */ - /* Allocate the irq and memory region for that device */ - ret = -EBUSY; - if (request_irq(dev->irq, gscps2_interrupt, 0, name, NULL)) - goto fail_miserably; - - if (!request_mem_region(hpa, GSC_STATUS + 4, name)) - goto fail_request_mem; - - /* Finalize input struct and register it */ - switch (id) { - case 0: /* keyboard */ - hpkeyb.irq = dev->irq; - input_register_device(&hpkeyb.dev); - break; - case 1: /* mouse */ - hpmouse.irq = dev->irq; - input_register_device(&hpmouse.dev); - break; - default: - break; - } - - printk(KERN_INFO "input: PS/2 %s port at 0x%08lx (irq %d) found and attached\n", - name, hpa, dev->irq); - - return 0; - -fail_request_mem: free_irq(dev->irq, NULL); -fail_miserably: iounmap(addr); -fail_pitifully: return ret; -} - - - -static struct parisc_device_id gscps2_device_tbl[] = { - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ -/* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, DINO PS/2 (XXX Not yet tested) */ - { 0, } /* 0 terminated list */ -}; - -static struct parisc_driver gscps2_driver = { - .name = "GSC PS2", - .id_table = gscps2_device_tbl, - .probe = gscps2_probe, -}; - -static int __init gscps2_init(void) -{ - if (register_parisc_driver(&gscps2_driver)) - return -EBUSY; - return 0; -} - -static void __exit gscps2_exit(void) -{ - /* TODO this is probably not very good and needs to be checked */ - if (hpkeyb.initialized) { - free_irq(hpkeyb.irq, gscps2_interrupt); - iounmap(hpkeyb.addr); - hpkeyb.initialized = 0; - input_unregister_device(&hpkeyb.dev); - } - if (hpmouse.initialized) { - free_irq(hpmouse.irq, gscps2_interrupt); - iounmap(hpmouse.addr); - hpmouse.initialized = 0; - input_unregister_device(&hpmouse.dev); - } - unregister_parisc_driver(&gscps2_driver); -} - - -MODULE_AUTHOR("Laurent Canet , Thibaut Varene "); -MODULE_DESCRIPTION("GSC PS/2 keyboard/mouse driver"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); - - -module_init(gscps2_init); -module_exit(gscps2_exit); diff -Nru a/drivers/input/mouse/98busmouse.c b/drivers/input/mouse/98busmouse.c --- a/drivers/input/mouse/98busmouse.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/98busmouse.c Sun Mar 14 14:11:43 2004 @@ -74,6 +74,8 @@ module_param_named(irq, pc98bm_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (13=default)"); +__obsolete_setup("pc98bm_irq="); + static int pc98bm_used = 0; static irqreturn_t pc98bm_interrupt(int irq, void *dev_id, struct pt_regs *regs); diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig --- a/drivers/input/mouse/Kconfig Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/Kconfig Sun Mar 14 14:11:43 2004 @@ -17,6 +17,7 @@ depends on INPUT && INPUT_MOUSE select SERIO select SERIO_I8042 if PC + select SERIO_GSCPS2 if GSC ---help--- Say Y here if you have a PS/2 mouse connected to your system. This includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 @@ -116,6 +117,19 @@ To compile this driver as a module, choose M here: the module will be called rpcmouse. + +config MOUSE_VSXXXAA + tristate "DEC VSXXX-AA/GA mouse and tablet" + depends on INPUT && INPUT_MOUSE + select SERIO + help + Say Y (or M) if you want to use a DEC VSXXX-AA (hockey + puck) or a VSXXX-GA (rectangular) mouse. Theses mice are + typically used on DECstations or VAXstations, but can also + be used on any box capable of RS232 (with some adaptor + described in the source file). This driver should, in theory, + also work with the digitizer DEC produced, but it isn't tested + with that (I don't have the hardware yet). config MOUSE_PC9800 tristate "NEC PC-9800 busmouse" diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile --- a/drivers/input/mouse/Makefile Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/Makefile Sun Mar 14 14:11:43 2004 @@ -13,5 +13,6 @@ obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o +obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o psmouse-objs := psmouse-base.o logips2pp.o synaptics.o diff -Nru a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c --- a/drivers/input/mouse/inport.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/inport.c Sun Mar 14 14:11:43 2004 @@ -85,6 +85,8 @@ module_param_named(irq, inport_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (5=default)"); +__obsolete_setup("inport_irq="); + static int inport_used; static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); diff -Nru a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c --- a/drivers/input/mouse/logibm.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/logibm.c Sun Mar 14 14:11:43 2004 @@ -75,6 +75,8 @@ module_param_named(irq, logibm_irq, uint, 0); MODULE_PARM_DESC(irq, "IRQ number (5=default)"); +__obsolete_setup("logibm_irq="); + static int logibm_used = 0; static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c --- a/drivers/input/mouse/psmouse-base.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/psmouse-base.c Sun Mar 14 14:11:43 2004 @@ -47,6 +47,12 @@ module_param_named(resetafter, psmouse_resetafter, uint, 0); MODULE_PARM_DESC(resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never)."); +__obsolete_setup("psmouse_noext"); +__obsolete_setup("psmouse_resolution="); +__obsolete_setup("psmouse_smartscroll="); +__obsolete_setup("psmouse_resetafter="); +__obsolete_setup("psmouse_rate="); + static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"}; /* @@ -163,14 +169,14 @@ psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->pktcnt = 0; } - + psmouse->last = jiffies; psmouse->packet[psmouse->pktcnt++] = data; if (psmouse->packet[0] == PSMOUSE_RET_BAT) { if (psmouse->pktcnt == 1) goto out; - + if (psmouse->pktcnt == 2) { if (psmouse->packet[1] == PSMOUSE_RET_ID) { psmouse->state = PSMOUSE_IGNORE; @@ -258,7 +264,7 @@ return (psmouse->cmdcnt = 0) - 1; while (psmouse->cmdcnt && timeout--) { - + if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) /* do not run in a endless loop */ timeout = 100000; /* 1 sec */ @@ -442,7 +448,7 @@ */ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) - return -1; + printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys); /* * And here we try to determine if it has any extensions over the @@ -497,7 +503,7 @@ static void psmouse_initialize(struct psmouse *psmouse) { unsigned char param[2]; - + /* * We set the mouse report rate, resolution and scaling. */ @@ -571,7 +577,7 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) { struct psmouse *psmouse; - + if ((serio->type & SERIO_TYPE) != SERIO_8042 && (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) return; @@ -603,7 +609,7 @@ serio->private = NULL; return; } - + sprintf(psmouse->devname, "%s %s %s", psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); sprintf(psmouse->phys, "%s/input0", @@ -617,7 +623,7 @@ psmouse->dev.id.version = psmouse->model; input_register_device(&psmouse->dev); - + printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); psmouse_initialize(psmouse); @@ -637,12 +643,14 @@ { struct psmouse *psmouse = serio->private; struct serio_dev *dev = serio->dev; - int old_type = psmouse->type; + int old_type; - if (!dev) { + if (!dev || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } + + old_type = psmouse->type; psmouse->state = PSMOUSE_NEW_DEVICE; psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0; diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c --- a/drivers/input/mouse/synaptics.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/synaptics.c Sun Mar 14 14:11:43 2004 @@ -435,6 +435,8 @@ goto init_fail; } + priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; + if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities)) synaptics_pt_create(psmouse); @@ -602,19 +604,42 @@ input_sync(dev); } -static int synaptics_validate_byte(struct psmouse *psmouse) +static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) { - static unsigned char newabs_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; - static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; - static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; - static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; - struct synaptics_data *priv = psmouse->private; - int idx = psmouse->pktcnt - 1; + static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; + static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; + static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; + static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; + static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + + switch (pkt_type) { + case SYN_NEWABS: + case SYN_NEWABS_RELAXED: + return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; + + case SYN_NEWABS_STRICT: + return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; + + case SYN_OLDABS: + return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; - if (SYN_MODEL_NEWABS(priv->model_id)) - return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; - else - return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; + default: + printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); + return 0; + } +} + +static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) +{ + int i; + + for (i = 0; i < 5; i++) + if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) { + printk(KERN_INFO "synaptics: using relaxed packet validation\n"); + return SYN_NEWABS_RELAXED; + } + + return SYN_NEWABS_STRICT; } void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) @@ -630,13 +655,17 @@ printk(KERN_NOTICE "Synaptics driver resynced.\n"); } + if (unlikely(priv->pkt_type == SYN_NEWABS)) + priv->pkt_type = synaptics_detect_pkt_type(psmouse); + if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); else synaptics_process_packet(psmouse); psmouse->pktcnt = 0; - } else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) { + } else if (psmouse->pktcnt && + !synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) { printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt); psmouse->pktcnt = 0; if (++priv->out_of_sync == psmouse_resetafter) { diff -Nru a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h --- a/drivers/input/mouse/synaptics.h Sun Mar 14 14:11:43 2004 +++ b/drivers/input/mouse/synaptics.h Sun Mar 14 14:11:43 2004 @@ -70,6 +70,12 @@ #define SYN_PS_SET_MODE2 0x14 #define SYN_PS_CLIENT_CMD 0x28 +/* synaptics packet types */ +#define SYN_NEWABS 0 +#define SYN_NEWABS_STRICT 1 +#define SYN_NEWABS_RELAXED 2 +#define SYN_OLDABS 3 + /* * A structure to describe the state of the touchpad hardware (buttons and pad) */ @@ -103,6 +109,7 @@ /* Data for normal processing */ unsigned int out_of_sync; /* # of packets out of sync */ int old_w; /* Previous w value */ + unsigned char pkt_type; /* packet type - old, new, etc */ }; #endif /* _SYNAPTICS_H */ diff -Nru a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/mouse/vsxxxaa.c Sun Mar 14 14:11:43 2004 @@ -0,0 +1,550 @@ +/* + * DEC VSXXX-AA and VSXXX-GA mouse driver. + * + * Copyright (C) 2003-2004 by Jan-Benedict Glaw + * + * The packet format was taken from a patch to GPM which is (C) 2001 + * by Karsten Merker + * and Maciej W. Rozycki + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Building an adaptor to DB9 / DB25 RS232 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for + * anything if you break your mouse, your computer or whatever! + * + * In theory, this mouse is a simple RS232 device. In practice, it has got + * a quite uncommon plug and the requirement to additionally get a power + * supply at +5V and -12V. + * + * If you look at the socket/jack (_not_ at the plug), we use this pin + * numbering: + * _______ + * / 7 6 5 \ + * | 4 --- 3 | + * \ 2 1 / + * ------- + * + * DEC socket DB9 DB25 Note + * 1 (GND) 5 7 - + * 2 (RxD) 3 3 - + * 3 (TxD) 2 2 - + * 4 (-12V) - - Somewhere from the PSU. At ATX, it's + * the blue wire at pin 12 of the ATX + * power connector. Please note that the + * docs say this should be +12V! However, + * I measured -12V... + * 5 (+5V) - - PSU (red wire of ATX power connector + * on pin 4, 6, 19 or 20) or HDD power + * connector (also red wire) + * 6 (not conn.) - - - + * 7 (dev. avail.) - - The mouse shorts this one to pin 1. + * This way, the host computer can detect + * the mouse. To use it with the adaptor, + * simply don't connect this pin. + * + * So to get a working adaptor, you need to connect the mouse with three + * wires to a RS232 port and two additional wires for +5V and -12V to the + * PSU. + * + * Flow specification for the link is 4800, 8o1. + */ + +/* + * TODO list: + * - Automatically attach to a given serial port (no need for inputattach). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR ("Jan-Benedict Glaw "); +MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"); +MODULE_LICENSE ("GPL"); + +#undef VSXXXAA_DEBUG +#ifdef VSXXXAA_DEBUG +#define DBG(x...) printk (x) +#else +#define DBG(x...) do {} while (0) +#endif + +#define VSXXXAA_INTRO_MASK 0x80 +#define VSXXXAA_INTRO_HEAD 0x80 +#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \ + == VSXXXAA_INTRO_HEAD) + +#define VSXXXAA_PACKET_MASK 0xe0 +#define VSXXXAA_PACKET_REL 0x80 +#define VSXXXAA_PACKET_ABS 0xc0 +#define VSXXXAA_PACKET_POR 0xa0 +#define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == type) + + + +struct vsxxxaa { + struct input_dev dev; + struct serio *serio; +#define BUFLEN 15 /* At least 5 is needed for a full tablet packet */ + unsigned char buf[BUFLEN]; + unsigned char count; + unsigned char version; + unsigned char country; + unsigned char type; + char phys[32]; +}; + +static void +vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num) +{ + if (num >= mouse->count) + mouse->count = 0; + else { + memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num); + mouse->count -= num; + } +} + +static void +vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte) +{ + if (mouse->count == BUFLEN) { + printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n", + mouse->dev.name, mouse->dev.phys); + vsxxxaa_drop_bytes (mouse, 1); + } + + mouse->buf[mouse->count++] = byte; +} + +static void +vsxxxaa_report_mouse (struct vsxxxaa *mouse) +{ + char *devtype; + + switch (mouse->type) { + case 0x02: devtype = "DEC mouse"; break; + case 0x04: devtype = "DEC tablet"; break; + default: devtype = "unknown DEC device"; break; + } + + printk (KERN_INFO "Found %s version 0x%x from country 0x%x " + "on port %s\n", devtype, mouse->version, + mouse->country, mouse->dev.phys); +} + +/* + * Returns number of bytes to be dropped, 0 if packet is okay. + */ +static int +vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len) +{ + int i; + + /* First byte must be a header byte */ + if (!IS_HDR_BYTE (mouse->buf[0])) { + DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]); + return 1; + } + + /* Check all following bytes */ + if (packet_len > 1) { + for (i = 1; i < packet_len; i++) { + if (IS_HDR_BYTE (mouse->buf[i])) { + printk (KERN_ERR "Need to drop %d bytes " + "of a broken packet.\n", + i - 1); + DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n", + packet_len, i, mouse->buf[i]); + return i - 1; + } + } + } + + return 0; +} + +static __inline__ int +vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len) +{ + return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type); +} + +static void +vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + struct input_dev *dev = &mouse->dev; + unsigned char *buf = mouse->buf; + int left, middle, right; + int dx, dy; + + /* + * Check for normal stream packets. This is three bytes, + * with the first byte's 3 MSB set to 100. + * + * [0]: 1 0 0 SignX SignY Left Middle Right + * [1]: 0 dx dx dx dx dx dx dx + * [2]: 0 dy dy dy dy dy dy dy + */ + + /* + * Low 7 bit of byte 1 are abs(dx), bit 7 is + * 0, bit 4 of byte 0 is direction. + */ + dx = buf[1] & 0x7f; + dx *= ((buf[0] >> 4) & 0x01)? -1: 1; + + /* + * Low 7 bit of byte 2 are abs(dy), bit 7 is + * 0, bit 3 of byte 0 is direction. + */ + dy = buf[2] & 0x7f; + dy *= ((buf[0] >> 3) & 0x01)? -1: 1; + + /* + * Get button state. It's the low three bits + * (for three buttons) of byte 0. + */ + left = (buf[0] & 0x04)? 1: 0; + middle = (buf[0] & 0x02)? 1: 0; + right = (buf[0] & 0x01)? 1: 0; + + vsxxxaa_drop_bytes (mouse, 3); + + DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n", + mouse->dev.name, mouse->dev.phys, dx, dy, + left? "L": "l", middle? "M": "m", right? "R": "r"); + + /* + * Report what we've found so far... + */ + input_regs (dev, regs); + input_report_key (dev, BTN_LEFT, left); + input_report_key (dev, BTN_MIDDLE, middle); + input_report_key (dev, BTN_RIGHT, right); + input_report_rel (dev, REL_X, dx); + input_report_rel (dev, REL_Y, dy); + input_sync (dev); +} + +static void +vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + struct input_dev *dev = &mouse->dev; + unsigned char *buf = mouse->buf; + int left, middle, right, extra; + int x, y; + + /* + * Tablet position / button packet + * + * [0]: 1 1 0 B4 B3 B2 B1 Pr + * [1]: 0 0 X5 X4 X3 X2 X1 X0 + * [2]: 0 0 X11 X10 X9 X8 X7 X6 + * [3]: 0 0 Y5 Y4 Y3 Y2 Y1 Y0 + * [4]: 0 0 Y11 Y10 Y9 Y8 Y7 Y6 + */ + + /* + * Get X/Y position + */ + x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f); + y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f); + + /* + * Get button state. It's bits <4..1> of byte 0. + */ + left = (buf[0] & 0x02)? 1: 0; + middle = (buf[0] & 0x04)? 1: 0; + right = (buf[0] & 0x08)? 1: 0; + extra = (buf[0] & 0x10)? 1: 0; + + vsxxxaa_drop_bytes (mouse, 5); + + DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n", + mouse->dev.name, mouse->dev.phys, x, y, + left? "L": "l", middle? "M": "m", + right? "R": "r", extra? "E": "e"); + + /* + * Report what we've found so far... + */ + input_regs (dev, regs); + input_report_key (dev, BTN_LEFT, left); + input_report_key (dev, BTN_MIDDLE, middle); + input_report_key (dev, BTN_RIGHT, right); + input_report_key (dev, BTN_EXTRA, extra); + input_report_abs (dev, ABS_X, x); + input_report_abs (dev, ABS_Y, y); + input_sync (dev); +} + +static void +vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + struct input_dev *dev = &mouse->dev; + unsigned char *buf = mouse->buf; + int left, middle, right; + unsigned char error; + + /* + * Check for Power-On-Reset packets. These are sent out + * after plugging the mouse in, or when explicitely + * requested by sending 'T'. + * + * [0]: 1 0 1 0 R3 R2 R1 R0 + * [1]: 0 M2 M1 M0 D3 D2 D1 D0 + * [2]: 0 E6 E5 E4 E3 E2 E1 E0 + * [3]: 0 0 0 0 0 Left Middle Right + * + * M: manufacturer location code + * R: revision code + * E: Error code. I'm not sure about these, but gpm's sources, + * which support this mouse, too, tell about them: + * E = [0x00 .. 0x1f]: no error, byte #3 is button state + * E = 0x3d: button error, byte #3 tells which one. + * E = : other error + * D: <0010> == mouse, <0100> == tablet + * + */ + + mouse->version = buf[0] & 0x0f; + mouse->country = (buf[1] >> 4) & 0x07; + mouse->type = buf[1] & 0x07; + error = buf[2] & 0x7f; + + /* + * Get button state. It's the low three bits + * (for three buttons) of byte 0. Maybe even the bit <3> + * has some meaning if a tablet is attached. + */ + left = (buf[0] & 0x04)? 1: 0; + middle = (buf[0] & 0x02)? 1: 0; + right = (buf[0] & 0x01)? 1: 0; + + vsxxxaa_drop_bytes (mouse, 4); + vsxxxaa_report_mouse (mouse); + + if (error <= 0x1f) { + /* No error. Report buttons */ + input_regs (dev, regs); + input_report_key (dev, BTN_LEFT, left); + input_report_key (dev, BTN_MIDDLE, middle); + input_report_key (dev, BTN_RIGHT, right); + input_sync (dev); + } else { + printk (KERN_ERR "Your %s on %s reports an undefined error, " + "please check it...\n", mouse->dev.name, + mouse->dev.phys); + } + + /* + * If the mouse was hot-plugged, we need to + * force differential mode now... + */ + printk (KERN_NOTICE "%s on %s: Forceing standard packet format and " + "streaming mode\n", mouse->dev.name, mouse->dev.phys); + mouse->serio->write (mouse->serio, 'S'); + mouse->serio->write (mouse->serio, 'R'); +} + +static void +vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs) +{ + unsigned char *buf = mouse->buf; + int stray_bytes; + + /* + * Parse buffer to death... + */ + do { + /* + * Out of sync? Throw away what we don't understand. Each + * packet starts with a byte whose bit 7 is set. Unhandled + * packets (ie. which we don't know about or simply b0rk3d + * data...) will get shifted out of the buffer after some + * activity on the mouse. + */ + while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) { + printk (KERN_ERR "%s on %s: Dropping a byte to regain " + "sync with mouse data stream...\n", + mouse->dev.name, mouse->dev.phys); + vsxxxaa_drop_bytes (mouse, 1); + } + + /* + * Check for packets we know about. + */ + + if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet (mouse, 3); + if (stray_bytes > 0) { + printk (KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes (mouse, stray_bytes); + continue; + } + + vsxxxaa_handle_REL_packet (mouse, regs); + continue; /* More to parse? */ + } + + if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet (mouse, 5); + if (stray_bytes > 0) { + printk (KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes (mouse, stray_bytes); + continue; + } + + vsxxxaa_handle_ABS_packet (mouse, regs); + continue; /* More to parse? */ + } + + if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) { + /* Check for broken packet */ + stray_bytes = vsxxxaa_check_packet (mouse, 4); + if (stray_bytes > 0) { + printk (KERN_ERR "Dropping %d bytes now...\n", + stray_bytes); + vsxxxaa_drop_bytes (mouse, stray_bytes); + continue; + } + + vsxxxaa_handle_POR_packet (mouse, regs); + continue; /* More to parse? */ + } + + break; /* No REL, ABS or POR packet found */ + } while (1); +} + +static irqreturn_t +vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags, + struct pt_regs *regs) +{ + struct vsxxxaa *mouse = serio->private; + + vsxxxaa_queue_byte (mouse, data); + vsxxxaa_parse_buffer (mouse, regs); + + return IRQ_HANDLED; +} + +static void +vsxxxaa_disconnect (struct serio *serio) +{ + struct vsxxxaa *mouse = serio->private; + + input_unregister_device (&mouse->dev); + serio_close (serio); + kfree (mouse); +} + +static void +vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) +{ + struct vsxxxaa *mouse; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA) + return; + + if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL))) + return; + + memset (mouse, 0, sizeof (struct vsxxxaa)); + + init_input_dev (&mouse->dev); + set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */ + set_bit (EV_REL, mouse->dev.evbit); /* We can move */ + set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */ + set_bit (BTN_MIDDLE, mouse->dev.keybit); + set_bit (BTN_RIGHT, mouse->dev.keybit); + set_bit (BTN_EXTRA, mouse->dev.keybit); /* ...and Tablet */ + set_bit (REL_X, mouse->dev.relbit); /* We can move in */ + set_bit (REL_Y, mouse->dev.relbit); /* two dimensions */ + set_bit (ABS_X, mouse->dev.absbit); /* DEC tablet support */ + set_bit (ABS_Y, mouse->dev.absbit); + + mouse->dev.absmin[ABS_X] = 0; + mouse->dev.absmax[ABS_X] = 1023; + mouse->dev.absmin[ABS_Y] = 0; + mouse->dev.absmax[ABS_Y] = 1023; + + mouse->dev.private = mouse; + serio->private = mouse; + + sprintf (mouse->phys, "%s/input0", serio->phys); + mouse->dev.phys = mouse->phys; + mouse->dev.name = "DEC VSXXX-AA/GA mouse or DEC tablet"; + mouse->dev.id.bustype = BUS_RS232; + mouse->serio = serio; + + if (serio_open (serio, dev)) { + kfree (mouse); + return; + } + + /* + * Request selftest and differential stream mode. + */ + mouse->serio->write (mouse->serio, 'T'); /* Test */ + mouse->serio->write (mouse->serio, 'R'); /* Differential stream */ + + input_register_device (&mouse->dev); + + printk (KERN_INFO "input: %s on %s\n", mouse->dev.name, serio->phys); +} + +static struct serio_dev vsxxxaa_dev = { + .interrupt = vsxxxaa_interrupt, + .connect = vsxxxaa_connect, + .disconnect = vsxxxaa_disconnect +}; + +int __init +vsxxxaa_init (void) +{ + serio_register_device (&vsxxxaa_dev); + return 0; +} + +void __exit +vsxxxaa_exit (void) +{ + serio_unregister_device (&vsxxxaa_dev); +} + +module_init (vsxxxaa_init); +module_exit (vsxxxaa_exit); + diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig --- a/drivers/input/serio/Kconfig Sun Mar 14 14:11:43 2004 +++ b/drivers/input/serio/Kconfig Sun Mar 14 14:11:43 2004 @@ -20,6 +20,7 @@ tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 default y select SERIO + depends on !PARISC ---help--- i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, @@ -48,6 +49,7 @@ config SERIO_CT82C710 tristate "ct82c710 Aux port controller" depends on SERIO + depends on !PARISC ---help--- Say Y here if you have a Texas Instruments TravelMate notebook equipped with the ct82c710 chip and want to use a mouse connected @@ -104,6 +106,20 @@ To compile this driver as a module, choose M here: the module will be called 98kbd-io. + +config SERIO_GSCPS2 + tristate "HP GSC PS/2 keyboard and PS/2 mouse controller" + depends on GSC && SERIO + default y + help + This driver provides support for the PS/2 ports on PA-RISC machines + over which HP PS/2 keyboards and PS/2 mice may be connected. + If you use these devices, you'll need to say Y here. + + It's safe to enable this driver, so if unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called gscps2. config SERIO_PCIPS2 tristate "PCI PS/2 keyboard and PS/2 mouse controller" diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile --- a/drivers/input/serio/Makefile Sun Mar 14 14:11:43 2004 +++ b/drivers/input/serio/Makefile Sun Mar 14 14:11:43 2004 @@ -14,4 +14,5 @@ obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o +obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o diff -Nru a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/serio/gscps2.c Sun Mar 14 14:11:43 2004 @@ -0,0 +1,470 @@ +/* + * drivers/input/serio/gscps2.c + * + * Copyright (c) 2004 Helge Deller + * Copyright (c) 2002 Laurent Canet + * Copyright (c) 2002 Thibaut Varene + * + * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c + * Copyright (c) 1999 Alex deVries + * Copyright (c) 1999-2000 Philipp Rumpf + * Copyright (c) 2000 Xavier Debacker + * Copyright (c) 2000-2001 Thomas Marteau + * + * HP GSC PS/2 port driver, found in PA/RISC Workstations + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * TODO: + * - Dino testing (did HP ever shipped a machine on which this port + * was usable/enabled ?) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Laurent Canet , Thibaut Varene , Helge Deller "); +MODULE_DESCRIPTION("HP GSC PS/2 port driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); + +#define PFX "gscps2.c: " + +/* + * Driver constants + */ + +/* various constants */ +#define ENABLE 1 +#define DISABLE 0 + +#define GSC_DINO_OFFSET 0x0800 /* offset for DINO controller versus LASI one */ + +/* PS/2 IO port offsets */ +#define GSC_ID 0x00 /* device ID offset (see: GSC_ID_XXX) */ +#define GSC_RESET 0x00 /* reset port offset */ +#define GSC_RCVDATA 0x04 /* receive port offset */ +#define GSC_XMTDATA 0x04 /* transmit port offset */ +#define GSC_CONTROL 0x08 /* see: Control register bits */ +#define GSC_STATUS 0x0C /* see: Status register bits */ + +/* Control register bits */ +#define GSC_CTRL_ENBL 0x01 /* enable interface */ +#define GSC_CTRL_LPBXR 0x02 /* loopback operation */ +#define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */ +#define GSC_CTRL_DATDIR 0x40 /* data line direct control */ +#define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */ + +/* Status register bits */ +#define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */ +#define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */ +#define GSC_STAT_TERR 0x04 /* Timeout Error */ +#define GSC_STAT_PERR 0x08 /* Parity Error */ +#define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt = irq on any port */ +#define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */ +#define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */ + +/* IDs returned by GSC_ID port register */ +#define GSC_ID_KEYBOARD 0 /* device ID values */ +#define GSC_ID_MOUSE 1 + + +static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); + +#define BUFFER_SIZE 0x0f + +/* GSC PS/2 port device struct */ +struct gscps2port { + struct list_head node; + struct parisc_device *padev; + struct serio port; + spinlock_t lock; + char *addr; + u8 act, append; /* position in buffer[] */ + struct { + u8 data; + u8 str; + } buffer[BUFFER_SIZE+1]; + int id; + char name[32]; +}; + +/* + * Various HW level routines + */ + +#define gscps2_readb_input(x) readb((x)+GSC_RCVDATA) +#define gscps2_readb_control(x) readb((x)+GSC_CONTROL) +#define gscps2_readb_status(x) readb((x)+GSC_STATUS) +#define gscps2_writeb_control(x, y) writeb((x), (y)+GSC_CONTROL) + + +/* + * wait_TBE() - wait for Transmit Buffer Empty + */ + +static int wait_TBE(char *addr) +{ + int timeout = 25000; /* device is expected to react within 250 msec */ + while (gscps2_readb_status(addr) & GSC_STAT_TBNE) { + if (!--timeout) + return 0; /* This should not happen */ + udelay(10); + } + return 1; +} + + +/* + * gscps2_flush() - flush the receive buffer + */ + +static void gscps2_flush(struct gscps2port *ps2port) +{ + while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) + gscps2_readb_input(ps2port->addr); + ps2port->act = ps2port->append = 0; +} + +/* + * gscps2_writeb_output() - write a byte to the port + * + * returns 1 on sucess, 0 on error + */ + +static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) +{ + unsigned long flags; + char *addr = ps2port->addr; + + if (!wait_TBE(addr)) { + printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data); + return 0; + } + + while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE) + /* wait */; + + spin_lock_irqsave(&ps2port->lock, flags); + writeb(data, addr+GSC_XMTDATA); + spin_unlock_irqrestore(&ps2port->lock, flags); + + /* this is ugly, but due to timing of the port it seems to be necessary. */ + mdelay(6); + + /* make sure any received data is returned as fast as possible */ + /* this is important e.g. when we set the LEDs on the keyboard */ + gscps2_interrupt(0, NULL, NULL); + + return 1; +} + + +/* + * gscps2_enable() - enables or disables the port + */ + +static void gscps2_enable(struct gscps2port *ps2port, int enable) +{ + unsigned long flags; + u8 data; + + /* now enable/disable the port */ + spin_lock_irqsave(&ps2port->lock, flags); + gscps2_flush(ps2port); + data = gscps2_readb_control(ps2port->addr); + if (enable) + data |= GSC_CTRL_ENBL; + else + data &= ~GSC_CTRL_ENBL; + gscps2_writeb_control(data, ps2port->addr); + spin_unlock_irqrestore(&ps2port->lock, flags); + wait_TBE(ps2port->addr); + gscps2_flush(ps2port); +} + +/* + * gscps2_reset() - resets the PS/2 port + */ + +static void gscps2_reset(struct gscps2port *ps2port) +{ + char *addr = ps2port->addr; + unsigned long flags; + + /* reset the interface */ + spin_lock_irqsave(&ps2port->lock, flags); + gscps2_flush(ps2port); + writeb(0xff, addr+GSC_RESET); + gscps2_flush(ps2port); + spin_unlock_irqrestore(&ps2port->lock, flags); + + /* enable it */ + gscps2_enable(ps2port, ENABLE); +} + +static LIST_HEAD(ps2port_list); + +/** + * gscps2_interrupt() - Interruption service routine + * + * This function reads received PS/2 bytes and processes them on + * all interfaces. + * The problematic part here is, that the keyboard and mouse PS/2 port + * share the same interrupt and it's not possible to send data if any + * one of them holds input data. To solve this problem we try to receive + * the data as fast as possible and handle the reporting to the upper layer + * later. + */ + +static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + struct gscps2port *ps2port; + + list_for_each_entry(ps2port, &ps2port_list, node) { + + unsigned long flags; + spin_lock_irqsave(&ps2port->lock, flags); + + while ( (ps2port->buffer[ps2port->append].str = + gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) { + ps2port->buffer[ps2port->append].data = + gscps2_readb_input(ps2port->addr); + ps2port->append = ((ps2port->append+1) & BUFFER_SIZE); + } + + spin_unlock_irqrestore(&ps2port->lock, flags); + + } /* list_for_each_entry */ + + /* all data was read from the ports - now report the data to upper layer */ + + list_for_each_entry(ps2port, &ps2port_list, node) { + + while (ps2port->act != ps2port->append) { + + unsigned int rxflags; + u8 data, status; + + /* Did new data arrived while we read existing data ? + If yes, exit now and let the new irq handler start over again */ + if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR) + return IRQ_HANDLED; + + status = ps2port->buffer[ps2port->act].str; + data = ps2port->buffer[ps2port->act].data; + + ps2port->act = ((ps2port->act+1) & BUFFER_SIZE); + rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | + ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); + + serio_interrupt(&ps2port->port, data, rxflags, regs); + + } /* while() */ + + } /* list_for_each_entry */ + + return IRQ_HANDLED; +} + + +/* + * gscps2_write() - send a byte out through the aux interface. + */ + +static int gscps2_write(struct serio *port, unsigned char data) +{ + struct gscps2port *ps2port = port->driver; + + if (!gscps2_writeb_output(ps2port, data)) { + printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); + return -1; + } + return 0; +} + +/* + * gscps2_open() is called when a port is opened by the higher layer. + * It resets and enables the port. + */ + +static int gscps2_open(struct serio *port) +{ + struct gscps2port *ps2port = port->driver; + + gscps2_reset(ps2port); + + gscps2_interrupt(0, NULL, NULL); + + return 0; +} + +/* + * gscps2_close() disables the port + */ + +static void gscps2_close(struct serio *port) +{ + struct gscps2port *ps2port = port->driver; + gscps2_enable(ps2port, DISABLE); +} + +static struct serio gscps2_serio_port = +{ + .name = "GSC PS/2", + .idbus = BUS_GSC, + .idvendor = PCI_VENDOR_ID_HP, + .idproduct = 0x0001, + .idversion = 0x0010, + .type = SERIO_8042, + .write = gscps2_write, + .open = gscps2_open, + .close = gscps2_close, +}; + +/** + * gscps2_probe() - Probes PS2 devices + * @return: success/error report + */ + +static int __init gscps2_probe(struct parisc_device *dev) +{ + struct gscps2port *ps2port; + unsigned long hpa = dev->hpa; + int ret; + + if (!dev->irq) + return -ENODEV; + + /* Offset for DINO PS/2. Works with LASI even */ + if (dev->id.sversion == 0x96) + hpa += GSC_DINO_OFFSET; + + ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); + if (!ps2port) + return -ENOMEM; + + dev_set_drvdata(&dev->dev, ps2port); + + memset(ps2port, 0, sizeof(struct gscps2port)); + ps2port->padev = dev; + ps2port->addr = ioremap(hpa, GSC_STATUS + 4); + spin_lock_init(&ps2port->lock); + + gscps2_reset(ps2port); + ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; + snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s", + gscps2_serio_port.name, + (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); + + memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); + ps2port->port.driver = ps2port; + ps2port->port.name = ps2port->name; + ps2port->port.phys = dev->dev.bus_id; + + list_add_tail(&ps2port->node, &ps2port_list); + + ret = -EBUSY; + if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port)) + goto fail_miserably; + + if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) { + printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", + hpa, ps2port->id); + ret = -ENODEV; + goto fail; + } + +#if 0 + if (!request_mem_region(hpa, GSC_STATUS + 4, ps2port->port.name)) + goto fail; +#endif + + printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", + ps2port->name, + ps2port->addr, + ps2port->padev->irq, + ps2port->port.phys); + + serio_register_port(&ps2port->port); + + return 0; + +fail: + free_irq(dev->irq, ps2port); + +fail_miserably: + list_del(&ps2port->node); + iounmap(ps2port->addr); + release_mem_region(dev->hpa, GSC_STATUS + 4); + kfree(ps2port); + return ret; +} + +/** + * gscps2_remove() - Removes PS2 devices + * @return: success/error report + */ + +static int __devexit gscps2_remove(struct parisc_device *dev) +{ + struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); + + serio_unregister_port(&ps2port->port); + free_irq(dev->irq, ps2port); + gscps2_flush(ps2port); + list_del(&ps2port->node); + iounmap(ps2port->addr); +#if 0 + release_mem_region(dev->hpa, GSC_STATUS + 4); +#endif + dev_set_drvdata(&dev->dev, NULL); + kfree(ps2port); + return 0; +} + + +static struct parisc_device_id gscps2_device_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ +#ifdef DINO_TESTED + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, /* DINO PS/2 */ +#endif + { 0, } /* 0 terminated list */ +}; + +static struct parisc_driver parisc_ps2_driver = { + .name = "GSC PS/2", + .id_table = gscps2_device_tbl, + .probe = gscps2_probe, + .remove = gscps2_remove, +}; + +static int __init gscps2_init(void) +{ + register_parisc_driver(&parisc_ps2_driver); + return 0; +} + +static void __exit gscps2_exit(void) +{ + unregister_parisc_driver(&parisc_ps2_driver); +} + + +module_init(gscps2_init); +module_exit(gscps2_exit); + diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h --- a/drivers/input/serio/i8042-io.h Sun Mar 14 14:11:43 2004 +++ b/drivers/input/serio/i8042-io.h Sun Mar 14 14:11:43 2004 @@ -25,6 +25,9 @@ #elif defined(__ia64__) # define I8042_KBD_IRQ isa_irq_to_vector(1) # define I8042_AUX_IRQ isa_irq_to_vector(12) +#elif defined(__arm__) +/* defined in include/asm-arm/arch-xxx/irqs.h */ +#include #else # define I8042_KBD_IRQ 1 # define I8042_AUX_IRQ 12 diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/serio/i8042.c Sun Mar 14 14:11:43 2004 @@ -52,6 +52,13 @@ module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +__obsolete_setup("i8042_noaux"); +__obsolete_setup("i8042_nomux"); +__obsolete_setup("i8042_unlock"); +__obsolete_setup("i8042_reset"); +__obsolete_setup("i8042_direct"); +__obsolete_setup("i8042_dumbkbd"); + #undef DEBUG #include "i8042.h" @@ -379,6 +386,8 @@ unsigned int dfl; int ret; + mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); + spin_lock_irqsave(&i8042_lock, flags); str = i8042_read_status(); if (str & I8042_STR_OBF) @@ -433,7 +442,6 @@ irq_ret: ret = 1; out: - mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); return IRQ_RETVAL(ret); } @@ -522,6 +530,11 @@ if (i8042_enable_mux_mode(values, &mux_version)) return -1; + + /* Workaround for broken chips which seem to support MUX, but in reality don't. */ + /* They all report version 12.10 */ + if (mux_version == 0xCA) + return -1; printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", (mux_version >> 4) & 0xf, mux_version & 0xf); @@ -707,14 +720,6 @@ else printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); } - -/* - * If the chip is configured into nontranslated mode by the BIOS, don't - * bother enabling translating and be happy. - */ - - if (~i8042_ctr & I8042_CTR_XLATE) - i8042_direct = 1; /* * Set nontranslated mode for the kbd interface if requested by an option. diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c --- a/drivers/input/serio/serio.c Sun Mar 14 14:11:43 2004 +++ b/drivers/input/serio/serio.c Sun Mar 14 14:11:43 2004 @@ -195,6 +195,9 @@ ret = serio->dev->interrupt(serio, data, flags, regs); } else { if (!flags) { + if ((serio->type == SERIO_8042 || + serio->type == SERIO_8042_XL) && (data != 0xaa)) + return ret; serio_rescan(serio); ret = IRQ_HANDLED; } diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c Sun Mar 14 14:11:43 2004 +++ b/drivers/usb/input/hid-core.c Sun Mar 14 14:11:43 2004 @@ -224,6 +224,9 @@ offset = report->size; report->size += parser->global.report_size * parser->global.report_count; + if (usages < parser->global.report_count) + usages = parser->global.report_count; + if (usages == 0) return 0; /* ignore padding fields */ @@ -235,9 +238,13 @@ field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); for (i = 0; i < usages; i++) { - field->usage[i].hid = parser->local.usage[i]; + int j = i; + /* Duplicate the last usage we parsed if we have excess values */ + if (i >= parser->local.usage_index) + j = parser->local.usage_index - 1; + field->usage[i].hid = parser->local.usage[j]; field->usage[i].collection_index = - parser->local.collection_index[i]; + parser->local.collection_index[j]; } field->maxusage = usages; @@ -1069,24 +1076,41 @@ { struct hid_report *report; unsigned char dir; + int len; report = hid->ctrl[hid->ctrltail].report; dir = hid->ctrl[hid->ctrltail].dir; - if (dir == USB_DIR_OUT) + len = ((report->size - 1) >> 3) + 1 + (report->id > 0); + if (dir == USB_DIR_OUT) { hid_output_report(report, hid->ctrlbuf); - - hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); - hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); + hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0); + hid->urbctrl->transfer_buffer_length = len; + } else { + int maxpacket, padlen; + + hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0); + maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0); + if (maxpacket > 0) { + padlen = (len + maxpacket - 1) / maxpacket; + padlen *= maxpacket; + if (padlen > HID_BUFFER_SIZE) + padlen = HID_BUFFER_SIZE; + } else + padlen = 0; + hid->urbctrl->transfer_buffer_length = padlen; + } hid->urbctrl->dev = hid->dev; hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); hid->cr->wIndex = cpu_to_le16(hid->ifnum); - hid->cr->wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); + hid->cr->wLength = cpu_to_le16(len); - dbg("submitting ctrl urb"); + dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u", + hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", + hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength); if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { err("usb_submit_urb(ctrl) failed"); @@ -1262,9 +1286,25 @@ struct hid_report_enum *report_enum; struct hid_report *report; struct list_head *list; - int len; int err, ret; + /* + * The Set_Idle request is supposed to affect only the + * "Interrupt In" pipe. Unfortunately, buggy devices such as + * the BTC keyboard (ID 046e:5303) the request also affects + * Get_Report requests on the control pipe. In the worst + * case, if the device was put on idle for an indefinite + * amount of time (as we do below) and there are no input + * events to report, the Get_Report requests will just hang + * until we get a USB timeout. To avoid this, we temporarily + * establish a minimal idle time of 1ms. This shouldn't hurt + * bugfree devices and will cause a worst-case extra delay of + * 1ms for buggy ones. + */ + usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), + HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (1 << 8), + hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + report_enum = hid->report_enum + HID_INPUT_REPORT; list = report_enum->report_list.next; while (list != &report_enum->report_list) { @@ -1297,11 +1337,8 @@ list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; - len = ((report->size - 1) >> 3) + 1 + report_enum->numbered; - if (len > hid->urbin->transfer_buffer_length) - hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE; usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), - 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, + HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); list = list->next; } @@ -1313,11 +1350,12 @@ #define USB_DEVICE_ID_WACOM_INTUOS 0x0020 #define USB_DEVICE_ID_WACOM_PL 0x0030 #define USB_DEVICE_ID_WACOM_INTUOS2 0x0040 +#define USB_DEVICE_ID_WACOM_VOLITO 0x0060 +#define USB_DEVICE_ID_WACOM_PTU 0x0003 #define USB_VENDOR_ID_KBGEAR 0x084e #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 - #define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_DEVICE_ID_AIPTEK_6000 0x0020 @@ -1356,22 +1394,52 @@ #define USB_VENDOR_ID_A4TECH 0x09DA #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 +#define USB_VENDOR_ID_CYPRESS 0x04b4 +#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 + #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 #define USB_VENDOR_ID_ALPS 0x0433 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 +#define USB_VENDOR_ID_SAITEK 0x06a3 +#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 + +#define USB_VENDOR_ID_NEC 0x073e +#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 + +#define USB_VENDOR_ID_CHIC 0x05fe +#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; unsigned quirks; } hid_blacklist[] = { + + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, @@ -1383,37 +1451,34 @@ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK }, - { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_BACK }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA }, + { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, + { 0, 0 } }; @@ -1518,12 +1583,17 @@ continue; if (endpoint->bEndpointAddress & USB_DIR_IN) { + int len; + if (hid->urbin) continue; if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, + len = usb_maxpacket(dev, pipe, 0); + if (len > HID_BUFFER_SIZE) + len = HID_BUFFER_SIZE; + usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len, hid_irq_in, hid, endpoint->bInterval); hid->urbin->transfer_dma = hid->inbuf_dma; hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff -Nru a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c --- a/drivers/usb/input/hid-ff.c Sun Mar 14 14:11:43 2004 +++ b/drivers/usb/input/hid-ff.c Sun Mar 14 14:11:43 2004 @@ -29,7 +29,7 @@ #include -#define DEBUG +#undef DEBUG #include #include "hid.h" diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c --- a/drivers/usb/input/hid-input.c Sun Mar 14 14:11:43 2004 +++ b/drivers/usb/input/hid-input.c Sun Mar 14 14:11:43 2004 @@ -377,7 +377,8 @@ set_bit(usage->type, input->evbit); if ((usage->type == EV_REL) - && (device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK) + && (device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_BACK + | HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA)) && (usage->code == REL_WHEEL)) { set_bit(REL_HWHEEL, bit); } @@ -431,21 +432,22 @@ input_regs(input, regs); - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK) - && (usage->code == BTN_BACK)) { + if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA) && (usage->code == BTN_EXTRA)) + || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_BACK) && (usage->code == BTN_BACK))) { if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; return; } + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { input_event(input, usage->type, REL_HWHEEL, value); return; } - if (usage->hat_min != usage->hat_max) { + if (usage->hat_min != usage->hat_max ) { /* FIXME: hat_max can be 0 and hat_min 1 */ value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; if (value < 0 || value > 8) value = 0; input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x); @@ -484,7 +486,7 @@ return; } - if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */ + if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ return; input_event(input, usage->type, usage->code, value); @@ -567,8 +569,10 @@ while (list != &report_enum->report_list) { report = (struct hid_report *) list; - if (!report->maxfield) + if (!report->maxfield) { + list = list->next; continue; + } if (!hidinput) { hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h --- a/drivers/usb/input/hid.h Sun Mar 14 14:11:43 2004 +++ b/drivers/usb/input/hid.h Sun Mar 14 14:11:43 2004 @@ -201,15 +201,16 @@ * HID device quirks. */ -#define HID_QUIRK_INVERT 0x001 -#define HID_QUIRK_NOTOUCH 0x002 -#define HID_QUIRK_IGNORE 0x004 -#define HID_QUIRK_NOGET 0x008 -#define HID_QUIRK_HIDDEV 0x010 -#define HID_QUIRK_BADPAD 0x020 -#define HID_QUIRK_MULTI_INPUT 0x040 -#define HID_QUIRK_2WHEEL_MOUSE_HACK 0x080 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x100 +#define HID_QUIRK_INVERT 0x001 +#define HID_QUIRK_NOTOUCH 0x002 +#define HID_QUIRK_IGNORE 0x004 +#define HID_QUIRK_NOGET 0x008 +#define HID_QUIRK_HIDDEV 0x010 +#define HID_QUIRK_BADPAD 0x020 +#define HID_QUIRK_MULTI_INPUT 0x040 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_BACK 0x080 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA 0x100 +#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x200 /* * This is the global environment of the parser. This information is @@ -309,7 +310,7 @@ #define HID_REPORT_TYPES 3 -#define HID_BUFFER_SIZE 32 +#define HID_BUFFER_SIZE 64 /* use 64 for compatibility with all possible packetlen */ #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ #define HID_OUTPUT_FIFO_SIZE 64 diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c --- a/drivers/usb/input/hiddev.c Sun Mar 14 14:11:43 2004 +++ b/drivers/usb/input/hiddev.c Sun Mar 14 14:11:43 2004 @@ -403,7 +403,8 @@ struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref uref; + struct hiddev_usage_ref_multi uref_multi; + struct hiddev_usage_ref *uref = &uref_multi.uref; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; @@ -575,68 +576,98 @@ return 0; case HIDIOCGUCODE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) return -EFAULT; - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - if (uref.field_index >= report->maxfield) + if (uref->field_index >= report->maxfield) return -EINVAL; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) + field = report->field[uref->field_index]; + if (uref->usage_index >= field->maxusage) return -EINVAL; - uref.usage_code = field->usage[uref.usage_index].hid; + uref->usage_code = field->usage[uref->usage_index].hid; - if (copy_to_user((void *) arg, &uref, sizeof(uref))) + if (copy_to_user((void *) arg, uref, sizeof(*uref))) return -EFAULT; return 0; case HIDIOCGUSAGE: case HIDIOCSUSAGE: + case HIDIOCGUSAGES: + case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) - return -EFAULT; + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { + if (copy_from_user(&uref_multi, (void *) arg, + sizeof(uref_multi))) + return -EFAULT; + } else { + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) + return -EFAULT; + } - if (cmd != HIDIOCGUSAGE && uref.report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; + if (cmd != HIDIOCGUSAGE && + cmd != HIDIOCGUSAGES && + uref->report_type == HID_REPORT_TYPE_INPUT) + return -EINVAL; - if (uref.report_id == HID_REPORT_ID_UNKNOWN) { - field = hiddev_lookup_usage(hid, &uref); + if (uref->report_id == HID_REPORT_ID_UNKNOWN) { + field = hiddev_lookup_usage(hid, uref); if (field == NULL) return -EINVAL; } else { - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - if (uref.field_index >= report->maxfield) + if (uref->field_index >= report->maxfield) return -EINVAL; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) + field = report->field[uref->field_index]; + if (uref->usage_index >= field->maxusage) return -EINVAL; + + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { + if (uref_multi.num_values >= HID_MAX_USAGES || + uref->usage_index >= field->maxusage || + (uref->usage_index + uref_multi.num_values) >= field->maxusage) + return -EINVAL; + } } switch (cmd) { case HIDIOCGUSAGE: - uref.value = field->value[uref.usage_index]; - if (copy_to_user((void *) arg, &uref, sizeof(uref))) + uref->value = field->value[uref->usage_index]; + if (copy_to_user((void *) arg, uref, sizeof(*uref))) return -EFAULT; return 0; case HIDIOCSUSAGE: - field->value[uref.usage_index] = uref.value; + field->value[uref->usage_index] = uref->value; return 0; case HIDIOCGCOLLECTIONINDEX: - return field->usage[uref.usage_index].collection_index; + return field->usage[uref->usage_index].collection_index; + case HIDIOCGUSAGES: + for (i = 0; i < uref_multi.num_values; i++) + uref_multi.values[i] = + field->value[uref->usage_index + i]; + if (copy_to_user((void *) arg, &uref_multi, + sizeof(uref_multi))) + return -EFAULT; + return 0; + case HIDIOCSUSAGES: + for (i = 0; i < uref_multi.num_values; i++) + field->value[uref->usage_index + i] = + uref_multi.values[i]; + return 0; } return 0; diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Sun Mar 14 14:11:43 2004 +++ b/drivers/usb/input/wacom.c Sun Mar 14 14:11:43 2004 @@ -1,14 +1,15 @@ /* * USB Wacom Graphire and Wacom Intuos tablet support * - * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2000-2004 Vojtech Pavlik * Copyright (c) 2000 Andreas Bach Aaen * Copyright (c) 2000 Clifford Wolf * Copyright (c) 2000 Sam Mosel * Copyright (c) 2000 James E. Blair * Copyright (c) 2000 Daniel Egger * Copyright (c) 2001 Frederic Lepied - * Copyright (c) 2002 Ping Cheng + * Copyright (c) 2004 Panagiotis Issaris + * Copyright (c) 2002-2004 Ping Cheng * * ChangeLog: * v0.1 (vp) - Initial release @@ -48,6 +49,8 @@ * v1.30 (vp) - Merge 2.4 and 2.5 drivers * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse * - Cleanups here and there + * v1.30.1 (pi) - Added Graphire3 support + * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ... */ /* @@ -106,7 +109,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type, unsigned char id, void *buf, int size) { - return usb_control_msg(interface_to_usbdev(intf), + return usb_control_msg(interface_to_usbdev(intf), usb_sndctrlpipe(interface_to_usbdev(intf), 0), USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, @@ -137,14 +140,12 @@ } if (data[0] != 2) - dbg("received unknown report #%d", data[0]); + dbg("wacom_pl_irq: received unknown report #%d", data[0]); prox = data[1] & 0x40; input_regs(dev, regs); - input_report_key(dev, BTN_TOOL_PEN, prox); - if (prox) { pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); @@ -152,15 +153,103 @@ pressure = (pressure << 1) | ((data[4] >> 6) & 1); pressure += (wacom->features->pressure_max + 1) / 2; + /* + * if going from out of proximity into proximity select between the eraser + * and the pen based on the state of the stylus2 button, choose eraser if + * pressed else choose pen. if not a proximity change from out to in, send + * an out of proximity for previous tool then a in for new tool. + */ + if (!wacom->tool[0]) { + /* Going into proximity select tool */ + wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN; + } + else { + /* was entered with stylus2 pressed */ + if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) { + /* report out proximity for previous tool */ + input_report_key(dev, wacom->tool[1], 0); + input_sync(dev); + wacom->tool[1] = BTN_TOOL_PEN; + goto exit; + } + } + if (wacom->tool[1] != BTN_TOOL_RUBBER) { + /* Unknown tool selected default to pen tool */ + wacom->tool[1] = BTN_TOOL_PEN; + } + input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */ input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14)); input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14)); input_report_abs(dev, ABS_PRESSURE, pressure); input_report_key(dev, BTN_TOUCH, data[4] & 0x08); input_report_key(dev, BTN_STYLUS, data[4] & 0x10); - input_report_key(dev, BTN_STYLUS2, data[4] & 0x20); + /* Only allow the stylus2 button to be reported for the pen tool. */ + input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); } - + else { + /* report proximity-out of a (valid) tool */ + if (wacom->tool[1] != BTN_TOOL_RUBBER) { + /* Unknown tool selected default to pen tool */ + wacom->tool[1] = BTN_TOOL_PEN; + } + input_report_key(dev, wacom->tool[1], prox); + } + + wacom->tool[0] = prox; /* Save proximity state */ + input_sync(dev); + +exit: + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result %d", + __FUNCTION__, retval); +} + +static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) +{ + struct wacom *wacom = urb->context; + unsigned char *data = wacom->data; + struct input_dev *dev = &wacom->dev; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + goto exit; + } + + if (data[0] != 2) + { + printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); + } + + input_regs(dev, regs); + if (data[1] & 0x04) + { + input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20); + input_report_key(dev, BTN_TOUCH, data[1] & 0x08); + } + else + { + input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20); + input_report_key(dev, BTN_TOUCH, data[1] & 0x01); + } + input_report_abs(dev, ABS_X, data[3] << 8 | data[2]); + input_report_abs(dev, ABS_Y, data[5] << 8 | data[4]); + input_report_abs(dev, ABS_PRESSURE, (data[6]|data[7] << 8)); + input_report_key(dev, BTN_STYLUS, data[1] & 0x02); + input_report_key(dev, BTN_STYLUS2, data[1] & 0x10); + input_sync(dev); exit: @@ -231,8 +320,12 @@ goto exit; } + /* check if we can handle the data */ + if (data[0] == 99) + goto exit; + if (data[0] != 2) - dbg("received unknown report #%d", data[0]); + dbg("wacom_graphire_irq: received unknown report #%d", data[0]); x = data[2] | ((__u32)data[3] << 8); y = data[4] | ((__u32)data[5] << 8); @@ -249,13 +342,16 @@ input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80); break; - case 2: /* Mouse */ + case 2: /* Mouse with wheel */ + input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); + input_report_rel(dev, REL_WHEEL, (signed char) data[6]); + /* fall through */ + + case 3: /* Mouse without wheel */ input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24); input_report_key(dev, BTN_LEFT, data[1] & 0x01); input_report_key(dev, BTN_RIGHT, data[1] & 0x02); - input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); input_report_abs(dev, ABS_DISTANCE, data[7]); - input_report_rel(dev, REL_WHEEL, (signed char) data[6]); input_report_abs(dev, ABS_X, x); input_report_abs(dev, ABS_Y, y); @@ -308,7 +404,7 @@ } if (data[0] != 2) - dbg("received unknown report #%d", data[0]); + dbg("wacom_intuos_irq: received unknown report #%d", data[0]); input_regs(dev, regs); @@ -317,18 +413,18 @@ if ((data[1] & 0xfc) == 0xc0) { /* Enter report */ - wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 4) + /* serial number of the tool */ - ((__u32)data[4] << 16) + ((__u32)data[5] << 12) + + wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) + /* serial number of the tool */ + ((__u32)data[4] << 20) + ((__u32)data[5] << 12) + ((__u32)data[6] << 4) + (data[7] >> 4); switch (((__u32)data[2] << 4) | (data[3] >> 4)) { - case 0x832: + case 0x812: case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL; break; /* Inking pen */ case 0x822: case 0x842: case 0x852: case 0x022: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Pen */ - case 0x812: + case 0x832: case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH; break; /* Stroke pen */ case 0x007: case 0x09c: @@ -337,7 +433,10 @@ case 0x82a: case 0x85a: case 0x91a: + case 0xd1a: case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER; break; /* Eraser */ + case 0xd12: + case 0x912: case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH; break; /* Airbrush */ default: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Unknown tool */ } @@ -350,13 +449,14 @@ if ((data[1] & 0xfe) == 0x80) { /* Exit report */ input_report_key(dev, wacom->tool[idx], 0); + input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); goto exit; } input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]); input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]); - input_report_abs(dev, ABS_DISTANCE, data[9] >> 4); + input_report_abs(dev, ABS_DISTANCE, data[9]); if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */ input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); @@ -378,8 +478,8 @@ if (data[1] & 0x02) { /* Rotation packet */ input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? - ((__u32)data[6] << 2) | ((data[7] >> 6) & 3): - (-(((__u32)data[6] << 2) | ((data[7] >> 6) & 3))) - 1); + ((__u32)data[6] << 3) | ((data[7] >> 5) & 7): + (-(((__u32)data[6] << 3) | ((data[7] >> 5) & 7))) - 1); } else { @@ -391,17 +491,17 @@ input_report_key(dev, BTN_SIDE, data[8] & 0x20); input_report_key(dev, BTN_EXTRA, data[8] & 0x10); - input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? + input_report_abs(dev, ABS_THROTTLE, -((data[8] & 0x08) ? ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) : - -((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); + -((__u32)data[6] << 2) | ((data[7] >> 6) & 3))); } else { if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */ input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_RIGHT, data[8] & 0x10); - input_report_abs(dev, REL_WHEEL, - ((__u32)(data[8] & 0x01) - (__u32)((data[8] & 0x02) >> 1))); + input_report_rel(dev, REL_WHEEL, + (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1))); } else { /* Lens cursor packets */ input_report_key(dev, BTN_LEFT, data[8] & 0x01); @@ -414,6 +514,8 @@ } } + input_report_key(dev, wacom->tool[idx], 1); + input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); exit: @@ -429,22 +531,26 @@ { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire3", 8, 10208, 7424, 511, 32, 1, wacom_graphire_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10360, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 6x8", 10, 20600, 16450, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 9x12", 10, 30670, 24130, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x12", 10, 30670, 31040, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos 12x18", 10, 45860, 31040, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, 1, wacom_graphire_irq }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, { "Wacom PL400", 8, 5408, 4056, 255, 32, 3, wacom_pl_irq }, { "Wacom PL500", 8, 6144, 4608, 255, 32, 3, wacom_pl_irq }, { "Wacom PL600", 8, 6126, 4604, 255, 32, 3, wacom_pl_irq }, { "Wacom PL600SX", 8, 6260, 5016, 255, 32, 3, wacom_pl_irq }, { "Wacom PL550", 8, 6144, 4608, 511, 32, 3, wacom_pl_irq }, { "Wacom PL800", 8, 7220, 5780, 511, 32, 3, wacom_pl_irq }, - { "Wacom Intuos2 4x5", 10, 12700, 10360, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 6x8", 10, 20600, 16450, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 9x12", 10, 30670, 24130, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 12x12", 10, 30670, 31040, 1023, 15, 2, wacom_intuos_irq }, - { "Wacom Intuos2 12x18", 10, 45860, 31040, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, + { "Wacom Volito", 8, 5104, 3712, 511, 32, 1, wacom_graphire_irq }, + { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, 3, wacom_ptu_irq }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, { } }; @@ -454,6 +560,7 @@ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) }, @@ -470,6 +577,9 @@ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } }; @@ -538,8 +648,9 @@ break; case 2: - wacom->dev.evbit[0] |= BIT(EV_MSC); + wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); wacom->dev.mscbit[0] |= BIT(MSC_SERIAL); + wacom->dev.relbit[0] |= BIT(REL_WHEEL); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2); diff -Nru a/include/asm-arm/arch-ebsa285/irqs.h b/include/asm-arm/arch-ebsa285/irqs.h --- a/include/asm-arm/arch-ebsa285/irqs.h Sun Mar 14 14:11:43 2004 +++ b/include/asm-arm/arch-ebsa285/irqs.h Sun Mar 14 14:11:43 2004 @@ -91,8 +91,8 @@ #undef RTC_IRQ #define RTC_IRQ IRQ_ISA_RTC_ALARM -#undef AUX_IRQ -#define AUX_IRQ (machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE) +#define I8042_KBD_IRQ IRQ_ISA_KEYBOARD +#define I8042_AUX_IRQ (machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE) #define IRQ_FLOPPYDISK IRQ_ISA_FLOPPY #define irq_canonicalize(_i) (((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA_2 : _i) diff -Nru a/include/asm-arm/arch-shark/irqs.h b/include/asm-arm/arch-shark/irqs.h --- a/include/asm-arm/arch-shark/irqs.h Sun Mar 14 14:11:43 2004 +++ b/include/asm-arm/arch-shark/irqs.h Sun Mar 14 14:11:43 2004 @@ -8,5 +8,6 @@ #define IRQ_ISA_KEYBOARD 1 #define RTC_IRQ 8 -#define AUX_IRQ 12 +#define I8042_KBD_IRQ 1 +#define I8042_AUX_IRQ 12 #define IRQ_HARDDISK 14 diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h --- a/include/linux/hiddev.h Sun Mar 14 14:11:43 2004 +++ b/include/linux/hiddev.h Sun Mar 14 14:11:43 2004 @@ -39,33 +39,33 @@ }; struct hiddev_devinfo { - unsigned int bustype; - unsigned int busnum; - unsigned int devnum; - unsigned int ifnum; - short vendor; - short product; - short version; - unsigned num_applications; + __u32 bustype; + __u32 busnum; + __u32 devnum; + __u32 ifnum; + __s16 vendor; + __s16 product; + __s16 version; + __u32 num_applications; }; struct hiddev_collection_info { - unsigned index; - unsigned type; - unsigned usage; - unsigned level; + __u32 index; + __u32 type; + __u32 usage; + __u32 level; }; #define HID_STRING_SIZE 256 struct hiddev_string_descriptor { - int index; + __s32 index; char value[HID_STRING_SIZE]; }; struct hiddev_report_info { - unsigned report_type; - unsigned report_id; - unsigned num_fields; + __u32 report_type; + __u32 report_id; + __u32 num_fields; }; /* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and @@ -88,20 +88,20 @@ #define HID_REPORT_TYPE_MAX 3 struct hiddev_field_info { - unsigned report_type; - unsigned report_id; - unsigned field_index; - unsigned maxusage; - unsigned flags; - unsigned physical; /* physical usage for this field */ - unsigned logical; /* logical usage for this field */ - unsigned application; /* application usage for this field */ + __u32 report_type; + __u32 report_id; + __u32 field_index; + __u32 maxusage; + __u32 flags; + __u32 physical; /* physical usage for this field */ + __u32 logical; /* logical usage for this field */ + __u32 application; /* application usage for this field */ __s32 logical_minimum; __s32 logical_maximum; __s32 physical_minimum; __s32 physical_maximum; - unsigned unit_exponent; - unsigned unit; + __u32 unit_exponent; + __u32 unit; }; /* Fill in report_type, report_id and field_index to get the information on a @@ -118,14 +118,22 @@ #define HID_FIELD_BUFFERED_BYTE 0x100 struct hiddev_usage_ref { - unsigned report_type; - unsigned report_id; - unsigned field_index; - unsigned usage_index; - unsigned usage_code; + __u32 report_type; + __u32 report_id; + __u32 field_index; + __u32 usage_index; + __u32 usage_code; __s32 value; }; +/* hiddev_usage_ref_multi is used for sending multiple bytes to a control. + * It really manifests itself as setting the value of consecutive usages */ +struct hiddev_usage_ref_multi { + struct hiddev_usage_ref uref; + __u32 num_values; + __s32 values[HID_MAX_USAGES]; +}; + /* FIELD_INDEX_NONE is returned in read() data from the kernel when flags * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has * been sent by the device @@ -160,6 +168,10 @@ #define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref) #define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info) #define HIDIOCGPHYS(len) _IOC(_IOC_READ, 'H', 0x12, len) + +/* For writing/reading to multiple/consecutive usages */ +#define HIDIOCGUSAGES _IOWR('H', 0x13, struct hiddev_usage_ref_multi) +#define HIDIOCSUSAGES _IOW('H', 0x14, struct hiddev_usage_ref_multi) /* * Flags to be used in HIDIOCSFLAG diff -Nru a/include/linux/init.h b/include/linux/init.h --- a/include/linux/init.h Sun Mar 14 14:11:43 2004 +++ b/include/linux/init.h Sun Mar 14 14:11:43 2004 @@ -110,12 +110,21 @@ }; /* OBSOLETE: see moduleparam.h for the right way. */ -#define __setup(str, fn) \ - static char __setup_str_##fn[] __initdata = str; \ - static struct obs_kernel_param __setup_##fn \ +#define __setup_param(str, unique_id, fn) \ + static char __setup_str_##unique_id[] __initdata = str; \ + static struct obs_kernel_param __setup_##unique_id \ __attribute_used__ \ __attribute__((__section__(".init.setup"))) \ - = { __setup_str_##fn, fn } + = { __setup_str_##unique_id, fn } + +#define __setup_null_param(str, unique_id) \ + __setup_param(str, unique_id, NULL) + +#define __setup(str, fn) \ + __setup_param(str, fn, fn) + +#define __obsolete_setup(str) \ + __setup_null_param(str, __LINE__) #endif /* __ASSEMBLY__ */ @@ -172,7 +181,10 @@ { return exitfn; } \ void cleanup_module(void) __attribute__((alias(#exitfn))); -#define __setup(str,func) /* nothing */ +#define __setup_param(str, unique_id, fn) /* nothing */ +#define __setup_null_param(str, unique_id) /* nothing */ +#define __setup(str, func) /* nothing */ +#define __obsolete_setup(str) /* nothing */ #endif /* Data marked not to be saved by software_suspend() */ diff -Nru a/include/linux/miscdevice.h b/include/linux/miscdevice.h --- a/include/linux/miscdevice.h Sun Mar 14 14:11:43 2004 +++ b/include/linux/miscdevice.h Sun Mar 14 14:11:43 2004 @@ -3,7 +3,6 @@ #include #include -#define BUSMOUSE_MINOR 0 #define PSMOUSE_MINOR 1 #define MS_BUSMOUSE_MINOR 2 #define ATIXL_BUSMOUSE_MINOR 3 diff -Nru a/include/linux/moduleparam.h b/include/linux/moduleparam.h --- a/include/linux/moduleparam.h Sun Mar 14 14:11:43 2004 +++ b/include/linux/moduleparam.h Sun Mar 14 14:11:43 2004 @@ -126,12 +126,15 @@ #define param_check_invbool(name, p) __param_check(name, p, int) /* Comma-separated array: num is set to number they actually specified. */ -#define module_param_array(name, type, num, perm) \ +#define module_param_array_named(name, array, type, num, perm) \ static struct kparam_array __param_arr_##name \ - = { ARRAY_SIZE(name), &num, param_set_##type, param_get_##type, \ - sizeof(name[0]), name }; \ + = { ARRAY_SIZE(array), &num, param_set_##type, param_get_##type,\ + sizeof(array[0]), array }; \ module_param_call(name, param_array_set, param_array_get, \ &__param_arr_##name, perm) + +#define module_param_array(name, type, num, perm) \ + module_param_array_named(name, name, type, num, perm) extern int param_array_set(const char *val, struct kernel_param *kp); extern int param_array_get(char *buffer, struct kernel_param *kp); diff -Nru a/include/linux/serio.h b/include/linux/serio.h --- a/include/linux/serio.h Sun Mar 14 14:11:43 2004 +++ b/include/linux/serio.h Sun Mar 14 14:11:43 2004 @@ -117,6 +117,7 @@ #define SERIO_MZ 0x05 #define SERIO_MZP 0x06 #define SERIO_MZPP 0x07 +#define SERIO_VSXXXAA 0x08 #define SERIO_SUNKBD 0x10 #define SERIO_WARRIOR 0x18 #define SERIO_SPACEORB 0x19 @@ -134,6 +135,7 @@ #define SERIO_HIL 0x25 #define SERIO_SNES232 0x26 #define SERIO_SEMTECH 0x27 +#define SERIO_LKKBD 0x28 #define SERIO_ID 0xff00UL #define SERIO_EXTRA 0xff0000UL diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Sun Mar 14 14:11:43 2004 +++ b/init/main.c Sun Mar 14 14:11:43 2004 @@ -156,8 +156,11 @@ p = &__setup_start; do { int n = strlen(p->str); - if (!strncmp(line,p->str,n)) { - if (p->setup_func(line+n)) + if (!strncmp(line, p->str, n)) { + if (!p->setup_func) { + printk(KERN_WARNING "Parameter %s is obsolete, ignored\n", p->str); + return 1; + } else if (p->setup_func(line + n)) return 1; } p++;