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