From bf51ddaaa91d3b1b831f59700ce928c43ad12c42 Mon Sep 17 00:00:00 2001
From: Antonio Huete Jimenez <tuxillo@quantumachine.net>
Date: Tue, 12 Oct 2010 01:11:07 +0200
Subject: [PATCH 1/3] mouse.h - Change to be not per-architecture.

As mouse.h was the same file in both architectures, and there
is no reason to have it per-platform, it has been put in sys/
---
 share/man/man4/man4.i386/mse.4    |    2 +-
 share/man/man4/mouse.4            |    2 +-
 share/man/man4/psm.4              |    2 +-
 share/man/man4/sysmouse.4         |    2 +-
 sys/dev/misc/mse/mse.c            |    2 +-
 sys/dev/misc/syscons/scmouse.c    |    2 +-
 sys/dev/misc/syscons/sysmouse.c   |    2 +-
 sys/dev/usbmisc/ums/ums.c         |    2 +-
 sys/platform/pc32/include/mouse.h |  337 -------------------------------------
 sys/platform/pc64/include/mouse.h |  337 -------------------------------------
 sys/sys/mouse.h                   |  336 ++++++++++++++++++++++++++++++++++++
 usr.sbin/moused/moused.c          |    2 +-
 12 files changed, 345 insertions(+), 683 deletions(-)
 delete mode 100644 sys/platform/pc32/include/mouse.h
 delete mode 100644 sys/platform/pc64/include/mouse.h
 create mode 100644 sys/sys/mouse.h

diff --git a/share/man/man4/man4.i386/mse.4 b/share/man/man4/man4.i386/mse.4
index a57982d..b982136 100644
--- a/share/man/man4/man4.i386/mse.4
+++ b/share/man/man4/man4.i386/mse.4
@@ -154,7 +154,7 @@ There are a few
 .Xr ioctl 2
 commands for mouse drivers.
 These commands and related structures and constants are defined in
-.In machine/mouse.h .
+.In sys/mouse.h .
 General description of the commands is given in
 .Xr mouse 4 .
 This section explains the features specific to the
diff --git a/share/man/man4/mouse.4 b/share/man/man4/mouse.4
index 2aa8ed7..f2f86c4 100644
--- a/share/man/man4/mouse.4
+++ b/share/man/man4/mouse.4
@@ -34,7 +34,7 @@
 .Nm mouse
 .Nd mouse and pointing device drivers
 .Sh SYNOPSIS
-.In machine/mouse.h
+.In sys/mouse.h
 .Sh DESCRIPTION
 The mouse drivers
 .Xr mse 4 ,
diff --git a/share/man/man4/psm.4 b/share/man/man4/psm.4
index a2c521f..e0cf031 100644
--- a/share/man/man4/psm.4
+++ b/share/man/man4/psm.4
@@ -348,7 +348,7 @@ There are a few
 .Xr ioctl 2
 commands for mouse drivers.
 These commands and related structures and constants are defined in
-.In machine/mouse.h .
+.In sys/mouse.h .
 General description of the commands is given in
 .Xr mouse 4 .
 This section explains the features specific to the
diff --git a/share/man/man4/sysmouse.4 b/share/man/man4/sysmouse.4
index 9595ad2..c915b74 100644
--- a/share/man/man4/sysmouse.4
+++ b/share/man/man4/sysmouse.4
@@ -36,7 +36,7 @@
 .\" .Nd supplies mouse data from syscons for other applications
 .Nd virtualized mouse driver
 .Sh SYNOPSIS
-.In machine/mouse.h
+.In sys/mouse.h
 .In machine/console.h
 .Sh DESCRIPTION
 The console driver, in conjunction with the mouse daemon
diff --git a/sys/dev/misc/mse/mse.c b/sys/dev/misc/mse/mse.c
index abd5c2d..310a909 100644
--- a/sys/dev/misc/mse/mse.c
+++ b/sys/dev/misc/mse/mse.c
@@ -57,7 +57,7 @@
 #include <sys/thread2.h>
 
 #include <machine/clock.h>
-#include <machine/mouse.h>
+#include <sys/mouse.h>
 
 #include <bus/isa/isavar.h>
 
diff --git a/sys/dev/misc/syscons/scmouse.c b/sys/dev/misc/syscons/scmouse.c
index 0a81332..6f23c8c 100644
--- a/sys/dev/misc/syscons/scmouse.c
+++ b/sys/dev/misc/syscons/scmouse.c
@@ -38,7 +38,7 @@
 #include <sys/thread2.h>
 
 #include <machine/console.h>
-#include <machine/mouse.h>
+#include <sys/mouse.h>
 
 #include "syscons.h"
 
diff --git a/sys/dev/misc/syscons/sysmouse.c b/sys/dev/misc/syscons/sysmouse.c
index 52cbfcf..b8e6825 100644
--- a/sys/dev/misc/syscons/sysmouse.c
+++ b/sys/dev/misc/syscons/sysmouse.c
@@ -45,7 +45,7 @@
 #include <sys/thread2.h>
 
 #include <machine/console.h>
-#include <machine/mouse.h>
+#include <sys/mouse.h>
 
 #include "syscons.h"
 
diff --git a/sys/dev/usbmisc/ums/ums.c b/sys/dev/usbmisc/ums/ums.c
index ace91b2..d9c81c5 100644
--- a/sys/dev/usbmisc/ums/ums.c
+++ b/sys/dev/usbmisc/ums/ums.c
@@ -67,7 +67,7 @@
 #include <bus/usb/usb_quirks.h>
 #include <bus/usb/hid.h>
 
-#include <machine/mouse.h>
+#include <sys/mouse.h>
 
 #ifdef USB_DEBUG
 #define DPRINTF(x)	if (umsdebug) kprintf x
diff --git a/sys/platform/pc32/include/mouse.h b/sys/platform/pc32/include/mouse.h
deleted file mode 100644
index 92d6733..0000000
--- a/sys/platform/pc32/include/mouse.h
+++ /dev/null
@@ -1,337 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993 Erik Forsberg.
- * Copyright (c) 1996, 1997 Kazutaka YOKOTA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/i386/include/mouse.h,v 1.15.2.2 2002/04/15 00:52:08 will Exp $
- * $DragonFly: src/sys/platform/pc32/include/mouse.h,v 1.2 2003/06/17 04:28:35 dillon Exp $
- */
-
-#ifndef _MACHINE_MOUSE_H_
-#define _MACHINE_MOUSE_H_
-
-#include <sys/types.h>
-#include <sys/ioccom.h>
-
-/* ioctls */
-#define MOUSE_GETSTATUS		_IOR('M', 0, mousestatus_t)
-#define MOUSE_GETHWINFO		_IOR('M', 1, mousehw_t)
-#define MOUSE_GETMODE		_IOR('M', 2, mousemode_t)
-#define MOUSE_SETMODE		_IOW('M', 3, mousemode_t)
-#define MOUSE_GETLEVEL		_IOR('M', 4, int)
-#define MOUSE_SETLEVEL		_IOW('M', 5, int)
-#define MOUSE_GETVARS		_IOR('M', 6, mousevar_t)
-#define MOUSE_SETVARS		_IOW('M', 7, mousevar_t)
-#define MOUSE_READSTATE		_IOWR('M', 8, mousedata_t)
-#define MOUSE_READDATA		_IOWR('M', 9, mousedata_t)
-
-#if notyet
-#define MOUSE_SETRESOLUTION	_IOW('M', 10, int)
-#define MOUSE_SETSCALING	_IOW('M', 11, int)
-#define MOUSE_SETRATE		_IOW('M', 12, int)
-#define MOUSE_GETHWID		_IOR('M', 13, int)
-#endif
-
-/* mouse status block */
-typedef struct mousestatus {
-    int     flags;		/* state change flags */
-    int     button;		/* button status */
-    int     obutton;		/* previous button status */
-    int     dx;			/* x movement */
-    int     dy;			/* y movement */
-    int     dz;			/* z movement */
-} mousestatus_t;
-
-/* button */
-#define MOUSE_BUTTON1DOWN	0x0001	/* left */
-#define MOUSE_BUTTON2DOWN	0x0002	/* middle */
-#define MOUSE_BUTTON3DOWN	0x0004	/* right */
-#define MOUSE_BUTTON4DOWN	0x0008
-#define MOUSE_BUTTON5DOWN	0x0010
-#define MOUSE_BUTTON6DOWN	0x0020
-#define MOUSE_BUTTON7DOWN	0x0040
-#define MOUSE_BUTTON8DOWN	0x0080
-#define MOUSE_MAXBUTTON		31
-#define MOUSE_STDBUTTONS	0x0007		/* buttons 1-3 */
-#define MOUSE_EXTBUTTONS	0x7ffffff8	/* the others (28 of them!) */
-#define MOUSE_BUTTONS		(MOUSE_STDBUTTONS | MOUSE_EXTBUTTONS)
-
-/* flags */
-#define MOUSE_STDBUTTONSCHANGED	MOUSE_STDBUTTONS
-#define MOUSE_EXTBUTTONSCHANGED	MOUSE_EXTBUTTONS
-#define MOUSE_BUTTONSCHANGED	MOUSE_BUTTONS
-#define MOUSE_POSCHANGED	0x80000000
-
-typedef struct mousehw {
-	int buttons;		/* -1 if unknown */
-	int iftype;		/* MOUSE_IF_XXX */
-	int type;		/* mouse/track ball/pad... */
-	int model;		/* I/F dependent model ID: MOUSE_MODEL_XXX */
-	int hwid;		/* I/F dependent hardware ID
-				 * for the PS/2 mouse, it will be PSM_XXX_ID 
-				 */
-} mousehw_t;
-
-/* iftype */
-#define MOUSE_IF_UNKNOWN	(-1)
-#define MOUSE_IF_SERIAL		0
-#define MOUSE_IF_BUS		1
-#define MOUSE_IF_INPORT		2
-#define MOUSE_IF_PS2		3
-#define MOUSE_IF_SYSMOUSE	4
-#define MOUSE_IF_USB		5
-
-/* type */
-#define MOUSE_UNKNOWN		(-1)	/* should be treated as a mouse */
-#define MOUSE_MOUSE		0
-#define MOUSE_TRACKBALL		1
-#define MOUSE_STICK		2
-#define MOUSE_PAD		3
-
-/* model */
-#define MOUSE_MODEL_UNKNOWN		(-1)
-#define MOUSE_MODEL_GENERIC		0
-#define MOUSE_MODEL_GLIDEPOINT		1
-#define MOUSE_MODEL_NETSCROLL		2
-#define MOUSE_MODEL_NET			3
-#define MOUSE_MODEL_INTELLI		4
-#define MOUSE_MODEL_THINK		5
-#define MOUSE_MODEL_EASYSCROLL		6
-#define MOUSE_MODEL_MOUSEMANPLUS	7
-#define MOUSE_MODEL_KIDSPAD		8
-#define MOUSE_MODEL_VERSAPAD		9
-#define MOUSE_MODEL_EXPLORER		10
-#define MOUSE_MODEL_4D			11
-#define MOUSE_MODEL_4DPLUS		12
-
-typedef struct mousemode {
-	int protocol;		/* MOUSE_PROTO_XXX */
-	int rate;		/* report rate (per sec), -1 if unknown */
-	int resolution;		/* MOUSE_RES_XXX, -1 if unknown */
-	int accelfactor;	/* accelation factor (must be 1 or greater) */
-	int level;		/* driver operation level */
-	int packetsize;		/* the length of the data packet */
-	unsigned char syncmask[2]; /* sync. data bits in the header byte */
-} mousemode_t;
-
-/* protocol */
-/*
- * Serial protocols:
- *   Microsoft, MouseSystems, Logitech, MM series, MouseMan, Hitachi Tablet,
- *   GlidePoint, IntelliMouse, Thinking Mouse, MouseRemote, Kidspad,
- *   VersaPad
- * Bus mouse protocols:
- *   bus, InPort
- * PS/2 mouse protocol:
- *   PS/2
- */
-#define MOUSE_PROTO_UNKNOWN	(-1)
-#define MOUSE_PROTO_MS		0	/* Microsoft Serial, 3 bytes */
-#define MOUSE_PROTO_MSC		1	/* Mouse Systems, 5 bytes */
-#define MOUSE_PROTO_LOGI	2	/* Logitech, 3 bytes */
-#define MOUSE_PROTO_MM		3	/* MM series, 3 bytes */
-#define MOUSE_PROTO_LOGIMOUSEMAN 4	/* Logitech MouseMan 3/4 bytes */
-#define MOUSE_PROTO_BUS		5	/* MS/Logitech bus mouse */
-#define MOUSE_PROTO_INPORT	6	/* MS/ATI InPort mouse */
-#define MOUSE_PROTO_PS2		7	/* PS/2 mouse, 3 bytes */
-#define MOUSE_PROTO_HITTAB	8	/* Hitachi Tablet 3 bytes */
-#define MOUSE_PROTO_GLIDEPOINT	9	/* ALPS GlidePoint, 3/4 bytes */
-#define MOUSE_PROTO_INTELLI	10	/* MS IntelliMouse, 4 bytes */
-#define MOUSE_PROTO_THINK	11	/* Kensignton Thinking Mouse, 3/4 bytes */
-#define MOUSE_PROTO_SYSMOUSE	12	/* /dev/sysmouse */
-#define MOUSE_PROTO_X10MOUSEREM	13	/* X10 MouseRemote, 3 bytes */
-#define MOUSE_PROTO_KIDSPAD	14	/* Genius Kidspad */
-#define MOUSE_PROTO_VERSAPAD	15	/* Interlink VersaPad, 6 bytes */
-#define	MOUSE_PROTO_JOGDIAL	16	/* Vaio's JogDial */
-
-#define MOUSE_RES_UNKNOWN	(-1)
-#define MOUSE_RES_DEFAULT	0
-#define MOUSE_RES_LOW		(-2)
-#define MOUSE_RES_MEDIUMLOW	(-3)
-#define MOUSE_RES_MEDIUMHIGH	(-4)
-#define MOUSE_RES_HIGH		(-5)
-
-typedef struct mousedata {
-	int len;		/* # of data in the buffer */
-	int buf[16];		/* data buffer */
-} mousedata_t;
-
-#if (defined(MOUSE_GETVARS))
-
-typedef struct mousevar {
-	int var[16];
-} mousevar_t;
-
-/* magic numbers in var[0] */
-#define MOUSE_VARS_PS2_SIG	0x00325350	/* 'PS2' */
-#define MOUSE_VARS_BUS_SIG	0x00535542	/* 'BUS' */
-#define MOUSE_VARS_INPORT_SIG	0x00504e49	/* 'INP' */
-
-#endif /* MOUSE_GETVARS */
-
-/* Microsoft Serial mouse data packet */
-#define MOUSE_MSS_PACKETSIZE	3
-#define MOUSE_MSS_SYNCMASK	0x40
-#define MOUSE_MSS_SYNC		0x40
-#define MOUSE_MSS_BUTTONS	0x30
-#define MOUSE_MSS_BUTTON1DOWN	0x20	/* left */
-#define MOUSE_MSS_BUTTON2DOWN	0x00	/* no middle button */
-#define MOUSE_MSS_BUTTON3DOWN	0x10	/* right */
-
-/* Logitech MouseMan data packet (M+ protocol) */
-#define MOUSE_LMAN_BUTTON2DOWN	0x20	/* middle button, the 4th byte */
-
-/* ALPS GlidePoint extention (variant of M+ protocol) */
-#define MOUSE_ALPS_BUTTON2DOWN	0x20	/* middle button, the 4th byte */
-#define MOUSE_ALPS_TAP		0x10	/* `tapping' action, the 4th byte */
-
-/* Kinsington Thinking Mouse extention (variant of M+ protocol) */
-#define MOUSE_THINK_BUTTON2DOWN 0x20	/* lower-left button, the 4th byte */
-#define MOUSE_THINK_BUTTON4DOWN 0x10	/* lower-right button, the 4th byte */
-
-/* MS IntelliMouse (variant of MS Serial) */
-#define MOUSE_INTELLI_PACKETSIZE 4
-#define MOUSE_INTELLI_BUTTON2DOWN 0x10	/* middle button in the 4th byte */
-
-/* Mouse Systems Corp. mouse data packet */
-#define MOUSE_MSC_PACKETSIZE	5
-#define MOUSE_MSC_SYNCMASK	0xf8
-#define MOUSE_MSC_SYNC		0x80
-#define MOUSE_MSC_BUTTONS	0x07
-#define MOUSE_MSC_BUTTON1UP	0x04	/* left */
-#define MOUSE_MSC_BUTTON2UP	0x02	/* middle */
-#define MOUSE_MSC_BUTTON3UP	0x01	/* right */
-#define MOUSE_MSC_MAXBUTTON	3
-
-/* MM series mouse data packet */
-#define MOUSE_MM_PACKETSIZE	3
-#define MOUSE_MM_SYNCMASK	0xe0
-#define MOUSE_MM_SYNC		0x80
-#define MOUSE_MM_BUTTONS	0x07
-#define MOUSE_MM_BUTTON1DOWN	0x04	/* left */
-#define MOUSE_MM_BUTTON2DOWN	0x02	/* middle */
-#define MOUSE_MM_BUTTON3DOWN	0x01	/* right */
-#define MOUSE_MM_XPOSITIVE	0x10
-#define MOUSE_MM_YPOSITIVE	0x08
-
-/* PS/2 mouse data packet */
-#define MOUSE_PS2_PACKETSIZE	3
-#define MOUSE_PS2_SYNCMASK	0xc8
-#define MOUSE_PS2_SYNC		0x08
-#define MOUSE_PS2_BUTTONS	0x07	/* 0x03 for 2 button mouse */
-#define MOUSE_PS2_BUTTON1DOWN	0x01	/* left */
-#define MOUSE_PS2_BUTTON2DOWN	0x04	/* middle */
-#define MOUSE_PS2_BUTTON3DOWN	0x02	/* right */
-#define MOUSE_PS2_TAP		MOUSE_PS2_SYNC /* GlidePoint (PS/2) `tapping'
-					        * Yes! this is the same bit 
-						* as SYNC!
-					 	*/
-
-#define MOUSE_PS2_XNEG		0x10
-#define MOUSE_PS2_YNEG		0x20
-#define MOUSE_PS2_XOVERFLOW	0x40
-#define MOUSE_PS2_YOVERFLOW	0x80
-
-/* Logitech MouseMan+ (PS/2) data packet (PS/2++ protocol) */
-#define MOUSE_PS2PLUS_SYNCMASK	0x48
-#define MOUSE_PS2PLUS_SYNC	0x48
-#define MOUSE_PS2PLUS_ZNEG	0x08	/* sign bit */
-#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10	/* 4th button on MouseMan+ */
-#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
-
-/* IBM ScrollPoint (PS/2) also uses PS/2++ protocol */
-#define MOUSE_SPOINT_ZNEG	0x80	/* sign bits */
-#define MOUSE_SPOINT_WNEG	0x08
-
-/* MS IntelliMouse (PS/2) data packet */
-#define MOUSE_PS2INTELLI_PACKETSIZE 4
-/* some compatible mice have additional buttons */
-#define MOUSE_PS2INTELLI_BUTTON4DOWN 0x40
-#define MOUSE_PS2INTELLI_BUTTON5DOWN 0x80
-
-/* MS IntelliMouse Explorer (PS/2) data packet (variation of IntelliMouse) */
-#define MOUSE_EXPLORER_ZNEG	0x08	/* sign bit */
-/* IntelliMouse Explorer has additional button data in the fourth byte */
-#define MOUSE_EXPLORER_BUTTON4DOWN 0x10
-#define MOUSE_EXPLORER_BUTTON5DOWN 0x20
-
-/* Interlink VersaPad (serial I/F) data packet */
-#define MOUSE_VERSA_PACKETSIZE	6
-#define MOUSE_VERSA_IN_USE	0x04
-#define MOUSE_VERSA_SYNCMASK	0xc3
-#define MOUSE_VERSA_SYNC	0xc0
-#define MOUSE_VERSA_BUTTONS	0x30
-#define MOUSE_VERSA_BUTTON1DOWN	0x20	/* left */
-#define MOUSE_VERSA_BUTTON2DOWN	0x00	/* middle */
-#define MOUSE_VERSA_BUTTON3DOWN	0x10	/* right */
-#define MOUSE_VERSA_TAP		0x08
-
-/* Interlink VersaPad (PS/2 I/F) data packet */
-#define MOUSE_PS2VERSA_PACKETSIZE	6
-#define MOUSE_PS2VERSA_IN_USE		0x10
-#define MOUSE_PS2VERSA_SYNCMASK		0xe8
-#define MOUSE_PS2VERSA_SYNC		0xc8
-#define MOUSE_PS2VERSA_BUTTONS		0x05
-#define MOUSE_PS2VERSA_BUTTON1DOWN	0x04	/* left */
-#define MOUSE_PS2VERSA_BUTTON2DOWN	0x00	/* middle */
-#define MOUSE_PS2VERSA_BUTTON3DOWN	0x01	/* right */
-#define MOUSE_PS2VERSA_TAP		0x02
-
-/* A4 Tech 4D Mouse (PS/2) data packet */
-#define MOUSE_4D_PACKETSIZE		3	
-#define MOUSE_4D_WHEELBITS		0xf0
-
-/* A4 Tech 4D+ Mouse (PS/2) data packet */
-#define MOUSE_4DPLUS_PACKETSIZE		3	
-#define MOUSE_4DPLUS_ZNEG		0x04	/* sign bit */
-#define MOUSE_4DPLUS_BUTTON4DOWN	0x08
-
-/* sysmouse extended data packet */
-/*
- * /dev/sysmouse sends data in two formats, depending on the protocol
- * level.  At the level 0, format is exactly the same as MousSystems'
- * five byte packet.  At the level 1, the first five bytes are the same
- * as at the level 0.  There are additional three bytes which shows
- * `dz' and the states of additional buttons.  `dz' is expressed as the
- * sum of the byte 5 and 6 which contain signed seven bit values.
- * The states of the button 4 though 10 are in the bit 0 though 6 in 
- * the byte 7 respectively: 1 indicates the button is up.
- */
-#define MOUSE_SYS_PACKETSIZE	8
-#define MOUSE_SYS_SYNCMASK	0xf8
-#define MOUSE_SYS_SYNC		0x80
-#define MOUSE_SYS_BUTTON1UP	0x04	/* left, 1st byte */
-#define MOUSE_SYS_BUTTON2UP	0x02	/* middle, 1st byte */
-#define MOUSE_SYS_BUTTON3UP	0x01	/* right, 1st byte */
-#define MOUSE_SYS_BUTTON4UP	0x0001	/* 7th byte */
-#define MOUSE_SYS_BUTTON5UP	0x0002
-#define MOUSE_SYS_BUTTON6UP	0x0004
-#define MOUSE_SYS_BUTTON7UP	0x0008
-#define MOUSE_SYS_BUTTON8UP	0x0010
-#define MOUSE_SYS_BUTTON9UP	0x0020
-#define MOUSE_SYS_BUTTON10UP	0x0040
-#define MOUSE_SYS_MAXBUTTON	10
-#define MOUSE_SYS_STDBUTTONS	0x07
-#define MOUSE_SYS_EXTBUTTONS	0x7f	/* the others */
-
-/* Mouse remote socket */
-#define _PATH_MOUSEREMOTE	"/var/run/MouseRemote"
-
-#endif /* _MACHINE_MOUSE_H_ */
diff --git a/sys/platform/pc64/include/mouse.h b/sys/platform/pc64/include/mouse.h
deleted file mode 100644
index 7b7cab9..0000000
--- a/sys/platform/pc64/include/mouse.h
+++ /dev/null
@@ -1,337 +0,0 @@
-/*-
- * Copyright (c) 1992, 1993 Erik Forsberg.
- * Copyright (c) 1996, 1997 Kazutaka YOKOTA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/i386/include/mouse.h,v 1.15.2.2 2002/04/15 00:52:08 will Exp $
- * $DragonFly: src/sys/platform/pc64/include/mouse.h,v 1.1 2007/08/21 19:45:45 corecode Exp $
- */
-
-#ifndef _MACHINE_MOUSE_H_
-#define _MACHINE_MOUSE_H_
-
-#include <sys/types.h>
-#include <sys/ioccom.h>
-
-/* ioctls */
-#define MOUSE_GETSTATUS		_IOR('M', 0, mousestatus_t)
-#define MOUSE_GETHWINFO		_IOR('M', 1, mousehw_t)
-#define MOUSE_GETMODE		_IOR('M', 2, mousemode_t)
-#define MOUSE_SETMODE		_IOW('M', 3, mousemode_t)
-#define MOUSE_GETLEVEL		_IOR('M', 4, int)
-#define MOUSE_SETLEVEL		_IOW('M', 5, int)
-#define MOUSE_GETVARS		_IOR('M', 6, mousevar_t)
-#define MOUSE_SETVARS		_IOW('M', 7, mousevar_t)
-#define MOUSE_READSTATE		_IOWR('M', 8, mousedata_t)
-#define MOUSE_READDATA		_IOWR('M', 9, mousedata_t)
-
-#if notyet
-#define MOUSE_SETRESOLUTION	_IOW('M', 10, int)
-#define MOUSE_SETSCALING	_IOW('M', 11, int)
-#define MOUSE_SETRATE		_IOW('M', 12, int)
-#define MOUSE_GETHWID		_IOR('M', 13, int)
-#endif
-
-/* mouse status block */
-typedef struct mousestatus {
-    int     flags;		/* state change flags */
-    int     button;		/* button status */
-    int     obutton;		/* previous button status */
-    int     dx;			/* x movement */
-    int     dy;			/* y movement */
-    int     dz;			/* z movement */
-} mousestatus_t;
-
-/* button */
-#define MOUSE_BUTTON1DOWN	0x0001	/* left */
-#define MOUSE_BUTTON2DOWN	0x0002	/* middle */
-#define MOUSE_BUTTON3DOWN	0x0004	/* right */
-#define MOUSE_BUTTON4DOWN	0x0008
-#define MOUSE_BUTTON5DOWN	0x0010
-#define MOUSE_BUTTON6DOWN	0x0020
-#define MOUSE_BUTTON7DOWN	0x0040
-#define MOUSE_BUTTON8DOWN	0x0080
-#define MOUSE_MAXBUTTON		31
-#define MOUSE_STDBUTTONS	0x0007		/* buttons 1-3 */
-#define MOUSE_EXTBUTTONS	0x7ffffff8	/* the others (28 of them!) */
-#define MOUSE_BUTTONS		(MOUSE_STDBUTTONS | MOUSE_EXTBUTTONS)
-
-/* flags */
-#define MOUSE_STDBUTTONSCHANGED	MOUSE_STDBUTTONS
-#define MOUSE_EXTBUTTONSCHANGED	MOUSE_EXTBUTTONS
-#define MOUSE_BUTTONSCHANGED	MOUSE_BUTTONS
-#define MOUSE_POSCHANGED	0x80000000
-
-typedef struct mousehw {
-	int buttons;		/* -1 if unknown */
-	int iftype;		/* MOUSE_IF_XXX */
-	int type;		/* mouse/track ball/pad... */
-	int model;		/* I/F dependent model ID: MOUSE_MODEL_XXX */
-	int hwid;		/* I/F dependent hardware ID
-				 * for the PS/2 mouse, it will be PSM_XXX_ID 
-				 */
-} mousehw_t;
-
-/* iftype */
-#define MOUSE_IF_UNKNOWN	(-1)
-#define MOUSE_IF_SERIAL		0
-#define MOUSE_IF_BUS		1
-#define MOUSE_IF_INPORT		2
-#define MOUSE_IF_PS2		3
-#define MOUSE_IF_SYSMOUSE	4
-#define MOUSE_IF_USB		5
-
-/* type */
-#define MOUSE_UNKNOWN		(-1)	/* should be treated as a mouse */
-#define MOUSE_MOUSE		0
-#define MOUSE_TRACKBALL		1
-#define MOUSE_STICK		2
-#define MOUSE_PAD		3
-
-/* model */
-#define MOUSE_MODEL_UNKNOWN		(-1)
-#define MOUSE_MODEL_GENERIC		0
-#define MOUSE_MODEL_GLIDEPOINT		1
-#define MOUSE_MODEL_NETSCROLL		2
-#define MOUSE_MODEL_NET			3
-#define MOUSE_MODEL_INTELLI		4
-#define MOUSE_MODEL_THINK		5
-#define MOUSE_MODEL_EASYSCROLL		6
-#define MOUSE_MODEL_MOUSEMANPLUS	7
-#define MOUSE_MODEL_KIDSPAD		8
-#define MOUSE_MODEL_VERSAPAD		9
-#define MOUSE_MODEL_EXPLORER		10
-#define MOUSE_MODEL_4D			11
-#define MOUSE_MODEL_4DPLUS		12
-
-typedef struct mousemode {
-	int protocol;		/* MOUSE_PROTO_XXX */
-	int rate;		/* report rate (per sec), -1 if unknown */
-	int resolution;		/* MOUSE_RES_XXX, -1 if unknown */
-	int accelfactor;	/* accelation factor (must be 1 or greater) */
-	int level;		/* driver operation level */
-	int packetsize;		/* the length of the data packet */
-	unsigned char syncmask[2]; /* sync. data bits in the header byte */
-} mousemode_t;
-
-/* protocol */
-/*
- * Serial protocols:
- *   Microsoft, MouseSystems, Logitech, MM series, MouseMan, Hitachi Tablet,
- *   GlidePoint, IntelliMouse, Thinking Mouse, MouseRemote, Kidspad,
- *   VersaPad
- * Bus mouse protocols:
- *   bus, InPort
- * PS/2 mouse protocol:
- *   PS/2
- */
-#define MOUSE_PROTO_UNKNOWN	(-1)
-#define MOUSE_PROTO_MS		0	/* Microsoft Serial, 3 bytes */
-#define MOUSE_PROTO_MSC		1	/* Mouse Systems, 5 bytes */
-#define MOUSE_PROTO_LOGI	2	/* Logitech, 3 bytes */
-#define MOUSE_PROTO_MM		3	/* MM series, 3 bytes */
-#define MOUSE_PROTO_LOGIMOUSEMAN 4	/* Logitech MouseMan 3/4 bytes */
-#define MOUSE_PROTO_BUS		5	/* MS/Logitech bus mouse */
-#define MOUSE_PROTO_INPORT	6	/* MS/ATI InPort mouse */
-#define MOUSE_PROTO_PS2		7	/* PS/2 mouse, 3 bytes */
-#define MOUSE_PROTO_HITTAB	8	/* Hitachi Tablet 3 bytes */
-#define MOUSE_PROTO_GLIDEPOINT	9	/* ALPS GlidePoint, 3/4 bytes */
-#define MOUSE_PROTO_INTELLI	10	/* MS IntelliMouse, 4 bytes */
-#define MOUSE_PROTO_THINK	11	/* Kensignton Thinking Mouse, 3/4 bytes */
-#define MOUSE_PROTO_SYSMOUSE	12	/* /dev/sysmouse */
-#define MOUSE_PROTO_X10MOUSEREM	13	/* X10 MouseRemote, 3 bytes */
-#define MOUSE_PROTO_KIDSPAD	14	/* Genius Kidspad */
-#define MOUSE_PROTO_VERSAPAD	15	/* Interlink VersaPad, 6 bytes */
-#define	MOUSE_PROTO_JOGDIAL	16	/* Vaio's JogDial */
-
-#define MOUSE_RES_UNKNOWN	(-1)
-#define MOUSE_RES_DEFAULT	0
-#define MOUSE_RES_LOW		(-2)
-#define MOUSE_RES_MEDIUMLOW	(-3)
-#define MOUSE_RES_MEDIUMHIGH	(-4)
-#define MOUSE_RES_HIGH		(-5)
-
-typedef struct mousedata {
-	int len;		/* # of data in the buffer */
-	int buf[16];		/* data buffer */
-} mousedata_t;
-
-#if (defined(MOUSE_GETVARS))
-
-typedef struct mousevar {
-	int var[16];
-} mousevar_t;
-
-/* magic numbers in var[0] */
-#define MOUSE_VARS_PS2_SIG	0x00325350	/* 'PS2' */
-#define MOUSE_VARS_BUS_SIG	0x00535542	/* 'BUS' */
-#define MOUSE_VARS_INPORT_SIG	0x00504e49	/* 'INP' */
-
-#endif /* MOUSE_GETVARS */
-
-/* Microsoft Serial mouse data packet */
-#define MOUSE_MSS_PACKETSIZE	3
-#define MOUSE_MSS_SYNCMASK	0x40
-#define MOUSE_MSS_SYNC		0x40
-#define MOUSE_MSS_BUTTONS	0x30
-#define MOUSE_MSS_BUTTON1DOWN	0x20	/* left */
-#define MOUSE_MSS_BUTTON2DOWN	0x00	/* no middle button */
-#define MOUSE_MSS_BUTTON3DOWN	0x10	/* right */
-
-/* Logitech MouseMan data packet (M+ protocol) */
-#define MOUSE_LMAN_BUTTON2DOWN	0x20	/* middle button, the 4th byte */
-
-/* ALPS GlidePoint extention (variant of M+ protocol) */
-#define MOUSE_ALPS_BUTTON2DOWN	0x20	/* middle button, the 4th byte */
-#define MOUSE_ALPS_TAP		0x10	/* `tapping' action, the 4th byte */
-
-/* Kinsington Thinking Mouse extention (variant of M+ protocol) */
-#define MOUSE_THINK_BUTTON2DOWN 0x20	/* lower-left button, the 4th byte */
-#define MOUSE_THINK_BUTTON4DOWN 0x10	/* lower-right button, the 4th byte */
-
-/* MS IntelliMouse (variant of MS Serial) */
-#define MOUSE_INTELLI_PACKETSIZE 4
-#define MOUSE_INTELLI_BUTTON2DOWN 0x10	/* middle button in the 4th byte */
-
-/* Mouse Systems Corp. mouse data packet */
-#define MOUSE_MSC_PACKETSIZE	5
-#define MOUSE_MSC_SYNCMASK	0xf8
-#define MOUSE_MSC_SYNC		0x80
-#define MOUSE_MSC_BUTTONS	0x07
-#define MOUSE_MSC_BUTTON1UP	0x04	/* left */
-#define MOUSE_MSC_BUTTON2UP	0x02	/* middle */
-#define MOUSE_MSC_BUTTON3UP	0x01	/* right */
-#define MOUSE_MSC_MAXBUTTON	3
-
-/* MM series mouse data packet */
-#define MOUSE_MM_PACKETSIZE	3
-#define MOUSE_MM_SYNCMASK	0xe0
-#define MOUSE_MM_SYNC		0x80
-#define MOUSE_MM_BUTTONS	0x07
-#define MOUSE_MM_BUTTON1DOWN	0x04	/* left */
-#define MOUSE_MM_BUTTON2DOWN	0x02	/* middle */
-#define MOUSE_MM_BUTTON3DOWN	0x01	/* right */
-#define MOUSE_MM_XPOSITIVE	0x10
-#define MOUSE_MM_YPOSITIVE	0x08
-
-/* PS/2 mouse data packet */
-#define MOUSE_PS2_PACKETSIZE	3
-#define MOUSE_PS2_SYNCMASK	0xc8
-#define MOUSE_PS2_SYNC		0x08
-#define MOUSE_PS2_BUTTONS	0x07	/* 0x03 for 2 button mouse */
-#define MOUSE_PS2_BUTTON1DOWN	0x01	/* left */
-#define MOUSE_PS2_BUTTON2DOWN	0x04	/* middle */
-#define MOUSE_PS2_BUTTON3DOWN	0x02	/* right */
-#define MOUSE_PS2_TAP		MOUSE_PS2_SYNC /* GlidePoint (PS/2) `tapping'
-					        * Yes! this is the same bit 
-						* as SYNC!
-					 	*/
-
-#define MOUSE_PS2_XNEG		0x10
-#define MOUSE_PS2_YNEG		0x20
-#define MOUSE_PS2_XOVERFLOW	0x40
-#define MOUSE_PS2_YOVERFLOW	0x80
-
-/* Logitech MouseMan+ (PS/2) data packet (PS/2++ protocol) */
-#define MOUSE_PS2PLUS_SYNCMASK	0x48
-#define MOUSE_PS2PLUS_SYNC	0x48
-#define MOUSE_PS2PLUS_ZNEG	0x08	/* sign bit */
-#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10	/* 4th button on MouseMan+ */
-#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
-
-/* IBM ScrollPoint (PS/2) also uses PS/2++ protocol */
-#define MOUSE_SPOINT_ZNEG	0x80	/* sign bits */
-#define MOUSE_SPOINT_WNEG	0x08
-
-/* MS IntelliMouse (PS/2) data packet */
-#define MOUSE_PS2INTELLI_PACKETSIZE 4
-/* some compatible mice have additional buttons */
-#define MOUSE_PS2INTELLI_BUTTON4DOWN 0x40
-#define MOUSE_PS2INTELLI_BUTTON5DOWN 0x80
-
-/* MS IntelliMouse Explorer (PS/2) data packet (variation of IntelliMouse) */
-#define MOUSE_EXPLORER_ZNEG	0x08	/* sign bit */
-/* IntelliMouse Explorer has additional button data in the fourth byte */
-#define MOUSE_EXPLORER_BUTTON4DOWN 0x10
-#define MOUSE_EXPLORER_BUTTON5DOWN 0x20
-
-/* Interlink VersaPad (serial I/F) data packet */
-#define MOUSE_VERSA_PACKETSIZE	6
-#define MOUSE_VERSA_IN_USE	0x04
-#define MOUSE_VERSA_SYNCMASK	0xc3
-#define MOUSE_VERSA_SYNC	0xc0
-#define MOUSE_VERSA_BUTTONS	0x30
-#define MOUSE_VERSA_BUTTON1DOWN	0x20	/* left */
-#define MOUSE_VERSA_BUTTON2DOWN	0x00	/* middle */
-#define MOUSE_VERSA_BUTTON3DOWN	0x10	/* right */
-#define MOUSE_VERSA_TAP		0x08
-
-/* Interlink VersaPad (PS/2 I/F) data packet */
-#define MOUSE_PS2VERSA_PACKETSIZE	6
-#define MOUSE_PS2VERSA_IN_USE		0x10
-#define MOUSE_PS2VERSA_SYNCMASK		0xe8
-#define MOUSE_PS2VERSA_SYNC		0xc8
-#define MOUSE_PS2VERSA_BUTTONS		0x05
-#define MOUSE_PS2VERSA_BUTTON1DOWN	0x04	/* left */
-#define MOUSE_PS2VERSA_BUTTON2DOWN	0x00	/* middle */
-#define MOUSE_PS2VERSA_BUTTON3DOWN	0x01	/* right */
-#define MOUSE_PS2VERSA_TAP		0x02
-
-/* A4 Tech 4D Mouse (PS/2) data packet */
-#define MOUSE_4D_PACKETSIZE		3	
-#define MOUSE_4D_WHEELBITS		0xf0
-
-/* A4 Tech 4D+ Mouse (PS/2) data packet */
-#define MOUSE_4DPLUS_PACKETSIZE		3	
-#define MOUSE_4DPLUS_ZNEG		0x04	/* sign bit */
-#define MOUSE_4DPLUS_BUTTON4DOWN	0x08
-
-/* sysmouse extended data packet */
-/*
- * /dev/sysmouse sends data in two formats, depending on the protocol
- * level.  At the level 0, format is exactly the same as MousSystems'
- * five byte packet.  At the level 1, the first five bytes are the same
- * as at the level 0.  There are additional three bytes which shows
- * `dz' and the states of additional buttons.  `dz' is expressed as the
- * sum of the byte 5 and 6 which contain signed seven bit values.
- * The states of the button 4 though 10 are in the bit 0 though 6 in 
- * the byte 7 respectively: 1 indicates the button is up.
- */
-#define MOUSE_SYS_PACKETSIZE	8
-#define MOUSE_SYS_SYNCMASK	0xf8
-#define MOUSE_SYS_SYNC		0x80
-#define MOUSE_SYS_BUTTON1UP	0x04	/* left, 1st byte */
-#define MOUSE_SYS_BUTTON2UP	0x02	/* middle, 1st byte */
-#define MOUSE_SYS_BUTTON3UP	0x01	/* right, 1st byte */
-#define MOUSE_SYS_BUTTON4UP	0x0001	/* 7th byte */
-#define MOUSE_SYS_BUTTON5UP	0x0002
-#define MOUSE_SYS_BUTTON6UP	0x0004
-#define MOUSE_SYS_BUTTON7UP	0x0008
-#define MOUSE_SYS_BUTTON8UP	0x0010
-#define MOUSE_SYS_BUTTON9UP	0x0020
-#define MOUSE_SYS_BUTTON10UP	0x0040
-#define MOUSE_SYS_MAXBUTTON	10
-#define MOUSE_SYS_STDBUTTONS	0x07
-#define MOUSE_SYS_EXTBUTTONS	0x7f	/* the others */
-
-/* Mouse remote socket */
-#define _PATH_MOUSEREMOTE	"/var/run/MouseRemote"
-
-#endif /* _MACHINE_MOUSE_H_ */
diff --git a/sys/sys/mouse.h b/sys/sys/mouse.h
new file mode 100644
index 0000000..599c5f5
--- /dev/null
+++ b/sys/sys/mouse.h
@@ -0,0 +1,336 @@
+/*-
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * Copyright (c) 1996, 1997 Kazutaka YOKOTA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/i386/include/mouse.h,v 1.15.2.2 2002/04/15 00:52:08 will Exp $
+ */
+
+#ifndef _MACHINE_MOUSE_H_
+#define _MACHINE_MOUSE_H_
+
+#include <sys/types.h>
+#include <sys/ioccom.h>
+
+/* ioctls */
+#define MOUSE_GETSTATUS		_IOR('M', 0, mousestatus_t)
+#define MOUSE_GETHWINFO		_IOR('M', 1, mousehw_t)
+#define MOUSE_GETMODE		_IOR('M', 2, mousemode_t)
+#define MOUSE_SETMODE		_IOW('M', 3, mousemode_t)
+#define MOUSE_GETLEVEL		_IOR('M', 4, int)
+#define MOUSE_SETLEVEL		_IOW('M', 5, int)
+#define MOUSE_GETVARS		_IOR('M', 6, mousevar_t)
+#define MOUSE_SETVARS		_IOW('M', 7, mousevar_t)
+#define MOUSE_READSTATE		_IOWR('M', 8, mousedata_t)
+#define MOUSE_READDATA		_IOWR('M', 9, mousedata_t)
+
+#if notyet
+#define MOUSE_SETRESOLUTION	_IOW('M', 10, int)
+#define MOUSE_SETSCALING	_IOW('M', 11, int)
+#define MOUSE_SETRATE		_IOW('M', 12, int)
+#define MOUSE_GETHWID		_IOR('M', 13, int)
+#endif
+
+/* mouse status block */
+typedef struct mousestatus {
+    int     flags;		/* state change flags */
+    int     button;		/* button status */
+    int     obutton;		/* previous button status */
+    int     dx;			/* x movement */
+    int     dy;			/* y movement */
+    int     dz;			/* z movement */
+} mousestatus_t;
+
+/* button */
+#define MOUSE_BUTTON1DOWN	0x0001	/* left */
+#define MOUSE_BUTTON2DOWN	0x0002	/* middle */
+#define MOUSE_BUTTON3DOWN	0x0004	/* right */
+#define MOUSE_BUTTON4DOWN	0x0008
+#define MOUSE_BUTTON5DOWN	0x0010
+#define MOUSE_BUTTON6DOWN	0x0020
+#define MOUSE_BUTTON7DOWN	0x0040
+#define MOUSE_BUTTON8DOWN	0x0080
+#define MOUSE_MAXBUTTON		31
+#define MOUSE_STDBUTTONS	0x0007		/* buttons 1-3 */
+#define MOUSE_EXTBUTTONS	0x7ffffff8	/* the others (28 of them!) */
+#define MOUSE_BUTTONS		(MOUSE_STDBUTTONS | MOUSE_EXTBUTTONS)
+
+/* flags */
+#define MOUSE_STDBUTTONSCHANGED	MOUSE_STDBUTTONS
+#define MOUSE_EXTBUTTONSCHANGED	MOUSE_EXTBUTTONS
+#define MOUSE_BUTTONSCHANGED	MOUSE_BUTTONS
+#define MOUSE_POSCHANGED	0x80000000
+
+typedef struct mousehw {
+	int buttons;		/* -1 if unknown */
+	int iftype;		/* MOUSE_IF_XXX */
+	int type;		/* mouse/track ball/pad... */
+	int model;		/* I/F dependent model ID: MOUSE_MODEL_XXX */
+	int hwid;		/* I/F dependent hardware ID
+				 * for the PS/2 mouse, it will be PSM_XXX_ID
+				 */
+} mousehw_t;
+
+/* iftype */
+#define MOUSE_IF_UNKNOWN	(-1)
+#define MOUSE_IF_SERIAL		0
+#define MOUSE_IF_BUS		1
+#define MOUSE_IF_INPORT		2
+#define MOUSE_IF_PS2		3
+#define MOUSE_IF_SYSMOUSE	4
+#define MOUSE_IF_USB		5
+
+/* type */
+#define MOUSE_UNKNOWN		(-1)	/* should be treated as a mouse */
+#define MOUSE_MOUSE		0
+#define MOUSE_TRACKBALL		1
+#define MOUSE_STICK		2
+#define MOUSE_PAD		3
+
+/* model */
+#define MOUSE_MODEL_UNKNOWN		(-1)
+#define MOUSE_MODEL_GENERIC		0
+#define MOUSE_MODEL_GLIDEPOINT		1
+#define MOUSE_MODEL_NETSCROLL		2
+#define MOUSE_MODEL_NET			3
+#define MOUSE_MODEL_INTELLI		4
+#define MOUSE_MODEL_THINK		5
+#define MOUSE_MODEL_EASYSCROLL		6
+#define MOUSE_MODEL_MOUSEMANPLUS	7
+#define MOUSE_MODEL_KIDSPAD		8
+#define MOUSE_MODEL_VERSAPAD		9
+#define MOUSE_MODEL_EXPLORER		10
+#define MOUSE_MODEL_4D			11
+#define MOUSE_MODEL_4DPLUS		12
+
+typedef struct mousemode {
+	int protocol;		/* MOUSE_PROTO_XXX */
+	int rate;		/* report rate (per sec), -1 if unknown */
+	int resolution;		/* MOUSE_RES_XXX, -1 if unknown */
+	int accelfactor;	/* accelation factor (must be 1 or greater) */
+	int level;		/* driver operation level */
+	int packetsize;		/* the length of the data packet */
+	unsigned char syncmask[2]; /* sync. data bits in the header byte */
+} mousemode_t;
+
+/* protocol */
+/*
+ * Serial protocols:
+ *   Microsoft, MouseSystems, Logitech, MM series, MouseMan, Hitachi Tablet,
+ *   GlidePoint, IntelliMouse, Thinking Mouse, MouseRemote, Kidspad,
+ *   VersaPad
+ * Bus mouse protocols:
+ *   bus, InPort
+ * PS/2 mouse protocol:
+ *   PS/2
+ */
+#define MOUSE_PROTO_UNKNOWN	(-1)
+#define MOUSE_PROTO_MS		0	/* Microsoft Serial, 3 bytes */
+#define MOUSE_PROTO_MSC		1	/* Mouse Systems, 5 bytes */
+#define MOUSE_PROTO_LOGI	2	/* Logitech, 3 bytes */
+#define MOUSE_PROTO_MM		3	/* MM series, 3 bytes */
+#define MOUSE_PROTO_LOGIMOUSEMAN 4	/* Logitech MouseMan 3/4 bytes */
+#define MOUSE_PROTO_BUS		5	/* MS/Logitech bus mouse */
+#define MOUSE_PROTO_INPORT	6	/* MS/ATI InPort mouse */
+#define MOUSE_PROTO_PS2		7	/* PS/2 mouse, 3 bytes */
+#define MOUSE_PROTO_HITTAB	8	/* Hitachi Tablet 3 bytes */
+#define MOUSE_PROTO_GLIDEPOINT	9	/* ALPS GlidePoint, 3/4 bytes */
+#define MOUSE_PROTO_INTELLI	10	/* MS IntelliMouse, 4 bytes */
+#define MOUSE_PROTO_THINK	11	/* Kensignton Thinking Mouse, 3/4 bytes */
+#define MOUSE_PROTO_SYSMOUSE	12	/* /dev/sysmouse */
+#define MOUSE_PROTO_X10MOUSEREM	13	/* X10 MouseRemote, 3 bytes */
+#define MOUSE_PROTO_KIDSPAD	14	/* Genius Kidspad */
+#define MOUSE_PROTO_VERSAPAD	15	/* Interlink VersaPad, 6 bytes */
+#define	MOUSE_PROTO_JOGDIAL	16	/* Vaio's JogDial */
+
+#define MOUSE_RES_UNKNOWN	(-1)
+#define MOUSE_RES_DEFAULT	0
+#define MOUSE_RES_LOW		(-2)
+#define MOUSE_RES_MEDIUMLOW	(-3)
+#define MOUSE_RES_MEDIUMHIGH	(-4)
+#define MOUSE_RES_HIGH		(-5)
+
+typedef struct mousedata {
+	int len;		/* # of data in the buffer */
+	int buf[16];		/* data buffer */
+} mousedata_t;
+
+#if (defined(MOUSE_GETVARS))
+
+typedef struct mousevar {
+	int var[16];
+} mousevar_t;
+
+/* magic numbers in var[0] */
+#define MOUSE_VARS_PS2_SIG	0x00325350	/* 'PS2' */
+#define MOUSE_VARS_BUS_SIG	0x00535542	/* 'BUS' */
+#define MOUSE_VARS_INPORT_SIG	0x00504e49	/* 'INP' */
+
+#endif /* MOUSE_GETVARS */
+
+/* Microsoft Serial mouse data packet */
+#define MOUSE_MSS_PACKETSIZE	3
+#define MOUSE_MSS_SYNCMASK	0x40
+#define MOUSE_MSS_SYNC		0x40
+#define MOUSE_MSS_BUTTONS	0x30
+#define MOUSE_MSS_BUTTON1DOWN	0x20	/* left */
+#define MOUSE_MSS_BUTTON2DOWN	0x00	/* no middle button */
+#define MOUSE_MSS_BUTTON3DOWN	0x10	/* right */
+
+/* Logitech MouseMan data packet (M+ protocol) */
+#define MOUSE_LMAN_BUTTON2DOWN	0x20	/* middle button, the 4th byte */
+
+/* ALPS GlidePoint extention (variant of M+ protocol) */
+#define MOUSE_ALPS_BUTTON2DOWN	0x20	/* middle button, the 4th byte */
+#define MOUSE_ALPS_TAP		0x10	/* `tapping' action, the 4th byte */
+
+/* Kinsington Thinking Mouse extention (variant of M+ protocol) */
+#define MOUSE_THINK_BUTTON2DOWN 0x20	/* lower-left button, the 4th byte */
+#define MOUSE_THINK_BUTTON4DOWN 0x10	/* lower-right button, the 4th byte */
+
+/* MS IntelliMouse (variant of MS Serial) */
+#define MOUSE_INTELLI_PACKETSIZE 4
+#define MOUSE_INTELLI_BUTTON2DOWN 0x10	/* middle button in the 4th byte */
+
+/* Mouse Systems Corp. mouse data packet */
+#define MOUSE_MSC_PACKETSIZE	5
+#define MOUSE_MSC_SYNCMASK	0xf8
+#define MOUSE_MSC_SYNC		0x80
+#define MOUSE_MSC_BUTTONS	0x07
+#define MOUSE_MSC_BUTTON1UP	0x04	/* left */
+#define MOUSE_MSC_BUTTON2UP	0x02	/* middle */
+#define MOUSE_MSC_BUTTON3UP	0x01	/* right */
+#define MOUSE_MSC_MAXBUTTON	3
+
+/* MM series mouse data packet */
+#define MOUSE_MM_PACKETSIZE	3
+#define MOUSE_MM_SYNCMASK	0xe0
+#define MOUSE_MM_SYNC		0x80
+#define MOUSE_MM_BUTTONS	0x07
+#define MOUSE_MM_BUTTON1DOWN	0x04	/* left */
+#define MOUSE_MM_BUTTON2DOWN	0x02	/* middle */
+#define MOUSE_MM_BUTTON3DOWN	0x01	/* right */
+#define MOUSE_MM_XPOSITIVE	0x10
+#define MOUSE_MM_YPOSITIVE	0x08
+
+/* PS/2 mouse data packet */
+#define MOUSE_PS2_PACKETSIZE	3
+#define MOUSE_PS2_SYNCMASK	0xc8
+#define MOUSE_PS2_SYNC		0x08
+#define MOUSE_PS2_BUTTONS	0x07	/* 0x03 for 2 button mouse */
+#define MOUSE_PS2_BUTTON1DOWN	0x01	/* left */
+#define MOUSE_PS2_BUTTON2DOWN	0x04	/* middle */
+#define MOUSE_PS2_BUTTON3DOWN	0x02	/* right */
+#define MOUSE_PS2_TAP		MOUSE_PS2_SYNC /* GlidePoint (PS/2) `tapping'
+					        * Yes! this is the same bit
+						* as SYNC!
+						*/
+
+#define MOUSE_PS2_XNEG		0x10
+#define MOUSE_PS2_YNEG		0x20
+#define MOUSE_PS2_XOVERFLOW	0x40
+#define MOUSE_PS2_YOVERFLOW	0x80
+
+/* Logitech MouseMan+ (PS/2) data packet (PS/2++ protocol) */
+#define MOUSE_PS2PLUS_SYNCMASK	0x48
+#define MOUSE_PS2PLUS_SYNC	0x48
+#define MOUSE_PS2PLUS_ZNEG	0x08	/* sign bit */
+#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10	/* 4th button on MouseMan+ */
+#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
+
+/* IBM ScrollPoint (PS/2) also uses PS/2++ protocol */
+#define MOUSE_SPOINT_ZNEG	0x80	/* sign bits */
+#define MOUSE_SPOINT_WNEG	0x08
+
+/* MS IntelliMouse (PS/2) data packet */
+#define MOUSE_PS2INTELLI_PACKETSIZE 4
+/* some compatible mice have additional buttons */
+#define MOUSE_PS2INTELLI_BUTTON4DOWN 0x40
+#define MOUSE_PS2INTELLI_BUTTON5DOWN 0x80
+
+/* MS IntelliMouse Explorer (PS/2) data packet (variation of IntelliMouse) */
+#define MOUSE_EXPLORER_ZNEG	0x08	/* sign bit */
+/* IntelliMouse Explorer has additional button data in the fourth byte */
+#define MOUSE_EXPLORER_BUTTON4DOWN 0x10
+#define MOUSE_EXPLORER_BUTTON5DOWN 0x20
+
+/* Interlink VersaPad (serial I/F) data packet */
+#define MOUSE_VERSA_PACKETSIZE	6
+#define MOUSE_VERSA_IN_USE	0x04
+#define MOUSE_VERSA_SYNCMASK	0xc3
+#define MOUSE_VERSA_SYNC	0xc0
+#define MOUSE_VERSA_BUTTONS	0x30
+#define MOUSE_VERSA_BUTTON1DOWN	0x20	/* left */
+#define MOUSE_VERSA_BUTTON2DOWN	0x00	/* middle */
+#define MOUSE_VERSA_BUTTON3DOWN	0x10	/* right */
+#define MOUSE_VERSA_TAP		0x08
+
+/* Interlink VersaPad (PS/2 I/F) data packet */
+#define MOUSE_PS2VERSA_PACKETSIZE	6
+#define MOUSE_PS2VERSA_IN_USE		0x10
+#define MOUSE_PS2VERSA_SYNCMASK		0xe8
+#define MOUSE_PS2VERSA_SYNC		0xc8
+#define MOUSE_PS2VERSA_BUTTONS		0x05
+#define MOUSE_PS2VERSA_BUTTON1DOWN	0x04	/* left */
+#define MOUSE_PS2VERSA_BUTTON2DOWN	0x00	/* middle */
+#define MOUSE_PS2VERSA_BUTTON3DOWN	0x01	/* right */
+#define MOUSE_PS2VERSA_TAP		0x02
+
+/* A4 Tech 4D Mouse (PS/2) data packet */
+#define MOUSE_4D_PACKETSIZE		3
+#define MOUSE_4D_WHEELBITS		0xf0
+
+/* A4 Tech 4D+ Mouse (PS/2) data packet */
+#define MOUSE_4DPLUS_PACKETSIZE		3
+#define MOUSE_4DPLUS_ZNEG		0x04	/* sign bit */
+#define MOUSE_4DPLUS_BUTTON4DOWN	0x08
+
+/* sysmouse extended data packet */
+/*
+ * /dev/sysmouse sends data in two formats, depending on the protocol
+ * level.  At the level 0, format is exactly the same as MousSystems'
+ * five byte packet.  At the level 1, the first five bytes are the same
+ * as at the level 0.  There are additional three bytes which shows
+ * `dz' and the states of additional buttons.  `dz' is expressed as the
+ * sum of the byte 5 and 6 which contain signed seven bit values.
+ * The states of the button 4 though 10 are in the bit 0 though 6 in
+ * the byte 7 respectively: 1 indicates the button is up.
+ */
+#define MOUSE_SYS_PACKETSIZE	8
+#define MOUSE_SYS_SYNCMASK	0xf8
+#define MOUSE_SYS_SYNC		0x80
+#define MOUSE_SYS_BUTTON1UP	0x04	/* left, 1st byte */
+#define MOUSE_SYS_BUTTON2UP	0x02	/* middle, 1st byte */
+#define MOUSE_SYS_BUTTON3UP	0x01	/* right, 1st byte */
+#define MOUSE_SYS_BUTTON4UP	0x0001	/* 7th byte */
+#define MOUSE_SYS_BUTTON5UP	0x0002
+#define MOUSE_SYS_BUTTON6UP	0x0004
+#define MOUSE_SYS_BUTTON7UP	0x0008
+#define MOUSE_SYS_BUTTON8UP	0x0010
+#define MOUSE_SYS_BUTTON9UP	0x0020
+#define MOUSE_SYS_BUTTON10UP	0x0040
+#define MOUSE_SYS_MAXBUTTON	10
+#define MOUSE_SYS_STDBUTTONS	0x07
+#define MOUSE_SYS_EXTBUTTONS	0x7f	/* the others */
+
+/* Mouse remote socket */
+#define _PATH_MOUSEREMOTE	"/var/run/MouseRemote"
+
+#endif /* _MACHINE_MOUSE_H_ */
diff --git a/usr.sbin/moused/moused.c b/usr.sbin/moused/moused.c
index ce8f0c5..4c3c5a1 100644
--- a/usr.sbin/moused/moused.c
+++ b/usr.sbin/moused/moused.c
@@ -49,7 +49,7 @@
  * $DragonFly: src/usr.sbin/moused/moused.c,v 1.7 2008/11/12 21:44:59 swildner Exp $
  */
 #include <machine/console.h>
