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
56990Sgd78059 * Common Development and Distribution License (the "License").
66990Sgd78059 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
229840Sgdamore@opensolaris.org * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * 2/3/5 Button PS/2 Mouse Protocol
280Sstevel@tonic-gate *
290Sstevel@tonic-gate * This module dynamically determines the number of buttons on the mouse.
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <sys/param.h>
330Sstevel@tonic-gate #include <sys/stream.h>
340Sstevel@tonic-gate #include <sys/vuid_event.h>
359840Sgdamore@opensolaris.org #include "vuidmice.h"
360Sstevel@tonic-gate #include <sys/vuid_wheel.h>
370Sstevel@tonic-gate #include <sys/mouse.h>
386990Sgd78059 #include <sys/strsun.h>
390Sstevel@tonic-gate #include <sys/ddi.h>
400Sstevel@tonic-gate #include <sys/sunddi.h>
410Sstevel@tonic-gate
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate * BUT(1) LEFT BUTTON
440Sstevel@tonic-gate * BUT(2) MIDDLE BUTTON (if present)
450Sstevel@tonic-gate * BUT(3) RIGHT BUTTON
460Sstevel@tonic-gate */
470Sstevel@tonic-gate
480Sstevel@tonic-gate #define PS2_BUTTONMASK 7 /* mask byte zero with this */
490Sstevel@tonic-gate
500Sstevel@tonic-gate #define PS2_BUTTON_L (uchar_t)0x01 /* Left button pressed */
510Sstevel@tonic-gate #define PS2_BUTTON_R (uchar_t)0x02 /* Right button pressed */
520Sstevel@tonic-gate #define PS2_BUTTON_M (uchar_t)0x04 /* Middle button pressed */
530Sstevel@tonic-gate #define PS2_DATA_XSIGN (uchar_t)0x10 /* X data sign bit */
540Sstevel@tonic-gate #define PS2_DATA_YSIGN (uchar_t)0x20 /* Y data sign bit */
550Sstevel@tonic-gate
560Sstevel@tonic-gate #define PS2_START 0 /* Beginning of packet */
570Sstevel@tonic-gate #define PS2_BUTTON 1 /* Got button status */
580Sstevel@tonic-gate #define PS2_MAYBE_REATTACH 2 /* Got button status */
590Sstevel@tonic-gate #define PS2_DELTA_Y 3 /* Got delta X */
600Sstevel@tonic-gate #define PS2_WHEEL_DELTA_Z 4
610Sstevel@tonic-gate #define PS2_WHEEL5_DELTA_Z 5
6210087SSeth.Goldberg@Sun.COM #define PS2_WAIT_RESET_COMPLETE 6
6310087SSeth.Goldberg@Sun.COM #define PS2_WAIT_FOR_AA 7
6410087SSeth.Goldberg@Sun.COM #define PS2_WAIT_FOR_00 8
650Sstevel@tonic-gate #define PS2_WAIT_SETRES0_ACK1 9
660Sstevel@tonic-gate #define PS2_WAIT_SETRES0_ACK2 10 /* -+ must be consecutive */
670Sstevel@tonic-gate #define PS2_WAIT_SCALE1_1_ACK 11 /* | */
680Sstevel@tonic-gate #define PS2_WAIT_SCALE1_2_ACK 12 /* | */
690Sstevel@tonic-gate #define PS2_WAIT_SCALE1_3_ACK 13 /* -+ */
7010087SSeth.Goldberg@Sun.COM #define PS2_WAIT_STATREQ_ACK 14 /* -+ */
7110087SSeth.Goldberg@Sun.COM #define PS2_WAIT_STATUS_1 15 /* | */
7210087SSeth.Goldberg@Sun.COM #define PS2_WAIT_STATUS_BUTTONS 16 /* | must stay in this order */
7310087SSeth.Goldberg@Sun.COM #define PS2_WAIT_STATUS_REV 17 /* -+ */
740Sstevel@tonic-gate #define PS2_WAIT_STATUS_3 18
750Sstevel@tonic-gate #define PS2_WAIT_WHEEL_SMPL1_CMD_ACK 19 /* Set the sample rate to 200 */
760Sstevel@tonic-gate #define PS2_WAIT_WHEEL_SMPL1_RATE_ACK 20
770Sstevel@tonic-gate #define PS2_WAIT_WHEEL_SMPL2_CMD_ACK 21 /* Set the sample rate to 200 */
780Sstevel@tonic-gate #define PS2_WAIT_WHEEL_SMPL2_RATE_ACK 22
790Sstevel@tonic-gate #define PS2_WAIT_WHEEL_SMPL3_CMD_ACK 23 /* Set the sample rate to 80 */
800Sstevel@tonic-gate #define PS2_WAIT_WHEEL_SMPL3_RATE_ACK 24
810Sstevel@tonic-gate #define PS2_WAIT_WHEEL_DEV_CMD 25
820Sstevel@tonic-gate #define PS2_WAIT_WHEEL_DEV_ACK 26 /* Detected wheel mouse */
830Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_SMPL1_CMD_ACK 27 /* Set the sample rate to 200 */
840Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_SMPL1_RATE_ACK 28
850Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_SMPL2_CMD_ACK 29 /* Set the sample rate to 200 */
860Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_SMPL2_RATE_ACK 30
870Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_SMPL3_CMD_ACK 31 /* Set the sample rate to 100 */
880Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_SMPL3_RATE_ACK 32
890Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_DEV_CMD 33
900Sstevel@tonic-gate #define PS2_WAIT_WHEEL5_DEV_ACK 34 /* Detected 5 button mouse */
910Sstevel@tonic-gate #define PS2_WAIT_SETRES3_CMD 35
920Sstevel@tonic-gate #define PS2_WAIT_SETRES3_ACK1 36
930Sstevel@tonic-gate #define PS2_WAIT_SETRES3_ACK2 37
940Sstevel@tonic-gate #define PS2_WAIT_STREAM_ACK 38
950Sstevel@tonic-gate #define PS2_WAIT_ON_ACK 39
960Sstevel@tonic-gate
970Sstevel@tonic-gate #define MOUSE_MODE_PLAIN 0 /* Normal PS/2 mouse - 3 byte msgs */
980Sstevel@tonic-gate #define MOUSE_MODE_WHEEL 1 /* Wheel mouse - 4 byte msgs */
990Sstevel@tonic-gate #define MOUSE_MODE_WHEEL5 2 /* Wheel + 5 btn mouse - 4 byte msgs */
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate #define PS2_FLAG_NO_EXTN 0x08 /* Mouse doesn't obey extended cmds */
1020Sstevel@tonic-gate #define PS2_FLAG_INIT_DONE 0x01 /* Mouse has been inited successfully */
1030Sstevel@tonic-gate #define PS2_FLAG_INIT_TIMEOUT 0x02 /* Mouse init timeout */
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate * The RESET command takes more time
1070Sstevel@tonic-gate * before the PS/2 mouse is ready
1080Sstevel@tonic-gate */
1090Sstevel@tonic-gate #define PS2_INIT_TMOUT_RESET 500000 /* 500ms for RESET command */
1100Sstevel@tonic-gate #define PS2_INIT_TMOUT_PER_CMD 200000 /* 200ms for each command-response */
111993Slq150181 #define PS2_INIT_TMOUT_PER_GROUP 500000 /* 500ms for group commands */
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate #define PS2_MAX_INIT_COUNT 5
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate static void vuidmice_send_wheel_event(queue_t *const, uchar_t,
1160Sstevel@tonic-gate uchar_t, uchar_t, int);
1170Sstevel@tonic-gate extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int);
1180Sstevel@tonic-gate extern void uniqtime32(struct timeval32 *);
1190Sstevel@tonic-gate static void VUID_INIT_TIMEOUT(void *q);
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate * We apply timeout to nearly each command-response
1230Sstevel@tonic-gate * during initialization:
1240Sstevel@tonic-gate *
1250Sstevel@tonic-gate * Set timeout for SET RESOLUTION
1260Sstevel@tonic-gate * Set timeout for SET SCALE
1270Sstevel@tonic-gate * Set timeout for SET SAMPLE RATE
1280Sstevel@tonic-gate * Set timeout for STATUS REQUEST
1290Sstevel@tonic-gate * Set timeout for GET DEV
1300Sstevel@tonic-gate * Set timeout for SET STREAM MODE and ENABLE.
1310Sstevel@tonic-gate *
1320Sstevel@tonic-gate * But for simplicity, sometimes we just apply the timeout
133993Slq150181 * to a function with group commands (e.g. wheel-mouse detection).
1340Sstevel@tonic-gate *
1350Sstevel@tonic-gate */
1360Sstevel@tonic-gate static void
vuid_set_timeout(queue_t * const qp,clock_t time)1370Sstevel@tonic-gate vuid_set_timeout(queue_t *const qp, clock_t time)
1380Sstevel@tonic-gate {
13910087SSeth.Goldberg@Sun.COM if (STATEP->init_tid != 0)
14010087SSeth.Goldberg@Sun.COM (void) quntimeout(qp, STATEP->init_tid);
1410Sstevel@tonic-gate STATEP->init_tid = qtimeout(qp, VUID_INIT_TIMEOUT,
1420Sstevel@tonic-gate qp, drv_usectohz(time));
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate static void
vuid_cancel_timeout(queue_t * const qp)1460Sstevel@tonic-gate vuid_cancel_timeout(queue_t *const qp)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate (void) quntimeout(qp, STATEP->init_tid);
1490Sstevel@tonic-gate STATEP->init_tid = 0;
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate * vuidmice_send_wheel_event
1540Sstevel@tonic-gate * Convert wheel data to firm_events
1550Sstevel@tonic-gate */
1560Sstevel@tonic-gate static void
vuidmice_send_wheel_event(queue_t * const qp,uchar_t event_id,uchar_t event_pair_type,uchar_t event_pair,int event_value)1570Sstevel@tonic-gate vuidmice_send_wheel_event(queue_t *const qp, uchar_t event_id,
1580Sstevel@tonic-gate uchar_t event_pair_type, uchar_t event_pair, int event_value)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate mblk_t *bp;
1610Sstevel@tonic-gate Firm_event *fep;
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate if ((bp = allocb((int)sizeof (Firm_event), BPRI_HI)) == NULL) {
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate return;
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate
1686990Sgd78059 fep = (void *)bp->b_wptr;
1690Sstevel@tonic-gate fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) |
1700Sstevel@tonic-gate vuid_id_offset(event_id);
1710Sstevel@tonic-gate fep->pair_type = event_pair_type;
1720Sstevel@tonic-gate fep->pair = event_pair;
1730Sstevel@tonic-gate fep->value = event_value;
1740Sstevel@tonic-gate uniqtime32(&fep->time);
1750Sstevel@tonic-gate bp->b_wptr += sizeof (Firm_event);
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate if (canput(qp->q_next)) {
1780Sstevel@tonic-gate putnext(qp, bp);
1790Sstevel@tonic-gate } else {
1800Sstevel@tonic-gate (void) putbq(qp, bp); /* read side is blocked */
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate static void
sendButtonEvent(queue_t * const qp)1860Sstevel@tonic-gate sendButtonEvent(queue_t *const qp)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate static int bmap[3] = {1, 3, 2};
1890Sstevel@tonic-gate uint_t b;
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate /* for each button, see if it has changed */
1920Sstevel@tonic-gate for (b = 0; b < STATEP->nbuttons; b++) {
1930Sstevel@tonic-gate uchar_t mask = 0x1 << b;
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate if ((STATEP->buttons & mask) != (STATEP->oldbuttons & mask))
1960Sstevel@tonic-gate VUID_PUTNEXT(qp, (uchar_t)BUT(bmap[b]), FE_PAIR_NONE, 0,
1976990Sgd78059 (STATEP->buttons & mask ? 1 : 0));
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate void
put1(queue_t * const qp,int c)2020Sstevel@tonic-gate put1(queue_t *const qp, int c)
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate mblk_t *bp;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate if (bp = allocb(1, BPRI_MED)) {
2070Sstevel@tonic-gate *bp->b_wptr++ = (char)c;
2080Sstevel@tonic-gate putnext(qp, bp);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate
21210087SSeth.Goldberg@Sun.COM static void
vuidmice_start_wdc_or_setres(queue_t * qp)21310087SSeth.Goldberg@Sun.COM vuidmice_start_wdc_or_setres(queue_t *qp)
21410087SSeth.Goldberg@Sun.COM {
21510087SSeth.Goldberg@Sun.COM /* Set timeout for set res or sample rate */
21610087SSeth.Goldberg@Sun.COM vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
21710087SSeth.Goldberg@Sun.COM
21810087SSeth.Goldberg@Sun.COM /*
21910087SSeth.Goldberg@Sun.COM * Start the wheel-mouse detection code. First, we look
22010087SSeth.Goldberg@Sun.COM * for standard wheel mice. If we set the sample rate
22110087SSeth.Goldberg@Sun.COM * to 200, 100, and then 80 and finally request the
22210087SSeth.Goldberg@Sun.COM * device ID, a wheel mouse will return an ID of 0x03.
22310087SSeth.Goldberg@Sun.COM * After that, we'll try for the wheel+5 variety. The
22410087SSeth.Goldberg@Sun.COM * incantation in this case is 200, 200, and 80. We'll
22510087SSeth.Goldberg@Sun.COM * get 0x04 back in that case.
22610087SSeth.Goldberg@Sun.COM */
22710087SSeth.Goldberg@Sun.COM if (STATEP->inited & PS2_FLAG_NO_EXTN) {
22810087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_SETRES3_ACK1;
22910087SSeth.Goldberg@Sun.COM put1(WR(qp), MSESETRES);
23010087SSeth.Goldberg@Sun.COM } else {
23110087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK;
23210087SSeth.Goldberg@Sun.COM put1(WR(qp), MSECHGMOD);
23310087SSeth.Goldberg@Sun.COM }
23410087SSeth.Goldberg@Sun.COM }
23510087SSeth.Goldberg@Sun.COM
2360Sstevel@tonic-gate int
VUID_OPEN(queue_t * const qp)2370Sstevel@tonic-gate VUID_OPEN(queue_t *const qp)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate STATEP->format = VUID_FIRM_EVENT;
2400Sstevel@tonic-gate STATEP->vuid_mouse_mode = MOUSE_MODE_PLAIN;
2410Sstevel@tonic-gate STATEP->inited = 0;
2420Sstevel@tonic-gate STATEP->nbuttons = 3;
2430Sstevel@tonic-gate
24410087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_RESET_COMPLETE;
2450Sstevel@tonic-gate
246993Slq150181 put1(WR(qp), MSERESET);
247993Slq150181
2480Sstevel@tonic-gate while ((STATEP->state != PS2_START) &&
2490Sstevel@tonic-gate !(STATEP->inited & PS2_FLAG_INIT_TIMEOUT)) {
2500Sstevel@tonic-gate if (qwait_sig(qp) == 0)
2510Sstevel@tonic-gate break;
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate * Later the PS/2 mouse maybe re-attach, so here
2560Sstevel@tonic-gate * clear the init_count.
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate STATEP->init_count = 0;
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate return (0);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate void
VUID_CLOSE(queue_t * const qp)2640Sstevel@tonic-gate VUID_CLOSE(queue_t *const qp)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate if (STATEP->init_tid != 0)
2670Sstevel@tonic-gate vuid_cancel_timeout(qp);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate static void
VUID_INIT_TIMEOUT(void * q)2710Sstevel@tonic-gate VUID_INIT_TIMEOUT(void *q)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate queue_t *qp = q;
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate STATEP->init_tid = 0;
2760Sstevel@tonic-gate
277822Ssethg /*
278822Ssethg * Some mice do not even send an error in response to
279822Ssethg * the wheel mouse sample commands, so if we're in any of
280822Ssethg * the PS2_WAIT_WHEEL_SMPL* states, and there has been
281822Ssethg * a timeout, assume the mouse cannot handle the extended
282822Ssethg * (wheel mouse) commands.
283822Ssethg */
284822Ssethg if ((STATEP->state == PS2_WAIT_WHEEL_SMPL1_CMD_ACK) ||
285822Ssethg (STATEP->state == PS2_WAIT_WHEEL_SMPL1_RATE_ACK) ||
2860Sstevel@tonic-gate (STATEP->state == PS2_WAIT_WHEEL_SMPL2_RATE_ACK) ||
2870Sstevel@tonic-gate (STATEP->state == PS2_WAIT_WHEEL_SMPL3_RATE_ACK)) {
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate * We overload 'inited' to mark the PS/2 mouse
2900Sstevel@tonic-gate * as one which doesn't respond to extended commands.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate STATEP->inited |= PS2_FLAG_NO_EXTN;
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
29610087SSeth.Goldberg@Sun.COM
29710087SSeth.Goldberg@Sun.COM /*
29810087SSeth.Goldberg@Sun.COM * If the Logitech button detection sequence timed out at some point
29910087SSeth.Goldberg@Sun.COM * in the sequence, ignore it and skip to the next step in
30010087SSeth.Goldberg@Sun.COM * initialization. Do NOT count this as a timeout, so do NOT
30110087SSeth.Goldberg@Sun.COM * increment init_count.
30210087SSeth.Goldberg@Sun.COM */
30310087SSeth.Goldberg@Sun.COM if (STATEP->state >= PS2_WAIT_STATREQ_ACK &&
30410087SSeth.Goldberg@Sun.COM STATEP->state <= PS2_WAIT_STATUS_REV) {
30510087SSeth.Goldberg@Sun.COM
30610087SSeth.Goldberg@Sun.COM /* See the comment under the PS2_WAIT_STATUS_BUTTONS case */
30710087SSeth.Goldberg@Sun.COM #if defined(VUID3PS2)
30810087SSeth.Goldberg@Sun.COM STATEP->nbuttons = 3;
30910087SSeth.Goldberg@Sun.COM #else
31010087SSeth.Goldberg@Sun.COM STATEP->nbuttons = 2;
31110087SSeth.Goldberg@Sun.COM #endif
31210087SSeth.Goldberg@Sun.COM vuidmice_start_wdc_or_setres(qp);
3130Sstevel@tonic-gate return;
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate
31610087SSeth.Goldberg@Sun.COM /*
31710087SSeth.Goldberg@Sun.COM * If the initialization process has timed out too many times, even if
31810087SSeth.Goldberg@Sun.COM * a subset of the process was successful, stop trying and put the
31910087SSeth.Goldberg@Sun.COM * mouse in the only state from which it can recover -- waiting for an
32010087SSeth.Goldberg@Sun.COM * 0xAA 0x00 response (i.e. like one we get on resume from mouse8042
32110087SSeth.Goldberg@Sun.COM * or from a replug).
32210087SSeth.Goldberg@Sun.COM */
32310087SSeth.Goldberg@Sun.COM if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) {
32410087SSeth.Goldberg@Sun.COM STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
32510087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_FOR_AA;
32610087SSeth.Goldberg@Sun.COM } else {
3270Sstevel@tonic-gate
32810087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_RESET_COMPLETE;
329993Slq150181
33010087SSeth.Goldberg@Sun.COM /* Try to reset the mouse again */
33110087SSeth.Goldberg@Sun.COM put1(WR(qp), MSERESET);
33210087SSeth.Goldberg@Sun.COM }
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate void
VUID_QUEUE(queue_t * const qp,mblk_t * mp)3360Sstevel@tonic-gate VUID_QUEUE(queue_t *const qp, mblk_t *mp)
3370Sstevel@tonic-gate {
33810087SSeth.Goldberg@Sun.COM int code, length;
3390Sstevel@tonic-gate clock_t now;
3400Sstevel@tonic-gate clock_t elapsed;
3410Sstevel@tonic-gate clock_t mouse_timeout;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate mouse_timeout = drv_usectohz(250000);
3440Sstevel@tonic-gate now = ddi_get_lbolt();
3450Sstevel@tonic-gate elapsed = now - STATEP->last_event_lbolt;
3460Sstevel@tonic-gate STATEP->last_event_lbolt = now;
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate while (mp->b_rptr < mp->b_wptr) {
34910087SSeth.Goldberg@Sun.COM length = MBLKL(mp);
3500Sstevel@tonic-gate code = *mp->b_rptr++;
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate switch (STATEP->state) {
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * Start state. We stay here if the start code is not
3560Sstevel@tonic-gate * received thus forcing us back into sync. When we get a
3570Sstevel@tonic-gate * start code the button mask comes with it forcing us to
3580Sstevel@tonic-gate * to the next state.
3590Sstevel@tonic-gate */
3600Sstevel@tonic-gate restart:
3610Sstevel@tonic-gate case PS2_START:
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate /*
3640Sstevel@tonic-gate * 3-byte packet format
3650Sstevel@tonic-gate *
3660Sstevel@tonic-gate * Bit 7 6 5 4 3 2 1 0
3670Sstevel@tonic-gate * Byte ---- ---- ----- ----- -- ------ ------ ------
3680Sstevel@tonic-gate * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn
3690Sstevel@tonic-gate * 2 |<--------------X Movement----------------->|
3700Sstevel@tonic-gate * 3 |<--------------Y Movement----------------->|
3710Sstevel@tonic-gate *
3720Sstevel@tonic-gate * 4-byte wheel packet format
3730Sstevel@tonic-gate *
3740Sstevel@tonic-gate * Bit 7 6 5 4 3 2 1 0
3750Sstevel@tonic-gate * Byte ---- ---- ----- ----- -- ------ ------ ------
3760Sstevel@tonic-gate * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn
3770Sstevel@tonic-gate * 2 |<--------------X Movement----------------->|
3780Sstevel@tonic-gate * 3 |<--------------Y Movement----------------->|
3790Sstevel@tonic-gate * 4 |<--------------Z Movement----------------->|
3800Sstevel@tonic-gate *
3810Sstevel@tonic-gate * 4-byte wheel+5 packet format
3820Sstevel@tonic-gate *
3830Sstevel@tonic-gate * Bit 7 6 5 4 3 2 1 0
3840Sstevel@tonic-gate * Byte ---- ---- ----- ----- -- ------ ------ ------
3850Sstevel@tonic-gate * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn
3860Sstevel@tonic-gate * 2 |<--------------X Movement----------------->|
3870Sstevel@tonic-gate * 3 |<--------------Y Movement----------------->|
3880Sstevel@tonic-gate * 4 0 0 5_Btn 4_Btn Z3 Z2 Z1 Z0
3890Sstevel@tonic-gate */
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate if (!(STATEP->inited & PS2_FLAG_INIT_DONE)) {
3920Sstevel@tonic-gate STATEP->sync_byte = code & 0x8;
3930Sstevel@tonic-gate STATEP->inited |= PS2_FLAG_INIT_DONE;
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate /*
3960Sstevel@tonic-gate * the PS/2 mouse data format doesn't have any sort of sync
3970Sstevel@tonic-gate * data to make sure we are in sync with the packet stream,
3980Sstevel@tonic-gate * but the Technical Reference manual states that bits 2 & 3
3990Sstevel@tonic-gate * of the first byte are reserved. Logitech uses bit 2 for
4000Sstevel@tonic-gate * the middle button. We HOPE that noone uses bit 3 though,
4010Sstevel@tonic-gate * and decide we're out of sync if bit 3 is not set here.
4020Sstevel@tonic-gate */
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate if ((code ^ STATEP->sync_byte) & 0x08) {
4050Sstevel@tonic-gate /* bit 3 not set */
4060Sstevel@tonic-gate STATEP->state = PS2_START;
4070Sstevel@tonic-gate break; /* toss the code */
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate /* get the button values */
4110Sstevel@tonic-gate STATEP->buttons = code & PS2_BUTTONMASK;
4120Sstevel@tonic-gate if (STATEP->buttons != STATEP->oldbuttons) {
4130Sstevel@tonic-gate sendButtonEvent(qp);
4140Sstevel@tonic-gate STATEP->oldbuttons = STATEP->buttons;
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate /* bit 5 indicates Y value is negative (the sign bit) */
4180Sstevel@tonic-gate if (code & PS2_DATA_YSIGN)
4190Sstevel@tonic-gate STATEP->deltay = -1 & ~0xff;
4200Sstevel@tonic-gate else
4210Sstevel@tonic-gate STATEP->deltay = 0;
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /* bit 4 is X sign bit */
4240Sstevel@tonic-gate if (code & PS2_DATA_XSIGN)
4250Sstevel@tonic-gate STATEP->deltax = -1 & ~0xff;
4260Sstevel@tonic-gate else
4270Sstevel@tonic-gate STATEP->deltax = 0;
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate if (code == MSE_AA)
4300Sstevel@tonic-gate STATEP->state = PS2_MAYBE_REATTACH;
4310Sstevel@tonic-gate else
4320Sstevel@tonic-gate STATEP->state = PS2_BUTTON;
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate break;
4350Sstevel@tonic-gate
43610087SSeth.Goldberg@Sun.COM case PS2_WAIT_FOR_AA:
43710087SSeth.Goldberg@Sun.COM /*
43810087SSeth.Goldberg@Sun.COM * On Dell latitude D800, the initial MSE_ACK is
43910087SSeth.Goldberg@Sun.COM * received after the initialization sequence
44010087SSeth.Goldberg@Sun.COM * times out, so restart it here.
44110087SSeth.Goldberg@Sun.COM */
44210087SSeth.Goldberg@Sun.COM if (code == MSE_ACK) {
44310087SSeth.Goldberg@Sun.COM STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
44410087SSeth.Goldberg@Sun.COM STATEP->init_count = 0;
44510087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_RESET_COMPLETE;
44610087SSeth.Goldberg@Sun.COM put1(WR(qp), MSERESET);
44710087SSeth.Goldberg@Sun.COM break;
44810087SSeth.Goldberg@Sun.COM }
44910087SSeth.Goldberg@Sun.COM
45010087SSeth.Goldberg@Sun.COM if (code != MSE_AA)
45110087SSeth.Goldberg@Sun.COM break;
45210087SSeth.Goldberg@Sun.COM
45310087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_FOR_00;
45410087SSeth.Goldberg@Sun.COM break;
45510087SSeth.Goldberg@Sun.COM
45610087SSeth.Goldberg@Sun.COM case PS2_WAIT_FOR_00:
45710087SSeth.Goldberg@Sun.COM if (code != MSE_00)
45810087SSeth.Goldberg@Sun.COM break;
45910087SSeth.Goldberg@Sun.COM
46010087SSeth.Goldberg@Sun.COM STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
46110087SSeth.Goldberg@Sun.COM STATEP->init_count = 0;
46210087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_RESET_COMPLETE;
46310087SSeth.Goldberg@Sun.COM put1(WR(qp), MSERESET);
46410087SSeth.Goldberg@Sun.COM break;
46510087SSeth.Goldberg@Sun.COM
4660Sstevel@tonic-gate case PS2_MAYBE_REATTACH:
4670Sstevel@tonic-gate if (code == MSE_00) {
46810087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_RESET_COMPLETE;
469993Slq150181 put1(WR(qp), MSERESET);
4700Sstevel@tonic-gate break;
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate /*FALLTHROUGH*/
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate case PS2_BUTTON:
4750Sstevel@tonic-gate /*
4760Sstevel@tonic-gate * Now for the 7 bits of delta x. "Or" in
4770Sstevel@tonic-gate * the sign bit and continue. This is ac-
4780Sstevel@tonic-gate * tually a signed 9 bit number, but I just
4790Sstevel@tonic-gate * truncate it to a signed char in order to
4800Sstevel@tonic-gate * avoid changing and retesting all of the
4810Sstevel@tonic-gate * mouse-related modules for this patch.
4820Sstevel@tonic-gate */
4830Sstevel@tonic-gate if (elapsed > mouse_timeout)
4840Sstevel@tonic-gate goto restart;
4850Sstevel@tonic-gate STATEP->deltax |= code & 0xff;
4860Sstevel@tonic-gate STATEP->state = PS2_DELTA_Y;
4870Sstevel@tonic-gate break;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate case PS2_DELTA_Y:
4900Sstevel@tonic-gate /*
4910Sstevel@tonic-gate * This byte is delta Y. If this is a plain mouse,
4920Sstevel@tonic-gate * we're done. Wheel mice have two different flavors
4930Sstevel@tonic-gate * of fourth byte.
4940Sstevel@tonic-gate */
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate if (elapsed > mouse_timeout) {
4970Sstevel@tonic-gate goto restart;
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate STATEP->deltay |= code & 0xff;
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate if (STATEP->vuid_mouse_mode == MOUSE_MODE_WHEEL) {
5020Sstevel@tonic-gate STATEP->state = PS2_WHEEL_DELTA_Z;
5030Sstevel@tonic-gate break;
5040Sstevel@tonic-gate } else if (STATEP->vuid_mouse_mode ==
5050Sstevel@tonic-gate MOUSE_MODE_WHEEL5) {
5060Sstevel@tonic-gate STATEP->state = PS2_WHEEL5_DELTA_Z;
5070Sstevel@tonic-gate break;
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate goto packet_complete;
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate case PS2_WHEEL5_DELTA_Z:
5120Sstevel@tonic-gate if (code & 0x10) {
5130Sstevel@tonic-gate /* fourth physical button */
5140Sstevel@tonic-gate VUID_PUTNEXT(qp, (uchar_t)BUT(4),
5150Sstevel@tonic-gate FE_PAIR_NONE, 0, 1);
5160Sstevel@tonic-gate VUID_PUTNEXT(qp, (uchar_t)BUT(4),
5170Sstevel@tonic-gate FE_PAIR_NONE, 0, 0);
5180Sstevel@tonic-gate } else if (code & 0x20) {
5190Sstevel@tonic-gate /* fifth physical button */
5200Sstevel@tonic-gate VUID_PUTNEXT(qp, (uchar_t)BUT(5),
5210Sstevel@tonic-gate FE_PAIR_NONE, 0, 1);
5220Sstevel@tonic-gate VUID_PUTNEXT(qp, (uchar_t)BUT(5),
5230Sstevel@tonic-gate FE_PAIR_NONE, 0, 0);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate /*FALLTHROUGH*/
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate case PS2_WHEEL_DELTA_Z:
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate * Check whether reporting vertical wheel
5300Sstevel@tonic-gate * movements is enabled
5310Sstevel@tonic-gate */
5320Sstevel@tonic-gate code &= 0xf;
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate if (STATEP->wheel_state_bf & (1 <<
5356990Sgd78059 VUIDMICE_VERTICAL_WHEEL_ID)) {
5360Sstevel@tonic-gate /*
5370Sstevel@tonic-gate * PS/2 mouse reports -ve values
5380Sstevel@tonic-gate * when the wheel is scrolled up. So
5390Sstevel@tonic-gate * we need to convert it into +ve as
5400Sstevel@tonic-gate * X interprets a +ve value as wheel up event.
5410Sstevel@tonic-gate * Same is true for the horizontal wheel also.
5420Sstevel@tonic-gate * The mouse reports 0xf when scrolled up
5430Sstevel@tonic-gate * and 0x1 when scrolled down. This observation
5440Sstevel@tonic-gate * is based on Logitech, HCL,
5450Sstevel@tonic-gate * Microsoft and Black Cat mouse only
5460Sstevel@tonic-gate */
5470Sstevel@tonic-gate if (code == 0xf) {
5480Sstevel@tonic-gate /* negative Z - wheel up */
5490Sstevel@tonic-gate code |= 0xfffffff0;
5500Sstevel@tonic-gate vuidmice_send_wheel_event(qp, 0,
5510Sstevel@tonic-gate FE_PAIR_NONE, 0, -code);
5520Sstevel@tonic-gate } else if (code == 0x01) {
5530Sstevel@tonic-gate /* positive Z - wheel down */
5540Sstevel@tonic-gate vuidmice_send_wheel_event(qp, 0,
5550Sstevel@tonic-gate FE_PAIR_NONE, 0, -code);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate /*
5600Sstevel@tonic-gate * Check whether reporting horizontal wheel
5610Sstevel@tonic-gate * movements is enabled
5620Sstevel@tonic-gate */
5630Sstevel@tonic-gate if (STATEP->wheel_state_bf &
5640Sstevel@tonic-gate (1 << VUIDMICE_HORIZONTAL_WHEEL_ID)) {
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate * The mouse return -7 and +7 when it
5680Sstevel@tonic-gate * is scrolled horizontally
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate if (code == 0x09) {
5710Sstevel@tonic-gate /* negative Z - wheel left */
5720Sstevel@tonic-gate vuidmice_send_wheel_event(qp, 1,
5730Sstevel@tonic-gate FE_PAIR_NONE, 0, 1);
5740Sstevel@tonic-gate } else if (code == 0x07) {
5750Sstevel@tonic-gate /* positive Z - wheel right */
5760Sstevel@tonic-gate vuidmice_send_wheel_event(qp, 1,
5770Sstevel@tonic-gate FE_PAIR_NONE, 0, -1);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate packet_complete:
5820Sstevel@tonic-gate STATEP->state = PS2_START;
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate * If we can peek at the next mouse character, and
5850Sstevel@tonic-gate * its not the start of the next packet, don't use
5860Sstevel@tonic-gate * this packet.
5870Sstevel@tonic-gate */
5886990Sgd78059 if (mp->b_wptr > mp->b_rptr &&
5890Sstevel@tonic-gate ((mp->b_rptr[0] ^ STATEP->sync_byte) & 0x08)) {
5900Sstevel@tonic-gate /*
5910Sstevel@tonic-gate * bit 3 not set
5920Sstevel@tonic-gate */
5930Sstevel@tonic-gate break;
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate /*
5970Sstevel@tonic-gate * send the info to the next level --
5980Sstevel@tonic-gate * need to send multiple events if we have both
5990Sstevel@tonic-gate * a delta *AND* button event(s)
6000Sstevel@tonic-gate */
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate /* motion has occurred ... */
6030Sstevel@tonic-gate if (STATEP->deltax)
6040Sstevel@tonic-gate VUID_PUTNEXT(qp, (uchar_t)LOC_X_DELTA,
6050Sstevel@tonic-gate FE_PAIR_ABSOLUTE, (uchar_t)LOC_X_ABSOLUTE,
6060Sstevel@tonic-gate STATEP->deltax);
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate if (STATEP->deltay)
6090Sstevel@tonic-gate VUID_PUTNEXT(qp, (uchar_t)LOC_Y_DELTA,
6100Sstevel@tonic-gate FE_PAIR_ABSOLUTE, (uchar_t)LOC_Y_ABSOLUTE,
6110Sstevel@tonic-gate STATEP->deltay);
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate STATEP->deltax = STATEP->deltay = 0;
6140Sstevel@tonic-gate break;
6150Sstevel@tonic-gate
61610087SSeth.Goldberg@Sun.COM case PS2_WAIT_RESET_COMPLETE:
61710087SSeth.Goldberg@Sun.COM
61810087SSeth.Goldberg@Sun.COM /*
61910087SSeth.Goldberg@Sun.COM * If length is 1, code holds the data from the message.
62010087SSeth.Goldberg@Sun.COM * for lengths > 1, we look at *(mp->b_rptr + offset)
62110087SSeth.Goldberg@Sun.COM * for the rest of the data.
62210087SSeth.Goldberg@Sun.COM */
62310087SSeth.Goldberg@Sun.COM if (length == 1) {
62410087SSeth.Goldberg@Sun.COM /*
625*10803SSeth.Goldberg@Sun.COM * A response with length 1 from the mouse
626*10803SSeth.Goldberg@Sun.COM * driver can be either an ACK (the first part
627*10803SSeth.Goldberg@Sun.COM * of the reset reply) or either MSEERROR or
628*10803SSeth.Goldberg@Sun.COM * MSERESEND. Issue another reset if either
629*10803SSeth.Goldberg@Sun.COM * of the latter are received. For mice that
630*10803SSeth.Goldberg@Sun.COM * are not connected, MSERESEND is received
631*10803SSeth.Goldberg@Sun.COM * quickly.
63210087SSeth.Goldberg@Sun.COM */
633*10803SSeth.Goldberg@Sun.COM
634*10803SSeth.Goldberg@Sun.COM if (code == MSE_ACK)
635*10803SSeth.Goldberg@Sun.COM break;
636*10803SSeth.Goldberg@Sun.COM
63710087SSeth.Goldberg@Sun.COM if (++STATEP->init_count >=
63810087SSeth.Goldberg@Sun.COM PS2_MAX_INIT_COUNT) {
63910087SSeth.Goldberg@Sun.COM STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
64010087SSeth.Goldberg@Sun.COM STATEP->state = PS2_WAIT_FOR_AA;
64110087SSeth.Goldberg@Sun.COM } else {
64210087SSeth.Goldberg@Sun.COM put1(WR(qp), MSERESET);
64310087SSeth.Goldberg@Sun.COM }
644*10803SSeth.Goldberg@Sun.COM
64510087SSeth.Goldberg@Sun.COM break;
64610087SSeth.Goldberg@Sun.COM
647*10803SSeth.Goldberg@Sun.COM } else if (length != 2) {
6480Sstevel@tonic-gate break;
6490Sstevel@tonic-gate }
650993Slq150181
651*10803SSeth.Goldberg@Sun.COM /*
652*10803SSeth.Goldberg@Sun.COM * The only possible 2-byte reply from mouse8042 is
653*10803SSeth.Goldberg@Sun.COM * 0xAA 0x00. If the mouse doesn't send that, mouse8042
654*10803SSeth.Goldberg@Sun.COM * will send a 1-byte error message, handled above by
655*10803SSeth.Goldberg@Sun.COM * resetting the mouse.
656*10803SSeth.Goldberg@Sun.COM */
657*10803SSeth.Goldberg@Sun.COM
658*10803SSeth.Goldberg@Sun.COM /* Skip past the 0x00 (since `code' contains 0xAA) */
659*10803SSeth.Goldberg@Sun.COM mp->b_rptr += 1;
6600Sstevel@tonic-gate
66110087SSeth.Goldberg@Sun.COM /* Reset completed successfully */
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate STATEP->state = PS2_WAIT_SETRES0_ACK1;
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate /* Set timeout for set res */
666993Slq150181 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
6670Sstevel@tonic-gate
66810087SSeth.Goldberg@Sun.COM /* Begin Logitech autodetect sequence */
669993Slq150181 put1(WR(qp), MSESETRES);
6700Sstevel@tonic-gate break;
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate case PS2_WAIT_SETRES0_ACK1:
6730Sstevel@tonic-gate if (code != MSE_ACK) {
6740Sstevel@tonic-gate break;
6750Sstevel@tonic-gate }
676993Slq150181 STATEP->state = PS2_WAIT_SETRES0_ACK2;
6770Sstevel@tonic-gate put1(WR(qp), 0);
6780Sstevel@tonic-gate break;
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate case PS2_WAIT_SETRES0_ACK2:
6810Sstevel@tonic-gate case PS2_WAIT_SCALE1_1_ACK:
6820Sstevel@tonic-gate case PS2_WAIT_SCALE1_2_ACK:
6830Sstevel@tonic-gate if (code != MSE_ACK) {
6840Sstevel@tonic-gate break;
6850Sstevel@tonic-gate }
686993Slq150181 STATEP->state++;
6870Sstevel@tonic-gate put1(WR(qp), MSESCALE1);
6880Sstevel@tonic-gate break;
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate case PS2_WAIT_SCALE1_3_ACK:
6910Sstevel@tonic-gate if (code != MSE_ACK) {
6920Sstevel@tonic-gate break;
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate /* Set res and scale have been ok */
6960Sstevel@tonic-gate vuid_cancel_timeout(qp);
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate STATEP->state = PS2_WAIT_STATREQ_ACK;
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate /* Set timeout for status request */
701993Slq150181 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
702993Slq150181
703993Slq150181 put1(WR(qp), MSESTATREQ);
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate break;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate case PS2_WAIT_STATREQ_ACK:
7080Sstevel@tonic-gate if (code != MSE_ACK) {
7090Sstevel@tonic-gate break;
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate STATEP->state = PS2_WAIT_STATUS_1;
7120Sstevel@tonic-gate break;
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate case PS2_WAIT_STATUS_1:
7150Sstevel@tonic-gate STATEP->state = PS2_WAIT_STATUS_BUTTONS;
7160Sstevel@tonic-gate break;
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate case PS2_WAIT_STATUS_BUTTONS:
7190Sstevel@tonic-gate if (code != 0) {
7200Sstevel@tonic-gate STATEP->nbuttons = (uchar_t)code;
7210Sstevel@tonic-gate STATEP->state = (uchar_t)PS2_WAIT_STATUS_REV;
7220Sstevel@tonic-gate } else {
7230Sstevel@tonic-gate #if defined(VUID3PS2)
7240Sstevel@tonic-gate /*
7250Sstevel@tonic-gate * It seems that there are some 3-button mice
7260Sstevel@tonic-gate * that don't play the Logitech autodetect
7270Sstevel@tonic-gate * game. One is a Mouse Systems mouse OEM'ed
7280Sstevel@tonic-gate * by Intergraph.
7290Sstevel@tonic-gate *
7300Sstevel@tonic-gate * Until we find out how to autodetect these
7310Sstevel@tonic-gate * mice, we'll assume that if we're being
7320Sstevel@tonic-gate * compiled as vuid3ps2 and the mouse doesn't
7330Sstevel@tonic-gate * play the autodetect game, it's a 3-button
7340Sstevel@tonic-gate * mouse. This effectively disables
7350Sstevel@tonic-gate * autodetect for mice using vuid3ps2, but
7360Sstevel@tonic-gate * since vuid3ps2 is used only on x86 where
7370Sstevel@tonic-gate * we currently assume manual configuration,
7380Sstevel@tonic-gate * this shouldn't be a problem. At some point
7390Sstevel@tonic-gate * in the future when we *do* start using
7400Sstevel@tonic-gate * autodetect on x86, we should probably define
7410Sstevel@tonic-gate * VUIDPS2 instead of VUID3PS2. Even then,
7420Sstevel@tonic-gate * we could leave this code so that *some*
7430Sstevel@tonic-gate * mice could use autodetect and others not.
7440Sstevel@tonic-gate */
7450Sstevel@tonic-gate STATEP->nbuttons = 3;
7460Sstevel@tonic-gate #else
7470Sstevel@tonic-gate STATEP->nbuttons = 2;
7480Sstevel@tonic-gate #endif
7490Sstevel@tonic-gate STATEP->state = PS2_WAIT_STATUS_3;
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate break;
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate case PS2_WAIT_STATUS_REV:
7540Sstevel@tonic-gate /*FALLTHROUGH*/
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate case PS2_WAIT_STATUS_3:
7570Sstevel@tonic-gate
75810087SSeth.Goldberg@Sun.COM /* Status request completed successfully */
7590Sstevel@tonic-gate vuid_cancel_timeout(qp);
7600Sstevel@tonic-gate
76110087SSeth.Goldberg@Sun.COM vuidmice_start_wdc_or_setres(qp);
76210087SSeth.Goldberg@Sun.COM break;
763993Slq150181
7640Sstevel@tonic-gate case PS2_WAIT_WHEEL_SMPL1_CMD_ACK:
7650Sstevel@tonic-gate if (code != MSE_ACK) {
7660Sstevel@tonic-gate break;
7670Sstevel@tonic-gate }
768993Slq150181 STATEP->state = PS2_WAIT_WHEEL_SMPL1_RATE_ACK;
7690Sstevel@tonic-gate put1(WR(qp), 200);
7700Sstevel@tonic-gate break;
7710Sstevel@tonic-gate case PS2_WAIT_WHEEL_SMPL1_RATE_ACK:
7720Sstevel@tonic-gate if (code != MSE_ACK) {
7730Sstevel@tonic-gate break;
7740Sstevel@tonic-gate }
775993Slq150181 STATEP->state = PS2_WAIT_WHEEL_SMPL2_CMD_ACK;
7760Sstevel@tonic-gate put1(WR(qp), MSECHGMOD);
7770Sstevel@tonic-gate break;
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate case PS2_WAIT_WHEEL_SMPL2_CMD_ACK:
7800Sstevel@tonic-gate if (code != MSE_ACK) {
7810Sstevel@tonic-gate break;
7820Sstevel@tonic-gate }
783993Slq150181 STATEP->state = PS2_WAIT_WHEEL_SMPL2_RATE_ACK;
7840Sstevel@tonic-gate put1(WR(qp), 100);
7850Sstevel@tonic-gate break;
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate case PS2_WAIT_WHEEL_SMPL2_RATE_ACK:
7880Sstevel@tonic-gate if (code != MSE_ACK) {
7890Sstevel@tonic-gate break;
7900Sstevel@tonic-gate }
791993Slq150181 STATEP->state = PS2_WAIT_WHEEL_SMPL3_CMD_ACK;
7920Sstevel@tonic-gate put1(WR(qp), MSECHGMOD);
7930Sstevel@tonic-gate break;
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate case PS2_WAIT_WHEEL_SMPL3_CMD_ACK:
7960Sstevel@tonic-gate if (code != MSE_ACK) {
7970Sstevel@tonic-gate break;
7980Sstevel@tonic-gate }
799993Slq150181 STATEP->state = PS2_WAIT_WHEEL_SMPL3_RATE_ACK;
8000Sstevel@tonic-gate put1(WR(qp), 80);
8010Sstevel@tonic-gate break;
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate case PS2_WAIT_WHEEL_SMPL3_RATE_ACK:
8040Sstevel@tonic-gate if (code != MSE_ACK) {
8050Sstevel@tonic-gate break;
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate
80810087SSeth.Goldberg@Sun.COM /* Set sample rate completed successfully */
8090Sstevel@tonic-gate vuid_cancel_timeout(qp);
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate STATEP->state = PS2_WAIT_WHEEL_DEV_CMD;
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate /* Set timeout for get dev */
8140Sstevel@tonic-gate vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
8150Sstevel@tonic-gate
816993Slq150181 put1(WR(qp), MSEGETDEV);
8170Sstevel@tonic-gate break;
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate case PS2_WAIT_WHEEL_DEV_CMD:
8200Sstevel@tonic-gate if (code != MSE_ACK) {
8210Sstevel@tonic-gate break;
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate STATEP->state = PS2_WAIT_WHEEL_DEV_ACK;
8240Sstevel@tonic-gate break;
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate case PS2_WAIT_WHEEL_DEV_ACK:
8270Sstevel@tonic-gate
82810087SSeth.Goldberg@Sun.COM /* Get dev completed successfully */
8290Sstevel@tonic-gate vuid_cancel_timeout(qp);
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate if (code != 0x03) {
8320Sstevel@tonic-gate STATEP->state = PS2_WAIT_SETRES3_ACK1;
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate /* Set timeout for set res */
8350Sstevel@tonic-gate vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
8360Sstevel@tonic-gate
837993Slq150181 put1(WR(qp), MSESETRES);
838993Slq150181
8390Sstevel@tonic-gate break;
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL;
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate /*
8450Sstevel@tonic-gate * Found wheel. By default enable the wheel.
8460Sstevel@tonic-gate */
8470Sstevel@tonic-gate STATEP->wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate STATEP->state = PS2_WAIT_WHEEL5_SMPL1_CMD_ACK;
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate /* Set timeout for set sample rate */
852993Slq150181 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
853993Slq150181
854993Slq150181 /* We're on a roll - try for wheel+5 */
855993Slq150181 put1(WR(qp), MSECHGMOD);
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate break;
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate case PS2_WAIT_WHEEL5_SMPL1_CMD_ACK:
8600Sstevel@tonic-gate if (code != MSE_ACK) {
8610Sstevel@tonic-gate break;
8620Sstevel@tonic-gate }
863993Slq150181 STATEP->state = PS2_WAIT_WHEEL5_SMPL1_RATE_ACK;
8640Sstevel@tonic-gate put1(WR(qp), 200);
8650Sstevel@tonic-gate break;
8660Sstevel@tonic-gate
8670Sstevel@tonic-gate case PS2_WAIT_WHEEL5_SMPL1_RATE_ACK:
8680Sstevel@tonic-gate if (code != MSE_ACK) {
8690Sstevel@tonic-gate break;
8700Sstevel@tonic-gate }
871993Slq150181 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_CMD_ACK;
8720Sstevel@tonic-gate put1(WR(qp), MSECHGMOD);
8730Sstevel@tonic-gate break;
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate case PS2_WAIT_WHEEL5_SMPL2_CMD_ACK:
8760Sstevel@tonic-gate if (code != MSE_ACK) {
8770Sstevel@tonic-gate break;
8780Sstevel@tonic-gate }
879993Slq150181 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_RATE_ACK;
8800Sstevel@tonic-gate put1(WR(qp), 200);
8810Sstevel@tonic-gate break;
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate case PS2_WAIT_WHEEL5_SMPL2_RATE_ACK:
8840Sstevel@tonic-gate if (code != MSE_ACK) {
8850Sstevel@tonic-gate break;
8860Sstevel@tonic-gate }
887993Slq150181 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_CMD_ACK;
8880Sstevel@tonic-gate put1(WR(qp), MSECHGMOD);
8890Sstevel@tonic-gate break;
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate case PS2_WAIT_WHEEL5_SMPL3_CMD_ACK:
8920Sstevel@tonic-gate if (code != MSE_ACK) {
8930Sstevel@tonic-gate break;
8940Sstevel@tonic-gate }
895993Slq150181 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_RATE_ACK;
8960Sstevel@tonic-gate put1(WR(qp), 80);
8970Sstevel@tonic-gate break;
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate case PS2_WAIT_WHEEL5_SMPL3_RATE_ACK:
9000Sstevel@tonic-gate if (code != MSE_ACK) {
9010Sstevel@tonic-gate break;
9020Sstevel@tonic-gate }
9030Sstevel@tonic-gate
90410087SSeth.Goldberg@Sun.COM /* Set sample rate completed successfully */
9050Sstevel@tonic-gate vuid_cancel_timeout(qp);
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD;
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate /* Set timeout for wheel5 get dev */
9100Sstevel@tonic-gate vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
9110Sstevel@tonic-gate
912993Slq150181 put1(WR(qp), MSEGETDEV);
913993Slq150181
9140Sstevel@tonic-gate break;
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate case PS2_WAIT_WHEEL5_DEV_CMD:
9170Sstevel@tonic-gate if (code != MSE_ACK) {
9180Sstevel@tonic-gate break;
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate STATEP->state = PS2_WAIT_WHEEL5_DEV_ACK;
9210Sstevel@tonic-gate break;
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate case PS2_WAIT_WHEEL5_DEV_ACK:
9240Sstevel@tonic-gate if (code == 0x04) {
9250Sstevel@tonic-gate STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL5;
9260Sstevel@tonic-gate STATEP->nbuttons = 5;
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate /*
9290Sstevel@tonic-gate * Found wheel. By default enable the wheel.
9300Sstevel@tonic-gate */
9310Sstevel@tonic-gate STATEP->wheel_state_bf |=
9320Sstevel@tonic-gate VUID_WHEEL_STATE_ENABLED <<
9330Sstevel@tonic-gate MOUSE_MODE_WHEEL;
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate
93610087SSeth.Goldberg@Sun.COM /* Wheel5 get dev completed successfully */
9370Sstevel@tonic-gate vuid_cancel_timeout(qp);
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate /* FALLTHROUGH */
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate case PS2_WAIT_SETRES3_CMD:
9420Sstevel@tonic-gate STATEP->state = PS2_WAIT_SETRES3_ACK1;
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate /* Set timeout for set res */
9450Sstevel@tonic-gate vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
9460Sstevel@tonic-gate
947993Slq150181 put1(WR(qp), MSESETRES);
948993Slq150181
9490Sstevel@tonic-gate break;
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate case PS2_WAIT_SETRES3_ACK1:
9520Sstevel@tonic-gate if (code != MSE_ACK) {
9530Sstevel@tonic-gate break;
9540Sstevel@tonic-gate }
955993Slq150181 STATEP->state = PS2_WAIT_SETRES3_ACK2;
9560Sstevel@tonic-gate put1(WR(qp), 3);
9570Sstevel@tonic-gate break;
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate case PS2_WAIT_SETRES3_ACK2:
9600Sstevel@tonic-gate if (code != MSE_ACK) {
9610Sstevel@tonic-gate break;
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate
96410087SSeth.Goldberg@Sun.COM /* Set res completed successfully */
9650Sstevel@tonic-gate vuid_cancel_timeout(qp);
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate STATEP->state = PS2_WAIT_STREAM_ACK;
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate /* Set timeout for enable */
9700Sstevel@tonic-gate vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
9710Sstevel@tonic-gate
972993Slq150181 put1(WR(qp), MSESTREAM);
973993Slq150181
9740Sstevel@tonic-gate break;
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate case PS2_WAIT_STREAM_ACK:
9770Sstevel@tonic-gate if (code != MSE_ACK) {
9780Sstevel@tonic-gate break;
9790Sstevel@tonic-gate }
980993Slq150181 STATEP->state = PS2_WAIT_ON_ACK;
9810Sstevel@tonic-gate put1(WR(qp), MSEON);
9820Sstevel@tonic-gate break;
9830Sstevel@tonic-gate
9840Sstevel@tonic-gate case PS2_WAIT_ON_ACK:
9850Sstevel@tonic-gate if (code != MSE_ACK) {
9860Sstevel@tonic-gate break;
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate
98910087SSeth.Goldberg@Sun.COM /* Enable completed successfully */
99010087SSeth.Goldberg@Sun.COM
99110087SSeth.Goldberg@Sun.COM /*
99210087SSeth.Goldberg@Sun.COM * The entire initialization sequence
99310087SSeth.Goldberg@Sun.COM * is complete. Now, we can clear the
99410087SSeth.Goldberg@Sun.COM * init_count retry counter.
99510087SSeth.Goldberg@Sun.COM */
99610087SSeth.Goldberg@Sun.COM STATEP->init_count = 0;
9970Sstevel@tonic-gate vuid_cancel_timeout(qp);
9980Sstevel@tonic-gate
99910087SSeth.Goldberg@Sun.COM
10000Sstevel@tonic-gate STATEP->state = PS2_START;
10010Sstevel@tonic-gate break;
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate freemsg(mp);
10050Sstevel@tonic-gate }
1006