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