bk://kernel.bkbits.net/vojtech/input
vojtech@suse.cz|ChangeSet|20041118110601|12542 vojtech

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/12/01 21:19:26-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# Documentation/kernel-parameters.txt
#   2004/12/01 21:19:22-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/12/01 01:16:30-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# drivers/usb/input/hid-core.c
#   2004/12/01 01:16:26-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/19 20:21:09-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-input
# 
# Documentation/kernel-parameters.txt
#   2004/11/19 20:21:04-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/18 12:06:01+01:00 vojtech@suse.cz 
#   Manual merge
# 
# drivers/usb/input/hid-core.c
#   2004/11/18 12:05:54+01:00 vojtech@suse.cz +5 -4
#   Manual merge
# 
# drivers/input/serio/serio.c
#   2004/11/18 11:50:15+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# drivers/input/serio/i8042.c
#   2004/11/18 11:50:15+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# drivers/input/input.c
#   2004/11/18 11:50:15+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/11/18 11:50:15+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/10 16:28:17-08:00 torvalds@ppc970.osdl.org 
#   Fix the fix.
#   
#   Silly #endif placement problem.
# 
# arch/i386/kernel/io_apic.c
#   2004/11/10 16:28:10-08:00 torvalds@ppc970.osdl.org +1 -1
#   Fix the fix.
#   
#   Silly #endif placement problem.
# 
# ChangeSet
#   2004/11/10 16:25:01-08:00 acme@conectiva.com.br 
#   [PATCH] fix  platform_rename_gsi related ia32 build breakage
#   
#   "platform_rename_gsi" does not exist unless CONFIG_ACPI_BOOT is defined.
# 
# arch/i386/kernel/io_apic.c
#   2004/11/10 15:58:57-08:00 acme@conectiva.com.br +2 -0
#   fix  platform_rename_gsi related ia32 build breakage
# 
# ChangeSet
#   2004/11/01 20:44:28+01:00 vojtech@suse.cz 
#   Merge suse.cz:/home/vojtech/bk/linus into suse.cz:/home/vojtech/bk/input
# 
# include/linux/input.h
#   2004/11/01 20:44:12+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# drivers/input/serio/Kconfig
#   2004/11/01 20:44:12+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/11/01 20:44:12+01:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/27 12:09:04+02:00 vojtech@suse.cz 
#   Manual merge
# 
# drivers/input/serio/i8042-io.h
#   2004/10/27 12:08:57+02:00 vojtech@suse.cz +2 -4
#   Manual merge
# 
# ChangeSet
#   2004/10/27 01:11:44-05:00 dtor_core@ameritech.net 
#   Input: parkbd - switch to using module_param. Parameter names are
#          parkbd.port and parkbd.mode
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/serio/parkbd.c
#   2004/10/27 01:10:52-05:00 dtor_core@ameritech.net +8 -11
#   Switch to using module_param()
# 
# Documentation/kernel-parameters.txt
#   2004/10/27 01:10:52-05:00 dtor_core@ameritech.net +7 -0
#   Document parkbd options.
# 
# ChangeSet
#   2004/10/24 21:02:03+02:00 vojtech@suse.cz 
#   Merge bk://dtor.bkbits.net/input/ into suse.cz:/home/vojtech/bk/input
# 
# drivers/input/keyboard/lkkbd.c
#   2004/10/24 21:01:51+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/24 20:59:23+02:00 vojtech@suse.cz 
#   Merge suse.cz:/home/vojtech/bk/linus into suse.cz:/home/vojtech/bk/input
# 
# drivers/usb/input/hid-core.c
#   2004/10/24 20:59:06+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/21 23:57:49-05:00 dtor_core@ameritech.net 
#   Input: gscps2 - remove unused statically allocated gscps2_serio_port
#          variable as the port is allocated dynamically.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/serio/gscps2.c
#   2004/10/21 23:57:31-05:00 dtor_core@ameritech.net +0 -13
#   Remove unused statically allocated gscps2_serio_port as the port is
#   allocated dynamically.
# 
# ChangeSet
#   2004/10/21 23:56:41-05:00 dtor_core@ameritech.net 
#   Input: get rid of pm_dev in input core as it is deprecated and
#          nothing uses it anyway.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# include/linux/input.h
#   2004/10/21 23:56:15-05:00 dtor_core@ameritech.net +0 -1
#   Get rid of pm_dev in input core as it is deprecated and nothing
#   uses it anyway.
# 
# drivers/input/touchscreen/h3600_ts_input.c
#   2004/10/21 23:56:15-05:00 dtor_core@ameritech.net +3 -2
#   Move pm_dev into h3600_dev structure (not that it works anyway).
# 
# drivers/input/input.c
#   2004/10/21 23:56:15-05:00 dtor_core@ameritech.net +0 -4
#   Get rid of pm_dev in input core as it is deprecated and nothing
#   uses it anyway.
# 
# ChangeSet
#   2004/10/21 23:55:41-05:00 dtor_core@ameritech.net 
#   Input: i8042 - get rid of reboot notifier as suspend method
#          should do the job.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/serio/i8042.c
#   2004/10/21 23:55:20-05:00 dtor_core@ameritech.net +5 -28
#   Get rid of reboot notifier as suspend method shoudl do the job.
# 
# ChangeSet
#   2004/10/21 23:53:52-05:00 dtor_core@ameritech.net 
#   Input: i8042 - get rid of old style power management handler since
#          APM calls both pm_send and device_suspend.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/serio/i8042.c
#   2004/10/21 23:53:26-05:00 dtor_core@ameritech.net +30 -59
#   Get rid of old style power management handler since APM calls both
#   pm_send and device_suspend so in fact we were resuming everything
#   twice.
# 
# ChangeSet
#   2004/10/21 23:52:36-05:00 dtor_core@ameritech.net 
#   Input: i8042 - allow turning debugging on and off "on-fly"
#          so people do not have to recompile their kernels to
#          provide debug info.
#   
#          Adds new parameter i8042.debug also accessible through
#          sysfs. 
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/serio/i8042.h
#   2004/10/21 23:52:18-05:00 dtor_core@ameritech.net +6 -2
#   Allow debugging to be turned on and off "on-fly"
# 
# drivers/input/serio/i8042.c
#   2004/10/21 23:52:18-05:00 dtor_core@ameritech.net +7 -1
#   Allow debugging to be turned on and off "on-fly"
# 
# ChangeSet
#   2004/10/21 23:51:43-05:00 dtor_core@ameritech.net 
#   Input: when creating input devices for hardware attached to
#          a serio port properly set input_device->dev pointer
#          so when corresponding class device is created it will
#          show proper links to parent device and driver in sysfs
#          hierarchy.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/vsxxxaa.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/mouse/sermouse.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/mouse/psmouse-base.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/keyboard/xtkbd.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/keyboard/sunkbd.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/keyboard/newtonkbd.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/keyboard/lkkbd.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/keyboard/atkbd.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/joystick/warrior.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/joystick/twidjoy.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/joystick/stinger.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/joystick/spaceorb.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/joystick/spaceball.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/joystick/magellan.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +1 -0
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# drivers/input/joystick/iforce/iforce-main.c
#   2004/10/21 23:51:23-05:00 dtor_core@ameritech.net +15 -1
#   Link input device with serio's device so when class device is
#   registered appropriate links to device and driver are created.
# 
# ChangeSet
#   2004/10/21 23:50:25-05:00 dtor_core@ameritech.net 
#   Input: evdev, joydev, mousedev, tsdev - remove class device and devfs
#          entry when hardware driver disconnects instead of waiting for
#          the last user to drop off. This way hardware drivers can be
#          unloaded at any time.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/tsdev.c
#   2004/10/21 23:49:57-05:00 dtor_core@ameritech.net +5 -5
#   Remove class device and devfs entry when hardware is disconncted;
#   do not wait till the last user drops off.
# 
# drivers/input/mousedev.c
#   2004/10/21 23:49:57-05:00 dtor_core@ameritech.net +2 -2
#   Remove class device and devfs entry when hardware is disconncted;
#   do not wait till the last user drops off.
# 
# drivers/input/joydev.c
#   2004/10/21 23:49:57-05:00 dtor_core@ameritech.net +2 -2
#   Remove class device and devfs entry when hardware is disconncted;
#   do not wait till the last user drops off.
# 
# drivers/input/evdev.c
#   2004/10/21 23:49:57-05:00 dtor_core@ameritech.net +2 -2
#   Remove class device and devfs entry when hardware is disconncted;
#   do not wait till the last user drops off.
# 
# ChangeSet
#   2004/10/21 23:49:17-05:00 dtor_core@ameritech.net 
#   Input: couple of whitespace fixes.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/vsxxxaa.c
#   2004/10/21 23:48:57-05:00 dtor_core@ameritech.net +1 -1
#   Whitespace fixes
# 
# drivers/input/mouse/sermouse.c
#   2004/10/21 23:48:57-05:00 dtor_core@ameritech.net +12 -12
#   Whitespace fixes
# 
# ChangeSet
#   2004/10/21 11:59:13+02:00 vojtech@suse.cz 
#   Merge suse.cz:/data2/bk/linus into suse.cz:/data2/bk/input
# 
# drivers/input/mouse/Kconfig
#   2004/10/21 11:59:08+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# drivers/input/joystick/gamecon.c
#   2004/10/21 11:59:08+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/10/21 11:59:08+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/20 14:54:11+02:00 vojtech@suse.cz 
#   Manual merge
# 
# drivers/usb/input/hid-core.c
#   2004/10/20 14:54:04+02:00 vojtech@suse.cz +5 -6
#   Manual merge
# 
# Documentation/kernel-parameters.txt
#   2004/10/20 14:49:34+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/20 10:13:15+02:00 vojtech@suse.cz 
#   input: Increase ACK timeouts in libps2 in case the RESET_BAT command is used.
#          This should fix most Synaptics "reset failed" cases. Thanks to Keith
#          Packard for the report.
#          Also add some more keyboard IDs, so that unusual keyboards are accepted
#          by libps2 and atkbd.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/libps2.h
#   2004/10/20 10:13:08+02:00 vojtech@suse.cz +1 -1
#   input: Increase ACK timeouts in libps2 in case the RESET_BAT command is used.
#          This should fix most Synaptics "reset failed" cases. Thanks to Keith
#          Packard for the report.
#          Also add some more keyboard IDs, so that unusual keyboards are accepted
#          by libps2 and atkbd.
# 
# drivers/input/serio/libps2.c
#   2004/10/20 10:13:08+02:00 vojtech@suse.cz +32 -10
#   input: Increase ACK timeouts in libps2 in case the RESET_BAT command is used.
#          This should fix most Synaptics "reset failed" cases. Thanks to Keith
#          Packard for the report.
#          Also add some more keyboard IDs, so that unusual keyboards are accepted
#          by libps2 and atkbd.
# 
# drivers/input/keyboard/atkbd.c
#   2004/10/20 10:13:08+02:00 vojtech@suse.cz +4 -1
#   input: Increase ACK timeouts in libps2 in case the RESET_BAT command is used.
#          This should fix most Synaptics "reset failed" cases. Thanks to Keith
#          Packard for the report.
#          Also add some more keyboard IDs, so that unusual keyboards are accepted
#          by libps2 and atkbd.
# 
# ChangeSet
#   2004/10/19 12:58:36+02:00 vojtech@suse.cz 
#   Input: i8042 ACPI enumeration - add PNP IDs found in AMD64 laptops.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2004/10/19 12:58:22+02:00 vojtech@suse.cz +2 -2
#   Input: i8042 ACPI enumeration - add PNP IDs found in AMD64 laptops.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2004/10/19 10:02:20+02:00 vojtech@suse.cz 
#   Merge suse.cz:/data2/bk/linus into suse.cz:/data2/bk/input
# 
# drivers/usb/input/hid-core.c
#   2004/10/19 10:02:15+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# drivers/input/joystick/Kconfig
#   2004/10/19 10:02:15+02:00 vojtech@suse.cz +0 -1
#   Auto merged
# 
# ChangeSet
#   2004/10/16 13:15:38+02:00 vojtech@suse.cz 
#   input: Fix ssize_t prototype mismatch in psmouse and atkbd.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/psmouse.h
#   2004/10/16 13:15:31+02:00 vojtech@suse.cz +1 -1
#   input: Fix ssize_t prototype mismatch in psmouse and atkbd.
# 
# drivers/input/keyboard/atkbd.c
#   2004/10/16 13:15:31+02:00 vojtech@suse.cz +2 -2
#   input: Fix ssize_t prototype mismatch in psmouse and atkbd.
# 
# ChangeSet
#   2004/10/13 15:54:28+02:00 vojtech@suse.cz 
#   Merge suse.cz:/data2/bk/linus into suse.cz:/data2/bk/input
# 
# drivers/usb/input/hid-core.c
#   2004/10/13 15:54:24+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# Documentation/kernel-parameters.txt
#   2004/10/13 15:54:24+02:00 vojtech@suse.cz +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/30 01:31:12-05:00 dtor_core@ameritech.net 
#   Input: psmouse - explicitely specify packet size instead of relying
#          on protocol numbering scheme. Make protocol detection routines
#          return -1 on failure to keep them consistent with ther rest
#          of the code. Set mouse parameters right in detection routines
#          instead of doing it in psmouse_extensions.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/synaptics.h
#   2004/09/30 01:30:53-05:00 dtor_core@ameritech.net +1 -1
#   Adjust synaptics_detect prototype.
# 
# drivers/input/mouse/synaptics.c
#   2004/09/30 01:30:53-05:00 dtor_core@ameritech.net +12 -3
#   Explicitely set up packet size and vendor/name, adjust detect
#   routine to return -1 on failure.
# 
# drivers/input/mouse/psmouse.h
#   2004/09/30 01:30:53-05:00 dtor_core@ameritech.net +1 -0
#   Add packet size to psmouse structure.
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/30 01:30:53-05:00 dtor_core@ameritech.net +82 -74
#   Explicitely set and check packet size and not rely on protocol
#   numbering scheme; rearrange detect methods to return -1 when
#   hardware is not detceted and also set psmouse properties instead
#   of duing it in psmouse_extensions.
# 
# drivers/input/mouse/logips2pp.c
#   2004/09/30 01:30:53-05:00 dtor_core@ameritech.net +3 -2
#   Explicitely set up packet size, adjust ps2pp_init to return -1
#   on failure.
# 
# drivers/input/mouse/alps.h
#   2004/09/30 01:30:53-05:00 dtor_core@ameritech.net +1 -1
#   Adjust alps_detect prototype.
# 
# drivers/input/mouse/alps.c
#   2004/09/30 01:30:53-05:00 dtor_core@ameritech.net +10 -2
#   Explicitely set up packet size and vendor/name, adjust alps_detect
#   to retrun -1 on failure.
# 
# ChangeSet
#   2004/09/30 01:30:25-05:00 dtor_core@ameritech.net 
#   Input: psmouse - make logips2pp fully decode its protocol packets
#          and not rely on generic handler to finish job.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/30 01:30:04-05:00 dtor_core@ameritech.net +0 -7
#   Make logips2pp fully decode its protocol packets and not rely
#   on generic handler to finish job.
# 
# drivers/input/mouse/logips2pp.h
#   2004/09/30 01:30:04-05:00 dtor_core@ameritech.net +0 -1
#   Make logips2pp fully decode its protocol packets and not rely
#   on generic handler to finish job.
# 
# drivers/input/mouse/logips2pp.c
#   2004/09/30 01:30:04-05:00 dtor_core@ameritech.net +33 -10
#   Make logips2pp fully decode its protocol packets and not rely
#   on generic handler to finish job.
# 
# ChangeSet
#   2004/09/30 01:28:49-05:00 dtor_core@ameritech.net 
#   Input: psmouse - drop PS2TPP protocol (it is handled exactly like
#          PS2PP) to free spot for THINKPS protocol and keep old protocol
#          numbers for binary compatibility with Synaptics/ALPS touchpad
#          driver for X.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/psmouse.h
#   2004/09/30 01:28:32-05:00 dtor_core@ameritech.net +0 -1
#   Remove PS2TPP protocol as it is handled exactly like PS2PP
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/30 01:28:32-05:00 dtor_core@ameritech.net +4 -7
#   Remove PS2TPP protocol as it is handled exactly like PS2PP
# 
# drivers/input/mouse/logips2pp.c
#   2004/09/30 01:28:32-05:00 dtor_core@ameritech.net +28 -24
#   Convert ps2pp_init to signal caller whether it supports
#   PS2PP protocol or not like other detection functions do.
# 
# ChangeSet
#   2004/09/30 01:28:03-05:00 dtor_core@ameritech.net 
#   Input: psmouse - export rate, resolution, resetafter and smartscroll
#          (Logitech only) as individual mouse attributes (sysfs) and allow
#          them to be set/changed independently for each mouse:
#   
#            echo -n "100" > /sys/bus/serio/devices/serio0/rate
#            echo -n "200" > /sys/bus/serio/devices/serio0/resolution
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/psmouse.h
#   2004/09/30 01:27:48-05:00 dtor_core@ameritech.net +21 -1
#   Add PSMOUSE_DEFINE_ATTR to help define psmouse sysfs attributes
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/30 01:27:48-05:00 dtor_core@ameritech.net +125 -2
#   Export rate, resolution and resetafter as sysfs attributes.
# 
# drivers/input/mouse/logips2pp.c
#   2004/09/30 01:27:48-05:00 dtor_core@ameritech.net +39 -9
#   Export smartscroll as a sysfs attribute.
# 
# ChangeSet
#   2004/09/30 01:27:24-05:00 dtor_core@ameritech.net 
#   Input: psmouse - reset mouse before doing intellimouse/explorer
#          probes in case it got confused by earlier probes; switch
#          to streaming mode before setting scale and resolution,
#          otherwise some KVMs get confused.
#   
#   Patch-by: Marko Macek <Marko.Macek@gmx.net>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/30 01:27:07-05:00 dtor_core@ameritech.net +11 -7
#   Reset mouse before doing intellimouse/explorer probes in case it
#   got confused by earlier probes; switch to streaming mode before
#   setting scale and resolution, otherwise some KVMs may get confused.
# 
# ChangeSet
#   2004/09/30 01:26:43-05:00 dtor_core@ameritech.net 
#   Input: synaptics - not only switch to 4-byte client protocol
#          but also revert to 3-byte mode if client selected lower
#          protocol.
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru> 
# 
# drivers/input/mouse/synaptics.c
#   2004/09/30 01:26:27-05:00 dtor_core@ameritech.net +7 -3
#   Not only switch to 4-byte client protocol but also disable it
#   if client switched to 3-byte protocol. 
# 
# ChangeSet
#   2004/09/30 01:25:47-05:00 dtor_core@ameritech.net 
#   Input: psmouse - add set_rate and set_resolution handlers to make
#          adding new protocols easier and remove special knowledge
#          from psmouse-base.c
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/synaptics.h
#   2004/09/30 01:25:30-05:00 dtor_core@ameritech.net +1 -0
#   Add current mode byte to synaptics structure.
# 
# drivers/input/mouse/synaptics.c
#   2004/09/30 01:25:30-05:00 dtor_core@ameritech.net +27 -10
#   Move rate switching code into separate synaptics_set_rate handler.
# 
# drivers/input/mouse/psmouse.h
#   2004/09/30 01:25:30-05:00 dtor_core@ameritech.net +7 -1
#   Add set_rate and set_resolution handlers to make adding new
#   protocols easier and remove special knowledge from psmouse-base.c
# 
# drivers/input/mouse/psmouse-base.c
#   2004/09/30 01:25:30-05:00 dtor_core@ameritech.net +20 -23
#   Add set_rate and set_resolution handlers to make adding new
#   protocols easier and remove special knowledge from psmouse-base.c
# 
# drivers/input/mouse/logips2pp.h
#   2004/09/30 01:25:30-05:00 dtor_core@ameritech.net +0 -1
#   Remove ps2pp_set_800dpi from list of exported functions.
# 
# drivers/input/mouse/logips2pp.c
#   2004/09/30 01:25:30-05:00 dtor_core@ameritech.net +14 -8
#   Add set_resultion handler.
# 
# ChangeSet
#   2004/09/30 01:24:59-05:00 dtor_core@ameritech.net 
#   Input: add a new signature for ALPS DualPoint found in
#          Dell Inspiron 8500
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/alps.c
#   2004/09/30 01:24:37-05:00 dtor_core@ameritech.net +1 -0
#   Add a new signature for DualPoint found in Dell Inspiron 8500
# 
# ChangeSet
#   2004/09/24 12:26:54+02:00 jbglaw@lug-owl.de 
#   input: More comment fixes in lkkbd.c
#   
#   Signed-off-by: Jan-Benedict Glaw <jbglaw@lug-owl.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/keyboard/lkkbd.c
#   2004/09/24 12:26:43+02:00 jbglaw@lug-owl.de +3 -3
#   input: More comment fixes in lkkbd.c
#   
#   Signed-off-by: Jan-Benedict Glaw <jbglaw@lug-owl.de>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2004/09/24 11:40:14+02:00 bjorn.helgaas@hp.com 
#   Input: Add ACPI-based i8042 keyboard and aux controller enumeration; can be
#   disabled by passing i8042.noacpi as a boot parameter.
#   
#   Original code by Bjorn Helgaas <bjorn.helgaas@hp.com>, reworked by
#   Dmitry Torokhov <dtor@mail.ru>, FixedIO support from Hans-Frieder Vogt
#   <hfvogt@gmx.net>
#   
#   Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2004/09/24 11:40:02+02:00 bjorn.helgaas@hp.com +308 -0
# 
# drivers/input/serio/i8042.h
#   2004/09/24 11:40:02+02:00 bjorn.helgaas@hp.com +2 -0
#   Input: Add ACPI-based i8042 keyboard and aux controller enumeration; can be
#   disabled by passing i8042.noacpi as a boot parameter.
#   
#   Original code by Bjorn Helgaas <bjorn.helgaas@hp.com>, reworked by
#   Dmitry Torokhov <dtor@mail.ru>, FixedIO support from Hans-Frieder Vogt
#   <hfvogt@gmx.net>
#   
#   Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042.c
#   2004/09/24 11:40:02+02:00 bjorn.helgaas@hp.com +6 -0
#   Input: Add ACPI-based i8042 keyboard and aux controller enumeration; can be
#   disabled by passing i8042.noacpi as a boot parameter.
#   
#   Original code by Bjorn Helgaas <bjorn.helgaas@hp.com>, reworked by
#   Dmitry Torokhov <dtor@mail.ru>, FixedIO support from Hans-Frieder Vogt
#   <hfvogt@gmx.net>
#   
#   Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/serio/i8042-x86ia64io.h
#   2004/09/24 11:40:02+02:00 bjorn.helgaas@hp.com +0 -0
#   BitKeeper file /home/vojtech/bk/input/drivers/input/serio/i8042-x86ia64io.h
# 
# drivers/input/serio/i8042-io.h
#   2004/09/24 11:40:02+02:00 bjorn.helgaas@hp.com +7 -44
#   Input: Add ACPI-based i8042 keyboard and aux controller enumeration; can be
#   disabled by passing i8042.noacpi as a boot parameter.
#   
#   Original code by Bjorn Helgaas <bjorn.helgaas@hp.com>, reworked by
#   Dmitry Torokhov <dtor@mail.ru>, FixedIO support from Hans-Frieder Vogt
#   <hfvogt@gmx.net>
#   
#   Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# Documentation/kernel-parameters.txt
#   2004/09/24 11:40:00+02:00 bjorn.helgaas@hp.com +2 -0
#   Input: Add ACPI-based i8042 keyboard and aux controller enumeration; can be
#   disabled by passing i8042.noacpi as a boot parameter.
#   
#   Original code by Bjorn Helgaas <bjorn.helgaas@hp.com>, reworked by
#   Dmitry Torokhov <dtor@mail.ru>, FixedIO support from Hans-Frieder Vogt
#   <hfvogt@gmx.net>
#   
#   Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2004/09/24 11:36:34+02:00 jbglaw@lug-owl.de 
#   Input: correct the the wrong use of "DB9" to the correct name, "DE9". 
#          Also, some comments/debugging output is fixed up.
#   
#   Signed-off-by: Jan-Benedict Glaw <jbglaw@lug-owl.de>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/input/mouse/vsxxxaa.c
#   2004/09/24 11:36:22+02:00 jbglaw@lug-owl.de +29 -24
#   Input: correct the the wrong use of "DB9" to the correct name, "DE9". 
#          Also, some comments/debugging output is fixed up.
#   
#   Signed-off-by: Jan-Benedict Glaw <jbglaw@lug-owl.de>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2004/09/24 10:30:25+02:00 lenz@cs.wisc.edu 
#   input: Add LED definitions for PDAs.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
#   Signed-off-by: John Lenz <lenz@cs.wisc.edu>
# 
# include/linux/input.h
#   2004/09/24 10:30:14+02:00 lenz@cs.wisc.edu +2 -0
#   input: Add LED definitions for PDAs.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
#   Signed-off-by: John Lenz <lenz@cs.wisc.edu>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Patrick Mochel <mochel@digitalimplant.org>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Patrick Mochel <mochel@digitalimplant.org>
# 
# ChangeSet
#   2004/09/23 12:59:31+02:00 vojtech@suse.cz 
#   input: Tidy up & 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->Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# include/linux/input.h
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +3 -0
#   input: Tidy up & 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->Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid.h
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +41 -3
#   input: Tidy up & 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->Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-input.c
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +217 -246
#   input: Tidy up & 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->Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-debug.h
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +263 -1
#   input: Tidy up & 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->Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# drivers/usb/input/hid-core.c
#   2004/09/23 12:59:24+02:00 vojtech@suse.cz +8 -9
#   input: Tidy up & 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->Input
#            mappings, more mappings added, devices with reports larger than MaxPacketSize
#            work again.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
# 
# ChangeSet
#   2004/09/22 22:35:49-05:00 dtor_core@ameritech.net 
#   Input: clean up ALPS DualPoint logic
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
# 
# drivers/input/mouse/alps.c
#   2004/09/22 22:35:28-05:00 dtor_core@ameritech.net +22 -37
#   Clean up DualPoint logic
# 
# 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 <vojtech@suse.cz>
# 
# 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 <vojtech@suse.cz>
# 
# 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" > /sys/bus/serio/devices/serio1/set
#          echo -n "1" > /sys/bus/serio/devices/serio1/softrepeat
#   
#   Signed-off-by: Dmitry Torokhov <dtor@mail.ru> 
# 
# 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 <dtor@mail.ru>
# 
# 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 <dtor@mail.ru>
# 
# 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 -> 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 -> ps2_command
# 
# drivers/input/mouse/alps.c
#   2004/09/22 01:48:17-05:00 dtor_core@ameritech.net +38 -30
#   Rename psmouse_coommand -> 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 16:12:18+02:00 vojtech@suse.cz 
#   input: Add AT-compatible rawmode generation for ARM.
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
#   Patch-by: Woody Suwalski <woodys@xandros.com>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Woody Suwalski <woodys@xandros.com>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Osterlund <petero2@telia.com>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Osterlund <petero2@telia.com>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Osterlund <petero2@telia.com>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Osterlund <petero2@telia.com>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Osterlund <petero2@telia.com>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Maydell <pmaydell@chiark.greenend.org.uk>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Maydell <pmaydell@chiark.greenend.org.uk>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Maydell <pmaydell@chiark.greenend.org.uk>
# 
# 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 <vojtech@suse.cz>
# 
# 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 <vojtech@suse.cz>
# 
# ChangeSet
#   2004/09/21 09:24:21+02:00 pnelson@suse.cz 
#   input: Fix oops in gamecon
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
#   Patch-by: Peter Nelson <pnelson@andrew.cmu.edu>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Peter Nelson <pnelson@andrew.cmu.edu>
# 
# ChangeSet
#   2004/09/19 13:46:50+02:00 olh@suse.de 
#   input: Joydump depends on gameport
#   
#   Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
#   Patch-by: Olaf Hering <olh@suse.de>
# 
# 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 <vojtech@suse.cz>
#   Patch-by: Olaf Hering <olh@suse.de>
# 
diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	2004-12-12 18:19:32 -08:00
+++ b/Documentation/kernel-parameters.txt	2004-12-12 18:19:32 -08:00
@@ -498,6 +498,8 @@
 	i8042.dumbkbd	[HW] Pretend that controlled can only read data from
 			     keyboard and can not control its state
 			     (Don't attempt to blink the leds)
+	i8042.noacpi	[HW] Don't use ACPI to discover KBD/AUX controller
+			     settings
 	i8042.noaux	[HW] Don't check for auxiliary (== mouse) port
 	i8042.nomux	[HW] Don't check presence of an active multiplexing
 			     controller
@@ -868,6 +870,13 @@
 
 	panic=		[KNL] Kernel behaviour on panic
 			Format: <timeout>
+
+	parkbd.port=	[HW] Parallel port number the keyboard adapter is
+			connected to, default is 0.
+			Format: <parport#>
+	parkbd.mode=	[HW] Parallel port keyboard adapter mode of operation,
+			0 for XT, 1 for AT (default is AT).
+			Format: <mode> 
 
 	parport=0	[HW,PPT]	Specify parallel ports. 0 disables.
 	parport=auto			Use 'auto' to force the driver to use
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/char/keyboard.c	2004-12-12 18:19:32 -08:00
@@ -939,7 +939,10 @@
 	tasklet_enable(&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) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_RPC))
 
 #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
 			((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/evdev.c	2004-12-12 18:19:32 -08:00
@@ -91,8 +91,6 @@
 
 static void evdev_free(struct evdev *evdev)
 {
-	devfs_remove("input/event%d", evdev->minor);
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
 	evdev_table[evdev->minor] = NULL;
 	kfree(evdev);
 }
@@ -441,6 +439,8 @@
 {
 	struct evdev *evdev = handle->private;
 
+	class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
+	devfs_remove("input/event%d", evdev->minor);
 	evdev->exist = 0;
 
 	if (evdev->open) {
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/input.c	2004-12-12 18:19:32 -08:00
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/major.h>
-#include <linux/pm.h>
 #include <linux/proc_fs.h>
 #include <linux/kobject_uevent.h>
 #include <linux/interrupt.h>
@@ -67,9 +66,6 @@
 {
 	struct input_handle *handle;
 
-	if (dev->pm_dev)
-		pm_access(dev->pm_dev);
-
 	if (type > EV_MAX || !test_bit(type, dev->evbit))
 		return;
 
@@ -230,8 +226,6 @@
 
 int input_open_device(struct input_handle *handle)
 {
-	if (handle->dev->pm_dev)
-		pm_access(handle->dev->pm_dev);
 	handle->open++;
 	if (handle->dev->open)
 		return handle->dev->open(handle->dev);
@@ -249,8 +243,6 @@
 void input_close_device(struct input_handle *handle)
 {
 	input_release_device(handle);
-	if (handle->dev->pm_dev)
-		pm_dev_idle(handle->dev->pm_dev);
 	if (handle->dev->close)
 		handle->dev->close(handle->dev);
 	handle->open--;
@@ -467,9 +459,6 @@
 	struct list_head * node, * next;
 
 	if (!dev) return;
-
-	if (dev->pm_dev)
-		pm_unregister(dev->pm_dev);
 
 	del_timer_sync(&dev->timer);
 
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joydev.c	2004-12-12 18:19:32 -08:00
@@ -143,9 +143,7 @@
 
 static void joydev_free(struct joydev *joydev)
 {
-	devfs_remove("input/js%d", joydev->minor);
 	joydev_table[joydev->minor] = NULL;
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
 	kfree(joydev);
 }
 
@@ -466,6 +464,8 @@
 {
 	struct joydev *joydev = handle->private;
 
+	class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
+	devfs_remove("input/js%d", joydev->minor);
 	joydev->exist = 0;
 
 	if (joydev->open)
diff -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
--- a/drivers/input/joystick/gamecon.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/gamecon.c	2004-12-12 18:19:32 -08: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->pd->port) ^ 0x80;
 		for (j = 0; j < 5; j++)
-			data[j] |= (read & gc_status_bit[j] & gc->pads[GC_PSX]) ? (1 << i) : 0;
+			data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0;
 		parport_write_data(gc->pd->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 < 5; i++)								/* Find the longest pad */
-		if((gc_status_bit[i] & gc->pads[GC_PSX]) && (GC_PSX_LEN(id[i]) > max_len))
+		if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) && (GC_PSX_LEN(id[i]) > max_len))
 			max_len = GC_PSX_LEN(id[i]);
 
 	for (i = 0; i < max_len * 2; i++) {						/* Read in all the data */
diff -Nru a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
--- a/drivers/input/joystick/iforce/iforce-main.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/iforce/iforce-main.c	2004-12-12 18:19:32 -08:00
@@ -352,7 +352,21 @@
  * Input device fields.
  */
 
-	iforce->dev.id.bustype = BUS_USB;
+	switch (iforce->bus) {
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
+	case IFORCE_USB:
+		iforce->dev.id.bustype = BUS_USB;
+		iforce->dev.dev = &iforce->usbdev->dev;
+		break;
+#endif
+#ifdef CONFIG_JOYSTICK_IFORCE_232
+	case IFORCE_232:
+		iforce->dev.id.bustype = BUS_RS232;
+		iforce->dev.dev = &iforce->serio->dev;
+		break;
+#endif
+	}
+
 	iforce->dev.private = iforce;
 	iforce->dev.name = "Unknown I-Force device";
 	iforce->dev.open = iforce_open;
diff -Nru a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
--- a/drivers/input/joystick/magellan.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/magellan.c	2004-12-12 18:19:32 -08:00
@@ -183,6 +183,7 @@
 	magellan->dev.id.vendor = SERIO_MAGELLAN;
 	magellan->dev.id.product = 0x0001;
 	magellan->dev.id.version = 0x0100;
+	magellan->dev.dev = &serio->dev;
 
 	serio->private = magellan;
 
diff -Nru a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
--- a/drivers/input/joystick/spaceball.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/spaceball.c	2004-12-12 18:19:32 -08:00
@@ -253,6 +253,7 @@
 	spaceball->dev.id.vendor = SERIO_SPACEBALL;
 	spaceball->dev.id.product = id;
 	spaceball->dev.id.version = 0x0100;
+	spaceball->dev.dev = &serio->dev;
 
 	serio->private = spaceball;
 
diff -Nru a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
--- a/drivers/input/joystick/spaceorb.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/spaceorb.c	2004-12-12 18:19:32 -08:00
@@ -200,6 +200,7 @@
 	spaceorb->dev.id.vendor = SERIO_SPACEORB;
 	spaceorb->dev.id.product = 0x0001;
 	spaceorb->dev.id.version = 0x0100;
+	spaceorb->dev.dev = &serio->dev;
 
 	serio->private = spaceorb;
 
diff -Nru a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
--- a/drivers/input/joystick/stinger.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/stinger.c	2004-12-12 18:19:32 -08:00
@@ -164,6 +164,7 @@
 	stinger->dev.id.vendor = SERIO_STINGER;
 	stinger->dev.id.product = 0x0001;
 	stinger->dev.id.version = 0x0100;
+	stinger->dev.dev = &serio->dev;
 
 	for (i = 0; i < 2; i++) {
 		stinger->dev.absmax[ABS_X+i] =  64;
diff -Nru a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
--- a/drivers/input/joystick/twidjoy.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/twidjoy.c	2004-12-12 18:19:32 -08:00
@@ -210,6 +210,7 @@
 	twidjoy->dev.id.vendor = SERIO_TWIDJOY;
 	twidjoy->dev.id.product = 0x0001;
 	twidjoy->dev.id.version = 0x0100;
+	twidjoy->dev.dev = &serio->dev;
 
 	twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
diff -Nru a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
--- a/drivers/input/joystick/warrior.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/joystick/warrior.c	2004-12-12 18:19:32 -08:00
@@ -168,6 +168,7 @@
 	warrior->dev.id.vendor = SERIO_WARRIOR;
 	warrior->dev.id.product = 0x0001;
 	warrior->dev.id.version = 0x0100;
+	warrior->dev.dev = &serio->dev;
 
 	for (i = 0; i < 2; i++) {
 		warrior->dev.absmax[ABS_X+i] = -64;
diff -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
--- a/drivers/input/keyboard/Kconfig	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/keyboard/Kconfig	2004-12-12 18:19:32 -08:00
@@ -16,6 +16,7 @@
 	default y
 	depends on INPUT && 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-12-12 18:19:32 -08:00
+++ b/drivers/input/keyboard/atkbd.c	2004-12-12 18:19:32 -08:00
@@ -26,6 +26,7 @@
 #include <linux/input.h>
 #include <linux/serio.h>
 #include <linux/workqueue.h>
+#include <linux/libps2.h>
 
 #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,
+				ssize_t (*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->resend = 0;
 #endif
 
-	if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) {
-		switch (code) {
-			case ATKBD_RET_ACK:
-				atkbd->nak = 0;
-				if (atkbd->cmdcnt) {
-					set_bit(ATKBD_FLAG_CMD, &atkbd->flags);
-					set_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
-				}
-				clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
-				wake_up_interruptible(&atkbd->wait);
-				break;
-			case ATKBD_RET_NAK:
-				atkbd->nak = 1;
-				clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
-				wake_up_interruptible(&atkbd->wait);
-				break;
-		}
-		goto out;
-	}
-
-	if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) {
-
-		if (atkbd->cmdcnt)
-			atkbd->cmdbuf[--atkbd->cmdcnt] = code;
-
-		if (test_and_clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags) && atkbd->cmdcnt)
-			wake_up_interruptible(&atkbd->wait);
+	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
+		if  (ps2_handle_ack(&atkbd->ps2dev, data))
+			goto out;
 
-		if (!atkbd->cmdcnt) {
-			clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
-			wake_up_interruptible(&atkbd->wait);
-		}
-		goto out;
-	}
+	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
+		if  (ps2_handle_response(&atkbd->ps2dev, data))
+			goto out;
 
-	if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags))
+	if (!atkbd->enabled)
 		goto out;
 
 	input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);
@@ -326,8 +300,8 @@
 
 	switch (code) {
 		case ATKBD_RET_BAT:
-			clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
-			serio_rescan(atkbd->serio);
+			atkbd->enabled = 0;
+			serio_rescan(atkbd->ps2dev.serio);
 			goto out;
 		case ATKBD_RET_EMUL0:
 			atkbd->emul = 1;
@@ -396,7 +370,7 @@
 			break;
 		default:
 			value = atkbd->release ? 0 :
-				(1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
+				(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
 
 			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->nak = 1;
-	set_bit(ATKBD_FLAG_ACK, &atkbd->flags);
-
-	if (serio_write(atkbd->serio, byte) == 0)
-		wait_event_interruptible_timeout(atkbd->wait,
-				!test_bit(ATKBD_FLAG_ACK, &atkbd->flags),
-				msecs_to_jiffies(200));
-
-	clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
-	return -atkbd->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 >> 12) & 0xf;
-	int receive = (command >> 8) & 0xf;
-	int rc = -1;
-	int i;
-
-	timeout = msecs_to_jiffies(command == ATKBD_CMD_RESET_BAT ? 4000 : 500);
-
-	down(&atkbd->cmd_sem);
-	clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
-
-	if (receive && param)
-		for (i = 0; i < receive; i++)
-			atkbd->cmdbuf[(receive - 1) - i] = param[i];
-
-	atkbd->cmdcnt = receive;
-
-	if (command & 0xff)
-		if (atkbd_sendbyte(atkbd, command & 0xff))
-			goto out;
-
-	for (i = 0; i < send; i++)
-		if (atkbd_sendbyte(atkbd, param[i]))
-			goto out;
-
-	timeout = wait_event_interruptible_timeout(atkbd->wait,
-				!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags), timeout);
-
-	if (atkbd->cmdcnt && timeout > 0) {
-		if (command == ATKBD_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)
-			timeout = msecs_to_jiffies(100);
-
-		if (command == ATKBD_CMD_GETID &&
-		    atkbd->cmdbuf[receive - 1] != 0xab && atkbd->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, &atkbd->flags);
-			atkbd->cmdcnt = 0;
-		}
-
-		wait_event_interruptible_timeout(atkbd->wait,
-				!test_bit(ATKBD_FLAG_CMD, &atkbd->flags), timeout);
-	}
-
-	if (param)
-		for (i = 0; i < receive; i++)
-			param[i] = atkbd->cmdbuf[(receive - 1) - i];
-
-	if (atkbd->cmdcnt && (command != ATKBD_CMD_RESET_BAT || atkbd->cmdcnt != 1))
-		goto out;
-
-	rc = 0;
-
-out:
-	clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
-	clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
-	up(&atkbd->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->atkbd, atkbd_work->param, atkbd_work->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 >> 12) & 0xf;
-	int receive = (command >> 8) & 0xf;
-
-	if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->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->atkbd = atkbd;
-	atkbd_work->command = command;
-	memcpy(atkbd_work->param, param, send);
-	INIT_WORK(&atkbd_work->work, atkbd_execute_scheduled_command, atkbd_work);
-
-	if (!schedule_work(&atkbd_work->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->led) ? 1 : 0)
 			         | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
 			         | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
-		        atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETLEDS);
+		        ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
 
 			if (atkbd->extra) {
 				param[0] = 0;
@@ -608,7 +437,7 @@
 					 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
 				         | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)
 				         | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
-				atkbd_schedule_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
+				ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
 			}
 
 			return 0;
@@ -616,7 +445,7 @@
 
 		case EV_REP:
 
-			if (atkbd_softrepeat) return 0;
+			if (atkbd->softrepeat) return 0;
 
 			i = j = 0;
 			while (i < 32 && period[i] < dev->rep[REP_PERIOD]) i++;
@@ -624,7 +453,7 @@
 			dev->rep[REP_PERIOD] = period[i];
 			dev->rep[REP_DELAY] = delay[j];
 			param[0] = i | (j << 5);
-			atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETREP);
+			ps2_schedule_command(&atkbd->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->ps2dev.serio);
+	atkbd->enabled = 1;
+	serio_continue_rx(atkbd->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->ps2dev.serio);
+	atkbd->enabled = 0;
+	serio_continue_rx(atkbd->ps2dev.serio);
+}
+
+/*
  * atkbd_probe() probes for an AT keyboard on a serio port.
  */
 
 static int atkbd_probe(struct atkbd *atkbd)
 {
+	struct ps2dev *ps2dev = &atkbd->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->serio->phys);
+		if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
+			printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->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,14 +520,17 @@
  * 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->id = 0xabba;
 		return 0;
 	}
 
