<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">bk://kernel.bkbits.net/vojtech/input
vojtech@suse.cz|ChangeSet|20040923110416|52112 vojtech

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/09/23 17:13:04-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# drivers/usb/input/hid-core.c
#   2004/09/23 17:13:00-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/23 13:01:47+02:00 mochel@digitalimplant.org 
#   input: Remove calls to pm_access() and pm_dev_idle() from input.c, as
#          they're empty functions anyway.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Patrick Mochel &lt;mochel@digitalimplant.org&gt;
# 
# drivers/input/input.c
#   2004/09/23 13:01:41+02:00 mochel@digitalimplant.org +0 -7
#   input: Remove calls to pm_access() and pm_dev_idle() from input.c, as
#          they're empty functions anyway.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Patrick Mochel &lt;mochel@digitalimplant.org&gt;
# 
# ChangeSet
#   2004/09/23 12:59:31+02:00 vojtech@suse.cz 
#   input: Tidy up &amp; fix the hid-input.c driver. Dual-wheel A4 mice don't report the phantom
#            button anymore, D-Pads are mapped to Hat-switches, debug can print HID-&gt;Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# include/linux/input.h
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +3 -0
#   input: Tidy up &amp; fix the hid-input.c driver. Dual-wheel A4 mice don't report the phantom
#            button anymore, D-Pads are mapped to Hat-switches, debug can print HID-&gt;Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# drivers/usb/input/hid.h
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +41 -3
#   input: Tidy up &amp; fix the hid-input.c driver. Dual-wheel A4 mice don't report the phantom
#            button anymore, D-Pads are mapped to Hat-switches, debug can print HID-&gt;Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# drivers/usb/input/hid-input.c
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +217 -246
#   input: Tidy up &amp; fix the hid-input.c driver. Dual-wheel A4 mice don't report the phantom
#            button anymore, D-Pads are mapped to Hat-switches, debug can print HID-&gt;Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# drivers/usb/input/hid-debug.h
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +263 -1
#   input: Tidy up &amp; fix the hid-input.c driver. Dual-wheel A4 mice don't report the phantom
#            button anymore, D-Pads are mapped to Hat-switches, debug can print HID-&gt;Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# drivers/usb/input/hid-core.c
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +8 -9
#   input: Tidy up &amp; fix the hid-input.c driver. Dual-wheel A4 mice don't report the phantom
#            button anymore, D-Pads are mapped to Hat-switches, debug can print HID-&gt;Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# ChangeSet
#   2004/09/22 23:57:11-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/Makefile
#   2004/09/22 23:57:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/09/22 23:57:06-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/22 14:08:35-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# drivers/usb/input/hid-core.c
#   2004/09/22 14:08:31-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/serio/Kconfig
#   2004/09/22 14:08:31-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/22 14:07:34-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/input/gameport/vortex.c
#   2004/09/22 14:07:29-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/22 10:46:32+02:00 vojtech@suse.cz 
#   input: More IOWarrior blacklist entries in hid.c, rearranging the
#          blacklist back to alphabetic order.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# drivers/usb/input/hid-core.c
#   2004/09/22 10:46:25+02:00 vojtech@suse.cz +9 -7
#   input: More IOWarrior blacklist entries in hid.c, rearranging the
#          blacklist back to alphabetic order.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# ChangeSet
#   2004/09/22 01:50:38-05:00 dtor_core@ameritech.net 
#   Input: atkbd - export extra, scroll, set, softrepeat and softraw as individual
#          keyboard attributes (sysfs) and allow them to be set/changed independently
#          for each keyboard:
#   
#          echo -n "2" &gt; /sys/bus/serio/devices/serio1/set
#          echo -n "1" &gt; /sys/bus/serio/devices/serio1/softrepeat
#   
#   Signed-off-by: Dmitry Torokhov &lt;dtor@mail.ru&gt; 
# 
# drivers/input/keyboard/atkbd.c
#   2004/09/22 01:50:23-05:00 dtor_core@ameritech.net +365 -76
#   Export extra, scroll, set, softrepeat and softraw as individual
#   sysfs keyboard attributes.
# 
# ChangeSet
#   2004/09/22 01:49:31-05:00 dtor_core@ameritech.net 
#   Input: add serio_[un]pin_driver() functions so attribute handlers
#          can safely access driver bound to a serio port.
#   
#   Signed-off-by: Dmitry Torokhov &lt;dtor@mail.ru&gt;
# 
# include/linux/serio.h
#   2004/09/22 01:49:13-05:00 dtor_core@ameritech.net +15 -1
#   Add drv_sem to serio structure and serio_[un]pin_driver() so attribute
#   handlers can safely access driver bound to a serio port
# 
# drivers/input/serio/serio.c
#   2004/09/22 01:49:13-05:00 dtor_core@ameritech.net +12 -8
#   Take drv_sem when binding/unbinding driver to a serio port
# 
# ChangeSet
#   2004/09/22 01:48:40-05:00 dtor_core@ameritech.net 
#   Input: pull common code from psmouse and atkbd into libps2 module
#   
#   Signed-off-by: Dmitry Torokhov &lt;dtor@mail.ru&gt;
# 
# include/linux/libps2.h
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +50 -0
#   BitKeeper file /misc/arc/dtor/include/linux/libps2.h
# 
# drivers/input/serio/Makefile
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +1 -0
#   Add libps2
# 
# drivers/input/serio/Kconfig
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +10 -0
#   Add libps2
# 
# drivers/input/mouse/synaptics.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +15 -13
#   Rename psmouse_coommand -&gt; ps2_command
# 
# drivers/input/mouse/psmouse.h
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +1 -15
#   Embed ps2dev into psmouse structure
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +52 -187
#   Switch to using libps2 to communicate with PS/2 port
# 
# drivers/input/mouse/logips2pp.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +23 -18
#   Rename psmouse_coommand -&gt; ps2_command
# 
# drivers/input/mouse/alps.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +38 -30
#   Rename psmouse_coommand -&gt; ps2_command
# 
# drivers/input/mouse/Kconfig
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +1 -0
#   Automatically select libps2 when selecting psmouse
# 
# include/linux/libps2.h
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +0 -0
#   BitKeeper file /usr/src/export/input/include/linux/libps2.h
# 
# drivers/input/serio/libps2.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +273 -0
#   BitKeeper file /misc/arc/dtor/drivers/input/serio/libps2.c
# 
# drivers/input/keyboard/atkbd.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +52 -238
#   Switch to using libps2 to communicate with PS/2 port
# 
# drivers/input/keyboard/Kconfig
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +1 -0
#   Automatically select libps2 when selecting atkbd
# 
# drivers/input/serio/libps2.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +0 -0
#   BitKeeper file /usr/src/export/input/drivers/input/serio/libps2.c
# 
# ChangeSet
#   2004/09/21 21:19:36-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# drivers/usb/input/hid-core.c
#   2004/09/21 21:19:32-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/keyboard.c
#   2004/09/21 21:19:32-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/21 21:18:33-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/serial/sunsu.c
#   2004/09/21 21:18:28-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/21 16:12:18+02:00 vojtech@suse.cz 
#   input: Add AT-compatible rawmode generation for ARM.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Woody Suwalski &lt;woodys@xandros.com&gt;
# 
# drivers/char/keyboard.c
#   2004/09/21 16:12:11+02:00 vojtech@suse.cz +4 -1
#   input: Add AT-compatible rawmode generation for ARM.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Woody Suwalski &lt;woodys@xandros.com&gt;
# 
# ChangeSet
#   2004/09/21 15:48:50+02:00 petero2@telia.com 
#   input: Add ALPS touchpad driver, driver by Neil Brown, Peter Osterlund
#          and Dmitry Torokhov, some fixes by Vojtech Pavlik.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Osterlund &lt;petero2@telia.com&gt;
# 
# drivers/input/mouse/alps.h
#   2004/09/21 15:48:43+02:00 petero2@telia.com +17 -0
# 
# drivers/input/mouse/alps.h
#   2004/09/21 15:48:43+02:00 petero2@telia.com +0 -0
#   BitKeeper file /data2/bk/input/drivers/input/mouse/alps.h
# 
# drivers/input/mouse/alps.c
#   2004/09/21 15:48:42+02:00 petero2@telia.com +422 -0
# 
# drivers/input/mousedev.c
#   2004/09/21 15:48:42+02:00 petero2@telia.com +10 -4
#   input: Add ALPS touchpad driver, driver by Neil Brown, Peter Osterlund
#          and Dmitry Torokhov, some fixes by Vojtech Pavlik.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Osterlund &lt;petero2@telia.com&gt;
# 
# drivers/input/mouse/psmouse.h
#   2004/09/21 15:48:42+02:00 petero2@telia.com +3 -0
#   input: Add ALPS touchpad driver, driver by Neil Brown, Peter Osterlund
#          and Dmitry Torokhov, some fixes by Vojtech Pavlik.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Osterlund &lt;petero2@telia.com&gt;
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/21 15:48:42+02:00 petero2@telia.com +22 -1
#   input: Add ALPS touchpad driver, driver by Neil Brown, Peter Osterlund
#          and Dmitry Torokhov, some fixes by Vojtech Pavlik.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Osterlund &lt;petero2@telia.com&gt;
# 
# drivers/input/mouse/alps.c
#   2004/09/21 15:48:42+02:00 petero2@telia.com +0 -0
#   BitKeeper file /data2/bk/input/drivers/input/mouse/alps.c
# 
# drivers/input/mouse/Makefile
#   2004/09/21 15:48:42+02:00 petero2@telia.com +1 -1
#   input: Add ALPS touchpad driver, driver by Neil Brown, Peter Osterlund
#          and Dmitry Torokhov, some fixes by Vojtech Pavlik.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Osterlund &lt;petero2@telia.com&gt;
# 
# ChangeSet
#   2004/09/21 15:27:54+02:00 pmaydell@chiark.greenend.org.uk 
#   input: Add support for Kensington ThinkingMouse PS/2 protocol.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Maydell &lt;pmaydell@chiark.greenend.org.uk&gt;
# 
# drivers/input/mouse/psmouse.h
#   2004/09/21 15:27:48+02:00 pmaydell@chiark.greenend.org.uk +11 -7
#   input: Add support for Kensington ThinkingMouse PS/2 protocol.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Maydell &lt;pmaydell@chiark.greenend.org.uk&gt;
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/21 15:27:48+02:00 pmaydell@chiark.greenend.org.uk +50 -5
#   input: Add support for Kensington ThinkingMouse PS/2 protocol.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Maydell &lt;pmaydell@chiark.greenend.org.uk&gt;
# 
# ChangeSet
#   2004/09/21 10:04:06+02:00 vojtech@suse.cz 
#   input: Some HID devices have problems returning the HID class descriptor.
#          Try a few times before giving up.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# drivers/usb/input/hid-core.c
#   2004/09/21 10:04:00+02:00 vojtech@suse.cz +8 -3
#   input: Some HID devices have problems returning the HID class descriptor.
#          Try a few times before giving up.
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
# 
# ChangeSet
#   2004/09/21 09:24:21+02:00 pnelson@suse.cz 
#   input: Fix oops in gamecon
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Nelson &lt;pnelson@andrew.cmu.edu&gt;
# 
# drivers/input/joystick/gamecon.c
#   2004/09/21 09:24:14+02:00 pnelson@suse.cz +3 -3
#   input: Fix oops in gamecon
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Peter Nelson &lt;pnelson@andrew.cmu.edu&gt;
# 
# ChangeSet
#   2004/09/19 21:58:28-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/input/serio/Kconfig
#   2004/09/19 21:58:24-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/19 13:46:50+02:00 olh@suse.de 
#   input: Joydump depends on gameport
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Olaf Hering &lt;olh@suse.de&gt;
# 
# drivers/input/joystick/Kconfig
#   2004/09/19 13:46:33+02:00 olh@suse.de +1 -1
#   input: Joydump depends on gameport
#   
#   Signed-off-by: Vojtech Pavlik &lt;vojtech@suse.cz&gt;
#   Patch-by: Olaf Hering &lt;olh@suse.de&gt;
# 
# ChangeSet
#   2004/09/17 13:30:06-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# Documentation/kernel-parameters.txt
#   2004/09/17 13:30:02-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/16 16:27:12-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# include/linux/hiddev.h
#   2004/09/16 16:27:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/compat_ioctl.c
#   2004/09/16 16:27:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hiddev.c
#   2004/09/16 16:27:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/serio/Kconfig
#   2004/09/16 16:27:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/Makefile
#   2004/09/16 16:27:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/09/16 16:27:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/09/16 16:27:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/08 12:29:01-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# include/linux/hiddev.h
#   2004/09/08 12:28:56-07:00 akpm@bix.(none) +0 -7
#   Auto merged
# 
# drivers/usb/input/hiddev.c
#   2004/09/08 12:28:56-07:00 akpm@bix.(none) +0 -6
#   Auto merged
# 
# drivers/Makefile
#   2004/09/08 12:28:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/07 21:06:53-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/09/07 21:06:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/09/07 21:06:47-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/03 14:23:28-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# MAINTAINERS
#   2004/09/03 14:23:24-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/31 14:02:33-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# MAINTAINERS
#   2004/08/31 14:02:26-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/28 16:27:11-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# MAINTAINERS
#   2004/08/28 16:27:07-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/27 23:57:20-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/input/serio/Kconfig
#   2004/08/27 23:57:14-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/27 23:57:14-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/27 13:41:40-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# MAINTAINERS
#   2004/08/27 13:41:36-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/08/27 13:41:36-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/25 19:45:04-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# MAINTAINERS
#   2004/08/25 19:44:59-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/25 14:17:06-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# include/linux/compat_ioctl.h
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-core.c
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/serio/gscps2.c
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/gameport/vortex.c
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/gameport/emu10k1-gp.c
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/Makefile
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/08/25 14:17:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/24 17:54:26-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/input/serio/gscps2.c
#   2004/08/24 17:54:22-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/24 17:54:22-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/08/24 17:54:22-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/23 16:53:47-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/usb/input/hid-core.c
#   2004/08/23 16:53:43-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/gameport/vortex.c
#   2004/08/23 16:53:43-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/gameport/emu10k1-gp.c
#   2004/08/23 16:53:43-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/Makefile
#   2004/08/23 16:53:43-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/23 16:53:42-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/23 14:14:32-07:00 akpm@bix.(none) 
#   Merge
# 
# MAINTAINERS
#   2004/08/23 14:14:28-07:00 akpm@bix.(none) +0 -0
#   SCCS merged
# 
# fs/compat_ioctl.c
#   2004/08/23 14:07:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-core.c
#   2004/08/23 14:07:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/Makefile
#   2004/08/23 14:07:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/i386/kernel/dmi_scan.c
#   2004/08/23 14:07:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/23 14:06:49-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# include/linux/compat_ioctl.h
#   2004/08/23 14:06:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/08/23 14:06:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/22 21:20:58-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# include/linux/compat_ioctl.h
#   2004/08/22 21:20:54-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/15 01:07:14-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# arch/i386/kernel/dmi_scan.c
#   2004/08/15 01:07:10-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/04 17:51:18-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/08/04 17:51:15-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/04 11:19:18-07:00 vojtech@kernel.bkbits.net 
#   Merge kernel.bkbits.net:/home/vojtech/linus
#   into kernel.bkbits.net:/home/vojtech/input
# 
# fs/compat_ioctl.c
#   2004/08/04 11:19:12-07:00 vojtech@kernel.bkbits.net +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/29 23:23:37-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/07/29 23:23:33-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hiddev.c
#   2004/07/29 23:23:33-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-core.c
#   2004/07/29 23:23:33-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/Makefile
#   2004/07/29 23:23:33-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/29 23:22:42-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/07/29 23:22:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/27 12:48:04-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# drivers/serial/sunsu.c
#   2004/07/27 12:48:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/keyboard/sunkbd.c
#   2004/07/27 12:48:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/joystick/analog.c
#   2004/07/27 12:48:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/26 22:48:28-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/serial/sunsu.c
#   2004/07/26 22:48:25-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/keyboard/sunkbd.c
#   2004/07/26 22:48:25-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/joystick/analog.c
#   2004/07/26 22:48:25-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/25 16:28:12-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/07/25 16:28:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-core.c
#   2004/07/25 16:28:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/Makefile
#   2004/07/25 16:28:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/16 18:31:00-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/usb/input/hid-core.c
#   2004/07/16 18:30:57-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/Makefile
#   2004/07/16 18:30:57-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/13 12:40:25-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/07/13 12:40:21-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/11 23:41:44-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/07/11 23:41:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hiddev.c
#   2004/07/11 23:41:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-tmff.c
#   2004/07/11 23:41:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/serio/i8042-io.h
#   2004/07/11 23:41:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/keyboard.c
#   2004/07/11 23:41:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/i386/kernel/dmi_scan.c
#   2004/07/11 23:41:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/07/11 23:41:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/11 13:33:39-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# arch/i386/kernel/dmi_scan.c
#   2004/07/11 13:33:36-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/07/11 13:33:36-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/08 14:24:00-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# include/linux/compat_ioctl.h
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/compat_ioctl.c
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hiddev.c
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-tmff.c
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/input/serio/i8042-io.h
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/keyboard.c
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/i386/kernel/dmi_scan.c
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/07/08 14:23:56-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/06 23:59:45-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# include/linux/compat_ioctl.h
#   2004/07/06 23:59:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/compat_ioctl.c
#   2004/07/06 23:59:41-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/05 13:01:11-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/usb/input/hiddev.c
#   2004/07/05 13:01:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/i386/kernel/dmi_scan.c
#   2004/07/05 13:01:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/07/05 13:01:08-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/30 11:25:44-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/vojtech/input
#   into bix.(none):/usr/src/bk-input
# 
# fs/compat_ioctl.c
#   2004/06/30 11:25:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/usb/input/hid-tmff.c
#   2004/06/30 11:25:40-07:00 akpm@bix.(none) +0 -1
#   Auto merged
# 
# drivers/input/serio/i8042-io.h
#   2004/06/30 11:25:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/char/keyboard.c
#   2004/06/30 11:25:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/char/keyboard.c	2004-09-23 21:12:57 -07:00
@@ -939,7 +939,10 @@
 	tasklet_enable(&amp;keyboard_tasklet);
 }
 
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
+    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) ||\
+    defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
+    (defined(CONFIG_ARM) &amp;&amp; defined(CONFIG_KEYBOARD_ATKBD) &amp;&amp; !defined(CONFIG_RPC))
 
 #define HW_RAW(dev) (test_bit(EV_MSC, dev-&gt;evbit) &amp;&amp; test_bit(MSC_RAW, dev-&gt;mscbit) &amp;&amp;\
 			((dev)-&gt;id.bustype == BUS_I8042) &amp;&amp; ((dev)-&gt;id.vendor == 0x0001) &amp;&amp; ((dev)-&gt;id.product == 0x0001))
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/input.c	2004-09-23 21:12:57 -07:00
@@ -67,9 +67,6 @@
 {
 	struct input_handle *handle;
 
-	if (dev-&gt;pm_dev)
-		pm_access(dev-&gt;pm_dev);
-
 	if (type &gt; EV_MAX || !test_bit(type, dev-&gt;evbit))
 		return;
 
@@ -230,8 +227,6 @@
 
 int input_open_device(struct input_handle *handle)
 {
-	if (handle-&gt;dev-&gt;pm_dev)
-		pm_access(handle-&gt;dev-&gt;pm_dev);
 	handle-&gt;open++;
 	if (handle-&gt;dev-&gt;open)
 		return handle-&gt;dev-&gt;open(handle-&gt;dev);
@@ -249,8 +244,6 @@
 void input_close_device(struct input_handle *handle)
 {
 	input_release_device(handle);
-	if (handle-&gt;dev-&gt;pm_dev)
-		pm_dev_idle(handle-&gt;dev-&gt;pm_dev);
 	if (handle-&gt;dev-&gt;close)
 		handle-&gt;dev-&gt;close(handle-&gt;dev);
 	handle-&gt;open--;
diff -Nru a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
--- a/drivers/input/joystick/Kconfig	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/joystick/Kconfig	2004-09-23 21:12:57 -07:00
@@ -249,7 +249,7 @@
 
 config JOYSTICK_JOYDUMP
 	tristate "Gameport data dumper"
-	depends on INPUT &amp;&amp; INPUT_JOYSTICK
+	depends on INPUT &amp;&amp; INPUT_JOYSTICK &amp;&amp; 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
diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
--- a/drivers/input/joystick/gamecon.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/joystick/gamecon.c	2004-09-23 21:12:57 -07:00
@@ -89,7 +89,7 @@
 static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
 
 static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
-				"Multisystem 2-button joystick", "N64 controller", "PSX controller"
+				"Multisystem 2-button joystick", "N64 controller", "PSX controller",
 				"PSX DDR controller" };
 /*
  * N64 support.
@@ -271,7 +271,7 @@
 		udelay(gc_psx_delay);
 		read = parport_read_status(gc-&gt;pd-&gt;port) ^ 0x80;
 		for (j = 0; j &lt; 5; j++)
-			data[j] |= (read &amp; gc_status_bit[j] &amp; gc-&gt;pads[GC_PSX]) ? (1 &lt;&lt; i) : 0;
+			data[j] |= (read &amp; gc_status_bit[j] &amp; (gc-&gt;pads[GC_PSX] | gc-&gt;pads[GC_DDR])) ? (1 &lt;&lt; i) : 0;
 		parport_write_data(gc-&gt;pd-&gt;port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
 		udelay(gc_psx_delay);
 	}
@@ -300,7 +300,7 @@
 	gc_psx_command(gc, 0, data2);							/* Dump status */
 
 	for (i =0; i &lt; 5; i++)								/* Find the longest pad */
-		if((gc_status_bit[i] &amp; gc-&gt;pads[GC_PSX]) &amp;&amp; (GC_PSX_LEN(id[i]) &gt; max_len))
+		if((gc_status_bit[i] &amp; (gc-&gt;pads[GC_PSX] | gc-&gt;pads[GC_DDR])) &amp;&amp; (GC_PSX_LEN(id[i]) &gt; max_len))
 			max_len = GC_PSX_LEN(id[i]);
 
 	for (i = 0; i &lt; max_len * 2; i++) {						/* Read in all the data */
diff -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
--- a/drivers/input/keyboard/Kconfig	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/keyboard/Kconfig	2004-09-23 21:12:57 -07:00
@@ -16,6 +16,7 @@
 	default y
 	depends on INPUT &amp;&amp; INPUT_KEYBOARD
 	select SERIO
+	select SERIO_LIBPS2
 	select SERIO_I8042 if PC
 	select SERIO_GSCPS2 if GSC
 	help
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/keyboard/atkbd.c	2004-09-23 21:12:57 -07:00
@@ -26,6 +26,7 @@
 #include &lt;linux/input.h&gt;
 #include &lt;linux/serio.h&gt;
 #include &lt;linux/workqueue.h&gt;
+#include &lt;linux/libps2.h&gt;
 
 #define DRIVER_DESC	"AT and PS/2 keyboard driver"
 
@@ -170,36 +171,29 @@
 	{ ATKBD_SCR_CLICK, 0x60 },
 };
 
-#define ATKBD_FLAG_ACK		0	/* Waiting for ACK/NAK */
-#define ATKBD_FLAG_CMD		1	/* Waiting for command to finish */
-#define ATKBD_FLAG_CMD1		2	/* First byte of command response */
-#define ATKBD_FLAG_ENABLED	3	/* Waining for init to finish */
-
 /*
  * The atkbd control structure
  */
 
 struct atkbd {
 
+	struct ps2dev	ps2dev;
+
 	/* Written only during init */
 	char name[64];
 	char phys[32];
-	struct serio *serio;
 	struct input_dev dev;
 
-	unsigned char set;
 	unsigned short id;
 	unsigned char keycode[512];
+	unsigned char set;
 	unsigned char translated;
 	unsigned char extra;
 	unsigned char write;
-
-	/* Protected by FLAG_ACK */
-	unsigned char nak;
-
-	/* Protected by FLAG_CMD */
-	unsigned char cmdbuf[4];
-	unsigned char cmdcnt;
+	unsigned char softrepeat;
+	unsigned char softraw;
+	unsigned char scroll;
+	unsigned char enabled;
 
 	/* Accessed only from interrupt */
 	unsigned char emul;
@@ -208,24 +202,31 @@
 	unsigned char bat_xl;
 	unsigned int last;
 	unsigned long time;
-
-	/* Ensures that only one command is executing at a time */
-	struct semaphore cmd_sem;
-
-	/* Used to signal completion from interrupt handler */
-	wait_queue_head_t wait;
-
-	/* Flags */
-	unsigned long flags;
 };
 
-/* Work structure to schedule execution of a command */
-struct atkbd_work {
-	struct work_struct work;
-	struct atkbd *atkbd;
-	int command;
-	unsigned char param[0];
-};
+static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
+				ssize_t (*handler)(struct atkbd *, char *));
+static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
+				int (*handler)(struct atkbd *, const char *, size_t));
+#define ATKBD_DEFINE_ATTR(_name)						\
+static ssize_t atkbd_show_##_name(struct atkbd *, char *);			\
+static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t);		\
+static ssize_t atkbd_do_show_##_name(struct device *d, char *b)			\
+{										\
+	return atkbd_attr_show_helper(d, b, atkbd_show_##_name);		\
+}										\
+static ssize_t atkbd_do_set_##_name(struct device *d, const char *b, size_t s)	\
+{										\
+	return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name);		\
+}										\
+static struct device_attribute atkbd_attr_##_name = 				\
+	__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
+
+ATKBD_DEFINE_ATTR(extra);
+ATKBD_DEFINE_ATTR(scroll);
+ATKBD_DEFINE_ATTR(set);
+ATKBD_DEFINE_ATTR(softrepeat);
+ATKBD_DEFINE_ATTR(softraw);
 
 
 static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
