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