bk://kernel.bkbits.net/vojtech/input
akropel1@rochester.rr.com|ChangeSet|20050307143012|39436 akropel1

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/07 15:30:12+01:00 akropel1@rochester.rr.com 
#   input: hid-debug.h includes resolv_event, which is not used if DEBUG is only
#          enabled in hid-core, but _is_ used when DEBUG is also enabled in hid-input.
#          Mark the function with __attribute__((unused)) to silence the warning
#          when only hid-core is being DEBUGged.
#   
#   Signed-off-by: Adam Kropelin <akropel1@rochester.rr.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-debug.h
#   2005/03/07 15:30:06+01:00 akropel1@rochester.rr.com +1 -1
#   input: hid-debug.h includes resolv_event, which is not used if DEBUG is only
#          enabled in hid-core, but _is_ used when DEBUG is also enabled in hid-input.
#          Mark the function with __attribute__((unused)) to silence the warning
#          when only hid-core is being DEBUGged.
#   
#   Signed-off-by: Adam Kropelin <akropel1@rochester.rr.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:29:15+01:00 dtor_core@ameritech.net 
#   Input: export psmouse module parameters via sysfs:
#             /sys/module/psmouse/parameters/proto
#             /sys/module/psmouse/parameters/rate
#             /sys/module/psmouse/parameters/resetafter
#             /sys/module/psmouse/parameters/resolution
#             /sys/module/psmouse/parameters/smartscroll
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse-base.c
#   2005/03/07 15:29:08+01:00 dtor_core@ameritech.net +40 -18
#   Input: export psmouse module parameters via sysfs:
#             /sys/module/psmouse/parameters/proto
#             /sys/module/psmouse/parameters/rate
#             /sys/module/psmouse/parameters/resetafter
#             /sys/module/psmouse/parameters/resolution
#             /sys/module/psmouse/parameters/smartscroll
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:28:44+01:00 dtor_core@ameritech.net 
#   Input: i8042 - disable MUX mode on some Fujitsu notebooks as it
#          does not seem to be working properly and requires psmouse
#          module to be reloaded several times for touchpad to be  
#          identified correctly.  
#          Since none of these notebooks have external PS/2 ports
#          disabling MUX should have no drawbacks.  
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/03/07 15:28:38+01:00 dtor_core@ameritech.net +47 -4
#   Input: i8042 - disable MUX mode on some Fujitsu notebooks as it
#          does not seem to be working properly and requires psmouse
#          module to be reloaded several times for touchpad to be  
#          identified correctly.  
#          Since none of these notebooks have external PS/2 ports
#          disabling MUX should have no drawbacks.  
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:27:41+01:00 dtor_core@ameritech.net 
#   input: some whitespace and formatting cleanup in Corgi drivers.
#          Also change del_timer to del_timer_sync in corgikbd and
#          add missing del_timer_sync to corgi_ts.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/corgi_ts.c
#   2005/03/07 15:27:35+01:00 dtor_core@ameritech.net +43 -43
#   input: some whitespace and formatting cleanup in Corgi drivers.
#          Also change del_timer to del_timer_sync in corgikbd and
#          add missing del_timer_sync to corgi_ts.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/corgikbd.c
#   2005/03/07 15:27:35+01:00 dtor_core@ameritech.net +43 -45
#   input: some whitespace and formatting cleanup in Corgi drivers.
#          Also change del_timer to del_timer_sync in corgikbd and
#          add missing del_timer_sync to corgi_ts.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:24:32+01:00 dtor_core@ameritech.net 
#   input: Fix compiler warning in trident gameport code with enabled debugging
#          and compiler error in ymfpci when compiled without gameport support.
#   
#   From: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# sound/pci/ymfpci/ymfpci.c
#   2005/03/07 15:24:26+01:00 dtor_core@ameritech.net +1 -1
#   input: Fix compiler warning in trident gameport code with enabled debugging
#          and compiler error in ymfpci when compiled without gameport support.
#   
#   From: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# sound/pci/trident/trident_main.c
#   2005/03/07 15:24:26+01:00 dtor_core@ameritech.net +1 -1
#   input: Fix compiler warning in trident gameport code with enabled debugging
#          and compiler error in ymfpci when compiled without gameport support.
#   
#   From: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:15:42+01:00 c.lucas@ifrance.com 
#   input: convert from pci_module_init to pci_register_driver
#   
#   Signed-off-by: Christophe Lucas <c.lucas@ifrance.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/pcips2.c
#   2005/03/07 15:15:36+01:00 c.lucas@ifrance.com +1 -1
#   input: convert from pci_module_init to pci_register_driver
#   
#   Signed-off-by: Christophe Lucas <c.lucas@ifrance.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/vortex.c
#   2005/03/07 15:15:36+01:00 c.lucas@ifrance.com +1 -1
#   input: convert from pci_module_init to pci_register_driver
#   
#   Signed-off-by: Christophe Lucas <c.lucas@ifrance.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/fm801-gp.c
#   2005/03/07 15:15:36+01:00 c.lucas@ifrance.com +1 -1
#   input: convert from pci_module_init to pci_register_driver
#   
#   Signed-off-by: Christophe Lucas <c.lucas@ifrance.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/emu10k1-gp.c
#   2005/03/07 15:15:36+01:00 c.lucas@ifrance.com +1 -1
#   input: convert from pci_module_init to pci_register_driver
#   
#   Signed-off-by: Christophe Lucas <c.lucas@ifrance.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/cs461x.c
#   2005/03/07 15:15:36+01:00 c.lucas@ifrance.com +1 -1
#   input: convert from pci_module_init to pci_register_driver
#   
#   Signed-off-by: Christophe Lucas <c.lucas@ifrance.com>
#   Signed-off-by: Domen Puncer <domen@coderock.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:14:28+01:00 akropel@rochester.rr.com 
#   input: hid-debug.h uses a C99 feature (range designators) not available in
#          gcc-2.95. Since gcc-2.95 is still a supported compiler for 2.6 and the 
#          initializers as used here add no functional value, this patch removes
#          them. gcc-2.95 is then able to compile hid-core with DEBUG enabled.
#   
#   Signed-off-by: Adam Kropelin <akropel1@rochester.rr.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-debug.h
#   2005/03/07 15:14:22+01:00 akropel@rochester.rr.com +0 -10
#   input: hid-debug.h uses a C99 feature (range designators) not available in
#          gcc-2.95. Since gcc-2.95 is still a supported compiler for 2.6 and the 
#          initializers as used here add no functional value, this patch removes
#          them. gcc-2.95 is then able to compile hid-core with DEBUG enabled.
#   
#   Signed-off-by: Adam Kropelin <akropel1@rochester.rr.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:13:27+01:00 lenz@cs.wisc.edu 
#   input: This patch is for the keyboard on Sharp Zaurus collie and poodle
#          models (SL5000, SL5500, and SL5600).  It uses the devices exported
#          in arch/arm/common/locomo.c.  The pressed state of the keys is now
#          handled by the input layer rather than directly in this driver.
#   
#   More information about the status of Zaurus (and some extra patches
#   if you need to test this out) can be found on my web page at
#   http://www.cs.wisc.edu/~lenz/zaurus
#   
#   Signed-off-by: John Lenz <lenz@cs.wisc.edu>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/locomokbd.c
#   2005/03/07 15:13:21+01:00 lenz@cs.wisc.edu +309 -0
# 
# drivers/input/keyboard/locomokbd.c
#   2005/03/07 15:13:21+01:00 lenz@cs.wisc.edu +0 -0
#   BitKeeper file /home/vojtech/bk/input-new/drivers/input/keyboard/locomokbd.c
# 
# drivers/input/keyboard/Makefile
#   2005/03/07 15:13:21+01:00 lenz@cs.wisc.edu +1 -0
#   input: This patch is for the keyboard on Sharp Zaurus collie and poodle
#          models (SL5000, SL5500, and SL5600).  It uses the devices exported
#          in arch/arm/common/locomo.c.  The pressed state of the keys is now
#          handled by the input layer rather than directly in this driver.
#   
#   More information about the status of Zaurus (and some extra patches
#   if you need to test this out) can be found on my web page at
#   http://www.cs.wisc.edu/~lenz/zaurus
#   
#   Signed-off-by: John Lenz <lenz@cs.wisc.edu>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/Kconfig
#   2005/03/07 15:13:21+01:00 lenz@cs.wisc.edu +9 -0
#   input: This patch is for the keyboard on Sharp Zaurus collie and poodle
#          models (SL5000, SL5500, and SL5600).  It uses the devices exported
#          in arch/arm/common/locomo.c.  The pressed state of the keys is now
#          handled by the input layer rather than directly in this driver.
#   
#   More information about the status of Zaurus (and some extra patches
#   if you need to test this out) can be found on my web page at
#   http://www.cs.wisc.edu/~lenz/zaurus
#   
#   Signed-off-by: John Lenz <lenz@cs.wisc.edu>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:12:03+01:00 lethal@linux-sh.org 
#   New BitKeeper file ``drivers/input/touchscreen/hp680_ts_input.c''
# 
# drivers/input/touchscreen/hp680_ts_input.c
#   2005/03/07 15:11:57+01:00 lethal@linux-sh.org +135 -0
# 
# drivers/input/touchscreen/hp680_ts_input.c
#   2005/03/07 15:11:57+01:00 lethal@linux-sh.org +0 -0
#   BitKeeper file /home/vojtech/bk/input-new/drivers/input/touchscreen/hp680_ts_input.c
# 
# drivers/input/touchscreen/Makefile
#   2005/03/07 15:11:57+01:00 lethal@linux-sh.org +2 -1
#   New BitKeeper file ``drivers/input/touchscreen/hp680_ts_input.c''
# 
# drivers/input/touchscreen/Kconfig
#   2005/03/07 15:11:57+01:00 lethal@linux-sh.org +12 -0
#   input: Add support for the touchscreen found in the hp680 and
#          hp690 jornada devices.
#   
#   Signed-off-by: Andriy Skulysh <askulysh@image.kiev.ua>
#   Signed-off-by: Paul Mundt <lethal@linux-sh.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:10:51+01:00 vojtech@suse.cz 
#   input: Fix a connector name in a comment in lkkbd.c
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/lkkbd.c
#   2005/03/07 15:10:46+01:00 vojtech@suse.cz +2 -2
#   input: Fix a connector name in a comment in lkkbd.c
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:09:59+01:00 vojtech@suse.cz 
#   input: Fix ALPS breakage caused by previous refactoring.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/03/07 15:09:53+01:00 vojtech@suse.cz +25 -32
#   input: Fix ALPS breakage caused by previous refactoring.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 15:07:54+01:00 vojtech@suse.cz 
#   input: Fix two typos in i8042 PnP code.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/03/07 15:07:11+01:00 vojtech@suse.cz +2 -2
#   input: Fix two typos in i8042 PnP code.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/07 14:50:57+01:00 vojtech@suse.cz 
#   Manual merge
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/03/07 14:50:52+01:00 vojtech@suse.cz +0 -1
#   Manual merge
# 
# sound/oss/sonicvibes.c
#   2005/03/07 14:48:09+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/01 14:13:43+01:00 ddstreet@ieee.org 
#   input: Add the option to use cooked coordinates in MicroTouch
#          USB touchscreen driver.
#   
#   From: Dan Streetman <ddstreet@ieee.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/mtouchusb.c
#   2005/03/01 14:13:37+01:00 ddstreet@ieee.org +29 -8
#   input: Add the option to use cooked coordinates in MicroTouch
#          USB touchscreen driver.
#   
#   From: Dan Streetman <ddstreet@ieee.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# Documentation/kernel-parameters.txt
#   2005/03/01 14:13:37+01:00 ddstreet@ieee.org +4 -0
#   input: Add the option to use cooked coordinates in MicroTouch
#          USB touchscreen driver.
#   
#   From: Dan Streetman <ddstreet@ieee.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/03/01 14:02:56+01:00 ddstreet@ieee.org 
#   input: Add MicroTouch (3M) serial touchscreen driver
#   
#   From: Dan Streetman <ddstreet@ieee.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/mtouch.c
#   2005/03/01 14:02:50+01:00 ddstreet@ieee.org +219 -0
# 
# include/linux/serio.h
#   2005/03/01 14:02:50+01:00 ddstreet@ieee.org +1 -0
#   input: Add MicroTouch (3M) serial touchscreen driver
#   
#   From: Dan Streetman <ddstreet@ieee.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/mtouch.c
#   2005/03/01 14:02:50+01:00 ddstreet@ieee.org +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/touchscreen/mtouch.c
# 
# drivers/input/touchscreen/Makefile
#   2005/03/01 14:02:50+01:00 ddstreet@ieee.org +1 -0
#   input: Add MicroTouch (3M) serial touchscreen driver
#   
#   From: Dan Streetman <ddstreet@ieee.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/Kconfig
#   2005/03/01 14:02:50+01:00 ddstreet@ieee.org +11 -0
#   input: Add MicroTouch (3M) serial touchscreen driver
#   
#   From: Dan Streetman <ddstreet@ieee.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/28 12:08:34+01:00 vojtech@suse.cz 
#   Merge suse.cz:/home/vojtech/bk/linus into suse.cz:/home/vojtech/bk/input
# 
# drivers/char/keyboard.c
#   2005/02/28 12:08:31+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/02/28 11:58:50+01:00 vojtech@suse.cz 
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/tmdc.c
#   2005/02/28 11:58:45+01:00 vojtech@suse.cz +2 -2
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/sidewinder.c
#   2005/02/28 11:58:45+01:00 vojtech@suse.cz +21 -21
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/interact.c
#   2005/02/28 11:58:45+01:00 vojtech@suse.cz +2 -2
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/analog.c
#   2005/02/28 11:58:45+01:00 vojtech@suse.cz +1 -1
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/adi.c
#   2005/02/28 11:58:45+01:00 vojtech@suse.cz +10 -9
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/a3d.c
#   2005/02/28 11:58:45+01:00 vojtech@suse.cz +2 -3
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/gameport.c
#   2005/02/28 11:58:45+01:00 vojtech@suse.cz +31 -3
#   input: Make gameport digital joysticks work on 2.6 and x86_64 again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/28 08:48:22+01:00 vojtech@suse.cz 
#   input: Add more PnP IDs to i8042 PnP probe table. BIOS manufacturers
#          are very creative.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/28 08:48:11+01:00 vojtech@suse.cz +6 -0
#   input: Add more PnP IDs to i8042 PnP probe table. BIOS manufacturers
#          are very creative.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/26 09:01:13+01:00 vojtech@suse.cz 
#   input: Fix string formatting in joydump.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/joydump.c
#   2005/02/26 09:01:02+01:00 vojtech@suse.cz +12 -12
#   input: Fix string formatting in joydump.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/26 08:13:30+01:00 dtor_core@ameritech.net 
#   input: set gameport devices' bus so they can be bound to drivers.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/gameport.c
#   2005/02/26 08:13:19+01:00 dtor_core@ameritech.net +1 -0
#   input: set gameport devices' bus so they can be bound to drivers.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/25 21:21:03+01:00 vojtech@suse.cz 
#   input: After testing on real world hardware, it's obvious we can't trust
#          ACPIPnP nor PnPBIOS to properly report the existence of a keyboard
#          and mouse port in all cases. Some BIOSes hide the ports if no mouse
#          or keyboard is connected, causing trouble with eg. KVM switches.
#   
#          The i8042 driver now does read-only probing first, which should
#          not cause any problems even if an i8042 controller really is not
#          present.
#   
#          However, on IA64 we still need to trust ACPI, since legacy-free hardware
#          is common there and invalid port accesses cause exceptions.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/25 21:20:51+01:00 vojtech@suse.cz +6 -7
#   input: After testing on real world hardware, it's obvious we can't trust
#          ACPIPnP nor PnPBIOS to properly report the existence of a keyboard
#          and mouse port in all cases. Some BIOSes hide the ports if no mouse
#          or keyboard is connected, causing trouble with eg. KVM switches.
#   
#          The i8042 driver now does read-only probing first, which should
#          not cause any problems even if an i8042 controller really is not
#          present.
#   
#          However, on IA64 we still need to trust ACPI, since legacy-free hardware
#          is common there and invalid port accesses cause exceptions.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/25 15:27:54+01:00 vojtech@suse.cz 
#   input: Add a missing brace in hid-core.c
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/25 15:27:48+01:00 vojtech@suse.cz +1 -1
#   input: Add a missing brace in hid-core.c
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/25 08:17:35+01:00 vojtech@suse.cz 
#   input: Remove filtering of duplicate events in hid-core. HIDDEV wants them,
#          and hid-input doesn't care, since input does the filtering anyway.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/25 08:17:23+01:00 vojtech@suse.cz +1 -10
#   input: Remove filtering of duplicate events in hid-core. HIDDEV wants them,
#          and hid-input doesn't care, since input does the filtering anyway.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/25 08:06:21+01:00 dtor_core@ameritech.net 
#   input: atkbd - "scroll" is a per-device attribute, don't use global
#          flag in interrupt handler.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/25 08:06:09+01:00 dtor_core@ameritech.net +1 -1
#   input: atkbd - "scroll" is a per-device attribute, don't use global
#          flag in interrupt handler.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 22:02:25+01:00 vojtech@suse.cz 
#   input: Disable scancode event generation in hid-core.c, as it can
#          cause floods of events when devices don't honor the set_idle()
#          call or report noise on absolute values, until a solution for
#          this is found.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-input.c
#   2005/02/24 22:02:13+01:00 vojtech@suse.cz +0 -4
#   input: Disable scancode event generation in hid-core.c, as it can
#          cause floods of events when devices don't honor the set_idle()
#          call or report noise on absolute values, until a solution for
#          this is found.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 21:54:53+01:00 vojtech@suse.cz 
#   input: Print a warning message when PnP fails to find an i8042
#          controller.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/24 21:54:40+01:00 vojtech@suse.cz +43 -42
#   input: Print a warning message when PnP fails to find an i8042
#          controller.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 21:38:18+01:00 vojtech@suse.cz 
#   input: Make the i8042 PnP detection even more BIOS and CONFIG-proof.
#          This now should work with almost any BIOS and kernel config
#          combination.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/24 21:38:07+01:00 vojtech@suse.cz +75 -66
#   input: Make the i8042 PnP detection even more BIOS and CONFIG-proof.
#          This now should work with almost any BIOS and kernel config
#          combination.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 20:37:21+01:00 vojtech@suse.cz 
#   input: Separate dualpoint and passthrough flags in ALPS driver.
#          Some non-dualpoint devices need passthrough enabled.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/24 20:37:08+01:00 vojtech@suse.cz +9 -8
#   input: Separate dualpoint and passthrough flags in ALPS driver.
#          Some non-dualpoint devices need passthrough enabled.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 20:12:05+01:00 vojtech@suse.cz 
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/keyboard.h
#   2005/02/24 20:11:54+01:00 vojtech@suse.cz +1 -1
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/joystick.h
#   2005/02/24 20:11:54+01:00 vojtech@suse.cz +4 -4
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/input.h
#   2005/02/24 20:11:54+01:00 vojtech@suse.cz +1 -1
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/uinput.c
#   2005/02/24 20:11:54+01:00 vojtech@suse.cz +3 -5
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joydev.c
#   2005/02/24 20:11:54+01:00 vojtech@suse.cz +13 -13
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/evdev.c
#   2005/02/24 20:11:54+01:00 vojtech@suse.cz +3 -2
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/char/keyboard.c
#   2005/02/24 20:11:54+01:00 vojtech@suse.cz +3 -1
#   input: Fix usage of *_MAX macros. Check keycode in KDIOSKEYCODE and
#          EVIOCSKEYCODE macros to be <= KEY_MAX. Check off-by one mistakes
#          in keycodemax usage. There was a lot of potential for overwriting
#          memory. Also enlarge NR_KEYS to 256 while we're at it.
#   
#   Found-by: Georgi Guninski <guninski@guninski.com>
#   Initial-patch-by: Linus Torvalds <torvalds@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 15:36:55+01:00 vojtech@suse.cz 
#   input: Make ALPS protocol synchronization dependent on
#          protocol variant to enhance robustness.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.h
#   2005/02/24 15:36:49+01:00 vojtech@suse.cz +11 -5
#   input: Make ALPS protocol synchronization dependent on
#          protocol variant to enhance robustness.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/24 15:36:49+01:00 vojtech@suse.cz +45 -48
#   input: Make ALPS protocol synchronization dependent on
#          protocol variant to enhance robustness.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 15:06:24+01:00 vojtech@suse.cz 
#   input: Fix i8042's interactions with ACPI. Only believe what ACPI
#          tells us if it is enabled, if is PnP enabled, and if is
#          ACPIPnP enabled. It will still lie to us, but it won't be
#          too bad.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/24 15:06:17+01:00 vojtech@suse.cz +57 -28
#   input: Fix i8042's interactions with ACPI. Only believe what ACPI
#          tells us if it is enabled, if is PnP enabled, and if is
#          ACPIPnP enabled. It will still lie to us, but it won't be
#          too bad.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 13:20:20+01:00 vojtech@suse.cz 
#   Merge
# 
# drivers/input/mouse/alps.c
#   2005/02/24 13:20:19+01:00 vojtech@suse.cz +0 -0
#   SCCS merged
# 
# ChangeSet
#   2005/02/24 12:44:37+01:00 vojtech@suse.cz 
#   input: Update kernel documentation to reflect the
#          i8042.noacpi -> i8042.nopnp change.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# Documentation/kernel-parameters.txt
#   2005/02/24 12:44:31+01:00 vojtech@suse.cz +2 -2
#   input: Update kernel documentation to reflect the
#          i8042.noacpi -> i8042.nopnp change.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 11:31:55+01:00 vojtech@suse.cz 
#   input: Workaround in i8042 for PnP BIOS reporting incorrect command
#          register address. If the address is in the standard range,
#          and a non-standard number is reported, we ignore it and use
#          the default.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/24 11:31:49+01:00 vojtech@suse.cz +14 -6
#   input: Workaround in i8042 for PnP BIOS reporting incorrect command
#          register address. If the address is in the standard range,
#          and a non-standard number is reported, we ignore it and use
#          the default.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 10:40:24+01:00 dtor_core@ameritech.net 
#   Input: fix identation in PID driver.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/pid.h
#   2005/02/24 10:40:18+01:00 dtor_core@ameritech.net +14 -14
#   Input: fix identation in PID driver.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/pid.c
#   2005/02/24 10:40:18+01:00 dtor_core@ameritech.net +112 -114
#   Input: fix identation in PID driver.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 10:39:32+01:00 vojtech@suse.cz 
#   input: Rename hid_find_field to hidinput_find_field to
#          match the naming convention in hid-input
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> 
# 
# drivers/usb/input/hid-input.c
#   2005/02/24 10:39:25+01:00 vojtech@suse.cz +2 -2
#   input: Rename hid_find_field to hidinput_find_field to
#          match the naming convention in hid-input
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> 
# 
# ChangeSet
#   2005/02/24 10:31:36+01:00 dtor_core@ameritech.net 
#   input: Fix compilation warning in PID driver and generally
#          repair force feedback effect erase routine that could
#          never have worked.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/pid.c
#   2005/02/24 10:31:29+01:00 dtor_core@ameritech.net +7 -15
#   input: Fix compilation warning in PID driver and generally
#          repair force feedback effect erase routine that could
#          never have worked.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid.h
#   2005/02/24 10:31:29+01:00 dtor_core@ameritech.net +1 -1
#   input: Fix compilation warning in PID driver and generally
#          repair force feedback effect erase routine that could
#          never have worked.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/24 10:31:29+01:00 dtor_core@ameritech.net +3 -3
#   input: Fix compilation warning in PID driver and generally
#          repair force feedback effect erase routine that could
#          never have worked.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 10:20:01+01:00 dtor_core@ameritech.net 
#   input: Fix sermouse not to call serio_open() twice.
#          Bug introduced in last serio update.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/sermouse.c
#   2005/02/24 10:19:54+01:00 dtor_core@ameritech.net +1 -1
#   input: Fix sermouse not to call serio_open() twice.
#          Bug introduced in last serio update.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 10:18:37+01:00 dtor_core@ameritech.net 
#   input: adjust file2alias utility to export aliases for
#          serio drivers (serio:tyNprNidNexN).
#          Move serio_device_id from serio.h to mod_devicetable.h
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# scripts/mod/file2alias.c
#   2005/02/24 10:18:30+01:00 dtor_core@ameritech.net +22 -1
#   input: adjust file2alias utility to export aliases for
#          serio drivers (serio:tyNprNidNexN).
#          Move serio_device_id from serio.h to mod_devicetable.h
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/24 10:18:30+01:00 dtor_core@ameritech.net +1 -9
#   input: adjust file2alias utility to export aliases for
#          serio drivers (serio:tyNprNidNexN).
#          Move serio_device_id from serio.h to mod_devicetable.h
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/mod_devicetable.h
#   2005/02/24 10:18:30+01:00 dtor_core@ameritech.net +10 -0
#   input: adjust file2alias utility to export aliases for
#          serio drivers (serio:tyNprNidNexN).
#          Move serio_device_id from serio.h to mod_devicetable.h
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/24 10:04:38+01:00 vojtech@suse.cz 
#   input: Add support for less usual ALPS touchpads, rearrange code,
#          separate touchpoint/passthrough into its own input device.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.h
#   2005/02/24 10:04:32+01:00 vojtech@suse.cz +6 -2
#   input: Add support for less usual ALPS touchpads, rearrange code,
#          separate touchpoint/passthrough into its own input device.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/24 10:04:32+01:00 vojtech@suse.cz +141 -121
#   input: Add support for less usual ALPS touchpads, rearrange code,
#          separate touchpoint/passthrough into its own input device.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/23 20:43:04+01:00 vojtech@suse.cz 
#   input: Add a missing ';' to hid-core.c
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/23 20:42:52+01:00 vojtech@suse.cz +1 -1
#   input: Add a missing ';' to hid-core.c
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/23 19:37:57+01:00 vojtech@suse.cz 
#   Manual merge
# 
# drivers/input/mouse/alps.c
#   2005/02/23 19:37:51+01:00 vojtech@suse.cz +0 -2
#   Manual merge
# 
# drivers/input/serio/sa1111ps2.c
#   2005/02/23 17:49:58+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# drivers/input/serio/ambakmi.c
#   2005/02/23 17:49:58+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/02/23 17:40:00+01:00 vojtech@suse.cz 
#   input: Fix keyboard scrollwheel support, add horizontal
#          wheel support, and enable both by default.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/23 17:39:54+01:00 vojtech@suse.cz +32 -22
#   input: Fix keyboard scrollwheel support, add horizontal
#          wheel support, and enable both by default.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/21 11:07:58+01:00 vojtech@suse.cz 
#   input: Fix a few conditions in power.c, which kept it from doint
#          anything at all.
#   
#   Found-by: BJ Douma <bjdouma@xs4all.nl>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/power.c
#   2005/02/21 11:07:46+01:00 vojtech@suse.cz +3 -9
#   input: Fix a few conditions in power.c, which kept it from doint
#          anything at all:
#   
#   Found-by: BJ Douma <bjdouma@xs4all.nl>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/16 09:35:42+01:00 dtor_core@ameritech.net 
#   Input: fix timer handling race in sidewinder joystick driver by
#          switching to gameport's polling facilities.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/sidewinder.c
#   2005/02/16 09:35:30+01:00 dtor_core@ameritech.net +7 -13
#   Input: fix timer handling race in sidewinder joystick driver by
#          switching to gameport's polling facilities.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/16 08:51:47+01:00 vojtech@suse.cz 
#   input: Fix Microtouch USB touchscreen Y axis direction.
#          [0,0] should be upper left corner.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/mtouchusb.c
#   2005/02/16 08:51:35+01:00 vojtech@suse.cz +1 -1
#   input: Fix Microtouch USB touchscreen Y axis direction.
#          [0,0] should be upper left corner.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/15 21:05:48+01:00 vojtech@suse.cz 
#   input: Properly ignore padding fields in HID reports.
#   
#   Bug-found-by: Ted <6x0124@yahoo.com.tw>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/15 21:05:37+01:00 vojtech@suse.cz +5 -3
#   input: Properly ignore padding fields in HID reports.
#   
#   Bug-found-by: Ted <6x0124@yahoo.com.tw>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/15 16:05:47+01:00 dtor_core@ameritech.net 
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/gameport.h
#   2005/02/15 16:05:41+01:00 dtor_core@ameritech.net +19 -0
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/tmdc.c
#   2005/02/15 16:05:41+01:00 dtor_core@ameritech.net +10 -15
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/interact.c
#   2005/02/15 16:05:41+01:00 dtor_core@ameritech.net +8 -16
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/guillemot.c
#   2005/02/15 16:05:41+01:00 dtor_core@ameritech.net +8 -15
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/grip_mp.c
#   2005/02/15 16:05:41+01:00 dtor_core@ameritech.net +7 -23
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/grip.c
#   2005/02/15 16:05:40+01:00 dtor_core@ameritech.net +9 -15
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/gf2k.c
#   2005/02/15 16:05:40+01:00 dtor_core@ameritech.net +13 -17
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/cobra.c
#   2005/02/15 16:05:40+01:00 dtor_core@ameritech.net +12 -16
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/analog.c
#   2005/02/15 16:05:40+01:00 dtor_core@ameritech.net +10 -15
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/adi.c
#   2005/02/15 16:05:40+01:00 dtor_core@ameritech.net +11 -14
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/a3d.c
#   2005/02/15 16:05:40+01:00 dtor_core@ameritech.net +17 -21
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/gameport.c
#   2005/02/15 16:05:40+01:00 dtor_core@ameritech.net +41 -1
#   Input: fix race timer handling races in gameport-based joystick drivers
#          by moving pollig timer down into gameport and using spinlock to
#          protect it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/15 15:14:38+01:00 syrjala@sci.fi 
#   input: Some changes to ati_remote key assignments:
#   - Channel up/down keys are reversed on my ATI Remote Wonder.
#   - Use KEY_TV, KEY_DVD and KEY_OK where appropriate.
#   - Replace KEY_PLAYCD with KEY_PLAY.
#   
#   Signed-off-by: Ville Syrjala <syrjala@sci.fi>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/ati_remote.c
#   2005/02/15 15:14:32+01:00 syrjala@sci.fi +6 -6
#   input: Some changes to ati_remote key assignments:
#   - Channel up/down keys are reversed on my ATI Remote Wonder.
#   - Use KEY_TV, KEY_DVD and KEY_OK where appropriate.
#   - Replace KEY_PLAYCD with KEY_PLAY.
#   
#   Signed-off-by: Ville Syrjala <syrjala@sci.fi>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/15 15:13:33+01:00 syrjala@sci.fi 
#   input: Make ati_remote clean up properly when removing either the device or the
#   module.
#   
#   Signed-off-by: Ville Syrjala <syrjala@sci.fi>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/ati_remote.c
#   2005/02/15 15:13:26+01:00 syrjala@sci.fi +3 -21
#   input: Make ati_remote clean up properly when removing either the device or the
#   module.
#   
#   Signed-off-by: Ville Syrjala <syrjala@sci.fi>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/14 07:59:28+01:00 dtor_core@ameritech.net 
#   Input: psmouse should probe for "special" protocols only if max
#          protocol is greater than IMEX so that proto=imps and    
#          proto=exps options work. Fix Kensington case.       
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse-base.c
#   2005/02/14 07:59:16+01:00 dtor_core@ameritech.net +1 -1
#   Input: psmouse should probe for "special" protocols only if max
#          protocol is greater than IMEX so that proto=imps and    
#          proto=exps options work. Fix Kensington case.       
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/13 18:58:47+01:00 petero2@telia.com 
#   input: Store alps hardware version info in the input_dev structure, so that
#          it shows up in /proc/bus/input/devices.
#    
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse.h
#   2005/02/13 18:58:36+01:00 petero2@telia.com +1 -1
#   input: Store alps hardware version info in the input_dev structure, so that
#          it shows up in /proc/bus/input/devices.
#    
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/13 18:58:36+01:00 petero2@telia.com +13 -4
#   input: Store alps hardware version info in the input_dev structure, so that
#          it shows up in /proc/bus/input/devices.
#    
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/12 20:10:55+01:00 vojtech@suse.cz 
#   input: HID list handling cleanup, fix two bugs in pid.c and one in hid-core.c
#          that the cleanup uncovered. Remove a workaround for BTC keyboard 
#          46e:5303, because it's breaking other devices. Instead enable
#          QUIRK_NOGET for this keyboard.
#          Change set_idle handling to use a '0' report ID, meaning all reports
#          instead of iterating over each individual report ID. This shouldn't
#          change much, since most normal devices have only one report with
#          id '0'.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/pid.c
#   2005/02/12 20:10:38+01:00 vojtech@suse.cz +5 -5
#   input: HID list handling cleanup, fix two bugs in pid.c and one in hid-core.c
#          that the cleanup uncovered. Remove a workaround for BTC keyboard 
#          46e:5303, because it's breaking other devices. Instead enable
#          QUIRK_NOGET for this keyboard.
#          Change set_idle handling to use a '0' report ID, meaning all reports
#          instead of iterating over each individual report ID. This shouldn't
#          change much, since most normal devices have only one report with
#          id '0'.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hiddev.c
#   2005/02/12 20:10:38+01:00 vojtech@suse.cz +2 -6
#   input: HID list handling cleanup, fix two bugs in pid.c and one in hid-core.c
#          that the cleanup uncovered. Remove a workaround for BTC keyboard 
#          46e:5303, because it's breaking other devices. Instead enable
#          QUIRK_NOGET for this keyboard.
#          Change set_idle handling to use a '0' report ID, meaning all reports
#          instead of iterating over each individual report ID. This shouldn't
#          change much, since most normal devices have only one report with
#          id '0'.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid.h
#   2005/02/12 20:10:38+01:00 vojtech@suse.cz +1 -2
#   input: HID list handling cleanup, fix two bugs in pid.c and one in hid-core.c
#          that the cleanup uncovered. Remove a workaround for BTC keyboard 
#          46e:5303, because it's breaking other devices. Instead enable
#          QUIRK_NOGET for this keyboard.
#          Change set_idle handling to use a '0' report ID, meaning all reports
#          instead of iterating over each individual report ID. This shouldn't
#          change much, since most normal devices have only one report with
#          id '0'.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-input.c
#   2005/02/12 20:10:38+01:00 vojtech@suse.cz +21 -15
#   input: HID list handling cleanup, fix two bugs in pid.c and one in hid-core.c
#          that the cleanup uncovered. Remove a workaround for BTC keyboard 
#          46e:5303, because it's breaking other devices. Instead enable
#          QUIRK_NOGET for this keyboard.
#          Change set_idle handling to use a '0' report ID, meaning all reports
#          instead of iterating over each individual report ID. This shouldn't
#          change much, since most normal devices have only one report with
#          id '0'.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/12 20:10:38+01:00 vojtech@suse.cz +20 -92
#   input: HID list handling cleanup, fix two bugs in pid.c and one in hid-core.c
#          that the cleanup uncovered. Remove a workaround for BTC keyboard 
#          46e:5303, because it's breaking other devices. Instead enable
#          QUIRK_NOGET for this keyboard.
#          Change set_idle handling to use a '0' report ID, meaning all reports
#          instead of iterating over each individual report ID. This shouldn't
#          change much, since most normal devices have only one report with
#          id '0'.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/12 20:05:32+01:00 vojtech@suse.cz 
#   input: Add pin numbers to parkbd.c documentation.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/parkbd.c
#   2005/02/12 20:05:21+01:00 vojtech@suse.cz +8 -8
#   input: Add pin numbers to parkbd.c documentation.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/12 08:18:35+01:00 davej@redhat.com 
#   input: Looks like someone forgot the ARCH_
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/char/keyboard.c
#   2005/02/12 08:18:24+01:00 davej@redhat.com +1 -1
#   input: Looks like someone forgot the ARCH_
#   
#   Signed-off-by: Dave Jones <davej@redhat.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/11 17:08:14+01:00 n1gp@hotmail.com 
#   input: Fix keybit initialization in MK712 touchscreen driver.
#          With this, the driver is tested to work properly.
#   
#   From: Richard Koch <n1gp@hotmail.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/mk712.c
#   2005/02/11 17:08:07+01:00 n1gp@hotmail.com +1 -1
#   input: Fix keybit initialization in MK712 touchscreen driver.
#          With this, the driver is tested to work properly.
#   
#   From: Richard Koch <n1gp@hotmail.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/11 01:23:40-05:00 dtor_core@ameritech.net 
#   Input: remove gameport->private in favor of using driver-specific data
#          in device structure, add gameport_get/set_drvdata to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/gameport.h
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +14 -1
#   Add gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/tmdc.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/sidewinder.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/interact.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/guillemot.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +5 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/grip_mp.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -3
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/grip.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/gf2k.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/cobra.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/analog.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +5 -2
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/adi.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +4 -3
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# drivers/input/joystick/a3d.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +6 -4
#   Use gameport_get/set_drvdata to access driver-specific data in gameport.
# 
# ChangeSet
#   2005/02/11 01:21:32-05:00 dtor_core@ameritech.net 
#   Input: complete gameport sysfs integration, ports are now
#          devices in driver model. Implemented similarly to serio.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/gameport.h
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +43 -21
#   Complete sysfs integration.
# 
# drivers/input/gameport/gameport.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +536 -50
#   Complete sysfs integration.
# 
# ChangeSet
#   2005/02/11 01:21:02-05:00 dtor_core@ameritech.net 
#   Input: integrate gameport drivers info dribver model/sysfs,
#          create "gameport" bus. drivers' connect() routines
#          now return error code instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/gameport.h
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +4 -2
#   Add device_driver structure to gameport_driver; make connect()
#   return error code instead of void.
# 
# drivers/input/joystick/tmdc.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +29 -24
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/sidewinder.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +53 -22
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/joydump.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +14 -6
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/interact.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +23 -9
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/guillemot.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +31 -22
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/grip_mp.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +36 -20
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/grip.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +29 -32
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/gf2k.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +29 -13
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/cobra.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +26 -16
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/analog.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +32 -20
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/adi.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +30 -33
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/joystick/a3d.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +31 -13
#   Sysfs integration; make connect() return error code instead of void.
# 
# drivers/input/gameport/gameport.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +39 -0
#   Start of sysfs integration - make gameport drivers part of
#   driver model.
# 
# drivers/Makefile
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +1 -1
#   Move input/gameport ahead of input/ since we need gameport
#   bus registered before we start adding joystick drivers.
# 
# ChangeSet
#   2005/02/11 01:20:30-05:00 dtor_core@ameritech.net 
#   Input: convert sound/pci to dynamic gameport allocation.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# sound/pci/ymfpci/ymfpci_main.c
#   2005/02/09 22:16:24-05:00 dtor_core@ameritech.net +1 -8
#   Convert to dynamic gameport allocation.
# 
# sound/pci/ymfpci/ymfpci.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +92 -57
#   Convert to dynamic gameport allocation.
# 
# sound/pci/via82xx.c
#   2005/02/09 22:16:24-05:00 dtor_core@ameritech.net +65 -24
#   Convert to dynamic gameport allocation.
# 
# sound/pci/trident/trident_main.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +42 -45
#   Convert to dynamic gameport allocation.
# 
# sound/pci/trident/trident.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +1 -1
#   Convert to dynamic gameport allocation.
# 
# sound/pci/sonicvibes.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +44 -11
#   Convert to dynamic gameport allocation.
# 
# sound/pci/es1968.c
#   2005/02/09 22:16:24-05:00 dtor_core@ameritech.net +56 -20
#   Convert to dynamic gameport allocation.
# 
# sound/pci/es1938.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +42 -10
#   Convert to dynamic gameport allocation.
# 
# sound/pci/ens1370.c
#   2005/02/09 22:16:24-05:00 dtor_core@ameritech.net +81 -41
#   Convert to dynamic gameport allocation.
# 
# sound/pci/cs46xx/cs46xx_lib.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +39 -42
#   Convert to dynamic gameport allocation.
# 
# sound/pci/cs4281.c
#   2005/02/09 22:16:24-05:00 dtor_core@ameritech.net +46 -45
#   Convert to dynamic gameport allocation.
# 
# sound/pci/cmipci.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +70 -34
#   Convert to dynamic gameport allocation.
# 
# sound/pci/azt3328.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +68 -43
#   Convert to dynamic gameport allocation.
# 
# sound/pci/au88x0/au88x0_game.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +26 -23
#   Convert to dynamic gameport allocation.
# 
# sound/pci/au88x0/au88x0.h
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +1 -1
#   Convert to dynamic gameport allocation.
# 
# sound/pci/au88x0/au88x0.c
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +3 -4
#   Convert to dynamic gameport allocation.
# 
# sound/pci/als4000.c
#   2005/02/09 22:16:24-05:00 dtor_core@ameritech.net +73 -38
#   Convert to dynamic gameport allocation.
# 
# include/sound/ymfpci.h
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +7 -7
#   Convert to dynamic gameport allocation.
# 
# include/sound/trident.h
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +2 -2
#   Convert to dynamic gameport allocation.
# 
# include/sound/cs46xx.h
#   2005/02/09 22:16:23-05:00 dtor_core@ameritech.net +2 -2
#   Convert to dynamic gameport allocation.
# 
# ChangeSet
#   2005/02/11 01:20:08-05:00 dtor_core@ameritech.net 
#   Input: convert sound/oss to dynamic gameport allocation.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# sound/oss/trident.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +29 -10
#   Convert to dynamic gameport allocation.
# 
# sound/oss/sonicvibes.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +36 -13
#   Convert to dynamic gameport allocation.
# 
# sound/oss/mad16.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +31 -16
#   Convert to dynamic gameport allocation.
# 
# sound/oss/esssolo1.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +34 -13
#   Convert to dynamic gameport allocation.
# 
# sound/oss/es1371.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +32 -20
#   Convert to dynamic gameport allocation.
# 
# sound/oss/es1370.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +22 -12
#   Convert to dynamic gameport allocation.
# 
# sound/oss/cmpci.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +65 -35
#   Convert to dynamic gameport allocation.
# 
# ChangeSet
#   2005/02/11 01:19:36-05:00 dtor_core@ameritech.net 
#   Input: convert input/gameport to dynamic gameport allocation.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/gameport.h
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +0 -3
#   drop input_id as nobody really uses it.
# 
# drivers/input/joystick/a3d.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +28 -31
#   Switch to dynamic gameport allocation.
# 
# drivers/input/gameport/vortex.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +34 -34
#   Switch to dynamic gameport allocation.
# 
# drivers/input/gameport/ns558.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +58 -62
#   Switch to dynamic gameport allocation.
# 
# drivers/input/gameport/lightning.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +108 -68
#   Switch to dynamic gameport allocation.
# 
# drivers/input/gameport/fm801-gp.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +29 -28
#   Switch to dynamic gameport allocation.
# 
# drivers/input/gameport/emu10k1-gp.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +20 -20
#   Switch to dynamic gameport allocation.
# 
# drivers/input/gameport/cs461x.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +9 -20
#   Switch to dynamic gameport allocation.
# 
# ChangeSet
#   2005/02/11 01:18:48-05:00 dtor_core@ameritech.net 
#   Input: prepare for dynamic gameport allocation:
#          - provide functions to allocate and free gameports;
#          - provide functions to properly set name and phys;
#          - dynamically allocated gameports are automatically
#            announced in kernel logs and freed when unregistered.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/gameport.h
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +31 -7
#   Provide functions to dynamically allocate and free gameports.
# 
# drivers/input/gameport/gameport.c
#   2005/02/10 19:00:00-05:00 dtor_core@ameritech.net +24 -0
#   Support dynamic gameport allocation.
# 
# ChangeSet
#   2005/02/11 01:18:29-05:00 dtor_core@ameritech.net 
#   Input: make connect and disconnect methods mandatory for gameport
#          drivers since that's where gameport_{open|close} are called
#          from to actually bind driver to a port.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/gameport/gameport.c
#   2005/02/09 01:35:11-05:00 dtor_core@ameritech.net +4 -5
#   Connect and disconnect handlers are now mandatory.
# 
# ChangeSet
#   2005/02/11 01:09:59-05:00 dtor_core@ameritech.net 
#   Input: more renames in gameport in preparations to sysfs integration
#          - gameport_dev -> gameport_driver
#          - gameport_[un]register_device -> gameport_[un]register_driver
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/gameport.h
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +6 -6
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/tmdc.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/sidewinder.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/joydump.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +6 -6
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/interact.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/guillemot.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/grip_mp.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/grip.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/gf2k.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/cobra.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/analog.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +9 -9
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/adi.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/joystick/a3d.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport_dev to gameport_driver
# 
# drivers/input/gameport/gameport.c
#   2005/02/09 01:09:41-05:00 dtor_core@ameritech.net +26 -26
#   Rename gameport_dev to gameport_driver
# 
# ChangeSet
#   2005/02/11 01:09:43-05:00 dtor_core@ameritech.net 
#   Input: rename gameport->driver to gameport->port_data in preparation
#          to sysfs integration.
#     
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# sound/pci/au88x0/au88x0_game.c
#   2005/02/09 01:09:23-05:00 dtor_core@ameritech.net +7 -8
#   Rename gameport->driver to gameport->port_data
# 
# sound/oss/trident.c
#   2005/02/09 01:09:23-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport->driver to gameport->port_data
# 
# include/linux/gameport.h
#   2005/02/09 01:09:23-05:00 dtor_core@ameritech.net +2 -2
#   Rename gameport->driver to gameport->port_data
# 
# drivers/input/joystick/a3d.c
#   2005/02/09 01:09:23-05:00 dtor_core@ameritech.net +4 -4
#   Rename gameport->driver to gameport->port_data
# 
# drivers/input/gameport/vortex.c
#   2005/02/09 01:09:23-05:00 dtor_core@ameritech.net +5 -5
#   Rename gameport->driver to gameport->port_data
# 
# drivers/input/gameport/lightning.c
#   2005/02/09 01:09:23-05:00 dtor_core@ameritech.net +4 -4
#   Rename gameport->driver to gameport->port_data
# 
# ChangeSet
#   2005/02/09 20:48:10+01:00 vojtech@suse.cz 
#   input: Fix Elo touchscreen touch detection.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/elo.c
#   2005/02/09 20:47:58+01:00 vojtech@suse.cz +2 -2
#   input: Fix Elo touchscreen touch detection.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/09 10:17:53+01:00 jbj1@ultraemail.net 
#   input: Fix a code example in a comment in hiddev.c
#   
#   From: Jens B. Jorgensen <jbj1@ultraemail.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/hiddev.h
#   2005/02/09 10:17:47+01:00 jbj1@ultraemail.net +2 -2
#   input: Fix a code example in a comment in hiddev.c
#   
#   From: Jens B. Jorgensen <jbj1@ultraemail.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/09 10:09:47+01:00 vojtech@suse.cz 
#   input: Add support for serial ELO touchscreens, including
#          Elo IntelliTouch, AccuTouch and SecureTouch.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/elo.c
#   2005/02/09 10:09:40+01:00 vojtech@suse.cz +315 -0
# 
# include/linux/serio.h
#   2005/02/09 10:09:40+01:00 vojtech@suse.cz +1 -0
#   input: Add support for serial ELO touchscreens, including
#          Elo IntelliTouch, AccuTouch and SecureTouch.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/elo.c
#   2005/02/09 10:09:40+01:00 vojtech@suse.cz +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/touchscreen/elo.c
# 
# drivers/input/touchscreen/Makefile
#   2005/02/09 10:09:40+01:00 vojtech@suse.cz +1 -0
#   input: Add support for serial ELO touchscreens, including
#          Elo IntelliTouch, AccuTouch and SecureTouch.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/Kconfig
#   2005/02/09 10:09:40+01:00 vojtech@suse.cz +13 -0
#   input: Add support for serial ELO touchscreens, including
#          Elo IntelliTouch, AccuTouch and SecureTouch.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/09 08:24:55+01:00 dtor_core@ameritech.net 
#   Input: alps - fix protocol validation rules causing touchpad
#          to lose sync if an absolute packet is received after
#          a relative packet with negative Y displacement.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/09 08:24:43+01:00 dtor_core@ameritech.net +2 -2
#   Input: alps - fix protocol validation rules causing touchpad
#          to lose sync if an absolute packet is received after
#          a relative packet with negative Y displacement.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 19:04:58+01:00 castet.matthieu@free.fr 
#   input: this patch turns off the pc speaker when pcspkr.ko is unloaded,
#          else it would never stop
#   
#   Signed-off-by: Matthieu Castet <castet.matthieu@free.fr>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/pcspkr.c
#   2005/02/08 19:04:45+01:00 castet.matthieu@free.fr +2 -0
#   input: this patch turns off the pc speaker when pcspkr.ko is unloaded,
#          else it would never stop
#   
#   Signed-off-by: Matthieu Castet <castet.matthieu@free.fr>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 18:00:02+01:00 svrmgrl@gmx.net 
#   input: Add a new ID to the Logitech ForceFeedback joystick driver.
#   
#   From: Rainer Kümmerle <svrmgrl@gmx.net>
#   Acked-by: Johann Deneux <johann.deneux@it.uu.se>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-lgff.c
#   2005/02/08 17:59:55+01:00 svrmgrl@gmx.net +1 -0
#   input: Add a new ID to the Logitech ForceFeedback joystick driver.
#   
#   From: Rainer Kümmerle <svrmgrl@gmx.net>
#   Acked-by: Johann Deneux <johann.deneux@it.uu.se>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-ff.c
#   2005/02/08 17:59:55+01:00 svrmgrl@gmx.net +1 -0
#   input: Add a new ID to the Logitech ForceFeedback joystick driver.
#   
#   From: Rainer Kümmerle <svrmgrl@gmx.net>
#   Acked-by: Johann Deneux <johann.deneux@it.uu.se>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 17:53:43+01:00 hal@realmsys.com 
#   input: Fix range checks for the HIDIOC[GS]USAGES ioctl() to allow
#          reading full number of bytes.
#   
#   From: Hal Tolley <hal@realmsys.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hiddev.c
#   2005/02/08 17:53:37+01:00 hal@realmsys.com +2 -3
#   input: Fix range checks for the HIDIOC[GS]USAGES ioctl() to allow
#          reading full number of bytes.
#   
#   From: Hal Tolley <hal@realmsys.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 17:37:12+01:00 vojtech@suse.cz 
#   input: Move #include <linux/interrupt.h> inside #ifdef __KERNEL__
#          in serio.h, to make it userspace-compilable.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/08 17:37:05+01:00 vojtech@suse.cz +1 -1
#   input: Move #include <linux/interrupt.h> inside #ifdef __KERNEL__
#          in serio.h, to make it userspace-compilable.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 17:35:59+01:00 vojtech@suse.cz 
#   input: Change touchscreen drivers NOT to rescale their values
#          to a 4:3 shape.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/mk712.c
#   2005/02/08 17:35:52+01:00 vojtech@suse.cz +3 -3
#   input: Change touchscreen drivers NOT to rescale their values
#          to a 4:3 shape.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/gunze.c
#   2005/02/08 17:35:52+01:00 vojtech@suse.cz +4 -4
#   input: Change touchscreen drivers NOT to rescale their values
#          to a 4:3 shape.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 16:05:23+01:00 vojtech@suse.cz 
#   Merge suse.cz:/home/vojtech/bk/linus into suse.cz:/home/vojtech/bk/input
# 
# drivers/input/mousedev.c
#   2005/02/08 16:05:20+01:00 vojtech@suse.cz +0 -2
#   Auto merged
# 
# ChangeSet
#   2005/02/08 10:27:30+01:00 stuart_hayes@dell.com 
#   input: A Chicony keyboard doesn't like get_report on its non-exisiting
#          PS/2 mouse interface. Add to HID blacklist.
#   
#   From: Stuart Hayes <stuart_hayes@dell.com>
#   Seen-by: Pete Zaitcev <zaitcev@redhat.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/08 10:27:15+01:00 stuart_hayes@dell.com +6 -1
#   input: A Chicony keyboard doesn't like get_report on its non-exisiting
#          PS/2 mouse interface. Add to HID blacklist.
#   
#   From: Stuart Hayes <stuart_hayes@dell.com>
#   Seen-by: Pete Zaitcev <zaitcev@redhat.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 10:20:19+01:00 akpm@osdl.org 
#   input: On some architectures the atomic ops return `long'. Fix
#          a printk() in serio.c to take that into account.
#   
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/08 10:20:08+01:00 akpm@osdl.org +1 -1
#   input: On some architectures the atomic ops return `long'. Fix
#          a printk() in serio.c to take that into account.
#   
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 10:18:37+01:00 dtor_core@ameritech.net 
#   Input: make sure that all instances of ns558 are released
#          upon module unload.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/ns558.c
#   2005/02/08 10:18:25+01:00 dtor_core@ameritech.net +2 -3
#   Input: make sure that all instances of ns558 are released
#          upon module unload.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/08 08:53:09+01:00 rufus-kernel@hackish.org 
#   input: For now, a bug in the PSX controllers support in gamecon prevents
#   hot-swapping of such controllers. If a controllers is removed then all
#   the controllers stop working and cpu usage gets high. The attached patch
#   (against 2.6.11-rc3) corrects this bug by checking the information read
#   from the controller. If the message length is bigger than the maximum
#   possible, then it means the controller is not there and therefore this
#   value should be discarded.
#   
#   Note that this is a re-send of a previous patch now that the patch of
#   Peter (which had to be applied before this one) has been intregrated in
#   the vanilla kernel. It's Peter's version modified to apply cleanly
#   against 2.6.11-rc3 plus a fix in the comment.
#   
#   Signed-off-by: Peter Nelson <rufus-kernel@hackish.org>
#   Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
# 
# drivers/input/joystick/gamecon.c
#   2005/02/08 08:52:57+01:00 rufus-kernel@hackish.org +11 -8
#   input: For now, a bug in the PSX controllers support in gamecon prevents
#   hot-swapping of such controllers. If a controllers is removed then all
#   the controllers stop working and cpu usage gets high. The attached patch
#   (against 2.6.11-rc3) corrects this bug by checking the information read
#   from the controller. If the message length is bigger than the maximum
#   possible, then it means the controller is not there and therefore this
#   value should be discarded.
#   
#   Note that this is a re-send of a previous patch now that the patch of
#   Peter (which had to be applied before this one) has been intregrated in
#   the vanilla kernel. It's Peter's version modified to apply cleanly
#   against 2.6.11-rc3 plus a fix in the comment.
#   
#   Signed-off-by: Peter Nelson <rufus-kernel@hackish.org>
#   Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
# 
# ChangeSet
#   2005/02/07 21:13:22+01:00 krautz@gmail.com 
#   input: Make the polling interval for mice a configurable parameter
#          of the HID driver. This is useful when a faster response
#          from a mouse is beneficial, ie games.
#   
#   Signed-off-by: Mikkel Krautz <krautz@gmail.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/07 21:13:10+01:00 krautz@gmail.com +12 -1
#   input: Make the polling interval for mice a configurable parameter
#          of the HID driver. This is useful when a faster response
#          from a mouse is beneficial, ie games.
#   
#   Signed-off-by: Mikkel Krautz <krautz@gmail.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# Documentation/kernel-parameters.txt
#   2005/02/07 21:13:10+01:00 krautz@gmail.com +4 -0
#   input: Make the polling interval for mice a configurable parameter
#          of the HID driver. This is useful when a faster response
#          from a mouse is beneficial, ie games.
#   
#   Signed-off-by: Mikkel Krautz <krautz@gmail.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/07 20:46:26+01:00 vojtech@silver.ucw.cz 
#   input: Fix i8042 PnP printk()'s and pnp_driver name.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/07 20:46:13+01:00 vojtech@silver.ucw.cz +5 -5
#   input: Fix i8042 PnP printk()'s and pnp_driver name.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/07 19:00:24+01:00 castet.matthieu@free.fr 
#   input: Now that ACPIPnP is available, replace ACPI probing in i8042
#          with PnP probing.
#   
#   From: Matthieu Castet <castet.matthieu@free.fr>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/07 19:00:12+01:00 castet.matthieu@free.fr +4 -4
#   input: Now that ACPIPnP is available, replace ACPI probing in i8042
#          with PnP probing.
#   
#   From: Matthieu Castet <castet.matthieu@free.fr>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2005/02/07 19:00:12+01:00 castet.matthieu@free.fr +63 -133
#   input: Now that ACPIPnP is available, replace ACPI probing in i8042
#          with PnP probing.
#   
#   From: Matthieu Castet <castet.matthieu@free.fr>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/07 18:32:36+01:00 duraid@octopus.com.au 
#   input: Properly set input.phys in Griffin Powermate driver.
#   
#   From: Duraid Madina <duraid@octopus.com.au>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/powermate.c
#   2005/02/07 18:32:16+01:00 duraid@octopus.com.au +1 -0
#   
#     Click [Discard] again if you really want to unedit this file,
#     or type Control-l to go back and work on the comments.
#   
#     Warning!  The changes to this file shown below will be lost.
# 
# ChangeSet
#   2005/02/07 18:30:35+01:00 vojtech@silver.ucw.cz 
#   input: Do a kill_fasync() in input handlers on device disconnect
#          to notify a client using poll() that the device is gone.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/tsdev.c
#   2005/02/07 18:30:18+01:00 vojtech@silver.ucw.cz +3 -0
#   input: Do a kill_fasync() in input handlers on device disconnect
#          to notify a client using poll() that the device is gone.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mousedev.c
#   2005/02/07 18:30:18+01:00 vojtech@silver.ucw.cz +3 -0
#   input: Do a kill_fasync() in input handlers on device disconnect
#          to notify a client using poll() that the device is gone.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joydev.c
#   2005/02/07 18:30:18+01:00 vojtech@silver.ucw.cz +3 -0
#   input: Do a kill_fasync() in input handlers on device disconnect
#          to notify a client using poll() that the device is gone.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/evdev.c
#   2005/02/07 18:30:17+01:00 vojtech@silver.ucw.cz +3 -0
#   input: Do a kill_fasync() in input handlers on device disconnect
#          to notify a client using poll() that the device is gone.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/07 13:09:39+01:00 dtor_core@ameritech.net 
#   Input: fix compie error in twidjoy.c
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/twidjoy.c
#   2005/02/07 13:09:33+01:00 dtor_core@ameritech.net +3 -1
#   Input: fix compie error in twidjoy.c
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/07 10:53:26+01:00 vojtech@suse.cz 
#   input: This patch fixes an oops in ns558 when no ports are found and
#   at the same time the driver gets registered with the PnP subsystem.
#   Since there is no need for port->type struct member, it removes it.
#   Patch based on a patch from Matthieu Castet <castet.matthieu@free.fr>
#   and Adam Belay <ambx1@neo.rr.com>
#     
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/ns558.c
#   2005/02/07 10:53:19+01:00 vojtech@suse.cz +19 -27
#   input: This patch fixes an oops in ns558 when no ports are found and
#   at the same time the driver gets registered with the PnP subsystem.
#   Since there is no need for port->type struct member, it removes it.
#   Patch based on a patch from Matthieu Castet <castet.matthieu@free.fr>
#   and Adam Belay <ambx1@neo.rr.com>
#     
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 20:56:49+01:00 bunk@stusta.de 
#   input: This patch removes the bouncing email address of Victor Krapivin from
#   MODULE_AUTHOR.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/cs461x.c
#   2005/02/06 20:56:36+01:00 bunk@stusta.de +1 -1
#   input: This patch removes the bouncing email address of Victor Krapivin from
#   MODULE_AUTHOR.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 20:47:57+01:00 juhl-lkml@dif.dk 
#   input: ere's a patch that removes a few pointless comparisons; "scancode" is
#   unsigned so it can never be <0 which makes the test pointless.
#   Also, there are a few instances where signed and unsigned variables are
#   comared, and as far as I can tell they really should just all be unsigned.
#   
#   Signed-off-by: Jesper Juhl <juhl-lkml@dif.dk>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/char/keyboard.c
#   2005/02/06 20:47:40+01:00 juhl-lkml@dif.dk +5 -5
#   input: ere's a patch that removes a few pointless comparisons; "scancode" is
#   unsigned so it can never be <0 which makes the test pointless.
#   Also, there are a few instances where signed and unsigned variables are
#   comared, and as far as I can tell they really should just all be unsigned.
#   
#   Signed-off-by: Jesper Juhl <juhl-lkml@dif.dk>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 20:19:36+01:00 pingc@wacom.com 
#   input: This patch adds support for a Wacom new tablet, Intuos3, and its associated
#   tools.
#   
#   From: Ping Cheng <pingc@wacom.com>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/wacom.c
#   2005/02/06 20:19:22+01:00 pingc@wacom.com +262 -73
#   input: This patch adds support for a Wacom new tablet, Intuos3, and its associated
#   tools.
#   
#   From: Ping Cheng <pingc@wacom.com>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 19:56:01+01:00 vojtech@silver.ucw.cz 
#   input: Fix ExplorerPS/2 wheel emulation for wheel events > 8 ticks.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mousedev.c
#   2005/02/06 19:55:46+01:00 vojtech@silver.ucw.cz +1 -1
#   input: Fix ExplorerPS/2 wheel emulation for wheel events > 8 ticks.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 19:49:20+01:00 vojtech@silver.ucw.cz 
#   input: Typo fix in parkbd.c comment
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/parkbd.c
#   2005/02/06 19:49:08+01:00 vojtech@silver.ucw.cz +1 -1
#   input: Typo fix in parkbd.c comment
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 18:04:33+01:00 vojtech@silver.ucw.cz 
#   input: Document the adapter schematic needed for parkbd.c, right
#          in the source.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/parkbd.c
#   2005/02/06 18:04:17+01:00 vojtech@silver.ucw.cz +33 -17
#   input: Document the adapter schematic needed for parkbd.c, right
#          in the source.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 15:55:16+01:00 akropel1@rochester.rr.com 
#   I have a buggy USB HID device (APC SmartUPS) in which the designers
#   forgot that ReportCount is a global item. Consequently, according to the
#   report descriptor, several reports have multiple copies of the same
#   usage in each field. When you actually query the device, however, only a
#   single copy of the usage is returned. hid-core catches the expected vs.
#   actual length mismatch and fails the transfer. This effectively makes
#   the buggy reports inaccessible even though enough data is present to
#   populate one usage (which is all userspace wants anyway).
#   
#   This patch changes hid-core to only warn (if debug is enabled) on such
#   reports rather than failing the transfer.
#   
#   Signed-off-by: Adam Kropelin <akropel1@rochester.rr.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/06 15:55:02+01:00 akropel1@rochester.rr.com +1 -3
#   I have a buggy USB HID device (APC SmartUPS) in which the designers
#   forgot that ReportCount is a global item. Consequently, according to the
#   report descriptor, several reports have multiple copies of the same
#   usage in each field. When you actually query the device, however, only a
#   single copy of the usage is returned. hid-core catches the expected vs.
#   actual length mismatch and fails the transfer. This effectively makes
#   the buggy reports inaccessible even though enough data is present to
#   populate one usage (which is all userspace wants anyway).
#   
#   This patch changes hid-core to only warn (if debug is enabled) on such
#   reports rather than failing the transfer.
#   
#   Signed-off-by: Adam Kropelin <akropel1@rochester.rr.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 15:46:02+01:00 cl81@gmx.net 
#   input: Typo fix in atkbd.c comment
#   
#   From: Christian Ludwig <cl81@gmx.net>
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/06 15:45:37+01:00 cl81@gmx.net +1 -1
#   input: Typo fix in atkbd.c comment
#   
#   From: Christian Ludwig <cl81@gmx.net>
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 14:34:19+01:00 deller@gmx.de 
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/hp_sdc_mlc.c
#   2005/02/06 14:34:07+01:00 deller@gmx.de +358 -0
# 
# drivers/input/serio/hp_sdc_mlc.c
#   2005/02/06 14:34:07+01:00 deller@gmx.de +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/serio/hp_sdc_mlc.c
# 
# drivers/input/serio/hp_sdc.c
#   2005/02/06 14:34:06+01:00 deller@gmx.de +1055 -0
# 
# drivers/input/serio/hil_mlc.c
#   2005/02/06 14:34:06+01:00 deller@gmx.de +949 -0
# 
# drivers/input/serio/hp_sdc.c
#   2005/02/06 14:34:06+01:00 deller@gmx.de +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/serio/hp_sdc.c
# 
# drivers/input/serio/hil_mlc.c
#   2005/02/06 14:34:06+01:00 deller@gmx.de +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/serio/hil_mlc.c
# 
# drivers/input/mouse/hil_ptr.c
#   2005/02/06 14:34:05+01:00 deller@gmx.de +414 -0
# 
# drivers/input/mouse/hil_ptr.c
#   2005/02/06 14:34:05+01:00 deller@gmx.de +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/mouse/hil_ptr.c
# 
# drivers/input/misc/hp_sdc_rtc.c
#   2005/02/06 14:34:04+01:00 deller@gmx.de +724 -0
# 
# drivers/input/misc/hp_sdc_rtc.c
#   2005/02/06 14:34:04+01:00 deller@gmx.de +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/misc/hp_sdc_rtc.c
# 
# drivers/input/keyboard/hilkbd.c
#   2005/02/06 14:34:03+01:00 deller@gmx.de +343 -0
# 
# drivers/input/keyboard/hilkbd.c
#   2005/02/06 14:34:03+01:00 deller@gmx.de +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/keyboard/hilkbd.c
# 
# drivers/input/keyboard/hil_kbd.c
#   2005/02/06 14:34:01+01:00 deller@gmx.de +375 -0
# 
# drivers/input/serio/gscps2.c
#   2005/02/06 14:34:01+01:00 deller@gmx.de +2 -2
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/Makefile
#   2005/02/06 14:34:01+01:00 deller@gmx.de +2 -0
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/Kconfig
#   2005/02/06 14:34:01+01:00 deller@gmx.de +27 -1
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/Makefile
#   2005/02/06 14:34:01+01:00 deller@gmx.de +1 -0
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/Kconfig
#   2005/02/06 14:34:01+01:00 deller@gmx.de +8 -0
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/Makefile
#   2005/02/06 14:34:01+01:00 deller@gmx.de +1 -0
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/Kconfig
#   2005/02/06 14:34:01+01:00 deller@gmx.de +8 -0
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/hpps2atkbd.h
#   2005/02/06 14:34:01+01:00 deller@gmx.de +4 -7
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/hil_kbd.c
#   2005/02/06 14:34:01+01:00 deller@gmx.de +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/keyboard/hil_kbd.c
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/06 14:34:01+01:00 deller@gmx.de +8 -6
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/Makefile
#   2005/02/06 14:34:01+01:00 deller@gmx.de +3 -0
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/Kconfig
#   2005/02/06 14:34:01+01:00 deller@gmx.de +68 -0
#   input: HP HIL support (from PARISC Linux tree).
#   
#   From: Helge Deller <deller@gmx.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 13:58:37+01:00 vojtech@silver.ucw.cz 
#   input: Fix poll() behavior of input handlers on disconnect.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/tsdev.c
#   2005/02/06 13:58:22+01:00 vojtech@silver.ucw.cz +2 -4
#   input: Fix poll() behavior of input handlers on disconnect.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mousedev.c
#   2005/02/06 13:58:22+01:00 vojtech@silver.ucw.cz +3 -3
#   input: Fix poll() behavior of input handlers on disconnect.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joydev.c
#   2005/02/06 13:58:22+01:00 vojtech@silver.ucw.cz +5 -5
#   input: Fix poll() behavior of input handlers on disconnect.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/evdev.c
#   2005/02/06 13:58:22+01:00 vojtech@silver.ucw.cz +2 -3
#   input: Fix poll() behavior of input handlers on disconnect.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 11:18:28+01:00 vojtech@silver.ucw.cz 
#   input: Add MCC devices to HID blacklist, cleanup whitespace along
#          the way.
#   
#   From: Mark Glines <mark-pmd@glines.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2005/02/06 11:18:17+01:00 vojtech@silver.ucw.cz +63 -62
#   input: Add MCC devices to HID blacklist, cleanup whitespace along
#          the way.
#   
#   From: Mark Glines <mark-pmd@glines.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 10:15:36+01:00 dtor_core@ameritech.net 
#   Input: add resume method to serio bus so ports are properly
#          set up at resume time. Remove calls to serio_reconnect
#          from i8042 as they should now be reconnected in course
#          of regular resume process.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/06 10:15:22+01:00 dtor_core@ameritech.net +17 -0
#   Input: add resume method to serio bus so ports are properly
#          set up at resume time. Remove calls to serio_reconnect
#          from i8042 as they should now be reconnected in course
#          of regular resume process.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/06 10:15:22+01:00 dtor_core@ameritech.net +4 -4
#   Input: add resume method to serio bus so ports are properly
#          set up at resume time. Remove calls to serio_reconnect
#          from i8042 as they should now be reconnected in course
#          of regular resume process.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/06 10:13:52+01:00 vojtech@silver.ucw.cz 
#   input: New driver for ICS MicroClock MK712 TouchScreens.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/mk712.c
#   2005/02/06 10:13:39+01:00 vojtech@silver.ucw.cz +222 -0
# 
# drivers/input/touchscreen/mk712.c
#   2005/02/06 10:13:39+01:00 vojtech@silver.ucw.cz +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/touchscreen/mk712.c
# 
# drivers/input/touchscreen/Makefile
#   2005/02/06 10:13:39+01:00 vojtech@silver.ucw.cz +2 -1
#   input: New driver for ICS MicroClock MK712 TouchScreens.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/Kconfig
#   2005/02/06 10:13:39+01:00 vojtech@silver.ucw.cz +11 -0
#   input: New driver for ICS MicroClock MK712 TouchScreens.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/05 20:08:22+01:00 rpurdie@rpsys.net 
#   input: Add support for Sharp SL-C7xx touchscreen (Corgi).
#   
#   From: Richard Purdie <rpurdie@rpsys.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/corgi_ts.c
#   2005/02/05 20:08:10+01:00 rpurdie@rpsys.net +380 -0
# 
# drivers/input/touchscreen/corgi_ts.c
#   2005/02/05 20:08:10+01:00 rpurdie@rpsys.net +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/touchscreen/corgi_ts.c
# 
# drivers/input/touchscreen/Makefile
#   2005/02/05 20:08:10+01:00 rpurdie@rpsys.net +1 -0
#   input: Add support for Sharp SL-C7xx touchscreen (Corgi).
#   
#   From: Richard Purdie <rpurdie@rpsys.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/Kconfig
#   2005/02/05 20:08:10+01:00 rpurdie@rpsys.net +14 -1
#   input: Add support for Sharp SL-C7xx touchscreen (Corgi).
#   
#   From: Richard Purdie <rpurdie@rpsys.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/05 20:06:12+01:00 rpurdie@rpsys.net 
#   input: Add support for Sharp Zaurus SL-C7cc Corgi keyboards.
#   
#   From: Richard Purdie <rpurdie@rpsys.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/corgikbd.c
#   2005/02/05 20:05:57+01:00 rpurdie@rpsys.net +363 -0
# 
# drivers/input/keyboard/corgikbd.c
#   2005/02/05 20:05:57+01:00 rpurdie@rpsys.net +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/keyboard/corgikbd.c
# 
# drivers/input/keyboard/Makefile
#   2005/02/05 20:05:57+01:00 rpurdie@rpsys.net +1 -0
#   input: Add support for Sharp Zaurus SL-C7cc Corgi keyboards.
#   
#   From: Richard Purdie <rpurdie@rpsys.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/Kconfig
#   2005/02/05 20:05:57+01:00 rpurdie@rpsys.net +16 -5
#   input: Add support for Sharp Zaurus SL-C7cc Corgi keyboards.
#   
#   From: Richard Purdie <rpurdie@rpsys.net>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/05 13:25:50+01:00 dtor_core@ameritech.net 
#   Input: make serio drivers register asynchronously. This should
#          speed up boot process as some drivers take a long time
#          probing for supported devices.
#   
#          Also change __inline__ to inline in serio.h
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/05 13:25:37+01:00 dtor_core@ameritech.net +15 -10
#   Input: make serio drivers register asynchronously. This should
#          speed up boot process as some drivers take a long time
#          probing for supported devices.
#   
#          Also change __inline__ to inline in serio.h
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/05 13:25:37+01:00 dtor_core@ameritech.net +36 -29
#   Input: make serio drivers register asynchronously. This should
#          speed up boot process as some drivers take a long time
#          probing for supported devices.
#   
#          Also change __inline__ to inline in serio.h
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/05 07:23:23+01:00 bunk@stusta.de 
#   input: This patch makes two needlessly global functions static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/cs461x.c
#   2005/02/05 07:23:10+01:00 bunk@stusta.de +2 -2
#   input: This patch makes two needlessly global functions static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 20:06:07+01:00 petero2@telia.com 
#   input: Only parse a "z == 127" packet as a relative Dualpoint stick
#   packet if the touchpad actually is a Dualpoint device.  The Glidepoint
#   modelsdon't have a stick, and can report z == 127 for a very wide finger.
#   If such a packet is parsed as a stick packet, the mouse pointer will
#   typically jump to one corner of the screen.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.h
#   2005/02/04 20:05:52+01:00 petero2@telia.com +1 -0
#   input: Only parse a "z == 127" packet as a relative Dualpoint stick
#   packet if the touchpad actually is a Dualpoint device.  The Glidepoint
#   modelsdon't have a stick, and can report z == 127 for a very wide finger.
#   If such a packet is parsed as a stick packet, the mouse pointer will
#   typically jump to one corner of the screen.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/04 20:05:52+01:00 petero2@telia.com +10 -10
#   input: Only parse a "z == 127" packet as a relative Dualpoint stick
#   packet if the touchpad actually is a Dualpoint device.  The Glidepoint
#   modelsdon't have a stick, and can report z == 127 for a very wide finger.
#   If such a packet is parsed as a stick packet, the mouse pointer will
#   typically jump to one corner of the screen.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 20:04:21+01:00 petero2@telia.com 
#   input: When hardware tapping is disabled on an ALPS touchpad, the touchpad
#   generates exactly the same data for a single tap and a fast double
#   tap.  The effect is that the second tap in the double tap sequence is
#   lost.
#   
#   To fix this problem, this patch enables hardware tapping and converts
#   the resulting tap and gesture bits to standard finger pressure values
#   (z), which is what mousedev.c and the userspace X driver expects.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.h
#   2005/02/04 20:04:09+01:00 petero2@telia.com +4 -0
#   input: When hardware tapping is disabled on an ALPS touchpad, the touchpad
#   generates exactly the same data for a single tap and a fast double
#   tap.  The effect is that the second tap in the double tap sequence is
#   lost.
#   
#   To fix this problem, this patch enables hardware tapping and converts
#   the resulting tap and gesture bits to standard finger pressure values
#   (z), which is what mousedev.c and the userspace X driver expects.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/04 20:04:09+01:00 petero2@telia.com +43 -10
#   input: When hardware tapping is disabled on an ALPS touchpad, the touchpad
#   generates exactly the same data for a single tap and a fast double
#   tap.  The effect is that the second tap in the double tap sequence is
#   lost.
#   
#   To fix this problem, this patch enables hardware tapping and converts
#   the resulting tap and gesture bits to standard finger pressure values
#   (z), which is what mousedev.c and the userspace X driver expects.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 15:41:37+01:00 zippel@linux-m68k.org 
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +5 -4
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +14 -15
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +11 -12
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +8 -7
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +7 -9
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +20 -24
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +22 -26
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/Kconfig
#   2005/02/04 15:41:31+01:00 zippel@linux-m68k.org +13 -12
#   input: Cleanup the Kconfig menus for the input subsystem.
#   
#   From: Roman Zippel <zippel@linux-m68k.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 15:35:12+01:00 vojtech@suse.cz 
#   input: Add support for the Logitech MX1000 mouse in PS/2 mode.
# 
# drivers/input/mouse/logips2pp.c
#   2005/02/04 15:35:06+01:00 vojtech@suse.cz +5 -0
#   input: Add support for the Logitech MX1000 mouse in PS/2 mode.
# 
# ChangeSet
#   2005/02/04 14:35:55+01:00 gijoe@poczta.onet.pl 
#   input: Add support for Logitech MX300 mouse in PS/2 mode.
#   
#   From: Daniel Johnson <gijoe@poczta.onet.pl>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/logips2pp.c
#   2005/02/04 14:35:49+01:00 gijoe@poczta.onet.pl +10 -8
#   input: Add support for Logitech MX300 mouse in PS/2 mode.
#   
#   From: Daniel Johnson <gijoe@poczta.onet.pl>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 14:25:26+01:00 petero2@telia.com 
#   input: Correct Y axis range for ALPS touchpads.
#   
#   From: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/04 14:25:19+01:00 petero2@telia.com +1 -1
#   input: Correct Y axis range for ALPS touchpads.
#   
#   From: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 14:23:40+01:00 petero2@telia.com 
#   input: Here it is, with the suggestions from Pete and Dmitry included. The
#   patch does the following:
#   
#   * Compensates for the lack of floating point arithmetic by keeping
#     track of remainders from the integer divisions.
#   * Removes the xres/yres scaling so that you get the same speed in the
#     X and Y directions even if your screen does not the same aspect ratio
#     as your touchpad.
#   * Sets scale factors to make the speed for synaptics and alps equal to
#     each other and equal to the synaptics speed from 2.6.10.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mousedev.c
#   2005/02/04 14:23:34+01:00 petero2@telia.com +19 -9
#   input: Here it is, with the suggestions from Pete and Dmitry included. The
#   patch does the following:
#   
#   * Compensates for the lack of floating point arithmetic by keeping
#     track of remainders from the integer divisions.
#   * Removes the xres/yres scaling so that you get the same speed in the
#     X and Y directions even if your screen does not the same aspect ratio
#     as your touchpad.
#   * Sets scale factors to make the speed for synaptics and alps equal to
#     each other and equal to the synaptics speed from 2.6.10.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 14:20:48+01:00 petero2@telia.com 
#   input: Some Synaptics touchpads have a middle mouse button that also works
#   as a scroll wheel.  Scroll data is reported as packets with w == 2 and
#   the scroll amount in byte 1, treated as a signed character.  For some
#   reason, the smallest possible wheel movement is reported as a scroll
#   amount of 4 units.  This amount is typically spread out over more than
#   one packet, so the driver has to accumulate scroll delta values to
#   correctly deal with this.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/synaptics.h
#   2005/02/04 14:20:41+01:00 petero2@telia.com +2 -0
#   input: Some Synaptics touchpads have a middle mouse button that also works
#   as a scroll wheel.  Scroll data is reported as packets with w == 2 and
#   the scroll amount in byte 1, treated as a signed character.  For some
#   reason, the smallest possible wheel movement is reported as a scroll
#   amount of 4 units.  This amount is typically spread out over more than
#   one packet, so the driver has to accumulate scroll delta values to
#   correctly deal with this.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/synaptics.c
#   2005/02/04 14:20:41+01:00 petero2@telia.com +26 -2
#   input: Some Synaptics touchpads have a middle mouse button that also works
#   as a scroll wheel.  Scroll data is reported as packets with w == 2 and
#   the scroll amount in byte 1, treated as a signed character.  For some
#   reason, the smallest possible wheel movement is reported as a scroll
#   amount of 4 units.  This amount is typically spread out over more than
#   one packet, so the driver has to accumulate scroll delta values to
#   correctly deal with this.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 14:16:34+01:00 petero2@telia.com 
#   input: mousedev_packet() incorrectly clears list->ready when called with
#   "tail == head - 1".  The effect is that the last mouse event from the
#   hardware isn't reported to user space until another hardware mouse
#   event arrives.  This can make the left mouse button get stuck when
#   tapping on a touchpad.  When this happens, the button doesn't unstick
#   until the next time you interact with the touchpad.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mousedev.c
#   2005/02/04 14:16:28+01:00 petero2@telia.com +2 -2
#   input: mousedev_packet() incorrectly clears list->ready when called with
#   "tail == head - 1".  The effect is that the last mouse event from the
#   hardware isn't reported to user space until another hardware mouse
#   event arrives.  This can make the left mouse button get stuck when
#   tapping on a touchpad.  When this happens, the button doesn't unstick
#   until the next time you interact with the touchpad.
#   
#   Signed-off-by: Peter Osterlund <petero2@telia.com>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 14:13:08+01:00 rddunlap@osdl.org 
#   input: joydump_connect: reduce stack usage from 2048 to 44 bytes (on i386)
#   by allocating 'buf' dynamically;
#           struct joydump buf[BUF_SIZE]; // 2048 bytes
#   
#   Signed-off-by: Randy Dunlap <rddunlap@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/joydump.c
#   2005/02/04 14:13:02+01:00 rddunlap@osdl.org +27 -11
#   input: joydump_connect: reduce stack usage from 2048 to 44 bytes (on i386)
#   by allocating 'buf' dynamically;
#           struct joydump buf[BUF_SIZE]; // 2048 bytes
#   
#   Signed-off-by: Randy Dunlap <rddunlap@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 14:09:42+01:00 micah@navi.cx 
#   input: This patch adds support to uinput for Linux's force feedback interface.
#          With these changes, it's possible to write drivers for force feedback
#          joysticks and similar devices in userspace.  It also adds a way to set the
#          physical path of devices created via uinput, and it has a couple trivial
#          bugfixes.
#   
#   Signed-off-by: Micah Dowty <micah@navi.cx>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/uinput.h
#   2005/02/04 14:09:36+01:00 micah@navi.cx +92 -0
#   input: This patch adds support to uinput for Linux's force feedback interface.
#          With these changes, it's possible to write drivers for force feedback
#          joysticks and similar devices in userspace.  It also adds a way to set the
#          physical path of devices created via uinput, and it has a couple trivial
#          bugfixes.
#   
#   Signed-off-by: Micah Dowty <micah@navi.cx>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/uinput.c
#   2005/02/04 14:09:36+01:00 micah@navi.cx +204 -13
#   input: This patch adds support to uinput for Linux's force feedback interface.
#          With these changes, it's possible to write drivers for force feedback
#          joysticks and similar devices in userspace.  It also adds a way to set the
#          physical path of devices created via uinput, and it has a couple trivial
#          bugfixes.
#   
#   Signed-off-by: Micah Dowty <micah@navi.cx>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 14:06:43+01:00 vojtech@suse.cz 
#   input: Don't even try to reset the i8042 controller when it's not
#          willing to talk to us at all - it's probably not there.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.h
#   2005/02/04 14:06:37+01:00 vojtech@suse.cz +2 -2
#   input: Don't even try to reset the i8042 controller when it's not
#          willing to talk to us at all - it's probably not there.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/04 14:06:37+01:00 vojtech@suse.cz +8 -4
#   input: Don't even try to reset the i8042 controller when it's not
#          willing to talk to us at all - it's probably not there.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:49:36+01:00 prarit@sgi.com 
#   Input: i8042 - call i8042_platform_exit to release resources
#          acquired by i8042_platform_init when controller
#          initialization fails.
#   
#   Signed-off-by: Prarit Bhargava <prarit@sgi.com>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/04 13:49:30+01:00 prarit@sgi.com +7 -2
#   Input: i8042 - call i8042_platform_exit to release resources
#          acquired by i8042_platform_init when controller
#          initialization fails.
#   
#   Signed-off-by: Prarit Bhargava <prarit@sgi.com>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:47:18+01:00 bunk@stusta.de 
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/tsdev.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +1 -1
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/gunze.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio_raw.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +3 -3
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +1 -1
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/parkbd.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +5 -5
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/ct82c710.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mousedev.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +1 -1
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/vsxxxaa.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/sermouse.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse-base.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/alps.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/uinput.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +1 -1
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/misc/pcspkr.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +1 -1
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/xtkbd.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +6 -6
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/sunkbd.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/newtonkbd.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +6 -6
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/lkkbd.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/warrior.c
#   2005/02/04 13:47:12+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/turbografx.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +3 -3
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/tmdc.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/stinger.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceorb.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceball.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/sidewinder.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/magellan.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/interact.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/guillemot.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/grip.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/gf2k.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/gamecon.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/db9.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/cobra.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/analog.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +3 -3
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/adi.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/a3d.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +5 -5
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/input.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +1 -1
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/vortex.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/ns558.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/lightning.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/fm801-gp.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/gameport/emu10k1-gp.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/evbug.c
#   2005/02/04 13:47:11+01:00 bunk@stusta.de +2 -2
#   Input: Make some needlessly global code static.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:44:14+01:00 dtor@mail.ru 
#   Input: serio - export id.type, id.proto, id.id and id.extra as
#          sysfs attributes to assist hotplug scripts in recovering
#          lost boot-time serio hotplug events.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/04 13:44:08+01:00 dtor@mail.ru +28 -0
#   Input: serio - export id.type, id.proto, id.id and id.extra as
#          sysfs attributes to assist hotplug scripts in recovering
#          lost boot-time serio hotplug events.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:43:30+01:00 dtor@mail.ru 
#   Input: i8042 - fix 'noloop' module parameter description
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/04 13:43:24+01:00 dtor@mail.ru +1 -1
#   Input: i8042 - fix 'noloop' module parameter description
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:42:32+01:00 dtor@mail.ru 
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +1 -1
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/h3600_ts_input.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +10 -6
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/gunze.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +8 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio_raw.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +6 -3
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +2 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/vsxxxaa.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +8 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/sermouse.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +8 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse-base.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +12 -3
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/xtkbd.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +8 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/sunkbd.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +9 -5
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/newtonkbd.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +8 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/lkkbd.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +9 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +10 -5
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/warrior.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +8 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/twidjoy.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +8 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/stinger.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +7 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceorb.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +9 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceball.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +10 -5
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/magellan.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +7 -4
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/iforce/iforce-serio.c
#   2005/02/04 13:42:25+01:00 dtor@mail.ru +10 -5
#   Input: make serio's connect routines return error code
#          instead of void.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:40:52+01:00 dtor@mail.ru 
#   Input: make serio implementation more in line with standard
#          driver model implementations. serio_register_port is
#          always asynchronous to allow freely registering child
#          ports. When deregistering serio core still takes care
#          of destroying children ports first.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/04 13:40:45+01:00 dtor@mail.ru +12 -5
#   Input: make serio implementation more in line with standard
#          driver model implementations. serio_register_port is
#          always asynchronous to allow freely registering child
#          ports. When deregistering serio core still takes care
#          of destroying children ports first.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/04 13:40:45+01:00 dtor@mail.ru +199 -163
#   Input: make serio implementation more in line with standard
#          driver model implementations. serio_register_port is
#          always asynchronous to allow freely registering child
#          ports. When deregistering serio core still takes care
#          of destroying children ports first.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/synaptics.c
#   2005/02/04 13:40:45+01:00 dtor@mail.ru +6 -4
#   Input: make serio implementation more in line with standard
#          driver model implementations. serio_register_port is
#          always asynchronous to allow freely registering child
#          ports. When deregistering serio core still takes care
#          of destroying children ports first.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse-base.c
#   2005/02/04 13:40:45+01:00 dtor@mail.ru +1 -10
#   Input: make serio implementation more in line with standard
#          driver model implementations. serio_register_port is
#          always asynchronous to allow freely registering child
#          ports. When deregistering serio core still takes care
#          of destroying children ports first.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:39:25+01:00 dtor@mail.ru 
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/04 13:39:19+01:00 dtor@mail.ru +24 -18
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/serial/sunzilog.c
#   2005/02/04 13:39:19+01:00 dtor@mail.ru +4 -3
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/serial/sunsu.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +4 -3
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/h3600_ts_input.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +17 -6
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/gunze.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +16 -6
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serport.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +15 -5
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio_raw.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +13 -3
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +66 -7
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/sa1111ps2.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/rpckbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/q40kbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/pcips2.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/parkbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/maceps2.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +3 -3
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/gscps2.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -5
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/ct82c710.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/ambakmi.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/vsxxxaa.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +13 -5
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/synaptics.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +1 -1
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/sermouse.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +52 -6
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse-base.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +22 -8
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/xtkbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +13 -3
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/sunkbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +19 -6
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/newtonkbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +13 -3
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/lkkbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +13 -5
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +26 -7
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/warrior.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +14 -4
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/twidjoy.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +14 -4
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/stinger.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +16 -6
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceorb.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +15 -5
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceball.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +17 -7
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/magellan.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +16 -6
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/iforce/iforce-serio.c
#   2005/02/04 13:39:18+01:00 dtor@mail.ru +15 -3
#   Input: replace serio's type field with serio_id structure and
#          add id_table to serio drivers to split initial matching
#          and probing routines for better sysfs integration and
#          to assist hotplug scripts in loading proper drivers.
#          Add serio_hotplug to notify userspace about new ports.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:36:53+01:00 dtor@mail.ru 
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +13 -1
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/h3600_ts_input.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +8 -5
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/touchscreen/gunze.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +7 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio_raw.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -6
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/vsxxxaa.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/synaptics.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +4 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/sermouse.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +7 -4
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse-base.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +16 -13
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/xtkbd.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/sunkbd.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/newtonkbd.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +7 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/lkkbd.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +5 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +10 -8
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/warrior.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/twidjoy.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +7 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/stinger.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +7 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceorb.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/spaceball.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/magellan.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +6 -3
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/iforce/iforce-serio.c
#   2005/02/04 13:36:46+01:00 dtor@mail.ru +10 -4
#   Input: remove serio->private in favor of using driver-specific data
#          in device structure, add serio_get_drvdata/serio_put_drvdata
#          to access it.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:33:07+01:00 dtor@mail.ru 
#   Input: use msecs_to_jiffies instead of manually calculating
#          delay for Toshiba bouncing keys workaround to the code
#          works with HZ != 1000.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/atkbd.c
#   2005/02/04 13:33:01+01:00 dtor@mail.ru +1 -1
#   Input: use msecs_to_jiffies instead of manually calculating
#          delay for Toshiba bouncing keys workaround to the code
#          works with HZ != 1000.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:24:54+01:00 dtor@mail.ru 
#   Input: use msecs_to_jiffies instead of homegrown ms_to_jiffies
#          when setting timer for autorepeat handling. This will
#          make sure that autorepeat is scheduled correctly when
#          HZ != 1000.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/input.c
#   2005/02/04 13:24:47+01:00 dtor@mail.ru +4 -11
#   Input: use msecs_to_jiffies instead of homegrown ms_to_jiffies
#          when setting timer for autorepeat handling. This will
#          make sure that autorepeat is scheduled correctly when
#          HZ != 1000.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:22:01+01:00 dtor@mail.ru 
#   Input: twidjoy - apparently Kconfig and Makefile disagreed on the
#          name for config option so the module was never built.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/joystick/Kconfig
#   2005/02/04 13:21:54+01:00 dtor@mail.ru +1 -1
#   Input: twidjoy - apparently Kconfig and Makefile disagreed on the
#          name for config option so the module was never built.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:18:43+01:00 dtor@mail.ru 
#   Input: synaptics - use DMI to detect Toshiba Satellite notebooks
#          and automatically reduce touchpad reporting rate to 40 pps
#          as they have trouble handling high rate (80 pps).
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/synaptics.c
#   2005/02/04 13:18:37+01:00 dtor@mail.ru +26 -0
#   Input: synaptics - use DMI to detect Toshiba Satellite notebooks
#          and automatically reduce touchpad reporting rate to 40 pps
#          as they have trouble handling high rate (80 pps).
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:17:07+01:00 dtor@mail.ru 
#   Input: evdev - return -EINVAL from evdev_read if read buffer
#          is too small.
#   
#          Based on a patch by James Lamanna.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/evdev.c
#   2005/02/04 13:17:01+01:00 dtor@mail.ru +3 -0
#   Input: evdev - return -EINVAL from evdev_read if read buffer
#          is too small.
#   
#          Based on a patch by James Lamanna.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:14:06+01:00 dtor@mail.ru 
#   Input: rearrange serio event processing to get rid of duplicate
#          events - do not sumbit event into the event queue if similar
#          event has not been processed yet; also once event has been
#          processed check the queue and delete events of the same type
#          that have been accumulated in the mean time.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/04 13:13:59+01:00 dtor@mail.ru +48 -9
#   Input: rearrange serio event processing to get rid of duplicate
#          events - do not sumbit event into the event queue if similar
#          event has not been processed yet; also once event has been
#          processed check the queue and delete events of the same type
#          that have been accumulated in the mean time.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 13:08:36+01:00 dtor@mail.ru 
#   Input: i8042 - make use of new serio start() and stop() callbacks
#          to ensure that i8042 interrupt handler that is shared among
#          several ports does not reference deleted ports. Also rename
#          i8042_valies structure to i8042_port, consolidate handling
#          of KBD, AUX and MUX ports, rearrange interrupt handler code.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.h
#   2005/02/04 13:08:30+01:00 dtor@mail.ru +3 -3
#   Input: i8042 - make use of new serio start() and stop() callbacks
#          to ensure that i8042 interrupt handler that is shared among
#          several ports does not reference deleted ports. Also rename
#          i8042_valies structure to i8042_port, consolidate handling
#          of KBD, AUX and MUX ports, rearrange interrupt handler code.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/04 13:08:30+01:00 dtor@mail.ru +164 -160
#   Input: i8042 - make use of new serio start() and stop() callbacks
#          to ensure that i8042 interrupt handler that is shared among
#          several ports does not reference deleted ports. Also rename
#          i8042_valies structure to i8042_port, consolidate handling
#          of KBD, AUX and MUX ports, rearrange interrupt handler code.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 12:57:11+01:00 dtor@mail.ru 
#   Input: add serio->start() and serio->stop() callback methods that
#          are called whenever serio port is finishes being registered
#          or unregistered. The callbacks are useful for drivers that
#          share interrupt between several ports and there is a danger
#          that interrupt handler will reference port that was just
#          unregistered.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/serio.h
#   2005/02/04 12:57:04+01:00 dtor@mail.ru +2 -0
#   Input: add serio->start() and serio->stop() callback methods that
#          are called whenever serio port is finishes being registered
#          or unregistered. The callbacks are useful for drivers that
#          share interrupt between several ports and there is a danger
#          that interrupt handler will reference port that was just
#          unregistered.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/serio.c
#   2005/02/04 12:57:04+01:00 dtor@mail.ru +7 -1
#   Input: add serio->start() and serio->stop() callback methods that
#          are called whenever serio port is finishes being registered
#          or unregistered. The callbacks are useful for drivers that
#          share interrupt between several ports and there is a danger
#          that interrupt handler will reference port that was just
#          unregistered.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2005/02/04 12:55:58+01:00 dtor@mail.ru 
#   Input: i8042 - move panicblink with the rest of module parameters,
#          add proper entry to kernel-parameters.txt
#           
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2005/02/04 12:55:51+01:00 dtor@mail.ru +21 -9
#   Input: i8042 - move panicblink with the rest of module parameters,
#          add proper entry to kernel-parameters.txt
#           
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# Documentation/kernel-parameters.txt
#   2005/02/04 12:55:51+01:00 dtor@mail.ru +3 -0
#   Input: i8042 - move panicblink with the rest of module parameters,
#          add proper entry to kernel-parameters.txt
#           
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	2005-03-07 15:26:30 -08:00
+++ b/Documentation/kernel-parameters.txt	2005-03-07 15:26:30 -08:00
@@ -73,6 +73,7 @@
 	SWSUSP	Software suspension is enabled.
 	TS	Appropriate touchscreen support is enabled.
 	USB	USB support is enabled.
+	USBHID	USB Human Interface Device support is enabled.
 	V4L	Video For Linux support is enabled.
 	VGA	The VGA console has been enabled.
 	VT	Virtual terminal support is enabled.
@@ -514,11 +515,14 @@
 	i8042.dumbkbd	[HW] Pretend that controlled can only read data from
 			     keyboard and can not control its state
 			     (Don't attempt to blink the leds)
-	i8042.noacpi	[HW] Don't use ACPI to discover KBD/AUX controller
-			     settings
 	i8042.noaux	[HW] Don't check for auxiliary (== mouse) port
 	i8042.nomux	[HW] Don't check presence of an active multiplexing
 			     controller
+	i8042.nopnp	[HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
+			     controllers
+	i8042.panicblink=
+			[HW] Frequency with which keyboard LEDs should blink
+			     when kernel panics (default is 0.5 sec)
 	i8042.reset	[HW] Reset the controller during init and cleanup
 	i8042.unlock	[HW] Unlock (ignore) the keylock
 
@@ -776,6 +780,10 @@
 	mtdparts=	[MTD]
 			See drivers/mtd/cmdline.c.
 
+	mtouchusb.raw_coordinates=
+			[HW] Make the MicroTouch USB driver use raw coordinates ('y', default)
+			or cooked coordinates ('n')
+
 	n2=		[NET] SDL Inc. RISCom/N2 synchronous serial card
 
 	NCR_D700=	[HW,SCSI]
@@ -1393,6 +1401,9 @@
 			Format: <io>,<irq>
 
 	usb-handoff	[HW] Enable early USB BIOS -> OS handoff
+
+	usbhid.mousepoll=
+			[USBHID] The interval which mice are to be polled at.
  
 	video=		[FB] Frame buffer configuration
 			See Documentation/fb/modedb.txt.
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	2005-03-07 15:26:30 -08:00
+++ b/drivers/Makefile	2005-03-07 15:26:30 -08:00
@@ -47,8 +47,8 @@
 obj-$(CONFIG_TC)		+= tc/
 obj-$(CONFIG_USB)		+= usb/
 obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
-obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
+obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_W1)		+= w1/
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/char/keyboard.c	2005-03-07 15:26:30 -08:00
@@ -141,7 +141,7 @@
 /* Simple translation table for the SysRq keys */
 
 #ifdef CONFIG_MAGIC_SYSRQ
-unsigned char kbd_sysrq_xlate[KEY_MAX] =
+unsigned char kbd_sysrq_xlate[KEY_MAX + 1] =
         "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
         "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
         "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
@@ -173,7 +173,7 @@
 	if (!dev)
 		return -ENODEV;
 
-	if (scancode < 0 || scancode >= dev->keycodemax)
+	if (scancode >= dev->keycodemax)
 		return -EINVAL;
 
 	return INPUT_KEYCODE(dev, scancode);
@@ -183,7 +183,7 @@
 {
 	struct list_head * node;
 	struct input_dev *dev = NULL;
-	int i, oldkey;
+	unsigned int i, oldkey;
 
 	list_for_each(node,&kbd_handler.h_list) {
 		struct input_handle *handle = to_handle_h(node);
@@ -196,7 +196,9 @@
 	if (!dev)
 		return -ENODEV;
 
-	if (scancode < 0 || scancode >= dev->keycodemax)
+	if (scancode >= dev->keycodemax)
+		return -EINVAL;
+	if (keycode > KEY_MAX)
 		return -EINVAL;
 	if (keycode < 0 || keycode > KEY_MAX)
 		return -EINVAL;
@@ -355,7 +357,7 @@
  */
 void compute_shiftstate(void)
 {
-	int i, j, k, sym, val;
+	unsigned int i, j, k, sym, val;
 
 	shift_state = 0;
 	memset(shift_down, 0, sizeof(shift_down));
@@ -396,7 +398,7 @@
 static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch)
 {
 	int d = diacr;
-	int i;
+	unsigned int i;
 
 	diacr = 0;
 
@@ -931,7 +933,7 @@
 #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) ||\
-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_RPC))
+    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
 
 #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))
diff -Nru a/drivers/input/Kconfig b/drivers/input/Kconfig
--- a/drivers/input/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/Kconfig	2005-03-07 15:26:30 -08:00
@@ -5,7 +5,7 @@
 menu "Input device support"
 
 config INPUT
-	tristate "Input devices (needed for keyboard, mouse, ...)" if EMBEDDED
+	tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
 	default y
 	---help---
 	  Say Y here if you have any input device (mouse, keyboard, tablet,
@@ -22,12 +22,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called input.
 
+if INPUT
+
 comment "Userland interfaces"
 
 config INPUT_MOUSEDEV
 	tristate "Mouse interface" if EMBEDDED
 	default y
-	depends on INPUT
 	---help---
 	  Say Y here if you want your mouse to be accessible as char devices
 	  13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
@@ -74,7 +75,6 @@
 
 config INPUT_JOYDEV
 	tristate "Joystick interface"
-	depends on INPUT
 	---help---
 	  Say Y here if you want your joystick or gamepad to be
 	  accessible as char device 13:0+ - /dev/input/jsX device.
@@ -88,7 +88,6 @@
 
 config INPUT_TSDEV
 	tristate "Touchscreen interface"
-	depends on INPUT
 	---help---
 	  Say Y here if you have an application that only can understand the
 	  Compaq touchscreen protocol for absolute pointer data. This is
@@ -111,7 +110,6 @@
 
 config INPUT_EVDEV
 	tristate "Event interface"
-	depends on INPUT
 	help
 	  Say Y here if you want your input device events be accessible
 	  under char device 13:64+ - /dev/input/eventX in a generic way.
@@ -121,7 +119,6 @@
 
 config INPUT_EVBUG
 	tristate "Event debugging"
-	depends on INPUT
 	---help---
 	  Say Y here if you have a problem with the input subsystem and
 	  want all events (keypresses, mouse movements), to be output to
@@ -134,12 +131,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called evbug.
 
-comment "Input I/O drivers"
-
-source "drivers/input/gameport/Kconfig"
-
-source "drivers/input/serio/Kconfig"
-
 comment "Input Device Drivers"
 
 source "drivers/input/keyboard/Kconfig"
@@ -151,6 +142,16 @@
 source "drivers/input/touchscreen/Kconfig"
 
 source "drivers/input/misc/Kconfig"
+
+endif
+
+menu "Hardware I/O ports"
+
+source "drivers/input/serio/Kconfig"
+
+source "drivers/input/gameport/Kconfig"
+
+endmenu
 
 endmenu
 
diff -Nru a/drivers/input/evbug.c b/drivers/input/evbug.c
--- a/drivers/input/evbug.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/evbug.c	2005-03-07 15:26:30 -08:00
@@ -88,13 +88,13 @@
 	.id_table =	evbug_ids,
 };
 
-int __init evbug_init(void)
+static int __init evbug_init(void)
 {
 	input_register_handler(&evbug_handler);
 	return 0;
 }
 
-void __exit evbug_exit(void)
+static void __exit evbug_exit(void)
 {
 	input_unregister_handler(&evbug_handler);
 }
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/evdev.c	2005-03-07 15:26:30 -08:00
@@ -169,6 +169,9 @@
 	struct evdev_list *list = file->private_data;
 	int retval;
 
+	if (count < sizeof(struct input_event))
+		return -EINVAL;
+
 	if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
@@ -196,9 +199,8 @@
 {
 	struct evdev_list *list = file->private_data;
 	poll_wait(file, &list->evdev->wait, wait);
-	if (list->head != list->tail)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -223,14 +225,15 @@
 
 		case EVIOCGKEYCODE:
 			if (get_user(t, ip)) return -EFAULT;
-			if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+			if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
 			if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT;
 			return 0;
 
 		case EVIOCSKEYCODE:
 			if (get_user(t, ip)) return -EFAULT;
-			if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+			if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
 			if (get_user(v, ip + 1)) return -EFAULT;
+			if (v < 0 || v > KEY_MAX) return -EINVAL;
 			u = SET_INPUT_KEYCODE(dev, t, v);
 			clear_bit(u, dev->keybit);
 			set_bit(v, dev->keybit);
@@ -438,6 +441,7 @@
 static void evdev_disconnect(struct input_handle *handle)
 {
 	struct evdev *evdev = handle->private;
+	struct evdev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
 	devfs_remove("input/event%d", evdev->minor);
@@ -446,6 +450,8 @@
 	if (evdev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&evdev->wait);
+		list_for_each_entry(list, &evdev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 	} else
 		evdev_free(evdev);
 }
diff -Nru a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
--- a/drivers/input/gameport/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/Kconfig	2005-03-07 15:26:30 -08:00
@@ -19,30 +19,10 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called gameport.
 
-
-# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on
-# in every .config. Please don't touch it. It is here to handle an
-# unusual dependency between GAMEPORT and sound drivers.
-#
-# Some sound drivers call gameport functions. If GAMEPORT is
-# not selected, empty stubs are provided for the functions and all is
-# well.
-# If GAMEPORT is built in, everything is fine.
-# If GAMEPORT is a module, however, it would need to be loaded for the
-# sound driver to be able to link properly. Therefore, the sound
-# driver must be a module as well in that case. Since there's no way
-# to express that directly in Kconfig, we use SOUND_GAMEPORT to
-# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm',
-# anything that depends on SOUND_GAMEPORT must be 'm' as well. if
-# GAMEPORT is 'y' or 'n', it can be anything".
-config SOUND_GAMEPORT
-	tristate
-	default y if GAMEPORT!=m
-	default m if GAMEPORT=m
+if GAMEPORT
 
 config GAMEPORT_NS558
 	tristate "Classic ISA and PnP gameport support"
-	depends on GAMEPORT
 	help
 	  Say Y here if you have an ISA or PnP gameport.
 
@@ -53,7 +33,6 @@
 
 config GAMEPORT_L4
 	tristate "PDPI Lightning 4 gamecard support"
-	depends on GAMEPORT
 	help
 	  Say Y here if you have a PDPI Lightning 4 gamecard.
 
@@ -62,7 +41,6 @@
 
 config GAMEPORT_EMU10K1
 	tristate "SB Live and Audigy gameport support"
-	depends on GAMEPORT
 	help
 	  Say Y here if you have a SoundBlaster Live! or SoundBlaster
 	  Audigy card and want to use its gameport.
@@ -72,7 +50,6 @@
 
 config GAMEPORT_VORTEX
 	tristate "Aureal Vortex, Vortex 2 gameport support"
-	depends on GAMEPORT
 	help
 	  Say Y here if you have an Aureal Vortex 1 or 2  card and want
 	  to use its gameport.
@@ -82,9 +59,28 @@
 
 config GAMEPORT_FM801
 	tristate "ForteMedia FM801 gameport support"
-	depends on GAMEPORT
 
 config GAMEPORT_CS461X
 	tristate "Crystal SoundFusion gameport support"
-	depends on GAMEPORT
 
+endif
+
+# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on
+# in every .config. Please don't touch it. It is here to handle an
+# unusual dependency between GAMEPORT and sound drivers.
+#
+# Some sound drivers call gameport functions. If GAMEPORT is
+# not selected, empty stubs are provided for the functions and all is
+# well.
+# If GAMEPORT is built in, everything is fine.
+# If GAMEPORT is a module, however, it would need to be loaded for the
+# sound driver to be able to link properly. Therefore, the sound
+# driver must be a module as well in that case. Since there's no way
+# to express that directly in Kconfig, we use SOUND_GAMEPORT to
+# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm',
+# anything that depends on SOUND_GAMEPORT must be 'm' as well. if
+# GAMEPORT is 'y' or 'n', it can be anything".
+config SOUND_GAMEPORT
+	tristate
+	default m if GAMEPORT=m
+	default y
diff -Nru a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
--- a/drivers/input/gameport/cs461x.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/cs461x.c	2005-03-07 15:26:30 -08:00
@@ -16,7 +16,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 
-MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
+MODULE_AUTHOR("Victor Krapivin");
 MODULE_LICENSE("GPL");
 
 /*
@@ -120,9 +120,6 @@
 static unsigned long ba0_addr;
 static unsigned int __iomem *ba0;
 
-static char phys[32];
-static char name[] = "CS416x Gameport";
-
 #ifdef CS461X_FULL_MAP
 static unsigned long ba1_addr;
 static union ba1_t {
@@ -160,10 +157,10 @@
 static int cs461x_free(struct pci_dev *pdev)
 {
 	struct gameport *port = pci_get_drvdata(pdev);
-	if(port){
+
+	if (port)
 	    gameport_unregister_port(port);
-	    kfree(port);
-	}
+
 	if (ba0) iounmap(ba0);
 #ifdef CS461X_FULL_MAP
 	if (ba1.name.data0) iounmap(ba1.name.data0);
@@ -267,18 +264,17 @@
                 return -ENOMEM;
         }
 #else
-	if (ba0 == NULL){
+	if (ba0 == NULL) {
 		cs461x_free(pdev);
 		return -ENOMEM;
 	}
 #endif
 
-	if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
-		printk(KERN_ERR "Memory allocation failed.\n");
+	if (!(port = gameport_allocate_port())) {
+		printk(KERN_ERR "cs461x: Memory allocation failed\n");
 		cs461x_free(pdev);
 		return -ENOMEM;
 	}
-	memset(port, 0, sizeof(struct gameport));
 
 	pci_set_drvdata(pdev, port);
 
@@ -287,22 +283,15 @@
 	port->read = cs461x_gameport_read;
 	port->cooked_read = cs461x_gameport_cooked_read;
 
-	sprintf(phys, "pci%s/gameport0", pci_name(pdev));
-
-	port->name = name;
-	port->phys = phys;
-	port->id.bustype = BUS_PCI;
-	port->id.vendor = pdev->vendor;
-	port->id.product = pdev->device;
+	gameport_set_name(port, "CS416x");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
+	port->dev.parent = &pdev->dev;
 
 	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
 	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
 
 	gameport_register_port(port);
 
-	printk(KERN_INFO "gameport: %s on pci%s speed %d kHz\n",
-		name, pci_name(pdev), port->speed);
-
 	return 0;
 }
 
@@ -318,12 +307,12 @@
         .remove =       __devexit_p(cs461x_pci_remove),
 };
 
-int __init cs461x_init(void)
+static int __init cs461x_init(void)
 {
-        return pci_module_init(&cs461x_pci_driver);
+        return pci_register_driver(&cs461x_pci_driver);
 }
 
-void __exit cs461x_exit(void)
+static void __exit cs461x_exit(void)
 {
         pci_unregister_driver(&cs461x_pci_driver);
 }
diff -Nru a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
--- a/drivers/input/gameport/emu10k1-gp.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/emu10k1-gp.c	2005-03-07 15:26:30 -08:00
@@ -44,13 +44,13 @@
 
 struct emu {
 	struct pci_dev *dev;
-	struct gameport gameport;
+	struct gameport *gameport;
+	int io;
 	int size;
-	char phys[32];
 };
 
 static struct pci_device_id emu_tbl[] = {
- 
+
 	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
 	{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
 	{ 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */
@@ -64,6 +64,7 @@
 {
 	int ioport, iolen;
 	struct emu *emu;
+	struct gameport *port;
 
 	if (pci_enable_device(pdev))
 		return -EBUSY;
@@ -74,31 +75,29 @@
 	if (!request_region(ioport, iolen, "emu10k1-gp"))
 		return -EBUSY;
 
-	if (!(emu = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
-		printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
+	emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!emu || !port) {
+		printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
 		release_region(ioport, iolen);
+		kfree(emu);
+		gameport_free_port(port);
 		return -ENOMEM;
 	}
-	memset(emu, 0, sizeof(struct emu));
-
-	sprintf(emu->phys, "pci%s/gameport0", pci_name(pdev));
 
+	emu->io = ioport;
 	emu->size = iolen;
 	emu->dev = pdev;
+	emu->gameport = port;
 
-	emu->gameport.io = ioport;
-	emu->gameport.name = pci_name(pdev);
-	emu->gameport.phys = emu->phys;
-	emu->gameport.id.bustype = BUS_PCI;
-	emu->gameport.id.vendor = pdev->vendor;
-	emu->gameport.id.product = pdev->device;
+	gameport_set_name(port, "EMU10K1");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
+	port->dev.parent = &pdev->dev;
+	port->io = ioport;
 
 	pci_set_drvdata(pdev, emu);
 
-	gameport_register_port(&emu->gameport);
-
-	printk(KERN_INFO "gameport: pci%s speed %d kHz\n",
-		pci_name(pdev), emu->gameport.speed);
+	gameport_register_port(port);
 
 	return 0;
 }
@@ -106,8 +105,9 @@
 static void __devexit emu_remove(struct pci_dev *pdev)
 {
 	struct emu *emu = pci_get_drvdata(pdev);
-	gameport_unregister_port(&emu->gameport);
-	release_region(emu->gameport.io, emu->size);
+
+	gameport_unregister_port(emu->gameport);
+	release_region(emu->io, emu->size);
 	kfree(emu);
 }
 
@@ -118,12 +118,12 @@
         .remove =       __devexit_p(emu_remove),
 };
 
-int __init emu_init(void)
+static int __init emu_init(void)
 {
-	return pci_module_init(&emu_driver);
+	return pci_register_driver(&emu_driver);
 }
 
-void __exit emu_exit(void)
+static void __exit emu_exit(void)
 {
 	pci_unregister_driver(&emu_driver);
 }
diff -Nru a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
--- a/drivers/input/gameport/fm801-gp.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/fm801-gp.c	2005-03-07 15:26:30 -08:00
@@ -37,10 +37,8 @@
 #define HAVE_COOKED
 
 struct fm801_gp {
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct resource *res_port;
-	char phys[32];
-	char name[32];
 };
 
 #ifdef HAVE_COOKED
@@ -83,40 +81,42 @@
 static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
 	struct fm801_gp *gp;
+	struct gameport *port;
 
-	if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) {
-		printk("cannot malloc for fm801-gp\n");
-		return -1;
+	gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!gp || !port) {
+		printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
+		kfree(gp);
+		gameport_free_port(port);
+		return -ENOMEM;
 	}
-	memset(gp, 0, sizeof(*gp));
 
-	gp->gameport.open = fm801_gp_open;
+	pci_enable_device(pci);
+
+	port->open = fm801_gp_open;
 #ifdef HAVE_COOKED
-	gp->gameport.cooked_read = fm801_gp_cooked_read;
+	port->cooked_read = fm801_gp_cooked_read;
 #endif
-
-	pci_enable_device(pci);
-	gp->gameport.io = pci_resource_start(pci, 0);
-	if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
-		printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
+	gameport_set_name(port, "FM801");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(pci));
+	port->dev.parent = &pci->dev;
+	port->io = pci_resource_start(pci, 0);
+
+	gp->gameport = port;
+	gp->res_port = request_region(port->io, 0x10, "FM801 GP");
+	if (!gp->res_port) {
 		kfree(gp);
-		return -1;
+		gameport_free_port(port);
+		printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
+			port->io, port->io + 0x0f);
+		return -EBUSY;
 	}
 
-	gp->gameport.phys = gp->phys;
-	gp->gameport.name = gp->name;
-	gp->gameport.id.bustype = BUS_PCI;
-	gp->gameport.id.vendor = pci->vendor;
-	gp->gameport.id.product = pci->device;
-
 	pci_set_drvdata(pci, gp);
 
-	outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */
-
-	gameport_register_port(&gp->gameport);
-
-	printk(KERN_INFO "gameport: at pci%s speed %d kHz\n",
-		pci_name(pci), gp->gameport.speed);
+	outb(0x60, port->io + 0x0d); /* enable joystick 1 and 2 */
+	gameport_register_port(port);
 
 	return 0;
 }
@@ -124,8 +124,9 @@
 static void __devexit fm801_gp_remove(struct pci_dev *pci)
 {
 	struct fm801_gp *gp = pci_get_drvdata(pci);
+
 	if (gp) {
-		gameport_unregister_port(&gp->gameport);
+		gameport_unregister_port(gp->gameport);
 		release_resource(gp->res_port);
 		kfree(gp);
 	}
@@ -143,12 +144,12 @@
 	.remove =	__devexit_p(fm801_gp_remove),
 };
 
-int __init fm801_gp_init(void)
+static int __init fm801_gp_init(void)
 {
-	return pci_module_init(&fm801_gp_driver);
+	return pci_register_driver(&fm801_gp_driver);
 }
 
-void __exit fm801_gp_exit(void)
+static void __exit fm801_gp_exit(void)
 {
 	pci_unregister_driver(&fm801_gp_driver);
 }
diff -Nru a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
--- a/drivers/input/gameport/gameport.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/gameport.c	2005-03-07 15:26:30 -08:00
@@ -2,6 +2,7 @@
  * Generic gameport layer
  *
  * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 2005 Dmitry Torokhov
  */
 
 /*
@@ -10,32 +11,55 @@
  * the Free Software Foundation.
  */
 
-#include <asm/io.h>
+#include <linux/stddef.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/gameport.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/slab.h>
-#include <linux/stddef.h>
 #include <linux/delay.h>
 
+/*#include <asm/io.h>*/
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Generic gameport layer");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(gameport_register_port);
+EXPORT_SYMBOL(__gameport_register_port);
 EXPORT_SYMBOL(gameport_unregister_port);
-EXPORT_SYMBOL(gameport_register_device);
-EXPORT_SYMBOL(gameport_unregister_device);
+EXPORT_SYMBOL(__gameport_register_driver);
+EXPORT_SYMBOL(gameport_unregister_driver);
 EXPORT_SYMBOL(gameport_open);
 EXPORT_SYMBOL(gameport_close);
 EXPORT_SYMBOL(gameport_rescan);
 EXPORT_SYMBOL(gameport_cooked_read);
+EXPORT_SYMBOL(gameport_set_name);
+EXPORT_SYMBOL(gameport_set_phys);
+EXPORT_SYMBOL(gameport_start_polling);
+EXPORT_SYMBOL(gameport_stop_polling);
+
+/*
+ * gameport_sem protects entire gameport subsystem and is taken
+ * every time gameport port or driver registrered or unregistered.
+ */
+static DECLARE_MUTEX(gameport_sem);
 
 static LIST_HEAD(gameport_list);
-static LIST_HEAD(gameport_dev_list);
 
-#ifdef __i386__
+static struct bus_type gameport_bus = {
+	.name =	"gameport",
+};
+
+static void gameport_add_port(struct gameport *gameport);
+static void gameport_destroy_port(struct gameport *gameport);
+static void gameport_reconnect_port(struct gameport *gameport);
+static void gameport_disconnect_port(struct gameport *gameport);
+
+#if defined(__i386__)
 
 #define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193182/HZ:0))
 #define GET_TIME(x)     do { x = get_time_pit(); } while (0)
@@ -57,13 +81,15 @@
 
 #endif
 
+
+
 /*
  * gameport_measure_speed() measures the gameport i/o speed.
  */
 
 static int gameport_measure_speed(struct gameport *gameport)
 {
-#ifdef __i386__
+#if defined(__i386__)
 
 	unsigned int i, t, t1, t2, t3, tx;
 	unsigned long flags;
@@ -76,7 +102,7 @@
 	for(i = 0; i < 50; i++) {
 		local_irq_save(flags);
 		GET_TIME(t1);
-		for(t = 0; t < 50; t++) gameport_read(gameport);
+		for (t = 0; t < 50; t++) gameport_read(gameport);
 		GET_TIME(t2);
 		GET_TIME(t3);
 		local_irq_restore(flags);
@@ -87,10 +113,36 @@
 	gameport_close(gameport);
 	return 59659 / (tx < 1 ? 1 : tx);
 
+#elif defined (__x86_64__)
+
+	unsigned int i, t;
+	unsigned long tx, t1, t2, flags;
+
+	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
+		return 0;
+
+	tx = 1 << 30;
+
+	for(i = 0; i < 50; i++) {
+		local_irq_save(flags);
+		rdtscl(t1);
+		for (t = 0; t < 50; t++) gameport_read(gameport);
+		rdtscl(t2);
+		local_irq_restore(flags);
+		udelay(i * 10);
+		if (t2 - t1 < tx) tx = t2 - t1;
+	}
+
+	gameport_close(gameport);
+	return (cpu_data[_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
+
 #else
 
 	unsigned int j, t = 0;
 
+	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
+		return 0;
+
 	j = jiffies; while (j == jiffies);
 	j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
 
@@ -100,81 +152,646 @@
 #endif
 }
 
-static void gameport_find_dev(struct gameport *gameport)
+void gameport_start_polling(struct gameport *gameport)
+{
+	spin_lock(&gameport->timer_lock);
+
+	if (!gameport->poll_cnt++) {
+		BUG_ON(!gameport->poll_handler);
+		BUG_ON(!gameport->poll_interval);
+		mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
+	}
+
+	spin_unlock(&gameport->timer_lock);
+}
+
+void gameport_stop_polling(struct gameport *gameport)
+{
+	spin_lock(&gameport->timer_lock);
+
+	if (!--gameport->poll_cnt)
+		del_timer(&gameport->poll_timer);
+
+	spin_unlock(&gameport->timer_lock);
+}
+
+static void gameport_run_poll_handler(unsigned long d)
+{
+	struct gameport *gameport = (struct gameport *)d;
+
+	gameport->poll_handler(gameport);
+	if (gameport->poll_cnt)
+		mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
+}
+
+/*
+ * Basic gameport -> driver core mappings
+ */
+
+static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
+{
+	down_write(&gameport_bus.subsys.rwsem);
+
+	gameport->dev.driver = &drv->driver;
+	if (drv->connect(gameport, drv)) {
+		gameport->dev.driver = NULL;
+		goto out;
+	}
+	device_bind_driver(&gameport->dev);
+out:
+	up_write(&gameport_bus.subsys.rwsem);
+}
+
+static void gameport_release_driver(struct gameport *gameport)
+{
+	down_write(&gameport_bus.subsys.rwsem);
+	device_release_driver(&gameport->dev);
+	up_write(&gameport_bus.subsys.rwsem);
+}
+
+static void gameport_find_driver(struct gameport *gameport)
+{
+	down_write(&gameport_bus.subsys.rwsem);
+	device_attach(&gameport->dev);
+	up_write(&gameport_bus.subsys.rwsem);
+}
+
+
+/*
+ * Gameport event processing.
+ */
+
+enum gameport_event_type {
+	GAMEPORT_RESCAN,
+	GAMEPORT_RECONNECT,
+	GAMEPORT_REGISTER_PORT,
+	GAMEPORT_REGISTER_DRIVER,
+};
+
+struct gameport_event {
+	enum gameport_event_type type;
+	void *object;
+	struct module *owner;
+	struct list_head node;
+};
+
+static DEFINE_SPINLOCK(gameport_event_lock);	/* protects gameport_event_list */
+static LIST_HEAD(gameport_event_list);
+static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
+static DECLARE_COMPLETION(gameport_exited);
+static int gameport_pid;
+
+static void gameport_queue_event(void *object, struct module *owner,
+			      enum gameport_event_type event_type)
 {
-        struct gameport_dev *dev;
+	unsigned long flags;
+	struct gameport_event *event;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
 
-        list_for_each_entry(dev, &gameport_dev_list, node) {
-		if (gameport->dev)
+	/*
+ 	 * Scan event list for the other events for the same gameport port,
+	 * starting with the most recent one. If event is the same we
+	 * do not need add new one. If event is of different type we
+	 * need to add this event and should not look further because
+	 * we need to preseve sequence of distinct events.
+ 	 */
+	list_for_each_entry_reverse(event, &gameport_event_list, node) {
+		if (event->object == object) {
+			if (event->type == event_type)
+				goto out;
 			break;
-		if (dev->connect)
-                	dev->connect(gameport, dev);
-        }
+		}
+	}
+
+	if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) {
+		if (!try_module_get(owner)) {
+			printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type);
+			goto out;
+		}
+
+		event->type = event_type;
+		event->object = object;
+		event->owner = owner;
+
+		list_add_tail(&event->node, &gameport_event_list);
+		wake_up(&gameport_wait);
+	} else {
+		printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type);
+	}
+out:
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
 }
 
-void gameport_rescan(struct gameport *gameport)
+static void gameport_free_event(struct gameport_event *event)
 {
-	gameport_close(gameport);
-	gameport_find_dev(gameport);
+	module_put(event->owner);
+	kfree(event);
 }
 
-void gameport_register_port(struct gameport *gameport)
+static void gameport_remove_duplicate_events(struct gameport_event *event)
 {
-	list_add_tail(&gameport->node, &gameport_list);
+	struct list_head *node, *next;
+	struct gameport_event *e;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	list_for_each_safe(node, next, &gameport_event_list) {
+		e = list_entry(node, struct gameport_event, node);
+		if (event->object == e->object) {
+			/*
+			 * If this event is of different type we should not
+			 * look further - we only suppress duplicate events
+			 * that were sent back-to-back.
+			 */
+			if (event->type != e->type)
+				break;
+
+			list_del_init(node);
+			gameport_free_event(e);
+		}
+	}
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+}
+
+
+static struct gameport_event *gameport_get_event(void)
+{
+	struct gameport_event *event;
+	struct list_head *node;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	if (list_empty(&gameport_event_list)) {
+		spin_unlock_irqrestore(&gameport_event_lock, flags);
+		return NULL;
+	}
+
+	node = gameport_event_list.next;
+	event = list_entry(node, struct gameport_event, node);
+	list_del_init(node);
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+
+	return event;
+}
+
+static void gameport_handle_events(void)
+{
+	struct gameport_event *event;
+	struct gameport_driver *gameport_drv;
+
+	down(&gameport_sem);
+
+	while ((event = gameport_get_event())) {
+
+		switch (event->type) {
+			case GAMEPORT_REGISTER_PORT:
+				gameport_add_port(event->object);
+				break;
+
+			case GAMEPORT_RECONNECT:
+				gameport_reconnect_port(event->object);
+				break;
+
+			case GAMEPORT_RESCAN:
+				gameport_disconnect_port(event->object);
+				gameport_find_driver(event->object);
+				break;
+
+			case GAMEPORT_REGISTER_DRIVER:
+				gameport_drv = event->object;
+				driver_register(&gameport_drv->driver);
+				break;
+
+			default:
+				break;
+		}
+
+		gameport_remove_duplicate_events(event);
+		gameport_free_event(event);
+	}
+
+	up(&gameport_sem);
+}
+
+/*
+ * Remove all events that have been submitted for a given gameport port.
+ */
+static void gameport_remove_pending_events(struct gameport *gameport)
+{
+	struct list_head *node, *next;
+	struct gameport_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	list_for_each_safe(node, next, &gameport_event_list) {
+		event = list_entry(node, struct gameport_event, node);
+		if (event->object == gameport) {
+			list_del_init(node);
+			gameport_free_event(event);
+		}
+	}
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+}
+
+/*
+ * Destroy child gameport port (if any) that has not been fully registered yet.
+ *
+ * Note that we rely on the fact that port can have only one child and therefore
+ * only one child registration request can be pending. Additionally, children
+ * are registered by driver's connect() handler so there can't be a grandchild
+ * pending registration together with a child.
+ */
+static struct gameport *gameport_get_pending_child(struct gameport *parent)
+{
+	struct gameport_event *event;
+	struct gameport *gameport, *child = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gameport_event_lock, flags);
+
+	list_for_each_entry(event, &gameport_event_list, node) {
+		if (event->type == GAMEPORT_REGISTER_PORT) {
+			gameport = event->object;
+			if (gameport->parent == parent) {
+				child = gameport;
+				break;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&gameport_event_lock, flags);
+	return child;
+}
+
+static int gameport_thread(void *nothing)
+{
+	lock_kernel();
+	daemonize("kgameportd");
+	allow_signal(SIGTERM);
+
+	do {
+		gameport_handle_events();
+		wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
+		try_to_freeze(PF_FREEZE);
+	} while (!signal_pending(current));
+
+	printk(KERN_DEBUG "gameport: kgameportd exiting\n");
+
+	unlock_kernel();
+	complete_and_exit(&gameport_exited, 0);
+}
+
+
+/*
+ * Gameport port operations
+ */
+
+static ssize_t gameport_show_description(struct device *dev, char *buf)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	return sprintf(buf, "%s\n", gameport->name);
+}
+
+static ssize_t gameport_rebind_driver(struct device *dev, const char *buf, size_t count)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	struct device_driver *drv;
+	int retval;
+
+	retval = down_interruptible(&gameport_sem);
+	if (retval)
+		return retval;
+
+	retval = count;
+	if (!strncmp(buf, "none", count)) {
+		gameport_disconnect_port(gameport);
+	} else if (!strncmp(buf, "reconnect", count)) {
+		gameport_reconnect_port(gameport);
+	} else if (!strncmp(buf, "rescan", count)) {
+		gameport_disconnect_port(gameport);
+		gameport_find_driver(gameport);
+	} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
+		gameport_disconnect_port(gameport);
+		gameport_bind_driver(gameport, to_gameport_driver(drv));
+		put_driver(drv);
+	} else {
+		retval = -EINVAL;
+	}
+
+	up(&gameport_sem);
+
+	return retval;
+}
+
+static struct device_attribute gameport_device_attrs[] = {
+	__ATTR(description, S_IRUGO, gameport_show_description, NULL),
+	__ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver),
+	__ATTR_NULL
+};
+
+static void gameport_release_port(struct device *dev)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+
+	kfree(gameport);
+	module_put(THIS_MODULE);
+}
+
+void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args);
+	va_end(args);
+}
+
+/*
+ * Prepare gameport port for registration.
+ */
+static void gameport_init_port(struct gameport *gameport)
+{
+	static atomic_t gameport_no = ATOMIC_INIT(0);
+
+	__module_get(THIS_MODULE);
+
+	init_MUTEX(&gameport->drv_sem);
+	device_initialize(&gameport->dev);
+	snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id),
+		 "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
+	gameport->dev.bus = &gameport_bus;
+	gameport->dev.release = gameport_release_port;
+	if (gameport->parent)
+		gameport->dev.parent = &gameport->parent->dev;
+
+	spin_lock_init(&gameport->timer_lock);
+	init_timer(&gameport->poll_timer);
+	gameport->poll_timer.function = gameport_run_poll_handler;
+	gameport->poll_timer.data = (unsigned long)gameport;
+}
+
+/*
+ * Complete gameport port registration.
+ * Driver core will attempt to find appropriate driver for the port.
+ */
+static void gameport_add_port(struct gameport *gameport)
+{
+	if (gameport->parent)
+		gameport->parent->child = gameport;
+
 	gameport->speed = gameport_measure_speed(gameport);
-	gameport_find_dev(gameport);
+
+	list_add_tail(&gameport->node, &gameport_list);
+
+	if (gameport->io)
+		printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",
+			gameport->name, gameport->phys, gameport->io, gameport->speed);
+	else
+		printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
+			gameport->name, gameport->phys, gameport->speed);
+
+	device_add(&gameport->dev);
+	gameport->registered = 1;
+}
+
+/*
+ * gameport_destroy_port() completes deregistration process and removes
+ * port from the system
+ */
+static void gameport_destroy_port(struct gameport *gameport)
+{
+	struct gameport *child;
+
+	child = gameport_get_pending_child(gameport);
+	if (child) {
+		gameport_remove_pending_events(child);
+		put_device(&child->dev);
+	}
+
+	if (gameport->parent) {
+		gameport->parent->child = NULL;
+		gameport->parent = NULL;
+	}
+
+	if (gameport->registered) {
+		device_del(&gameport->dev);
+		list_del_init(&gameport->node);
+		gameport->registered = 0;
+	}
+
+	gameport_remove_pending_events(gameport);
+	put_device(&gameport->dev);
 }
 
+/*
+ * Reconnect gameport port and all its children (re-initialize attached devices)
+ */
+static void gameport_reconnect_port(struct gameport *gameport)
+{
+	do {
+		if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) {
+			gameport_disconnect_port(gameport);
+			gameport_find_driver(gameport);
+			/* Ok, old children are now gone, we are done */
+			break;
+		}
+		gameport = gameport->child;
+	} while (gameport);
+}
+
+/*
+ * gameport_disconnect_port() unbinds a port from its driver. As a side effect
+ * all child ports are unbound and destroyed.
+ */
+static void gameport_disconnect_port(struct gameport *gameport)
+{
+	struct gameport *s, *parent;
+
+	if (gameport->child) {
+		/*
+		 * Children ports should be disconnected and destroyed
+		 * first, staring with the leaf one, since we don't want
+		 * to do recursion
+		 */
+		for (s = gameport; s->child; s = s->child)
+			/* empty */;
+
+		do {
+			parent = s->parent;
+
+			gameport_release_driver(s);
+			gameport_destroy_port(s);
+		} while ((s = parent) != gameport);
+	}
+
+	/*
+	 * Ok, no children left, now disconnect this port
+	 */
+	gameport_release_driver(gameport);
+}
+
+void gameport_rescan(struct gameport *gameport)
+{
+	gameport_queue_event(gameport, NULL, GAMEPORT_RESCAN);
+}
+
+void gameport_reconnect(struct gameport *gameport)
+{
+	gameport_queue_event(gameport, NULL, GAMEPORT_RECONNECT);
+}
+
+/*
+ * Submits register request to kgameportd for subsequent execution.
+ * Note that port registration is always asynchronous.
+ */
+void __gameport_register_port(struct gameport *gameport, struct module *owner)
+{
+	gameport_init_port(gameport);
+	gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT);
+}
+
+/*
+ * Synchronously unregisters gameport port.
+ */
 void gameport_unregister_port(struct gameport *gameport)
 {
-	list_del_init(&gameport->node);
-	if (gameport->dev && gameport->dev->disconnect)
-		gameport->dev->disconnect(gameport);
+	down(&gameport_sem);
+	gameport_disconnect_port(gameport);
+	gameport_destroy_port(gameport);
+	up(&gameport_sem);
 }
 
-void gameport_register_device(struct gameport_dev *dev)
+
+/*
+ * Gameport driver operations
+ */
+
+static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf)
 {
-	struct gameport *gameport;
+	struct gameport_driver *driver = to_gameport_driver(drv);
+	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
+}
+
+static struct driver_attribute gameport_driver_attrs[] = {
+	__ATTR(description, S_IRUGO, gameport_driver_show_description, NULL),
+	__ATTR_NULL
+};
+
+static int gameport_driver_probe(struct device *dev)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	struct gameport_driver *drv = to_gameport_driver(dev->driver);
+
+	drv->connect(gameport, drv);
+	return gameport->drv ? 0 : -ENODEV;
+}
+
+static int gameport_driver_remove(struct device *dev)
+{
+	struct gameport *gameport = to_gameport_port(dev);
+	struct gameport_driver *drv = to_gameport_driver(dev->driver);
+
+	drv->disconnect(gameport);
+	return 0;
+}
 
-	list_add_tail(&dev->node, &gameport_dev_list);
-	list_for_each_entry(gameport, &gameport_list, node)
-		if (!gameport->dev && dev->connect)
-			dev->connect(gameport, dev);
+void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
+{
+	drv->driver.bus = &gameport_bus;
+	drv->driver.probe = gameport_driver_probe;
+	drv->driver.remove = gameport_driver_remove;
+	gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
 }
 
-void gameport_unregister_device(struct gameport_dev *dev)
+void gameport_unregister_driver(struct gameport_driver *drv)
 {
 	struct gameport *gameport;
 
-	list_del_init(&dev->node);
+	down(&gameport_sem);
+	drv->ignore = 1;	/* so gameport_find_driver ignores it */
+
+start_over:
 	list_for_each_entry(gameport, &gameport_list, node) {
-		if (gameport->dev == dev && dev->disconnect)
-			dev->disconnect(gameport);
-		gameport_find_dev(gameport);
+		if (gameport->drv == drv) {
+			gameport_disconnect_port(gameport);
+			gameport_find_driver(gameport);
+			/* we could've deleted some ports, restart */
+			goto start_over;
+		}
 	}
+
+	driver_unregister(&drv->driver);
+	up(&gameport_sem);
 }
 
-int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
+static int gameport_bus_match(struct device *dev, struct device_driver *drv)
 {
+	struct gameport_driver *gameport_drv = to_gameport_driver(drv);
+
+	return !gameport_drv->ignore;
+}
+
+static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv)
+{
+	down(&gameport->drv_sem);
+	gameport->drv = drv;
+	up(&gameport->drv_sem);
+}
+
+int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode)
+{
+
 	if (gameport->open) {
-		if (gameport->open(gameport, mode))
+		if (gameport->open(gameport, mode)) {
 			return -1;
+		}
 	} else {
 		if (mode != GAMEPORT_MODE_RAW)
 			return -1;
 	}
 
-	if (gameport->dev)
-		return -1;
-
-	gameport->dev = dev;
-
+	gameport_set_drv(gameport, drv);
 	return 0;
 }
 
 void gameport_close(struct gameport *gameport)
 {
-	gameport->dev = NULL;
+	del_timer_sync(&gameport->poll_timer);
+	gameport->poll_handler = NULL;
+	gameport->poll_interval = 0;
+	gameport_set_drv(gameport, NULL);
 	if (gameport->close)
 		gameport->close(gameport);
 }
+
+static int __init gameport_init(void)
+{
+	if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+		printk(KERN_ERR "gameport: Failed to start kgameportd\n");
+		return -1;
+	}
+
+	gameport_bus.dev_attrs = gameport_device_attrs;
+	gameport_bus.drv_attrs = gameport_driver_attrs;
+	gameport_bus.match = gameport_bus_match;
+	bus_register(&gameport_bus);
+
+	return 0;
+}
+
+static void __exit gameport_exit(void)
+{
+	bus_unregister(&gameport_bus);
+	kill_proc(gameport_pid, SIGTERM, 1);
+	wait_for_completion(&gameport_exited);
+}
+
+module_init(gameport_init);
+module_exit(gameport_exit);
diff -Nru a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c
--- a/drivers/input/gameport/lightning.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/lightning.c	2005-03-07 15:26:30 -08:00
@@ -54,12 +54,11 @@
 MODULE_LICENSE("GPL");
 
 struct l4 {
-	struct gameport gameport;
+	struct gameport *gameport;
 	unsigned char port;
-	char phys[32];
-} *l4_port[8];
+};
 
-char l4_name[] = "PDPI Lightning 4";
+static struct l4 l4_ports[8];
 
 /*
  * l4_wait_ready() waits for the L4 to become ready.
@@ -67,10 +66,10 @@
 
 static int l4_wait_ready(void)
 {
-	unsigned int t;
-	t = L4_TIMEOUT;
+	unsigned int t = L4_TIMEOUT;
+
 	while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
-	return -(t<=0);
+	return -(t <= 0);
 }
 
 /*
@@ -79,7 +78,7 @@
 
 static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->port_data;
 	unsigned char status;
 	int i, result = -1;
 
@@ -112,7 +111,8 @@
 
 static int l4_open(struct gameport *gameport, int mode)
 {
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->port_data;
+
         if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
 		return -1;
 	outb(L4_SELECT_ANALOG, L4_PORT);
@@ -129,24 +129,29 @@
 
 	outb(L4_SELECT_ANALOG, L4_PORT);
 	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+	if (inb(L4_PORT) & L4_BUSY)
+		goto out;
 
-	if (inb(L4_PORT) & L4_BUSY) goto fail;
 	outb(L4_CMD_GETCAL, L4_PORT);
+	if (l4_wait_ready())
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
-	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
+	if (l4_wait_ready())
+		goto out;
         outb(port & 3, L4_PORT);
 
 	for (i = 0; i < 4; i++) {
-		if (l4_wait_ready()) goto fail;
+		if (l4_wait_ready())
+			goto out;
 		cal[i] = inb(L4_PORT);
 	}
 
 	result = 0;
 
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);
+out:	outb(L4_SELECT_ANALOG, L4_PORT);
 	return result;
 }
 
@@ -160,24 +165,29 @@
 
 	outb(L4_SELECT_ANALOG, L4_PORT);
 	outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+	if (inb(L4_PORT) & L4_BUSY)
+		goto out;
 
-	if (inb(L4_PORT) & L4_BUSY) goto fail;
 	outb(L4_CMD_SETCAL, L4_PORT);
+	if (l4_wait_ready())
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
-	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2))
+		goto out;
 
-	if (l4_wait_ready()) goto fail;
+	if (l4_wait_ready())
+		goto out;
         outb(port & 3, L4_PORT);
 
 	for (i = 0; i < 4; i++) {
-		if (l4_wait_ready()) goto fail;
+		if (l4_wait_ready())
+			goto out;
 		outb(cal[i], L4_PORT);
 	}
 
 	result = 0;
 
-fail:	outb(L4_SELECT_ANALOG, L4_PORT);
+out:	outb(L4_SELECT_ANALOG, L4_PORT);
 	return result;
 }
 
@@ -190,7 +200,7 @@
 {
 	int i, t;
 	int cal[4];
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->port_data;
 
 	if (l4_getcal(l4->port, cal))
 		return -1;
@@ -209,73 +219,102 @@
 	return 0;
 }
 
-static int __init l4_init(void)
+static int __init l4_create_ports(int card_no)
 {
-	int cal[4] = {255,255,255,255};
-	int i, j, rev, cards = 0;
-	struct gameport *gameport;
 	struct l4 *l4;
+	struct gameport *port;
+	int i, idx;
 
-	if (!request_region(L4_PORT, 1, "lightning"))
-		return -1;
+	for (i = 0; i < 4; i++) {
 
-	for (i = 0; i < 2; i++) {
+		idx = card_no * 4 + i;
+		l4 = &l4_ports[idx];
 
-		outb(L4_SELECT_ANALOG, L4_PORT);
-		outb(L4_SELECT_DIGITAL + i, L4_PORT);
+		if (!(l4->gameport = port = gameport_allocate_port())) {
+			printk(KERN_ERR "lightning: Memory allocation failed\n");
+			while (--i >= 0) {
+				gameport_free_port(l4->gameport);
+				l4->gameport = NULL;
+			}
+			return -ENOMEM;
+		}
+		l4->port = idx;
 
-		if (inb(L4_PORT) & L4_BUSY) continue;
-		outb(L4_CMD_ID, L4_PORT);
+		port->port_data = l4;
+		port->open = l4_open;
+		port->cooked_read = l4_cooked_read;
+		port->calibrate = l4_calibrate;
 
-		if (l4_wait_ready()) continue;
-		if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
+		gameport_set_name(port, "PDPI Lightning 4");
+		gameport_set_phys(port, "isa%04x/gameport%d", L4_PORT, idx);
 
-		if (l4_wait_ready()) continue;
-		if (inb(L4_PORT) != L4_ID) continue;
+		if (idx == 0)
+			port->io = L4_PORT;
+	}
 
-		if (l4_wait_ready()) continue;
-		rev = inb(L4_PORT);
+	return 0;
+}
 
-		if (!rev) continue;
+static int __init l4_add_card(int card_no)
+{
+	int cal[4] = { 255, 255, 255, 255 };
+	int i, rev, result;
+	struct l4 *l4;
 
-		if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
-			printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
-			continue;
-		}
-		memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
+	outb(L4_SELECT_ANALOG, L4_PORT);
+	outb(L4_SELECT_DIGITAL + card_no, L4_PORT);
 
-		for (j = 0; j < 4; j++) {
+	if (inb(L4_PORT) & L4_BUSY)
+		return -1;
+	outb(L4_CMD_ID, L4_PORT);
 
-			l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
-			l4->port = i * 4 + j;
+	if (l4_wait_ready())
+		return -1;
 
-			sprintf(l4->phys, "isa%04x/gameport%d", L4_PORT, 4 * i + j);
+	if (inb(L4_PORT) != L4_SELECT_DIGITAL + card_no)
+		return -1;
 
-			gameport = &l4->gameport;
-			gameport->driver = l4;
-			gameport->open = l4_open;
-			gameport->cooked_read = l4_cooked_read;
-			gameport->calibrate = l4_calibrate;
+	if (l4_wait_ready())
+		return -1;
+	if (inb(L4_PORT) != L4_ID)
+		return -1;
 
-			gameport->name = l4_name;
-			gameport->phys = l4->phys;
-			gameport->id.bustype = BUS_ISA;
+	if (l4_wait_ready())
+		return -1;
+	rev = inb(L4_PORT);
 
-			if (!i && !j)
-				gameport->io = L4_PORT;
+	if (!rev)
+		return -1;
 
-			if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
-				l4_setcal(l4->port, cal);
+	result = l4_create_ports(card_no);
+	if (result)
+		return result;
 
-			gameport_register_port(gameport);
-		}
+	printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
+		card_no ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
 
-		printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
-			i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
+	for (i = 0; i < 4; i++) {
+		l4 = &l4_ports[card_no * 4 + i];
 
-		cards++;
+		if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
+			l4_setcal(l4->port, cal);
+		gameport_register_port(l4->gameport);
 	}
 
+	return 0;
+}
+
+static int __init l4_init(void)
+{
+	int i, cards = 0;
+
+	if (!request_region(L4_PORT, 1, "lightning"))
+		return -1;
+
+	for (i = 0; i < 2; i++)
+		if (l4_add_card(i) == 0)
+			cards++;
+
 	outb(L4_SELECT_ANALOG, L4_PORT);
 
 	if (!cards) {
@@ -289,13 +328,14 @@
 static void __exit l4_exit(void)
 {
 	int i;
-	int cal[4] = {59, 59, 59, 59};
+	int cal[4] = { 59, 59, 59, 59 };
 
 	for (i = 0; i < 8; i++)
-		if (l4_port[i]) {
-			l4_setcal(l4_port[i]->port, cal);
-			gameport_unregister_port(&l4_port[i]->gameport);
+		if (l4_ports[i].gameport) {
+			l4_setcal(l4_ports[i].port, cal);
+			gameport_unregister_port(l4_ports[i].gameport);
 		}
+
 	outb(L4_SELECT_ANALOG, L4_PORT);
 	release_region(L4_PORT, 1);
 }
diff -Nru a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
--- a/drivers/input/gameport/ns558.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/ns558.c	2005-03-07 15:26:30 -08:00
@@ -44,20 +44,16 @@
 MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
 MODULE_LICENSE("GPL");
 
-#define NS558_ISA	1
-#define NS558_PNP	2
-
 static int ns558_isa_portlist[] = { 0x201, 0x200, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
 				    0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
 
 struct ns558 {
 	int type;
+	int io;
 	int size;
 	struct pnp_dev *dev;
+	struct gameport *gameport;
 	struct list_head node;
-	struct gameport gameport;
-	char phys[32];
-	char name[32];
 };
 
 static LIST_HEAD(ns558_list);
@@ -68,18 +64,19 @@
  * A joystick must be attached for this to work.
  */
 
-static void ns558_isa_probe(int io)
+static int ns558_isa_probe(int io)
 {
 	int i, j, b;
 	unsigned char c, u, v;
-	struct ns558 *port;
+	struct ns558 *ns558;
+	struct gameport *port;
 
 /*
  * No one should be using this address.
  */
 
 	if (!request_region(io, 1, "ns558-isa"))
-		return;
+		return -EBUSY;
 
 /*
  * We must not be able to write arbitrary values to the port.
@@ -90,8 +87,8 @@
 	outb(~c & ~3, io);
 	if (~(u = v = inb(io)) & 3) {
 		outb(c, io);
-		i = 0;
-		goto out;
+		release_region(io, 1);
+		return -ENODEV;
 	}
 /*
  * After a trigger, there must be at least some bits changing.
@@ -101,8 +98,8 @@
 
 	if (u == v) {
 		outb(c, io);
-		i = 0;
-		goto out;
+		release_region(io, 1);
+		return -ENODEV;
 	}
 	msleep(3);
 /*
@@ -113,8 +110,8 @@
 	for (i = 0; i < 1000; i++)
 		if ((u ^ inb(io)) & 0xf) {
 			outb(c, io);
-			i = 0;
-			goto out;
+			release_region(io, 1);
+			return -ENODEV;
 		}
 /*
  * And now find the number of mirrors of the port.
@@ -122,17 +119,17 @@
 
 	for (i = 1; i < 5; i++) {
 
-		release_region(io & (-1 << (i-1)), (1 << (i-1)));
+		release_region(io & (-1 << (i - 1)), (1 << (i - 1)));
 
-		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))	/* Don't disturb anyone */
-			break;
+		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
+			break;				/* Don't disturb anyone */
 
 		outb(0xff, io & (-1 << i));
 		for (j = b = 0; j < 1000; j++)
 			if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
 		msleep(3);
 
-		if (b > 300) {					/* We allow 30% difference */
+		if (b > 300) {				/* We allow 30% difference */
 			release_region(io & (-1 << i), (1 << i));
 			break;
 		}
@@ -142,35 +139,33 @@
 
 	if (i != 4) {
 		if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
-			return;
+			return -EBUSY;
 	}
 
-	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+	ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!ns558 || !port) {
 		printk(KERN_ERR "ns558: Memory allocation failed.\n");
-		goto out;
+		release_region(io & (-1 << i), (1 << i));
+		kfree(ns558);
+		gameport_free_port(port);
+		return -ENOMEM;
 	}
-	memset(port, 0, sizeof(struct ns558));
 
-	port->type = NS558_ISA;
-	port->size = (1 << i);
-	port->gameport.io = io;
-	port->gameport.phys = port->phys;
-	port->gameport.name = port->name;
-	port->gameport.id.bustype = BUS_ISA;
-
-	sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
-	sprintf(port->name, "NS558 ISA");
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
-	if (port->size > 1) printk(" size %d", port->size);
-	printk(" speed %d kHz\n", port->gameport.speed);
-
-	list_add(&port->node, &ns558_list);
-	return;
-out:
-	release_region(io & (-1 << i), (1 << i));
+	memset(ns558, 0, sizeof(struct ns558));
+	ns558->io = io;
+	ns558->size = 1 << i;
+	ns558->gameport = port;
+
+	port->io = io;
+	gameport_set_name(port, "NS558 ISA Gameport");
+	gameport_set_phys(port, "isa%04x/gameport0", io & (-1 << i));
+
+	gameport_register_port(port);
+
+	list_add(&ns558->node, &ns558_list);
+
+	return 0;
 }
 
 #ifdef CONFIG_PNP
@@ -206,46 +201,42 @@
 static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
 {
 	int ioport, iolen;
-	struct ns558 *port;
+	struct ns558 *ns558;
+	struct gameport *port;
 
 	if (!pnp_port_valid(dev, 0)) {
 		printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
 		return -ENODEV;
 	}
 
-	ioport = pnp_port_start(dev,0);
-	iolen = pnp_port_len(dev,0);
+	ioport = pnp_port_start(dev, 0);
+	iolen = pnp_port_len(dev, 0);
 
 	if (!request_region(ioport, iolen, "ns558-pnp"))
 		return -EBUSY;
 
-	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
-		printk(KERN_ERR "ns558: Memory allocation failed.\n");
+	ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!ns558 || !port) {
+		printk(KERN_ERR "ns558: Memory allocation failed\n");
+		kfree(ns558);
+		gameport_free_port(port);
 		return -ENOMEM;
 	}
-	memset(port, 0, sizeof(struct ns558));
 
-	port->type = NS558_PNP;
-	port->size = iolen;
-	port->dev = dev;
+	ns558->io = ioport;
+	ns558->size = iolen;
+	ns558->dev = dev;
+	ns558->gameport = port;
+
+	gameport_set_name(port, "NS558 PnP Gameport");
+	gameport_set_phys(port, "pnp%s/gameport0", dev->dev.bus_id);
+	port->dev.parent = &dev->dev;
+	port->io = ioport;
 
-	port->gameport.io = ioport;
-	port->gameport.phys = port->phys;
-	port->gameport.name = port->name;
-	port->gameport.id.bustype = BUS_ISAPNP;
-	port->gameport.id.version = 0x100;
+	gameport_register_port(port);
 
-	sprintf(port->phys, "pnp%s/gameport0", dev->dev.bus_id);
-	sprintf(port->name, "%s", "NS558 PnP Gameport");
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport: NS558 PnP at pnp%s io %#x",
-		dev->dev.bus_id, port->gameport.io);
-	if (iolen > 1) printk(" size %d", iolen);
-	printk(" speed %d kHz\n", port->gameport.speed);
-
-	list_add_tail(&port->node, &ns558_list);
+	list_add_tail(&ns558->node, &ns558_list);
 	return 0;
 }
 
@@ -261,43 +252,39 @@
 
 #endif
 
-int __init ns558_init(void)
+static int pnp_registered = 0;
+
+static int __init ns558_init(void)
 {
 	int i = 0;
 
 /*
- * Probe for ISA ports.
+ * Probe ISA ports first so that PnP gets to choose free port addresses
+ * not occupied by the ISA ports.
  */
 
 	while (ns558_isa_portlist[i])
 		ns558_isa_probe(ns558_isa_portlist[i++]);
 
-	pnp_register_driver(&ns558_pnp_driver);
-	return list_empty(&ns558_list) ? -ENODEV : 0;
-}
+	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
+		pnp_registered = 1;
 
-void __exit ns558_exit(void)
-{
-	struct ns558 *port;
 
-	list_for_each_entry(port, &ns558_list, node) {
-		gameport_unregister_port(&port->gameport);
-		switch (port->type) {
+	return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
+}
 
-#ifdef CONFIG_PNP
-			case NS558_PNP:
-				/* fall through */
-#endif
-			case NS558_ISA:
-				release_region(port->gameport.io & ~(port->size - 1), port->size);
-				kfree(port);
-				break;
+static void __exit ns558_exit(void)
+{
+	struct ns558 *ns558;
 
-			default:
-				break;
-		}
+	list_for_each_entry(ns558, &ns558_list, node) {
+		gameport_unregister_port(ns558->gameport);
+		release_region(ns558->io & ~(ns558->size - 1), ns558->size);
+		kfree(ns558);
 	}
-	pnp_unregister_driver(&ns558_pnp_driver);
+
+	if (pnp_registered)
+		pnp_unregister_driver(&ns558_pnp_driver);
 }
 
 module_init(ns558_init);
diff -Nru a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
--- a/drivers/input/gameport/vortex.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/gameport/vortex.c	2005-03-07 15:26:30 -08:00
@@ -53,28 +53,27 @@
 #define VORTEX_DATA_WAIT	20	/* 20 ms */
 
 struct vortex {
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct pci_dev *dev;
-        unsigned char __iomem *base;
-        unsigned char __iomem *io;
-	char phys[32];
+	unsigned char __iomem *base;
+	unsigned char __iomem *io;
 };
 
 static unsigned char vortex_read(struct gameport *gameport)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 	return readb(vortex->io + VORTEX_LEG);
 }
 
 static void vortex_trigger(struct gameport *gameport)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 	writeb(0xff, vortex->io + VORTEX_LEG);
 }
 
 static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 	int i;
 
 	*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
@@ -89,7 +88,7 @@
 
 static int vortex_open(struct gameport *gameport, int mode)
 {
-	struct vortex *vortex = gameport->driver;
+	struct vortex *vortex = gameport->port_data;
 
 	switch (mode) {
 		case GAMEPORT_MODE_COOKED:
@@ -109,30 +108,17 @@
 static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	struct vortex *vortex;
+	struct gameport *port;
 	int i;
 
-	if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL)))
-		return -1;
-        memset(vortex, 0, sizeof(struct vortex));
-
-	vortex->dev = dev;
-	sprintf(vortex->phys, "pci%s/gameport0", pci_name(dev));
-
-	pci_set_drvdata(dev, vortex);
-
-	vortex->gameport.driver = vortex;
-	vortex->gameport.fuzz = 64;
-
-	vortex->gameport.read = vortex_read;
-	vortex->gameport.trigger = vortex_trigger;
-	vortex->gameport.cooked_read = vortex_cooked_read;
-	vortex->gameport.open = vortex_open;
-
-	vortex->gameport.name = pci_name(dev);
-	vortex->gameport.phys = vortex->phys;
-	vortex->gameport.id.bustype = BUS_PCI;
-	vortex->gameport.id.vendor = dev->vendor;
-	vortex->gameport.id.product = dev->device;
+	vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
+	port = gameport_allocate_port();
+	if (!vortex || !port) {
+		printk(KERN_ERR "vortex: Memory allocation failed.\n");
+		kfree(vortex);
+		gameport_free_port(port);
+		return -ENOMEM;
+	}
 
 	for (i = 0; i < 6; i++)
 		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
@@ -140,14 +126,26 @@
 
 	pci_enable_device(dev);
 
+	vortex->dev = dev;
+	vortex->gameport = port;
 	vortex->base = ioremap(pci_resource_start(vortex->dev, i),
 				pci_resource_len(vortex->dev, i));
 	vortex->io = vortex->base + id->driver_data;
 
-	gameport_register_port(&vortex->gameport);
+	pci_set_drvdata(dev, vortex);
+
+	port->port_data = vortex;
+	port->fuzz = 64;
 
-	printk(KERN_INFO "gameport at pci%s speed %d kHz\n",
-		pci_name(dev), vortex->gameport.speed);
+	gameport_set_name(port, "AU88x0");
+	gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
+	port->dev.parent = &dev->dev;
+	port->read = vortex_read;
+	port->trigger = vortex_trigger;
+	port->cooked_read = vortex_cooked_read;
+	port->open = vortex_open;
+
+	gameport_register_port(port);
 
 	return 0;
 }
@@ -155,15 +153,17 @@
 static void __devexit vortex_remove(struct pci_dev *dev)
 {
 	struct vortex *vortex = pci_get_drvdata(dev);
-	gameport_unregister_port(&vortex->gameport);
+
+	gameport_unregister_port(vortex->gameport);
 	iounmap(vortex->base);
 	kfree(vortex);
 }
 
-static struct pci_device_id vortex_id_table[] =
-{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
- { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
- { 0 }};
+static struct pci_device_id vortex_id_table[] = {
+	{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
+	{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
+	{ 0 }
+};
 
 static struct pci_driver vortex_driver = {
 	.name =		"vortex_gameport",
@@ -172,12 +172,12 @@
 	.remove =	__devexit_p(vortex_remove),
 };
 
-int __init vortex_init(void)
+static int __init vortex_init(void)
 {
-	return pci_module_init(&vortex_driver);
+	return pci_register_driver(&vortex_driver);
 }
 
-void __exit vortex_exit(void)
+static void __exit vortex_exit(void)
 {
 	pci_unregister_driver(&vortex_driver);
 }
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/input.c	2005-03-07 15:26:30 -08:00
@@ -50,18 +50,10 @@
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *proc_bus_input_dir;
-DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
+static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
 static int input_devices_state;
 #endif
 
-static inline unsigned int ms_to_jiffies(unsigned int ms)
-{
-        unsigned int j;
-        j = (ms * HZ + 500) / 1000;
-        return (j > 0) ? j : 1;
-}
-
-
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	struct input_handle *handle;
@@ -96,9 +88,9 @@
 
 			change_bit(code, dev->key);
 
-			if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->timer.data && value) {
+			if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
 				dev->repeat_key = code;
-				mod_timer(&dev->timer, jiffies + ms_to_jiffies(dev->rep[REP_DELAY]));
+				mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
 			}
 
 			break;
@@ -198,7 +190,8 @@
 	input_event(dev, EV_KEY, dev->repeat_key, 2);
 	input_sync(dev);
 
-	mod_timer(&dev->timer, jiffies + ms_to_jiffies(dev->rep[REP_PERIOD]));
+	if (dev->rep[REP_PERIOD])
+		mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
 }
 
 int input_accept_process(struct input_handle *handle, struct file *file)
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joydev.c	2005-03-07 15:26:30 -08:00
@@ -47,15 +47,15 @@
 	struct input_handle handle;
 	wait_queue_head_t wait;
 	struct list_head list;
-	struct js_corr corr[ABS_MAX];
+	struct js_corr corr[ABS_MAX + 1];
 	struct JS_DATA_SAVE_TYPE glue;
 	int nabs;
 	int nkey;
-	__u16 keymap[KEY_MAX - BTN_MISC];
-	__u16 keypam[KEY_MAX - BTN_MISC];
-	__u8 absmap[ABS_MAX];
-	__u8 abspam[ABS_MAX];
-	__s16 abs[ABS_MAX];
+	__u16 keymap[KEY_MAX - BTN_MISC + 1];
+	__u16 keypam[KEY_MAX - BTN_MISC + 1];
+	__u8 absmap[ABS_MAX + 1];
+	__u8 abspam[ABS_MAX + 1];
+	__s16 abs[ABS_MAX + 1];
 };
 
 struct joydev_list {
@@ -281,9 +281,8 @@
 {
 	struct joydev_list *list = file->private_data;
 	poll_wait(file, &list->joydev->wait, wait);
-	if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? 
+		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -338,7 +337,7 @@
 			return copy_to_user(argp, joydev->corr,
 						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
 		case JSIOCSAXMAP:
-			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * ABS_MAX))
+			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
 				return -EFAULT;
 			for (i = 0; i < joydev->nabs; i++) {
 				if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
@@ -347,9 +346,9 @@
 			return 0;
 		case JSIOCGAXMAP:
 			return copy_to_user(argp, joydev->abspam,
-						sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
+						sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
 		case JSIOCSBTNMAP:
-			if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
+			if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
 				return -EFAULT;
 			for (i = 0; i < joydev->nkey; i++) {
 				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
@@ -358,7 +357,7 @@
 			return 0;
 		case JSIOCGBTNMAP:
 			return copy_to_user(argp, joydev->keypam,
-						sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
+						sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
 		default:
 			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
 				int len;
@@ -409,21 +408,21 @@
 	joydev->handle.private = joydev;
 	sprintf(joydev->name, "js%d", minor);
 
-	for (i = 0; i < ABS_MAX; i++)
+	for (i = 0; i < ABS_MAX + 1; i++)
 		if (test_bit(i, dev->absbit)) {
 			joydev->absmap[i] = joydev->nabs;
 			joydev->abspam[joydev->nabs] = i;
 			joydev->nabs++;
 		}
 
-	for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
+	for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++)
 		if (test_bit(i + BTN_MISC, dev->keybit)) {
 			joydev->keymap[i] = joydev->nkey;
 			joydev->keypam[joydev->nkey] = i + BTN_MISC;
 			joydev->nkey++;
 		}
 
-	for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
+	for (i = 0; i < BTN_JOYSTICK - BTN_MISC + 1; i++)
 		if (test_bit(i + BTN_MISC, dev->keybit)) {
 			joydev->keymap[i] = joydev->nkey;
 			joydev->keypam[joydev->nkey] = i + BTN_MISC;
@@ -463,14 +462,18 @@
 static void joydev_disconnect(struct input_handle *handle)
 {
 	struct joydev *joydev = handle->private;
+	struct joydev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
 	devfs_remove("input/js%d", joydev->minor);
 	joydev->exist = 0;
 
-	if (joydev->open)
+	if (joydev->open) {
 		input_close_device(handle);
-	else
+		wake_up_interruptible(&joydev->wait);
+		list_for_each_entry(list, &joydev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+	} else
 		joydev_free(joydev);
 }
 
diff -Nru a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
--- a/drivers/input/joystick/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/Kconfig	2005-03-07 15:26:30 -08:00
@@ -1,9 +1,8 @@
 #
 # Joystick driver configuration
 #
-config INPUT_JOYSTICK
+menuconfig INPUT_JOYSTICK
 	bool "Joysticks"
-	depends on INPUT
 	help
 	  If you have a joystick, 6dof controller, gamepad, steering wheel,
 	  weapon control system or something like that you can say Y here
@@ -13,9 +12,11 @@
 	  Please read the file <file:Documentation/input/joystick.txt> which
 	  contains more information.
 
+if INPUT_JOYSTICK
+
 config JOYSTICK_ANALOG
 	tristate "Classic PC analog joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	---help---
 	  Say Y here if you have a joystick that connects to the PC
 	  gameport. In addition to the usual PC analog joystick, this driver
@@ -32,7 +33,7 @@
 
 config JOYSTICK_A3D
 	tristate "Assasin 3D and MadCatz Panther devices"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have an FPGaming or MadCatz controller using the
 	  A3D protocol over the PC gameport.
@@ -42,7 +43,7 @@
 
 config JOYSTICK_ADI
 	tristate "Logitech ADI digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Logitech controller using the ADI
 	  protocol over the PC gameport.
@@ -52,7 +53,7 @@
 
 config JOYSTICK_COBRA
 	tristate "Creative Labs Blaster Cobra gamepad"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Creative Labs Blaster Cobra gamepad.
 
@@ -61,7 +62,7 @@
 
 config JOYSTICK_GF2K
 	tristate "Genius Flight2000 Digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Genius Flight2000 or MaxFighter digitally
 	  communicating joystick or gamepad.
@@ -71,7 +72,7 @@
 
 config JOYSTICK_GRIP
 	tristate "Gravis GrIP joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Gravis controller using the GrIP protocol
 	  over the PC gameport.
@@ -81,7 +82,7 @@
 
 config JOYSTICK_GRIP_MP
 	tristate "Gravis GrIP MultiPort"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have the original Gravis GrIP MultiPort, a hub
 	  that connects to the gameport and you connect gamepads to it.
@@ -91,7 +92,7 @@
 
 config JOYSTICK_GUILLEMOT
 	tristate "Guillemot joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Guillemot joystick using a digital
 	  protocol over the PC gameport.
@@ -101,7 +102,7 @@
 
 config JOYSTICK_INTERACT
 	tristate "InterAct digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have an InterAct gameport or joystick
 	  communicating digitally over the gameport.
@@ -111,7 +112,7 @@
 
 config JOYSTICK_SIDEWINDER
 	tristate "Microsoft SideWinder digital joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a Microsoft controller using the Digital
 	  Overdrive protocol over PC gameport.
@@ -121,7 +122,7 @@
 
 config JOYSTICK_TMDC
 	tristate "ThrustMaster DirectConnect joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you have a ThrustMaster controller using the
 	  DirectConnect (BSP) protocol over the PC gameport.
@@ -133,7 +134,6 @@
 
 config JOYSTICK_WARRIOR
 	tristate "Logitech WingMan Warrior joystick"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Logitech WingMan Warrior joystick connected
@@ -144,7 +144,6 @@
 
 config JOYSTICK_MAGELLAN
 	tristate "LogiCad3d Magellan/SpaceMouse 6dof controllers"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Magellan or Space Mouse 6DOF controller
@@ -155,7 +154,6 @@
 
 config JOYSTICK_SPACEORB
 	tristate "SpaceTec SpaceOrb/Avenger 6dof controllers"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
@@ -166,7 +164,6 @@
 
 config JOYSTICK_SPACEBALL
 	tristate "SpaceTec SpaceBall 6dof controllers"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a SpaceTec SpaceBall 2003/3003/4000 FLX
@@ -178,7 +175,6 @@
 
 config JOYSTICK_STINGER
 	tristate "Gravis Stinger gamepad"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Gravis Stinger connected to one of your
@@ -187,9 +183,8 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called stinger.
 
-config JOYSTICK_TWIDDLER
+config JOYSTICK_TWIDJOY
 	tristate "Twiddler as a joystick"
-	depends on INPUT && INPUT_JOYSTICK
 	select SERIO
 	help
 	  Say Y here if you have a Handykey Twiddler connected to your
@@ -200,7 +195,7 @@
 
 config JOYSTICK_DB9
 	tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && PARPORT
+	depends on PARPORT
 	---help---
 	  Say Y here if you have a Sega Master System gamepad, Sega Genesis
 	  gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
@@ -213,7 +208,7 @@
 
 config JOYSTICK_GAMECON
 	tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
-	depends on INPUT && INPUT_JOYSTICK && PARPORT
+	depends on PARPORT
 	---help---
 	  Say Y here if you have a Nintendo Entertainment System gamepad,
 	  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
@@ -227,7 +222,7 @@
 
 config JOYSTICK_TURBOGRAFX
 	tristate "Multisystem joysticks via TurboGraFX device"
-	depends on INPUT && INPUT_JOYSTICK && PARPORT
+	depends on PARPORT
 	help
 	  Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
 	  and want to use it with Multisystem -- Atari, Amiga, Commodore,
@@ -239,7 +234,7 @@
 
 config JOYSTICK_AMIGA
 	tristate "Amiga joysticks"
-	depends on AMIGA && INPUT && INPUT_JOYSTICK
+	depends on AMIGA
 	help
 	  Say Y here if you have an Amiga with a digital joystick connected
 	  to it.
@@ -249,7 +244,7 @@
 
 config JOYSTICK_JOYDUMP
 	tristate "Gameport data dumper"
-	depends on INPUT && INPUT_JOYSTICK && GAMEPORT
+	select GAMEPORT
 	help
 	  Say Y here if you want to dump data from your joystick into the system
 	  log for debugging purposes. Say N if you are making a production
@@ -258,3 +253,4 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called joydump.
 
+endif
diff -Nru a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
--- a/drivers/input/joystick/a3d.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/a3d.c	2005-03-07 15:26:30 -08:00
@@ -35,38 +35,35 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"FP-Gaming Assasin 3D joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define A3D_MAX_START		400	/* 400 us */
-#define A3D_MAX_STROBE		60	/* 40 us */
-#define A3D_DELAY_READ		3	/* 3 ms */
+#define A3D_MAX_START		600	/* 600 us */
+#define A3D_MAX_STROBE		80	/* 80 us */
 #define A3D_MAX_LENGTH		40	/* 40*3 bits */
-#define A3D_REFRESH_TIME	HZ/50	/* 20 ms */
 
 #define A3D_MODE_A3D		1	/* Assassin 3D */
 #define A3D_MODE_PAN		2	/* Panther */
 #define A3D_MODE_OEM		3	/* Panther OEM version */
 #define A3D_MODE_PXL		4	/* Panther XL */
 
-char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
+static char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
 			"MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
 
 struct a3d {
 	struct gameport *gameport;
-	struct gameport adc;
+	struct gameport *adc;
 	struct input_dev dev;
-	struct timer_list timer;
 	int axes[4];
 	int buttons;
 	int mode;
 	int length;
-	int used;
 	int reads;
 	int bads;
 	char phys[32];
-	char adcphys[32];
 };
 
 /*
@@ -109,7 +106,9 @@
 static int a3d_csum(char *data, int count)
 {
 	int i, csum = 0;
-	for (i = 0; i < count - 2; i++) csum += data[i];
+
+	for (i = 0; i < count - 2; i++)
+		csum += data[i];
 	return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
 }
 
@@ -139,7 +138,7 @@
 
 			a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
 
-			return;
+			break;
 
 		case A3D_MODE_PXL:
 
@@ -169,24 +168,26 @@
 
 			input_sync(dev);
 
-			return;
+			break;
 	}
 }
 
 
 /*
- * a3d_timer() reads and analyzes A3D joystick data.
+ * a3d_poll() reads and analyzes A3D joystick data.
  */
 
-static void a3d_timer(unsigned long private)
+static void a3d_poll(struct gameport *gameport)
 {
-	struct a3d *a3d = (void *) private;
+	struct a3d *a3d = gameport_get_drvdata(gameport);
 	unsigned char data[A3D_MAX_LENGTH];
+
 	a3d->reads++;
-	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
-		|| data[0] != a3d->mode || a3d_csum(data, a3d->length))
-	 	a3d->bads++; else a3d_read(a3d, data);
-	mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
+	    data[0] != a3d->mode || a3d_csum(data, a3d->length))
+	 	a3d->bads++;
+	else
+		a3d_read(a3d, data);
 }
 
 /*
@@ -195,10 +196,11 @@
  * call this more than 50 times a second, which would use too much CPU.
  */
 
-int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct a3d *a3d = gameport->driver;
+	struct a3d *a3d = gameport->port_data;
 	int i;
+
 	for (i = 0; i < 4; i++)
 		axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
 	*buttons = a3d->buttons;
@@ -210,13 +212,14 @@
  * any but cooked data.
  */
 
-int a3d_adc_open(struct gameport *gameport, int mode)
+static int a3d_adc_open(struct gameport *gameport, int mode)
 {
-	struct a3d *a3d = gameport->driver;
+	struct a3d *a3d = gameport->port_data;
+
 	if (mode != GAMEPORT_MODE_COOKED)
 		return -1;
-	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+
+	gameport_start_polling(a3d->gameport);
 	return 0;
 }
 
@@ -226,9 +229,9 @@
 
 static void a3d_adc_close(struct gameport *gameport)
 {
-	struct a3d *a3d = gameport->driver;
-	if (!--a3d->used)
-		del_timer(&a3d->timer);
+	struct a3d *a3d = gameport->port_data;
+
+	gameport_stop_polling(a3d->gameport);
 }
 
 /*
@@ -238,8 +241,8 @@
 static int a3d_open(struct input_dev *dev)
 {
 	struct a3d *a3d = dev->private;
-	if (!a3d->used++)
-		mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+
+	gameport_start_polling(a3d->gameport);
 	return 0;
 }
 
@@ -250,49 +253,53 @@
 static void a3d_close(struct input_dev *dev)
 {
 	struct a3d *a3d = dev->private;
-	if (!--a3d->used)
-		del_timer(&a3d->timer);
+
+	gameport_stop_polling(a3d->gameport);
 }
 
 /*
  * a3d_connect() probes for A3D joysticks.
  */
 
-static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct a3d *a3d;
+	struct gameport *adc;
 	unsigned char data[A3D_MAX_LENGTH];
 	int i;
+	int err;
 
-	if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
-		return;
-	memset(a3d, 0, sizeof(struct a3d));
-
-	gameport->private = a3d;
+	if (!(a3d = kcalloc(1, sizeof(struct a3d), GFP_KERNEL)))
+		return -ENOMEM;
 
 	a3d->gameport = gameport;
-	init_timer(&a3d->timer);
-	a3d->timer.data = (long) a3d;
-	a3d->timer.function = a3d_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, a3d);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
 
-	if (!i || a3d_csum(data, i))
+	if (!i || a3d_csum(data, i)) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
 	a3d->mode = data[0];
 
 	if (!a3d->mode || a3d->mode > 5) {
 		printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
 			"(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, a3d_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(a3d->phys, "%s/input0", gameport->phys);
-	sprintf(a3d->adcphys, "%s/gameport0", gameport->phys);
 
 	if (a3d->mode == A3D_MODE_PXL) {
 
@@ -315,16 +322,11 @@
 		a3d_read(a3d, data);
 
 		for (i = 0; i < 4; i++) {
-			if (i < 2) {
-				a3d->dev.absmin[axes[i]] = 48;
-				a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
-				a3d->dev.absflat[axes[i]] = 8;
-			} else {
-				a3d->dev.absmin[axes[i]] = 2;
-				a3d->dev.absmax[axes[i]] = 253;
-			}
-			a3d->dev.absmin[ABS_HAT0X + i] = -1;
-			a3d->dev.absmax[ABS_HAT0X + i] = 1;
+			if (i < 2)
+				input_set_abs_params(&a3d->dev, axes[i], 48, a3d->dev.abs[axes[i]] * 2 - 48, 0, 8);
+			else
+				input_set_abs_params(&a3d->dev, axes[i], 2, 253, 0, 0);
+			input_set_abs_params(&a3d->dev, ABS_HAT0X + i, -1, 1, 0, 0);
 		}
 
 	} else {
@@ -336,23 +338,23 @@
 		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
 		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
 
-		a3d->adc.driver = a3d;
-		a3d->adc.open = a3d_adc_open;
-		a3d->adc.close = a3d_adc_close;
-		a3d->adc.cooked_read = a3d_adc_cooked_read;
-		a3d->adc.fuzz = 1;
-
-		a3d->adc.name = a3d_names[a3d->mode];
-		a3d->adc.phys = a3d->adcphys;
-		a3d->adc.id.bustype = BUS_GAMEPORT;
-		a3d->adc.id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
-		a3d->adc.id.product = a3d->mode;
-		a3d->adc.id.version = 0x0100;
-
 		a3d_read(a3d, data);
 
-		gameport_register_port(&a3d->adc);
-		printk(KERN_INFO "gameport: %s on %s\n", a3d_names[a3d->mode], gameport->phys);
+		if (!(a3d->adc = adc = gameport_allocate_port()))
+			printk(KERN_ERR "a3d: Not enough memory for ADC port\n");
+		else {
+			adc->port_data = a3d;
+			adc->open = a3d_adc_open;
+			adc->close = a3d_adc_close;
+			adc->cooked_read = a3d_adc_cooked_read;
+			adc->fuzz = 1;
+
+			gameport_set_name(adc, a3d_names[a3d->mode]);
+			gameport_set_phys(adc, "%s/gameport0", gameport->phys);
+			adc->dev.parent = &gameport->dev;
+
+			gameport_register_port(adc);
+		}
 	}
 
 	a3d->dev.private = a3d;
@@ -369,36 +371,46 @@
 	input_register_device(&a3d->dev);
 	printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:  kfree(a3d);
+fail1:  gameport_set_drvdata(gameport, NULL);
+	kfree(a3d);
+	return err;
 }
 
 static void a3d_disconnect(struct gameport *gameport)
 {
+	struct a3d *a3d = gameport_get_drvdata(gameport);
 
-	struct a3d *a3d = gameport->private;
 	input_unregister_device(&a3d->dev);
-	if (a3d->mode < A3D_MODE_PXL)
-		gameport_unregister_port(&a3d->adc);
+	if (a3d->adc) {
+		gameport_unregister_port(a3d->adc);
+		a3d->adc = NULL;
+	}
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(a3d);
 }
 
-static struct gameport_dev a3d_dev = {
-	.connect =	a3d_connect,
-	.disconnect =	a3d_disconnect,
+static struct gameport_driver a3d_drv = {
+	.driver		= {
+		.name	= "adc",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= a3d_connect,
+	.disconnect	= a3d_disconnect,
 };
 
-int __init a3d_init(void)
+static int __init a3d_init(void)
 {
-	gameport_register_device(&a3d_dev);
+	gameport_register_driver(&a3d_drv);
 	return 0;
 }
 
-void __exit a3d_exit(void)
+static void __exit a3d_exit(void)
 {
-	gameport_unregister_device(&a3d_dev);
+	gameport_unregister_driver(&a3d_drv);
 }
 
 module_init(a3d_init);
diff -Nru a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
--- a/drivers/input/joystick/adi.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/adi.c	2005-03-07 15:26:30 -08:00
@@ -1,7 +1,5 @@
 /*
- * $Id: adi.c,v 1.23 2002/01/22 20:26:17 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *  Copyright (c) 1998-2005 Vojtech Pavlik
  */
 
 /*
@@ -37,8 +35,10 @@
 #include <linux/gameport.h>
 #include <linux/init.h>
 
+#define DRIVER_DESC	"Logitech ADI joystick family driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Logitech ADI joystick family driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -47,7 +47,6 @@
 
 #define ADI_MAX_START		200	/* Trigger to packet timeout [200us] */
 #define ADI_MAX_STROBE		40	/* Single bit timeout [40us] */
-#define ADI_REFRESH_TIME	HZ/50	/* How often to poll the joystick [20 ms] */
 #define ADI_INIT_DELAY		10	/* Delay after init packet [10ms] */
 #define ADI_DATA_DELAY		4	/* Delay after data packet [4ms] */
 
@@ -57,7 +56,7 @@
 #define ADI_MIN_ID_LENGTH	66
 #define ADI_MAX_NAME_LENGTH	48
 #define ADI_MAX_CNAME_LENGTH	16
-#define ADI_MAX_PHYS_LENGTH	32
+#define ADI_MAX_PHYS_LENGTH	64
 
 #define ADI_FLAG_HAT		0x04
 #define ADI_FLAG_10BIT		0x08
@@ -127,11 +126,9 @@
 
 struct adi_port {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct adi adi[2];
 	int bad;
 	int reads;
-	int used;
 };
 
 /*
@@ -275,15 +272,15 @@
 }
 
 /*
- * adi_timer() repeatedly polls the Logitech joysticks.
+ * adi_poll() repeatedly polls the Logitech joysticks.
  */
 
-static void adi_timer(unsigned long data)
+static void adi_poll(struct gameport *gameport)
 {
-	struct adi_port *port = (void *) data;
+	struct adi_port *port = gameport_get_drvdata(gameport);
+
 	port->bad -= adi_read(port);
 	port->reads++;
-	mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
 }
 
 /*
@@ -293,8 +290,8 @@
 static int adi_open(struct input_dev *dev)
 {
 	struct adi_port *port = dev->private;
-	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
+
+	gameport_start_polling(port->gameport);
 	return 0;
 }
 
@@ -305,8 +302,8 @@
 static void adi_close(struct input_dev *dev)
 {
 	struct adi_port *port = dev->private;
-	if (!--port->used)
-		del_timer(&port->timer);
+
+	gameport_stop_polling(port->gameport);
 }
 
 /*
@@ -316,13 +313,16 @@
 
 static void adi_init_digital(struct gameport *gameport)
 {
-	int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
+	int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
 	int i;
 
 	for (i = 0; seq[i]; i++) {
 		gameport_trigger(gameport);
 		if (seq[i] > 0) msleep(seq[i]);
-		if (seq[i] < 0) mdelay(-seq[i]);
+		if (seq[i] < 0) {
+			mdelay(-seq[i]);
+			udelay(-seq[i]*14);	/* It looks like mdelay() is off by approx 1.4% */
+		}
 	}
 }
 
@@ -408,9 +408,9 @@
 
 	t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
 
-	sprintf(buf, adi_names[t], adi->id);
-	sprintf(adi->name, "Logitech %s", buf);
-	sprintf(adi->phys, "%s/input%d", port->gameport->phys, half);
+	snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id);
+	snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s", buf);
+	snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half);
 
 	adi->abs = adi_abs[t];
 	adi->key = adi_key[t];
@@ -439,35 +439,23 @@
 {
 	int i, t, x;
 
-	if (!adi->length) return;
+	if (!adi->length)
+		return;
 
 	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) {
 
 		t = adi->abs[i];
 		x = adi->dev.abs[t];
 
-		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
-			if (i < adi->axes10) x = 512; else x = 128;
-		}
-
-		if (i < adi->axes10) {
-			adi->dev.absmax[t] = x * 2 - 64;
-			adi->dev.absmin[t] = 64;
-			adi->dev.absfuzz[t] = 2;
-			adi->dev.absflat[t] = 16;
-			continue;
-		}
+		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE)
+			x = i < adi->axes10 ? 512 : 128;
 
-		if (i < adi->axes10 + adi->axes8) {
-			adi->dev.absmax[t] = x * 2 - 48;
-			adi->dev.absmin[t] = 48;
-			adi->dev.absfuzz[t] = 1;
-			adi->dev.absflat[t] = 16;
-			continue;
-		}
-
-		adi->dev.absmax[t] = 1;
-		adi->dev.absmin[t] = -1;
+		if (i < adi->axes10)
+			input_set_abs_params(&adi->dev, t, 64, x * 2 - 64, 2, 16);
+		else if (i < adi->axes10 + adi->axes8)
+			input_set_abs_params(&adi->dev, t, 48, x * 2 - 48, 1, 16);
+		else
+			input_set_abs_params(&adi->dev, t, -1, 1, 0, 0);
 	}
 }
 
@@ -475,25 +463,23 @@
  * adi_connect() probes for Logitech ADI joysticks.
  */
 
-static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct adi_port *port;
 	int i;
+	int err;
 
-	if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
-		return;
-	memset(port, 0, sizeof(struct adi_port));
-
-	gameport->private = port;
+	if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL)))
+		return -ENOMEM;
 
 	port->gameport = gameport;
-	init_timer(&port->timer);
-	port->timer.data = (long) port;
-	port->timer.function = adi_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+	gameport_set_drvdata(gameport, port);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err) {
 		kfree(port);
-		return;
+		return err;
 	}
 
 	adi_init_digital(gameport);
@@ -510,9 +496,12 @@
 	if (!port->adi[0].length && !port->adi[1].length) {
 		gameport_close(gameport);
 		kfree(port);
-		return;
+		return -ENODEV;
 	}
 
+	gameport_set_poll_handler(gameport, adi_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	msleep(ADI_INIT_DELAY);
 	if (adi_read(port)) {
 		msleep(ADI_DATA_DELAY);
@@ -526,17 +515,20 @@
 			printk(KERN_INFO "input: %s [%s] on %s\n",
 				port->adi[i].name, port->adi[i].cname, gameport->phys);
 		}
+
+	return 0;
 }
 
 static void adi_disconnect(struct gameport *gameport)
 {
 	int i;
+	struct adi_port *port = gameport_get_drvdata(gameport);
 
-	struct adi_port *port = gameport->private;
 	for (i = 0; i < 2; i++)
 		if (port->adi[i].length > 0)
 			input_unregister_device(&port->adi[i].dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(port);
 }
 
@@ -544,20 +536,24 @@
  * The gameport device structure.
  */
 
-static struct gameport_dev adi_dev = {
-	.connect =	adi_connect,
-	.disconnect =	adi_disconnect,
+static struct gameport_driver adi_drv = {
+	.driver		= {
+		.name	= "adi",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= adi_connect,
+	.disconnect	= adi_disconnect,
 };
 
-int __init adi_init(void)
+static int __init adi_init(void)
 {
-	gameport_register_device(&adi_dev);
+	gameport_register_driver(&adi_drv);
 	return 0;
 }
 
-void __exit adi_exit(void)
+static void __exit adi_exit(void)
 {
-	gameport_unregister_device(&adi_dev);
+	gameport_unregister_driver(&adi_drv);
 }
 
 module_init(adi_init);
diff -Nru a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
--- a/drivers/input/joystick/analog.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/analog.c	2005-03-07 15:26:30 -08:00
@@ -40,8 +40,10 @@
 #include <linux/gameport.h>
 #include <asm/timex.h>
 
+#define DRIVER_DESC	"Analog joystick and gamepad driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Analog joystick and gamepad driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -88,7 +90,6 @@
 
 #define ANALOG_MAX_TIME		3	/* 3 ms */
 #define ANALOG_LOOP_TIME	2000	/* 2 * loop */
-#define ANALOG_REFRESH_TIME	HZ/100	/* 10 ms */
 #define ANALOG_SAITEK_DELAY	200	/* 200 us */
 #define ANALOG_SAITEK_TIME	2000	/* 2000 us */
 #define ANALOG_AXIS_TIME	2	/* 2 * refresh */
@@ -119,7 +120,6 @@
 
 struct analog_port {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct analog analog[2];
 	unsigned char mask;
 	char saitek;
@@ -132,7 +132,6 @@
 	int axes[4];
 	int buttons;
 	int initial[4];
-	int used;
 	int axtime;
 };
 
@@ -305,12 +304,12 @@
 }
 
 /*
- * analog_timer() repeatedly polls the Analog joysticks.
+ * analog_poll() repeatedly polls the Analog joysticks.
  */
 
-static void analog_timer(unsigned long data)
+static void analog_poll(struct gameport *gameport)
 {
-	struct analog_port *port = (void *) data;
+	struct analog_port *port = gameport_get_drvdata(gameport);
 	int i;
 
 	char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
@@ -336,8 +335,6 @@
 	for (i = 0; i < 2; i++)
 		if (port->analog[i].mask)
 			analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
-
-	mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
 }
 
 /*
@@ -347,8 +344,8 @@
 static int analog_open(struct input_dev *dev)
 {
 	struct analog_port *port = dev->private;
-	if (!port->used++)
-		mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
+
+	gameport_start_polling(port->gameport);
 	return 0;
 }
 
@@ -359,8 +356,8 @@
 static void analog_close(struct input_dev *dev)
 {
 	struct analog_port *port = dev->private;
-	if (!--port->used)
-		del_timer(&port->timer);
+
+	gameport_stop_polling(port->gameport);
 }
 
 /*
@@ -379,7 +376,7 @@
 #ifdef FAKE_TIME
 	analog_faketime += 830;
 #endif
-	udelay(1000);
+	mdelay(1);
 	GET_TIME(t2);
 	GET_TIME(t3);
 	local_irq_restore(flags);
@@ -587,17 +584,15 @@
 	return -!(analog[0].mask || analog[1].mask);
 }
 
-static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
+static int analog_init_port(struct gameport *gameport, struct gameport_driver *drv, struct analog_port *port)
 {
 	int i, t, u, v;
 
-	gameport->private = port;
 	port->gameport = gameport;
-	init_timer(&port->timer);
-	port->timer.data = (long) port;
-	port->timer.function = analog_timer;
 
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+	gameport_set_drvdata(gameport, port);
+
+	if (!gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) {
 
 		analog_calibrate_timer(port);
 
@@ -608,7 +603,8 @@
 		port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
 
 		for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
-			if (!analog_cooked_read(port)) break;
+			if (!analog_cooked_read(port))
+				break;
 			msleep(ANALOG_MAX_TIME);
 		}
 
@@ -617,11 +613,13 @@
 		msleep(ANALOG_MAX_TIME);
 		t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
 		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
+		while ((gameport_read(port->gameport) & port->mask) && (u < t))
+			u++;
 		udelay(ANALOG_SAITEK_DELAY);
 		t = gameport_time(gameport, ANALOG_SAITEK_TIME);
 		gameport_trigger(gameport);
-		while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
+		while ((gameport_read(port->gameport) & port->mask) && (v < t))
+			v++;
 
 		if (v < (u >> 1)) { /* FIXME - more than one port */
 			analog_options[0] |= /* FIXME - more than one port */
@@ -632,59 +630,66 @@
 		gameport_close(gameport);
 	}
 
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+	if (!gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) {
 
 		for (i = 0; i < ANALOG_INIT_RETRIES; i++)
 			if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
 				break;
 		for (i = 0; i < 4; i++)
-			if (port->axes[i] != -1) port->mask |= 1 << i;
+			if (port->axes[i] != -1)
+				port->mask |= 1 << i;
 
 		port->fuzz = gameport->fuzz;
 		port->cooked = 1;
 		return 0;
 	}
 
-	if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
-		return 0;
-
-	return -1;
+	return gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
 }
 
-static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int analog_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct analog_port *port;
 	int i;
+	int err;
 
-	if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
-		return;
-	memset(port, 0, sizeof(struct analog_port));
+	if (!(port = kcalloc(1, sizeof(struct analog_port), GFP_KERNEL)))
+		return - ENOMEM;
 
-	if (analog_init_port(gameport, dev, port)) {
+	err = analog_init_port(gameport, drv, port);
+	if (err) {
 		kfree(port);
-		return;
+		return err;
 	}
 
-	if (analog_init_masks(port)) {
+	err = analog_init_masks(port);
+	if (err) {
 		gameport_close(gameport);
+		gameport_set_drvdata(gameport, NULL);
 		kfree(port);
-		return;
+		return err;
 	}
 
+	gameport_set_poll_handler(gameport, analog_poll);
+	gameport_set_poll_interval(gameport, 10);
+
 	for (i = 0; i < 2; i++)
 		if (port->analog[i].mask)
 			analog_init_device(port, port->analog + i, i);
+
+	return 0;
 }
 
 static void analog_disconnect(struct gameport *gameport)
 {
 	int i;
+	struct analog_port *port = gameport_get_drvdata(gameport);
 
-	struct analog_port *port = gameport->private;
 	for (i = 0; i < 2; i++)
 		if (port->analog[i].mask)
 			input_unregister_device(&port->analog[i].dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n",
 		port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
 		port->gameport->phys);
@@ -696,7 +701,7 @@
 	int value;
 };
 
-struct analog_types analog_types[] = {
+static struct analog_types analog_types[] = {
 	{ "none",	0x00000000 },
 	{ "auto",	0x000000ff },
 	{ "2btn",	0x0000003f },
@@ -741,21 +746,26 @@
  * The gameport device structure.
  */
 
-static struct gameport_dev analog_dev = {
-	.connect =	analog_connect,
-	.disconnect =	analog_disconnect,
+static struct gameport_driver analog_drv = {
+	.driver		= {
+		.name	= "analog",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= analog_connect,
+	.disconnect	= analog_disconnect,
 };
 
-int __init analog_init(void)
+static int __init analog_init(void)
 {
 	analog_parse_options();
-	gameport_register_device(&analog_dev);
+	gameport_register_driver(&analog_drv);
+
 	return 0;
 }
 
-void __exit analog_exit(void)
+static void __exit analog_exit(void)
 {
-	gameport_unregister_device(&analog_dev);
+	gameport_unregister_driver(&analog_drv);
 }
 
 module_init(analog_init);
diff -Nru a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
--- a/drivers/input/joystick/cobra.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/cobra.c	2005-03-07 15:26:30 -08:00
@@ -35,12 +35,13 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"Creative Labs Blaster GamePad Cobra driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Creative Labs Blaster GamePad Cobra driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define COBRA_MAX_STROBE	45	/* 45 us max wait for first strobe */
-#define COBRA_REFRESH_TIME	HZ/50	/* 20 ms between reads */
 #define COBRA_LENGTH		36
 
 static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
@@ -49,9 +50,7 @@
 
 struct cobra {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[2];
-	int used;
 	int reads;
 	int bads;
 	unsigned char exists;
@@ -112,18 +111,19 @@
 	return ret;
 }
 
-static void cobra_timer(unsigned long private)
+static void cobra_poll(struct gameport *gameport)
 {
-	struct cobra *cobra = (void *) private;
+	struct cobra *cobra = gameport_get_drvdata(gameport);
 	struct input_dev *dev;
 	unsigned int data[2];
 	int i, j, r;
 
 	cobra->reads++;
 
-	if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
+	if ((r = cobra_read_packet(gameport, data)) != cobra->exists) {
 		cobra->bads++;
-	else
+		return;
+	}
 
 	for (i = 0; i < 2; i++)
 		if (cobra->exists & r & (1 << i)) {
@@ -139,43 +139,39 @@
 			input_sync(dev);
 
 		}
-
-	mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
 }
 
 static int cobra_open(struct input_dev *dev)
 {
 	struct cobra *cobra = dev->private;
-	if (!cobra->used++)
-		mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
+
+	gameport_start_polling(cobra->gameport);
 	return 0;
 }
 
 static void cobra_close(struct input_dev *dev)
 {
 	struct cobra *cobra = dev->private;
-	if (!--cobra->used)
-		del_timer(&cobra->timer);
+
+	gameport_stop_polling(cobra->gameport);
 }
 
-static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct cobra *cobra;
 	unsigned int data[2];
 	int i, j;
+	int err;
 
-	if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
-		return;
-	memset(cobra, 0, sizeof(struct cobra));
-
-	gameport->private = cobra;
+	if (!(cobra = kcalloc(1, sizeof(struct cobra), GFP_KERNEL)))
+		return -ENOMEM;
 
 	cobra->gameport = gameport;
-	init_timer(&cobra->timer);
-	cobra->timer.data = (long) cobra;
-	cobra->timer.function = cobra_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, cobra);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	cobra->exists = cobra_read_packet(gameport, data);
@@ -187,8 +183,13 @@
 			cobra->exists &= ~(1 << i);
 		}
 
-	if (!cobra->exists)
+	if (!cobra->exists) {
+		err = -ENODEV;
 		goto fail2;
+	}
+
+	gameport_set_poll_handler(gameport, cobra_poll);
+	gameport_set_poll_interval(gameport, 20);
 
 	for (i = 0; i < 2; i++)
 		if ((cobra->exists >> i) & 1) {
@@ -207,49 +208,56 @@
 			cobra->dev[i].id.version = 0x0100;
 
 			cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-			cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+			input_set_abs_params(&cobra->dev[i], ABS_X, -1, 1, 0, 0);
+			input_set_abs_params(&cobra->dev[i], ABS_Y, -1, 1, 0, 0);
 
 			for (j = 0; cobra_btn[j]; j++)
 				set_bit(cobra_btn[j], cobra->dev[i].keybit);
 
-			cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
-			cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
-
-			input_register_device(cobra->dev + i);
+			input_register_device(&cobra->dev[i]);
 			printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys);
 		}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(cobra);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(cobra);
+	return err;
 }
 
 static void cobra_disconnect(struct gameport *gameport)
 {
+	struct cobra *cobra = gameport_get_drvdata(gameport);
 	int i;
 
-	struct cobra *cobra = gameport->private;
 	for (i = 0; i < 2; i++)
 		if ((cobra->exists >> i) & 1)
 			input_unregister_device(cobra->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(cobra);
 }
 
-static struct gameport_dev cobra_dev = {
-	.connect =	cobra_connect,
-	.disconnect =	cobra_disconnect,
+static struct gameport_driver cobra_drv = {
+	.driver		= {
+		.name	= "cobra",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= cobra_connect,
+	.disconnect	= cobra_disconnect,
 };
 
-int __init cobra_init(void)
+static int __init cobra_init(void)
 {
-	gameport_register_device(&cobra_dev);
+	gameport_register_driver(&cobra_drv);
 	return 0;
 }
 
-void __exit cobra_exit(void)
+static void __exit cobra_exit(void)
 {
-	gameport_unregister_device(&cobra_dev);
+	gameport_unregister_driver(&cobra_drv);
 }
 
 module_init(cobra_init);
diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
--- a/drivers/input/joystick/db9.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/db9.c	2005-03-07 15:26:30 -08:00
@@ -619,7 +619,7 @@
 	return db9;
 }
 
-int __init db9_init(void)
+static int __init db9_init(void)
 {
 	db9_base[0] = db9_probe(db9, db9_nargs);
 	db9_base[1] = db9_probe(db9_2, db9_nargs_2);
@@ -631,7 +631,7 @@
 	return -ENODEV;
 }
 
-void __exit db9_exit(void)
+static void __exit db9_exit(void)
 {
 	int i, j;
 
diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
--- a/drivers/input/joystick/gamecon.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/gamecon.c	2005-03-07 15:26:30 -08:00
@@ -227,7 +227,8 @@
  */
 
 #define GC_PSX_DELAY	25		/* 25 usec */
-#define GC_PSX_LENGTH	8		/* talk to the controller in bytes */
+#define GC_PSX_LENGTH	8		/* talk to the controller in bits */
+#define GC_PSX_BYTES	6		/* the maximum number of bytes to read off the controller */
 
 #define GC_PSX_MOUSE	1		/* Mouse */
 #define GC_PSX_NEGCON	2		/* NegCon */
@@ -241,7 +242,7 @@
 #define GC_PSX_SELECT	0x02		/* Pin 3 */
 
 #define GC_PSX_ID(x)	((x) >> 4)	/* High nibble is device type */
-#define GC_PSX_LEN(x)	((x) & 0xf)	/* Low nibble is length in words */
+#define GC_PSX_LEN(x)	(((x) & 0xf) << 1)	/* Low nibble is length in bytes/2 */
 
 static int gc_psx_delay = GC_PSX_DELAY;
 module_param_named(psx_delay, gc_psx_delay, uint, 0);
@@ -259,13 +260,13 @@
  * the psx pad.
  */
 
-static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH])
+static void gc_psx_command(struct gc *gc, int b, unsigned char data[5])
 {
 	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 < GC_PSX_LENGTH; i++, b >>= 1) {
 		cmd = (b & 1) ? GC_PSX_COMMAND : 0;
 		parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
 		udelay(gc_psx_delay);
@@ -282,7 +283,7 @@
  * device identifier code.
  */
 
-static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5])
+static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_BYTES], unsigned char id[5])
 {
 	int i, j, max_len = 0;
 	unsigned long flags;
@@ -300,10 +301,12 @@
 	gc_psx_command(gc, 0, data2);							/* Dump status */
 
 	for (i =0; i < 5; i++)								/* Find the longest pad */
-		if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) && (GC_PSX_LEN(id[i]) > max_len))
+		if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR]))
+			&& (GC_PSX_LEN(id[i]) > max_len)
+			&& (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES))
 			max_len = GC_PSX_LEN(id[i]);
 
-	for (i = 0; i < max_len * 2; i++) {						/* Read in all the data */
+	for (i = 0; i < max_len; i++) {						/* Read in all the data */
 		gc_psx_command(gc, 0, data2);
 		for (j = 0; j < 5; j++)
 			data[j][i] = data2[j];
@@ -328,7 +331,7 @@
 	struct gc *gc = (void *) private;
 	struct input_dev *dev = gc->dev;
 	unsigned char data[GC_MAX_LENGTH];
-	unsigned char data_psx[5][GC_PSX_LENGTH];
+	unsigned char data_psx[5][GC_PSX_BYTES];
 	int i, j, s;
 
 /*
@@ -665,7 +668,7 @@
 	return gc;
 }
 
-int __init gc_init(void)
+static int __init gc_init(void)
 {
 	gc_base[0] = gc_probe(gc, gc_nargs);
 	gc_base[1] = gc_probe(gc_2, gc_nargs_2);
@@ -677,7 +680,7 @@
 	return -ENODEV;
 }
 
-void __exit gc_exit(void)
+static void __exit gc_exit(void)
 {
 	int i, j;
 
diff -Nru a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
--- a/drivers/input/joystick/gf2k.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/gf2k.c	2005-03-07 15:26:30 -08:00
@@ -36,15 +36,16 @@
 #include <linux/input.h>
 #include <linux/gameport.h>
 
+#define DRIVER_DESC	"Genius Flight 2000 joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Genius Flight 2000 joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define GF2K_START		400	/* The time we wait for the first bit [400 us] */
 #define GF2K_STROBE		40	/* The time we wait for the first bit [40 us] */
 #define GF2K_TIMEOUT		4	/* Wait for everything to settle [4 ms] */
 #define GF2K_LENGTH		80	/* Max number of triplets in a packet */
-#define GF2K_REFRESH		HZ/50	/* Time between joystick polls [20 ms] */
 
 /*
  * Genius joystick ids ...
@@ -80,11 +81,9 @@
 
 struct gf2k {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev;
 	int reads;
 	int bads;
-	int used;
 	unsigned char id;
 	unsigned char length;
 	char phys[32];
@@ -202,60 +201,56 @@
 }
 
 /*
- * gf2k_timer() reads and analyzes Genius joystick data.
+ * gf2k_poll() reads and analyzes Genius joystick data.
  */
 
-static void gf2k_timer(unsigned long private)
+static void gf2k_poll(struct gameport *gameport)
 {
-	struct gf2k *gf2k = (void *) private;
+	struct gf2k *gf2k = gameport_get_drvdata(gameport);
 	unsigned char data[GF2K_LENGTH];
 
 	gf2k->reads++;
 
-	if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
+	if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id])
 		gf2k->bads++;
-	} else gf2k_read(gf2k, data);
-
-	mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+	else
+		gf2k_read(gf2k, data);
 }
 
 static int gf2k_open(struct input_dev *dev)
 {
 	struct gf2k *gf2k = dev->private;
-	if (!gf2k->used++)
-		mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+
+	gameport_start_polling(gf2k->gameport);
 	return 0;
 }
 
 static void gf2k_close(struct input_dev *dev)
 {
 	struct gf2k *gf2k = dev->private;
-	if (!--gf2k->used)
-		del_timer(&gf2k->timer);
+
+	gameport_stop_polling(gf2k->gameport);
 }
 
 /*
  * gf2k_connect() probes for Genius id joysticks.
  */
 
-static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct gf2k *gf2k;
 	unsigned char data[GF2K_LENGTH];
-	int i;
-
-	if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
-		return;
-	memset(gf2k, 0, sizeof(struct gf2k));
+	int i, err;
 
-	gameport->private = gf2k;
+	if (!(gf2k = kcalloc(1, sizeof(struct gf2k), GFP_KERNEL)))
+		return -ENOMEM;
 
 	gf2k->gameport = gameport;
-	init_timer(&gf2k->timer);
-	gf2k->timer.data = (long) gf2k;
-	gf2k->timer.function = gf2k_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, gf2k);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	gf2k_trigger_seq(gameport, gf2k_seq_reset);
@@ -266,16 +261,22 @@
 
 	msleep(GF2K_TIMEOUT);
 
-	if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
+	if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
-	if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
+	if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5))) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
 #ifdef RESET_WORKS
 	if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
-	    (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
+	    (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) {
+		err = -ENODEV;
 		goto fail2;
+	}
 #else
 	gf2k->id = 6;
 #endif
@@ -283,9 +284,13 @@
 	if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
 		printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n",
 			gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, gf2k_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(gf2k->phys, "%s/input0", gameport->phys);
 
 	gf2k->length = gf2k_lens[gf2k->id];
@@ -333,33 +338,42 @@
 	input_register_device(&gf2k->dev);
 	printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(gf2k);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(gf2k);
+	return err;
 }
 
 static void gf2k_disconnect(struct gameport *gameport)
 {
-	struct gf2k *gf2k = gameport->private;
+	struct gf2k *gf2k = gameport_get_drvdata(gameport);
+
 	input_unregister_device(&gf2k->dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(gf2k);
 }
 
-static struct gameport_dev gf2k_dev = {
-	.connect =	gf2k_connect,
-	.disconnect =	gf2k_disconnect,
+static struct gameport_driver gf2k_drv = {
+	.driver		= {
+		.name	= "gf2k",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= gf2k_connect,
+	.disconnect	= gf2k_disconnect,
 };
 
-int __init gf2k_init(void)
+static int __init gf2k_init(void)
 {
-	gameport_register_device(&gf2k_dev);
+	gameport_register_driver(&gf2k_drv);
 	return 0;
 }
 
-void __exit gf2k_exit(void)
+static void __exit gf2k_exit(void)
 {
-	gameport_unregister_device(&gf2k_dev);
+	gameport_unregister_driver(&gf2k_drv);
 }
 
 module_init(gf2k_init);
diff -Nru a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
--- a/drivers/input/joystick/grip.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/grip.c	2005-03-07 15:26:30 -08:00
@@ -35,8 +35,10 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"Gravis GrIP protocol joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Gravis GrIP protocol joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define GRIP_MODE_GPP		1
@@ -51,14 +53,10 @@
 #define GRIP_MAX_CHUNKS_XT	10
 #define GRIP_MAX_BITS_XT	30
 
-#define GRIP_REFRESH_TIME	HZ/50	/* 20 ms */
-
 struct grip {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[2];
 	unsigned char mode[2];
-	int used;
 	int reads;
 	int bads;
 	char phys[2][32];
@@ -183,9 +181,9 @@
  * grip_timer() repeatedly polls the joysticks and generates events.
  */
 
-static void grip_timer(unsigned long private)
+static void grip_poll(struct gameport *gameport)
 {
-	struct grip *grip = (void*) private;
+	struct grip *grip = gameport_get_drvdata(gameport);
 	unsigned int data[GRIP_LENGTH_XT];
 	struct input_dev *dev;
 	int i, j;
@@ -279,43 +277,39 @@
 
 		input_sync(dev);
 	}
-
-	mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
 }
 
 static int grip_open(struct input_dev *dev)
 {
 	struct grip *grip = dev->private;
-	if (!grip->used++)
-		mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+
+	gameport_start_polling(grip->gameport);
 	return 0;
 }
 
 static void grip_close(struct input_dev *dev)
 {
 	struct grip *grip = dev->private;
-	if (!--grip->used)
-		del_timer(&grip->timer);
+
+	gameport_stop_polling(grip->gameport);
 }
 
-static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct grip *grip;
 	unsigned int data[GRIP_LENGTH_XT];
 	int i, j, t;
+	int err;
 
-	if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
-		return;
-	memset(grip, 0, sizeof(struct grip));
-
-	gameport->private = grip;
+	if (!(grip = kcalloc(1, sizeof(struct grip), GFP_KERNEL)))
+		return -ENOMEM;
 
 	grip->gameport = gameport;
-	init_timer(&grip->timer);
-	grip->timer.data = (long) grip;
-	grip->timer.function = grip_timer;
 
-	 if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, grip);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	for (i = 0; i < 2; i++) {
@@ -337,8 +331,13 @@
 		}
 	}
 
-	if (!grip->mode[0] && !grip->mode[1])
+	if (!grip->mode[0] && !grip->mode[1]) {
+		err = -ENODEV;
 		goto fail2;
+	}
+
+	gameport_set_poll_handler(gameport, grip_poll);
+	gameport_set_poll_interval(gameport, 20);
 
 	for (i = 0; i < 2; i++)
 		if (grip->mode[i]) {
@@ -361,68 +360,62 @@
 
 			for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
 
-				set_bit(t, grip->dev[i].absbit);
-
-				if (j < grip_cen[grip->mode[i]]) {
-					grip->dev[i].absmin[t] = 14;
-					grip->dev[i].absmax[t] = 52;
-					grip->dev[i].absfuzz[t] = 1;
-					grip->dev[i].absflat[t] = 2;
-					continue;
-				}
-
-				if (j < grip_anx[grip->mode[i]]) {
-					grip->dev[i].absmin[t] = 3;
-					grip->dev[i].absmax[t] = 57;
-					grip->dev[i].absfuzz[t] = 1;
-					continue;
-				}
-
-				grip->dev[i].absmin[t] = -1;
-				grip->dev[i].absmax[t] = 1;
+				if (j < grip_cen[grip->mode[i]])
+					input_set_abs_params(&grip->dev[i], t, 14, 52, 1, 2);
+				else if (j < grip_anx[grip->mode[i]])
+					input_set_abs_params(&grip->dev[i], t, 3, 57, 1, 0);
+				else
+					input_set_abs_params(&grip->dev[i], t, -1, 1, 0, 0);
 			}
 
 			for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
 				if (t > 0)
 					set_bit(t, grip->dev[i].keybit);
 
-			input_register_device(grip->dev + i);
-
 			printk(KERN_INFO "input: %s on %s\n",
 				grip_name[grip->mode[i]], gameport->phys);
+			input_register_device(grip->dev + i);
 		}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(grip);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(grip);
+	return err;
 }
 
 static void grip_disconnect(struct gameport *gameport)
 {
+	struct grip *grip = gameport_get_drvdata(gameport);
 	int i;
 
-	struct grip *grip = gameport->private;
 	for (i = 0; i < 2; i++)
 		if (grip->mode[i])
 			input_unregister_device(grip->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(grip);
 }
 
-static struct gameport_dev grip_dev = {
-	.connect =	grip_connect,
-	.disconnect =	grip_disconnect,
+static struct gameport_driver grip_drv = {
+	.driver		= {
+		.name	= "grip",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= grip_connect,
+	.disconnect	= grip_disconnect,
 };
 
-int __init grip_init(void)
+static int __init grip_init(void)
 {
-	gameport_register_device(&grip_dev);
+	gameport_register_driver(&grip_drv);
 	return 0;
 }
 
-void __exit grip_exit(void)
+static void __exit grip_exit(void)
 {
-	gameport_unregister_device(&grip_dev);
+	gameport_unregister_driver(&grip_drv);
 }
 
 module_init(grip_init);
diff -Nru a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
--- a/drivers/input/joystick/grip_mp.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/grip_mp.c	2005-03-07 15:26:30 -08:00
@@ -20,8 +20,10 @@
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 
+#define DRIVER_DESC	"Gravis Grip Multiport driver"
+
 MODULE_AUTHOR("Brian Bonnlander");
-MODULE_DESCRIPTION("Gravis Grip Multiport driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #ifdef GRIP_DEBUG
@@ -36,11 +38,9 @@
 
 struct grip_mp {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[4];
 	int mode[4];
 	int registered[4];
-	int used;
 	int reads;
 	int bads;
 
@@ -79,7 +79,6 @@
  */
 
 #define GRIP_INIT_DELAY         2000          /*  2 ms */
-#define GRIP_REFRESH_TIME       HZ/50	      /* 20 ms */
 
 #define GRIP_MODE_NONE		0
 #define GRIP_MODE_RESET         1
@@ -477,9 +476,9 @@
 	}
 
 	if (dig_mode)
-		dbg("multiport_init(): digital mode achieved.\n");
+		dbg("multiport_init(): digital mode activated.\n");
 	else {
-		dbg("multiport_init(): unable to achieve digital mode.\n");
+		dbg("multiport_init(): unable to activate digital mode.\n");
 		return 0;
 	}
 
@@ -524,8 +523,9 @@
  * Get the multiport state.
  */
 
-static void get_and_report_mp_state(struct grip_mp *grip)
+static void grip_poll(struct gameport *gameport)
 {
+	struct grip_mp *grip = gameport_get_drvdata(gameport);
 	int i, npkts, flags;
 
 	for (npkts = 0; npkts < 4; npkts++) {
@@ -551,8 +551,8 @@
 static int grip_open(struct input_dev *dev)
 {
 	struct grip_mp *grip = dev->private;
-	if (!grip->used++)
-		mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+
+	gameport_start_polling(grip->gameport);
 	return 0;
 }
 
@@ -563,8 +563,8 @@
 static void grip_close(struct input_dev *dev)
 {
 	struct grip_mp *grip = dev->private;
-	if (!--grip->used)
-		del_timer(&grip->timer);
+
+	gameport_start_polling(grip->gameport);
 }
 
 /*
@@ -585,11 +585,8 @@
 	grip->dev[slot].id.version = 0x0100;
 	grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-	for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) {
-		set_bit(t, grip->dev[slot].absbit);
-		grip->dev[slot].absmin[t] = -1;
-		grip->dev[slot].absmax[t] = 1;
-	}
+	for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++)
+		input_set_abs_params(&grip->dev[slot], t, -1, 1, 0, 0);
 
 	for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++)
 		if (t > 0)
@@ -605,69 +602,75 @@
 	       grip_name[grip->mode[slot]], slot);
 }
 
-/*
- * Repeatedly polls the multiport and generates events.
- */
-
-static void grip_timer(unsigned long private)
-{
-	struct grip_mp *grip = (void*) private;
-	get_and_report_mp_state(grip);
-	mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
-}
-
-static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct grip_mp *grip;
+	int err;
+
+	if (!(grip = kcalloc(1, sizeof(struct grip_mp), GFP_KERNEL)))
+		return -ENOMEM;
 
-	if (!(grip = kmalloc(sizeof(struct grip_mp), GFP_KERNEL)))
-		return;
-	memset(grip, 0, sizeof(struct grip_mp));
-	gameport->private = grip;
 	grip->gameport = gameport;
-	init_timer(&grip->timer);
-	grip->timer.data = (long) grip;
-	grip->timer.function = grip_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, grip);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
-	if (!multiport_init(grip))
+
+	gameport_set_poll_handler(gameport, grip_poll);
+	gameport_set_poll_interval(gameport, 20);
+
+	if (!multiport_init(grip)) {
+		err = -ENODEV;
 		goto fail2;
-	if (!grip->mode[0] && !grip->mode[1] &&   /* nothing plugged in */
-	    !grip->mode[2] && !grip->mode[3])
+	}
+
+	if (!grip->mode[0] && !grip->mode[1] && !grip->mode[2] && !grip->mode[3]) {
+		/* nothing plugged in */
+		err = -ENODEV;
 		goto fail2;
-	return;
+	}
+
+	return 0;
 
 fail2:	gameport_close(gameport);
-fail1:	kfree(grip);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(grip);
+	return err;
 }
 
 static void grip_disconnect(struct gameport *gameport)
 {
+	struct grip_mp *grip = gameport_get_drvdata(gameport);
 	int i;
 
-	struct grip_mp *grip = gameport->private;
 	for (i = 0; i < 4; i++)
 		if (grip->registered[i])
 			input_unregister_device(grip->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(grip);
 }
 
-static struct gameport_dev grip_dev = {
+static struct gameport_driver grip_drv = {
+	.driver		= {
+		.name	= "grip_mp",
+	},
+	.description	= DRIVER_DESC,
 	.connect	= grip_connect,
 	.disconnect	= grip_disconnect,
 };
 
-static int grip_init(void)
+static int __init grip_init(void)
 {
-	gameport_register_device(&grip_dev);
+	gameport_register_driver(&grip_drv);
 	return 0;
 }
 
-static void grip_exit(void)
+static void __exit grip_exit(void)
 {
-	gameport_unregister_device(&grip_dev);
+	gameport_unregister_driver(&grip_drv);
 }
 
 module_init(grip_init);
diff -Nru a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
--- a/drivers/input/joystick/guillemot.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/guillemot.c	2005-03-07 15:26:30 -08:00
@@ -36,14 +36,15 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"Guillemot Digital joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Guillemot Digital joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define GUILLEMOT_MAX_START	600	/* 600 us */
 #define GUILLEMOT_MAX_STROBE	60	/* 60 us */
 #define GUILLEMOT_MAX_LENGTH	17	/* 17 bytes */
-#define GUILLEMOT_REFRESH_TIME	HZ/50	/* 20 ms */
 
 static short guillemot_abs_pad[] =
 	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
@@ -67,8 +68,6 @@
 struct guillemot {
 	struct gameport *gameport;
 	struct input_dev dev;
-	struct timer_list timer;
-	int used;
 	int bads;
 	int reads;
 	struct guillemot_type *type;
@@ -118,12 +117,12 @@
 }
 
 /*
- * guillemot_timer() reads and analyzes Guillemot joystick data.
+ * guillemot_poll() reads and analyzes Guillemot joystick data.
  */
 
-static void guillemot_timer(unsigned long private)
+static void guillemot_poll(struct gameport *gameport)
 {
-	struct guillemot *guillemot = (struct guillemot *) private;
+	struct guillemot *guillemot = gameport_get_drvdata(gameport);
 	struct input_dev *dev = &guillemot->dev;
 	u8 data[GUILLEMOT_MAX_LENGTH];
 	int i;
@@ -148,8 +147,6 @@
 	}
 
 	input_sync(dev);
-
-	mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
 }
 
 /*
@@ -159,8 +156,8 @@
 static int guillemot_open(struct input_dev *dev)
 {
 	struct guillemot *guillemot = dev->private;
-	if (!guillemot->used++)
-		mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
+
+	gameport_start_polling(guillemot->gameport);
 	return 0;
 }
 
@@ -171,38 +168,38 @@
 static void guillemot_close(struct input_dev *dev)
 {
 	struct guillemot *guillemot = dev->private;
-	if (!--guillemot->used)
-		del_timer(&guillemot->timer);
+
+	gameport_stop_polling(guillemot->gameport);
 }
 
 /*
  * guillemot_connect() probes for Guillemot joysticks.
  */
 
-static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct guillemot *guillemot;
 	u8 data[GUILLEMOT_MAX_LENGTH];
 	int i, t;
+	int err;
 
-	if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL)))
-		return;
-	memset(guillemot, 0, sizeof(struct guillemot));
-
-	gameport->private = guillemot;
+	if (!(guillemot = kcalloc(1, sizeof(struct guillemot), GFP_KERNEL)))
+		return -ENOMEM;
 
 	guillemot->gameport = gameport;
-	init_timer(&guillemot->timer);
-	guillemot->timer.data = (long) guillemot;
-	guillemot->timer.function = guillemot_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, guillemot);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	i = guillemot_read_packet(gameport, data);
 
-	if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa)
+	if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) {
+		err = -ENODEV;
 		goto fail2;
+	}
 
 	for (i = 0; guillemot_type[i].name; i++)
 		if (guillemot_type[i].id == data[11])
@@ -211,9 +208,13 @@
 	if (!guillemot_type[i].name) {
 		printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
 			gameport->phys, data[12], data[13], data[11], data[14], data[15]);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, guillemot_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(guillemot->phys, "%s/input0", gameport->phys);
 
 	guillemot->type = guillemot_type + i;
@@ -231,19 +232,13 @@
 
 	guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-	for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) {
-		set_bit(t, guillemot->dev.absbit);
-		guillemot->dev.absmin[t] = 0;
-		guillemot->dev.absmax[t] = 255;
-	}
+	for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++)
+		input_set_abs_params(&guillemot->dev, t, 0, 255, 0, 0);
 
-	if (guillemot->type->hat)
-		for (i = 0; i < 2; i++) {
-			t = ABS_HAT0X + i;
-			set_bit(t, guillemot->dev.absbit);
-			guillemot->dev.absmin[t] = -1;
-			guillemot->dev.absmax[t] = 1;
-		}
+	if (guillemot->type->hat) {
+		input_set_abs_params(&guillemot->dev, ABS_HAT0X, -1, 1, 0, 0);
+		input_set_abs_params(&guillemot->dev, ABS_HAT0Y, -1, 1, 0, 0);
+	}
 
 	for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
 		set_bit(t, guillemot->dev.keybit);
@@ -252,34 +247,42 @@
 	printk(KERN_INFO "input: %s ver %d.%02d on %s\n",
 		guillemot->type->name, data[14], data[15], gameport->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:  kfree(guillemot);
+fail1:  gameport_set_drvdata(gameport, NULL);
+	kfree(guillemot);
+	return err;
 }
 
 static void guillemot_disconnect(struct gameport *gameport)
 {
-	struct guillemot *guillemot = gameport->private;
+	struct guillemot *guillemot = gameport_get_drvdata(gameport);
+
 	printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
 	input_unregister_device(&guillemot->dev);
 	gameport_close(gameport);
 	kfree(guillemot);
 }
 
-static struct gameport_dev guillemot_dev = {
-	.connect =	guillemot_connect,
-	.disconnect =	guillemot_disconnect,
+static struct gameport_driver guillemot_drv = {
+	.driver		= {
+		.name	= "guillemot",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= guillemot_connect,
+	.disconnect	= guillemot_disconnect,
 };
 
-int __init guillemot_init(void)
+static int __init guillemot_init(void)
 {
-	gameport_register_device(&guillemot_dev);
+	gameport_register_driver(&guillemot_drv);
 	return 0;
 }
 
-void __exit guillemot_exit(void)
+static void __exit guillemot_exit(void)
 {
-	gameport_unregister_device(&guillemot_dev);
+	gameport_unregister_driver(&guillemot_drv);
 }
 
 module_init(guillemot_init);
diff -Nru a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
--- a/drivers/input/joystick/iforce/iforce-serio.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/iforce/iforce-serio.c	2005-03-07 15:26:30 -08:00
@@ -75,13 +75,15 @@
 
 static void iforce_serio_write_wakeup(struct serio *serio)
 {
-	iforce_serial_xmit((struct iforce *)serio->private);
+	struct iforce *iforce = serio_get_drvdata(serio);
+
+	iforce_serial_xmit(iforce);
 }
 
 static irqreturn_t iforce_serio_irq(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct iforce* iforce = serio->private;
+	struct iforce *iforce = serio_get_drvdata(serio);
 
 	if (!iforce->pkt) {
 		if (data == 0x2b)
@@ -124,45 +126,66 @@
 	return IRQ_HANDLED;
 }
 
-static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
+static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct iforce *iforce;
-	if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
-		return;
+	int err;
+
+	if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL)))
+		return -ENOMEM;
 
-	if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
 	memset(iforce, 0, sizeof(struct iforce));
 
 	iforce->bus = IFORCE_232;
 	iforce->serio = serio;
-	serio->private = iforce;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, iforce);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(iforce);
-		return;
+		return err;
 	}
 
 	if (iforce_init_device(iforce)) {
 		serio_close(serio);
+		serio_set_drvdata(serio, NULL);
 		kfree(iforce);
-		return;
+		return -ENODEV;
 	}
+
+	return 0;
 }
 
 static void iforce_serio_disconnect(struct serio *serio)
 {
-	struct iforce* iforce = serio->private;
+	struct iforce *iforce = serio_get_drvdata(serio);
 
 	input_unregister_device(&iforce->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(iforce);
 }
 
+static struct serio_device_id iforce_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_IFORCE,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, iforce_serio_ids);
+
 struct serio_driver iforce_serio_drv = {
 	.driver		= {
 		.name	= "iforce",
 	},
 	.description	= "RS232 I-Force joysticks and wheels driver",
+	.id_table	= iforce_serio_ids,
 	.write_wakeup	= iforce_serio_write_wakeup,
 	.interrupt	= iforce_serio_irq,
 	.connect	= iforce_serio_connect,
diff -Nru a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
--- a/drivers/input/joystick/interact.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/interact.c	2005-03-07 15:26:30 -08:00
@@ -39,14 +39,15 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"InterAct digital joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("InterAct digital joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define INTERACT_MAX_START	400	/* 400 us */
-#define INTERACT_MAX_STROBE	40	/* 40 us */
+#define INTERACT_MAX_START	600	/* 400 us */
+#define INTERACT_MAX_STROBE	60	/* 40 us */
 #define INTERACT_MAX_LENGTH	32	/* 32 bits */
-#define INTERACT_REFRESH_TIME	HZ/50	/* 20 ms */
 
 #define INTERACT_TYPE_HHFX	0	/* HammerHead/FX */
 #define INTERACT_TYPE_PP8D	1	/* ProPad 8 */
@@ -54,8 +55,6 @@
 struct interact {
 	struct gameport *gameport;
 	struct input_dev dev;
-	struct timer_list timer;
-	int used;
 	int bads;
 	int reads;
 	unsigned char type;
@@ -125,12 +124,12 @@
 }
 
 /*
- * interact_timer() reads and analyzes InterAct joystick data.
+ * interact_poll() reads and analyzes InterAct joystick data.
  */
 
-static void interact_timer(unsigned long private)
+static void interact_poll(struct gameport *gameport)
 {
-	struct interact *interact = (struct interact *) private;
+	struct interact *interact = gameport_get_drvdata(gameport);
 	struct input_dev *dev = &interact->dev;
 	u32 data[3];
 	int i;
@@ -177,9 +176,6 @@
 	}
 
 	input_sync(dev);
-
-	mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
-
 }
 
 /*
@@ -189,8 +185,8 @@
 static int interact_open(struct input_dev *dev)
 {
 	struct interact *interact = dev->private;
-	if (!interact->used++)
-		mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
+
+	gameport_start_polling(interact->gameport);
 	return 0;
 }
 
@@ -201,37 +197,36 @@
 static void interact_close(struct input_dev *dev)
 {
 	struct interact *interact = dev->private;
-	if (!--interact->used)
-		del_timer(&interact->timer);
+
+	gameport_stop_polling(interact->gameport);
 }
 
 /*
  * interact_connect() probes for InterAct joysticks.
  */
 
-static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int interact_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct interact *interact;
 	__u32 data[3];
 	int i, t;
+	int err;
 
-	if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
-		return;
-	memset(interact, 0, sizeof(struct interact));
-
-	gameport->private = interact;
+	if (!(interact = kcalloc(1, sizeof(struct interact), GFP_KERNEL)))
+		return -ENOMEM;
 
 	interact->gameport = gameport;
-	init_timer(&interact->timer);
-	interact->timer.data = (long) interact;
-	interact->timer.function = interact_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, interact);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
 
 	if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
+		err = -ENODEV;
 		goto fail2;
 	}
 
@@ -242,9 +237,13 @@
 	if (!interact_type[i].length) {
 		printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n",
 			gameport->phys, i, data[0], data[1], data[2]);
+		err = -ENODEV;
 		goto fail2;
 	}
 
+	gameport_set_poll_handler(gameport, interact_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	sprintf(interact->phys, "%s/input0", gameport->phys);
 
 	interact->type = i;
@@ -281,33 +280,42 @@
 	printk(KERN_INFO "input: %s on %s\n",
 		interact_type[interact->type].name, gameport->phys);
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:  kfree(interact);
+fail1:  gameport_set_drvdata(gameport, NULL);
+	kfree(interact);
+	return err;
 }
 
 static void interact_disconnect(struct gameport *gameport)
 {
-	struct interact *interact = gameport->private;
+	struct interact *interact = gameport_get_drvdata(gameport);
+
 	input_unregister_device(&interact->dev);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(interact);
 }
 
-static struct gameport_dev interact_dev = {
-	.connect =	interact_connect,
-	.disconnect =	interact_disconnect,
+static struct gameport_driver interact_drv = {
+	.driver		= {
+		.name	= "interact",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= interact_connect,
+	.disconnect	= interact_disconnect,
 };
 
-int __init interact_init(void)
+static int __init interact_init(void)
 {
-	gameport_register_device(&interact_dev);
+	gameport_register_driver(&interact_drv);
 	return 0;
 }
 
-void __exit interact_exit(void)
+static void __exit interact_exit(void)
 {
-	gameport_unregister_device(&interact_dev);
+	gameport_unregister_driver(&interact_drv);
 }
 
 module_init(interact_init);
diff -Nru a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
--- a/drivers/input/joystick/joydump.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/joydump.c	2005-03-07 15:26:30 -08:00
@@ -35,8 +35,10 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 
+#define DRIVER_DESC	"Gameport data dumper module"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Gameport data dumper module");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 #define BUF_SIZE 256
@@ -46,38 +48,46 @@
 	unsigned char data;
 };
 
-static void __devinit joydump_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int joydump_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
-	struct joydump buf[BUF_SIZE];
+	struct joydump *buf;	/* all entries */
+	struct joydump *dump, *prev;	/* one entry each */
 	int axes[4], buttons;
 	int i, j, t, timeout;
 	unsigned long flags;
 	unsigned char u;
 
-	printk(KERN_INFO "joydump: ,------------------- START ------------------.\n");
-	printk(KERN_INFO "joydump: | Dumping gameport%s.\n", gameport->phys);
-	printk(KERN_INFO "joydump: | Speed: %4d kHz.                            |\n", gameport->speed);
+	printk(KERN_INFO "joydump: ,------------------ START ----------------.\n");
+	printk(KERN_INFO "joydump: | Dumping: %30s |\n", gameport->phys);
+	printk(KERN_INFO "joydump: | Speed: %28d kHz |\n", gameport->speed);
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+	if (gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) {
 
 		printk(KERN_INFO "joydump: | Raw mode not available - trying cooked.    |\n");
 
-		if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+		if (gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) {
 
-			printk(KERN_INFO "joydump: | Cooked not available either. Failing.      |\n");
-			printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
-			return;
+			printk(KERN_INFO "joydump: | Cooked not available either. Failing.   |\n");
+			printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
+			return -ENODEV;
 		}
 
 		gameport_cooked_read(gameport, axes, &buttons);
 
 		for (i = 0; i < 4; i++)
-			printk(KERN_INFO "joydump: | Axis %d: %4d.                              |\n", i, axes[i]);
-		printk(KERN_INFO "joydump: | Buttons %02x.                                |\n", buttons);
-		printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
+			printk(KERN_INFO "joydump: | Axis %d: %4d.                           |\n", i, axes[i]);
+		printk(KERN_INFO "joydump: | Buttons %02x.                             |\n", buttons);
+		printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
 	}
 
 	timeout = gameport_time(gameport, 10000); /* 10 ms */
+
+	buf = kmalloc(BUF_SIZE * sizeof(struct joydump), GFP_KERNEL);
+	if (!buf) {
+		printk(KERN_INFO "joydump: no memory for testing\n");
+		goto jd_end;
+	}
+	dump = buf;
 	t = 0;
 	i = 1;
 
@@ -85,19 +95,21 @@
 
 	u = gameport_read(gameport);
 
-	buf[0].data = u;
-	buf[0].time = t;
+	dump->data = u;
+	dump->time = t;
+	dump++;
 
 	gameport_trigger(gameport);
 
 	while (i < BUF_SIZE && t < timeout) {
 
-		buf[i].data = gameport_read(gameport);
+		dump->data = gameport_read(gameport);
 
-		if (buf[i].data ^ u) {
-			u = buf[i].data;
-			buf[i].time = t;
+		if (dump->data ^ u) {
+			u = dump->data;
+			dump->time = t;
 			i++;
+			dump++;
 		}
 		t++;
 	}
@@ -109,42 +121,54 @@
  */
 
 	t = i;
+	dump = buf;
+	prev = dump;
 
-	printk(KERN_INFO "joydump: >------------------- DATA -------------------<\n");
-	printk(KERN_INFO "joydump: | index: %3d delta: %3d.%02d us data: ", 0, 0, 0);
+	printk(KERN_INFO "joydump: >------------------ DATA -----------------<\n");
+	printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", 0, 0);
 	for (j = 7; j >= 0; j--)
-		printk("%d",(buf[0].data >> j) & 1);
+		printk("%d", (dump->data >> j) & 1);
 	printk(" |\n");
-	for (i = 1; i < t; i++) {
+	dump++;
+
+	for (i = 1; i < t; i++, dump++, prev++) {
 		printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ",
-			i, buf[i].time - buf[i-1].time);
+			i, dump->time - prev->time);
 		for (j = 7; j >= 0; j--)
-			printk("%d",(buf[i].data >> j) & 1);
-		printk("    |\n");
+			printk("%d", (dump->data >> j) & 1);
+		printk(" |\n");
 	}
+	kfree(buf);
+
+jd_end:
+	printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
 
-	printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
+	return 0;
 }
 
-static void __devexit joydump_disconnect(struct gameport *gameport)
+static void joydump_disconnect(struct gameport *gameport)
 {
 	gameport_close(gameport);
 }
 
-static struct gameport_dev joydump_dev = {
-	.connect =	joydump_connect,
-	.disconnect =	joydump_disconnect,
+static struct gameport_driver joydump_drv = {
+	.driver		= {
+		.name	= "joydump",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= joydump_connect,
+	.disconnect	= joydump_disconnect,
 };
 
 static int __init joydump_init(void)
 {
-	gameport_register_device(&joydump_dev);
+	gameport_register_driver(&joydump_drv);
 	return 0;
 }
 
 static void __exit joydump_exit(void)
 {
-	gameport_unregister_device(&joydump_dev);
+	gameport_unregister_driver(&joydump_drv);
 }
 
 module_init(joydump_init);
diff -Nru a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
--- a/drivers/input/joystick/magellan.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/magellan.c	2005-03-07 15:26:30 -08:00
@@ -118,7 +118,7 @@
 static irqreturn_t magellan_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct magellan* magellan = serio->private;
+	struct magellan* magellan = serio_get_drvdata(serio);
 
 	if (data == '\r') {
 		magellan_process_packet(magellan, regs);
@@ -136,28 +136,28 @@
 
 static void magellan_disconnect(struct serio *serio)
 {
-	struct magellan* magellan = serio->private;
+	struct magellan* magellan = serio_get_drvdata(serio);
+
 	input_unregister_device(&magellan->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(magellan);
 }
 
 /*
  * magellan_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
+ * new serio device that supports Magellan protocol and registers it as
+ * an input device.
  */
 
-static void magellan_connect(struct serio *serio, struct serio_driver *drv)
+static int magellan_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct magellan *magellan;
 	int i, t;
-
-	if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
-		return;
+	int err;
 
 	if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(magellan, 0, sizeof(struct magellan));
 
@@ -185,28 +185,44 @@
 	magellan->dev.id.version = 0x0100;
 	magellan->dev.dev = &serio->dev;
 
-	serio->private = magellan;
+	serio_set_drvdata(serio, magellan);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(magellan);
-		return;
+		return err;
 	}
 
 	input_register_device(&magellan->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys);
 
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id magellan_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MAGELLAN,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, magellan_serio_ids);
+
 static struct serio_driver magellan_drv = {
 	.driver		= {
 		.name	= "magellan",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= magellan_serio_ids,
 	.interrupt	= magellan_interrupt,
 	.connect	= magellan_connect,
 	.disconnect	= magellan_disconnect,
@@ -216,13 +232,13 @@
  * The functions for inserting/removing us as a module.
  */
 
-int __init magellan_init(void)
+static int __init magellan_init(void)
 {
 	serio_register_driver(&magellan_drv);
 	return 0;
 }
 
-void __exit magellan_exit(void)
+static void __exit magellan_exit(void)
 {
 	serio_unregister_driver(&magellan_drv);
 }
diff -Nru a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
--- a/drivers/input/joystick/sidewinder.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/sidewinder.c	2005-03-07 15:26:30 -08:00
@@ -1,7 +1,5 @@
 /*
- * $Id: sidewinder.c,v 1.29 2002/01/22 20:28:51 vojtech Exp $
- *
- *  Copyright (c) 1998-2001 Vojtech Pavlik
+ *  Copyright (c) 1998-2005 Vojtech Pavlik
  */
 
 /*
@@ -36,8 +34,10 @@
 #include <linux/input.h>
 #include <linux/gameport.h>
 
+#define DRIVER_DESC	"Microsoft SideWinder joystick family driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Microsoft SideWinder joystick family driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -45,18 +45,18 @@
  * as well as break everything.
  */
 
-/* #define SW_DEBUG */
+#undef SW_DEBUG
+#undef SW_DEBUG_DATA
 
-#define SW_START	400	/* The time we wait for the first bit [400 us] */
-#define SW_STROBE	45	/* Max time per bit [45 us] */
-#define SW_TIMEOUT	4000	/* Wait for everything to settle [4 ms] */
+#define SW_START	600	/* The time we wait for the first bit [600 us] */
+#define SW_STROBE	60	/* Max time per bit [60 us] */
+#define SW_TIMEOUT	6	/* Wait for everything to settle [6 ms] */
 #define SW_KICK		45	/* Wait after A0 fall till kick [45 us] */
 #define SW_END		8	/* Number of bits before end of packet to kick */
 #define SW_FAIL		16	/* Number of packet read errors to fail and reinitialize */
 #define SW_BAD		2	/* Number of packet read errors to switch off 3d Pro optimization */
 #define SW_OK		64	/* Number of packet read successes to switch optimization back on */
 #define SW_LENGTH	512	/* Max number of bits in a packet */
-#define SW_REFRESH	HZ/50	/* Time to wait between updates of joystick data [20 ms] */
 
 #ifdef SW_DEBUG
 #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
@@ -113,7 +113,6 @@
 
 struct sw {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[4];
 	char name[64];
 	char phys[4][32];
@@ -125,7 +124,6 @@
 	int ok;
 	int reads;
 	int bads;
-	int used;
 };
 
 /*
@@ -141,7 +139,7 @@
 	unsigned char pending, u, v;
 
 	i = -id;						/* Don't care about data, only want ID */
-	timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0;	/* Set up global timeout for ID packet */
+	timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 0; /* Set up global timeout for ID packet */
 	kick = id ? gameport_time(gameport, SW_KICK) : 0;	/* Set up kick timeout for ID packet */
 	start = gameport_time(gameport, SW_START);
 	strobe = gameport_time(gameport, SW_STROBE);
@@ -160,7 +158,8 @@
 		v = gameport_read(gameport);
 	} while (!(~v & u & 0x10) && (bitout > 0));		/* Wait for first falling edge on clock */
 
-	if (bitout > 0) bitout = strobe;			/* Extend time if not timed out */
+	if (bitout > 0)
+		bitout = strobe;				/* Extend time if not timed out */
 
 	while ((timeout > 0 || bitout > 0) && (i < length)) {
 
@@ -194,7 +193,7 @@
 
 	local_irq_restore(flags);					/* Done - relax */
 
-#ifdef SW_DEBUG
+#ifdef SW_DEBUG_DATA
 	{
 		int j;
 		printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
@@ -249,7 +248,7 @@
 	i = 0;
         do {
                 gameport_trigger(gameport);			/* Trigger */
-		t = gameport_time(gameport, SW_TIMEOUT);
+		t = gameport_time(gameport, SW_TIMEOUT * 1000);
 		while ((gameport_read(gameport) & 1) && t) t--;	/* Wait for axis to fall back to 0 */
                 udelay(seq[i]);					/* Delay magic time */
         } while (seq[++i]);
@@ -266,6 +265,7 @@
 static int sw_parity(__u64 t)
 {
 	int x = t ^ (t >> 32);
+
 	x ^= x >> 16;
 	x ^= x >> 8;
 	x ^= x >> 4;
@@ -307,7 +307,8 @@
 
 		case SW_ID_3DP:
 
-			if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
+			if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8)
+				return -1;
 
 			input_report_abs(dev, ABS_X,        (GB( 3,3) << 7) | GB(16,7));
 			input_report_abs(dev, ABS_Y,        (GB( 0,3) << 7) | GB(24,7));
@@ -331,7 +332,8 @@
 
 			for (i = 0; i < sw->number; i ++) {
 
-				if (sw_parity(GB(i*15,15))) return -1;
+				if (sw_parity(GB(i*15,15)))
+					return -1;
 
 				input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
 				input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
@@ -347,7 +349,8 @@
 		case SW_ID_PP:
 		case SW_ID_FFP:
 
-			if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
+			if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8)
+				return -1;
 
 			input_report_abs(dev, ABS_X,        GB( 9,10));
 			input_report_abs(dev, ABS_Y,        GB(19,10));
@@ -366,7 +369,8 @@
 
 		case SW_ID_FSP:
 
-			if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
+			if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8)
+				return -1;
 
 			input_report_abs(dev, ABS_X,        GB( 0,10));
 			input_report_abs(dev, ABS_Y,        GB(16,10));
@@ -389,7 +393,8 @@
 
 		case SW_ID_FFW:
 
-			if (!sw_parity(GB(0,33))) return -1;
+			if (!sw_parity(GB(0,33)))
+				return -1;
 
 			input_report_abs(dev, ABS_RX,       GB( 0,10));
 			input_report_abs(dev, ABS_RUDDER,   GB(10, 6));
@@ -466,19 +471,20 @@
 		sw->length = 66;
 	}
 
-	if (sw->fail < SW_FAIL) return -1;					/* Not enough, don't reinitialize yet */
+	if (sw->fail < SW_FAIL)
+		return -1;							/* Not enough, don't reinitialize yet */
 
 	printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s"
 		" - reinitializing joystick.\n", sw->gameport->phys);
 
 	if (!i && sw->type == SW_ID_3DP) {					/* 3D Pro can be in analog mode */
-		udelay(3 * SW_TIMEOUT);
+		mdelay(3 * SW_TIMEOUT);
 		sw_init_digital(sw->gameport);
 	}
 
-	udelay(SW_TIMEOUT);
+	mdelay(SW_TIMEOUT);
 	i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0);			/* Read normal data packet */
-	udelay(SW_TIMEOUT);
+	mdelay(SW_TIMEOUT);
 	sw_read_packet(sw->gameport, buf, SW_LENGTH, i);			/* Read ID packet, this initializes the stick */
 
 	sw->fail = SW_FAIL;
@@ -486,28 +492,28 @@
 	return -1;
 }
 
-static void sw_timer(unsigned long private)
+static void sw_poll(struct gameport *gameport)
 {
-	struct sw *sw = (void *) private;
+	struct sw *sw = gameport_get_drvdata(gameport);
 
 	sw->reads++;
-	if (sw_read(sw)) sw->bads++;
-	mod_timer(&sw->timer, jiffies + SW_REFRESH);
+	if (sw_read(sw))
+		sw->bads++;
 }
 
 static int sw_open(struct input_dev *dev)
 {
 	struct sw *sw = dev->private;
-	if (!sw->used++)
-		mod_timer(&sw->timer, jiffies + SW_REFRESH);
+
+	gameport_start_polling(sw->gameport);
 	return 0;
 }
 
 static void sw_close(struct input_dev *dev)
 {
 	struct sw *sw = dev->private;
-	if (!--sw->used)
-		del_timer(&sw->timer);
+
+	gameport_stop_polling(sw->gameport);
 }
 
 /*
@@ -561,7 +567,10 @@
 {
 	int i;
 	unsigned char xor = 0;
-	for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
+
+	for (i = 1; i < len; i++)
+		xor |= (buf[i - 1] ^ buf[i]) & 6;
+
 	return !!xor * 2 + 1;
 }
 
@@ -569,10 +578,11 @@
  * sw_connect() probes for SideWinder type joysticks.
  */
 
-static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
 	struct sw *sw;
 	int i, j, k, l;
+	int err;
 	unsigned char *buf = NULL;	/* [SW_LENGTH] */
 	unsigned char *idbuf = NULL;	/* [SW_LENGTH] */
 	unsigned char m = 1;
@@ -580,50 +590,55 @@
 
 	comment[0] = 0;
 
-	if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
-	memset(sw, 0, sizeof(struct sw));
-
+	sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL);
 	buf = kmalloc(SW_LENGTH, GFP_KERNEL);
 	idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
-	if (!buf || !idbuf)
+	if (!sw || !buf || !idbuf) {
+		err = -ENOMEM;
 		goto fail1;
-
-	gameport->private = sw;
+	}
 
 	sw->gameport = gameport;
-	init_timer(&sw->timer);
-	sw->timer.data = (long) sw;
-	sw->timer.function = sw_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, sw);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
 	dbg("Init 0: Opened %s, io %#x, speed %d",
 		gameport->phys, gameport->io, gameport->speed);
 
 	i = sw_read_packet(gameport, buf, SW_LENGTH, 0);		/* Read normal packet */
-	udelay(SW_TIMEOUT);
+	msleep(SW_TIMEOUT);
 	dbg("Init 1: Mode %d. Length %d.", m , i);
 
 	if (!i) {							/* No data. 3d Pro analog mode? */
 		sw_init_digital(gameport);				/* Switch to digital */
-		udelay(SW_TIMEOUT);
+		msleep(SW_TIMEOUT);
 		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
-		udelay(SW_TIMEOUT);
+		msleep(SW_TIMEOUT);
 		dbg("Init 1b: Length %d.", i);
-		if (!i) goto fail2;					/* No data -> FAIL */
+		if (!i) {						/* No data -> FAIL */
+			err = -ENODEV;
+			goto fail2;
+		}
 	}
 
 	j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);		/* Read ID. This initializes the stick */
 	m |= sw_guess_mode(idbuf, j);					/* ID packet should carry mode info [3DP] */
-	dbg("Init 2: Mode %d. ID Length %d.", m , j);
+	dbg("Init 2: Mode %d. ID Length %d.", m, j);
 
-	if (!j) {							/* Read ID failed. Happens in 1-bit mode on PP */
-		udelay(SW_TIMEOUT);
+	if (j <= 0) {							/* Read ID failed. Happens in 1-bit mode on PP */
+		msleep(SW_TIMEOUT);
 		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Retry reading packet */
+		m |= sw_guess_mode(buf, i);
 		dbg("Init 2b: Mode %d. Length %d.", m, i);
-		if (!i) goto fail2;
-		udelay(SW_TIMEOUT);
+		if (!i) {
+			err = -ENODEV;
+			goto fail2;
+		}
+		msleep(SW_TIMEOUT);
 		j = sw_read_packet(gameport, idbuf, SW_LENGTH, i);	/* Retry reading ID */
 		dbg("Init 2c: ID Length %d.", j);
 	}
@@ -634,7 +649,7 @@
 
 	do {
 		k--;
-		udelay(SW_TIMEOUT);
+		msleep(SW_TIMEOUT);
 		i = sw_read_packet(gameport, buf, SW_LENGTH, 0);	/* Read data packet */
 		dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
 
@@ -686,13 +701,14 @@
 			}
 		}
 
-	} while (k && (sw->type == -1));
+	} while (k && sw->type == -1);
 
 	if (sw->type == -1) {
 		printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
 			"on %s, contact <vojtech@ucw.cz>\n", gameport->phys);
 		sw_print_packet("ID", j * 3, idbuf, 3);
 		sw_print_packet("Data", i * m, buf, m);
+		err = -ENODEV;
 		goto fail2;
 	}
 
@@ -701,6 +717,9 @@
 	sw_print_packet("Data", i * m, buf, m);
 #endif
 
+	gameport_set_poll_handler(gameport, sw_poll);
+	gameport_set_poll_interval(gameport, 20);
+
 	k = i;
 	l = j;
 
@@ -742,38 +761,46 @@
 			sw->name, comment, gameport->phys, m, l, k);
 	}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(sw);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(sw);
 	kfree(buf);
 	kfree(idbuf);
+	return err;
 }
 
 static void sw_disconnect(struct gameport *gameport)
 {
+	struct sw *sw = gameport_get_drvdata(gameport);
 	int i;
 
-	struct sw *sw = gameport->private;
 	for (i = 0; i < sw->number; i++)
 		input_unregister_device(sw->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(sw);
 }
 
-static struct gameport_dev sw_dev = {
-	.connect =	sw_connect,
-	.disconnect =	sw_disconnect,
+static struct gameport_driver sw_drv = {
+	.driver		= {
+		.name	= "sidewinder",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= sw_connect,
+	.disconnect	= sw_disconnect,
 };
 
-int __init sw_init(void)
+static int __init sw_init(void)
 {
-	gameport_register_device(&sw_dev);
+	gameport_register_driver(&sw_drv);
 	return 0;
 }
 
-void __exit sw_exit(void)
+static void __exit sw_exit(void)
 {
-	gameport_unregister_device(&sw_dev);
+	gameport_unregister_driver(&sw_drv);
 }
 
 module_init(sw_init);
diff -Nru a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
--- a/drivers/input/joystick/spaceball.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/spaceball.c	2005-03-07 15:26:30 -08:00
@@ -154,7 +154,7 @@
 static irqreturn_t spaceball_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct spaceball *spaceball = serio->private;
+	struct spaceball *spaceball = serio_get_drvdata(serio);
 
 	switch (data) {
 		case 0xd:
@@ -191,31 +191,32 @@
 
 static void spaceball_disconnect(struct serio *serio)
 {
-	struct spaceball* spaceball = serio->private;
+	struct spaceball* spaceball = serio_get_drvdata(serio);
+
 	input_unregister_device(&spaceball->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(spaceball);
 }
 
 /*
  * spaceball_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
+ * new serio device that supports Spaceball protocol and registers it as
+ * an input device.
  */
 
-static void spaceball_connect(struct serio *serio, struct serio_driver *drv)
+static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct spaceball *spaceball;
 	int i, t, id;
+	int err;
 
-	if ((serio->type & ~SERIO_ID) != (SERIO_RS232 | SERIO_SPACEBALL))
-		return;
-
-	if ((id = (serio->type & SERIO_ID) >> 8) > SPACEBALL_MAX_ID)
-		return;
+	if ((id = serio->id.id) > SPACEBALL_MAX_ID)
+		return -ENODEV;
 
 	if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
-		return;
+		return - ENOMEM;
+
 	memset(spaceball, 0, sizeof(struct spaceball));
 
 	spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
@@ -255,28 +256,45 @@
 	spaceball->dev.id.version = 0x0100;
 	spaceball->dev.dev = &serio->dev;
 
-	serio->private = spaceball;
+	serio_set_drvdata(serio, spaceball);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(spaceball);
-		return;
+		return err;
 	}
 
 	input_register_device(&spaceball->dev);
 
 	printk(KERN_INFO "input: %s on serio%s\n",
 		spaceball_names[id], serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id spaceball_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SPACEBALL,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, spaceball_serio_ids);
+
 static struct serio_driver spaceball_drv = {
 	.driver		= {
 		.name	= "spaceball",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= spaceball_serio_ids,
 	.interrupt	= spaceball_interrupt,
 	.connect	= spaceball_connect,
 	.disconnect	= spaceball_disconnect,
@@ -286,13 +304,13 @@
  * The functions for inserting/removing us as a module.
  */
 
-int __init spaceball_init(void)
+static int __init spaceball_init(void)
 {
 	serio_register_driver(&spaceball_drv);
 	return 0;
 }
 
-void __exit spaceball_exit(void)
+static void __exit spaceball_exit(void)
 {
 	serio_unregister_driver(&spaceball_drv);
 }
diff -Nru a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
--- a/drivers/input/joystick/spaceorb.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/spaceorb.c	2005-03-07 15:26:30 -08:00
@@ -135,7 +135,7 @@
 static irqreturn_t spaceorb_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct spaceorb* spaceorb = serio->private;
+	struct spaceorb* spaceorb = serio_get_drvdata(serio);
 
 	if (~data & 0x80) {
 		if (spaceorb->idx) spaceorb_process_packet(spaceorb, regs);
@@ -152,28 +152,29 @@
 
 static void spaceorb_disconnect(struct serio *serio)
 {
-	struct spaceorb* spaceorb = serio->private;
+	struct spaceorb* spaceorb = serio_get_drvdata(serio);
+
 	input_unregister_device(&spaceorb->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(spaceorb);
 }
 
 /*
  * spaceorb_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
+ * new serio device that supports SpaceOrb/Avenger protocol and registers
  * it as an input device.
  */
 
-static void spaceorb_connect(struct serio *serio, struct serio_driver *drv)
+static int spaceorb_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct spaceorb *spaceorb;
 	int i, t;
-
-	if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
-		return;
+	int err;
 
 	if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
+
 	memset(spaceorb, 0, sizeof(struct spaceorb));
 
 	spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
@@ -202,25 +203,42 @@
 	spaceorb->dev.id.version = 0x0100;
 	spaceorb->dev.dev = &serio->dev;
 
-	serio->private = spaceorb;
+	serio_set_drvdata(serio, spaceorb);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(spaceorb);
-		return;
+		return err;
 	}
 
 	input_register_device(&spaceorb->dev);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id spaceorb_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SPACEORB,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, spaceorb_serio_ids);
+
 static struct serio_driver spaceorb_drv = {
 	.driver		= {
 		.name	= "spaceorb",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= spaceorb_serio_ids,
 	.interrupt	= spaceorb_interrupt,
 	.connect	= spaceorb_connect,
 	.disconnect	= spaceorb_disconnect,
@@ -230,13 +248,13 @@
  * The functions for inserting/removing us as a module.
  */
 
-int __init spaceorb_init(void)
+static int __init spaceorb_init(void)
 {
 	serio_register_driver(&spaceorb_drv);
 	return 0;
 }
 
-void __exit spaceorb_exit(void)
+static void __exit spaceorb_exit(void)
 {
 	serio_unregister_driver(&spaceorb_drv);
 }
diff -Nru a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
--- a/drivers/input/joystick/stinger.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/stinger.c	2005-03-07 15:26:30 -08:00
@@ -103,7 +103,7 @@
 static irqreturn_t stinger_interrupt(struct serio *serio,
 	unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct stinger* stinger = serio->private;
+	struct stinger *stinger = serio_get_drvdata(serio);
 
 	/* All Stinger packets are 4 bytes */
 
@@ -124,28 +124,28 @@
 
 static void stinger_disconnect(struct serio *serio)
 {
-	struct stinger* stinger = serio->private;
+	struct stinger *stinger = serio_get_drvdata(serio);
+
 	input_unregister_device(&stinger->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(stinger);
 }
 
 /*
  * stinger_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Stinger, and if found, registers
- * it as an input device.
+ * new serio device that supports Stinger protocol and registers it as
+ * an input device.
  */
 
-static void stinger_connect(struct serio *serio, struct serio_driver *drv)
+static int stinger_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct stinger *stinger;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_STINGER))
-		return;
+	int err;
 
 	if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(stinger, 0, sizeof(struct stinger));
 
@@ -173,28 +173,45 @@
 	}
 
 	stinger->dev.private = stinger;
-	serio->private = stinger;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, stinger);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(stinger);
-		return;
+		return err;
 	}
 
 	input_register_device(&stinger->dev);
 
 	printk(KERN_INFO "input: %s on %s\n",  stinger_name, serio->phys);
 
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id stinger_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_STINGER,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, stinger_serio_ids);
+
 static struct serio_driver stinger_drv = {
 	.driver		= {
 		.name	= "stinger",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= stinger_serio_ids,
 	.interrupt	= stinger_interrupt,
 	.connect	= stinger_connect,
 	.disconnect	= stinger_disconnect,
@@ -204,13 +221,13 @@
  * The functions for inserting/removing us as a module.
  */
 
-int __init stinger_init(void)
+static int __init stinger_init(void)
 {
 	serio_register_driver(&stinger_drv);
 	return 0;
 }
 
-void __exit stinger_exit(void)
+static void __exit stinger_exit(void)
 {
 	serio_unregister_driver(&stinger_drv);
 }
diff -Nru a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
--- a/drivers/input/joystick/tmdc.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/tmdc.c	2005-03-07 15:26:30 -08:00
@@ -39,14 +39,15 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+#define DRIVER_DESC	"ThrustMaster DirectConnect joystick driver"
+
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("ThrustMaster DirectConnect joystick driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define TMDC_MAX_START		400	/* 400 us */
-#define TMDC_MAX_STROBE		45	/* 45 us */
+#define TMDC_MAX_START		600	/* 600 us */
+#define TMDC_MAX_STROBE		60	/* 60 us */
 #define TMDC_MAX_LENGTH		13
-#define TMDC_REFRESH_TIME	HZ/50	/* 20 ms */
 
 #define TMDC_MODE_M3DI		1
 #define TMDC_MODE_3DRP		3
@@ -92,7 +93,6 @@
 
 struct tmdc {
 	struct gameport *gameport;
-	struct timer_list timer;
 	struct input_dev dev[2];
 	char name[2][64];
 	char phys[2][32];
@@ -102,7 +102,6 @@
 	unsigned char absc[2];
 	unsigned char btnc[2][4];
 	unsigned char btno[2][4];
-	int used;
 	int reads;
 	int bads;
 	unsigned char exists;
@@ -158,13 +157,13 @@
 }
 
 /*
- * tmdc_read() reads and analyzes ThrustMaster joystick data.
+ * tmdc_poll() reads and analyzes ThrustMaster joystick data.
  */
 
-static void tmdc_timer(unsigned long private)
+static void tmdc_poll(struct gameport *gameport)
 {
 	unsigned char data[2][TMDC_MAX_LENGTH];
-	struct tmdc *tmdc = (void *) private;
+	struct tmdc *tmdc = gameport_get_drvdata(gameport);
 	struct input_dev *dev;
 	unsigned char r, bad = 0;
 	int i, j, k, l;
@@ -219,32 +218,30 @@
 	}
 
 	tmdc->bads += bad;
-
-	mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
 }
 
 static int tmdc_open(struct input_dev *dev)
 {
 	struct tmdc *tmdc = dev->private;
-	if (!tmdc->used++)
-		mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
+
+	gameport_start_polling(tmdc->gameport);
 	return 0;
 }
 
 static void tmdc_close(struct input_dev *dev)
 {
 	struct tmdc *tmdc = dev->private;
-	if (!--tmdc->used)
-		del_timer(&tmdc->timer);
+
+	gameport_stop_polling(tmdc->gameport);
 }
 
 /*
  * tmdc_probe() probes for ThrustMaster type joysticks.
  */
 
-static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
+static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
 {
-	struct models {
+	static struct models {
 		unsigned char id;
 		char *name;
 		char abs;
@@ -263,23 +260,26 @@
 	unsigned char data[2][TMDC_MAX_LENGTH];
 	struct tmdc *tmdc;
 	int i, j, k, l, m;
+	int err;
 
-	if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
-		return;
-	memset(tmdc, 0, sizeof(struct tmdc));
-
-	gameport->private = tmdc;
+	if (!(tmdc = kcalloc(1, sizeof(struct tmdc), GFP_KERNEL)))
+		return -ENOMEM;
 
 	tmdc->gameport = gameport;
-	init_timer(&tmdc->timer);
-	tmdc->timer.data = (long) tmdc;
-	tmdc->timer.function = tmdc_timer;
 
-	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+	gameport_set_drvdata(gameport, tmdc);
+
+	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
+	if (err)
 		goto fail1;
 
-	if (!(tmdc->exists = tmdc_read_packet(gameport, data)))
+	if (!(tmdc->exists = tmdc_read_packet(gameport, data))) {
+		err = -ENODEV;
 		goto fail2;
+	}
+
+	gameport_set_poll_handler(gameport, tmdc_poll);
+	gameport_set_poll_interval(gameport, 20);
 
 	for (j = 0; j < 2; j++)
 		if (tmdc->exists & (1 << j)) {
@@ -321,20 +321,13 @@
 
 			tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-			for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
-				if (tmdc->abs[j][i] < 0) continue;
-				set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
-				tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
-				tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
-				tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
-				tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
-			}
+			for (i = 0; i < models[m].abs && i < TMDC_ABS; i++)
+				if (tmdc->abs[j][i] >= 0)
+					input_set_abs_params(&tmdc->dev[j], tmdc->abs[j][i], 8, 248, 2, 4);
+
+			for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++)
+				input_set_abs_params(&tmdc->dev[j], tmdc_abs_hat[i], -1, 1, 0, 0);
 
-			for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
-				set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit);
-				tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1;
-				tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
-			}
 
 			for (k = l = 0; k < 4; k++) {
 				for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
@@ -346,36 +339,45 @@
 			printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys);
 		}
 
-	return;
+	return 0;
+
 fail2:	gameport_close(gameport);
-fail1:	kfree(tmdc);
+fail1:	gameport_set_drvdata(gameport, NULL);
+	kfree(tmdc);
+	return err;
 }
 
 static void tmdc_disconnect(struct gameport *gameport)
 {
-	struct tmdc *tmdc = gameport->private;
+	struct tmdc *tmdc = gameport_get_drvdata(gameport);
 	int i;
+
 	for (i = 0; i < 2; i++)
 		if (tmdc->exists & (1 << i))
 			input_unregister_device(tmdc->dev + i);
 	gameport_close(gameport);
+	gameport_set_drvdata(gameport, NULL);
 	kfree(tmdc);
 }
 
-static struct gameport_dev tmdc_dev = {
-	.connect =	tmdc_connect,
-	.disconnect =	tmdc_disconnect,
+static struct gameport_driver tmdc_drv = {
+	.driver		= {
+		.name	= "tmdc",
+	},
+	.description	= DRIVER_DESC,
+	.connect	= tmdc_connect,
+	.disconnect	= tmdc_disconnect,
 };
 
-int __init tmdc_init(void)
+static int __init tmdc_init(void)
 {
-	gameport_register_device(&tmdc_dev);
+	gameport_register_driver(&tmdc_drv);
 	return 0;
 }
 
-void __exit tmdc_exit(void)
+static void __exit tmdc_exit(void)
 {
-	gameport_unregister_device(&tmdc_dev);
+	gameport_unregister_driver(&tmdc_drv);
 }
 
 module_init(tmdc_init);
diff -Nru a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
--- a/drivers/input/joystick/turbografx.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/turbografx.c	2005-03-07 15:26:30 -08:00
@@ -77,7 +77,7 @@
 static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
 static char *tgfx_name = "TurboGraFX Multisystem joystick";
 
-struct tgfx {
+static struct tgfx {
 	struct pardevice *pd;
 	struct timer_list timer;
 	struct input_dev dev[7];
@@ -229,7 +229,7 @@
 	return tgfx;
 }
 
-int __init tgfx_init(void)
+static int __init tgfx_init(void)
 {
 	tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs);
 	tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2);
@@ -241,7 +241,7 @@
 	return -ENODEV;
 }
 
-void __exit tgfx_exit(void)
+static void __exit tgfx_exit(void)
 {
 	int i, j;
 
diff -Nru a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
--- a/drivers/input/joystick/twidjoy.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/twidjoy.c	2005-03-07 15:26:30 -08:00
@@ -58,7 +58,9 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 
-MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver");
+#define DRIVER_DESC	"Handykey Twiddler keyboard as a joystick driver"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 /*
@@ -147,7 +149,7 @@
 
 static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct twidjoy *twidjoy = serio->private;
+	struct twidjoy *twidjoy = serio_get_drvdata(serio);
 
 	/* All Twiddler packets are 5 bytes. The fact that the first byte
 	 * has a MSB of 0 and all other bytes have a MSB of 1 can be used
@@ -175,9 +177,11 @@
 
 static void twidjoy_disconnect(struct serio *serio)
 {
-	struct twidjoy *twidjoy = serio->private;
+	struct twidjoy *twidjoy = serio_get_drvdata(serio);
+
 	input_unregister_device(&twidjoy->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(twidjoy);
 }
 
@@ -187,17 +191,15 @@
  * it as an input device.
  */
 
-static void twidjoy_connect(struct serio *serio, struct serio_driver *drv)
+static int twidjoy_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct twidjoy_button_spec *bp;
 	struct twidjoy *twidjoy;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY))
-		return;
+	int err;
 
 	if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(twidjoy, 0, sizeof(struct twidjoy));
 
@@ -231,27 +233,45 @@
 	}
 
 	twidjoy->dev.private = twidjoy;
-	serio->private = twidjoy;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, twidjoy);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(twidjoy);
-		return;
+		return err;
 	}
 
 	input_register_device(&twidjoy->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id twidjoy_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_TWIDJOY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, twidjoy_serio_ids);
+
 static struct serio_driver twidjoy_drv = {
 	.driver		= {
 		.name	= "twidjoy",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= twidjoy_serio_ids,
 	.interrupt	= twidjoy_interrupt,
 	.connect	= twidjoy_connect,
 	.disconnect	= twidjoy_disconnect,
diff -Nru a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
--- a/drivers/input/joystick/warrior.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/joystick/warrior.c	2005-03-07 15:26:30 -08:00
@@ -104,7 +104,7 @@
 static irqreturn_t warrior_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct warrior* warrior = serio->private;
+	struct warrior *warrior = serio_get_drvdata(serio);
 
 	if (data & 0x80) {
 		if (warrior->idx) warrior_process_packet(warrior, regs);
@@ -129,9 +129,11 @@
 
 static void warrior_disconnect(struct serio *serio)
 {
-	struct warrior* warrior = serio->private;
+	struct warrior *warrior = serio_get_drvdata(serio);
+
 	input_unregister_device(&warrior->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(warrior);
 }
 
@@ -141,16 +143,14 @@
  * it as an input device.
  */
 
-static void warrior_connect(struct serio *serio, struct serio_driver *drv)
+static int warrior_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct warrior *warrior;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_WARRIOR))
-		return;
+	int err;
 
 	if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(warrior, 0, sizeof(struct warrior));
 
@@ -186,27 +186,44 @@
 
 	warrior->dev.private = warrior;
 
-	serio->private = warrior;
+	serio_set_drvdata(serio, warrior);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(warrior);
-		return;
+		return err;
 	}
 
 	input_register_device(&warrior->dev);
 
 	printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id warrior_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_WARRIOR,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, warrior_serio_ids);
+
 static struct serio_driver warrior_drv = {
 	.driver		= {
 		.name	= "warrior",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= warrior_serio_ids,
 	.interrupt	= warrior_interrupt,
 	.connect	= warrior_connect,
 	.disconnect	= warrior_disconnect,
@@ -216,13 +233,13 @@
  * The functions for inserting/removing us as a module.
  */
 
-int __init warrior_init(void)
+static int __init warrior_init(void)
 {
 	serio_register_driver(&warrior_drv);
 	return 0;
 }
 
-void __exit warrior_exit(void)
+static void __exit warrior_exit(void)
 {
 	serio_unregister_driver(&warrior_drv);
 }
diff -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
--- a/drivers/input/keyboard/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/Kconfig	2005-03-07 15:26:30 -08:00
@@ -1,20 +1,20 @@
 #
 # Input core configuration
 #
-config INPUT_KEYBOARD
+menuconfig INPUT_KEYBOARD
 	bool "Keyboards" if EMBEDDED || !X86
 	default y
-	depends on INPUT
 	help
 	  Say Y here, and a list of supported keyboards will be displayed.
 	  This option doesn't affect the kernel.
 
 	  If unsure, say Y.
 
+if INPUT_KEYBOARD
+
 config KEYBOARD_ATKBD
-	tristate "AT keyboard support" if !PC
+	tristate "AT keyboard" if !PC
 	default y
-	depends on INPUT && INPUT_KEYBOARD
 	select SERIO
 	select SERIO_LIBPS2
 	select SERIO_I8042 if PC
@@ -30,9 +30,46 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called atkbd.
 
+config KEYBOARD_ATKBD_HP_KEYCODES
+	bool "Use HP keyboard scancodes"
+	depends on PARISC && KEYBOARD_ATKBD
+	default y
+	help
+	  Say Y here if you have a PA-RISC machine and want to use an AT or
+	  PS/2 keyboard, and your keyboard uses keycodes that are specific to
+	  PA-RISC keyboards.
+
+	  Say N if you use a standard keyboard.
+
+config KEYBOARD_ATKBD_RDI_KEYCODES
+	bool "Use PrecisionBook keyboard scancodes"
+	depends on KEYBOARD_ATKBD_HP_KEYCODES
+	default n
+	help
+	  If you have an RDI PrecisionBook, say Y here if you want to use its
+	  built-in keyboard (as opposed to an external keyboard).
+
+	  The PrecisionBook has five keys that conflict with those used by most
+	  AT and PS/2 keyboards. These are as follows:
+
+	    PrecisionBook    Standard AT or PS/2
+
+	    F1               F12
+	    Left Ctrl        Left Alt
+	    Caps Lock        Left Ctrl
+	    Right Ctrl       Caps Lock
+	    Left             102nd key (the key to the right of Left Shift)
+
+	  If you say N here, and use the PrecisionBook keyboard, then each key
+	  in the left-hand column will be interpreted as the corresponding key
+	  in the right-hand column.
+
+	  If you say Y here, and use an external keyboard, then each key in the
+	  right-hand column will be interpreted as the key shown in the
+	  left-hand column.
+
 config KEYBOARD_SUNKBD
-	tristate "Sun Type 4 and Type 5 keyboard support"
-	depends on INPUT && INPUT_KEYBOARD
+	tristate "Sun Type 4 and Type 5 keyboard"
 	select SERIO
 	help
 	  Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
@@ -43,8 +80,7 @@
 	  module will be called sunkbd.
 
 config KEYBOARD_LKKBD
-	tristate "DECstation/VAXstation LK201/LK401 keyboard support"
-	depends on INPUT && INPUT_KEYBOARD
+	tristate "DECstation/VAXstation LK201/LK401 keyboard"
 	select SERIO
 	help
 	  Say Y here if you want to use a LK201 or LK401 style serial
@@ -55,9 +91,17 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called lkkbd.
 
+config KEYBOARD_LOCOMO
+	tristate "LoCoMo Keyboard Support"
+	depends on SHARP_LOCOMO
+	help
+	  Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called locomokbd.
+
 config KEYBOARD_XTKBD
-	tristate "XT Keyboard support"
-	depends on INPUT && INPUT_KEYBOARD
+	tristate "XT keyboard"
 	select SERIO
 	help
 	  Say Y here if you want to use the old IBM PC/XT keyboard (or
@@ -70,7 +114,6 @@
 
 config KEYBOARD_NEWTON
 	tristate "Newton keyboard"
-	depends on INPUT && INPUT_KEYBOARD
 	select SERIO
 	help
 	  Say Y here if you have a Newton keyboard on a serial port.
@@ -78,9 +121,20 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called newtonkbd.
 
+config KEYBOARD_CORGI
+	tristate "Corgi keyboard"
+	depends on PXA_SHARPSL
+	default y	
+	help
+	  Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx 
+	  series of PDAs.
+
+	  To compile this driver as a module, choose M here: the 
+	  module will be called corgikbd.
+
 config KEYBOARD_MAPLE
-	tristate "Maple bus keyboard support"
-	depends on SH_DREAMCAST && INPUT && INPUT_KEYBOARD && MAPLE
+	tristate "Maple bus keyboard"
+	depends on SH_DREAMCAST && MAPLE
 	help
 	  Say Y here if you have a DreamCast console running Linux and have
 	  a keyboard attached to its Maple bus.
@@ -90,10 +144,42 @@
 
 config KEYBOARD_AMIGA
 	tristate "Amiga keyboard"
-	depends on AMIGA && INPUT && INPUT_KEYBOARD
+	depends on AMIGA
 	help
 	  Say Y here if you are running Linux on any AMIGA and have a keyboard
 	  attached.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called amikbd.
+
+config KEYBOARD_HIL_OLD
+	tristate "HP HIL keyboard support (simple driver)"
+	depends on GSC
+	default y
+	help
+	  The "Human Interface Loop" is a older, 8-channel USB-like
+	  controller used in several Hewlett Packard models. This driver
+	  was adapted from the one written for m68k/hp300, and implements
+	  support for a keyboard attached to the HIL port, but not for
+	  any other types of HIL input devices like mice or tablets.
+	  However, it has been thoroughly tested and is stable.
+
+	  If you want full HIL support including support for multiple
+	  keyboards, mices and tablets, you have to enable the
+	  "HP System Device Controller i8042 Support" in the input/serio
+	  submenu.
+
+config KEYBOARD_HIL
+	tristate "HP HIL keyboard support"
+	depends on GSC
+	default y
+	select HP_SDC
+	select HIL_MLC
+	select SERIO
+	help
+	  The "Human Interface Loop" is a older, 8-channel USB-like
+	  controller used in several Hewlett Packard models.
+	  This driver implements support for HIL-keyboards attached
+	  to your machine, so normally you should say Y here.
+
+endif
diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
--- a/drivers/input/keyboard/Makefile	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/Makefile	2005-03-07 15:26:30 -08:00
@@ -10,5 +10,10 @@
 obj-$(CONFIG_KEYBOARD_LKKBD)		+= lkkbd.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
+obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_98KBD)		+= 98kbd.o
+obj-$(CONFIG_KEYBOARD_CORGI)		+= corgikbd.o
+obj-$(CONFIG_KEYBOARD_HIL)		+= hil_kbd.o
+obj-$(CONFIG_KEYBOARD_HIL_OLD)		+= hilkbd.o
+
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/atkbd.c	2005-03-07 15:26:30 -08:00
@@ -54,7 +54,7 @@
 module_param_named(softraw, atkbd_softraw, bool, 0);
 MODULE_PARM_DESC(softraw, "Use software generated rawmode");
 
-static int atkbd_scroll;
+static int atkbd_scroll = 1;
 module_param_named(scroll, atkbd_scroll, bool, 0);
 MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
 
@@ -71,12 +71,15 @@
  * are loadable via an userland utility.
  */
 
-#if defined(__hppa__)
-#include "hpps2atkbd.h"
-#else
-
 static unsigned char atkbd_set2_keycode[512] = {
 
+#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
+
+/* XXX: need a more general approach */
+
+#include "hpps2atkbd.h"	/* include the keyboard scancodes */
+
+#else
 	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
 	  0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
 	  0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
@@ -96,9 +99,8 @@
 	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
 
 	  0,  0,  0, 65, 99,
-};
-
 #endif
+};
 
 static unsigned char atkbd_set3_keycode[512] = {
 
@@ -141,7 +143,6 @@
 #define ATKBD_CMD_EX_SETLEDS	0x20eb
 #define ATKBD_CMD_OK_GETID	0x02e8
 
-
 #define ATKBD_RET_ACK		0xfa
 #define ATKBD_RET_NAK		0xfe
 #define ATKBD_RET_BAT		0xaa
@@ -160,15 +161,22 @@
 #define ATKBD_SCR_4		252
 #define ATKBD_SCR_8		251
 #define ATKBD_SCR_CLICK		250
+#define ATKBD_SCR_LEFT		249
+#define ATKBD_SCR_RIGHT		248
 
-#define ATKBD_SPECIAL		250
+#define ATKBD_SPECIAL		248
 
-static unsigned char atkbd_scroll_keys[5][2] = {
-	{ ATKBD_SCR_1,     0x45 },
-	{ ATKBD_SCR_2,     0x29 },
-	{ ATKBD_SCR_4,     0x36 },
-	{ ATKBD_SCR_8,     0x27 },
-	{ ATKBD_SCR_CLICK, 0x60 },
+static struct {
+	unsigned char keycode;
+	unsigned char set2;
+} atkbd_scroll_keys[] = {
+	{ ATKBD_SCR_1,     0xc5 },
+	{ ATKBD_SCR_2,     0xa9 },
+	{ ATKBD_SCR_4,     0xb6 },
+	{ ATKBD_SCR_8,     0xa7 },
+	{ ATKBD_SCR_CLICK, 0xe0 },
+	{ ATKBD_SCR_LEFT,  0xcb },
+	{ ATKBD_SCR_RIGHT, 0xd2 },
 };
 
 /*
@@ -249,9 +257,9 @@
 static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
 			unsigned int flags, struct pt_regs *regs)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 	unsigned int code = data;
-	int scroll = 0, click = -1;
+	int scroll = 0, hscroll = 0, click = -1;
 	int value;
 
 #ifdef ATKBD_DEBUG
@@ -370,6 +378,12 @@
 		case ATKBD_SCR_CLICK:
 			click = !atkbd->release;
 			break;
+		case ATKBD_SCR_LEFT:
+			hscroll = -1;
+			break;
+		case ATKBD_SCR_RIGHT:
+			hscroll = 1;
+			break;
 		default:
 			value = atkbd->release ? 0 :
 				(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
@@ -380,7 +394,7 @@
 					break;
 				case 1:
 					atkbd->last = code;
-					atkbd->time = jiffies + (atkbd->dev.rep[REP_DELAY] * HZ + 500) / 1000 / 2;
+					atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev.rep[REP_DELAY]) / 2;
 					break;
 				case 2:
 					if (!time_after(jiffies, atkbd->time) && atkbd->last == code)
@@ -391,10 +405,12 @@
 			atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);
 	}
 
-	if (scroll || click != -1) {
+	if (atkbd->scroll) {
 		input_regs(&atkbd->dev, regs);
-		input_report_key(&atkbd->dev, BTN_MIDDLE, click);
+		if (click != -1)
+			input_report_key(&atkbd->dev, BTN_MIDDLE, click);
 		input_report_rel(&atkbd->dev, REL_WHEEL, scroll);
+		input_report_rel(&atkbd->dev, REL_HWHEEL, hscroll);
 		input_sync(&atkbd->dev);
 	}
 
@@ -403,7 +419,6 @@
 	return IRQ_HANDLED;
 }
 
-
 /*
  * Event callback from the input module. Events that change the state of
  * the hardware are processed here.
@@ -647,7 +662,7 @@
 
 static void atkbd_cleanup(struct serio *serio)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
 }
 
@@ -658,7 +673,7 @@
 
 static void atkbd_disconnect(struct serio *serio)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 
 	atkbd_disable(atkbd);
 
@@ -674,6 +689,7 @@
 
 	input_unregister_device(&atkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(atkbd);
 }
 
@@ -694,12 +710,9 @@
 			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
 			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
 			if (atkbd->scroll)
-				for (j = 0; i < 5; i++) {
-					if (atkbd_unxlate_table[i] == atkbd_scroll_keys[j][1])
-						atkbd->keycode[i] = atkbd_scroll_keys[j][0];
-					if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j][1])
-						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j][0];
-				}
+				for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
+					if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2)
+						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
 		}
 	} else if (atkbd->set == 3) {
 		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
@@ -707,8 +720,8 @@
 		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
 
 		if (atkbd->scroll)
-			for (i = 0; i < 5; i++)
-				atkbd->keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
+			for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
+				atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
 	}
 }
 
@@ -754,7 +767,7 @@
 
 	if (atkbd->scroll) {
 		atkbd->dev.evbit[0] |= BIT(EV_REL);
-		atkbd->dev.relbit[0] = BIT(REL_WHEEL);
+		atkbd->dev.relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL);
 		set_bit(BTN_MIDDLE, atkbd->dev.keybit);
 	}
 
@@ -768,23 +781,25 @@
 }
 
 /*
- * atkbd_connect() is called when the serio module finds and interface
+ * atkbd_connect() is called when the serio module finds an interface
  * that isn't handled yet by an appropriate device driver. We check if
  * there is an AT keyboard out there and if yes, we register ourselves
  * to the input module.
  */
 
-static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct atkbd *atkbd;
+	int err;
 
 	if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
-		return;
+		return - ENOMEM;
+
 	memset(atkbd, 0, sizeof(struct atkbd));
 
 	ps2_init(&atkbd->ps2dev, serio);
 
-	switch (serio->type & SERIO_TYPE) {
+	switch (serio->id.type) {
 
 		case SERIO_8042_XL:
 			atkbd->translated = 1;
@@ -792,12 +807,6 @@
 			if (serio->write)
 				atkbd->write = 1;
 			break;
-		case SERIO_RS232:
-			if ((serio->type & SERIO_PROTO) == SERIO_PS2SER)
-				break;
-		default:
-			kfree(atkbd);
-			return;
 	}
 
 	atkbd->softraw = atkbd_softraw;
@@ -810,20 +819,22 @@
 	if (atkbd->softrepeat)
 		atkbd->softraw = 1;
 
-	serio->private = atkbd;
+	serio_set_drvdata(serio, atkbd);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(atkbd);
-		return;
+		return err;
 	}
 
 	if (atkbd->write) {
 
 		if (atkbd_probe(atkbd)) {
 			serio_close(serio);
-			serio->private = NULL;
+			serio_set_drvdata(serio, NULL);
 			kfree(atkbd);
-			return;
+			return -ENODEV;
 		}
 
 		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
@@ -856,6 +867,8 @@
 	atkbd_enable(atkbd);
 
 	printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
+
+	return 0;
 }
 
 /*
@@ -865,7 +878,7 @@
 
 static int atkbd_reconnect(struct serio *serio)
 {
-	struct atkbd *atkbd = serio->private;
+	struct atkbd *atkbd = serio_get_drvdata(serio);
 	struct serio_driver *drv = serio->drv;
 	unsigned char param[1];
 
@@ -897,11 +910,36 @@
 	return 0;
 }
 
+static struct serio_device_id atkbd_serio_ids[] = {
+	{
+		.type	= SERIO_8042,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_8042_XL,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_PS2SER,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
+
 static struct serio_driver atkbd_drv = {
 	.driver		= {
 		.name	= "atkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= atkbd_serio_ids,
 	.interrupt	= atkbd_interrupt,
 	.connect	= atkbd_connect,
 	.reconnect	= atkbd_reconnect,
@@ -924,7 +962,7 @@
 		goto out;
 	}
 
-	retval = handler((struct atkbd *)serio->private, buf);
+	retval = handler((struct atkbd *)serio_get_drvdata(serio), buf);
 
 out:
 	serio_unpin_driver(serio);
@@ -947,7 +985,7 @@
 		goto out;
 	}
 
-	atkbd = serio->private;
+	atkbd = serio_get_drvdata(serio);
 	atkbd_disable(atkbd);
 	retval = handler(atkbd, buf, count);
 	atkbd_enable(atkbd);
@@ -1095,13 +1133,13 @@
 }
 
 
-int __init atkbd_init(void)
+static int __init atkbd_init(void)
 {
 	serio_register_driver(&atkbd_drv);
 	return 0;
 }
 
-void __exit atkbd_exit(void)
+static void __exit atkbd_exit(void)
 {
 	serio_unregister_driver(&atkbd_drv);
 }
diff -Nru a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/keyboard/corgikbd.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,361 @@
+/*
+ *  Keyboard driver for Sharp Corgi models (SL-C7xx)
+ *
+ *  Copyright (c) 2004-2005 Richard Purdie
+ *
+ *  Based on xtkbd.c/locomkbd.c
+ *
+ *  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/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+
+#include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware/scoop.h>
+
+#define KB_ROWS				8
+#define KB_COLS				12
+#define KB_ROWMASK(r)		(1 << (r))
+#define SCANCODE(r,c)		( ((r)<<4) + (c) + 1 )
+/* zero code, 124 scancodes + 3 hinge combinations */
+#define	NR_SCANCODES		( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 )
+#define SCAN_INTERVAL		(HZ/10)
+#define CORGIKBD_PRESSED	1
+
+#define HINGE_SCAN_INTERVAL		(HZ/4)
+
+#define CORGI_KEY_CALENDER	KEY_F1
+#define CORGI_KEY_ADDRESS	KEY_F2
+#define CORGI_KEY_FN		KEY_F3
+#define CORGI_KEY_OFF		KEY_SUSPEND
+#define CORGI_KEY_EXOK		KEY_F5
+#define CORGI_KEY_EXCANCEL	KEY_F6
+#define CORGI_KEY_EXJOGDOWN	KEY_F7
+#define CORGI_KEY_EXJOGUP	KEY_F8
+#define CORGI_KEY_JAP1		KEY_LEFTCTRL
+#define CORGI_KEY_JAP2		KEY_LEFTALT
+#define CORGI_KEY_OK		KEY_F11
+#define CORGI_KEY_MENU		KEY_F12
+#define CORGI_HINGE_0		KEY_KP0
+#define CORGI_HINGE_1		KEY_KP1
+#define CORGI_HINGE_2		KEY_KP2
+
+static unsigned char corgikbd_keycode[NR_SCANCODES] = {
+	0,                                                                                                                /* 0 */
+	0, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, 0, 0, 0, 0, 0, 0, 0, 	                      /* 1-16 */
+	0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, 0, 0, 0, 0, 0, 0, 0,                                   /* 17-32 */
+	KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
+	CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,         /* 49-64 */
+	CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 	  /* 65-80 */
+	KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
+	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
+	CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
+	CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2	  /* 125-127 */
+};
+
+
+struct corgikbd {
+	unsigned char keycode[ARRAY_SIZE(corgikbd_keycode)];
+	struct input_dev input;
+	char phys[32];
+
+	unsigned char state[ARRAY_SIZE(corgikbd_keycode)];
+	spinlock_t lock;
+
+	struct timer_list timer;
+	struct timer_list htimer;
+};
+
+static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data)
+{
+	if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) {
+		corgikbd_data->state[scancode] |= CORGIKBD_PRESSED;
+		input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1);
+		if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
+			input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
+	} else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) {
+		corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED;
+		input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0);
+	}
+}
+
+#define KB_DISCHARGE_DELAY	10
+#define KB_ACTIVATE_DELAY	10
+
+/* Helper functions for reading the keyboard matrix
+ * Note: We should really be using pxa_gpio_mode to alter GPDR but it
+ *       requires a function call per GPIO bit which is excessive
+ *       when we need to access 12 bits at once multiple times.
+ * These functions must be called within local_irq_save()/local_irq_restore()
+ * or similar.
+ */
+static inline void corgikbd_discharge_all(void)
+{
+	// STROBE All HiZ
+	GPCR2  = CORGI_GPIO_ALL_STROBE_BIT;
+	GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT;
+}
+
+static inline void corgikbd_activate_all(void)
+{
+	// STROBE ALL -> High
+	GPSR2  = CORGI_GPIO_ALL_STROBE_BIT;
+	GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT;
+
+	udelay(KB_DISCHARGE_DELAY);
+
+	// Clear any interrupts we may have triggered when altering the GPIO lines
+	GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT;
+	GEDR2 = CORGI_GPIO_LOW_SENSE_BIT;
+}
+
+static inline void corgikbd_activate_col(int col)
+{
+	// STROBE col -> High, not col -> HiZ
+	GPSR2 = CORGI_GPIO_STROBE_BIT(col);
+	GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
+}
+
+static inline void corgikbd_reset_col(int col)
+{
+	// STROBE col -> Low
+	GPCR2 = CORGI_GPIO_STROBE_BIT(col);
+	// STROBE col -> out, not col -> HiZ
+	GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
+}
+
+#define GET_ROWS_STATUS(c)	(((GPLR1 & CORGI_GPIO_HIGH_SENSE_BIT) >> CORGI_GPIO_HIGH_SENSE_RSHIFT) | ((GPLR2 & CORGI_GPIO_LOW_SENSE_BIT) << CORGI_GPIO_LOW_SENSE_LSHIFT))
+
+/*
+ * The corgi keyboard only generates interrupts when a key is pressed.
+ * When a key is pressed, we enable a timer which then scans the
+ * keyboard to detect when the key is released.
+ */
+
+/* Scan the hardware keyboard and push any changes up through the input layer */
+static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs)
+{
+	unsigned int row, col, rowd, scancode;
+	unsigned long flags;
+	unsigned int num_pressed;
+
+	spin_lock_irqsave(&corgikbd_data->lock, flags);
+
+	if (regs)
+		input_regs(&corgikbd_data->input, regs);
+
+	num_pressed = 0;
+	for (col = 0; col < KB_COLS; col++) {
+		/*
+		 * Discharge the output driver capacitatance
+		 * in the keyboard matrix. (Yes it is significant..)
+		 */
+
+		corgikbd_discharge_all();
+		udelay(KB_DISCHARGE_DELAY);
+
+		corgikbd_activate_col(col);
+		udelay(KB_ACTIVATE_DELAY);
+
+		rowd = GET_ROWS_STATUS(col);
+		for (row = 0; row < KB_ROWS; row++) {
+			scancode = SCANCODE(row, col);
+			handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data);
+			if (rowd & KB_ROWMASK(row))
+				num_pressed++;
+		}
+		corgikbd_reset_col(col);
+	}
+
+	corgikbd_activate_all();
+
+	input_sync(&corgikbd_data->input);
+
+	/* if any keys are pressed, enable the timer */
+	if (num_pressed)
+		mod_timer(&corgikbd_data->timer, jiffies + SCAN_INTERVAL);
+
+	spin_unlock_irqrestore(&corgikbd_data->lock, flags);
+}
+
+/*
+ * corgi keyboard interrupt handler.
+ */
+static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct corgikbd *corgikbd_data = dev_id;
+
+	if (!timer_pending(&corgikbd_data->timer)) {
+		/** wait chattering delay **/
+		udelay(20);
+		corgikbd_scankeyboard(corgikbd_data, regs);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * corgi timer checking for released keys
+ */
+static void corgikbd_timer_callback(unsigned long data)
+{
+	struct corgikbd *corgikbd_data = (struct corgikbd *) data;
+	corgikbd_scankeyboard(corgikbd_data, NULL);
+}
+
+/*
+ * The hinge switches generate no interrupt so they need to be
+ * monitored by a timer.
+ *
+ * When we detect changes, we debounce it and then pass the three
+ * positions the system can take as keypresses to the input system.
+ */
+
+#define HINGE_STABLE_COUNT 2
+static int sharpsl_hinge_state;
+static int hinge_count;
+
+static void corgikbd_hinge_timer(unsigned long data)
+{
+	struct corgikbd *corgikbd_data = (struct corgikbd *) data;
+	unsigned long gprr;
+	unsigned long flags;
+
+	gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
+	if (gprr != sharpsl_hinge_state) {
+		hinge_count = 0;
+		sharpsl_hinge_state = gprr;
+	} else if (hinge_count < HINGE_STABLE_COUNT) {
+		hinge_count++;
+		if (hinge_count >= HINGE_STABLE_COUNT) {
+			spin_lock_irqsave(&corgikbd_data->lock, flags);
+
+			handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */
+			handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */
+			handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed  */
+			input_sync(&corgikbd_data->input);
+
+			spin_unlock_irqrestore(&corgikbd_data->lock, flags);
+		}
+	}
+	mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL);
+}
+
+static int __init corgikbd_probe(struct device *dev)
+{
+	int i;
+	struct corgikbd *corgikbd;
+
+	corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL);
+	if (!corgikbd)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev,corgikbd);
+	strcpy(corgikbd->phys, "corgikbd/input0");
+
+	spin_lock_init(corgikbd->lock);
+
+	/* Init Keyboard rescan timer */
+	init_timer(&corgikbd->timer);
+	corgikbd->timer.function = corgikbd_timer_callback;
+	corgikbd->timer.data = (unsigned long) corgikbd;
+
+	/* Init Hinge Timer */
+	init_timer(&corgikbd->htimer);
+	corgikbd->htimer.function = corgikbd_hinge_timer;
+	corgikbd->htimer.data = (unsigned long) corgikbd;
+
+	init_input_dev(&corgikbd->input);
+	corgikbd->input.private = corgikbd;
+	corgikbd->input.name = "Corgi Keyboard";
+	corgikbd->input.dev = dev;
+	corgikbd->input.phys = corgikbd->phys;
+	corgikbd->input.id.bustype = BUS_HOST;
+	corgikbd->input.id.vendor = 0x0001;
+	corgikbd->input.id.product = 0x0001;
+	corgikbd->input.id.version = 0x0100;
+	corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR);
+	corgikbd->input.keycode = corgikbd->keycode;
+	corgikbd->input.keycodesize = sizeof(unsigned char);
+	corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode);
+
+	memcpy(corgikbd->keycode, corgikbd_keycode, sizeof(corgikbd->keycode));
+	for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++)
+		set_bit(corgikbd->keycode[i], corgikbd->input.keybit);
+	clear_bit(0, corgikbd->input.keybit);
+
+	input_register_device(&corgikbd->input);
+	mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL);
+
+	/* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
+	for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) {
+		pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN);
+		if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt,
+						SA_INTERRUPT, "corgikbd", corgikbd))
+			printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i);
+		else
+			set_irq_type(CORGI_IRQ_GPIO_KEY_SENSE(i),IRQT_RISING);
+	}
+
+	/* Set Strobe lines as outputs - set high */
+	for (i = 0; i < CORGI_KEY_STROBE_NUM; i++)
+		pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH);
+
+	printk(KERN_INFO "input: Corgi Keyboard Registered\n");
+
+	return 0;
+}
+
+static int corgikbd_remove(struct device *dev)
+{
+	int i;
+	struct corgikbd *corgikbd = dev_get_drvdata(dev);
+
+	for (i = 0; i < CORGI_KEY_SENSE_NUM; i++)
+		free_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd);
+
+	del_timer_sync(&corgikbd->htimer);
+	del_timer_sync(&corgikbd->timer);
+
+	input_unregister_device(&corgikbd->input);
+
+	kfree(corgikbd);
+
+	return 0;
+}
+
+static struct device_driver corgikbd_driver = {
+	.name		= "corgi-keyboard",
+	.bus		= &platform_bus_type,
+	.probe		= corgikbd_probe,
+	.remove		= corgikbd_remove,
+};
+
+static int __devinit corgikbd_init(void)
+{
+	return driver_register(&corgikbd_driver);
+}
+
+static void __exit corgikbd_exit(void)
+{
+	driver_unregister(&corgikbd_driver);
+}
+
+module_init(corgikbd_init);
+module_exit(corgikbd_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Corgi Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff -Nru a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/keyboard/hil_kbd.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,375 @@
+/*
+ * Generic linux-input device driver for keyboard devices
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ */
+
+#include <linux/hil.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+
+#define PREFIX "HIL KEYB: "
+#define HIL_GENERIC_NAME "HIL keyboard"
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define HIL_KBD_MAX_LENGTH 16
+
+#define HIL_KBD_SET1_UPBIT 0x01
+#define HIL_KBD_SET1_SHIFT 1
+static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] = 
+	{ HIL_KEYCODES_SET1 };
+
+#define HIL_KBD_SET2_UPBIT 0x01
+#define HIL_KBD_SET2_SHIFT 1
+/* Set2 is user defined */
+
+#define HIL_KBD_SET3_UPBIT 0x80
+#define HIL_KBD_SET3_SHIFT 0
+static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] =
+	{ HIL_KEYCODES_SET3 };
+
+static char hil_language[][16] = { HIL_LOCALE_MAP };
+
+struct hil_kbd {
+	struct input_dev dev;
+	struct serio *serio;
+
+	/* Input buffer and index for packets from HIL bus. */
+	hil_packet data[HIL_KBD_MAX_LENGTH];
+	int idx4; /* four counts per packet */
+
+	/* Raw device info records from HIL bus, see hil.h for fields. */
+	char	idd[HIL_KBD_MAX_LENGTH];	/* DID byte and IDD record */
+	char	rsc[HIL_KBD_MAX_LENGTH];	/* RSC record */
+	char	exd[HIL_KBD_MAX_LENGTH];	/* EXD record */
+	char	rnm[HIL_KBD_MAX_LENGTH + 1];	/* RNM record + NULL term. */
+
+	/* Something to sleep around with. */
+	struct semaphore sem;
+};
+
+/* Process a complete packet after transfer from the HIL */
+static void hil_kbd_process_record(struct hil_kbd *kbd)
+{
+	struct input_dev *dev = &kbd->dev;
+	hil_packet *data = kbd->data;
+	hil_packet p;
+	int idx, i, cnt;
+
+	idx = kbd->idx4/4;
+	p = data[idx - 1];
+
+	if ((p & ~HIL_CMDCT_POL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
+	if ((p & ~HIL_CMDCT_RPL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+
+	/* Not a poll response.  See if we are loading config records. */
+	switch (p & HIL_PKT_DATA_MASK) {
+	case HIL_CMD_IDD:
+		for (i = 0; i < idx; i++)
+			kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH; i++)
+			kbd->idd[i] = 0;
+		break;
+	case HIL_CMD_RSC:
+		for (i = 0; i < idx; i++)
+			kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH; i++)
+			kbd->rsc[i] = 0;
+		break;
+	case HIL_CMD_EXD:
+		for (i = 0; i < idx; i++)
+			kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH; i++)
+			kbd->exd[i] = 0;
+		break;
+	case HIL_CMD_RNM:
+		for (i = 0; i < idx; i++)
+			kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
+			kbd->rnm[i] = '\0';
+		break;
+	default:
+		/* These occur when device isn't present */
+		if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; 
+		/* Anything else we'd like to know about. */
+		printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
+		break;
+	}
+	goto out;
+
+ report:
+	cnt = 1;
+	switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
+	case HIL_POL_CHARTYPE_NONE:
+		break;
+	case HIL_POL_CHARTYPE_ASCII:
+		while (cnt < idx - 1)
+			input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
+		break;
+	case HIL_POL_CHARTYPE_RSVD1:
+	case HIL_POL_CHARTYPE_RSVD2:
+	case HIL_POL_CHARTYPE_BINARY:
+		while (cnt < idx - 1)
+			input_report_key(dev, kbd->data[cnt++], 1);
+		break;
+	case HIL_POL_CHARTYPE_SET1:
+		while (cnt < idx - 1) {
+			unsigned int key;
+			int up;
+			key = kbd->data[cnt++];
+			up = key & HIL_KBD_SET1_UPBIT;
+			key &= (~HIL_KBD_SET1_UPBIT & 0xff);
+			key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT];
+			if (key != KEY_RESERVED)
+				input_report_key(dev, key, !up);
+		}
+		break;
+	case HIL_POL_CHARTYPE_SET2:
+		while (cnt < idx - 1) {
+			unsigned int key;
+			int up;
+			key = kbd->data[cnt++];
+			up = key & HIL_KBD_SET2_UPBIT;
+			key &= (~HIL_KBD_SET1_UPBIT & 0xff);
+			key = key >> HIL_KBD_SET2_SHIFT;
+			if (key != KEY_RESERVED)
+				input_report_key(dev, key, !up);
+		}
+		break;
+	case HIL_POL_CHARTYPE_SET3:
+		while (cnt < idx - 1) {
+			unsigned int key;
+			int up;
+			key = kbd->data[cnt++];
+			up = key & HIL_KBD_SET3_UPBIT;
+			key &= (~HIL_KBD_SET1_UPBIT & 0xff);
+			key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT];
+			if (key != KEY_RESERVED)
+				input_report_key(dev, key, !up);
+		}
+		break;
+	}
+ out:
+	kbd->idx4 = 0;
+	up(&kbd->sem);
+}
+
+static void hil_kbd_process_err(struct hil_kbd *kbd) {
+	printk(KERN_WARNING PREFIX "errored HIL packet\n");
+	kbd->idx4 = 0;
+	up(&kbd->sem);
+}
+
+static irqreturn_t hil_kbd_interrupt(struct serio *serio, 
+	      unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct hil_kbd *kbd;
+	hil_packet packet;
+	int idx;
+
+	kbd = (struct hil_kbd *)serio->private;
+	if (kbd == NULL) {
+		BUG();
+		return IRQ_HANDLED;
+	}
+
+	if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
+		hil_kbd_process_err(kbd);
+		return IRQ_HANDLED;
+	}
+	idx = kbd->idx4/4;
+	if (!(kbd->idx4 % 4)) kbd->data[idx] = 0;
+	packet = kbd->data[idx];
+	packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
+	kbd->data[idx] = packet;
+
+	/* Records of N 4-byte hil_packets must terminate with a command. */
+	if ((++(kbd->idx4)) % 4) return IRQ_HANDLED;
+	if ((packet & 0xffff0000) != HIL_ERR_INT) {
+		hil_kbd_process_err(kbd);
+		return IRQ_HANDLED;
+	}
+	if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd);
+	return IRQ_HANDLED;
+}
+
+static void hil_kbd_disconnect(struct serio *serio)
+{
+	struct hil_kbd *kbd;
+
+	kbd = (struct hil_kbd *)serio->private;
+	if (kbd == NULL) {
+		BUG();
+		return;
+	}
+
+	input_unregister_device(&kbd->dev);
+	serio_close(serio);
+	kfree(kbd);
+}
+
+static void hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct hil_kbd	*kbd;
+	uint8_t		did, *idd;
+	int		i;
+	
+	if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return;
+
+	if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return;
+	memset(kbd, 0, sizeof(struct hil_kbd));
+
+	if (serio_open(serio, drv)) goto bail0;
+
+	serio->private = kbd;
+	kbd->serio = serio;
+	kbd->dev.private = kbd;
+
+	init_MUTEX_LOCKED(&(kbd->sem));
+
+	/* Get device info.  MLC driver supplies devid/status/etc. */
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_IDD);
+	down(&(kbd->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RSC);
+	down(&(kbd->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RNM);
+	down(&(kbd->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_EXD);
+	down(&(kbd->sem));
+
+	up(&(kbd->sem));
+
+	did = kbd->idd[0];
+	idd = kbd->idd + 1;
+	switch (did & HIL_IDD_DID_TYPE_MASK) {
+	case HIL_IDD_DID_TYPE_KB_INTEGRAL:
+	case HIL_IDD_DID_TYPE_KB_ITF:
+	case HIL_IDD_DID_TYPE_KB_RSVD:
+	case HIL_IDD_DID_TYPE_CHAR:
+		printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
+			did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
+		break;
+	default:
+		goto bail1;
+	}
+
+	if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
+		printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
+		goto bail1;
+	}
+
+
+	kbd->dev.evbit[0]	= BIT(EV_KEY) | BIT(EV_REP);
+	kbd->dev.ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	kbd->dev.keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
+	kbd->dev.keycodesize	= sizeof(hil_kbd_set1[0]);
+	kbd->dev.keycode	= hil_kbd_set1;
+	kbd->dev.name		= strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
+	kbd->dev.phys		= "hpkbd/input0";	/* XXX */
+
+	kbd->dev.id.bustype	= BUS_HIL;
+	kbd->dev.id.vendor	= PCI_VENDOR_ID_HP;
+	kbd->dev.id.product	= 0x0001; /* TODO: get from kbd->rsc */
+	kbd->dev.id.version	= 0x0100; /* TODO: get from kbd->rsc */
+	kbd->dev.dev		= &serio->dev;
+
+	for (i = 0; i < 128; i++) {
+		set_bit(hil_kbd_set1[i], kbd->dev.keybit);
+		set_bit(hil_kbd_set3[i], kbd->dev.keybit);
+	}
+	clear_bit(0, kbd->dev.keybit);
+
+	input_register_device(&kbd->dev);
+	printk(KERN_INFO "input: %s, ID: %d\n",
+		kbd->dev.name, did);
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
+	down(&(kbd->sem));
+	up(&(kbd->sem));
+
+	return;
+ bail1:
+	serio_close(serio);
+ bail0:
+	kfree(kbd);
+}
+
+
+struct serio_driver hil_kbd_serio_drv = {
+	.driver		= {
+		.name	= "hil_kbd",
+	},
+	.description	= "HP HIL keyboard driver",
+	.connect 	= hil_kbd_connect,
+	.disconnect 	= hil_kbd_disconnect,
+	.interrupt 	= hil_kbd_interrupt
+};
+
+static int __init hil_kbd_init(void)
+{
+	serio_register_driver(&hil_kbd_serio_drv);
+        return 0;
+}
+                
+static void __exit hil_kbd_exit(void)
+{
+	serio_unregister_driver(&hil_kbd_serio_drv);
+}
+                        
+module_init(hil_kbd_init);
+module_exit(hil_kbd_exit);
diff -Nru a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/keyboard/hilkbd.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,343 @@
+/*
+ *  linux/drivers/hil/hilkbd.c
+ *
+ *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
+ *  Copyright (C) 1999-2003 Helge Deller <deller@gmx.de>
+ *
+ *  Very basic HP Human Interface Loop (HIL) driver.
+ *  This driver handles the keyboard on HP300 (m68k) and on some 
+ *  HP700 (parisc) series machines.
+ *
+ * 
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2.  See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/pci_ids.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/hil.h>
+#include <linux/spinlock.h>
+
+
+MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller");
+MODULE_DESCRIPTION("HIL keyboard driver (basic functionality)");
+MODULE_LICENSE("GPL v2");
+
+
+#if defined(CONFIG_PARISC)
+
+ #include <asm/io.h>
+ #include <asm/hardware.h>
+ #include <asm/parisc-device.h>
+ static unsigned long hil_base;	/* HPA for the HIL device */
+ static unsigned int hil_irq;
+ #define HILBASE		hil_base /* HPPA (parisc) port address */
+ #define HIL_DATA		0x800
+ #define HIL_CMD		0x801
+ #define HIL_IRQ		hil_irq
+ #define hil_readb(p)		gsc_readb(p)
+ #define hil_writeb(v,p)	gsc_writeb((v),(p))
+
+#elif defined(CONFIG_HP300)
+
+ #define HILBASE		0xf0428000 /* HP300 (m86k) port address */
+ #define HIL_DATA		0x1
+ #define HIL_CMD		0x3
+ #define HIL_IRQ		2
+ #define hil_readb(p)		readb(p)
+ #define hil_writeb(v,p)	writeb((v),(p))
+
+#else
+#error "HIL is not supported on this platform"
+#endif
+
+
+ 
+/* HIL helper functions */
+ 
+#define hil_busy()              (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)
+#define hil_data_available()    (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
+#define hil_status()            (hil_readb(HILBASE + HIL_CMD))
+#define hil_command(x)          do { hil_writeb((x), HILBASE + HIL_CMD); } while (0)
+#define hil_read_data()         (hil_readb(HILBASE + HIL_DATA))
+#define hil_write_data(x)       do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)
+
+/* HIL constants */
+ 
+#define	HIL_BUSY		0x02
+#define	HIL_DATA_RDY		0x01
+
+#define	HIL_SETARD		0xA0		/* set auto-repeat delay */
+#define	HIL_SETARR		0xA2		/* set auto-repeat rate */
+#define	HIL_SETTONE		0xA3		/* set tone generator */
+#define	HIL_CNMT		0xB2		/* clear nmi */
+#define	HIL_INTON		0x5C		/* Turn on interrupts. */
+#define	HIL_INTOFF		0x5D		/* Turn off interrupts. */
+
+#define	HIL_READKBDSADR	 	0xF9
+#define	HIL_WRITEKBDSADR 	0xE9
+
+static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = 
+	{ HIL_KEYCODES_SET1 };
+
+/* HIL structure */
+static struct {
+	struct input_dev dev;
+
+	unsigned int curdev;
+	
+	unsigned char s;
+	unsigned char c;
+	int valid;
+	
+	unsigned char data[16];
+	unsigned int ptr;
+	spinlock_t lock;
+
+	void *dev_id;	/* native bus device */
+} hil_dev;
+
+
+static void poll_finished(void)
+{
+	int down;
+	int key;
+	unsigned char scode;
+	
+	switch (hil_dev.data[0]) {
+	case 0x40:
+		down = (hil_dev.data[1] & 1) == 0;
+		scode = hil_dev.data[1] >> 1;
+		key = hphilkeyb_keycode[scode];
+		input_report_key(&hil_dev.dev, key, down);
+		break;
+	}
+	hil_dev.curdev = 0;
+}
+
+static inline void handle_status(unsigned char s, unsigned char c)
+{
+	if (c & 0x8) {
+		/* End of block */
+		if (c & 0x10)
+			poll_finished();
+	} else {
+		if (c & 0x10) {
+			if (hil_dev.curdev)
+				poll_finished();  /* just in case */
+			hil_dev.curdev = c & 7;
+			hil_dev.ptr = 0;
+		}
+	}
+}
+
+static inline void handle_data(unsigned char s, unsigned char c)
+{
+	if (hil_dev.curdev) {
+		hil_dev.data[hil_dev.ptr++] = c;
+		hil_dev.ptr &= 15;
+	}
+}
+
+
+/* 
+ * Handle HIL interrupts.
+ */
+static irqreturn_t hil_interrupt(int irq, void *handle, struct pt_regs *regs)
+{
+	unsigned char s, c;
+	
+	s = hil_status();
+	c = hil_read_data();
+
+	switch (s >> 4) {
+	case 0x5:
+		handle_status(s, c);
+		break;
+	case 0x6:
+		handle_data(s, c);
+		break;
+	case 0x4:
+		hil_dev.s = s;
+		hil_dev.c = c;
+		mb();
+		hil_dev.valid = 1;
+		break;
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * Send a command to the HIL
+ */
+
+static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hil_dev.lock, flags);
+	while (hil_busy())
+		/* wait */;
+	hil_command(cmd);
+	while (len--) {
+		while (hil_busy())
+			/* wait */;
+		hil_write_data(*(data++));
+	}
+	spin_unlock_irqrestore(&hil_dev.lock, flags);
+}
+
+
+/*
+ * Initialise HIL. 
+ */
+
+static int __init
+hil_keyb_init(void)
+{
+	unsigned char c;
+	unsigned int i, kbid;
+	wait_queue_head_t hil_wait;
+
+	if (hil_dev.dev.id.bustype) {
+		return -ENODEV; /* already initialized */
+	}
+	
+#if defined(CONFIG_HP300)
+	if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
+		return -ENODEV;
+	
+	request_region(HILBASE+HIL_DATA, 2, "hil");
+#endif
+	
+	request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+
+	/* Turn on interrupts */
+	hil_do(HIL_INTON, NULL, 0);
+
+	/* Look for keyboards */
+	hil_dev.valid = 0;	/* clear any pending data */
+	hil_do(HIL_READKBDSADR, NULL, 0);
+
+	init_waitqueue_head(&hil_wait);
+	wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ);
+	if (!hil_dev.valid) {
+		printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n");
+	}
+
+	c = hil_dev.c; 
+	hil_dev.valid = 0;
+	if (c == 0) {
+		kbid = -1;
+		printk(KERN_WARNING "HIL: no keyboard present.\n");
+	} else {
+		kbid = ffz(~c);
+		/* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */
+	}
+
+	/* set it to raw mode */
+	c = 0;
+	hil_do(HIL_WRITEKBDSADR, &c, 1);
+	
+	init_input_dev(&hil_dev.dev);
+
+	for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
+		if (hphilkeyb_keycode[i] != KEY_RESERVED)
+			set_bit(hphilkeyb_keycode[i], hil_dev.dev.keybit);
+
+	hil_dev.dev.evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
+	hil_dev.dev.ledbit[0]   = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	hil_dev.dev.keycodemax  = HIL_KEYCODES_SET1_TBLSIZE;
+        hil_dev.dev.keycodesize = sizeof(hphilkeyb_keycode[0]);
+	hil_dev.dev.keycode     = hphilkeyb_keycode;
+	hil_dev.dev.name 	= "HIL keyboard";
+	hil_dev.dev.phys 	= "hpkbd/input0";
+
+	hil_dev.dev.id.bustype	= BUS_HIL;
+	hil_dev.dev.id.vendor	= PCI_VENDOR_ID_HP;
+	hil_dev.dev.id.product	= 0x0001;
+	hil_dev.dev.id.version	= 0x0010;
+
+	input_register_device(&hil_dev.dev);
+	printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
+		hil_dev.dev.name, kbid, HILBASE, HIL_IRQ);
+
+	return 0;
+}
+
+#if defined(CONFIG_PARISC)
+static int __init
+hil_init_chip(struct parisc_device *dev)
+{
+	if (!dev->irq) {
+		printk(KERN_WARNING "HIL: IRQ not found for HIL bus at 0x%08lx\n", dev->hpa);
+		return -ENODEV;
+	}
+
+	hil_base = dev->hpa;
+	hil_irq  = dev->irq;
+	hil_dev.dev_id = dev;
+	
+	printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq);
+
+	return hil_keyb_init();
+}
+
+static struct parisc_device_id hil_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, hil_tbl);
+
+static struct parisc_driver hil_driver = {
+	.name =		"HIL",
+	.id_table =	hil_tbl,
+	.probe =	hil_init_chip,
+};
+#endif /* CONFIG_PARISC */
+
+
+
+
+
+static int __init hil_init(void)
+{
+#if defined(CONFIG_PARISC)
+	return register_parisc_driver(&hil_driver);
+#else
+	return hil_keyb_init();
+#endif
+}
+
+
+static void __exit hil_exit(void)
+{
+	if (HIL_IRQ) {
+		disable_irq(HIL_IRQ);
+		free_irq(HIL_IRQ, hil_dev.dev_id);
+	}
+
+	/* Turn off interrupts */
+	hil_do(HIL_INTOFF, NULL, 0);
+
+	input_unregister_device(&hil_dev.dev);
+
+#if defined(CONFIG_PARISC)
+	unregister_parisc_driver(&hil_driver);
+#else
+	release_region(HILBASE+HIL_DATA, 2);
+#endif
+}
+
+module_init(hil_init);
+module_exit(hil_exit);
+
diff -Nru a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h
--- a/drivers/input/keyboard/hpps2atkbd.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/hpps2atkbd.h	2005-03-07 15:26:30 -08:00
@@ -14,10 +14,8 @@
  */
 
 
-/* undefine if you have a RDI PRECISIONBOOK */
-#define STANDARD_KEYBOARD
-
-#if defined(STANDARD_KEYBOARD)
+/* Is the keyboard an RDI PrecisionBook? */
+#ifndef CONFIG_KEYBOARD_ATKBD_RDI_KEYCODES
 # define CONFLICT(x,y) x
 #else
 # define CONFLICT(x,y) y
@@ -50,10 +48,10 @@
 /* 60 */  KEY_DOWN,     C_61,          KEY_PAUSE,     KEY_UP,        KEY_DELETE,    KEY_END,      KEY_BACKSPACE, KEY_INSERT,
 /* 68 */  KEY_RESERVED, KEY_KP1,       KEY_RIGHT,     KEY_KP4,       KEY_KP7,       KEY_PAGEDOWN, KEY_HOME,      KEY_PAGEUP,
 /* 70 */  KEY_KP0,      KEY_KPDOT,     KEY_KP2,       KEY_KP5,       KEY_KP6,       KEY_KP8,      KEY_ESC,       KEY_NUMLOCK,
-/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_103RD,
+/* 78 */  KEY_F11,      KEY_KPPLUS,    KEY_KP3,       KEY_KPMINUS,   KEY_KPASTERISK,KEY_KP9,      KEY_SCROLLLOCK,KEY_102ND,
 /* 80 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
 /* 88 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
-/* 90 */  KEY_RESERVED, KEY_RIGHTALT,  KEY_SYSRQ,     KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
+/* 90 */  KEY_RESERVED, KEY_RIGHTALT,  255,           KEY_RESERVED,  KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
 /* 98 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_CAPSLOCK, KEY_RESERVED,  KEY_LEFTMETA,
 /* a0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RIGHTMETA,
 /* a8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_COMPOSE,
@@ -103,7 +101,6 @@
 /* f0 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,
 /* f8 */  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED,  KEY_RESERVED, KEY_RESERVED,  KEY_RESERVED
 
-#undef STANDARD_KEYBOARD
 #undef CONFLICT
 #undef C_07
 #undef C_11
diff -Nru a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
--- a/drivers/input/keyboard/lkkbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/lkkbd.c	2005-03-07 15:26:30 -08:00
@@ -14,14 +14,14 @@
  * DISCLAIMER: This works for _me_. If you break anything by using the
  * information given below, I will _not_ be liable!
  *
- * RJ11 pinout:		To DE9:		Or DB25:
+ * RJ10 pinout:		To DE9:		Or DB25:
  * 	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
  * 	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
  * 	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
  * 	3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
  *
  * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
- * RJ11, it's like this:
+ * RJ10, it's like this:
  *
  *      __=__	Hold the plug in front of you, cable downwards,
  *     /___/|	nose is hidden behind the plug. Now, pin 1 is at
@@ -417,7 +417,7 @@
 lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
 		struct pt_regs *regs)
 {
-	struct lkkbd *lk = serio->private;
+	struct lkkbd *lk = serio_get_drvdata (serio);
 	int i;
 
 	DBG (KERN_INFO "Got byte 0x%02x\n", data);
@@ -623,19 +623,16 @@
 /*
  * lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
  */
-static void
+static int
 lkkbd_connect (struct serio *serio, struct serio_driver *drv)
 {
 	struct lkkbd *lk;
 	int i;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-	if ((serio->type & SERIO_PROTO) != SERIO_LKKBD)
-		return;
+	int err;
 
 	if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
+
 	memset (lk, 0, sizeof (struct lkkbd));
 
 	init_input_dev (&lk->dev);
@@ -665,11 +662,13 @@
 	lk->dev.event = lkkbd_event;
 	lk->dev.private = lk;
 
-	serio->private = lk;
+	serio_set_drvdata (serio, lk);
 
-	if (serio_open (serio, drv)) {
+	err = serio_open (serio, drv);
+	if (err) {
+		serio_set_drvdata (serio, NULL);
 		kfree (lk);
-		return;
+		return err;
 	}
 
 	sprintf (lk->name, "DEC LK keyboard");
@@ -691,6 +690,8 @@
 
 	printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys);
 	lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
+
+	return 0;
 }
 
 /*
@@ -699,18 +700,32 @@
 static void
 lkkbd_disconnect (struct serio *serio)
 {
-	struct lkkbd *lk = serio->private;
+	struct lkkbd *lk = serio_get_drvdata (serio);
 
 	input_unregister_device (&lk->dev);
 	serio_close (serio);
+	serio_set_drvdata (serio, NULL);
 	kfree (lk);
 }
 
+static struct serio_device_id lkkbd_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_LKKBD,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, lkkbd_serio_ids);
+
 static struct serio_driver lkkbd_drv = {
 	.driver		= {
 		.name	= "lkkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= lkkbd_serio_ids,
 	.connect	= lkkbd_connect,
 	.disconnect	= lkkbd_disconnect,
 	.interrupt	= lkkbd_interrupt,
@@ -719,14 +734,14 @@
 /*
  * The functions for insering/removing us as a module.
  */
-int __init
+static int __init
 lkkbd_init (void)
 {
 	serio_register_driver(&lkkbd_drv);
 	return 0;
 }
 
-void __exit
+static void __exit
 lkkbd_exit (void)
 {
 	serio_unregister_driver(&lkkbd_drv);
diff -Nru a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/keyboard/locomokbd.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,309 @@
+/*
+ *  Copyright (c) 2005 John Lenz
+ *
+ * Based on from xtkbd.c
+ */
+
+/*
+ * LoCoMo keyboard driver for Linux/ARM
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware/locomo.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_DESCRIPTION("LoCoMo keyboard driver");
+MODULE_LICENSE("GPL");
+
+#define LOCOMOKBD_NUMKEYS 	128
+
+#define KEY_ACTIVITY		KEY_F16
+#define KEY_CONTACT		KEY_F18
+#define KEY_CENTER		KEY_F15
+
+static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
+	0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,				/* 0 - 9 */
+	0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT,			/* 10 - 19 */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,						/* 20 - 29 */
+	0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,				/* 30 - 39 */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,					/* 40 - 49 */
+	KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T,		/* 50 - 59 */
+	KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0,			/* 60 - 69 */
+	KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0,	/* 70 - 79 */
+	0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J,		/* 80 - 89 */
+	KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
+	0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,		/* 100 - 109 */
+	KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,		/* 110 - 119 */
+	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 		/* 120 - 128 */
+};
+
+#define KB_ROWS			16
+#define KB_COLS			8
+#define KB_ROWMASK(r)		(1 << (r))
+#define SCANCODE(c,r)		( ((c)<<4) + (r) + 1 )
+#define	NR_SCANCODES		128
+
+#define KB_DELAY		8
+#define SCAN_INTERVAL		(HZ/10)
+#define LOCOMOKBD_PRESSED	1
+
+struct locomokbd {
+	unsigned char keycode[LOCOMOKBD_NUMKEYS];
+	struct input_dev input;
+	char phys[32];
+
+	struct locomo_dev *ldev;
+	unsigned long base;
+	spinlock_t lock;
+	
+	struct timer_list timer;
+};
+
+/* helper functions for reading the keyboard matrix */
+static inline void locomokbd_charge_all(unsigned long membase)
+{
+	locomo_writel(0x00FF, membase + LOCOMO_KSC);
+}
+
+static inline void locomokbd_activate_all(unsigned long membase)
+{
+	unsigned long r;
+	
+	locomo_writel(0, membase + LOCOMO_KSC);
+	r = locomo_readl(membase + LOCOMO_KIC);
+	r &= 0xFEFF;
+	locomo_writel(r, membase + LOCOMO_KIC);
+}
+
+static inline void locomokbd_activate_col(unsigned long membase, int col)
+{
+	unsigned short nset;
+	unsigned short nbset;
+
+	nset = 0xFF & ~(1 << col);
+	nbset = (nset << 8) + nset;
+	locomo_writel(nbset, membase + LOCOMO_KSC);
+}
+
+static inline void locomokbd_reset_col(unsigned long membase, int col)
+{
+	unsigned short nbset;
+
+	nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF;
+	locomo_writel(nbset, membase + LOCOMO_KSC);
+}
+
+/*
+ * The LoCoMo keyboard only generates interrupts when a key is pressed.
+ * So when a key is pressed, we enable a timer.  This timer scans the
+ * keyboard, and this is how we detect when the key is released.
+ */
+
+/* Scan the hardware keyboard and push any changes up through the input layer */
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs) 
+{
+	unsigned int row, col, rowd, scancode;
+	unsigned long flags;
+	unsigned int num_pressed;
+	unsigned long membase = locomokbd->base;
+
+	spin_lock_irqsave(&locomokbd->lock, flags);
+
+	if (regs)
+		input_regs(&locomokbd->input, regs);
+	
+	locomokbd_charge_all(membase);
+
+	num_pressed = 0;
+	for (col = 0; col < KB_COLS; col++) {
+
+		locomokbd_activate_col(membase, col);
+		udelay(KB_DELAY);
+		 
+		rowd = ~locomo_readl(membase + LOCOMO_KIB);
+		for (row = 0; row < KB_ROWS; row++ ) {
+			scancode = SCANCODE(col, row);
+			if (rowd & KB_ROWMASK(row)) {
+				num_pressed += 1;
+				input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 1);
+			} else {
+				input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 0);
+			}
+		}
+		locomokbd_reset_col(membase, col);
+	}
+	locomokbd_activate_all(membase);
+
+	input_sync(&locomokbd->input);
+
+	/* if any keys are pressed, enable the timer */
+	if (num_pressed)
+		mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
+
+	spin_unlock_irqrestore(&locomokbd->lock, flags);
+}
+
+/* 
+ * LoCoMo keyboard interrupt handler.
+ */
+static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct locomokbd *locomokbd = dev_id;
+	/** wait chattering delay **/
+	udelay(100);
+
+	locomokbd_scankeyboard(locomokbd, regs);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * LoCoMo timer checking for released keys
+ */
+static void locomokbd_timer_callback(unsigned long data)
+{
+	struct locomokbd *locomokbd = (struct locomokbd *) data;
+	locomokbd_scankeyboard(locomokbd, NULL);
+}
+
+static int locomokbd_probe(struct locomo_dev *dev)
+{
+	struct locomokbd *locomokbd;
+	int i, ret;
+
+	locomokbd = kmalloc(sizeof(struct locomokbd), GFP_KERNEL);
+	if (!locomokbd)
+		return -ENOMEM;
+
+	memset(locomokbd, 0, sizeof(struct locomokbd));
+
+	/* try and claim memory region */
+	if (!request_mem_region((unsigned long) dev->mapbase, 
+				dev->length, 
+				LOCOMO_DRIVER_NAME(dev))) {
+		ret = -EBUSY;
+		printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
+		goto free;
+	}
+
+	locomokbd->ldev = dev;
+	locomo_set_drvdata(dev, locomokbd);
+
+	locomokbd->base = (unsigned long) dev->mapbase;
+
+	spin_lock_init(&locomokbd->lock);
+
+	init_timer(&locomokbd->timer);
+	locomokbd->timer.function = locomokbd_timer_callback;
+	locomokbd->timer.data = (unsigned long) locomokbd;
+
+	locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	
+	init_input_dev(&locomokbd->input);
+	locomokbd->input.keycode = locomokbd->keycode;
+	locomokbd->input.keycodesize = sizeof(unsigned char);
+	locomokbd->input.keycodemax = ARRAY_SIZE(locomokbd_keycode);
+	locomokbd->input.private = locomokbd;
+
+	memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode));
+	for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
+		set_bit(locomokbd->keycode[i], locomokbd->input.keybit);
+	clear_bit(0, locomokbd->input.keybit);
+
+	strcpy(locomokbd->phys, "locomokbd/input0");
+
+	locomokbd->input.name = "LoCoMo keyboard";
+	locomokbd->input.phys = locomokbd->phys;
+	locomokbd->input.id.bustype = BUS_XTKBD;
+	locomokbd->input.id.vendor = 0x0001;
+	locomokbd->input.id.product = 0x0001;
+	locomokbd->input.id.version = 0x0100;
+
+	/* attempt to get the interrupt */
+	ret = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
+	if (ret) {
+		printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n");
+		goto out;
+	}
+
+	input_register_device(&locomokbd->input);
+
+	printk(KERN_INFO "input: LoCoMo keyboard on locomokbd\n");
+
+	return 0;
+
+out:
+	release_mem_region((unsigned long) dev->mapbase, dev->length);
+	locomo_set_drvdata(dev, NULL);
+free:
+	kfree(locomokbd);
+
+	return ret;
+}
+
+static int locomokbd_remove(struct locomo_dev *dev)
+{
+	struct locomokbd *locomokbd = locomo_get_drvdata(dev);
+	
+	free_irq(dev->irq[0], locomokbd);
+
+	del_timer_sync(&locomokbd->timer);
+	
+	input_unregister_device(&locomokbd->input);
+	locomo_set_drvdata(dev, NULL);
+
+	release_mem_region((unsigned long) dev->mapbase, dev->length);
+
+	kfree(locomokbd);
+
+	return 0;
+}
+
+static struct locomo_driver keyboard_driver = {
+	.drv = {
+		.name = "locomokbd"
+	},
+	.devid	= LOCOMO_DEVID_KEYBOARD,
+	.probe	= locomokbd_probe,
+	.remove	= locomokbd_remove,
+};
+
+static int __init locomokbd_init(void)
+{
+	return locomo_driver_register(&keyboard_driver);
+}
+
+static void __exit locomokbd_exit(void)
+{
+	locomo_driver_unregister(&keyboard_driver);
+}
+
+module_init(locomokbd_init);
+module_exit(locomokbd_exit);
diff -Nru a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
--- a/drivers/input/keyboard/newtonkbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/newtonkbd.c	2005-03-07 15:26:30 -08:00
@@ -66,10 +66,10 @@
 	char phys[32];
 };
 
-irqreturn_t nkbd_interrupt(struct serio *serio,
+static irqreturn_t nkbd_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct nkbd *nkbd = serio->private;
+	struct nkbd *nkbd = serio_get_drvdata(serio);
 
 	/* invalid scan codes are probably the init sequence, so we ignore them */
 	if (nkbd->keycode[data & NKBD_KEY]) {
@@ -84,16 +84,14 @@
 
 }
 
-void nkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct nkbd *nkbd;
 	int i;
-
-	if (serio->type != (SERIO_RS232 | SERIO_NEWTON))
-		return;
+	int err;
 
 	if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(nkbd, 0, sizeof(struct nkbd));
 
@@ -106,11 +104,14 @@
 	nkbd->dev.keycodesize = sizeof(unsigned char);
 	nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode);
 	nkbd->dev.private = nkbd;
-	serio->private = nkbd;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, nkbd);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(nkbd);
-		return;
+		return err;
 	}
 
 	memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
@@ -131,33 +132,50 @@
 	input_register_device(&nkbd->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
+
+	return 0;
 }
 
-void nkbd_disconnect(struct serio *serio)
+static void nkbd_disconnect(struct serio *serio)
 {
-	struct nkbd *nkbd = serio->private;
+	struct nkbd *nkbd = serio_get_drvdata(serio);
+
 	input_unregister_device(&nkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(nkbd);
 }
 
-struct serio_driver nkbd_drv = {
+static struct serio_device_id nkbd_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_NEWTON,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, nkbd_serio_ids);
+
+static struct serio_driver nkbd_drv = {
 	.driver		= {
 		.name	= "newtonkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= nkbd_serio_ids,
 	.interrupt	= nkbd_interrupt,
 	.connect	= nkbd_connect,
 	.disconnect	= nkbd_disconnect,
 };
 
-int __init nkbd_init(void)
+static int __init nkbd_init(void)
 {
 	serio_register_driver(&nkbd_drv);
 	return 0;
 }
 
-void __exit nkbd_exit(void)
+static void __exit nkbd_exit(void)
 {
 	serio_unregister_driver(&nkbd_drv);
 }
diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- a/drivers/input/keyboard/sunkbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/sunkbd.c	2005-03-07 15:26:30 -08:00
@@ -95,7 +95,7 @@
 static irqreturn_t sunkbd_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct sunkbd* sunkbd = serio->private;
+	struct sunkbd* sunkbd = serio_get_drvdata(serio);
 
 	if (sunkbd->reset <= -1) {		/* If cp[i] is 0xff, sunkbd->reset will stay -1. */
 		sunkbd->reset = data;		/* The keyboard sends 0xff 0xff 0xID on powerup */
@@ -223,19 +223,14 @@
  * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
  */
 
-static void sunkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct sunkbd *sunkbd;
 	int i;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-
-	if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD)
-		return;
+	int err;
 
 	if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(sunkbd, 0, sizeof(struct sunkbd));
 
@@ -257,17 +252,20 @@
 	sunkbd->dev.event = sunkbd_event;
 	sunkbd->dev.private = sunkbd;
 
-	serio->private = sunkbd;
+	serio_set_drvdata(serio, sunkbd);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(sunkbd);
-		return;
+		return err;
 	}
 
 	if (sunkbd_initialize(sunkbd) < 0) {
 		serio_close(serio);
+		serio_set_drvdata(serio, NULL);
 		kfree(sunkbd);
-		return;
+		return -ENODEV;
 	}
 
 	sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
@@ -290,6 +288,8 @@
 	input_register_device(&sunkbd->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys);
+
+	return 0;
 }
 
 /*
@@ -298,17 +298,37 @@
 
 static void sunkbd_disconnect(struct serio *serio)
 {
-	struct sunkbd *sunkbd = serio->private;
+	struct sunkbd *sunkbd = serio_get_drvdata(serio);
 	input_unregister_device(&sunkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(sunkbd);
 }
 
+static struct serio_device_id sunkbd_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SUNKBD,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_UNKNOWN, /* sunkbd does probe */
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
+
 static struct serio_driver sunkbd_drv = {
 	.driver		= {
 		.name	= "sunkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= sunkbd_serio_ids,
 	.interrupt	= sunkbd_interrupt,
 	.connect	= sunkbd_connect,
 	.disconnect	= sunkbd_disconnect,
@@ -318,13 +338,13 @@
  * The functions for insering/removing us as a module.
  */
 
-int __init sunkbd_init(void)
+static int __init sunkbd_init(void)
 {
 	serio_register_driver(&sunkbd_drv);
 	return 0;
 }
 
-void __exit sunkbd_exit(void)
+static void __exit sunkbd_exit(void)
 {
 	serio_unregister_driver(&sunkbd_drv);
 }
diff -Nru a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
--- a/drivers/input/keyboard/xtkbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/keyboard/xtkbd.c	2005-03-07 15:26:30 -08:00
@@ -65,10 +65,10 @@
 	char phys[32];
 };
 
-irqreturn_t xtkbd_interrupt(struct serio *serio,
+static irqreturn_t xtkbd_interrupt(struct serio *serio,
 	unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct xtkbd *xtkbd = serio->private;
+	struct xtkbd *xtkbd = serio_get_drvdata(serio);
 
 	switch (data) {
 		case XTKBD_EMUL0:
@@ -88,16 +88,14 @@
 	return IRQ_HANDLED;
 }
 
-void xtkbd_connect(struct serio *serio, struct serio_driver *drv)
+static int xtkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct xtkbd *xtkbd;
 	int i;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_XT)
-		return;
+	int err;
 
 	if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(xtkbd, 0, sizeof(struct xtkbd));
 
@@ -111,11 +109,13 @@
 	xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode);
 	xtkbd->dev.private = xtkbd;
 
-	serio->private = xtkbd;
+	serio_set_drvdata(serio, xtkbd);
 
-	if (serio_open(serio, drv)) {
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(xtkbd);
-		return;
+		return err;
 	}
 
 	memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode));
@@ -136,33 +136,50 @@
 	input_register_device(&xtkbd->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys);
+
+	return 0;
 }
 
-void xtkbd_disconnect(struct serio *serio)
+static void xtkbd_disconnect(struct serio *serio)
 {
-	struct xtkbd *xtkbd = serio->private;
+	struct xtkbd *xtkbd = serio_get_drvdata(serio);
+
 	input_unregister_device(&xtkbd->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(xtkbd);
 }
 
-struct serio_driver xtkbd_drv = {
+static struct serio_device_id xtkbd_serio_ids[] = {
+	{
+		.type	= SERIO_XT,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, xtkbd_serio_ids);
+
+static struct serio_driver xtkbd_drv = {
 	.driver		= {
 		.name	= "xtkbd",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= xtkbd_serio_ids,
 	.interrupt	= xtkbd_interrupt,
 	.connect	= xtkbd_connect,
 	.disconnect	= xtkbd_disconnect,
 };
 
-int __init xtkbd_init(void)
+static int __init xtkbd_init(void)
 {
 	serio_register_driver(&xtkbd_drv);
 	return 0;
 }
 
-void __exit xtkbd_exit(void)
+static void __exit xtkbd_exit(void)
 {
 	serio_unregister_driver(&xtkbd_drv);
 }
diff -Nru a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
--- a/drivers/input/misc/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/misc/Kconfig	2005-03-07 15:26:30 -08:00
@@ -1,9 +1,8 @@
 #
 # Input misc drivers configuration
 #
-config INPUT_MISC
-	bool "Misc"
-	depends on INPUT
+menuconfig INPUT_MISC
+	bool "Miscellaneous devices"
 	help
 	  Say Y here, and a list of miscellaneous input drivers will be displayed.
 	  Everything that didn't fit into the other categories is here. This option
@@ -11,9 +10,11 @@
 
 	  If unsure, say Y.
 
+if INPUT_MISC
+
 config INPUT_PCSPKR
 	tristate "PC Speaker support"
-	depends on (ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES) && INPUT && INPUT_MISC
+	depends on ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
 	help
 	  Say Y here if you want the standard PC Speaker to be used for
 	  bells and whistles.
@@ -25,7 +26,7 @@
 
 config INPUT_SPARCSPKR
 	tristate "SPARC Speaker support"
-	depends on (SPARC32 || SPARC64) && INPUT && INPUT_MISC && PCI
+	depends on PCI && (SPARC32 || SPARC64)
 	help
 	  Say Y here if you want the standard Speaker on Sparc PCI systems
 	  to be used for bells and whistles.
@@ -37,11 +38,10 @@
 
 config INPUT_M68K_BEEP
 	tristate "M68k Beeper support"
-	depends on M68K && INPUT && INPUT_MISC
+	depends on M68K
 
 config INPUT_UINPUT
 	tristate "User level driver support"
-	depends on INPUT && INPUT_MISC
 	help
 	  Say Y here if you want to support user level drivers for input
 	  subsystem accessible under char device 10:223 - /dev/input/uinput.
@@ -49,3 +49,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called uinput.
 
+config HP_SDC_RTC
+	tristate "HP SDC Real Time Clock"       
+	depends on GSC
+	select HP_SDC
+	help
+	  Say Y here if you want to support the built-in real time clock
+	  of the HP SDC controller.
+
+endif
diff -Nru a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
--- a/drivers/input/misc/Makefile	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/misc/Makefile	2005-03-07 15:26:30 -08:00
@@ -9,3 +9,4 @@
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
 obj-$(CONFIG_INPUT_98SPKR)		+= 98spkr.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
+obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
diff -Nru a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/misc/hp_sdc_rtc.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,724 @@
+/*
+ * HP i8042 SDC + MSM-58321 BBRTC driver.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ * References:
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ * efirtc.c by Stephane Eranian/Hewlett Packard
+ *
+ */
+
+#include <linux/hp_sdc.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/miscdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/rtc.h>
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("HP i8042 SDC + MSM-58321 RTC Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define RTC_VERSION "1.10d"
+
+static unsigned long epoch = 2000;
+
+static struct semaphore i8042tregs;
+
+static hp_sdc_irqhook hp_sdc_rtc_isr;
+
+static struct fasync_struct *hp_sdc_rtc_async_queue;
+
+static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait);
+
+static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin);
+
+static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
+			       size_t count, loff_t *ppos);
+
+static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
+			    unsigned int cmd, unsigned long arg);
+
+static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait);
+
+static int hp_sdc_rtc_open(struct inode *inode, struct file *file);
+static int hp_sdc_rtc_release(struct inode *inode, struct file *file);
+static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on);
+
+static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,
+				int count, int *eof, void *data);
+
+static void hp_sdc_rtc_isr (int irq, void *dev_id, 
+			    uint8_t status, uint8_t data) 
+{
+	return;
+}
+
+static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm)
+{
+	struct semaphore tsem;
+	hp_sdc_transaction t;
+	uint8_t tseq[91];
+	int i;
+	
+	i = 0;
+	while (i < 91) {
+		tseq[i++] = HP_SDC_ACT_DATAREG |
+			HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN;
+		tseq[i++] = 0x01;			/* write i8042[0x70] */
+	  	tseq[i]   = i / 7;			/* BBRTC reg address */
+		i++;
+		tseq[i++] = HP_SDC_CMD_DO_RTCR;		/* Trigger command   */
+		tseq[i++] = 2;		/* expect 1 stat/dat pair back.   */
+		i++; i++;               /* buffer for stat/dat pair       */
+	}
+	tseq[84] |= HP_SDC_ACT_SEMAPHORE;
+	t.endidx =		91;
+	t.seq =			tseq;
+	t.act.semaphore =	&tsem;
+	init_MUTEX_LOCKED(&tsem);
+	
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	
+	down_interruptible(&tsem);  /* Put ourselves to sleep for results. */
+	
+	/* Check for nonpresence of BBRTC */
+	if (!((tseq[83] | tseq[90] | tseq[69] | tseq[76] |
+	       tseq[55] | tseq[62] | tseq[34] | tseq[41] |
+	       tseq[20] | tseq[27] | tseq[6]  | tseq[13]) & 0x0f))
+		return -1;
+
+	memset(rtctm, 0, sizeof(struct rtc_time));
+	rtctm->tm_year = (tseq[83] & 0x0f) + (tseq[90] & 0x0f) * 10;
+	rtctm->tm_mon  = (tseq[69] & 0x0f) + (tseq[76] & 0x0f) * 10;
+	rtctm->tm_mday = (tseq[55] & 0x0f) + (tseq[62] & 0x0f) * 10;
+	rtctm->tm_wday = (tseq[48] & 0x0f);
+	rtctm->tm_hour = (tseq[34] & 0x0f) + (tseq[41] & 0x0f) * 10;
+	rtctm->tm_min  = (tseq[20] & 0x0f) + (tseq[27] & 0x0f) * 10;
+	rtctm->tm_sec  = (tseq[6]  & 0x0f) + (tseq[13] & 0x0f) * 10;
+	
+	return 0;
+}
+
+static int hp_sdc_rtc_read_bbrtc (struct rtc_time *rtctm)
+{
+	struct rtc_time tm, tm_last;
+	int i = 0;
+
+	/* MSM-58321 has no read latch, so must read twice and compare. */
+
+	if (hp_sdc_rtc_do_read_bbrtc(&tm_last)) return -1;
+	if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
+
+	while (memcmp(&tm, &tm_last, sizeof(struct rtc_time))) {
+		if (i++ > 4) return -1;
+		memcpy(&tm_last, &tm, sizeof(struct rtc_time));
+		if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
+	}
+
+	memcpy(rtctm, &tm, sizeof(struct rtc_time));
+
+	return 0;
+}
+
+
+static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg)
+{
+	hp_sdc_transaction t;
+	uint8_t tseq[26] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
+		0,
+		HP_SDC_CMD_READ_T1, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T2, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T3, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T4, 2, 0, 0,
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 
+		HP_SDC_CMD_READ_T5, 2, 0, 0
+	};
+
+	t.endidx = numreg * 5;
+
+	tseq[1] = loadcmd;
+	tseq[t.endidx - 4] |= HP_SDC_ACT_SEMAPHORE; /* numreg assumed > 1 */
+
+	t.seq =			tseq;
+	t.act.semaphore =	&i8042tregs;
+
+	down_interruptible(&i8042tregs);  /* Sleep if output regs in use. */
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	
+	down_interruptible(&i8042tregs);  /* Sleep until results come back. */
+	up(&i8042tregs);
+
+	return (tseq[5] | 
+		((uint64_t)(tseq[10]) << 8)  | ((uint64_t)(tseq[15]) << 16) |
+		((uint64_t)(tseq[20]) << 24) | ((uint64_t)(tseq[25]) << 32));
+}
+
+
+/* Read the i8042 real-time clock */
+static inline int hp_sdc_rtc_read_rt(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms; 
+	unsigned int days;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_RT, 5);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+	days  = (unsigned int)(raw >> 24) & 0xffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec =  (time_t)(tenms / 100) + days * 86400;
+
+	return 0;
+}
+
+
+/* Read the i8042 fast handshake timer */
+static inline int hp_sdc_rtc_read_fhs(struct timeval *res) {
+	uint64_t raw;
+	unsigned int tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2);
+	if (raw < 0) return -1;
+
+	tenms = (unsigned int)raw & 0xffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 match timer (a.k.a. alarm) */
+static inline int hp_sdc_rtc_read_mt(struct timeval *res) {
+	int64_t raw;	
+	uint32_t tenms; 
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_MT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 delay timer */
+static inline int hp_sdc_rtc_read_dt(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_DT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Read the i8042 cycle timer (a.k.a. periodic) */
+static inline int hp_sdc_rtc_read_ct(struct timeval *res) {
+	int64_t raw;
+	uint32_t tenms;
+
+	raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_CT, 3);
+	if (raw < 0) return -1;
+
+	tenms = (uint32_t)raw & 0xffffff;
+
+	res->tv_usec = (suseconds_t)(tenms % 100) * 10000;
+	res->tv_sec  = (time_t)(tenms / 100);
+
+	return 0;
+}
+
+
+/* Set the i8042 real-time clock */
+static int hp_sdc_rtc_set_rt (struct timeval *setto)
+{
+	uint32_t tenms;
+	unsigned int days;
+	hp_sdc_transaction t;
+	uint8_t tseq[11] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_RTMS, 3, 0, 0, 0,
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_RTD, 2, 0, 0 
+	};
+
+	t.endidx = 10;
+
+	if (0xffff < setto->tv_sec / 86400) return -1;
+	days = setto->tv_sec / 86400;
+	if (0xffff < setto->tv_usec / 1000000 / 86400) return -1;
+	days += ((setto->tv_sec % 86400) + setto->tv_usec / 1000000) / 86400;
+	if (days > 0xffff) return -1;
+
+	if (0xffffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffffff) return -1;
+
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+	tseq[5] = (uint8_t)((tenms >> 16) & 0xff);
+
+	tseq[9] = (uint8_t)(days & 0xff);
+	tseq[10] = (uint8_t)((days >> 8) & 0xff);
+
+	t.seq =	tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	return 0;
+}
+
+/* Set the i8042 fast handshake timer */
+static int hp_sdc_rtc_set_fhs (struct timeval *setto)
+{
+	uint32_t tenms;
+	hp_sdc_transaction t;
+	uint8_t tseq[5] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		HP_SDC_CMD_SET_FHS, 2, 0, 0
+	};
+
+	t.endidx = 4;
+
+	if (0xffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffff) return -1;
+
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+
+	t.seq =	tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) return -1;
+	return 0;
+}
+
+
+/* Set the i8042 match timer (a.k.a. alarm) */
+#define hp_sdc_rtc_set_mt (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_MT)
+
+/* Set the i8042 delay timer */
+#define hp_sdc_rtc_set_dt (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_DT)
+
+/* Set the i8042 cycle timer (a.k.a. periodic) */
+#define hp_sdc_rtc_set_ct (setto) \
+	hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_CT)
+
+/* Set one of the i8042 3-byte wide timers */
+static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd)
+{
+	uint32_t tenms;
+	hp_sdc_transaction t;
+	uint8_t tseq[6] = {
+		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,
+		0, 3, 0, 0, 0
+	};
+
+	t.endidx = 6;
+
+	if (0xffffff < setto->tv_sec) return -1;
+	tenms  = setto->tv_sec * 100;
+	if (0xffffff < setto->tv_usec / 10000) return -1;
+	tenms += setto->tv_usec / 10000;
+	if (tenms > 0xffffff) return -1;
+
+	tseq[1] = setcmd;
+	tseq[3] = (uint8_t)(tenms & 0xff);
+	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);
+	tseq[5] = (uint8_t)((tenms >> 16)  & 0xff);
+
+	t.seq =			tseq;
+
+	if (hp_sdc_enqueue_transaction(&t)) { 
+		return -1;
+	}
+	return 0;
+}
+
+static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin)
+{
+        return -ESPIPE;
+}
+
+static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
+			       size_t count, loff_t *ppos) {
+	ssize_t retval;
+
+        if (count < sizeof(unsigned long))
+                return -EINVAL;
+
+	retval = put_user(68, (unsigned long *)buf);
+	return retval;
+}
+
+static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait)
+{
+        unsigned long l;
+
+	l = 0;
+        if (l != 0)
+                return POLLIN | POLLRDNORM;
+        return 0;
+}
+
+static int hp_sdc_rtc_open(struct inode *inode, struct file *file)
+{
+        return 0;
+}
+
+static int hp_sdc_rtc_release(struct inode *inode, struct file *file)
+{
+	/* Turn off interrupts? */
+
+        if (file->f_flags & FASYNC) {
+                hp_sdc_rtc_fasync (-1, file, 0);
+        }
+
+        return 0;
+}
+
+static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on)
+{
+        return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue);
+}
+
+static int hp_sdc_rtc_proc_output (char *buf)
+{
+#define YN(bit) ("no")
+#define NY(bit) ("yes")
+        char *p;
+        struct rtc_time tm;
+	struct timeval tv;
+
+	memset(&tm, 0, sizeof(struct rtc_time));
+
+	p = buf;
+
+	if (hp_sdc_rtc_read_bbrtc(&tm)) {
+		p += sprintf(p, "BBRTC\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p,
+			     "rtc_time\t: %02d:%02d:%02d\n"
+			     "rtc_date\t: %04d-%02d-%02d\n"
+			     "rtc_epoch\t: %04lu\n",
+			     tm.tm_hour, tm.tm_min, tm.tm_sec,
+			     tm.tm_year + 1900, tm.tm_mon + 1, 
+			     tm.tm_mday, epoch);
+	}
+
+	if (hp_sdc_rtc_read_rt(&tv)) {
+		p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_fhs(&tv)) {
+		p += sprintf(p, "handshake\t: READ FAILED!\n");
+	} else {
+        	p += sprintf(p, "handshake\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_mt(&tv)) {
+		p += sprintf(p, "alarm\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_dt(&tv)) {
+		p += sprintf(p, "delay\t\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "delay\t\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+	if (hp_sdc_rtc_read_ct(&tv)) {
+		p += sprintf(p, "periodic\t: READ FAILED!\n");
+	} else {
+		p += sprintf(p, "periodic\t: %ld.%02d seconds\n", 
+			     tv.tv_sec, tv.tv_usec/1000);
+	}
+
+        p += sprintf(p,
+                     "DST_enable\t: %s\n"
+                     "BCD\t\t: %s\n"
+                     "24hr\t\t: %s\n"
+                     "square_wave\t: %s\n"
+                     "alarm_IRQ\t: %s\n"
+                     "update_IRQ\t: %s\n"
+                     "periodic_IRQ\t: %s\n"
+		     "periodic_freq\t: %ld\n"
+                     "batt_status\t: %s\n",
+                     YN(RTC_DST_EN),
+                     NY(RTC_DM_BINARY),
+                     YN(RTC_24H),
+                     YN(RTC_SQWE),
+                     YN(RTC_AIE),
+                     YN(RTC_UIE),
+                     YN(RTC_PIE),
+                     1UL,
+                     1 ? "okay" : "dead");
+
+        return  p - buf;
+#undef YN
+#undef NY
+}
+
+static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data)
+{
+	int len = hp_sdc_rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+
+static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, 
+			    unsigned int cmd, unsigned long arg)
+{
+#if 1
+	return -EINVAL;
+#else
+	
+        struct rtc_time wtime; 
+	struct timeval ttime;
+	int use_wtime = 0;
+
+	/* This needs major work. */
+
+        switch (cmd) {
+
+        case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */
+        case RTC_AIE_ON:        /* Allow alarm interrupts.      */
+	case RTC_PIE_OFF:       /* Mask periodic int. enab. bit */
+        case RTC_PIE_ON:        /* Allow periodic ints          */
+        case RTC_UIE_ON:        /* Allow ints for RTC updates.  */
+        case RTC_UIE_OFF:       /* Allow ints for RTC updates.  */
+        {
+		/* We cannot mask individual user timers and we
+		   cannot tell them apart when they occur, so it 
+		   would be disingenuous to succeed these IOCTLs */
+		return -EINVAL;
+        }
+        case RTC_ALM_READ:      /* Read the present alarm time */
+        {
+		if (hp_sdc_rtc_read_mt(&ttime)) return -EFAULT;
+		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;
+
+		wtime.tm_hour = ttime.tv_sec / 3600;  ttime.tv_sec %= 3600;
+		wtime.tm_min  = ttime.tv_sec / 60;    ttime.tv_sec %= 60;
+		wtime.tm_sec  = ttime.tv_sec;
+                
+		break;
+        }
+        case RTC_IRQP_READ:     /* Read the periodic IRQ rate.  */
+        {
+                return put_user(hp_sdc_rtc_freq, (unsigned long *)arg);
+        }
+        case RTC_IRQP_SET:      /* Set periodic IRQ rate.       */
+        {
+                /* 
+                 * The max we can do is 100Hz.
+		 */
+
+                if ((arg < 1) || (arg > 100)) return -EINVAL;
+		ttime.tv_sec = 0;
+		ttime.tv_usec = 1000000 / arg;
+		if (hp_sdc_rtc_set_ct(&ttime)) return -EFAULT;
+		hp_sdc_rtc_freq = arg;
+                return 0;
+        }
+        case RTC_ALM_SET:       /* Store a time into the alarm */
+        {
+                /*
+                 * This expects a struct hp_sdc_rtc_time. Writing 0xff means
+                 * "don't care" or "match all" for PC timers.  The HP SDC
+		 * does not support that perk, but it could be emulated fairly
+		 * easily.  Only the tm_hour, tm_min and tm_sec are used.
+		 * We could do it with 10ms accuracy with the HP SDC, if the 
+		 * rtc interface left us a way to do that.
+                 */
+                struct hp_sdc_rtc_time alm_tm;
+
+                if (copy_from_user(&alm_tm, (struct hp_sdc_rtc_time*)arg,
+                                   sizeof(struct hp_sdc_rtc_time)))
+                       return -EFAULT;
+
+                if (alm_tm.tm_hour > 23) return -EINVAL;
+		if (alm_tm.tm_min  > 59) return -EINVAL;
+		if (alm_tm.tm_sec  > 59) return -EINVAL;  
+
+		ttime.sec = alm_tm.tm_hour * 3600 + 
+		  alm_tm.tm_min * 60 + alm_tm.tm_sec;
+		ttime.usec = 0;
+		if (hp_sdc_rtc_set_mt(&ttime)) return -EFAULT;
+                return 0;
+        }
+        case RTC_RD_TIME:       /* Read the time/date from RTC  */
+        {
+		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;
+                break;
+        }
+        case RTC_SET_TIME:      /* Set the RTC */
+        {
+                struct rtc_time hp_sdc_rtc_tm;
+                unsigned char mon, day, hrs, min, sec, leap_yr;
+                unsigned int yrs;
+
+                if (!capable(CAP_SYS_TIME))
+                        return -EACCES;
+		if (copy_from_user(&hp_sdc_rtc_tm, (struct rtc_time *)arg,
+                                   sizeof(struct rtc_time)))
+                        return -EFAULT;
+
+                yrs = hp_sdc_rtc_tm.tm_year + 1900;
+                mon = hp_sdc_rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+                day = hp_sdc_rtc_tm.tm_mday;
+                hrs = hp_sdc_rtc_tm.tm_hour;
+                min = hp_sdc_rtc_tm.tm_min;
+                sec = hp_sdc_rtc_tm.tm_sec;
+
+                if (yrs < 1970)
+                        return -EINVAL;
+
+                leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+                if ((mon > 12) || (day == 0))
+                        return -EINVAL;
+                if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+                        return -EINVAL;
+		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+                        return -EINVAL;
+
+                if ((yrs -= eH) > 255)    /* They are unsigned */
+                        return -EINVAL;
+
+
+                return 0;
+        }
+        case RTC_EPOCH_READ:    /* Read the epoch.      */
+        {
+                return put_user (epoch, (unsigned long *)arg);
+        }
+        case RTC_EPOCH_SET:     /* Set the epoch.       */
+        {
+                /* 
+                 * There were no RTC clocks before 1900.
+                 */
+                if (arg < 1900)
+		  return -EINVAL;
+		if (!capable(CAP_SYS_TIME))
+		  return -EACCES;
+		
+                epoch = arg;
+                return 0;
+        }
+        default:
+                return -EINVAL;
+        }
+        return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+#endif
+}
+
+static struct file_operations hp_sdc_rtc_fops = {
+        .owner =	THIS_MODULE,
+        .llseek =	hp_sdc_rtc_llseek,
+        .read =		hp_sdc_rtc_read,
+        .poll =		hp_sdc_rtc_poll,
+        .ioctl =	hp_sdc_rtc_ioctl,
+        .open =		hp_sdc_rtc_open,
+        .release =	hp_sdc_rtc_release,
+        .fasync =	hp_sdc_rtc_fasync,
+};
+
+static struct miscdevice hp_sdc_rtc_dev = {
+        .minor =	RTC_MINOR,
+        .name =		"rtc_HIL",
+        .fops =		&hp_sdc_rtc_fops
+};
+
+static int __init hp_sdc_rtc_init(void)
+{
+	int ret;
+
+	init_MUTEX(&i8042tregs);
+
+	if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
+		return ret;
+	misc_register(&hp_sdc_rtc_dev);
+        create_proc_read_entry ("driver/rtc", 0, 0, 
+				hp_sdc_rtc_read_proc, NULL);
+
+	printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded "
+			 "(RTC v " RTC_VERSION ")\n");
+
+	return 0;
+}
+
+static void __exit hp_sdc_rtc_exit(void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+        misc_deregister(&hp_sdc_rtc_dev);
+	hp_sdc_release_timer_irq(hp_sdc_rtc_isr);
+        printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n");
+}
+
+module_init(hp_sdc_rtc_init);
+module_exit(hp_sdc_rtc_exit);
diff -Nru a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
--- a/drivers/input/misc/pcspkr.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/misc/pcspkr.c	2005-03-07 15:26:30 -08:00
@@ -27,7 +27,7 @@
 static char pcspkr_phys[] = "isa0061/input0";
 static struct input_dev pcspkr_dev;
 
-DEFINE_SPINLOCK(i8253_beep_lock);
+static DEFINE_SPINLOCK(i8253_beep_lock);
 
 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -89,6 +89,8 @@
 static void __exit pcspkr_exit(void)
 {
         input_unregister_device(&pcspkr_dev);
+	/* turn off the speaker */
+	pcspkr_event(NULL, EV_SND, SND_BELL, 0);
 }
 
 module_init(pcspkr_init);
diff -Nru a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
--- a/drivers/input/misc/uinput.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/misc/uinput.c	2005-03-07 15:26:30 -08:00
@@ -20,6 +20,9 @@
  * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
  *
  * Changes/Revisions:
+ *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
+ *		- added force feedback support
+ *              - added UI_SET_PHYS
  *	0.1	20/06/2002
  *		- first public version
  */
@@ -47,7 +50,7 @@
 {
 	struct uinput_device	*udev;
 
-	udev = (struct uinput_device *)dev->private;
+	udev = dev->private;
 
 	udev->buff[udev->head].type = type;
 	udev->buff[udev->head].code = code;
@@ -60,14 +63,93 @@
 	return 0;
 }
 
+static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request)
+{
+	/* Atomically allocate an ID for the given request. Returns 0 on success. */
+	struct uinput_device *udev = dev->private;
+	int id;
+
+	down(&udev->requests_sem);
+	for (id=0; id<UINPUT_NUM_REQUESTS; id++)
+		if (!udev->requests[id]) {
+			udev->requests[id] = request;
+			request->id = id;
+			up(&udev->requests_sem);
+			return 0;
+		}
+	up(&udev->requests_sem);
+	return -1;
+}
+
+static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id)
+{
+	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
+	if (id >= UINPUT_NUM_REQUESTS || id < 0)
+		return NULL;
+	if (udev->requests[id]->completed)
+		return NULL;
+	return udev->requests[id];
+}
+
+static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code)
+{
+	struct uinput_device *udev = dev->private;
+
+	memset(request, 0, sizeof(struct uinput_request));
+	request->code = code;
+	init_waitqueue_head(&request->waitq);
+
+	/* Allocate an ID. If none are available right away, wait. */
+	request->retval = wait_event_interruptible(udev->requests_waitq,
+				       !uinput_request_alloc_id(dev, request));
+}
+
+static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request)
+{
+	struct uinput_device *udev = dev->private;
+	int retval;
+
+	/* Tell our userspace app about this new request by queueing an input event */
+	uinput_dev_event(dev, EV_UINPUT, request->code, request->id);
+
+	/* Wait for the request to complete */
+	retval = wait_event_interruptible(request->waitq, request->completed);
+	if (retval)
+		request->retval = retval;
+
+	/* Release this request's ID, let others know it's available */
+	udev->requests[request->id] = NULL;
+	wake_up_interruptible(&udev->requests_waitq);
+}
+
 static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
 {
-	return 0;
+	struct uinput_request request;
+
+	if (!test_bit(EV_FF, dev->evbit))
+		return -ENOSYS;
+
+	uinput_request_init(dev, &request, UI_FF_UPLOAD);
+	if (request.retval)
+		return request.retval;
+	request.u.effect = effect;
+	uinput_request_submit(dev, &request);
+	return request.retval;
 }
 
 static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
 {
-	return 0;
+	struct uinput_request request;
+
+	if (!test_bit(EV_FF, dev->evbit))
+		return -ENOSYS;
+
+	uinput_request_init(dev, &request, UI_FF_ERASE);
+	if (request.retval)
+		return request.retval;
+	request.u.effect_id = effect_id;
+	uinput_request_submit(dev, &request);
+	return request.retval;
 }
 
 static int uinput_create_device(struct uinput_device *udev)
@@ -116,6 +198,8 @@
 	if (!newdev)
 		goto error;
 	memset(newdev, 0, sizeof(struct uinput_device));
+	init_MUTEX(&newdev->requests_sem);
+	init_waitqueue_head(&newdev->requests_waitq);
 
 	newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
 	if (!newinput)
@@ -138,12 +222,11 @@
 	unsigned int cnt;
 	int retval = 0;
 
-	for (cnt = 0; cnt < ABS_MAX; cnt++) {
+	for (cnt = 0; cnt < ABS_MAX + 1; cnt++) {
 		if (!test_bit(cnt, dev->absbit))
 			continue;
 
-		if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
-		    (dev->absmax[cnt] <= dev->absmin[cnt])) {
+		if ((dev->absmax[cnt] <= dev->absmin[cnt])) {
 			printk(KERN_DEBUG
 				"%s: invalid abs[%02x] min:%d max:%d\n",
 				UINPUT_NAME, cnt,
@@ -152,8 +235,7 @@
 			break;
 		}
 
-		if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
-		    (dev->absflat[cnt] > dev->absmax[cnt])) {
+		if (dev->absflat[cnt] > (dev->absmax[cnt] - dev->absmin[cnt])) {
 			printk(KERN_DEBUG
 				"%s: absflat[%02x] out of range: %d "
 				"(min:%d/max:%d)\n",
@@ -176,7 +258,7 @@
 
 	retval = count;
 
-	udev = (struct uinput_device *)file->private_data;
+	udev = file->private_data;
 	dev = udev->dev;
 
 	user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
@@ -228,7 +310,7 @@
 
 static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
-	struct uinput_device	*udev = file->private_data;
+	struct uinput_device *udev = file->private_data;
 
 	if (test_bit(UIST_CREATED, &(udev->state))) {
 		struct input_event	ev;
@@ -279,9 +361,6 @@
 {
 	struct uinput_device *udev = file->private_data;
 
-	if (!test_bit(UIST_CREATED, &(udev->state)))
-		return 0;
-
 	poll_wait(file, &udev->waitq, wait);
 
 	if (udev->head != udev->tail)
@@ -295,6 +374,11 @@
 	if (test_bit(UIST_CREATED, &(udev->state)))
 		uinput_destroy_device(udev);
 
+	if (NULL != udev->dev->name)
+		kfree(udev->dev->name);
+	if (NULL != udev->dev->phys)
+		kfree(udev->dev->phys);
+
 	kfree(udev->dev);
 	kfree(udev);
 
@@ -303,19 +387,35 @@
 
 static int uinput_close(struct inode *inode, struct file *file)
 {
-	return uinput_burn_device((struct uinput_device *)file->private_data);
+	return uinput_burn_device(file->private_data);
 }
 
 static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int			retval = 0;
 	struct uinput_device	*udev;
+	void __user             *p = (void __user *)arg;
+	struct uinput_ff_upload ff_up;
+	struct uinput_ff_erase  ff_erase;
+	struct uinput_request   *req;
+	int                     length;
 
-	udev = (struct uinput_device *)file->private_data;
+	udev = file->private_data;
 
 	/* device attributes can not be changed after the device is created */
-	if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
-		return -EINVAL;
+	switch (cmd) {
+		case UI_SET_EVBIT:
+		case UI_SET_KEYBIT:
+		case UI_SET_RELBIT:
+		case UI_SET_ABSBIT:
+		case UI_SET_MSCBIT:
+		case UI_SET_LEDBIT:
+		case UI_SET_SNDBIT:
+		case UI_SET_FFBIT:
+		case UI_SET_PHYS:
+			if (test_bit(UIST_CREATED, &(udev->state)))
+				return -EINVAL;
+	}
 
 	switch (cmd) {
 		case UI_DEV_CREATE:
@@ -390,13 +490,102 @@
 			set_bit(arg, udev->dev->ffbit);
 			break;
 
+		case UI_SET_PHYS:
+			length = strnlen_user(p, 1024);
+			if (length <= 0) {
+				retval = -EFAULT;
+				break;
+			}
+			if (NULL != udev->dev->phys)
+				kfree(udev->dev->phys);
+			udev->dev->phys = kmalloc(length, GFP_KERNEL);
+			if (!udev->dev->phys) {
+				retval = -ENOMEM;
+				break;
+			}
+			if (copy_from_user(udev->dev->phys, p, length)) {
+				retval = -EFAULT;
+				kfree(udev->dev->phys);
+				udev->dev->phys = NULL;
+				break;
+			}
+			udev->dev->phys[length-1] = '\0';
+			break;
+
+		case UI_BEGIN_FF_UPLOAD:
+			if (copy_from_user(&ff_up, p, sizeof(ff_up))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_up.request_id);
+			if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) {
+				retval = -EINVAL;
+				break;
+			}
+			ff_up.retval = 0;
+			memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect));
+			if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
+				retval = -EFAULT;
+				break;
+			}
+			break;
+
+		case UI_BEGIN_FF_ERASE:
+			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_erase.request_id);
+			if (!(req && req->code==UI_FF_ERASE)) {
+				retval = -EINVAL;
+				break;
+			}
+			ff_erase.retval = 0;
+			ff_erase.effect_id = req->u.effect_id;
+			if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+			break;
+
+		case UI_END_FF_UPLOAD:
+			if (copy_from_user(&ff_up, p, sizeof(ff_up))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_up.request_id);
+			if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) {
+				retval = -EINVAL;
+				break;
+			}
+			req->retval = ff_up.retval;
+			memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
+			req->completed = 1;
+			wake_up_interruptible(&req->waitq);
+			break;
+
+		case UI_END_FF_ERASE:
+			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+				retval = -EFAULT;
+				break;
+			}
+			req = uinput_request_find(udev, ff_erase.request_id);
+			if (!(req && req->code==UI_FF_ERASE)) {
+				retval = -EINVAL;
+				break;
+			}
+			req->retval = ff_erase.retval;
+			req->completed = 1;
+			wake_up_interruptible(&req->waitq);
+			break;
+
 		default:
-			retval = -EFAULT;
+			retval = -EINVAL;
 	}
 	return retval;
 }
 
-struct file_operations uinput_fops = {
+static struct file_operations uinput_fops = {
 	.owner =	THIS_MODULE,
 	.open =		uinput_open,
 	.release =	uinput_close,
diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/Kconfig	2005-03-07 15:26:30 -08:00
@@ -1,20 +1,20 @@
 #
 # Mouse driver configuration
 #
-config INPUT_MOUSE
-	bool "Mice"
+menuconfig INPUT_MOUSE
+	bool "Mouse"
 	default y
-	depends on INPUT
 	help
 	  Say Y here, and a list of supported mice will be displayed.
 	  This option doesn't affect the kernel.
 
 	  If unsure, say Y.
 
+if INPUT_MOUSE
+
 config MOUSE_PS2
 	tristate "PS/2 mouse"
 	default y
-	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	select SERIO_LIBPS2
 	select SERIO_I8042 if PC
@@ -39,7 +39,6 @@
 
 config MOUSE_SERIAL
 	tristate "Serial mouse"
-	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	---help---
 	  Say Y here if you have a serial (RS-232, COM port) mouse connected
@@ -53,7 +52,7 @@
 
 config MOUSE_INPORT
 	tristate "InPort/MS/ATIXL busmouse"
-	depends on INPUT && INPUT_MOUSE && ISA
+	depends on ISA
 	help
 	  Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
 	  They are rather rare these days.
@@ -69,7 +68,7 @@
 
 config MOUSE_LOGIBM
 	tristate "Logitech busmouse"
-	depends on INPUT && INPUT_MOUSE && ISA
+	depends on ISA
 	help
 	  Say Y here if you have a Logitech busmouse.
 	  They are rather rare these days.
@@ -79,7 +78,7 @@
 
 config MOUSE_PC110PAD
 	tristate "IBM PC110 touchpad"
-	depends on INPUT && INPUT_MOUSE && ISA
+	depends on ISA
 	help
 	  Say Y if you have the IBM PC-110 micro-notebook and want its
 	  touchpad supported.
@@ -89,7 +88,7 @@
 
 config MOUSE_MAPLE
 	tristate "Maple bus mouse"
-	depends on SH_DREAMCAST && INPUT && INPUT_MOUSE && MAPLE
+	depends on SH_DREAMCAST && MAPLE
 	help
 	  Say Y if you have a DreamCast console and a mouse attached to
 	  its Maple bus.
@@ -99,7 +98,7 @@
 
 config MOUSE_AMIGA
 	tristate "Amiga mouse"
-	depends on AMIGA && INPUT && INPUT_MOUSE
+	depends on AMIGA
 	help
 	  Say Y here if you have an Amiga and want its native mouse
 	  supported by the kernel.
@@ -109,7 +108,7 @@
 
 config MOUSE_RISCPC
 	tristate "Acorn RiscPC mouse"
-	depends on ARCH_ACORN && INPUT && INPUT_MOUSE
+	depends on ARCH_ACORN
 	help
 	  Say Y here if you have the Acorn RiscPC computer and want its
 	  native mouse supported.
@@ -119,7 +118,6 @@
 
 config MOUSE_VSXXXAA
 	tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet"
-	depends on INPUT && INPUT_MOUSE
 	select SERIO
 	help
 	  Say Y (or M) if you want to use a DEC VSXXX-AA (hockey
@@ -129,3 +127,12 @@
 	  described in the source file). This driver also works with the
 	  digitizer (VSXXX-AB) DEC produced.
 
+config MOUSE_HIL
+	tristate "HIL pointers (mice etc)."     
+	depends on GSC
+	select HP_SDC
+	select HIL_MLC
+	help
+	  Say Y here to support HIL pointers.
+
+endif
diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
--- a/drivers/input/mouse/Makefile	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/Makefile	2005-03-07 15:26:30 -08:00
@@ -12,6 +12,7 @@
 obj-$(CONFIG_MOUSE_PC110PAD)	+= pc110pad.o
 obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
+obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 
 psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o
diff -Nru a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
--- a/drivers/input/mouse/alps.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/alps.c	2005-03-07 15:26:30 -08:00
@@ -4,6 +4,7 @@
  * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
  * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
  * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
  *
  * ALPS detection, tap switching and status querying info is taken from
  * tpconfig utility (by C. Scott Ananian and Bruce Kall).
@@ -27,102 +28,122 @@
 #define dbg(format, arg...) do {} while (0)
 #endif
 
-#define ALPS_MODEL_GLIDEPOINT	1
-#define ALPS_MODEL_DUALPOINT	2
-
-struct alps_model_info {
-	unsigned char signature[3];
-	unsigned char model;
-} alps_model_data[] = {
-/*	{ { 0x33, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },	*/
-	{ { 0x53, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x53, 0x02, 0x14 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x63, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x63, 0x02, 0x14 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x73, 0x02, 0x0a },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x73, 0x02, 0x14 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x63, 0x02, 0x28 },	ALPS_MODEL_GLIDEPOINT },
-/*	{ { 0x63, 0x02, 0x3c },	ALPS_MODEL_GLIDEPOINT },	*/
-/*	{ { 0x63, 0x02, 0x50 },	ALPS_MODEL_GLIDEPOINT },	*/
-	{ { 0x63, 0x02, 0x64 },	ALPS_MODEL_GLIDEPOINT },
-	{ { 0x20, 0x02, 0x0e },	ALPS_MODEL_DUALPOINT },
-	{ { 0x22, 0x02, 0x0a },	ALPS_MODEL_DUALPOINT },
-	{ { 0x22, 0x02, 0x14 }, ALPS_MODEL_DUALPOINT },
-	{ { 0x63, 0x03, 0xc8 },	ALPS_MODEL_DUALPOINT },
+#define ALPS_DUALPOINT	0x01
+#define ALPS_WHEEL	0x02
+#define ALPS_FW_BK	0x04
+#define ALPS_4BTN	0x08
+#define ALPS_OLDPROTO	0x10
+#define ALPS_PASS	0x20
+
+static struct alps_model_info alps_model_data[] = {
+	{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		/* UMAX-530T */
+	{ { 0x53, 0x02, 0x0a },	0xf8, 0xf8, 0 },
+	{ { 0x53, 0x02, 0x14 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x0a },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x14 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		/* Toshiba Satellite S2400-103 */
+	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK },		/* NEC Versa L320 */
+	{ { 0x63, 0x02, 0x64 },	0xf8, 0xf8, 0 },
+	{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },		/* Dell Latitude D800 */
+	{ { 0x73, 0x02, 0x0a },	0xf8, 0xf8, 0 },
+	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, 0 },
+	{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
+	{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
+	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
 };
 
 /*
- * ALPS abolute Mode
- * byte 0:  1    1    1    1    1  mid0 rig0 lef0
+ * XXX - this entry is suspicious. First byte has zero lower nibble,
+ * which is what a normal mouse would report. Also, the value 0x0e
+ * isn't valid per PS/2 spec.
+ */
+
+/*
+ * ALPS abolute Mode - new format
+ * 
+ * byte 0:  1    ?    ?    ?    1    ?    ?    ? 
  * byte 1:  0   x6   x5   x4   x3   x2   x1   x0
- * byte 2:  0   x10  x9   x8   x7  up1  fin  ges
- * byte 3:  0   y9   y8   y7    1  mid1 rig1 lef1
+ * byte 2:  0   x10  x9   x8   x7    ?  fin  ges
+ * byte 3:  0   y9   y8   y7    1    M    R    L 
  * byte 4:  0   y6   y5   y4   y3   y2   y1   y0
  * byte 5:  0   z6   z5   z4   z3   z2   z1   z0
  *
- * On a dualpoint, {mid,rig,lef}0 are the stick, 1 are the pad.
- * We just 'or' them together for now.
- *
- * We used to send 'ges'tures as BTN_TOUCH but this made it impossible
- * to disable tap events in the synaptics driver since the driver
- * was unable to distinguish a gesture tap from an actual button click.
- * A tap gesture now creates an emulated touch that the synaptics
- * driver can interpret as a tap event, if MaxTapTime=0 and
- * MaxTapMove=0 then the driver will ignore taps.
- *
- * The touchpad on an 'Acer Aspire' has 4 buttons:
- *   left,right,up,down.
- * This device always sets {mid,rig,lef}0 to 1 and
- * reflects left,right,down,up in lef1,rig1,mid1,up1.
+ * ?'s can have different meanings on different models,
+ * such as wheel rotation, extra buttons, stick buttons
+ * on a dualpoint, etc.
  */
 
 static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 {
+	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev = &psmouse->dev;
-	int x, y, z;
-	int left = 0, right = 0, middle = 0;
+	struct input_dev *dev2 = &priv->dev2;
+	int x, y, z, ges, fin, left, right, middle;
 
 	input_regs(dev, regs);
 
 	if ((packet[0] & 0xc8) == 0x08) {   /* 3-byte PS/2 packet */
-		x = packet[1];
-		if (packet[0] & 0x10)
-			x = x - 256;
-		y = packet[2];
-		if (packet[0] & 0x20)
-			y = y - 256;
-		left  = (packet[0]     ) & 1;
-		right = (packet[0] >> 1) & 1;
-
-		input_report_rel(dev, REL_X, x);
-		input_report_rel(dev, REL_Y, -y);
-		input_report_key(dev, BTN_A, left);
-		input_report_key(dev, BTN_B, right);
-		input_sync(dev);
+		input_report_key(dev2, BTN_LEFT,   packet[0] & 1);    
+		input_report_key(dev2, BTN_RIGHT,  packet[0] & 2);
+		input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
+		input_report_rel(dev2, REL_X,
+			packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
+		input_report_rel(dev2, REL_Y,
+			packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
+		input_sync(dev2);
 		return;
 	}
 
-	x = (packet[1] & 0x7f) | ((packet[2] & 0x78)<<(7-3));
-	y = (packet[4] & 0x7f) | ((packet[3] & 0x70)<<(7-4));
-	z = packet[5];
-
-	if (z == 127) {	/* DualPoint stick is relative, not absolute */
-		if (x > 383)
-			x = x - 768;
-		if (y > 255)
-			y = y - 512;
-		left  = packet[3] & 1;
-		right = (packet[3] >> 1) & 1;
-
-		input_report_rel(dev, REL_X, x);
-		input_report_rel(dev, REL_Y, -y);
-		input_report_key(dev, BTN_LEFT, left);
-		input_report_key(dev, BTN_RIGHT, right);
+	if (priv->i->flags & ALPS_OLDPROTO) {
+		left = packet[2] & 0x08;
+		right = packet[2] & 0x10;
+		middle = 0;
+		x = packet[1] | ((packet[0] & 0x07) << 7);
+		y = packet[4] | ((packet[3] & 0x07) << 7);
+		z = packet[5];
+	} else {
+		left = packet[3] & 1;
+		right = packet[3] & 2;
+		middle = packet[3] & 4;
+		x = packet[1] | ((packet[2] & 0x78) << (7 - 3));
+		y = packet[4] | ((packet[3] & 0x70) << (7 - 4));
+		z = packet[5];
+	}
+
+	ges = packet[2] & 1;
+	fin = packet[2] & 2;
+
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
+	input_report_key(dev, BTN_MIDDLE, middle);
+
+	if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) {
+		input_report_rel(dev2, REL_X,  (x > 383 ? (x - 768) : x));
+		input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
 		input_sync(dev);
+		input_sync(dev2);
 		return;
 	}
 
+	/* Convert hardware tap to a reasonable Z value */
+	if (ges && !fin) z = 40;
+
+	/*
+	 * A "tap and drag" operation is reported by the hardware as a transition
+	 * from (!fin && ges) to (fin && ges). This should be translated to the
+	 * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually.
+	 */
+	if (ges && fin && !priv->prev_fin) {
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
+		input_report_abs(dev, ABS_PRESSURE, 0);
+		input_report_key(dev, BTN_TOOL_FINGER, 0);
+		input_sync(dev);
+	}
+	priv->prev_fin = fin;
+
 	if (z > 30) input_report_key(dev, BTN_TOUCH, 1);
 	if (z < 25) input_report_key(dev, BTN_TOUCH, 0);
 
@@ -130,38 +151,26 @@
 		input_report_abs(dev, ABS_X, x);
 		input_report_abs(dev, ABS_Y, y);
 	}
+
 	input_report_abs(dev, ABS_PRESSURE, z);
 	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 
-	left  |= (packet[2]     ) & 1;
-	left  |= (packet[3]     ) & 1;
-	right |= (packet[3] >> 1) & 1;
-	if (packet[0] == 0xff) {
-		int back    = (packet[3] >> 2) & 1;
-		int forward = (packet[2] >> 2) & 1;
-		if (back && forward) {
-			middle = 1;
-			back = 0;
-			forward = 0;
-		}
-		input_report_key(dev, BTN_BACK,    back);
-		input_report_key(dev, BTN_FORWARD, forward);
-	} else {
-		left   |= (packet[0]     ) & 1;
-		right  |= (packet[0] >> 1) & 1;
-		middle |= (packet[0] >> 2) & 1;
-		middle |= (packet[3] >> 2) & 1;
-	}
 
-	input_report_key(dev, BTN_LEFT, left);
-	input_report_key(dev, BTN_RIGHT, right);
-	input_report_key(dev, BTN_MIDDLE, middle);
+	if (priv->i->flags & ALPS_WHEEL)
+		input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
+
+	if (priv->i->flags & ALPS_FW_BK) {
+		input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
+		input_report_key(dev, BTN_BACK, packet[2] & 0x04);
+	}
 
 	input_sync(dev);
 }
 
 static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 {
+	struct alps_data *priv = psmouse->private;
+
 	if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
 		if (psmouse->pktcnt == 3) {
 			alps_process_packet(psmouse, regs);
@@ -170,13 +179,12 @@
 		return PSMOUSE_GOOD_DATA;
 	}
 
-	/* ALPS absolute mode packets start with 0b11111mrl */
-	if ((psmouse->packet[0] & 0xf8) != 0xf8)
+	if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0)
 		return PSMOUSE_BAD_DATA;
 
 	/* Bytes 2 - 6 should have 0 in the highest bit */
 	if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
-	    (psmouse->packet[psmouse->pktcnt-1] & 0x80))
+	    (psmouse->packet[psmouse->pktcnt - 1] & 0x80))
 		return PSMOUSE_BAD_DATA;
 
 	if (psmouse->pktcnt == 6) {
@@ -187,51 +195,58 @@
 	return PSMOUSE_GOOD_DATA;
 }
 
-int alps_get_model(struct psmouse *psmouse)
+static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
 	unsigned char param[4];
 	int i;
 
 	/*
 	 * First try "E6 report".
-	 * ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64
+	 * ALPS should return 0,0,10 or 0,0,100
 	 */
 	param[0] = 0;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11))
-		return -1;
+		return NULL;
 
 	param[0] = param[1] = param[2] = 0xff;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-		return -1;
+		return NULL;
 
 	dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
 
-	if (param[0] != 0x00 || param[1] != 0x00 || (param[2] != 0x0a && param[2] != 0x64))
-		return -1;
+	if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
+		return NULL;
 
-	/* Now try "E7 report". ALPS should return 0x33 in byte 1 */
+	/*
+	 * Now try "E7 report". Allowed responses are in
+	 * alps_model_data[].signature
+	 */
 	param[0] = 0;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
 	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21))
-		return -1;
+		return NULL;
 
 	param[0] = param[1] = param[2] = 0xff;
 	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-		return -1;
+		return NULL;
 
 	dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
 
+	for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++);
+	*version = (param[0] << 8) | (param[1] << 4) | i;
+
 	for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
 		if (!memcmp(param, alps_model_data[i].signature, sizeof(alps_model_data[i].signature)))
-			return alps_model_data[i].model;
+			return alps_model_data + i;
 
-	return -1;
+	return NULL;
 }
 
 /*
@@ -322,27 +337,28 @@
 
 static int alps_reconnect(struct psmouse *psmouse)
 {
-	int model;
+	struct alps_data *priv = psmouse->private;
 	unsigned char param[4];
+	int version;
 
-	if ((model = alps_get_model(psmouse)) < 0)
+	if (!(priv->i = alps_get_model(psmouse, &version)))
 		return -1;
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
+	if (priv->i->flags & ALPS_PASS && alps_passthrough_mode(psmouse, 1))
 		return -1;
 
 	if (alps_get_status(psmouse, param))
 		return -1;
 
 	if (param[0] & 0x04)
-		alps_tap_mode(psmouse, 0);
+		alps_tap_mode(psmouse, 1);
 
 	if (alps_absolute_mode(psmouse)) {
 		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
 		return -1;
 	}
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
+	if (priv->i->flags == ALPS_PASS && alps_passthrough_mode(psmouse, 0))
 		return -1;
 
 	return 0;
@@ -350,57 +366,83 @@
 
 static void alps_disconnect(struct psmouse *psmouse)
 {
+	struct alps_data *priv = psmouse->private;
 	psmouse_reset(psmouse);
+	input_unregister_device(&priv->dev2);
+	kfree(priv);
 }
 
 int alps_init(struct psmouse *psmouse)
 {
+	struct alps_data *priv;
 	unsigned char param[4];
-	int model;
+	int version;
 
-	if ((model = alps_get_model(psmouse)) < 0)
-		return -1;
+	psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL);
+	if (!priv)
+		goto init_fail;
+	memset(priv, 0, sizeof(struct alps_data));
 
-	printk(KERN_INFO "ALPS Touchpad (%s) detected\n",
-		model == ALPS_MODEL_GLIDEPOINT ? "Glidepoint" : "Dualpoint");
+	if (!(priv->i = alps_get_model(psmouse, &version)))
+		goto init_fail;
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
-		return -1;
+	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
+		goto init_fail;
 
 	if (alps_get_status(psmouse, param)) {
 		printk(KERN_ERR "alps.c: touchpad status report request failed\n");
-		return -1;
+		goto init_fail;
 	}
 
 	if (param[0] & 0x04) {
-		printk(KERN_INFO "  Disabling hardware tapping\n");
-		if (alps_tap_mode(psmouse, 0))
-			printk(KERN_WARNING "alps.c: Failed to disable hardware tapping\n");
+		printk(KERN_INFO "  Enabling hardware tapping\n");
+		if (alps_tap_mode(psmouse, 1))
+			printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
 	}
 
 	if (alps_absolute_mode(psmouse)) {
 		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
-		return -1;
+		goto init_fail;
 	}
 
-	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
-		return -1;
+	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0))
+		goto init_fail;
 
-	psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
-	psmouse->dev.relbit[LONG(REL_X)] |= BIT(REL_X);
-	psmouse->dev.relbit[LONG(REL_Y)] |= BIT(REL_Y);
-	psmouse->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A);
-	psmouse->dev.keybit[LONG(BTN_B)] |= BIT(BTN_B);
+	psmouse->dev.evbit[LONG(EV_KEY)] |= BIT(EV_KEY);
+	psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+	psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
+	psmouse->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 
 	psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
 	input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0);
-	input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1023, 0, 0);
+	input_set_abs_params(&psmouse->dev, ABS_Y, 0, 767, 0, 0);
 	input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0);
 
-	psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
-	psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
-	psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
-	psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
+	if (priv->i->flags & ALPS_WHEEL) {
+		psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
+		psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
+	}
+
+	if (priv->i->flags & ALPS_FW_BK) {
+		psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
+		psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
+	}
+
+	sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys);
+	priv->dev2.phys = priv->phys;
+	priv->dev2.name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
+	priv->dev2.id.bustype = BUS_I8042;
+	priv->dev2.id.vendor = 0x0002;
+	priv->dev2.id.product = PSMOUSE_ALPS;
+	priv->dev2.id.version = 0x0000; 
+	
+	priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
+	priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+
+	input_register_device(&priv->dev2);
+
+	printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys);
 
 	psmouse->protocol_handler = alps_process_byte;
 	psmouse->disconnect = alps_disconnect;
@@ -408,16 +450,27 @@
 	psmouse->pktsize = 6;
 
 	return 0;
+
+init_fail:
+	kfree(priv);
+	return -1;
 }
 
 int alps_detect(struct psmouse *psmouse, int set_properties)
 {
-	if (alps_get_model(psmouse) < 0)
+	int version;
+	struct alps_model_info *model; 
+
+	if (!(model = alps_get_model(psmouse, &version)))
 		return -1;
 
 	if (set_properties) {
 		psmouse->vendor = "ALPS";
-		psmouse->name = "TouchPad";
+		if (model->flags & ALPS_DUALPOINT) 
+			psmouse->name = "DualPoint TouchPad";
+		else
+			psmouse->name = "GlidePoint";
+		psmouse->model = version;
 	}
 	return 0;
 }
diff -Nru a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
--- a/drivers/input/mouse/alps.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/alps.h	2005-03-07 15:26:30 -08:00
@@ -2,6 +2,7 @@
  * ALPS touchpad PS/2 mouse driver
  *
  * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
  *
  * 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
@@ -13,5 +14,19 @@
 
 int alps_detect(struct psmouse *psmouse, int set_properties);
 int alps_init(struct psmouse *psmouse);
+
+struct alps_model_info {
+        unsigned char signature[3];
+        unsigned char byte0, mask0;
+        unsigned char flags;
+};
+
+struct alps_data {
+	struct input_dev dev2;		/* Relative device */
+	char name[32];			/* Name */
+	char phys[32];			/* Phys */
+	struct alps_model_info *i; 	/* Info */
+	int prev_fin;			/* Finger bit from previous packet */
+};
 
 #endif
diff -Nru a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/mouse/hil_ptr.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,414 @@
+/*
+ * Generic linux-input device driver for axis-bearing devices
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ */
+
+#include <linux/hil.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+
+#define PREFIX "HIL PTR: "
+#define HIL_GENERIC_NAME "HIL pointer device"
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+
+#define TABLET_SIMULATES_MOUSE	/* allow tablet to be used as mouse */
+#undef  TABLET_AUTOADJUST	/* auto-adjust valid tablet ranges */
+
+
+#define HIL_PTR_MAX_LENGTH 16
+
+struct hil_ptr {
+	struct input_dev dev;
+	struct serio *serio;
+
+	/* Input buffer and index for packets from HIL bus. */
+	hil_packet data[HIL_PTR_MAX_LENGTH];
+	int idx4; /* four counts per packet */
+
+	/* Raw device info records from HIL bus, see hil.h for fields. */
+	char	idd[HIL_PTR_MAX_LENGTH];	/* DID byte and IDD record */
+	char	rsc[HIL_PTR_MAX_LENGTH];	/* RSC record */
+	char	exd[HIL_PTR_MAX_LENGTH];	/* EXD record */
+	char	rnm[HIL_PTR_MAX_LENGTH + 1];	/* RNM record + NULL term. */
+
+	/* Extra device details not contained in struct input_dev. */
+	unsigned int nbtn, naxes;
+	unsigned int btnmap[7];
+
+	/* Something to sleep around with. */
+	struct semaphore sem;
+};
+
+/* Process a complete packet after transfer from the HIL */
+static void hil_ptr_process_record(struct hil_ptr *ptr)
+{
+	struct input_dev *dev = &ptr->dev;
+	hil_packet *data = ptr->data;
+	hil_packet p;
+	int idx, i, cnt, laxis;
+	int ax16, absdev;
+
+	idx = ptr->idx4/4;
+	p = data[idx - 1];
+
+	if ((p & ~HIL_CMDCT_POL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
+	if ((p & ~HIL_CMDCT_RPL) == 
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+
+	/* Not a poll response.  See if we are loading config records. */
+	switch (p & HIL_PKT_DATA_MASK) {
+	case HIL_CMD_IDD:
+		for (i = 0; i < idx; i++)
+			ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH; i++)
+			ptr->idd[i] = 0;
+		break;
+	case HIL_CMD_RSC:
+		for (i = 0; i < idx; i++)
+			ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH; i++)
+			ptr->rsc[i] = 0;
+		break;
+	case HIL_CMD_EXD:
+		for (i = 0; i < idx; i++)
+			ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH; i++)
+			ptr->exd[i] = 0;
+		break;
+	case HIL_CMD_RNM:
+		for (i = 0; i < idx; i++)
+			ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
+		for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
+			ptr->rnm[i] = '\0';
+		break;
+	default:
+		/* These occur when device isn't present */
+		if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; 
+		/* Anything else we'd like to know about. */
+		printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
+		break;
+	}
+	goto out;
+
+ report:
+	if ((p & HIL_CMDCT_POL) != idx - 1) {
+		printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx);
+		goto out;
+	}
+
+	i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0;
+	laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK;
+	laxis += i;
+
+	ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
+	absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; 
+
+	for (cnt = 1; i < laxis; i++) {
+		unsigned int lo,hi,val;
+		lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;
+		hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;
+		if (absdev) {
+			val = lo + (hi<<8);
+#ifdef TABLET_AUTOADJUST
+			if (val < ptr->dev.absmin[ABS_X + i])
+				ptr->dev.absmin[ABS_X + i] = val;
+			if (val > ptr->dev.absmax[ABS_X + i])
+				ptr->dev.absmax[ABS_X + i] = val;
+#endif
+			if (i%3) val = ptr->dev.absmax[ABS_X + i] - val;
+			input_report_abs(dev, ABS_X + i, val);
+		} else {
+			val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
+			if (i%3) val *= -1;
+			input_report_rel(dev, REL_X + i, val);
+		}
+	}
+
+	while (cnt < idx - 1) {
+		unsigned int btn;
+		int up;
+		btn = ptr->data[cnt++];
+		up = btn & 1;
+		btn &= 0xfe;
+		if (btn == 0x8e) {
+			continue; /* TODO: proximity == touch? */
+		}
+		else if ((btn > 0x8c) || (btn < 0x80)) continue;
+		btn = (btn - 0x80) >> 1;
+		btn = ptr->btnmap[btn];
+		input_report_key(dev, btn, !up);
+	}
+	input_sync(dev);
+ out:
+	ptr->idx4 = 0;
+	up(&ptr->sem);
+}
+
+static void hil_ptr_process_err(struct hil_ptr *ptr) {
+	printk(KERN_WARNING PREFIX "errored HIL packet\n");
+	ptr->idx4 = 0;
+	up(&ptr->sem);
+	return;
+}
+
+static irqreturn_t hil_ptr_interrupt(struct serio *serio, 
+        unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct hil_ptr *ptr;
+	hil_packet packet;
+	int idx;
+
+	ptr = (struct hil_ptr *)serio->private;
+	if (ptr == NULL) {
+		BUG();
+		return IRQ_HANDLED;
+	}
+
+	if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
+		hil_ptr_process_err(ptr);
+		return IRQ_HANDLED;
+	}
+	idx = ptr->idx4/4;
+	if (!(ptr->idx4 % 4)) ptr->data[idx] = 0;
+	packet = ptr->data[idx];
+	packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
+	ptr->data[idx] = packet;
+
+	/* Records of N 4-byte hil_packets must terminate with a command. */
+	if ((++(ptr->idx4)) % 4) return IRQ_HANDLED;
+	if ((packet & 0xffff0000) != HIL_ERR_INT) {
+		hil_ptr_process_err(ptr);
+		return IRQ_HANDLED;
+	}
+	if (packet & HIL_PKT_CMD) 
+		hil_ptr_process_record(ptr);
+	return IRQ_HANDLED;
+}
+
+static void hil_ptr_disconnect(struct serio *serio)
+{
+	struct hil_ptr *ptr;
+
+	ptr = (struct hil_ptr *)serio->private;
+	if (ptr == NULL) {
+		BUG();
+		return;
+	}
+
+	input_unregister_device(&ptr->dev);
+	serio_close(serio);
+	kfree(ptr);
+}
+
+static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
+{
+	struct hil_ptr	*ptr;
+	char		*txt;
+	unsigned int	i, naxsets, btntype;
+	uint8_t		did, *idd;
+
+	if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return;
+
+	if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return;
+	memset(ptr, 0, sizeof(struct hil_ptr));
+
+	if (serio_open(serio, driver)) goto bail0;
+
+	serio->private = ptr;
+	ptr->serio = serio;
+	ptr->dev.private = ptr;
+
+	init_MUTEX_LOCKED(&(ptr->sem));
+
+	/* Get device info.  MLC driver supplies devid/status/etc. */
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_IDD);
+	down(&(ptr->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RSC);
+	down(&(ptr->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_RNM);
+	down(&(ptr->sem));
+
+	serio->write(serio, 0);
+	serio->write(serio, 0);
+	serio->write(serio, HIL_PKT_CMD >> 8);
+	serio->write(serio, HIL_CMD_EXD);
+	down(&(ptr->sem));
+
+	up(&(ptr->sem));
+
+	init_input_dev(&ptr->dev);
+	did = ptr->idd[0];
+	idd = ptr->idd + 1;
+	txt = "unknown";
+	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
+		ptr->dev.evbit[0] = BIT(EV_REL);
+		txt = "relative";
+	}
+
+	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
+		ptr->dev.evbit[0] = BIT(EV_ABS);
+		txt = "absolute";
+	}
+	if (!ptr->dev.evbit[0]) {
+		goto bail1;
+	}
+
+	ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
+	if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY);
+
+	naxsets = HIL_IDD_NUM_AXSETS(*idd);
+	ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
+
+	printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n",
+			did, txt);
+	printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n",
+			ptr->nbtn, naxsets, ptr->naxes);
+	
+	btntype = BTN_MISC;
+	if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
+#ifdef TABLET_SIMULATES_MOUSE
+		btntype = BTN_TOUCH;
+#else
+		btntype = BTN_DIGI;
+#endif
+	if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
+		btntype = BTN_TOUCH;
+		
+	if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
+		btntype = BTN_MOUSE;
+
+	for (i = 0; i < ptr->nbtn; i++) {
+		set_bit(btntype | i, ptr->dev.keybit);
+		ptr->btnmap[i] = btntype | i;
+	}
+
+	if (btntype == BTN_MOUSE) {
+		/* Swap buttons 2 and 3 */
+		ptr->btnmap[1] = BTN_MIDDLE;
+		ptr->btnmap[2] = BTN_RIGHT;
+	}
+
+	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
+		for (i = 0; i < ptr->naxes; i++) {
+			set_bit(REL_X + i, ptr->dev.relbit);
+		}
+		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
+			set_bit(REL_X + i, ptr->dev.relbit);
+		}
+	} else {
+		for (i = 0; i < ptr->naxes; i++) {
+	  		set_bit(ABS_X + i, ptr->dev.absbit);
+			ptr->dev.absmin[ABS_X + i] = 0;
+			ptr->dev.absmax[ABS_X + i] = 
+				HIL_IDD_AXIS_MAX((ptr->idd + 1), i);
+		}
+		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
+			set_bit(ABS_X + i, ptr->dev.absbit);
+			ptr->dev.absmin[ABS_X + i] = 0;
+			ptr->dev.absmax[ABS_X + i] = 
+				HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3));
+		}
+#ifdef TABLET_AUTOADJUST
+		for (i = 0; i < ABS_MAX; i++) {
+			int diff = ptr->dev.absmax[ABS_X + i] / 10;
+			ptr->dev.absmin[ABS_X + i] += diff;
+			ptr->dev.absmax[ABS_X + i] -= diff;
+		}
+#endif
+	}
+
+	ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
+
+	ptr->dev.id.bustype	= BUS_HIL;
+	ptr->dev.id.vendor	= PCI_VENDOR_ID_HP;
+	ptr->dev.id.product	= 0x0001; /* TODO: get from ptr->rsc */
+	ptr->dev.id.version	= 0x0100; /* TODO: get from ptr->rsc */
+	ptr->dev.dev		= &serio->dev;
+
+	input_register_device(&ptr->dev);
+	printk(KERN_INFO "input: %s (%s), ID: %d\n",
+                ptr->dev.name, 
+		(btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
+		did);
+
+	return;
+ bail1:
+	serio_close(serio);
+ bail0:
+	kfree(ptr);
+	return;
+}
+
+
+static struct serio_driver hil_ptr_serio_driver = {
+	.driver		= {
+		.name	= "hil_ptr",
+	},
+	.description	= "HP HIL mouse/tablet driver",
+	.connect =	hil_ptr_connect,
+	.disconnect =	hil_ptr_disconnect,
+	.interrupt =	hil_ptr_interrupt
+};
+
+static int __init hil_ptr_init(void)
+{
+	serio_register_driver(&hil_ptr_serio_driver);
+        return 0;
+}
+                
+static void __exit hil_ptr_exit(void)
+{
+	serio_unregister_driver(&hil_ptr_serio_driver);
+}
+                        
+module_init(hil_ptr_init);
+module_exit(hil_ptr_exit);
diff -Nru a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
--- a/drivers/input/mouse/logips2pp.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/logips2pp.c	2005-03-07 15:26:30 -08:00
@@ -202,6 +202,9 @@
 	static struct ps2pp_info ps2pp_list[] = {
 		{ 12,	0,			PS2PP_SIDE_BTN},
 		{ 13,	0,			0 },
+		{ 15,	PS2PP_KIND_MX,					/* MX1000 */
+				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
 		{ 40,	0,			PS2PP_SIDE_BTN },
 		{ 41,	0,			PS2PP_SIDE_BTN },
 		{ 42,	0,			PS2PP_SIDE_BTN },
@@ -210,9 +213,9 @@
 		{ 51,	0,			0 },
 		{ 52,	PS2PP_KIND_WHEEL,	PS2PP_SIDE_BTN | PS2PP_WHEEL },
 		{ 53,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
-		{ 61,	PS2PP_KIND_MX,
+		{ 61,	PS2PP_KIND_MX,					/* MX700 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
-				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX700 */
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
 		{ 73,	0,			PS2PP_SIDE_BTN },
 		{ 75,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
 		{ 76,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
@@ -222,15 +225,17 @@
 		{ 88,	PS2PP_KIND_WHEEL,	PS2PP_WHEEL },
 		{ 96,	0,			0 },
 		{ 97,	PS2PP_KIND_TP3,		PS2PP_WHEEL | PS2PP_HWHEEL },
-		{ 100,	PS2PP_KIND_MX,
+		{ 100,	PS2PP_KIND_MX,					/* MX510 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
-				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX510 */
-		{ 112,	PS2PP_KIND_MX,
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
+		{ 111,  PS2PP_KIND_MX,					/* MX300 */
+				PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN },
+		{ 112,	PS2PP_KIND_MX,					/* MX500 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
-				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },	/* MX500 */
-		{ 114,	PS2PP_KIND_MX,
+				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
+		{ 114,	PS2PP_KIND_MX,					/* MX310 */
 				PS2PP_WHEEL | PS2PP_SIDE_BTN |
-				PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },	/* M310 */
+				PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },
 		{ }
 	};
 	int i;
@@ -238,6 +243,8 @@
 	for (i = 0; ps2pp_list[i].model; i++)
 		if (model == ps2pp_list[i].model)
 			return &ps2pp_list[i];
+
+	printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
 	return NULL;
 }
 
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/psmouse-base.c	2005-03-07 15:26:30 -08:00
@@ -31,25 +31,30 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static char *psmouse_proto;
 static unsigned int psmouse_max_proto = -1U;
-module_param_named(proto, psmouse_proto, charp, 0);
-MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps). Useful for KVM switches.");
+static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
+static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
+static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
+#define param_check_proto_abbrev(name, p)	__param_check(name, p, unsigned int)
+#define param_set_proto_abbrev			psmouse_set_maxproto
+#define param_get_proto_abbrev			psmouse_get_maxproto
+module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
+MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
 
 static unsigned int psmouse_resolution = 200;
-module_param_named(resolution, psmouse_resolution, uint, 0);
+module_param_named(resolution, psmouse_resolution, uint, 0644);
 MODULE_PARM_DESC(resolution, "Resolution, in dpi.");
 
 static unsigned int psmouse_rate = 100;
-module_param_named(rate, psmouse_rate, uint, 0);
+module_param_named(rate, psmouse_rate, uint, 0644);
 MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
 
 static unsigned int psmouse_smartscroll = 1;
-module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
+module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
 static unsigned int psmouse_resetafter;
-module_param_named(resetafter, psmouse_resetafter, uint, 0);
+module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
 PSMOUSE_DEFINE_ATTR(rate);
@@ -142,7 +147,7 @@
 static irqreturn_t psmouse_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct psmouse *psmouse = serio->private;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
 	psmouse_ret_t rc;
 
 	if (psmouse->state == PSMOUSE_IGNORE)
@@ -423,7 +428,7 @@
  * upsets the thinkingmouse).
  */
 
-	if (max_proto > PSMOUSE_PS2 && thinking_detect(psmouse, set_properties) == 0)
+	if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0)
 		return PSMOUSE_THINKPS;
 
 /*
@@ -634,7 +639,7 @@
 
 static void psmouse_cleanup(struct serio *serio)
 {
-	struct psmouse *psmouse = serio->private;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
 
 	psmouse_reset(psmouse);
 }
@@ -651,11 +656,11 @@
 	device_remove_file(&serio->dev, &psmouse_attr_resolution);
 	device_remove_file(&serio->dev, &psmouse_attr_resetafter);
 
-	psmouse = serio->private;
+	psmouse = serio_get_drvdata(serio);
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		if (parent->pt_deactivate)
 			parent->pt_deactivate(parent);
 	}
@@ -667,6 +672,7 @@
 
 	input_unregister_device(&psmouse->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(psmouse);
 }
 
@@ -674,29 +680,29 @@
  * psmouse_connect() is a callback from the serio module when
  * an unhandled serio port is found.
  */
-static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
+static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct psmouse *psmouse, *parent = NULL;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
-	    (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
-		return;
+	int retval;
 
 	/*
 	 * If this is a pass-through port deactivate parent so the device
 	 * connected to this port can be successfully identified
 	 */
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
 	}
 
-	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
+	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
+		retval = -ENOMEM;
 		goto out;
+	}
 
 	memset(psmouse, 0, sizeof(struct psmouse));
 
 	ps2_init(&psmouse->ps2dev, serio);
+	sprintf(psmouse->phys, "%s/input0", serio->phys);
 	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
@@ -704,17 +710,20 @@
 	psmouse->dev.dev = &serio->dev;
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
-	serio->private = psmouse;
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, psmouse);
+
+	retval = serio_open(serio, drv);
+	if (retval) {
+		serio_set_drvdata(serio, NULL);
 		kfree(psmouse);
-		serio->private = NULL;
 		goto out;
 	}
 
 	if (psmouse_probe(psmouse) < 0) {
 		serio_close(serio);
+		serio_set_drvdata(serio, NULL);
 		kfree(psmouse);
-		serio->private = NULL;
+		retval = -ENODEV;
 		goto out;
 	}
 
@@ -731,8 +740,6 @@
 
 	sprintf(psmouse->devname, "%s %s %s",
 		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
-	sprintf(psmouse->phys, "%s/input0",
-		serio->phys);
 
 	psmouse->dev.name = psmouse->devname;
 	psmouse->dev.phys = psmouse->phys;
@@ -756,26 +763,22 @@
 	device_create_file(&serio->dev, &psmouse_attr_resolution);
 	device_create_file(&serio->dev, &psmouse_attr_resetafter);
 
-	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);
-	}
-
 	psmouse_activate(psmouse);
 
+	retval = 0;
+
 out:
 	/* If this is a pass-through port the parent awaits to be activated */
 	if (parent)
 		psmouse_activate(parent);
+
+	return retval;
 }
 
 
 static int psmouse_reconnect(struct serio *serio)
 {
-	struct psmouse *psmouse = serio->private;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
 	struct psmouse *parent = NULL;
 	struct serio_driver *drv = serio->drv;
 	int rc = -1;
@@ -785,8 +788,8 @@
 		return -1;
 	}
 
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
 	}
 
@@ -820,12 +823,30 @@
 	return rc;
 }
 
+static struct serio_device_id psmouse_serio_ids[] = {
+	{
+		.type	= SERIO_8042,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_PS_PSTHRU,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, psmouse_serio_ids);
 
 static struct serio_driver psmouse_drv = {
 	.driver		= {
 		.name	= "psmouse",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= psmouse_serio_ids,
 	.interrupt	= psmouse_interrupt,
 	.connect	= psmouse_connect,
 	.reconnect	= psmouse_reconnect,
@@ -848,7 +869,7 @@
 		goto out;
 	}
 
-	retval = handler(serio->private, buf);
+	retval = handler(serio_get_drvdata(serio), buf);
 
 out:
 	serio_unpin_driver(serio);
@@ -859,7 +880,8 @@
 				ssize_t (*handler)(struct psmouse *, const char *, size_t))
 {
 	struct serio *serio = to_serio_port(dev);
-	struct psmouse *psmouse = serio->private, *parent = NULL;
+	struct psmouse *psmouse = serio_get_drvdata(serio);
+	struct psmouse *parent = NULL;
 	int retval;
 
 	retval = serio_pin_driver(serio);
@@ -871,8 +893,8 @@
 		goto out;
 	}
 
-	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
-		parent = serio->parent->private;
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
 	}
 	psmouse_deactivate(psmouse);
@@ -942,28 +964,45 @@
 	return count;
 }
 
-static inline void psmouse_parse_proto(void)
+static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
 {
-	if (psmouse_proto) {
-		if (!strcmp(psmouse_proto, "bare"))
-			psmouse_max_proto = PSMOUSE_PS2;
-		else if (!strcmp(psmouse_proto, "imps"))
-			psmouse_max_proto = PSMOUSE_IMPS;
-		else if (!strcmp(psmouse_proto, "exps"))
-			psmouse_max_proto = PSMOUSE_IMEX;
-		else
-			printk(KERN_ERR "psmouse: unknown protocol type '%s'\n", psmouse_proto);
+	int i;
+
+	if (!val)
+		return -EINVAL;
+
+	if (!strncmp(val, "any", 3)) {
+		*((unsigned int *)kp->arg) = -1UL;
+		return 0;
 	}
+
+	for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
+		if (!psmouse_proto_abbrev[i])
+			continue;
+
+		if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
+			*((unsigned int *)kp->arg) = i;
+			return 0;
+		}
+	}
+
+	return -EINVAL;					\
+}
+
+static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
+{
+	return sprintf(buffer, "%s\n",
+			psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
+				psmouse_proto_abbrev[psmouse_max_proto] : "any");
 }
 
-int __init psmouse_init(void)
+static int __init psmouse_init(void)
 {
-	psmouse_parse_proto();
 	serio_register_driver(&psmouse_drv);
 	return 0;
 }
 
-void __exit psmouse_exit(void)
+static void __exit psmouse_exit(void)
 {
 	serio_unregister_driver(&psmouse_drv);
 }
diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/psmouse.h	2005-03-07 15:26:30 -08:00
@@ -44,7 +44,7 @@
 	unsigned char pktcnt;
 	unsigned char pktsize;
 	unsigned char type;
-	unsigned char model;
+	unsigned int model;
 	unsigned long last;
 	unsigned long out_of_sync;
 	enum psmouse_state state;
diff -Nru a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
--- a/drivers/input/mouse/sermouse.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/sermouse.c	2005-03-07 15:26:30 -08:00
@@ -209,7 +209,7 @@
 static irqreturn_t sermouse_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct sermouse *sermouse = serio->private;
+	struct sermouse *sermouse = serio_get_drvdata(serio);
 
 	if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
 	sermouse->last = jiffies;
@@ -228,9 +228,11 @@
 
 static void sermouse_disconnect(struct serio *serio)
 {
-	struct sermouse *sermouse = serio->private;
+	struct sermouse *sermouse = serio_get_drvdata(serio);
+
 	input_unregister_device(&sermouse->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(sermouse);
 }
 
@@ -239,19 +241,17 @@
  * an unhandled serio port is found.
  */
 
-static void sermouse_connect(struct serio *serio, struct serio_driver *drv)
+static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct sermouse *sermouse;
 	unsigned char c;
+	int err;
 
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-
-	if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP))
-		return;
+	if (!serio->id.proto || serio->id.proto > SERIO_MZPP)
+		return -ENODEV;
 
 	if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(sermouse, 0, sizeof(struct sermouse));
 
@@ -261,10 +261,8 @@
 	sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 	sermouse->dev.private = sermouse;
 
-	serio->private = sermouse;
-
-	sermouse->type = serio->type & SERIO_PROTO;
-	c = (serio->type & SERIO_EXTRA) >> 16;
+	sermouse->type = serio->id.proto;
+	c = serio->id.extra;
 
 	if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit);
 	if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit);
@@ -282,33 +280,88 @@
 	sermouse->dev.id.version = 0x0100;
 	sermouse->dev.dev = &serio->dev;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, sermouse);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(sermouse);
-		return;
+		return err;
 	}
 
 	input_register_device(&sermouse->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
+
+	return 0;
 }
 
+static struct serio_device_id sermouse_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MSC,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_SUN,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MS,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MP,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MZ,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MZP,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MZPP,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, sermouse_serio_ids);
+
 static struct serio_driver sermouse_drv = {
 	.driver		= {
 		.name	= "sermouse",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= sermouse_serio_ids,
 	.interrupt	= sermouse_interrupt,
 	.connect	= sermouse_connect,
 	.disconnect	= sermouse_disconnect,
 };
 
-int __init sermouse_init(void)
+static int __init sermouse_init(void)
 {
 	serio_register_driver(&sermouse_drv);
 	return 0;
 }
 
-void __exit sermouse_exit(void)
+static void __exit sermouse_exit(void)
 {
 	serio_unregister_driver(&sermouse_drv);
 }
diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/synaptics.c	2005-03-07 15:26:30 -08:00
@@ -229,7 +229,7 @@
  ****************************************************************************/
 static int synaptics_pt_write(struct serio *serio, unsigned char c)
 {
-	struct psmouse *parent = serio->parent->private;
+	struct psmouse *parent = serio_get_drvdata(serio->parent);
 	char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
 
 	if (psmouse_sliced_command(parent, c))
@@ -246,7 +246,7 @@
 
 static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
 {
-	struct psmouse *child = ptport->private;
+	struct psmouse *child = serio_get_drvdata(ptport);
 
 	if (child && child->state == PSMOUSE_ACTIVATED) {
 		serio_interrupt(ptport, packet[1], 0, NULL);
@@ -260,7 +260,8 @@
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
 {
-	struct psmouse *child = psmouse->ps2dev.serio->child->private;
+	struct serio *ptport = psmouse->ps2dev.serio->child;
+	struct psmouse *child = serio_get_drvdata(ptport);
 	struct synaptics_data *priv = psmouse->private;
 
 	/* adjust the touchpad to child's choice of protocol */
@@ -287,7 +288,7 @@
 
 	memset(serio, 0, sizeof(struct serio));
 
-	serio->type = SERIO_PS_PSTHRU;
+	serio->id.type = SERIO_PS_PSTHRU;
 	strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
 	strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
 	serio->write = synaptics_pt_write;
@@ -295,7 +296,8 @@
 
 	psmouse->pt_activate = synaptics_pt_activate;
 
-	psmouse->ps2dev.serio->child = serio;
+	printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
+	serio_register_port(serio);
 }
 
 /*****************************************************************************
@@ -322,8 +324,11 @@
 		hw->left  = (buf[0] & 0x01) ? 1 : 0;
 		hw->right = (buf[0] & 0x02) ? 1 : 0;
 
-		if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
+		if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
 			hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+			if (hw->w == 2)
+				hw->scroll = (signed char)(buf[1]);
+		}
 
 		if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
 			hw->up   = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
@@ -379,6 +384,26 @@
 
 	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
+	if (hw.scroll) {
+		priv->scroll += hw.scroll;
+
+		while (priv->scroll >= 4) {
+			input_report_key(dev, BTN_BACK, !hw.down);
+			input_sync(dev);
+			input_report_key(dev, BTN_BACK, hw.down);
+			input_sync(dev);
+			priv->scroll -= 4;
+		}
+		while (priv->scroll <= -4) {
+			input_report_key(dev, BTN_FORWARD, !hw.up);
+			input_sync(dev);
+			input_report_key(dev, BTN_FORWARD, hw.up);
+			input_sync(dev);
+			priv->scroll += 4;
+		}
+		return;
+	}
+
 	if (hw.z > 0) {
 		num_fingers = 1;
 		finger_width = 5;
@@ -528,7 +553,8 @@
 	if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
 		set_bit(BTN_MIDDLE, dev->keybit);
 
-	if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
+	if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
+	    SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
 		set_bit(BTN_FORWARD, dev->keybit);
 		set_bit(BTN_BACK, dev->keybit);
 	}
@@ -551,6 +577,7 @@
 {
 	synaptics_reset(psmouse);
 	kfree(psmouse->private);
+	psmouse->private = NULL;
 }
 
 static int synaptics_reconnect(struct psmouse *psmouse)
@@ -604,6 +631,20 @@
 	return 0;
 }
 
+#if defined(__i386__)
+#include <linux/dmi.h>
+static struct dmi_system_id toshiba_dmi_table[] = {
+	{
+		.ident = "Toshiba Satellite",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"),
+		},
+	},
+	{ }
+};
+#endif
+
 int synaptics_init(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv;
@@ -625,9 +666,6 @@
 
 	priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
 
-	if (SYN_CAP_PASS_THROUGH(priv->capabilities))
-		synaptics_pt_create(psmouse);
-
 	print_ident(priv);
 	set_input_params(&psmouse->dev, priv);
 
@@ -636,6 +674,21 @@
 	psmouse->disconnect = synaptics_disconnect;
 	psmouse->reconnect = synaptics_reconnect;
 	psmouse->pktsize = 6;
+
+	if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+		synaptics_pt_create(psmouse);
+
+#if defined(__i386__)
+	/*
+	 * Toshiba's KBC seems to have trouble handling data from
+	 * Synaptics as full rate, switch to lower rate which is roughly
+	 * thye same as rate of standard PS/2 mouse.
+	 */
+	if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) {
+		printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n");
+		psmouse->rate = 40;
+	}
+#endif
 
 	return 0;
 
diff -Nru a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
--- a/drivers/input/mouse/synaptics.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/synaptics.h	2005-03-07 15:26:30 -08:00
@@ -92,6 +92,7 @@
 	unsigned int up:1;
 	unsigned int down:1;
 	unsigned char ext_buttons;
+	signed char scroll;
 };
 
 struct synaptics_data {
@@ -103,6 +104,7 @@
 
 	unsigned char pkt_type;			/* packet type - old, new, etc */
 	unsigned char mode;			/* current mode byte */
+	int scroll;
 };
 
 #endif /* _SYNAPTICS_H */
diff -Nru a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
--- a/drivers/input/mouse/vsxxxaa.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mouse/vsxxxaa.c	2005-03-07 15:26:30 -08:00
@@ -470,7 +470,7 @@
 vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
 		struct pt_regs *regs)
 {
-	struct vsxxxaa *mouse = serio->private;
+	struct vsxxxaa *mouse = serio_get_drvdata (serio);
 
 	vsxxxaa_queue_byte (mouse, data);
 	vsxxxaa_parse_buffer (mouse, regs);
@@ -481,25 +481,22 @@
 static void
 vsxxxaa_disconnect (struct serio *serio)
 {
-	struct vsxxxaa *mouse = serio->private;
+	struct vsxxxaa *mouse = serio_get_drvdata (serio);
 
 	input_unregister_device (&mouse->dev);
 	serio_close (serio);
+	serio_set_drvdata (serio, NULL);
 	kfree (mouse);
 }
 
-static void
+static int
 vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
 {
 	struct vsxxxaa *mouse;
-
-	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
-		return;
-	if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA)
-		return;
+	int err;
 
 	if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset (mouse, 0, sizeof (struct vsxxxaa));
 
@@ -522,7 +519,6 @@
 	mouse->dev.absmax[ABS_Y] = 1023;
 
 	mouse->dev.private = mouse;
-	serio->private = mouse;
 
 	sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer");
 	sprintf (mouse->phys, "%s/input0", serio->phys);
@@ -532,9 +528,13 @@
 	mouse->dev.dev = &serio->dev;
 	mouse->serio = serio;
 
-	if (serio_open (serio, drv)) {
+	serio_set_drvdata (serio, mouse);
+
+	err = serio_open (serio, drv);
+	if (err) {
+		serio_set_drvdata (serio, NULL);
 		kfree (mouse);
-		return;
+		return err;
 	}
 
 	/*
@@ -546,26 +546,41 @@
 	input_register_device (&mouse->dev);
 
 	printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys);
+
+	return 0;
 }
 
+static struct serio_device_id vsxxaa_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_VSXXXAA,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, vsxxaa_serio_ids);
+
 static struct serio_driver vsxxxaa_drv = {
 	.driver		= {
 		.name	= "vsxxxaa",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= vsxxaa_serio_ids,
 	.connect	= vsxxxaa_connect,
 	.interrupt	= vsxxxaa_interrupt,
 	.disconnect	= vsxxxaa_disconnect,
 };
 
-int __init
+static int __init
 vsxxxaa_init (void)
 {
 	serio_register_driver(&vsxxxaa_drv);
 	return 0;
 }
 
-void __exit
+static void __exit
 vsxxxaa_exit (void)
 {
 	serio_unregister_driver(&vsxxxaa_drv);
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/mousedev.c	2005-03-07 15:26:30 -08:00
@@ -71,6 +71,7 @@
 	struct mousedev_hw_data packet;
 	unsigned int pkt_count;
 	int old_x[4], old_y[4];
+	int frac_dx, frac_dy;
 	unsigned long touch;
 };
 
@@ -117,24 +118,31 @@
 
 static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
 {
-	int size;
+	int size, tmp;
+	enum { FRACTION_DENOM = 128 };
 
 	if (mousedev->touch) {
+		size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+		if (size == 0) size = 256 * 2;
 		switch (code) {
 			case ABS_X:
-				size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
-				if (size == 0) size = xres;
 				fx(0) = value;
-				if (mousedev->pkt_count >= 2)
-					mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) * xres / (size * 2);
+				if (mousedev->pkt_count >= 2) {
+					tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
+					tmp += mousedev->frac_dx;
+					mousedev->packet.dx = tmp / FRACTION_DENOM;
+					mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
+				}
 				break;
 
 			case ABS_Y:
-				size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
-				if (size == 0) size = yres;
 				fy(0) = value;
-				if (mousedev->pkt_count >= 2)
-					mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) * yres / (size * 2);
+				if (mousedev->pkt_count >= 2) {
+					tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
+					tmp += mousedev->frac_dy;
+					mousedev->packet.dy = tmp / FRACTION_DENOM;
+					mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
+				}
 				break;
 		}
 	}
@@ -268,6 +276,8 @@
 			clear_bit(0, &mousedev_mix.packet.buttons);
 		}
 		mousedev->touch = mousedev->pkt_count = 0;
+		mousedev->frac_dx = 0;
+		mousedev->frac_dy = 0;
 	}
 	else
 		if (!mousedev->touch)
@@ -445,7 +455,7 @@
 
 	switch (list->mode) {
 		case MOUSEDEV_EMUL_EXPS:
-			ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+			ps2_data[3] = mousedev_limit_delta(p->dz, 7);
 			p->dz -= ps2_data[3];
 			ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
 			list->bufsiz = 4;
@@ -585,12 +595,11 @@
 {
 	struct mousedev_list *list = file->private_data;
 	poll_wait(file, &list->mousedev->wait, wait);
-	if (list->ready || list->buffer)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
+		(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
-struct file_operations mousedev_fops = {
+static struct file_operations mousedev_fops = {
 	.owner =	THIS_MODULE,
 	.read =		mousedev_read,
 	.write =	mousedev_write,
@@ -643,6 +652,7 @@
 static void mousedev_disconnect(struct input_handle *handle)
 {
 	struct mousedev *mousedev = handle->private;
+	struct mousedev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
 	devfs_remove("input/mouse%d", mousedev->minor);
@@ -650,6 +660,9 @@
 
 	if (mousedev->open) {
 		input_close_device(handle);
+		wake_up_interruptible(&mousedev->wait);
+		list_for_each_entry(list, &mousedev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 	} else {
 		if (mousedev_mix.open)
 			input_close_device(handle);
diff -Nru a/drivers/input/power.c b/drivers/input/power.c
--- a/drivers/input/power.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/power.c	2005-03-07 15:26:30 -08:00
@@ -58,8 +58,6 @@
 
 	printk("Entering power_event\n");
 
-	if (type != EV_KEY || type != EV_PWR) return;
-
 	if (type == EV_PWR) {
 		switch (code) {
 			case KEY_SUSPEND:
@@ -76,7 +74,9 @@
 			default:
 				return;
 		}
-	} else {
+	}
+
+	if (type == EV_KEY) {
 		switch (code) {
 			case KEY_SUSPEND:
 				printk("Powering down input device\n");
@@ -102,12 +102,6 @@
 					  struct input_device_id *id)
 {
 	struct input_handle *handle;
-
-	if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit))
-		return NULL;
-
-	if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit)))
-		return NULL;
 
 	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
 		return NULL;
diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/Kconfig	2005-03-07 15:26:30 -08:00
@@ -2,11 +2,11 @@
 # Input core configuration
 #
 config SERIO
-	tristate "Serial i/o support" if EMBEDDED || !X86
+	tristate "Serial I/O support" if EMBEDDED || !X86
 	default y
 	---help---
 	  Say Yes here if you have any input device that uses serial I/O to
-	  communicate with the system. This includes the 
+	  communicate with the system. This includes the
 	  		* standard AT keyboard and PS/2 mouse *
 	  as well as serial mice, Sun keyboards, some joysticks and 6dof
 	  devices and more.
@@ -16,10 +16,11 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called serio.
 
+if SERIO
+
 config SERIO_I8042
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
-	select SERIO
 	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K
 	---help---
 	  i8042 is the chip over which the standard AT keyboard and PS/2
@@ -34,7 +35,6 @@
 config SERIO_SERPORT
 	tristate "Serial port line discipline"
 	default y
-	depends on SERIO
 	---help---
 	  Say Y here if you plan to use an input device (mouse, joystick,
 	  tablet, 6dof) that communicates over the RS232 serial (COM) port.
@@ -48,8 +48,7 @@
 
 config SERIO_CT82C710
 	tristate "ct82c710 Aux port controller"
-	depends on SERIO
-	depends on !PARISC
+	depends on X86
 	---help---
 	  Say Y here if you have a Texas Instruments TravelMate notebook
 	  equipped with the ct82c710 chip and want to use a mouse connected
@@ -62,11 +61,11 @@
 
 config SERIO_Q40KBD
 	tristate "Q40 keyboard controller"
-	depends on Q40 && SERIO
+	depends on Q40
 
 config SERIO_PARKBD
 	tristate "Parallel port keyboard adapter"
-	depends on SERIO && PARPORT
+	depends on PARPORT
 	---help---
 	  Say Y here if you built a simple parallel port adapter to attach
 	  an additional AT keyboard, XT keyboard or PS/2 mouse.
@@ -80,7 +79,7 @@
 
 config SERIO_RPCKBD
 	tristate "Acorn RiscPC keyboard controller"
-	depends on (ARCH_ACORN || ARCH_CLPS7500) && SERIO
+	depends on ARCH_ACORN || ARCH_CLPS7500
 	default y
 	help
 	  Say Y here if you have the Acorn RiscPC and want to use an AT
@@ -91,15 +90,15 @@
 
 config SERIO_AMBAKMI
 	tristate "AMBA KMI keyboard controller"
-	depends on ARM_AMBA && SERIO
+	depends on ARM_AMBA
 
 config SERIO_SA1111
 	tristate "Intel SA1111 keyboard controller"
-	depends on SA1111 && SERIO
+	depends on SA1111
 
 config SERIO_GSCPS2
 	tristate "HP GSC PS/2 keyboard and PS/2 mouse controller"
-	depends on GSC && SERIO
+	depends on GSC
 	default y
 	help
 	  This driver provides support for the PS/2 ports on PA-RISC machines
@@ -111,9 +110,35 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called gscps2.
 
+config HP_SDC
+	tristate "HP System Device Controller i8042 Support"
+	depends on GSC && SERIO
+	default y
+	---help---
+	  This option enables supports for the the "System Device
+	  Controller", an i8042 carrying microcode to manage a
+	  few miscellanous devices on some Hewlett Packard systems.
+	  The SDC itself contains a 10ms resolution timer/clock capable
+	  of delivering interrupts on a periodic and one-shot basis.
+	  The SDC may also be connected to a battery-backed real-time
+	  clock, a basic audio waveform generator, and an HP-HIL Master
+	  Link Controller serving up to seven input devices.
+
+	  By itself this option is rather useless, but enabling it will
+	  enable selection of drivers for the abovementioned devices.
+	  It is, however, incompatible with the old, reliable HIL keyboard
+	  driver, and the new HIL driver is experimental, so if you plan
+	  to use a HIL keyboard as your primary keyboard, you may wish
+	  to keep using that driver until the new HIL drivers have had
+	  more testing.
+
+config HIL_MLC
+	tristate "HIL MLC Support (needed for HIL input devices)"
+	depends on HP_SDC
+
 config SERIO_PCIPS2
 	tristate "PCI PS/2 keyboard and PS/2 mouse controller"
-	depends on PCI && SERIO
+	depends on PCI
 	help
 	  Say Y here if you have a Mobility Docking station with PS/2
 	  keyboard and mice ports.
@@ -123,7 +148,7 @@
 
 config SERIO_MACEPS2
 	tristate "SGI O2 MACE PS/2 controller"
-	depends on SGI_IP32 && SERIO
+	depends on SGI_IP32
 	help
 	  Say Y here if you have SGI O2 workstation and want to use its
 	  PS/2 ports.
@@ -133,7 +158,6 @@
 
 config SERIO_LIBPS2
 	tristate "PS/2 driver library" if EMBEDDED
-	depends on SERIO
 	help
 	  Say Y here if you are using a driver for device connected
 	  to a PS/2 port, such as PS/2 mouse or standard AT keyboard.
@@ -143,7 +167,6 @@
 
 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
@@ -156,3 +179,5 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called serio_raw.
+
+endif
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/Makefile	2005-03-07 15:26:30 -08:00
@@ -15,6 +15,8 @@
 obj-$(CONFIG_SERIO_Q40KBD)	+= q40kbd.o
 obj-$(CONFIG_SERIO_98KBD)	+= 98kbd-io.o
 obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
+obj-$(CONFIG_HP_SDC)		+= hp_sdc.o
+obj-$(CONFIG_HIL_MLC)		+= hp_sdc_mlc.o hil_mlc.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
 obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
diff -Nru a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
--- a/drivers/input/serio/ambakmi.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/ambakmi.c	2005-03-07 15:26:30 -08:00
@@ -134,7 +134,7 @@
 	memset(kmi, 0, sizeof(struct amba_kmi_port));
 	memset(io, 0, sizeof(struct serio));
 
-	io->type	= SERIO_8042;
+	io->id.type	= SERIO_8042;
 	io->write	= amba_kmi_write;
 	io->open	= amba_kmi_open;
 	io->close	= amba_kmi_close;
diff -Nru a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
--- a/drivers/input/serio/ct82c710.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/ct82c710.c	2005-03-07 15:26:30 -08:00
@@ -181,7 +181,7 @@
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type = SERIO_8042;
+		serio->id.type = SERIO_8042;
 		serio->open = ct82c710_open;
 		serio->close = ct82c710_close;
 		serio->write = ct82c710_write;
@@ -193,7 +193,7 @@
 	return serio;
 }
 
-int __init ct82c710_init(void)
+static int __init ct82c710_init(void)
 {
 	if (ct82c710_probe())
 		return -ENODEV;
@@ -215,7 +215,7 @@
 	return 0;
 }
 
-void __exit ct82c710_exit(void)
+static void __exit ct82c710_exit(void)
 {
 	serio_unregister_port(ct82c710_port);
 	platform_device_unregister(ct82c710_device);
diff -Nru a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
--- a/drivers/input/serio/gscps2.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/gscps2.c	2005-03-07 15:26:30 -08:00
@@ -38,7 +38,7 @@
 #include <asm/parisc-device.h>
 
 MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@esiee.fr>, Helge Deller <deller@gmx.de>");
-MODULE_DESCRIPTION("HP GSC PS/2 port driver");
+MODULE_DESCRIPTION("HP GSC PS2 port driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
 
@@ -363,11 +363,7 @@
 	snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s",
 		 (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse");
 	strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
-	serio->idbus		= BUS_GSC;
-	serio->idvendor		= PCI_VENDOR_ID_HP;
-	serio->idproduct	= 0x0001;
-	serio->idversion	= 0x0010;
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= gscps2_write;
 	serio->open		= gscps2_open;
 	serio->close		= gscps2_close;
@@ -448,7 +444,7 @@
 };
 
 static struct parisc_driver parisc_ps2_driver = {
-	.name		= "GSC PS/2",
+	.name		= "GSC PS2",
 	.id_table	= gscps2_device_tbl,
 	.probe		= gscps2_probe,
 	.remove		= gscps2_remove,
diff -Nru a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/serio/hil_mlc.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,949 @@
+/*
+ * HIL MLC state machine and serio interface driver
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ *
+ *
+ *	Driver theory of operation:
+ *
+ *	Some access methods and an ISR is defined by the sub-driver 
+ *	(e.g. hp_sdc_mlc.c).  These methods are expected to provide a 
+ *	few bits of logic in addition to raw access to the HIL MLC, 
+ *	specifically, the ISR, which is entirely registered by the 
+ *	sub-driver and invoked directly, must check for record 
+ *	termination or packet match, at which point a semaphore must
+ *	be cleared and then the hil_mlcs_tasklet must be scheduled.
+ *
+ *	The hil_mlcs_tasklet processes the state machine for all MLCs
+ *	each time it runs, checking each MLC's progress at the current
+ *	node in the state machine, and moving the MLC to subsequent nodes
+ *	in the state machine when appropriate.  It will reschedule
+ *	itself if output is pending.  (This rescheduling should be replaced
+ *	at some point with a sub-driver-specific mechanism.)
+ *
+ *	A timer task prods the tasklet once per second to prevent 
+ *	hangups when attached devices do not return expected data
+ *	and to initiate probes of the loop for new devices.
+ */
+
+#include <linux/hil_mlc.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("HIL MLC serio");
+MODULE_LICENSE("Dual BSD/GPL");
+
+EXPORT_SYMBOL(hil_mlc_register);
+EXPORT_SYMBOL(hil_mlc_unregister);
+
+#define PREFIX "HIL MLC: "
+
+static LIST_HEAD(hil_mlcs);
+static rwlock_t			hil_mlcs_lock = RW_LOCK_UNLOCKED;
+static struct timer_list	hil_mlcs_kicker;
+static int			hil_mlcs_probe;
+
+static void hil_mlcs_process(unsigned long unused);
+DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
+
+
+/* #define HIL_MLC_DEBUG */
+
+/********************** Device info/instance management **********************/
+
+static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) {
+	int j;
+	for (j = val; j < 7 ; j++) {
+		mlc->di_map[j] = -1;
+	}
+}
+
+static void hil_mlc_clear_di_scratch (hil_mlc *mlc) {
+	memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch));
+}
+
+static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) {
+	memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch));
+}
+
+static int hil_mlc_match_di_scratch (hil_mlc *mlc) {
+	int idx;
+
+	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
+		int j, found;
+
+		/* In-use slots are not eligible. */
+		found = 0;
+		for (j = 0; j < 7 ; j++) {
+			if (mlc->di_map[j] == idx) found++;
+		}
+		if (found) continue;
+		if (!memcmp(mlc->di + idx, 
+			    &(mlc->di_scratch), 
+			    sizeof(mlc->di_scratch))) break;
+	}
+	return((idx >= HIL_MLC_DEVMEM) ? -1 : idx);
+}
+
+static int hil_mlc_find_free_di(hil_mlc *mlc) {
+	int idx;
+	/* TODO: Pick all-zero slots first, failing that, 
+	 * randomize the slot picked among those eligible. 
+	 */
+	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
+		int j, found;
+		found = 0;
+		for (j = 0; j < 7 ; j++) {
+			if (mlc->di_map[j] == idx) found++;
+		}
+		if (!found) break;
+	}
+	return(idx); /* Note: It is guaranteed at least one above will match */
+}
+
+static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) {
+	int idx;
+	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
+		int j, found;
+		found = 0;
+		for (j = 0; j < 7 ; j++) {
+			if (mlc->di_map[j] == idx) found++;
+		}
+		if (!found) mlc->serio_map[idx].di_revmap = -1;
+	}
+}
+
+static void hil_mlc_send_polls(hil_mlc *mlc) {
+	int did, i, cnt;
+	struct serio *serio;
+	struct serio_driver *drv;
+
+	i = cnt = 0;
+	did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8;
+	serio = did ? mlc->serio[mlc->di_map[did - 1]] : NULL;
+	drv = (serio != NULL) ? serio->drv : NULL;
+
+	while (mlc->icount < 15 - i) {
+		hil_packet p;
+		p = mlc->ipacket[i];
+		if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
+			if (drv == NULL || drv->interrupt == NULL) goto skip;
+
+			drv->interrupt(serio, 0, 0, NULL);
+			drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+			drv->interrupt(serio, HIL_PKT_CMD >> 8,  0, NULL);
+			drv->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL);
+		skip:
+			did = (p & HIL_PKT_ADDR_MASK) >> 8;
+			serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
+			drv = (serio != NULL) ? serio->drv : NULL;
+			cnt = 0;
+		}
+		cnt++; i++;
+		if (drv == NULL || drv->interrupt == NULL) continue;
+		drv->interrupt(serio, (p >> 24), 0, NULL);
+		drv->interrupt(serio, (p >> 16) & 0xff, 0, NULL);
+		drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL);
+		drv->interrupt(serio, p & 0xff, 0, NULL);
+	}
+}
+
+/*************************** State engine *********************************/
+
+#define HILSEN_SCHED	0x000100	/* Schedule the tasklet		*/
+#define HILSEN_BREAK	0x000200	/* Wait until next pass		*/
+#define HILSEN_UP	0x000400	/* relative node#, decrement	*/
+#define HILSEN_DOWN	0x000800	/* relative node#, increment	*/
+#define HILSEN_FOLLOW	0x001000	/* use retval as next node#	*/
+
+#define HILSEN_MASK	0x0000ff
+#define HILSEN_START	0
+#define HILSEN_RESTART	1
+#define HILSEN_DHR	9
+#define HILSEN_DHR2	10
+#define HILSEN_IFC	14
+#define HILSEN_HEAL0	16
+#define HILSEN_HEAL	18
+#define HILSEN_ACF      21
+#define HILSEN_ACF2	22
+#define HILSEN_DISC0	25
+#define HILSEN_DISC	27
+#define HILSEN_MATCH	40
+#define HILSEN_OPERATE	41
+#define HILSEN_PROBE	44
+#define HILSEN_DSR	52
+#define HILSEN_REPOLL	55
+#define HILSEN_IFCACF	58
+#define HILSEN_END	60
+
+#define HILSEN_NEXT	(HILSEN_DOWN | 1)
+#define HILSEN_SAME	(HILSEN_DOWN | 0)
+#define HILSEN_LAST	(HILSEN_UP | 1)
+
+#define HILSEN_DOZE	(HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
+#define HILSEN_SLEEP	(HILSEN_SAME | HILSEN_BREAK)
+
+static int hilse_match(hil_mlc *mlc, int unused) {
+	int rc;
+	rc = hil_mlc_match_di_scratch(mlc);
+	if (rc == -1) {
+		rc = hil_mlc_find_free_di(mlc);
+		if (rc == -1) goto err;
+#ifdef HIL_MLC_DEBUG
+		printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
+#endif
+		hil_mlc_copy_di_scratch(mlc, rc);
+		mlc->di_map[mlc->ddi] = rc;
+		mlc->serio_map[rc].di_revmap = mlc->ddi;
+		hil_mlc_clean_serio_map(mlc);
+		serio_rescan(mlc->serio[rc]);
+		return -1;
+	}
+	mlc->di_map[mlc->ddi] = rc;
+#ifdef HIL_MLC_DEBUG
+	printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
+#endif
+	mlc->serio_map[rc].di_revmap = mlc->ddi;
+	hil_mlc_clean_serio_map(mlc);
+	return 0;
+ err:
+	printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
+	return 1;
+}
+
+/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
+static int hilse_init_lcv(hil_mlc *mlc, int unused) {
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+
+	if(mlc->lcv == 0) goto restart;  /* First init, no need to dally */
+	if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1;
+ restart:
+	mlc->lcv_tv = tv;
+	mlc->lcv = 0;
+	return 0;
+}
+
+static int hilse_inc_lcv(hil_mlc *mlc, int lim) {
+	if (mlc->lcv++ >= lim) return -1;
+	return 0;
+}
+
+#if 0
+static int hilse_set_lcv(hil_mlc *mlc, int val) {
+	mlc->lcv = val;
+	return 0;
+}
+#endif
+
+/* Management of the discovered device index (zero based, -1 means no devs) */
+static int hilse_set_ddi(hil_mlc *mlc, int val) {
+	mlc->ddi = val;
+	hil_mlc_clear_di_map(mlc, val + 1);
+	return 0;
+}
+
+static int hilse_dec_ddi(hil_mlc *mlc, int unused) {
+	mlc->ddi--;
+	if (mlc->ddi <= -1) { 
+		mlc->ddi = -1;
+		hil_mlc_clear_di_map(mlc, 0);
+		return -1;
+	}
+	hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
+	return 0;
+}
+
+static int hilse_inc_ddi(hil_mlc *mlc, int unused) {
+	if (mlc->ddi >= 6) {
+		BUG();
+		return -1;
+	}
+	mlc->ddi++;
+	return 0;
+}
+
+static int hilse_take_idd(hil_mlc *mlc, int unused) {
+	int i;
+
+	/* Help the state engine: 
+	 * Is this a real IDD response or just an echo? 
+	 *
+	 * Real IDD response does not start with a command. 
+	 */
+	if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail;
+	/* Should have the command echoed further down. */
+	for (i = 1; i < 16; i++) {
+		if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == 
+		     (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) &&
+		    (mlc->ipacket[i] & HIL_PKT_CMD) && 
+		    ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
+			break;
+	}
+	if (i > 15) goto bail;
+	/* And the rest of the packets should still be clear. */
+	while (++i < 16) {
+		if (mlc->ipacket[i]) break;
+	}
+	if (i < 16) goto bail;
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.idd[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	/* Next step is to see if RSC supported */
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) 
+		return HILSEN_NEXT;
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) 
+		return HILSEN_DOWN | 4;
+	return 0;
+ bail:
+	mlc->ddi--;
+	return -1; /* This should send us off to ACF */
+}
+
+static int hilse_take_rsc(hil_mlc *mlc, int unused) {
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.rsc[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	/* Next step is to see if EXD supported (IDD has already been read) */
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) 
+		return HILSEN_NEXT;
+	return 0;
+}
+
+static int hilse_take_exd(hil_mlc *mlc, int unused) {
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.exd[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	/* Next step is to see if RNM supported. */
+	if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) 
+		return HILSEN_NEXT;
+	return 0;
+}
+
+static int hilse_take_rnm(hil_mlc *mlc, int unused) {
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		mlc->di_scratch.rnm[i] = 
+			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
+	}
+	do {
+	  char nam[17];
+	  snprintf(nam, 16, "%s", mlc->di_scratch.rnm);
+	  nam[16] = '\0';
+	  printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam);
+	} while (0);
+	return 0;
+}
+
+static int hilse_operate(hil_mlc *mlc, int repoll) { 
+
+	if (mlc->opercnt == 0) hil_mlcs_probe = 0;
+	mlc->opercnt = 1;
+
+	hil_mlc_send_polls(mlc);
+
+	if (!hil_mlcs_probe) return 0;
+	hil_mlcs_probe = 0;
+	mlc->opercnt = 0;
+	return 1;
+}
+
+#define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \
+{ HILSE_FUNC,		{ func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc },
+#define OUT(pack) \
+{ HILSE_OUT,		{ packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 },
+#define CTS \
+{ HILSE_CTS,		{ packet: 0    }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 },
+#define EXPECT(comp, to, got, got_wrong, timed_out) \
+{ HILSE_EXPECT,		{ packet: comp }, to, got, got_wrong, timed_out },
+#define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \
+{ HILSE_EXPECT_LAST,	{ packet: comp }, to, got, got_wrong, timed_out },
+#define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \
+{ HILSE_EXPECT_DISC,	{ packet: comp }, to, got, got_wrong, timed_out },
+#define IN(to, got, got_error, timed_out) \
+{ HILSE_IN,		{ packet: 0    }, to, got, got_error, timed_out },
+#define OUT_DISC(pack) \
+{ HILSE_OUT_DISC,	{ packet: pack }, 0, 0, 0, 0 },
+#define OUT_LAST(pack) \
+{ HILSE_OUT_LAST,	{ packet: pack }, 0, 0, 0, 0 },
+
+struct hilse_node hil_mlc_se[HILSEN_END] = {
+
+	/* 0  HILSEN_START */
+	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_SLEEP,	0)
+
+	/* 1  HILSEN_RESTART */
+	FUNC(hilse_inc_lcv, 10,	HILSEN_NEXT,	HILSEN_START,  0)
+	OUT(HIL_CTRL_ONLY)			/* Disable APE */
+	CTS
+
+#define TEST_PACKET(x) \
+(HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT) | x << 4 | x)
+
+	OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0x5))
+	EXPECT(HIL_ERR_INT | TEST_PACKET(0x5),
+	       2000,		HILSEN_NEXT,	HILSEN_RESTART,	HILSEN_RESTART)
+	OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0xa))
+	EXPECT(HIL_ERR_INT | TEST_PACKET(0xa),
+	       2000,		HILSEN_NEXT,	HILSEN_RESTART,	HILSEN_RESTART)
+	OUT(HIL_CTRL_ONLY | 0)			/* Disable test mode */
+	
+	/* 9  HILSEN_DHR */
+	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_SLEEP,	0)
+
+	/* 10 HILSEN_DHR2 */
+	FUNC(hilse_inc_lcv, 10,	HILSEN_NEXT,	HILSEN_START,	0)
+	FUNC(hilse_set_ddi, -1,	HILSEN_NEXT,	0,		0)
+	OUT(HIL_PKT_CMD | HIL_CMD_DHR)
+	IN(300000,		HILSEN_DHR2,	HILSEN_DHR2,	HILSEN_NEXT)
+
+	/* 14 HILSEN_IFC */
+  	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
+	       20000,		HILSEN_DISC,	HILSEN_DHR2,	HILSEN_NEXT )
+
+	/* If devices are there, they weren't in PUP or other loopback mode.
+	 * We're more concerned at this point with restoring operation
+	 * to devices than discovering new ones, so we try to salvage
+	 * the loop configuration by closing off the loop.
+	 */
+
+	/* 16 HILSEN_HEAL0 */
+	FUNC(hilse_dec_ddi, 0,	HILSEN_NEXT,	HILSEN_ACF,	0)
+	FUNC(hilse_inc_ddi, 0,	HILSEN_NEXT,	0,		0)
+
+	/* 18 HILSEN_HEAL */
+	OUT_LAST(HIL_CMD_ELB)
+	EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, 
+		    20000,	HILSEN_REPOLL,	HILSEN_DSR,	HILSEN_NEXT)
+	FUNC(hilse_dec_ddi, 0,	HILSEN_HEAL,	HILSEN_NEXT,	0)
+
+	/* 21 HILSEN_ACF */
+	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_DOZE,	0)
+
+	/* 22 HILSEN_ACF2 */
+	FUNC(hilse_inc_lcv, 10,	HILSEN_NEXT,	HILSEN_START,	0)
+	OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
+	IN(20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)
+
+	/* 25 HILSEN_DISC0 */
+	OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
+	EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_ELB | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+
+	/* Only enter here if response just received */
+	/* 27 HILSEN_DISC */
+	OUT_DISC(HIL_PKT_CMD | HIL_CMD_IDD)
+	EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_IDD | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_START)
+	FUNC(hilse_inc_ddi,  0,	HILSEN_NEXT,	HILSEN_START,	0)
+	FUNC(hilse_take_idd, 0,	HILSEN_MATCH,	HILSEN_IFCACF,	HILSEN_FOLLOW)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_RSC)
+	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RSC | HIL_ERR_INT,
+	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+	FUNC(hilse_take_rsc, 0,	HILSEN_MATCH,	0,		HILSEN_FOLLOW)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_EXD)
+	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_EXD | HIL_ERR_INT,
+	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+	FUNC(hilse_take_exd, 0,	HILSEN_MATCH,	0,		HILSEN_FOLLOW)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_RNM)
+	EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RNM | HIL_ERR_INT,
+	       30000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_DSR)
+	FUNC(hilse_take_rnm, 0, HILSEN_MATCH,	0,		0)
+
+	/* 40 HILSEN_MATCH */
+	FUNC(hilse_match, 0,	HILSEN_NEXT,	HILSEN_NEXT,	/* TODO */ 0)
+
+	/* 41 HILSEN_OPERATE */
+	OUT(HIL_PKT_CMD | HIL_CMD_POL)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_POL | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)
+	FUNC(hilse_operate, 0,	HILSEN_OPERATE,	HILSEN_IFC,	HILSEN_NEXT)
+
+	/* 44 HILSEN_PROBE */
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT)
+	IN(10000, 		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)
+	OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
+	IN(10000,		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)
+	OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
+	IN(10000,		HILSEN_DISC0,	HILSEN_DSR,	HILSEN_NEXT)
+	OUT_LAST(HIL_PKT_CMD | HIL_CMD_ELB)
+	IN(10000,		HILSEN_OPERATE,	HILSEN_DSR,	HILSEN_DSR)
+
+	/* 52 HILSEN_DSR */
+	FUNC(hilse_set_ddi, -1,	HILSEN_NEXT,	0,		0)
+	OUT(HIL_PKT_CMD | HIL_CMD_DSR)
+	IN(20000, 		HILSEN_DHR,	HILSEN_DHR,	HILSEN_IFC)
+
+	/* 55 HILSEN_REPOLL */
+	OUT(HIL_PKT_CMD | HIL_CMD_RPL)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_RPL | HIL_ERR_INT,
+	       20000,		HILSEN_NEXT,	HILSEN_DSR,	HILSEN_NEXT)
+	FUNC(hilse_operate, 1,	HILSEN_OPERATE,	HILSEN_IFC,	HILSEN_PROBE)
+
+	/* 58 HILSEN_IFCACF */
+  	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+	EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
+	       20000,		HILSEN_ACF2,	HILSEN_DHR2,	HILSEN_HEAL)
+
+	/* 60 HILSEN_END */
+};
+
+static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) {
+
+	switch (node->act) {
+	case HILSE_EXPECT_DISC:
+		mlc->imatch = node->object.packet;
+		mlc->imatch |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
+		break;
+	case HILSE_EXPECT_LAST:
+		mlc->imatch = node->object.packet;
+		mlc->imatch |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
+		break;
+	case HILSE_EXPECT:
+		mlc->imatch = node->object.packet;
+		break;
+	case HILSE_IN:
+		mlc->imatch = 0;
+		break;
+	default:
+		BUG();
+	}
+	mlc->istarted = 1;
+	mlc->intimeout = node->arg;
+	do_gettimeofday(&(mlc->instart));
+	mlc->icount = 15;
+	memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
+	if (down_trylock(&(mlc->isem))) BUG();
+
+	return;
+}
+
+#ifdef HIL_MLC_DEBUG
+static int doze = 0;
+static int seidx; /* For debug */
+static int kick = 1;
+#endif
+
+static int hilse_donode (hil_mlc *mlc) {
+	struct hilse_node *node;
+	int nextidx = 0;
+	int sched_long = 0;
+	unsigned long flags;
+
+#ifdef HIL_MLC_DEBUG
+	if (mlc->seidx && (mlc->seidx != seidx)  && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
+	  printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx);
+		doze = 0;
+	}
+	kick = 0;
+
+	seidx = mlc->seidx;
+#endif
+	node = hil_mlc_se + mlc->seidx;
+
+	switch (node->act) {
+		int rc;
+		hil_packet pack;
+
+	case HILSE_FUNC:
+		if (node->object.func == NULL) break;
+		rc = node->object.func(mlc, node->arg);
+		nextidx = (rc > 0) ? node->ugly : 
+			((rc < 0) ? node->bad : node->good);
+		if (nextidx == HILSEN_FOLLOW) nextidx = rc;
+		break;
+	case HILSE_EXPECT_LAST:
+	case HILSE_EXPECT_DISC:
+	case HILSE_EXPECT:
+	case HILSE_IN:
+		/* Already set up from previous HILSE_OUT_* */
+		write_lock_irqsave(&(mlc->lock), flags);
+		rc = mlc->in(mlc, node->arg);
+		if (rc == 2)  {
+			nextidx = HILSEN_DOZE;
+			sched_long = 1;
+			write_unlock_irqrestore(&(mlc->lock), flags);
+			break;
+		}
+		if (rc == 1)		nextidx = node->ugly;
+		else if (rc == 0)	nextidx = node->good;
+		else			nextidx = node->bad;
+		mlc->istarted = 0;
+		write_unlock_irqrestore(&(mlc->lock), flags);
+		break;
+	case HILSE_OUT_LAST:
+		write_lock_irqsave(&(mlc->lock), flags);
+		pack = node->object.packet;
+		pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
+		goto out;
+	case HILSE_OUT_DISC:
+		write_lock_irqsave(&(mlc->lock), flags);
+		pack = node->object.packet;
+		pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
+		goto out;
+	case HILSE_OUT:
+		write_lock_irqsave(&(mlc->lock), flags);
+		pack = node->object.packet;
+	out:
+		if (mlc->istarted) goto out2;
+		/* Prepare to receive input */
+		if ((node + 1)->act & HILSE_IN)
+			hilse_setup_input(mlc, node + 1);
+
+	out2:
+		write_unlock_irqrestore(&(mlc->lock), flags);
+
+		if (down_trylock(&mlc->osem)) {
+			nextidx = HILSEN_DOZE;
+			break;
+		}
+		up(&mlc->osem);
+
+		write_lock_irqsave(&(mlc->lock), flags);
+		if (!(mlc->ostarted)) {
+			mlc->ostarted = 1;
+			mlc->opacket = pack;
+			mlc->out(mlc);
+			nextidx = HILSEN_DOZE;
+			write_unlock_irqrestore(&(mlc->lock), flags);
+			break;
+		}
+		mlc->ostarted = 0;
+		do_gettimeofday(&(mlc->instart));
+		write_unlock_irqrestore(&(mlc->lock), flags);
+		nextidx = HILSEN_NEXT;
+		break;
+	case HILSE_CTS:
+		nextidx = mlc->cts(mlc) ? node->bad : node->good;
+		break;
+	default:
+		BUG();
+		nextidx = 0;
+		break;
+	}
+
+#ifdef HIL_MLC_DEBUG
+	if (nextidx == HILSEN_DOZE) doze++;
+#endif
+
+	while (nextidx & HILSEN_SCHED) {
+		struct timeval tv;
+
+		if (!sched_long) goto sched;
+
+		do_gettimeofday(&tv);
+		tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+		tv.tv_usec -= mlc->instart.tv_usec;
+		if (tv.tv_usec >= mlc->intimeout) goto sched;
+		tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000;
+		if (!tv.tv_usec) goto sched;
+		mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
+		break;
+	sched:
+		tasklet_schedule(&hil_mlcs_tasklet);
+		break;
+	} 
+	if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK;
+	else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK;
+	else mlc->seidx = nextidx & HILSEN_MASK;
+
+	if (nextidx & HILSEN_BREAK)	return 1;
+	return 0;
+}
+
+/******************** tasklet context functions **************************/
+static void hil_mlcs_process(unsigned long unused) {
+	struct list_head *tmp;
+
+	read_lock(&hil_mlcs_lock);
+	list_for_each(tmp, &hil_mlcs) {
+		struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);
+		while (hilse_donode(mlc) == 0) {
+#ifdef HIL_MLC_DEBUG
+		  if (mlc->seidx != 41 && 
+		      mlc->seidx != 42 && 
+		      mlc->seidx != 43) 
+		    printk(KERN_DEBUG PREFIX " + ");
+#endif
+		};
+	}
+	read_unlock(&hil_mlcs_lock);
+}
+
+/************************* Keepalive timer task *********************/
+
+void hil_mlcs_timer (unsigned long data) {
+	hil_mlcs_probe = 1;
+	tasklet_schedule(&hil_mlcs_tasklet);
+	/* Re-insert the periodic task. */
+	if (!timer_pending(&hil_mlcs_kicker))
+		mod_timer(&hil_mlcs_kicker, jiffies + HZ);
+}
+
+/******************** user/kernel context functions **********************/
+
+static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
+	struct hil_mlc_serio_map *map;
+	struct hil_mlc *mlc;
+	struct serio_driver *drv;
+	uint8_t *idx, *last;
+
+	map = serio->port_data;
+	if (map == NULL) {
+		BUG();
+		return -EIO;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return -EIO;
+	}
+	mlc->serio_opacket[map->didx] |= 
+		((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
+
+	if (mlc->serio_oidx[map->didx] >= 3) {
+		/* for now only commands */
+		if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) 
+			return -EIO;
+		switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {
+		case HIL_CMD_IDD:
+			idx = mlc->di[map->didx].idd;
+			goto emu;
+		case HIL_CMD_RSC:
+			idx = mlc->di[map->didx].rsc;
+			goto emu;
+		case HIL_CMD_EXD:
+			idx = mlc->di[map->didx].exd;
+			goto emu;
+		case HIL_CMD_RNM:
+			idx = mlc->di[map->didx].rnm;
+			goto emu;
+		default:
+			break;
+		}
+		mlc->serio_oidx[map->didx] = 0;
+		mlc->serio_opacket[map->didx] = 0;
+	}
+
+	mlc->serio_oidx[map->didx]++;
+	return -EIO;
+ emu:
+	drv = serio->drv;
+	if (drv == NULL) {
+		BUG();
+		return -EIO;
+	}
+	last = idx + 15;
+	while ((last != idx) && (*last == 0)) last--;
+
+	while (idx != last) {
+		drv->interrupt(serio, 0, 0, NULL);
+		drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+		drv->interrupt(serio, 0, 0, NULL);
+		drv->interrupt(serio, *idx, 0, NULL);
+		idx++;
+	}
+	drv->interrupt(serio, 0, 0, NULL);
+	drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
+	drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL);
+	drv->interrupt(serio, *idx, 0, NULL);
+	
+	mlc->serio_oidx[map->didx] = 0;
+	mlc->serio_opacket[map->didx] = 0;
+
+	return 0;
+}
+
+static int hil_mlc_serio_open(struct serio *serio) {
+	struct hil_mlc_serio_map *map;
+	struct hil_mlc *mlc;
+
+	if (serio->private != NULL) return -EBUSY;
+
+	map = serio->port_data;
+	if (map == NULL) {
+		BUG();
+		return -ENODEV;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void hil_mlc_serio_close(struct serio *serio) {
+	struct hil_mlc_serio_map *map;
+	struct hil_mlc *mlc;
+
+	map = serio->port_data;
+	if (map == NULL) {
+		BUG();
+		return;
+	}
+	mlc = map->mlc;
+	if (mlc == NULL) {
+		BUG();
+		return;
+	}
+
+	serio->private = NULL;
+	serio->drv = NULL;
+	/* TODO wake up interruptable */
+}
+
+int hil_mlc_register(hil_mlc *mlc) {
+	int i;
+        unsigned long flags;
+
+	if (mlc == NULL) {
+		return -EINVAL;
+	}
+
+	mlc->istarted = 0;
+        mlc->ostarted = 0;
+
+        mlc->lock = RW_LOCK_UNLOCKED;
+        init_MUTEX(&(mlc->osem));
+
+        init_MUTEX(&(mlc->isem));
+        mlc->icount = -1;
+        mlc->imatch = 0;
+
+	mlc->opercnt = 0;
+
+        init_MUTEX_LOCKED(&(mlc->csem));
+
+	hil_mlc_clear_di_scratch(mlc);
+	hil_mlc_clear_di_map(mlc, 0);
+	for (i = 0; i < HIL_MLC_DEVMEM; i++) {
+		struct serio *mlc_serio;
+		hil_mlc_copy_di_scratch(mlc, i);
+		mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL);
+		mlc->serio[i] = mlc_serio;
+		memset(mlc_serio, 0, sizeof(*mlc_serio));
+		mlc_serio->type			= SERIO_HIL | SERIO_HIL_MLC;
+		mlc_serio->write		= hil_mlc_serio_write;
+		mlc_serio->open			= hil_mlc_serio_open;
+		mlc_serio->close		= hil_mlc_serio_close;
+		mlc_serio->port_data		= &(mlc->serio_map[i]);
+		mlc->serio_map[i].mlc		= mlc;
+		mlc->serio_map[i].didx		= i;
+		mlc->serio_map[i].di_revmap	= -1;
+		mlc->serio_opacket[i]		= 0;
+		mlc->serio_oidx[i]		= 0;
+		serio_register_port(mlc_serio);
+	}
+
+	mlc->tasklet = &hil_mlcs_tasklet;
+
+	write_lock_irqsave(&hil_mlcs_lock, flags);
+	list_add_tail(&mlc->list, &hil_mlcs);
+	mlc->seidx = HILSEN_START;
+	write_unlock_irqrestore(&hil_mlcs_lock, flags);
+
+	tasklet_schedule(&hil_mlcs_tasklet);
+	return 0;
+}
+
+int hil_mlc_unregister(hil_mlc *mlc) {
+	struct list_head *tmp;
+        unsigned long flags;
+	int i;
+
+	if (mlc == NULL)
+		return -EINVAL;
+
+	write_lock_irqsave(&hil_mlcs_lock, flags);
+	list_for_each(tmp, &hil_mlcs) {
+		if (list_entry(tmp, hil_mlc, list) == mlc)
+			goto found;
+	}
+
+	/* not found in list */
+	write_unlock_irqrestore(&hil_mlcs_lock, flags);
+	tasklet_schedule(&hil_mlcs_tasklet);
+	return -ENODEV;
+
+ found:
+	list_del(tmp);
+        write_unlock_irqrestore(&hil_mlcs_lock, flags);
+
+	for (i = 0; i < HIL_MLC_DEVMEM; i++) {
+		serio_unregister_port(mlc->serio[i]);
+		mlc->serio[i] = NULL;
+	}
+
+	tasklet_schedule(&hil_mlcs_tasklet);
+	return 0;
+}
+
+/**************************** Module interface *************************/
+
+static int __init hil_mlc_init(void)
+{
+	init_timer(&hil_mlcs_kicker);
+	hil_mlcs_kicker.expires = jiffies + HZ;
+	hil_mlcs_kicker.function = &hil_mlcs_timer;
+	add_timer(&hil_mlcs_kicker);
+
+	tasklet_enable(&hil_mlcs_tasklet);
+
+	return 0;
+}
+                
+static void __exit hil_mlc_exit(void)
+{
+	del_timer(&hil_mlcs_kicker);
+
+	tasklet_disable(&hil_mlcs_tasklet);
+	tasklet_kill(&hil_mlcs_tasklet);
+}
+                        
+module_init(hil_mlc_init);
+module_exit(hil_mlc_exit);
diff -Nru a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/serio/hp_sdc.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,1055 @@
+/*
+ * HP i8042-based System Device Controller driver.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ * References:
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ * Helge Deller's original hilkbd.c port for PA-RISC.
+ *
+ *
+ * Driver theory of operation:
+ *
+ * hp_sdc_put does all writing to the SDC.  ISR can run on a different 
+ * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time 
+ * (it cannot really benefit from SMP anyway.)  A tasket fit this perfectly.
+ *
+ * All data coming back from the SDC is sent via interrupt and can be read 
+ * fully in the ISR, so there are no latency/throughput problems there.  
+ * The problem is with output, due to the slow clock speed of the SDC 
+ * compared to the CPU.  This should not be too horrible most of the time, 
+ * but if used with HIL devices that support the multibyte transfer command, 
+ * keeping outbound throughput flowing at the 6500KBps that the HIL is 
+ * capable of is more than can be done at HZ=100.
+ *
+ * Busy polling for IBF clear wastes CPU cycles and bus cycles.  hp_sdc.ibf 
+ * is set to 0 when the IBF flag in the status register has cleared.  ISR 
+ * may do this, and may also access the parts of queued transactions related 
+ * to reading data back from the SDC, but otherwise will not touch the 
+ * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1.
+ *
+ * The i8042 write index and the values in the 4-byte input buffer
+ * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively,
+ * to minimize the amount of IO needed to the SDC.  However these values 
+ * do not need to be locked since they are only ever accessed by hp_sdc_put.
+ *
+ * A timer task schedules the tasklet once per second just to make
+ * sure it doesn't freeze up and to allow for bad reads to time out.
+ */
+
+#include <linux/hp_sdc.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/slab.h>
+#include <linux/hil.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/* Machine-specific abstraction */
+
+#if defined(__hppa__)
+# include <asm/parisc-device.h>
+# define sdc_readb(p)		gsc_readb(p)
+# define sdc_writeb(v,p)	gsc_writeb((v),(p))
+#elif defined(__mc68000__)
+# include <asm/uaccess.h>
+# define sdc_readb(p)		in_8(p)
+# define sdc_writeb(v,p)	out_8((p),(v))
+#else
+# error "HIL is not supported on this platform"
+#endif
+
+#define PREFIX "HP SDC: "
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("HP i8042-based SDC Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+EXPORT_SYMBOL(hp_sdc_request_timer_irq);
+EXPORT_SYMBOL(hp_sdc_request_hil_irq);
+EXPORT_SYMBOL(hp_sdc_request_cooked_irq);
+
+EXPORT_SYMBOL(hp_sdc_release_timer_irq);
+EXPORT_SYMBOL(hp_sdc_release_hil_irq);
+EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
+
+EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
+EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
+
+static hp_i8042_sdc	hp_sdc;	/* All driver state is kept in here. */
+
+/*************** primitives for use in any context *********************/
+static inline uint8_t hp_sdc_status_in8 (void) {
+	uint8_t status;
+	unsigned long flags;
+
+	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
+	status = sdc_readb(hp_sdc.status_io);
+	if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0;
+	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
+
+	return status;
+}
+
+static inline uint8_t hp_sdc_data_in8 (void) {
+	return sdc_readb(hp_sdc.data_io); 
+}
+
+static inline void hp_sdc_status_out8 (uint8_t val) {
+	unsigned long flags;
+
+	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
+	hp_sdc.ibf = 1;
+	if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff;
+	sdc_writeb(val, hp_sdc.status_io);
+	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
+}
+
+static inline void hp_sdc_data_out8 (uint8_t val) {
+	unsigned long flags;
+
+	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
+	hp_sdc.ibf = 1;
+	sdc_writeb(val, hp_sdc.data_io);
+	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
+}
+
+/*	Care must be taken to only invoke hp_sdc_spin_ibf when 
+ *	absolutely needed, or in rarely invoked subroutines.  
+ *	Not only does it waste CPU cycles, it also wastes bus cycles. 
+ */
+static inline void hp_sdc_spin_ibf(void) {
+	unsigned long flags;
+	rwlock_t *lock;
+
+	lock = &hp_sdc.ibf_lock;
+
+	read_lock_irqsave(lock, flags);
+	if (!hp_sdc.ibf) {
+		read_unlock_irqrestore(lock, flags);
+		return;
+	}
+	read_unlock(lock);
+	write_lock(lock);
+	while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {};
+	hp_sdc.ibf = 0;
+	write_unlock_irqrestore(lock, flags);
+}
+
+
+/************************ Interrupt context functions ************************/
+static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
+	hp_sdc_transaction *curr;
+
+	read_lock(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr < 0) {
+	  	read_unlock(&hp_sdc.rtq_lock);
+		return;
+	}
+	curr = hp_sdc.tq[hp_sdc.rcurr];
+	read_unlock(&hp_sdc.rtq_lock);
+
+	curr->seq[curr->idx++] = status;
+	curr->seq[curr->idx++] = data;
+	hp_sdc.rqty -= 2;
+	do_gettimeofday(&hp_sdc.rtv);
+
+	if (hp_sdc.rqty <= 0) {
+		/* All data has been gathered. */
+		if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) {
+			if (curr->act.semaphore) up(curr->act.semaphore);
+		}
+		if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) {
+			if (curr->act.irqhook)
+				curr->act.irqhook(irq, dev_id, status, data);
+		}
+		curr->actidx = curr->idx;
+		curr->idx++;
+		/* Return control of this transaction */
+		write_lock(&hp_sdc.rtq_lock);
+		hp_sdc.rcurr = -1; 
+		hp_sdc.rqty = 0;
+		write_unlock(&hp_sdc.rtq_lock);
+		tasklet_schedule(&hp_sdc.task);
+	}
+}
+
+static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) {
+	uint8_t status, data;
+
+	status = hp_sdc_status_in8();
+	/* Read data unconditionally to advance i8042. */
+	data =   hp_sdc_data_in8();
+
+	/* For now we are ignoring these until we get the SDC to behave. */
+	if (((status & 0xf1) == 0x51) && data == 0x82) {
+	  return IRQ_HANDLED;
+	}
+
+	switch(status & HP_SDC_STATUS_IRQMASK) {
+	      case 0: /* This case is not documented. */
+		break;
+	      case HP_SDC_STATUS_USERTIMER:
+	      case HP_SDC_STATUS_PERIODIC:
+	      case HP_SDC_STATUS_TIMER:
+		read_lock(&hp_sdc.hook_lock);
+	      	if (hp_sdc.timer != NULL)
+			hp_sdc.timer(irq, dev_id, status, data);
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	      case HP_SDC_STATUS_REG:
+		hp_sdc_take(irq, dev_id, status, data);
+		break;
+	      case HP_SDC_STATUS_HILCMD:
+	      case HP_SDC_STATUS_HILDATA:
+		read_lock(&hp_sdc.hook_lock);
+		if (hp_sdc.hil != NULL)
+			hp_sdc.hil(irq, dev_id, status, data);
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	      case HP_SDC_STATUS_PUP:
+		read_lock(&hp_sdc.hook_lock);
+		if (hp_sdc.pup != NULL)
+			hp_sdc.pup(irq, dev_id, status, data);
+		else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	      default:
+		read_lock(&hp_sdc.hook_lock);
+		if (hp_sdc.cooked != NULL)
+			hp_sdc.cooked(irq, dev_id, status, data);
+		read_unlock(&hp_sdc.hook_lock);
+		break;
+	}
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) {
+	int status;
+	
+	status = hp_sdc_status_in8();
+	printk(KERN_WARNING PREFIX "NMI !\n");
+
+#if 0	
+	if (status & HP_SDC_NMISTATUS_FHS) {
+		read_lock(&hp_sdc.hook_lock);
+	      	if (hp_sdc.timer != NULL)
+			hp_sdc.timer(irq, dev_id, status, 0);
+		read_unlock(&hp_sdc.hook_lock);
+	}
+	else {
+		/* TODO: pass this on to the HIL handler, or do SAK here? */
+		printk(KERN_WARNING PREFIX "HIL NMI\n");
+	}
+#endif
+	return IRQ_HANDLED;
+}
+
+
+/***************** Kernel (tasklet) context functions ****************/
+
+unsigned long hp_sdc_put(void);
+
+static void hp_sdc_tasklet(unsigned long foo) {
+
+	write_lock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr >= 0) {
+		struct timeval tv;
+		do_gettimeofday(&tv);
+		if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000;
+		if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) {
+			hp_sdc_transaction *curr;
+			uint8_t tmp;
+
+			curr = hp_sdc.tq[hp_sdc.rcurr];
+			/* If this turns out to be a normal failure mode
+			 * we'll need to figure out a way to communicate
+			 * it back to the application. and be less verbose.
+			 */
+			printk(KERN_WARNING PREFIX "read timeout (%ius)!\n",
+			       tv.tv_usec - hp_sdc.rtv.tv_usec);
+			curr->idx += hp_sdc.rqty;
+			hp_sdc.rqty = 0;
+			tmp = curr->seq[curr->actidx];
+			curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
+			if(tmp & HP_SDC_ACT_SEMAPHORE) {
+				if (curr->act.semaphore) 
+					up(curr->act.semaphore);
+			}
+			if(tmp & HP_SDC_ACT_CALLBACK) {
+				/* Note this means that irqhooks may be called
+				 * in tasklet/bh context.
+				 */
+				if (curr->act.irqhook) 
+					curr->act.irqhook(0, 0, 0, 0);
+			}
+			curr->actidx = curr->idx;
+			curr->idx++;
+			hp_sdc.rcurr = -1; 
+		}
+	}
+	write_unlock_irq(&hp_sdc.rtq_lock);
+	hp_sdc_put();
+}
+
+unsigned long hp_sdc_put(void) {
+	hp_sdc_transaction *curr;
+	uint8_t act;
+	int idx, curridx;
+
+	int limit = 0;
+
+	write_lock(&hp_sdc.lock);
+
+	/* If i8042 buffers are full, we cannot do anything that
+	   requires output, so we skip to the administrativa. */
+	if (hp_sdc.ibf) {
+		hp_sdc_status_in8();
+		if (hp_sdc.ibf) goto finish;
+	}
+
+ anew:
+	/* See if we are in the middle of a sequence. */
+	if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0;
+	read_lock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++;
+	read_unlock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+	curridx = hp_sdc.wcurr;
+
+	if (hp_sdc.tq[curridx] != NULL) goto start;
+
+	while (++curridx != hp_sdc.wcurr) {
+		if (curridx >= HP_SDC_QUEUE_LEN) {
+			curridx = -1; /* Wrap to top */
+			continue;
+		}
+		read_lock_irq(&hp_sdc.rtq_lock);
+		if (hp_sdc.rcurr == curridx) {
+			read_unlock_irq(&hp_sdc.rtq_lock);
+			continue;
+		}
+		read_unlock_irq(&hp_sdc.rtq_lock);
+		if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */
+	}
+	if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */
+		curridx = -1;
+	}
+	hp_sdc.wcurr = curridx;
+
+ start:
+
+	/* Check to see if the interrupt mask needs to be set. */
+	if (hp_sdc.set_im) {
+		hp_sdc_status_out8(hp_sdc.im | HP_SDC_CMD_SET_IM);
+		hp_sdc.set_im = 0;
+		goto finish;
+	}
+
+	if (hp_sdc.wcurr == -1) goto done;
+
+	curr = hp_sdc.tq[curridx];
+	idx = curr->actidx;
+
+	if (curr->actidx >= curr->endidx) {
+		hp_sdc.tq[curridx] = NULL;
+		/* Interleave outbound data between the transactions. */
+		hp_sdc.wcurr++;
+		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+		goto finish;	
+	}
+
+	act = curr->seq[idx];
+	idx++;
+
+	if (curr->idx >= curr->endidx) {
+		if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+		hp_sdc.tq[curridx] = NULL;
+		/* Interleave outbound data between the transactions. */
+		hp_sdc.wcurr++;
+		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+		goto finish;	
+	}
+
+	while (act & HP_SDC_ACT_PRECMD) {
+		if (curr->idx != idx) {
+			idx++;
+			act &= ~HP_SDC_ACT_PRECMD;
+			break;
+		}
+		hp_sdc_status_out8(curr->seq[idx]);
+		curr->idx++;
+		/* act finished? */
+		if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
+		  goto actdone;
+		/* skip quantity field if data-out sequence follows. */
+		if (act & HP_SDC_ACT_DATAOUT) curr->idx++;
+		goto finish;
+	}
+	if (act & HP_SDC_ACT_DATAOUT) {
+		int qty;
+
+		qty = curr->seq[idx];
+		idx++;
+		if (curr->idx - idx < qty) {
+			hp_sdc_data_out8(curr->seq[curr->idx]);
+			curr->idx++;
+			/* act finished? */
+			if ((curr->idx - idx >= qty) && 
+			    ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT))
+				goto actdone;
+			goto finish;
+		}
+		idx += qty;
+		act &= ~HP_SDC_ACT_DATAOUT;
+	}
+	else while (act & HP_SDC_ACT_DATAREG) {
+		int mask;
+		uint8_t w7[4];
+
+		mask = curr->seq[idx];
+		if (idx != curr->idx) {
+			idx++;
+			idx += !!(mask & 1);
+			idx += !!(mask & 2);
+			idx += !!(mask & 4);
+			idx += !!(mask & 8);
+			act &= ~HP_SDC_ACT_DATAREG;
+			break;
+		}
+		
+		w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0];
+		w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1];
+		w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2];
+		w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
+		
+		if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
+		        w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) {
+			int i = 0;
+
+			/* Need to point the write index register */	
+			while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+			if (i < 4) {
+				hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
+				hp_sdc.wi = 0x70 + i;
+				goto finish;
+			}
+			idx++;
+			if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
+				goto actdone;
+			curr->idx = idx;
+			act &= ~HP_SDC_ACT_DATAREG;
+			break;
+		}
+
+		hp_sdc_data_out8(w7[hp_sdc.wi - 0x70]);
+		hp_sdc.r7[hp_sdc.wi - 0x70] = w7[hp_sdc.wi - 0x70];
+		hp_sdc.wi++; /* write index register autoincrements */
+		{
+			int i = 0;
+
+			while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+			if (i >= 4) {
+				curr->idx = idx + 1;
+				if ((act & HP_SDC_ACT_DURING) == 
+				    HP_SDC_ACT_DATAREG)
+				        goto actdone;
+			}
+		}
+		goto finish;
+	}
+	/* We don't go any further in the command if there is a pending read,
+	   because we don't want interleaved results. */
+	read_lock_irq(&hp_sdc.rtq_lock);
+	if (hp_sdc.rcurr >= 0) {
+		read_unlock_irq(&hp_sdc.rtq_lock);
+		goto finish;
+	}
+	read_unlock_irq(&hp_sdc.rtq_lock);
+
+
+	if (act & HP_SDC_ACT_POSTCMD) {
+	  	uint8_t postcmd;
+
+		/* curr->idx should == idx at this point. */
+		postcmd = curr->seq[idx];
+		curr->idx++;
+		if (act & HP_SDC_ACT_DATAIN) {
+
+			/* Start a new read */
+	  		hp_sdc.rqty = curr->seq[curr->idx];
+			do_gettimeofday(&hp_sdc.rtv);
+			curr->idx++;
+			/* Still need to lock here in case of spurious irq. */
+			write_lock_irq(&hp_sdc.rtq_lock);
+			hp_sdc.rcurr = curridx; 
+			write_unlock_irq(&hp_sdc.rtq_lock);
+			hp_sdc_status_out8(postcmd);
+			goto finish;
+		}
+		hp_sdc_status_out8(postcmd);
+		goto actdone;
+	}
+
+actdone:
+	if (act & HP_SDC_ACT_SEMAPHORE) {
+		up(curr->act.semaphore);
+	}
+	else if (act & HP_SDC_ACT_CALLBACK) {
+		curr->act.irqhook(0,0,0,0);
+	}
+	if (curr->idx >= curr->endidx) { /* This transaction is over. */
+		if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+		hp_sdc.tq[curridx] = NULL;
+	}
+	else {
+		curr->actidx = idx + 1;
+		curr->idx = idx + 2;
+	}
+	/* Interleave outbound data between the transactions. */
+	hp_sdc.wcurr++;
+	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+
+ finish:
+	/* If by some quirk IBF has cleared and our ISR has run to 
+	   see that that has happened, do it all again. */
+	if (!hp_sdc.ibf && limit++ < 20) goto anew;
+
+ done:
+	if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task);
+	write_unlock(&hp_sdc.lock);
+	return 0;
+}
+
+/******* Functions called in either user or kernel context ****/
+int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
+	unsigned long flags;
+	int i;
+
+	if (this == NULL) {
+		tasklet_schedule(&hp_sdc.task);
+		return -EINVAL;
+	};
+
+	write_lock_irqsave(&hp_sdc.lock, flags);
+
+	/* Can't have same transaction on queue twice */
+	for (i=0; i < HP_SDC_QUEUE_LEN; i++)
+		if (hp_sdc.tq[i] == this) goto fail;
+
+	this->actidx = 0;
+	this->idx = 1;
+
+	/* Search for empty slot */
+	for (i=0; i < HP_SDC_QUEUE_LEN; i++) {
+		if (hp_sdc.tq[i] == NULL) {
+			hp_sdc.tq[i] = this;
+			write_unlock_irqrestore(&hp_sdc.lock, flags);
+			tasklet_schedule(&hp_sdc.task);
+			return 0;
+		}
+	}
+	write_unlock_irqrestore(&hp_sdc.lock, flags);
+	printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
+	return -EBUSY;
+
+ fail:
+	write_unlock_irqrestore(&hp_sdc.lock,flags);
+	printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
+	return -EINVAL;
+}
+
+int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
+	unsigned long flags;
+	int i;
+
+	write_lock_irqsave(&hp_sdc.lock, flags);
+
+	/* TODO: don't remove it if it's not done. */
+
+	for (i=0; i < HP_SDC_QUEUE_LEN; i++)
+		if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL;
+
+	write_unlock_irqrestore(&hp_sdc.lock, flags);
+	return 0;
+}
+
+
+
+/********************** User context functions **************************/
+int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
+
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.timer != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EBUSY;
+	}
+
+	hp_sdc.timer = callback;
+	/* Enable interrupts from the timers */
+	hp_sdc.im &= ~HP_SDC_IM_FH;
+        hp_sdc.im &= ~HP_SDC_IM_PT;
+	hp_sdc.im &= ~HP_SDC_IM_TIMERS;
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
+
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.hil != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EBUSY;
+	}
+
+	hp_sdc.hil = callback;
+	hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
+
+	if (callback == NULL || hp_sdc.dev == NULL) {
+		return -EINVAL;
+	}
+	write_lock_irq(&hp_sdc.hook_lock);
+	if (hp_sdc.cooked != NULL) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EBUSY;
+	}
+
+	/* Enable interrupts from the HIL MLC */
+	hp_sdc.cooked = callback;
+	hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
+
+
+	write_lock_irq(&hp_sdc.hook_lock);
+	if ((callback != hp_sdc.timer) ||
+	    (hp_sdc.timer == NULL)) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EINVAL;
+	}
+
+	/* Disable interrupts from the timers */
+	hp_sdc.timer = NULL;
+	hp_sdc.im |= HP_SDC_IM_TIMERS;
+	hp_sdc.im |= HP_SDC_IM_FH;
+	hp_sdc.im |= HP_SDC_IM_PT;
+	hp_sdc.set_im = 1;
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
+
+	write_lock_irq(&hp_sdc.hook_lock);
+	if ((callback != hp_sdc.hil) ||
+	    (hp_sdc.hil == NULL)) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EINVAL;
+	}
+
+	hp_sdc.hil = NULL;
+	/* Disable interrupts from HIL only if there is no cooked driver. */
+	if(hp_sdc.cooked == NULL) {
+		hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);
+		hp_sdc.set_im = 1;
+	}
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
+
+	write_lock_irq(&hp_sdc.hook_lock);
+	if ((callback != hp_sdc.cooked) ||
+	    (hp_sdc.cooked == NULL)) {
+		write_unlock_irq(&hp_sdc.hook_lock);
+		return -EINVAL;
+	}
+
+	hp_sdc.cooked = NULL;
+	/* Disable interrupts from HIL only if there is no raw HIL driver. */
+	if(hp_sdc.hil == NULL) {
+		hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);
+		hp_sdc.set_im = 1;
+	}
+	write_unlock_irq(&hp_sdc.hook_lock);
+	tasklet_schedule(&hp_sdc.task);
+
+	return 0;
+}
+
+/************************* Keepalive timer task *********************/
+
+void hp_sdc_kicker (unsigned long data) {
+	tasklet_schedule(&hp_sdc.task);
+	/* Re-insert the periodic task. */
+	mod_timer(&hp_sdc.kicker, jiffies + HZ);
+}
+
+/************************** Module Initialization ***************************/
+
+#if defined(__hppa__)
+
+static struct parisc_device_id hp_sdc_tbl[] = {
+	{
+		.hw_type =	HPHW_FIO, 
+		.hversion_rev =	HVERSION_REV_ANY_ID,
+		.hversion =	HVERSION_ANY_ID,
+		.sversion =	0x73, 
+	 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl);
+
+static int __init hp_sdc_init_hppa(struct parisc_device *d);
+
+static struct parisc_driver hp_sdc_driver = {
+	.name =		"HP SDC",
+	.id_table =	hp_sdc_tbl,
+	.probe =	hp_sdc_init_hppa,
+};
+
+#endif /* __hppa__ */
+
+static int __init hp_sdc_init(void)
+{
+	int i;
+	char *errstr;
+	hp_sdc_transaction t_sync;
+	uint8_t ts_sync[6];
+	struct semaphore s_sync;
+
+  	hp_sdc.lock		= RW_LOCK_UNLOCKED;
+  	hp_sdc.ibf_lock		= RW_LOCK_UNLOCKED;
+  	hp_sdc.rtq_lock		= RW_LOCK_UNLOCKED;
+  	hp_sdc.hook_lock	= RW_LOCK_UNLOCKED;
+
+	hp_sdc.timer		= NULL;
+	hp_sdc.hil		= NULL;
+	hp_sdc.pup		= NULL;
+	hp_sdc.cooked		= NULL;
+	hp_sdc.im		= HP_SDC_IM_MASK;  /* Mask maskable irqs */
+	hp_sdc.set_im		= 1;
+	hp_sdc.wi		= 0xff;
+	hp_sdc.r7[0]		= 0xff;
+	hp_sdc.r7[1]		= 0xff;
+	hp_sdc.r7[2]		= 0xff;
+	hp_sdc.r7[3]		= 0xff;
+	hp_sdc.ibf		= 1;
+
+	for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL;
+	hp_sdc.wcurr		= -1;
+        hp_sdc.rcurr		= -1;
+	hp_sdc.rqty		= 0;
+
+	hp_sdc.dev_err = -ENODEV;
+
+	errstr = "IO not found for";
+	if (!hp_sdc.base_io) goto err0;
+
+	errstr = "IRQ not found for";
+	if (!hp_sdc.irq) goto err0;
+
+	hp_sdc.dev_err = -EBUSY;
+
+#if defined(__hppa__)
+	errstr = "IO not available for";
+        if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;
+#endif	
+
+	errstr = "IRQ not available for";
+        if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC",
+		       (void *) hp_sdc.base_io)) goto err1;
+
+	errstr = "NMI not available for";
+	if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", 
+			(void *) hp_sdc.base_io)) goto err2;
+
+	printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", 
+	       (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
+
+	hp_sdc_status_in8();
+	hp_sdc_data_in8();
+
+	tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0);
+
+	/* Sync the output buffer registers, thus scheduling hp_sdc_tasklet. */
+	t_sync.actidx	= 0;
+	t_sync.idx	= 1;
+	t_sync.endidx	= 6;
+	t_sync.seq	= ts_sync;
+	ts_sync[0]	= HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE;
+	ts_sync[1]	= 0x0f;
+	ts_sync[2] = ts_sync[3]	= ts_sync[4] = ts_sync[5] = 0;
+	t_sync.act.semaphore = &s_sync;
+	init_MUTEX_LOCKED(&s_sync);
+	hp_sdc_enqueue_transaction(&t_sync);
+	down(&s_sync); /* Wait for t_sync to complete */
+
+	/* Create the keepalive task */
+	init_timer(&hp_sdc.kicker);
+	hp_sdc.kicker.expires = jiffies + HZ;
+	hp_sdc.kicker.function = &hp_sdc_kicker;
+	add_timer(&hp_sdc.kicker);
+
+	hp_sdc.dev_err = 0;
+	return 0;
+ err2:
+	free_irq(hp_sdc.irq, NULL);
+ err1:
+	release_region(hp_sdc.data_io, 2);
+ err0:
+	printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", 
+		errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
+	hp_sdc.dev = NULL;
+	return hp_sdc.dev_err;
+}
+
+#if defined(__hppa__)
+
+static int __init hp_sdc_init_hppa(struct parisc_device *d)
+{
+	if (!d) return 1;
+	if (hp_sdc.dev != NULL) return 1;	/* We only expect one SDC */
+
+	hp_sdc.dev		= d;
+	hp_sdc.irq		= d->irq;
+	/* TODO: Is NMI == IRQ - 1 all cases, or is there a way to query? */
+	hp_sdc.nmi		= d->irq - 1;
+	hp_sdc.base_io		= (unsigned long) d->hpa;
+	hp_sdc.data_io		= (unsigned long) d->hpa + 0x800;
+	hp_sdc.status_io	= (unsigned long) d->hpa + 0x801;
+
+	return hp_sdc_init();
+}
+
+#endif /* __hppa__ */
+
+#if !defined(__mc68000__) /* Link error on m68k! */
+static void __exit hp_sdc_exit(void)
+#else
+static void hp_sdc_exit(void)
+#endif
+{
+	write_lock_irq(&hp_sdc.lock);
+
+	/* Turn off all maskable "sub-function" irq's. */
+	hp_sdc_spin_ibf();
+	sdc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io);
+
+	/* Wait until we know this has been processed by the i8042 */
+	hp_sdc_spin_ibf();
+
+	free_irq(hp_sdc.nmi, NULL);
+	free_irq(hp_sdc.irq, NULL);
+	write_unlock_irq(&hp_sdc.lock);
+
+	del_timer(&hp_sdc.kicker);
+
+	tasklet_kill(&hp_sdc.task);
+
+/*        release_region(hp_sdc.data_io, 2); */
+
+#if defined(__hppa__)
+	if (unregister_parisc_driver(&hp_sdc_driver)) 
+		printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
+#endif
+}
+
+static int __init hp_sdc_register(void)
+{
+	hp_sdc_transaction tq_init;
+	uint8_t tq_init_seq[5];
+	struct semaphore tq_init_sem;
+#if defined(__mc68000__)
+	mm_segment_t fs;
+	unsigned char i;
+#endif
+	
+	hp_sdc.dev = NULL;
+	hp_sdc.dev_err = 0;
+#if defined(__hppa__)
+	if (register_parisc_driver(&hp_sdc_driver)) {
+		printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n");
+		return -ENODEV;
+	}
+#elif defined(__mc68000__)
+	if (!MACH_IS_HP300)
+	    return -ENODEV;
+
+	hp_sdc.irq	 = 1;
+	hp_sdc.nmi	 = 7;
+	hp_sdc.base_io	 = (unsigned long) 0xf0428000;
+	hp_sdc.data_io	 = (unsigned long) hp_sdc.base_io + 1;
+	hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3;
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (!get_user(i, (unsigned char *)hp_sdc.data_io))
+		hp_sdc.dev = (void *)1;
+	set_fs(fs);
+	hp_sdc.dev_err   = hp_sdc_init();
+#endif
+	if (hp_sdc.dev == NULL) {
+		printk(KERN_WARNING PREFIX "No SDC found.\n");
+		return hp_sdc.dev_err;
+	}
+
+	init_MUTEX_LOCKED(&tq_init_sem);
+
+	tq_init.actidx		= 0;
+	tq_init.idx		= 1;
+	tq_init.endidx		= 5;
+	tq_init.seq		= tq_init_seq;
+	tq_init.act.semaphore	= &tq_init_sem;
+
+	tq_init_seq[0] = 
+	  HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
+	tq_init_seq[1] = HP_SDC_CMD_READ_KCC;
+	tq_init_seq[2] = 1;
+	tq_init_seq[3] = 0;
+	tq_init_seq[4] = 0;
+
+	hp_sdc_enqueue_transaction(&tq_init);
+
+	down(&tq_init_sem);
+	up(&tq_init_sem);
+
+	if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
+		printk(KERN_WARNING PREFIX "Error reading config byte.\n");
+		hp_sdc_exit();
+		return -ENODEV;
+	}
+	hp_sdc.r11 = tq_init_seq[4];
+	if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
+		char *str;
+		printk(KERN_INFO PREFIX "New style SDC\n");
+		tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
+		tq_init.actidx		= 0;
+		tq_init.idx		= 1;
+		down(&tq_init_sem);
+		hp_sdc_enqueue_transaction(&tq_init);		
+		down(&tq_init_sem);
+		up(&tq_init_sem);
+		if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
+			printk(KERN_WARNING PREFIX "Error reading extended config byte.\n");
+			return -ENODEV;
+		}
+		hp_sdc.r7e = tq_init_seq[4];
+		HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
+		printk(KERN_INFO PREFIX "Revision: %s\n", str);
+		if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) {
+			printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
+		}
+		if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) {
+			printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
+		}
+		printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
+		       "on next firmware reset.\n");
+		tq_init_seq[0] = HP_SDC_ACT_PRECMD | 
+			HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
+		tq_init_seq[1] = HP_SDC_CMD_SET_STR;
+		tq_init_seq[2] = 1;
+		tq_init_seq[3] = 0;
+		tq_init.actidx		= 0;
+		tq_init.idx		= 1;
+		tq_init.endidx		= 4;
+		down(&tq_init_sem);
+		hp_sdc_enqueue_transaction(&tq_init);		
+		down(&tq_init_sem);
+		up(&tq_init_sem);
+	}
+	else {
+		printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", 
+		       (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
+	}
+
+        return 0;
+}
+
+module_init(hp_sdc_register);
+module_exit(hp_sdc_exit);
+
+/* Timing notes:  These measurements taken on my 64MHz 7100-LC (715/64) 
+ *                                              cycles cycles-adj    time
+ * between two consecutive mfctl(16)'s:              4        n/a    63ns
+ * hp_sdc_spin_ibf when idle:                      119        115   1.7us
+ * gsc_writeb status register:                      83         79   1.2us
+ * IBF to clear after sending SET_IM:             6204       6006    93us
+ * IBF to clear after sending LOAD_RT:            4467       4352    68us  
+ * IBF to clear after sending two LOAD_RTs:      18974      18859   295us
+ * READ_T1, read status/data, IRQ, call handler: 35564        n/a   556us
+ * cmd to ~IBF READ_T1 2nd time right after:   5158403        n/a    81ms
+ * between IRQ received and ~IBF for above:    2578877        n/a    40ms
+ *
+ * Performance stats after a run of this module configuring HIL and
+ * receiving a few mouse events:
+ *
+ * status in8  282508 cycles 7128 calls
+ * status out8   8404 cycles  341 calls
+ * data out8     1734 cycles   78 calls
+ * isr         174324 cycles  617 calls (includes take)
+ * take          1241 cycles    2 calls
+ * put        1411504 cycles 6937 calls
+ * task       1655209 cycles 6937 calls (includes put)
+ *
+ */
diff -Nru a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/serio/hp_sdc_mlc.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,358 @@
+/*
+ * Access to HP-HIL MLC through HP System Device Controller.
+ *
+ * Copyright (c) 2001 Brian S. Julin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *
+ * References:
+ * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
+ * System Device Controller Microprocessor Firmware Theory of Operation
+ *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
+ *
+ */
+
+#include <linux/hil_mlc.h>
+#include <linux/hp_sdc.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#define PREFIX "HP SDC MLC: "
+
+static hil_mlc hp_sdc_mlc;
+
+MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
+MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines");
+MODULE_LICENSE("Dual BSD/GPL");
+
+struct hp_sdc_mlc_priv_s {
+	int emtestmode;
+	hp_sdc_transaction trans;
+	u8 tseq[16];
+	int got5x;
+} hp_sdc_mlc_priv;
+
+/************************* Interrupt context ******************************/
+static void hp_sdc_mlc_isr (int irq, void *dev_id, 
+			    uint8_t status, uint8_t data) {
+  	int idx;
+	hil_mlc *mlc = &hp_sdc_mlc;
+
+	write_lock(&(mlc->lock));
+	if (mlc->icount < 0) {
+		printk(KERN_WARNING PREFIX "HIL Overflow!\n");
+		up(&mlc->isem);
+		goto out;
+	}
+	idx = 15 - mlc->icount;
+	if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
+		mlc->ipacket[idx] |= data | HIL_ERR_INT;
+		mlc->icount--;
+		if (hp_sdc_mlc_priv.got5x) goto check;
+		if (!idx) goto check;
+		if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) !=
+		    (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
+			mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
+			mlc->ipacket[idx] |= (mlc->ipacket[idx-1] 
+						    & HIL_PKT_ADDR_MASK);
+		}
+		goto check;
+	}
+	/* We know status is 5X */
+	if (data & HP_SDC_HIL_ISERR) goto err;
+	mlc->ipacket[idx] = 
+		(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
+	hp_sdc_mlc_priv.got5x = 1;
+	goto out;
+
+ check:
+	hp_sdc_mlc_priv.got5x = 0;
+	if (mlc->imatch == 0) goto done;
+	if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) 
+	    && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done;
+	if (mlc->ipacket[idx] == mlc->imatch) goto done;
+	goto out;
+
+ err:				
+	printk(KERN_DEBUG PREFIX "err code %x\n", data);
+	switch (data) {
+	case HP_SDC_HIL_RC_DONE:
+		printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
+		break;
+	case HP_SDC_HIL_ERR:
+		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | 
+		  HIL_ERR_FERR | HIL_ERR_FOF;
+		break;
+	case HP_SDC_HIL_TO:
+		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
+		break;
+	case HP_SDC_HIL_RC:
+		printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
+		break;
+	default:
+		printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
+		break;
+	}
+	/* No more data will be coming due to an error. */
+ done:
+	tasklet_schedule(mlc->tasklet);
+	up(&(mlc->isem));
+ out:
+	write_unlock(&(mlc->lock));
+}
+
+
+/******************** Tasklet or userspace context functions ****************/
+
+static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) {
+	unsigned long flags;
+	struct hp_sdc_mlc_priv_s *priv;
+	int rc = 2;
+
+	priv = mlc->priv;
+
+	write_lock_irqsave(&(mlc->lock), flags);
+
+	/* Try to down the semaphore */
+	if (down_trylock(&(mlc->isem))) {
+		struct timeval tv;
+		if (priv->emtestmode) {
+			mlc->ipacket[0] = 
+				HIL_ERR_INT | (mlc->opacket & 
+					       (HIL_PKT_CMD | 
+						HIL_PKT_ADDR_MASK | 
+						HIL_PKT_DATA_MASK));
+			mlc->icount = 14;
+			/* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
+			goto wasup;
+		}
+		do_gettimeofday(&tv);
+		tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+		if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) {
+		  /*		  printk("!%i %i", 
+				  tv.tv_usec - mlc->instart.tv_usec, 
+				  mlc->intimeout);
+		  */
+			rc = 1;
+			up(&(mlc->isem));
+		}
+		goto done;
+	}
+ wasup:
+	up(&(mlc->isem));
+	rc = 0;
+	goto done;
+ done:
+	write_unlock_irqrestore(&(mlc->lock), flags);
+	return rc;
+}
+
+static int hp_sdc_mlc_cts (hil_mlc *mlc) {
+	struct hp_sdc_mlc_priv_s *priv;
+	unsigned long flags;
+
+	priv = mlc->priv;	
+
+	write_lock_irqsave(&(mlc->lock), flags);
+
+	/* Try to down the semaphores -- they should be up. */
+	if (down_trylock(&(mlc->isem))) {
+		BUG();
+		goto busy;
+	}
+	if (down_trylock(&(mlc->osem))) {
+	 	BUG();
+		up(&(mlc->isem));
+		goto busy;
+	}
+	up(&(mlc->isem));
+	up(&(mlc->osem));
+
+	if (down_trylock(&(mlc->csem))) {
+		if (priv->trans.act.semaphore != &(mlc->csem)) goto poll;
+		goto busy;
+	}
+	if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done;
+
+ poll:
+	priv->trans.act.semaphore = &(mlc->csem);
+	priv->trans.actidx = 0;
+	priv->trans.idx = 1;
+	priv->trans.endidx = 5;
+	priv->tseq[0] = 
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
+	priv->tseq[1] = HP_SDC_CMD_READ_USE;
+	priv->tseq[2] = 1;
+	priv->tseq[3] = 0;
+	priv->tseq[4] = 0;
+	hp_sdc_enqueue_transaction(&(priv->trans));
+ busy:
+	write_unlock_irqrestore(&(mlc->lock), flags);
+	return 1;
+ done:
+	priv->trans.act.semaphore = &(mlc->osem);
+	up(&(mlc->csem));
+	write_unlock_irqrestore(&(mlc->lock), flags);
+	return 0;
+}
+
+static void hp_sdc_mlc_out (hil_mlc *mlc) {
+	struct hp_sdc_mlc_priv_s *priv;
+	unsigned long flags;
+
+	priv = mlc->priv;
+
+	write_lock_irqsave(&(mlc->lock), flags);
+	
+	/* Try to down the semaphore -- it should be up. */
+	if (down_trylock(&(mlc->osem))) {
+	 	BUG();
+		goto done;
+	}
+
+	if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control;
+
+ do_data:
+	if (priv->emtestmode) {
+		up(&(mlc->osem));
+		goto done;
+	}
+	/* Shouldn't be sending commands when loop may be busy */
+	if (down_trylock(&(mlc->csem))) {
+	 	BUG();
+		goto done;
+	}
+	up(&(mlc->csem));
+
+	priv->trans.actidx = 0;
+	priv->trans.idx = 1;
+	priv->trans.act.semaphore = &(mlc->osem);
+	priv->trans.endidx = 6;
+	priv->tseq[0] = 
+		HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
+	priv->tseq[1] = 0x7;
+	priv->tseq[2] = 
+		(mlc->opacket & 
+		 (HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
+		   >> HIL_PKT_ADDR_SHIFT;
+	priv->tseq[3] = 
+		(mlc->opacket & HIL_PKT_DATA_MASK) 
+		  >> HIL_PKT_DATA_SHIFT;
+	priv->tseq[4] = 0;  /* No timeout */
+	if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1;
+	priv->tseq[5] = HP_SDC_CMD_DO_HIL;
+	goto enqueue;
+
+ do_control:
+	priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
+	if ((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE) {
+		BUG(); /* we cannot emulate this, it should not be used. */
+	}
+	if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only;
+	if (mlc->opacket & HIL_CTRL_APE) { 
+		BUG(); /* Should not send command/data after engaging APE */
+		goto done;
+	}
+	/* Disengaging APE this way would not be valid either since 
+	 * the loop must be allowed to idle.
+	 *
+	 * So, it works out that we really never actually send control 
+	 * and data when using SDC, we just send the data. 
+	 */
+	goto do_data;
+
+ control_only:
+	priv->trans.actidx = 0;
+	priv->trans.idx = 1;
+	priv->trans.act.semaphore = &(mlc->osem);
+	priv->trans.endidx = 4;
+	priv->tseq[0] = 
+	  HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
+	priv->tseq[1] = HP_SDC_CMD_SET_LPC;
+	priv->tseq[2] = 1;
+	//	priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC;
+	priv->tseq[3] = 0;
+	if (mlc->opacket & HIL_CTRL_APE) {
+		priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
+		down_trylock(&(mlc->csem));
+	} 
+ enqueue:
+	hp_sdc_enqueue_transaction(&(priv->trans));
+ done:
+	write_unlock_irqrestore(&(mlc->lock), flags);
+}
+
+static int __init hp_sdc_mlc_init(void)
+{
+	hil_mlc *mlc = &hp_sdc_mlc;
+
+	printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n");
+
+	hp_sdc_mlc_priv.emtestmode = 0;
+	hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
+	hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem);
+	hp_sdc_mlc_priv.got5x = 0;
+
+	mlc->cts		= &hp_sdc_mlc_cts;
+	mlc->in			= &hp_sdc_mlc_in;
+	mlc->out		= &hp_sdc_mlc_out;
+
+	if (hil_mlc_register(mlc)) {
+		printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
+		goto err0;
+	}
+	mlc->priv		= &hp_sdc_mlc_priv;
+
+	if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
+		printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
+		goto err1;
+	}
+	return 0;
+ err1:
+	if (hil_mlc_unregister(mlc)) {
+		printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
+			"This is bad.  Could cause an oops.\n");
+	}
+ err0:
+	return -EBUSY;
+}
+
+static void __exit hp_sdc_mlc_exit(void)
+{
+	hil_mlc *mlc = &hp_sdc_mlc;
+	if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) {
+		printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
+			"This is bad.  Could cause an oops.\n");
+	}
+	if (hil_mlc_unregister(mlc)) {
+		printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
+			"This is bad.  Could cause an oops.\n");
+	}
+}
+
+module_init(hp_sdc_mlc_init);
+module_exit(hp_sdc_mlc_exit);
diff -Nru a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
--- a/drivers/input/serio/i8042-x86ia64io.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/i8042-x86ia64io.h	2005-03-07 15:26:30 -08:00
@@ -67,7 +67,7 @@
 
 #include <linux/dmi.h>
 
-static struct dmi_system_id __initdata i8042_dmi_table[] = {
+static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
 	{
 		.ident = "Compaq Proliant 8500",
 		.matches = {
@@ -86,186 +86,208 @@
 	},
 	{ }
 };
+
+/*
+ * Some Fujitsu notebooks are ahving trouble with touhcpads if
+ * active multiplexing mode is activated. Luckily they don't have
+ * external PS/2 ports so we can safely disable it.
+ */
+static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
+	{
+		.ident = "Fujitsu Lifebook P7010/P7010D",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
+		},
+	},
+	{
+		.ident = "Fujitsu Lifebook P5020D",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"),
+		},
+	},
+	{
+		.ident = "Fujitsu Lifebook S2000",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
+		},
+	},
+	{
+		.ident = "Fujitsu T70H",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
+		},
+	},
+	{ }
+};
+
+
+
 #endif
 
-#ifdef CONFIG_ACPI
-#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-
-struct i8042_acpi_resources {
-	unsigned int port1;
-	unsigned int port2;
-	unsigned int irq;
-};
-
-static int i8042_acpi_kbd_registered;
-static int i8042_acpi_aux_registered;
-
-static acpi_status i8042_acpi_parse_resource(struct acpi_resource *res, void *data)
-{
-	struct i8042_acpi_resources *i8042_res = data;
-	struct acpi_resource_io *io;
-	struct acpi_resource_fixed_io *fixed_io;
-	struct acpi_resource_irq *irq;
-	struct acpi_resource_ext_irq *ext_irq;
-
-	switch (res->id) {
-		case ACPI_RSTYPE_IO:
-			io = &res->data.io;
-			if (io->range_length) {
-				if (!i8042_res->port1)
-					i8042_res->port1 = io->min_base_address;
-				else
-					i8042_res->port2 = io->min_base_address;
-			}
-			break;
-
-		case ACPI_RSTYPE_FIXED_IO:
-			fixed_io = &res->data.fixed_io;
-			if (fixed_io->range_length) {
-				if (!i8042_res->port1)
-					i8042_res->port1 = fixed_io->base_address;
-				else
-					i8042_res->port2 = fixed_io->base_address;
-			}
-			break;
-
-		case ACPI_RSTYPE_IRQ:
-			irq = &res->data.irq;
-			if (irq->number_of_interrupts > 0)
-				i8042_res->irq =
-					acpi_register_gsi(irq->interrupts[0],
-							  irq->edge_level,
-							  irq->active_high_low);
-			break;
-
-		case ACPI_RSTYPE_EXT_IRQ:
-			ext_irq = &res->data.extended_irq;
-			if (ext_irq->number_of_interrupts > 0)
-				i8042_res->irq =
-					acpi_register_gsi(ext_irq->interrupts[0],
-							  ext_irq->edge_level,
-							  ext_irq->active_high_low);
-			break;
-	}
-	return AE_OK;
-}
 
-static int i8042_acpi_kbd_add(struct acpi_device *device)
+#ifdef CONFIG_PNP
+#include <linux/pnp.h>
+
+static int i8042_pnp_kbd_registered;
+static int i8042_pnp_aux_registered;
+
+static int i8042_pnp_command_reg;
+static int i8042_pnp_data_reg;
+static int i8042_pnp_kbd_irq;
+static int i8042_pnp_aux_irq;
+
+static char i8042_pnp_kbd_name[32];
+static char i8042_pnp_aux_name[32];
+
+static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
 {
-	struct i8042_acpi_resources kbd_res;
-	acpi_status status;
+	if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1)
+		i8042_pnp_data_reg = pnp_port_start(dev,0);
 
-	memset(&kbd_res, 0, sizeof(kbd_res));
-	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-				     i8042_acpi_parse_resource, &kbd_res);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
+	if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1)
+		i8042_pnp_command_reg = pnp_port_start(dev, 1);
+
+	if (pnp_irq_valid(dev,0))
+		i8042_pnp_kbd_irq = pnp_irq(dev, 0);
 
-	if (kbd_res.port1)
-		i8042_data_reg = kbd_res.port1;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no data port; default is 0x%x\n",
-			acpi_device_bid(device), i8042_data_reg);
-
-	if (kbd_res.port2)
-		i8042_command_reg = kbd_res.port2;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no command port; default is 0x%x\n",
-			acpi_device_bid(device), i8042_command_reg);
-
-	if (kbd_res.irq)
-		i8042_kbd_irq = kbd_res.irq;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
-			acpi_device_bid(device), i8042_kbd_irq);
-
-	strncpy(acpi_device_name(device), "PS/2 Keyboard Controller",
-		sizeof(acpi_device_name(device)));
-	printk("ACPI: %s [%s] at I/O 0x%x, 0x%x, irq %d\n",
-		acpi_device_name(device), acpi_device_bid(device),
-		i8042_data_reg, i8042_command_reg, i8042_kbd_irq);
+	strncpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name));
+	if (strlen(pnp_dev_name(dev))) {
+		strncat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name));
+		strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));
+	}
 
 	return 0;
 }
 
-static int i8042_acpi_aux_add(struct acpi_device *device)
+static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
 {
-	struct i8042_acpi_resources aux_res;
-	acpi_status status;
+	if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1)
+		i8042_pnp_data_reg = pnp_port_start(dev,0);
 
-	memset(&aux_res, 0, sizeof(aux_res));
-	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-				     i8042_acpi_parse_resource, &aux_res);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
+	if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1)
+		i8042_pnp_command_reg = pnp_port_start(dev, 1);
 
-	if (aux_res.irq)
-		i8042_aux_irq = aux_res.irq;
-	else
-		printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
-			acpi_device_bid(device), i8042_aux_irq);
-
-	strncpy(acpi_device_name(device), "PS/2 Mouse Controller",
-		sizeof(acpi_device_name(device)));
-	printk("ACPI: %s [%s] at irq %d\n",
-		acpi_device_name(device), acpi_device_bid(device), i8042_aux_irq);
+	if (pnp_irq_valid(dev, 0))
+		i8042_pnp_aux_irq = pnp_irq(dev, 0);
+
+	strncpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name));
+	if (strlen(pnp_dev_name(dev))) {
+		strncat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name));
+		strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name));
+	}
 
 	return 0;
 }
 
-static struct acpi_driver i8042_acpi_kbd_driver = {
-	.name		= "i8042",
-	.ids		= "PNP0303,PNP030B",
-	.ops		= {
-		.add		= i8042_acpi_kbd_add,
-	},
+static struct pnp_device_id pnp_kbd_devids[] = {
+	{ .id = "PNP0303", .driver_data = 0 },
+	{ .id = "PNP030b", .driver_data = 0 },
+	{ .id = "", },
 };
 
-static struct acpi_driver i8042_acpi_aux_driver = {
-	.name		= "i8042",
-	.ids		= "PNP0F03,PNP0F0B,PNP0F0E,PNP0F12,PNP0F13,SYN0801",
-	.ops		= {
-		.add		= i8042_acpi_aux_add,
-	},
+static struct pnp_driver i8042_pnp_kbd_driver = {
+	.name           = "i8042 kbd",
+	.id_table       = pnp_kbd_devids,
+	.probe          = i8042_pnp_kbd_probe,
+};
+
+static struct pnp_device_id pnp_aux_devids[] = {
+	{ .id = "PNP0f03", .driver_data = 0 },
+	{ .id = "PNP0f0b", .driver_data = 0 },
+	{ .id = "PNP0f0e", .driver_data = 0 },
+	{ .id = "PNP0f12", .driver_data = 0 },
+	{ .id = "PNP0f13", .driver_data = 0 },
+	{ .id = "PNP0f19", .driver_data = 0 },
+	{ .id = "PNP0f1c", .driver_data = 0 },
+	{ .id = "SYN0801", .driver_data = 0 },
+	{ .id = "", },
 };
 
-static int i8042_acpi_init(void)
+static struct pnp_driver i8042_pnp_aux_driver = {
+	.name           = "i8042 aux",
+	.id_table       = pnp_aux_devids,
+	.probe          = i8042_pnp_aux_probe,
+};
+
+static void i8042_pnp_exit(void)
+{
+	if (i8042_pnp_kbd_registered)
+		pnp_unregister_driver(&i8042_pnp_kbd_driver);
+
+	if (i8042_pnp_aux_registered)
+		pnp_unregister_driver(&i8042_pnp_aux_driver);
+}
+
+static int i8042_pnp_init(void)
 {
-	int result;
+	int result_kbd, result_aux;
 
-	if (acpi_disabled || i8042_noacpi) {
-		printk("i8042: ACPI detection disabled\n");
+	if (i8042_nopnp) {
+		printk("i8042: PNP detection disabled\n");
 		return 0;
 	}
 
-	result = acpi_bus_register_driver(&i8042_acpi_kbd_driver);
-	if (result < 0)
-		return result;
+	if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0)
+		i8042_pnp_kbd_registered = 1;
+	if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0)
+		i8042_pnp_aux_registered = 1;
 
-	if (result == 0) {
-		acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
+	if (result_kbd <= 0 && result_aux <= 0) {
+		i8042_pnp_exit();
+#if defined(__ia64__)
 		return -ENODEV;
+#else
+		printk(KERN_WARNING "PNP: No PS/2 controller found. Probing ports directly.\n");
+		return 0;
+#endif
+	}
+
+	if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
+	      i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
+		printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+			i8042_pnp_data_reg, i8042_data_reg);
+		i8042_pnp_data_reg = i8042_data_reg;
+	}
+
+	if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
+	      i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
+		printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+			i8042_pnp_command_reg, i8042_command_reg);
+		i8042_pnp_command_reg = i8042_command_reg;
+	}
+
+	if (!i8042_pnp_kbd_irq) {
+		printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq);
+		i8042_pnp_kbd_irq = i8042_kbd_irq;
+	}
+
+	if (result_aux > 0 && !i8042_pnp_aux_irq) {
+		printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq);
+		i8042_pnp_aux_irq = i8042_aux_irq;
 	}
-	i8042_acpi_kbd_registered = 1;
 
-	result = acpi_bus_register_driver(&i8042_acpi_aux_driver);
-	if (result >= 0)
-		i8042_acpi_aux_registered = 1;
-	if (result == 0)
+#if defined(__ia64__)
+	if (result_aux <= 0)
 		i8042_noaux = 1;
+#endif
+
+	i8042_data_reg = i8042_pnp_data_reg;
+	i8042_command_reg = i8042_pnp_command_reg;
+	i8042_kbd_irq = i8042_pnp_kbd_irq;
+	i8042_aux_irq = i8042_pnp_aux_irq;
+
+	printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n",
+		i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name,
+		i8042_data_reg, i8042_command_reg, i8042_kbd_irq,
+		(result_aux > 0) ? "," : "", i8042_aux_irq);
 
 	return 0;
 }
 
-static void i8042_acpi_exit(void)
-{
-	if (i8042_acpi_kbd_registered)
-		acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
-
-	if (i8042_acpi_aux_registered)
-		acpi_bus_unregister_driver(&i8042_acpi_aux_driver);
-}
 #endif
 
 static inline int i8042_platform_init(void)
@@ -281,8 +303,8 @@
 	i8042_kbd_irq = I8042_MAP_IRQ(1);
 	i8042_aux_irq = I8042_MAP_IRQ(12);
 
-#ifdef CONFIG_ACPI
-	if (i8042_acpi_init())
+#ifdef CONFIG_PNP
+	if (i8042_pnp_init())
 		return -1;
 #endif
 
@@ -291,8 +313,11 @@
 #endif
 
 #if defined(__i386__)
-	if (dmi_check_system(i8042_dmi_table))
+	if (dmi_check_system(i8042_dmi_noloop_table))
 		i8042_noloop = 1;
+
+	if (dmi_check_system(i8042_dmi_nomux_table))
+		i8042_nomux = 1;
 #endif
 
 	return 0;
@@ -300,8 +325,8 @@
 
 static inline void i8042_platform_exit(void)
 {
-#ifdef CONFIG_ACPI
-	i8042_acpi_exit();
+#ifdef CONFIG_PNP
+	i8042_pnp_exit();
 #endif
 }
 
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/i8042.c	2005-03-07 15:26:30 -08:00
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/serio.h>
 #include <linux/err.h>
+#include <linux/rcupdate.h>
 
 #include <asm/io.h>
 
@@ -52,12 +53,16 @@
 
 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");
+MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
 
-#ifdef CONFIG_ACPI
-static int i8042_noacpi;
-module_param_named(noacpi, i8042_noacpi, bool, 0);
-MODULE_PARM_DESC(noacpi, "Do not use ACPI to detect controller settings");
+static unsigned int i8042_blink_frequency = 500;
+module_param_named(panicblink, i8042_blink_frequency, uint, 0600);
+MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics");
+
+#ifdef CONFIG_PNP
+static int i8042_nopnp;
+module_param_named(nopnp, i8042_nopnp, bool, 0);
+MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
 #endif
 
 #define DEBUG
@@ -76,9 +81,10 @@
 
 #include "i8042.h"
 
-DEFINE_SPINLOCK(i8042_lock);
+static DEFINE_SPINLOCK(i8042_lock);
 
-struct i8042_values {
+struct i8042_port {
+	struct serio *serio;
 	int irq;
 	unsigned char disable;
 	unsigned char irqen;
@@ -87,25 +93,25 @@
 	char name[8];
 };
 
-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",
+#define I8042_KBD_PORT_NO	0
+#define I8042_AUX_PORT_NO	1
+#define I8042_MUX_PORT_NO	2
+#define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
+static struct i8042_port i8042_ports[I8042_NUM_PORTS] = {
+	{
+		.disable	= I8042_CTR_KBDDIS,
+		.irqen 		= I8042_CTR_KBDINT,
+		.mux		= -1,
+		.name		= "KBD",
+	},
+	{
+		.disable	= I8042_CTR_AUXDIS,
+		.irqen		= I8042_CTR_AUXINT,
+		.mux		= -1,
+		.name		= "AUX",
+	}
 };
 
-static struct i8042_values i8042_mux_values[I8042_NUM_MUX_PORTS];
-
-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_ctr;
 static unsigned char i8042_mux_open;
@@ -113,6 +119,7 @@
 static struct timer_list i8042_timer;
 static struct platform_device *i8042_platform_device;
 
+
 /*
  * Shared IRQ's require a device pointer, but this driver doesn't support
  * multiple devices
@@ -155,16 +162,17 @@
 static int i8042_flush(void)
 {
 	unsigned long flags;
-	unsigned char data;
+	unsigned char data, str;
 	int i = 0;
 
 	spin_lock_irqsave(&i8042_lock, flags);
 
-	while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) {
+	while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) {
 		udelay(50);
 		data = i8042_read_data();
+		i++;
 		dbg("%02x <- i8042 (flush, %s)", data,
-			i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd");
+			str & I8042_STR_AUXDATA ? "aux" : "kbd");
 	}
 
 	spin_unlock_irqrestore(&i8042_lock, flags);
@@ -246,19 +254,19 @@
  * i8042_aux_write() sends a byte out through the aux interface.
  */
 
-static int i8042_aux_write(struct serio *port, unsigned char c)
+static int i8042_aux_write(struct serio *serio, unsigned char c)
 {
-	struct i8042_values *values = port->port_data;
+	struct i8042_port *port = serio->port_data;
 	int retval;
 
 /*
  * Send the byte out.
  */
 
-	if (values->mux == -1)
+	if (port->mux == -1)
 		retval = i8042_command(&c, I8042_CMD_AUX_SEND);
 	else
-		retval = i8042_command(&c, I8042_CMD_MUX_SEND + values->mux);
+		retval = i8042_command(&c, I8042_CMD_MUX_SEND + port->mux);
 
 /*
  * Make sure the interrupt happens and the character is received even
@@ -274,9 +282,10 @@
  * i8042_activate_port() enables port on a chip.
  */
 
-static int i8042_activate_port(struct serio *port)
+static int i8042_activate_port(struct i8042_port *port)
 {
-	struct i8042_values *values = port->port_data;
+	if (!port->serio)
+		return -1;
 
 	i8042_flush();
 
@@ -284,12 +293,12 @@
 	 * Enable port again here because it is disabled if we are
 	 * resuming (normally it is enabled already).
 	 */
-	i8042_ctr &= ~values->disable;
+	i8042_ctr &= ~port->disable;
 
-	i8042_ctr |= values->irqen;
+	i8042_ctr |= port->irqen;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-		i8042_ctr &= ~values->irqen;
+		i8042_ctr &= ~port->irqen;
 		return -1;
 	}
 
@@ -302,22 +311,22 @@
  * It allocates the interrupt and calls i8042_enable_port.
  */
 
-static int i8042_open(struct serio *port)
+static int i8042_open(struct serio *serio)
 {
-	struct i8042_values *values = port->port_data;
+	struct i8042_port *port = serio->port_data;
 
-	if (values->mux != -1)
+	if (port->mux != -1)
 		if (i8042_mux_open++)
 			return 0;
 
-	if (request_irq(values->irq, i8042_interrupt,
+	if (request_irq(port->irq, i8042_interrupt,
 			SA_SHIRQ, "i8042", i8042_request_irq_cookie)) {
-		printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
+		printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name);
 		goto irq_fail;
 	}
 
 	if (i8042_activate_port(port)) {
-		printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", values->name);
+		printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name);
 		goto activate_fail;
 	}
 
@@ -326,11 +335,10 @@
 	return 0;
 
 activate_fail:
-	free_irq(values->irq, i8042_request_irq_cookie);
+	free_irq(port->irq, i8042_request_irq_cookie);
 
 irq_fail:
-	values->exists = 0;
-	serio_unregister_port_delayed(port);
+	serio_unregister_port_delayed(serio);
 
 	return -1;
 }
@@ -341,27 +349,58 @@
  * the BIOS could have used the AUX interrupt for PCI.
  */
 
-static void i8042_close(struct serio *port)
+static void i8042_close(struct serio *serio)
 {
-	struct i8042_values *values = port->port_data;
+	struct i8042_port *port = serio->port_data;
 
-	if (values->mux != -1)
+	if (port->mux != -1)
 		if (--i8042_mux_open)
 			return;
 
-	i8042_ctr &= ~values->irqen;
+	i8042_ctr &= ~port->irqen;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-		printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
-		return;
+		printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name);
+/*
+ * We still want to continue and free IRQ so if more data keeps coming in
+ * kernel will just ignore the irq.
+ */
 	}
 
-	free_irq(values->irq, i8042_request_irq_cookie);
+	free_irq(port->irq, i8042_request_irq_cookie);
 
 	i8042_flush();
 }
 
 /*
+ * i8042_start() is called by serio core when port is about to finish
+ * registering. It will mark port as existing so i8042_interrupt can
+ * start sending data through it.
+ */
+static int i8042_start(struct serio *serio)
+{
+	struct i8042_port *port = serio->port_data;
+
+	port->exists = 1;
+	mb();
+	return 0;
+}
+
+/*
+ * i8042_stop() marks serio port as non-existing so i8042_interrupt
+ * will not try to send data to the port that is about to go away.
+ * The function is called by serio core as part of unregister procedure.
+ */
+static void i8042_stop(struct serio *serio)
+{
+	struct i8042_port *port = serio->port_data;
+
+	port->exists = 0;
+	synchronize_kernel();
+	port->serio = NULL;
+}
+
+/*
  * i8042_interrupt() is the most important function in this driver -
  * it handles the interrupts from the i8042, and sends incoming bytes
  * to the upper layers.
@@ -369,25 +408,25 @@
 
 static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct i8042_port *port;
 	unsigned long flags;
-	unsigned char str, data = 0;
+	unsigned char str, data;
 	unsigned int dfl;
-	unsigned int aux_idx;
+	unsigned int port_no;
 	int ret;
 
 	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
 	spin_lock_irqsave(&i8042_lock, flags);
 	str = i8042_read_status();
-	if (str & I8042_STR_OBF)
-		data = i8042_read_data();
-	spin_unlock_irqrestore(&i8042_lock, flags);
-
-	if (~str & I8042_STR_OBF) {
+	if (unlikely(~str & I8042_STR_OBF)) {
+		spin_unlock_irqrestore(&i8042_lock, flags);
 		if (irq) dbg("Interrupt %d, without any data", irq);
 		ret = 0;
 		goto out;
 	}
+	data = i8042_read_data();
+	spin_unlock_irqrestore(&i8042_lock, flags);
 
 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
 		static unsigned long last_transmit;
@@ -419,39 +458,28 @@
 			}
 		}
 
-		aux_idx = (str >> 6) & 3;
-
-		dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
-			data, aux_idx, irq,
-			dfl & SERIO_PARITY ? ", bad parity" : "",
-			dfl & SERIO_TIMEOUT ? ", timeout" : "");
-
-		if (likely(i8042_mux_values[aux_idx].exists))
-			serio_interrupt(i8042_mux_port[aux_idx], data, dfl, regs);
-
+		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
 		last_str = str;
 		last_transmit = jiffies;
-		goto irq_ret;
+	} else {
+
+		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
+		      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+
+		port_no = (str & I8042_STR_AUXDATA) ?
+				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
 	}
 
-	dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
-	      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+	port = &i8042_ports[port_no];
 
 	dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
-		data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
-		dfl & SERIO_PARITY ? ", bad parity" : "",
-		dfl & SERIO_TIMEOUT ? ", timeout" : "");
+	    data, port->name, irq,
+	    dfl & SERIO_PARITY ? ", bad parity" : "",
+	    dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
+	if (likely(port->exists))
+		serio_interrupt(port->serio, data, dfl, regs);
 
-	if (str & I8042_STR_AUXDATA) {
-		if (likely(i8042_aux_values.exists))
-			serio_interrupt(i8042_aux_port, data, dfl, regs);
-	} else {
-		if (likely(i8042_kbd_values.exists))
-			serio_interrupt(i8042_kbd_port, data, dfl, regs);
-	}
-
-irq_ret:
 	ret = 1;
 out:
 	return IRQ_RETVAL(ret);
@@ -500,7 +528,7 @@
  * the controller has been switched into Multiplexed mode
  */
 
-static int i8042_enable_mux_ports(struct i8042_values *values)
+static int i8042_enable_mux_ports(void)
 {
 	unsigned char param;
 	int i;
@@ -535,7 +563,7 @@
  * LCS/Telegraphics.
  */
 
-static int __init i8042_check_mux(struct i8042_values *values)
+static int __init i8042_check_mux(void)
 {
 	unsigned char mux_version;
 
@@ -550,7 +578,7 @@
 	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
 		(mux_version >> 4) & 0xf, mux_version & 0xf);
 
-	if (i8042_enable_mux_ports(values))
+	if (i8042_enable_mux_ports())
 		return -1;
 
 	i8042_mux_present = 1;
@@ -563,7 +591,7 @@
  * the presence of an AUX interface.
  */
 
-static int __init i8042_check_aux(struct i8042_values *values)
+static int __init i8042_check_aux(void)
 {
 	unsigned char param;
 	static int i8042_check_aux_cookie;
@@ -573,10 +601,10 @@
  * in trying to detect AUX presence.
  */
 
-	if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
-				"i8042", &i8042_check_aux_cookie))
+	if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt,
+			SA_SHIRQ, "i8042", &i8042_check_aux_cookie))
                 return -1;
-	free_irq(values->irq, &i8042_check_aux_cookie);
+	free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie);
 
 /*
  * Get rid of bytes in the queue.
@@ -641,27 +669,25 @@
  * registers it, and reports to the user.
  */
 
-static int __init i8042_port_register(struct serio *port)
+static int __init i8042_port_register(struct i8042_port *port)
 {
-	struct i8042_values *values = port->port_data;
-
-	values->exists = 1;
-
-	i8042_ctr &= ~values->disable;
+	i8042_ctr &= ~port->disable;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
 		printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");
-		values->exists = 0;
+		kfree(port->serio);
+		port->serio = NULL;
+		i8042_ctr |= port->disable;
 		return -1;
 	}
 
 	printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
-	       values->name,
+	       port->name,
 	       (unsigned long) I8042_DATA_REG,
 	       (unsigned long) I8042_COMMAND_REG,
-	       values->irq);
+	       port->irq);
 
-	serio_register_port(port);
+	serio_register_port(port->serio);
 
 	return 0;
 }
@@ -688,7 +714,10 @@
  * before doing anything else.
  */
 
-	i8042_flush();
+	if (i8042_flush() == I8042_BUFFER_SIZE) {
+		printk(KERN_ERR "i8042.c: No controller found.\n");
+		return -1;
+	}
 
 	if (i8042_reset) {
 
@@ -771,7 +800,7 @@
 /*
  * Reset the controller.
  */
-void i8042_controller_reset(void)
+static void i8042_controller_reset(void)
 {
 	unsigned char param;
 
@@ -806,7 +835,7 @@
  * able to talk to the hardware when rebooting.
  */
 
-void i8042_controller_cleanup(void)
+static void i8042_controller_cleanup(void)
 {
 	int i;
 
@@ -816,39 +845,41 @@
  * Reset anything that is connected to the ports.
  */
 
-	if (i8042_kbd_values.exists)
-		serio_cleanup(i8042_kbd_port);
-
-	if (i8042_aux_values.exists)
-		serio_cleanup(i8042_aux_port);
-
-	for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
-		if (i8042_mux_values[i].exists)
-			serio_cleanup(i8042_mux_port[i]);
+	for (i = 0; i < I8042_NUM_PORTS; i++)
+		if (i8042_ports[i].exists)
+			serio_cleanup(i8042_ports[i].serio);
 
 	i8042_controller_reset();
 }
 
 
-static int blink_frequency = 500;
-module_param_named(panicblink, blink_frequency, int, 0600);
+/*
+ * i8042_panic_blink() will flash the keyboard LEDs and is called when
+ * kernel panics. Flashing LEDs is useful for users running X who may
+ * not see the console and will help distingushing panics from "real"
+ * lockups.
+ *
+ * Note that DELAY has a limit of 10ms so we will not get stuck here
+ * waiting for KBC to free up even if KBD interrupt is off
+ */
 
-/* Catch the case when the kbd interrupt is off */
 #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
 
-/* Tell the user who may be running in X and not see the console that we have
-   panic'ed. This is to distingush panics from "real" lockups.  */
 static long i8042_panic_blink(long count)
 {
 	long delay = 0;
 	static long last_blink;
 	static char led;
-	/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is
-	   different. */
-	if (!blink_frequency)
+
+	/*
+	 * We expect frequency to be about 1/2s. KDB uses about 1s.
+	 * Make sure they are different.
+	 */
+	if (!i8042_blink_frequency)
 		return 0;
-	if (count - last_blink < blink_frequency)
+	if (count - last_blink < i8042_blink_frequency)
 		return 0;
+
 	led ^= 0x01 | 0x04;
 	while (i8042_read_status() & I8042_STR_IBF)
 		DELAY;
@@ -869,7 +900,7 @@
  * Here we try to restore the original BIOS settings
  */
 
-static int i8042_suspend(struct device *dev, u32 state, u32 level)
+static int i8042_suspend(struct device *dev, pm_message_t state, u32 level)
 {
 	if (level == SUSPEND_DISABLE) {
 		del_timer_sync(&i8042_timer);
@@ -897,24 +928,16 @@
 	}
 
 	if (i8042_mux_present)
-		if (i8042_set_mux_mode(1, NULL) ||
-		    i8042_enable_mux_ports(&i8042_aux_values)) {
+		if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
 			printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n");
-		}
 
 /*
- * Reconnect anything that was connected to the ports.
+ * Activate all ports.
  */
 
-	if (i8042_kbd_values.exists && i8042_activate_port(i8042_kbd_port) == 0)
-		serio_reconnect(i8042_kbd_port);
-
-	if (i8042_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0)
-		serio_reconnect(i8042_aux_port);
+	for (i = 0; i < I8042_NUM_PORTS; i++)
+		i8042_activate_port(&i8042_ports[i]);
 
-	for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
-		if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port[i]) == 0)
-			serio_reconnect(i8042_mux_port[i]);
 /*
  * Restart timer (for polling "stuck" data)
  */
@@ -944,72 +967,83 @@
 	.shutdown	= i8042_shutdown,
 };
 
-static struct serio * __init i8042_allocate_kbd_port(void)
+static void __init i8042_create_kbd_port(void)
 {
 	struct serio *serio;
+	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
 
 	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,
+		serio->id.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->start		= i8042_start;
+		serio->stop		= i8042_stop;
+		serio->port_data	= port;
 		serio->dev.parent	= &i8042_platform_device->dev;
 		strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name));
 		strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
-	}
 
-	return serio;
+		port->serio = serio;
+		i8042_port_register(port);
+	}
 }
 
-static struct serio * __init i8042_allocate_aux_port(void)
+static void __init i8042_create_aux_port(void)
 {
 	struct serio *serio;
+	struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];
 
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->write		= i8042_aux_write;
 		serio->open		= i8042_open;
 		serio->close		= i8042_close;
-		serio->port_data	= &i8042_aux_values,
+		serio->start		= i8042_start;
+		serio->stop		= i8042_stop;
+		serio->port_data	= port;
 		serio->dev.parent	= &i8042_platform_device->dev;
 		strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name));
 		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
-	}
 
-	return serio;
+		port->serio = serio;
+		i8042_port_register(port);
+	}
 }
 
-static struct serio * __init i8042_allocate_mux_port(int index)
+static void __init i8042_create_mux_port(int index)
 {
 	struct serio *serio;
-	struct i8042_values *values = &i8042_mux_values[index];
+	struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index];
 
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
-		*values = i8042_aux_values;
-		snprintf(values->name, sizeof(values->name), "AUX%d", index);
-		values->mux = index;
-
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->write		= i8042_aux_write;
 		serio->open		= i8042_open;
 		serio->close		= i8042_close;
-		serio->port_data	= values;
+		serio->start		= i8042_start;
+		serio->stop		= i8042_stop;
+		serio->port_data	= port;
 		serio->dev.parent	= &i8042_platform_device->dev;
 		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;
+		*port = i8042_ports[I8042_AUX_PORT_NO];
+		port->exists = 0;
+		snprintf(port->name, sizeof(port->name), "AUX%d", index);
+		port->mux = index;
+		port->serio = serio;
+		i8042_port_register(port);
+	}
 }
 
-int __init i8042_init(void)
+static int __init i8042_init(void)
 {
 	int i;
 	int err;
@@ -1022,60 +1056,51 @@
 	if (i8042_platform_init())
 		return -EBUSY;
 
-	i8042_aux_values.irq = I8042_AUX_IRQ;
-	i8042_kbd_values.irq = I8042_KBD_IRQ;
+	i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
+	i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;
 
-	if (i8042_controller_init())
+	if (i8042_controller_init()) {
+		i8042_platform_exit();
 		return -ENODEV;
+	}
 
 	err = driver_register(&i8042_driver);
-	if (err)
+	if (err) {
+		i8042_platform_exit();
 		return err;
+	}
 
 	i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0);
 	if (IS_ERR(i8042_platform_device)) {
 		driver_unregister(&i8042_driver);
+		i8042_platform_exit();
 		return PTR_ERR(i8042_platform_device);
 	}
 
-	if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) {
-		if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values))
-			for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
-				i8042_mux_port[i] = i8042_allocate_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);
-		}
+	if (!i8042_noaux && !i8042_check_aux()) {
+		if (!i8042_nomux && !i8042_check_mux())
+			for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
+				i8042_create_mux_port(i);
+		else
+			i8042_create_aux_port();
 	}
 
-	i8042_kbd_port = i8042_allocate_kbd_port();
-	if (i8042_kbd_port)
-		i8042_port_register(i8042_kbd_port);
+	i8042_create_kbd_port();
 
 	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
 	return 0;
 }
 
-void __exit i8042_exit(void)
+static void __exit i8042_exit(void)
 {
 	int i;
 
 	i8042_controller_cleanup();
 
-	if (i8042_kbd_values.exists)
-		serio_unregister_port(i8042_kbd_port);
-
-	if (i8042_aux_values.exists)
-		serio_unregister_port(i8042_aux_port);
-
-	for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
-		if (i8042_mux_values[i].exists)
-			serio_unregister_port(i8042_mux_port[i]);
+	for (i = 0; i < I8042_NUM_PORTS; i++)
+		if (i8042_ports[i].exists)
+			serio_unregister_port(i8042_ports[i].serio);
 
 	del_timer_sync(&i8042_timer);
 
diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
--- a/drivers/input/serio/i8042.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/i8042.h	2005-03-07 15:26:30 -08:00
@@ -100,10 +100,10 @@
 
 /*
  * Expected maximum internal i8042 buffer size. This is used for flushing
- * the i8042 buffers. 32 should be more than enough.
+ * the i8042 buffers.
  */
 
-#define I8042_BUFFER_SIZE	32
+#define I8042_BUFFER_SIZE	16
 
 /*
  * Number of AUX ports on controllers supporting active multiplexing
@@ -117,13 +117,13 @@
  */
 
 #ifdef DEBUG
-static unsigned long i8042_start;
-#define dbg_init() do { i8042_start = jiffies; } while (0)
+static unsigned long i8042_start_time;
+#define dbg_init() do { i8042_start_time = jiffies; } while (0)
 #define dbg(format, arg...) 							\
 	do { 									\
 		if (i8042_debug)						\
 			printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" ,	\
-	 			## arg, (int) (jiffies - i8042_start));		\
+	 			## arg, (int) (jiffies - i8042_start_time));	\
 	} while (0)
 #else
 #define dbg_init() do { } while (0)
diff -Nru a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
--- a/drivers/input/serio/maceps2.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/maceps2.c	2005-03-07 15:26:30 -08:00
@@ -125,7 +125,7 @@
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->write		= maceps2_write;
 		serio->open		= maceps2_open;
 		serio->close		= maceps2_close;
diff -Nru a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
--- a/drivers/input/serio/parkbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/parkbd.c	2005-03-07 15:26:30 -08:00
@@ -1,31 +1,47 @@
 /*
- * $Id: parkbd.c,v 1.10 2002/03/13 10:09:20 vojtech Exp $
+ *  Parallel port to Keyboard port adapter driver for Linux
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *  Copyright (c) 1999-2004 Vojtech Pavlik
  */
 
 /*
- *  Parallel port to Keyboard port adapter driver for Linux
+ * 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.
  */
 
 /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * To connect an AT or XT keyboard to the parallel port, a fairly simple adapter
+ * can be made:
+ * 
+ *  Parallel port            Keyboard port
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ *     +5V --------------------- +5V (4)
+ *  
+ *                 ______
+ *     +5V -------|______|--.
+ *                          |
+ *     ACK (10) ------------|
+ *                          |--- KBD CLOCK (5)
+ *     STROBE (1) ---|<|----'
+ *     
+ *                 ______
+ *     +5V -------|______|--.
+ *                          |
+ *     BUSY (11) -----------|
+ *                          |--- KBD DATA (1)
+ *     AUTOFD (14) --|<|----'
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *     GND (18-25) ------------- GND (3)
+ *     
+ * The diodes can be fairly any type, and the resistors should be somewhere
+ * around 5 kOhm, but the adapter will likely work without the resistors,
+ * too.
  *
- * 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:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * The +5V source can be taken either from USB, from mouse or keyboard ports,
+ * or from a joystick port. Unfortunately, the parallel port of a PC doesn't
+ * have a +5V pin, and feeding the keyboard from signal pins is out of question
+ * with 300 mA power reqirement of a typical AT keyboard.
  */
 
 #include <linux/module.h>
@@ -158,7 +174,7 @@
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type = parkbd_mode;
+		serio->id.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);
@@ -167,7 +183,7 @@
 	return serio;
 }
 
-int __init parkbd_init(void)
+static int __init parkbd_init(void)
 {
 	int err;
 
@@ -191,7 +207,7 @@
 	return 0;
 }
 
-void __exit parkbd_exit(void)
+static void __exit parkbd_exit(void)
 {
 	parport_release(parkbd_dev);
 	serio_unregister_port(parkbd_port);
diff -Nru a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
--- a/drivers/input/serio/pcips2.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/pcips2.c	2005-03-07 15:26:30 -08:00
@@ -150,7 +150,7 @@
 	memset(ps2if, 0, sizeof(struct pcips2_data));
 	memset(serio, 0, sizeof(struct serio));
 
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= pcips2_write;
 	serio->open		= pcips2_open;
 	serio->close		= pcips2_close;
@@ -217,7 +217,7 @@
 
 static int __init pcips2_init(void)
 {
-	return pci_module_init(&pcips2_driver);
+	return pci_register_driver(&pcips2_driver);
 }
 
 static void __exit pcips2_exit(void)
diff -Nru a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
--- a/drivers/input/serio/q40kbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/q40kbd.c	2005-03-07 15:26:30 -08:00
@@ -122,7 +122,7 @@
 	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
 		memset(serio, 0, sizeof(struct serio));
-		serio->type		= SERIO_8042;
+		serio->id.type		= SERIO_8042;
 		serio->open		= q40kbd_open;
 		serio->close		= q40kbd_close;
 		serio->dev.parent	= &q40kbd_device->dev;
diff -Nru a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
--- a/drivers/input/serio/rpckbd.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/rpckbd.c	2005-03-07 15:26:30 -08:00
@@ -115,7 +115,7 @@
 		return -ENOMEM;
 
 	memset(serio, 0, sizeof(struct serio));
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= rpckbd_write;
 	serio->open		= rpckbd_open;
 	serio->close		= rpckbd_close;
diff -Nru a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
--- a/drivers/input/serio/sa1111ps2.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/sa1111ps2.c	2005-03-07 15:26:30 -08:00
@@ -245,7 +245,7 @@
 	memset(ps2if, 0, sizeof(struct ps2if));
 	memset(serio, 0, sizeof(struct serio));
 
-	serio->type		= SERIO_8042;
+	serio->id.type		= SERIO_8042;
 	serio->write		= ps2_write;
 	serio->open		= ps2_open;
 	serio->close		= ps2_close;
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/serio.c	2005-03-07 15:26:30 -08:00
@@ -41,76 +41,98 @@
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(serio_interrupt);
-EXPORT_SYMBOL(serio_register_port);
-EXPORT_SYMBOL(serio_register_port_delayed);
+EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
-EXPORT_SYMBOL(serio_unregister_port_delayed);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_unregister_port_delayed);
+EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(serio_unregister_driver);
 EXPORT_SYMBOL(serio_open);
 EXPORT_SYMBOL(serio_close);
 EXPORT_SYMBOL(serio_rescan);
 EXPORT_SYMBOL(serio_reconnect);
 
-static DECLARE_MUTEX(serio_sem);	/* protects serio_list and serio_diriver_list */
+/*
+ * serio_sem protects entire serio subsystem and is taken every time
+ * serio port or driver registrered or unregistered.
+ */
+static DECLARE_MUTEX(serio_sem);
+
 static LIST_HEAD(serio_list);
-static LIST_HEAD(serio_driver_list);
-static unsigned int serio_no;
 
-struct bus_type serio_bus = {
+static 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_add_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)
+static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
 {
-	get_driver(&drv->driver);
+	while (ids->type || ids->proto) {
+		if ((ids->type == SERIO_ANY || ids->type == serio->id.type) &&
+		    (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) &&
+		    (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) &&
+		    (ids->id == SERIO_ANY || ids->id == serio->id.id))
+			return 1;
+		ids++;
+	}
+	return 0;
+}
 
-	drv->connect(serio, drv);
-	if (serio->drv) {
-		down_write(&serio_bus.subsys.rwsem);
+/*
+ * Basic serio -> driver core mappings
+ */
+
+static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
+{
+	down_write(&serio_bus.subsys.rwsem);
+
+	if (serio_match_port(drv->id_table, serio)) {
 		serio->dev.driver = &drv->driver;
+		if (drv->connect(serio, drv)) {
+			serio->dev.driver = NULL;
+			goto out;
+		}
 		device_bind_driver(&serio->dev);
-		up_write(&serio_bus.subsys.rwsem);
-		return 1;
 	}
+out:
+	up_write(&serio_bus.subsys.rwsem);
+}
 
-	put_driver(&drv->driver);
-	return 0;
+static void serio_release_driver(struct serio *serio)
+{
+	down_write(&serio_bus.subsys.rwsem);
+	device_release_driver(&serio->dev);
+	up_write(&serio_bus.subsys.rwsem);
 }
 
-/* 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;
+	down_write(&serio_bus.subsys.rwsem);
+	device_attach(&serio->dev);
+	up_write(&serio_bus.subsys.rwsem);
 }
 
+
 /*
  * Serio event processing.
  */
 
-struct serio_event {
-	int type;
-	struct serio *serio;
-	struct list_head node;
-};
-
 enum serio_event_type {
 	SERIO_RESCAN,
 	SERIO_RECONNECT,
 	SERIO_REGISTER_PORT,
 	SERIO_UNREGISTER_PORT,
+	SERIO_REGISTER_DRIVER,
+};
+
+struct serio_event {
+	enum serio_event_type type;
+	void *object;
+	struct module *owner;
+	struct list_head node;
 };
 
 static DEFINE_SPINLOCK(serio_event_lock);	/* protects serio_event_list */
@@ -119,24 +141,82 @@
 static DECLARE_COMPLETION(serio_exited);
 static int serio_pid;
 
-static void serio_queue_event(struct serio *serio, int event_type)
+static void serio_queue_event(void *object, struct module *owner,
+			      enum serio_event_type event_type)
 {
 	unsigned long flags;
 	struct serio_event *event;
 
 	spin_lock_irqsave(&serio_event_lock, flags);
 
+	/*
+ 	 * Scan event list for the other events for the same serio port,
+	 * starting with the most recent one. If event is the same we
+	 * do not need add new one. If event is of different type we
+	 * need to add this event and should not look further because
+	 * we need to preseve sequence of distinct events.
+ 	 */
+	list_for_each_entry_reverse(event, &serio_event_list, node) {
+		if (event->object == object) {
+			if (event->type == event_type)
+				goto out;
+			break;
+		}
+	}
+
 	if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
+		if (!try_module_get(owner)) {
+			printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type);
+			goto out;
+		}
+
 		event->type = event_type;
-		event->serio = serio;
+		event->object = object;
+		event->owner = owner;
 
 		list_add_tail(&event->node, &serio_event_list);
 		wake_up(&serio_wait);
+	} else {
+		printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type);
+	}
+out:
+	spin_unlock_irqrestore(&serio_event_lock, flags);
+}
+
+static void serio_free_event(struct serio_event *event)
+{
+	module_put(event->owner);
+	kfree(event);
+}
+
+static void serio_remove_duplicate_events(struct serio_event *event)
+{
+	struct list_head *node, *next;
+	struct serio_event *e;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serio_event_lock, flags);
+
+	list_for_each_safe(node, next, &serio_event_list) {
+		e = list_entry(node, struct serio_event, node);
+		if (event->object == e->object) {
+			/*
+			 * If this event is of different type we should not
+			 * look further - we only suppress duplicate events
+			 * that were sent back-to-back.
+			 */
+			if (event->type != e->type)
+				break;
+
+			list_del_init(node);
+			serio_free_event(e);
+		}
 	}
 
 	spin_unlock_irqrestore(&serio_event_lock, flags);
 }
 
+
 static struct serio_event *serio_get_event(void)
 {
 	struct serio_event *event;
@@ -151,7 +231,7 @@
 	}
 
 	node = serio_event_list.next;
-	event = container_of(node, struct serio_event, node);
+	event = list_entry(node, struct serio_event, node);
 	list_del_init(node);
 
 	spin_unlock_irqrestore(&serio_event_lock, flags);
@@ -162,39 +242,50 @@
 static void serio_handle_events(void)
 {
 	struct serio_event *event;
+	struct serio_driver *serio_drv;
 
-	while ((event = serio_get_event())) {
+	down(&serio_sem);
 
-		down(&serio_sem);
+	while ((event = serio_get_event())) {
 
 		switch (event->type) {
-			case SERIO_REGISTER_PORT :
-				serio_create_port(event->serio);
-				serio_connect_port(event->serio, NULL);
+			case SERIO_REGISTER_PORT:
+				serio_add_port(event->object);
 				break;
 
-			case SERIO_UNREGISTER_PORT :
-				serio_disconnect_port(event->serio);
-				serio_destroy_port(event->serio);
+			case SERIO_UNREGISTER_PORT:
+				serio_disconnect_port(event->object);
+				serio_destroy_port(event->object);
 				break;
 
-			case SERIO_RECONNECT :
-				serio_reconnect_port(event->serio);
+			case SERIO_RECONNECT:
+				serio_reconnect_port(event->object);
 				break;
 
-			case SERIO_RESCAN :
-				serio_disconnect_port(event->serio);
-				serio_connect_port(event->serio, NULL);
+			case SERIO_RESCAN:
+				serio_disconnect_port(event->object);
+				serio_find_driver(event->object);
 				break;
+
+			case SERIO_REGISTER_DRIVER:
+				serio_drv = event->object;
+				driver_register(&serio_drv->driver);
+				break;
+
 			default:
 				break;
 		}
 
-		up(&serio_sem);
-		kfree(event);
+		serio_remove_duplicate_events(event);
+		serio_free_event(event);
 	}
+
+	up(&serio_sem);
 }
 
+/*
+ * Remove all events that have been submitted for a given serio port.
+ */
 static void serio_remove_pending_events(struct serio *serio)
 {
 	struct list_head *node, *next;
@@ -204,16 +295,45 @@
 	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) {
+		event = list_entry(node, struct serio_event, node);
+		if (event->object == serio) {
 			list_del_init(node);
-			kfree(event);
+			serio_free_event(event);
 		}
 	}
 
 	spin_unlock_irqrestore(&serio_event_lock, flags);
 }
 
+/*
+ * Destroy child serio port (if any) that has not been fully registered yet.
+ *
+ * Note that we rely on the fact that port can have only one child and therefore
+ * only one child registration request can be pending. Additionally, children
+ * are registered by driver's connect() handler so there can't be a grandchild
+ * pending registration together with a child.
+ */
+static struct serio *serio_get_pending_child(struct serio *parent)
+{
+	struct serio_event *event;
+	struct serio *serio, *child = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serio_event_lock, flags);
+
+	list_for_each_entry(event, &serio_event_list, node) {
+		if (event->type == SERIO_REGISTER_PORT) {
+			serio = event->object;
+			if (serio->parent == parent) {
+				child = serio;
+				break;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&serio_event_lock, flags);
+	return child;
+}
 
 static int serio_thread(void *nothing)
 {
@@ -244,6 +364,30 @@
 	return sprintf(buf, "%s\n", serio->name);
 }
 
+static ssize_t serio_show_id_type(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.type);
+}
+
+static ssize_t serio_show_id_proto(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.proto);
+}
+
+static ssize_t serio_show_id_id(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.id);
+}
+
+static ssize_t serio_show_id_extra(struct device *dev, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+	return sprintf(buf, "%02x\n", serio->id.extra);
+}
+
 static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
 {
 	struct serio *serio = to_serio_port(dev);
@@ -261,10 +405,10 @@
 		serio_reconnect_port(serio);
 	} else if (!strncmp(buf, "rescan", count)) {
 		serio_disconnect_port(serio);
-		serio_connect_port(serio, NULL);
+		serio_find_driver(serio);
 	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
 		serio_disconnect_port(serio);
-		serio_connect_port(serio, to_serio_driver(drv));
+		serio_bind_driver(serio, to_serio_driver(drv));
 		put_driver(drv);
 	} else {
 		retval = -EINVAL;
@@ -300,6 +444,10 @@
 
 static struct device_attribute serio_device_attrs[] = {
 	__ATTR(description, S_IRUGO, serio_show_description, NULL),
+	__ATTR(id_type, S_IRUGO, serio_show_id_type, NULL),
+	__ATTR(id_proto, S_IRUGO, serio_show_id_proto, NULL),
+	__ATTR(id_id, S_IRUGO, serio_show_id_id, NULL),
+	__ATTR(id_extra, S_IRUGO, serio_show_id_extra, NULL),
 	__ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
 	__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
 	__ATTR_NULL
@@ -314,95 +462,88 @@
 	module_put(THIS_MODULE);
 }
 
-static void serio_create_port(struct serio *serio)
+/*
+ * Prepare serio port for registration.
+ */
+static void serio_init_port(struct serio *serio)
 {
-	try_module_get(THIS_MODULE);
+	static atomic_t serio_no = ATOMIC_INIT(0);
+
+	__module_get(THIS_MODULE);
 
 	spin_lock_init(&serio->lock);
 	init_MUTEX(&serio->drv_sem);
-	list_add_tail(&serio->node, &serio_list);
-	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++);
+	device_initialize(&serio->dev);
+	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id),
+		 "serio%ld", (long)atomic_inc_return(&serio_no) - 1);
 	serio->dev.bus = &serio_bus;
 	serio->dev.release = serio_release_port;
 	if (serio->parent)
 		serio->dev.parent = &serio->parent->dev;
-	device_register(&serio->dev);
 }
 
 /*
- * serio_destroy_port() completes deregistration process and removes
- * port from the system
+ * Complete serio port registration.
+ * Driver core will attempt to find appropriate driver for the port.
  */
-static void serio_destroy_port(struct serio *serio)
+static void serio_add_port(struct serio *serio)
 {
-	struct serio_driver *drv = serio->drv;
-	unsigned long flags;
-
-	serio_remove_pending_events(serio);
-	list_del_init(&serio->node);
-
-	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);
-	}
-
 	if (serio->parent) {
-		spin_lock_irqsave(&serio->parent->lock, flags);
-		serio->parent->child = NULL;
-		spin_unlock_irqrestore(&serio->parent->lock, flags);
+		serio_pause_rx(serio->parent);
+		serio->parent->child = serio;
+		serio_continue_rx(serio->parent);
 	}
 
-	device_unregister(&serio->dev);
+	list_add_tail(&serio->node, &serio_list);
+	if (serio->start)
+		serio->start(serio);
+	device_add(&serio->dev);
+	serio->registered = 1;
 }
 
 /*
- * 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.
+ * serio_destroy_port() completes deregistration process and removes
+ * port from the system
  */
-static void serio_connect_port(struct serio *serio, struct serio_driver *drv)
+static void serio_destroy_port(struct serio *serio)
 {
-	WARN_ON(serio->drv);
-	WARN_ON(serio->child);
+	struct serio *child;
 
-	if (drv)
-		serio_bind_driver(serio, drv);
-	else if (!serio->manual_bind)
-		serio_find_driver(serio);
-
-	/* Ok, now bind children, if any */
-	while (serio->child) {
-		serio = serio->child;
+	child = serio_get_pending_child(serio);
+	if (child) {
+		serio_remove_pending_events(child);
+		put_device(&child->dev);
+	}
 
-		WARN_ON(serio->drv);
-		WARN_ON(serio->child);
+	if (serio->stop)
+		serio->stop(serio);
 
-		serio_create_port(serio);
+	if (serio->parent) {
+		serio_pause_rx(serio->parent);
+		serio->parent->child = NULL;
+		serio_continue_rx(serio->parent);
+		serio->parent = NULL;
+	}
 
-		if (!serio->manual_bind) {
-			/*
-			 * 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);
-		}
+	if (serio->registered) {
+		device_del(&serio->dev);
+		list_del_init(&serio->node);
+		serio->registered = 0;
 	}
+
+	serio_remove_pending_events(serio);
+	put_device(&serio->dev);
 }
 
 /*
- *
+ * Reconnect serio port and all its children (re-initialize attached devices)
  */
 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);
+			serio_find_driver(serio);
 			/* Ok, old children are now gone, we are done */
 			break;
 		}
@@ -416,8 +557,7 @@
  */
 static void serio_disconnect_port(struct serio *serio)
 {
-	struct serio_driver *drv = serio->drv;
-	struct serio *s;
+	struct serio *s, *parent;
 
 	if (serio->child) {
 		/*
@@ -425,56 +565,46 @@
 		 * first, staring with the leaf one, since we don't want
 		 * to do recursion
 		 */
+		for (s = serio; s->child; s = s->child)
+			/* empty */;
+
 		do {
-			s = serio->child;
-		} while (s->child);
+			parent = s->parent;
 
-		while (s != serio) {
-			s = s->parent;
-			serio_destroy_port(s->child);
-		}
+			serio_release_driver(s);
+			serio_destroy_port(s);
+		} while ((s = parent) != serio);
 	}
 
 	/*
 	 * 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);
-	}
+	serio_release_driver(serio);
 }
 
 void serio_rescan(struct serio *serio)
 {
-	serio_queue_event(serio, SERIO_RESCAN);
+	serio_queue_event(serio, NULL, SERIO_RESCAN);
 }
 
 void serio_reconnect(struct serio *serio)
 {
-	serio_queue_event(serio, SERIO_RECONNECT);
-}
-
-void serio_register_port(struct serio *serio)
-{
-	down(&serio_sem);
-	serio_create_port(serio);
-	serio_connect_port(serio, NULL);
-	up(&serio_sem);
+	serio_queue_event(serio, NULL, SERIO_RECONNECT);
 }
 
 /*
  * Submits register request to kseriod for subsequent execution.
- * Can be used when it is not obvious whether the serio_sem is
- * taken or not and when delayed execution is feasible.
+ * Note that port registration is always asynchronous.
  */
-void serio_register_port_delayed(struct serio *serio)
+void __serio_register_port(struct serio *serio, struct module *owner)
 {
-	serio_queue_event(serio, SERIO_REGISTER_PORT);
+	serio_init_port(serio);
+	serio_queue_event(serio, owner, SERIO_REGISTER_PORT);
 }
 
+/*
+ * Synchronously unregisters serio port.
+ */
 void serio_unregister_port(struct serio *serio)
 {
 	down(&serio_sem);
@@ -484,13 +614,13 @@
 }
 
 /*
- * Submits unregister request to kseriod for subsequent execution.
+ * Submits register request to kseriod for subsequent execution.
  * Can be used when it is not obvious whether the serio_sem is
  * taken or not and when delayed execution is feasible.
  */
-void serio_unregister_port_delayed(struct serio *serio)
+void __serio_unregister_port_delayed(struct serio *serio, struct module *owner)
 {
-	serio_queue_event(serio, SERIO_UNREGISTER_PORT);
+	serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT);
 }
 
 
@@ -535,35 +665,30 @@
 	__ATTR_NULL
 };
 
-void serio_register_driver(struct serio_driver *drv)
+static int serio_driver_probe(struct device *dev)
 {
-	struct serio *serio;
-
-	down(&serio_sem);
+	struct serio *serio = to_serio_port(dev);
+	struct serio_driver *drv = to_serio_driver(dev->driver);
 
-	list_add_tail(&drv->node, &serio_driver_list);
+	return drv->connect(serio, drv);
+}
 
-	drv->driver.bus = &serio_bus;
-	driver_register(&drv->driver);
+static int serio_driver_remove(struct device *dev)
+{
+	struct serio *serio = to_serio_port(dev);
+	struct serio_driver *drv = to_serio_driver(dev->driver);
 
-	if (drv->manual_bind)
-		goto out;
+	drv->disconnect(serio);
+	return 0;
+}
 
-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;
-		}
-	}
+void __serio_register_driver(struct serio_driver *drv, struct module *owner)
+{
+	drv->driver.bus = &serio_bus;
+	drv->driver.probe = serio_driver_probe;
+	drv->driver.remove = serio_driver_remove;
 
-out:
-	up(&serio_sem);
+	serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER);
 }
 
 void serio_unregister_driver(struct serio_driver *drv)
@@ -571,21 +696,19 @@
 	struct serio *serio;
 
 	down(&serio_sem);
-
-	list_del_init(&drv->node);
+	drv->manual_bind = 1;	/* so serio_find_driver ignores it */
 
 start_over:
 	list_for_each_entry(serio, &serio_list, node) {
 		if (serio->drv == drv) {
 			serio_disconnect_port(serio);
-			serio_connect_port(serio, NULL);
+			serio_find_driver(serio);
 			/* we could've deleted some ports, restart */
 			goto start_over;
 		}
 	}
 
 	driver_unregister(&drv->driver);
-
 	up(&serio_sem);
 }
 
@@ -598,6 +721,75 @@
 	up(&serio->drv_sem);
 }
 
+static int serio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct serio *serio = to_serio_port(dev);
+	struct serio_driver *serio_drv = to_serio_driver(drv);
+
+	if (serio->manual_bind || serio_drv->manual_bind)
+		return 0;
+
+	return serio_match_port(serio_drv->id_table, serio);
+}
+
+#ifdef CONFIG_HOTPLUG
+
+#define PUT_ENVP(fmt, val) 						\
+do {									\
+	envp[i++] = buffer;						\
+	length += snprintf(buffer, buffer_size - length, fmt, val);	\
+	if (buffer_size - length <= 0 || i >= num_envp)			\
+		return -ENOMEM;						\
+	length++;							\
+	buffer += length;						\
+} while (0)
+static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+	struct serio *serio;
+	int i = 0;
+	int length = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	serio = to_serio_port(dev);
+
+	PUT_ENVP("SERIO_TYPE=%02x", serio->id.type);
+	PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto);
+	PUT_ENVP("SERIO_ID=%02x", serio->id.id);
+	PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra);
+
+	envp[i] = NULL;
+
+	return 0;
+}
+#undef PUT_ENVP
+
+#else
+
+static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+	return -ENODEV;
+}
+
+#endif /* CONFIG_HOTPLUG */
+
+static int serio_resume(struct device *dev)
+{
+	struct serio *serio = to_serio_port(dev);
+
+	if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+		serio_disconnect_port(serio);
+		/*
+		 * Driver re-probing can take a while, so better let kseriod
+		 * deal with it.
+		 */
+		serio_rescan(serio);
+	}
+
+	return 0;
+}
+
 /* called from serio_driver->connect/disconnect methods under serio_sem */
 int serio_open(struct serio *serio, struct serio_driver *drv)
 {
@@ -629,14 +821,9 @@
 
         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;
-			}
-		}
+	} else if (!dfl && serio->registered) {
+		serio_rescan(serio);
+		ret = IRQ_HANDLED;
 	}
 
 	spin_unlock_irqrestore(&serio->lock, flags);
@@ -647,12 +834,15 @@
 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_ERR "serio: Failed to start kseriod\n");
 		return -1;
 	}
 
 	serio_bus.dev_attrs = serio_device_attrs;
 	serio_bus.drv_attrs = serio_driver_attrs;
+	serio_bus.match = serio_bus_match;
+	serio_bus.hotplug = serio_hotplug;
+	serio_bus.resume = serio_resume;
 	bus_register(&serio_bus);
 
 	return 0;
diff -Nru a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
--- a/drivers/input/serio/serio_raw.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/serio_raw.c	2005-03-07 15:26:30 -08:00
@@ -235,7 +235,7 @@
 	return 0;
 }
 
-struct file_operations serio_raw_fops = {
+static struct file_operations serio_raw_fops = {
 	.owner =	THIS_MODULE,
 	.open =		serio_raw_open,
 	.release =	serio_raw_release,
@@ -253,7 +253,7 @@
 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 *serio_raw = serio_get_drvdata(serio);
 	struct serio_raw_list *list;
 	unsigned int head = serio_raw->head;
 
@@ -270,17 +270,14 @@
 	return IRQ_HANDLED;
 }
 
-static void serio_raw_connect(struct serio *serio, struct serio_driver *drv)
+static int 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;
+		return -ENOMEM;
 	}
 
 	down(&serio_raw_sem);
@@ -292,8 +289,10 @@
 	INIT_LIST_HEAD(&serio_raw->list);
 	init_waitqueue_head(&serio_raw->wait);
 
-	serio->private = serio_raw;
-	if (serio_open(serio, drv))
+	serio_set_drvdata(serio, serio_raw);
+
+	err = serio_open(serio, drv);
+	if (err)
 		goto out_free;
 
 	list_add_tail(&serio_raw->node, &serio_raw_list);
@@ -322,15 +321,16 @@
 	serio_close(serio);
 	list_del_init(&serio_raw->node);
 out_free:
-	serio->private = NULL;
+	serio_set_drvdata(serio, NULL);
 	kfree(serio_raw);
 out:
 	up(&serio_raw_sem);
+	return err;
 }
 
 static int serio_raw_reconnect(struct serio *serio)
 {
-	struct serio_raw *serio_raw = serio->private;
+	struct serio_raw *serio_raw = serio_get_drvdata(serio);
 	struct serio_driver *drv = serio->drv;
 
 	if (!drv || !serio_raw) {
@@ -351,10 +351,10 @@
 
 	down(&serio_raw_sem);
 
-	serio_raw = serio->private;
+	serio_raw = serio_get_drvdata(serio);
 
 	serio_close(serio);
-	serio->private = NULL;
+	serio_set_drvdata(serio, NULL);
 
 	serio_raw->serio = NULL;
 	if (!serio_raw_cleanup(serio_raw))
@@ -363,11 +363,24 @@
 	up(&serio_raw_sem);
 }
 
+static struct serio_device_id serio_raw_serio_ids[] = {
+	{
+		.type	= SERIO_8042,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids);
+
 static struct serio_driver serio_raw_drv = {
 	.driver		= {
 		.name	= "serio_raw",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= serio_raw_serio_ids,
 	.interrupt	= serio_raw_interrupt,
 	.connect	= serio_raw_connect,
 	.reconnect	= serio_raw_reconnect,
@@ -375,13 +388,13 @@
 	.manual_bind	= 1,
 };
 
-int __init serio_raw_init(void)
+static int __init serio_raw_init(void)
 {
 	serio_register_driver(&serio_raw_drv);
 	return 0;
 }
 
-void __exit serio_raw_exit(void)
+static void __exit serio_raw_exit(void)
 {
 	serio_unregister_driver(&serio_raw_drv);
 }
diff -Nru a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
--- a/drivers/input/serio/serport.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/serio/serport.c	2005-03-07 15:26:30 -08:00
@@ -49,7 +49,7 @@
 {
 	struct serport *serport = serio->port_data;
 
-	serport->serio->type = 0;
+	serport->serio->id.type = 0;
 	wake_up_interruptible(&serport->wait);
 }
 
@@ -84,7 +84,7 @@
 	memset(serio, 0, sizeof(struct serio));
 	strlcpy(serio->name, "Serial port", sizeof(serio->name));
 	snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
-	serio->type = SERIO_RS232;
+	serio->id.type = SERIO_RS232;
 	serio->write = serport_serio_write;
 	serio->close = serport_serio_close;
 	serio->port_data = serport;
@@ -148,7 +148,7 @@
 
 	serio_register_port(serport->serio);
 	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->id.type);
 	serio_unregister_port(serport->serio);
 
 	clear_bit(SERPORT_BUSY, &serport->flags);
@@ -163,9 +163,19 @@
 static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct serport *serport = (struct serport*) tty->disc_data;
+	struct serio *serio = serport->serio;
+	unsigned long type;
 
-	if (cmd == SPIOCSTYPE)
-		return get_user(serport->serio->type, (unsigned long __user *) arg);
+	if (cmd == SPIOCSTYPE) {
+		if (get_user(type, (unsigned long __user *) arg))
+			return -EFAULT;
+
+		serio->id.proto	= type & 0x000000ff;
+		serio->id.id	= (type & 0x0000ff00) >> 8;
+		serio->id.extra	= (type & 0x00ff0000) >> 16;
+
+		return 0;
+	}
 
 	return -EINVAL;
 }
diff -Nru a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
--- a/drivers/input/touchscreen/Kconfig	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/touchscreen/Kconfig	2005-03-07 15:26:30 -08:00
@@ -1,18 +1,19 @@
 #
 # Mouse driver configuration
 #
-config INPUT_TOUCHSCREEN
+menuconfig INPUT_TOUCHSCREEN
 	bool "Touchscreens"
-	depends on INPUT
 	help
 	  Say Y here, and a list of supported touchscreens will be displayed.
 	  This option doesn't affect the kernel.
 
 	  If unsure, say Y.
 
+if INPUT_TOUCHSCREEN
+
 config TOUCHSCREEN_BITSY
-	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen input driver"
-	depends on SA1100_BITSY && INPUT && INPUT_TOUCHSCREEN
+	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
+	depends on SA1100_BITSY
 	select SERIO
 	help
 	  Say Y here if you have the h3600 (Bitsy) touchscreen.
@@ -22,9 +23,21 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called h3600_ts_input.
 
+config TOUCHSCREEN_CORGI
+	tristate "Corgi touchscreen (for Sharp SL-C7xx)"
+	depends on PXA_SHARPSL
+	default y	
+	help
+	  Say Y here to enable the driver for the touchscreen on the 
+	  Sharp SL-C7xx series of PDAs.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ads7846_ts.
+
 config TOUCHSCREEN_GUNZE
 	tristate "Gunze AHL-51S touchscreen"
-	depends on INPUT && INPUT_TOUCHSCREEN
 	select SERIO
 	help
 	  Say Y here if you have the Gunze AHL-51 touchscreen connected to
@@ -35,3 +48,51 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called gunze.
 
+config TOUCHSCREEN_ELO
+	tristate "Elo serial touchscreens"
+	select SERIO
+	help
+	  Say Y here if you have an Elo serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gunze.
+
+config TOUCHSCREEN_MTOUCH
+	tristate "MicroTouch serial touchscreens"
+	select SERIO
+	help
+	  Say Y here if you have a MicroTouch (3M) serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mtouch.
+
+config TOUCHSCREEN_MK712
+	tristate "ICS MicroClock MK712 touchscreen"
+	help
+	  Say Y here if you have the ICS MicroClock MK712 touchscreen
+	  controller chip in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mk712.
+
+config TOUCHSCREEN_HP600
+	tristate "HP Jornada 680/690 touchscreen"
+	depends on SH_HP600 && SH_ADC
+	help
+	  Say Y here if you have a HP Jornada 680 or 690 and want to
+          support the built-in touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hp680_ts_input.
+
+endif
diff -Nru a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
--- a/drivers/input/touchscreen/Makefile	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/touchscreen/Makefile	2005-03-07 15:26:30 -08:00
@@ -5,4 +5,9 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_TOUCHSCREEN_BITSY)	+= h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CORGI)	+= corgi_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)	+= gunze.o
+obj-$(CONFIG_TOUCHSCREEN_ELO)	+= elo.o
+obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
+obj-$(CONFIG_TOUCHSCREEN_MK712)	+= mk712.o
+obj-$(CONFIG_TOUCHSCREEN_HP600)	+= hp680_ts_input.o
diff -Nru a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/touchscreen/corgi_ts.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,380 @@
+/*
+ *  Touchscreen driver for Sharp Corgi models (SL-C7xx)
+ *
+ *  Copyright (c) 2004-2005 Richard Purdie
+ *
+ *  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/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+
+#include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+
+#define PWR_MODE_ACTIVE		0
+#define PWR_MODE_SUSPEND	1
+
+#define X_AXIS_MAX		3830
+#define X_AXIS_MIN		150
+#define Y_AXIS_MAX		3830
+#define Y_AXIS_MIN		190
+#define PRESSURE_MIN		0
+#define PRESSURE_MAX		15000
+
+struct ts_event {
+	short pressure;
+	short x;
+	short y;
+};
+
+struct corgi_ts {
+	char phys[32];
+	struct input_dev input;
+	struct timer_list timer;
+	struct ts_event tc;
+	int pendown;
+	int power_mode;
+};
+
+#define STATUS_HSYNC		(GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC))
+
+#define SyncHS()	while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
+#define CCNT(a)		asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
+#define CCNT_ON()	{int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
+#define CCNT_OFF()	{int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
+
+#define WAIT_HS_400_VGA		7013U	// 17.615us
+#define WAIT_HS_400_QVGA	16622U	// 41.750us
+
+
+/* ADS7846 Touch Screen Controller bit definitions */
+#define ADSCTRL_PD0		(1u << 0)	/* PD0 */
+#define ADSCTRL_PD1		(1u << 1)	/* PD1 */
+#define ADSCTRL_DFR		(1u << 2)	/* SER/DFR */
+#define ADSCTRL_MOD		(1u << 3)	/* Mode */
+#define ADSCTRL_ADR_SH	4	/* Address setting */
+#define ADSCTRL_STS		(1u << 7)	/* Start Bit */
+
+/* External Functions */
+extern int w100fb_get_xres(void);
+extern int w100fb_get_blanking(void);
+extern int w100fb_get_fastsysclk(void);
+extern unsigned int get_clk_frequency_khz(int info);
+
+static unsigned long calc_waittime(void)
+{
+	int w100fb_xres = w100fb_get_xres();
+	unsigned int waittime = 0;
+
+	if (w100fb_xres == 480 || w100fb_xres == 640) {
+		waittime = WAIT_HS_400_VGA * get_clk_frequency_khz(0) / 398131U;
+
+		if (w100fb_get_fastsysclk() == 100)
+			waittime = waittime * 75 / 100;
+
+		if (w100fb_xres == 640)
+			waittime *= 3;
+
+		return waittime;
+	}
+
+	return WAIT_HS_400_QVGA * get_clk_frequency_khz(0) / 398131U;
+}
+
+static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
+{
+	int pos = 0;
+	unsigned long timer1 = 0, timer2;
+	int dosleep;
+
+	dosleep = !w100fb_get_blanking();
+
+	if (dosleep && doSend) {
+		CCNT_ON();
+		/* polling HSync */
+		SyncHS();
+		/* get CCNT */
+		CCNT(timer1);
+	}
+
+	if (doRecive)
+		pos = corgi_ssp_ads7846_get();
+
+	if (doSend) {
+		int cmd = ADSCTRL_PD0 | ADSCTRL_PD1 | (address << ADSCTRL_ADR_SH) | ADSCTRL_STS;
+		/* dummy command */
+		corgi_ssp_ads7846_put(cmd);
+		corgi_ssp_ads7846_get();
+
+		if (dosleep) {
+			/* Wait after HSync */
+			CCNT(timer2);
+			if (timer2-timer1 > wait_time) {
+				/* timeout */
+				SyncHS();
+				/* get OSCR */
+				CCNT(timer1);
+				/* Wait after HSync */
+				CCNT(timer2);
+			}
+			while (timer2 - timer1 < wait_time)
+				CCNT(timer2);
+		}
+		corgi_ssp_ads7846_put(cmd);
+		if (dosleep)
+			CCNT_OFF();
+	}
+	return pos;
+}
+
+static int read_xydata(struct corgi_ts *corgi_ts)
+{
+	unsigned int x, y, z1, z2;
+	unsigned long flags, wait_time;
+
+	/* critical section */
+	local_irq_save(flags);
+	corgi_ssp_ads7846_lock();
+	wait_time=calc_waittime();
+
+	/* Y-axis */
+	sync_receive_data_send_cmd(0, 1, 1u, wait_time);
+
+	/* Y-axis */
+	sync_receive_data_send_cmd(1, 1, 1u, wait_time);
+
+	/* X-axis */
+	y = sync_receive_data_send_cmd(1, 1, 5u, wait_time);
+
+	/* Z1 */
+	x = sync_receive_data_send_cmd(1, 1, 3u, wait_time);
+
+	/* Z2 */
+	z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time);
+	z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time);
+
+	/* Power-Down Enable */
+	corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	corgi_ssp_ads7846_get();
+
+	corgi_ssp_ads7846_unlock();
+	local_irq_restore(flags);
+
+	if (x== 0 || y == 0 || z1 == 0 || (x * (z2 - z1) / z1) >= 15000) {
+		corgi_ts->tc.pressure = 0;
+		return 0;
+	}
+
+	corgi_ts->tc.x = x;
+	corgi_ts->tc.y = y;
+	corgi_ts->tc.pressure = (x * (z2 - z1)) / z1;
+	return 1;
+}
+
+static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
+{
+	if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
+		return;
+
+	if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
+		return;
+
+	if (regs)
+		input_regs(&corgi_ts->input, regs);
+
+	input_report_abs(&corgi_ts->input, ABS_X, corgi_ts->tc.x);
+	input_report_abs(&corgi_ts->input, ABS_Y, corgi_ts->tc.y);
+	input_report_abs(&corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure);
+	input_report_key(&corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0));
+	input_sync(&corgi_ts->input);
+}
+
+static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
+{
+	if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) {
+		/* Disable Interrupt */
+		set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE);
+		if (read_xydata(corgi_ts)) {
+			corgi_ts->pendown = 1;
+			new_data(corgi_ts, regs);
+		}
+		mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
+	} else {
+		if (corgi_ts->pendown == 1 || corgi_ts->pendown == 2) {
+			mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
+			corgi_ts->pendown++;
+			return;
+		}
+
+		if (corgi_ts->pendown) {
+			corgi_ts->tc.pressure = 0;
+			new_data(corgi_ts, regs);
+		}
+
+		/* Enable Falling Edge */
+		set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+		corgi_ts->pendown = 0;
+	}
+}
+
+static void corgi_ts_timer(unsigned long data)
+{
+	struct corgi_ts *corgits_data = (struct corgi_ts *) data;
+	ts_interrupt_main(corgits_data, 1, NULL);
+}
+
+static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct corgi_ts *corgits_data = dev_id;
+	ts_interrupt_main(corgits_data, 0, regs);
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+static int corgits_suspend(struct device *dev, uint32_t state, uint32_t level)
+{
+	if (level == SUSPEND_POWER_DOWN) {
+		struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+
+		if (corgi_ts->pendown) {
+			del_timer_sync(&corgi_ts->timer);
+			corgi_ts->tc.pressure = 0;
+			new_data(corgi_ts, NULL);
+			corgi_ts->pendown = 0;
+		}
+		corgi_ts->power_mode = PWR_MODE_SUSPEND;
+
+		corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	}
+	return 0;
+}
+
+static int corgits_resume(struct device *dev, uint32_t level)
+{
+	if (level == RESUME_POWER_ON) {
+		struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+
+		corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+		/* Enable Falling Edge */
+		set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+		corgi_ts->power_mode = PWR_MODE_ACTIVE;
+	}
+	return 0;
+}
+#else
+#define corgits_suspend		NULL
+#define corgits_resume		NULL
+#endif
+
+static int __init corgits_probe(struct device *dev)
+{
+	struct corgi_ts *corgi_ts;
+
+	if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL)))
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, corgi_ts);
+
+	memset(corgi_ts, 0, sizeof(struct corgi_ts));
+
+	init_input_dev(&corgi_ts->input);
+	corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	input_set_abs_params(&corgi_ts->input, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
+	input_set_abs_params(&corgi_ts->input, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
+	input_set_abs_params(&corgi_ts->input, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
+
+	strcpy(corgi_ts->phys, "corgits/input0");
+
+	corgi_ts->input.private = corgi_ts;
+	corgi_ts->input.name = "Corgi Touchscreen";
+	corgi_ts->input.dev = dev;
+	corgi_ts->input.phys = corgi_ts->phys;
+	corgi_ts->input.id.bustype = BUS_HOST;
+	corgi_ts->input.id.vendor = 0x0001;
+	corgi_ts->input.id.product = 0x0002;
+	corgi_ts->input.id.version = 0x0100;
+
+	pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN);
+	pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
+
+	/* Initiaize ADS7846 Difference Reference mode */
+	corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+	corgi_ssp_ads7846_putget((3u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+	corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+	corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
+	mdelay(5);
+
+	init_timer(&corgi_ts->timer);
+	corgi_ts->timer.data = (unsigned long) corgi_ts;
+	corgi_ts->timer.function = corgi_ts_timer;
+
+	input_register_device(&corgi_ts->input);
+	corgi_ts->power_mode = PWR_MODE_ACTIVE;
+
+	if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
+		input_unregister_device(&corgi_ts->input);
+		kfree(corgi_ts);
+		return -EBUSY;
+	}
+
+	/* Enable Falling Edge */
+	set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+
+	printk(KERN_INFO "input: Corgi Touchscreen Registered\n");
+
+	return 0;
+}
+
+static int corgits_remove(struct device *dev)
+{
+	struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
+
+	free_irq(CORGI_IRQ_GPIO_TP_INT, NULL);
+	del_timer_sync(&corgi_ts->timer);
+	input_unregister_device(&corgi_ts->input);
+	kfree(corgi_ts);
+	return 0;
+}
+
+static struct device_driver corgits_driver = {
+	.name		= "corgi-ts",
+	.bus		= &platform_bus_type,
+	.probe		= corgits_probe,
+	.remove		= corgits_remove,
+	.suspend	= corgits_suspend,
+	.resume		= corgits_resume,
+};
+
+static int __devinit corgits_init(void)
+{
+	return driver_register(&corgits_driver);
+}
+
+static void __exit corgits_exit(void)
+{
+	driver_unregister(&corgits_driver);
+}
+
+module_init(corgits_init);
+module_exit(corgits_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Corgi TouchScreen Driver");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/touchscreen/elo.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,315 @@
+/*
+ * Elo serial touchscreen driver
+ *
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * This driver can handle serial Elo touchscreens using either the Elo standard
+ * 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo
+ * legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Elo serial touchscreen driver"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define	ELO_MAX_LENGTH	10
+
+static char *elo_name = "Elo Serial TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct elo {
+	struct input_dev dev;
+	struct serio *serio;
+	int id;
+	int idx;
+	unsigned char csum;
+	unsigned char data[ELO_MAX_LENGTH];
+	char phys[32];
+};
+
+static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs)
+{
+	struct input_dev *dev = &elo->dev;
+
+	elo->csum += elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+		case 0:
+			if (data != 'U') {
+				elo->idx = 0;
+				elo->csum = 0;
+			}
+			break;
+
+		case 1:
+			if (data != 'T') {
+				elo->idx = 0;
+				elo->csum = 0;
+			}
+			break;
+
+		case 9:
+			if (elo->csum) {
+				input_regs(dev, regs);
+				input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
+				input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
+				input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]);
+				input_report_key(dev, BTN_TOUCH, elo->data[2] & 3);
+				input_sync(dev);
+			}
+			elo->idx = 0;
+			elo->csum = 0;
+			break;
+	}
+}
+
+static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs)
+{
+	struct input_dev *dev = &elo->dev;
+
+	elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+		case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break;
+		case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break;
+		case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break;
+
+		case 3:
+			if (data & 0xc0) {
+				elo->idx = 0;
+				break;
+			}
+
+			input_regs(dev, regs);
+			input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
+			input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
+
+			if (elo->id == 2) {
+				input_report_key(dev, BTN_TOUCH, 1);
+				input_sync(dev);
+				elo->idx = 0;
+			}
+
+			break;
+
+		case 4:
+			if (data) {
+				input_sync(dev);
+				elo->idx = 0;
+			}
+			break;
+
+		case 5:
+			if ((data & 0xf0) == 0) {
+				input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
+				input_report_key(dev, BTN_TOUCH, elo->data[5]);
+			}
+			input_sync(dev);
+			elo->idx = 0;
+			break;
+	}
+}
+
+static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs)
+{
+	struct input_dev *dev = &elo->dev;
+
+	elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+		case 0:
+			if ((data & 0x7f) != 0x01)
+				elo->idx = 0;
+			break;
+		case 2:
+			input_regs(dev, regs);
+			input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
+			input_report_abs(dev, ABS_X, elo->data[1]);
+			input_report_abs(dev, ABS_Y, elo->data[2]);
+			input_sync(dev);
+			elo->idx = 0;
+			break;
+	}
+}
+
+static irqreturn_t elo_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct elo* elo = serio_get_drvdata(serio);
+
+	switch(elo->id) {
+		case 0:
+			elo_process_data_10(elo, data, regs);
+			break;
+
+		case 1:
+		case 2:
+			elo_process_data_6(elo, data, regs);
+			break;
+
+		case 3:
+			elo_process_data_3(elo, data, regs);
+			break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * elo_disconnect() is the opposite of elo_connect()
+ */
+
+static void elo_disconnect(struct serio *serio)
+{
+	struct elo* elo = serio_get_drvdata(serio);
+
+	input_unregister_device(&elo->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	kfree(elo);
+}
+
+/*
+ * elo_connect() is the routine that is called when someone adds a
+ * new serio device that supports Gunze protocol and registers it as
+ * an input device.
+ */
+
+static int elo_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct elo *elo;
+	int err;
+
+	if (!(elo = kmalloc(sizeof(struct elo), GFP_KERNEL)))
+		return -ENOMEM;
+
+	memset(elo, 0, sizeof(struct elo));
+
+	init_input_dev(&elo->dev);
+	elo->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	elo->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	elo->id = serio->id.id;
+
+	switch (elo->id) {
+
+		case 0: /* 10-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
+			break;
+		
+		case 1: /* 6-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
+
+		case 2: /* 4-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_X, 96, 4000, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
+			break;
+
+		case 3: /* 3-byte protocol */
+			input_set_abs_params(&elo->dev, ABS_X, 0, 255, 0, 0);
+			input_set_abs_params(&elo->dev, ABS_Y, 0, 255, 0, 0);
+			break;
+	}
+
+	elo->serio = serio;
+
+	sprintf(elo->phys, "%s/input0", serio->phys);
+
+	elo->dev.private = elo;
+	elo->dev.name = elo_name;
+	elo->dev.phys = elo->phys;
+	elo->dev.id.bustype = BUS_RS232;
+	elo->dev.id.vendor = SERIO_ELO;
+	elo->dev.id.product = elo->id;
+	elo->dev.id.version = 0x0100;
+
+	serio_set_drvdata(serio, elo);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
+		kfree(elo);
+		return err;
+	}
+
+	input_register_device(&elo->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", elo_name, serio->phys);
+
+	return 0;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id elo_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_ELO,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, elo_serio_ids);
+
+static struct serio_driver elo_drv = {
+	.driver		= {
+		.name	= "elo",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= elo_serio_ids,
+	.interrupt	= elo_interrupt,
+	.connect	= elo_connect,
+	.disconnect	= elo_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init elo_init(void)
+{
+	serio_register_driver(&elo_drv);
+	return 0;
+}
+
+static void __exit elo_exit(void)
+{
+	serio_unregister_driver(&elo_drv);
+}
+
+module_init(elo_init);
+module_exit(elo_exit);
diff -Nru a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
--- a/drivers/input/touchscreen/gunze.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/touchscreen/gunze.c	2005-03-07 15:26:30 -08:00
@@ -74,8 +74,8 @@
 	}
 
 	input_regs(dev, regs);
-	input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4);
-	input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3);
+	input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
+	input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
 	input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
 	input_sync(dev);
 }
@@ -83,7 +83,7 @@
 static irqreturn_t gunze_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
-	struct gunze* gunze = serio->private;
+	struct gunze* gunze = serio_get_drvdata(serio);
 
 	if (data == '\r') {
 		gunze_process_packet(gunze, regs);
@@ -101,38 +101,37 @@
 
 static void gunze_disconnect(struct serio *serio)
 {
-	struct gunze* gunze = serio->private;
+	struct gunze* gunze = serio_get_drvdata(serio);
+
 	input_unregister_device(&gunze->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(gunze);
 }
 
 /*
  * gunze_connect() is the routine that is called when someone adds a
- * new serio device. It looks whether it was registered as a Gunze touchscreen
- * and if yes, registers it as an input device.
+ * new serio device that supports Gunze protocol and registers it as
+ * an input device.
  */
 
-static void gunze_connect(struct serio *serio, struct serio_driver *drv)
+static int gunze_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct gunze *gunze;
-
-	if (serio->type != (SERIO_RS232 | SERIO_GUNZE))
-		return;
+	int err;
 
 	if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(gunze, 0, sizeof(struct gunze));
 
 	init_input_dev(&gunze->dev);
 	gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-	input_set_abs_params(&gunze->dev, ABS_X, 96, 4000, 0, 0);
-	input_set_abs_params(&gunze->dev, ABS_Y, 72, 3000, 0, 0);
+	input_set_abs_params(&gunze->dev, ABS_X, 24, 1000, 0, 0);
+	input_set_abs_params(&gunze->dev, ABS_Y, 24, 1000, 0, 0);
 
 	gunze->serio = serio;
-	serio->private = gunze;
 
 	sprintf(gunze->phys, "%s/input0", serio->phys);
 
@@ -144,25 +143,44 @@
 	gunze->dev.id.product = 0x0051;
 	gunze->dev.id.version = 0x0100;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, gunze);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
 		kfree(gunze);
-		return;
+		return err;
 	}
 
 	input_register_device(&gunze->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys);
+
+	return 0;
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id gunze_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_GUNZE,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, gunze_serio_ids);
+
 static struct serio_driver gunze_drv = {
 	.driver		= {
 		.name	= "gunze",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= gunze_serio_ids,
 	.interrupt	= gunze_interrupt,
 	.connect	= gunze_connect,
 	.disconnect	= gunze_disconnect,
@@ -172,13 +190,13 @@
  * The functions for inserting/removing us as a module.
  */
 
-int __init gunze_init(void)
+static int __init gunze_init(void)
 {
 	serio_register_driver(&gunze_drv);
 	return 0;
 }
 
-void __exit gunze_exit(void)
+static void __exit gunze_exit(void)
 {
 	serio_unregister_driver(&gunze_drv);
 }
diff -Nru a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
--- a/drivers/input/touchscreen/h3600_ts_input.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/touchscreen/h3600_ts_input.c	2005-03-07 15:26:30 -08:00
@@ -102,6 +102,7 @@
 	struct input_dev dev;
 	struct pm_dev *pm_dev;
 	struct serio *serio;
+	struct pm_dev *pm_dev;
 	unsigned char event;	/* event ID from packet */
 	unsigned char chksum;
 	unsigned char len;
@@ -331,7 +332,7 @@
 static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
                                      unsigned int flags, struct pt_regs *regs)
 {
-        struct h3600_dev *ts = serio->private;
+        struct h3600_dev *ts = serio_get_drvdata(serio);
 
 	/*
          * We have a new frame coming in.
@@ -373,18 +374,16 @@
 
 /*
  * h3600ts_connect() is the routine that is called when someone adds a
- * new serio device. It looks whether it was registered as a H3600 touchscreen
- * and if yes, registers it as an input device.
+ * new serio device that supports H3600 protocol and registers it as
+ * an input device.
  */
-static void h3600ts_connect(struct serio *serio, struct serio_driver *drv)
+static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct h3600_dev *ts;
-
-	if (serio->type != (SERIO_RS232 | SERIO_H3600))
-		return;
+	int err;
 
 	if (!(ts = kmalloc(sizeof(struct h3600_dev), GFP_KERNEL)))
-		return;
+		return -ENOMEM;
 
 	memset(ts, 0, sizeof(struct h3600_dev));
 
@@ -399,7 +398,7 @@
 			"h3600_action", &ts->dev)) {
 		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
 		kfree(ts);
-		return;
+		return -EBUSY;
 	}
 
         if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
@@ -408,7 +407,7 @@
 		free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
 		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
 		kfree(ts);
-		return;
+		return -EBUSY;
 	}
 
 	/* Now we have things going we setup our input device */
@@ -431,7 +430,6 @@
 	ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
 
 	ts->serio = serio;
-	serio->private = ts;
 
 	sprintf(ts->phys, "%s/input0", serio->phys);
 
@@ -444,11 +442,15 @@
 	ts->dev.id.product = 0x0666;  /* FIXME !!! We can ask the hardware */
 	ts->dev.id.version = 0x0100;
 
-	if (serio_open(serio, drv)) {
+	serio_set_drvdata(serio, ts);
+
+	err = serio_open(serio, drv);
+	if (err) {
         	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
         	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+		serio_set_drvdata(serio, NULL);
 		kfree(ts);
-		return;
+		return err;
 	}
 
 	//h3600_flite_control(1, 25);     /* default brightness */
@@ -460,6 +462,8 @@
 	input_register_device(&ts->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", h3600_name, serio->phys);
+
+	return 0;
 }
 
 /*
@@ -468,24 +472,38 @@
 
 static void h3600ts_disconnect(struct serio *serio)
 {
-	struct h3600_dev *ts = serio->private;
+	struct h3600_dev *ts = serio_get_drvdata(serio);
 
-        free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
-        free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
+	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
+	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
 	input_unregister_device(&ts->dev);
 	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
 	kfree(ts);
 }
 
 /*
- * The serio device structure.
+ * The serio driver structure.
  */
 
+static struct serio_device_id h3600ts_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_H3600,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids);
+
 static struct serio_driver h3600ts_drv = {
 	.driver		= {
 		.name	= "h3600ts",
 	},
 	.description	= DRIVER_DESC,
+	.id_table	= h3600ts_serio_ids,
 	.interrupt	= h3600ts_interrupt,
 	.connect	= h3600ts_connect,
 	.disconnect	= h3600ts_disconnect,
diff -Nru a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/touchscreen/hp680_ts_input.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,135 @@
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/adc.h>
+#include <asm/hp6xx/hp6xx.h>
+
+#define MODNAME "hp680_ts_input"
+
+#define HP680_TS_ABS_X_MIN	40
+#define HP680_TS_ABS_X_MAX	950
+#define HP680_TS_ABS_Y_MIN	80
+#define HP680_TS_ABS_Y_MAX	910
+
+#define	SCPCR	0xa4000116
+#define	PHDR	0xa400012e
+#define SCPDR	0xa4000136
+
+static void do_softint(void *data);
+
+static struct input_dev hp680_ts_dev;
+static DECLARE_WORK(work, do_softint, 0);
+static char *hp680_ts_name = "HP Jornada touchscreen";
+static char *hp680_ts_phys = "input0";
+
+static void do_softint(void *data)
+{
+	int absx = 0, absy = 0;
+	u8 scpdr;
+	int touched = 0;
+
+	if (ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN) {
+		scpdr = ctrl_inb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_ENABLE;
+		scpdr &= ~SCPDR_TS_SCAN_Y;
+		ctrl_outb(scpdr, SCPDR);
+		udelay(30);
+
+		absy = adc_single(ADC_CHANNEL_TS_Y);
+
+		scpdr = ctrl_inb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_Y;
+		scpdr &= ~SCPDR_TS_SCAN_X;
+		ctrl_outb(scpdr, SCPDR);
+		udelay(30);
+
+		absx = adc_single(ADC_CHANNEL_TS_X);
+
+		scpdr = ctrl_inb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_X;
+		scpdr &= ~SCPDR_TS_SCAN_ENABLE;
+		ctrl_outb(scpdr, SCPDR);
+		udelay(100);
+		touched = ctrl_inb(PHDR) & PHDR_TS_PEN_DOWN;
+	}
+
+	if (touched) {
+		input_report_key(&hp680_ts_dev, BTN_TOUCH, 1);
+		input_report_abs(&hp680_ts_dev, ABS_X, absx);
+		input_report_abs(&hp680_ts_dev, ABS_Y, absy);
+	} else {
+		input_report_key(&hp680_ts_dev, BTN_TOUCH, 0);
+	}
+
+	input_sync(&hp680_ts_dev);
+	enable_irq(HP680_TS_IRQ);
+}
+
+static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	disable_irq_nosync(irq);
+	schedule_delayed_work(&work, HZ / 20);
+
+	return IRQ_HANDLED;
+}
+
+static int __init hp680_ts_init(void)
+{
+	u8 scpdr;
+	u16 scpcr;
+
+	scpdr = ctrl_inb(SCPDR);
+	scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
+	scpdr &= ~SCPDR_TS_SCAN_ENABLE;
+	ctrl_outb(scpdr, SCPDR);
+
+	scpcr = ctrl_inw(SCPCR);
+	scpcr &= ~SCPCR_TS_MASK;
+	scpcr |= SCPCR_TS_ENABLE;
+	ctrl_outw(scpcr, SCPCR);
+
+	memset(&hp680_ts_dev, 0, sizeof(hp680_ts_dev));
+	init_input_dev(&hp680_ts_dev);
+
+	hp680_ts_dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+	hp680_ts_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+	hp680_ts_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	hp680_ts_dev.absmin[ABS_X] = HP680_TS_ABS_X_MIN;
+	hp680_ts_dev.absmin[ABS_Y] = HP680_TS_ABS_Y_MIN;
+	hp680_ts_dev.absmax[ABS_X] = HP680_TS_ABS_X_MAX;
+	hp680_ts_dev.absmax[ABS_Y] = HP680_TS_ABS_Y_MAX;
+
+	hp680_ts_dev.name = hp680_ts_name;
+	hp680_ts_dev.phys = hp680_ts_phys;
+	input_register_device(&hp680_ts_dev);
+
+	if (request_irq
+	    (HP680_TS_IRQ, hp680_ts_interrupt, SA_INTERRUPT, MODNAME, 0) < 0) {
+		printk(KERN_ERR "hp680_touchscreen.c : Can't allocate irq %d\n",
+		       HP680_TS_IRQ);
+		input_unregister_device(&hp680_ts_dev);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void __exit hp680_ts_exit(void)
+{
+	free_irq(HP680_TS_IRQ, 0);
+	cancel_delayed_work(&work);
+	flush_scheduled_work();
+	input_unregister_device(&hp680_ts_dev);
+}
+
+module_init(hp680_ts_init);
+module_exit(hp680_ts_exit);
+
+MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
+MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/touchscreen/mk712.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,222 @@
+/*
+ * ICS MK712 touchscreen controller driver
+ *
+ * Copyright (c) 1999-2002 Transmeta Corporation
+ * Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * This driver supports the ICS MicroClock MK712 TouchScreen controller,
+ * found in Gateway AOL Connected Touchpad computers.
+ *
+ * Documentation for ICS MK712 can be found at:
+ * 	http://www.icst.com/pdf/mk712.pdf
+ */
+
+/*
+ * 1999-12-18: original version, Daniel Quinlan
+ * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
+ *             to use queue_empty, Nathan Laredo
+ * 1999-12-20: improved random point rejection, Nathan Laredo
+ * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
+ *             queue code, added module options, other fixes, Daniel Quinlan
+ * 2002-03-15: Clean up for kernel merge <alan@redhat.com>
+ *             Fixed multi open race, fixed memory checks, fixed resource
+ *             allocation, fixed close/powerdown bug, switched to new init
+ * 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
+ * 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <asm/io.h>
+
+MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
+MODULE_LICENSE("GPL");
+
+static unsigned int mk712_io = 0x260;	/* Also 0x200, 0x208, 0x300 */
+module_param_named(io, mk712_io, uint, 0);
+MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
+
+static unsigned int mk712_irq = 10;	/* Also 12, 14, 15 */
+module_param_named(irq, mk712_irq, uint, 0);
+MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
+
+/* eight 8-bit registers */
+#define MK712_STATUS		0
+#define MK712_X			2
+#define MK712_Y			4
+#define MK712_CONTROL		6
+#define MK712_RATE		7
+
+/* status */
+#define	MK712_STATUS_TOUCH			0x10
+#define	MK712_CONVERSION_COMPLETE		0x80
+
+/* control */
+#define MK712_ENABLE_INT			0x01
+#define MK712_INT_ON_CONVERSION_COMPLETE	0x02
+#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS	0x04
+#define MK712_ENABLE_PERIODIC_CONVERSIONS	0x10
+#define MK712_READ_ONE_POINT			0x20
+#define MK712_POWERUP				0x40
+
+static int mk712_used = 0;
+static struct input_dev mk712_dev;
+static DEFINE_SPINLOCK(mk712_lock);
+
+static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned char status;
+	static int debounce = 1;
+	static unsigned short last_x;
+	static unsigned short last_y;
+
+	spin_lock(&mk712_lock);
+	input_regs(&mk712_dev, regs);
+
+	status = inb(mk712_io + MK712_STATUS);
+
+	if (~status & MK712_CONVERSION_COMPLETE) {
+		debounce = 1;
+		goto end;
+	}
+
+	if (~status & MK712_STATUS_TOUCH)
+	{
+		debounce = 1;
+		input_report_key(&mk712_dev, BTN_TOUCH, 0);
+		goto end;
+	}
+
+	if (debounce)
+	{
+		debounce = 0;
+		goto end;
+	}
+
+	input_report_key(&mk712_dev, BTN_TOUCH, 1);
+	input_report_abs(&mk712_dev, ABS_X, last_x);
+	input_report_abs(&mk712_dev, ABS_Y, last_y);
+
+end:
+
+	last_x = inw(mk712_io + MK712_X) & 0x0fff;
+	last_y = inw(mk712_io + MK712_Y) & 0x0fff;
+	input_sync(&mk712_dev);
+	spin_unlock(&mk712_lock);
+	return IRQ_HANDLED;
+}
+
+static int mk712_open(struct input_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+
+	if (!mk712_used++) {
+
+		outb(0, mk712_io + MK712_CONTROL); /* Reset */
+
+		outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+			MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+			MK712_ENABLE_PERIODIC_CONVERSIONS |
+			MK712_POWERUP, mk712_io + MK712_CONTROL);
+
+		outb(10, mk712_io + MK712_RATE); /* 187 points per second */
+	}
+
+	spin_unlock_irqrestore(&mk712_lock, flags);
+
+	return 0;
+}
+
+static void mk712_close(struct input_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+
+	if (!--mk712_used)
+		outb(0, mk712_io + MK712_CONTROL);
+
+	spin_unlock_irqrestore(&mk712_lock, flags);
+}
+
+static struct input_dev mk712_dev = {
+	.evbit   = { BIT(EV_KEY) | BIT(EV_ABS) },
+	.keybit  = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+	.absbit  = { BIT(ABS_X) | BIT(ABS_Y) },
+	.open    = mk712_open,
+	.close   = mk712_close,
+	.name    = "ICS MicroClock MK712 TouchScreen",
+	.phys    = "isa0260/input0",
+	.absmin  = { [ABS_X] = 0, [ABS_Y] = 0 },
+	.absmax  = { [ABS_X] = 0xfff, [ABS_Y] = 0xfff },
+	.absfuzz = { [ABS_X] = 88, [ABS_Y] = 88 },
+	.id      = {
+		.bustype = BUS_ISA,
+		.vendor  = 0x0005,
+		.product = 0x0001,
+		.version = 0x0100,
+	},
+};
+
+int __init mk712_init(void)
+{
+
+	if(!request_region(mk712_io, 8, "mk712"))
+	{
+		printk(KERN_WARNING "mk712: unable to get IO region\n");
+		return -ENODEV;
+	}
+
+	outb(0, mk712_io + MK712_CONTROL);
+
+	if ((inw(mk712_io + MK712_X) & 0xf000) ||	/* Sanity check */
+	    (inw(mk712_io + MK712_Y) & 0xf000) ||
+	    (inw(mk712_io + MK712_STATUS) & 0xf333)) {
+		printk(KERN_WARNING "mk712: device not present\n");
+		release_region(mk712_io, 8);
+		return -ENODEV;
+	}
+
+	if(request_irq(mk712_irq, mk712_interrupt, 0, "mk712", &mk712_dev))
+	{
+		printk(KERN_WARNING "mk712: unable to get IRQ\n");
+		release_region(mk712_io, 8);
+		return -EBUSY;
+	}
+
+	input_register_device(&mk712_dev);
+
+	printk(KERN_INFO "input: ICS MicroClock MK712 TouchScreen at %#x irq %d\n", mk712_io, mk712_irq);
+
+	return 0;
+}
+
+static void __exit mk712_exit(void)
+{
+	input_unregister_device(&mk712_dev);
+	free_irq(mk712_irq, &mk712_dev);
+	release_region(mk712_io, 8);
+}
+
+module_init(mk712_init);
+module_exit(mk712_exit);
diff -Nru a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/touchscreen/mtouch.c	2005-03-07 15:26:30 -08:00
@@ -0,0 +1,219 @@
+/*
+ * MicroTouch (3M) serial touchscreen driver
+ *
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * 2005/02/19 Dan Streetman <ddstreet@ieee.org>
+ *   Copied elo.c and edited for MicroTouch protocol
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"MicroTouch serial touchscreen driver"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define MTOUCH_FORMAT_TABLET_STATUS_BIT 0x80
+#define MTOUCH_FORMAT_TABLET_TOUCH_BIT 0x40
+#define MTOUCH_FORMAT_TABLET_LENGTH 5
+#define MTOUCH_RESPONSE_BEGIN_BYTE 0x01
+#define MTOUCH_RESPONSE_END_BYTE 0x0d
+
+/* todo: check specs for max length of all responses */
+#define MTOUCH_MAX_LENGTH 16
+
+#define MTOUCH_MIN_XC 0
+#define MTOUCH_MAX_XC 0x3fff
+#define MTOUCH_MIN_YC 0
+#define MTOUCH_MAX_YC 0x3fff
+
+#define MTOUCH_GET_XC(data) (((data[2])<<7) | data[1])
+#define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3])
+#define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0])
+
+static char *mtouch_name = "MicroTouch Serial TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct mtouch {
+	struct input_dev dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[MTOUCH_MAX_LENGTH];
+	char phys[32];
+};
+
+static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs)
+{
+	struct input_dev *dev = &mtouch->dev;
+
+	if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) {
+		input_regs(dev, regs);
+		input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data));
+		input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data));
+		input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data));
+		input_sync(dev);
+
+		mtouch->idx = 0;
+	}
+}
+
+static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs)
+{
+	if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) {
+		/* FIXME - process response */
+		mtouch->idx = 0;
+	} else if (MTOUCH_MAX_LENGTH == mtouch->idx) {
+		printk(KERN_ERR "mtouch.c: too many response bytes\n");
+		mtouch->idx = 0;
+	}
+}
+
+static irqreturn_t mtouch_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags, struct pt_regs *regs)
+{
+	struct mtouch* mtouch = serio_get_drvdata(serio);
+
+	mtouch->data[mtouch->idx] = data;
+
+	if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
+		mtouch_process_format_tablet(mtouch, regs);
+	else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
+		mtouch_process_response(mtouch, regs);
+	else
+		printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * mtouch_disconnect() is the opposite of mtouch_connect()
+ */
+
+static void mtouch_disconnect(struct serio *serio)
+{
+	struct mtouch* mtouch = serio_get_drvdata(serio);
+
+	input_unregister_device(&mtouch->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	kfree(mtouch);
+}
+
+/*
+ * mtouch_connect() is the routine that is called when someone adds a
+ * new serio device that supports MicroTouch (Format Tablet) protocol and registers it as
+ * an input device.
+ */
+
+static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct mtouch *mtouch;
+	int err;
+
+	if (!(mtouch = kmalloc(sizeof(*mtouch), GFP_KERNEL)))
+		return -ENOMEM;
+
+	memset(mtouch, 0, sizeof(*mtouch));
+
+	init_input_dev(&mtouch->dev);
+	mtouch->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	mtouch->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	input_set_abs_params(&mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
+	input_set_abs_params(&mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0);
+
+	mtouch->serio = serio;
+
+	sprintf(mtouch->phys, "%s/input0", serio->phys);
+
+	mtouch->dev.private = mtouch;
+	mtouch->dev.name = mtouch_name;
+	mtouch->dev.phys = mtouch->phys;
+	mtouch->dev.id.bustype = BUS_RS232;
+	mtouch->dev.id.vendor = SERIO_MICROTOUCH;
+	mtouch->dev.id.product = 0;
+	mtouch->dev.id.version = 0x0100;
+
+	serio_set_drvdata(serio, mtouch);
+
+	err = serio_open(serio, drv);
+	if (err) {
+		serio_set_drvdata(serio, NULL);
+		kfree(mtouch);
+		return err;
+	}
+
+	input_register_device(&mtouch->dev);
+
+	printk(KERN_INFO "input: %s on %s\n", mtouch->dev.name, serio->phys);
+
+	return 0;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id mtouch_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MICROTOUCH,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, mtouch_serio_ids);
+
+static struct serio_driver mtouch_drv = {
+	.driver		= {
+		.name	= "mtouch",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= mtouch_serio_ids,
+	.interrupt	= mtouch_interrupt,
+	.connect	= mtouch_connect,
+	.disconnect	= mtouch_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init mtouch_init(void)
+{
+	serio_register_driver(&mtouch_drv);
+	return 0;
+}
+
+static void __exit mtouch_exit(void)
+{
+	serio_unregister_driver(&mtouch_drv);
+}
+
+module_init(mtouch_init);
+module_exit(mtouch_exit);
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/input/tsdev.c	2005-03-07 15:26:30 -08:00
@@ -232,11 +232,9 @@
 static unsigned int tsdev_poll(struct file *file, poll_table * wait)
 {
 	struct tsdev_list *list = file->private_data;
-
 	poll_wait(file, &list->tsdev->wait, wait);
-	if (list->head != list->tail)
-		return POLLIN | POLLRDNORM;
-	return 0;
+	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int tsdev_ioctl(struct inode *inode, struct file *file,
@@ -265,7 +263,7 @@
 	return retval;
 }
 
-struct file_operations tsdev_fops = {
+static struct file_operations tsdev_fops = {
 	.owner =	THIS_MODULE,
 	.open =		tsdev_open,
 	.release =	tsdev_release,
@@ -426,6 +424,7 @@
 static void tsdev_disconnect(struct input_handle *handle)
 {
 	struct tsdev *tsdev = handle->private;
+	struct tsdev_list *list;
 
 	class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
 	devfs_remove("input/ts%d", tsdev->minor);
@@ -435,6 +434,8 @@
 	if (tsdev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&tsdev->wait);
+		list_for_each_entry(list, &tsdev->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
 	} else
 		tsdev_free(tsdev);
 }
diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
--- a/drivers/serial/sunsu.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/serial/sunsu.c	2005-03-07 15:26:30 -08:00
@@ -1314,12 +1314,13 @@
 
 		serio->port_data = up;
 
-		serio->type = SERIO_RS232;
+		serio->id.type = SERIO_RS232;
 		if (up->su_type == SU_PORT_KBD) {
-			serio->type |= SERIO_SUNKBD;
+			serio->id.proto = SERIO_SUNKBD;
 			strlcpy(serio->name, "sukbd", sizeof(serio->name));
 		} else {
-			serio->type |= (SERIO_SUN | (1 << 16));
+			serio->id.proto = SERIO_SUN;
+			serio->id.extra = 1;
 			strlcpy(serio->name, "sums", sizeof(serio->name));
 		}
 		strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"),
diff -Nru a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
--- a/drivers/serial/sunzilog.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/serial/sunzilog.c	2005-03-07 15:26:30 -08:00
@@ -1562,12 +1562,13 @@
 
 		serio->port_data = up;
 
-		serio->type = SERIO_RS232;
+		serio->id.type = SERIO_RS232;
 		if (channel == KEYBOARD_LINE) {
-			serio->type |= SERIO_SUNKBD;
+			serio->id.proto = SERIO_SUNKBD;
 			strlcpy(serio->name, "zskbd", sizeof(serio->name));
 		} else {
-			serio->type |= (SERIO_SUN | (1 << 16));
+			serio->id.proto = SERIO_SUN;
+			serio->id.extra = 1;
 			strlcpy(serio->name, "zsms", sizeof(serio->name));
 		}
 		strlcpy(serio->phys,
diff -Nru a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
--- a/drivers/usb/input/ati_remote.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/ati_remote.c	2005-03-07 15:26:30 -08:00
@@ -174,7 +174,6 @@
 	dma_addr_t outbuf_dma;
 
 	int open;                   /* open counter */
-	int present;                /* device plugged in? */
 	
 	unsigned char old_data[2];  /* Detect duplicate events */
 	unsigned long old_jiffies;
@@ -252,8 +251,8 @@
 	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
 	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
 	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
-	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_PROG1, 1},      /* TV */
-	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_PROG2, 1},      /* DVD */
+	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
+	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
 	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
 	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
 	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
@@ -263,14 +262,14 @@
 	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
 	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
 	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
-	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_ENTER, 1},      /* "OK" */
+	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
 	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
 	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
 	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
-	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
-	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
+	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
+	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
 	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
-	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAYCD, 1},     /* ( >) */
+	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
 	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
 	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
 	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */ 
@@ -356,19 +355,8 @@
 {
 	struct ati_remote *ati_remote = inputdev->private;
 	
-	if (ati_remote == NULL) {
-		err("ati_remote: %s: object is NULL!\n", __FUNCTION__);
-		return;
-	}
-	
-	if (ati_remote->open <= 0)
-		dev_dbg(&ati_remote->interface->dev, "%s: Not open.\n", __FUNCTION__);
-	else
-		--ati_remote->open;
-	
-	/* If still present, disconnect will call delete. */
-	if (!ati_remote->present && !ati_remote->open)
-		ati_remote_delete(ati_remote);
+	if (!--ati_remote->open)
+		usb_kill_urb(ati_remote->irq_urb);
 }
 
 /*
@@ -812,7 +800,6 @@
 		 ati_remote->name, path);
 
 	usb_set_intfdata(interface, ati_remote);
-	ati_remote->present = 1;	
 	
 error:
 	if (buf)
@@ -840,12 +827,7 @@
 		return;
 	}
 	
-	/* Mark device as unplugged */
-	ati_remote->present = 0;
-
-	/* If device is still open, ati_remote_close will call delete. */
-	if (!ati_remote->open)
-		ati_remote_delete(ati_remote);
+	ati_remote_delete(ati_remote);
 
 	up(&disconnect_sem);
 }
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/hid-core.c	2005-03-07 15:26:30 -08:00
@@ -37,13 +37,20 @@
  * Version Information
  */
 
-#define DRIVER_VERSION "v2.0"
+#define DRIVER_VERSION "v2.01"
 #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
 #define DRIVER_DESC "USB HID core driver"
 #define DRIVER_LICENSE "GPL"
 
 static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
 				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
+/*
+ * Module parameters.
+ */
+
+static unsigned int hid_mousepoll_interval;
+module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
+MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
 /*
  * Register a new report for a device.
@@ -121,18 +128,17 @@
 
 	if (parser->device->maxcollection == parser->device->collection_size) {
 		collection = kmalloc(sizeof(struct hid_collection) *
-				     parser->device->collection_size * 2,
-				     GFP_KERNEL);
+				parser->device->collection_size * 2, GFP_KERNEL);
 		if (collection == NULL) {
 			dbg("failed to reallocate collection array");
 			return -1;
 		}
 		memcpy(collection, parser->device->collection,
-		       sizeof(struct hid_collection) *
-		       parser->device->collection_size);
+			sizeof(struct hid_collection) *
+			parser->device->collection_size);
 		memset(collection + parser->device->collection_size, 0,
-		       sizeof(struct hid_collection) *
-		       parser->device->collection_size);
+			sizeof(struct hid_collection) *
+			parser->device->collection_size);
 		kfree(parser->device->collection);
 		parser->device->collection = collection;
 		parser->device->collection_size *= 2;
@@ -141,12 +147,12 @@
 	parser->collection_stack[parser->collection_stack_ptr++] =
 		parser->device->maxcollection;
 
-	collection = parser->device->collection + 
+	collection = parser->device->collection +
 		parser->device->maxcollection++;
 	collection->type = type;
 	collection->usage = usage;
 	collection->level = parser->collection_stack_ptr - 1;
-	
+
 	if (type == HID_COLLECTION_APPLICATION)
 		parser->device->maxapplication++;
 
@@ -193,7 +199,7 @@
 	}
 	parser->local.usage[parser->local.usage_index] = usage;
 	parser->local.collection_index[parser->local.usage_index] =
-		parser->collection_stack_ptr ? 
+		parser->collection_stack_ptr ?
 		parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
 	parser->local.usage_index++;
 	return 0;
@@ -220,13 +226,15 @@
 		dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
 		return -1;
 	}
-	
-	if (!(usages = max_t(int, parser->local.usage_index, parser->global.report_count)))
-		return 0; /* Ignore padding fields */
 
 	offset = report->size;
 	report->size += parser->global.report_size * parser->global.report_count;
 
+	if (!parser->local.usage_index) /* Ignore padding fields */
+		return 0; 
+
+	usages = max_t(int, parser->local.usage_index, parser->global.report_count);
+
 	if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
 		return 0;
 
@@ -581,13 +589,13 @@
 		item->size = *start++;
 		item->tag  = *start++;
 
-		if ((end - start) < item->size) 
+		if ((end - start) < item->size)
 			return NULL;
 
 		item->data.longdata = start;
 		start += item->size;
 		return start;
-	} 
+	}
 
 	item->format = HID_ITEM_FORMAT_SHORT;
 	item->size = b & 3;
@@ -604,7 +612,7 @@
 			return start;
 
 		case 2:
-			if ((end - start) < 2) 
+			if ((end - start) < 2)
 				return NULL;
 			item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
 			start = (__u8 *)((__le16 *)start + 1);
@@ -646,13 +654,13 @@
 		return NULL;
 	memset(device, 0, sizeof(struct hid_device));
 
-	if (!(device->collection =kmalloc(sizeof(struct hid_collection) *
+	if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
 				   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
 		kfree(device);
 		return NULL;
 	}
 	memset(device->collection, 0, sizeof(struct hid_collection) *
-	       HID_DEFAULT_NUM_COLLECTIONS);
+		HID_DEFAULT_NUM_COLLECTIONS);
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
 	for (i = 0; i < HID_REPORT_TYPES; i++)
@@ -806,8 +814,7 @@
 	__s32 max = field->logical_maximum;
 	__s32 *value;
 
-	value = kmalloc(sizeof(__s32)*count, GFP_ATOMIC);
-	if (!value)
+	if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
 		return;
 
 	for (n = 0; n < count; n++) {
@@ -824,14 +831,6 @@
 	for (n = 0; n < count; n++) {
 
 		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-
-			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				if (!value[n])
-					continue;
-			} else {
-				if (value[n] == field->value[n])
-					continue;
-			}	
 			hid_process_event(hid, field, &field->usage[n], value[n], regs);
 			continue;
 		}
@@ -893,10 +892,8 @@
 
 	size = ((report->size - 1) >> 3) + 1;
 
-	if (len < size) {
+	if (len < size)
 		dbg("report %d is too short, (%d < %d)", report->id, len, size);
-		return -1;
-	}
 
 	if (hid->claimed & HID_CLAIMED_HIDDEV)
 		hiddev_report_event(hid, report);
@@ -934,7 +931,7 @@
 		default:		/* error */
 			warn("input irq status %d received", urb->status);
 	}
-	
+
 	status = usb_submit_urb(urb, SLAB_ATOMIC);
 	if (status)
 		err("can't resubmit intr, %s-%s/input%d, status %d",
@@ -956,7 +953,7 @@
 	for (n = 0; n < count; n++) {
 		if (field->logical_minimum < 0)	/* signed values */
 			implement(data, offset + n * size, size, s32ton(field->value[n], size));
-		 else				/* unsigned values */
+		else				/* unsigned values */
 			implement(data, offset + n * size, size, field->value[n]);
 	}
 }
@@ -1003,63 +1000,21 @@
 	return 0;
 }
 
-int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
-{
-	struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT;
-	struct list_head *list = report_enum->report_list.next;
-	int i, j;
-
-	while (list != &report_enum->report_list) {
-		struct hid_report *report = (struct hid_report *) list;
-		list = list->next;
-		for (i = 0; i < report->maxfield; i++) {
-			*field = report->field[i];
-			for (j = 0; j < (*field)->maxusage; j++)
-				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
-					return j;
-		}
-	}
-	return -1;
-}
-
 /*
- * Find a report with a specified HID usage.
+ * Find a report field with a specified HID usage.
  */
 
-int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type)
-{
-	struct hid_report_enum *report_enum = hid->report_enum + type;
-	struct list_head *list = report_enum->report_list.next;
-	int i, j;
-
-	while (list != &report_enum->report_list) {
-		*report = (struct hid_report *) list;
-		list = list->next;
-		for (i = 0; i < (*report)->maxfield; i++) {
-			struct hid_field *field = (*report)->field[i];
-			for (j = 0; j < field->maxusage; j++)
-				if (field->logical == wanted_usage)
-					return j;
-		}
-	}
-	return -1;
-}
-
-#if 0
-static int hid_find_field_in_report(struct hid_report *report, __u32 wanted_usage, struct hid_field **field)
+struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
 {
-	int i, j;
-
-	for (i = 0; i < report->maxfield; i++) {
-		*field = report->field[i];
-		for (j = 0; j < (*field)->maxusage; j++)
-			if ((*field)->usage[j].hid == wanted_usage)
-				return j;
-	}
+	struct hid_report *report;
+	int i;
 
-	return -1;
+	list_for_each_entry(report, &hid->report_enum[type].report_list, list)
+		for (i = 0; i < report->maxfield; i++)
+			if (report->field[i]->logical == wanted_usage)
+				return report->field[i];
+	return NULL;
 }
-#endif
 
 static int hid_submit_out(struct hid_device *hid)
 {
@@ -1118,8 +1073,8 @@
 	hid->cr->wLength = cpu_to_le16(len);
 
 	dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
-	    hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
-	    hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength);
+		hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+		hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength);
 
 	if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) {
 		err("usb_submit_urb(ctrl) failed");
@@ -1186,7 +1141,7 @@
 
 	switch (urb->status) {
 		case 0:			/* success */
-			if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) 
+			if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
 				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs);
 		case -ESHUTDOWN:	/* unplug */
 		case -EILSEQ:		/* unplug timectrl on uhci */
@@ -1332,47 +1287,19 @@
 
 void hid_init_reports(struct hid_device *hid)
 {
-	struct hid_report_enum *report_enum;
 	struct hid_report *report;
-	struct list_head *list;
-	int err, ret, size;
+	int err, ret;
 
-	/*
-	 * The Set_Idle request is supposed to affect only the
-	 * "Interrupt In" pipe. Unfortunately, buggy devices such as
-	 * the BTC keyboard (ID 046e:5303) the request also affects
-	 * Get_Report requests on the control pipe.  In the worst
-	 * case, if the device was put on idle for an indefinite
-	 * amount of time (as we do below) and there are no input
-	 * events to report, the Get_Report requests will just hang
-	 * until we get a USB timeout.  To avoid this, we temporarily
-	 * establish a minimal idle time of 1ms.  This shouldn't hurt
-	 * bugfree devices and will cause a worst-case extra delay of
-	 * 1ms for buggy ones.
-	 */
-	usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
-			HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (1 << 8),
-			hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
-
-	report_enum = hid->report_enum + HID_INPUT_REPORT;
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
-		size = ((report->size - 1) >> 3) + 1 + report_enum->numbered;
+	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) {
+		int size = ((report->size - 1) >> 3) + 1 + hid->report_enum[HID_INPUT_REPORT].numbered;
 		if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE;
 		if (size > hid->urbin->transfer_buffer_length)
 			hid->urbin->transfer_buffer_length = size;
 		hid_submit_report(hid, report, USB_DIR_IN);
-		list = list->next;
 	}
 
-	report_enum = hid->report_enum + HID_FEATURE_REPORT;
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
+	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
 		hid_submit_report(hid, report, USB_DIR_IN);
-		list = list->next;
-	}
 
 	err = 0;
 	ret = hid_wait_io(hid);
@@ -1388,15 +1315,9 @@
 	if (err)
 		warn("timeout initializing reports\n");
 
-	report_enum = hid->report_enum + HID_INPUT_REPORT;
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
-		usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
-			HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id,
-			hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
-		list = list->next;
-	}
+	usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
+		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+		hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
 }
 
 #define USB_VENDOR_ID_WACOM		0x056a
@@ -1405,11 +1326,11 @@
 #define USB_DEVICE_ID_WACOM_INTUOS	0x0020
 #define USB_DEVICE_ID_WACOM_PL		0x0030
 #define USB_DEVICE_ID_WACOM_INTUOS2	0x0040
-#define USB_DEVICE_ID_WACOM_VOLITO      0x0060
-#define USB_DEVICE_ID_WACOM_PTU         0x0003
+#define USB_DEVICE_ID_WACOM_VOLITO	0x0060
+#define USB_DEVICE_ID_WACOM_PTU		0x0003
 
-#define USB_VENDOR_ID_KBGEAR            0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO  0x1001
+#define USB_VENDOR_ID_KBGEAR		0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
 
 #define USB_VENDOR_ID_AIPTEK		0x08ca
 #define USB_DEVICE_ID_AIPTEK_01		0x0001
@@ -1424,35 +1345,35 @@
 #define USB_DEVICE_ID_POWERMATE		0x0410
 #define USB_DEVICE_ID_SOUNDKNOB		0x04AA
 
-#define USB_VENDOR_ID_ATEN             0x0557  
-#define USB_DEVICE_ID_ATEN_UC100KM     0x2004
-#define USB_DEVICE_ID_ATEN_CS124U      0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
-
-#define USB_VENDOR_ID_TOPMAX           0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
-
-#define USB_VENDOR_ID_HAPP             0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING     0x0010
-#define USB_DEVICE_ID_UGCI_FLYING      0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
-
-#define USB_VENDOR_ID_MGE              0x0463
-#define USB_DEVICE_ID_MGE_UPS          0xffff
-#define USB_DEVICE_ID_MGE_UPS1         0x0001
+#define USB_VENDOR_ID_ATEN		0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM	0x2004
+#define USB_DEVICE_ID_ATEN_CS124U	0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC	0x2208
+
+#define USB_VENDOR_ID_TOPMAX		0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD	0x0103
+
+#define USB_VENDOR_ID_HAPP		0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING	0x0010
+#define USB_DEVICE_ID_UGCI_FLYING	0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING	0x0030
+
+#define USB_VENDOR_ID_MGE		0x0463
+#define USB_DEVICE_ID_MGE_UPS		0xffff
+#define USB_DEVICE_ID_MGE_UPS1		0x0001
 
 #define USB_VENDOR_ID_ONTRAK		0x0a07
 #define USB_DEVICE_ID_ONTRAK_ADU100	0x0064
 
-#define USB_VENDOR_ID_TANGTOP          0x0d3d
-#define USB_DEVICE_ID_TANGTOP_USBPS2   0x0001
+#define USB_VENDOR_ID_TANGTOP		0x0d3d
+#define USB_DEVICE_ID_TANGTOP_USBPS2	0x0001
 
 #define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5	0x0100
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
-#define USB_VENDOR_ID_A4TECH		0x09DA
+#define USB_VENDOR_ID_A4TECH		0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
 
 #define USB_VENDOR_ID_CYPRESS		0x04b4
@@ -1494,6 +1415,21 @@
 #define USB_VENDOR_ID_DELORME		0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
 
+#define USB_VENDOR_ID_MCC		0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS	0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS	0x007a
+
+#define USB_VENDOR_ID_CHICONY		0x04f2
+#define USB_DEVICE_ID_CHICONY_USBHUB_KB	0x0100
+
+#define USB_VENDOR_ID_BTC		0x046e
+#define USB_DEVICE_ID_BTC_KEYBOARD	0x5303
+
+
+/*
+ * Alphabetically sorted blacklist by quirk type.
+ */
+
 static struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
@@ -1512,9 +1448,9 @@
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
-	
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, 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_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
@@ -1522,6 +1458,9 @@
 	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, 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_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
@@ -1557,18 +1496,18 @@
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-	
 
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
+	{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
 
 	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
 
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
@@ -1579,13 +1518,6 @@
 	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
 
-	{ 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_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
-
 	{ 0, 0 }
 };
 
@@ -1695,6 +1627,10 @@
 		if (dev->speed == USB_SPEED_HIGH)
 			interval = 1 << (interval - 1);
 
+		/* Change the polling interval of mice. */
+		if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
+			interval = hid_mousepoll_interval;
+		
 		if (endpoint->bEndpointAddress & USB_DIR_IN) {
 			if (hid->urbin)
 				continue;
@@ -1724,7 +1660,7 @@
 	}
 
 	init_waitqueue_head(&hid->wait);
-	
+
 	spin_lock_init(&hid->outlock);
 	spin_lock_init(&hid->ctrllock);
 
@@ -1746,9 +1682,9 @@
 	} else if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) {
 			snprintf(hid->name, 128, "%s", buf);
 	} else
-		snprintf(hid->name, 128, "%04x:%04x", 
-			 le16_to_cpu(dev->descriptor.idVendor),
-			 le16_to_cpu(dev->descriptor.idProduct));
+		snprintf(hid->name, 128, "%04x:%04x",
+			le16_to_cpu(dev->descriptor.idVendor),
+			le16_to_cpu(dev->descriptor.idProduct));
 
 	usb_make_path(dev, buf, 64);
 	snprintf(hid->phys, 64, "%s/input%d", buf,
@@ -1810,7 +1746,7 @@
 	hid_free_device(hid);
 }
 
-static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id)
+static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct hid_device *hid;
 	char path[64];
@@ -1892,7 +1828,7 @@
 
 static struct usb_device_id hid_usb_ids [] = {
 	{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
-	    .bInterfaceClass = USB_INTERFACE_CLASS_HID },
+		.bInterfaceClass = USB_INTERFACE_CLASS_HID },
 	{ }						/* Terminating entry */
 };
 
diff -Nru a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
--- a/drivers/usb/input/hid-debug.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/hid-debug.h	2005-03-07 15:26:30 -08:00
@@ -473,7 +473,6 @@
 
 
 static char *events[EV_MAX + 1] = {
-	[0 ... EV_MAX] = NULL,
 	[EV_SYN] = "Sync",			[EV_KEY] = "Key",
 	[EV_REL] = "Relative",			[EV_ABS] = "Absolute",
 	[EV_MSC] = "Misc",			[EV_LED] = "LED",
@@ -483,11 +482,9 @@
 };
 
 static char *syncs[2] = {
-	[0 ... 1] = NULL,
 	[SYN_REPORT] = "Report",		[SYN_CONFIG] = "Config",
 };
 static char *keys[KEY_MAX + 1] = {
-	[0 ... KEY_MAX] = NULL,
 	[KEY_RESERVED] = "Reserved",		[KEY_ESC] = "Esc",
 	[KEY_1] = "1",				[KEY_2] = "2",
 	[KEY_3] = "3",				[KEY_4] = "4",
@@ -665,7 +662,6 @@
 };
 
 static char *relatives[REL_MAX + 1] = {
-	[0 ... REL_MAX] = NULL,
 	[REL_X] = "X",			[REL_Y] = "Y",
 	[REL_Z] = "Z",			[REL_HWHEEL] = "HWheel",
 	[REL_DIAL] = "Dial",		[REL_WHEEL] = "Wheel", 
@@ -673,7 +669,6 @@
 };
 
 static char *absolutes[ABS_MAX + 1] = {
-	[0 ... ABS_MAX] = NULL,
 	[ABS_X] = "X",			[ABS_Y] = "Y",
 	[ABS_Z] = "Z",			[ABS_RX] = "Rx",
 	[ABS_RY] = "Ry",		[ABS_RZ] = "Rz",
@@ -690,13 +685,11 @@
 };
 
 static char *misc[MSC_MAX + 1] = {
-	[ 0 ... MSC_MAX] = NULL,
 	[MSC_SERIAL] = "Serial",	[MSC_PULSELED] = "Pulseled",
 	[MSC_GESTURE] = "Gesture",	[MSC_RAW] = "RawData"
 };
 
 static char *leds[LED_MAX + 1] = {
-	[0 ... LED_MAX] = NULL,
 	[LED_NUML] = "NumLock",		[LED_CAPSL] = "CapsLock", 
 	[LED_SCROLLL] = "ScrollLock",	[LED_COMPOSE] = "Compose",
 	[LED_KANA] = "Kana",		[LED_SLEEP] = "Sleep", 
@@ -705,25 +698,22 @@
 };
 
 static char *repeats[REP_MAX + 1] = {
-	[0 ... REP_MAX] = NULL,
 	[REP_DELAY] = "Delay",		[REP_PERIOD] = "Period"
 };
 
 static char *sounds[SND_MAX + 1] = {
-	[0 ... SND_MAX] = NULL,
 	[SND_CLICK] = "Click",		[SND_BELL] = "Bell",
 	[SND_TONE] = "Tone"
 };
 
 static char **names[EV_MAX + 1] = {
-	[0 ... EV_MAX] = NULL,
 	[EV_SYN] = syncs,			[EV_KEY] = keys,
 	[EV_REL] = relatives,			[EV_ABS] = absolutes,
 	[EV_MSC] = misc,			[EV_LED] = leds,
 	[EV_SND] = sounds,			[EV_REP] = repeats,
 };
 
-static void resolv_event(__u8 type, __u16 code) {
+static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) {
 
 	printk("%s.%s", events[type] ? events[type] : "?",
 		names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
diff -Nru a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
--- a/drivers/usb/input/hid-ff.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/hid-ff.c	2005-03-07 15:26:30 -08:00
@@ -55,6 +55,7 @@
 	{0x46d, 0xc211, hid_lgff_init}, // Logitech Cordless rumble pad
 	{0x46d, 0xc283, hid_lgff_init}, // Logitech Wingman Force 3d
 	{0x46d, 0xc295, hid_lgff_init},	// Logitech MOMO force wheel
+	{0x46d, 0xc219, hid_lgff_init}, // Logitech Cordless rumble pad 2
 #endif
 #ifdef CONFIG_HID_PID
 	{0x45e, 0x001b, hid_pid_init},
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/hid-input.c	2005-03-07 15:26:30 -08:00
@@ -404,7 +404,6 @@
 		return;
 
 	input_regs(input, regs);
-	input_event(input, EV_MSC, MSC_SCAN, usage->hid);
 
 	if (!usage->type)
 		return;
@@ -483,10 +482,26 @@
 	}
 }
 
+static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+{
+	struct hid_report *report;
+	int i, j;
+
+	list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
+		for (i = 0; i < report->maxfield; i++) {
+			*field = report->field[i];
+			for (j = 0; j < (*field)->maxusage; j++)
+				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
+					return j;
+		}
+	}
+	return -1;
+}
+
 static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	struct hid_device *hid = dev->private;
-	struct hid_field *field = NULL;
+	struct hid_field *field;
 	int offset;
 
 	if (type == EV_FF)
@@ -495,7 +510,7 @@
 	if (type != EV_LED)
 		return -1;
 
-	if ((offset = hid_find_field(hid, type, code, &field)) == -1) {
+	if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
 		warn("event field not found");
 		return -1;
 	}
@@ -527,9 +542,7 @@
 int hidinput_connect(struct hid_device *hid)
 {
 	struct usb_device *dev = hid->dev;
-	struct hid_report_enum *report_enum;
 	struct hid_report *report;
-	struct list_head *list;
 	struct hid_input *hidinput = NULL;
 	int i, j, k;
 
@@ -544,16 +557,11 @@
 	if (i == hid->maxcollection)
 		return -1;
 
-	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
-		report_enum = hid->report_enum + k;
-		list = report_enum->report_list.next;
-		while (list != &report_enum->report_list) {
-			report = (struct hid_report *) list;
+	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+		list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
 
-			if (!report->maxfield) {
-				list = list->next;
+			if (!report->maxfield)
 				continue;
-			}
 
 			if (!hidinput) {
 				hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL);
@@ -578,9 +586,6 @@
 				hidinput->input.id.product = le16_to_cpu(dev->descriptor.idProduct);
 				hidinput->input.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
 				hidinput->input.dev = &hid->intf->dev;
-
-				set_bit(EV_MSC, hidinput->input.evbit);
-				set_bit(MSC_SCAN, hidinput->input.mscbit);
 			}
 
 			for (i = 0; i < report->maxfield; i++)
@@ -598,10 +603,7 @@
 				input_register_device(&hidinput->input);
 				hidinput = NULL;
 			}
-
-			list = list->next;
 		}
-	}
 
 	/* This only gets called when we are a single-input (most of the
 	 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
@@ -619,7 +621,7 @@
 	struct list_head *lh, *next;
 	struct hid_input *hidinput;
 
-	list_for_each_safe (lh, next, &hid->inputs) {
+	list_for_each_safe(lh, next, &hid->inputs) {
 		hidinput = list_entry(lh, struct hid_input, list);
 		input_unregister_device(&hidinput->input);
 		list_del(&hidinput->list);
diff -Nru a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
--- a/drivers/usb/input/hid-lgff.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/hid-lgff.c	2005-03-07 15:26:30 -08:00
@@ -126,6 +126,7 @@
 
 static struct device_type devices[] = {
 	{0x046d, 0xc211, ff_rumble},
+	{0x046d, 0xc219, ff_rumble},
 	{0x046d, 0xc283, ff_joystick},
 	{0x0000, 0x0000, ff_joystick}
 };
diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/hid.h	2005-03-07 15:26:30 -08:00
@@ -484,11 +484,10 @@
 
 int hid_open(struct hid_device *);
 void hid_close(struct hid_device *);
-int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **);
 int hid_set_field(struct hid_field *, unsigned, __s32);
 void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
 void hid_init_reports(struct hid_device *hid);
-int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type);
+struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type);
 int hid_wait_io(struct hid_device* hid);
 
 
diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/hiddev.c	2005-03-07 15:26:30 -08:00
@@ -124,7 +124,6 @@
 	int i, j;
 	struct hid_report *report;
 	struct hid_report_enum *report_enum;
-	struct list_head *list;
 	struct hid_field *field;
 
 	if (uref->report_type < HID_REPORT_TYPE_MIN ||
@@ -132,9 +131,8 @@
 
 	report_enum = hid->report_enum +
 		(uref->report_type - HID_REPORT_TYPE_MIN);
-	list = report_enum->report_list.next;
-	while (list != &report_enum->report_list) {
-		report = (struct hid_report *) list;
+
+	list_for_each_entry(report, &report_enum->report_list, list)
 		for (i = 0; i < report->maxfield; i++) {
 			field = report->field[i];
 			for (j = 0; j < field->maxusage; j++) {
@@ -146,8 +144,6 @@
 				}
 			}
 		}
-		list = list->next;
-	}
 
 	return NULL;
 }
@@ -634,9 +630,8 @@
 				goto inval;
 
 			else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
-				 (uref_multi->num_values >= HID_MAX_MULTI_USAGES ||
-				  uref->usage_index + uref_multi->num_values >= field->report_count ||
-				  uref->usage_index + uref_multi->num_values < uref->usage_index))
+				 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+				  uref->usage_index + uref_multi->num_values >= field->report_count))
 				goto inval;
 			}
 
diff -Nru a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
--- a/drivers/usb/input/mtouchusb.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/mtouchusb.c	2005-03-07 15:26:30 -08:00
@@ -34,6 +34,9 @@
  *    Eliminated vendor/product module params
  *    Performed multiple successfull tests with an EXII-5010UC
  *
+ *  1.5 02/27/2005 ddstreet@ieee.org
+ *    Added module parameter to select raw or hw-calibrated coordinate reporting
+ *
  *****************************************************************************/
 
 #include <linux/config.h>
@@ -52,11 +55,13 @@
 #include <linux/usb.h>
 
 #define MTOUCHUSB_MIN_XC                0x0
-#define MTOUCHUSB_MAX_XC                0x4000
+#define MTOUCHUSB_MAX_RAW_XC            0x4000
+#define MTOUCHUSB_MAX_CALIB_XC          0xffff
 #define MTOUCHUSB_XC_FUZZ               0x0
 #define MTOUCHUSB_XC_FLAT               0x0
 #define MTOUCHUSB_MIN_YC                0x0
-#define MTOUCHUSB_MAX_YC                0x4000
+#define MTOUCHUSB_MAX_RAW_YC            0x4000
+#define MTOUCHUSB_MAX_CALIB_YC          0xffff
 #define MTOUCHUSB_YC_FUZZ               0x0
 #define MTOUCHUSB_YC_FLAT               0x0
 
@@ -65,15 +70,28 @@
 #define MTOUCHUSB_REPORT_DATA_SIZE      11
 #define MTOUCHUSB_REQ_CTRLLR_ID         10
 
-#define MTOUCHUSB_GET_XC(data)          (data[8]<<8 | data[7])
-#define MTOUCHUSB_GET_YC(data)          (data[10]<<8 | data[9])
+#define MTOUCHUSB_GET_RAW_XC(data)      (data[8]<<8 | data[7])
+#define MTOUCHUSB_GET_CALIB_XC(data)    (data[4]<<8 | data[3])
+#define MTOUCHUSB_GET_RAW_YC(data)      (data[10]<<8 | data[9])
+#define MTOUCHUSB_GET_CALIB_YC(data)    (data[6]<<8 | data[5])
+#define MTOUCHUSB_GET_XC(data)          (raw_coordinates ? \
+                                         MTOUCHUSB_GET_RAW_XC(data) : \
+                                         MTOUCHUSB_GET_CALIB_XC(data))
+#define MTOUCHUSB_GET_YC(data)          (raw_coordinates ? \
+                                         MTOUCHUSB_GET_RAW_YC(data) : \
+                                         MTOUCHUSB_GET_CALIB_YC(data))
 #define MTOUCHUSB_GET_TOUCHED(data)     ((data[2] & 0x40) ? 1:0)
 
-#define DRIVER_VERSION "v1.4"
+#define DRIVER_VERSION "v1.5"
 #define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
 #define DRIVER_DESC "3M USB Touchscreen Driver"
 #define DRIVER_LICENSE "GPL"
 
+static int raw_coordinates = 1;
+
+module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
+
 struct mtouch_usb {
         unsigned char *data;
         dma_addr_t data_dma;
@@ -123,7 +141,8 @@
         input_report_abs(&mtouch->input, ABS_X,
                          MTOUCHUSB_GET_XC(mtouch->data));
         input_report_abs(&mtouch->input, ABS_Y,
-                         MTOUCHUSB_GET_YC(mtouch->data));
+			 (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
+                         - MTOUCHUSB_GET_YC(mtouch->data));
         input_sync(&mtouch->input);
 
 exit:
@@ -234,11 +253,13 @@
 
         /* Used to Scale Compensated Data and Flip Y */
         mtouch->input.absmin[ABS_X] =  MTOUCHUSB_MIN_XC;
-        mtouch->input.absmax[ABS_X] =  MTOUCHUSB_MAX_XC;
+        mtouch->input.absmax[ABS_X] =  raw_coordinates ? \
+                                       MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
         mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
         mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
         mtouch->input.absmin[ABS_Y] =  MTOUCHUSB_MIN_YC;
-        mtouch->input.absmax[ABS_Y] =  MTOUCHUSB_MAX_YC;
+        mtouch->input.absmax[ABS_Y] =  raw_coordinates ? \
+                                       MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
         mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
         mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
 
diff -Nru a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
--- a/drivers/usb/input/pid.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/pid.c	2005-03-07 15:26:30 -08:00
@@ -48,106 +48,96 @@
 /* Called when a transfer is completed */
 static void hid_pid_ctrl_out(struct urb *u, struct pt_regs *regs)
 {
-    dev_dbg(&u->dev->dev, "hid_pid_ctrl_out - Transfer Completed\n");
+	dev_dbg(&u->dev->dev, "hid_pid_ctrl_out - Transfer Completed\n");
 }
 
-static void hid_pid_exit(struct hid_device* hid)
+static void hid_pid_exit(struct hid_device *hid)
 {
-    struct hid_ff_pid *private = hid->ff_private;
-    
-    if (private->urbffout) {
-	usb_kill_urb(private->urbffout);
-	usb_free_urb(private->urbffout);
-    }
+	struct hid_ff_pid *private = hid->ff_private;
+
+	if (private->urbffout) {
+		usb_kill_urb(private->urbffout);
+		usb_free_urb(private->urbffout);
+	}
 }
 
-static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "requested periodic force upload\n");
-    return 0;
+static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "requested periodic force upload\n");
+	return 0;
 }
 
-static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "requested constant force upload\n");
-    return 0;
+static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "requested constant force upload\n");
+	return 0;
 }
 
-static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "requested Condition force upload\n");
-    return 0;
+static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "requested Condition force upload\n");
+	return 0;
 }
 
-static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) {
-    dev_info(&pid->hid->dev->dev, "request ramp force upload\n");
-    return 0;
+static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
+{
+	dev_info(&pid->hid->dev->dev, "request ramp force upload\n");
+	return 0;
 }
 
 static int hid_pid_event(struct hid_device *hid, struct input_dev *input,
-			  unsigned int type, unsigned int code, int value)
+			 unsigned int type, unsigned int code, int value)
 {
-    dev_dbg(&hid->dev->dev, "PID event received: type=%d,code=%d,value=%d.\n", type, code, value);
+	dev_dbg(&hid->dev->dev, "PID event received: type=%d,code=%d,value=%d.\n", type, code, value);
 
-    if (type != EV_FF)
-	return -1;
+	if (type != EV_FF)
+		return -1;
 
-    
-
-    return 0;
+	return 0;
 }
 
 /* Lock must be held by caller */
-static void hid_pid_ctrl_playback(struct hid_device *hid,
-				   struct hid_pid_effect *effect, int play)
+static void hid_pid_ctrl_playback(struct hid_device *hid, struct hid_pid_effect *effect, int play)
 {
-	if (play) {
+	if (play)
 		set_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
-
-	} else {
+	else
 		clear_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
-	}
 }
 
-
 static int hid_pid_erase(struct input_dev *dev, int id)
 {
 	struct hid_device *hid = dev->private;
-	struct hid_field* field;
-	struct hid_report* report;
 	struct hid_ff_pid *pid = hid->ff_private;
+	struct hid_field *field;
 	unsigned long flags;
-	unsigned wanted_report = HID_UP_PID | FF_PID_USAGE_BLOCK_FREE;  /*  PID Block Free Report */
 	int ret;
 
 	if (!CHECK_OWNERSHIP(id, pid))
 		return -EACCES;
 
 	/* Find report */
-	ret =  hid_find_report_by_usage(hid, wanted_report, &report, HID_OUTPUT_REPORT);
-	if(!ret) {
+	field = hid_find_field_by_usage(hid, HID_UP_PID | FF_PID_USAGE_BLOCK_FREE,
+					HID_OUTPUT_REPORT);
+	if (!field) {
 		dev_err(&hid->dev->dev, "couldn't find report\n");
-		return ret;
-	}
-
-	/* Find field */
-	field = (struct hid_field *) kmalloc(sizeof(struct hid_field), GFP_KERNEL);
-	if(!field) {
-		dev_err(&hid->dev->dev, "couldn't allocate field\n");
-		return -ENOMEM;
+		return -EIO;
 	}
 
-	ret = hid_set_field(field, ret, pid->effects[id].device_id);
-	if(!ret) {
+	ret = hid_set_field(field, 0, pid->effects[id].device_id);
+	if (ret) {
 		dev_err(&hid->dev->dev, "couldn't set field\n");
 		return ret;
 	}
 
-	hid_submit_report(hid, report, USB_DIR_OUT);
+	hid_submit_report(hid, field->report, USB_DIR_OUT);
 
 	spin_lock_irqsave(&pid->lock, flags);
 	hid_pid_ctrl_playback(hid, pid->effects + id, 0);
 	pid->effects[id].flags = 0;
 	spin_unlock_irqrestore(&pid->lock, flags);
 
-	return ret;
+	return 0;
 }
 
 /* Erase all effects this process owns */
@@ -158,31 +148,32 @@
 	int i;
 
 	/*NOTE: no need to lock here. The only times EFFECT_USED is
-	  modified is when effects are uploaded or when an effect is
-	  erased. But a process cannot close its dev/input/eventX fd
-	  and perform ioctls on the same fd all at the same time */
-	for (i=0; i<dev->ff_effects_max; ++i)
-		if ( current->pid == pid->effects[i].owner
-		     && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags))
+	   modified is when effects are uploaded or when an effect is
+	   erased. But a process cannot close its dev/input/eventX fd
+	   and perform ioctls on the same fd all at the same time */
+	/*FIXME: multiple threads, anyone? */
+	for (i = 0; i < dev->ff_effects_max; ++i)
+		if (current->pid == pid->effects[i].owner
+		    && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags))
 			if (hid_pid_erase(dev, i))
 				dev_warn(&hid->dev->dev, "erase effect %d failed", i);
 
 	return 0;
 }
 
-
 static int hid_pid_upload_effect(struct input_dev *dev,
-				  struct ff_effect *effect)
+				 struct ff_effect *effect)
 {
-	struct hid_ff_pid* pid_private  = (struct hid_ff_pid*)(dev->private);
+	struct hid_ff_pid *pid_private = (struct hid_ff_pid *)(dev->private);
 	int ret;
 	int is_update;
-	unsigned long flags = 0;
+	unsigned long flags;
 
-        dev_dbg(&pid_private->hid->dev->dev, "upload effect called: effect_type=%x\n",effect->type);
+	dev_dbg(&pid_private->hid->dev->dev, "upload effect called: effect_type=%x\n", effect->type);
 	/* Check this effect type is supported by this device */
 	if (!test_bit(effect->type, dev->ffbit)) {
-		dev_dbg(&pid_private->hid->dev->dev, "invalid kind of effect requested.\n");
+		dev_dbg(&pid_private->hid->dev->dev,
+			"invalid kind of effect requested.\n");
 		return -EINVAL;
 	}
 
@@ -190,31 +181,30 @@
 	 * If we want to create a new effect, get a free id
 	 */
 	if (effect->id == -1) {
-		int id=0;
+		int id = 0;
 
 		// Spinlock so we don`t get a race condition when choosing IDs
 		spin_lock_irqsave(&pid_private->lock, flags);
 
-		while(id < FF_EFFECTS_MAX)
-			if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags)) 
-			    break;
+		while (id < FF_EFFECTS_MAX)
+			if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags))
+				break;
 
-		if ( id == FF_EFFECTS_MAX) {
-			spin_unlock_irqrestore(&pid_private->lock,flags);
+		if (id == FF_EFFECTS_MAX) {
+			spin_unlock_irqrestore(&pid_private->lock, flags);
 // TEMP - We need to get ff_effects_max correctly first:  || id >= dev->ff_effects_max) {
 			dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n");
 			return -ENOMEM;
 		}
 
 		effect->id = id;
-		dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d\n.",id);
+		dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d\n.", id);
 		pid_private->effects[id].owner = current->pid;
-		pid_private->effects[id].flags = (1<<FF_PID_FLAGS_USED);
-		spin_unlock_irqrestore(&pid_private->lock,flags);
+		pid_private->effects[id].flags = (1 << FF_PID_FLAGS_USED);
+		spin_unlock_irqrestore(&pid_private->lock, flags);
 
 		is_update = FF_PID_FALSE;
-	}
-	else {
+	} else {
 		/* We want to update an effect */
 		if (!CHECK_OWNERSHIP(effect->id, pid_private))
 			return -EACCES;
@@ -224,9 +214,8 @@
 			return -EINVAL;
 
 		/* Check the effect is not already being updated */
-		if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags)) {
+		if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags))
 			return -EAGAIN;
-		}
 
 		is_update = FF_PID_TRUE;
 	}
@@ -235,28 +224,30 @@
 	 * Upload the effect
 	 */
 	switch (effect->type) {
-		case FF_PERIODIC:
-			ret = pid_upload_periodic(pid_private, effect, is_update);
-			break;
-
-		case FF_CONSTANT:
-			ret = pid_upload_constant(pid_private, effect, is_update);
-			break;
-
-		case FF_SPRING:
-		case FF_FRICTION:
-		case FF_DAMPER:
-		case FF_INERTIA:
-			ret = pid_upload_condition(pid_private, effect, is_update);
-			break;
-
-		case FF_RAMP:
-			ret = pid_upload_ramp(pid_private, effect, is_update);
-			break;
-
-		default:
-			dev_dbg(&pid_private->hid->dev->dev, "invalid type of effect requested - %x.\n", effect->type);
-			return -EINVAL;
+	case FF_PERIODIC:
+		ret = pid_upload_periodic(pid_private, effect, is_update);
+		break;
+
+	case FF_CONSTANT:
+		ret = pid_upload_constant(pid_private, effect, is_update);
+		break;
+
+	case FF_SPRING:
+	case FF_FRICTION:
+	case FF_DAMPER:
+	case FF_INERTIA:
+		ret = pid_upload_condition(pid_private, effect, is_update);
+		break;
+
+	case FF_RAMP:
+		ret = pid_upload_ramp(pid_private, effect, is_update);
+		break;
+
+	default:
+		dev_dbg(&pid_private->hid->dev->dev,
+			"invalid type of effect requested - %x.\n",
+			effect->type);
+		return -EINVAL;
 	}
 	/* If a packet was sent, forbid new updates until we are notified
 	 * that the packet was updated
@@ -269,37 +260,36 @@
 
 int hid_pid_init(struct hid_device *hid)
 {
-    struct hid_ff_pid *private;
-    struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
+	struct hid_ff_pid *private;
+	struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
 
-    private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
-    if (!private) return -1;
-    
-    memset(private,0,sizeof(struct hid_ff_pid));
-
-    hid->ff_private = private; /* 'cause memset can move the block away */
-
-    private->hid = hid;
-    
-    hid->ff_exit = hid_pid_exit;
-    hid->ff_event = hid_pid_event;
-    
-    /* Open output URB */
-    if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
-	kfree(private);
-	return -1;
-    }
-
-    usb_fill_control_urb(private->urbffout, hid->dev,0,(void *) &private->ffcr,private->ctrl_buffer,8,hid_pid_ctrl_out,hid);
-    hidinput->input.upload_effect = hid_pid_upload_effect;
-    hidinput->input.flush = hid_pid_flush;
-    hidinput->input.ff_effects_max = 8;  // A random default
-    set_bit(EV_FF, hidinput->input.evbit);
-    set_bit(EV_FF_STATUS, hidinput->input.evbit);
-
-    spin_lock_init(&private->lock);
-
-    printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio@lsi.usp.br>.\n");
-    
-    return 0;    
+	private = hid->ff_private = kcalloc(1, sizeof(struct hid_ff_pid), GFP_KERNEL);
+	if (!private)
+		return -ENOMEM;
+
+	private->hid = hid;
+
+	hid->ff_exit = hid_pid_exit;
+	hid->ff_event = hid_pid_event;
+
+	/* Open output URB */
+	if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
+		kfree(private);
+		return -1;
+	}
+
+	usb_fill_control_urb(private->urbffout, hid->dev, 0,
+			     (void *)&private->ffcr, private->ctrl_buffer, 8,
+			     hid_pid_ctrl_out, hid);
+	hidinput->input.upload_effect = hid_pid_upload_effect;
+	hidinput->input.flush = hid_pid_flush;
+	hidinput->input.ff_effects_max = 8;	// A random default
+	set_bit(EV_FF, hidinput->input.evbit);
+	set_bit(EV_FF_STATUS, hidinput->input.evbit);
+
+	spin_lock_init(&private->lock);
+
+	printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio@lsi.usp.br>.\n");
+
+	return 0;
 }
diff -Nru a/drivers/usb/input/pid.h b/drivers/usb/input/pid.h
--- a/drivers/usb/input/pid.h	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/pid.h	2005-03-07 15:26:30 -08:00
@@ -25,31 +25,31 @@
 
 #define FF_EFFECTS_MAX 64
 
-#define FF_PID_FLAGS_USED	1  /* If the effect exists */
-#define FF_PID_FLAGS_UPDATING	2  /* If the effect is being updated */
-#define FF_PID_FLAGS_PLAYING	3  /* If the effect is currently being played */
+#define FF_PID_FLAGS_USED	1	/* If the effect exists */
+#define FF_PID_FLAGS_UPDATING	2	/* If the effect is being updated */
+#define FF_PID_FLAGS_PLAYING	3	/* If the effect is currently being played */
 
 #define FF_PID_FALSE	0
 #define FF_PID_TRUE	1
 
 struct hid_pid_effect {
-    unsigned long flags;
-    pid_t owner;
-    unsigned int device_id;  // The device-assigned ID
-    struct ff_effect effect;
+	unsigned long flags;
+	pid_t owner;
+	unsigned int device_id;	/* The device-assigned ID */
+	struct ff_effect effect;
 };
 
 struct hid_ff_pid {
-    struct hid_device *hid;
-    unsigned long int gain;
+	struct hid_device *hid;
+	unsigned long gain;
 
-    struct urb *urbffout;
-    struct usb_ctrlrequest ffcr;
-    spinlock_t lock;
+	struct urb *urbffout;
+	struct usb_ctrlrequest ffcr;
+	spinlock_t lock;
 
-    char ctrl_buffer[8];
+	unsigned char ctrl_buffer[8];
 
-    struct hid_pid_effect effects[FF_EFFECTS_MAX];
+	struct hid_pid_effect effects[FF_EFFECTS_MAX];
 };
 
 /*
diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
--- a/drivers/usb/input/powermate.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/powermate.c	2005-03-07 15:26:30 -08:00
@@ -395,6 +395,7 @@
 	pm->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
 	pm->input.event = powermate_input_event;
 	pm->input.dev = &intf->dev;
+	pm->input.phys = pm->phys;
 
 	input_register_device(&pm->input);
 
diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
--- a/drivers/usb/input/wacom.c	2005-03-07 15:26:30 -08:00
+++ b/drivers/usb/input/wacom.c	2005-03-07 15:26:30 -08:00
@@ -72,7 +72,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.30"
+#define DRIVER_VERSION "v1.40"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -141,8 +141,10 @@
 		goto exit;
 	}
 
-	if (data[0] != 2)
+	if (data[0] != 2) {
 		dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+		goto exit;
+	}
 
 	prox = data[1] & 0x40;
 
@@ -233,6 +235,7 @@
 	if (data[0] != 2)
 	{
 		printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+		goto exit;
 	}
 
 	input_regs(dev, regs);
@@ -246,9 +249,9 @@
 		input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
 		input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
 	}
-	input_report_abs(dev, ABS_X, data[3] << 8 | data[2]);
-	input_report_abs(dev, ABS_Y, data[5] << 8 | data[4]);
-	input_report_abs(dev, ABS_PRESSURE, (data[6]|data[7] << 8));
+	input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2]));
+	input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4]));
+	input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
 	input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
 	input_report_key(dev, BTN_STYLUS2, data[1] & 0x10);
 
@@ -283,10 +286,15 @@
 		goto exit;
 	}
 
+	if (data[0] != 2) {
+		printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+		goto exit;
+	}
+
 	input_regs(dev, regs);
 	input_report_key(dev, BTN_TOOL_PEN, 1);
-	input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((__le16 *) &data[1])));
-	input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((__le16 *) &data[3])));
+	input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1]));
+	input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3]));
 	input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
 	input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
 	input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
@@ -322,12 +330,10 @@
 		goto exit;
 	}
 
-	/* check if we can handle the data */
-	if (data[0] == 99)
-		goto exit;
-
-	if (data[0] != 2)
+	if (data[0] != 2) {
 		dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+		goto exit;
+	}
 
 	x = le16_to_cpu(*(__le16 *) &data[2]);
 	y = le16_to_cpu(*(__le16 *) &data[4]);
@@ -381,107 +387,171 @@
 		     __FUNCTION__, retval);
 }
 
-static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
+static int wacom_intuos_inout(struct urb *urb)
 {
 	struct wacom *wacom = urb->context;
 	unsigned char *data = wacom->data;
 	struct input_dev *dev = &wacom->dev;
-	unsigned int t;
 	int idx;
-	int retval;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	if (data[0] != 2)
-		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
-
-	input_regs(dev, regs);
 
 	/* tool number */
 	idx = data[1] & 0x01;
 
-	if ((data[1] & 0xfc) == 0xc0) {						/* Enter report */
-
-		wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +		/* serial number of the tool */
+	/* Enter report */
+	if ((data[1] & 0xfc) == 0xc0)
+	{
+		/* serial number of the tool */
+		wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +
 			((__u32)data[4] << 20) + ((__u32)data[5] << 12) +
 			((__u32)data[6] << 4) + (data[7] >> 4);
 
 		switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
-			case 0x812:
-			case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL;		break;	/* Inking pen */
-			case 0x822:
+			case 0x812: /* Inking pen */
+			case 0x801: /* Intuos3 Inking pen */
+			case 0x012:
+				wacom->tool[idx] = BTN_TOOL_PENCIL;
+				break;
+			case 0x822: /* Pen */
 			case 0x842:
 			case 0x852:
-			case 0x022: wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Pen */
-			case 0x832:
-			case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH;		break;	/* Stroke pen */
-			case 0x007:
+			case 0x823: /* Intuos3 Grip Pen */
+			case 0x813: /* Intuos3 Classic Pen */
+			case 0x885: /* Intuos3 Marker Pen */
+			case 0x022:
+				wacom->tool[idx] = BTN_TOOL_PEN;
+				break;
+			case 0x832: /* Stroke pen */
+			case 0x032:
+				wacom->tool[idx] = BTN_TOOL_BRUSH;
+				break;
+			case 0x007: /* Mouse 4D and 2D */
 		        case 0x09c:
-			case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE;		break;	/* Mouse 4D and 2D */
-			case 0x096: wacom->tool[idx] = BTN_TOOL_LENS;		break;	/* Lens cursor */
-			case 0x82a:
+			case 0x094:
+			case 0x017: /* Intuos3 2D Mouse */
+				wacom->tool[idx] = BTN_TOOL_MOUSE;
+				break;
+			case 0x096: /* Lens cursor */
+			case 0x097: /* Intuos3 Lens cursor */
+				wacom->tool[idx] = BTN_TOOL_LENS;
+				break;
+			case 0x82a: /* Eraser */
 			case 0x85a:
 		        case 0x91a:
 			case 0xd1a:
-			case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER;		break;	/* Eraser */
+			case 0x0fa:
+			case 0x82b: /* Intuos3 Grip Pen Eraser */
+			case 0x81b: /* Intuos3 Classic Pen Eraser */
+			case 0x91b: /* Intuos3 Airbrush Eraser */
+				wacom->tool[idx] = BTN_TOOL_RUBBER;
+				break;
 			case 0xd12:
 			case 0x912:
-			case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH;	break;	/* Airbrush */
-			default:    wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Unknown tool */
+			case 0x112:
+			case 0x913: /* Intuos3 Airbrush */
+				wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+				break;	/* Airbrush */
+			default: /* Unknown tool */
+				wacom->tool[idx] = BTN_TOOL_PEN;
 		}
-
 		input_report_key(dev, wacom->tool[idx], 1);
 		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
 		input_sync(dev);
-		goto exit;
+		return 1;
 	}
 
-	if ((data[1] & 0xfe) == 0x80) {						/* Exit report */
+	/* Exit report */
+	if ((data[1] & 0xfe) == 0x80) {
 		input_report_key(dev, wacom->tool[idx], 0);
 		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
 		input_sync(dev);
-		goto exit;
+		return 1;
 	}
 
-	input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
-	input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
-	input_report_abs(dev, ABS_DISTANCE, data[9]);
+	return 0;
+}
 
-	if ((data[1] & 0xb8) == 0xa0) {						/* general pen packet */
-		input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
-		input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+static void wacom_intuos_general(struct urb *urb)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	unsigned int t;
+
+	/* general pen packet */
+	if ((data[1] & 0xb8) == 0xa0)
+	{
+		t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+		input_report_abs(dev, ABS_PRESSURE, t);
+		input_report_abs(dev, ABS_TILT_X,
+				((data[7] << 1) & 0x7e) | (data[8] >> 7));
 		input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
 		input_report_key(dev, BTN_STYLUS, data[1] & 2);
 		input_report_key(dev, BTN_STYLUS2, data[1] & 4);
 		input_report_key(dev, BTN_TOUCH, t > 10);
 	}
 
-	if ((data[1] & 0xbc) == 0xb4) {						/* airbrush second packet */
-		input_report_abs(dev, ABS_WHEEL, ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
-		input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+	/* airbrush second packet */
+	if ((data[1] & 0xbc) == 0xb4)
+	{
+		input_report_abs(dev, ABS_WHEEL,
+				((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+		input_report_abs(dev, ABS_TILT_X,
+				((data[7] << 1) & 0x7e) | (data[8] >> 7));
 		input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
 	}
+	return;
+}
+
+static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	unsigned int t;
+	int idx;
+	int retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	if (data[0] != 2 && data[0] != 5 && data[0] != 6) {
+		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+		goto exit;
+	}
+
+	input_regs(dev, regs);
+
+	/* tool number */
+	idx = data[1] & 0x01;
+
+	/* process in/out prox events */
+	if (wacom_intuos_inout(urb)) goto exit;
+
+	input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
+	input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
+	input_report_abs(dev, ABS_DISTANCE, data[9]);
+
+	/* process general packets */
+	wacom_intuos_general(urb);
 	
 	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {		/* 4D mouse or Lens cursor packets */
 
 		if (data[1] & 0x02) {						/* Rotation packet */
 
-			input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
-					 ((__u32)data[6] << 3) | ((data[7] >> 5) & 7):
-					 (-(((__u32)data[6] << 3) | ((data[7] >> 5) & 7))) - 1);
+			t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
+			input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2);
 
 		} else {
 
@@ -493,9 +563,8 @@
 
 				input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
 				input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
-				input_report_abs(dev, ABS_THROTTLE,  -((data[8] & 0x08) ?
-						 ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
-						 -((__u32)data[6] << 2) | ((data[7] >> 6) & 3)));
+				t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+				input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
 
 			} else {
 				if (wacom->tool[idx] == BTN_TOOL_MOUSE) {	/* 2D mouse packets */	
@@ -527,6 +596,111 @@
 		     __FUNCTION__, retval);
 }
 
+static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	unsigned int t;
+	int idx, retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	/* check for valid report */
+	if (data[0] != 2 && data[0] != 5 && data[0] != 12)
+	{
+		printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]);
+		goto exit;
+	}
+
+	input_regs(dev, regs);
+
+	/* tool index is always 0 here since there is no dual input tool */
+	idx = data[1] & 0x01;
+
+	/* pad packets. Works as a second tool and is always in prox */
+	if (data[0] == 12)
+	{
+		/* initiate the pad as a device */
+		if (wacom->tool[1] != BTN_TOOL_FINGER)
+		{
+			wacom->tool[1] = BTN_TOOL_FINGER;
+			input_report_key(dev, wacom->tool[1], 1);
+		}
+		input_report_key(dev, BTN_0, (data[5] & 0x01));
+		input_report_key(dev, BTN_1, (data[5] & 0x02));
+		input_report_key(dev, BTN_2, (data[5] & 0x04));
+		input_report_key(dev, BTN_3, (data[5] & 0x08));
+		input_report_key(dev, BTN_4, (data[6] & 0x01));
+		input_report_key(dev, BTN_5, (data[6] & 0x02));
+		input_report_key(dev, BTN_6, (data[6] & 0x04));
+		input_report_key(dev, BTN_7, (data[6] & 0x08));
+		input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+		input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+		input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff);
+		input_sync(dev);
+		goto exit;
+	}
+
+	/* process in/out prox events */
+	if (wacom_intuos_inout(urb)) goto exit;
+
+	input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1));
+	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1));
+	input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+
+	/* process general packets */
+	wacom_intuos_general(urb);
+
+	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0)
+	{
+		/* Marker pen rotation packet. Reported as wheel due to valuator limitation */
+		if (data[1] & 0x02)
+		{
+			t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
+			t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+				((t-1) / 2 + 450)) : (450 - t / 2) ;
+			input_report_abs(dev, ABS_WHEEL, t);
+		}
+
+		/* 2D mouse packets */
+		if (wacom->tool[idx] == BTN_TOOL_MOUSE)
+		{
+			input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
+			input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
+			input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
+			input_report_key(dev, BTN_SIDE,   data[8] & 0x40);
+			input_report_key(dev, BTN_EXTRA,  data[8] & 0x20);
+			/* mouse wheel is positive when rolled backwards */
+			input_report_rel(dev, REL_WHEEL,  ((__u32)((data[8] & 0x02) >> 1)
+					 - (__u32)(data[8] & 0x01)));
+		}
+	}
+
+	input_report_key(dev, wacom->tool[idx], 1);
+	input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+	input_sync(dev);
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		    __FUNCTION__, retval);
+}
+
 static struct wacom_features wacom_features[] = {
 	{ "Wacom Penpartner",    7,   5040,  3780,  255, 32, 0, wacom_penpartner_irq },
         { "Wacom Graphire",      8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
@@ -552,6 +726,9 @@
 	{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
 	{ "Wacom Volito",        8,   5104,  3712,  511, 32, 1, wacom_graphire_irq },
 	{ "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, 3, wacom_ptu_irq },
+	{ "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq },
+	{ "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq },
+	{ "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq },
 	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
  	{ }
 };
@@ -581,6 +758,9 @@
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
 	{ }
 };
@@ -651,6 +831,12 @@
  			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
 			break;
 
+		case 4: /* new functions for Intuos3 */
+			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+			wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY);
+			/* fall through */
+
 		case 2:
 			wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
 			wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
@@ -662,7 +848,7 @@
 			break;
 
 		case 3:
- 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2);
+ 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
 			break;
 	}
 
@@ -674,6 +860,8 @@
 	wacom->dev.absmax[ABS_TILT_Y] = 127;
 	wacom->dev.absmax[ABS_WHEEL] = 1023;
 
+	wacom->dev.absmax[ABS_RX] = 4097;
+	wacom->dev.absmax[ABS_RY] = 4097;
 	wacom->dev.absmin[ABS_RZ] = -900;
 	wacom->dev.absmax[ABS_RZ] = 899;
 	wacom->dev.absmin[ABS_THROTTLE] = -1023;
@@ -712,9 +900,10 @@
 
 	input_register_device(&wacom->dev);
 
+	/* ask the tablet to report tablet data */
+	usb_set_report(intf, 3, 2, rep_data, 2);
+	/* repeat once (not sure why the first call often fails) */
 	usb_set_report(intf, 3, 2, rep_data, 2);
-	usb_set_report(intf, 3, 5, rep_data, 0);
-	usb_set_report(intf, 3, 6, rep_data, 0);
 
 	printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path);
 
diff -Nru a/include/linux/gameport.h b/include/linux/gameport.h
--- a/include/linux/gameport.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/gameport.h	2005-03-07 15:26:30 -08:00
@@ -10,19 +10,14 @@
  */
 
 #include <asm/io.h>
-#include <linux/input.h>
 #include <linux/list.h>
-
-struct gameport;
+#include <linux/device.h>
 
 struct gameport {
 
-	void *private;	/* Private pointer for joystick drivers */
-	void *driver;	/* Private pointer for gameport drivers */
-	char *name;
-	char *phys;
-
-	struct input_id id;
+	void *port_data;	/* Private pointer for gameport drivers */
+	char name[32];
+	char phys[32];
 
 	int io;
 	int speed;
@@ -35,36 +30,105 @@
 	int (*open)(struct gameport *, int);
 	void (*close)(struct gameport *);
 
-	struct gameport_dev *dev;
+	struct timer_list poll_timer;
+	unsigned int poll_interval;	/* in msecs */
+	spinlock_t timer_lock;
+	unsigned int poll_cnt;
+	void (*poll_handler)(struct gameport *);
+
+	struct gameport *parent, *child;
+
+	struct gameport_driver *drv;
+	struct semaphore drv_sem;	/* protects serio->drv so attributes can pin driver */
+
+	struct device dev;
+	unsigned int registered;	/* port has been fully registered with driver core */
 
 	struct list_head node;
 };
+#define to_gameport_port(d)	container_of(d, struct gameport, dev)
 
-struct gameport_dev {
+struct gameport_driver {
 
 	void *private;
-	char *name;
+	char *description;
 
-	void (*connect)(struct gameport *, struct gameport_dev *dev);
+	int (*connect)(struct gameport *, struct gameport_driver *drv);
+	int (*reconnect)(struct gameport *);
 	void (*disconnect)(struct gameport *);
 
-	struct list_head node;
+	struct device_driver driver;
+
+	unsigned int ignore;
 };
+#define to_gameport_driver(d)	container_of(d, struct gameport_driver, driver)
 
-int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode);
+int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode);
 void gameport_close(struct gameport *gameport);
 void gameport_rescan(struct gameport *gameport);
 
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
-void gameport_register_port(struct gameport *gameport);
+void __gameport_register_port(struct gameport *gameport, struct module *owner);
+static inline void gameport_register_port(struct gameport *gameport)
+{
+	__gameport_register_port(gameport, THIS_MODULE);
+}
+
 void gameport_unregister_port(struct gameport *gameport);
-#else
-static inline void gameport_register_port(struct gameport *gameport) { return; }
-static inline void gameport_unregister_port(struct gameport *gameport) { return; }
-#endif
 
-void gameport_register_device(struct gameport_dev *dev);
-void gameport_unregister_device(struct gameport_dev *dev);
+static inline struct gameport *gameport_allocate_port(void)
+{
+	struct gameport *gameport = kcalloc(1, sizeof(struct gameport), GFP_KERNEL);
+
+	return gameport;
+}
+
+static inline void gameport_free_port(struct gameport *gameport)
+{
+	kfree(gameport);
+}
+
+static inline void gameport_set_name(struct gameport *gameport, const char *name)
+{
+	strlcpy(gameport->name, name, sizeof(gameport->name));
+}
+
+void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+
+/*
+ * Use the following fucntions to manipulate gameport's per-port
+ * driver-specific data.
+ */
+static inline void *gameport_get_drvdata(struct gameport *gameport)
+{
+	return dev_get_drvdata(&gameport->dev);
+}
+
+static inline void gameport_set_drvdata(struct gameport *gameport, void *data)
+{
+	dev_set_drvdata(&gameport->dev, data);
+}
+
+/*
+ * Use the following fucntions to pin gameport's driver in process context
+ */
+static inline int gameport_pin_driver(struct gameport *gameport)
+{
+	return down_interruptible(&gameport->drv_sem);
+}
+
+static inline void gameport_unpin_driver(struct gameport *gameport)
+{
+	up(&gameport->drv_sem);
+}
+
+void __gameport_register_driver(struct gameport_driver *drv, struct module *owner);
+static inline void gameport_register_driver(struct gameport_driver *drv)
+{
+	__gameport_register_driver(drv, THIS_MODULE);
+}
+
+void gameport_unregister_driver(struct gameport_driver *drv);
 
 #define GAMEPORT_MODE_DISABLED		0
 #define GAMEPORT_MODE_RAW		1
@@ -81,7 +145,7 @@
 #define GAMEPORT_ID_VENDOR_GRAVIS	0x0009
 #define GAMEPORT_ID_VENDOR_GUILLEMOT	0x000a
 
-static __inline__ void gameport_trigger(struct gameport *gameport)
+static inline void gameport_trigger(struct gameport *gameport)
 {
 	if (gameport->trigger)
 		gameport->trigger(gameport);
@@ -89,7 +153,7 @@
 		outb(0xff, gameport->io);
 }
 
-static __inline__ unsigned char gameport_read(struct gameport *gameport)
+static inline unsigned char gameport_read(struct gameport *gameport)
 {
 	if (gameport->read)
 		return gameport->read(gameport);
@@ -97,7 +161,7 @@
 		return inb(gameport->io);
 }
 
-static __inline__ int gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static inline int gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
 	if (gameport->cooked_read)
 		return gameport->cooked_read(gameport, axes, buttons);
@@ -105,7 +169,7 @@
 		return -1;
 }
 
-static __inline__ int gameport_calibrate(struct gameport *gameport, int *axes, int *max)
+static inline int gameport_calibrate(struct gameport *gameport, int *axes, int *max)
 {
 	if (gameport->calibrate)
 		return gameport->calibrate(gameport, axes, max);
@@ -113,9 +177,22 @@
 		return -1;
 }
 
-static __inline__ int gameport_time(struct gameport *gameport, int time)
+static inline int gameport_time(struct gameport *gameport, int time)
 {
 	return (time * gameport->speed) / 1000;
 }
+
+static inline void gameport_set_poll_handler(struct gameport *gameport, void (*handler)(struct gameport *))
+{
+	gameport->poll_handler = handler;
+}
+
+static inline void gameport_set_poll_interval(struct gameport *gameport, unsigned int msecs)
+{
+	gameport->poll_interval = msecs;
+}
+
+void gameport_start_polling(struct gameport *gameport);
+void gameport_stop_polling(struct gameport *gameport);
 
 #endif
diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h
--- a/include/linux/hiddev.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/hiddev.h	2005-03-07 15:26:30 -08:00
@@ -201,8 +201,8 @@
  *		ioctl(fd, HIDIOCGUSAGE, &uref);
  *          }
  *	}
- *	uref.report_id |= HID_REPORT_ID_NEXT;
- *	ret = ioctl(fd, HIDIOCGREPORTINFO, &uref);
+ *	rinfo.report_id |= HID_REPORT_ID_NEXT;
+ *	ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
  *  }
  */
 
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/input.h	2005-03-07 15:26:30 -08:00
@@ -771,7 +771,7 @@
 #include <linux/fs.h>
 #include <linux/timer.h>
 
-#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define NBITS(x) (((x)/BITS_PER_LONG)+1)
 #define BIT(x)	(1UL<<((x)%BITS_PER_LONG))
 #define LONG(x) ((x)/BITS_PER_LONG)
 
diff -Nru a/include/linux/joystick.h b/include/linux/joystick.h
--- a/include/linux/joystick.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/joystick.h	2005-03-07 15:26:30 -08:00
@@ -66,10 +66,10 @@
 #define JSIOCSCORR		_IOW('j', 0x21, struct js_corr)			/* set correction values */
 #define JSIOCGCORR		_IOR('j', 0x22, struct js_corr)			/* get correction values */
 
-#define JSIOCSAXMAP		_IOW('j', 0x31, __u8[ABS_MAX])			/* set axis mapping */
-#define JSIOCGAXMAP		_IOR('j', 0x32, __u8[ABS_MAX])			/* get axis mapping */
-#define JSIOCSBTNMAP		_IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC])	/* set button mapping */
-#define JSIOCGBTNMAP		_IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC])	/* get button mapping */
+#define JSIOCSAXMAP		_IOW('j', 0x31, __u8[ABS_MAX + 1])		/* set axis mapping */
+#define JSIOCGAXMAP		_IOR('j', 0x32, __u8[ABS_MAX + 1])		/* get axis mapping */
+#define JSIOCSBTNMAP		_IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC + 1])	/* set button mapping */
+#define JSIOCGBTNMAP		_IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC + 1])	/* get button mapping */
 
 /*
  * Types and constants for get/set correction
diff -Nru a/include/linux/keyboard.h b/include/linux/keyboard.h
--- a/include/linux/keyboard.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/keyboard.h	2005-03-07 15:26:30 -08:00
@@ -16,7 +16,7 @@
 
 #define NR_SHIFT	9
 
-#define NR_KEYS		255
+#define NR_KEYS		256
 #define MAX_NR_KEYMAPS	256
 /* This means 128Kb if all keymaps are allocated. Only the superuser
 	may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */
diff -Nru a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
--- a/include/linux/mod_devicetable.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/mod_devicetable.h	2005-03-07 15:26:30 -08:00
@@ -165,4 +165,14 @@
 };
 
 
+#define SERIO_ANY	0xff
+
+struct serio_device_id {
+	__u8 type;
+	__u8 extra;
+	__u8 id;
+	__u8 proto;
+};
+
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/serio.h	2005-03-07 15:26:30 -08:00
@@ -10,18 +10,18 @@
  */
 
 #include <linux/ioctl.h>
-#include <linux/interrupt.h>
 
 #define SPIOCSTYPE	_IOW('q', 0x01, unsigned long)
 
 #ifdef __KERNEL__
 
+#include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
+#include <linux/mod_devicetable.h>
 
 struct serio {
-	void *private;
 	void *port_data;
 
 	char name[32];
@@ -29,19 +29,15 @@
 
 	unsigned int manual_bind;
 
-	unsigned short idbus;
-	unsigned short idvendor;
-	unsigned short idproduct;
-	unsigned short idversion;
-
-	unsigned long type;
-	unsigned long event;
+	struct serio_device_id id;
 
 	spinlock_t lock;		/* protects critical sections from port's interrupt handler */
 
 	int (*write)(struct serio *, unsigned char);
 	int (*open)(struct serio *);
 	void (*close)(struct serio *);
+	int (*start)(struct serio *);
+	void (*stop)(struct serio *);
 
 	struct serio *parent, *child;
 
@@ -49,6 +45,7 @@
 	struct semaphore drv_sem;	/* protects serio->drv so attributes can pin driver */
 
 	struct device dev;
+	unsigned int registered;	/* port has been fully registered with driver core */
 
 	struct list_head node;
 };
@@ -58,19 +55,18 @@
 	void *private;
 	char *description;
 
+	struct serio_device_id *id_table;
 	unsigned int manual_bind;
 
 	void (*write_wakeup)(struct serio *);
 	irqreturn_t (*interrupt)(struct serio *, unsigned char,
 			unsigned int, struct pt_regs *);
-	void (*connect)(struct serio *, struct serio_driver *drv);
+	int  (*connect)(struct serio *, struct serio_driver *drv);
 	int  (*reconnect)(struct serio *);
 	void (*disconnect)(struct serio *);
 	void (*cleanup)(struct serio *);
 
 	struct device_driver driver;
-
-	struct list_head node;
 };
 #define to_serio_driver(d)	container_of(d, struct serio_driver, driver)
 
@@ -80,15 +76,28 @@
 void serio_reconnect(struct serio *serio);
 irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
 
-void serio_register_port(struct serio *serio);
-void serio_register_port_delayed(struct serio *serio);
+void __serio_register_port(struct serio *serio, struct module *owner);
+static inline void serio_register_port(struct serio *serio)
+{
+	__serio_register_port(serio, THIS_MODULE);
+}
+
 void serio_unregister_port(struct serio *serio);
-void serio_unregister_port_delayed(struct serio *serio);
+void __serio_unregister_port_delayed(struct serio *serio, struct module *owner);
+static inline void serio_unregister_port_delayed(struct serio *serio)
+{
+	__serio_unregister_port_delayed(serio, THIS_MODULE);
+}
+
+void __serio_register_driver(struct serio_driver *drv, struct module *owner);
+static inline void serio_register_driver(struct serio_driver *drv)
+{
+	__serio_register_driver(drv, THIS_MODULE);
+}
 
-void serio_register_driver(struct serio_driver *drv);
 void serio_unregister_driver(struct serio_driver *drv);
 
-static __inline__ int serio_write(struct serio *serio, unsigned char data)
+static inline int serio_write(struct serio *serio, unsigned char data)
 {
 	if (serio->write)
 		return serio->write(serio, data);
@@ -96,29 +105,42 @@
 		return -1;
 }
 
-static __inline__ void serio_drv_write_wakeup(struct serio *serio)
+static inline void serio_drv_write_wakeup(struct serio *serio)
 {
 	if (serio->drv && serio->drv->write_wakeup)
 		serio->drv->write_wakeup(serio);
 }
 
-static __inline__ void serio_cleanup(struct serio *serio)
+static inline void serio_cleanup(struct serio *serio)
 {
 	if (serio->drv && serio->drv->cleanup)
 		serio->drv->cleanup(serio);
 }
 
+/*
+ * Use the following fucntions to manipulate serio's per-port
+ * driver-specific data.
+ */
+static inline void *serio_get_drvdata(struct serio *serio)
+{
+	return dev_get_drvdata(&serio->dev);
+}
+
+static inline void serio_set_drvdata(struct serio *serio, void *data)
+{
+	dev_set_drvdata(&serio->dev, data);
+}
 
 /*
  * Use the following fucntions to protect critical sections in
  * driver code from port's interrupt handler
  */
-static __inline__ void serio_pause_rx(struct serio *serio)
+static inline void serio_pause_rx(struct serio *serio)
 {
 	spin_lock_irq(&serio->lock);
 }
 
-static __inline__ void serio_continue_rx(struct serio *serio)
+static inline void serio_continue_rx(struct serio *serio)
 {
 	spin_unlock_irq(&serio->lock);
 }
@@ -126,12 +148,12 @@
 /*
  * Use the following fucntions to pin serio's driver in process context
  */
-static __inline__ int serio_pin_driver(struct serio *serio)
+static inline int serio_pin_driver(struct serio *serio)
 {
 	return down_interruptible(&serio->drv_sem);
 }
 
-static __inline__ void serio_unpin_driver(struct serio *serio)
+static inline void serio_unpin_driver(struct serio *serio)
 {
 	up(&serio->drv_sem);
 }
@@ -146,15 +168,20 @@
 #define SERIO_PARITY	2
 #define SERIO_FRAME	4
 
-#define SERIO_TYPE	0xff000000UL
-#define SERIO_XT	0x00000000UL
-#define SERIO_8042	0x01000000UL
-#define SERIO_RS232	0x02000000UL
-#define SERIO_HIL_MLC	0x03000000UL
-#define SERIO_PS_PSTHRU	0x05000000UL
-#define SERIO_8042_XL	0x06000000UL
+/*
+ * Serio types
+ */
+#define SERIO_XT	0x00
+#define SERIO_8042	0x01
+#define SERIO_RS232	0x02
+#define SERIO_HIL_MLC	0x03
+#define SERIO_PS_PSTHRU	0x05
+#define SERIO_8042_XL	0x06
 
-#define SERIO_PROTO	0xFFUL
+/*
+ * Serio types
+ */
+#define SERIO_UNKNOWN	0x00
 #define SERIO_MSC	0x01
 #define SERIO_SUN	0x02
 #define SERIO_MS	0x03
@@ -181,8 +208,7 @@
 #define SERIO_SNES232	0x26
 #define SERIO_SEMTECH	0x27
 #define SERIO_LKKBD	0x28
-
-#define SERIO_ID	0xff00UL
-#define SERIO_EXTRA	0xff0000UL
+#define SERIO_ELO	0x29
+#define SERIO_MICROTOUCH	0x30
 
 #endif
diff -Nru a/include/linux/uinput.h b/include/linux/uinput.h
--- a/include/linux/uinput.h	2005-03-07 15:26:30 -08:00
+++ b/include/linux/uinput.h	2005-03-07 15:26:30 -08:00
@@ -22,6 +22,9 @@
  * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
  * 
  * Changes/Revisions:
+ *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
+ *		- added force feedback support
+ *             - added UI_SET_PHYS
  *	0.1	20/06/2002
  *		- first public version
  */
@@ -29,10 +32,25 @@
 #define UINPUT_MINOR		223
 #define UINPUT_NAME		"uinput"
 #define UINPUT_BUFFER_SIZE	16
+#define UINPUT_NUM_REQUESTS	16
 
 /* state flags => bit index for {set|clear|test}_bit ops */
 #define UIST_CREATED		0
 
+struct uinput_request {
+	int			id;
+	int			code;	/* UI_FF_UPLOAD, UI_FF_ERASE */
+
+	int			retval;
+	wait_queue_head_t	waitq;
+	int			completed;
+
+	union {
+		int		effect_id;
+		struct ff_effect* effect;
+	} u;
+};
+
 struct uinput_device {
 	struct input_dev	*dev;
 	unsigned long		state;
@@ -41,13 +59,30 @@
 				head,
 				tail;
 	struct input_event	buff[UINPUT_BUFFER_SIZE];
+
+	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
+	wait_queue_head_t	requests_waitq;
+	struct semaphore	requests_sem;
 };
 #endif	/* __KERNEL__ */
 
+struct uinput_ff_upload {
+	int			request_id;
+	int			retval;
+	struct ff_effect	effect;
+};
+
+struct uinput_ff_erase {
+	int			request_id;
+	int			retval;
+	int			effect_id;
+};
+
 /* ioctl */
 #define UINPUT_IOCTL_BASE	'U'
 #define UI_DEV_CREATE		_IO(UINPUT_IOCTL_BASE, 1)
 #define UI_DEV_DESTROY		_IO(UINPUT_IOCTL_BASE, 2)
+
 #define UI_SET_EVBIT		_IOW(UINPUT_IOCTL_BASE, 100, int)
 #define UI_SET_KEYBIT		_IOW(UINPUT_IOCTL_BASE, 101, int)
 #define UI_SET_RELBIT		_IOW(UINPUT_IOCTL_BASE, 102, int)
@@ -56,6 +91,63 @@
 #define UI_SET_LEDBIT		_IOW(UINPUT_IOCTL_BASE, 105, int)
 #define UI_SET_SNDBIT		_IOW(UINPUT_IOCTL_BASE, 106, int)
 #define UI_SET_FFBIT		_IOW(UINPUT_IOCTL_BASE, 107, int)
+#define UI_SET_PHYS		_IOW(UINPUT_IOCTL_BASE, 108, char*)
+
+#define UI_BEGIN_FF_UPLOAD	_IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload)
+#define UI_END_FF_UPLOAD	_IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload)
+#define UI_BEGIN_FF_ERASE	_IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
+#define UI_END_FF_ERASE		_IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
+
+/* To write a force-feedback-capable driver, the upload_effect
+ * and erase_effect callbacks in input_dev must be implemented.
+ * The uinput driver will generate a fake input event when one of
+ * these callbacks are invoked. The userspace code then uses
+ * ioctls to retrieve additional parameters and send the return code.
+ * The callback blocks until this return code is sent.
+ *
+ * The described callback mechanism is only used if EV_FF is set.
+ * Otherwise, default implementations of upload_effect and erase_effect
+ * are used.
+ *
+ * To implement upload_effect():
+ *   1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD.
+ *      A request ID will be given in 'value'.
+ *   2. Allocate a uinput_ff_upload struct, fill in request_id with
+ *      the 'value' from the EV_UINPUT event.
+ *   3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
+ *      uinput_ff_upload struct. It will be filled in with the
+ *      ff_effect passed to upload_effect().
+ *   4. Perform the effect upload, and place the modified ff_effect
+ *      and a return code back into the uinput_ff_upload struct.
+ *   5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
+ *      uinput_ff_upload_effect struct. This will complete execution
+ *      of our upload_effect() handler.
+ *
+ * To implement erase_effect():
+ *   1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE.
+ *      A request ID will be given in 'value'.
+ *   2. Allocate a uinput_ff_erase struct, fill in request_id with
+ *      the 'value' from the EV_UINPUT event.
+ *   3. Issue a UI_BEGIN_FF_ERASE ioctl, giving it the
+ *      uinput_ff_erase struct. It will be filled in with the
+ *      effect ID passed to erase_effect().
+ *   4. Perform the effect erasure, and place a return code back
+ *      into the uinput_ff_erase struct.
+ *      and a return code back into the uinput_ff_erase struct.
+ *   5. Issue a UI_END_FF_ERASE ioctl, also giving it the
+ *      uinput_ff_erase_effect struct. This will complete execution
+ *      of our erase_effect() handler.
+ */
+
+/* This is the new event type, used only by uinput.
+ * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value'
+ * is the unique request ID. This number was picked
+ * arbitrarily, above EV_MAX (since the input system
+ * never sees it) but in the range of a 16-bit int.
+ */
+#define EV_UINPUT		0x0101
+#define UI_FF_UPLOAD		1
+#define UI_FF_ERASE		2
 
 #ifndef NBITS
 #define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
diff -Nru a/include/sound/cs46xx.h b/include/sound/cs46xx.h
--- a/include/sound/cs46xx.h	2005-03-07 15:26:30 -08:00
+++ b/include/sound/cs46xx.h	2005-03-07 15:26:30 -08:00
@@ -1720,7 +1720,7 @@
 	snd_kcontrol_t *eapd_switch; /* for amplifier hack */
 	int accept_valid;	/* accept mmap valid (for OSS) */
 
-	struct snd_cs46xx_gameport *gameport;
+	struct gameport *gameport;
 
 #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
 	int current_gpio;
@@ -1751,6 +1751,6 @@
 int snd_cs46xx_mixer(cs46xx_t *chip);
 int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi);
 int snd_cs46xx_start_dsp(cs46xx_t *chip);
-void snd_cs46xx_gameport(cs46xx_t *chip);
+int snd_cs46xx_gameport(cs46xx_t *chip);
 
 #endif /* __SOUND_CS46XX_H */
diff -Nru a/include/sound/trident.h b/include/sound/trident.h
--- a/include/sound/trident.h	2005-03-07 15:26:30 -08:00
+++ b/include/sound/trident.h	2005-03-07 15:26:30 -08:00
@@ -448,7 +448,7 @@
 
 	spinlock_t reg_lock;
 
-	struct snd_trident_gameport *gameport;
+	struct gameport *gameport;
 };
 
 int snd_trident_create(snd_card_t * card,
@@ -457,7 +457,7 @@
 		       int pcm_spdif_device,
 		       int max_wavetable_size,
 		       trident_t ** rtrident);
-void snd_trident_gameport(trident_t *trident);
+int snd_trident_create_gameport(trident_t *trident);
 
 int snd_trident_pcm(trident_t * trident, int device, snd_pcm_t **rpcm);
 int snd_trident_foldback_pcm(trident_t * trident, int device, snd_pcm_t **rpcm);
diff -Nru a/include/sound/ymfpci.h b/include/sound/ymfpci.h
--- a/include/sound/ymfpci.h	2005-03-07 15:26:30 -08:00
+++ b/include/sound/ymfpci.h	2005-03-07 15:26:30 -08:00
@@ -198,6 +198,10 @@
 #define YMFPCI_LEGACY2_IMOD	(1 << 15)	/* legacy IRQ mode */
 /* SIEN:IMOD 0:0 = legacy irq, 0:1 = INTA, 1:0 = serialized IRQ */
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
 /*
  *
  */
@@ -311,9 +315,8 @@
 	struct resource *mpu_res;
 
 	unsigned short old_legacy_ctrl;
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
-	struct resource *joystick_res;
-	struct gameport gameport;
+#ifdef SUPPORT_JOYSTICK
+	struct gameport *gameport;
 #endif
 
 	struct snd_dma_buffer work_ptr;
@@ -381,6 +384,7 @@
 		      struct pci_dev *pci,
 		      unsigned short old_legacy_ctrl,
 		      ymfpci_t ** rcodec);
+void snd_ymfpci_free_gameport(ymfpci_t *chip);
 
 int snd_ymfpci_pcm(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
 int snd_ymfpci_pcm2(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
@@ -388,9 +392,5 @@
 int snd_ymfpci_pcm_4ch(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
 int snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch);
 int snd_ymfpci_timer(ymfpci_t *chip, int device);
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK
-#endif
 
 #endif /* __SOUND_YMFPCI_H */
diff -Nru a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
--- a/scripts/mod/file2alias.c	2005-03-07 15:26:30 -08:00
+++ b/scripts/mod/file2alias.c	2005-03-07 15:26:30 -08:00
@@ -4,7 +4,7 @@
  *
  * Copyright 2002-2003  Rusty Russell, IBM Corporation
  *           2003       Kai Germaschewski
- *           
+ *
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -181,6 +181,24 @@
 	return 1;
 }
 
+/* Looks like: "serio:tyNprNidNexN" */
+static int do_serio_entry(const char *filename,
+			  struct serio_device_id *id, char *alias)
+{
+	id->type = TO_NATIVE(id->type);
+	id->proto = TO_NATIVE(id->proto);
+	id->id = TO_NATIVE(id->id);
+	id->extra = TO_NATIVE(id->extra);
+
+	strcpy(alias, "serio:");
+	ADD(alias, "ty", id->type != SERIO_ANY, id->type);
+	ADD(alias, "pr", id->proto != SERIO_ANY, id->proto);
+	ADD(alias, "id", id->id != SERIO_ANY, id->id);
+	ADD(alias, "ex", id->extra != SERIO_ANY, id->extra);
+
+	return 1;
+}
+
 /* looks like: "pnp:dD" */
 static int do_pnp_entry(const char *filename,
 			struct pnp_device_id *id, char *alias)
@@ -270,6 +288,9 @@
 	else if (sym_is(symname, "__mod_ccw_device_table"))
 		do_table(symval, sym->st_size, sizeof(struct ccw_device_id),
 			 do_ccw_entry, mod);
+	else if (sym_is(symname, "__mod_serio_device_table"))
+		do_table(symval, sym->st_size, sizeof(struct serio_device_id),
+			 do_serio_entry, mod);
 	else if (sym_is(symname, "__mod_pnp_device_table"))
 		do_table(symval, sym->st_size, sizeof(struct pnp_device_id),
 			 do_pnp_entry, mod);
diff -Nru a/sound/oss/cmpci.c b/sound/oss/cmpci.c
--- a/sound/oss/cmpci.c	2005-03-07 15:26:30 -08:00
+++ b/sound/oss/cmpci.c	2005-03-07 15:26:30 -08:00
@@ -426,7 +426,7 @@
 	struct address_info mpu_data;
 #endif
 #ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-	struct gameport gameport;
+	struct gameport *gameport;
 #endif
 
 	int	chip_version;
@@ -468,17 +468,17 @@
 
 static LIST_HEAD(devs);
 
-static	int	mpuio = 0;
-static	int	fmio = 0;
-static	int	joystick = 0;
-static	int	spdif_inverse = 0;
-static	int	spdif_loop = 0;
-static	int	spdif_out = 0;
-static	int	use_line_as_rear = 0;
-static	int	use_line_as_bass = 0;
-static	int	use_mic_as_bass = 0;
-static	int	mic_boost = 0;
-static	int	hw_copy = 0;
+static	int	mpuio;
+static	int	fmio;
+static	int	joystick;
+static	int	spdif_inverse;
+static	int	spdif_loop;
+static	int	spdif_out;
+static	int	use_line_as_rear;
+static	int	use_line_as_bass;
+static	int	use_mic_as_bass;
+static	int	mic_boost;
+static	int	hw_copy;
 module_param(mpuio, int, 0);
 module_param(fmio, int, 0);
 module_param(joystick, bool, 0);
@@ -2984,6 +2984,51 @@
 	return ChipVersion;
 }
 
+#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+static int __devinit cm_create_gameport(struct cm_state *s, int io_port)
+{
+	struct gameport *gp;
+
+	if (!request_region(io_port, CM_EXTENT_GAME, "cmpci GAME")) {
+		printk(KERN_ERR "cmpci: gameport io ports 0x%#x in use\n", io_port);
+		return -EBUSY;
+	}
+
+	if (!(s->gameport = gp = gameport_allocate_port())) {
+		printk(KERN_ERR "cmpci: can not allocate memory for gameport\n");
+		release_region(io_port, CM_EXTENT_GAME);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "C-Media GP");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+	gp->dev.parent = &s->dev->dev;
+	gp->io = io_port;
+
+	/* enable joystick */
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static void __devexit cm_free_gameport(struct cm_state *s)
+{
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+
+		gameport_unregister_port(s->gameport);
+		s->gameport = NULL;
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
+		release_region(gpio, CM_EXTENT_GAME);
+	}
+}
+#else
+static inline int cm_create_gameport(struct cm_state *s, int io_port) { return -ENOSYS; }
+static inline void cm_free_gameport(struct cm_state *s) { }
+#endif
+
 #define	echo_option(x)\
 if (x) strcat(options, "" #x " ")
 
@@ -3229,22 +3274,11 @@
 	}
 skip_mpu:
 #endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-	/* enable joystick */
-	if (joystick) {
-		s->gameport.io = 0x200;
-		if (!request_region(s->gameport.io, CM_EXTENT_GAME, "cmpci GAME")) {
-			printk(KERN_ERR "cmpci: gameport io ports in use\n");
-			s->gameport.io = 0;
-	       	} else {
-			maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
-			gameport_register_port(&s->gameport);
-		}
-	} else {
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
-		s->gameport.io = 0;
-	}
-#endif
+	/* disable joystick port */
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
+	if (joystick)
+		cm_create_gameport(s, 0x200);
+
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -3278,13 +3312,9 @@
 
 	if (!s)
 		return;
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, CM_EXTENT_GAME);
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
-	}
-#endif
+
+	cm_free_gameport(s);
+
 #ifdef CONFIG_SOUND_CMPCI_FM
 	if (s->iosynth) {
 		/* disable FM */
diff -Nru a/sound/oss/es1370.c b/sound/oss/es1370.c
--- a/sound/oss/es1370.c	2005-03-07 15:26:30 -08:00
+++ b/sound/oss/es1370.c	2005-03-07 15:26:30 -08:00
@@ -384,7 +384,7 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct semaphore sem;
 };
 
@@ -2556,6 +2556,7 @@
 static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct es1370_state *s;
+	struct gameport *gp = NULL;
 	mm_segment_t fs;
 	int i, val, ret;
 
@@ -2604,12 +2605,17 @@
 	/* note: setting CTRL_SERR_DIS is reported to break
 	 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
 	s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
-	s->gameport.io = 0;
-	if (!request_region(0x200, JOY_EXTENT, "es1370"))
+	if (!request_region(0x200, JOY_EXTENT, "es1370")) {
 		printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
-	else {
+	} else if (!(s->gameport = gp = gameport_allocate_port())) {
+		printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
+		release_region(0x200, JOY_EXTENT);
+	} else {
+		gameport_set_name(gp, "ESS1370");
+		gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+		gp->dev.parent = &s->dev->dev;
+		gp->io = 0x200;
 		s->ctrl |= CTRL_JYSTK_EN;
-		s->gameport.io = 0x200;
 	}
 	if (lineout[devindex])
 		s->ctrl |= CTRL_XCTL0;
@@ -2665,9 +2671,10 @@
 		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
 	}
 	set_fs(fs);
+
 	/* register gameport */
-	if (s->gameport.io)
-		gameport_register_port(&s->gameport);
+	if (gp)
+		gameport_register_port(gp);
 
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
@@ -2689,8 +2696,10 @@
  err_dev1:
 	printk(KERN_ERR "es1370: cannot register misc device\n");
 	free_irq(s->irq, s);
-	if (s->gameport.io)
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		release_region(s->gameport->io, JOY_EXTENT);
+		gameport_free_port(s->gameport);
+	}
  err_irq:
 	release_region(s->io, ES1370_EXTENT);
  err_region:
@@ -2709,9 +2718,10 @@
 	outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
 	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, JOY_EXTENT);
 	}
 	release_region(s->io, ES1370_EXTENT);
 	unregister_sound_dsp(s->dev_audio);
diff -Nru a/sound/oss/es1371.c b/sound/oss/es1371.c
--- a/sound/oss/es1371.c	2005-03-07 15:26:30 -08:00
+++ b/sound/oss/es1371.c	2005-03-07 15:26:30 -08:00
@@ -453,7 +453,7 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 	struct semaphore sem;
 };
 
@@ -2786,12 +2786,12 @@
 	{ PCI_ANY_ID, PCI_ANY_ID }
 };
 
-
 static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct es1371_state *s;
+	struct gameport *gp;
 	mm_segment_t fs;
-	int i, val, res = -1;
+	int i, gpio, val, res = -1;
 	int idx;
 	unsigned long tmo;
 	signed long tmo2;
@@ -2849,8 +2849,8 @@
 		printk(KERN_ERR PFX "irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u joystick %#x\n",
-	       s->rev, s->io, s->irq, s->gameport.io);
+	printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n",
+	       s->rev, s->io, s->irq);
 	/* register devices */
 	if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1)))<0)
 		goto err_dev1;
@@ -2881,16 +2881,23 @@
                     	printk(KERN_INFO PFX "Enabling internal amplifier.\n");
 		}
 	}
-	s->gameport.io = 0;
-	for (i = 0x218; i >= 0x200; i -= 0x08) {
-		if (request_region(i, JOY_EXTENT, "es1371")) {
-			s->ctrl |= CTRL_JYSTK_EN | (((i >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
-			s->gameport.io = i;
+
+	for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
+		if (request_region(gpio, JOY_EXTENT, "es1371"))
 			break;
-		}
-	}
-	if (!s->gameport.io)
+
+	if (gpio < 0x200) {
 		printk(KERN_ERR PFX "no free joystick address found\n");
+	} else if (!(s->gameport = gp = gameport_allocate_port())) {
+		printk(KERN_ERR PFX "can not allocate memory for gameport\n");
+		release_region(gpio, JOY_EXTENT);
+	} else {
+		gameport_set_name(gp, "ESS1371 Gameport");
+		gameport_set_phys(gp, "isa%04x/gameport0", gpio);
+		gp->dev.parent = &s->dev->dev;
+		gp->io = gpio;
+		s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+	}
 
 	s->sctrl = 0;
 	cssr = 0;
@@ -2960,9 +2967,11 @@
 	set_fs(fs);
 	/* turn on S/PDIF output driver if requested */
 	outl(cssr, s->io+ES1371_REG_STATUS);
+
 	/* register gameport */
-	if (s->gameport.io)
-		gameport_register_port(&s->gameport);
+	if (s->gameport)
+		gameport_register_port(s->gameport);
+
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -2973,8 +2982,10 @@
        	return 0;
 
  err_gp:
-	if (s->gameport.io)
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		release_region(s->gameport->io, JOY_EXTENT);
+		gameport_free_port(s->gameport);
+	}
 #ifdef ES1371_DEBUG
 	if (s->ps)
 		remove_proc_entry("es1371", NULL);
@@ -3013,9 +3024,10 @@
 	outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
 	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, JOY_EXTENT);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, JOY_EXTENT);
 	}
 	release_region(s->io, ES1371_EXTENT);
 	unregister_sound_dsp(s->dev_audio);
diff -Nru a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
--- a/sound/oss/esssolo1.c	2005-03-07 15:26:30 -08:00
+++ b/sound/oss/esssolo1.c	2005-03-07 15:26:30 -08:00
@@ -226,7 +226,7 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -2280,9 +2280,36 @@
 	return 0;
 }
 
+static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
+{
+	struct gameport *gp;
+
+	if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) {
+		printk(KERN_ERR "solo1: gameport io ports are in use\n");
+		return -EBUSY;
+	}
+
+	s->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "solo1: can not allocate memory for gameport\n");
+		release_region(io_port, GAMEPORT_EXTENT);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ESS Solo1 Gameport");
+	gameport_set_phys(gp, "isa%04x/gameport0", io_port);
+	gp->dev.parent = &s->dev->dev;
+	gp->io = io_port;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
 static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct solo1_state *s;
+	int gpio;
 	int ret;
 
  	if ((ret=pci_enable_device(pcidev)))
@@ -2323,7 +2350,7 @@
 	s->vcbase = pci_resource_start(pcidev, 2);
 	s->ddmabase = s->vcbase + DDMABASE_OFFSET;
 	s->mpubase = pci_resource_start(pcidev, 3);
-	s->gameport.io = pci_resource_start(pcidev, 4);
+	gpio = pci_resource_start(pcidev, 4);
 	s->irq = pcidev->irq;
 	ret = -EBUSY;
 	if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
@@ -2342,15 +2369,10 @@
 		printk(KERN_ERR "solo1: io ports in use\n");
 		goto err_region4;
 	}
-	if (s->gameport.io && !request_region(s->gameport.io, GAMEPORT_EXTENT, "ESS Solo1")) {
-		printk(KERN_ERR "solo1: gameport io ports in use\n");
-		s->gameport.io = 0;
-	}
 	if ((ret=request_irq(s->irq,solo1_interrupt,SA_SHIRQ,"ESS Solo1",s))) {
 		printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
 		goto err_irq;
 	}
-	printk(KERN_INFO "solo1: joystick port at %#x\n", s->gameport.io+1);
 	/* register devices */
 	if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) {
 		ret = s->dev_audio;
@@ -2373,7 +2395,7 @@
 		goto err;
 	}
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	solo1_register_gameport(s, gpio);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	return 0;
@@ -2390,8 +2412,6 @@
 	printk(KERN_ERR "solo1: initialisation error\n");
 	free_irq(s->irq, s);
  err_irq:
-	if (s->gameport.io)
-		release_region(s->gameport.io, GAMEPORT_EXTENT);
 	release_region(s->mpubase, MPUBASE_EXTENT);
  err_region4:
 	release_region(s->ddmabase, DDMABASE_EXTENT);
@@ -2417,9 +2437,10 @@
 	synchronize_irq(s->irq);
 	pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, GAMEPORT_EXTENT);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, GAMEPORT_EXTENT);
 	}
 	release_region(s->iobase, IOBASE_EXTENT);
 	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
diff -Nru a/sound/oss/mad16.c b/sound/oss/mad16.c
--- a/sound/oss/mad16.c	2005-03-07 15:26:30 -08:00
+++ b/sound/oss/mad16.c	2005-03-07 15:26:30 -08:00
@@ -52,7 +52,7 @@
 
 static int      mad16_conf;
 static int      mad16_cdsel;
-static struct gameport gameport;
+static struct gameport *gameport;
 static DEFINE_SPINLOCK(lock);
 
 #define C928	1
@@ -902,7 +902,30 @@
 	-1, -1, -1, -1
 };
 
-static int __init init_mad16(void)
+static int __devinit mad16_register_gameport(int io_port)
+{
+	if (!request_region(io_port, 1, "mad16 gameport")) {
+		printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port);
+		return -EBUSY;
+	}
+
+	gameport = gameport_allocate_port();
+	if (!gameport) {
+		printk(KERN_ERR "mad16: can not allocate memory for gameport\n");
+		release_region(io_port, 1);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gameport, "MAD16 Gameport");
+	gameport_set_phys(gameport, "isa%04x/gameport0", io_port);
+	gameport->io = io_port;
+
+	gameport_register_port(gameport);
+
+	return 0;
+}
+
+static int __devinit init_mad16(void)
 {
 	int dmatype = 0;
 
@@ -1027,17 +1050,9 @@
 
 	found_mpu = probe_mad16_mpu(&cfg_mpu);
 
-	if (joystick == 1) {
-		/* register gameport */
-		if (!request_region(0x201, 1, "mad16 gameport"))
-			printk(KERN_ERR "mad16: gameport address 0x201 already in use\n");
-		else {
-			printk(KERN_ERR "mad16: gameport enabled at 0x201\n");
-			gameport.io = 0x201;
-			gameport_register_port(&gameport);
-		}
-	}
-	else printk(KERN_ERR "mad16: gameport disabled.\n");
+	if (joystick)
+		mad16_register_gameport(0x201);
+
 	return 0;
 }
 
@@ -1045,10 +1060,10 @@
 {
 	if (found_mpu)
 		unload_mad16_mpu(&cfg_mpu);
-	if (gameport.io) {
+	if (gameport) {
 		/* the gameport was initialized so we must free it up */
-		gameport_unregister_port(&gameport);
-		gameport.io = 0;
+		gameport_unregister_port(gameport);
+		gameport = NULL;
 		release_region(0x201, 1);
 	}
 	unload_mad16(&cfg);
diff -Nru a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
--- a/sound/oss/sonicvibes.c	2005-03-07 15:26:30 -08:00
+++ b/sound/oss/sonicvibes.c	2005-03-07 15:26:30 -08:00
@@ -365,7 +365,7 @@
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
 
-	struct gameport gameport;
+	struct gameport *gameport;
 };
 
 /* --------------------------------------------------------------------- */
@@ -2485,12 +2485,39 @@
 #define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
 				 (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
 
+static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
+{
+	struct gameport *gp;
+
+	if (!request_region(io_port, SV_EXTENT_GAME, "S3 SonicVibes Gameport")) {
+		printk(KERN_ERR "sv: gameport io ports are in use\n");
+		return -EBUSY;
+	}
+
+	s->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "sv: can not allocate memory for gameport\n");
+		release_region(io_port, SV_EXTENT_GAME);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "S3 SonicVibes Gameport");
+	gameport_set_phys(gp, "isa%04x/gameport0", io_port);
+	gp->dev.parent = &s->dev->dev;
+	gp->io = io_port;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
 static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
        	struct sv_state *s;
 	mm_segment_t fs;
 	int i, val, ret;
+	int gpio;
 	char *ddmaname;
 	unsigned ddmanamelen;
 
@@ -2546,11 +2573,11 @@
 	s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI);
 	s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA);
 	s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
-	s->gameport.io = pci_resource_start(pcidev, RESOURCE_GAME);
+	gpio = pci_resource_start(pcidev, RESOURCE_GAME);
 	pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9);  /* enable and use extended mode */
 	pci_write_config_dword(pcidev, 0x48, s->iodmac | 9);  /* enable */
 	printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n",
-	       s->iosb, s->ioenh, s->iosynth, s->iomidi, s->gameport.io, s->iodmaa, s->iodmac);
+	       s->iosb, s->ioenh, s->iosynth, s->iomidi, gpio, s->iodmaa, s->iodmac);
 	s->irq = pcidev->irq;
 	
 	/* hack */
@@ -2577,10 +2604,7 @@
 		printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
 		goto err_region1;
 	}
-	if (s->gameport.io && !request_region(s->gameport.io, SV_EXTENT_GAME, "ESS Solo1")) {
-		printk(KERN_ERR "sv: gameport io ports in use\n");
-		s->gameport.io = 0;
-	}
+
 	/* initialize codec registers */
 	outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
 	udelay(50);
@@ -2639,7 +2663,7 @@
 	}
 	set_fs(fs);
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	sv_register_gameport(s, gpio);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
@@ -2659,8 +2683,6 @@
 	printk(KERN_ERR "sv: cannot register misc device\n");
 	free_irq(s->irq, s);
  err_irq:
-	if (s->gameport.io)
-		release_region(s->gameport.io, SV_EXTENT_GAME);
 	release_region(s->iosynth, SV_EXTENT_SYNTH);
  err_region1:
 	release_region(s->iomidi, SV_EXTENT_MIDI);
@@ -2689,9 +2711,10 @@
 	/*outb(0, s->iodmaa + SV_DMA_RESET);*/
 	/*outb(0, s->iodmac + SV_DMA_RESET);*/
 	free_irq(s->irq, s);
-	if (s->gameport.io) {
-		gameport_unregister_port(&s->gameport);
-		release_region(s->gameport.io, SV_EXTENT_GAME);
+	if (s->gameport) {
+		int gpio = s->gameport->io;
+		gameport_unregister_port(s->gameport);
+		release_region(gpio, SV_EXTENT_GAME);
 	}
 	release_region(s->iodmac, SV_EXTENT_DMA);
 	release_region(s->iodmaa, SV_EXTENT_DMA);
diff -Nru a/sound/oss/trident.c b/sound/oss/trident.c
--- a/sound/oss/trident.c	2005-03-07 15:26:30 -08:00
+++ b/sound/oss/trident.c	2005-03-07 15:26:30 -08:00
@@ -441,7 +441,7 @@
 	struct timer_list timer;
 
 	/* Game port support */
-	struct gameport gameport;
+	struct gameport *gameport;
 };
 
 enum dmabuf_mode {
@@ -4257,21 +4257,21 @@
 static unsigned char
 trident_game_read(struct gameport *gameport)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 	return inb(TRID_REG(card, T4D_GAME_LEG));
 }
 
 static void
 trident_game_trigger(struct gameport *gameport)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 	outb(0xff, TRID_REG(card, T4D_GAME_LEG));
 }
 
 static int
 trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 	int i;
 
 	*buttons = (~inb(TRID_REG(card, T4D_GAME_LEG)) >> 4) & 0xf;
@@ -4288,7 +4288,7 @@
 static int
 trident_game_open(struct gameport *gameport, int mode)
 {
-	struct trident_card *card = gameport->driver;
+	struct trident_card *card = gameport->port_data;
 
 	switch (mode) {
 	case GAMEPORT_MODE_COOKED:
@@ -4305,6 +4305,31 @@
 	return 0;
 }
 
+static int __devinit
+trident_register_gameport(struct trident_card *card)
+{
+	struct gameport *gp;
+
+	card->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "trident: can not allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "Trident 4DWave");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(card->pci_dev));
+	gp->read = trident_game_read;
+	gp->trigger = trident_game_trigger;
+	gp->cooked_read = trident_game_cooked_read;
+	gp->open = trident_game_open;
+	gp->fuzz = 64;
+	gp->port_data = card;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
 /* install the driver, we do not allocate hardware channel nor DMA buffer */ 
 /* now, they are defered until "ACCESS" time (in prog_dmabuf called by */ 
 /* open/read/write/ioctl/mmap) */
@@ -4368,13 +4393,6 @@
 	card->banks[BANK_B].addresses = &bank_b_addrs;
 	card->banks[BANK_B].bitmap = 0UL;
 
-	card->gameport.driver = card;
-	card->gameport.fuzz = 64;
-	card->gameport.read = trident_game_read;
-	card->gameport.trigger = trident_game_trigger;
-	card->gameport.cooked_read = trident_game_cooked_read;
-	card->gameport.open = trident_game_open;
-
 	init_MUTEX(&card->open_sem);
 	spin_lock_init(&card->lock);
 	init_timer(&card->timer);
@@ -4508,7 +4526,7 @@
 	trident_enable_loop_interrupts(card);
 
 	/* Register gameport */
-	gameport_register_port(&card->gameport);
+	trident_register_gameport(card);
 
 out:
 	return rc;
@@ -4551,7 +4569,8 @@
 	}
 
 	/* Unregister gameport */
-	gameport_unregister_port(&card->gameport);
+	if (card->gameport)
+		gameport_unregister_port(card->gameport);
 
 	/* Kill interrupts, and SP/DIF */
 	trident_disable_loop_interrupts(card);
diff -Nru a/sound/pci/als4000.c b/sound/pci/als4000.c
--- a/sound/pci/als4000.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/als4000.c	2005-03-07 15:26:30 -08:00
@@ -104,8 +104,7 @@
 	struct pci_dev *pci;
 	unsigned long gcr;
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 } snd_card_als4000_t;
 
@@ -566,21 +565,80 @@
 	spin_unlock_irq(&chip->reg_lock);
 }
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_als4000_create_gameport(snd_card_als4000_t *acard, int dev)
+{
+	struct gameport *gp;
+	struct resource *r;
+	int io_port;
+
+	if (joystick_port[dev] == 0)
+		return -ENODEV;
+
+	if (joystick_port[dev] == 1) { /* auto-detect */
+		for (io_port = 0x200; io_port <= 0x218; io_port += 8) {
+			r = request_region(io_port, 8, "ALS4000 gameport");
+			if (r)
+				break;
+		}
+	} else {
+		io_port = joystick_port[dev];
+		r = request_region(io_port, 8, "ALS4000 gameport");
+	}
+
+	if (!r) {
+		printk(KERN_WARNING "als4000: cannot reserve joystick ports\n");
+		return -EBUSY;
+	}
+
+	acard->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "als4000: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ALS4000 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(acard->pci));
+	gp->dev.parent = &acard->pci->dev;
+	gp->io = io_port;
+	gp->port_data = r;
+
+	/* Enable legacy joystick port */
+	snd_als4000_set_addr(acard->gcr, 0, 0, 0, 1);
+
+	gameport_register_port(acard->gameport);
+
+	return 0;
+}
+
+static void snd_als4000_free_gameport(snd_card_als4000_t *acard)
+{
+	if (acard->gameport) {
+		struct resource *r = acard->gameport->port_data;
+
+		gameport_unregister_port(acard->gameport);
+		acard->gameport = NULL;
+
+		snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_als4000_create_gameport(snd_card_als4000_t *acard, int dev) { return -ENOSYS; }
+static inline void snd_als4000_free_gameport(snd_card_als4000_t *acard) { }
+#endif
+
 static void snd_card_als4000_free( snd_card_t *card )
 {
 	snd_card_als4000_t * acard = (snd_card_als4000_t *)card->private_data;
+
 	/* make sure that interrupts are disabled */
 	snd_als4000_gcr_write_addr( acard->gcr, 0x8c, 0);
 	/* free resources */
-#ifdef SUPPORT_JOYSTICK
-	if (acard->res_joystick) {
-		if (acard->gameport.io)
-			gameport_unregister_port(&acard->gameport);
-		snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */
-		release_resource(acard->res_joystick);
-		kfree_nocheck(acard->res_joystick);
-	}
-#endif
+	snd_als4000_free_gameport(acard);
 	pci_release_regions(acard->pci);
 	pci_disable_device(acard->pci);
 }
@@ -596,7 +654,6 @@
 	opl3_t *opl3;
 	unsigned short word;
 	int err;
-	int joystick = 0;
 
 	if (dev >= SNDRV_CARDS)
 		return -ENODEV;
@@ -640,26 +697,9 @@
 	acard->gcr = gcr;
 	card->private_free = snd_card_als4000_free;
 
-	/* disable all legacy ISA stuff except for joystick */
-#ifdef SUPPORT_JOYSTICK
-	if (joystick_port[dev] == 1) {
-		/* auto-detect */
-		long p;
-		for (p = 0x200; p <= 0x218; p += 8) {
-			if ((acard->res_joystick = request_region(p, 8, "ALS4000 gameport")) != NULL) {
-				joystick_port[dev] = p;
-				break;
-			}
-		}
-	} else if (joystick_port[dev] > 0)
-		acard->res_joystick = request_region(joystick_port[dev], 8, "ALS4000 gameport");
-	if (acard->res_joystick)
-		joystick = joystick_port[dev];
-	else
-		joystick = 0;
-#endif
-	snd_als4000_set_addr(gcr, 0, 0, 0, joystick);
-	
+	/* disable all legacy ISA stuff */
+	snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0);
+
 	if ((err = snd_sbdsp_create(card,
 				    gcr + 0x10,
 				    pci->irq,
@@ -711,12 +751,7 @@
 		}
 	}
 
-#ifdef SUPPORT_JOYSTICK
-	if (acard->res_joystick) {
-		acard->gameport.io = joystick;
-		gameport_register_port(&acard->gameport);
-	}
-#endif
+	snd_als4000_create_gameport(acard, dev);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff -Nru a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
--- a/sound/pci/au88x0/au88x0.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/au88x0/au88x0.c	2005-03-07 15:26:30 -08:00
@@ -290,10 +290,9 @@
 		snd_card_free(card);
 		return err;
 	}
-	if ((err = vortex_gameport_register(chip)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+
+	vortex_gameport_register(chip);
+
 #if 0
 	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
 			       sizeof(snd_vortex_synth_arg_t), &wave) < 0
diff -Nru a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
--- a/sound/pci/au88x0/au88x0.h	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/au88x0/au88x0.h	2005-03-07 15:26:30 -08:00
@@ -272,7 +272,7 @@
 
 /* Driver stuff. */
 static int __devinit vortex_gameport_register(vortex_t * card);
-static int __devexit vortex_gameport_unregister(vortex_t * card);
+static void vortex_gameport_unregister(vortex_t * card);
 #ifndef CHIP_AU8820
 static int __devinit vortex_eq_init(vortex_t * vortex);
 static int __devexit vortex_eq_free(vortex_t * vortex);
diff -Nru a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
--- a/sound/pci/au88x0/au88x0_game.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/au88x0/au88x0_game.c	2005-03-07 15:26:30 -08:00
@@ -44,20 +44,20 @@
 
 static unsigned char vortex_game_read(struct gameport *gameport)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport->port_data;
 	return hwread(vortex->mmio, VORTEX_GAME_LEGACY);
 }
 
 static void vortex_game_trigger(struct gameport *gameport)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport->port_data;
 	hwwrite(vortex->mmio, VORTEX_GAME_LEGACY, 0xff);
 }
 
 static int
 vortex_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport->port_data;
 	int i;
 
 	*buttons = (~hwread(vortex->mmio, VORTEX_GAME_LEGACY) >> 4) & 0xf;
@@ -73,7 +73,7 @@
 
 static int vortex_game_open(struct gameport *gameport, int mode)
 {
-	vortex_t *vortex = gameport->driver;
+	vortex_t *vortex = gameport->port_data;
 
 	switch (mode) {
 	case GAMEPORT_MODE_COOKED:
@@ -94,40 +94,42 @@
 	return 0;
 }
 
-static int vortex_gameport_register(vortex_t * vortex)
+static int __devinit vortex_gameport_register(vortex_t * vortex)
 {
-	if ((vortex->gameport = kcalloc(1, sizeof(struct gameport), GFP_KERNEL)) == NULL) {
-		return -1;
+	struct gameport *gp;
+
+	vortex->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");
+		return -ENOMEM;
 	};
-	
-	vortex->gameport->driver = vortex;
-	vortex->gameport->fuzz = 64;
-
-	vortex->gameport->read = vortex_game_read;
-	vortex->gameport->trigger = vortex_game_trigger;
-	vortex->gameport->cooked_read = vortex_game_cooked_read;
-	vortex->gameport->open = vortex_game_open;
-
-	gameport_register_port((struct gameport *)vortex->gameport);
-
-/*	printk(KERN_INFO "gameport%d: %s at speed %d kHz\n",
-		vortex->gameport->number, vortex->pci_dev->name, vortex->gameport->speed);
-*/
+
+	gameport_set_name(gp, "AU88x0 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(vortex->pci_dev));
+	gp->dev.parent = &vortex->pci_dev->dev;
+
+	gp->read = vortex_game_read;
+	gp->trigger = vortex_game_trigger;
+	gp->cooked_read = vortex_game_cooked_read;
+	gp->open = vortex_game_open;
+
+	gp->port_data = vortex;
+	gp->fuzz = 64;
+
+	gameport_register_port(gp);
+
 	return 0;
 }
 
-static int vortex_gameport_unregister(vortex_t * vortex)
+static void vortex_gameport_unregister(vortex_t * vortex)
 {
-	if (vortex->gameport != NULL) {
+	if (vortex->gameport) {
 		gameport_unregister_port(vortex->gameport);
-		kfree(vortex->gameport);
+		vortex->gameport = NULL;
 	}
-	return 0;
 }
 
 #else
-
-static inline int vortex_gameport_register(vortex_t * vortex) { return 0; }
-static inline int vortex_gameport_unregister(vortex_t * vortex) { return 0; }
-
+static inline int vortex_gameport_register(vortex_t * vortex) { return -ENOSYS; }
+static inline void vortex_gameport_unregister(vortex_t * vortex) { }
 #endif
diff -Nru a/sound/pci/azt3328.c b/sound/pci/azt3328.c
--- a/sound/pci/azt3328.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/azt3328.c	2005-03-07 15:26:30 -08:00
@@ -160,19 +160,19 @@
 #endif
 	    
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
-#ifdef SUPPORT_JOYSTICK
-static int joystick[SNDRV_CARDS];
-#endif
-
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard.");
+
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for AZF3328 soundcard.");
+
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard.");
+
 #ifdef SUPPORT_JOYSTICK
+static int joystick[SNDRV_CARDS];
 module_param_array(joystick, bool, NULL, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard.");
 #endif
@@ -189,8 +189,7 @@
 	unsigned long mixer_port;
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 
 	struct pci_dev *pci;
@@ -1222,6 +1221,63 @@
 
 /******************************************************************/
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_azf3328_config_joystick(azf3328_t *chip, int dev)
+{
+	struct gameport *gp;
+	struct resource *r;
+
+	if (!joystick[dev])
+		return -ENODEV;
+
+	if (!(r = request_region(0x200, 8, "AZF3328 gameport"))) {
+		printk(KERN_WARNING "azt3328: cannot reserve joystick ports\n");
+		return -EBUSY;
+	}
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "AZF3328 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+	gp->io = 0x200;
+	gp->port_data = r;
+
+	snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
+			      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY);
+
+	gameport_register_port(chip->gameport);
+
+	return 0;
+}
+
+static void snd_azf3328_free_joystick(azf3328_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = chip->gameport->port_data;
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+		/* disable gameport */
+		snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
+				      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_azf3328_config_joystick(azf3328_t *chip, int dev) { return -ENOSYS; }
+static inline void snd_azf3328_free_joystick(azf3328_t *chip) { }
+#endif
+
+/******************************************************************/
+
 static int snd_azf3328_free(azf3328_t *chip)
 {
         if (chip->irq < 0)
@@ -1236,16 +1292,7 @@
 
         synchronize_irq(chip->irq);
       __end_hw:
-#ifdef SUPPORT_JOYSTICK
-	if (chip->res_joystick) {
-		gameport_unregister_port(&chip->gameport);
-		/* disable gameport */
-		snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
-				      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
-		release_resource(chip->res_joystick);
-		kfree_nocheck(chip->res_joystick);
-	}
-#endif
+	snd_azf3328_free_joystick(chip);
         if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
 	pci_release_regions(chip->pci);
@@ -1373,28 +1420,6 @@
 	return 0;
 }
 
-#ifdef SUPPORT_JOYSTICK
-static void __devinit snd_azf3328_config_joystick(azf3328_t *chip, int joystick)
-{
-	unsigned char val;
-
-	if (joystick == 1) {
-		if ((chip->res_joystick = request_region(0x200, 8, "AZF3328 gameport")) != NULL)
-			chip->gameport.io = 0x200;
-	}
-
-	val = inb(chip->io2_port + IDX_IO2_LEGACY_ADDR);
-	if (chip->res_joystick)
-		val |= LEGACY_JOY;
-	else
-		val &= ~LEGACY_JOY;
-
-	outb(val, chip->io2_port + IDX_IO2_LEGACY_ADDR);
-	if (chip->res_joystick)
-		gameport_register_port(&chip->gameport);
-}
-#endif
-
 static int __devinit snd_azf3328_probe(struct pci_dev *pci,
 					  const struct pci_device_id *pci_id)
 {
@@ -1465,9 +1490,9 @@
 "azt3328: Feel free to contact hw7oshyuv3001@sneakemail.com for bug reports etc.!\n");
 #endif
 
-#ifdef SUPPORT_JOYSTICK
-	snd_azf3328_config_joystick(chip, joystick[dev]);
-#endif
+	if (snd_azf3328_config_joystick(chip, dev) < 0)
+		snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR,
+			      snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
 
 	pci_set_drvdata(pci, card);
 	dev++;
diff -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c
--- a/sound/pci/cmipci.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/cmipci.c	2005-03-07 15:26:30 -08:00
@@ -471,8 +471,7 @@
 	snd_rawmidi_t *rmidi;
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 
 	spinlock_t reg_lock;
@@ -2522,6 +2521,71 @@
 		strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC");
 }
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_cmipci_create_gameport(cmipci_t *cm, int dev)
+{
+	static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */
+	struct gameport *gp;
+	struct resource *r = NULL;
+	int i, io_port = 0;
+
+	if (joystick_port[dev] == 0)
+		return -ENODEV;
+
+	if (joystick_port[dev] == 1) { /* auto-detect */
+		for (i = 0; ports[i]; i++) {
+			io_port = ports[i];
+			r = request_region(io_port, 1, "CMIPCI gameport");
+			if (r)
+				break;
+		}
+	} else {
+		io_port = joystick_port[dev];
+		r = request_region(io_port, 1, "CMIPCI gameport");
+	}
+
+	if (!r) {
+		printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+		return -EBUSY;
+	}
+
+	cm->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "cmipci: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+	gameport_set_name(gp, "C-Media Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(cm->pci));
+	gp->dev.parent = &cm->pci->dev;
+	gp->io = io_port;
+	gp->port_data = r;
+
+	snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
+
+	gameport_register_port(cm->gameport);
+
+	return 0;
+}
+
+static void snd_cmipci_free_gameport(cmipci_t *cm)
+{
+	if (cm->gameport) {
+		struct resource *r = cm->gameport->port_data;
+
+		gameport_unregister_port(cm->gameport);
+		cm->gameport = NULL;
+
+		snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_cmipci_create_gameport(cmipci_t *cm, int dev) { return -ENOSYS; }
+static inline void snd_cmipci_free_gameport(cmipci_t *cm) { }
+#endif
 
 static int snd_cmipci_free(cmipci_t *cm)
 {
@@ -2541,14 +2605,8 @@
 
 		free_irq(cm->irq, (void *)cm);
 	}
-#ifdef SUPPORT_JOYSTICK
-	if (cm->res_joystick) {
-		gameport_unregister_port(&cm->gameport);
-		snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-		release_resource(cm->res_joystick);
-		kfree_nocheck(cm->res_joystick);
-	}
-#endif
+
+	snd_cmipci_free_gameport(cm);
 	pci_release_regions(cm->pci);
 	pci_disable_device(cm->pci);
 	kfree(cm);
@@ -2757,31 +2815,9 @@
 	snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K|CM_SPDF_AC97);
 #endif /* USE_VAR48KRATE */
 
-#ifdef SUPPORT_JOYSTICK
-	if (joystick_port[dev] > 0) {
-		if (joystick_port[dev] == 1) { /* auto-detect */
-			static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */
-			int i;
-			for (i = 0; ports[i]; i++) {
-				joystick_port[dev] = ports[i];
-				cm->res_joystick = request_region(ports[i], 1, "CMIPCI gameport");
-				if (cm->res_joystick)
-					break;
-			}
-		} else {
-			cm->res_joystick = request_region(joystick_port[dev], 1, "CMIPCI gameport");
-		}
-	}
-	if (cm->res_joystick) {
-		cm->gameport.io = joystick_port[dev];
-		snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-		gameport_register_port(&cm->gameport);
-	} else {
-		if (joystick_port[dev] > 0)
-			printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+	if (snd_cmipci_create_gameport(cm, dev) < 0)
 		snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-	}
-#endif
+
 	snd_card_set_dev(card, &pci->dev);
 
 	*rcmipci = cm;
diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c
--- a/sound/pci/cs4281.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/cs4281.c	2005-03-07 15:26:30 -08:00
@@ -495,7 +495,7 @@
 	unsigned int midcr;
 	unsigned int uartm;
 
-	struct snd_cs4281_gameport *gameport;
+	struct gameport *gameport;
 
 #ifdef CONFIG_PM
 	u32 suspend_regs[SUSPEND_REGISTERS];
@@ -1238,38 +1238,29 @@
 
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
-typedef struct snd_cs4281_gameport {
-	struct gameport info;
-	cs4281_t *chip;
-} cs4281_gameport_t;
-
 static void snd_cs4281_gameport_trigger(struct gameport *gameport)
 {
-	cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport;
-	cs4281_t *chip;
-	snd_assert(gp, return);
-	chip = gp->chip;
+	cs4281_t *chip = gameport->port_data;
+
+	snd_assert(chip, return);
 	snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff);
 }
 
 static unsigned char snd_cs4281_gameport_read(struct gameport *gameport)
 {
-	cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport;
-	cs4281_t *chip;
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	cs4281_t *chip = gameport->port_data;
+
+	snd_assert(chip, return 0);
 	return snd_cs4281_peekBA0(chip, BA0_JSPT);
 }
 
 #ifdef COOKED_MODE
 static int snd_cs4281_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport;
-	cs4281_t *chip;
+	cs4281_t *chip = gameport->port_data;
 	unsigned js1, js2, jst;
 	
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	snd_assert(chip, return 0);
 
 	js1 = snd_cs4281_peekBA0(chip, BA0_JSC1);
 	js2 = snd_cs4281_peekBA0(chip, BA0_JSC2);
@@ -1282,10 +1273,12 @@
 	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
 	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
 
-	for(jst=0;jst<4;++jst)
-		if(axes[jst]==0xFFFF) axes[jst] = -1;
+	for (jst = 0; jst < 4; ++jst)
+		if (axes[jst] == 0xFFFF) axes[jst] = -1;
 	return 0;
 }
+#else
+#define snd_cs4281_gameport_cooked_read	NULL
 #endif
 
 static int snd_cs4281_gameport_open(struct gameport *gameport, int mode)
@@ -1303,31 +1296,43 @@
 	return 0;
 }
 
-static void __devinit snd_cs4281_gameport(cs4281_t *chip)
+static int __devinit snd_cs4281_create_gameport(cs4281_t *chip)
 {
-	cs4281_gameport_t *gp;
-	gp = kmalloc(sizeof(*gp), GFP_KERNEL);
-	if (! gp) {
-		snd_printk(KERN_ERR "cannot allocate gameport area\n");
-		return;
-	}
-	memset(gp, 0, sizeof(*gp));
-	gp->info.open = snd_cs4281_gameport_open;
-	gp->info.read = snd_cs4281_gameport_read;
-	gp->info.trigger = snd_cs4281_gameport_trigger;
-#ifdef COOKED_MODE
-	gp->info.cooked_read = snd_cs4281_gameport_cooked_read;
-#endif
-	gp->chip = chip;
-	chip->gameport = gp;
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "cs4281: cannot allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "CS4281 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+	gp->open = snd_cs4281_gameport_open;
+	gp->read = snd_cs4281_gameport_read;
+	gp->trigger = snd_cs4281_gameport_trigger;
+	gp->cooked_read = snd_cs4281_gameport_cooked_read;
+	gp->port_data = chip;
 
 	snd_cs4281_pokeBA0(chip, BA0_JSIO, 0xFF); // ?
 	snd_cs4281_pokeBA0(chip, BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-	gameport_register_port(&gp->info);
+
+	gameport_register_port(gp);
+
+	return 0;
 }
 
+static void snd_cs4281_free_gameport(cs4281_t *chip)
+{
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
+}
 #else
-#define snd_cs4281_gameport(chip) /*NOP*/
+static inline int snd_cs4281_gameport(cs4281_t *chip) { return -ENOSYS; }
+static inline void snd_cs4281_gameport_free(cs4281_t *chip) { }
 #endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */
 
 
@@ -1337,12 +1342,8 @@
 
 static int snd_cs4281_free(cs4281_t *chip)
 {
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (chip->gameport) {
-		gameport_unregister_port(&chip->gameport->info);
-		kfree(chip->gameport);
-	}
-#endif
+	snd_cs4281_free_gameport(chip);
+
 	if (chip->irq >= 0)
 		synchronize_irq(chip->irq);
 
@@ -1990,7 +1991,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	snd_cs4281_gameport(chip);
+	snd_cs4281_create_gameport(chip);
 	strcpy(card->driver, "CS4281");
 	strcpy(card->shortname, "Cirrus Logic CS4281");
 	sprintf(card->longname, "%s at 0x%lx, irq %d",
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/cs46xx/cs46xx_lib.c	2005-03-07 15:26:30 -08:00
@@ -2690,37 +2690,28 @@
 
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
-typedef struct snd_cs46xx_gameport {
-	struct gameport info;
-	cs46xx_t *chip;
-} cs46xx_gameport_t;
-
 static void snd_cs46xx_gameport_trigger(struct gameport *gameport)
 {
-	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;
-	cs46xx_t *chip;
-	snd_assert(gp, return);
-	chip = gp->chip;
+	cs46xx_t *chip = gameport->port_data;
+
+	snd_assert(chip, return);
 	snd_cs46xx_pokeBA0(chip, BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
 }
 
 static unsigned char snd_cs46xx_gameport_read(struct gameport *gameport)
 {
-	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;
-	cs46xx_t *chip;
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	cs46xx_t *chip = gameport->port_data;
+
+	snd_assert(chip, return 0);
 	return snd_cs46xx_peekBA0(chip, BA0_JSPT); //inb(gameport->io);
 }
 
 static int snd_cs46xx_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport;
-	cs46xx_t *chip;
+	cs46xx_t *chip = gameport->port_data;
 	unsigned js1, js2, jst;
-	
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+
+	snd_assert(chip, return 0);
 
 	js1 = snd_cs46xx_peekBA0(chip, BA0_JSC1);
 	js2 = snd_cs46xx_peekBA0(chip, BA0_JSC2);
@@ -2751,33 +2742,44 @@
 	return 0;
 }
 
-void __devinit snd_cs46xx_gameport(cs46xx_t *chip)
+int __devinit snd_cs46xx_gameport(cs46xx_t *chip)
 {
-	cs46xx_gameport_t *gp;
-	gp = kmalloc(sizeof(*gp), GFP_KERNEL);
-	if (! gp) {
-		snd_printk("cannot allocate gameport area\n");
-		return;
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "cs46xx: cannot allocate memory for gameport\n");
+		return -ENOMEM;
 	}
-	memset(gp, 0, sizeof(*gp));
-	gp->info.open = snd_cs46xx_gameport_open;
-	gp->info.read = snd_cs46xx_gameport_read;
-	gp->info.trigger = snd_cs46xx_gameport_trigger;
-	gp->info.cooked_read = snd_cs46xx_gameport_cooked_read;
-	gp->chip = chip;
-	chip->gameport = gp;
+
+	gameport_set_name(gp, "CS46xx Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+	gp->port_data = chip;
+
+	gp->open = snd_cs46xx_gameport_open;
+	gp->read = snd_cs46xx_gameport_read;
+	gp->trigger = snd_cs46xx_gameport_trigger;
+	gp->cooked_read = snd_cs46xx_gameport_cooked_read;
 
 	snd_cs46xx_pokeBA0(chip, BA0_JSIO, 0xFF); // ?
 	snd_cs46xx_pokeBA0(chip, BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-	gameport_register_port(&gp->info);
-}
 
-#else
+	gameport_register_port(gp);
 
-void __devinit snd_cs46xx_gameport(cs46xx_t *chip)
-{
+	return 0;
 }
 
+static inline void snd_cs46xx_remove_gameport(cs46xx_t *chip)
+{
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
+}
+#else
+int __devinit snd_cs46xx_gameport(cs46xx_t *chip) { return -ENOSYS; }
+static inline void snd_cs46xx_remove_gameport(cs46xx_t *chip) { }
 #endif /* CONFIG_GAMEPORT */
 
 /*
@@ -2893,12 +2895,7 @@
 	if (chip->active_ctrl)
 		chip->active_ctrl(chip, 1);
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (chip->gameport) {
-		gameport_unregister_port(&chip->gameport->info);
-		kfree(chip->gameport);
-	}
-#endif
+	snd_cs46xx_remove_gameport(chip);
 
 	if (chip->amplifier_ctrl)
 		chip->amplifier_ctrl(chip, -chip->amplifier); /* force to off */
diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c
--- a/sound/pci/ens1370.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/ens1370.c	2005-03-07 15:26:30 -08:00
@@ -430,7 +430,7 @@
 #endif
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
+	struct gameport *gameport;
 #endif
 };
 
@@ -1734,43 +1734,99 @@
 #endif /* CHIP1370 */
 
 #ifdef SUPPORT_JOYSTICK
-static int snd_ensoniq_joystick(ensoniq_t *ensoniq, long port)
-{
+
 #ifdef CHIP1371
-	if (port == 1) { /* auto-detect */
-		for (port = 0x200; port <= 0x218; port += 8)
-			if (request_region(port, 8, "ens137x: gameport"))
+static int __devinit snd_ensoniq_get_joystick_port(int dev)
+{
+	switch (joystick_port[dev]) {
+	case 0: /* disabled */
+	case 1: /* auto-detect */
+	case 0x200:
+	case 0x208:
+	case 0x210:
+	case 0x218:
+		return joystick_port[dev];
+
+	default:
+		printk(KERN_ERR "ens1371: invalid joystick port %#x", joystick_port[dev]);
+		return 0;
+	}
+}
+#else
+static inline int snd_ensoniq_get_joystick_port(int dev)
+{
+	return joystick[dev] ? 0x200 : 0;
+}
+#endif
+
+static int __devinit snd_ensoniq_create_gameport(ensoniq_t *ensoniq, int dev)
+{
+	struct gameport *gp;
+	int io_port;
+
+	io_port = snd_ensoniq_get_joystick_port(dev);
+
+	switch (io_port) {
+	case 0:
+		return -ENOSYS;
+
+	case 1: /* auto_detect */
+		for (io_port = 0x200; io_port <= 0x218; io_port += 8)
+			if (request_region(io_port, 8, "ens137x: gameport"))
 				break;
-		if (port > 0x218) {
-			snd_printk("no gameport available\n");
+		if (io_port > 0x218) {
+			printk(KERN_WARNING "ens137x: no gameport ports available\n");
 			return -EBUSY;
 		}
-	} else
-#endif
-	{
-		if (!request_region(port, 8, "ens137x: gameport")) {
-			snd_printk("gameport io port 0x%03x in use", ensoniq->gameport.io);
+		break;
+
+	default:
+		if (!request_region(io_port, 8, "ens137x: gameport")) {
+			printk(KERN_WARNING "ens137x: gameport io port 0x%#x in use\n", io_port);
 			return -EBUSY;
 		}
+		break;
 	}
-	ensoniq->gameport.io = port;
+
+	ensoniq->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "ens137x: cannot allocate memory for gameport\n");
+		release_region(io_port, 8);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ES137x");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(ensoniq->pci));
+	gp->dev.parent = &ensoniq->pci->dev;
+	gp->io = io_port;
+
 	ensoniq->ctrl |= ES_JYSTK_EN;
 #ifdef CHIP1371
 	ensoniq->ctrl &= ~ES_1371_JOY_ASELM;
-	ensoniq->ctrl |= ES_1371_JOY_ASEL((ensoniq->gameport.io - 0x200) / 8);
+	ensoniq->ctrl |= ES_1371_JOY_ASEL((io_port - 0x200) / 8);
 #endif
 	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
-	gameport_register_port(&ensoniq->gameport);
+
+	gameport_register_port(ensoniq->gameport);
+
 	return 0;
 }
 
-static void snd_ensoniq_joystick_free(ensoniq_t *ensoniq)
+static void snd_ensoniq_free_gameport(ensoniq_t *ensoniq)
 {
-	gameport_unregister_port(&ensoniq->gameport);
-	ensoniq->ctrl &= ~ES_JYSTK_EN;
-	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
-	release_region(ensoniq->gameport.io, 8);
+	if (ensoniq->gameport) {
+		int port = ensoniq->gameport->io;
+
+		gameport_unregister_port(ensoniq->gameport);
+		ensoniq->gameport = NULL;
+		ensoniq->ctrl &= ~ES_JYSTK_EN;
+		outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+		release_region(port, 8);
+	}
 }
+#else
+static inline int snd_ensoniq_create_gameport(ensoniq_t *ensoniq, long port) { return -ENOSYS; }
+static inline void snd_ensoniq_free_gameport(ensoniq_t *ensoniq) { }
 #endif /* SUPPORT_JOYSTICK */
 
 /*
@@ -1810,10 +1866,7 @@
 
 static int snd_ensoniq_free(ensoniq_t *ensoniq)
 {
-#ifdef SUPPORT_JOYSTICK
-	if (ensoniq->ctrl & ES_JYSTK_EN)
-		snd_ensoniq_joystick_free(ensoniq);
-#endif
+	snd_ensoniq_free_gameport(ensoniq);
 	if (ensoniq->irq < 0)
 		goto __hw_end;
 #ifdef CHIP1370
@@ -2313,22 +2366,9 @@
 		snd_card_free(card);
 		return err;
 	}
-#ifdef SUPPORT_JOYSTICK
-#ifdef CHIP1371
-	switch (joystick_port[dev]) {
-	case 1: /* auto-detect */
-	case 0x200:
-	case 0x208:
-	case 0x210:
-	case 0x218:
-		snd_ensoniq_joystick(ensoniq, joystick_port[dev]);
-		break;
-	}
-#else
-	if (joystick[dev])
-		snd_ensoniq_joystick(ensoniq, 0x200);
-#endif
-#endif /* SUPPORT_JOYSTICK */
+
+	snd_ensoniq_create_gameport(ensoniq, dev);
+
 	strcpy(card->driver, DRIVER_NAME);
 
 	strcpy(card->shortname, "Ensoniq AudioPCI");
diff -Nru a/sound/pci/es1938.c b/sound/pci/es1938.c
--- a/sound/pci/es1938.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/es1938.c	2005-03-07 15:26:30 -08:00
@@ -72,6 +72,10 @@
                 "{ESS,ES1969},"
 		"{TerraTec,128i PCI}}");
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 #ifndef PCI_VENDOR_ID_ESS
 #define PCI_VENDOR_ID_ESS		0x125d
 #endif
@@ -237,8 +241,8 @@
 	spinlock_t mixer_lock;
         snd_info_entry_t *proc_entry;
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	struct gameport gameport;
+#ifdef SUPPORT_JOYSTICK
+	struct gameport *gameport;
 #endif
 #ifdef CONFIG_PM
 	unsigned char saved_regs[SAVED_REG_SIZE];
@@ -1418,6 +1422,39 @@
 }
 #endif /* CONFIG_PM */
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_es1938_create_gameport(es1938_t *chip)
+{
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "es1938: cannot allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "ES1938");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+	gp->io = chip->game_port;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static void snd_es1938_free_gameport(es1938_t *chip)
+{
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
+}
+#else
+static inline int snd_es1938_create_gameport(es1938_t *chip) { return -ENOSYS; }
+static inline void snd_es1938_free_gameport(es1938_t *chip) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int snd_es1938_free(es1938_t *chip)
 {
 	/* disable irqs */
@@ -1425,10 +1462,8 @@
 	if (chip->rmidi)
 		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0);
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (chip->gameport.io)
-		gameport_unregister_port(&chip->gameport);
-#endif
+	snd_es1938_free_gameport(chip);
+
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
 	pci_release_regions(chip->pci);
@@ -1698,10 +1733,7 @@
 		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0x40);
 	}
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	chip->gameport.io = chip->game_port;
-	gameport_register_port(&chip->gameport);
-#endif
+	snd_es1938_create_gameport(chip);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c
--- a/sound/pci/es1968.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/es1968.c	2005-03-07 15:26:30 -08:00
@@ -605,8 +605,7 @@
 #endif
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 };
 
@@ -2450,6 +2449,59 @@
 }
 #endif /* CONFIG_PM */
 
+#ifdef SUPPORT_JOYSTICK
+#define JOYSTICK_ADDR	0x200
+static int __devinit snd_es1968_create_gameport(es1968_t *chip, int dev)
+{
+	struct gameport *gp;
+	struct resource *r;
+	u16 val;
+
+	if (!joystick[dev])
+		return -ENODEV;
+
+	r = request_region(JOYSTICK_ADDR, 8, "ES1968 gameport");
+	if (!r)
+		return -EBUSY;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "es1968: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	pci_read_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, &val);
+	pci_write_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, val | 0x04);
+
+	gameport_set_name(gp, "ES1968 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+	gp->io = JOYSTICK_ADDR;
+
+	gameport_register_port(gp);
+
+	return 0;
+}
+
+static void snd_es1968_free_gameport(es1968_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = chip->gameport->port_data;
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_es1968_create_gameport(es1968_t *chip, int dev) { return -ENOSYS; }
+static inline void snd_es1968_free_gameport(es1968_t *chip) { }
+#endif
+
 static int snd_es1968_free(es1968_t *chip)
 {
 	if (chip->io_port) {
@@ -2460,13 +2512,7 @@
 
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
-#ifdef SUPPORT_JOYSTICK
-	if (chip->res_joystick) {
-		gameport_unregister_port(&chip->gameport);
-		release_resource(chip->res_joystick);
-		kfree_nocheck(chip->res_joystick);
-	}
-#endif
+	snd_es1968_free_gameport(chip);
 	snd_es1968_set_acpi(chip, ACPI_D3);
 	chip->master_switch = NULL;
 	chip->master_volume = NULL;
@@ -2693,17 +2739,7 @@
 		}
 	}
 
-#ifdef SUPPORT_JOYSTICK
-#define JOYSTICK_ADDR	0x200
-	if (joystick[dev] &&
-	    (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "ES1968 gameport")) != NULL) {
-		u16 val;
-		pci_read_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, &val);
-		pci_write_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, val | 0x04);
-		chip->gameport.io = JOYSTICK_ADDR;
-		gameport_register_port(&chip->gameport);
-	}
-#endif
+	snd_es1968_create_gameport(chip, dev);
 
 	snd_es1968_start_irq(chip);
 
diff -Nru a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
--- a/sound/pci/sonicvibes.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/sonicvibes.c	2005-03-07 15:26:30 -08:00
@@ -46,6 +46,10 @@
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");
 
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
 #ifndef PCI_VENDOR_ID_S3
 #define PCI_VENDOR_ID_S3             0x5333
 #endif
@@ -242,8 +246,8 @@
 	snd_kcontrol_t *master_mute;
 	snd_kcontrol_t *master_volume;
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	struct gameport gameport;
+#ifdef SUPPORT_JOYSTICK
+	struct gameport *gameport;
 #endif
 };
 
@@ -1163,15 +1167,47 @@
 
  */
 
+#ifdef SUPPORT_JOYSTICK
 static snd_kcontrol_new_t snd_sonicvibes_game_control __devinitdata =
 SONICVIBES_SINGLE("Joystick Speed", 0, SV_IREG_GAME_PORT, 1, 15, 0);
 
-static int snd_sonicvibes_free(sonicvibes_t *sonic)
+static int __devinit snd_sonicvibes_create_gameport(sonicvibes_t *sonic)
 {
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (sonic->gameport.io)
-		gameport_unregister_port(&sonic->gameport);
+	struct gameport *gp;
+
+	sonic->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "sonicvibes: cannot allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "SonicVibes Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(sonic->pci));
+	gp->dev.parent = &sonic->pci->dev;
+	gp->io = sonic->game_port;
+
+	gameport_register_port(gp);
+
+	snd_ctl_add(sonic->card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic));
+
+	return 0;
+}
+
+static void snd_sonicvibes_free_gameport(sonicvibes_t *sonic)
+{
+	if (sonic->gameport) {
+		gameport_unregister_port(sonic->gameport);
+		sonic->gameport = NULL;
+	}
+}
+#else
+static inline int snd_sonicvibes_create_gameport(sonicvibes_t *sonic) { return -ENOSYS; }
+static inline void snd_sonicvibes_free_gameport(sonicvibes_t *sonic) { }
 #endif
+
+static int snd_sonicvibes_free(sonicvibes_t *sonic)
+{
+	snd_sonicvibes_free_gameport(sonic);
 	pci_write_config_dword(sonic->pci, 0x40, sonic->dmaa_port);
 	pci_write_config_dword(sonic->pci, 0x48, sonic->dmac_port);
 	if (sonic->irq >= 0)
@@ -1332,7 +1368,6 @@
 	snd_sonicvibes_debug(sonic);
 #endif
 	sonic->revision = snd_sonicvibes_in(sonic, SV_IREG_REVISION);
-	snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic));
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sonic, &ops)) < 0) {
 		snd_sonicvibes_free(sonic);
@@ -1459,10 +1494,8 @@
 		snd_card_free(card);
 		return err;
 	}
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	sonic->gameport.io = sonic->game_port;
-	gameport_register_port(&sonic->gameport);
-#endif
+
+	snd_sonicvibes_create_gameport(sonic);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff -Nru a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
--- a/sound/pci/trident/trident.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/trident/trident.c	2005-03-07 15:26:30 -08:00
@@ -157,7 +157,7 @@
 	}
 #endif
 
-	snd_trident_gameport(trident);
+	snd_trident_create_gameport(trident);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff -Nru a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
--- a/sound/pci/trident/trident_main.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/trident/trident_main.c	2005-03-07 15:26:30 -08:00
@@ -3110,37 +3110,28 @@
 
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
 
-typedef struct snd_trident_gameport {
-	struct gameport info;
-	trident_t *chip;
-} trident_gameport_t;
-
 static unsigned char snd_trident_gameport_read(struct gameport *gameport)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	trident_t *chip = gameport->port_data;
+
+	snd_assert(chip, return 0);
 	return inb(TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
 static void snd_trident_gameport_trigger(struct gameport *gameport)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
-	snd_assert(gp, return);
-	chip = gp->chip;
+	trident_t *chip = gameport->port_data;
+
+	snd_assert(chip, return);
 	outb(0xff, TRID_REG(chip, GAMEPORT_LEGACY));
 }
 
 static int snd_trident_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
+	trident_t *chip = gameport->port_data;
 	int i;
 
-	snd_assert(gp, return 0);
-	chip = gp->chip;
+	snd_assert(chip, return 0);
 
 	*buttons = (~inb(TRID_REG(chip, GAMEPORT_LEGACY)) >> 4) & 0xf;
 
@@ -3154,10 +3145,9 @@
 
 static int snd_trident_gameport_open(struct gameport *gameport, int mode)
 {
-	trident_gameport_t *gp = (trident_gameport_t *)gameport;
-	trident_t *chip;
-	snd_assert(gp, return -1);
-	chip = gp->chip;
+	trident_t *chip = gameport->port_data;
+
+	snd_assert(chip, return 0);
 
 	switch (mode) {
 		case GAMEPORT_MODE_COOKED:
@@ -3173,30 +3163,42 @@
 	}
 }
 
-void __devinit snd_trident_gameport(trident_t *chip)
+int __devinit snd_trident_create_gameport(trident_t *chip)
 {
-	trident_gameport_t *gp;
-	gp = kmalloc(sizeof(*gp), GFP_KERNEL);
-	if (! gp) {
-		snd_printk("cannot allocate gameport area\n");
-		return;
-	}
-	memset(gp, 0, sizeof(*gp));
-	gp->chip = chip;
-	gp->info.fuzz = 64;
-	gp->info.read = snd_trident_gameport_read;
-	gp->info.trigger = snd_trident_gameport_trigger;
-	gp->info.cooked_read = snd_trident_gameport_cooked_read;
-	gp->info.open = snd_trident_gameport_open;
-	chip->gameport = gp;
+	struct gameport *gp;
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "trident: cannot allocate memory for gameport\n");
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "Trident 4DWave");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+
+	gp->port_data = chip;
+	gp->fuzz = 64;
+	gp->read = snd_trident_gameport_read;
+	gp->trigger = snd_trident_gameport_trigger;
+	gp->cooked_read = snd_trident_gameport_cooked_read;
+	gp->open = snd_trident_gameport_open;
 
-	gameport_register_port(&gp->info);
+	gameport_register_port(gp);
+
+	return 0;
 }
 
-#else
-void __devinit snd_trident_gameport(trident_t *chip)
+static inline void snd_trident_free_gameport(trident_t *chip)
 {
+	if (chip->gameport) {
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+	}
 }
+#else
+int __devinit snd_trident_create_gameport(trident_t *chip) { return -ENOSYS; }
+static inline void snd_trident_free_gameport(trident_t *chip) { }
 #endif /* CONFIG_GAMEPORT */
 
 /*
@@ -3661,12 +3663,7 @@
 
 static int snd_trident_free(trident_t *trident)
 {
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-	if (trident->gameport) {
-		gameport_unregister_port(&trident->gameport->info);
-		kfree(trident->gameport);
-	}
-#endif
+	snd_trident_free_gameport(trident);
 	snd_trident_disable_eso(trident);
 	// Disable S/PDIF out
 	if (trident->device == TRIDENT_DEVICE_ID_NX)
diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c
--- a/sound/pci/via82xx.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/via82xx.c	2005-03-07 15:26:30 -08:00
@@ -394,8 +394,7 @@
 	snd_info_entry_t *proc_entry;
 
 #ifdef SUPPORT_JOYSTICK
-	struct gameport gameport;
-	struct resource *res_joystick;
+	struct gameport *gameport;
 #endif
 };
 
@@ -1635,11 +1634,70 @@
 	return 0;
 }
 
+#ifdef SUPPORT_JOYSTICK
+#define JOYSTICK_ADDR	0x200
+static int __devinit snd_via686_create_gameport(via82xx_t *chip, int dev, unsigned char *legacy)
+{
+	struct gameport *gp;
+	struct resource *r;
+
+	if (!joystick[dev])
+		return -ENODEV;
+
+	r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport");
+	if (!r) {
+		printk(KERN_WARNING "via82xx: cannot reserve joystick port 0x%#x\n", JOYSTICK_ADDR);
+		return -EBUSY;
+	}
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "via82xx: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+	gameport_set_name(gp, "VIA686 Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+	gp->io = JOYSTICK_ADDR;
+	gp->port_data = r;
+
+	/* Enable legacy joystick port */
+	*legacy |= VIA_FUNC_ENABLE_GAME;
+	pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, *legacy);
+
+	gameport_register_port(chip->gameport);
+
+	return 0;
+}
+
+static void snd_via686_free_gameport(via82xx_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = chip->gameport->port_data;
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_via686_create_gameport(via82xx_t *chip, int dev, unsigned char *legacy)
+{
+	return -ENOSYS;
+}
+static inline void snd_via686_free_gameport(via82xx_t *chip) { }
+#endif
+
+
 /*
  *
  */
 
-static int snd_via8233_init_misc(via82xx_t *chip, int dev)
+static int __devinit snd_via8233_init_misc(via82xx_t *chip, int dev)
 {
 	int i, err, caps;
 	unsigned char val;
@@ -1671,7 +1729,7 @@
 	return 0;
 }
 
-static int snd_via686_init_misc(via82xx_t *chip, int dev)
+static int __devinit snd_via686_init_misc(via82xx_t *chip, int dev)
 {
 	unsigned char legacy, legacy_cfg;
 	int rev_h = 0;
@@ -1718,15 +1776,6 @@
 		mpu_port[dev] = 0;
 	}
 
-#ifdef SUPPORT_JOYSTICK
-#define JOYSTICK_ADDR	0x200
-	if (joystick[dev] &&
-	    (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport")) != NULL) {
-		legacy |= VIA_FUNC_ENABLE_GAME;
-		chip->gameport.io = JOYSTICK_ADDR;
-	}
-#endif
-
 	pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy);
 	pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg);
 	if (chip->mpu_res) {
@@ -1741,10 +1790,7 @@
 		pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy);
 	}
 
-#ifdef SUPPORT_JOYSTICK
-	if (chip->res_joystick)
-		gameport_register_port(&chip->gameport);
-#endif
+	snd_via686_create_gameport(chip, dev, &legacy);
 
 #ifdef CONFIG_PM
 	chip->legacy_saved = legacy;
@@ -1973,14 +2019,9 @@
 		kfree_nocheck(chip->mpu_res);
 	}
 	pci_release_regions(chip->pci);
+
 	if (chip->chip_type == TYPE_VIA686) {
-#ifdef SUPPORT_JOYSTICK
-		if (chip->res_joystick) {
-			gameport_unregister_port(&chip->gameport);
-			release_resource(chip->res_joystick);
-			kfree_nocheck(chip->res_joystick);
-		}
-#endif
+		snd_via686_free_gameport(chip);
 		pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy);
 		pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->old_legacy_cfg);
 	}
diff -Nru a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
--- a/sound/pci/ymfpci/ymfpci.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/ymfpci/ymfpci.c	2005-03-07 15:26:30 -08:00
@@ -79,6 +79,96 @@
 
 MODULE_DEVICE_TABLE(pci, snd_ymfpci_ids);
 
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_ymfpci_create_gameport(ymfpci_t *chip, int dev,
+						int legacy_ctrl, int legacy_ctrl2)
+{
+	struct gameport *gp;
+	struct resource *r = NULL;
+	int io_port = joystick_port[dev];
+
+	if (!io_port)
+		return -ENODEV;
+
+	if (chip->pci->device >= 0x0010) { /* YMF 744/754 */
+
+		if (io_port == 1) {
+			/* auto-detect */
+			if (!(io_port = pci_resource_start(chip->pci, 2)))
+				return -ENODEV;
+		}
+	} else {
+		if (io_port == 1) {
+			/* auto-detect */
+			for (io_port = 0x201; io_port <= 0x205; io_port++) {
+				if (io_port == 0x203)
+					continue;
+				if ((r = request_region(io_port, 1, "YMFPCI gameport")) != NULL)
+					break;
+			}
+			if (!r) {
+				printk(KERN_ERR "ymfpci: no gameport ports available\n");
+				return -EBUSY;
+			}
+		}
+		switch (io_port) {
+		case 0x201: legacy_ctrl2 |= 0 << 6; break;
+		case 0x202: legacy_ctrl2 |= 1 << 6; break;
+		case 0x204: legacy_ctrl2 |= 2 << 6; break;
+		case 0x205: legacy_ctrl2 |= 3 << 6; break;
+		default:
+			printk(KERN_ERR "ymfpci: invalid joystick port %#x", io_port);
+			return -EINVAL;
+		}
+	}
+
+	if (!r && !(r = request_region(io_port, 1, "YMFPCI gameport"))) {
+		printk(KERN_ERR "ymfpci: joystick port %#x is in use.\n", io_port);
+		return -EBUSY;
+	}
+
+	chip->gameport = gp = gameport_allocate_port();
+	if (!gp) {
+		printk(KERN_ERR "ymfpci: cannot allocate memory for gameport\n");
+		release_resource(r);
+		kfree_nocheck(r);
+		return -ENOMEM;
+	}
+
+
+	gameport_set_name(gp, "Yamaha YMF Gameport");
+	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+	gp->dev.parent = &chip->pci->dev;
+	gp->io = io_port;
+
+	if (chip->pci->device >= 0x0010) /* YMF 744/754 */
+		pci_write_config_word(chip->pci, PCIR_DSXG_JOYBASE, io_port);
+
+	pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, legacy_ctrl | YMFPCI_LEGACY_JPEN);
+	pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, legacy_ctrl2);
+
+	gameport_register_port(chip->gameport);
+
+	return 0;
+}
+
+void snd_ymfpci_free_gameport(ymfpci_t *chip)
+{
+	if (chip->gameport) {
+		struct resource *r = chip->gameport->port_data;
+
+		gameport_unregister_port(chip->gameport);
+		chip->gameport = NULL;
+
+		release_resource(r);
+		kfree_nocheck(r);
+	}
+}
+#else
+static inline int snd_ymfpci_create_gameport(ymfpci_t *chip, int dev, int l, int l2) { return -ENOSYS; }
+void snd_ymfpci_free_gameport(ymfpci_t *chip) { }
+#endif /* SUPPORT_JOYSTICK */
+
 static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
 					   const struct pci_device_id *pci_id)
 {
@@ -86,9 +176,6 @@
 	snd_card_t *card;
 	struct resource *fm_res = NULL;
 	struct resource *mpu_res = NULL;
-#ifdef SUPPORT_JOYSTICK
-	struct resource *joystick_res = NULL;
-#endif
 	ymfpci_t *chip;
 	opl3_t *opl3;
 	char *str;
@@ -138,17 +225,6 @@
 			legacy_ctrl |= YMFPCI_LEGACY_MEN;
 			pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]);
 		}
-#ifdef SUPPORT_JOYSTICK
-		if (joystick_port[dev] == 1) {
-			/* auto-detect */
-			joystick_port[dev] = pci_resource_start(pci, 2);
-		}
-		if (joystick_port[dev] > 0 &&
-		    (joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport")) != NULL) {
-			legacy_ctrl |= YMFPCI_LEGACY_JPEN;
-			pci_write_config_word(pci, PCIR_DSXG_JOYBASE, joystick_port[dev]);
-		}
-#endif
 	} else {
 		switch (fm_port[dev]) {
 		case 0x388: legacy_ctrl2 |= 0; break;
@@ -178,34 +254,6 @@
 			legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO;
 			mpu_port[dev] = 0;
 		}
-#ifdef SUPPORT_JOYSTICK
-		if (joystick_port[dev] == 1) {
-			/* auto-detect */
-			long p;
-			for (p = 0x201; p <= 0x205; p++) {
-				if (p == 0x203) continue;
-				if ((joystick_res = request_region(p, 1, "YMFPCI gameport")) != NULL)
-					break;
-			}
-			if (joystick_res)
-				joystick_port[dev] = p;
-		}
-		switch (joystick_port[dev]) {
-		case 0x201: legacy_ctrl2 |= 0 << 6; break;
-		case 0x202: legacy_ctrl2 |= 1 << 6; break;
-		case 0x204: legacy_ctrl2 |= 2 << 6; break;
-		case 0x205: legacy_ctrl2 |= 3 << 6; break;
-		default: joystick_port[dev] = 0; break;
-		}
-		if (! joystick_res && joystick_port[dev] > 0)
-			joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport");
-		if (joystick_res) {
-			legacy_ctrl |= YMFPCI_LEGACY_JPEN;
-		} else {
-			legacy_ctrl2 &= ~YMFPCI_LEGACY2_JSIO;
-			joystick_port[dev] = 0;
-		}
-#endif
 	}
 	if (mpu_res) {
 		legacy_ctrl |= YMFPCI_LEGACY_MIEN;
@@ -226,19 +274,10 @@
 			release_resource(fm_res);
 			kfree_nocheck(fm_res);
 		}
-#ifdef SUPPORT_JOYSTICK
-		if (joystick_res) {
-			release_resource(joystick_res);
-			kfree_nocheck(joystick_res);
-		}
-#endif
 		return err;
 	}
 	chip->fm_res = fm_res;
 	chip->mpu_res = mpu_res;
-#ifdef SUPPORT_JOYSTICK
-	chip->joystick_res = joystick_res;
-#endif
 	strcpy(card->driver, str);
 	sprintf(card->shortname, "Yamaha DS-XG (%s)", str);
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
@@ -292,12 +331,8 @@
 			return err;
 		}
 	}
-#ifdef SUPPORT_JOYSTICK
-	if (chip->joystick_res) {
-		chip->gameport.io = joystick_port[dev];
-		gameport_register_port(&chip->gameport);
-	}
-#endif
+
+	snd_ymfpci_create_gameport(chip, dev, legacy_ctrl, legacy_ctrl2);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
diff -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
--- a/sound/pci/ymfpci/ymfpci_main.c	2005-03-07 15:26:30 -08:00
+++ b/sound/pci/ymfpci/ymfpci_main.c	2005-03-07 15:26:30 -08:00
@@ -2079,14 +2079,7 @@
 		release_resource(chip->fm_res);
 		kfree_nocheck(chip->fm_res);
 	}
-#ifdef SUPPORT_JOYSTICK
-	if (chip->joystick_res) {
-		if (chip->gameport.io)
-			gameport_unregister_port(&chip->gameport);
-		release_resource(chip->joystick_res);
-		kfree_nocheck(chip->joystick_res);
-	}
-#endif
+	snd_ymfpci_free_gameport(chip);
 	if (chip->reg_area_virt)
 		iounmap(chip->reg_area_virt);
 	if (chip->work_ptr.area)
