1/* 2 * Copyright 1998 by Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 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 Kazutaka YOKOTA not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Kazutaka YOKOTA makes no representations 11 * about the suitability of this software for any purpose. It is provided 12 * "as is" without express or implied warranty. 13 * 14 * KAZUTAKA YOKOTA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL KAZUTAKA YOKOTA 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 "config.h" 25#endif 26 27#include <xorg-server.h> 28#include <stdio.h> 29#include <string.h> 30#include <unistd.h> 31#include <X11/X.h> 32#include <X11/Xproto.h> 33#include "inputstr.h" 34#include "scrnintstr.h" 35#include "xf86.h" 36#include "xf86Priv.h" 37#include "xf86Xinput.h" 38#include "xf86_OSproc.h" 39#include "mouse.h" 40#include "mousePriv.h" 41 42#ifdef MOUSEINITDEBUG 43# define DEBUG 44# define EXTMOUSEDEBUG 45#endif 46 47/* serial PnP ID string */ 48typedef struct { 49 int revision; /* PnP revision, 100 for 1.00 */ 50 char *eisaid; /* EISA ID including mfr ID and product ID */ 51 char *serial; /* serial No, optional */ 52 char *class; /* device class, optional */ 53 char *compat; /* list of compatible drivers, optional */ 54 char *description; /* product description, optional */ 55 int neisaid; /* length of the above fields... */ 56 int nserial; 57 int nclass; 58 int ncompat; 59 int ndescription; 60} pnpid_t; 61 62/* symbol table entry */ 63typedef struct { 64 const char *name; 65 MouseProtocolID val; 66} symtab_t; 67 68/* PnP EISA/product IDs */ 69static symtab_t pnpprod[] = { 70 { "KML0001", PROT_THINKING }, /* Kensington ThinkingMouse */ 71 { "MSH0001", PROT_IMSERIAL }, /* MS IntelliMouse */ 72 { "MSH0004", PROT_IMSERIAL }, /* MS IntelliMouse TrackBall */ 73 { "KYEEZ00", PROT_MS }, /* Genius EZScroll */ 74 { "KYE0001", PROT_MS }, /* Genius PnP Mouse */ 75 { "KYE0002", PROT_MS }, /* MouseSystem (Genius?) SmartScroll */ 76 { "KYE0003", PROT_IMSERIAL }, /* Genius NetMouse */ 77 { "KYE0004", PROT_IMSERIAL }, /* Genius NetScroll+ (serial) */ 78 { "LGI800C", PROT_IMSERIAL }, /* Logitech MouseMan (4 button model) */ 79 { "LGI8033", PROT_IMSERIAL }, /* Logitech Cordless MouseMan Wheel */ 80 { "LGI8050", PROT_IMSERIAL }, /* Logitech MouseMan+ */ 81 { "LGI8051", PROT_IMSERIAL }, /* Logitech FirstMouse+ */ 82 { "LGI8001", PROT_LOGIMAN }, /* Logitech serial */ 83 { "A4W0005", PROT_IMSERIAL }, /* A4 Tech 4D/4D+ Mouse */ 84 { "PEC9802", PROT_IMSERIAL }, /* 8D Scroll Mouse */ 85 86 { "PNP0F00", PROT_BM }, /* MS bus */ 87 { "PNP0F01", PROT_MS }, /* MS serial */ 88 { "PNP0F02", PROT_BM }, /* MS InPort */ 89 { "PNP0F03", PROT_PS2 }, /* MS PS/2 */ 90 /* 91 * EzScroll returns PNP0F04 in the compatible device field; but it 92 * doesn't look compatible... XXX 93 */ 94 { "PNP0F04", PROT_MSC }, /* MouseSystems */ 95 { "PNP0F05", PROT_MSC }, /* MouseSystems */ 96#ifdef notyet 97 { "PNP0F06", PROT_??? }, /* Genius Mouse */ 98 { "PNP0F07", PROT_??? }, /* Genius Mouse */ 99#endif 100 { "PNP0F08", PROT_LOGIMAN }, /* Logitech serial */ 101 { "PNP0F09", PROT_MS }, /* MS BallPoint serial */ 102 { "PNP0F0A", PROT_MS }, /* MS PnP serial */ 103 { "PNP0F0B", PROT_MS }, /* MS PnP BallPoint serial */ 104 { "PNP0F0C", PROT_MS }, /* MS serial compatible */ 105 { "PNP0F0D", PROT_BM }, /* MS InPort compatible */ 106 { "PNP0F0E", PROT_PS2 }, /* MS PS/2 compatible */ 107 { "PNP0F0F", PROT_MS }, /* MS BallPoint compatible */ 108#ifdef notyet 109 { "PNP0F10", PROT_??? }, /* TI QuickPort */ 110#endif 111 { "PNP0F11", PROT_BM }, /* MS bus compatible */ 112 { "PNP0F12", PROT_PS2 }, /* Logitech PS/2 */ 113 { "PNP0F13", PROT_PS2 }, /* PS/2 */ 114#ifdef notyet 115 { "PNP0F14", PROT_??? }, /* MS Kids Mouse */ 116#endif 117 { "PNP0F15", PROT_BM }, /* Logitech bus */ 118#ifdef notyet 119 { "PNP0F16", PROT_??? }, /* Logitech SWIFT */ 120#endif 121 { "PNP0F17", PROT_LOGIMAN }, /* Logitech serial compat */ 122 { "PNP0F18", PROT_BM }, /* Logitech bus compatible */ 123 { "PNP0F19", PROT_PS2 }, /* Logitech PS/2 compatible */ 124#ifdef notyet 125 { "PNP0F1A", PROT_??? }, /* Logitech SWIFT compatible */ 126 { "PNP0F1B", PROT_??? }, /* HP Omnibook */ 127 { "PNP0F1C", PROT_??? }, /* Compaq LTE TrackBall PS/2 */ 128 { "PNP0F1D", PROT_??? }, /* Compaq LTE TrackBall serial */ 129 { "PNP0F1E", PROT_??? }, /* MS Kids Trackball */ 130#endif 131 { NULL, PROT_UNKNOWN }, 132}; 133 134static const char *pnpSerial[] = { 135 "BaudRate", "1200", 136 "DataBits", "7", 137 "StopBits", "1", 138 "Parity", "None", 139 "FlowControl", "None", 140 "VTime", "0", 141 "VMin", "1", 142 NULL 143}; 144 145static int pnpgets(InputInfoPtr, char *, Bool *prePNP); 146static int pnpparse(InputInfoPtr, pnpid_t *, char *, int); 147static MouseProtocolID prepnpparse(InputInfoPtr pInfo, char *buf); 148static symtab_t *pnpproto(pnpid_t *); 149static symtab_t *gettoken(symtab_t *, char *, int); 150static MouseProtocolID getPs2ProtocolPnP(InputInfoPtr pInfo); 151static MouseProtocolID probePs2ProtocolPnP(InputInfoPtr pInfo); 152 153static MouseProtocolID 154MouseGetSerialPnpProtocol(InputInfoPtr pInfo) 155{ 156 char buf[256]; /* PnP ID string may be up to 256 bytes long */ 157 pnpid_t pnpid; 158 symtab_t *t; 159 int len; 160 Bool prePNP; 161 162 if ((len = pnpgets(pInfo, buf, &prePNP)) > 0) 163 { 164 if (!prePNP) { 165 if (pnpparse(pInfo, &pnpid, buf, len) && 166 (t = pnpproto(&pnpid)) != NULL) { 167 xf86MsgVerb(X_INFO, 2, "%s: PnP-detected protocol ID: %d\n", 168 pInfo->name, t->val); 169 return (t->val); 170 } 171 } else 172 return prepnpparse(pInfo,buf); 173 } 174 return PROT_UNKNOWN; 175} 176 177MouseProtocolID 178MouseGetPnpProtocol(InputInfoPtr pInfo) 179{ 180 MouseDevPtr pMse = pInfo->private; 181 mousePrivPtr mPriv = (mousePrivPtr)pMse->mousePriv; 182 MouseProtocolID val; 183 CARD32 last; 184 185 if ((val = MouseGetSerialPnpProtocol(pInfo)) != PROT_UNKNOWN) { 186 if (val == MouseGetSerialPnpProtocol(pInfo)) 187 return val; 188 } 189 190 last = mPriv->pnpLast; 191 mPriv->pnpLast = currentTime.milliseconds; 192 193 if (last) { 194 if (last - currentTime.milliseconds < 100 195 || (mPriv->disablePnPauto 196 && (last - currentTime.milliseconds < 10000))) { 197#ifdef EXTMOUSEDEBUG 198 xf86ErrorF("Mouse: Disabling PnP\n"); 199#endif 200 mPriv->disablePnPauto = TRUE; 201 return PROT_UNKNOWN; 202 } 203 } 204 205#ifdef EXTMOUSEDEBUG 206 if (mPriv->disablePnPauto) 207 xf86ErrorF("Mouse: Enabling PnP\n"); 208#endif 209 mPriv->disablePnPauto = FALSE; 210 211 if (mPriv->soft) 212 return getPs2ProtocolPnP(pInfo); 213 else 214 return probePs2ProtocolPnP(pInfo); 215} 216 217/* 218 * Try to elicit a PnP ID as described in 219 * Microsoft, Hayes: "Plug and Play External COM Device Specification, 220 * rev 1.00", 1995. 221 * 222 * The routine does not fully implement the COM Enumerator as per Section 223 * 2.1 of the document. In particular, we don't have idle state in which 224 * the driver software monitors the com port for dynamic connection or 225 * removal of a device at the port, because `moused' simply quits if no 226 * device is found. 227 * 228 * In addition, as PnP COM device enumeration procedure slightly has 229 * changed since its first publication, devices which follow earlier 230 * revisions of the above spec. may fail to respond if the rev 1.0 231 * procedure is used. XXX 232 */ 233static int 234pnpgets(InputInfoPtr pInfo, char *buf, Bool *prePNP) 235{ 236 int i; 237 char c; 238 pointer pnpOpts; 239 240#if 0 241 /* 242 * This is the procedure described in rev 1.0 of PnP COM device spec. 243 * Unfortunately, some devices which conform to earlier revisions of 244 * the spec gets confused and do not return the ID string... 245 */ 246 247 /* port initialization (2.1.2) */ 248 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1) 249 return 0; 250 i |= XF86_M_DTR; /* DTR = 1 */ 251 i &= ~XF86_M_RTS; /* RTS = 0 */ 252 if (xf86SetSerialModemState(pInfo->fd, i) == -1) 253 goto disconnect_idle; 254 usleep(200000); 255 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1 || 256 (i & XF86_M_DSR) == 0) 257 goto disconnect_idle; 258 259 /* port setup, 1st phase (2.1.3) */ 260 pnpOpts = xf86OptionListCreate(pnpSerial, -1, 1); 261 xf86SetSerial(pInfo->fd, pnpOpts); 262 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 263 xf86SerialModemClearBits(pInfo->fd, i); 264 usleep(200000); 265 i = TIOCM_DTR; /* DTR = 1, RTS = 0 */ 266 xf86SerialModemSetBits(pInfo->fd, i); 267 usleep(200000); 268 269 /* wait for response, 1st phase (2.1.4) */ 270 xf86FlushInput(pInfo->fd); 271 i = TIOCM_RTS; /* DTR = 1, RTS = 1 */ 272 xf86SerialModemSetBits(pInfo->fd, i); 273 274 /* try to read something */ 275 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) { 276 277 /* port setup, 2nd phase (2.1.5) */ 278 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 279 xf86SerialModemClearBits(pInfo->fd, i); 280 usleep(200000); 281 282 /* wait for response, 2nd phase (2.1.6) */ 283 xf86FlushInput(pInfo->fd); 284 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 285 xf86SerialModemSetBits(pInfo->fd, i); 286 287 /* try to read something */ 288 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) 289 goto connect_idle; 290 } 291#else 292 /* 293 * This is a simplified procedure; it simply toggles RTS. 294 */ 295 296 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1) 297 return 0; 298 i |= XF86_M_DTR; /* DTR = 1 */ 299 i &= ~XF86_M_RTS; /* RTS = 0 */ 300 if (xf86SetSerialModemState(pInfo->fd, i) == -1) 301 goto disconnect_idle; 302 usleep(200000); 303 304 pnpOpts = xf86OptionListCreate(pnpSerial, -1, 1); 305 xf86SetSerial(pInfo->fd, pnpOpts); 306 307 /* wait for response */ 308 xf86FlushInput(pInfo->fd); 309 i = XF86_M_DTR | XF86_M_RTS; /* DTR = 1, RTS = 1 */ 310 xf86SerialModemSetBits(pInfo->fd, i); 311 312 /* try to read something */ 313 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) 314 goto connect_idle; 315#endif 316 317 /* collect PnP COM device ID (2.1.7) */ 318 i = 0; 319 *prePNP = FALSE; 320 321 usleep(200000); /* the mouse must send `Begin ID' within 200msec */ 322 while (xf86ReadSerial(pInfo->fd, &c, 1) == 1) { 323 /* we may see "M", or "M3..." before `Begin ID' */ 324 if (c == 'M') 325 *prePNP = TRUE; 326 327 if ((c == 0x08) || (c == 0x28)) { /* Begin ID */ 328 *prePNP = FALSE; 329 buf[0] = c; 330 i = 1; 331 break; 332 } 333 if (*prePNP) 334 buf[i++] = c; 335 336 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) 337 break; 338 } 339 if (i <= 0) { 340 /* we haven't seen `Begin ID' in time... */ 341 goto connect_idle; 342 } 343 if (*prePNP) 344 return i; 345 346 ++c; /* make it `End ID' */ 347 for (;;) { 348 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) 349 break; 350 351 xf86ReadSerial(pInfo->fd, &buf[i], 1); 352 if (buf[i++] == c) /* End ID */ 353 break; 354 if (i >= 256) 355 break; 356 } 357 if (buf[i - 1] != c) 358 goto connect_idle; 359 return i; 360 361 /* 362 * According to PnP spec, we should set DTR = 1 and RTS = 0 while 363 * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed, 364 * assuming there is something at the port even if it didn't 365 * respond to the PnP enumeration procedure. 366 */ 367disconnect_idle: 368 i = XF86_M_DTR | XF86_M_RTS; /* DTR = 1, RTS = 1 */ 369 xf86SerialModemSetBits(pInfo->fd, i); 370connect_idle: 371 return 0; 372} 373 374static int 375pnpparse(InputInfoPtr pInfo, pnpid_t *id, char *buf, int len) 376{ 377 char s[3]; 378 int offset; 379 int sum = 0; 380 int i, j; 381 382 id->revision = 0; 383 id->eisaid = NULL; 384 id->serial = NULL; 385 id->class = NULL; 386 id->compat = NULL; 387 id->description = NULL; 388 id->neisaid = 0; 389 id->nserial = 0; 390 id->nclass = 0; 391 id->ncompat = 0; 392 id->ndescription = 0; 393 394 offset = 0x28 - buf[0]; 395 396 /* calculate checksum */ 397 for (i = 0; i < len - 3; ++i) { 398 sum += buf[i]; 399 buf[i] += offset; 400 } 401 sum += buf[len - 1]; 402 for (; i < len; ++i) 403 buf[i] += offset; 404 xf86MsgVerb(X_INFO, 2, "%s: PnP ID string: `%*.*s'\n", pInfo->name, 405 len, len, buf); 406 407 /* revision */ 408 buf[1] -= offset; 409 buf[2] -= offset; 410 id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f); 411 xf86MsgVerb(X_INFO, 2, "%s: PnP rev %d.%02d\n", pInfo->name, 412 id->revision / 100, id->revision % 100); 413 414 /* EISA vendor and product ID */ 415 id->eisaid = &buf[3]; 416 id->neisaid = 7; 417 418 /* option strings */ 419 i = 10; 420 if (buf[i] == '\\') { 421 /* device serial # */ 422 for (j = ++i; i < len; ++i) { 423 if (buf[i] == '\\') 424 break; 425 } 426 if (i >= len) 427 i -= 3; 428 if (i - j == 8) { 429 id->serial = &buf[j]; 430 id->nserial = 8; 431 } 432 } 433 if (buf[i] == '\\') { 434 /* PnP class */ 435 for (j = ++i; i < len; ++i) { 436 if (buf[i] == '\\') 437 break; 438 } 439 if (i >= len) 440 i -= 3; 441 if (i > j + 1) { 442 id->class = &buf[j]; 443 id->nclass = i - j; 444 } 445 } 446 if (buf[i] == '\\') { 447 /* compatible driver */ 448 for (j = ++i; i < len; ++i) { 449 if (buf[i] == '\\') 450 break; 451 } 452 /* 453 * PnP COM spec prior to v0.96 allowed '*' in this field, 454 * it's not allowed now; just ignore it. 455 */ 456 if (buf[j] == '*') 457 ++j; 458 if (i >= len) 459 i -= 3; 460 if (i > j + 1) { 461 id->compat = &buf[j]; 462 id->ncompat = i - j; 463 } 464 } 465 if (buf[i] == '\\') { 466 /* product description */ 467 for (j = ++i; i < len; ++i) { 468 if (buf[i] == ';') 469 break; 470 } 471 if (i >= len) 472 i -= 3; 473 if (i > j + 1) { 474 id->description = &buf[j]; 475 id->ndescription = i - j; 476 } 477 } 478 479 /* checksum exists if there are any optional fields */ 480 if ((id->nserial > 0) || (id->nclass > 0) 481 || (id->ncompat > 0) || (id->ndescription > 0)) { 482 xf86MsgVerb(X_INFO, 4, "%s: PnP checksum: 0x%02X\n", pInfo->name, sum); 483 sprintf(s, "%02X", sum & 0x0ff); 484 if (strncmp(s, &buf[len - 3], 2) != 0) { 485#if 0 486 /* 487 * Checksum error!! 488 * I found some mice do not comply with the PnP COM device 489 * spec regarding checksum... XXX 490 */ 491 return FALSE; 492#endif 493 } 494 } 495 496 return TRUE; 497} 498 499/* We can only identify MS at the moment */ 500static MouseProtocolID 501prepnpparse(InputInfoPtr pInfo, char *buf) 502{ 503 if (buf[0] == 'M' && buf[1] == '3') 504 return PROT_MS; 505 return PROT_UNKNOWN; 506} 507 508 509static symtab_t * 510pnpproto(pnpid_t *id) 511{ 512 symtab_t *t; 513 int i, j; 514 515 if (id->nclass > 0) 516 if (strncmp(id->class, "MOUSE", id->nclass) != 0) 517 /* this is not a mouse! */ 518 return NULL; 519 520 if (id->neisaid > 0) { 521 t = gettoken(pnpprod, id->eisaid, id->neisaid); 522 if (t->val != -1) 523 return t; 524 } 525 526 /* 527 * The 'Compatible drivers' field may contain more than one 528 * ID separated by ','. 529 */ 530 if (id->ncompat <= 0) 531 return NULL; 532 for (i = 0; i < id->ncompat; ++i) { 533 for (j = i; id->compat[i] != ','; ++i) 534 if (i >= id->ncompat) 535 break; 536 if (i > j) { 537 t = gettoken(pnpprod, id->compat + j, i - j); 538 if (t->val != -1) 539 return t; 540 } 541 } 542 543 return NULL; 544} 545 546/* name/val mapping */ 547 548static symtab_t * 549gettoken(symtab_t *tab, char *s, int len) 550{ 551 int i; 552 553 for (i = 0; tab[i].name != NULL; ++i) { 554 if (strncmp(tab[i].name, s, len) == 0) 555 break; 556 } 557 return &tab[i]; 558} 559 560/******************* PS/2 PnP probing ****************/ 561 562static int 563readMouse(InputInfoPtr pInfo, unsigned char *u) 564{ 565 566 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) 567 return FALSE; 568 569 xf86ReadSerial(pInfo->fd, u, 1); 570 return TRUE; 571} 572 573static void 574ps2DisableWrapMode(InputInfoPtr pInfo) 575{ 576 unsigned char reset_wrap_mode[] = { 0xEC }; 577 ps2SendPacket(pInfo, reset_wrap_mode, sizeof(reset_wrap_mode)); 578} 579 580Bool 581ps2SendPacket(InputInfoPtr pInfo, unsigned char *bytes, int len) 582{ 583 unsigned char c; 584 int i,j; 585 586#ifdef DEBUG 587 xf86ErrorF("Ps/2 data package:"); 588 for (i = 0; i < len; i++) 589 xf86ErrorF(" %x", *(bytes + i)); 590 xf86ErrorF("\n"); 591#endif 592 593 for (i = 0; i < len; i++) { 594 for (j = 0; j < 10; j++) { 595 xf86WriteSerial(pInfo->fd, bytes + i, 1); 596 usleep(10000); 597 if (!readMouse(pInfo,&c)) { 598#ifdef DEBUG 599 xf86ErrorF("sending 0x%x to PS/2 unsuccessful\n",*(bytes + i)); 600#endif 601 return FALSE; 602 } 603#ifdef DEBUG 604 xf86ErrorF("Received: 0x%x\n",c); 605#endif 606 if (c == 0xFA) /* ACK */ 607 break; 608 609 if (c == 0xFE) /* resend */ 610 continue; 611 612 613 if (c == 0xFC) /* error */ 614 return FALSE; 615 616 /* Some mice accidentally enter wrap mode during init */ 617 if (c == *(bytes + i) /* wrap mode */ 618 && (*(bytes + i) != 0xEC)) /* avoid recursion */ 619 ps2DisableWrapMode(pInfo); 620 621 return FALSE; 622 } 623 if (j == 10) 624 return FALSE; 625 } 626 627 return TRUE; 628} 629 630static Bool 631ps2DisableDataReporting(InputInfoPtr pInfo) 632{ 633 unsigned char packet[] = { 0xF5 }; 634 return ps2SendPacket(pInfo, packet, sizeof(packet)); 635} 636 637Bool 638ps2EnableDataReporting(InputInfoPtr pInfo) 639{ 640 unsigned char packet[] = { 0xF4 }; 641 return ps2SendPacket(pInfo, packet, sizeof(packet)); 642} 643 644int 645ps2GetDeviceID(InputInfoPtr pInfo) 646{ 647 unsigned char u; 648 unsigned char packet[] = { 0xf2 }; 649 650 usleep(30000); 651 xf86FlushInput(pInfo->fd); 652 if (!ps2SendPacket(pInfo, packet, sizeof(packet))) 653 return -1; 654 while (1) { 655 if (!readMouse(pInfo,&u)) 656 return -1; 657 if (u != 0xFA) 658 break; 659 } 660#ifdef DEBUG 661 xf86ErrorF("Obtained Mouse Type: %x\n",u); 662#endif 663 return (int) u; 664} 665 666Bool 667ps2Reset(InputInfoPtr pInfo) 668{ 669 unsigned char u; 670 unsigned char packet[] = { 0xff }; 671 unsigned char reply[] = { 0xaa, 0x00 }; 672 unsigned int i; 673#ifdef DEBUG 674 xf86ErrorF("PS/2 Mouse reset\n"); 675#endif 676 if (!ps2SendPacket(pInfo, packet, sizeof(packet))) 677 return FALSE; 678 /* we need a little delay here */ 679 xf86WaitForInput(pInfo->fd, 500000); 680 for (i = 0; i < sizeof(reply) ; i++) { 681 if (!readMouse(pInfo,&u)) { 682 goto EXIT; 683 } 684 if (u != reply[i]) 685 goto EXIT; 686 } 687 return TRUE; 688 689 EXIT: 690 xf86FlushInput(pInfo->fd); 691 return FALSE; 692} 693 694static MouseProtocolID 695probePs2ProtocolPnP(InputInfoPtr pInfo) 696{ 697 unsigned char u; 698 MouseProtocolID ret = PROT_UNKNOWN; 699 700 xf86FlushInput(pInfo->fd); 701 702 ps2DisableDataReporting(pInfo); 703 704 if (ps2Reset(pInfo)) { /* Reset PS2 device */ 705 unsigned char seq[] = { 243, 200, 243, 100, 243, 80 }; 706 /* Try to identify Intelli Mouse */ 707 if (ps2SendPacket(pInfo, seq, sizeof(seq))) { 708 u = ps2GetDeviceID(pInfo); 709 if (u == 0x03) { 710 /* found IntelliMouse now try IntelliExplorer */ 711 unsigned char im_seq[] = { 243, 200, 243, 200, 243, 80 }; 712 if (ps2SendPacket(pInfo,im_seq,sizeof(im_seq))) { 713 u = ps2GetDeviceID(pInfo); 714 if (u == 0x04) 715 ret = PROT_EXPPS2; 716 else 717 ret = PROT_IMPS2; 718 } 719 } else if (ps2Reset(pInfo)) /* reset again to find sane state */ 720 ret = PROT_PS2; 721 } 722 723 if (ret != PROT_UNKNOWN) 724 ps2EnableDataReporting(pInfo); 725 } 726 return ret; 727} 728 729static struct ps2protos { 730 int Id; 731 MouseProtocolID protoID; 732} ps2 [] = { 733 { 0x0, PROT_PS2 }, 734 { 0x3, PROT_IMPS2 }, 735 { 0x4, PROT_EXPPS2 }, 736 { -1 , PROT_UNKNOWN } 737}; 738 739 740static MouseProtocolID 741getPs2ProtocolPnP(InputInfoPtr pInfo) 742{ 743 int Id; 744 int i; 745 MouseProtocolID proto; 746 int count = 4; 747 748 xf86FlushInput(pInfo->fd); 749 750 while (--count) 751 if (ps2DisableDataReporting(pInfo)) 752 break; 753 754 if (!count) { 755 proto = PROT_UNKNOWN; 756 goto EXIT; 757 } 758 759 if ((Id = ps2GetDeviceID(pInfo)) == -1) { 760 proto = PROT_UNKNOWN; 761 goto EXIT; 762 } 763 764 if (-1 == ps2EnableDataReporting(pInfo)) { 765 proto = PROT_UNKNOWN; 766 goto EXIT; 767 } 768 769 for (i = 0; ps2[i].protoID != PROT_UNKNOWN; i++) { 770 if (ps2[i].Id == Id) { 771 xf86MsgVerb(X_PROBED,2,"Found PS/2 proto ID %x\n",Id); 772 proto = ps2[i].protoID; 773 goto EXIT; 774 } 775 } 776 777 proto = PROT_UNKNOWN; 778 xf86Msg(X_ERROR,"Found unknown PS/2 proto ID %x\n",Id); 779 780 EXIT: 781 xf86FlushInput(pInfo->fd); 782 return proto; 783} 784 785