xref: /dflybsd-src/sys/dev/smbus/cyapa/cyapa.c (revision e19e5bbc20dd1d64f1833c5d0ac7a605c8e9bfa0)
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);
1755