-	if (param[0] != 0xab && param[0] != 0xac)
+	if (param[0] != 0xab && param[0] != 0xac &&	/* Regular and NCD Sun keyboards */
+	    param[0] != 0x2b && param[0] != 0x5d &&	/* Trust keyboard, raw and translated */
+	    param[0] != 0x60 && param[0] != 0x47)	/* NMB SGI keyboard, raw and translated */
 		return -1;
+
 	atkbd->id = (param[0] << 8) | param[1];
 
 	if (atkbd->id == 0xaca1 && atkbd->translated) {
@@ -686,15 +543,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 = &atkbd->ps2dev;
 	unsigned char param[2];
 
+	atkbd->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 +565,48 @@
 
 	if (atkbd->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->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->id = param[0] << 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 = &atkbd->ps2dev;
 	unsigned char param[1];
 
 /*
@@ -754,7 +614,7 @@
  */
 
 	param[0] = 0;
-	if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
 		return -1;
 
 /*
@@ -762,16 +622,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->serio->phys);
+			ps2dev->serio->phys);
 		return -1;
 	}
 
@@ -786,9 +646,10 @@
 static void atkbd_cleanup(struct serio *serio)
 {
 	struct atkbd *atkbd = serio->private;
-	atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT);
+	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
 }
 
+
 /*
  * atkbd_disconnect() closes and frees.
  */
@@ -797,15 +658,109 @@
 {
 	struct atkbd *atkbd = serio->private;
 
-	clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+	atkbd_disable(atkbd);
+
+	/* make sure we don't have a command in flight */
 	synchronize_kernel();
 	flush_scheduled_work();
 
+	device_remove_file(&serio->dev, &atkbd_attr_extra);
+	device_remove_file(&serio->dev, &atkbd_attr_scroll);
+	device_remove_file(&serio->dev, &atkbd_attr_set);
+	device_remove_file(&serio->dev, &atkbd_attr_softrepeat);
+	device_remove_file(&serio->dev, &atkbd_attr_softraw);
+
 	input_unregister_device(&atkbd->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->keycode, 0, sizeof(atkbd->keycode));
+
+	if (atkbd->translated) {
+		for (i = 0; i < 128; i++) {
+			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
+			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+			if (atkbd->scroll)
+				for (j = 0; i < 5; i++) {
+					if (atkbd_unxlate_table[i] == atkbd_scroll_keys[j][1])
+						atkbd->keycode[i] = atkbd_scroll_keys[j][0];
+					if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j][1])
+						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j][0];
+				}
+		}
+	} else if (atkbd->set == 3) {
+		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
+	} else {
+		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
+
+		if (atkbd->scroll)
+			for (i = 0; i < 5; i++)
+				atkbd->keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
+	}
+}
+
+/*
+ * atkbd_set_device_attrs() sets up keyboard's input device structure
+ */
+
+static void atkbd_set_device_attrs(struct atkbd *atkbd)
+{
+	int i;
+
+	memset(&atkbd->dev, 0, sizeof(struct input_dev));
+
+	init_input_dev(&atkbd->dev);
+
+	atkbd->dev.name = atkbd->name;
+	atkbd->dev.phys = atkbd->phys;
+	atkbd->dev.id.bustype = BUS_I8042;
+	atkbd->dev.id.vendor = 0x0001;
+	atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set;
+	atkbd->dev.id.version = atkbd->id;
+	atkbd->dev.event = atkbd_event;
+	atkbd->dev.private = atkbd;
+	atkbd->dev.dev = &atkbd->ps2dev.serio->dev;
+
+	atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
+
+	if (atkbd->write) {
+		atkbd->dev.evbit[0] |= BIT(EV_LED);
+		atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+	}
+
+	if (atkbd->extra)
+		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) |
+					BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
+
+	if (!atkbd->softrepeat) {
+		atkbd->dev.rep[REP_DELAY] = 250;
+		atkbd->dev.rep[REP_PERIOD] = 33;
+	}
+
+	atkbd->dev.mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
+
+	if (atkbd->scroll) {
+		atkbd->dev.evbit[0] |= BIT(EV_REL);
+		atkbd->dev.relbit[0] = BIT(REL_WHEEL);
+		set_bit(BTN_MIDDLE, atkbd->dev.keybit);
+	}
+
+	for (i = 0; i < 512; i++)
+		if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
+			set_bit(atkbd->keycode[i], atkbd->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 +771,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(&atkbd->cmd_sem);
-	init_waitqueue_head(&atkbd->wait);
+	ps2_init(&atkbd->ps2dev, serio);
 
 	switch (serio->type & SERIO_TYPE) {
 
@@ -841,31 +794,19 @@
 			return;
 	}
 
-	if (!atkbd->write)
-		atkbd_softrepeat = 1;
-	if (atkbd_softrepeat)
-		atkbd_softraw = 1;
-
-	if (atkbd->write) {
-		atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC);
-		atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	} else  atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
-	atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
+	atkbd->softraw = atkbd_softraw;
+	atkbd->softrepeat = atkbd_softrepeat;
+	atkbd->scroll = atkbd_scroll;
 