-#include <machine/mouse.h>
+#include <sys/mouse.h>
 #include <sys/cdefs.h>
 #include <sys/param.h>
 #include <sys/consio.h>
-- 
1.7.0.5

From 3b5ee5d8ffc95cc00cce0228edd66567fdcc8dc4 Mon Sep 17 00:00:00 2001
From: Antonio Huete Jimenez <tuxillo@quantumachine.net>
Date: Tue, 12 Oct 2010 12:49:28 +0200
Subject: [PATCH 2/3] psm - Sync psm(4) with FreeBSD

Changelog:
- Support for A4 Tech RFSW-35 mouse wheel.
- Ignore strange return values in test_aux_port()  from some laptops
  (Compaq, Toshiba, Acer).
- Support synaptics touchpad w/ many features such as supporting integrated
  wheel, up/down buttons or tapping.
- Synaptic tunables hw.psm.tap_enabled and hw.psm.synaptics_support to control
  activation and/or features like gestures.
- Fix many issues with buggy KVM switches which got the mouse confused on sync
  packets.
- ALPS glide point ID.
- Let some PS/2 mice to get directly to Explorer mode (i.e. A4Tech X-7xx)

Obtained-From: FreeBSD
---
 share/man/man4/psm.4         |   57 +-
 sys/dev/misc/kbd/atkbdcreg.h |    4 +
 sys/dev/misc/psm/psm.c       | 6410 +++++++++++++++++++++++++++---------------
 sys/sys/mouse.h              |   25 +
 4 files changed, 4213 insertions(+), 2283 deletions(-)

diff --git a/share/man/man4/psm.4 b/share/man/man4/psm.4
index e0cf031..29a5d8c 100644
--- a/share/man/man4/psm.4
+++ b/share/man/man4/psm.4
@@ -27,7 +27,7 @@
 .\" $FreeBSD: src/share/man/man4/psm.4,v 1.24.2.9 2002/12/29 16:35:38 schweikh Exp $
 .\" $DragonFly: src/share/man/man4/psm.4,v 1.7 2008/05/02 02:05:05 swildner Exp $
 .\"
-.Dd April 1, 2000
+.Dd October 15, 2010
 .Dt PSM 4
 .Os
 .Sh NAME
@@ -343,6 +343,27 @@ It has no effect unless the
 .Em HOOKRESUME
 flag is set as well.
 .El
+.Sh LOADER TUNABLES
+Extended support for Synaptics touchpads can be enabled by setting
+.Va hw.psm.synaptics_support
+to
+.Em 1
+at boot-time.
+This will enable
+.Nm
+to handle packets from guest devices (sticks) and extra buttons.
+.Pp
+Tap and drag gestures can be disabled by setting
+.Va hw.psm.tap_enabled
+to
+.Em 0
+at boot-time.
+Currently, this is only supported on Synaptics touchpads with Extended
+support disabled. The behaviour may be changed after boot by setting
+the sysctl with the same name and by restarting
+.Xr moused 8
+using
+.Pa /etc/rc.d/moused .
 .Sh IOCTLS
 There are a few
 .Xr ioctl 2
@@ -433,6 +454,36 @@ Microsoft Ballpoint mouse
 Microsoft IntelliMouse
 .El
 .Pp
+.It Dv MOUSE_SYN_GETHWINFO Ar synapticshw_t *synhw
+Retrieves extra information associated with Synaptics Touchpads.
+Only available when
+.Va hw.psm.synaptics_support
+has been enabled.
+.Bd -literal
+typedef struct synapticshw {
+    int infoMajor;	/* major hardware revision */
+    int infoMinor;	/* minor hardware revision */
+    int infoRot180;	/* touchpad is rotated */
+    int infoPortrait;	/* touchpad is a portrait */
+    int infoSensor;	/* sensor model */
+    int infoHardware;	/* hardware model */
+    int infoNewAbs;	/* supports the newabs format */
+    int capPen;		/* can detect a pen */
+    int infoSimpleC;	/* supports simple commands */
+    int infoGeometry;	/* touchpad dimensions */
+    int capExtended;	/* supports extended packets */
+    int capSleep;	/* can be suspended/resumed */
+    int capFourButtons;	/* has four buttons */
+    int capMultiFinger;	/* can detect multiple fingers */
+    int capPalmDetect;	/* can detect a palm */
+    int capPassthrough;	/* can passthrough guest packets */
+} synapticshw_t;
+.Ed
+.Pp
+See the
+.Em Synaptics TouchPad Interfacing Guide
+for more information about the fields in this structure.
+.Pp
 .It Dv MOUSE_GETMODE Ar mousemode_t *mode
 The command gets the current operation parameters of the mouse
 driver.
@@ -779,6 +830,10 @@ Clicking any button without moving the mouse may also work.
 .Xr sysmouse 4 ,
 .Xr moused 8 ,
 .Xr syslogd 8
+.Rs
+.%T Synaptics TouchPad Interfacing Guide
+.%U http://www.synaptics.com/
+.Re
 .\".Sh HISTORY
 .Sh AUTHORS
 .An -nosplit
diff --git a/sys/dev/misc/kbd/atkbdcreg.h b/sys/dev/misc/kbd/atkbdcreg.h
index e4c71e1..07383ec 100644
--- a/sys/dev/misc/kbd/atkbdcreg.h
+++ b/sys/dev/misc/kbd/atkbdcreg.h
@@ -136,6 +136,7 @@
 #define PSM_EXPLORER_ID		4
 #define PSM_4DMOUSE_ID		6
 #define PSM_4DPLUS_ID		8
+#define PSM_4DPLUS_RFSW35_ID  24
 
 #ifdef _KERNEL
 
@@ -211,6 +212,9 @@ enum kbdc_device_ivar {
 
 typedef caddr_t KBDC;
 
+#define KBDC_RID_KBD	 0
+#define KBDC_RID_AUX	 1
+
 /* function prototypes */
 
 atkbdc_softc_t *atkbdc_get_softc(int unit);
diff --git a/sys/dev/misc/psm/psm.c b/sys/dev/misc/psm/psm.c
index 4a6ede1..d7a8535 100644
--- a/sys/dev/misc/psm/psm.c
+++ b/sys/dev/misc/psm/psm.c
@@ -19,11 +19,7 @@
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/isa/psm.c,v 1.23.2.7 2003/11/12 04:26:26 mikeh Exp $
- * $DragonFly: src/sys/dev/misc/psm/psm.c,v 1.25 2007/06/13 17:15:25 dillon Exp $
  */
-
 /*
  *  Ported to 386bsd Oct 17, 1992
  *  Sandi Donno, Computer Science, University of Cape Town, South Africa
@@ -54,14 +50,15 @@
  *  - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
  *  - 14, 30 November 1996. Uses `kbdio.c'.
  *  - 13 December 1996. Uses queuing version of `kbdio.c'.
- *  - January/February 1997. Tweaked probe logic for 
+ *  - January/February 1997. Tweaked probe logic for
  *    HiNote UltraII/Latitude/Armada laptops.
  *  - 30 July 1997. Added APM support.
- *  - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX). 
+ *  - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX).
  *    Improved sync check logic.
  *    Vendor specific support routines.
+ *
+ * $FreeBSD: src/sys/dev/atkbdc/psm.c,v 1.107 2010/09/09 07:52:15 ed Exp $
  */
-
 #include "opt_psm.h"
 
 #include <sys/param.h>
@@ -75,13 +72,14 @@
 #include <sys/syslog.h>
 #include <sys/malloc.h>
 #include <sys/rman.h>
+#include <sys/sysctl.h>
 #include <sys/thread2.h>
 #include <sys/time.h>
 #include <sys/uio.h>
 
 #include <machine/clock.h>
 #include <machine/limits.h>
-#include <machine/mouse.h>
+#include <sys/mouse.h>
 
 #include <bus/isa/isavar.h>
 #include <dev/misc/kbd/atkbdcreg.h>
@@ -93,231 +91,389 @@
 
 /* debugging */
 #ifndef PSM_DEBUG
-#define PSM_DEBUG	0	/* logging: 0: none, 1: brief, 2: verbose */
+#define	PSM_DEBUG	0	/*
+				 * logging: 0: none, 1: brief, 2: verbose
+				 *          3: sync errors, 4: all packets
+				 */
 #endif
+#define	VLOG(level, args)	do {	\
+	if (verbose >= level)		\
+		log args;		\
+} while (0)
 
-#ifndef PSM_SYNCERR_THRESHOLD1
-#define PSM_SYNCERR_THRESHOLD1	20
+#ifndef PSM_INPUT_TIMEOUT
+#define	PSM_INPUT_TIMEOUT	2000000	/* 2 sec */
 #endif
 
-#ifndef PSM_INPUT_TIMEOUT
-#define PSM_INPUT_TIMEOUT	2000000	/* 2 sec */
+#ifndef PSM_TAP_TIMEOUT
+#define	PSM_TAP_TIMEOUT		125000
+#endif
+
+#ifndef PSM_TAP_THRESHOLD
+#define	PSM_TAP_THRESHOLD	25
 #endif
 
 /* end of driver specific options */
 
-#define PSM_DRIVER_NAME		"psm"
-#define PSMCPNP_DRIVER_NAME	"psmcpnp"
+#define PSM_DRIVER_NAME	      "psm"
+#define	PSMCPNP_DRIVER_NAME	"psmcpnp"
 
 /* input queue */
-#define PSM_BUFSIZE		960
-#define PSM_SMALLBUFSIZE	240
+#define	PSM_BUFSIZE		960
+#define	PSM_SMALLBUFSIZE	240
 
 /* operation levels */
-#define PSM_LEVEL_BASE		0
-#define PSM_LEVEL_STANDARD	1
-#define PSM_LEVEL_NATIVE	2
-#define PSM_LEVEL_MIN		PSM_LEVEL_BASE
-#define PSM_LEVEL_MAX		PSM_LEVEL_NATIVE
+#define	PSM_LEVEL_BASE		0
+#define	PSM_LEVEL_STANDARD	1
+#define	PSM_LEVEL_NATIVE	2
+#define	PSM_LEVEL_MIN		PSM_LEVEL_BASE
+#define	PSM_LEVEL_MAX		PSM_LEVEL_NATIVE
 
 /* Logitech PS2++ protocol */
