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