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