-#define MOUSE_PS2PLUS_CHECKBITS(b)	\
-				((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
-#define MOUSE_PS2PLUS_PACKET_TYPE(b)	\
-				(((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
+#define	MOUSE_PS2PLUS_CHECKBITS(b)	\
+    ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
+#define	MOUSE_PS2PLUS_PACKET_TYPE(b)	\
+    (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
 
 /* some macros */
-#define PSM_UNIT(dev)		(minor(dev) >> 1)
-#define PSM_NBLOCKIO(dev)	(minor(dev) & 1)
-#define PSM_MKMINOR(unit,block)	((((unit) & 0xff) << 1) | ((block) ? 0:1))
-
-#ifndef max
-#define max(x,y)		((x) > (y) ? (x) : (y))
-#endif
-#ifndef min
-#define min(x,y)		((x) < (y) ? (x) : (y))
-#endif
-
-#define abs(x)			(((x) < 0) ? -(x) : (x))
+#define PSM_UNIT(dev)	      (minor(dev) >> 1)
+#define PSM_NBLOCKIO(dev)     (minor(dev) & 1)
+#define PSM_MKMINOR(unit,block)	   ((((unit) & 0xff) << 1) | ((block) ? 0:1))
 
 /* ring buffer */
 typedef struct ringbuf {
-    int           count;	/* # of valid elements in the buffer */
-    int           head;		/* head pointer */
-    int           tail;		/* tail poiner */
-    unsigned char buf[PSM_BUFSIZE];
+	int		count;	/* # of valid elements in the buffer */
+	int		head;	/* head pointer */
+	int		tail;	/* tail poiner */
+	u_char buf[PSM_BUFSIZE];
 } ringbuf_t;
 
+/* data buffer */
+typedef struct packetbuf {
+	u_char	ipacket[16];	/* interim input buffer */
+	int	inputbytes;	/* # of bytes in the input buffer */
+} packetbuf_t;
+
+#ifndef PSM_PACKETQUEUE
+#define	PSM_PACKETQUEUE	128
+#endif
+
+enum {
+	SYNAPTICS_SYSCTL_MIN_PRESSURE,
+	SYNAPTICS_SYSCTL_MAX_PRESSURE,
+	SYNAPTICS_SYSCTL_MAX_WIDTH,
+	SYNAPTICS_SYSCTL_MARGIN_TOP,
+	SYNAPTICS_SYSCTL_MARGIN_RIGHT,
+	SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
+	SYNAPTICS_SYSCTL_MARGIN_LEFT,
+	SYNAPTICS_SYSCTL_NA_TOP,
+	SYNAPTICS_SYSCTL_NA_RIGHT,
+	SYNAPTICS_SYSCTL_NA_BOTTOM,
+	SYNAPTICS_SYSCTL_NA_LEFT,
+	SYNAPTICS_SYSCTL_WINDOW_MIN,
+	SYNAPTICS_SYSCTL_WINDOW_MAX,
+	SYNAPTICS_SYSCTL_MULTIPLICATOR,
+	SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
+	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
+	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
+	SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
+	SYNAPTICS_SYSCTL_DIV_MIN,
+	SYNAPTICS_SYSCTL_DIV_MAX,
+	SYNAPTICS_SYSCTL_DIV_MAX_NA,
+	SYNAPTICS_SYSCTL_DIV_LEN,
+	SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
+	SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
+	SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
+	SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
+	SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
+	SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
+	SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
+	SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX
+};
+
+typedef struct synapticsinfo {
+	struct sysctl_ctx_list	 sysctl_ctx;
+	struct sysctl_oid	*sysctl_tree;
+	int			 directional_scrolls;
+	int			 min_pressure;
+	int			 max_pressure;
+	int			 max_width;
+	int			 margin_top;
+	int			 margin_right;
+	int			 margin_bottom;
+	int			 margin_left;
+	int			 na_top;
+	int			 na_right;
+	int			 na_bottom;
+	int			 na_left;
+	int			 window_min;
+	int			 window_max;
+	int			 multiplicator;
+	int			 weight_current;
+	int			 weight_previous;
+	int			 weight_previous_na;
+	int			 weight_len_squared;
+	int			 div_min;
+	int			 div_max;
+	int			 div_max_na;
+	int			 div_len;
+	int			 tap_max_delta;
+	int			 tap_min_queue;
+	int			 taphold_timeout;
+	int			 vscroll_ver_area;
+	int			 vscroll_hor_area;
+	int			 vscroll_min_delta;
+	int			 vscroll_div_min;
+	int			 vscroll_div_max;
+} synapticsinfo_t;
+
+typedef struct synapticspacket {
+	int			x;
+	int			y;
+} synapticspacket_t;
+
+#define	SYNAPTICS_PACKETQUEUE 10
+#define SYNAPTICS_QUEUE_CURSOR(x)					\
+	(x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE
+
+typedef struct synapticsaction {
+	synapticspacket_t	queue[SYNAPTICS_PACKETQUEUE];
+	int			queue_len;
+	int			queue_cursor;
+	int			window_min;
+	int			start_x;
+	int			start_y;
+	int			avg_dx;
+	int			avg_dy;
+	int			squelch_x;
+	int			squelch_y;
+	int			fingers_nb;
+	int			tap_button;
+	int			in_taphold;
+	int			in_vscroll;
+} synapticsaction_t;
+
 /* driver control block */
 struct psm_softc {		/* Driver status information */
-    int		  unit;
-    struct kqinfo rkq;		/* Processes with registered kevents */
-    unsigned char state;	/* Mouse driver state */
-    int           config;	/* driver configuration flags */
-    int           flags;	/* other flags */
-    KBDC          kbdc;		/* handle to access the keyboard controller */
-    struct resource *intr;	/* IRQ resource */
-    void	  *ih;		/* interrupt handle */
-    mousehw_t     hw;		/* hardware information */
-    mousemode_t   mode;		/* operation mode */
-    mousemode_t   dflt_mode;	/* default operation mode */
-    mousestatus_t status;	/* accumulated mouse movement */
-    ringbuf_t     queue;	/* mouse status queue */
-    unsigned char ipacket[16];	/* interim input buffer */
-    int           inputbytes;	/* # of bytes in the input buffer */
-    int           button;	/* the latest button state */
-    int		  xold;	/* previous absolute X position */
-    int		  yold;	/* previous absolute Y position */
-    int		  syncerrors;
-    struct timeval inputtimeout;
-    int		  watchdog;	/* watchdog timer flag */
-    struct callout callout;	/* watchdog timer call out */
+	int		unit;
+	struct kqinfo rkq;	   /* Processes with registered kevents */
+	u_char		state;		/* Mouse driver state */
+	int		config;		/* driver configuration flags */
+	int		flags;		/* other flags */
+	KBDC		kbdc;		/* handle to access kbd controller */
+	struct resource	*intr;		/* IRQ resource */
+	void		*ih;		/* interrupt handle */
+	mousehw_t	hw;		/* hardware information */
+	synapticshw_t	synhw;		/* Synaptics hardware information */
+	synapticsinfo_t	syninfo;	/* Synaptics configuration */
+	synapticsaction_t synaction;	/* Synaptics action context */
+	mousemode_t	mode;		/* operation mode */
+	mousemode_t	dflt_mode;	/* default operation mode */
+	mousestatus_t	status;		/* accumulated mouse movement */
+	ringbuf_t	queue;		/* mouse status queue */
+	packetbuf_t	pqueue[PSM_PACKETQUEUE]; /* mouse data queue */
+	int		pqueue_start;	/* start of data in queue */
+	int		pqueue_end;	/* end of data in queue */
+	int		button;		/* the latest button state */
+	int		xold;		/* previous absolute X position */
+	int		yold;		/* previous absolute Y position */
+	int		xaverage;	/* average X position */
+	int		yaverage;	/* average Y position */
+	int		squelch; /* level to filter movement at low speed */
+	int		zmax;	/* maximum pressure value for touchpads */
+	int		syncerrors; /* # of bytes discarded to synchronize */
+	int		pkterrors;  /* # of packets failed during quaranteen. */
+	struct timeval	inputtimeout;
+	struct timeval	lastsoftintr;	/* time of last soft interrupt */
+	struct timeval	lastinputerr;	/* time last sync error happened */
+	struct timeval	taptimeout;	/* tap timeout for touchpads */
+	int		watchdog;	/* watchdog timer flag */
+	struct callout	 callout;	/* watchdog timer call out */
+	struct callout	 softcallout; /* buffer timer call out */
+	struct cdev	*dev;
+	struct cdev	*bdev;
+	int		lasterr;
+	int		cmdcount;
+	struct sigio	*async;		/* Processes waiting for SIGIO */
 };
-devclass_t psm_devclass;
-#define PSM_SOFTC(unit)	((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
+static devclass_t psm_devclass;
+#define PSM_SOFTC(unit)	 ((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
 
 /* driver state flags (state) */
-#define PSM_VALID		0x80
-#define PSM_OPEN		1	/* Device is open */
-#define PSM_ASLP		2	/* Waiting for mouse data */
+#define	PSM_VALID		0x80
+#define	PSM_OPEN		1	/* Device is open */
+#define	PSM_ASLP		2	/* Waiting for mouse data */
+#define	PSM_SOFTARMED		4	/* Software interrupt armed */
+#define	PSM_NEED_SYNCBITS	8	/* Set syncbits using next data pkt */
 
 /* driver configuration flags (config) */
-#define PSM_CONFIG_RESOLUTION	0x000f	/* resolution */
-#define PSM_CONFIG_ACCEL	0x00f0  /* acceleration factor */
-#define PSM_CONFIG_NOCHECKSYNC	0x0100  /* disable sync. test */
-#define PSM_CONFIG_NOIDPROBE	0x0200  /* disable mouse model probe */
-#define PSM_CONFIG_NORESET	0x0400  /* don't reset the mouse */
-#define PSM_CONFIG_FORCETAP	0x0800  /* assume `tap' action exists */
-#define PSM_CONFIG_IGNPORTERROR	0x1000  /* ignore error in aux port test */
-#define PSM_CONFIG_HOOKRESUME	0x2000	/* hook the system resume event */
-#define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
-#define PSM_CONFIG_SYNCHACK	0x8000 /* enable `out-of-sync' hack */
-
-#define PSM_CONFIG_FLAGS	(PSM_CONFIG_RESOLUTION 		\
-				    | PSM_CONFIG_ACCEL		\
-				    | PSM_CONFIG_NOCHECKSYNC	\
-				    | PSM_CONFIG_SYNCHACK	\
-				    | PSM_CONFIG_NOIDPROBE	\
-				    | PSM_CONFIG_NORESET	\
-				    | PSM_CONFIG_FORCETAP	\
-				    | PSM_CONFIG_IGNPORTERROR	\
-				    | PSM_CONFIG_HOOKRESUME	\
-				    | PSM_CONFIG_INITAFTERSUSPEND)
+#define	PSM_CONFIG_RESOLUTION	0x000f	/* resolution */
+#define	PSM_CONFIG_ACCEL	0x00f0  /* acceleration factor */
+#define	PSM_CONFIG_NOCHECKSYNC	0x0100  /* disable sync. test */
+#define	PSM_CONFIG_NOIDPROBE	0x0200  /* disable mouse model probe */
+#define	PSM_CONFIG_NORESET	0x0400  /* don't reset the mouse */
+#define	PSM_CONFIG_FORCETAP	0x0800  /* assume `tap' action exists */
+#define	PSM_CONFIG_IGNPORTERROR	0x1000  /* ignore error in aux port test */
+#define	PSM_CONFIG_HOOKRESUME	0x2000	/* hook the system resume event */
+#define	PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
+#define	PSM_CONFIG_SYNCHACK	0x8000	/* enable `out-of-sync' hack */
+
+#define	PSM_CONFIG_FLAGS	\
+    (PSM_CONFIG_RESOLUTION |	\
+    PSM_CONFIG_ACCEL |		\
+    PSM_CONFIG_NOCHECKSYNC |	\
+    PSM_CONFIG_SYNCHACK |	\
+    PSM_CONFIG_NOIDPROBE |	\
+    PSM_CONFIG_NORESET |	\
+    PSM_CONFIG_FORCETAP |	\
+    PSM_CONFIG_IGNPORTERROR |	\
+    PSM_CONFIG_HOOKRESUME |	\
+    PSM_CONFIG_INITAFTERSUSPEND)
 
 /* other flags (flags) */
-#define PSM_FLAGS_FINGERDOWN	0x0001 /* VersaPad finger down */
+#define	PSM_FLAGS_FINGERDOWN	0x0001	/* VersaPad finger down */
+
+/* Tunables */
+static int tap_enabled = -1;
+TUNABLE_INT("hw.psm.tap_enabled", &tap_enabled);
+
+static int synaptics_support = 0;
+TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
+
+static int verbose = PSM_DEBUG;
+TUNABLE_INT("debug.psm.loglevel", &verbose);
 
 /* for backward compatibility */
-#define OLD_MOUSE_GETHWINFO	_IOR('M', 1, old_mousehw_t)
-#define OLD_MOUSE_GETMODE	_IOR('M', 2, old_mousemode_t)
-#define OLD_MOUSE_SETMODE	_IOW('M', 3, old_mousemode_t)
+#define	OLD_MOUSE_GETHWINFO	_IOR('M', 1, old_mousehw_t)
+#define	OLD_MOUSE_GETMODE	_IOR('M', 2, old_mousemode_t)
+#define	OLD_MOUSE_SETMODE	_IOW('M', 3, old_mousemode_t)
 
 typedef struct old_mousehw {
-    int buttons;
-    int iftype;
-    int type;
-    int hwid;
+	int	buttons;
+	int	iftype;
+	int	type;
+	int	hwid;
 } old_mousehw_t;
 
 typedef struct old_mousemode {
-    int protocol;
-    int rate;
-    int resolution;
-    int accelfactor;
+	int	protocol;
+	int	rate;
+	int	resolution;
+	int	accelfactor;
 } old_mousemode_t;
 
 /* packet formatting function */
-typedef int packetfunc_t (struct psm_softc *, unsigned char *,
-			      int *, int, mousestatus_t *);
+typedef int	packetfunc_t(struct psm_softc *, u_char *, int *, int,
+    mousestatus_t *);
 
 /* function prototypes */
-static int psmprobe (device_t);
-static int psmattach (device_t);
-static int psmdetach (device_t);
-static int psmresume (device_t);
-
-static d_open_t psmopen;
-static d_close_t psmclose;
-static d_read_t psmread;
-static d_ioctl_t psmioctl;
+static void	psmidentify(driver_t *, device_t);
+static int	psmprobe(device_t);
+static int	psmattach(device_t);
+static int	psmdetach(device_t);
+static int	psmresume(device_t);
+
+static d_open_t		psmopen;
+static d_close_t	psmclose;
+static d_read_t		psmread;
+static d_write_t	psmwrite;
+static d_ioctl_t	psmioctl;
 static d_kqfilter_t psmkqfilter;
 
-static int enable_aux_dev (KBDC);
-static int disable_aux_dev (KBDC);
-static int get_mouse_status (KBDC, int *, int, int);
-static int get_aux_id (KBDC);
-static int set_mouse_sampling_rate (KBDC, int);
-static int set_mouse_scaling (KBDC, int);
-static int set_mouse_resolution (KBDC, int);
-static int set_mouse_mode (KBDC);
-static int get_mouse_buttons (KBDC);
-static int is_a_mouse (int);
-static void recover_from_error (KBDC);
-static int restore_controller (KBDC, int);
-static int doinitialize (struct psm_softc *, mousemode_t *);
-static int doopen (struct psm_softc *, int);
-static int reinitialize (struct psm_softc *, int);
-static char *model_name (int);
-static void psmintr (void *);
-static void psmtimeout (void *);
-static void psmfilter_detach(struct knote *);
-static int psmfilter(struct knote *, long);
+static int	enable_aux_dev(KBDC);
+static int	disable_aux_dev(KBDC);
+static int	get_mouse_status(KBDC, int *, int, int);
+static int	get_aux_id(KBDC);
+static int	set_mouse_sampling_rate(KBDC, int);
+static int	set_mouse_scaling(KBDC, int);
+static int	set_mouse_resolution(KBDC, int);
+static int	set_mouse_mode(KBDC);
+static int	get_mouse_buttons(KBDC);
+static int	is_a_mouse(int);
+static void	recover_from_error(KBDC);
+static int	restore_controller(KBDC, int);
+static int	doinitialize(struct psm_softc *, mousemode_t *);
+static int	doopen(struct psm_softc *, int);
+static int	reinitialize(struct psm_softc *, int);
+static char	*model_name(int);
+static void	psmsoftintr(void *);
+static void	psmintr(void *);
+static void	psmtimeout(void *);
+static void    psmfilter_detach(struct knote *);
+static int     psmfilter(struct knote *, long);
+static int	timeelapsed(const struct timeval *, int, int,
+		    const struct timeval *);
+static void	dropqueue(struct psm_softc *);
+static void	flushpackets(struct psm_softc *);
+static void	proc_mmanplus(struct psm_softc *, packetbuf_t *,
+		    mousestatus_t *, int *, int *, int *);
+static int	proc_synaptics(struct psm_softc *, packetbuf_t *,
+		    mousestatus_t *, int *, int *, int *);
+static void	proc_versapad(struct psm_softc *, packetbuf_t *,
+		    mousestatus_t *, int *, int *, int *);
+static int	tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
+		    u_char *);
 
 /* vendor specific features */
-typedef int probefunc_t (struct psm_softc *);
-
-static int mouse_id_proc1 (KBDC, int, int, int *);
-static int mouse_ext_command (KBDC, int);
-static probefunc_t enable_groller;
-static probefunc_t enable_gmouse;
-static probefunc_t enable_aglide; 
-static probefunc_t enable_kmouse;
-static probefunc_t enable_msexplorer;
-static probefunc_t enable_msintelli;
-static probefunc_t enable_4dmouse;
-static probefunc_t enable_4dplus;
-static probefunc_t enable_mmanplus;
-static probefunc_t enable_versapad;
-static int tame_mouse (struct psm_softc *, mousestatus_t *, unsigned char *);
+typedef int	probefunc_t(struct psm_softc *);
+
+static int	mouse_id_proc1(KBDC, int, int, int *);
+static int	mouse_ext_command(KBDC, int);
+
+static probefunc_t	enable_groller;
+static probefunc_t	enable_gmouse;
+static probefunc_t	enable_aglide;
+static probefunc_t	enable_kmouse;
+static probefunc_t	enable_msexplorer;
+static probefunc_t	enable_msintelli;
+static probefunc_t	enable_4dmouse;
+static probefunc_t	enable_4dplus;
+static probefunc_t	enable_mmanplus;
+static probefunc_t	enable_synaptics;
+static probefunc_t	enable_versapad;
 
 static struct {
-    int                 model;
-    unsigned char	syncmask;
-    int 		packetsize;
-    probefunc_t 	*probefunc;
+	int		model;
+	u_char		syncmask;
+	int		packetsize;
+	probefunc_t	*probefunc;
 } vendortype[] = {
-    /*
-     * WARNING: the order of probe is very important.  Don't mess it
-     * unless you know what you are doing.
-     */
-    { MOUSE_MODEL_NET,			/* Genius NetMouse */
-      0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse, },
-    { MOUSE_MODEL_NETSCROLL,		/* Genius NetScroll */
-      0xc8, 6, enable_groller, },
-    { MOUSE_MODEL_MOUSEMANPLUS,		/* Logitech MouseMan+ */
-      0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus, },
-    { MOUSE_MODEL_EXPLORER,		/* Microsoft IntelliMouse Explorer */
-      0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer, },
-    { MOUSE_MODEL_4D,			/* A4 Tech 4D Mouse */
-      0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse, },
-    { MOUSE_MODEL_4DPLUS,		/* A4 Tech 4D+ Mouse */
-      0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus, },
-    { MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
-      0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli, },
-    { MOUSE_MODEL_GLIDEPOINT,		/* ALPS GlidePoint */
-      0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
-    { MOUSE_MODEL_THINK,		/* Kensignton ThinkingMouse */
-      0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, },
-    { MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
-      0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, },
-    { MOUSE_MODEL_GENERIC,
-      0xc0, MOUSE_PS2_PACKETSIZE, NULL, },
+	/*
+	 * WARNING: the order of probe is very important.  Don't mess it
+	 * unless you know what you are doing.
+	 */
+	{ MOUSE_MODEL_NET,		/* Genius NetMouse */
+	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse },
+	{ MOUSE_MODEL_NETSCROLL,	/* Genius NetScroll */
+	  0xc8, 6, enable_groller },
+	{ MOUSE_MODEL_MOUSEMANPLUS,	/* Logitech MouseMan+ */
+	  0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus },
+	{ MOUSE_MODEL_EXPLORER,		/* Microsoft IntelliMouse Explorer */
+	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer },
+	{ MOUSE_MODEL_4D,		/* A4 Tech 4D Mouse */
+	  0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse },
+	{ MOUSE_MODEL_4DPLUS,		/* A4 Tech 4D+ Mouse */
+	  0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
+	{ MOUSE_MODEL_SYNAPTICS,	/* Synaptics Touchpad */
+	  0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
+	{ MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
+	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
+	{ MOUSE_MODEL_GLIDEPOINT,	/* ALPS GlidePoint */
+	  0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide },
+	{ MOUSE_MODEL_THINK,		/* Kensington ThinkingMouse */
+	  0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
+	{ MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
+	  0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
+	{ MOUSE_MODEL_GENERIC,
+	  0xc0, MOUSE_PS2_PACKETSIZE, NULL },
 };
-#define GENERIC_MOUSE_ENTRY	((sizeof(vendortype) / sizeof(*vendortype)) - 1)
+#define	GENERIC_MOUSE_ENTRY	\
+    ((sizeof(vendortype) / sizeof(*vendortype)) - 1)
 
 /* device driver declarateion */
 static device_method_t psm_methods[] = {
 	/* Device interface */
+	DEVMETHOD(device_identify,	psmidentify),
 	DEVMETHOD(device_probe,		psmprobe),
 	DEVMETHOD(device_attach,	psmattach),
 	DEVMETHOD(device_detach,	psmdetach),
@@ -327,164 +483,144 @@ static device_method_t psm_methods[] = {
 };
 
 static driver_t psm_driver = {
-    PSM_DRIVER_NAME,
-    psm_methods,
-    sizeof(struct psm_softc),
+	PSM_DRIVER_NAME,
+	psm_methods,
+	sizeof(struct psm_softc),
 };
 
-#if notyet
-static struct isa_pnp_id psm_ids[] = {
-    { 0x130fd041, "PS/2 mouse port" },			/* PNP0F13 */
-    { 0x1303d041, "PS/2 port" },			/* PNP0313, XXX */
-    { 0 }
-};
-#endif
-
 #define CDEV_MAJOR        21
 
 static struct dev_ops psm_ops = {
 	{ PSM_DRIVER_NAME, CDEV_MAJOR, 0 },
-	.d_open =	psmopen,
-	.d_close =	psmclose,
-	.d_read =	psmread,
-	.d_ioctl =	psmioctl,
-	.d_kqfilter =	psmkqfilter
+	.d_open =   psmopen,
+	.d_close =  psmclose,
+	.d_read =   psmread,
+	.d_write =  psmwrite,
+	.d_ioctl =  psmioctl,
+	.d_kqfilter =	 psmkqfilter
 };
 
-/* debug message level */
-static int verbose = PSM_DEBUG;
-
 /* device I/O routines */
 static int
 enable_aux_dev(KBDC kbdc)
 {
-    int res;
+	int res;
 
-    res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res);
+	res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
+	VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res));
 
-    return (res == PSM_ACK);
+	return (res == PSM_ACK);
 }
 
 static int
 disable_aux_dev(KBDC kbdc)
 {
-    int res;
+	int res;
 
-    res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res);
+	res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
+	VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res));
 
-    return (res == PSM_ACK);
+	return (res == PSM_ACK);
 }
 
 static int
 get_mouse_status(KBDC kbdc, int *status, int flag, int len)
 {
-    int cmd;
-    int res;
-    int i;
-
-    switch (flag) {
-    case 0:
-    default:
-	cmd = PSMC_SEND_DEV_STATUS;
-	break;
-    case 1:
-	cmd = PSMC_SEND_DEV_DATA;
-	break;
-    }
-    empty_aux_buffer(kbdc, 5);
-    res = send_aux_command(kbdc, cmd);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", 
-	    (flag == 1) ? "DATA" : "STATUS", res);
-    if (res != PSM_ACK)
-        return 0;
-
-    for (i = 0; i < len; ++i) {
-        status[i] = read_aux_data(kbdc);
-	if (status[i] < 0)
-	    break;
-    }
-
-    if (verbose) {
-        log(LOG_DEBUG, "psm: %s %02x %02x %02x\n",
-            (flag == 1) ? "data" : "status", status[0], status[1], status[2]);
-    }
-
-    return i;
+	int cmd;
+	int res;
+	int i;
+
+	switch (flag) {
+	case 0:
+	default:
+		cmd = PSMC_SEND_DEV_STATUS;
+		break;
+	case 1:
+		cmd = PSMC_SEND_DEV_DATA;
+		break;
+	}
+	empty_aux_buffer(kbdc, 5);
+	res = send_aux_command(kbdc, cmd);
+	VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
+	    (flag == 1) ? "DATA" : "STATUS", res));
+	if (res != PSM_ACK)
+		return (0);
+
+	for (i = 0; i < len; ++i) {
+		status[i] = read_aux_data(kbdc);
+		if (status[i] < 0)
+			break;
+	}
+
+	VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n",
+	    (flag == 1) ? "data" : "status", status[0], status[1], status[2]));
+
+	return (i);
 }
 
 static int
 get_aux_id(KBDC kbdc)
 {
-    int res;
-    int id;
+	int res;
+	int id;
 
-    empty_aux_buffer(kbdc, 5);
-    res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res);
-    if (res != PSM_ACK)
-	return (-1);
+	empty_aux_buffer(kbdc, 5);
+	res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
+	VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res));
+	if (res != PSM_ACK)
+		return (-1);
 
-    /* 10ms delay */
-    DRIVERSLEEP(10000);
+	/* 10ms delay */
+	DRIVERSLEEP(10000);
 
-    id = read_aux_data(kbdc);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: device ID: %04x\n", id);
+	id = read_aux_data(kbdc);
+	VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id));
 
-    return id;
+	return (id);
 }
 
 static int
 set_mouse_sampling_rate(KBDC kbdc, int rate)
 {
-    int res;
+	int res;
 
-    res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res);
+	res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
+	VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res));
 
-    return ((res == PSM_ACK) ? rate : -1);
+	return ((res == PSM_ACK) ? rate : -1);
 }
 
 static int
 set_mouse_scaling(KBDC kbdc, int scale)
 {
-    int res;
-
-    switch (scale) {
-    case 1:
-    default:
-	scale = PSMC_SET_SCALING11;
-	break;
-    case 2:
-	scale = PSMC_SET_SCALING21;
-	break;
-    }
-    res = send_aux_command(kbdc, scale);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", 
-	    (scale == PSMC_SET_SCALING21) ? "21" : "11", res);
-
-    return (res == PSM_ACK);
+	int res;
+
+	switch (scale) {
+	case 1:
+	default:
+		scale = PSMC_SET_SCALING11;
+		break;
+	case 2:
+		scale = PSMC_SET_SCALING21;
+		break;
+	}
+	res = send_aux_command(kbdc, scale);
+	VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
+	    (scale == PSMC_SET_SCALING21) ? "21" : "11", res));
+
+	return (res == PSM_ACK);
 }
 
 /* `val' must be 0 through PSMD_MAX_RESOLUTION */
 static int
 set_mouse_resolution(KBDC kbdc, int val)
 {
-    int res;
+	int res;
 
-    res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res);
+	res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
+	VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res));
 
-    return ((res == PSM_ACK) ? val : -1);
+	return ((res == PSM_ACK) ? val : -1);
 }
 
 /*
@@ -494,37 +630,34 @@ set_mouse_resolution(KBDC kbdc, int val)
 static int
 set_mouse_mode(KBDC kbdc)
 {
-    int res;
+	int res;
 
-    res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res);
+	res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
+	VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res));
 
-    return (res == PSM_ACK);
+	return (res == PSM_ACK);
 }
 
 static int
 get_mouse_buttons(KBDC kbdc)
 {
-    int c = 2;		/* assume two buttons by default */
-    int status[3];
-
-    /*
-     * NOTE: a special sequence to obtain Logitech Mouse specific
-     * information: set resolution to 25 ppi, set scaling to 1:1, set
-     * scaling to 1:1, set scaling to 1:1. Then the second byte of the
-     * mouse status bytes is the number of available buttons.
-     * Some manufactures also support this sequence.
-     */
-    if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
-        return c;
-    if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1)
-        && set_mouse_scaling(kbdc, 1) 
-	&& (get_mouse_status(kbdc, status, 0, 3) >= 3)) {
-        if (status[1] != 0)
-            return status[1];
-    }
-    return c;
+	int c = 2;		/* assume two buttons by default */
+	int status[3];
+
+	/*
+	 * NOTE: a special sequence to obtain Logitech Mouse specific
+	 * information: set resolution to 25 ppi, set scaling to 1:1, set
+	 * scaling to 1:1, set scaling to 1:1. Then the second byte of the
+	 * mouse status bytes is the number of available buttons.
+	 * Some manufactures also support this sequence.
+	 */
+	if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
+		return (c);
+	if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) &&
+	    set_mouse_scaling(kbdc, 1) &&
+	    get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0)
+		return (status[1]);
+	return (c);
 }
 
 /* misc subroutines */
@@ -536,99 +669,97 @@ static int
 is_a_mouse(int id)
 {
 #if 0
-    static int valid_ids[] = {
-        PSM_MOUSE_ID,		/* mouse */
-        PSM_BALLPOINT_ID,	/* ballpoint device */
-        PSM_INTELLI_ID,		/* Intellimouse */
-        PSM_EXPLORER_ID,	/* Intellimouse Explorer */
-        -1			/* end of table */
-    };
-    int i;
-
-    for (i = 0; valid_ids[i] >= 0; ++i)
-        if (valid_ids[i] == id)
-            return TRUE;
-    return FALSE;
+	static int valid_ids[] = {
+		PSM_MOUSE_ID,		/* mouse */
+		PSM_BALLPOINT_ID,	/* ballpoint device */
+		PSM_INTELLI_ID,		/* Intellimouse */
+		PSM_EXPLORER_ID,	/* Intellimouse Explorer */
+		-1			/* end of table */
+	};
+	int i;
+
+	for (i = 0; valid_ids[i] >= 0; ++i)
+	if (valid_ids[i] == id)
+		return (TRUE);
+	return (FALSE);
 #else
-    return TRUE;
+	return (TRUE);
 #endif
 }
 
 static char *
 model_name(int model)
 {
-    static struct {
-	int model_code;
-	char *model_name;
-    } models[] = {
-        { MOUSE_MODEL_NETSCROLL,	"NetScroll" },
-        { MOUSE_MODEL_NET,		"NetMouse/NetScroll Optical" },
-        { MOUSE_MODEL_GLIDEPOINT,	"GlidePoint" },
-        { MOUSE_MODEL_THINK,		"ThinkingMouse" },
-        { MOUSE_MODEL_INTELLI,		"IntelliMouse" },
-        { MOUSE_MODEL_MOUSEMANPLUS,	"MouseMan+" },
-        { MOUSE_MODEL_VERSAPAD,		"VersaPad" },
-        { MOUSE_MODEL_EXPLORER,		"IntelliMouse Explorer" },
-        { MOUSE_MODEL_4D,		"4D Mouse" },
-        { MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
-        { MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
-        { MOUSE_MODEL_UNKNOWN,		NULL },
-    };
-    int i;
-
-    for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i) {
-	if (models[i].model_code == model)
-	    return models[i].model_name;
-    }
-    return "Unknown";
+	static struct {
+		int	model_code;
+		char	*model_name;
+	} models[] = {
+		{ MOUSE_MODEL_NETSCROLL,	"NetScroll" },
+		{ MOUSE_MODEL_NET,		"NetMouse/NetScroll Optical" },
+		{ MOUSE_MODEL_GLIDEPOINT,	"GlidePoint" },
+		{ MOUSE_MODEL_THINK,		"ThinkingMouse" },
+		{ MOUSE_MODEL_INTELLI,		"IntelliMouse" },
+		{ MOUSE_MODEL_MOUSEMANPLUS,	"MouseMan+" },
+		{ MOUSE_MODEL_VERSAPAD,		"VersaPad" },
+		{ MOUSE_MODEL_EXPLORER,		"IntelliMouse Explorer" },
+		{ MOUSE_MODEL_4D,		"4D Mouse" },
+		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
+		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
+		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
+		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
+	};
+	int i;
+
+	for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i)
+		if (models[i].model_code == model)
+			break;
+	return (models[i].model_name);
 }
 
 static void
 recover_from_error(KBDC kbdc)
 {
-    /* discard anything left in the output buffer */
-    empty_both_buffers(kbdc, 10);
+	/* discard anything left in the output buffer */
+	empty_both_buffers(kbdc, 10);
 
 #if 0
-    /*
-     * NOTE: KBDC_RESET_KBD may not restore the communication between the
-     * keyboard and the controller.
-     */
-    reset_kbd(kbdc);
+	/*
+	 * NOTE: KBDC_RESET_KBD may not restore the communication between the
+	 * keyboard and the controller.
+	 */
+	reset_kbd(kbdc);
 #else
-    /*
-     * NOTE: somehow diagnostic and keyboard port test commands bring the
-     * keyboard back.
-     */
-    if (!test_controller(kbdc)) 
-        log(LOG_ERR, "psm: keyboard controller failed.\n");
-    /* if there isn't a keyboard in the system, the following error is OK */
-    if (test_kbd_port(kbdc) != 0) {
-	if (verbose)
-	    log(LOG_ERR, "psm: keyboard port failed.\n");
-    }
+	/*
+	 * NOTE: somehow diagnostic and keyboard port test commands bring the
+	 * keyboard back.
+	 */
+	if (!test_controller(kbdc))
+		log(LOG_ERR, "psm: keyboard controller failed.\n");
+	/* if there isn't a keyboard in the system, the following error is OK */
+	if (test_kbd_port(kbdc) != 0)
+		VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n"));
 #endif
 }
 
 static int
 restore_controller(KBDC kbdc, int command_byte)
 {
-    empty_both_buffers(kbdc, 10);
-
-    if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
-	log(LOG_ERR, "psm: failed to restore the keyboard controller "
-		     "command byte.\n");
-	empty_both_buffers(kbdc, 10);
-	return FALSE;
-    } else {
 	empty_both_buffers(kbdc, 10);
-	return TRUE;
-    }
+
+	if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
+		log(LOG_ERR, "psm: failed to restore the keyboard controller "
+		    "command byte.\n");
+		empty_both_buffers(kbdc, 10);
+		return (FALSE);
+	} else {
+		empty_both_buffers(kbdc, 10);
+		return (TRUE);
+	}
 }
 
-/* 
+/*
  * Re-initialize the aux port and device. The aux port must be enabled
- * and its interrupt must be disabled before calling this routine. 
+ * and its interrupt must be disabled before calling this routine.
  * The aux device will be disabled before returning.
  * The keyboard controller must be locked via `kbdc_lock()' before
  * calling this routine.
@@ -636,1746 +767,2732 @@ restore_controller(KBDC kbdc, int command_byte)
 static int
 doinitialize(struct psm_softc *sc, mousemode_t *mode)
 {
-    KBDC kbdc = sc->kbdc;
-    int stat[3];
-    int i;
-
-    switch((i = test_aux_port(kbdc))) {
-    case 1:	/* ignore this error */
-    case 2:	/* Ignore 2 and 3 for use with some acer and compal laptops */
-    case 3:
-    case PSM_ACK:
-	if (verbose)
-	    log(LOG_DEBUG, "psm%d: strange result for test aux port (%d).\n",
-	        sc->unit, i);
-	/* fall though */
-    case 0:	/* no error */
-    	break;
-    case -1: 	/* time out */
-    default: 	/* error */
-    	recover_from_error(kbdc);
-	if (sc->config & PSM_CONFIG_IGNPORTERROR)
-	    break;
-    	log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
-    	    sc->unit, i);
-    	return FALSE;
-    }
-
-    if (sc->config & PSM_CONFIG_NORESET) {
-	/* 
-	 * Don't try to reset the pointing device.  It may possibly be
-	 * left in the unknown state, though...
-	 */
-    } else {
-	/* 
-	 * NOTE: some controllers appears to hang the `keyboard' when
-	 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued. 
-	 */
-	if (!reset_aux_dev(kbdc)) {
-            recover_from_error(kbdc);
-            log(LOG_ERR, "psm%d: failed to reset the aux device.\n", sc->unit);
-            return FALSE;
-	}
-    }
-
-    /* 
-     * both the aux port and the aux device is functioning, see
-     * if the device can be enabled. 
-     */
-    if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
-        log(LOG_ERR, "psm%d: failed to enable the aux device.\n", sc->unit);
-        return FALSE;
-    }
-    empty_both_buffers(kbdc, 10);	/* remove stray data if any */
-
-    if (sc->config & PSM_CONFIG_NOIDPROBE) {
-	i = GENERIC_MOUSE_ENTRY;
-    } else {
-	/* FIXME: hardware ID, mouse buttons? */
-
-	/* other parameters */
-	for (i = 0; vendortype[i].probefunc != NULL; ++i) {
-	    if ((*vendortype[i].probefunc)(sc)) {
-		if (verbose >= 2)
-		    log(LOG_ERR, "psm%d: found %s\n", 
-			sc->unit, model_name(vendortype[i].model));
+	KBDC kbdc = sc->kbdc;
+	int stat[3];
+	int i;
+
+	switch((i = test_aux_port(kbdc))) {
+	case 1:	/* ignore these errors */
+	case 2:
+	case 3:
+	case PSM_ACK:
+		if (verbose)
+			log(LOG_DEBUG,
+			    "psm%d: strange result for test aux port (%d).\n",
+			    sc->unit, i);
+		/* FALLTHROUGH */
+	case 0:		/* no error */
 		break;
-	    }
-	}
-    }
-
-    sc->hw.model = vendortype[i].model;
-    sc->mode.packetsize = vendortype[i].packetsize;
-
-    /* set mouse parameters */
-    if (mode != NULL) {
-	if (mode->rate > 0)
-            mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
-	if (mode->resolution >= 0)
-            mode->resolution = set_mouse_resolution(kbdc, mode->resolution);
-        set_mouse_scaling(kbdc, 1);
-        set_mouse_mode(kbdc);	
-    }
-
-    /* request a data packet and extract sync. bits */
-    if (get_mouse_status(kbdc, stat, 1, 3) < 3) {
-        log(LOG_DEBUG, "psm%d: failed to get data (doinitialize).\n",
-	    sc->unit);
-        sc->mode.syncmask[0] = 0;
-    } else {
-        sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0];	/* syncbits */
-	/* the NetScroll Mouse will send three more bytes... Ignore them */
-	empty_aux_buffer(kbdc, 5);
-    }
+	case -1:	/* time out */
+	default:	/* error */
+		recover_from_error(kbdc);
+		if (sc->config & PSM_CONFIG_IGNPORTERROR)
+			break;
+		log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
+		    sc->unit, i);
+		return (FALSE);
+	}
+
+	if (sc->config & PSM_CONFIG_NORESET) {
+		/*
+		 * Don't try to reset the pointing device.  It may possibly
+		 * be left in the unknown state, though...
+		 */
+	} else {
+		/*
+		 * NOTE: some controllers appears to hang the `keyboard' when
+		 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
+		 */
+		if (!reset_aux_dev(kbdc)) {
+			recover_from_error(kbdc);
+			log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
+			    sc->unit);
+			return (FALSE);
+		}
+	}
+
+	/*
+	 * both the aux port and the aux device is functioning, see
+	 * if the device can be enabled.
+	 */
+	if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
+		log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
+		    sc->unit);
+		return (FALSE);
+	}
+	empty_both_buffers(kbdc, 10);	/* remove stray data if any */
+
+	if (sc->config & PSM_CONFIG_NOIDPROBE)
+		i = GENERIC_MOUSE_ENTRY;
+	else {
+		/* FIXME: hardware ID, mouse buttons? */
+
+		/* other parameters */
+		for (i = 0; vendortype[i].probefunc != NULL; ++i)
+			if ((*vendortype[i].probefunc)(sc)) {
+				if (verbose >= 2)
+					log(LOG_ERR, "psm%d: found %s\n",
+					    sc->unit,
+					    model_name(vendortype[i].model));
+				break;
+			}
+	}
+
+	sc->hw.model = vendortype[i].model;
+	sc->mode.packetsize = vendortype[i].packetsize;
+
+	/* set mouse parameters */
+	if (mode != NULL) {
+		if (mode->rate > 0)
+			mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
+		if (mode->resolution >= 0)
+			mode->resolution =
+			    set_mouse_resolution(kbdc, mode->resolution);
+		set_mouse_scaling(kbdc, 1);
+		set_mouse_mode(kbdc);
+	}
+
+	/* Record sync on the next data packet we see. */
+	sc->flags |= PSM_NEED_SYNCBITS;
 
-    /* just check the status of the mouse */
-    if (get_mouse_status(kbdc, stat, 0, 3) < 3)
-        log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
-	    sc->unit);
+	/* just check the status of the mouse */
+	if (get_mouse_status(kbdc, stat, 0, 3) < 3)
+		log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
+		    sc->unit);
 
-    return TRUE;
+	return (TRUE);
 }
 
 static int
 doopen(struct psm_softc *sc, int command_byte)
 {
-    int stat[3];
-
-    /* enable the mouse device */
-    if (!enable_aux_dev(sc->kbdc)) {
-	/* MOUSE ERROR: failed to enable the mouse because:
-	 * 1) the mouse is faulty,
-	 * 2) the mouse has been removed(!?)
-	 * In the latter case, the keyboard may have hung, and need 
-	 * recovery procedure...
+	int stat[3];
+
+	/*
+	 * FIXME: Synaptics TouchPad seems to go back to Relative Mode with
+	 * no obvious reason. Thus we check the current mode and restore the
+	 * Absolute Mode if it was cleared.
+	 *
+	 * The previous hack at the end of psmprobe() wasn't efficient when
+	 * moused(8) was restarted.
+	 *
+	 * A Reset (FF) or Set Defaults (F6) command would clear the
+	 * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5
+	 * doesn't show any evidence of such a command.
 	 */
-	recover_from_error(sc->kbdc);
-#if 0
-	/* FIXME: we could reset the mouse here and try to enable
-	 * it again. But it will take long time and it's not a good
-	 * idea to disable the keyboard that long...
+	if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
+		mouse_ext_command(sc->kbdc, 1);
+		get_mouse_status(sc->kbdc, stat, 0, 3);
+		if (stat[1] == 0x47 && stat[2] == 0x40) {
+			/* Set the mode byte -- request wmode where
+			 * available */
+			if (sc->synhw.capExtended)
+				mouse_ext_command(sc->kbdc, 0xc1);
+			else
+				mouse_ext_command(sc->kbdc, 0xc0);
+			set_mouse_sampling_rate(sc->kbdc, 20);
+			VLOG(5, (LOG_DEBUG, "psm%d: Synaptis Absolute Mode "
+			    "hopefully restored\n",
+			    sc->unit));
+		}
+	}
+
+	/*
+	 * A user may want to disable tap and drag gestures on a Synaptics
+	 * TouchPad when it operates in Relative Mode.
 	 */
