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