-	if (!atkbd_softrepeat) {
-		atkbd->dev.rep[REP_DELAY] = 250;
-		atkbd->dev.rep[REP_PERIOD] = 33;
-	} else atkbd_softraw = 1;
+	if (!atkbd->write)
+		atkbd->softrepeat = 1;
 
-	atkbd->serio = serio;
-
-	init_input_dev(&atkbd->dev);
+	if (atkbd->softrepeat)
+		atkbd->softraw = 1;
 
 	atkbd->dev.keycode = atkbd->keycode;
 	atkbd->dev.keycodesize = sizeof(unsigned char);
 	atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
-	atkbd->dev.event = atkbd_event;
-	atkbd->dev.private = atkbd;
 
 	serio->private = atkbd;
 
@@ -883,56 +824,34 @@
 			return;
 		}
 
-		atkbd->set = atkbd_set_3(atkbd);
-		atkbd_enable(atkbd);
+		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
+		atkbd_activate(atkbd);
 
 	} else {
 		atkbd->set = 2;
 		atkbd->id = 0xab00;
 	}
 
-	if (atkbd->extra) {
-		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
+	if (atkbd->extra)
 		sprintf(atkbd->name, "AT Set 2 Extra keyboard");
-	} else
+	else
 		sprintf(atkbd->name, "AT %s Set %d keyboard",
 			atkbd->translated ? "Translated" : "Raw", atkbd->set);
 
 	sprintf(atkbd->phys, "%s/input0", serio->phys);
 
-	if (atkbd_scroll) {
-		for (i = 0; i < 5; i++)
-			atkbd_set2_keycode[atkbd_scroll_keys[i][1]] = atkbd_scroll_keys[i][0];
-		atkbd->dev.evbit[0] |= BIT(EV_REL);
-		atkbd->dev.relbit[0] = BIT(REL_WHEEL);
-		set_bit(BTN_MIDDLE, atkbd->dev.keybit);
-	}
-
-	if (atkbd->translated) {
-		for (i = 0; i < 128; i++) {
-			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
-			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
-		}
-	} else if (atkbd->set == 3) {
-		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
-	} else {
-		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
-	}
-
-	atkbd->dev.name = atkbd->name;
-	atkbd->dev.phys = atkbd->phys;
-	atkbd->dev.id.bustype = BUS_I8042;
-	atkbd->dev.id.vendor = 0x0001;
-	atkbd->dev.id.product = atkbd->translated ? 1 : atkbd->set;
-	atkbd->dev.id.version = atkbd->id;
-
-	for (i = 0; i < 512; i++)
-		if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
-			set_bit(atkbd->keycode[i], atkbd->dev.keybit);
+	atkbd_set_keycode_table(atkbd);
+	atkbd_set_device_attrs(atkbd);
 
 	input_register_device(&atkbd->dev);
 
-	set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+	device_create_file(&serio->dev, &atkbd_attr_extra);
+	device_create_file(&serio->dev, &atkbd_attr_scroll);
+	device_create_file(&serio->dev, &atkbd_attr_set);
+	device_create_file(&serio->dev, &atkbd_attr_softrepeat);
+	device_create_file(&serio->dev, &atkbd_attr_softraw);
+
+	atkbd_enable(atkbd);
 
 	printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
 }
@@ -948,11 +867,13 @@
 	struct serio_driver *drv = serio->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->write) {
 		param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
 		         | (test_bit(LED_NUML,    atkbd->dev.led) ? 2 : 0)
@@ -960,16 +881,16 @@
 
 		if (atkbd_probe(atkbd))
 			return -1;
-		if (atkbd->set != atkbd_set_3(atkbd))
+		if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
 			return -1;
 
-		atkbd_enable(atkbd);
+		atkbd_activate(atkbd);
 
-		if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+		if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
 			return -1;
 	}
 
-	set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+	atkbd_enable(atkbd);
 
 	return 0;
 }
@@ -985,6 +906,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->drv != &atkbd_drv) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	retval = handler((struct atkbd *)serio->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,
+				ssize_t (*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->drv != &atkbd_drv) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	atkbd = serio->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->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->write)
+		return -EIO;
+
+	value = simple_strtoul(buf, &rest, 10);
+	if (*rest || value > 1)
+		return -EINVAL;
+
+	if (atkbd->extra != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&atkbd->dev);
+		atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
+		atkbd_activate(atkbd);
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&atkbd->dev);
+	}
+	return count;
+}
+
+static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd->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, &rest, 10);
+	if (*rest || value > 1)
+		return -EINVAL;
+
+	if (atkbd->scroll != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&atkbd->dev);
+		atkbd->scroll = value;
+		atkbd_set_keycode_table(atkbd);
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&atkbd->dev);
+	}
+	return count;
+}
+
+static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd->set);
+}
+
+static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	if (!atkbd->write)
+		return -EIO;
+
+	value = simple_strtoul(buf, &rest, 10);
+	if (*rest || (value != 2 && value != 3))
+		return -EINVAL;
+
+	if (atkbd->set != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&atkbd->dev);
+		atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
+		atkbd_activate(atkbd);
+		atkbd_set_keycode_table(atkbd);
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&atkbd->dev);
+	}
+	return count;
+}
+
+static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd->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->write)
+		return -EIO;
+
+	value = simple_strtoul(buf, &rest, 10);
+	if (*rest || value > 1)
+		return -EINVAL;
+
+	if (atkbd->softrepeat != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&atkbd->dev);
+		atkbd->softrepeat = value;
+		if (atkbd->softrepeat)
+			atkbd->softraw = 1;
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&atkbd->dev);
+	}
+
+	return count;
+}
+
+
+static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
+{
+	return sprintf(buf, "%d\n", atkbd->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, &rest, 10);
+	if (*rest || value > 1)
+		return -EINVAL;
+
+	if (atkbd->softraw != value) {
+		/* unregister device as it's properties will change */
+		input_unregister_device(&atkbd->dev);
+		atkbd->softraw = value;
+		atkbd_set_device_attrs(atkbd);
+		input_register_device(&atkbd->dev);
+	}
+	return count;
+}
+
 
 int __init atkbd_init(void)
 {
diff -Nru a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
--- a/drivers/input/keyboard/lkkbd.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/keyboard/lkkbd.c	2004-12-12 18:19:32 -08:00
@@ -14,13 +14,13 @@
  * DISCLAIMER: This works for _me_. If you break anything by using the
  * information given below, I will _not_ be liable!
  *
- * RJ11 pinout:		To DB9:		Or DB25:
+ * RJ11 pinout:		To DE9:		Or DB25:
  * 	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
  * 	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
  * 	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
- * 	3 - +12V (from HDD drive connector), DON'T connect to DB9 or DB25!!!
+ * 	3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
  *
- * Pin numbers for DB9 and DB25 are noted on the plug (quite small:). For
+ * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
  * RJ11, it's like this:
  *
  *      __=__	Hold the plug in front of you, cable downwards,
@@ -685,6 +685,7 @@
 	lk->dev.id.vendor = SERIO_LKKBD;
 	lk->dev.id.product = 0;
 	lk->dev.id.version = 0x0100;
+	lk->dev.dev = &serio->dev;
 
 	input_register_device (&lk->dev);
 
diff -Nru a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
--- a/drivers/input/keyboard/newtonkbd.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/keyboard/newtonkbd.c	2004-12-12 18:19:32 -08:00
@@ -126,6 +126,7 @@
 	nkbd->dev.id.vendor = SERIO_NEWTON;
 	nkbd->dev.id.product = 0x0001;
 	nkbd->dev.id.version = 0x0100;
+	nkbd->dev.dev = &serio->dev;
 
 	input_register_device(&nkbd->dev);
 
diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- a/drivers/input/keyboard/sunkbd.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/keyboard/sunkbd.c	2004-12-12 18:19:32 -08:00
@@ -285,6 +285,7 @@
 	sunkbd->dev.id.vendor = SERIO_SUNKBD;
 	sunkbd->dev.id.product = sunkbd->type;
 	sunkbd->dev.id.version = 0x0100;
+	sunkbd->dev.dev = &serio->dev;
 
 	input_register_device(&sunkbd->dev);
 
diff -Nru a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
--- a/drivers/input/keyboard/xtkbd.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/keyboard/xtkbd.c	2004-12-12 18:19:32 -08:00
@@ -131,6 +131,7 @@
 	xtkbd->dev.id.vendor = 0x0001;
 	xtkbd->dev.id.product = 0x0001;
 	xtkbd->dev.id.version = 0x0100;
+	xtkbd->dev.dev = &serio->dev;
 
 	input_register_device(&xtkbd->dev);
 
diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/Kconfig	2004-12-12 18:19:32 -08:00
@@ -16,6 +16,7 @@
 	default y
 	depends on INPUT && 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-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/Makefile	2004-12-12 18:19:32 -08: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-12-12 18:19:32 -08:00
@@ -0,0 +1,424 @@
+/*
+ * ALPS touchpad PS/2 mouse driver
+ *
+ * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
+ * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
+ *
+ * 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 <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+
+#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 },
+	{ { 0x63, 0x03, 0xc8 },	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->packet;
+	struct input_dev *dev = &psmouse->dev;
+	int x, y, z;
+	int left = 0, right = 0, middle = 0;
+
+	input_regs(dev, regs);
+
+	if ((packet[0] & 0xc8) == 0x08) {   /* 3-byte PS/2 packet */
+		x = packet[1];
+		if (packet[0] & 0x10)
+			x = x - 256;
+		y = packet[2];
+		if (packet[0] & 0x20)
+			y = y - 256;
+		left  = (packet[0]     ) & 1;
+		right = (packet[0] >> 1) & 1;
+
+		input_report_rel(dev, REL_X, x);
+		input_report_rel(dev, REL_Y, -y);
+		input_report_key(dev, BTN_A, left);
+		input_report_key(dev, BTN_B, right);
+		input_sync(dev);
+		return;
+	}
+
+	x = (packet[1] & 0x7f) | ((packet[2] & 0x78)<<(7-3));
+	y = (packet[4] & 0x7f) | ((packet[3] & 0x70)<<(7-4));
+	z = packet[5];
+
+	if (z == 127) {	/* DualPoint stick is relative, not absolute */
+		if (x > 383)
+			x = x - 768;
+		if (y > 255)
+			y = y - 512;
+		left  = packet[3] & 1;
+		right = (packet[3] >> 1) & 1;
+
+		input_report_rel(dev, REL_X, x);
+		input_report_rel(dev, REL_Y, -y);
+		input_report_key(dev, BTN_LEFT, left);
+		input_report_key(dev, BTN_RIGHT, right);
+		input_sync(dev);
+		return;
+	}
+
+	if (z > 30) input_report_key(dev, BTN_TOUCH, 1);
+	if (z < 25) input_report_key(dev, BTN_TOUCH, 0);
+
+	if (z > 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 > 0);
+
+	left  |= (packet[2]     ) & 1;
+	left  |= (packet[3]     ) & 1;
+	right |= (packet[3] >> 1) & 1;
+	if (packet[0] == 0xff) {
+		int back    = (packet[3] >> 2) & 1;
+		int forward = (packet[2] >> 2) & 1;
+		if (back && forward) {
+			middle = 1;
+			back = 0;
+			forward = 0;
+		}
+		input_report_key(dev, BTN_BACK,    back);
+		input_report_key(dev, BTN_FORWARD, forward);
+	} else {
+		left   |= (packet[0]     ) & 1;
+		right  |= (packet[0] >> 1) & 1;
+		middle |= (packet[0] >> 2) & 1;
+		middle |= (packet[3] >> 2) & 1;
+	}
+
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
+	input_report_key(dev, BTN_MIDDLE, middle);
+
+	input_sync(dev);
+}
+
+static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
+		if (psmouse->pktcnt == 3) {
+			alps_process_packet(psmouse, regs);
+			return PSMOUSE_FULL_PACKET;
+		}
+		return PSMOUSE_GOOD_DATA;
+	}
+
+	/* ALPS absolute mode packets start with 0b11111mrl */
+	if ((psmouse->packet[0] & 0xf8) != 0xf8)
+		return PSMOUSE_BAD_DATA;
+
+	/* Bytes 2 - 6 should have 0 in the highest bit */
+	if (psmouse->pktcnt > 1 && psmouse->pktcnt <= 6 &&
+	    (psmouse->packet[psmouse->pktcnt] & 0x80))
+		return PSMOUSE_BAD_DATA;
+
+	if (psmouse->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 = &psmouse->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 && 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 < 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 = &psmouse->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_absolute_mode(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->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;
+
+	/*
+	 * Switch mouse to poll (remote) mode so motion data will not
+	 * get in our way
+	 */
+	return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
+}
+
+static int alps_get_status(struct psmouse *psmouse, char *param)
+{
+	struct ps2dev *ps2dev = &psmouse->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 enable)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
+	unsigned char tap_arg = enable ? 0x0A : 0x00;
+	unsigned char param[4];
+
+	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, &tap_arg, cmd))
+		return -1;
+
+	if (alps_get_status(psmouse, param))
+		return -1;
+
+	return 0;
+}
+
+static int alps_reconnect(struct psmouse *psmouse)
+{
+	int model;
+	unsigned char param[4];
+
+	if ((model = alps_get_model(psmouse)) < 0)
+		return -1;
+
+	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
+		return -1;
+
+	if (alps_get_status(psmouse, param))
+		return -1;
+
+	if (param[0] & 0x04)
+		alps_tap_mode(psmouse, 0);
+
+	if (alps_absolute_mode(psmouse)) {
+		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
+		return -1;
+	}
+
+	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
+		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)) < 0)
+		return -1;
+
+	printk(KERN_INFO "ALPS Touchpad (%s) detected\n",
+		model == ALPS_MODEL_GLIDEPOINT ? "Glidepoint" : "Dualpoint");
+
+	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
+		return -1;
+
+	if (alps_get_status(psmouse, param)) {
+		printk(KERN_ERR "alps.c: touchpad status report request failed\n");
+		return -1;
+	}
+
+	if (param[0] & 0x04) {
+		printk(KERN_INFO "  Disabling hardware tapping\n");
+		if (alps_tap_mode(psmouse, 0))
+			printk(KERN_WARNING "alps.c: Failed to disable hardware tapping\n");
+	}
+
+	if (alps_absolute_mode(psmouse)) {
+		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
+		return -1;
+	}
+
+	if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
+		return -1;
+
+	psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
+	psmouse->dev.relbit[LONG(REL_X)] |= BIT(REL_X);
+	psmouse->dev.relbit[LONG(REL_Y)] |= BIT(REL_Y);
+	psmouse->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A);
+	psmouse->dev.keybit[LONG(BTN_B)] |= BIT(BTN_B);
+
+	psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
+	input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0);
+	input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1023, 0, 0);
+	input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0);
+
+	psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+	psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
+	psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
+	psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
+
+	psmouse->protocol_handler = alps_process_byte;
+	psmouse->disconnect = alps_disconnect;
+	psmouse->reconnect = alps_reconnect;
+	psmouse->pktsize = 6;
+
+	return 0;
+}
+
+int alps_detect(struct psmouse *psmouse, int set_properties)
+{
+	if (alps_get_model(psmouse) < 0)
+		return -1;
+
+	if (set_properties) {
+		psmouse->vendor = "ALPS";
+		psmouse->name = "TouchPad";
+	}
+	return 0;
+}
+
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-12-12 18:19:32 -08:00
@@ -0,0 +1,17 @@
+/*
+ * ALPS touchpad PS/2 mouse driver
+ *
+ * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
+ *
+ * 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 set_properties);
+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-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/logips2pp.c	2004-12-12 18:19:32 -08:00
@@ -11,6 +11,7 @@
 
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <linux/libps2.h>
 #include "psmouse.h"
 #include "logips2pp.h"
 
@@ -37,13 +38,23 @@
  * Process a PS2++ or PS2T++ packet.
  */
 
