xserver-multidpi/hw/kdrive/linux/mouse.c
Daniel Stone 02d0910511 new KDrive input world order
Convert KDrive to GPE/GKE interface.
Add first-class drivers and enumerate every device separately through
Xi, instead of lamely attempting to aggregate them.
Add XKB support to the Linux keyboard driver.
Add 'thumb button' support to the tslib driver.
Rejig InitInput, so each DDX has to add a list of drivers it supports.
Support NewInputDeviceRequest, et al.
2006-07-21 15:19:51 -04:00

1030 lines
22 KiB
C

/*
* $RCSId: xc/programs/Xserver/hw/kdrive/linux/mouse.c,v 1.6 2002/08/02 16:11:35 keithp Exp $
*
* Copyright © 2001 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif
#define NEED_EVENTS
#include <errno.h>
#include <termios.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include <X11/Xpoll.h>
#include "inputstr.h"
#include "scrnintstr.h"
#include "kdrive.h"
#undef DEBUG
#undef DEBUG_BYTES
#define KBUFIO_SIZE 256
#define MOUSE_TIMEOUT 100
typedef struct _kbufio {
int fd;
unsigned char buf[KBUFIO_SIZE];
int avail;
int used;
} Kbufio;
static Bool
MouseWaitForReadable (int fd, int timeout)
{
fd_set set;
struct timeval tv, *tp;
int n;
CARD32 done;
done = GetTimeInMillis () + timeout;
for (;;)
{
FD_ZERO (&set);
FD_SET (fd, &set);
if (timeout == -1)
tp = 0;
else
{
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
tp = &tv;
}
n = select (fd + 1, &set, 0, 0, tp);
if (n > 0)
return TRUE;
if (n < 0 && (errno == EAGAIN || errno == EINTR))
{
timeout = (int) (done - GetTimeInMillis ());
if (timeout > 0)
continue;
}
break;
}
return FALSE;
}
static int
MouseReadByte (Kbufio *b, int timeout)
{
int n;
if (b->avail <= b->used)
{
if (timeout && !MouseWaitForReadable (b->fd, timeout))
{
#ifdef DEBUG_BYTES
ErrorF ("\tTimeout %d\n", timeout);
#endif
return -1;
}
n = read (b->fd, b->buf, KBUFIO_SIZE);
if (n <= 0)
return -1;
b->avail = n;
b->used = 0;
}
#ifdef DEBUG_BYTES
ErrorF ("\tget %02x\n", b->buf[b->used]);
#endif
return b->buf[b->used++];
}
#if NOTUSED
static int
MouseFlush (Kbufio *b, char *buf, int size)
{
CARD32 now = GetTimeInMillis ();
CARD32 done = now + 100;
int c;
int n = 0;
while ((c = MouseReadByte (b, done - now)) != -1)
{
if (buf)
{
if (n == size)
{
memmove (buf, buf + 1, size - 1);
n--;
}
buf[n++] = c;
}
now = GetTimeInMillis ();
if ((INT32) (now - done) >= 0)
break;
}
return n;
}
static int
MousePeekByte (Kbufio *b, int timeout)
{
int c;
c = MouseReadByte (b, timeout);
if (c != -1)
--b->used;
return c;
}
#endif /* NOTUSED */
static Bool
MouseWaitForWritable (int fd, int timeout)
{
fd_set set;
struct timeval tv, *tp;
int n;
FD_ZERO (&set);
FD_SET (fd, &set);
if (timeout == -1)
tp = 0;
else
{
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
tp = &tv;
}
n = select (fd + 1, 0, &set, 0, tp);
if (n > 0)
return TRUE;
return FALSE;
}
static Bool
MouseWriteByte (int fd, unsigned char c, int timeout)
{
int ret;
#ifdef DEBUG_BYTES
ErrorF ("\tput %02x\n", c);
#endif
for (;;)
{
ret = write (fd, &c, 1);
if (ret == 1)
return TRUE;
if (ret == 0)
return FALSE;
if (errno != EWOULDBLOCK)
return FALSE;
if (!MouseWaitForWritable (fd, timeout))
return FALSE;
}
}
static Bool
MouseWriteBytes (int fd, unsigned char *c, int n, int timeout)
{
while (n--)
if (!MouseWriteByte (fd, *c++, timeout))
return FALSE;
return TRUE;
}
#define MAX_MOUSE 10 /* maximum length of mouse protocol */
#define MAX_SKIP 16 /* number of error bytes before switching */
#define MAX_VALID 4 /* number of valid packets before accepting */
typedef struct _kmouseProt {
char *name;
Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne);
int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne);
Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne);
Bool (*Init) (KdPointerInfo *pi);
unsigned char headerMask, headerValid;
unsigned char dataMask, dataValid;
Bool tty;
unsigned int c_iflag;
unsigned int c_oflag;
unsigned int c_lflag;
unsigned int c_cflag;
unsigned int speed;
unsigned char *init;
unsigned long state;
} KmouseProt;
typedef enum _kmouseStage {
MouseBroken, MouseTesting, MouseWorking
} KmouseStage;
typedef struct _kmouse {
Kbufio iob;
const KmouseProt *prot;
int i_prot;
KmouseStage stage; /* protocol verification stage */
Bool tty; /* mouse device is a tty */
int valid; /* sequential valid events */
int tested; /* bytes scanned during Testing phase */
int invalid;/* total invalid bytes for this protocol */
unsigned long state; /* private per protocol, init to prot->state */
} Kmouse;
static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
const KmouseProt *prot = km->prot;
int i;
for (i = 0; i < ne; i++)
if ((ev[i] & prot->headerMask) == prot->headerValid)
break;
if (i != 0)
return i;
for (i = 1; i < ne; i++)
if ((ev[i] & prot->dataMask) != prot->dataValid)
return -1;
return 0;
}
static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
{
return ne == 3;
}
static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
{
return ne == 4;
}
static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
{
return ne == 5;
}
static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy)
{
Kmouse *km = pi->driverPrivate;
if (km->stage == MouseWorking)
return TRUE;
if (dx < -50 || dx > 50)
{
#ifdef DEBUG
ErrorF ("Large X %d\n", dx);
#endif
return FALSE;
}
if (dy < -50 || dy > 50)
{
#ifdef DEBUG
ErrorF ("Large Y %d\n", dy);
#endif
return FALSE;
}
return TRUE;
}
/*
* Standard PS/2 mouse protocol
*/
static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy, dz;
unsigned long flags;
unsigned long flagsrelease = 0;
flags = KD_MOUSE_DELTA;
if (ev[0] & 4)
flags |= KD_BUTTON_2;
if (ev[0] & 2)
flags |= KD_BUTTON_3;
if (ev[0] & 1)
flags |= KD_BUTTON_1;
if (ne > 3)
{
dz = (int) (signed char) ev[3];
if (dz < 0)
{
flags |= KD_BUTTON_4;
flagsrelease = KD_BUTTON_4;
}
else if (dz > 0)
{
flags |= KD_BUTTON_5;
flagsrelease = KD_BUTTON_5;
}
}
dx = ev[1];
if (ev[0] & 0x10)
dx -= 256;
dy = ev[2];
if (ev[0] & 0x20)
dy -= 256;
dy = -dy;
if (!MouseReasonable (pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
{
KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
if (flagsrelease)
{
flags &= ~flagsrelease;
KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
}
}
return TRUE;
}
static Bool ps2Init (KdPointerInfo *pi);
static const KmouseProt ps2Prot = {
"ps/2",
threeComplete, mouseValid, ps2Parse, ps2Init,
0x08, 0x08, 0x00, 0x00,
FALSE
};
static const KmouseProt imps2Prot = {
"imps/2",
fourComplete, mouseValid, ps2Parse, ps2Init,
0x08, 0x08, 0x00, 0x00,
FALSE
};
static const KmouseProt exps2Prot = {
"exps/2",
fourComplete, mouseValid, ps2Parse, ps2Init,
0x08, 0x08, 0x00, 0x00,
FALSE
};
/*
* Once the mouse is known to speak ps/2 protocol, go and find out
* what advanced capabilities it has and turn them on
*/
/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */
/* aux device commands (sent to KBD_DATA_PORT) */
#define PSMC_SET_SCALING11 0x00e6
#define PSMC_SET_SCALING21 0x00e7
#define PSMC_SET_RESOLUTION 0x00e8
#define PSMC_SEND_DEV_STATUS 0x00e9
#define PSMC_SET_STREAM_MODE 0x00ea
#define PSMC_SEND_DEV_DATA 0x00eb
#define PSMC_SET_REMOTE_MODE 0x00f0
#define PSMC_SEND_DEV_ID 0x00f2
#define PSMC_SET_SAMPLING_RATE 0x00f3
#define PSMC_ENABLE_DEV 0x00f4
#define PSMC_DISABLE_DEV 0x00f5
#define PSMC_SET_DEFAULTS 0x00f6
#define PSMC_RESET_DEV 0x00ff
/* PSMC_SET_RESOLUTION argument */
#define PSMD_RES_LOW 0 /* typically 25ppi */
#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */
#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */
#define PSMD_RES_HIGH 3 /* typically 200ppi */
#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH
/* PSMC_SET_SAMPLING_RATE */
#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */
/* aux device ID */
#define PSM_MOUSE_ID 0
#define PSM_BALLPOINT_ID 2
#define PSM_INTELLI_ID 3
#define PSM_EXPLORER_ID 4
#define PSM_4DMOUSE_ID 6
#define PSM_4DPLUS_ID 8
static unsigned char ps2_init[] = {
PSMC_ENABLE_DEV,
0,
};
#define NINIT_PS2 1
static unsigned char wheel_3button_init[] = {
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 100,
PSMC_SET_SAMPLING_RATE, 80,
PSMC_SEND_DEV_ID,
0,
};
#define NINIT_IMPS2 4
static unsigned char wheel_5button_init[] = {
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 100,
PSMC_SET_SAMPLING_RATE, 80,
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 80,
PSMC_SEND_DEV_ID,
0
};
#define NINIT_EXPS2 7
static unsigned char intelli_init[] = {
PSMC_SET_SAMPLING_RATE, 200,
PSMC_SET_SAMPLING_RATE, 100,
PSMC_SET_SAMPLING_RATE, 80,
0
};
#define NINIT_INTELLI 3
static int
ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next)
{
Kmouse *km = pi->driverPrivate;
int c = -1;
int skipping;
Bool waiting;
skipping = 0;
waiting = FALSE;
while (ninit || ret_next)
{
c = MouseReadByte (&km->iob, MOUSE_TIMEOUT);
if (c == -1)
break;
/* look for ACK */
if (c == 0xfa)
{
ninit--;
if (ret_next)
waiting = TRUE;
}
/* look for packet start -- not the response */
else if ((c & 0x08) == 0x08)
waiting = FALSE;
else if (waiting)
break;
}
return c;
}
static Bool
ps2Init (KdPointerInfo *pi)
{
Kmouse *km = pi->driverPrivate;
int skipping;
Bool waiting;
int id;
unsigned char *init;
int ninit;
/* Send Intellimouse initialization sequence */
MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100);
/*
* Send ID command
*/
if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100))
return FALSE;
skipping = 0;
waiting = FALSE;
id = ps2SkipInit (pi, 0, TRUE);
switch (id) {
case 3:
init = wheel_3button_init;
ninit = NINIT_IMPS2;
km->prot = &imps2Prot;
break;
case 4:
init = wheel_5button_init;
ninit = NINIT_EXPS2;
km->prot = &exps2Prot;
break;
default:
init = ps2_init;
ninit = NINIT_PS2;
km->prot = &ps2Prot;
break;
}
if (init)
MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100);
/*
* Flush out the available data to eliminate responses to the
* initialization string. Make sure any partial event is
* skipped
*/
(void) ps2SkipInit (pi, ninit, FALSE);
return TRUE;
}
static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
dx = (signed char) ev[1];
dy = -(signed char) ev[2];
if ((ev[0] & 4) == 0)
flags |= KD_BUTTON_1;
if ((ev[0] & 2) == 0)
flags |= KD_BUTTON_2;
if ((ev[0] & 1) == 0)
flags |= KD_BUTTON_3;
if (!MouseReasonable (pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt busProt = {
"bus",
threeComplete, mouseValid, busParse, 0,
0xf8, 0x00, 0x00, 0x00,
FALSE
};
/*
* Standard MS serial protocol, three bytes
*/
static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
if (ev[0] & 0x20)
flags |= KD_BUTTON_1;
if (ev[0] & 0x10)
flags |= KD_BUTTON_3;
dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
if (!MouseReasonable (pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt msProt = {
"ms",
threeComplete, mouseValid, msParse, 0,
0xc0, 0x40, 0xc0, 0x00,
TRUE,
IGNPAR,
0,
0,
CS7 | CSTOPB | CREAD | CLOCAL,
B1200,
};
/*
* Logitech mice send 3 or 4 bytes, the only way to tell is to look at the
* first byte of a synchronized protocol stream and see if it's got
* any bits turned on that can't occur in that fourth byte
*/
static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
if ((ev[0] & 0x40) == 0x40)
return ne == 3;
if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0)
return ne == 1;
return FALSE;
}
static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
const KmouseProt *prot = km->prot;
int i;
for (i = 0; i < ne; i++)
{
if ((ev[i] & 0x40) == 0x40)
break;
if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0)
break;
}
if (i != 0)
return i;
for (i = 1; i < ne; i++)
if ((ev[i] & prot->dataMask) != prot->dataValid)
return -1;
return 0;
}
static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
if (ne == 3)
{
if (ev[0] & 0x20)
flags |= KD_BUTTON_1;
if (ev[0] & 0x10)
flags |= KD_BUTTON_3;
dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
flags |= km->state & KD_BUTTON_2;
}
else
{
if (ev[0] & 0x20)
flags |= KD_BUTTON_2;
dx = 0;
dy = 0;
flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3);
}
if (!MouseReasonable (pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt logiProt = {
"logitech",
logiComplete, logiValid, logiParse, 0,
0xc0, 0x40, 0xc0, 0x00,
TRUE,
IGNPAR,
0,
0,
CS7 | CSTOPB | CREAD | CLOCAL,
B1200,
};
/*
* Mouse systems protocol, 5 bytes
*/
static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne)
{
Kmouse *km = pi->driverPrivate;
int dx, dy;
unsigned long flags;
flags = KD_MOUSE_DELTA;
if (!(ev[0] & 0x4))
flags |= KD_BUTTON_1;
if (!(ev[0] & 0x2))
flags |= KD_BUTTON_2;
if (!(ev[0] & 0x1))
flags |= KD_BUTTON_3;
dx = (signed char)(ev[1]) + (signed char)(ev[3]);
dy = - ((signed char)(ev[2]) + (signed char)(ev[4]));
if (!MouseReasonable (pi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
return TRUE;
}
static const KmouseProt mscProt = {
"msc",
fiveComplete, mouseValid, mscParse, 0,
0xf8, 0x80, 0x00, 0x00,
TRUE,
IGNPAR,
0,
0,
CS8 | CSTOPB | CREAD | CLOCAL,
B1200,
};
/*
* Use logitech before ms -- they're the same except that
* logitech sometimes has a fourth byte
*/
static const KmouseProt *kmouseProts[] = {
&ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt,
};
#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0]))
static void
MouseInitProtocol (Kmouse *km)
{
int ret;
struct termios t;
if (km->prot->tty)
{
ret = tcgetattr (km->iob.fd, &t);
if (ret >= 0)
{
t.c_iflag = km->prot->c_iflag;
t.c_oflag = km->prot->c_oflag;
t.c_lflag = km->prot->c_lflag;
t.c_cflag = km->prot->c_cflag;
cfsetispeed (&t, km->prot->speed);
cfsetospeed (&t, km->prot->speed);
ret = tcsetattr (km->iob.fd, TCSANOW, &t);
}
}
km->stage = MouseBroken;
km->valid = 0;
km->tested = 0;
km->invalid = 0;
km->state = km->prot->state;
}
static void
MouseFirstProtocol (Kmouse *km, char *prot)
{
if (prot)
{
for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++)
if (!strcmp (prot, kmouseProts[km->i_prot]->name))
break;
if (km->i_prot == NUM_PROT)
{
int i;
ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot);
for (i = 0; i < NUM_PROT; i++)
ErrorF (" %s", kmouseProts[i]->name);
ErrorF ("\n");
}
else
{
km->prot = kmouseProts[km->i_prot];
if (km->tty && !km->prot->tty)
ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n",
prot);
else if (!km->tty && km->prot->tty)
ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n",
prot);
}
}
if (!km->prot)
{
for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++)
;
km->prot = kmouseProts[km->i_prot];
}
MouseInitProtocol (km);
}
static void
MouseNextProtocol (Kmouse *km)
{
do
{
if (!km->prot)
km->i_prot = 0;
else
if (++km->i_prot == NUM_PROT) km->i_prot = 0;
km->prot = kmouseProts[km->i_prot];
} while (km->prot->tty != km->tty);
MouseInitProtocol (km);
ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name);
}
static void
MouseRead (int mousePort, void *closure)
{
KdPointerInfo *pi = closure;
Kmouse *km = pi->driverPrivate;
unsigned char event[MAX_MOUSE];
int ne;
int c;
int i;
int timeout;
timeout = 0;
ne = 0;
for(;;)
{
c = MouseReadByte (&km->iob, timeout);
if (c == -1)
{
if (ne)
{
km->invalid += ne + km->tested;
km->valid = 0;
km->tested = 0;
km->stage = MouseBroken;
}
break;
}
event[ne++] = c;
i = (*km->prot->Valid) (pi, event, ne);
if (i != 0)
{
#ifdef DEBUG
ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n",
km->prot->name, i > 0 ? i : ne, ne);
#endif
if (i > 0 && i < ne)
{
ne -= i;
memmove (event, event + i, ne);
}
else
{
i = ne;
ne = 0;
}
km->invalid += i + km->tested;
km->valid = 0;
km->tested = 0;
if (km->stage == MouseWorking)
km->i_prot--;
km->stage = MouseBroken;
if (km->invalid > MAX_SKIP)
{
MouseNextProtocol (km);
ne = 0;
}
timeout = 0;
}
else
{
if ((*km->prot->Complete) (pi, event, ne))
{
if ((*km->prot->Parse) (pi, event, ne))
{
switch (km->stage)
{
case MouseBroken:
#ifdef DEBUG
ErrorF ("Mouse protocol %s seems OK\n",
km->prot->name);
#endif
/* do not zero invalid to accumulate invalid bytes */
km->valid = 0;
km->tested = 0;
km->stage = MouseTesting;
/* fall through ... */
case MouseTesting:
km->valid++;
km->tested += ne;
if (km->valid > MAX_VALID)
{
#ifdef DEBUG
ErrorF ("Mouse protocol %s working\n",
km->prot->name);
#endif
km->stage = MouseWorking;
km->invalid = 0;
km->tested = 0;
km->valid = 0;
if (km->prot->Init && !(*km->prot->Init) (pi))
km->stage = MouseBroken;
}
break;
case MouseWorking:
break;
}
}
else
{
km->invalid += ne + km->tested;
km->valid = 0;
km->tested = 0;
km->stage = MouseBroken;
}
ne = 0;
timeout = 0;
}
else
timeout = MOUSE_TIMEOUT;
}
}
}
int MouseInputType;
char *kdefaultMouse[] = {
"/dev/input/mice",
"/dev/mouse",
"/dev/psaux",
"/dev/adbmouse",
"/dev/ttyS0",
"/dev/ttyS1",
};
#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))
static Status
MouseInit (KdPointerInfo *pi)
{
int i;
int fd;
Kmouse *km;
if (!pi)
return BadImplementation;
if (!pi->path || strcmp(pi->path, "auto") == 0) {
for (i = 0; i < NUM_DEFAULT_MOUSE; i++) {
fd = open (kdefaultMouse[i], 2);
if (fd >= 0) {
pi->path = KdSaveString (kdefaultMouse[i]);
break;
}
}
}
else {
fd = open (pi->path, 2);
}
if (fd < 0)
return BadMatch;
close(fd);
km = (Kmouse *) xalloc (sizeof (Kmouse));
if (km) {
km->iob.avail = km->iob.used = 0;
MouseFirstProtocol(km, "exps/2");
km->i_prot = 0;
km->tty = isatty (fd);
km->iob.fd = -1;
pi->driverPrivate = km;
}
else {
close (fd);
return BadAlloc;
}
return Success;
}
static Status
MouseEnable (KdPointerInfo *pi)
{
Kmouse *km;
if (!pi || !pi->driverPrivate || !pi->path)
return BadImplementation;
km = pi->driverPrivate;
km->iob.fd = open(pi->path, 2);
if (km->iob.fd < 0)
return BadMatch;
if (!KdRegisterFd (km->iob.fd, MouseRead, pi))
{
close(km->iob.fd);
return BadAlloc;
}
return Success;
}
static void
MouseDisable (KdPointerInfo *pi)
{
Kmouse *km;
if (!pi || !pi->driverPrivate)
return;
km = pi->driverPrivate;
KdUnregisterFd (pi, km->iob.fd, TRUE);
}
static void
MouseFini (KdPointerInfo *pi)
{
xfree (pi->driverPrivate);
pi->driverPrivate = NULL;
}
KdPointerDriver LinuxMouseDriver = {
"mouse",
MouseInit,
MouseEnable,
MouseDisable,
MouseFini,
NULL,
};