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