-void ps2pp_process_packet(struct psmouse *psmouse)
+static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 {
 	struct input_dev *dev = &psmouse->dev;
-        unsigned char *packet = psmouse->packet;
+	unsigned char *packet = psmouse->packet;
+
+	if (psmouse->pktcnt < 3)
+		return PSMOUSE_GOOD_DATA;
+
+/*
+ * Full packet accumulated, process it
+ */
+
+	input_regs(dev, regs);
 
 	if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
 
+		/* Logitech extended packet */
 		switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
 
 			case 0x0d: /* Mouse extra info */
@@ -78,11 +89,20 @@
 					(packet[1] >> 4) | (packet[0] & 0x30));
 #endif
 		}
-
-		packet[0] &= 0x0f;
-		packet[1] = 0;
-		packet[2] = 0;
+	} else {
+		/* Standard PS/2 motion data */
+		input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
+		input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
 	}
+
+	input_report_key(dev, BTN_LEFT,    packet[0]       & 1);
+	input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
+	input_report_key(dev, BTN_RIGHT,  (packet[0] >> 1) & 1);
+
+	input_sync(dev);
+
+	return PSMOUSE_FULL_PACKET;
+
 }
 
 /*
@@ -97,7 +117,7 @@
 	if (psmouse_sliced_command(psmouse, command))
 		return -1;
 
-	if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
+	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL))
 		return -1;
 
 	return 0;
@@ -108,40 +128,73 @@
  * enabled if we do nothing to it. Of course I put this in because I want it
  * disabled :P
  * 1 - enabled (if previously disabled, also default)
- * 0/2 - disabled
+ * 0 - disabled
  */
 
-static void ps2pp_set_smartscroll(struct psmouse *psmouse)
+static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll)
 {
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
 	unsigned char param[4];
 
+	if (smartscroll > 1)
+		smartscroll = 1;
+
 	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);
-
-	if (psmouse_smartscroll < 2) {
-		/* 0 - disabled, 1 - enabled */
-		param[0] = psmouse_smartscroll;
-		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);
+
+	param[0] = smartscroll;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+}
+
+static ssize_t psmouse_attr_show_smartscroll(struct psmouse *psmouse, char *buf)
+{
+	return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0);
 }
 
+static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	value = simple_strtoul(buf, &rest, 10);
+	if (*rest || value > 1)
+		return -EINVAL;
+
+	ps2pp_set_smartscroll(psmouse, value);
+	psmouse->smartscroll = value;
+	return count;
+}
+
+PSMOUSE_DEFINE_ATTR(smartscroll);
+
 /*
  * Support 800 dpi resolution _only_ if the user wants it (there are good
  * reasons to not use it even if the mouse supports it, and of course there are
  * also good reasons to use it, let the user decide).
  */
 
-void ps2pp_set_800dpi(struct psmouse *psmouse)
+static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+	if (resolution > 400) {
+		struct ps2dev *ps2dev = &psmouse->ps2dev;
+		unsigned char param = 3;
+
+		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_SETRES);
+		psmouse->resolution = 800;
+	} else
+		psmouse_set_resolution(psmouse, resolution);
+}
+
+static void ps2pp_disconnect(struct psmouse *psmouse)
 {
-	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, &param, PSMOUSE_CMD_SETRES);
+	device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll);
 }
 
 static struct ps2pp_info *get_model_info(unsigned char model)
@@ -238,23 +291,27 @@
 
 int ps2pp_init(struct psmouse *psmouse, int set_properties)
 {
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
 	unsigned char param[4];
-	unsigned char protocol = PSMOUSE_PS2;
 	unsigned char model, buttons;
 	struct ps2pp_info *model_info;
+	int use_ps2pp = 0;
 
 	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] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
-		buttons = param[1];
-		model_info = get_model_info(model);
+	if (!param[1])
+		return -1;
+
+	model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
+	buttons = param[1];
+
+	if ((model_info = get_model_info(model)) != NULL) {
 
 /*
  * Do Logitech PS2++ / PS2T++ magic init.
@@ -263,21 +320,21 @@
 
 			/* 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) &&
+			if (!ps2_command(ps2dev, param, 0x13d1) &&
 			    param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
-				protocol = PSMOUSE_PS2TPP;
+				use_ps2pp = 1;
 			}
 
-		} else if (model_info != NULL) {
+		} else {
 
 			param[0] = param[1] = param[2] = 0;
 			ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
@@ -286,25 +343,37 @@
 			if ((param[0] & 0x78) == 0x48 &&
 			    (param[1] & 0xf3) == 0xc2 &&
 			    (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
-				ps2pp_set_smartscroll(psmouse);
-				protocol = PSMOUSE_PS2PP;
+				ps2pp_set_smartscroll(psmouse, psmouse->smartscroll);
+				use_ps2pp = 1;
 			}
 		}
+	}
 
-		if (set_properties) {
-			psmouse->vendor = "Logitech";
-			psmouse->model = model;
-
-			if (buttons < 3)
-				clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
-			if (buttons < 2)
-				clear_bit(BTN_RIGHT, psmouse->dev.keybit);
+	if (set_properties) {
+		psmouse->vendor = "Logitech";
+		psmouse->model = model;
+
+		if (use_ps2pp) {
+			psmouse->protocol_handler = ps2pp_process_byte;
+			psmouse->pktsize = 3;
+
+			if (model_info->kind != PS2PP_KIND_TP3) {
+				psmouse->set_resolution = ps2pp_set_resolution;
+				psmouse->disconnect = ps2pp_disconnect;
 
-			if (model_info)
-				ps2pp_set_model_properties(psmouse, model_info);
+				device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll);
+			}
 		}
+
+		if (buttons < 3)
+			clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
+		if (buttons < 2)
+			clear_bit(BTN_RIGHT, psmouse->dev.keybit);
+
+		if (model_info)
+			ps2pp_set_model_properties(psmouse, model_info);
 	}
 
-	return protocol;
+	return use_ps2pp ? 0 : -1;
 }
 
diff -Nru a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h
--- a/drivers/input/mouse/logips2pp.h	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/logips2pp.h	2004-12-12 18:19:32 -08:00
@@ -11,8 +11,6 @@
 #ifndef _LOGIPS2PP_H
 #define _LOGIPS2PP_H
 
-void ps2pp_process_packet(struct psmouse *psmouse);
-void ps2pp_set_800dpi(struct psmouse *psmouse);
 int ps2pp_init(struct psmouse *psmouse, int set_properties);
 
 #endif
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/psmouse-base.c	2004-12-12 18:19:32 -08: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 <linux/input.h>
 #include <linux/serio.h>
 #include <linux/init.h>
+#include <linux/libps2.h>
 #include "psmouse.h"
 #include "synaptics.h"
 #include "logips2pp.h"
+#include "alps.h"
 
 #define DRIVER_DESC	"PS/2 mouse driver"
 
@@ -33,15 +36,15 @@
 module_param_named(proto, psmouse_proto, charp, 0);
 MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps). Useful for KVM switches.");
 
-int psmouse_resolution = 200;
+static unsigned int psmouse_resolution = 200;
 module_param_named(resolution, psmouse_resolution, uint, 0);
 MODULE_PARM_DESC(resolution, "Resolution, in dpi.");
 
-unsigned int psmouse_rate = 100;
+static unsigned int psmouse_rate = 100;
 module_param_named(rate, psmouse_rate, uint, 0);
 MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
 
-int psmouse_smartscroll = 1;
+static unsigned int psmouse_smartscroll = 1;
 module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
@@ -49,13 +52,17 @@
 module_param_named(resetafter, psmouse_resetafter, uint, 0);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
+PSMOUSE_DEFINE_ATTR(rate);
+PSMOUSE_DEFINE_ATTR(resolution);
+PSMOUSE_DEFINE_ATTR(resetafter);
+
 __obsolete_setup("psmouse_noext");
 __obsolete_setup("psmouse_resolution=");
 __obsolete_setup("psmouse_smartscroll=");
 __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++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
 
 /*
  * psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -67,7 +74,7 @@
 	struct input_dev *dev = &psmouse->dev;
 	unsigned char *packet = psmouse->packet;
 
-	if (psmouse->pktcnt < 3 + (psmouse->type >= PSMOUSE_GENPS))
+	if (psmouse->pktcnt < psmouse->pktsize)
 		return PSMOUSE_GOOD_DATA;
 
 /*
@@ -77,13 +84,6 @@
 	input_regs(dev, regs);
 
 /*
- * The PS2++ protocol is a little bit complex
- */
-
-	if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP)
-		ps2pp_process_packet(psmouse);
-
-/*
  * Scroll wheel on IntelliMice, scroll buttons on NetMice
  */
 
@@ -110,6 +110,15 @@
 	}
 
 /*
+ * Extra button on ThinkingMouse
+ */
+	if (psmouse->type == PSMOUSE_THINKPS) {
+		input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
+		/* Without this bit of weirdness moving up gives wildly high Y changes. */
+		packet[1] |= (packet[0] & 0x40) << 1;
+	}
+
+/*
  * Generic PS/2 Mouse
  */
 
@@ -144,63 +153,17 @@
 			printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
 				flags & SERIO_TIMEOUT ? " timeout" : "",
 				flags & SERIO_PARITY ? " bad parity" : "");
-		psmouse->nak = 1;
-		clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
-		clear_bit(PSMOUSE_FLAG_CMD,  &psmouse->flags);
-		wake_up_interruptible(&psmouse->wait);
+		ps2_cmd_aborted(&psmouse->ps2dev);
 		goto out;
 	}
 
-	if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) {
-		switch (data) {
-			case PSMOUSE_RET_ACK:
-				psmouse->nak = 0;
-				break;
-
-			case PSMOUSE_RET_NAK:
-				psmouse->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, &psmouse->flags)) {
-					psmouse->nak = 0;
-					break;
-				}
-				/* Fall through */
-			default:
-				goto out;
-		}
-
-		if (!psmouse->nak && psmouse->cmdcnt) {
-			set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
-			set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
-		}
-		clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
-		wake_up_interruptible(&psmouse->wait);
-
-		if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK)
+	if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
+		if  (ps2_handle_ack(&psmouse->ps2dev, data))
 			goto out;
-	}
 
-	if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
-		if (psmouse->cmdcnt)
-			psmouse->cmdbuf[--psmouse->cmdcnt] = data;
-
-		if (test_and_clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags) && psmouse->cmdcnt)
-			wake_up_interruptible(&psmouse->wait);
-
-		if (!psmouse->cmdcnt) {
-			clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
-			wake_up_interruptible(&psmouse->wait);
-		}
-		goto out;
-	}
+	if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
+		if  (ps2_handle_response(&psmouse->ps2dev, data))
+			goto out;
 
 	if (psmouse->state == PSMOUSE_INITIALIZING)
 		goto out;
@@ -243,10 +206,10 @@
 				psmouse->name, psmouse->phys, psmouse->pktcnt);
 			psmouse->pktcnt = 0;
 
-			if (++psmouse->out_of_sync == psmouse_resetafter) {
+			if (++psmouse->out_of_sync == psmouse->resetafter) {
 				psmouse->state = PSMOUSE_IGNORE;
 				printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
-				serio_reconnect(psmouse->serio);
+				serio_reconnect(psmouse->ps2dev.serio);
 			}
 			break;
 
@@ -266,100 +229,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->nak = 1;
-	set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
-
-	if (serio_write(psmouse->serio, byte) == 0)
-		wait_event_interruptible_timeout(psmouse->wait,
-				!test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags),
-				msecs_to_jiffies(200));
-
-	clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
-	return -psmouse->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 >> 12) & 0xf;
-	int receive = (command >> 8) & 0xf;
-	int rc = -1;
-	int i;
-
-	timeout = msecs_to_jiffies(command == PSMOUSE_CMD_RESET_BAT ? 4000 : 500);
-
-	clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
-	if (command == PSMOUSE_CMD_GETID)
-		set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
-
-	if (receive && param)
-		for (i = 0; i < receive; i++)
-			psmouse->cmdbuf[(receive - 1) - i] = param[i];
-
-	psmouse->cmdcnt = receive;
-
-	if (command & 0xff)
-		if (psmouse_sendbyte(psmouse, command & 0xff))
-			goto out;
-
-	for (i = 0; i < send; i++)
-		if (psmouse_sendbyte(psmouse, param[i]))
-			goto out;
-
-	timeout = wait_event_interruptible_timeout(psmouse->wait,
-				!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags), timeout);
-
-	if (psmouse->cmdcnt && timeout > 0) {
-		if (command == PSMOUSE_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)
-			timeout = msecs_to_jiffies(100);
-
-		if (command == PSMOUSE_CMD_GETID &&
-		    psmouse->cmdbuf[receive - 1] != 0xab && psmouse->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, &psmouse->flags);
-			psmouse->cmdcnt = 0;
-		}
-
-		wait_event_interruptible_timeout(psmouse->wait,
-				!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags), timeout);
-	}
-
-	if (param)
-		for (i = 0; i < receive; i++)
-			param[i] = psmouse->cmdbuf[(receive - 1) - i];
-
-	if (psmouse->cmdcnt && (command != PSMOUSE_CMD_RESET_BAT || psmouse->cmdcnt != 1))
-		goto out;
-
-	rc = 0;
-
-out:
-	clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
-	clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
-	clear_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
-	return rc;
-}
 
 /*
  * psmouse_sliced_command() sends an extended PS/2 command to the mouse
@@ -372,12 +241,12 @@
 {
 	int i;
 
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
 		return -1;
 
 	for (i = 6; i >= 0; i -= 2) {
 		unsigned char d = (command >> i) & 3;
-		if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+		if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES))
 			return -1;
 	}
 
@@ -392,7 +261,7 @@
 {
 	unsigned char param[2];
 
-	if (psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT))
+	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT))
 		return -1;
 
 	if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
@@ -405,56 +274,138 @@
 /*
  * Genius NetMouse magic init.
  */
-static int genius_detect(struct psmouse *psmouse)
+static int genius_detect(struct psmouse *psmouse, int set_properties)
 {
+	struct ps2dev *ps2dev = &psmouse->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);
+
+	if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55)
+		return -1;
+
+	if (set_properties) {
+		set_bit(BTN_EXTRA, psmouse->dev.keybit);
+		set_bit(BTN_SIDE, psmouse->dev.keybit);
+		set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+		psmouse->vendor = "Genius";
+		psmouse->name = "Wheel Mouse";
+		psmouse->pktsize = 4;
+	}
 
-	return param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55;
+	return 0;
 }
 
 /*
  * IntelliMouse magic init.
  */
-static int intellimouse_detect(struct psmouse *psmouse)
+static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
 {
+	struct ps2dev *ps2dev = &psmouse->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);
+
+	if (param[0] != 3)
+		return -1;
+
+	if (set_properties) {
+		set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+		if (!psmouse->vendor) psmouse->vendor = "Generic";
+		if (!psmouse->name) psmouse->name = "Wheel Mouse";
+		psmouse->pktsize = 4;
+	}
 
-	return param[0] == 3;
+	return 0;
 }
 
 /*
  * Try IntelliMouse/Explorer magic init.
  */
-static int im_explorer_detect(struct psmouse *psmouse)
+static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
 {
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
 	unsigned char param[2];
 
-	intellimouse_detect(psmouse);
+	intellimouse_detect(psmouse, 0);
 
 	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);
