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