Commit 4125f64c authored by Vojtech Pavlik's avatar Vojtech Pavlik

Merge suse.cz:/data/bk/linus into suse.cz:/data/bk/input

parents e3a2c92a c256c1a3
...@@ -335,6 +335,7 @@ controller (compatible with DirectPadPro): ...@@ -335,6 +335,7 @@ controller (compatible with DirectPadPro):
* Analog PSX Pad (red mode) * Analog PSX Pad (red mode)
* Analog PSX Pad (green mode) * Analog PSX Pad (green mode)
* PSX Rumble Pad * PSX Rumble Pad
* PSX DDR Pad
2.4 Sega 2.4 Sega
~~~~~~~~ ~~~~~~~~
...@@ -452,14 +453,22 @@ uses the following kernel/module command line: ...@@ -452,14 +453,22 @@ uses the following kernel/module command line:
5 | Multisystem 2-button joystick 5 | Multisystem 2-button joystick
6 | N64 pad 6 | N64 pad
7 | Sony PSX controller 7 | Sony PSX controller
8 | Sony PSX DDR controller
The exact type of the PSX controller type is autoprobed, so you must have The exact type of the PSX controller type is autoprobed when used so
your controller plugged in before initializing. hot swapping should work (but is not recomended).
Should you want to use more than one of parallel ports at once, you can use Should you want to use more than one of parallel ports at once, you can use
gamecon.map2 and gamecon.map3 as additional command line parameters for two gamecon.map2 and gamecon.map3 as additional command line parameters for two
more parallel ports. more parallel ports.
There are two options specific to PSX driver portion. gamecon.psx_delay sets
the command delay when talking to the controllers. The default of 25 should
work but you can try lowering it for better performace. If your pads don't
respond try raising it untill they work. Setting the type to 8 allows the
driver to be used with Dance Dance Revolution or similar games. Arrow keys are
registered as key presses instead of X and Y axes.
3.2 db9.c 3.2 db9.c
~~~~~~~~~ ~~~~~~~~~
Apart from making an interface, there is nothing difficult on using the Apart from making an interface, there is nothing difficult on using the
......
...@@ -652,6 +652,12 @@ running once the system is up. ...@@ -652,6 +652,12 @@ running once the system is up.
mga= [HW,DRM] mga= [HW,DRM]
mousedev.tap_time=
[MOUSE] Maximum time between finger touching and
leaving touchpad surface for touch to be considered
a tap and be reported as a left button click (for
touchpads working in absolute mode only).
Format: <msecs>
mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices
reporting absolute coordinates, such as tablets reporting absolute coordinates, such as tablets
mousedev.yres= [MOUSE] Vertical screen resolution, used for devices mousedev.yres= [MOUSE] Vertical screen resolution, used for devices
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
unsigned long dmi_broken; unsigned long dmi_broken;
EXPORT_SYMBOL(dmi_broken); EXPORT_SYMBOL(dmi_broken);
unsigned int i8042_dmi_noloop = 0;
EXPORT_SYMBOL(i8042_dmi_noloop);
int is_sony_vaio_laptop; int is_sony_vaio_laptop;
int is_unsafe_smbus; int is_unsafe_smbus;
int es7000_plat = 0; int es7000_plat = 0;
...@@ -370,6 +373,17 @@ static __init int sony_vaio_laptop(struct dmi_blacklist *d) ...@@ -370,6 +373,17 @@ static __init int sony_vaio_laptop(struct dmi_blacklist *d)
return 0; return 0;
} }
/*
* Several HP Proliant (and maybe other OSB4/ProFusion) systems
* shouldn't use the AUX LoopBack command, or they crash or reboot.
*/
static __init int set_8042_noloop(struct dmi_blacklist *d)
{
i8042_dmi_noloop = 1;
return 0;
}
/* /*
* This bios swaps the APM minute reporting bytes over (Many sony laptops * This bios swaps the APM minute reporting bytes over (Many sony laptops
* have this problem). * have this problem).
...@@ -851,6 +865,23 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={ ...@@ -851,6 +865,23 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
NO_MATCH, NO_MATCH, NO_MATCH, NO_MATCH,
} }, } },
/*
* Several HP Proliant (and maybe other OSB4/ProFusion) systems
* can't use i8042 in mux mode, or they crash or reboot.
*/
{ set_8042_noloop, "Compaq Proliant 8500", {
MATCH(DMI_SYS_VENDOR, "Compaq"),
MATCH(DMI_PRODUCT_NAME , "ProLiant"),
MATCH(DMI_PRODUCT_VERSION, "8500"),
NO_MATCH }},
{ set_8042_noloop, "Compaq Proliant DL760", {
MATCH(DMI_SYS_VENDOR, "Compaq"),
MATCH(DMI_PRODUCT_NAME , "ProLiant"),
MATCH(DMI_PRODUCT_VERSION, "DL760"),
NO_MATCH }},
#ifdef CONFIG_ACPI_BOOT #ifdef CONFIG_ACPI_BOOT
/* /*
* If your system is blacklisted here, but you find that acpi=force * If your system is blacklisted here, but you find that acpi=force
......
...@@ -123,7 +123,7 @@ int shift_state = 0; ...@@ -123,7 +123,7 @@ int shift_state = 0;
*/ */
static struct input_handler kbd_handler; static struct input_handler kbd_handler;
static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
static int dead_key_next; static int dead_key_next;
static int npadch = -1; /* -1 or number assembled on pad */ static int npadch = -1; /* -1 or number assembled on pad */
...@@ -142,7 +142,7 @@ static struct ledptr { ...@@ -142,7 +142,7 @@ static struct ledptr {
/* Simple translation table for the SysRq keys */ /* Simple translation table for the SysRq keys */
#ifdef CONFIG_MAGIC_SYSRQ #ifdef CONFIG_MAGIC_SYSRQ
unsigned char kbd_sysrq_xlate[128] = unsigned char kbd_sysrq_xlate[KEY_MAX] =
"\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
"qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
"dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
...@@ -941,6 +941,9 @@ void kbd_refresh_leds(struct input_handle *handle) ...@@ -941,6 +941,9 @@ void kbd_refresh_leds(struct input_handle *handle)
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211) #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211)
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
static unsigned short x86_keycodes[256] = static unsigned short x86_keycodes[256] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
...@@ -1007,6 +1010,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, ...@@ -1007,6 +1010,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
#else #else
#define HW_RAW(dev) 0
#warning "Cannot generate rawmode keyboard for your architecture yet." #warning "Cannot generate rawmode keyboard for your architecture yet."
static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
...@@ -1019,7 +1024,15 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u ...@@ -1019,7 +1024,15 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u
} }
#endif #endif
void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) void kbd_rawcode(unsigned char data)
{
struct vc_data *vc = vc_cons[fg_console].d;
kbd = kbd_table + fg_console;
if (kbd->kbdmode == VC_RAW)
put_queue(vc, data);
}
void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs)
{ {
struct vc_data *vc = vc_cons[fg_console].d; struct vc_data *vc = vc_cons[fg_console].d;
unsigned short keysym, *key_map; unsigned short keysym, *key_map;
...@@ -1053,7 +1066,7 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) ...@@ -1053,7 +1066,7 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
return; return;
#endif /* CONFIG_MAC_EMUMOUSEBTN */ #endif /* CONFIG_MAC_EMUMOUSEBTN */
if ((raw_mode = (kbd->kbdmode == VC_RAW))) if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
if (emulate_raw(vc, keycode, !down << 7)) if (emulate_raw(vc, keycode, !down << 7))
if (keycode < BTN_MISC) if (keycode < BTN_MISC)
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
...@@ -1119,6 +1132,9 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) ...@@ -1119,6 +1132,9 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
return; return;
} }
if (keycode > NR_KEYS)
return;
keysym = key_map[keycode]; keysym = key_map[keycode];
type = KTYP(keysym); type = KTYP(keysym);
...@@ -1148,11 +1164,12 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) ...@@ -1148,11 +1164,12 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
} }
static void kbd_event(struct input_handle *handle, unsigned int event_type, static void kbd_event(struct input_handle *handle, unsigned int event_type,
unsigned int keycode, int down) unsigned int event_code, int value)
{ {
if (event_type != EV_KEY) if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
return; kbd_rawcode(value);
kbd_keycode(keycode, down, handle->dev->regs); if (event_type == EV_KEY)
kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs);
tasklet_schedule(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet);
do_poke_blanked_console = 1; do_poke_blanked_console = 1;
schedule_console_callback(); schedule_console_callback();
......
...@@ -50,8 +50,11 @@ struct emu { ...@@ -50,8 +50,11 @@ struct emu {
}; };
static struct pci_device_id emu_tbl[] = { static struct pci_device_id emu_tbl[] = {
{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
{ 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */
{ 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */
{ 0, } { 0, }
}; };
......
/* /*
* $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $ * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
* *
* Copyright (c) 1999-2001 Vojtech Pavlik * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
* *
* Based on the work of: * Based on the work of:
* Andree Borrmann John Dahlstrom * Andree Borrmann John Dahlstrom
* David Kuder Nathan Hand * David Kuder Nathan Hand
*/ */
/*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*/
/* /*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -72,8 +69,9 @@ __obsolete_setup("gc_3="); ...@@ -72,8 +69,9 @@ __obsolete_setup("gc_3=");
#define GC_MULTI2 5 #define GC_MULTI2 5
#define GC_N64 6 #define GC_N64 6
#define GC_PSX 7 #define GC_PSX 7
#define GC_DDR 8
#define GC_MAX 7 #define GC_MAX 8
#define GC_REFRESH_TIME HZ/100 #define GC_REFRESH_TIME HZ/100
...@@ -91,7 +89,8 @@ static struct gc *gc_base[3]; ...@@ -91,7 +89,8 @@ static struct gc *gc_base[3];
static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
"Multisystem 2-button joystick", "N64 controller", "PSX controller" }; "Multisystem 2-button joystick", "N64 controller", "PSX controller"
"PSX DDR controller" };
/* /*
* N64 support. * N64 support.
*/ */
...@@ -237,7 +236,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) ...@@ -237,7 +236,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
#define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ #define GC_PSX_RUMBLE 7 /* Rumble in Red mode */
#define GC_PSX_CLOCK 0x04 /* Pin 4 */ #define GC_PSX_CLOCK 0x04 /* Pin 4 */
#define GC_PSX_COMMAND 0x01 /* Pin 1 */ #define GC_PSX_COMMAND 0x01 /* Pin 2 */
#define GC_PSX_POWER 0xf8 /* Pins 5-9 */ #define GC_PSX_POWER 0xf8 /* Pins 5-9 */
#define GC_PSX_SELECT 0x02 /* Pin 3 */ #define GC_PSX_SELECT 0x02 /* Pin 3 */
...@@ -253,25 +252,29 @@ __obsolete_setup("gc_psx_delay="); ...@@ -253,25 +252,29 @@ __obsolete_setup("gc_psx_delay=");
static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
/* /*
* gc_psx_command() writes 8bit command and reads 8bit data from * gc_psx_command() writes 8bit command and reads 8bit data from
* the psx pad. * the psx pad.
*/ */
static int gc_psx_command(struct gc *gc, int b) static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH])
{ {
int i, cmd, data = 0; int i, j, cmd, read;
for (i = 0; i < 5; i++)
data[i] = 0;
for (i = 0; i < 8; i++, b >>= 1) { for (i = 0; i < 8; i++, b >>= 1) {
cmd = (b & 1) ? GC_PSX_COMMAND : 0; cmd = (b & 1) ? GC_PSX_COMMAND : 0;
parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
udelay(gc_psx_delay); udelay(gc_psx_delay);
data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; read = parport_read_status(gc->pd->port) ^ 0x80;
for (j = 0; j < 5; j++)
data[j] |= (read & gc_status_bit[j] & gc->pads[GC_PSX]) ? (1 << i) : 0;
parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
udelay(gc_psx_delay); udelay(gc_psx_delay);
} }
return data;
} }
/* /*
...@@ -279,30 +282,39 @@ static int gc_psx_command(struct gc *gc, int b) ...@@ -279,30 +282,39 @@ static int gc_psx_command(struct gc *gc, int b)
* device identifier code. * device identifier code.
*/ */
static int gc_psx_read_packet(struct gc *gc, unsigned char *data) static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5])
{ {
int i, id; int i, j, max_len = 0;
unsigned long flags; unsigned long flags;
unsigned char data2[5];
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
udelay(gc_psx_delay * 2); udelay(gc_psx_delay);
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */
udelay(gc_psx_delay * 2); udelay(gc_psx_delay);
local_irq_save(flags); local_irq_save(flags);
gc_psx_command(gc, 0x01); /* Access pad */ gc_psx_command(gc, 0x01, data2); /* Access pad */
id = gc_psx_command(gc, 0x42); /* Get device id */ gc_psx_command(gc, 0x42, id); /* Get device ids */
if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */ gc_psx_command(gc, 0, data2); /* Dump status */
for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
data[i] = gc_psx_command(gc, 0); for (i =0; i < 5; i++) /* Find the longest pad */
} else id = 0; if((gc_status_bit[i] & gc->pads[GC_PSX]) && (GC_PSX_LEN(id[i]) > max_len))
max_len = GC_PSX_LEN(id[i]);
for (i = 0; i < max_len * 2; i++) { /* Read in all the data */
gc_psx_command(gc, 0, data2);
for (j = 0; j < 5; j++)
data[j][i] = data2[j];
}
local_irq_restore(flags); local_irq_restore(flags);
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
return GC_PSX_ID(id); for(i = 0; i < 5; i++) /* Set id's to the real value */
id[i] = GC_PSX_ID(id[i]);
} }
/* /*
...@@ -316,6 +328,7 @@ static void gc_timer(unsigned long private) ...@@ -316,6 +328,7 @@ static void gc_timer(unsigned long private)
struct gc *gc = (void *) private; struct gc *gc = (void *) private;
struct input_dev *dev = gc->dev; struct input_dev *dev = gc->dev;
unsigned char data[GC_MAX_LENGTH]; unsigned char data[GC_MAX_LENGTH];
unsigned char data_psx[5][GC_PSX_LENGTH];
int i, j, s; int i, j, s;
/* /*
...@@ -412,53 +425,72 @@ static void gc_timer(unsigned long private) ...@@ -412,53 +425,72 @@ static void gc_timer(unsigned long private)
* PSX controllers * PSX controllers
*/ */
if (gc->pads[GC_PSX]) { if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) {
for (i = 0; i < 5; i++) gc_psx_read_packet(gc, data_psx, data);
if (gc->pads[GC_PSX] & gc_status_bit[i])
break;
switch (gc_psx_read_packet(gc, data)) { for (i = 0; i < 5; i++) {
switch (data[i]) {
case GC_PSX_RUMBLE: case GC_PSX_RUMBLE:
input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04); input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04);
input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02); input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02);
input_sync(dev + i);
case GC_PSX_NEGCON: case GC_PSX_NEGCON:
case GC_PSX_ANALOG: case GC_PSX_ANALOG:
if(gc->pads[GC_DDR] & gc_status_bit[i]) {
for(j = 0; j < 4; j++)
input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j));
} else {
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]);
input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80)); input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128);
input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10)); input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128);
}
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j));
input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08);
input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01);
input_sync(dev + i); input_sync(dev + i);
break; break;
case GC_PSX_NORMAL: case GC_PSX_NORMAL:
if(gc->pads[GC_DDR] & gc_status_bit[i]) {
input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); for(j = 0; j < 4; j++)
input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j));
} else {
input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128);
input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128);
/* for some reason if the extra axes are left unset they drift */
/* for (j = 0; j < 4; j++)
input_report_abs(dev + i, gc_psx_abs[j+2], 128);
* This needs to be debugged properly,
* maybe fuzz processing needs to be done in input_sync()
* --vojtech
*/
}
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j));
input_report_key(dev + i, BTN_START, ~data[0] & 0x08); input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08);
input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01);
input_sync(dev + i); input_sync(dev + i);
break; break;
case 0: /* not a pad, ignore */
break;
}
} }
} }
...@@ -490,8 +522,7 @@ static struct gc __init *gc_probe(int *config, int nargs) ...@@ -490,8 +522,7 @@ static struct gc __init *gc_probe(int *config, int nargs)
{ {
struct gc *gc; struct gc *gc;
struct parport *pp; struct parport *pp;
int i, j, psx; int i, j;
unsigned char data[32];
if (config[0] < 0) if (config[0] < 0)
return NULL; return NULL;
...@@ -588,25 +619,16 @@ static struct gc __init *gc_probe(int *config, int nargs) ...@@ -588,25 +619,16 @@ static struct gc __init *gc_probe(int *config, int nargs)
break; break;
case GC_PSX: case GC_PSX:
case GC_DDR:
psx = gc_psx_read_packet(gc, data); if(config[i + 1] == GC_DDR) {
for (j = 0; j < 4; j++)
switch(psx) { set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit);
case GC_PSX_NEGCON:
case GC_PSX_NORMAL:
case GC_PSX_ANALOG:
case GC_PSX_RUMBLE:
for (j = 0; j < 6; j++) {
psx = gc_psx_abs[j];
set_bit(psx, gc->dev[i].absbit);
if (j < 4) {
gc->dev[i].absmin[psx] = 4;
gc->dev[i].absmax[psx] = 252;
gc->dev[i].absflat[psx] = 2;
} else { } else {
gc->dev[i].absmin[psx] = -1; for (j = 0; j < 6; j++) {
gc->dev[i].absmax[psx] = 1; set_bit(gc_psx_abs[j], gc->dev[i].absbit);
gc->dev[i].absmin[gc_psx_abs[j]] = 4;
gc->dev[i].absmax[gc_psx_abs[j]] = 252;
gc->dev[i].absflat[gc_psx_abs[j]] = 2;
} }
} }
...@@ -614,18 +636,6 @@ static struct gc __init *gc_probe(int *config, int nargs) ...@@ -614,18 +636,6 @@ static struct gc __init *gc_probe(int *config, int nargs)
set_bit(gc_psx_btn[j], gc->dev[i].keybit); set_bit(gc_psx_btn[j], gc->dev[i].keybit);
break; break;
case 0:
gc->pads[GC_PSX] &= ~gc_status_bit[i];
printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
break;
default:
gc->pads[GC_PSX] &= ~gc_status_bit[i];
printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
" please report to <vojtech@ucw.cz>.\n", psx);
}
break;
} }
sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i);
......
...@@ -47,6 +47,10 @@ static int atkbd_softrepeat; ...@@ -47,6 +47,10 @@ 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_softraw = 1;
module_param_named(softraw, atkbd_softraw, bool, 0);
MODULE_PARM_DESC(softraw, "Use software generated rawmode");
static int atkbd_scroll; static int atkbd_scroll;
module_param_named(scroll, atkbd_scroll, bool, 0); module_param_named(scroll, atkbd_scroll, bool, 0);
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
...@@ -164,34 +168,48 @@ static unsigned char atkbd_scroll_keys[5][2] = { ...@@ -164,34 +168,48 @@ static unsigned char atkbd_scroll_keys[5][2] = {
{ ATKBD_SCR_CLICK, 0x60 }, { ATKBD_SCR_CLICK, 0x60 },
}; };
#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */
#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */
#define ATKBD_FLAG_CMD1 2 /* First byte of command response */
#define ATKBD_FLAG_ID 3 /* First byte is not keyboard ID */
#define ATKBD_FLAG_ENABLED 4 /* Waining for init to finish */
/* /*
* The atkbd control structure * The atkbd control structure
*/ */
struct atkbd { struct atkbd {
unsigned char keycode[512];
struct input_dev dev;
struct serio *serio;
/* Written only during init */
char name[64]; char name[64];
char phys[32]; char phys[32];
unsigned short id; struct serio *serio;
struct input_dev dev;
unsigned char set; unsigned char set;
unsigned int translated:1; unsigned short id;
unsigned int extra:1; unsigned char keycode[512];
unsigned int write:1; unsigned char translated;
unsigned char extra;
unsigned char write;
/* Protected by FLAG_ACK */
unsigned char nak;
/* Protected by FLAG_CMD */
unsigned char cmdbuf[4]; unsigned char cmdbuf[4];
unsigned char cmdcnt; unsigned char cmdcnt;
volatile signed char ack;
unsigned char emul;
unsigned int resend:1;
unsigned int release:1;
unsigned int bat_xl:1;
unsigned int enabled:1;
/* Accessed only from interrupt */
unsigned char emul;
unsigned char resend;
unsigned char release;
unsigned char bat_xl;
unsigned int last; unsigned int last;
unsigned long time; unsigned long time;
/* Flags */
unsigned long flags;
}; };
static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
...@@ -224,7 +242,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -224,7 +242,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
#if !defined(__i386__) && !defined (__x86_64__) #if !defined(__i386__) && !defined (__x86_64__)
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
printk("atkbd.c: frame/parity error: %02x\n", flags); printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
serio_write(serio, ATKBD_CMD_RESEND); serio_write(serio, ATKBD_CMD_RESEND);
atkbd->resend = 1; atkbd->resend = 1;
goto out; goto out;
...@@ -234,24 +252,45 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -234,24 +252,45 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->resend = 0; atkbd->resend = 0;
#endif #endif
if (!atkbd->ack) if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags))
switch (code) { switch (code) {
case ATKBD_RET_ACK: case ATKBD_RET_ACK:
atkbd->ack = 1; atkbd->nak = 0;
if (atkbd->cmdcnt) {
set_bit(ATKBD_FLAG_CMD, &atkbd->flags);
set_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
set_bit(ATKBD_FLAG_ID, &atkbd->flags);
}
clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
goto out; goto out;
case ATKBD_RET_NAK: case ATKBD_RET_NAK:
atkbd->ack = -1; atkbd->nak = 1;
clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
goto out; goto out;
} }
if (atkbd->cmdcnt) { if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) {
atkbd->cmdbuf[--atkbd->cmdcnt] = code;
atkbd->cmdcnt--;
atkbd->cmdbuf[atkbd->cmdcnt] = code;
if (atkbd->cmdcnt == 1) {
if (code != 0xab && code != 0xac)
clear_bit(ATKBD_FLAG_ID, &atkbd->flags);
clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
}
if (!atkbd->cmdcnt)
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
goto out; goto out;
} }
if (!atkbd->enabled) if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags))
goto out; goto out;
input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);
if (atkbd->translated) { if (atkbd->translated) {
if (atkbd->emul || if (atkbd->emul ||
...@@ -270,6 +309,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -270,6 +309,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
switch (code) { switch (code) {
case ATKBD_RET_BAT: case ATKBD_RET_BAT:
clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
serio_rescan(atkbd->serio); serio_rescan(atkbd->serio);
goto out; goto out;
case ATKBD_RET_EMUL0: case ATKBD_RET_EMUL0:
...@@ -300,6 +340,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -300,6 +340,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
code |= (atkbd->set != 3) ? 0x80 : 0x100; code |= (atkbd->set != 3) ? 0x80 : 0x100;
} }
if (atkbd->keycode[code] != ATKBD_KEY_NULL)
input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code);
switch (atkbd->keycode[code]) { switch (atkbd->keycode[code]) {
case ATKBD_KEY_NULL: case ATKBD_KEY_NULL:
break; break;
...@@ -376,18 +419,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -376,18 +419,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
{ {
int timeout = 20000; /* 200 msec */ int timeout = 200000; /* 200 msec */
atkbd->ack = 0;
#ifdef ATKBD_DEBUG #ifdef ATKBD_DEBUG
printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
#endif #endif
set_bit(ATKBD_FLAG_ACK, &atkbd->flags);
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
if (serio_write(atkbd->serio, byte)) if (serio_write(atkbd->serio, byte))
return -1; return -1;
while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) udelay(1);
clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
while (!atkbd->ack && timeout--) udelay(10); return -atkbd->nak;
return -(atkbd->ack <= 0);
} }
/* /*
...@@ -405,7 +450,7 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) ...@@ -405,7 +450,7 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
atkbd->cmdcnt = receive; atkbd->cmdcnt = receive;
if (command == ATKBD_CMD_RESET_BAT) if (command == ATKBD_CMD_RESET_BAT)
timeout = 2000000; /* 2 sec */ timeout = 4000000; /* 4 sec */
if (receive && param) if (receive && param)
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
...@@ -413,38 +458,40 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) ...@@ -413,38 +458,40 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
if (command & 0xff) if (command & 0xff)
if (atkbd_sendbyte(atkbd, command & 0xff)) if (atkbd_sendbyte(atkbd, command & 0xff))
return (atkbd->cmdcnt = 0) - 1; return -1;
for (i = 0; i < send; i++) for (i = 0; i < send; i++)
if (atkbd_sendbyte(atkbd, param[i])) if (atkbd_sendbyte(atkbd, param[i]))
return (atkbd->cmdcnt = 0) - 1; return -1;
while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) {
while (atkbd->cmdcnt && timeout--) { if (!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags)) {
if (atkbd->cmdcnt == 1 && if (command == ATKBD_CMD_RESET_BAT && timeout > 100000)
command == ATKBD_CMD_RESET_BAT && timeout > 100000)
timeout = 100000; timeout = 100000;
if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID && if (command == ATKBD_CMD_GETID && !test_bit(ATKBD_FLAG_ID, &atkbd->flags)) {
atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) { clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
atkbd->cmdcnt = 0; atkbd->cmdcnt = 0;
break; break;
} }
}
udelay(1); udelay(1);
} }
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
if (param) if (param)
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
param[i] = atkbd->cmdbuf[(receive - 1) - i]; param[i] = atkbd->cmdbuf[(receive - 1) - i];
if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1) if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1)
atkbd->cmdcnt = 0; return 0;
if (atkbd->cmdcnt) { if (atkbd->cmdcnt)
atkbd->cmdcnt = 0;
return -1; return -1;
}
return 0; return 0;
} }
...@@ -672,6 +719,7 @@ static void atkbd_cleanup(struct serio *serio) ...@@ -672,6 +719,7 @@ static void atkbd_cleanup(struct serio *serio)
static void atkbd_disconnect(struct serio *serio) static void atkbd_disconnect(struct serio *serio)
{ {
struct atkbd *atkbd = serio->private; struct atkbd *atkbd = serio->private;
clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
input_unregister_device(&atkbd->dev); input_unregister_device(&atkbd->dev);
serio_close(serio); serio_close(serio);
kfree(atkbd); kfree(atkbd);
...@@ -709,17 +757,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -709,17 +757,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
return; return;
} }
if (!atkbd->write)
atkbd_softrepeat = 1;
if (atkbd_softrepeat)
atkbd_softraw = 1;
if (atkbd->write) { if (atkbd->write) {
atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC);
atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
} else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
if (!atkbd_softrepeat) { if (!atkbd_softrepeat) {
atkbd->dev.rep[REP_DELAY] = 250; atkbd->dev.rep[REP_DELAY] = 250;
atkbd->dev.rep[REP_PERIOD] = 33; atkbd->dev.rep[REP_PERIOD] = 33;
} } else atkbd_softraw = 1;
atkbd->ack = 1;
atkbd->serio = serio; atkbd->serio = serio;
init_input_dev(&atkbd->dev); init_input_dev(&atkbd->dev);
...@@ -754,8 +807,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -754,8 +807,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->id = 0xab00; atkbd->id = 0xab00;
} }
atkbd->enabled = 1;
if (atkbd->extra) { 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 Extra keyboard"); sprintf(atkbd->name, "AT Set 2 Extra keyboard");
...@@ -797,6 +848,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -797,6 +848,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
input_register_device(&atkbd->dev); input_register_device(&atkbd->dev);
set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
} }
...@@ -832,6 +885,8 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -832,6 +885,8 @@ static int atkbd_reconnect(struct serio *serio)
return -1; return -1;
} }
set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
return 0; return 0;
} }
......
...@@ -279,6 +279,9 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) ...@@ -279,6 +279,9 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait)
{ {
struct uinput_device *udev = file->private_data; struct uinput_device *udev = file->private_data;
if (!test_bit(UIST_CREATED, &(udev->state)))
return 0;
poll_wait(file, &udev->waitq, wait); poll_wait(file, &udev->waitq, wait);
if (udev->head != udev->tail) if (udev->head != udev->tail)
......
...@@ -30,8 +30,6 @@ config MOUSE_PS2 ...@@ -30,8 +30,6 @@ config MOUSE_PS2
and a new verion of GPM at: and a new verion of GPM at:
http://www.geocities.com/dt_or/gpm/gpm.html http://www.geocities.com/dt_or/gpm/gpm.html
to take advantage of the advanced features of the touchpad. to take advantage of the advanced features of the touchpad.
If you do not want install specialized drivers but want tapping
working please use option psmouse.proto=imps.
If unsure, say Y. If unsure, say Y.
......
...@@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) ...@@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
protocol = PSMOUSE_PS2TPP; protocol = PSMOUSE_PS2TPP;
} }
} else if (get_model_info(model) != NULL) { } else if (model_info != NULL) {
param[0] = param[1] = param[2] = 0; param[0] = param[1] = param[2] = 0;
ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
......
...@@ -142,34 +142,45 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -142,34 +142,45 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "", flags & SERIO_TIMEOUT ? " timeout" : "",
flags & SERIO_PARITY ? " bad parity" : ""); flags & SERIO_PARITY ? " bad parity" : "");
if (psmouse->acking) { psmouse->nak = 1;
psmouse->ack = -1; clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
psmouse->acking = 0; clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
}
psmouse->pktcnt = 0;
goto out; goto out;
} }
if (psmouse->acking) { if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags))
switch (data) { switch (data) {
case PSMOUSE_RET_ACK: case PSMOUSE_RET_ACK:
psmouse->ack = 1; psmouse->nak = 0;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
goto out;
break; break;
case PSMOUSE_RET_NAK: case PSMOUSE_RET_NAK:
psmouse->ack = -1; psmouse->nak = 1;
break; clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
goto out;
default: default:
psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ psmouse->nak = 0; /* Workaround for mice which don't ACK the Get ID command */
if (psmouse->cmdcnt) clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
psmouse->cmdbuf[--psmouse->cmdcnt] = data; if (!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags))
break;
}
psmouse->acking = 0;
goto out; goto out;
} }
if (psmouse->cmdcnt) { if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
psmouse->cmdbuf[--psmouse->cmdcnt] = data;
psmouse->cmdcnt--;
psmouse->cmdbuf[psmouse->cmdcnt] = data;
if (psmouse->cmdcnt == 1) {
if (data != 0xab && data != 0xac)
clear_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
}
if (!psmouse->cmdcnt)
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
goto out; goto out;
} }
...@@ -242,18 +253,15 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -242,18 +253,15 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
{ {
int timeout = 10000; /* 100 msec */ int timeout = 200000; /* 200 msec */
psmouse->ack = 0;
psmouse->acking = 1;
if (serio_write(psmouse->serio, byte)) { set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
psmouse->acking = 0; if (serio_write(psmouse->serio, byte))
return -1; return -1;
} while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) udelay(1);
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
while (!psmouse->ack && timeout--) udelay(10); return -psmouse->nak;
return -(psmouse->ack <= 0);
} }
/* /*
...@@ -273,44 +281,60 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -273,44 +281,60 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
if (command == PSMOUSE_CMD_RESET_BAT) if (command == PSMOUSE_CMD_RESET_BAT)
timeout = 4000000; /* 4 sec */ timeout = 4000000; /* 4 sec */
/* initialize cmdbuf with preset values from param */ if (receive && param)
if (receive)
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
psmouse->cmdbuf[(receive - 1) - i] = param[i]; psmouse->cmdbuf[(receive - 1) - i] = param[i];
if (receive) {
set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
set_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
}
if (command & 0xff) if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff)) if (psmouse_sendbyte(psmouse, command & 0xff)) {
return (psmouse->cmdcnt = 0) - 1; clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
return -1;
}
for (i = 0; i < send; i++) for (i = 0; i < send; i++)
if (psmouse_sendbyte(psmouse, param[i])) if (psmouse_sendbyte(psmouse, param[i])) {
return (psmouse->cmdcnt = 0) - 1; clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
return -1;
}
while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) {
while (psmouse->cmdcnt && timeout--) { if (!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags)) {
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT && if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000)
timeout > 100000) /* do not run in a endless loop */ timeout = 100000;
timeout = 100000; /* 1 sec */
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID && if (command == PSMOUSE_CMD_GETID && !test_bit(PSMOUSE_FLAG_ID, &psmouse->flags)) {
psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) { clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
psmouse->cmdcnt = 0; psmouse->cmdcnt = 0;
break; break;
} }
}
udelay(1); udelay(1);
} }
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
if (param)
for (i = 0; i < receive; i++) for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i]; param[i] = psmouse->cmdbuf[(receive - 1) - i];
if (command == PSMOUSE_CMD_RESET_BAT && psmouse->cmdcnt == 1)
return 0;
if (psmouse->cmdcnt) if (psmouse->cmdcnt)
return (psmouse->cmdcnt = 0) - 1; return -1;
return 0; return 0;
} }
/* /*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse * psmouse_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech * using sliced syntax, understood by advanced devices, such as Logitech
...@@ -394,6 +418,8 @@ static int im_explorer_detect(struct psmouse *psmouse) ...@@ -394,6 +418,8 @@ static int im_explorer_detect(struct psmouse *psmouse)
{ {
unsigned char param[2]; unsigned char param[2];
intellimouse_detect(psmouse);
param[0] = 200; param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
param[0] = 200; param[0] = 200;
...@@ -735,7 +761,12 @@ static int psmouse_reconnect(struct serio *serio) ...@@ -735,7 +761,12 @@ static int psmouse_reconnect(struct serio *serio)
} }
psmouse->state = PSMOUSE_CMD_MODE; psmouse->state = PSMOUSE_CMD_MODE;
psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
psmouse->pktcnt = psmouse->out_of_sync = 0;
if (psmouse->reconnect) { if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse)) if (psmouse->reconnect(psmouse))
return -1; return -1;
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
#define PSMOUSE_ACTIVATED 1 #define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2 #define PSMOUSE_IGNORE 2
#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */
#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */
#define PSMOUSE_FLAG_CMD1 2 /* First byte of command response */
#define PSMOUSE_FLAG_ID 3 /* First byte is not keyboard ID */
/* psmouse protocol handler return codes */ /* psmouse protocol handler return codes */
typedef enum { typedef enum {
PSMOUSE_BAD_DATA, PSMOUSE_BAD_DATA,
...@@ -54,11 +59,11 @@ struct psmouse { ...@@ -54,11 +59,11 @@ struct psmouse {
unsigned long last; unsigned long last;
unsigned long out_of_sync; unsigned long out_of_sync;
unsigned char state; unsigned char state;
char acking; unsigned char nak;
volatile char ack;
char error; char error;
char devname[64]; char devname[64];
char phys[32]; char phys[32];
unsigned long flags;
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
int (*reconnect)(struct psmouse *psmouse); int (*reconnect)(struct psmouse *psmouse);
......
...@@ -48,8 +48,13 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; ...@@ -48,8 +48,13 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
module_param(yres, uint, 0); module_param(yres, uint, 0);
MODULE_PARM_DESC(yres, "Vertical screen resolution"); MODULE_PARM_DESC(yres, "Vertical screen resolution");
static unsigned tap_time = 200;
module_param(tap_time, uint, 0);
MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
struct mousedev_motion { struct mousedev_motion {
int dx, dy, dz; int dx, dy, dz;
unsigned long buttons;
}; };
struct mousedev { struct mousedev {
...@@ -62,21 +67,31 @@ struct mousedev { ...@@ -62,21 +67,31 @@ struct mousedev {
struct input_handle handle; struct input_handle handle;
struct mousedev_motion packet; struct mousedev_motion packet;
unsigned long buttons;
unsigned int pkt_count; unsigned int pkt_count;
int old_x[4], old_y[4]; int old_x[4], old_y[4];
unsigned int touch; unsigned long touch;
}; };
enum mousedev_emul {
MOUSEDEV_EMUL_PS2,
MOUSEDEV_EMUL_IMPS,
MOUSEDEV_EMUL_EXPS
} __attribute__ ((packed));
#define PACKET_QUEUE_LEN 16
struct mousedev_list { struct mousedev_list {
struct fasync_struct *fasync; struct fasync_struct *fasync;
struct mousedev *mousedev; struct mousedev *mousedev;
struct list_head node; struct list_head node;
int dx, dy, dz;
unsigned long buttons; struct mousedev_motion packets[PACKET_QUEUE_LEN];
unsigned int head, tail;
spinlock_t packet_lock;
signed char ps2[6]; signed char ps2[6];
unsigned char ready, buffer, bufsiz; unsigned char ready, buffer, bufsiz;
unsigned char mode, imexseq, impsseq; unsigned char imexseq, impsseq;
enum mousedev_emul mode;
}; };
#define MOUSEDEV_SEQ_LEN 6 #define MOUSEDEV_SEQ_LEN 6
...@@ -165,30 +180,70 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int ...@@ -165,30 +180,70 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
} }
if (value) { if (value) {
set_bit(index, &mousedev->buttons); set_bit(index, &mousedev->packet.buttons);
set_bit(index, &mousedev_mix.buttons); set_bit(index, &mousedev_mix.packet.buttons);
} else { } else {
clear_bit(index, &mousedev->buttons); clear_bit(index, &mousedev->packet.buttons);
clear_bit(index, &mousedev_mix.buttons); clear_bit(index, &mousedev_mix.packet.buttons);
} }
} }
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
{ {
struct mousedev_list *list; struct mousedev_list *list;
struct mousedev_motion *p;
unsigned long flags;
list_for_each_entry(list, &mousedev->list, node) { list_for_each_entry(list, &mousedev->list, node) {
list->dx += packet->dx; spin_lock_irqsave(&list->packet_lock, flags);
list->dy += packet->dy;
list->dz += packet->dz; p = &list->packets[list->head];
list->buttons = mousedev->buttons; if (list->ready && p->buttons != packet->buttons) {
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
if (new_head != list->tail) {
p = &list->packets[list->head = new_head];
memset(p, 0, sizeof(struct mousedev_motion));
}
}
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
list->ready = 1; list->ready = 1;
spin_unlock_irqrestore(&list->packet_lock, flags);
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
} }
wake_up_interruptible(&mousedev->wait); wake_up_interruptible(&mousedev->wait);
} }
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
if (!value) {
if (mousedev->touch &&
!time_after(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
/*
* Toggle left button to emulate tap.
* We rely on the fact that mousedev_mix always has 0
* motion packet so we won't mess current position.
*/
set_bit(0, &mousedev->packet.buttons);
set_bit(0, &mousedev_mix.packet.buttons);
mousedev_notify_readers(mousedev, &mousedev_mix.packet);
mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet);
clear_bit(0, &mousedev->packet.buttons);
clear_bit(0, &mousedev_mix.packet.buttons);
}
mousedev->touch = mousedev->pkt_count = 0;
}
else
if (!mousedev->touch)
mousedev->touch = jiffies;
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{ {
struct mousedev *mousedev = handle->private; struct mousedev *mousedev = handle->private;
...@@ -212,12 +267,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig ...@@ -212,12 +267,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
case EV_KEY: case EV_KEY:
if (value != 2) { if (value != 2) {
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
/* Handle touchpad data */ mousedev_touchpad_touch(mousedev, value);
mousedev->touch = value;
if (!mousedev->touch)
mousedev->pkt_count = 0;
}
else else
mousedev_key_event(mousedev, code, value); mousedev_key_event(mousedev, code, value);
} }
...@@ -237,7 +288,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig ...@@ -237,7 +288,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
mousedev_notify_readers(mousedev, &mousedev->packet); mousedev_notify_readers(mousedev, &mousedev->packet);
mousedev_notify_readers(&mousedev_mix, &mousedev->packet); mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
memset(&mousedev->packet, 0, sizeof(struct mousedev_motion)); mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
} }
break; break;
} }
...@@ -322,6 +373,7 @@ static int mousedev_open(struct inode * inode, struct file * file) ...@@ -322,6 +373,7 @@ static int mousedev_open(struct inode * inode, struct file * file)
return -ENOMEM; return -ENOMEM;
memset(list, 0, sizeof(struct mousedev_list)); memset(list, 0, sizeof(struct mousedev_list));
spin_lock_init(&list->packet_lock);
list->mousedev = mousedev_table[i]; list->mousedev = mousedev_table[i];
list_add_tail(&list->node, &mousedev_table[i]->list); list_add_tail(&list->node, &mousedev_table[i]->list);
file->private_data = list; file->private_data = list;
...@@ -341,32 +393,56 @@ static int mousedev_open(struct inode * inode, struct file * file) ...@@ -341,32 +393,56 @@ static int mousedev_open(struct inode * inode, struct file * file)
return 0; return 0;
} }
static void mousedev_packet(struct mousedev_list *list, unsigned char off) static inline int mousedev_limit_delta(int delta, int limit)
{ {
list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); return delta > limit ? limit : (delta < -limit ? -limit : delta);
list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); }
list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
list->dx -= list->ps2[off + 1]; static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
list->dy -= list->ps2[off + 2]; {
list->bufsiz = off + 3; struct mousedev_motion *p;
unsigned long flags;
if (list->mode == 2) {
list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz)); spin_lock_irqsave(&list->packet_lock, flags);
list->dz -= list->ps2[off + 3]; p = &list->packets[list->tail];
list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
list->bufsiz++; ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
} else { ps2_data[1] = mousedev_limit_delta(p->dx, 127);
list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1); ps2_data[2] = mousedev_limit_delta(p->dy, 127);
p->dx -= ps2_data[1];
p->dy -= ps2_data[2];
switch (list->mode) {
case MOUSEDEV_EMUL_EXPS:
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
p->dz -= ps2_data[3];
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
list->bufsiz = 4;
break;
case MOUSEDEV_EMUL_IMPS:
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
p->dz -= ps2_data[3];
list->bufsiz = 4;
break;
case MOUSEDEV_EMUL_PS2:
default:
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
p->dz = 0;
list->bufsiz = 3;
break;
} }
if (list->mode == 1) { if (!p->dx && !p->dy && !p->dz) {
list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); if (list->tail != list->head)
list->dz -= list->ps2[off + 3]; list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
list->bufsiz++; if (list->tail == list->head)
list->ready = 0;
} }
if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; spin_unlock_irqrestore(&list->packet_lock, flags);
list->buffer = list->bufsiz;
} }
...@@ -384,31 +460,31 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si ...@@ -384,31 +460,31 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
if (c == mousedev_imex_seq[list->imexseq]) { if (c == mousedev_imex_seq[list->imexseq]) {
if (++list->imexseq == MOUSEDEV_SEQ_LEN) { if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
list->imexseq = 0; list->imexseq = 0;
list->mode = 2; list->mode = MOUSEDEV_EMUL_EXPS;
} }
} else list->imexseq = 0; } else list->imexseq = 0;
if (c == mousedev_imps_seq[list->impsseq]) { if (c == mousedev_imps_seq[list->impsseq]) {
if (++list->impsseq == MOUSEDEV_SEQ_LEN) { if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
list->impsseq = 0; list->impsseq = 0;
list->mode = 1; list->mode = MOUSEDEV_EMUL_IMPS;
} }
} else list->impsseq = 0; } else list->impsseq = 0;
list->ps2[0] = 0xfa; list->ps2[0] = 0xfa;
list->bufsiz = 1;
switch (c) { switch (c) {
case 0xeb: /* Poll */ case 0xeb: /* Poll */
mousedev_packet(list, 1); mousedev_packet(list, &list->ps2[1]);
list->bufsiz++; /* account for leading ACK */
break; break;
case 0xf2: /* Get ID */ case 0xf2: /* Get ID */
switch (list->mode) { switch (list->mode) {
case 0: list->ps2[1] = 0; break; case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break;
case 1: list->ps2[1] = 3; break; case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
case 2: list->ps2[1] = 4; break; case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
} }
list->bufsiz = 2; list->bufsiz = 2;
break; break;
...@@ -419,13 +495,15 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si ...@@ -419,13 +495,15 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
break; break;
case 0xff: /* Reset */ case 0xff: /* Reset */
list->impsseq = 0; list->impsseq = list->imexseq = 0;
list->imexseq = 0; list->mode = MOUSEDEV_EMUL_PS2;
list->mode = 0; list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
list->ps2[1] = 0xaa;
list->ps2[2] = 0x00;
list->bufsiz = 3; list->bufsiz = 3;
break; break;
default:
list->bufsiz = 1;
break;
} }
list->buffer = list->bufsiz; list->buffer = list->bufsiz;
...@@ -451,8 +529,10 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co ...@@ -451,8 +529,10 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
if (retval) if (retval)
return retval; return retval;
if (!list->buffer && list->ready) if (!list->buffer && list->ready) {
mousedev_packet(list, 0); mousedev_packet(list, list->ps2);
list->buffer = list->bufsiz;
}
if (count > list->buffer) if (count > list->buffer)
count = list->buffer; count = list->buffer;
......
/* /*
* i8042 keyboard and mouse controller driver for Linux * i8042 keyboard and mouse controller driver for Linux
* *
* Copyright (c) 1999-2002 Vojtech Pavlik * Copyright (c) 1999-2004 Vojtech Pavlik
*/ */
/* /*
...@@ -52,6 +52,11 @@ static unsigned int i8042_dumbkbd; ...@@ -52,6 +52,11 @@ static unsigned int i8042_dumbkbd;
module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
#ifdef __i386__
extern unsigned int i8042_dmi_noloop;
#endif
static unsigned int i8042_noloop;
__obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_noaux");
__obsolete_setup("i8042_nomux"); __obsolete_setup("i8042_nomux");
__obsolete_setup("i8042_unlock"); __obsolete_setup("i8042_unlock");
...@@ -95,6 +100,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); ...@@ -95,6 +100,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/* /*
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
* be ready for reading values from it / writing values to it. * be ready for reading values from it / writing values to it.
* Called always with i8042_lock held.
*/ */
static int i8042_wait_read(void) static int i8042_wait_read(void)
...@@ -154,6 +160,9 @@ static int i8042_command(unsigned char *param, int command) ...@@ -154,6 +160,9 @@ static int i8042_command(unsigned char *param, int command)
unsigned long flags; unsigned long flags;
int retval = 0, i = 0; int retval = 0, i = 0;
if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
return -1;
spin_lock_irqsave(&i8042_lock, flags); spin_lock_irqsave(&i8042_lock, flags);
retval = i8042_wait_write(); retval = i8042_wait_write();
...@@ -474,17 +483,8 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux ...@@ -474,17 +483,8 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9) if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
return -1; return -1;
param = 0xa4; param = 0xa4;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b) { if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
/*
* Do another loop test with the 0x5a value. Doing anything else upsets
* Profusion/ServerWorks OSB4 chipsets.
*/
param = 0x5a;
i8042_command(&param, I8042_CMD_AUX_LOOP);
return -1; return -1;
}
if (mux_version) if (mux_version)
*mux_version = ~param; *mux_version = ~param;
...@@ -677,6 +677,7 @@ static void i8042_timer_func(unsigned long data) ...@@ -677,6 +677,7 @@ static void i8042_timer_func(unsigned long data)
static int i8042_controller_init(void) static int i8042_controller_init(void)
{ {
unsigned long flags;
/* /*
* Test the i8042. We need to know if it thinks it's working correctly * Test the i8042. We need to know if it thinks it's working correctly
...@@ -723,12 +724,14 @@ static int i8042_controller_init(void) ...@@ -723,12 +724,14 @@ static int i8042_controller_init(void)
* Handle keylock. * Handle keylock.
*/ */
spin_lock_irqsave(&i8042_lock, flags);
if (~i8042_read_status() & I8042_STR_KEYLOCK) { if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock) if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK; i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
} }
spin_unlock_irqrestore(&i8042_lock, flags);
/* /*
* If the chip is configured into nontranslated mode by the BIOS, don't * If the chip is configured into nontranslated mode by the BIOS, don't
...@@ -964,6 +967,13 @@ int __init i8042_init(void) ...@@ -964,6 +967,13 @@ int __init i8042_init(void)
if (i8042_dumbkbd) if (i8042_dumbkbd)
i8042_kbd_port.write = NULL; i8042_kbd_port.write = NULL;
#ifdef __i386__
if (i8042_dmi_noloop) {
printk(KERN_INFO "i8042.c: AUX LoopBack command disabled by DMI.\n");
i8042_noloop = 1;
}
#endif
if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) {
if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values))
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
......
/*
* $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/* /*
* The Serio abstraction module * The Serio abstraction module
*
* Copyright (c) 1999-2004 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
* Copyright (c) 2003 Daniele Bellucci
*/ */
/* /*
...@@ -26,10 +24,6 @@ ...@@ -26,10 +24,6 @@
* Should you need to contact me, the author, you can do so either by * Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*
* Changes:
* 20 Jul. 2003 Daniele Bellucci <bellucda@tiscali.it>
* Minor cleanups.
*/ */
#include <linux/stddef.h> #include <linux/stddef.h>
...@@ -61,17 +55,11 @@ EXPORT_SYMBOL(serio_close); ...@@ -61,17 +55,11 @@ EXPORT_SYMBOL(serio_close);
EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_rescan);
EXPORT_SYMBOL(serio_reconnect); EXPORT_SYMBOL(serio_reconnect);
struct serio_event { static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */
int type;
struct serio *serio;
struct list_head node;
};
static DECLARE_MUTEX(serio_sem);
static LIST_HEAD(serio_list); static LIST_HEAD(serio_list);
static LIST_HEAD(serio_dev_list); static LIST_HEAD(serio_dev_list);
static LIST_HEAD(serio_event_list);
static int serio_pid; /* serio_find_dev() must be called with serio_sem down. */
static void serio_find_dev(struct serio *serio) static void serio_find_dev(struct serio *serio)
{ {
...@@ -85,34 +73,76 @@ static void serio_find_dev(struct serio *serio) ...@@ -85,34 +73,76 @@ static void serio_find_dev(struct serio *serio)
} }
} }
#define SERIO_RESCAN 1 /*
#define SERIO_RECONNECT 2 * Serio event processing.
#define SERIO_REGISTER_PORT 3 */
#define SERIO_UNREGISTER_PORT 4
struct serio_event {
int type;
struct serio *serio;
struct list_head node;
};
enum serio_event_type {
SERIO_RESCAN,
SERIO_RECONNECT,
SERIO_REGISTER_PORT,
SERIO_UNREGISTER_PORT,
};
static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */
static LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait); static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited); static DECLARE_COMPLETION(serio_exited);
static int serio_pid;
static void serio_invalidate_pending_events(struct serio *serio) static void serio_queue_event(struct serio *serio, int event_type)
{ {
unsigned long flags;
struct serio_event *event; struct serio_event *event;
list_for_each_entry(event, &serio_event_list, node) spin_lock_irqsave(&serio_event_lock, flags);
if (event->serio == serio)
event->serio = NULL; if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
event->type = event_type;
event->serio = serio;
list_add_tail(&event->node, &serio_event_list);
wake_up(&serio_wait);
}
spin_unlock_irqrestore(&serio_event_lock, flags);
} }
void serio_handle_events(void) static struct serio_event *serio_get_event(void)
{ {
struct list_head *node, *next;
struct serio_event *event; struct serio_event *event;
struct list_head *node;
unsigned long flags;
list_for_each_safe(node, next, &serio_event_list) { spin_lock_irqsave(&serio_event_lock, flags);
if (list_empty(&serio_event_list)) {
spin_unlock_irqrestore(&serio_event_lock, flags);
return NULL;
}
node = serio_event_list.next;
event = container_of(node, struct serio_event, node); event = container_of(node, struct serio_event, node);
list_del_init(node);
spin_unlock_irqrestore(&serio_event_lock, flags);
return event;
}
static void serio_handle_events(void)
{
struct serio_event *event;
while ((event = serio_get_event())) {
down(&serio_sem); down(&serio_sem);
if (event->serio == NULL)
goto event_done;
switch (event->type) { switch (event->type) {
case SERIO_REGISTER_PORT : case SERIO_REGISTER_PORT :
...@@ -137,13 +167,32 @@ void serio_handle_events(void) ...@@ -137,13 +167,32 @@ void serio_handle_events(void)
default: default:
break; break;
} }
event_done:
up(&serio_sem); up(&serio_sem);
kfree(event);
}
}
static void serio_remove_pending_events(struct serio *serio)
{
struct list_head *node, *next;
struct serio_event *event;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
list_for_each_safe(node, next, &serio_event_list) {
event = container_of(node, struct serio_event, node);
if (event->serio == serio) {
list_del_init(node); list_del_init(node);
kfree(event); kfree(event);
} }
}
spin_unlock_irqrestore(&serio_event_lock, flags);
} }
static int serio_thread(void *nothing) static int serio_thread(void *nothing)
{ {
lock_kernel(); lock_kernel();
...@@ -163,18 +212,10 @@ static int serio_thread(void *nothing) ...@@ -163,18 +212,10 @@ static int serio_thread(void *nothing)
complete_and_exit(&serio_exited, 0); complete_and_exit(&serio_exited, 0);
} }
static void serio_queue_event(struct serio *serio, int event_type)
{
struct serio_event *event;
if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
event->type = event_type;
event->serio = serio;
list_add_tail(&event->node, &serio_event_list); /*
wake_up(&serio_wait); * Serio port operations
} */
}
void serio_rescan(struct serio *serio) void serio_rescan(struct serio *serio)
{ {
...@@ -186,25 +227,6 @@ void serio_reconnect(struct serio *serio) ...@@ -186,25 +227,6 @@ void serio_reconnect(struct serio *serio)
serio_queue_event(serio, SERIO_RECONNECT); serio_queue_event(serio, SERIO_RECONNECT);
} }
irqreturn_t serio_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs)
{
irqreturn_t ret = IRQ_NONE;
if (serio->dev && serio->dev->interrupt) {
ret = serio->dev->interrupt(serio, data, flags, regs);
} else {
if (!flags) {
if ((serio->type == SERIO_8042 ||
serio->type == SERIO_8042_XL) && (data != 0xaa))
return ret;
serio_rescan(serio);
ret = IRQ_HANDLED;
}
}
return ret;
}
void serio_register_port(struct serio *serio) void serio_register_port(struct serio *serio)
{ {
down(&serio_sem); down(&serio_sem);
...@@ -229,6 +251,7 @@ void serio_register_port_delayed(struct serio *serio) ...@@ -229,6 +251,7 @@ void serio_register_port_delayed(struct serio *serio)
*/ */
void __serio_register_port(struct serio *serio) void __serio_register_port(struct serio *serio)
{ {
spin_lock_init(&serio->lock);
list_add_tail(&serio->node, &serio_list); list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio); serio_find_dev(serio);
} }
...@@ -257,12 +280,16 @@ void serio_unregister_port_delayed(struct serio *serio) ...@@ -257,12 +280,16 @@ void serio_unregister_port_delayed(struct serio *serio)
*/ */
void __serio_unregister_port(struct serio *serio) void __serio_unregister_port(struct serio *serio)
{ {
serio_invalidate_pending_events(serio); serio_remove_pending_events(serio);
list_del_init(&serio->node); list_del_init(&serio->node);
if (serio->dev && serio->dev->disconnect) if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio); serio->dev->disconnect(serio);
} }
/*
* Serio device operations
*/
void serio_register_device(struct serio_dev *dev) void serio_register_device(struct serio_dev *dev)
{ {
struct serio *serio; struct serio *serio;
...@@ -292,9 +319,15 @@ void serio_unregister_device(struct serio_dev *dev) ...@@ -292,9 +319,15 @@ void serio_unregister_device(struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */ /* called from serio_dev->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_dev *dev) int serio_open(struct serio *serio, struct serio_dev *dev)
{ {
unsigned long flags;
spin_lock_irqsave(&serio->lock, flags);
serio->dev = dev; serio->dev = dev;
spin_unlock_irqrestore(&serio->lock, flags);
if (serio->open && serio->open(serio)) { if (serio->open && serio->open(serio)) {
spin_lock_irqsave(&serio->lock, flags);
serio->dev = NULL; serio->dev = NULL;
spin_unlock_irqrestore(&serio->lock, flags);
return -1; return -1;
} }
return 0; return 0;
...@@ -303,9 +336,38 @@ int serio_open(struct serio *serio, struct serio_dev *dev) ...@@ -303,9 +336,38 @@ int serio_open(struct serio *serio, struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */ /* called from serio_dev->connect/disconnect methods under serio_sem */
void serio_close(struct serio *serio) void serio_close(struct serio *serio)
{ {
unsigned long flags;
if (serio->close) if (serio->close)
serio->close(serio); serio->close(serio);
spin_lock_irqsave(&serio->lock, flags);
serio->dev = NULL; serio->dev = NULL;
spin_unlock_irqrestore(&serio->lock, flags);
}
irqreturn_t serio_interrupt(struct serio *serio,
unsigned char data, unsigned int dfl, struct pt_regs *regs)
{
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
spin_lock_irqsave(&serio->lock, flags);
if (likely(serio->dev)) {
ret = serio->dev->interrupt(serio, data, dfl, regs);
} else {
if (!dfl) {
if ((serio->type != SERIO_8042 &&
serio->type != SERIO_8042_XL) || (data == 0xaa)) {
serio_rescan(serio);
ret = IRQ_HANDLED;
}
}
}
spin_unlock_irqrestore(&serio->lock, flags);
return ret;
} }
static int __init serio_init(void) static int __init serio_init(void)
......
This diff is collapsed.
...@@ -1430,6 +1430,11 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1430,6 +1430,11 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
#define USB_VENDOR_ID_CODEMERCS 0x07c0
#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
static struct hid_blacklist { static struct hid_blacklist {
__u16 idVendor; __u16 idVendor;
__u16 idProduct; __u16 idProduct;
...@@ -1444,20 +1449,20 @@ static struct hid_blacklist { ...@@ -1444,20 +1449,20 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, 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_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_POWERMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, 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_UPS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, 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, 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 + 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 + 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 + 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 + 400, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, 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 },
......
...@@ -110,7 +110,7 @@ int hid_tmff_init(struct hid_device *hid) ...@@ -110,7 +110,7 @@ int hid_tmff_init(struct hid_device *hid)
{ {
struct tmff_device *private; struct tmff_device *private;
struct list_head *pos; struct list_head *pos;
struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list); struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL); private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
if (!private) if (!private)
......
...@@ -639,15 +639,21 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -639,15 +639,21 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
goto inval; goto inval;
field = report->field[uref->field_index]; field = report->field[uref->field_index];
if (cmd == HIDIOCGCOLLECTIONINDEX) {
if (uref->usage_index >= field->maxusage) if (uref->usage_index >= field->maxusage)
goto inval; goto inval;
} else if (uref->usage_index >= field->report_count)
goto inval;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { else if ((cmd == HIDIOCGUSAGES ||
if (uref_multi->num_values >= HID_MAX_USAGES || cmd == HIDIOCSUSAGES) &&
uref->usage_index >= field->maxusage || (uref->usage_index + uref_multi->num_values >=
(uref->usage_index + uref_multi->num_values) >= field->maxusage) field->report_count ||
uref->usage_index + uref_multi->num_values <
uref->usage_index))
goto inval; goto inval;
}
} }
switch (cmd) { switch (cmd) {
......
...@@ -115,6 +115,8 @@ ...@@ -115,6 +115,8 @@
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/msdos_fs.h> #include <linux/msdos_fs.h>
#include <linux/hiddev.h>
#undef INCLUDES #undef INCLUDES
#endif #endif
......
...@@ -728,3 +728,20 @@ COMPATIBLE_IOCTL(SIOCSIWRETRY) ...@@ -728,3 +728,20 @@ COMPATIBLE_IOCTL(SIOCSIWRETRY)
COMPATIBLE_IOCTL(SIOCGIWRETRY) COMPATIBLE_IOCTL(SIOCGIWRETRY)
COMPATIBLE_IOCTL(SIOCSIWPOWER) COMPATIBLE_IOCTL(SIOCSIWPOWER)
COMPATIBLE_IOCTL(SIOCGIWPOWER) COMPATIBLE_IOCTL(SIOCGIWPOWER)
/* hiddev */
COMPATIBLE_IOCTL(HIDIOCGVERSION)
COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
COMPATIBLE_IOCTL(HIDIOCGSTRING)
COMPATIBLE_IOCTL(HIDIOCINITREPORT)
COMPATIBLE_IOCTL(HIDIOCGREPORT)
COMPATIBLE_IOCTL(HIDIOCSREPORT)
COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
COMPATIBLE_IOCTL(HIDIOCGUSAGE)
COMPATIBLE_IOCTL(HIDIOCSUSAGE)
COMPATIBLE_IOCTL(HIDIOCGUCODE)
COMPATIBLE_IOCTL(HIDIOCGFLAG)
COMPATIBLE_IOCTL(HIDIOCSFLAG)
COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
...@@ -128,10 +128,11 @@ struct hiddev_usage_ref { ...@@ -128,10 +128,11 @@ struct hiddev_usage_ref {
/* hiddev_usage_ref_multi is used for sending multiple bytes to a control. /* hiddev_usage_ref_multi is used for sending multiple bytes to a control.
* It really manifests itself as setting the value of consecutive usages */ * It really manifests itself as setting the value of consecutive usages */
#define HID_MAX_MULTI_USAGES 1024
struct hiddev_usage_ref_multi { struct hiddev_usage_ref_multi {
struct hiddev_usage_ref uref; struct hiddev_usage_ref uref;
__u32 num_values; __u32 num_values;
__s32 values[HID_MAX_USAGES]; __s32 values[HID_MAX_MULTI_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
...@@ -212,6 +213,11 @@ struct hiddev_usage_ref_multi { ...@@ -212,6 +213,11 @@ struct hiddev_usage_ref_multi {
* In-kernel definitions. * In-kernel definitions.
*/ */
struct hid_device;
struct hid_usage;
struct hid_field;
struct hid_report;
#ifdef CONFIG_USB_HIDDEV #ifdef CONFIG_USB_HIDDEV
int hiddev_connect(struct hid_device *); int hiddev_connect(struct hid_device *);
void hiddev_disconnect(struct hid_device *); void hiddev_disconnect(struct hid_device *);
......
...@@ -527,6 +527,8 @@ struct input_absinfo { ...@@ -527,6 +527,8 @@ struct input_absinfo {
#define MSC_SERIAL 0x00 #define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01 #define MSC_PULSELED 0x01
#define MSC_GESTURE 0x02 #define MSC_GESTURE 0x02
#define MSC_RAW 0x03
#define MSC_SCAN 0x04
#define MSC_MAX 0x07 #define MSC_MAX 0x07
/* /*
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h>
struct serio { struct serio {
void *private; void *private;
...@@ -32,11 +33,13 @@ struct serio { ...@@ -32,11 +33,13 @@ struct serio {
unsigned long type; unsigned long type;
unsigned long event; unsigned long event;
spinlock_t lock;
int (*write)(struct serio *, unsigned char); int (*write)(struct serio *, unsigned char);
int (*open)(struct serio *); int (*open)(struct serio *);
void (*close)(struct serio *); void (*close)(struct serio *);
struct serio_dev *dev; struct serio_dev *dev; /* Accessed from interrupt, writes must be protected by serio_lock */
struct list_head node; struct list_head node;
}; };
......
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