+
+	if (param[0] != 4)
+		return -1;
+
+	if (set_properties) {
+		set_bit(REL_WHEEL, psmouse->dev.relbit);
+		set_bit(BTN_SIDE, psmouse->dev.keybit);
+		set_bit(BTN_EXTRA, psmouse->dev.keybit);
+
+		if (!psmouse->vendor) psmouse->vendor = "Generic";
+		if (!psmouse->name) psmouse->name = "Explorer Mouse";
+		psmouse->pktsize = 4;
+	}
 
-	return param[0] == 4;
+	return 0;
+}
+
+/*
+ * Kensington ThinkingMouse / ExpertMouse magic init.
+ */
+static int thinking_detect(struct psmouse *psmouse, int set_properties)
+{
+	struct ps2dev *ps2dev = &psmouse->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);
+
+	if (param[0] != 2)
+		return -1;
+
+	if (set_properties) {
+		set_bit(BTN_EXTRA, psmouse->dev.keybit);
+
+		psmouse->vendor = "Kensington";
+		psmouse->name = "ThinkingMouse";
+	}
+
+	return 0;
+}
+
+/*
+ * Bare PS/2 protocol "detection". Always succeeds.
+ */
+static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
+{
+	if (!psmouse->vendor) psmouse->vendor = "Generic";
+	if (!psmouse->name) psmouse->name = "Mouse";
+
+	return 0;
 }
 
 /*
@@ -468,16 +419,19 @@
 	int synaptics_hardware = 0;
 
 /*
+ * Try Kensington ThinkingMouse (we try first, because synaptics probe
+ * upsets the thinkingmouse).
+ */
+
+	if (max_proto > PSMOUSE_PS2 && thinking_detect(psmouse, set_properties) == 0)
+		return PSMOUSE_THINKPS;
+
+/*
  * Try Synaptics TouchPad
  */
-	if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
+	if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
 		synaptics_hardware = 1;
 
-		if (set_properties) {
-			psmouse->vendor = "Synaptics";
-			psmouse->name = "TouchPad";
-		}
-
 		if (max_proto > PSMOUSE_IMEX) {
 			if (!set_properties || synaptics_init(psmouse) == 0)
 				return PSMOUSE_SYNAPTICS;
@@ -494,53 +448,43 @@
 		synaptics_reset(psmouse);
 	}
 
-	if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
+/*
+ * Try ALPS TouchPad
+ */
+	if (max_proto > PSMOUSE_IMEX && alps_detect(psmouse, set_properties) == 0) {
+		if (!set_properties || alps_init(psmouse) == 0)
+			return PSMOUSE_ALPS;
 
-		if (set_properties) {
-			set_bit(BTN_EXTRA, psmouse->dev.keybit);
-			set_bit(BTN_SIDE, psmouse->dev.keybit);
-			set_bit(REL_WHEEL, psmouse->dev.relbit);
-			psmouse->vendor = "Genius";
-			psmouse->name = "Wheel Mouse";
-		}
+/*
+ * Init failed, try basic relative protocols
+ */
+		max_proto = PSMOUSE_IMEX;
+	}
 
+	if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0)
 		return PSMOUSE_GENPS;
-	}
 
-	if (max_proto > PSMOUSE_IMEX) {
-		int type = ps2pp_init(psmouse, set_properties);
-		if (type > PSMOUSE_PS2)
-			return type;
-	}
+	if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
+		return PSMOUSE_PS2PP;
 
-	if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) {
-
-		if (set_properties) {
-			set_bit(REL_WHEEL, psmouse->dev.relbit);
-			set_bit(BTN_SIDE, psmouse->dev.keybit);
-			set_bit(BTN_EXTRA, psmouse->dev.keybit);
-			if (!psmouse->name)
-				psmouse->name = "Explorer Mouse";
-		}
+/*
+ * Reset to defaults in case the device got confused by extended
+ * protocol probes.
+ */
+	ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
 
+	if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
 		return PSMOUSE_IMEX;
-	}
-
-	if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) {
-
-		if (set_properties) {
-			set_bit(REL_WHEEL, psmouse->dev.relbit);
-			if (!psmouse->name)
-				psmouse->name = "Wheel Mouse";
-		}
 
+	if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
 		return PSMOUSE_IMPS;
-	}
 
 /*
  * Okay, all failed, we have a standard mouse here. The number of the buttons
  * is still a question, though. We assume 3.
  */
+	ps2bare_detect(psmouse, set_properties);
+
 	if (synaptics_hardware) {
 /*
  * We detected Synaptics hardware but it did not respond to IMPS/2 probes.
@@ -549,7 +493,7 @@
  * extensions.
  */
 		psmouse_reset(psmouse);
-		psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS);
+		ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
 	}
 
 	return PSMOUSE_PS2;
@@ -561,6 +505,7 @@
 
 static int psmouse_probe(struct psmouse *psmouse)
 {
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
 	unsigned char param[2];
 
 /*
@@ -569,8 +514,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 && param[0] != 0x03 && param[0] != 0x04)
@@ -580,8 +524,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->serio->phys);
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
+		printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
 
 	return 0;
 }
@@ -590,38 +534,29 @@
  * Here we set the mouse resolution.
  */
 
-static void psmouse_set_resolution(struct psmouse *psmouse)
+void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
 {
-	unsigned char param[1];
+	unsigned char params[] = { 0, 1, 2, 2, 3 };
 
-	if (psmouse->type == PSMOUSE_PS2PP && psmouse_resolution > 400) {
-		ps2pp_set_800dpi(psmouse);
-		return;
-	}
-
-	if (!psmouse_resolution || psmouse_resolution >= 200)
-		param[0] = 3;
-	else if (psmouse_resolution >= 100)
-		param[0] = 2;
-	else if (psmouse_resolution >= 50)
-		param[0] = 1;
-	else if (psmouse_resolution)
-		param[0] = 0;
+	if (resolution == 0 || resolution > 200)
+		resolution = 200;
 
-        psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	ps2_command(&psmouse->ps2dev, &params[resolution / 50], PSMOUSE_CMD_SETRES);
+	psmouse->resolution = 25 << params[resolution / 50];
 }
 
 /*
  * Here we set the mouse report rate.
  */
 
-static void psmouse_set_rate(struct psmouse *psmouse)
+static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
 {
 	unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
 	int i = 0;
 
-	while (rates[i] > psmouse_rate) i++;
-	psmouse_command(psmouse, rates + i, PSMOUSE_CMD_SETRATE);
+	while (rates[i] > rate) i++;
+	ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE);
+	psmouse->rate = rates[i];
 }
 
 /*
@@ -630,23 +565,21 @@
 
 static void psmouse_initialize(struct psmouse *psmouse)
 {
-	unsigned char param[2];
-
 /*
- * We set the mouse report rate, resolution and scaling.
+ * We set the mouse into streaming mode.
  */
 
-	if (psmouse_max_proto != PSMOUSE_PS2) {
-		psmouse_set_rate(psmouse);
-		psmouse_set_resolution(psmouse);
-		psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
-	}
+	ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM);
 
 /*
- * We set the mouse into streaming mode.
+ * We set the mouse report rate, resolution and scaling.
  */
 
-	psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+	if (psmouse_max_proto != PSMOUSE_PS2) {
+		psmouse->set_rate(psmouse, psmouse->rate);
+		psmouse->set_resolution(psmouse, psmouse->resolution);
+		ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+	}
 }
 
 /*
@@ -657,11 +590,11 @@
 
 static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
 {
-	serio_pause_rx(psmouse->serio);
+	serio_pause_rx(psmouse->ps2dev.serio);
 	psmouse->state = new_state;
-	psmouse->pktcnt = psmouse->cmdcnt = psmouse->out_of_sync = 0;
-	psmouse->flags = 0;
-	serio_continue_rx(psmouse->serio);
+	psmouse->pktcnt = psmouse->out_of_sync = 0;
+	psmouse->ps2dev.flags = 0;
+	serio_continue_rx(psmouse->ps2dev.serio);
 }
 
 /*
@@ -670,8 +603,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->serio->phys);
+	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
+			psmouse->ps2dev.serio->phys);
 
 	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
 }
@@ -684,8 +618,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->serio->phys);
+	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+		printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
+			psmouse->ps2dev.serio->phys);
 
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 }
@@ -710,6 +645,10 @@
 {
 	struct psmouse *psmouse, *parent;
 
+	device_remove_file(&serio->dev, &psmouse_attr_rate);
+	device_remove_file(&serio->dev, &psmouse_attr_resolution);
+	device_remove_file(&serio->dev, &psmouse_attr_resetafter);
+
 	psmouse = serio->private;
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
@@ -755,13 +694,12 @@
 
 	memset(psmouse, 0, sizeof(struct psmouse));
 
-	init_waitqueue_head(&psmouse->wait);
-	init_input_dev(&psmouse->dev);
+	ps2_init(&psmouse->ps2dev, serio);
 	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	psmouse->serio = serio;
 	psmouse->dev.private = psmouse;
+	psmouse->dev.dev = &serio->dev;
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
 	serio->private = psmouse;
@@ -778,13 +716,16 @@
 		goto out;
 	}
 
+	psmouse->rate = psmouse_rate;
+	psmouse->resolution = psmouse_resolution;
+	psmouse->resetafter = psmouse_resetafter;
+	psmouse->smartscroll = psmouse_smartscroll;
+	psmouse->set_rate = psmouse_set_rate;
+	psmouse->set_resolution = psmouse_set_resolution;
+	psmouse->protocol_handler = psmouse_process_byte;
+	psmouse->pktsize = 3;
+
 	psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
-	if (!psmouse->vendor)
-		psmouse->vendor = "Generic";
-	if (!psmouse->name)
-		psmouse->name = "Mouse";
-	if (!psmouse->protocol_handler)
-		psmouse->protocol_handler = psmouse_process_byte;
 
 	sprintf(psmouse->devname, "%s %s %s",
 		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
@@ -809,6 +750,10 @@
 	if (parent && parent->pt_activate)
 		parent->pt_activate(parent);
 
+	device_create_file(&serio->dev, &psmouse_attr_rate);
+	device_create_file(&serio->dev, &psmouse_attr_resolution);
+	device_create_file(&serio->dev, &psmouse_attr_resetafter);
+
 	if (serio->child) {
 		/*
 		 * Nothing to be done here, serio core will detect that
@@ -846,7 +791,7 @@
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
 	if (psmouse->reconnect) {
-	       if (psmouse->reconnect(psmouse))
+		if (psmouse->reconnect(psmouse))
 			goto out;
 	} else if (psmouse_probe(psmouse) < 0 ||
 		   psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
@@ -885,6 +830,115 @@
 	.disconnect	= psmouse_disconnect,
 	.cleanup	= psmouse_cleanup,
 };
+
+ssize_t psmouse_attr_show_helper(struct device *dev, char *buf,
+				 ssize_t (*handler)(struct psmouse *, char *))
+{
+	struct serio *serio = to_serio_port(dev);
+	int retval;
+
+	retval = serio_pin_driver(serio);
+	if (retval)
+		return retval;
+
+	if (serio->drv != &psmouse_drv) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	retval = handler(serio->private, buf);
+
+out:
+	serio_unpin_driver(serio);
+	return retval;
+}
+
+ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count,
+				ssize_t (*handler)(struct psmouse *, const char *, size_t))
+{
+	struct serio *serio = to_serio_port(dev);
+	struct psmouse *psmouse = serio->private, *parent = NULL;
+	int retval;
+
+	retval = serio_pin_driver(serio);
+	if (retval)
+		return retval;
+
+	if (serio->drv != &psmouse_drv) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
+		parent = serio->parent->private;
+		psmouse_deactivate(parent);
+	}
+	psmouse_deactivate(psmouse);
+
+	retval = handler(psmouse, buf, count);
+
+	psmouse_activate(psmouse);
+	if (parent)
+		psmouse_activate(parent);
+
+out:
+	serio_unpin_driver(serio);
+	return retval;
+}
+
+static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
+{
+	return sprintf(buf, "%d\n", psmouse->rate);
+}
+
+static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	value = simple_strtoul(buf, &rest, 10);
+	if (*rest)
+		return -EINVAL;
+
+	psmouse->set_rate(psmouse, value);
+	return count;
+}
+
+static ssize_t psmouse_attr_show_resolution(struct psmouse *psmouse, char *buf)
+{
+	return sprintf(buf, "%d\n", psmouse->resolution);
+}
+
+static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	value = simple_strtoul(buf, &rest, 10);
+	if (*rest)
+		return -EINVAL;
+
+	psmouse->set_resolution(psmouse, value);
+	return count;
+}
+
+static ssize_t psmouse_attr_show_resetafter(struct psmouse *psmouse, char *buf)
+{
+	return sprintf(buf, "%d\n", psmouse->resetafter);
+}
+
+static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *buf, size_t count)
+{
+	unsigned long value;
+	char *rest;
+
+	value = simple_strtoul(buf, &rest, 10);
+	if (*rest)
+		return -EINVAL;
+
+	psmouse->resetafter = value;
+	return count;
+}
 
 static inline void psmouse_parse_proto(void)
 {
diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/psmouse.h	2004-12-12 18:19:32 -08: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,28 +37,29 @@
 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 pktsize;
 	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;
+	unsigned int rate;
+	unsigned int resolution;
+	unsigned int resetafter;
+	unsigned int smartscroll;	/* Logitech only */
 
 	psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
+	void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
+	void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
+
 	int (*reconnect)(struct psmouse *psmouse);
 	void (*disconnect)(struct psmouse *psmouse);
 
@@ -69,19 +67,40 @@
 	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_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);
+void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
 
-extern int psmouse_smartscroll;
-extern unsigned int psmouse_rate;
+ssize_t psmouse_attr_show_helper(struct device *dev, char *buf,
+			ssize_t (*handler)(struct psmouse *, char *));
+ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count,
+			ssize_t (*handler)(struct psmouse *, const char *, size_t));
+
+#define PSMOUSE_DEFINE_ATTR(_name)						\
+static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *);		\
+static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\
+static ssize_t psmouse_do_show_##_name(struct device *d, char *b)		\
+{										\
+	return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name);	\
+}										\
+static ssize_t psmouse_do_set_##_name(struct device *d, const char *b, size_t s)\
+{										\
+	return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name);	\
+}										\
+static struct device_attribute psmouse_attr_##_name = 				\
+	__ATTR(_name, S_IWUSR | S_IRUGO,					\
+		psmouse_do_show_##_name, psmouse_do_set_##_name);
 
 #endif /* _PSMOUSE_H */
diff -Nru a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
--- a/drivers/input/mouse/sermouse.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/sermouse.c	2004-12-12 18:19:32 -08:00
@@ -11,18 +11,18 @@
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or 
+ * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
+ *
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -73,19 +73,19 @@
 
 		case 0:
 			if ((data & 0xf8) != 0x80) return;
-			input_report_key(dev, BTN_LEFT,   !(data & 4)); 
+			input_report_key(dev, BTN_LEFT,   !(data & 4));
 			input_report_key(dev, BTN_RIGHT,  !(data & 1));
 			input_report_key(dev, BTN_MIDDLE, !(data & 2));
 			break;
 
-		case 1: 
-		case 3: 
+		case 1:
+		case 3:
 			input_report_rel(dev, REL_X, data / 2);
 			input_report_rel(dev, REL_Y, -buf[1]);
 			buf[0] = data - data / 2;
 			break;
 
-		case 2: 
+		case 2:
 		case 4:
 			input_report_rel(dev, REL_X, buf[0]);
 			input_report_rel(dev, REL_Y, buf[1] - data);
@@ -145,7 +145,7 @@
 		case 3:
 
 			switch (sermouse->type) {
-			
+
 				case SERIO_MS:
 					 sermouse->type = SERIO_MP;
 
@@ -164,7 +164,7 @@
 					input_report_rel(dev, REL_WHEEL,  (data & 8) - (data & 7));
 					break;
 			}
-					
+
 			break;
 
 		case 4:
@@ -243,7 +243,7 @@
 {
 	struct sermouse *sermouse;
 	unsigned char c;
-	
+
 	if ((serio->type & SERIO_TYPE) != SERIO_RS232)
 		return;
 
@@ -280,6 +280,7 @@
 	sermouse->dev.id.vendor = sermouse->type;
 	sermouse->dev.id.product = c;
 	sermouse->dev.id.version = 0x0100;
+	sermouse->dev.dev = &serio->dev;
 
 	if (serio_open(serio, drv)) {
 		kfree(sermouse);
@@ -287,7 +288,7 @@
 	}
 
 	input_register_device(&sermouse->dev);
-	
+
 	printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
 }
 
diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/synaptics.c	2004-12-12 18:19:32 -08:00
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <linux/libps2.h>
 #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(&psmouse->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(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
 		return -1;
 	return 0;
 }
@@ -192,23 +193,37 @@
 	return 0;
 }
 
-static int synaptics_set_mode(struct psmouse *psmouse, int mode)
+static int synaptics_set_absolute_mode(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv = psmouse->private;
 
-	mode |= SYN_BIT_ABSOLUTE_MODE;
-	if (psmouse_rate >= 80)
-		mode |= SYN_BIT_HIGH_RATE;
+	priv->mode = SYN_BIT_ABSOLUTE_MODE;
 	if (SYN_ID_MAJOR(priv->identity) >= 4)
-		mode |= SYN_BIT_DISABLE_GESTURE;
+		priv->mode |= SYN_BIT_DISABLE_GESTURE;
 	if (SYN_CAP_EXTENDED(priv->capabilities))
-		mode |= SYN_BIT_W_MODE;
-	if (synaptics_mode_cmd(psmouse, mode))
+		priv->mode |= SYN_BIT_W_MODE;
+
+	if (synaptics_mode_cmd(psmouse, priv->mode))
 		return -1;
 
 	return 0;
 }
 
+static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	if (rate >= 80) {
+		priv->mode |= SYN_BIT_HIGH_RATE;
+		psmouse->rate = 80;
+	} else {
+		priv->mode &= ~SYN_BIT_HIGH_RATE;
+		psmouse->rate = 40;
+	}
+
+	synaptics_mode_cmd(psmouse, priv->mode);
+}
+
 /*****************************************************************************
  *	Synaptics pass-through PS/2 port support
  ****************************************************************************/
@@ -219,7 +234,7 @@
 
 	if (psmouse_sliced_command(parent, c))
 		return -1;
-	if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
+	if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE))
 		return -1;
 	return 0;
 }
