1706f2543Smrg/*
2706f2543Smrg * Copyright � 2001 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that
7706f2543Smrg * copyright notice and this permission notice appear in supporting
8706f2543Smrg * documentation, and that the name of Keith Packard not be used in
9706f2543Smrg * advertising or publicity pertaining to distribution of the software without
10706f2543Smrg * specific, written prior permission.  Keith Packard makes no
11706f2543Smrg * representations about the suitability of this software for any purpose.  It
12706f2543Smrg * is provided "as is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#ifdef HAVE_CONFIG_H
24706f2543Smrg#include <kdrive-config.h>
25706f2543Smrg#endif
26706f2543Smrg#include <errno.h>
27706f2543Smrg#include <termios.h>
28706f2543Smrg#include <X11/X.h>
29706f2543Smrg#include <X11/Xproto.h>
30706f2543Smrg#include <X11/Xpoll.h>
31706f2543Smrg#include "inputstr.h"
32706f2543Smrg#include "scrnintstr.h"
33706f2543Smrg#include "kdrive.h"
34706f2543Smrg
35706f2543Smrg#undef DEBUG
36706f2543Smrg#undef DEBUG_BYTES
37706f2543Smrg#define KBUFIO_SIZE 256
38706f2543Smrg#define MOUSE_TIMEOUT	100
39706f2543Smrg
40706f2543Smrgtypedef struct _kbufio {
41706f2543Smrg    int		    fd;
42706f2543Smrg    unsigned char   buf[KBUFIO_SIZE];
43706f2543Smrg    int		    avail;
44706f2543Smrg    int		    used;
45706f2543Smrg} Kbufio;
46706f2543Smrg
47706f2543Smrgstatic Bool
48706f2543SmrgMouseWaitForReadable (int fd, int timeout)
49706f2543Smrg{
50706f2543Smrg    fd_set	    set;
51706f2543Smrg    struct timeval  tv, *tp;
52706f2543Smrg    int		    n;
53706f2543Smrg    CARD32	    done;
54706f2543Smrg
55706f2543Smrg    done = GetTimeInMillis () + timeout;
56706f2543Smrg    for (;;)
57706f2543Smrg    {
58706f2543Smrg	FD_ZERO (&set);
59706f2543Smrg	FD_SET (fd, &set);
60706f2543Smrg	if (timeout == -1)
61706f2543Smrg	    tp = 0;
62706f2543Smrg	else
63706f2543Smrg	{
64706f2543Smrg	    tv.tv_sec = timeout / 1000;
65706f2543Smrg	    tv.tv_usec = (timeout % 1000) * 1000;
66706f2543Smrg	    tp = &tv;
67706f2543Smrg	}
68706f2543Smrg	n = select (fd + 1, &set, 0, 0, tp);
69706f2543Smrg	if (n > 0)
70706f2543Smrg	    return TRUE;
71706f2543Smrg	if (n < 0 && (errno == EAGAIN || errno == EINTR))
72706f2543Smrg	{
73706f2543Smrg	    timeout = (int) (done - GetTimeInMillis ());
74706f2543Smrg	    if (timeout > 0)
75706f2543Smrg		continue;
76706f2543Smrg	}
77706f2543Smrg	break;
78706f2543Smrg    }
79706f2543Smrg    return FALSE;
80706f2543Smrg}
81706f2543Smrg
82706f2543Smrgstatic int
83706f2543SmrgMouseReadByte (Kbufio *b, int timeout)
84706f2543Smrg{
85706f2543Smrg    int	n;
86706f2543Smrg    if (b->avail <= b->used)
87706f2543Smrg    {
88706f2543Smrg	if (timeout && !MouseWaitForReadable (b->fd, timeout))
89706f2543Smrg	{
90706f2543Smrg#ifdef DEBUG_BYTES
91706f2543Smrg	    ErrorF ("\tTimeout %d\n", timeout);
92706f2543Smrg#endif
93706f2543Smrg	    return -1;
94706f2543Smrg	}
95706f2543Smrg	n = read (b->fd, b->buf, KBUFIO_SIZE);
96706f2543Smrg	if (n <= 0)
97706f2543Smrg	    return -1;
98706f2543Smrg        b->avail = n;
99706f2543Smrg        b->used = 0;
100706f2543Smrg    }
101706f2543Smrg#ifdef DEBUG_BYTES
102706f2543Smrg    ErrorF ("\tget %02x\n", b->buf[b->used]);
103706f2543Smrg#endif
104706f2543Smrg    return b->buf[b->used++];
105706f2543Smrg}
106706f2543Smrg
107706f2543Smrg#if NOTUSED
108706f2543Smrgstatic int
109706f2543SmrgMouseFlush (Kbufio *b, char *buf, int size)
110706f2543Smrg{
111706f2543Smrg    CARD32  now = GetTimeInMillis ();
112706f2543Smrg    CARD32  done = now + 100;
113706f2543Smrg    int	    c;
114706f2543Smrg    int	    n = 0;
115706f2543Smrg
116706f2543Smrg    while ((c = MouseReadByte (b, done - now)) != -1)
117706f2543Smrg    {
118706f2543Smrg	if (buf)
119706f2543Smrg	{
120706f2543Smrg	    if (n == size)
121706f2543Smrg	    {
122706f2543Smrg		memmove (buf, buf + 1, size - 1);
123706f2543Smrg		n--;
124706f2543Smrg	    }
125706f2543Smrg	    buf[n++] = c;
126706f2543Smrg	}
127706f2543Smrg	now = GetTimeInMillis ();
128706f2543Smrg	if ((INT32) (now - done) >= 0)
129706f2543Smrg	    break;
130706f2543Smrg    }
131706f2543Smrg    return n;
132706f2543Smrg}
133706f2543Smrg
134706f2543Smrgstatic int
135706f2543SmrgMousePeekByte (Kbufio *b, int timeout)
136706f2543Smrg{
137706f2543Smrg    int	    c;
138706f2543Smrg
139706f2543Smrg    c = MouseReadByte (b, timeout);
140706f2543Smrg    if (c != -1)
141706f2543Smrg	--b->used;
142706f2543Smrg    return c;
143706f2543Smrg}
144706f2543Smrg#endif /* NOTUSED */
145706f2543Smrg
146706f2543Smrgstatic Bool
147706f2543SmrgMouseWaitForWritable (int fd, int timeout)
148706f2543Smrg{
149706f2543Smrg    fd_set	    set;
150706f2543Smrg    struct timeval  tv, *tp;
151706f2543Smrg    int		    n;
152706f2543Smrg
153706f2543Smrg    FD_ZERO (&set);
154706f2543Smrg    FD_SET (fd, &set);
155706f2543Smrg    if (timeout == -1)
156706f2543Smrg	tp = 0;
157706f2543Smrg    else
158706f2543Smrg    {
159706f2543Smrg	tv.tv_sec = timeout / 1000;
160706f2543Smrg	tv.tv_usec = (timeout % 1000) * 1000;
161706f2543Smrg	tp = &tv;
162706f2543Smrg    }
163706f2543Smrg    n = select (fd + 1, 0, &set, 0, tp);
164706f2543Smrg    if (n > 0)
165706f2543Smrg	return TRUE;
166706f2543Smrg    return FALSE;
167706f2543Smrg}
168706f2543Smrg
169706f2543Smrgstatic Bool
170706f2543SmrgMouseWriteByte (int fd, unsigned char c, int timeout)
171706f2543Smrg{
172706f2543Smrg    int	ret;
173706f2543Smrg
174706f2543Smrg#ifdef DEBUG_BYTES
175706f2543Smrg    ErrorF ("\tput %02x\n", c);
176706f2543Smrg#endif
177706f2543Smrg    for (;;)
178706f2543Smrg    {
179706f2543Smrg	ret = write (fd, &c, 1);
180706f2543Smrg	if (ret == 1)
181706f2543Smrg	    return TRUE;
182706f2543Smrg	if (ret == 0)
183706f2543Smrg	    return FALSE;
184706f2543Smrg	if (errno != EWOULDBLOCK)
185706f2543Smrg	    return FALSE;
186706f2543Smrg	if (!MouseWaitForWritable (fd, timeout))
187706f2543Smrg	    return FALSE;
188706f2543Smrg    }
189706f2543Smrg}
190706f2543Smrg
191706f2543Smrgstatic Bool
192706f2543SmrgMouseWriteBytes (int fd, unsigned char *c, int n, int timeout)
193706f2543Smrg{
194706f2543Smrg    while (n--)
195706f2543Smrg	if (!MouseWriteByte (fd, *c++, timeout))
196706f2543Smrg	    return FALSE;
197706f2543Smrg    return TRUE;
198706f2543Smrg}
199706f2543Smrg
200706f2543Smrg#define MAX_MOUSE   10	    /* maximum length of mouse protocol */
201706f2543Smrg#define MAX_SKIP    16	    /* number of error bytes before switching */
202706f2543Smrg#define MAX_VALID   4	    /* number of valid packets before accepting */
203706f2543Smrg
204706f2543Smrgtypedef struct _kmouseProt {
205706f2543Smrg    char	    *name;
206706f2543Smrg    Bool	    (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne);
207706f2543Smrg    int		    (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne);
208706f2543Smrg    Bool	    (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne);
209706f2543Smrg    Bool	    (*Init) (KdPointerInfo *pi);
210706f2543Smrg    unsigned char   headerMask, headerValid;
211706f2543Smrg    unsigned char   dataMask, dataValid;
212706f2543Smrg    Bool	    tty;
213706f2543Smrg    unsigned int    c_iflag;
214706f2543Smrg    unsigned int    c_oflag;
215706f2543Smrg    unsigned int    c_lflag;
216706f2543Smrg    unsigned int    c_cflag;
217706f2543Smrg    unsigned int    speed;
218706f2543Smrg    unsigned char   *init;
219706f2543Smrg    unsigned long   state;
220706f2543Smrg} KmouseProt;
221706f2543Smrg
222706f2543Smrgtypedef enum _kmouseStage {
223706f2543Smrg    MouseBroken, MouseTesting, MouseWorking
224706f2543Smrg} KmouseStage;
225706f2543Smrg
226706f2543Smrgtypedef struct _kmouse {
227706f2543Smrg    Kbufio		iob;
228706f2543Smrg    const KmouseProt	*prot;
229706f2543Smrg    int			i_prot;
230706f2543Smrg    KmouseStage		stage;	/* protocol verification stage */
231706f2543Smrg    Bool		tty;	/* mouse device is a tty */
232706f2543Smrg    int			valid;	/* sequential valid events */
233706f2543Smrg    int			tested;	/* bytes scanned during Testing phase */
234706f2543Smrg    int			invalid;/* total invalid bytes for this protocol */
235706f2543Smrg    unsigned long	state;	/* private per protocol, init to prot->state */
236706f2543Smrg} Kmouse;
237706f2543Smrg
238706f2543Smrgstatic int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne)
239706f2543Smrg{
240706f2543Smrg    Kmouse		*km = pi->driverPrivate;
241706f2543Smrg    const KmouseProt	*prot = km->prot;
242706f2543Smrg    int	    i;
243706f2543Smrg
244706f2543Smrg    for (i = 0; i < ne; i++)
245706f2543Smrg	if ((ev[i] & prot->headerMask) == prot->headerValid)
246706f2543Smrg	    break;
247706f2543Smrg    if (i != 0)
248706f2543Smrg	return i;
249706f2543Smrg    for (i = 1; i < ne; i++)
250706f2543Smrg	if ((ev[i] & prot->dataMask) != prot->dataValid)
251706f2543Smrg	    return -1;
252706f2543Smrg    return 0;
253706f2543Smrg}
254706f2543Smrg
255706f2543Smrgstatic Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
256706f2543Smrg{
257706f2543Smrg    return ne == 3;
258706f2543Smrg}
259706f2543Smrg
260706f2543Smrgstatic Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
261706f2543Smrg{
262706f2543Smrg    return ne == 4;
263706f2543Smrg}
264706f2543Smrg
265706f2543Smrgstatic Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
266706f2543Smrg{
267706f2543Smrg    return ne == 5;
268706f2543Smrg}
269706f2543Smrg
270706f2543Smrgstatic Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy)
271706f2543Smrg{
272706f2543Smrg    Kmouse		*km = pi->driverPrivate;
273706f2543Smrg
274706f2543Smrg    if (km->stage == MouseWorking)
275706f2543Smrg	return TRUE;
276706f2543Smrg    if (dx < -50 || dx > 50)
277706f2543Smrg    {
278706f2543Smrg#ifdef DEBUG
279706f2543Smrg	ErrorF ("Large X %d\n", dx);
280706f2543Smrg#endif
281706f2543Smrg	return FALSE;
282706f2543Smrg    }
283706f2543Smrg    if (dy < -50 || dy > 50)
284706f2543Smrg    {
285706f2543Smrg#ifdef DEBUG
286706f2543Smrg	ErrorF ("Large Y %d\n", dy);
287706f2543Smrg#endif
288706f2543Smrg	return FALSE;
289706f2543Smrg    }
290706f2543Smrg    return TRUE;
291706f2543Smrg}
292706f2543Smrg
293706f2543Smrg/*
294706f2543Smrg * Standard PS/2 mouse protocol
295706f2543Smrg */
296706f2543Smrgstatic Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne)
297706f2543Smrg{
298706f2543Smrg    Kmouse	    *km = pi->driverPrivate;
299706f2543Smrg    int		    dx, dy, dz;
300706f2543Smrg    unsigned long   flags;
301706f2543Smrg    unsigned long   flagsrelease = 0;
302706f2543Smrg
303706f2543Smrg    flags = KD_MOUSE_DELTA;
304706f2543Smrg    if (ev[0] & 4)
305706f2543Smrg	flags |= KD_BUTTON_2;
306706f2543Smrg    if (ev[0] & 2)
307706f2543Smrg	flags |= KD_BUTTON_3;
308706f2543Smrg    if (ev[0] & 1)
309706f2543Smrg	flags |= KD_BUTTON_1;
310706f2543Smrg
311706f2543Smrg    if (ne > 3)
312706f2543Smrg    {
313706f2543Smrg	dz = (int) (signed char) ev[3];
314706f2543Smrg	if (dz < 0)
315706f2543Smrg	{
316706f2543Smrg	    flags |= KD_BUTTON_4;
317706f2543Smrg	    flagsrelease = KD_BUTTON_4;
318706f2543Smrg	}
319706f2543Smrg	else if (dz > 0)
320706f2543Smrg	{
321706f2543Smrg	    flags |= KD_BUTTON_5;
322706f2543Smrg	    flagsrelease = KD_BUTTON_5;
323706f2543Smrg	}
324706f2543Smrg    }
325706f2543Smrg
326706f2543Smrg    dx = ev[1];
327706f2543Smrg    if (ev[0] & 0x10)
328706f2543Smrg	dx -= 256;
329706f2543Smrg    dy = ev[2];
330706f2543Smrg    if (ev[0] & 0x20)
331706f2543Smrg	dy -= 256;
332706f2543Smrg    dy = -dy;
333706f2543Smrg    if (!MouseReasonable (pi, flags, dx, dy))
334706f2543Smrg	return FALSE;
335706f2543Smrg    if (km->stage == MouseWorking)
336706f2543Smrg    {
337706f2543Smrg	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
338706f2543Smrg	if (flagsrelease)
339706f2543Smrg	{
340706f2543Smrg	    flags &= ~flagsrelease;
341706f2543Smrg	    KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
342706f2543Smrg	}
343706f2543Smrg    }
344706f2543Smrg    return TRUE;
345706f2543Smrg}
346706f2543Smrg
347706f2543Smrgstatic Bool ps2Init (KdPointerInfo *pi);
348706f2543Smrg
349706f2543Smrgstatic const KmouseProt ps2Prot = {
350706f2543Smrg    "ps/2",
351706f2543Smrg    threeComplete, mouseValid, ps2Parse, ps2Init,
352706f2543Smrg    0x08, 0x08, 0x00, 0x00,
353706f2543Smrg    FALSE
354706f2543Smrg};
355706f2543Smrg
356706f2543Smrgstatic const KmouseProt imps2Prot = {
357706f2543Smrg    "imps/2",
358706f2543Smrg    fourComplete, mouseValid, ps2Parse, ps2Init,
359706f2543Smrg    0x08, 0x08, 0x00, 0x00,
360706f2543Smrg    FALSE
361706f2543Smrg};
362706f2543Smrg
363706f2543Smrgstatic const KmouseProt exps2Prot = {
364706f2543Smrg    "exps/2",
365706f2543Smrg    fourComplete, mouseValid, ps2Parse, ps2Init,
366706f2543Smrg    0x08, 0x08, 0x00, 0x00,
367706f2543Smrg    FALSE
368706f2543Smrg};
369706f2543Smrg
370706f2543Smrg/*
371706f2543Smrg * Once the mouse is known to speak ps/2 protocol, go and find out
372706f2543Smrg * what advanced capabilities it has and turn them on
373706f2543Smrg */
374706f2543Smrg
375706f2543Smrg/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */
376706f2543Smrg
377706f2543Smrg/* aux device commands (sent to KBD_DATA_PORT) */
378706f2543Smrg#define PSMC_SET_SCALING11      0x00e6
379706f2543Smrg#define PSMC_SET_SCALING21      0x00e7
380706f2543Smrg#define PSMC_SET_RESOLUTION     0x00e8
381706f2543Smrg#define PSMC_SEND_DEV_STATUS    0x00e9
382706f2543Smrg#define PSMC_SET_STREAM_MODE    0x00ea
383706f2543Smrg#define PSMC_SEND_DEV_DATA      0x00eb
384706f2543Smrg#define PSMC_SET_REMOTE_MODE    0x00f0
385706f2543Smrg#define PSMC_SEND_DEV_ID        0x00f2
386706f2543Smrg#define PSMC_SET_SAMPLING_RATE  0x00f3
387706f2543Smrg#define PSMC_ENABLE_DEV         0x00f4
388706f2543Smrg#define PSMC_DISABLE_DEV        0x00f5
389706f2543Smrg#define PSMC_SET_DEFAULTS       0x00f6
390706f2543Smrg#define PSMC_RESET_DEV          0x00ff
391706f2543Smrg
392706f2543Smrg/* PSMC_SET_RESOLUTION argument */
393706f2543Smrg#define PSMD_RES_LOW            0       /* typically 25ppi */
394706f2543Smrg#define PSMD_RES_MEDIUM_LOW     1       /* typically 50ppi */
395706f2543Smrg#define PSMD_RES_MEDIUM_HIGH    2       /* typically 100ppi (default) */
396706f2543Smrg#define PSMD_RES_HIGH           3       /* typically 200ppi */
397706f2543Smrg#define PSMD_MAX_RESOLUTION     PSMD_RES_HIGH
398706f2543Smrg
399706f2543Smrg/* PSMC_SET_SAMPLING_RATE */
400706f2543Smrg#define PSMD_MAX_RATE           255     /* FIXME: not sure if it's possible */
401706f2543Smrg
402706f2543Smrg/* aux device ID */
403706f2543Smrg#define PSM_MOUSE_ID            0
404706f2543Smrg#define PSM_BALLPOINT_ID        2
405706f2543Smrg#define PSM_INTELLI_ID          3
406706f2543Smrg#define PSM_EXPLORER_ID         4
407706f2543Smrg#define PSM_4DMOUSE_ID          6
408706f2543Smrg#define PSM_4DPLUS_ID           8
409706f2543Smrg
410706f2543Smrgstatic unsigned char	ps2_init[] = {
411706f2543Smrg    PSMC_ENABLE_DEV,
412706f2543Smrg    0,
413706f2543Smrg};
414706f2543Smrg
415706f2543Smrg#define NINIT_PS2   1
416706f2543Smrg
417706f2543Smrgstatic unsigned char    wheel_3button_init[] = {
418706f2543Smrg    PSMC_SET_SAMPLING_RATE, 200,
419706f2543Smrg    PSMC_SET_SAMPLING_RATE, 100,
420706f2543Smrg    PSMC_SET_SAMPLING_RATE,  80,
421706f2543Smrg    PSMC_SEND_DEV_ID,
422706f2543Smrg    0,
423706f2543Smrg};
424706f2543Smrg
425706f2543Smrg#define NINIT_IMPS2 4
426706f2543Smrg
427706f2543Smrgstatic unsigned char    wheel_5button_init[] = {
428706f2543Smrg    PSMC_SET_SAMPLING_RATE, 200,
429706f2543Smrg    PSMC_SET_SAMPLING_RATE, 100,
430706f2543Smrg    PSMC_SET_SAMPLING_RATE,  80,
431706f2543Smrg    PSMC_SET_SAMPLING_RATE, 200,
432706f2543Smrg    PSMC_SET_SAMPLING_RATE, 200,
433706f2543Smrg    PSMC_SET_SAMPLING_RATE,  80,
434706f2543Smrg    PSMC_SEND_DEV_ID,
435706f2543Smrg    0
436706f2543Smrg};
437706f2543Smrg
438706f2543Smrg#define NINIT_EXPS2 7
439706f2543Smrg
440706f2543Smrgstatic unsigned char	intelli_init[] = {
441706f2543Smrg    PSMC_SET_SAMPLING_RATE, 200,
442706f2543Smrg    PSMC_SET_SAMPLING_RATE, 100,
443706f2543Smrg    PSMC_SET_SAMPLING_RATE,  80,
444706f2543Smrg    0
445706f2543Smrg};
446706f2543Smrg
447706f2543Smrg#define NINIT_INTELLI	3
448706f2543Smrg
449706f2543Smrgstatic int
450706f2543Smrgps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next)
451706f2543Smrg{
452706f2543Smrg    Kmouse  *km = pi->driverPrivate;
453706f2543Smrg    int	    c = -1;
454706f2543Smrg    int	    skipping;
455706f2543Smrg    Bool    waiting;
456706f2543Smrg
457706f2543Smrg    skipping = 0;
458706f2543Smrg    waiting = FALSE;
459706f2543Smrg    while (ninit || ret_next)
460706f2543Smrg    {
461706f2543Smrg	c = MouseReadByte (&km->iob, MOUSE_TIMEOUT);
462706f2543Smrg	if (c == -1)
463706f2543Smrg	    break;
464706f2543Smrg	/* look for ACK */
465706f2543Smrg	if (c == 0xfa)
466706f2543Smrg	{
467706f2543Smrg	    ninit--;
468706f2543Smrg	    if (ret_next)
469706f2543Smrg		waiting = TRUE;
470706f2543Smrg	}
471706f2543Smrg	/* look for packet start -- not the response */
472706f2543Smrg	else if ((c & 0x08) == 0x08)
473706f2543Smrg	    waiting = FALSE;
474706f2543Smrg	else if (waiting)
475706f2543Smrg	    break;
476706f2543Smrg    }
477706f2543Smrg    return c;
478706f2543Smrg}
479706f2543Smrg
480706f2543Smrgstatic Bool
481706f2543Smrgps2Init (KdPointerInfo *pi)
482706f2543Smrg{
483706f2543Smrg    Kmouse	    *km = pi->driverPrivate;
484706f2543Smrg    int		    skipping;
485706f2543Smrg    Bool	    waiting;
486706f2543Smrg    int		    id;
487706f2543Smrg    unsigned char   *init;
488706f2543Smrg    int		    ninit;
489706f2543Smrg
490706f2543Smrg    /* Send Intellimouse initialization sequence */
491706f2543Smrg    MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100);
492706f2543Smrg    /*
493706f2543Smrg     * Send ID command
494706f2543Smrg     */
495706f2543Smrg    if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100))
496706f2543Smrg	return FALSE;
497706f2543Smrg    skipping = 0;
498706f2543Smrg    waiting = FALSE;
499706f2543Smrg    id = ps2SkipInit (pi, 0, TRUE);
500706f2543Smrg    switch (id) {
501706f2543Smrg    case 3:
502706f2543Smrg	init = wheel_3button_init;
503706f2543Smrg	ninit = NINIT_IMPS2;
504706f2543Smrg	km->prot = &imps2Prot;
505706f2543Smrg	break;
506706f2543Smrg    case 4:
507706f2543Smrg	init = wheel_5button_init;
508706f2543Smrg	ninit = NINIT_EXPS2;
509706f2543Smrg	km->prot = &exps2Prot;
510706f2543Smrg	break;
511706f2543Smrg    default:
512706f2543Smrg	init = ps2_init;
513706f2543Smrg	ninit = NINIT_PS2;
514706f2543Smrg	km->prot = &ps2Prot;
515706f2543Smrg	break;
516706f2543Smrg    }
517706f2543Smrg    if (init)
518706f2543Smrg	MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100);
519706f2543Smrg    /*
520706f2543Smrg     * Flush out the available data to eliminate responses to the
521706f2543Smrg     * initialization string.  Make sure any partial event is
522706f2543Smrg     * skipped
523706f2543Smrg     */
524706f2543Smrg    (void) ps2SkipInit (pi, ninit, FALSE);
525706f2543Smrg    return TRUE;
526706f2543Smrg}
527706f2543Smrg
528706f2543Smrgstatic Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne)
529706f2543Smrg{
530706f2543Smrg    Kmouse	    *km = pi->driverPrivate;
531706f2543Smrg    int		    dx, dy;
532706f2543Smrg    unsigned long   flags;
533706f2543Smrg
534706f2543Smrg    flags = KD_MOUSE_DELTA;
535706f2543Smrg    dx = (signed char) ev[1];
536706f2543Smrg    dy = -(signed char) ev[2];
537706f2543Smrg    if ((ev[0] & 4) == 0)
538706f2543Smrg	flags |= KD_BUTTON_1;
539706f2543Smrg    if ((ev[0] & 2) == 0)
540706f2543Smrg	flags |= KD_BUTTON_2;
541706f2543Smrg    if ((ev[0] & 1) == 0)
542706f2543Smrg	flags |= KD_BUTTON_3;
543706f2543Smrg    if (!MouseReasonable (pi, flags, dx, dy))
544706f2543Smrg	return FALSE;
545706f2543Smrg    if (km->stage == MouseWorking)
546706f2543Smrg	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
547706f2543Smrg    return TRUE;
548706f2543Smrg}
549706f2543Smrg
550706f2543Smrgstatic const KmouseProt busProt = {
551706f2543Smrg    "bus",
552706f2543Smrg    threeComplete, mouseValid, busParse, 0,
553706f2543Smrg    0xf8, 0x00, 0x00, 0x00,
554706f2543Smrg    FALSE
555706f2543Smrg};
556706f2543Smrg
557706f2543Smrg/*
558706f2543Smrg * Standard MS serial protocol, three bytes
559706f2543Smrg */
560706f2543Smrg
561706f2543Smrgstatic Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne)
562706f2543Smrg{
563706f2543Smrg    Kmouse	    *km = pi->driverPrivate;
564706f2543Smrg    int		    dx, dy;
565706f2543Smrg    unsigned long   flags;
566706f2543Smrg
567706f2543Smrg    flags = KD_MOUSE_DELTA;
568706f2543Smrg
569706f2543Smrg    if (ev[0] & 0x20)
570706f2543Smrg	flags |= KD_BUTTON_1;
571706f2543Smrg    if (ev[0] & 0x10)
572706f2543Smrg	flags |= KD_BUTTON_3;
573706f2543Smrg
574706f2543Smrg    dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
575706f2543Smrg    dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
576706f2543Smrg    if (!MouseReasonable (pi, flags, dx, dy))
577706f2543Smrg	return FALSE;
578706f2543Smrg    if (km->stage == MouseWorking)
579706f2543Smrg	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
580706f2543Smrg    return TRUE;
581706f2543Smrg}
582706f2543Smrg
583706f2543Smrgstatic const KmouseProt msProt = {
584706f2543Smrg    "ms",
585706f2543Smrg    threeComplete, mouseValid, msParse, 0,
586706f2543Smrg    0xc0, 0x40, 0xc0, 0x00,
587706f2543Smrg    TRUE,
588706f2543Smrg    IGNPAR,
589706f2543Smrg    0,
590706f2543Smrg    0,
591706f2543Smrg    CS7 | CSTOPB | CREAD | CLOCAL,
592706f2543Smrg    B1200,
593706f2543Smrg};
594706f2543Smrg
595706f2543Smrg/*
596706f2543Smrg * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the
597706f2543Smrg * first byte of a synchronized protocol stream and see if it's got
598706f2543Smrg * any bits turned on that can't occur in that fourth byte
599706f2543Smrg */
600706f2543Smrgstatic Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
601706f2543Smrg{
602706f2543Smrg    Kmouse		*km = pi->driverPrivate;
603706f2543Smrg
604706f2543Smrg    if ((ev[0] & 0x40) == 0x40)
605706f2543Smrg	return ne == 3;
606706f2543Smrg    if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0)
607706f2543Smrg	return ne == 1;
608706f2543Smrg    return FALSE;
609706f2543Smrg}
610706f2543Smrg
611706f2543Smrgstatic int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne)
612706f2543Smrg{
613706f2543Smrg    Kmouse		*km = pi->driverPrivate;
614706f2543Smrg    const KmouseProt	*prot = km->prot;
615706f2543Smrg    int	    i;
616706f2543Smrg
617706f2543Smrg    for (i = 0; i < ne; i++)
618706f2543Smrg    {
619706f2543Smrg	if ((ev[i] & 0x40) == 0x40)
620706f2543Smrg	    break;
621706f2543Smrg	if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0)
622706f2543Smrg	    break;
623706f2543Smrg    }
624706f2543Smrg    if (i != 0)
625706f2543Smrg	return i;
626706f2543Smrg    for (i = 1; i < ne; i++)
627706f2543Smrg	if ((ev[i] & prot->dataMask) != prot->dataValid)
628706f2543Smrg	    return -1;
629706f2543Smrg    return 0;
630706f2543Smrg}
631706f2543Smrg
632706f2543Smrgstatic Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne)
633706f2543Smrg{
634706f2543Smrg    Kmouse	    *km = pi->driverPrivate;
635706f2543Smrg    int		    dx, dy;
636706f2543Smrg    unsigned long   flags;
637706f2543Smrg
638706f2543Smrg    flags = KD_MOUSE_DELTA;
639706f2543Smrg
640706f2543Smrg    if (ne == 3)
641706f2543Smrg    {
642706f2543Smrg	if (ev[0] & 0x20)
643706f2543Smrg	    flags |= KD_BUTTON_1;
644706f2543Smrg	if (ev[0] & 0x10)
645706f2543Smrg	    flags |= KD_BUTTON_3;
646706f2543Smrg
647706f2543Smrg	dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
648706f2543Smrg	dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
649706f2543Smrg	flags |= km->state & KD_BUTTON_2;
650706f2543Smrg    }
651706f2543Smrg    else
652706f2543Smrg    {
653706f2543Smrg	if (ev[0] & 0x20)
654706f2543Smrg	    flags |= KD_BUTTON_2;
655706f2543Smrg	dx = 0;
656706f2543Smrg	dy = 0;
657706f2543Smrg	flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3);
658706f2543Smrg    }
659706f2543Smrg
660706f2543Smrg    if (!MouseReasonable (pi, flags, dx, dy))
661706f2543Smrg	return FALSE;
662706f2543Smrg    if (km->stage == MouseWorking)
663706f2543Smrg	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
664706f2543Smrg    return TRUE;
665706f2543Smrg}
666706f2543Smrg
667706f2543Smrgstatic const KmouseProt logiProt = {
668706f2543Smrg    "logitech",
669706f2543Smrg    logiComplete, logiValid, logiParse, 0,
670706f2543Smrg    0xc0, 0x40, 0xc0, 0x00,
671706f2543Smrg    TRUE,
672706f2543Smrg    IGNPAR,
673706f2543Smrg    0,
674706f2543Smrg    0,
675706f2543Smrg    CS7 | CSTOPB | CREAD | CLOCAL,
676706f2543Smrg    B1200,
677706f2543Smrg};
678706f2543Smrg
679706f2543Smrg/*
680706f2543Smrg * Mouse systems protocol, 5 bytes
681706f2543Smrg */
682706f2543Smrgstatic Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne)
683706f2543Smrg{
684706f2543Smrg    Kmouse	    *km = pi->driverPrivate;
685706f2543Smrg    int		    dx, dy;
686706f2543Smrg    unsigned long   flags;
687706f2543Smrg
688706f2543Smrg    flags = KD_MOUSE_DELTA;
689706f2543Smrg
690706f2543Smrg    if (!(ev[0] & 0x4))
691706f2543Smrg	flags |= KD_BUTTON_1;
692706f2543Smrg    if (!(ev[0] & 0x2))
693706f2543Smrg	flags |= KD_BUTTON_2;
694706f2543Smrg    if (!(ev[0] & 0x1))
695706f2543Smrg	flags |= KD_BUTTON_3;
696706f2543Smrg    dx =    (signed char)(ev[1]) + (signed char)(ev[3]);
697706f2543Smrg    dy = - ((signed char)(ev[2]) + (signed char)(ev[4]));
698706f2543Smrg
699706f2543Smrg    if (!MouseReasonable (pi, flags, dx, dy))
700706f2543Smrg	return FALSE;
701706f2543Smrg    if (km->stage == MouseWorking)
702706f2543Smrg	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
703706f2543Smrg    return TRUE;
704706f2543Smrg}
705706f2543Smrg
706706f2543Smrgstatic const KmouseProt mscProt = {
707706f2543Smrg    "msc",
708706f2543Smrg    fiveComplete, mouseValid, mscParse, 0,
709706f2543Smrg    0xf8, 0x80, 0x00, 0x00,
710706f2543Smrg    TRUE,
711706f2543Smrg    IGNPAR,
712706f2543Smrg    0,
713706f2543Smrg    0,
714706f2543Smrg    CS8 | CSTOPB | CREAD | CLOCAL,
715706f2543Smrg    B1200,
716706f2543Smrg};
717706f2543Smrg
718706f2543Smrg/*
719706f2543Smrg * Use logitech before ms -- they're the same except that
720706f2543Smrg * logitech sometimes has a fourth byte
721706f2543Smrg */
722706f2543Smrgstatic const KmouseProt *kmouseProts[] = {
723706f2543Smrg    &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt,
724706f2543Smrg};
725706f2543Smrg
726706f2543Smrg#define NUM_PROT    (sizeof (kmouseProts) / sizeof (kmouseProts[0]))
727706f2543Smrg
728706f2543Smrgstatic void
729706f2543SmrgMouseInitProtocol (Kmouse *km)
730706f2543Smrg{
731706f2543Smrg    int		    ret;
732706f2543Smrg    struct termios  t;
733706f2543Smrg
734706f2543Smrg    if (km->prot->tty)
735706f2543Smrg    {
736706f2543Smrg	ret = tcgetattr (km->iob.fd, &t);
737706f2543Smrg
738706f2543Smrg	if (ret >= 0)
739706f2543Smrg	{
740706f2543Smrg	    t.c_iflag = km->prot->c_iflag;
741706f2543Smrg	    t.c_oflag = km->prot->c_oflag;
742706f2543Smrg	    t.c_lflag = km->prot->c_lflag;
743706f2543Smrg	    t.c_cflag = km->prot->c_cflag;
744706f2543Smrg	    cfsetispeed (&t, km->prot->speed);
745706f2543Smrg	    cfsetospeed (&t, km->prot->speed);
746706f2543Smrg	    ret = tcsetattr (km->iob.fd, TCSANOW, &t);
747706f2543Smrg	}
748706f2543Smrg    }
749706f2543Smrg    km->stage = MouseBroken;
750706f2543Smrg    km->valid = 0;
751706f2543Smrg    km->tested = 0;
752706f2543Smrg    km->invalid = 0;
753706f2543Smrg    km->state = km->prot->state;
754706f2543Smrg}
755706f2543Smrg
756706f2543Smrgstatic void
757706f2543SmrgMouseFirstProtocol (Kmouse *km, char *prot)
758706f2543Smrg{
759706f2543Smrg    if (prot)
760706f2543Smrg    {
761706f2543Smrg	for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++)
762706f2543Smrg	    if (!strcmp (prot, kmouseProts[km->i_prot]->name))
763706f2543Smrg		break;
764706f2543Smrg	if (km->i_prot == NUM_PROT)
765706f2543Smrg	{
766706f2543Smrg	    int	i;
767706f2543Smrg	    ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot);
768706f2543Smrg	    for (i = 0; i < NUM_PROT; i++)
769706f2543Smrg		ErrorF (" %s", kmouseProts[i]->name);
770706f2543Smrg	    ErrorF ("\n");
771706f2543Smrg	}
772706f2543Smrg	else
773706f2543Smrg	{
774706f2543Smrg	    km->prot = kmouseProts[km->i_prot];
775706f2543Smrg	    if (km->tty && !km->prot->tty)
776706f2543Smrg		ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n",
777706f2543Smrg			prot);
778706f2543Smrg	    else if (!km->tty && km->prot->tty)
779706f2543Smrg		ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n",
780706f2543Smrg			prot);
781706f2543Smrg	}
782706f2543Smrg    }
783706f2543Smrg    if (!km->prot)
784706f2543Smrg    {
785706f2543Smrg	for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++)
786706f2543Smrg	    ;
787706f2543Smrg	km->prot = kmouseProts[km->i_prot];
788706f2543Smrg    }
789706f2543Smrg    MouseInitProtocol (km);
790706f2543Smrg}
791706f2543Smrg
792706f2543Smrgstatic void
793706f2543SmrgMouseNextProtocol (Kmouse *km)
794706f2543Smrg{
795706f2543Smrg    do
796706f2543Smrg    {
797706f2543Smrg	if (!km->prot)
798706f2543Smrg	    km->i_prot = 0;
799706f2543Smrg	else
800706f2543Smrg	    if (++km->i_prot == NUM_PROT) km->i_prot = 0;
801706f2543Smrg	km->prot = kmouseProts[km->i_prot];
802706f2543Smrg    } while (km->prot->tty != km->tty);
803706f2543Smrg    MouseInitProtocol (km);
804706f2543Smrg    ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name);
805706f2543Smrg}
806706f2543Smrg
807706f2543Smrgstatic void
808706f2543SmrgMouseRead (int mousePort, void *closure)
809706f2543Smrg{
810706f2543Smrg    KdPointerInfo   *pi = closure;
811706f2543Smrg    Kmouse	    *km = pi->driverPrivate;
812706f2543Smrg    unsigned char   event[MAX_MOUSE];
813706f2543Smrg    int		    ne;
814706f2543Smrg    int		    c;
815706f2543Smrg    int		    i;
816706f2543Smrg    int		    timeout;
817706f2543Smrg
818706f2543Smrg    timeout = 0;
819706f2543Smrg    ne = 0;
820706f2543Smrg    for(;;)
821706f2543Smrg    {
822706f2543Smrg	c = MouseReadByte (&km->iob, timeout);
823706f2543Smrg	if (c == -1)
824706f2543Smrg	{
825706f2543Smrg	    if (ne)
826706f2543Smrg	    {
827706f2543Smrg		km->invalid += ne + km->tested;
828706f2543Smrg		km->valid = 0;
829706f2543Smrg		km->tested = 0;
830706f2543Smrg		km->stage = MouseBroken;
831706f2543Smrg	    }
832706f2543Smrg	    break;
833706f2543Smrg	}
834706f2543Smrg	event[ne++] = c;
835706f2543Smrg	i = (*km->prot->Valid) (pi, event, ne);
836706f2543Smrg	if (i != 0)
837706f2543Smrg	{
838706f2543Smrg#ifdef DEBUG
839706f2543Smrg	    ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n",
840706f2543Smrg		    km->prot->name, i > 0 ? i : ne, ne);
841706f2543Smrg#endif
842706f2543Smrg	    if (i > 0 && i < ne)
843706f2543Smrg	    {
844706f2543Smrg		ne -= i;
845706f2543Smrg		memmove (event, event + i, ne);
846706f2543Smrg	    }
847706f2543Smrg	    else
848706f2543Smrg	    {
849706f2543Smrg		i = ne;
850706f2543Smrg		ne = 0;
851706f2543Smrg	    }
852706f2543Smrg	    km->invalid += i + km->tested;
853706f2543Smrg	    km->valid = 0;
854706f2543Smrg	    km->tested = 0;
855706f2543Smrg	    if (km->stage == MouseWorking)
856706f2543Smrg		km->i_prot--;
857706f2543Smrg	    km->stage = MouseBroken;
858706f2543Smrg	    if (km->invalid > MAX_SKIP)
859706f2543Smrg	    {
860706f2543Smrg		MouseNextProtocol (km);
861706f2543Smrg		ne = 0;
862706f2543Smrg	    }
863706f2543Smrg	    timeout = 0;
864706f2543Smrg	}
865706f2543Smrg	else
866706f2543Smrg	{
867706f2543Smrg	    if ((*km->prot->Complete) (pi, event, ne))
868706f2543Smrg	    {
869706f2543Smrg		if ((*km->prot->Parse) (pi, event, ne))
870706f2543Smrg		{
871706f2543Smrg		    switch (km->stage)
872706f2543Smrg		    {
873706f2543Smrg		    case MouseBroken:
874706f2543Smrg#ifdef DEBUG
875706f2543Smrg			ErrorF ("Mouse protocol %s seems OK\n",
876706f2543Smrg				km->prot->name);
877706f2543Smrg#endif
878706f2543Smrg			/* do not zero invalid to accumulate invalid bytes */
879706f2543Smrg			km->valid = 0;
880706f2543Smrg			km->tested = 0;
881706f2543Smrg			km->stage = MouseTesting;
882706f2543Smrg			/* fall through ... */
883706f2543Smrg		    case MouseTesting:
884706f2543Smrg			km->valid++;
885706f2543Smrg			km->tested += ne;
886706f2543Smrg			if (km->valid > MAX_VALID)
887706f2543Smrg			{
888706f2543Smrg#ifdef DEBUG
889706f2543Smrg			    ErrorF ("Mouse protocol %s working\n",
890706f2543Smrg				    km->prot->name);
891706f2543Smrg#endif
892706f2543Smrg			    km->stage = MouseWorking;
893706f2543Smrg			    km->invalid = 0;
894706f2543Smrg			    km->tested = 0;
895706f2543Smrg			    km->valid = 0;
896706f2543Smrg			    if (km->prot->Init && !(*km->prot->Init) (pi))
897706f2543Smrg				km->stage = MouseBroken;
898706f2543Smrg			}
899706f2543Smrg			break;
900706f2543Smrg		    case MouseWorking:
901706f2543Smrg			break;
902706f2543Smrg		    }
903706f2543Smrg		}
904706f2543Smrg		else
905706f2543Smrg		{
906706f2543Smrg		    km->invalid += ne + km->tested;
907706f2543Smrg		    km->valid = 0;
908706f2543Smrg		    km->tested = 0;
909706f2543Smrg		    km->stage = MouseBroken;
910706f2543Smrg		}
911706f2543Smrg		ne = 0;
912706f2543Smrg		timeout = 0;
913706f2543Smrg	    }
914706f2543Smrg	    else
915706f2543Smrg		timeout = MOUSE_TIMEOUT;
916706f2543Smrg	}
917706f2543Smrg    }
918706f2543Smrg}
919706f2543Smrg
920706f2543Smrgint MouseInputType;
921706f2543Smrg
922706f2543Smrgchar *kdefaultMouse[] =  {
923706f2543Smrg    "/dev/input/mice",
924706f2543Smrg    "/dev/mouse",
925706f2543Smrg    "/dev/psaux",
926706f2543Smrg    "/dev/adbmouse",
927706f2543Smrg    "/dev/ttyS0",
928706f2543Smrg    "/dev/ttyS1",
929706f2543Smrg};
930706f2543Smrg
931706f2543Smrg#define NUM_DEFAULT_MOUSE    (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))
932706f2543Smrg
933706f2543Smrgstatic Status
934706f2543SmrgMouseInit (KdPointerInfo *pi)
935706f2543Smrg{
936706f2543Smrg    int		i;
937706f2543Smrg    int		fd;
938706f2543Smrg    Kmouse	*km;
939706f2543Smrg
940706f2543Smrg    if (!pi)
941706f2543Smrg        return BadImplementation;
942706f2543Smrg
943706f2543Smrg    if (!pi->path || strcmp(pi->path, "auto") == 0) {
944706f2543Smrg        for (i = 0; i < NUM_DEFAULT_MOUSE; i++) {
945706f2543Smrg            fd = open (kdefaultMouse[i], 2);
946706f2543Smrg            if (fd >= 0) {
947706f2543Smrg                pi->path = strdup (kdefaultMouse[i]);
948706f2543Smrg                break;
949706f2543Smrg            }
950706f2543Smrg        }
951706f2543Smrg    }
952706f2543Smrg    else {
953706f2543Smrg        fd = open (pi->path, 2);
954706f2543Smrg    }
955706f2543Smrg
956706f2543Smrg    if (fd < 0)
957706f2543Smrg        return BadMatch;
958706f2543Smrg
959706f2543Smrg    close(fd);
960706f2543Smrg
961706f2543Smrg    km = (Kmouse *) malloc(sizeof (Kmouse));
962706f2543Smrg    if (km) {
963706f2543Smrg        km->iob.avail = km->iob.used = 0;
964706f2543Smrg        MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2");
965706f2543Smrg        /* MouseFirstProtocol sets state to MouseBroken for later protocol
966706f2543Smrg         * checks. Skip these checks if a protocol was supplied */
967706f2543Smrg        if (pi->protocol)
968706f2543Smrg                km->state = MouseWorking;
969706f2543Smrg        km->i_prot = 0;
970706f2543Smrg        km->tty = isatty (fd);
971706f2543Smrg        km->iob.fd = -1;
972706f2543Smrg        pi->driverPrivate = km;
973706f2543Smrg    }
974706f2543Smrg    else {
975706f2543Smrg        close (fd);
976706f2543Smrg        return BadAlloc;
977706f2543Smrg    }
978706f2543Smrg
979706f2543Smrg    return Success;
980706f2543Smrg}
981706f2543Smrg
982706f2543Smrgstatic Status
983706f2543SmrgMouseEnable (KdPointerInfo *pi)
984706f2543Smrg{
985706f2543Smrg    Kmouse *km;
986706f2543Smrg
987706f2543Smrg    if (!pi || !pi->driverPrivate || !pi->path)
988706f2543Smrg        return BadImplementation;
989706f2543Smrg
990706f2543Smrg    km = pi->driverPrivate;
991706f2543Smrg
992706f2543Smrg    km->iob.fd = open(pi->path, 2);
993706f2543Smrg    if (km->iob.fd < 0)
994706f2543Smrg        return BadMatch;
995706f2543Smrg
996706f2543Smrg    if (!KdRegisterFd (km->iob.fd, MouseRead, pi))
997706f2543Smrg    {
998706f2543Smrg        close(km->iob.fd);
999706f2543Smrg        return BadAlloc;
1000706f2543Smrg    }
1001706f2543Smrg
1002706f2543Smrg    return Success;
1003706f2543Smrg}
1004706f2543Smrg
1005706f2543Smrgstatic void
1006706f2543SmrgMouseDisable (KdPointerInfo *pi)
1007706f2543Smrg{
1008706f2543Smrg    Kmouse *km;
1009706f2543Smrg    if (!pi || !pi->driverPrivate)
1010706f2543Smrg        return;
1011706f2543Smrg
1012706f2543Smrg    km = pi->driverPrivate;
1013706f2543Smrg    KdUnregisterFd (pi, km->iob.fd, TRUE);
1014706f2543Smrg}
1015706f2543Smrg
1016706f2543Smrgstatic void
1017706f2543SmrgMouseFini (KdPointerInfo *pi)
1018706f2543Smrg{
1019706f2543Smrg    free(pi->driverPrivate);
1020706f2543Smrg    pi->driverPrivate = NULL;
1021706f2543Smrg}
1022706f2543Smrg
1023706f2543SmrgKdPointerDriver LinuxMouseDriver = {
1024706f2543Smrg    "mouse",
1025706f2543Smrg    MouseInit,
1026706f2543Smrg    MouseEnable,
1027706f2543Smrg    MouseDisable,
1028706f2543Smrg    MouseFini,
1029706f2543Smrg    NULL,
1030706f2543Smrg};
1031