-	if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
-	    recover_from_error(sc->kbdc);
+	if (sc->hw.model == MOUSE_MODEL_GENERIC) {
+		if (tap_enabled > 0) {
+			/*
+			 * Enable tap & drag gestures. We use a Mode Byte
+			 * and clear the DisGest bit (see §2.5 of Synaptics
+			 * TouchPad Interfacing Guide).
+			 */
+			VLOG(2, (LOG_DEBUG,
+			    "psm%d: enable tap and drag gestures\n",
+			    sc->unit));
+			mouse_ext_command(sc->kbdc, 0x00);
+			set_mouse_sampling_rate(sc->kbdc, 20);
+		} else if (tap_enabled == 0) {
+			/*
+			 * Disable tap & drag gestures. We use a Mode Byte
+			 * and set the DisGest bit (see §2.5 of Synaptics
+			 * TouchPad Interfacing Guide).
+			 */
+			VLOG(2, (LOG_DEBUG,
+			    "psm%d: disable tap and drag gestures\n",
+			    sc->unit));
+			mouse_ext_command(sc->kbdc, 0x04);
+			set_mouse_sampling_rate(sc->kbdc, 20);
+		}
+	}
+
+	/* enable the mouse device */
+	if (!enable_aux_dev(sc->kbdc)) {
+		/* MOUSE ERROR: failed to enable the mouse because:
+		 * 1) the mouse is faulty,
+		 * 2) the mouse has been removed(!?)
+		 * In the latter case, the keyboard may have hung, and need
+		 * recovery procedure...
+		 */
+		recover_from_error(sc->kbdc);
+#if 0
+		/* FIXME: we could reset the mouse here and try to enable
+		 * it again. But it will take long time and it's not a good
+		 * idea to disable the keyboard that long...
+		 */
+		if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
+			recover_from_error(sc->kbdc);
 #else
-        {
+		{
 #endif
-            restore_controller(sc->kbdc, command_byte);
-	    /* mark this device is no longer available */
-	    sc->state &= ~PSM_VALID;	
-	    log(LOG_ERR, "psm%d: failed to enable the device (doopen).\n",
-		sc->unit);
-	    return (EIO);
+			restore_controller(sc->kbdc, command_byte);
+			/* mark this device is no longer available */
+			sc->state &= ~PSM_VALID;
+			log(LOG_ERR,
+			    "psm%d: failed to enable the device (doopen).\n",
+			sc->unit);
+			return (EIO);
+		}
 	}
-    }
 
-    if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) 
-        log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n", sc->unit);
+	if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
+		log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n",
+		    sc->unit);
 
-    /* enable the aux port and interrupt */
-    if (!set_controller_command_byte(sc->kbdc, 
+	/* enable the aux port and interrupt */
+	if (!set_controller_command_byte(sc->kbdc,
 	    kbdc_get_device_mask(sc->kbdc),
-	    (command_byte & KBD_KBD_CONTROL_BITS)
-		| KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
-	/* CONTROLLER ERROR */
-	disable_aux_dev(sc->kbdc);
-        restore_controller(sc->kbdc, command_byte);
-	log(LOG_ERR, "psm%d: failed to enable the aux interrupt (doopen).\n",
-	    sc->unit);
-	return (EIO);
-    }
-
-    /* start the watchdog timer */
-    sc->watchdog = FALSE;
-    callout_reset(&sc->callout, hz * 2, psmtimeout, (void *)(uintptr_t)sc);
-
-    return (0);
+	    (command_byte & KBD_KBD_CONTROL_BITS) |
+	    KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
+		/* CONTROLLER ERROR */
+		disable_aux_dev(sc->kbdc);
+		restore_controller(sc->kbdc, command_byte);
+		log(LOG_ERR,
+		    "psm%d: failed to enable the aux interrupt (doopen).\n",
+		    sc->unit);
+		return (EIO);
+	}
+
+	/* start the watchdog timer */
+	sc->watchdog = FALSE;
+	callout_reset(&sc->callout, hz * 2, psmtimeout, (void *)(uintptr_t)sc);
+
+	return (0);
 }
 
 static int
 reinitialize(struct psm_softc *sc, int doinit)
 {
-    int err;
-    int c;
-
-    /* don't let anybody mess with the aux device */
-    if (!kbdc_lock(sc->kbdc, TRUE))
-	return (EIO);
-    crit_enter();
-
-    /* block our watchdog timer */
-    sc->watchdog = FALSE;
-    callout_stop(&sc->callout);
-
-    /* save the current controller command byte */
-    empty_both_buffers(sc->kbdc, 10);
-    c = get_controller_command_byte(sc->kbdc);
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm%d: current command byte: %04x (reinitialize).\n", 
-	    sc->unit, c);
-
-    /* enable the aux port but disable the aux interrupt and the keyboard */
-    if ((c == -1) || !set_controller_command_byte(sc->kbdc,
+	int err;
+	int c;
+
+	/* don't let anybody mess with the aux device */
+	if (!kbdc_lock(sc->kbdc, TRUE))
+		return (EIO);
+
+	crit_enter();
+
+	/* block our watchdog timer */
+	sc->watchdog = FALSE;
+	callout_stop(&sc->callout);
+
+	/* save the current controller command byte */
+	empty_both_buffers(sc->kbdc, 10);
+	c = get_controller_command_byte(sc->kbdc);
+	VLOG(2, (LOG_DEBUG,
+	    "psm%d: current command byte: %04x (reinitialize).\n",
+	    sc->unit, c));
+
+	/* enable the aux port but disable the aux interrupt and the keyboard */
+	if ((c == -1) || !set_controller_command_byte(sc->kbdc,
 	    kbdc_get_device_mask(sc->kbdc),
-  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
-	        | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-        /* CONTROLLER ERROR */
+	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
+	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+		/* CONTROLLER ERROR */
+		crit_exit();
+		kbdc_lock(sc->kbdc, FALSE);
+		log(LOG_ERR,
+		    "psm%d: unable to set the command byte (reinitialize).\n",
+		    sc->unit);
+		return (EIO);
+	}
+
+	/* flush any data */
+	if (sc->state & PSM_VALID) {
+		/* this may fail; but never mind... */
+		disable_aux_dev(sc->kbdc);
+		empty_aux_buffer(sc->kbdc, 10);
+	}
+	flushpackets(sc);
+	sc->syncerrors = 0;
+	sc->pkterrors = 0;
+	memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr));
+
+	/* try to detect the aux device; are you still there? */
+	err = 0;
+	if (doinit) {
+		if (doinitialize(sc, &sc->mode)) {
+			/* yes */
+			sc->state |= PSM_VALID;
+		} else {
+			/* the device has gone! */
+			restore_controller(sc->kbdc, c);
+			sc->state &= ~PSM_VALID;
+			log(LOG_ERR,
+			    "psm%d: the aux device has gone! (reinitialize).\n",
+			    sc->unit);
+			err = ENXIO;
+		}
+	}
 	crit_exit();
-        kbdc_lock(sc->kbdc, FALSE);
-	log(LOG_ERR, "psm%d: unable to set the command byte (reinitialize).\n",
-	    sc->unit);
-	return (EIO);
-    }
-
-    /* flush any data */
-    if (sc->state & PSM_VALID) {
-	disable_aux_dev(sc->kbdc);	/* this may fail; but never mind... */
-	empty_aux_buffer(sc->kbdc, 10);
-    }
-    sc->inputbytes = 0;
-    sc->syncerrors = 0;
-
-    /* try to detect the aux device; are you still there? */
-    err = 0;
-    if (doinit) {
-	if (doinitialize(sc, &sc->mode)) {
-	    /* yes */
-	    sc->state |= PSM_VALID;
+
+	/* restore the driver state */
+	if ((sc->state & PSM_OPEN) && (err == 0)) {
+		/* enable the aux device and the port again */
+		err = doopen(sc, c);
+		if (err != 0)
+			log(LOG_ERR, "psm%d: failed to enable the device "
+			    "(reinitialize).\n", sc->unit);
 	} else {
-	    /* the device has gone! */
-	    restore_controller(sc->kbdc, c);
-	    sc->state &= ~PSM_VALID;
-	    log(LOG_ERR, "psm%d: the aux device has gone! (reinitialize).\n",
-		sc->unit);
-	    err = ENXIO;
-	}
-    }
-    crit_exit();
-
-    /* restore the driver state */
-    if ((sc->state & PSM_OPEN) && (err == 0)) {
-        /* enable the aux device and the port again */
-	err = doopen(sc, c);
-	if (err != 0) 
-	    log(LOG_ERR, "psm%d: failed to enable the device (reinitialize).\n",
-		sc->unit);
-    } else {
-        /* restore the keyboard port and disable the aux port */
-        if (!set_controller_command_byte(sc->kbdc, 
-                kbdc_get_device_mask(sc->kbdc),
-                (c & KBD_KBD_CONTROL_BITS)
-                    | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-            /* CONTROLLER ERROR */
-            log(LOG_ERR, "psm%d: failed to disable the aux port (reinitialize).\n",
-                sc->unit);
-            err = EIO;
-	}
-    }
-
-    kbdc_lock(sc->kbdc, FALSE);
-    return (err);
+		/* restore the keyboard port and disable the aux port */
+		if (!set_controller_command_byte(sc->kbdc,
+		    kbdc_get_device_mask(sc->kbdc),
+		    (c & KBD_KBD_CONTROL_BITS) |
+		    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+			/* CONTROLLER ERROR */
+			log(LOG_ERR, "psm%d: failed to disable the aux port "
+			    "(reinitialize).\n", sc->unit);
+			err = EIO;
+		}
+	}
+
+	kbdc_lock(sc->kbdc, FALSE);
+	return (err);
 }
 
 /* psm driver entry points */
 
-#define endprobe(v)	{   if (bootverbose) 				\
-				--verbose;   				\
-                            kbdc_set_device_mask(sc->kbdc, mask);	\
-			    kbdc_lock(sc->kbdc, FALSE);			\
-			    return (v);	     				\
-			}
+static void
+psmidentify(driver_t *driver, device_t parent)
+{
+	device_t psmc;
+	device_t psm;
+	u_long irq;
+	int unit;
+
+	unit = device_get_unit(parent);
+
+	/* always add at least one child */
+	psm = BUS_ADD_CHILD(parent, parent, KBDC_RID_AUX, driver->name, unit);
+	if (psm == NULL)
+		return;
+
+	irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX);
+	if (irq > 0)
+		return;
+
+	/*
+	 * If the PS/2 mouse device has already been reported by ACPI or
+	 * PnP BIOS, obtain the IRQ resource from it.
+	 * (See psmcpnp_attach() below.)
+	 */
+	psmc = device_find_child(device_get_parent(parent),
+	    PSMCPNP_DRIVER_NAME, unit);
+	if (psmc == NULL)
+		return;
+	irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0);
+	if (irq <= 0)
+		return;
+	bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
+}
+
+#define	endprobe(v)	do {			\
+	if (bootverbose)			\
+		--verbose;			\
+	kbdc_set_device_mask(sc->kbdc, mask);	\
+	kbdc_lock(sc->kbdc, FALSE);		\
+	return (v);				\
+} while (0)
 
 static int
 psmprobe(device_t dev)
 {
-    int unit = device_get_unit(dev);
-    struct psm_softc *sc = device_get_softc(dev);
-    uintptr_t irq;
-    uintptr_t flags;
-    int stat[3];
-    int command_byte;
-    int mask;
-    int rid;
-    int i;
+	int unit = device_get_unit(dev);
+	struct psm_softc *sc = device_get_softc(dev);
+	uintptr_t irq;
+	uintptr_t flags;
+	int stat[3];
+	int command_byte;
+	int mask;
+	int i;
 
 #if 0
-    kbdc_debug(TRUE);
-#endif
-
-#if notyet
-    /* check PnP IDs */
-    if (XXX_PNP_PROBE(device_get_parent(dev), dev, psm_ids) == ENXIO)
-	return ENXIO;
+	kbdc_debug(TRUE);
 #endif
 
-    BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
-    BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
+	BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
+	BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
 
-    sc->unit = unit;
-    sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
-    sc->config = flags & PSM_CONFIG_FLAGS;
-    /* XXX: for backward compatibility */
+	sc->unit = unit;
+	sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
+	sc->config = flags & PSM_CONFIG_FLAGS;
+	/* XXX: for backward compatibility */
 #if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
-    sc->config |= 
+	sc->config |=
 #ifdef PSM_RESETAFTERSUSPEND
 	PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
 #else
 	PSM_CONFIG_HOOKRESUME;
 #endif
 #endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
-    sc->flags = 0;
-    if (bootverbose)
-        ++verbose;
-
-    device_set_desc(dev, "PS/2 Mouse");
-
-    if (!kbdc_lock(sc->kbdc, TRUE)) {
-        kprintf("psm%d: unable to lock the controller.\n", unit);
-        if (bootverbose)
-            --verbose;
-	return (ENXIO);
-    }
-
-    /*
-     * NOTE: two bits in the command byte controls the operation of the
-     * aux port (mouse port): the aux port disable bit (bit 5) and the aux
-     * port interrupt (IRQ 12) enable bit (bit 2).
-     */
-
-    /* discard anything left after the keyboard initialization */
-    empty_both_buffers(sc->kbdc, 10);
-
-    /* save the current command byte; it will be used later */
-    mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
-    command_byte = get_controller_command_byte(sc->kbdc);
-    if (verbose) 
-        kprintf("psm%d: current command byte:%04x\n", unit, command_byte);
-    if (command_byte == -1) {
-        /* CONTROLLER ERROR */
-        kprintf("psm%d: unable to get the current command byte value.\n",
-            unit);
-        endprobe(ENXIO);
-    }
-
-    /*
-     * disable the keyboard port while probing the aux port, which must be
-     * enabled during this routine
-     */
-    if (!set_controller_command_byte(sc->kbdc,
-	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
-  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
-                | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-        /* 
-	 * this is CONTROLLER ERROR; I don't know how to recover 
-         * from this error... 
+	sc->flags = 0;
+	if (bootverbose)
+		++verbose;
+
+	device_set_desc(dev, "PS/2 Mouse");
+
+	if (!kbdc_lock(sc->kbdc, TRUE)) {
+		kprintf("psm%d: unable to lock the controller.\n", unit);
+		if (bootverbose)
+			--verbose;
+		return (ENXIO);
+	}
+
+	/*
+	 * NOTE: two bits in the command byte controls the operation of the
+	 * aux port (mouse port): the aux port disable bit (bit 5) and the aux
+	 * port interrupt (IRQ 12) enable bit (bit 2).
 	 */
-        restore_controller(sc->kbdc, command_byte);
-        kprintf("psm%d: unable to set the command byte.\n", unit);
-        endprobe(ENXIO);
-    }
-    write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
-
-    /*
-     * NOTE: `test_aux_port()' is designed to return with zero if the aux
-     * port exists and is functioning. However, some controllers appears
-     * to respond with zero even when the aux port doesn't exist. (It may
-     * be that this is only the case when the controller DOES have the aux
-     * port but the port is not wired on the motherboard.) The keyboard
-     * controllers without the port, such as the original AT, are
-     * supporsed to return with an error code or simply time out. In any
-     * case, we have to continue probing the port even when the controller
-     * passes this test.
-     *
-     * XXX: some controllers erroneously return the error code 1 when
-     * it has the perfectly functional aux port. We have to ignore this
-     * error code. Even if the controller HAS error with the aux port,
-     * it will be detected later...
-     * XXX: another incompatible controller returns PSM_ACK (0xfa)...
-     */
-    switch ((i = test_aux_port(sc->kbdc))) {
-    case 1:	   /* ignore this error */
-    case 2:	/* Ignore 2 and 3 for use with some acer and compal laptops */
-    case 3:
-    case PSM_ACK:
-        if (verbose)
-	    kprintf("psm%d: strange result for test aux port (%d).\n",
-	        unit, i);
-	/* fall though */
-    case 0:        /* no error */
-        break;
-    case -1:        /* time out */
-    default:        /* error */
-        recover_from_error(sc->kbdc);
-	if (sc->config & PSM_CONFIG_IGNPORTERROR)
-	    break;
-        restore_controller(sc->kbdc, command_byte);
-        if (verbose)
-            kprintf("psm%d: the aux port is not functioning (%d).\n",
-                unit, i);
-        endprobe(ENXIO);
-    }
-
-    if (sc->config & PSM_CONFIG_NORESET) {
-	/* 
-	 * Don't try to reset the pointing device.  It may possibly be
-	 * left in the unknown state, though...
+
+	/* discard anything left after the keyboard initialization */
+	empty_both_buffers(sc->kbdc, 10);
+
+	/* save the current command byte; it will be used later */
+	mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
+	command_byte = get_controller_command_byte(sc->kbdc);
+	if (verbose)
+		kprintf("psm%d: current command byte:%04x\n", unit,
+		    command_byte);
+	if (command_byte == -1) {
+		/* CONTROLLER ERROR */
+		kprintf("psm%d: unable to get the current command byte value.\n",
+			unit);
+		endprobe(ENXIO);
+	}
+
+	/*
+	 * disable the keyboard port while probing the aux port, which must be
+	 * enabled during this routine
 	 */
-    } else {
+	if (!set_controller_command_byte(sc->kbdc,
+	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
+	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
+	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+		/*
+		 * this is CONTROLLER ERROR; I don't know how to recover
+		 * from this error...
+		 */
+		restore_controller(sc->kbdc, command_byte);
+		kprintf("psm%d: unable to set the command byte.\n", unit);
+		endprobe(ENXIO);
+	}
+	write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
+
 	/*
-	 * NOTE: some controllers appears to hang the `keyboard' when the aux
-	 * port doesn't exist and `PSMC_RESET_DEV' is issued.
+	 * NOTE: `test_aux_port()' is designed to return with zero if the aux
+	 * port exists and is functioning. However, some controllers appears
+	 * to respond with zero even when the aux port doesn't exist. (It may
+	 * be that this is only the case when the controller DOES have the aux
+	 * port but the port is not wired on the motherboard.) The keyboard
+	 * controllers without the port, such as the original AT, are
+	 * supporsed to return with an error code or simply time out. In any
+	 * case, we have to continue probing the port even when the controller
+	 * passes this test.
 	 *
-	 * Attempt to reset the controller twice -- this helps
-	 * pierce through some KVM switches. The second reset
-	 * is non-fatal.
+	 * XXX: some controllers erroneously return the error code 1, 2 or 3
+	 * when it has the perfectly functional aux port. We have to ignore
+	 * this error code. Even if the controller HAS error with the aux
+	 * port, it will be detected later...
+	 * XXX: another incompatible controller returns PSM_ACK (0xfa)...
 	 */
-	if (!reset_aux_dev(sc->kbdc)) {
-            recover_from_error(sc->kbdc);
-            restore_controller(sc->kbdc, command_byte);
-            if (verbose)
-        	kprintf("psm%d: failed to reset the aux device.\n", unit);
-            endprobe(ENXIO);
-	} else if (!reset_aux_dev(sc->kbdc)) {
-	    recover_from_error(sc->kbdc);
-	    if (verbose >= 2)
-        	kprintf("psm%d: failed to reset the aux device (2).\n",
-        	    unit);
-	}
-    }
-
-    /*
-     * both the aux port and the aux device is functioning, see if the
-     * device can be enabled. NOTE: when enabled, the device will start
-     * sending data; we shall immediately disable the device once we know
-     * the device can be enabled.
-     */
-    if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
-        /* MOUSE ERROR */
-	recover_from_error(sc->kbdc);
-	restore_controller(sc->kbdc, command_byte);
-	if (verbose)
-	    kprintf("psm%d: failed to enable the aux device.\n", unit);
-        endprobe(ENXIO);
-    }
-
-    /* save the default values after reset */
-    if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
-	sc->dflt_mode.rate = sc->mode.rate = stat[2];
-	sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
-    } else {
-	sc->dflt_mode.rate = sc->mode.rate = -1;
-	sc->dflt_mode.resolution = sc->mode.resolution = -1;
-    }
-
-    /* hardware information */
-    sc->hw.iftype = MOUSE_IF_PS2;
-
-    /* verify the device is a mouse */
-    sc->hw.hwid = get_aux_id(sc->kbdc);
-    if (!is_a_mouse(sc->hw.hwid)) {
-        restore_controller(sc->kbdc, command_byte);
-        if (verbose)
-            kprintf("psm%d: unknown device type (%d).\n", unit, sc->hw.hwid);
-        endprobe(ENXIO);
-    }
-    switch (sc->hw.hwid) {
-    case PSM_BALLPOINT_ID:
-        sc->hw.type = MOUSE_TRACKBALL;
-        break;
-    case PSM_MOUSE_ID:
-    case PSM_INTELLI_ID:
-    case PSM_EXPLORER_ID:
-    case PSM_4DMOUSE_ID:
-    case PSM_4DPLUS_ID:
-        sc->hw.type = MOUSE_MOUSE;
-        break;
-    default:
-        sc->hw.type = MOUSE_UNKNOWN;
-        break;
-    }
-
-    if (sc->config & PSM_CONFIG_NOIDPROBE) {
-	sc->hw.buttons = 2;
-	i = GENERIC_MOUSE_ENTRY;
-    } else {
-	/* # of buttons */
-	sc->hw.buttons = get_mouse_buttons(sc->kbdc);
-
-	/* other parameters */
-	for (i = 0; vendortype[i].probefunc != NULL; ++i) {
-	    if ((*vendortype[i].probefunc)(sc)) {
-		if (verbose >= 2)
-		    kprintf("psm%d: found %s\n",
-			   unit, model_name(vendortype[i].model));
+	switch ((i = test_aux_port(sc->kbdc))) {
+	case 1:		/* ignore these errors */
+	case 2:
+	case 3:
+	case PSM_ACK:
+		if (verbose)
+			kprintf("psm%d: strange result for test aux port "
+			    "(%d).\n", unit, i);
+		/* FALLTHROUGH */
+	case 0:		/* no error */
+		break;
+	case -1:	/* time out */
+	default:	/* error */
+		recover_from_error(sc->kbdc);
+		if (sc->config & PSM_CONFIG_IGNPORTERROR)
+			break;
+		restore_controller(sc->kbdc, command_byte);
+		if (verbose)
+			kprintf("psm%d: the aux port is not functioning (%d).\n",
+			    unit, i);
+		endprobe(ENXIO);
+	}
+
+	if (sc->config & PSM_CONFIG_NORESET) {
+		/*
+		 * Don't try to reset the pointing device.  It may possibly be
+		 * left in the unknown state, though...
+		 */
+	} else {
+		/*
+		 * NOTE: some controllers appears to hang the `keyboard' when
+		 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
+		 *
+		 * Attempt to reset the controller twice -- this helps
+		 * pierce through some KVM switches. The second reset
+		 * is non-fatal.
+		 */
+		if (!reset_aux_dev(sc->kbdc)) {
+			recover_from_error(sc->kbdc);
+			restore_controller(sc->kbdc, command_byte);
+			if (verbose)
+				kprintf("psm%d: failed to reset the aux "
+				    "device.\n", unit);
+			endprobe(ENXIO);
+		} else if (!reset_aux_dev(sc->kbdc)) {
+			recover_from_error(sc->kbdc);
+			if (verbose >= 2)
+				kprintf("psm%d: failed to reset the aux device "
+				    "(2).\n", unit);
+		}
+	}
+
+	/*
+	 * both the aux port and the aux device is functioning, see if the
+	 * device can be enabled. NOTE: when enabled, the device will start
+	 * sending data; we shall immediately disable the device once we know
+	 * the device can be enabled.
+	 */
+	if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
+		/* MOUSE ERROR */
+		recover_from_error(sc->kbdc);
+		restore_controller(sc->kbdc, command_byte);
+		if (verbose)
+			kprintf("psm%d: failed to enable the aux device.\n",
+			    unit);
+		endprobe(ENXIO);
+	}
+
+	/* save the default values after reset */
+	if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
+		sc->dflt_mode.rate = sc->mode.rate = stat[2];
+		sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
+	} else {
+		sc->dflt_mode.rate = sc->mode.rate = -1;
+		sc->dflt_mode.resolution = sc->mode.resolution = -1;
+	}
+
+	/* hardware information */
+	sc->hw.iftype = MOUSE_IF_PS2;
+
+	/* verify the device is a mouse */
+	sc->hw.hwid = get_aux_id(sc->kbdc);
+	if (!is_a_mouse(sc->hw.hwid)) {
+		restore_controller(sc->kbdc, command_byte);
+		if (verbose)
+			kprintf("psm%d: unknown device type (%d).\n", unit,
+			    sc->hw.hwid);
+		endprobe(ENXIO);
+	}
+	switch (sc->hw.hwid) {
+	case PSM_BALLPOINT_ID:
+		sc->hw.type = MOUSE_TRACKBALL;
+		break;
+	case PSM_MOUSE_ID:
+	case PSM_INTELLI_ID:
+	case PSM_EXPLORER_ID:
+	case PSM_4DMOUSE_ID:
+	case PSM_4DPLUS_ID:
+		sc->hw.type = MOUSE_MOUSE;
+		break;
+	default:
+		sc->hw.type = MOUSE_UNKNOWN;
 		break;
-	    }
-	}
-    }
-
-    sc->hw.model = vendortype[i].model;
-
-    sc->dflt_mode.level = PSM_LEVEL_BASE;
-    sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
-    sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
-    if (sc->config & PSM_CONFIG_NOCHECKSYNC)
-        sc->dflt_mode.syncmask[0] = 0;
-    else
-        sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
-    if (sc->config & PSM_CONFIG_FORCETAP)
-        sc->mode.syncmask[0] &= ~MOUSE_PS2_TAP;
-    sc->dflt_mode.syncmask[1] = 0;	/* syncbits */
-    sc->mode = sc->dflt_mode;
-    sc->mode.packetsize = vendortype[i].packetsize;
-
-    /* set mouse parameters */
+	}
+
+	if (sc->config & PSM_CONFIG_NOIDPROBE) {
+		sc->hw.buttons = 2;
+		i = GENERIC_MOUSE_ENTRY;
+	} else {
+		/* # of buttons */
+		sc->hw.buttons = get_mouse_buttons(sc->kbdc);
+
+		/* other parameters */
+		for (i = 0; vendortype[i].probefunc != NULL; ++i)
+			if ((*vendortype[i].probefunc)(sc)) {
+				if (verbose >= 2)
+					kprintf("psm%d: found %s\n", unit,
+					    model_name(vendortype[i].model));
+				break;
+			}
+	}
+
+	sc->hw.model = vendortype[i].model;
+
+	sc->dflt_mode.level = PSM_LEVEL_BASE;
+	sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
+	sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
+	if (sc->config & PSM_CONFIG_NOCHECKSYNC)
+		sc->dflt_mode.syncmask[0] = 0;
+	else
+		sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
+	if (sc->config & PSM_CONFIG_FORCETAP)
+		sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP;
+	sc->dflt_mode.syncmask[1] = 0;	/* syncbits */
+	sc->mode = sc->dflt_mode;
+	sc->mode.packetsize = vendortype[i].packetsize;
+
+	/* set mouse parameters */
 #if 0
-    /* 
-     * A version of Logitech FirstMouse+ won't report wheel movement,
-     * if SET_DEFAULTS is sent...  Don't use this command.
-     * This fix was found by Takashi Nishida.
-     */
-    i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
-    if (verbose >= 2)
-	kprintf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
+	/*
+	 * A version of Logitech FirstMouse+ won't report wheel movement,
+	 * if SET_DEFAULTS is sent...  Don't use this command.
+	 * This fix was found by Takashi Nishida.
+	 */
+	i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
+	if (verbose >= 2)
+		kprintf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
 #endif
-    if (sc->config & PSM_CONFIG_RESOLUTION) {
-        sc->mode.resolution
-	    = set_mouse_resolution(sc->kbdc, 
-				   (sc->config & PSM_CONFIG_RESOLUTION) - 1);
-    } else if (sc->mode.resolution >= 0) {
-	sc->mode.resolution
-	    = set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
-    }
-    if (sc->mode.rate > 0) {
-	sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
-    }
-    set_mouse_scaling(sc->kbdc, 1);
-
-    /* request a data packet and extract sync. bits */
-    if (get_mouse_status(sc->kbdc, stat, 1, 3) < 3) {
-        kprintf("psm%d: failed to get data.\n", unit);
-        sc->mode.syncmask[0] = 0;
-    } else {
-        sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0];	/* syncbits */
-	/* the NetScroll Mouse will send three more bytes... Ignore them */
-	empty_aux_buffer(sc->kbdc, 5);
-    }
-
-    /* just check the status of the mouse */
-    /* 
-     * NOTE: XXX there are some arcane controller/mouse combinations out 
-     * there, which hung the controller unless there is data transmission 
-     * after ACK from the mouse.
-     */
-    if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) {
-        kprintf("psm%d: failed to get status.\n", unit);
-    } else {
-	/* 
-	 * When in its native mode, some mice operate with different 
-	 * default parameters than in the PS/2 compatible mode.
+	if (sc->config & PSM_CONFIG_RESOLUTION)
+		sc->mode.resolution =
+		    set_mouse_resolution(sc->kbdc,
+		    (sc->config & PSM_CONFIG_RESOLUTION) - 1);
+	else if (sc->mode.resolution >= 0)
+		sc->mode.resolution =
+		    set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
+	if (sc->mode.rate > 0)
+		sc->mode.rate =
+		    set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
+	set_mouse_scaling(sc->kbdc, 1);
+
+	/* Record sync on the next data packet we see. */
+	sc->flags |= PSM_NEED_SYNCBITS;
+
+	/* just check the status of the mouse */
+	/*
+	 * NOTE: XXX there are some arcane controller/mouse combinations out
+	 * there, which hung the controller unless there is data transmission
+	 * after ACK from the mouse.
 	 */
-        sc->dflt_mode.rate = sc->mode.rate = stat[2];
-        sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
-     }
+	if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
+		kprintf("psm%d: failed to get status.\n", unit);
+	else {
+		/*
+		 * When in its native mode, some mice operate with different
+		 * default parameters than in the PS/2 compatible mode.
+		 */
+		sc->dflt_mode.rate = sc->mode.rate = stat[2];
+		sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
+	}
 
-    /* disable the aux port for now... */
-    if (!set_controller_command_byte(sc->kbdc, 
+	/* disable the aux port for now... */
+	if (!set_controller_command_byte(sc->kbdc,
 	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
-            (command_byte & KBD_KBD_CONTROL_BITS)
-                | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-        /* 
-	 * this is CONTROLLER ERROR; I don't know the proper way to 
-         * recover from this error... 
-	 */
-        restore_controller(sc->kbdc, command_byte);
-        kprintf("psm%d: unable to set the command byte.\n", unit);
-        endprobe(ENXIO);
-    }
-
-    /* see if IRQ is available */
-    rid = 0;
-    sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
-				  RF_ACTIVE);
-    if (sc->intr == NULL) {
-        kprintf("psm%d: unable to allocate the IRQ resource (%d).\n",
-	       unit, (int)irq);
-        endprobe(ENXIO);
-    } else {
-	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
-    }
+	    (command_byte & KBD_KBD_CONTROL_BITS) |
+	    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+		/*
+		 * this is CONTROLLER ERROR; I don't know the proper way to
+		 * recover from this error...
+		 */
+		restore_controller(sc->kbdc, command_byte);
+		kprintf("psm%d: unable to set the command byte.\n", unit);
+		endprobe(ENXIO);
+	}
 
-    /* done */
-    kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
-    kbdc_lock(sc->kbdc, FALSE);
-    return (0);
+	/* done */
+	kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
+	kbdc_lock(sc->kbdc, FALSE);
+	return (0);
 }
 
 static int
 psmattach(device_t dev)
 {
-    int unit = device_get_unit(dev);
-    struct psm_softc *sc = device_get_softc(dev);
-    uintptr_t irq;
-    int error;
-    int rid;
-
-    if (sc == NULL)    /* shouldn't happen */
-	return (ENXIO);
-
-    /* Setup initial state */
-    sc->state = PSM_VALID;
-    callout_init(&sc->callout);
-
-    /* Setup our interrupt handler */
-    rid = 0;
-    BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
-    sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
-				  RF_ACTIVE);
-    if (sc->intr == NULL)
-	return (ENXIO);
-    error = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->intr,
-			   INTR_NOPOLL, psmintr, sc, &sc->ih, NULL);
-    if (error) {
-	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
-	return (error);
-    }
-
-    /* Done */
-    make_dev(&psm_ops, PSM_MKMINOR(unit, FALSE), 0, 0, 0666, "psm%d", unit);
-    make_dev(&psm_ops, PSM_MKMINOR(unit, TRUE), 0, 0, 0666, "bpsm%d", unit);
-
-    if (!verbose) {
-        kprintf("psm%d: model %s, device ID %d\n", 
-	    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
-    } else {
-        kprintf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
-	    unit, model_name(sc->hw.model),
-	    sc->hw.hwid & 0x00ff, sc->hw.hwid >> 8, sc->hw.buttons);
-	kprintf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
-	    unit, sc->config, sc->flags, sc->mode.packetsize);
-	kprintf("psm%d: syncmask:%02x, syncbits:%02x\n",
-	    unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
-    }
-
-    if (bootverbose)
-        --verbose;
-
-    return (0);
+	int unit = device_get_unit(dev);
+	struct psm_softc *sc = device_get_softc(dev);
+	int error;
+	intptr_t irq;
+	int rid;
+
+	/* Setup initial state */
+	sc->state = PSM_VALID;
+	callout_init(&sc->callout);
+	callout_init(&sc->softcallout);
+
+	/* Setup our interrupt handler */
+	rid = KBDC_RID_AUX;
+	BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
+	sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
+			RF_ACTIVE);
+
+	if (sc->intr == NULL)
+		return (ENXIO);
+	error = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->intr,
+			INTR_NOPOLL, psmintr, sc, &sc->ih, NULL);
+	if (error) {
+		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
+		return (error);
+	}
+
+	/* Done */
+	make_dev(&psm_ops, PSM_MKMINOR(unit, FALSE), 0, 0, 0666, "psm%d", unit);
+	make_dev(&psm_ops, PSM_MKMINOR(unit, TRUE), 0, 0, 0666, "bpsm%d", unit);
+
+	if (!verbose)
+		kprintf("psm%d: model %s, device ID %d\n",
+		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
+	else {
+		kprintf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
+		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff,
+		    sc->hw.hwid >> 8, sc->hw.buttons);
+		kprintf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
+		    unit, sc->config, sc->flags, sc->mode.packetsize);
+		kprintf("psm%d: syncmask:%02x, syncbits:%02x\n",
+		    unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
+	}
+
+	if (bootverbose)
+		--verbose;
+
+	return (0);
 }
 
 static int
 psmdetach(device_t dev)
 {
-    struct psm_softc *sc;
-    int rid;
-    int unit;
+	struct psm_softc *sc;
+	int rid;
 
-    sc = device_get_softc(dev);
-    if (sc->state & PSM_OPEN)
-	return EBUSY;
+	sc = device_get_softc(dev);
+	if (sc->state & PSM_OPEN)
+		return (EBUSY);
 
-    unit = device_get_unit(dev);
+	rid = KBDC_RID_AUX;
+	bus_teardown_intr(dev, sc->intr, sc->ih);
+	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
 
-    rid = 0;
-    BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->intr, sc->ih);
-    bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
-    kprintf("devfs: Please make sure that only the right psm device was removed!!!!\n");
-    dev_ops_remove_minor(&psm_ops, /*PSM_MKMINOR(-1, 0), */PSM_MKMINOR(unit, 0));
+	destroy_dev(sc->dev);
+	destroy_dev(sc->bdev);
 
-    return 0;
+	return (0);
 }
 
 static int
 psmopen(struct dev_open_args *ap)
 {
-    cdev_t dev = ap->a_head.a_dev;
-    int unit = PSM_UNIT(dev);
-    struct psm_softc *sc;
-    int command_byte;
-    int err;
-
-    /* Get device data */
-    sc = PSM_SOFTC(unit);
-    if ((sc == NULL) || (sc->state & PSM_VALID) == 0)
-	/* the device is no longer valid/functioning */
-        return (ENXIO);
-
-    /* Disallow multiple opens */
-    if (sc->state & PSM_OPEN)
-        return (EBUSY);
+	cdev_t dev = ap->a_head.a_dev;
+	int unit = PSM_UNIT(dev);
+	struct psm_softc *sc;
+	int command_byte;
+	int err;
+
+	/* Get device data */
+	sc = PSM_SOFTC(unit);
+	if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
+		/* the device is no longer valid/functioning */
+		return (ENXIO);
+	}
+
+	/* Disallow multiple opens */
+	if (sc->state & PSM_OPEN)
+		return (EBUSY);
 
 #if 0
-    device_busy(devclass_get_device(psm_devclass, unit));
+	device_busy(devclass_get_device(psm_devclass, sc->unit));
 #endif
 
