cyapa - Introduce better three-finger button emulation
[dragonfly.git] / sys / dev / smbus / 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>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * CYAPA - Cypress APA trackpad with I2C Interface driver
36  *
37  * Written from scratch but referenced the linux cyapa.c driver to
38  * figure out the bootstrapping and commands.
39  *
40  * Unable to locate any datasheet for the device.
41  *
42  * Attaches under smbus but uses an I2C protocol (no count field).
43  * This driver should override the "smb" device for the specific unit
44  * we validate against (smb0-67).
45  *
46  * xorg.conf:
47  *
48  * Section "InputDevice"
49  *         Identifier  "Mouse0"
50  *         Driver      "mouse"
51  *         Option      "Protocol" "imps/2"              (slider)
52  * #       Option      "Protocol" "ps/2"                (basic mouse)
53  * #       Option      "Protocol" "explorerps/2"        (not working well yet)
54  *                                                      (for b4/b5)
55  *         Option      "Device" "/dev/cyapa0-67"
56  * EndSection
57  *
58  * NOTE: In explorerps/2 mode the slider has only 4 bits of delta resolution
59  *       and may not work as smoothly.  Buttons are recognized as button
60  *       8 and button 9.
61  *
62  *                                  FEATURES
63  *
64  * Jitter supression    - Implements 2-pixel hysteresis with memory.
65  *
66  * False-finger supression- Two-fingers-down does not emulate anything,
67  *                          on purpose.
68  *
69  * Slider jesture       - Tap right hand side and slide up or down.
70  *
71  *                        (Three finger jestures)
72  * left button jesture  - Two fingers down on the left, tap/hold right
73  * middle button jesture- Two fingers down left & right, tap/hold middle
74  * right button jesture - Two fingers down on the right, tap/hold left
75  *
76  * track-pad button     - Tap/push physical button, left, middle, or right
77  *                        side of the trackpad will issue a LEFT, MIDDLE, or
78  *                        RIGHT button event.
79  *
80  * track-pad button     - Any tap/slide of more than 32 pixels and pushing
81  *                        harder to articulate the trackpad physical button
82  *                        always issues a LEFT button event.
83  *
84  * first-finger tracking- The X/Y coordinates always track the first finger
85  *                        down.  If you have multiple fingers down and lift
86  *                        up the designated first finger, a new designated
87  *                        first finger will be selected without causing the
88  *                        mouse to jump (delta's are reset).
89  */
90 #include <sys/kernel.h>
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/device.h>
94 #include <sys/module.h>
95 #include <sys/bus.h>
96 #include <sys/conf.h>
97 #include <sys/uio.h>
98 #include <sys/fcntl.h>
99 /*#include <sys/input.h>*/
100 #include <sys/vnode.h>
101 #include <sys/sysctl.h>
102 #include <sys/event.h>
103 #include <sys/devfs.h>
104
105 #include <bus/smbus/smbconf.h>
106 #include <bus/smbus/smbus.h>
107 #include "cyapa.h"
108
109 #include "smbus_if.h"
110 #include "bus_if.h"
111 #include "device_if.h"
112
113 #define CYAPA_BUFSIZE   128                     /* power of 2 */
114 #define CYAPA_BUFMASK   (CYAPA_BUFSIZE - 1)
115
116 #define ZSCALE          10
117
118 struct cyapa_fifo {
119         int     rindex;
120         int     windex;
121         char    buf[CYAPA_BUFSIZE];
122 };
123
124 struct cyapa_softc {
125         device_t dev;
126         int     count;                  /* >0 if device opened */
127         int     unit;
128         int     addr;
129         cdev_t  devnode;
130         struct kqinfo kqinfo;
131         struct lock lk;
132
133         int     cap_resx;
134         int     cap_resy;
135         int     cap_phyx;
136         int     cap_phyy;
137         uint8_t cap_buttons;
138
139         int     poll_flags;
140         thread_t poll_td;
141 #if 0
142         struct inputev iev;             /* subr_input.c */
143 #endif
144
145         /*
146          * PS/2 mouse emulation
147          */
148         short   track_x;                /* current tracking */
149         short   track_y;
150         short   track_z;
151         uint16_t track_but;
152         char    track_id1;              /* first finger id */
153         char    track_id2;              /* second finger id */
154         short   delta_x;                /* accumulation -> report */
155         short   delta_y;
156         short   delta_z;
157         short   fuzz_x;
158         short   fuzz_y;
159         short   fuzz_z;
160         short   touch_x;                /* touch down coordinates */
161         short   touch_y;
162         short   touch_z;
163         uint16_t reported_but;
164
165         struct cyapa_fifo rfifo;        /* device->host */
166         struct cyapa_fifo wfifo;        /* host->device */
167         uint8_t ps2_cmd;                /* active p2_cmd waiting for data */
168         uint8_t ps2_acked;
169         int     data_signal;
170         int     blocked;
171         int     reporting_mode;         /* 0=disabled 1=enabled */
172         int     scaling_mode;           /* 0=1:1 1=2:1 */
173         int     remote_mode;            /* 0 for streaming mode */
174         int     resolution;             /* count/mm */
175         int     sample_rate;            /* samples/sec */
176         int     zenabled;               /* z-axis enabled (mode 1 or 2) */
177 };
178
179 #define CYPOLL_SHUTDOWN 0x0001
180
181 #define SIMULATE_BUT4   0x0100
182 #define SIMULATE_BUT5   0x0200
183 #define SIMULATE_LOCK   0x8000
184
185 static void cyapa_poll_thread(void *arg);
186 static int cyapa_raw_input(struct cyapa_softc *sc, struct cyapa_regs *regs);
187
188 static int fifo_empty(struct cyapa_fifo *fifo);
189 static size_t fifo_ready(struct cyapa_fifo *fifo);
190 #if 0
191 static size_t fifo_total_ready(struct cyapa_fifo *fifo);
192 #endif
193 static char *fifo_read(struct cyapa_fifo *fifo, size_t n);
194 static char *fifo_write(struct cyapa_fifo *fifo, size_t n);
195 static uint8_t fifo_read_char(struct cyapa_fifo *fifo);
196 static void fifo_write_char(struct cyapa_fifo *fifo, uint8_t c);
197 static size_t fifo_space(struct cyapa_fifo *fifo);
198 static void fifo_reset(struct cyapa_fifo *fifo);
199
200 static short cyapa_fuzz(short delta, short *fuzz);
201
202 static int cyapa_idle_freq = 1;
203 SYSCTL_INT(_debug, OID_AUTO, cyapa_idle_freq, CTLFLAG_RW,
204                 &cyapa_idle_freq, 0, "");
205 static int cyapa_slow_freq = 20;
206 SYSCTL_INT(_debug, OID_AUTO, cyapa_slow_freq, CTLFLAG_RW,
207                 &cyapa_slow_freq, 0, "");
208 static int cyapa_norm_freq = 100;
209 SYSCTL_INT(_debug, OID_AUTO, cyapa_norm_freq, CTLFLAG_RW,
210                 &cyapa_norm_freq, 0, "");
211
212 static int cyapa_debug = 0;
213 SYSCTL_INT(_debug, OID_AUTO, cyapa_debug, CTLFLAG_RW,
214                 &cyapa_debug, 0, "");
215
216 static
217 void
218 cyapa_lock(struct cyapa_softc *sc)
219 {
220         lockmgr(&sc->lk, LK_EXCLUSIVE);
221 }
222
223 static
224 void
225 cyapa_unlock(struct cyapa_softc *sc)
226 {
227         lockmgr(&sc->lk, LK_RELEASE);
228 }
229
230 /*
231  * Notify if possible receive data ready.  Must be called
232  * without the lock held to avoid deadlocking in kqueue.
233  */
234 static
235 void
236 cyapa_notify(struct cyapa_softc *sc)
237 {
238         if (sc->data_signal || !fifo_empty(&sc->rfifo)) {
239                 KNOTE(&sc->kqinfo.ki_note, 0);
240                 if (sc->blocked) {
241                         cyapa_lock(sc);
242                         sc->blocked = 0;
243                         wakeup(&sc->blocked);
244                         cyapa_unlock(sc);
245                 }
246         }
247 }
248
249 /*
250  * Initialize the device
251  */
252 static
253 int
254 init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe)
255 {
256         static char bl_exit[] = {
257                         0x00, 0xff, 0xa5, 0x00, 0x01,
258                         0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
259         static char bl_deactivate[] = {
260                         0x00, 0xff, 0x3b, 0x00, 0x01,
261                         0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
262         device_t bus;
263         struct cyapa_boot_regs boot;
264         int error;
265         int retries;
266
267
268         bus = device_get_parent(dev);   /* smbus */
269
270         /*
271          * Get status
272          */
273         error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
274                             SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
275                             NULL, 0, (void *)&boot, sizeof(boot), NULL);
276         if (error)
277                 goto done;
278
279         /*
280          * Bootstrap the device if necessary.  It can take up to 2 seconds
281          * for the device to fully initialize.
282          */
283         retries = 2 * 10;
284         while ((boot.stat & CYAPA_STAT_RUNNING) == 0 && retries > 0) {
285                 if (boot.boot & CYAPA_BOOT_BUSY) {
286                         /*
287                          * Busy, wait loop.
288                          */
289                 } else if (boot.error & CYAPA_ERROR_BOOTLOADER) {
290                         /*
291                          * Magic
292                          */
293                         error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
294                                             SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
295                                             bl_deactivate,
296                                             sizeof(bl_deactivate),
297                                             NULL, 0, NULL);
298                         if (error)
299                                 goto done;
300                 } else {
301                         /*
302                          * Magic
303                          */
304                         error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
305                                             SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
306                                             bl_exit,
307                                             sizeof(bl_exit),
308                                             NULL, 0, NULL);
309                         if (error)
310                                 goto done;
311                 }
312                 tsleep(&error, 0, "cyapabt", hz / 10);
313                 --retries;
314                 error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
315                                     SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
316                                     NULL, 0, (void *)&boot, sizeof(boot), NULL);
317                 if (error)
318                         goto done;
319         }
320
321         if (retries == 0) {
322                 device_printf(dev, "Unable to bring device out of bootstrap\n");
323                 error = ENXIO;
324                 goto done;
325         }
326
327         /*
328          * Check identity
329          */
330         error = smbus_trans(bus, addr, CMD_QUERY_CAPABILITIES,
331                             SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
332                             NULL, 0, (void *)cap, sizeof(*cap), NULL);
333
334         if (strncmp(cap->prod_ida, "CYTRA", 5) != 0) {
335                 device_printf(dev, "Product ID \"%5.5s\" mismatch\n",
336                              cap->prod_ida);
337                 error = ENXIO;
338         }
339
340 done:
341         if (error)
342                 device_printf(dev, "Unable to initialize\n");
343         return error;
344 }
345
346 /*
347  * Device infrastructure
348  */
349 #define CYAPA_SOFTC(unit) \
350         ((struct cyapa_softc *)devclass_get_softc(cyapa_devclass, (unit)))
351
352 static void cyapa_identify(driver_t *driver, device_t parent);
353 static int cyapa_probe(device_t);
354 static int cyapa_attach(device_t);
355 static int cyapa_detach(device_t);
356
357 static devclass_t cyapa_devclass;
358
359 static device_method_t cyapa_methods[] = {
360         /* device interface */
361         DEVMETHOD(device_identify,      cyapa_identify),
362         DEVMETHOD(device_probe,         cyapa_probe),
363         DEVMETHOD(device_attach,        cyapa_attach),
364         DEVMETHOD(device_detach,        cyapa_detach),
365
366 #if 0
367         /* smbus interface */
368         DEVMETHOD(smbus_intr,           smbus_generic_intr),
369 #endif
370
371         DEVMETHOD_END
372 };
373
374 static driver_t cyapa_driver = {
375         "cyapa",
376         cyapa_methods,
377         sizeof(struct cyapa_softc),
378 };
379
380 static  d_open_t        cyapaopen;
381 static  d_close_t       cyapaclose;
382 static  d_ioctl_t       cyapaioctl;
383 static  d_read_t        cyaparead;
384 static  d_write_t       cyapawrite;
385 static  d_kqfilter_t    cyapakqfilter;
386
387 static struct dev_ops cyapa_ops = {
388         { "cyapa", 0, 0 },
389         .d_open =       cyapaopen,
390         .d_close =      cyapaclose,
391         .d_ioctl =      cyapaioctl,
392         .d_read =       cyaparead,
393         .d_write =      cyapawrite,
394         .d_kqfilter =   cyapakqfilter,
395 };
396
397 static void
398 cyapa_identify(driver_t *driver, device_t parent)
399 {
400         if (device_find_child(parent, "cyapa", -1) == NULL)
401                 BUS_ADD_CHILD(parent, parent, 0, "cyapa", -1);
402 }
403
404 static int
405 cyapa_probe(device_t dev)
406 {
407         struct cyapa_cap cap;
408         int unit;
409         int addr;
410         int error;
411
412         unit = device_get_unit(dev);
413
414         /*
415          * Only match against specific addresses to avoid blowing up
416          * other I2C devices (?).  At least for now.
417          *
418          * 0x400 (from smbus) - means specific device address probe,
419          *                      rather than generic.
420          *
421          * 0x67 - cypress trackpad on the acer c720.
422          */
423         if ((unit & 0x04FF) != (0x0400 | 0x067))
424                 return ENXIO;
425         addr = unit & 0x3FF;
426         error = init_device(dev, &cap, addr, 1);
427         if (error)
428                 return ENXIO;
429
430         device_set_desc(dev, "Cypress APA I2C Trackpad");
431
432         return (BUS_PROBE_VENDOR);
433 }
434
435 static int
436 cyapa_attach(device_t dev)
437 {
438         struct cyapa_softc *sc = (struct cyapa_softc *)device_get_softc(dev);
439         struct cyapa_cap cap;
440         int unit;
441         int addr;
442
443         if (!sc)
444                 return ENOMEM;
445
446         bzero(sc, sizeof(struct cyapa_softc *));
447
448         lockinit(&sc->lk, "cyapa", 0, 0);
449         sc->reporting_mode = 1;
450
451         unit = device_get_unit(dev);
452         if ((unit & 0x04FF) != (0x0400 | 0x067))
453                 return ENXIO;
454         addr = unit & 0x3FF;
455         if (init_device(dev, &cap, addr, 0))
456                 return ENXIO;
457
458         sc->dev = dev;
459         sc->unit = unit;
460         sc->addr = addr;
461
462         if (unit & 0x0400) {
463                 sc->devnode = make_dev(&cyapa_ops, unit,
464                                 UID_ROOT, GID_WHEEL, 0600,
465                                 "cyapa%d-%02x", unit >> 11, unit & 1023);
466         } else {
467                 sc->devnode = make_dev(&cyapa_ops, unit,
468                                 UID_ROOT, GID_WHEEL, 0600, "cyapa%d", unit);
469         }
470
471         sc->cap_resx = ((cap.max_abs_xy_high << 4) & 0x0F00) |
472                         cap.max_abs_x_low;
473         sc->cap_resy = ((cap.max_abs_xy_high << 8) & 0x0F00) |
474                         cap.max_abs_y_low;
475         sc->cap_phyx = ((cap.phy_siz_xy_high << 4) & 0x0F00) |
476                         cap.phy_siz_x_low;
477         sc->cap_phyy = ((cap.phy_siz_xy_high << 8) & 0x0F00) |
478                         cap.phy_siz_y_low;
479         sc->cap_buttons = cap.buttons;
480
481         device_printf(dev, "%5.5s-%6.6s-%2.2s buttons=%c%c%c res=%dx%d\n",
482                 cap.prod_ida, cap.prod_idb, cap.prod_idc,
483                 ((cap.buttons & CYAPA_FNGR_LEFT) ? 'L' : '-'),
484                 ((cap.buttons & CYAPA_FNGR_MIDDLE) ? 'M' : '-'),
485                 ((cap.buttons & CYAPA_FNGR_RIGHT) ? 'R' : '-'),
486                 sc->cap_resx,
487                 sc->cap_resy);
488
489         /*
490          * Setup input event tracking
491          */
492 #if 0
493         inputev_init(&sc->iev, "Cypress APA Trackpad (cyapa)");
494         inputev_set_evbit(&sc->iev, EV_ABS);
495         inputev_set_abs_params(&sc->iev, ABS_MT_POSITION_X,
496                                0, sc->cap_resx, 0, 0);
497         inputev_set_abs_params(&sc->iev, ABS_MT_POSITION_Y,
498                                0, sc->cap_resy, 0, 0);
499         inputev_set_abs_params(&sc->iev, ABS_MT_PRESSURE,
500                                0, 255, 0, 0);
501         if (sc->cap_phyx)
502                 inputev_set_res(&sc->iev, ABS_MT_POSITION_X,
503                                 sc->cap_resx / sc->cap_phyx);
504         if (sc->cap_phyy)
505                 inputev_set_res(&sc->iev, ABS_MT_POSITION_Y,
506                                 sc->cap_resy / sc->cap_phyy);
507         if (cap.buttons & CYAPA_FNGR_LEFT) {
508                 inputev_set_keybit(&sc->iev, BTN_LEFT);
509                 inputev_set_propbit(&sc->iev, INPUT_PROP_BUTTONPAD);
510         }
511         if (cap.buttons & CYAPA_FNGR_MIDDLE)
512                 inputev_set_keybit(&sc->iev, BTN_MIDDLE);
513         if (cap.buttons & CYAPA_FNGR_RIGHT)
514                 inputev_set_keybit(&sc->iev, BTN_RIGHT);
515
516         inputev_register(&sc->iev);
517 #endif
518
519         /*
520          * Start the polling thread.
521          */
522         lwkt_create(cyapa_poll_thread, sc,
523                     &sc->poll_td, NULL, 0, -1, "cyapa-poll");
524
525         return (0);
526 }
527
528 static int
529 cyapa_detach(device_t dev)
530 {
531         struct cyapa_softc *sc = (struct cyapa_softc *)device_get_softc(dev);
532
533 #if 0
534         /*
535          * Cleanup input event tracking
536          */
537         inputev_deregister(&sc->iev);
538 #endif
539
540         /*
541          * Cleanup our poller thread
542          */
543         atomic_set_int(&sc->poll_flags, CYPOLL_SHUTDOWN);
544         while (sc->poll_td) {
545                 wakeup(&sc->poll_flags);
546                 tsleep(&sc->poll_td, 0, "cyapadet", hz);
547         }
548
549         if (sc->devnode)
550                 dev_ops_remove_minor(&cyapa_ops, device_get_unit(dev));
551         if (sc->devnode)
552                 devfs_assume_knotes(sc->devnode, &sc->kqinfo);
553
554         return (0);
555 }
556
557 /*
558  * USER DEVICE I/O FUNCTIONS
559  */
560 static int
561 cyapaopen (struct dev_open_args *ap)
562 {
563         cdev_t dev = ap->a_head.a_dev;
564         struct cyapa_softc *sc = CYAPA_SOFTC(minor(dev));
565
566         if (sc == NULL)
567                 return (ENXIO);
568
569         if (sc->count != 0)
570                 return (EBUSY);
571
572         sc->count++;
573
574         return (0);
575 }
576
577 static int
578 cyapaclose(struct dev_close_args *ap)
579 {
580         cdev_t dev = ap->a_head.a_dev;
581         struct cyapa_softc *sc = CYAPA_SOFTC(minor(dev));
582
583         if (sc == NULL)
584                 return (ENXIO);
585
586         if (sc->count == 0)
587                 /* This is not supposed to happen. */
588                 return (0);
589
590         sc->count--;
591
592         return (0);
593 }
594
595 static int
596 cyaparead(struct dev_read_args *ap)
597 {
598         cdev_t dev = ap->a_head.a_dev;
599         struct cyapa_softc *sc = CYAPA_SOFTC(minor(dev));
600         int error;
601         struct uio *uio = ap->a_uio;
602         int ioflag = ap->a_ioflag;
603         int didread;
604         size_t n;
605
606         /*
607          * If buffer is empty, load a new event if it is ready
608          */
609         cyapa_lock(sc);
610 again:
611         if (fifo_empty(&sc->rfifo) &&
612             (sc->data_signal || sc->delta_x || sc->delta_y ||
613              sc->track_but != sc->reported_but)) {
614                 uint8_t c0;
615                 uint16_t but;
616                 short delta_x;
617                 short delta_y;
618                 short delta_z;
619
620                 /*
621                  * Accumulate delta_x, delta_y.
622                  */
623                 sc->data_signal = 0;
624                 delta_x = sc->delta_x;
625                 delta_y = sc->delta_y;
626                 delta_z = sc->delta_z;
627                 if (delta_x > 255) {
628                         delta_x = 255;
629                         sc->data_signal = 1;
630                 }
631                 if (delta_x < -256) {
632                         delta_x = -256;
633                         sc->data_signal = 1;
634                 }
635                 if (delta_y > 255) {
636                         delta_y = 255;
637                         sc->data_signal = 1;
638                 }
639                 if (delta_y < -256) {
640                         delta_y = -256;
641                         sc->data_signal = 1;
642                 }
643                 if (delta_z > 255) {
644                         delta_z = 255;
645                         sc->data_signal = 1;
646                 }
647                 if (delta_z < -256) {
648                         delta_z = -256;
649                         sc->data_signal = 1;
650                 }
651                 but = sc->track_but;
652
653                 /*
654                  * Adjust baseline for next calculation
655                  */
656                 sc->delta_x -= delta_x;
657                 sc->delta_y -= delta_y;
658                 sc->delta_z -= delta_z;
659                 sc->reported_but = but;
660
661                 /*
662                  * Fuzz reduces movement jitter by introducing some
663                  * hysteresis.  It operates without cumulative error so
664                  * if you swish around quickly and return your finger to
665                  * where it started, so to will the mouse.
666                  */
667                 delta_x = cyapa_fuzz(delta_x, &sc->fuzz_x);
668                 delta_y = cyapa_fuzz(delta_y, &sc->fuzz_y);
669                 delta_z = cyapa_fuzz(delta_z, &sc->fuzz_z);
670
671                 /*
672                  * Generate report
673                  */
674                 c0 = 0;
675                 if (delta_x < 0)
676                         c0 |= 0x10;
677                 if (delta_y < 0)
678                         c0 |= 0x20;
679                 c0 |= 0x08;
680                 if (but & CYAPA_FNGR_LEFT)
681                         c0 |= 0x01;
682                 if (but & CYAPA_FNGR_MIDDLE)
683                         c0 |= 0x04;
684                 if (but & CYAPA_FNGR_RIGHT)
685                         c0 |= 0x02;
686
687                 fifo_write_char(&sc->rfifo, c0);
688                 fifo_write_char(&sc->rfifo, (uint8_t)delta_x);
689                 fifo_write_char(&sc->rfifo, (uint8_t)delta_y);
690                 switch(sc->zenabled) {
691                 case 1:
692                         /*
693                          * Z axis all 8 bits
694                          */
695                         fifo_write_char(&sc->rfifo, (uint8_t)delta_z);
696                         break;
697                 case 2:
698                         /*
699                          * Z axis low 4 bits + 4th button and 5th button
700                          * (high 2 bits must be left 0).  Auto-scale
701                          * delta_z to fit to avoid a wrong-direction
702                          * overflow (don't try to retain the remainder).
703                          */
704                         while (delta_z > 7 || delta_z < -8)
705                                 delta_z >>= 1;
706                         c0 = (uint8_t)delta_z & 0x0F;
707                         if (but & SIMULATE_BUT4)
708                                 c0 |= 0x10;
709                         if (but & SIMULATE_BUT5)
710                                 c0 |= 0x20;
711                         fifo_write_char(&sc->rfifo, c0);
712                         break;
713                 default:
714                         /* basic PS/2 */
715                         break;
716                 }
717                 cyapa_unlock(sc);
718                 cyapa_notify(sc);
719                 cyapa_lock(sc);
720         }
721
722         /*
723          * Blocking / Non-blocking
724          */
725         error = 0;
726         didread = (uio->uio_resid == 0);
727
728         while ((ioflag & IO_NDELAY) == 0 && fifo_empty(&sc->rfifo)) {
729                 if (sc->data_signal)
730                         goto again;
731                 sc->blocked = 1;
732                 error = lksleep(&sc->blocked, &sc->lk, PCATCH, "cyablk", 0);
733                 if (error)
734                         break;
735         }
736
737         /*
738          * Return any buffered data
739          */
740         while (error == 0 && uio->uio_resid &&
741                (n = fifo_ready(&sc->rfifo)) > 0) {
742                 if (n > uio->uio_resid)
743                         n = uio->uio_resid;
744 #if 0
745                 {
746                         uint8_t *ptr = fifo_read(&sc->rfifo, 0);
747                         size_t v;
748                         kprintf("read: ");
749                         for (v = 0; v < n; ++v)
750                                 kprintf(" %02x", ptr[v]);
751                         kprintf("\n");
752                 }
753 #endif
754                 error = uiomove(fifo_read(&sc->rfifo, 0), n, uio);
755                 if (error)
756                         break;
757                 fifo_read(&sc->rfifo, n);
758                 didread = 1;
759         }
760         cyapa_unlock(sc);
761
762         if (error == 0 && didread == 0)
763                 error = EWOULDBLOCK;
764
765         return error;
766 }
767
768 static int
769 cyapawrite(struct dev_write_args *ap)
770 {
771         cdev_t dev = ap->a_head.a_dev;
772         struct cyapa_softc *sc = CYAPA_SOFTC(minor(dev));
773         struct uio *uio = ap->a_uio;
774         int error;
775         int cmd_completed;
776         size_t n;
777         uint8_t c0;
778
779 again:
780         /*
781          * Copy data from userland.  This will also cross-over the end
782          * of the fifo and keep filling.
783          */
784         cyapa_lock(sc);
785         while ((n = fifo_space(&sc->wfifo)) > 0 && uio->uio_resid) {
786                 if (n > uio->uio_resid)
787                         n = uio->uio_resid;
788                 error = uiomove(fifo_write(&sc->wfifo, 0), n, uio);
789                 if (error)
790                         break;
791                 fifo_write(&sc->wfifo, n);
792         }
793
794         /*
795          * Handle commands
796          */
797         cmd_completed = (fifo_ready(&sc->wfifo) != 0);
798         while (fifo_ready(&sc->wfifo) && cmd_completed && error == 0) {
799                 if (sc->ps2_cmd == 0)
800                         sc->ps2_cmd = fifo_read_char(&sc->wfifo);
801                 switch(sc->ps2_cmd) {
802                 case 0xE6:
803                         /*
804                          * SET SCALING 1:1
805                          */
806                         sc->scaling_mode = 0;
807                         fifo_write_char(&sc->rfifo, 0xFA);
808                         break;
809                 case 0xE7:
810                         /*
811                          * SET SCALING 2:1
812                          */
813                         sc->scaling_mode = 1;
814                         fifo_write_char(&sc->rfifo, 0xFA);
815                         break;
816                 case 0xE8:
817                         /*
818                          * SET RESOLUTION +1 byte
819                          */
820                         if (sc->ps2_acked == 0) {
821                                 sc->ps2_acked = 1;
822                                 fifo_write_char(&sc->rfifo, 0xFA);
823                         }
824                         if (fifo_ready(&sc->wfifo) == 0) {
825                                 cmd_completed = 0;
826                                 break;
827                         }
828                         sc->resolution = fifo_read_char(&sc->wfifo);
829                         fifo_write_char(&sc->rfifo, 0xFA);
830                         break;
831                 case 0xE9:
832                         /*
833                          * STATUS REQUEST
834                          *
835                          * byte1:
836                          *      bit 7   0
837                          *      bit 6   Mode    (1=remote mode, 0=stream mode)
838                          *      bit 5   Enable  (data reporting enabled)
839                          *      bit 4   Scaling (0=1:1 1=2:1)
840                          *      bit 3   0
841                          *      bit 2   LEFT BUTTON     (1 if pressed)
842                          *      bit 1   MIDDLE BUTTON   (1 if pressed)
843                          *      bit 0   RIGHT BUTTON    (1 if pressed)
844                          *
845                          * byte2: resolution counts/mm
846                          * byte3: sample rate
847                          */
848                         c0 = 0;
849                         if (sc->remote_mode)
850                                 c0 |= 0x40;
851                         if (sc->reporting_mode)
852                                 c0 |= 0x20;
853                         if (sc->scaling_mode)
854                                 c0 |= 0x10;
855                         if (sc->track_but & CYAPA_FNGR_LEFT)
856                                 c0 |= 0x04;
857                         if (sc->track_but & CYAPA_FNGR_MIDDLE)
858                                 c0 |= 0x02;
859                         if (sc->track_but & CYAPA_FNGR_RIGHT)
860                                 c0 |= 0x01;
861                         fifo_write_char(&sc->rfifo, 0xFA);
862                         fifo_write_char(&sc->rfifo, c0);
863                         fifo_write_char(&sc->rfifo, 0x00);
864                         fifo_write_char(&sc->rfifo, 100);
865                         break;
866                 case 0xEA:
867                         /*
868                          * Set stream mode and reset movement counters
869                          */
870                         sc->remote_mode = 0;
871                         fifo_write_char(&sc->rfifo, 0xFA);
872                         sc->delta_x = 0;
873                         sc->delta_y = 0;
874                         sc->delta_z = 0;
875                         break;
876                 case 0xEB:
877                         /*
878                          * Read Data (if in remote mode).  If not in remote
879                          * mode force an event.
880                          */
881                         fifo_write_char(&sc->rfifo, 0xFA);
882                         sc->data_signal = 1;
883                         break;
884                 case 0xEC:
885                         /*
886                          * Reset Wrap Mode (ignored)
887                          */
888                         fifo_write_char(&sc->rfifo, 0xFA);
889                         break;
890                 case 0xEE:
891                         /*
892                          * Set Wrap Mode (ignored)
893                          */
894                         fifo_write_char(&sc->rfifo, 0xFA);
895                         break;
896                 case 0xF0:
897                         /*
898                          * Set Remote Mode
899                          */
900                         sc->remote_mode = 1;
901                         fifo_write_char(&sc->rfifo, 0xFA);
902                         sc->delta_x = 0;
903                         sc->delta_y = 0;
904                         sc->delta_z = 0;
905                         break;
906                 case 0xF2:
907                         /*
908                          * Get Device ID
909                          *
910                          * If we send 0x00 - normal PS/2 mouse, no Z-axis
911                          *
912                          * If we send 0x03 - Intellimouse, data packet has
913                          * an additional Z movement byte (8 bits signed).
914                          * (also reset movement counters)
915                          *
916                          * If we send 0x04 - Now includes z-axis and the
917                          * 4th and 5th mouse buttons.
918                          */
919                         fifo_write_char(&sc->rfifo, 0xFA);
920                         switch(sc->zenabled) {
921                         case 1:
922                                 fifo_write_char(&sc->rfifo, 0x03);
923                                 break;
924                         case 2:
925                                 fifo_write_char(&sc->rfifo, 0x04);
926                                 break;
927                         default:
928                                 fifo_write_char(&sc->rfifo, 0x00);
929                                 break;
930                         }
931                         sc->delta_x = 0;
932                         sc->delta_y = 0;
933                         sc->delta_z = 0;
934                         break;
935                 case 0xF3:
936                         /*
937                          * Set Sample Rate
938                          *
939                          * byte1: the sample rate
940                          */
941                         if (sc->ps2_acked == 0) {
942                                 sc->ps2_acked = 1;
943                                 fifo_write_char(&sc->rfifo, 0xFA);
944                         }
945                         if (fifo_ready(&sc->wfifo) == 0) {
946                                 cmd_completed = 0;
947                                 break;
948                         }
949                         sc->sample_rate = fifo_read_char(&sc->wfifo);
950                         fifo_write_char(&sc->rfifo, 0xFA);
951
952                         /*
953                          * zenabling sequence: 200,100,80 (device id 0x03)
954                          *                     200,200,80 (device id 0x04)
955                          *
956                          * We support id 0x03 (no 4th or 5th button).
957                          * We support id 0x04 (w/ 4th and 5th button).
958                          */
959                         if (sc->zenabled == 0 && sc->sample_rate == 200)
960                                 sc->zenabled = -1;
961                         else if (sc->zenabled == -1 && sc->sample_rate == 100)
962                                 sc->zenabled = -2;
963                         else if (sc->zenabled == -1 && sc->sample_rate == 200)
964                                 sc->zenabled = -3;
965                         else if (sc->zenabled == -2 && sc->sample_rate == 80)
966                                 sc->zenabled = 1;       /* z-axis mode */
967                         else if (sc->zenabled == -3 && sc->sample_rate == 80)
968                                 sc->zenabled = 2;       /* z-axis+but4/5 */
969                         break;
970                 case 0xF4:
971                         /*
972                          * Enable data reporting.  Only effects stream mode.
973                          */
974                         fifo_write_char(&sc->rfifo, 0xFA);
975                         sc->reporting_mode = 1;
976                         break;
977                 case 0xF5:
978                         /*
979                          * Disable data reporting.  Only effects stream mode.
980                          */
981                         fifo_write_char(&sc->rfifo, 0xFA);
982                         sc->reporting_mode = 1;
983                         break;
984                 case 0xF6:
985                         /*
986                          * SET DEFAULTS
987                          *
988                          * (reset sampling rate, resolution, scaling and
989                          *  enter stream mode)
990                          */
991                         fifo_write_char(&sc->rfifo, 0xFA);
992                         sc->sample_rate = 100;
993                         sc->resolution = 4;
994                         sc->scaling_mode = 0;
995                         sc->reporting_mode = 0;
996                         sc->remote_mode = 0;
997                         sc->delta_x = 0;
998                         sc->delta_y = 0;
999                         sc->delta_z = 0;
1000                         /* signal */
1001                         break;
1002                 case 0xFE:
1003                         /*
1004                          * RESEND
1005                          *
1006                          * Force a resend by guaranteeing that reported_but
1007                          * differs from track_but.
1008                          */
1009                         fifo_write_char(&sc->rfifo, 0xFA);
1010                         sc->data_signal = 1;
1011                         break;
1012                 case 0xFF:
1013                         /*
1014                          * RESET
1015                          */
1016                         fifo_reset(&sc->rfifo); /* should we do this? */
1017                         fifo_reset(&sc->wfifo); /* should we do this? */
1018                         fifo_write_char(&sc->rfifo, 0xFA);
1019                         sc->delta_x = 0;
1020                         sc->delta_y = 0;
1021                         sc->delta_z = 0;
1022                         sc->zenabled = 0;
1023                         break;
1024                 default:
1025                         kprintf("unknown command %02x\n", sc->ps2_cmd);
1026                         break;
1027                 }
1028                 if (cmd_completed) {
1029                         sc->ps2_cmd = 0;
1030                         sc->ps2_acked = 0;
1031                 }
1032                 cyapa_unlock(sc);
1033                 cyapa_notify(sc);
1034                 cyapa_lock(sc);
1035         }
1036         cyapa_unlock(sc);
1037         if (error == 0 && (cmd_completed || uio->uio_resid))
1038                 goto again;
1039         return error;
1040 }
1041
1042 static void cyapa_filt_detach(struct knote *);
1043 static int cyapa_filt(struct knote *, long);
1044
1045 static struct filterops cyapa_filtops =
1046         { FILTEROP_ISFD, NULL, cyapa_filt_detach, cyapa_filt };
1047
1048 static int
1049 cyapakqfilter(struct dev_kqfilter_args *ap)
1050 {
1051         cdev_t dev = ap->a_head.a_dev;
1052         struct cyapa_softc *sc = CYAPA_SOFTC(minor(dev));
1053         struct knote *kn = ap->a_kn;
1054         struct klist *klist;
1055
1056         switch(kn->kn_filter) {
1057         case EVFILT_READ:
1058                 kn->kn_fop = &cyapa_filtops;
1059                 kn->kn_hook = (void *)sc;
1060                 ap->a_result = 0;
1061                 break;
1062         default:
1063                 ap->a_result = EOPNOTSUPP;
1064                 return (0);
1065         }
1066         klist = &sc->kqinfo.ki_note;
1067         knote_insert(klist, kn);
1068
1069         return (0);
1070 }
1071
1072 static void
1073 cyapa_filt_detach(struct knote *kn)
1074 {
1075         struct cyapa_softc *sc = (struct cyapa_softc *)kn->kn_hook;
1076         struct klist *klist;
1077
1078         klist = &sc->kqinfo.ki_note;
1079         knote_remove(klist, kn);
1080 }
1081
1082 static int
1083 cyapa_filt(struct knote *kn, long hint)
1084 {
1085         struct cyapa_softc *sc = (struct cyapa_softc *)kn->kn_hook;
1086         int ready;
1087
1088         cyapa_lock(sc);
1089         if (fifo_ready(&sc->rfifo) || sc->data_signal)
1090                 ready = 1;
1091         else
1092                 ready = 0;
1093         cyapa_unlock(sc);
1094
1095         return (ready);
1096 }
1097
1098 static int
1099 cyapaioctl(struct dev_ioctl_args *ap)
1100 {
1101         cdev_t dev = ap->a_head.a_dev;
1102         device_t bus;           /* smbbus */
1103         /*struct cyapacmd *s = (struct cyapacmd *)ap->a_data;*/
1104         void *s = NULL;
1105         struct cyapa_softc *sc = CYAPA_SOFTC(minor(dev));
1106         int error;
1107
1108         if (sc == NULL)
1109                 return (ENXIO);
1110         if (s == NULL)
1111                 return (EINVAL);
1112
1113         /*
1114          * NOTE: smbus_*() functions automatically recurse the parent to
1115          *       get to the actual device driver.
1116          */
1117         bus = device_get_parent(sc->dev);       /* smbus */
1118
1119         /* Allocate the bus. */
1120         if ((error = smbus_request_bus(bus, sc->dev,
1121                         (ap->a_fflag & O_NONBLOCK) ?
1122                         SMB_DONTWAIT : (SMB_WAIT | SMB_INTR))))
1123                 return (error);
1124
1125         switch (ap->a_cmd) {
1126         default:
1127 #if 0
1128                 error = inputev_ioctl(&sc->iev, ap->a_cmd, ap->a_data);
1129 #endif
1130                 error = ENOTTY;
1131                 break;
1132         }
1133
1134         smbus_release_bus(bus, sc->dev);
1135
1136         return (error);
1137 }
1138
1139 /*
1140  * MAJOR SUPPORT FUNCTIONS
1141  */
1142 static
1143 void
1144 cyapa_poll_thread(void *arg)
1145 {
1146         struct cyapa_softc *sc = arg;
1147         struct cyapa_regs regs;
1148         device_t bus;           /* smbbus */
1149         int error;
1150         int freq = cyapa_norm_freq;
1151         int isidle = 0;
1152
1153         bus = device_get_parent(sc->dev);
1154
1155         while ((sc->poll_flags & CYPOLL_SHUTDOWN) == 0) {
1156                 error = smbus_request_bus(bus, sc->dev, SMB_WAIT);
1157                 if (error == 0) {
1158                         error = smbus_trans(bus, sc->addr, CMD_DEV_STATUS,
1159                                             SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
1160                                             NULL, 0,
1161                                             (void *)&regs, sizeof(regs), NULL);
1162                         if (error == 0) {
1163                                 isidle = cyapa_raw_input(sc, &regs);
1164                         }
1165                         smbus_release_bus(bus, sc->dev);
1166                 }
1167                 tsleep(&sc->poll_flags, 0, "cyapw", (hz + freq - 1) / freq);
1168                 if (sc->count == 0)
1169                         freq = cyapa_slow_freq;
1170                 else if (isidle)
1171                         freq = cyapa_idle_freq;
1172                 else
1173                         freq = cyapa_norm_freq;
1174         }
1175         sc->poll_td = NULL;
1176         wakeup(&sc->poll_td);
1177 }
1178
1179 static
1180 int
1181 cyapa_raw_input(struct cyapa_softc *sc, struct cyapa_regs *regs)
1182 {
1183         int nfingers;
1184         int i;
1185         int j;
1186         int k;
1187         short x;
1188         short y;
1189         short z;
1190         short x1;
1191         short x2;
1192         uint16_t but;   /* high bits used for simulated but4/but5 */
1193
1194         nfingers = CYAPA_FNGR_NUMFINGERS(regs->fngr);
1195
1196         if (cyapa_debug) {
1197                 kprintf("stat %02x buttons %c%c%c nfngrs=%d ",
1198                         regs->stat,
1199                         ((regs->fngr & CYAPA_FNGR_LEFT) ? 'L' : '-'),
1200                         ((regs->fngr & CYAPA_FNGR_MIDDLE) ? 'L' : '-'),
1201                         ((regs->fngr & CYAPA_FNGR_RIGHT) ? 'L' : '-'),
1202                         nfingers
1203                 );
1204         }
1205         for (i = 0; i < nfingers; ++i) {
1206                 if (cyapa_debug) {
1207                         kprintf(" [x=%04d y=%04d p=%d]",
1208                                 CYAPA_TOUCH_X(regs, i),
1209                                 CYAPA_TOUCH_Y(regs, i),
1210                                 CYAPA_TOUCH_P(regs, i));
1211                 }
1212 #if 0
1213                 inputev_mt_slot(&sc->iev, regs->touch[i].id - 1);
1214                 inputev_mt_report_slot_state(&sc->iev, MT_TOOL_FINGER, 1);
1215                 inputev_report_abs(&sc->iev, ABS_MT_POSITION_X,
1216                                    CYAPA_TOUCH_X(regs, i));
1217                 inputev_report_abs(&sc->iev, ABS_MT_POSITION_Y,
1218                                    CYAPA_TOUCH_Y(regs, i));
1219                 inputev_report_abs(&sc->iev, ABS_MT_PRESSURE,
1220                                    CYAPA_TOUCH_P(regs, i));
1221 #endif
1222         }
1223 #if 0
1224         inputev_mt_sync_frame(&sc->iev);
1225
1226         if (sc->cap_buttons & CYAPA_FNGR_LEFT)
1227                 inputev_report_key(&sc->iev, BTN_LEFT,
1228                                  regs->fngr & CYAPA_FNGR_LEFT);
1229         if (sc->cap_buttons & CYAPA_FNGR_MIDDLE)
1230                 inputev_report_key(&sc->iev, BTN_LEFT,
1231                                  regs->fngr & CYAPA_FNGR_MIDDLE);
1232         if (sc->cap_buttons & CYAPA_FNGR_RIGHT)
1233                 inputev_report_key(&sc->iev, BTN_LEFT,
1234                                  regs->fngr & CYAPA_FNGR_RIGHT);
1235 #endif
1236         /*
1237          * Tracking for local solutions
1238          */
1239         cyapa_lock(sc);
1240         if (nfingers == 0) {
1241                 sc->track_x = -1;
1242                 sc->track_y = -1;
1243                 sc->track_z = -1;
1244                 sc->fuzz_x = 0;
1245                 sc->fuzz_y = 0;
1246                 sc->fuzz_z = 0;
1247                 sc->touch_x = -1;
1248                 sc->touch_y = -1;
1249                 sc->touch_z = -1;
1250                 sc->track_id1 = -1;
1251                 sc->track_id2 = -1;
1252                 sc->track_but = 0;
1253                 i = 0;
1254                 j = 0;
1255                 k = 0;
1256         } else {
1257                 /*
1258                  * The id assigned on touch can move around in the array,
1259                  * find it.  If that finger is lifted up, assign some other
1260                  * finger for mouse tracking and reset track_x and track_y
1261                  * to avoid a mouse jump.
1262                  *
1263                  * If >= 2 fingers are down be sure not to assign i and
1264                  * j to the same index.
1265                  */
1266                 for (i = 0; i < nfingers; ++i) {
1267                         if (sc->track_id1 == regs->touch[i].id)
1268                                 break;
1269                 }
1270                 if (i == nfingers) {
1271                         i = 0;
1272                         sc->track_x = -1;
1273                         sc->track_y = -1;
1274                         sc->track_z = -1;
1275                         sc->track_id1 = regs->touch[i].id;
1276                         if (sc->track_id2 == sc->track_id1)
1277                                 sc->track_id2 = -1;
1278                 }
1279
1280                 /*
1281                  * A second finger.
1282                  */
1283                 for (j = 0; j < nfingers; ++j) {
1284                         if (sc->track_id2 == regs->touch[j].id)
1285                                 break;
1286                 }
1287                 if (j == nfingers) {
1288                         if (nfingers >= 2) {
1289                                 if (i == 0)
1290                                         j = 1;
1291                                 else
1292                                         j = 0;
1293                                 sc->track_id2 = regs->touch[j].id;
1294                         } else {
1295                                 sc->track_id2 = -1;
1296                                 j = 0;
1297                         }
1298                 }
1299
1300                 /*
1301                  * The third finger is used to tap or tap-hold to simulate
1302                  * a button, we don't have to record it persistently.
1303                  */
1304                 if (nfingers >= 3) {
1305                         k = 0;
1306                         if (i == 0 || j == 0)
1307                                 k = 1;
1308                         if (i == 1 || j == 1)
1309                                 k = 2;
1310                 } else {
1311                         k = 0;
1312                 }
1313                 kprintf("ID %3d,%3d,%3d\t%3d,%3d,%3d\n",
1314                         sc->track_id1,
1315                         sc->track_id2,
1316                         ((nfingers >= 3) ? regs->touch[k].id : -1),
1317                         CYAPA_TOUCH_X(regs, i),
1318                         CYAPA_TOUCH_X(regs, j),
1319                         CYAPA_TOUCH_X(regs, k)
1320                 );
1321         }
1322
1323         /*
1324          * On initial touch determine if we are in the slider area.  Setting
1325          * track_z conditionalizes the delta calculations later on.
1326          */
1327         if (nfingers && sc->zenabled > 0 &&
1328             sc->track_x == -1 && sc->track_z == -1) {
1329                 x = CYAPA_TOUCH_X(regs, i);
1330                 z = CYAPA_TOUCH_Y(regs, i);
1331                 if (x > sc->cap_resx * 9 / 10)
1332                         sc->track_z = z;
1333         }
1334
1335         if (nfingers && sc->track_z != -1) {
1336                 /*
1337                  * Slider emulation (right side of trackpad).  Z is tracked
1338                  * based on the Y position.  X and Y tracking are disabled.
1339                  *
1340                  * Because we are emulating a mouse-wheel, we do not want
1341                  * to shove events out at the maximum resolution.
1342                  */
1343                 z = CYAPA_TOUCH_Y(regs, i);
1344                 sc->delta_z += z / ZSCALE - sc->track_z;
1345                 if (sc->touch_z == -1)
1346                         sc->touch_z = z;        /* not used atm */
1347                 sc->track_z = z / ZSCALE;
1348         } else if (nfingers) {
1349                 /*
1350                  * Normal pad position reporting (track_z is left -1)
1351                  */
1352                 x = CYAPA_TOUCH_X(regs, i);
1353                 y = CYAPA_TOUCH_Y(regs, i);
1354                 if (sc->track_x != -1) {
1355                         sc->delta_x += x - sc->track_x;
1356                         sc->delta_y -= y - sc->track_y;
1357                         if (sc->delta_x > sc->cap_resx)
1358                                 sc->delta_x = sc->cap_resx;
1359                         if (sc->delta_x < -sc->cap_resx)
1360                                 sc->delta_x = -sc->cap_resx;
1361                         if (sc->delta_y > sc->cap_resx)
1362                                 sc->delta_y = sc->cap_resy;
1363                         if (sc->delta_y < -sc->cap_resy)
1364                                 sc->delta_y = -sc->cap_resy;
1365                 }
1366                 if (sc->touch_x == -1) {
1367                         sc->touch_x = x;
1368                         sc->touch_y = y;
1369                 }
1370                 sc->track_x = x;
1371                 sc->track_y = y;
1372         }
1373         if (nfingers >= 5 && sc->zenabled > 1 && sc->track_z < 0) {
1374                 /*
1375                  * Simulate the 5th button (when not in slider mode)
1376                  */
1377                 but = SIMULATE_BUT5;
1378         } else if (nfingers >= 4 && sc->zenabled > 1 && sc->track_z < 0) {
1379                 /*
1380                  * Simulate the 4th button (when not in slider mode)
1381                  */
1382                 but = SIMULATE_BUT4;
1383         } else if (nfingers >= 3 && sc->track_z < 0) {
1384                 /*
1385                  * Simulate the left, middle, or right button with 3
1386                  * fingers when not in slider mode.
1387                  *
1388                  * This makes it ultra easy to hit GUI buttons and move
1389                  * windows with a light touch, without having to apply the
1390                  * pressure required to articulate the button.
1391                  *
1392                  * However, if we are coming down from 4 or 5 fingers,
1393                  * do NOT simulate the left button and instead just release
1394                  * button 4 or button 5.  Leave SIMULATE_LOCK set to
1395                  * placemark the condition.  We must go down to 2 fingers
1396                  * to release the lock.
1397                  *
1398                  * LEFT BUTTON: Fingers arranged left-to-right 1 2 3,
1399                  *              move mouse with fingers 2 and 3 and tap
1400                  *              or hold with finger 1 (to the left of fingers
1401                  *              2 and 3).
1402                  *
1403                  * RIGHT BUTTON: Move mouse with fingers 1 and 2 and tap
1404                  *               or hold with finger 3.
1405                  *
1406                  * MIDDLE BUTTON: Move mouse with fingers 1 and 3 and tap
1407                  *                or hold with finger 2.
1408                  */
1409                 x1 = CYAPA_TOUCH_X(regs, i);    /* 1st finger down */
1410                 x2 = CYAPA_TOUCH_X(regs, j);    /* 2nd finger down */
1411                 x = CYAPA_TOUCH_X(regs, k);     /* 3rd finger (button) down */
1412                 if (sc->track_but & (SIMULATE_BUT4 |
1413                                             SIMULATE_BUT5 |
1414                                             SIMULATE_LOCK)) {
1415                         but = SIMULATE_LOCK;
1416                 } else if (sc->track_but & ~SIMULATE_LOCK) {
1417                         but = sc->track_but;
1418                 } else if (x < x1 && x < x2) {
1419                         but = CYAPA_FNGR_LEFT;
1420                 } else if (x > x1 && x < x2) {
1421                         but = CYAPA_FNGR_MIDDLE;
1422                 } else if (x > x2 && x < x1) {
1423                         but = CYAPA_FNGR_MIDDLE;
1424                 } else {
1425                         but = CYAPA_FNGR_RIGHT;
1426                 }
1427         } else if (nfingers == 2 || (nfingers >= 2 && sc->track_z >= 0)) {
1428                 /*
1429                  * If 2 fingers are held down or 2 or more fingers are held
1430                  * down and we are in slider mode, any key press is
1431                  * interpreted as a left mouse button press.
1432                  *
1433                  * If a keypress is already active we retain the active
1434                  * keypress instead.
1435                  *
1436                  * The high-button state is unconditionally cleared with <= 2
1437                  * fingers.
1438                  */
1439                 if (regs->fngr & CYAPA_FNGR_LEFT) {
1440                         but = sc->track_but & ~SIMULATE_LOCK;
1441                         if (but == 0)
1442                                 but = CYAPA_FNGR_LEFT;
1443                 } else {
1444                         but = 0;
1445                 }
1446         } else if (nfingers == 1 &&
1447                    (abs(sc->touch_x - sc->track_x) > 32 ||
1448                     abs(sc->touch_y - sc->track_y) > 32)) {
1449                 /*
1450                  * When using one finger, any significant mouse movement
1451                  * will lock you to the left mouse button if you push the
1452                  * button, regardless of where you are on the pad.
1453                  *
1454                  * If a keypress is already active we retain the active
1455                  * keypress instead.
1456                  *
1457                  * The high-button state is unconditionally cleared with <= 2
1458                  * fingers.
1459                  */
1460                 if (regs->fngr & CYAPA_FNGR_LEFT) {
1461                         but = sc->track_but & ~SIMULATE_LOCK;
1462                         if (but == 0)
1463                                 but = CYAPA_FNGR_LEFT;
1464                 } else {
1465                         but = 0;
1466                 }
1467         } else if (nfingers == 1 && (regs->fngr & CYAPA_FNGR_LEFT)) {
1468                 /*
1469                  * If you are swiping while holding a button down, the
1470                  * button registration does not change.  Otherwise the
1471                  * registered button depends on where you are on the pad.
1472                  *
1473                  * Since no significant movement occurred we allow the
1474                  * button to be pressed while within the slider area
1475                  * and still be properly registered as the right button.
1476                  *
1477                  * The high-button state is unconditionally cleared with <= 2
1478                  * fingers.
1479                  */
1480                 if (sc->track_but & ~SIMULATE_LOCK)
1481                         but = sc->track_but & ~SIMULATE_LOCK;
1482                 else if (sc->track_x < sc->cap_resx * 1 / 3)
1483                         but = CYAPA_FNGR_LEFT;
1484                 else if (sc->track_x < sc->cap_resx * 2 / 3)
1485                         but = CYAPA_FNGR_MIDDLE;
1486                 else
1487                         but = CYAPA_FNGR_RIGHT;
1488         } else if (nfingers == 1) {
1489                 /*
1490                  * Clear all finger state if 1 finger is down and nothing
1491                  * is pressed.
1492                  */
1493                 but = 0;
1494         } else {
1495                 /*
1496                  * Clear all finger state if no fingers are down.
1497                  */
1498                 but = 0;
1499         }
1500         sc->track_but = but;
1501         if (sc->delta_x || sc->delta_y || sc->delta_z ||
1502             sc->track_but != sc->reported_but) {
1503                 if (sc->remote_mode == 0 && sc->reporting_mode)
1504                         sc->data_signal = 1;
1505         }
1506         cyapa_unlock(sc);
1507         cyapa_notify(sc);
1508
1509         if (cyapa_debug)
1510                 kprintf("\n");
1511         return(0);
1512 }
1513
1514 /*
1515  * FIFO FUNCTIONS
1516  */
1517
1518 /*
1519  * Returns non-zero if the fifo is empty
1520  */
1521 static
1522 int
1523 fifo_empty(struct cyapa_fifo *fifo)
1524 {
1525         return(fifo->rindex == fifo->windex);
1526 }
1527
1528 /*
1529  * Returns the number of characters available for reading from
1530  * the fifo without wrapping the fifo buffer.
1531  */
1532 static
1533 size_t
1534 fifo_ready(struct cyapa_fifo *fifo)
1535 {
1536         size_t n;
1537
1538         n = CYAPA_BUFSIZE - (fifo->rindex & CYAPA_BUFMASK);
1539         if (n > (size_t)(fifo->windex - fifo->rindex))
1540                 n = (size_t)(fifo->windex - fifo->rindex);
1541         return n;
1542 }
1543
1544 #if 0
1545 /*
1546  * Returns the number of characters available for reading from
1547  * the fifo including wrapping the fifo buffer.
1548  */
1549 static
1550 size_t
1551 fifo_total_ready(struct cyapa_fifo *fifo)
1552 {
1553         return ((size_t)(fifo->windex - fifo->rindex));
1554 }
1555 #endif
1556
1557 /*
1558  * Returns a read pointer into the fifo and then bumps
1559  * rindex.  The FIFO must have at least 'n' characters in
1560  * it.  The value (n) can cause the index to wrap but users
1561  * of the buffer should never supply a value for (n) that wraps
1562  * the buffer.
1563  */
1564 static
1565 char *
1566 fifo_read(struct cyapa_fifo *fifo, size_t n)
1567 {
1568         char *ptr;
1569
1570         if (n > (CYAPA_BUFSIZE - (fifo->rindex & CYAPA_BUFMASK))) {
1571                 kprintf("fifo_read: overflow\n");
1572                 return (fifo->buf);
1573         }
1574         ptr = fifo->buf + (fifo->rindex & CYAPA_BUFMASK);
1575         fifo->rindex += n;
1576
1577         return (ptr);
1578 }
1579
1580 static
1581 uint8_t
1582 fifo_read_char(struct cyapa_fifo *fifo)
1583 {
1584         uint8_t c;
1585
1586         if (fifo->rindex == fifo->windex) {
1587                 kprintf("fifo_read_char: overflow\n");
1588                 c = 0;
1589         } else {
1590                 c = fifo->buf[fifo->rindex & CYAPA_BUFMASK];
1591                 ++fifo->rindex;
1592         }
1593         return c;
1594 }
1595
1596
1597 /*
1598  * Write a character to the FIFO.  The character will be discarded
1599  * if the FIFO is full.
1600  */
1601 static
1602 void
1603 fifo_write_char(struct cyapa_fifo *fifo, uint8_t c)
1604 {
1605         if (fifo->windex - fifo->rindex < CYAPA_BUFSIZE) {
1606                 fifo->buf[fifo->windex & CYAPA_BUFMASK] = c;
1607                 ++fifo->windex;
1608         }
1609 }
1610
1611 /*
1612  * Return the amount of space available for writing without wrapping
1613  * the fifo.
1614  */
1615 static
1616 size_t
1617 fifo_space(struct cyapa_fifo *fifo)
1618 {
1619         size_t n;
1620
1621         n = CYAPA_BUFSIZE - (fifo->windex & CYAPA_BUFMASK);
1622         if (n > (size_t)(CYAPA_BUFSIZE - (fifo->windex - fifo->rindex)))
1623                 n = (size_t)(CYAPA_BUFSIZE - (fifo->windex - fifo->rindex));
1624         return n;
1625 }
1626
1627 static
1628 char *
1629 fifo_write(struct cyapa_fifo *fifo, size_t n)
1630 {
1631         char *ptr;
1632
1633         ptr = fifo->buf + (fifo->windex & CYAPA_BUFMASK);
1634         fifo->windex += n;
1635
1636         return(ptr);
1637 }
1638
1639 static
1640 void
1641 fifo_reset(struct cyapa_fifo *fifo)
1642 {
1643         fifo->rindex = 0;
1644         fifo->windex = 0;
1645 }
1646
1647 /*
1648  * Fuzz handling
1649  */
1650 static
1651 short
1652 cyapa_fuzz(short delta, short *fuzzp)
1653 {
1654     short fuzz;
1655
1656     fuzz = *fuzzp;
1657     if (fuzz >= 0 && delta < 0) {
1658         ++delta;
1659         --fuzz;
1660     } else if (fuzz <= 0 && delta > 0) {
1661         --delta;
1662         ++fuzz;
1663     }
1664     *fuzzp = fuzz;
1665
1666     return delta;
1667 }
1668
1669 DRIVER_MODULE(cyapa, smbus, cyapa_driver, cyapa_devclass, NULL, NULL);
1670 MODULE_DEPEND(cyapa, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
1671 MODULE_VERSION(cyapa, 1);