pms.c revision 1.27
1/* $OpenBSD: pms.c,v 1.27 2012/01/28 21:00:48 mpi Exp $ */ 2/* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */ 3 4/*- 5 * Copyright (c) 1994 Charles M. Hannum. 6 * Copyright (c) 1992, 1993 Erik Forsberg. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 18 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/param.h> 28#include <sys/systm.h> 29#include <sys/device.h> 30#include <sys/ioctl.h> 31#include <sys/malloc.h> 32 33#include <machine/bus.h> 34 35#include <dev/ic/pckbcvar.h> 36 37#include <dev/pckbc/pmsreg.h> 38 39#include <dev/wscons/wsconsio.h> 40#include <dev/wscons/wsmousevar.h> 41 42#ifdef DEBUG 43#define DPRINTF(x...) do { printf(x); } while (0); 44#else 45#define DPRINTF(x...) 46#endif 47 48#define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 49 50#define WSMOUSE_BUTTON(x) (1 << ((x) - 1)) 51 52struct pms_softc; 53 54struct pms_protocol { 55 int type; 56#define PMS_STANDARD 0 57#define PMS_INTELLI 1 58#define PMS_SYNAPTICS 2 59#define PMS_ALPS 3 60 u_int packetsize; 61 int (*enable)(struct pms_softc *); 62 int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *); 63 int (*sync)(struct pms_softc *, int); 64 void (*proc)(struct pms_softc *); 65 void (*disable)(struct pms_softc *); 66}; 67 68struct synaptics_softc { 69 int identify; 70 int capabilities, ext_capabilities; 71 int model, ext_model; 72 int resolution, dimension; 73 74 int mode; 75 76 int res_x, res_y; 77 int min_x, min_y; 78 int max_x, max_y; 79 80 /* Compat mode */ 81 int wsmode; 82 int old_x, old_y; 83 u_int old_buttons; 84#define SYNAPTICS_SCALE 4 85#define SYNAPTICS_PRESSURE 30 86}; 87 88struct alps_softc { 89 int model; 90 int mask; 91 int version; 92 93 int min_x, min_y; 94 int max_x, max_y; 95 int old_fin; 96 97 /* Compat mode */ 98 int wsmode; 99 int old_x, old_y; 100 u_int old_buttons; 101#define ALPS_PRESSURE 40 102}; 103 104struct pms_softc { /* driver status information */ 105 struct device sc_dev; 106 107 pckbc_tag_t sc_kbctag; 108 109 int sc_state; 110#define PMS_STATE_DISABLED 0 111#define PMS_STATE_ENABLED 1 112#define PMS_STATE_SUSPENDED 2 113 114 int sc_dev_enable; 115#define PMS_DEV_IGNORE 0x00 116#define PMS_DEV_PRIMARY 0x01 117#define PMS_DEV_SECONDARY 0x02 118 119 int poll; 120 int inputstate; 121 122 const struct pms_protocol *protocol; 123 struct synaptics_softc *synaptics; 124 struct alps_softc *alps; 125 126 u_char packet[8]; 127 128 struct device *sc_wsmousedev; 129 struct device *sc_sec_wsmousedev; 130}; 131 132static const u_int butmap[8] = { 133 0, 134 WSMOUSE_BUTTON(1), 135 WSMOUSE_BUTTON(3), 136 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(3), 137 WSMOUSE_BUTTON(2), 138 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2), 139 WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3), 140 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3) 141}; 142 143static const struct alps_model { 144 int version; 145 int mask; 146 int model; 147} alps_models[] = { 148#if 0 149 /* FIXME some clipads are not working yet */ 150 { 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 151 { 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 152#endif 153 { 0x2021, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 154 { 0x2221, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 155 { 0x2222, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 156 { 0x3222, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 157 { 0x5321, 0xf8, ALPS_GLIDEPOINT }, 158 { 0x5322, 0xf8, ALPS_GLIDEPOINT }, 159 { 0x603b, 0xf8, ALPS_GLIDEPOINT }, 160 { 0x6321, 0xf8, ALPS_GLIDEPOINT }, 161 { 0x6322, 0xf8, ALPS_GLIDEPOINT }, 162 { 0x6323, 0xf8, ALPS_GLIDEPOINT }, 163 { 0x6324, 0x8f, ALPS_GLIDEPOINT }, 164 { 0x6325, 0xef, ALPS_GLIDEPOINT }, 165 { 0x6326, 0xf8, ALPS_GLIDEPOINT }, 166 { 0x7301, 0xf8, ALPS_DUALPOINT }, 167 { 0x7321, 0xf8, ALPS_GLIDEPOINT }, 168 { 0x7322, 0xf8, ALPS_GLIDEPOINT }, 169 { 0x7325, 0xcf, ALPS_GLIDEPOINT }, 170#if 0 171 /* 172 * This model has a clitpad sending almost compatible PS2 173 * packets but not compatible enough to be used with the 174 * ALPS protocol. 175 */ 176 { 0x633b, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 177 178 { 0x7326, 0, 0 }, /* XXX Uses unknown v3 protocol */ 179#endif 180}; 181 182int pmsprobe(struct device *, void *, void *); 183void pmsattach(struct device *, struct device *, void *); 184int pmsactivate(struct device *, int); 185 186void pmsinput(void *, int); 187 188int pms_change_state(struct pms_softc *, int, int); 189 190int pms_ioctl(void *, u_long, caddr_t, int, struct proc *); 191int pms_enable(void *); 192void pms_disable(void *); 193 194int pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *); 195int pms_sec_enable(void *); 196void pms_sec_disable(void *); 197 198int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int); 199int pms_spec_cmd(struct pms_softc *, int); 200int pms_get_devid(struct pms_softc *, u_char *); 201int pms_get_status(struct pms_softc *, u_char *); 202int pms_set_rate(struct pms_softc *, int); 203int pms_set_resolution(struct pms_softc *, int); 204int pms_set_scaling(struct pms_softc *, int); 205int pms_reset(struct pms_softc *); 206int pms_dev_enable(struct pms_softc *); 207int pms_dev_disable(struct pms_softc *); 208 209int pms_enable_intelli(struct pms_softc *); 210 211int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *); 212int pms_sync_mouse(struct pms_softc *, int); 213void pms_proc_mouse(struct pms_softc *); 214 215int pms_enable_synaptics(struct pms_softc *); 216int pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *); 217int pms_sync_synaptics(struct pms_softc *, int); 218void pms_proc_synaptics(struct pms_softc *); 219void pms_disable_synaptics(struct pms_softc *); 220 221int pms_enable_alps(struct pms_softc *); 222int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *); 223int pms_sync_alps(struct pms_softc *, int); 224void pms_proc_alps(struct pms_softc *); 225 226int synaptics_set_mode(struct pms_softc *, int); 227int synaptics_query(struct pms_softc *, int, int *); 228int synaptics_get_hwinfo(struct pms_softc *); 229void synaptics_sec_proc(struct pms_softc *); 230 231int alps_get_hwinfo(struct pms_softc *); 232 233struct cfattach pms_ca = { 234 sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, 235 pmsactivate 236}; 237 238struct cfdriver pms_cd = { 239 NULL, "pms", DV_DULL 240}; 241 242const struct wsmouse_accessops pms_accessops = { 243 pms_enable, 244 pms_ioctl, 245 pms_disable, 246}; 247 248const struct wsmouse_accessops pms_sec_accessops = { 249 pms_sec_enable, 250 pms_sec_ioctl, 251 pms_sec_disable, 252}; 253 254const struct pms_protocol pms_protocols[] = { 255 /* Generic PS/2 mouse */ 256 { 257 PMS_STANDARD, 3, 258 NULL, 259 pms_ioctl_mouse, 260 pms_sync_mouse, 261 pms_proc_mouse, 262 NULL 263 }, 264 /* Microsoft IntelliMouse */ 265 { 266 PMS_INTELLI, 4, 267 pms_enable_intelli, 268 pms_ioctl_mouse, 269 pms_sync_mouse, 270 pms_proc_mouse, 271 NULL 272 }, 273 /* Synaptics touchpad */ 274 { 275 PMS_SYNAPTICS, 6, 276 pms_enable_synaptics, 277 pms_ioctl_synaptics, 278 pms_sync_synaptics, 279 pms_proc_synaptics, 280 pms_disable_synaptics 281 }, 282 /* ALPS touchpad */ 283 { 284 PMS_ALPS, 6, 285 pms_enable_alps, 286 pms_ioctl_alps, 287 pms_sync_alps, 288 pms_proc_alps, 289 NULL 290 }, 291}; 292 293int 294pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen) 295{ 296 if (sc->poll) { 297 return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 298 cmd, len, resplen, resp, 1); 299 } else { 300 return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 301 cmd, len, resplen, 1, resp); 302 } 303} 304 305int 306pms_spec_cmd(struct pms_softc *sc, int cmd) 307{ 308 if (pms_set_scaling(sc, 1) || 309 pms_set_resolution(sc, (cmd >> 6) & 0x03) || 310 pms_set_resolution(sc, (cmd >> 4) & 0x03) || 311 pms_set_resolution(sc, (cmd >> 2) & 0x03) || 312 pms_set_resolution(sc, (cmd >> 0) & 0x03)) 313 return (-1); 314 return (0); 315} 316 317int 318pms_get_devid(struct pms_softc *sc, u_char *resp) 319{ 320 u_char cmd[1]; 321 322 cmd[0] = PMS_SEND_DEV_ID; 323 return (pms_cmd(sc, cmd, 1, resp, 1)); 324} 325 326int 327pms_get_status(struct pms_softc *sc, u_char *resp) 328{ 329 u_char cmd[1]; 330 331 cmd[0] = PMS_SEND_DEV_STATUS; 332 return (pms_cmd(sc, cmd, 1, resp, 3)); 333} 334 335int 336pms_set_rate(struct pms_softc *sc, int value) 337{ 338 u_char cmd[2]; 339 340 cmd[0] = PMS_SET_SAMPLE; 341 cmd[1] = value; 342 return (pms_cmd(sc, cmd, 2, NULL, 0)); 343} 344 345int 346pms_set_resolution(struct pms_softc *sc, int value) 347{ 348 u_char cmd[2]; 349 350 cmd[0] = PMS_SET_RES; 351 cmd[1] = value; 352 return (pms_cmd(sc, cmd, 2, NULL, 0)); 353} 354 355int 356pms_set_scaling(struct pms_softc *sc, int scale) 357{ 358 u_char cmd[1]; 359 360 switch (scale) { 361 case 1: 362 default: 363 cmd[0] = PMS_SET_SCALE11; 364 break; 365 case 2: 366 cmd[0] = PMS_SET_SCALE21; 367 break; 368 } 369 return (pms_cmd(sc, cmd, 1, NULL, 0)); 370} 371 372int 373pms_reset(struct pms_softc *sc) 374{ 375 u_char cmd[1], resp[2]; 376 int res; 377 378 cmd[0] = PMS_RESET; 379 res = pms_cmd(sc, cmd, 1, resp, 2); 380#ifdef DEBUG 381 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) 382 printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n", 383 DEVNAME(sc), res, resp[0], resp[1]); 384#endif 385 return (res); 386} 387 388int 389pms_dev_enable(struct pms_softc *sc) 390{ 391 u_char cmd[1]; 392 int res; 393 394 cmd[0] = PMS_DEV_ENABLE; 395 res = pms_cmd(sc, cmd, 1, NULL, 0); 396 if (res) 397 printf("%s: enable error\n", DEVNAME(sc)); 398 return (res); 399} 400 401int 402pms_dev_disable(struct pms_softc *sc) 403{ 404 u_char cmd[1]; 405 int res; 406 407 cmd[0] = PMS_DEV_DISABLE; 408 res = pms_cmd(sc, cmd, 1, NULL, 0); 409 if (res) 410 printf("%s: disable error\n", DEVNAME(sc)); 411 return (res); 412} 413 414int 415pms_enable_intelli(struct pms_softc *sc) 416{ 417 u_char resp; 418 419 /* the special sequence to enable the third button and the roller */ 420 if (pms_set_rate(sc, PMS_INTELLI_MAGIC1) || 421 pms_set_rate(sc, PMS_INTELLI_MAGIC2) || 422 pms_set_rate(sc, PMS_INTELLI_MAGIC3) || 423 pms_get_devid(sc, &resp) || 424 resp != PMS_INTELLI_ID) 425 return (0); 426 427 return (1); 428} 429 430int 431pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 432 struct proc *p) 433{ 434 int i; 435 436 switch (cmd) { 437 case WSMOUSEIO_GTYPE: 438 *(u_int *)data = WSMOUSE_TYPE_PS2; 439 break; 440 case WSMOUSEIO_SRES: 441 i = ((int) *(u_int *)data - 12) / 25; 442 /* valid values are {0,1,2,3} */ 443 if (i < 0) 444 i = 0; 445 if (i > 3) 446 i = 3; 447 448 if (pms_set_resolution(sc, i)) 449 printf("%s: SET_RES command error\n", DEVNAME(sc)); 450 break; 451 default: 452 return (-1); 453 } 454 return (0); 455} 456 457int 458pms_sync_mouse(struct pms_softc *sc, int data) 459{ 460 if (sc->inputstate != 0) 461 return (0); 462 463 switch (sc->protocol->type) { 464 case PMS_STANDARD: 465 if ((data & 0xc0) != 0) 466 return (-1); 467 break; 468 case PMS_INTELLI: 469 if ((data & 0x08) != 0x08) 470 return (-1); 471 break; 472 } 473 474 return (0); 475} 476 477void 478pms_proc_mouse(struct pms_softc *sc) 479{ 480 u_int buttons; 481 int dx, dy, dz; 482 483 buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; 484 dx = (sc->packet[0] & PMS_PS2_XNEG) ? 485 (int)sc->packet[1] - 256 : sc->packet[1]; 486 dy = (sc->packet[0] & PMS_PS2_YNEG) ? 487 (int)sc->packet[2] - 256 : sc->packet[2]; 488 489 switch (sc->protocol->type) { 490 case PMS_STANDARD: 491 dz = 0; 492 break; 493 case PMS_INTELLI: 494 dz = (signed char)sc->packet[3]; 495 break; 496 } 497 498 wsmouse_input(sc->sc_wsmousedev, 499 buttons, dx, dy, dz, 0, WSMOUSE_INPUT_DELTA); 500} 501 502int 503pmsprobe(struct device *parent, void *match, void *aux) 504{ 505 struct pckbc_attach_args *pa = aux; 506 u_char cmd[1], resp[2]; 507 int res; 508 509 if (pa->pa_slot != PCKBC_AUX_SLOT) 510 return (0); 511 512 /* Flush any garbage. */ 513 pckbc_flush(pa->pa_tag, pa->pa_slot); 514 515 /* reset the device */ 516 cmd[0] = PMS_RESET; 517 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); 518 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { 519#ifdef DEBUG 520 printf("pms: reset error %d (response 0x%02x, type 0x%02x)\n", 521 res, resp[0], resp[1]); 522#endif 523 return (0); 524 } 525 526 return (1); 527} 528 529void 530pmsattach(struct device *parent, struct device *self, void *aux) 531{ 532 struct pms_softc *sc = (void *)self; 533 struct pckbc_attach_args *pa = aux; 534 struct wsmousedev_attach_args a; 535 int i; 536 537 sc->sc_kbctag = pa->pa_tag; 538 539 printf("\n"); 540 541 pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT, 542 pmsinput, sc, DEVNAME(sc)); 543 544 a.accessops = &pms_accessops; 545 a.accesscookie = sc; 546 547 /* 548 * Attach the wsmouse, saving a handle to it. 549 * Note that we don't need to check this pointer against NULL 550 * here or in pmsintr, because if this fails pms_enable() will 551 * never be called, so pmsinput() will never be called. 552 */ 553 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 554 555 sc->poll = 1; 556 sc->sc_dev_enable = 0; 557 558 sc->protocol = &pms_protocols[0]; 559 for (i = 1; i < nitems(pms_protocols); i++) { 560 pms_reset(sc); 561 if (pms_protocols[i].enable(sc)) 562 sc->protocol = &pms_protocols[i]; 563 } 564 565 DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type); 566 567 /* no interrupts until enabled */ 568 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE); 569} 570 571int 572pmsactivate(struct device *self, int act) 573{ 574 struct pms_softc *sc = (struct pms_softc *)self; 575 576 switch (act) { 577 case DVACT_SUSPEND: 578 if (sc->sc_state == PMS_STATE_ENABLED) 579 pms_change_state(sc, PMS_STATE_SUSPENDED, 580 PMS_DEV_IGNORE); 581 break; 582 case DVACT_RESUME: 583 if (sc->sc_state == PMS_STATE_SUSPENDED) 584 pms_change_state(sc, PMS_STATE_ENABLED, 585 PMS_DEV_IGNORE); 586 break; 587 } 588 return (0); 589} 590 591int 592pms_change_state(struct pms_softc *sc, int newstate, int dev) 593{ 594 int i; 595 596 if (dev != PMS_DEV_IGNORE) { 597 switch (newstate) { 598 case PMS_STATE_ENABLED: 599 if (sc->sc_dev_enable & dev) 600 return (EBUSY); 601 602 sc->sc_dev_enable |= dev; 603 604 if (sc->sc_state == PMS_STATE_ENABLED) 605 return (0); 606 607 break; 608 case PMS_STATE_DISABLED: 609 sc->sc_dev_enable &= ~dev; 610 611 if (sc->sc_dev_enable) 612 return (0); 613 614 break; 615 } 616 } 617 618 switch (newstate) { 619 case PMS_STATE_ENABLED: 620 sc->inputstate = 0; 621 622 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1); 623 624 if (sc->poll) 625 pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT); 626 627 pms_reset(sc); 628 629 if (sc->protocol->type != PMS_STANDARD && 630 sc->protocol->enable(sc) == 0) 631 sc->protocol = &pms_protocols[0]; 632 633 if (sc->protocol->type == PMS_STANDARD) 634 for (i = 1; i < nitems(pms_protocols); i++) { 635 pms_reset(sc); 636 if (pms_protocols[i].enable(sc)) 637 sc->protocol = &pms_protocols[i]; 638 } 639 640#ifdef DEBUG 641 printf("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type); 642#endif 643 644 pms_dev_enable(sc); 645 break; 646 case PMS_STATE_DISABLED: 647 case PMS_STATE_SUSPENDED: 648 pms_dev_disable(sc); 649 650 if (sc->protocol && sc->protocol->disable) 651 sc->protocol->disable(sc); 652 653 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0); 654 break; 655 } 656 657 sc->sc_state = newstate; 658 sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0; 659 660 return (0); 661} 662 663int 664pms_enable(void *v) 665{ 666 struct pms_softc *sc = v; 667 668 return pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY); 669} 670 671void 672pms_disable(void *v) 673{ 674 struct pms_softc *sc = v; 675 676 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY); 677} 678 679int 680pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 681{ 682 struct pms_softc *sc = v; 683 684 if (sc->protocol && sc->protocol->ioctl) 685 return (sc->protocol->ioctl(sc, cmd, data, flag, p)); 686 else 687 return (-1); 688} 689 690int 691pms_sec_enable(void *v) 692{ 693 struct pms_softc *sc = v; 694 695 return (pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY)); 696} 697 698void 699pms_sec_disable(void *v) 700{ 701 struct pms_softc *sc = v; 702 703 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY); 704} 705 706int 707pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 708{ 709 switch (cmd) { 710 case WSMOUSEIO_GTYPE: 711 *(u_int *)data = WSMOUSE_TYPE_PS2; 712 break; 713 default: 714 return (-1); 715 } 716 return (0); 717} 718 719void 720pmsinput(void *vsc, int data) 721{ 722 struct pms_softc *sc = vsc; 723 724 if (sc->sc_state != PMS_STATE_ENABLED) { 725 /* Interrupts are not expected. Discard the byte. */ 726 return; 727 } 728 729 if (sc->protocol->sync(sc, data)) { 730#ifdef DIAGNOSTIC 731 printf("%s: not in sync yet, discard input\n", DEVNAME(sc)); 732#endif 733 sc->inputstate = 0; 734 return; 735 } 736 737 sc->packet[sc->inputstate++] = data; 738 739 if (sc->inputstate != sc->protocol->packetsize) 740 return; 741 742 sc->protocol->proc(sc); 743 sc->inputstate = 0; 744} 745 746int 747synaptics_set_mode(struct pms_softc *sc, int mode) 748{ 749 struct synaptics_softc *syn = sc->synaptics; 750 751 if (pms_spec_cmd(sc, mode) || 752 pms_set_rate(sc, SYNAPTICS_CMD_SET_MODE)) 753 return (-1); 754 755 syn->mode = mode; 756 757 return (0); 758} 759 760int 761synaptics_query(struct pms_softc *sc, int query, int *val) 762{ 763 u_char resp[3]; 764 765 if (pms_spec_cmd(sc, query) || 766 pms_get_status(sc, resp)) 767 return (-1); 768 769 if (val) 770 *val = (resp[0] << 16) | (resp[1] << 8) | resp[2]; 771 772 return (0); 773} 774 775int 776synaptics_get_hwinfo(struct pms_softc *sc) 777{ 778 struct synaptics_softc *syn = sc->synaptics; 779 780 if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify)) 781 return (-1); 782 if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES, 783 &syn->capabilities)) 784 return (-1); 785 if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model)) 786 return (-1); 787 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) && 788 synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model)) 789 return (-1); 790 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) && 791 synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES, 792 &syn->ext_capabilities)) 793 return (-1); 794 if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) && 795 synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &syn->resolution)) 796 return (-1); 797 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) && 798 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_DIMENSIONS) && 799 synaptics_query(sc, SYNAPTICS_QUE_EXT_DIMENSIONS, &syn->dimension)) 800 return (-1); 801 802 syn->res_x = SYNAPTICS_RESOLUTION_X(syn->resolution); 803 syn->res_y = SYNAPTICS_RESOLUTION_Y(syn->resolution); 804 syn->min_x = SYNAPTICS_XMIN_BEZEL; 805 syn->min_y = SYNAPTICS_YMIN_BEZEL; 806 syn->max_x = (syn->dimension) ? 807 SYNAPTICS_DIM_X(syn->dimension) : SYNAPTICS_XMAX_BEZEL; 808 syn->max_y = (syn->dimension) ? 809 SYNAPTICS_DIM_Y(syn->dimension) : SYNAPTICS_YMAX_BEZEL; 810 811 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8) 812 syn->ext_model &= ~0xf000; 813 814 return (0); 815} 816 817void 818synaptics_sec_proc(struct pms_softc *sc) 819{ 820 u_int buttons; 821 int dx, dy; 822 823 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 824 return; 825 826 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK]; 827 dx = (sc->packet[1] & PMS_PS2_XNEG) ? 828 (int)sc->packet[4] - 256 : sc->packet[4]; 829 dy = (sc->packet[1] & PMS_PS2_YNEG) ? 830 (int)sc->packet[5] - 256 : sc->packet[5]; 831 832 wsmouse_input(sc->sc_sec_wsmousedev, 833 buttons, dx, dy, 0, 0, WSMOUSE_INPUT_DELTA); 834} 835 836int 837pms_enable_synaptics(struct pms_softc *sc) 838{ 839 struct synaptics_softc *syn = sc->synaptics; 840 struct wsmousedev_attach_args a; 841 u_char resp[3]; 842 int mode; 843 844 if (pms_set_resolution(sc, 0) || 845 pms_set_resolution(sc, 0) || 846 pms_set_resolution(sc, 0) || 847 pms_set_resolution(sc, 0) || 848 pms_get_status(sc, resp) || 849 resp[1] != SYNAPTICS_ID_MAGIC) 850 return (0); 851 852 if (sc->synaptics == NULL) { 853 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc), 854 M_DEVBUF, M_WAITOK | M_ZERO); 855 if (syn == NULL) { 856 printf("%s: synaptics: not enough memory\n", 857 DEVNAME(sc)); 858 return (0); 859 } 860 861 if (synaptics_get_hwinfo(sc)) 862 return (0); 863 864 if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) { 865 printf("%s: don't support Synaptics OLDABS\n", 866 DEVNAME(sc)); 867 return (0); 868 } 869 870 /* enable pass-through PS/2 port if supported */ 871 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) { 872 a.accessops = &pms_sec_accessops; 873 a.accesscookie = sc; 874 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 875 wsmousedevprint); 876 } 877 878 syn->wsmode = WSMOUSE_COMPAT; 879 880 printf("%s: Synaptics %s, firmware %d.%d\n", DEVNAME(sc), 881 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ? 882 "clickpad" : "touchpad"), 883 SYNAPTICS_ID_MAJOR(syn->identify), 884 SYNAPTICS_ID_MINOR(syn->identify)); 885 } 886 887 mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE; 888 if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4) 889 mode |= SYNAPTICS_DISABLE_GESTURE; 890 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED) 891 mode |= SYNAPTICS_W_MODE; 892 if (synaptics_set_mode(sc, mode)) 893 return (0); 894 895 /* enable advanced gesture mode if supported */ 896 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && 897 (pms_spec_cmd(sc, SYNAPTICS_QUE_MODEL) || 898 pms_set_rate(sc, SYNAPTICS_CMD_SET_ADV_GESTURE_MODE))) 899 return (0); 900 901 return (1); 902} 903 904int 905pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 906 struct proc *p) 907{ 908 struct synaptics_softc *syn = sc->synaptics; 909 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 910 int wsmode; 911 912 switch (cmd) { 913 case WSMOUSEIO_GTYPE: 914 *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS; 915 break; 916 case WSMOUSEIO_GCALIBCOORDS: 917 wsmc->minx = syn->min_x; 918 wsmc->maxx = syn->max_x; 919 wsmc->miny = syn->min_y; 920 wsmc->maxy = syn->max_y; 921 wsmc->swapxy = 0; 922 wsmc->resx = syn->res_x; 923 wsmc->resy = syn->res_y; 924 break; 925 case WSMOUSEIO_SETMODE: 926 wsmode = *(u_int *)data; 927 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 928 return (EINVAL); 929 syn->wsmode = wsmode; 930 break; 931 default: 932 return (-1); 933 } 934 return (0); 935} 936 937int 938pms_sync_synaptics(struct pms_softc *sc, int data) 939{ 940 switch (sc->inputstate) { 941 case 0: 942 if ((data & 0xc8) != 0x80) 943 return (-1); 944 break; 945 case 3: 946 if ((data & 0xc8) != 0xc0) 947 return (-1); 948 break; 949 } 950 951 return (0); 952} 953 954void 955pms_proc_synaptics(struct pms_softc *sc) 956{ 957 struct synaptics_softc *syn = sc->synaptics; 958 u_int buttons; 959 int x, y, z, w, dx, dy; 960 961 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) | 962 ((sc->packet[3] & 0x04) >> 2); 963 964 if ((syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) && w == 3) { 965 synaptics_sec_proc(sc); 966 return; 967 } 968 969 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 970 return; 971 972 /* XXX ignore advanced gesture packet, not yet supported */ 973 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && w == 2) 974 return; 975 976 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) | 977 sc->packet[4]; 978 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) | 979 sc->packet[5]; 980 z = sc->packet[2]; 981 982 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ? 983 WSMOUSE_BUTTON(1) : 0; 984 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ? 985 WSMOUSE_BUTTON(3) : 0; 986 987 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) { 988 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 989 WSMOUSE_BUTTON(1) : 0; 990 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) { 991 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 992 WSMOUSE_BUTTON(2) : 0; 993 } 994 995 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) { 996 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 997 WSMOUSE_BUTTON(4) : 0; 998 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ? 999 WSMOUSE_BUTTON(5) : 0; 1000 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) && 1001 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) { 1002 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0; 1003 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0; 1004 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0; 1005 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0; 1006 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0; 1007 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0; 1008 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0; 1009 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0; 1010 x &= ~0x0f; 1011 y &= ~0x0f; 1012 } 1013 1014 /* ignore final events that happen when removing all fingers */ 1015 if (x <= 1 || y <= 1) { 1016 x = syn->old_x; 1017 y = syn->old_y; 1018 } 1019 1020 if (syn->wsmode == WSMOUSE_NATIVE) { 1021 wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, w, 1022 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | 1023 WSMOUSE_INPUT_ABSOLUTE_Z | WSMOUSE_INPUT_ABSOLUTE_W); 1024 } else { 1025 dx = dy = 0; 1026 if (z > SYNAPTICS_PRESSURE) { 1027 dx = x - syn->old_x; 1028 dy = y - syn->old_y; 1029 dx /= SYNAPTICS_SCALE; 1030 dy /= SYNAPTICS_SCALE; 1031 } 1032 if (dx || dy || buttons != syn->old_buttons) 1033 wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0, 1034 WSMOUSE_INPUT_DELTA); 1035 syn->old_buttons = buttons; 1036 } 1037 1038 syn->old_x = x; 1039 syn->old_y = y; 1040} 1041 1042void 1043pms_disable_synaptics(struct pms_softc *sc) 1044{ 1045 struct synaptics_softc *syn = sc->synaptics; 1046 1047 if (syn->capabilities & SYNAPTICS_CAP_SLEEP) 1048 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE | 1049 SYNAPTICS_DISABLE_GESTURE); 1050} 1051 1052int 1053alps_get_hwinfo(struct pms_softc *sc) 1054{ 1055 struct alps_softc *alps = sc->alps; 1056 u_char resp[3]; 1057 int i; 1058 1059 if (pms_set_resolution(sc, 0) || 1060 pms_set_scaling(sc, 2) || 1061 pms_set_scaling(sc, 2) || 1062 pms_set_scaling(sc, 2) || 1063 pms_get_status(sc, resp)) { 1064 DPRINTF("%s: alps: model query error\n", DEVNAME(sc)); 1065 return (-1); 1066 } 1067 1068 alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1); 1069 1070 for (i = 0; i < nitems(alps_models); i++) 1071 if (alps->version == alps_models[i].version) { 1072 alps->model = alps_models[i].model; 1073 alps->mask = alps_models[i].mask; 1074 return (0); 1075 } 1076 1077 return (-1); 1078} 1079 1080int 1081pms_enable_alps(struct pms_softc *sc) 1082{ 1083 struct alps_softc *alps = sc->alps; 1084 struct wsmousedev_attach_args a; 1085 u_char resp[3]; 1086 1087 if (pms_set_resolution(sc, 0) || 1088 pms_set_scaling(sc, 1) || 1089 pms_set_scaling(sc, 1) || 1090 pms_set_scaling(sc, 1) || 1091 pms_get_status(sc, resp) || 1092 resp[0] != PMS_ALPS_MAGIC1 || 1093 resp[1] != PMS_ALPS_MAGIC2 || 1094 (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2)) 1095 return (0); 1096 1097 if (sc->alps == NULL) { 1098 sc->alps = alps = malloc(sizeof(struct alps_softc), 1099 M_DEVBUF, M_WAITOK | M_ZERO); 1100 if (alps == NULL) { 1101 printf("%s: alps: not enough memory\n", DEVNAME(sc)); 1102 goto err; 1103 } 1104 1105 if (alps_get_hwinfo(sc)) 1106 goto err; 1107 1108 printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc), 1109 (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"), 1110 alps->version); 1111 1112 alps->min_x = ALPS_XMIN_BEZEL; 1113 alps->min_y = ALPS_YMIN_BEZEL; 1114 alps->max_x = ALPS_XMAX_BEZEL; 1115 alps->max_y = ALPS_YMAX_BEZEL; 1116 1117 alps->wsmode = WSMOUSE_COMPAT; 1118 1119 if (alps->model & ALPS_DUALPOINT) { 1120 a.accessops = &pms_sec_accessops; 1121 a.accesscookie = sc; 1122 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 1123 wsmousedevprint); 1124 } 1125 } 1126 1127 if (alps->model == 0) 1128 goto err; 1129 1130 if ((alps->model & ALPS_PASSTHROUGH) && 1131 (pms_set_scaling(sc, 2) || 1132 pms_set_scaling(sc, 2) || 1133 pms_set_scaling(sc, 2) || 1134 pms_dev_disable(sc))) { 1135 DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc)); 1136 goto err; 1137 } 1138 1139 if (pms_dev_disable(sc) || 1140 pms_dev_disable(sc) || 1141 pms_set_rate(sc, 0x0a)) { 1142 DPRINTF("%s: alps: tapping error\n", DEVNAME(sc)); 1143 goto err; 1144 } 1145 1146 if (pms_dev_disable(sc) || 1147 pms_dev_disable(sc) || 1148 pms_dev_disable(sc) || 1149 pms_dev_disable(sc) || 1150 pms_dev_enable(sc)) { 1151 DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc)); 1152 goto err; 1153 } 1154 1155 if ((alps->model & ALPS_PASSTHROUGH) && 1156 (pms_set_scaling(sc, 1) || 1157 pms_set_scaling(sc, 1) || 1158 pms_set_scaling(sc, 1) || 1159 pms_dev_disable(sc))) { 1160 DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc)); 1161 goto err; 1162 } 1163 1164 return (1); 1165 1166err: 1167 pms_reset(sc); 1168 1169 return (0); 1170} 1171 1172int 1173pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 1174 struct proc *p) 1175{ 1176 struct alps_softc *alps = sc->alps; 1177 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1178 int wsmode; 1179 1180 switch (cmd) { 1181 case WSMOUSEIO_GTYPE: 1182 *(u_int *)data = WSMOUSE_TYPE_ALPS; 1183 break; 1184 case WSMOUSEIO_GCALIBCOORDS: 1185 wsmc->minx = alps->min_x; 1186 wsmc->maxx = alps->max_x; 1187 wsmc->miny = alps->min_y; 1188 wsmc->maxy = alps->max_y; 1189 wsmc->swapxy = 0; 1190 break; 1191 case WSMOUSEIO_SETMODE: 1192 wsmode = *(u_int *)data; 1193 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 1194 return (EINVAL); 1195 alps->wsmode = wsmode; 1196 break; 1197 default: 1198 return (-1); 1199 } 1200 return (0); 1201} 1202 1203int 1204pms_sync_alps(struct pms_softc *sc, int data) 1205{ 1206 struct alps_softc *alps = sc->alps; 1207 1208 switch (sc->inputstate) { 1209 case 0: 1210 if ((data & alps->mask) != alps->mask) 1211 return (-1); 1212 break; 1213 case 1: 1214 case 2: 1215 case 3: 1216 case 4: 1217 case 5: 1218 if ((data & 0x80) != 0) 1219 return (-1); 1220 break; 1221 } 1222 1223 return (0); 1224} 1225 1226void 1227pms_proc_alps(struct pms_softc *sc) 1228{ 1229 struct alps_softc *alps = sc->alps; 1230 int x, y, z, dx, dy; 1231 u_int buttons; 1232 int fin, ges; 1233 1234 x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4); 1235 y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3); 1236 z = sc->packet[5]; 1237 1238 buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) | 1239 ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) | 1240 ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0); 1241 1242 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) && z == ALPS_Z_MAGIC) { 1243 dx = (x > ALPS_XSEC_BEZEL / 2) ? (x - ALPS_XSEC_BEZEL) : x; 1244 dy = (y > ALPS_YSEC_BEZEL / 2) ? (y - ALPS_YSEC_BEZEL) : y; 1245 1246 wsmouse_input(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0, 1247 WSMOUSE_INPUT_DELTA); 1248 1249 return; 1250 } 1251 1252 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 1253 return; 1254 1255 /* 1256 * XXX The Y-axis is in the oposit direction compared to 1257 * Synaptics touchpads and PS/2 mouses. 1258 * It's why we need to translate the y value here for both 1259 * NATIVE and COMPAT modes. 1260 */ 1261 y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL; 1262 1263 if (alps->wsmode == WSMOUSE_NATIVE) { 1264 ges = sc->packet[2] & 0x01; 1265 fin = sc->packet[2] & 0x02; 1266 1267 /* Simulate click (tap) */ 1268 if (ges && !fin) 1269 z = 35; 1270 1271 /* Generate a null pressure event (needed for tap & drag) */ 1272 if (ges && fin && !alps->old_fin) 1273 z = 0; 1274 1275 wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, 0, 1276 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | 1277 WSMOUSE_INPUT_ABSOLUTE_Z); 1278 1279 alps->old_fin = fin; 1280 } else { 1281 dx = dy = 0; 1282 if (z > ALPS_PRESSURE) { 1283 dx = x - alps->old_x; 1284 dy = y - alps->old_y; 1285 1286 /* Prevent jump */ 1287 dx = abs(dx) > 50 ? 0 : dx; 1288 dy = abs(dy) > 50 ? 0 : dy; 1289 } 1290 1291 if (dx || dy || buttons != alps->old_buttons) 1292 wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0, 1293 WSMOUSE_INPUT_DELTA); 1294 1295 alps->old_x = x; 1296 alps->old_y = y; 1297 alps->old_buttons = buttons; 1298 } 1299} 1300