-    /* Initialize state */
-    sc->mode.level = sc->dflt_mode.level;
-    sc->mode.protocol = sc->dflt_mode.protocol;
-    sc->watchdog = FALSE;
-
-    /* flush the event queue */
-    sc->queue.count = 0;
-    sc->queue.head = 0;
-    sc->queue.tail = 0;
-    sc->status.flags = 0;
-    sc->status.button = 0;
-    sc->status.obutton = 0;
-    sc->status.dx = 0;
-    sc->status.dy = 0;
-    sc->status.dz = 0;
-    sc->button = 0;
-
-    /* empty input buffer */
-    bzero(sc->ipacket, sizeof(sc->ipacket));
-    sc->inputbytes = 0;
-    sc->syncerrors = 0;
-
-    /* don't let timeout routines in the keyboard driver to poll the kbdc */
-    if (!kbdc_lock(sc->kbdc, TRUE))
-	return (EIO);
-
-    /* save the current controller command byte */
-    crit_enter();
-    command_byte = get_controller_command_byte(sc->kbdc);
-
-    /* enable the aux port and temporalily disable the keyboard */
-    if ((command_byte == -1) 
-        || !set_controller_command_byte(sc->kbdc,
+	/* Initialize state */
+	sc->mode.level = sc->dflt_mode.level;
+	sc->mode.protocol = sc->dflt_mode.protocol;
+	sc->watchdog = FALSE;
+	sc->async = NULL;
+
+	/* flush the event queue */
+	sc->queue.count = 0;
+	sc->queue.head = 0;
+	sc->queue.tail = 0;
+	sc->status.flags = 0;
+	sc->status.button = 0;
+	sc->status.obutton = 0;
+	sc->status.dx = 0;
+	sc->status.dy = 0;
+	sc->status.dz = 0;
+	sc->button = 0;
+	sc->pqueue_start = 0;
+	sc->pqueue_end = 0;
+
+	/* empty input buffer */
+	flushpackets(sc);
+	sc->syncerrors = 0;
+	sc->pkterrors = 0;
+
+	/* don't let timeout routines in the keyboard driver to poll the kbdc */
+	if (!kbdc_lock(sc->kbdc, TRUE))
+		return (EIO);
+
+	/* save the current controller command byte */
+	crit_enter();
+	command_byte = get_controller_command_byte(sc->kbdc);
+
+	/* enable the aux port and temporalily disable the keyboard */
+	if (command_byte == -1 || !set_controller_command_byte(sc->kbdc,
 	    kbdc_get_device_mask(sc->kbdc),
-  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
-	        | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-        /* CONTROLLER ERROR; do you know how to get out of this? */
-        kbdc_lock(sc->kbdc, FALSE);
+	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
+	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+		/* CONTROLLER ERROR; do you know how to get out of this? */
+		kbdc_lock(sc->kbdc, FALSE);
+		crit_exit();
+		log(LOG_ERR,
+		    "psm%d: unable to set the command byte (psmopen).\n",
+		    sc->unit);
+		return (EIO);
+	}
+	/*
+	 * Now that the keyboard controller is told not to generate
+	 * the keyboard and mouse interrupts, call `splx()' to allow
+	 * the other tty interrupts. The clock interrupt may also occur,
+	 * but timeout routines will be blocked by the poll flag set
+	 * via `kbdc_lock()'
+	 */
 	crit_exit();
-	log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n",
-	    unit);
-	return (EIO);
-    }
-    /* 
-     * Now that the keyboard controller is told not to generate 
-     * the keyboard and mouse interrupts, call `splx()' to allow 
-     * the other tty interrupts. The clock interrupt may also occur, 
-     * but timeout routines will be blocked by the poll flag set 
-     * via `kbdc_lock()'
-     */
-    crit_exit();
-  
-    /* enable the mouse device */
-    err = doopen(sc, command_byte);
-
-    /* done */
-    if (err == 0) 
-        sc->state |= PSM_OPEN;
-    kbdc_lock(sc->kbdc, FALSE);
-    return (err);
+
+	/* enable the mouse device */
+	err = doopen(sc, command_byte);
+
+	/* done */
+	if (err == 0)
+		sc->state |= PSM_OPEN;
+	kbdc_lock(sc->kbdc, FALSE);
+	return (err);
 }
 
 static int
 psmclose(struct dev_close_args *ap)
 {
-    cdev_t dev = ap->a_head.a_dev;
-    int unit = PSM_UNIT(dev);
-    struct psm_softc *sc = PSM_SOFTC(unit);
-    int stat[3];
-    int command_byte;
-
-    /* don't let timeout routines in the keyboard driver to poll the kbdc */
-    if (!kbdc_lock(sc->kbdc, TRUE))
-	return (EIO);
-
-    /* save the current controller command byte */
-    crit_enter();
-    command_byte = get_controller_command_byte(sc->kbdc);
-    if (command_byte == -1) {
-        kbdc_lock(sc->kbdc, FALSE);
-	crit_exit();
-	return (EIO);
-    }
+	cdev_t dev = ap->a_head.a_dev;
+	int unit = PSM_UNIT(dev);
+	struct psm_softc *sc = PSM_SOFTC(unit);
+	int stat[3];
+	int command_byte;
+
+	/* don't let timeout routines in the keyboard driver to poll the kbdc */
+	if (!kbdc_lock(sc->kbdc, TRUE))
+		return (EIO);
 
-    /* disable the aux interrupt and temporalily disable the keyboard */
-    if (!set_controller_command_byte(sc->kbdc, 
+	/* save the current controller command byte */
+	crit_enter();
+	command_byte = get_controller_command_byte(sc->kbdc);
+	if (command_byte == -1) {
+		kbdc_lock(sc->kbdc, FALSE);
+		crit_exit();
+		return (EIO);
+	}
+
+	/* disable the aux interrupt and temporalily disable the keyboard */
+	if (!set_controller_command_byte(sc->kbdc,
 	    kbdc_get_device_mask(sc->kbdc),
-  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
-	        | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-	log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n",
-	    unit);
-	/* CONTROLLER ERROR;
-	 * NOTE: we shall force our way through. Because the only
-	 * ill effect we shall see is that we may not be able
-	 * to read ACK from the mouse, and it doesn't matter much 
-	 * so long as the mouse will accept the DISABLE command.
-	 */
-    }
-    crit_exit();
-
-    /* stop the watchdog timer */
-    callout_stop(&sc->callout);
-
-    /* remove anything left in the output buffer */
-    empty_aux_buffer(sc->kbdc, 10);
-
-    /* disable the aux device, port and interrupt */
-    if (sc->state & PSM_VALID) {
-        if (!disable_aux_dev(sc->kbdc)) {
-	    /* MOUSE ERROR; 
-	     * NOTE: we don't return error and continue, pretending 
-	     * we have successfully disabled the device. It's OK because 
-	     * the interrupt routine will discard any data from the mouse
-	     * hereafter. 
-	     */
-	    log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n",
-		unit);
-        }
-
-        if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
-            log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", 
-		unit);
-    }
-
-    if (!set_controller_command_byte(sc->kbdc, 
+	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
+	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+		log(LOG_ERR,
+		    "psm%d: failed to disable the aux int (psmclose).\n",
+		    sc->unit);
+		/* CONTROLLER ERROR;
+		 * NOTE: we shall force our way through. Because the only
+		 * ill effect we shall see is that we may not be able
+		 * to read ACK from the mouse, and it doesn't matter much
+		 * so long as the mouse will accept the DISABLE command.
+		 */
+	}
+	crit_exit();
+
+	/* stop the watchdog timer */
+	callout_stop(&sc->callout);
+
+	/* remove anything left in the output buffer */
+	empty_aux_buffer(sc->kbdc, 10);
+
+	/* disable the aux device, port and interrupt */
+	if (sc->state & PSM_VALID) {
+		if (!disable_aux_dev(sc->kbdc)) {
+			/* MOUSE ERROR;
+			 * NOTE: we don't return (error) and continue,
+			 * pretending we have successfully disabled the device.
+			 * It's OK because the interrupt routine will discard
+			 * any data from the mouse hereafter.
+			 */
+			log(LOG_ERR,
+			    "psm%d: failed to disable the device (psmclose).\n",
+			    sc->unit);
+		}
+
+		if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
+			log(LOG_DEBUG,
+			    "psm%d: failed to get status (psmclose).\n",
+			    sc->unit);
+	}
+
+	if (!set_controller_command_byte(sc->kbdc,
 	    kbdc_get_device_mask(sc->kbdc),
-	    (command_byte & KBD_KBD_CONTROL_BITS)
-	        | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-	/* CONTROLLER ERROR; 
-	 * we shall ignore this error; see the above comment.
-	 */
-	log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n",
-	    unit);
-    }
+	    (command_byte & KBD_KBD_CONTROL_BITS) |
+	    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+		/*
+		 * CONTROLLER ERROR;
+		 * we shall ignore this error; see the above comment.
+		 */
+		log(LOG_ERR,
+		    "psm%d: failed to disable the aux port (psmclose).\n",
+		    sc->unit);
+	}
 
-    /* remove anything left in the output buffer */
-    empty_aux_buffer(sc->kbdc, 10);
+	/* remove anything left in the output buffer */
+	empty_aux_buffer(sc->kbdc, 10);
 
-    /* close is almost always successful */
-    sc->state &= ~PSM_OPEN;
-    kbdc_lock(sc->kbdc, FALSE);
+	/* close is almost always successful */
+	sc->state &= ~PSM_OPEN;
+	kbdc_lock(sc->kbdc, FALSE);
 #if 0
-    device_unbusy(devclass_get_device(psm_devclass, unit));
+	device_unbusy(devclass_get_device(psm_devclass, sc->unit));
 #endif
-    return (0);
+	return (0);
 }
 
 static int
-tame_mouse(struct psm_softc *sc, mousestatus_t *status, unsigned char *buf)
+tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status,
+    u_char *buf)
 {
-    static unsigned char butmapps2[8] = {
-        0,
-        MOUSE_PS2_BUTTON1DOWN, 
-        MOUSE_PS2_BUTTON2DOWN,
-        MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
-        MOUSE_PS2_BUTTON3DOWN,
-        MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
-        MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
-        MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
-    };
-    static unsigned char butmapmsc[8] = {
-        MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
-        MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
-        MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
-        MOUSE_MSC_BUTTON3UP,
-        MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
-        MOUSE_MSC_BUTTON2UP,
-        MOUSE_MSC_BUTTON1UP, 
-        0,
-    };
-    int mapped;
-    int i;
-
-    if (sc->mode.level == PSM_LEVEL_BASE) {
-        mapped = status->button & ~MOUSE_BUTTON4DOWN;
-        if (status->button & MOUSE_BUTTON4DOWN) 
-	    mapped |= MOUSE_BUTTON1DOWN;
-        status->button = mapped;
-        buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
-        i = max(min(status->dx, 255), -256);
-	if (i < 0)
-	    buf[0] |= MOUSE_PS2_XNEG;
-        buf[1] = i;
-        i = max(min(status->dy, 255), -256);
-	if (i < 0)
-	    buf[0] |= MOUSE_PS2_YNEG;
-        buf[2] = i;
-	return MOUSE_PS2_PACKETSIZE;
-    } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
-        buf[0] = MOUSE_MSC_SYNC | butmapmsc[status->button & MOUSE_STDBUTTONS];
-        i = max(min(status->dx, 255), -256);
-        buf[1] = i >> 1;
-        buf[3] = i - buf[1];
-        i = max(min(status->dy, 255), -256);
-        buf[2] = i >> 1;
-        buf[4] = i - buf[2];
-        i = max(min(status->dz, 127), -128);
-        buf[5] = (i >> 1) & 0x7f;
-        buf[6] = (i - (i >> 1)) & 0x7f;
-        buf[7] = (~status->button >> 3) & 0x7f;
-	return MOUSE_SYS_PACKETSIZE;
-    }
-    return sc->inputbytes;
+	static u_char butmapps2[8] = {
+		0,
+		MOUSE_PS2_BUTTON1DOWN,
+		MOUSE_PS2_BUTTON2DOWN,
+		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
+		MOUSE_PS2_BUTTON3DOWN,
+		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
+		MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
+		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN |
+		    MOUSE_PS2_BUTTON3DOWN,
+	};
+	static u_char butmapmsc[8] = {
+		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP |
+		    MOUSE_MSC_BUTTON3UP,
+		MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
+		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
+		MOUSE_MSC_BUTTON3UP,
+		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
+		MOUSE_MSC_BUTTON2UP,
+		MOUSE_MSC_BUTTON1UP,
+		0,
+	};
+	int mapped;
+	int i;
+
+	if (sc->mode.level == PSM_LEVEL_BASE) {
+		mapped = status->button & ~MOUSE_BUTTON4DOWN;
+		if (status->button & MOUSE_BUTTON4DOWN)
+			mapped |= MOUSE_BUTTON1DOWN;
+		status->button = mapped;
+		buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
+		i = imax(imin(status->dx, 255), -256);
+		if (i < 0)
+			buf[0] |= MOUSE_PS2_XNEG;
+		buf[1] = i;
+		i = imax(imin(status->dy, 255), -256);
+		if (i < 0)
+			buf[0] |= MOUSE_PS2_YNEG;
+		buf[2] = i;
+		return (MOUSE_PS2_PACKETSIZE);
+	} else if (sc->mode.level == PSM_LEVEL_STANDARD) {
+		buf[0] = MOUSE_MSC_SYNC |
+		    butmapmsc[status->button & MOUSE_STDBUTTONS];
+		i = imax(imin(status->dx, 255), -256);
+		buf[1] = i >> 1;
+		buf[3] = i - buf[1];
+		i = imax(imin(status->dy, 255), -256);
+		buf[2] = i >> 1;
+		buf[4] = i - buf[2];
+		i = imax(imin(status->dz, 127), -128);
+		buf[5] = (i >> 1) & 0x7f;
+		buf[6] = (i - (i >> 1)) & 0x7f;
+		buf[7] = (~status->button >> 3) & 0x7f;
+		return (MOUSE_SYS_PACKETSIZE);
+	}
+	return (pb->inputbytes);
 }
 
 static int
 psmread(struct dev_read_args *ap)
 {
-    cdev_t dev = ap->a_head.a_dev;
-    struct uio *uio = ap->a_uio;
-    struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
-    unsigned char buf[PSM_SMALLBUFSIZE];
-    int error = 0;
-    int l;
-
-    if ((sc->state & PSM_VALID) == 0)
-	return EIO;
-
-    /* block until mouse activity occured */
-    crit_enter();
-    while (sc->queue.count <= 0) {
-        if (PSM_NBLOCKIO(dev)) {
-            crit_exit();
-            return EWOULDBLOCK;
-        }
-        sc->state |= PSM_ASLP;
-        error = tsleep((caddr_t) sc, PCATCH, "psmrea", 0);
-        sc->state &= ~PSM_ASLP;
-        if (error) {
-            crit_exit();
-            return error;
-        } else if ((sc->state & PSM_VALID) == 0) {
-            /* the device disappeared! */
-            crit_exit();
-            return EIO;
-	}
-    }
-    crit_exit();
-
-    /* copy data to the user land */
-    while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
-        crit_enter();
-	l = (int)szmin(sc->queue.count, uio->uio_resid);
-	if (l > sizeof(buf))
-	    l = sizeof(buf);
-	if (l > sizeof(sc->queue.buf) - sc->queue.head) {
-	    bcopy(&sc->queue.buf[sc->queue.head], &buf[0], 
-		sizeof(sc->queue.buf) - sc->queue.head);
-	    bcopy(&sc->queue.buf[0], 
-		&buf[sizeof(sc->queue.buf) - sc->queue.head],
-		l - (sizeof(sc->queue.buf) - sc->queue.head));
-	} else {
-	    bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
+	cdev_t dev = ap->a_head.a_dev;
+	struct uio *uio = ap->a_uio;
+	struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
+	u_char buf[PSM_SMALLBUFSIZE];
+	int error = 0;
+	int l;
+
+	if ((sc->state & PSM_VALID) == 0)
+		return (EIO);
+
+	/* block until mouse activity occured */
+	crit_enter();
+	while (sc->queue.count <= 0) {
+		if (dev != sc->bdev) {
+			crit_exit();
+			return (EWOULDBLOCK);
+		}
+		sc->state |= PSM_ASLP;
+		error = tsleep((caddr_t) sc, PCATCH, "psmrea", 0);
+		sc->state &= ~PSM_ASLP;
+		if (error) {
+			crit_exit();
+			return (error);
+		} else if ((sc->state & PSM_VALID) == 0) {
+			/* the device disappeared! */
+			crit_exit();
+			return (EIO);
+		}
+	}
+	crit_exit();
+
+	/* copy data to the user land */
+	while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
+		crit_enter();
+		l = imin(sc->queue.count, uio->uio_resid);
+		if (l > sizeof(buf))
+			l = sizeof(buf);
+		if (l > sizeof(sc->queue.buf) - sc->queue.head) {
+			bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
+			    sizeof(sc->queue.buf) - sc->queue.head);
+			bcopy(&sc->queue.buf[0],
+			    &buf[sizeof(sc->queue.buf) - sc->queue.head],
+			    l - (sizeof(sc->queue.buf) - sc->queue.head));
+		} else
+			bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
+		sc->queue.count -= l;
+		sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
+		crit_exit();
+		error = uiomove(buf, (size_t)l, uio);
+		if (error)
+			break;
 	}
-	sc->queue.count -= l;
-	sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
-        crit_exit();
-        error = uiomove(buf, (size_t)l, uio);
-        if (error)
-	    break;
-    }
 
