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