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