-    return error;
+	return (error);
 }
 
 static int
 block_mouse_data(struct psm_softc *sc, int *c)
 {
-    if (!kbdc_lock(sc->kbdc, TRUE)) 
-	return EIO;
 
-    crit_enter();
-    *c = get_controller_command_byte(sc->kbdc);
-    if ((*c == -1) 
-	|| !set_controller_command_byte(sc->kbdc, 
+	if (!kbdc_lock(sc->kbdc, TRUE))
+		return (EIO);
+
+	crit_enter();
+	*c = get_controller_command_byte(sc->kbdc);
+	if ((*c == -1) || !set_controller_command_byte(sc->kbdc,
 	    kbdc_get_device_mask(sc->kbdc),
-            KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
-                | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
-        /* this is CONTROLLER ERROR */
+	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
+	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
+		/* this is CONTROLLER ERROR */
+		crit_exit();
+		kbdc_lock(sc->kbdc, FALSE);
+		return (EIO);
+	}
+
+	/*
+	 * The device may be in the middle of status data transmission.
+	 * The transmission will be interrupted, thus, incomplete status
+	 * data must be discarded. Although the aux interrupt is disabled
+	 * at the keyboard controller level, at most one aux interrupt
+	 * may have already been pending and a data byte is in the
+	 * output buffer; throw it away. Note that the second argument
+	 * to `empty_aux_buffer()' is zero, so that the call will just
+	 * flush the internal queue.
+	 * `psmintr()' will be invoked after `splx()' if an interrupt is
+	 * pending; it will see no data and returns immediately.
+	 */
+	empty_aux_buffer(sc->kbdc, 0);		/* flush the queue */
+	read_aux_data_no_wait(sc->kbdc);	/* throw away data if any */
+	flushpackets(sc);
 	crit_exit();
-        kbdc_lock(sc->kbdc, FALSE);
-	return EIO;
-    }
-
-    /* 
-     * The device may be in the middle of status data transmission.
-     * The transmission will be interrupted, thus, incomplete status 
-     * data must be discarded. Although the aux interrupt is disabled 
-     * at the keyboard controller level, at most one aux interrupt 
-     * may have already been pending and a data byte is in the 
-     * output buffer; throw it away. Note that the second argument 
-     * to `empty_aux_buffer()' is zero, so that the call will just 
-     * flush the internal queue.
-     * `psmintr()' will be invoked after `splx()' if an interrupt is
-     * pending; it will see no data and returns immediately.
-     */
-    empty_aux_buffer(sc->kbdc, 0);	/* flush the queue */
-    read_aux_data_no_wait(sc->kbdc);	/* throw away data if any */
-    sc->inputbytes = 0;
-    crit_exit();
-
-    return 0;
+
+	return (0);
+}
+
+static void
+dropqueue(struct psm_softc *sc)
+{
+
+	sc->queue.count = 0;
+	sc->queue.head = 0;
+	sc->queue.tail = 0;
+	if ((sc->state & PSM_SOFTARMED) != 0) {
+		sc->state &= ~PSM_SOFTARMED;
+		callout_stop(&sc->softcallout);
+	}
+	sc->pqueue_start = sc->pqueue_end;
+}
+
+static void
+flushpackets(struct psm_softc *sc)
+{
+
+	dropqueue(sc);
+	bzero(&sc->pqueue, sizeof(sc->pqueue));
 }
 
 static int
 unblock_mouse_data(struct psm_softc *sc, int c)
 {
-    int error = 0;
+	int error = 0;
 
-    /* 
-     * We may have seen a part of status data during `set_mouse_XXX()'.
-     * they have been queued; flush it.
-     */
-    empty_aux_buffer(sc->kbdc, 0);
+	/*
+	 * We may have seen a part of status data during `set_mouse_XXX()'.
+	 * they have been queued; flush it.
+	 */
+	empty_aux_buffer(sc->kbdc, 0);
 
-    /* restore ports and interrupt */
-    if (!set_controller_command_byte(sc->kbdc, 
-            kbdc_get_device_mask(sc->kbdc),
+	/* restore ports and interrupt */
+	if (!set_controller_command_byte(sc->kbdc,
+	    kbdc_get_device_mask(sc->kbdc),
 	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
-        /* CONTROLLER ERROR; this is serious, we may have
-         * been left with the inaccessible keyboard and
-         * the disabled mouse interrupt. 
-         */
-        error = EIO;
-    }
-
-    kbdc_lock(sc->kbdc, FALSE);
-    return error;
+		/*
+		 * CONTROLLER ERROR; this is serious, we may have
+		 * been left with the inaccessible keyboard and
+		 * the disabled mouse interrupt.
+		 */
+		error = EIO;
+	}
+
+	kbdc_lock(sc->kbdc, FALSE);
+	return (error);
+}
+
+static int
+psmwrite(struct dev_write_args *ap)
+{
+	cdev_t dev = ap->a_head.a_dev;
+	struct uio *uio = ap->a_uio;
+	struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
+	u_char buf[PSM_SMALLBUFSIZE];
+	int error = 0, i, l;
+
+	if ((sc->state & PSM_VALID) == 0)
+		return (EIO);
+
+	if (sc->mode.level < PSM_LEVEL_NATIVE)
+		return (ENODEV);
+
+	/* copy data from the user land */
+	while (uio->uio_resid > 0) {
+		l = imin(PSM_SMALLBUFSIZE, uio->uio_resid);
+		error = uiomove(buf, l, uio);
+		if (error)
+			break;
+		for (i = 0; i < l; i++) {
+			VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i]));
+			if (!write_aux_command(sc->kbdc, buf[i])) {
+				VLOG(2, (LOG_DEBUG,
+				    "psm: cmd 0x%x failed.\n", buf[i]));
+				return (reinitialize(sc, FALSE));
+			}
+		}
+	}
+
+	return (error);
 }
 
 static int
 psmioctl(struct dev_ioctl_args *ap)
 {
-    cdev_t dev = ap->a_head.a_dev;
-    caddr_t addr=  ap->a_data;
-    struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
-    mousemode_t mode;
-    mousestatus_t status;
+	cdev_t dev = ap->a_head.a_dev;
+	caddr_t addr=  ap->a_data;
+	struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
+	mousemode_t mode;
+	mousestatus_t status;
 #if (defined(MOUSE_GETVARS))
-    mousevar_t *var;
+	mousevar_t *var;
 #endif
-    mousedata_t *data;
-    int stat[3];
-    int command_byte;
-    int error = 0;
+	mousedata_t *data;
+	int stat[3];
+	int command_byte;
+	int error = 0;
+
+	mode.resolution = -1;
+
+	/* Perform IOCTL command */
+	switch (ap->a_cmd) {
+
+	case OLD_MOUSE_GETHWINFO:
+		crit_enter();
+		((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
+		((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
+		((old_mousehw_t *)addr)->type = sc->hw.type;
+		((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
+		crit_exit();
+		break;
 
-    mode.resolution = -1;
+	case MOUSE_GETHWINFO:
+		crit_enter();
+		*(mousehw_t *)addr = sc->hw;
+		if (sc->mode.level == PSM_LEVEL_BASE)
+			((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
+		crit_exit();
+		break;
 
-    /* Perform IOCTL command */
+	case MOUSE_SYN_GETHWINFO:
+		crit_enter();
+		if (synaptics_support && sc->hw.model == MOUSE_MODEL_SYNAPTICS)
+			*(synapticshw_t *)addr = sc->synhw;
+		else
+			error = EINVAL;
+		crit_exit();
+		break;
 
-    switch (ap->a_cmd) {
-    case OLD_MOUSE_GETHWINFO:
-	crit_enter();
-        ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
-        ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
-        ((old_mousehw_t *)addr)->type = sc->hw.type;
-        ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
-	crit_exit();
-        break;
+	case OLD_MOUSE_GETMODE:
+		crit_enter();
+		switch (sc->mode.level) {
+		case PSM_LEVEL_BASE:
+			((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
+			break;
+		case PSM_LEVEL_STANDARD:
+			((old_mousemode_t *)addr)->protocol =
+			    MOUSE_PROTO_SYSMOUSE;
+			break;
+		case PSM_LEVEL_NATIVE:
+			((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
+			break;
+		}
+		((old_mousemode_t *)addr)->rate = sc->mode.rate;
+		((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
+		((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
+		crit_exit();
+		break;
 
-    case MOUSE_GETHWINFO:
-	crit_enter();
-        *(mousehw_t *)addr = sc->hw;
-	if (sc->mode.level == PSM_LEVEL_BASE)
-	    ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
-	crit_exit();
-        break;
+	case MOUSE_GETMODE:
+		crit_enter();
+		*(mousemode_t *)addr = sc->mode;
+		if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
+			((mousemode_t *)addr)->syncmask[0] = 0;
+			((mousemode_t *)addr)->syncmask[1] = 0;
+		}
+		((mousemode_t *)addr)->resolution =
+			MOUSE_RES_LOW - sc->mode.resolution;
+		switch (sc->mode.level) {
+		case PSM_LEVEL_BASE:
+			((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
+			((mousemode_t *)addr)->packetsize =
+			    MOUSE_PS2_PACKETSIZE;
+			break;
+		case PSM_LEVEL_STANDARD:
+			((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
+			((mousemode_t *)addr)->packetsize =
+			    MOUSE_SYS_PACKETSIZE;
+			((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
+			((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
+			break;
+		case PSM_LEVEL_NATIVE:
+			/* FIXME: this isn't quite correct... XXX */
+			((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
+			break;
+		}
+		crit_exit();
+		break;
 
-    case OLD_MOUSE_GETMODE:
-	crit_enter();
-	switch (sc->mode.level) {
-	case PSM_LEVEL_BASE:
-	    ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
-	    break;
-	case PSM_LEVEL_STANDARD:
-	    ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
-	    break;
-	case PSM_LEVEL_NATIVE:
-	    ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
-	    break;
-	}
-        ((old_mousemode_t *)addr)->rate = sc->mode.rate;
-        ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
-        ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
-	crit_exit();
-        break;
+	case OLD_MOUSE_SETMODE:
+	case MOUSE_SETMODE:
+		if (ap->a_cmd == OLD_MOUSE_SETMODE) {
+			mode.rate = ((old_mousemode_t *)addr)->rate;
+			/*
+			 * resolution  old I/F   new I/F
+			 * default        0         0
+			 * low            1        -2
+			 * medium low     2        -3
+			 * medium high    3        -4
+			 * high           4        -5
+			 */
+			if (((old_mousemode_t *)addr)->resolution > 0)
+				mode.resolution =
+				    -((old_mousemode_t *)addr)->resolution - 1;
+			else
+				mode.resolution = 0;
+			mode.accelfactor =
+			    ((old_mousemode_t *)addr)->accelfactor;
+			mode.level = -1;
+		} else
+			mode = *(mousemode_t *)addr;
+
+		/* adjust and validate parameters. */
+		if (mode.rate > UCHAR_MAX)
+			return (EINVAL);
+		if (mode.rate == 0)
+			mode.rate = sc->dflt_mode.rate;
+		else if (mode.rate == -1)
+			/* don't change the current setting */
+			;
+		else if (mode.rate < 0)
+			return (EINVAL);
+		if (mode.resolution >= UCHAR_MAX)
+			return (EINVAL);
+		if (mode.resolution >= 200)
+			mode.resolution = MOUSE_RES_HIGH;
+		else if (mode.resolution >= 100)
+			mode.resolution = MOUSE_RES_MEDIUMHIGH;
+		else if (mode.resolution >= 50)
+			mode.resolution = MOUSE_RES_MEDIUMLOW;
+		else if (mode.resolution > 0)
+			mode.resolution = MOUSE_RES_LOW;
+		if (mode.resolution == MOUSE_RES_DEFAULT)
+			mode.resolution = sc->dflt_mode.resolution;
+		else if (mode.resolution == -1)
+			/* don't change the current setting */
+			;
+		else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
+			mode.resolution = MOUSE_RES_LOW - mode.resolution;
+		if (mode.level == -1)
+			/* don't change the current setting */
+			mode.level = sc->mode.level;
+		else if ((mode.level < PSM_LEVEL_MIN) ||
+		    (mode.level > PSM_LEVEL_MAX))
+			return (EINVAL);
+		if (mode.accelfactor == -1)
+			/* don't change the current setting */
+			mode.accelfactor = sc->mode.accelfactor;
+		else if (mode.accelfactor < 0)
+			return (EINVAL);
+
+		/* don't allow anybody to poll the keyboard controller */
+		error = block_mouse_data(sc, &command_byte);
+		if (error)
+			return (error);
+
+		/* set mouse parameters */
+		if (mode.rate > 0)
+			mode.rate = set_mouse_sampling_rate(sc->kbdc,
+			    mode.rate);
+		if (mode.resolution >= 0)
+			mode.resolution =
+			    set_mouse_resolution(sc->kbdc, mode.resolution);
+		set_mouse_scaling(sc->kbdc, 1);
+		get_mouse_status(sc->kbdc, stat, 0, 3);
+
+		crit_enter();
+		sc->mode.rate = mode.rate;
+		sc->mode.resolution = mode.resolution;
+		sc->mode.accelfactor = mode.accelfactor;
+		sc->mode.level = mode.level;
+		crit_exit();
+
+		unblock_mouse_data(sc, command_byte);
+		break;
 
-    case MOUSE_GETMODE:
-	crit_enter();
-        *(mousemode_t *)addr = sc->mode;
-        ((mousemode_t *)addr)->resolution = 
-	    MOUSE_RES_LOW - sc->mode.resolution;
-	switch (sc->mode.level) {
-	case PSM_LEVEL_BASE:
-	    ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
-	    ((mousemode_t *)addr)->packetsize = MOUSE_PS2_PACKETSIZE;
-	    break;
-	case PSM_LEVEL_STANDARD:
-	    ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
-	    ((mousemode_t *)addr)->packetsize = MOUSE_SYS_PACKETSIZE;
-	    ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
-	    ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
-	    break;
-	case PSM_LEVEL_NATIVE:
-	    /* FIXME: this isn't quite correct... XXX */
-	    ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
-	    break;
-	}
-	crit_exit();
-        break;
-
-    case OLD_MOUSE_SETMODE:
-    case MOUSE_SETMODE:
-	if (ap->a_cmd == OLD_MOUSE_SETMODE) {
-	    mode.rate = ((old_mousemode_t *)addr)->rate;
-	    /*
-	     * resolution  old I/F   new I/F
-	     * default        0         0
-	     * low            1        -2
-	     * medium low     2        -3
-	     * medium high    3        -4
-	     * high           4        -5
-	     */
-	    if (((old_mousemode_t *)addr)->resolution > 0)
-	        mode.resolution = -((old_mousemode_t *)addr)->resolution - 1;
-	    mode.accelfactor = ((old_mousemode_t *)addr)->accelfactor;
-	    mode.level = -1;
-	} else {
-	    mode = *(mousemode_t *)addr;
-	}
-
-	/* adjust and validate parameters. */
-	if (mode.rate > UCHAR_MAX)
-	    return EINVAL;
-        if (mode.rate == 0)
-            mode.rate = sc->dflt_mode.rate;
-	else if (mode.rate == -1)
-	    /* don't change the current setting */
-	    ;
-	else if (mode.rate < 0)
-	    return EINVAL;
-	if (mode.resolution >= UCHAR_MAX)
-	    return EINVAL;
-	if (mode.resolution >= 200)
-	    mode.resolution = MOUSE_RES_HIGH;
-	else if (mode.resolution >= 100)
-	    mode.resolution = MOUSE_RES_MEDIUMHIGH;
-	else if (mode.resolution >= 50)
-	    mode.resolution = MOUSE_RES_MEDIUMLOW;
-	else if (mode.resolution > 0)
-	    mode.resolution = MOUSE_RES_LOW;
-        if (mode.resolution == MOUSE_RES_DEFAULT)
-            mode.resolution = sc->dflt_mode.resolution;
-        else if (mode.resolution == -1)
-	    /* don't change the current setting */
-	    ;
-        else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
-            mode.resolution = MOUSE_RES_LOW - mode.resolution;
-	if (mode.level == -1)
-	    /* don't change the current setting */
-	    mode.level = sc->mode.level;
-	else if ((mode.level < PSM_LEVEL_MIN) || (mode.level > PSM_LEVEL_MAX))
-	    return EINVAL;
-        if (mode.accelfactor == -1)
-	    /* don't change the current setting */
-	    mode.accelfactor = sc->mode.accelfactor;
-        else if (mode.accelfactor < 0)
-	    return EINVAL;
-
-	/* don't allow anybody to poll the keyboard controller */
-	error = block_mouse_data(sc, &command_byte);
-	if (error)
-            return error;
-
-        /* set mouse parameters */
-	if (mode.rate > 0)
-	    mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
-	if (mode.resolution >= 0)
-	    mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
-	set_mouse_scaling(sc->kbdc, 1);
-	get_mouse_status(sc->kbdc, stat, 0, 3);
-
-        crit_enter();
-    	sc->mode.rate = mode.rate;
-    	sc->mode.resolution = mode.resolution;
-    	sc->mode.accelfactor = mode.accelfactor;
-    	sc->mode.level = mode.level;
-        crit_exit();
-
-	unblock_mouse_data(sc, command_byte);
-        break;
-
-    case MOUSE_GETLEVEL:
-	*(int *)addr = sc->mode.level;
-        break;
-
-    case MOUSE_SETLEVEL:
-	if ((*(int *)addr < PSM_LEVEL_MIN) || (*(int *)addr > PSM_LEVEL_MAX))
-	    return EINVAL;
-	sc->mode.level = *(int *)addr;
-        break;
-
-    case MOUSE_GETSTATUS:
-        crit_enter();
-	status = sc->status;
-	sc->status.flags = 0;
-	sc->status.obutton = sc->status.button;
-	sc->status.button = 0;
-	sc->status.dx = 0;
-	sc->status.dy = 0;
-	sc->status.dz = 0;
-        crit_exit();
-        *(mousestatus_t *)addr = status;
-        break;
+	case MOUSE_GETLEVEL:
+		*(int *)addr = sc->mode.level;
+		break;
+
+	case MOUSE_SETLEVEL:
+		if ((*(int *)addr < PSM_LEVEL_MIN) ||
+		    (*(int *)addr > PSM_LEVEL_MAX))
+			return (EINVAL);
+		sc->mode.level = *(int *)addr;
+		break;
+
+	case MOUSE_GETSTATUS:
+		crit_enter();
+		status = sc->status;
+		sc->status.flags = 0;
+		sc->status.obutton = sc->status.button;
+		sc->status.button = 0;
+		sc->status.dx = 0;
+		sc->status.dy = 0;
+		sc->status.dz = 0;
+		crit_exit();
+		*(mousestatus_t *)addr = status;
+		break;
 
 #if (defined(MOUSE_GETVARS))
-    case MOUSE_GETVARS:
-	var = (mousevar_t *)addr;
-	bzero(var, sizeof(*var));
-	crit_enter();
-        var->var[0] = MOUSE_VARS_PS2_SIG;
-        var->var[1] = sc->config;
-        var->var[2] = sc->flags;
-	crit_exit();
-        break;
+	case MOUSE_GETVARS:
+		var = (mousevar_t *)addr;
+		bzero(var, sizeof(*var));
+		crit_enter();
+		var->var[0] = MOUSE_VARS_PS2_SIG;
+		var->var[1] = sc->config;
+		var->var[2] = sc->flags;
+		crit_exit();
+		break;
 
-    case MOUSE_SETVARS:
-	return ENODEV;
+	case MOUSE_SETVARS:
+		return (ENODEV);
 #endif /* MOUSE_GETVARS */
 
-    case MOUSE_READSTATE:
-    case MOUSE_READDATA:
-	data = (mousedata_t *)addr;
-	if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
-	    return EINVAL;
-
-	error = block_mouse_data(sc, &command_byte);
-	if (error)
-            return error;
-        if ((data->len = get_mouse_status(sc->kbdc, data->buf, 
-		(ap->a_cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
-            error = EIO;
-	unblock_mouse_data(sc, command_byte);
-	break;
+	case MOUSE_READSTATE:
+	case MOUSE_READDATA:
+		data = (mousedata_t *)addr;
+		if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
+			return (EINVAL);
+
+		error = block_mouse_data(sc, &command_byte);
+		if (error)
+			return (error);
+		if ((data->len = get_mouse_status(sc->kbdc, data->buf,
+		    (ap->a_cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
+			error = EIO;
+		unblock_mouse_data(sc, command_byte);
+		break;
 
 #if (defined(MOUSE_SETRESOLUTION))
-    case MOUSE_SETRESOLUTION:
-	mode.resolution = *(int *)addr;
-	if (mode.resolution >= UCHAR_MAX)
-	    return EINVAL;
-	else if (mode.resolution >= 200)
-	    mode.resolution = MOUSE_RES_HIGH;
-	else if (mode.resolution >= 100)
-	    mode.resolution = MOUSE_RES_MEDIUMHIGH;
-	else if (mode.resolution >= 50)
-	    mode.resolution = MOUSE_RES_MEDIUMLOW;
-	else if (mode.resolution > 0)
-	    mode.resolution = MOUSE_RES_LOW;
-        if (mode.resolution == MOUSE_RES_DEFAULT)
-            mode.resolution = sc->dflt_mode.resolution;
-        else if (mode.resolution == -1)
-	    mode.resolution = sc->mode.resolution;
-        else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
-            mode.resolution = MOUSE_RES_LOW - mode.resolution;
-
-	error = block_mouse_data(sc, &command_byte);
-	if (error)
-            return error;
-        sc->mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
-	if (sc->mode.resolution != mode.resolution)
-	    error = EIO;
-	unblock_mouse_data(sc, command_byte);
-        break;
+	case MOUSE_SETRESOLUTION:
+		mode.resolution = *(int *)addr;
+		if (mode.resolution >= UCHAR_MAX)
+			return (EINVAL);
+		else if (mode.resolution >= 200)
+			mode.resolution = MOUSE_RES_HIGH;
+		else if (mode.resolution >= 100)
+			mode.resolution = MOUSE_RES_MEDIUMHIGH;
+		else if (mode.resolution >= 50)
+			mode.resolution = MOUSE_RES_MEDIUMLOW;
+		else if (mode.resolution > 0)
+			mode.resolution = MOUSE_RES_LOW;
+		if (mode.resolution == MOUSE_RES_DEFAULT)
+			mode.resolution = sc->dflt_mode.resolution;
+		else if (mode.resolution == -1)
+			mode.resolution = sc->mode.resolution;
+		else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
+			mode.resolution = MOUSE_RES_LOW - mode.resolution;
+
+		error = block_mouse_data(sc, &command_byte);
+		if (error)
+			return (error);
+		sc->mode.resolution =
+		    set_mouse_resolution(sc->kbdc, mode.resolution);
+		if (sc->mode.resolution != mode.resolution)
+			error = EIO;
+		unblock_mouse_data(sc, command_byte);
+		break;
 #endif /* MOUSE_SETRESOLUTION */
 
 #if (defined(MOUSE_SETRATE))
-    case MOUSE_SETRATE:
-	mode.rate = *(int *)addr;
-	if (mode.rate > UCHAR_MAX)
-	    return EINVAL;
-        if (mode.rate == 0)
-            mode.rate = sc->dflt_mode.rate;
-	else if (mode.rate < 0)
-	    mode.rate = sc->mode.rate;
-
-	error = block_mouse_data(sc, &command_byte);
-	if (error)
-            return error;
-        sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
-	if (sc->mode.rate != mode.rate)
-	    error = EIO;
-	unblock_mouse_data(sc, command_byte);
-        break;
+	case MOUSE_SETRATE:
+		mode.rate = *(int *)addr;
+		if (mode.rate > UCHAR_MAX)
+			return (EINVAL);
+		if (mode.rate == 0)
+			mode.rate = sc->dflt_mode.rate;
+		else if (mode.rate < 0)
+			mode.rate = sc->mode.rate;
+
+		error = block_mouse_data(sc, &command_byte);
+		if (error)
+			return (error);
+		sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
+		if (sc->mode.rate != mode.rate)
+			error = EIO;
+		unblock_mouse_data(sc, command_byte);
+		break;
 #endif /* MOUSE_SETRATE */
 
 #if (defined(MOUSE_SETSCALING))
-    case MOUSE_SETSCALING:
-	if ((*(int *)addr <= 0) || (*(int *)addr > 2))
-	    return EINVAL;
-
-	error = block_mouse_data(sc, &command_byte);
-	if (error)
-            return error;
-        if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
-	    error = EIO;
-	unblock_mouse_data(sc, command_byte);
-        break;
+	case MOUSE_SETSCALING:
+		if ((*(int *)addr <= 0) || (*(int *)addr > 2))
+			return (EINVAL);
+
+		error = block_mouse_data(sc, &command_byte);
+		if (error)
+			return (error);
+		if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
+			error = EIO;
+		unblock_mouse_data(sc, command_byte);
+		break;
 #endif /* MOUSE_SETSCALING */
 
 #if (defined(MOUSE_GETHWID))
-    case MOUSE_GETHWID:
-	error = block_mouse_data(sc, &command_byte);
-	if (error)
-            return error;
-        sc->hw.hwid &= ~0x00ff;
-        sc->hw.hwid |= get_aux_id(sc->kbdc);
-	*(int *)addr = sc->hw.hwid & 0x00ff;
-	unblock_mouse_data(sc, command_byte);
-        break;
+	case MOUSE_GETHWID:
+		error = block_mouse_data(sc, &command_byte);
+		if (error)
+			return (error);
+		sc->hw.hwid &= ~0x00ff;
+		sc->hw.hwid |= get_aux_id(sc->kbdc);
+		*(int *)addr = sc->hw.hwid & 0x00ff;
+		unblock_mouse_data(sc, command_byte);
+		break;
 #endif /* MOUSE_GETHWID */
 
-    default:
-	return ENOTTY;
-    }
+	default:
+		return (ENOTTY);
+	}
 
-    return error;
+	return (error);
 }
 
 static void
 psmtimeout(void *arg)
 {
-    struct psm_softc *sc;
-
-    sc = (struct psm_softc *)arg;
-    crit_enter();
-    if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
-	if (verbose >= 4)
-	    log(LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit);
-	psmintr(sc);
-	kbdc_lock(sc->kbdc, FALSE);
-    }
-    sc->watchdog = TRUE;
-    callout_reset(&sc->callout, hz, psmtimeout, (void *)(uintptr_t)sc);
-    crit_exit();
+	struct psm_softc *sc;
+
+	sc = (struct psm_softc *)arg;
+	crit_enter();
+	if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
+		VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit));
+		psmintr(sc);
+		kbdc_lock(sc->kbdc, FALSE);
+	}
+	sc->watchdog = TRUE;
+	crit_exit();
+	callout_reset(&sc->callout, hz, psmtimeout, (void *)(uintptr_t)sc);
 }
 
+/* Add all sysctls under the debug.psm and hw.psm nodes */
+SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
+SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
+
+SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0,
+    "Verbosity level");
+
+static int psmhz = 20;
+SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0,
+    "Frequency of the softcallout (in hz)");
+static int psmerrsecs = 2;
+SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0,
+    "Number of seconds during which packets will dropped after a sync error");
+static int psmerrusecs = 0;
+SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0,
+    "Microseconds to add to psmerrsecs");
+static int psmsecs = 0;
+SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0,
+    "Max number of seconds between soft interrupts");
+static int psmusecs = 500000;
+SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0,
+    "Microseconds to add to psmsecs");
+static int pkterrthresh = 2;
+SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
+    "Number of error packets allowed before reinitializing the mouse");
+
+SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RW, &tap_enabled, 0,
+    "Enable tap and drag gestures");
+static int tap_threshold = PSM_TAP_THRESHOLD;
+SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
+    "Button tap threshold");
+static int tap_timeout = PSM_TAP_TIMEOUT;
+SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
+    "Tap timeout for touchpads");
+
 static void
 psmintr(void *arg)
 {
-    /*
-     * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
-     * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
-     */
-    static int butmap[8] = {
-        0, 
-	MOUSE_BUTTON1DOWN, 
-	MOUSE_BUTTON3DOWN, 
-	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 
-	MOUSE_BUTTON2DOWN, 
-	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 
-	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
-        MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
-    };
-    static int butmap_versapad[8] = {
-	0, 
-	MOUSE_BUTTON3DOWN, 
-	0, 
-	MOUSE_BUTTON3DOWN, 
-	MOUSE_BUTTON1DOWN, 
-	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 
-	MOUSE_BUTTON1DOWN,
-	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
-    };
-    struct psm_softc *sc = arg;
-    mousestatus_t ms;
-    struct timeval tv;
-    int x, y, z;
-    int c;
-    int l;
-    int x0, y0;
-
-    /* read until there is nothing to read */
-    while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
-    
-        /* discard the byte if the device is not open */
-        if ((sc->state & PSM_OPEN) == 0)
-            continue;
-    
-	getmicrouptime(&tv);
-	if ((sc->inputbytes > 0) && timevalcmp(&tv, &sc->inputtimeout, >)) {
-	    log(LOG_DEBUG, "psmintr: delay too long; resetting byte count\n");
-	    sc->inputbytes = 0;
-	    sc->syncerrors = 0;
-	}
-	sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT/1000000;
-	sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT%1000000;
-	timevaladd(&sc->inputtimeout, &tv);
-
-        sc->ipacket[sc->inputbytes++] = c;
-        if (sc->inputbytes < sc->mode.packetsize) 
-	    continue;
+	struct psm_softc *sc = arg;
+	struct timeval now;
+	int c;
+	packetbuf_t *pb;
+
+
+	/* read until there is nothing to read */
+	while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
+		pb = &sc->pqueue[sc->pqueue_end];
+
+		/* discard the byte if the device is not open */
+		if ((sc->state & PSM_OPEN) == 0)
+			continue;
+
+		getmicrouptime(&now);
+		if ((pb->inputbytes > 0) &&
+		    timevalcmp(&now, &sc->inputtimeout, >)) {
+			VLOG(3, (LOG_DEBUG, "psmintr: delay too long; "
+			    "resetting byte count\n"));
+			pb->inputbytes = 0;
+			sc->syncerrors = 0;
+			sc->pkterrors = 0;
+		}
+		sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000;
+		sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000;
+		timevaladd(&sc->inputtimeout, &now);
 
-#if 0
-        log(LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n",
-	    sc->ipacket[0], sc->ipacket[1], sc->ipacket[2],
-	    sc->ipacket[3], sc->ipacket[4], sc->ipacket[5]);
-#endif
+		pb->ipacket[pb->inputbytes++] = c;
 
-	c = sc->ipacket[0];
-
-	if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
-            log(LOG_DEBUG, "psmintr: out of sync (%04x != %04x).\n", 
-		c & sc->mode.syncmask[0], sc->mode.syncmask[1]);
-	    ++sc->syncerrors;
-	    if (sc->syncerrors < sc->mode.packetsize) {
-		log(LOG_DEBUG, "psmintr: discard a byte (%d).\n", sc->syncerrors);
-		--sc->inputbytes;
-		bcopy(&sc->ipacket[1], &sc->ipacket[0], sc->inputbytes);
-	    } else if (sc->syncerrors == sc->mode.packetsize) {
-		log(LOG_DEBUG, "psmintr: re-enable the mouse.\n");
-		sc->inputbytes = 0;
-		disable_aux_dev(sc->kbdc);
-		enable_aux_dev(sc->kbdc);
-	    } else if (sc->syncerrors < PSM_SYNCERR_THRESHOLD1) {
-		log(LOG_DEBUG, "psmintr: discard a byte (%d).\n", sc->syncerrors);
-		--sc->inputbytes;
-		bcopy(&sc->ipacket[1], &sc->ipacket[0], sc->inputbytes);
-	    } else if (sc->syncerrors >= PSM_SYNCERR_THRESHOLD1) {
-		log(LOG_DEBUG, "psmintr: reset the mouse.\n");
-		reinitialize(sc, TRUE);
-	    }
-	    continue;
-	}
-
-	/* 
-	 * A kludge for Kensington device! 
-	 * The MSB of the horizontal count appears to be stored in 
-	 * a strange place.
+		if (sc->mode.level == PSM_LEVEL_NATIVE) {
+			VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0]));
+			sc->syncerrors = 0;
+			sc->pkterrors = 0;
+			goto next;
+		} else {
+			if (pb->inputbytes < sc->mode.packetsize)
+				continue;
+
+			VLOG(4, (LOG_DEBUG,
+			    "psmintr: %02x %02x %02x %02x %02x %02x\n",
+			    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
+			    pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
+		}
+
+		c = pb->ipacket[0];
+
+		if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
+			sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]);
+			sc->flags &= ~PSM_NEED_SYNCBITS;
+			VLOG(2, (LOG_DEBUG,
+			    "psmintr: Sync bytes now %04x,%04x\n",
+			    sc->mode.syncmask[0], sc->mode.syncmask[0]));
+		} else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
+			VLOG(3, (LOG_DEBUG, "psmintr: out of sync "
+			    "(%04x != %04x) %d cmds since last error.\n",
+			    c & sc->mode.syncmask[0], sc->mode.syncmask[1],
+			    sc->cmdcount - sc->lasterr));
+			sc->lasterr = sc->cmdcount;
+			/*
+			 * The sync byte test is a weak measure of packet
+			 * validity.  Conservatively discard any input yet
+			 * to be seen by userland when we detect a sync
+			 * error since there is a good chance some of
+			 * the queued packets have undetected errors.
+			 */
+			dropqueue(sc);
+			if (sc->syncerrors == 0)
+				sc->pkterrors++;
+			++sc->syncerrors;
+			sc->lastinputerr = now;
+			if (sc->syncerrors >= sc->mode.packetsize * 2 ||
+			    sc->pkterrors >= pkterrthresh) {
+				/*
+				 * If we've failed to find a single sync byte
+				 * in 2 packets worth of data, or we've seen
+				 * persistent packet errors during the
+				 * validation period, reinitialize the mouse
+				 * in hopes of returning it to the expected
+				 * mode.
+				 */
+				VLOG(3, (LOG_DEBUG,
+				    "psmintr: reset the mouse.\n"));
+				reinitialize(sc, TRUE);
+			} else if (sc->syncerrors == sc->mode.packetsize) {
+				/*
+				 * Try a soft reset after searching for a sync
+				 * byte through a packet length of bytes.
+				 */
+				VLOG(3, (LOG_DEBUG,
+				    "psmintr: re-enable the mouse.\n"));
+				pb->inputbytes = 0;
+				disable_aux_dev(sc->kbdc);
+				enable_aux_dev(sc->kbdc);
+			} else {
+				VLOG(3, (LOG_DEBUG,
+				    "psmintr: discard a byte (%d)\n",
+				    sc->syncerrors));
+				pb->inputbytes--;
+				bcopy(&pb->ipacket[1], &pb->ipacket[0],
+				    pb->inputbytes);
+			}
+			continue;
+		}
+
+		/*
+		 * We have what appears to be a valid packet.
+		 * Reset the error counters.
+		 */
+		sc->syncerrors = 0;
+
+		/*
+		 * Drop even good packets if they occur within a timeout
+		 * period of a sync error.  This allows the detection of
+		 * a change in the mouse's packet mode without exposing
+		 * erratic mouse behavior to the user.  Some KVMs forget
+		 * enhanced mouse modes during switch events.
+		 */
+		if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs,
+		    &now)) {
+			pb->inputbytes = 0;
+			continue;
+		}
+
+		/*
+		 * Now that we're out of the validation period, reset
+		 * the packet error count.
+		 */
+		sc->pkterrors = 0;
+
+		sc->cmdcount++;
+next:
+		if (++sc->pqueue_end >= PSM_PACKETQUEUE)
+			sc->pqueue_end = 0;
+		/*
+		 * If we've filled the queue then call the softintr ourselves,
+		 * otherwise schedule the interrupt for later.
+		 */
+		if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) ||
+		    (sc->pqueue_end == sc->pqueue_start)) {
+			if ((sc->state & PSM_SOFTARMED) != 0) {
+				sc->state &= ~PSM_SOFTARMED;
+				callout_stop(&sc->softcallout);
+			}
+			psmsoftintr(arg);
+		} else if ((sc->state & PSM_SOFTARMED) == 0) {
+			sc->state |= PSM_SOFTARMED;
+			callout_reset(&sc->softcallout,  psmhz < 1 ? 1 : (hz/psmhz),
+			      psmsoftintr, arg);
+		}
+	}
+}
+
+static void
+proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
+    int *x, int *y, int *z)
+{
+
+	/*
+	 * PS2++ protocl packet
+	 *
+	 *          b7 b6 b5 b4 b3 b2 b1 b0
+	 * byte 1:  *  1  p3 p2 1  *  *  *
+	 * byte 2:  c1 c2 p1 p0 d1 d0 1  0
+	 *
+	 * p3-p0: packet type
+	 * c1, c2: c1 & c2 == 1, if p2 == 0
+	 *         c1 & c2 == 0, if p2 == 1
+	 *
+	 * packet type: 0 (device type)
+	 * See comments in enable_mmanplus() below.
+	 *
+	 * packet type: 1 (wheel data)
+	 *
+	 *          b7 b6 b5 b4 b3 b2 b1 b0
+	 * byte 3:  h  *  B5 B4 s  d2 d1 d0
+	 *
+	 * h: 1, if horizontal roller data
+	 *    0, if vertical roller data
+	 * B4, B5: button 4 and 5
+	 * s: sign bit
+	 * d2-d0: roller data
+	 *
+	 * packet type: 2 (reserved)
 	 */
-	if (sc->hw.model == MOUSE_MODEL_THINK)
-	    sc->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
-
-        /* ignore the overflow bits... */
-        x = (c & MOUSE_PS2_XNEG) ?  sc->ipacket[1] - 256 : sc->ipacket[1];
-        y = (c & MOUSE_PS2_YNEG) ?  sc->ipacket[2] - 256 : sc->ipacket[2];
-	z = 0;
-        ms.obutton = sc->button;		  /* previous button state */
-        ms.button = butmap[c & MOUSE_PS2_BUTTONS];
-	/* `tapping' action */
-	if (sc->config & PSM_CONFIG_FORCETAP)
-	    ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
-
-	switch (sc->hw.model) {
-
-	case MOUSE_MODEL_EXPLORER:
-	    /*
-	     *          b7 b6 b5 b4 b3 b2 b1 b0
-	     * byte 1:  oy ox sy sx 1  M  R  L
-	     * byte 2:  x  x  x  x  x  x  x  x
-	     * byte 3:  y  y  y  y  y  y  y  y
-	     * byte 4:  *  *  S2 S1 s  d2 d1 d0
-	     *
-	     * L, M, R, S1, S2: left, middle, right and side buttons
-	     * s: wheel data sign bit
-	     * d2-d0: wheel data
-	     */
-	    z = (sc->ipacket[3] & MOUSE_EXPLORER_ZNEG)
-		? (sc->ipacket[3] & 0x0f) - 16 : (sc->ipacket[3] & 0x0f);
-	    ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN)
-		? MOUSE_BUTTON4DOWN : 0;
-	    ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN)
-		? MOUSE_BUTTON5DOWN : 0;
-	    break;
-
-	case MOUSE_MODEL_INTELLI:
-	case MOUSE_MODEL_NET:
-	    /* wheel data is in the fourth byte */
-	    z = (char)sc->ipacket[3];
-	    /* some mice may send 7 when there is no Z movement?! XXX */
-	    if ((z >= 7) || (z <= -7))
-		z = 0;
-	    /* some compatible mice have additional buttons */
-	    ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN)
-		? MOUSE_BUTTON4DOWN : 0;
-	    ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN)
-		? MOUSE_BUTTON5DOWN : 0;
-	    break;
-
-	case MOUSE_MODEL_MOUSEMANPLUS:
-	    /*
-	     * PS2++ protocl packet
-	     *
-	     *          b7 b6 b5 b4 b3 b2 b1 b0
-	     * byte 1:  *  1  p3 p2 1  *  *  *
-	     * byte 2:  c1 c2 p1 p0 d1 d0 1  0
-	     *
-	     * p3-p0: packet type
-	     * c1, c2: c1 & c2 == 1, if p2 == 0
-	     *         c1 & c2 == 0, if p2 == 1
-	     *
-	     * packet type: 0 (device type)
-	     * See comments in enable_mmanplus() below.
-	     * 
-	     * packet type: 1 (wheel data)
-	     *
-	     *          b7 b6 b5 b4 b3 b2 b1 b0
-	     * byte 3:  h  *  B5 B4 s  d2 d1 d0
-	     *
-	     * h: 1, if horizontal roller data
-	     *    0, if vertical roller data
-	     * B4, B5: button 4 and 5
-	     * s: sign bit
-	     * d2-d0: roller data
-	     *
-	     * packet type: 2 (reserved)
-	     */
-	    if (((c & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
-		    && (abs(x) > 191)
-		    && MOUSE_PS2PLUS_CHECKBITS(sc->ipacket)) {
-		/* the extended data packet encodes button and wheel events */
-		switch (MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket)) {
+	if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) &&
+	    (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) {
+		/*
+		 * the extended data packet encodes button
+		 * and wheel events
+		 */
+		switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) {
 		case 1:
-		    /* wheel data packet */
-		    x = y = 0;
-		    if (sc->ipacket[2] & 0x80) {
-			/* horizontal roller count - ignore it XXX*/
-		    } else {
-			/* vertical roller count */
-			z = (sc->ipacket[2] & MOUSE_PS2PLUS_ZNEG)
-			    ? (sc->ipacket[2] & 0x0f) - 16
-			    : (sc->ipacket[2] & 0x0f);
-		    }
-		    ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
-			? MOUSE_BUTTON4DOWN : 0;
-		    ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
-			? MOUSE_BUTTON5DOWN : 0;
-		    break;
+			/* wheel data packet */
+			*x = *y = 0;
+			if (pb->ipacket[2] & 0x80) {
+				/* XXX horizontal roller count - ignore it */
+				;
+			} else {
+				/* vertical roller count */
+				*z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ?
+				    (pb->ipacket[2] & 0x0f) - 16 :
+				    (pb->ipacket[2] & 0x0f);
+			}
+			ms->button |= (pb->ipacket[2] &
+			    MOUSE_PS2PLUS_BUTTON4DOWN) ?
+			    MOUSE_BUTTON4DOWN : 0;
+			ms->button |= (pb->ipacket[2] &
+			    MOUSE_PS2PLUS_BUTTON5DOWN) ?
+			    MOUSE_BUTTON5DOWN : 0;
+			break;
 		case 2:
-		    /* this packet type is reserved by Logitech... */
-		    /*
-		     * IBM ScrollPoint Mouse uses this packet type to
-		     * encode both vertical and horizontal scroll movement.
-		     */
-		    x = y = 0;
-		    /* horizontal count */
-		    if (sc->ipacket[2] & 0x0f)
-			z = (sc->ipacket[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
-		    /* vertical count */
-		    if (sc->ipacket[2] & 0xf0)
-			z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
-#if 0
-		    /* vertical count */
-		    z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG)
-			? ((sc->ipacket[2] >> 4) & 0x0f) - 16
-			: ((sc->ipacket[2] >> 4) & 0x0f);
-		    /* horizontal count */
-		    w = (sc->ipacket[2] & MOUSE_SPOINT_WNEG)
-			? (sc->ipacket[2] & 0x0f) - 16
-			: (sc->ipacket[2] & 0x0f);
-#endif
-		    break;
+			/*
+			 * this packet type is reserved by
+			 * Logitech...
+			 */
+			/*
+			 * IBM ScrollPoint Mouse uses this
+			 * packet type to encode both vertical
+			 * and horizontal scroll movement.
+			 */
+			*x = *y = 0;
+			/* horizontal count */
+			if (pb->ipacket[2] & 0x0f)
+				*z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ?
+				    -2 : 2;
+			/* vertical count */
+			if (pb->ipacket[2] & 0xf0)
+				*z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ?
+				    -1 : 1;
+			break;
 		case 0:
-		    /* device type packet - shouldn't happen */
-		    /* FALL THROUGH */
+			/* device type packet - shouldn't happen */
+			/* FALLTHROUGH */
 		default:
-		    x = y = 0;
-		    ms.button = ms.obutton;
-		    if (bootverbose)
-			log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
-				       "0x%02x 0x%02x 0x%02x\n",
-			    MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
-			    sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
-		    break;
+			*x = *y = 0;
+			ms->button = ms->obutton;
+			VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet "
+			    "type %d: 0x%02x 0x%02x 0x%02x\n",
+			    MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket),
+			    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]));
+			break;
 		}
-	    } else {
+	} else {
 		/* preserve button states */
-		ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
-	    }
-	    break;
-
-	case MOUSE_MODEL_GLIDEPOINT:
-	    /* `tapping' action */
-	    ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
-	    break;
-
-	case MOUSE_MODEL_NETSCROLL:
-	    /* three addtional bytes encode buttons and wheel events */
-	    ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN)
-		? MOUSE_BUTTON4DOWN : 0;
-	    ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON1DOWN)
-		? MOUSE_BUTTON5DOWN : 0;
-	    z = (sc->ipacket[3] & MOUSE_PS2_XNEG) 
-		? sc->ipacket[4] - 256 : sc->ipacket[4];
-	    break;
-
-	case MOUSE_MODEL_THINK:
-	    /* the fourth button state in the first byte */
-	    ms.button |= (c & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
-	    break;
-
-	case MOUSE_MODEL_VERSAPAD:
-	    /* VersaPad PS/2 absolute mode message format
-	     *
-	     * [packet1]     7   6   5   4   3   2   1   0(LSB)
-	     *  ipacket[0]:  1   1   0   A   1   L   T   R
-	     *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
-	     *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
-	     *  ipacket[3]:  1   1   1   A   1   L   T   R
-	     *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
-	     *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
-	     *
-	     * [note]
-	     *  R: right physical mouse button (1=on)
-	     *  T: touch pad virtual button (1=tapping)
-	     *  L: left physical mouse button (1=on)
-	     *  A: position data is valid (1=valid)
-	     *  H: horizontal data (12bit signed integer. H11 is sign bit.)
-	     *  V: vertical data (12bit signed integer. V11 is sign bit.)
-	     *  P: pressure data
-	     *
-	     * Tapping is mapped to MOUSE_BUTTON4.
-	     */
-	    ms.button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
-	    ms.button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
-	    x = y = 0;
-	    if (c & MOUSE_PS2VERSA_IN_USE) {
-		x0 = sc->ipacket[1] | (((sc->ipacket[4]) & 0x0f) << 8);
-		y0 = sc->ipacket[2] | (((sc->ipacket[4]) & 0xf0) << 4);
+		ms->button |= ms->obutton & MOUSE_EXTBUTTONS;
+	}
+}
+
+static int
+proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
+    int *x, int *y, int *z)
+{
+	static int touchpad_buttons;
+	static int guest_buttons;
+	int w, x0, y0;
+
+	/* TouchPad PS/2 absolute mode message format
+	 *
+	 *  Bits:        7   6   5   4   3   2   1   0 (LSB)
+	 *  ------------------------------------------------
+	 *  ipacket[0]:  1   0  W3  W2   0  W1   R   L
+	 *  ipacket[1]: Yb  Ya  Y9  Y8  Xb  Xa  X9  X8
+	 *  ipacket[2]: Z7  Z6  Z5  Z4  Z3  Z2  Z1  Z0
+	 *  ipacket[3]:  1   1  Yc  Xc   0  W0   D   U
+	 *  ipacket[4]: X7  X6  X5  X4  X3  X2  X1  X0
+	 *  ipacket[5]: Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
+	 *
+	 * Legend:
+	 *  L: left physical mouse button
+	 *  R: right physical mouse button
+	 *  D: down button
+	 *  U: up button
+	 *  W: "wrist" value
+	 *  X: x position
+	 *  Y: y position
+	 *  Z: pressure
+	 *
+	 * Absolute reportable limits:    0 - 6143.
+	 * Typical bezel limits:       1472 - 5472.
+	 * Typical edge marings:       1632 - 5312.
+	 *
+	 * w = 3 Passthrough Packet
+	 *
+	 * Byte 2,5,6 == Byte 1,2,3 of "Guest"
+	 */
+
+	if (!synaptics_support)
+		return (0);
+
+	/* Sanity check for out of sync packets. */
+	if ((pb->ipacket[0] & 0xc8) != 0x80 ||
+	    (pb->ipacket[3] & 0xc8) != 0xc0)
+		return (-1);
+
+	*x = *y = 0;
+
+	/*
+	 * Pressure value.
+	 * Interpretation:
+	 *   z = 0      No finger contact
+	 *   z = 10     Finger hovering near the pad
+	 *   z = 30     Very light finger contact
+	 *   z = 80     Normal finger contact
+	 *   z = 110    Very heavy finger contact
+	 *   z = 200    Finger lying flat on pad surface
+	 *   z = 255    Maximum reportable Z
+	 */
+	*z = pb->ipacket[2];
+
+	/*
+	 * Finger width value
+	 * Interpretation:
+	 *   w = 0      Two finger on the pad (capMultiFinger needed)
+	 *   w = 1      Three or more fingers (capMultiFinger needed)
+	 *   w = 2      Pen (instead of finger) (capPen needed)
+	 *   w = 3      Reserved (passthrough?)
+	 *   w = 4-7    Finger of normal width (capPalmDetect needed)
+	 *   w = 8-14   Very wide finger or palm (capPalmDetect needed)
+	 *   w = 15     Maximum reportable width (capPalmDetect needed)
+	 */
+	/* XXX Is checking capExtended enough? */
+	if (sc->synhw.capExtended)
+		w = ((pb->ipacket[0] & 0x30) >> 2) |
+		    ((pb->ipacket[0] & 0x04) >> 1) |
+		    ((pb->ipacket[3] & 0x04) >> 2);
+	else {
+		/* Assume a finger of regular width. */
+		w = 4;
+	}
+
+	/* Handle packets from the guest device */
+	/* XXX Documentation? */
+	if (w == 3 && sc->synhw.capPassthrough) {
+		*x = ((pb->ipacket[1] & 0x10) ?
+		    pb->ipacket[4] - 256 : pb->ipacket[4]);
+		*y = ((pb->ipacket[1] & 0x20) ?
+		    pb->ipacket[5] - 256 : pb->ipacket[5]);
+		*z = 0;
+
+		guest_buttons = 0;
+		if (pb->ipacket[1] & 0x01)
+			guest_buttons |= MOUSE_BUTTON1DOWN;
+		if (pb->ipacket[1] & 0x04)
+			guest_buttons |= MOUSE_BUTTON2DOWN;
+		if (pb->ipacket[1] & 0x02)
+			guest_buttons |= MOUSE_BUTTON3DOWN;
+
+		ms->button = touchpad_buttons | guest_buttons;
+		goto SYNAPTICS_END;
+	}
+
+	/* Button presses */
+	touchpad_buttons = 0;
+	if (pb->ipacket[0] & 0x01)
+		touchpad_buttons |= MOUSE_BUTTON1DOWN;
+	if (pb->ipacket[0] & 0x02)
+		touchpad_buttons |= MOUSE_BUTTON3DOWN;
+
+	if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
+		if ((pb->ipacket[3] & 0x01) && (pb->ipacket[0] & 0x01) == 0)
+			touchpad_buttons |= MOUSE_BUTTON4DOWN;
+		if ((pb->ipacket[3] & 0x02) && (pb->ipacket[0] & 0x02) == 0)
+			touchpad_buttons |= MOUSE_BUTTON5DOWN;
+	}
+
+	/*
+	 * In newer pads - bit 0x02 in the third byte of
+	 * the packet indicates that we have an extended
+	 * button press.
+	 */
+	/* XXX Documentation? */
+	if (pb->ipacket[3] & 0x02) {
+		/*
+		 * if directional_scrolls is not 1, we treat any of
+		 * the scrolling directions as middle-click.
+		 */
+		if (sc->syninfo.directional_scrolls) {
+			if (pb->ipacket[4] & 0x01)
+				touchpad_buttons |= MOUSE_BUTTON4DOWN;
+			if (pb->ipacket[5] & 0x01)
+				touchpad_buttons |= MOUSE_BUTTON5DOWN;
+			if (pb->ipacket[4] & 0x02)
+				touchpad_buttons |= MOUSE_BUTTON6DOWN;
+			if (pb->ipacket[5] & 0x02)
+				touchpad_buttons |= MOUSE_BUTTON7DOWN;
+		} else {
+			if ((pb->ipacket[4] & 0x0F) ||
+			    (pb->ipacket[5] & 0x0F))
+				touchpad_buttons |= MOUSE_BUTTON2DOWN;
+		}
+	}
+
+	ms->button = touchpad_buttons | guest_buttons;
+
+	/* Check pressure to detect a real wanted action on the
+	 * touchpad. */
+	if (*z >= sc->syninfo.min_pressure) {
+		synapticsaction_t *synaction;
+		int cursor, peer, window;
+		int dx, dy, dxp, dyp;
+		int max_width, max_pressure;
+		int margin_top, margin_right, margin_bottom, margin_left;
+		int na_top, na_right, na_bottom, na_left;
+		int window_min, window_max;
+		int multiplicator;
+		int weight_current, weight_previous, weight_len_squared;
+		int div_min, div_max, div_len;
+		int vscroll_hor_area, vscroll_ver_area;
+
+		int len, weight_prev_x, weight_prev_y;
+		int div_max_x, div_max_y, div_x, div_y;
+
+		/* Read sysctl. */
+		/* XXX Verify values? */
+		max_width = sc->syninfo.max_width;
+		max_pressure = sc->syninfo.max_pressure;
+		margin_top = sc->syninfo.margin_top;
+		margin_right = sc->syninfo.margin_right;
+		margin_bottom = sc->syninfo.margin_bottom;
+		margin_left = sc->syninfo.margin_left;
+		na_top = sc->syninfo.na_top;
+		na_right = sc->syninfo.na_right;
+		na_bottom = sc->syninfo.na_bottom;
+		na_left = sc->syninfo.na_left;
+		window_min = sc->syninfo.window_min;
+		window_max = sc->syninfo.window_max;
+		multiplicator = sc->syninfo.multiplicator;
+		weight_current = sc->syninfo.weight_current;
+		weight_previous = sc->syninfo.weight_previous;
+		weight_len_squared = sc->syninfo.weight_len_squared;
+		div_min = sc->syninfo.div_min;
+		div_max = sc->syninfo.div_max;
+		div_len = sc->syninfo.div_len;
+		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
+		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
+
+		/* Palm detection. */
+		if (!(
+		    (sc->synhw.capMultiFinger && (w == 0 || w == 1)) ||
+		    (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
+		    (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
+		    (sc->synhw.capPen && w == 2))) {
+			/*
+			 * We consider the packet irrelevant for the current
+			 * action when:
+			 *  - the width isn't comprised in:
+			 *    [4; max_width]
+			 *  - the pressure isn't comprised in:
+			 *    [min_pressure; max_pressure]
+			 *  - pen aren't supported but w is 2
+			 *
+			 *  Note that this doesn't terminate the current action.
+			 */
+			VLOG(2, (LOG_DEBUG,
+			    "synaptics: palm detected! (%d)\n", w));
+			goto SYNAPTICS_END;
+		}
+
+		/* Read current absolute position. */
+		x0 = ((pb->ipacket[3] & 0x10) << 8) |
+		    ((pb->ipacket[1] & 0x0f) << 8) |
+		    pb->ipacket[4];
+		y0 = ((pb->ipacket[3] & 0x20) << 7) |
+		    ((pb->ipacket[1] & 0xf0) << 4) |
+		    pb->ipacket[5];
+
+		synaction = &(sc->synaction);
+
+		/*
+		 * If the action is just beginning, init the structure and
+		 * compute tap timeout.
+		 */
+		if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
+			VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
+
+			/* Store the first point of this action. */
+			synaction->start_x = x0;
+			synaction->start_y = y0;
+			dx = dy = 0;
+
+			/* Initialize queue. */
+			synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
+			synaction->queue_len = 0;
+			synaction->window_min = window_min;
+
+			/* Reset average. */
+			synaction->avg_dx = 0;
+			synaction->avg_dy = 0;
+
+			/* Reset squelch. */
+			synaction->squelch_x = 0;
+			synaction->squelch_y = 0;
+
+			/* Reset pressure peak. */
+			sc->zmax = 0;
+
+			/* Reset fingers count. */
+			synaction->fingers_nb = 0;
+
+			/* Reset virtual scrolling state. */
+			synaction->in_vscroll = 0;
+
+			/* Compute tap timeout. */
+			sc->taptimeout.tv_sec  = tap_timeout / 1000000;
+			sc->taptimeout.tv_usec = tap_timeout % 1000000;
+			timevaladd(&sc->taptimeout, &sc->lastsoftintr);
+
+			sc->flags |= PSM_FLAGS_FINGERDOWN;
+		} else {
+			/* Calculate the current delta. */
+			cursor = synaction->queue_cursor;
+			dx = x0 - synaction->queue[cursor].x;
+			dy = y0 - synaction->queue[cursor].y;
+		}
+
+		/* If in tap-hold, add the recorded button. */
+		if (synaction->in_taphold)
+			ms->button |= synaction->tap_button;
+
+		/*
+		 * From now on, we can use the SYNAPTICS_END label to skip
+		 * the current packet.
+		 */
+
+		/*
+		 * Limit the coordinates to the specified margins because
+		 * this area isn't very reliable.
+		 */
+		if (x0 <= margin_left)
+			x0 = margin_left;
+		else if (x0 >= 6143 - margin_right)
+			x0 = 6143 - margin_right;
+		if (y0 <= margin_bottom)
+			y0 = margin_bottom;
+		else if (y0 >= 6143 - margin_top)
+			y0 = 6143 - margin_top;
+
+		VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
+		    x0, y0, *z, w));
+
+		/* Queue this new packet. */
+		cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
+		synaction->queue[cursor].x = x0;
+		synaction->queue[cursor].y = y0;
+		synaction->queue_cursor = cursor;
+		if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
+			synaction->queue_len++;
+		VLOG(5, (LOG_DEBUG,
+		    "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
+		    cursor, x0, y0, dx, dy));
+
+		/*
+		 * For tap, we keep the maximum number of fingers and the
+		 * pressure peak. Also with multiple fingers, we increase
+		 * the minimum window.
+		 */
+		switch (w) {
+		case 1: /* Three or more fingers. */
+			synaction->fingers_nb = imax(3, synaction->fingers_nb);
+			synaction->window_min = window_max;
+			break;
+		case 0: /* Two fingers. */
+			synaction->fingers_nb = imax(2, synaction->fingers_nb);
+			synaction->window_min = window_max;
+			break;
+		default: /* One finger or undetectable. */
+			synaction->fingers_nb = imax(1, synaction->fingers_nb);
+		}
+		sc->zmax = imax(*z, sc->zmax);
+
+		/* Do we have enough packets to consider this a movement? */
+		if (synaction->queue_len < synaction->window_min)
+			goto SYNAPTICS_END;
+
+		/* Is a scrolling action occuring? */
+		if (!synaction->in_taphold && !synaction->in_vscroll) {
+			/*
+			 * A scrolling action must not conflict with a tap
+			 * action. Here are the conditions to consider a
+			 * scrolling action:
+			 *  - the action in a configurable area
+			 *  - one of the following:
+			 *     . the distance between the last packet and the
+			 *       first should be above a configurable minimum
+			 *     . tap timed out
+			 */
+			dxp = abs(synaction->queue[synaction->queue_cursor].x -
+			    synaction->start_x);
+			dyp = abs(synaction->queue[synaction->queue_cursor].y -
+			    synaction->start_y);
+
+			if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
+			    dxp >= sc->syninfo.vscroll_min_delta ||
+			    dyp >= sc->syninfo.vscroll_min_delta) {
+				/* Check for horizontal scrolling. */
+				if ((vscroll_hor_area > 0 &&
+				    synaction->start_y <= vscroll_hor_area) ||
+				    (vscroll_hor_area < 0 &&
+				     synaction->start_y >=
+				     6143 + vscroll_hor_area))
+					synaction->in_vscroll += 2;
+
+				/* Check for vertical scrolling. */
+				if ((vscroll_ver_area > 0 &&
+				    synaction->start_x <= vscroll_ver_area) ||
+				    (vscroll_ver_area < 0 &&
+				     synaction->start_x >=
+				     6143 + vscroll_ver_area))
+					synaction->in_vscroll += 1;
+
+				/* Avoid conflicts if area overlaps. */
+				if (synaction->in_vscroll == 3)
+					synaction->in_vscroll =
+					    (dxp > dyp) ? 2 : 1;
+			}
+			VLOG(5, (LOG_DEBUG,
+			    "synaptics: virtual scrolling: %s "
+			    "(direction=%d, dxp=%d, dyp=%d)\n",
+			    synaction->in_vscroll ? "YES" : "NO",
+			    synaction->in_vscroll, dxp, dyp));
+		}
+
+		weight_prev_x = weight_prev_y = weight_previous;
+		div_max_x = div_max_y = div_max;
+
+		if (synaction->in_vscroll) {
+			/* Dividers are different with virtual scrolling. */
+			div_min = sc->syninfo.vscroll_div_min;
+			div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
+		} else {
+			/*
+			 * There's a lot of noise in coordinates when
+			 * the finger is on the touchpad's borders. When
+			 * using this area, we apply a special weight and
+			 * div.
+			 */
+			if (x0 <= na_left || x0 >= 6143 - na_right) {
+				weight_prev_x = sc->syninfo.weight_previous_na;
+				div_max_x = sc->syninfo.div_max_na;
+			}
+
+			if (y0 <= na_bottom || y0 >= 6143 - na_top) {
+				weight_prev_y = sc->syninfo.weight_previous_na;
+				div_max_y = sc->syninfo.div_max_na;
+			}
+		}
+
+		/*
+		 * Calculate weights for the average operands and
+		 * the divisor. Both depend on the distance between
+		 * the current packet and a previous one (based on the
+		 * window width).
+		 */
+		window = imin(synaction->queue_len, window_max);
+		peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
+		dxp = abs(x0 - synaction->queue[peer].x) + 1;
+		dyp = abs(y0 - synaction->queue[peer].y) + 1;
+		len = (dxp * dxp) + (dyp * dyp);
+		weight_prev_x = imin(weight_prev_x,
+		    weight_len_squared * weight_prev_x / len);
+		weight_prev_y = imin(weight_prev_y,
+		    weight_len_squared * weight_prev_y / len);
+
+		len = (dxp + dyp) / 2;
+		div_x = div_len * div_max_x / len;
+		div_x = imin(div_max_x, div_x);
+		div_x = imax(div_min, div_x);
+		div_y = div_len * div_max_y / len;
+		div_y = imin(div_max_y, div_y);
+		div_y = imax(div_min, div_y);
+
+		VLOG(3, (LOG_DEBUG,
+		    "synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
+		    peer, len, weight_prev_x, weight_prev_y, div_x, div_y));
+
+		/* Compute averages. */
+		synaction->avg_dx =
+		    (weight_current * dx * multiplicator +
+		     weight_prev_x * synaction->avg_dx) /
+		    (weight_current + weight_prev_x);
+
+		synaction->avg_dy =
+		    (weight_current * dy * multiplicator +
+		     weight_prev_y * synaction->avg_dy) /
+		    (weight_current + weight_prev_y);
+
+		VLOG(5, (LOG_DEBUG,
+		    "synaptics: avg_dx~=%d, avg_dy~=%d\n",
+		    synaction->avg_dx / multiplicator,
+		    synaction->avg_dy / multiplicator));
+
+		/* Use these averages to calculate x & y. */
+		synaction->squelch_x += synaction->avg_dx;
+		*x = synaction->squelch_x / (div_x * multiplicator);
+		synaction->squelch_x = synaction->squelch_x %
+		    (div_x * multiplicator);
+
+		synaction->squelch_y += synaction->avg_dy;
+		*y = synaction->squelch_y / (div_y * multiplicator);
+		synaction->squelch_y = synaction->squelch_y %
+		    (div_y * multiplicator);
+
+		if (synaction->in_vscroll) {
+			switch(synaction->in_vscroll) {
+			case 1: /* Vertical scrolling. */
+				if (*y != 0)
+					ms->button |= (*y > 0) ?
+					    MOUSE_BUTTON4DOWN :
+					    MOUSE_BUTTON5DOWN;
+				break;
+			case 2: /* Horizontal scrolling. */
+				if (*x != 0)
+					ms->button |= (*x > 0) ?
+					    MOUSE_BUTTON7DOWN :
+					    MOUSE_BUTTON6DOWN;
+				break;
+			}
+
+			/* The pointer is not moved. */
+			*x = *y = 0;
+		} else {
+			VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n",
+			    dx, dy, *x, *y));
+		}
+	} else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
+		/*
+		 * An action is currently taking place but the pressure
+		 * dropped under the minimum, putting an end to it.
+		 */
+		synapticsaction_t *synaction;
+		int taphold_timeout, dx, dy, tap_max_delta;
+
+		synaction = &(sc->synaction);
+		dx = abs(synaction->queue[synaction->queue_cursor].x -
+		    synaction->start_x);
+		dy = abs(synaction->queue[synaction->queue_cursor].y -
+		    synaction->start_y);
+
+		/* Max delta is disabled for multi-fingers tap. */
+		if (synaction->fingers_nb > 1)
+			tap_max_delta = imax(dx, dy);
+		else
+			tap_max_delta = sc->syninfo.tap_max_delta;
+
+		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
+
+		/* Check for tap. */
+		VLOG(3, (LOG_DEBUG,
+		    "synaptics: zmax=%d, dx=%d, dy=%d, "
+		    "delta=%d, fingers=%d, queue=%d\n",
+		    sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb,
+		    synaction->queue_len));
+		if (!synaction->in_vscroll && sc->zmax >= tap_threshold &&
+		    timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) &&
+		    dx <= tap_max_delta && dy <= tap_max_delta &&
+		    synaction->queue_len >= sc->syninfo.tap_min_queue) {
+			/*
+			 * We have a tap if:
+			 *   - the maximum pressure went over tap_threshold
+			 *   - the action ended before tap_timeout
+			 *
+			 * To handle tap-hold, we must delay any button push to
+			 * the next action.
+			 */
+			if (synaction->in_taphold) {
+				/*
+				 * This is the second and last tap of a
+				 * double tap action, not a tap-hold.
+				 */
+				synaction->in_taphold = 0;
+
+				/*
+				 * For double-tap to work:
+				 *   - no button press is emitted (to
+				 *     simulate a button release)
+				 *   - PSM_FLAGS_FINGERDOWN is set to
+				 *     force the next packet to emit a
+				 *     button press)
+				 */
+				VLOG(2, (LOG_DEBUG,
+				    "synaptics: button RELEASE: %d\n",
+				    synaction->tap_button));
+				sc->flags |= PSM_FLAGS_FINGERDOWN;
+			} else {
+				/*
+				 * This is the first tap: we set the
+				 * tap-hold state and notify the button
+				 * down event.
+				 */
+				synaction->in_taphold = 1;
+				taphold_timeout = sc->syninfo.taphold_timeout;
+				sc->taptimeout.tv_sec  = taphold_timeout /
+				    1000000;
+				sc->taptimeout.tv_usec = taphold_timeout %
+				    1000000;
+				timevaladd(&sc->taptimeout, &sc->lastsoftintr);
+
+				switch (synaction->fingers_nb) {
+				case 3:
+					synaction->tap_button =
+					    MOUSE_BUTTON2DOWN;
+					break;
+				case 2:
+					synaction->tap_button =
+					    MOUSE_BUTTON3DOWN;
+					break;
+				default:
+					synaction->tap_button =
+					    MOUSE_BUTTON1DOWN;
+				}
+				VLOG(2, (LOG_DEBUG,
+				    "synaptics: button PRESS: %d\n",
+				    synaction->tap_button));
+				ms->button |= synaction->tap_button;
+			}
+		} else {
+			/*
+			 * Not enough pressure or timeout: reset
+			 * tap-hold state.
+			 */
+			if (synaction->in_taphold) {
+				VLOG(2, (LOG_DEBUG,
+				    "synaptics: button RELEASE: %d\n",
+				    synaction->tap_button));
+				synaction->in_taphold = 0;
+			} else {
+				VLOG(2, (LOG_DEBUG,
+				    "synaptics: not a tap-hold\n"));
+			}
+		}
+	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
+	    sc->synaction.in_taphold) {
+		/*
+		 * For a tap-hold to work, the button must remain down at
+		 * least until timeout (where the in_taphold flags will be
+		 * cleared) or during the next action.
+		 */
+		if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
+			ms->button |= sc->synaction.tap_button;
+		} else {
+			VLOG(2, (LOG_DEBUG,
+			    "synaptics: button RELEASE: %d\n",
+			    sc->synaction.tap_button));
+			sc->synaction.in_taphold = 0;
+		}
+	}
+
+SYNAPTICS_END:
+	/*
+	 * Use the extra buttons as a scrollwheel
+	 *
+	 * XXX X.Org uses the Z axis for vertical wheel only,
+	 * whereas moused(8) understands special values to differ
+	 * vertical and horizontal wheels.
+	 *
+	 * xf86-input-mouse needs therefore a small patch to
+	 * understand these special values. Without it, the
+	 * horizontal wheel acts as a vertical wheel in X.Org.
+	 *
+	 * That's why the horizontal wheel is disabled by
+	 * default for now.
+	 */
+	if (ms->button & MOUSE_BUTTON4DOWN) {
+		*z = -1;
+		ms->button &= ~MOUSE_BUTTON4DOWN;
+	} else if (ms->button & MOUSE_BUTTON5DOWN) {
+		*z = 1;
+		ms->button &= ~MOUSE_BUTTON5DOWN;
+	} else if (ms->button & MOUSE_BUTTON6DOWN) {
+		*z = -2;
+		ms->button &= ~MOUSE_BUTTON6DOWN;
+	} else if (ms->button & MOUSE_BUTTON7DOWN) {
+		*z = 2;
+		ms->button &= ~MOUSE_BUTTON7DOWN;
+	} else
+		*z = 0;
+
+	return (0);
+}
+
+static void
+proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
+    int *x, int *y, int *z)
+{
+	static int butmap_versapad[8] = {
+		0,
+		MOUSE_BUTTON3DOWN,
+		0,
+		MOUSE_BUTTON3DOWN,
+		MOUSE_BUTTON1DOWN,
+		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+		MOUSE_BUTTON1DOWN,
+		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
+	};
+	int c, x0, y0;
+
+	/* VersaPad PS/2 absolute mode message format
+	 *
+	 * [packet1]     7   6   5   4   3   2   1   0(LSB)
+	 *  ipacket[0]:  1   1   0   A   1   L   T   R
+	 *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
+	 *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
+	 *  ipacket[3]:  1   1   1   A   1   L   T   R
+	 *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
+	 *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
+	 *
+	 * [note]
+	 *  R: right physical mouse button (1=on)
+	 *  T: touch pad virtual button (1=tapping)
+	 *  L: left physical mouse button (1=on)
+	 *  A: position data is valid (1=valid)
+	 *  H: horizontal data (12bit signed integer. H11 is sign bit.)
+	 *  V: vertical data (12bit signed integer. V11 is sign bit.)
+	 *  P: pressure data
+	 *
+	 * Tapping is mapped to MOUSE_BUTTON4.
+	 */
+	c = pb->ipacket[0];
+	*x = *y = 0;
+	ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
+	ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
+	if (c & MOUSE_PS2VERSA_IN_USE) {
+		x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8);
+		y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4);
 		if (x0 & 0x800)