@@ -268,42 +269,15 @@
 		atkbd-&gt;resend = 0;
 #endif
 
-	if (test_bit(ATKBD_FLAG_ACK, &amp;atkbd-&gt;flags)) {
-		switch (code) {
-			case ATKBD_RET_ACK:
-				atkbd-&gt;nak = 0;
-				if (atkbd-&gt;cmdcnt) {
-					set_bit(ATKBD_FLAG_CMD, &amp;atkbd-&gt;flags);
-					set_bit(ATKBD_FLAG_CMD1, &amp;atkbd-&gt;flags);
-				}
-				clear_bit(ATKBD_FLAG_ACK, &amp;atkbd-&gt;flags);
-				wake_up_interruptible(&amp;atkbd-&gt;wait);
-				break;
-			case ATKBD_RET_NAK:
-				atkbd-&gt;nak = 1;
-				clear_bit(ATKBD_FLAG_ACK, &amp;atkbd-&gt;flags);
-				wake_up_interruptible(&amp;atkbd-&gt;wait);
-				break;
-		}
-		goto out;
-	}
-
-	if (test_bit(ATKBD_FLAG_CMD, &amp;atkbd-&gt;flags)) {
-
-		if (atkbd-&gt;cmdcnt)
-			atkbd-&gt;cmdbuf[--atkbd-&gt;cmdcnt] = code;
-
-		if (test_and_clear_bit(ATKBD_FLAG_CMD1, &amp;atkbd-&gt;flags) &amp;&amp; atkbd-&gt;cmdcnt)
-			wake_up_interruptible(&amp;atkbd-&gt;wait);
+	if (unlikely(atkbd-&gt;ps2dev.flags &amp; PS2_FLAG_ACK))
+		if  (ps2_handle_ack(&amp;atkbd-&gt;ps2dev, data))
+			goto out;
 
-		if (!atkbd-&gt;cmdcnt) {
-			clear_bit(ATKBD_FLAG_CMD, &amp;atkbd-&gt;flags);
-			wake_up_interruptible(&amp;atkbd-&gt;wait);
-		}
-		goto out;
-	}
+	if (unlikely(atkbd-&gt;ps2dev.flags &amp; PS2_FLAG_CMD))
+		if  (ps2_handle_response(&amp;atkbd-&gt;ps2dev, data))
+			goto out;
 
-	if (!test_bit(ATKBD_FLAG_ENABLED, &amp;atkbd-&gt;flags))
+	if (!atkbd-&gt;enabled)
 		goto out;
 
 	input_event(&amp;atkbd-&gt;dev, EV_MSC, MSC_RAW, code);
@@ -326,8 +300,8 @@
 
 	switch (code) {
 		case ATKBD_RET_BAT:
-			clear_bit(ATKBD_FLAG_ENABLED, &amp;atkbd-&gt;flags);
-			serio_rescan(atkbd-&gt;serio);
+			atkbd-&gt;enabled = 0;
+			serio_rescan(atkbd-&gt;ps2dev.serio);
 			goto out;
 		case ATKBD_RET_EMUL0:
 			atkbd-&gt;emul = 1;
@@ -396,7 +370,7 @@
 			break;
 		default:
 			value = atkbd-&gt;release ? 0 :
-				(1 + (!atkbd_softrepeat &amp;&amp; test_bit(atkbd-&gt;keycode[code], atkbd-&gt;dev.key)));
+				(1 + (!atkbd-&gt;softrepeat &amp;&amp; test_bit(atkbd-&gt;keycode[code], atkbd-&gt;dev.key)));
 
 			switch (value) { 	/* Workaround Toshiba laptop multiple keypress */
 				case 0:
@@ -427,151 +401,6 @@
 	return IRQ_HANDLED;
 }
 
-/*
- * atkbd_sendbyte() sends a byte to the keyboard, and waits for
- * acknowledge. It doesn't handle resends according to the keyboard
- * protocol specs, because if these are needed, the keyboard needs
- * replacement anyway, and they only make a mess in the protocol.
- *
- * atkbd_sendbyte() can only be called from a process context
- */
-
-static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
-{
-#ifdef ATKBD_DEBUG
-	printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
-#endif
-	atkbd-&gt;nak = 1;
-	set_bit(ATKBD_FLAG_ACK, &amp;atkbd-&gt;flags);
-
-	if (serio_write(atkbd-&gt;serio, byte) == 0)
-		wait_event_interruptible_timeout(atkbd-&gt;wait,
-				!test_bit(ATKBD_FLAG_ACK, &amp;atkbd-&gt;flags),
-				msecs_to_jiffies(200));
-
-	clear_bit(ATKBD_FLAG_ACK, &amp;atkbd-&gt;flags);
-	return -atkbd-&gt;nak;
-}
-
-/*
- * atkbd_command() sends a command, and its parameters to the keyboard,
- * then waits for the response and puts it in the param array.
- *
- * atkbd_command() can only be called from a process context
- */
-
-static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
-{
-	int timeout;
-	int send = (command &gt;&gt; 12) &amp; 0xf;
-	int receive = (command &gt;&gt; 8) &amp; 0xf;
-	int rc = -1;
-	int i;
-
-	timeout = msecs_to_jiffies(command == ATKBD_CMD_RESET_BAT ? 4000 : 500);
-
-	down(&amp;atkbd-&gt;cmd_sem);
-	clear_bit(ATKBD_FLAG_CMD, &amp;atkbd-&gt;flags);
-
-	if (receive &amp;&amp; param)
-		for (i = 0; i &lt; receive; i++)
-			atkbd-&gt;cmdbuf[(receive - 1) - i] = param[i];
-
-	atkbd-&gt;cmdcnt = receive;
-
-	if (command &amp; 0xff)
-		if (atkbd_sendbyte(atkbd, command &amp; 0xff))
-			goto out;
-
-	for (i = 0; i &lt; send; i++)
-		if (atkbd_sendbyte(atkbd, param[i]))
-			goto out;
-
-	timeout = wait_event_interruptible_timeout(atkbd-&gt;wait,
-				!test_bit(ATKBD_FLAG_CMD1, &amp;atkbd-&gt;flags), timeout);
-
-	if (atkbd-&gt;cmdcnt &amp;&amp; timeout &gt; 0) {
-		if (command == ATKBD_CMD_RESET_BAT &amp;&amp; jiffies_to_msecs(timeout) &gt; 100)
-			timeout = msecs_to_jiffies(100);
-
-		if (command == ATKBD_CMD_GETID &amp;&amp;
-		    atkbd-&gt;cmdbuf[receive - 1] != 0xab &amp;&amp; atkbd-&gt;cmdbuf[receive - 1] != 0xac) {
-			/*
-			 * Device behind the port is not a keyboard
-			 * so we don't need to wait for the 2nd byte
-			 * of ID response.
-			 */
-			clear_bit(ATKBD_FLAG_CMD, &amp;atkbd-&gt;flags);
-			atkbd-&gt;cmdcnt = 0;
-		}
-
-		wait_event_interruptible_timeout(atkbd-&gt;wait,
-				!test_bit(ATKBD_FLAG_CMD, &amp;atkbd-&gt;flags), timeout);
-	}
-
-	if (param)
-		for (i = 0; i &lt; receive; i++)
-			param[i] = atkbd-&gt;cmdbuf[(receive - 1) - i];
-
-	if (atkbd-&gt;cmdcnt &amp;&amp; (command != ATKBD_CMD_RESET_BAT || atkbd-&gt;cmdcnt != 1))
-		goto out;
-
-	rc = 0;
-
-out:
-	clear_bit(ATKBD_FLAG_CMD, &amp;atkbd-&gt;flags);
-	clear_bit(ATKBD_FLAG_CMD1, &amp;atkbd-&gt;flags);
-	up(&amp;atkbd-&gt;cmd_sem);
-
-	return rc;
-}
-
-/*
- * atkbd_execute_scheduled_command() sends a command, previously scheduled by
- * atkbd_schedule_command(), to the keyboard.
- */
-
-static void atkbd_execute_scheduled_command(void *data)
-{
-	struct atkbd_work *atkbd_work = data;
-
-	atkbd_command(atkbd_work-&gt;atkbd, atkbd_work-&gt;param, atkbd_work-&gt;command);
-
-	kfree(atkbd_work);
-}
-
-/*
- * atkbd_schedule_command() allows to schedule delayed execution of a keyboard
- * command and can be used to issue a command from an interrupt or softirq
- * context.
- */
-
-static int atkbd_schedule_command(struct atkbd *atkbd, unsigned char *param, int command)
-{
-	struct atkbd_work *atkbd_work;
-	int send = (command &gt;&gt; 12) &amp; 0xf;
-	int receive = (command &gt;&gt; 8) &amp; 0xf;
-
-	if (!test_bit(ATKBD_FLAG_ENABLED, &amp;atkbd-&gt;flags))
-		return -1;
-
-	if (!(atkbd_work = kmalloc(sizeof(struct atkbd_work) + max(send, receive), GFP_ATOMIC)))
-		return -1;
-
-	memset(atkbd_work, 0, sizeof(struct atkbd_work));
-	atkbd_work-&gt;atkbd = atkbd;
-	atkbd_work-&gt;command = command;
-	memcpy(atkbd_work-&gt;param, param, send);
-	INIT_WORK(&amp;atkbd_work-&gt;work, atkbd_execute_scheduled_command, atkbd_work);
-
-	if (!schedule_work(&amp;atkbd_work-&gt;work)) {
-		kfree(atkbd_work);
-		return -1;
-	}
-
-	return 0;
-}
-
 
 /*
  * Event callback from the input module. Events that change the state of
@@ -599,7 +428,7 @@
 			param[0] = (test_bit(LED_SCROLLL, dev-&gt;led) ? 1 : 0)
 			         | (test_bit(LED_NUML,    dev-&gt;led) ? 2 : 0)
 			         | (test_bit(LED_CAPSL,   dev-&gt;led) ? 4 : 0);
-		        atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETLEDS);
+		        ps2_schedule_command(&amp;atkbd-&gt;ps2dev, param, ATKBD_CMD_SETLEDS);
 
 			if (atkbd-&gt;extra) {
 				param[0] = 0;
@@ -608,7 +437,7 @@
 					 | (test_bit(LED_SUSPEND, dev-&gt;led) ? 0x04 : 0)
 				         | (test_bit(LED_MISC,    dev-&gt;led) ? 0x10 : 0)
 				         | (test_bit(LED_MUTE,    dev-&gt;led) ? 0x20 : 0);
-				atkbd_schedule_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
+				ps2_schedule_command(&amp;atkbd-&gt;ps2dev, param, ATKBD_CMD_EX_SETLEDS);
 			}
 
 			return 0;
@@ -616,7 +445,7 @@
 
 		case EV_REP:
 
-			if (atkbd_softrepeat) return 0;
+			if (atkbd-&gt;softrepeat) return 0;
 
 			i = j = 0;
 			while (i &lt; 32 &amp;&amp; period[i] &lt; dev-&gt;rep[REP_PERIOD]) i++;
@@ -624,7 +453,7 @@
 			dev-&gt;rep[REP_PERIOD] = period[i];
 			dev-&gt;rep[REP_DELAY] = delay[j];
 			param[0] = i | (j &lt;&lt; 5);
-			atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETREP);
+			ps2_schedule_command(&amp;atkbd-&gt;ps2dev, param, ATKBD_CMD_SETREP);
 
 			return 0;
 	}
@@ -633,11 +462,36 @@
 }
 
 /*
+ * atkbd_enable() signals that interrupt handler is allowed to
+ * generate input events.
+ */
+
+static inline void atkbd_enable(struct atkbd *atkbd)
+{
+	serio_pause_rx(atkbd-&gt;ps2dev.serio);
+	atkbd-&gt;enabled = 1;
+	serio_continue_rx(atkbd-&gt;ps2dev.serio);
+}
+
+/*
+ * atkbd_disable() tells input handler that all incoming data except
+ * for ACKs and command response should be dropped.
+ */
+
+static inline void atkbd_disable(struct atkbd *atkbd)
+{
+	serio_pause_rx(atkbd-&gt;ps2dev.serio);
+	atkbd-&gt;enabled = 0;
+	serio_continue_rx(atkbd-&gt;ps2dev.serio);
+}
+
+/*
  * atkbd_probe() probes for an AT keyboard on a serio port.
  */
 
 static int atkbd_probe(struct atkbd *atkbd)
 {
+	struct ps2dev *ps2dev = &amp;atkbd-&gt;ps2dev;
 	unsigned char param[2];
 
 /*
@@ -647,8 +501,8 @@
  */
 
 	if (atkbd_reset)
-		if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
-			printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd-&gt;serio-&gt;phys);
+		if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
+			printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev-&gt;serio-&gt;phys);
 
 /*
  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
@@ -658,7 +512,7 @@
  */
 
 	param[0] = param[1] = 0xa5;	/* initialize with invalid values */
-	if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
+	if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
 
 /*
  * If the get ID command failed, we check if we can at least set the LEDs on
@@ -666,7 +520,7 @@
  * the LEDs off, which we want anyway.
  */
 		param[0] = 0;
-		if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
 			return -1;
 		atkbd-&gt;id = 0xabba;
 		return 0;
@@ -686,15 +540,17 @@
 }
 
 /*
- * atkbd_set_3 checks if a keyboard has a working Set 3 support, and
+ * atkbd_select_set checks if a keyboard has a working Set 3 support, and
  * sets it into that. Unfortunately there are keyboards that can be switched
  * to Set 3, but don't work well in that (BTC Multimedia ...)
  */
 
-static int atkbd_set_3(struct atkbd *atkbd)
+static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
 {
+	struct ps2dev *ps2dev = &amp;atkbd-&gt;ps2dev;
 	unsigned char param[2];
 
+	atkbd-&gt;extra = 0;
 /*
  * For known special keyboards we can go ahead and set the correct set.
  * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
@@ -706,47 +562,48 @@
 
 	if (atkbd-&gt;id == 0xaca1) {
 		param[0] = 3;
-		atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET);
+		ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
 		return 3;
 	}
 
-	if (atkbd_extra) {
+	if (allow_extra) {
 		param[0] = 0x71;
-		if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) {
+		if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
 			atkbd-&gt;extra = 1;
 			return 2;
 		}
 	}
 
-	if (atkbd_set != 3)
+	if (target_set != 3)
 		return 2;
 
-	if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
+	if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
 		atkbd-&gt;id = param[0] &lt;&lt; 8 | param[1];
 		return 2;
 	}
 
 	param[0] = 3;
-	if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
+	if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
 		return 2;
 
 	param[0] = 0;
-	if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET))
+	if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
 		return 2;
 
 	if (param[0] != 3) {
 		param[0] = 2;
-		if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
+		if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
 		return 2;
 	}
 
-	atkbd_command(atkbd, param, ATKBD_CMD_SETALL_MBR);
+	ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
 
 	return 3;
 }
 
-static int atkbd_enable(struct atkbd *atkbd)
+static int atkbd_activate(struct atkbd *atkbd)
 {
+	struct ps2dev *ps2dev = &amp;atkbd-&gt;ps2dev;
 	unsigned char param[1];
 
 /*
@@ -754,7 +611,7 @@
  */
 
 	param[0] = 0;
-	if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
 		return -1;
 
 /*
@@ -762,16 +619,16 @@
  */
 
 	param[0] = 0;
-	if (atkbd_command(atkbd, param, ATKBD_CMD_SETREP))
+	if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
 		return -1;
 
 /*
  * Enable the keyboard to receive keystrokes.
  */
 
-	if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) {
+	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
 		printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
-			atkbd-&gt;serio-&gt;phys);
+			ps2dev-&gt;serio-&gt;phys);
 		return -1;
 	}
 
@@ -786,9 +643,10 @@
 static void atkbd_cleanup(struct serio *serio)
 {
 	struct atkbd *atkbd = serio-&gt;private;
-	atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT);
+	ps2_command(&amp;atkbd-&gt;ps2dev, NULL, ATKBD_CMD_RESET_BAT);
 }
 
+
 /*
  * atkbd_disconnect() closes and frees.
  */