@@ -245,12 +260,18 @@
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
 {
-	struct psmouse *child = psmouse->serio->child->private;
+	struct psmouse *child = psmouse->ps2dev.serio->child->private;
+	struct synaptics_data *priv = psmouse->private;
 
 	/* adjust the touchpad to child's choice of protocol */
-	if (child && child->type >= PSMOUSE_GENPS) {
-		if (synaptics_set_mode(psmouse, SYN_BIT_FOUR_BYTE_CLIENT))
-			printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+	if (child) {
+		if (child->type >= PSMOUSE_GENPS)
+			priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
+		else
+			priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
+
+		if (synaptics_mode_cmd(psmouse, priv->mode))
+			printk(KERN_INFO "synaptics: failed to switch guest protocol\n");
 	}
 }
 
@@ -270,11 +291,11 @@
 	strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
 	strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
 	serio->write = synaptics_pt_write;
-	serio->parent = psmouse->serio;
+	serio->parent = psmouse->ps2dev.serio;
 
 	psmouse->pt_activate = synaptics_pt_activate;
 
-	psmouse->serio->child = serio;
+	psmouse->ps2dev.serio->child = serio;
 }
 
 /*****************************************************************************
@@ -470,8 +491,8 @@
 			priv->pkt_type = synaptics_detect_pkt_type(psmouse);
 
 		if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
-			if (psmouse->serio->child)
-				synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet);
+			if (psmouse->ps2dev.serio->child)
+				synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
 		} else
 			synaptics_process_packet(psmouse);
 
@@ -537,7 +558,7 @@
 	struct synaptics_data *priv = psmouse->private;
 	struct synaptics_data old_priv = *priv;
 
-	if (!synaptics_detect(psmouse))
+	if (synaptics_detect(psmouse, 0))
 		return -1;
 
 	if (synaptics_query_hardware(psmouse)) {
@@ -551,7 +572,7 @@
 	    old_priv.ext_cap != priv->ext_cap)
 		return -1;
 
-	if (synaptics_set_mode(psmouse, 0)) {
+	if (synaptics_set_absolute_mode(psmouse)) {
 		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
 		return -1;
 	}
@@ -559,19 +580,28 @@
 	return 0;
 }
 
-int synaptics_detect(struct psmouse *psmouse)
+int synaptics_detect(struct psmouse *psmouse, int set_properties)
 {
+	struct ps2dev *ps2dev = &psmouse->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);
+
+	if (param[1] != 0x47)
+		return -1;
+
+	if (set_properties) {
+		psmouse->vendor = "Synaptics";
+		psmouse->name = "TouchPad";
+	}
 
-	return param[1] == 0x47;
+	return 0;
 }
 
 int synaptics_init(struct psmouse *psmouse)
@@ -588,7 +618,7 @@
 		goto init_fail;
 	}
 
-	if (synaptics_set_mode(psmouse, 0)) {
+	if (synaptics_set_absolute_mode(psmouse)) {
 		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
 		goto init_fail;
 	}
@@ -602,8 +632,10 @@
 	set_input_params(&psmouse->dev, priv);
 
 	psmouse->protocol_handler = synaptics_process_byte;
+	psmouse->set_rate = synaptics_set_rate;
 	psmouse->disconnect = synaptics_disconnect;
 	psmouse->reconnect = synaptics_reconnect;
+	psmouse->pktsize = 6;
 
 	return 0;
 
diff -Nru a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
--- a/drivers/input/mouse/synaptics.h	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/synaptics.h	2004-12-12 18:19:32 -08:00
@@ -9,7 +9,7 @@
 #ifndef _SYNAPTICS_H
 #define _SYNAPTICS_H
 
-extern int synaptics_detect(struct psmouse *psmouse);
+extern int synaptics_detect(struct psmouse *psmouse, int set_properties);
 extern int synaptics_init(struct psmouse *psmouse);
 extern void synaptics_reset(struct psmouse *psmouse);
 
@@ -104,6 +104,7 @@
 	/* Data for normal processing */
 	int old_w;				/* Previous w value */
 	unsigned char pkt_type;			/* packet type - old, new, etc */
+	unsigned char mode;			/* current mode byte */
 };
 
 #endif /* _SYNAPTICS_H */
diff -Nru a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
--- a/drivers/input/mouse/vsxxxaa.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mouse/vsxxxaa.c	2004-12-12 18:19:32 -08:00
@@ -1,11 +1,14 @@
 /*
- * DEC VSXXX-AA and VSXXX-GA mouse driver.
+ * Driver for	DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
+ * 		DEC VSXXX-GA mouse (rectangular mouse, with ball)
+ * 		DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
  *
  * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
  *
- * The packet format was taken from a patch to GPM which is (C) 2001
+ * The packet format was initially taken from a patch to GPM which is (C) 2001
  * by	Karsten Merker <merker@linuxtag.org>
  * and	Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ * Later on, I had access to the device's documentation (referenced below).
  */
 
 /*
@@ -25,7 +28,7 @@
  */
 
 /*
- * Building an adaptor to DB9 / DB25 RS232
+ * Building an adaptor to DE9 / DB25 RS232
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
  * DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for
@@ -42,8 +45,8 @@
  *  | 4 --- 3 |
  *   \  2 1  /
  *    -------
- * 
- *	DEC socket	DB9	DB25	Note
+ *
+ *	DEC socket	DE9	DB25	Note
  *	1 (GND)		5	7	-
  *	2 (RxD)		2	3	-
  *	3 (TxD)		3	2	-
@@ -82,7 +85,7 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 
-#define DRIVER_DESC	"Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"
+#define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet"
 
 MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
 MODULE_DESCRIPTION (DRIVER_DESC);
@@ -104,7 +107,7 @@
 #define VSXXXAA_PACKET_REL	0x80
 #define VSXXXAA_PACKET_ABS	0xc0
 #define VSXXXAA_PACKET_POR	0xa0
-#define MATCH_PACKET_TYPE(data, type)	(((data) & VSXXXAA_PACKET_MASK) == type)
+#define MATCH_PACKET_TYPE(data, type)	(((data) & VSXXXAA_PACKET_MASK) == (type))
 
 
 
@@ -150,7 +153,7 @@
 {
 	switch (mouse->type) {
 		case 0x02:
-			sprintf (mouse->name, "DEC VSXXX-AA/GA mouse");
+			sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse");
 			break;
 
 		case 0x04:
@@ -158,7 +161,8 @@
 			break;
 
 		default:
-			sprintf (mouse->name, "unknown DEC pointer device");
+			sprintf (mouse->name, "unknown DEC pointer device "
+					"(type = 0x%02x)", mouse->type);
 			break;
 	}
 
@@ -336,13 +340,10 @@
 	 *
 	 * M: manufacturer location code
 	 * R: revision code
-	 * E: Error code. I'm not sure about these, but gpm's sources,
-	 *    which support this mouse, too, tell about them:
-	 *	E = [0x00 .. 0x1f]: no error, byte #3 is button state
-	 *	E = 0x3d: button error, byte #3 tells which one.
-	 *	E = <else>: other error
+	 * E: Error code. If it's in the range of 0x00..0x1f, only some
+	 *    minor problem occured. Errors >= 0x20 are considered bad
+	 *    and the device may not work properly...
 	 * D: <0010> == mouse, <0100> == tablet
-	 *
 	 */
 
 	mouse->version = buf[0] & 0x0f;
@@ -363,28 +364,32 @@
 	vsxxxaa_detection_done (mouse);
 
 	if (error <= 0x1f) {
-		/* No error. Report buttons */
+		/* No (serious) error. Report buttons */
 		input_regs (dev, regs);
 		input_report_key (dev, BTN_LEFT, left);
 		input_report_key (dev, BTN_MIDDLE, middle);
 		input_report_key (dev, BTN_RIGHT, right);
 		input_report_key (dev, BTN_TOUCH, 0);
 		input_sync (dev);
-	} else {
-		printk (KERN_ERR "Your %s on %s reports an undefined error, "
-				"please check it...\n", mouse->name,
-				mouse->phys);
+
+		if (error != 0)
+			printk (KERN_INFO "Your %s on %s reports error=0x%02x\n",
+					mouse->name, mouse->phys, error);
+
 	}
 
 	/*
 	 * If the mouse was hot-plugged, we need to force differential mode
 	 * now... However, give it a second to recover from it's reset.
 	 */
-	printk (KERN_NOTICE "%s on %s: Forceing standard packet format and "
-			"streaming mode\n", mouse->name, mouse->phys);
-	mouse->serio->write (mouse->serio, 'S');
+	printk (KERN_NOTICE "%s on %s: Forceing standard packet format, "
+			"incremental streaming mode and 72 samples/sec\n",
+			mouse->name, mouse->phys);
+	mouse->serio->write (mouse->serio, 'S');	/* Standard format */
+	mdelay (50);
+	mouse->serio->write (mouse->serio, 'R');	/* Incremental */
 	mdelay (50);
-	mouse->serio->write (mouse->serio, 'R');
+	mouse->serio->write (mouse->serio, 'L');	/* 72 samples/sec */
 }
 
 static void
@@ -519,11 +524,12 @@
 	mouse->dev.private = mouse;
 	serio->private = mouse;
 
-	sprintf (mouse->name, "DEC VSXXX-AA/GA mouse or VSXXX-AB digitizer");
+	sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer");
 	sprintf (mouse->phys, "%s/input0", serio->phys);
 	mouse->dev.name = mouse->name;
 	mouse->dev.phys = mouse->phys;
 	mouse->dev.id.bustype = BUS_RS232;
+	mouse->dev.dev = &serio->dev;
 	mouse->serio = serio;
 
 	if (serio_open (serio, drv)) {
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/mousedev.c	2004-12-12 18:19:32 -08:00
@@ -115,20 +115,26 @@
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 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->touch) {
 		switch (code) {
 			case ABS_X:
+				size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+				if (size == 0) size = xres;
 				fx(0) = value;
 				if (mousedev->pkt_count >= 2)
-					mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
+					mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) * xres / (size * 2);
 				break;
 
 			case ABS_Y:
+				size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
+				if (size == 0) size = yres;
 				fy(0) = value;
 				if (mousedev->pkt_count >= 2)
-					mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
+					mousedev->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->dev->keybit))
-				mousedev_touchpad_event(mousedev, code, value);
+				mousedev_touchpad_event(handle->dev, mousedev, code, value);
 			else
 				mousedev_abs_event(handle->dev, mousedev, code, value);
 
@@ -329,8 +335,6 @@
 
 static void mousedev_free(struct mousedev *mousedev)
 {
-	devfs_remove("input/mouse%d", mousedev->minor);
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
 	mousedev_table[mousedev->minor] = NULL;
 	kfree(mousedev);
 }
@@ -640,6 +644,8 @@
 {
 	struct mousedev *mousedev = handle->private;
 
+	class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
+	devfs_remove("input/mouse%d", mousedev->minor);
 	mousedev->exist = 0;
 
 	if (mousedev->open) {
diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/Kconfig	2004-12-12 18:19:32 -08: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-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/Makefile	2004-12-12 18:19:32 -08: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/gscps2.c b/drivers/input/serio/gscps2.c
--- a/drivers/input/serio/gscps2.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/gscps2.c	2004-12-12 18:19:32 -08:00
@@ -322,19 +322,6 @@
 	gscps2_enable(ps2port, DISABLE);
 }
 
-static struct serio gscps2_serio_port =
-{
-	.name =		"GSC PS/2",
-	.idbus =	BUS_GSC,
-	.idvendor =	PCI_VENDOR_ID_HP,
-	.idproduct =	0x0001,
-	.idversion =	0x0010,
-	.type =		SERIO_8042,
-	.write =	gscps2_write,
-	.open =		gscps2_open,
-	.close =	gscps2_close,
-};
-
 /**
  * gscps2_probe() - Probes PS2 devices
  * @return: success/error report
diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
--- a/drivers/input/serio/i8042-io.h	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/i8042-io.h	2004-12-12 18:19:32 -08:00
@@ -3,7 +3,7 @@
 
 /*
  * 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 
+ * under the terms of the GNU General Public License version 2 as published by
  * the Free Software Foundation.
  */
 
@@ -22,9 +22,6 @@
 #ifdef __alpha__
 # define I8042_KBD_IRQ	1
 # define I8042_AUX_IRQ	(RTC_PORT(0) == 0x170 ? 9 : 12)	/* Jensen is special */
-#elif defined(__ia64__)
-# define I8042_KBD_IRQ isa_irq_to_vector(1)
-# define I8042_AUX_IRQ isa_irq_to_vector(12)
 #elif defined(__arm__)
 /* defined in include/asm-arm/arch-xxx/irqs.h */
 #include <asm/irq.h>
@@ -40,8 +37,8 @@
  * Register numbers.
  */
 
-#define I8042_COMMAND_REG	0x64	
-#define I8042_STATUS_REG	0x64	
+#define I8042_COMMAND_REG	0x64
+#define I8042_STATUS_REG	0x64
 #define I8042_DATA_REG		0x60
 
 static inline int i8042_read_data(void)
@@ -57,59 +54,25 @@
 static inline void i8042_write_data(int val)
 {
 	outb(val, I8042_DATA_REG);
-	return;
 }
 
 static inline void i8042_write_command(int val)
 {
 	outb(val, I8042_COMMAND_REG);
-	return;
 }
 
-#if defined(__i386__)
-
-#include <linux/dmi.h>
-
-static struct dmi_system_id __initdata i8042_dmi_table[] = {
-	{
-		.ident = "Compaq Proliant 8500",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
-			DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "8500"),
-		},
-	},
-	{
-		.ident = "Compaq Proliant DL760",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
-			DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
-			DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
-		},
-	},
-	{ }
-};
-#endif
-
 static inline int i8042_platform_init(void)
 {
 /*
- * On ix86 platforms touching the i8042 data register region can do really
- * bad things. Because of this the region is always reserved on ix86 boxes.
+ * On some platforms touching the i8042 data register region can do really
+ * bad things. Because of this the region is always reserved on such boxes.
  */
-#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) && !defined(__mips__) && !defined (CONFIG_PPC64)
+#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64)
 	if (!request_region(I8042_DATA_REG, 16, "i8042"))
 		return -1;
 #endif
 
-#if !defined(__i386__) && !defined(__x86_64__)
         i8042_reset = 1;
-#endif
-
-#if defined(__i386__)
-	if (dmi_check_system(i8042_dmi_table))
-		i8042_noloop = 1;
-#endif
 
 #if defined(CONFIG_PPC64)
 	if (check_legacy_ioport(I8042_DATA_REG))
@@ -122,7 +85,7 @@
 
 static inline void i8042_platform_exit(void)
 {
-#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) && !defined(CONFIG_PPC64)
+#if !defined(__sh__) && !defined(__alpha__) && !defined(CONFIG_PPC64)
 	release_region(I8042_DATA_REG, 16);
 #endif
 }
diff -Nru a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/input/serio/i8042-x86ia64io.h	2004-12-12 18:19:32 -08:00
@@ -0,0 +1,308 @@
+#ifndef _I8042_X86IA64IO_H
+#define _I8042_X86IA64IO_H
+
+/*
+ * 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.
+ */
+
+/*
+ * Names.
+ */
+
+#define I8042_KBD_PHYS_DESC "isa0060/serio0"
+#define I8042_AUX_PHYS_DESC "isa0060/serio1"
+#define I8042_MUX_PHYS_DESC "isa0060/serio%d"
+
+/*
+ * IRQs.
+ */
+
+#if defined(__ia64__)
+# define I8042_MAP_IRQ(x)	isa_irq_to_vector((x))
+#else
+# define I8042_MAP_IRQ(x)	(x)
+#endif
+
+#define I8042_KBD_IRQ	i8042_kbd_irq
+#define I8042_AUX_IRQ	i8042_aux_irq
+
+static int i8042_kbd_irq;
+static int i8042_aux_irq;
+
+/*
+ * Register numbers.
+ */
+
+#define I8042_COMMAND_REG	i8042_command_reg
+#define I8042_STATUS_REG	i8042_command_reg
+#define I8042_DATA_REG		i8042_data_reg
+
+static int i8042_command_reg = 0x64;
+static int i8042_data_reg = 0x60;
+
+
+static inline int i8042_read_data(void)
+{
+	return inb(I8042_DATA_REG);
+}
+
+static inline int i8042_read_status(void)
+{
+	return inb(I8042_STATUS_REG);
+}
+
+static inline void i8042_write_data(int val)
+{
+	outb(val, I8042_DATA_REG);
+}
+
+static inline void i8042_write_command(int val)
+{
+	outb(val, I8042_COMMAND_REG);
+}
+
+#if defined(__i386__)
+
+#include <linux/dmi.h>
+
+static struct dmi_system_id __initdata i8042_dmi_table[] = {
+	{
+		.ident = "Compaq Proliant 8500",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+			DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "8500"),
+		},
+	},
+	{
+		.ident = "Compaq Proliant DL760",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+			DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
+		},
+	},
+	{ }
+};
+#endif
+
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+struct i8042_acpi_resources {
+	unsigned int port1;
+	unsigned int port2;
+	unsigned int irq;
+};
+
+static int i8042_acpi_kbd_registered;
+static int i8042_acpi_aux_registered;
+
+static acpi_status i8042_acpi_parse_resource(struct acpi_resource *res, void *data)
+{
+	struct i8042_acpi_resources *i8042_res = data;
+	struct acpi_resource_io *io;
+	struct acpi_resource_fixed_io *fixed_io;
+	struct acpi_resource_irq *irq;
+	struct acpi_resource_ext_irq *ext_irq;
+
+	switch (res->id) {
+		case ACPI_RSTYPE_IO:
+			io = &res->data.io;
+			if (io->range_length) {
+				if (!i8042_res->port1)
+					i8042_res->port1 = io->min_base_address;
+				else
+					i8042_res->port2 = io->min_base_address;
+			}
+			break;
+
+		case ACPI_RSTYPE_FIXED_IO:
+			fixed_io = &res->data.fixed_io;
+			if (fixed_io->range_length) {
+				if (!i8042_res->port1)
+					i8042_res->port1 = fixed_io->base_address;
+				else
+					i8042_res->port2 = fixed_io->base_address;
+			}
+			break;
+
+		case ACPI_RSTYPE_IRQ:
+			irq = &res->data.irq;
+			if (irq->number_of_interrupts > 0)
+				i8042_res->irq =
+					acpi_register_gsi(irq->interrupts[0],
+							  irq->edge_level,
+							  irq->active_high_low);
+			break;
+
+		case ACPI_RSTYPE_EXT_IRQ:
+			ext_irq = &res->data.extended_irq;
+			if (ext_irq->number_of_interrupts > 0)
+				i8042_res->irq =
+					acpi_register_gsi(ext_irq->interrupts[0],
+							  ext_irq->edge_level,
+							  ext_irq->active_high_low);
+			break;
+	}
+	return AE_OK;
+}
+
+static int i8042_acpi_kbd_add(struct acpi_device *device)
+{
+	struct i8042_acpi_resources kbd_res;
+	acpi_status status;
+
+	memset(&kbd_res, 0, sizeof(kbd_res));
+	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+				     i8042_acpi_parse_resource, &kbd_res);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	if (kbd_res.port1)
+		i8042_data_reg = kbd_res.port1;
+	else
+		printk(KERN_WARNING "ACPI: [%s] has no data port; default is 0x%x\n",
+			acpi_device_bid(device), i8042_data_reg);
+
+	if (kbd_res.port2)
+		i8042_command_reg = kbd_res.port2;
+	else
+		printk(KERN_WARNING "ACPI: [%s] has no command port; default is 0x%x\n",
+			acpi_device_bid(device), i8042_command_reg);
+
+	if (kbd_res.irq)
+		i8042_kbd_irq = kbd_res.irq;
+	else
+		printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
+			acpi_device_bid(device), i8042_kbd_irq);
+
+	strncpy(acpi_device_name(device), "PS/2 Keyboard Controller",
+		sizeof(acpi_device_name(device)));
+	printk("ACPI: %s [%s] at I/O 0x%x, 0x%x, irq %d\n",
+		acpi_device_name(device), acpi_device_bid(device),
+		i8042_data_reg, i8042_command_reg, i8042_kbd_irq);
+
+	return 0;
+}
+
+static int i8042_acpi_aux_add(struct acpi_device *device)
+{
+	struct i8042_acpi_resources aux_res;
+	acpi_status status;
+
+	memset(&aux_res, 0, sizeof(aux_res));
+	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+				     i8042_acpi_parse_resource, &aux_res);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	if (aux_res.irq)
+		i8042_aux_irq = aux_res.irq;
+	else
+		printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
+			acpi_device_bid(device), i8042_aux_irq);
+
+	strncpy(acpi_device_name(device), "PS/2 Mouse Controller",
+		sizeof(acpi_device_name(device)));
+	printk("ACPI: %s [%s] at irq %d\n",
+		acpi_device_name(device), acpi_device_bid(device), i8042_aux_irq);
+
+	return 0;
+}
+
+static struct acpi_driver i8042_acpi_kbd_driver = {
+	.name		= "i8042",
+	.ids		= "PNP0303,PNP030B",
+	.ops		= {
+		.add		= i8042_acpi_kbd_add,
+	},
+};
+
+static struct acpi_driver i8042_acpi_aux_driver = {
+	.name		= "i8042",
+	.ids		= "PNP0F13,SYN0801",
+	.ops		= {
+		.add		= i8042_acpi_aux_add,
+	},
+};
+
+static int i8042_acpi_init(void)
+{
+	int result;
+
+	if (acpi_disabled || i8042_noacpi) {
+		printk("i8042: ACPI detection disabled\n");
+		return 0;
+	}
+
+	result = acpi_bus_register_driver(&i8042_acpi_kbd_driver);
+	if (result < 0)
+		return result;
+
+	if (result == 0) {
+		acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
+		return -ENODEV;
+	}
+	i8042_acpi_kbd_registered = 1;
+
+	result = acpi_bus_register_driver(&i8042_acpi_aux_driver);
+	if (result >= 0)
+		i8042_acpi_aux_registered = 1;
+	if (result == 0)
+		i8042_noaux = 1;
+
+	return 0;
+}
+
+static void i8042_acpi_exit(void)
+{
+	if (i8042_acpi_kbd_registered)
+		acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
+
+	if (i8042_acpi_aux_registered)
+		acpi_bus_unregister_driver(&i8042_acpi_aux_driver);
+}
+#endif
+
+static inline int i8042_platform_init(void)
+{
+/*
+ * On ix86 platforms touching the i8042 data register region can do really
+ * bad things. Because of this the region is always reserved on ix86 boxes.
+ *
+ *	if (!request_region(I8042_DATA_REG, 16, "i8042"))
+ *		return -1;
+ */
+
+	i8042_kbd_irq = I8042_MAP_IRQ(1);
+	i8042_aux_irq = I8042_MAP_IRQ(12);
+
+#ifdef CONFIG_ACPI
+	if (i8042_acpi_init())
+		return -1;
+#endif
+
+#if defined(__ia64__)
+        i8042_reset = 1;
+#endif
+
+#if defined(__i386__)
+	if (dmi_check_system(i8042_dmi_table))
+		i8042_noloop = 1;
+#endif
+
+	return 0;
+}
+
+static inline void i8042_platform_exit(void)
+{
+#ifdef CONFIG_ACPI
+	i8042_acpi_exit();
+#endif
+}
+
+#endif /* _I8042_X86IA64IO_H */
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/i8042.c	2004-12-12 18:19:32 -08:00
@@ -16,10 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/config.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
-#include <linux/sysdev.h>
-#include <linux/pm.h>
 #include <linux/serio.h>
 #include <linux/err.h>
 
