psm.c revision 178019
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: head/sys/dev/atkbdc/psm.c 178019 2008-04-08 19:09:45Z jkim $");
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/poll.h>
74#include <sys/syslog.h>
75#include <machine/bus.h>
76#include <sys/rman.h>
77#include <sys/selinfo.h>
78#include <sys/sysctl.h>
79#include <sys/time.h>
80#include <sys/uio.h>
81
82#include <sys/limits.h>
83#include <sys/mouse.h>
84#include <machine/resource.h>
85
86#ifdef DEV_ISA
87#include <isa/isavar.h>
88#endif
89
90#include <dev/atkbdc/atkbdcreg.h>
91#include <dev/atkbdc/psm.h>
92
93/*
94 * Driver specific options: the following options may be set by
95 * `options' statements in the kernel configuration file.
96 */
97
98/* debugging */
99#ifndef PSM_DEBUG
100#define	PSM_DEBUG	0	/*
101				 * logging: 0: none, 1: brief, 2: verbose
102				 *          3: sync errors, 4: all packets
103				 */
104#endif
105#define	VLOG(level, args)	do {	\
106	if (verbose >= level)		\
107		log args;		\
108} while (0)
109
110#ifndef PSM_INPUT_TIMEOUT
111#define	PSM_INPUT_TIMEOUT	2000000	/* 2 sec */
112#endif
113
114#ifndef PSM_TAP_TIMEOUT
115#define	PSM_TAP_TIMEOUT		125000
116#endif
117
118#ifndef PSM_TAP_THRESHOLD
119#define	PSM_TAP_THRESHOLD	25
120#endif
121
122/* end of driver specific options */
123
124#define	PSMCPNP_DRIVER_NAME	"psmcpnp"
125
126/* input queue */
127#define	PSM_BUFSIZE		960
128#define	PSM_SMALLBUFSIZE	240
129
130/* operation levels */
131#define	PSM_LEVEL_BASE		0
132#define	PSM_LEVEL_STANDARD	1
133#define	PSM_LEVEL_NATIVE	2
134#define	PSM_LEVEL_MIN		PSM_LEVEL_BASE
135#define	PSM_LEVEL_MAX		PSM_LEVEL_NATIVE
136
137/* Logitech PS2++ protocol */
138#define	MOUSE_PS2PLUS_CHECKBITS(b)	\
139    ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
140#define	MOUSE_PS2PLUS_PACKET_TYPE(b)	\
141    (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
142
143/* some macros */
144#define	PSM_UNIT(dev)		(minor(dev) >> 1)
145#define	PSM_NBLOCKIO(dev)	(minor(dev) & 1)
146#define	PSM_MKMINOR(unit,block)	(((unit) << 1) | ((block) ? 0:1))
147
148/* ring buffer */
149typedef struct ringbuf {
150	int		count;	/* # of valid elements in the buffer */
151	int		head;	/* head pointer */
152	int		tail;	/* tail poiner */
153	u_char buf[PSM_BUFSIZE];
154} ringbuf_t;
155
156/* data buffer */
157typedef struct packetbuf {
158	u_char	ipacket[16];	/* interim input buffer */
159	int	inputbytes;	/* # of bytes in the input buffer */
160} packetbuf_t;
161
162#ifndef PSM_PACKETQUEUE
163#define	PSM_PACKETQUEUE	128
164#endif
165
166typedef struct synapticsinfo {
167	struct sysctl_ctx_list	sysctl_ctx;
168	struct sysctl_oid	*sysctl_tree;
169	int			directional_scrolls;
170	int			low_speed_threshold;
171	int			min_movement;
172	int			squelch_level;
173} synapticsinfo_t;
174
175/* driver control block */
176struct psm_softc {		/* Driver status information */
177	int		unit;
178	struct selinfo	rsel;		/* Process selecting for Input */
179	u_char		state;		/* Mouse driver state */
180	int		config;		/* driver configuration flags */
181	int		flags;		/* other flags */
182	KBDC		kbdc;		/* handle to access kbd controller */
183	struct resource	*intr;		/* IRQ resource */
184	void		*ih;		/* interrupt handle */
185	mousehw_t	hw;		/* hardware information */
186	synapticshw_t	synhw;		/* Synaptics hardware information */
187	synapticsinfo_t	syninfo;	/* Synaptics configuration */
188	mousemode_t	mode;		/* operation mode */
189	mousemode_t	dflt_mode;	/* default operation mode */
190	mousestatus_t	status;		/* accumulated mouse movement */
191	ringbuf_t	queue;		/* mouse status queue */
192	packetbuf_t	pqueue[PSM_PACKETQUEUE]; /* mouse data queue */
193	int		pqueue_start;	/* start of data in queue */
194	int		pqueue_end;	/* end of data in queue */
195	int		button;		/* the latest button state */
196	int		xold;		/* previous absolute X position */
197	int		yold;		/* previous absolute Y position */
198	int		xaverage;	/* average X position */
199	int		yaverage;	/* average Y position */
200	int		squelch; /* level to filter movement at low speed */
201	int		zmax;	/* maximum pressure value for touchpads */
202	int		syncerrors; /* # of bytes discarded to synchronize */
203	int		pkterrors;  /* # of packets failed during quaranteen. */
204	struct timeval	inputtimeout;
205	struct timeval	lastsoftintr;	/* time of last soft interrupt */
206	struct timeval	lastinputerr;	/* time last sync error happened */
207	struct timeval	taptimeout;	/* tap timeout for touchpads */
208	int		watchdog;	/* watchdog timer flag */
209	struct callout_handle callout;	/* watchdog timer call out */
210	struct callout_handle softcallout; /* buffer timer call out */
211	struct cdev	*dev;
212	struct cdev	*bdev;
213	int		lasterr;
214	int		cmdcount;
215};
216static devclass_t psm_devclass;
217#define	PSM_SOFTC(unit)	\
218    ((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
219
220/* driver state flags (state) */
221#define	PSM_VALID		0x80
222#define	PSM_OPEN		1	/* Device is open */
223#define	PSM_ASLP		2	/* Waiting for mouse data */
224#define	PSM_SOFTARMED		4	/* Software interrupt armed */
225#define	PSM_NEED_SYNCBITS	8	/* Set syncbits using next data pkt */
226
227/* driver configuration flags (config) */
228#define	PSM_CONFIG_RESOLUTION	0x000f	/* resolution */
229#define	PSM_CONFIG_ACCEL	0x00f0  /* acceleration factor */
230#define	PSM_CONFIG_NOCHECKSYNC	0x0100  /* disable sync. test */
231#define	PSM_CONFIG_NOIDPROBE	0x0200  /* disable mouse model probe */
232#define	PSM_CONFIG_NORESET	0x0400  /* don't reset the mouse */
233#define	PSM_CONFIG_FORCETAP	0x0800  /* assume `tap' action exists */
234#define	PSM_CONFIG_IGNPORTERROR	0x1000  /* ignore error in aux port test */
235#define	PSM_CONFIG_HOOKRESUME	0x2000	/* hook the system resume event */
236#define	PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
237#define	PSM_CONFIG_SYNCHACK	0x8000	/* enable `out-of-sync' hack */
238
239#define	PSM_CONFIG_FLAGS	\
240    (PSM_CONFIG_RESOLUTION |	\
241    PSM_CONFIG_ACCEL |		\
242    PSM_CONFIG_NOCHECKSYNC |	\
243    PSM_CONFIG_SYNCHACK |	\
244    PSM_CONFIG_NOIDPROBE |	\
245    PSM_CONFIG_NORESET |	\
246    PSM_CONFIG_FORCETAP |	\
247    PSM_CONFIG_IGNPORTERROR |	\
248    PSM_CONFIG_HOOKRESUME |	\
249    PSM_CONFIG_INITAFTERSUSPEND)
250
251/* other flags (flags) */
252#define	PSM_FLAGS_FINGERDOWN	0x0001	/* VersaPad finger down */
253
254/* Tunables */
255static int synaptics_support = 0;
256TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
257
258static int verbose = PSM_DEBUG;
259TUNABLE_INT("debug.psm.loglevel", &verbose);
260
261/* for backward compatibility */
262#define	OLD_MOUSE_GETHWINFO	_IOR('M', 1, old_mousehw_t)
263#define	OLD_MOUSE_GETMODE	_IOR('M', 2, old_mousemode_t)
264#define	OLD_MOUSE_SETMODE	_IOW('M', 3, old_mousemode_t)
265
266typedef struct old_mousehw {
267	int	buttons;
268	int	iftype;
269	int	type;
270	int	hwid;
271} old_mousehw_t;
272
273typedef struct old_mousemode {
274	int	protocol;
275	int	rate;
276	int	resolution;
277	int	accelfactor;
278} old_mousemode_t;
279
280/* packet formatting function */
281typedef int	packetfunc_t(struct psm_softc *, u_char *, int *, int,
282    mousestatus_t *);
283
284/* function prototypes */
285static void	psmidentify(driver_t *, device_t);
286static int	psmprobe(device_t);
287static int	psmattach(device_t);
288static int	psmdetach(device_t);
289static int	psmresume(device_t);
290
291static d_open_t		psmopen;
292static d_close_t	psmclose;
293static d_read_t		psmread;
294static d_write_t	psmwrite;
295static d_ioctl_t	psmioctl;
296static d_poll_t		psmpoll;
297
298static int	enable_aux_dev(KBDC);
299static int	disable_aux_dev(KBDC);
300static int	get_mouse_status(KBDC, int *, int, int);
301static int	get_aux_id(KBDC);
302static int	set_mouse_sampling_rate(KBDC, int);
303static int	set_mouse_scaling(KBDC, int);
304static int	set_mouse_resolution(KBDC, int);
305static int	set_mouse_mode(KBDC);
306static int	get_mouse_buttons(KBDC);
307static int	is_a_mouse(int);
308static void	recover_from_error(KBDC);
309static int	restore_controller(KBDC, int);
310static int	doinitialize(struct psm_softc *, mousemode_t *);
311static int	doopen(struct psm_softc *, int);
312static int	reinitialize(struct psm_softc *, int);
313static char	*model_name(int);
314static void	psmsoftintr(void *);
315static void	psmintr(void *);
316static void	psmtimeout(void *);
317static int	timeelapsed(const struct timeval *, int, int,
318		    const struct timeval *);
319static void	dropqueue(struct psm_softc *);
320static void	flushpackets(struct psm_softc *);
321static void	proc_mmanplus(struct psm_softc *, packetbuf_t *,
322		    mousestatus_t *, int *, int *, int *);
323static int	proc_synaptics(struct psm_softc *, packetbuf_t *,
324		    mousestatus_t *, int *, int *, int *);
325static void	proc_versapad(struct psm_softc *, packetbuf_t *,
326		    mousestatus_t *, int *, int *, int *);
327static int	tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
328		    u_char *);
329
330/* vendor specific features */
331typedef int	probefunc_t(struct psm_softc *);
332
333static int	mouse_id_proc1(KBDC, int, int, int *);
334static int	mouse_ext_command(KBDC, int);
335
336static probefunc_t	enable_groller;
337static probefunc_t	enable_gmouse;
338static probefunc_t	enable_aglide;
339static probefunc_t	enable_kmouse;
340static probefunc_t	enable_msexplorer;
341static probefunc_t	enable_msintelli;
342static probefunc_t	enable_4dmouse;
343static probefunc_t	enable_4dplus;
344static probefunc_t	enable_mmanplus;
345static probefunc_t	enable_synaptics;
346static probefunc_t	enable_versapad;
347
348static struct {
349	int		model;
350	u_char		syncmask;
351	int		packetsize;
352	probefunc_t	*probefunc;
353} vendortype[] = {
354	/*
355	 * WARNING: the order of probe is very important.  Don't mess it
356	 * unless you know what you are doing.
357	 */
358	{ MOUSE_MODEL_NET,		/* Genius NetMouse */
359	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse },
360	{ MOUSE_MODEL_NETSCROLL,	/* Genius NetScroll */
361	  0xc8, 6, enable_groller },
362	{ MOUSE_MODEL_MOUSEMANPLUS,	/* Logitech MouseMan+ */
363	  0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus },
364	{ MOUSE_MODEL_EXPLORER,		/* Microsoft IntelliMouse Explorer */
365	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer },
366	{ MOUSE_MODEL_4D,		/* A4 Tech 4D Mouse */
367	  0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse },
368	{ MOUSE_MODEL_4DPLUS,		/* A4 Tech 4D+ Mouse */
369	  0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
370	{ MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
371	  0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
372	{ MOUSE_MODEL_GLIDEPOINT,	/* ALPS GlidePoint */
373	  0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide },
374	{ MOUSE_MODEL_THINK,		/* Kensington ThinkingMouse */
375	  0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
376	{ MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
377	  0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
378	{ MOUSE_MODEL_SYNAPTICS,	/* Synaptics Touchpad */
379	  0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
380	{ MOUSE_MODEL_GENERIC,
381	  0xc0, MOUSE_PS2_PACKETSIZE, NULL },
382};
383#define	GENERIC_MOUSE_ENTRY	\
384    ((sizeof(vendortype) / sizeof(*vendortype)) - 1)
385
386/* device driver declarateion */
387static device_method_t psm_methods[] = {
388	/* Device interface */
389	DEVMETHOD(device_identify,	psmidentify),
390	DEVMETHOD(device_probe,		psmprobe),
391	DEVMETHOD(device_attach,	psmattach),
392	DEVMETHOD(device_detach,	psmdetach),
393	DEVMETHOD(device_resume,	psmresume),
394
395	{ 0, 0 }
396};
397
398static driver_t psm_driver = {
399	PSM_DRIVER_NAME,
400	psm_methods,
401	sizeof(struct psm_softc),
402};
403
404static struct cdevsw psm_cdevsw = {
405	.d_version =	D_VERSION,
406	.d_flags =	D_NEEDGIANT,
407	.d_open =	psmopen,
408	.d_close =	psmclose,
409	.d_read =	psmread,
410	.d_write =	psmwrite,
411	.d_ioctl =	psmioctl,
412	.d_poll =	psmpoll,
413	.d_name =	PSM_DRIVER_NAME,
414};
415
416/* device I/O routines */
417static int
418enable_aux_dev(KBDC kbdc)
419{
420	int res;
421
422	res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
423	VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res));
424
425	return (res == PSM_ACK);
426}
427
428static int
429disable_aux_dev(KBDC kbdc)
430{
431	int res;
432
433	res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
434	VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res));
435
436	return (res == PSM_ACK);
437}
438
439static int
440get_mouse_status(KBDC kbdc, int *status, int flag, int len)
441{
442	int cmd;
443	int res;
444	int i;
445
446	switch (flag) {
447	case 0:
448	default:
449		cmd = PSMC_SEND_DEV_STATUS;
450		break;
451	case 1:
452		cmd = PSMC_SEND_DEV_DATA;
453		break;
454	}
455	empty_aux_buffer(kbdc, 5);
456	res = send_aux_command(kbdc, cmd);
457	VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
458	    (flag == 1) ? "DATA" : "STATUS", res));
459	if (res != PSM_ACK)
460		return (0);
461
462	for (i = 0; i < len; ++i) {
463		status[i] = read_aux_data(kbdc);
464		if (status[i] < 0)
465			break;
466	}
467
468	VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n",
469	    (flag == 1) ? "data" : "status", status[0], status[1], status[2]));
470
471	return (i);
472}
473
474static int
475get_aux_id(KBDC kbdc)
476{
477	int res;
478	int id;
479
480	empty_aux_buffer(kbdc, 5);
481	res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
482	VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res));
483	if (res != PSM_ACK)
484		return (-1);
485
486	/* 10ms delay */
487	DELAY(10000);
488
489	id = read_aux_data(kbdc);
490	VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id));
491
492	return (id);
493}
494
495static int
496set_mouse_sampling_rate(KBDC kbdc, int rate)
497{
498	int res;
499
500	res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
501	VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res));
502
503	return ((res == PSM_ACK) ? rate : -1);
504}
505
506static int
507set_mouse_scaling(KBDC kbdc, int scale)
508{
509	int res;
510
511	switch (scale) {
512	case 1:
513	default:
514		scale = PSMC_SET_SCALING11;
515		break;
516	case 2:
517		scale = PSMC_SET_SCALING21;
518		break;
519	}
520	res = send_aux_command(kbdc, scale);
521	VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
522	    (scale == PSMC_SET_SCALING21) ? "21" : "11", res));
523
524	return (res == PSM_ACK);
525}
526
527/* `val' must be 0 through PSMD_MAX_RESOLUTION */
528static int
529set_mouse_resolution(KBDC kbdc, int val)
530{
531	int res;
532
533	res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
534	VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res));
535
536	return ((res == PSM_ACK) ? val : -1);
537}
538
539/*
540 * NOTE: once `set_mouse_mode()' is called, the mouse device must be
541 * re-enabled by calling `enable_aux_dev()'
542 */
543static int
544set_mouse_mode(KBDC kbdc)
545{
546	int res;
547
548	res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
549	VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res));
550
551	return (res == PSM_ACK);
552}
553
554static int
555get_mouse_buttons(KBDC kbdc)
556{
557	int c = 2;		/* assume two buttons by default */
558	int status[3];
559
560	/*
561	 * NOTE: a special sequence to obtain Logitech Mouse specific
562	 * information: set resolution to 25 ppi, set scaling to 1:1, set
563	 * scaling to 1:1, set scaling to 1:1. Then the second byte of the
564	 * mouse status bytes is the number of available buttons.
565	 * Some manufactures also support this sequence.
566	 */
567	if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
568		return (c);
569	if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) &&
570	    set_mouse_scaling(kbdc, 1) &&
571	    get_mouse_status(kbdc, status, 0, 3) >= 3 && status[1] != 0)
572		return (status[1]);
573	return (c);
574}
575
576/* misc subroutines */
577/*
578 * Someday, I will get the complete list of valid pointing devices and
579 * their IDs... XXX
580 */
581static int
582is_a_mouse(int id)
583{
584#if 0
585	static int valid_ids[] = {
586		PSM_MOUSE_ID,		/* mouse */
587		PSM_BALLPOINT_ID,	/* ballpoint device */
588		PSM_INTELLI_ID,		/* Intellimouse */
589		PSM_EXPLORER_ID,	/* Intellimouse Explorer */
590		-1			/* end of table */
591	};
592	int i;
593
594	for (i = 0; valid_ids[i] >= 0; ++i)
595	if (valid_ids[i] == id)
596		return (TRUE);
597	return (FALSE);
598#else
599	return (TRUE);
600#endif
601}
602
603static char *
604model_name(int model)
605{
606	static struct {
607		int	model_code;
608		char	*model_name;
609	} models[] = {
610		{ MOUSE_MODEL_NETSCROLL,	"NetScroll" },
611		{ MOUSE_MODEL_NET,		"NetMouse/NetScroll Optical" },
612		{ MOUSE_MODEL_GLIDEPOINT,	"GlidePoint" },
613		{ MOUSE_MODEL_THINK,		"ThinkingMouse" },
614		{ MOUSE_MODEL_INTELLI,		"IntelliMouse" },
615		{ MOUSE_MODEL_MOUSEMANPLUS,	"MouseMan+" },
616		{ MOUSE_MODEL_VERSAPAD,		"VersaPad" },
617		{ MOUSE_MODEL_EXPLORER,		"IntelliMouse Explorer" },
618		{ MOUSE_MODEL_4D,		"4D Mouse" },
619		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
620		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
621		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
622		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
623	};
624	int i;
625
626	for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i)
627		if (models[i].model_code == model)
628			break;
629	return (models[i].model_name);
630}
631
632static void
633recover_from_error(KBDC kbdc)
634{
635	/* discard anything left in the output buffer */
636	empty_both_buffers(kbdc, 10);
637
638#if 0
639	/*
640	 * NOTE: KBDC_RESET_KBD may not restore the communication between the
641	 * keyboard and the controller.
642	 */
643	reset_kbd(kbdc);
644#else
645	/*
646	 * NOTE: somehow diagnostic and keyboard port test commands bring the
647	 * keyboard back.
648	 */
649	if (!test_controller(kbdc))
650		log(LOG_ERR, "psm: keyboard controller failed.\n");
651	/* if there isn't a keyboard in the system, the following error is OK */
652	if (test_kbd_port(kbdc) != 0)
653		VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n"));
654#endif
655}
656
657static int
658restore_controller(KBDC kbdc, int command_byte)
659{
660	empty_both_buffers(kbdc, 10);
661
662	if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
663		log(LOG_ERR, "psm: failed to restore the keyboard controller "
664		    "command byte.\n");
665		empty_both_buffers(kbdc, 10);
666		return (FALSE);
667	} else {
668		empty_both_buffers(kbdc, 10);
669		return (TRUE);
670	}
671}
672
673/*
674 * Re-initialize the aux port and device. The aux port must be enabled
675 * and its interrupt must be disabled before calling this routine.
676 * The aux device will be disabled before returning.
677 * The keyboard controller must be locked via `kbdc_lock()' before
678 * calling this routine.
679 */
680static int
681doinitialize(struct psm_softc *sc, mousemode_t *mode)
682{
683	KBDC kbdc = sc->kbdc;
684	int stat[3];
685	int i;
686
687	switch((i = test_aux_port(kbdc))) {
688	case 1:	/* ignore these errors */
689	case 2:
690	case 3:
691	case PSM_ACK:
692		if (verbose)
693			log(LOG_DEBUG,
694			    "psm%d: strange result for test aux port (%d).\n",
695			    sc->unit, i);
696		/* FALLTHROUGH */
697	case 0:		/* no error */
698		break;
699	case -1:	/* time out */
700	default:	/* error */
701		recover_from_error(kbdc);
702		if (sc->config & PSM_CONFIG_IGNPORTERROR)
703			break;
704		log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
705		    sc->unit, i);
706		return (FALSE);
707	}
708
709	if (sc->config & PSM_CONFIG_NORESET) {
710		/*
711		 * Don't try to reset the pointing device.  It may possibly
712		 * be left in the unknown state, though...
713		 */
714	} else {
715		/*
716		 * NOTE: some controllers appears to hang the `keyboard' when
717		 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
718		 */
719		if (!reset_aux_dev(kbdc)) {
720			recover_from_error(kbdc);
721			log(LOG_ERR, "psm%d: failed to reset the aux device.\n",
722			    sc->unit);
723			return (FALSE);
724		}
725	}
726
727	/*
728	 * both the aux port and the aux device is functioning, see
729	 * if the device can be enabled.
730	 */
731	if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
732		log(LOG_ERR, "psm%d: failed to enable the aux device.\n",
733		    sc->unit);
734		return (FALSE);
735	}
736	empty_both_buffers(kbdc, 10);	/* remove stray data if any */
737
738	if (sc->config & PSM_CONFIG_NOIDPROBE)
739		i = GENERIC_MOUSE_ENTRY;
740	else {
741		/* FIXME: hardware ID, mouse buttons? */
742
743		/* other parameters */
744		for (i = 0; vendortype[i].probefunc != NULL; ++i)
745			if ((*vendortype[i].probefunc)(sc)) {
746				if (verbose >= 2)
747					log(LOG_ERR, "psm%d: found %s\n",
748					    sc->unit,
749					    model_name(vendortype[i].model));
750				break;
751			}
752	}
753
754	sc->hw.model = vendortype[i].model;
755	sc->mode.packetsize = vendortype[i].packetsize;
756
757	/* set mouse parameters */
758	if (mode != (mousemode_t *)NULL) {
759		if (mode->rate > 0)
760			mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
761		if (mode->resolution >= 0)
762			mode->resolution =
763			    set_mouse_resolution(kbdc, mode->resolution);
764		set_mouse_scaling(kbdc, 1);
765		set_mouse_mode(kbdc);
766	}
767
768	/* Record sync on the next data packet we see. */
769	sc->flags |= PSM_NEED_SYNCBITS;
770
771	/* just check the status of the mouse */
772	if (get_mouse_status(kbdc, stat, 0, 3) < 3)
773		log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n",
774		    sc->unit);
775
776	return (TRUE);
777}
778
779static int
780doopen(struct psm_softc *sc, int command_byte)
781{
782	int stat[3];
783
784	/* enable the mouse device */
785	if (!enable_aux_dev(sc->kbdc)) {
786		/* MOUSE ERROR: failed to enable the mouse because:
787		 * 1) the mouse is faulty,
788		 * 2) the mouse has been removed(!?)
789		 * In the latter case, the keyboard may have hung, and need
790		 * recovery procedure...
791		 */
792		recover_from_error(sc->kbdc);
793#if 0
794		/* FIXME: we could reset the mouse here and try to enable
795		 * it again. But it will take long time and it's not a good
796		 * idea to disable the keyboard that long...
797		 */
798		if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
799			recover_from_error(sc->kbdc);
800#else
801		{
802#endif
803			restore_controller(sc->kbdc, command_byte);
804			/* mark this device is no longer available */
805			sc->state &= ~PSM_VALID;
806			log(LOG_ERR,
807			    "psm%d: failed to enable the device (doopen).\n",
808			sc->unit);
809			return (EIO);
810		}
811	}
812
813	if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
814		log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n",
815		    sc->unit);
816
817	/* enable the aux port and interrupt */
818	if (!set_controller_command_byte(sc->kbdc,
819	    kbdc_get_device_mask(sc->kbdc),
820	    (command_byte & KBD_KBD_CONTROL_BITS) |
821	    KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
822		/* CONTROLLER ERROR */
823		disable_aux_dev(sc->kbdc);
824		restore_controller(sc->kbdc, command_byte);
825		log(LOG_ERR,
826		    "psm%d: failed to enable the aux interrupt (doopen).\n",
827		    sc->unit);
828		return (EIO);
829	}
830
831	/* start the watchdog timer */
832	sc->watchdog = FALSE;
833	sc->callout = timeout(psmtimeout, (void *)(uintptr_t)sc, hz*2);
834
835	return (0);
836}
837
838static int
839reinitialize(struct psm_softc *sc, int doinit)
840{
841	int err;
842	int c;
843	int s;
844
845	/* don't let anybody mess with the aux device */
846	if (!kbdc_lock(sc->kbdc, TRUE))
847		return (EIO);
848	s = spltty();
849
850	/* block our watchdog timer */
851	sc->watchdog = FALSE;
852	untimeout(psmtimeout, (void *)(uintptr_t)sc, sc->callout);
853	callout_handle_init(&sc->callout);
854
855	/* save the current controller command byte */
856	empty_both_buffers(sc->kbdc, 10);
857	c = get_controller_command_byte(sc->kbdc);
858	VLOG(2, (LOG_DEBUG,
859	    "psm%d: current command byte: %04x (reinitialize).\n",
860	    sc->unit, c));
861
862	/* enable the aux port but disable the aux interrupt and the keyboard */
863	if ((c == -1) || !set_controller_command_byte(sc->kbdc,
864	    kbdc_get_device_mask(sc->kbdc),
865	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
866	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
867		/* CONTROLLER ERROR */
868		splx(s);
869		kbdc_lock(sc->kbdc, FALSE);
870		log(LOG_ERR,
871		    "psm%d: unable to set the command byte (reinitialize).\n",
872		    sc->unit);
873		return (EIO);
874	}
875
876	/* flush any data */
877	if (sc->state & PSM_VALID) {
878		/* this may fail; but never mind... */
879		disable_aux_dev(sc->kbdc);
880		empty_aux_buffer(sc->kbdc, 10);
881	}
882	flushpackets(sc);
883	sc->syncerrors = 0;
884	sc->pkterrors = 0;
885	memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr));
886
887	/* try to detect the aux device; are you still there? */
888	err = 0;
889	if (doinit) {
890		if (doinitialize(sc, &sc->mode)) {
891			/* yes */
892			sc->state |= PSM_VALID;
893		} else {
894			/* the device has gone! */
895			restore_controller(sc->kbdc, c);
896			sc->state &= ~PSM_VALID;
897			log(LOG_ERR,
898			    "psm%d: the aux device has gone! (reinitialize).\n",
899			    sc->unit);
900			err = ENXIO;
901		}
902	}
903	splx(s);
904
905	/* restore the driver state */
906	if ((sc->state & PSM_OPEN) && (err == 0)) {
907		/* enable the aux device and the port again */
908		err = doopen(sc, c);
909		if (err != 0)
910			log(LOG_ERR, "psm%d: failed to enable the device "
911			    "(reinitialize).\n", sc->unit);
912	} else {
913		/* restore the keyboard port and disable the aux port */
914		if (!set_controller_command_byte(sc->kbdc,
915		    kbdc_get_device_mask(sc->kbdc),
916		    (c & KBD_KBD_CONTROL_BITS) |
917		    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
918			/* CONTROLLER ERROR */
919			log(LOG_ERR, "psm%d: failed to disable the aux port "
920			    "(reinitialize).\n", sc->unit);
921			err = EIO;
922		}
923	}
924
925	kbdc_lock(sc->kbdc, FALSE);
926	return (err);
927}
928
929/* psm driver entry points */
930
931static void
932psmidentify(driver_t *driver, device_t parent)
933{
934	device_t psmc;
935	device_t psm;
936	u_long irq;
937	int unit;
938
939	unit = device_get_unit(parent);
940
941	/* always add at least one child */
942	psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit);
943	if (psm == NULL)
944		return;
945
946	irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX);
947	if (irq > 0)
948		return;
949
950	/*
951	 * If the PS/2 mouse device has already been reported by ACPI or
952	 * PnP BIOS, obtain the IRQ resource from it.
953	 * (See psmcpnp_attach() below.)
954	 */
955	psmc = device_find_child(device_get_parent(parent),
956	    PSMCPNP_DRIVER_NAME, unit);
957	if (psmc == NULL)
958		return;
959	irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0);
960	if (irq <= 0)
961		return;
962	bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
963}
964
965#define	endprobe(v)	do {			\
966	if (bootverbose)			\
967		--verbose;			\
968	kbdc_set_device_mask(sc->kbdc, mask);	\
969	kbdc_lock(sc->kbdc, FALSE);		\
970	return (v);				\
971} while (0)
972
973static int
974psmprobe(device_t dev)
975{
976	int unit = device_get_unit(dev);
977	struct psm_softc *sc = device_get_softc(dev);
978	int stat[3];
979	int command_byte;
980	int mask;
981	int rid;
982	int i;
983
984#if 0
985	kbdc_debug(TRUE);
986#endif
987
988	/* see if IRQ is available */
989	rid = KBDC_RID_AUX;
990	sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
991	    RF_SHAREABLE | RF_ACTIVE);
992	if (sc->intr == NULL) {
993		if (bootverbose)
994			device_printf(dev, "unable to allocate IRQ\n");
995		return (ENXIO);
996	}
997	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
998
999	sc->unit = unit;
1000	sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
1001	sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS;
1002	/* XXX: for backward compatibility */
1003#if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
1004	sc->config |=
1005#ifdef PSM_RESETAFTERSUSPEND
1006	PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
1007#else
1008	PSM_CONFIG_HOOKRESUME;
1009#endif
1010#endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
1011	sc->flags = 0;
1012	if (bootverbose)
1013		++verbose;
1014
1015	device_set_desc(dev, "PS/2 Mouse");
1016
1017	if (!kbdc_lock(sc->kbdc, TRUE)) {
1018		printf("psm%d: unable to lock the controller.\n", unit);
1019		if (bootverbose)
1020			--verbose;
1021		return (ENXIO);
1022	}
1023
1024	/*
1025	 * NOTE: two bits in the command byte controls the operation of the
1026	 * aux port (mouse port): the aux port disable bit (bit 5) and the aux
1027	 * port interrupt (IRQ 12) enable bit (bit 2).
1028	 */
1029
1030	/* discard anything left after the keyboard initialization */
1031	empty_both_buffers(sc->kbdc, 10);
1032
1033	/* save the current command byte; it will be used later */
1034	mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
1035	command_byte = get_controller_command_byte(sc->kbdc);
1036	if (verbose)
1037		printf("psm%d: current command byte:%04x\n", unit,
1038		    command_byte);
1039	if (command_byte == -1) {
1040		/* CONTROLLER ERROR */
1041		printf("psm%d: unable to get the current command byte value.\n",
1042			unit);
1043		endprobe(ENXIO);
1044	}
1045
1046	/*
1047	 * disable the keyboard port while probing the aux port, which must be
1048	 * enabled during this routine
1049	 */
1050	if (!set_controller_command_byte(sc->kbdc,
1051	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1052	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1053	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1054		/*
1055		 * this is CONTROLLER ERROR; I don't know how to recover
1056		 * from this error...
1057		 */
1058		restore_controller(sc->kbdc, command_byte);
1059		printf("psm%d: unable to set the command byte.\n", unit);
1060		endprobe(ENXIO);
1061	}
1062	write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
1063
1064	/*
1065	 * NOTE: `test_aux_port()' is designed to return with zero if the aux
1066	 * port exists and is functioning. However, some controllers appears
1067	 * to respond with zero even when the aux port doesn't exist. (It may
1068	 * be that this is only the case when the controller DOES have the aux
1069	 * port but the port is not wired on the motherboard.) The keyboard
1070	 * controllers without the port, such as the original AT, are
1071	 * supporsed to return with an error code or simply time out. In any
1072	 * case, we have to continue probing the port even when the controller
1073	 * passes this test.
1074	 *
1075	 * XXX: some controllers erroneously return the error code 1, 2 or 3
1076	 * when it has the perfectly functional aux port. We have to ignore
1077	 * this error code. Even if the controller HAS error with the aux
1078	 * port, it will be detected later...
1079	 * XXX: another incompatible controller returns PSM_ACK (0xfa)...
1080	 */
1081	switch ((i = test_aux_port(sc->kbdc))) {
1082	case 1:		/* ignore these errors */
1083	case 2:
1084	case 3:
1085	case PSM_ACK:
1086		if (verbose)
1087			printf("psm%d: strange result for test aux port "
1088			    "(%d).\n", unit, i);
1089		/* FALLTHROUGH */
1090	case 0:		/* no error */
1091		break;
1092	case -1:	/* time out */
1093	default:	/* error */
1094		recover_from_error(sc->kbdc);
1095		if (sc->config & PSM_CONFIG_IGNPORTERROR)
1096			break;
1097		restore_controller(sc->kbdc, command_byte);
1098		if (verbose)
1099			printf("psm%d: the aux port is not functioning (%d).\n",
1100			    unit, i);
1101		endprobe(ENXIO);
1102	}
1103
1104	if (sc->config & PSM_CONFIG_NORESET) {
1105		/*
1106		 * Don't try to reset the pointing device.  It may possibly be
1107		 * left in the unknown state, though...
1108		 */
1109	} else {
1110		/*
1111		 * NOTE: some controllers appears to hang the `keyboard' when
1112		 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
1113		 *
1114		 * Attempt to reset the controller twice -- this helps
1115		 * pierce through some KVM switches. The second reset
1116		 * is non-fatal.
1117		 */
1118		if (!reset_aux_dev(sc->kbdc)) {
1119			recover_from_error(sc->kbdc);
1120			restore_controller(sc->kbdc, command_byte);
1121			if (verbose)
1122				printf("psm%d: failed to reset the aux "
1123				    "device.\n", unit);
1124			endprobe(ENXIO);
1125		} else if (!reset_aux_dev(sc->kbdc)) {
1126			recover_from_error(sc->kbdc);
1127			if (verbose >= 2)
1128				printf("psm%d: failed to reset the aux device "
1129				    "(2).\n", unit);
1130		}
1131	}
1132
1133	/*
1134	 * both the aux port and the aux device is functioning, see if the
1135	 * device can be enabled. NOTE: when enabled, the device will start
1136	 * sending data; we shall immediately disable the device once we know
1137	 * the device can be enabled.
1138	 */
1139	if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
1140		/* MOUSE ERROR */
1141		recover_from_error(sc->kbdc);
1142		restore_controller(sc->kbdc, command_byte);
1143		if (verbose)
1144			printf("psm%d: failed to enable the aux device.\n",
1145			    unit);
1146		endprobe(ENXIO);
1147	}
1148
1149	/* save the default values after reset */
1150	if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
1151		sc->dflt_mode.rate = sc->mode.rate = stat[2];
1152		sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1153	} else {
1154		sc->dflt_mode.rate = sc->mode.rate = -1;
1155		sc->dflt_mode.resolution = sc->mode.resolution = -1;
1156	}
1157
1158	/* hardware information */
1159	sc->hw.iftype = MOUSE_IF_PS2;
1160
1161	/* verify the device is a mouse */
1162	sc->hw.hwid = get_aux_id(sc->kbdc);
1163	if (!is_a_mouse(sc->hw.hwid)) {
1164		restore_controller(sc->kbdc, command_byte);
1165		if (verbose)
1166			printf("psm%d: unknown device type (%d).\n", unit,
1167			    sc->hw.hwid);
1168		endprobe(ENXIO);
1169	}
1170	switch (sc->hw.hwid) {
1171	case PSM_BALLPOINT_ID:
1172		sc->hw.type = MOUSE_TRACKBALL;
1173		break;
1174	case PSM_MOUSE_ID:
1175	case PSM_INTELLI_ID:
1176	case PSM_EXPLORER_ID:
1177	case PSM_4DMOUSE_ID:
1178	case PSM_4DPLUS_ID:
1179		sc->hw.type = MOUSE_MOUSE;
1180		break;
1181	default:
1182		sc->hw.type = MOUSE_UNKNOWN;
1183		break;
1184	}
1185
1186	if (sc->config & PSM_CONFIG_NOIDPROBE) {
1187		sc->hw.buttons = 2;
1188		i = GENERIC_MOUSE_ENTRY;
1189	} else {
1190		/* # of buttons */
1191		sc->hw.buttons = get_mouse_buttons(sc->kbdc);
1192
1193		/* other parameters */
1194		for (i = 0; vendortype[i].probefunc != NULL; ++i)
1195			if ((*vendortype[i].probefunc)(sc)) {
1196				if (verbose >= 2)
1197					printf("psm%d: found %s\n", unit,
1198					    model_name(vendortype[i].model));
1199				break;
1200			}
1201	}
1202
1203	sc->hw.model = vendortype[i].model;
1204
1205	sc->dflt_mode.level = PSM_LEVEL_BASE;
1206	sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
1207	sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
1208	if (sc->config & PSM_CONFIG_NOCHECKSYNC)
1209		sc->dflt_mode.syncmask[0] = 0;
1210	else
1211		sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
1212	if (sc->config & PSM_CONFIG_FORCETAP)
1213		sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP;
1214	sc->dflt_mode.syncmask[1] = 0;	/* syncbits */
1215	sc->mode = sc->dflt_mode;
1216	sc->mode.packetsize = vendortype[i].packetsize;
1217
1218	/* set mouse parameters */
1219#if 0
1220	/*
1221	 * A version of Logitech FirstMouse+ won't report wheel movement,
1222	 * if SET_DEFAULTS is sent...  Don't use this command.
1223	 * This fix was found by Takashi Nishida.
1224	 */
1225	i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
1226	if (verbose >= 2)
1227		printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
1228#endif
1229	if (sc->config & PSM_CONFIG_RESOLUTION)
1230		sc->mode.resolution =
1231		    set_mouse_resolution(sc->kbdc,
1232		    (sc->config & PSM_CONFIG_RESOLUTION) - 1);
1233	else if (sc->mode.resolution >= 0)
1234		sc->mode.resolution =
1235		    set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
1236	if (sc->mode.rate > 0)
1237		sc->mode.rate =
1238		    set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
1239	set_mouse_scaling(sc->kbdc, 1);
1240
1241	/* Record sync on the next data packet we see. */
1242	sc->flags |= PSM_NEED_SYNCBITS;
1243
1244	/* just check the status of the mouse */
1245	/*
1246	 * NOTE: XXX there are some arcane controller/mouse combinations out
1247	 * there, which hung the controller unless there is data transmission
1248	 * after ACK from the mouse.
1249	 */
1250	if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1251		printf("psm%d: failed to get status.\n", unit);
1252	else {
1253		/*
1254		 * When in its native mode, some mice operate with different
1255		 * default parameters than in the PS/2 compatible mode.
1256		 */
1257		sc->dflt_mode.rate = sc->mode.rate = stat[2];
1258		sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1259	}
1260
1261	/* disable the aux port for now... */
1262	if (!set_controller_command_byte(sc->kbdc,
1263	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1264	    (command_byte & KBD_KBD_CONTROL_BITS) |
1265	    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1266		/*
1267		 * this is CONTROLLER ERROR; I don't know the proper way to
1268		 * recover from this error...
1269		 */
1270		restore_controller(sc->kbdc, command_byte);
1271		printf("psm%d: unable to set the command byte.\n", unit);
1272		endprobe(ENXIO);
1273	}
1274
1275	/*
1276	 * Synaptics TouchPad seems to go back to Relative Mode after
1277	 * the previous set_controller_command_byte() call; by issueing
1278	 * a Read Mode Byte command, the touchpad is in Absolute Mode
1279	 * again.
1280	 */
1281	if (sc->hw.model == MOUSE_MODEL_SYNAPTICS)
1282		mouse_ext_command(sc->kbdc, 1);
1283
1284	/* done */
1285	kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
1286	kbdc_lock(sc->kbdc, FALSE);
1287	return (0);
1288}
1289
1290static int
1291psmattach(device_t dev)
1292{
1293	int unit = device_get_unit(dev);
1294	struct psm_softc *sc = device_get_softc(dev);
1295	int error;
1296	int rid;
1297
1298	/* Setup initial state */
1299	sc->state = PSM_VALID;
1300	callout_handle_init(&sc->callout);
1301
1302	/* Setup our interrupt handler */
1303	rid = KBDC_RID_AUX;
1304	sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1305	    RF_SHAREABLE | RF_ACTIVE);
1306	if (sc->intr == NULL)
1307		return (ENXIO);
1308	error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc,
1309	    &sc->ih);
1310	if (error) {
1311		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1312		return (error);
1313	}
1314
1315	/* Done */
1316	sc->dev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, FALSE), 0, 0, 0666,
1317	    "psm%d", unit);
1318	sc->bdev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, TRUE), 0, 0, 0666,
1319	    "bpsm%d", unit);
1320
1321	if (!verbose)
1322		printf("psm%d: model %s, device ID %d\n",
1323		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1324	else {
1325		printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
1326		    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff,
1327		    sc->hw.hwid >> 8, sc->hw.buttons);
1328		printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
1329		    unit, sc->config, sc->flags, sc->mode.packetsize);
1330		printf("psm%d: syncmask:%02x, syncbits:%02x\n",
1331		    unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
1332	}
1333
1334	if (bootverbose)
1335		--verbose;
1336
1337	return (0);
1338}
1339
1340static int
1341psmdetach(device_t dev)
1342{
1343	struct psm_softc *sc;
1344	int rid;
1345
1346	sc = device_get_softc(dev);
1347	if (sc->state & PSM_OPEN)
1348		return (EBUSY);
1349
1350	rid = KBDC_RID_AUX;
1351	bus_teardown_intr(dev, sc->intr, sc->ih);
1352	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1353
1354	destroy_dev(sc->dev);
1355	destroy_dev(sc->bdev);
1356
1357	return (0);
1358}
1359
1360static int
1361psmopen(struct cdev *dev, int flag, int fmt, struct thread *td)
1362{
1363	int unit = PSM_UNIT(dev);
1364	struct psm_softc *sc;
1365	int command_byte;
1366	int err;
1367	int s;
1368
1369	/* Get device data */
1370	sc = PSM_SOFTC(unit);
1371	if ((sc == NULL) || (sc->state & PSM_VALID) == 0) {
1372		/* the device is no longer valid/functioning */
1373		return (ENXIO);
1374	}
1375
1376	/* Disallow multiple opens */
1377	if (sc->state & PSM_OPEN)
1378		return (EBUSY);
1379
1380	device_busy(devclass_get_device(psm_devclass, unit));
1381
1382	/* Initialize state */
1383	sc->mode.level = sc->dflt_mode.level;
1384	sc->mode.protocol = sc->dflt_mode.protocol;
1385	sc->watchdog = FALSE;
1386
1387	/* flush the event queue */
1388	sc->queue.count = 0;
1389	sc->queue.head = 0;
1390	sc->queue.tail = 0;
1391	sc->status.flags = 0;
1392	sc->status.button = 0;
1393	sc->status.obutton = 0;
1394	sc->status.dx = 0;
1395	sc->status.dy = 0;
1396	sc->status.dz = 0;
1397	sc->button = 0;
1398	sc->pqueue_start = 0;
1399	sc->pqueue_end = 0;
1400
1401	/* empty input buffer */
1402	flushpackets(sc);
1403	sc->syncerrors = 0;
1404	sc->pkterrors = 0;
1405
1406	/* don't let timeout routines in the keyboard driver to poll the kbdc */
1407	if (!kbdc_lock(sc->kbdc, TRUE))
1408		return (EIO);
1409
1410	/* save the current controller command byte */
1411	s = spltty();
1412	command_byte = get_controller_command_byte(sc->kbdc);
1413
1414	/* enable the aux port and temporalily disable the keyboard */
1415	if (command_byte == -1 || !set_controller_command_byte(sc->kbdc,
1416	    kbdc_get_device_mask(sc->kbdc),
1417	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1418	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1419		/* CONTROLLER ERROR; do you know how to get out of this? */
1420		kbdc_lock(sc->kbdc, FALSE);
1421		splx(s);
1422		log(LOG_ERR,
1423		    "psm%d: unable to set the command byte (psmopen).\n", unit);
1424		return (EIO);
1425	}
1426	/*
1427	 * Now that the keyboard controller is told not to generate
1428	 * the keyboard and mouse interrupts, call `splx()' to allow
1429	 * the other tty interrupts. The clock interrupt may also occur,
1430	 * but timeout routines will be blocked by the poll flag set
1431	 * via `kbdc_lock()'
1432	 */
1433	splx(s);
1434
1435	/* enable the mouse device */
1436	err = doopen(sc, command_byte);
1437
1438	/* done */
1439	if (err == 0)
1440		sc->state |= PSM_OPEN;
1441	kbdc_lock(sc->kbdc, FALSE);
1442	return (err);
1443}
1444
1445static int
1446psmclose(struct cdev *dev, int flag, int fmt, struct thread *td)
1447{
1448	int unit = PSM_UNIT(dev);
1449	struct psm_softc *sc = PSM_SOFTC(unit);
1450	int stat[3];
1451	int command_byte;
1452	int s;
1453
1454	/* don't let timeout routines in the keyboard driver to poll the kbdc */
1455	if (!kbdc_lock(sc->kbdc, TRUE))
1456		return (EIO);
1457
1458	/* save the current controller command byte */
1459	s = spltty();
1460	command_byte = get_controller_command_byte(sc->kbdc);
1461	if (command_byte == -1) {
1462		kbdc_lock(sc->kbdc, FALSE);
1463		splx(s);
1464		return (EIO);
1465	}
1466
1467	/* disable the aux interrupt and temporalily disable the keyboard */
1468	if (!set_controller_command_byte(sc->kbdc,
1469	    kbdc_get_device_mask(sc->kbdc),
1470	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1471	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1472		log(LOG_ERR,
1473		    "psm%d: failed to disable the aux int (psmclose).\n", unit);
1474		/* CONTROLLER ERROR;
1475		 * NOTE: we shall force our way through. Because the only
1476		 * ill effect we shall see is that we may not be able
1477		 * to read ACK from the mouse, and it doesn't matter much
1478		 * so long as the mouse will accept the DISABLE command.
1479		 */
1480	}
1481	splx(s);
1482
1483	/* stop the watchdog timer */
1484	untimeout(psmtimeout, (void *)(uintptr_t)sc, sc->callout);
1485	callout_handle_init(&sc->callout);
1486
1487	/* remove anything left in the output buffer */
1488	empty_aux_buffer(sc->kbdc, 10);
1489
1490	/* disable the aux device, port and interrupt */
1491	if (sc->state & PSM_VALID) {
1492		if (!disable_aux_dev(sc->kbdc)) {
1493			/* MOUSE ERROR;
1494			 * NOTE: we don't return (error) and continue,
1495			 * pretending we have successfully disabled the device.
1496			 * It's OK because the interrupt routine will discard
1497			 * any data from the mouse hereafter.
1498			 */
1499			log(LOG_ERR,
1500			    "psm%d: failed to disable the device (psmclose).\n",
1501			    unit);
1502		}
1503
1504		if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1505			log(LOG_DEBUG,
1506			    "psm%d: failed to get status (psmclose).\n", unit);
1507	}
1508
1509	if (!set_controller_command_byte(sc->kbdc,
1510	    kbdc_get_device_mask(sc->kbdc),
1511	    (command_byte & KBD_KBD_CONTROL_BITS) |
1512	    KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1513		/*
1514		 * CONTROLLER ERROR;
1515		 * we shall ignore this error; see the above comment.
1516		 */
1517		log(LOG_ERR,
1518		    "psm%d: failed to disable the aux port (psmclose).\n",
1519		    unit);
1520	}
1521
1522	/* remove anything left in the output buffer */
1523	empty_aux_buffer(sc->kbdc, 10);
1524
1525	/* close is almost always successful */
1526	sc->state &= ~PSM_OPEN;
1527	kbdc_lock(sc->kbdc, FALSE);
1528	device_unbusy(devclass_get_device(psm_devclass, unit));
1529	return (0);
1530}
1531
1532static int
1533tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status,
1534    u_char *buf)
1535{
1536	static u_char butmapps2[8] = {
1537		0,
1538		MOUSE_PS2_BUTTON1DOWN,
1539		MOUSE_PS2_BUTTON2DOWN,
1540		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
1541		MOUSE_PS2_BUTTON3DOWN,
1542		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
1543		MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1544		MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN |
1545		    MOUSE_PS2_BUTTON3DOWN,
1546	};
1547	static u_char butmapmsc[8] = {
1548		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP |
1549		    MOUSE_MSC_BUTTON3UP,
1550		MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1551		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1552		MOUSE_MSC_BUTTON3UP,
1553		MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1554		MOUSE_MSC_BUTTON2UP,
1555		MOUSE_MSC_BUTTON1UP,
1556		0,
1557	};
1558	int mapped;
1559	int i;
1560
1561	if (sc->mode.level == PSM_LEVEL_BASE) {
1562		mapped = status->button & ~MOUSE_BUTTON4DOWN;
1563		if (status->button & MOUSE_BUTTON4DOWN)
1564			mapped |= MOUSE_BUTTON1DOWN;
1565		status->button = mapped;
1566		buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
1567		i = imax(imin(status->dx, 255), -256);
1568		if (i < 0)
1569			buf[0] |= MOUSE_PS2_XNEG;
1570		buf[1] = i;
1571		i = imax(imin(status->dy, 255), -256);
1572		if (i < 0)
1573			buf[0] |= MOUSE_PS2_YNEG;
1574		buf[2] = i;
1575		return (MOUSE_PS2_PACKETSIZE);
1576	} else if (sc->mode.level == PSM_LEVEL_STANDARD) {
1577		buf[0] = MOUSE_MSC_SYNC |
1578		    butmapmsc[status->button & MOUSE_STDBUTTONS];
1579		i = imax(imin(status->dx, 255), -256);
1580		buf[1] = i >> 1;
1581		buf[3] = i - buf[1];
1582		i = imax(imin(status->dy, 255), -256);
1583		buf[2] = i >> 1;
1584		buf[4] = i - buf[2];
1585		i = imax(imin(status->dz, 127), -128);
1586		buf[5] = (i >> 1) & 0x7f;
1587		buf[6] = (i - (i >> 1)) & 0x7f;
1588		buf[7] = (~status->button >> 3) & 0x7f;
1589		return (MOUSE_SYS_PACKETSIZE);
1590	}
1591	return (pb->inputbytes);
1592}
1593
1594static int
1595psmread(struct cdev *dev, struct uio *uio, int flag)
1596{
1597	register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
1598	u_char buf[PSM_SMALLBUFSIZE];
1599	int error = 0;
1600	int s;
1601	int l;
1602
1603	if ((sc->state & PSM_VALID) == 0)
1604		return (EIO);
1605
1606	/* block until mouse activity occured */
1607	s = spltty();
1608	while (sc->queue.count <= 0) {
1609		if (PSM_NBLOCKIO(dev)) {
1610			splx(s);
1611			return (EWOULDBLOCK);
1612		}
1613		sc->state |= PSM_ASLP;
1614		error = tsleep(sc, PZERO | PCATCH, "psmrea", 0);
1615		sc->state &= ~PSM_ASLP;
1616		if (error) {
1617			splx(s);
1618			return (error);
1619		} else if ((sc->state & PSM_VALID) == 0) {
1620			/* the device disappeared! */
1621			splx(s);
1622			return (EIO);
1623		}
1624	}
1625	splx(s);
1626
1627	/* copy data to the user land */
1628	while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
1629		s = spltty();
1630		l = imin(sc->queue.count, uio->uio_resid);
1631		if (l > sizeof(buf))
1632			l = sizeof(buf);
1633		if (l > sizeof(sc->queue.buf) - sc->queue.head) {
1634			bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
1635			    sizeof(sc->queue.buf) - sc->queue.head);
1636			bcopy(&sc->queue.buf[0],
1637			    &buf[sizeof(sc->queue.buf) - sc->queue.head],
1638			    l - (sizeof(sc->queue.buf) - sc->queue.head));
1639		} else
1640			bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
1641		sc->queue.count -= l;
1642		sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
1643		splx(s);
1644		error = uiomove(buf, l, uio);
1645		if (error)
1646			break;
1647	}
1648
1649	return (error);
1650}
1651
1652static int
1653block_mouse_data(struct psm_softc *sc, int *c)
1654{
1655	int s;
1656
1657	if (!kbdc_lock(sc->kbdc, TRUE))
1658		return (EIO);
1659
1660	s = spltty();
1661	*c = get_controller_command_byte(sc->kbdc);
1662	if ((*c == -1) || !set_controller_command_byte(sc->kbdc,
1663	    kbdc_get_device_mask(sc->kbdc),
1664	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT |
1665	    KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1666		/* this is CONTROLLER ERROR */
1667		splx(s);
1668		kbdc_lock(sc->kbdc, FALSE);
1669		return (EIO);
1670	}
1671
1672	/*
1673	 * The device may be in the middle of status data transmission.
1674	 * The transmission will be interrupted, thus, incomplete status
1675	 * data must be discarded. Although the aux interrupt is disabled
1676	 * at the keyboard controller level, at most one aux interrupt
1677	 * may have already been pending and a data byte is in the
1678	 * output buffer; throw it away. Note that the second argument
1679	 * to `empty_aux_buffer()' is zero, so that the call will just
1680	 * flush the internal queue.
1681	 * `psmintr()' will be invoked after `splx()' if an interrupt is
1682	 * pending; it will see no data and returns immediately.
1683	 */
1684	empty_aux_buffer(sc->kbdc, 0);		/* flush the queue */
1685	read_aux_data_no_wait(sc->kbdc);	/* throw away data if any */
1686	flushpackets(sc);
1687	splx(s);
1688
1689	return (0);
1690}
1691
1692static void
1693dropqueue(struct psm_softc *sc)
1694{
1695
1696	sc->queue.count = 0;
1697	sc->queue.head = 0;
1698	sc->queue.tail = 0;
1699	if ((sc->state & PSM_SOFTARMED) != 0) {
1700		sc->state &= ~PSM_SOFTARMED;
1701		untimeout(psmsoftintr, (void *)(uintptr_t)sc, sc->softcallout);
1702	}
1703	sc->pqueue_start = sc->pqueue_end;
1704}
1705
1706static void
1707flushpackets(struct psm_softc *sc)
1708{
1709
1710	dropqueue(sc);
1711	bzero(&sc->pqueue, sizeof(sc->pqueue));
1712}
1713
1714static int
1715unblock_mouse_data(struct psm_softc *sc, int c)
1716{
1717	int error = 0;
1718
1719	/*
1720	 * We may have seen a part of status data during `set_mouse_XXX()'.
1721	 * they have been queued; flush it.
1722	 */
1723	empty_aux_buffer(sc->kbdc, 0);
1724
1725	/* restore ports and interrupt */
1726	if (!set_controller_command_byte(sc->kbdc,
1727	    kbdc_get_device_mask(sc->kbdc),
1728	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1729		/*
1730		 * CONTROLLER ERROR; this is serious, we may have
1731		 * been left with the inaccessible keyboard and
1732		 * the disabled mouse interrupt.
1733		 */
1734		error = EIO;
1735	}
1736
1737	kbdc_lock(sc->kbdc, FALSE);
1738	return (error);
1739}
1740
1741static int
1742psmwrite(struct cdev *dev, struct uio *uio, int flag)
1743{
1744	register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
1745	u_char buf[PSM_SMALLBUFSIZE];
1746	int error = 0, i, l;
1747
1748	if ((sc->state & PSM_VALID) == 0)
1749		return (EIO);
1750
1751	if (sc->mode.level < PSM_LEVEL_NATIVE)
1752		return (ENODEV);
1753
1754	/* copy data from the user land */
1755	while (uio->uio_resid > 0) {
1756		l = imin(PSM_SMALLBUFSIZE, uio->uio_resid);
1757		error = uiomove(buf, l, uio);
1758		if (error)
1759			break;
1760		for (i = 0; i < l; i++) {
1761			VLOG(4, (LOG_DEBUG, "psm: cmd 0x%x\n", buf[i]));
1762			if (!write_aux_command(sc->kbdc, buf[i])) {
1763				VLOG(2, (LOG_DEBUG,
1764				    "psm: cmd 0x%x failed.\n", buf[i]));
1765				return (reinitialize(sc, FALSE));
1766			}
1767		}
1768	}
1769
1770	return (error);
1771}
1772
1773static int
1774psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
1775    struct thread *td)
1776{
1777	struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
1778	mousemode_t mode;
1779	mousestatus_t status;
1780#if (defined(MOUSE_GETVARS))
1781	mousevar_t *var;
1782#endif
1783	mousedata_t *data;
1784	int stat[3];
1785	int command_byte;
1786	int error = 0;
1787	int s;
1788
1789	/* Perform IOCTL command */
1790	switch (cmd) {
1791
1792	case OLD_MOUSE_GETHWINFO:
1793		s = spltty();
1794		((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
1795		((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
1796		((old_mousehw_t *)addr)->type = sc->hw.type;
1797		((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
1798		splx(s);
1799		break;
1800
1801	case MOUSE_GETHWINFO:
1802		s = spltty();
1803		*(mousehw_t *)addr = sc->hw;
1804		if (sc->mode.level == PSM_LEVEL_BASE)
1805			((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
1806		splx(s);
1807		break;
1808
1809	case MOUSE_SYN_GETHWINFO:
1810		s = spltty();
1811		if (synaptics_support && sc->hw.model == MOUSE_MODEL_SYNAPTICS)
1812			*(synapticshw_t *)addr = sc->synhw;
1813		else
1814			error = EINVAL;
1815		splx(s);
1816		break;
1817
1818	case OLD_MOUSE_GETMODE:
1819		s = spltty();
1820		switch (sc->mode.level) {
1821		case PSM_LEVEL_BASE:
1822			((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1823			break;
1824		case PSM_LEVEL_STANDARD:
1825			((old_mousemode_t *)addr)->protocol =
1826			    MOUSE_PROTO_SYSMOUSE;
1827			break;
1828		case PSM_LEVEL_NATIVE:
1829			((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1830			break;
1831		}
1832		((old_mousemode_t *)addr)->rate = sc->mode.rate;
1833		((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
1834		((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
1835		splx(s);
1836		break;
1837
1838	case MOUSE_GETMODE:
1839		s = spltty();
1840		*(mousemode_t *)addr = sc->mode;
1841		if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
1842			((mousemode_t *)addr)->syncmask[0] = 0;
1843			((mousemode_t *)addr)->syncmask[1] = 0;
1844		}
1845		((mousemode_t *)addr)->resolution =
1846			MOUSE_RES_LOW - sc->mode.resolution;
1847		switch (sc->mode.level) {
1848		case PSM_LEVEL_BASE:
1849			((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1850			((mousemode_t *)addr)->packetsize =
1851			    MOUSE_PS2_PACKETSIZE;
1852			break;
1853		case PSM_LEVEL_STANDARD:
1854			((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
1855			((mousemode_t *)addr)->packetsize =
1856			    MOUSE_SYS_PACKETSIZE;
1857			((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
1858			((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
1859			break;
1860		case PSM_LEVEL_NATIVE:
1861			/* FIXME: this isn't quite correct... XXX */
1862			((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1863			break;
1864		}
1865		splx(s);
1866		break;
1867
1868	case OLD_MOUSE_SETMODE:
1869	case MOUSE_SETMODE:
1870		if (cmd == OLD_MOUSE_SETMODE) {
1871			mode.rate = ((old_mousemode_t *)addr)->rate;
1872			/*
1873			 * resolution  old I/F   new I/F
1874			 * default        0         0
1875			 * low            1        -2
1876			 * medium low     2        -3
1877			 * medium high    3        -4
1878			 * high           4        -5
1879			 */
1880			if (((old_mousemode_t *)addr)->resolution > 0)
1881				mode.resolution =
1882				    -((old_mousemode_t *)addr)->resolution - 1;
1883			else
1884				mode.resolution = 0;
1885			mode.accelfactor =
1886			    ((old_mousemode_t *)addr)->accelfactor;
1887			mode.level = -1;
1888		} else
1889			mode = *(mousemode_t *)addr;
1890
1891		/* adjust and validate parameters. */
1892		if (mode.rate > UCHAR_MAX)
1893			return (EINVAL);
1894		if (mode.rate == 0)
1895			mode.rate = sc->dflt_mode.rate;
1896		else if (mode.rate == -1)
1897			/* don't change the current setting */
1898			;
1899		else if (mode.rate < 0)
1900			return (EINVAL);
1901		if (mode.resolution >= UCHAR_MAX)
1902			return (EINVAL);
1903		if (mode.resolution >= 200)
1904			mode.resolution = MOUSE_RES_HIGH;
1905		else if (mode.resolution >= 100)
1906			mode.resolution = MOUSE_RES_MEDIUMHIGH;
1907		else if (mode.resolution >= 50)
1908			mode.resolution = MOUSE_RES_MEDIUMLOW;
1909		else if (mode.resolution > 0)
1910			mode.resolution = MOUSE_RES_LOW;
1911		if (mode.resolution == MOUSE_RES_DEFAULT)
1912			mode.resolution = sc->dflt_mode.resolution;
1913		else if (mode.resolution == -1)
1914			/* don't change the current setting */
1915			;
1916		else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
1917			mode.resolution = MOUSE_RES_LOW - mode.resolution;
1918		if (mode.level == -1)
1919			/* don't change the current setting */
1920			mode.level = sc->mode.level;
1921		else if ((mode.level < PSM_LEVEL_MIN) ||
1922		    (mode.level > PSM_LEVEL_MAX))
1923			return (EINVAL);
1924		if (mode.accelfactor == -1)
1925			/* don't change the current setting */
1926			mode.accelfactor = sc->mode.accelfactor;
1927		else if (mode.accelfactor < 0)
1928			return (EINVAL);
1929
1930		/* don't allow anybody to poll the keyboard controller */
1931		error = block_mouse_data(sc, &command_byte);
1932		if (error)
1933			return (error);
1934
1935		/* set mouse parameters */
1936		if (mode.rate > 0)
1937			mode.rate = set_mouse_sampling_rate(sc->kbdc,
1938			    mode.rate);
1939		if (mode.resolution >= 0)
1940			mode.resolution =
1941			    set_mouse_resolution(sc->kbdc, mode.resolution);
1942		set_mouse_scaling(sc->kbdc, 1);
1943		get_mouse_status(sc->kbdc, stat, 0, 3);
1944
1945		s = spltty();
1946		sc->mode.rate = mode.rate;
1947		sc->mode.resolution = mode.resolution;
1948		sc->mode.accelfactor = mode.accelfactor;
1949		sc->mode.level = mode.level;
1950		splx(s);
1951
1952		unblock_mouse_data(sc, command_byte);
1953		break;
1954
1955	case MOUSE_GETLEVEL:
1956		*(int *)addr = sc->mode.level;
1957		break;
1958
1959	case MOUSE_SETLEVEL:
1960		if ((*(int *)addr < PSM_LEVEL_MIN) ||
1961		    (*(int *)addr > PSM_LEVEL_MAX))
1962			return (EINVAL);
1963		sc->mode.level = *(int *)addr;
1964		break;
1965
1966	case MOUSE_GETSTATUS:
1967		s = spltty();
1968		status = sc->status;
1969		sc->status.flags = 0;
1970		sc->status.obutton = sc->status.button;
1971		sc->status.button = 0;
1972		sc->status.dx = 0;
1973		sc->status.dy = 0;
1974		sc->status.dz = 0;
1975		splx(s);
1976		*(mousestatus_t *)addr = status;
1977		break;
1978
1979#if (defined(MOUSE_GETVARS))
1980	case MOUSE_GETVARS:
1981		var = (mousevar_t *)addr;
1982		bzero(var, sizeof(*var));
1983		s = spltty();
1984		var->var[0] = MOUSE_VARS_PS2_SIG;
1985		var->var[1] = sc->config;
1986		var->var[2] = sc->flags;
1987		splx(s);
1988		break;
1989
1990	case MOUSE_SETVARS:
1991		return (ENODEV);
1992#endif /* MOUSE_GETVARS */
1993
1994	case MOUSE_READSTATE:
1995	case MOUSE_READDATA:
1996		data = (mousedata_t *)addr;
1997		if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
1998			return (EINVAL);
1999
2000		error = block_mouse_data(sc, &command_byte);
2001		if (error)
2002			return (error);
2003		if ((data->len = get_mouse_status(sc->kbdc, data->buf,
2004		    (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
2005			error = EIO;
2006		unblock_mouse_data(sc, command_byte);
2007		break;
2008
2009#if (defined(MOUSE_SETRESOLUTION))
2010	case MOUSE_SETRESOLUTION:
2011		mode.resolution = *(int *)addr;
2012		if (mode.resolution >= UCHAR_MAX)
2013			return (EINVAL);
2014		else if (mode.resolution >= 200)
2015			mode.resolution = MOUSE_RES_HIGH;
2016		else if (mode.resolution >= 100)
2017			mode.resolution = MOUSE_RES_MEDIUMHIGH;
2018		else if (mode.resolution >= 50)
2019			mode.resolution = MOUSE_RES_MEDIUMLOW;
2020		else if (mode.resolution > 0)
2021			mode.resolution = MOUSE_RES_LOW;
2022		if (mode.resolution == MOUSE_RES_DEFAULT)
2023			mode.resolution = sc->dflt_mode.resolution;
2024		else if (mode.resolution == -1)
2025			mode.resolution = sc->mode.resolution;
2026		else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
2027			mode.resolution = MOUSE_RES_LOW - mode.resolution;
2028
2029		error = block_mouse_data(sc, &command_byte);
2030		if (error)
2031			return (error);
2032		sc->mode.resolution =
2033		    set_mouse_resolution(sc->kbdc, mode.resolution);
2034		if (sc->mode.resolution != mode.resolution)
2035			error = EIO;
2036		unblock_mouse_data(sc, command_byte);
2037		break;
2038#endif /* MOUSE_SETRESOLUTION */
2039
2040#if (defined(MOUSE_SETRATE))
2041	case MOUSE_SETRATE:
2042		mode.rate = *(int *)addr;
2043		if (mode.rate > UCHAR_MAX)
2044			return (EINVAL);
2045		if (mode.rate == 0)
2046			mode.rate = sc->dflt_mode.rate;
2047		else if (mode.rate < 0)
2048			mode.rate = sc->mode.rate;
2049
2050		error = block_mouse_data(sc, &command_byte);
2051		if (error)
2052			return (error);
2053		sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
2054		if (sc->mode.rate != mode.rate)
2055			error = EIO;
2056		unblock_mouse_data(sc, command_byte);
2057		break;
2058#endif /* MOUSE_SETRATE */
2059
2060#if (defined(MOUSE_SETSCALING))
2061	case MOUSE_SETSCALING:
2062		if ((*(int *)addr <= 0) || (*(int *)addr > 2))
2063			return (EINVAL);
2064
2065		error = block_mouse_data(sc, &command_byte);
2066		if (error)
2067			return (error);
2068		if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
2069			error = EIO;
2070		unblock_mouse_data(sc, command_byte);
2071		break;
2072#endif /* MOUSE_SETSCALING */
2073
2074#if (defined(MOUSE_GETHWID))
2075	case MOUSE_GETHWID:
2076		error = block_mouse_data(sc, &command_byte);
2077		if (error)
2078			return (error);
2079		sc->hw.hwid &= ~0x00ff;
2080		sc->hw.hwid |= get_aux_id(sc->kbdc);
2081		*(int *)addr = sc->hw.hwid & 0x00ff;
2082		unblock_mouse_data(sc, command_byte);
2083		break;
2084#endif /* MOUSE_GETHWID */
2085
2086	default:
2087		return (ENOTTY);
2088	}
2089
2090	return (error);
2091}
2092
2093static void
2094psmtimeout(void *arg)
2095{
2096	struct psm_softc *sc;
2097	int s;
2098
2099	sc = (struct psm_softc *)arg;
2100	s = spltty();
2101	if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
2102		VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit));
2103		psmintr(sc);
2104		kbdc_lock(sc->kbdc, FALSE);
2105	}
2106	sc->watchdog = TRUE;
2107	splx(s);
2108	sc->callout = timeout(psmtimeout, (void *)(uintptr_t)sc, hz);
2109}
2110
2111/* Add all sysctls under the debug.psm and hw.psm nodes */
2112SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2113SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
2114
2115SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0, "");
2116
2117static int psmhz = 20;
2118SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0, "");
2119static int psmerrsecs = 2;
2120SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0, "");
2121static int psmerrusecs = 0;
2122SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0, "");
2123static int psmsecs = 0;
2124SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0, "");
2125static int psmusecs = 500000;
2126SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0, "");
2127static int pkterrthresh = 2;
2128SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh,
2129    0, "");
2130
2131static int tap_threshold = PSM_TAP_THRESHOLD;
2132SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0, "");
2133static int tap_timeout = PSM_TAP_TIMEOUT;
2134SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0, "");
2135
2136static void
2137psmintr(void *arg)
2138{
2139	struct psm_softc *sc = arg;
2140	struct timeval now;
2141	int c;
2142	packetbuf_t *pb;
2143
2144
2145	/* read until there is nothing to read */
2146	while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
2147		pb = &sc->pqueue[sc->pqueue_end];
2148
2149		/* discard the byte if the device is not open */
2150		if ((sc->state & PSM_OPEN) == 0)
2151			continue;
2152
2153		getmicrouptime(&now);
2154		if ((pb->inputbytes > 0) &&
2155		    timevalcmp(&now, &sc->inputtimeout, >)) {
2156			VLOG(3, (LOG_DEBUG, "psmintr: delay too long; "
2157			    "resetting byte count\n"));
2158			pb->inputbytes = 0;
2159			sc->syncerrors = 0;
2160			sc->pkterrors = 0;
2161		}
2162		sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT / 1000000;
2163		sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT % 1000000;
2164		timevaladd(&sc->inputtimeout, &now);
2165
2166		pb->ipacket[pb->inputbytes++] = c;
2167
2168		if (sc->mode.level == PSM_LEVEL_NATIVE) {
2169			VLOG(4, (LOG_DEBUG, "psmintr: %02x\n", pb->ipacket[0]));
2170			sc->syncerrors = 0;
2171			sc->pkterrors = 0;
2172			goto next;
2173		} else {
2174			if (pb->inputbytes < sc->mode.packetsize)
2175				continue;
2176
2177			VLOG(4, (LOG_DEBUG,
2178			    "psmintr: %02x %02x %02x %02x %02x %02x\n",
2179			    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2],
2180			    pb->ipacket[3], pb->ipacket[4], pb->ipacket[5]));
2181		}
2182
2183		c = pb->ipacket[0];
2184
2185		if ((sc->flags & PSM_NEED_SYNCBITS) != 0) {
2186			sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]);
2187			sc->flags &= ~PSM_NEED_SYNCBITS;
2188			VLOG(2, (LOG_DEBUG,
2189			    "psmintr: Sync bytes now %04x,%04x\n",
2190			    sc->mode.syncmask[0], sc->mode.syncmask[0]));
2191		} else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
2192			VLOG(3, (LOG_DEBUG, "psmintr: out of sync "
2193			    "(%04x != %04x) %d cmds since last error.\n",
2194			    c & sc->mode.syncmask[0], sc->mode.syncmask[1],
2195			    sc->cmdcount - sc->lasterr));
2196			sc->lasterr = sc->cmdcount;
2197			/*
2198			 * The sync byte test is a weak measure of packet
2199			 * validity.  Conservatively discard any input yet
2200			 * to be seen by userland when we detect a sync
2201			 * error since there is a good chance some of
2202			 * the queued packets have undetected errors.
2203			 */
2204			dropqueue(sc);
2205			if (sc->syncerrors == 0)
2206				sc->pkterrors++;
2207			++sc->syncerrors;
2208			sc->lastinputerr = now;
2209			if (sc->syncerrors >= sc->mode.packetsize * 2 ||
2210			    sc->pkterrors >= pkterrthresh) {
2211				/*
2212				 * If we've failed to find a single sync byte
2213				 * in 2 packets worth of data, or we've seen
2214				 * persistent packet errors during the
2215				 * validation period, reinitialize the mouse
2216				 * in hopes of returning it to the expected
2217				 * mode.
2218				 */
2219				VLOG(3, (LOG_DEBUG,
2220				    "psmintr: reset the mouse.\n"));
2221				reinitialize(sc, TRUE);
2222			} else if (sc->syncerrors == sc->mode.packetsize) {
2223				/*
2224				 * Try a soft reset after searching for a sync
2225				 * byte through a packet length of bytes.
2226				 */
2227				VLOG(3, (LOG_DEBUG,
2228				    "psmintr: re-enable the mouse.\n"));
2229				pb->inputbytes = 0;
2230				disable_aux_dev(sc->kbdc);
2231				enable_aux_dev(sc->kbdc);
2232			} else {
2233				VLOG(3, (LOG_DEBUG,
2234				    "psmintr: discard a byte (%d)\n",
2235				    sc->syncerrors));
2236				pb->inputbytes--;
2237				bcopy(&pb->ipacket[1], &pb->ipacket[0],
2238				    pb->inputbytes);
2239			}
2240			continue;
2241		}
2242
2243		/*
2244		 * We have what appears to be a valid packet.
2245		 * Reset the error counters.
2246		 */
2247		sc->syncerrors = 0;
2248
2249		/*
2250		 * Drop even good packets if they occur within a timeout
2251		 * period of a sync error.  This allows the detection of
2252		 * a change in the mouse's packet mode without exposing
2253		 * erratic mouse behavior to the user.  Some KVMs forget
2254		 * enhanced mouse modes during switch events.
2255		 */
2256		if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs,
2257		    &now)) {
2258			pb->inputbytes = 0;
2259			continue;
2260		}
2261
2262		/*
2263		 * Now that we're out of the validation period, reset
2264		 * the packet error count.
2265		 */
2266		sc->pkterrors = 0;
2267
2268		sc->cmdcount++;
2269next:
2270		if (++sc->pqueue_end >= PSM_PACKETQUEUE)
2271			sc->pqueue_end = 0;
2272		/*
2273		 * If we've filled the queue then call the softintr ourselves,
2274		 * otherwise schedule the interrupt for later.
2275		 */
2276		if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) ||
2277		    (sc->pqueue_end == sc->pqueue_start)) {
2278			if ((sc->state & PSM_SOFTARMED) != 0) {
2279				sc->state &= ~PSM_SOFTARMED;
2280				untimeout(psmsoftintr, arg, sc->softcallout);
2281			}
2282			psmsoftintr(arg);
2283		} else if ((sc->state & PSM_SOFTARMED) == 0) {
2284			sc->state |= PSM_SOFTARMED;
2285			sc->softcallout = timeout(psmsoftintr, arg,
2286			    psmhz < 1 ? 1 : (hz/psmhz));
2287		}
2288	}
2289}
2290
2291static void
2292proc_mmanplus(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2293    int *x, int *y, int *z)
2294{
2295
2296	/*
2297	 * PS2++ protocl packet
2298	 *
2299	 *          b7 b6 b5 b4 b3 b2 b1 b0
2300	 * byte 1:  *  1  p3 p2 1  *  *  *
2301	 * byte 2:  c1 c2 p1 p0 d1 d0 1  0
2302	 *
2303	 * p3-p0: packet type
2304	 * c1, c2: c1 & c2 == 1, if p2 == 0
2305	 *         c1 & c2 == 0, if p2 == 1
2306	 *
2307	 * packet type: 0 (device type)
2308	 * See comments in enable_mmanplus() below.
2309	 *
2310	 * packet type: 1 (wheel data)
2311	 *
2312	 *          b7 b6 b5 b4 b3 b2 b1 b0
2313	 * byte 3:  h  *  B5 B4 s  d2 d1 d0
2314	 *
2315	 * h: 1, if horizontal roller data
2316	 *    0, if vertical roller data
2317	 * B4, B5: button 4 and 5
2318	 * s: sign bit
2319	 * d2-d0: roller data
2320	 *
2321	 * packet type: 2 (reserved)
2322	 */
2323	if (((pb->ipacket[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) &&
2324	    (abs(*x) > 191) && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) {
2325		/*
2326		 * the extended data packet encodes button
2327		 * and wheel events
2328		 */
2329		switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) {
2330		case 1:
2331			/* wheel data packet */
2332			*x = *y = 0;
2333			if (pb->ipacket[2] & 0x80) {
2334				/* XXX horizontal roller count - ignore it */
2335				;
2336			} else {
2337				/* vertical roller count */
2338				*z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) ?
2339				    (pb->ipacket[2] & 0x0f) - 16 :
2340				    (pb->ipacket[2] & 0x0f);
2341			}
2342			ms->button |= (pb->ipacket[2] &
2343			    MOUSE_PS2PLUS_BUTTON4DOWN) ?
2344			    MOUSE_BUTTON4DOWN : 0;
2345			ms->button |= (pb->ipacket[2] &
2346			    MOUSE_PS2PLUS_BUTTON5DOWN) ?
2347			    MOUSE_BUTTON5DOWN : 0;
2348			break;
2349		case 2:
2350			/*
2351			 * this packet type is reserved by
2352			 * Logitech...
2353			 */
2354			/*
2355			 * IBM ScrollPoint Mouse uses this
2356			 * packet type to encode both vertical
2357			 * and horizontal scroll movement.
2358			 */
2359			*x = *y = 0;
2360			/* horizontal count */
2361			if (pb->ipacket[2] & 0x0f)
2362				*z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ?
2363				    -2 : 2;
2364			/* vertical count */
2365			if (pb->ipacket[2] & 0xf0)
2366				*z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ?
2367				    -1 : 1;
2368			break;
2369		case 0:
2370			/* device type packet - shouldn't happen */
2371			/* FALLTHROUGH */
2372		default:
2373			*x = *y = 0;
2374			ms->button = ms->obutton;
2375			VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet "
2376			    "type %d: 0x%02x 0x%02x 0x%02x\n",
2377			    MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket),
2378			    pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]));
2379			break;
2380		}
2381	} else {
2382		/* preserve button states */
2383		ms->button |= ms->obutton & MOUSE_EXTBUTTONS;
2384	}
2385}
2386
2387static int
2388proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2389    int *x, int *y, int *z)
2390{
2391	static int touchpad_buttons;
2392	static int guest_buttons;
2393	int w, x0, y0, xavg, yavg, xsensitivity, ysensitivity, sensitivity = 0;
2394
2395	/* TouchPad PS/2 absolute mode message format
2396	 *
2397	 *  Bits:        7   6   5   4   3   2   1   0 (LSB)
2398	 *  ------------------------------------------------
2399	 *  ipacket[0]:  1   0  W3  W2   0  W1   R   L
2400	 *  ipacket[1]: Yb  Ya  Y9  Y8  Xb  Xa  X9  X8
2401	 *  ipacket[2]: Z7  Z6  Z5  Z4  Z3  Z2  Z1  Z0
2402	 *  ipacket[3]:  1   1  Yc  Xc   0  W0   D   U
2403	 *  ipacket[4]: X7  X6  X5  X4  X3  X2  X1  X0
2404	 *  ipacket[5]: Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
2405	 *
2406	 * Legend:
2407	 *  L: left physical mouse button
2408	 *  R: right physical mouse button
2409	 *  D: down button
2410	 *  U: up button
2411	 *  W: "wrist" value
2412	 *  X: x position
2413	 *  Y: x position
2414	 *  Z: pressure
2415	 *
2416	 * Absolute reportable limits:    0 - 6143.
2417	 * Typical bezel limits:       1472 - 5472.
2418	 * Typical edge marings:       1632 - 5312.
2419	 *
2420	 * w = 3 Passthrough Packet
2421	 *
2422	 * Byte 2,5,6 == Byte 1,2,3 of "Guest"
2423	 */
2424
2425	if (!synaptics_support)
2426		return (0);
2427
2428	/* Sanity check for out of sync packets. */
2429	if ((pb->ipacket[0] & 0xc8) != 0x80 ||
2430	    (pb->ipacket[3] & 0xc8) != 0xc0)
2431		return (-1);
2432
2433	*x = *y = x0 = y0 = 0;
2434
2435	/* Pressure value. */
2436	*z = pb->ipacket[2];
2437
2438	/* Finger width value */
2439	if (sc->synhw.capExtended)
2440		w = ((pb->ipacket[0] & 0x30) >> 2) |
2441		    ((pb->ipacket[0] & 0x04) >> 1) |
2442		    ((pb->ipacket[3] & 0x04) >> 2);
2443	else {
2444		/* Assume a finger of regular width */
2445		w = 4;
2446	}
2447
2448	/* Handle packets from the guest device */
2449	if (w == 3 && sc->synhw.capPassthrough) {
2450		*x = ((pb->ipacket[1] & 0x10) ?
2451		    pb->ipacket[4] - 256 : pb->ipacket[4]);
2452		*y = ((pb->ipacket[1] & 0x20) ?
2453		    pb->ipacket[5] - 256 : pb->ipacket[5]);
2454		*z = 0;
2455
2456		guest_buttons = 0;
2457		if (pb->ipacket[1] & 0x01)
2458			guest_buttons |= MOUSE_BUTTON1DOWN;
2459		if (pb->ipacket[1] & 0x04)
2460			guest_buttons |= MOUSE_BUTTON2DOWN;
2461		if (pb->ipacket[1] & 0x02)
2462			guest_buttons |= MOUSE_BUTTON3DOWN;
2463
2464		ms->button = touchpad_buttons | guest_buttons;
2465		return (0);
2466	}
2467
2468	/* Button presses */
2469	touchpad_buttons = 0;
2470	if (pb->ipacket[0] & 0x01)
2471		touchpad_buttons |= MOUSE_BUTTON1DOWN;
2472	if (pb->ipacket[0] & 0x02)
2473		touchpad_buttons |= MOUSE_BUTTON3DOWN;
2474
2475	if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
2476		if ((pb->ipacket[3] & 0x01) && (pb->ipacket[0] & 0x01) == 0)
2477			touchpad_buttons |= MOUSE_BUTTON4DOWN;
2478		if ((pb->ipacket[3] & 0x02) && (pb->ipacket[0] & 0x02) == 0)
2479			touchpad_buttons |= MOUSE_BUTTON5DOWN;
2480	}
2481
2482	/*
2483	 * In newer pads - bit 0x02 in the third byte of
2484	 * the packet indicates that we have an extended
2485	 * button press.
2486	 */
2487	if (pb->ipacket[3] & 0x02) {
2488		/*
2489		 * if directional_scrolls is not 1, we treat any of
2490		 * the scrolling directions as middle-click.
2491		 */
2492		if (sc->syninfo.directional_scrolls) {
2493			if (pb->ipacket[4] & 0x01)
2494				touchpad_buttons |= MOUSE_BUTTON4DOWN;
2495			if (pb->ipacket[5] & 0x01)
2496				touchpad_buttons |= MOUSE_BUTTON5DOWN;
2497			if (pb->ipacket[4] & 0x02)
2498				touchpad_buttons |= MOUSE_BUTTON6DOWN;
2499			if (pb->ipacket[5] & 0x02)
2500				touchpad_buttons |= MOUSE_BUTTON7DOWN;
2501		} else {
2502			if ((pb->ipacket[4] & 0x0F) || (pb->ipacket[5] & 0x0F))
2503				touchpad_buttons |= MOUSE_BUTTON2DOWN;
2504		}
2505	}
2506
2507	ms->button = touchpad_buttons | guest_buttons;
2508
2509	/* There is a finger on the pad. */
2510	if ((w >= 4 && w <= 7) && (*z >= 16 && *z < 200)) {
2511		x0 = ((pb->ipacket[3] & 0x10) << 8) |
2512		    ((pb->ipacket[1] & 0x0f) << 8) | pb->ipacket[4];
2513		y0 = ((pb->ipacket[3] & 0x20) << 7) |
2514		    ((pb->ipacket[1] & 0xf0) << 4) | pb->ipacket[5];
2515
2516		if (sc->flags & PSM_FLAGS_FINGERDOWN) {
2517			*x = x0 - sc->xold;
2518			*y = y0 - sc->yold;
2519
2520			/*
2521			 * we compute averages of x and y
2522			 * movement
2523			 */
2524			if (sc->xaverage == 0)
2525				sc->xaverage = *x;
2526
2527			if (sc->yaverage == 0)
2528				sc->yaverage = *y;
2529
2530			xavg = sc->xaverage;
2531			yavg = sc->yaverage;
2532
2533			sc->xaverage = (xavg + *x) >> 1;
2534			sc->yaverage = (yavg + *y) >> 1;
2535
2536			/*
2537			 * then use the averages to compute
2538			 * a sensitivity level in each dimension
2539			 */
2540			xsensitivity = (sc->xaverage - xavg);
2541			if (xsensitivity < 0)
2542				xsensitivity = -xsensitivity;
2543
2544			ysensitivity = (sc->yaverage - yavg);
2545			if (ysensitivity < 0)
2546				ysensitivity = -ysensitivity;
2547
2548			/*
2549			 * The sensitivity level is higher the faster
2550			 * the finger is moving.  It also tends to be
2551			 * higher in the middle of a touchpad motion
2552			 * than on either end
2553			 * Note - sensitivity gets to 0 when moving slowly -
2554			 * so we add 1 to it to give it a meaningful value
2555			 * in that case.
2556			 */
2557			sensitivity = (xsensitivity & ysensitivity) + 1;
2558
2559			/*
2560			 * If either our x or y change is greater than
2561			 * our hi/low speed threshold - we do the high-speed
2562			 * absolute to relative calculation otherwise
2563			 * we do the low-speed calculation.
2564			 */
2565			if ((*x > sc->syninfo.low_speed_threshold ||
2566			    *x < -sc->syninfo.low_speed_threshold) ||
2567			    (*y > sc->syninfo.low_speed_threshold ||
2568			    *y < -sc->syninfo.low_speed_threshold)) {
2569				x0 = (x0 + sc->xold * 3) / 4;
2570				y0 = (y0 + sc->yold * 3) / 4;
2571				*x = (x0 - sc->xold) * 10 / 85;
2572				*y = (y0 - sc->yold) * 10 / 85;
2573			} else {
2574				/*
2575				 * This is the low speed calculation.
2576				 * We simply check to see if our movement is
2577				 * more than our minimum movement threshold
2578				 * and if it is - set the movement to 1
2579				 * in the correct direction.
2580				 * NOTE - Normally this would result
2581				 * in pointer movement that was WAY too fast.
2582				 * This works due to the movement squelch
2583				 * we do later.
2584				 */
2585				if (*x < -sc->syninfo.min_movement)
2586					*x = -1;
2587				else if (*x > sc->syninfo.min_movement)
2588					*x = 1;
2589				else
2590					*x = 0;
2591				if (*y < -sc->syninfo.min_movement)
2592					*y = -1;
2593				else if (*y > sc->syninfo.min_movement)
2594					*y = 1;
2595				else
2596					*y = 0;
2597
2598			}
2599		} else
2600			sc->flags |= PSM_FLAGS_FINGERDOWN;
2601
2602		/*
2603		 * The squelch process.  Take our sensitivity value and
2604		 * add it to the current squelch value - if squelch is
2605		 * less than our squelch threshold we kill the movement,
2606		 * otherwise we reset squelch and pass the movement through.
2607		 * Since squelch is cumulative - when mouse movement is slow
2608		 * (around sensitivity 1) the net result is that only 1
2609		 * out of every squelch_level packets is delivered,
2610		 * effectively slowing down the movement.
2611		 */
2612		sc->squelch += sensitivity;
2613		if (sc->squelch < sc->syninfo.squelch_level) {
2614			*x = 0;
2615			*y = 0;
2616		} else
2617			sc->squelch = 0;
2618
2619		sc->xold = x0;
2620		sc->yold = y0;
2621		sc->zmax = imax(*z, sc->zmax);
2622	} else {
2623		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
2624
2625		if (sc->zmax > tap_threshold &&
2626		    timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) {
2627			if (w == 0)
2628				ms->button |= MOUSE_BUTTON3DOWN;
2629			else if (w == 1)
2630				ms->button |= MOUSE_BUTTON2DOWN;
2631			else
2632				ms->button |= MOUSE_BUTTON1DOWN;
2633		}
2634
2635		sc->zmax = 0;
2636		sc->taptimeout.tv_sec = tap_timeout / 1000000;
2637		sc->taptimeout.tv_usec = tap_timeout % 1000000;
2638		timevaladd(&sc->taptimeout, &sc->lastsoftintr);
2639	}
2640
2641	/* Use the extra buttons as a scrollwheel */
2642	if (ms->button & MOUSE_BUTTON4DOWN)
2643		*z = -1;
2644	else if (ms->button & MOUSE_BUTTON5DOWN)
2645		*z = 1;
2646	else
2647		*z = 0;
2648
2649	return (0);
2650}
2651
2652static void
2653proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
2654    int *x, int *y, int *z)
2655{
2656	static int butmap_versapad[8] = {
2657		0,
2658		MOUSE_BUTTON3DOWN,
2659		0,
2660		MOUSE_BUTTON3DOWN,
2661		MOUSE_BUTTON1DOWN,
2662		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
2663		MOUSE_BUTTON1DOWN,
2664		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
2665	};
2666	int c, x0, y0;
2667
2668	/* VersaPad PS/2 absolute mode message format
2669	 *
2670	 * [packet1]     7   6   5   4   3   2   1   0(LSB)
2671	 *  ipacket[0]:  1   1   0   A   1   L   T   R
2672	 *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
2673	 *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
2674	 *  ipacket[3]:  1   1   1   A   1   L   T   R
2675	 *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
2676	 *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
2677	 *
2678	 * [note]
2679	 *  R: right physical mouse button (1=on)
2680	 *  T: touch pad virtual button (1=tapping)
2681	 *  L: left physical mouse button (1=on)
2682	 *  A: position data is valid (1=valid)
2683	 *  H: horizontal data (12bit signed integer. H11 is sign bit.)
2684	 *  V: vertical data (12bit signed integer. V11 is sign bit.)
2685	 *  P: pressure data
2686	 *
2687	 * Tapping is mapped to MOUSE_BUTTON4.
2688	 */
2689	c = pb->ipacket[0];
2690	*x = *y = 0;
2691	ms->button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
2692	ms->button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
2693	if (c & MOUSE_PS2VERSA_IN_USE) {
2694		x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8);
2695		y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4);
2696		if (x0 & 0x800)
2697			x0 -= 0x1000;
2698		if (y0 & 0x800)
2699			y0 -= 0x1000;
2700		if (sc->flags & PSM_FLAGS_FINGERDOWN) {
2701			*x = sc->xold - x0;
2702			*y = y0 - sc->yold;
2703			if (*x < 0)	/* XXX */
2704				++*x;
2705			else if (*x)
2706				--*x;
2707			if (*y < 0)
2708				++*y;
2709			else if (*y)
2710				--*y;
2711		} else
2712			sc->flags |= PSM_FLAGS_FINGERDOWN;
2713		sc->xold = x0;
2714		sc->yold = y0;
2715	} else
2716		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
2717}
2718
2719static void
2720psmsoftintr(void *arg)
2721{
2722	/*
2723	 * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
2724	 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
2725	 */
2726	static int butmap[8] = {
2727		0,
2728		MOUSE_BUTTON1DOWN,
2729		MOUSE_BUTTON3DOWN,
2730		MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
2731		MOUSE_BUTTON2DOWN,
2732		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
2733		MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
2734		MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
2735	};
2736	register struct psm_softc *sc = arg;
2737	mousestatus_t ms;
2738	packetbuf_t *pb;
2739	int x, y, z, c, l, s;
2740
2741	getmicrouptime(&sc->lastsoftintr);
2742
2743	s = spltty();
2744
2745	do {
2746		pb = &sc->pqueue[sc->pqueue_start];
2747
2748		if (sc->mode.level == PSM_LEVEL_NATIVE)
2749			goto next_native;
2750
2751		c = pb->ipacket[0];
2752		/*
2753		 * A kludge for Kensington device!
2754		 * The MSB of the horizontal count appears to be stored in
2755		 * a strange place.
2756		 */
2757		if (sc->hw.model == MOUSE_MODEL_THINK)
2758			pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
2759
2760		/* ignore the overflow bits... */
2761		x = (c & MOUSE_PS2_XNEG) ?
2762		    pb->ipacket[1] - 256 : pb->ipacket[1];
2763		y = (c & MOUSE_PS2_YNEG) ?
2764		    pb->ipacket[2] - 256 : pb->ipacket[2];
2765		z = 0;
2766		ms.obutton = sc->button;	  /* previous button state */
2767		ms.button = butmap[c & MOUSE_PS2_BUTTONS];
2768		/* `tapping' action */
2769		if (sc->config & PSM_CONFIG_FORCETAP)
2770			ms.button |= ((c & MOUSE_PS2_TAP)) ?
2771			    0 : MOUSE_BUTTON4DOWN;
2772
2773		switch (sc->hw.model) {
2774
2775		case MOUSE_MODEL_EXPLORER:
2776			/*
2777			 *          b7 b6 b5 b4 b3 b2 b1 b0
2778			 * byte 1:  oy ox sy sx 1  M  R  L
2779			 * byte 2:  x  x  x  x  x  x  x  x
2780			 * byte 3:  y  y  y  y  y  y  y  y
2781			 * byte 4:  *  *  S2 S1 s  d2 d1 d0
2782			 *
2783			 * L, M, R, S1, S2: left, middle, right and side buttons
2784			 * s: wheel data sign bit
2785			 * d2-d0: wheel data
2786			 */
2787			z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) ?
2788			    (pb->ipacket[3] & 0x0f) - 16 :
2789			    (pb->ipacket[3] & 0x0f);
2790			ms.button |=
2791			    (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) ?
2792			    MOUSE_BUTTON4DOWN : 0;
2793			ms.button |=
2794			    (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) ?
2795			    MOUSE_BUTTON5DOWN : 0;
2796			break;
2797
2798		case MOUSE_MODEL_INTELLI:
2799		case MOUSE_MODEL_NET:
2800			/* wheel data is in the fourth byte */
2801			z = (char)pb->ipacket[3];
2802			/*
2803			 * XXX some mice may send 7 when there is no Z movement?			 */
2804			if ((z >= 7) || (z <= -7))
2805				z = 0;
2806			/* some compatible mice have additional buttons */
2807			ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) ?
2808			    MOUSE_BUTTON4DOWN : 0;
2809			ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) ?
2810			    MOUSE_BUTTON5DOWN : 0;
2811			break;
2812
2813		case MOUSE_MODEL_MOUSEMANPLUS:
2814			proc_mmanplus(sc, pb, &ms, &x, &y, &z);
2815			break;
2816
2817		case MOUSE_MODEL_GLIDEPOINT:
2818			/* `tapping' action */
2819			ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 :
2820			    MOUSE_BUTTON4DOWN;
2821			break;
2822
2823		case MOUSE_MODEL_NETSCROLL:
2824			/*
2825			 * three addtional bytes encode buttons and
2826			 * wheel events
2827			 */
2828			ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) ?
2829			    MOUSE_BUTTON4DOWN : 0;
2830			ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) ?
2831			    MOUSE_BUTTON5DOWN : 0;
2832			z = (pb->ipacket[3] & MOUSE_PS2_XNEG) ?
2833			    pb->ipacket[4] - 256 : pb->ipacket[4];
2834			break;
2835
2836		case MOUSE_MODEL_THINK:
2837			/* the fourth button state in the first byte */
2838			ms.button |= (c & MOUSE_PS2_TAP) ?
2839			    MOUSE_BUTTON4DOWN : 0;
2840			break;
2841
2842		case MOUSE_MODEL_VERSAPAD:
2843			proc_versapad(sc, pb, &ms, &x, &y, &z);
2844			c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
2845			    ((y < 0) ? MOUSE_PS2_YNEG : 0);
2846			break;
2847
2848		case MOUSE_MODEL_4D:
2849			/*
2850			 *          b7 b6 b5 b4 b3 b2 b1 b0
2851			 * byte 1:  s2 d2 s1 d1 1  M  R  L
2852			 * byte 2:  sx x  x  x  x  x  x  x
2853			 * byte 3:  sy y  y  y  y  y  y  y
2854			 *
2855			 * s1: wheel 1 direction
2856			 * d1: wheel 1 data
2857			 * s2: wheel 2 direction
2858			 * d2: wheel 2 data
2859			 */
2860			x = (pb->ipacket[1] & 0x80) ?
2861			    pb->ipacket[1] - 256 : pb->ipacket[1];
2862			y = (pb->ipacket[2] & 0x80) ?
2863			    pb->ipacket[2] - 256 : pb->ipacket[2];
2864			switch (c & MOUSE_4D_WHEELBITS) {
2865			case 0x10:
2866				z = 1;
2867				break;
2868			case 0x30:
2869				z = -1;
2870				break;
2871			case 0x40:	/* XXX 2nd wheel turning right */
2872				z = 2;
2873				break;
2874			case 0xc0:	/* XXX 2nd wheel turning left */
2875				z = -2;
2876				break;
2877			}
2878			break;
2879
2880		case MOUSE_MODEL_4DPLUS:
2881			if ((x < 16 - 256) && (y < 16 - 256)) {
2882				/*
2883				 *          b7 b6 b5 b4 b3 b2 b1 b0
2884				 * byte 1:  0  0  1  1  1  M  R  L
2885				 * byte 2:  0  0  0  0  1  0  0  0
2886				 * byte 3:  0  0  0  0  S  s  d1 d0
2887				 *
2888				 * L, M, R, S: left, middle, right,
2889				 *             and side buttons
2890				 * s: wheel data sign bit
2891				 * d1-d0: wheel data
2892				 */
2893				x = y = 0;
2894				if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
2895					ms.button |= MOUSE_BUTTON4DOWN;
2896				z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) ?
2897				    ((pb->ipacket[2] & 0x07) - 8) :
2898				    (pb->ipacket[2] & 0x07) ;
2899			} else {
2900				/* preserve previous button states */
2901				ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
2902			}
2903			break;
2904
2905		case MOUSE_MODEL_SYNAPTICS:
2906			if (proc_synaptics(sc, pb, &ms, &x, &y, &z) != 0)
2907				goto next;
2908			break;
2909
2910		case MOUSE_MODEL_GENERIC:
2911		default:
2912			break;
2913		}
2914
2915	/* scale values */
2916	if (sc->mode.accelfactor >= 1) {
2917		if (x != 0) {
2918			x = x * x / sc->mode.accelfactor;
2919			if (x == 0)
2920				x = 1;
2921			if (c & MOUSE_PS2_XNEG)
2922				x = -x;
2923		}
2924		if (y != 0) {
2925			y = y * y / sc->mode.accelfactor;
2926			if (y == 0)
2927				y = 1;
2928			if (c & MOUSE_PS2_YNEG)
2929				y = -y;
2930		}
2931	}
2932
2933	ms.dx = x;
2934	ms.dy = y;
2935	ms.dz = z;
2936	ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) |
2937	    (ms.obutton ^ ms.button);
2938
2939	pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket);
2940
2941	sc->status.flags |= ms.flags;
2942	sc->status.dx += ms.dx;
2943	sc->status.dy += ms.dy;
2944	sc->status.dz += ms.dz;
2945	sc->status.button = ms.button;
2946	sc->button = ms.button;
2947
2948next_native:
2949	sc->watchdog = FALSE;
2950
2951	/* queue data */
2952	if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) {
2953		l = imin(pb->inputbytes,
2954		    sizeof(sc->queue.buf) - sc->queue.tail);
2955		bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
2956		if (pb->inputbytes > l)
2957			bcopy(&pb->ipacket[l], &sc->queue.buf[0],
2958			    pb->inputbytes - l);
2959		sc->queue.tail = (sc->queue.tail + pb->inputbytes) %
2960		    sizeof(sc->queue.buf);
2961		sc->queue.count += pb->inputbytes;
2962	}
2963	pb->inputbytes = 0;
2964
2965next:
2966	if (++sc->pqueue_start >= PSM_PACKETQUEUE)
2967		sc->pqueue_start = 0;
2968	} while (sc->pqueue_start != sc->pqueue_end);
2969
2970	if (sc->state & PSM_ASLP) {
2971		sc->state &= ~PSM_ASLP;
2972		wakeup(sc);
2973	}
2974	selwakeuppri(&sc->rsel, PZERO);
2975	sc->state &= ~PSM_SOFTARMED;
2976	splx(s);
2977}
2978
2979static int
2980psmpoll(struct cdev *dev, int events, struct thread *td)
2981{
2982	struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
2983	int s;
2984	int revents = 0;
2985
2986	/* Return true if a mouse event available */
2987	s = spltty();
2988	if (events & (POLLIN | POLLRDNORM)) {
2989		if (sc->queue.count > 0)
2990			revents |= events & (POLLIN | POLLRDNORM);
2991		else
2992			selrecord(td, &sc->rsel);
2993	}
2994	splx(s);
2995
2996	return (revents);
2997}
2998
2999/* vendor/model specific routines */
3000
3001static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
3002{
3003	if (set_mouse_resolution(kbdc, res) != res)
3004		return (FALSE);
3005	if (set_mouse_scaling(kbdc, scale) &&
3006	    set_mouse_scaling(kbdc, scale) &&
3007	    set_mouse_scaling(kbdc, scale) &&
3008	    (get_mouse_status(kbdc, status, 0, 3) >= 3))
3009		return (TRUE);
3010	return (FALSE);
3011}
3012
3013static int
3014mouse_ext_command(KBDC kbdc, int command)
3015{
3016	int c;
3017
3018	c = (command >> 6) & 0x03;
3019	if (set_mouse_resolution(kbdc, c) != c)
3020		return (FALSE);
3021	c = (command >> 4) & 0x03;
3022	if (set_mouse_resolution(kbdc, c) != c)
3023		return (FALSE);
3024	c = (command >> 2) & 0x03;
3025	if (set_mouse_resolution(kbdc, c) != c)
3026		return (FALSE);
3027	c = (command >> 0) & 0x03;
3028	if (set_mouse_resolution(kbdc, c) != c)
3029		return (FALSE);
3030	return (TRUE);
3031}
3032
3033#ifdef notyet
3034/* Logitech MouseMan Cordless II */
3035static int
3036enable_lcordless(struct psm_softc *sc)
3037{
3038	int status[3];
3039	int ch;
3040
3041	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 2, status))
3042		return (FALSE);
3043	if (status[1] == PSMD_RES_HIGH)
3044		return (FALSE);
3045	ch = (status[0] & 0x07) - 1;	/* channel # */
3046	if ((ch <= 0) || (ch > 4))
3047		return (FALSE);
3048	/*
3049	 * status[1]: always one?
3050	 * status[2]: battery status? (0-100)
3051	 */
3052	return (TRUE);
3053}
3054#endif /* notyet */
3055
3056/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
3057static int
3058enable_groller(struct psm_softc *sc)
3059{
3060	int status[3];
3061
3062	/*
3063	 * The special sequence to enable the fourth button and the
3064	 * roller. Immediately after this sequence check status bytes.
3065	 * if the mouse is NetScroll, the second and the third bytes are
3066	 * '3' and 'D'.
3067	 */
3068
3069	/*
3070	 * If the mouse is an ordinary PS/2 mouse, the status bytes should
3071	 * look like the following.
3072	 *
3073	 * byte 1 bit 7 always 0
3074	 *        bit 6 stream mode (0)
3075	 *        bit 5 disabled (0)
3076	 *        bit 4 1:1 scaling (0)
3077	 *        bit 3 always 0
3078	 *        bit 0-2 button status
3079	 * byte 2 resolution (PSMD_RES_HIGH)
3080	 * byte 3 report rate (?)
3081	 */
3082
3083	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
3084		return (FALSE);
3085	if ((status[1] != '3') || (status[2] != 'D'))
3086		return (FALSE);
3087	/* FIXME: SmartScroll Mouse has 5 buttons! XXX */
3088	sc->hw.buttons = 4;
3089	return (TRUE);
3090}
3091
3092/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
3093static int
3094enable_gmouse(struct psm_softc *sc)
3095{
3096	int status[3];
3097
3098	/*
3099	 * The special sequence to enable the middle, "rubber" button.
3100	 * Immediately after this sequence check status bytes.
3101	 * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
3102	 * the second and the third bytes are '3' and 'U'.
3103	 * NOTE: NetMouse reports that it has three buttons although it has
3104	 * two buttons and a rubber button. NetMouse Pro and MIE Mouse
3105	 * say they have three buttons too and they do have a button on the
3106	 * side...
3107	 */
3108	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
3109		return (FALSE);
3110	if ((status[1] != '3') || (status[2] != 'U'))
3111		return (FALSE);
3112	return (TRUE);
3113}
3114
3115/* ALPS GlidePoint */
3116static int
3117enable_aglide(struct psm_softc *sc)
3118{
3119	int status[3];
3120
3121	/*
3122	 * The special sequence to obtain ALPS GlidePoint specific
3123	 * information. Immediately after this sequence, status bytes will
3124	 * contain something interesting.
3125	 * NOTE: ALPS produces several models of GlidePoint. Some of those
3126	 * do not respond to this sequence, thus, cannot be detected this way.
3127	 */
3128	if (set_mouse_sampling_rate(sc->kbdc, 100) != 100)
3129		return (FALSE);
3130	if (!mouse_id_proc1(sc->kbdc, PSMD_RES_LOW, 2, status))
3131		return (FALSE);
3132	if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
3133		return (FALSE);
3134	return (TRUE);
3135}
3136
3137/* Kensington ThinkingMouse/Trackball */
3138static int
3139enable_kmouse(struct psm_softc *sc)
3140{
3141	static u_char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
3142	KBDC kbdc = sc->kbdc;
3143	int status[3];
3144	int id1;
3145	int id2;
3146	int i;
3147
3148	id1 = get_aux_id(kbdc);
3149	if (set_mouse_sampling_rate(kbdc, 10) != 10)
3150		return (FALSE);
3151	/*
3152	 * The device is now in the native mode? It returns a different
3153	 * ID value...
3154	 */
3155	id2 = get_aux_id(kbdc);
3156	if ((id1 == id2) || (id2 != 2))
3157		return (FALSE);
3158
3159	if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
3160		return (FALSE);
3161#if PSM_DEBUG >= 2
3162	/* at this point, resolution is LOW, sampling rate is 10/sec */
3163	if (get_mouse_status(kbdc, status, 0, 3) < 3)
3164		return (FALSE);
3165#endif
3166
3167	/*
3168	 * The special sequence to enable the third and fourth buttons.
3169	 * Otherwise they behave like the first and second buttons.
3170	 */
3171	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3172		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3173			return (FALSE);
3174
3175	/*
3176	 * At this point, the device is using default resolution and
3177	 * sampling rate for the native mode.
3178	 */
3179	if (get_mouse_status(kbdc, status, 0, 3) < 3)
3180		return (FALSE);
3181	if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
3182		return (FALSE);
3183
3184	/* the device appears be enabled by this sequence, diable it for now */
3185	disable_aux_dev(kbdc);
3186	empty_aux_buffer(kbdc, 5);
3187
3188	return (TRUE);
3189}
3190
3191/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
3192static int
3193enable_mmanplus(struct psm_softc *sc)
3194{
3195	KBDC kbdc = sc->kbdc;
3196	int data[3];
3197
3198	/* the special sequence to enable the fourth button and the roller. */
3199	/*
3200	 * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
3201	 * must be called exactly three times since the last RESET command
3202	 * before this sequence. XXX
3203	 */
3204	if (!set_mouse_scaling(kbdc, 1))
3205		return (FALSE);
3206	if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
3207		return (FALSE);
3208	if (get_mouse_status(kbdc, data, 1, 3) < 3)
3209		return (FALSE);
3210
3211	/*
3212	 * PS2++ protocl, packet type 0
3213	 *
3214	 *          b7 b6 b5 b4 b3 b2 b1 b0
3215	 * byte 1:  *  1  p3 p2 1  *  *  *
3216	 * byte 2:  1  1  p1 p0 m1 m0 1  0
3217	 * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
3218	 *
3219	 * p3-p0: packet type: 0
3220	 * m7-m0: model ID: MouseMan+:0x50,
3221	 *		    FirstMouse+:0x51,
3222	 *		    ScrollPoint:0x58...
3223	 */
3224	/* check constant bits */
3225	if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
3226		return (FALSE);
3227	if ((data[1] & 0xc3) != 0xc2)
3228		return (FALSE);
3229	/* check d3-d0 in byte 2 */
3230	if (!MOUSE_PS2PLUS_CHECKBITS(data))
3231		return (FALSE);
3232	/* check p3-p0 */
3233	if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
3234		return (FALSE);
3235
3236	sc->hw.hwid &= 0x00ff;
3237	sc->hw.hwid |= data[2] << 8;	/* save model ID */
3238
3239	/*
3240	 * MouseMan+ (or FirstMouse+) is now in its native mode, in which
3241	 * the wheel and the fourth button events are encoded in the
3242	 * special data packet. The mouse may be put in the IntelliMouse mode
3243	 * if it is initialized by the IntelliMouse's method.
3244	 */
3245	return (TRUE);
3246}
3247
3248/* MS IntelliMouse Explorer */
3249static int
3250enable_msexplorer(struct psm_softc *sc)
3251{
3252	static u_char rate0[] = { 200, 100, 80, };
3253	static u_char rate1[] = { 200, 200, 80, };
3254	KBDC kbdc = sc->kbdc;
3255	int id;
3256	int i;
3257
3258	/*
3259	 * This is needed for at least A4Tech X-7xx mice - they do not go
3260	 * straight to Explorer mode, but need to be set to Intelli mode
3261	 * first.
3262	 */
3263	enable_msintelli(sc);
3264
3265	/* the special sequence to enable the extra buttons and the roller. */
3266	for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i)
3267		if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
3268			return (FALSE);
3269	/* the device will give the genuine ID only after the above sequence */
3270	id = get_aux_id(kbdc);
3271	if (id != PSM_EXPLORER_ID)
3272		return (FALSE);
3273
3274	sc->hw.hwid = id;
3275	sc->hw.buttons = 5;		/* IntelliMouse Explorer XXX */
3276
3277	/*
3278	 * XXX: this is a kludge to fool some KVM switch products
3279	 * which think they are clever enough to know the 4-byte IntelliMouse
3280	 * protocol, and assume any other protocols use 3-byte packets.
3281	 * They don't convey 4-byte data packets from the IntelliMouse Explorer
3282	 * correctly to the host computer because of this!
3283	 * The following sequence is actually IntelliMouse's "wake up"
3284	 * sequence; it will make the KVM think the mouse is IntelliMouse
3285	 * when it is in fact IntelliMouse Explorer.
3286	 */
3287	for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i)
3288		if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
3289			break;
3290	id = get_aux_id(kbdc);
3291
3292	return (TRUE);
3293}
3294
3295/* MS IntelliMouse */
3296static int
3297enable_msintelli(struct psm_softc *sc)
3298{
3299	/*
3300	 * Logitech MouseMan+ and FirstMouse+ will also respond to this
3301	 * probe routine and act like IntelliMouse.
3302	 */
3303
3304	static u_char rate[] = { 200, 100, 80, };
3305	KBDC kbdc = sc->kbdc;
3306	int id;
3307	int i;
3308
3309	/* the special sequence to enable the third button and the roller. */
3310	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3311		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3312			return (FALSE);
3313	/* the device will give the genuine ID only after the above sequence */
3314	id = get_aux_id(kbdc);
3315	if (id != PSM_INTELLI_ID)
3316		return (FALSE);
3317
3318	sc->hw.hwid = id;
3319	sc->hw.buttons = 3;
3320
3321	return (TRUE);
3322}
3323
3324/* A4 Tech 4D Mouse */
3325static int
3326enable_4dmouse(struct psm_softc *sc)
3327{
3328	/*
3329	 * Newer wheel mice from A4 Tech may use the 4D+ protocol.
3330	 */
3331
3332	static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
3333	KBDC kbdc = sc->kbdc;
3334	int id;
3335	int i;
3336
3337	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3338		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3339			return (FALSE);
3340	id = get_aux_id(kbdc);
3341	/*
3342	 * WinEasy 4D, 4 Way Scroll 4D: 6
3343	 * Cable-Free 4D: 8 (4DPLUS)
3344	 * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
3345	 */
3346	if (id != PSM_4DMOUSE_ID)
3347		return (FALSE);
3348
3349	sc->hw.hwid = id;
3350	sc->hw.buttons = 3;		/* XXX some 4D mice have 4? */
3351
3352	return (TRUE);
3353}
3354
3355/* A4 Tech 4D+ Mouse */
3356static int
3357enable_4dplus(struct psm_softc *sc)
3358{
3359	/*
3360	 * Newer wheel mice from A4 Tech seem to use this protocol.
3361	 * Older models are recognized as either 4D Mouse or IntelliMouse.
3362	 */
3363	KBDC kbdc = sc->kbdc;
3364	int id;
3365
3366	/*
3367	 * enable_4dmouse() already issued the following ID sequence...
3368	static u_char rate[] = { 200, 100, 80, 60, 40, 20 };
3369	int i;
3370
3371	for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i)
3372		if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
3373			return (FALSE);
3374	*/
3375
3376	id = get_aux_id(kbdc);
3377	switch (id) {
3378	case PSM_4DPLUS_ID:
3379		sc->hw.buttons = 4;
3380		break;
3381	case PSM_4DPLUS_RFSW35_ID:
3382		sc->hw.buttons = 3;
3383		break;
3384	default:
3385		return (FALSE);
3386	}
3387
3388	sc->hw.hwid = id;
3389
3390	return (TRUE);
3391}
3392
3393/* Synaptics Touchpad */
3394static int
3395enable_synaptics(struct psm_softc *sc)
3396{
3397	int status[3];
3398	KBDC kbdc;
3399
3400	if (!synaptics_support)
3401		return (FALSE);
3402
3403	/* Attach extra synaptics sysctl nodes under hw.psm.synaptics */
3404	sysctl_ctx_init(&sc->syninfo.sysctl_ctx);
3405	sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx,
3406	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD,
3407	    0, "Synaptics TouchPad");
3408
3409	/*
3410	 * synaptics_directional_scrolls - if non-zero, the directional
3411	 * pad scrolls, otherwise it registers as a middle-click.
3412	 */
3413	sc->syninfo.directional_scrolls = 1;
3414	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
3415	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
3416	    "directional_scrolls", CTLFLAG_RW,
3417	    &sc->syninfo.directional_scrolls, 0,
3418	    "directional pad scrolls (1=yes  0=3rd button)");
3419
3420	/*
3421	 * Synaptics_low_speed_threshold - the number of touchpad units
3422	 * below-which we go into low-speed tracking mode.
3423	 */
3424	sc->syninfo.low_speed_threshold = 20;
3425	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
3426	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
3427	    "low_speed_threshold", CTLFLAG_RW,
3428	    &sc->syninfo.low_speed_threshold, 0,
3429	    "threshold between low and hi speed positioning");
3430
3431	/*
3432	 * Synaptics_min_movement - the number of touchpad units below
3433	 * which we ignore altogether.
3434	 */
3435	sc->syninfo.min_movement = 2;
3436	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
3437	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
3438	    "min_movement", CTLFLAG_RW,
3439	    &sc->syninfo.min_movement, 0,
3440	    "ignore touchpad movements less than this");
3441
3442	/*
3443	 * Synaptics_squelch_level - level at which we squelch movement
3444	 * packets.
3445	 *
3446	 * This effectively sends 1 out of every synaptics_squelch_level
3447	 * packets when * running in low-speed mode.
3448	 */
3449	sc->syninfo.squelch_level=3;
3450	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
3451	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
3452	    "squelch_level", CTLFLAG_RW,
3453	    &sc->syninfo.squelch_level, 0,
3454	    "squelch level for synaptics touchpads");
3455
3456	kbdc = sc->kbdc;
3457	disable_aux_dev(kbdc);
3458	sc->hw.buttons = 3;
3459	sc->squelch = 0;
3460
3461	/* Just to be on the safe side */
3462	set_mouse_scaling(kbdc, 1);
3463
3464	/* Identify the Touchpad version */
3465	if (mouse_ext_command(kbdc, 0) == 0)
3466		return (FALSE);
3467	if (get_mouse_status(kbdc, status, 0, 3) != 3)
3468		return (FALSE);
3469	if (status[1] != 0x47)
3470		return (FALSE);
3471
3472	sc->synhw.infoMinor = status[0];
3473	sc->synhw.infoMajor = status[2] & 0x0f;
3474
3475	if (verbose >= 2)
3476		printf("Synaptics Touchpad v%d.%d\n", sc->synhw.infoMajor,
3477		    sc->synhw.infoMinor);
3478
3479	if (sc->synhw.infoMajor < 4) {
3480		printf("  Unsupported (pre-v4) Touchpad detected\n");
3481		return (FALSE);
3482	}
3483
3484	/* Get the Touchpad model information */
3485	if (mouse_ext_command(kbdc, 3) == 0)
3486		return (FALSE);
3487	if (get_mouse_status(kbdc, status, 0, 3) != 3)
3488		return (FALSE);
3489	if ((status[1] & 0x01) != 0) {
3490		printf("  Failed to read model information\n");
3491		return (FALSE);
3492	}
3493
3494	sc->synhw.infoRot180   = (status[0] & 0x80) >> 7;
3495	sc->synhw.infoPortrait = (status[0] & 0x40) >> 6;
3496	sc->synhw.infoSensor   =  status[0] & 0x3f;
3497	sc->synhw.infoHardware = (status[1] & 0xfe) >> 1;
3498	sc->synhw.infoNewAbs   = (status[2] & 0x80) >> 7;
3499	sc->synhw.capPen       = (status[2] & 0x40) >> 6;
3500	sc->synhw.infoSimplC   = (status[2] & 0x20) >> 5;
3501	sc->synhw.infoGeometry =  status[2] & 0x0f;
3502
3503	if (verbose >= 2) {
3504		printf("  Model information:\n");
3505		printf("   infoRot180: %d\n", sc->synhw.infoRot180);
3506		printf("   infoPortrait: %d\n", sc->synhw.infoPortrait);
3507		printf("   infoSensor: %d\n", sc->synhw.infoSensor);
3508		printf("   infoHardware: %d\n", sc->synhw.infoHardware);
3509		printf("   infoNewAbs: %d\n", sc->synhw.infoNewAbs);
3510		printf("   capPen: %d\n", sc->synhw.capPen);
3511		printf("   infoSimplC: %d\n", sc->synhw.infoSimplC);
3512		printf("   infoGeometry: %d\n", sc->synhw.infoGeometry);
3513	}
3514
3515	/* Read the extended capability bits */
3516	if (mouse_ext_command(kbdc, 2) == 0)
3517		return (FALSE);
3518	if (get_mouse_status(kbdc, status, 0, 3) != 3)
3519		return (FALSE);
3520	if (status[1] != 0x47) {
3521		printf("  Failed to read extended capability bits\n");
3522		return (FALSE);
3523	}
3524
3525	/* Set the different capabilities when they exist */
3526	if ((status[0] & 0x80) >> 7) {
3527		sc->synhw.capExtended    = (status[0] & 0x80) >> 7;
3528		sc->synhw.capPassthrough = (status[2] & 0x80) >> 7;
3529		sc->synhw.capSleep       = (status[2] & 0x10) >> 4;
3530		sc->synhw.capFourButtons = (status[2] & 0x08) >> 3;
3531		sc->synhw.capMultiFinger = (status[2] & 0x02) >> 1;
3532		sc->synhw.capPalmDetect  = (status[2] & 0x01);
3533
3534		if (verbose >= 2) {
3535			printf("  Extended capabilities:\n");
3536			printf("   capExtended: %d\n", sc->synhw.capExtended);
3537			printf("   capPassthrough: %d\n",
3538			    sc->synhw.capPassthrough);
3539			printf("   capSleep: %d\n", sc->synhw.capSleep);
3540			printf("   capFourButtons: %d\n",
3541			    sc->synhw.capFourButtons);
3542			printf("   capMultiFinger: %d\n",
3543			    sc->synhw.capMultiFinger);
3544			printf("   capPalmDetect: %d\n",
3545			    sc->synhw.capPalmDetect);
3546		}
3547
3548		/*
3549		 * if we have bits set in status[0] & 0x70 - then we can load
3550		 * more information about buttons using query 0x09
3551		 */
3552		if (status[0] & 0x70) {
3553			if (mouse_ext_command(kbdc, 0x09) == 0)
3554				return (FALSE);
3555			if (get_mouse_status(kbdc, status, 0, 3) != 3)
3556				return (FALSE);
3557			sc->hw.buttons = ((status[1] & 0xf0) >> 4) + 3;
3558			if (verbose >= 2)
3559				printf("  Additional Buttons: %d\n",
3560				    sc->hw.buttons -3);
3561		}
3562	} else {
3563		sc->synhw.capExtended = 0;
3564
3565		if (verbose >= 2)
3566			printf("  No extended capabilities\n");
3567	}
3568
3569	/*
3570	 * Read the mode byte
3571	 *
3572	 * XXX: Note the Synaptics documentation also defines the first
3573	 * byte of the response to this query to be a constant 0x3b, this
3574	 * does not appear to be true for Touchpads with guest devices.
3575	 */
3576	if (mouse_ext_command(kbdc, 1) == 0)
3577		return (FALSE);
3578	if (get_mouse_status(kbdc, status, 0, 3) != 3)
3579		return (FALSE);
3580	if (status[1] != 0x47) {
3581		printf("  Failed to read mode byte\n");
3582		return (FALSE);
3583	}
3584
3585	/* Set the mode byte -- request wmode where available */
3586	if (sc->synhw.capExtended)
3587		mouse_ext_command(kbdc, 0xc1);
3588	else
3589		mouse_ext_command(kbdc, 0xc0);
3590
3591	/* Reset the sampling rate */
3592	set_mouse_sampling_rate(kbdc, 20);
3593
3594	/*
3595	 * Report the correct number of buttons
3596	 *
3597	 * XXX: I'm not sure this is used anywhere.
3598	 */
3599	if (sc->synhw.capExtended && sc->synhw.capFourButtons)
3600		sc->hw.buttons = 4;
3601
3602	return (TRUE);
3603}
3604
3605/* Interlink electronics VersaPad */
3606static int
3607enable_versapad(struct psm_softc *sc)
3608{
3609	KBDC kbdc = sc->kbdc;
3610	int data[3];
3611
3612	set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
3613	set_mouse_sampling_rate(kbdc, 100);		/* set rate 100 */
3614	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
3615	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
3616	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
3617	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
3618	if (get_mouse_status(kbdc, data, 0, 3) < 3)	/* get status */
3619		return (FALSE);
3620	if (data[2] != 0xa || data[1] != 0 )	/* rate == 0xa && res. == 0 */
3621		return (FALSE);
3622	set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
3623
3624	sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
3625
3626	return (TRUE);				/* PS/2 absolute mode */
3627}
3628
3629/*
3630 * Return true if 'now' is earlier than (start + (secs.usecs)).
3631 * Now may be NULL and the function will fetch the current time from
3632 * getmicrouptime(), or a cached 'now' can be passed in.
3633 * All values should be numbers derived from getmicrouptime().
3634 */
3635static int
3636timeelapsed(start, secs, usecs, now)
3637	const struct timeval *start, *now;
3638	int secs, usecs;
3639{
3640	struct timeval snow, tv;
3641
3642	/* if there is no 'now' passed in, the get it as a convience. */
3643	if (now == NULL) {
3644		getmicrouptime(&snow);
3645		now = &snow;
3646	}
3647
3648	tv.tv_sec = secs;
3649	tv.tv_usec = usecs;
3650	timevaladd(&tv, start);
3651	return (timevalcmp(&tv, now, <));
3652}
3653
3654static int
3655psmresume(device_t dev)
3656{
3657	struct psm_softc *sc = device_get_softc(dev);
3658	int unit = device_get_unit(dev);
3659	int err;
3660
3661	VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit));
3662
3663	if (!(sc->config & PSM_CONFIG_HOOKRESUME))
3664		return (0);
3665
3666	err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND);
3667
3668	if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
3669		/*
3670		 * Release the blocked process; it must be notified that
3671		 * the device cannot be accessed anymore.
3672		 */
3673		sc->state &= ~PSM_ASLP;
3674		wakeup(sc);
3675	}
3676
3677	VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit));
3678
3679	return (err);
3680}
3681
3682DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
3683
3684#ifdef DEV_ISA
3685
3686/*
3687 * This sucks up assignments from PNPBIOS and ACPI.
3688 */
3689
3690/*
3691 * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may
3692 * appear BEFORE the AT keyboard controller.  As the PS/2 mouse device
3693 * can be probed and attached only after the AT keyboard controller is
3694 * attached, we shall quietly reserve the IRQ resource for later use.
3695 * If the PS/2 mouse device is reported to us AFTER the keyboard controller,
3696 * copy the IRQ resource to the PS/2 mouse device instance hanging
3697 * under the keyboard controller, then probe and attach it.
3698 */
3699
3700static	devclass_t			psmcpnp_devclass;
3701
3702static	device_probe_t			psmcpnp_probe;
3703static	device_attach_t			psmcpnp_attach;
3704
3705static device_method_t psmcpnp_methods[] = {
3706	DEVMETHOD(device_probe,		psmcpnp_probe),
3707	DEVMETHOD(device_attach,	psmcpnp_attach),
3708
3709	{ 0, 0 }
3710};
3711
3712static driver_t psmcpnp_driver = {
3713	PSMCPNP_DRIVER_NAME,
3714	psmcpnp_methods,
3715	1,			/* no softc */
3716};
3717
3718static struct isa_pnp_id psmcpnp_ids[] = {
3719	{ 0x030fd041, "PS/2 mouse port" },		/* PNP0F03 */
3720	{ 0x0e0fd041, "PS/2 mouse port" },		/* PNP0F0E */
3721	{ 0x120fd041, "PS/2 mouse port" },		/* PNP0F12 */
3722	{ 0x130fd041, "PS/2 mouse port" },		/* PNP0F13 */
3723	{ 0x1303d041, "PS/2 port" },			/* PNP0313, XXX */
3724	{ 0x02002e4f, "Dell PS/2 mouse port" },		/* Lat. X200, Dell */
3725	{ 0x0002a906, "ALPS Glide Point" },		/* ALPS Glide Point */
3726	{ 0x80374d24, "IBM PS/2 mouse port" },		/* IBM3780, ThinkPad */
3727	{ 0x81374d24, "IBM PS/2 mouse port" },		/* IBM3781, ThinkPad */
3728	{ 0x0190d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9001, Vaio */
3729	{ 0x0290d94d, "SONY VAIO PS/2 mouse port"},	/* SNY9002, Vaio */
3730	{ 0x0390d94d, "SONY VAIO PS/2 mouse port"},	/* SNY9003, Vaio */
3731	{ 0x0490d94d, "SONY VAIO PS/2 mouse port"},     /* SNY9004, Vaio */
3732	{ 0 }
3733};
3734
3735static int
3736create_a_copy(device_t atkbdc, device_t me)
3737{
3738	device_t psm;
3739	u_long irq;
3740
3741	/* find the PS/2 mouse device instance under the keyboard controller */
3742	psm = device_find_child(atkbdc, PSM_DRIVER_NAME,
3743	    device_get_unit(atkbdc));
3744	if (psm == NULL)
3745		return (ENXIO);
3746	if (device_get_state(psm) != DS_NOTPRESENT)
3747		return (0);
3748
3749	/* move our resource to the found device */
3750	irq = bus_get_resource_start(me, SYS_RES_IRQ, 0);
3751	bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1);
3752
3753	/* ...then probe and attach it */
3754	return (device_probe_and_attach(psm));
3755}
3756
3757static int
3758psmcpnp_probe(device_t dev)
3759{
3760	struct resource *res;
3761	u_long irq;
3762	int rid;
3763
3764	if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
3765		return (ENXIO);
3766
3767	/*
3768	 * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
3769	 * to the PS/2 mouse device node. But, some buggy PnP BIOS
3770	 * declares the PS/2 mouse device node without an IRQ resource!
3771	 * If this happens, we shall refer to device hints.
3772	 * If we still don't find it there, use a hardcoded value... XXX
3773	 */
3774	rid = 0;
3775	irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
3776	if (irq <= 0) {
3777		if (resource_long_value(PSM_DRIVER_NAME,
3778		    device_get_unit(dev),"irq", &irq) != 0)
3779			irq = 12;	/* XXX */
3780		device_printf(dev, "irq resource info is missing; "
3781		    "assuming irq %ld\n", irq);
3782		bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
3783	}
3784	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE);
3785	bus_release_resource(dev, SYS_RES_IRQ, rid, res);
3786
3787	/* keep quiet */
3788	if (!bootverbose)
3789		device_quiet(dev);
3790
3791	return ((res == NULL) ? ENXIO : 0);
3792}
3793
3794static int
3795psmcpnp_attach(device_t dev)
3796{
3797	device_t atkbdc;
3798	int rid;
3799
3800	/* find the keyboard controller, which may be on acpi* or isa* bus */
3801	atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME),
3802	    device_get_unit(dev));
3803	if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED))
3804		create_a_copy(atkbdc, dev);
3805	else {
3806		/*
3807		 * If we don't have the AT keyboard controller yet,
3808		 * just reserve the IRQ for later use...
3809		 * (See psmidentify() above.)
3810		 */
3811		rid = 0;
3812		bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE);
3813	}
3814
3815	return (0);
3816}
3817
3818DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0);
3819DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0);
3820
3821#endif /* DEV_ISA */
3822