pms.c revision 1.19
1/* $OpenBSD: pms.c,v 1.19 2011/08/17 16:10:27 shadchin 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#define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 43 44#define WSMOUSE_BUTTON(x) (1 << ((x) - 1)) 45 46struct pms_softc; 47 48struct pms_protocol { 49 int type; 50#define PMS_STANDARD 0 51#define PMS_INTELLI 1 52#define PMS_SYNAPTICS 2 53 u_int packetsize; 54 int (*enable)(struct pms_softc *); 55 int (*ioctl)(struct pms_softc *, u_long, caddr_t, int, struct proc *); 56 int (*sync)(struct pms_softc *, int); 57 void (*proc)(struct pms_softc *); 58 void (*disable)(struct pms_softc *); 59}; 60 61struct synaptics_softc { 62 int identify; 63 int capabilities, ext_capabilities; 64 int model, ext_model; 65 int resolution, dimension; 66 67 int mode; 68 69 int res_x, res_y; 70 int min_x, min_y; 71 int max_x, max_y; 72 73 /* Compat mode */ 74 int wsmode; 75 int old_x, old_y; 76 u_int old_buttons; 77#define SYNAPTICS_SCALE 4 78#define SYNAPTICS_PRESSURE 30 79}; 80 81struct pms_softc { /* driver status information */ 82 struct device sc_dev; 83 84 pckbc_tag_t sc_kbctag; 85 86 int sc_state; 87#define PMS_STATE_DISABLED 0 88#define PMS_STATE_ENABLED 1 89#define PMS_STATE_SUSPENDED 2 90 91 int sc_dev_enable; 92#define PMS_DEV_IGNORE 0x00 93#define PMS_DEV_PRIMARY 0x01 94#define PMS_DEV_SECONDARY 0x02 95 96 int poll; 97 int inputstate; 98 99 const struct pms_protocol *protocol; 100 struct synaptics_softc *synaptics; 101 102 u_char packet[8]; 103 104 struct device *sc_wsmousedev; 105 struct device *sc_pt_wsmousedev; 106}; 107 108static const u_int butmap[8] = { 109 0, 110 WSMOUSE_BUTTON(1), 111 WSMOUSE_BUTTON(3), 112 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(3), 113 WSMOUSE_BUTTON(2), 114 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2), 115 WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3), 116 WSMOUSE_BUTTON(1) | WSMOUSE_BUTTON(2) | WSMOUSE_BUTTON(3) 117}; 118 119int pmsprobe(struct device *, void *, void *); 120void pmsattach(struct device *, struct device *, void *); 121int pmsactivate(struct device *, int); 122 123void pmsinput(void *, int); 124 125int pms_change_state(struct pms_softc *, int, int); 126int pms_ioctl(void *, u_long, caddr_t, int, struct proc *); 127int pms_enable(void *); 128void pms_disable(void *); 129 130int pms_cmd(struct pms_softc *, u_char *, int, u_char *, int); 131int pms_spec_cmd(struct pms_softc *, int); 132int pms_get_devid(struct pms_softc *, u_char *); 133int pms_get_status(struct pms_softc *, u_char *); 134int pms_set_rate(struct pms_softc *, int); 135int pms_set_resolution(struct pms_softc *, int); 136int pms_set_scaling(struct pms_softc *, int); 137int pms_reset(struct pms_softc *); 138int pms_dev_enable(struct pms_softc *); 139int pms_dev_disable(struct pms_softc *); 140 141int pms_enable_intelli(struct pms_softc *); 142 143int pms_ioctl_mouse(struct pms_softc *, u_long, caddr_t, int, struct proc *); 144int pms_sync_mouse(struct pms_softc *, int); 145void pms_proc_mouse(struct pms_softc *); 146 147int pms_enable_synaptics(struct pms_softc *); 148int pms_ioctl_synaptics(struct pms_softc *, u_long, caddr_t, int, struct proc *); 149int pms_sync_synaptics(struct pms_softc *, int); 150void pms_proc_synaptics(struct pms_softc *); 151void pms_disable_synaptics(struct pms_softc *); 152 153int synaptics_set_mode(struct pms_softc *, int); 154int synaptics_query(struct pms_softc *, int, int *); 155int synaptics_get_hwinfo(struct pms_softc *); 156 157void synaptics_pt_proc(struct pms_softc *); 158 159int synaptics_pt_ioctl(void *, u_long, caddr_t, int, struct proc *); 160int synaptics_pt_enable(void *); 161void synaptics_pt_disable(void *); 162 163struct cfattach pms_ca = { 164 sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, 165 pmsactivate 166}; 167 168struct cfdriver pms_cd = { 169 NULL, "pms", DV_DULL 170}; 171 172const struct wsmouse_accessops pms_accessops = { 173 pms_enable, 174 pms_ioctl, 175 pms_disable, 176}; 177 178const struct wsmouse_accessops synaptics_pt_accessops = { 179 synaptics_pt_enable, 180 synaptics_pt_ioctl, 181 synaptics_pt_disable, 182}; 183 184const struct pms_protocol pms_protocols[] = { 185 /* Generic PS/2 mouse */ 186 { 187 PMS_STANDARD, 3, 188 NULL, 189 pms_ioctl_mouse, 190 pms_sync_mouse, 191 pms_proc_mouse, 192 NULL 193 }, 194 /* Microsoft IntelliMouse */ 195 { 196 PMS_INTELLI, 4, 197 pms_enable_intelli, 198 pms_ioctl_mouse, 199 pms_sync_mouse, 200 pms_proc_mouse, 201 NULL 202 }, 203 /* Synaptics touchpad */ 204 { 205 PMS_SYNAPTICS, 6, 206 pms_enable_synaptics, 207 pms_ioctl_synaptics, 208 pms_sync_synaptics, 209 pms_proc_synaptics, 210 pms_disable_synaptics 211 } 212}; 213 214int 215pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen) 216{ 217 if (sc->poll) { 218 return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 219 cmd, len, resplen, resp, 1); 220 } else { 221 return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT, 222 cmd, len, resplen, 1, resp); 223 } 224} 225 226int 227pms_spec_cmd(struct pms_softc *sc, int cmd) 228{ 229 if (pms_set_scaling(sc, 1) || 230 pms_set_resolution(sc, (cmd >> 6) & 0x03) || 231 pms_set_resolution(sc, (cmd >> 4) & 0x03) || 232 pms_set_resolution(sc, (cmd >> 2) & 0x03) || 233 pms_set_resolution(sc, (cmd >> 0) & 0x03)) 234 return (-1); 235 return (0); 236} 237 238int 239pms_get_devid(struct pms_softc *sc, u_char *resp) 240{ 241 u_char cmd[1]; 242 243 cmd[0] = PMS_SEND_DEV_ID; 244 return (pms_cmd(sc, cmd, 1, resp, 1)); 245} 246 247int 248pms_get_status(struct pms_softc *sc, u_char *resp) 249{ 250 u_char cmd[1]; 251 252 cmd[0] = PMS_SEND_DEV_STATUS; 253 return (pms_cmd(sc, cmd, 1, resp, 3)); 254} 255 256int 257pms_set_rate(struct pms_softc *sc, int value) 258{ 259 u_char cmd[2]; 260 261 cmd[0] = PMS_SET_SAMPLE; 262 cmd[1] = value; 263 return (pms_cmd(sc, cmd, 2, NULL, 0)); 264} 265 266int 267pms_set_resolution(struct pms_softc *sc, int value) 268{ 269 u_char cmd[2]; 270 271 cmd[0] = PMS_SET_RES; 272 cmd[1] = value; 273 return (pms_cmd(sc, cmd, 2, NULL, 0)); 274} 275 276int 277pms_set_scaling(struct pms_softc *sc, int scale) 278{ 279 u_char cmd[1]; 280 281 switch (scale) { 282 case 1: 283 default: 284 cmd[0] = PMS_SET_SCALE11; 285 break; 286 case 2: 287 cmd[0] = PMS_SET_SCALE21; 288 break; 289 } 290 return (pms_cmd(sc, cmd, 1, NULL, 0)); 291} 292 293int 294pms_reset(struct pms_softc *sc) 295{ 296 u_char cmd[1], resp[2]; 297 int res; 298 299 cmd[0] = PMS_RESET; 300 res = pms_cmd(sc, cmd, 1, resp, 2); 301#ifdef DEBUG 302 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) 303 printf("%s: reset error %d (response 0x%02x, type 0x%02x)\n", 304 DEVNAME(sc), res, resp[0], resp[1]); 305#endif 306 return (res); 307} 308 309int 310pms_dev_enable(struct pms_softc *sc) 311{ 312 u_char cmd[1]; 313 int res; 314 315 cmd[0] = PMS_DEV_ENABLE; 316 res = pms_cmd(sc, cmd, 1, NULL, 0); 317 if (res) 318 printf("%s: enable error\n", DEVNAME(sc)); 319 return (res); 320} 321 322int 323pms_dev_disable(struct pms_softc *sc) 324{ 325 u_char cmd[1]; 326 int res; 327 328 cmd[0] = PMS_DEV_DISABLE; 329 res = pms_cmd(sc, cmd, 1, NULL, 0); 330 if (res) 331 printf("%s: disable error\n", DEVNAME(sc)); 332 return (res); 333} 334 335int 336pms_enable_intelli(struct pms_softc *sc) 337{ 338 u_char resp; 339 340 /* the special sequence to enable the third button and the roller */ 341 if (pms_set_rate(sc, PMS_INTELLI_MAGIC1) || 342 pms_set_rate(sc, PMS_INTELLI_MAGIC2) || 343 pms_set_rate(sc, PMS_INTELLI_MAGIC3) || 344 pms_get_devid(sc, &resp) || 345 resp != PMS_INTELLI_ID) 346 return (0); 347 348 return (1); 349} 350 351int 352pms_ioctl_mouse(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 353 struct proc *p) 354{ 355 int i; 356 357 switch (cmd) { 358 case WSMOUSEIO_GTYPE: 359 *(u_int *)data = WSMOUSE_TYPE_PS2; 360 break; 361 case WSMOUSEIO_SRES: 362 i = ((int) *(u_int *)data - 12) / 25; 363 /* valid values are {0,1,2,3} */ 364 if (i < 0) 365 i = 0; 366 if (i > 3) 367 i = 3; 368 369 if (pms_set_resolution(sc, i)) 370 printf("%s: SET_RES command error\n", DEVNAME(sc)); 371 break; 372 default: 373 return (-1); 374 } 375 return (0); 376} 377 378int 379pms_sync_mouse(struct pms_softc *sc, int data) 380{ 381 if (sc->inputstate != 0) 382 return (0); 383 384 switch (sc->protocol->type) { 385 case PMS_STANDARD: 386 if ((data & 0xc0) != 0) 387 return (-1); 388 break; 389 case PMS_INTELLI: 390 if ((data & 0x08) != 0x08) 391 return (-1); 392 break; 393 } 394 395 return (0); 396} 397 398void 399pms_proc_mouse(struct pms_softc *sc) 400{ 401 u_int buttons; 402 int dx, dy, dz; 403 404 buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK]; 405 dx = (sc->packet[0] & PMS_PS2_XNEG) ? 406 (int)sc->packet[1] - 256 : sc->packet[1]; 407 dy = (sc->packet[0] & PMS_PS2_YNEG) ? 408 (int)sc->packet[2] - 256 : sc->packet[2]; 409 410 switch (sc->protocol->type) { 411 case PMS_STANDARD: 412 dz = 0; 413 break; 414 case PMS_INTELLI: 415 dz = (signed char)sc->packet[3]; 416 break; 417 } 418 419 wsmouse_input(sc->sc_wsmousedev, 420 buttons, dx, dy, dz, 0, WSMOUSE_INPUT_DELTA); 421} 422 423int 424pmsprobe(struct device *parent, void *match, void *aux) 425{ 426 struct pckbc_attach_args *pa = aux; 427 u_char cmd[1], resp[2]; 428 int res; 429 430 if (pa->pa_slot != PCKBC_AUX_SLOT) 431 return (0); 432 433 /* Flush any garbage. */ 434 pckbc_flush(pa->pa_tag, pa->pa_slot); 435 436 /* reset the device */ 437 cmd[0] = PMS_RESET; 438 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1); 439 if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) { 440#ifdef DEBUG 441 printf("pms: reset error %d (response 0x%02x, type 0x%02x)\n", 442 res, resp[0], resp[1]); 443#endif 444 return (0); 445 } 446 447 return (1); 448} 449 450void 451pmsattach(struct device *parent, struct device *self, void *aux) 452{ 453 struct pms_softc *sc = (void *)self; 454 struct pckbc_attach_args *pa = aux; 455 struct wsmousedev_attach_args a; 456 int i; 457 458 sc->sc_kbctag = pa->pa_tag; 459 460 printf("\n"); 461 462 pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT, 463 pmsinput, sc, DEVNAME(sc)); 464 465 a.accessops = &pms_accessops; 466 a.accesscookie = sc; 467 468 /* 469 * Attach the wsmouse, saving a handle to it. 470 * Note that we don't need to check this pointer against NULL 471 * here or in pmsintr, because if this fails pms_enable() will 472 * never be called, so pmsinput() will never be called. 473 */ 474 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 475 476 sc->poll = 1; 477 sc->sc_dev_enable = 0; 478 479 sc->protocol = &pms_protocols[0]; 480 for (i = 1; i < nitems(pms_protocols); i++) { 481 pms_reset(sc); 482 if (pms_protocols[i].enable(sc)) 483 sc->protocol = &pms_protocols[i]; 484 } 485 486 /* no interrupts until enabled */ 487 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_IGNORE); 488} 489 490int 491pmsactivate(struct device *self, int act) 492{ 493 struct pms_softc *sc = (struct pms_softc *)self; 494 495 switch (act) { 496 case DVACT_SUSPEND: 497 if (sc->sc_state == PMS_STATE_ENABLED) 498 pms_change_state(sc, PMS_STATE_SUSPENDED, 499 PMS_DEV_IGNORE); 500 break; 501 case DVACT_RESUME: 502 if (sc->sc_state == PMS_STATE_SUSPENDED) 503 pms_change_state(sc, PMS_STATE_ENABLED, 504 PMS_DEV_IGNORE); 505 break; 506 } 507 return (0); 508} 509 510int 511pms_change_state(struct pms_softc *sc, int newstate, int dev) 512{ 513 int i; 514 515 if (dev != PMS_DEV_IGNORE) { 516 switch (newstate) { 517 case PMS_STATE_ENABLED: 518 if (sc->sc_dev_enable & dev) 519 return (EBUSY); 520 521 sc->sc_dev_enable |= dev; 522 523 if (sc->sc_state == PMS_STATE_ENABLED) 524 return (0); 525 526 break; 527 case PMS_STATE_DISABLED: 528 sc->sc_dev_enable &= ~dev; 529 530 if (sc->sc_dev_enable) 531 return (0); 532 533 break; 534 } 535 } 536 537 switch (newstate) { 538 case PMS_STATE_ENABLED: 539 sc->inputstate = 0; 540 541 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1); 542 543 if (sc->poll) 544 pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT); 545 546 pms_reset(sc); 547 548 if (sc->protocol->type != PMS_STANDARD && 549 sc->protocol->enable(sc) == 0) 550 sc->protocol = &pms_protocols[0]; 551 552 if (sc->protocol->type == PMS_STANDARD) 553 for (i = 1; i < nitems(pms_protocols); i++) { 554 pms_reset(sc); 555 if (pms_protocols[i].enable(sc)) 556 sc->protocol = &pms_protocols[i]; 557 } 558 559#ifdef DEBUG 560 printf("%s: protocol type %d\n", DEVNAME(sc), sc->protocol->type); 561#endif 562 563 pms_dev_enable(sc); 564 break; 565 case PMS_STATE_DISABLED: 566 case PMS_STATE_SUSPENDED: 567 pms_dev_disable(sc); 568 569 if (sc->protocol && sc->protocol->disable) 570 sc->protocol->disable(sc); 571 572 pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0); 573 break; 574 } 575 576 sc->sc_state = newstate; 577 sc->poll = (newstate == PMS_STATE_SUSPENDED) ? 1 : 0; 578 579 return (0); 580} 581 582int 583pms_enable(void *v) 584{ 585 struct pms_softc *sc = v; 586 587 return pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_PRIMARY); 588} 589 590void 591pms_disable(void *v) 592{ 593 struct pms_softc *sc = v; 594 595 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_PRIMARY); 596} 597 598int 599pms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 600{ 601 struct pms_softc *sc = v; 602 603 if (sc->protocol && sc->protocol->ioctl) 604 return (sc->protocol->ioctl(sc, cmd, data, flag, p)); 605 else 606 return (-1); 607} 608 609void 610pmsinput(void *vsc, int data) 611{ 612 struct pms_softc *sc = vsc; 613 614 if (sc->sc_state != PMS_STATE_ENABLED) { 615 /* Interrupts are not expected. Discard the byte. */ 616 return; 617 } 618 619 if (sc->protocol->sync(sc, data)) { 620#ifdef DIAGNOSTIC 621 printf("%s: not in sync yet, discard input\n", DEVNAME(sc)); 622#endif 623 sc->inputstate = 0; 624 return; 625 } 626 627 sc->packet[sc->inputstate++] = data; 628 if (sc->inputstate != sc->protocol->packetsize) 629 return; 630 631 sc->protocol->proc(sc); 632 sc->inputstate = 0; 633} 634 635int 636synaptics_set_mode(struct pms_softc *sc, int mode) 637{ 638 struct synaptics_softc *syn = sc->synaptics; 639 640 if (pms_spec_cmd(sc, mode) || 641 pms_set_rate(sc, SYNAPTICS_CMD_SET_MODE)) 642 return (-1); 643 644 syn->mode = mode; 645 646 return (0); 647} 648 649int 650synaptics_query(struct pms_softc *sc, int query, int *val) 651{ 652 u_char resp[3]; 653 654 if (pms_spec_cmd(sc, query) || 655 pms_get_status(sc, resp)) 656 return (-1); 657 658 if (val) 659 *val = (resp[0] << 16) | (resp[1] << 8) | resp[2]; 660 661 return (0); 662} 663 664int 665synaptics_get_hwinfo(struct pms_softc *sc) 666{ 667 struct synaptics_softc *syn = sc->synaptics; 668 669 if (synaptics_query(sc, SYNAPTICS_QUE_IDENTIFY, &syn->identify)) 670 return (-1); 671 if (synaptics_query(sc, SYNAPTICS_QUE_CAPABILITIES, 672 &syn->capabilities)) 673 return (-1); 674 if (synaptics_query(sc, SYNAPTICS_QUE_MODEL, &syn->model)) 675 return (-1); 676 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 1) && 677 synaptics_query(sc, SYNAPTICS_QUE_EXT_MODEL, &syn->ext_model)) 678 return (-1); 679 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 4) && 680 synaptics_query(sc, SYNAPTICS_QUE_EXT_CAPABILITIES, 681 &syn->ext_capabilities)) 682 return (-1); 683 if ((SYNAPTICS_ID_MAJOR(syn->identify) >= 4) && 684 synaptics_query(sc, SYNAPTICS_QUE_RESOLUTION, &syn->resolution)) 685 return (-1); 686 if ((SYNAPTICS_CAP_EXTENDED_QUERIES(syn->capabilities) >= 5) && 687 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_MAX_DIMENSIONS) && 688 synaptics_query(sc, SYNAPTICS_QUE_EXT_DIMENSIONS, &syn->dimension)) 689 return (-1); 690 691 syn->res_x = SYNAPTICS_RESOLUTION_X(syn->resolution); 692 syn->res_y = SYNAPTICS_RESOLUTION_Y(syn->resolution); 693 syn->min_x = SYNAPTICS_XMIN_BEZEL; 694 syn->min_y = SYNAPTICS_YMIN_BEZEL; 695 syn->max_x = (syn->dimension) ? 696 SYNAPTICS_DIM_X(syn->dimension) : SYNAPTICS_XMAX_BEZEL; 697 syn->max_y = (syn->dimension) ? 698 SYNAPTICS_DIM_Y(syn->dimension) : SYNAPTICS_YMAX_BEZEL; 699 700 if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) > 8) 701 syn->ext_model &= ~0xf000; 702 703 return (0); 704} 705 706void 707synaptics_pt_proc(struct pms_softc *sc) 708{ 709 u_int buttons; 710 int dx, dy; 711 712 if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0) 713 return; 714 715 buttons = butmap[sc->packet[1] & PMS_PS2_BUTTONSMASK]; 716 dx = (sc->packet[1] & PMS_PS2_XNEG) ? 717 (int)sc->packet[4] - 256 : sc->packet[4]; 718 dy = (sc->packet[1] & PMS_PS2_YNEG) ? 719 (int)sc->packet[5] - 256 : sc->packet[5]; 720 721 wsmouse_input(sc->sc_pt_wsmousedev, 722 buttons, dx, dy, 0, 0, WSMOUSE_INPUT_DELTA); 723} 724 725int 726synaptics_pt_enable(void *v) 727{ 728 struct pms_softc *sc = v; 729 730 return (pms_change_state(sc, PMS_STATE_ENABLED, PMS_DEV_SECONDARY)); 731} 732 733void 734synaptics_pt_disable(void *v) 735{ 736 struct pms_softc *sc = v; 737 738 pms_change_state(sc, PMS_STATE_DISABLED, PMS_DEV_SECONDARY); 739} 740 741int 742synaptics_pt_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 743{ 744 switch (cmd) { 745 case WSMOUSEIO_GTYPE: 746 *(u_int *)data = WSMOUSE_TYPE_PS2; 747 break; 748 default: 749 return (-1); 750 } 751 return (0); 752} 753 754int 755pms_enable_synaptics(struct pms_softc *sc) 756{ 757 struct synaptics_softc *syn = sc->synaptics; 758 struct wsmousedev_attach_args a; 759 u_char resp[3]; 760 int mode; 761 762 if (pms_set_resolution(sc, 0) || 763 pms_set_resolution(sc, 0) || 764 pms_set_resolution(sc, 0) || 765 pms_set_resolution(sc, 0) || 766 pms_get_status(sc, resp) || 767 resp[1] != SYNAPTICS_ID_MAGIC) 768 return (0); 769 770 if (sc->synaptics == NULL) { 771 sc->synaptics = syn = malloc(sizeof(struct synaptics_softc), 772 M_DEVBUF, M_WAITOK | M_ZERO); 773 if (syn == NULL) { 774 printf("%s: synaptics: not enough memory\n", 775 DEVNAME(sc)); 776 return (0); 777 } 778 779 if (synaptics_get_hwinfo(sc)) 780 return (0); 781 782 if ((syn->model & SYNAPTICS_MODEL_NEWABS) == 0) { 783 printf("%s: don't support Synaptics OLDABS\n", 784 DEVNAME(sc)); 785 return (0); 786 } 787 788 /* enable pass-through PS/2 port if supported */ 789 if (syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) { 790 a.accessops = &synaptics_pt_accessops; 791 a.accesscookie = sc; 792 sc->sc_pt_wsmousedev = config_found((void *)sc, &a, 793 wsmousedevprint); 794 } 795 796 syn->wsmode = WSMOUSE_COMPAT; 797 798 printf("%s: Synaptics %s, firmware %d.%d\n", DEVNAME(sc), 799 (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD ? 800 "clickpad" : "touchpad"), 801 SYNAPTICS_ID_MAJOR(syn->identify), 802 SYNAPTICS_ID_MINOR(syn->identify)); 803 } 804 805 mode = SYNAPTICS_ABSOLUTE_MODE | SYNAPTICS_HIGH_RATE; 806 if (SYNAPTICS_ID_MAJOR(syn->identify) >= 4) 807 mode |= SYNAPTICS_DISABLE_GESTURE; 808 if (syn->capabilities & SYNAPTICS_CAP_EXTENDED) 809 mode |= SYNAPTICS_W_MODE; 810 if (synaptics_set_mode(sc, mode)) 811 return (0); 812 813 /* enable advanced gesture mode if supported */ 814 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && 815 (pms_spec_cmd(sc, SYNAPTICS_QUE_MODEL) || 816 pms_set_rate(sc, SYNAPTICS_CMD_SET_ADV_GESTURE_MODE))) 817 return (0); 818 819 return (1); 820} 821 822int 823pms_ioctl_synaptics(struct pms_softc *sc, u_long cmd, caddr_t data, int flag, 824 struct proc *p) 825{ 826 struct synaptics_softc *syn = sc->synaptics; 827 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 828 int wsmode; 829 830 switch (cmd) { 831 case WSMOUSEIO_GTYPE: 832 *(u_int *)data = WSMOUSE_TYPE_SYNAPTICS; 833 break; 834 case WSMOUSEIO_GCALIBCOORDS: 835 wsmc->minx = syn->min_x; 836 wsmc->maxx = syn->max_x; 837 wsmc->miny = syn->min_y; 838 wsmc->maxy = syn->max_y; 839 wsmc->swapxy = 0; 840 wsmc->resx = syn->res_x; 841 wsmc->resy = syn->res_y; 842 break; 843 case WSMOUSEIO_SETMODE: 844 wsmode = *(u_int *)data; 845 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) 846 return (EINVAL); 847 syn->wsmode = wsmode; 848 break; 849 default: 850 return (-1); 851 } 852 return (0); 853} 854 855int 856pms_sync_synaptics(struct pms_softc *sc, int data) 857{ 858 switch (sc->inputstate) { 859 case 0: 860 if ((data & 0xc8) != 0x80) 861 return (-1); 862 break; 863 case 3: 864 if ((data & 0xc8) != 0xc0) 865 return (-1); 866 break; 867 } 868 869 return (0); 870} 871 872void 873pms_proc_synaptics(struct pms_softc *sc) 874{ 875 struct synaptics_softc *syn = sc->synaptics; 876 u_int buttons; 877 int x, y, z, w, dx, dy; 878 879 w = ((sc->packet[0] & 0x30) >> 2) | ((sc->packet[0] & 0x04) >> 1) | 880 ((sc->packet[3] & 0x04) >> 2); 881 882 if ((syn->capabilities & SYNAPTICS_CAP_PASSTHROUGH) && w == 3) { 883 synaptics_pt_proc(sc); 884 return; 885 } 886 887 if ((sc->sc_dev_enable & PMS_DEV_PRIMARY) == 0) 888 return; 889 890 /* XXX ignore advanced gesture packet, not yet supported */ 891 if ((syn->ext_capabilities & SYNAPTICS_EXT_CAP_ADV_GESTURE) && w == 2) 892 return; 893 894 x = ((sc->packet[3] & 0x10) << 8) | ((sc->packet[1] & 0x0f) << 8) | 895 sc->packet[4]; 896 y = ((sc->packet[3] & 0x20) << 7) | ((sc->packet[1] & 0xf0) << 4) | 897 sc->packet[5]; 898 z = sc->packet[2]; 899 900 buttons = ((sc->packet[0] & sc->packet[3]) & 0x01) ? 901 WSMOUSE_BUTTON(1) : 0; 902 buttons |= ((sc->packet[0] & sc->packet[3]) & 0x02) ? 903 WSMOUSE_BUTTON(3) : 0; 904 905 if (syn->ext_capabilities & SYNAPTICS_EXT_CAP_CLICKPAD) { 906 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 907 WSMOUSE_BUTTON(1) : 0; 908 } else if (syn->capabilities & SYNAPTICS_CAP_MIDDLE_BUTTON) { 909 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 910 WSMOUSE_BUTTON(2) : 0; 911 } 912 913 if (syn->capabilities & SYNAPTICS_CAP_FOUR_BUTTON) { 914 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x01) ? 915 WSMOUSE_BUTTON(4) : 0; 916 buttons |= ((sc->packet[0] ^ sc->packet[3]) & 0x02) ? 917 WSMOUSE_BUTTON(5) : 0; 918 } else if (SYNAPTICS_EXT_MODEL_BUTTONS(syn->ext_model) && 919 ((sc->packet[0] ^ sc->packet[3]) & 0x02)) { 920 buttons |= (sc->packet[4] & 0x01) ? WSMOUSE_BUTTON(6) : 0; 921 buttons |= (sc->packet[5] & 0x01) ? WSMOUSE_BUTTON(7) : 0; 922 buttons |= (sc->packet[4] & 0x02) ? WSMOUSE_BUTTON(8) : 0; 923 buttons |= (sc->packet[5] & 0x02) ? WSMOUSE_BUTTON(9) : 0; 924 buttons |= (sc->packet[4] & 0x04) ? WSMOUSE_BUTTON(10) : 0; 925 buttons |= (sc->packet[5] & 0x04) ? WSMOUSE_BUTTON(11) : 0; 926 buttons |= (sc->packet[4] & 0x08) ? WSMOUSE_BUTTON(12) : 0; 927 buttons |= (sc->packet[5] & 0x08) ? WSMOUSE_BUTTON(13) : 0; 928 x &= ~0x0f; 929 y &= ~0x0f; 930 } 931 932 /* ignore final events that happen when removing all fingers */ 933 if (x <= 1 || y <= 1) { 934 x = syn->old_x; 935 y = syn->old_y; 936 } 937 938 if (syn->wsmode == WSMOUSE_NATIVE) { 939 wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, w, 940 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | 941 WSMOUSE_INPUT_ABSOLUTE_Z | WSMOUSE_INPUT_ABSOLUTE_W); 942 } else { 943 dx = dy = 0; 944 if (z > SYNAPTICS_PRESSURE) { 945 dx = x - syn->old_x; 946 dy = y - syn->old_y; 947 dx /= SYNAPTICS_SCALE; 948 dy /= SYNAPTICS_SCALE; 949 } 950 if (dx || dy || buttons != syn->old_buttons) 951 wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, 0, 0, 952 WSMOUSE_INPUT_DELTA); 953 syn->old_buttons = buttons; 954 } 955 956 syn->old_x = x; 957 syn->old_y = y; 958} 959 960void 961pms_disable_synaptics(struct pms_softc *sc) 962{ 963 struct synaptics_softc *syn = sc->synaptics; 964 965 if (syn->capabilities & SYNAPTICS_CAP_SLEEP) 966 synaptics_set_mode(sc, SYNAPTICS_SLEEP_MODE | 967 SYNAPTICS_DISABLE_GESTURE); 968} 969