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