xref: /onnv-gate/usr/src/uts/common/io/vuidmice/vuidps2.c (revision 993:d22cfce406aa)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * 			2/3/5 Button PS/2 Mouse Protocol
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * This module dynamically determines the number of buttons on the mouse.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/param.h>
360Sstevel@tonic-gate #include <sys/stream.h>
370Sstevel@tonic-gate #include <sys/vuid_event.h>
380Sstevel@tonic-gate #include <sys/vuidmice.h>
390Sstevel@tonic-gate #include <sys/vuid_wheel.h>
400Sstevel@tonic-gate #include <sys/mouse.h>
410Sstevel@tonic-gate #include <sys/ddi.h>
420Sstevel@tonic-gate #include <sys/sunddi.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * BUT(1)		LEFT   BUTTON
460Sstevel@tonic-gate  * BUT(2)		MIDDLE BUTTON (if present)
470Sstevel@tonic-gate  * BUT(3)		RIGHT  BUTTON
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #define	PS2_BUTTONMASK		7		/* mask byte zero with this */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	PS2_BUTTON_L		(uchar_t)0x01	/* Left button pressed */
530Sstevel@tonic-gate #define	PS2_BUTTON_R		(uchar_t)0x02	/* Right button pressed */
540Sstevel@tonic-gate #define	PS2_BUTTON_M		(uchar_t)0x04	/* Middle button pressed */
550Sstevel@tonic-gate #define	PS2_DATA_XSIGN		(uchar_t)0x10	/* X data sign bit */
560Sstevel@tonic-gate #define	PS2_DATA_YSIGN		(uchar_t)0x20	/* Y data sign bit */
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #define	PS2_START			0	/* Beginning of packet	*/
590Sstevel@tonic-gate #define	PS2_BUTTON			1	/* Got button status	*/
600Sstevel@tonic-gate #define	PS2_MAYBE_REATTACH		2	/* Got button status	*/
610Sstevel@tonic-gate #define	PS2_DELTA_Y			3	/* Got delta X		*/
620Sstevel@tonic-gate #define	PS2_WHEEL_DELTA_Z		4
630Sstevel@tonic-gate #define	PS2_WHEEL5_DELTA_Z		5
640Sstevel@tonic-gate #define	PS2_WAIT_RESET_ACK		6
650Sstevel@tonic-gate #define	PS2_WAIT_RESET_AA		7
660Sstevel@tonic-gate #define	PS2_WAIT_RESET_00		8
670Sstevel@tonic-gate #define	PS2_WAIT_SETRES0_ACK1		9
680Sstevel@tonic-gate #define	PS2_WAIT_SETRES0_ACK2		10	/* -+ must be consecutive */
690Sstevel@tonic-gate #define	PS2_WAIT_SCALE1_1_ACK		11	/*  | */
700Sstevel@tonic-gate #define	PS2_WAIT_SCALE1_2_ACK		12	/*  | */
710Sstevel@tonic-gate #define	PS2_WAIT_SCALE1_3_ACK		13	/* -+ */
720Sstevel@tonic-gate #define	PS2_WAIT_STATREQ_ACK		14
730Sstevel@tonic-gate #define	PS2_WAIT_STATUS_1		15
740Sstevel@tonic-gate #define	PS2_WAIT_STATUS_BUTTONS		16
750Sstevel@tonic-gate #define	PS2_WAIT_STATUS_REV		17
760Sstevel@tonic-gate #define	PS2_WAIT_STATUS_3		18
770Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_SMPL1_CMD_ACK	19	/* Set the sample rate to 200 */
780Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_SMPL1_RATE_ACK	20
790Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_SMPL2_CMD_ACK	21	/* Set the sample rate to 200 */
800Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_SMPL2_RATE_ACK	22
810Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_SMPL3_CMD_ACK	23	/* Set the sample rate to 80 */
820Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_SMPL3_RATE_ACK	24
830Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_DEV_CMD		25
840Sstevel@tonic-gate #define	PS2_WAIT_WHEEL_DEV_ACK		26	/* Detected wheel mouse */
850Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_SMPL1_CMD_ACK	27	/* Set the sample rate to 200 */
860Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_SMPL1_RATE_ACK	28
870Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_SMPL2_CMD_ACK	29	/* Set the sample rate to 200 */
880Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_SMPL2_RATE_ACK	30
890Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_SMPL3_CMD_ACK	31	/* Set the sample rate to 100 */
900Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_SMPL3_RATE_ACK	32
910Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_DEV_CMD		33
920Sstevel@tonic-gate #define	PS2_WAIT_WHEEL5_DEV_ACK		34	/* Detected 5 button mouse */
930Sstevel@tonic-gate #define	PS2_WAIT_SETRES3_CMD		35
940Sstevel@tonic-gate #define	PS2_WAIT_SETRES3_ACK1		36
950Sstevel@tonic-gate #define	PS2_WAIT_SETRES3_ACK2		37
960Sstevel@tonic-gate #define	PS2_WAIT_STREAM_ACK		38
970Sstevel@tonic-gate #define	PS2_WAIT_ON_ACK			39
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #define	MSE_AA		0xaa
1000Sstevel@tonic-gate #define	MSE_00		0x00
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate #define	MOUSE_MODE_PLAIN	0	/* Normal PS/2 mouse - 3 byte msgs */
1030Sstevel@tonic-gate #define	MOUSE_MODE_WHEEL	1	/* Wheel mouse - 4 byte msgs */
1040Sstevel@tonic-gate #define	MOUSE_MODE_WHEEL5	2	/* Wheel + 5 btn mouse - 4 byte msgs */
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate #define	PS2_FLAG_NO_EXTN	0x08	/* Mouse doesn't obey extended cmds */
1070Sstevel@tonic-gate #define	PS2_FLAG_INIT_DONE	0x01	/* Mouse has been inited successfully */
1080Sstevel@tonic-gate #define	PS2_FLAG_INIT_TIMEOUT	0x02	/* Mouse init timeout */
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate  * The RESET command takes more time
1120Sstevel@tonic-gate  * before the PS/2 mouse is ready
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate #define	PS2_INIT_TMOUT_RESET	500000	/* 500ms for RESET command */
1150Sstevel@tonic-gate #define	PS2_INIT_TMOUT_PER_CMD	200000	/* 200ms for each command-response */
116*993Slq150181 #define	PS2_INIT_TMOUT_PER_GROUP	500000 /* 500ms for group commands */
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate #define	PS2_MAX_INIT_COUNT	5
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate static void vuidmice_send_wheel_event(queue_t *const, uchar_t,
1220Sstevel@tonic-gate 		uchar_t, uchar_t, int);
1230Sstevel@tonic-gate extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int);
1240Sstevel@tonic-gate extern void uniqtime32(struct timeval32 *);
1250Sstevel@tonic-gate static void VUID_INIT_TIMEOUT(void *q);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate  * We apply timeout to nearly each command-response
1290Sstevel@tonic-gate  * during initialization:
1300Sstevel@tonic-gate  *
1310Sstevel@tonic-gate  * Set timeout for RESET
1320Sstevel@tonic-gate  * Set timeout for SET RESOLUTION
1330Sstevel@tonic-gate  * Set timeout for SET SCALE
1340Sstevel@tonic-gate  * Set timeout for SET SAMPLE RATE
1350Sstevel@tonic-gate  * Set timeout for STATUS REQUEST
1360Sstevel@tonic-gate  * Set timeout for GET DEV
1370Sstevel@tonic-gate  * Set timeout for SET STREAM MODE and ENABLE.
1380Sstevel@tonic-gate  *
1390Sstevel@tonic-gate  * But for simplicity, sometimes we just apply the timeout
140*993Slq150181  * to a function with group commands (e.g. wheel-mouse detection).
1410Sstevel@tonic-gate  *
1420Sstevel@tonic-gate  */
1430Sstevel@tonic-gate static void
1440Sstevel@tonic-gate vuid_set_timeout(queue_t *const qp, clock_t time)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	ASSERT(STATEP->init_tid == 0);
1470Sstevel@tonic-gate 	STATEP->init_tid = qtimeout(qp, VUID_INIT_TIMEOUT,
1480Sstevel@tonic-gate 	    qp, drv_usectohz(time));
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate static void
1520Sstevel@tonic-gate vuid_cancel_timeout(queue_t *const qp)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate 	ASSERT(STATEP->init_tid != 0);
1550Sstevel@tonic-gate 	(void) quntimeout(qp, STATEP->init_tid);
1560Sstevel@tonic-gate 	STATEP->init_tid = 0;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate  * vuidmice_send_wheel_event
1610Sstevel@tonic-gate  *	Convert wheel data to firm_events
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate static void
1640Sstevel@tonic-gate vuidmice_send_wheel_event(queue_t *const qp, uchar_t event_id,
1650Sstevel@tonic-gate     uchar_t event_pair_type, uchar_t event_pair, int event_value)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate 	mblk_t		*bp;
1680Sstevel@tonic-gate 	Firm_event	*fep;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	if ((bp = allocb((int)sizeof (Firm_event), BPRI_HI)) == NULL) {
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 		return;
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	fep = (Firm_event *)bp->b_wptr;
1760Sstevel@tonic-gate 	fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) |
1770Sstevel@tonic-gate 	    vuid_id_offset(event_id);
1780Sstevel@tonic-gate 	fep->pair_type = event_pair_type;
1790Sstevel@tonic-gate 	fep->pair = event_pair;
1800Sstevel@tonic-gate 	fep->value = event_value;
1810Sstevel@tonic-gate 	uniqtime32(&fep->time);
1820Sstevel@tonic-gate 	bp->b_wptr += sizeof (Firm_event);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (canput(qp->q_next)) {
1850Sstevel@tonic-gate 		putnext(qp, bp);
1860Sstevel@tonic-gate 	} else {
1870Sstevel@tonic-gate 		(void) putbq(qp, bp); /* read side is blocked */
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate static void
1930Sstevel@tonic-gate sendButtonEvent(queue_t *const qp)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	static int bmap[3] = {1, 3, 2};
1960Sstevel@tonic-gate 	uint_t b;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	/* for each button, see if it has changed */
1990Sstevel@tonic-gate 	for (b = 0; b < STATEP->nbuttons; b++) {
2000Sstevel@tonic-gate 		uchar_t	mask = 0x1 << b;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 		if ((STATEP->buttons & mask) != (STATEP->oldbuttons & mask))
2030Sstevel@tonic-gate 			VUID_PUTNEXT(qp, (uchar_t)BUT(bmap[b]), FE_PAIR_NONE, 0,
2040Sstevel@tonic-gate 				(STATEP->buttons & mask ? 1 : 0));
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate void
2090Sstevel@tonic-gate put1(queue_t *const qp, int c)
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate 	mblk_t *bp;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if (bp = allocb(1, BPRI_MED)) {
2140Sstevel@tonic-gate 		*bp->b_wptr++ = (char)c;
2150Sstevel@tonic-gate 		putnext(qp, bp);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate int
2200Sstevel@tonic-gate VUID_OPEN(queue_t *const qp)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	STATEP->format = VUID_FIRM_EVENT;
2230Sstevel@tonic-gate 	STATEP->vuid_mouse_mode = MOUSE_MODE_PLAIN;
2240Sstevel@tonic-gate 	STATEP->inited = 0;
2250Sstevel@tonic-gate 	STATEP->nbuttons = 3;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	STATEP->state = PS2_WAIT_RESET_ACK;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	/* Set timeout for reset */
2300Sstevel@tonic-gate 	vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
2310Sstevel@tonic-gate 
232*993Slq150181 	put1(WR(qp), MSERESET);
233*993Slq150181 
2340Sstevel@tonic-gate 	while ((STATEP->state != PS2_START) &&
2350Sstevel@tonic-gate 	    !(STATEP->inited & PS2_FLAG_INIT_TIMEOUT)) {
2360Sstevel@tonic-gate 		if (qwait_sig(qp) == 0)
2370Sstevel@tonic-gate 			break;
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	/*
2410Sstevel@tonic-gate 	 * Later the PS/2 mouse maybe re-attach, so here
2420Sstevel@tonic-gate 	 * clear the init_count.
2430Sstevel@tonic-gate 	 */
2440Sstevel@tonic-gate 	STATEP->init_count = 0;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	return (0);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate void
2500Sstevel@tonic-gate VUID_CLOSE(queue_t *const qp)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	if (STATEP->init_tid != 0)
2530Sstevel@tonic-gate 		vuid_cancel_timeout(qp);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate static void
2570Sstevel@tonic-gate VUID_INIT_TIMEOUT(void *q)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	queue_t	*qp = q;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	STATEP->init_tid = 0;
2620Sstevel@tonic-gate 
263822Ssethg 	/*
264822Ssethg 	 * Some mice do not even send an error in response to
265822Ssethg 	 * the wheel mouse sample commands, so if we're in any of
266822Ssethg 	 * the PS2_WAIT_WHEEL_SMPL* states, and there has been
267822Ssethg 	 * a timeout, assume the mouse cannot handle the extended
268822Ssethg 	 * (wheel mouse) commands.
269822Ssethg 	 */
270822Ssethg 	if ((STATEP->state == PS2_WAIT_WHEEL_SMPL1_CMD_ACK) ||
271822Ssethg 	    (STATEP->state == PS2_WAIT_WHEEL_SMPL1_RATE_ACK) ||
2720Sstevel@tonic-gate 	    (STATEP->state == PS2_WAIT_WHEEL_SMPL2_RATE_ACK) ||
2730Sstevel@tonic-gate 	    (STATEP->state == PS2_WAIT_WHEEL_SMPL3_RATE_ACK)) {
2740Sstevel@tonic-gate 		/*
2750Sstevel@tonic-gate 		 * We overload 'inited' to mark the PS/2 mouse
2760Sstevel@tonic-gate 		 * as one which doesn't respond to extended commands.
2770Sstevel@tonic-gate 		 */
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		STATEP->inited |= PS2_FLAG_NO_EXTN;
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) {
2830Sstevel@tonic-gate 		STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
2840Sstevel@tonic-gate 		return;
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	STATEP->state = PS2_WAIT_RESET_ACK;
2890Sstevel@tonic-gate 
290*993Slq150181 	vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
291*993Slq150181 
2920Sstevel@tonic-gate 	/* try again */
2930Sstevel@tonic-gate 	put1(WR(qp), MSERESET);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate void
2970Sstevel@tonic-gate VUID_QUEUE(queue_t *const qp, mblk_t *mp)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	int code;
3000Sstevel@tonic-gate 	clock_t now;
3010Sstevel@tonic-gate 	clock_t elapsed;
3020Sstevel@tonic-gate 	clock_t mouse_timeout;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	mouse_timeout = drv_usectohz(250000);
3050Sstevel@tonic-gate 	now = ddi_get_lbolt();
3060Sstevel@tonic-gate 	elapsed = now - STATEP->last_event_lbolt;
3070Sstevel@tonic-gate 	STATEP->last_event_lbolt = now;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	while (mp->b_rptr < mp->b_wptr) {
3100Sstevel@tonic-gate 		code = *mp->b_rptr++;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 		switch (STATEP->state) {
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 		/*
3150Sstevel@tonic-gate 		 * Start state. We stay here if the start code is not
3160Sstevel@tonic-gate 		 * received thus forcing us back into sync. When we get a
3170Sstevel@tonic-gate 		 * start code the button mask comes with it forcing us to
3180Sstevel@tonic-gate 		 * to the next state.
3190Sstevel@tonic-gate 		 */
3200Sstevel@tonic-gate restart:
3210Sstevel@tonic-gate 		case PS2_START:
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 			/*
3240Sstevel@tonic-gate 			 * 3-byte packet format
3250Sstevel@tonic-gate 			 *
3260Sstevel@tonic-gate 			 * Bit   7   6    5	4	3   2	1	0
3270Sstevel@tonic-gate 			 * Byte ---- ---- ----- ----- -- ------ ------ ------
3280Sstevel@tonic-gate 			 * 1    Y_Ov X_Ov Y_Sgn X_Sgn  1 MdlBtn RgtBtn LftBtn
3290Sstevel@tonic-gate 			 * 2    |<--------------X Movement----------------->|
3300Sstevel@tonic-gate 			 * 3    |<--------------Y Movement----------------->|
3310Sstevel@tonic-gate 			 *
3320Sstevel@tonic-gate 			 * 4-byte wheel packet format
3330Sstevel@tonic-gate 			 *
3340Sstevel@tonic-gate 			 * Bit   7    6   5	4	3   2	1	0
3350Sstevel@tonic-gate 			 * Byte ---- ---- ----- ----- -- ------ ------ ------
3360Sstevel@tonic-gate 			 * 1    Y_Ov X_Ov Y_Sgn X_Sgn  1 MdlBtn RgtBtn LftBtn
3370Sstevel@tonic-gate 			 * 2    |<--------------X Movement----------------->|
3380Sstevel@tonic-gate 			 * 3    |<--------------Y Movement----------------->|
3390Sstevel@tonic-gate 			 * 4    |<--------------Z Movement----------------->|
3400Sstevel@tonic-gate 			 *
3410Sstevel@tonic-gate 			 * 4-byte wheel+5 packet format
3420Sstevel@tonic-gate 			 *
3430Sstevel@tonic-gate 			 * Bit   7    6   5	4	3   2	1	0
3440Sstevel@tonic-gate 			 * Byte ---- ---- ----- ----- -- ------ ------ ------
3450Sstevel@tonic-gate 			 * 1    Y_Ov X_Ov Y_Sgn X_Sgn  1 MdlBtn RgtBtn LftBtn
3460Sstevel@tonic-gate 			 * 2    |<--------------X Movement----------------->|
3470Sstevel@tonic-gate 			 * 3    |<--------------Y Movement----------------->|
3480Sstevel@tonic-gate 			 * 4	0    0   5_Btn 4_Btn Z3   Z2	Z1	Z0
3490Sstevel@tonic-gate 			 */
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 			if (!(STATEP->inited & PS2_FLAG_INIT_DONE)) {
3520Sstevel@tonic-gate 				STATEP->sync_byte = code & 0x8;
3530Sstevel@tonic-gate 				STATEP->inited |= PS2_FLAG_INIT_DONE;
3540Sstevel@tonic-gate 			}
3550Sstevel@tonic-gate 		/*
3560Sstevel@tonic-gate 		 * the PS/2 mouse data format doesn't have any sort of sync
3570Sstevel@tonic-gate 		 * data to make sure we are in sync with the packet stream,
3580Sstevel@tonic-gate 		 * but the Technical Reference manual states that bits 2 & 3
3590Sstevel@tonic-gate 		 * of the first byte are reserved.  Logitech uses bit 2 for
3600Sstevel@tonic-gate 		 * the middle button.  We HOPE that noone uses bit 3 though,
3610Sstevel@tonic-gate 		 * and decide we're out of sync if bit 3 is not set here.
3620Sstevel@tonic-gate 		 */
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 			if ((code ^ STATEP->sync_byte) & 0x08) {
3650Sstevel@tonic-gate 				/* bit 3 not set */
3660Sstevel@tonic-gate 				STATEP->state = PS2_START;
3670Sstevel@tonic-gate 				break;			/* toss the code */
3680Sstevel@tonic-gate 			}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 			/* get the button values */
3710Sstevel@tonic-gate 			STATEP->buttons = code & PS2_BUTTONMASK;
3720Sstevel@tonic-gate 			if (STATEP->buttons != STATEP->oldbuttons) {
3730Sstevel@tonic-gate 				sendButtonEvent(qp);
3740Sstevel@tonic-gate 				STATEP->oldbuttons = STATEP->buttons;
3750Sstevel@tonic-gate 			}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 			/* bit 5 indicates Y value is negative (the sign bit) */
3780Sstevel@tonic-gate 			if (code & PS2_DATA_YSIGN)
3790Sstevel@tonic-gate 				STATEP->deltay = -1 & ~0xff;
3800Sstevel@tonic-gate 			else
3810Sstevel@tonic-gate 				STATEP->deltay = 0;
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 			/* bit 4 is X sign bit */
3840Sstevel@tonic-gate 			if (code & PS2_DATA_XSIGN)
3850Sstevel@tonic-gate 				STATEP->deltax = -1 & ~0xff;
3860Sstevel@tonic-gate 			else
3870Sstevel@tonic-gate 				STATEP->deltax = 0;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 			if (code == MSE_AA)
3900Sstevel@tonic-gate 				STATEP->state = PS2_MAYBE_REATTACH;
3910Sstevel@tonic-gate 			else
3920Sstevel@tonic-gate 				STATEP->state = PS2_BUTTON;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		case PS2_MAYBE_REATTACH:
3970Sstevel@tonic-gate 			if (code == MSE_00) {
3980Sstevel@tonic-gate 				STATEP->state = PS2_WAIT_RESET_ACK;
3990Sstevel@tonic-gate 				vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
400*993Slq150181 				put1(WR(qp), MSERESET);
4010Sstevel@tonic-gate 				break;
4020Sstevel@tonic-gate 			}
4030Sstevel@tonic-gate 			/*FALLTHROUGH*/
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 		case PS2_BUTTON:
4060Sstevel@tonic-gate 			/*
4070Sstevel@tonic-gate 			 * Now for the 7 bits of delta x.  "Or" in
4080Sstevel@tonic-gate 			 * the sign bit and continue.  This is ac-
4090Sstevel@tonic-gate 			 * tually a signed 9 bit number, but I just
4100Sstevel@tonic-gate 			 * truncate it to a signed char in order to
4110Sstevel@tonic-gate 			 * avoid changing and retesting all of the
4120Sstevel@tonic-gate 			 * mouse-related modules for this patch.
4130Sstevel@tonic-gate 			 */
4140Sstevel@tonic-gate 			if (elapsed > mouse_timeout)
4150Sstevel@tonic-gate 				goto restart;
4160Sstevel@tonic-gate 			STATEP->deltax |= code & 0xff;
4170Sstevel@tonic-gate 			STATEP->state = PS2_DELTA_Y;
4180Sstevel@tonic-gate 			break;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 		case PS2_DELTA_Y:
4210Sstevel@tonic-gate 			/*
4220Sstevel@tonic-gate 			 * This byte is delta Y.  If this is a plain mouse,
4230Sstevel@tonic-gate 			 * we're done.  Wheel mice have two different flavors
4240Sstevel@tonic-gate 			 * of fourth byte.
4250Sstevel@tonic-gate 			 */
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 			if (elapsed > mouse_timeout) {
4280Sstevel@tonic-gate 				goto restart;
4290Sstevel@tonic-gate 			}
4300Sstevel@tonic-gate 			STATEP->deltay |= code & 0xff;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 			if (STATEP->vuid_mouse_mode == MOUSE_MODE_WHEEL) {
4330Sstevel@tonic-gate 				STATEP->state = PS2_WHEEL_DELTA_Z;
4340Sstevel@tonic-gate 				break;
4350Sstevel@tonic-gate 			} else if (STATEP->vuid_mouse_mode ==
4360Sstevel@tonic-gate 			    MOUSE_MODE_WHEEL5) {
4370Sstevel@tonic-gate 				STATEP->state = PS2_WHEEL5_DELTA_Z;
4380Sstevel@tonic-gate 				break;
4390Sstevel@tonic-gate 			}
4400Sstevel@tonic-gate 			goto packet_complete;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		case PS2_WHEEL5_DELTA_Z:
4430Sstevel@tonic-gate 			if (code & 0x10) {
4440Sstevel@tonic-gate 				/* fourth physical button */
4450Sstevel@tonic-gate 				VUID_PUTNEXT(qp, (uchar_t)BUT(4),
4460Sstevel@tonic-gate 				    FE_PAIR_NONE, 0, 1);
4470Sstevel@tonic-gate 				VUID_PUTNEXT(qp, (uchar_t)BUT(4),
4480Sstevel@tonic-gate 				    FE_PAIR_NONE, 0, 0);
4490Sstevel@tonic-gate 			} else if (code & 0x20) {
4500Sstevel@tonic-gate 				/* fifth physical button */
4510Sstevel@tonic-gate 				VUID_PUTNEXT(qp, (uchar_t)BUT(5),
4520Sstevel@tonic-gate 				    FE_PAIR_NONE, 0, 1);
4530Sstevel@tonic-gate 				VUID_PUTNEXT(qp, (uchar_t)BUT(5),
4540Sstevel@tonic-gate 				    FE_PAIR_NONE, 0, 0);
4550Sstevel@tonic-gate 			}
4560Sstevel@tonic-gate 			/*FALLTHROUGH*/
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 		case PS2_WHEEL_DELTA_Z:
4590Sstevel@tonic-gate 			/*
4600Sstevel@tonic-gate 			 * Check whether reporting vertical wheel
4610Sstevel@tonic-gate 			 * movements is enabled
4620Sstevel@tonic-gate 			 */
4630Sstevel@tonic-gate 			code &= 0xf;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 			if (STATEP->wheel_state_bf & (1 <<
4660Sstevel@tonic-gate 				VUIDMICE_VERTICAL_WHEEL_ID)) {
4670Sstevel@tonic-gate 				/*
4680Sstevel@tonic-gate 				 * PS/2 mouse reports -ve values
4690Sstevel@tonic-gate 				 * when the wheel is scrolled up. So
4700Sstevel@tonic-gate 				 * we need to convert it into +ve as
4710Sstevel@tonic-gate 				 * X interprets a +ve value as wheel up event.
4720Sstevel@tonic-gate 				 * Same is true for the horizontal wheel also.
4730Sstevel@tonic-gate 				 * The mouse reports 0xf when scrolled up
4740Sstevel@tonic-gate 				 * and 0x1 when scrolled down. This observation
4750Sstevel@tonic-gate 				 * is based on Logitech, HCL,
4760Sstevel@tonic-gate 				 * Microsoft and Black Cat mouse only
4770Sstevel@tonic-gate 				 */
4780Sstevel@tonic-gate 				if (code == 0xf) {
4790Sstevel@tonic-gate 					/* negative Z - wheel up */
4800Sstevel@tonic-gate 					code |= 0xfffffff0;
4810Sstevel@tonic-gate 					vuidmice_send_wheel_event(qp, 0,
4820Sstevel@tonic-gate 					    FE_PAIR_NONE, 0, -code);
4830Sstevel@tonic-gate 				} else if (code == 0x01) {
4840Sstevel@tonic-gate 					/* positive Z - wheel down */
4850Sstevel@tonic-gate 					vuidmice_send_wheel_event(qp, 0,
4860Sstevel@tonic-gate 					    FE_PAIR_NONE, 0, -code);
4870Sstevel@tonic-gate 				}
4880Sstevel@tonic-gate 			}
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 			/*
4910Sstevel@tonic-gate 			 * Check whether reporting horizontal wheel
4920Sstevel@tonic-gate 			 * movements is enabled
4930Sstevel@tonic-gate 			 */
4940Sstevel@tonic-gate 			if (STATEP->wheel_state_bf &
4950Sstevel@tonic-gate 			    (1 << VUIDMICE_HORIZONTAL_WHEEL_ID)) {
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 				/*
4980Sstevel@tonic-gate 				 * The mouse return -7 and +7 when it
4990Sstevel@tonic-gate 				 * is scrolled horizontally
5000Sstevel@tonic-gate 				 */
5010Sstevel@tonic-gate 				if (code == 0x09) {
5020Sstevel@tonic-gate 					/* negative Z - wheel left */
5030Sstevel@tonic-gate 					vuidmice_send_wheel_event(qp, 1,
5040Sstevel@tonic-gate 					    FE_PAIR_NONE, 0, 1);
5050Sstevel@tonic-gate 				} else if (code == 0x07) {
5060Sstevel@tonic-gate 					/* positive Z - wheel right */
5070Sstevel@tonic-gate 					vuidmice_send_wheel_event(qp, 1,
5080Sstevel@tonic-gate 					    FE_PAIR_NONE, 0, -1);
5090Sstevel@tonic-gate 				}
5100Sstevel@tonic-gate 			}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate packet_complete:
5130Sstevel@tonic-gate 			STATEP->state = PS2_START;
5140Sstevel@tonic-gate 			/*
5150Sstevel@tonic-gate 			 * If we can peek at the next mouse character, and
5160Sstevel@tonic-gate 			 * its not the start of the next packet, don't use
5170Sstevel@tonic-gate 			 * this packet.
5180Sstevel@tonic-gate 			 */
5190Sstevel@tonic-gate 			if ((mp->b_wptr - mp->b_rptr) > 0 &&
5200Sstevel@tonic-gate 			    ((mp->b_rptr[0] ^ STATEP->sync_byte) & 0x08)) {
5210Sstevel@tonic-gate 				/*
5220Sstevel@tonic-gate 				 * bit 3 not set
5230Sstevel@tonic-gate 				 */
5240Sstevel@tonic-gate 				break;
5250Sstevel@tonic-gate 			}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 			/*
5280Sstevel@tonic-gate 			 * send the info to the next level --
5290Sstevel@tonic-gate 			 * need to send multiple events if we have both
5300Sstevel@tonic-gate 			 * a delta *AND* button event(s)
5310Sstevel@tonic-gate 			 */
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 			/* motion has occurred ... */
5340Sstevel@tonic-gate 			if (STATEP->deltax)
5350Sstevel@tonic-gate 				VUID_PUTNEXT(qp, (uchar_t)LOC_X_DELTA,
5360Sstevel@tonic-gate 				    FE_PAIR_ABSOLUTE, (uchar_t)LOC_X_ABSOLUTE,
5370Sstevel@tonic-gate 				    STATEP->deltax);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 			if (STATEP->deltay)
5400Sstevel@tonic-gate 				VUID_PUTNEXT(qp, (uchar_t)LOC_Y_DELTA,
5410Sstevel@tonic-gate 				    FE_PAIR_ABSOLUTE, (uchar_t)LOC_Y_ABSOLUTE,
5420Sstevel@tonic-gate 				    STATEP->deltay);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 			STATEP->deltax = STATEP->deltay = 0;
5450Sstevel@tonic-gate 			break;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		case PS2_WAIT_RESET_ACK:
5480Sstevel@tonic-gate 			if (code != MSE_ACK) {
5490Sstevel@tonic-gate 				break;
5500Sstevel@tonic-gate 			}
551*993Slq150181 
552*993Slq150181 			/*
553*993Slq150181 			 * On Dell latitude D800, we find that the MSE_ACK is
554*993Slq150181 			 * coming up even after timeout in VUID_OPEN during
555*993Slq150181 			 * early boot. So here (PS2_WAIT_RESET_ACK) we check
556*993Slq150181 			 * if timeout happened before, if true, we reset the
557*993Slq150181 			 * timeout to restart the initialization.
558*993Slq150181 			 */
559*993Slq150181 			if (STATEP->inited & PS2_FLAG_INIT_TIMEOUT) {
560*993Slq150181 				STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
561*993Slq150181 				vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET);
562*993Slq150181 			}
563*993Slq150181 
5640Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_RESET_AA;
5650Sstevel@tonic-gate 			break;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		case PS2_WAIT_RESET_AA:
5680Sstevel@tonic-gate 			if (code != MSE_AA) {
5690Sstevel@tonic-gate 				break;
5700Sstevel@tonic-gate 			}
5710Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_RESET_00;
5720Sstevel@tonic-gate 			break;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 		case PS2_WAIT_RESET_00:
5750Sstevel@tonic-gate 			if (code != MSE_00) {
5760Sstevel@tonic-gate 				break;
5770Sstevel@tonic-gate 			}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 			/* Reset has been ok */
5800Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_SETRES0_ACK1;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 			/* Set timeout for set res */
585*993Slq150181 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
5860Sstevel@tonic-gate 
587*993Slq150181 			put1(WR(qp), MSESETRES);
5880Sstevel@tonic-gate 			break;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		case PS2_WAIT_SETRES0_ACK1:
5910Sstevel@tonic-gate 			if (code != MSE_ACK) {
5920Sstevel@tonic-gate 				break;
5930Sstevel@tonic-gate 			}
594*993Slq150181 			STATEP->state = PS2_WAIT_SETRES0_ACK2;
5950Sstevel@tonic-gate 			put1(WR(qp), 0);
5960Sstevel@tonic-gate 			break;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 		case PS2_WAIT_SETRES0_ACK2:
5990Sstevel@tonic-gate 		case PS2_WAIT_SCALE1_1_ACK:
6000Sstevel@tonic-gate 		case PS2_WAIT_SCALE1_2_ACK:
6010Sstevel@tonic-gate 			if (code != MSE_ACK) {
6020Sstevel@tonic-gate 				break;
6030Sstevel@tonic-gate 			}
604*993Slq150181 			STATEP->state++;
6050Sstevel@tonic-gate 			put1(WR(qp), MSESCALE1);
6060Sstevel@tonic-gate 			break;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		case PS2_WAIT_SCALE1_3_ACK:
6090Sstevel@tonic-gate 			if (code != MSE_ACK) {
6100Sstevel@tonic-gate 				break;
6110Sstevel@tonic-gate 			}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 			/* Set res and scale have been ok */
6140Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_STATREQ_ACK;
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 			/* Set timeout for status request */
619*993Slq150181 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
620*993Slq150181 
621*993Slq150181 			put1(WR(qp), MSESTATREQ);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 			break;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 		case PS2_WAIT_STATREQ_ACK:
6260Sstevel@tonic-gate 			if (code != MSE_ACK) {
6270Sstevel@tonic-gate 				break;
6280Sstevel@tonic-gate 			}
6290Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_STATUS_1;
6300Sstevel@tonic-gate 			break;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 		case PS2_WAIT_STATUS_1:
6330Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_STATUS_BUTTONS;
6340Sstevel@tonic-gate 			break;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 		case PS2_WAIT_STATUS_BUTTONS:
6370Sstevel@tonic-gate 			if (code != 0) {
6380Sstevel@tonic-gate 				STATEP->nbuttons = (uchar_t)code;
6390Sstevel@tonic-gate 				STATEP->state = (uchar_t)PS2_WAIT_STATUS_REV;
6400Sstevel@tonic-gate 			} else {
6410Sstevel@tonic-gate #if	defined(VUID3PS2)
6420Sstevel@tonic-gate 				/*
6430Sstevel@tonic-gate 				 * It seems that there are some 3-button mice
6440Sstevel@tonic-gate 				 * that don't play the Logitech autodetect
6450Sstevel@tonic-gate 				 * game.  One is a Mouse Systems mouse OEM'ed
6460Sstevel@tonic-gate 				 * by Intergraph.
6470Sstevel@tonic-gate 				 *
6480Sstevel@tonic-gate 				 * Until we find out how to autodetect these
6490Sstevel@tonic-gate 				 * mice, we'll assume that if we're being
6500Sstevel@tonic-gate 				 * compiled as vuid3ps2 and the mouse doesn't
6510Sstevel@tonic-gate 				 * play the autodetect game, it's a 3-button
6520Sstevel@tonic-gate 				 * mouse.  This effectively disables
6530Sstevel@tonic-gate 				 * autodetect for mice using vuid3ps2, but
6540Sstevel@tonic-gate 				 * since vuid3ps2 is used only on x86 where
6550Sstevel@tonic-gate 				 * we currently assume manual configuration,
6560Sstevel@tonic-gate 				 * this shouldn't be a problem.  At some point
6570Sstevel@tonic-gate 				 * in the future when we *do* start using
6580Sstevel@tonic-gate 				 * autodetect on x86, we should probably define
6590Sstevel@tonic-gate 				 * VUIDPS2 instead of VUID3PS2.  Even then,
6600Sstevel@tonic-gate 				 * we could leave this code so that *some*
6610Sstevel@tonic-gate 				 * mice could use autodetect and others not.
6620Sstevel@tonic-gate 				 */
6630Sstevel@tonic-gate 				STATEP->nbuttons = 3;
6640Sstevel@tonic-gate #else
6650Sstevel@tonic-gate 				STATEP->nbuttons = 2;
6660Sstevel@tonic-gate #endif
6670Sstevel@tonic-gate 				STATEP->state = PS2_WAIT_STATUS_3;
6680Sstevel@tonic-gate 			}
6690Sstevel@tonic-gate 			break;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		case PS2_WAIT_STATUS_REV:
6720Sstevel@tonic-gate 			/*FALLTHROUGH*/
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 		case PS2_WAIT_STATUS_3:
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 			/* Status request has been ok */
6770Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
6780Sstevel@tonic-gate 
679*993Slq150181 			/* Set timeout for set res or sample rate */
680*993Slq150181 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
681*993Slq150181 
6820Sstevel@tonic-gate 			/*
6830Sstevel@tonic-gate 			 * Start the wheel-mouse detection code.  First, we look
6840Sstevel@tonic-gate 			 * for standard wheel mice.  If we set the sample rate
6850Sstevel@tonic-gate 			 * to 200, 100, and then 80 and finally request the
6860Sstevel@tonic-gate 			 * device ID, a wheel mouse will return an ID of 0x03.
6870Sstevel@tonic-gate 			 * After that, we'll try for the wheel+5 variety.  The
6880Sstevel@tonic-gate 			 * incantation in this case is 200, 200, and 80.  We'll
6890Sstevel@tonic-gate 			 * get 0x04 back in that case.
6900Sstevel@tonic-gate 			 */
6910Sstevel@tonic-gate 			if (STATEP->inited & PS2_FLAG_NO_EXTN) {
6920Sstevel@tonic-gate 				STATEP->state = PS2_WAIT_SETRES3_ACK1;
6930Sstevel@tonic-gate 				put1(WR(qp), MSESETRES);
6940Sstevel@tonic-gate 			} else {
695*993Slq150181 				STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK;
6960Sstevel@tonic-gate 				put1(WR(qp), MSECHGMOD);
6970Sstevel@tonic-gate 			}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 			break;
7000Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_SMPL1_CMD_ACK:
7010Sstevel@tonic-gate 			if (code != MSE_ACK) {
7020Sstevel@tonic-gate 				break;
7030Sstevel@tonic-gate 			}
704*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL_SMPL1_RATE_ACK;
7050Sstevel@tonic-gate 			put1(WR(qp), 200);
7060Sstevel@tonic-gate 			break;
7070Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_SMPL1_RATE_ACK:
7080Sstevel@tonic-gate 			if (code != MSE_ACK) {
7090Sstevel@tonic-gate 				break;
7100Sstevel@tonic-gate 			}
711*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL_SMPL2_CMD_ACK;
7120Sstevel@tonic-gate 			put1(WR(qp), MSECHGMOD);
7130Sstevel@tonic-gate 			break;
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_SMPL2_CMD_ACK:
7160Sstevel@tonic-gate 			if (code != MSE_ACK) {
7170Sstevel@tonic-gate 				break;
7180Sstevel@tonic-gate 			}
719*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL_SMPL2_RATE_ACK;
7200Sstevel@tonic-gate 			put1(WR(qp), 100);
7210Sstevel@tonic-gate 			break;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_SMPL2_RATE_ACK:
7240Sstevel@tonic-gate 			if (code != MSE_ACK) {
7250Sstevel@tonic-gate 				break;
7260Sstevel@tonic-gate 			}
727*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL_SMPL3_CMD_ACK;
7280Sstevel@tonic-gate 			put1(WR(qp), MSECHGMOD);
7290Sstevel@tonic-gate 			break;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_SMPL3_CMD_ACK:
7320Sstevel@tonic-gate 			if (code != MSE_ACK) {
7330Sstevel@tonic-gate 				break;
7340Sstevel@tonic-gate 			}
735*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL_SMPL3_RATE_ACK;
7360Sstevel@tonic-gate 			put1(WR(qp), 80);
7370Sstevel@tonic-gate 			break;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_SMPL3_RATE_ACK:
7400Sstevel@tonic-gate 			if (code != MSE_ACK) {
7410Sstevel@tonic-gate 				break;
7420Sstevel@tonic-gate 			}
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 			/* Set sample rate has been ok */
7450Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_WHEEL_DEV_CMD;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 			/* Set timeout for get dev */
7500Sstevel@tonic-gate 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
7510Sstevel@tonic-gate 
752*993Slq150181 			put1(WR(qp), MSEGETDEV);
7530Sstevel@tonic-gate 			break;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_DEV_CMD:
7560Sstevel@tonic-gate 			if (code != MSE_ACK) {
7570Sstevel@tonic-gate 				break;
7580Sstevel@tonic-gate 			}
7590Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_WHEEL_DEV_ACK;
7600Sstevel@tonic-gate 			break;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		case PS2_WAIT_WHEEL_DEV_ACK:
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 			/* Get dev has been ok */
7650Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 			if (code != 0x03) {
7680Sstevel@tonic-gate 				STATEP->state = PS2_WAIT_SETRES3_ACK1;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 				/* Set timeout for set res */
7710Sstevel@tonic-gate 				vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
7720Sstevel@tonic-gate 
773*993Slq150181 				put1(WR(qp), MSESETRES);
774*993Slq150181 
7750Sstevel@tonic-gate 				break;
7760Sstevel@tonic-gate 			}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 			STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL;
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 			/*
7810Sstevel@tonic-gate 			 * Found wheel. By default enable the wheel.
7820Sstevel@tonic-gate 			 */
7830Sstevel@tonic-gate 			STATEP->wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_WHEEL5_SMPL1_CMD_ACK;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 			/* Set timeout for set sample rate */
788*993Slq150181 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
789*993Slq150181 
790*993Slq150181 			/* We're on a roll - try for wheel+5 */
791*993Slq150181 			put1(WR(qp), MSECHGMOD);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 			break;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_SMPL1_CMD_ACK:
7960Sstevel@tonic-gate 			if (code != MSE_ACK) {
7970Sstevel@tonic-gate 				break;
7980Sstevel@tonic-gate 			}
799*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL5_SMPL1_RATE_ACK;
8000Sstevel@tonic-gate 			put1(WR(qp), 200);
8010Sstevel@tonic-gate 			break;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_SMPL1_RATE_ACK:
8040Sstevel@tonic-gate 			if (code != MSE_ACK) {
8050Sstevel@tonic-gate 				break;
8060Sstevel@tonic-gate 			}
807*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL5_SMPL2_CMD_ACK;
8080Sstevel@tonic-gate 			put1(WR(qp), MSECHGMOD);
8090Sstevel@tonic-gate 			break;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_SMPL2_CMD_ACK:
8120Sstevel@tonic-gate 			if (code != MSE_ACK) {
8130Sstevel@tonic-gate 				break;
8140Sstevel@tonic-gate 			}
815*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL5_SMPL2_RATE_ACK;
8160Sstevel@tonic-gate 			put1(WR(qp), 200);
8170Sstevel@tonic-gate 			break;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_SMPL2_RATE_ACK:
8200Sstevel@tonic-gate 			if (code != MSE_ACK) {
8210Sstevel@tonic-gate 				break;
8220Sstevel@tonic-gate 			}
823*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL5_SMPL3_CMD_ACK;
8240Sstevel@tonic-gate 			put1(WR(qp), MSECHGMOD);
8250Sstevel@tonic-gate 			break;
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_SMPL3_CMD_ACK:
8280Sstevel@tonic-gate 			if (code != MSE_ACK) {
8290Sstevel@tonic-gate 				break;
8300Sstevel@tonic-gate 			}
831*993Slq150181 			STATEP->state = PS2_WAIT_WHEEL5_SMPL3_RATE_ACK;
8320Sstevel@tonic-gate 			put1(WR(qp), 80);
8330Sstevel@tonic-gate 			break;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_SMPL3_RATE_ACK:
8360Sstevel@tonic-gate 			if (code != MSE_ACK) {
8370Sstevel@tonic-gate 				break;
8380Sstevel@tonic-gate 			}
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 			/* Set sample rate has been ok */
8410Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 			/* Set timeout for wheel5 get dev */
8460Sstevel@tonic-gate 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
8470Sstevel@tonic-gate 
848*993Slq150181 			put1(WR(qp), MSEGETDEV);
849*993Slq150181 
8500Sstevel@tonic-gate 			break;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_DEV_CMD:
8530Sstevel@tonic-gate 			if (code != MSE_ACK) {
8540Sstevel@tonic-gate 				break;
8550Sstevel@tonic-gate 			}
8560Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_WHEEL5_DEV_ACK;
8570Sstevel@tonic-gate 			break;
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		case PS2_WAIT_WHEEL5_DEV_ACK:
8600Sstevel@tonic-gate 			if (code == 0x04) {
8610Sstevel@tonic-gate 				STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL5;
8620Sstevel@tonic-gate 				STATEP->nbuttons	= 5;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 				/*
8650Sstevel@tonic-gate 				 * Found wheel. By default enable the wheel.
8660Sstevel@tonic-gate 				 */
8670Sstevel@tonic-gate 				STATEP->wheel_state_bf |=
8680Sstevel@tonic-gate 				    VUID_WHEEL_STATE_ENABLED <<
8690Sstevel@tonic-gate 				    MOUSE_MODE_WHEEL;
8700Sstevel@tonic-gate 			}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 			/* Wheel5 get dev has been ok */
8730Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 			/* FALLTHROUGH */
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 		case PS2_WAIT_SETRES3_CMD:
8780Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_SETRES3_ACK1;
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 			/* Set timeout for set res */
8810Sstevel@tonic-gate 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
8820Sstevel@tonic-gate 
883*993Slq150181 			put1(WR(qp), MSESETRES);
884*993Slq150181 
8850Sstevel@tonic-gate 			break;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 		case PS2_WAIT_SETRES3_ACK1:
8880Sstevel@tonic-gate 			if (code != MSE_ACK) {
8890Sstevel@tonic-gate 				break;
8900Sstevel@tonic-gate 			}
891*993Slq150181 			STATEP->state = PS2_WAIT_SETRES3_ACK2;
8920Sstevel@tonic-gate 			put1(WR(qp), 3);
8930Sstevel@tonic-gate 			break;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 		case PS2_WAIT_SETRES3_ACK2:
8960Sstevel@tonic-gate 			if (code != MSE_ACK) {
8970Sstevel@tonic-gate 				break;
8980Sstevel@tonic-gate 			}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 			/* Set res has been ok */
9010Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 			STATEP->state = PS2_WAIT_STREAM_ACK;
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 			/* Set timeout for enable */
9060Sstevel@tonic-gate 			vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
9070Sstevel@tonic-gate 
908*993Slq150181 			put1(WR(qp), MSESTREAM);
909*993Slq150181 
9100Sstevel@tonic-gate 			break;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		case PS2_WAIT_STREAM_ACK:
9130Sstevel@tonic-gate 			if (code != MSE_ACK) {
9140Sstevel@tonic-gate 				break;
9150Sstevel@tonic-gate 			}
916*993Slq150181 			STATEP->state = PS2_WAIT_ON_ACK;
9170Sstevel@tonic-gate 			put1(WR(qp), MSEON);
9180Sstevel@tonic-gate 			break;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 		case PS2_WAIT_ON_ACK:
9210Sstevel@tonic-gate 			if (code != MSE_ACK) {
9220Sstevel@tonic-gate 				break;
9230Sstevel@tonic-gate 			}
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 			/* Enable has been ok */
9260Sstevel@tonic-gate 			vuid_cancel_timeout(qp);
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 			STATEP->state = PS2_START;
9290Sstevel@tonic-gate 			break;
9300Sstevel@tonic-gate 		}
9310Sstevel@tonic-gate 	}
9320Sstevel@tonic-gate 	freemsg(mp);
9330Sstevel@tonic-gate }
934