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