@@ -57,6 +54,19 @@
 module_param_named(noloop, i8042_noloop, bool, 0);
 MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port");
 
+#ifdef CONFIG_ACPI
+static int i8042_noacpi;
+module_param_named(noacpi, i8042_noacpi, bool, 0);
+MODULE_PARM_DESC(noacpi, "Do not use ACPI to detect controller settings");
+#endif
+
+#define DEBUG
+#ifdef DEBUG
+static int i8042_debug;
+module_param_named(debug, i8042_debug, bool, 600);
+MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
+#endif
+
 __obsolete_setup("i8042_noaux");
 __obsolete_setup("i8042_nomux");
 __obsolete_setup("i8042_unlock");
@@ -64,7 +74,6 @@
 __obsolete_setup("i8042_direct");
 __obsolete_setup("i8042_dumbkbd");
 
-#undef DEBUG
 #include "i8042.h"
 
 spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED;
@@ -101,7 +110,6 @@
 static unsigned char i8042_ctr;
 static unsigned char i8042_mux_open;
 static unsigned char i8042_mux_present;
-static struct pm_dev *i8042_pm_dev;
 static struct timer_list i8042_timer;
 static struct platform_device *i8042_platform_device;
 
@@ -852,10 +860,12 @@
  * Here we try to restore the original BIOS settings
  */
 
-static int i8042_controller_suspend(void)
+static int i8042_suspend(struct device *dev, u32 state, u32 level)
 {
-	del_timer_sync(&i8042_timer);
-	i8042_controller_reset();
+	if (level == SUSPEND_DISABLE) {
+		del_timer_sync(&i8042_timer);
+		i8042_controller_reset();
+	}
 
 	return 0;
 }
@@ -865,10 +875,13 @@
  * Here we try to reset everything back to a state in which suspended
  */
 
-static int i8042_controller_resume(void)
+static int i8042_resume(struct device *dev, u32 level)
 {
 	int i;
 
+	if (level != RESUME_ENABLE)
+		return 0;
+
 	if (i8042_controller_init()) {
 		printk(KERN_ERR "i8042: resume failed\n");
 		return -1;
@@ -901,42 +914,14 @@
 	panic_blink = i8042_panic_blink;
 
 	return 0;
-}
 
+}
 
 /*
  * We need to reset the 8042 back to original mode on system shutdown,
  * because otherwise BIOSes will be confused.
  */
 
-static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
-        		    void *unused)
-{
-        if (code == SYS_DOWN || code == SYS_HALT)
-        	i8042_controller_cleanup();
-        return NOTIFY_DONE;
-}
-
-static struct notifier_block i8042_notifier =
-{
-        i8042_notify_sys,
-        NULL,
-        0
-};
-
-/*
- * Suspend/resume handlers for the new PM scheme (driver model)
- */
-static int i8042_suspend(struct device *dev, u32 state, u32 level)
-{
-	return level == SUSPEND_DISABLE ? i8042_controller_suspend() : 0;
-}
-
-static int i8042_resume(struct device *dev, u32 level)
-{
-	return level == RESUME_ENABLE ? i8042_controller_resume() : 0;
-}
-
 static void i8042_shutdown(struct device *dev)
 {
 	i8042_controller_cleanup();
@@ -950,22 +935,6 @@
 	.shutdown	= i8042_shutdown,
 };
 
-/*
- * Suspend/resume handler for the old PM scheme (APM)
- */
-static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dummy)
-{
-	switch (request) {
-		case PM_SUSPEND:
-			return i8042_controller_suspend();
-
-		case PM_RESUME:
-			return i8042_controller_resume();
-	}
-
-	return 0;
-}
-
 static struct serio * __init i8042_allocate_kbd_port(void)
 {
 	struct serio *serio;
@@ -1080,21 +1049,12 @@
 
 	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
-	i8042_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, i8042_pm_callback);
-
-	register_reboot_notifier(&i8042_notifier);
-
 	return 0;
 }
 
 void __exit i8042_exit(void)
 {
 	int i;
-
-	unregister_reboot_notifier(&i8042_notifier);
-
-	if (i8042_pm_dev)
-		pm_unregister(i8042_pm_dev);
 
 	i8042_controller_cleanup();
 
diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
--- a/drivers/input/serio/i8042.h	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/i8042.h	2004-12-12 18:19:32 -08:00
@@ -23,6 +23,8 @@
 #include "i8042-ppcio.h"
 #elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)
 #include "i8042-sparcio.h"
+#elif defined(CONFIG_X86) || defined(CONFIG_IA64)
+#include "i8042-x86ia64io.h"
 #else
 #include "i8042-io.h"
 #endif
@@ -117,8 +119,12 @@
 #ifdef DEBUG
 static unsigned long i8042_start;
 #define dbg_init() do { i8042_start = jiffies; } while (0)
-#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" ,\
-	 ## arg, (int) (jiffies - i8042_start))
+#define dbg(format, arg...) 							\
+	do { 									\
+		if (i8042_debug)						\
+			printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" ,	\
+	 			## arg, (int) (jiffies - i8042_start));		\
+	} while (0)
 #else
 #define dbg_init() do { } while (0)
 #define dbg(format, arg...) do {} while (0)
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-12-12 18:19:32 -08:00
@@ -0,0 +1,295 @@
+/*
+ * 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 <linux/delay.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/libps2.h>
+
+#define DRIVER_DESC	"PS/2 driver library"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+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, int timeout)
+{
+	serio_pause_rx(ps2dev->serio);
+	ps2dev->nak = 1;
+	ps2dev->flags |= PS2_FLAG_ACK;
+	serio_continue_rx(ps2dev->serio);
+
+	if (serio_write(ps2dev->serio, byte) == 0)
+		wait_event_interruptible_timeout(ps2dev->wait,
+					!(ps2dev->flags & PS2_FLAG_ACK),
+					msecs_to_jiffies(timeout));
+
+	serio_pause_rx(ps2dev->serio);
+	ps2dev->flags &= ~PS2_FLAG_ACK;
+	serio_continue_rx(ps2dev->serio);
+
+	return -ps2dev->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 >> 12) & 0xf;
+	int receive = (command >> 8) & 0xf;
+	int rc = -1;
+	int i;
+
+	down(&ps2dev->cmd_sem);
+
+	serio_pause_rx(ps2dev->serio);
+	ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
+	ps2dev->cmdcnt = receive;
+	if (receive && param)
+		for (i = 0; i < receive; i++)
+			ps2dev->cmdbuf[(receive - 1) - i] = param[i];
+	serio_continue_rx(ps2dev->serio);
+
+	/*
+	 * Some devices (Synaptics) peform the reset before
+	 * ACKing the reset command, and so it can take a long
+	 * time before the ACK arrrives.
+	 */
+	if (command & 0xff)
+		if (ps2_sendbyte(ps2dev, command & 0xff,
+			command == PS2_CMD_RESET_BAT ? 1000 : 200))
+			goto out;
+
+	for (i = 0; i < send; i++)
+		if (ps2_sendbyte(ps2dev, param[i], 200))
+			goto out;
+
+	/*
+	 * The reset command takes a long time to execute.
+	 */
+	timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500);
+
+	wait_event_interruptible_timeout(ps2dev->wait,
+		!(ps2dev->flags & PS2_FLAG_CMD1), timeout);
+
+	if (ps2dev->cmdcnt && timeout > 0) {
+
+		if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
+			/*
+			 * Device has sent the first response byte
+			 * after a reset command, reset is thus done,
+			 * shorten the timeout. The next byte will come
+			 * soon (keyboard) or not at all (mouse).
+			 */
+			timeout = msecs_to_jiffies(100);
+		}
+
+		if (command == PS2_CMD_GETID &&
+		    ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
+		    ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
+		    ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
+		    ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
+		    ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
+		    ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
+			/*
+			 * 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->serio);
+			ps2dev->flags = ps2dev->cmdcnt = 0;
+			serio_continue_rx(ps2dev->serio);
+		}
+
+		wait_event_interruptible_timeout(ps2dev->wait,
+				!(ps2dev->flags & PS2_FLAG_CMD), timeout);
+	}
+
+	if (param)
+		for (i = 0; i < receive; i++)
+			param[i] = ps2dev->cmdbuf[(receive - 1) - i];
+
+	if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1))
+		goto out;
+
+	rc = 0;
+
+out:
+	serio_pause_rx(ps2dev->serio);
+	ps2dev->flags = 0;
+	serio_continue_rx(ps2dev->serio);
+
+	up(&ps2dev->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->ps2dev, ps2work->param, ps2work->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 >> 12) & 0xf;
+	int receive = (command >> 8) & 0xf;
+
+	if (!(ps2work = kmalloc(sizeof(struct ps2work) + max(send, receive), GFP_ATOMIC)))
+		return -1;
+
+	memset(ps2work, 0, sizeof(struct ps2work));
+	ps2work->ps2dev = ps2dev;
+	ps2work->command = command;
+	memcpy(ps2work->param, param, send);
+	INIT_WORK(&ps2work->work, ps2_execute_scheduled_command, ps2work);
+
+	if (!schedule_work(&ps2work->work)) {
+		kfree(ps2work);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * ps2_init() initializes ps2dev structure
+ */
+
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
+{
+	init_MUTEX(&ps2dev->cmd_sem);
+	init_waitqueue_head(&ps2dev->wait);
+	ps2dev->serio = serio;
+}
+
+/*
+ * ps2_handle_ack()
+ */
+
+int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
+{
+	switch (data) {
+		case PS2_RET_ACK:
+			ps2dev->nak = 0;
+			break;
+
+		case PS2_RET_NAK:
+			ps2dev->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->flags & PS2_FLAG_WAITID) {
+				ps2dev->nak = 0;
+				break;
+			}
+			/* Fall through */
+		default:
+			return 1;
+	}
+
+	if (!ps2dev->nak && ps2dev->cmdcnt)
+		ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
+
+	ps2dev->flags &= ~PS2_FLAG_ACK;
+	wake_up_interruptible(&ps2dev->wait);
+
+	return data == PS2_RET_ACK || data == PS2_RET_NAK;
+}
+
+
+int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
+{
+	if (ps2dev->cmdcnt)
+		ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
+
+	if (ps2dev->flags & PS2_FLAG_CMD1) {
+		ps2dev->flags &= ~PS2_FLAG_CMD1;
+		if (ps2dev->cmdcnt)
+			wake_up_interruptible(&ps2dev->wait);
+	}
+
+	if (!ps2dev->cmdcnt) {
+		ps2dev->flags &= ~PS2_FLAG_CMD;
+		wake_up_interruptible(&ps2dev->wait);
+	}
+
+	return 1;
+}
+
+void ps2_cmd_aborted(struct ps2dev *ps2dev)
+{
+	if (ps2dev->flags & PS2_FLAG_ACK)
+		ps2dev->nak = 1;
+
+	if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
+		wake_up_interruptible(&ps2dev->wait);
+
+	ps2dev->flags = 0;
+}
+
diff -Nru a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
--- a/drivers/input/serio/parkbd.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/parkbd.c	2004-12-12 18:19:32 -08:00
@@ -37,15 +37,17 @@
 MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(parkbd, "1i");
-MODULE_PARM(parkbd_mode, "1i");
+static unsigned int parkbd_pp_no;
+module_param_named(port, parkbd_pp_no, int, 0);
+MODULE_PARM_DESC(port, "Parallel port the adapter is connected to (default is 0)");
+
+static unsigned int parkbd_mode = SERIO_8042;
+module_param_named(mode, parkbd_mode, uint, 0);
+MODULE_PARM_DESC(mode, "Mode of operation: XT = 0/AT = 1 (default)");
 
 #define PARKBD_CLOCK	0x01	/* Strobe & Ack */
 #define PARKBD_DATA	0x02	/* AutoFd & Busy */
 
-static int parkbd;
-static int parkbd_mode = SERIO_8042;
-
 static int parkbd_buffer;
 static int parkbd_counter;
 static unsigned long parkbd_last;
@@ -126,12 +128,7 @@
 {
 	struct parport *pp;
 
-	if (parkbd < 0) {
-		printk(KERN_ERR "parkbd: no port specified\n");
-		return -ENODEV;
-	}
-
-	pp = parport_find_number(parkbd);
+	pp = parport_find_number(parkbd_pp_no);
 
 	if (pp == NULL) {
 		printk(KERN_ERR "parkbd: no such parport\n");
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/serio/serio.c	2004-12-12 18:19:32 -08:00
@@ -321,6 +321,7 @@
 	try_module_get(THIS_MODULE);
 
 	spin_lock_init(&serio->lock);
+	init_MUTEX(&serio->drv_sem);
 	list_add_tail(&serio->node, &serio_list);
 	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++);
 	serio->dev.bus = &serio_bus;
@@ -590,17 +591,22 @@
 	up(&serio_sem);
 }
 
-/* called from serio_driver->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(&serio->drv_sem);
 	serio_pause_rx(serio);
 	serio->drv = drv;
 	serio_continue_rx(serio);
+	up(&serio->drv_sem);
+}
+
+/* called from serio_driver->connect/disconnect methods under serio_sem */
+int serio_open(struct serio *serio, struct serio_driver *drv)
+{
+	serio_set_drv(serio, drv);
 
 	if (serio->open && serio->open(serio)) {
-		serio_pause_rx(serio);
-		serio->drv = NULL;
-		serio_continue_rx(serio);
+		serio_set_drv(serio, NULL);
 		return -1;
 	}
 	return 0;
@@ -612,9 +618,7 @@
 	if (serio->close)
 		serio->close(serio);
 
-	serio_pause_rx(serio);
-	serio->drv = NULL;
-	serio_continue_rx(serio);
+	serio_set_drv(serio, NULL);
 }
 
 irqreturn_t serio_interrupt(struct serio *serio,
diff -Nru a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
--- a/drivers/input/touchscreen/h3600_ts_input.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/touchscreen/h3600_ts_input.c	2004-12-12 18:19:32 -08:00
@@ -100,6 +100,7 @@
  */
 struct h3600_dev {
 	struct input_dev dev;
+	struct pm_dev *pm_dev;
 	struct serio *serio;
 	unsigned char event;	/* event ID from packet */
 	unsigned char chksum;
@@ -452,8 +453,8 @@
 
 	//h3600_flite_control(1, 25);     /* default brightness */
 #ifdef CONFIG_PM
-	ts->dev.pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT,
-					h3600ts_pm_callback);
+	ts->pm_dev = pm_register(PM_ILLUMINATION_DEV, PM_SYS_LIGHT,
+				h3600ts_pm_callback);
 	printk("registered pm callback\n");
 #endif
 	input_register_device(&ts->dev);
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/input/tsdev.c	2004-12-12 18:19:32 -08:00
@@ -1,7 +1,7 @@
 /*
  * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
  *
- *  Copyright (c) 2001 "Crazy" james Simmons 
+ *  Copyright (c) 2001 "Crazy" james Simmons
  *
  *  Compaq touchscreen protocol driver. The protocol emulated by this driver
  *  is obsolete; for new programs use the tslib library which can read directly
@@ -177,8 +177,6 @@
 
 static void tsdev_free(struct tsdev *tsdev)
 {
-	devfs_remove("input/ts%d", tsdev->minor);
-	class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
 	tsdev_table[tsdev->minor] = NULL;
 	kfree(tsdev);
 }
@@ -418,7 +416,7 @@
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor);
-	class_simple_device_add(input_class, 
+	class_simple_device_add(input_class,
 				MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
 				dev->dev, "ts%d", minor);
 
@@ -429,6 +427,9 @@
 {
 	struct tsdev *tsdev = handle->private;
 
+	class_simple_device_remove(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
+	devfs_remove("input/ts%d", tsdev->minor);
+	devfs_remove("input/tsraw%d", tsdev->minor);
 	tsdev->exist = 0;
 
 	if (tsdev->open) {
@@ -436,7 +437,6 @@
 		wake_up_interruptible(&tsdev->wait);
 	} else
 		tsdev_free(tsdev);
-	devfs_remove("input/tsraw%d", tsdev->minor);
 }
 
 static struct input_device_id tsdev_ids[] = {
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	2004-12-12 18:19:32 -08:00
+++ b/drivers/usb/input/hid-core.c	2004-12-12 18:19:32 -08:00
@@ -1281,9 +1281,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 << 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 << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT);
+		retries--;
+	} while (result < 0 && retries);
+	return result;
 }
 
 int hid_open(struct hid_device *hid)
@@ -1314,7 +1319,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
@@ -1337,6 +1342,10 @@
 	list = report_enum->report_list.next;
 	while (list != &report_enum->report_list) {
 		report = (struct hid_report *) list;
+		size = ((report->size - 1) >> 3) + 1 + report_enum->numbered;
+		if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE;
+		if (size > hid->urbin->transfer_buffer_length)
+			hid->urbin->transfer_buffer_length = size;
 		hid_submit_report(hid, report, USB_DIR_IN);
 		list = list->next;
 	}
@@ -1460,11 +1469,11 @@
 #define USB_DEVICE_ID_1_PHIDGETSERVO_20	0x8101
 #define USB_DEVICE_ID_4_PHIDGETSERVO_20	0x8104
 
-#define USB_VENDOR_ID_CODEMERCS        0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW40  0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW24  0x1501
-#define USB_DEVICE_ID_CODEMERCS_IOW48  0x1502
-#define USB_DEVICE_ID_CODEMERCS_IOW28  0x1503
+#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
 
 #define USB_VENDOR_ID_DELORME		0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
@@ -1485,8 +1494,16 @@
 	{ 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 },
@@ -1522,15 +1539,9 @@
 	{ 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 },
+	
 
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
@@ -1539,8 +1550,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_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
 
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
@@ -1669,17 +1680,12 @@
 			interval = 1 << (interval - 1);
 
 		if (endpoint->bEndpointAddress & USB_DIR_IN) {
-			int len;
-
 			if (hid->urbin)
 				continue;
 			if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
 				goto fail;
 			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-			len = usb_maxpacket(dev, pipe, 0);
-			if (len > HID_BUFFER_SIZE)
-				len = HID_BUFFER_SIZE;
-			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len,
+			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
 					 hid_irq_in, hid, interval);
 			hid->urbin->transfer_dma = hid->inbuf_dma;
 			hid->urbin->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-12-12 18:19:32 -08:00
+++ b/drivers/usb/input/hid-debug.h	2004-12-12 18:19:32 -08:00
@@ -27,6 +27,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#include <linux/input.h>
+
 struct hid_usage_entry {
 	unsigned  page;
 	unsigned  usage;
@@ -323,7 +325,7 @@
 	printk(".");
 	for (p = hid_usage_table; p->description; p++)
 		if (p->page == (usage >> 16)) {
-			for(++p; p->description && p->page != 0; p++)
+			for(++p; p->description && p->usage != 0; p++)
 				if (p->usage == (usage & 0xffff)) {
 					printk("%s", p->description);
 					return;
@@ -461,4 +463,264 @@
 	printk("hid-debug: input ");
 	resolv_usage(usage->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-12-12 18:19:32 -08:00
+++ b/drivers/usb/input/hid-input.c	2004-12-12 18:19:32 -08:00
@@ -32,6 +32,8 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 
+#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, &hid->inputs) {
-		int i;
-
-		hidinput = list_entry(lh, struct hid_input, list);
-
-		if (! hidinput->report)
-			continue;
-
-		for (i = 0; i < hidinput->report->maxfield; i++)
-			if (hidinput->report->field[i] == field)
-				return &hidinput->input;
-	}
-
-	/* Assume we only have one input and use it */
-	if (!list_empty(&hid->inputs)) {
-		hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-		return &hidinput->input;
-	}
-
-	/* This is really a bug */
-	return NULL;
-}
+#define map_abs(c)	do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
+#define map_rel(c)	do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
+#define map_key(c)	do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
+#define map_led(c)	do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
+#define map_ff(c)	do { usage->code = c; usage->type = EV_FF;  bit = input->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->ffbit); } while (0)
 
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
 				     struct hid_usage *usage)
 {
 	struct input_dev *input = &hidinput->input;
 	struct hid_device *device = hidinput->input.private;
-	int max;
-	int is_abs = 0;
+	int max, code;
 	unsigned long *bit;
 
+	field->hidinput = hidinput;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "Mapping: ");
+	resolv_usage(usage->hid);
+	printk(" ---> ");
+#endif
+
+	if (field->flags & HID_MAIN_ITEM_CONSTANT)
+		goto ignore;
+
 	switch (usage->hid & HID_USAGE_PAGE) {
 
+		case HID_UP_UNDEFINED:
+			goto ignore;
+
 		case HID_UP_KEYBOARD:
 
 			set_bit(EV_REP, input->evbit);
-			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
 
 			if ((usage->hid & HID_USAGE) < 256) {
-				if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE]))
-					return;
-				clear_bit(usage->code, bit);
+				if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
+				map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
 			} else
