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