TinyX/kdrive/linux/mouse.c

944 lines
20 KiB
C

/*
*
* 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
#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(const int fd, const unsigned char c, const 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(const int fd, const unsigned char *c, int n,
const 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) (KdMouseInfo * mi, unsigned char *ev, int ne);
int (*Valid) (KdMouseInfo * mi, unsigned char *ev, int ne);
Bool(*Parse) (KdMouseInfo * mi, unsigned char *ev, int ne);
Bool(*Init) (KdMouseInfo * mi);
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(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
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(KdMouseInfo * mi, unsigned char *ev, int ne)
{
return ne == 3;
}
static Bool fourComplete(KdMouseInfo * mi, unsigned char *ev, int ne)
{
return ne == 4;
}
static Bool fiveComplete(KdMouseInfo * mi, unsigned char *ev, int ne)
{
return ne == 5;
}
static Bool MouseReasonable(KdMouseInfo * mi, unsigned long flags, int dx,
int dy)
{
Kmouse *km = mi->driver;
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(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
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(mi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking) {
KdEnqueueMouseEvent(mi, flags, dx, dy);
if (flagsrelease) {
flags &= ~flagsrelease;
KdEnqueueMouseEvent(mi, flags, dx, dy);
}
}
return TRUE;
}
static Bool ps2Init(KdMouseInfo * mi);
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 const unsigned char ps2_init[] = {
PSMC_ENABLE_DEV,
0,
};
#define NINIT_PS2 1
static const 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 const 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 const 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(KdMouseInfo * const mi, int ninit, const Bool ret_next)
{
Kmouse * const km = mi->driver;
int c = -1;
Bool waiting;
waiting = FALSE;
while (ninit || ret_next) {
c = MouseReadByte(&km->iob, 1); // Minimum timeout like in xf86-input-mouse
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(KdMouseInfo * mi)
{
Kmouse *km = mi->driver;
int id;
const 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;
id = ps2SkipInit(mi, 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(mi, ninit, FALSE);
return TRUE;
}
static Bool busParse(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
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(mi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueueMouseEvent(mi, flags, dx, dy);
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(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
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(mi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueueMouseEvent(mi, flags, dx, dy);
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(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
if ((ev[0] & 0x40) == 0x40)
return ne == 3;
if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0)
return ne == 1;
return FALSE;
}
static int logiValid(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
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(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
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(mi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueueMouseEvent(mi, flags, dx, dy);
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(KdMouseInfo * mi, unsigned char *ev, int ne)
{
Kmouse *km = mi->driver;
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(mi, flags, dx, dy))
return FALSE;
if (km->stage == MouseWorking)
KdEnqueueMouseEvent(mi, flags, dx, dy);
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);
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)
{
KdMouseInfo *mi = closure;
Kmouse *km = mi->driver;
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) (mi, 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) (mi, event, ne)) {
if ((*km->prot->Parse) (mi, 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) (mi))
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;
}
}
}
static int MouseInputType;
const char * const kdefaultMouse[] = {
"/dev/mouse",
"/dev/psaux",
"/dev/input/mice",
"/dev/adbmouse",
"/dev/ttyS0",
"/dev/ttyS1",
};
#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))
static Bool MouseInit(void)
{
int i;
int fd = -1;
Kmouse *km;
KdMouseInfo *mi, *next;
int n = 0;
if (!MouseInputType)
MouseInputType = KdAllocInputType();
for (mi = kdMouseInfo; mi; mi = next) {
next = mi->next;
if (mi->inputType)
continue;
if (!mi->name) {
for (i = 0; i < NUM_DEFAULT_MOUSE; i++) {
fd = open(kdefaultMouse[i], 2);
if (fd >= 0) {
mi->name = strdup(kdefaultMouse[i]);
break;
}
}
} else
fd = open(mi->name, 2);
if (fd >= 0) {
km = malloc(sizeof(Kmouse));
if (km) {
km->iob.fd = fd;
km->iob.avail = km->iob.used = 0;
km->prot = 0;
km->i_prot = 0;
km->tty = isatty(fd);
mi->driver = km;
mi->inputType = MouseInputType;
MouseFirstProtocol(km, mi->prot);
if (KdRegisterFd
(MouseInputType, fd, MouseRead, (void *)mi))
n++;
} else
close(fd);
}
}
return TRUE;
}
static void MouseFini(void)
{
KdMouseInfo *mi;
KdUnregisterFds(MouseInputType, TRUE);
for (mi = kdMouseInfo; mi; mi = mi->next) {
if (mi->inputType == MouseInputType) {
free(mi->driver);
mi->driver = 0;
mi->inputType = 0;
}
}
}
const KdMouseFuncs LinuxMouseFuncs = {
MouseInit,
MouseFini,
};