Commit 442af075 authored by Vojtech Pavlik's avatar Vojtech Pavlik

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

parents 628505a0 a8c6003a
...@@ -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
......
...@@ -650,6 +650,12 @@ running once the system is up. ...@@ -650,6 +650,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
......
...@@ -37,9 +37,9 @@ obj-$(CONFIG_PARIDE) += block/paride/ ...@@ -37,9 +37,9 @@ obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/ obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_I2C) += i2c/
obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_W1) += w1/
......
...@@ -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_SUPERH) #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_SUPERH)
#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, }
}; };
......
...@@ -247,7 +247,7 @@ config JOYSTICK_AMIGA ...@@ -247,7 +247,7 @@ config JOYSTICK_AMIGA
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 amijoy. module will be called amijoy.
config INPUT_JOYDUMP config JOYSTICK_JOYDUMP
tristate "Gameport data dumper" tristate "Gameport data dumper"
depends on INPUT && INPUT_JOYSTICK depends on INPUT && INPUT_JOYSTICK
help help
......
/* /*
* $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);
......
...@@ -524,7 +524,7 @@ static int __init iforce_init(void) ...@@ -524,7 +524,7 @@ static int __init iforce_init(void)
usb_register(&iforce_usb_driver); usb_register(&iforce_usb_driver);
#endif #endif
#ifdef CONFIG_JOYSTICK_IFORCE_232 #ifdef CONFIG_JOYSTICK_IFORCE_232
serio_register_device(&iforce_serio_dev); serio_register_driver(&iforce_serio_drv);
#endif #endif
return 0; return 0;
} }
...@@ -535,7 +535,7 @@ static void __exit iforce_exit(void) ...@@ -535,7 +535,7 @@ static void __exit iforce_exit(void)
usb_deregister(&iforce_usb_driver); usb_deregister(&iforce_usb_driver);
#endif #endif
#ifdef CONFIG_JOYSTICK_IFORCE_232 #ifdef CONFIG_JOYSTICK_IFORCE_232
serio_unregister_device(&iforce_serio_dev); serio_unregister_driver(&iforce_serio_drv);
#endif #endif
} }
......
...@@ -124,7 +124,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, ...@@ -124,7 +124,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio,
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct iforce *iforce; struct iforce *iforce;
if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
...@@ -137,7 +137,7 @@ static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) ...@@ -137,7 +137,7 @@ static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
iforce->serio = serio; iforce->serio = serio;
serio->private = iforce; serio->private = iforce;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(iforce); kfree(iforce);
return; return;
} }
...@@ -158,7 +158,11 @@ static void iforce_serio_disconnect(struct serio *serio) ...@@ -158,7 +158,11 @@ static void iforce_serio_disconnect(struct serio *serio)
kfree(iforce); kfree(iforce);
} }
struct serio_dev iforce_serio_dev = { struct serio_driver iforce_serio_drv = {
.driver = {
.name = "iforce",
},
.description = "RS232 I-Force joysticks and wheels driver",
.write_wakeup = iforce_serio_write_wakeup, .write_wakeup = iforce_serio_write_wakeup,
.interrupt = iforce_serio_irq, .interrupt = iforce_serio_irq,
.connect = iforce_serio_connect, .connect = iforce_serio_connect,
......
...@@ -187,5 +187,5 @@ int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); ...@@ -187,5 +187,5 @@ int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update);
/* Public variables */ /* Public variables */
extern struct serio_dev iforce_serio_dev; extern struct serio_driver iforce_serio_drv;
extern struct usb_driver iforce_usb_driver; extern struct usb_driver iforce_usb_driver;
...@@ -35,8 +35,10 @@ ...@@ -35,8 +35,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -146,7 +148,7 @@ static void magellan_disconnect(struct serio *serio) ...@@ -146,7 +148,7 @@ static void magellan_disconnect(struct serio *serio)
* it as an input device. * it as an input device.
*/ */
static void magellan_connect(struct serio *serio, struct serio_dev *dev) static void magellan_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct magellan *magellan; struct magellan *magellan;
int i, t; int i, t;
...@@ -184,7 +186,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) ...@@ -184,7 +186,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev)
serio->private = magellan; serio->private = magellan;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(magellan); kfree(magellan);
return; return;
} }
...@@ -199,7 +201,11 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) ...@@ -199,7 +201,11 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev magellan_dev = { static struct serio_driver magellan_drv = {
.driver = {
.name = "magellan",
},
.description = DRIVER_DESC,
.interrupt = magellan_interrupt, .interrupt = magellan_interrupt,
.connect = magellan_connect, .connect = magellan_connect,
.disconnect = magellan_disconnect, .disconnect = magellan_disconnect,
...@@ -211,13 +217,13 @@ static struct serio_dev magellan_dev = { ...@@ -211,13 +217,13 @@ static struct serio_dev magellan_dev = {
int __init magellan_init(void) int __init magellan_init(void)
{ {
serio_register_device(&magellan_dev); serio_register_driver(&magellan_drv);
return 0; return 0;
} }
void __exit magellan_exit(void) void __exit magellan_exit(void)
{ {
serio_unregister_device(&magellan_dev); serio_unregister_driver(&magellan_drv);
} }
module_init(magellan_init); module_init(magellan_init);
......
...@@ -39,8 +39,10 @@ ...@@ -39,8 +39,10 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -201,7 +203,7 @@ static void spaceball_disconnect(struct serio *serio) ...@@ -201,7 +203,7 @@ static void spaceball_disconnect(struct serio *serio)
* it as an input device. * it as an input device.
*/ */
static void spaceball_connect(struct serio *serio, struct serio_dev *dev) static void spaceball_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct spaceball *spaceball; struct spaceball *spaceball;
int i, t, id; int i, t, id;
...@@ -254,7 +256,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) ...@@ -254,7 +256,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
serio->private = spaceball; serio->private = spaceball;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(spaceball); kfree(spaceball);
return; return;
} }
...@@ -269,7 +271,11 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) ...@@ -269,7 +271,11 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev spaceball_dev = { static struct serio_driver spaceball_drv = {
.driver = {
.name = "spaceball",
},
.description = DRIVER_DESC,
.interrupt = spaceball_interrupt, .interrupt = spaceball_interrupt,
.connect = spaceball_connect, .connect = spaceball_connect,
.disconnect = spaceball_disconnect, .disconnect = spaceball_disconnect,
...@@ -281,13 +287,13 @@ static struct serio_dev spaceball_dev = { ...@@ -281,13 +287,13 @@ static struct serio_dev spaceball_dev = {
int __init spaceball_init(void) int __init spaceball_init(void)
{ {
serio_register_device(&spaceball_dev); serio_register_driver(&spaceball_drv);
return 0; return 0;
} }
void __exit spaceball_exit(void) void __exit spaceball_exit(void)
{ {
serio_unregister_device(&spaceball_dev); serio_unregister_driver(&spaceball_drv);
} }
module_init(spaceball_init); module_init(spaceball_init);
......
...@@ -38,8 +38,10 @@ ...@@ -38,8 +38,10 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -162,7 +164,7 @@ static void spaceorb_disconnect(struct serio *serio) ...@@ -162,7 +164,7 @@ static void spaceorb_disconnect(struct serio *serio)
* it as an input device. * it as an input device.
*/ */
static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) static void spaceorb_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct spaceorb *spaceorb; struct spaceorb *spaceorb;
int i, t; int i, t;
...@@ -201,7 +203,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) ...@@ -201,7 +203,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
serio->private = spaceorb; serio->private = spaceorb;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(spaceorb); kfree(spaceorb);
return; return;
} }
...@@ -213,7 +215,11 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) ...@@ -213,7 +215,11 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev spaceorb_dev = { static struct serio_driver spaceorb_drv = {
.driver = {
.name = "spaceorb",
},
.description = DRIVER_DESC,
.interrupt = spaceorb_interrupt, .interrupt = spaceorb_interrupt,
.connect = spaceorb_connect, .connect = spaceorb_connect,
.disconnect = spaceorb_disconnect, .disconnect = spaceorb_disconnect,
...@@ -225,13 +231,13 @@ static struct serio_dev spaceorb_dev = { ...@@ -225,13 +231,13 @@ static struct serio_dev spaceorb_dev = {
int __init spaceorb_init(void) int __init spaceorb_init(void)
{ {
serio_register_device(&spaceorb_dev); serio_register_driver(&spaceorb_drv);
return 0; return 0;
} }
void __exit spaceorb_exit(void) void __exit spaceorb_exit(void)
{ {
serio_unregister_device(&spaceorb_dev); serio_unregister_driver(&spaceorb_drv);
} }
module_init(spaceorb_init); module_init(spaceorb_init);
......
...@@ -36,8 +36,10 @@ ...@@ -36,8 +36,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#define DRIVER_DESC "Gravis Stinger gamepad driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Gravis Stinger gamepad driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -134,7 +136,7 @@ static void stinger_disconnect(struct serio *serio) ...@@ -134,7 +136,7 @@ static void stinger_disconnect(struct serio *serio)
* it as an input device. * it as an input device.
*/ */
static void stinger_connect(struct serio *serio, struct serio_dev *dev) static void stinger_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct stinger *stinger; struct stinger *stinger;
int i; int i;
...@@ -172,7 +174,7 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) ...@@ -172,7 +174,7 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev)
stinger->dev.private = stinger; stinger->dev.private = stinger;
serio->private = stinger; serio->private = stinger;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(stinger); kfree(stinger);
return; return;
} }
...@@ -187,7 +189,11 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) ...@@ -187,7 +189,11 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev stinger_dev = { static struct serio_driver stinger_drv = {
.driver = {
.name = "stinger",
},
.description = DRIVER_DESC,
.interrupt = stinger_interrupt, .interrupt = stinger_interrupt,
.connect = stinger_connect, .connect = stinger_connect,
.disconnect = stinger_disconnect, .disconnect = stinger_disconnect,
...@@ -199,13 +205,13 @@ static struct serio_dev stinger_dev = { ...@@ -199,13 +205,13 @@ static struct serio_dev stinger_dev = {
int __init stinger_init(void) int __init stinger_init(void)
{ {
serio_register_device(&stinger_dev); serio_register_driver(&stinger_drv);
return 0; return 0;
} }
void __exit stinger_exit(void) void __exit stinger_exit(void)
{ {
serio_unregister_device(&stinger_dev); serio_unregister_driver(&stinger_drv);
} }
module_init(stinger_init); module_init(stinger_init);
......
...@@ -187,7 +187,7 @@ static void twidjoy_disconnect(struct serio *serio) ...@@ -187,7 +187,7 @@ static void twidjoy_disconnect(struct serio *serio)
* it as an input device. * it as an input device.
*/ */
static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) static void twidjoy_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct twidjoy_button_spec *bp; struct twidjoy_button_spec *bp;
struct twidjoy *twidjoy; struct twidjoy *twidjoy;
...@@ -232,7 +232,7 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) ...@@ -232,7 +232,7 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev)
twidjoy->dev.private = twidjoy; twidjoy->dev.private = twidjoy;
serio->private = twidjoy; serio->private = twidjoy;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(twidjoy); kfree(twidjoy);
return; return;
} }
...@@ -246,7 +246,11 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) ...@@ -246,7 +246,11 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev twidjoy_dev = { static struct serio_driver twidjoy_drv = {
.driver = {
.name = "twidjoy",
},
.description = DRIVER_DESC,
.interrupt = twidjoy_interrupt, .interrupt = twidjoy_interrupt,
.connect = twidjoy_connect, .connect = twidjoy_connect,
.disconnect = twidjoy_disconnect, .disconnect = twidjoy_disconnect,
...@@ -258,13 +262,13 @@ static struct serio_dev twidjoy_dev = { ...@@ -258,13 +262,13 @@ static struct serio_dev twidjoy_dev = {
int __init twidjoy_init(void) int __init twidjoy_init(void)
{ {
serio_register_device(&twidjoy_dev); serio_register_driver(&twidjoy_drv);
return 0; return 0;
} }
void __exit twidjoy_exit(void) void __exit twidjoy_exit(void)
{ {
serio_unregister_device(&twidjoy_dev); serio_unregister_driver(&twidjoy_drv);
} }
module_init(twidjoy_init); module_init(twidjoy_init);
......
...@@ -35,8 +35,10 @@ ...@@ -35,8 +35,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#define DRIVER_DESC "Logitech WingMan Warrior joystick driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Logitech WingMan Warrior joystick driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -139,7 +141,7 @@ static void warrior_disconnect(struct serio *serio) ...@@ -139,7 +141,7 @@ static void warrior_disconnect(struct serio *serio)
* it as an input device. * it as an input device.
*/ */
static void warrior_connect(struct serio *serio, struct serio_dev *dev) static void warrior_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct warrior *warrior; struct warrior *warrior;
int i; int i;
...@@ -185,7 +187,7 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) ...@@ -185,7 +187,7 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev)
serio->private = warrior; serio->private = warrior;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(warrior); kfree(warrior);
return; return;
} }
...@@ -199,7 +201,11 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) ...@@ -199,7 +201,11 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev warrior_dev = { static struct serio_driver warrior_drv = {
.driver = {
.name = "warrior",
},
.description = DRIVER_DESC,
.interrupt = warrior_interrupt, .interrupt = warrior_interrupt,
.connect = warrior_connect, .connect = warrior_connect,
.disconnect = warrior_disconnect, .disconnect = warrior_disconnect,
...@@ -211,13 +217,13 @@ static struct serio_dev warrior_dev = { ...@@ -211,13 +217,13 @@ static struct serio_dev warrior_dev = {
int __init warrior_init(void) int __init warrior_init(void)
{ {
serio_register_device(&warrior_dev); serio_register_driver(&warrior_drv);
return 0; return 0;
} }
void __exit warrior_exit(void) void __exit warrior_exit(void)
{ {
serio_unregister_device(&warrior_dev); serio_unregister_driver(&warrior_drv);
} }
module_init(warrior_init); module_init(warrior_init);
......
...@@ -27,8 +27,10 @@ ...@@ -27,8 +27,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int atkbd_set = 2; static int atkbd_set = 2;
...@@ -47,6 +49,10 @@ static int atkbd_softrepeat; ...@@ -47,6 +49,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 +170,48 @@ static unsigned char atkbd_scroll_keys[5][2] = { ...@@ -164,34 +170,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 +244,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -224,7 +244,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 +254,45 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -234,24 +254,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 +311,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -270,6 +311,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 +342,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -300,6 +342,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 +421,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -376,18 +421,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 +452,7 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) ...@@ -405,7 +452,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 +460,40 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) ...@@ -413,38 +460,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 +721,7 @@ static void atkbd_cleanup(struct serio *serio) ...@@ -672,6 +721,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);
...@@ -684,7 +734,7 @@ static void atkbd_disconnect(struct serio *serio) ...@@ -684,7 +734,7 @@ static void atkbd_disconnect(struct serio *serio)
* to the input module. * to the input module.
*/ */
static void atkbd_connect(struct serio *serio, struct serio_dev *dev) static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct atkbd *atkbd; struct atkbd *atkbd;
int i; int i;
...@@ -709,17 +759,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -709,17 +759,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);
...@@ -732,7 +787,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -732,7 +787,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
serio->private = atkbd; serio->private = atkbd;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(atkbd); kfree(atkbd);
return; return;
} }
...@@ -754,8 +809,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -754,8 +809,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 +850,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -797,6 +850,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);
} }
...@@ -808,10 +863,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -808,10 +863,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
static int atkbd_reconnect(struct serio *serio) 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_driver *drv = serio->drv;
unsigned char param[1]; unsigned char param[1];
if (!dev) { if (!drv) {
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;
} }
...@@ -832,10 +887,16 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -832,10 +887,16 @@ static int atkbd_reconnect(struct serio *serio)
return -1; return -1;
} }
set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
return 0; return 0;
} }
static struct serio_dev atkbd_dev = { static struct serio_driver atkbd_drv = {
.driver = {
.name = "atkbd",
},
.description = DRIVER_DESC,
.interrupt = atkbd_interrupt, .interrupt = atkbd_interrupt,
.connect = atkbd_connect, .connect = atkbd_connect,
.reconnect = atkbd_reconnect, .reconnect = atkbd_reconnect,
...@@ -845,13 +906,13 @@ static struct serio_dev atkbd_dev = { ...@@ -845,13 +906,13 @@ static struct serio_dev atkbd_dev = {
int __init atkbd_init(void) int __init atkbd_init(void)
{ {
serio_register_device(&atkbd_dev); serio_register_driver(&atkbd_drv);
return 0; return 0;
} }
void __exit atkbd_exit(void) void __exit atkbd_exit(void)
{ {
serio_unregister_device(&atkbd_dev); serio_unregister_driver(&atkbd_drv);
} }
module_init(atkbd_init); module_init(atkbd_init);
......
...@@ -76,8 +76,10 @@ ...@@ -76,8 +76,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#define DRIVER_DESC "LK keyboard driver"
MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
MODULE_DESCRIPTION ("LK keyboard driver"); MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
/* /*
...@@ -622,7 +624,7 @@ lkkbd_reinit (void *data) ...@@ -622,7 +624,7 @@ lkkbd_reinit (void *data)
* lkkbd_connect() probes for a LK keyboard and fills the necessary structures. * lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
*/ */
static void static void
lkkbd_connect (struct serio *serio, struct serio_dev *dev) lkkbd_connect (struct serio *serio, struct serio_driver *drv)
{ {
struct lkkbd *lk; struct lkkbd *lk;
int i; int i;
...@@ -665,7 +667,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) ...@@ -665,7 +667,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev)
serio->private = lk; serio->private = lk;
if (serio_open (serio, dev)) { if (serio_open (serio, drv)) {
kfree (lk); kfree (lk);
return; return;
} }
...@@ -703,7 +705,11 @@ lkkbd_disconnect (struct serio *serio) ...@@ -703,7 +705,11 @@ lkkbd_disconnect (struct serio *serio)
kfree (lk); kfree (lk);
} }
static struct serio_dev lkkbd_dev = { static struct serio_driver lkkbd_drv = {
.driver = {
.name = "lkkbd",
},
.description = DRIVER_DESC,
.connect = lkkbd_connect, .connect = lkkbd_connect,
.disconnect = lkkbd_disconnect, .disconnect = lkkbd_disconnect,
.interrupt = lkkbd_interrupt, .interrupt = lkkbd_interrupt,
...@@ -715,14 +721,14 @@ static struct serio_dev lkkbd_dev = { ...@@ -715,14 +721,14 @@ static struct serio_dev lkkbd_dev = {
int __init int __init
lkkbd_init (void) lkkbd_init (void)
{ {
serio_register_device (&lkkbd_dev); serio_register_driver(&lkkbd_drv);
return 0; return 0;
} }
void __exit void __exit
lkkbd_exit (void) lkkbd_exit (void)
{ {
serio_unregister_device (&lkkbd_dev); serio_unregister_driver(&lkkbd_drv);
} }
module_init (lkkbd_init); module_init (lkkbd_init);
......
...@@ -32,8 +32,10 @@ ...@@ -32,8 +32,10 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/serio.h> #include <linux/serio.h>
#define DRIVER_DESC "Newton keyboard driver"
MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>"); MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>");
MODULE_DESCRIPTION("Newton keyboard driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define NKBD_KEY 0x7f #define NKBD_KEY 0x7f
...@@ -82,7 +84,7 @@ irqreturn_t nkbd_interrupt(struct serio *serio, ...@@ -82,7 +84,7 @@ irqreturn_t nkbd_interrupt(struct serio *serio,
} }
void nkbd_connect(struct serio *serio, struct serio_dev *dev) void nkbd_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct nkbd *nkbd; struct nkbd *nkbd;
int i; int i;
...@@ -106,7 +108,7 @@ void nkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -106,7 +108,7 @@ void nkbd_connect(struct serio *serio, struct serio_dev *dev)
nkbd->dev.private = nkbd; nkbd->dev.private = nkbd;
serio->private = nkbd; serio->private = nkbd;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(nkbd); kfree(nkbd);
return; return;
} }
...@@ -138,21 +140,25 @@ void nkbd_disconnect(struct serio *serio) ...@@ -138,21 +140,25 @@ void nkbd_disconnect(struct serio *serio)
kfree(nkbd); kfree(nkbd);
} }
struct serio_dev nkbd_dev = { struct serio_driver nkbd_drv = {
.driver = {
.name = "newtonkbd",
},
.description = DRIVER_DESC,
.interrupt = nkbd_interrupt, .interrupt = nkbd_interrupt,
.connect = nkbd_connect, .connect = nkbd_connect,
.disconnect = nkbd_disconnect .disconnect = nkbd_disconnect,
}; };
int __init nkbd_init(void) int __init nkbd_init(void)
{ {
serio_register_device(&nkbd_dev); serio_register_driver(&nkbd_drv);
return 0; return 0;
} }
void __exit nkbd_exit(void) void __exit nkbd_exit(void)
{ {
serio_unregister_device(&nkbd_dev); serio_unregister_driver(&nkbd_drv);
} }
module_init(nkbd_init); module_init(nkbd_init);
......
...@@ -37,8 +37,10 @@ ...@@ -37,8 +37,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#define DRIVER_DESC "Sun keyboard driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Sun keyboard driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static unsigned char sunkbd_keycode[128] = { static unsigned char sunkbd_keycode[128] = {
...@@ -221,7 +223,7 @@ static void sunkbd_reinit(void *data) ...@@ -221,7 +223,7 @@ static void sunkbd_reinit(void *data)
* sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
*/ */
static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) static void sunkbd_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct sunkbd *sunkbd; struct sunkbd *sunkbd;
int i; int i;
...@@ -257,7 +259,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -257,7 +259,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev)
serio->private = sunkbd; serio->private = sunkbd;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(sunkbd); kfree(sunkbd);
return; return;
} }
...@@ -301,10 +303,14 @@ static void sunkbd_disconnect(struct serio *serio) ...@@ -301,10 +303,14 @@ static void sunkbd_disconnect(struct serio *serio)
kfree(sunkbd); kfree(sunkbd);
} }
static struct serio_dev sunkbd_dev = { static struct serio_driver sunkbd_drv = {
.driver = {
.name = "sunkbd",
},
.description = DRIVER_DESC,
.interrupt = sunkbd_interrupt, .interrupt = sunkbd_interrupt,
.connect = sunkbd_connect, .connect = sunkbd_connect,
.disconnect = sunkbd_disconnect .disconnect = sunkbd_disconnect,
}; };
/* /*
...@@ -313,13 +319,13 @@ static struct serio_dev sunkbd_dev = { ...@@ -313,13 +319,13 @@ static struct serio_dev sunkbd_dev = {
int __init sunkbd_init(void) int __init sunkbd_init(void)
{ {
serio_register_device(&sunkbd_dev); serio_register_driver(&sunkbd_drv);
return 0; return 0;
} }
void __exit sunkbd_exit(void) void __exit sunkbd_exit(void)
{ {
serio_unregister_device(&sunkbd_dev); serio_unregister_driver(&sunkbd_drv);
} }
module_init(sunkbd_init); module_init(sunkbd_init);
......
...@@ -34,8 +34,10 @@ ...@@ -34,8 +34,10 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/serio.h> #include <linux/serio.h>
#define DRIVER_DESC "XT keyboard driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("XT keyboard driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define XTKBD_EMUL0 0xe0 #define XTKBD_EMUL0 0xe0
...@@ -86,7 +88,7 @@ irqreturn_t xtkbd_interrupt(struct serio *serio, ...@@ -86,7 +88,7 @@ irqreturn_t xtkbd_interrupt(struct serio *serio,
return IRQ_HANDLED; return IRQ_HANDLED;
} }
void xtkbd_connect(struct serio *serio, struct serio_dev *dev) void xtkbd_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct xtkbd *xtkbd; struct xtkbd *xtkbd;
int i; int i;
...@@ -111,7 +113,7 @@ void xtkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -111,7 +113,7 @@ void xtkbd_connect(struct serio *serio, struct serio_dev *dev)
serio->private = xtkbd; serio->private = xtkbd;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(xtkbd); kfree(xtkbd);
return; return;
} }
...@@ -143,21 +145,25 @@ void xtkbd_disconnect(struct serio *serio) ...@@ -143,21 +145,25 @@ void xtkbd_disconnect(struct serio *serio)
kfree(xtkbd); kfree(xtkbd);
} }
struct serio_dev xtkbd_dev = { struct serio_driver xtkbd_drv = {
.driver = {
.name = "xtkbd",
},
.description = DRIVER_DESC,
.interrupt = xtkbd_interrupt, .interrupt = xtkbd_interrupt,
.connect = xtkbd_connect, .connect = xtkbd_connect,
.disconnect = xtkbd_disconnect .disconnect = xtkbd_disconnect,
}; };
int __init xtkbd_init(void) int __init xtkbd_init(void)
{ {
serio_register_device(&xtkbd_dev); serio_register_driver(&xtkbd_drv);
return 0; return 0;
} }
void __exit xtkbd_exit(void) void __exit xtkbd_exit(void)
{ {
serio_unregister_device(&xtkbd_dev); serio_unregister_driver(&xtkbd_drv);
} }
module_init(xtkbd_init); module_init(xtkbd_init);
......
...@@ -14,7 +14,7 @@ config INPUT_MISC ...@@ -14,7 +14,7 @@ config INPUT_MISC
config INPUT_PCSPKR config INPUT_PCSPKR
tristate "PC Speaker support" tristate "PC Speaker support"
depends on (ALPHA || X86 || X86_64 || MIPS) && INPUT && INPUT_MISC depends on (ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES) && INPUT && INPUT_MISC
help help
Say Y here if you want the standard PC Speaker to be used for Say Y here if you want the standard PC Speaker to be used for
bells and whistles. bells and whistles.
......
...@@ -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 */
......
...@@ -22,8 +22,10 @@ ...@@ -22,8 +22,10 @@
#include "synaptics.h" #include "synaptics.h"
#include "logips2pp.h" #include "logips2pp.h"
#define DRIVER_DESC "PS/2 mouse driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("PS/2 mouse driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static char *psmouse_proto; static char *psmouse_proto;
...@@ -142,34 +144,45 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -142,34 +144,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 (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
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) { if (!psmouse->cmdcnt)
psmouse->cmdbuf[--psmouse->cmdcnt] = data; clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
goto out; goto out;
} }
...@@ -242,18 +255,15 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -242,18 +255,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 +283,60 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -273,44 +283,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 +420,8 @@ static int im_explorer_detect(struct psmouse *psmouse) ...@@ -394,6 +420,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;
...@@ -626,16 +654,15 @@ static void psmouse_cleanup(struct serio *serio) ...@@ -626,16 +654,15 @@ static void psmouse_cleanup(struct serio *serio)
static void psmouse_disconnect(struct serio *serio) static void psmouse_disconnect(struct serio *serio)
{ {
struct psmouse *psmouse = serio->private; struct psmouse *psmouse, *parent;
psmouse = serio->private;
psmouse->state = PSMOUSE_CMD_MODE; psmouse->state = PSMOUSE_CMD_MODE;
if (psmouse->ptport) { if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
if (psmouse->ptport->deactivate) parent = serio->parent->private;
psmouse->ptport->deactivate(psmouse); if (parent->pt_deactivate)
__serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */ parent->pt_deactivate(parent);
kfree(psmouse->ptport);
psmouse->ptport = NULL;
} }
if (psmouse->disconnect) if (psmouse->disconnect)
...@@ -652,16 +679,19 @@ static void psmouse_disconnect(struct serio *serio) ...@@ -652,16 +679,19 @@ static void psmouse_disconnect(struct serio *serio)
* psmouse_connect() is a callback from the serio module when * psmouse_connect() is a callback from the serio module when
* an unhandled serio port is found. * an unhandled serio port is found.
*/ */
static void psmouse_connect(struct serio *serio, struct serio_dev *dev) static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct psmouse *psmouse; struct psmouse *psmouse, *parent = NULL;
if ((serio->type & SERIO_TYPE) != SERIO_8042 && if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
(serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
return; return;
if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU)
parent = serio->parent->private;
if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
return; goto out;
memset(psmouse, 0, sizeof(struct psmouse)); memset(psmouse, 0, sizeof(struct psmouse));
...@@ -674,17 +704,17 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -674,17 +704,17 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->dev.private = psmouse; psmouse->dev.private = psmouse;
serio->private = psmouse; serio->private = psmouse;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(psmouse); kfree(psmouse);
serio->private = NULL; serio->private = NULL;
return; goto out;
} }
if (psmouse_probe(psmouse) < 0) { if (psmouse_probe(psmouse) < 0) {
serio_close(serio); serio_close(serio);
kfree(psmouse); kfree(psmouse);
serio->private = NULL; serio->private = NULL;
return; goto out;
} }
psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
...@@ -713,29 +743,50 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -713,29 +743,50 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse_initialize(psmouse); psmouse_initialize(psmouse);
if (psmouse->ptport) { if (parent && parent->pt_activate)
printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys); parent->pt_activate(parent);
__serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */
if (psmouse->ptport->activate)
psmouse->ptport->activate(psmouse);
}
/*
* OK, the device is ready, we just need to activate it (turn the
* stream mode on). But if mouse has a pass-through port we don't
* want to do it yet to not disturb child detection.
* The child will activate this port when it's ready.
*/
if (serio->child) {
/*
* Nothing to be done here, serio core will detect that
* the driver set serio->child and will register it for us.
*/
printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys);
} else
psmouse_activate(psmouse); psmouse_activate(psmouse);
out:
/* If this is a pass-through port the parent awaits to be activated */
if (parent)
psmouse_activate(parent);
} }
static int psmouse_reconnect(struct serio *serio) static int psmouse_reconnect(struct serio *serio)
{ {
struct psmouse *psmouse = serio->private; struct psmouse *psmouse = serio->private;
struct serio_dev *dev = serio->dev; struct psmouse *parent = NULL;
struct serio_driver *drv = serio->drv;
if (!dev || !psmouse) { if (!drv || !psmouse) {
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
return -1; return -1;
} }
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;
...@@ -748,21 +799,28 @@ static int psmouse_reconnect(struct serio *serio) ...@@ -748,21 +799,28 @@ static int psmouse_reconnect(struct serio *serio)
*/ */
psmouse_initialize(psmouse); psmouse_initialize(psmouse);
if (psmouse->ptport) { if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU)
if (psmouse_reconnect(&psmouse->ptport->serio)) { parent = serio->parent->private;
__serio_unregister_port(&psmouse->ptport->serio);
__serio_register_port(&psmouse->ptport->serio);
if (psmouse->ptport->activate)
psmouse->ptport->activate(psmouse);
}
}
if (parent && parent->pt_activate)
parent->pt_activate(parent);
if (!serio->child)
psmouse_activate(psmouse); psmouse_activate(psmouse);
/* If this is a pass-through port the parent waits to be activated */
if (parent)
psmouse_activate(parent);
return 0; return 0;
} }
static struct serio_dev psmouse_dev = { static struct serio_driver psmouse_drv = {
.driver = {
.name = "psmouse",
},
.description = DRIVER_DESC,
.interrupt = psmouse_interrupt, .interrupt = psmouse_interrupt,
.connect = psmouse_connect, .connect = psmouse_connect,
.reconnect = psmouse_reconnect, .reconnect = psmouse_reconnect,
...@@ -787,13 +845,13 @@ static inline void psmouse_parse_proto(void) ...@@ -787,13 +845,13 @@ static inline void psmouse_parse_proto(void)
int __init psmouse_init(void) int __init psmouse_init(void)
{ {
psmouse_parse_proto(); psmouse_parse_proto();
serio_register_device(&psmouse_dev); serio_register_driver(&psmouse_drv);
return 0; return 0;
} }
void __exit psmouse_exit(void) void __exit psmouse_exit(void)
{ {
serio_unregister_device(&psmouse_dev); serio_unregister_driver(&psmouse_drv);
} }
module_init(psmouse_init); module_init(psmouse_init);
......
...@@ -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,
...@@ -29,20 +34,10 @@ typedef enum { ...@@ -29,20 +34,10 @@ typedef enum {
PSMOUSE_FULL_PACKET PSMOUSE_FULL_PACKET
} psmouse_ret_t; } psmouse_ret_t;
struct psmouse;
struct psmouse_ptport {
struct serio serio;
void (*activate)(struct psmouse *parent);
void (*deactivate)(struct psmouse *parent);
};
struct psmouse { struct psmouse {
void *private; void *private;
struct input_dev dev; struct input_dev dev;
struct serio *serio; struct serio *serio;
struct psmouse_ptport *ptport;
char *vendor; char *vendor;
char *name; char *name;
unsigned char cmdbuf[8]; unsigned char cmdbuf[8];
...@@ -54,15 +49,18 @@ struct psmouse { ...@@ -54,15 +49,18 @@ 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);
void (*disconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse);
void (*pt_activate)(struct psmouse *psmouse);
void (*pt_deactivate)(struct psmouse *psmouse);
}; };
#define PSMOUSE_PS2 1 #define PSMOUSE_PS2 1
......
...@@ -37,8 +37,10 @@ ...@@ -37,8 +37,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#define DRIVER_DESC "Serial mouse driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serial mouse driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
...@@ -237,7 +239,7 @@ static void sermouse_disconnect(struct serio *serio) ...@@ -237,7 +239,7 @@ static void sermouse_disconnect(struct serio *serio)
* an unhandled serio port is found. * an unhandled serio port is found.
*/ */
static void sermouse_connect(struct serio *serio, struct serio_dev *dev) static void sermouse_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct sermouse *sermouse; struct sermouse *sermouse;
unsigned char c; unsigned char c;
...@@ -279,7 +281,7 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -279,7 +281,7 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev)
sermouse->dev.id.product = c; sermouse->dev.id.product = c;
sermouse->dev.id.version = 0x0100; sermouse->dev.id.version = 0x0100;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(sermouse); kfree(sermouse);
return; return;
} }
...@@ -289,21 +291,25 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -289,21 +291,25 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev)
printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
} }
static struct serio_dev sermouse_dev = { static struct serio_driver sermouse_drv = {
.driver = {
.name = "sermouse",
},
.description = DRIVER_DESC,
.interrupt = sermouse_interrupt, .interrupt = sermouse_interrupt,
.connect = sermouse_connect, .connect = sermouse_connect,
.disconnect = sermouse_disconnect .disconnect = sermouse_disconnect,
}; };
int __init sermouse_init(void) int __init sermouse_init(void)
{ {
serio_register_device(&sermouse_dev); serio_register_driver(&sermouse_drv);
return 0; return 0;
} }
void __exit sermouse_exit(void) void __exit sermouse_exit(void)
{ {
serio_unregister_device(&sermouse_dev); serio_unregister_driver(&sermouse_drv);
} }
module_init(sermouse_init); module_init(sermouse_init);
......
...@@ -212,9 +212,9 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) ...@@ -212,9 +212,9 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode)
/***************************************************************************** /*****************************************************************************
* Synaptics pass-through PS/2 port support * Synaptics pass-through PS/2 port support
****************************************************************************/ ****************************************************************************/
static int synaptics_pt_write(struct serio *port, unsigned char c) static int synaptics_pt_write(struct serio *serio, unsigned char c)
{ {
struct psmouse *parent = port->driver; struct psmouse *parent = serio->parent->private;
char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
if (psmouse_sliced_command(parent, c)) if (psmouse_sliced_command(parent, c))
...@@ -248,7 +248,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet ...@@ -248,7 +248,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
static void synaptics_pt_activate(struct psmouse *psmouse) static void synaptics_pt_activate(struct psmouse *psmouse)
{ {
struct psmouse *child = psmouse->ptport->serio.private; struct psmouse *child = psmouse->serio->child->private;
/* adjust the touchpad to child's choice of protocol */ /* adjust the touchpad to child's choice of protocol */
if (child && child->type >= PSMOUSE_GENPS) { if (child && child->type >= PSMOUSE_GENPS) {
...@@ -259,23 +259,25 @@ static void synaptics_pt_activate(struct psmouse *psmouse) ...@@ -259,23 +259,25 @@ static void synaptics_pt_activate(struct psmouse *psmouse)
static void synaptics_pt_create(struct psmouse *psmouse) static void synaptics_pt_create(struct psmouse *psmouse)
{ {
struct psmouse_ptport *port; struct serio *serio;
psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (!port) { if (!serio) {
printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
return; return;
} }
memset(port, 0, sizeof(struct psmouse_ptport)); memset(serio, 0, sizeof(struct serio));
port->serio.type = SERIO_PS_PSTHRU; serio->type = SERIO_PS_PSTHRU;
port->serio.name = "Synaptics pass-through"; strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
port->serio.phys = "synaptics-pt/serio0"; strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
port->serio.write = synaptics_pt_write; serio->write = synaptics_pt_write;
port->serio.driver = psmouse; serio->parent = psmouse->serio;
port->activate = synaptics_pt_activate; psmouse->pt_activate = synaptics_pt_activate;
psmouse->serio->child = serio;
} }
/***************************************************************************** /*****************************************************************************
...@@ -470,8 +472,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r ...@@ -470,8 +472,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r
if (unlikely(priv->pkt_type == SYN_NEWABS)) if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse); priv->pkt_type = synaptics_detect_pkt_type(psmouse);
if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) if (psmouse->serio->child && psmouse->serio->child->drv && synaptics_is_pt_packet(psmouse->packet))
synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet);
else else
synaptics_process_packet(psmouse); synaptics_process_packet(psmouse);
......
...@@ -82,8 +82,10 @@ ...@@ -82,8 +82,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#define DRIVER_DESC "Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"
MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>"); MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"); MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
#undef VSXXXAA_DEBUG #undef VSXXXAA_DEBUG
...@@ -482,7 +484,7 @@ vsxxxaa_disconnect (struct serio *serio) ...@@ -482,7 +484,7 @@ vsxxxaa_disconnect (struct serio *serio)
} }
static void static void
vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
{ {
struct vsxxxaa *mouse; struct vsxxxaa *mouse;
...@@ -524,7 +526,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) ...@@ -524,7 +526,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev)
mouse->dev.id.bustype = BUS_RS232; mouse->dev.id.bustype = BUS_RS232;
mouse->serio = serio; mouse->serio = serio;
if (serio_open (serio, dev)) { if (serio_open (serio, drv)) {
kfree (mouse); kfree (mouse);
return; return;
} }
...@@ -540,7 +542,11 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) ...@@ -540,7 +542,11 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev)
printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys);
} }
static struct serio_dev vsxxxaa_dev = { static struct serio_driver vsxxxaa_drv = {
.driver = {
.name = "vsxxxaa",
},
.description = DRIVER_DESC,
.connect = vsxxxaa_connect, .connect = vsxxxaa_connect,
.interrupt = vsxxxaa_interrupt, .interrupt = vsxxxaa_interrupt,
.disconnect = vsxxxaa_disconnect, .disconnect = vsxxxaa_disconnect,
...@@ -549,14 +555,14 @@ static struct serio_dev vsxxxaa_dev = { ...@@ -549,14 +555,14 @@ static struct serio_dev vsxxxaa_dev = {
int __init int __init
vsxxxaa_init (void) vsxxxaa_init (void)
{ {
serio_register_device (&vsxxxaa_dev); serio_register_driver(&vsxxxaa_drv);
return 0; return 0;
} }
void __exit void __exit
vsxxxaa_exit (void) vsxxxaa_exit (void)
{ {
serio_unregister_device (&vsxxxaa_dev); serio_unregister_driver(&vsxxxaa_drv);
} }
module_init (vsxxxaa_init); module_init (vsxxxaa_init);
......
...@@ -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;
......
...@@ -130,3 +130,19 @@ config SERIO_MACEPS2 ...@@ -130,3 +130,19 @@ config SERIO_MACEPS2
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 maceps2. module will be called maceps2.
config SERIO_RAW
tristate "Raw access to serio ports"
depends on SERIO
help
Say Y here if you want to have raw access to serio ports, such as
AUX ports on i8042 keyboard controller. Each serio port that is
bound to this driver will be accessible via a char device with
major 10 and dynamically allocated minor. The driver will try
allocating minor 1 (that historically corresponds to /dev/psaux)
first. To bind this driver to a serio port use sysfs interface:
echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
To compile this driver as a module, choose M here: the
module will be called serio_raw.
...@@ -17,3 +17,4 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o ...@@ -17,3 +17,4 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#define KMI_BASE (kmi->base) #define KMI_BASE (kmi->base)
struct amba_kmi_port { struct amba_kmi_port {
struct serio io; struct serio *io;
struct clk *clk; struct clk *clk;
unsigned char *base; unsigned char *base;
unsigned int irq; unsigned int irq;
...@@ -44,7 +44,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) ...@@ -44,7 +44,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
int handled = IRQ_NONE; int handled = IRQ_NONE;
while (status & KMIIR_RXINTR) { while (status & KMIIR_RXINTR) {
serio_interrupt(&kmi->io, readb(KMIDATA), 0, regs); serio_interrupt(kmi->io, readb(KMIDATA), 0, regs);
status = readb(KMIIR); status = readb(KMIIR);
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
} }
...@@ -54,7 +54,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) ...@@ -54,7 +54,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
static int amba_kmi_write(struct serio *io, unsigned char val) static int amba_kmi_write(struct serio *io, unsigned char val)
{ {
struct amba_kmi_port *kmi = io->driver; struct amba_kmi_port *kmi = io->port_data;
unsigned int timeleft = 10000; /* timeout in 100ms */ unsigned int timeleft = 10000; /* timeout in 100ms */
while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--)
...@@ -68,7 +68,7 @@ static int amba_kmi_write(struct serio *io, unsigned char val) ...@@ -68,7 +68,7 @@ static int amba_kmi_write(struct serio *io, unsigned char val)
static int amba_kmi_open(struct serio *io) static int amba_kmi_open(struct serio *io)
{ {
struct amba_kmi_port *kmi = io->driver; struct amba_kmi_port *kmi = io->port_data;
unsigned int divisor; unsigned int divisor;
int ret; int ret;
...@@ -105,7 +105,7 @@ static int amba_kmi_open(struct serio *io) ...@@ -105,7 +105,7 @@ static int amba_kmi_open(struct serio *io)
static void amba_kmi_close(struct serio *io) static void amba_kmi_close(struct serio *io)
{ {
struct amba_kmi_port *kmi = io->driver; struct amba_kmi_port *kmi = io->port_data;
writeb(0, KMICR); writeb(0, KMICR);
...@@ -117,6 +117,7 @@ static void amba_kmi_close(struct serio *io) ...@@ -117,6 +117,7 @@ static void amba_kmi_close(struct serio *io)
static int amba_kmi_probe(struct amba_device *dev, void *id) static int amba_kmi_probe(struct amba_device *dev, void *id)
{ {
struct amba_kmi_port *kmi; struct amba_kmi_port *kmi;
struct serio *io;
int ret; int ret;
ret = amba_request_regions(dev, NULL); ret = amba_request_regions(dev, NULL);
...@@ -124,21 +125,25 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) ...@@ -124,21 +125,25 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
return ret; return ret;
kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
if (!kmi) { io = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (!kmi || !io) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
memset(kmi, 0, sizeof(struct amba_kmi_port)); memset(kmi, 0, sizeof(struct amba_kmi_port));
memset(io, 0, sizeof(struct serio));
kmi->io.type = SERIO_8042;
kmi->io.write = amba_kmi_write; io->type = SERIO_8042;
kmi->io.open = amba_kmi_open; io->write = amba_kmi_write;
kmi->io.close = amba_kmi_close; io->open = amba_kmi_open;
kmi->io.name = dev->dev.bus_id; io->close = amba_kmi_close;
kmi->io.phys = dev->dev.bus_id; strlcpy(io->name, dev->dev.bus_id, sizeof(io->name));
kmi->io.driver = kmi; strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys));
io->port_data = kmi;
io->dev.parent = &dev->dev;
kmi->io = io;
kmi->base = ioremap(dev->res.start, KMI_SIZE); kmi->base = ioremap(dev->res.start, KMI_SIZE);
if (!kmi->base) { if (!kmi->base) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -154,13 +159,14 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) ...@@ -154,13 +159,14 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
kmi->irq = dev->irq[0]; kmi->irq = dev->irq[0];
amba_set_drvdata(dev, kmi); amba_set_drvdata(dev, kmi);
serio_register_port(&kmi->io); serio_register_port(kmi->io);
return 0; return 0;
unmap: unmap:
iounmap(kmi->base); iounmap(kmi->base);
out: out:
kfree(kmi); kfree(kmi);
kfree(io);
amba_release_regions(dev); amba_release_regions(dev);
return ret; return ret;
} }
...@@ -171,7 +177,7 @@ static int amba_kmi_remove(struct amba_device *dev) ...@@ -171,7 +177,7 @@ static int amba_kmi_remove(struct amba_device *dev)
amba_set_drvdata(dev, NULL); amba_set_drvdata(dev, NULL);
serio_unregister_port(&kmi->io); serio_unregister_port(kmi->io);
clk_put(kmi->clk); clk_put(kmi->clk);
iounmap(kmi->base); iounmap(kmi->base);
kfree(kmi); kfree(kmi);
...@@ -184,7 +190,7 @@ static int amba_kmi_resume(struct amba_device *dev) ...@@ -184,7 +190,7 @@ static int amba_kmi_resume(struct amba_device *dev)
struct amba_kmi_port *kmi = amba_get_drvdata(dev); struct amba_kmi_port *kmi = amba_get_drvdata(dev);
/* kick the serio layer to rescan this port */ /* kick the serio layer to rescan this port */
serio_rescan(&kmi->io); serio_reconnect(kmi->io);
return 0; return 0;
} }
...@@ -214,7 +220,7 @@ static int __init amba_kmi_init(void) ...@@ -214,7 +220,7 @@ static int __init amba_kmi_init(void)
static void __exit amba_kmi_exit(void) static void __exit amba_kmi_exit(void)
{ {
return amba_driver_unregister(&ambakmi_driver); amba_driver_unregister(&ambakmi_driver);
} }
module_init(amba_kmi_init); module_init(amba_kmi_init);
......
...@@ -43,9 +43,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); ...@@ -43,9 +43,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static char ct82c710_name[] = "C&T 82c710 mouse port";
static char ct82c710_phys[16];
/* /*
* ct82c710 interface * ct82c710 interface
*/ */
...@@ -61,10 +58,20 @@ static char ct82c710_phys[16]; ...@@ -61,10 +58,20 @@ static char ct82c710_phys[16];
#define CT82C710_IRQ 12 #define CT82C710_IRQ 12
static struct serio *ct82c710_port;
static int ct82c710_data; static int ct82c710_data;
static int ct82c710_status; static int ct82c710_status;
static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs);
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
{
return serio_interrupt(ct82c710_port, inb(ct82c710_data), 0, regs);
}
/* /*
* Wait for device to send output char and flush any input char. * Wait for device to send output char and flush any input char.
...@@ -139,26 +146,6 @@ static int ct82c710_write(struct serio *port, unsigned char c) ...@@ -139,26 +146,6 @@ static int ct82c710_write(struct serio *port, unsigned char c)
return 0; return 0;
} }
static struct serio ct82c710_port =
{
.type = SERIO_8042,
.name = ct82c710_name,
.phys = ct82c710_phys,
.write = ct82c710_write,
.open = ct82c710_open,
.close = ct82c710_close,
};
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
{
return serio_interrupt(&ct82c710_port, inb(ct82c710_data), 0, regs);
}
/* /*
* See if we can find a 82C710 device. Read mouse address. * See if we can find a 82C710 device. Read mouse address.
*/ */
...@@ -183,6 +170,24 @@ static int __init ct82c710_probe(void) ...@@ -183,6 +170,24 @@ static int __init ct82c710_probe(void)
return 0; return 0;
} }
static struct serio * __init ct82c710_allocate_port(void)
{
struct serio *serio;
serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
memset(serio, 0, sizeof(struct serio));
serio->type = SERIO_8042;
serio->open = ct82c710_open;
serio->close = ct82c710_close;
serio->write = ct82c710_write;
strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name));
snprintf(serio->phys, sizeof(serio->phys), "isa%04x/serio0", ct82c710_data);
}
return serio;
}
int __init ct82c710_init(void) int __init ct82c710_init(void)
{ {
if (ct82c710_probe()) if (ct82c710_probe())
...@@ -191,9 +196,12 @@ int __init ct82c710_init(void) ...@@ -191,9 +196,12 @@ int __init ct82c710_init(void)
if (request_region(ct82c710_data, 2, "ct82c710")) if (request_region(ct82c710_data, 2, "ct82c710"))
return -EBUSY; return -EBUSY;
sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); if (!(ct82c710_port = ct82c710_allocate_port())) {
release_region(ct82c710_data, 2);
return -ENOMEM;
}
serio_register_port(&ct82c710_port); serio_register_port(ct82c710_port);
printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n",
ct82c710_data, CT82C710_IRQ); ct82c710_data, CT82C710_IRQ);
...@@ -203,7 +211,7 @@ int __init ct82c710_init(void) ...@@ -203,7 +211,7 @@ int __init ct82c710_init(void)
void __exit ct82c710_exit(void) void __exit ct82c710_exit(void)
{ {
serio_unregister_port(&ct82c710_port); serio_unregister_port(ct82c710_port);
release_region(ct82c710_data, 2); release_region(ct82c710_data, 2);
} }
......
...@@ -91,7 +91,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); ...@@ -91,7 +91,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
struct gscps2port { struct gscps2port {
struct list_head node; struct list_head node;
struct parisc_device *padev; struct parisc_device *padev;
struct serio port; struct serio *port;
spinlock_t lock; spinlock_t lock;
char *addr; char *addr;
u8 act, append; /* position in buffer[] */ u8 act, append; /* position in buffer[] */
...@@ -100,7 +100,6 @@ struct gscps2port { ...@@ -100,7 +100,6 @@ struct gscps2port {
u8 str; u8 str;
} buffer[BUFFER_SIZE+1]; } buffer[BUFFER_SIZE+1];
int id; int id;
char name[32];
}; };
/* /*
...@@ -272,7 +271,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) ...@@ -272,7 +271,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 );
serio_interrupt(&ps2port->port, data, rxflags, regs); serio_interrupt(ps2port->port, data, rxflags, regs);
} /* while() */ } /* while() */
...@@ -288,7 +287,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) ...@@ -288,7 +287,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
static int gscps2_write(struct serio *port, unsigned char data) static int gscps2_write(struct serio *port, unsigned char data)
{ {
struct gscps2port *ps2port = port->driver; struct gscps2port *ps2port = port->port_data;
if (!gscps2_writeb_output(ps2port, data)) { if (!gscps2_writeb_output(ps2port, data)) {
printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data);
...@@ -304,7 +303,7 @@ static int gscps2_write(struct serio *port, unsigned char data) ...@@ -304,7 +303,7 @@ static int gscps2_write(struct serio *port, unsigned char data)
static int gscps2_open(struct serio *port) static int gscps2_open(struct serio *port)
{ {
struct gscps2port *ps2port = port->driver; struct gscps2port *ps2port = port->port_data;
gscps2_reset(ps2port); gscps2_reset(ps2port);
...@@ -319,7 +318,7 @@ static int gscps2_open(struct serio *port) ...@@ -319,7 +318,7 @@ static int gscps2_open(struct serio *port)
static void gscps2_close(struct serio *port) static void gscps2_close(struct serio *port)
{ {
struct gscps2port *ps2port = port->driver; struct gscps2port *ps2port = port->port_data;
gscps2_enable(ps2port, DISABLE); gscps2_enable(ps2port, DISABLE);
} }
...@@ -344,6 +343,7 @@ static struct serio gscps2_serio_port = ...@@ -344,6 +343,7 @@ static struct serio gscps2_serio_port =
static int __init gscps2_probe(struct parisc_device *dev) static int __init gscps2_probe(struct parisc_device *dev)
{ {
struct gscps2port *ps2port; struct gscps2port *ps2port;
struct serio *serio;
unsigned long hpa = dev->hpa; unsigned long hpa = dev->hpa;
int ret; int ret;
...@@ -355,34 +355,45 @@ static int __init gscps2_probe(struct parisc_device *dev) ...@@ -355,34 +355,45 @@ static int __init gscps2_probe(struct parisc_device *dev)
hpa += GSC_DINO_OFFSET; hpa += GSC_DINO_OFFSET;
ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL);
if (!ps2port) serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
return -ENOMEM; if (!ps2port || !serio) {
ret = -ENOMEM;
goto fail_nomem;
}
dev_set_drvdata(&dev->dev, ps2port); dev_set_drvdata(&dev->dev, ps2port);
memset(ps2port, 0, sizeof(struct gscps2port)); memset(ps2port, 0, sizeof(struct gscps2port));
memset(serio, 0, sizeof(struct serio));
ps2port->port = serio;
ps2port->padev = dev; ps2port->padev = dev;
ps2port->addr = ioremap(hpa, GSC_STATUS + 4); ps2port->addr = ioremap(hpa, GSC_STATUS + 4);
spin_lock_init(&ps2port->lock); spin_lock_init(&ps2port->lock);
gscps2_reset(ps2port); gscps2_reset(ps2port);
ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f;
snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s",
gscps2_serio_port.name, snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s",
(ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse");
strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); serio->idbus = BUS_GSC;
ps2port->port.driver = ps2port; serio->idvendor = PCI_VENDOR_ID_HP;
ps2port->port.name = ps2port->name; serio->idproduct = 0x0001;
ps2port->port.phys = dev->dev.bus_id; serio->idversion = 0x0010;
serio->type = SERIO_8042;
serio->write = gscps2_write;
serio->open = gscps2_open;
serio->close = gscps2_close;
serio->port_data = ps2port;
serio->dev.parent = &dev->dev;
list_add_tail(&ps2port->node, &ps2port_list); list_add_tail(&ps2port->node, &ps2port_list);
ret = -EBUSY; ret = -EBUSY;
if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port)) if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port))
goto fail_miserably; goto fail_miserably;
if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) { 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", printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n",
hpa, ps2port->id); hpa, ps2port->id);
ret = -ENODEV; ret = -ENODEV;
...@@ -395,12 +406,12 @@ static int __init gscps2_probe(struct parisc_device *dev) ...@@ -395,12 +406,12 @@ static int __init gscps2_probe(struct parisc_device *dev)
#endif #endif
printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n",
ps2port->name, ps2port->port->name,
ps2port->addr, ps2port->addr,
ps2port->padev->irq, ps2port->padev->irq,
ps2port->port.phys); ps2port->port->phys);
serio_register_port(&ps2port->port); serio_register_port(ps2port->port);
return 0; return 0;
...@@ -411,7 +422,10 @@ static int __init gscps2_probe(struct parisc_device *dev) ...@@ -411,7 +422,10 @@ static int __init gscps2_probe(struct parisc_device *dev)
list_del(&ps2port->node); list_del(&ps2port->node);
iounmap(ps2port->addr); iounmap(ps2port->addr);
release_mem_region(dev->hpa, GSC_STATUS + 4); release_mem_region(dev->hpa, GSC_STATUS + 4);
fail_nomem:
kfree(ps2port); kfree(ps2port);
kfree(serio);
return ret; return ret;
} }
...@@ -424,7 +438,7 @@ static int __devexit gscps2_remove(struct parisc_device *dev) ...@@ -424,7 +438,7 @@ static int __devexit gscps2_remove(struct parisc_device *dev)
{ {
struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); struct gscps2port *ps2port = dev_get_drvdata(&dev->dev);
serio_unregister_port(&ps2port->port); serio_unregister_port(ps2port->port);
free_irq(dev->irq, ps2port); free_irq(dev->irq, ps2port);
gscps2_flush(ps2port); gscps2_flush(ps2port);
list_del(&ps2port->node); list_del(&ps2port->node);
......
...@@ -65,6 +65,31 @@ static inline void i8042_write_command(int val) ...@@ -65,6 +65,31 @@ static inline void i8042_write_command(int val)
return; return;
} }
#if defined(__i386__)
#include <linux/dmi.h>
static struct dmi_system_id __initdata i8042_dmi_table[] = {
{
.ident = "Compaq Proliant 8500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
DMI_MATCH(DMI_PRODUCT_VERSION, "8500"),
},
},
{
.ident = "Compaq Proliant DL760",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
},
},
{ }
};
#endif
static inline int i8042_platform_init(void) static inline int i8042_platform_init(void)
{ {
/* /*
...@@ -79,6 +104,12 @@ static inline int i8042_platform_init(void) ...@@ -79,6 +104,12 @@ static inline int i8042_platform_init(void)
#if !defined(__i386__) && !defined(__x86_64__) #if !defined(__i386__) && !defined(__x86_64__)
i8042_reset = 1; i8042_reset = 1;
#endif #endif
#if defined(__i386__)
if (dmi_check_system(i8042_dmi_table))
i8042_noloop = 1;
#endif
return 0; return 0;
} }
......
/* /*
* 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,10 @@ static unsigned int i8042_dumbkbd; ...@@ -52,6 +52,10 @@ 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");
static unsigned int i8042_noloop;
module_param_named(noloop, i8042_noloop, bool, 0);
MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port");
__obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_noaux");
__obsolete_setup("i8042_nomux"); __obsolete_setup("i8042_nomux");
__obsolete_setup("i8042_unlock"); __obsolete_setup("i8042_unlock");
...@@ -70,19 +74,35 @@ struct i8042_values { ...@@ -70,19 +74,35 @@ struct i8042_values {
unsigned char irqen; unsigned char irqen;
unsigned char exists; unsigned char exists;
signed char mux; signed char mux;
unsigned char *name; char name[8];
unsigned char *phys; };
static struct i8042_values i8042_kbd_values = {
.disable = I8042_CTR_KBDDIS,
.irqen = I8042_CTR_KBDINT,
.mux = -1,
.name = "KBD",
};
static struct i8042_values i8042_aux_values = {
.disable = I8042_CTR_AUXDIS,
.irqen = I8042_CTR_AUXINT,
.mux = -1,
.name = "AUX",
}; };
static struct serio i8042_kbd_port; static struct i8042_values i8042_mux_values[I8042_NUM_MUX_PORTS];
static struct serio i8042_aux_port;
static struct serio *i8042_kbd_port;
static struct serio *i8042_aux_port;
static struct serio *i8042_mux_port[I8042_NUM_MUX_PORTS];
static unsigned char i8042_initial_ctr; static unsigned char i8042_initial_ctr;
static unsigned char i8042_ctr; static unsigned char i8042_ctr;
static unsigned char i8042_mux_open; static unsigned char i8042_mux_open;
static unsigned char i8042_mux_present; static unsigned char i8042_mux_present;
static unsigned char i8042_sysdev_initialized; static unsigned char i8042_sysdev_initialized;
static struct pm_dev *i8042_pm_dev; static struct pm_dev *i8042_pm_dev;
struct timer_list i8042_timer; static struct timer_list i8042_timer;
/* /*
* Shared IRQ's require a device pointer, but this driver doesn't support * Shared IRQ's require a device pointer, but this driver doesn't support
...@@ -95,6 +115,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); ...@@ -95,6 +115,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 +175,9 @@ static int i8042_command(unsigned char *param, int command) ...@@ -154,6 +175,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();
...@@ -214,7 +238,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c) ...@@ -214,7 +238,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c)
static int i8042_aux_write(struct serio *port, unsigned char c) static int i8042_aux_write(struct serio *port, unsigned char c)
{ {
struct i8042_values *values = port->driver; struct i8042_values *values = port->port_data;
int retval; int retval;
/* /*
...@@ -242,7 +266,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c) ...@@ -242,7 +266,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c)
static int i8042_activate_port(struct serio *port) static int i8042_activate_port(struct serio *port)
{ {
struct i8042_values *values = port->driver; struct i8042_values *values = port->port_data;
i8042_flush(); i8042_flush();
...@@ -270,7 +294,7 @@ static int i8042_activate_port(struct serio *port) ...@@ -270,7 +294,7 @@ static int i8042_activate_port(struct serio *port)
static int i8042_open(struct serio *port) static int i8042_open(struct serio *port)
{ {
struct i8042_values *values = port->driver; struct i8042_values *values = port->port_data;
if (values->mux != -1) if (values->mux != -1)
if (i8042_mux_open++) if (i8042_mux_open++)
...@@ -309,7 +333,7 @@ static int i8042_open(struct serio *port) ...@@ -309,7 +333,7 @@ static int i8042_open(struct serio *port)
static void i8042_close(struct serio *port) static void i8042_close(struct serio *port)
{ {
struct i8042_values *values = port->driver; struct i8042_values *values = port->port_data;
if (values->mux != -1) if (values->mux != -1)
if (--i8042_mux_open) if (--i8042_mux_open)
...@@ -327,52 +351,6 @@ static void i8042_close(struct serio *port) ...@@ -327,52 +351,6 @@ static void i8042_close(struct serio *port)
i8042_flush(); i8042_flush();
} }
/*
* Structures for registering the devices in the serio.c module.
*/
static struct i8042_values i8042_kbd_values = {
.irqen = I8042_CTR_KBDINT,
.disable = I8042_CTR_KBDDIS,
.name = "KBD",
.mux = -1,
};
static struct serio i8042_kbd_port =
{
.type = SERIO_8042_XL,
.write = i8042_kbd_write,
.open = i8042_open,
.close = i8042_close,
.driver = &i8042_kbd_values,
.name = "i8042 Kbd Port",
.phys = I8042_KBD_PHYS_DESC,
};
static struct i8042_values i8042_aux_values = {
.irqen = I8042_CTR_AUXINT,
.disable = I8042_CTR_AUXDIS,
.name = "AUX",
.mux = -1,
};
static struct serio i8042_aux_port =
{
.type = SERIO_8042,
.write = i8042_aux_write,
.open = i8042_open,
.close = i8042_close,
.driver = &i8042_aux_values,
.name = "i8042 Aux Port",
.phys = I8042_AUX_PHYS_DESC,
};
static struct i8042_values i8042_mux_values[4];
static struct serio i8042_mux_port[4];
static char i8042_mux_names[4][32];
static char i8042_mux_short[4][16];
static char i8042_mux_phys[4][32];
/* /*
* i8042_interrupt() is the most important function in this driver - * i8042_interrupt() is the most important function in this driver -
* it handles the interrupts from the i8042, and sends incoming bytes * it handles the interrupts from the i8042, and sends incoming bytes
...@@ -419,7 +397,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -419,7 +397,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : ""); dfl & SERIO_TIMEOUT ? ", timeout" : "");
serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); serio_interrupt(i8042_mux_port[(str >> 6) & 3], data, dfl, regs);
goto irq_ret; goto irq_ret;
} }
...@@ -430,14 +408,14 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -430,14 +408,14 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dfl & SERIO_TIMEOUT ? ", timeout" : ""); dfl & SERIO_TIMEOUT ? ", timeout" : "");
if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
serio_interrupt(&i8042_aux_port, data, dfl, regs); serio_interrupt(i8042_aux_port, data, dfl, regs);
goto irq_ret; goto irq_ret;
} }
if (!i8042_kbd_values.exists) if (!i8042_kbd_values.exists)
goto irq_ret; goto irq_ret;
serio_interrupt(&i8042_kbd_port, data, dfl, regs); serio_interrupt(i8042_kbd_port, data, dfl, regs);
irq_ret: irq_ret:
ret = 1; ret = 1;
...@@ -474,17 +452,8 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux ...@@ -474,17 +452,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;
...@@ -639,8 +608,10 @@ static int __init i8042_check_aux(struct i8042_values *values) ...@@ -639,8 +608,10 @@ static int __init i8042_check_aux(struct i8042_values *values)
* registers it, and reports to the user. * registers it, and reports to the user.
*/ */
static int __init i8042_port_register(struct i8042_values *values, struct serio *port) static int __init i8042_port_register(struct serio *port)
{ {
struct i8042_values *values = port->port_data;
values->exists = 1; values->exists = 1;
i8042_ctr &= ~values->disable; i8042_ctr &= ~values->disable;
...@@ -677,6 +648,7 @@ static void i8042_timer_func(unsigned long data) ...@@ -677,6 +648,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 +695,14 @@ static int i8042_controller_init(void) ...@@ -723,12 +695,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
...@@ -745,10 +719,8 @@ static int i8042_controller_init(void) ...@@ -745,10 +719,8 @@ static int i8042_controller_init(void)
* BIOSes. * BIOSes.
*/ */
if (i8042_direct) { if (i8042_direct)
i8042_ctr &= ~I8042_CTR_XLATE; i8042_ctr &= ~I8042_CTR_XLATE;
i8042_kbd_port.type = SERIO_8042;
}
/* /*
* Write CTR back. * Write CTR back.
...@@ -802,14 +774,14 @@ void i8042_controller_cleanup(void) ...@@ -802,14 +774,14 @@ void i8042_controller_cleanup(void)
*/ */
if (i8042_kbd_values.exists) if (i8042_kbd_values.exists)
serio_cleanup(&i8042_kbd_port); serio_cleanup(i8042_kbd_port);
if (i8042_aux_values.exists) if (i8042_aux_values.exists)
serio_cleanup(&i8042_aux_port); serio_cleanup(i8042_aux_port);
for (i = 0; i < 4; i++) for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
if (i8042_mux_values[i].exists) if (i8042_mux_values[i].exists)
serio_cleanup(i8042_mux_port + i); serio_cleanup(i8042_mux_port[i]);
i8042_controller_reset(); i8042_controller_reset();
} }
...@@ -851,15 +823,15 @@ static int i8042_controller_resume(void) ...@@ -851,15 +823,15 @@ static int i8042_controller_resume(void)
* Reconnect anything that was connected to the ports. * Reconnect anything that was connected to the ports.
*/ */
if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0) if (i8042_kbd_values.exists && i8042_activate_port(i8042_kbd_port) == 0)
serio_reconnect(&i8042_kbd_port); serio_reconnect(i8042_kbd_port);
if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0) if (i8042_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0)
serio_reconnect(&i8042_aux_port); serio_reconnect(i8042_aux_port);
for (i = 0; i < 4; i++) for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0) if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port[i]) == 0)
serio_reconnect(i8042_mux_port + i); serio_reconnect(i8042_mux_port[i]);
/* /*
* Restart timer (for polling "stuck" data) * Restart timer (for polling "stuck" data)
*/ */
...@@ -929,18 +901,66 @@ static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dum ...@@ -929,18 +901,66 @@ static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dum
return 0; return 0;
} }
static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index) static struct serio * __init i8042_allocate_kbd_port(void)
{
struct serio *serio;
serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
memset(serio, 0, sizeof(struct serio));
serio->type = i8042_direct ? SERIO_8042 : SERIO_8042_XL,
serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write,
serio->open = i8042_open,
serio->close = i8042_close,
serio->port_data = &i8042_kbd_values,
strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name));
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
}
return serio;
}
static struct serio * __init i8042_allocate_aux_port(void)
{
struct serio *serio;
serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
memset(serio, 0, sizeof(struct serio));
serio->type = SERIO_8042;
serio->write = i8042_aux_write;
serio->open = i8042_open;
serio->close = i8042_close;
serio->port_data = &i8042_aux_values,
strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name));
strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
}
return serio;
}
static struct serio * __init i8042_allocate_mux_port(int index)
{ {
memcpy(port, &i8042_aux_port, sizeof(struct serio)); struct serio *serio;
memcpy(values, &i8042_aux_values, sizeof(struct i8042_values)); struct i8042_values *values = &i8042_mux_values[index];
sprintf(i8042_mux_names[index], "i8042 Aux-%d Port", index);
sprintf(i8042_mux_phys[index], I8042_MUX_PHYS_DESC, index + 1); serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
sprintf(i8042_mux_short[index], "AUX%d", index); if (serio) {
port->name = i8042_mux_names[index]; *values = i8042_aux_values;
port->phys = i8042_mux_phys[index]; snprintf(values->name, sizeof(values->name), "AUX%d", index);
port->driver = values;
values->name = i8042_mux_short[index];
values->mux = index; values->mux = index;
memset(serio, 0, sizeof(struct serio));
serio->type = SERIO_8042;
serio->write = i8042_aux_write;
serio->open = i8042_open;
serio->close = i8042_close;
serio->port_data = values;
snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index);
snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1);
}
return serio;
} }
int __init i8042_init(void) int __init i8042_init(void)
...@@ -961,20 +981,23 @@ int __init i8042_init(void) ...@@ -961,20 +981,23 @@ int __init i8042_init(void)
if (i8042_controller_init()) if (i8042_controller_init())
return -ENODEV; return -ENODEV;
if (i8042_dumbkbd)
i8042_kbd_port.write = NULL;
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 < I8042_NUM_MUX_PORTS; i++) {
i8042_init_mux_values(i8042_mux_values + i, i8042_mux_port + i, i); i8042_mux_port[i] = i8042_allocate_mux_port(i);
i8042_port_register(i8042_mux_values + i, i8042_mux_port + i); if (i8042_mux_port[i])
i8042_port_register(i8042_mux_port[i]);
}
else {
i8042_aux_port = i8042_allocate_aux_port();
if (i8042_aux_port)
i8042_port_register(i8042_aux_port);
} }
else
i8042_port_register(&i8042_aux_values, &i8042_aux_port);
} }
i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); i8042_kbd_port = i8042_allocate_kbd_port();
if (i8042_kbd_port)
i8042_port_register(i8042_kbd_port);
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
...@@ -1009,14 +1032,15 @@ void __exit i8042_exit(void) ...@@ -1009,14 +1032,15 @@ void __exit i8042_exit(void)
i8042_controller_cleanup(); i8042_controller_cleanup();
if (i8042_kbd_values.exists) if (i8042_kbd_values.exists)
serio_unregister_port(&i8042_kbd_port); serio_unregister_port(i8042_kbd_port);
if (i8042_aux_values.exists) if (i8042_aux_values.exists)
serio_unregister_port(&i8042_aux_port); serio_unregister_port(i8042_aux_port);
for (i = 0; i < 4; i++) for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
if (i8042_mux_values[i].exists) if (i8042_mux_values[i].exists)
serio_unregister_port(i8042_mux_port + i); serio_unregister_port(i8042_mux_port[i]);
del_timer_sync(&i8042_timer); del_timer_sync(&i8042_timer);
i8042_platform_exit(); i8042_platform_exit();
......
...@@ -103,6 +103,13 @@ ...@@ -103,6 +103,13 @@
#define I8042_BUFFER_SIZE 32 #define I8042_BUFFER_SIZE 32
/*
* Number of AUX ports on controllers supporting active multiplexing
* specification
*/
#define I8042_NUM_MUX_PORTS 4
/* /*
* Debug. * Debug.
*/ */
......
...@@ -46,15 +46,17 @@ MODULE_LICENSE("GPL"); ...@@ -46,15 +46,17 @@ MODULE_LICENSE("GPL");
#define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ #define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */
#define PS2_CONTROL_RESET BIT(5) /* reset */ #define PS2_CONTROL_RESET BIT(5) /* reset */
struct maceps2_data { struct maceps2_data {
struct mace_ps2port *port; struct mace_ps2port *port;
int irq; int irq;
}; };
static struct maceps2_data port_data[2];
static struct serio *maceps2_port[2];
static int maceps2_write(struct serio *dev, unsigned char val) static int maceps2_write(struct serio *dev, unsigned char val)
{ {
struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port;
unsigned int timeout = MACE_PS2_TIMEOUT; unsigned int timeout = MACE_PS2_TIMEOUT;
do { do {
...@@ -68,11 +70,10 @@ static int maceps2_write(struct serio *dev, unsigned char val) ...@@ -68,11 +70,10 @@ static int maceps2_write(struct serio *dev, unsigned char val)
return -1; return -1;
} }
static irqreturn_t maceps2_interrupt(int irq, void *dev_id, static irqreturn_t maceps2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct serio *dev = dev_id; struct serio *dev = dev_id;
struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port;
unsigned int byte; unsigned int byte;
if (mace_read(port->status) & PS2_STATUS_RX_FULL) { if (mace_read(port->status) & PS2_STATUS_RX_FULL) {
...@@ -85,7 +86,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id, ...@@ -85,7 +86,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id,
static int maceps2_open(struct serio *dev) static int maceps2_open(struct serio *dev)
{ {
struct maceps2_data *data = (struct maceps2_data *)dev->driver; struct maceps2_data *data = (struct maceps2_data *)dev->port_data;
if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) {
printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); printk(KERN_ERR "Could not allocate PS/2 IRQ\n");
...@@ -106,7 +107,7 @@ static int maceps2_open(struct serio *dev) ...@@ -106,7 +107,7 @@ static int maceps2_open(struct serio *dev)
static void maceps2_close(struct serio *dev) static void maceps2_close(struct serio *dev)
{ {
struct maceps2_data *data = (struct maceps2_data *)dev->driver; struct maceps2_data *data = (struct maceps2_data *)dev->port_data;
mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET,
data->port->control); data->port->control);
...@@ -114,46 +115,52 @@ static void maceps2_close(struct serio *dev) ...@@ -114,46 +115,52 @@ static void maceps2_close(struct serio *dev)
free_irq(data->irq, dev); free_irq(data->irq, dev);
} }
static struct maceps2_data port0_data, port1_data;
static struct serio maceps2_port0 = static struct serio * __init maceps2_allocate_port(int idx)
{ {
.type = SERIO_8042, struct serio *serio;
.open = maceps2_open,
.close = maceps2_close, serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
.write = maceps2_write, if (serio) {
.name = "MACE PS/2 port0", memset(serio, 0, sizeof(struct serio));
.phys = "mace/serio0", serio->type = SERIO_8042;
.driver = &port0_data, serio->write = maceps2_write;
}; serio->open = maceps2_open;
serio->close = maceps2_close;
snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx);
snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx);
serio->port_data = &port_data[idx];
}
return serio;
}
static struct serio maceps2_port1 =
{
.type = SERIO_8042,
.open = maceps2_open,
.close = maceps2_close,
.write = maceps2_write,
.name = "MACE PS/2 port1",
.phys = "mace/serio1",
.driver = &port1_data,
};
static int __init maceps2_init(void) static int __init maceps2_init(void)
{ {
port0_data.port = &mace->perif.ps2.keyb; port_data[0].port = &mace->perif.ps2.keyb;
port0_data.irq = MACEISA_KEYB_IRQ; port_data[0].irq = MACEISA_KEYB_IRQ;
port1_data.port = &mace->perif.ps2.mouse; port_data[1].port = &mace->perif.ps2.mouse;
port1_data.irq = MACEISA_MOUSE_IRQ; port_data[1].irq = MACEISA_MOUSE_IRQ;
serio_register_port(&maceps2_port0);
serio_register_port(&maceps2_port1); maceps2_port[0] = maceps2_allocate_port(0);
maceps2_port[1] = maceps2_allocate_port(1);
if (!maceps2_port[0] || !maceps2_port[1]) {
kfree(maceps2_port[0]);
kfree(maceps2_port[1]);
return -ENOMEM;
}
serio_register_port(maceps2_port[0]);
serio_register_port(maceps2_port[1]);
return 0; return 0;
} }
static void __exit maceps2_exit(void) static void __exit maceps2_exit(void)
{ {
serio_unregister_port(&maceps2_port0); serio_unregister_port(maceps2_port[0]);
serio_unregister_port(&maceps2_port1); serio_unregister_port(maceps2_port[1]);
} }
module_init(maceps2_init); module_init(maceps2_init);
......
...@@ -53,9 +53,7 @@ static int parkbd_writing; ...@@ -53,9 +53,7 @@ static int parkbd_writing;
static unsigned long parkbd_start; static unsigned long parkbd_start;
static struct pardevice *parkbd_dev; static struct pardevice *parkbd_dev;
static struct serio *parkbd_port;
static char parkbd_name[] = "PARKBD AT/XT keyboard adapter";
static char parkbd_phys[32];
static int parkbd_readlines(void) static int parkbd_readlines(void)
{ {
...@@ -86,13 +84,6 @@ static int parkbd_write(struct serio *port, unsigned char c) ...@@ -86,13 +84,6 @@ static int parkbd_write(struct serio *port, unsigned char c)
return 0; return 0;
} }
static struct serio parkbd_port =
{
.write = parkbd_write,
.name = parkbd_name,
.phys = parkbd_phys,
};
static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
...@@ -125,7 +116,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -125,7 +116,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
if (parkbd_counter == parkbd_mode + 10) if (parkbd_counter == parkbd_mode + 10)
serio_interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs);
} }
parkbd_last = jiffies; parkbd_last = jiffies;
...@@ -163,16 +154,38 @@ static int parkbd_getport(void) ...@@ -163,16 +154,38 @@ static int parkbd_getport(void)
return 0; return 0;
} }
static struct serio * __init parkbd_allocate_serio(void)
{
struct serio *serio;
serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
serio->type = parkbd_mode;
serio->write = parkbd_write,
strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name));
snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name);
}
return serio;
}
int __init parkbd_init(void) int __init parkbd_init(void)
{ {
if (parkbd_getport()) return -1; int err;
parkbd_writelines(3);
parkbd_port.type = parkbd_mode; err = parkbd_getport();
if (err)
return err;
parkbd_port = parkbd_allocate_serio();
if (!parkbd_port) {
parport_release(parkbd_dev);
return -ENOMEM;
}
sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name); parkbd_writelines(3);
serio_register_port(&parkbd_port); serio_register_port(parkbd_port);
printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", printk(KERN_INFO "serio: PARKBD %s adapter on %s\n",
parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); parkbd_mode ? "AT" : "XT", parkbd_dev->port->name);
...@@ -183,7 +196,7 @@ int __init parkbd_init(void) ...@@ -183,7 +196,7 @@ int __init parkbd_init(void)
void __exit parkbd_exit(void) void __exit parkbd_exit(void)
{ {
parport_release(parkbd_dev); parport_release(parkbd_dev);
serio_unregister_port(&parkbd_port); serio_unregister_port(parkbd_port);
parport_unregister_device(parkbd_dev); parport_unregister_device(parkbd_dev);
} }
......
...@@ -38,14 +38,14 @@ ...@@ -38,14 +38,14 @@
#define PS2_STAT_TXEMPTY (1<<7) #define PS2_STAT_TXEMPTY (1<<7)
struct pcips2_data { struct pcips2_data {
struct serio io; struct serio *io;
unsigned int base; unsigned int base;
struct pci_dev *dev; struct pci_dev *dev;
}; };
static int pcips2_write(struct serio *io, unsigned char val) static int pcips2_write(struct serio *io, unsigned char val)
{ {
struct pcips2_data *ps2if = io->driver; struct pcips2_data *ps2if = io->port_data;
unsigned int stat; unsigned int stat;
do { do {
...@@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs) ...@@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs)
if (hweight8(scancode) & 1) if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY; flag ^= SERIO_PARITY;
serio_interrupt(&ps2if->io, scancode, flag, regs); serio_interrupt(ps2if->io, scancode, flag, regs);
} while (1); } while (1);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
...@@ -101,7 +101,7 @@ static void pcips2_flush_input(struct pcips2_data *ps2if) ...@@ -101,7 +101,7 @@ static void pcips2_flush_input(struct pcips2_data *ps2if)
static int pcips2_open(struct serio *io) static int pcips2_open(struct serio *io)
{ {
struct pcips2_data *ps2if = io->driver; struct pcips2_data *ps2if = io->port_data;
int ret, val = 0; int ret, val = 0;
outb(PS2_CTRL_ENABLE, ps2if->base); outb(PS2_CTRL_ENABLE, ps2if->base);
...@@ -119,7 +119,7 @@ static int pcips2_open(struct serio *io) ...@@ -119,7 +119,7 @@ static int pcips2_open(struct serio *io)
static void pcips2_close(struct serio *io) static void pcips2_close(struct serio *io)
{ {
struct pcips2_data *ps2if = io->driver; struct pcips2_data *ps2if = io->port_data;
outb(0, ps2if->base); outb(0, ps2if->base);
...@@ -129,6 +129,7 @@ static void pcips2_close(struct serio *io) ...@@ -129,6 +129,7 @@ static void pcips2_close(struct serio *io)
static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
struct pcips2_data *ps2if; struct pcips2_data *ps2if;
struct serio *serio;
int ret; int ret;
ret = pci_enable_device(dev); ret = pci_enable_device(dev);
...@@ -142,29 +143,35 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i ...@@ -142,29 +143,35 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i
} }
ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL);
if (!ps2if) { serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (!ps2if || !serio) {
ret = -ENOMEM; ret = -ENOMEM;
goto release; goto release;
} }
memset(ps2if, 0, sizeof(struct pcips2_data)); memset(ps2if, 0, sizeof(struct pcips2_data));
memset(serio, 0, sizeof(struct serio));
ps2if->io.type = SERIO_8042;
ps2if->io.write = pcips2_write; serio->type = SERIO_8042;
ps2if->io.open = pcips2_open; serio->write = pcips2_write;
ps2if->io.close = pcips2_close; serio->open = pcips2_open;
ps2if->io.name = pci_name(dev); serio->close = pcips2_close;
ps2if->io.phys = dev->dev.bus_id; strlcpy(serio->name, pci_name(dev), sizeof(serio->name));
ps2if->io.driver = ps2if; strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
serio->port_data = ps2if;
serio->dev.parent = &dev->dev;
ps2if->io = serio;
ps2if->dev = dev; ps2if->dev = dev;
ps2if->base = pci_resource_start(dev, 0); ps2if->base = pci_resource_start(dev, 0);
pci_set_drvdata(dev, ps2if); pci_set_drvdata(dev, ps2if);
serio_register_port(&ps2if->io); serio_register_port(ps2if->io);
return 0; return 0;
release: release:
kfree(ps2if);
kfree(serio);
release_region(pci_resource_start(dev, 0), release_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0)); pci_resource_len(dev, 0));
disable: disable:
...@@ -176,7 +183,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev) ...@@ -176,7 +183,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev)
{ {
struct pcips2_data *ps2if = pci_get_drvdata(dev); struct pcips2_data *ps2if = pci_get_drvdata(dev);
serio_unregister_port(&ps2if->io); serio_unregister_port(ps2if->io);
release_region(pci_resource_start(dev, 0), release_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0)); pci_resource_len(dev, 0));
pci_set_drvdata(dev, NULL); pci_set_drvdata(dev, NULL);
......
...@@ -47,43 +47,98 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); ...@@ -47,43 +47,98 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static struct serio q40kbd_port = spinlock_t q40kbd_lock = SPIN_LOCK_UNLOCKED;
{ static struct serio *q40kbd_port;
.type = SERIO_8042,
.name = "Q40 kbd port", static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
.phys = "Q40",
.write = NULL,
};
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{ {
unsigned long flags;
spin_lock_irqsave(&q40kbd_lock, flags);
if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
serio_interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0, regs); serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs);
master_outb(-1, KEYBOARD_UNLOCK_REG); master_outb(-1, KEYBOARD_UNLOCK_REG);
spin_unlock_irqrestore(&q40kbd_lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int __init q40kbd_init(void) /*
* q40kbd_flush() flushes all data that may be in the keyboard buffers
*/
static void q40kbd_flush(void)
{ {
int maxread = 100; int maxread = 100;
unsigned long flags;
if (!MACH_IS_Q40) spin_lock_irqsave(&q40kbd_lock, flags);
return -EIO;
/* allocate the IRQ */
request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL);
/* flush any pending input */
while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
master_inb(KEYCODE_REG); master_inb(KEYCODE_REG);
spin_unlock_irqrestore(&q40kbd_lock, flags);
}
/*
* q40kbd_open() is called when a port is open by the higher layer.
* It allocates the interrupt and enables in in the chip.
*/
static int q40kbd_open(struct serio *port)
{
q40kbd_flush();
if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) {
printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
return -1;
}
/* off we go */ /* off we go */
master_outb(-1,KEYBOARD_UNLOCK_REG); master_outb(-1, KEYBOARD_UNLOCK_REG);
master_outb(1,KEY_IRQ_ENABLE_REG); master_outb(1, KEY_IRQ_ENABLE_REG);
return 0;
}
serio_register_port(&q40kbd_port); static void q40kbd_close(struct serio *port)
{
master_outb(0, KEY_IRQ_ENABLE_REG);
master_outb(-1, KEYBOARD_UNLOCK_REG);
free_irq(Q40_IRQ_KEYBOARD, NULL);
q40kbd_flush();
}
static struct serio * __init q40kbd_allocate_port(void)
{
struct serio *serio;
serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
memset(serio, 0, sizeof(struct serio));
serio->type = SERIO_8042;
serio->open = q40kbd_open;
serio->close = q40kbd_close;
strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name));
strlcpy(serio->phys, "Q40", sizeof(serio->phys));
}
return serio;
}
static int __init q40kbd_init(void)
{
if (!MACH_IS_Q40)
return -EIO;
if (!(q40kbd_port = q40kbd_allocate_port()))
return -ENOMEM;
serio_register_port(q40kbd_port);
printk(KERN_INFO "serio: Q40 kbd registered\n"); printk(KERN_INFO "serio: Q40 kbd registered\n");
return 0; return 0;
...@@ -91,11 +146,7 @@ static int __init q40kbd_init(void) ...@@ -91,11 +146,7 @@ static int __init q40kbd_init(void)
static void __exit q40kbd_exit(void) static void __exit q40kbd_exit(void)
{ {
master_outb(0,KEY_IRQ_ENABLE_REG); serio_unregister_port(q40kbd_port);
master_outb(-1,KEYBOARD_UNLOCK_REG);
serio_unregister_port(&q40kbd_port);
free_irq(Q40_IRQ_KEYBOARD, NULL);
} }
module_init(q40kbd_init); module_init(q40kbd_init);
......
...@@ -44,6 +44,8 @@ MODULE_AUTHOR("Vojtech Pavlik, Russell King"); ...@@ -44,6 +44,8 @@ MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static struct serio *rpckbd_port;
static int rpckbd_write(struct serio *port, unsigned char val) static int rpckbd_write(struct serio *port, unsigned char val)
{ {
while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
...@@ -101,25 +103,41 @@ static void rpckbd_close(struct serio *port) ...@@ -101,25 +103,41 @@ static void rpckbd_close(struct serio *port)
free_irq(IRQ_KEYBOARDTX, port); free_irq(IRQ_KEYBOARDTX, port);
} }
static struct serio rpckbd_port = /*
* Allocate and initialize serio structure for subsequent registration
* with serio core.
*/
static struct serio * __init rpckbd_allocate_port(void)
{ {
.type = SERIO_8042, struct serio *serio;
.open = rpckbd_open,
.close = rpckbd_close, serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
.write = rpckbd_write, if (serio) {
.name = "RiscPC PS/2 kbd port", memset(serio, 0, sizeof(struct serio));
.phys = "rpckbd/serio0", serio->type = SERIO_8042;
}; serio->write = rpckbd_write;
serio->open = rpckbd_open;
serio->close = rpckbd_close;
strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
}
return serio;
}
static int __init rpckbd_init(void) static int __init rpckbd_init(void)
{ {
serio_register_port(&rpckbd_port); if (!(rpckbd_port = rpckbd_allocate_port()))
return -ENOMEM;
serio_register_port(rpckbd_port);
return 0; return 0;
} }
static void __exit rpckbd_exit(void) static void __exit rpckbd_exit(void)
{ {
serio_unregister_port(&rpckbd_port); serio_unregister_port(rpckbd_port);
} }
module_init(rpckbd_init); module_init(rpckbd_init);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
struct ps2if { struct ps2if {
struct serio io; struct serio *io;
struct sa1111_dev *dev; struct sa1111_dev *dev;
unsigned long base; unsigned long base;
unsigned int open; unsigned int open;
...@@ -59,7 +59,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) ...@@ -59,7 +59,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
if (hweight8(scancode) & 1) if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY; flag ^= SERIO_PARITY;
serio_interrupt(&ps2if->io, scancode, flag, regs); serio_interrupt(ps2if->io, scancode, flag, regs);
status = sa1111_readl(ps2if->base + SA1111_PS2STAT); status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
} }
...@@ -95,7 +95,7 @@ static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs) ...@@ -95,7 +95,7 @@ static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
*/ */
static int ps2_write(struct serio *io, unsigned char val) static int ps2_write(struct serio *io, unsigned char val)
{ {
struct ps2if *ps2if = io->driver; struct ps2if *ps2if = io->port_data;
unsigned long flags; unsigned long flags;
unsigned int head; unsigned int head;
...@@ -122,7 +122,7 @@ static int ps2_write(struct serio *io, unsigned char val) ...@@ -122,7 +122,7 @@ static int ps2_write(struct serio *io, unsigned char val)
static int ps2_open(struct serio *io) static int ps2_open(struct serio *io)
{ {
struct ps2if *ps2if = io->driver; struct ps2if *ps2if = io->port_data;
int ret; int ret;
sa1111_enable_device(ps2if->dev); sa1111_enable_device(ps2if->dev);
...@@ -154,7 +154,7 @@ static int ps2_open(struct serio *io) ...@@ -154,7 +154,7 @@ static int ps2_open(struct serio *io)
static void ps2_close(struct serio *io) static void ps2_close(struct serio *io)
{ {
struct ps2if *ps2if = io->driver; struct ps2if *ps2if = io->port_data;
sa1111_writel(0, ps2if->base + SA1111_PS2CR); sa1111_writel(0, ps2if->base + SA1111_PS2CR);
...@@ -232,22 +232,28 @@ static int __init ps2_test(struct ps2if *ps2if) ...@@ -232,22 +232,28 @@ static int __init ps2_test(struct ps2if *ps2if)
static int ps2_probe(struct sa1111_dev *dev) static int ps2_probe(struct sa1111_dev *dev)
{ {
struct ps2if *ps2if; struct ps2if *ps2if;
struct serio *serio;
int ret; int ret;
ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
if (!ps2if) { serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
return -ENOMEM; if (!ps2if || !serio) {
ret = -ENOMEM;
goto free;
} }
memset(ps2if, 0, sizeof(struct ps2if)); memset(ps2if, 0, sizeof(struct ps2if));
memset(serio, 0, sizeof(struct serio));
ps2if->io.type = SERIO_8042;
ps2if->io.write = ps2_write; serio->type = SERIO_8042;
ps2if->io.open = ps2_open; serio->write = ps2_write;
ps2if->io.close = ps2_close; serio->open = ps2_open;
ps2if->io.name = dev->dev.bus_id; serio->close = ps2_close;
ps2if->io.phys = dev->dev.bus_id; strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name));
ps2if->io.driver = ps2if; strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
serio->port_data = ps2if;
serio->dev.parent = &dev->dev;
ps2if->io = serio;
ps2if->dev = dev; ps2if->dev = dev;
sa1111_set_drvdata(dev, ps2if); sa1111_set_drvdata(dev, ps2if);
...@@ -292,7 +298,7 @@ static int ps2_probe(struct sa1111_dev *dev) ...@@ -292,7 +298,7 @@ static int ps2_probe(struct sa1111_dev *dev)
ps2_clear_input(ps2if); ps2_clear_input(ps2if);
sa1111_disable_device(ps2if->dev); sa1111_disable_device(ps2if->dev);
serio_register_port(&ps2if->io); serio_register_port(ps2if->io);
return 0; return 0;
out: out:
...@@ -302,6 +308,7 @@ static int ps2_probe(struct sa1111_dev *dev) ...@@ -302,6 +308,7 @@ static int ps2_probe(struct sa1111_dev *dev)
free: free:
sa1111_set_drvdata(dev, NULL); sa1111_set_drvdata(dev, NULL);
kfree(ps2if); kfree(ps2if);
kfree(serio);
return ret; return ret;
} }
...@@ -312,7 +319,7 @@ static int ps2_remove(struct sa1111_dev *dev) ...@@ -312,7 +319,7 @@ static int ps2_remove(struct sa1111_dev *dev)
{ {
struct ps2if *ps2if = sa1111_get_drvdata(dev); struct ps2if *ps2if = sa1111_get_drvdata(dev);
serio_unregister_port(&ps2if->io); serio_unregister_port(ps2if->io);
release_mem_region(dev->res.start, release_mem_region(dev->res.start,
dev->res.end - dev->res.start + 1); dev->res.end - dev->res.start + 1);
sa1111_set_drvdata(dev, NULL); sa1111_set_drvdata(dev, NULL);
......
/*
* $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>
...@@ -50,100 +44,178 @@ MODULE_LICENSE("GPL"); ...@@ -50,100 +44,178 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(serio_register_port); EXPORT_SYMBOL(serio_register_port);
EXPORT_SYMBOL(serio_register_port_delayed); EXPORT_SYMBOL(serio_register_port_delayed);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_port_delayed); EXPORT_SYMBOL(serio_unregister_port_delayed);
EXPORT_SYMBOL(__serio_unregister_port); EXPORT_SYMBOL(serio_register_driver);
EXPORT_SYMBOL(serio_register_device); EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_close);
EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_rescan);
EXPORT_SYMBOL(serio_reconnect); EXPORT_SYMBOL(serio_reconnect);
static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_diriver_list */
static LIST_HEAD(serio_list);
static LIST_HEAD(serio_driver_list);
static unsigned int serio_no;
struct bus_type serio_bus = {
.name = "serio",
};
static void serio_find_driver(struct serio *serio);
static void serio_create_port(struct serio *serio);
static void serio_destroy_port(struct serio *serio);
static void serio_connect_port(struct serio *serio, struct serio_driver *drv);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
{
get_driver(&drv->driver);
drv->connect(serio, drv);
if (serio->drv) {
down_write(&serio_bus.subsys.rwsem);
serio->dev.driver = &drv->driver;
device_bind_driver(&serio->dev);
up_write(&serio_bus.subsys.rwsem);
return 1;
}
put_driver(&drv->driver);
return 0;
}
/* serio_find_driver() must be called with serio_sem down. */
static void serio_find_driver(struct serio *serio)
{
struct serio_driver *drv;
list_for_each_entry(drv, &serio_driver_list, node)
if (!drv->manual_bind)
if (serio_bind_driver(serio, drv))
break;
}
/*
* Serio event processing.
*/
struct serio_event { struct serio_event {
int type; int type;
struct serio *serio; struct serio *serio;
struct list_head node; struct list_head node;
}; };
static DECLARE_MUTEX(serio_sem); enum serio_event_type {
static LIST_HEAD(serio_list); SERIO_RESCAN,
static LIST_HEAD(serio_dev_list); 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 LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited);
static int serio_pid; static int serio_pid;
static void serio_find_dev(struct serio *serio) static void serio_queue_event(struct serio *serio, int event_type)
{ {
struct serio_dev *dev; unsigned long flags;
struct serio_event *event;
list_for_each_entry(dev, &serio_dev_list, node) { spin_lock_irqsave(&serio_event_lock, flags);
if (serio->dev)
break; if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
if (dev->connect) event->type = event_type;
dev->connect(serio, dev); event->serio = serio;
}
}
#define SERIO_RESCAN 1 list_add_tail(&event->node, &serio_event_list);
#define SERIO_RECONNECT 2 wake_up(&serio_wait);
#define SERIO_REGISTER_PORT 3 }
#define SERIO_UNREGISTER_PORT 4
static DECLARE_WAIT_QUEUE_HEAD(serio_wait); spin_unlock_irqrestore(&serio_event_lock, flags);
static DECLARE_COMPLETION(serio_exited); }
static void serio_invalidate_pending_events(struct serio *serio) static struct serio_event *serio_get_event(void)
{ {
struct serio_event *event; struct serio_event *event;
struct list_head *node;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
list_for_each_entry(event, &serio_event_list, node) if (list_empty(&serio_event_list)) {
if (event->serio == serio) spin_unlock_irqrestore(&serio_event_lock, flags);
event->serio = NULL; return NULL;
}
node = serio_event_list.next;
event = container_of(node, struct serio_event, node);
list_del_init(node);
spin_unlock_irqrestore(&serio_event_lock, flags);
return event;
} }
void serio_handle_events(void) static void serio_handle_events(void)
{ {
struct list_head *node, *next;
struct serio_event *event; struct serio_event *event;
list_for_each_safe(node, next, &serio_event_list) { while ((event = serio_get_event())) {
event = container_of(node, struct serio_event, node);
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 :
__serio_register_port(event->serio); serio_create_port(event->serio);
serio_connect_port(event->serio, NULL);
break; break;
case SERIO_UNREGISTER_PORT : case SERIO_UNREGISTER_PORT :
__serio_unregister_port(event->serio); serio_disconnect_port(event->serio);
serio_destroy_port(event->serio);
break; break;
case SERIO_RECONNECT : case SERIO_RECONNECT :
if (event->serio->dev && event->serio->dev->reconnect) serio_reconnect_port(event->serio);
if (event->serio->dev->reconnect(event->serio) == 0)
break; break;
/* reconnect failed - fall through to rescan */
case SERIO_RESCAN : case SERIO_RESCAN :
if (event->serio->dev && event->serio->dev->disconnect) serio_disconnect_port(event->serio);
event->serio->dev->disconnect(event->serio); serio_connect_port(event->serio, NULL);
serio_find_dev(event->serio);
break; break;
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,52 +235,211 @@ static int serio_thread(void *nothing) ...@@ -163,52 +235,211 @@ 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)
/*
* Serio port operations
*/
static ssize_t serio_show_description(struct device *dev, char *buf)
{ {
struct serio_event *event; struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%s\n", serio->name);
}
static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL);
if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { static ssize_t serio_show_driver(struct device *dev, char *buf)
event->type = event_type; {
event->serio = serio; return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)");
}
list_add_tail(&event->node, &serio_event_list); static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
wake_up(&serio_wait); {
struct serio *serio = to_serio_port(dev);
struct device_driver *drv;
struct kobject *k;
int retval;
retval = down_interruptible(&serio_sem);
if (retval)
return retval;
retval = count;
if (!strncmp(buf, "none", count)) {
serio_disconnect_port(serio);
} else if (!strncmp(buf, "reconnect", count)) {
serio_reconnect_port(serio);
} else if (!strncmp(buf, "rescan", count)) {
serio_disconnect_port(serio);
serio_connect_port(serio, NULL);
} else if ((k = kset_find_obj(&serio_bus.drivers, buf)) != NULL) {
drv = container_of(k, struct device_driver, kobj);
serio_disconnect_port(serio);
serio_connect_port(serio, to_serio_driver(drv));
} else {
retval = -EINVAL;
} }
up(&serio_sem);
return retval;
} }
static DEVICE_ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver);
void serio_rescan(struct serio *serio) static void serio_release_port(struct device *dev)
{ {
serio_queue_event(serio, SERIO_RESCAN); struct serio *serio = to_serio_port(dev);
kfree(serio);
module_put(THIS_MODULE);
} }
void serio_reconnect(struct serio *serio) static void serio_create_port(struct serio *serio)
{ {
serio_queue_event(serio, SERIO_RECONNECT); try_module_get(THIS_MODULE);
spin_lock_init(&serio->lock);
list_add_tail(&serio->node, &serio_list);
snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++);
serio->dev.bus = &serio_bus;
serio->dev.release = serio_release_port;
if (serio->parent)
serio->dev.parent = &serio->parent->dev;
device_register(&serio->dev);
device_create_file(&serio->dev, &dev_attr_description);
device_create_file(&serio->dev, &dev_attr_driver);
} }
irqreturn_t serio_interrupt(struct serio *serio, /*
unsigned char data, unsigned int flags, struct pt_regs *regs) * serio_destroy_port() completes deregistration process and removes
* port from the system
*/
static void serio_destroy_port(struct serio *serio)
{ {
irqreturn_t ret = IRQ_NONE; struct serio_driver *drv = serio->drv;
unsigned long flags;
if (serio->dev && serio->dev->interrupt) { serio_remove_pending_events(serio);
ret = serio->dev->interrupt(serio, data, flags, regs); list_del_init(&serio->node);
} else {
if (!flags) { if (drv) {
if ((serio->type == SERIO_8042 || drv->disconnect(serio);
serio->type == SERIO_8042_XL) && (data != 0xaa)) down_write(&serio_bus.subsys.rwsem);
return ret; device_release_driver(&serio->dev);
serio_rescan(serio); up_write(&serio_bus.subsys.rwsem);
ret = IRQ_HANDLED; put_driver(&drv->driver);
} }
if (serio->parent) {
spin_lock_irqsave(&serio->parent->lock, flags);
serio->parent->child = NULL;
spin_unlock_irqrestore(&serio->parent->lock, flags);
} }
return ret;
device_unregister(&serio->dev);
}
/*
* serio_connect_port() tries to bind the port and possible all its
* children to appropriate drivers. If driver passed in the function will not
* try otehr drivers when binding parent port.
*/
static void serio_connect_port(struct serio *serio, struct serio_driver *drv)
{
WARN_ON(serio->drv);
WARN_ON(serio->child);
if (drv)
serio_bind_driver(serio, drv);
else
serio_find_driver(serio);
/* Ok, now bind children, if any */
while (serio->child) {
serio = serio->child;
WARN_ON(serio->drv);
WARN_ON(serio->child);
serio_create_port(serio);
/*
* With children we just _prefer_ passed in driver,
* but we will try other options in case preferred
* is not the one
*/
if (!drv || !serio_bind_driver(serio, drv))
serio_find_driver(serio);
}
}
/*
*
*/
static void serio_reconnect_port(struct serio *serio)
{
do {
if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
serio_disconnect_port(serio);
serio_connect_port(serio, NULL);
/* Ok, old children are now gone, we are done */
break;
}
serio = serio->child;
} while (serio);
}
/*
* serio_disconnect_port() unbinds a port from its driver. As a side effect
* all child ports are unbound and destroyed.
*/
static void serio_disconnect_port(struct serio *serio)
{
struct serio_driver *drv = serio->drv;
struct serio *s;
if (serio->child) {
/*
* Children ports should be disconnected and destroyed
* first, staring with the leaf one, since we don't want
* to do recursion
*/
do {
s = serio->child;
} while (s->child);
while (s != serio) {
s = s->parent;
serio_destroy_port(s->child);
}
}
/*
* Ok, no children left, now disconnect this port
*/
if (drv) {
drv->disconnect(serio);
down_write(&serio_bus.subsys.rwsem);
device_release_driver(&serio->dev);
up_write(&serio_bus.subsys.rwsem);
put_driver(&drv->driver);
}
}
void serio_rescan(struct serio *serio)
{
serio_queue_event(serio, SERIO_RESCAN);
}
void serio_reconnect(struct serio *serio)
{
serio_queue_event(serio, SERIO_RECONNECT);
} }
void serio_register_port(struct serio *serio) void serio_register_port(struct serio *serio)
{ {
down(&serio_sem); down(&serio_sem);
__serio_register_port(serio); serio_create_port(serio);
serio_connect_port(serio, NULL);
up(&serio_sem); up(&serio_sem);
} }
...@@ -222,21 +453,11 @@ void serio_register_port_delayed(struct serio *serio) ...@@ -222,21 +453,11 @@ void serio_register_port_delayed(struct serio *serio)
serio_queue_event(serio, SERIO_REGISTER_PORT); serio_queue_event(serio, SERIO_REGISTER_PORT);
} }
/*
* Should only be called directly if serio_sem has already been taken,
* for example when unregistering a serio from other input device's
* connect() function.
*/
void __serio_register_port(struct serio *serio)
{
list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio);
}
void serio_unregister_port(struct serio *serio) void serio_unregister_port(struct serio *serio)
{ {
down(&serio_sem); down(&serio_sem);
__serio_unregister_port(serio); serio_disconnect_port(serio);
serio_destroy_port(serio);
up(&serio_sem); up(&serio_sem);
} }
...@@ -250,82 +471,142 @@ void serio_unregister_port_delayed(struct serio *serio) ...@@ -250,82 +471,142 @@ void serio_unregister_port_delayed(struct serio *serio)
serio_queue_event(serio, SERIO_UNREGISTER_PORT); serio_queue_event(serio, SERIO_UNREGISTER_PORT);
} }
/* /*
* Should only be called directly if serio_sem has already been taken, * Serio driver operations
* for example when unregistering a serio from other input device's
* disconnect() function.
*/ */
void __serio_unregister_port(struct serio *serio)
static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf)
{ {
serio_invalidate_pending_events(serio); struct serio_driver *driver = to_serio_driver(drv);
list_del_init(&serio->node); return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
} }
static DRIVER_ATTR(description, S_IRUGO, serio_driver_show_description, NULL);
void serio_register_device(struct serio_dev *dev) void serio_register_driver(struct serio_driver *drv)
{ {
struct serio *serio; struct serio *serio;
down(&serio_sem); down(&serio_sem);
list_add_tail(&dev->node, &serio_dev_list);
list_for_each_entry(serio, &serio_list, node) list_add_tail(&drv->node, &serio_driver_list);
if (!serio->dev && dev->connect)
dev->connect(serio, dev); drv->driver.bus = &serio_bus;
driver_register(&drv->driver);
driver_create_file(&drv->driver, &driver_attr_description);
if (drv->manual_bind)
goto out;
start_over:
list_for_each_entry(serio, &serio_list, node) {
if (!serio->drv) {
serio_connect_port(serio, drv);
/*
* if new child appeared then the list is changed,
* we need to start over
*/
if (serio->child)
goto start_over;
}
}
out:
up(&serio_sem); up(&serio_sem);
} }
void serio_unregister_device(struct serio_dev *dev) void serio_unregister_driver(struct serio_driver *drv)
{ {
struct serio *serio; struct serio *serio;
down(&serio_sem); down(&serio_sem);
list_del_init(&dev->node);
list_del_init(&drv->node);
start_over:
list_for_each_entry(serio, &serio_list, node) { list_for_each_entry(serio, &serio_list, node) {
if (serio->dev == dev && dev->disconnect) if (serio->drv == drv) {
dev->disconnect(serio); serio_disconnect_port(serio);
serio_find_dev(serio); serio_connect_port(serio, NULL);
/* we could've deleted some ports, restart */
goto start_over;
} }
}
driver_unregister(&drv->driver);
up(&serio_sem); up(&serio_sem);
} }
/* called from serio_dev->connect/disconnect methods under serio_sem */ /* called from serio_driver->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_dev *dev) int serio_open(struct serio *serio, struct serio_driver *drv)
{ {
serio->dev = dev; unsigned long flags;
spin_lock_irqsave(&serio->lock, flags);
serio->drv = drv;
spin_unlock_irqrestore(&serio->lock, flags);
if (serio->open && serio->open(serio)) { if (serio->open && serio->open(serio)) {
serio->dev = NULL; spin_lock_irqsave(&serio->lock, flags);
serio->drv = NULL;
spin_unlock_irqrestore(&serio->lock, flags);
return -1; return -1;
} }
return 0; return 0;
} }
/* called from serio_dev->connect/disconnect methods under serio_sem */ /* called from serio_driver->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);
serio->dev = NULL; spin_lock_irqsave(&serio->lock, flags);
serio->drv = NULL;
spin_unlock_irqrestore(&serio->lock, flags);
} }
static int __init serio_init(void) irqreturn_t serio_interrupt(struct serio *serio,
unsigned char data, unsigned int dfl, struct pt_regs *regs)
{ {
int pid; unsigned long flags;
irqreturn_t ret = IRQ_NONE;
spin_lock_irqsave(&serio->lock, flags);
pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL); if (likely(serio->drv)) {
ret = serio->drv->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;
}
}
}
if (!pid) { spin_unlock_irqrestore(&serio->lock, flags);
return ret;
}
static int __init serio_init(void)
{
if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
printk(KERN_WARNING "serio: Failed to start kseriod\n"); printk(KERN_WARNING "serio: Failed to start kseriod\n");
return -1; return -1;
} }
serio_pid = pid; bus_register(&serio_bus);
return 0; return 0;
} }
static void __exit serio_exit(void) static void __exit serio_exit(void)
{ {
bus_unregister(&serio_bus);
kill_proc(serio_pid, SIGTERM, 1); kill_proc(serio_pid, SIGTERM, 1);
wait_for_completion(&serio_exited); wait_for_completion(&serio_exited);
} }
......
/*
* Raw serio device providing access to a raw byte stream from underlying
* serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
*
* Copyright (c) 2004 Dmitry Torokhov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/miscdevice.h>
#include <linux/wait.h>
#define DRIVER_DESC "Raw serio driver"
MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
#define SERIO_RAW_QUEUE_LEN 64
struct serio_raw {
unsigned char queue[SERIO_RAW_QUEUE_LEN];
unsigned int tail, head;
char name[16];
unsigned int refcnt;
struct serio *serio;
struct miscdevice dev;
wait_queue_head_t wait;
struct list_head list;
struct list_head node;
};
struct serio_raw_list {
struct fasync_struct *fasync;
struct serio_raw *serio_raw;
struct list_head node;
};
static DECLARE_MUTEX(serio_raw_sem);
static LIST_HEAD(serio_raw_list);
static unsigned int serio_raw_no;
/*********************************************************************
* Interface with userspace (file operations) *
*********************************************************************/
static int serio_raw_fasync(int fd, struct file *file, int on)
{
struct serio_raw_list *list = file->private_data;
int retval;
retval = fasync_helper(fd, file, on, &list->fasync);
return retval < 0 ? retval : 0;
}
static struct serio_raw *serio_raw_locate(int minor)
{
struct serio_raw *serio_raw;
list_for_each_entry(serio_raw, &serio_raw_list, node) {
if (serio_raw->dev.minor == minor)
return serio_raw;
}
return NULL;
}
static int serio_raw_open(struct inode *inode, struct file *file)
{
struct serio_raw *serio_raw;
struct serio_raw_list *list;
int retval = 0;
retval = down_interruptible(&serio_raw_sem);
if (retval)
return retval;
if (!(serio_raw = serio_raw_locate(iminor(inode)))) {
retval = -ENODEV;
goto out;
}
if (!serio_raw->serio) {
retval = -ENODEV;
goto out;
}
if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) {
retval = -ENOMEM;
goto out;
}
memset(list, 0, sizeof(struct serio_raw_list));
list->serio_raw = serio_raw;
file->private_data = list;
serio_raw->refcnt++;
list_add_tail(&list->node, &serio_raw->list);
out:
up(&serio_raw_sem);
return retval;
}
static int serio_raw_cleanup(struct serio_raw *serio_raw)
{
if (--serio_raw->refcnt == 0) {
misc_deregister(&serio_raw->dev);
list_del_init(&serio_raw->node);
kfree(serio_raw);
return 1;
}
return 0;
}
static int serio_raw_release(struct inode *inode, struct file *file)
{
struct serio_raw_list *list = file->private_data;
struct serio_raw *serio_raw = list->serio_raw;
down(&serio_raw_sem);
serio_raw_fasync(-1, file, 0);
serio_raw_cleanup(serio_raw);
up(&serio_raw_sem);
return 0;
}
static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
{
unsigned long flags;
int empty;
spin_lock_irqsave(&serio_raw->serio->lock, flags);
empty = serio_raw->head == serio_raw->tail;
if (!empty) {
*c = serio_raw->queue[serio_raw->tail];
serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
}
spin_unlock_irqrestore(&serio_raw->serio->lock, flags);
return !empty;
}
static ssize_t serio_raw_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct serio_raw_list *list = file->private_data;
struct serio_raw *serio_raw = list->serio_raw;
char c;
ssize_t retval = 0;
if (!serio_raw->serio)
return -ENODEV;
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(list->serio_raw->wait,
serio_raw->head != serio_raw->tail || !serio_raw->serio);
if (retval)
return retval;
if (!serio_raw->serio)
return -ENODEV;
while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
if (put_user(c, buffer++))
return -EFAULT;
retval++;
}
return retval;
}
static ssize_t serio_raw_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct serio_raw_list *list = file->private_data;
ssize_t written = 0;
int retval;
unsigned char c;
retval = down_interruptible(&serio_raw_sem);
if (retval)
return retval;
if (!list->serio_raw->serio) {
retval = -ENODEV;
goto out;
}
if (count > 32)
count = 32;
while (count--) {
if (get_user(c, buffer++)) {
retval = -EFAULT;
goto out;
}
if (serio_write(list->serio_raw->serio, c)) {
retval = -EIO;
goto out;
}
written++;
};
out:
up(&serio_raw_sem);
return written;
}
static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
{
struct serio_raw_list *list = file->private_data;
poll_wait(file, &list->serio_raw->wait, wait);
if (list->serio_raw->head != list->serio_raw->tail)
return POLLIN | POLLRDNORM;
return 0;
}
struct file_operations serio_raw_fops = {
.owner = THIS_MODULE,
.open = serio_raw_open,
.release = serio_raw_release,
.read = serio_raw_read,
.write = serio_raw_write,
.poll = serio_raw_poll,
.fasync = serio_raw_fasync,
};
/*********************************************************************
* Interface with serio port *
*********************************************************************/
static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
unsigned int dfl, struct pt_regs *regs)
{
struct serio_raw *serio_raw = serio->private;
struct serio_raw_list *list;
unsigned int head = serio_raw->head;
/* we are holding serio->lock here so we are prootected */
serio_raw->queue[head] = data;
head = (head + 1) % SERIO_RAW_QUEUE_LEN;
if (likely(head != serio_raw->tail)) {
serio_raw->head = head;
list_for_each_entry(list, &serio_raw->list, node)
kill_fasync(&list->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&serio_raw->wait);
}
return IRQ_HANDLED;
}
static void serio_raw_connect(struct serio *serio, struct serio_driver *drv)
{
struct serio_raw *serio_raw;
int err;
if ((serio->type & SERIO_TYPE) != SERIO_8042)
return;
if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
return;
}
down(&serio_raw_sem);
memset(serio_raw, 0, sizeof(struct serio_raw));
snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
serio_raw->refcnt = 1;
serio_raw->serio = serio;
INIT_LIST_HEAD(&serio_raw->list);
init_waitqueue_head(&serio_raw->wait);
serio->private = serio_raw;
if (serio_open(serio, drv))
goto out_free;
list_add_tail(&serio_raw->node, &serio_raw_list);
serio_raw->dev.minor = PSMOUSE_MINOR;
serio_raw->dev.name = serio_raw->name;
serio_raw->dev.fops = &serio_raw_fops;
err = misc_register(&serio_raw->dev);
if (err) {
serio_raw->dev.minor = MISC_DYNAMIC_MINOR;
err = misc_register(&serio_raw->dev);
}
if (err) {
printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n",
serio->phys);
goto out_close;
}
printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n",
serio->phys, serio_raw->name, serio_raw->dev.minor);
goto out;
out_close:
serio_close(serio);
list_del_init(&serio_raw->node);
out_free:
serio->private = NULL;
kfree(serio_raw);
out:
up(&serio_raw_sem);
}
static int serio_raw_reconnect(struct serio *serio)
{
struct serio_raw *serio_raw = serio->private;
struct serio_driver *drv = serio->drv;
if (!drv || !serio_raw) {
printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
/*
* Nothing needs to be done here, we just need this method to
* keep the same device.
*/
return 0;
}
static void serio_raw_disconnect(struct serio *serio)
{
struct serio_raw *serio_raw;
down(&serio_raw_sem);
serio_raw = serio->private;
serio_close(serio);
serio->private = NULL;
serio_raw->serio = NULL;
if (!serio_raw_cleanup(serio_raw))
wake_up_interruptible(&serio_raw->wait);
up(&serio_raw_sem);
}
static struct serio_driver serio_raw_drv = {
.driver = {
.name = "serio_raw",
},
.description = DRIVER_DESC,
.interrupt = serio_raw_interrupt,
.connect = serio_raw_connect,
.reconnect = serio_raw_reconnect,
.disconnect = serio_raw_disconnect,
.manual_bind = 1,
};
int __init serio_raw_init(void)
{
serio_register_driver(&serio_raw_drv);
return 0;
}
void __exit serio_raw_exit(void)
{
serio_unregister_driver(&serio_raw_drv);
}
module_init(serio_raw_init);
module_exit(serio_raw_exit);
...@@ -31,28 +31,25 @@ MODULE_ALIAS_LDISC(N_MOUSE); ...@@ -31,28 +31,25 @@ MODULE_ALIAS_LDISC(N_MOUSE);
struct serport { struct serport {
struct tty_struct *tty; struct tty_struct *tty;
wait_queue_head_t wait; wait_queue_head_t wait;
struct serio serio; struct serio *serio;
unsigned long flags; unsigned long flags;
char phys[32];
}; };
char serport_name[] = "Serial port";
/* /*
* Callback functions from the serio code. * Callback functions from the serio code.
*/ */
static int serport_serio_write(struct serio *serio, unsigned char data) static int serport_serio_write(struct serio *serio, unsigned char data)
{ {
struct serport *serport = serio->driver; struct serport *serport = serio->port_data;
return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1);
} }
static void serport_serio_close(struct serio *serio) static void serport_serio_close(struct serio *serio)
{ {
struct serport *serport = serio->driver; struct serport *serport = serio->port_data;
serport->serio.type = 0; serport->serio->type = 0;
wake_up_interruptible(&serport->wait); wake_up_interruptible(&serport->wait);
} }
...@@ -64,26 +61,30 @@ static void serport_serio_close(struct serio *serio) ...@@ -64,26 +61,30 @@ static void serport_serio_close(struct serio *serio)
static int serport_ldisc_open(struct tty_struct *tty) static int serport_ldisc_open(struct tty_struct *tty)
{ {
struct serport *serport; struct serport *serport;
struct serio *serio;
char name[64]; char name[64];
serport = kmalloc(sizeof(struct serport), GFP_KERNEL); serport = kmalloc(sizeof(struct serport), GFP_KERNEL);
if (unlikely(!serport)) serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (unlikely(!serport || !serio)) {
kfree(serport);
kfree(serio);
return -ENOMEM; return -ENOMEM;
memset(serport, 0, sizeof(struct serport)); }
memset(serport, 0, sizeof(struct serport));
serport->serio = serio;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
serport->tty = tty; serport->tty = tty;
tty->disc_data = serport; tty->disc_data = serport;
snprintf(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name)); memset(serio, 0, sizeof(struct serio));
strlcpy(serio->name, "Serial port", sizeof(serio->name));
serport->serio.name = serport_name; snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
serport->serio.phys = serport->phys; serio->type = SERIO_RS232;
serio->write = serport_serio_write;
serport->serio.type = SERIO_RS232; serio->close = serport_serio_close;
serport->serio.write = serport_serio_write; serio->port_data = serport;
serport->serio.close = serport_serio_close;
serport->serio.driver = serport;
init_waitqueue_head(&serport->wait); init_waitqueue_head(&serport->wait);
...@@ -114,7 +115,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c ...@@ -114,7 +115,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
struct serport *serport = (struct serport*) tty->disc_data; struct serport *serport = (struct serport*) tty->disc_data;
int i; int i;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
serio_interrupt(&serport->serio, cp[i], 0, NULL); serio_interrupt(serport->serio, cp[i], 0, NULL);
} }
/* /*
...@@ -142,10 +143,10 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u ...@@ -142,10 +143,10 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
return -EBUSY; return -EBUSY;
serio_register_port(&serport->serio); serio_register_port(serport->serio);
printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
wait_event_interruptible(serport->wait, !serport->serio.type); wait_event_interruptible(serport->wait, !serport->serio->type);
serio_unregister_port(&serport->serio); serio_unregister_port(serport->serio);
clear_bit(SERPORT_BUSY, &serport->flags); clear_bit(SERPORT_BUSY, &serport->flags);
...@@ -161,7 +162,7 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi ...@@ -161,7 +162,7 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi
struct serport *serport = (struct serport*) tty->disc_data; struct serport *serport = (struct serport*) tty->disc_data;
if (cmd == SPIOCSTYPE) if (cmd == SPIOCSTYPE)
return get_user(serport->serio.type, (unsigned long __user *) arg); return get_user(serport->serio->type, (unsigned long __user *) arg);
return -EINVAL; return -EINVAL;
} }
...@@ -170,7 +171,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty) ...@@ -170,7 +171,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty)
{ {
struct serport *sp = (struct serport *) tty->disc_data; struct serport *sp = (struct serport *) tty->disc_data;
serio_dev_write_wakeup(&sp->serio); serio_drv_write_wakeup(sp->serio);
} }
/* /*
......
...@@ -36,8 +36,10 @@ ...@@ -36,8 +36,10 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#define DRIVER_DESC "Gunze AHL-51S touchscreen driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -111,7 +113,7 @@ static void gunze_disconnect(struct serio *serio) ...@@ -111,7 +113,7 @@ static void gunze_disconnect(struct serio *serio)
* and if yes, registers it as an input device. * and if yes, registers it as an input device.
*/ */
static void gunze_connect(struct serio *serio, struct serio_dev *dev) static void gunze_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct gunze *gunze; struct gunze *gunze;
...@@ -142,7 +144,7 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) ...@@ -142,7 +144,7 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev)
gunze->dev.id.product = 0x0051; gunze->dev.id.product = 0x0051;
gunze->dev.id.version = 0x0100; gunze->dev.id.version = 0x0100;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
kfree(gunze); kfree(gunze);
return; return;
} }
...@@ -156,7 +158,11 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) ...@@ -156,7 +158,11 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev gunze_dev = { static struct serio_driver gunze_drv = {
.driver = {
.name = "gunze",
},
.description = DRIVER_DESC,
.interrupt = gunze_interrupt, .interrupt = gunze_interrupt,
.connect = gunze_connect, .connect = gunze_connect,
.disconnect = gunze_disconnect, .disconnect = gunze_disconnect,
...@@ -168,13 +174,13 @@ static struct serio_dev gunze_dev = { ...@@ -168,13 +174,13 @@ static struct serio_dev gunze_dev = {
int __init gunze_init(void) int __init gunze_init(void)
{ {
serio_register_device(&gunze_dev); serio_register_driver(&gunze_drv);
return 0; return 0;
} }
void __exit gunze_exit(void) void __exit gunze_exit(void)
{ {
serio_unregister_device(&gunze_dev); serio_unregister_driver(&gunze_drv);
} }
module_init(gunze_init); module_init(gunze_init);
......
...@@ -45,8 +45,10 @@ ...@@ -45,8 +45,10 @@
#include <asm/arch/hardware.h> #include <asm/arch/hardware.h>
#include <asm/arch/irqs.h> #include <asm/arch/irqs.h>
#define DRIVER_DESC "H3600 touchscreen driver"
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("H3600 touchscreen driver"); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*
...@@ -373,7 +375,7 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, ...@@ -373,7 +375,7 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
* new serio device. It looks whether it was registered as a H3600 touchscreen * new serio device. It looks whether it was registered as a H3600 touchscreen
* and if yes, registers it as an input device. * and if yes, registers it as an input device.
*/ */
static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) static void h3600ts_connect(struct serio *serio, struct serio_driver *drv)
{ {
struct h3600_dev *ts; struct h3600_dev *ts;
...@@ -441,7 +443,7 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -441,7 +443,7 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */
ts->dev.id.version = 0x0100; ts->dev.id.version = 0x0100;
if (serio_open(serio, dev)) { if (serio_open(serio, drv)) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
kfree(ts); kfree(ts);
...@@ -478,7 +480,11 @@ static void h3600ts_disconnect(struct serio *serio) ...@@ -478,7 +480,11 @@ static void h3600ts_disconnect(struct serio *serio)
* The serio device structure. * The serio device structure.
*/ */
static struct serio_dev h3600ts_dev = { static struct serio_driver h3600ts_drv = {
.driver = {
.name = "h3600ts",
},
.description = DRIVER_DESC,
.interrupt = h3600ts_interrupt, .interrupt = h3600ts_interrupt,
.connect = h3600ts_connect, .connect = h3600ts_connect,
.disconnect = h3600ts_disconnect, .disconnect = h3600ts_disconnect,
...@@ -490,13 +496,13 @@ static struct serio_dev h3600ts_dev = { ...@@ -490,13 +496,13 @@ static struct serio_dev h3600ts_dev = {
static int __init h3600ts_init(void) static int __init h3600ts_init(void)
{ {
serio_register_device(&h3600ts_dev); serio_register_driver(&h3600ts_drv);
return 0; return 0;
} }
static void __exit h3600ts_exit(void) static void __exit h3600ts_exit(void)
{ {
serio_unregister_device(&h3600ts_dev); serio_unregister_driver(&h3600ts_drv);
} }
module_init(h3600ts_init); module_init(h3600ts_init);
......
...@@ -3,9 +3,17 @@ ...@@ -3,9 +3,17 @@
* *
* Copyright (c) 2001 "Crazy" james Simmons * Copyright (c) 2001 "Crazy" james Simmons
* *
* Input driver to Touchscreen device driver module. * Compaq touchscreen protocol driver. The protocol emulated by this driver
* is obsolete; for new programs use the tslib library which can read directly
* from evdev and perform dejittering, variance filtering and calibration -
* all in user space, not at kernel level. The meaning of this driver is
* to allow usage of newer input drivers with old applications that use the
* old /dev/h3600_ts and /dev/h3600_tsraw devices.
* *
* Sponsored by Transvirtual Technology * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
* Fixed to actually work, not just output random numbers.
* Added support for both h3600_ts and h3600_tsraw protocol
* emulation.
*/ */
/* /*
...@@ -24,11 +32,13 @@ ...@@ -24,11 +32,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Should you need to contact me, the author, you can do so either by * Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <jsimmons@transvirtual.com>. * e-mail - mail your message to <jsimmons@infradead.org>.
*/ */
#define TSDEV_MINOR_BASE 128 #define TSDEV_MINOR_BASE 128
#define TSDEV_MINORS 32 #define TSDEV_MINORS 32
/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
#define TSDEV_MINOR_MASK 15
#define TSDEV_BUFFER_SIZE 64 #define TSDEV_BUFFER_SIZE 64
#include <linux/slab.h> #include <linux/slab.h>
...@@ -52,48 +62,84 @@ ...@@ -52,48 +62,84 @@
#define CONFIG_INPUT_TSDEV_SCREEN_Y 320 #define CONFIG_INPUT_TSDEV_SCREEN_Y 320
#endif #endif
/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
* devices. The first one must output X/Y data in 'cooked' format, e.g.
* filtered, dejittered and calibrated. Second device just outputs raw
* data received from the hardware.
*
* This driver doesn't support filtering and dejittering; it supports only
* calibration. Filtering and dejittering must be done in the low-level
* driver, if needed, because it may gain additional benefits from knowing
* the low-level details, the nature of noise and so on.
*
* The driver precomputes a calibration matrix given the initial xres and
* yres values (quite innacurate for most touchscreens) that will result
* in a more or less expected range of output values. The driver supports
* the TS_SET_CAL ioctl, which will replace the calibration matrix with a
* new one, supposedly generated from the values taken from the raw device.
*/
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("Input driver to touchscreen converter"); MODULE_DESCRIPTION("Input driver to touchscreen converter");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
module_param(xres, uint, 0); module_param(xres, uint, 0);
MODULE_PARM_DESC(xres, "Horizontal screen resolution"); MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; static int yres = CONFIG_INPUT_TSDEV_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 (can be negative for Y-mirror)");
/* From Compaq's Touch Screen Specification version 0.2 (draft) */
struct ts_event {
short pressure;
short x;
short y;
short millisecs;
};
struct ts_calibration {
int xscale;
int xtrans;
int yscale;
int ytrans;
int xyswap;
};
struct tsdev { struct tsdev {
int exist; int exist;
int open; int open;
int minor; int minor;
char name[16]; char name[8];
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head list; struct list_head list;
struct input_handle handle; struct input_handle handle;
int x, y, pressure;
struct ts_calibration cal;
}; };
/* From Compaq's Touch Screen Specification version 0.2 (draft) */
typedef struct {
short pressure;
short x;
short y;
short millisecs;
} TS_EVENT;
struct tsdev_list { struct tsdev_list {
struct fasync_struct *fasync; struct fasync_struct *fasync;
struct list_head node; struct list_head node;
struct tsdev *tsdev; struct tsdev *tsdev;
int head, tail; int head, tail;
int oldx, oldy, pendown; struct ts_event event[TSDEV_BUFFER_SIZE];
TS_EVENT event[TSDEV_BUFFER_SIZE]; int raw;
}; };
/* The following ioctl codes are defined ONLY for backward compatibility.
* Don't use tsdev for new developement; use the tslib library instead.
* Touchscreen calibration is a fully userspace task.
*/
/* Use 'f' as magic number */
#define IOC_H3600_TS_MAGIC 'f'
#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
static struct input_handler tsdev_handler; static struct input_handler tsdev_handler;
static struct tsdev *tsdev_table[TSDEV_MINORS]; static struct tsdev *tsdev_table[TSDEV_MINORS/2];
static int tsdev_fasync(int fd, struct file *file, int on) static int tsdev_fasync(int fd, struct file *file, int on)
{ {
...@@ -109,13 +155,16 @@ static int tsdev_open(struct inode *inode, struct file *file) ...@@ -109,13 +155,16 @@ static int tsdev_open(struct inode *inode, struct file *file)
int i = iminor(inode) - TSDEV_MINOR_BASE; int i = iminor(inode) - TSDEV_MINOR_BASE;
struct tsdev_list *list; struct tsdev_list *list;
if (i >= TSDEV_MINORS || !tsdev_table[i]) if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
return -ENODEV; return -ENODEV;
if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
memset(list, 0, sizeof(struct tsdev_list)); memset(list, 0, sizeof(struct tsdev_list));
list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
i &= TSDEV_MINOR_MASK;
list->tsdev = tsdev_table[i]; list->tsdev = tsdev_table[i];
list_add_tail(&list->node, &tsdev_table[i]->list); list_add_tail(&list->node, &tsdev_table[i]->list);
file->private_data = list; file->private_data = list;
...@@ -169,11 +218,13 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, ...@@ -169,11 +218,13 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
if (!list->tsdev->exist) if (!list->tsdev->exist)
return -ENODEV; return -ENODEV;
while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) { while (list->head != list->tail &&
if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT))) retval + sizeof (struct ts_event) <= count) {
if (copy_to_user (buffer + retval, list->event + list->tail,
sizeof (struct ts_event)))
return -EFAULT; return -EFAULT;
list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
retval += sizeof(TS_EVENT); retval += sizeof (struct ts_event);
} }
return retval; return retval;
...@@ -193,22 +244,27 @@ static unsigned int tsdev_poll(struct file *file, poll_table * wait) ...@@ -193,22 +244,27 @@ static unsigned int tsdev_poll(struct file *file, poll_table * wait)
static int tsdev_ioctl(struct inode *inode, struct file *file, static int tsdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
/*
struct tsdev_list *list = file->private_data; struct tsdev_list *list = file->private_data;
struct tsdev *evdev = list->tsdev; struct tsdev *tsdev = list->tsdev;
struct input_dev *dev = tsdev->handle.dev; int retval = 0;
int retval;
switch (cmd) { switch (cmd) {
case HHEHE: case TS_GET_CAL:
return 0; if (copy_to_user ((void *)arg, &tsdev->cal,
case hjff: sizeof (struct ts_calibration)))
return 0; retval = -EFAULT;
break;
case TS_SET_CAL:
if (copy_from_user (&tsdev->cal, (void *)arg,
sizeof (struct ts_calibration)))
retval = -EFAULT;
break;
default: default:
return 0; retval = -EINVAL;
break;
} }
*/
return -EINVAL; return retval;
} }
struct file_operations tsdev_fops = { struct file_operations tsdev_fops = {
...@@ -227,33 +283,23 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, ...@@ -227,33 +283,23 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
struct tsdev *tsdev = handle->private; struct tsdev *tsdev = handle->private;
struct tsdev_list *list; struct tsdev_list *list;
struct timeval time; struct timeval time;
int size;
list_for_each_entry(list, &tsdev->list, node) {
switch (type) { switch (type) {
case EV_ABS: case EV_ABS:
switch (code) { switch (code) {
case ABS_X: case ABS_X:
if (!list->pendown) tsdev->x = value;
return;
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
if (size > 0)
list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size);
else
list->oldx = ((value - handle->dev->absmin[ABS_X]));
break; break;
case ABS_Y: case ABS_Y:
if (!list->pendown) tsdev->y = value;
return;
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
if (size > 0)
list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size);
else
list->oldy = ((value - handle->dev->absmin[ABS_Y]));
break; break;
case ABS_PRESSURE: case ABS_PRESSURE:
list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ? if (value > handle->dev->absmax[ABS_PRESSURE])
value - handle->dev->absmin[ABS_PRESSURE] : 0; value = handle->dev->absmax[ABS_PRESSURE];
value -= handle->dev->absmin[ABS_PRESSURE];
if (value < 0)
value = 0;
tsdev->pressure = value;
break; break;
} }
break; break;
...@@ -261,22 +307,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, ...@@ -261,22 +307,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
case EV_REL: case EV_REL:
switch (code) { switch (code) {
case REL_X: case REL_X:
if (!list->pendown) tsdev->x += value;
return; if (tsdev->x < 0)
list->oldx += value; tsdev->x = 0;
if (list->oldx < 0) else if (tsdev->x > xres)
list->oldx = 0; tsdev->x = xres;
else if (list->oldx > xres)
list->oldx = xres;
break; break;
case REL_Y: case REL_Y:
if (!list->pendown) tsdev->y += value;
return; if (tsdev->y < 0)
list->oldy += value; tsdev->y = 0;
if (list->oldy < 0) else if (tsdev->y > yres)
list->oldy = 0; tsdev->y = yres;
else if (list->oldy > xres)
list->oldy = xres;
break; break;
} }
break; break;
...@@ -285,24 +327,41 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, ...@@ -285,24 +327,41 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
if (code == BTN_TOUCH || code == BTN_MOUSE) { if (code == BTN_TOUCH || code == BTN_MOUSE) {
switch (value) { switch (value) {
case 0: case 0:
list->pendown = 0; tsdev->pressure = 0;
break; break;
case 1: case 1:
if (!list->pendown) if (!tsdev->pressure)
list->pendown = 1; tsdev->pressure = 1;
break; break;
case 2:
return;
} }
} else }
return;
break; break;
} }
if (type != EV_SYN || code != SYN_REPORT)
return;
list_for_each_entry(list, &tsdev->list, node) {
int x, y, tmp;
do_gettimeofday(&time); do_gettimeofday(&time);
list->event[list->head].millisecs = time.tv_usec / 100; list->event[list->head].millisecs = time.tv_usec / 100;
list->event[list->head].pressure = list->pendown; list->event[list->head].pressure = tsdev->pressure;
list->event[list->head].x = list->oldx;
list->event[list->head].y = list->oldy; x = tsdev->x;
y = tsdev->y;
/* Calibration */
if (!list->raw) {
x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
if (tsdev->cal.xyswap) {
tmp = x; x = y; y = tmp;
}
}
list->event[list->head].x = x;
list->event[list->head].y = y;
list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
} }
...@@ -314,11 +373,11 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, ...@@ -314,11 +373,11 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
struct input_device_id *id) struct input_device_id *id)
{ {
struct tsdev *tsdev; struct tsdev *tsdev;
int minor; int minor, delta;
for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor]; for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor];
minor++); minor++);
if (minor == TSDEV_MINORS) { if (minor >= TSDEV_MINORS/2) {
printk(KERN_ERR printk(KERN_ERR
"tsdev: You have way too many touchscreens\n"); "tsdev: You have way too many touchscreens\n");
return NULL; return NULL;
...@@ -340,10 +399,25 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, ...@@ -340,10 +399,25 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
tsdev->handle.handler = handler; tsdev->handle.handler = handler;
tsdev->handle.private = tsdev; tsdev->handle.private = tsdev;
/* Precompute the rough calibration matrix */
delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
if (delta == 0)
delta = 1;
tsdev->cal.xscale = (xres << 8) / delta;
tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
if (delta == 0)
delta = 1;
tsdev->cal.yscale = (yres << 8) / delta;
tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
tsdev_table[minor] = tsdev; tsdev_table[minor] = tsdev;
devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2),
S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor);
class_simple_device_add(input_class, class_simple_device_add(input_class,
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
dev->dev, "ts%d", minor); dev->dev, "ts%d", minor);
...@@ -362,6 +436,7 @@ static void tsdev_disconnect(struct input_handle *handle) ...@@ -362,6 +436,7 @@ static void tsdev_disconnect(struct input_handle *handle)
wake_up_interruptible(&tsdev->wait); wake_up_interruptible(&tsdev->wait);
} else } else
tsdev_free(tsdev); tsdev_free(tsdev);
devfs_remove("input/tsraw%d", tsdev->minor);
} }
static struct input_device_id tsdev_ids[] = { static struct input_device_id tsdev_ids[] = {
...@@ -379,6 +454,12 @@ static struct input_device_id tsdev_ids[] = { ...@@ -379,6 +454,12 @@ static struct input_device_id tsdev_ids[] = {
.absbit = { BIT(ABS_X) | BIT(ABS_Y) }, .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
},/* A tablet like device, at least touch detection, two absolute axes */ },/* A tablet like device, at least touch detection, two absolute axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
},/* A tablet like device with several gradations of pressure */
{},/* Terminating entry */ {},/* Terminating entry */
}; };
......
...@@ -98,7 +98,7 @@ struct uart_sunsu_port { ...@@ -98,7 +98,7 @@ struct uart_sunsu_port {
unsigned int irq; unsigned int irq;
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
struct serio serio; struct serio *serio;
int serio_open; int serio_open;
#endif #endif
}; };
...@@ -520,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg ...@@ -520,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
/* Stop-A is handled by drivers/char/keyboard.c now. */ /* Stop-A is handled by drivers/char/keyboard.c now. */
if (up->su_type == SU_PORT_KBD) { if (up->su_type == SU_PORT_KBD) {
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
serio_interrupt(&up->serio, ch, 0, regs); serio_interrupt(up->serio, ch, 0, regs);
#endif #endif
} else if (up->su_type == SU_PORT_MS) { } else if (up->su_type == SU_PORT_MS) {
int ret = suncore_mouse_baud_detection(ch, is_break); int ret = suncore_mouse_baud_detection(ch, is_break);
...@@ -534,7 +534,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg ...@@ -534,7 +534,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
case 0: case 0:
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
serio_interrupt(&up->serio, ch, 0, regs); serio_interrupt(up->serio, ch, 0, regs);
#endif #endif
break; break;
}; };
...@@ -994,7 +994,7 @@ static spinlock_t sunsu_serio_lock = SPIN_LOCK_UNLOCKED; ...@@ -994,7 +994,7 @@ static spinlock_t sunsu_serio_lock = SPIN_LOCK_UNLOCKED;
static int sunsu_serio_write(struct serio *serio, unsigned char ch) static int sunsu_serio_write(struct serio *serio, unsigned char ch)
{ {
struct uart_sunsu_port *up = serio->driver; struct uart_sunsu_port *up = serio->port_data;
unsigned long flags; unsigned long flags;
int lsr; int lsr;
...@@ -1014,7 +1014,7 @@ static int sunsu_serio_write(struct serio *serio, unsigned char ch) ...@@ -1014,7 +1014,7 @@ static int sunsu_serio_write(struct serio *serio, unsigned char ch)
static int sunsu_serio_open(struct serio *serio) static int sunsu_serio_open(struct serio *serio)
{ {
struct uart_sunsu_port *up = serio->driver; struct uart_sunsu_port *up = serio->port_data;
unsigned long flags; unsigned long flags;
int ret; int ret;
...@@ -1031,7 +1031,7 @@ static int sunsu_serio_open(struct serio *serio) ...@@ -1031,7 +1031,7 @@ static int sunsu_serio_open(struct serio *serio)
static void sunsu_serio_close(struct serio *serio) static void sunsu_serio_close(struct serio *serio)
{ {
struct uart_sunsu_port *up = serio->driver; struct uart_sunsu_port *up = serio->port_data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sunsu_serio_lock, flags); spin_lock_irqsave(&sunsu_serio_lock, flags);
...@@ -1284,13 +1284,11 @@ static struct uart_driver sunsu_reg = { ...@@ -1284,13 +1284,11 @@ static struct uart_driver sunsu_reg = {
.major = TTY_MAJOR, .major = TTY_MAJOR,
}; };
static int __init sunsu_kbd_ms_init(void) static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel)
{ {
struct uart_sunsu_port *up; struct serio *serio;
int i;
for (i = 0, up = sunsu_ports; i < 2; i++, up++) { up->port.line = channel;
up->port.line = i;
up->port.type = PORT_UNKNOWN; up->port.type = PORT_UNKNOWN;
up->port.uartclk = (SU_BASE_BAUD * 16); up->port.uartclk = (SU_BASE_BAUD * 16);
...@@ -1301,37 +1299,43 @@ static int __init sunsu_kbd_ms_init(void) ...@@ -1301,37 +1299,43 @@ static int __init sunsu_kbd_ms_init(void)
sunsu_autoconfig(up); sunsu_autoconfig(up);
if (up->port.type == PORT_UNKNOWN) if (up->port.type == PORT_UNKNOWN)
continue; return -1;
printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n",
i, channel,
up->port.membase, __irq_itoa(up->irq), up->port.membase, __irq_itoa(up->irq),
sunsu_type(&up->port)); sunsu_type(&up->port));
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
memset(&up->serio, 0, sizeof(up->serio)); up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
memset(serio, 0, sizeof(serio));
up->serio.driver = up; serio->port_data = up;
up->serio.type = SERIO_RS232; serio->type = SERIO_RS232;
if (up->su_type == SU_PORT_KBD) { if (up->su_type == SU_PORT_KBD) {
up->serio.type |= SERIO_SUNKBD; serio->type |= SERIO_SUNKBD;
up->serio.name = "sukbd"; strlcpy(serio->name, "sukbd", sizeof(serio->name));
} else { } else {
up->serio.type |= (SERIO_SUN | (1 << 16)); serio->type |= (SERIO_SUN | (1 << 16));
up->serio.name = "sums"; strlcpy(serio->name, "sums", sizeof(serio->name));
} }
up->serio.phys = (i == 0 ? "su/serio0" : "su/serio1"); strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"),
sizeof(serio->phys));
up->serio.write = sunsu_serio_write; serio->write = sunsu_serio_write;
up->serio.open = sunsu_serio_open; serio->open = sunsu_serio_open;
up->serio.close = sunsu_serio_close; serio->close = sunsu_serio_close;
serio_register_port(&up->serio); serio_register_port(serio);
} else {
printk(KERN_WARNING "su%d: not enough memory for serio port\n",
channel);
}
#endif #endif
sunsu_startup(&up->port); sunsu_startup(&up->port);
}
return 0; return 0;
} }
...@@ -1680,10 +1684,12 @@ static int __init sunsu_probe(void) ...@@ -1680,10 +1684,12 @@ static int __init sunsu_probe(void)
if (scan.msx != -1 && scan.kbx != -1) { if (scan.msx != -1 && scan.kbx != -1) {
sunsu_ports[0].su_type = SU_PORT_MS; sunsu_ports[0].su_type = SU_PORT_MS;
sunsu_ports[0].port_node = scan.msnode; sunsu_ports[0].port_node = scan.msnode;
sunsu_kbd_ms_init(&sunsu_ports[0], 0);
sunsu_ports[1].su_type = SU_PORT_KBD; sunsu_ports[1].su_type = SU_PORT_KBD;
sunsu_ports[1].port_node = scan.kbnode; sunsu_ports[1].port_node = scan.kbnode;
sunsu_kbd_ms_init(&sunsu_ports[1], 1);
sunsu_kbd_ms_init();
return 0; return 0;
} }
...@@ -1715,7 +1721,10 @@ static void __exit sunsu_exit(void) ...@@ -1715,7 +1721,10 @@ static void __exit sunsu_exit(void)
if (up->su_type == SU_PORT_MS || if (up->su_type == SU_PORT_MS ||
up->su_type == SU_PORT_KBD) { up->su_type == SU_PORT_KBD) {
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
serio_unregister_port(&up->serio); if (up->serio) {
serio_unregister_port(up->serio);
up->serio = NULL;
}
#endif #endif
} else if (up->port.type != PORT_UNKNOWN) { } else if (up->port.type != PORT_UNKNOWN) {
uart_remove_one_port(&sunsu_reg, &up->port); uart_remove_one_port(&sunsu_reg, &up->port);
......
...@@ -107,7 +107,7 @@ struct uart_sunzilog_port { ...@@ -107,7 +107,7 @@ struct uart_sunzilog_port {
unsigned char prev_status; unsigned char prev_status;
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
struct serio serio; struct serio *serio;
int serio_open; int serio_open;
#endif #endif
}; };
...@@ -291,7 +291,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, ...@@ -291,7 +291,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
/* Stop-A is handled by drivers/char/keyboard.c now. */ /* Stop-A is handled by drivers/char/keyboard.c now. */
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
if (up->serio_open) if (up->serio_open)
serio_interrupt(&up->serio, ch, 0, regs); serio_interrupt(up->serio, ch, 0, regs);
#endif #endif
} else if (ZS_IS_MOUSE(up)) { } else if (ZS_IS_MOUSE(up)) {
int ret = suncore_mouse_baud_detection(ch, is_break); int ret = suncore_mouse_baud_detection(ch, is_break);
...@@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, ...@@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
case 0: case 0:
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
if (up->serio_open) if (up->serio_open)
serio_interrupt(&up->serio, ch, 0, regs); serio_interrupt(up->serio, ch, 0, regs);
#endif #endif
break; break;
}; };
...@@ -1295,7 +1295,7 @@ static spinlock_t sunzilog_serio_lock = SPIN_LOCK_UNLOCKED; ...@@ -1295,7 +1295,7 @@ static spinlock_t sunzilog_serio_lock = SPIN_LOCK_UNLOCKED;
static int sunzilog_serio_write(struct serio *serio, unsigned char ch) static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
{ {
struct uart_sunzilog_port *up = serio->driver; struct uart_sunzilog_port *up = serio->port_data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sunzilog_serio_lock, flags); spin_lock_irqsave(&sunzilog_serio_lock, flags);
...@@ -1309,7 +1309,7 @@ static int sunzilog_serio_write(struct serio *serio, unsigned char ch) ...@@ -1309,7 +1309,7 @@ static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
static int sunzilog_serio_open(struct serio *serio) static int sunzilog_serio_open(struct serio *serio)
{ {
struct uart_sunzilog_port *up = serio->driver; struct uart_sunzilog_port *up = serio->port_data;
unsigned long flags; unsigned long flags;
int ret; int ret;
...@@ -1326,7 +1326,7 @@ static int sunzilog_serio_open(struct serio *serio) ...@@ -1326,7 +1326,7 @@ static int sunzilog_serio_open(struct serio *serio)
static void sunzilog_serio_close(struct serio *serio) static void sunzilog_serio_close(struct serio *serio)
{ {
struct uart_sunzilog_port *up = serio->driver; struct uart_sunzilog_port *up = serio->port_data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&sunzilog_serio_lock, flags); spin_lock_irqsave(&sunzilog_serio_lock, flags);
...@@ -1529,6 +1529,7 @@ static void __init sunzilog_prepare(void) ...@@ -1529,6 +1529,7 @@ static void __init sunzilog_prepare(void)
static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel)
{ {
int baud, brg; int baud, brg;
struct serio *serio;
if (channel == KEYBOARD_LINE) { if (channel == KEYBOARD_LINE) {
up->flags |= SUNZILOG_FLAG_CONS_KEYB; up->flags |= SUNZILOG_FLAG_CONS_KEYB;
...@@ -1547,26 +1548,34 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe ...@@ -1547,26 +1548,34 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
sunzilog_convert_to_zs(up, up->cflag, 0, brg); sunzilog_convert_to_zs(up, up->cflag, 0, brg);
#ifdef CONFIG_SERIO #ifdef CONFIG_SERIO
memset(&up->serio, 0, sizeof(up->serio)); up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
up->serio.driver = up; memset(serio, 0, sizeof(serio));
up->serio.type = SERIO_RS232; serio->port_data = up;
serio->type = SERIO_RS232;
if (channel == KEYBOARD_LINE) { if (channel == KEYBOARD_LINE) {
up->serio.type |= SERIO_SUNKBD; serio->type |= SERIO_SUNKBD;
up->serio.name = "zskbd"; strlcpy(serio->name, "zskbd", sizeof(serio->name));
} else { } else {
up->serio.type |= (SERIO_SUN | (1 << 16)); serio->type |= (SERIO_SUN | (1 << 16));
up->serio.name = "zsms"; strlcpy(serio->name, "zsms", sizeof(serio->name));
} }
up->serio.phys = (channel == KEYBOARD_LINE ? strlcpy(serio->phys,
"zs/serio0" : "zs/serio1"); (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"),
sizeof(serio->phys));
up->serio.write = sunzilog_serio_write; serio->write = sunzilog_serio_write;
up->serio.open = sunzilog_serio_open; serio->open = sunzilog_serio_open;
up->serio.close = sunzilog_serio_close; serio->close = sunzilog_serio_close;
serio_register_port(&up->serio); serio_register_port(serio);
} else {
printk(KERN_WARNING "zs%d: not enough memory for serio port\n",
channel);
}
#endif #endif
sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
...@@ -1732,9 +1741,14 @@ static void __exit sunzilog_exit(void) ...@@ -1732,9 +1741,14 @@ static void __exit sunzilog_exit(void)
for (i = 0; i < NUM_CHANNELS; i++) { for (i = 0; i < NUM_CHANNELS; i++) {
struct uart_sunzilog_port *up = &sunzilog_port_table[i]; struct uart_sunzilog_port *up = &sunzilog_port_table[i];
if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
continue; #ifdef CONFIG_SERIO
if (up->serio) {
serio_unregister_port(up->serio);
up->serio = NULL;
}
#endif
} else
uart_remove_one_port(&sunzilog_reg, &up->port); uart_remove_one_port(&sunzilog_reg, &up->port);
} }
......
...@@ -1439,6 +1439,11 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1439,6 +1439,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;
...@@ -1453,20 +1458,20 @@ static struct hid_blacklist { ...@@ -1453,20 +1458,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 },
......
...@@ -223,16 +223,6 @@ static int hiddev_fasync(int fd, struct file *file, int on) ...@@ -223,16 +223,6 @@ static int hiddev_fasync(int fd, struct file *file, int on)
return retval < 0 ? retval : 0; return retval < 0 ? retval : 0;
} }
/*
* De-allocate a hiddev structure
*/
static struct usb_class_driver hiddev_class;
static void hiddev_cleanup(struct hiddev *hiddev)
{
hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
kfree(hiddev);
}
/* /*
* release file op * release file op
...@@ -253,7 +243,7 @@ static int hiddev_release(struct inode * inode, struct file * file) ...@@ -253,7 +243,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
if (list->hiddev->exist) if (list->hiddev->exist)
hid_close(list->hiddev->hid); hid_close(list->hiddev->hid);
else else
hiddev_cleanup(list->hiddev); kfree(list->hiddev);
} }
kfree(list); kfree(list);
...@@ -636,15 +626,21 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -636,15 +626,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) {
...@@ -795,17 +791,21 @@ int hiddev_connect(struct hid_device *hid) ...@@ -795,17 +791,21 @@ int hiddev_connect(struct hid_device *hid)
* This is where hid.c calls us to disconnect a hiddev device from the * This is where hid.c calls us to disconnect a hiddev device from the
* corresponding hid device (usually because the usb device has disconnected) * corresponding hid device (usually because the usb device has disconnected)
*/ */
static struct usb_class_driver hiddev_class;
void hiddev_disconnect(struct hid_device *hid) void hiddev_disconnect(struct hid_device *hid)
{ {
struct hiddev *hiddev = hid->hiddev; struct hiddev *hiddev = hid->hiddev;
hiddev->exist = 0; hiddev->exist = 0;
hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
if (hiddev->open) { if (hiddev->open) {
hid_close(hiddev->hid); hid_close(hiddev->hid);
wake_up_interruptible(&hiddev->wait); wake_up_interruptible(&hiddev->wait);
} else { } else {
hiddev_cleanup(hiddev); kfree(hiddev);
} }
} }
......
...@@ -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
......
/*
* 8253/8254 Programmable Interval Timer
*/
#ifndef _8253PIT_H
#define _8253PIT_H
#define PIT_TICK_RATE 1193182UL
#endif
/*
* 8253/8254 Programmable Interval Timer
*/
#ifndef _8253PIT_H
#define _8253PIT_H
#define PIT_TICK_RATE 1193182UL
#endif
...@@ -732,3 +732,20 @@ COMPATIBLE_IOCTL(SIOCSIWRETRY) ...@@ -732,3 +732,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,12 +17,15 @@ ...@@ -17,12 +17,15 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
struct serio { struct serio {
void *private; void *private;
void *driver; void *port_data;
char *name;
char *phys; char name[32];
char phys[32];
unsigned short idbus; unsigned short idbus;
unsigned short idvendor; unsigned short idvendor;
...@@ -32,31 +35,43 @@ struct serio { ...@@ -32,31 +35,43 @@ 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 *parent, *child;
struct serio_driver *drv; /* Accessed from interrupt, writes must be protected by serio_lock */
struct device dev;
struct list_head node; struct list_head node;
}; };
#define to_serio_port(d) container_of(d, struct serio, dev)
struct serio_dev { struct serio_driver {
void *private; void *private;
char *name; char *description;
int manual_bind;
void (*write_wakeup)(struct serio *); void (*write_wakeup)(struct serio *);
irqreturn_t (*interrupt)(struct serio *, unsigned char, irqreturn_t (*interrupt)(struct serio *, unsigned char,
unsigned int, struct pt_regs *); unsigned int, struct pt_regs *);
void (*connect)(struct serio *, struct serio_dev *dev); void (*connect)(struct serio *, struct serio_driver *drv);
int (*reconnect)(struct serio *); int (*reconnect)(struct serio *);
void (*disconnect)(struct serio *); void (*disconnect)(struct serio *);
void (*cleanup)(struct serio *); void (*cleanup)(struct serio *);
struct device_driver driver;
struct list_head node; struct list_head node;
}; };
#define to_serio_driver(d) container_of(d, struct serio_driver, driver)
int serio_open(struct serio *serio, struct serio_dev *dev); int serio_open(struct serio *serio, struct serio_driver *drv);
void serio_close(struct serio *serio); void serio_close(struct serio *serio);
void serio_rescan(struct serio *serio); void serio_rescan(struct serio *serio);
void serio_reconnect(struct serio *serio); void serio_reconnect(struct serio *serio);
...@@ -64,12 +79,10 @@ irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned in ...@@ -64,12 +79,10 @@ irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned in
void serio_register_port(struct serio *serio); void serio_register_port(struct serio *serio);
void serio_register_port_delayed(struct serio *serio); void serio_register_port_delayed(struct serio *serio);
void __serio_register_port(struct serio *serio);
void serio_unregister_port(struct serio *serio); void serio_unregister_port(struct serio *serio);
void serio_unregister_port_delayed(struct serio *serio); void serio_unregister_port_delayed(struct serio *serio);
void __serio_unregister_port(struct serio *serio); void serio_register_driver(struct serio_driver *drv);
void serio_register_device(struct serio_dev *dev); void serio_unregister_driver(struct serio_driver *drv);
void serio_unregister_device(struct serio_dev *dev);
static __inline__ int serio_write(struct serio *serio, unsigned char data) static __inline__ int serio_write(struct serio *serio, unsigned char data)
{ {
...@@ -79,16 +92,16 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data) ...@@ -79,16 +92,16 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data)
return -1; return -1;
} }
static __inline__ void serio_dev_write_wakeup(struct serio *serio) static __inline__ void serio_drv_write_wakeup(struct serio *serio)
{ {
if (serio->dev && serio->dev->write_wakeup) if (serio->drv && serio->drv->write_wakeup)
serio->dev->write_wakeup(serio); serio->drv->write_wakeup(serio);
} }
static __inline__ void serio_cleanup(struct serio *serio) static __inline__ void serio_cleanup(struct serio *serio)
{ {
if (serio->dev && serio->dev->cleanup) if (serio->drv && serio->drv->cleanup)
serio->dev->cleanup(serio); serio->drv->cleanup(serio);
} }
#endif #endif
......
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