1 /* $NetBSD: pms.c,v 1.30 2010/02/24 22:38:08 dyoung Exp $ */ 2 3 /*- 4 * Copyright (c) 2004 Kentaro Kurahone. 5 * Copyright (c) 2004 Ales Krenek. 6 * Copyright (c) 1994 Charles M. Hannum. 7 * Copyright (c) 1992, 1993 Erik Forsberg. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 19 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: pms.c,v 1.30 2010/02/24 22:38:08 dyoung Exp $"); 30 31 #include "opt_pms.h" 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/ioctl.h> 37 #include <sys/kernel.h> 38 #include <sys/kthread.h> 39 40 #include <sys/bus.h> 41 42 #include <dev/pckbport/pckbportvar.h> 43 #ifdef PMS_SYNAPTICS_TOUCHPAD 44 #include <dev/pckbport/synapticsvar.h> 45 #endif 46 #ifdef PMS_ELANTECH_TOUCHPAD 47 #include <dev/pckbport/elantechvar.h> 48 #endif 49 50 #include <dev/pckbport/pmsreg.h> 51 #include <dev/pckbport/pmsvar.h> 52 53 54 #include <dev/wscons/wsconsio.h> 55 #include <dev/wscons/wsmousevar.h> 56 57 #ifdef PMSDEBUG 58 int pmsdebug = 1; 59 #define DPRINTF(x) if (pmsdebug) printf x 60 #else 61 #define DPRINTF(x) 62 #endif 63 64 const enum pms_type tries[] = { 65 PMS_SCROLL5, PMS_SCROLL3, PMS_STANDARD, PMS_UNKNOWN 66 }; 67 68 const struct pms_protocol pms_protocols[] = { 69 { { 0, 0, 0 }, 0, "unknown protocol" }, 70 { { 0, 0, 0 }, 0, "no scroll wheel (3 buttons)" }, 71 { { 200, 100, 80 }, 3, "scroll wheel (3 buttons)" }, 72 { { 200, 200, 80 }, 4, "scroll wheel (5 buttons)" }, 73 { { 0, 0, 0 }, 0, "synaptics" }, 74 { { 0, 0, 0 }, 0, "elantech" } 75 }; 76 77 78 int pmsprobe(device_t, cfdata_t, void *); 79 void pmsattach(device_t, device_t, void *); 80 void pmsinput(void *, int); 81 82 CFATTACH_DECL_NEW(pms, sizeof(struct pms_softc), 83 pmsprobe, pmsattach, NULL, NULL); 84 85 static int pms_protocol(pckbport_tag_t, pckbport_slot_t); 86 static void do_enable(struct pms_softc *); 87 static void do_disable(struct pms_softc *); 88 static void pms_reset_thread(void*); 89 int pms_enable(void *); 90 int pms_ioctl(void *, u_long, void *, int, struct lwp *); 91 void pms_disable(void *); 92 93 static bool pms_suspend(device_t, const pmf_qual_t *); 94 static bool pms_resume(device_t, const pmf_qual_t *); 95 96 const struct wsmouse_accessops pms_accessops = { 97 pms_enable, 98 pms_ioctl, 99 pms_disable, 100 }; 101 102 static int 103 pms_protocol(pckbport_tag_t tag, pckbport_slot_t slot) 104 { 105 u_char cmd[2], resp[1]; 106 int i, j, res; 107 const struct pms_protocol *p; 108 109 for (j = 0; j < sizeof(tries) / sizeof(tries[0]); ++j) { 110 p = &pms_protocols[tries[j]]; 111 if (!p->rates[0]) 112 break; 113 cmd[0] = PMS_SET_SAMPLE; 114 for (i = 0; i < 3; i++) { 115 cmd[1] = p->rates[i]; 116 res = pckbport_enqueue_cmd(tag, slot, cmd, 2, 0, 1, 0); 117 if (res) 118 return PMS_STANDARD; 119 } 120 121 cmd[0] = PMS_SEND_DEV_ID; 122 res = pckbport_enqueue_cmd(tag, slot, cmd, 1, 1, 1, resp); 123 if (res) 124 return PMS_UNKNOWN; 125 if (resp[0] == p->response) { 126 DPRINTF(("pms_protocol: found mouse protocol %d\n", 127 tries[j])); 128 return tries[j]; 129 } 130 } 131 DPRINTF(("pms_protocol: standard PS/2 protocol (no scroll wheel)\n")); 132 return PMS_STANDARD; 133 } 134 135 int 136 pmsprobe(device_t parent, cfdata_t match, void *aux) 137 { 138 struct pckbport_attach_args *pa = aux; 139 u_char cmd[1], resp[2]; 140 int res; 141 142 if (pa->pa_slot != PCKBPORT_AUX_SLOT) 143 return 0; 144 145 /* Flush any garbage. */ 146 pckbport_flush(pa->pa_tag, pa->pa_slot); 147 148 /* reset the device */ 149 cmd[0] = PMS_RESET; 150 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); 151 if (res) { 152 aprint_debug("pmsprobe: reset error %d\n", res); 153 return 0; 154 } 155 if (resp[0] != PMS_RSTDONE) { 156 printf("pmsprobe: reset response 0x%x\n", resp[0]); 157 return 0; 158 } 159 160 /* get type number (0 = mouse) */ 161 if (resp[1] != 0) { 162 aprint_debug("pmsprobe: type 0x%x\n", resp[1]); 163 return 0; 164 } 165 166 return 10; 167 } 168 169 void 170 pmsattach(device_t parent, device_t self, void *aux) 171 { 172 struct pms_softc *sc = device_private(self); 173 struct pckbport_attach_args *pa = aux; 174 struct wsmousedev_attach_args a; 175 u_char cmd[2], resp[2]; 176 int res; 177 178 sc->sc_dev = self; 179 sc->sc_kbctag = pa->pa_tag; 180 sc->sc_kbcslot = pa->pa_slot; 181 182 aprint_naive("\n"); 183 aprint_normal("\n"); 184 185 /* Flush any garbage. */ 186 pckbport_flush(pa->pa_tag, pa->pa_slot); 187 188 /* reset the device */ 189 cmd[0] = PMS_RESET; 190 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); 191 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { 192 aprint_debug("pmsattach: reset error\n"); 193 return; 194 } 195 sc->inputstate = 0; 196 sc->buttons = 0; 197 sc->protocol = PMS_UNKNOWN; 198 199 #ifdef PMS_SYNAPTICS_TOUCHPAD 200 /* Probe for synaptics touchpad. */ 201 if (pms_synaptics_probe_init(sc) == 0) { 202 sc->protocol = PMS_SYNAPTICS; 203 } else 204 #endif 205 #ifdef PMS_ELANTECH_TOUCHPAD 206 if (pms_elantech_probe_init(sc) == 0) { 207 sc->protocol = PMS_ELANTECH; 208 } else 209 #endif 210 /* Install generic handler. */ 211 pckbport_set_inputhandler(sc->sc_kbctag, sc->sc_kbcslot, 212 pmsinput, sc, device_xname(sc->sc_dev)); 213 214 a.accessops = &pms_accessops; 215 a.accesscookie = sc; 216 217 /* 218 * Attach the wsmouse, saving a handle to it. 219 * Note that we don't need to check this pointer against NULL 220 * here or in pmsintr, because if this fails pms_enable() will 221 * never be called, so pmsinput() will never be called. 222 */ 223 sc->sc_wsmousedev = config_found_ia(self, "wsmousedev", &a, wsmousedevprint); 224 225 /* no interrupts until enabled */ 226 cmd[0] = PMS_DEV_DISABLE; 227 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 0, 0, 0); 228 if (res) 229 aprint_error("pmsattach: disable error\n"); 230 pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0); 231 232 kthread_create(PRI_NONE, 0, NULL, pms_reset_thread, sc, 233 &sc->sc_event_thread, device_xname(sc->sc_dev)); 234 235 #ifndef PMS_DISABLE_POWERHOOK 236 sc->sc_suspended = 0; 237 #endif 238 if (!pmf_device_register(self, pms_suspend, pms_resume)) 239 aprint_error_dev(self, "couldn't establish power handler\n"); 240 } 241 242 static void 243 do_enable(struct pms_softc *sc) 244 { 245 u_char cmd[2]; 246 int res; 247 248 sc->inputstate = 0; 249 sc->buttons = 0; 250 251 pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 1); 252 253 #ifdef PMS_SYNAPTICS_TOUCHPAD 254 if (sc->protocol == PMS_SYNAPTICS) 255 pms_synaptics_enable(sc); 256 #endif 257 #ifdef PMS_ELANTECH_TOUCHPAD 258 if (sc->protocol == PMS_ELANTECH) 259 pms_elantech_enable(sc); 260 #endif 261 262 cmd[0] = PMS_DEV_ENABLE; 263 res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 264 1, 0, 1, 0); 265 if (res) 266 aprint_error("pms_enable: command error %d\n", res); 267 268 if (sc->protocol == PMS_UNKNOWN) 269 sc->protocol = pms_protocol(sc->sc_kbctag, sc->sc_kbcslot); 270 DPRINTF(("pms_enable: using %s protocol\n", 271 pms_protocols[sc->protocol].name)); 272 #if 0 273 { 274 u_char scmd[2]; 275 276 scmd[0] = PMS_SET_RES; 277 scmd[1] = 3; /* 8 counts/mm */ 278 res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd, 279 2, 0, 1, 0); 280 if (res) 281 printf("pms_enable: setup error1 (%d)\n", res); 282 283 scmd[0] = PMS_SET_SCALE21; 284 res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd, 285 1, 0, 1, 0); 286 if (res) 287 printf("pms_enable: setup error2 (%d)\n", res); 288 289 scmd[0] = PMS_SET_SAMPLE; 290 scmd[1] = 100; /* 100 samples/sec */ 291 res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd, 292 2, 0, 1, 0); 293 if (res) 294 printf("pms_enable: setup error3 (%d)\n", res); 295 } 296 #endif 297 } 298 299 static void 300 do_disable(struct pms_softc *sc) 301 { 302 u_char cmd[1]; 303 int res; 304 305 cmd[0] = PMS_DEV_DISABLE; 306 res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 307 1, 0, 1, 0); 308 if (res) 309 aprint_error("pms_disable: command error\n"); 310 311 pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0); 312 } 313 314 int 315 pms_enable(void *v) 316 { 317 struct pms_softc *sc = v; 318 int s; 319 320 if (sc->sc_enabled) 321 return EBUSY; 322 323 do_enable(sc); 324 325 s = spltty(); 326 sc->sc_enabled = 1; 327 splx(s); 328 329 return 0; 330 } 331 332 void 333 pms_disable(void *v) 334 { 335 struct pms_softc *sc = v; 336 int s; 337 338 do_disable(sc); 339 340 s = spltty(); 341 sc->sc_enabled = 0; 342 splx(s); 343 } 344 345 static bool 346 pms_suspend(device_t dv, const pmf_qual_t *qual) 347 { 348 struct pms_softc *sc = device_private(dv); 349 350 if (sc->sc_enabled) 351 do_disable(sc); 352 353 return true; 354 } 355 356 static bool 357 pms_resume(device_t dv, const pmf_qual_t *qual) 358 { 359 struct pms_softc *sc = device_private(dv); 360 361 #ifdef PMS_SYNAPTICS_TOUCHPAD 362 if (sc->protocol == PMS_SYNAPTICS) { 363 pms_synaptics_resume(sc); 364 if (sc->sc_enabled) { 365 do_enable(sc); 366 } 367 } else 368 #endif 369 #ifdef PMS_ELANTECH_TOUCHPAD 370 if (sc->protocol == PMS_ELANTECH) { 371 pms_elantech_resume(sc); 372 if (sc->sc_enabled) { 373 do_enable(sc); 374 } 375 } else 376 #endif 377 if (sc->sc_enabled) { 378 /* recheck protocol & init mouse */ 379 sc->protocol = PMS_UNKNOWN; 380 do_enable(sc); /* only if we were suspended */ 381 } 382 383 return true; 384 } 385 386 int 387 pms_ioctl(void *v, u_long cmd, void *data, int flag, 388 struct lwp *l) 389 { 390 struct pms_softc *sc = v; 391 u_char kbcmd[2]; 392 int i; 393 394 switch (cmd) { 395 case WSMOUSEIO_GTYPE: 396 *(u_int *)data = WSMOUSE_TYPE_PS2; 397 break; 398 399 case WSMOUSEIO_SRES: 400 i = (*(u_int *)data - 12) / 25; 401 402 if (i < 0) 403 i = 0; 404 405 if (i > 3) 406 i = 3; 407 408 kbcmd[0] = PMS_SET_RES; 409 kbcmd[1] = i; 410 i = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, kbcmd, 411 2, 0, 1, 0); 412 413 if (i) 414 printf("pms_ioctl: SET_RES command error\n"); 415 break; 416 417 default: 418 return EPASSTHROUGH; 419 } 420 return 0; 421 } 422 423 static void 424 pms_reset_thread(void *arg) 425 { 426 struct pms_softc *sc = arg; 427 u_char cmd[1], resp[2]; 428 int res; 429 int save_protocol; 430 431 for (;;) { 432 tsleep(&sc->sc_enabled, PWAIT, "pmsreset", 0); 433 #ifdef PMSDEBUG 434 if (pmsdebug) 435 #endif 436 #if defined(PMSDEBUG) || defined(DIAGNOSTIC) 437 aprint_debug_dev(sc->sc_dev, 438 "resetting mouse interface\n"); 439 #endif 440 save_protocol = sc->protocol; 441 pms_disable(sc); 442 cmd[0] = PMS_RESET; 443 res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 444 1, 2, 1, resp); 445 if (res) { 446 DPRINTF(("%s: reset error %d\n", 447 device_xname(sc->sc_dev), res)); 448 } 449 450 /* For the synaptics and elantech case, leave the protocol alone. */ 451 if (sc->protocol != PMS_SYNAPTICS && sc->protocol != PMS_ELANTECH) 452 sc->protocol = PMS_UNKNOWN; 453 454 pms_enable(sc); 455 if (sc->protocol != save_protocol) { 456 #if defined(PMSDEBUG) || defined(DIAGNOSTIC) 457 aprint_verbose_dev(sc->sc_dev, 458 "protocol change, sleeping and retrying\n"); 459 #endif 460 pms_disable(sc); 461 cmd[0] = PMS_RESET; 462 res = pckbport_enqueue_cmd(sc->sc_kbctag, 463 sc->sc_kbcslot, cmd, 1, 2, 1, resp); 464 if (res) { 465 DPRINTF(("%s: reset error %d\n", 466 device_xname(sc->sc_dev), res)); 467 } 468 tsleep(pms_reset_thread, PWAIT, "pmsreset", hz); 469 cmd[0] = PMS_RESET; 470 res = pckbport_enqueue_cmd(sc->sc_kbctag, 471 sc->sc_kbcslot, cmd, 1, 2, 1, resp); 472 if (res) { 473 DPRINTF(("%s: reset error %d\n", 474 device_xname(sc->sc_dev), res)); 475 } 476 sc->protocol = PMS_UNKNOWN; /* reprobe protocol */ 477 pms_enable(sc); 478 #if defined(PMSDEBUG) || defined(DIAGNOSTIC) 479 if (sc->protocol != save_protocol) { 480 printf("%s: protocol changed.\n", 481 device_xname(sc->sc_dev)); 482 } 483 #endif 484 } 485 } 486 } 487 488 /* Masks for the first byte of a packet */ 489 #define PMS_LBUTMASK 0x01 490 #define PMS_RBUTMASK 0x02 491 #define PMS_MBUTMASK 0x04 492 #define PMS_4BUTMASK 0x10 493 #define PMS_5BUTMASK 0x20 494 495 void 496 pmsinput(void *vsc, int data) 497 { 498 struct pms_softc *sc = vsc; 499 u_int changed; 500 int dx, dy, dz = 0; 501 int newbuttons = 0; 502 503 if (!sc->sc_enabled) { 504 /* Interrupts are not expected. Discard the byte. */ 505 return; 506 } 507 508 getmicrouptime(&sc->current); 509 510 if (sc->inputstate > 0) { 511 struct timeval diff; 512 513 timersub(&sc->current, &sc->last, &diff); 514 /* 515 * Empirically, the delay should be about 1700us on a standard 516 * PS/2 port. I have seen delays as large as 4500us (rarely) 517 * in regular use. When using a confused mouse, I generally 518 * see delays at least as large as 30,000us. -seebs 519 * 520 * The thinkpad trackball returns at 22-23ms. So we use 521 * >= 40ms. In the future, I'll implement adaptable timeout 522 * by increasing the timeout if the mouse reset happens 523 * too frequently -christos 524 */ 525 if (diff.tv_sec > 0 || diff.tv_usec >= 40000) { 526 DPRINTF(("pms_input: unusual delay (%ld.%06ld s), " 527 "scheduling reset\n", 528 (long)diff.tv_sec, (long)diff.tv_usec)); 529 sc->inputstate = 0; 530 sc->sc_enabled = 0; 531 wakeup(&sc->sc_enabled); 532 return; 533 } 534 } 535 sc->last = sc->current; 536 537 if (sc->inputstate == 0) { 538 /* 539 * Some devices (seen on trackballs anytime, and on 540 * some mice shortly after reset) output garbage bytes 541 * between packets. Just ignore them. 542 */ 543 if ((data & 0xc0) != 0) 544 return; /* not in sync yet, discard input */ 545 } 546 547 sc->packet[sc->inputstate++] = data & 0xff; 548 switch (sc->inputstate) { 549 case 0: 550 /* no useful processing can be done yet */ 551 break; 552 553 case 1: 554 /* 555 * Why should we test for bit 0x8 and insist on it here? 556 * The old (psm.c and psm_intelli.c) drivers didn't do 557 * it, and there are devices where it does harm (that's 558 * why it is not used if using PMS_STANDARD protocol). 559 * Anyway, it does not to cause any harm to accept packets 560 * without this bit. 561 */ 562 #if 0 563 if (sc->protocol == PMS_STANDARD) 564 break; 565 if (!(sc->packet[0] & 0x8)) { 566 DPRINTF(("pmsinput: 0x8 not set in first byte " 567 "[0x%02x], resetting\n", sc->packet[0])); 568 sc->inputstate = 0; 569 sc->sc_enabled = 0; 570 wakeup(&sc->sc_enabled); 571 return; 572 } 573 #endif 574 break; 575 576 case 2: 577 break; 578 579 case 4: 580 /* Case 4 is a superset of case 3. This is *not* an accident. */ 581 if (sc->protocol == PMS_SCROLL3) { 582 dz = sc->packet[3]; 583 if (dz >= 128) 584 dz -= 256; 585 if (dz == -128) 586 dz = -127; 587 } else if (sc->protocol == PMS_SCROLL5) { 588 dz = sc->packet[3] & 0xf; 589 if (dz >= 8) 590 dz -= 16; 591 if (sc->packet[3] & PMS_4BUTMASK) 592 newbuttons |= 0x8; 593 if (sc->packet[3] & PMS_5BUTMASK) 594 newbuttons |= 0x10; 595 } else { 596 DPRINTF(("pmsinput: why am I looking at this byte?\n")); 597 dz = 0; 598 } 599 /* FALLTHROUGH */ 600 case 3: 601 /* 602 * This is only an endpoint for scroll protocols with 4 603 * bytes, or the standard protocol with 3. 604 */ 605 if (sc->protocol != PMS_STANDARD && sc->inputstate == 3) 606 break; 607 608 newbuttons |= ((sc->packet[0] & PMS_LBUTMASK) ? 0x1 : 0) | 609 ((sc->packet[0] & PMS_MBUTMASK) ? 0x2 : 0) | 610 ((sc->packet[0] & PMS_RBUTMASK) ? 0x4 : 0); 611 612 dx = sc->packet[1]; 613 if (dx >= 128) 614 dx -= 256; 615 if (dx == -128) 616 dx = -127; 617 618 dy = sc->packet[2]; 619 if (dy >= 128) 620 dy -= 256; 621 if (dy == -128) 622 dy = -127; 623 624 sc->inputstate = 0; 625 changed = (sc->buttons ^ newbuttons); 626 sc->buttons = newbuttons; 627 628 #ifdef PMSDEBUG 629 if (sc->protocol == PMS_STANDARD) { 630 DPRINTF(("pms: packet: 0x%02x%02x%02x\n", 631 sc->packet[0], sc->packet[1], sc->packet[2])); 632 } else { 633 DPRINTF(("pms: packet: 0x%02x%02x%02x%02x\n", 634 sc->packet[0], sc->packet[1], sc->packet[2], 635 sc->packet[3])); 636 } 637 #endif 638 if (dx || dy || dz || changed) { 639 #ifdef PMSDEBUG 640 DPRINTF(("pms: x %+03d y %+03d z %+03d " 641 "buttons 0x%02x\n", dx, dy, dz, sc->buttons)); 642 #endif 643 wsmouse_input(sc->sc_wsmousedev, 644 sc->buttons, dx, dy, dz, 0, 645 WSMOUSE_INPUT_DELTA); 646 } 647 memset(sc->packet, 0, 4); 648 break; 649 650 /* If we get here, we have problems. */ 651 default: 652 printf("pmsinput: very confused. resetting.\n"); 653 sc->inputstate = 0; 654 sc->sc_enabled = 0; 655 wakeup(&sc->sc_enabled); 656 return; 657 } 658 } 659