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