@@ -797,15 +655,108 @@
 {
 	struct atkbd *atkbd = serio-&gt;private;
 
-	clear_bit(ATKBD_FLAG_ENABLED, &amp;atkbd-&gt;flags);
+	atkbd_disable(atkbd);
+
+	/* make sure we don't have a command in flight */
 	synchronize_kernel();
 	flush_scheduled_work();
 
+	device_remove_file(&amp;serio-&gt;dev, &amp;atkbd_attr_extra);
+	device_remove_file(&amp;serio-&gt;dev, &amp;atkbd_attr_scroll);
+	device_remove_file(&amp;serio-&gt;dev, &amp;atkbd_attr_set);
+	device_remove_file(&amp;serio-&gt;dev, &amp;atkbd_attr_softrepeat);
+	device_remove_file(&amp;serio-&gt;dev, &amp;atkbd_attr_softraw);
+
 	input_unregister_device(&amp;atkbd-&gt;dev);
 	serio_close(serio);
 	kfree(atkbd);
 }
 
+
+/*
+ * atkbd_set_device_attrs() initializes keyboard's keycode table
+ * according to the selected scancode set
+ */
+
+static void atkbd_set_keycode_table(struct atkbd *atkbd)
+{
+	int i, j;
+
+	memset(atkbd-&gt;keycode, 0, sizeof(atkbd-&gt;keycode));
+
+	if (atkbd-&gt;translated) {
+		for (i = 0; i &lt; 128; i++) {
+			atkbd-&gt;keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
+			atkbd-&gt;keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+			if (atkbd-&gt;scroll)
+				for (j = 0; i &lt; 5; i++) {
+					if (atkbd_unxlate_table[i] == atkbd_scroll_keys[j][1])
+						atkbd-&gt;keycode[i] = atkbd_scroll_keys[j][0];
+					if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j][1])
+						atkbd-&gt;keycode[i | 0x80] = atkbd_scroll_keys[j][0];
+				}
+		}
+	} else if (atkbd-&gt;set == 3) {
+		memcpy(atkbd-&gt;keycode, atkbd_set3_keycode, sizeof(atkbd-&gt;keycode));
+	} else {
+		memcpy(atkbd-&gt;keycode, atkbd_set2_keycode, sizeof(atkbd-&gt;keycode));
+
+		if (atkbd-&gt;scroll)
+			for (i = 0; i &lt; 5; i++)
+				atkbd-&gt;keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
+	}
+}
+
+/*
+ * atkbd_set_device_attrs() sets up keyboard's input device structure
+ */
+
+static void atkbd_set_device_attrs(struct atkbd *atkbd)
+{
+	int i;
+
+	memset(&amp;atkbd-&gt;dev, 0, sizeof(struct input_dev));
+
+	init_input_dev(&amp;atkbd-&gt;dev);
+
+	atkbd-&gt;dev.name = atkbd-&gt;name;
+	atkbd-&gt;dev.phys = atkbd-&gt;phys;
+	atkbd-&gt;dev.id.bustype = BUS_I8042;
+	atkbd-&gt;dev.id.vendor = 0x0001;
+	atkbd-&gt;dev.id.product = atkbd-&gt;translated ? 1 : atkbd-&gt;set;
+	atkbd-&gt;dev.id.version = atkbd-&gt;id;
+	atkbd-&gt;dev.event = atkbd_event;
+	atkbd-&gt;dev.private = atkbd;
+
+	atkbd-&gt;dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
+
+	if (atkbd-&gt;write) {
+		atkbd-&gt;dev.evbit[0] |= BIT(EV_LED);
+		atkbd-&gt;dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	}
+
+	if (atkbd-&gt;extra)
+		atkbd-&gt;dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) |
+					BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
+
+	if (!atkbd-&gt;softrepeat) {
+		atkbd-&gt;dev.rep[REP_DELAY] = 250;
+		atkbd-&gt;dev.rep[REP_PERIOD] = 33;
+	}
+
+	atkbd-&gt;dev.mscbit[0] = atkbd-&gt;softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
+
+	if (atkbd-&gt;scroll) {
+		atkbd-&gt;dev.evbit[0] |= BIT(EV_REL);
+		atkbd-&gt;dev.relbit[0] = BIT(REL_WHEEL);
+		set_bit(BTN_MIDDLE, atkbd-&gt;dev.keybit);
+	}
+
+	for (i = 0; i &lt; 512; i++)
+		if (atkbd-&gt;keycode[i] &amp;&amp; atkbd-&gt;keycode[i] &lt; ATKBD_SPECIAL)
+			set_bit(atkbd-&gt;keycode[i], atkbd-&gt;dev.keybit);
+}
+
 /*
  * atkbd_connect() is called when the serio module finds and interface
  * that isn't handled yet by an appropriate device driver. We check if
@@ -816,14 +767,12 @@
 static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
 {
 	struct atkbd *atkbd;
-	int i;
 
 	if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
 		return;
 	memset(atkbd, 0, sizeof(struct atkbd));
 
-	init_MUTEX(&amp;atkbd-&gt;cmd_sem);
-	init_waitqueue_head(&amp;atkbd-&gt;wait);
+	ps2_init(&amp;atkbd-&gt;ps2dev, serio);
 
 	switch (serio-&gt;type &amp; SERIO_TYPE) {
 
@@ -841,31 +790,19 @@
 			return;
 	}
 
-	if (!atkbd-&gt;write)
-		atkbd_softrepeat = 1;
-	if (atkbd_softrepeat)
-		atkbd_softraw = 1;
-
-	if (atkbd-&gt;write) {
-		atkbd-&gt;dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC);
-		atkbd-&gt;dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	} else  atkbd-&gt;dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
-	atkbd-&gt;dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
+	atkbd-&gt;softraw = atkbd_softraw;
+	atkbd-&gt;softrepeat = atkbd_softrepeat;
+	atkbd-&gt;scroll = atkbd_scroll;
 
-	if (!atkbd_softrepeat) {
-		atkbd-&gt;dev.rep[REP_DELAY] = 250;
-		atkbd-&gt;dev.rep[REP_PERIOD] = 33;
-	} else atkbd_softraw = 1;
-
-	atkbd-&gt;serio = serio;
+	if (!atkbd-&gt;write)
+		atkbd-&gt;softrepeat = 1;
 
-	init_input_dev(&amp;atkbd-&gt;dev);
+	if (atkbd-&gt;softrepeat)
+		atkbd-&gt;softraw = 1;
 
 	atkbd-&gt;dev.keycode = atkbd-&gt;keycode;
 	atkbd-&gt;dev.keycodesize = sizeof(unsigned char);
 	atkbd-&gt;dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
-	atkbd-&gt;dev.event = atkbd_event;
-	atkbd-&gt;dev.private = atkbd;
 
 	serio-&gt;private = atkbd;
 
@@ -883,56 +820,34 @@
 			return;
 		}
 
-		atkbd-&gt;set = atkbd_set_3(atkbd);
-		atkbd_enable(atkbd);
+		atkbd-&gt;set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
+		atkbd_activate(atkbd);
 
 	} else {
 		atkbd-&gt;set = 2;
 		atkbd-&gt;id = 0xab00;
 	}
 
-	if (atkbd-&gt;extra) {
-		atkbd-&gt;dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
+	if (atkbd-&gt;extra)
 		sprintf(atkbd-&gt;name, "AT Set 2 Extra keyboard");
-	} else
+	else
 		sprintf(atkbd-&gt;name, "AT %s Set %d keyboard",
 			atkbd-&gt;translated ? "Translated" : "Raw", atkbd-&gt;set);
 
 	sprintf(atkbd-&gt;phys, "%s/input0", serio-&gt;phys);
 
-	if (atkbd_scroll) {
-		for (i = 0; i &lt; 5; i++)
-			atkbd_set2_keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
-		atkbd-&gt;dev.evbit[0] |= BIT(EV_REL);
-		atkbd-&gt;dev.relbit[0] = BIT(REL_WHEEL);
-		set_bit(BTN_MIDDLE, atkbd-&gt;dev.keybit);
-	}
-
-	if (atkbd-&gt;translated) {
-		for (i = 0; i &lt; 128; i++) {
-			atkbd-&gt;keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
-			atkbd-&gt;keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
-		}
-	} else if (atkbd-&gt;set == 3) {
-		memcpy(atkbd-&gt;keycode, atkbd_set3_keycode, sizeof(atkbd-&gt;keycode));
-	} else {
-		memcpy(atkbd-&gt;keycode, atkbd_set2_keycode, sizeof(atkbd-&gt;keycode));
-	}
-
-	atkbd-&gt;dev.name = atkbd-&gt;name;
-	atkbd-&gt;dev.phys = atkbd-&gt;phys;
-	atkbd-&gt;dev.id.bustype = BUS_I8042;
-	atkbd-&gt;dev.id.vendor = 0x0001;
-	atkbd-&gt;dev.id.product = atkbd-&gt;translated ? 1 : atkbd-&gt;set;
-	atkbd-&gt;dev.id.version = atkbd-&gt;id;
-
-	for (i = 0; i &lt; 512; i++)
-		if (atkbd-&gt;keycode[i] &amp;&amp; atkbd-&gt;keycode[i] &lt; ATKBD_SPECIAL)
-			set_bit(atkbd-&gt;keycode[i], atkbd-&gt;dev.keybit);
+	atkbd_set_keycode_table(atkbd);
+	atkbd_set_device_attrs(atkbd);
 
 	input_register_device(&amp;atkbd-&gt;dev);
 
-	set_bit(ATKBD_FLAG_ENABLED, &amp;atkbd-&gt;flags);
+	device_create_file(&amp;serio-&gt;dev, &amp;atkbd_attr_extra);
+	device_create_file(&amp;serio-&gt;dev, &amp;atkbd_attr_scroll);
+	device_create_file(&amp;serio-&gt;dev, &amp;atkbd_attr_set);
+	device_create_file(&amp;serio-&gt;dev, &amp;atkbd_attr_softrepeat);
+	device_create_file(&amp;serio-&gt;dev, &amp;atkbd_attr_softraw);
+
+	atkbd_enable(atkbd);
 
 	printk(KERN_INFO "input: %s on %s\n", atkbd-&gt;name, serio-&gt;phys);
 }
@@ -948,11 +863,13 @@
 	struct serio_driver *drv = serio-&gt;drv;
 	unsigned char param[1];
 
-	if (!drv) {
+	if (!atkbd || !drv) {
 		printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
 		return -1;
 	}
 
+	atkbd_disable(atkbd);
+
 	if (atkbd-&gt;write) {
 		param[0] = (test_bit(LED_SCROLLL, atkbd-&gt;dev.led) ? 1 : 0)
 		         | (test_bit(LED_NUML,    atkbd-&gt;dev.led) ? 2 : 0)
@@ -960,16 +877,16 @@
 
 		if (atkbd_probe(atkbd))
 			return -1;
-		if (atkbd-&gt;set != atkbd_set_3(atkbd))
+		if (atkbd-&gt;set != atkbd_select_set(atkbd, atkbd-&gt;set, atkbd-&gt;extra))
 			return -1;
 
-		atkbd_enable(atkbd);
+		atkbd_activate(atkbd);
 
-		if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+		if (ps2_command(&amp;atkbd-&gt;ps2dev, param, ATKBD_CMD_SETLEDS))
 			return -1;
 	}
 
-	set_bit(ATKBD_FLAG_ENABLED, &amp;atkbd-&gt;flags);
+	atkbd_enable(atkbd);
 
 	return 0;
 }
@@ -985,6 +902,192 @@
 	.disconnect	= atkbd_disconnect,
 	.cleanup	= atkbd_cleanup,
 };
+
+static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
+				ssize_t (*handler)(struct atkbd *, char *))
+{
+	struct serio *serio = to_serio_port(dev);
+	int retval;
+
+	retval = serio_pin_driver(serio);
+	if (retval)
+		return retval;
+
+	if (serio-&gt;drv != &amp;atkbd_drv) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	retval = handler((struct atkbd *)serio-&gt;private, buf);
+
+out:
+	serio_unpin_driver(serio);
+	return retval;
+}
+
+static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
+				int (*handler)(struct atkbd *, const char *, size_t))
+{
+	struct serio *serio = to_serio_port(dev);
+	struct atkbd *atkbd;
+	int retval;
+
+	retval = serio_pin_driver(serio);
+	if (retval)
+		return retval;
+
+	if (serio-&gt;drv != &amp;atkbd_drv) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	atkbd = serio-&gt;private;
+	atkbd_disable(atkbd);
+	retval = handler(atkbd, buf, count);
+	atkbd_enable(atkbd);
+
+out:
+	serio_unpin_driver(serio);
+	return retval;
+}
+
+static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd-&gt;extra ? 1 : 0);
+}
+
+static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	if (!atkbd-&gt;write)
+		return -EIO;
+
+	value = simple_strtoul(buf, &amp;rest, 10);
+	if (*rest || value &gt; 1)
+		return -EINVAL;
+
+	if (atkbd-&gt;extra != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&amp;atkbd-&gt;dev);
+		atkbd-&gt;set = atkbd_select_set(atkbd, atkbd-&gt;set, value);
+		atkbd_activate(atkbd);
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&amp;atkbd-&gt;dev);
+	}
+	return count;
+}
+
+static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd-&gt;scroll ? 1 : 0);
+}
+
+static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	value = simple_strtoul(buf, &amp;rest, 10);
+	if (*rest || value &gt; 1)
+		return -EINVAL;
+
+	if (atkbd-&gt;scroll != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&amp;atkbd-&gt;dev);
+		atkbd-&gt;scroll = value;
+		atkbd_set_keycode_table(atkbd);
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&amp;atkbd-&gt;dev);
+	}
+	return count;
+}
+
+static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd-&gt;set);
+}
+
+static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	if (!atkbd-&gt;write)
+		return -EIO;
+
+	value = simple_strtoul(buf, &amp;rest, 10);
+	if (*rest || (value != 2 &amp;&amp; value != 3))
+		return -EINVAL;
+
+	if (atkbd-&gt;set != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&amp;atkbd-&gt;dev);
+		atkbd-&gt;set = atkbd_select_set(atkbd, value, atkbd-&gt;extra);
+		atkbd_activate(atkbd);
+		atkbd_set_keycode_table(atkbd);
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&amp;atkbd-&gt;dev);
+	}
+	return count;
+}
+
+static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd-&gt;softrepeat ? 1 : 0);
+}
+
+static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	if (!atkbd-&gt;write)
+		return -EIO;
+
+	value = simple_strtoul(buf, &amp;rest, 10);
+	if (*rest || value &gt; 1)
+		return -EINVAL;
+
+	if (atkbd-&gt;softrepeat != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&amp;atkbd-&gt;dev);
+		atkbd-&gt;softrepeat = value;
+		if (atkbd-&gt;softrepeat)
+			atkbd-&gt;softraw = 1;
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&amp;atkbd-&gt;dev);
+	}
+
+	return count;
+}
+
+
+static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd-&gt;softraw ? 1 : 0);
+}
+
+static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	value = simple_strtoul(buf, &amp;rest, 10);
+	if (*rest || value &gt; 1)
+		return -EINVAL;
+
+	if (atkbd-&gt;softraw != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&amp;atkbd-&gt;dev);
+		atkbd-&gt;softraw = value;
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&amp;atkbd-&gt;dev);
+	}
+	return count;
+}
+
 
 int __init atkbd_init(void)
 {
diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/mouse/Kconfig	2004-09-23 21:12:57 -07:00
@@ -16,6 +16,7 @@
 	default y
 	depends on INPUT &amp;&amp; INPUT_MOUSE
 	select SERIO
+	select SERIO_LIBPS2
 	select SERIO_I8042 if PC
 	select SERIO_GSCPS2 if GSC
 	---help---
diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
--- a/drivers/input/mouse/Makefile	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/mouse/Makefile	2004-09-23 21:12:57 -07:00
@@ -14,4 +14,4 @@
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 
-psmouse-objs  := psmouse-base.o logips2pp.o synaptics.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
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/mouse/alps.c	2004-09-23 21:12:57 -07:00
@@ -0,0 +1,430 @@
+/*
+ * ALPS touchpad PS/2 mouse driver
+ *
+ * Copyright (c) 2003 Neil Brown &lt;neilb@cse.unsw.edu.au&gt;
+ * Copyright (c) 2003 Peter Osterlund &lt;petero2@telia.com&gt;
+ * Copyright (c) 2004 Dmitry Torokhov &lt;dtor@mail.ru&gt;
+ *
+ * ALPS detection, tap switching and status querying info is taken from
+ * tpconfig utility (by C. Scott Ananian and Bruce Kall).
+ *
+ * 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 &lt;linux/input.h&gt;
+#include &lt;linux/serio.h&gt;
+#include &lt;linux/libps2.h&gt;
+
+#include "psmouse.h"
+#include "alps.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg)
+#else
+#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 },
+};
+
+/*
+ * ALPS abolute Mode
+ * byte 0:  1    1    1    1    1  mid0 rig0 lef0
+ * 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 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.
+ */
+
+static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	unsigned char *packet = psmouse-&gt;packet;
+	struct input_dev *dev = &amp;psmouse-&gt;dev;
+	int x, y, z;
+	int left = 0, right = 0, middle = 0;
+
+	input_regs(dev, regs);
+
+	if ((packet[0] &amp; 0xc8) == 0x08) {   /* 3-byte PS/2 packet */
+		x = packet[1];
+		if (packet[0] &amp; 0x10)
+			x = x - 256;
+		y = packet[2];
+		if (packet[0] &amp; 0x20)
+			y = y - 256;
+		left  = (packet[0]     ) &amp; 1;
+		right = (packet[0] &gt;&gt; 1) &amp; 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);
+		return;
+	}
+
+	x = (packet[1] &amp; 0x7f) | ((packet[2] &amp; 0x78)&lt;&lt;(7-3));
+	y = (packet[4] &amp; 0x7f) | ((packet[3] &amp; 0x70)&lt;&lt;(7-4));
+	z = packet[5];
+
+	if (z == 127) {	/* DualPoint stick is relative, not absolute */
+		if (x &gt; 383)
+			x = x - 768;
+		if (y &gt; 255)
+			y = y - 512;
+		left  = packet[3] &amp; 1;
+		right = (packet[3] &gt;&gt; 1) &amp; 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);
+		input_sync(dev);
+		return;
+	}
+
+	if (z &gt; 30) input_report_key(dev, BTN_TOUCH, 1);
+	if (z &lt; 25) input_report_key(dev, BTN_TOUCH, 0);
+
+	if (z &gt; 0) {
+		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 &gt; 0);
+
+	left  |= (packet[2]     ) &amp; 1;
+	left  |= (packet[3]     ) &amp; 1;
+	right |= (packet[3] &gt;&gt; 1) &amp; 1;
+	if (packet[0] == 0xff) {
+		int back    = (packet[3] &gt;&gt; 2) &amp; 1;
+		int forward = (packet[2] &gt;&gt; 2) &amp; 1;
+		if (back &amp;&amp; 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]     ) &amp; 1;
+		right  |= (packet[0] &gt;&gt; 1) &amp; 1;
+		middle |= (packet[0] &gt;&gt; 2) &amp; 1;
+		middle |= (packet[3] &gt;&gt; 2) &amp; 1;
+	}
+
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
+	input_report_key(dev, BTN_MIDDLE, middle);
+
+	input_sync(dev);
+}
+
+static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	if ((psmouse-&gt;packet[0] &amp; 0xc8) == 0x08) { /* PS/2 packet */
+		if (psmouse-&gt;pktcnt == 3) {
+			alps_process_packet(psmouse, regs);
+			return PSMOUSE_FULL_PACKET;
+		}
+		return PSMOUSE_GOOD_DATA;
+	}
+
+	/* ALPS absolute mode packets start with 0b11111mrl */
+	if ((psmouse-&gt;packet[0] &amp; 0xf8) != 0xf8)
+		return PSMOUSE_BAD_DATA;
+
+	/* Bytes 2 - 6 should have 0 in the highest bit */
+	if (psmouse-&gt;pktcnt &gt; 1 &amp;&amp; psmouse-&gt;pktcnt &lt;= 6 &amp;&amp;
+	    (psmouse-&gt;packet[psmouse-&gt;pktcnt] &amp; 0x80))
+		return PSMOUSE_BAD_DATA;
+
+	if (psmouse-&gt;pktcnt == 6) {
+		alps_process_packet(psmouse, regs);
+		return PSMOUSE_FULL_PACKET;
+	}
+
+	return PSMOUSE_GOOD_DATA;
+}
+
+int alps_get_model(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
+	unsigned char param[4];
+	int i;
+
+	/*
+	 * First try "E6 report".
+	 * ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64
+	 */
+	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;
+
+	param[0] = param[1] = param[2] = 0xff;
+	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+		return -1;
+
+	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 &amp;&amp; param[2] != 0x64))
+		return -1;
+
+	/* Now try "E7 report". ALPS should return 0x33 in byte 1 */
+	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;
+
+	param[0] = param[1] = param[2] = 0xff;
+	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+		return -1;
+
+	dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
+
+	for (i = 0; i &lt; 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 -1;
+}
+
+/*
+ * For DualPoint devices select the device that should respond to
+ * subsequent commands. It looks like glidepad is behind stickpointer,
+ * I'd thought it would be other way around...
+ */
+static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
+{
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
+	unsigned char param[3];
+	int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
+
+	if (ps2_command(ps2dev, NULL, cmd) ||
+	    ps2_command(ps2dev, NULL, cmd) ||
+	    ps2_command(ps2dev, NULL, cmd) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+		return -1;
+
+	/* we may get 3 more bytes, just ignore them */
+	ps2_command(ps2dev, param, 0x0300);
+
+	return 0;
+}
+
+static int alps_magic_knock(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
+
+	/* Try ALPS magic knock - 4 disable before enable */
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+		return -1;
+	return 0;
+}
+
+static int alps_absolute_mode(struct psmouse *psmouse)
+{
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
+		return -1;
+
+	if (alps_passthrough_mode(psmouse, 1))
+		return -1;
+
+	if (alps_magic_knock(psmouse))
+		return -1;
+
+	if (alps_passthrough_mode(psmouse, 0))
+		return -1;
+
+	if (alps_magic_knock(psmouse))
+		return -1;
+
+	/*
+	 * Switch mouse to poll (remote) mode so motion data will not
+	 * get in our way
+	 */
+	return ps2_command(&amp;psmouse-&gt;ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
+}
+
+static int alps_get_status(struct psmouse *psmouse, char *param)
+{
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
+
+	/* Get status: 0xF5 0xF5 0xF5 0xE9 */
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+		return -1;
+
+	dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
+
+	return 0;
+}
+
+/*
+ * Turn touchpad tapping on or off. The sequences are:
+ * 0xE9 0xF5 0xF5 0xF3 0x0A to enable,
+ * 0xE9 0xF5 0xF5 0xE8 0x00 to disable.
+ * My guess that 0xE9 (GetInfo) is here as a sync point.
+ * For models that also have stickpointer (DualPoints) its tapping
+ * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but
+ * we don't fiddle with it.
+ */
+static int alps_tap_mode(struct psmouse *psmouse, int model, int enable)
+{
+	int rc = 0;
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
+	int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
+	unsigned char tap_arg = enable ? 0x0A : 0x00;
+	unsigned char param[4];
+
+	if (model == ALPS_MODEL_DUALPOINT &amp;&amp; alps_passthrough_mode(psmouse, 1))
+		return -1;
+
+	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+	    ps2_command(ps2dev, &amp;tap_arg, cmd))
+		rc = -1;
+
+	if (model == ALPS_MODEL_DUALPOINT &amp;&amp; alps_passthrough_mode(psmouse, 0))
+		return -1;
+
+	if (alps_get_status(psmouse, param))
+		return -1;
+
+
+	return rc;
+}
+
+static int alps_reconnect(struct psmouse *psmouse)
+{
+	int model;
+	unsigned char param[4];
+
+	if ((model = alps_get_model(psmouse)) &lt; 0)
+		return -1;
+
+	if (alps_get_status(psmouse, param))
+		return -1;
+
+	if ((model == ALPS_MODEL_DUALPOINT ? param[2] : param[0]) &amp; 0x04)
+		alps_tap_mode(psmouse, model, 0);
+
+	if (alps_absolute_mode(psmouse)) {
+		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void alps_disconnect(struct psmouse *psmouse)
+{
+	psmouse_reset(psmouse);
+}
+
+int alps_init(struct psmouse *psmouse)
+{
+	unsigned char param[4];
+	int model;
+
+	if ((model = alps_get_model(psmouse)) &lt; 0)
+		return -1;
+
+	if (alps_get_status(psmouse, param)) {
+		printk(KERN_ERR "alps.c: touchpad status report request failed\n");
+		return -1;
+	}
+
+	printk(KERN_INFO "ALPS Touchpad (%s) detected\n",
+		model == ALPS_MODEL_GLIDEPOINT ? "Glidepoint" : "Dualpoint");
+
+	if ((model == ALPS_MODEL_DUALPOINT ? param[2] : param[0]) &amp; 0x04) {
+		printk(KERN_INFO "  Disabling hardware tapping\n");
+		if (alps_tap_mode(psmouse, model, 0))
+			printk(KERN_WARNING "alps.c: Failed to disable hardware tapping\n");
+	}
+
+	if (alps_absolute_mode(psmouse)) {
+		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
+		return -1;
+	}
+
+	psmouse-&gt;dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
+	psmouse-&gt;dev.relbit[LONG(REL_X)] |= BIT(REL_X);
+	psmouse-&gt;dev.relbit[LONG(REL_Y)] |= BIT(REL_Y);
+	psmouse-&gt;dev.keybit[LONG(BTN_A)] |= BIT(BTN_A);
+	psmouse-&gt;dev.keybit[LONG(BTN_B)] |= BIT(BTN_B);
+
+	psmouse-&gt;dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
+	input_set_abs_params(&amp;psmouse-&gt;dev, ABS_X, 0, 1023, 0, 0);
+	input_set_abs_params(&amp;psmouse-&gt;dev, ABS_Y, 0, 1023, 0, 0);
+	input_set_abs_params(&amp;psmouse-&gt;dev, ABS_PRESSURE, 0, 127, 0, 0);
+
+	psmouse-&gt;dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+	psmouse-&gt;dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
+	psmouse-&gt;dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
+	psmouse-&gt;dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
+
+	psmouse-&gt;protocol_handler = alps_process_byte;
+	psmouse-&gt;disconnect = alps_disconnect;
+	psmouse-&gt;reconnect = alps_reconnect;
+
+	return 0;
+}
+
+int alps_detect(struct psmouse *psmouse)
+{
+	return alps_get_model(psmouse) &lt; 0 ? 0 : 1;
+}
+
diff -Nru a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/mouse/alps.h	2004-09-23 21:12:57 -07:00
@@ -0,0 +1,17 @@
+/*
+ * ALPS touchpad PS/2 mouse driver
+ *
+ * Copyright (c) 2003 Peter Osterlund &lt;petero2@telia.com&gt;
+ *
+ * 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.
+ */
+
+#ifndef _ALPS_H
+#define _ALPS_H
+
+int alps_detect(struct psmouse *psmouse);
+int alps_init(struct psmouse *psmouse);
+
+#endif
diff -Nru a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
--- a/drivers/input/mouse/logips2pp.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/mouse/logips2pp.c	2004-09-23 21:12:57 -07:00
@@ -11,6 +11,7 @@
 
 #include &lt;linux/input.h&gt;
 #include &lt;linux/serio.h&gt;
+#include &lt;linux/libps2.h&gt;
 #include "psmouse.h"
 #include "logips2pp.h"
 
@@ -97,7 +98,7 @@
 	if (psmouse_sliced_command(psmouse, command))
 		return -1;
 
-	if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, param, PSMOUSE_CMD_POLL))
 		return -1;
 
 	return 0;
@@ -113,19 +114,20 @@
 
 static void ps2pp_set_smartscroll(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param[4];
 
 	ps2pp_cmd(psmouse, param, 0x32);
 
 	param[0] = 0;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 
 	if (psmouse_smartscroll &lt; 2) {
 		/* 0 - disabled, 1 - enabled */
 		param[0] = psmouse_smartscroll;
-		psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+		ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 	}
 }
 
@@ -137,11 +139,13 @@
 
 void ps2pp_set_800dpi(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param = 3;
-	psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse, &amp;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);
+	ps2_command(ps2dev, &amp;param, PSMOUSE_CMD_SETRES);
 }
 
 static struct ps2pp_info *get_model_info(unsigned char model)
