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