/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* 2/3/5 Button PS/2 Mouse Protocol
*
* This module dynamically determines the number of buttons on the mouse.
*/
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/vuid_event.h>
#include "vuidmice.h"
#include <sys/vuid_wheel.h>
#include <sys/mouse.h>
#include <sys/strsun.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
/*
* BUT(1) LEFT BUTTON
* BUT(2) MIDDLE BUTTON (if present)
* BUT(3) RIGHT BUTTON
*/
#define PS2_BUTTONMASK 7 /* mask byte zero with this */
#define PS2_BUTTON_L (uchar_t)0x01 /* Left button pressed */
#define PS2_BUTTON_R (uchar_t)0x02 /* Right button pressed */
#define PS2_BUTTON_M (uchar_t)0x04 /* Middle button pressed */
#define PS2_DATA_XSIGN (uchar_t)0x10 /* X data sign bit */
#define PS2_DATA_YSIGN (uchar_t)0x20 /* Y data sign bit */
#define PS2_START 0 /* Beginning of packet */
#define PS2_BUTTON 1 /* Got button status */
#define PS2_MAYBE_REATTACH 2 /* Got button status */
#define PS2_DELTA_Y 3 /* Got delta X */
#define PS2_WHEEL_DELTA_Z 4
#define PS2_WHEEL5_DELTA_Z 5
#define PS2_WAIT_RESET_COMPLETE 6
#define PS2_WAIT_FOR_AA 7
#define PS2_WAIT_FOR_00 8
#define PS2_WAIT_SETRES0_ACK1 9
#define PS2_WAIT_SETRES0_ACK2 10 /* -+ must be consecutive */
#define PS2_WAIT_SCALE1_1_ACK 11 /* | */
#define PS2_WAIT_SCALE1_2_ACK 12 /* | */
#define PS2_WAIT_SCALE1_3_ACK 13 /* -+ */
#define PS2_WAIT_STATREQ_ACK 14 /* -+ */
#define PS2_WAIT_STATUS_1 15 /* | */
#define PS2_WAIT_STATUS_BUTTONS 16 /* | must stay in this order */
#define PS2_WAIT_STATUS_REV 17 /* -+ */
#define PS2_WAIT_STATUS_3 18
#define PS2_WAIT_WHEEL_SMPL1_CMD_ACK 19 /* Set the sample rate to 200 */
#define PS2_WAIT_WHEEL_SMPL1_RATE_ACK 20
#define PS2_WAIT_WHEEL_SMPL2_CMD_ACK 21 /* Set the sample rate to 200 */
#define PS2_WAIT_WHEEL_SMPL2_RATE_ACK 22
#define PS2_WAIT_WHEEL_SMPL3_CMD_ACK 23 /* Set the sample rate to 80 */
#define PS2_WAIT_WHEEL_SMPL3_RATE_ACK 24
#define PS2_WAIT_WHEEL_DEV_CMD 25
#define PS2_WAIT_WHEEL_DEV_ACK 26 /* Detected wheel mouse */
#define PS2_WAIT_WHEEL5_SMPL1_CMD_ACK 27 /* Set the sample rate to 200 */
#define PS2_WAIT_WHEEL5_SMPL1_RATE_ACK 28
#define PS2_WAIT_WHEEL5_SMPL2_CMD_ACK 29 /* Set the sample rate to 200 */
#define PS2_WAIT_WHEEL5_SMPL2_RATE_ACK 30
#define PS2_WAIT_WHEEL5_SMPL3_CMD_ACK 31 /* Set the sample rate to 100 */
#define PS2_WAIT_WHEEL5_SMPL3_RATE_ACK 32
#define PS2_WAIT_WHEEL5_DEV_CMD 33
#define PS2_WAIT_WHEEL5_DEV_ACK 34 /* Detected 5 button mouse */
#define PS2_WAIT_SETRES3_CMD 35
#define PS2_WAIT_SETRES3_ACK1 36
#define PS2_WAIT_SETRES3_ACK2 37
#define PS2_WAIT_STREAM_ACK 38
#define PS2_WAIT_ON_ACK 39
#define MOUSE_MODE_PLAIN 0 /* Normal PS/2 mouse - 3 byte msgs */
#define MOUSE_MODE_WHEEL 1 /* Wheel mouse - 4 byte msgs */
#define MOUSE_MODE_WHEEL5 2 /* Wheel + 5 btn mouse - 4 byte msgs */
#define PS2_FLAG_NO_EXTN 0x08 /* Mouse doesn't obey extended cmds */
#define PS2_FLAG_INIT_DONE 0x01 /* Mouse has been inited successfully */
#define PS2_FLAG_INIT_TIMEOUT 0x02 /* Mouse init timeout */
/*
* The RESET command takes more time
* before the PS/2 mouse is ready
*/
#define PS2_INIT_TMOUT_RESET 500000 /* 500ms for RESET command */
#define PS2_INIT_TMOUT_PER_CMD 200000 /* 200ms for each command-response */
#define PS2_INIT_TMOUT_PER_GROUP 500000 /* 500ms for group commands */
#define PS2_MAX_INIT_COUNT 5
static void vuidmice_send_wheel_event(queue_t *const, uchar_t,
uchar_t, uchar_t, int);
extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int);
extern void uniqtime32(struct timeval32 *);
static void VUID_INIT_TIMEOUT(void *q);
/*
* We apply timeout to nearly each command-response
* during initialization:
*
* Set timeout for SET RESOLUTION
* Set timeout for SET SCALE
* Set timeout for SET SAMPLE RATE
* Set timeout for STATUS REQUEST
* Set timeout for GET DEV
* Set timeout for SET STREAM MODE and ENABLE.
*
* But for simplicity, sometimes we just apply the timeout
* to a function with group commands (e.g. wheel-mouse detection).
*
*/
static void
vuid_set_timeout(queue_t *const qp, clock_t time)
{
if (STATEP->init_tid != 0)
(void) quntimeout(qp, STATEP->init_tid);
STATEP->init_tid = qtimeout(qp, VUID_INIT_TIMEOUT,
qp, drv_usectohz(time));
}
static void
vuid_cancel_timeout(queue_t *const qp)
{
(void) quntimeout(qp, STATEP->init_tid);
STATEP->init_tid = 0;
}
/*
* vuidmice_send_wheel_event
* Convert wheel data to firm_events
*/
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)
{
mblk_t *bp;
Firm_event *fep;
if ((bp = allocb((int)sizeof (Firm_event), BPRI_HI)) == NULL) {
return;
}
fep = (void *)bp->b_wptr;
fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) |
vuid_id_offset(event_id);
fep->pair_type = event_pair_type;
fep->pair = event_pair;
fep->value = event_value;
uniqtime32(&fep->time);
bp->b_wptr += sizeof (Firm_event);
if (canput(qp->q_next)) {
putnext(qp, bp);
} else {
(void) putbq(qp, bp); /* read side is blocked */
}
}
static void
sendButtonEvent(queue_t *const qp)
{
static int bmap[3] = {1, 3, 2};
uint_t b;
/* for each button, see if it has changed */
for (b = 0; b < STATEP->nbuttons; b++) {
uchar_t mask = 0x1 << b;
if ((STATEP->buttons & mask) != (STATEP->oldbuttons & mask))
VUID_PUTNEXT(qp, (uchar_t)BUT(bmap[b]), FE_PAIR_NONE, 0,
(STATEP->buttons & mask ? 1 : 0));
}
}
void
put1(queue_t *const qp, int c)
{
mblk_t *bp;
if (bp = allocb(1, BPRI_MED)) {
*bp->b_wptr++ = (char)c;
putnext(qp, bp);
}
}
static void
vuidmice_start_wdc_or_setres(queue_t *qp)
{
/* Set timeout for set res or sample rate */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
/*
* Start the wheel-mouse detection code. First, we look
* for standard wheel mice. If we set the sample rate
* to 200, 100, and then 80 and finally request the
* device ID, a wheel mouse will return an ID of 0x03.
* After that, we'll try for the wheel+5 variety. The
* incantation in this case is 200, 200, and 80. We'll
* get 0x04 back in that case.
*/
if (STATEP->inited & PS2_FLAG_NO_EXTN) {
STATEP->state = PS2_WAIT_SETRES3_ACK1;
put1(WR(qp), MSESETRES);
} else {
STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK;
put1(WR(qp), MSECHGMOD);
}
}
int
VUID_OPEN(queue_t *const qp)
{
STATEP->format = VUID_FIRM_EVENT;
STATEP->vuid_mouse_mode = MOUSE_MODE_PLAIN;
STATEP->inited = 0;
STATEP->nbuttons = 3;
STATEP->state = PS2_WAIT_RESET_COMPLETE;
put1(WR(qp), MSERESET);
while ((STATEP->state != PS2_START) &&
!(STATEP->inited & PS2_FLAG_INIT_TIMEOUT)) {
if (qwait_sig(qp) == 0)
break;
}
/*
* Later the PS/2 mouse maybe re-attach, so here
* clear the init_count.
*/
STATEP->init_count = 0;
return (0);
}
void
VUID_CLOSE(queue_t *const qp)
{
if (STATEP->init_tid != 0)
vuid_cancel_timeout(qp);
}
static void
VUID_INIT_TIMEOUT(void *q)
{
queue_t *qp = q;
STATEP->init_tid = 0;
/*
* Some mice do not even send an error in response to
* the wheel mouse sample commands, so if we're in any of
* the PS2_WAIT_WHEEL_SMPL* states, and there has been
* a timeout, assume the mouse cannot handle the extended
* (wheel mouse) commands.
*/
if ((STATEP->state == PS2_WAIT_WHEEL_SMPL1_CMD_ACK) ||
(STATEP->state == PS2_WAIT_WHEEL_SMPL1_RATE_ACK) ||
(STATEP->state == PS2_WAIT_WHEEL_SMPL2_RATE_ACK) ||
(STATEP->state == PS2_WAIT_WHEEL_SMPL3_RATE_ACK)) {
/*
* We overload 'inited' to mark the PS/2 mouse
* as one which doesn't respond to extended commands.
*/
STATEP->inited |= PS2_FLAG_NO_EXTN;
}
/*
* If the Logitech button detection sequence timed out at some point
* in the sequence, ignore it and skip to the next step in
* initialization. Do NOT count this as a timeout, so do NOT
* increment init_count.
*/
if (STATEP->state >= PS2_WAIT_STATREQ_ACK &&
STATEP->state <= PS2_WAIT_STATUS_REV) {
/* See the comment under the PS2_WAIT_STATUS_BUTTONS case */
#if defined(VUID3PS2)
STATEP->nbuttons = 3;
#else
STATEP->nbuttons = 2;
#endif
vuidmice_start_wdc_or_setres(qp);
return;
}
/*
* If the initialization process has timed out too many times, even if
* a subset of the process was successful, stop trying and put the
* mouse in the only state from which it can recover -- waiting for an
* 0xAA 0x00 response (i.e. like one we get on resume from mouse8042
* or from a replug).
*/
if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) {
STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
STATEP->state = PS2_WAIT_FOR_AA;
} else {
STATEP->state = PS2_WAIT_RESET_COMPLETE;
/* Try to reset the mouse again */
put1(WR(qp), MSERESET);
}
}
void
VUID_QUEUE(queue_t *const qp, mblk_t *mp)
{
int code, length;
clock_t now;
clock_t elapsed;
clock_t mouse_timeout;
mouse_timeout = drv_usectohz(250000);
now = ddi_get_lbolt();
elapsed = now - STATEP->last_event_lbolt;
STATEP->last_event_lbolt = now;
while (mp->b_rptr < mp->b_wptr) {
length = MBLKL(mp);
code = *mp->b_rptr++;
switch (STATEP->state) {
/*
* Start state. We stay here if the start code is not
* received thus forcing us back into sync. When we get a
* start code the button mask comes with it forcing us to
* to the next state.
*/
restart:
case PS2_START:
/*
* 3-byte packet format
*
* Bit 7 6 5 4 3 2 1 0
* Byte ---- ---- ----- ----- -- ------ ------ ------
* 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn
* 2 |<--------------X Movement----------------->|
* 3 |<--------------Y Movement----------------->|
*
* 4-byte wheel packet format
*
* Bit 7 6 5 4 3 2 1 0
* Byte ---- ---- ----- ----- -- ------ ------ ------
* 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn
* 2 |<--------------X Movement----------------->|
* 3 |<--------------Y Movement----------------->|
* 4 |<--------------Z Movement----------------->|
*
* 4-byte wheel+5 packet format
*
* Bit 7 6 5 4 3 2 1 0
* Byte ---- ---- ----- ----- -- ------ ------ ------
* 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn
* 2 |<--------------X Movement----------------->|
* 3 |<--------------Y Movement----------------->|
* 4 0 0 5_Btn 4_Btn Z3 Z2 Z1 Z0
*/
if (!(STATEP->inited & PS2_FLAG_INIT_DONE)) {
STATEP->sync_byte = code & 0x8;
STATEP->inited |= PS2_FLAG_INIT_DONE;
}
/*
* the PS/2 mouse data format doesn't have any sort of sync
* data to make sure we are in sync with the packet stream,
* but the Technical Reference manual states that bits 2 & 3
* of the first byte are reserved. Logitech uses bit 2 for
* the middle button. We HOPE that noone uses bit 3 though,
* and decide we're out of sync if bit 3 is not set here.
*/
if ((code ^ STATEP->sync_byte) & 0x08) {
/* bit 3 not set */
STATEP->state = PS2_START;
break; /* toss the code */
}
/* get the button values */
STATEP->buttons = code & PS2_BUTTONMASK;
if (STATEP->buttons != STATEP->oldbuttons) {
sendButtonEvent(qp);
STATEP->oldbuttons = STATEP->buttons;
}
/* bit 5 indicates Y value is negative (the sign bit) */
if (code & PS2_DATA_YSIGN)
STATEP->deltay = -1 & ~0xff;
else
STATEP->deltay = 0;
/* bit 4 is X sign bit */
if (code & PS2_DATA_XSIGN)
STATEP->deltax = -1 & ~0xff;
else
STATEP->deltax = 0;
if (code == MSE_AA)
STATEP->state = PS2_MAYBE_REATTACH;
else
STATEP->state = PS2_BUTTON;
break;
case PS2_WAIT_FOR_AA:
/*
* On Dell latitude D800, the initial MSE_ACK is
* received after the initialization sequence
* times out, so restart it here.
*/
if (code == MSE_ACK) {
STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
STATEP->init_count = 0;
STATEP->state = PS2_WAIT_RESET_COMPLETE;
put1(WR(qp), MSERESET);
break;
}
if (code != MSE_AA)
break;
STATEP->state = PS2_WAIT_FOR_00;
break;
case PS2_WAIT_FOR_00:
if (code != MSE_00)
break;
STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT;
STATEP->init_count = 0;
STATEP->state = PS2_WAIT_RESET_COMPLETE;
put1(WR(qp), MSERESET);
break;
case PS2_MAYBE_REATTACH:
if (code == MSE_00) {
STATEP->state = PS2_WAIT_RESET_COMPLETE;
put1(WR(qp), MSERESET);
break;
}
/*FALLTHROUGH*/
case PS2_BUTTON:
/*
* Now for the 7 bits of delta x. "Or" in
* the sign bit and continue. This is ac-
* tually a signed 9 bit number, but I just
* truncate it to a signed char in order to
* avoid changing and retesting all of the
* mouse-related modules for this patch.
*/
if (elapsed > mouse_timeout)
goto restart;
STATEP->deltax |= code & 0xff;
STATEP->state = PS2_DELTA_Y;
break;
case PS2_DELTA_Y:
/*
* This byte is delta Y. If this is a plain mouse,
* we're done. Wheel mice have two different flavors
* of fourth byte.
*/
if (elapsed > mouse_timeout) {
goto restart;
}
STATEP->deltay |= code & 0xff;
if (STATEP->vuid_mouse_mode == MOUSE_MODE_WHEEL) {
STATEP->state = PS2_WHEEL_DELTA_Z;
break;
} else if (STATEP->vuid_mouse_mode ==
MOUSE_MODE_WHEEL5) {
STATEP->state = PS2_WHEEL5_DELTA_Z;
break;
}
goto packet_complete;
case PS2_WHEEL5_DELTA_Z:
if (code & 0x10) {
/* fourth physical button */
VUID_PUTNEXT(qp, (uchar_t)BUT(4),
FE_PAIR_NONE, 0, 1);
VUID_PUTNEXT(qp, (uchar_t)BUT(4),
FE_PAIR_NONE, 0, 0);
} else if (code & 0x20) {
/* fifth physical button */
VUID_PUTNEXT(qp, (uchar_t)BUT(5),
FE_PAIR_NONE, 0, 1);
VUID_PUTNEXT(qp, (uchar_t)BUT(5),
FE_PAIR_NONE, 0, 0);
}
/*FALLTHROUGH*/
case PS2_WHEEL_DELTA_Z:
/*
* Check whether reporting vertical wheel
* movements is enabled
*/
code &= 0xf;
if (STATEP->wheel_state_bf & (1 <<
VUIDMICE_VERTICAL_WHEEL_ID)) {
/*
* PS/2 mouse reports -ve values
* when the wheel is scrolled up. So
* we need to convert it into +ve as
* X interprets a +ve value as wheel up event.
* Same is true for the horizontal wheel also.
* The mouse reports 0xf when scrolled up
* and 0x1 when scrolled down. This observation
* is based on Logitech, HCL,
* Microsoft and Black Cat mouse only
*/
if (code == 0xf) {
/* negative Z - wheel up */
code |= 0xfffffff0;
vuidmice_send_wheel_event(qp, 0,
FE_PAIR_NONE, 0, -code);
} else if (code == 0x01) {
/* positive Z - wheel down */
vuidmice_send_wheel_event(qp, 0,
FE_PAIR_NONE, 0, -code);
}
}
/*
* Check whether reporting horizontal wheel
* movements is enabled
*/
if (STATEP->wheel_state_bf &
(1 << VUIDMICE_HORIZONTAL_WHEEL_ID)) {
/*
* The mouse return -7 and +7 when it
* is scrolled horizontally
*/
if (code == 0x09) {
/* negative Z - wheel left */
vuidmice_send_wheel_event(qp, 1,
FE_PAIR_NONE, 0, 1);
} else if (code == 0x07) {
/* positive Z - wheel right */
vuidmice_send_wheel_event(qp, 1,
FE_PAIR_NONE, 0, -1);
}
}
packet_complete:
STATEP->state = PS2_START;
/*
* If we can peek at the next mouse character, and
* its not the start of the next packet, don't use
* this packet.
*/
if (mp->b_wptr > mp->b_rptr &&
((mp->b_rptr[0] ^ STATEP->sync_byte) & 0x08)) {
/*
* bit 3 not set
*/
break;
}
/*
* send the info to the next level --
* need to send multiple events if we have both
* a delta *AND* button event(s)
*/
/* motion has occurred ... */
if (STATEP->deltax)
VUID_PUTNEXT(qp, (uchar_t)LOC_X_DELTA,
FE_PAIR_ABSOLUTE, (uchar_t)LOC_X_ABSOLUTE,
STATEP->deltax);
if (STATEP->deltay)
VUID_PUTNEXT(qp, (uchar_t)LOC_Y_DELTA,
FE_PAIR_ABSOLUTE, (uchar_t)LOC_Y_ABSOLUTE,
STATEP->deltay);
STATEP->deltax = STATEP->deltay = 0;
break;
case PS2_WAIT_RESET_COMPLETE:
/*
* If length is 1, code holds the data from the message.
* for lengths > 1, we look at *(mp->b_rptr + offset)
* for the rest of the data.
*/
if (length == 1) {
/*
* A response with length 1 from the mouse
* driver can be either an ACK (the first part
* of the reset reply) or either MSEERROR or
* MSERESEND. Issue another reset if either
* of the latter are received. For mice that
* are not connected, MSERESEND is received
* quickly.
*/
if (code == MSE_ACK)
break;
if (++STATEP->init_count >=
PS2_MAX_INIT_COUNT) {
STATEP->inited |= PS2_FLAG_INIT_TIMEOUT;
STATEP->state = PS2_WAIT_FOR_AA;
} else {
put1(WR(qp), MSERESET);
}
break;
} else if (length != 2) {
break;
}
/*
* The only possible 2-byte reply from mouse8042 is
* 0xAA 0x00. If the mouse doesn't send that, mouse8042
* will send a 1-byte error message, handled above by
* resetting the mouse.
*/
/* Skip past the 0x00 (since `code' contains 0xAA) */
mp->b_rptr += 1;
/* Reset completed successfully */
STATEP->state = PS2_WAIT_SETRES0_ACK1;
/* Set timeout for set res */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
/* Begin Logitech autodetect sequence */
put1(WR(qp), MSESETRES);
break;
case PS2_WAIT_SETRES0_ACK1:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_SETRES0_ACK2;
put1(WR(qp), 0);
break;
case PS2_WAIT_SETRES0_ACK2:
case PS2_WAIT_SCALE1_1_ACK:
case PS2_WAIT_SCALE1_2_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state++;
put1(WR(qp), MSESCALE1);
break;
case PS2_WAIT_SCALE1_3_ACK:
if (code != MSE_ACK) {
break;
}
/* Set res and scale have been ok */
vuid_cancel_timeout(qp);
STATEP->state = PS2_WAIT_STATREQ_ACK;
/* Set timeout for status request */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
put1(WR(qp), MSESTATREQ);
break;
case PS2_WAIT_STATREQ_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_STATUS_1;
break;
case PS2_WAIT_STATUS_1:
STATEP->state = PS2_WAIT_STATUS_BUTTONS;
break;
case PS2_WAIT_STATUS_BUTTONS:
if (code != 0) {
STATEP->nbuttons = (uchar_t)code;
STATEP->state = (uchar_t)PS2_WAIT_STATUS_REV;
} else {
#if defined(VUID3PS2)
/*
* It seems that there are some 3-button mice
* that don't play the Logitech autodetect
* game. One is a Mouse Systems mouse OEM'ed
* by Intergraph.
*
* Until we find out how to autodetect these
* mice, we'll assume that if we're being
* compiled as vuid3ps2 and the mouse doesn't
* play the autodetect game, it's a 3-button
* mouse. This effectively disables
* autodetect for mice using vuid3ps2, but
* since vuid3ps2 is used only on x86 where
* we currently assume manual configuration,
* this shouldn't be a problem. At some point
* in the future when we *do* start using
* autodetect on x86, we should probably define
* VUIDPS2 instead of VUID3PS2. Even then,
* we could leave this code so that *some*
* mice could use autodetect and others not.
*/
STATEP->nbuttons = 3;
#else
STATEP->nbuttons = 2;
#endif
STATEP->state = PS2_WAIT_STATUS_3;
}
break;
case PS2_WAIT_STATUS_REV:
/*FALLTHROUGH*/
case PS2_WAIT_STATUS_3:
/* Status request completed successfully */
vuid_cancel_timeout(qp);
vuidmice_start_wdc_or_setres(qp);
break;
case PS2_WAIT_WHEEL_SMPL1_CMD_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL_SMPL1_RATE_ACK;
put1(WR(qp), 200);
break;
case PS2_WAIT_WHEEL_SMPL1_RATE_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL_SMPL2_CMD_ACK;
put1(WR(qp), MSECHGMOD);
break;
case PS2_WAIT_WHEEL_SMPL2_CMD_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL_SMPL2_RATE_ACK;
put1(WR(qp), 100);
break;
case PS2_WAIT_WHEEL_SMPL2_RATE_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL_SMPL3_CMD_ACK;
put1(WR(qp), MSECHGMOD);
break;
case PS2_WAIT_WHEEL_SMPL3_CMD_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL_SMPL3_RATE_ACK;
put1(WR(qp), 80);
break;
case PS2_WAIT_WHEEL_SMPL3_RATE_ACK:
if (code != MSE_ACK) {
break;
}
/* Set sample rate completed successfully */
vuid_cancel_timeout(qp);
STATEP->state = PS2_WAIT_WHEEL_DEV_CMD;
/* Set timeout for get dev */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
put1(WR(qp), MSEGETDEV);
break;
case PS2_WAIT_WHEEL_DEV_CMD:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL_DEV_ACK;
break;
case PS2_WAIT_WHEEL_DEV_ACK:
/* Get dev completed successfully */
vuid_cancel_timeout(qp);
if (code != 0x03) {
STATEP->state = PS2_WAIT_SETRES3_ACK1;
/* Set timeout for set res */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
put1(WR(qp), MSESETRES);
break;
}
STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL;
/*
* Found wheel. By default enable the wheel.
*/
STATEP->wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
STATEP->state = PS2_WAIT_WHEEL5_SMPL1_CMD_ACK;
/* Set timeout for set sample rate */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP);
/* We're on a roll - try for wheel+5 */
put1(WR(qp), MSECHGMOD);
break;
case PS2_WAIT_WHEEL5_SMPL1_CMD_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL5_SMPL1_RATE_ACK;
put1(WR(qp), 200);
break;
case PS2_WAIT_WHEEL5_SMPL1_RATE_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL5_SMPL2_CMD_ACK;
put1(WR(qp), MSECHGMOD);
break;
case PS2_WAIT_WHEEL5_SMPL2_CMD_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL5_SMPL2_RATE_ACK;
put1(WR(qp), 200);
break;
case PS2_WAIT_WHEEL5_SMPL2_RATE_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL5_SMPL3_CMD_ACK;
put1(WR(qp), MSECHGMOD);
break;
case PS2_WAIT_WHEEL5_SMPL3_CMD_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL5_SMPL3_RATE_ACK;
put1(WR(qp), 80);
break;
case PS2_WAIT_WHEEL5_SMPL3_RATE_ACK:
if (code != MSE_ACK) {
break;
}
/* Set sample rate completed successfully */
vuid_cancel_timeout(qp);
STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD;
/* Set timeout for wheel5 get dev */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
put1(WR(qp), MSEGETDEV);
break;
case PS2_WAIT_WHEEL5_DEV_CMD:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_WHEEL5_DEV_ACK;
break;
case PS2_WAIT_WHEEL5_DEV_ACK:
if (code == 0x04) {
STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL5;
STATEP->nbuttons = 5;
/*
* Found wheel. By default enable the wheel.
*/
STATEP->wheel_state_bf |=
VUID_WHEEL_STATE_ENABLED <<
MOUSE_MODE_WHEEL;
}
/* Wheel5 get dev completed successfully */
vuid_cancel_timeout(qp);
/* FALLTHROUGH */
case PS2_WAIT_SETRES3_CMD:
STATEP->state = PS2_WAIT_SETRES3_ACK1;
/* Set timeout for set res */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
put1(WR(qp), MSESETRES);
break;
case PS2_WAIT_SETRES3_ACK1:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_SETRES3_ACK2;
put1(WR(qp), 3);
break;
case PS2_WAIT_SETRES3_ACK2:
if (code != MSE_ACK) {
break;
}
/* Set res completed successfully */
vuid_cancel_timeout(qp);
STATEP->state = PS2_WAIT_STREAM_ACK;
/* Set timeout for enable */
vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD);
put1(WR(qp), MSESTREAM);
break;
case PS2_WAIT_STREAM_ACK:
if (code != MSE_ACK) {
break;
}
STATEP->state = PS2_WAIT_ON_ACK;
put1(WR(qp), MSEON);
break;
case PS2_WAIT_ON_ACK:
if (code != MSE_ACK) {
break;
}
/* Enable completed successfully */
/*
* The entire initialization sequence
* is complete. Now, we can clear the
* init_count retry counter.
*/
STATEP->init_count = 0;
vuid_cancel_timeout(qp);
STATEP->state = PS2_START;
break;
}
}
freemsg(mp);
}