@@ -238,18 +242,19 @@
 
 int ps2pp_init(struct psmouse *psmouse, int set_properties)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param[4];
 	unsigned char protocol = PSMOUSE_PS2;
 	unsigned char model, buttons;
 	struct ps2pp_info *model_info;
 
 	param[0] = 0;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+	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);
 	param[1] = 0;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
 
 	if (param[1] != 0) {
 		model = ((param[0] &gt;&gt; 4) &amp; 0x07) | ((param[0] &lt;&lt; 3) &amp; 0x78);
@@ -263,16 +268,16 @@
 
 			/* Unprotect RAM */
 			param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
-			psmouse_command(psmouse, param, 0x30d1);
+			ps2_command(ps2dev, param, 0x30d1);
 			/* Enable features */
 			param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
-			psmouse_command(psmouse, param, 0x30d1);
+			ps2_command(ps2dev, param, 0x30d1);
 			/* Enable PS2++ */
 			param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
-			psmouse_command(psmouse, param, 0x30d1);
+			ps2_command(ps2dev, param, 0x30d1);
 
 			param[0] = 0;
-			if (!psmouse_command(psmouse, param, 0x13d1) &amp;&amp;
+			if (!ps2_command(ps2dev, param, 0x13d1) &amp;&amp;
 			    param[0] == 0x06 &amp;&amp; param[1] == 0x00 &amp;&amp; param[2] == 0x14) {
 				protocol = PSMOUSE_PS2TPP;
 			}
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/mouse/psmouse-base.c	2004-09-23 21:12:57 -07:00
@@ -2,6 +2,7 @@
  * PS/2 mouse driver
  *
  * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 2003-2004 Dmitry Torokhov
  */
 
 /*
@@ -18,9 +19,11 @@
 #include &lt;linux/input.h&gt;
 #include &lt;linux/serio.h&gt;
 #include &lt;linux/init.h&gt;
+#include &lt;linux/libps2.h&gt;
 #include "psmouse.h"
 #include "synaptics.h"
 #include "logips2pp.h"
+#include "alps.h"
 
 #define DRIVER_DESC	"PS/2 mouse driver"
 
@@ -55,7 +58,7 @@
 __obsolete_setup("psmouse_resetafter=");
 __obsolete_setup("psmouse_rate=");
 
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
 
 /*
  * psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -110,6 +113,15 @@
 	}
 
 /*
+ * Extra button on ThinkingMouse
+ */
+	if (psmouse-&gt;type == PSMOUSE_THINKPS) {
+		input_report_key(dev, BTN_EXTRA, (packet[0] &gt;&gt; 3) &amp; 1);
+		/* Without this bit of weirdness moving up gives wildly high Y changes. */
+		packet[1] |= (packet[0] &amp; 0x40) &lt;&lt; 1;
+	}
+
+/*
  * Generic PS/2 Mouse
  */
 
@@ -144,63 +156,17 @@
 			printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
 				flags &amp; SERIO_TIMEOUT ? " timeout" : "",
 				flags &amp; SERIO_PARITY ? " bad parity" : "");
-		psmouse-&gt;nak = 1;
-		clear_bit(PSMOUSE_FLAG_ACK, &amp;psmouse-&gt;flags);
-		clear_bit(PSMOUSE_FLAG_CMD,  &amp;psmouse-&gt;flags);
-		wake_up_interruptible(&amp;psmouse-&gt;wait);
+		ps2_cmd_aborted(&amp;psmouse-&gt;ps2dev);
 		goto out;
 	}
 
-	if (test_bit(PSMOUSE_FLAG_ACK, &amp;psmouse-&gt;flags)) {
-		switch (data) {
-			case PSMOUSE_RET_ACK:
-				psmouse-&gt;nak = 0;
-				break;
-
-			case PSMOUSE_RET_NAK:
-				psmouse-&gt;nak = 1;
-				break;
-
-			/*
-			 * Workaround for mice which don't ACK the Get ID command.
-			 * These are valid mouse IDs that we recognize.
-			 */
-			case 0x00:
-			case 0x03:
-			case 0x04:
-				if (test_bit(PSMOUSE_FLAG_WAITID, &amp;psmouse-&gt;flags)) {
-					psmouse-&gt;nak = 0;
-					break;
-				}
-				/* Fall through */
-			default:
-				goto out;
-		}
-
-		if (!psmouse-&gt;nak &amp;&amp; psmouse-&gt;cmdcnt) {
-			set_bit(PSMOUSE_FLAG_CMD, &amp;psmouse-&gt;flags);
-			set_bit(PSMOUSE_FLAG_CMD1, &amp;psmouse-&gt;flags);
-		}
-		clear_bit(PSMOUSE_FLAG_ACK, &amp;psmouse-&gt;flags);
-		wake_up_interruptible(&amp;psmouse-&gt;wait);
-
-		if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK)
+	if (unlikely(psmouse-&gt;ps2dev.flags &amp; PS2_FLAG_ACK))
+		if  (ps2_handle_ack(&amp;psmouse-&gt;ps2dev, data))
 			goto out;
-	}
 
-	if (test_bit(PSMOUSE_FLAG_CMD, &amp;psmouse-&gt;flags)) {
-		if (psmouse-&gt;cmdcnt)
-			psmouse-&gt;cmdbuf[--psmouse-&gt;cmdcnt] = data;
-
-		if (test_and_clear_bit(PSMOUSE_FLAG_CMD1, &amp;psmouse-&gt;flags) &amp;&amp; psmouse-&gt;cmdcnt)
-			wake_up_interruptible(&amp;psmouse-&gt;wait);
-
-		if (!psmouse-&gt;cmdcnt) {
-			clear_bit(PSMOUSE_FLAG_CMD, &amp;psmouse-&gt;flags);
-			wake_up_interruptible(&amp;psmouse-&gt;wait);
-		}
-		goto out;
-	}
+	if (unlikely(psmouse-&gt;ps2dev.flags &amp; PS2_FLAG_CMD))
+		if  (ps2_handle_response(&amp;psmouse-&gt;ps2dev, data))
+			goto out;
 
 	if (psmouse-&gt;state == PSMOUSE_INITIALIZING)
 		goto out;
@@ -246,7 +212,7 @@
 			if (++psmouse-&gt;out_of_sync == psmouse_resetafter) {
 				psmouse-&gt;state = PSMOUSE_IGNORE;
 				printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
-				serio_reconnect(psmouse-&gt;serio);
+				serio_reconnect(psmouse-&gt;ps2dev.serio);
 			}
 			break;
 
@@ -266,100 +232,6 @@
 	return IRQ_HANDLED;
 }
 
-/*
- * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because when there would
- * be need for retransmissions, the mouse has to be replaced anyway.
- *
- * psmouse_sendbyte() can only be called from a process context
- */
-
-static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
-{
-	psmouse-&gt;nak = 1;
-	set_bit(PSMOUSE_FLAG_ACK, &amp;psmouse-&gt;flags);
-
-	if (serio_write(psmouse-&gt;serio, byte) == 0)
-		wait_event_interruptible_timeout(psmouse-&gt;wait,
-				!test_bit(PSMOUSE_FLAG_ACK, &amp;psmouse-&gt;flags),
-				msecs_to_jiffies(200));
-
-	clear_bit(PSMOUSE_FLAG_ACK, &amp;psmouse-&gt;flags);
-	return -psmouse-&gt;nak;
-}
-
-/*
- * psmouse_command() sends a command and its parameters to the mouse,
- * then waits for the response and puts it in the param array.
- *
- * psmouse_command() can only be called from a process context
- */
-
-int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
-{
-	int timeout;
-	int send = (command &gt;&gt; 12) &amp; 0xf;
-	int receive = (command &gt;&gt; 8) &amp; 0xf;
-	int rc = -1;
-	int i;
-
-	timeout = msecs_to_jiffies(command == PSMOUSE_CMD_RESET_BAT ? 4000 : 500);
-
-	clear_bit(PSMOUSE_FLAG_CMD, &amp;psmouse-&gt;flags);
-	if (command == PSMOUSE_CMD_GETID)
-		set_bit(PSMOUSE_FLAG_WAITID, &amp;psmouse-&gt;flags);
-
-	if (receive &amp;&amp; param)
-		for (i = 0; i &lt; receive; i++)
-			psmouse-&gt;cmdbuf[(receive - 1) - i] = param[i];
-
-	psmouse-&gt;cmdcnt = receive;
-
-	if (command &amp; 0xff)
-		if (psmouse_sendbyte(psmouse, command &amp; 0xff))
-			goto out;
-
-	for (i = 0; i &lt; send; i++)
-		if (psmouse_sendbyte(psmouse, param[i]))
-			goto out;
-
-	timeout = wait_event_interruptible_timeout(psmouse-&gt;wait,
-				!test_bit(PSMOUSE_FLAG_CMD1, &amp;psmouse-&gt;flags), timeout);
-
-	if (psmouse-&gt;cmdcnt &amp;&amp; timeout &gt; 0) {
-		if (command == PSMOUSE_CMD_RESET_BAT &amp;&amp; jiffies_to_msecs(timeout) &gt; 100)
-			timeout = msecs_to_jiffies(100);
-
-		if (command == PSMOUSE_CMD_GETID &amp;&amp;
-		    psmouse-&gt;cmdbuf[receive - 1] != 0xab &amp;&amp; psmouse-&gt;cmdbuf[receive - 1] != 0xac) {
-			/*
-			 * Device behind the port is not a keyboard
-			 * so we don't need to wait for the 2nd byte
-			 * of ID response.
-			 */
-			clear_bit(PSMOUSE_FLAG_CMD, &amp;psmouse-&gt;flags);
-			psmouse-&gt;cmdcnt = 0;
-		}
-
-		wait_event_interruptible_timeout(psmouse-&gt;wait,
-				!test_bit(PSMOUSE_FLAG_CMD, &amp;psmouse-&gt;flags), timeout);
-	}
-
-	if (param)
-		for (i = 0; i &lt; receive; i++)
-			param[i] = psmouse-&gt;cmdbuf[(receive - 1) - i];
-
-	if (psmouse-&gt;cmdcnt &amp;&amp; (command != PSMOUSE_CMD_RESET_BAT || psmouse-&gt;cmdcnt != 1))
-		goto out;
-
-	rc = 0;
-
-out:
-	clear_bit(PSMOUSE_FLAG_CMD, &amp;psmouse-&gt;flags);
-	clear_bit(PSMOUSE_FLAG_CMD1, &amp;psmouse-&gt;flags);
-	clear_bit(PSMOUSE_FLAG_WAITID, &amp;psmouse-&gt;flags);
-	return rc;
-}
 
 /*
  * psmouse_sliced_command() sends an extended PS/2 command to the mouse
@@ -372,12 +244,12 @@
 {
 	int i;
 
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
 		return -1;
 
 	for (i = 6; i &gt;= 0; i -= 2) {
 		unsigned char d = (command &gt;&gt; i) &amp; 3;
-		if (psmouse_command(psmouse, &amp;d, PSMOUSE_CMD_SETRES))
+		if (ps2_command(&amp;psmouse-&gt;ps2dev, &amp;d, PSMOUSE_CMD_SETRES))
 			return -1;
 	}
 
@@ -392,7 +264,7 @@
 {
 	unsigned char param[2];
 
-	if (psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT))
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, param, PSMOUSE_CMD_RESET_BAT))
 		return -1;
 
 	if (param[0] != PSMOUSE_RET_BAT &amp;&amp; param[1] != PSMOUSE_RET_ID)
@@ -407,14 +279,15 @@
  */
 static int genius_detect(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param[4];
 
 	param[0] = 3;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+	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);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
 
 	return param[0] == 0x00 &amp;&amp; param[1] == 0x33 &amp;&amp; param[2] == 0x55;
 }
@@ -424,15 +297,16 @@
  */
 static int intellimouse_detect(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param[2];
 
 	param[0] = 200;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 	param[0] = 100;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 	param[0] =  80;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
 
 	return param[0] == 3;
 }
@@ -442,22 +316,44 @@
  */
 static int im_explorer_detect(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param[2];
 
 	intellimouse_detect(psmouse);
 
 	param[0] = 200;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 	param[0] = 200;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 	param[0] =  80;
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
 
 	return param[0] == 4;
 }
 
 /*
+ * Kensington ThinkingMouse / ExpertMouse magic init.
+ */
+static int thinking_detect(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
+	unsigned char param[2];
+	unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 };
+	int i;
+
+	param[0] = 10;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] = 0;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	for (i = 0; seq[i]; i++)
+		ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
+
+	return param[0] == 2;
+}
+
+/*
  * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
  * the mouse may have.
  */
@@ -468,6 +364,22 @@
 	int synaptics_hardware = 0;
 
 /*
+ * Try Kensington ThinkingMouse (we try first, because synaptics probe
+ * upsets the thinkingmouse).
+ */
+
+	if (max_proto &gt; PSMOUSE_PS2 &amp;&amp; thinking_detect(psmouse)) {
+
+		if (set_properties) {
+			set_bit(BTN_EXTRA, psmouse-&gt;dev.keybit);
+			psmouse-&gt;vendor = "Kensington";
+			psmouse-&gt;name = "ThinkingMouse";
+		}
+
+		return PSMOUSE_THINKPS;
+	}
+
+/*
  * Try Synaptics TouchPad
  */
 	if (max_proto &gt; PSMOUSE_PS2 &amp;&amp; synaptics_detect(psmouse)) {
@@ -494,6 +406,25 @@
 		synaptics_reset(psmouse);
 	}
 
