Commit 206a887f authored by Vojtech Pavlik's avatar Vojtech Pavlik

Merge suse.cz:/home/vojtech/bk/linus into suse.cz:/home/vojtech/bk/input

parents 0672b0ba 948fe30b
...@@ -174,11 +174,18 @@ running once the system is up. ...@@ -174,11 +174,18 @@ running once the system is up.
atascsi= [HW,SCSI] Atari SCSI atascsi= [HW,SCSI] Atari SCSI
atkbd.set= [HW] Select keyboard code set atkbd.extra= [HW] Enable extra LEDs and keys on IBM RapidAccess, EzKey
Format: <int> and similar keyboards
atkbd.reset= [HW] Reset keyboard during initialization
atkbd.set= [HW] Select keyboard code set
Format: <int> (2 = AT (default) 3 = PS/2)
atkbd.scroll= [HW] Enable scroll wheel on MS Office and similar keyboards
atkbd.softrepeat= atkbd.softrepeat=
[HW] Use software keyboard repeat [HW] Use software keyboard repeat
atkbd.reset= [HW] Reset keyboard during initialization
autotest [IA64] autotest [IA64]
......
...@@ -28,7 +28,7 @@ in the package: See the file COPYING. ...@@ -28,7 +28,7 @@ in the package: See the file COPYING.
1. Usage 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 adapters that conform to the Universal Serial Bus Communication Device Class
Abstract Control Model (USB CDC ACM) specification. Abstract Control Model (USB CDC ACM) specification.
...@@ -65,9 +65,9 @@ minor/major numbers anywhere you want, but either the above location or ...@@ -65,9 +65,9 @@ minor/major numbers anywhere you want, but either the above location or
To use the modems you need these modules loaded: To use the modems you need these modules loaded:
usbcore.o usbcore.ko
usb-[uo]hci.o or uhci.o uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko
acm.o cdc-acm.ko
After that, the modem[s] should be accessible. You should be able to use After that, the modem[s] should be accessible. You should be able to use
minicom, ppp and mgetty with them. minicom, ppp and mgetty with them.
......
...@@ -198,11 +198,6 @@ source "drivers/input/Kconfig" ...@@ -198,11 +198,6 @@ source "drivers/input/Kconfig"
source "drivers/char/Kconfig" source "drivers/char/Kconfig"
config KBDMOUSE
bool
depends on ARCH_ACORN && BUSMOUSE=y
default y
source "drivers/media/Kconfig" source "drivers/media/Kconfig"
source "fs/Kconfig" source "fs/Kconfig"
......
...@@ -599,30 +599,6 @@ config PC9800_OLDLP_CONSOLE ...@@ -599,30 +599,6 @@ config PC9800_OLDLP_CONSOLE
bool "Support for console on line printer" bool "Support for console on line printer"
depends on PC9800_OLDLP 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 config QIC02_TAPE
tristate "QIC-02 tape support" tristate "QIC-02 tape support"
help help
......
...@@ -49,7 +49,6 @@ obj-$(CONFIG_PRINTER) += lp.o ...@@ -49,7 +49,6 @@ obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_TIPAR) += tipar.o obj-$(CONFIG_TIPAR) += tipar.o
obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o
obj-$(CONFIG_BUSMOUSE) += busmouse.o
obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_APPLICOM) += applicom.o
......
...@@ -209,7 +209,7 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -209,7 +209,7 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct evdev *evdev = list->evdev; struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev; struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs; struct input_absinfo abs;
int t, u, v; int i, t, u, v;
if (!evdev->exist) return -ENODEV; if (!evdev->exist) return -ENODEV;
...@@ -234,6 +234,9 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -234,6 +234,9 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
u = SET_INPUT_KEYCODE(dev, t, v); u = SET_INPUT_KEYCODE(dev, t, v);
clear_bit(u, dev->keybit); clear_bit(u, dev->keybit);
set_bit(v, dev->keybit); set_bit(v, dev->keybit);
for (i = 0; i < dev->keycodemax; i++)
if (INPUT_KEYCODE(dev,i) == u)
set_bit(u, dev->keybit);
return 0; return 0;
case EVIOCSFF: case EVIOCSFF:
......
...@@ -77,7 +77,7 @@ static void ns558_isa_probe(int io) ...@@ -77,7 +77,7 @@ static void ns558_isa_probe(int io)
* No one should be using this address. * No one should be using this address.
*/ */
if (check_region(io, 1)) if (!request_region(io, 1, "ns558-isa"))
return; return;
/* /*
...@@ -89,7 +89,8 @@ static void ns558_isa_probe(int io) ...@@ -89,7 +89,8 @@ static void ns558_isa_probe(int io)
outb(~c & ~3, io); outb(~c & ~3, io);
if (~(u = v = inb(io)) & 3) { if (~(u = v = inb(io)) & 3) {
outb(c, io); outb(c, io);
return; i = 0;
goto out;
} }
/* /*
* After a trigger, there must be at least some bits changing. * After a trigger, there must be at least some bits changing.
...@@ -99,7 +100,8 @@ static void ns558_isa_probe(int io) ...@@ -99,7 +100,8 @@ static void ns558_isa_probe(int io)
if (u == v) { if (u == v) {
outb(c, io); outb(c, io);
return; i = 0;
goto out;
} }
wait_ms(3); wait_ms(3);
/* /*
...@@ -110,7 +112,8 @@ static void ns558_isa_probe(int io) ...@@ -110,7 +112,8 @@ static void ns558_isa_probe(int io)
for (i = 0; i < 1000; i++) for (i = 0; i < 1000; i++)
if ((u ^ inb(io)) & 0xf) { if ((u ^ inb(io)) & 0xf) {
outb(c, io); outb(c, io);
return; i = 0;
goto out;
} }
/* /*
* And now find the number of mirrors of the port. * And now find the number of mirrors of the port.
...@@ -118,7 +121,9 @@ static void ns558_isa_probe(int io) ...@@ -118,7 +121,9 @@ static void ns558_isa_probe(int io)
for (i = 1; i < 5; i++) { 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; break;
outb(0xff, io & (-1 << i)); outb(0xff, io & (-1 << i));
...@@ -126,18 +131,25 @@ static void ns558_isa_probe(int io) ...@@ -126,18 +131,25 @@ static void ns558_isa_probe(int io)
if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++; if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
wait_ms(3); 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; break;
}
} }
i--; i--;
if (i != 4) {
if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
return;
}
if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) { if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
printk(KERN_ERR "ns558: Memory allocation failed.\n"); 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->type = NS558_ISA;
port->size = (1 << i); port->size = (1 << i);
port->gameport.io = io; port->gameport.io = io;
...@@ -148,8 +160,6 @@ static void ns558_isa_probe(int io) ...@@ -148,8 +160,6 @@ static void ns558_isa_probe(int io)
sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i)); sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
sprintf(port->name, "NS558 ISA"); sprintf(port->name, "NS558 ISA");
request_region(io & (-1 << i), (1 << i), "ns558-isa");
gameport_register_port(&port->gameport); gameport_register_port(&port->gameport);
printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io); printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
...@@ -157,6 +167,9 @@ static void ns558_isa_probe(int io) ...@@ -157,6 +167,9 @@ static void ns558_isa_probe(int io)
printk(" speed %d kHz\n", port->gameport.speed); printk(" speed %d kHz\n", port->gameport.speed);
list_add(&port->node, &ns558_list); list_add(&port->node, &ns558_list);
return;
out:
release_region(io & (-1 << i), (1 << i));
} }
#ifdef CONFIG_PNP #ifdef CONFIG_PNP
......
...@@ -17,6 +17,7 @@ config KEYBOARD_ATKBD ...@@ -17,6 +17,7 @@ config KEYBOARD_ATKBD
depends on INPUT && INPUT_KEYBOARD depends on INPUT && INPUT_KEYBOARD
select SERIO select SERIO
select SERIO_I8042 if PC select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC
help help
Say Y here if you want to use a standard AT or PS/2 keyboard. Usually 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 you'll need this, unless you have a different type keyboard (USB, ADB
......
...@@ -37,14 +37,13 @@ MODULE_LICENSE("GPL"); ...@@ -37,14 +37,13 @@ MODULE_LICENSE("GPL");
static int atkbd_set = 2; static int atkbd_set = 2;
module_param_named(set, atkbd_set, int, 0); 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__) #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
static int atkbd_reset; static int atkbd_reset;
#else #else
static int atkbd_reset = 1; static int atkbd_reset = 1;
#endif #endif
static int atkbd_softrepeat;
module_param_named(reset, atkbd_reset, bool, 0); module_param_named(reset, atkbd_reset, bool, 0);
MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
...@@ -52,6 +51,14 @@ static int atkbd_softrepeat; ...@@ -52,6 +51,14 @@ static int atkbd_softrepeat;
module_param_named(softrepeat, atkbd_softrepeat, bool, 0); module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); 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");
/* /*
* Scancode to keycode tables. These are just the default setting, and * Scancode to keycode tables. These are just the default setting, and
* are loadable via an userland utility. * are loadable via an userland utility.
...@@ -127,11 +134,11 @@ static unsigned char atkbd_unxlate_table[128] = { ...@@ -127,11 +134,11 @@ static unsigned char atkbd_unxlate_table[128] = {
#define ATKBD_CMD_EX_SETLEDS 0x20eb #define ATKBD_CMD_EX_SETLEDS 0x20eb
#define ATKBD_CMD_OK_GETID 0x02e8 #define ATKBD_CMD_OK_GETID 0x02e8
#define ATKBD_RET_ACK 0xfa #define ATKBD_RET_ACK 0xfa
#define ATKBD_RET_NAK 0xfe #define ATKBD_RET_NAK 0xfe
#define ATKBD_RET_BAT 0xaa #define ATKBD_RET_BAT 0xaa
#define ATKBD_RET_EMUL0 0xe0 #define ATKBD_RET_EMUL0 0xe0
#define ATKBD_RET_EMULX 0x80
#define ATKBD_RET_EMUL1 0xe1 #define ATKBD_RET_EMUL1 0xe1
#define ATKBD_RET_RELEASE 0xf0 #define ATKBD_RET_RELEASE 0xf0
#define ATKBD_RET_HANGUEL 0xf1 #define ATKBD_RET_HANGUEL 0xf1
...@@ -141,6 +148,22 @@ static unsigned char atkbd_unxlate_table[128] = { ...@@ -141,6 +148,22 @@ static unsigned char atkbd_unxlate_table[128] = {
#define ATKBD_KEY_UNKNOWN 0 #define ATKBD_KEY_UNKNOWN 0
#define ATKBD_KEY_NULL 255 #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 * The atkbd control structure
*/ */
...@@ -155,6 +178,7 @@ struct atkbd { ...@@ -155,6 +178,7 @@ struct atkbd {
unsigned char cmdbuf[4]; unsigned char cmdbuf[4];
unsigned char cmdcnt; unsigned char cmdcnt;
unsigned char set; unsigned char set;
unsigned char extra;
unsigned char release; unsigned char release;
int lastkey; int lastkey;
volatile signed char ack; volatile signed char ack;
...@@ -189,6 +213,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -189,6 +213,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
{ {
struct atkbd *atkbd = serio->private; struct atkbd *atkbd = serio->private;
unsigned int code = data; unsigned int code = data;
int scroll = 0, click = -1;
int value; int value;
#ifdef ATKBD_DEBUG #ifdef ATKBD_DEBUG
...@@ -284,6 +309,21 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -284,6 +309,21 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
else else
printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f); printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f);
break; 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: default:
value = atkbd->release ? 0 : value = atkbd->release ? 0 :
(1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); (1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
...@@ -305,6 +345,13 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -305,6 +345,13 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value); 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; atkbd->release = 0;
out: out:
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -420,7 +467,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co ...@@ -420,7 +467,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
| (test_bit(LED_CAPSL, dev->led) ? 4 : 0); | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS);
if (atkbd->set == 4) { if (atkbd->extra) {
param[0] = 0; param[0] = 0;
param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
| (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
...@@ -529,21 +576,22 @@ static int atkbd_set_3(struct atkbd *atkbd) ...@@ -529,21 +576,22 @@ static int atkbd_set_3(struct atkbd *atkbd)
return 3; return 3;
} }
if (atkbd_set != 2) if (atkbd_extra) {
if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) { param[0] = 0x71;
atkbd->id = param[0] << 8 | param[1]; if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) {
atkbd->extra = 1;
return 2; 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; return 2;
if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
atkbd->id = param[0] << 8 | param[1];
return 2;
}
param[0] = 3; param[0] = 3;
if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET)) if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
return 2; return 2;
...@@ -696,24 +744,32 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -696,24 +744,32 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->id = 0xab00; 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); 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 } else
sprintf(atkbd->name, "AT %s Set %d keyboard", sprintf(atkbd->name, "AT %s Set %d keyboard",
atkbd->translated ? "Translated" : "Raw", atkbd->set); atkbd->translated ? "Translated" : "Raw", atkbd->set);
sprintf(atkbd->phys, "%s/input0", serio->phys); 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) { if (atkbd->translated) {
for (i = 0; i < 128; i++) { for (i = 0; i < 128; i++) {
atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
} }
} else if (atkbd->set == 2) { } else if (atkbd->set == 3) {
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
} else {
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
} else {
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
} }
atkbd->dev.name = atkbd->name; atkbd->dev.name = atkbd->name;
...@@ -724,7 +780,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -724,7 +780,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.id.version = atkbd->id; atkbd->dev.id.version = atkbd->id;
for (i = 0; i < 512; i++) 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); set_bit(atkbd->keycode[i], atkbd->dev.keybit);
input_register_device(&atkbd->dev); input_register_device(&atkbd->dev);
...@@ -741,46 +797,20 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -741,46 +797,20 @@ static int atkbd_reconnect(struct serio *serio)
{ {
struct atkbd *atkbd = serio->private; struct atkbd *atkbd = serio->private;
struct serio_dev *dev = serio->dev; struct serio_dev *dev = serio->dev;
int i;
if (!dev) { if (!dev) {
printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
return -1; return -1;
} }
if (atkbd->write) { if (atkbd->write) {
if (atkbd_probe(atkbd)) if (atkbd_probe(atkbd))
return -1; return -1;
if (atkbd->set != atkbd_set_3(atkbd))
atkbd->set = atkbd_set_3(atkbd); return -1;
atkbd_enable(atkbd); 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));
} }
for (i = 0; i < 512; i++)
if (atkbd->keycode[i] && atkbd->keycode[i] < 255)
set_bit(atkbd->keycode[i], atkbd->dev.keybit);
return 0; return 0;
} }
......
...@@ -4,14 +4,9 @@ ...@@ -4,14 +4,9 @@
* Copyright (c) 2004 Helge Deller <deller@gmx.de> * Copyright (c) 2004 Helge Deller <deller@gmx.de>
* Copyright (c) 2002 Laurent Canet <canetl@esiee.fr> * Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
* Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr> * Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
* Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
* *
* based on linux-2.4's hp_mouse.c & hp_keyb.c * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops
* Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
* Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
* Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
*
* HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations
* *
* This file is subject to the terms and conditions of the GNU General Public * 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 * License. See the file "COPYING" in the main directory of this archive
...@@ -19,87 +14,100 @@ ...@@ -19,87 +14,100 @@
*/ */
#define KBD_UNKNOWN 0 /* undefine if you have a RDI PRECISIONBOOK */
#define STANDARD_KEYBOARD
/* Raw SET 2 scancode table */
#if 0 #if defined(STANDARD_KEYBOARD)
/* conflicting keys between a RDI Precisionbook keyboard and a normal HP keyboard */ # define CONFLICT(x,y) x
keytable[0x07] = KEY_F1; /* KEY_F12 */ #else
keytable[0x11] = KEY_LEFTCTRL; /* KEY_LEFTALT */ # define CONFLICT(x,y) y
keytable[0x14] = KEY_CAPSLOCK; /* KEY_LEFTCTRL */
keytable[0x61] = KEY_LEFT; /* KEY_102ND */
#endif #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 )
/* Raw SET 2 scancode table */
static unsigned char atkbd_set2_keycode[512] = { /* 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,
/* 00 */ KBD_UNKNOWN, KEY_F9, KBD_UNKNOWN, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F1, /* These are offset for escaped keycodes: */
/* 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 */ 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
/* 00 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_F7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, #undef STANDARD_KEYBOARD
/* 08 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_LEFTMETA, KEY_RIGHTMETA, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, #undef CONFLICT
/* 10 */ KBD_UNKNOWN, KEY_RIGHTALT, KBD_UNKNOWN, KBD_UNKNOWN, KEY_RIGHTCTRL, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, #undef C_07
/* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, #undef C_11
/* 20 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, #undef C_14
/* 28 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, #undef C_58
/* 30 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, #undef C_61
/* 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
};
...@@ -77,6 +77,7 @@ struct sunkbd { ...@@ -77,6 +77,7 @@ struct sunkbd {
struct input_dev dev; struct input_dev dev;
struct serio *serio; struct serio *serio;
struct work_struct tq; struct work_struct tq;
wait_queue_head_t wait;
char name[64]; char name[64];
char phys[32]; char phys[32];
char type; char type;
...@@ -96,11 +97,13 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, ...@@ -96,11 +97,13 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio,
if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ 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 */ sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */
wake_up_interruptible(&sunkbd->wait);
goto out; goto out;
} }
if (sunkbd->layout == -1) { if (sunkbd->layout == -1) {
sunkbd->layout = data; sunkbd->layout = data;
wake_up_interruptible(&sunkbd->wait);
goto out; goto out;
} }
...@@ -176,22 +179,19 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c ...@@ -176,22 +179,19 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c
static int sunkbd_initialize(struct sunkbd *sunkbd) static int sunkbd_initialize(struct sunkbd *sunkbd)
{ {
int t;
t = 1000;
sunkbd->reset = -2; sunkbd->reset = -2;
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
while (sunkbd->reset < 0 && --t) mdelay(1); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
if (!t) return -1; if (sunkbd->reset <0)
return -1;
sunkbd->type = sunkbd->reset; sunkbd->type = sunkbd->reset;
if (sunkbd->type == 4) { /* Type 4 keyboard */ if (sunkbd->type == 4) { /* Type 4 keyboard */
t = 250;
sunkbd->layout = -2; sunkbd->layout = -2;
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
while (sunkbd->layout < 0 && --t) mdelay(1); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4);
if (!t) return -1; if (sunkbd->layout < 0) return -1;
if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
} }
...@@ -206,9 +206,8 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) ...@@ -206,9 +206,8 @@ static int sunkbd_initialize(struct sunkbd *sunkbd)
static void sunkbd_reinit(void *data) static void sunkbd_reinit(void *data)
{ {
struct sunkbd *sunkbd = 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, SUNKBD_CMD_SETLED);
sunkbd->serio->write(sunkbd->serio, sunkbd->serio->write(sunkbd->serio,
...@@ -239,6 +238,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -239,6 +238,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev)
memset(sunkbd, 0, sizeof(struct sunkbd)); memset(sunkbd, 0, sizeof(struct sunkbd));
init_input_dev(&sunkbd->dev); 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.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); sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
...@@ -275,7 +275,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -275,7 +275,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev)
set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
clear_bit(0, 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.name = sunkbd->name;
sunkbd->dev.phys = sunkbd->phys; sunkbd->dev.phys = sunkbd->phys;
......
...@@ -54,12 +54,3 @@ config INPUT_UINPUT ...@@ -54,12 +54,3 @@ config INPUT_UINPUT
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called uinput. 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.
...@@ -9,4 +9,3 @@ obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o ...@@ -9,4 +9,3 @@ obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_98SPKR) += 98spkr.o obj-$(CONFIG_INPUT_98SPKR) += 98spkr.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_GSC) += gsc_ps2.o
/*
* drivers/input/misc/gsc_ps2.c
*
* Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
* Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
*
* Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
* Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
* Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
* Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
*
* 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 <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ptrace.h> /* interrupt.h wants struct pt_regs defined */
#include <linux/interrupt.h>
#include <linux/sched.h> /* for request_irq/free_irq */
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/kd.h>
#include <linux/pci_ids.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/parisc-device.h>
/* 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 <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>");
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);
...@@ -17,6 +17,7 @@ config MOUSE_PS2 ...@@ -17,6 +17,7 @@ config MOUSE_PS2
depends on INPUT && INPUT_MOUSE depends on INPUT && INPUT_MOUSE
select SERIO select SERIO
select SERIO_I8042 if PC select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC
---help--- ---help---
Say Y here if you have a PS/2 mouse connected to your system. This 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 includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
......
...@@ -20,6 +20,7 @@ config SERIO_I8042 ...@@ -20,6 +20,7 @@ config SERIO_I8042
tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
default y default y
select SERIO select SERIO
depends on !PARISC
---help--- ---help---
i8042 is the chip over which the standard AT keyboard and PS/2 i8042 is the chip over which the standard AT keyboard and PS/2
mouse are connected to the computer. If you use these devices, mouse are connected to the computer. If you use these devices,
...@@ -48,6 +49,7 @@ config SERIO_SERPORT ...@@ -48,6 +49,7 @@ config SERIO_SERPORT
config SERIO_CT82C710 config SERIO_CT82C710
tristate "ct82c710 Aux port controller" tristate "ct82c710 Aux port controller"
depends on SERIO depends on SERIO
depends on !PARISC
---help--- ---help---
Say Y here if you have a Texas Instruments TravelMate notebook Say Y here if you have a Texas Instruments TravelMate notebook
equipped with the ct82c710 chip and want to use a mouse connected equipped with the ct82c710 chip and want to use a mouse connected
...@@ -105,6 +107,20 @@ config SERIO_98KBD ...@@ -105,6 +107,20 @@ config SERIO_98KBD
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called 98kbd-io. 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 config SERIO_PCIPS2
tristate "PCI PS/2 keyboard and PS/2 mouse controller" tristate "PCI PS/2 keyboard and PS/2 mouse controller"
depends on PCI && SERIO depends on PCI && SERIO
......
...@@ -14,4 +14,5 @@ obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o ...@@ -14,4 +14,5 @@ obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o
obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o
obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
/*
* drivers/input/serio/gscps2.c
*
* Copyright (c) 2004 Helge Deller <deller@gmx.de>
* Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
* Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
*
* Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
* Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
* Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
* Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
*
* 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 <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/pci_ids.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/parisc-device.h>
MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>, Helge Deller <deller@gmx.de>");
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);
...@@ -379,6 +379,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -379,6 +379,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned int dfl; unsigned int dfl;
int ret; int ret;
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
spin_lock_irqsave(&i8042_lock, flags); spin_lock_irqsave(&i8042_lock, flags);
str = i8042_read_status(); str = i8042_read_status();
if (str & I8042_STR_OBF) if (str & I8042_STR_OBF)
...@@ -433,7 +435,6 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -433,7 +435,6 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irq_ret: irq_ret:
ret = 1; ret = 1;
out: out:
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
return IRQ_RETVAL(ret); return IRQ_RETVAL(ret);
} }
......
...@@ -224,6 +224,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -224,6 +224,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
offset = report->size; offset = report->size;
report->size += parser->global.report_size * parser->global.report_count; report->size += parser->global.report_size * parser->global.report_count;
if (usages < parser->global.report_count)
usages = parser->global.report_count;
if (usages == 0) if (usages == 0)
return 0; /* ignore padding fields */ return 0; /* ignore padding fields */
...@@ -235,9 +238,13 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign ...@@ -235,9 +238,13 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
for (i = 0; i < usages; i++) { 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 = field->usage[i].collection_index =
parser->local.collection_index[i]; parser->local.collection_index[j];
} }
field->maxusage = usages; field->maxusage = usages;
...@@ -1317,7 +1324,6 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1317,7 +1324,6 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_KBGEAR 0x084e #define USB_VENDOR_ID_KBGEAR 0x084e
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
#define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_VENDOR_ID_AIPTEK 0x08ca
#define USB_DEVICE_ID_AIPTEK_6000 0x0020 #define USB_DEVICE_ID_AIPTEK_6000 0x0020
...@@ -1356,17 +1362,40 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1356,17 +1362,40 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_A4TECH 0x09DA #define USB_VENDOR_ID_A4TECH 0x09DA
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 #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_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
#define USB_VENDOR_ID_ALPS 0x0433 #define USB_VENDOR_ID_ALPS 0x0433
#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
struct hid_blacklist { struct hid_blacklist {
__u16 idVendor; __u16 idVendor;
__u16 idProduct; __u16 idProduct;
unsigned quirks; unsigned quirks;
} hid_blacklist[] = { } 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_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, 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 + 1, HID_QUIRK_IGNORE },
...@@ -1388,32 +1417,24 @@ struct hid_blacklist { ...@@ -1388,32 +1417,24 @@ struct hid_blacklist {
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, 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 + 3, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, 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_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { 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_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, 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_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, 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_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_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_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK },
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_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_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
{ 0, 0 } { 0, 0 }
}; };
......
...@@ -432,20 +432,21 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct ...@@ -432,20 +432,21 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
input_regs(input, regs); input_regs(input, regs);
if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK) if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK)
&& (usage->code == BTN_BACK)) { && (usage->code == BTN_BACK || usage->code == BTN_EXTRA)) {
if (value) if (value)
hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
else else
hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
return; return;
} }
if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON)
&& (usage->code == REL_WHEEL)) { && (usage->code == REL_WHEEL)) {
input_event(input, usage->type, REL_HWHEEL, value); input_event(input, usage->type, REL_HWHEEL, value);
return; 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; value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
if (value < 0 || value > 8) value = 0; if (value < 0 || value > 8) value = 0;
input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x); input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x);
...@@ -484,7 +485,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct ...@@ -484,7 +485,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return; 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; return;
input_event(input, usage->type, usage->code, value); input_event(input, usage->type, usage->code, value);
......
...@@ -403,7 +403,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -403,7 +403,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_collection_info cinfo; struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo; struct hiddev_report_info rinfo;
struct hiddev_field_info finfo; 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 hiddev_devinfo dinfo;
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
...@@ -575,68 +576,98 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -575,68 +576,98 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0; return 0;
case HIDIOCGUCODE: case HIDIOCGUCODE:
if (copy_from_user(&uref, (void *) arg, sizeof(uref))) if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
return -EFAULT; return -EFAULT;
rinfo.report_type = uref.report_type; rinfo.report_type = uref->report_type;
rinfo.report_id = uref.report_id; rinfo.report_id = uref->report_id;
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL; return -EINVAL;
if (uref.field_index >= report->maxfield) if (uref->field_index >= report->maxfield)
return -EINVAL; return -EINVAL;
field = report->field[uref.field_index]; field = report->field[uref->field_index];
if (uref.usage_index >= field->maxusage) if (uref->usage_index >= field->maxusage)
return -EINVAL; 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 -EFAULT;
return 0; return 0;
case HIDIOCGUSAGE: case HIDIOCGUSAGE:
case HIDIOCSUSAGE: case HIDIOCSUSAGE:
case HIDIOCGUSAGES:
case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX: case HIDIOCGCOLLECTIONINDEX:
if (copy_from_user(&uref, (void *) arg, sizeof(uref))) if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
return -EFAULT; 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) if (cmd != HIDIOCGUSAGE &&
return -EINVAL; cmd != HIDIOCGUSAGES &&
uref->report_type == HID_REPORT_TYPE_INPUT)
return -EINVAL;
if (uref.report_id == HID_REPORT_ID_UNKNOWN) { if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
field = hiddev_lookup_usage(hid, &uref); field = hiddev_lookup_usage(hid, uref);
if (field == NULL) if (field == NULL)
return -EINVAL; return -EINVAL;
} else { } else {
rinfo.report_type = uref.report_type; rinfo.report_type = uref->report_type;
rinfo.report_id = uref.report_id; rinfo.report_id = uref->report_id;
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL; return -EINVAL;
if (uref.field_index >= report->maxfield) if (uref->field_index >= report->maxfield)
return -EINVAL; return -EINVAL;
field = report->field[uref.field_index]; field = report->field[uref->field_index];
if (uref.usage_index >= field->maxusage) if (uref->usage_index >= field->maxusage)
return -EINVAL; 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) { switch (cmd) {
case HIDIOCGUSAGE: case HIDIOCGUSAGE:
uref.value = field->value[uref.usage_index]; uref->value = field->value[uref->usage_index];
if (copy_to_user((void *) arg, &uref, sizeof(uref))) if (copy_to_user((void *) arg, uref, sizeof(*uref)))
return -EFAULT; return -EFAULT;
return 0; return 0;
case HIDIOCSUSAGE: case HIDIOCSUSAGE:
field->value[uref.usage_index] = uref.value; field->value[uref->usage_index] = uref->value;
return 0; return 0;
case HIDIOCGCOLLECTIONINDEX: 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; return 0;
......
/* /*
* USB Wacom Graphire and Wacom Intuos tablet support * USB Wacom Graphire and Wacom Intuos tablet support
* *
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz>
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk> * Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
* Copyright (c) 2000 Clifford Wolf <clifford@clifford.at> * Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
* Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org> * Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* Copyright (c) 2000 Daniel Egger <egger@suse.de> * Copyright (c) 2000 Daniel Egger <egger@suse.de>
* Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com> * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
* Copyright (c) 2002 Ping Cheng <pingc@wacom.com> * Copyright (c) 2002 Ping Cheng <pingc@wacom.com>
* Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
* *
* ChangeLog: * ChangeLog:
* v0.1 (vp) - Initial release * v0.1 (vp) - Initial release
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
* v1.30 (vp) - Merge 2.4 and 2.5 drivers * v1.30 (vp) - Merge 2.4 and 2.5 drivers
* - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
* - Cleanups here and there * - Cleanups here and there
* v1.30.1 (pi) - Added Graphire3 support
*/ */
/* /*
......
...@@ -39,33 +39,33 @@ struct hiddev_event { ...@@ -39,33 +39,33 @@ struct hiddev_event {
}; };
struct hiddev_devinfo { struct hiddev_devinfo {
unsigned int bustype; __u32 bustype;
unsigned int busnum; __u32 busnum;
unsigned int devnum; __u32 devnum;
unsigned int ifnum; __u32 ifnum;
short vendor; __s16 vendor;
short product; __s16 product;
short version; __s16 version;
unsigned num_applications; __u32 num_applications;
}; };
struct hiddev_collection_info { struct hiddev_collection_info {
unsigned index; __u32 index;
unsigned type; __u32 type;
unsigned usage; __u32 usage;
unsigned level; __u32 level;
}; };
#define HID_STRING_SIZE 256 #define HID_STRING_SIZE 256
struct hiddev_string_descriptor { struct hiddev_string_descriptor {
int index; __s32 index;
char value[HID_STRING_SIZE]; char value[HID_STRING_SIZE];
}; };
struct hiddev_report_info { struct hiddev_report_info {
unsigned report_type; __u32 report_type;
unsigned report_id; __u32 report_id;
unsigned num_fields; __u32 num_fields;
}; };
/* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and /* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and
...@@ -88,20 +88,20 @@ struct hiddev_report_info { ...@@ -88,20 +88,20 @@ struct hiddev_report_info {
#define HID_REPORT_TYPE_MAX 3 #define HID_REPORT_TYPE_MAX 3
struct hiddev_field_info { struct hiddev_field_info {
unsigned report_type; __u32 report_type;
unsigned report_id; __u32 report_id;
unsigned field_index; __u32 field_index;
unsigned maxusage; __u32 maxusage;
unsigned flags; __u32 flags;
unsigned physical; /* physical usage for this field */ __u32 physical; /* physical usage for this field */
unsigned logical; /* logical usage for this field */ __u32 logical; /* logical usage for this field */
unsigned application; /* application usage for this field */ __u32 application; /* application usage for this field */
__s32 logical_minimum; __s32 logical_minimum;
__s32 logical_maximum; __s32 logical_maximum;
__s32 physical_minimum; __s32 physical_minimum;
__s32 physical_maximum; __s32 physical_maximum;
unsigned unit_exponent; __u32 unit_exponent;
unsigned unit; __u32 unit;
}; };
/* Fill in report_type, report_id and field_index to get the information on a /* Fill in report_type, report_id and field_index to get the information on a
...@@ -118,14 +118,22 @@ struct hiddev_field_info { ...@@ -118,14 +118,22 @@ struct hiddev_field_info {
#define HID_FIELD_BUFFERED_BYTE 0x100 #define HID_FIELD_BUFFERED_BYTE 0x100
struct hiddev_usage_ref { struct hiddev_usage_ref {
unsigned report_type; __u32 report_type;
unsigned report_id; __u32 report_id;
unsigned field_index; __u32 field_index;
unsigned usage_index; __u32 usage_index;
unsigned usage_code; __u32 usage_code;
__s32 value; __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 /* 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 * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has
* been sent by the device * been sent by the device
...@@ -161,6 +169,10 @@ struct hiddev_usage_ref { ...@@ -161,6 +169,10 @@ struct hiddev_usage_ref {
#define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info) #define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info)
#define HIDIOCGPHYS(len) _IOC(_IOC_READ, 'H', 0x12, len) #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 * Flags to be used in HIDIOCSFLAG
*/ */
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/major.h> #include <linux/major.h>
#define BUSMOUSE_MINOR 0
#define PSMOUSE_MINOR 1 #define PSMOUSE_MINOR 1
#define MS_BUSMOUSE_MINOR 2 #define MS_BUSMOUSE_MINOR 2
#define ATIXL_BUSMOUSE_MINOR 3 #define ATIXL_BUSMOUSE_MINOR 3
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment