The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/cyapa/cyapa.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 4f5320bba20a05318516575459fb1514


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.