From 28fd5f7525848cf0109f9cf2d6311f3717570a5d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 12 Oct 2001 06:33:12 +0000 Subject: [PATCH] kdrive: add new auto-detecting and auto-switching mouse driver --- hw/kdrive/chips/chipsstub.c | 4 +- hw/kdrive/fbdev/fbinit.c | 8 +- hw/kdrive/i810/i810stub.c | 2 +- hw/kdrive/igs/igsstub.c | 4 +- hw/kdrive/ipaq/ipaq.c | 8 +- hw/kdrive/linux/Imakefile | 6 +- hw/kdrive/linux/bus.c | 4 +- hw/kdrive/linux/keyboard.c | 4 +- hw/kdrive/linux/mouse.c | 917 ++++++++++++++++++++++++++++++++ hw/kdrive/linux/ms.c | 22 +- hw/kdrive/linux/ps2.c | 4 +- hw/kdrive/mach64/mach64stub.c | 4 +- hw/kdrive/pcmcia/pcmciastub.c | 4 +- hw/kdrive/savage/s3stub.c | 4 +- hw/kdrive/sis530/sisstub.c | 4 +- hw/kdrive/src/kdrive.c | 120 ++++- hw/kdrive/src/kdrive.h | 53 +- hw/kdrive/src/kinfo.c | 36 +- hw/kdrive/src/kinput.c | 301 ++++++----- hw/kdrive/trident/tridentstub.c | 4 +- hw/kdrive/trio/s3stub.c | 4 +- hw/kdrive/ts300/ts300.c | 4 +- hw/kdrive/vesa/vesainit.c | 4 +- 23 files changed, 1324 insertions(+), 201 deletions(-) create mode 100644 hw/kdrive/linux/mouse.c diff --git a/hw/kdrive/chips/chipsstub.c b/hw/kdrive/chips/chipsstub.c index 5c8a6d4c6..52dac0d97 100644 --- a/hw/kdrive/chips/chipsstub.c +++ b/hw/kdrive/chips/chipsstub.c @@ -22,7 +22,7 @@ * * Author: Keith Packard, SuSE, Inc. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/chips/chipsstub.c,v 1.5 2000/11/29 08:42:25 keithp Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/chips/chipsstub.c,v 1.1 2001/09/05 07:12:42 keithp Exp $ */ #include "chips.h" @@ -45,7 +45,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); } int diff --git a/hw/kdrive/fbdev/fbinit.c b/hw/kdrive/fbdev/fbinit.c index 512382d06..7d70e6eae 100644 --- a/hw/kdrive/fbdev/fbinit.c +++ b/hw/kdrive/fbdev/fbinit.c @@ -21,7 +21,7 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/fbdev/fbinit.c,v 1.7 2001/05/23 08:56:08 alanh Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/fbdev/fbinit.c,v 1.8 2001/05/29 17:47:55 keithp Exp $ */ #include @@ -42,11 +42,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { -#ifdef __powerpc__ - KdInitInput (&BusMouseFuncs, &LinuxKeyboardFuncs); -#else - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); -#endif + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); #ifdef TOUCHSCREEN KdInitTouchScreen (&TsFuncs); #endif diff --git a/hw/kdrive/i810/i810stub.c b/hw/kdrive/i810/i810stub.c index f7097c7d8..f7fbbe259 100644 --- a/hw/kdrive/i810/i810stub.c +++ b/hw/kdrive/i810/i810stub.c @@ -66,7 +66,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); } int diff --git a/hw/kdrive/igs/igsstub.c b/hw/kdrive/igs/igsstub.c index af526a0e0..9d5949aa3 100644 --- a/hw/kdrive/igs/igsstub.c +++ b/hw/kdrive/igs/igsstub.c @@ -1,5 +1,5 @@ /* - * $XFree86: xc/programs/Xserver/hw/kdrive/igs/igsstub.c,v 1.1 2000/05/06 22:17:44 keithp Exp $ + * $XFree86: xc/programs/Xserver/hw/kdrive/igs/igsstub.c,v 1.2 2000/05/24 23:52:48 keithp Exp $ * * Copyright © 2000 Keith Packard * @@ -53,7 +53,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); } int diff --git a/hw/kdrive/ipaq/ipaq.c b/hw/kdrive/ipaq/ipaq.c index 35963f6f3..53fb7fd4a 100644 --- a/hw/kdrive/ipaq/ipaq.c +++ b/hw/kdrive/ipaq/ipaq.c @@ -22,7 +22,7 @@ * Adapted from ts300.c by Alan Hourihane * For the Compaq IPAQ handheld, with the HP VGA Out Card (F1252A). */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/ipaq/ipaq.c,v 1.1 2001/05/23 17:28:39 alanh Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/ipaq/ipaq.c,v 1.2 2001/05/29 17:47:55 keithp Exp $ */ #include "pcmcia.h" @@ -47,11 +47,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { -#ifdef __powerpc__ - KdInitInput (&BusMouseFuncs, &LinuxKeyboardFuncs); -#else - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); -#endif + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); #ifdef TOUCHSCREEN KdInitTouchScreen (&TsFuncs); #endif diff --git a/hw/kdrive/linux/Imakefile b/hw/kdrive/linux/Imakefile index 51ff075d8..69a08d2e0 100644 --- a/hw/kdrive/linux/Imakefile +++ b/hw/kdrive/linux/Imakefile @@ -1,5 +1,5 @@ XCOMM $XConsortium: Imakefile /main/10 1996/12/02 10:20:33 lehors $ -XCOMM $XFree86: xc/programs/Xserver/hw/kdrive/linux/Imakefile,v 1.6 2001/08/09 20:45:15 dawes Exp $ +XCOMM $XFree86: xc/programs/Xserver/hw/kdrive/linux/Imakefile,v 1.7 2001/09/29 04:16:39 keithp Exp $ KDRIVE=.. #include "../Kdrive.tmpl" @@ -8,9 +8,9 @@ TSSRCS = ts.c TSOBJS = ts.o #endif -SRCS = keyboard.c linux.c ps2.c ms.c bus.c agp.c $(TSSRCS) +SRCS = keyboard.c linux.c mouse.c ps2.c bus.c ms.c agp.c $(TSSRCS) -OBJS = keyboard.o linux.o ps2.o ms.o bus.o agp.o $(TSOBJS) +OBJS = keyboard.o linux.o mouse.o ps2.o bus.o ms.o agp.o $(TSOBJS) INCLUDES = -I. $(KDINCS) diff --git a/hw/kdrive/linux/bus.c b/hw/kdrive/linux/bus.c index 0237e5279..58afc1f8c 100644 --- a/hw/kdrive/linux/bus.c +++ b/hw/kdrive/linux/bus.c @@ -1,5 +1,5 @@ /* - * $XFree86$ + * $XFree86: xc/programs/Xserver/hw/kdrive/linux/bus.c,v 1.2 2001/06/29 14:00:41 keithp Exp $ * * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * @@ -53,7 +53,7 @@ BusRead (int adbPort, void *closure) flags |= KD_BUTTON_2; if ((buf[0] & 1) == 0) flags |= KD_BUTTON_3; - KdEnqueueMouseEvent (flags, dx, dy); + KdEnqueueMouseEvent (kdMouseInfo, flags, dx, dy); } } diff --git a/hw/kdrive/linux/keyboard.c b/hw/kdrive/linux/keyboard.c index 12486adc5..2f8477d4c 100644 --- a/hw/kdrive/linux/keyboard.c +++ b/hw/kdrive/linux/keyboard.c @@ -1,5 +1,5 @@ /* - * $XFree86: xc/programs/Xserver/hw/kdrive/linux/keyboard.c,v 1.7 2001/06/29 14:00:41 keithp Exp $ + * $XFree86: xc/programs/Xserver/hw/kdrive/linux/keyboard.c,v 1.8 2001/09/29 04:16:39 keithp Exp $ * * Copyright © 1999 Keith Packard * @@ -438,8 +438,8 @@ LinuxKeyboardInit (void) if (!LinuxKbdType) LinuxKbdType = KdAllocInputType (); - LinuxKeyboardEnable (LinuxConsoleFd, 0); KdRegisterFd (LinuxKbdType, LinuxConsoleFd, LinuxKeyboardRead, 0); + LinuxKeyboardEnable (LinuxConsoleFd, 0); KdRegisterFdEnableDisable (LinuxConsoleFd, LinuxKeyboardEnable, LinuxKeyboardDisable); diff --git a/hw/kdrive/linux/mouse.c b/hw/kdrive/linux/mouse.c new file mode 100644 index 000000000..b208c0242 --- /dev/null +++ b/hw/kdrive/linux/mouse.c @@ -0,0 +1,917 @@ +/* + * $XFree86: $ + * + * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. + * + * 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. + */ + +#define NEED_EVENTS +#include "X.h" +#include "Xproto.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" +#include "Xpoll.h" +#include +#include + +#undef DEBUG +#undef DEBUG_BYTES +#define KBUFIO_SIZE 256 + +typedef struct _kbufio { + int fd; + unsigned char buf[KBUFIO_SIZE]; + int avail; + int used; +} Kbufio; + +Bool +MouseWaitForReadable (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, &set, 0, 0, tp); + if (n > 0) + return TRUE; + return FALSE; +} + +int +MouseReadByte (Kbufio *b, int timeout) +{ + int n; + if (b->avail <= b->used) + { + if (timeout && !MouseWaitForReadable (b->fd, timeout)) + 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++]; +} + +int +MouseFlush (Kbufio *b, char *buf, int size) +{ + CARD32 now = GetTimeInMillis (); + CARD32 done = now + 100; + int p = 0; + 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; +} + +int +MousePeekByte (Kbufio *b, int timeout) +{ + int c; + + c = MouseReadByte (b, timeout); + if (c != -1) + --b->used; + return c; +} + +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; +} + +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; + } +} + +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) (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; + + 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; + else if (dz < 0) + flags |= 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); + 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 + */ +static unsigned char ps2_init[] = { + 0xf4, 0 +}; + +#define NINIT_PS2 1 + +static unsigned char wheel_3button_init[] = { + 0xf3, 0xc8, 0xf3, 0x64, 0xf3, 0x50, 0xf2, 0 +}; + +#define NINIT_IMPS2 4 + +static unsigned char wheel_5button_init[] = { + 0xf3, 0xc8, 0xf3, 0x64, 0xf3, 0x50, + 0xf3, 0xc8, 0xf3, 0xc8, 0xf3, 0x50, 0xf2, 0 +}; + +#define NINIT_EXPS2 7 + +static unsigned char intelli_init[] = { + 0xf3, 0xc8, 0xf3, 0x64, 0xf3, 0x50, 0 +}; + +#define NINIT_INTELLI 3 + +static int +ps2SkipInit (KdMouseInfo *mi, int ninit, Bool ret_next) +{ + Kmouse *km = mi->driver; + int c; + int skipping; + Bool waiting; + + skipping = 0; + waiting = FALSE; + while (ninit || ret_next) + { + c = MouseReadByte (&km->iob, 100); + 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 c; + int skipping; + Bool waiting; + int id; + unsigned char *init; + int ninit; + + /* Send Intellimouse initialization sequence */ + MouseWriteBytes (km->iob.fd, intelli_init, strlen (intelli_init), 100); + /* + * Send ID command + */ + if (!MouseWriteByte (km->iob.fd, 0xf2, 100)) + return FALSE; + skipping = 0; + waiting = 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 (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); +} + +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 = (char) ev[1]; + dy = -(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 = (char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (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; + const KmouseProt *prot = km->prot; + int c; + + if ((ev[0] & 0x40) == 0x40) + return ne == 3; + if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0) + return ne == 1; +} + +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 = (char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (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 = (char)(ev[1]) + (char)(ev[3]); + dy = - ((char)(ev[2]) + (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])) + +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; +} + +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); +} + +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); +} + +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; + 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; + } + } + else + { + km->invalid += ne + km->tested; + km->valid = 0; + km->tested = 0; + km->stage = MouseBroken; + } + ne = 0; + timeout = 0; + } + else + timeout = 100; + } + } +} + +int MouseInputType; + +char *kdefaultMouse[] = { + "/dev/mouse", + "/dev/psaux", + "/dev/input/mice", + "/dev/adbmouse", + "/dev/ttyS0", + "/dev/ttyS1", +}; + +#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0])) + +int +MouseInit (void) +{ + int i; + int fd; + Kmouse *km; + KdMouseInfo *mi, *next; + KmouseProt *mp; + int n = 0; + char *prot; + + for (mi = kdMouseInfo; mi; mi = next) + { + next = mi->next; + prot = mi->prot; + if (!mi->name) + { + for (i = 0; i < NUM_DEFAULT_MOUSE; i++) + { + fd = open (kdefaultMouse[i], 2); + if (fd >= 0) + { + mi->name = KdSaveString (kdefaultMouse[i]); + break; + } + } + } + else + fd = open (mi->name, 2); + + if (fd >= 0) + { + km = (Kmouse *) xalloc (sizeof (Kmouse)); + if (km) + { + km->tty = isatty (fd); + mi->driver = km; + km->iob.fd = fd; + km->iob.avail = km->iob.used = 0; + MouseFirstProtocol (km, mi->prot); + if (KdRegisterFd (MouseInputType, fd, MouseRead, (void *) mi)) + n++; + } + else + close (fd); + } + else + KdMouseInfoDispose (mi); + } +} + +void +MouseFini (void) +{ + KdMouseInfo *mi; + + KdUnregisterFds (MouseInputType, TRUE); + for (mi = kdMouseInfo; mi; mi = mi->next) + { + if (mi->driver) + { + xfree (mi->driver); + mi->driver = 0; + } + } +} + +KdMouseFuncs LinuxMouseFuncs = { + MouseInit, + MouseFini, +}; diff --git a/hw/kdrive/linux/ms.c b/hw/kdrive/linux/ms.c index 4eba864cb..762e2118b 100644 --- a/hw/kdrive/linux/ms.c +++ b/hw/kdrive/linux/ms.c @@ -20,7 +20,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* $XFree86$ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/linux/ms.c,v 1.1 2001/08/09 20:45:15 dawes Exp $ */ #define NEED_EVENTS #include "X.h" @@ -63,7 +63,7 @@ MsReadBytes (int fd, char *buf, int len, int min) } void -MsRead (int port) +MsRead (int port, void *closure) { unsigned char buf[3 * 200]; unsigned char *b; @@ -87,11 +87,13 @@ MsRead (int port) dy = (char)(((b[0] & 0x0C) << 4) | (b[2] & 0x3F)); n -= 3; b += 3; - KdEnqueueMouseEvent (flags, dx, dy); + KdEnqueueMouseEvent (kdMouseInfo, flags, dx, dy); } } } +int MsInputType; + int MsInit (void) { @@ -100,6 +102,8 @@ MsInit (void) struct termios t; int ret; + if (!MsInputType) + MsInputType = KdAllocInputType (); port = open (device, O_RDWR | O_NONBLOCK); if(port < 0) { ErrorF("Couldn't open %s (%d)\n", device, (int)errno); @@ -107,8 +111,7 @@ MsInit (void) } else if (port == 0) { ErrorF("Opening %s returned 0! Please complain to Keith.\n", device); - close(port); - return 0; + goto bail; } if(!isatty(port)) { @@ -137,7 +140,8 @@ MsInit (void) ErrorF("Couldn't tcsetattr(%s): %d\n", device, errno); goto bail; } - return port; + if (KdRegisterFd (MsInputType, port, MsRead, (void *) 0)) + return 1; bail: close(port); @@ -145,14 +149,12 @@ MsInit (void) } void -MsFini (int port) +MsFini (void) { - if (port >= 0) - close(port); + KdUnregisterFds (MsInputType, TRUE); } KdMouseFuncs MsMouseFuncs = { MsInit, - MsRead, MsFini }; diff --git a/hw/kdrive/linux/ps2.c b/hw/kdrive/linux/ps2.c index f1ccfd77c..a3fc712a3 100644 --- a/hw/kdrive/linux/ps2.c +++ b/hw/kdrive/linux/ps2.c @@ -1,5 +1,5 @@ /* - * $XFree86: xc/programs/Xserver/hw/kdrive/linux/ps2.c,v 1.4 2001/04/01 14:00:04 tsi Exp $ + * $XFree86: xc/programs/Xserver/hw/kdrive/linux/ps2.c,v 1.5 2001/06/29 14:00:41 keithp Exp $ * * Copyright © 1999 Keith Packard * @@ -110,7 +110,7 @@ Ps2Read (int ps2Port, void *closure) dy = -dy; n -= 3; b += 3; - KdEnqueueMouseEvent (flags, dx, dy); + KdEnqueueMouseEvent (kdMouseInfo, flags, dx, dy); } } } diff --git a/hw/kdrive/mach64/mach64stub.c b/hw/kdrive/mach64/mach64stub.c index fac8d46ac..6647610fc 100644 --- a/hw/kdrive/mach64/mach64stub.c +++ b/hw/kdrive/mach64/mach64stub.c @@ -22,7 +22,7 @@ * * Author: Keith Packard, SuSE, Inc. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/mach64/mach64stub.c,v 1.5 2000/11/29 08:42:25 keithp Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/mach64/mach64stub.c,v 1.1 2001/06/03 18:48:19 keithp Exp $ */ #include "mach64.h" @@ -44,7 +44,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); } int diff --git a/hw/kdrive/pcmcia/pcmciastub.c b/hw/kdrive/pcmcia/pcmciastub.c index e30881633..af05b4a6a 100644 --- a/hw/kdrive/pcmcia/pcmciastub.c +++ b/hw/kdrive/pcmcia/pcmciastub.c @@ -21,7 +21,7 @@ * * Authors: Alan Hourihane, */ -/* $XFree86$ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/pcmcia/pcmciastub.c,v 1.1 2001/05/23 08:56:09 alanh Exp $ */ #include "pcmcia.h" @@ -42,7 +42,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); } extern pcmciaDisplayModeRec pcmciaDefaultModes[]; diff --git a/hw/kdrive/savage/s3stub.c b/hw/kdrive/savage/s3stub.c index 89d05b376..90ade29c2 100644 --- a/hw/kdrive/savage/s3stub.c +++ b/hw/kdrive/savage/s3stub.c @@ -22,7 +22,7 @@ * * Author: Keith Packard, SuSE, Inc. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/savage/s3stub.c,v 1.2 1999/12/30 03:03:13 robin Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/savage/s3stub.c,v 1.3 2000/02/23 20:30:05 dawes Exp $ */ #include "s3.h" @@ -61,7 +61,7 @@ InitInput (int argc, char **argv) KdInitInput (&VxWorksMouseFuncs, &VxWorksKeyboardFuncs); #endif #ifdef linux - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); #endif } diff --git a/hw/kdrive/sis530/sisstub.c b/hw/kdrive/sis530/sisstub.c index a0d28821e..323e5dcce 100644 --- a/hw/kdrive/sis530/sisstub.c +++ b/hw/kdrive/sis530/sisstub.c @@ -22,7 +22,7 @@ * * Author: Keith Packard, SuSE, Inc. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/sis530/sisstub.c,v 1.2 1999/12/30 03:03:15 robin Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/sis530/sisstub.c,v 1.4 2000/08/09 17:52:44 keithp Exp $ */ #include "sis.h" @@ -50,7 +50,7 @@ InitOutput (ScreenInfo *pScreenInfo, int argc, char **argv) void InitInput (int argc, char **argv) { - KdInitInput (&Ps2MouseFuncs, &LinuxKeyboardFuncs); + KdInitInput (&LinuxMouseFuncs, &LinuxKeyboardFuncs); } int diff --git a/hw/kdrive/src/kdrive.c b/hw/kdrive/src/kdrive.c index 3e1aa84ff..dabfd9c22 100644 --- a/hw/kdrive/src/kdrive.c +++ b/hw/kdrive/src/kdrive.c @@ -21,7 +21,7 @@ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ -/* $XFree86: xc/programs/Xserver/hw/kdrive/kdrive.c,v 1.19 2001/07/24 21:26:17 keithp Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/kdrive/kdrive.c,v 1.20 2001/09/29 04:16:38 keithp Exp $ */ #include "kdrive.h" #ifdef PSEUDO8 @@ -373,7 +373,7 @@ KdParseScreen (KdScreenInfo *screen, screen->fb[fb].depth = 0; if (!arg) return; - if (strlen (arg) > sizeof (save)) + if (strlen (arg) >= sizeof (save)) return; for (i = 0; i < 2; i++) @@ -460,6 +460,114 @@ KdParseScreen (KdScreenInfo *screen, } } +/* + * Mouse argument syntax: + * + * device,protocol,options... + * + * Options are any of: + * 1-5 n button mouse + * 2button emulate middle button + * {NMO} Reorder buttons + */ + +char * +KdSaveString (char *str) +{ + char *n = (char *) xalloc (strlen (str) + 1); + + if (!n) + return 0; + strcpy (n, str); + return n; +} + +/* + * Parse mouse information. Syntax: + * + * ,,{,