+/*
+ * Try ALPS TouchPad
+ */
+	if (max_proto &gt; PSMOUSE_IMEX &amp;&amp; alps_detect(psmouse)) {
+
+		if (set_properties) {
+			psmouse-&gt;vendor = "ALPS";
+			psmouse-&gt;name = "TouchPad";
+		}
+
+		if (!set_properties || alps_init(psmouse) == 0)
+			return PSMOUSE_ALPS;
+
+/*
+ * Init failed, try basic relative protocols
+ */
+		max_proto = PSMOUSE_IMEX;
+	}
+
 	if (max_proto &gt; PSMOUSE_IMEX &amp;&amp; genius_detect(psmouse)) {
 
 		if (set_properties) {
@@ -549,7 +480,7 @@
  * extensions.
  */
 		psmouse_reset(psmouse);
-		psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS);
+		ps2_command(&amp;psmouse-&gt;ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
 	}
 
 	return PSMOUSE_PS2;
@@ -561,6 +492,7 @@
 
 static int psmouse_probe(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param[2];
 
 /*
@@ -569,8 +501,7 @@
  */
 
 	param[0] = 0xa5;
-
-	if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
+	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
 		return -1;
 
 	if (param[0] != 0x00 &amp;&amp; param[0] != 0x03 &amp;&amp; param[0] != 0x04)
@@ -580,8 +511,8 @@
  * Then we reset and disable the mouse so that it doesn't generate events.
  */
 
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
-		printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse-&gt;serio-&gt;phys);
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
+		printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev-&gt;serio-&gt;phys);
 
 	return 0;
 }
@@ -608,7 +539,7 @@
 	else if (psmouse_resolution)
 		param[0] = 0;
 
-        psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	ps2_command(&amp;psmouse-&gt;ps2dev, param, PSMOUSE_CMD_SETRES);
 }
 
 /*
@@ -621,7 +552,7 @@
 	int i = 0;
 
 	while (rates[i] &gt; psmouse_rate) i++;
-	psmouse_command(psmouse, rates + i, PSMOUSE_CMD_SETRATE);
+	ps2_command(&amp;psmouse-&gt;ps2dev, rates + i, PSMOUSE_CMD_SETRATE);
 }
 
 /*
@@ -639,14 +570,14 @@
 	if (psmouse_max_proto != PSMOUSE_PS2) {
 		psmouse_set_rate(psmouse);
 		psmouse_set_resolution(psmouse);
-		psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
+		ps2_command(&amp;psmouse-&gt;ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
 	}
 
 /*
  * We set the mouse into streaming mode.
  */
 
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+	ps2_command(&amp;psmouse-&gt;ps2dev, param, PSMOUSE_CMD_SETSTREAM);
 }
 
 /*
@@ -657,11 +588,11 @@
 
 static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
 {
-	serio_pause_rx(psmouse-&gt;serio);
+	serio_pause_rx(psmouse-&gt;ps2dev.serio);
 	psmouse-&gt;state = new_state;
-	psmouse-&gt;pktcnt = psmouse-&gt;cmdcnt = psmouse-&gt;out_of_sync = 0;
-	psmouse-&gt;flags = 0;
-	serio_continue_rx(psmouse-&gt;serio);
+	psmouse-&gt;pktcnt = psmouse-&gt;out_of_sync = 0;
+	psmouse-&gt;ps2dev.flags = 0;
+	serio_continue_rx(psmouse-&gt;ps2dev.serio);
 }
 
 /*
@@ -670,8 +601,9 @@
 
 static void psmouse_activate(struct psmouse *psmouse)
 {
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
-		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse-&gt;serio-&gt;phys);
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
+			psmouse-&gt;ps2dev.serio-&gt;phys);
 
 	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
 }
@@ -684,8 +616,9 @@
 
 static void psmouse_deactivate(struct psmouse *psmouse)
 {
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE))
-		printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", psmouse-&gt;serio-&gt;phys);
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+		printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
+			psmouse-&gt;ps2dev.serio-&gt;phys);
 
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 }
@@ -755,12 +688,10 @@
 
 	memset(psmouse, 0, sizeof(struct psmouse));
 
-	init_waitqueue_head(&amp;psmouse-&gt;wait);
-	init_input_dev(&amp;psmouse-&gt;dev);
+	ps2_init(&amp;psmouse-&gt;ps2dev, serio);
 	psmouse-&gt;dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	psmouse-&gt;dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse-&gt;dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	psmouse-&gt;serio = serio;
 	psmouse-&gt;dev.private = psmouse;
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
@@ -846,7 +777,7 @@
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
 	if (psmouse-&gt;reconnect) {
-	       if (psmouse-&gt;reconnect(psmouse))
+		if (psmouse-&gt;reconnect(psmouse))
 			goto out;
 	} else if (psmouse_probe(psmouse) &lt; 0 ||
 		   psmouse-&gt;type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/mouse/psmouse.h	2004-09-23 21:12:57 -07:00
@@ -2,9 +2,11 @@
 #define _PSMOUSE_H
 
 #define PSMOUSE_CMD_SETSCALE11	0x00e6
+#define PSMOUSE_CMD_SETSCALE21	0x00e7
 #define PSMOUSE_CMD_SETRES	0x10e8
 #define PSMOUSE_CMD_GETINFO	0x03e9
 #define PSMOUSE_CMD_SETSTREAM	0x00ea
+#define PSMOUSE_CMD_SETPOLL	0x00f0
 #define PSMOUSE_CMD_POLL	0x03eb
 #define PSMOUSE_CMD_GETID	0x02f2
 #define PSMOUSE_CMD_SETRATE	0x10f3
@@ -18,11 +20,6 @@
 #define PSMOUSE_RET_ACK		0xfa
 #define PSMOUSE_RET_NAK		0xfe
 
-#define PSMOUSE_FLAG_ACK	0	/* Waiting for ACK/NAK */
-#define PSMOUSE_FLAG_CMD	1	/* Waiting for command to finish */
-#define PSMOUSE_FLAG_CMD1	2	/* Waiting for the first byte of command response */
-#define PSMOUSE_FLAG_WAITID	3	/* Command execiting is GET ID */
-
 enum psmouse_state {
 	PSMOUSE_IGNORE,
 	PSMOUSE_INITIALIZING,
@@ -40,26 +37,18 @@
 struct psmouse {
 	void *private;
 	struct input_dev dev;
-	struct serio *serio;
+	struct ps2dev ps2dev;
 	char *vendor;
 	char *name;
-	unsigned char cmdbuf[8];
 	unsigned char packet[8];
-	unsigned char cmdcnt;
 	unsigned char pktcnt;
 	unsigned char type;
 	unsigned char model;
 	unsigned long last;
 	unsigned long out_of_sync;
 	enum psmouse_state state;
-	unsigned char nak;
-	char error;
 	char devname[64];
 	char phys[32];
-	unsigned long flags;
-
-	/* Used to signal completion from interrupt handler */
-	wait_queue_head_t wait;
 
 	psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
 	int (*reconnect)(struct psmouse *psmouse);
@@ -69,15 +58,19 @@
 	void (*pt_deactivate)(struct psmouse *psmouse);
 };
 
-#define PSMOUSE_PS2		1
-#define PSMOUSE_PS2PP		2
-#define PSMOUSE_PS2TPP		3
-#define PSMOUSE_GENPS		4
-#define PSMOUSE_IMPS		5
-#define PSMOUSE_IMEX		6
-#define PSMOUSE_SYNAPTICS 	7
+enum psmouse_type {
+	PSMOUSE_NONE,
+	PSMOUSE_PS2,
+	PSMOUSE_PS2PP,
+	PSMOUSE_PS2TPP,
+	PSMOUSE_THINKPS,
+	PSMOUSE_GENPS,
+	PSMOUSE_IMPS,
+	PSMOUSE_IMEX,
+	PSMOUSE_SYNAPTICS,
+	PSMOUSE_ALPS,
+};
 
-int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
 int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
 int psmouse_reset(struct psmouse *psmouse);
 
diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/mouse/synaptics.c	2004-09-23 21:12:57 -07:00
@@ -26,6 +26,7 @@
 #include &lt;linux/module.h&gt;
 #include &lt;linux/input.h&gt;
 #include &lt;linux/serio.h&gt;
+#include &lt;linux/libps2.h&gt;
 #include "psmouse.h"
 #include "synaptics.h"
 
@@ -50,7 +51,7 @@
 {
 	if (psmouse_sliced_command(psmouse, c))
 		return -1;
-	if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, param, PSMOUSE_CMD_GETINFO))
 		return -1;
 	return 0;
 }
@@ -65,7 +66,7 @@
 	if (psmouse_sliced_command(psmouse, mode))
 		return -1;
 	param[0] = SYN_PS_SET_MODE2;
-	if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+	if (ps2_command(&amp;psmouse-&gt;ps2dev, param, PSMOUSE_CMD_SETRATE))
 		return -1;
 	return 0;
 }
@@ -219,7 +220,7 @@
 
 	if (psmouse_sliced_command(parent, c))
 		return -1;
-	if (psmouse_command(parent, &amp;rate_param, PSMOUSE_CMD_SETRATE))
+	if (ps2_command(&amp;parent-&gt;ps2dev, &amp;rate_param, PSMOUSE_CMD_SETRATE))
 		return -1;
 	return 0;
 }
