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