psm.c revision 70834
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 * $FreeBSD: head/sys/dev/atkbdc/psm.c 70834 2001-01-09 04:33:49Z wollman $
24 */
25
26/*
27 *  Ported to 386bsd Oct 17, 1992
28 *  Sandi Donno, Computer Science, University of Cape Town, South Africa
29 *  Please send bug reports to sandi@cs.uct.ac.za
30 *
31 *  Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca -
32 *  although I was only partially successful in getting the alpha release
33 *  of his "driver for the Logitech and ATI Inport Bus mice for use with
34 *  386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
35 *  found his code to be an invaluable reference when porting this driver
36 *  to 386bsd.
37 *
38 *  Further modifications for latest 386BSD+patchkit and port to NetBSD,
39 *  Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993
40 *
41 *  Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
42 *  Andrew Herbert - 12 June 1993
43 *
44 *  Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu>
45 *  - 13 June 1993
46 *
47 *  Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp>
48 *  - 24 October 1993
49 *
50 *  Hardware access routines and probe logic rewritten by
51 *  Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp>
52 *  - 3, 14, 22 October 1996.
53 *  - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'...
54 *  - 14, 30 November 1996. Uses `kbdio.c'.
55 *  - 13 December 1996. Uses queuing version of `kbdio.c'.
56 *  - January/February 1997. Tweaked probe logic for
57 *    HiNote UltraII/Latitude/Armada laptops.
58 *  - 30 July 1997. Added APM support.
59 *  - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX).
60 *    Improved sync check logic.
61 *    Vendor specific support routines.
62 */
63
64#include "opt_psm.h"
65
66#include <sys/param.h>
67#include <sys/systm.h>
68#include <sys/kernel.h>
69#include <sys/module.h>
70#include <sys/bus.h>
71#include <sys/conf.h>
72#include <sys/poll.h>
73#include <sys/syslog.h>
74#include <machine/bus.h>
75#include <sys/rman.h>
76#include <sys/selinfo.h>
77#include <sys/uio.h>
78
79#include <machine/limits.h>
80#include <sys/mouse.h>
81#include <machine/resource.h>
82
83#include <isa/isavar.h>
84#include <dev/kbd/atkbdcreg.h>
85
86/*
87 * Driver specific options: the following options may be set by
88 * `options' statements in the kernel configuration file.
89 */
90
91/* debugging */
92#ifndef PSM_DEBUG
93#define PSM_DEBUG	0	/* logging: 0: none, 1: brief, 2: verbose */
94#endif
95
96/* end of driver specific options */
97
98/* input queue */
99#define PSM_BUFSIZE		960
100#define PSM_SMALLBUFSIZE	240
101
102/* operation levels */
103#define PSM_LEVEL_BASE		0
104#define PSM_LEVEL_STANDARD	1
105#define PSM_LEVEL_NATIVE	2
106#define PSM_LEVEL_MIN		PSM_LEVEL_BASE
107#define PSM_LEVEL_MAX		PSM_LEVEL_NATIVE
108
109/* Logitech PS2++ protocol */
110#define MOUSE_PS2PLUS_CHECKBITS(b)	\
111				((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
112#define MOUSE_PS2PLUS_PACKET_TYPE(b)	\
113				(((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
114
115/* some macros */
116#define PSM_UNIT(dev)		(minor(dev) >> 1)
117#define PSM_NBLOCKIO(dev)	(minor(dev) & 1)
118#define PSM_MKMINOR(unit,block)	(((unit) << 1) | ((block) ? 0:1))
119
120#ifndef max
121#define max(x,y)		((x) > (y) ? (x) : (y))
122#endif
123#ifndef min
124#define min(x,y)		((x) < (y) ? (x) : (y))
125#endif
126
127#define abs(x)			(((x) < 0) ? -(x) : (x))
128
129/* ring buffer */
130typedef struct ringbuf {
131    int           count;	/* # of valid elements in the buffer */
132    int           head;		/* head pointer */
133    int           tail;		/* tail poiner */
134    unsigned char buf[PSM_BUFSIZE];
135} ringbuf_t;
136
137/* driver control block */
138struct psm_softc {		/* Driver status information */
139    struct selinfo rsel;	/* Process selecting for Input */
140    unsigned char state;	/* Mouse driver state */
141    int           config;	/* driver configuration flags */
142    int           flags;	/* other flags */
143    KBDC          kbdc;		/* handle to access the keyboard controller */
144    struct resource *intr;	/* IRQ resource */
145    void	  *ih;		/* interrupt handle */
146    mousehw_t     hw;		/* hardware information */
147    mousemode_t   mode;		/* operation mode */
148    mousemode_t   dflt_mode;	/* default operation mode */
149    mousestatus_t status;	/* accumulated mouse movement */
150    ringbuf_t     queue;	/* mouse status queue */
151    unsigned char ipacket[16];	/* interim input buffer */
152    int           inputbytes;	/* # of bytes in the input buffer */
153    int           button;	/* the latest button state */
154    int		  xold;	/* previous absolute X position */
155    int		  yold;	/* previous absolute Y position */
156    int		  watchdog;	/* watchdog timer flag */
157    struct callout_handle callout;	/* watchdog timer call out */
158    dev_t	  dev;
159    dev_t	  bdev;
160};
161devclass_t psm_devclass;
162#define PSM_SOFTC(unit)	((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
163
164/* driver state flags (state) */
165#define PSM_VALID		0x80
166#define PSM_OPEN		1	/* Device is open */
167#define PSM_ASLP		2	/* Waiting for mouse data */
168
169/* driver configuration flags (config) */
170#define PSM_CONFIG_RESOLUTION	0x000f	/* resolution */
171#define PSM_CONFIG_ACCEL	0x00f0  /* acceleration factor */
172#define PSM_CONFIG_NOCHECKSYNC	0x0100  /* disable sync. test */
173#define PSM_CONFIG_NOIDPROBE	0x0200  /* disable mouse model probe */
174#define PSM_CONFIG_NORESET	0x0400  /* don't reset the mouse */
175#define PSM_CONFIG_FORCETAP	0x0800  /* assume `tap' action exists */
176#define PSM_CONFIG_IGNPORTERROR	0x1000  /* ignore error in aux port test */
177#define PSM_CONFIG_HOOKRESUME	0x2000	/* hook the system resume event */
178#define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */
179#define PSM_CONFIG_SYNCHACK	0x8000 /* enable `out-of-sync' hack */
180
181#define PSM_CONFIG_FLAGS	(PSM_CONFIG_RESOLUTION 		\
182				    | PSM_CONFIG_ACCEL		\
183				    | PSM_CONFIG_NOCHECKSYNC	\
184				    | PSM_CONFIG_SYNCHACK	\
185				    | PSM_CONFIG_NOIDPROBE	\
186				    | PSM_CONFIG_NORESET	\
187				    | PSM_CONFIG_FORCETAP	\
188				    | PSM_CONFIG_IGNPORTERROR	\
189				    | PSM_CONFIG_HOOKRESUME	\
190				    | PSM_CONFIG_INITAFTERSUSPEND)
191
192/* other flags (flags) */
193#define PSM_FLAGS_FINGERDOWN	0x0001 /* VersaPad finger down */
194
195/* for backward compatibility */
196#define OLD_MOUSE_GETHWINFO	_IOR('M', 1, old_mousehw_t)
197#define OLD_MOUSE_GETMODE	_IOR('M', 2, old_mousemode_t)
198#define OLD_MOUSE_SETMODE	_IOW('M', 3, old_mousemode_t)
199
200typedef struct old_mousehw {
201    int buttons;
202    int iftype;
203    int type;
204    int hwid;
205} old_mousehw_t;
206
207typedef struct old_mousemode {
208    int protocol;
209    int rate;
210    int resolution;
211    int accelfactor;
212} old_mousemode_t;
213
214/* packet formatting function */
215typedef int packetfunc_t __P((struct psm_softc *, unsigned char *,
216			      int *, int, mousestatus_t *));
217
218/* function prototypes */
219static int psmprobe __P((device_t));
220static int psmattach __P((device_t));
221static int psmdetach __P((device_t));
222static int psmresume __P((device_t));
223
224static d_open_t psmopen;
225static d_close_t psmclose;
226static d_read_t psmread;
227static d_ioctl_t psmioctl;
228static d_poll_t psmpoll;
229
230static int enable_aux_dev __P((KBDC));
231static int disable_aux_dev __P((KBDC));
232static int get_mouse_status __P((KBDC, int *, int, int));
233static int get_aux_id __P((KBDC));
234static int set_mouse_sampling_rate __P((KBDC, int));
235static int set_mouse_scaling __P((KBDC, int));
236static int set_mouse_resolution __P((KBDC, int));
237static int set_mouse_mode __P((KBDC));
238static int get_mouse_buttons __P((KBDC));
239static int is_a_mouse __P((int));
240static void recover_from_error __P((KBDC));
241static int restore_controller __P((KBDC, int));
242static int reinitialize __P((int, mousemode_t *));
243static int doopen __P((int, int));
244static char *model_name __P((int));
245static void psmintr __P((void *));
246static void psmtimeout __P((void *));
247
248/* vendor specific features */
249typedef int probefunc_t __P((struct psm_softc *));
250
251static int mouse_id_proc1 __P((KBDC, int, int, int *));
252static int mouse_ext_command __P((KBDC, int));
253static probefunc_t enable_groller;
254static probefunc_t enable_gmouse;
255static probefunc_t enable_aglide;
256static probefunc_t enable_kmouse;
257static probefunc_t enable_msexplorer;
258static probefunc_t enable_msintelli;
259static probefunc_t enable_4dmouse;
260static probefunc_t enable_4dplus;
261static probefunc_t enable_mmanplus;
262static probefunc_t enable_versapad;
263static int tame_mouse __P((struct psm_softc *, mousestatus_t *, unsigned char *));
264
265static struct {
266    int                 model;
267    unsigned char	syncmask;
268    int 		packetsize;
269    probefunc_t 	*probefunc;
270} vendortype[] = {
271    /*
272     * WARNING: the order of probe is very important.  Don't mess it
273     * unless you know what you are doing.
274     */
275    { MOUSE_MODEL_NET,			/* Genius NetMouse */
276      0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse, },
277    { MOUSE_MODEL_NETSCROLL,		/* Genius NetScroll */
278      0xc8, 6, enable_groller, },
279    { MOUSE_MODEL_MOUSEMANPLUS,		/* Logitech MouseMan+ */
280      0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus, },
281    { MOUSE_MODEL_EXPLORER,		/* Microsoft IntelliMouse Explorer */
282      0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer, },
283    { MOUSE_MODEL_4D,			/* A4 Tech 4D Mouse */
284      0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse, },
285    { MOUSE_MODEL_4DPLUS,		/* A4 Tech 4D+ Mouse */
286      0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus, },
287    { MOUSE_MODEL_INTELLI,		/* Microsoft IntelliMouse */
288      0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli, },
289    { MOUSE_MODEL_GLIDEPOINT,		/* ALPS GlidePoint */
290      0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
291    { MOUSE_MODEL_THINK,		/* Kensignton ThinkingMouse */
292      0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, },
293    { MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
294      0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, },
295    { MOUSE_MODEL_GENERIC,
296      0xc0, MOUSE_PS2_PACKETSIZE, NULL, },
297};
298#define GENERIC_MOUSE_ENTRY	((sizeof(vendortype) / sizeof(*vendortype)) - 1)
299
300/* device driver declarateion */
301static device_method_t psm_methods[] = {
302	/* Device interface */
303	DEVMETHOD(device_probe,		psmprobe),
304	DEVMETHOD(device_attach,	psmattach),
305	DEVMETHOD(device_detach,	psmdetach),
306	DEVMETHOD(device_resume,	psmresume),
307
308	{ 0, 0 }
309};
310
311static driver_t psm_driver = {
312    "psm",
313    psm_methods,
314    sizeof(struct psm_softc),
315};
316
317#if notyet
318static struct isa_pnp_id psm_ids[] = {
319    { 0x130fd041, "PS/2 mouse port" },			/* PNP0F13 */
320    { 0x1303d041, "PS/2 port" },			/* PNP0313, XXX */
321    { 0 }
322};
323#endif
324
325#define CDEV_MAJOR        21
326
327static struct cdevsw psm_cdevsw = {
328	/* open */	psmopen,
329	/* close */	psmclose,
330	/* read */	psmread,
331	/* write */	nowrite,
332	/* ioctl */	psmioctl,
333	/* poll */	psmpoll,
334	/* mmap */	nommap,
335	/* strategy */	nostrategy,
336	/* name */	"psm",
337	/* maj */	CDEV_MAJOR,
338	/* dump */	nodump,
339	/* psize */	nopsize,
340	/* flags */	0,
341	/* bmaj */	-1
342};
343
344/* debug message level */
345static int verbose = PSM_DEBUG;
346
347/* device I/O routines */
348static int
349enable_aux_dev(KBDC kbdc)
350{
351    int res;
352
353    res = send_aux_command(kbdc, PSMC_ENABLE_DEV);
354    if (verbose >= 2)
355        log(LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res);
356
357    return (res == PSM_ACK);
358}
359
360static int
361disable_aux_dev(KBDC kbdc)
362{
363    int res;
364
365    res = send_aux_command(kbdc, PSMC_DISABLE_DEV);
366    if (verbose >= 2)
367        log(LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res);
368
369    return (res == PSM_ACK);
370}
371
372static int
373get_mouse_status(KBDC kbdc, int *status, int flag, int len)
374{
375    int cmd;
376    int res;
377    int i;
378
379    switch (flag) {
380    case 0:
381    default:
382	cmd = PSMC_SEND_DEV_STATUS;
383	break;
384    case 1:
385	cmd = PSMC_SEND_DEV_DATA;
386	break;
387    }
388    empty_aux_buffer(kbdc, 5);
389    res = send_aux_command(kbdc, cmd);
390    if (verbose >= 2)
391        log(LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n",
392	    (flag == 1) ? "DATA" : "STATUS", res);
393    if (res != PSM_ACK)
394        return 0;
395
396    for (i = 0; i < len; ++i) {
397        status[i] = read_aux_data(kbdc);
398	if (status[i] < 0)
399	    break;
400    }
401
402    if (verbose) {
403        log(LOG_DEBUG, "psm: %s %02x %02x %02x\n",
404            (flag == 1) ? "data" : "status", status[0], status[1], status[2]);
405    }
406
407    return i;
408}
409
410static int
411get_aux_id(KBDC kbdc)
412{
413    int res;
414    int id;
415
416    empty_aux_buffer(kbdc, 5);
417    res = send_aux_command(kbdc, PSMC_SEND_DEV_ID);
418    if (verbose >= 2)
419        log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res);
420    if (res != PSM_ACK)
421	return (-1);
422
423    /* 10ms delay */
424    DELAY(10000);
425
426    id = read_aux_data(kbdc);
427    if (verbose >= 2)
428        log(LOG_DEBUG, "psm: device ID: %04x\n", id);
429
430    return id;
431}
432
433static int
434set_mouse_sampling_rate(KBDC kbdc, int rate)
435{
436    int res;
437
438    res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate);
439    if (verbose >= 2)
440        log(LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res);
441
442    return ((res == PSM_ACK) ? rate : -1);
443}
444
445static int
446set_mouse_scaling(KBDC kbdc, int scale)
447{
448    int res;
449
450    switch (scale) {
451    case 1:
452    default:
453	scale = PSMC_SET_SCALING11;
454	break;
455    case 2:
456	scale = PSMC_SET_SCALING21;
457	break;
458    }
459    res = send_aux_command(kbdc, scale);
460    if (verbose >= 2)
461        log(LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n",
462	    (scale == PSMC_SET_SCALING21) ? "21" : "11", res);
463
464    return (res == PSM_ACK);
465}
466
467/* `val' must be 0 through PSMD_MAX_RESOLUTION */
468static int
469set_mouse_resolution(KBDC kbdc, int val)
470{
471    int res;
472
473    res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val);
474    if (verbose >= 2)
475        log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res);
476
477    return ((res == PSM_ACK) ? val : -1);
478}
479
480/*
481 * NOTE: once `set_mouse_mode()' is called, the mouse device must be
482 * re-enabled by calling `enable_aux_dev()'
483 */
484static int
485set_mouse_mode(KBDC kbdc)
486{
487    int res;
488
489    res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE);
490    if (verbose >= 2)
491        log(LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res);
492
493    return (res == PSM_ACK);
494}
495
496static int
497get_mouse_buttons(KBDC kbdc)
498{
499    int c = 2;		/* assume two buttons by default */
500    int status[3];
501
502    /*
503     * NOTE: a special sequence to obtain Logitech Mouse specific
504     * information: set resolution to 25 ppi, set scaling to 1:1, set
505     * scaling to 1:1, set scaling to 1:1. Then the second byte of the
506     * mouse status bytes is the number of available buttons.
507     * Some manufactures also support this sequence.
508     */
509    if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
510        return c;
511    if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1)
512        && set_mouse_scaling(kbdc, 1)
513	&& (get_mouse_status(kbdc, status, 0, 3) >= 3)) {
514        if (status[1] != 0)
515            return status[1];
516    }
517    return c;
518}
519
520/* misc subroutines */
521/*
522 * Someday, I will get the complete list of valid pointing devices and
523 * their IDs... XXX
524 */
525static int
526is_a_mouse(int id)
527{
528#if 0
529    static int valid_ids[] = {
530        PSM_MOUSE_ID,		/* mouse */
531        PSM_BALLPOINT_ID,	/* ballpoint device */
532        PSM_INTELLI_ID,		/* Intellimouse */
533        PSM_EXPLORER_ID,	/* Intellimouse Explorer */
534        -1			/* end of table */
535    };
536    int i;
537
538    for (i = 0; valid_ids[i] >= 0; ++i)
539        if (valid_ids[i] == id)
540            return TRUE;
541    return FALSE;
542#else
543    return TRUE;
544#endif
545}
546
547static char *
548model_name(int model)
549{
550    static struct {
551	int model_code;
552	char *model_name;
553    } models[] = {
554        { MOUSE_MODEL_NETSCROLL,	"NetScroll" },
555        { MOUSE_MODEL_NET,		"NetMouse/NetScroll Optical" },
556        { MOUSE_MODEL_GLIDEPOINT,	"GlidePoint" },
557        { MOUSE_MODEL_THINK,		"ThinkingMouse" },
558        { MOUSE_MODEL_INTELLI,		"IntelliMouse" },
559        { MOUSE_MODEL_MOUSEMANPLUS,	"MouseMan+" },
560        { MOUSE_MODEL_VERSAPAD,		"VersaPad" },
561        { MOUSE_MODEL_EXPLORER,		"IntelliMouse Explorer" },
562        { MOUSE_MODEL_4D,		"4D Mouse" },
563        { MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
564        { MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
565        { MOUSE_MODEL_UNKNOWN,		NULL },
566    };
567    int i;
568
569    for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i) {
570	if (models[i].model_code == model)
571	    return models[i].model_name;
572    }
573    return "Unknown";
574}
575
576static void
577recover_from_error(KBDC kbdc)
578{
579    /* discard anything left in the output buffer */
580    empty_both_buffers(kbdc, 10);
581
582#if 0
583    /*
584     * NOTE: KBDC_RESET_KBD may not restore the communication between the
585     * keyboard and the controller.
586     */
587    reset_kbd(kbdc);
588#else
589    /*
590     * NOTE: somehow diagnostic and keyboard port test commands bring the
591     * keyboard back.
592     */
593    if (!test_controller(kbdc))
594        log(LOG_ERR, "psm: keyboard controller failed.\n");
595    /* if there isn't a keyboard in the system, the following error is OK */
596    if (test_kbd_port(kbdc) != 0) {
597	if (verbose)
598	    log(LOG_ERR, "psm: keyboard port failed.\n");
599    }
600#endif
601}
602
603static int
604restore_controller(KBDC kbdc, int command_byte)
605{
606    empty_both_buffers(kbdc, 10);
607
608    if (!set_controller_command_byte(kbdc, 0xff, command_byte)) {
609	log(LOG_ERR, "psm: failed to restore the keyboard controller "
610		     "command byte.\n");
611	empty_both_buffers(kbdc, 10);
612	return FALSE;
613    } else {
614	empty_both_buffers(kbdc, 10);
615	return TRUE;
616    }
617}
618
619/*
620 * Re-initialize the aux port and device. The aux port must be enabled
621 * and its interrupt must be disabled before calling this routine.
622 * The aux device will be disabled before returning.
623 * The keyboard controller must be locked via `kbdc_lock()' before
624 * calling this routine.
625 */
626static int
627reinitialize(int unit, mousemode_t *mode)
628{
629    struct psm_softc *sc = PSM_SOFTC(unit);
630    KBDC kbdc = sc->kbdc;
631    int stat[3];
632    int i;
633
634    switch((i = test_aux_port(kbdc))) {
635    case 1:	/* ignore this error */
636    case PSM_ACK:
637	if (verbose)
638	    log(LOG_DEBUG, "psm%d: strange result for test aux port (%d).\n",
639	        unit, i);
640	/* fall though */
641    case 0:	/* no error */
642    	break;
643    case -1: 	/* time out */
644    default: 	/* error */
645    	recover_from_error(kbdc);
646	if (sc->config & PSM_CONFIG_IGNPORTERROR)
647	    break;
648    	log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n",
649    	    unit, i);
650    	return FALSE;
651    }
652
653    if (sc->config & PSM_CONFIG_NORESET) {
654	/*
655	 * Don't try to reset the pointing device.  It may possibly be
656	 * left in the unknown state, though...
657	 */
658    } else {
659	/*
660	 * NOTE: some controllers appears to hang the `keyboard' when
661	 * the aux port doesn't exist and `PSMC_RESET_DEV' is issued.
662	 */
663	if (!reset_aux_dev(kbdc)) {
664            recover_from_error(kbdc);
665            log(LOG_ERR, "psm%d: failed to reset the aux device.\n", unit);
666            return FALSE;
667	}
668    }
669
670    /*
671     * both the aux port and the aux device is functioning, see
672     * if the device can be enabled.
673     */
674    if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) {
675        log(LOG_ERR, "psm%d: failed to enable the aux device.\n", unit);
676        return FALSE;
677    }
678    empty_both_buffers(kbdc, 10);	/* remove stray data if any */
679
680    if (sc->config & PSM_CONFIG_NOIDPROBE) {
681	i = GENERIC_MOUSE_ENTRY;
682    } else {
683	/* FIXME: hardware ID, mouse buttons? */
684
685	/* other parameters */
686	for (i = 0; vendortype[i].probefunc != NULL; ++i) {
687	    if ((*vendortype[i].probefunc)(sc)) {
688		if (verbose >= 2)
689		    log(LOG_ERR, "psm%d: found %s\n",
690			unit, model_name(vendortype[i].model));
691		break;
692	    }
693	}
694    }
695
696    sc->hw.model = vendortype[i].model;
697    sc->mode.packetsize = vendortype[i].packetsize;
698
699    /* set mouse parameters */
700    if (mode != (mousemode_t *)NULL) {
701	if (mode->rate > 0)
702            mode->rate = set_mouse_sampling_rate(kbdc, mode->rate);
703	if (mode->resolution >= 0)
704            mode->resolution = set_mouse_resolution(kbdc, mode->resolution);
705        set_mouse_scaling(kbdc, 1);
706        set_mouse_mode(kbdc);
707    }
708
709    /* request a data packet and extract sync. bits */
710    if (get_mouse_status(kbdc, stat, 1, 3) < 3) {
711        log(LOG_DEBUG, "psm%d: failed to get data (reinitialize).\n", unit);
712        sc->mode.syncmask[0] = 0;
713    } else {
714        sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0];	/* syncbits */
715	/* the NetScroll Mouse will send three more bytes... Ignore them */
716	empty_aux_buffer(kbdc, 5);
717    }
718
719    /* just check the status of the mouse */
720    if (get_mouse_status(kbdc, stat, 0, 3) < 3)
721        log(LOG_DEBUG, "psm%d: failed to get status (reinitialize).\n", unit);
722
723    return TRUE;
724}
725
726static int
727doopen(int unit, int command_byte)
728{
729    struct psm_softc *sc = PSM_SOFTC(unit);
730    int stat[3];
731
732    /* enable the mouse device */
733    if (!enable_aux_dev(sc->kbdc)) {
734	/* MOUSE ERROR: failed to enable the mouse because:
735	 * 1) the mouse is faulty,
736	 * 2) the mouse has been removed(!?)
737	 * In the latter case, the keyboard may have hung, and need
738	 * recovery procedure...
739	 */
740	recover_from_error(sc->kbdc);
741#if 0
742	/* FIXME: we could reset the mouse here and try to enable
743	 * it again. But it will take long time and it's not a good
744	 * idea to disable the keyboard that long...
745	 */
746	if (!reinitialize(unit, &sc->mode) || !enable_aux_dev(sc->kbdc)) {
747	    recover_from_error(sc->kbdc);
748#else
749        {
750#endif
751            restore_controller(sc->kbdc, command_byte);
752	    /* mark this device is no longer available */
753	    sc->state &= ~PSM_VALID;
754	    log(LOG_ERR, "psm%d: failed to enable the device (doopen).\n",
755		unit);
756	    return (EIO);
757	}
758    }
759
760    if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
761        log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n", unit);
762
763    /* enable the aux port and interrupt */
764    if (!set_controller_command_byte(sc->kbdc,
765	    kbdc_get_device_mask(sc->kbdc),
766	    (command_byte & KBD_KBD_CONTROL_BITS)
767		| KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) {
768	/* CONTROLLER ERROR */
769	disable_aux_dev(sc->kbdc);
770        restore_controller(sc->kbdc, command_byte);
771	log(LOG_ERR, "psm%d: failed to enable the aux interrupt (doopen).\n",
772	    unit);
773	return (EIO);
774    }
775
776    /* start the watchdog timer */
777    sc->watchdog = FALSE;
778    sc->callout = timeout(psmtimeout, (void *)(uintptr_t)unit, hz*2);
779
780    return (0);
781}
782
783/* psm driver entry points */
784
785#define endprobe(v)	{   if (bootverbose) 				\
786				--verbose;   				\
787                            kbdc_set_device_mask(sc->kbdc, mask);	\
788			    kbdc_lock(sc->kbdc, FALSE);			\
789			    return (v);	     				\
790			}
791
792static int
793psmprobe(device_t dev)
794{
795    int unit = device_get_unit(dev);
796    struct psm_softc *sc = device_get_softc(dev);
797    uintptr_t irq;
798    uintptr_t flags;
799    int stat[3];
800    int command_byte;
801    int mask;
802    int rid;
803    int i;
804
805#if 0
806    kbdc_debug(TRUE);
807#endif
808
809#if notyet
810    /* check PnP IDs */
811    if (XXX_PNP_PROBE(device_get_parent(dev), dev, psm_ids) == ENXIO)
812	return ENXIO;
813#endif
814
815    BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
816    BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
817
818    sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
819    sc->config = flags & PSM_CONFIG_FLAGS;
820    /* XXX: for backward compatibility */
821#if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM)
822    sc->config |=
823#ifdef PSM_RESETAFTERSUSPEND
824	PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
825#else
826	PSM_CONFIG_HOOKRESUME;
827#endif
828#endif /* PSM_HOOKRESUME | PSM_HOOKAPM */
829    sc->flags = 0;
830    if (bootverbose)
831        ++verbose;
832
833    device_set_desc(dev, "PS/2 Mouse");
834
835    if (!kbdc_lock(sc->kbdc, TRUE)) {
836        printf("psm%d: unable to lock the controller.\n", unit);
837        if (bootverbose)
838            --verbose;
839	return (ENXIO);
840    }
841
842    /*
843     * NOTE: two bits in the command byte controls the operation of the
844     * aux port (mouse port): the aux port disable bit (bit 5) and the aux
845     * port interrupt (IRQ 12) enable bit (bit 2).
846     */
847
848    /* discard anything left after the keyboard initialization */
849    empty_both_buffers(sc->kbdc, 10);
850
851    /* save the current command byte; it will be used later */
852    mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS;
853    command_byte = get_controller_command_byte(sc->kbdc);
854    if (verbose)
855        printf("psm%d: current command byte:%04x\n", unit, command_byte);
856    if (command_byte == -1) {
857        /* CONTROLLER ERROR */
858        printf("psm%d: unable to get the current command byte value.\n",
859            unit);
860        endprobe(ENXIO);
861    }
862
863    /*
864     * disable the keyboard port while probing the aux port, which must be
865     * enabled during this routine
866     */
867    if (!set_controller_command_byte(sc->kbdc,
868	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
869  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
870                | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
871        /*
872	 * this is CONTROLLER ERROR; I don't know how to recover
873         * from this error...
874	 */
875        restore_controller(sc->kbdc, command_byte);
876        printf("psm%d: unable to set the command byte.\n", unit);
877        endprobe(ENXIO);
878    }
879    write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT);
880
881    /*
882     * NOTE: `test_aux_port()' is designed to return with zero if the aux
883     * port exists and is functioning. However, some controllers appears
884     * to respond with zero even when the aux port doesn't exist. (It may
885     * be that this is only the case when the controller DOES have the aux
886     * port but the port is not wired on the motherboard.) The keyboard
887     * controllers without the port, such as the original AT, are
888     * supporsed to return with an error code or simply time out. In any
889     * case, we have to continue probing the port even when the controller
890     * passes this test.
891     *
892     * XXX: some controllers erroneously return the error code 1 when
893     * it has the perfectly functional aux port. We have to ignore this
894     * error code. Even if the controller HAS error with the aux port,
895     * it will be detected later...
896     * XXX: another incompatible controller returns PSM_ACK (0xfa)...
897     */
898    switch ((i = test_aux_port(sc->kbdc))) {
899    case 1:	   /* ignore this error */
900    case PSM_ACK:
901        if (verbose)
902	    printf("psm%d: strange result for test aux port (%d).\n",
903	        unit, i);
904	/* fall though */
905    case 0:        /* no error */
906        break;
907    case -1:        /* time out */
908    default:        /* error */
909        recover_from_error(sc->kbdc);
910	if (sc->config & PSM_CONFIG_IGNPORTERROR)
911	    break;
912        restore_controller(sc->kbdc, command_byte);
913        if (verbose)
914            printf("psm%d: the aux port is not functioning (%d).\n",
915                unit, i);
916        endprobe(ENXIO);
917    }
918
919    if (sc->config & PSM_CONFIG_NORESET) {
920	/*
921	 * Don't try to reset the pointing device.  It may possibly be
922	 * left in the unknown state, though...
923	 */
924    } else {
925	/*
926	 * NOTE: some controllers appears to hang the `keyboard' when the aux
927	 * port doesn't exist and `PSMC_RESET_DEV' is issued.
928	 */
929	if (!reset_aux_dev(sc->kbdc)) {
930            recover_from_error(sc->kbdc);
931            restore_controller(sc->kbdc, command_byte);
932            if (verbose)
933        	printf("psm%d: failed to reset the aux device.\n", unit);
934            endprobe(ENXIO);
935	}
936    }
937
938    /*
939     * both the aux port and the aux device is functioning, see if the
940     * device can be enabled. NOTE: when enabled, the device will start
941     * sending data; we shall immediately disable the device once we know
942     * the device can be enabled.
943     */
944    if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) {
945        /* MOUSE ERROR */
946	recover_from_error(sc->kbdc);
947	restore_controller(sc->kbdc, command_byte);
948	if (verbose)
949	    printf("psm%d: failed to enable the aux device.\n", unit);
950        endprobe(ENXIO);
951    }
952
953    /* save the default values after reset */
954    if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) {
955	sc->dflt_mode.rate = sc->mode.rate = stat[2];
956	sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
957    } else {
958	sc->dflt_mode.rate = sc->mode.rate = -1;
959	sc->dflt_mode.resolution = sc->mode.resolution = -1;
960    }
961
962    /* hardware information */
963    sc->hw.iftype = MOUSE_IF_PS2;
964
965    /* verify the device is a mouse */
966    sc->hw.hwid = get_aux_id(sc->kbdc);
967    if (!is_a_mouse(sc->hw.hwid)) {
968        restore_controller(sc->kbdc, command_byte);
969        if (verbose)
970            printf("psm%d: unknown device type (%d).\n", unit, sc->hw.hwid);
971        endprobe(ENXIO);
972    }
973    switch (sc->hw.hwid) {
974    case PSM_BALLPOINT_ID:
975        sc->hw.type = MOUSE_TRACKBALL;
976        break;
977    case PSM_MOUSE_ID:
978    case PSM_INTELLI_ID:
979    case PSM_EXPLORER_ID:
980    case PSM_4DMOUSE_ID:
981    case PSM_4DPLUS_ID:
982        sc->hw.type = MOUSE_MOUSE;
983        break;
984    default:
985        sc->hw.type = MOUSE_UNKNOWN;
986        break;
987    }
988
989    if (sc->config & PSM_CONFIG_NOIDPROBE) {
990	sc->hw.buttons = 2;
991	i = GENERIC_MOUSE_ENTRY;
992    } else {
993	/* # of buttons */
994	sc->hw.buttons = get_mouse_buttons(sc->kbdc);
995
996	/* other parameters */
997	for (i = 0; vendortype[i].probefunc != NULL; ++i) {
998	    if ((*vendortype[i].probefunc)(sc)) {
999		if (verbose >= 2)
1000		    printf("psm%d: found %s\n",
1001			   unit, model_name(vendortype[i].model));
1002		break;
1003	    }
1004	}
1005    }
1006
1007    sc->hw.model = vendortype[i].model;
1008
1009    sc->dflt_mode.level = PSM_LEVEL_BASE;
1010    sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE;
1011    sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4;
1012    if (sc->config & PSM_CONFIG_NOCHECKSYNC)
1013        sc->dflt_mode.syncmask[0] = 0;
1014    else
1015        sc->dflt_mode.syncmask[0] = vendortype[i].syncmask;
1016    if (sc->config & PSM_CONFIG_FORCETAP)
1017        sc->mode.syncmask[0] &= ~MOUSE_PS2_TAP;
1018    sc->dflt_mode.syncmask[1] = 0;	/* syncbits */
1019    sc->mode = sc->dflt_mode;
1020    sc->mode.packetsize = vendortype[i].packetsize;
1021
1022    /* set mouse parameters */
1023#if 0
1024    /*
1025     * A version of Logitech FirstMouse+ won't report wheel movement,
1026     * if SET_DEFAULTS is sent...  Don't use this command.
1027     * This fix was found by Takashi Nishida.
1028     */
1029    i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS);
1030    if (verbose >= 2)
1031	printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i);
1032#endif
1033    if (sc->config & PSM_CONFIG_RESOLUTION) {
1034        sc->mode.resolution
1035	    = set_mouse_resolution(sc->kbdc,
1036				   (sc->config & PSM_CONFIG_RESOLUTION) - 1);
1037    } else if (sc->mode.resolution >= 0) {
1038	sc->mode.resolution
1039	    = set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution);
1040    }
1041    if (sc->mode.rate > 0) {
1042	sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate);
1043    }
1044    set_mouse_scaling(sc->kbdc, 1);
1045
1046    /* request a data packet and extract sync. bits */
1047    if (get_mouse_status(sc->kbdc, stat, 1, 3) < 3) {
1048        printf("psm%d: failed to get data.\n", unit);
1049        sc->mode.syncmask[0] = 0;
1050    } else {
1051        sc->mode.syncmask[1] = stat[0] & sc->mode.syncmask[0];	/* syncbits */
1052	/* the NetScroll Mouse will send three more bytes... Ignore them */
1053	empty_aux_buffer(sc->kbdc, 5);
1054    }
1055
1056    /* just check the status of the mouse */
1057    /*
1058     * NOTE: XXX there are some arcane controller/mouse combinations out
1059     * there, which hung the controller unless there is data transmission
1060     * after ACK from the mouse.
1061     */
1062    if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) {
1063        printf("psm%d: failed to get status.\n", unit);
1064    } else {
1065	/*
1066	 * When in its native mode, some mice operate with different
1067	 * default parameters than in the PS/2 compatible mode.
1068	 */
1069        sc->dflt_mode.rate = sc->mode.rate = stat[2];
1070        sc->dflt_mode.resolution = sc->mode.resolution = stat[1];
1071     }
1072
1073    /* disable the aux port for now... */
1074    if (!set_controller_command_byte(sc->kbdc,
1075	    KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS,
1076            (command_byte & KBD_KBD_CONTROL_BITS)
1077                | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1078        /*
1079	 * this is CONTROLLER ERROR; I don't know the proper way to
1080         * recover from this error...
1081	 */
1082        restore_controller(sc->kbdc, command_byte);
1083        printf("psm%d: unable to set the command byte.\n", unit);
1084        endprobe(ENXIO);
1085    }
1086
1087    /* see if IRQ is available */
1088    rid = 0;
1089    sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
1090				  RF_ACTIVE);
1091    if (sc->intr == NULL) {
1092        printf("psm%d: unable to allocate the IRQ resource (%d).\n",
1093	       unit, (int)irq);
1094        endprobe(ENXIO);
1095    } else {
1096	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1097    }
1098
1099    /* done */
1100    kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
1101    kbdc_lock(sc->kbdc, FALSE);
1102    return (0);
1103}
1104
1105static int
1106psmattach(device_t dev)
1107{
1108    int unit = device_get_unit(dev);
1109    struct psm_softc *sc = device_get_softc(dev);
1110    uintptr_t irq;
1111    int error;
1112    int rid;
1113
1114    if (sc == NULL)    /* shouldn't happen */
1115	return (ENXIO);
1116
1117    /* Setup initial state */
1118    sc->state = PSM_VALID;
1119    callout_handle_init(&sc->callout);
1120
1121    /* Setup our interrupt handler */
1122    rid = 0;
1123    BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
1124    sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
1125				  RF_ACTIVE);
1126    if (sc->intr == NULL)
1127	return (ENXIO);
1128    error = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->intr,
1129			   INTR_TYPE_TTY, psmintr, sc, &sc->ih);
1130    if (error) {
1131	bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1132	return (error);
1133    }
1134
1135    /* Done */
1136    sc->dev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, FALSE), 0, 0, 0666,
1137		       "psm%d", unit);
1138    sc->bdev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, TRUE), 0, 0, 0666,
1139			"bpsm%d", unit);
1140
1141    if (!verbose) {
1142        printf("psm%d: model %s, device ID %d\n",
1143	    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
1144    } else {
1145        printf("psm%d: model %s, device ID %d-%02x, %d buttons\n",
1146	    unit, model_name(sc->hw.model),
1147	    sc->hw.hwid & 0x00ff, sc->hw.hwid >> 8, sc->hw.buttons);
1148	printf("psm%d: config:%08x, flags:%08x, packet size:%d\n",
1149	    unit, sc->config, sc->flags, sc->mode.packetsize);
1150	printf("psm%d: syncmask:%02x, syncbits:%02x\n",
1151	    unit, sc->mode.syncmask[0], sc->mode.syncmask[1]);
1152    }
1153
1154    if (bootverbose)
1155        --verbose;
1156
1157    return (0);
1158}
1159
1160static int
1161psmdetach(device_t dev)
1162{
1163    struct psm_softc *sc;
1164    int rid;
1165
1166    sc = device_get_softc(dev);
1167    if (sc->state & PSM_OPEN)
1168	return EBUSY;
1169
1170    rid = 0;
1171    BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->intr, sc->ih);
1172    bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
1173
1174    destroy_dev(sc->dev);
1175    destroy_dev(sc->bdev);
1176
1177    return 0;
1178}
1179
1180static int
1181psmopen(dev_t dev, int flag, int fmt, struct proc *p)
1182{
1183    int unit = PSM_UNIT(dev);
1184    struct psm_softc *sc;
1185    int command_byte;
1186    int err;
1187    int s;
1188
1189    /* Get device data */
1190    sc = PSM_SOFTC(unit);
1191    if ((sc == NULL) || (sc->state & PSM_VALID) == 0)
1192	/* the device is no longer valid/functioning */
1193        return (ENXIO);
1194
1195    /* Disallow multiple opens */
1196    if (sc->state & PSM_OPEN)
1197        return (EBUSY);
1198
1199    device_busy(devclass_get_device(psm_devclass, unit));
1200
1201    /* Initialize state */
1202    sc->rsel.si_flags = 0;
1203    sc->rsel.si_pid = 0;
1204    sc->mode.level = sc->dflt_mode.level;
1205    sc->mode.protocol = sc->dflt_mode.protocol;
1206    sc->watchdog = FALSE;
1207
1208    /* flush the event queue */
1209    sc->queue.count = 0;
1210    sc->queue.head = 0;
1211    sc->queue.tail = 0;
1212    sc->status.flags = 0;
1213    sc->status.button = 0;
1214    sc->status.obutton = 0;
1215    sc->status.dx = 0;
1216    sc->status.dy = 0;
1217    sc->status.dz = 0;
1218    sc->button = 0;
1219
1220    /* empty input buffer */
1221    bzero(sc->ipacket, sizeof(sc->ipacket));
1222    sc->inputbytes = 0;
1223
1224    /* don't let timeout routines in the keyboard driver to poll the kbdc */
1225    if (!kbdc_lock(sc->kbdc, TRUE))
1226	return (EIO);
1227
1228    /* save the current controller command byte */
1229    s = spltty();
1230    command_byte = get_controller_command_byte(sc->kbdc);
1231
1232    /* enable the aux port and temporalily disable the keyboard */
1233    if ((command_byte == -1)
1234        || !set_controller_command_byte(sc->kbdc,
1235	    kbdc_get_device_mask(sc->kbdc),
1236  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
1237	        | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1238        /* CONTROLLER ERROR; do you know how to get out of this? */
1239        kbdc_lock(sc->kbdc, FALSE);
1240	splx(s);
1241	log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n",
1242	    unit);
1243	return (EIO);
1244    }
1245    /*
1246     * Now that the keyboard controller is told not to generate
1247     * the keyboard and mouse interrupts, call `splx()' to allow
1248     * the other tty interrupts. The clock interrupt may also occur,
1249     * but timeout routines will be blocked by the poll flag set
1250     * via `kbdc_lock()'
1251     */
1252    splx(s);
1253
1254    /* enable the mouse device */
1255    err = doopen(unit, command_byte);
1256
1257    /* done */
1258    if (err == 0)
1259        sc->state |= PSM_OPEN;
1260    kbdc_lock(sc->kbdc, FALSE);
1261    return (err);
1262}
1263
1264static int
1265psmclose(dev_t dev, int flag, int fmt, struct proc *p)
1266{
1267    int unit = PSM_UNIT(dev);
1268    struct psm_softc *sc = PSM_SOFTC(unit);
1269    int stat[3];
1270    int command_byte;
1271    int s;
1272
1273    /* don't let timeout routines in the keyboard driver to poll the kbdc */
1274    if (!kbdc_lock(sc->kbdc, TRUE))
1275	return (EIO);
1276
1277    /* save the current controller command byte */
1278    s = spltty();
1279    command_byte = get_controller_command_byte(sc->kbdc);
1280    if (command_byte == -1) {
1281        kbdc_lock(sc->kbdc, FALSE);
1282	splx(s);
1283	return (EIO);
1284    }
1285
1286    /* disable the aux interrupt and temporalily disable the keyboard */
1287    if (!set_controller_command_byte(sc->kbdc,
1288	    kbdc_get_device_mask(sc->kbdc),
1289  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
1290	        | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1291	log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n",
1292	    unit);
1293	/* CONTROLLER ERROR;
1294	 * NOTE: we shall force our way through. Because the only
1295	 * ill effect we shall see is that we may not be able
1296	 * to read ACK from the mouse, and it doesn't matter much
1297	 * so long as the mouse will accept the DISABLE command.
1298	 */
1299    }
1300    splx(s);
1301
1302    /* stop the watchdog timer */
1303    untimeout(psmtimeout, (void *)(uintptr_t)unit, sc->callout);
1304    callout_handle_init(&sc->callout);
1305
1306    /* remove anything left in the output buffer */
1307    empty_aux_buffer(sc->kbdc, 10);
1308
1309    /* disable the aux device, port and interrupt */
1310    if (sc->state & PSM_VALID) {
1311        if (!disable_aux_dev(sc->kbdc)) {
1312	    /* MOUSE ERROR;
1313	     * NOTE: we don't return error and continue, pretending
1314	     * we have successfully disabled the device. It's OK because
1315	     * the interrupt routine will discard any data from the mouse
1316	     * hereafter.
1317	     */
1318	    log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n",
1319		unit);
1320        }
1321
1322        if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
1323            log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n",
1324		unit);
1325    }
1326
1327    if (!set_controller_command_byte(sc->kbdc,
1328	    kbdc_get_device_mask(sc->kbdc),
1329	    (command_byte & KBD_KBD_CONTROL_BITS)
1330	        | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1331	/* CONTROLLER ERROR;
1332	 * we shall ignore this error; see the above comment.
1333	 */
1334	log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n",
1335	    unit);
1336    }
1337
1338    /* remove anything left in the output buffer */
1339    empty_aux_buffer(sc->kbdc, 10);
1340
1341    /* close is almost always successful */
1342    sc->state &= ~PSM_OPEN;
1343    kbdc_lock(sc->kbdc, FALSE);
1344    device_unbusy(devclass_get_device(psm_devclass, unit));
1345    return (0);
1346}
1347
1348static int
1349tame_mouse(struct psm_softc *sc, mousestatus_t *status, unsigned char *buf)
1350{
1351    static unsigned char butmapps2[8] = {
1352        0,
1353        MOUSE_PS2_BUTTON1DOWN,
1354        MOUSE_PS2_BUTTON2DOWN,
1355        MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN,
1356        MOUSE_PS2_BUTTON3DOWN,
1357        MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN,
1358        MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1359        MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN,
1360    };
1361    static unsigned char butmapmsc[8] = {
1362        MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1363        MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1364        MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1365        MOUSE_MSC_BUTTON3UP,
1366        MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1367        MOUSE_MSC_BUTTON2UP,
1368        MOUSE_MSC_BUTTON1UP,
1369        0,
1370    };
1371    int mapped;
1372    int i;
1373
1374    if (sc->mode.level == PSM_LEVEL_BASE) {
1375        mapped = status->button & ~MOUSE_BUTTON4DOWN;
1376        if (status->button & MOUSE_BUTTON4DOWN)
1377	    mapped |= MOUSE_BUTTON1DOWN;
1378        status->button = mapped;
1379        buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS];
1380        i = max(min(status->dx, 255), -256);
1381	if (i < 0)
1382	    buf[0] |= MOUSE_PS2_XNEG;
1383        buf[1] = i;
1384        i = max(min(status->dy, 255), -256);
1385	if (i < 0)
1386	    buf[0] |= MOUSE_PS2_YNEG;
1387        buf[2] = i;
1388	return MOUSE_PS2_PACKETSIZE;
1389    } else if (sc->mode.level == PSM_LEVEL_STANDARD) {
1390        buf[0] = MOUSE_MSC_SYNC | butmapmsc[status->button & MOUSE_STDBUTTONS];
1391        i = max(min(status->dx, 255), -256);
1392        buf[1] = i >> 1;
1393        buf[3] = i - buf[1];
1394        i = max(min(status->dy, 255), -256);
1395        buf[2] = i >> 1;
1396        buf[4] = i - buf[2];
1397        i = max(min(status->dz, 127), -128);
1398        buf[5] = (i >> 1) & 0x7f;
1399        buf[6] = (i - (i >> 1)) & 0x7f;
1400        buf[7] = (~status->button >> 3) & 0x7f;
1401	return MOUSE_SYS_PACKETSIZE;
1402    }
1403    return sc->inputbytes;;
1404}
1405
1406static int
1407psmread(dev_t dev, struct uio *uio, int flag)
1408{
1409    register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
1410    unsigned char buf[PSM_SMALLBUFSIZE];
1411    int error = 0;
1412    int s;
1413    int l;
1414
1415    if ((sc->state & PSM_VALID) == 0)
1416	return EIO;
1417
1418    /* block until mouse activity occured */
1419    s = spltty();
1420    while (sc->queue.count <= 0) {
1421        if (PSM_NBLOCKIO(dev)) {
1422            splx(s);
1423            return EWOULDBLOCK;
1424        }
1425        sc->state |= PSM_ASLP;
1426        error = tsleep((caddr_t) sc, PZERO | PCATCH, "psmrea", 0);
1427        sc->state &= ~PSM_ASLP;
1428        if (error) {
1429            splx(s);
1430            return error;
1431        } else if ((sc->state & PSM_VALID) == 0) {
1432            /* the device disappeared! */
1433            splx(s);
1434            return EIO;
1435	}
1436    }
1437    splx(s);
1438
1439    /* copy data to the user land */
1440    while ((sc->queue.count > 0) && (uio->uio_resid > 0)) {
1441        s = spltty();
1442	l = min(sc->queue.count, uio->uio_resid);
1443	if (l > sizeof(buf))
1444	    l = sizeof(buf);
1445	if (l > sizeof(sc->queue.buf) - sc->queue.head) {
1446	    bcopy(&sc->queue.buf[sc->queue.head], &buf[0],
1447		sizeof(sc->queue.buf) - sc->queue.head);
1448	    bcopy(&sc->queue.buf[0],
1449		&buf[sizeof(sc->queue.buf) - sc->queue.head],
1450		l - (sizeof(sc->queue.buf) - sc->queue.head));
1451	} else {
1452	    bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l);
1453	}
1454	sc->queue.count -= l;
1455	sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf);
1456        splx(s);
1457        error = uiomove(buf, l, uio);
1458        if (error)
1459	    break;
1460    }
1461
1462    return error;
1463}
1464
1465static int
1466block_mouse_data(struct psm_softc *sc, int *c)
1467{
1468    int s;
1469
1470    if (!kbdc_lock(sc->kbdc, TRUE))
1471	return EIO;
1472
1473    s = spltty();
1474    *c = get_controller_command_byte(sc->kbdc);
1475    if ((*c == -1)
1476	|| !set_controller_command_byte(sc->kbdc,
1477	    kbdc_get_device_mask(sc->kbdc),
1478            KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
1479                | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
1480        /* this is CONTROLLER ERROR */
1481	splx(s);
1482        kbdc_lock(sc->kbdc, FALSE);
1483	return EIO;
1484    }
1485
1486    /*
1487     * The device may be in the middle of status data transmission.
1488     * The transmission will be interrupted, thus, incomplete status
1489     * data must be discarded. Although the aux interrupt is disabled
1490     * at the keyboard controller level, at most one aux interrupt
1491     * may have already been pending and a data byte is in the
1492     * output buffer; throw it away. Note that the second argument
1493     * to `empty_aux_buffer()' is zero, so that the call will just
1494     * flush the internal queue.
1495     * `psmintr()' will be invoked after `splx()' if an interrupt is
1496     * pending; it will see no data and returns immediately.
1497     */
1498    empty_aux_buffer(sc->kbdc, 0);	/* flush the queue */
1499    read_aux_data_no_wait(sc->kbdc);	/* throw away data if any */
1500    sc->inputbytes = 0;
1501    splx(s);
1502
1503    return 0;
1504}
1505
1506static int
1507unblock_mouse_data(struct psm_softc *sc, int c)
1508{
1509    int error = 0;
1510
1511    /*
1512     * We may have seen a part of status data during `set_mouse_XXX()'.
1513     * they have been queued; flush it.
1514     */
1515    empty_aux_buffer(sc->kbdc, 0);
1516
1517    /* restore ports and interrupt */
1518    if (!set_controller_command_byte(sc->kbdc,
1519            kbdc_get_device_mask(sc->kbdc),
1520	    c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
1521        /* CONTROLLER ERROR; this is serious, we may have
1522         * been left with the inaccessible keyboard and
1523         * the disabled mouse interrupt.
1524         */
1525        error = EIO;
1526    }
1527
1528    kbdc_lock(sc->kbdc, FALSE);
1529    return error;
1530}
1531
1532static int
1533psmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1534{
1535    struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
1536    mousemode_t mode;
1537    mousestatus_t status;
1538#if (defined(MOUSE_GETVARS))
1539    mousevar_t *var;
1540#endif
1541    mousedata_t *data;
1542    int stat[3];
1543    int command_byte;
1544    int error = 0;
1545    int s;
1546
1547    /* Perform IOCTL command */
1548    switch (cmd) {
1549
1550    case OLD_MOUSE_GETHWINFO:
1551	s = spltty();
1552        ((old_mousehw_t *)addr)->buttons = sc->hw.buttons;
1553        ((old_mousehw_t *)addr)->iftype = sc->hw.iftype;
1554        ((old_mousehw_t *)addr)->type = sc->hw.type;
1555        ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;
1556	splx(s);
1557        break;
1558
1559    case MOUSE_GETHWINFO:
1560	s = spltty();
1561        *(mousehw_t *)addr = sc->hw;
1562	if (sc->mode.level == PSM_LEVEL_BASE)
1563	    ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC;
1564	splx(s);
1565        break;
1566
1567    case OLD_MOUSE_GETMODE:
1568	s = spltty();
1569	switch (sc->mode.level) {
1570	case PSM_LEVEL_BASE:
1571	    ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1572	    break;
1573	case PSM_LEVEL_STANDARD:
1574	    ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
1575	    break;
1576	case PSM_LEVEL_NATIVE:
1577	    ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1578	    break;
1579	}
1580        ((old_mousemode_t *)addr)->rate = sc->mode.rate;
1581        ((old_mousemode_t *)addr)->resolution = sc->mode.resolution;
1582        ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor;
1583	splx(s);
1584        break;
1585
1586    case MOUSE_GETMODE:
1587	s = spltty();
1588        *(mousemode_t *)addr = sc->mode;
1589        ((mousemode_t *)addr)->resolution =
1590	    MOUSE_RES_LOW - sc->mode.resolution;
1591	switch (sc->mode.level) {
1592	case PSM_LEVEL_BASE:
1593	    ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1594	    ((mousemode_t *)addr)->packetsize = MOUSE_PS2_PACKETSIZE;
1595	    break;
1596	case PSM_LEVEL_STANDARD:
1597	    ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE;
1598	    ((mousemode_t *)addr)->packetsize = MOUSE_SYS_PACKETSIZE;
1599	    ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK;
1600	    ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC;
1601	    break;
1602	case PSM_LEVEL_NATIVE:
1603	    /* FIXME: this isn't quite correct... XXX */
1604	    ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2;
1605	    break;
1606	}
1607	splx(s);
1608        break;
1609
1610    case OLD_MOUSE_SETMODE:
1611    case MOUSE_SETMODE:
1612	if (cmd == OLD_MOUSE_SETMODE) {
1613	    mode.rate = ((old_mousemode_t *)addr)->rate;
1614	    /*
1615	     * resolution  old I/F   new I/F
1616	     * default        0         0
1617	     * low            1        -2
1618	     * medium low     2        -3
1619	     * medium high    3        -4
1620	     * high           4        -5
1621	     */
1622	    if (((old_mousemode_t *)addr)->resolution > 0)
1623	        mode.resolution = -((old_mousemode_t *)addr)->resolution - 1;
1624	    mode.accelfactor = ((old_mousemode_t *)addr)->accelfactor;
1625	    mode.level = -1;
1626	} else {
1627	    mode = *(mousemode_t *)addr;
1628	}
1629
1630	/* adjust and validate parameters. */
1631	if (mode.rate > UCHAR_MAX)
1632	    return EINVAL;
1633        if (mode.rate == 0)
1634            mode.rate = sc->dflt_mode.rate;
1635	else if (mode.rate == -1)
1636	    /* don't change the current setting */
1637	    ;
1638	else if (mode.rate < 0)
1639	    return EINVAL;
1640	if (mode.resolution >= UCHAR_MAX)
1641	    return EINVAL;
1642	if (mode.resolution >= 200)
1643	    mode.resolution = MOUSE_RES_HIGH;
1644	else if (mode.resolution >= 100)
1645	    mode.resolution = MOUSE_RES_MEDIUMHIGH;
1646	else if (mode.resolution >= 50)
1647	    mode.resolution = MOUSE_RES_MEDIUMLOW;
1648	else if (mode.resolution > 0)
1649	    mode.resolution = MOUSE_RES_LOW;
1650        if (mode.resolution == MOUSE_RES_DEFAULT)
1651            mode.resolution = sc->dflt_mode.resolution;
1652        else if (mode.resolution == -1)
1653	    /* don't change the current setting */
1654	    ;
1655        else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
1656            mode.resolution = MOUSE_RES_LOW - mode.resolution;
1657	if (mode.level == -1)
1658	    /* don't change the current setting */
1659	    mode.level = sc->mode.level;
1660	else if ((mode.level < PSM_LEVEL_MIN) || (mode.level > PSM_LEVEL_MAX))
1661	    return EINVAL;
1662        if (mode.accelfactor == -1)
1663	    /* don't change the current setting */
1664	    mode.accelfactor = sc->mode.accelfactor;
1665        else if (mode.accelfactor < 0)
1666	    return EINVAL;
1667
1668	/* don't allow anybody to poll the keyboard controller */
1669	error = block_mouse_data(sc, &command_byte);
1670	if (error)
1671            return error;
1672
1673        /* set mouse parameters */
1674	if (mode.rate > 0)
1675	    mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
1676	if (mode.resolution >= 0)
1677	    mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
1678	set_mouse_scaling(sc->kbdc, 1);
1679	get_mouse_status(sc->kbdc, stat, 0, 3);
1680
1681        s = spltty();
1682    	sc->mode.rate = mode.rate;
1683    	sc->mode.resolution = mode.resolution;
1684    	sc->mode.accelfactor = mode.accelfactor;
1685    	sc->mode.level = mode.level;
1686        splx(s);
1687
1688	unblock_mouse_data(sc, command_byte);
1689        break;
1690
1691    case MOUSE_GETLEVEL:
1692	*(int *)addr = sc->mode.level;
1693        break;
1694
1695    case MOUSE_SETLEVEL:
1696	if ((*(int *)addr < PSM_LEVEL_MIN) || (*(int *)addr > PSM_LEVEL_MAX))
1697	    return EINVAL;
1698	sc->mode.level = *(int *)addr;
1699        break;
1700
1701    case MOUSE_GETSTATUS:
1702        s = spltty();
1703	status = sc->status;
1704	sc->status.flags = 0;
1705	sc->status.obutton = sc->status.button;
1706	sc->status.button = 0;
1707	sc->status.dx = 0;
1708	sc->status.dy = 0;
1709	sc->status.dz = 0;
1710        splx(s);
1711        *(mousestatus_t *)addr = status;
1712        break;
1713
1714#if (defined(MOUSE_GETVARS))
1715    case MOUSE_GETVARS:
1716	var = (mousevar_t *)addr;
1717	bzero(var, sizeof(*var));
1718	s = spltty();
1719        var->var[0] = MOUSE_VARS_PS2_SIG;
1720        var->var[1] = sc->config;
1721        var->var[2] = sc->flags;
1722	splx(s);
1723        break;
1724
1725    case MOUSE_SETVARS:
1726	return ENODEV;
1727#endif /* MOUSE_GETVARS */
1728
1729    case MOUSE_READSTATE:
1730    case MOUSE_READDATA:
1731	data = (mousedata_t *)addr;
1732	if (data->len > sizeof(data->buf)/sizeof(data->buf[0]))
1733	    return EINVAL;
1734
1735	error = block_mouse_data(sc, &command_byte);
1736	if (error)
1737            return error;
1738        if ((data->len = get_mouse_status(sc->kbdc, data->buf,
1739		(cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0)
1740            error = EIO;
1741	unblock_mouse_data(sc, command_byte);
1742	break;
1743
1744#if (defined(MOUSE_SETRESOLUTION))
1745    case MOUSE_SETRESOLUTION:
1746	mode.resolution = *(int *)addr;
1747	if (mode.resolution >= UCHAR_MAX)
1748	    return EINVAL;
1749	else if (mode.resolution >= 200)
1750	    mode.resolution = MOUSE_RES_HIGH;
1751	else if (mode.resolution >= 100)
1752	    mode.resolution = MOUSE_RES_MEDIUMHIGH;
1753	else if (mode.resolution >= 50)
1754	    mode.resolution = MOUSE_RES_MEDIUMLOW;
1755	else if (mode.resolution > 0)
1756	    mode.resolution = MOUSE_RES_LOW;
1757        if (mode.resolution == MOUSE_RES_DEFAULT)
1758            mode.resolution = sc->dflt_mode.resolution;
1759        else if (mode.resolution == -1)
1760	    mode.resolution = sc->mode.resolution;
1761        else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */
1762            mode.resolution = MOUSE_RES_LOW - mode.resolution;
1763
1764	error = block_mouse_data(sc, &command_byte);
1765	if (error)
1766            return error;
1767        sc->mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution);
1768	if (sc->mode.resolution != mode.resolution)
1769	    error = EIO;
1770	unblock_mouse_data(sc, command_byte);
1771        break;
1772#endif /* MOUSE_SETRESOLUTION */
1773
1774#if (defined(MOUSE_SETRATE))
1775    case MOUSE_SETRATE:
1776	mode.rate = *(int *)addr;
1777	if (mode.rate > UCHAR_MAX)
1778	    return EINVAL;
1779        if (mode.rate == 0)
1780            mode.rate = sc->dflt_mode.rate;
1781	else if (mode.rate < 0)
1782	    mode.rate = sc->mode.rate;
1783
1784	error = block_mouse_data(sc, &command_byte);
1785	if (error)
1786            return error;
1787        sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate);
1788	if (sc->mode.rate != mode.rate)
1789	    error = EIO;
1790	unblock_mouse_data(sc, command_byte);
1791        break;
1792#endif /* MOUSE_SETRATE */
1793
1794#if (defined(MOUSE_SETSCALING))
1795    case MOUSE_SETSCALING:
1796	if ((*(int *)addr <= 0) || (*(int *)addr > 2))
1797	    return EINVAL;
1798
1799	error = block_mouse_data(sc, &command_byte);
1800	if (error)
1801            return error;
1802        if (!set_mouse_scaling(sc->kbdc, *(int *)addr))
1803	    error = EIO;
1804	unblock_mouse_data(sc, command_byte);
1805        break;
1806#endif /* MOUSE_SETSCALING */
1807
1808#if (defined(MOUSE_GETHWID))
1809    case MOUSE_GETHWID:
1810	error = block_mouse_data(sc, &command_byte);
1811	if (error)
1812            return error;
1813        sc->hw.hwid &= ~0x00ff;
1814        sc->hw.hwid |= get_aux_id(sc->kbdc);
1815	*(int *)addr = sc->hw.hwid & 0x00ff;
1816	unblock_mouse_data(sc, command_byte);
1817        break;
1818#endif /* MOUSE_GETHWID */
1819
1820    default:
1821	return ENOTTY;
1822    }
1823
1824    return error;
1825}
1826
1827static void
1828psmtimeout(void *arg)
1829{
1830    struct psm_softc *sc;
1831    int unit;
1832    int s;
1833
1834    unit = (int)(uintptr_t)arg;
1835    sc = devclass_get_softc(psm_devclass, unit);
1836    s = spltty();
1837    if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) {
1838	if (verbose >= 4)
1839	    log(LOG_DEBUG, "psm%d: lost interrupt?\n", unit);
1840	psmintr(sc);
1841	kbdc_lock(sc->kbdc, FALSE);
1842    }
1843    sc->watchdog = TRUE;
1844    splx(s);
1845    sc->callout = timeout(psmtimeout, (void *)(uintptr_t)unit, hz);
1846}
1847
1848static void
1849psmintr(void *arg)
1850{
1851    /*
1852     * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
1853     * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
1854     */
1855    static int butmap[8] = {
1856        0,
1857	MOUSE_BUTTON1DOWN,
1858	MOUSE_BUTTON3DOWN,
1859	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1860	MOUSE_BUTTON2DOWN,
1861	MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
1862	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
1863        MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
1864    };
1865    static int butmap_versapad[8] = {
1866	0,
1867	MOUSE_BUTTON3DOWN,
1868	0,
1869	MOUSE_BUTTON3DOWN,
1870	MOUSE_BUTTON1DOWN,
1871	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1872	MOUSE_BUTTON1DOWN,
1873	MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN
1874    };
1875    register struct psm_softc *sc = arg;
1876    mousestatus_t ms;
1877    int x, y, z;
1878    int c;
1879    int l;
1880    int x0, y0;
1881
1882    /* read until there is nothing to read */
1883    while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
1884
1885        /* discard the byte if the device is not open */
1886        if ((sc->state & PSM_OPEN) == 0)
1887            continue;
1888
1889        sc->ipacket[sc->inputbytes++] = c;
1890        if (sc->inputbytes < sc->mode.packetsize)
1891	    continue;
1892
1893#if 0
1894        log(LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n",
1895	    sc->ipacket[0], sc->ipacket[1], sc->ipacket[2],
1896	    sc->ipacket[3], sc->ipacket[4], sc->ipacket[5]);
1897#endif
1898
1899	c = sc->ipacket[0];
1900
1901	if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) {
1902            log(LOG_DEBUG, "psmintr: out of sync (%04x != %04x).\n",
1903		c & sc->mode.syncmask[0], sc->mode.syncmask[1]);
1904	    sc->inputbytes = 0;
1905	    if (sc->config & PSM_CONFIG_SYNCHACK) {
1906		/*
1907		 * XXX: this is a grotesque hack to get us out of
1908		 * dreaded "out of sync" error.
1909		 */
1910		log(LOG_DEBUG, "psmintr: re-enable the mouse.\n");
1911		disable_aux_dev(sc->kbdc);
1912		enable_aux_dev(sc->kbdc);
1913	    }
1914            continue;
1915	}
1916
1917	/*
1918	 * A kludge for Kensington device!
1919	 * The MSB of the horizontal count appears to be stored in
1920	 * a strange place.
1921	 */
1922	if (sc->hw.model == MOUSE_MODEL_THINK)
1923	    sc->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
1924
1925        /* ignore the overflow bits... */
1926        x = (c & MOUSE_PS2_XNEG) ?  sc->ipacket[1] - 256 : sc->ipacket[1];
1927        y = (c & MOUSE_PS2_YNEG) ?  sc->ipacket[2] - 256 : sc->ipacket[2];
1928	z = 0;
1929        ms.obutton = sc->button;		  /* previous button state */
1930        ms.button = butmap[c & MOUSE_PS2_BUTTONS];
1931	/* `tapping' action */
1932	if (sc->config & PSM_CONFIG_FORCETAP)
1933	    ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
1934
1935	switch (sc->hw.model) {
1936
1937	case MOUSE_MODEL_EXPLORER:
1938	    /*
1939	     *          b7 b6 b5 b4 b3 b2 b1 b0
1940	     * byte 1:  oy ox sy sx 1  M  R  L
1941	     * byte 2:  x  x  x  x  x  x  x  x
1942	     * byte 3:  y  y  y  y  y  y  y  y
1943	     * byte 4:  *  *  S2 S1 s  d2 d1 d0
1944	     *
1945	     * L, M, R, S1, S2: left, middle, right and side buttons
1946	     * s: wheel data sign bit
1947	     * d2-d0: wheel data
1948	     */
1949	    z = (sc->ipacket[3] & MOUSE_EXPLORER_ZNEG)
1950		? (sc->ipacket[3] & 0x0f) - 16 : (sc->ipacket[3] & 0x0f);
1951	    ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN)
1952		? MOUSE_BUTTON4DOWN : 0;
1953	    ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN)
1954		? MOUSE_BUTTON5DOWN : 0;
1955	    break;
1956
1957	case MOUSE_MODEL_INTELLI:
1958	case MOUSE_MODEL_NET:
1959	    /* wheel data is in the fourth byte */
1960	    z = (char)sc->ipacket[3];
1961	    /* some mice may send 7 when there is no Z movement?! XXX */
1962	    if ((z >= 7) || (z <= -7))
1963		z = 0;
1964	    /* some compatible mice have additional buttons */
1965	    ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN)
1966		? MOUSE_BUTTON4DOWN : 0;
1967	    ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN)
1968		? MOUSE_BUTTON5DOWN : 0;
1969	    break;
1970
1971	case MOUSE_MODEL_MOUSEMANPLUS:
1972	    /*
1973	     * PS2++ protocl packet
1974	     *
1975	     *          b7 b6 b5 b4 b3 b2 b1 b0
1976	     * byte 1:  *  1  p3 p2 1  *  *  *
1977	     * byte 2:  c1 c2 p1 p0 d1 d0 1  0
1978	     *
1979	     * p3-p0: packet type
1980	     * c1, c2: c1 & c2 == 1, if p2 == 0
1981	     *         c1 & c2 == 0, if p2 == 1
1982	     *
1983	     * packet type: 0 (device type)
1984	     * See comments in enable_mmanplus() below.
1985	     *
1986	     * packet type: 1 (wheel data)
1987	     *
1988	     *          b7 b6 b5 b4 b3 b2 b1 b0
1989	     * byte 3:  h  *  B5 B4 s  d2 d1 d0
1990	     *
1991	     * h: 1, if horizontal roller data
1992	     *    0, if vertical roller data
1993	     * B4, B5: button 4 and 5
1994	     * s: sign bit
1995	     * d2-d0: roller data
1996	     *
1997	     * packet type: 2 (reserved)
1998	     */
1999	    if (((c & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
2000		    && (abs(x) > 191)
2001		    && MOUSE_PS2PLUS_CHECKBITS(sc->ipacket)) {
2002		/* the extended data packet encodes button and wheel events */
2003		switch (MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket)) {
2004		case 1:
2005		    /* wheel data packet */
2006		    x = y = 0;
2007		    if (sc->ipacket[2] & 0x80) {
2008			/* horizontal roller count - ignore it XXX*/
2009		    } else {
2010			/* vertical roller count */
2011			z = (sc->ipacket[2] & MOUSE_PS2PLUS_ZNEG)
2012			    ? (sc->ipacket[2] & 0x0f) - 16
2013			    : (sc->ipacket[2] & 0x0f);
2014		    }
2015		    ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
2016			? MOUSE_BUTTON4DOWN : 0;
2017		    ms.button |= (sc->ipacket[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
2018			? MOUSE_BUTTON5DOWN : 0;
2019		    break;
2020		case 2:
2021		    /* this packet type is reserved by Logitech... */
2022		    /*
2023		     * IBM ScrollPoint Mouse uses this packet type to
2024		     * encode both vertical and horizontal scroll movement.
2025		     */
2026		    x = y = 0;
2027		    /* horizontal count */
2028		    if (sc->ipacket[2] & 0x0f)
2029			z = (sc->ipacket[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
2030		    /* vertical count */
2031		    if (sc->ipacket[2] & 0xf0)
2032			z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
2033#if 0
2034		    /* vertical count */
2035		    z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG)
2036			? ((sc->ipacket[2] >> 4) & 0x0f) - 16
2037			: ((sc->ipacket[2] >> 4) & 0x0f);
2038		    /* horizontal count */
2039		    w = (sc->ipacket[2] & MOUSE_SPOINT_WNEG)
2040			? (sc->ipacket[2] & 0x0f) - 16
2041			: (sc->ipacket[2] & 0x0f);
2042#endif
2043		    break;
2044		case 0:
2045		    /* device type packet - shouldn't happen */
2046		    /* FALL THROUGH */
2047		default:
2048		    x = y = 0;
2049		    ms.button = ms.obutton;
2050		    if (bootverbose)
2051			log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
2052				       "0x%02x 0x%02x 0x%02x\n",
2053			    MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
2054			    sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
2055		    break;
2056		}
2057	    } else {
2058		/* preserve button states */
2059		ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
2060	    }
2061	    break;
2062
2063	case MOUSE_MODEL_GLIDEPOINT:
2064	    /* `tapping' action */
2065	    ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
2066	    break;
2067
2068	case MOUSE_MODEL_NETSCROLL:
2069	    /* three addtional bytes encode buttons and wheel events */
2070	    ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN)
2071		? MOUSE_BUTTON4DOWN : 0;
2072	    ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON1DOWN)
2073		? MOUSE_BUTTON5DOWN : 0;
2074	    z = (sc->ipacket[3] & MOUSE_PS2_XNEG)
2075		? sc->ipacket[4] - 256 : sc->ipacket[4];
2076	    break;
2077
2078	case MOUSE_MODEL_THINK:
2079	    /* the fourth button state in the first byte */
2080	    ms.button |= (c & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
2081	    break;
2082
2083	case MOUSE_MODEL_VERSAPAD:
2084	    /* VersaPad PS/2 absolute mode message format
2085	     *
2086	     * [packet1]     7   6   5   4   3   2   1   0(LSB)
2087	     *  ipacket[0]:  1   1   0   A   1   L   T   R
2088	     *  ipacket[1]: H7  H6  H5  H4  H3  H2  H1  H0
2089	     *  ipacket[2]: V7  V6  V5  V4  V3  V2  V1  V0
2090	     *  ipacket[3]:  1   1   1   A   1   L   T   R
2091	     *  ipacket[4]:V11 V10  V9  V8 H11 H10  H9  H8
2092	     *  ipacket[5]:  0  P6  P5  P4  P3  P2  P1  P0
2093	     *
2094	     * [note]
2095	     *  R: right physical mouse button (1=on)
2096	     *  T: touch pad virtual button (1=tapping)
2097	     *  L: left physical mouse button (1=on)
2098	     *  A: position data is valid (1=valid)
2099	     *  H: horizontal data (12bit signed integer. H11 is sign bit.)
2100	     *  V: vertical data (12bit signed integer. V11 is sign bit.)
2101	     *  P: pressure data
2102	     *
2103	     * Tapping is mapped to MOUSE_BUTTON4.
2104	     */
2105	    ms.button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS];
2106	    ms.button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
2107	    x = y = 0;
2108	    if (c & MOUSE_PS2VERSA_IN_USE) {
2109		x0 = sc->ipacket[1] | (((sc->ipacket[4]) & 0x0f) << 8);
2110		y0 = sc->ipacket[2] | (((sc->ipacket[4]) & 0xf0) << 4);
2111		if (x0 & 0x800)
2112		    x0 -= 0x1000;
2113		if (y0 & 0x800)
2114		    y0 -= 0x1000;
2115		if (sc->flags & PSM_FLAGS_FINGERDOWN) {
2116		    x = sc->xold - x0;
2117		    y = y0 - sc->yold;
2118		    if (x < 0)	/* XXX */
2119			x++;
2120		    else if (x)
2121			x--;
2122		    if (y < 0)
2123			y++;
2124		    else if (y)
2125			y--;
2126		} else {
2127		    sc->flags |= PSM_FLAGS_FINGERDOWN;
2128		}
2129		sc->xold = x0;
2130		sc->yold = y0;
2131	    } else {
2132		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
2133	    }
2134	    c = ((x < 0) ? MOUSE_PS2_XNEG : 0)
2135		| ((y < 0) ? MOUSE_PS2_YNEG : 0);
2136	    break;
2137
2138	case MOUSE_MODEL_4D:
2139	    /*
2140	     *          b7 b6 b5 b4 b3 b2 b1 b0
2141	     * byte 1:  s2 d2 s1 d1 1  M  R  L
2142	     * byte 2:  sx x  x  x  x  x  x  x
2143	     * byte 3:  sy y  y  y  y  y  y  y
2144	     *
2145	     * s1: wheel 1 direction
2146	     * d1: wheel 1 data
2147	     * s2: wheel 2 direction
2148	     * d2: wheel 2 data
2149	     */
2150	    x = (sc->ipacket[1] & 0x80) ? sc->ipacket[1] - 256 : sc->ipacket[1];
2151	    y = (sc->ipacket[2] & 0x80) ? sc->ipacket[2] - 256 : sc->ipacket[2];
2152	    switch (c & MOUSE_4D_WHEELBITS) {
2153	    case 0x10:
2154		z = 1;
2155		break;
2156	    case 0x30:
2157		z = -1;
2158		break;
2159	    case 0x40:	/* 2nd wheel turning right XXX */
2160		z = 2;
2161		break;
2162	    case 0xc0:	/* 2nd wheel turning left XXX */
2163		z = -2;
2164		break;
2165	    }
2166	    break;
2167
2168	case MOUSE_MODEL_4DPLUS:
2169	    if ((x < 16 - 256) && (y < 16 - 256)) {
2170		/*
2171		 *          b7 b6 b5 b4 b3 b2 b1 b0
2172		 * byte 1:  0  0  1  1  1  M  R  L
2173		 * byte 2:  0  0  0  0  1  0  0  0
2174		 * byte 3:  0  0  0  0  S  s  d1 d0
2175		 *
2176		 * L, M, R, S: left, middle, right and side buttons
2177		 * s: wheel data sign bit
2178		 * d1-d0: wheel data
2179		 */
2180		x = y = 0;
2181		if (sc->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
2182		    ms.button |= MOUSE_BUTTON4DOWN;
2183		z = (sc->ipacket[2] & MOUSE_4DPLUS_ZNEG)
2184			? ((sc->ipacket[2] & 0x07) - 8)
2185			: (sc->ipacket[2] & 0x07) ;
2186	    } else {
2187		/* preserve previous button states */
2188		ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
2189	    }
2190	    break;
2191
2192	case MOUSE_MODEL_GENERIC:
2193	default:
2194	    break;
2195	}
2196
2197        /* scale values */
2198        if (sc->mode.accelfactor >= 1) {
2199            if (x != 0) {
2200                x = x * x / sc->mode.accelfactor;
2201                if (x == 0)
2202                    x = 1;
2203                if (c & MOUSE_PS2_XNEG)
2204                    x = -x;
2205            }
2206            if (y != 0) {
2207                y = y * y / sc->mode.accelfactor;
2208                if (y == 0)
2209                    y = 1;
2210                if (c & MOUSE_PS2_YNEG)
2211                    y = -y;
2212            }
2213        }
2214
2215        ms.dx = x;
2216        ms.dy = y;
2217        ms.dz = z;
2218        ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0)
2219	    | (ms.obutton ^ ms.button);
2220
2221	if (sc->mode.level < PSM_LEVEL_NATIVE)
2222	    sc->inputbytes = tame_mouse(sc, &ms, sc->ipacket);
2223
2224        sc->status.flags |= ms.flags;
2225        sc->status.dx += ms.dx;
2226        sc->status.dy += ms.dy;
2227        sc->status.dz += ms.dz;
2228        sc->status.button = ms.button;
2229        sc->button = ms.button;
2230
2231	sc->watchdog = FALSE;
2232
2233        /* queue data */
2234        if (sc->queue.count + sc->inputbytes < sizeof(sc->queue.buf)) {
2235	    l = min(sc->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail);
2236	    bcopy(&sc->ipacket[0], &sc->queue.buf[sc->queue.tail], l);
2237	    if (sc->inputbytes > l)
2238	        bcopy(&sc->ipacket[l], &sc->queue.buf[0], sc->inputbytes - l);
2239            sc->queue.tail =
2240		(sc->queue.tail + sc->inputbytes) % sizeof(sc->queue.buf);
2241            sc->queue.count += sc->inputbytes;
2242	}
2243        sc->inputbytes = 0;
2244
2245        if (sc->state & PSM_ASLP) {
2246            sc->state &= ~PSM_ASLP;
2247            wakeup((caddr_t) sc);
2248    	}
2249        selwakeup(&sc->rsel);
2250    }
2251}
2252
2253static int
2254psmpoll(dev_t dev, int events, struct proc *p)
2255{
2256    struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));
2257    int s;
2258    int revents = 0;
2259
2260    /* Return true if a mouse event available */
2261    s = spltty();
2262    if (events & (POLLIN | POLLRDNORM)) {
2263	if (sc->queue.count > 0)
2264	    revents |= events & (POLLIN | POLLRDNORM);
2265	else
2266	    selrecord(p, &sc->rsel);
2267    }
2268    splx(s);
2269
2270    return (revents);
2271}
2272
2273/* vendor/model specific routines */
2274
2275static int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status)
2276{
2277    if (set_mouse_resolution(kbdc, res) != res)
2278        return FALSE;
2279    if (set_mouse_scaling(kbdc, scale)
2280	&& set_mouse_scaling(kbdc, scale)
2281	&& set_mouse_scaling(kbdc, scale)
2282	&& (get_mouse_status(kbdc, status, 0, 3) >= 3))
2283	return TRUE;
2284    return FALSE;
2285}
2286
2287static int
2288mouse_ext_command(KBDC kbdc, int command)
2289{
2290    int c;
2291
2292    c = (command >> 6) & 0x03;
2293    if (set_mouse_resolution(kbdc, c) != c)
2294	return FALSE;
2295    c = (command >> 4) & 0x03;
2296    if (set_mouse_resolution(kbdc, c) != c)
2297	return FALSE;
2298    c = (command >> 2) & 0x03;
2299    if (set_mouse_resolution(kbdc, c) != c)
2300	return FALSE;
2301    c = (command >> 0) & 0x03;
2302    if (set_mouse_resolution(kbdc, c) != c)
2303	return FALSE;
2304    return TRUE;
2305}
2306
2307#if notyet
2308/* Logitech MouseMan Cordless II */
2309static int
2310enable_lcordless(struct psm_softc *sc)
2311{
2312    int status[3];
2313    int ch;
2314
2315    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 2, status))
2316        return FALSE;
2317    if (status[1] == PSMD_RES_HIGH)
2318	return FALSE;
2319    ch = (status[0] & 0x07) - 1;	/* channel # */
2320    if ((ch <= 0) || (ch > 4))
2321	return FALSE;
2322    /*
2323     * status[1]: always one?
2324     * status[2]: battery status? (0-100)
2325     */
2326    return TRUE;
2327}
2328#endif /* notyet */
2329
2330/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
2331static int
2332enable_groller(struct psm_softc *sc)
2333{
2334    int status[3];
2335
2336    /*
2337     * The special sequence to enable the fourth button and the
2338     * roller. Immediately after this sequence check status bytes.
2339     * if the mouse is NetScroll, the second and the third bytes are
2340     * '3' and 'D'.
2341     */
2342
2343    /*
2344     * If the mouse is an ordinary PS/2 mouse, the status bytes should
2345     * look like the following.
2346     *
2347     * byte 1 bit 7 always 0
2348     *        bit 6 stream mode (0)
2349     *        bit 5 disabled (0)
2350     *        bit 4 1:1 scaling (0)
2351     *        bit 3 always 0
2352     *        bit 0-2 button status
2353     * byte 2 resolution (PSMD_RES_HIGH)
2354     * byte 3 report rate (?)
2355     */
2356
2357    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
2358        return FALSE;
2359    if ((status[1] != '3') || (status[2] != 'D'))
2360        return FALSE;
2361    /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
2362    sc->hw.buttons = 4;
2363    return TRUE;
2364}
2365
2366/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
2367static int
2368enable_gmouse(struct psm_softc *sc)
2369{
2370    int status[3];
2371
2372    /*
2373     * The special sequence to enable the middle, "rubber" button.
2374     * Immediately after this sequence check status bytes.
2375     * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse,
2376     * the second and the third bytes are '3' and 'U'.
2377     * NOTE: NetMouse reports that it has three buttons although it has
2378     * two buttons and a rubber button. NetMouse Pro and MIE Mouse
2379     * say they have three buttons too and they do have a button on the
2380     * side...
2381     */
2382    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status))
2383        return FALSE;
2384    if ((status[1] != '3') || (status[2] != 'U'))
2385        return FALSE;
2386    return TRUE;
2387}
2388
2389/* ALPS GlidePoint */
2390static int
2391enable_aglide(struct psm_softc *sc)
2392{
2393    int status[3];
2394
2395    /*
2396     * The special sequence to obtain ALPS GlidePoint specific
2397     * information. Immediately after this sequence, status bytes will
2398     * contain something interesting.
2399     * NOTE: ALPS produces several models of GlidePoint. Some of those
2400     * do not respond to this sequence, thus, cannot be detected this way.
2401     */
2402    if (set_mouse_sampling_rate(sc->kbdc, 100) != 100)
2403	return FALSE;
2404    if (!mouse_id_proc1(sc->kbdc, PSMD_RES_LOW, 2, status))
2405        return FALSE;
2406    if ((status[1] == PSMD_RES_LOW) || (status[2] == 100))
2407        return FALSE;
2408    return TRUE;
2409}
2410
2411/* Kensington ThinkingMouse/Trackball */
2412static int
2413enable_kmouse(struct psm_softc *sc)
2414{
2415    static unsigned char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
2416    KBDC kbdc = sc->kbdc;
2417    int status[3];
2418    int id1;
2419    int id2;
2420    int i;
2421
2422    id1 = get_aux_id(kbdc);
2423    if (set_mouse_sampling_rate(kbdc, 10) != 10)
2424	return FALSE;
2425    /*
2426     * The device is now in the native mode? It returns a different
2427     * ID value...
2428     */
2429    id2 = get_aux_id(kbdc);
2430    if ((id1 == id2) || (id2 != 2))
2431	return FALSE;
2432
2433    if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW)
2434        return FALSE;
2435#if PSM_DEBUG >= 2
2436    /* at this point, resolution is LOW, sampling rate is 10/sec */
2437    if (get_mouse_status(kbdc, status, 0, 3) < 3)
2438        return FALSE;
2439#endif
2440
2441    /*
2442     * The special sequence to enable the third and fourth buttons.
2443     * Otherwise they behave like the first and second buttons.
2444     */
2445    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
2446        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
2447	    return FALSE;
2448    }
2449
2450    /*
2451     * At this point, the device is using default resolution and
2452     * sampling rate for the native mode.
2453     */
2454    if (get_mouse_status(kbdc, status, 0, 3) < 3)
2455        return FALSE;
2456    if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1]))
2457        return FALSE;
2458
2459    /* the device appears be enabled by this sequence, diable it for now */
2460    disable_aux_dev(kbdc);
2461    empty_aux_buffer(kbdc, 5);
2462
2463    return TRUE;
2464}
2465
2466/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
2467static int
2468enable_mmanplus(struct psm_softc *sc)
2469{
2470    KBDC kbdc = sc->kbdc;
2471    int data[3];
2472
2473    /* the special sequence to enable the fourth button and the roller. */
2474    /*
2475     * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
2476     * must be called exactly three times since the last RESET command
2477     * before this sequence. XXX
2478     */
2479    if (!set_mouse_scaling(kbdc, 1))
2480	return FALSE;
2481    if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb))
2482	return FALSE;
2483    if (get_mouse_status(kbdc, data, 1, 3) < 3)
2484        return FALSE;
2485
2486    /*
2487     * PS2++ protocl, packet type 0
2488     *
2489     *          b7 b6 b5 b4 b3 b2 b1 b0
2490     * byte 1:  *  1  p3 p2 1  *  *  *
2491     * byte 2:  1  1  p1 p0 m1 m0 1  0
2492     * byte 3:  m7 m6 m5 m4 m3 m2 m1 m0
2493     *
2494     * p3-p0: packet type: 0
2495     * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51, ScrollPoint:0x58...
2496     */
2497    /* check constant bits */
2498    if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
2499        return FALSE;
2500    if ((data[1] & 0xc3) != 0xc2)
2501        return FALSE;
2502    /* check d3-d0 in byte 2 */
2503    if (!MOUSE_PS2PLUS_CHECKBITS(data))
2504        return FALSE;
2505    /* check p3-p0 */
2506    if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0)
2507        return FALSE;
2508
2509    sc->hw.hwid &= 0x00ff;
2510    sc->hw.hwid |= data[2] << 8;	/* save model ID */
2511
2512    /*
2513     * MouseMan+ (or FirstMouse+) is now in its native mode, in which
2514     * the wheel and the fourth button events are encoded in the
2515     * special data packet. The mouse may be put in the IntelliMouse mode
2516     * if it is initialized by the IntelliMouse's method.
2517     */
2518    return TRUE;
2519}
2520
2521/* MS IntelliMouse Explorer */
2522static int
2523enable_msexplorer(struct psm_softc *sc)
2524{
2525    static unsigned char rate0[] = { 200, 100, 80, };
2526    static unsigned char rate1[] = { 200, 200, 80, };
2527    KBDC kbdc = sc->kbdc;
2528    int id;
2529    int i;
2530
2531    /* the special sequence to enable the extra buttons and the roller. */
2532    for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i) {
2533        if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i])
2534	    return FALSE;
2535    }
2536    /* the device will give the genuine ID only after the above sequence */
2537    id = get_aux_id(kbdc);
2538    if (id != PSM_EXPLORER_ID)
2539	return FALSE;
2540
2541    sc->hw.hwid = id;
2542    sc->hw.buttons = 5;		/* IntelliMouse Explorer XXX */
2543
2544    /*
2545     * XXX: this is a kludge to fool some KVM switch products
2546     * which think they are clever enough to know the 4-byte IntelliMouse
2547     * protocol, and assume any other protocols use 3-byte packets.
2548     * They don't convey 4-byte data packets from the IntelliMouse Explorer
2549     * correctly to the host computer because of this!
2550     * The following sequence is actually IntelliMouse's "wake up"
2551     * sequence; it will make the KVM think the mouse is IntelliMouse
2552     * when it is in fact IntelliMouse Explorer.
2553     */
2554    for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i) {
2555        if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i])
2556	    break;
2557    }
2558    id = get_aux_id(kbdc);
2559
2560    return TRUE;
2561}
2562
2563/* MS IntelliMouse */
2564static int
2565enable_msintelli(struct psm_softc *sc)
2566{
2567    /*
2568     * Logitech MouseMan+ and FirstMouse+ will also respond to this
2569     * probe routine and act like IntelliMouse.
2570     */
2571
2572    static unsigned char rate[] = { 200, 100, 80, };
2573    KBDC kbdc = sc->kbdc;
2574    int id;
2575    int i;
2576
2577    /* the special sequence to enable the third button and the roller. */
2578    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
2579        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
2580	    return FALSE;
2581    }
2582    /* the device will give the genuine ID only after the above sequence */
2583    id = get_aux_id(kbdc);
2584    if (id != PSM_INTELLI_ID)
2585	return FALSE;
2586
2587    sc->hw.hwid = id;
2588    sc->hw.buttons = 3;
2589
2590    return TRUE;
2591}
2592
2593/* A4 Tech 4D Mouse */
2594static int
2595enable_4dmouse(struct psm_softc *sc)
2596{
2597    /*
2598     * Newer wheel mice from A4 Tech may use the 4D+ protocol.
2599     */
2600
2601    static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
2602    KBDC kbdc = sc->kbdc;
2603    int id;
2604    int i;
2605
2606    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
2607        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
2608	    return FALSE;
2609    }
2610    id = get_aux_id(kbdc);
2611    /*
2612     * WinEasy 4D, 4 Way Scroll 4D: 6
2613     * Cable-Free 4D: 8 (4DPLUS)
2614     * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS)
2615     */
2616    if (id != PSM_4DMOUSE_ID)
2617	return FALSE;
2618
2619    sc->hw.hwid = id;
2620    sc->hw.buttons = 3;		/* XXX some 4D mice have 4? */
2621
2622    return TRUE;
2623}
2624
2625/* A4 Tech 4D+ Mouse */
2626static int
2627enable_4dplus(struct psm_softc *sc)
2628{
2629    /*
2630     * Newer wheel mice from A4 Tech seem to use this protocol.
2631     * Older models are recognized as either 4D Mouse or IntelliMouse.
2632     */
2633    KBDC kbdc = sc->kbdc;
2634    int id;
2635
2636    /*
2637     * enable_4dmouse() already issued the following ID sequence...
2638    static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
2639    int i;
2640
2641    for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
2642        if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
2643	    return FALSE;
2644    }
2645    */
2646
2647    id = get_aux_id(kbdc);
2648    if (id != PSM_4DPLUS_ID)
2649	return FALSE;
2650
2651    sc->hw.hwid = id;
2652    sc->hw.buttons = 4;		/* XXX */
2653
2654    return TRUE;
2655}
2656
2657/* Interlink electronics VersaPad */
2658static int
2659enable_versapad(struct psm_softc *sc)
2660{
2661    KBDC kbdc = sc->kbdc;
2662    int data[3];
2663
2664    set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */
2665    set_mouse_sampling_rate(kbdc, 100);		/* set rate 100 */
2666    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
2667    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
2668    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
2669    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
2670    if (get_mouse_status(kbdc, data, 0, 3) < 3)	/* get status */
2671	return FALSE;
2672    if (data[2] != 0xa || data[1] != 0 )	/* rate == 0xa && res. == 0 */
2673	return FALSE;
2674    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
2675
2676    sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
2677
2678    return TRUE;				/* PS/2 absolute mode */
2679}
2680
2681static int
2682psmresume(device_t dev)
2683{
2684    struct psm_softc *sc = device_get_softc(dev);
2685    int unit = device_get_unit(dev);
2686    int err = 0;
2687    int s;
2688    int c;
2689
2690    if (verbose >= 2)
2691        log(LOG_NOTICE, "psm%d: system resume hook called.\n", unit);
2692
2693    if (!(sc->config & PSM_CONFIG_HOOKRESUME))
2694	return (0);
2695
2696    /* don't let anybody mess with the aux device */
2697    if (!kbdc_lock(sc->kbdc, TRUE))
2698	return (EIO);
2699    s = spltty();
2700
2701    /* block our watchdog timer */
2702    sc->watchdog = FALSE;
2703    untimeout(psmtimeout, (void *)(uintptr_t)unit, sc->callout);
2704    callout_handle_init(&sc->callout);
2705
2706    /* save the current controller command byte */
2707    empty_both_buffers(sc->kbdc, 10);
2708    c = get_controller_command_byte(sc->kbdc);
2709    if (verbose >= 2)
2710        log(LOG_DEBUG, "psm%d: current command byte: %04x (psmresume).\n",
2711	    unit, c);
2712
2713    /* enable the aux port but disable the aux interrupt and the keyboard */
2714    if ((c == -1) || !set_controller_command_byte(sc->kbdc,
2715	    kbdc_get_device_mask(sc->kbdc),
2716  	    KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
2717	        | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
2718        /* CONTROLLER ERROR */
2719	splx(s);
2720        kbdc_lock(sc->kbdc, FALSE);
2721	log(LOG_ERR, "psm%d: unable to set the command byte (psmresume).\n",
2722	    unit);
2723	return (EIO);
2724    }
2725
2726    /* flush any data */
2727    if (sc->state & PSM_VALID) {
2728	disable_aux_dev(sc->kbdc);	/* this may fail; but never mind... */
2729	empty_aux_buffer(sc->kbdc, 10);
2730    }
2731    sc->inputbytes = 0;
2732
2733    /* try to detect the aux device; are you still there? */
2734    if (sc->config & PSM_CONFIG_INITAFTERSUSPEND) {
2735	if (reinitialize(unit, &sc->mode)) {
2736	    /* yes */
2737	    sc->state |= PSM_VALID;
2738	} else {
2739	    /* the device has gone! */
2740	    restore_controller(sc->kbdc, c);
2741	    sc->state &= ~PSM_VALID;
2742	    log(LOG_ERR, "psm%d: the aux device has gone! (psmresume).\n",
2743		unit);
2744	    err = ENXIO;
2745	}
2746    }
2747    splx(s);
2748
2749    /* restore the driver state */
2750    if ((sc->state & PSM_OPEN) && (err == 0)) {
2751        /* enable the aux device and the port again */
2752	err = doopen(unit, c);
2753	if (err != 0)
2754	    log(LOG_ERR, "psm%d: failed to enable the device (psmresume).\n",
2755		unit);
2756    } else {
2757        /* restore the keyboard port and disable the aux port */
2758        if (!set_controller_command_byte(sc->kbdc,
2759                kbdc_get_device_mask(sc->kbdc),
2760                (c & KBD_KBD_CONTROL_BITS)
2761                    | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
2762            /* CONTROLLER ERROR */
2763            log(LOG_ERR, "psm%d: failed to disable the aux port (psmresume).\n",
2764                unit);
2765            err = EIO;
2766	}
2767    }
2768
2769    /* done */
2770    kbdc_lock(sc->kbdc, FALSE);
2771    if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) {
2772	/*
2773	 * Release the blocked process; it must be notified that the device
2774	 * cannot be accessed anymore.
2775	 */
2776        sc->state &= ~PSM_ASLP;
2777        wakeup((caddr_t)sc);
2778    }
2779
2780    if (verbose >= 2)
2781        log(LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit);
2782
2783    return (err);
2784}
2785
2786DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
2787