-		    x0 -= 0x1000;
+			x0 -= 0x1000;
 		if (y0 & 0x800)
-		    y0 -= 0x1000;
+			y0 -= 0x1000;
 		if (sc->flags & PSM_FLAGS_FINGERDOWN) {
-		    x = sc->xold - x0;
-		    y = y0 - sc->yold;
-		    if (x < 0)	/* XXX */
-			x++;
-		    else if (x)
-			x--;
-		    if (y < 0)
-			y++;
-		    else if (y)
-			y--;
-		} else {
-		    sc->flags |= PSM_FLAGS_FINGERDOWN;
-		}
+			*x = sc->xold - x0;
+			*y = y0 - sc->yold;
+			if (*x < 0)	/* XXX */
+				++*x;
+			else if (*x)
+				--*x;
+			if (*y < 0)
+				++*y;
+			else if (*y)
+				--*y;
+		} else
+			sc->flags |= PSM_FLAGS_FINGERDOWN;
 		sc->xold = x0;
 		sc->yold = y0;
-	    } else {
+	} else
 		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
-	    }
-	    c = ((x < 0) ? MOUSE_PS2_XNEG : 0)
-		| ((y < 0) ? MOUSE_PS2_YNEG : 0);
-	    break;
-
-	case MOUSE_MODEL_4D:
-	    /*
-	     *          b7 b6 b5 b4 b3 b2 b1 b0
-	     * byte 1:  s2 d2 s1 d1 1  M  R  L
-	     * byte 2:  sx x  x  x  x  x  x  x
-	     * byte 3:  sy y  y  y  y  y  y  y
-	     *
-	     * s1: wheel 1 direction
-	     * d1: wheel 1 data
-	     * s2: wheel 2 direction
-	     * d2: wheel 2 data
-	     */
-	    x = (sc->ipacket[1] & 0x80) ? sc->ipacket[1] - 256 : sc->ipacket[1];
-	    y = (sc->ipacket[2] & 0x80) ? sc->ipacket[2] - 256 : sc->ipacket[2];
-	    switch (c & MOUSE_4D_WHEELBITS) {
-	    case 0x10:
-		z = 1;
-		break;
-	    case 0x30:
-		z = -1;
-		break;
-	    case 0x40:	/* 2nd wheel turning right XXX */
-		z = 2;
-		break;
-	    case 0xc0:	/* 2nd wheel turning left XXX */
-		z = -2;
-		break;
-	    }
-	    break;
+}
+
+static void
+psmsoftintr(void *arg)
+{
+	/*
+	 * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
+	 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
+	 */
+	static int butmap[8] = {
+		0,
+		MOUSE_BUTTON1DOWN,
+		MOUSE_BUTTON3DOWN,
+		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+		MOUSE_BUTTON2DOWN,
+		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
+		MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
+		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
+	};
+	struct psm_softc *sc = arg;
+	mousestatus_t ms;
+	packetbuf_t *pb;
+	int x, y, z, c, l;
+
+	getmicrouptime(&sc->lastsoftintr);
+
+	crit_enter();
+
+	do {
+		pb = &sc->pqueue[sc->pqueue_start];
+
+		if (sc->mode.level == PSM_LEVEL_NATIVE)
+			goto next_native;
 
-	case MOUSE_MODEL_4DPLUS:
-	    if ((x < 16 - 256) && (y < 16 - 256)) {
+		c = pb->ipacket[0];
 		/*
-		 *          b7 b6 b5 b4 b3 b2 b1 b0
-		 * byte 1:  0  0  1  1  1  M  R  L
-		 * byte 2:  0  0  0  0  1  0  0  0
-		 * byte 3:  0  0  0  0  S  s  d1 d0
-		 *
-		 * L, M, R, S: left, middle, right and side buttons
-		 * s: wheel data sign bit
-		 * d1-d0: wheel data
+		 * A kludge for Kensington device!
+		 * The MSB of the horizontal count appears to be stored in
+		 * a strange place.
 		 */
-		x = y = 0;
-		if (sc->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
-		    ms.button |= MOUSE_BUTTON4DOWN;
-		z = (sc->ipacket[2] & MOUSE_4DPLUS_ZNEG)
-			? ((sc->ipacket[2] & 0x07) - 8)
-			: (sc->ipacket[2] & 0x07) ;
-	    } else {
-		/* preserve previous button states */
-		ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
-	    }
-	    break;
-
-	case MOUSE_MODEL_GENERIC:
-	default:
-	    break;
-	}
-
-        /* scale values */
-        if (sc->mode.accelfactor >= 1) {
-            if (x != 0) {
-                x = x * x / sc->mode.accelfactor;
-                if (x == 0)
-                    x = 1;
-                if (c & MOUSE_PS2_XNEG)
-                    x = -x;
-            }
-            if (y != 0) {
-                y = y * y / sc->mode.accelfactor;
-                if (y == 0)
-                    y = 1;
-                if (c & MOUSE_PS2_YNEG)
-                    y = -y;
-            }
-        }
-
-        ms.dx = x;
-        ms.dy = y;
-        ms.dz = z;
-        ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) 
-	    | (ms.obutton ^ ms.button);
+		if (sc->hw.model == MOUSE_MODEL_THINK)
+			pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
+
+		/* ignore the overflow bits... */
+		x = (c & MOUSE_PS2_XNEG) ?
+		    pb->ipacket[1] - 256 : pb->ipacket[1];
+		y = (c & MOUSE_PS2_YNEG) ?
+		    pb->ipacket[2] - 256 : pb->ipacket[2];
+		z = 0;
+		ms.obutton = sc->button;	  /* previous button state */
+		ms.button = butmap[c & MOUSE_PS2_BUTTONS];
+		/* `tapping' action */
+		if (sc->config & PSM_CONFIG_FORCETAP)
+			ms.button |= ((c & MOUSE_PS2_TAP)) ?
+			    0 : MOUSE_BUTTON4DOWN;
+
+		switch (sc->hw.model) {
+
+		case MOUSE_MODEL_EXPLORER:
+			/*
+			 *          b7 b6 b5 b4 b3 b2 b1 b0
+			 * byte 1:  oy ox sy sx 1  M  R  L
+			 * byte 2:  x  x  x  x  x  x  x  x
+			 * byte 3:  y  y  y  y  y  y  y  y
+			 * byte 4:  *  *  S2 S1 s  d2 d1 d0
+			 *
+			 * L, M, R, S1, S2: left, middle, right and side buttons
+			 * s: wheel data sign bit
+			 * d2-d0: wheel data
+			 */
+			z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ?
+			    (pb->ipacket[3] & 0x0f) - 16 :
+			    (pb->ipacket[3] & 0x0f);
+			ms.button |=
+			    (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ?
+			    MOUSE_BUTTON4DOWN : 0;
+			ms.button |=
+			    (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ?
+			    MOUSE_BUTTON5DOWN : 0;
+			break;
+
+		case MOUSE_MODEL_INTELLI:
+		case MOUSE_MODEL_NET:
+			/* wheel data is in the fourth byte */
+			z = (char)pb->ipacket[3];
+			/*
+			 * XXX some mice may send 7 when there is no Z movement?			 */
+			if ((z >= 7) || (z <= -7))
+				z = 0;
+			/* some compatible mice have additional buttons */
+			ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ?
+			    MOUSE_BUTTON4DOWN : 0;
+			ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ?
+			    MOUSE_BUTTON5DOWN : 0;
+			break;
+
+		case MOUSE_MODEL_MOUSEMANPLUS:
+			proc_mmanplus(sc, pb, &ms, &x, &y, &z);
+			break;
+
+		case MOUSE_MODEL_GLIDEPOINT:
+			/* `tapping' action */
+			ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 :
+			    MOUSE_BUTTON4DOWN;
+			break;
+
+		case MOUSE_MODEL_NETSCROLL:
+			/*
+			 * three addtional bytes encode buttons and
+			 * wheel events
+			 */
+			ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ?
+			    MOUSE_BUTTON4DOWN : 0;
+			ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ?
+			    MOUSE_BUTTON5DOWN : 0;
+			z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ?
+			    pb->ipacket[4] - 256 : pb->ipacket[4];
+			break;
+
+		case MOUSE_MODEL_THINK:
+			/* the fourth button state in the first byte */
+			ms.button |= (c & MOUSE_PS2_TAP) ?
+			    MOUSE_BUTTON4DOWN : 0;
+			break;
+
+		case MOUSE_MODEL_VERSAPAD:
+			proc_versapad(sc, pb, &ms, &x, &y, &z);
+			c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
+			    ((y < 0) ? MOUSE_PS2_YNEG : 0);
+			break;
+
+		case MOUSE_MODEL_4D:
+			/*
+			 *          b7 b6 b5 b4 b3 b2 b1 b0
+			 * byte 1:  s2 d2 s1 d1 1  M  R  L
+			 * byte 2:  sx x  x  x  x  x  x  x
+			 * byte 3:  sy y  y  y  y  y  y  y
+			 *
+			 * s1: wheel 1 direction
+			 * d1: wheel 1 data
+			 * s2: wheel 2 direction
+			 * d2: wheel 2 data
+			 */
+			x = (pb->ipacket[1] & 0x80) ?
+			    pb->ipacket[1] - 256 : pb->ipacket[1];
+			y = (pb->ipacket[2] & 0x80) ?
+			    pb->ipacket[2] - 256 : pb->ipacket[2];
+			switch (c & MOUSE_4D_WHEELBITS) {
+			case 0x10:
+				z = 1;
+				break;
+			case 0x30:
+				z = -1;
+				break;
+			case 0x40:	/* XXX 2nd wheel turning right */
+				z = 2;
+				break;
+			case 0xc0:	/* XXX 2nd wheel turning left */
+				z = -2;
+				break;
+			}
+			break;
+
+		case MOUSE_MODEL_4DPLUS:
+			if ((x < 16 - 256) && (y < 16 - 256)) {
+				/*
+				 *          b7 b6 b5 b4 b3 b2 b1 b0
+				 * byte 1:  0  0  1  1  1  M  R  L
+				 * byte 2:  0  0  0  0  1  0  0  0
+				 * byte 3:  0  0  0  0  S  s  d1 d0
+				 *
+				 * L, M, R, S: left, middle, right,
+				 *             and side buttons
+				 * s: wheel data sign bit
+				 * d1-d0: wheel data
+				 */
+				x = y = 0;
+				if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
+					ms.button |= MOUSE_BUTTON4DOWN;
+				z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ?
+				    ((pb->ipacket[2] & 0x07) - 8) :
+				    (pb->ipacket[2] & 0x07) ;
+			} else {
+				/* preserve previous button states */
+				ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
+			}
+			break;
 
-	if (sc->mode.level < PSM_LEVEL_NATIVE)
-	    sc->inputbytes = tame_mouse(sc, &ms, sc->ipacket);
+		case MOUSE_MODEL_SYNAPTICS:
+			if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0)
+				goto next;
+			break;
+
+		case MOUSE_MODEL_GENERIC:
+		default:
+			break;
+		}
+
+	/* scale values */
+	if (sc->mode.accelfactor >= 1) {
+		if (x != 0) {
+			x = x * x / sc->mode.accelfactor;
+			if (x == 0)
+				x = 1;
+			if (c & MOUSE_PS2_XNEG)
+				x = -x;
+		}
+		if (y != 0) {
+			y = y * y / sc->mode.accelfactor;
+			if (y == 0)
+				y = 1;
+			if (c & MOUSE_PS2_YNEG)
+				y = -y;
+		}
+	}
+
+	ms.dx = x;
+	ms.dy = y;
+	ms.dz = z;
+	ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) |
+	    (ms.obutton ^ ms.button);
+
+	pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket);
 
-        sc->status.flags |= ms.flags;
-        sc->status.dx += ms.dx;
-        sc->status.dy += ms.dy;
-        sc->status.dz += ms.dz;
-        sc->status.button = ms.button;
-        sc->button = ms.button;
+	sc->status.flags |= ms.flags;
+	sc->status.dx += ms.dx;
+	sc->status.dy += ms.dy;
+	sc->status.dz += ms.dz;
+	sc->status.button = ms.button;
+	sc->button = ms.button;
 
+next_native:
 	sc->watchdog = FALSE;
 
-        /* queue data */
-        if (sc->queue.count + sc->inputbytes < sizeof(sc->queue.buf)) {
-	    l = min(sc->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail);
-	    bcopy(&sc->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
-	    if (sc->inputbytes > l)
-	        bcopy(&sc->ipacket[l], &sc->queue.buf[0], sc->inputbytes - l);
-            sc->queue.tail = 
-		(sc->queue.tail + sc->inputbytes) % sizeof(sc->queue.buf);
-            sc->queue.count += sc->inputbytes;
-	}
-        sc->inputbytes = 0;
-
-        if (sc->state & PSM_ASLP) {
-            sc->state &= ~PSM_ASLP;
-            wakeup((caddr_t) sc);
-    	}
+	/* queue data */
+	if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) {
+		l = imin(pb->inputbytes,
+		    sizeof(sc->queue.buf) - sc->queue.tail);
+		bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
+		if (pb->inputbytes > l)
+			bcopy(&pb->ipacket[l], &sc->queue.buf[0],
+			    pb->inputbytes - l);
+		sc->queue.tail = (sc->queue.tail + pb->inputbytes) %
+		    sizeof(sc->queue.buf);
+		sc->queue.count += pb->inputbytes;
+	}
+	pb->inputbytes = 0;
+
+next:
+	if (++sc->pqueue_start >= PSM_PACKETQUEUE)
+		sc->pqueue_start = 0;
+	} while (sc->pqueue_start != sc->pqueue_end);
+
+	if (sc->state & PSM_ASLP) {
+		sc->state &= ~PSM_ASLP;
+		wakeup(sc);
+	}
 	KNOTE(&sc->rkq.ki_note, 0);
-    }
+
+	sc->state &= ~PSM_SOFTARMED;
+	crit_exit();
 }
 
 static struct filterops psmfiltops =
@@ -2392,13 +3509,13 @@ psmkqfilter(struct dev_kqfilter_args *ap)
 	ap->a_result = 0;
 
 	switch (kn->kn_filter) {
-	case EVFILT_READ:
-		kn->kn_fop = &psmfiltops;
-		kn->kn_hook = (caddr_t)sc;
-		break;
-	default:
-		ap->a_result = EOPNOTSUPP;
-		return (0);
+		case EVFILT_READ:
+			kn->kn_fop = &psmfiltops;
+			kn->kn_hook = (caddr_t)sc;
+			break;
+		default:
+			ap->a_result = EOPNOTSUPP;
+			return (0);
 	}
 
 	klist = &sc->rkq.ki_note;
@@ -2435,56 +3552,56 @@ psmfilter(struct knote *kn, long hint)
 
 static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
 {
-    if (set_mouse_resolution(kbdc, res) != res)
-        return FALSE;
-    if (set_mouse_scaling(kbdc, scale)
-	&& set_mouse_scaling(kbdc, scale)
-	&& set_mouse_scaling(kbdc, scale) 
-	&& (get_mouse_status(kbdc, status, 0, 3) >= 3)) 
-	return TRUE;
-    return FALSE;
+	if (set_mouse_resolution(kbdc, res) != res)
+		return (FALSE);
+	if (set_mouse_scaling(kbdc, scale) &&
+	    set_mouse_scaling(kbdc, scale) &&
+	    set_mouse_scaling(kbdc, scale) &&
+	    (get_mouse_status(kbdc, status, 0, 3) >= 3))
+		return (TRUE);
+	return (FALSE);
 }
 
-static int 
+static int
 mouse_ext_command(KBDC kbdc, int command)
 {
-    int c;
-
-    c = (command >> 6) & 0x03;
-    if (set_mouse_resolution(kbdc, c) != c)
-	return FALSE;
-    c = (command >> 4) & 0x03;
-    if (set_mouse_resolution(kbdc, c) != c)
-	return FALSE;
-    c = (command >> 2) & 0x03;
-    if (set_mouse_resolution(kbdc, c) != c)
-	return FALSE;
-    c = (command >> 0) & 0x03;
-    if (set_mouse_resolution(kbdc, c) != c)
-	return FALSE;
-    return TRUE;
+	int c;
+
+	c = (command >> 6) & 0x03;
+	if (set_mouse_resolution(kbdc, c) != c)
+		return (FALSE);
+	c = (command >> 4) & 0x03;
+	if (set_mouse_resolution(kbdc, c) != c)
+		return (FALSE);
+	c = (command >> 2) & 0x03;
+	if (set_mouse_resolution(kbdc, c) != c)
+		return (FALSE);
+	c = (command >> 0) & 0x03;
+	if (set_mouse_resolution(kbdc, c) != c)
+		return (FALSE);
+	return (TRUE);
 }
 
-#if notyet
+#ifdef notyet
 /* Logitech MouseMan Cordless II */
 static int
 enable_lcordless(struct psm_softc *sc)
 {
-    int status[3];
-    int ch;
-
-    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 2, status))
-        return FALSE;
-    if (status[1] == PSMD_RES_HIGH)
-	return FALSE;
-    ch = (status[0] & 0x07) - 1;	/* channel # */
-    if ((ch <= 0) || (ch > 4))
-	return FALSE;
-    /* 
-     * status[1]: always one?
-     * status[2]: battery status? (0-100)
-     */
-    return TRUE;
+	int status[3];
+	int ch;
+
+	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 2, status))
+		return (FALSE);
+	if (status[1] == PSMD_RES_HIGH)
+		return (FALSE);
+	ch = (status[0] & 0x07) - 1;	/* channel # */
+	if ((ch <= 0) || (ch > 4))
+		return (FALSE);
+	/*
+	 * status[1]: always one?
+	 * status[2]: battery status? (0-100)
+	 */
+	return (TRUE);
 }
 #endif /* notyet */
 