@@ -245,7 +246,7 @@
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
 {
-	struct psmouse *child = psmouse-&gt;serio-&gt;child-&gt;private;
+	struct psmouse *child = psmouse-&gt;ps2dev.serio-&gt;child-&gt;private;
 
 	/* adjust the touchpad to child's choice of protocol */
 	if (child &amp;&amp; child-&gt;type &gt;= PSMOUSE_GENPS) {
@@ -270,11 +271,11 @@
 	strlcpy(serio-&gt;name, "Synaptics pass-through", sizeof(serio-&gt;name));
 	strlcpy(serio-&gt;phys, "synaptics-pt/serio0", sizeof(serio-&gt;name));
 	serio-&gt;write = synaptics_pt_write;
-	serio-&gt;parent = psmouse-&gt;serio;
+	serio-&gt;parent = psmouse-&gt;ps2dev.serio;
 
 	psmouse-&gt;pt_activate = synaptics_pt_activate;
 
-	psmouse-&gt;serio-&gt;child = serio;
+	psmouse-&gt;ps2dev.serio-&gt;child = serio;
 }
 
 /*****************************************************************************
@@ -470,8 +471,8 @@
 			priv-&gt;pkt_type = synaptics_detect_pkt_type(psmouse);
 
 		if (SYN_CAP_PASS_THROUGH(priv-&gt;capabilities) &amp;&amp; synaptics_is_pt_packet(psmouse-&gt;packet)) {
-			if (psmouse-&gt;serio-&gt;child)
-				synaptics_pass_pt_packet(psmouse-&gt;serio-&gt;child, psmouse-&gt;packet);
+			if (psmouse-&gt;ps2dev.serio-&gt;child)
+				synaptics_pass_pt_packet(psmouse-&gt;ps2dev.serio-&gt;child, psmouse-&gt;packet);
 		} else
 			synaptics_process_packet(psmouse);
 
@@ -561,15 +562,16 @@
 
 int synaptics_detect(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &amp;psmouse-&gt;ps2dev;
 	unsigned char param[4];
 
 	param[0] = 0;
 
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
 
 	return param[1] == 0x47;
 }
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/mousedev.c	2004-09-23 21:12:57 -07:00
@@ -115,20 +115,26 @@
 #define fx(i)  (mousedev-&gt;old_x[(mousedev-&gt;pkt_count - (i)) &amp; 03])
 #define fy(i)  (mousedev-&gt;old_y[(mousedev-&gt;pkt_count - (i)) &amp; 03])
 
-static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
 {
+	int size;
+
 	if (mousedev-&gt;touch) {
 		switch (code) {
 			case ABS_X:
+				size = dev-&gt;absmax[ABS_X] - dev-&gt;absmin[ABS_X];
+				if (size == 0) size = xres;
 				fx(0) = value;
 				if (mousedev-&gt;pkt_count &gt;= 2)
-					mousedev-&gt;packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
+					mousedev-&gt;packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) * xres / (size * 2);
 				break;
 
 			case ABS_Y:
+				size = dev-&gt;absmax[ABS_Y] - dev-&gt;absmin[ABS_Y];
+				if (size == 0) size = yres;
 				fy(0) = value;
 				if (mousedev-&gt;pkt_count &gt;= 2)
-					mousedev-&gt;packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
+					mousedev-&gt;packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) * yres / (size * 2);
 				break;
 		}
 	}
@@ -279,7 +285,7 @@
 				return;
 
 			if (test_bit(BTN_TOOL_FINGER, handle-&gt;dev-&gt;keybit))
-				mousedev_touchpad_event(mousedev, code, value);
+				mousedev_touchpad_event(handle-&gt;dev, mousedev, code, value);
 			else
 				mousedev_abs_event(handle-&gt;dev, mousedev, code, value);
 
diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/serio/Kconfig	2004-09-23 21:12:57 -07:00
@@ -131,6 +131,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called maceps2.
 
+config SERIO_LIBPS2
+	tristate "PS/2 driver library"
+	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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called libps2.
+
 config SERIO_RAW
 	tristate "Raw access to serio ports"
 	depends on SERIO
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/serio/Makefile	2004-09-23 21:12:57 -07:00
@@ -17,4 +17,5 @@
 obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
+obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
 obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
diff -Nru a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/serio/libps2.c	2004-09-23 21:12:57 -07:00
@@ -0,0 +1,273 @@
+/*
+ * PS/2 driver library
+ *
+ * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 2004 Dmitry Torokhov
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include &lt;linux/delay.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/moduleparam.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/interrupt.h&gt;
+#include &lt;linux/input.h&gt;
+#include &lt;linux/serio.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;linux/libps2.h&gt;
+
+#define DRIVER_DESC	"PS/2 driver library"
+
+MODULE_AUTHOR("Dmitry Torokhov &lt;dtor@mail.ru&gt;");
+MODULE_DESCRIPTION("PS/2 driver library");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ps2_init);
+EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_command);
+EXPORT_SYMBOL(ps2_schedule_command);
+EXPORT_SYMBOL(ps2_handle_ack);
+EXPORT_SYMBOL(ps2_handle_response);
+EXPORT_SYMBOL(ps2_cmd_aborted);
+
+/* Work structure to schedule execution of a command */
+struct ps2work {
+	struct work_struct work;
+	struct ps2dev *ps2dev;
+	int command;
+	unsigned char param[0];
+};
+
+
+/*
+ * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because when there would
+ * be need for retransmissions, the mouse has to be replaced anyway.
+ *
+ * ps2_sendbyte() can only be called from a process context
+ */
+
+int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte)
+{
+	serio_pause_rx(ps2dev-&gt;serio);
+	ps2dev-&gt;nak = 1;
+	ps2dev-&gt;flags |= PS2_FLAG_ACK;
+	serio_continue_rx(ps2dev-&gt;serio);
+
+	if (serio_write(ps2dev-&gt;serio, byte) == 0)
+		wait_event_interruptible_timeout(ps2dev-&gt;wait,
+					!(ps2dev-&gt;flags &amp; PS2_FLAG_ACK),
+					msecs_to_jiffies(200));
+
+	serio_pause_rx(ps2dev-&gt;serio);
+	ps2dev-&gt;flags &amp;= ~PS2_FLAG_ACK;
+	serio_continue_rx(ps2dev-&gt;serio);
+
+	return -ps2dev-&gt;nak;
+}
+
+/*
+ * ps2_command() sends a command and its parameters to the mouse,
+ * then waits for the response and puts it in the param array.
+ *
+ * ps2_command() can only be called from a process context
+ */
+
+int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+{
+	int timeout;
+	int send = (command &gt;&gt; 12) &amp; 0xf;
+	int receive = (command &gt;&gt; 8) &amp; 0xf;
+	int rc = -1;
+	int i;
+
+	down(&amp;ps2dev-&gt;cmd_sem);
+
+	timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500);
+
+	serio_pause_rx(ps2dev-&gt;serio);
+	ps2dev-&gt;flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
+	ps2dev-&gt;cmdcnt = receive;
+	if (receive &amp;&amp; param)
+		for (i = 0; i &lt; receive; i++)
+			ps2dev-&gt;cmdbuf[(receive - 1) - i] = param[i];
+	serio_continue_rx(ps2dev-&gt;serio);
+
+	if (command &amp; 0xff)
+		if (ps2_sendbyte(ps2dev, command &amp; 0xff))
+			goto out;
+
+	for (i = 0; i &lt; send; i++)
+		if (ps2_sendbyte(ps2dev, param[i]))
+			goto out;
+
+	timeout = wait_event_interruptible_timeout(ps2dev-&gt;wait,
+				!(ps2dev-&gt;flags &amp; PS2_FLAG_CMD1), timeout);
+
+	if (ps2dev-&gt;cmdcnt &amp;&amp; timeout &gt; 0) {
+		if (command == PS2_CMD_RESET_BAT &amp;&amp; jiffies_to_msecs(timeout) &gt; 100)
+			timeout = msecs_to_jiffies(100);
+
+		if (command == PS2_CMD_GETID &amp;&amp;
+		    ps2dev-&gt;cmdbuf[receive - 1] != 0xab &amp;&amp; ps2dev-&gt;cmdbuf[receive - 1] != 0xac) {
+			/*
+			 * Device behind the port is not a keyboard
+			 * so we don't need to wait for the 2nd byte
+			 * of ID response.
+			 */
+			serio_pause_rx(ps2dev-&gt;serio);
+			ps2dev-&gt;flags = ps2dev-&gt;cmdcnt = 0;
+			serio_continue_rx(ps2dev-&gt;serio);
+		}
+
+		wait_event_interruptible_timeout(ps2dev-&gt;wait,
+				!(ps2dev-&gt;flags &amp; PS2_FLAG_CMD), timeout);
+	}
+
+	if (param)
+		for (i = 0; i &lt; receive; i++)
+			param[i] = ps2dev-&gt;cmdbuf[(receive - 1) - i];
+
+	if (ps2dev-&gt;cmdcnt &amp;&amp; (command != PS2_CMD_RESET_BAT || ps2dev-&gt;cmdcnt != 1))
+		goto out;
+
+	rc = 0;
+
+out:
+	serio_pause_rx(ps2dev-&gt;serio);
+	ps2dev-&gt;flags = 0;
+	serio_continue_rx(ps2dev-&gt;serio);
+
+	up(&amp;ps2dev-&gt;cmd_sem);
+	return rc;
+}
+
+/*
+ * ps2_execute_scheduled_command() sends a command, previously scheduled by
+ * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.)
+ */
+
+static void ps2_execute_scheduled_command(void *data)
+{
+	struct ps2work *ps2work = data;
+
+	ps2_command(ps2work-&gt;ps2dev, ps2work-&gt;param, ps2work-&gt;command);
+	kfree(ps2work);
+}
+
+/*
+ * ps2_schedule_command() allows to schedule delayed execution of a PS/2
+ * command and can be used to issue a command from an interrupt or softirq
+ * context.
+ */
+
+int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+{
+	struct ps2work *ps2work;
+	int send = (command &gt;&gt; 12) &amp; 0xf;
+	int receive = (command &gt;&gt; 8) &amp; 0xf;
+
+	if (!(ps2work = kmalloc(sizeof(struct ps2work) + max(send, receive), GFP_ATOMIC)))
+		return -1;
+
+	memset(ps2work, 0, sizeof(struct ps2work));
+	ps2work-&gt;ps2dev = ps2dev;
+	ps2work-&gt;command = command;
+	memcpy(ps2work-&gt;param, param, send);
+	INIT_WORK(&amp;ps2work-&gt;work, ps2_execute_scheduled_command, ps2work);
+
+	if (!schedule_work(&amp;ps2work-&gt;work)) {
+		kfree(ps2work);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * ps2_init() initializes ps2dev structure
+ */
+
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
+{
+	init_MUTEX(&amp;ps2dev-&gt;cmd_sem);
+	init_waitqueue_head(&amp;ps2dev-&gt;wait);
+	ps2dev-&gt;serio = serio;
+}
+
+/*
+ * ps2_handle_ack()
+ */
+
+int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
+{
+	switch (data) {
+		case PS2_RET_ACK:
+			ps2dev-&gt;nak = 0;
+			break;
+
+		case PS2_RET_NAK:
+			ps2dev-&gt;nak = 1;
+			break;
+
+		/*
+		 * Workaround for mice which don't ACK the Get ID command.
+		 * These are valid mouse IDs that we recognize.
+		 */
+		case 0x00:
+		case 0x03:
+		case 0x04:
+			if (ps2dev-&gt;flags &amp; PS2_FLAG_WAITID) {
+				ps2dev-&gt;nak = 0;
+				break;
+			}
+			/* Fall through */
+		default:
+			return 1;
+	}
+
+	if (!ps2dev-&gt;nak &amp;&amp; ps2dev-&gt;cmdcnt)
+		ps2dev-&gt;flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
+
+	ps2dev-&gt;flags &amp;= ~PS2_FLAG_ACK;
+	wake_up_interruptible(&amp;ps2dev-&gt;wait);
+
+	return data == PS2_RET_ACK || data == PS2_RET_NAK;
+}
+
+
+int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
+{
+	if (ps2dev-&gt;cmdcnt)
+		ps2dev-&gt;cmdbuf[--ps2dev-&gt;cmdcnt] = data;
+
+	if (ps2dev-&gt;flags &amp; PS2_FLAG_CMD1) {
+		ps2dev-&gt;flags &amp;= ~PS2_FLAG_CMD1;
+		if (ps2dev-&gt;cmdcnt)
+			wake_up_interruptible(&amp;ps2dev-&gt;wait);
+	}
+
+	if (!ps2dev-&gt;cmdcnt) {
+		ps2dev-&gt;flags &amp;= ~PS2_FLAG_CMD;
+		wake_up_interruptible(&amp;ps2dev-&gt;wait);
+	}
+
+	return 1;
+}
+
+void ps2_cmd_aborted(struct ps2dev *ps2dev)
+{
+	if (ps2dev-&gt;flags &amp; PS2_FLAG_ACK)
+		ps2dev-&gt;nak = 1;
+
+	if (ps2dev-&gt;flags &amp; (PS2_FLAG_ACK | PS2_FLAG_CMD))
+		wake_up_interruptible(&amp;ps2dev-&gt;wait);
+
+	ps2dev-&gt;flags = 0;
+}
+
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/input/serio/serio.c	2004-09-23 21:12:57 -07:00
@@ -326,6 +326,7 @@
 	try_module_get(THIS_MODULE);
 
 	spin_lock_init(&amp;serio-&gt;lock);
+	init_MUTEX(&amp;serio-&gt;drv_sem);
 	list_add_tail(&amp;serio-&gt;node, &amp;serio_list);
 	snprintf(serio-&gt;dev.bus_id, sizeof(serio-&gt;dev.bus_id), "serio%d", serio_no++);
 	serio-&gt;dev.bus = &amp;serio_bus;
@@ -595,17 +596,22 @@
 	up(&amp;serio_sem);
 }
 
-/* called from serio_driver-&gt;connect/disconnect methods under serio_sem */
-int serio_open(struct serio *serio, struct serio_driver *drv)
+static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
 {
+	down(&amp;serio-&gt;drv_sem);
 	serio_pause_rx(serio);
 	serio-&gt;drv = drv;
 	serio_continue_rx(serio);
+	up(&amp;serio-&gt;drv_sem);
+}
+
+/* called from serio_driver-&gt;connect/disconnect methods under serio_sem */
+int serio_open(struct serio *serio, struct serio_driver *drv)
+{
+	serio_set_drv(serio, drv);
 
 	if (serio-&gt;open &amp;&amp; serio-&gt;open(serio)) {
-		serio_pause_rx(serio);
-		serio-&gt;drv = NULL;
-		serio_continue_rx(serio);
+		serio_set_drv(serio, NULL);
 		return -1;
 	}
 	return 0;
@@ -617,9 +623,7 @@
 	if (serio-&gt;close)
 		serio-&gt;close(serio);
 
-	serio_pause_rx(serio);
-	serio-&gt;drv = NULL;
-	serio_continue_rx(serio);
+	serio_set_drv(serio, NULL);
 }
 
 irqreturn_t serio_interrupt(struct serio *serio,
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/usb/input/hid-core.c	2004-09-23 21:12:57 -07:00
@@ -1275,9 +1275,14 @@
 static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 		unsigned char type, void *buf, int size)
 {
-	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-		USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
-		(type &lt;&lt; 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);
+	int result, retries = 4;
+	do {
+		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+				(type &lt;&lt; 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);
+		retries--;
+	} while (result &lt; 0 &amp;&amp; retries);
+	return result;
 }
 
 int hid_open(struct hid_device *hid)
@@ -1308,7 +1313,7 @@
 	struct hid_report_enum *report_enum;
 	struct hid_report *report;
 	struct list_head *list;
-	int err, ret;
+	int err, ret, size;
 
 	/*
 	 * The Set_Idle request is supposed to affect only the
@@ -1331,6 +1336,10 @@
 	list = report_enum-&gt;report_list.next;
 	while (list != &amp;report_enum-&gt;report_list) {
 		report = (struct hid_report *) list;
+		size = ((report-&gt;size - 1) &gt;&gt; 3) + 1 + report_enum-&gt;numbered;
+		if (size &gt; HID_BUFFER_SIZE) size = HID_BUFFER_SIZE;
+		if (size &gt; hid-&gt;urbin-&gt;transfer_buffer_length)
+			hid-&gt;urbin-&gt;transfer_buffer_length = size;
 		hid_submit_report(hid, report, USB_DIR_IN);
 		list = list-&gt;next;
 	}
@@ -1456,6 +1465,8 @@
 #define USB_VENDOR_ID_CODEMERCS		0x07c0
 #define USB_DEVICE_ID_CODEMERCS_IOW40	0x1500
 #define USB_DEVICE_ID_CODEMERCS_IOW24	0x1501
+#define USB_DEVICE_ID_CODEMERCS_IOW48	0x1502
+#define USB_DEVICE_ID_CODEMERCS_IOW28	0x1503
 
 
 static struct hid_blacklist {
@@ -1474,8 +1485,15 @@
 	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, 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 },
+	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
+	{ 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_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
@@ -1511,13 +1529,6 @@
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_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 },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, 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 },
 
@@ -1528,8 +1539,8 @@
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, 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_BACK },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA },
+	{ 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_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
@@ -1650,17 +1661,12 @@
 			interval = 1 &lt;&lt; (interval - 1);
 
 		if (endpoint-&gt;bEndpointAddress &amp; USB_DIR_IN) {
-			int len;
-
 			if (hid-&gt;urbin)
 				continue;
 			if (!(hid-&gt;urbin = usb_alloc_urb(0, GFP_KERNEL)))
 				goto fail;
 			pipe = usb_rcvintpipe(dev, endpoint-&gt;bEndpointAddress);
-			len = usb_maxpacket(dev, pipe, 0);
-			if (len &gt; HID_BUFFER_SIZE)
-				len = HID_BUFFER_SIZE;
-			usb_fill_int_urb(hid-&gt;urbin, dev, pipe, hid-&gt;inbuf, len,
+			usb_fill_int_urb(hid-&gt;urbin, dev, pipe, hid-&gt;inbuf, 0,
 					 hid_irq_in, hid, interval);
 			hid-&gt;urbin-&gt;transfer_dma = hid-&gt;inbuf_dma;
 			hid-&gt;urbin-&gt;transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
diff -Nru a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
--- a/drivers/usb/input/hid-debug.h	2004-09-23 21:12:57 -07:00
+++ b/drivers/usb/input/hid-debug.h	2004-09-23 21:12:57 -07:00
@@ -27,6 +27,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#include &lt;linux/input.h&gt;
+
 struct hid_usage_entry {
 	unsigned  page;
 	unsigned  usage;
@@ -323,7 +325,7 @@
 	printk(".");
 	for (p = hid_usage_table; p-&gt;description; p++)
 		if (p-&gt;page == (usage &gt;&gt; 16)) {
-			for(++p; p-&gt;description &amp;&amp; p-&gt;page != 0; p++)
+			for(++p; p-&gt;description &amp;&amp; p-&gt;usage != 0; p++)
 				if (p-&gt;usage == (usage &amp; 0xffff)) {
 					printk("%s", p-&gt;description);
 					return;
@@ -461,4 +463,264 @@
 	printk("hid-debug: input ");
 	resolv_usage(usage-&gt;hid);
 	printk(" = %d\n", value);
+}
+
+
+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",
+	[EV_SND] = "Sound",			[EV_REP] = "Repeat",
+	[EV_FF] = "ForceFeedback",		[EV_PWR] = "Power",
+	[EV_FF_STATUS] = "ForceFeedbackStatus",
+};
+
+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",
+	[KEY_5] = "5",				[KEY_6] = "6",
+	[KEY_7] = "7",				[KEY_8] = "8",
+	[KEY_9] = "9",				[KEY_0] = "0",
+	[KEY_MINUS] = "Minus",			[KEY_EQUAL] = "Equal",
+	[KEY_BACKSPACE] = "Backspace",		[KEY_TAB] = "Tab",
+	[KEY_Q] = "Q",				[KEY_W] = "W",
+	[KEY_E] = "E",				[KEY_R] = "R",
+	[KEY_T] = "T",				[KEY_Y] = "Y",
+	[KEY_U] = "U",				[KEY_I] = "I",
+	[KEY_O] = "O",				[KEY_P] = "P",
+	[KEY_LEFTBRACE] = "LeftBrace",		[KEY_RIGHTBRACE] = "RightBrace",
+	[KEY_ENTER] = "Enter",			[KEY_LEFTCTRL] = "LeftControl",
+	[KEY_A] = "A",				[KEY_S] = "S",
+	[KEY_D] = "D",				[KEY_F] = "F",
+	[KEY_G] = "G",				[KEY_H] = "H",
+	[KEY_J] = "J",				[KEY_K] = "K",
+	[KEY_L] = "L",				[KEY_SEMICOLON] = "Semicolon",
+	[KEY_APOSTROPHE] = "Apostrophe",	[KEY_GRAVE] = "Grave",
+	[KEY_LEFTSHIFT] = "LeftShift",		[KEY_BACKSLASH] = "BackSlash",
+	[KEY_Z] = "Z",				[KEY_X] = "X",
+	[KEY_C] = "C",				[KEY_V] = "V",
+	[KEY_B] = "B",				[KEY_N] = "N",
+	[KEY_M] = "M",				[KEY_COMMA] = "Comma",
+	[KEY_DOT] = "Dot",			[KEY_SLASH] = "Slash",
+	[KEY_RIGHTSHIFT] = "RightShift",	[KEY_KPASTERISK] = "KPAsterisk",
+	[KEY_LEFTALT] = "LeftAlt",		[KEY_SPACE] = "Space",
+	[KEY_CAPSLOCK] = "CapsLock",		[KEY_F1] = "F1",
+	[KEY_F2] = "F2",			[KEY_F3] = "F3",
+	[KEY_F4] = "F4",			[KEY_F5] = "F5",
+	[KEY_F6] = "F6",			[KEY_F7] = "F7",
+	[KEY_F8] = "F8",			[KEY_F9] = "F9",
+	[KEY_F10] = "F10",			[KEY_NUMLOCK] = "NumLock",
+	[KEY_SCROLLLOCK] = "ScrollLock",	[KEY_KP7] = "KP7",
+	[KEY_KP8] = "KP8",			[KEY_KP9] = "KP9",
+	[KEY_KPMINUS] = "KPMinus",		[KEY_KP4] = "KP4",
+	[KEY_KP5] = "KP5",			[KEY_KP6] = "KP6",
+	[KEY_KPPLUS] = "KPPlus",		[KEY_KP1] = "KP1",
+	[KEY_KP2] = "KP2",			[KEY_KP3] = "KP3",
+	[KEY_KP0] = "KP0",			[KEY_KPDOT] = "KPDot",
+	[KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
+	[KEY_F11] = "F11",			[KEY_F12] = "F12",
+	[KEY_RO] = "RO",			[KEY_KATAKANA] = "Katakana",
+	[KEY_HIRAGANA] = "HIRAGANA",		[KEY_HENKAN] = "Henkan",
+	[KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
+	[KEY_KPJPCOMMA] = "KPJpComma",		[KEY_KPENTER] = "KPEnter",
+	[KEY_RIGHTCTRL] = "RightCtrl",		[KEY_KPSLASH] = "KPSlash",
+	[KEY_SYSRQ] = "SysRq",			[KEY_RIGHTALT] = "RightAlt",
+	[KEY_LINEFEED] = "LineFeed",		[KEY_HOME] = "Home",
+	[KEY_UP] = "Up",			[KEY_PAGEUP] = "PageUp",
+	[KEY_LEFT] = "Left",			[KEY_RIGHT] = "Right",
+	[KEY_END] = "End",			[KEY_DOWN] = "Down",
+	[KEY_PAGEDOWN] = "PageDown",		[KEY_INSERT] = "Insert",
+	[KEY_DELETE] = "Delete",		[KEY_MACRO] = "Macro",
+	[KEY_MUTE] = "Mute",			[KEY_VOLUMEDOWN] = "VolumeDown",
+	[KEY_VOLUMEUP] = "VolumeUp",		[KEY_POWER] = "Power",
+	[KEY_KPEQUAL] = "KPEqual",		[KEY_KPPLUSMINUS] = "KPPlusMinus",
+	[KEY_PAUSE] = "Pause",			[KEY_KPCOMMA] = "KPComma",
+	[KEY_HANGUEL] = "Hanguel",		[KEY_HANJA] = "Hanja",
+	[KEY_YEN] = "Yen",			[KEY_LEFTMETA] = "LeftMeta",
+	[KEY_RIGHTMETA] = "RightMeta",		[KEY_COMPOSE] = "Compose",
+	[KEY_STOP] = "Stop",			[KEY_AGAIN] = "Again",
+	[KEY_PROPS] = "Props",			[KEY_UNDO] = "Undo",
+	[KEY_FRONT] = "Front",			[KEY_COPY] = "Copy",
+	[KEY_OPEN] = "Open",			[KEY_PASTE] = "Paste",
+	[KEY_FIND] = "Find",			[KEY_CUT] = "Cut",
+	[KEY_HELP] = "Help",			[KEY_MENU] = "Menu",
+	[KEY_CALC] = "Calc",			[KEY_SETUP] = "Setup",
+	[KEY_SLEEP] = "Sleep",			[KEY_WAKEUP] = "WakeUp",
+	[KEY_FILE] = "File",			[KEY_SENDFILE] = "SendFile",
+	[KEY_DELETEFILE] = "DeleteFile",	[KEY_XFER] = "X-fer",
+	[KEY_PROG1] = "Prog1",			[KEY_PROG2] = "Prog2",
+	[KEY_WWW] = "WWW",			[KEY_MSDOS] = "MSDOS",
+	[KEY_COFFEE] = "Coffee",		[KEY_DIRECTION] = "Direction",
+	[KEY_CYCLEWINDOWS] = "CycleWindows",	[KEY_MAIL] = "Mail",
+	[KEY_BOOKMARKS] = "Bookmarks",		[KEY_COMPUTER] = "Computer",
+	[KEY_BACK] = "Back",			[KEY_FORWARD] = "Forward",
+	[KEY_CLOSECD] = "CloseCD",		[KEY_EJECTCD] = "EjectCD",
+	[KEY_EJECTCLOSECD] = "EjectCloseCD",	[KEY_NEXTSONG] = "NextSong",
+	[KEY_PLAYPAUSE] = "PlayPause",		[KEY_PREVIOUSSONG] = "PreviousSong",
+	[KEY_STOPCD] = "StopCD",		[KEY_RECORD] = "Record",
+	[KEY_REWIND] = "Rewind",		[KEY_PHONE] = "Phone",
+	[KEY_ISO] = "ISOKey",			[KEY_CONFIG] = "Config",
+	[KEY_HOMEPAGE] = "HomePage",		[KEY_REFRESH] = "Refresh",
+	[KEY_EXIT] = "Exit",			[KEY_MOVE] = "Move",
+	[KEY_EDIT] = "Edit",			[KEY_SCROLLUP] = "ScrollUp",
+	[KEY_SCROLLDOWN] = "ScrollDown",	[KEY_KPLEFTPAREN] = "KPLeftParenthesis",
+	[KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_F13] = "F13",
+	[KEY_F14] = "F14",			[KEY_F15] = "F15",
+	[KEY_F16] = "F16",			[KEY_F17] = "F17",
+	[KEY_F18] = "F18",			[KEY_F19] = "F19",
+	[KEY_F20] = "F20",			[KEY_F21] = "F21",
+	[KEY_F22] = "F22",			[KEY_F23] = "F23",
+	[KEY_F24] = "F24",			[KEY_PLAYCD] = "PlayCD",
+	[KEY_PAUSECD] = "PauseCD",		[KEY_PROG3] = "Prog3",
+	[KEY_PROG4] = "Prog4",			[KEY_SUSPEND] = "Suspend",
+	[KEY_CLOSE] = "Close",			[KEY_PLAY] = "Play",
+	[KEY_FASTFORWARD] = "Fast Forward",	[KEY_BASSBOOST] = "Bass Boost",
+	[KEY_PRINT] = "Print",			[KEY_HP] = "HP",
+	[KEY_CAMERA] = "Camera",		[KEY_SOUND] = "Sound",
+	[KEY_QUESTION] = "Question",		[KEY_EMAIL] = "Email",
+	[KEY_CHAT] = "Chat",			[KEY_SEARCH] = "Search",
+	[KEY_CONNECT] = "Connect",		[KEY_FINANCE] = "Finance",
+	[KEY_SPORT] = "Sport",			[KEY_SHOP] = "Shop",
+	[KEY_ALTERASE] = "Alternate Erase",	[KEY_CANCEL] = "Cancel",
+	[KEY_BRIGHTNESSDOWN] = "Brightness down", [KEY_BRIGHTNESSUP] = "Brightness up",
+	[KEY_MEDIA] = "Media",			[KEY_UNKNOWN] = "Unknown",
+	[BTN_0] = "Btn0",			[BTN_1] = "Btn1",
+	[BTN_2] = "Btn2",			[BTN_3] = "Btn3",
+	[BTN_4] = "Btn4",			[BTN_5] = "Btn5",
+	[BTN_6] = "Btn6",			[BTN_7] = "Btn7",
+	[BTN_8] = "Btn8",			[BTN_9] = "Btn9",
+	[BTN_LEFT] = "LeftBtn",			[BTN_RIGHT] = "RightBtn",
+	[BTN_MIDDLE] = "MiddleBtn",		[BTN_SIDE] = "SideBtn",
+	[BTN_EXTRA] = "ExtraBtn",		[BTN_FORWARD] = "ForwardBtn",
+	[BTN_BACK] = "BackBtn",			[BTN_TASK] = "TaskBtn",
+	[BTN_TRIGGER] = "Trigger",		[BTN_THUMB] = "ThumbBtn",
+	[BTN_THUMB2] = "ThumbBtn2",		[BTN_TOP] = "TopBtn",
+	[BTN_TOP2] = "TopBtn2",			[BTN_PINKIE] = "PinkieBtn",
+	[BTN_BASE] = "BaseBtn",			[BTN_BASE2] = "BaseBtn2",
+	[BTN_BASE3] = "BaseBtn3",		[BTN_BASE4] = "BaseBtn4",
+	[BTN_BASE5] = "BaseBtn5",		[BTN_BASE6] = "BaseBtn6",
+	[BTN_DEAD] = "BtnDead",			[BTN_A] = "BtnA",
+	[BTN_B] = "BtnB",			[BTN_C] = "BtnC",
+	[BTN_X] = "BtnX",			[BTN_Y] = "BtnY",
+	[BTN_Z] = "BtnZ",			[BTN_TL] = "BtnTL",
+	[BTN_TR] = "BtnTR",			[BTN_TL2] = "BtnTL2",
+	[BTN_TR2] = "BtnTR2",			[BTN_SELECT] = "BtnSelect",
+	[BTN_START] = "BtnStart",		[BTN_MODE] = "BtnMode",
+	[BTN_THUMBL] = "BtnThumbL",		[BTN_THUMBR] = "BtnThumbR",
+	[BTN_TOOL_PEN] = "ToolPen",		[BTN_TOOL_RUBBER] = "ToolRubber",
+	[BTN_TOOL_BRUSH] = "ToolBrush",		[BTN_TOOL_PENCIL] = "ToolPencil",
+	[BTN_TOOL_AIRBRUSH] = "ToolAirbrush",	[BTN_TOOL_FINGER] = "ToolFinger",
+	[BTN_TOOL_MOUSE] = "ToolMouse",		[BTN_TOOL_LENS] = "ToolLens",
+	[BTN_TOUCH] = "Touch",			[BTN_STYLUS] = "Stylus",
+	[BTN_STYLUS2] = "Stylus2",		[BTN_TOOL_DOUBLETAP] = "Tool Doubletap",
+	[BTN_TOOL_TRIPLETAP] = "Tool Tripletap", [BTN_GEAR_DOWN] = "WheelBtn",
+	[BTN_GEAR_UP] = "Gear up",		[KEY_OK] = "Ok",
+	[KEY_SELECT] = "Select",		[KEY_GOTO] = "Goto",
+	[KEY_CLEAR] = "Clear",			[KEY_POWER2] = "Power2",
+	[KEY_OPTION] = "Option",		[KEY_INFO] = "Info",
+	[KEY_TIME] = "Time",			[KEY_VENDOR] = "Vendor",
+	[KEY_ARCHIVE] = "Archive",		[KEY_PROGRAM] = "Program",
+	[KEY_CHANNEL] = "Channel",		[KEY_FAVORITES] = "Favorites",
+	[KEY_EPG] = "EPG",			[KEY_PVR] = "PVR",
+	[KEY_MHP] = "MHP",			[KEY_LANGUAGE] = "Language",
+	[KEY_TITLE] = "Title",			[KEY_SUBTITLE] = "Subtitle",
+	[KEY_ANGLE] = "Angle",			[KEY_ZOOM] = "Zoom",
+	[KEY_MODE] = "Mode",			[KEY_KEYBOARD] = "Keyboard",
+	[KEY_SCREEN] = "Screen",		[KEY_PC] = "PC",
+	[KEY_TV] = "TV",			[KEY_TV2] = "TV2",
+	[KEY_VCR] = "VCR",			[KEY_VCR2] = "VCR2",
+	[KEY_SAT] = "Sat",			[KEY_SAT2] = "Sat2",
+	[KEY_CD] = "CD",			[KEY_TAPE] = "Tape",
+	[KEY_RADIO] = "Radio",			[KEY_TUNER] = "Tuner",
+	[KEY_PLAYER] = "Player",		[KEY_TEXT] = "Text",
+	[KEY_DVD] = "DVD",			[KEY_AUX] = "Aux",
+	[KEY_MP3] = "MP3",			[KEY_AUDIO] = "Audio",
+	[KEY_VIDEO] = "Video",			[KEY_DIRECTORY] = "Directory",
+	[KEY_LIST] = "List",			[KEY_MEMO] = "Memo",
+	[KEY_CALENDAR] = "Calendar",		[KEY_RED] = "Red",
+	[KEY_GREEN] = "Green",			[KEY_YELLOW] = "Yellow",
+	[KEY_BLUE] = "Blue",			[KEY_CHANNELUP] = "ChannelUp",
+	[KEY_CHANNELDOWN] = "ChannelDown",	[KEY_FIRST] = "First",
+	[KEY_LAST] = "Last",			[KEY_AB] = "AB",
+	[KEY_NEXT] = "Next",			[KEY_RESTART] = "Restart",
+	[KEY_SLOW] = "Slow",			[KEY_SHUFFLE] = "Shuffle",
+	[KEY_BREAK] = "Break",			[KEY_PREVIOUS] = "Previous",
+	[KEY_DIGITS] = "Digits",		[KEY_TEEN] = "TEEN",
+	[KEY_TWEN] = "TWEN",			[KEY_DEL_EOL] = "Delete EOL",
+	[KEY_DEL_EOS] = "Delete EOS",		[KEY_INS_LINE] = "Insert line",
+	[KEY_DEL_LINE] = "Delete line",
+};
+
+static char *absval[5] = { "Value", "Min  ", "Max  ", "Fuzz ", "Flat " };
+
+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", 
+	[REL_MISC] = "Misc",	
+};
+
+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",
+	[ABS_THROTTLE] = "Throttle",	[ABS_RUDDER] = "Rudder",
+	[ABS_WHEEL] = "Wheel",		[ABS_GAS] = "Gas",
+	[ABS_BRAKE] = "Brake",		[ABS_HAT0X] = "Hat0X",
+	[ABS_HAT0Y] = "Hat0Y",		[ABS_HAT1X] = "Hat1X",
+	[ABS_HAT1Y] = "Hat1Y",		[ABS_HAT2X] = "Hat2X",
+	[ABS_HAT2Y] = "Hat2Y",		[ABS_HAT3X] = "Hat3X",
+	[ABS_HAT3Y] = "Hat 3Y",		[ABS_PRESSURE] = "Pressure",
+	[ABS_DISTANCE] = "Distance",	[ABS_TILT_X] = "XTilt",
+	[ABS_TILT_Y] = "YTilt",		[ABS_TOOL_WIDTH] = "Tool Width",
+	[ABS_VOLUME] = "Volume",	[ABS_MISC] = "Misc",
+};
+
+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", 
+	[LED_SUSPEND] = "Suspend",	[LED_MUTE] = "Mute",
+	[LED_MISC] = "Misc",
+};
+
+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) {
+
+	printk("%s.%s", events[type] ? events[type] : "?",
+		names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
 }
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c	2004-09-23 21:12:57 -07:00
+++ b/drivers/usb/input/hid-input.c	2004-09-23 21:12:57 -07:00
@@ -32,6 +32,8 @@
 #include &lt;linux/input.h&gt;
 #include &lt;linux/usb.h&gt;
 
+#undef DEBUG
+
 #include "hid.h"
 
 #define unk	KEY_UNKNOWN
@@ -60,114 +62,130 @@
 	__s32 y;
 }  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
 
-static struct input_dev *find_input(struct hid_device *hid, struct hid_field *field)
-{
-	struct list_head *lh;
-	struct hid_input *hidinput;
-
-	list_for_each (lh, &amp;hid-&gt;inputs) {
-		int i;
-
-		hidinput = list_entry(lh, struct hid_input, list);
-
-		if (! hidinput-&gt;report)
-			continue;
-
-		for (i = 0; i &lt; hidinput-&gt;report-&gt;maxfield; i++)
-			if (hidinput-&gt;report-&gt;field[i] == field)
-				return &amp;hidinput-&gt;input;
-	}
-
-	/* Assume we only have one input and use it */
-	if (!list_empty(&amp;hid-&gt;inputs)) {
-		hidinput = list_entry(hid-&gt;inputs.next, struct hid_input, list);
-		return &amp;hidinput-&gt;input;
-	}
-
-	/* This is really a bug */
-	return NULL;
-}
+#define map_abs(c)	do { usage-&gt;code = c; usage-&gt;type = EV_ABS; bit = input-&gt;absbit; max = ABS_MAX; } while (0)
+#define map_rel(c)	do { usage-&gt;code = c; usage-&gt;type = EV_REL; bit = input-&gt;relbit; max = REL_MAX; } while (0)
+#define map_key(c)	do { usage-&gt;code = c; usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX; } while (0)
+#define map_led(c)	do { usage-&gt;code = c; usage-&gt;type = EV_LED; bit = input-&gt;ledbit; max = LED_MAX; } while (0)
+#define map_ff(c)	do { usage-&gt;code = c; usage-&gt;type = EV_FF;  bit = input-&gt;ffbit;  max =  FF_MAX; } while (0)
+
+#define map_abs_clear(c)	do { map_abs(c); clear_bit(c, bit); } while (0)
+#define map_key_clear(c)	do { map_key(c); clear_bit(c, bit); } while (0)
+#define map_ff_effect(c)	do { set_bit(c, input-&gt;ffbit); } while (0)
 
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
 				     struct hid_usage *usage)
 {
 	struct input_dev *input = &amp;hidinput-&gt;input;
 	struct hid_device *device = hidinput-&gt;input.private;
-	int max;
-	int is_abs = 0;
+	int max, code;
 	unsigned long *bit;
 
+	field-&gt;hidinput = hidinput;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "Mapping: ");
+	resolv_usage(usage-&gt;hid);
+	printk(" ---&gt; ");
+#endif
+
+	if (field-&gt;flags &amp; HID_MAIN_ITEM_CONSTANT)
+		goto ignore;
+
 	switch (usage-&gt;hid &amp; HID_USAGE_PAGE) {
 
+		case HID_UP_UNDEFINED:
+			goto ignore;
+
 		case HID_UP_KEYBOARD:
 
 			set_bit(EV_REP, input-&gt;evbit);
-			usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
 
 			if ((usage-&gt;hid &amp; HID_USAGE) &lt; 256) {
-				if (!(usage-&gt;code = hid_keyboard[usage-&gt;hid &amp; HID_USAGE]))
-					return;
-				clear_bit(usage-&gt;code, bit);
+				if (!hid_keyboard[usage-&gt;hid &amp; HID_USAGE]) goto ignore;
+				map_key_clear(hid_keyboard[usage-&gt;hid &amp; HID_USAGE]);
 			} else
-				usage-&gt;code = KEY_UNKNOWN;
+				map_key(KEY_UNKNOWN);
 
 			break;
 
 		case HID_UP_BUTTON:
 
-			usage-&gt;code = ((usage-&gt;hid - 1) &amp; 0xf) + 0x100;
-			usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
+			code = ((usage-&gt;hid - 1) &amp; 0xf);
 
 			switch (field-&gt;application) {
-				case HID_GD_GAMEPAD:  usage-&gt;code += 0x10;
-				case HID_GD_JOYSTICK: usage-&gt;code += 0x10;
-				case HID_GD_MOUSE:    usage-&gt;code += 0x10; break;
+				case HID_GD_MOUSE:
+				case HID_GD_POINTER:  code += 0x110; break;
+				case HID_GD_JOYSTICK: code += 0x120; break;
+				case HID_GD_GAMEPAD:  code += 0x130; break;
 				default:
-					if (field-&gt;physical == HID_GD_POINTER)
-						usage-&gt;code += 0x10;
-					break;
+					switch (field-&gt;physical) {
+						case HID_GD_MOUSE:
+						case HID_GD_POINTER:  code += 0x110; break;
+						case HID_GD_JOYSTICK: code += 0x120; break;
+						case HID_GD_GAMEPAD:  code += 0x130; break;
+						default:              code += 0x100;
+					}
 			}
+
+			map_key(code);
 			break;
 
 		case HID_UP_GENDESK:
 
 			if ((usage-&gt;hid &amp; 0xf0) == 0x80) {	/* SystemControl */
 				switch (usage-&gt;hid &amp; 0xf) {
-					case 0x1: usage-&gt;code = KEY_POWER;  break;
-					case 0x2: usage-&gt;code = KEY_SLEEP;  break;
-					case 0x3: usage-&gt;code = KEY_WAKEUP; break;
-					default: usage-&gt;code = KEY_UNKNOWN; break;
+					case 0x1: map_key_clear(KEY_POWER);  break;
+					case 0x2: map_key_clear(KEY_SLEEP);  break;
+					case 0x3: map_key_clear(KEY_WAKEUP); break;
+					default: goto unknown;
 				}
-				usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
 				break;
 			}
 
-			usage-&gt;code = usage-&gt;hid &amp; 0xf;
-
-			if (field-&gt;report_size == 1) {
-				usage-&gt;code = BTN_MISC;
-				usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
+			if ((usage-&gt;hid &amp; 0xf0) == 0x90) {	/* D-pad */
+				switch (usage-&gt;hid) {
+					case HID_GD_UP:	   usage-&gt;hat_dir = 1; break;
+					case HID_GD_DOWN:  usage-&gt;hat_dir = 5; break;
+					case HID_GD_RIGHT: usage-&gt;hat_dir = 3; break;
+					case HID_GD_LEFT:  usage-&gt;hat_dir = 7; break;
+					default: goto unknown;
+				}
+				if (field-&gt;dpad) {
+					map_abs(field-&gt;dpad);
+					goto ignore;
+				}
+				map_abs(ABS_HAT0X);
 				break;
 			}
 
-			if (field-&gt;flags &amp; HID_MAIN_ITEM_RELATIVE) {
-				usage-&gt;type = EV_REL; bit = input-&gt;relbit; max = REL_MAX;
-				break;
-			}
+			switch (usage-&gt;hid) {
 
-			usage-&gt;type = EV_ABS; bit = input-&gt;absbit; max = ABS_MAX;
+				/* These usage IDs map directly to the usage codes. */
+				case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
+				case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
+				case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
+					if (field-&gt;flags &amp; HID_MAIN_ITEM_RELATIVE) 
+						map_rel(usage-&gt;hid &amp; 0xf);
+					else
+						map_abs(usage-&gt;hid &amp; 0xf);
+					break;
 
-			if (usage-&gt;hid == HID_GD_HATSWITCH) {
-				usage-&gt;code = ABS_HAT0X;
-				usage-&gt;hat_min = field-&gt;logical_minimum;
-				usage-&gt;hat_max = field-&gt;logical_maximum;
+				case HID_GD_HATSWITCH:
+					usage-&gt;hat_min = field-&gt;logical_minimum;
+					usage-&gt;hat_max = field-&gt;logical_maximum;
+					map_abs(ABS_HAT0X);
+					break;
+
+				case HID_GD_START:	map_key_clear(BTN_START);	break;
+				case HID_GD_SELECT:	map_key_clear(BTN_SELECT);	break;
+
+				default: goto unknown;
 			}
+
 			break;
 
 		case HID_UP_LED:
-
-			usage-&gt;code = (usage-&gt;hid - 1) &amp; 0xf;
-			usage-&gt;type = EV_LED; bit = input-&gt;ledbit; max = LED_MAX;
+			map_led((usage-&gt;hid - 1) &amp; 0xf);
 			break;
 
 		case HID_UP_DIGITIZER:
@@ -175,49 +193,36 @@
 			switch (usage-&gt;hid &amp; 0xff) {
 
 				case 0x30: /* TipPressure */
-
 					if (!test_bit(BTN_TOUCH, input-&gt;keybit)) {
 						device-&gt;quirks |= HID_QUIRK_NOTOUCH;
 						set_bit(EV_KEY, input-&gt;evbit);
 						set_bit(BTN_TOUCH, input-&gt;keybit);
 					}
-					usage-&gt;type = EV_ABS; bit = input-&gt;absbit; max = ABS_MAX;
-					usage-&gt;code = ABS_PRESSURE;
-					clear_bit(usage-&gt;code, bit);
+
+					map_abs_clear(ABS_PRESSURE);
 					break;
 
 				case 0x32: /* InRange */
-
-					usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
 					switch (field-&gt;physical &amp; 0xff) {
-						case 0x21: usage-&gt;code = BTN_TOOL_MOUSE; break;
-						case 0x22: usage-&gt;code = BTN_TOOL_FINGER; break;
-						default: usage-&gt;code = BTN_TOOL_PEN; break;
+						case 0x21: map_key(BTN_TOOL_MOUSE); break;
+						case 0x22: map_key(BTN_TOOL_FINGER); break;
+						default: map_key(BTN_TOOL_PEN); break;
 					}
 					break;
 
 				case 0x3c: /* Invert */
-
-					usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
-					usage-&gt;code = BTN_TOOL_RUBBER;
-					clear_bit(usage-&gt;code, bit);
+					map_key_clear(BTN_TOOL_RUBBER);
 					break;
 
 				case 0x33: /* Touch */
 				case 0x42: /* TipSwitch */
 				case 0x43: /* TipSwitch2 */
-
 					device-&gt;quirks &amp;= ~HID_QUIRK_NOTOUCH;
-					usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
-					usage-&gt;code = BTN_TOUCH;
-					clear_bit(usage-&gt;code, bit);
+					map_key_clear(BTN_TOUCH);
 					break;
 
 				case 0x44: /* BarrelSwitch */
-
-					usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
-					usage-&gt;code = BTN_STYLUS;
-					clear_bit(usage-&gt;code, bit);
+					map_key_clear(BTN_STYLUS);
 					break;
 
 				default:  goto unknown;
@@ -228,54 +233,42 @@
 
 			set_bit(EV_REP, input-&gt;evbit);
 			switch (usage-&gt;hid &amp; HID_USAGE) {
-				case 0x000: usage-&gt;code = 0; break;
-				case 0x034: usage-&gt;code = KEY_SLEEP;		break;
-				case 0x036: usage-&gt;code = BTN_MISC;		break;
-				case 0x08a: usage-&gt;code = KEY_WWW;		break;
-				case 0x095: usage-&gt;code = KEY_HELP;		break;
-
-				case 0x0b0: usage-&gt;code = KEY_PLAY;		break;
-				case 0x0b1: usage-&gt;code = KEY_PAUSE;		break;
-				case 0x0b2: usage-&gt;code = KEY_RECORD;		break;
-				case 0x0b3: usage-&gt;code = KEY_FASTFORWARD;	break;
-				case 0x0b4: usage-&gt;code = KEY_REWIND;		break;
-				case 0x0b5: usage-&gt;code = KEY_NEXTSONG;		break;
-				case 0x0b6: usage-&gt;code = KEY_PREVIOUSSONG;	break;
-				case 0x0b7: usage-&gt;code = KEY_STOPCD;		break;
-				case 0x0b8: usage-&gt;code = KEY_EJECTCD;		break;
-				case 0x0cd: usage-&gt;code = KEY_PLAYPAUSE;	break;
-			        case 0x0e0: is_abs = 1;
-					    usage-&gt;code = ABS_VOLUME;
-					    break;
-				case 0x0e2: usage-&gt;code = KEY_MUTE;		break;
-				case 0x0e5: usage-&gt;code = KEY_BASSBOOST;	break;
-				case 0x0e9: usage-&gt;code = KEY_VOLUMEUP;		break;
-				case 0x0ea: usage-&gt;code = KEY_VOLUMEDOWN;	break;
-
-				case 0x183: usage-&gt;code = KEY_CONFIG;		break;
-				case 0x18a: usage-&gt;code = KEY_MAIL;		break;
-				case 0x192: usage-&gt;code = KEY_CALC;		break;
-				case 0x194: usage-&gt;code = KEY_FILE;		break;
-				case 0x21a: usage-&gt;code = KEY_UNDO;		break;
-				case 0x21b: usage-&gt;code = KEY_COPY;		break;
-				case 0x21c: usage-&gt;code = KEY_CUT;		break;
-				case 0x21d: usage-&gt;code = KEY_PASTE;		break;
-
-				case 0x221: usage-&gt;code = KEY_FIND;		break;
-				case 0x223: usage-&gt;code = KEY_HOMEPAGE;		break;
-				case 0x224: usage-&gt;code = KEY_BACK;		break;
-				case 0x225: usage-&gt;code = KEY_FORWARD;		break;
-				case 0x226: usage-&gt;code = KEY_STOP;		break;
-				case 0x227: usage-&gt;code = KEY_REFRESH;		break;
-				case 0x22a: usage-&gt;code = KEY_BOOKMARKS;	break;
-
-				default:    usage-&gt;code = KEY_UNKNOWN;		break;
-			}
-
-			if (is_abs) {
-			        usage-&gt;type = EV_ABS; bit = input-&gt;absbit; max = ABS_MAX;
-			} else  {
-				usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
+				case 0x000: goto ignore;
+				case 0x034: map_key_clear(KEY_SLEEP);		break;
+				case 0x036: map_key_clear(BTN_MISC);		break;
+				case 0x08a: map_key_clear(KEY_WWW);		break;
+				case 0x095: map_key_clear(KEY_HELP);		break;
+				case 0x0b0: map_key_clear(KEY_PLAY);		break;
+				case 0x0b1: map_key_clear(KEY_PAUSE);		break;
+				case 0x0b2: map_key_clear(KEY_RECORD);		break;
+				case 0x0b3: map_key_clear(KEY_FASTFORWARD);	break;
+				case 0x0b4: map_key_clear(KEY_REWIND);		break;
+				case 0x0b5: map_key_clear(KEY_NEXTSONG);	break;
+				case 0x0b6: map_key_clear(KEY_PREVIOUSSONG);	break;
+				case 0x0b7: map_key_clear(KEY_STOPCD);		break;
+				case 0x0b8: map_key_clear(KEY_EJECTCD);		break;
+				case 0x0cd: map_key_clear(KEY_PLAYPAUSE);	break;
+			        case 0x0e0: map_abs_clear(ABS_VOLUME);		break;
+				case 0x0e2: map_key_clear(KEY_MUTE);		break;
+				case 0x0e5: map_key_clear(KEY_BASSBOOST);	break;
+				case 0x0e9: map_key_clear(KEY_VOLUMEUP);	break;
+				case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);	break;
+				case 0x183: map_key_clear(KEY_CONFIG);		break;
+				case 0x18a: map_key_clear(KEY_MAIL);		break;
+				case 0x192: map_key_clear(KEY_CALC);		break;
+				case 0x194: map_key_clear(KEY_FILE);		break;
+				case 0x21a: map_key_clear(KEY_UNDO);		break;
+				case 0x21b: map_key_clear(KEY_COPY);		break;
+				case 0x21c: map_key_clear(KEY_CUT);		break;
+				case 0x21d: map_key_clear(KEY_PASTE);		break;
+				case 0x221: map_key_clear(KEY_FIND);		break;
+				case 0x223: map_key_clear(KEY_HOMEPAGE);	break;
+				case 0x224: map_key_clear(KEY_BACK);		break;
+				case 0x225: map_key_clear(KEY_FORWARD);		break;
+				case 0x226: map_key_clear(KEY_STOP);		break;
+				case 0x227: map_key_clear(KEY_REFRESH);		break;
+				case 0x22a: map_key_clear(KEY_BOOKMARKS);	break;
+				default:    goto unknown;
 			}
 			break;
 
@@ -283,114 +276,82 @@
 
 			set_bit(EV_REP, input-&gt;evbit);
 			switch (usage-&gt;hid &amp; HID_USAGE) {
-			        case 0x021: usage-&gt;code = KEY_PRINT;            break;
-				case 0x070: usage-&gt;code = KEY_HP;		break;
-				case 0x071: usage-&gt;code = KEY_CAMERA;		break;
-				case 0x072: usage-&gt;code = KEY_SOUND;		break;
-				case 0x073: usage-&gt;code = KEY_QUESTION;		break;
-
-				case 0x080: usage-&gt;code = KEY_EMAIL;		break;
-				case 0x081: usage-&gt;code = KEY_CHAT;		break;
-				case 0x082: usage-&gt;code = KEY_SEARCH;		break;
-				case 0x083: usage-&gt;code = KEY_CONNECT;	        break;
-				case 0x084: usage-&gt;code = KEY_FINANCE;		break;
-				case 0x085: usage-&gt;code = KEY_SPORT;		break;
-				case 0x086: usage-&gt;code = KEY_SHOP;	        break;
-
-				default:    usage-&gt;code = KEY_UNKNOWN;		break;
-
+			        case 0x021: map_key_clear(KEY_PRINT);           break;
+				case 0x070: map_key_clear(KEY_HP);		break;
+				case 0x071: map_key_clear(KEY_CAMERA);		break;
+				case 0x072: map_key_clear(KEY_SOUND);		break;
+				case 0x073: map_key_clear(KEY_QUESTION);	break;
+				case 0x080: map_key_clear(KEY_EMAIL);		break;
+				case 0x081: map_key_clear(KEY_CHAT);		break;
+				case 0x082: map_key_clear(KEY_SEARCH);		break;
+				case 0x083: map_key_clear(KEY_CONNECT);	        break;
+				case 0x084: map_key_clear(KEY_FINANCE);		break;
+				case 0x085: map_key_clear(KEY_SPORT);		break;
+				case 0x086: map_key_clear(KEY_SHOP);	        break;
+				default:    goto unknown;
 			}
-
-			usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
 			break;
 			
 		case HID_UP_PID:
 
-			usage-&gt;type = EV_FF; bit = input-&gt;ffbit; max = FF_MAX;
-			
+			set_bit(EV_FF, input-&gt;evbit);
 			switch(usage-&gt;hid &amp; HID_USAGE) {
-				case 0x26: set_bit(FF_CONSTANT, input-&gt;ffbit); break;
-				case 0x27: set_bit(FF_RAMP,     input-&gt;ffbit); break;
-				case 0x28: set_bit(FF_CUSTOM,   input-&gt;ffbit); break;
-				case 0x30: set_bit(FF_SQUARE,   input-&gt;ffbit);
-				           set_bit(FF_PERIODIC, input-&gt;ffbit); break;
-				case 0x31: set_bit(FF_SINE,     input-&gt;ffbit);
-				           set_bit(FF_PERIODIC, input-&gt;ffbit); break;
-				case 0x32: set_bit(FF_TRIANGLE, input-&gt;ffbit);
-				           set_bit(FF_PERIODIC, input-&gt;ffbit); break;
-				case 0x33: set_bit(FF_SAW_UP,   input-&gt;ffbit);
-				           set_bit(FF_PERIODIC, input-&gt;ffbit); break;
-				case 0x34: set_bit(FF_SAW_DOWN, input-&gt;ffbit);
-				           set_bit(FF_PERIODIC, input-&gt;ffbit); break;
-				case 0x40: set_bit(FF_SPRING,   input-&gt;ffbit); break;
-				case 0x41: set_bit(FF_DAMPER,   input-&gt;ffbit); break;
-				case 0x42: set_bit(FF_INERTIA , input-&gt;ffbit); break;
-				case 0x43: set_bit(FF_FRICTION, input-&gt;ffbit); break;
-				case 0x7e: usage-&gt;code = FF_GAIN;       break;
-				case 0x83:  /* Simultaneous Effects Max */
-					input-&gt;ff_effects_max = (field-&gt;value[0]);
-					dbg("Maximum Effects - %d",input-&gt;ff_effects_max);
-					break;
-				case 0x98:  /* Device Control */
-					usage-&gt;code = FF_AUTOCENTER;    break;
-				case 0xa4:  /* Safety Switch */
-					usage-&gt;code = BTN_DEAD;
-					bit = input-&gt;keybit;
-					usage-&gt;type = EV_KEY;
-					max = KEY_MAX;
-					dbg("Safety Switch Report\n");
-					break;
-				case 0x9f: /* Device Paused */
-				case 0xa0: /* Actuators Enabled */
-					dbg("Not telling the input API about ");
-					resolv_usage(usage-&gt;hid);
-					return;
+				case 0x26: map_ff_effect(FF_CONSTANT);	goto ignore;
+				case 0x27: map_ff_effect(FF_RAMP);	goto ignore;
+				case 0x28: map_ff_effect(FF_CUSTOM);	goto ignore;
+				case 0x30: map_ff_effect(FF_SQUARE);	map_ff_effect(FF_PERIODIC); goto ignore;
+				case 0x31: map_ff_effect(FF_SINE);	map_ff_effect(FF_PERIODIC); goto ignore;
+				case 0x32: map_ff_effect(FF_TRIANGLE);	map_ff_effect(FF_PERIODIC); goto ignore;
+				case 0x33: map_ff_effect(FF_SAW_UP);	map_ff_effect(FF_PERIODIC); goto ignore;
+				case 0x34: map_ff_effect(FF_SAW_DOWN);	map_ff_effect(FF_PERIODIC); goto ignore;
+				case 0x40: map_ff_effect(FF_SPRING);	goto ignore;
+				case 0x41: map_ff_effect(FF_DAMPER);	goto ignore;
+				case 0x42: map_ff_effect(FF_INERTIA);	goto ignore;
+				case 0x43: map_ff_effect(FF_FRICTION);	goto ignore;
+				case 0x7e: map_ff(FF_GAIN);		break;
+				case 0x83: input-&gt;ff_effects_max = field-&gt;value[0]; goto ignore;
+				case 0x98: map_ff(FF_AUTOCENTER);	break;
+				case 0xa4: map_key_clear(BTN_DEAD);	break;
+				default: goto ignore;
 			}
 			break;
+
 		default:
 		unknown:
-			resolv_usage(usage-&gt;hid);
-
 			if (field-&gt;report_size == 1) {
-
 				if (field-&gt;report-&gt;type == HID_OUTPUT_REPORT) {
-					usage-&gt;code = LED_MISC;
-					usage-&gt;type = EV_LED; bit = input-&gt;ledbit; max = LED_MAX;
+					map_led(LED_MISC);
 					break;
 				}
-
-				usage-&gt;code = BTN_MISC;
-				usage-&gt;type = EV_KEY; bit = input-&gt;keybit; max = KEY_MAX;
+				map_key(BTN_MISC);
 				break;
 			}
-
 			if (field-&gt;flags &amp; HID_MAIN_ITEM_RELATIVE) {
-				usage-&gt;code = REL_MISC;
-				usage-&gt;type = EV_REL; bit = input-&gt;relbit; max = REL_MAX;
+				map_rel(REL_MISC);
 				break;
 			}
-
-			usage-&gt;code = ABS_MISC;
-			usage-&gt;type = EV_ABS; bit = input-&gt;absbit; max = ABS_MAX;
+			map_abs(ABS_MISC);
 			break;
 	}
 
 	set_bit(usage-&gt;type, input-&gt;evbit);
-	if ((usage-&gt;type == EV_REL)
-			&amp;&amp; (device-&gt;quirks &amp; (HID_QUIRK_2WHEEL_MOUSE_HACK_BACK
-				| HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA))
-			&amp;&amp; (usage-&gt;code == REL_WHEEL)) {
-		set_bit(REL_HWHEEL, bit);
-	}
 
-	while (usage-&gt;code &lt;= max &amp;&amp; test_and_set_bit(usage-&gt;code, bit)) {
+	while (usage-&gt;code &lt;= max &amp;&amp; test_and_set_bit(usage-&gt;code, bit))
 		usage-&gt;code = find_next_zero_bit(bit, max + 1, usage-&gt;code);
-	}
 
 	if (usage-&gt;code &gt; max)
-		return;
+		goto ignore;
+
+	if ((device-&gt;quirks &amp; (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &amp;&amp;
+		 (usage-&gt;type == EV_REL) &amp;&amp; (usage-&gt;code == REL_WHEEL)) 
+			set_bit(REL_HWHEEL, bit);
+
+	if (((device-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_5) &amp;&amp; (usage-&gt;hid == 0x00090005))
+		|| ((device-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_7) &amp;&amp; (usage-&gt;hid == 0x00090007)))
+		goto ignore;
 
 	if (usage-&gt;type == EV_ABS) {
+
 		int a = field-&gt;logical_minimum;
 		int b = field-&gt;logical_maximum;
 
@@ -399,61 +360,69 @@
 			b = field-&gt;logical_maximum = 255;
 		}
 		
-		input-&gt;absmin[usage-&gt;code] = a;
-		input-&gt;absmax[usage-&gt;code] = b;
-		input-&gt;absfuzz[usage-&gt;code] = 0;
-		input-&gt;absflat[usage-&gt;code] = 0;
-
-		if (field-&gt;application == HID_GD_GAMEPAD || field-&gt;application == HID_GD_JOYSTICK) {
-			input-&gt;absfuzz[usage-&gt;code] = (b - a) &gt;&gt; 8;
-			input-&gt;absflat[usage-&gt;code] = (b - a) &gt;&gt; 4;
-		}
+		if (field-&gt;application == HID_GD_GAMEPAD || field-&gt;application == HID_GD_JOYSTICK)
+			input_set_abs_params(input, usage-&gt;code, a, b, (b - a) &gt;&gt; 8, (b - a) &gt;&gt; 4);
+		else	input_set_abs_params(input, usage-&gt;code, a, b, 0, 0);
+		
 	}
 
-	if (usage-&gt;hat_min != usage-&gt;hat_max) {
+	if (usage-&gt;hat_min &lt; usage-&gt;hat_max || usage-&gt;hat_dir) {
 		int i;
 		for (i = usage-&gt;code; i &lt; usage-&gt;code + 2 &amp;&amp; i &lt;= max; i++) {
-			input-&gt;absmax[i] = 1;
-			input-&gt;absmin[i] = -1;
-			input-&gt;absfuzz[i] = 0;
-			input-&gt;absflat[i] = 0;
+			input_set_abs_params(input, i, -1, 1, 0, 0);
+			set_bit(i, input-&gt;absbit);
 		}
-		set_bit(usage-&gt;code + 1, input-&gt;absbit);
+		if (usage-&gt;hat_dir &amp;&amp; !field-&gt;dpad)
+			field-&gt;dpad = usage-&gt;code;
 	}
+
+#ifdef DEBUG
+	resolv_event(usage-&gt;type, usage-&gt;code);
+	printk("\n");
+#endif
+	return;
+
+ignore:
+#ifdef DEBUG
+	printk("IGNORED\n");
+#endif
+	return;
 }
 
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
 {
-	struct input_dev *input = find_input(hid, field);
+	struct input_dev *input = &amp;field-&gt;hidinput-&gt;input;
 	int *quirks = &amp;hid-&gt;quirks;
 
 	if (!input)
 		return;
 
+	if (!usage-&gt;type)
+		return;
+
 	input_regs(input, regs);
 
-	if (((hid-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA) &amp;&amp; (usage-&gt;code == BTN_EXTRA))
-		|| ((hid-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_BACK) &amp;&amp; (usage-&gt;code == BTN_BACK))) {
-		if (value)
-			hid-&gt;quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-		else
-			hid-&gt;quirks &amp;= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+	if (((hid-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_5) &amp;&amp; (usage-&gt;hid == 0x00090005))
+		|| ((hid-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_7) &amp;&amp; (usage-&gt;hid == 0x00090007))) {
+		if (value) hid-&gt;quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+		else       hid-&gt;quirks &amp;= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
 		return;
 	}
 
-	if ((hid-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_ON)
-			&amp;&amp; (usage-&gt;code == REL_WHEEL)) {
+	if ((hid-&gt;quirks &amp; HID_QUIRK_2WHEEL_MOUSE_HACK_ON) &amp;&amp; (usage-&gt;code == REL_WHEEL)) {
 		input_event(input, usage-&gt;type, REL_HWHEEL, value);
 		return;
 	}
 
-	if (usage-&gt;hat_min != usage-&gt;hat_max ) { /* FIXME: hat_max can be 0 and hat_min 1 */
-		value = (value - usage-&gt;hat_min) * 8 / (usage-&gt;hat_max - usage-&gt;hat_min + 1) + 1;
-		if (value &lt; 0 || value &gt; 8) value = 0;
-		input_event(input, usage-&gt;type, usage-&gt;code    , hid_hat_to_axis[value].x);
-		input_event(input, usage-&gt;type, usage-&gt;code + 1, hid_hat_to_axis[value].y);
-		return;
-	}
+	if (usage-&gt;hat_min &lt; usage-&gt;hat_max || usage-&gt;hat_dir) { 
+		int hat_dir = usage-&gt;hat_dir;
+		if (!hat_dir)
+			hat_dir = (value - usage-&gt;hat_min) * 8 / (usage-&gt;hat_max - usage-&gt;hat_min + 1) + 1;
+		if (hat_dir &lt; 0 || hat_dir &gt; 8) hat_dir = 0;
+		input_event(input, usage-&gt;type, usage-&gt;code    , hid_hat_to_axis[hat_dir].x);
+                input_event(input, usage-&gt;type, usage-&gt;code + 1, hid_hat_to_axis[hat_dir].y);
+                return;
+        }
 
 	if (usage-&gt;hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
 		*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks &amp; ~HID_QUIRK_INVERT);
@@ -481,6 +450,7 @@
 		dbg("Maximum Effects - %d",input-&gt;ff_effects_max);
 		return;
 	}
+
 	if (usage-&gt;hid == (HID_UP_PID | 0x7fUL)) {
 		dbg("PID Pool Report\n");
 		return;
@@ -556,9 +526,10 @@
 	INIT_LIST_HEAD(&amp;hid-&gt;inputs);
 
 	for (i = 0; i &lt; hid-&gt;maxcollection; i++)
-		if (hid-&gt;collection[i].type == HID_COLLECTION_APPLICATION &amp;&amp;
-		    IS_INPUT_APPLICATION(hid-&gt;collection[i].usage))
-			break;
+		if (hid-&gt;collection[i].type == HID_COLLECTION_APPLICATION ||
+		    hid-&gt;collection[i].type == HID_COLLECTION_PHYSICAL)
+		    	if (IS_INPUT_APPLICATION(hid-&gt;collection[i].usage))
+				break;
 
 	if (i == hid-&gt;maxcollection)
 		return -1;
diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h	2004-09-23 21:12:57 -07:00
+++ b/drivers/usb/input/hid.h	2004-09-23 21:12:57 -07:00
@@ -171,6 +171,7 @@
 
 #define HID_USAGE_PAGE		0xffff0000
 
+#define HID_UP_UNDEFINED	0x00000000
 #define HID_UP_GENDESK 		0x00010000
 #define HID_UP_KEYBOARD 	0x00070000
 #define HID_UP_LED 		0x00080000
@@ -187,7 +188,36 @@
 #define HID_GD_MOUSE		0x00010002
 #define HID_GD_JOYSTICK		0x00010004
 #define HID_GD_GAMEPAD		0x00010005
+#define HID_GD_KEYBOARD		0x00010006
+#define HID_GD_KEYPAD		0x00010007
+#define HID_GD_MULTIAXIS	0x00010008
+#define HID_GD_X		0x00010030
+#define HID_GD_Y		0x00010031
+#define HID_GD_Z		0x00010032
+#define HID_GD_RX		0x00010033
+#define HID_GD_RY		0x00010034
+#define HID_GD_RZ		0x00010035
+#define HID_GD_SLIDER		0x00010036
+#define HID_GD_DIAL		0x00010037
+#define HID_GD_WHEEL		0x00010038
 #define HID_GD_HATSWITCH	0x00010039
+#define HID_GD_BUFFER		0x0001003a
+#define HID_GD_BYTECOUNT	0x0001003b
+#define HID_GD_MOTION		0x0001003c
+#define HID_GD_START		0x0001003d
+#define HID_GD_SELECT		0x0001003e
+#define HID_GD_VX		0x00010040
+#define HID_GD_VY		0x00010041
+#define HID_GD_VZ		0x00010042
+#define HID_GD_VBRX		0x00010043
+#define HID_GD_VBRY		0x00010044
+#define HID_GD_VBRZ		0x00010045
+#define HID_GD_VNO		0x00010046
+#define HID_GD_FEATURE		0x00010047
+#define HID_GD_UP		0x00010090
+#define HID_GD_DOWN		0x00010091
+#define HID_GD_RIGHT		0x00010092
+#define HID_GD_LEFT		0x00010093
 
 /*
  * HID report types --- Ouch! HID spec says 1 2 3!
@@ -208,8 +238,8 @@
 #define HID_QUIRK_HIDDEV			0x010
 #define HID_QUIRK_BADPAD			0x020
 #define HID_QUIRK_MULTI_INPUT			0x040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_BACK	0x080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA	0x100
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_7		0x080
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_5		0x100
 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON		0x200
 
 /*
@@ -262,12 +292,16 @@
 struct hid_usage {
 	unsigned  hid;			/* hid usage code */
 	unsigned  collection_index;	/* index into collection array */
+	/* hidinput data */
 	__u16     code;			/* input driver code */
 	__u8      type;			/* input driver type */
 	__s8	  hat_min;		/* hat switch fun */
 	__s8	  hat_max;		/* ditto */
+	__s8	  hat_dir;		/* ditto */
 };
 
+struct hid_input;
+
 struct hid_field {
 	unsigned  physical;		/* physical usage for this field */
 	unsigned  logical;		/* logical usage for this field */
@@ -288,6 +322,9 @@
 	unsigned  unit;
 	struct hid_report *report;	/* associated report */
 	unsigned index;			/* index into report-&gt;field[] */
+	/* hidinput data */
+	struct hid_input *hidinput;	/* associated input structure */
+	__u16 dpad;			/* dpad input code */
 };
 
 #define HID_MAX_FIELDS 64
@@ -423,6 +460,7 @@
 #define hid_dump_device(c)	do { } while (0)
 #define hid_dump_field(a,b)	do { } while (0)
 #define resolv_usage(a)		do { } while (0)
+#define resolv_event(a,b)	do { } while (0)
 #endif
 
 #endif
@@ -430,7 +468,7 @@
 #ifdef CONFIG_USB_HIDINPUT
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
-#define IS_INPUT_APPLICATION(a) (((a &gt;= 0x00010000) &amp;&amp; (a &lt;= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001))
+#define IS_INPUT_APPLICATION(a) (((a &gt;= 0x00010000) &amp;&amp; (a &lt;= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
 extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32, struct pt_regs *regs);
 extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
 extern int hidinput_connect(struct hid_device *);
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	2004-09-23 21:12:57 -07:00
+++ b/include/linux/input.h	2004-09-23 21:12:57 -07:00
@@ -482,6 +482,9 @@
 #define REL_X			0x00
 #define REL_Y			0x01
 #define REL_Z			0x02
+#define REL_RX			0x03
+#define REL_RY			0x04
+#define REL_RZ			0x05
 #define REL_HWHEEL		0x06
 #define REL_DIAL		0x07
 #define REL_WHEEL		0x08
diff -Nru a/include/linux/libps2.h b/include/linux/libps2.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/libps2.h	2004-09-23 21:12:57 -07:00
@@ -0,0 +1,50 @@
+#ifndef _LIBPS2_H
+#define _LIBPS2_H
+
+/*
+ * Copyright (C) 1999-2002 Vojtech Pavlik
+ * Copyright (C) 2004 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+
+#define PS2_CMD_GETID		0x02f2
+#define PS2_CMD_RESET_BAT	0x02ff
+
+#define PS2_RET_BAT		0xaa
+#define PS2_RET_ID		0x00
+#define PS2_RET_ACK		0xfa
+#define PS2_RET_NAK		0xfe
+
+#define PS2_FLAG_ACK		1	/* Waiting for ACK/NAK */
+#define PS2_FLAG_CMD		2	/* Waiting for command to finish */
+#define PS2_FLAG_CMD1		4	/* Waiting for the first byte of command response */
+#define PS2_FLAG_WAITID		8	/* Command execiting is GET ID */
+
+struct ps2dev {
+	struct serio *serio;
+
+	/* Ensures that only one command is executing at a time */
+	struct semaphore cmd_sem;
+
+	/* Used to signal completion from interrupt handler */
+	wait_queue_head_t wait;
+
+	unsigned long flags;
+	unsigned char cmdbuf[6];
+	unsigned char cmdcnt;
+	unsigned char nak;
+};
+
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
+int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte);
+int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
+int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command);
+int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
+int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);
+void ps2_cmd_aborted(struct ps2dev *ps2dev);
+
+#endif /* _LIBPS2_H */
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	2004-09-23 21:12:57 -07:00
+++ b/include/linux/serio.h	2004-09-23 21:12:57 -07:00
@@ -45,7 +45,8 @@
 
 	struct serio *parent, *child;
 
-	struct serio_driver *drv;	/* accessed from interrupt, must be protected by serio-&gt;lock */
+	struct serio_driver *drv;	/* accessed from interrupt, must be protected by serio-&gt;lock and serio-&gt;sem */
+	struct semaphore drv_sem;	/* protects serio-&gt;drv so attributes can pin driver */
 
 	struct device dev;
 
@@ -120,6 +121,19 @@
 static __inline__ void serio_continue_rx(struct serio *serio)
 {
 	spin_unlock_irq(&amp;serio-&gt;lock);
+}
+
+/*
+ * Use the following fucntions to pin serio's driver in process context
+ */
+static __inline__ int serio_pin_driver(struct serio *serio)
+{
+	return down_interruptible(&amp;serio-&gt;drv_sem);
+}
+
+static __inline__ void serio_unpin_driver(struct serio *serio)
+{
+	up(&amp;serio-&gt;drv_sem);
 }
 
 
</pre></body></html>