/*
* 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
* 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/vuid_event.h>
#include "vuidmice.h"
#include <sys/vuid_wheel.h>
/*
* BUT(1) LEFT BUTTON
* BUT(2) MIDDLE BUTTON (if present)
* BUT(3) RIGHT BUTTON
*/
/*
* The RESET command takes more time
* before the PS/2 mouse is ready
*/
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
{
}
static void
{
}
/*
* vuidmice_send_wheel_event
* Convert wheel data to firm_events
*/
static void
{
return;
}
} else {
}
}
static void
{
uint_t b;
/* for each button, see if it has changed */
}
}
void
{
}
}
static void
{
/* Set timeout for set res or sample rate */
/*
* 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.
*/
} else {
}
}
int
{
break;
}
/*
* Later the PS/2 mouse maybe re-attach, so here
* clear the init_count.
*/
STATEP->init_count = 0;
return (0);
}
void
{
}
static void
VUID_INIT_TIMEOUT(void *q)
{
/*
* 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.
*/
/*
* We overload 'inited' to mark the PS/2 mouse
* as one which doesn't respond to extended commands.
*/
}
/*
* 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.
*/
/* See the comment under the PS2_WAIT_STATUS_BUTTONS case */
#if defined(VUID3PS2)
#else
#endif
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).
*/
} else {
/* Try to reset the mouse again */
}
}
void
{
now = ddi_get_lbolt();
/*
* 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.
*/
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
*/
}
/*
* 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.
*/
/* bit 3 not set */
break; /* toss the code */
}
/* get the button values */
}
/* bit 5 indicates Y value is negative (the sign bit) */
if (code & PS2_DATA_YSIGN)
else
/* bit 4 is X sign bit */
if (code & PS2_DATA_XSIGN)
else
else
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.
*/
STATEP->init_count = 0;
break;
}
break;
break;
case PS2_WAIT_FOR_00:
break;
STATEP->init_count = 0;
break;
case PS2_MAYBE_REATTACH:
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;
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;
}
break;
} else if (STATEP->vuid_mouse_mode ==
break;
}
goto packet_complete;
case PS2_WHEEL5_DELTA_Z:
if (code & 0x10) {
/* fourth physical button */
FE_PAIR_NONE, 0, 1);
FE_PAIR_NONE, 0, 0);
} else if (code & 0x20) {
/* fifth physical button */
FE_PAIR_NONE, 0, 1);
FE_PAIR_NONE, 0, 0);
}
/*FALLTHROUGH*/
case PS2_WHEEL_DELTA_Z:
/*
* Check whether reporting vertical wheel
* movements is enabled
*/
code &= 0xf;
/*
* 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;
FE_PAIR_NONE, 0, -code);
} else if (code == 0x01) {
/* positive Z - wheel down */
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 */
FE_PAIR_NONE, 0, 1);
} else if (code == 0x07) {
/* positive Z - wheel right */
FE_PAIR_NONE, 0, -1);
}
}
/*
* If we can peek at the next mouse character, and
* its not the start of the next packet, don't use
* this packet.
*/
/*
* 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 ... */
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.
*/
break;
if (++STATEP->init_count >=
} else {
}
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) */
/* Reset completed successfully */
/* Set timeout for set res */
/* Begin Logitech autodetect sequence */
break;
case PS2_WAIT_SETRES0_ACK1:
break;
}
break;
case PS2_WAIT_SETRES0_ACK2:
case PS2_WAIT_SCALE1_1_ACK:
case PS2_WAIT_SCALE1_2_ACK:
break;
}
break;
case PS2_WAIT_SCALE1_3_ACK:
break;
}
/* Set res and scale have been ok */
/* Set timeout for status request */
break;
case PS2_WAIT_STATREQ_ACK:
break;
}
break;
case PS2_WAIT_STATUS_1:
break;
case PS2_WAIT_STATUS_BUTTONS:
if (code != 0) {
} 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.
*/
#else
#endif
}
break;
case PS2_WAIT_STATUS_REV:
/*FALLTHROUGH*/
case PS2_WAIT_STATUS_3:
/* Status request completed successfully */
break;
break;
}
break;
break;
}
break;
break;
}
break;
break;
}
break;
break;
}
break;
break;
}
/* Set sample rate completed successfully */
/* Set timeout for get dev */
break;
case PS2_WAIT_WHEEL_DEV_CMD:
break;
}
break;
case PS2_WAIT_WHEEL_DEV_ACK:
/* Get dev completed successfully */
if (code != 0x03) {
/* Set timeout for set res */
break;
}
/*
* Found wheel. By default enable the wheel.
*/
/* Set timeout for set sample rate */
/* We're on a roll - try for wheel+5 */
break;
break;
}
break;
break;
}
break;
break;
}
break;
break;
}
break;
break;
}
break;
break;
}
/* Set sample rate completed successfully */
/* Set timeout for wheel5 get dev */
break;
case PS2_WAIT_WHEEL5_DEV_CMD:
break;
}
break;
case PS2_WAIT_WHEEL5_DEV_ACK:
if (code == 0x04) {
/*
* Found wheel. By default enable the wheel.
*/
STATEP->wheel_state_bf |=
}
/* Wheel5 get dev completed successfully */
/* FALLTHROUGH */
case PS2_WAIT_SETRES3_CMD:
/* Set timeout for set res */
break;
case PS2_WAIT_SETRES3_ACK1:
break;
}
break;
case PS2_WAIT_SETRES3_ACK2:
break;
}
/* Set res completed successfully */
/* Set timeout for enable */
break;
case PS2_WAIT_STREAM_ACK:
break;
}
break;
case PS2_WAIT_ON_ACK:
break;
}
/* Enable completed successfully */
/*
* The entire initialization sequence
* is complete. Now, we can clear the
* init_count retry counter.
*/
STATEP->init_count = 0;
break;
}
}
}