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