1 /* 2 * Copyright (c) 2014 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> and was subsequently ported, 6 * modified and enhanced for FreeBSD by Michael Gmelin <freebsd@grem.de>. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 /* 40 * CYAPA - Cypress APA trackpad with I2C Interface driver 41 * 42 * Based on DragonFlyBSD's cyapa driver, which referenced the linux 43 * cyapa.c driver to figure out the bootstrapping and commands. 44 * 45 * Unable to locate any datasheet for the device. 46 * 47 * 48 * Trackpad layout: 49 * 50 * 2/3 1/3 51 * +--------------------+------------+ 52 * | | Middle | 53 * | | Button | 54 * | Left | | 55 * | Button +------------+ 56 * | | Right | 57 * | | Button | 58 * +--------------------+............| 59 * | Thumb/Button Area | 15% 60 * +---------------------------------+ 61 * 62 * 63 * FEATURES 64 * 65 * IMPS/2 emulation - Emulates the IntelliMouse protocol. 66 * 67 * Jitter supression - Implements 2-pixel hysteresis with memory. 68 * 69 * Jump detecion - Detect jumps caused by touchpad. 70 * 71 * Two finger scrolling - Use two fingers for Z axis scrolling. 72 * 73 * Button down/2nd finger - While one finger clicks and holds down the 74 * touchpad, the second one can be used to move 75 * the mouse cursor. Useful for drawing or 76 * selecting text. 77 * 78 * Thumb/Button Area - The lower 15%* of the trackpad will not affect 79 * the mouse cursor position. This allows for high 80 * precision clicking, by controlling the cursor 81 * with the index finger and pushing/holding the 82 * pad down with the thumb. 83 * * can be changed using sysctl 84 * 85 * Track-pad button - Push physical button. Left 2/3rds of the pad 86 * will issue a LEFT button event, upper right 87 * corner will issue a MIDDLE button event, 88 * lower right corner will issue a RIGHT button 89 * event. Optional tap support can be enabled 90 * and configured using sysctl. 91 * 92 * WARNINGS 93 * 94 * These trackpads get confused when three or more fingers are down on the 95 * same horizontal axis and will start to glitch the finger detection. 96 * Removing your hand for a few seconds will allow the trackpad to 97 * recalibrate. Generally speaking, when using three or more fingers 98 * please try to place at least one finger off-axis (a little above or 99 * below) the other two. 100 */ 101 102 #include <sys/param.h> 103 #include <sys/bus.h> 104 #include <sys/conf.h> 105 #include <sys/event.h> 106 #include <sys/fcntl.h> 107 #include <sys/kernel.h> 108 #include <sys/kthread.h> 109 #include <sys/lock.h> 110 #include <sys/lockmgr.h> 111 #include <sys/malloc.h> 112 #include <sys/mbuf.h> 113 #include <sys/module.h> 114 #include <sys/mouse.h> 115 #include <sys/mutex.h> 116 #include <sys/poll.h> 117 #include <sys/selinfo.h> 118 #include <sys/sysctl.h> 119 #include <sys/sysctl.h> 120 #include <sys/systm.h> 121 #include <sys/systm.h> 122 #include <sys/uio.h> 123 #include <sys/vnode.h> 124 125 #include <dev/iicbus/iiconf.h> 126 #include <dev/iicbus/iicbus.h> 127 #include <dev/cyapa/cyapa.h> 128 129 #include "iicbus_if.h" 130 #include "bus_if.h" 131 #include "device_if.h" 132 133 #define CYAPA_BUFSIZE 128 /* power of 2 */ 134 #define CYAPA_BUFMASK (CYAPA_BUFSIZE - 1) 135 136 #define ZSCALE 15 137 138 #define TIME_TO_IDLE (hz * 10) 139 #define TIME_TO_RESET (hz * 3) 140 141 static MALLOC_DEFINE(M_CYAPA, "cyapa", "CYAPA device data"); 142 143 struct cyapa_fifo { 144 int rindex; 145 int windex; 146 char buf[CYAPA_BUFSIZE]; 147 }; 148 149 struct cyapa_softc { 150 device_t dev; 151 int count; /* >0 if device opened */ 152 struct cdev *devnode; 153 struct selinfo selinfo; 154 struct mtx mutex; 155 156 int cap_resx; 157 int cap_resy; 158 int cap_phyx; 159 int cap_phyy; 160 uint8_t cap_buttons; 161 162 int detaching; /* driver is detaching */ 163 int poll_thread_running; /* poll thread is running */ 164 165 /* PS/2 mouse emulation */ 166 int track_x; /* current tracking */ 167 int track_y; 168 int track_z; 169 int track_z_ticks; 170 uint16_t track_but; 171 char track_id; /* first finger id */ 172 int track_nfingers; 173 int delta_x; /* accumulation -> report */ 174 int delta_y; 175 int delta_z; 176 int fuzz_x; 177 int fuzz_y; 178 int fuzz_z; 179 int touch_x; /* touch down coordinates */ 180 int touch_y; 181 int touch_z; 182 int finger1_ticks; 183 int finger2_ticks; 184 int finger3_ticks; 185 uint16_t reported_but; 186 187 struct cyapa_fifo rfifo; /* device->host */ 188 struct cyapa_fifo wfifo; /* host->device */ 189 uint8_t ps2_cmd; /* active p2_cmd waiting for data */ 190 uint8_t ps2_acked; 191 int active_tick; 192 int data_signal; 193 int blocked; 194 int isselect; 195 int reporting_mode; /* 0=disabled 1=enabled */ 196 int scaling_mode; /* 0=1:1 1=2:1 */ 197 int remote_mode; /* 0 for streaming mode */ 198 int zenabled; /* z-axis enabled (mode 1 or 2) */ 199 mousehw_t hw; /* hardware information */ 200 mousemode_t mode; /* mode */ 201 int poll_ticks; 202 }; 203 204 struct cyapa_cdevpriv { 205 struct cyapa_softc *sc; 206 }; 207 208 #define CYPOLL_SHUTDOWN 0x0001 209 210 static void cyapa_poll_thread(void *arg); 211 static int cyapa_raw_input(struct cyapa_softc *sc, struct cyapa_regs *regs, 212 int freq); 213 static void cyapa_set_power_mode(struct cyapa_softc *sc, int mode); 214 215 static int fifo_empty(struct cyapa_softc *sc, struct cyapa_fifo *fifo); 216 static size_t fifo_ready(struct cyapa_softc *sc, struct cyapa_fifo *fifo); 217 static char *fifo_read(struct cyapa_softc *sc, struct cyapa_fifo *fifo, 218 size_t n); 219 static char *fifo_write(struct cyapa_softc *sc, struct cyapa_fifo *fifo, 220 size_t n); 221 static uint8_t fifo_read_char(struct cyapa_softc *sc, 222 struct cyapa_fifo *fifo); 223 static void fifo_write_char(struct cyapa_softc *sc, struct cyapa_fifo *fifo, 224 uint8_t c); 225 static size_t fifo_space(struct cyapa_softc *sc, struct cyapa_fifo *fifo); 226 static void fifo_reset(struct cyapa_softc *sc, struct cyapa_fifo *fifo); 227 228 static int cyapa_fuzz(int delta, int *fuzz); 229 230 static int cyapa_idle_freq = 1; 231 SYSCTL_INT(_debug, OID_AUTO, cyapa_idle_freq, CTLFLAG_RW, 232 &cyapa_idle_freq, 0, "Scan frequency in idle mode"); 233 static int cyapa_slow_freq = 20; 234 SYSCTL_INT(_debug, OID_AUTO, cyapa_slow_freq, CTLFLAG_RW, 235 &cyapa_slow_freq, 0, "Scan frequency in slow mode "); 236 static int cyapa_norm_freq = 100; 237 SYSCTL_INT(_debug, OID_AUTO, cyapa_norm_freq, CTLFLAG_RW, 238 &cyapa_norm_freq, 0, "Normal scan frequency"); 239 static int cyapa_minpressure = 12; 240 SYSCTL_INT(_debug, OID_AUTO, cyapa_minpressure, CTLFLAG_RW, 241 &cyapa_minpressure, 0, "Minimum pressure to detect finger"); 242 static int cyapa_enable_tapclick = 0; 243 SYSCTL_INT(_debug, OID_AUTO, cyapa_enable_tapclick, CTLFLAG_RW, 244 &cyapa_enable_tapclick, 0, "Enable tap to click"); 245 static int cyapa_tapclick_min_ticks = 1; 246 SYSCTL_INT(_debug, OID_AUTO, cyapa_tapclick_min_ticks, CTLFLAG_RW, 247 &cyapa_tapclick_min_ticks, 0, "Minimum tap duration for click"); 248 static int cyapa_tapclick_max_ticks = 8; 249 SYSCTL_INT(_debug, OID_AUTO, cyapa_tapclick_max_ticks, CTLFLAG_RW, 250 &cyapa_tapclick_max_ticks, 0, "Maximum tap duration for click"); 251 static int cyapa_move_min_ticks = 4; 252 SYSCTL_INT(_debug, OID_AUTO, cyapa_move_min_ticks, CTLFLAG_RW, 253 &cyapa_move_min_ticks, 0, 254 "Minimum ticks before cursor position is changed"); 255 static int cyapa_scroll_wait_ticks = 0; 256 SYSCTL_INT(_debug, OID_AUTO, cyapa_scroll_wait_ticks, CTLFLAG_RW, 257 &cyapa_scroll_wait_ticks, 0, 258 "Wait N ticks before starting to scroll"); 259 static int cyapa_scroll_stick_ticks = 15; 260 SYSCTL_INT(_debug, OID_AUTO, cyapa_scroll_stick_ticks, CTLFLAG_RW, 261 &cyapa_scroll_stick_ticks, 0, 262 "Prevent cursor move on single finger for N ticks after scroll"); 263 static int cyapa_thumbarea_percent = 15; 264 SYSCTL_INT(_debug, OID_AUTO, cyapa_thumbarea_percent, CTLFLAG_RW, 265 &cyapa_thumbarea_percent, 0, 266 "Size of bottom thumb area in percent"); 267 268 static int cyapa_debug = 0; 269 SYSCTL_INT(_debug, OID_AUTO, cyapa_debug, CTLFLAG_RW, 270 &cyapa_debug, 0, "Enable debugging"); 271 static int cyapa_reset = 0; 272 SYSCTL_INT(_debug, OID_AUTO, cyapa_reset, CTLFLAG_RW, 273 &cyapa_reset, 0, "Reset track pad"); 274 275 static int 276 cyapa_read_bytes(device_t dev, uint8_t reg, uint8_t *val, int cnt) 277 { 278 uint16_t addr = iicbus_get_addr(dev); 279 struct iic_msg msgs[] = { 280 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 281 { addr, IIC_M_RD, cnt, val }, 282 }; 283 284 return (iicbus_transfer(dev, msgs, nitems(msgs))); 285 } 286 287 static int 288 cyapa_write_bytes(device_t dev, uint8_t reg, const uint8_t *val, int cnt) 289 { 290 uint16_t addr = iicbus_get_addr(dev); 291 struct iic_msg msgs[] = { 292 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 293 { addr, IIC_M_WR | IIC_M_NOSTART, cnt, __DECONST(uint8_t *, val) }, 294 }; 295 296 return (iicbus_transfer(dev, msgs, nitems(msgs))); 297 } 298 299 static void 300 cyapa_lock(struct cyapa_softc *sc) 301 { 302 303 mtx_lock(&sc->mutex); 304 } 305 306 static void 307 cyapa_unlock(struct cyapa_softc *sc) 308 { 309 310 mtx_unlock(&sc->mutex); 311 } 312 313 #define CYAPA_LOCK_ASSERT(sc) mtx_assert(&(sc)->mutex, MA_OWNED); 314 315 /* 316 * Notify if possible receive data ready. Must be called 317 * with sc->mutex held (cyapa_lock(sc)). 318 */ 319 static void 320 cyapa_notify(struct cyapa_softc *sc) 321 { 322 323 CYAPA_LOCK_ASSERT(sc); 324 325 if (sc->data_signal || !fifo_empty(sc, &sc->rfifo)) { 326 KNOTE_LOCKED(&sc->selinfo.si_note, 0); 327 if (sc->blocked || sc->isselect) { 328 if (sc->blocked) { 329 sc->blocked = 0; 330 wakeup(&sc->blocked); 331 } 332 if (sc->isselect) { 333 sc->isselect = 0; 334 selwakeup(&sc->selinfo); 335 } 336 } 337 } 338 } 339 340 /* 341 * Initialize the device 342 */ 343 static int 344 init_device(device_t dev, struct cyapa_cap *cap, int probe) 345 { 346 static char bl_exit[] = { 347 0x00, 0xff, 0xa5, 0x00, 0x01, 348 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; 349 static char bl_deactivate[] = { 350 0x00, 0xff, 0x3b, 0x00, 0x01, 351 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; 352 struct cyapa_boot_regs boot; 353 int error; 354 int retries; 355 356 /* Get status */ 357 error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, 358 (void *)&boot, sizeof(boot)); 359 if (error) 360 goto done; 361 362 /* 363 * Bootstrap the device if necessary. It can take up to 2 seconds 364 * for the device to fully initialize. 365 */ 366 retries = 20; 367 while ((boot.stat & CYAPA_STAT_RUNNING) == 0 && retries > 0) { 368 if (boot.boot & CYAPA_BOOT_BUSY) { 369 /* Busy, wait loop. */ 370 } else if (boot.error & CYAPA_ERROR_BOOTLOADER) { 371 /* Magic */ 372 error = cyapa_write_bytes(dev, CMD_BOOT_STATUS, 373 bl_deactivate, sizeof(bl_deactivate)); 374 if (error) 375 goto done; 376 } else { 377 /* Magic */ 378 error = cyapa_write_bytes(dev, CMD_BOOT_STATUS, 379 bl_exit, sizeof(bl_exit)); 380 if (error) 381 goto done; 382 } 383 pause("cyapab1", (hz * 2) / 10); 384 --retries; 385 error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, 386 (void *)&boot, sizeof(boot)); 387 if (error) 388 goto done; 389 } 390 391 if (retries == 0) { 392 device_printf(dev, "Unable to bring device out of bootstrap\n"); 393 error = ENXIO; 394 goto done; 395 } 396 397 /* Check identity */ 398 if (cap) { 399 error = cyapa_read_bytes(dev, CMD_QUERY_CAPABILITIES, 400 (void *)cap, sizeof(*cap)); 401 402 if (strncmp(cap->prod_ida, "CYTRA", 5) != 0) { 403 device_printf(dev, "Product ID \"%5.5s\" mismatch\n", 404 cap->prod_ida); 405 error = ENXIO; 406 } 407 } 408 error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, 409 (void *)&boot, sizeof(boot)); 410 411 if (probe == 0) /* official init */ 412 device_printf(dev, "cyapa init status %02x\n", boot.stat); 413 else if (probe == 2) 414 device_printf(dev, "cyapa reset status %02x\n", boot.stat); 415 416 done: 417 if (error) 418 device_printf(dev, "Unable to initialize\n"); 419 return (error); 420 } 421 422 static int cyapa_probe(device_t); 423 static int cyapa_attach(device_t); 424 static int cyapa_detach(device_t); 425 static void cyapa_cdevpriv_dtor(void*); 426 427 static devclass_t cyapa_devclass; 428 429 static device_method_t cyapa_methods[] = { 430 /* device interface */ 431 DEVMETHOD(device_probe, cyapa_probe), 432 DEVMETHOD(device_attach, cyapa_attach), 433 DEVMETHOD(device_detach, cyapa_detach), 434 435 DEVMETHOD_END 436 }; 437 438 static driver_t cyapa_driver = { 439 "cyapa", 440 cyapa_methods, 441 sizeof(struct cyapa_softc), 442 }; 443 444 static d_open_t cyapaopen; 445 static d_ioctl_t cyapaioctl; 446 static d_read_t cyaparead; 447 static d_write_t cyapawrite; 448 static d_kqfilter_t cyapakqfilter; 449 static d_poll_t cyapapoll; 450 451 static struct cdevsw cyapa_cdevsw = { 452 .d_version = D_VERSION, 453 .d_open = cyapaopen, 454 .d_ioctl = cyapaioctl, 455 .d_read = cyaparead, 456 .d_write = cyapawrite, 457 .d_kqfilter = cyapakqfilter, 458 .d_poll = cyapapoll, 459 }; 460 461 static int 462 cyapa_probe(device_t dev) 463 { 464 struct cyapa_cap cap; 465 int addr; 466 int error; 467 468 addr = iicbus_get_addr(dev); 469 470 /* 471 * 0x67 - cypress trackpad on the acer c720 472 * (other devices might use other ids). 473 */ 474 if (addr != 0xce) 475 return (ENXIO); 476 477 error = init_device(dev, &cap, 1); 478 if (error != 0) 479 return (ENXIO); 480 481 device_set_desc(dev, "Cypress APA I2C Trackpad"); 482 483 return (BUS_PROBE_VENDOR); 484 } 485 486 static int 487 cyapa_attach(device_t dev) 488 { 489 struct cyapa_softc *sc; 490 struct cyapa_cap cap; 491 int unit; 492 int addr; 493 494 sc = device_get_softc(dev); 495 sc->reporting_mode = 1; 496 497 unit = device_get_unit(dev); 498 addr = iicbus_get_addr(dev); 499 500 if (init_device(dev, &cap, 0)) 501 return (ENXIO); 502 503 mtx_init(&sc->mutex, "cyapa", NULL, MTX_DEF); 504 505 sc->dev = dev; 506 507 knlist_init_mtx(&sc->selinfo.si_note, &sc->mutex); 508 509 sc->cap_resx = ((cap.max_abs_xy_high << 4) & 0x0F00) | 510 cap.max_abs_x_low; 511 sc->cap_resy = ((cap.max_abs_xy_high << 8) & 0x0F00) | 512 cap.max_abs_y_low; 513 sc->cap_phyx = ((cap.phy_siz_xy_high << 4) & 0x0F00) | 514 cap.phy_siz_x_low; 515 sc->cap_phyy = ((cap.phy_siz_xy_high << 8) & 0x0F00) | 516 cap.phy_siz_y_low; 517 sc->cap_buttons = cap.buttons; 518 519 device_printf(dev, "%5.5s-%6.6s-%2.2s buttons=%c%c%c res=%dx%d\n", 520 cap.prod_ida, cap.prod_idb, cap.prod_idc, 521 ((cap.buttons & CYAPA_FNGR_LEFT) ? 'L' : '-'), 522 ((cap.buttons & CYAPA_FNGR_MIDDLE) ? 'M' : '-'), 523 ((cap.buttons & CYAPA_FNGR_RIGHT) ? 'R' : '-'), 524 sc->cap_resx, sc->cap_resy); 525 526 sc->hw.buttons = 5; 527 sc->hw.iftype = MOUSE_IF_PS2; 528 sc->hw.type = MOUSE_MOUSE; 529 sc->hw.model = MOUSE_MODEL_INTELLI; 530 sc->hw.hwid = addr; 531 532 sc->mode.protocol = MOUSE_PROTO_PS2; 533 sc->mode.rate = 100; 534 sc->mode.resolution = 4; 535 sc->mode.accelfactor = 1; 536 sc->mode.level = 0; 537 sc->mode.packetsize = MOUSE_PS2_PACKETSIZE; 538 539 /* Setup input event tracking */ 540 cyapa_set_power_mode(sc, CMD_POWER_MODE_IDLE); 541 542 /* Start the polling thread */ 543 kthread_add(cyapa_poll_thread, sc, NULL, NULL, 544 0, 0, "cyapa-poll"); 545 546 sc->devnode = make_dev(&cyapa_cdevsw, unit, 547 UID_ROOT, GID_WHEEL, 0600, "cyapa%d", unit); 548 549 sc->devnode->si_drv1 = sc; 550 551 return (0); 552 } 553 554 static int 555 cyapa_detach(device_t dev) 556 { 557 struct cyapa_softc *sc; 558 559 sc = device_get_softc(dev); 560 561 /* Cleanup poller thread */ 562 cyapa_lock(sc); 563 while (sc->poll_thread_running) { 564 sc->detaching = 1; 565 mtx_sleep(&sc->detaching, &sc->mutex, PCATCH, "cyapadet", hz); 566 } 567 cyapa_unlock(sc); 568 569 destroy_dev(sc->devnode); 570 571 knlist_clear(&sc->selinfo.si_note, 0); 572 seldrain(&sc->selinfo); 573 knlist_destroy(&sc->selinfo.si_note); 574 575 mtx_destroy(&sc->mutex); 576 577 return (0); 578 } 579 580 /* 581 * USER DEVICE I/O FUNCTIONS 582 */ 583 static int 584 cyapaopen(struct cdev *dev, int oflags, int devtype, struct thread *td) 585 { 586 struct cyapa_cdevpriv *priv; 587 int error; 588 589 priv = malloc(sizeof(*priv), M_CYAPA, M_WAITOK | M_ZERO); 590 priv->sc = dev->si_drv1; 591 592 error = devfs_set_cdevpriv(priv, cyapa_cdevpriv_dtor); 593 if (error == 0) { 594 cyapa_lock(priv->sc); 595 priv->sc->count++; 596 cyapa_unlock(priv->sc); 597 } 598 else 599 free(priv, M_CYAPA); 600 601 return (error); 602 } 603 604 static void 605 cyapa_cdevpriv_dtor(void *data) 606 { 607 struct cyapa_cdevpriv *priv; 608 609 priv = data; 610 KASSERT(priv != NULL, ("cyapa cdevpriv should not be NULL!")); 611 612 cyapa_lock(priv->sc); 613 priv->sc->count--; 614 cyapa_unlock(priv->sc); 615 616 free(priv, M_CYAPA); 617 } 618 619 static int 620 cyaparead(struct cdev *dev, struct uio *uio, int ioflag) 621 { 622 struct cyapa_softc *sc; 623 int error; 624 int didread; 625 size_t n; 626 char* ptr; 627 628 sc = dev->si_drv1; 629 /* If buffer is empty, load a new event if it is ready */ 630 cyapa_lock(sc); 631 again: 632 if (fifo_empty(sc, &sc->rfifo) && 633 (sc->data_signal || sc->delta_x || sc->delta_y || 634 sc->track_but != sc->reported_but)) { 635 uint8_t c0; 636 uint16_t but; 637 int delta_x; 638 int delta_y; 639 int delta_z; 640 641 /* Accumulate delta_x, delta_y */ 642 sc->data_signal = 0; 643 delta_x = sc->delta_x; 644 delta_y = sc->delta_y; 645 delta_z = sc->delta_z; 646 if (delta_x > 255) { 647 delta_x = 255; 648 sc->data_signal = 1; 649 } 650 if (delta_x < -256) { 651 delta_x = -256; 652 sc->data_signal = 1; 653 } 654 if (delta_y > 255) { 655 delta_y = 255; 656 sc->data_signal = 1; 657 } 658 if (delta_y < -256) { 659 delta_y = -256; 660 sc->data_signal = 1; 661 } 662 if (delta_z > 255) { 663 delta_z = 255; 664 sc->data_signal = 1; 665 } 666 if (delta_z < -256) { 667 delta_z = -256; 668 sc->data_signal = 1; 669 } 670 but = sc->track_but; 671 672 /* Adjust baseline for next calculation */ 673 sc->delta_x -= delta_x; 674 sc->delta_y -= delta_y; 675 sc->delta_z -= delta_z; 676 sc->reported_but = but; 677 678 /* 679 * Fuzz reduces movement jitter by introducing some 680 * hysteresis. It operates without cumulative error so 681 * if you swish around quickly and return your finger to 682 * where it started, so to will the mouse. 683 */ 684 delta_x = cyapa_fuzz(delta_x, &sc->fuzz_x); 685 delta_y = cyapa_fuzz(delta_y, &sc->fuzz_y); 686 delta_z = cyapa_fuzz(delta_z, &sc->fuzz_z); 687 688 /* 689 * Generate report 690 */ 691 c0 = 0; 692 if (delta_x < 0) 693 c0 |= 0x10; 694 if (delta_y < 0) 695 c0 |= 0x20; 696 c0 |= 0x08; 697 if (but & CYAPA_FNGR_LEFT) 698 c0 |= 0x01; 699 if (but & CYAPA_FNGR_MIDDLE) 700 c0 |= 0x04; 701 if (but & CYAPA_FNGR_RIGHT) 702 c0 |= 0x02; 703 704 fifo_write_char(sc, &sc->rfifo, c0); 705 fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_x); 706 fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_y); 707 switch(sc->zenabled) { 708 case 1: 709 /* Z axis all 8 bits */ 710 fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_z); 711 break; 712 case 2: 713 /* 714 * Z axis low 4 bits + 4th button and 5th button 715 * (high 2 bits must be left 0). Auto-scale 716 * delta_z to fit to avoid a wrong-direction 717 * overflow (don't try to retain the remainder). 718 */ 719 while (delta_z > 7 || delta_z < -8) 720 delta_z >>= 1; 721 c0 = (uint8_t)delta_z & 0x0F; 722 fifo_write_char(sc, &sc->rfifo, c0); 723 break; 724 default: 725 /* basic PS/2 */ 726 break; 727 } 728 cyapa_notify(sc); 729 } 730 731 /* Blocking / Non-blocking */ 732 error = 0; 733 didread = (uio->uio_resid == 0); 734 735 while ((ioflag & IO_NDELAY) == 0 && fifo_empty(sc, &sc->rfifo)) { 736 if (sc->data_signal) 737 goto again; 738 sc->blocked = 1; 739 error = mtx_sleep(&sc->blocked, &sc->mutex, PCATCH, "cyablk", 0); 740 if (error) 741 break; 742 } 743 744 /* Return any buffered data */ 745 while (error == 0 && uio->uio_resid && 746 (n = fifo_ready(sc, &sc->rfifo)) > 0) { 747 if (n > uio->uio_resid) 748 n = uio->uio_resid; 749 ptr = fifo_read(sc, &sc->rfifo, 0); 750 cyapa_unlock(sc); 751 error = uiomove(ptr, n, uio); 752 cyapa_lock(sc); 753 if (error) 754 break; 755 fifo_read(sc, &sc->rfifo, n); 756 didread = 1; 757 } 758 cyapa_unlock(sc); 759 760 if (error == 0 && didread == 0) { 761 error = EWOULDBLOCK; 762 } 763 return (didread ? 0 : error); 764 } 765 766 static int 767 cyapawrite(struct cdev *dev, struct uio *uio, int ioflag) 768 { 769 struct cyapa_softc *sc; 770 int error; 771 int cmd_completed; 772 size_t n; 773 uint8_t c0; 774 char* ptr; 775 776 sc = dev->si_drv1; 777 again: 778 /* 779 * Copy data from userland. This will also cross-over the end 780 * of the fifo and keep filling. 781 */ 782 cyapa_lock(sc); 783 while ((n = fifo_space(sc, &sc->wfifo)) > 0 && uio->uio_resid) { 784 if (n > uio->uio_resid) 785 n = uio->uio_resid; 786 ptr = fifo_write(sc, &sc->wfifo, 0); 787 cyapa_unlock(sc); 788 error = uiomove(ptr, n, uio); 789 cyapa_lock(sc); 790 if (error) 791 break; 792 fifo_write(sc, &sc->wfifo, n); 793 } 794 795 /* Handle commands */ 796 cmd_completed = (fifo_ready(sc, &sc->wfifo) != 0); 797 while (fifo_ready(sc, &sc->wfifo) && cmd_completed && error == 0) { 798 if (sc->ps2_cmd == 0) 799 sc->ps2_cmd = fifo_read_char(sc, &sc->wfifo); 800 switch(sc->ps2_cmd) { 801 case 0xE6: 802 /* SET SCALING 1:1 */ 803 sc->scaling_mode = 0; 804 fifo_write_char(sc, &sc->rfifo, 0xFA); 805 break; 806 case 0xE7: 807 /* SET SCALING 2:1 */ 808 sc->scaling_mode = 1; 809 fifo_write_char(sc, &sc->rfifo, 0xFA); 810 break; 811 case 0xE8: 812 /* SET RESOLUTION +1 byte */ 813 if (sc->ps2_acked == 0) { 814 sc->ps2_acked = 1; 815 fifo_write_char(sc, &sc->rfifo, 0xFA); 816 } 817 if (fifo_ready(sc, &sc->wfifo) == 0) { 818 cmd_completed = 0; 819 break; 820 } 821 sc->mode.resolution = fifo_read_char(sc, &sc->wfifo); 822 fifo_write_char(sc, &sc->rfifo, 0xFA); 823 break; 824 case 0xE9: 825 /* 826 * STATUS REQUEST 827 * 828 * byte1: 829 * bit 7 0 830 * bit 6 Mode (1=remote mode, 0=stream mode) 831 * bit 5 Enable (data reporting enabled) 832 * bit 4 Scaling (0=1:1 1=2:1) 833 * bit 3 0 834 * bit 2 LEFT BUTTON (1 if pressed) 835 * bit 1 MIDDLE BUTTON (1 if pressed) 836 * bit 0 RIGHT BUTTON (1 if pressed) 837 * 838 * byte2: resolution counts/mm 839 * byte3: sample rate 840 */ 841 c0 = 0; 842 if (sc->remote_mode) 843 c0 |= 0x40; 844 if (sc->reporting_mode) 845 c0 |= 0x20; 846 if (sc->scaling_mode) 847 c0 |= 0x10; 848 if (sc->track_but & CYAPA_FNGR_LEFT) 849 c0 |= 0x04; 850 if (sc->track_but & CYAPA_FNGR_MIDDLE) 851 c0 |= 0x02; 852 if (sc->track_but & CYAPA_FNGR_RIGHT) 853 c0 |= 0x01; 854 fifo_write_char(sc, &sc->rfifo, 0xFA); 855 fifo_write_char(sc, &sc->rfifo, c0); 856 fifo_write_char(sc, &sc->rfifo, 0x00); 857 fifo_write_char(sc, &sc->rfifo, 100); 858 break; 859 case 0xEA: 860 /* Set stream mode and reset movement counters */ 861 sc->remote_mode = 0; 862 fifo_write_char(sc, &sc->rfifo, 0xFA); 863 sc->delta_x = 0; 864 sc->delta_y = 0; 865 sc->delta_z = 0; 866 break; 867 case 0xEB: 868 /* 869 * Read Data (if in remote mode). If not in remote 870 * mode force an event. 871 */ 872 fifo_write_char(sc, &sc->rfifo, 0xFA); 873 sc->data_signal = 1; 874 break; 875 case 0xEC: 876 /* Reset Wrap Mode (ignored) */ 877 fifo_write_char(sc, &sc->rfifo, 0xFA); 878 break; 879 case 0xEE: 880 /* Set Wrap Mode (ignored) */ 881 fifo_write_char(sc, &sc->rfifo, 0xFA); 882 break; 883 case 0xF0: 884 /* Set Remote Mode */ 885 sc->remote_mode = 1; 886 fifo_write_char(sc, &sc->rfifo, 0xFA); 887 sc->delta_x = 0; 888 sc->delta_y = 0; 889 sc->delta_z = 0; 890 break; 891 case 0xF2: 892 /* 893 * Get Device ID 894 * 895 * If we send 0x00 - normal PS/2 mouse, no Z-axis 896 * 897 * If we send 0x03 - Intellimouse, data packet has 898 * an additional Z movement byte (8 bits signed). 899 * (also reset movement counters) 900 * 901 * If we send 0x04 - Now includes z-axis and the 902 * 4th and 5th mouse buttons. 903 */ 904 fifo_write_char(sc, &sc->rfifo, 0xFA); 905 switch(sc->zenabled) { 906 case 1: 907 fifo_write_char(sc, &sc->rfifo, 0x03); 908 break; 909 case 2: 910 fifo_write_char(sc, &sc->rfifo, 0x04); 911 break; 912 default: 913 fifo_write_char(sc, &sc->rfifo, 0x00); 914 break; 915 } 916 sc->delta_x = 0; 917 sc->delta_y = 0; 918 sc->delta_z = 0; 919 break; 920 case 0xF3: 921 /* 922 * Set Sample Rate 923 * 924 * byte1: the sample rate 925 */ 926 if (sc->ps2_acked == 0) { 927 sc->ps2_acked = 1; 928 fifo_write_char(sc, &sc->rfifo, 0xFA); 929 } 930 if (fifo_ready(sc, &sc->wfifo) == 0) { 931 cmd_completed = 0; 932 break; 933 } 934 sc->mode.rate = fifo_read_char(sc, &sc->wfifo); 935 fifo_write_char(sc, &sc->rfifo, 0xFA); 936 937 /* 938 * zenabling sequence: 200,100,80 (device id 0x03) 939 * 200,200,80 (device id 0x04) 940 * 941 * We support id 0x03 (no 4th or 5th button). 942 * We support id 0x04 (w/ 4th and 5th button). 943 */ 944 if (sc->zenabled == 0 && sc->mode.rate == 200) 945 sc->zenabled = -1; 946 else if (sc->zenabled == -1 && sc->mode.rate == 100) 947 sc->zenabled = -2; 948 else if (sc->zenabled == -1 && sc->mode.rate == 200) 949 sc->zenabled = -3; 950 else if (sc->zenabled == -2 && sc->mode.rate == 80) 951 sc->zenabled = 1; /* z-axis mode */ 952 else if (sc->zenabled == -3 && sc->mode.rate == 80) 953 sc->zenabled = 2; /* z-axis+but4/5 */ 954 if (sc->mode.level) 955 sc->zenabled = 1; 956 break; 957 case 0xF4: 958 /* Enable data reporting. Only effects stream mode. */ 959 fifo_write_char(sc, &sc->rfifo, 0xFA); 960 sc->reporting_mode = 1; 961 break; 962 case 0xF5: 963 /* 964 * Disable data reporting. Only effects stream mode 965 * and is ignored right now. 966 */ 967 fifo_write_char(sc, &sc->rfifo, 0xFA); 968 sc->reporting_mode = 1; 969 break; 970 case 0xF6: 971 /* 972 * SET DEFAULTS 973 * 974 * (reset sampling rate, resolution, scaling and 975 * enter stream mode) 976 */ 977 fifo_write_char(sc, &sc->rfifo, 0xFA); 978 sc->mode.rate = 100; 979 sc->mode.resolution = 4; 980 sc->scaling_mode = 0; 981 sc->reporting_mode = 1; 982 sc->remote_mode = 0; 983 sc->delta_x = 0; 984 sc->delta_y = 0; 985 sc->delta_z = 0; 986 /* signal */ 987 break; 988 case 0xFE: 989 /* 990 * RESEND 991 * 992 * Force a resend by guaranteeing that reported_but 993 * differs from track_but. 994 */ 995 fifo_write_char(sc, &sc->rfifo, 0xFA); 996 sc->data_signal = 1; 997 break; 998 case 0xFF: 999 /* 1000 * RESET 1001 */ 1002 fifo_reset(sc, &sc->rfifo); /* should we do this? */ 1003 fifo_reset(sc, &sc->wfifo); /* should we do this? */ 1004 fifo_write_char(sc, &sc->rfifo, 0xFA); 1005 sc->delta_x = 0; 1006 sc->delta_y = 0; 1007 sc->delta_z = 0; 1008 sc->zenabled = 0; 1009 sc->mode.level = 0; 1010 break; 1011 default: 1012 printf("unknown command %02x\n", sc->ps2_cmd); 1013 break; 1014 } 1015 if (cmd_completed) { 1016 sc->ps2_cmd = 0; 1017 sc->ps2_acked = 0; 1018 } 1019 cyapa_notify(sc); 1020 } 1021 cyapa_unlock(sc); 1022 if (error == 0 && (cmd_completed || uio->uio_resid)) 1023 goto again; 1024 return (error); 1025 } 1026 1027 static void cyapafiltdetach(struct knote *); 1028 static int cyapafilt(struct knote *, long); 1029 1030 static struct filterops cyapa_filtops = { 1031 .f_isfd = 1, 1032 .f_detach = cyapafiltdetach, 1033 .f_event = cyapafilt 1034 }; 1035 1036 static int 1037 cyapakqfilter(struct cdev *dev, struct knote *kn) 1038 { 1039 struct cyapa_softc *sc; 1040 struct knlist *knlist; 1041 1042 sc = dev->si_drv1; 1043 1044 switch(kn->kn_filter) { 1045 case EVFILT_READ: 1046 kn->kn_fop = &cyapa_filtops; 1047 kn->kn_hook = (void *)sc; 1048 break; 1049 default: 1050 return (EOPNOTSUPP); 1051 } 1052 knlist = &sc->selinfo.si_note; 1053 knlist_add(knlist, kn, 0); 1054 1055 return (0); 1056 } 1057 1058 static int 1059 cyapapoll(struct cdev *dev, int events, struct thread *td) 1060 { 1061 struct cyapa_softc *sc; 1062 int revents; 1063 1064 sc = dev->si_drv1; 1065 revents = 0; 1066 1067 cyapa_lock(sc); 1068 if (events & (POLLIN | POLLRDNORM)) { 1069 if (sc->data_signal || !fifo_empty(sc, &sc->rfifo)) 1070 revents = events & (POLLIN | POLLRDNORM); 1071 else { 1072 sc->isselect = 1; 1073 selrecord(td, &sc->selinfo); 1074 } 1075 } 1076 cyapa_unlock(sc); 1077 1078 return (revents); 1079 } 1080 1081 static void 1082 cyapafiltdetach(struct knote *kn) 1083 { 1084 struct cyapa_softc *sc; 1085 struct knlist *knlist; 1086 1087 sc = (struct cyapa_softc *)kn->kn_hook; 1088 1089 knlist = &sc->selinfo.si_note; 1090 knlist_remove(knlist, kn, 0); 1091 } 1092 1093 static int 1094 cyapafilt(struct knote *kn, long hint) 1095 { 1096 struct cyapa_softc *sc; 1097 int ready; 1098 1099 sc = (struct cyapa_softc *)kn->kn_hook; 1100 1101 cyapa_lock(sc); 1102 ready = fifo_ready(sc, &sc->rfifo) || sc->data_signal; 1103 cyapa_unlock(sc); 1104 1105 return (ready); 1106 } 1107 1108 static int 1109 cyapaioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 1110 { 1111 struct cyapa_softc *sc; 1112 int error; 1113 1114 sc = dev->si_drv1; 1115 error = 0; 1116 1117 cyapa_lock(sc); 1118 switch (cmd) { 1119 case MOUSE_GETHWINFO: 1120 *(mousehw_t *)data = sc->hw; 1121 if (sc->mode.level == 0) 1122 ((mousehw_t *)data)->model = MOUSE_MODEL_GENERIC; 1123 break; 1124 1125 case MOUSE_GETMODE: 1126 *(mousemode_t *)data = sc->mode; 1127 ((mousemode_t *)data)->resolution = 1128 MOUSE_RES_LOW - sc->mode.resolution; 1129 switch (sc->mode.level) { 1130 case 0: 1131 ((mousemode_t *)data)->protocol = MOUSE_PROTO_PS2; 1132 ((mousemode_t *)data)->packetsize = 1133 MOUSE_PS2_PACKETSIZE; 1134 break; 1135 case 2: 1136 ((mousemode_t *)data)->protocol = MOUSE_PROTO_PS2; 1137 ((mousemode_t *)data)->packetsize = 1138 MOUSE_PS2_PACKETSIZE + 1; 1139 break; 1140 } 1141 break; 1142 1143 case MOUSE_GETLEVEL: 1144 *(int *)data = sc->mode.level; 1145 break; 1146 1147 case MOUSE_SETLEVEL: 1148 if ((*(int *)data < 0) && 1149 (*(int *)data > 2)) { 1150 error = EINVAL; 1151 break; 1152 } 1153 sc->mode.level = *(int *)data ? 2 : 0; 1154 sc->zenabled = sc->mode.level ? 1 : 0; 1155 break; 1156 1157 default: 1158 error = ENOTTY; 1159 break; 1160 } 1161 cyapa_unlock(sc); 1162 1163 return (error); 1164 } 1165 1166 /* 1167 * MAJOR SUPPORT FUNCTIONS 1168 */ 1169 static void 1170 cyapa_poll_thread(void *arg) 1171 { 1172 struct cyapa_softc *sc; 1173 struct cyapa_regs regs; 1174 device_t bus; /* iicbus */ 1175 int error; 1176 int freq; 1177 int isidle; 1178 int pstate; 1179 int npstate; 1180 int last_reset; 1181 1182 sc = arg; 1183 freq = cyapa_norm_freq; 1184 isidle = 0; 1185 pstate = CMD_POWER_MODE_IDLE; 1186 last_reset = ticks; 1187 1188 bus = device_get_parent(sc->dev); 1189 1190 cyapa_lock(sc); 1191 sc->poll_thread_running = 1; 1192 1193 while (!sc->detaching) { 1194 cyapa_unlock(sc); 1195 error = iicbus_request_bus(bus, sc->dev, IIC_WAIT); 1196 if (error == 0) { 1197 error = cyapa_read_bytes(sc->dev, CMD_DEV_STATUS, 1198 (void *)®s, sizeof(regs)); 1199 if (error == 0) { 1200 isidle = cyapa_raw_input(sc, ®s, freq); 1201 } 1202 1203 /* 1204 * For some reason the device can crap-out. If it 1205 * drops back into bootstrap mode try to reinitialize 1206 * it. 1207 */ 1208 if (cyapa_reset || 1209 ((regs.stat & CYAPA_STAT_RUNNING) == 0 && 1210 (unsigned)(ticks - last_reset) > TIME_TO_RESET)) { 1211 cyapa_reset = 0; 1212 last_reset = ticks; 1213 init_device(sc->dev, NULL, 2); 1214 } 1215 iicbus_release_bus(bus, sc->dev); 1216 } 1217 pause("cyapw", hz / freq); 1218 ++sc->poll_ticks; 1219 1220 if (sc->count == 0) { 1221 freq = cyapa_idle_freq; 1222 npstate = CMD_POWER_MODE_IDLE; 1223 } else if (isidle) { 1224 freq = cyapa_slow_freq; 1225 npstate = CMD_POWER_MODE_IDLE; 1226 } else { 1227 freq = cyapa_norm_freq; 1228 npstate = CMD_POWER_MODE_FULL; 1229 } 1230 if (pstate != npstate) { 1231 pstate = npstate; 1232 cyapa_set_power_mode(sc, pstate); 1233 if (cyapa_debug) { 1234 switch(pstate) { 1235 case CMD_POWER_MODE_OFF: 1236 printf("cyapa: power off\n"); 1237 break; 1238 case CMD_POWER_MODE_IDLE: 1239 printf("cyapa: power idle\n"); 1240 break; 1241 case CMD_POWER_MODE_FULL: 1242 printf("cyapa: power full\n"); 1243 break; 1244 } 1245 } 1246 } 1247 1248 cyapa_lock(sc); 1249 } 1250 sc->poll_thread_running = 0; 1251 cyapa_unlock(sc); 1252 kthread_exit(); 1253 } 1254 1255 static int 1256 cyapa_raw_input(struct cyapa_softc *sc, struct cyapa_regs *regs, int freq) 1257 { 1258 int nfingers; 1259 int afingers; /* actual fingers after culling */ 1260 int i; 1261 int j; 1262 int k; 1263 int isidle; 1264 int thumbarea_begin; 1265 int seen_thumb; 1266 int x; 1267 int y; 1268 int z; 1269 int newfinger; 1270 int lessfingers; 1271 int click_x; 1272 int click_y; 1273 uint16_t but; /* high bits used for simulated but4/but5 */ 1274 1275 thumbarea_begin = sc->cap_resy - 1276 ((sc->cap_resy * cyapa_thumbarea_percent) / 100); 1277 click_x = click_y = 0; 1278 1279 /* 1280 * If the device is not running the rest of the status 1281 * means something else, set fingers to 0. 1282 */ 1283 if ((regs->stat & CYAPA_STAT_RUNNING) == 0) { 1284 regs->fngr = 0; 1285 } 1286 1287 /* Process fingers/movement */ 1288 nfingers = CYAPA_FNGR_NUMFINGERS(regs->fngr); 1289 afingers = nfingers; 1290 1291 if (cyapa_debug) { 1292 printf("stat %02x buttons %c%c%c nfngrs=%d ", 1293 regs->stat, 1294 ((regs->fngr & CYAPA_FNGR_LEFT) ? 'L' : '-'), 1295 ((regs->fngr & CYAPA_FNGR_MIDDLE) ? 'M' : '-'), 1296 ((regs->fngr & CYAPA_FNGR_RIGHT) ? 'R' : '-'), 1297 nfingers); 1298 } 1299 1300 seen_thumb = 0; 1301 for (i = 0; i < afingers; ) { 1302 if (cyapa_debug) { 1303 printf(" [x=%04d y=%04d p=%d i=%d]", 1304 CYAPA_TOUCH_X(regs, i), 1305 CYAPA_TOUCH_Y(regs, i), 1306 CYAPA_TOUCH_P(regs, i), 1307 regs->touch[i].id); 1308 } 1309 if ((CYAPA_TOUCH_Y(regs, i) > thumbarea_begin && seen_thumb) || 1310 CYAPA_TOUCH_P(regs, i) < cyapa_minpressure) { 1311 --afingers; 1312 if (i < afingers) { 1313 regs->touch[i] = regs->touch[i+1]; 1314 continue; 1315 } 1316 } else { 1317 if (CYAPA_TOUCH_Y(regs, i) > thumbarea_begin) 1318 seen_thumb = 1; 1319 } 1320 ++i; 1321 } 1322 nfingers = afingers; 1323 1324 /* Tracking for local solutions */ 1325 cyapa_lock(sc); 1326 1327 /* 1328 * Track timing for finger-downs. Used to detect false-3-finger 1329 * button-down. 1330 */ 1331 switch(afingers) { 1332 case 0: 1333 break; 1334 case 1: 1335 if (sc->track_nfingers == 0) 1336 sc->finger1_ticks = sc->poll_ticks; 1337 break; 1338 case 2: 1339 if (sc->track_nfingers <= 0) 1340 sc->finger1_ticks = sc->poll_ticks; 1341 if (sc->track_nfingers <= 1) 1342 sc->finger2_ticks = sc->poll_ticks; 1343 break; 1344 case 3: 1345 default: 1346 if (sc->track_nfingers <= 0) 1347 sc->finger1_ticks = sc->poll_ticks; 1348 if (sc->track_nfingers <= 1) 1349 sc->finger2_ticks = sc->poll_ticks; 1350 if (sc->track_nfingers <= 2) 1351 sc->finger3_ticks = sc->poll_ticks; 1352 break; 1353 } 1354 newfinger = sc->track_nfingers < afingers; 1355 lessfingers = sc->track_nfingers > afingers; 1356 sc->track_nfingers = afingers; 1357 1358 /* 1359 * Lookup and track finger indexes in the touch[] array. 1360 */ 1361 if (afingers == 0) { 1362 click_x = sc->track_x; 1363 click_y = sc->track_y; 1364 sc->track_x = -1; 1365 sc->track_y = -1; 1366 sc->track_z = -1; 1367 sc->fuzz_x = 0; 1368 sc->fuzz_y = 0; 1369 sc->fuzz_z = 0; 1370 sc->touch_x = -1; 1371 sc->touch_y = -1; 1372 sc->touch_z = -1; 1373 sc->track_id = -1; 1374 sc->track_but = 0; 1375 i = 0; 1376 j = 0; 1377 k = 0; 1378 } else { 1379 /* 1380 * The id assigned on touch can move around in the array, 1381 * find it. If that finger is lifted up, assign some other 1382 * finger for mouse tracking and reset track_x and track_y 1383 * to avoid a mouse jump. 1384 * 1385 * If >= 2 fingers are down be sure not to assign i and 1386 * j to the same index. 1387 */ 1388 for (i = 0; i < nfingers; ++i) { 1389 if (sc->track_id == regs->touch[i].id) 1390 break; 1391 } 1392 if (i == nfingers) { 1393 i = 0; 1394 sc->track_x = -1; 1395 sc->track_y = -1; 1396 sc->track_z = -1; 1397 while (CYAPA_TOUCH_Y(regs, i) >= thumbarea_begin && 1398 i < nfingers) ++i; 1399 if (i == nfingers) { 1400 i = 0; 1401 } 1402 sc->track_id = regs->touch[i].id; 1403 } 1404 else if ((sc->track_but || 1405 CYAPA_TOUCH_Y(regs, i) >= thumbarea_begin) && 1406 newfinger && afingers == 2) { 1407 j = regs->touch[0].id == sc->track_id ? 1 : 0; 1408 if (CYAPA_TOUCH_Y(regs, j) < thumbarea_begin) { 1409 i = j; 1410 sc->track_x = -1; 1411 sc->track_y = -1; 1412 sc->track_z = -1; 1413 sc->track_id = regs->touch[i].id; 1414 } 1415 } 1416 } 1417 1418 /* Two finger scrolling - reset after timeout */ 1419 if (sc->track_z != -1 && afingers != 2 && 1420 (sc->poll_ticks - sc->track_z_ticks) > cyapa_scroll_stick_ticks) { 1421 sc->track_z = -1; 1422 sc->track_z_ticks = 0; 1423 } 1424 1425 /* Initiate two finger scrolling */ 1426 if (!(regs->fngr & CYAPA_FNGR_LEFT) && 1427 ((afingers && sc->track_z != -1) || 1428 (afingers == 2 && CYAPA_TOUCH_Y(regs, 0) < thumbarea_begin && 1429 CYAPA_TOUCH_Y(regs, 1) < thumbarea_begin))) { 1430 if (afingers == 2 && (sc->poll_ticks - sc->finger2_ticks) 1431 > cyapa_scroll_wait_ticks) { 1432 z = (CYAPA_TOUCH_Y(regs, 0) + 1433 CYAPA_TOUCH_Y(regs, 1)) >> 1; 1434 sc->delta_z += z / ZSCALE - sc->track_z; 1435 if (sc->track_z == -1) { 1436 sc->delta_z = 0; 1437 } 1438 if (sc->touch_z == -1) 1439 sc->touch_z = z; /* not used atm */ 1440 sc->track_z = z / ZSCALE; 1441 sc->track_z_ticks = sc->poll_ticks; 1442 } 1443 } else if (afingers) { 1444 /* Normal pad position reporting */ 1445 x = CYAPA_TOUCH_X(regs, i); 1446 y = CYAPA_TOUCH_Y(regs, i); 1447 click_x = x; 1448 click_y = y; 1449 if (sc->track_x != -1 && sc->track_y < thumbarea_begin && 1450 (afingers > 1 || (sc->poll_ticks - sc->finger1_ticks) 1451 >= cyapa_move_min_ticks || freq < cyapa_norm_freq)) { 1452 sc->delta_x += x - sc->track_x; 1453 sc->delta_y -= y - sc->track_y; 1454 if (sc->delta_x > sc->cap_resx) 1455 sc->delta_x = sc->cap_resx; 1456 if (sc->delta_x < -sc->cap_resx) 1457 sc->delta_x = -sc->cap_resx; 1458 if (sc->delta_y > sc->cap_resy) 1459 sc->delta_y = sc->cap_resy; 1460 if (sc->delta_y < -sc->cap_resy) 1461 sc->delta_y = -sc->cap_resy; 1462 1463 if (abs(sc->delta_y) > sc->cap_resy / 2 || 1464 abs(sc->delta_x) > sc->cap_resx / 2) { 1465 if (cyapa_debug) 1466 printf("Detected jump by %i %i\n", 1467 sc->delta_x, sc->delta_y); 1468 sc->delta_x = sc->delta_y = 0; 1469 } 1470 } 1471 if (sc->touch_x == -1) { 1472 sc->touch_x = x; 1473 sc->touch_y = y; 1474 } 1475 sc->track_x = x; 1476 sc->track_y = y; 1477 } 1478 1479 /* Select finger (L = 2/3x, M = 1/3u, R = 1/3d) */ 1480 int is_tapclick = (cyapa_enable_tapclick && lessfingers && 1481 afingers == 0 && sc->poll_ticks - sc->finger1_ticks 1482 >= cyapa_tapclick_min_ticks && 1483 sc->poll_ticks - sc->finger1_ticks < cyapa_tapclick_max_ticks); 1484 1485 if (regs->fngr & CYAPA_FNGR_LEFT || is_tapclick) { 1486 if (sc->track_but) { 1487 but = sc->track_but; 1488 } else if (afingers == 1) { 1489 if (click_x < sc->cap_resx * 2 / 3) 1490 but = CYAPA_FNGR_LEFT; 1491 else if (click_y < sc->cap_resy / 2) 1492 but = CYAPA_FNGR_MIDDLE; 1493 else 1494 but = CYAPA_FNGR_RIGHT; 1495 } else if (is_tapclick) { 1496 if (click_x < sc->cap_resx * 2 / 3 || 1497 cyapa_enable_tapclick < 2) 1498 but = CYAPA_FNGR_LEFT; 1499 else if (click_y < sc->cap_resy / 2 && 1500 cyapa_enable_tapclick > 2) 1501 but = CYAPA_FNGR_MIDDLE; 1502 else 1503 but = CYAPA_FNGR_RIGHT; 1504 } else { 1505 but = CYAPA_FNGR_LEFT; 1506 } 1507 } else { 1508 but = 0; 1509 } 1510 1511 /* 1512 * Detect state change from last reported state and 1513 * determine if we have gone idle. 1514 */ 1515 sc->track_but = but; 1516 if (sc->delta_x || sc->delta_y || sc->delta_z || 1517 sc->track_but != sc->reported_but) { 1518 sc->active_tick = ticks; 1519 if (sc->remote_mode == 0 && sc->reporting_mode) 1520 sc->data_signal = 1; 1521 isidle = 0; 1522 } else if ((unsigned)(ticks - sc->active_tick) >= TIME_TO_IDLE) { 1523 sc->active_tick = ticks - TIME_TO_IDLE; /* prevent overflow */ 1524 isidle = 1; 1525 } else { 1526 isidle = 0; 1527 } 1528 cyapa_notify(sc); 1529 cyapa_unlock(sc); 1530 1531 if (cyapa_debug) 1532 printf("%i >> %i << %i\n", isidle, sc->track_id, sc->delta_y); 1533 return (isidle); 1534 } 1535 1536 static void 1537 cyapa_set_power_mode(struct cyapa_softc *sc, int mode) 1538 { 1539 uint8_t data; 1540 device_t bus; 1541 int error; 1542 1543 bus = device_get_parent(sc->dev); 1544 error = iicbus_request_bus(bus, sc->dev, IIC_WAIT); 1545 if (error == 0) { 1546 error = cyapa_read_bytes(sc->dev, CMD_POWER_MODE, 1547 &data, 1); 1548 data = (data & ~0xFC) | mode; 1549 if (error == 0) { 1550 error = cyapa_write_bytes(sc->dev, CMD_POWER_MODE, 1551 &data, 1); 1552 } 1553 iicbus_release_bus(bus, sc->dev); 1554 } 1555 } 1556 1557 /* 1558 * FIFO FUNCTIONS 1559 */ 1560 1561 /* 1562 * Returns non-zero if the fifo is empty 1563 */ 1564 static int 1565 fifo_empty(struct cyapa_softc *sc, struct cyapa_fifo *fifo) 1566 { 1567 1568 CYAPA_LOCK_ASSERT(sc); 1569 1570 return (fifo->rindex == fifo->windex); 1571 } 1572 1573 /* 1574 * Returns the number of characters available for reading from 1575 * the fifo without wrapping the fifo buffer. 1576 */ 1577 static size_t 1578 fifo_ready(struct cyapa_softc *sc, struct cyapa_fifo *fifo) 1579 { 1580 size_t n; 1581 1582 CYAPA_LOCK_ASSERT(sc); 1583 1584 n = CYAPA_BUFSIZE - (fifo->rindex & CYAPA_BUFMASK); 1585 if (n > (size_t)(fifo->windex - fifo->rindex)) 1586 n = (size_t)(fifo->windex - fifo->rindex); 1587 return (n); 1588 } 1589 1590 /* 1591 * Returns a read pointer into the fifo and then bumps 1592 * rindex. The FIFO must have at least 'n' characters in 1593 * it. The value (n) can cause the index to wrap but users 1594 * of the buffer should never supply a value for (n) that wraps 1595 * the buffer. 1596 */ 1597 static char * 1598 fifo_read(struct cyapa_softc *sc, struct cyapa_fifo *fifo, size_t n) 1599 { 1600 char *ptr; 1601 1602 CYAPA_LOCK_ASSERT(sc); 1603 if (n > (CYAPA_BUFSIZE - (fifo->rindex & CYAPA_BUFMASK))) { 1604 printf("fifo_read: overflow\n"); 1605 return (fifo->buf); 1606 } 1607 ptr = fifo->buf + (fifo->rindex & CYAPA_BUFMASK); 1608 fifo->rindex += n; 1609 1610 return (ptr); 1611 } 1612 1613 static uint8_t 1614 fifo_read_char(struct cyapa_softc *sc, struct cyapa_fifo *fifo) 1615 { 1616 uint8_t c; 1617 1618 CYAPA_LOCK_ASSERT(sc); 1619 1620 if (fifo->rindex == fifo->windex) { 1621 printf("fifo_read_char: overflow\n"); 1622 c = 0; 1623 } else { 1624 c = fifo->buf[fifo->rindex & CYAPA_BUFMASK]; 1625 ++fifo->rindex; 1626 } 1627 return (c); 1628 } 1629 1630 1631 /* 1632 * Write a character to the FIFO. The character will be discarded 1633 * if the FIFO is full. 1634 */ 1635 static void 1636 fifo_write_char(struct cyapa_softc *sc, struct cyapa_fifo *fifo, uint8_t c) 1637 { 1638 1639 CYAPA_LOCK_ASSERT(sc); 1640 1641 if (fifo->windex - fifo->rindex < CYAPA_BUFSIZE) { 1642 fifo->buf[fifo->windex & CYAPA_BUFMASK] = c; 1643 ++fifo->windex; 1644 } 1645 } 1646 1647 /* 1648 * Return the amount of space available for writing without wrapping 1649 * the fifo. 1650 */ 1651 static size_t 1652 fifo_space(struct cyapa_softc *sc, struct cyapa_fifo *fifo) 1653 { 1654 size_t n; 1655 1656 CYAPA_LOCK_ASSERT(sc); 1657 1658 n = CYAPA_BUFSIZE - (fifo->windex & CYAPA_BUFMASK); 1659 if (n > (size_t)(CYAPA_BUFSIZE - (fifo->windex - fifo->rindex))) 1660 n = (size_t)(CYAPA_BUFSIZE - (fifo->windex - fifo->rindex)); 1661 return (n); 1662 } 1663 1664 static char * 1665 fifo_write(struct cyapa_softc *sc, struct cyapa_fifo *fifo, size_t n) 1666 { 1667 char *ptr; 1668 1669 CYAPA_LOCK_ASSERT(sc); 1670 1671 ptr = fifo->buf + (fifo->windex & CYAPA_BUFMASK); 1672 fifo->windex += n; 1673 1674 return (ptr); 1675 } 1676 1677 static void 1678 fifo_reset(struct cyapa_softc *sc, struct cyapa_fifo *fifo) 1679 { 1680 1681 CYAPA_LOCK_ASSERT(sc); 1682 1683 fifo->rindex = 0; 1684 fifo->windex = 0; 1685 } 1686 1687 /* 1688 * Fuzz handling 1689 */ 1690 static int 1691 cyapa_fuzz(int delta, int *fuzzp) 1692 { 1693 int fuzz; 1694 1695 fuzz = *fuzzp; 1696 if (fuzz >= 0 && delta < 0) { 1697 ++delta; 1698 --fuzz; 1699 } else if (fuzz <= 0 && delta > 0) { 1700 --delta; 1701 ++fuzz; 1702 } 1703 *fuzzp = fuzz; 1704 1705 return (delta); 1706 } 1707 1708 DRIVER_MODULE(cyapa, iicbus, cyapa_driver, cyapa_devclass, NULL, NULL); 1709 MODULE_DEPEND(cyapa, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 1710 MODULE_VERSION(cyapa, 1); 1711