1/*-
2 * Copyright (c) 1992, 1993 Erik Forsberg.
3 * Copyright (c) 1996, 1997 Kazutaka YOKOTA.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 *
12 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
15 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23/*
24 *  Ported to 386bsd Oct 17, 1992
25 *  Sandi Donno, Computer Science, University of Cape Town, South Africa
26 *  Please send bug reports to sandi@cs.uct.ac.za
27 *
28 *  Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
29 *  although I was only partially successful in getting the alpha release
30 *  of his "driver for the Logitech and ATI Inport Bus mice for use with
31 *  386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
32 *  found his code to be an invaluable reference when porting this driver
33 *  to 386bsd.
34 *
35 *  Further modifications for latest 386BSD+patchkit and port to NetBSD,
36 *  Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
37 *
38 *  Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
39 *  Andrew Herbert - 12 June 1993
40 *
41 *  Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
42 *  - 13 June 1993
43 *
44 *  Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
45 *  - 24 October 1993
46 *
47 *  Hardware access routines and probe logic rewritten by
48 *  Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
49 *  - 3, 14, 22 October 1996.
50 *  - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
51 *  - 14, 30 November 1996. Uses `kbdio.c'.
52 *  - 13 December 1996. Uses queuing version of `kbdio.c'.
53 *  - January/February 1997. Tweaked probe logic for
54 *    HiNote UltraII/Latitude/Armada laptops.
55 *  - 30 July 1997. Added APM support.
56 *  - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX).
57 *    Improved sync check logic.
58 *    Vendor specific support routines.
59 */
60
61#include <sys/cdefs.h>
62__FBSDID("$FreeBSD: stable/10/sys/dev/atkbdc/psm.c 329533 2018-02-18 22:12:20Z wulf $");
63
64#include "opt_isa.h"
65#include "opt_psm.h"
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/kernel.h>
70#include <sys/module.h>
71#include <sys/bus.h>
72#include <sys/conf.h>
73#include <sys/filio.h>
74#include <sys/poll.h>
75#include <sys/sigio.h>
76#include <sys/signalvar.h>
77#include <sys/syslog.h>
78#include <machine/bus.h>
79#include <sys/rman.h>
80#include <sys/selinfo.h>
81#include <sys/sysctl.h>
82#include <sys/time.h>
83#include <sys/uio.h>
84
85#include <sys/limits.h>
86#include <sys/mouse.h>
87#include <machine/resource.h>
88
89#ifdef DEV_ISA
90#include <isa/isavar.h>
91#endif
92
93#include <dev/atkbdc/atkbdcreg.h>
94#include <dev/atkbdc/psm.h>
95
96/*
97 * Driver specific options: the following options may be set by
98 * `options' statements in the kernel configuration file.
99 */
100
101/* debugging */
102#ifndef PSM_DEBUG
103#define	PSM_DEBUG	0	/*
104				 * logging: 0: none, 1: brief, 2: verbose
105				 *          3: sync errors, 4: all packets
106				 */
107#endif
108#define	VLOG(level, args)	do {	\
109	if (verbose >= level)		\
110		log args;		\
111} while (0)
112
113#ifndef PSM_INPUT_TIMEOUT
114#define	PSM_INPUT_TIMEOUT	2000000	/* 2 sec */
115#endif
116
117#ifndef PSM_TAP_TIMEOUT
118#define	PSM_TAP_TIMEOUT		125000
119#endif
120
121#ifndef PSM_TAP_THRESHOLD
122#define	PSM_TAP_THRESHOLD	25
123#endif
124
125/* end of driver specific options */
126
127#define	PSMCPNP_DRIVER_NAME	"psmcpnp"
128
129/* input queue */
130#define	PSM_BUFSIZE		960
131#define	PSM_SMALLBUFSIZE	240
132
133/* operation levels */
134#define	PSM_LEVEL_BASE		0
135#define	PSM_LEVEL_STANDARD	1
136#define	PSM_LEVEL_NATIVE	2
137#define	PSM_LEVEL_MIN		PSM_LEVEL_BASE
138#define	PSM_LEVEL_MAX		PSM_LEVEL_NATIVE
139
140/* Logitech PS2++ protocol */
141#define	MOUSE_PS2PLUS_CHECKBITS(b)	\
142    ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
143#define	MOUSE_PS2PLUS_PACKET_TYPE(b)	\
144    (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
145
146/* ring buffer */
147typedef struct ringbuf {
148	int		count;	/* # of valid elements in the buffer */
149	int		head;	/* head pointer */
150	int		tail;	/* tail poiner */
151	u_char buf[PSM_BUFSIZE];
152} ringbuf_t;
153
154/* data buffer */
155typedef struct packetbuf {
156	u_char	ipacket[16];	/* interim input buffer */
157	int	inputbytes;	/* # of bytes in the input buffer */
158} packetbuf_t;
159
160#ifndef PSM_PACKETQUEUE
161#define	PSM_PACKETQUEUE	128
162#endif
163
164enum {
165	SYNAPTICS_SYSCTL_MIN_PRESSURE,
166	SYNAPTICS_SYSCTL_MAX_PRESSURE,
167	SYNAPTICS_SYSCTL_MAX_WIDTH,
168	SYNAPTICS_SYSCTL_MARGIN_TOP,
169	SYNAPTICS_SYSCTL_MARGIN_RIGHT,
170	SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
171	SYNAPTICS_SYSCTL_MARGIN_LEFT,
172	SYNAPTICS_SYSCTL_NA_TOP,
173	SYNAPTICS_SYSCTL_NA_RIGHT,
174	SYNAPTICS_SYSCTL_NA_BOTTOM,
175	SYNAPTICS_SYSCTL_NA_LEFT,
176	SYNAPTICS_SYSCTL_WINDOW_MIN,
177	SYNAPTICS_SYSCTL_WINDOW_MAX,
178	SYNAPTICS_SYSCTL_MULTIPLICATOR,
179	SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
180	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
181	SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
182	SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
183	SYNAPTICS_SYSCTL_DIV_MIN,
184	SYNAPTICS_SYSCTL_DIV_MAX,
185	SYNAPTICS_SYSCTL_DIV_MAX_NA,
186	SYNAPTICS_SYSCTL_DIV_LEN,
187	SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
188	SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
189	SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
190	SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
191	SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
192	SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
193	SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
194	SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
195	SYNAPTICS_SYSCTL_TOUCHPAD_OFF
196};
197
198typedef struct synapticsinfo {
199	struct sysctl_ctx_list	 sysctl_ctx;
200	struct sysctl_oid	*sysctl_tree;
201	int			 directional_scrolls;
202	int			 two_finger_scroll;
203	int			 min_pressure;
204	int			 max_pressure;
205	int			 max_width;
206	int			 margin_top;
207	int			 margin_right;
208	int			 margin_bottom;
209	int			 margin_left;
210	int			 na_top;
211	int			 na_right;
212	int			 na_bottom;
213	int			 na_left;
214	int			 window_min;
215	int			 window_max;
216	int			 multiplicator;
217	int			 weight_current;
218	int			 weight_previous;
219	int			 weight_previous_na;
220	int			 weight_len_squared;
221	int			 div_min;
222	int			 div_max;
223	int			 div_max_na;
224	int			 div_len;
225	int			 tap_max_delta;
226	int			 tap_min_queue;
227	int			 taphold_timeout;
228	int			 vscroll_ver_area;
229	int			 vscroll_hor_area;
230	int			 vscroll_min_delta;
231	int			 vscroll_div_min;
232	int			 vscroll_div_max;
233	int			 touchpad_off;
234} synapticsinfo_t;
235
236typedef struct synapticspacket {
237	int			x;
238	int			y;
239} synapticspacket_t;
240
241#define	SYNAPTICS_PACKETQUEUE 10
242#define SYNAPTICS_QUEUE_CURSOR(x)					\
243	(x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE
244
245#define	SYNAPTICS_VERSION_GE(synhw, major, minor)			\
246    ((synhw).infoMajor > (major) ||					\
247     ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
248
249typedef struct synapticsaction {
250	synapticspacket_t	queue[SYNAPTICS_PACKETQUEUE];
251	int			queue_len;
252	int			queue_cursor;
253	int			window_min;
254	int			start_x;
255	int			start_y;
256	int			avg_dx;
257	int			avg_dy;
258	int			squelch_x;
259	int			squelch_y;
260	int			fingers_nb;
261	int			tap_button;
262	int			in_taphold;
263	int			in_vscroll;
264} synapticsaction_t;
265
266enum {
267	TRACKPOINT_SYSCTL_SENSITIVITY,
268	TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
269	TRACKPOINT_SYSCTL_UPPER_PLATEAU,
270	TRACKPOINT_SYSCTL_BACKUP_RANGE,
271	TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
272	TRACKPOINT_SYSCTL_MINIMUM_DRAG,
273	TRACKPOINT_SYSCTL_UP_THRESHOLD,
274	TRACKPOINT_SYSCTL_THRESHOLD,
275	TRACKPOINT_SYSCTL_JENKS_CURVATURE,
276	TRACKPOINT_SYSCTL_Z_TIME,
277	TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
278	TRACKPOINT_SYSCTL_SKIP_BACKUPS
279};
280
281typedef struct trackpointinfo {
282	struct sysctl_ctx_list sysctl_ctx;
283	struct sysctl_oid *sysctl_tree;
284	int	sensitivity;
285	int	inertia;
286	int	uplateau;
287	int	reach;
288	int	draghys;
289	int	mindrag;
290	int	upthresh;
291	int	threshold;
292	int	jenks;
293	int	ztime;
294	int	pts;
295	int	skipback;
296} trackpointinfo_t;
297
298/* driver control block */
299struct psm_softc {		/* Driver status information */
300	int		unit;
301	struct selinfo	rsel;		/* Process selecting for Input */
302	u_char		state;		/* Mouse driver state */
303	int		config;		/* driver configuration flags */
304	int		flags;		/* other flags */
305	KBDC		kbdc;		/* handle to access kbd controller */
306	struct resource	*intr;		/* IRQ resource */
307	void		*ih;		/* interrupt handle */
308	mousehw_t	hw;		/* hardware information */
309	synapticshw_t	synhw;		/* Synaptics hardware information */
310	synapticsinfo_t	syninfo;	/* Synaptics configuration */
311	synapticsaction_t synaction;	/* Synaptics action context */
312	int		tphw;		/* TrackPoint hardware information */
313	trackpointinfo_t tpinfo;	/* TrackPoint configuration */
314	mousemode_t	mode;		/* operation mode */
315	mousemode_t	dflt_mode;	/* default operation mode */
316	mousestatus_t	status;		/* accumulated mouse movement */
317	ringbuf_t	queue;		/* mouse status queue */
318	packetbuf_t	pqueue[PSM_PACKETQUEUE]; /* mouse data queue */
319	int		pqueue_start;	/* start of data in queue */
320	int		pqueue_end;	/* end of data in queue */
321	int		button;		/* the latest button state */
322	int		xold;		/* previous absolute X position */
323	int		yold;		/* previous absolute Y position */
324	int		xaverage;	/* average X position */
325	int		yaverage;	/* average Y position */
326	int		squelch; /* level to filter movement at low speed */
327	int		zmax;	/* maximum pressure value for touchpads */
328	int		syncerrors; /* # of bytes discarded to synchronize */
329	int		pkterrors;  /* # of packets failed during quaranteen. */
330	struct timeval	inputtimeout;
331	struct timeval	lastsoftintr;	/* time of last soft interrupt */
332	struct timeval	lastinputerr;	/* time last sync error happened */
333	struct timeval	taptimeout;	/* tap timeout for touchpads */
334	int		watchdog;	/* watchdog timer flag */
335	struct callout	callout;	/* watchdog timer call out */
336	struct callout	softcallout; /* buffer timer call out */
337	struct cdev	*dev;
338	struct cdev	*bdev;
339	int		lasterr;
340	int		cmdcount;
341	struct sigio	*async;		/* Processes waiting for SIGIO */
342	int		extended_buttons;
343};
344static devclass_t psm_devclass;
345
346/* driver state flags (state) */
347#define	PSM_VALID		0x80
348#define	PSM_OPEN		1	/* Device is open */
349#define	PSM_ASLP		2	/* Waiting for mouse data */
350#define	PSM_SOFTARMED		4	/* Software interrupt armed */
351#define	PSM_NEED_SYNCBITS	8	/* Set syncbits using next data pkt */
352
353/* driver configuration flags (config) */
354#define	PSM_CONFIG_RESOLUTION	0x000f	/* resolution */
355#define	PSM_CONFIG_ACCEL	0x00f0  /* acceleration factor */
356#define	PSM_CONFIG_NOCHECKSYNC	0x0100  /* disable sync. test */
357#define	PSM_CONFIG_NOIDPROBE	0x0200  /* disable mouse model probe */
358#define	PSM_CONFIG_NORESET	0x0400  /* don't reset the mouse */
359#define	PSM_CONFIG_FORCETAP	0x0800  /* assume `tap' action exists */
360#define	PSM_CONFIG_IGNPORTERROR	0x1000  /* ignore error in aux port test */
361#define	PSM_CONFIG_HOOKRESUME	0x2000	/* hook the system resume event */
362#define	PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
363
364#define	PSM_CONFIG_FLAGS	\
365    (PSM_CONFIG_RESOLUTION |	\
366    PSM_CONFIG_ACCEL |		\
367    PSM_CONFIG_NOCHECKSYNC |	\
368    PSM_CONFIG_NOIDPROBE |	\
369    PSM_CONFIG_NORESET |	\
370    PSM_CONFIG_FORCETAP |	\
371    PSM_CONFIG_IGNPORTERROR |	\
372    PSM_CONFIG_HOOKRESUME |	\
373    PSM_CONFIG_INITAFTERSUSPEND)
374
375/* other flags (flags) */
376#define	PSM_FLAGS_FINGERDOWN	0x0001	/* VersaPad finger down */
377
378/* Tunables */
379static int tap_enabled = -1;
380TUNABLE_INT("hw.psm.tap_enabled", &tap_enabled);
381
382static int synaptics_support = 0;
383TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
384
385static int trackpoint_support = 0;
386TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
387
388static int verbose = PSM_DEBUG;
389TUNABLE_INT("debug.psm.loglevel", &verbose);
390
391/* for backward compatibility */
392#define	OLD_MOUSE_GETHWINFO	_IOR('M', 1, old_mousehw_t)
393#define	OLD_MOUSE_GETMODE	_IOR('M', 2, old_mousemode_t)
394#define	OLD_MOUSE_SETMODE	_IOW('M', 3, old_mousemode_t)
395
396typedef struct old_mousehw {
397	int	buttons;
398	int	iftype;
399	int	type;
400	int	hwid;
401} old_mousehw_t;
402
403typedef struct old_mousemode {
404	int	protocol;
405	int	rate;
406	int	resolution;
407	int	accelfactor;
408} old_mousemode_t;
409
410/* packet formatting function */
411typedef int	packetfunc_t(struct psm_softc *, u_char *, int *, int,
412    mousestatus_t *);
413
414/* function prototypes */
415static void	psmidentify(driver_t *, device_t);
416static int	psmprobe(device_t);
417static int	psmattach(device_t);
418static int	psmdetach(device_t);
419static int	psmresume(device_t);
420
421static d_open_t		psmopen;
422static d_close_t	psmclose;
423static d_read_t		psmread;
424static d_write_t	psmwrite;
425static d_ioctl_t	psmioctl;
426static d_poll_t		psmpoll;
427
428static int	enable_aux_dev(KBDC);
429static int	disable_aux_dev(KBDC);
430static int	get_mouse_status(KBDC, int *, int, int);
431static int	get_aux_id(KBDC);
432static int	set_mouse_sampling_rate(KBDC, int);
433static int	set_mouse_scaling(KBDC, int);
434static int	set_mouse_resolution(KBDC, int);
435static int	set_mouse_mode(KBDC);
436static int	get_mouse_buttons(KBDC);
437static int	is_a_mouse(int);
438static void	recover_from_error(KBDC);
439static int	restore_controller(KBDC, int);
440static int	doinitialize(struct psm_softc *, mousemode_t *);
441static int	doopen(struct psm_softc *, int);
442static int	reinitialize(struct psm_softc *, int);
443static char	*model_name(int);
444static void	psmsoftintr(void *);
445static void	psmintr(void *);
446static void	psmtimeout(void *);
447static int	timeelapsed(const struct timeval *, int, int,
448		    const struct timeval *);
449static void	dropqueue(struct psm_softc *);
450static void	flushpackets(struct psm_softc *);
451static void	proc_mmanplus(struct psm_softc *, packetbuf_t *,
452		    mousestatus_t *, int *, int *, int *);
453static int	proc_synaptics(struct psm_softc *, packetbuf_t *,
454		    mousestatus_t *, int *, int *, int *);
455static void	proc_versapad(struct psm_softc *, packetbuf_t *,
456		    mousestatus_t *, int *, int *, int *);
457static int	tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
458		    u_char *);
459
460/* vendor specific features */
461typedef int	probefunc_t(KBDC, struct psm_softc *);
462
463static int	mouse_id_proc1(KBDC, int, int, int *);
464static int	mouse_ext_command(KBDC, int);
465
466static probefunc_t	enable_groller;
467static probefunc_t	enable_gmouse;
468static probefunc_t	enable_aglide;
469static probefunc_t	enable_kmouse;
470static probefunc_t	enable_msexplorer;
471static probefunc_t	enable_msintelli;
472static probefunc_t	enable_4dmouse;
473static probefunc_t	enable_4dplus;
474static probefunc_t	enable_mmanplus;
475static probefunc_t	enable_synaptics;
476static probefunc_t	enable_trackpoint;
477static probefunc_t	enable_versapad;
478
479static void set_trackpoint_parameters(struct psm_softc *sc);
480static void synaptics_passthrough_on(struct psm_softc *sc);
481static void synaptics_passthrough_off(struct psm_softc *sc);
482
483static struct {
484	int		model;
485	u_char		syncmask;
486	int		packetsize;
487	probefunc_t	*probefunc;
488} vendortype[] = {
489	/*
490	 * WARNING: the order of probe is very important.  Don't mess it
491	 * unless you know what you are doing.
492	 */
493	{ MOUSE_MODEL_NET,		/* Genius NetMouse */
494	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse },
495	{ MOUSE_MODEL_NETSCROLL,	/* Genius NetScroll */
496	  0xc8, 6, enable_groller },
497	{ MOUSE_MODEL_MOUSEMANPLUS,	/* Logitech MouseMan+ */
498	  0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus },
499	{ MOUSE_MODEL_EXPLORER,		/* Microsoft IntelliMouse Explorer */
500	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer },
501	{ MOUSE_MODEL_4D,		/* A4 Tech 4D Mouse */
502	  0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse },
503	{ MOUSE_MODEL_4DPLUS,		/* A4 Tech 4D+ Mouse */
504	  0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
505	{ MOUSE_MODEL_SYNAPTICS,	/* Synaptics Touchpad */
506	  0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
507	{ MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
508	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
509	{ MOUSE_MODEL_GLIDEPOINT,	/* ALPS GlidePoint */
510	  0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide },
511	{ MOUSE_MODEL_THINK,		/* Kensington ThinkingMouse */
512	  0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
513	{ MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
514	  0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
515	{ MOUSE_MODEL_TRACKPOINT,	/* IBM/Lenovo TrackPoint */
516	  0xc0, MOUSE_PS2_PACKETSIZE, enable_trackpoint },
517	{ MOUSE_MODEL_GENERIC,
518	  0xc0, MOUSE_PS2_PACKETSIZE, NULL },
519};
520#define	GENERIC_MOUSE_ENTRY	\
521    ((sizeof(vendortype) / sizeof(*vendortype)) - 1)
522
523/* device driver declarateion */
524static device_method_t psm_methods[] = {
525	/* Device interface */
526	DEVMETHOD(device_identify,	psmidentify),
527	DEVMETHOD(device_probe,		psmprobe),
528	DEVMETHOD(device_attach,	psmattach),
529	DEVMETHOD(device_detach,	psmdetach),
530	DEVMETHOD(device_resume,	psmresume),
531
532	{ 0, 0 }
533};
534
535static driver_t psm_driver = {
536	PSM_DRIVER_NAME,
537	psm_methods,
538	sizeof(struct psm_softc),
539};
540
541static struct cdevsw psm_cdevsw = {
542	.d_version =	D_VERSION,
543	.d_flags =	D_NEEDGIANT,
544	.d_open =	psmopen,
545	.d_close =	psmclose,
546	.d_read =	psmread,
547	.d_write =	psmwrite,
548	.d_ioctl =	psmioctl,
549	.d_poll =	psmpoll,
550	.d_name =	PSM_DRIVER_NAME,
551};
552
553/* device I/O routines */
554static int
555enable_aux_dev(KBDC kbdc)
556{
557	int res;
558
559	res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
560	VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res));
561
562	return (res == PSM_ACK);
563}
564
565static int
566disable_aux_dev(KBDC kbdc)
567{
568	int res;
569
570	res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
571	VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res));
572
573	return (res == PSM_ACK);
574}
575
576static int
577get_mouse_status(KBDC kbdc, int *status, int flag, int len)
578{
579	int cmd;
580	int res;
581	int i;
582
583	switch (flag) {
584	case 0:
585	default:
586		cmd = PSMC_SEND_DEV_STATUS;
587		break;
588	case 1:
589		cmd = PSMC_SEND_DEV_DATA;
590		break;
591	}
592	empty_aux_buffer(kbdc, 5);
593	res = send_aux_command(kbdc, cmd);
594	VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
595	    (flag == 1) ? "DATA" : "STATUS", res));
596	if (res != PSM_ACK)
597		return (0);
598
599	for (i = 0; i < len; ++i) {
600		status[i] = read_aux_data(kbdc);
601		if (status[i] < 0)
602			break;
603	}
604
605	VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n",
606	    (flag == 1) ? "data" : "status", status[0], status[1], status[2]));
607
608	return (i);
609}
610
611static int
612get_aux_id(KBDC kbdc)
613{
614	int res;
615	int id;
616
617	empty_aux_buffer(kbdc, 5);
618	res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
619	VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res));
620	if (res != PSM_ACK)
621		return (-1);
622
623	/* 10ms delay */
624	DELAY(10000);
625
626	id = read_aux_data(kbdc);
627	VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id));
628
629	return (id);
630}
631
632static int
633set_mouse_sampling_rate(KBDC kbdc, int rate)
634{
635	int res;
636
637	res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
638	VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res));
639
640	return ((res == PSM_ACK) ? rate : -1);
641}
642
643static int
644set_mouse_scaling(KBDC kbdc, int scale)
645{
646	int res;
647
648	switch (scale) {
649	case 1:
650	default:
651		scale = PSMC_SET_SCALING11;
652		break;
653	case 2:
654		scale = PSMC_SET_SCALING21;
655		break;
656	}
657	res = send_aux_command(kbdc, scale);
658	VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
659	    (scale == PSMC_SET_SCALING21) ? "21" : "11", res));
660
661	return (res == PSM_ACK);
662}
663
664/* `val' must be 0 through PSMD_MAX_RESOLUTION */
665static int
666set_mouse_resolution(KBDC kbdc, int val)
667{
668	int res;
669
670	res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
671	VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res));
672
673	return ((res == PSM_ACK) ? val : -1);
674}
675
676/*
677 * NOTE: once `set_mouse_mode()' is called, the mouse device must be
678 * re-enabled by calling `enable_aux_dev()'
679 */
680static int
681set_mouse_mode(KBDC kbdc)
682{
683	int res;
684
685	res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
686	VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res));
687
688	return (res == PSM_ACK);
689}
690
691static int
692get_mouse_buttons(KBDC kbdc)
693{
694	int c = 2;		/* assume two buttons by default */
695	int status[3];
696
697	/*
698	 * NOTE: a special sequence to obtain Logitech Mouse specific
699	 * information: set resolution to 25 ppi, set scaling to 1:1, set
700	 * scaling to 1:1, set scaling to 1:1. Then the second byte of the
701	 * mouse status bytes is the number of available buttons.
702	 * Some manufactures also support this sequence.
703	 */
704	if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
705		return (c);
706	if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) &&
707	    set_mouse_scaling(kbdc, 1) &&
708	    get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0)
709		return (status[1]);
710	return (c);
711}
712
713/* misc subroutines */
714/*
715 * Someday, I will get the complete list of valid pointing devices and
716 * their IDs... XXX
717 */
718static int
719is_a_mouse(int id)
720{
721#if 0
722	static int valid_ids[] = {
723		PSM_MOUSE_ID,		/* mouse */
724		PSM_BALLPOINT_ID,	/* ballpoint device */
725		PSM_INTELLI_ID,		/* Intellimouse */
726		PSM_EXPLORER_ID,	/* Intellimouse Explorer */
727		-1			/* end of table */
728	};
729	int i;
730
731	for (i = 0; valid_ids[i] >= 0; ++i)
732	if (valid_ids[i] == id)
733		return (TRUE);
734	return (FALSE);
735#else
736	return (TRUE);
737#endif
738}
739
740static char *
741model_name(int model)
742{
743	static struct {
744		int	model_code;
745		char	*model_name;
746	} models[] = {
747		{ MOUSE_MODEL_NETSCROLL,	"NetScroll" },
748		{ MOUSE_MODEL_NET,		"NetMouse/NetScroll Optical" },
749		{ MOUSE_MODEL_GLIDEPOINT,	"GlidePoint" },
750		{ MOUSE_MODEL_THINK,		"ThinkingMouse" },
751		{ MOUSE_MODEL_INTELLI,		"IntelliMouse" },
752		{ MOUSE_MODEL_MOUSEMANPLUS,	"MouseMan+" },
753		{ MOUSE_MODEL_VERSAPAD,		"VersaPad" },
754		{ MOUSE_MODEL_EXPLORER,		"IntelliMouse Explorer" },
755		{ MOUSE_MODEL_4D,		"4D Mouse" },
756		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
757		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
758		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
759		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
760		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
761	};
762	int i;
763
764	for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i)
765		if (models[i].model_code == model)
766			break;
767	return (models[i].model_name);
768}
769
770static void
771recover_from_error(KBDC kbdc)
772{
773	/* discard anything left in the output buffer */
774	empty_both_buffers(kbdc, 10);
775
776#if 0
777	/*
778	 * NOTE: KBDC_RESET_KBD may not restore the communication between the
779	 * keyboard and the controller.
780	 */
781	reset_kbd(kbdc);
782#else
783	/*
784	 * NOTE: somehow diagnostic and keyboard port test commands bring the
785	 * keyboard back.
786	 */
787	if (!test_controller(kbdc))
788		log(LOG_ERR, "psm: keyboard controller failed.\n");
789	/* if there isn't a keyboard in the system, the following error is OK */
790	if (test_kbd_port(kbdc) != 0)
791		VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n"));
792#endif
793}
794
795static int
796restore_controller(KBDC kbdc, int command_byte)
797{
798	empty_both_buffers(kbdc, 10);
799
800	if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
801		log(LOG_ERR, "psm: failed to restore the keyboard controller "
802		    "command byte.\n");
803		empty_both_buffers(kbdc, 10);
804		return (FALSE);
805	} else {
806		empty_both_buffers(kbdc, 10);
807		return (TRUE);
808	}
809}
810
811/*
812 * Re-initialize the aux port and device. The aux port must be enabled
813 * and its interrupt must be disabled before calling this routine.
814 * The aux device will be disabled before returning.
815 * The keyboard controller must be locked via `kbdc_lock()' before
816 * calling this routine.
817 */
818static int
819doinitialize(struct psm_softc *sc, mousemode_t *mode)
820{
821	KBDC kbdc = sc->kbdc;
822	int stat[3];
823	int i;
824
825	switch((i = test_aux_port(kbdc))) {
826	case 1:	/* ignore these errors */
827	case 2:
828	case 3:
829	case PSM_ACK:
830		if (verbose)
831			log(LOG_DEBUG,
832			    "psm%d: strange result for test aux port (%d).\n",
833			    sc->unit, i);
834		/* FALLTHROUGH */
835	case 0:		/* no error */
836		break;
837	case -1:	/* time out */
838	default:	/* error */
839		recover_from_error(kbdc);
840		if (sc->config & PSM_CONFIG_IGNPORTERROR)
841			break;
842		log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
843		    sc->unit, i);
844		return (FALSE);
845	}
846
847	if (sc->config & PSM_CONFIG_NORESET) {
848		/*
849		 * Don't try to reset the pointing device.  It may possibly
850		 * be left in the unknown state, though...
851		 */
852	} else {
853		/*
854		 * NOTE: some controllers appears to hang the `keyboard' when
855		 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
856		 */
857		if (!reset_aux_dev(kbdc)) {
858			recover_from_error(kbdc);
859			log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
860			    sc->unit);
861			return (FALSE);
862		}
863	}
864
865	/*
866	 * both the aux port and the aux device is functioning, see
867	 * if the device can be enabled.
868	 */
869	if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
870		log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
871		    sc->unit);
872		return (FALSE);
873	}
874	empty_both_buffers(kbdc, 10);	/* remove stray data if any */
875
876	/* Re-enable the mouse. */
877	for (i = 0; vendortype[i].probefunc != NULL; ++i)
878		if (vendortype[i].model == sc->hw.model)
879			(*vendortype[i].probefunc)(sc->kbdc, NULL);
880
881	/* set mouse parameters */
882	if (mode != (mousemode_t *)NULL) {
883		if (mode->rate > 0)
884			mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
885		if (mode->resolution >= 0)
886			mode->resolution =
887			    set_mouse_resolution(kbdc, mode->resolution);
888		set_mouse_scaling(kbdc, 1);
889		set_mouse_mode(kbdc);
890
891		/*
892		 * Trackpoint settings are lost on resume.
893		 * Restore them here.
894		 */
895		if (sc->tphw > 0)
896			set_trackpoint_parameters(sc);
897	}
898
899	/* Record sync on the next data packet we see. */
900	sc->flags |= PSM_NEED_SYNCBITS;
901
902	/* just check the status of the mouse */
903	if (get_mouse_status(kbdc, stat, 0, 3) < 3)
904		log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
905		    sc->unit);
906
907	return (TRUE);
908}
909
910static int
911doopen(struct psm_softc *sc, int command_byte)
912{
913	int stat[3];
914
915	/*
916	 * FIXME: Synaptics TouchPad seems to go back to Relative Mode with
917	 * no obvious reason. Thus we check the current mode and restore the
918	 * Absolute Mode if it was cleared.
919	 *
920	 * The previous hack at the end of psmprobe() wasn't efficient when
921	 * moused(8) was restarted.
922	 *
923	 * A Reset (FF) or Set Defaults (F6) command would clear the
924	 * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5
925	 * doesn't show any evidence of such a command.
926	 */
927	if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
928		mouse_ext_command(sc->kbdc, 1);
929		get_mouse_status(sc->kbdc, stat, 0, 3);
930		if ((SYNAPTICS_VERSION_GE(sc->synhw, 7, 5) ||
931		     stat[1] == 0x47) &&
932		    stat[2] == 0x40) {
933			/* Set the mode byte -- request wmode where
934			 * available */
935			if (sc->synhw.capExtended)
936				mouse_ext_command(sc->kbdc, 0xc1);
937			else
938				mouse_ext_command(sc->kbdc, 0xc0);
939			set_mouse_sampling_rate(sc->kbdc, 20);
940			VLOG(5, (LOG_DEBUG, "psm%d: Synaptis Absolute Mode "
941			    "hopefully restored\n",
942			    sc->unit));
943		}
944	}
945
946	/*
947	 * A user may want to disable tap and drag gestures on a Synaptics
948	 * TouchPad when it operates in Relative Mode.
949	 */
950	if (sc->hw.model == MOUSE_MODEL_GENERIC) {
951		if (tap_enabled > 0) {
952			/*
953			 * Enable tap & drag gestures. We use a Mode Byte
954			 * and clear the DisGest bit (see ��2.5 of Synaptics
955			 * TouchPad Interfacing Guide).
956			 */
957			VLOG(2, (LOG_DEBUG,
958			    "psm%d: enable tap and drag gestures\n",
959			    sc->unit));
960			mouse_ext_command(sc->kbdc, 0x00);
961			set_mouse_sampling_rate(sc->kbdc, 20);
962		} else if (tap_enabled == 0) {
963			/*
964			 * Disable tap & drag gestures. We use a Mode Byte
965			 * and set the DisGest bit (see ��2.5 of Synaptics
966			 * TouchPad Interfacing Guide).
967			 */
968			VLOG(2, (LOG_DEBUG,
969			    "psm%d: disable tap and drag gestures\n",
970			    sc->unit));
971			mouse_ext_command(sc->kbdc, 0x04);
972			set_mouse_sampling_rate(sc->kbdc, 20);
973		}
974	}
975
976	/* enable the mouse device */
977	if (!enable_aux_dev(sc->kbdc)) {
978		/* MOUSE ERROR: failed to enable the mouse because:
979		 * 1) the mouse is faulty,
980		 * 2) the mouse has been removed(!?)
981		 * In the latter case, the keyboard may have hung, and need
982		 * recovery procedure...
983		 */
984		recover_from_error(sc->kbdc);
985#if 0
986		/* FIXME: we could reset the mouse here and try to enable
987		 * it again. But it will take long time and it's not a good
988		 * idea to disable the keyboard that long...
989		 */
990		if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
991			recover_from_error(sc->kbdc);
992#else
993		{
994#endif
995			restore_controller(sc->kbdc, command_byte);
996			/* mark this device is no longer available */
997			sc->state &= ~PSM_VALID;
998			log(LOG_ERR,
999			    "psm%d: failed to enable the device (doopen).\n",
1000			sc->unit);
1001			return (EIO);
1002		}
1003	}
1004
1005	if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1006		log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n",
1007		    sc->unit);
1008
1009	/* enable the aux port and interrupt */
1010	if (!set_controller_command_byte(sc->kbdc,
1011	    kbdc_get_device_mask(sc->kbdc),
1012	    (command_byte & KBD_KBD_CONTROL_BITS) |
1013	    KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
1014		/* CONTROLLER ERROR */
1015		disable_aux_dev(sc->kbdc);
1016		restore_controller(sc->kbdc, command_byte);
1017		log(LOG_ERR,
1018		    "psm%d: failed to enable the aux interrupt (doopen).\n",
1019		    sc->unit);
1020		return (EIO);
1021	}
1022
1023	/* start the watchdog timer */
1024	sc->watchdog = FALSE;
1025	callout_reset(&sc->callout, hz * 2, psmtimeout, sc);
1026
1027	return (0);
1028}
1029
1030static int
1031reinitialize(struct psm_softc *sc, int doinit)
1032{
1033	int err;
1034	int c;
1035	int s;
1036
1037	/* don't let anybody mess with the aux device */
1038	if (!kbdc_lock(sc->kbdc, TRUE))
1039		return (EIO);
1040	s = spltty();
1041
1042	/* block our watchdog timer */
1043	sc->watchdog = FALSE;
1044	callout_stop(&sc->callout);
1045
1046	/* save the current controller command byte */
1047	empty_both_buffers(sc->kbdc, 10);
1048	c = get_controller_command_byte(sc->kbdc);
1049	VLOG(2, (LOG_DEBUG,
1050	    "psm%d: current command byte: %04x (reinitialize).\n",
1051	    sc->unit, c));
1052
1053	/* enable the aux port but disable the aux interrupt and the keyboard */
1054	if ((c == -1) || !set_controller_command_byte(sc->kbdc,
1055	    kbdc_get_device_mask(sc->kbdc),
1056	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1057	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1058		/* CONTROLLER ERROR */
1059		splx(s);
1060		kbdc_lock(sc->kbdc, FALSE);
1061		log(LOG_ERR,
1062		    "psm%d: unable to set the command byte (reinitialize).\n",
1063		    sc->unit);
1064		return (EIO);
1065	}
1066
1067	/* flush any data */
1068	if (sc->state & PSM_VALID) {
1069		/* this may fail; but never mind... */
1070		disable_aux_dev(sc->kbdc);
1071		empty_aux_buffer(sc->kbdc, 10);
1072	}
1073	flushpackets(sc);
1074	sc->syncerrors = 0;
1075	sc->pkterrors = 0;
1076	memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr));
1077
1078	/* try to detect the aux device; are you still there? */
1079	err = 0;
1080	if (doinit) {
1081		if (doinitialize(sc, &sc->mode)) {
1082			/* yes */
1083			sc->state |= PSM_VALID;
1084		} else {
1085			/* the device has gone! */
1086			restore_controller(sc->kbdc, c);
1087			sc->state &= ~PSM_VALID;
1088			log(LOG_ERR,
1089			    "psm%d: the aux device has gone! (reinitialize).\n",
1090			    sc->unit);
1091			err = ENXIO;
1092		}
1093	}
1094	splx(s);
1095
1096	/* restore the driver state */
1097	if ((sc->state & PSM_OPEN) && (err == 0)) {
1098		/* enable the aux device and the port again */
1099		err = doopen(sc, c);
1100		if (err != 0)
1101			log(LOG_ERR, "psm%d: failed to enable the device "
1102			    "(reinitialize).\n", sc->unit);
1103	} else {
1104		/* restore the keyboard port and disable the aux port */
1105		if (!set_controller_command_byte(sc->kbdc,
1106		    kbdc_get_device_mask(sc->kbdc),
1107		    (c & KBD_KBD_CONTROL_BITS) |
1108		    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1109			/* CONTROLLER ERROR */
1110			log(LOG_ERR, "psm%d: failed to disable the aux port "
1111			    "(reinitialize).\n", sc->unit);
1112			err = EIO;
1113		}
1114	}
1115
1116	kbdc_lock(sc->kbdc, FALSE);
1117	return (err);
1118}
1119
1120/* psm driver entry points */
1121
1122static void
1123psmidentify(driver_t *driver, device_t parent)
1124{
1125	device_t psmc;
1126	device_t psm;
1127	u_long irq;
1128	int unit;
1129
1130	unit = device_get_unit(parent);
1131
1132	/* always add at least one child */
1133	psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit);
1134	if (psm == NULL)
1135		return;
1136
1137	irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX);
1138	if (irq > 0)
1139		return;
1140
1141	/*
1142	 * If the PS/2 mouse device has already been reported by ACPI or
1143	 * PnP BIOS, obtain the IRQ resource from it.
1144	 * (See psmcpnp_attach() below.)
1145	 */
1146	psmc = device_find_child(device_get_parent(parent),
1147	    PSMCPNP_DRIVER_NAME, unit);
1148	if (psmc == NULL)
1149		return;
1150	irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0);
1151	if (irq <= 0)
1152		return;
1153	bus_delete_resource(psmc, SYS_RES_IRQ, 0);
1154	bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
1155}
1156
1157#define	endprobe(v)	do {			\
1158	if (bootverbose)			\
1159		--verbose;			\
1160	kbdc_set_device_mask(sc->kbdc, mask);	\
1161	kbdc_lock(sc->kbdc, FALSE);		\
1162	return (v);				\
1163} while (0)
1164
1165static int
1166psmprobe(device_t dev)
1167{
1168	int unit = device_get_unit(dev);
1169	struct psm_softc *sc = device_get_softc(dev);
1170	int stat[3];
1171	int command_byte;
1172	int mask;
1173	int rid;
1174	int i;
1175
1176#if 0
1177	kbdc_debug(TRUE);
1178#endif
1179
1180	/* see if IRQ is available */
1181	rid = KBDC_RID_AUX;
1182	sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1183	if (sc->intr == NULL) {
1184		if (bootverbose)
1185			device_printf(dev, "unable to allocate IRQ\n");
1186		return (ENXIO);
1187	}
1188	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1189
1190	sc->unit = unit;
1191	sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
1192	sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS;
1193	/* XXX: for backward compatibility */
1194#if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
1195	sc->config |=
1196#ifdef PSM_RESETAFTERSUSPEND
1197	PSM_CONFIG_INITAFTERSUSPEND;
1198#else
1199	PSM_CONFIG_HOOKRESUME;
1200#endif
1201#endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
1202	sc->flags = 0;
1203	if (bootverbose)
1204		++verbose;
1205
1206	device_set_desc(dev, "PS/2 Mouse");
1207
1208	if (!kbdc_lock(sc->kbdc, TRUE)) {
1209		printf("psm%d: unable to lock the controller.\n", unit);
1210		if (bootverbose)
1211			--verbose;
1212		return (ENXIO);
1213	}
1214
1215	/*
1216	 * NOTE: two bits in the command byte controls the operation of the
1217	 * aux port (mouse port): the aux port disable bit (bit 5) and the aux
1218	 * port interrupt (IRQ 12) enable bit (bit 2).
1219	 */
1220
1221	/* discard anything left after the keyboard initialization */
1222	empty_both_buffers(sc->kbdc, 10);
1223
1224	/* save the current command byte; it will be used later */
1225	mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
1226	command_byte = get_controller_command_byte(sc->kbdc);
1227	if (verbose)
1228		printf("psm%d: current command byte:%04x\n", unit,
1229		    command_byte);
1230	if (command_byte == -1) {
1231		/* CONTROLLER ERROR */
1232		printf("psm%d: unable to get the current command byte value.\n",
1233			unit);
1234		endprobe(ENXIO);
1235	}
1236
1237	/*
1238	 * disable the keyboard port while probing the aux port, which must be
1239	 * enabled during this routine
1240	 */
1241	if (!set_controller_command_byte(sc->kbdc,
1242	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1243	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1244	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1245		/*
1246		 * this is CONTROLLER ERROR; I don't know how to recover
1247		 * from this error...
1248		 */
1249		restore_controller(sc->kbdc, command_byte);
1250		printf("psm%d: unable to set the command byte.\n", unit);
1251		endprobe(ENXIO);
1252	}
1253	write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
1254
1255	/*
1256	 * NOTE: `test_aux_port()' is designed to return with zero if the aux
1257	 * port exists and is functioning. However, some controllers appears
1258	 * to respond with zero even when the aux port doesn't exist. (It may
1259	 * be that this is only the case when the controller DOES have the aux
1260	 * port but the port is not wired on the motherboard.) The keyboard
1261	 * controllers without the port, such as the original AT, are
1262	 * supposed to return with an error code or simply time out. In any
1263	 * case, we have to continue probing the port even when the controller
1264	 * passes this test.
1265	 *
1266	 * XXX: some controllers erroneously return the error code 1, 2 or 3
1267	 * when it has a perfectly functional aux port. We have to ignore
1268	 * this error code. Even if the controller HAS error with the aux
1269	 * port, it will be detected later...
1270	 * XXX: another incompatible controller returns PSM_ACK (0xfa)...
1271	 */
1272	switch ((i = test_aux_port(sc->kbdc))) {
1273	case 1:		/* ignore these errors */
1274	case 2:
1275	case 3:
1276	case PSM_ACK:
1277		if (verbose)
1278			printf("psm%d: strange result for test aux port "
1279			    "(%d).\n", unit, i);
1280		/* FALLTHROUGH */
1281	case 0:		/* no error */
1282		break;
1283	case -1:	/* time out */
1284	default:	/* error */
1285		recover_from_error(sc->kbdc);
1286		if (sc->config & PSM_CONFIG_IGNPORTERROR)
1287			break;
1288		restore_controller(sc->kbdc, command_byte);
1289		if (verbose)
1290			printf("psm%d: the aux port is not functioning (%d).\n",
1291			    unit, i);
1292		endprobe(ENXIO);
1293	}
1294
1295	if (sc->config & PSM_CONFIG_NORESET) {
1296		/*
1297		 * Don't try to reset the pointing device.  It may possibly be
1298		 * left in an unknown state, though...
1299		 */
1300	} else {
1301		/*
1302		 * NOTE: some controllers appears to hang the `keyboard' when
1303		 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
1304		 *
1305		 * Attempt to reset the controller twice -- this helps
1306		 * pierce through some KVM switches. The second reset
1307		 * is non-fatal.
1308		 */
1309		if (!reset_aux_dev(sc->kbdc)) {
1310			recover_from_error(sc->kbdc);
1311			restore_controller(sc->kbdc, command_byte);
1312			if (verbose)
1313				printf("psm%d: failed to reset the aux "
1314				    "device.\n", unit);
1315			endprobe(ENXIO);
1316		} else if (!reset_aux_dev(sc->kbdc)) {
1317			recover_from_error(sc->kbdc);
1318			if (verbose >= 2)
1319				printf("psm%d: failed to reset the aux device "
1320				    "(2).\n", unit);
1321		}
1322	}
1323
1324	/*
1325	 * both the aux port and the aux device are functioning, see if the
1326	 * device can be enabled. NOTE: when enabled, the device will start
1327	 * sending data; we shall immediately disable the device once we know
1328	 * the device can be enabled.
1329	 */
1330	if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
1331		/* MOUSE ERROR */
1332		recover_from_error(sc->kbdc);
1333		restore_controller(sc->kbdc, command_byte);
1334		if (verbose)
1335			printf("psm%d: failed to enable the aux device.\n",
1336			    unit);
1337		endprobe(ENXIO);
1338	}
1339
1340	/* save the default values after reset */
1341	if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
1342		sc->dflt_mode.rate = sc->mode.rate = stat[2];
1343		sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1344	} else {
1345		sc->dflt_mode.rate = sc->mode.rate = -1;
1346		sc->dflt_mode.resolution = sc->mode.resolution = -1;
1347	}
1348
1349	/* hardware information */
1350	sc->hw.iftype = MOUSE_IF_PS2;
1351
1352	/* verify the device is a mouse */
1353	sc->hw.hwid = get_aux_id(sc->kbdc);
1354	if (!is_a_mouse(sc->hw.hwid)) {
1355		restore_controller(sc->kbdc, command_byte);
1356		if (verbose)
1357			printf("psm%d: unknown device type (%d).\n", unit,
1358			    sc->hw.hwid);
1359		endprobe(ENXIO);
1360	}
1361	switch (sc->hw.hwid) {
1362	case PSM_BALLPOINT_ID:
1363		sc->hw.type = MOUSE_TRACKBALL;
1364		break;
1365	case PSM_MOUSE_ID:
1366	case PSM_INTELLI_ID:
1367	case PSM_EXPLORER_ID:
1368	case PSM_4DMOUSE_ID:
1369	case PSM_4DPLUS_ID:
1370		sc->hw.type = MOUSE_MOUSE;
1371		break;
1372	default:
1373		sc->hw.type = MOUSE_UNKNOWN;
1374		break;
1375	}
1376
1377	if (sc->config & PSM_CONFIG_NOIDPROBE) {
1378		sc->hw.buttons = 2;
1379		i = GENERIC_MOUSE_ENTRY;
1380	} else {
1381		/* # of buttons */
1382		sc->hw.buttons = get_mouse_buttons(sc->kbdc);
1383
1384		/* other parameters */
1385		for (i = 0; vendortype[i].probefunc != NULL; ++i)
1386			if ((*vendortype[i].probefunc)(sc->kbdc, sc)) {
1387				if (verbose >= 2)
1388					printf("psm%d: found %s\n", unit,
1389					    model_name(vendortype[i].model));
1390				break;
1391			}
1392	}
1393
1394	sc->hw.model = vendortype[i].model;
1395
1396	sc->dflt_mode.level = PSM_LEVEL_BASE;
1397	sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
1398	sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
1399	if (sc->config & PSM_CONFIG_NOCHECKSYNC)
1400		sc->dflt_mode.syncmask[0] = 0;
1401	else
1402		sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
1403	if (sc->config & PSM_CONFIG_FORCETAP)
1404		sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP;
1405	sc->dflt_mode.syncmask[1] = 0;	/* syncbits */
1406	sc->mode = sc->dflt_mode;
1407	sc->mode.packetsize = vendortype[i].packetsize;
1408
1409	/* set mouse parameters */
1410#if 0
1411	/*
1412	 * A version of Logitech FirstMouse+ won't report wheel movement,
1413	 * if SET_DEFAULTS is sent...  Don't use this command.
1414	 * This fix was found by Takashi Nishida.
1415	 */
1416	i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
1417	if (verbose >= 2)
1418		printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
1419#endif
1420	if (sc->config & PSM_CONFIG_RESOLUTION)
1421		sc->mode.resolution =
1422		    set_mouse_resolution(sc->kbdc,
1423		    (sc->config & PSM_CONFIG_RESOLUTION) - 1);
1424	else if (sc->mode.resolution >= 0)
1425		sc->mode.resolution =
1426		    set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
1427	if (sc->mode.rate > 0)
1428		sc->mode.rate =
1429		    set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
1430	set_mouse_scaling(sc->kbdc, 1);
1431
1432	/* Record sync on the next data packet we see. */
1433	sc->flags |= PSM_NEED_SYNCBITS;
1434
1435	/* just check the status of the mouse */
1436	/*
1437	 * NOTE: XXX there are some arcane controller/mouse combinations out
1438	 * there, which hung the controller unless there is data transmission
1439	 * after ACK from the mouse.
1440	 */
1441	if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1442		printf("psm%d: failed to get status.\n", unit);
1443	else {
1444		/*
1445		 * When in its native mode, some mice operate with different
1446		 * default parameters than in the PS/2 compatible mode.
1447		 */
1448		sc->dflt_mode.rate = sc->mode.rate = stat[2];
1449		sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1450	}
1451
1452	/* disable the aux port for now... */
1453	if (!set_controller_command_byte(sc->kbdc,
1454	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1455	    (command_byte & KBD_KBD_CONTROL_BITS) |
1456	    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1457		/*
1458		 * this is CONTROLLER ERROR; I don't know the proper way to
1459		 * recover from this error...
1460		 */
1461		restore_controller(sc->kbdc, command_byte);
1462		printf("psm%d: unable to set the command byte.\n", unit);
1463		endprobe(ENXIO);
1464	}
1465
1466	/* done */
1467	kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
1468	kbdc_lock(sc->kbdc, FALSE);
1469	return (0);
1470}
1471
1472static int
1473psmattach(device_t dev)
1474{
1475	int unit = device_get_unit(dev);
1476	struct psm_softc *sc = device_get_softc(dev);
1477	int error;
1478	int rid;
1479
1480	/* Setup initial state */
1481	sc->state = PSM_VALID;
1482	callout_init(&sc->callout, 0);
1483	callout_init(&sc->softcallout, 0);
1484
1485	/* Setup our interrupt handler */
1486	rid = KBDC_RID_AUX;
1487	sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1488	if (sc->intr == NULL)
1489		return (ENXIO);
1490	error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc,
1491	    &sc->ih);
1492	if (error) {
1493		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1494		return (error);
1495	}
1496
1497	/* Done */
1498	sc->dev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "psm%d", unit);
1499	sc->dev->si_drv1 = sc;
1500	sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit);
1501	sc->bdev->si_drv1 = sc;
1502
1503	/* Some touchpad devices need full reinitialization after suspend. */
1504	switch (sc->hw.model) {
1505	case MOUSE_MODEL_SYNAPTICS:
1506	case MOUSE_MODEL_GLIDEPOINT:
1507	case MOUSE_MODEL_VERSAPAD:
1508		sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1509		break;
1510	default:
1511		if (sc->synhw.infoMajor >= 4 || sc->tphw > 0)
1512			sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
1513		break;
1514	}
1515
1516	if (!verbose)
1517		printf("psm%d: model %s, device ID %d\n",
1518		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1519	else {
1520		printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
1521		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff,
1522		    sc->hw.hwid >> 8, sc->hw.buttons);
1523		printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
1524		    unit, sc->config, sc->flags, sc->mode.packetsize);
1525		printf("psm%d: syncmask:%02x, syncbits:%02x\n",
1526		    unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
1527	}
1528
1529	if (bootverbose)
1530		--verbose;
1531
1532	return (0);
1533}
1534
1535static int
1536psmdetach(device_t dev)
1537{
1538	struct psm_softc *sc;
1539	int rid;
1540
1541	sc = device_get_softc(dev);
1542	if (sc->state & PSM_OPEN)
1543		return (EBUSY);
1544
1545	rid = KBDC_RID_AUX;
1546	bus_teardown_intr(dev, sc->intr, sc->ih);
1547	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1548
1549	destroy_dev(sc->dev);
1550	destroy_dev(sc->bdev);
1551
1552	callout_drain(&sc->callout);
1553	callout_drain(&sc->softcallout);
1554
1555	return (0);
1556}
1557
1558static int
1559psmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
1560{
1561	struct psm_softc *sc;
1562	int command_byte;
1563	int err;
1564	int s;
1565
1566	/* Get device data */
1567	sc = dev->si_drv1;
1568	if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
1569		/* the device is no longer valid/functioning */
1570		return (ENXIO);
1571	}
1572
1573	/* Disallow multiple opens */
1574	if (sc->state & PSM_OPEN)
1575		return (EBUSY);
1576
1577	device_busy(devclass_get_device(psm_devclass, sc->unit));
1578
1579	/* Initialize state */
1580	sc->mode.level = sc->dflt_mode.level;
1581	sc->mode.protocol = sc->dflt_mode.protocol;
1582	sc->watchdog = FALSE;
1583	sc->async = NULL;
1584
1585	/* flush the event queue */
1586	sc->queue.count = 0;
1587	sc->queue.head = 0;
1588	sc->queue.tail = 0;
1589	sc->status.flags = 0;
1590	sc->status.button = 0;
1591	sc->status.obutton = 0;
1592	sc->status.dx = 0;
1593	sc->status.dy = 0;
1594	sc->status.dz = 0;
1595	sc->button = 0;
1596	sc->pqueue_start = 0;
1597	sc->pqueue_end = 0;
1598
1599	/* empty input buffer */
1600	flushpackets(sc);
1601	sc->syncerrors = 0;
1602	sc->pkterrors = 0;
1603
1604	/* don't let timeout routines in the keyboard driver to poll the kbdc */
1605	if (!kbdc_lock(sc->kbdc, TRUE))
1606		return (EIO);
1607
1608	/* save the current controller command byte */
1609	s = spltty();
1610	command_byte = get_controller_command_byte(sc->kbdc);
1611
1612	/* enable the aux port and temporalily disable the keyboard */
1613	if (command_byte == -1 || !set_controller_command_byte(sc->kbdc,
1614	    kbdc_get_device_mask(sc->kbdc),
1615	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1616	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1617		/* CONTROLLER ERROR; do you know how to get out of this? */
1618		kbdc_lock(sc->kbdc, FALSE);
1619		splx(s);
1620		log(LOG_ERR,
1621		    "psm%d: unable to set the command byte (psmopen).\n",
1622		    sc->unit);
1623		return (EIO);
1624	}
1625	/*
1626	 * Now that the keyboard controller is told not to generate
1627	 * the keyboard and mouse interrupts, call `splx()' to allow
1628	 * the other tty interrupts. The clock interrupt may also occur,
1629	 * but timeout routines will be blocked by the poll flag set
1630	 * via `kbdc_lock()'
1631	 */
1632	splx(s);
1633
1634	/* enable the mouse device */
1635	err = doopen(sc, command_byte);
1636
1637	/* done */
1638	if (err == 0)
1639		sc->state |= PSM_OPEN;
1640	kbdc_lock(sc->kbdc, FALSE);
1641	return (err);
1642}
1643
1644static int
1645psmclose(struct cdev *dev, int flag, int fmt, struct thread *td)
1646{
1647	struct psm_softc *sc = dev->si_drv1;
1648	int stat[3];
1649	int command_byte;
1650	int s;
1651
1652	/* don't let timeout routines in the keyboard driver to poll the kbdc */
1653	if (!kbdc_lock(sc->kbdc, TRUE))
1654		return (EIO);
1655
1656	/* save the current controller command byte */
1657	s = spltty();
1658	command_byte = get_controller_command_byte(sc->kbdc);
1659	if (command_byte == -1) {
1660		kbdc_lock(sc->kbdc, FALSE);
1661		splx(s);
1662		return (EIO);
1663	}
1664
1665	/* disable the aux interrupt and temporalily disable the keyboard */
1666	if (!set_controller_command_byte(sc->kbdc,
1667	    kbdc_get_device_mask(sc->kbdc),
1668	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1669	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1670		log(LOG_ERR,
1671		    "psm%d: failed to disable the aux int (psmclose).\n",
1672		    sc->unit);
1673		/* CONTROLLER ERROR;
1674		 * NOTE: we shall force our way through. Because the only
1675		 * ill effect we shall see is that we may not be able
1676		 * to read ACK from the mouse, and it doesn't matter much
1677		 * so long as the mouse will accept the DISABLE command.
1678		 */
1679	}
1680	splx(s);
1681
1682	/* stop the watchdog timer */
1683	callout_stop(&sc->callout);
1684
1685	/* remove anything left in the output buffer */
1686	empty_aux_buffer(sc->kbdc, 10);
1687
1688	/* disable the aux device, port and interrupt */
1689	if (sc->state & PSM_VALID) {
1690		if (!disable_aux_dev(sc->kbdc)) {
1691			/* MOUSE ERROR;
1692			 * NOTE: we don't return (error) and continue,
1693			 * pretending we have successfully disabled the device.
1694			 * It's OK because the interrupt routine will discard
1695			 * any data from the mouse hereafter.
1696			 */
1697			log(LOG_ERR,
1698			    "psm%d: failed to disable the device (psmclose).\n",
1699			    sc->unit);
1700		}
1701
1702		if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1703			log(LOG_DEBUG,
1704			    "psm%d: failed to get status (psmclose).\n",
1705			    sc->unit);
1706	}
1707
1708	if (!set_controller_command_byte(sc->kbdc,
1709	    kbdc_get_device_mask(sc->kbdc),
1710	    (command_byte & KBD_KBD_CONTROL_BITS) |
1711	    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1712		/*
1713		 * CONTROLLER ERROR;
1714		 * we shall ignore this error; see the above comment.
1715		 */
1716		log(LOG_ERR,
1717		    "psm%d: failed to disable the aux port (psmclose).\n",
1718		    sc->unit);
1719	}
1720
1721	/* remove anything left in the output buffer */
1722	empty_aux_buffer(sc->kbdc, 10);
1723
1724	/* clean up and sigio requests */
1725	if (sc->async != NULL) {
1726		funsetown(&sc->async);
1727		sc->async = NULL;
1728	}
1729
1730	/* close is almost always successful */
1731	sc->state &= ~PSM_OPEN;
1732	kbdc_lock(sc->kbdc, FALSE);
1733	device_unbusy(devclass_get_device(psm_devclass, sc->unit));
1734	return (0);
1735}
1736
1737static int
1738tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status,
1739    u_char *buf)
1740{
1741	static u_char butmapps2[8] = {
1742		0,
1743		MOUSE_PS2_BUTTON1DOWN,
1744		MOUSE_PS2_BUTTON2DOWN,
1745		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
1746		MOUSE_PS2_BUTTON3DOWN,
1747		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
1748		MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1749		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN |
1750		    MOUSE_PS2_BUTTON3DOWN,
1751	};
1752	static u_char butmapmsc[8] = {
1753		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP |
1754		    MOUSE_MSC_BUTTON3UP,
1755		MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1756		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1757		MOUSE_MSC_BUTTON3UP,
1758		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1759		MOUSE_MSC_BUTTON2UP,
1760		MOUSE_MSC_BUTTON1UP,
1761		0,
1762	};
1763	int mapped;
1764	int i;
1765
1766	if (sc->mode.level == PSM_LEVEL_BASE) {
1767		mapped = status->button & ~MOUSE_BUTTON4DOWN;
1768		if (status->button & MOUSE_BUTTON4DOWN)
1769			mapped |= MOUSE_BUTTON1DOWN;
1770		status->button = mapped;
1771		buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
1772		i = imax(imin(status->dx, 255), -256);
1773		if (i < 0)
1774			buf[0] |= MOUSE_PS2_XNEG;
1775		buf[1] = i;
1776		i = imax(imin(status->dy, 255), -256);
1777		if (i < 0)
1778			buf[0] |= MOUSE_PS2_YNEG;
1779		buf[2] = i;
1780		return (MOUSE_PS2_PACKETSIZE);
1781	} else if (sc->mode.level == PSM_LEVEL_STANDARD) {
1782		buf[0] = MOUSE_MSC_SYNC |
1783		    butmapmsc[status->button & MOUSE_STDBUTTONS];
1784		i = imax(imin(status->dx, 255), -256);
1785		buf[1] = i >> 1;
1786		buf[3] = i - buf[1];
1787		i = imax(imin(status->dy, 255), -256);
1788		buf[2] = i >> 1;
1789		buf[4] = i - buf[2];
1790		i = imax(imin(status->dz, 127), -128);
1791		buf[5] = (i >> 1) & 0x7f;
1792		buf[6] = (i - (i >> 1)) & 0x7f;
1793		buf[7] = (~status->button >> 3) & 0x7f;
1794		return (MOUSE_SYS_PACKETSIZE);
1795	}
1796	return (pb->inputbytes);
1797}
1798
1799static int
1800psmread(struct cdev *dev, struct uio *uio, int flag)
1801{
1802	struct psm_softc *sc = dev->si_drv1;
1803	u_char buf[PSM_SMALLBUFSIZE];
1804	int error = 0;
1805	int s;
1806	int l;
1807
1808	if ((sc->state & PSM_VALID) == 0)
1809		return (EIO);
1810
1811	/* block until mouse activity occured */
1812	s = spltty();
1813	while (sc->queue.count <= 0) {
1814		if (dev != sc->bdev) {
1815			splx(s);
1816			return (EWOULDBLOCK);
1817		}
1818		sc->state |= PSM_ASLP;
1819		error = tsleep(sc, PZERO | PCATCH, "psmrea", 0);
1820		sc->state &= ~PSM_ASLP;
1821		if (error) {
1822			splx(s);
1823			return (error);
1824		} else if ((sc->state & PSM_VALID) == 0) {
1825			/* the device disappeared! */
1826			splx(s);
1827			return (EIO);
1828		}
1829	}
1830	splx(s);
1831
1832	/* copy data to the user land */
1833	while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
1834		s = spltty();
1835		l = imin(sc->queue.count, uio->uio_resid);
1836		if (l > sizeof(buf))
1837			l = sizeof(buf);
1838		if (l > sizeof(sc->queue.buf) - sc->queue.head) {
1839			bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
1840			    sizeof(sc->queue.buf) - sc->queue.head);
1841			bcopy(&sc->queue.buf[0],
1842			    &buf[sizeof(sc->queue.buf) - sc->queue.head],
1843			    l - (sizeof(sc->queue.buf) - sc->queue.head));
1844		} else
1845			bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
1846		sc->queue.count -= l;
1847		sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
1848		splx(s);
1849		error = uiomove(buf, l, uio);
1850		if (error)
1851			break;
1852	}
1853
1854	return (error);
1855}
1856
1857static int
1858block_mouse_data(struct psm_softc *sc, int *c)
1859{
1860	int s;
1861
1862	if (!kbdc_lock(sc->kbdc, TRUE))
1863		return (EIO);
1864
1865	s = spltty();
1866	*c = get_controller_command_byte(sc->kbdc);
1867	if ((*c == -1) || !set_controller_command_byte(sc->kbdc,
1868	    kbdc_get_device_mask(sc->kbdc),
1869	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1870	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1871		/* this is CONTROLLER ERROR */
1872		splx(s);
1873		kbdc_lock(sc->kbdc, FALSE);
1874		return (EIO);
1875	}
1876
1877	/*
1878	 * The device may be in the middle of status data transmission.
1879	 * The transmission will be interrupted, thus, incomplete status
1880	 * data must be discarded. Although the aux interrupt is disabled
1881	 * at the keyboard controller level, at most one aux interrupt
1882	 * may have already been pending and a data byte is in the
1883	 * output buffer; throw it away. Note that the second argument
1884	 * to `empty_aux_buffer()' is zero, so that the call will just
1885	 * flush the internal queue.
1886	 * `psmintr()' will be invoked after `splx()' if an interrupt is
1887	 * pending; it will see no data and returns immediately.
1888	 */
1889	empty_aux_buffer(sc->kbdc, 0);		/* flush the queue */
1890	read_aux_data_no_wait(sc->kbdc);	/* throw away data if any */
1891	flushpackets(sc);
1892	splx(s);
1893
1894	return (0);
1895}
1896
1897static void
1898dropqueue(struct psm_softc *sc)
1899{
1900
1901	sc->queue.count = 0;
1902	sc->queue.head = 0;
1903	sc->queue.tail = 0;
1904	if ((sc->state & PSM_SOFTARMED) != 0) {
1905		sc->state &= ~PSM_SOFTARMED;
1906		callout_stop(&sc->softcallout);
1907	}
1908	sc->pqueue_start = sc->pqueue_end;
1909}
1910
1911static void
1912flushpackets(struct psm_softc *sc)
1913{
1914
1915	dropqueue(sc);
1916	bzero(&sc->pqueue, sizeof(sc->pqueue));
1917}
1918
1919static int
1920unblock_mouse_data(struct psm_softc *sc, int c)
1921{
1922	int error = 0;
1923
1924	/*
1925	 * We may have seen a part of status data during `set_mouse_XXX()'.
1926	 * they have been queued; flush it.
1927	 */
1928	empty_aux_buffer(sc->kbdc, 0);
1929
1930	/* restore ports and interrupt */
1931	if (!set_controller_command_byte(sc->kbdc,
1932	    kbdc_get_device_mask(sc->kbdc),
1933	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1934		/*
1935		 * CONTROLLER ERROR; this is serious, we may have
1936		 * been left with the inaccessible keyboard and
1937		 * the disabled mouse interrupt.
1938		 */
1939		error = EIO;
1940	}
1941
1942	kbdc_lock(sc->kbdc, FALSE);
1943	return (error);
1944}
1945
1946static int
1947psmwrite(struct cdev *dev, struct uio *uio, int flag)
1948{
1949	struct psm_softc *sc = dev->si_drv1;
1950	u_char buf[PSM_SMALLBUFSIZE];
1951	int error = 0, i, l;
1952
1953	if ((sc->state & PSM_VALID) == 0)
1954		return (EIO);
1955
1956	if (sc->mode.level < PSM_LEVEL_NATIVE)
1957		return (ENODEV);
1958
1959	/* copy data from the user land */
1960	while (uio->uio_resid > 0) {
1961		l = imin(PSM_SMALLBUFSIZE, uio->uio_resid);
1962		error = uiomove(buf, l, uio);
1963		if (error)
1964			break;
1965		for (i = 0; i < l; i++) {
1966			VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i]));
1967			if (!write_aux_command(sc->kbdc, buf[i])) {
1968				VLOG(2, (LOG_DEBUG,
1969				    "psm: cmd 0x%x failed.\n", buf[i]));
1970				return (reinitialize(sc, FALSE));
1971			}
1972		}
1973	}
1974
1975	return (error);
1976}
1977
1978static int
1979psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
1980    struct thread *td)
1981{
1982	struct psm_softc *sc = dev->si_drv1;
1983	mousemode_t mode;
1984	mousestatus_t status;
1985#if (defined(MOUSE_GETVARS))
1986	mousevar_t *var;
1987#endif
1988	mousedata_t *data;
1989	int stat[3];
1990	int command_byte;
1991	int error = 0;
1992	int s;
1993
1994	/* Perform IOCTL command */
1995	switch (cmd) {
1996
1997	case OLD_MOUSE_GETHWINFO:
1998		s = spltty();
1999		((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
2000		((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
2001		((old_mousehw_t *)addr)->type = sc->hw.type;
2002		((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
2003		splx(s);
2004		break;
2005
2006	case MOUSE_GETHWINFO:
2007		s = spltty();
2008		*(mousehw_t *)addr = sc->hw;
2009		if (sc->mode.level == PSM_LEVEL_BASE)
2010			((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
2011		splx(s);
2012		break;
2013
2014	case MOUSE_SYN_GETHWINFO:
2015		s = spltty();
2016		if (sc->synhw.infoMajor >= 4)
2017			*(synapticshw_t *)addr = sc->synhw;
2018		else
2019			error = EINVAL;
2020		splx(s);
2021		break;
2022
2023	case OLD_MOUSE_GETMODE:
2024		s = spltty();
2025		switch (sc->mode.level) {
2026		case PSM_LEVEL_BASE:
2027			((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2028			break;
2029		case PSM_LEVEL_STANDARD:
2030			((old_mousemode_t *)addr)->protocol =
2031			    MOUSE_PROTO_SYSMOUSE;
2032			break;
2033		case PSM_LEVEL_NATIVE:
2034			((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2035			break;
2036		}
2037		((old_mousemode_t *)addr)->rate = sc->mode.rate;
2038		((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
2039		((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
2040		splx(s);
2041		break;
2042
2043	case MOUSE_GETMODE:
2044		s = spltty();
2045		*(mousemode_t *)addr = sc->mode;
2046		if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2047			((mousemode_t *)addr)->syncmask[0] = 0;
2048			((mousemode_t *)addr)->syncmask[1] = 0;
2049		}
2050		((mousemode_t *)addr)->resolution =
2051			MOUSE_RES_LOW - sc->mode.resolution;
2052		switch (sc->mode.level) {
2053		case PSM_LEVEL_BASE:
2054			((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2055			((mousemode_t *)addr)->packetsize =
2056			    MOUSE_PS2_PACKETSIZE;
2057			break;
2058		case PSM_LEVEL_STANDARD:
2059			((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
2060			((mousemode_t *)addr)->packetsize =
2061			    MOUSE_SYS_PACKETSIZE;
2062			((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
2063			((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
2064			break;
2065		case PSM_LEVEL_NATIVE:
2066			/* FIXME: this isn't quite correct... XXX */
2067			((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
2068			break;
2069		}
2070		splx(s);
2071		break;
2072
2073	case OLD_MOUSE_SETMODE:
2074	case MOUSE_SETMODE:
2075		if (cmd == OLD_MOUSE_SETMODE) {
2076			mode.rate = ((old_mousemode_t *)addr)->rate;
2077			/*
2078			 * resolution  old I/F   new I/F
2079			 * default        0         0
2080			 * low            1        -2
2081			 * medium low     2        -3
2082			 * medium high    3        -4
2083			 * high           4        -5
2084			 */
2085			if (((old_mousemode_t *)addr)->resolution > 0)
2086				mode.resolution =
2087				    -((old_mousemode_t *)addr)->resolution - 1;
2088			else
2089				mode.resolution = 0;
2090			mode.accelfactor =
2091			    ((old_mousemode_t *)addr)->accelfactor;
2092			mode.level = -1;
2093		} else
2094			mode = *(mousemode_t *)addr;
2095
2096		/* adjust and validate parameters. */
2097		if (mode.rate > UCHAR_MAX)
2098			return (EINVAL);
2099		if (mode.rate == 0)
2100			mode.rate = sc->dflt_mode.rate;
2101		else if (mode.rate == -1)
2102			/* don't change the current setting */
2103			;
2104		else if (mode.rate < 0)
2105			return (EINVAL);
2106		if (mode.resolution >= UCHAR_MAX)
2107			return (EINVAL);
2108		if (mode.resolution >= 200)
2109			mode.resolution = MOUSE_RES_HIGH;
2110		else if (mode.resolution >= 100)
2111			mode.resolution = MOUSE_RES_MEDIUMHIGH;
2112		else if (mode.resolution >= 50)
2113			mode.resolution = MOUSE_RES_MEDIUMLOW;
2114		else if (mode.resolution > 0)
2115			mode.resolution = MOUSE_RES_LOW;
2116		if (mode.resolution == MOUSE_RES_DEFAULT)
2117			mode.resolution = sc->dflt_mode.resolution;
2118		else if (mode.resolution == -1)
2119			/* don't change the current setting */
2120			;
2121		else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2122			mode.resolution = MOUSE_RES_LOW - mode.resolution;
2123		if (mode.level == -1)
2124			/* don't change the current setting */
2125			mode.level = sc->mode.level;
2126		else if ((mode.level < PSM_LEVEL_MIN) ||
2127		    (mode.level > PSM_LEVEL_MAX))
2128			return (EINVAL);
2129		if (mode.accelfactor == -1)
2130			/* don't change the current setting */
2131			mode.accelfactor = sc->mode.accelfactor;
2132		else if (mode.accelfactor < 0)
2133			return (EINVAL);
2134
2135		/* don't allow anybody to poll the keyboard controller */
2136		error = block_mouse_data(sc, &command_byte);
2137		if (error)
2138			return (error);
2139
2140		/* set mouse parameters */
2141		if (mode.rate > 0)
2142			mode.rate = set_mouse_sampling_rate(sc->kbdc,
2143			    mode.rate);
2144		if (mode.resolution >= 0)
2145			mode.resolution =
2146			    set_mouse_resolution(sc->kbdc, mode.resolution);
2147		set_mouse_scaling(sc->kbdc, 1);
2148		get_mouse_status(sc->kbdc, stat, 0, 3);
2149
2150		s = spltty();
2151		sc->mode.rate = mode.rate;
2152		sc->mode.resolution = mode.resolution;
2153		sc->mode.accelfactor = mode.accelfactor;
2154		sc->mode.level = mode.level;
2155		splx(s);
2156
2157		unblock_mouse_data(sc, command_byte);
2158		break;
2159
2160	case MOUSE_GETLEVEL:
2161		*(int *)addr = sc->mode.level;
2162		break;
2163
2164	case MOUSE_SETLEVEL:
2165		if ((*(int *)addr < PSM_LEVEL_MIN) ||
2166		    (*(int *)addr > PSM_LEVEL_MAX))
2167			return (EINVAL);
2168		sc->mode.level = *(int *)addr;
2169		break;
2170
2171	case MOUSE_GETSTATUS:
2172		s = spltty();
2173		status = sc->status;
2174		sc->status.flags = 0;
2175		sc->status.obutton = sc->status.button;
2176		sc->status.button = 0;
2177		sc->status.dx = 0;
2178		sc->status.dy = 0;
2179		sc->status.dz = 0;
2180		splx(s);
2181		*(mousestatus_t *)addr = status;
2182		break;
2183
2184#if (defined(MOUSE_GETVARS))
2185	case MOUSE_GETVARS:
2186		var = (mousevar_t *)addr;
2187		bzero(var, sizeof(*var));
2188		s = spltty();
2189		var->var[0] = MOUSE_VARS_PS2_SIG;
2190		var->var[1] = sc->config;
2191		var->var[2] = sc->flags;
2192		splx(s);
2193		break;
2194
2195	case MOUSE_SETVARS:
2196		return (ENODEV);
2197#endif /* MOUSE_GETVARS */
2198
2199	case MOUSE_READSTATE:
2200	case MOUSE_READDATA:
2201		data = (mousedata_t *)addr;
2202		if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
2203			return (EINVAL);
2204
2205		error = block_mouse_data(sc, &command_byte);
2206		if (error)
2207			return (error);
2208		if ((data->len = get_mouse_status(sc->kbdc, data->buf,
2209		    (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
2210			error = EIO;
2211		unblock_mouse_data(sc, command_byte);
2212		break;
2213
2214#if (defined(MOUSE_SETRESOLUTION))
2215	case MOUSE_SETRESOLUTION:
2216		mode.resolution = *(int *)addr;
2217		if (mode.resolution >= UCHAR_MAX)
2218			return (EINVAL);
2219		else if (mode.resolution >= 200)
2220			mode.resolution = MOUSE_RES_HIGH;
2221		else if (mode.resolution >= 100)
2222			mode.resolution = MOUSE_RES_MEDIUMHIGH;
2223		else if (mode.resolution >= 50)
2224			mode.resolution = MOUSE_RES_MEDIUMLOW;
2225		else if (mode.resolution > 0)
2226			mode.resolution = MOUSE_RES_LOW;
2227		if (mode.resolution == MOUSE_RES_DEFAULT)
2228			mode.resolution = sc->dflt_mode.resolution;
2229		else if (mode.resolution == -1)
2230			mode.resolution = sc->mode.resolution;
2231		else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2232			mode.resolution = MOUSE_RES_LOW - mode.resolution;
2233
2234		error = block_mouse_data(sc, &command_byte);
2235		if (error)
2236			return (error);
2237		sc->mode.resolution =
2238		    set_mouse_resolution(sc->kbdc, mode.resolution);
2239		if (sc->mode.resolution != mode.resolution)
2240			error = EIO;
2241		unblock_mouse_data(sc, command_byte);
2242		break;
2243#endif /* MOUSE_SETRESOLUTION */
2244
2245#if (defined(MOUSE_SETRATE))
2246	case MOUSE_SETRATE:
2247		mode.rate = *(int *)addr;
2248		if (mode.rate > UCHAR_MAX)
2249			return (EINVAL);
2250		if (mode.rate == 0)
2251			mode.rate = sc->dflt_mode.rate;
2252		else if (mode.rate < 0)
2253			mode.rate = sc->mode.rate;
2254
2255		error = block_mouse_data(sc, &command_byte);
2256		if (error)
2257			return (error);
2258		sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
2259		if (sc->mode.rate != mode.rate)
2260			error = EIO;
2261		unblock_mouse_data(sc, command_byte);
2262		break;
2263#endif /* MOUSE_SETRATE */
2264
2265#if (defined(MOUSE_SETSCALING))
2266	case MOUSE_SETSCALING:
2267		if ((*(int *)addr <= 0) || (*(int *)addr > 2))
2268			return (EINVAL);
2269
2270		error = block_mouse_data(sc, &command_byte);
2271		if (error)
2272			return (error);
2273		if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
2274			error = EIO;
2275		unblock_mouse_data(sc, command_byte);
2276		break;
2277#endif /* MOUSE_SETSCALING */
2278
2279#if (defined(MOUSE_GETHWID))
2280	case MOUSE_GETHWID:
2281		error = block_mouse_data(sc, &command_byte);
2282		if (error)
2283			return (error);
2284		sc->hw.hwid &= ~0x00ff;
2285		sc->hw.hwid |= get_aux_id(sc->kbdc);
2286		*(int *)addr = sc->hw.hwid & 0x00ff;
2287		unblock_mouse_data(sc, command_byte);
2288		break;
2289#endif /* MOUSE_GETHWID */
2290
2291	case FIONBIO:
2292	case FIOASYNC:
2293		break;
2294	case FIOSETOWN:
2295		error = fsetown(*(int *)addr, &sc->async);
2296		break;
2297	case FIOGETOWN:
2298		*(int *) addr = fgetown(&sc->async);
2299		break;
2300	default:
2301		return (ENOTTY);
2302	}
2303
2304	return (error);
2305}
2306
2307static void
2308psmtimeout(void *arg)
2309{
2310	struct psm_softc *sc;
2311	int s;
2312
2313	sc = (struct psm_softc *)arg;
2314	s = spltty();
2315	if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
2316		VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit));
2317		psmintr(sc);
2318		kbdc_lock(sc->kbdc, FALSE);
2319	}
2320	sc->watchdog = TRUE;
2321	splx(s);
2322	callout_reset(&sc->callout, hz, psmtimeout, sc);
2323}
2324
2325/* Add all sysctls under the debug.psm and hw.psm nodes */
2326static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2327static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2328
2329SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0,
2330    "Verbosity level");
2331
2332static int psmhz = 20;
2333SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0,
2334    "Frequency of the softcallout (in hz)");
2335static int psmerrsecs = 2;
2336SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0,
2337    "Number of seconds during which packets will dropped after a sync error");
2338static int psmerrusecs = 0;
2339SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0,
2340    "Microseconds to add to psmerrsecs");
2341static int psmsecs = 0;
2342SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0,
2343    "Max number of seconds between soft interrupts");
2344static int psmusecs = 500000;
2345SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0,
2346    "Microseconds to add to psmsecs");
2347static int pkterrthresh = 2;
2348SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
2349    "Number of error packets allowed before reinitializing the mouse");
2350
2351SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RW, &tap_enabled, 0,
2352    "Enable tap and drag gestures");
2353static int tap_threshold = PSM_TAP_THRESHOLD;
2354SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
2355    "Button tap threshold");
2356static int tap_timeout = PSM_TAP_TIMEOUT;
2357SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
2358    "Tap timeout for touchpads");
2359
2360static void
2361psmintr(void *arg)
2362{
2363	struct psm_softc *sc = arg;
2364	struct timeval now;
2365	int c;
2366	packetbuf_t *pb;
2367
2368
2369	/* read until there is nothing to read */
2370	while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
2371		pb = &sc->pqueue[sc->pqueue_end];
2372
2373		/* discard the byte if the device is not open */
2374		if ((sc->state & PSM_OPEN) == 0)
2375			continue;
2376
2377		getmicrouptime(&now);
2378		if ((pb->inputbytes > 0) &&
2379		    timevalcmp(&now, &sc->inputtimeout, >)) {
2380			VLOG(3, (LOG_DEBUG, "psmintr: delay too long; "
2381			    "resetting byte count\n"));
2382			pb->inputbytes = 0;
2383			sc->syncerrors = 0;
2384			sc->pkterrors = 0;
2385		}
2386		sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000;
2387		sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000;
2388		timevaladd(&sc->inputtimeout, &now);
2389
2390		pb->ipacket[pb->inputbytes++] = c;
2391
2392		if (sc->mode.level == PSM_LEVEL_NATIVE) {
2393			VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0]));
2394			sc->syncerrors = 0;
2395			sc->pkterrors = 0;
2396			goto next;
2397		} else {
2398			if (pb->inputbytes < sc->mode.packetsize)
2399				continue;
2400
2401			VLOG(4, (LOG_DEBUG,
2402			    "psmintr: %02x %02x %02x %02x %02x %02x\n",
2403			    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
2404			    pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
2405		}
2406
2407		c = pb->ipacket[0];
2408
2409		if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2410			sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]);
2411			sc->flags &= ~PSM_NEED_SYNCBITS;
2412			VLOG(2, (LOG_DEBUG,
2413			    "psmintr: Sync bytes now %04x,%04x\n",
2414			    sc->mode.syncmask[0], sc->mode.syncmask[1]));
2415		} else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
2416			VLOG(3, (LOG_DEBUG, "psmintr: out of sync "
2417			    "(%04x != %04x) %d cmds since last error.\n",
2418			    c & sc->mode.syncmask[0], sc->mode.syncmask[1],
2419			    sc->cmdcount - sc->lasterr));
2420			sc->lasterr = sc->cmdcount;
2421			/*
2422			 * The sync byte test is a weak measure of packet
2423			 * validity.  Conservatively discard any input yet
2424			 * to be seen by userland when we detect a sync
2425			 * error since there is a good chance some of
2426			 * the queued packets have undetected errors.
2427			 */
2428			dropqueue(sc);
2429			if (sc->syncerrors == 0)
2430				sc->pkterrors++;
2431			++sc->syncerrors;
2432			sc->lastinputerr = now;
2433			if (sc->syncerrors >= sc->mode.packetsize * 2 ||
2434			    sc->pkterrors >= pkterrthresh) {
2435				/*
2436				 * If we've failed to find a single sync byte
2437				 * in 2 packets worth of data, or we've seen
2438				 * persistent packet errors during the
2439				 * validation period, reinitialize the mouse
2440				 * in hopes of returning it to the expected
2441				 * mode.
2442				 */
2443				VLOG(3, (LOG_DEBUG,
2444				    "psmintr: reset the mouse.\n"));
2445				reinitialize(sc, TRUE);
2446			} else if (sc->syncerrors == sc->mode.packetsize) {
2447				/*
2448				 * Try a soft reset after searching for a sync
2449				 * byte through a packet length of bytes.
2450				 */
2451				VLOG(3, (LOG_DEBUG,
2452				    "psmintr: re-enable the mouse.\n"));
2453				pb->inputbytes = 0;
2454				disable_aux_dev(sc->kbdc);
2455				enable_aux_dev(sc->kbdc);
2456			} else {
2457				VLOG(3, (LOG_DEBUG,
2458				    "psmintr: discard a byte (%d)\n",
2459				    sc->syncerrors));
2460				pb->inputbytes--;
2461				bcopy(&pb->ipacket[1], &pb->ipacket[0],
2462				    pb->inputbytes);
2463			}
2464			continue;
2465		}
2466
2467		/*
2468		 * We have what appears to be a valid packet.
2469		 * Reset the error counters.
2470		 */
2471		sc->syncerrors = 0;
2472
2473		/*
2474		 * Drop even good packets if they occur within a timeout
2475		 * period of a sync error.  This allows the detection of
2476		 * a change in the mouse's packet mode without exposing
2477		 * erratic mouse behavior to the user.  Some KVMs forget
2478		 * enhanced mouse modes during switch events.
2479		 */
2480		if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs,
2481		    &now)) {
2482			pb->inputbytes = 0;
2483			continue;
2484		}
2485
2486		/*
2487		 * Now that we're out of the validation period, reset
2488		 * the packet error count.
2489		 */
2490		sc->pkterrors = 0;
2491
2492		sc->cmdcount++;
2493next:
2494		if (++sc->pqueue_end >= PSM_PACKETQUEUE)
2495			sc->pqueue_end = 0;
2496		/*
2497		 * If we've filled the queue then call the softintr ourselves,
2498		 * otherwise schedule the interrupt for later.
2499		 */
2500		if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) ||
2501		    (sc->pqueue_end == sc->pqueue_start)) {
2502			if ((sc->state & PSM_SOFTARMED) != 0) {
2503				sc->state &= ~PSM_SOFTARMED;
2504				callout_stop(&sc->softcallout);
2505			}
2506			psmsoftintr(arg);
2507		} else if ((sc->state & PSM_SOFTARMED) == 0) {
2508			sc->state |= PSM_SOFTARMED;
2509			callout_reset(&sc->softcallout,
2510			    psmhz < 1 ? 1 : (hz/psmhz), psmsoftintr, arg);
2511		}
2512	}
2513}
2514
2515static void
2516proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2517    int *x, int *y, int *z)
2518{
2519
2520	/*
2521	 * PS2++ protocol packet
2522	 *
2523	 *          b7 b6 b5 b4 b3 b2 b1 b0
2524	 * byte 1:  *  1  p3 p2 1  *  *  *
2525	 * byte 2:  c1 c2 p1 p0 d1 d0 1  0
2526	 *
2527	 * p3-p0: packet type
2528	 * c1, c2: c1 & c2 == 1, if p2 == 0
2529	 *         c1 & c2 == 0, if p2 == 1
2530	 *
2531	 * packet type: 0 (device type)
2532	 * See comments in enable_mmanplus() below.
2533	 *
2534	 * packet type: 1 (wheel data)
2535	 *
2536	 *          b7 b6 b5 b4 b3 b2 b1 b0
2537	 * byte 3:  h  *  B5 B4 s  d2 d1 d0
2538	 *
2539	 * h: 1, if horizontal roller data
2540	 *    0, if vertical roller data
2541	 * B4, B5: button 4 and 5
2542	 * s: sign bit
2543	 * d2-d0: roller data
2544	 *
2545	 * packet type: 2 (reserved)
2546	 */
2547	if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) &&
2548	    (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) {
2549		/*
2550		 * the extended data packet encodes button
2551		 * and wheel events
2552		 */
2553		switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) {
2554		case 1:
2555			/* wheel data packet */
2556			*x = *y = 0;
2557			if (pb->ipacket[2] & 0x80) {
2558				/* XXX horizontal roller count - ignore it */
2559				;
2560			} else {
2561				/* vertical roller count */
2562				*z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ?
2563				    (pb->ipacket[2] & 0x0f) - 16 :
2564				    (pb->ipacket[2] & 0x0f);
2565			}
2566			ms->button |= (pb->ipacket[2] &
2567			    MOUSE_PS2PLUS_BUTTON4DOWN) ?
2568			    MOUSE_BUTTON4DOWN : 0;
2569			ms->button |= (pb->ipacket[2] &
2570			    MOUSE_PS2PLUS_BUTTON5DOWN) ?
2571			    MOUSE_BUTTON5DOWN : 0;
2572			break;
2573		case 2:
2574			/*
2575			 * this packet type is reserved by
2576			 * Logitech...
2577			 */
2578			/*
2579			 * IBM ScrollPoint Mouse uses this
2580			 * packet type to encode both vertical
2581			 * and horizontal scroll movement.
2582			 */
2583			*x = *y = 0;
2584			/* horizontal count */
2585			if (pb->ipacket[2] & 0x0f)
2586				*z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ?
2587				    -2 : 2;
2588			/* vertical count */
2589			if (pb->ipacket[2] & 0xf0)
2590				*z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ?
2591				    -1 : 1;
2592			break;
2593		case 0:
2594			/* device type packet - shouldn't happen */
2595			/* FALLTHROUGH */
2596		default:
2597			*x = *y = 0;
2598			ms->button = ms->obutton;
2599			VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet "
2600			    "type %d: 0x%02x 0x%02x 0x%02x\n",
2601			    MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket),
2602			    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]));
2603			break;
2604		}
2605	} else {
2606		/* preserve button states */
2607		ms->button |= ms->obutton & MOUSE_EXTBUTTONS;
2608	}
2609}
2610
2611static int
2612proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2613    int *x, int *y, int *z)
2614{
2615	static int touchpad_buttons;
2616	static int guest_buttons;
2617	int w, x0, y0;
2618
2619	/* TouchPad PS/2 absolute mode message format with capFourButtons:
2620	 *
2621	 *  Bits:        7   6   5   4   3   2   1   0 (LSB)
2622	 *  ------------------------------------------------
2623	 *  ipacket[0]:  1   0  W3  W2   0  W1   R   L
2624	 *  ipacket[1]: Yb  Ya  Y9  Y8  Xb  Xa  X9  X8
2625	 *  ipacket[2]: Z7  Z6  Z5  Z4  Z3  Z2  Z1  Z0
2626	 *  ipacket[3]:  1   1  Yc  Xc   0  W0 D^R U^L
2627	 *  ipacket[4]: X7  X6  X5  X4  X3  X2  X1  X0
2628	 *  ipacket[5]: Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
2629	 *
2630	 * Legend:
2631	 *  L: left physical mouse button
2632	 *  R: right physical mouse button
2633	 *  D: down button
2634	 *  U: up button
2635	 *  W: "wrist" value
2636	 *  X: x position
2637	 *  Y: y position
2638	 *  Z: pressure
2639	 *
2640	 * Without capFourButtons but with nExtendeButtons and/or capMiddle
2641	 *
2642	 *  Bits:        7   6   5   4      3      2      1      0 (LSB)
2643	 *  ------------------------------------------------------
2644	 *  ipacket[3]:  1   1  Yc  Xc      0     W0    E^R    M^L
2645	 *  ipacket[4]: X7  X6  X5  X4  X3|b7  X2|b5  X1|b3  X0|b1
2646	 *  ipacket[5]: Y7  Y6  Y5  Y4  Y3|b8  Y2|b6  Y1|b4  Y0|b2
2647	 *
2648	 * Legend:
2649	 *  M: Middle physical mouse button
2650	 *  E: Extended mouse buttons reported instead of low bits of X and Y
2651	 *  b1-b8: Extended mouse buttons
2652	 *    Only ((nExtendedButtons + 1) >> 1) bits are used in packet
2653	 *    4 and 5, for reading X and Y value they should be zeroed.
2654	 *
2655	 * Absolute reportable limits:    0 - 6143.
2656	 * Typical bezel limits:       1472 - 5472.
2657	 * Typical edge marings:       1632 - 5312.
2658	 *
2659	 * w = 3 Passthrough Packet
2660	 *
2661	 * Byte 2,5,6 == Byte 1,2,3 of "Guest"
2662	 */
2663
2664	if (!synaptics_support)
2665		return (0);
2666
2667	/* Sanity check for out of sync packets. */
2668	if ((pb->ipacket[0] & 0xc8) != 0x80 ||
2669	    (pb->ipacket[3] & 0xc8) != 0xc0)
2670		return (-1);
2671
2672	*x = *y = 0;
2673
2674	/*
2675	 * Pressure value.
2676	 * Interpretation:
2677	 *   z = 0      No finger contact
2678	 *   z = 10     Finger hovering near the pad
2679	 *   z = 30     Very light finger contact
2680	 *   z = 80     Normal finger contact
2681	 *   z = 110    Very heavy finger contact
2682	 *   z = 200    Finger lying flat on pad surface
2683	 *   z = 255    Maximum reportable Z
2684	 */
2685	*z = pb->ipacket[2];
2686
2687	/*
2688	 * Finger width value
2689	 * Interpretation:
2690	 *   w = 0      Two finger on the pad (capMultiFinger needed)
2691	 *   w = 1      Three or more fingers (capMultiFinger needed)
2692	 *   w = 2      Pen (instead of finger) (capPen needed)
2693	 *   w = 3      Reserved (passthrough?)
2694	 *   w = 4-7    Finger of normal width (capPalmDetect needed)
2695	 *   w = 8-14   Very wide finger or palm (capPalmDetect needed)
2696	 *   w = 15     Maximum reportable width (capPalmDetect needed)
2697	 */
2698	/* XXX Is checking capExtended enough? */
2699	if (sc->synhw.capExtended)
2700		w = ((pb->ipacket[0] & 0x30) >> 2) |
2701		    ((pb->ipacket[0] & 0x04) >> 1) |
2702		    ((pb->ipacket[3] & 0x04) >> 2);
2703	else {
2704		/* Assume a finger of regular width. */
2705		w = 4;
2706	}
2707
2708	/*
2709	 * Handle packets from the guest device. See:
2710	 * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
2711	 */
2712	if (w == 3 && sc->synhw.capPassthrough) {
2713		*x = ((pb->ipacket[1] & 0x10) ?
2714		    pb->ipacket[4] - 256 : pb->ipacket[4]);
2715		*y = ((pb->ipacket[1] & 0x20) ?
2716		    pb->ipacket[5] - 256 : pb->ipacket[5]);
2717		*z = 0;
2718
2719		guest_buttons = 0;
2720		if (pb->ipacket[1] & 0x01)
2721			guest_buttons |= MOUSE_BUTTON1DOWN;
2722		if (pb->ipacket[1] & 0x04)
2723			guest_buttons |= MOUSE_BUTTON2DOWN;
2724		if (pb->ipacket[1] & 0x02)
2725			guest_buttons |= MOUSE_BUTTON3DOWN;
2726
2727		ms->button = touchpad_buttons | guest_buttons;
2728		goto SYNAPTICS_END;
2729	}
2730
2731	if (sc->syninfo.touchpad_off) {
2732		*x = *y = *z = 0;
2733		ms->button = ms->obutton;
2734		goto SYNAPTICS_END;
2735	}
2736
2737	/* Button presses */
2738	touchpad_buttons = 0;
2739	if (pb->ipacket[0] & 0x01)
2740		touchpad_buttons |= MOUSE_BUTTON1DOWN;
2741	if (pb->ipacket[0] & 0x02)
2742		touchpad_buttons |= MOUSE_BUTTON3DOWN;
2743
2744	if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
2745		if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x01)
2746			touchpad_buttons |= MOUSE_BUTTON4DOWN;
2747		if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02)
2748			touchpad_buttons |= MOUSE_BUTTON5DOWN;
2749	} else if (sc->synhw.capExtended && sc->synhw.capMiddle &&
2750	    !sc->synhw.capClickPad) {
2751		/* Middle Button */
2752		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
2753			touchpad_buttons |= MOUSE_BUTTON2DOWN;
2754	} else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
2755		/* Extended Buttons */
2756		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
2757			if (sc->syninfo.directional_scrolls) {
2758				if (pb->ipacket[4] & 0x01)
2759					touchpad_buttons |= MOUSE_BUTTON4DOWN;
2760				if (pb->ipacket[5] & 0x01)
2761					touchpad_buttons |= MOUSE_BUTTON5DOWN;
2762				if (pb->ipacket[4] & 0x02)
2763					touchpad_buttons |= MOUSE_BUTTON6DOWN;
2764				if (pb->ipacket[5] & 0x02)
2765					touchpad_buttons |= MOUSE_BUTTON7DOWN;
2766			} else {
2767				if (pb->ipacket[4] & 0x01)
2768					touchpad_buttons |= MOUSE_BUTTON1DOWN;
2769				if (pb->ipacket[5] & 0x01)
2770					touchpad_buttons |= MOUSE_BUTTON3DOWN;
2771				if (pb->ipacket[4] & 0x02)
2772					touchpad_buttons |= MOUSE_BUTTON2DOWN;
2773				sc->extended_buttons = touchpad_buttons;
2774			}
2775
2776			/*
2777			 * Zero out bits used by extended buttons to avoid
2778			 * misinterpretation of the data absolute position.
2779			 *
2780			 * The bits represented by
2781			 *
2782			 *     (nExtendedButtons + 1) >> 1
2783			 *
2784			 * will be masked out in both bytes.
2785			 * The mask for n bits is computed with the formula
2786			 *
2787			 *     (1 << n) - 1
2788			 */
2789			int maskedbits = 0;
2790			int mask = 0;
2791			maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1;
2792			mask = (1 << maskedbits) - 1;
2793			pb->ipacket[4] &= ~(mask);
2794			pb->ipacket[5] &= ~(mask);
2795		} else	if (!sc->syninfo.directional_scrolls &&
2796		    !sc->synaction.in_vscroll) {
2797			/*
2798			 * Keep reporting MOUSE DOWN until we get a new packet
2799			 * indicating otherwise.
2800			 */
2801			touchpad_buttons |= sc->extended_buttons;
2802		}
2803	}
2804	/* Handle ClickPad. */
2805	if (sc->synhw.capClickPad &&
2806	    ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
2807		touchpad_buttons |= MOUSE_BUTTON1DOWN;
2808
2809	ms->button = touchpad_buttons | guest_buttons;
2810
2811	/*
2812	 * Check pressure to detect a real wanted action on the
2813	 * touchpad.
2814	 */
2815	if (*z >= sc->syninfo.min_pressure) {
2816		synapticsaction_t *synaction;
2817		int cursor, peer, window;
2818		int dx, dy, dxp, dyp;
2819		int max_width, max_pressure;
2820		int margin_top, margin_right, margin_bottom, margin_left;
2821		int na_top, na_right, na_bottom, na_left;
2822		int window_min, window_max;
2823		int multiplicator;
2824		int weight_current, weight_previous, weight_len_squared;
2825		int div_min, div_max, div_len;
2826		int vscroll_hor_area, vscroll_ver_area;
2827		int two_finger_scroll;
2828		int len, weight_prev_x, weight_prev_y;
2829		int div_max_x, div_max_y, div_x, div_y;
2830
2831		/* Read sysctl. */
2832		/* XXX Verify values? */
2833		max_width = sc->syninfo.max_width;
2834		max_pressure = sc->syninfo.max_pressure;
2835		margin_top = sc->syninfo.margin_top;
2836		margin_right = sc->syninfo.margin_right;
2837		margin_bottom = sc->syninfo.margin_bottom;
2838		margin_left = sc->syninfo.margin_left;
2839		na_top = sc->syninfo.na_top;
2840		na_right = sc->syninfo.na_right;
2841		na_bottom = sc->syninfo.na_bottom;
2842		na_left = sc->syninfo.na_left;
2843		window_min = sc->syninfo.window_min;
2844		window_max = sc->syninfo.window_max;
2845		multiplicator = sc->syninfo.multiplicator;
2846		weight_current = sc->syninfo.weight_current;
2847		weight_previous = sc->syninfo.weight_previous;
2848		weight_len_squared = sc->syninfo.weight_len_squared;
2849		div_min = sc->syninfo.div_min;
2850		div_max = sc->syninfo.div_max;
2851		div_len = sc->syninfo.div_len;
2852		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
2853		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
2854		two_finger_scroll = sc->syninfo.two_finger_scroll;
2855
2856		/* Palm detection. */
2857		if (!(
2858		    (sc->synhw.capMultiFinger && (w == 0 || w == 1)) ||
2859		    (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
2860		    (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
2861		    (sc->synhw.capPen && w == 2))) {
2862			/*
2863			 * We consider the packet irrelevant for the current
2864			 * action when:
2865			 *  - the width isn't comprised in:
2866			 *    [4; max_width]
2867			 *  - the pressure isn't comprised in:
2868			 *    [min_pressure; max_pressure]
2869			 *  - pen aren't supported but w is 2
2870			 *
2871			 *  Note that this doesn't terminate the current action.
2872			 */
2873			VLOG(2, (LOG_DEBUG,
2874			    "synaptics: palm detected! (%d)\n", w));
2875			goto SYNAPTICS_END;
2876		}
2877
2878		/* Read current absolute position. */
2879		x0 = ((pb->ipacket[3] & 0x10) << 8) |
2880		    ((pb->ipacket[1] & 0x0f) << 8) |
2881		    pb->ipacket[4];
2882		y0 = ((pb->ipacket[3] & 0x20) << 7) |
2883		    ((pb->ipacket[1] & 0xf0) << 4) |
2884		    pb->ipacket[5];
2885
2886		synaction = &(sc->synaction);
2887
2888		/*
2889		 * If the action is just beginning, init the structure and
2890		 * compute tap timeout.
2891		 */
2892		if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
2893			VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
2894
2895			/* Store the first point of this action. */
2896			synaction->start_x = x0;
2897			synaction->start_y = y0;
2898			dx = dy = 0;
2899
2900			/* Initialize queue. */
2901			synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
2902			synaction->queue_len = 0;
2903			synaction->window_min = window_min;
2904
2905			/* Reset average. */
2906			synaction->avg_dx = 0;
2907			synaction->avg_dy = 0;
2908
2909			/* Reset squelch. */
2910			synaction->squelch_x = 0;
2911			synaction->squelch_y = 0;
2912
2913			/* Reset pressure peak. */
2914			sc->zmax = 0;
2915
2916			/* Reset fingers count. */
2917			synaction->fingers_nb = 0;
2918
2919			/* Reset virtual scrolling state. */
2920			synaction->in_vscroll = 0;
2921
2922			/* Compute tap timeout. */
2923			sc->taptimeout.tv_sec  = tap_timeout / 1000000;
2924			sc->taptimeout.tv_usec = tap_timeout % 1000000;
2925			timevaladd(&sc->taptimeout, &sc->lastsoftintr);
2926
2927			sc->flags |= PSM_FLAGS_FINGERDOWN;
2928		} else {
2929			/* Calculate the current delta. */
2930			cursor = synaction->queue_cursor;
2931			dx = x0 - synaction->queue[cursor].x;
2932			dy = y0 - synaction->queue[cursor].y;
2933		}
2934
2935		/* If in tap-hold, add the recorded button. */
2936		if (synaction->in_taphold)
2937			ms->button |= synaction->tap_button;
2938
2939		/*
2940		 * From now on, we can use the SYNAPTICS_END label to skip
2941		 * the current packet.
2942		 */
2943
2944		/*
2945		 * Limit the coordinates to the specified margins because
2946		 * this area isn't very reliable.
2947		 */
2948		if (x0 <= margin_left)
2949			x0 = margin_left;
2950		else if (x0 >= 6143 - margin_right)
2951			x0 = 6143 - margin_right;
2952		if (y0 <= margin_bottom)
2953			y0 = margin_bottom;
2954		else if (y0 >= 6143 - margin_top)
2955			y0 = 6143 - margin_top;
2956
2957		VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
2958		    x0, y0, *z, w));
2959
2960		/* Queue this new packet. */
2961		cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
2962		synaction->queue[cursor].x = x0;
2963		synaction->queue[cursor].y = y0;
2964		synaction->queue_cursor = cursor;
2965		if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
2966			synaction->queue_len++;
2967		VLOG(5, (LOG_DEBUG,
2968		    "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
2969		    cursor, x0, y0, dx, dy));
2970
2971		/*
2972		 * For tap, we keep the maximum number of fingers and the
2973		 * pressure peak. Also with multiple fingers, we increase
2974		 * the minimum window.
2975		 */
2976		switch (w) {
2977		case 1: /* Three or more fingers. */
2978			synaction->fingers_nb = imax(3, synaction->fingers_nb);
2979			synaction->window_min = window_max;
2980			break;
2981		case 0: /* Two fingers. */
2982			synaction->fingers_nb = imax(2, synaction->fingers_nb);
2983			synaction->window_min = window_max;
2984			break;
2985		default: /* One finger or undetectable. */
2986			synaction->fingers_nb = imax(1, synaction->fingers_nb);
2987		}
2988		sc->zmax = imax(*z, sc->zmax);
2989
2990		/* Do we have enough packets to consider this a movement? */
2991		if (synaction->queue_len < synaction->window_min)
2992			goto SYNAPTICS_END;
2993
2994		/* Is a scrolling action occuring? */
2995		if (!synaction->in_taphold && !synaction->in_vscroll) {
2996			/*
2997			 * A scrolling action must not conflict with a tap
2998			 * action. Here are the conditions to consider a
2999			 * scrolling action:
3000			 *  - the action in a configurable area
3001			 *  - one of the following:
3002			 *     . the distance between the last packet and the
3003			 *       first should be above a configurable minimum
3004			 *     . tap timed out
3005			 */
3006			dxp = abs(synaction->queue[synaction->queue_cursor].x -
3007			    synaction->start_x);
3008			dyp = abs(synaction->queue[synaction->queue_cursor].y -
3009			    synaction->start_y);
3010
3011			if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
3012			    dxp >= sc->syninfo.vscroll_min_delta ||
3013			    dyp >= sc->syninfo.vscroll_min_delta) {
3014				/*
3015				 * Handle two finger scrolling.
3016				 * Note that we don't rely on fingers_nb
3017				 * as that keeps the maximum number of fingers.
3018				 */
3019				if (two_finger_scroll) {
3020					if (w == 0) {
3021						synaction->in_vscroll +=
3022						    dyp ? 2 : 0;
3023						synaction->in_vscroll +=
3024						    dxp ? 1 : 0;
3025					}
3026				} else {
3027					/* Check for horizontal scrolling. */
3028					if ((vscroll_hor_area > 0 &&
3029					    synaction->start_y <=
3030					        vscroll_hor_area) ||
3031					    (vscroll_hor_area < 0 &&
3032					     synaction->start_y >=
3033					     6143 + vscroll_hor_area))
3034						synaction->in_vscroll += 2;
3035
3036					/* Check for vertical scrolling. */
3037					if ((vscroll_ver_area > 0 &&
3038					    synaction->start_x <=
3039						vscroll_ver_area) ||
3040					    (vscroll_ver_area < 0 &&
3041					     synaction->start_x >=
3042					     6143 + vscroll_ver_area))
3043						synaction->in_vscroll += 1;
3044				}
3045
3046				/* Avoid conflicts if area overlaps. */
3047				if (synaction->in_vscroll >= 3)
3048					synaction->in_vscroll =
3049					    (dxp > dyp) ? 2 : 1;
3050			}
3051		}
3052		/*
3053		 * Reset two finger scrolling when the number of fingers
3054		 * is different from two.
3055		 */
3056		if (two_finger_scroll && w != 0)
3057			synaction->in_vscroll = 0;
3058
3059		VLOG(5, (LOG_DEBUG,
3060			"synaptics: virtual scrolling: %s "
3061			"(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n",
3062			synaction->in_vscroll ? "YES" : "NO",
3063			synaction->in_vscroll, dxp, dyp,
3064			synaction->fingers_nb));
3065
3066		weight_prev_x = weight_prev_y = weight_previous;
3067		div_max_x = div_max_y = div_max;
3068
3069		if (synaction->in_vscroll) {
3070			/* Dividers are different with virtual scrolling. */
3071			div_min = sc->syninfo.vscroll_div_min;
3072			div_max_x = div_max_y = sc->syninfo.vscroll_div_max;
3073		} else {
3074			/*
3075			 * There's a lot of noise in coordinates when
3076			 * the finger is on the touchpad's borders. When
3077			 * using this area, we apply a special weight and
3078			 * div.
3079			 */
3080			if (x0 <= na_left || x0 >= 6143 - na_right) {
3081				weight_prev_x = sc->syninfo.weight_previous_na;
3082				div_max_x = sc->syninfo.div_max_na;
3083			}
3084
3085			if (y0 <= na_bottom || y0 >= 6143 - na_top) {
3086				weight_prev_y = sc->syninfo.weight_previous_na;
3087				div_max_y = sc->syninfo.div_max_na;
3088			}
3089		}
3090
3091		/*
3092		 * Calculate weights for the average operands and
3093		 * the divisor. Both depend on the distance between
3094		 * the current packet and a previous one (based on the
3095		 * window width).
3096		 */
3097		window = imin(synaction->queue_len, window_max);
3098		peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1);
3099		dxp = abs(x0 - synaction->queue[peer].x) + 1;
3100		dyp = abs(y0 - synaction->queue[peer].y) + 1;
3101		len = (dxp * dxp) + (dyp * dyp);
3102		weight_prev_x = imin(weight_prev_x,
3103		    weight_len_squared * weight_prev_x / len);
3104		weight_prev_y = imin(weight_prev_y,
3105		    weight_len_squared * weight_prev_y / len);
3106
3107		len = (dxp + dyp) / 2;
3108		div_x = div_len * div_max_x / len;
3109		div_x = imin(div_max_x, div_x);
3110		div_x = imax(div_min, div_x);
3111		div_y = div_len * div_max_y / len;
3112		div_y = imin(div_max_y, div_y);
3113		div_y = imax(div_min, div_y);
3114
3115		VLOG(3, (LOG_DEBUG,
3116		    "synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n",
3117		    peer, len, weight_prev_x, weight_prev_y, div_x, div_y));
3118
3119		/* Compute averages. */
3120		synaction->avg_dx =
3121		    (weight_current * dx * multiplicator +
3122		     weight_prev_x * synaction->avg_dx) /
3123		    (weight_current + weight_prev_x);
3124
3125		synaction->avg_dy =
3126		    (weight_current * dy * multiplicator +
3127		     weight_prev_y * synaction->avg_dy) /
3128		    (weight_current + weight_prev_y);
3129
3130		VLOG(5, (LOG_DEBUG,
3131		    "synaptics: avg_dx~=%d, avg_dy~=%d\n",
3132		    synaction->avg_dx / multiplicator,
3133		    synaction->avg_dy / multiplicator));
3134
3135		/* Use these averages to calculate x & y. */
3136		synaction->squelch_x += synaction->avg_dx;
3137		*x = synaction->squelch_x / (div_x * multiplicator);
3138		synaction->squelch_x = synaction->squelch_x %
3139		    (div_x * multiplicator);
3140
3141		synaction->squelch_y += synaction->avg_dy;
3142		*y = synaction->squelch_y / (div_y * multiplicator);
3143		synaction->squelch_y = synaction->squelch_y %
3144		    (div_y * multiplicator);
3145
3146		if (synaction->in_vscroll) {
3147			switch(synaction->in_vscroll) {
3148			case 1: /* Vertical scrolling. */
3149				if (*y != 0)
3150					ms->button |= (*y > 0) ?
3151					    MOUSE_BUTTON4DOWN :
3152					    MOUSE_BUTTON5DOWN;
3153				break;
3154			case 2: /* Horizontal scrolling. */
3155				if (*x != 0)
3156					ms->button |= (*x > 0) ?
3157					    MOUSE_BUTTON7DOWN :
3158					    MOUSE_BUTTON6DOWN;
3159				break;
3160			}
3161
3162			/* The pointer is not moved. */
3163			*x = *y = 0;
3164		} else {
3165			VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n",
3166			    dx, dy, *x, *y));
3167		}
3168	} else if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3169		/*
3170		 * An action is currently taking place but the pressure
3171		 * dropped under the minimum, putting an end to it.
3172		 */
3173		synapticsaction_t *synaction;
3174		int taphold_timeout, dx, dy, tap_max_delta;
3175
3176		synaction = &(sc->synaction);
3177		dx = abs(synaction->queue[synaction->queue_cursor].x -
3178		    synaction->start_x);
3179		dy = abs(synaction->queue[synaction->queue_cursor].y -
3180		    synaction->start_y);
3181
3182		/* Max delta is disabled for multi-fingers tap. */
3183		if (synaction->fingers_nb > 1)
3184			tap_max_delta = imax(dx, dy);
3185		else
3186			tap_max_delta = sc->syninfo.tap_max_delta;
3187
3188		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3189
3190		/* Check for tap. */
3191		VLOG(3, (LOG_DEBUG,
3192		    "synaptics: zmax=%d, dx=%d, dy=%d, "
3193		    "delta=%d, fingers=%d, queue=%d\n",
3194		    sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb,
3195		    synaction->queue_len));
3196		if (!synaction->in_vscroll && sc->zmax >= tap_threshold &&
3197		    timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) &&
3198		    dx <= tap_max_delta && dy <= tap_max_delta &&
3199		    synaction->queue_len >= sc->syninfo.tap_min_queue) {
3200			/*
3201			 * We have a tap if:
3202			 *   - the maximum pressure went over tap_threshold
3203			 *   - the action ended before tap_timeout
3204			 *
3205			 * To handle tap-hold, we must delay any button push to
3206			 * the next action.
3207			 */
3208			if (synaction->in_taphold) {
3209				/*
3210				 * This is the second and last tap of a
3211				 * double tap action, not a tap-hold.
3212				 */
3213				synaction->in_taphold = 0;
3214
3215				/*
3216				 * For double-tap to work:
3217				 *   - no button press is emitted (to
3218				 *     simulate a button release)
3219				 *   - PSM_FLAGS_FINGERDOWN is set to
3220				 *     force the next packet to emit a
3221				 *     button press)
3222				 */
3223				VLOG(2, (LOG_DEBUG,
3224				    "synaptics: button RELEASE: %d\n",
3225				    synaction->tap_button));
3226				sc->flags |= PSM_FLAGS_FINGERDOWN;
3227			} else {
3228				/*
3229				 * This is the first tap: we set the
3230				 * tap-hold state and notify the button
3231				 * down event.
3232				 */
3233				synaction->in_taphold = 1;
3234				taphold_timeout = sc->syninfo.taphold_timeout;
3235				sc->taptimeout.tv_sec  = taphold_timeout /
3236				    1000000;
3237				sc->taptimeout.tv_usec = taphold_timeout %
3238				    1000000;
3239				timevaladd(&sc->taptimeout, &sc->lastsoftintr);
3240
3241				switch (synaction->fingers_nb) {
3242				case 3:
3243					synaction->tap_button =
3244					    MOUSE_BUTTON2DOWN;
3245					break;
3246				case 2:
3247					synaction->tap_button =
3248					    MOUSE_BUTTON3DOWN;
3249					break;
3250				default:
3251					synaction->tap_button =
3252					    MOUSE_BUTTON1DOWN;
3253				}
3254				VLOG(2, (LOG_DEBUG,
3255				    "synaptics: button PRESS: %d\n",
3256				    synaction->tap_button));
3257				ms->button |= synaction->tap_button;
3258			}
3259		} else {
3260			/*
3261			 * Not enough pressure or timeout: reset
3262			 * tap-hold state.
3263			 */
3264			if (synaction->in_taphold) {
3265				VLOG(2, (LOG_DEBUG,
3266				    "synaptics: button RELEASE: %d\n",
3267				    synaction->tap_button));
3268				synaction->in_taphold = 0;
3269			} else {
3270				VLOG(2, (LOG_DEBUG,
3271				    "synaptics: not a tap-hold\n"));
3272			}
3273		}
3274	} else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) &&
3275	    sc->synaction.in_taphold) {
3276		/*
3277		 * For a tap-hold to work, the button must remain down at
3278		 * least until timeout (where the in_taphold flags will be
3279		 * cleared) or during the next action.
3280		 */
3281		if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
3282			ms->button |= sc->synaction.tap_button;
3283		} else {
3284			VLOG(2, (LOG_DEBUG,
3285			    "synaptics: button RELEASE: %d\n",
3286			    sc->synaction.tap_button));
3287			sc->synaction.in_taphold = 0;
3288		}
3289	}
3290
3291SYNAPTICS_END:
3292	/*
3293	 * Use the extra buttons as a scrollwheel
3294	 *
3295	 * XXX X.Org uses the Z axis for vertical wheel only,
3296	 * whereas moused(8) understands special values to differ
3297	 * vertical and horizontal wheels.
3298	 *
3299	 * xf86-input-mouse needs therefore a small patch to
3300	 * understand these special values. Without it, the
3301	 * horizontal wheel acts as a vertical wheel in X.Org.
3302	 *
3303	 * That's why the horizontal wheel is disabled by
3304	 * default for now.
3305	 */
3306
3307	if (ms->button & MOUSE_BUTTON4DOWN) {
3308		*z = -1;
3309		ms->button &= ~MOUSE_BUTTON4DOWN;
3310	} else if (ms->button & MOUSE_BUTTON5DOWN) {
3311		*z = 1;
3312		ms->button &= ~MOUSE_BUTTON5DOWN;
3313	} else if (ms->button & MOUSE_BUTTON6DOWN) {
3314		*z = -2;
3315		ms->button &= ~MOUSE_BUTTON6DOWN;
3316	} else if (ms->button & MOUSE_BUTTON7DOWN) {
3317		*z = 2;
3318		ms->button &= ~MOUSE_BUTTON7DOWN;
3319	} else
3320		*z = 0;
3321
3322	return (0);
3323}
3324
3325static void
3326proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
3327    int *x, int *y, int *z)
3328{
3329	static int butmap_versapad[8] = {
3330		0,
3331		MOUSE_BUTTON3DOWN,
3332		0,
3333		MOUSE_BUTTON3DOWN,
3334		MOUSE_BUTTON1DOWN,
3335		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3336		MOUSE_BUTTON1DOWN,
3337		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
3338	};
3339	int c, x0, y0;
3340
3341	/* VersaPad PS/2 absolute mode message format
3342	 *
3343	 * [packet1]     7   6   5   4   3   2   1   0(LSB)
3344	 *  ipacket[0]:  1   1   0   A   1   L   T   R
3345	 *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
3346	 *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
3347	 *  ipacket[3]:  1   1   1   A   1   L   T   R
3348	 *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
3349	 *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
3350	 *
3351	 * [note]
3352	 *  R: right physical mouse button (1=on)
3353	 *  T: touch pad virtual button (1=tapping)
3354	 *  L: left physical mouse button (1=on)
3355	 *  A: position data is valid (1=valid)
3356	 *  H: horizontal data (12bit signed integer. H11 is sign bit.)
3357	 *  V: vertical data (12bit signed integer. V11 is sign bit.)
3358	 *  P: pressure data
3359	 *
3360	 * Tapping is mapped to MOUSE_BUTTON4.
3361	 */
3362	c = pb->ipacket[0];
3363	*x = *y = 0;
3364	ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
3365	ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
3366	if (c & MOUSE_PS2VERSA_IN_USE) {
3367		x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8);
3368		y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4);
3369		if (x0 & 0x800)
3370			x0 -= 0x1000;
3371		if (y0 & 0x800)
3372			y0 -= 0x1000;
3373		if (sc->flags & PSM_FLAGS_FINGERDOWN) {
3374			*x = sc->xold - x0;
3375			*y = y0 - sc->yold;
3376			if (*x < 0)	/* XXX */
3377				++*x;
3378			else if (*x)
3379				--*x;
3380			if (*y < 0)
3381				++*y;
3382			else if (*y)
3383				--*y;
3384		} else
3385			sc->flags |= PSM_FLAGS_FINGERDOWN;
3386		sc->xold = x0;
3387		sc->yold = y0;
3388	} else
3389		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
3390}
3391
3392static void
3393psmsoftintr(void *arg)
3394{
3395	/*
3396	 * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
3397	 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
3398	 */
3399	static int butmap[8] = {
3400		0,
3401		MOUSE_BUTTON1DOWN,
3402		MOUSE_BUTTON3DOWN,
3403		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
3404		MOUSE_BUTTON2DOWN,
3405		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
3406		MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
3407		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
3408	};
3409	struct psm_softc *sc = arg;
3410	mousestatus_t ms;
3411	packetbuf_t *pb;
3412	int x, y, z, c, l, s;
3413
3414	getmicrouptime(&sc->lastsoftintr);
3415
3416	s = spltty();
3417
3418	do {
3419		pb = &sc->pqueue[sc->pqueue_start];
3420
3421		if (sc->mode.level == PSM_LEVEL_NATIVE)
3422			goto next_native;
3423
3424		c = pb->ipacket[0];
3425		/*
3426		 * A kludge for Kensington device!
3427		 * The MSB of the horizontal count appears to be stored in
3428		 * a strange place.
3429		 */
3430		if (sc->hw.model == MOUSE_MODEL_THINK)
3431			pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
3432
3433		/* ignore the overflow bits... */
3434		x = (c & MOUSE_PS2_XNEG) ?
3435		    pb->ipacket[1] - 256 : pb->ipacket[1];
3436		y = (c & MOUSE_PS2_YNEG) ?
3437		    pb->ipacket[2] - 256 : pb->ipacket[2];
3438		z = 0;
3439		ms.obutton = sc->button;	  /* previous button state */
3440		ms.button = butmap[c & MOUSE_PS2_BUTTONS];
3441		/* `tapping' action */
3442		if (sc->config & PSM_CONFIG_FORCETAP)
3443			ms.button |= ((c & MOUSE_PS2_TAP)) ?
3444			    0 : MOUSE_BUTTON4DOWN;
3445
3446		switch (sc->hw.model) {
3447
3448		case MOUSE_MODEL_EXPLORER:
3449			/*
3450			 *          b7 b6 b5 b4 b3 b2 b1 b0
3451			 * byte 1:  oy ox sy sx 1  M  R  L
3452			 * byte 2:  x  x  x  x  x  x  x  x
3453			 * byte 3:  y  y  y  y  y  y  y  y
3454			 * byte 4:  *  *  S2 S1 s  d2 d1 d0
3455			 *
3456			 * L, M, R, S1, S2: left, middle, right and side buttons
3457			 * s: wheel data sign bit
3458			 * d2-d0: wheel data
3459			 */
3460			z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ?
3461			    (pb->ipacket[3] & 0x0f) - 16 :
3462			    (pb->ipacket[3] & 0x0f);
3463			ms.button |=
3464			    (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ?
3465			    MOUSE_BUTTON4DOWN : 0;
3466			ms.button |=
3467			    (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ?
3468			    MOUSE_BUTTON5DOWN : 0;
3469			break;
3470
3471		case MOUSE_MODEL_INTELLI:
3472		case MOUSE_MODEL_NET:
3473			/* wheel data is in the fourth byte */
3474			z = (char)pb->ipacket[3];
3475			/*
3476			 * XXX some mice may send 7 when there is no Z movement?			 */
3477			if ((z >= 7) || (z <= -7))
3478				z = 0;
3479			/* some compatible mice have additional buttons */
3480			ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ?
3481			    MOUSE_BUTTON4DOWN : 0;
3482			ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ?
3483			    MOUSE_BUTTON5DOWN : 0;
3484			break;
3485
3486		case MOUSE_MODEL_MOUSEMANPLUS:
3487			proc_mmanplus(sc, pb, &ms, &x, &y, &z);
3488			break;
3489
3490		case MOUSE_MODEL_GLIDEPOINT:
3491			/* `tapping' action */
3492			ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 :
3493			    MOUSE_BUTTON4DOWN;
3494			break;
3495
3496		case MOUSE_MODEL_NETSCROLL:
3497			/*
3498			 * three addtional bytes encode buttons and
3499			 * wheel events
3500			 */
3501			ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ?
3502			    MOUSE_BUTTON4DOWN : 0;
3503			ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ?
3504			    MOUSE_BUTTON5DOWN : 0;
3505			z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ?
3506			    pb->ipacket[4] - 256 : pb->ipacket[4];
3507			break;
3508
3509		case MOUSE_MODEL_THINK:
3510			/* the fourth button state in the first byte */
3511			ms.button |= (c & MOUSE_PS2_TAP) ?
3512			    MOUSE_BUTTON4DOWN : 0;
3513			break;
3514
3515		case MOUSE_MODEL_VERSAPAD:
3516			proc_versapad(sc, pb, &ms, &x, &y, &z);
3517			c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
3518			    ((y < 0) ? MOUSE_PS2_YNEG : 0);
3519			break;
3520
3521		case MOUSE_MODEL_4D:
3522			/*
3523			 *          b7 b6 b5 b4 b3 b2 b1 b0
3524			 * byte 1:  s2 d2 s1 d1 1  M  R  L
3525			 * byte 2:  sx x  x  x  x  x  x  x
3526			 * byte 3:  sy y  y  y  y  y  y  y
3527			 *
3528			 * s1: wheel 1 direction
3529			 * d1: wheel 1 data
3530			 * s2: wheel 2 direction
3531			 * d2: wheel 2 data
3532			 */
3533			x = (pb->ipacket[1] & 0x80) ?
3534			    pb->ipacket[1] - 256 : pb->ipacket[1];
3535			y = (pb->ipacket[2] & 0x80) ?
3536			    pb->ipacket[2] - 256 : pb->ipacket[2];
3537			switch (c & MOUSE_4D_WHEELBITS) {
3538			case 0x10:
3539				z = 1;
3540				break;
3541			case 0x30:
3542				z = -1;
3543				break;
3544			case 0x40:	/* XXX 2nd wheel turning right */
3545				z = 2;
3546				break;
3547			case 0xc0:	/* XXX 2nd wheel turning left */
3548				z = -2;
3549				break;
3550			}
3551			break;
3552
3553		case MOUSE_MODEL_4DPLUS:
3554			if ((x < 16 - 256) && (y < 16 - 256)) {
3555				/*
3556				 *          b7 b6 b5 b4 b3 b2 b1 b0
3557				 * byte 1:  0  0  1  1  1  M  R  L
3558				 * byte 2:  0  0  0  0  1  0  0  0
3559				 * byte 3:  0  0  0  0  S  s  d1 d0
3560				 *
3561				 * L, M, R, S: left, middle, right,
3562				 *             and side buttons
3563				 * s: wheel data sign bit
3564				 * d1-d0: wheel data
3565				 */
3566				x = y = 0;
3567				if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
3568					ms.button |= MOUSE_BUTTON4DOWN;
3569				z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ?
3570				    ((pb->ipacket[2] & 0x07) - 8) :
3571				    (pb->ipacket[2] & 0x07) ;
3572			} else {
3573				/* preserve previous button states */
3574				ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
3575			}
3576			break;
3577
3578		case MOUSE_MODEL_SYNAPTICS:
3579			if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0) {
3580				VLOG(3, (LOG_DEBUG, "synaptics: "
3581				    "packet rejected\n"));
3582				goto next;
3583			}
3584			break;
3585
3586		case MOUSE_MODEL_TRACKPOINT:
3587		case MOUSE_MODEL_GENERIC:
3588		default:
3589			break;
3590		}
3591
3592	/* scale values */
3593	if (sc->mode.accelfactor >= 1) {
3594		if (x != 0) {
3595			x = x * x / sc->mode.accelfactor;
3596			if (x == 0)
3597				x = 1;
3598			if (c & MOUSE_PS2_XNEG)
3599				x = -x;
3600		}
3601		if (y != 0) {
3602			y = y * y / sc->mode.accelfactor;
3603			if (y == 0)
3604				y = 1;
3605			if (c & MOUSE_PS2_YNEG)
3606				y = -y;
3607		}
3608	}
3609
3610	ms.dx = x;
3611	ms.dy = y;
3612	ms.dz = z;
3613	ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) |
3614	    (ms.obutton ^ ms.button);
3615
3616	pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket);
3617
3618	sc->status.flags |= ms.flags;
3619	sc->status.dx += ms.dx;
3620	sc->status.dy += ms.dy;
3621	sc->status.dz += ms.dz;
3622	sc->status.button = ms.button;
3623	sc->button = ms.button;
3624
3625next_native:
3626	sc->watchdog = FALSE;
3627
3628	/* queue data */
3629	if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) {
3630		l = imin(pb->inputbytes,
3631		    sizeof(sc->queue.buf) - sc->queue.tail);
3632		bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
3633		if (pb->inputbytes > l)
3634			bcopy(&pb->ipacket[l], &sc->queue.buf[0],
3635			    pb->inputbytes - l);
3636		sc->queue.tail = (sc->queue.tail + pb->inputbytes) %
3637		    sizeof(sc->queue.buf);
3638		sc->queue.count += pb->inputbytes;
3639	}
3640
3641next:
3642	pb->inputbytes = 0;
3643	if (++sc->pqueue_start >= PSM_PACKETQUEUE)
3644		sc->pqueue_start = 0;
3645	} while (sc->pqueue_start != sc->pqueue_end);
3646
3647	if (sc->state & PSM_ASLP) {
3648		sc->state &= ~PSM_ASLP;
3649		wakeup(sc);
3650	}
3651	selwakeuppri(&sc->rsel, PZERO);
3652	if (sc->async != NULL) {
3653		pgsigio(&sc->async, SIGIO, 0);
3654	}
3655	sc->state &= ~PSM_SOFTARMED;
3656	splx(s);
3657}
3658
3659static int
3660psmpoll(struct cdev *dev, int events, struct thread *td)
3661{
3662	struct psm_softc *sc = dev->si_drv1;
3663	int s;
3664	int revents = 0;
3665
3666	/* Return true if a mouse event available */
3667	s = spltty();
3668	if (events & (POLLIN | POLLRDNORM)) {
3669		if (sc->queue.count > 0)
3670			revents |= events & (POLLIN | POLLRDNORM);
3671		else
3672			selrecord(td, &sc->rsel);
3673	}
3674	splx(s);
3675
3676	return (revents);
3677}
3678
3679/* vendor/model specific routines */
3680
3681static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
3682{
3683	if (set_mouse_resolution(kbdc, res) != res)
3684		return (FALSE);
3685	if (set_mouse_scaling(kbdc, scale) &&
3686	    set_mouse_scaling(kbdc, scale) &&
3687	    set_mouse_scaling(kbdc, scale) &&
3688	    (get_mouse_status(kbdc, status, 0, 3) >= 3))
3689		return (TRUE);
3690	return (FALSE);
3691}
3692
3693static int
3694mouse_ext_command(KBDC kbdc, int command)
3695{
3696	int c;
3697
3698	c = (command >> 6) & 0x03;
3699	if (set_mouse_resolution(kbdc, c) != c)
3700		return (FALSE);
3701	c = (command >> 4) & 0x03;
3702	if (set_mouse_resolution(kbdc, c) != c)
3703		return (FALSE);
3704	c = (command >> 2) & 0x03;
3705	if (set_mouse_resolution(kbdc, c) != c)
3706		return (FALSE);
3707	c = (command >> 0) & 0x03;
3708	if (set_mouse_resolution(kbdc, c) != c)
3709		return (FALSE);
3710	return (TRUE);
3711}
3712
3713#ifdef notyet
3714/* Logitech MouseMan Cordless II */
3715static int
3716enable_lcordless(KDBC kbdc, struct psm_softc *sc)
3717{
3718	int status[3];
3719	int ch;
3720
3721	if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 2, status))
3722		return (FALSE);
3723	if (status[1] == PSMD_RES_HIGH)
3724		return (FALSE);
3725	ch = (status[0] & 0x07) - 1;	/* channel # */
3726	if ((ch <= 0) || (ch > 4))
3727		return (FALSE);
3728	/*
3729	 * status[1]: always one?
3730	 * status[2]: battery status? (0-100)
3731	 */
3732	return (TRUE);
3733}
3734#endif /* notyet */
3735
3736/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
3737static int
3738enable_groller(KBDC kbdc, struct psm_softc *sc)
3739{
3740	int status[3];
3741
3742	/*
3743	 * The special sequence to enable the fourth button and the
3744	 * roller. Immediately after this sequence check status bytes.
3745	 * if the mouse is NetScroll, the second and the third bytes are
3746	 * '3' and 'D'.
3747	 */
3748
3749	/*
3750	 * If the mouse is an ordinary PS/2 mouse, the status bytes should
3751	 * look like the following.
3752	 *
3753	 * byte 1 bit 7 always 0
3754	 *        bit 6 stream mode (0)
3755	 *        bit 5 disabled (0)
3756	 *        bit 4 1:1 scaling (0)
3757	 *        bit 3 always 0
3758	 *        bit 0-2 button status
3759	 * byte 2 resolution (PSMD_RES_HIGH)
3760	 * byte 3 report rate (?)
3761	 */
3762
3763	if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3764		return (FALSE);
3765	if ((status[1] != '3') || (status[2] != 'D'))
3766		return (FALSE);
3767	/* FIXME: SmartScroll Mouse has 5 buttons! XXX */
3768	if (sc != NULL)
3769		sc->hw.buttons = 4;
3770	return (TRUE);
3771}
3772
3773/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
3774static int
3775enable_gmouse(KBDC kbdc, struct psm_softc *sc)
3776{
3777	int status[3];
3778
3779	/*
3780	 * The special sequence to enable the middle, "rubber" button.
3781	 * Immediately after this sequence check status bytes.
3782	 * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
3783	 * the second and the third bytes are '3' and 'U'.
3784	 * NOTE: NetMouse reports that it has three buttons although it has
3785	 * two buttons and a rubber button. NetMouse Pro and MIE Mouse
3786	 * say they have three buttons too and they do have a button on the
3787	 * side...
3788	 */
3789	if (!mouse_id_proc1(kbdc, PSMD_RES_HIGH, 1, status))
3790		return (FALSE);
3791	if ((status[1] != '3') || (status[2] != 'U'))
3792		return (FALSE);
3793	return (TRUE);
3794}
3795
3796/* ALPS GlidePoint */
3797static int
3798enable_aglide(KBDC kbdc, struct psm_softc *sc)
3799{
3800	int status[3];
3801
3802	/*
3803	 * The special sequence to obtain ALPS GlidePoint specific
3804	 * information. Immediately after this sequence, status bytes will
3805	 * contain something interesting.
3806	 * NOTE: ALPS produces several models of GlidePoint. Some of those
3807	 * do not respond to this sequence, thus, cannot be detected this way.
3808	 */
3809	if (set_mouse_sampling_rate(kbdc, 100) != 100)
3810		return (FALSE);
3811	if (!mouse_id_proc1(kbdc, PSMD_RES_LOW, 2, status))
3812		return (FALSE);
3813	if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
3814		return (FALSE);
3815	return (TRUE);
3816}
3817
3818/* Kensington ThinkingMouse/Trackball */
3819static int
3820enable_kmouse(KBDC kbdc, struct psm_softc *sc)
3821{
3822	static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
3823	int status[3];
3824	int id1;
3825	int id2;
3826	int i;
3827
3828	id1 = get_aux_id(kbdc);
3829	if (set_mouse_sampling_rate(kbdc, 10) != 10)
3830		return (FALSE);
3831	/*
3832	 * The device is now in the native mode? It returns a different
3833	 * ID value...
3834	 */
3835	id2 = get_aux_id(kbdc);
3836	if ((id1 == id2) || (id2 != 2))
3837		return (FALSE);
3838
3839	if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
3840		return (FALSE);
3841#if PSM_DEBUG >= 2
3842	/* at this point, resolution is LOW, sampling rate is 10/sec */
3843	if (get_mouse_status(kbdc, status, 0, 3) < 3)
3844		return (FALSE);
3845#endif
3846
3847	/*
3848	 * The special sequence to enable the third and fourth buttons.
3849	 * Otherwise they behave like the first and second buttons.
3850	 */
3851	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3852		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3853			return (FALSE);
3854
3855	/*
3856	 * At this point, the device is using default resolution and
3857	 * sampling rate for the native mode.
3858	 */
3859	if (get_mouse_status(kbdc, status, 0, 3) < 3)
3860		return (FALSE);
3861	if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
3862		return (FALSE);
3863
3864	/* the device appears be enabled by this sequence, diable it for now */
3865	disable_aux_dev(kbdc);
3866	empty_aux_buffer(kbdc, 5);
3867
3868	return (TRUE);
3869}
3870
3871/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
3872static int
3873enable_mmanplus(KBDC kbdc, struct psm_softc *sc)
3874{
3875	int data[3];
3876
3877	/* the special sequence to enable the fourth button and the roller. */
3878	/*
3879	 * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
3880	 * must be called exactly three times since the last RESET command
3881	 * before this sequence. XXX
3882	 */
3883	if (!set_mouse_scaling(kbdc, 1))
3884		return (FALSE);
3885	if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
3886		return (FALSE);
3887	if (get_mouse_status(kbdc, data, 1, 3) < 3)
3888		return (FALSE);
3889
3890	/*
3891	 * PS2++ protocol, packet type 0
3892	 *
3893	 *          b7 b6 b5 b4 b3 b2 b1 b0
3894	 * byte 1:  *  1  p3 p2 1  *  *  *
3895	 * byte 2:  1  1  p1 p0 m1 m0 1  0
3896	 * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
3897	 *
3898	 * p3-p0: packet type: 0
3899	 * m7-m0: model ID: MouseMan+:0x50,
3900	 *		    FirstMouse+:0x51,
3901	 *		    ScrollPoint:0x58...
3902	 */
3903	/* check constant bits */
3904	if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
3905		return (FALSE);
3906	if ((data[1] & 0xc3) != 0xc2)
3907		return (FALSE);
3908	/* check d3-d0 in byte 2 */
3909	if (!MOUSE_PS2PLUS_CHECKBITS(data))
3910		return (FALSE);
3911	/* check p3-p0 */
3912	if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
3913		return (FALSE);
3914
3915	if (sc != NULL) {
3916		sc->hw.hwid &= 0x00ff;
3917		sc->hw.hwid |= data[2] << 8;	/* save model ID */
3918	}
3919
3920	/*
3921	 * MouseMan+ (or FirstMouse+) is now in its native mode, in which
3922	 * the wheel and the fourth button events are encoded in the
3923	 * special data packet. The mouse may be put in the IntelliMouse mode
3924	 * if it is initialized by the IntelliMouse's method.
3925	 */
3926	return (TRUE);
3927}
3928
3929/* MS IntelliMouse Explorer */
3930static int
3931enable_msexplorer(KBDC kbdc, struct psm_softc *sc)
3932{
3933	static u_char rate0[] = { 200, 100, 80, };
3934	static u_char rate1[] = { 200, 200, 80, };
3935	int id;
3936	int i;
3937
3938	/*
3939	 * This is needed for at least A4Tech X-7xx mice - they do not go
3940	 * straight to Explorer mode, but need to be set to Intelli mode
3941	 * first.
3942	 */
3943	enable_msintelli(kbdc, sc);
3944
3945	/* the special sequence to enable the extra buttons and the roller. */
3946	for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i)
3947		if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
3948			return (FALSE);
3949	/* the device will give the genuine ID only after the above sequence */
3950	id = get_aux_id(kbdc);
3951	if (id != PSM_EXPLORER_ID)
3952		return (FALSE);
3953
3954	if (sc != NULL) {
3955		sc->hw.buttons = 5;	/* IntelliMouse Explorer XXX */
3956		sc->hw.hwid = id;
3957	}
3958
3959	/*
3960	 * XXX: this is a kludge to fool some KVM switch products
3961	 * which think they are clever enough to know the 4-byte IntelliMouse
3962	 * protocol, and assume any other protocols use 3-byte packets.
3963	 * They don't convey 4-byte data packets from the IntelliMouse Explorer
3964	 * correctly to the host computer because of this!
3965	 * The following sequence is actually IntelliMouse's "wake up"
3966	 * sequence; it will make the KVM think the mouse is IntelliMouse
3967	 * when it is in fact IntelliMouse Explorer.
3968	 */
3969	for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i)
3970		if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
3971			break;
3972	get_aux_id(kbdc);
3973
3974	return (TRUE);
3975}
3976
3977/* MS IntelliMouse */
3978static int
3979enable_msintelli(KBDC kbdc, struct psm_softc *sc)
3980{
3981	/*
3982	 * Logitech MouseMan+ and FirstMouse+ will also respond to this
3983	 * probe routine and act like IntelliMouse.
3984	 */
3985
3986	static u_char rate[] = { 200, 100, 80, };
3987	int id;
3988	int i;
3989
3990	/* the special sequence to enable the third button and the roller. */
3991	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3992		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3993			return (FALSE);
3994	/* the device will give the genuine ID only after the above sequence */
3995	id = get_aux_id(kbdc);
3996	if (id != PSM_INTELLI_ID)
3997		return (FALSE);
3998
3999	if (sc != NULL) {
4000		sc->hw.buttons = 3;
4001		sc->hw.hwid = id;
4002	}
4003
4004	return (TRUE);
4005}
4006
4007/* A4 Tech 4D Mouse */
4008static int
4009enable_4dmouse(KBDC kbdc, struct psm_softc *sc)
4010{
4011	/*
4012	 * Newer wheel mice from A4 Tech may use the 4D+ protocol.
4013	 */
4014
4015	static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
4016	int id;
4017	int i;
4018
4019	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
4020		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
4021			return (FALSE);
4022	id = get_aux_id(kbdc);
4023	/*
4024	 * WinEasy 4D, 4 Way Scroll 4D: 6
4025	 * Cable-Free 4D: 8 (4DPLUS)
4026	 * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
4027	 */
4028	if (id != PSM_4DMOUSE_ID)
4029		return (FALSE);
4030
4031	if (sc != NULL) {
4032		sc->hw.buttons = 3;	/* XXX some 4D mice have 4? */
4033		sc->hw.hwid = id;
4034	}
4035
4036	return (TRUE);
4037}
4038
4039/* A4 Tech 4D+ Mouse */
4040static int
4041enable_4dplus(KBDC kbdc, struct psm_softc *sc)
4042{
4043	/*
4044	 * Newer wheel mice from A4 Tech seem to use this protocol.
4045	 * Older models are recognized as either 4D Mouse or IntelliMouse.
4046	 */
4047	int id;
4048
4049	/*
4050	 * enable_4dmouse() already issued the following ID sequence...
4051	static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
4052	int i;
4053
4054	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
4055		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
4056			return (FALSE);
4057	*/
4058
4059	id = get_aux_id(kbdc);
4060	switch (id) {
4061	case PSM_4DPLUS_ID:
4062		break;
4063	case PSM_4DPLUS_RFSW35_ID:
4064		break;
4065	default:
4066		return (FALSE);
4067	}
4068
4069	if (sc != NULL) {
4070		sc->hw.buttons = (id == PSM_4DPLUS_ID) ? 4 : 3;
4071		sc->hw.hwid = id;
4072	}
4073
4074	return (TRUE);
4075}
4076
4077/* Synaptics Touchpad */
4078static int
4079synaptics_sysctl(SYSCTL_HANDLER_ARGS)
4080{
4081	int error, arg;
4082
4083	/* Read the current value. */
4084	arg = *(int *)oidp->oid_arg1;
4085	error = sysctl_handle_int(oidp, &arg, 0, req);
4086
4087	/* Sanity check. */
4088	if (error || !req->newptr)
4089		return (error);
4090
4091	/*
4092	 * Check that the new value is in the concerned node's range
4093	 * of values.
4094	 */
4095	switch (oidp->oid_arg2) {
4096	case SYNAPTICS_SYSCTL_MIN_PRESSURE:
4097	case SYNAPTICS_SYSCTL_MAX_PRESSURE:
4098		if (arg < 0 || arg > 255)
4099			return (EINVAL);
4100		break;
4101	case SYNAPTICS_SYSCTL_MAX_WIDTH:
4102		if (arg < 4 || arg > 15)
4103			return (EINVAL);
4104		break;
4105	case SYNAPTICS_SYSCTL_MARGIN_TOP:
4106	case SYNAPTICS_SYSCTL_MARGIN_RIGHT:
4107	case SYNAPTICS_SYSCTL_MARGIN_BOTTOM:
4108	case SYNAPTICS_SYSCTL_MARGIN_LEFT:
4109	case SYNAPTICS_SYSCTL_NA_TOP:
4110	case SYNAPTICS_SYSCTL_NA_RIGHT:
4111	case SYNAPTICS_SYSCTL_NA_BOTTOM:
4112	case SYNAPTICS_SYSCTL_NA_LEFT:
4113		if (arg < 0 || arg > 6143)
4114			return (EINVAL);
4115		break;
4116	case SYNAPTICS_SYSCTL_WINDOW_MIN:
4117	case SYNAPTICS_SYSCTL_WINDOW_MAX:
4118	case SYNAPTICS_SYSCTL_TAP_MIN_QUEUE:
4119		if (arg < 1 || arg > SYNAPTICS_PACKETQUEUE)
4120			return (EINVAL);
4121		break;
4122	case SYNAPTICS_SYSCTL_MULTIPLICATOR:
4123	case SYNAPTICS_SYSCTL_WEIGHT_CURRENT:
4124	case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS:
4125	case SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA:
4126	case SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED:
4127	case SYNAPTICS_SYSCTL_DIV_MIN:
4128	case SYNAPTICS_SYSCTL_DIV_MAX:
4129	case SYNAPTICS_SYSCTL_DIV_MAX_NA:
4130	case SYNAPTICS_SYSCTL_DIV_LEN:
4131	case SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN:
4132	case SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX:
4133		if (arg < 1)
4134			return (EINVAL);
4135		break;
4136	case SYNAPTICS_SYSCTL_TAP_MAX_DELTA:
4137	case SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT:
4138	case SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA:
4139		if (arg < 0)
4140			return (EINVAL);
4141		break;
4142	case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA:
4143	case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA:
4144		if (arg < -6143 || arg > 6143)
4145			return (EINVAL);
4146		break;
4147        case SYNAPTICS_SYSCTL_TOUCHPAD_OFF:
4148		if (arg < 0 || arg > 1)
4149			return (EINVAL);
4150		break;
4151	default:
4152		return (EINVAL);
4153	}
4154
4155	/* Update. */
4156	*(int *)oidp->oid_arg1 = arg;
4157
4158	return (error);
4159}
4160
4161static void
4162synaptics_sysctl_create_tree(struct psm_softc *sc)
4163{
4164
4165	if (sc->syninfo.sysctl_tree != NULL)
4166		return;
4167
4168	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
4169	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
4170	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
4171	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
4172	    0, "Synaptics TouchPad");
4173
4174	/* hw.psm.synaptics.directional_scrolls. */
4175	sc->syninfo.directional_scrolls = 0;
4176	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
4177	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4178	    "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
4179	    &sc->syninfo.directional_scrolls, 0,
4180	    "Enable hardware scrolling pad (if non-zero) or register it as "
4181	    "extended buttons (if 0)");
4182
4183	/*
4184	 * Turn off two finger scroll if we have a
4185	 * physical area reserved for scrolling or when
4186	 * there's no multi finger support.
4187	 */
4188	if (sc->synhw.verticalScroll || sc->synhw.capMultiFinger == 0)
4189		sc->syninfo.two_finger_scroll = 0;
4190	else
4191		sc->syninfo.two_finger_scroll = 1;
4192	/* hw.psm.synaptics.two_finger_scroll. */
4193	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
4194	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4195	    "two_finger_scroll", CTLFLAG_RW|CTLFLAG_ANYBODY,
4196	    &sc->syninfo.two_finger_scroll, 0,
4197	    "Enable two finger scrolling");
4198
4199	/* hw.psm.synaptics.min_pressure. */
4200	sc->syninfo.min_pressure = 16;
4201	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4202	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4203	    "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4204	    &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE,
4205	    synaptics_sysctl, "I",
4206	    "Minimum pressure required to start an action");
4207
4208	/* hw.psm.synaptics.max_pressure. */
4209	sc->syninfo.max_pressure = 220;
4210	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4211	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4212	    "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4213	    &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE,
4214	    synaptics_sysctl, "I",
4215	    "Maximum pressure to detect palm");
4216
4217	/* hw.psm.synaptics.max_width. */
4218	sc->syninfo.max_width = 10;
4219	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4220	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4221	    "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4222	    &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH,
4223	    synaptics_sysctl, "I",
4224	    "Maximum finger width to detect palm");
4225
4226	/* hw.psm.synaptics.top_margin. */
4227	sc->syninfo.margin_top = 200;
4228	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4229	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4230	    "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4231	    &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP,
4232	    synaptics_sysctl, "I",
4233	    "Top margin");
4234
4235	/* hw.psm.synaptics.right_margin. */
4236	sc->syninfo.margin_right = 200;
4237	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4238	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4239	    "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4240	    &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT,
4241	    synaptics_sysctl, "I",
4242	    "Right margin");
4243
4244	/* hw.psm.synaptics.bottom_margin. */
4245	sc->syninfo.margin_bottom = 200;
4246	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4247	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4248	    "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4249	    &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
4250	    synaptics_sysctl, "I",
4251	    "Bottom margin");
4252
4253	/* hw.psm.synaptics.left_margin. */
4254	sc->syninfo.margin_left = 200;
4255	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4256	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4257	    "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4258	    &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT,
4259	    synaptics_sysctl, "I",
4260	    "Left margin");
4261
4262	/* hw.psm.synaptics.na_top. */
4263	sc->syninfo.na_top = 1783;
4264	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4265	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4266	    "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4267	    &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP,
4268	    synaptics_sysctl, "I",
4269	    "Top noisy area, where weight_previous_na is used instead "
4270	    "of weight_previous");
4271
4272	/* hw.psm.synaptics.na_right. */
4273	sc->syninfo.na_right = 563;
4274	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4275	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4276	    "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4277	    &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT,
4278	    synaptics_sysctl, "I",
4279	    "Right noisy area, where weight_previous_na is used instead "
4280	    "of weight_previous");
4281
4282	/* hw.psm.synaptics.na_bottom. */
4283	sc->syninfo.na_bottom = 1408;
4284	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4285	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4286	    "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4287	    &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM,
4288	    synaptics_sysctl, "I",
4289	    "Bottom noisy area, where weight_previous_na is used instead "
4290	    "of weight_previous");
4291
4292	/* hw.psm.synaptics.na_left. */
4293	sc->syninfo.na_left = 1600;
4294	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4295	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4296	    "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4297	    &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT,
4298	    synaptics_sysctl, "I",
4299	    "Left noisy area, where weight_previous_na is used instead "
4300	    "of weight_previous");
4301
4302	/* hw.psm.synaptics.window_min. */
4303	sc->syninfo.window_min = 4;
4304	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4305	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4306	    "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4307	    &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN,
4308	    synaptics_sysctl, "I",
4309	    "Minimum window size to start an action");
4310
4311	/* hw.psm.synaptics.window_max. */
4312	sc->syninfo.window_max = 10;
4313	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4314	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4315	    "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4316	    &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX,
4317	    synaptics_sysctl, "I",
4318	    "Maximum window size");
4319
4320	/* hw.psm.synaptics.multiplicator. */
4321	sc->syninfo.multiplicator = 10000;
4322	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4323	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4324	    "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4325	    &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR,
4326	    synaptics_sysctl, "I",
4327	    "Multiplicator to increase precision in averages and divisions");
4328
4329	/* hw.psm.synaptics.weight_current. */
4330	sc->syninfo.weight_current = 3;
4331	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4332	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4333	    "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4334	    &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
4335	    synaptics_sysctl, "I",
4336	    "Weight of the current movement in the new average");
4337
4338	/* hw.psm.synaptics.weight_previous. */
4339	sc->syninfo.weight_previous = 6;
4340	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4341	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4342	    "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4343	    &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
4344	    synaptics_sysctl, "I",
4345	    "Weight of the previous average");
4346
4347	/* hw.psm.synaptics.weight_previous_na. */
4348	sc->syninfo.weight_previous_na = 20;
4349	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4350	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4351	    "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4352	    &sc->syninfo.weight_previous_na,
4353	    SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
4354	    synaptics_sysctl, "I",
4355	    "Weight of the previous average (inside the noisy area)");
4356
4357	/* hw.psm.synaptics.weight_len_squared. */
4358	sc->syninfo.weight_len_squared = 2000;
4359	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4360	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4361	    "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4362	    &sc->syninfo.weight_len_squared,
4363	    SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
4364	    synaptics_sysctl, "I",
4365	    "Length (squared) of segments where weight_previous "
4366	    "starts to decrease");
4367
4368	/* hw.psm.synaptics.div_min. */
4369	sc->syninfo.div_min = 9;
4370	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4371	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4372	    "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4373	    &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN,
4374	    synaptics_sysctl, "I",
4375	    "Divisor for fast movements");
4376
4377	/* hw.psm.synaptics.div_max. */
4378	sc->syninfo.div_max = 17;
4379	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4380	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4381	    "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4382	    &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX,
4383	    synaptics_sysctl, "I",
4384	    "Divisor for slow movements");
4385
4386	/* hw.psm.synaptics.div_max_na. */
4387	sc->syninfo.div_max_na = 30;
4388	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4389	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4390	    "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4391	    &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA,
4392	    synaptics_sysctl, "I",
4393	    "Divisor with slow movements (inside the noisy area)");
4394
4395	/* hw.psm.synaptics.div_len. */
4396	sc->syninfo.div_len = 100;
4397	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4398	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4399	    "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4400	    &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN,
4401	    synaptics_sysctl, "I",
4402	    "Length of segments where div_max starts to decrease");
4403
4404	/* hw.psm.synaptics.tap_max_delta. */
4405	sc->syninfo.tap_max_delta = 80;
4406	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4407	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4408	    "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4409	    &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
4410	    synaptics_sysctl, "I",
4411	    "Length of segments above which a tap is ignored");
4412
4413	/* hw.psm.synaptics.tap_min_queue. */
4414	sc->syninfo.tap_min_queue = 2;
4415	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4416	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4417	    "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4418	    &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
4419	    synaptics_sysctl, "I",
4420	    "Number of packets required to consider a tap");
4421
4422	/* hw.psm.synaptics.taphold_timeout. */
4423	sc->synaction.in_taphold = 0;
4424	sc->syninfo.taphold_timeout = tap_timeout;
4425	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4426	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4427	    "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4428	    &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
4429	    synaptics_sysctl, "I",
4430	    "Maximum elapsed time between two taps to consider a tap-hold "
4431	    "action");
4432
4433	/* hw.psm.synaptics.vscroll_hor_area. */
4434	sc->syninfo.vscroll_hor_area = 0; /* 1300 */
4435	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4436	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4437	    "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4438	    &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
4439	    synaptics_sysctl, "I",
4440	    "Area reserved for horizontal virtual scrolling");
4441
4442	/* hw.psm.synaptics.vscroll_ver_area. */
4443	sc->syninfo.vscroll_ver_area = -600;
4444	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4445	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4446	    "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4447	    &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
4448	    synaptics_sysctl, "I",
4449	    "Area reserved for vertical virtual scrolling");
4450
4451	/* hw.psm.synaptics.vscroll_min_delta. */
4452	sc->syninfo.vscroll_min_delta = 50;
4453	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4454	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4455	    "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4456	    &sc->syninfo.vscroll_min_delta,
4457	    SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
4458	    synaptics_sysctl, "I",
4459	    "Minimum movement to consider virtual scrolling");
4460
4461	/* hw.psm.synaptics.vscroll_div_min. */
4462	sc->syninfo.vscroll_div_min = 100;
4463	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4464	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4465	    "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4466	    &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
4467	    synaptics_sysctl, "I",
4468	    "Divisor for fast scrolling");
4469
4470	/* hw.psm.synaptics.vscroll_div_min. */
4471	sc->syninfo.vscroll_div_max = 150;
4472	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4473	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4474	    "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4475	    &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
4476	    synaptics_sysctl, "I",
4477	    "Divisor for slow scrolling");
4478
4479	/* hw.psm.synaptics.touchpad_off. */
4480	sc->syninfo.touchpad_off = 0;
4481	SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx,
4482	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
4483	    "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4484	    &sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF,
4485	    synaptics_sysctl, "I",
4486	    "Turn off touchpad");
4487}
4488
4489static int
4490enable_synaptics(KBDC kbdc, struct psm_softc *sc)
4491{
4492	synapticshw_t synhw;
4493	int status[3];
4494	int buttons;
4495
4496	VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n"));
4497
4498	/*
4499	 * Just to be on the safe side: this avoids troubles with
4500	 * following mouse_ext_command() when the previous command
4501	 * was PSMC_SET_RESOLUTION. Set Scaling has no effect on
4502	 * Synaptics Touchpad behaviour.
4503	 */
4504	set_mouse_scaling(kbdc, 1);
4505
4506	/* Identify the Touchpad version. */
4507	if (mouse_ext_command(kbdc, 0) == 0)
4508		return (FALSE);
4509	if (get_mouse_status(kbdc, status, 0, 3) != 3)
4510		return (FALSE);
4511	if (status[1] != 0x47)
4512		return (FALSE);
4513
4514	bzero(&synhw, sizeof(synhw));
4515	synhw.infoMinor = status[0];
4516	synhw.infoMajor = status[2] & 0x0f;
4517
4518	if (verbose >= 2)
4519		printf("Synaptics Touchpad v%d.%d\n", synhw.infoMajor,
4520		    synhw.infoMinor);
4521
4522	if (synhw.infoMajor < 4) {
4523		printf("  Unsupported (pre-v4) Touchpad detected\n");
4524		return (FALSE);
4525	}
4526
4527	/* Get the Touchpad model information. */
4528	if (mouse_ext_command(kbdc, 3) == 0)
4529		return (FALSE);
4530	if (get_mouse_status(kbdc, status, 0, 3) != 3)
4531		return (FALSE);
4532	if ((status[1] & 0x01) != 0) {
4533		printf("  Failed to read model information\n");
4534		return (FALSE);
4535	}
4536
4537	synhw.infoRot180   = (status[0] & 0x80) != 0;
4538	synhw.infoPortrait = (status[0] & 0x40) != 0;
4539	synhw.infoSensor   =  status[0] & 0x3f;
4540	synhw.infoHardware = (status[1] & 0xfe) >> 1;
4541	synhw.infoNewAbs   = (status[2] & 0x80) != 0;
4542	synhw.capPen       = (status[2] & 0x40) != 0;
4543	synhw.infoSimplC   = (status[2] & 0x20) != 0;
4544	synhw.infoGeometry =  status[2] & 0x0f;
4545
4546	if (verbose >= 2) {
4547		printf("  Model information:\n");
4548		printf("   infoRot180: %d\n", synhw.infoRot180);
4549		printf("   infoPortrait: %d\n", synhw.infoPortrait);
4550		printf("   infoSensor: %d\n", synhw.infoSensor);
4551		printf("   infoHardware: %d\n", synhw.infoHardware);
4552		printf("   infoNewAbs: %d\n", synhw.infoNewAbs);
4553		printf("   capPen: %d\n", synhw.capPen);
4554		printf("   infoSimplC: %d\n", synhw.infoSimplC);
4555		printf("   infoGeometry: %d\n", synhw.infoGeometry);
4556	}
4557
4558	/* Read the extended capability bits. */
4559	if (mouse_ext_command(kbdc, 2) == 0)
4560		return (FALSE);
4561	if (get_mouse_status(kbdc, status, 0, 3) != 3)
4562		return (FALSE);
4563	if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4564		printf("  Failed to read extended capability bits\n");
4565		return (FALSE);
4566	}
4567
4568	/* Set the different capabilities when they exist. */
4569	buttons = 0;
4570	synhw.capExtended = (status[0] & 0x80) != 0;
4571	if (synhw.capExtended) {
4572		synhw.nExtendedQueries = (status[0] & 0x70) != 0;
4573		synhw.capMiddle        = (status[0] & 0x04) != 0;
4574		synhw.capPassthrough   = (status[2] & 0x80) != 0;
4575		synhw.capSleep         = (status[2] & 0x10) != 0;
4576		synhw.capFourButtons   = (status[2] & 0x08) != 0;
4577		synhw.capMultiFinger   = (status[2] & 0x02) != 0;
4578		synhw.capPalmDetect    = (status[2] & 0x01) != 0;
4579
4580		if (verbose >= 2) {
4581			printf("  Extended capabilities:\n");
4582			printf("   capExtended: %d\n", synhw.capExtended);
4583			printf("   capMiddle: %d\n", synhw.capMiddle);
4584			printf("   nExtendedQueries: %d\n",
4585			    synhw.nExtendedQueries);
4586			printf("   capPassthrough: %d\n", synhw.capPassthrough);
4587			printf("   capSleep: %d\n", synhw.capSleep);
4588			printf("   capFourButtons: %d\n", synhw.capFourButtons);
4589			printf("   capMultiFinger: %d\n", synhw.capMultiFinger);
4590			printf("   capPalmDetect: %d\n", synhw.capPalmDetect);
4591		}
4592
4593		/*
4594		 * If nExtendedQueries is 1 or greater, then the TouchPad
4595		 * supports this number of extended queries. We can load
4596		 * more information about buttons using query 0x09.
4597		 */
4598		if (synhw.capExtended && synhw.nExtendedQueries) {
4599			if (mouse_ext_command(kbdc, 0x09) == 0)
4600				return (FALSE);
4601			if (get_mouse_status(kbdc, status, 0, 3) != 3)
4602				return (FALSE);
4603			synhw.verticalScroll   = (status[0] & 0x01) != 0;
4604			synhw.horizontalScroll = (status[0] & 0x02) != 0;
4605			synhw.verticalWheel    = (status[0] & 0x08) != 0;
4606			synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
4607			if (verbose >= 2) {
4608				printf("  Extended model ID:\n");
4609				printf("   verticalScroll: %d\n",
4610				    synhw.verticalScroll);
4611				printf("   horizontalScroll: %d\n",
4612				    synhw.horizontalScroll);
4613				printf("   verticalWheel: %d\n",
4614				    synhw.verticalWheel);
4615				printf("   nExtendedButtons: %d\n",
4616				    synhw.nExtendedButtons);
4617			}
4618			/*
4619			 * Add the number of extended buttons to the total
4620			 * button support count, including the middle button
4621			 * if capMiddle support bit is set.
4622			 */
4623			buttons = synhw.nExtendedButtons + synhw.capMiddle;
4624		} else
4625			/*
4626			 * If the capFourButtons support bit is set,
4627			 * add a fourth button to the total button count.
4628			 */
4629			buttons = synhw.capFourButtons ? 1 : 0;
4630	}
4631	if (verbose >= 2) {
4632		if (synhw.capExtended)
4633			printf("  Additional Buttons: %d\n", buttons);
4634		else
4635			printf("  No extended capabilities\n");
4636	}
4637
4638	/* Read the continued capabilities bits. */
4639	if (mouse_ext_command(kbdc, 0xc) != 0 &&
4640	    get_mouse_status(kbdc, status, 0, 3) == 3) {
4641		synhw.capClickPad         = (status[1] & 0x01) << 1;
4642		synhw.capClickPad        |= (status[0] & 0x10) != 0;
4643		synhw.capDeluxeLEDs       = (status[1] & 0x02) != 0;
4644		synhw.noAbsoluteFilter    = (status[1] & 0x04) != 0;
4645		synhw.capReportsV         = (status[1] & 0x08) != 0;
4646		synhw.capUniformClickPad  = (status[1] & 0x10) != 0;
4647		synhw.capReportsMin       = (status[1] & 0x20) != 0;
4648		synhw.capInterTouch       = (status[1] & 0x40) != 0;
4649		synhw.capReportsMax       = (status[2] & 0x02) != 0;
4650		synhw.capClearPad         = (status[2] & 0x04) != 0;
4651		synhw.capAdvancedGestures = (status[2] & 0x08) != 0;
4652		synhw.capCoveredPad       = (status[2] & 0x80) != 0;
4653
4654		if (verbose >= 2) {
4655			printf("  Continued capabilities:\n");
4656			printf("   capClickPad: %d\n", synhw.capClickPad);
4657			printf("   capDeluxeLEDs: %d\n", synhw.capDeluxeLEDs);
4658			printf("   noAbsoluteFilter: %d\n",
4659			    synhw.noAbsoluteFilter);
4660			printf("   capReportsV: %d\n", synhw.capReportsV);
4661			printf("   capUniformClickPad: %d\n",
4662			    synhw.capUniformClickPad);
4663			printf("   capReportsMin: %d\n", synhw.capReportsMin);
4664			printf("   capInterTouch: %d\n", synhw.capInterTouch);
4665			printf("   capReportsMax: %d\n", synhw.capReportsMax);
4666			printf("   capClearPad: %d\n", synhw.capClearPad);
4667			printf("   capAdvancedGestures: %d\n",
4668			    synhw.capAdvancedGestures);
4669			printf("   capCoveredPad: %d\n", synhw.capCoveredPad);
4670		}
4671		buttons += synhw.capClickPad;
4672	}
4673
4674	/*
4675	 * Add the default number of 3 buttons to the total
4676	 * count of supported buttons reported above.
4677	 */
4678	buttons += 3;
4679
4680	/*
4681	 * Read the mode byte.
4682	 *
4683	 * XXX: Note the Synaptics documentation also defines the first
4684	 * byte of the response to this query to be a constant 0x3b, this
4685	 * does not appear to be true for Touchpads with guest devices.
4686	 */
4687	if (mouse_ext_command(kbdc, 1) == 0)
4688		return (FALSE);
4689	if (get_mouse_status(kbdc, status, 0, 3) != 3)
4690		return (FALSE);
4691	if (!SYNAPTICS_VERSION_GE(synhw, 7, 5) && status[1] != 0x47) {
4692		printf("  Failed to read mode byte\n");
4693		return (FALSE);
4694	}
4695
4696	if (sc != NULL)
4697		sc->synhw = synhw;
4698	if (!synaptics_support)
4699		return (FALSE);
4700
4701	/* Set the mode byte; request wmode where available. */
4702	mouse_ext_command(kbdc, synhw.capExtended ? 0xc1 : 0xc0);
4703
4704	/* "Commit" the Set Mode Byte command sent above. */
4705	set_mouse_sampling_rate(kbdc, 20);
4706
4707	VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons));
4708
4709	if (sc != NULL) {
4710		if (trackpoint_support && synhw.capPassthrough) {
4711			synaptics_passthrough_on(sc);
4712			enable_trackpoint(kbdc, sc);
4713			synaptics_passthrough_off(sc);
4714		}
4715		/* Create sysctl tree. */
4716		synaptics_sysctl_create_tree(sc);
4717		sc->hw.buttons = buttons;
4718	}
4719
4720	return (TRUE);
4721}
4722
4723static void
4724synaptics_passthrough_on(struct psm_softc *sc)
4725{
4726	int mode_byte;
4727
4728	mode_byte = 0xc1 | (1 << 5);
4729	VLOG(2, (LOG_NOTICE, "psm: setting pass-through mode. %d\n",
4730		mode_byte));
4731	mouse_ext_command(sc->kbdc, mode_byte);
4732
4733	/* "Commit" the Set Mode Byte command sent above. */
4734	set_mouse_sampling_rate(sc->kbdc, 20);
4735}
4736
4737static void
4738synaptics_passthrough_off(struct psm_softc *sc)
4739{
4740	int mode_byte;
4741
4742	mode_byte = 0xc1;
4743	VLOG(2, (LOG_NOTICE, "psm: turning pass-through mode off.\n"));
4744	set_mouse_scaling(sc->kbdc, 2);
4745	set_mouse_scaling(sc->kbdc, 1);
4746	mouse_ext_command(sc->kbdc, mode_byte);
4747
4748	/* "Commit" the Set Mode Byte command sent above. */
4749	set_mouse_sampling_rate(sc->kbdc, 20);
4750}
4751
4752/* IBM/Lenovo TrackPoint */
4753static int
4754trackpoint_command(struct psm_softc *sc, int cmd, int loc, int val)
4755{
4756	const int seq[] = { 0xe2, cmd, loc, val };
4757	int i;
4758
4759	if (sc->synhw.capPassthrough)
4760		synaptics_passthrough_on(sc);
4761
4762	for (i = 0; i < nitems(seq); i++) {
4763		if (sc->synhw.capPassthrough &&
4764		    (seq[i] == 0xff || seq[i] == 0xe7))
4765			if (send_aux_command(sc->kbdc, 0xe7) != PSM_ACK) {
4766				synaptics_passthrough_off(sc);
4767				return (EIO);
4768			}
4769		if (send_aux_command(sc->kbdc, seq[i]) != PSM_ACK) {
4770			if (sc->synhw.capPassthrough)
4771				synaptics_passthrough_off(sc);
4772			return (EIO);
4773		}
4774	}
4775
4776	if (sc->synhw.capPassthrough)
4777		synaptics_passthrough_off(sc);
4778
4779	return (0);
4780}
4781
4782#define	PSM_TPINFO(x)	offsetof(struct psm_softc, tpinfo.x)
4783#define	TPMASK		0
4784#define	TPLOC		1
4785#define	TPINFO		2
4786
4787static int
4788trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
4789{
4790	static const int data[][3] = {
4791		{ 0x00, 0x4a, PSM_TPINFO(sensitivity) },
4792		{ 0x00, 0x4d, PSM_TPINFO(inertia) },
4793		{ 0x00, 0x60, PSM_TPINFO(uplateau) },
4794		{ 0x00, 0x57, PSM_TPINFO(reach) },
4795		{ 0x00, 0x58, PSM_TPINFO(draghys) },
4796		{ 0x00, 0x59, PSM_TPINFO(mindrag) },
4797		{ 0x00, 0x5a, PSM_TPINFO(upthresh) },
4798		{ 0x00, 0x5c, PSM_TPINFO(threshold) },
4799		{ 0x00, 0x5d, PSM_TPINFO(jenks) },
4800		{ 0x00, 0x5e, PSM_TPINFO(ztime) },
4801		{ 0x01, 0x2c, PSM_TPINFO(pts) },
4802		{ 0x08, 0x2d, PSM_TPINFO(skipback) }
4803	};
4804	struct psm_softc *sc;
4805	int error, newval, *oldvalp;
4806	const int *tp;
4807
4808	if (arg1 == NULL || arg2 < 0 || arg2 >= nitems(data))
4809		return (EINVAL);
4810	sc = arg1;
4811	tp = data[arg2];
4812	oldvalp = (int *)((intptr_t)sc + tp[TPINFO]);
4813	newval = *oldvalp;
4814	error = sysctl_handle_int(oidp, &newval, 0, req);
4815	if (error != 0)
4816		return (error);
4817	if (newval == *oldvalp)
4818		return (0);
4819	if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1))
4820		return (EINVAL);
4821	error = trackpoint_command(sc, tp[TPMASK] == 0 ? 0x81 : 0x47,
4822	    tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]);
4823	if (error != 0)
4824		return (error);
4825	*oldvalp = newval;
4826
4827	return (0);
4828}
4829
4830static void
4831trackpoint_sysctl_create_tree(struct psm_softc *sc)
4832{
4833
4834	if (sc->tpinfo.sysctl_tree != NULL)
4835		return;
4836
4837	/* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
4838	sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
4839	sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
4840	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
4841	    0, "IBM/Lenovo TrackPoint");
4842
4843	/* hw.psm.trackpoint.sensitivity */
4844	sc->tpinfo.sensitivity = 0x80;
4845	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4846	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4847	    "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4848	    sc, TRACKPOINT_SYSCTL_SENSITIVITY,
4849	    trackpoint_sysctl, "I",
4850	    "Sensitivity");
4851
4852	/* hw.psm.trackpoint.negative_inertia */
4853	sc->tpinfo.inertia = 0x06;
4854	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4855	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4856	    "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4857	    sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
4858	    trackpoint_sysctl, "I",
4859	    "Negative inertia factor");
4860
4861	/* hw.psm.trackpoint.upper_plateau */
4862	sc->tpinfo.uplateau = 0x61;
4863	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4864	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4865	    "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4866	    sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
4867	    trackpoint_sysctl, "I",
4868	    "Transfer function upper plateau speed");
4869
4870	/* hw.psm.trackpoint.backup_range */
4871	sc->tpinfo.reach = 0x0a;
4872	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4873	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4874	    "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4875	    sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
4876	    trackpoint_sysctl, "I",
4877	    "Backup range");
4878
4879	/* hw.psm.trackpoint.drag_hysteresis */
4880	sc->tpinfo.draghys = 0xff;
4881	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4882	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4883	    "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4884	    sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
4885	    trackpoint_sysctl, "I",
4886	    "Drag hysteresis");
4887
4888	/* hw.psm.trackpoint.minimum_drag */
4889	sc->tpinfo.mindrag = 0x14;
4890	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4891	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4892	    "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4893	    sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
4894	    trackpoint_sysctl, "I",
4895	    "Minimum drag");
4896
4897	/* hw.psm.trackpoint.up_threshold */
4898	sc->tpinfo.upthresh = 0xff;
4899	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4900	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4901	    "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4902	    sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
4903	    trackpoint_sysctl, "I",
4904	    "Up threshold for release");
4905
4906	/* hw.psm.trackpoint.threshold */
4907	sc->tpinfo.threshold = 0x08;
4908	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4909	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4910	    "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4911	    sc, TRACKPOINT_SYSCTL_THRESHOLD,
4912	    trackpoint_sysctl, "I",
4913	    "Threshold");
4914
4915	/* hw.psm.trackpoint.jenks_curvature */
4916	sc->tpinfo.jenks = 0x87;
4917	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4918	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4919	    "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4920	    sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
4921	    trackpoint_sysctl, "I",
4922	    "Jenks curvature");
4923
4924	/* hw.psm.trackpoint.z_time */
4925	sc->tpinfo.ztime = 0x26;
4926	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4927	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4928	    "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4929	    sc, TRACKPOINT_SYSCTL_Z_TIME,
4930	    trackpoint_sysctl, "I",
4931	    "Z time constant");
4932
4933	/* hw.psm.trackpoint.press_to_select */
4934	sc->tpinfo.pts = 0x00;
4935	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4936	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4937	    "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4938	    sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
4939	    trackpoint_sysctl, "I",
4940	    "Press to Select");
4941
4942	/* hw.psm.trackpoint.skip_backups */
4943	sc->tpinfo.skipback = 0x00;
4944	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
4945	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
4946	    "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
4947	    sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
4948	    trackpoint_sysctl, "I",
4949	    "Skip backups from drags");
4950}
4951
4952static void
4953set_trackpoint_parameters(struct psm_softc *sc)
4954{
4955	trackpoint_command(sc, 0x81, 0x4a, sc->tpinfo.sensitivity);
4956	trackpoint_command(sc, 0x81, 0x60, sc->tpinfo.uplateau);
4957	trackpoint_command(sc, 0x81, 0x4d, sc->tpinfo.inertia);
4958	trackpoint_command(sc, 0x81, 0x57, sc->tpinfo.reach);
4959	trackpoint_command(sc, 0x81, 0x58, sc->tpinfo.draghys);
4960	trackpoint_command(sc, 0x81, 0x59, sc->tpinfo.mindrag);
4961	trackpoint_command(sc, 0x81, 0x5a, sc->tpinfo.upthresh);
4962	trackpoint_command(sc, 0x81, 0x5c, sc->tpinfo.threshold);
4963	trackpoint_command(sc, 0x81, 0x5d, sc->tpinfo.jenks);
4964	trackpoint_command(sc, 0x81, 0x5e, sc->tpinfo.ztime);
4965	if (sc->tpinfo.pts == 0x01)
4966		trackpoint_command(sc, 0x47, 0x2c, 0x01);
4967	if (sc->tpinfo.skipback == 0x01)
4968		trackpoint_command(sc, 0x47, 0x2d, 0x08);
4969}
4970
4971static int
4972enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
4973{
4974	int id;
4975
4976	if (send_aux_command(kbdc, 0xe1) != PSM_ACK ||
4977	    read_aux_data(kbdc) != 0x01)
4978		return (FALSE);
4979	id = read_aux_data(kbdc);
4980	if (id < 0x01)
4981		return (FALSE);
4982	if (sc != NULL)
4983		sc->tphw = id;
4984	if (!trackpoint_support)
4985		return (FALSE);
4986
4987	if (sc != NULL) {
4988		/* Create sysctl tree. */
4989		trackpoint_sysctl_create_tree(sc);
4990
4991		/*
4992		 * Don't overwrite hwid and buttons when we are
4993		 * a guest device.
4994		 */
4995		if (!sc->synhw.capPassthrough) {
4996			sc->hw.hwid = id;
4997			sc->hw.buttons = 3;
4998		}
4999	}
5000
5001	return (TRUE);
5002}
5003
5004/* Interlink electronics VersaPad */
5005static int
5006enable_versapad(KBDC kbdc, struct psm_softc *sc)
5007{
5008	int data[3];
5009
5010	set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
5011	set_mouse_sampling_rate(kbdc, 100);		/* set rate 100 */
5012	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
5013	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
5014	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
5015	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
5016	if (get_mouse_status(kbdc, data, 0, 3) < 3)	/* get status */
5017		return (FALSE);
5018	if (data[2] != 0xa || data[1] != 0 )	/* rate == 0xa && res. == 0 */
5019		return (FALSE);
5020	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
5021
5022	return (TRUE);				/* PS/2 absolute mode */
5023}
5024
5025/*
5026 * Return true if 'now' is earlier than (start + (secs.usecs)).
5027 * Now may be NULL and the function will fetch the current time from
5028 * getmicrouptime(), or a cached 'now' can be passed in.
5029 * All values should be numbers derived from getmicrouptime().
5030 */
5031static int
5032timeelapsed(start, secs, usecs, now)
5033	const struct timeval *start, *now;
5034	int secs, usecs;
5035{
5036	struct timeval snow, tv;
5037
5038	/* if there is no 'now' passed in, the get it as a convience. */
5039	if (now == NULL) {
5040		getmicrouptime(&snow);
5041		now = &snow;
5042	}
5043
5044	tv.tv_sec = secs;
5045	tv.tv_usec = usecs;
5046	timevaladd(&tv, start);
5047	return (timevalcmp(&tv, now, <));
5048}
5049
5050static int
5051psmresume(device_t dev)
5052{
5053	struct psm_softc *sc = device_get_softc(dev);
5054	int unit = device_get_unit(dev);
5055	int err;
5056
5057	VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit));
5058
5059	if ((sc->config &
5060	    (PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND)) == 0)
5061		return (0);
5062
5063	err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
5064
5065	if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
5066		/*
5067		 * Release the blocked process; it must be notified that
5068		 * the device cannot be accessed anymore.
5069		 */
5070		sc->state &= ~PSM_ASLP;
5071		wakeup(sc);
5072	}
5073
5074	VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit));
5075
5076	return (err);
5077}
5078
5079DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
5080
5081#ifdef DEV_ISA
5082
5083/*
5084 * This sucks up assignments from PNPBIOS and ACPI.
5085 */
5086
5087/*
5088 * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may
5089 * appear BEFORE the AT keyboard controller.  As the PS/2 mouse device
5090 * can be probed and attached only after the AT keyboard controller is
5091 * attached, we shall quietly reserve the IRQ resource for later use.
5092 * If the PS/2 mouse device is reported to us AFTER the keyboard controller,
5093 * copy the IRQ resource to the PS/2 mouse device instance hanging
5094 * under the keyboard controller, then probe and attach it.
5095 */
5096
5097static	devclass_t			psmcpnp_devclass;
5098
5099static	device_probe_t			psmcpnp_probe;
5100static	device_attach_t			psmcpnp_attach;
5101
5102static device_method_t psmcpnp_methods[] = {
5103	DEVMETHOD(device_probe,		psmcpnp_probe),
5104	DEVMETHOD(device_attach,	psmcpnp_attach),
5105
5106	{ 0, 0 }
5107};
5108
5109static driver_t psmcpnp_driver = {
5110	PSMCPNP_DRIVER_NAME,
5111	psmcpnp_methods,
5112	1,			/* no softc */
5113};
5114
5115static struct isa_pnp_id psmcpnp_ids[] = {
5116	{ 0x030fd041, "PS/2 mouse port" },		/* PNP0F03 */
5117	{ 0x0e0fd041, "PS/2 mouse port" },		/* PNP0F0E */
5118	{ 0x120fd041, "PS/2 mouse port" },		/* PNP0F12 */
5119	{ 0x130fd041, "PS/2 mouse port" },		/* PNP0F13 */
5120	{ 0x1303d041, "PS/2 port" },			/* PNP0313, XXX */
5121	{ 0x02002e4f, "Dell PS/2 mouse port" },		/* Lat. X200, Dell */
5122	{ 0x0002a906, "ALPS Glide Point" },		/* ALPS Glide Point */
5123	{ 0x80374d24, "IBM PS/2 mouse port" },		/* IBM3780, ThinkPad */
5124	{ 0x81374d24, "IBM PS/2 mouse port" },		/* IBM3781, ThinkPad */
5125	{ 0x0190d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9001, Vaio */
5126	{ 0x0290d94d, "SONY VAIO PS/2 mouse port"},	/* SNY9002, Vaio */
5127	{ 0x0390d94d, "SONY VAIO PS/2 mouse port"},	/* SNY9003, Vaio */
5128	{ 0x0490d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9004, Vaio */
5129	{ 0 }
5130};
5131
5132static int
5133create_a_copy(device_t atkbdc, device_t me)
5134{
5135	device_t psm;
5136	u_long irq;
5137
5138	/* find the PS/2 mouse device instance under the keyboard controller */
5139	psm = device_find_child(atkbdc, PSM_DRIVER_NAME,
5140	    device_get_unit(atkbdc));
5141	if (psm == NULL)
5142		return (ENXIO);
5143	if (device_get_state(psm) != DS_NOTPRESENT)
5144		return (0);
5145
5146	/* move our resource to the found device */
5147	irq = bus_get_resource_start(me, SYS_RES_IRQ, 0);
5148	bus_delete_resource(me, SYS_RES_IRQ, 0);
5149	bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
5150
5151	/* ...then probe and attach it */
5152	return (device_probe_and_attach(psm));
5153}
5154
5155static int
5156psmcpnp_probe(device_t dev)
5157{
5158	struct resource *res;
5159	u_long irq;
5160	int rid;
5161
5162	if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
5163		return (ENXIO);
5164
5165	/*
5166	 * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
5167	 * to the PS/2 mouse device node. But, some buggy PnP BIOS
5168	 * declares the PS/2 mouse device node without an IRQ resource!
5169	 * If this happens, we shall refer to device hints.
5170	 * If we still don't find it there, use a hardcoded value... XXX
5171	 */
5172	rid = 0;
5173	irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
5174	if (irq <= 0) {
5175		if (resource_long_value(PSM_DRIVER_NAME,
5176		    device_get_unit(dev),"irq", &irq) != 0)
5177			irq = 12;	/* XXX */
5178		device_printf(dev, "irq resource info is missing; "
5179		    "assuming irq %ld\n", irq);
5180		bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
5181	}
5182	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
5183	bus_release_resource(dev, SYS_RES_IRQ, rid, res);
5184
5185	/* keep quiet */
5186	if (!bootverbose)
5187		device_quiet(dev);
5188
5189	return ((res == NULL) ? ENXIO : 0);
5190}
5191
5192static int
5193psmcpnp_attach(device_t dev)
5194{
5195	device_t atkbdc;
5196
5197	/* find the keyboard controller, which may be on acpi* or isa* bus */
5198	atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME),
5199	    device_get_unit(dev));
5200	if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED))
5201		create_a_copy(atkbdc, dev);
5202
5203	return (0);
5204}
5205
5206DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5207DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0);
5208
5209#endif /* DEV_ISA */
5210