-				usage->code = KEY_UNKNOWN;
+				map_key(KEY_UNKNOWN);
 
 			break;
 
 		case HID_UP_BUTTON:
 
-			usage->code = ((usage->hid - 1) & 0xf) + 0x100;
-			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+			code = ((usage->hid - 1) & 0xf);
 
 			switch (field->application) {
-				case HID_GD_GAMEPAD:  usage->code += 0x10;
-				case HID_GD_JOYSTICK: usage->code += 0x10;
-				case HID_GD_MOUSE:    usage->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->physical == HID_GD_POINTER)
-						usage->code += 0x10;
-					break;
+					switch (field->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->hid & 0xf0) == 0x80) {	/* SystemControl */
 				switch (usage->hid & 0xf) {
-					case 0x1: usage->code = KEY_POWER;  break;
-					case 0x2: usage->code = KEY_SLEEP;  break;
-					case 0x3: usage->code = KEY_WAKEUP; break;
-					default: usage->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->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
 				break;
 			}
 
-			usage->code = usage->hid & 0xf;
-
-			if (field->report_size == 1) {
-				usage->code = BTN_MISC;
-				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+			if ((usage->hid & 0xf0) == 0x90) {	/* D-pad */
+				switch (usage->hid) {
+					case HID_GD_UP:	   usage->hat_dir = 1; break;
+					case HID_GD_DOWN:  usage->hat_dir = 5; break;
+					case HID_GD_RIGHT: usage->hat_dir = 3; break;
+					case HID_GD_LEFT:  usage->hat_dir = 7; break;
+					default: goto unknown;
+				}
+				if (field->dpad) {
+					map_abs(field->dpad);
+					goto ignore;
+				}
+				map_abs(ABS_HAT0X);
 				break;
 			}
 
-			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
-				break;
-			}
+			switch (usage->hid) {
 
-			usage->type = EV_ABS; bit = input->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->flags & HID_MAIN_ITEM_RELATIVE) 
+						map_rel(usage->hid & 0xf);
+					else
+						map_abs(usage->hid & 0xf);
+					break;
 
-			if (usage->hid == HID_GD_HATSWITCH) {
-				usage->code = ABS_HAT0X;
-				usage->hat_min = field->logical_minimum;
-				usage->hat_max = field->logical_maximum;
+				case HID_GD_HATSWITCH:
+					usage->hat_min = field->logical_minimum;
+					usage->hat_max = field->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->code = (usage->hid - 1) & 0xf;
-			usage->type = EV_LED; bit = input->ledbit; max = LED_MAX;
+			map_led((usage->hid - 1) & 0xf);
 			break;
 
 		case HID_UP_DIGITIZER:
@@ -175,49 +193,36 @@
 			switch (usage->hid & 0xff) {
 
 				case 0x30: /* TipPressure */
-
 					if (!test_bit(BTN_TOUCH, input->keybit)) {
 						device->quirks |= HID_QUIRK_NOTOUCH;
 						set_bit(EV_KEY, input->evbit);
 						set_bit(BTN_TOUCH, input->keybit);
 					}
-					usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
-					usage->code = ABS_PRESSURE;
-					clear_bit(usage->code, bit);
+
+					map_abs_clear(ABS_PRESSURE);
 					break;
 
 				case 0x32: /* InRange */
-
-					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
 					switch (field->physical & 0xff) {
-						case 0x21: usage->code = BTN_TOOL_MOUSE; break;
-						case 0x22: usage->code = BTN_TOOL_FINGER; break;
-						default: usage->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->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-					usage->code = BTN_TOOL_RUBBER;
-					clear_bit(usage->code, bit);
+					map_key_clear(BTN_TOOL_RUBBER);
 					break;
 
 				case 0x33: /* Touch */
 				case 0x42: /* TipSwitch */
 				case 0x43: /* TipSwitch2 */
-
 					device->quirks &= ~HID_QUIRK_NOTOUCH;
-					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-					usage->code = BTN_TOUCH;
-					clear_bit(usage->code, bit);
+					map_key_clear(BTN_TOUCH);
 					break;
 
 				case 0x44: /* BarrelSwitch */
-
-					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-					usage->code = BTN_STYLUS;
-					clear_bit(usage->code, bit);
+					map_key_clear(BTN_STYLUS);
 					break;
 
 				default:  goto unknown;
@@ -228,54 +233,42 @@
 
 			set_bit(EV_REP, input->evbit);
 			switch (usage->hid & HID_USAGE) {
-				case 0x000: usage->code = 0; break;
-				case 0x034: usage->code = KEY_SLEEP;		break;
-				case 0x036: usage->code = BTN_MISC;		break;
-				case 0x08a: usage->code = KEY_WWW;		break;
-				case 0x095: usage->code = KEY_HELP;		break;
-
-				case 0x0b0: usage->code = KEY_PLAY;		break;
-				case 0x0b1: usage->code = KEY_PAUSE;		break;
-				case 0x0b2: usage->code = KEY_RECORD;		break;
-				case 0x0b3: usage->code = KEY_FASTFORWARD;	break;
-				case 0x0b4: usage->code = KEY_REWIND;		break;
-				case 0x0b5: usage->code = KEY_NEXTSONG;		break;
-				case 0x0b6: usage->code = KEY_PREVIOUSSONG;	break;
-				case 0x0b7: usage->code = KEY_STOPCD;		break;
-				case 0x0b8: usage->code = KEY_EJECTCD;		break;
-				case 0x0cd: usage->code = KEY_PLAYPAUSE;	break;
-			        case 0x0e0: is_abs = 1;
-					    usage->code = ABS_VOLUME;
-					    break;
-				case 0x0e2: usage->code = KEY_MUTE;		break;
-				case 0x0e5: usage->code = KEY_BASSBOOST;	break;
-				case 0x0e9: usage->code = KEY_VOLUMEUP;		break;
-				case 0x0ea: usage->code = KEY_VOLUMEDOWN;	break;
-
-				case 0x183: usage->code = KEY_CONFIG;		break;
-				case 0x18a: usage->code = KEY_MAIL;		break;
-				case 0x192: usage->code = KEY_CALC;		break;
-				case 0x194: usage->code = KEY_FILE;		break;
-				case 0x21a: usage->code = KEY_UNDO;		break;
-				case 0x21b: usage->code = KEY_COPY;		break;
-				case 0x21c: usage->code = KEY_CUT;		break;
-				case 0x21d: usage->code = KEY_PASTE;		break;
-
-				case 0x221: usage->code = KEY_FIND;		break;
-				case 0x223: usage->code = KEY_HOMEPAGE;		break;
-				case 0x224: usage->code = KEY_BACK;		break;
-				case 0x225: usage->code = KEY_FORWARD;		break;
-				case 0x226: usage->code = KEY_STOP;		break;
-				case 0x227: usage->code = KEY_REFRESH;		break;
-				case 0x22a: usage->code = KEY_BOOKMARKS;	break;
-
-				default:    usage->code = KEY_UNKNOWN;		break;
-			}
-
-			if (is_abs) {
-			        usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
-			} else  {
-				usage->type = EV_KEY; bit = input->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->evbit);
 			switch (usage->hid & HID_USAGE) {
-			        case 0x021: usage->code = KEY_PRINT;            break;
-				case 0x070: usage->code = KEY_HP;		break;
-				case 0x071: usage->code = KEY_CAMERA;		break;
-				case 0x072: usage->code = KEY_SOUND;		break;
-				case 0x073: usage->code = KEY_QUESTION;		break;
-
-				case 0x080: usage->code = KEY_EMAIL;		break;
-				case 0x081: usage->code = KEY_CHAT;		break;
-				case 0x082: usage->code = KEY_SEARCH;		break;
-				case 0x083: usage->code = KEY_CONNECT;	        break;
-				case 0x084: usage->code = KEY_FINANCE;		break;
-				case 0x085: usage->code = KEY_SPORT;		break;
-				case 0x086: usage->code = KEY_SHOP;	        break;
-
-				default:    usage->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->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
 			break;
 			
 		case HID_UP_PID:
 
-			usage->type = EV_FF; bit = input->ffbit; max = FF_MAX;
-			
+			set_bit(EV_FF, input->evbit);
 			switch(usage->hid & HID_USAGE) {
-				case 0x26: set_bit(FF_CONSTANT, input->ffbit); break;
-				case 0x27: set_bit(FF_RAMP,     input->ffbit); break;
-				case 0x28: set_bit(FF_CUSTOM,   input->ffbit); break;
-				case 0x30: set_bit(FF_SQUARE,   input->ffbit);
-				           set_bit(FF_PERIODIC, input->ffbit); break;
-				case 0x31: set_bit(FF_SINE,     input->ffbit);
-				           set_bit(FF_PERIODIC, input->ffbit); break;
-				case 0x32: set_bit(FF_TRIANGLE, input->ffbit);
-				           set_bit(FF_PERIODIC, input->ffbit); break;
-				case 0x33: set_bit(FF_SAW_UP,   input->ffbit);
-				           set_bit(FF_PERIODIC, input->ffbit); break;
-				case 0x34: set_bit(FF_SAW_DOWN, input->ffbit);
-				           set_bit(FF_PERIODIC, input->ffbit); break;
-				case 0x40: set_bit(FF_SPRING,   input->ffbit); break;
-				case 0x41: set_bit(FF_DAMPER,   input->ffbit); break;
-				case 0x42: set_bit(FF_INERTIA , input->ffbit); break;
-				case 0x43: set_bit(FF_FRICTION, input->ffbit); break;
-				case 0x7e: usage->code = FF_GAIN;       break;
-				case 0x83:  /* Simultaneous Effects Max */
-					input->ff_effects_max = (field->value[0]);
-					dbg("Maximum Effects - %d",input->ff_effects_max);
-					break;
-				case 0x98:  /* Device Control */
-					usage->code = FF_AUTOCENTER;    break;
-				case 0xa4:  /* Safety Switch */
-					usage->code = BTN_DEAD;
-					bit = input->keybit;
-					usage->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->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->ff_effects_max = field->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->hid);
-
 			if (field->report_size == 1) {
-
 				if (field->report->type == HID_OUTPUT_REPORT) {
-					usage->code = LED_MISC;
-					usage->type = EV_LED; bit = input->ledbit; max = LED_MAX;
+					map_led(LED_MISC);
 					break;
 				}
-
-				usage->code = BTN_MISC;
-				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+				map_key(BTN_MISC);
 				break;
 			}
-
 			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				usage->code = REL_MISC;
-				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
+				map_rel(REL_MISC);
 				break;
 			}
-
-			usage->code = ABS_MISC;
-			usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
+			map_abs(ABS_MISC);
 			break;
 	}
 
 	set_bit(usage->type, input->evbit);
-	if ((usage->type == EV_REL)
-			&& (device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_BACK
-				| HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA))
-			&& (usage->code == REL_WHEEL)) {
-		set_bit(REL_HWHEEL, bit);
-	}
 
-	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
+	while (usage->code <= max && test_and_set_bit(usage->code, bit))
 		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
-	}
 
 	if (usage->code > max)
-		return;
+		goto ignore;
+
+	if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
+		 (usage->type == EV_REL) && (usage->code == REL_WHEEL)) 
+			set_bit(REL_HWHEEL, bit);
+
+	if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
+		|| ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
+		goto ignore;
 
 	if (usage->type == EV_ABS) {
+
 		int a = field->logical_minimum;
 		int b = field->logical_maximum;
 
@@ -399,61 +360,69 @@
 			b = field->logical_maximum = 255;
 		}
 		
-		input->absmin[usage->code] = a;
-		input->absmax[usage->code] = b;
-		input->absfuzz[usage->code] = 0;
-		input->absflat[usage->code] = 0;
-
-		if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) {
-			input->absfuzz[usage->code] = (b - a) >> 8;
-			input->absflat[usage->code] = (b - a) >> 4;
-		}
+		if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
+			input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
+		else	input_set_abs_params(input, usage->code, a, b, 0, 0);
+		
 	}
 
-	if (usage->hat_min != usage->hat_max) {
+	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
 		int i;
 		for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
-			input->absmax[i] = 1;
-			input->absmin[i] = -1;
-			input->absfuzz[i] = 0;
-			input->absflat[i] = 0;
+			input_set_abs_params(input, i, -1, 1, 0, 0);
+			set_bit(i, input->absbit);
 		}
-		set_bit(usage->code + 1, input->absbit);
+		if (usage->hat_dir && !field->dpad)
+			field->dpad = usage->code;
 	}
+
+#ifdef DEBUG
+	resolv_event(usage->type, usage->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 = &field->hidinput->input;
 	int *quirks = &hid->quirks;
 
 	if (!input)
 		return;
 
+	if (!usage->type)
+		return;
+
 	input_regs(input, regs);
 
-	if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA) && (usage->code == BTN_EXTRA))
-		|| ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_BACK) && (usage->code == BTN_BACK))) {
-		if (value)
-			hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-		else
-			hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+	if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
+		|| ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
+		if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+		else       hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
 		return;
 	}
 
-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON)
-			&& (usage->code == REL_WHEEL)) {
+	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
 		input_event(input, usage->type, REL_HWHEEL, value);
 		return;
 	}
 
-	if (usage->hat_min != usage->hat_max ) { /* FIXME: hat_max can be 0 and hat_min 1 */
-		value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
-		if (value < 0 || value > 8) value = 0;
-		input_event(input, usage->type, usage->code    , hid_hat_to_axis[value].x);
-		input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y);
-		return;
-	}
+	if (usage->hat_min < usage->hat_max || usage->hat_dir) { 
+		int hat_dir = usage->hat_dir;
+		if (!hat_dir)
+			hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
+		if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
+		input_event(input, usage->type, usage->code    , hid_hat_to_axis[hat_dir].x);
+                input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
+                return;
+        }
 
 	if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
 		*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
@@ -481,6 +450,7 @@
 		dbg("Maximum Effects - %d",input->ff_effects_max);
 		return;
 	}
+
 	if (usage->hid == (HID_UP_PID | 0x7fUL)) {
 		dbg("PID Pool Report\n");
 		return;
@@ -556,9 +526,10 @@
 	INIT_LIST_HEAD(&hid->inputs);
 
 	for (i = 0; i < hid->maxcollection; i++)
-		if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
-		    IS_INPUT_APPLICATION(hid->collection[i].usage))
-			break;
+		if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
+		    hid->collection[i].type == HID_COLLECTION_PHYSICAL)
+		    	if (IS_INPUT_APPLICATION(hid->collection[i].usage))
+				break;
 
 	if (i == hid->maxcollection)
 		return -1;
diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h	2004-12-12 18:19:32 -08:00
+++ b/drivers/usb/input/hid.h	2004-12-12 18:19:32 -08: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->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 >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001))
+#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 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-12-12 18:19:32 -08:00
+++ b/include/linux/input.h	2004-12-12 18:19:32 -08:00
@@ -504,6 +504,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
@@ -566,6 +569,8 @@
 #define LED_SUSPEND		0x06
 #define LED_MUTE		0x07
 #define LED_MISC		0x08
+#define LED_MAIL		0x09
+#define LED_CHARGING		0x0a
 #define LED_MAX			0x0f
 
 /*
@@ -823,7 +828,6 @@
 	unsigned int repeat_key;
 	struct timer_list timer;
 
-	struct pm_dev *pm_dev;
 	struct pt_regs *regs;
 	int state;
 
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-12-12 18:19:32 -08: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 timeout);
+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-12-12 18:19:32 -08:00
+++ b/include/linux/serio.h	2004-12-12 18:19:32 -08:00
@@ -45,7 +45,8 @@
 
 	struct serio *parent, *child;
 
-	struct serio_driver *drv;	/* accessed from interrupt, must be protected by serio->lock */
+	struct serio_driver *drv;	/* accessed from interrupt, must be protected by serio->lock and serio->sem */
+	struct semaphore drv_sem;	/* protects serio->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(&serio->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(&serio->drv_sem);
+}
+
+static __inline__ void serio_unpin_driver(struct serio *serio)
+{
+	up(&serio->drv_sem);
 }
 
 
