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