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