@@ -2492,381 +3609,1110 @@ enable_lcordless(struct psm_softc *sc)
 static int
 enable_groller(struct psm_softc *sc)
 {
-    int status[3];
-
-    /*
-     * The special sequence to enable the fourth button and the
-     * roller. Immediately after this sequence check status bytes.
-     * if the mouse is NetScroll, the second and the third bytes are 
-     * '3' and 'D'.
-     */
-
-    /*
-     * If the mouse is an ordinary PS/2 mouse, the status bytes should
-     * look like the following.
-     * 
-     * byte 1 bit 7 always 0
-     *        bit 6 stream mode (0)
-     *        bit 5 disabled (0)
-     *        bit 4 1:1 scaling (0)
-     *        bit 3 always 0
-     *        bit 0-2 button status
-     * byte 2 resolution (PSMD_RES_HIGH)
-     * byte 3 report rate (?)
-     */
-
-    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
-        return FALSE;
-    if ((status[1] != '3') || (status[2] != 'D'))
-        return FALSE;
-    /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
-    sc->hw.buttons = 4;
-    return TRUE;
+	int status[3];
+
+	/*
+	 * The special sequence to enable the fourth button and the
+	 * roller. Immediately after this sequence check status bytes.
+	 * if the mouse is NetScroll, the second and the third bytes are
+	 * '3' and 'D'.
+	 */
+
+	/*
+	 * If the mouse is an ordinary PS/2 mouse, the status bytes should
+	 * look like the following.
+	 *
+	 * byte 1 bit 7 always 0
+	 *        bit 6 stream mode (0)
+	 *        bit 5 disabled (0)
+	 *        bit 4 1:1 scaling (0)
+	 *        bit 3 always 0
+	 *        bit 0-2 button status
+	 * byte 2 resolution (PSMD_RES_HIGH)
+	 * byte 3 report rate (?)
+	 */
+
+	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
+		return (FALSE);
+	if ((status[1] != '3') || (status[2] != 'D'))
+		return (FALSE);
+	/* FIXME: SmartScroll Mouse has 5 buttons! XXX */
+	sc->hw.buttons = 4;
+	return (TRUE);
 }
 
 /* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
 static int
 enable_gmouse(struct psm_softc *sc)
 {
-    int status[3];
-
-    /*
-     * The special sequence to enable the middle, "rubber" button. 
-     * Immediately after this sequence check status bytes.
-     * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse, 
-     * the second and the third bytes are '3' and 'U'.
-     * NOTE: NetMouse reports that it has three buttons although it has
-     * two buttons and a rubber button. NetMouse Pro and MIE Mouse
-     * say they have three buttons too and they do have a button on the
-     * side...
-     */
-    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
-        return FALSE;
-    if ((status[1] != '3') || (status[2] != 'U'))
-        return FALSE;
-    return TRUE;
+	int status[3];
+
+	/*
+	 * The special sequence to enable the middle, "rubber" button.
+	 * Immediately after this sequence check status bytes.
+	 * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
+	 * the second and the third bytes are '3' and 'U'.
+	 * NOTE: NetMouse reports that it has three buttons although it has
+	 * two buttons and a rubber button. NetMouse Pro and MIE Mouse
+	 * say they have three buttons too and they do have a button on the
+	 * side...
+	 */
+	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
+		return (FALSE);
+	if ((status[1] != '3') || (status[2] != 'U'))
+		return (FALSE);
+	return (TRUE);
 }
 
 /* ALPS GlidePoint */
 static int
 enable_aglide(struct psm_softc *sc)
 {
-    int status[3];
-
-    /*
-     * The special sequence to obtain ALPS GlidePoint specific
-     * information. Immediately after this sequence, status bytes will 
-     * contain something interesting.
-     * NOTE: ALPS produces several models of GlidePoint. Some of those
-     * do not respond to this sequence, thus, cannot be detected this way.
-     */
-    if (set_mouse_sampling_rate(sc->kbdc, 100) != 100)
-	return FALSE;
-    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_LOW, 2, status))
-        return FALSE;
-    if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
-        return FALSE;
-    return TRUE;
+	int status[3];
+
+	/*
+	 * The special sequence to obtain ALPS GlidePoint specific
+	 * information. Immediately after this sequence, status bytes will
+	 * contain something interesting.
+	 * NOTE: ALPS produces several models of GlidePoint. Some of those
+	 * do not respond to this sequence, thus, cannot be detected this way.
+	 */
+	if (set_mouse_sampling_rate(sc->kbdc, 100) != 100)
+		return (FALSE);
+	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_LOW, 2, status))
+		return (FALSE);
+	if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
+		return (FALSE);
+	return (TRUE);
 }
 
 /* Kensington ThinkingMouse/Trackball */
 static int
 enable_kmouse(struct psm_softc *sc)
 {
-    static unsigned char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
-    KBDC kbdc = sc->kbdc;
-    int status[3];
-    int id1;
-    int id2;
-    int i;
-
-    id1 = get_aux_id(kbdc);
-    if (set_mouse_sampling_rate(kbdc, 10) != 10)
-	return FALSE;
-    /* 
-     * The device is now in the native mode? It returns a different
-     * ID value...
-     */
-    id2 = get_aux_id(kbdc);
-    if ((id1 == id2) || (id2 != 2))
-	return FALSE;
-
-    if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
-        return FALSE;
+	static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
+	KBDC kbdc = sc->kbdc;
+	int status[3];
+	int id1;
+	int id2;
+	int i;
+
+	id1 = get_aux_id(kbdc);
+	if (set_mouse_sampling_rate(kbdc, 10) != 10)
+		return (FALSE);
+	/*
+	 * The device is now in the native mode? It returns a different
+	 * ID value...
+	 */
+	id2 = get_aux_id(kbdc);
+	if ((id1 == id2) || (id2 != 2))
+		return (FALSE);
+
+	if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
+		return (FALSE);
 #if PSM_DEBUG >= 2
-    /* at this point, resolution is LOW, sampling rate is 10/sec */
-    if (get_mouse_status(kbdc, status, 0, 3) < 3)
-        return FALSE;
+	/* at this point, resolution is LOW, sampling rate is 10/sec */
+	if (get_mouse_status(kbdc, status, 0, 3) < 3)
+		return (FALSE);
 #endif
 
-    /*
-     * The special sequence to enable the third and fourth buttons.
-     * Otherwise they behave like the first and second buttons.
-     */
-    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
-        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
-	    return FALSE;
-    }
-
-    /* 
-     * At this point, the device is using default resolution and
-     * sampling rate for the native mode. 
-     */
-    if (get_mouse_status(kbdc, status, 0, 3) < 3)
-        return FALSE;
-    if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
-        return FALSE;
-
-    /* the device appears be enabled by this sequence, diable it for now */
-    disable_aux_dev(kbdc);
-    empty_aux_buffer(kbdc, 5);
-
-    return TRUE;
+	/*
+	 * The special sequence to enable the third and fourth buttons.
+	 * Otherwise they behave like the first and second buttons.
+	 */
+	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
+		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+			return (FALSE);
+
+	/*
+	 * At this point, the device is using default resolution and
+	 * sampling rate for the native mode.
+	 */
+	if (get_mouse_status(kbdc, status, 0, 3) < 3)
+		return (FALSE);
+	if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
+		return (FALSE);
+
+	/* the device appears be enabled by this sequence, diable it for now */
+	disable_aux_dev(kbdc);
+	empty_aux_buffer(kbdc, 5);
+
+	return (TRUE);
 }
 
 /* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
 static int
 enable_mmanplus(struct psm_softc *sc)
 {
-    KBDC kbdc = sc->kbdc;
-    int data[3];
-
-    /* the special sequence to enable the fourth button and the roller. */
-    /*
-     * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
-     * must be called exactly three times since the last RESET command
-     * before this sequence. XXX
-     */
-    if (!set_mouse_scaling(kbdc, 1))
-	return FALSE;
-    if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
-	return FALSE;
-    if (get_mouse_status(kbdc, data, 1, 3) < 3)
-        return FALSE;
-
-    /*
-     * PS2++ protocl, packet type 0
-     *
-     *          b7 b6 b5 b4 b3 b2 b1 b0
-     * byte 1:  *  1  p3 p2 1  *  *  *
-     * byte 2:  1  1  p1 p0 m1 m0 1  0
-     * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
-     *
-     * p3-p0: packet type: 0
-     * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51, ScrollPoint:0x58...
-     */
-    /* check constant bits */
-    if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
-        return FALSE;
-    if ((data[1] & 0xc3) != 0xc2)
-        return FALSE;
-    /* check d3-d0 in byte 2 */
-    if (!MOUSE_PS2PLUS_CHECKBITS(data))
-        return FALSE;
-    /* check p3-p0 */
-    if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
-        return FALSE;
-
-    sc->hw.hwid &= 0x00ff;
-    sc->hw.hwid |= data[2] << 8;	/* save model ID */
-
-    /*
-     * MouseMan+ (or FirstMouse+) is now in its native mode, in which
-     * the wheel and the fourth button events are encoded in the
-     * special data packet. The mouse may be put in the IntelliMouse mode
-     * if it is initialized by the IntelliMouse's method.
-     */
-    return TRUE;
+	KBDC kbdc = sc->kbdc;
+	int data[3];
+
+	/* the special sequence to enable the fourth button and the roller. */
+	/*
+	 * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
+	 * must be called exactly three times since the last RESET command
+	 * before this sequence. XXX
+	 */
+	if (!set_mouse_scaling(kbdc, 1))
+		return (FALSE);
+	if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
+		return (FALSE);
+	if (get_mouse_status(kbdc, data, 1, 3) < 3)
+		return (FALSE);
+
+	/*
+	 * PS2++ protocl, packet type 0
+	 *
+	 *          b7 b6 b5 b4 b3 b2 b1 b0
+	 * byte 1:  *  1  p3 p2 1  *  *  *
+	 * byte 2:  1  1  p1 p0 m1 m0 1  0
+	 * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
+	 *
+	 * p3-p0: packet type: 0
+	 * m7-m0: model ID: MouseMan+:0x50,
+	 *		    FirstMouse+:0x51,
+	 *		    ScrollPoint:0x58...
+	 */
+	/* check constant bits */
+	if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
+		return (FALSE);
+	if ((data[1] & 0xc3) != 0xc2)
+		return (FALSE);
+	/* check d3-d0 in byte 2 */
+	if (!MOUSE_PS2PLUS_CHECKBITS(data))
+		return (FALSE);
+	/* check p3-p0 */
+	if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
+		return (FALSE);
+
+	sc->hw.hwid &= 0x00ff;
+	sc->hw.hwid |= data[2] << 8;	/* save model ID */
+
+	/*
+	 * MouseMan+ (or FirstMouse+) is now in its native mode, in which
+	 * the wheel and the fourth button events are encoded in the
+	 * special data packet. The mouse may be put in the IntelliMouse mode
+	 * if it is initialized by the IntelliMouse's method.
+	 */
+	return (TRUE);
 }
 
 /* MS IntelliMouse Explorer */
 static int
 enable_msexplorer(struct psm_softc *sc)
 {
-    static unsigned char rate0[] = { 200, 100, 80, };
-    static unsigned char rate1[] = { 200, 200, 80, };
-    KBDC kbdc = sc->kbdc;
-    int id;
-    int i;
-
-    /* the special sequence to enable the extra buttons and the roller. */
-    for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i) {
-        if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
-	    return FALSE;
-    }
-    /* the device will give the genuine ID only after the above sequence */
-    id = get_aux_id(kbdc);
-    if (id != PSM_EXPLORER_ID)
-	return FALSE;
-
-    sc->hw.hwid = id;
-    sc->hw.buttons = 5;		/* IntelliMouse Explorer XXX */
-
-    /*
-     * XXX: this is a kludge to fool some KVM switch products
-     * which think they are clever enough to know the 4-byte IntelliMouse
-     * protocol, and assume any other protocols use 3-byte packets.
-     * They don't convey 4-byte data packets from the IntelliMouse Explorer 
-     * correctly to the host computer because of this!
-     * The following sequence is actually IntelliMouse's "wake up"
-     * sequence; it will make the KVM think the mouse is IntelliMouse
-     * when it is in fact IntelliMouse Explorer.
-     */
-    for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i) {
-        if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
-	    break;
-    }
-    id = get_aux_id(kbdc);
-
-    return TRUE;
+	static u_char rate0[] = { 200, 100, 80, };
+	static u_char rate1[] = { 200, 200, 80, };
+	KBDC kbdc = sc->kbdc;
+	int id;
+	int i;
+
+	/*
+	 * This is needed for at least A4Tech X-7xx mice - they do not go
+	 * straight to Explorer mode, but need to be set to Intelli mode
+	 * first.
+	 */
+	enable_msintelli(sc);
+
+	/* the special sequence to enable the extra buttons and the roller. */
+	for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i)
+		if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
+			return (FALSE);
+	/* the device will give the genuine ID only after the above sequence */
+	id = get_aux_id(kbdc);
+	if (id != PSM_EXPLORER_ID)
+		return (FALSE);
+
+	sc->hw.hwid = id;
+	sc->hw.buttons = 5;		/* IntelliMouse Explorer XXX */
+
+	/*
+	 * XXX: this is a kludge to fool some KVM switch products
+	 * which think they are clever enough to know the 4-byte IntelliMouse
+	 * protocol, and assume any other protocols use 3-byte packets.
+	 * They don't convey 4-byte data packets from the IntelliMouse Explorer
+	 * correctly to the host computer because of this!
+	 * The following sequence is actually IntelliMouse's "wake up"
+	 * sequence; it will make the KVM think the mouse is IntelliMouse
+	 * when it is in fact IntelliMouse Explorer.
+	 */
+	for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i)
+		if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
+			break;
+	id = get_aux_id(kbdc);
+
+	return (TRUE);
 }
 
 /* MS IntelliMouse */
 static int
 enable_msintelli(struct psm_softc *sc)
 {
-    /*
-     * Logitech MouseMan+ and FirstMouse+ will also respond to this
-     * probe routine and act like IntelliMouse.
-     */
-
-    static unsigned char rate[] = { 200, 100, 80, };
-    KBDC kbdc = sc->kbdc;
-    int id;
-    int i;
-
-    /* the special sequence to enable the third button and the roller. */
-    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
-        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
-	    return FALSE;
-    }
-    /* the device will give the genuine ID only after the above sequence */
-    id = get_aux_id(kbdc);
-    if (id != PSM_INTELLI_ID)
-	return FALSE;
-
-    sc->hw.hwid = id;
-    sc->hw.buttons = 3;
-
-    return TRUE;
+	/*
+	 * Logitech MouseMan+ and FirstMouse+ will also respond to this
+	 * probe routine and act like IntelliMouse.
+	 */
+
+	static u_char rate[] = { 200, 100, 80, };
+	KBDC kbdc = sc->kbdc;
+	int id;
+	int i;
+
+	/* the special sequence to enable the third button and the roller. */
+	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
+		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+			return (FALSE);
+	/* the device will give the genuine ID only after the above sequence */
+	id = get_aux_id(kbdc);
+	if (id != PSM_INTELLI_ID)
+		return (FALSE);
+
+	sc->hw.hwid = id;
+	sc->hw.buttons = 3;
+
+	return (TRUE);
 }
 
 /* A4 Tech 4D Mouse */
 static int
 enable_4dmouse(struct psm_softc *sc)
 {
-    /*
-     * Newer wheel mice from A4 Tech may use the 4D+ protocol.
-     */
-
-    static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
-    KBDC kbdc = sc->kbdc;
-    int id;
-    int i;
-
-    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
-        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
-	    return FALSE;
-    }
-    id = get_aux_id(kbdc);
-    /*
-     * WinEasy 4D, 4 Way Scroll 4D: 6
-     * Cable-Free 4D: 8 (4DPLUS)
-     * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
-     */
-    if (id != PSM_4DMOUSE_ID)
-	return FALSE;
-
-    sc->hw.hwid = id;
-    sc->hw.buttons = 3;		/* XXX some 4D mice have 4? */
-
-    return TRUE;
+	/*
+	 * Newer wheel mice from A4 Tech may use the 4D+ protocol.
+	 */
+
+	static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
+	KBDC kbdc = sc->kbdc;
+	int id;
+	int i;
+
+	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
+		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+			return (FALSE);
+	id = get_aux_id(kbdc);
+	/*
+	 * WinEasy 4D, 4 Way Scroll 4D: 6
+	 * Cable-Free 4D: 8 (4DPLUS)
+	 * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
+	 */
+	if (id != PSM_4DMOUSE_ID)
+		return (FALSE);
+
+	sc->hw.hwid = id;
+	sc->hw.buttons = 3;		/* XXX some 4D mice have 4? */
+
+	return (TRUE);
 }
 
 /* A4 Tech 4D+ Mouse */
 static int
 enable_4dplus(struct psm_softc *sc)
 {
-    /*
-     * Newer wheel mice from A4 Tech seem to use this protocol.
-     * Older models are recognized as either 4D Mouse or IntelliMouse.
-     */
-    KBDC kbdc = sc->kbdc;
-    int id;
-
-    /*
-     * enable_4dmouse() already issued the following ID sequence...
-    static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
-    int i;
-
-    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
-        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
-	    return FALSE;
-    }
-    */
-
-    id = get_aux_id(kbdc);
-    if (id != PSM_4DPLUS_ID)
-	return FALSE;
-
-    sc->hw.hwid = id;
-    sc->hw.buttons = 4;		/* XXX */
-
-    return TRUE;
+	/*
+	 * Newer wheel mice from A4 Tech seem to use this protocol.
+	 * Older models are recognized as either 4D Mouse or IntelliMouse.
+	 */
+	KBDC kbdc = sc->kbdc;
+	int id;
+
+	/*
+	 * enable_4dmouse() already issued the following ID sequence...
+	static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
+	int i;
+
+	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
+		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+			return (FALSE);
+	*/
+
+	id = get_aux_id(kbdc);
+	switch (id) {
+	case PSM_4DPLUS_ID:
+		sc->hw.buttons = 4;
+		break;
+	case PSM_4DPLUS_RFSW35_ID:
+		sc->hw.buttons = 3;
+		break;
+	default:
+		return (FALSE);
+	}
+
+	sc->hw.hwid = id;
+
+	return (TRUE);
+}
+
+/* Synaptics Touchpad */
+static int
+synaptics_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	int error, arg;
+
+	/* Read the current value. */
+	arg = *(int *)oidp->oid_arg1;
+	error = sysctl_handle_int(oidp, &arg, 0, req);
+
+	/* Sanity check. */
+	if (error || !req->newptr)
+		return (error);
+
+	/*
+	 * Check that the new value is in the concerned node's range
+	 * of values.
+	 */
+	switch (oidp->oid_arg2) {
+	case SYNAPTICS_SYSCTL_MIN_PRESSURE:
+	case SYNAPTICS_SYSCTL_MAX_PRESSURE:
+		if (arg < 0 || arg > 255)
+			return (EINVAL);
+		break;
+	case SYNAPTICS_SYSCTL_MAX_WIDTH:
+		if (arg < 4 || arg > 15)
+			return (EINVAL);
+		break;
+	case SYNAPTICS_SYSCTL_MARGIN_TOP:
+	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
+	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
+	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
+	case SYNAPTICS_SYSCTL_NA_TOP:
+	case SYNAPTICS_SYSCTL_NA_RIGHT:
+	case SYNAPTICS_SYSCTL_NA_BOTTOM:
+	case SYNAPTICS_SYSCTL_NA_LEFT:
+		if (arg < 0 || arg > 6143)
+			return (EINVAL);
+		break;
+	case SYNAPTICS_SYSCTL_WINDOW_MIN:
+	case SYNAPTICS_SYSCTL_WINDOW_MAX:
+	case SYNAPTICS_SYSCTL_TAP_MIN_QUEUE:
+		if (arg < 1 || arg > SYNAPTICS_PACKETQUEUE)
+			return (EINVAL);
+		break;
+	case SYNAPTICS_SYSCTL_MULTIPLICATOR:
+	case SYNAPTICS_SYSCTL_WEIGHT_CURRENT:
+	case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS:
+	case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA:
+	case SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED:
+	case SYNAPTICS_SYSCTL_DIV_MIN:
+	case SYNAPTICS_SYSCTL_DIV_MAX:
+	case SYNAPTICS_SYSCTL_DIV_MAX_NA:
+	case SYNAPTICS_SYSCTL_DIV_LEN:
+	case SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN:
+	case SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX:
+		if (arg < 1)
+			return (EINVAL);
+		break;
+	case SYNAPTICS_SYSCTL_TAP_MAX_DELTA:
+	case SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT:
+	case SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA:
+		if (arg < 0)
+			return (EINVAL);
+		break;
+	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
+	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
+		if (arg < -6143 || arg > 6143)
+			return (EINVAL);
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	/* Update. */
+	*(int *)oidp->oid_arg1 = arg;
+
+	return (error);
+}
+
+static void
+synaptics_sysctl_create_tree(struct psm_softc *sc)
+{
+
+	if (sc->syninfo.sysctl_tree != NULL)
+		return;
+
+	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
+	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
+	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
+	    0, "Synaptics TouchPad");
+
+	/* hw.psm.synaptics.directional_scrolls. */
+	sc->syninfo.directional_scrolls = 1;
+	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.directional_scrolls, 0,
+	    "Enable hardware scrolling pad (if non-zero) or register it as "
+	    "a middle-click (if 0)");
+
+	/* hw.psm.synaptics.min_pressure. */
+	sc->syninfo.min_pressure = 16;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
+	    synaptics_sysctl, "I",
+	    "Minimum pressure required to start an action");
+
+	/* hw.psm.synaptics.max_pressure. */
+	sc->syninfo.max_pressure = 220;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
+	    synaptics_sysctl, "I",
+	    "Maximum pressure to detect palm");
+
+	/* hw.psm.synaptics.max_width. */
+	sc->syninfo.max_width = 10;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
+	    synaptics_sysctl, "I",
+	    "Maximum finger width to detect palm");
+
+	/* hw.psm.synaptics.top_margin. */
+	sc->syninfo.margin_top = 200;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
+	    synaptics_sysctl, "I",
+	    "Top margin");
+
+	/* hw.psm.synaptics.right_margin. */
+	sc->syninfo.margin_right = 200;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
+	    synaptics_sysctl, "I",
+	    "Right margin");
+
+	/* hw.psm.synaptics.bottom_margin. */
+	sc->syninfo.margin_bottom = 200;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
+	    synaptics_sysctl, "I",
+	    "Bottom margin");
+
+	/* hw.psm.synaptics.left_margin. */
+	sc->syninfo.margin_left = 200;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
+	    synaptics_sysctl, "I",
+	    "Left margin");
+
+	/* hw.psm.synaptics.na_top. */
+	sc->syninfo.na_top = 1783;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
+	    synaptics_sysctl, "I",
+	    "Top noisy area, where weight_previous_na is used instead "
+	    "of weight_previous");
+
+	/* hw.psm.synaptics.na_right. */
+	sc->syninfo.na_right = 563;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
+	    synaptics_sysctl, "I",
+	    "Right noisy area, where weight_previous_na is used instead "
+	    "of weight_previous");
+
+	/* hw.psm.synaptics.na_bottom. */
+	sc->syninfo.na_bottom = 1408;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
+	    synaptics_sysctl, "I",
+	    "Bottom noisy area, where weight_previous_na is used instead "
+	    "of weight_previous");
+
+	/* hw.psm.synaptics.na_left. */
+	sc->syninfo.na_left = 1600;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
+	    synaptics_sysctl, "I",
+	    "Left noisy area, where weight_previous_na is used instead "
+	    "of weight_previous");
+
+	/* hw.psm.synaptics.window_min. */
+	sc->syninfo.window_min = 4;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
+	    synaptics_sysctl, "I",
+	    "Minimum window size to start an action");
+
+	/* hw.psm.synaptics.window_max. */
+	sc->syninfo.window_max = 10;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
+	    synaptics_sysctl, "I",
+	    "Maximum window size");
+
+	/* hw.psm.synaptics.multiplicator. */
+	sc->syninfo.multiplicator = 10000;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
+	    synaptics_sysctl, "I",
+	    "Multiplicator to increase precision in averages and divisions");
+
+	/* hw.psm.synaptics.weight_current. */
+	sc->syninfo.weight_current = 3;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
+	    synaptics_sysctl, "I",
+	    "Weight of the current movement in the new average");
+
+	/* hw.psm.synaptics.weight_previous. */
+	sc->syninfo.weight_previous = 6;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
+	    synaptics_sysctl, "I",
+	    "Weight of the previous average");
+
+	/* hw.psm.synaptics.weight_previous_na. */
+	sc->syninfo.weight_previous_na = 20;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.weight_previous_na,
+	    SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
+	    synaptics_sysctl, "I",
+	    "Weight of the previous average (inside the noisy area)");
+
+	/* hw.psm.synaptics.weight_len_squared. */
+	sc->syninfo.weight_len_squared = 2000;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.weight_len_squared,
+	    SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
+	    synaptics_sysctl, "I",
+	    "Length (squared) of segments where weight_previous "
+	    "starts to decrease");
+
+	/* hw.psm.synaptics.div_min. */
+	sc->syninfo.div_min = 9;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
+	    synaptics_sysctl, "I",
+	    "Divisor for fast movements");
+
+	/* hw.psm.synaptics.div_max. */
+	sc->syninfo.div_max = 17;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
+	    synaptics_sysctl, "I",
+	    "Divisor for slow movements");
+
+	/* hw.psm.synaptics.div_max_na. */
+	sc->syninfo.div_max_na = 30;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
+	    synaptics_sysctl, "I",
+	    "Divisor with slow movements (inside the noisy area)");
+
+	/* hw.psm.synaptics.div_len. */
+	sc->syninfo.div_len = 100;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
+	    synaptics_sysctl, "I",
+	    "Length of segments where div_max starts to decrease");
+
+	/* hw.psm.synaptics.tap_max_delta. */
+	sc->syninfo.tap_max_delta = 80;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
+	    synaptics_sysctl, "I",
+	    "Length of segments above which a tap is ignored");
+
+	/* hw.psm.synaptics.tap_min_queue. */
+	sc->syninfo.tap_min_queue = 2;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
+	    synaptics_sysctl, "I",
+	    "Number of packets required to consider a tap");
+
+	/* hw.psm.synaptics.taphold_timeout. */
+	sc->synaction.in_taphold = 0;
+	sc->syninfo.taphold_timeout = tap_timeout;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
+	    synaptics_sysctl, "I",
+	    "Maximum elapsed time between two taps to consider a tap-hold "
+	    "action");
+
+	/* hw.psm.synaptics.vscroll_hor_area. */
+	sc->syninfo.vscroll_hor_area = 0; /* 1300 */
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
+	    synaptics_sysctl, "I",
+	    "Area reserved for horizontal virtual scrolling");
+
+	/* hw.psm.synaptics.vscroll_ver_area. */
+	sc->syninfo.vscroll_ver_area = -600;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
+	    synaptics_sysctl, "I",
+	    "Area reserved for vertical virtual scrolling");
+
+	/* hw.psm.synaptics.vscroll_min_delta. */
+	sc->syninfo.vscroll_min_delta = 50;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.vscroll_min_delta,
+	    SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
+	    synaptics_sysctl, "I",
+	    "Minimum movement to consider virtual scrolling");
+
+	/* hw.psm.synaptics.vscroll_div_min. */
+	sc->syninfo.vscroll_div_min = 100;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
+	    synaptics_sysctl, "I",
+	    "Divisor for fast scrolling");
+
+	/* hw.psm.synaptics.vscroll_div_min. */
+	sc->syninfo.vscroll_div_max = 150;
+	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
+	    synaptics_sysctl, "I",
+	    "Divisor for slow scrolling");
+}
+
+static int
+enable_synaptics(struct psm_softc *sc)
+{
+	int status[3];
+	KBDC kbdc;
+
+	if (!synaptics_support)
+		return (FALSE);
+
+	kbdc = sc->kbdc;
+	VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n"));
+	sc->hw.buttons = 3;
+	sc->squelch = 0;
+
+	/*
+	 * Just to be on the safe side: this avoids troubles with
+	 * following mouse_ext_command() when the previous command
+	 * was PSMC_SET_RESOLUTION. Set Scaling has no effect on
+	 * Synaptics Touchpad behaviour.
+	 */
+	set_mouse_scaling(kbdc, 1);
+
+	/* Identify the Touchpad version. */
+	if (mouse_ext_command(kbdc, 0) == 0)
+		return (FALSE);
+	if (get_mouse_status(kbdc, status, 0, 3) != 3)
+		return (FALSE);
+	if (status[1] != 0x47)
+		return (FALSE);
+
+	sc->synhw.infoMinor = status[0];
+	sc->synhw.infoMajor = status[2] & 0x0f;
+
+	if (verbose >= 2)
+		kprintf("Synaptics Touchpad v%d.%d\n", sc->synhw.infoMajor,
+		    sc->synhw.infoMinor);
+
+	if (sc->synhw.infoMajor < 4) {
+		kprintf("  Unsupported (pre-v4) Touchpad detected\n");
+		return (FALSE);
+	}
+
+	/* Get the Touchpad model information. */
+	if (mouse_ext_command(kbdc, 3) == 0)
+		return (FALSE);
+	if (get_mouse_status(kbdc, status, 0, 3) != 3)
+		return (FALSE);
+	if ((status[1] & 0x01) != 0) {
+		kprintf("  Failed to read model information\n");
+		return (FALSE);
+	}
+
+	sc->synhw.infoRot180   = (status[0] & 0x80) >> 7;
+	sc->synhw.infoPortrait = (status[0] & 0x40) >> 6;
+	sc->synhw.infoSensor   =  status[0] & 0x3f;
+	sc->synhw.infoHardware = (status[1] & 0xfe) >> 1;
+	sc->synhw.infoNewAbs   = (status[2] & 0x80) >> 7;
+	sc->synhw.capPen       = (status[2] & 0x40) >> 6;
+	sc->synhw.infoSimplC   = (status[2] & 0x20) >> 5;
+	sc->synhw.infoGeometry =  status[2] & 0x0f;
+
+	if (verbose >= 2) {
+		kprintf("  Model information:\n");
+		kprintf("   infoRot180: %d\n", sc->synhw.infoRot180);
+		kprintf("   infoPortrait: %d\n", sc->synhw.infoPortrait);
+		kprintf("   infoSensor: %d\n", sc->synhw.infoSensor);
+		kprintf("   infoHardware: %d\n", sc->synhw.infoHardware);
+		kprintf("   infoNewAbs: %d\n", sc->synhw.infoNewAbs);
+		kprintf("   capPen: %d\n", sc->synhw.capPen);
+		kprintf("   infoSimplC: %d\n", sc->synhw.infoSimplC);
+		kprintf("   infoGeometry: %d\n", sc->synhw.infoGeometry);
+	}
+
+	/* Read the extended capability bits. */
+	if (mouse_ext_command(kbdc, 2) == 0)
+		return (FALSE);
+	if (get_mouse_status(kbdc, status, 0, 3) != 3)
+		return (FALSE);
+	if (status[1] != 0x47) {
+		kprintf("  Failed to read extended capability bits\n");
+		return (FALSE);
+	}
+
+	/* Set the different capabilities when they exist. */
+	if ((status[0] & 0x80) >> 7) {
+		sc->synhw.capExtended    = (status[0] & 0x80) >> 7;
+		sc->synhw.capPassthrough = (status[2] & 0x80) >> 7;
+		sc->synhw.capSleep       = (status[2] & 0x10) >> 4;
+		sc->synhw.capFourButtons = (status[2] & 0x08) >> 3;
+		sc->synhw.capMultiFinger = (status[2] & 0x02) >> 1;
+		sc->synhw.capPalmDetect  = (status[2] & 0x01);
+
+		if (verbose >= 2) {
+			kprintf("  Extended capabilities:\n");
+			kprintf("   capExtended: %d\n", sc->synhw.capExtended);
+			kprintf("   capPassthrough: %d\n",
+			    sc->synhw.capPassthrough);
+			kprintf("   capSleep: %d\n", sc->synhw.capSleep);
+			kprintf("   capFourButtons: %d\n",
+			    sc->synhw.capFourButtons);
+			kprintf("   capMultiFinger: %d\n",
+			    sc->synhw.capMultiFinger);
+			kprintf("   capPalmDetect: %d\n",
+			    sc->synhw.capPalmDetect);
+		}
+
+		/*
+		 * If we have bits set in status[0] & 0x70, then we can load
+		 * more information about buttons using query 0x09.
+		 */
+		if (status[0] & 0x70) {
+			if (mouse_ext_command(kbdc, 0x09) == 0)
+				return (FALSE);
+			if (get_mouse_status(kbdc, status, 0, 3) != 3)
+				return (FALSE);
+			sc->hw.buttons = ((status[1] & 0xf0) >> 4) + 3;
+			if (verbose >= 2)
+				kprintf("  Additional Buttons: %d\n",
+				    sc->hw.buttons -3);
+		}
+	} else {
+		sc->synhw.capExtended = 0;
+
+		if (verbose >= 2)
+			kprintf("  No extended capabilities\n");
+	}
+
+	/*
+	 * Read the mode byte.
+	 *
+	 * XXX: Note the Synaptics documentation also defines the first
+	 * byte of the response to this query to be a constant 0x3b, this
+	 * does not appear to be true for Touchpads with guest devices.
+	 */
+	if (mouse_ext_command(kbdc, 1) == 0)
+		return (FALSE);
+	if (get_mouse_status(kbdc, status, 0, 3) != 3)
+		return (FALSE);
+	if (status[1] != 0x47) {
+		kprintf("  Failed to read mode byte\n");
+		return (FALSE);
+	}
+
+	/* Set the mode byte; request wmode where available. */
+	if (sc->synhw.capExtended)
+		mouse_ext_command(kbdc, 0xc1);
+	else
+		mouse_ext_command(kbdc, 0xc0);
+
+	/* "Commit" the Set Mode Byte command sent above. */
+	set_mouse_sampling_rate(kbdc, 20);
+
+	/*
+	 * Report the correct number of buttons
+	 *
+	 * XXX: I'm not sure this is used anywhere.
+	 */
+	if (sc->synhw.capExtended && sc->synhw.capFourButtons)
+		sc->hw.buttons = 4;
+
+	VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n",
+	    sc->hw.buttons));
+
+	/* Create sysctl tree. */
+	synaptics_sysctl_create_tree(sc);
+
+	/*
+	 * The touchpad will have to be reinitialized after
+	 * suspend/resume.
+	 */
+	sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
+
+	return (TRUE);
 }
 
 /* Interlink electronics VersaPad */
 static int
 enable_versapad(struct psm_softc *sc)
 {
-    KBDC kbdc = sc->kbdc;
-    int data[3];
-
-    set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
-    set_mouse_sampling_rate(kbdc, 100);		/* set rate 100 */
-    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
-    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
-    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
-    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
-    if (get_mouse_status(kbdc, data, 0, 3) < 3)	/* get status */
-	return FALSE;
-    if (data[2] != 0xa || data[1] != 0 )	/* rate == 0xa && res. == 0 */
-	return FALSE;
-    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
-
-    sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
-
-    return TRUE;				/* PS/2 absolute mode */
+	KBDC kbdc = sc->kbdc;
+	int data[3];
+
+	set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
+	set_mouse_sampling_rate(kbdc, 100);		/* set rate 100 */
+	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
+	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
+	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
+	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
+	if (get_mouse_status(kbdc, data, 0, 3) < 3)	/* get status */
+		return (FALSE);
+	if (data[2] != 0xa || data[1] != 0 )	/* rate == 0xa && res. == 0 */
+		return (FALSE);
+	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
+
+	sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
+
+	return (TRUE);				/* PS/2 absolute mode */
+}
+
+/*
+ * Return true if 'now' is earlier than (start + (secs.usecs)).
+ * Now may be NULL and the function will fetch the current time from
+ * getmicrouptime(), or a cached 'now' can be passed in.
+ * All values should be numbers derived from getmicrouptime().
+ */
+static int
+timeelapsed(start, secs, usecs, now)
+	const struct timeval *start, *now;
+	int secs, usecs;
+{
+	struct timeval snow, tv;
+
+	/* if there is no 'now' passed in, the get it as a convience. */
+	if (now == NULL) {
+		getmicrouptime(&snow);
+		now = &snow;
+	}
+
+	tv.tv_sec = secs;
+	tv.tv_usec = usecs;
+	timevaladd(&tv, start);
+	return (timevalcmp(&tv, now, <));
 }
 
 static int
 psmresume(device_t dev)
 {
-    struct psm_softc *sc = device_get_softc(dev);
-    int unit = device_get_unit(dev);
-    int err;
+	struct psm_softc *sc = device_get_softc(dev);
+	int unit = device_get_unit(dev);
+	int err;
 
-    if (verbose >= 2)
-        log(LOG_NOTICE, "psm%d: system resume hook called.\n", unit);
+	VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit));
 
-    if (!(sc->config & PSM_CONFIG_HOOKRESUME))
-	return (0);
+	if (!(sc->config & PSM_CONFIG_HOOKRESUME))
+		return (0);
 
-    err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
+	err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
 
-    if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
-	/* 
-	 * Release the blocked process; it must be notified that the device
-	 * cannot be accessed anymore.
-	 */
-        sc->state &= ~PSM_ASLP;
-        wakeup((caddr_t)sc);
-    }
+	if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
+		/*
+		 * Release the blocked process; it must be notified that
+		 * the device cannot be accessed anymore.
+		 */
+		sc->state &= ~PSM_ASLP;
+		wakeup(sc);
+	}
 
-    if (verbose >= 2)
-        log(LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit);
+	VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit));
 
-    return (err);
+	return (err);
 }
 
 DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
+
+
+#if 0
+/*
+ * This sucks up assignments from PNPBIOS and ACPI.
+ */
+
+/*
+ * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may
+ * appear BEFORE the AT keyboard controller.  As the PS/2 mouse device
+ * can be probed and attached only after the AT keyboard controller is
+ * attached, we shall quietly reserve the IRQ resource for later use.
+ * If the PS/2 mouse device is reported to us AFTER the keyboard controller,
+ * copy the IRQ resource to the PS/2 mouse device instance hanging
+ * under the keyboard controller, then probe and attach it.
+ */
+
+static	devclass_t			psmcpnp_devclass;
+
+static	device_probe_t			psmcpnp_probe;
+static	device_attach_t			psmcpnp_attach;
+
+static device_method_t psmcpnp_methods[] = {
+	DEVMETHOD(device_probe,		psmcpnp_probe),
+	DEVMETHOD(device_attach,	psmcpnp_attach),
+
+	{ 0, 0 }
+};
+
+static driver_t psmcpnp_driver = {
+	PSMCPNP_DRIVER_NAME,
+	psmcpnp_methods,
+	1,			/* no softc */
+};
+
+static struct isa_pnp_id psmcpnp_ids[] = {
+	{ 0x030fd041, "PS/2 mouse port" },		/* PNP0F03 */
+	{ 0x0e0fd041, "PS/2 mouse port" },		/* PNP0F0E */
+	{ 0x120fd041, "PS/2 mouse port" },		/* PNP0F12 */
+	{ 0x130fd041, "PS/2 mouse port" },		/* PNP0F13 */
+	{ 0x1303d041, "PS/2 port" },			/* PNP0313, XXX */
+	{ 0x02002e4f, "Dell PS/2 mouse port" },		/* Lat. X200, Dell */
+	{ 0x0002a906, "ALPS Glide Point" },		/* ALPS Glide Point */
+	{ 0x80374d24, "IBM PS/2 mouse port" },		/* IBM3780, ThinkPad */
+	{ 0x81374d24, "IBM PS/2 mouse port" },		/* IBM3781, ThinkPad */
+	{ 0x0190d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9001, Vaio */
+	{ 0x0290d94d, "SONY VAIO PS/2 mouse port"},	/* SNY9002, Vaio */
+	{ 0x0390d94d, "SONY VAIO PS/2 mouse port"},	/* SNY9003, Vaio */
+	{ 0x0490d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9004, Vaio */
+	{ 0 }
+};
+
+static int
+create_a_copy(device_t atkbdc, device_t me)
+{
+	device_t psm;
+	u_long irq;
+
+	/* find the PS/2 mouse device instance under the keyboard controller */
+	psm = device_find_child(atkbdc, PSM_DRIVER_NAME,
+	    device_get_unit(atkbdc));
+	if (psm == NULL)
+		return (ENXIO);
+	if (device_get_state(psm) != DS_NOTPRESENT)
+		return (0);
+
+	/* move our resource to the found device */
+	irq = bus_get_resource_start(me, SYS_RES_IRQ, 0);
+	bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
+
+	/* ...then probe and attach it */
+	return (device_probe_and_attach(psm));
+}
+
+static int
+psmcpnp_probe(device_t dev)
+{
+	struct resource *res;
+	u_long irq;
+	int rid;
+
+	if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
+		return (ENXIO);
+
+	/*
+	 * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
+	 * to the PS/2 mouse device node. But, some buggy PnP BIOS
+	 * declares the PS/2 mouse device node without an IRQ resource!
+	 * If this happens, we shall refer to device hints.
+	 * If we still don't find it there, use a hardcoded value... XXX
+	 */
+	rid = 0;
+	irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
+	if (irq <= 0) {
+		if (resource_long_value(PSM_DRIVER_NAME,
+		    device_get_unit(dev),"irq", &irq) != 0)
+			irq = 12;	/* XXX */
+		device_printf(dev, "irq resource info is missing; "
+		    "assuming irq %ld\n", irq);
+		bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
+	}
+	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE);
+	bus_release_resource(dev, SYS_RES_IRQ, rid, res);
+
+	/* keep quiet */
+	if (!bootverbose)
+		device_quiet(dev);
+
+	return ((res == NULL) ? ENXIO : 0);
+}
+
+static int
+psmcpnp_attach(device_t dev)
+{
+	device_t atkbdc;
+	int rid;
+
+	/* find the keyboard controller, which may be on acpi* or isa* bus */
+	atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME),
+	    device_get_unit(dev));
+	if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED))
+		create_a_copy(atkbdc, dev);
+	else {
+		/*
+		 * If we don't have the AT keyboard controller yet,
+		 * just reserve the IRQ for later use...
+		 * (See psmidentify() above.)
+		 */
+		rid = 0;
+		bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE);
+	}
+
+	return (0);
+}
+
+DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0);
+DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0);
+#endif
diff --git a/sys/sys/mouse.h b/sys/sys/mouse.h
index 599c5f5..e032da8 100644
--- a/sys/sys/mouse.h
+++ b/sys/sys/mouse.h
@@ -48,6 +48,8 @@
 #define MOUSE_GETHWID		_IOR('M', 13, int)
 #endif
 
+#define MOUSE_SYN_GETHWINFO	_IOR('M', 100, synapticshw_t)
+
 /* mouse status block */
 typedef struct mousestatus {
     int     flags;		/* state change flags */
@@ -88,6 +90,25 @@ typedef struct mousehw {
 				 */
 } mousehw_t;
 
+typedef struct synapticshw {
+	int infoMajor;
+	int infoMinor;
+	int infoRot180;
+	int infoPortrait;
+	int infoSensor;
+	int infoHardware;
+	int infoNewAbs;
+	int capPen;
+	int infoSimplC;
+	int infoGeometry;
+	int capExtended;
+	int capSleep;
+	int capFourButtons;
+	int capMultiFinger;
+	int capPalmDetect;
+	int capPassthrough;
+} synapticshw_t;
+
 /* iftype */
 #define MOUSE_IF_UNKNOWN	(-1)
 #define MOUSE_IF_SERIAL		0
@@ -119,6 +140,7 @@ typedef struct mousehw {
 #define MOUSE_MODEL_EXPLORER		10
 #define MOUSE_MODEL_4D			11
 #define MOUSE_MODEL_4DPLUS		12
+#define MOUSE_MODEL_SYNAPTICS		13
 
 typedef struct mousemode {
 	int protocol;		/* MOUSE_PROTO_XXX */
@@ -185,6 +207,9 @@ typedef struct mousevar {
 
 #endif /* MOUSE_GETVARS */
 
+/* Synaptics Touchpad */
+#define MOUSE_SYNAPTICS_PACKETSIZE 6	/* '3' works better */
+
 /* Microsoft Serial mouse data packet */
 #define MOUSE_MSS_PACKETSIZE	3
 #define MOUSE_MSS_SYNCMASK	0x40
-- 
1.7.0.5

From aacc13e7f365dd58e65d70eea78607447f49fb1a Mon Sep 17 00:00:00 2001
From: Antonio Huete Jimenez <tuxillo@quantumachine.net>
Date: Thu, 14 Oct 2010 21:55:01 +0200
Subject: [PATCH 3/3] moused(8) - Add Synaptics touchpads to the model list.

Obtained-from: FreeBSD
---
 usr.sbin/moused/moused.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/usr.sbin/moused/moused.c b/usr.sbin/moused/moused.c
index 4c3c5a1..1b6894d 100644
--- a/usr.sbin/moused/moused.c
+++ b/usr.sbin/moused/moused.c
@@ -223,6 +223,7 @@ static symtab_t	rmodels[] = {
     { "IntelliMouse Explorer",	MOUSE_MODEL_EXPLORER },
     { "4D Mouse",		MOUSE_MODEL_4D },
     { "4D+ Mouse",		MOUSE_MODEL_4DPLUS },
+    { "Synaptics Touchpad",	MOUSE_MODEL_SYNAPTICS },
     { "generic",		MOUSE_MODEL_GENERIC },
     { NULL,			MOUSE_MODEL_UNKNOWN },
 };
-- 
1.7.0.5

