1 /* $OpenBSD: pms.c,v 1.70 2016/05/22 22:06:11 bru 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/rwlock.h> 30 #include <sys/device.h> 31 #include <sys/ioctl.h> 32 #include <sys/malloc.h> 33 34 #include <machine/bus.h> 35 36 #include <dev/ic/pckbcvar.h> 37 38 #include <dev/pckbc/pmsreg.h> 39 40 #include <dev/wscons/wsconsio.h> 41 #include <dev/wscons/wsmousevar.h> 42 43 #if defined(__i386__) || defined(__amd64__) 44 #include "acpi.h" 45 #endif 46 47 #if !defined(SMALL_KERNEL) && NACPI > 0 48 extern int mouse_has_softbtn; 49 #else 50 int mouse_has_softbtn; 51 #endif 52 53 #ifdef DEBUG 54 #define DPRINTF(x...) do { printf(x); } while (0); 55 #else 56 #define DPRINTF(x...) 57 #endif 58 59 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 60 61 #define WSMOUSE_BUTTON(x) (1 << ((x) - 1)) 62 63 struct pms_softc; 64 65 struct pms_protocol { 66 int type; 67 #define PMS_STANDARD 0 68 #define PMS_INTELLI 1 69 #define PMS_SYNAPTICS 2 70 #define PMS_ALPS 3 71 #define PMS_ELANTECH_V1 4 72 #define PMS_ELANTECH_V2 5 73 #define PMS_ELANTECH_V3 6 74 #define PMS_ELANTECH_V4 7 75 u_int packetsize; 76 int (*enable)(struct pms_softc *); 77 int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *); 78 int (*sync)(struct pms_softc *, int); 79 void (*proc)(struct pms_softc *); 80 void (*disable)(struct pms_softc *); 81 }; 82 83 struct synaptics_softc { 84 int identify; 85 int capabilities, ext_capabilities, ext2_capabilities; 86 int model, ext_model; 87 int resolution, dimension; 88 int modes; 89 90 int mode; 91 92 int mask; 93 #define SYNAPTICS_MASK_NEWABS_STRICT 0xc8 94 #define SYNAPTICS_MASK_NEWABS_RELAXED 0xc0 95 #define SYNAPTICS_VALID_NEWABS_FIRST 0x80 96 #define SYNAPTICS_VALID_NEWABS_NEXT 0xc0 97 98 int res_x, res_y; 99 int min_x, min_y; 100 int max_x, max_y; 101 102 /* Compat mode */ 103 int wsmode; 104 int old_x, old_y; 105 u_int old_buttons; 106 u_int sec_buttons; 107 #define SYNAPTICS_SCALE 4 108 #define SYNAPTICS_PRESSURE 30 109 }; 110 111 struct alps_softc { 112 int model; 113 #define ALPS_GLIDEPOINT (1 << 1) 114 #define ALPS_DUALPOINT (1 << 2) 115 #define ALPS_PASSTHROUGH (1 << 3) 116 #define ALPS_INTERLEAVED (1 << 4) 117 118 int mask; 119 int version; 120 121 int min_x, min_y; 122 int max_x, max_y; 123 124 u_int gesture; 125 126 u_int sec_buttons; /* trackpoint */ 127 128 /* Compat mode */ 129 int wsmode; 130 int old_x, old_y; 131 u_int old_buttons; 132 #define ALPS_PRESSURE 40 133 }; 134 135 struct elantech_softc { 136 int flags; 137 #define ELANTECH_F_REPORTS_PRESSURE 0x01 138 #define ELANTECH_F_HAS_ROCKER 0x02 139 #define ELANTECH_F_2FINGER_PACKET 0x04 140 #define ELANTECH_F_HW_V1_OLD 0x08 141 #define ELANTECH_F_CRC_ENABLED 0x10 142 int fw_version; 143 144 int min_x, min_y; 145 int max_x, max_y; 146 147 u_int mt_slots; 148 149 int width; 150 151 u_char parity[256]; 152 u_char p1, p2, p3; 153 154 /* Compat mode */ 155 int wsmode; 156 int old_x, old_y; 157 u_int old_buttons; 158 }; 159 160 struct pms_softc { /* driver status information */ 161 struct device sc_dev; 162 163 pckbc_tag_t sc_kbctag; 164 165 int sc_state; 166 #define PMS_STATE_DISABLED 0 167 #define PMS_STATE_ENABLED 1 168 #define PMS_STATE_SUSPENDED 2 169 170 struct rwlock sc_state_lock; 171 172 int sc_dev_enable; 173 #define PMS_DEV_IGNORE 0x00 174 #define PMS_DEV_PRIMARY 0x01 175 #define PMS_DEV_SECONDARY 0x02 176 177 int poll; 178 int inputstate; 179 180 const struct pms_protocol *protocol; 181 struct synaptics_softc *synaptics; 182 struct alps_softc *alps; 183 struct elantech_softc *elantech; 184 185 u_char packet[8]; 186 187 struct device *sc_wsmousedev; 188 struct device *sc_sec_wsmousedev; 189 }; 190 191 static const u_int butmap[8] = { 192 0, 193 WSMOUSE_BUTTON(1), 194 WSMOUSE_BUTTON(3), 195 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(3), 196 WSMOUSE_BUTTON(2), 197 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2), 198 WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3), 199 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3) 200 }; 201 202 static const struct alps_model { 203 int version; 204 int mask; 205 int model; 206 } alps_models[] = { 207 { 0x2021, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 208 { 0x2221, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 209 { 0x2222, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 210 { 0x3222, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 211 { 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED }, 212 { 0x5321, 0xf8, ALPS_GLIDEPOINT }, 213 { 0x5322, 0xf8, ALPS_GLIDEPOINT }, 214 { 0x603b, 0xf8, ALPS_GLIDEPOINT }, 215 { 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED }, 216 { 0x6321, 0xf8, ALPS_GLIDEPOINT }, 217 { 0x6322, 0xf8, ALPS_GLIDEPOINT }, 218 { 0x6323, 0xf8, ALPS_GLIDEPOINT }, 219 { 0x6324, 0x8f, ALPS_GLIDEPOINT }, 220 { 0x6325, 0xef, ALPS_GLIDEPOINT }, 221 { 0x6326, 0xf8, ALPS_GLIDEPOINT }, 222 { 0x7301, 0xf8, ALPS_DUALPOINT }, 223 { 0x7321, 0xf8, ALPS_GLIDEPOINT }, 224 { 0x7322, 0xf8, ALPS_GLIDEPOINT }, 225 { 0x7325, 0xcf, ALPS_GLIDEPOINT }, 226 #if 0 227 /* 228 * This model has a clitpad sending almost compatible PS2 229 * packets but not compatible enough to be used with the 230 * ALPS protocol. 231 */ 232 { 0x633b, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH }, 233 234 { 0x7326, 0, 0 }, /* XXX Uses unknown v3 protocol */ 235 #endif 236 }; 237 238 int pmsprobe(struct device *, void *, void *); 239 void pmsattach(struct device *, struct device *, void *); 240 int pmsactivate(struct device *, int); 241 242 void pmsinput(void *, int); 243 244 int pms_change_state(struct pms_softc *, int, int); 245 246 int pms_ioctl(void *, u_long, caddr_t, int, struct proc *); 247 int pms_enable(void *); 248 void pms_disable(void *); 249 250 int pms_sec_ioctl(void *, u_long, caddr_t, int, struct proc *); 251 int pms_sec_enable(void *); 252 void pms_sec_disable(void *); 253 254 int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int); 255 int pms_spec_cmd(struct pms_softc *, int); 256 int pms_get_devid(struct pms_softc *, u_char *); 257 int pms_get_status(struct pms_softc *, u_char *); 258 int pms_set_rate(struct pms_softc *, int); 259 int pms_set_resolution(struct pms_softc *, int); 260 int pms_set_scaling(struct pms_softc *, int); 261 int pms_reset(struct pms_softc *); 262 int pms_dev_enable(struct pms_softc *); 263 int pms_dev_disable(struct pms_softc *); 264 void pms_protocol_lookup(struct pms_softc *); 265 266 int pms_enable_intelli(struct pms_softc *); 267 268 int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *); 269 int pms_sync_mouse(struct pms_softc *, int); 270 void pms_proc_mouse(struct pms_softc *); 271 272 int pms_enable_synaptics(struct pms_softc *); 273 int pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *); 274 int pms_sync_synaptics(struct pms_softc *, int); 275 void pms_proc_synaptics(struct pms_softc *); 276 void pms_disable_synaptics(struct pms_softc *); 277 278 int pms_enable_alps(struct pms_softc *); 279 int pms_ioctl_alps(struct pms_softc *, u_long, caddr_t, int, struct proc *); 280 int pms_sync_alps(struct pms_softc *, int); 281 void pms_proc_alps(struct pms_softc *); 282 283 int pms_enable_elantech_v1(struct pms_softc *); 284 int pms_enable_elantech_v2(struct pms_softc *); 285 int pms_enable_elantech_v3(struct pms_softc *); 286 int pms_enable_elantech_v4(struct pms_softc *); 287 int pms_ioctl_elantech(struct pms_softc *, u_long, caddr_t, int, 288 struct proc *); 289 int pms_sync_elantech_v1(struct pms_softc *, int); 290 int pms_sync_elantech_v2(struct pms_softc *, int); 291 int pms_sync_elantech_v3(struct pms_softc *, int); 292 int pms_sync_elantech_v4(struct pms_softc *, int); 293 void pms_proc_elantech_v1(struct pms_softc *); 294 void pms_proc_elantech_v2(struct pms_softc *); 295 void pms_proc_elantech_v3(struct pms_softc *); 296 void pms_proc_elantech_v4(struct pms_softc *); 297 298 int synaptics_knock(struct pms_softc *); 299 int synaptics_set_mode(struct pms_softc *, int); 300 int synaptics_query(struct pms_softc *, int, int *); 301 int synaptics_get_hwinfo(struct pms_softc *); 302 void synaptics_sec_proc(struct pms_softc *); 303 304 int alps_sec_proc(struct pms_softc *); 305 int alps_get_hwinfo(struct pms_softc *); 306 307 int elantech_knock(struct pms_softc *); 308 void elantech_send_input(struct pms_softc *, int, int, int, int); 309 int elantech_get_hwinfo_v1(struct pms_softc *); 310 int elantech_get_hwinfo_v2(struct pms_softc *); 311 int elantech_get_hwinfo_v3(struct pms_softc *); 312 int elantech_get_hwinfo_v4(struct pms_softc *); 313 int elantech_ps2_cmd(struct pms_softc *, u_char); 314 int elantech_set_absolute_mode_v1(struct pms_softc *); 315 int elantech_set_absolute_mode_v2(struct pms_softc *); 316 int elantech_set_absolute_mode_v3(struct pms_softc *); 317 int elantech_set_absolute_mode_v4(struct pms_softc *); 318 319 void elantech_send_mt_input(struct pms_softc *, int); 320 321 struct cfattach pms_ca = { 322 sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, 323 pmsactivate 324 }; 325 326 struct cfdriver pms_cd = { 327 NULL, "pms", DV_DULL 328 }; 329 330 const struct wsmouse_accessops pms_accessops = { 331 pms_enable, 332 pms_ioctl, 333 pms_disable, 334 }; 335 336 const struct wsmouse_accessops pms_sec_accessops = { 337 pms_sec_enable, 338 pms_sec_ioctl, 339 pms_sec_disable, 340 }; 341 342 const struct pms_protocol pms_protocols[] = { 343 /* Generic PS/2 mouse */ 344 { 345 PMS_STANDARD, 3, 346 NULL, 347 pms_ioctl_mouse, 348 pms_sync_mouse, 349 pms_proc_mouse, 350 NULL 351 }, 352 /* Synaptics touchpad */ 353 { 354 PMS_SYNAPTICS, 6, 355 pms_enable_synaptics, 356 pms_ioctl_synaptics, 357 pms_sync_synaptics, 358 pms_proc_synaptics, 359 pms_disable_synaptics 360 }, 361 /* ALPS touchpad */ 362 { 363 PMS_ALPS, 6, 364 pms_enable_alps, 365 pms_ioctl_alps, 366 pms_sync_alps, 367 pms_proc_alps, 368 NULL 369 }, 370 /* Elantech touchpad (hardware version 1) */ 371 { 372 PMS_ELANTECH_V1, 4, 373 pms_enable_elantech_v1, 374 pms_ioctl_elantech, 375 pms_sync_elantech_v1, 376 pms_proc_elantech_v1, 377 NULL 378 }, 379 /* Elantech touchpad (hardware version 2) */ 380 { 381 PMS_ELANTECH_V2, 6, 382 pms_enable_elantech_v2, 383 pms_ioctl_elantech, 384 pms_sync_elantech_v2, 385 pms_proc_elantech_v2, 386 NULL 387 }, 388 /* Elantech touchpad (hardware version 3) */ 389 { 390 PMS_ELANTECH_V3, 6, 391 pms_enable_elantech_v3, 392 pms_ioctl_elantech, 393 pms_sync_elantech_v3, 394 pms_proc_elantech_v3, 395 NULL 396 }, 397 /* Elantech touchpad (hardware version 4) */ 398 { 399 PMS_ELANTECH_V4, 6, 400 pms_enable_elantech_v4, 401 pms_ioctl_elantech, 402 pms_sync_elantech_v4, 403 pms_proc_elantech_v4, 404 NULL 405 }, 406 /* Microsoft IntelliMouse */ 407 { 408 PMS_INTELLI, 4, 409 pms_enable_intelli, 410 pms_ioctl_mouse, 411 pms_sync_mouse, 412 pms_proc_mouse, 413 NULL 414 }, 415 }; 416 417 int 418 pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen) 419 { 420 if (sc->poll) { 421 return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 422 cmd, len, resplen, resp, 1); 423 } else { 424 return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 425 cmd, len, resplen, 1, resp); 426 } 427 } 428 429 int 430 pms_spec_cmd(struct pms_softc *sc, int cmd) 431 { 432 if (pms_set_scaling(sc, 1) || 433 pms_set_resolution(sc, (cmd >> 6) & 0x03) || 434 pms_set_resolution(sc, (cmd >> 4) & 0x03) || 435 pms_set_resolution(sc, (cmd >> 2) & 0x03) || 436 pms_set_resolution(sc, (cmd >> 0) & 0x03)) 437 return (-1); 438 return (0); 439 } 440 441 int 442 pms_get_devid(struct pms_softc *sc, u_char *resp) 443 { 444 u_char cmd[1]; 445 446 cmd[0] = PMS_SEND_DEV_ID; 447 return (pms_cmd(sc, cmd, 1, resp, 1)); 448 } 449 450 int 451 pms_get_status(struct pms_softc *sc, u_char *resp) 452 { 453 u_char cmd[1]; 454 455 cmd[0] = PMS_SEND_DEV_STATUS; 456 return (pms_cmd(sc, cmd, 1, resp, 3)); 457 } 458 459 int 460 pms_set_rate(struct pms_softc *sc, int value) 461 { 462 u_char cmd[2]; 463 464 cmd[0] = PMS_SET_SAMPLE; 465 cmd[1] = value; 466 return (pms_cmd(sc, cmd, 2, NULL, 0)); 467 } 468 469 int 470 pms_set_resolution(struct pms_softc *sc, int value) 471 { 472 u_char cmd[2]; 473 474 cmd[0] = PMS_SET_RES; 475 cmd[1] = value; 476 return (pms_cmd(sc, cmd, 2, NULL, 0)); 477 } 478 479 int 480 pms_set_scaling(struct pms_softc *sc, int scale) 481 { 482 u_char cmd[1]; 483 484 switch (scale) { 485 case 1: 486 default: 487 cmd[0] = PMS_SET_SCALE11; 488 break; 489 case 2: 490 cmd[0] = PMS_SET_SCALE21; 491 break; 492 } 493 return (pms_cmd(sc, cmd, 1, NULL, 0)); 494 } 495 496 int 497 pms_reset(struct pms_softc *sc) 498 { 499 u_char cmd[1], resp[2]; 500 int res; 501 502 cmd[0] = PMS_RESET; 503 res = pms_cmd(sc, cmd, 1, resp, 2); 504 #ifdef DEBUG 505 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) 506 printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n", 507 DEVNAME(sc), res, resp[0], resp[1]); 508 #endif 509 return (res); 510 } 511 512 int 513 pms_dev_enable(struct pms_softc *sc) 514 { 515 u_char cmd[1]; 516 int res; 517 518 cmd[0] = PMS_DEV_ENABLE; 519 res = pms_cmd(sc, cmd, 1, NULL, 0); 520 if (res) 521 printf("%s: enable error\n", DEVNAME(sc)); 522 return (res); 523 } 524 525 int 526 pms_dev_disable(struct pms_softc *sc) 527 { 528 u_char cmd[1]; 529 int res; 530 531 cmd[0] = PMS_DEV_DISABLE; 532 res = pms_cmd(sc, cmd, 1, NULL, 0); 533 if (res) 534 printf("%s: disable error\n", DEVNAME(sc)); 535 return (res); 536 } 537 538 void 539 pms_protocol_lookup(struct pms_softc *sc) 540 { 541 int i; 542 543 sc->protocol = &pms_protocols[0]; 544 for (i = 1; i < nitems(pms_protocols); i++) { 545 pms_reset(sc); 546 if (pms_protocols[i].enable(sc)) { 547 sc->protocol = &pms_protocols[i]; 548 break; 549 } 550 } 551 552 DPRINTF("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type); 553 } 554 555 int 556 pms_enable_intelli(struct pms_softc *sc) 557 { 558 u_char resp; 559 560 /* the special sequence to enable the third button and the roller */ 561 if (pms_set_rate(sc, PMS_INTELLI_MAGIC1) || 562 pms_set_rate(sc, PMS_INTELLI_MAGIC2) || 563 pms_set_rate(sc, PMS_INTELLI_MAGIC3) || 564 pms_get_devid(sc, &resp) || 565 resp != PMS_INTELLI_ID) 566 return (0); 567 568 return (1); 569 } 570 571 int 572 pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 573 struct proc *p) 574 { 575 int i; 576 577 switch (cmd) { 578 case WSMOUSEIO_GTYPE: 579 *(u_int *)data = WSMOUSE_TYPE_PS2; 580 break; 581 case WSMOUSEIO_SRES: 582 i = ((int) *(u_int *)data - 12) / 25; 583 /* valid values are {0,1,2,3} */ 584 if (i < 0) 585 i = 0; 586 if (i > 3) 587 i = 3; 588 589 if (pms_set_resolution(sc, i)) 590 printf("%s: SET_RES command error\n", DEVNAME(sc)); 591 break; 592 default: 593 return (-1); 594 } 595 return (0); 596 } 597 598 int 599 pms_sync_mouse(struct pms_softc *sc, int data) 600 { 601 if (sc->inputstate != 0) 602 return (0); 603 604 switch (sc->protocol->type) { 605 case PMS_STANDARD: 606 if ((data & 0xc0) != 0) 607 return (-1); 608 break; 609 case PMS_INTELLI: 610 if ((data & 0x08) != 0x08) 611 return (-1); 612 break; 613 } 614 615 return (0); 616 } 617 618 void 619 pms_proc_mouse(struct pms_softc *sc) 620 { 621 u_int buttons; 622 int dx, dy, dz; 623 624 buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; 625 dx = (sc->packet[0] & PMS_PS2_XNEG) ? 626 (int)sc->packet[1] - 256 : sc->packet[1]; 627 dy = (sc->packet[0] & PMS_PS2_YNEG) ? 628 (int)sc->packet[2] - 256 : sc->packet[2]; 629 630 if (sc->protocol->type == PMS_INTELLI) 631 dz = (signed char)sc->packet[3]; 632 else 633 dz = 0; 634 635 WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, dz, 0); 636 } 637 638 int 639 pmsprobe(struct device *parent, void *match, void *aux) 640 { 641 struct pckbc_attach_args *pa = aux; 642 u_char cmd[1], resp[2]; 643 int res; 644 645 if (pa->pa_slot != PCKBC_AUX_SLOT) 646 return (0); 647 648 /* Flush any garbage. */ 649 pckbc_flush(pa->pa_tag, pa->pa_slot); 650 651 /* reset the device */ 652 cmd[0] = PMS_RESET; 653 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); 654 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { 655 #ifdef DEBUG 656 printf("pms: reset error %d (response 0x%02x, type 0x%02x)\n", 657 res, resp[0], resp[1]); 658 #endif 659 return (0); 660 } 661 662 return (1); 663 } 664 665 void 666 pmsattach(struct device *parent, struct device *self, void *aux) 667 { 668 struct pms_softc *sc = (void *)self; 669 struct pckbc_attach_args *pa = aux; 670 struct wsmousedev_attach_args a; 671 672 sc->sc_kbctag = pa->pa_tag; 673 674 pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT, 675 pmsinput, sc, DEVNAME(sc)); 676 677 printf("\n"); 678 679 a.accessops = &pms_accessops; 680 a.accesscookie = sc; 681 682 rw_init(&sc->sc_state_lock, "pmsst"); 683 684 /* 685 * Attach the wsmouse, saving a handle to it. 686 * Note that we don't need to check this pointer against NULL 687 * here or in pmsintr, because if this fails pms_enable() will 688 * never be called, so pmsinput() will never be called. 689 */ 690 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 691 692 sc->poll = 1; 693 sc->sc_dev_enable = 0; 694 695 /* See if the device understands an extended (touchpad) protocol. */ 696 pms_protocol_lookup(sc); 697 698 /* no interrupts until enabled */ 699 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE); 700 } 701 702 int 703 pmsactivate(struct device *self, int act) 704 { 705 struct pms_softc *sc = (struct pms_softc *)self; 706 707 switch (act) { 708 case DVACT_SUSPEND: 709 if (sc->sc_state == PMS_STATE_ENABLED) 710 pms_change_state(sc, PMS_STATE_SUSPENDED, 711 PMS_DEV_IGNORE); 712 break; 713 case DVACT_RESUME: 714 if (sc->sc_state == PMS_STATE_SUSPENDED) 715 pms_change_state(sc, PMS_STATE_ENABLED, 716 PMS_DEV_IGNORE); 717 break; 718 } 719 return (0); 720 } 721 722 int 723 pms_change_state(struct pms_softc *sc, int newstate, int dev) 724 { 725 if (dev != PMS_DEV_IGNORE) { 726 switch (newstate) { 727 case PMS_STATE_ENABLED: 728 if (sc->sc_dev_enable & dev) 729 return (EBUSY); 730 731 sc->sc_dev_enable |= dev; 732 733 if (sc->sc_state == PMS_STATE_ENABLED) 734 return (0); 735 736 break; 737 case PMS_STATE_DISABLED: 738 sc->sc_dev_enable &= ~dev; 739 740 if (sc->sc_dev_enable) 741 return (0); 742 743 break; 744 } 745 } 746 747 switch (newstate) { 748 case PMS_STATE_ENABLED: 749 sc->inputstate = 0; 750 751 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1); 752 753 if (sc->poll) 754 pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT); 755 756 pms_reset(sc); 757 if (sc->protocol->enable != NULL && 758 sc->protocol->enable(sc) == 0) 759 pms_protocol_lookup(sc); 760 761 pms_dev_enable(sc); 762 break; 763 case PMS_STATE_DISABLED: 764 case PMS_STATE_SUSPENDED: 765 pms_dev_disable(sc); 766 767 if (sc->protocol->disable) 768 sc->protocol->disable(sc); 769 770 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0); 771 break; 772 } 773 774 sc->sc_state = newstate; 775 sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0; 776 777 return (0); 778 } 779 780 int 781 pms_enable(void *v) 782 { 783 struct pms_softc *sc = v; 784 int rv; 785 786 rw_enter_write(&sc->sc_state_lock); 787 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY); 788 rw_exit_write(&sc->sc_state_lock); 789 790 return (rv); 791 } 792 793 void 794 pms_disable(void *v) 795 { 796 struct pms_softc *sc = v; 797 798 rw_enter_write(&sc->sc_state_lock); 799 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY); 800 rw_exit_write(&sc->sc_state_lock); 801 } 802 803 int 804 pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 805 { 806 struct pms_softc *sc = v; 807 808 if (sc->protocol->ioctl) 809 return (sc->protocol->ioctl(sc, cmd, data, flag, p)); 810 else 811 return (-1); 812 } 813 814 int 815 pms_sec_enable(void *v) 816 { 817 struct pms_softc *sc = v; 818 int rv; 819 820 rw_enter_write(&sc->sc_state_lock); 821 rv = pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY); 822 rw_exit_write(&sc->sc_state_lock); 823 824 return (rv); 825 } 826 827 void 828 pms_sec_disable(void *v) 829 { 830 struct pms_softc *sc = v; 831 832 rw_enter_write(&sc->sc_state_lock); 833 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY); 834 rw_exit_write(&sc->sc_state_lock); 835 } 836 837 int 838 pms_sec_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 839 { 840 switch (cmd) { 841 case WSMOUSEIO_GTYPE: 842 *(u_int *)data = WSMOUSE_TYPE_PS2; 843 break; 844 default: 845 return (-1); 846 } 847 return (0); 848 } 849 850 void 851 pmsinput(void *vsc, int data) 852 { 853 struct pms_softc *sc = vsc; 854 855 if (sc->sc_state != PMS_STATE_ENABLED) { 856 /* Interrupts are not expected. Discard the byte. */ 857 return; 858 } 859 860 sc->packet[sc->inputstate] = data; 861 if (sc->protocol->sync(sc, data)) { 862 #ifdef DIAGNOSTIC 863 printf("%s: not in sync yet, discard input (state %d)\n", 864 DEVNAME(sc), sc->inputstate); 865 #endif 866 sc->inputstate = 0; 867 return; 868 } 869 870 sc->inputstate++; 871 872 if (sc->inputstate != sc->protocol->packetsize) 873 return; 874 875 sc->inputstate = 0; 876 sc->protocol->proc(sc); 877 } 878 879 int 880 synaptics_set_mode(struct pms_softc *sc, int mode) 881 { 882 struct synaptics_softc *syn = sc->synaptics; 883 884 if (pms_spec_cmd(sc, mode) || 885 pms_set_rate(sc, SYNAPTICS_CMD_SET_MODE)) 886 return (-1); 887 888 syn->mode = mode; 889 890 return (0); 891 } 892 893 int 894 synaptics_query(struct pms_softc *sc, int query, int *val) 895 { 896 u_char resp[3]; 897 898 if (pms_spec_cmd(sc, query) || 899 pms_get_status(sc, resp)) 900 return (-1); 901 902 if (val) 903 *val = (resp[0] << 16) | (resp[1] << 8) | resp[2]; 904 905 return (0); 906 } 907 908 int 909 synaptics_get_hwinfo(struct pms_softc *sc) 910 { 911 struct synaptics_softc *syn = sc->synaptics; 912 913 if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify)) 914 return (-1); 915 if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES, 916 &syn->capabilities)) 917 return (-1); 918 if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model)) 919 return (-1); 920 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) && 921 synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model)) 922 return (-1); 923 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) && 924 synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES, 925 &syn->ext_capabilities)) 926 return (-1); 927 if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) && 928 synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &syn->resolution)) 929 return (-1); 930 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) && 931 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_DIMENSIONS) && 932 synaptics_query(sc, SYNAPTICS_QUE_EXT_DIMENSIONS, &syn->dimension)) 933 return (-1); 934 if (SYNAPTICS_ID_FULL(syn->identify) >= 0x705) { 935 if (synaptics_query(sc, SYNAPTICS_QUE_MODES, &syn->modes)) 936 return (-1); 937 if ((syn->modes & SYNAPTICS_EXT2_CAP) && 938 synaptics_query(sc, SYNAPTICS_QUE_EXT2_CAPABILITIES, 939 &syn->ext2_capabilities)) 940 return (-1); 941 } 942 943 if (syn->resolution & SYNAPTICS_RESOLUTION_VALID) { 944 syn->res_x = SYNAPTICS_RESOLUTION_X(syn->resolution); 945 syn->res_y = SYNAPTICS_RESOLUTION_Y(syn->resolution); 946 } 947 syn->min_x = SYNAPTICS_XMIN_BEZEL; 948 syn->min_y = SYNAPTICS_YMIN_BEZEL; 949 syn->max_x = (syn->dimension) ? 950 SYNAPTICS_DIM_X(syn->dimension) : SYNAPTICS_XMAX_BEZEL; 951 syn->max_y = (syn->dimension) ? 952 SYNAPTICS_DIM_Y(syn->dimension) : SYNAPTICS_YMAX_BEZEL; 953 954 syn->sec_buttons = 0; 955 956 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8) 957 syn->ext_model &= ~0xf000; 958 959 if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) { 960 printf("%s: don't support Synaptics OLDABS\n", DEVNAME(sc)); 961 return (-1); 962 } 963 964 if ((SYNAPTICS_ID_MAJOR(syn->identify) == 5) && 965 (SYNAPTICS_ID_MINOR(syn->identify) == 9)) 966 syn->mask = SYNAPTICS_MASK_NEWABS_RELAXED; 967 else 968 syn->mask = SYNAPTICS_MASK_NEWABS_STRICT; 969 970 return (0); 971 } 972 973 void 974 synaptics_sec_proc(struct pms_softc *sc) 975 { 976 struct synaptics_softc *syn = sc->synaptics; 977 u_int buttons; 978 int dx, dy; 979 980 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 981 return; 982 983 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK]; 984 buttons |= syn->sec_buttons; 985 dx = (sc->packet[1] & PMS_PS2_XNEG) ? 986 (int)sc->packet[4] - 256 : sc->packet[4]; 987 dy = (sc->packet[1] & PMS_PS2_YNEG) ? 988 (int)sc->packet[5] - 256 : sc->packet[5]; 989 990 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0); 991 } 992 993 int 994 synaptics_knock(struct pms_softc *sc) 995 { 996 u_char resp[3]; 997 998 if (pms_set_resolution(sc, 0) || 999 pms_set_resolution(sc, 0) || 1000 pms_set_resolution(sc, 0) || 1001 pms_set_resolution(sc, 0) || 1002 pms_get_status(sc, resp) || 1003 resp[1] != SYNAPTICS_ID_MAGIC) 1004 return (-1); 1005 1006 return (0); 1007 } 1008 1009 int 1010 pms_enable_synaptics(struct pms_softc *sc) 1011 { 1012 struct synaptics_softc *syn = sc->synaptics; 1013 struct wsmousedev_attach_args a; 1014 int mode, i; 1015 1016 if (synaptics_knock(sc)) { 1017 if (sc->synaptics == NULL) 1018 goto err; 1019 /* 1020 * Some synaptics touchpads don't resume quickly. 1021 * Retry a few times. 1022 */ 1023 for (i = 10; i > 0; --i) { 1024 printf("%s: device not resuming, retrying\n", 1025 DEVNAME(sc)); 1026 pms_reset(sc); 1027 if (synaptics_knock(sc) == 0) 1028 break; 1029 delay(100000); 1030 } 1031 if (i == 0) { 1032 printf("%s: lost device\n", DEVNAME(sc)); 1033 goto err; 1034 } 1035 } 1036 1037 if (sc->synaptics == NULL) { 1038 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc), 1039 M_DEVBUF, M_WAITOK | M_ZERO); 1040 if (syn == NULL) { 1041 printf("%s: synaptics: not enough memory\n", 1042 DEVNAME(sc)); 1043 goto err; 1044 } 1045 1046 if (synaptics_get_hwinfo(sc)) { 1047 free(sc->synaptics, M_DEVBUF, 1048 sizeof(struct synaptics_softc)); 1049 sc->synaptics = NULL; 1050 goto err; 1051 } 1052 1053 /* enable pass-through PS/2 port if supported */ 1054 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) { 1055 a.accessops = &pms_sec_accessops; 1056 a.accesscookie = sc; 1057 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 1058 wsmousedevprint); 1059 } 1060 1061 syn->wsmode = WSMOUSE_COMPAT; 1062 1063 printf("%s: Synaptics %s, firmware %d.%d\n", DEVNAME(sc), 1064 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ? 1065 "clickpad" : "touchpad"), 1066 SYNAPTICS_ID_MAJOR(syn->identify), 1067 SYNAPTICS_ID_MINOR(syn->identify)); 1068 } 1069 1070 mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE; 1071 if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4) 1072 mode |= SYNAPTICS_DISABLE_GESTURE; 1073 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED) 1074 mode |= SYNAPTICS_W_MODE; 1075 if (synaptics_set_mode(sc, mode)) 1076 goto err; 1077 1078 /* enable advanced gesture mode if supported */ 1079 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && 1080 (pms_spec_cmd(sc, SYNAPTICS_QUE_MODEL) || 1081 pms_set_rate(sc, SYNAPTICS_CMD_SET_ADV_GESTURE_MODE))) 1082 goto err; 1083 1084 return (1); 1085 1086 err: 1087 pms_reset(sc); 1088 1089 return (0); 1090 } 1091 1092 int 1093 pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 1094 struct proc *p) 1095 { 1096 struct synaptics_softc *syn = sc->synaptics; 1097 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1098 int wsmode; 1099 1100 switch (cmd) { 1101 case WSMOUSEIO_GTYPE: 1102 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) && 1103 !(syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) 1104 && mouse_has_softbtn) 1105 *(u_int *)data = WSMOUSE_TYPE_SYNAP_SBTN; 1106 else 1107 *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS; 1108 break; 1109 case WSMOUSEIO_GCALIBCOORDS: 1110 wsmc->minx = syn->min_x; 1111 wsmc->maxx = syn->max_x; 1112 wsmc->miny = syn->min_y; 1113 wsmc->maxy = syn->max_y; 1114 wsmc->swapxy = 0; 1115 wsmc->resx = syn->res_x; 1116 wsmc->resy = syn->res_y; 1117 break; 1118 case WSMOUSEIO_SETMODE: 1119 wsmode = *(u_int *)data; 1120 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 1121 return (EINVAL); 1122 syn->wsmode = wsmode; 1123 break; 1124 default: 1125 return (-1); 1126 } 1127 return (0); 1128 } 1129 1130 int 1131 pms_sync_synaptics(struct pms_softc *sc, int data) 1132 { 1133 struct synaptics_softc *syn = sc->synaptics; 1134 1135 switch (sc->inputstate) { 1136 case 0: 1137 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_FIRST) 1138 return (-1); 1139 break; 1140 case 3: 1141 if ((data & syn->mask) != SYNAPTICS_VALID_NEWABS_NEXT) 1142 return (-1); 1143 break; 1144 } 1145 1146 return (0); 1147 } 1148 1149 void 1150 pms_proc_synaptics(struct pms_softc *sc) 1151 { 1152 struct synaptics_softc *syn = sc->synaptics; 1153 u_int buttons; 1154 int x, y, z, w, dx, dy, width; 1155 1156 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) | 1157 ((sc->packet[3] & 0x04) >> 2); 1158 z = sc->packet[2]; 1159 1160 if ((syn->capabilities & SYNAPTICS_CAP_EXTENDED) == 0) { 1161 /* 1162 * Emulate W mode for models that don't provide it. Bit 3 1163 * of the w-input signals a touch ("finger"), Bit 2 and 1164 * the "gesture" bits 1-0 can be ignored. 1165 */ 1166 if (w & 8) 1167 w = 4; 1168 else 1169 z = w = 0; 1170 } 1171 1172 1173 if ((syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) && w == 3) { 1174 synaptics_sec_proc(sc); 1175 return; 1176 } 1177 1178 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 1179 return; 1180 1181 /* XXX ignore advanced gesture packet, not yet supported */ 1182 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && w == 2) 1183 return; 1184 1185 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) | 1186 sc->packet[4]; 1187 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) | 1188 sc->packet[5]; 1189 1190 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ? 1191 WSMOUSE_BUTTON(1) : 0; 1192 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ? 1193 WSMOUSE_BUTTON(3) : 0; 1194 1195 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) { 1196 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1197 WSMOUSE_BUTTON(1) : 0; 1198 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) { 1199 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1200 WSMOUSE_BUTTON(2) : 0; 1201 } 1202 1203 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) { 1204 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 1205 WSMOUSE_BUTTON(4) : 0; 1206 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ? 1207 WSMOUSE_BUTTON(5) : 0; 1208 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) && 1209 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) { 1210 if (syn->ext2_capabilities & SYNAPTICS_EXT2_CAP_BUTTONS_STICK) { 1211 /* 1212 * Trackstick buttons on this machine are wired to the 1213 * trackpad as extra buttons, so route the event 1214 * through the trackstick interface as normal buttons 1215 */ 1216 syn->sec_buttons = 1217 (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(1) : 0; 1218 syn->sec_buttons |= 1219 (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(3) : 0; 1220 syn->sec_buttons |= 1221 (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(2) : 0; 1222 wsmouse_buttons( 1223 sc->sc_sec_wsmousedev, syn->sec_buttons); 1224 wsmouse_input_sync(sc->sc_sec_wsmousedev); 1225 return; 1226 } 1227 1228 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0; 1229 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0; 1230 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0; 1231 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0; 1232 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0; 1233 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0; 1234 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0; 1235 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0; 1236 x &= ~0x0f; 1237 y &= ~0x0f; 1238 } 1239 1240 /* ignore final events that happen when removing all fingers */ 1241 if (x <= 1 || y <= 1) { 1242 x = syn->old_x; 1243 y = syn->old_y; 1244 } 1245 1246 if (syn->wsmode == WSMOUSE_NATIVE) { 1247 if (z) { 1248 width = imax(w, 4); 1249 w = (w < 2 ? w + 2 : 1); 1250 } else { 1251 width = w = 0; 1252 } 1253 wsmouse_set(sc->sc_wsmousedev, WSMOUSE_TOUCH_WIDTH, width, 0); 1254 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 1255 } else { 1256 dx = dy = 0; 1257 if (z > SYNAPTICS_PRESSURE) { 1258 dx = x - syn->old_x; 1259 dy = y - syn->old_y; 1260 dx /= SYNAPTICS_SCALE; 1261 dy /= SYNAPTICS_SCALE; 1262 } 1263 if (dx || dy || buttons != syn->old_buttons) 1264 WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, 0, 0); 1265 syn->old_buttons = buttons; 1266 } 1267 1268 syn->old_x = x; 1269 syn->old_y = y; 1270 } 1271 1272 void 1273 pms_disable_synaptics(struct pms_softc *sc) 1274 { 1275 struct synaptics_softc *syn = sc->synaptics; 1276 1277 if (syn->capabilities & SYNAPTICS_CAP_SLEEP) 1278 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE | 1279 SYNAPTICS_DISABLE_GESTURE); 1280 } 1281 1282 int 1283 alps_sec_proc(struct pms_softc *sc) 1284 { 1285 struct alps_softc *alps = sc->alps; 1286 int dx, dy, pos = 0; 1287 1288 if ((sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) { 1289 /* 1290 * We need to keep buttons states because interleaved 1291 * packets only signalize x/y movements. 1292 */ 1293 alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; 1294 } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK) == 1295 PMS_ALPS_INTERLEAVED_VALID) { 1296 sc->inputstate = 3; 1297 pos = 3; 1298 } else { 1299 return (0); 1300 } 1301 1302 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 1303 return (1); 1304 1305 dx = (sc->packet[pos] & PMS_PS2_XNEG) ? 1306 (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1]; 1307 dy = (sc->packet[pos] & PMS_PS2_YNEG) ? 1308 (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2]; 1309 1310 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, alps->sec_buttons, dx, dy, 0, 0); 1311 1312 return (1); 1313 } 1314 1315 int 1316 alps_get_hwinfo(struct pms_softc *sc) 1317 { 1318 struct alps_softc *alps = sc->alps; 1319 u_char resp[3]; 1320 int i; 1321 1322 if (pms_set_resolution(sc, 0) || 1323 pms_set_scaling(sc, 2) || 1324 pms_set_scaling(sc, 2) || 1325 pms_set_scaling(sc, 2) || 1326 pms_get_status(sc, resp)) { 1327 DPRINTF("%s: alps: model query error\n", DEVNAME(sc)); 1328 return (-1); 1329 } 1330 1331 alps->version = (resp[0] << 8) | (resp[1] << 4) | (resp[2] / 20 + 1); 1332 1333 for (i = 0; i < nitems(alps_models); i++) 1334 if (alps->version == alps_models[i].version) { 1335 alps->model = alps_models[i].model; 1336 alps->mask = alps_models[i].mask; 1337 return (0); 1338 } 1339 1340 return (-1); 1341 } 1342 1343 int 1344 pms_enable_alps(struct pms_softc *sc) 1345 { 1346 struct alps_softc *alps = sc->alps; 1347 struct wsmousedev_attach_args a; 1348 u_char resp[3]; 1349 1350 if (pms_set_resolution(sc, 0) || 1351 pms_set_scaling(sc, 1) || 1352 pms_set_scaling(sc, 1) || 1353 pms_set_scaling(sc, 1) || 1354 pms_get_status(sc, resp) || 1355 resp[0] != PMS_ALPS_MAGIC1 || 1356 resp[1] != PMS_ALPS_MAGIC2 || 1357 (resp[2] != PMS_ALPS_MAGIC3_1 && resp[2] != PMS_ALPS_MAGIC3_2 && 1358 resp[2] != PMS_ALPS_MAGIC3_3)) 1359 goto err; 1360 1361 if (sc->alps == NULL) { 1362 sc->alps = alps = malloc(sizeof(struct alps_softc), 1363 M_DEVBUF, M_WAITOK | M_ZERO); 1364 if (alps == NULL) { 1365 printf("%s: alps: not enough memory\n", DEVNAME(sc)); 1366 goto err; 1367 } 1368 1369 if (alps_get_hwinfo(sc)) { 1370 free(sc->alps, M_DEVBUF, sizeof(struct alps_softc)); 1371 sc->alps = NULL; 1372 goto err; 1373 } 1374 1375 printf("%s: ALPS %s, version 0x%04x\n", DEVNAME(sc), 1376 (alps->model & ALPS_DUALPOINT ? "Dualpoint" : "Glidepoint"), 1377 alps->version); 1378 1379 alps->min_x = ALPS_XMIN_BEZEL; 1380 alps->min_y = ALPS_YMIN_BEZEL; 1381 alps->max_x = ALPS_XMAX_BEZEL; 1382 alps->max_y = ALPS_YMAX_BEZEL; 1383 1384 alps->wsmode = WSMOUSE_COMPAT; 1385 1386 if (alps->model & ALPS_DUALPOINT) { 1387 a.accessops = &pms_sec_accessops; 1388 a.accesscookie = sc; 1389 sc->sc_sec_wsmousedev = config_found((void *)sc, &a, 1390 wsmousedevprint); 1391 } 1392 } 1393 1394 if (alps->model == 0) 1395 goto err; 1396 1397 if ((alps->model & ALPS_PASSTHROUGH) && 1398 (pms_set_scaling(sc, 2) || 1399 pms_set_scaling(sc, 2) || 1400 pms_set_scaling(sc, 2) || 1401 pms_dev_disable(sc))) { 1402 DPRINTF("%s: alps: passthrough on error\n", DEVNAME(sc)); 1403 goto err; 1404 } 1405 1406 if (pms_dev_disable(sc) || 1407 pms_dev_disable(sc) || 1408 pms_set_rate(sc, 0x0a)) { 1409 DPRINTF("%s: alps: tapping error\n", DEVNAME(sc)); 1410 goto err; 1411 } 1412 1413 if (pms_dev_disable(sc) || 1414 pms_dev_disable(sc) || 1415 pms_dev_disable(sc) || 1416 pms_dev_disable(sc) || 1417 pms_dev_enable(sc)) { 1418 DPRINTF("%s: alps: absolute mode error\n", DEVNAME(sc)); 1419 goto err; 1420 } 1421 1422 if ((alps->model & ALPS_PASSTHROUGH) && 1423 (pms_set_scaling(sc, 1) || 1424 pms_set_scaling(sc, 1) || 1425 pms_set_scaling(sc, 1) || 1426 pms_dev_disable(sc))) { 1427 DPRINTF("%s: alps: passthrough off error\n", DEVNAME(sc)); 1428 goto err; 1429 } 1430 1431 alps->sec_buttons = 0; 1432 1433 return (1); 1434 1435 err: 1436 pms_reset(sc); 1437 1438 return (0); 1439 } 1440 1441 int 1442 pms_ioctl_alps(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 1443 struct proc *p) 1444 { 1445 struct alps_softc *alps = sc->alps; 1446 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1447 int wsmode; 1448 1449 switch (cmd) { 1450 case WSMOUSEIO_GTYPE: 1451 *(u_int *)data = WSMOUSE_TYPE_ALPS; 1452 break; 1453 case WSMOUSEIO_GCALIBCOORDS: 1454 wsmc->minx = alps->min_x; 1455 wsmc->maxx = alps->max_x; 1456 wsmc->miny = alps->min_y; 1457 wsmc->maxy = alps->max_y; 1458 wsmc->swapxy = 0; 1459 break; 1460 case WSMOUSEIO_SETMODE: 1461 wsmode = *(u_int *)data; 1462 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 1463 return (EINVAL); 1464 alps->wsmode = wsmode; 1465 break; 1466 default: 1467 return (-1); 1468 } 1469 return (0); 1470 } 1471 1472 int 1473 pms_sync_alps(struct pms_softc *sc, int data) 1474 { 1475 struct alps_softc *alps = sc->alps; 1476 1477 if ((alps->model & ALPS_DUALPOINT) && 1478 (sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) { 1479 if (sc->inputstate == 2) 1480 sc->inputstate += 3; 1481 return (0); 1482 } 1483 1484 switch (sc->inputstate) { 1485 case 0: 1486 if ((data & alps->mask) != alps->mask) 1487 return (-1); 1488 break; 1489 case 1: 1490 case 2: 1491 case 3: 1492 if ((data & PMS_ALPS_MASK) != PMS_ALPS_VALID) 1493 return (-1); 1494 break; 1495 case 4: 1496 case 5: 1497 if ((alps->model & ALPS_INTERLEAVED) == 0 && 1498 (data & PMS_ALPS_MASK) != PMS_ALPS_VALID) 1499 return (-1); 1500 break; 1501 } 1502 1503 return (0); 1504 } 1505 1506 void 1507 pms_proc_alps(struct pms_softc *sc) 1508 { 1509 struct alps_softc *alps = sc->alps; 1510 int x, y, z, dx, dy; 1511 u_int buttons, gesture; 1512 1513 if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc)) 1514 return; 1515 1516 x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4); 1517 y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3); 1518 z = sc->packet[5]; 1519 1520 buttons = ((sc->packet[3] & 1) ? WSMOUSE_BUTTON(1) : 0) | 1521 ((sc->packet[3] & 2) ? WSMOUSE_BUTTON(3) : 0) | 1522 ((sc->packet[3] & 4) ? WSMOUSE_BUTTON(2) : 0); 1523 1524 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) && z == ALPS_Z_MAGIC) { 1525 dx = (x > ALPS_XSEC_BEZEL / 2) ? (x - ALPS_XSEC_BEZEL) : x; 1526 dy = (y > ALPS_YSEC_BEZEL / 2) ? (y - ALPS_YSEC_BEZEL) : y; 1527 1528 WSMOUSE_INPUT(sc->sc_sec_wsmousedev, buttons, dx, dy, 0, 0); 1529 1530 return; 1531 } 1532 1533 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 1534 return; 1535 1536 /* 1537 * XXX The Y-axis is in the oposit direction compared to 1538 * Synaptics touchpads and PS/2 mouses. 1539 * It's why we need to translate the y value here for both 1540 * NATIVE and COMPAT modes. 1541 */ 1542 y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL; 1543 1544 if (alps->wsmode == WSMOUSE_NATIVE) { 1545 if (alps->gesture == ALPS_TAP) { 1546 /* Report a touch with the tap coordinates. */ 1547 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, 1548 alps->old_x, alps->old_y, ALPS_PRESSURE, 0); 1549 if (z > 0) { 1550 /* 1551 * The hardware doesn't send a null pressure 1552 * event when dragging starts. 1553 */ 1554 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, 1555 alps->old_x, alps->old_y, 0, 0); 1556 } 1557 } 1558 1559 gesture = sc->packet[2] & 0x03; 1560 if (gesture != ALPS_TAP) 1561 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, 0); 1562 1563 if (alps->gesture != ALPS_DRAG || gesture != ALPS_TAP) 1564 alps->gesture = gesture; 1565 1566 alps->old_x = x; 1567 alps->old_y = y; 1568 1569 } else { 1570 dx = dy = 0; 1571 if (z > ALPS_PRESSURE) { 1572 dx = x - alps->old_x; 1573 dy = y - alps->old_y; 1574 1575 /* Prevent jump */ 1576 dx = abs(dx) > 50 ? 0 : dx; 1577 dy = abs(dy) > 50 ? 0 : dy; 1578 } 1579 1580 if (dx || dy || buttons != alps->old_buttons) 1581 WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, 0, 0); 1582 1583 alps->old_x = x; 1584 alps->old_y = y; 1585 alps->old_buttons = buttons; 1586 } 1587 } 1588 1589 int 1590 elantech_set_absolute_mode_v1(struct pms_softc *sc) 1591 { 1592 int i; 1593 u_char resp[3]; 1594 1595 /* Enable absolute mode. Magic numbers from Linux driver. */ 1596 if (pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1597 pms_spec_cmd(sc, 0x10) || 1598 pms_spec_cmd(sc, 0x16) || 1599 pms_set_scaling(sc, 1) || 1600 pms_spec_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1601 pms_spec_cmd(sc, 0x11) || 1602 pms_spec_cmd(sc, 0x8f) || 1603 pms_set_scaling(sc, 1)) 1604 return (-1); 1605 1606 /* Read back reg 0x10 to ensure hardware is ready. */ 1607 for (i = 0; i < 5; i++) { 1608 if (pms_spec_cmd(sc, ELANTECH_CMD_READ_REG) || 1609 pms_spec_cmd(sc, 0x10) || 1610 pms_get_status(sc, resp) == 0) 1611 break; 1612 delay(2000); 1613 } 1614 if (i == 5) 1615 return (-1); 1616 1617 if ((resp[0] & ELANTECH_ABSOLUTE_MODE) == 0) 1618 return (-1); 1619 1620 return (0); 1621 } 1622 1623 int 1624 elantech_set_absolute_mode_v2(struct pms_softc *sc) 1625 { 1626 int i; 1627 u_char resp[3]; 1628 u_char reg10 = (sc->elantech->fw_version == 0x20030 ? 0x54 : 0xc4); 1629 1630 /* Enable absolute mode. Magic numbers from Linux driver. */ 1631 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1632 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1633 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1634 elantech_ps2_cmd(sc, 0x10) || 1635 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1636 elantech_ps2_cmd(sc, reg10) || 1637 pms_set_scaling(sc, 1) || 1638 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1639 elantech_ps2_cmd(sc, ELANTECH_CMD_WRITE_REG) || 1640 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1641 elantech_ps2_cmd(sc, 0x11) || 1642 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1643 elantech_ps2_cmd(sc, 0x88) || 1644 pms_set_scaling(sc, 1)) 1645 return (-1); 1646 1647 /* Read back reg 0x10 to ensure hardware is ready. */ 1648 for (i = 0; i < 5; i++) { 1649 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1650 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_REG) || 1651 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1652 elantech_ps2_cmd(sc, 0x10) || 1653 pms_get_status(sc, resp) == 0) 1654 break; 1655 delay(2000); 1656 } 1657 if (i == 5) 1658 return (-1); 1659 1660 return (0); 1661 } 1662 1663 int 1664 elantech_set_absolute_mode_v3(struct pms_softc *sc) 1665 { 1666 int i; 1667 u_char resp[3]; 1668 1669 /* Enable absolute mode. Magic numbers from Linux driver. */ 1670 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1671 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1672 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1673 elantech_ps2_cmd(sc, 0x10) || 1674 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1675 elantech_ps2_cmd(sc, 0x0b) || 1676 pms_set_scaling(sc, 1)) 1677 return (-1); 1678 1679 /* Read back reg 0x10 to ensure hardware is ready. */ 1680 for (i = 0; i < 5; i++) { 1681 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1682 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1683 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1684 elantech_ps2_cmd(sc, 0x10) || 1685 pms_get_status(sc, resp) == 0) 1686 break; 1687 delay(2000); 1688 } 1689 if (i == 5) 1690 return (-1); 1691 1692 return (0); 1693 } 1694 1695 int 1696 elantech_set_absolute_mode_v4(struct pms_softc *sc) 1697 { 1698 /* Enable absolute mode. Magic numbers from Linux driver. */ 1699 if (elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1700 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1701 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1702 elantech_ps2_cmd(sc, 0x07) || 1703 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1704 elantech_ps2_cmd(sc, ELANTECH_CMD_READ_WRITE_REG) || 1705 elantech_ps2_cmd(sc, ELANTECH_PS2_CUSTOM_COMMAND) || 1706 elantech_ps2_cmd(sc, 0x01) || 1707 pms_set_scaling(sc, 1)) 1708 return (-1); 1709 1710 /* v4 has no register 0x10 to read response from */ 1711 1712 return (0); 1713 } 1714 1715 int 1716 elantech_get_hwinfo_v1(struct pms_softc *sc) 1717 { 1718 struct elantech_softc *elantech = sc->elantech; 1719 int fw_version; 1720 u_char capabilities[3]; 1721 1722 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1723 return (-1); 1724 1725 if (fw_version < 0x20030 || fw_version == 0x20600) { 1726 if (fw_version < 0x20000) 1727 elantech->flags |= ELANTECH_F_HW_V1_OLD; 1728 } else 1729 return (-1); 1730 1731 elantech->fw_version = fw_version; 1732 1733 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1734 pms_get_status(sc, capabilities)) 1735 return (-1); 1736 1737 if (capabilities[0] & ELANTECH_CAP_HAS_ROCKER) 1738 elantech->flags |= ELANTECH_F_HAS_ROCKER; 1739 1740 if (elantech_set_absolute_mode_v1(sc)) 1741 return (-1); 1742 1743 elantech->min_x = ELANTECH_V1_X_MIN; 1744 elantech->max_x = ELANTECH_V1_X_MAX; 1745 elantech->min_y = ELANTECH_V1_Y_MIN; 1746 elantech->max_y = ELANTECH_V1_Y_MAX; 1747 1748 return (0); 1749 } 1750 1751 int 1752 elantech_get_hwinfo_v2(struct pms_softc *sc) 1753 { 1754 struct elantech_softc *elantech = sc->elantech; 1755 int fw_version, ic_ver; 1756 u_char capabilities[3]; 1757 int i, fixed_dpi; 1758 u_char resp[3]; 1759 1760 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1761 return (-1); 1762 1763 ic_ver = (fw_version & 0x0f0000) >> 16; 1764 if (ic_ver != 2 && ic_ver != 4) 1765 return (-1); 1766 1767 elantech->fw_version = fw_version; 1768 if (fw_version >= 0x20800) 1769 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1770 1771 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1772 pms_get_status(sc, capabilities)) 1773 return (-1); 1774 1775 if (elantech_set_absolute_mode_v2(sc)) 1776 return (-1); 1777 1778 if (fw_version == 0x20800 || fw_version == 0x20b00 || 1779 fw_version == 0x20030) { 1780 elantech->max_x = ELANTECH_V2_X_MAX; 1781 elantech->max_y = ELANTECH_V2_Y_MAX; 1782 } else { 1783 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1784 pms_get_status(sc, resp)) 1785 return (-1); 1786 fixed_dpi = resp[1] & 0x10; 1787 i = (fw_version > 0x20800 && fw_version < 0x20900) ? 1 : 2; 1788 if ((fw_version >> 16) == 0x14 && fixed_dpi) { 1789 if (pms_spec_cmd(sc, ELANTECH_QUE_SAMPLE) || 1790 pms_get_status(sc, resp)) 1791 return (-1); 1792 elantech->max_x = (capabilities[1] - i) * resp[1] / 2; 1793 elantech->max_y = (capabilities[2] - i) * resp[2] / 2; 1794 } else if (fw_version == 0x040216) { 1795 elantech->max_x = 819; 1796 elantech->max_y = 405; 1797 } else if (fw_version == 0x040219 || fw_version == 0x040215) { 1798 elantech->max_x = 900; 1799 elantech->max_y = 500; 1800 } else { 1801 elantech->max_x = (capabilities[1] - i) * 64; 1802 elantech->max_y = (capabilities[2] - i) * 64; 1803 } 1804 } 1805 1806 return (0); 1807 } 1808 1809 int 1810 elantech_get_hwinfo_v3(struct pms_softc *sc) 1811 { 1812 struct elantech_softc *elantech = sc->elantech; 1813 int fw_version; 1814 u_char resp[3]; 1815 1816 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1817 return (-1); 1818 1819 if (((fw_version & 0x0f0000) >> 16) != 5) 1820 return (-1); 1821 1822 elantech->fw_version = fw_version; 1823 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1824 1825 if ((fw_version & 0x4000) == 0x4000) 1826 elantech->flags |= ELANTECH_F_CRC_ENABLED; 1827 1828 if (elantech_set_absolute_mode_v3(sc)) 1829 return (-1); 1830 1831 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1832 pms_get_status(sc, resp)) 1833 return (-1); 1834 1835 elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1]; 1836 elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2]; 1837 1838 return (0); 1839 } 1840 1841 int 1842 elantech_get_hwinfo_v4(struct pms_softc *sc) 1843 { 1844 struct elantech_softc *elantech = sc->elantech; 1845 int fw_version; 1846 u_char capabilities[3]; 1847 u_char resp[3]; 1848 1849 if (synaptics_query(sc, ELANTECH_QUE_FW_VER, &fw_version)) 1850 return (-1); 1851 1852 if (((fw_version & 0x0f0000) >> 16) != 6 && 1853 (fw_version & 0x0f0000) >> 16 != 8) 1854 return (-1); 1855 1856 elantech->fw_version = fw_version; 1857 elantech->flags |= ELANTECH_F_REPORTS_PRESSURE; 1858 1859 if (elantech_set_absolute_mode_v4(sc)) 1860 return (-1); 1861 1862 if (pms_spec_cmd(sc, ELANTECH_QUE_CAPABILITIES) || 1863 pms_get_status(sc, capabilities)) 1864 return (-1); 1865 1866 if (pms_spec_cmd(sc, ELANTECH_QUE_FW_ID) || 1867 pms_get_status(sc, resp)) 1868 return (-1); 1869 1870 elantech->max_x = (resp[0] & 0x0f) << 8 | resp[1]; 1871 elantech->max_y = (resp[0] & 0xf0) << 4 | resp[2]; 1872 1873 if ((capabilities[1] < 2) || (capabilities[1] > elantech->max_x)) 1874 return (-1); 1875 1876 elantech->width = elantech->max_x / (capabilities[1] - 1); 1877 1878 return (0); 1879 } 1880 1881 int 1882 elantech_ps2_cmd(struct pms_softc *sc, u_char command) 1883 { 1884 u_char cmd[1]; 1885 1886 cmd[0] = command; 1887 return (pms_cmd(sc, cmd, 1, NULL, 0)); 1888 } 1889 1890 int 1891 elantech_knock(struct pms_softc *sc) 1892 { 1893 u_char resp[3]; 1894 1895 if (pms_dev_disable(sc) || 1896 pms_set_scaling(sc, 1) || 1897 pms_set_scaling(sc, 1) || 1898 pms_set_scaling(sc, 1) || 1899 pms_get_status(sc, resp) || 1900 resp[0] != PMS_ELANTECH_MAGIC1 || 1901 resp[1] != PMS_ELANTECH_MAGIC2 || 1902 (resp[2] != PMS_ELANTECH_MAGIC3_1 && 1903 resp[2] != PMS_ELANTECH_MAGIC3_2)) 1904 return (-1); 1905 1906 return (0); 1907 } 1908 1909 int 1910 pms_enable_elantech_v1(struct pms_softc *sc) 1911 { 1912 struct elantech_softc *elantech = sc->elantech; 1913 int i; 1914 1915 if (elantech_knock(sc)) 1916 goto err; 1917 1918 if (sc->elantech == NULL) { 1919 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 1920 M_DEVBUF, M_WAITOK | M_ZERO); 1921 if (elantech == NULL) { 1922 printf("%s: elantech: not enough memory\n", 1923 DEVNAME(sc)); 1924 goto err; 1925 } 1926 1927 if (elantech_get_hwinfo_v1(sc)) { 1928 free(sc->elantech, M_DEVBUF, 1929 sizeof(struct elantech_softc)); 1930 sc->elantech = NULL; 1931 goto err; 1932 } 1933 1934 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 1935 DEVNAME(sc), 1, sc->elantech->fw_version); 1936 } else if (elantech_set_absolute_mode_v1(sc)) 1937 goto err; 1938 1939 for (i = 0; i < nitems(sc->elantech->parity); i++) 1940 sc->elantech->parity[i] = sc->elantech->parity[i & (i - 1)] ^ 1; 1941 1942 return (1); 1943 1944 err: 1945 pms_reset(sc); 1946 1947 return (0); 1948 } 1949 1950 int 1951 pms_enable_elantech_v2(struct pms_softc *sc) 1952 { 1953 struct elantech_softc *elantech = sc->elantech; 1954 1955 if (elantech_knock(sc)) 1956 goto err; 1957 1958 if (sc->elantech == NULL) { 1959 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 1960 M_DEVBUF, M_WAITOK | M_ZERO); 1961 if (elantech == NULL) { 1962 printf("%s: elantech: not enough memory\n", 1963 DEVNAME(sc)); 1964 goto err; 1965 } 1966 1967 if (elantech_get_hwinfo_v2(sc)) { 1968 free(sc->elantech, M_DEVBUF, 1969 sizeof(struct elantech_softc)); 1970 sc->elantech = NULL; 1971 goto err; 1972 } 1973 1974 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 1975 DEVNAME(sc), 2, sc->elantech->fw_version); 1976 } else if (elantech_set_absolute_mode_v2(sc)) 1977 goto err; 1978 1979 return (1); 1980 1981 err: 1982 pms_reset(sc); 1983 1984 return (0); 1985 } 1986 1987 int 1988 pms_enable_elantech_v3(struct pms_softc *sc) 1989 { 1990 struct elantech_softc *elantech = sc->elantech; 1991 1992 if (elantech_knock(sc)) 1993 goto err; 1994 1995 if (sc->elantech == NULL) { 1996 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 1997 M_DEVBUF, M_WAITOK | M_ZERO); 1998 if (elantech == NULL) { 1999 printf("%s: elantech: not enough memory\n", 2000 DEVNAME(sc)); 2001 goto err; 2002 } 2003 2004 if (elantech_get_hwinfo_v3(sc)) { 2005 free(sc->elantech, M_DEVBUF, 2006 sizeof(struct elantech_softc)); 2007 sc->elantech = NULL; 2008 goto err; 2009 } 2010 2011 printf("%s: Elantech Touchpad, version %d, firmware 0x%x\n", 2012 DEVNAME(sc), 3, sc->elantech->fw_version); 2013 } else if (elantech_set_absolute_mode_v3(sc)) 2014 goto err; 2015 2016 return (1); 2017 2018 err: 2019 pms_reset(sc); 2020 2021 return (0); 2022 } 2023 2024 int 2025 pms_elantech_v4_configure(struct device *sc_wsmousedev, 2026 struct elantech_softc *elantech) 2027 { 2028 if (wsmouse_mt_init(sc_wsmousedev, ELANTECH_MAX_FINGERS, 0)) 2029 return (-1); 2030 2031 wsmouse_set_param(sc_wsmousedev, WSMPARAM_DX_DIV, SYNAPTICS_SCALE); 2032 wsmouse_set_param(sc_wsmousedev, WSMPARAM_DY_DIV, SYNAPTICS_SCALE); 2033 return (0); 2034 } 2035 2036 int 2037 pms_enable_elantech_v4(struct pms_softc *sc) 2038 { 2039 struct elantech_softc *elantech = sc->elantech; 2040 2041 if (elantech_knock(sc)) 2042 goto err; 2043 2044 if (sc->elantech == NULL) { 2045 sc->elantech = elantech = malloc(sizeof(struct elantech_softc), 2046 M_DEVBUF, M_WAITOK | M_ZERO); 2047 if (elantech == NULL) { 2048 printf("%s: elantech: not enough memory\n", 2049 DEVNAME(sc)); 2050 goto err; 2051 } 2052 2053 if (elantech_get_hwinfo_v4(sc)) { 2054 free(sc->elantech, M_DEVBUF, 2055 sizeof(struct elantech_softc)); 2056 sc->elantech = NULL; 2057 goto err; 2058 } 2059 2060 if (pms_elantech_v4_configure( 2061 sc->sc_wsmousedev, sc->elantech)) { 2062 free(sc->elantech, M_DEVBUF, 0); 2063 sc->elantech = NULL; 2064 printf("%s: setup failed\n", DEVNAME(sc)); 2065 goto err; 2066 } 2067 wsmouse_set_mode(sc->sc_wsmousedev, WSMOUSE_COMPAT); 2068 2069 printf("%s: Elantech Clickpad, version %d, firmware 0x%x\n", 2070 DEVNAME(sc), 4, sc->elantech->fw_version); 2071 } else if (elantech_set_absolute_mode_v4(sc)) 2072 goto err; 2073 2074 return (1); 2075 2076 err: 2077 pms_reset(sc); 2078 2079 return (0); 2080 } 2081 2082 int 2083 pms_ioctl_elantech(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 2084 struct proc *p) 2085 { 2086 struct elantech_softc *elantech = sc->elantech; 2087 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 2088 int wsmode; 2089 2090 switch (cmd) { 2091 case WSMOUSEIO_GTYPE: 2092 *(u_int *)data = WSMOUSE_TYPE_ELANTECH; 2093 break; 2094 case WSMOUSEIO_GCALIBCOORDS: 2095 wsmc->minx = elantech->min_x; 2096 wsmc->maxx = elantech->max_x; 2097 wsmc->miny = elantech->min_y; 2098 wsmc->maxy = elantech->max_y; 2099 wsmc->swapxy = 0; 2100 wsmc->resx = 0; 2101 wsmc->resy = 0; 2102 break; 2103 case WSMOUSEIO_SETMODE: 2104 wsmode = *(u_int *)data; 2105 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 2106 return (EINVAL); 2107 elantech->wsmode = wsmode; 2108 if (sc->protocol->type == PMS_ELANTECH_V4) 2109 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 2110 break; 2111 default: 2112 return (-1); 2113 } 2114 return (0); 2115 } 2116 2117 int 2118 pms_sync_elantech_v1(struct pms_softc *sc, int data) 2119 { 2120 struct elantech_softc *elantech = sc->elantech; 2121 u_char p; 2122 2123 switch (sc->inputstate) { 2124 case 0: 2125 if (elantech->flags & ELANTECH_F_HW_V1_OLD) { 2126 elantech->p1 = (data & 0x20) >> 5; 2127 elantech->p2 = (data & 0x10) >> 4; 2128 } else { 2129 elantech->p1 = (data & 0x10) >> 4; 2130 elantech->p2 = (data & 0x20) >> 5; 2131 } 2132 elantech->p3 = (data & 0x04) >> 2; 2133 return (0); 2134 case 1: 2135 p = elantech->p1; 2136 break; 2137 case 2: 2138 p = elantech->p2; 2139 break; 2140 case 3: 2141 p = elantech->p3; 2142 break; 2143 default: 2144 return (-1); 2145 } 2146 2147 if (data < 0 || data >= nitems(elantech->parity) || 2148 elantech->parity[data] != p) 2149 return (-1); 2150 2151 return (0); 2152 } 2153 2154 int 2155 pms_sync_elantech_v2(struct pms_softc *sc, int data) 2156 { 2157 struct elantech_softc *elantech = sc->elantech; 2158 2159 /* Variants reporting pressure always have the same constant bits. */ 2160 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) { 2161 if (sc->inputstate == 0 && (data & 0x0c) != 0x04) 2162 return (-1); 2163 if (sc->inputstate == 3 && (data & 0x0f) != 0x02) 2164 return (-1); 2165 return (0); 2166 } 2167 2168 /* For variants not reporting pressure, 1 and 3 finger touch packets 2169 * have different constant bits than 2 finger touch packets. */ 2170 switch (sc->inputstate) { 2171 case 0: 2172 if ((data & 0xc0) == 0x80) { 2173 if ((data & 0x0c) != 0x0c) 2174 return (-1); 2175 elantech->flags |= ELANTECH_F_2FINGER_PACKET; 2176 } else { 2177 if ((data & 0x3c) != 0x3c) 2178 return (-1); 2179 elantech->flags &= ~ELANTECH_F_2FINGER_PACKET; 2180 } 2181 break; 2182 case 1: 2183 case 4: 2184 if (elantech->flags & ELANTECH_F_2FINGER_PACKET) 2185 break; 2186 if ((data & 0xf0) != 0x00) 2187 return (-1); 2188 break; 2189 case 3: 2190 if (elantech->flags & ELANTECH_F_2FINGER_PACKET) { 2191 if ((data & 0x0e) != 0x08) 2192 return (-1); 2193 } else { 2194 if ((data & 0x3e) != 0x38) 2195 return (-1); 2196 } 2197 break; 2198 default: 2199 break; 2200 } 2201 2202 return (0); 2203 } 2204 2205 int 2206 pms_sync_elantech_v3(struct pms_softc *sc, int data) 2207 { 2208 struct elantech_softc *elantech = sc->elantech; 2209 2210 switch (sc->inputstate) { 2211 case 0: 2212 if (elantech->flags & ELANTECH_F_CRC_ENABLED) 2213 break; 2214 if ((data & 0x0c) != 0x04 && (data & 0x0c) != 0x0c) 2215 return (-1); 2216 break; 2217 case 3: 2218 if (elantech->flags & ELANTECH_F_CRC_ENABLED) { 2219 if ((data & 0x09) != 0x08 && (data & 0x09) != 0x09) 2220 return (-1); 2221 } else { 2222 if ((data & 0xcf) != 0x02 && (data & 0xce) != 0x0c) 2223 return (-1); 2224 } 2225 break; 2226 } 2227 2228 return (0); 2229 } 2230 2231 int 2232 pms_sync_elantech_v4(struct pms_softc *sc, int data) 2233 { 2234 if (sc->inputstate == 0 && (data & 0x0c) != 0x04) 2235 return (-1); 2236 else 2237 return (0); 2238 } 2239 2240 void 2241 pms_proc_elantech_v1(struct pms_softc *sc) 2242 { 2243 struct elantech_softc *elantech = sc->elantech; 2244 int x, y, w, z; 2245 2246 if (elantech->flags & ELANTECH_F_HW_V1_OLD) 2247 w = ((sc->packet[1] & 0x80) >> 7) + 2248 ((sc->packet[1] & 0x30) >> 4); 2249 else 2250 w = (sc->packet[0] & 0xc0) >> 6; 2251 2252 /* Hardware version 1 doesn't report pressure. */ 2253 if (w) { 2254 x = ((sc->packet[1] & 0x0c) << 6) | sc->packet[2]; 2255 y = ((sc->packet[1] & 0x03) << 8) | sc->packet[3]; 2256 z = SYNAPTICS_PRESSURE; 2257 } else { 2258 x = elantech->old_x; 2259 y = elantech->old_y; 2260 z = 0; 2261 } 2262 2263 elantech_send_input(sc, x, y, z, w); 2264 } 2265 2266 void 2267 pms_proc_elantech_v2(struct pms_softc *sc) 2268 { 2269 const u_char debounce_pkt[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff }; 2270 struct elantech_softc *elantech = sc->elantech; 2271 int x, y, w, z; 2272 2273 /* 2274 * The hardware sends this packet when in debounce state. 2275 * The packet should be ignored. 2276 */ 2277 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))) 2278 return; 2279 2280 w = (sc->packet[0] & 0xc0) >> 6; 2281 if (w == 1 || w == 3) { 2282 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2]; 2283 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5]; 2284 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) 2285 z = ((sc->packet[1] & 0xf0) | 2286 (sc->packet[4] & 0xf0) >> 4); 2287 else 2288 z = SYNAPTICS_PRESSURE; 2289 } else if (w == 2) { 2290 x = (((sc->packet[0] & 0x10) << 4) | sc->packet[1]) << 2; 2291 y = (((sc->packet[0] & 0x20) << 3) | sc->packet[2]) << 2; 2292 z = SYNAPTICS_PRESSURE; 2293 } else { 2294 x = elantech->old_x; 2295 y = elantech->old_y; 2296 z = 0; 2297 } 2298 2299 elantech_send_input(sc, x, y, z, w); 2300 } 2301 2302 void 2303 pms_proc_elantech_v3(struct pms_softc *sc) 2304 { 2305 const u_char debounce_pkt[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; 2306 struct elantech_softc *elantech = sc->elantech; 2307 int x, y, w, z; 2308 2309 x = ((sc->packet[1] & 0x0f) << 8 | sc->packet[2]); 2310 y = ((sc->packet[4] & 0x0f) << 8 | sc->packet[5]); 2311 z = 0; 2312 w = (sc->packet[0] & 0xc0) >> 6; 2313 if (w == 2) { 2314 /* 2315 * Two-finger touch causes two packets -- a head packet 2316 * and a tail packet. We report a single event and ignore 2317 * the tail packet. 2318 */ 2319 if (elantech->flags & ELANTECH_F_CRC_ENABLED) { 2320 if ((sc->packet[3] & 0x09) != 0x08) 2321 return; 2322 } else { 2323 /* The hardware sends this packet when in debounce state. 2324 * The packet should be ignored. */ 2325 if (!memcmp(sc->packet, debounce_pkt, sizeof(debounce_pkt))) 2326 return; 2327 if ((sc->packet[0] & 0x0c) != 0x04 && 2328 (sc->packet[3] & 0xcf) != 0x02) { 2329 /* not the head packet -- ignore */ 2330 return; 2331 } 2332 } 2333 } 2334 2335 /* Prevent juming cursor if pad isn't touched or reports garbage. */ 2336 if (w == 0 || 2337 ((x == 0 || y == 0 || x == elantech->max_x || y == elantech->max_y) 2338 && (x != elantech->old_x || y != elantech->old_y))) { 2339 x = elantech->old_x; 2340 y = elantech->old_y; 2341 } 2342 2343 if (elantech->flags & ELANTECH_F_REPORTS_PRESSURE) 2344 z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4); 2345 else if (w) 2346 z = SYNAPTICS_PRESSURE; 2347 2348 elantech_send_input(sc, x, y, z, w); 2349 } 2350 2351 void 2352 pms_proc_elantech_v4(struct pms_softc *sc) 2353 { 2354 struct elantech_softc *elantech = sc->elantech; 2355 struct device *sc_wsmousedev = sc->sc_wsmousedev; 2356 int id, weight, n, x, y, z; 2357 u_int buttons, slots; 2358 2359 switch (sc->packet[3] & 0x1f) { 2360 case ELANTECH_V4_PKT_STATUS: 2361 slots = elantech->mt_slots; 2362 elantech->mt_slots = sc->packet[1] & 0x1f; 2363 slots &= ~elantech->mt_slots; 2364 for (id = 0; slots; id++, slots >>= 1) { 2365 if (slots & 1) 2366 wsmouse_mtstate(sc_wsmousedev, id, 0, 0, 0); 2367 } 2368 break; 2369 2370 case ELANTECH_V4_PKT_HEAD: 2371 id = ((sc->packet[3] & 0xe0) >> 5) - 1; 2372 if (id > -1 && id < ELANTECH_MAX_FINGERS) { 2373 x = ((sc->packet[1] & 0x0f) << 8) | sc->packet[2]; 2374 y = ((sc->packet[4] & 0x0f) << 8) | sc->packet[5]; 2375 z = (sc->packet[1] & 0xf0) 2376 | ((sc->packet[4] & 0xf0) >> 4); 2377 wsmouse_mtstate(sc_wsmousedev, id, x, y, z); 2378 } 2379 break; 2380 2381 case ELANTECH_V4_PKT_MOTION: 2382 weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE : 1; 2383 for (n = 0; n < 6; n += 3) { 2384 id = ((sc->packet[n] & 0xe0) >> 5) - 1; 2385 if (id < 0 || id >= ELANTECH_MAX_FINGERS) 2386 continue; 2387 x = weight * (signed char)sc->packet[n + 1]; 2388 y = weight * (signed char)sc->packet[n + 2]; 2389 z = WSMOUSE_DEFAULT_PRESSURE; 2390 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_X, x, id); 2391 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_REL_Y, y, id); 2392 wsmouse_set(sc_wsmousedev, WSMOUSE_MT_PRESSURE, z, id); 2393 } 2394 2395 break; 2396 2397 default: 2398 printf("%s: unknown packet type 0x%x\n", DEVNAME(sc), 2399 sc->packet[3] & 0x1f); 2400 return; 2401 } 2402 2403 buttons = 0; 2404 if (sc->packet[0] & 0x01) 2405 buttons |= WSMOUSE_BUTTON(1); 2406 if (sc->packet[0] & 0x02) 2407 buttons |= WSMOUSE_BUTTON(3); 2408 wsmouse_buttons(sc_wsmousedev, buttons); 2409 2410 wsmouse_input_sync(sc_wsmousedev); 2411 } 2412 2413 void 2414 elantech_send_input(struct pms_softc *sc, int x, int y, int z, int w) 2415 { 2416 struct elantech_softc *elantech = sc->elantech; 2417 int dx, dy; 2418 u_int buttons = 0; 2419 2420 if (sc->packet[0] & 0x01) 2421 buttons |= WSMOUSE_BUTTON(1); 2422 if (sc->packet[0] & 0x02) 2423 buttons |= WSMOUSE_BUTTON(3); 2424 2425 if (elantech->flags & ELANTECH_F_HAS_ROCKER) { 2426 if (sc->packet[0] & 0x40) /* up */ 2427 buttons |= WSMOUSE_BUTTON(4); 2428 if (sc->packet[0] & 0x80) /* down */ 2429 buttons |= WSMOUSE_BUTTON(5); 2430 } 2431 2432 if (elantech->wsmode == WSMOUSE_NATIVE) { 2433 WSMOUSE_TOUCH(sc->sc_wsmousedev, buttons, x, y, z, w); 2434 } else { 2435 dx = dy = 0; 2436 2437 if ((elantech->flags & ELANTECH_F_REPORTS_PRESSURE) && 2438 z > SYNAPTICS_PRESSURE) { 2439 dx = x - elantech->old_x; 2440 dy = y - elantech->old_y; 2441 dx /= SYNAPTICS_SCALE; 2442 dy /= SYNAPTICS_SCALE; 2443 } 2444 if (dx || dy || buttons != elantech->old_buttons) 2445 WSMOUSE_INPUT(sc->sc_wsmousedev, buttons, dx, dy, 0, 0); 2446 elantech->old_buttons = buttons; 2447 } 2448 2449 elantech->old_x = x; 2450 elantech->old_y = y; 2451 } 2452