1/*
2 * Copyright � 2001 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <kdrive-config.h>
25#endif
26#include <errno.h>
27#include <termios.h>
28#include <X11/X.h>
29#include <X11/Xproto.h>
30#include <X11/Xpoll.h>
31#include "inputstr.h"
32#include "scrnintstr.h"
33#include "kdrive.h"
34
35#undef DEBUG
36#undef DEBUG_BYTES
37#define KBUFIO_SIZE 256
38#define MOUSE_TIMEOUT	100
39
40typedef struct _kbufio {
41    int		    fd;
42    unsigned char   buf[KBUFIO_SIZE];
43    int		    avail;
44    int		    used;
45} Kbufio;
46
47static Bool
48MouseWaitForReadable (int fd, int timeout)
49{
50    fd_set	    set;
51    struct timeval  tv, *tp;
52    int		    n;
53    CARD32	    done;
54
55    done = GetTimeInMillis () + timeout;
56    for (;;)
57    {
58	FD_ZERO (&set);
59	FD_SET (fd, &set);
60	if (timeout == -1)
61	    tp = 0;
62	else
63	{
64	    tv.tv_sec = timeout / 1000;
65	    tv.tv_usec = (timeout % 1000) * 1000;
66	    tp = &tv;
67	}
68	n = select (fd + 1, &set, 0, 0, tp);
69	if (n > 0)
70	    return TRUE;
71	if (n < 0 && (errno == EAGAIN || errno == EINTR))
72	{
73	    timeout = (int) (done - GetTimeInMillis ());
74	    if (timeout > 0)
75		continue;
76	}
77	break;
78    }
79    return FALSE;
80}
81
82static int
83MouseReadByte (Kbufio *b, int timeout)
84{
85    int	n;
86    if (b->avail <= b->used)
87    {
88	if (timeout && !MouseWaitForReadable (b->fd, timeout))
89	{
90#ifdef DEBUG_BYTES
91	    ErrorF ("\tTimeout %d\n", timeout);
92#endif
93	    return -1;
94	}
95	n = read (b->fd, b->buf, KBUFIO_SIZE);
96	if (n <= 0)
97	    return -1;
98        b->avail = n;
99        b->used = 0;
100    }
101#ifdef DEBUG_BYTES
102    ErrorF ("\tget %02x\n", b->buf[b->used]);
103#endif
104    return b->buf[b->used++];
105}
106
107#if NOTUSED
108static int
109MouseFlush (Kbufio *b, char *buf, int size)
110{
111    CARD32  now = GetTimeInMillis ();
112    CARD32  done = now + 100;
113    int	    c;
114    int	    n = 0;
115
116    while ((c = MouseReadByte (b, done - now)) != -1)
117    {
118	if (buf)
119	{
120	    if (n == size)
121	    {
122		memmove (buf, buf + 1, size - 1);
123		n--;
124	    }
125	    buf[n++] = c;
126	}
127	now = GetTimeInMillis ();
128	if ((INT32) (now - done) >= 0)
129	    break;
130    }
131    return n;
132}
133
134static int
135MousePeekByte (Kbufio *b, int timeout)
136{
137    int	    c;
138
139    c = MouseReadByte (b, timeout);
140    if (c != -1)
141	--b->used;
142    return c;
143}
144#endif /* NOTUSED */
145
146static Bool
147MouseWaitForWritable (int fd, int timeout)
148{
149    fd_set	    set;
150    struct timeval  tv, *tp;
151    int		    n;
152
153    FD_ZERO (&set);
154    FD_SET (fd, &set);
155    if (timeout == -1)
156	tp = 0;
157    else
158    {
159	tv.tv_sec = timeout / 1000;
160	tv.tv_usec = (timeout % 1000) * 1000;
161	tp = &tv;
162    }
163    n = select (fd + 1, 0, &set, 0, tp);
164    if (n > 0)
165	return TRUE;
166    return FALSE;
167}
168
169static Bool
170MouseWriteByte (int fd, unsigned char c, int timeout)
171{
172    int	ret;
173
174#ifdef DEBUG_BYTES
175    ErrorF ("\tput %02x\n", c);
176#endif
177    for (;;)
178    {
179	ret = write (fd, &c, 1);
180	if (ret == 1)
181	    return TRUE;
182	if (ret == 0)
183	    return FALSE;
184	if (errno != EWOULDBLOCK)
185	    return FALSE;
186	if (!MouseWaitForWritable (fd, timeout))
187	    return FALSE;
188    }
189}
190
191static Bool
192MouseWriteBytes (int fd, unsigned char *c, int n, int timeout)
193{
194    while (n--)
195	if (!MouseWriteByte (fd, *c++, timeout))
196	    return FALSE;
197    return TRUE;
198}
199
200#define MAX_MOUSE   10	    /* maximum length of mouse protocol */
201#define MAX_SKIP    16	    /* number of error bytes before switching */
202#define MAX_VALID   4	    /* number of valid packets before accepting */
203
204typedef struct _kmouseProt {
205    char	    *name;
206    Bool	    (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne);
207    int		    (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne);
208    Bool	    (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne);
209    Bool	    (*Init) (KdPointerInfo *pi);
210    unsigned char   headerMask, headerValid;
211    unsigned char   dataMask, dataValid;
212    Bool	    tty;
213    unsigned int    c_iflag;
214    unsigned int    c_oflag;
215    unsigned int    c_lflag;
216    unsigned int    c_cflag;
217    unsigned int    speed;
218    unsigned char   *init;
219    unsigned long   state;
220} KmouseProt;
221
222typedef enum _kmouseStage {
223    MouseBroken, MouseTesting, MouseWorking
224} KmouseStage;
225
226typedef struct _kmouse {
227    Kbufio		iob;
228    const KmouseProt	*prot;
229    int			i_prot;
230    KmouseStage		stage;	/* protocol verification stage */
231    Bool		tty;	/* mouse device is a tty */
232    int			valid;	/* sequential valid events */
233    int			tested;	/* bytes scanned during Testing phase */
234    int			invalid;/* total invalid bytes for this protocol */
235    unsigned long	state;	/* private per protocol, init to prot->state */
236} Kmouse;
237
238static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne)
239{
240    Kmouse		*km = pi->driverPrivate;
241    const KmouseProt	*prot = km->prot;
242    int	    i;
243
244    for (i = 0; i < ne; i++)
245	if ((ev[i] & prot->headerMask) == prot->headerValid)
246	    break;
247    if (i != 0)
248	return i;
249    for (i = 1; i < ne; i++)
250	if ((ev[i] & prot->dataMask) != prot->dataValid)
251	    return -1;
252    return 0;
253}
254
255static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
256{
257    return ne == 3;
258}
259
260static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
261{
262    return ne == 4;
263}
264
265static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
266{
267    return ne == 5;
268}
269
270static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy)
271{
272    Kmouse		*km = pi->driverPrivate;
273
274    if (km->stage == MouseWorking)
275	return TRUE;
276    if (dx < -50 || dx > 50)
277    {
278#ifdef DEBUG
279	ErrorF ("Large X %d\n", dx);
280#endif
281	return FALSE;
282    }
283    if (dy < -50 || dy > 50)
284    {
285#ifdef DEBUG
286	ErrorF ("Large Y %d\n", dy);
287#endif
288	return FALSE;
289    }
290    return TRUE;
291}
292
293/*
294 * Standard PS/2 mouse protocol
295 */
296static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne)
297{
298    Kmouse	    *km = pi->driverPrivate;
299    int		    dx, dy, dz;
300    unsigned long   flags;
301    unsigned long   flagsrelease = 0;
302
303    flags = KD_MOUSE_DELTA;
304    if (ev[0] & 4)
305	flags |= KD_BUTTON_2;
306    if (ev[0] & 2)
307	flags |= KD_BUTTON_3;
308    if (ev[0] & 1)
309	flags |= KD_BUTTON_1;
310
311    if (ne > 3)
312    {
313	dz = (int) (signed char) ev[3];
314	if (dz < 0)
315	{
316	    flags |= KD_BUTTON_4;
317	    flagsrelease = KD_BUTTON_4;
318	}
319	else if (dz > 0)
320	{
321	    flags |= KD_BUTTON_5;
322	    flagsrelease = KD_BUTTON_5;
323	}
324    }
325
326    dx = ev[1];
327    if (ev[0] & 0x10)
328	dx -= 256;
329    dy = ev[2];
330    if (ev[0] & 0x20)
331	dy -= 256;
332    dy = -dy;
333    if (!MouseReasonable (pi, flags, dx, dy))
334	return FALSE;
335    if (km->stage == MouseWorking)
336    {
337	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
338	if (flagsrelease)
339	{
340	    flags &= ~flagsrelease;
341	    KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
342	}
343    }
344    return TRUE;
345}
346
347static Bool ps2Init (KdPointerInfo *pi);
348
349static const KmouseProt ps2Prot = {
350    "ps/2",
351    threeComplete, mouseValid, ps2Parse, ps2Init,
352    0x08, 0x08, 0x00, 0x00,
353    FALSE
354};
355
356static const KmouseProt imps2Prot = {
357    "imps/2",
358    fourComplete, mouseValid, ps2Parse, ps2Init,
359    0x08, 0x08, 0x00, 0x00,
360    FALSE
361};
362
363static const KmouseProt exps2Prot = {
364    "exps/2",
365    fourComplete, mouseValid, ps2Parse, ps2Init,
366    0x08, 0x08, 0x00, 0x00,
367    FALSE
368};
369
370/*
371 * Once the mouse is known to speak ps/2 protocol, go and find out
372 * what advanced capabilities it has and turn them on
373 */
374
375/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */
376
377/* aux device commands (sent to KBD_DATA_PORT) */
378#define PSMC_SET_SCALING11      0x00e6
379#define PSMC_SET_SCALING21      0x00e7
380#define PSMC_SET_RESOLUTION     0x00e8
381#define PSMC_SEND_DEV_STATUS    0x00e9
382#define PSMC_SET_STREAM_MODE    0x00ea
383#define PSMC_SEND_DEV_DATA      0x00eb
384#define PSMC_SET_REMOTE_MODE    0x00f0
385#define PSMC_SEND_DEV_ID        0x00f2
386#define PSMC_SET_SAMPLING_RATE  0x00f3
387#define PSMC_ENABLE_DEV         0x00f4
388#define PSMC_DISABLE_DEV        0x00f5
389#define PSMC_SET_DEFAULTS       0x00f6
390#define PSMC_RESET_DEV          0x00ff
391
392/* PSMC_SET_RESOLUTION argument */
393#define PSMD_RES_LOW            0       /* typically 25ppi */
394#define PSMD_RES_MEDIUM_LOW     1       /* typically 50ppi */
395#define PSMD_RES_MEDIUM_HIGH    2       /* typically 100ppi (default) */
396#define PSMD_RES_HIGH           3       /* typically 200ppi */
397#define PSMD_MAX_RESOLUTION     PSMD_RES_HIGH
398
399/* PSMC_SET_SAMPLING_RATE */
400#define PSMD_MAX_RATE           255     /* FIXME: not sure if it's possible */
401
402/* aux device ID */
403#define PSM_MOUSE_ID            0
404#define PSM_BALLPOINT_ID        2
405#define PSM_INTELLI_ID          3
406#define PSM_EXPLORER_ID         4
407#define PSM_4DMOUSE_ID          6
408#define PSM_4DPLUS_ID           8
409
410static unsigned char	ps2_init[] = {
411    PSMC_ENABLE_DEV,
412    0,
413};
414
415#define NINIT_PS2   1
416
417static unsigned char    wheel_3button_init[] = {
418    PSMC_SET_SAMPLING_RATE, 200,
419    PSMC_SET_SAMPLING_RATE, 100,
420    PSMC_SET_SAMPLING_RATE,  80,
421    PSMC_SEND_DEV_ID,
422    0,
423};
424
425#define NINIT_IMPS2 4
426
427static unsigned char    wheel_5button_init[] = {
428    PSMC_SET_SAMPLING_RATE, 200,
429    PSMC_SET_SAMPLING_RATE, 100,
430    PSMC_SET_SAMPLING_RATE,  80,
431    PSMC_SET_SAMPLING_RATE, 200,
432    PSMC_SET_SAMPLING_RATE, 200,
433    PSMC_SET_SAMPLING_RATE,  80,
434    PSMC_SEND_DEV_ID,
435    0
436};
437
438#define NINIT_EXPS2 7
439
440static unsigned char	intelli_init[] = {
441    PSMC_SET_SAMPLING_RATE, 200,
442    PSMC_SET_SAMPLING_RATE, 100,
443    PSMC_SET_SAMPLING_RATE,  80,
444    0
445};
446
447#define NINIT_INTELLI	3
448
449static int
450ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next)
451{
452    Kmouse  *km = pi->driverPrivate;
453    int	    c = -1;
454    int	    skipping;
455    Bool    waiting;
456
457    skipping = 0;
458    waiting = FALSE;
459    while (ninit || ret_next)
460    {
461	c = MouseReadByte (&km->iob, MOUSE_TIMEOUT);
462	if (c == -1)
463	    break;
464	/* look for ACK */
465	if (c == 0xfa)
466	{
467	    ninit--;
468	    if (ret_next)
469		waiting = TRUE;
470	}
471	/* look for packet start -- not the response */
472	else if ((c & 0x08) == 0x08)
473	    waiting = FALSE;
474	else if (waiting)
475	    break;
476    }
477    return c;
478}
479
480static Bool
481ps2Init (KdPointerInfo *pi)
482{
483    Kmouse	    *km = pi->driverPrivate;
484    int		    skipping;
485    Bool	    waiting;
486    int		    id;
487    unsigned char   *init;
488    int		    ninit;
489
490    /* Send Intellimouse initialization sequence */
491    MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100);
492    /*
493     * Send ID command
494     */
495    if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100))
496	return FALSE;
497    skipping = 0;
498    waiting = FALSE;
499    id = ps2SkipInit (pi, 0, TRUE);
500    switch (id) {
501    case 3:
502	init = wheel_3button_init;
503	ninit = NINIT_IMPS2;
504	km->prot = &imps2Prot;
505	break;
506    case 4:
507	init = wheel_5button_init;
508	ninit = NINIT_EXPS2;
509	km->prot = &exps2Prot;
510	break;
511    default:
512	init = ps2_init;
513	ninit = NINIT_PS2;
514	km->prot = &ps2Prot;
515	break;
516    }
517    if (init)
518	MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100);
519    /*
520     * Flush out the available data to eliminate responses to the
521     * initialization string.  Make sure any partial event is
522     * skipped
523     */
524    (void) ps2SkipInit (pi, ninit, FALSE);
525    return TRUE;
526}
527
528static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne)
529{
530    Kmouse	    *km = pi->driverPrivate;
531    int		    dx, dy;
532    unsigned long   flags;
533
534    flags = KD_MOUSE_DELTA;
535    dx = (signed char) ev[1];
536    dy = -(signed char) ev[2];
537    if ((ev[0] & 4) == 0)
538	flags |= KD_BUTTON_1;
539    if ((ev[0] & 2) == 0)
540	flags |= KD_BUTTON_2;
541    if ((ev[0] & 1) == 0)
542	flags |= KD_BUTTON_3;
543    if (!MouseReasonable (pi, flags, dx, dy))
544	return FALSE;
545    if (km->stage == MouseWorking)
546	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
547    return TRUE;
548}
549
550static const KmouseProt busProt = {
551    "bus",
552    threeComplete, mouseValid, busParse, 0,
553    0xf8, 0x00, 0x00, 0x00,
554    FALSE
555};
556
557/*
558 * Standard MS serial protocol, three bytes
559 */
560
561static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne)
562{
563    Kmouse	    *km = pi->driverPrivate;
564    int		    dx, dy;
565    unsigned long   flags;
566
567    flags = KD_MOUSE_DELTA;
568
569    if (ev[0] & 0x20)
570	flags |= KD_BUTTON_1;
571    if (ev[0] & 0x10)
572	flags |= KD_BUTTON_3;
573
574    dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
575    dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
576    if (!MouseReasonable (pi, flags, dx, dy))
577	return FALSE;
578    if (km->stage == MouseWorking)
579	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
580    return TRUE;
581}
582
583static const KmouseProt msProt = {
584    "ms",
585    threeComplete, mouseValid, msParse, 0,
586    0xc0, 0x40, 0xc0, 0x00,
587    TRUE,
588    IGNPAR,
589    0,
590    0,
591    CS7 | CSTOPB | CREAD | CLOCAL,
592    B1200,
593};
594
595/*
596 * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the
597 * first byte of a synchronized protocol stream and see if it's got
598 * any bits turned on that can't occur in that fourth byte
599 */
600static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne)
601{
602    Kmouse		*km = pi->driverPrivate;
603
604    if ((ev[0] & 0x40) == 0x40)
605	return ne == 3;
606    if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0)
607	return ne == 1;
608    return FALSE;
609}
610
611static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne)
612{
613    Kmouse		*km = pi->driverPrivate;
614    const KmouseProt	*prot = km->prot;
615    int	    i;
616
617    for (i = 0; i < ne; i++)
618    {
619	if ((ev[i] & 0x40) == 0x40)
620	    break;
621	if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0)
622	    break;
623    }
624    if (i != 0)
625	return i;
626    for (i = 1; i < ne; i++)
627	if ((ev[i] & prot->dataMask) != prot->dataValid)
628	    return -1;
629    return 0;
630}
631
632static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne)
633{
634    Kmouse	    *km = pi->driverPrivate;
635    int		    dx, dy;
636    unsigned long   flags;
637
638    flags = KD_MOUSE_DELTA;
639
640    if (ne == 3)
641    {
642	if (ev[0] & 0x20)
643	    flags |= KD_BUTTON_1;
644	if (ev[0] & 0x10)
645	    flags |= KD_BUTTON_3;
646
647	dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F));
648	dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F));
649	flags |= km->state & KD_BUTTON_2;
650    }
651    else
652    {
653	if (ev[0] & 0x20)
654	    flags |= KD_BUTTON_2;
655	dx = 0;
656	dy = 0;
657	flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3);
658    }
659
660    if (!MouseReasonable (pi, flags, dx, dy))
661	return FALSE;
662    if (km->stage == MouseWorking)
663	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
664    return TRUE;
665}
666
667static const KmouseProt logiProt = {
668    "logitech",
669    logiComplete, logiValid, logiParse, 0,
670    0xc0, 0x40, 0xc0, 0x00,
671    TRUE,
672    IGNPAR,
673    0,
674    0,
675    CS7 | CSTOPB | CREAD | CLOCAL,
676    B1200,
677};
678
679/*
680 * Mouse systems protocol, 5 bytes
681 */
682static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne)
683{
684    Kmouse	    *km = pi->driverPrivate;
685    int		    dx, dy;
686    unsigned long   flags;
687
688    flags = KD_MOUSE_DELTA;
689
690    if (!(ev[0] & 0x4))
691	flags |= KD_BUTTON_1;
692    if (!(ev[0] & 0x2))
693	flags |= KD_BUTTON_2;
694    if (!(ev[0] & 0x1))
695	flags |= KD_BUTTON_3;
696    dx =    (signed char)(ev[1]) + (signed char)(ev[3]);
697    dy = - ((signed char)(ev[2]) + (signed char)(ev[4]));
698
699    if (!MouseReasonable (pi, flags, dx, dy))
700	return FALSE;
701    if (km->stage == MouseWorking)
702	KdEnqueuePointerEvent (pi, flags, dx, dy, 0);
703    return TRUE;
704}
705
706static const KmouseProt mscProt = {
707    "msc",
708    fiveComplete, mouseValid, mscParse, 0,
709    0xf8, 0x80, 0x00, 0x00,
710    TRUE,
711    IGNPAR,
712    0,
713    0,
714    CS8 | CSTOPB | CREAD | CLOCAL,
715    B1200,
716};
717
718/*
719 * Use logitech before ms -- they're the same except that
720 * logitech sometimes has a fourth byte
721 */
722static const KmouseProt *kmouseProts[] = {
723    &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt,
724};
725
726#define NUM_PROT    (sizeof (kmouseProts) / sizeof (kmouseProts[0]))
727
728static void
729MouseInitProtocol (Kmouse *km)
730{
731    int		    ret;
732    struct termios  t;
733
734    if (km->prot->tty)
735    {
736	ret = tcgetattr (km->iob.fd, &t);
737
738	if (ret >= 0)
739	{
740	    t.c_iflag = km->prot->c_iflag;
741	    t.c_oflag = km->prot->c_oflag;
742	    t.c_lflag = km->prot->c_lflag;
743	    t.c_cflag = km->prot->c_cflag;
744	    cfsetispeed (&t, km->prot->speed);
745	    cfsetospeed (&t, km->prot->speed);
746	    ret = tcsetattr (km->iob.fd, TCSANOW, &t);
747	}
748    }
749    km->stage = MouseBroken;
750    km->valid = 0;
751    km->tested = 0;
752    km->invalid = 0;
753    km->state = km->prot->state;
754}
755
756static void
757MouseFirstProtocol (Kmouse *km, char *prot)
758{
759    if (prot)
760    {
761	for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++)
762	    if (!strcmp (prot, kmouseProts[km->i_prot]->name))
763		break;
764	if (km->i_prot == NUM_PROT)
765	{
766	    int	i;
767	    ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot);
768	    for (i = 0; i < NUM_PROT; i++)
769		ErrorF (" %s", kmouseProts[i]->name);
770	    ErrorF ("\n");
771	}
772	else
773	{
774	    km->prot = kmouseProts[km->i_prot];
775	    if (km->tty && !km->prot->tty)
776		ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n",
777			prot);
778	    else if (!km->tty && km->prot->tty)
779		ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n",
780			prot);
781	}
782    }
783    if (!km->prot)
784    {
785	for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++)
786	    ;
787	km->prot = kmouseProts[km->i_prot];
788    }
789    MouseInitProtocol (km);
790}
791
792static void
793MouseNextProtocol (Kmouse *km)
794{
795    do
796    {
797	if (!km->prot)
798	    km->i_prot = 0;
799	else
800	    if (++km->i_prot == NUM_PROT) km->i_prot = 0;
801	km->prot = kmouseProts[km->i_prot];
802    } while (km->prot->tty != km->tty);
803    MouseInitProtocol (km);
804    ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name);
805}
806
807static void
808MouseRead (int mousePort, void *closure)
809{
810    KdPointerInfo   *pi = closure;
811    Kmouse	    *km = pi->driverPrivate;
812    unsigned char   event[MAX_MOUSE];
813    int		    ne;
814    int		    c;
815    int		    i;
816    int		    timeout;
817
818    timeout = 0;
819    ne = 0;
820    for(;;)
821    {
822	c = MouseReadByte (&km->iob, timeout);
823	if (c == -1)
824	{
825	    if (ne)
826	    {
827		km->invalid += ne + km->tested;
828		km->valid = 0;
829		km->tested = 0;
830		km->stage = MouseBroken;
831	    }
832	    break;
833	}
834	event[ne++] = c;
835	i = (*km->prot->Valid) (pi, event, ne);
836	if (i != 0)
837	{
838#ifdef DEBUG
839	    ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n",
840		    km->prot->name, i > 0 ? i : ne, ne);
841#endif
842	    if (i > 0 && i < ne)
843	    {
844		ne -= i;
845		memmove (event, event + i, ne);
846	    }
847	    else
848	    {
849		i = ne;
850		ne = 0;
851	    }
852	    km->invalid += i + km->tested;
853	    km->valid = 0;
854	    km->tested = 0;
855	    if (km->stage == MouseWorking)
856		km->i_prot--;
857	    km->stage = MouseBroken;
858	    if (km->invalid > MAX_SKIP)
859	    {
860		MouseNextProtocol (km);
861		ne = 0;
862	    }
863	    timeout = 0;
864	}
865	else
866	{
867	    if ((*km->prot->Complete) (pi, event, ne))
868	    {
869		if ((*km->prot->Parse) (pi, event, ne))
870		{
871		    switch (km->stage)
872		    {
873		    case MouseBroken:
874#ifdef DEBUG
875			ErrorF ("Mouse protocol %s seems OK\n",
876				km->prot->name);
877#endif
878			/* do not zero invalid to accumulate invalid bytes */
879			km->valid = 0;
880			km->tested = 0;
881			km->stage = MouseTesting;
882			/* fall through ... */
883		    case MouseTesting:
884			km->valid++;
885			km->tested += ne;
886			if (km->valid > MAX_VALID)
887			{
888#ifdef DEBUG
889			    ErrorF ("Mouse protocol %s working\n",
890				    km->prot->name);
891#endif
892			    km->stage = MouseWorking;
893			    km->invalid = 0;
894			    km->tested = 0;
895			    km->valid = 0;
896			    if (km->prot->Init && !(*km->prot->Init) (pi))
897				km->stage = MouseBroken;
898			}
899			break;
900		    case MouseWorking:
901			break;
902		    }
903		}
904		else
905		{
906		    km->invalid += ne + km->tested;
907		    km->valid = 0;
908		    km->tested = 0;
909		    km->stage = MouseBroken;
910		}
911		ne = 0;
912		timeout = 0;
913	    }
914	    else
915		timeout = MOUSE_TIMEOUT;
916	}
917    }
918}
919
920int MouseInputType;
921
922char *kdefaultMouse[] =  {
923    "/dev/input/mice",
924    "/dev/mouse",
925    "/dev/psaux",
926    "/dev/adbmouse",
927    "/dev/ttyS0",
928    "/dev/ttyS1",
929};
930
931#define NUM_DEFAULT_MOUSE    (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))
932
933static Status
934MouseInit (KdPointerInfo *pi)
935{
936    int		i;
937    int		fd;
938    Kmouse	*km;
939
940    if (!pi)
941        return BadImplementation;
942
943    if (!pi->path || strcmp(pi->path, "auto") == 0) {
944        for (i = 0; i < NUM_DEFAULT_MOUSE; i++) {
945            fd = open (kdefaultMouse[i], 2);
946            if (fd >= 0) {
947                pi->path = strdup (kdefaultMouse[i]);
948                break;
949            }
950        }
951    }
952    else {
953        fd = open (pi->path, 2);
954    }
955
956    if (fd < 0)
957        return BadMatch;
958
959    close(fd);
960
961    km = (Kmouse *) malloc(sizeof (Kmouse));
962    if (km) {
963        km->iob.avail = km->iob.used = 0;
964        MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2");
965        /* MouseFirstProtocol sets state to MouseBroken for later protocol
966         * checks. Skip these checks if a protocol was supplied */
967        if (pi->protocol)
968                km->state = MouseWorking;
969        km->i_prot = 0;
970        km->tty = isatty (fd);
971        km->iob.fd = -1;
972        pi->driverPrivate = km;
973    }
974    else {
975        close (fd);
976        return BadAlloc;
977    }
978
979    return Success;
980}
981
982static Status
983MouseEnable (KdPointerInfo *pi)
984{
985    Kmouse *km;
986
987    if (!pi || !pi->driverPrivate || !pi->path)
988        return BadImplementation;
989
990    km = pi->driverPrivate;
991
992    km->iob.fd = open(pi->path, 2);
993    if (km->iob.fd < 0)
994        return BadMatch;
995
996    if (!KdRegisterFd (km->iob.fd, MouseRead, pi))
997    {
998        close(km->iob.fd);
999        return BadAlloc;
1000    }
1001
1002    return Success;
1003}
1004
1005static void
1006MouseDisable (KdPointerInfo *pi)
1007{
1008    Kmouse *km;
1009    if (!pi || !pi->driverPrivate)
1010        return;
1011
1012    km = pi->driverPrivate;
1013    KdUnregisterFd (pi, km->iob.fd, TRUE);
1014}
1015
1016static void
1017MouseFini (KdPointerInfo *pi)
1018{
1019    free(pi->driverPrivate);
1020    pi->driverPrivate = NULL;
1021}
1022
1023KdPointerDriver LinuxMouseDriver = {
1024    "mouse",
1025    MouseInit,
1026    MouseEnable,
1027    MouseDisable,
1028    MouseFini,
1029    NULL,
1030};
1031