2 * Copyright © 2001 Keith Packard
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.
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.
24 #include <kdrive-config.h>
29 #include <X11/Xproto.h>
30 #include <X11/Xpoll.h>
32 #include "scrnintstr.h"
37 #define KBUFIO_SIZE 256
38 #define MOUSE_TIMEOUT 100
40 typedef struct _kbufio
{
42 unsigned char buf
[KBUFIO_SIZE
];
48 MouseWaitForReadable(int fd
, int timeout
)
51 struct timeval tv
, *tp
;
55 done
= GetTimeInMillis() + timeout
;
62 tv
.tv_sec
= timeout
/ 1000;
63 tv
.tv_usec
= (timeout
% 1000) * 1000;
66 n
= select(fd
+ 1, &set
, 0, 0, tp
);
69 if (n
< 0 && (errno
== EAGAIN
|| errno
== EINTR
)) {
70 timeout
= (int) (done
- GetTimeInMillis());
80 MouseReadByte(Kbufio
* b
, int timeout
)
84 if (b
->avail
<= b
->used
) {
85 if (timeout
&& !MouseWaitForReadable(b
->fd
, timeout
)) {
87 ErrorF("\tTimeout %d\n", timeout
);
91 n
= read(b
->fd
, b
->buf
, KBUFIO_SIZE
);
98 ErrorF("\tget %02x\n", b
->buf
[b
->used
]);
100 return b
->buf
[b
->used
++];
105 MouseFlush(Kbufio
* b
, char *buf
, int size
)
107 CARD32 now
= GetTimeInMillis();
108 CARD32 done
= now
+ 100;
112 while ((c
= MouseReadByte(b
, done
- now
)) != -1) {
115 memmove(buf
, buf
+ 1, size
- 1);
120 now
= GetTimeInMillis();
121 if ((INT32
) (now
- done
) >= 0)
128 MousePeekByte(Kbufio
* b
, int timeout
)
132 c
= MouseReadByte(b
, timeout
);
140 MouseWaitForWritable(int fd
, int timeout
)
143 struct timeval tv
, *tp
;
151 tv
.tv_sec
= timeout
/ 1000;
152 tv
.tv_usec
= (timeout
% 1000) * 1000;
155 n
= select(fd
+ 1, 0, &set
, 0, tp
);
162 MouseWriteByte(int fd
, unsigned char c
, int timeout
)
167 ErrorF("\tput %02x\n", c
);
170 ret
= write(fd
, &c
, 1);
175 if (errno
!= EWOULDBLOCK
)
177 if (!MouseWaitForWritable(fd
, timeout
))
183 MouseWriteBytes(int fd
, unsigned char *c
, int n
, int timeout
)
186 if (!MouseWriteByte(fd
, *c
++, timeout
))
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 */
195 typedef struct _kmouseProt
{
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
;
204 unsigned int c_iflag
;
205 unsigned int c_oflag
;
206 unsigned int c_lflag
;
207 unsigned int c_cflag
;
213 typedef enum _kmouseStage
{
214 MouseBroken
, MouseTesting
, MouseWorking
217 typedef struct _kmouse
{
219 const KmouseProt
*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 */
230 mouseValid(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
232 Kmouse
*km
= pi
->driverPrivate
;
233 const KmouseProt
*prot
= km
->prot
;
236 for (i
= 0; i
< ne
; i
++)
237 if ((ev
[i
] & prot
->headerMask
) == prot
->headerValid
)
241 for (i
= 1; i
< ne
; i
++)
242 if ((ev
[i
] & prot
->dataMask
) != prot
->dataValid
)
248 threeComplete(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
254 fourComplete(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
260 fiveComplete(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
266 MouseReasonable(KdPointerInfo
* pi
, unsigned long flags
, int dx
, int dy
)
268 Kmouse
*km
= pi
->driverPrivate
;
270 if (km
->stage
== MouseWorking
)
272 if (dx
< -50 || dx
> 50) {
274 ErrorF("Large X %d\n", dx
);
278 if (dy
< -50 || dy
> 50) {
280 ErrorF("Large Y %d\n", dy
);
288 * Standard PS/2 mouse protocol
291 ps2Parse(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
293 Kmouse
*km
= pi
->driverPrivate
;
296 unsigned long flagsrelease
= 0;
298 flags
= KD_MOUSE_DELTA
;
300 flags
|= KD_BUTTON_2
;
302 flags
|= KD_BUTTON_3
;
304 flags
|= KD_BUTTON_1
;
307 dz
= (int) (signed char) ev
[3];
309 flags
|= KD_BUTTON_4
;
310 flagsrelease
= KD_BUTTON_4
;
313 flags
|= KD_BUTTON_5
;
314 flagsrelease
= KD_BUTTON_5
;
325 if (!MouseReasonable(pi
, flags
, dx
, dy
))
327 if (km
->stage
== MouseWorking
) {
328 KdEnqueuePointerEvent(pi
, flags
, dx
, dy
, 0);
330 flags
&= ~flagsrelease
;
331 KdEnqueuePointerEvent(pi
, flags
, dx
, dy
, 0);
337 static Bool
ps2Init(KdPointerInfo
* pi
);
339 static const KmouseProt ps2Prot
= {
341 threeComplete
, mouseValid
, ps2Parse
, ps2Init
,
342 0x08, 0x08, 0x00, 0x00,
346 static const KmouseProt imps2Prot
= {
348 fourComplete
, mouseValid
, ps2Parse
, ps2Init
,
349 0x08, 0x08, 0x00, 0x00,
353 static const KmouseProt exps2Prot
= {
355 fourComplete
, mouseValid
, ps2Parse
, ps2Init
,
356 0x08, 0x08, 0x00, 0x00,
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
365 /* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */
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
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
389 /* PSMC_SET_SAMPLING_RATE */
390 #define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */
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
400 static unsigned char ps2_init
[] = {
407 static unsigned char wheel_3button_init
[] = {
408 PSMC_SET_SAMPLING_RATE
, 200,
409 PSMC_SET_SAMPLING_RATE
, 100,
410 PSMC_SET_SAMPLING_RATE
, 80,
415 #define NINIT_IMPS2 4
417 static 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,
428 #define NINIT_EXPS2 7
430 static unsigned char intelli_init
[] = {
431 PSMC_SET_SAMPLING_RATE
, 200,
432 PSMC_SET_SAMPLING_RATE
, 100,
433 PSMC_SET_SAMPLING_RATE
, 80,
437 #define NINIT_INTELLI 3
440 ps2SkipInit(KdPointerInfo
* pi
, int ninit
, Bool ret_next
)
442 Kmouse
*km
= pi
->driverPrivate
;
447 while (ninit
|| ret_next
) {
448 c
= MouseReadByte(&km
->iob
, MOUSE_TIMEOUT
);
457 /* look for packet start -- not the response */
458 else if ((c
& 0x08) == 0x08)
467 ps2Init(KdPointerInfo
* pi
)
469 Kmouse
*km
= pi
->driverPrivate
;
474 /* Send Intellimouse initialization sequence */
475 MouseWriteBytes(km
->iob
.fd
, intelli_init
, strlen((char *) intelli_init
),
480 if (!MouseWriteByte(km
->iob
.fd
, PSMC_SEND_DEV_ID
, 100))
482 id
= ps2SkipInit(pi
, 0, TRUE
);
485 init
= wheel_3button_init
;
487 km
->prot
= &imps2Prot
;
490 init
= wheel_5button_init
;
492 km
->prot
= &exps2Prot
;
501 MouseWriteBytes(km
->iob
.fd
, init
, strlen((char *) init
), 100);
503 * Flush out the available data to eliminate responses to the
504 * initialization string. Make sure any partial event is
507 (void) ps2SkipInit(pi
, ninit
, FALSE
);
512 busParse(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
514 Kmouse
*km
= pi
->driverPrivate
;
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
))
529 if (km
->stage
== MouseWorking
)
530 KdEnqueuePointerEvent(pi
, flags
, dx
, dy
, 0);
534 static const KmouseProt busProt
= {
536 threeComplete
, mouseValid
, busParse
, 0,
537 0xf8, 0x00, 0x00, 0x00,
542 * Standard MS serial protocol, three bytes
546 msParse(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
548 Kmouse
*km
= pi
->driverPrivate
;
552 flags
= KD_MOUSE_DELTA
;
555 flags
|= KD_BUTTON_1
;
557 flags
|= KD_BUTTON_3
;
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
))
563 if (km
->stage
== MouseWorking
)
564 KdEnqueuePointerEvent(pi
, flags
, dx
, dy
, 0);
568 static const KmouseProt msProt
= {
570 threeComplete
, mouseValid
, msParse
, 0,
571 0xc0, 0x40, 0xc0, 0x00,
576 CS7
| CSTOPB
| CREAD
| CLOCAL
,
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
586 logiComplete(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
588 Kmouse
*km
= pi
->driverPrivate
;
590 if ((ev
[0] & 0x40) == 0x40)
592 if (km
->stage
!= MouseBroken
&& (ev
[0] & ~0x23) == 0)
598 logiValid(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
600 Kmouse
*km
= pi
->driverPrivate
;
601 const KmouseProt
*prot
= km
->prot
;
604 for (i
= 0; i
< ne
; i
++) {
605 if ((ev
[i
] & 0x40) == 0x40)
607 if (km
->stage
!= MouseBroken
&& (ev
[i
] & ~0x23) == 0)
612 for (i
= 1; i
< ne
; i
++)
613 if ((ev
[i
] & prot
->dataMask
) != prot
->dataValid
)
619 logiParse(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
621 Kmouse
*km
= pi
->driverPrivate
;
625 flags
= KD_MOUSE_DELTA
;
629 flags
|= KD_BUTTON_1
;
631 flags
|= KD_BUTTON_3
;
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
;
639 flags
|= KD_BUTTON_2
;
642 flags
|= km
->state
& (KD_BUTTON_1
| KD_BUTTON_3
);
645 if (!MouseReasonable(pi
, flags
, dx
, dy
))
647 if (km
->stage
== MouseWorking
)
648 KdEnqueuePointerEvent(pi
, flags
, dx
, dy
, 0);
652 static const KmouseProt logiProt
= {
654 logiComplete
, logiValid
, logiParse
, 0,
655 0xc0, 0x40, 0xc0, 0x00,
660 CS7
| CSTOPB
| CREAD
| CLOCAL
,
665 * Mouse systems protocol, 5 bytes
668 mscParse(KdPointerInfo
* pi
, unsigned char *ev
, int ne
)
670 Kmouse
*km
= pi
->driverPrivate
;
674 flags
= KD_MOUSE_DELTA
;
677 flags
|= KD_BUTTON_1
;
679 flags
|= KD_BUTTON_2
;
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]));
685 if (!MouseReasonable(pi
, flags
, dx
, dy
))
687 if (km
->stage
== MouseWorking
)
688 KdEnqueuePointerEvent(pi
, flags
, dx
, dy
, 0);
692 static const KmouseProt mscProt
= {
694 fiveComplete
, mouseValid
, mscParse
, 0,
695 0xf8, 0x80, 0x00, 0x00,
700 CS8
| CSTOPB
| CREAD
| CLOCAL
,
705 * Use logitech before ms -- they're the same except that
706 * logitech sometimes has a fourth byte
708 static const KmouseProt
*kmouseProts
[] = {
709 &ps2Prot
, &imps2Prot
, &exps2Prot
, &busProt
, &logiProt
, &msProt
, &mscProt
,
712 #define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0]))
715 MouseInitProtocol(Kmouse
* km
)
721 ret
= tcgetattr(km
->iob
.fd
, &t
);
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
);
733 km
->stage
= MouseBroken
;
737 km
->state
= km
->prot
->state
;
741 MouseFirstProtocol(Kmouse
* km
, const char *prot
)
744 for (km
->i_prot
= 0; km
->i_prot
< NUM_PROT
; km
->i_prot
++)
745 if (!strcmp(prot
, kmouseProts
[km
->i_prot
]->name
))
747 if (km
->i_prot
== NUM_PROT
) {
750 ErrorF("Unknown mouse protocol \"%s\". Pick one of:", prot
);
751 for (i
= 0; i
< NUM_PROT
; i
++)
752 ErrorF(" %s", kmouseProts
[i
]->name
);
756 km
->prot
= kmouseProts
[km
->i_prot
];
757 if (km
->tty
&& !km
->prot
->tty
)
759 ("Mouse device is serial port, protocol %s is not serial protocol\n",
761 else if (!km
->tty
&& km
->prot
->tty
)
763 ("Mouse device is not serial port, protocol %s is serial protocol\n",
768 for (km
->i_prot
= 0; kmouseProts
[km
->i_prot
]->tty
!= km
->tty
;
770 km
->prot
= kmouseProts
[km
->i_prot
];
772 MouseInitProtocol(km
);
776 MouseNextProtocol(Kmouse
* km
)
781 else if (++km
->i_prot
== NUM_PROT
)
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
);
790 MouseRead(int mousePort
, void *closure
)
792 KdPointerInfo
*pi
= closure
;
793 Kmouse
*km
= pi
->driverPrivate
;
794 unsigned char event
[MAX_MOUSE
];
803 c
= MouseReadByte(&km
->iob
, timeout
);
806 km
->invalid
+= ne
+ km
->tested
;
809 km
->stage
= MouseBroken
;
814 i
= (*km
->prot
->Valid
) (pi
, event
, ne
);
817 ErrorF("Mouse protocol %s broken %d of %d bytes bad\n",
818 km
->prot
->name
, i
> 0 ? i
: ne
, ne
);
820 if (i
> 0 && i
< ne
) {
822 memmove(event
, event
+ i
, ne
);
828 km
->invalid
+= i
+ km
->tested
;
831 if (km
->stage
== MouseWorking
)
833 km
->stage
= MouseBroken
;
834 if (km
->invalid
> MAX_SKIP
) {
835 MouseNextProtocol(km
);
841 if ((*km
->prot
->Complete
) (pi
, event
, ne
)) {
842 if ((*km
->prot
->Parse
) (pi
, event
, ne
)) {
846 ErrorF("Mouse protocol %s seems OK\n", km
->prot
->name
);
848 /* do not zero invalid to accumulate invalid bytes */
851 km
->stage
= MouseTesting
;
852 /* fall through ... */
856 if (km
->valid
> MAX_VALID
) {
858 ErrorF("Mouse protocol %s working\n",
861 km
->stage
= MouseWorking
;
865 if (km
->prot
->Init
&& !(*km
->prot
->Init
) (pi
))
866 km
->stage
= MouseBroken
;
874 km
->invalid
+= ne
+ km
->tested
;
877 km
->stage
= MouseBroken
;
883 timeout
= MOUSE_TIMEOUT
;
890 const char *kdefaultMouse
[] = {
899 #define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))
902 MouseInit(KdPointerInfo
* pi
)
909 return BadImplementation
;
911 if (!pi
->path
|| strcmp(pi
->path
, "auto") == 0) {
912 for (i
= 0; i
< NUM_DEFAULT_MOUSE
; i
++) {
913 fd
= open(kdefaultMouse
[i
], 2);
915 pi
->path
= strdup(kdefaultMouse
[i
]);
921 fd
= open(pi
->path
, 2);
929 km
= (Kmouse
*) malloc(sizeof(Kmouse
));
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 */
936 km
->state
= MouseWorking
;
938 km
->tty
= isatty(fd
);
940 pi
->driverPrivate
= km
;
951 MouseEnable(KdPointerInfo
* pi
)
955 if (!pi
|| !pi
->driverPrivate
|| !pi
->path
)
956 return BadImplementation
;
958 km
= pi
->driverPrivate
;
960 km
->iob
.fd
= open(pi
->path
, 2);
964 if (!KdRegisterFd(km
->iob
.fd
, MouseRead
, pi
)) {
973 MouseDisable(KdPointerInfo
* pi
)
977 if (!pi
|| !pi
->driverPrivate
)
980 km
= pi
->driverPrivate
;
981 KdUnregisterFd(pi
, km
->iob
.fd
, TRUE
);
985 MouseFini(KdPointerInfo
* pi
)
987 free(pi
->driverPrivate
);
988 pi
->driverPrivate
= NULL
;
991 KdPointerDriver LinuxMouseDriver
= {