Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131959993
D3068.id7255.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
54 KB
Referenced Files
None
Subscribers
None
D3068.id7255.diff
View Options
Index: share/man/man4/Makefile
===================================================================
--- share/man/man4/Makefile
+++ share/man/man4/Makefile
@@ -106,6 +106,7 @@
cue.4 \
cxgb.4 \
cxgbe.4 \
+ cyapa.4 \
cy.4 \
da.4 \
dc.4 \
Index: share/man/man4/cyapa.4
===================================================================
--- /dev/null
+++ share/man/man4/cyapa.4
@@ -0,0 +1,194 @@
+.\" Copyright (c) 2015 Michael Gmelin <freebsd@grem.de>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 21, 2015
+.Dt CYAPA 4
+.Os
+.Sh NAME
+.Nm cyapa
+.Nd Cypress APA trackpad with I2C interface driver
+.Sh SYNOPSIS
+To compile this driver into the kernel, place the following lines into
+the kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device cyapa"
+.Cd "device ig4"
+.Cd "device smbus"
+.Ed
+.Pp
+Alternatively, to load the driver as a module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+cyapa_load="YES"
+ig4_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the Cypress APA trackpad.
+It emulates the IntelliMouse PS/2 protocol.
+It supports basic mouse ioctls, so that
+.Xr moused 8
+is supported properly.
+.Ss Trackpad layout
+.Bd -literal
+ 2/3 1/3
+ +--------------------+------------+
+ | | Middle |
+ | | Button |
+ | Left | |
+ | Button +------------+
+ | | Right |
+ | | Button |
+ +--------------------+............|
+ | Thumb/Button Area | 15%
+ +---------------------------------+
+.Ed
+.Ss Trackpad features
+.Bl -tag -width 8n
+.It Va Two finger scrolling
+Use two fingers for Z axis scrolling.
+.It Va Button down/second finger
+While one finger clicks and holds down the touchpad, the second finger can be
+used to move the mouse cursor.
+This can be useful for drawing or selecting text.
+.It Va Thumb/Button area
+The lower 15% of the trackpad will not affect the mouse cursor position.
+This allows for high precision clicking, by controlling the cursor with the
+index finger and pushing/holding the pad down with the thumb.
+.It Va Trackpad button
+Push physical button.
+The left two thirds of the pad issues a LEFT button event.
+The upper right corner issues a MIDDLE button event.
+The lower right corner issues a RIGHT button.
+Optionally, tap to click can be enabled (see below).
+.El
+.Sh SYSCTL VARIABLES
+These
+.Xr sysctl 8
+variables are available:
+.Bl -tag -width 8n
+.It Va debug.cyapa_idle_freq
+Scan frequency in idle mode, the default is 1.
+.It Va debug.cyapa_slow_freq
+Scan frequency in slow mode, the default is 20.
+.It Va debug.cyapa_norm_freq
+Scan frequency in normal mode, the default is 100.
+.It Va debug.cyapa_minpressure
+Minimum pressure to detect a finger, the default is 12.
+.It Va debug.cyapa_enable_tapclick
+Controls tap to click.
+Possible values:
+.Bl -tag -width 8n
+.It 0
+Tap to click is disabled.
+This is the default value.
+.It 1
+Tap to click always generates a left mouse button event.
+.It 2
+Tap to click generates left mouse button event if the left 2/3rds of the pad
+are tapped and a right mouse button event otherwise.
+.It 3
+Tap to click generates mouse button events as if the physical button was
+pressed (see
+.Sx DESCRIPTION
+above).
+.El
+.It Va debug.cyapa_tapclick_min_ticks
+Minimum tap duration in ticks to create a click, the default is 1.
+.It Va debug.cyapa_tapclick_max_ticks
+Maximum tap duration in ticks to create a click, the default is 8.
+.It Va debug.cyapa_move_min_ticks
+Minimum ticks before cursor movement occurs, the default is 4.
+.It Va debug.cyapa_scroll_wait_ticks
+Ticks to wait before starting to scroll, the default is 0.
+.It Va debug.cyapa_scroll_stick_ticks
+Ticks while preventing cursor movement on single finger after scroll,
+the default is 15.
+.It Va debug.cyapa_thumbarea_percent
+Size of bottom thumb area in percent, the default is 15.
+.It Va debug.cyapa_debug
+Setting this to a non-zero value enables debug output to console and syslog,
+the default is 0.
+.It Va debug.cyapa_reset
+Setting this to a non-zero value reinitializes the device.
+The sysctl resets to zero immediately.
+.El
+.Sh FILES
+.Nm
+creates
+.Pa /dev/cyapa0 ,
+which presents the mouse as an
+.Ar IntelliMouse PS/2
+device.
+It supports
+.Xr moused 8
+level 0 and level 2 (level 1 will be used by default).
+.Sh EXAMPLES
+To use
+.Nm
+with
+.Xr moused 8
+add the following lines to the
+.Xr rc.conf 5
+file:
+.Pp
+.Dl moused_enable="YES"
+.Dl moused_port="/dev/cyapa0"
+.Pp
+If vertical scrolling is not desired, add
+.Pp
+.Dl moused_flags="-l0"
+.Pp
+to
+.Xr rc.conf 5 .
+.Pp
+Enable tap to click for the left and the right mouse button and
+disable the thumb area by adding these lines to the
+.Xr sysctl.conf 5
+file:
+.Pp
+.Dl debug.cyapa_thumbarea_percent=0
+.Dl debug.cyapa_enable_tapclick=2
+.Sh SEE ALSO
+.Xr ig4 4 ,
+.Xr moused 4 ,
+.Xr smbus 4 ,
+.Xr sysmouse 4
+.Sh AUTHORS
+.An -nosplit
+The original
+.Nm
+driver was written for DragonFly BSD by
+.An Matthew Dillon .
+.Pp
+It has been ported, modified, and enhanced for
+.Fx
+by
+.An Michael Gmelin Aq Mt freebsd@grem.de .
+.Pp
+This manual page was written by
+.An Michael Gmelin Aq Mt freebsd@grem.de .
Index: sys/dev/cyapa/cyapa.h
===================================================================
--- /dev/null
+++ sys/dev/cyapa/cyapa.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project. All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com> and was subsequently ported
+ * to FreeBSD by Michael Gmelin <freebsd@grem.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_DEV_SMBUS_CYAPA_CYAPA_H_
+#define _SYS_DEV_SMBUS_CYAPA_CYAPA_H_
+
+#define CYAPA_MAX_MT 5
+
+/*
+ * Boot-time registers. This is the device map
+ * if (stat & CYAPA_STAT_RUNNING) is 0.
+ */
+struct cyapa_boot_regs {
+ uint8_t stat; /* CYAPA_STAT_xxx */
+ uint8_t boot; /* CYAPA_BOOT_xxx */
+ uint8_t error;
+} __packed;
+
+#define CYAPA_BOOT_BUSY 0x80
+#define CYAPA_BOOT_RUNNING 0x10
+#define CYAPA_BOOT_DATA_VALID 0x08
+#define CYAPA_BOOT_CSUM_VALID 0x01
+
+#define CYAPA_ERROR_INVALID 0x80
+#define CYAPA_ERROR_INVALID_KEY 0x40
+#define CYAPA_ERROR_BOOTLOADER 0x20
+#define CYAPA_ERROR_CMD_CSUM 0x10
+#define CYAPA_ERROR_FLASH_PROT 0x08
+#define CYAPA_ERROR_FLASH_CSUM 0x04
+
+struct cyapa_regs {
+ uint8_t stat;
+ uint8_t fngr;
+
+ struct {
+ uint8_t xy_high; /* 7:4 high 4 bits of x */
+ uint8_t x_low; /* 3:0 high 4 bits of y */
+ uint8_t y_low;
+ uint8_t pressure;
+ uint8_t id; /* 1-15 incremented each touch */
+ } touch[CYAPA_MAX_MT];
+} __packed;
+
+struct cyapa_cap {
+ uint8_t prod_ida[5]; /* 0x00 - 0x04 */
+ uint8_t prod_idb[6]; /* 0x05 - 0x0A */
+ uint8_t prod_idc[2]; /* 0x0B - 0x0C */
+ uint8_t reserved[6]; /* 0x0D - 0x12 */
+ uint8_t buttons; /* 0x13 */
+ uint8_t gen; /* 0x14, low 4 bits */
+ uint8_t max_abs_xy_high;/* 0x15 7:4 high x bits, 3:0 high y bits */
+ uint8_t max_abs_x_low; /* 0x16 */
+ uint8_t max_abs_y_low; /* 0x17 */
+ uint8_t phy_siz_xy_high;/* 0x18 7:4 high x bits, 3:0 high y bits */
+ uint8_t phy_siz_x_low; /* 0x19 */
+ uint8_t phy_siz_y_low; /* 0x1A */
+} __packed;
+
+#define CYAPA_STAT_RUNNING 0x80
+#define CYAPA_STAT_PWR_MASK 0x0C
+#define CYAPA_PWR_OFF 0x00
+#define CYAPA_PWR_IDLE 0x08
+#define CYAPA_PWR_ACTIVE 0x0C
+
+#define CYAPA_STAT_DEV_MASK 0x03
+#define CYAPA_DEV_NORMAL 0x03
+#define CYAPA_DEV_BUSY 0x01
+
+#define CYAPA_FNGR_DATA_VALID 0x08
+#define CYAPA_FNGR_MIDDLE 0x04
+#define CYAPA_FNGR_RIGHT 0x02
+#define CYAPA_FNGR_LEFT 0x01
+#define CYAPA_FNGR_NUMFINGERS(c) (((c) >> 4) & 0x0F)
+
+#define CYAPA_TOUCH_X(regs, i) ((((regs)->touch[i].xy_high << 4) & 0x0F00) | \
+ (regs)->touch[i].x_low)
+#define CYAPA_TOUCH_Y(regs, i) ((((regs)->touch[i].xy_high << 8) & 0x0F00) | \
+ (regs)->touch[i].y_low)
+#define CYAPA_TOUCH_P(regs, i) ((regs)->touch[i].pressure)
+
+#define CMD_BOOT_STATUS 0x00 /* only if in boot state */
+#define CMD_DEV_STATUS 0x00 /* only if in operational state */
+#define CMD_SOFT_RESET 0x28
+#define CMD_POWER_MODE 0x29
+#define CMD_POWER_MODE_OFF 0x00
+#define CMD_POWER_MODE_IDLE 0x14
+#define CMD_POWER_MODE_FULL 0xFC
+#define CMD_QUERY_CAPABILITIES 0x2A
+
+#endif
Index: sys/dev/cyapa/cyapa.c
===================================================================
--- /dev/null
+++ sys/dev/cyapa/cyapa.c
@@ -0,0 +1,1705 @@
+/*
+ * Copyright (c) 2014 The DragonFly Project. All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com> and was subsequently ported,
+ * modified and enhanced for FreeBSD by Michael Gmelin <freebsd@grem.de>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * CYAPA - Cypress APA trackpad with I2C Interface driver
+ *
+ * Based on DragonFlyBSD's cyapa driver, which referenced the linux
+ * cyapa.c driver to figure out the bootstrapping and commands.
+ *
+ * Unable to locate any datasheet for the device.
+ *
+ *
+ * Trackpad layout:
+ *
+ * 2/3 1/3
+ * +--------------------+------------+
+ * | | Middle |
+ * | | Button |
+ * | Left | |
+ * | Button +------------+
+ * | | Right |
+ * | | Button |
+ * +--------------------+............|
+ * | Thumb/Button Area | 15%
+ * +---------------------------------+
+ *
+ *
+ * FEATURES
+ *
+ * IMPS/2 emulation - Emulates the IntelliMouse protocol.
+ *
+ * Jitter supression - Implements 2-pixel hysteresis with memory.
+ *
+ * Jump detecion - Detect jumps caused by touchpad.
+ *
+ * Two finger scrolling - Use two fingers for Z axis scrolling.
+ *
+ * Button down/2nd finger - While one finger clicks and holds down the
+ * touchpad, the second one can be used to move
+ * the mouse cursor. Useful for drawing or
+ * selecting text.
+ *
+ * Thumb/Button Area - The lower 15%* of the trackpad will not affect
+ * the mouse cursor position. This allows for high
+ * precision clicking, by controlling the cursor
+ * with the index finger and pushing/holding the
+ * pad down with the thumb.
+ * * can be changed using sysctl
+ *
+ * Track-pad button - Push physical button. Left 2/3rds of the pad
+ * will issue a LEFT button event, upper right
+ * corner will issue a MIDDLE button event,
+ * lower right corner will issue a RIGHT button
+ * event. Optional tap support can be enabled
+ * and configured using sysctl.
+ *
+ * WARNINGS
+ *
+ * These trackpads get confused when three or more fingers are down on the
+ * same horizontal axis and will start to glitch the finger detection.
+ * Removing your hand for a few seconds will allow the trackpad to
+ * recalibrate. Generally speaking, when using three or more fingers
+ * please try to place at least one finger off-axis (a little above or
+ * below) the other two.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/event.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/lockmgr.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/mouse.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+#include <sys/sysctl.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+
+#include <dev/smbus/smbconf.h>
+#include <dev/smbus/smbus.h>
+#include <dev/cyapa/cyapa.h>
+
+#include "smbus_if.h"
+#include "bus_if.h"
+#include "device_if.h"
+
+#define CYAPA_BUFSIZE 128 /* power of 2 */
+#define CYAPA_BUFMASK (CYAPA_BUFSIZE - 1)
+
+#define ZSCALE 15 // was 10
+
+#define TIME_TO_IDLE (hz * 10)
+#define TIME_TO_RESET (hz * 3)
+
+static MALLOC_DEFINE(M_CYAPA, "cyapa", "CYAPA device data");
+
+struct cyapa_fifo {
+ int rindex;
+ int windex;
+ char buf[CYAPA_BUFSIZE];
+};
+
+struct cyapa_softc {
+ device_t dev;
+ int count; /* >0 if device opened */
+ int unit;
+ int addr;
+ struct cdev *devnode;
+ struct selinfo selinfo;
+ struct mtx mutex;
+
+ int cap_resx;
+ int cap_resy;
+ int cap_phyx;
+ int cap_phyy;
+ uint8_t cap_buttons;
+
+ int detaching; /* driver is detaching */
+ int poll_thread_running; /* poll thread is running */
+
+ /* PS/2 mouse emulation */
+ int track_x; /* current tracking */
+ int track_y;
+ int track_z;
+ int track_z_ticks;
+ uint16_t track_but;
+ char track_id; /* first finger id */
+ int track_nfingers;
+ int delta_x; /* accumulation -> report */
+ int delta_y;
+ int delta_z;
+ int fuzz_x;
+ int fuzz_y;
+ int fuzz_z;
+ int touch_x; /* touch down coordinates */
+ int touch_y;
+ int touch_z;
+ int finger1_ticks;
+ int finger2_ticks;
+ int finger3_ticks;
+ uint16_t reported_but;
+
+ struct cyapa_fifo rfifo; /* device->host */
+ struct cyapa_fifo wfifo; /* host->device */
+ uint8_t ps2_cmd; /* active p2_cmd waiting for data */
+ uint8_t ps2_acked;
+ int active_tick;
+ int data_signal;
+ int blocked;
+ int isselect;
+ int reporting_mode; /* 0=disabled 1=enabled */
+ int scaling_mode; /* 0=1:1 1=2:1 */
+ int remote_mode; /* 0 for streaming mode */
+ int zenabled; /* z-axis enabled (mode 1 or 2) */
+ mousehw_t hw; /* hardware information */
+ mousemode_t mode; /* mode */
+ int poll_ticks;
+};
+
+struct cyapa_cdevpriv {
+ struct cyapa_softc *sc;
+};
+
+#define CYPOLL_SHUTDOWN 0x0001
+
+static void cyapa_poll_thread(void *arg);
+static int cyapa_raw_input(struct cyapa_softc *sc, struct cyapa_regs *regs, int freq);
+static void cyapa_set_power_mode(struct cyapa_softc *sc, int mode);
+
+static int fifo_empty(struct cyapa_fifo *fifo);
+static size_t fifo_ready(struct cyapa_fifo *fifo);
+static char *fifo_read(struct cyapa_fifo *fifo, size_t n);
+static char *fifo_write(struct cyapa_fifo *fifo, size_t n);
+static uint8_t fifo_read_char(struct cyapa_fifo *fifo);
+static void fifo_write_char(struct cyapa_fifo *fifo, uint8_t c);
+static size_t fifo_space(struct cyapa_fifo *fifo);
+static void fifo_reset(struct cyapa_fifo *fifo);
+
+static int cyapa_fuzz(int delta, int *fuzz);
+
+static int cyapa_idle_freq = 1;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_idle_freq, CTLFLAG_RW,
+ &cyapa_idle_freq, 0, "Scan frequency in idle mode");
+static int cyapa_slow_freq = 20;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_slow_freq, CTLFLAG_RW,
+ &cyapa_slow_freq, 0, "Scan frequency in slow mode ");
+static int cyapa_norm_freq = 100;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_norm_freq, CTLFLAG_RW,
+ &cyapa_norm_freq, 0, "Normal scan frequency");
+static int cyapa_minpressure = 12;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_minpressure, CTLFLAG_RW,
+ &cyapa_minpressure, 0, "Minimum pressure to detect finger");
+static int cyapa_enable_tapclick = 0;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_enable_tapclick, CTLFLAG_RW,
+ &cyapa_enable_tapclick, 0, "Enable tap to click");
+static int cyapa_tapclick_min_ticks = 1;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_tapclick_min_ticks, CTLFLAG_RW,
+ &cyapa_tapclick_min_ticks, 0, "Minimum tap duration for click");
+static int cyapa_tapclick_max_ticks = 8;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_tapclick_max_ticks, CTLFLAG_RW,
+ &cyapa_tapclick_max_ticks, 0, "Maximum tap duration for click");
+static int cyapa_move_min_ticks = 4;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_move_min_ticks, CTLFLAG_RW,
+ &cyapa_move_min_ticks, 0,
+ "Minimum ticks before cursor position is changed");
+static int cyapa_scroll_wait_ticks = 0;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_scroll_wait_ticks, CTLFLAG_RW,
+ &cyapa_scroll_wait_ticks, 0,
+ "Wait N ticks before starting to scroll");
+static int cyapa_scroll_stick_ticks = 15;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_scroll_stick_ticks, CTLFLAG_RW,
+ &cyapa_scroll_stick_ticks, 0,
+ "Prevent cursor move on single finger for N ticks after scroll");
+static int cyapa_thumbarea_percent = 15;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_thumbarea_percent, CTLFLAG_RW,
+ &cyapa_thumbarea_percent, 0,
+ "Size of bottom thumb area in percent");
+
+static int cyapa_debug = 0;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_debug, CTLFLAG_RW,
+ &cyapa_debug, 0, "Enable debugging");
+static int cyapa_reset = 0;
+SYSCTL_INT(_debug, OID_AUTO, cyapa_reset, CTLFLAG_RW,
+ &cyapa_reset, 0, "Reset track pad");
+
+static void
+cyapa_lock(struct cyapa_softc *sc)
+{
+
+ mtx_lock(&sc->mutex);
+}
+
+static void
+cyapa_unlock(struct cyapa_softc *sc)
+{
+
+ mtx_unlock(&sc->mutex);
+}
+
+#define CYAPA_LOCK_ASSERT(sc) mtx_assert(&(sc)->mutex, MA_OWNED);
+
+/*
+ * Notify if possible receive data ready. Must be called
+ * with sc->mutex held (cyapa_lock(sc)).
+ */
+static void
+cyapa_notify(struct cyapa_softc *sc)
+{
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ if (sc->data_signal || !fifo_empty(&sc->rfifo)) {
+ KNOTE_LOCKED(&sc->selinfo.si_note, 0);
+ if (sc->blocked || sc->isselect) {
+ if (sc->blocked) {
+ sc->blocked = 0;
+ wakeup(&sc->blocked);
+ }
+ if (sc->isselect) {
+ sc->isselect = 0;
+ selwakeup(&sc->selinfo);
+ }
+ }
+ }
+}
+
+/*
+ * Initialize the device
+ */
+static int
+init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe)
+{
+ static char bl_exit[] = {
+ 0x00, 0xff, 0xa5, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+ static char bl_deactivate[] = {
+ 0x00, 0xff, 0x3b, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+ device_t bus;
+ struct cyapa_boot_regs boot;
+ int error;
+ int retries;
+
+ bus = device_get_parent(dev); /* smbus */
+
+ /* Get status */
+ error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ NULL, 0, (void *)&boot, sizeof(boot), NULL);
+ if (error)
+ goto done;
+
+ /*
+ * Bootstrap the device if necessary. It can take up to 2 seconds
+ * for the device to fully initialize.
+ */
+ retries = 20;
+ while ((boot.stat & CYAPA_STAT_RUNNING) == 0 && retries > 0) {
+ if (boot.boot & CYAPA_BOOT_BUSY) {
+ /* Busy, wait loop. */
+ } else if (boot.error & CYAPA_ERROR_BOOTLOADER) {
+ /* Magic */
+ error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ bl_deactivate, sizeof(bl_deactivate),
+ NULL, 0, NULL);
+ if (error)
+ goto done;
+ } else {
+ /* Magic */
+ error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ bl_exit, sizeof(bl_exit), NULL, 0, NULL);
+ if (error)
+ goto done;
+ }
+ pause("cyapab1", (hz * 2) / 10);
+ --retries;
+ error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ NULL, 0, (void *)&boot, sizeof(boot), NULL);
+ if (error)
+ goto done;
+ }
+
+ if (retries == 0) {
+ device_printf(dev, "Unable to bring device out of bootstrap\n");
+ error = ENXIO;
+ goto done;
+ }
+
+ /* Check identity */
+ if (cap) {
+ error = smbus_trans(bus, addr, CMD_QUERY_CAPABILITIES,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ NULL, 0, (void *)cap, sizeof(*cap), NULL);
+
+ if (strncmp(cap->prod_ida, "CYTRA", 5) != 0) {
+ device_printf(dev, "Product ID \"%5.5s\" mismatch\n",
+ cap->prod_ida);
+ error = ENXIO;
+ }
+ }
+ error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ NULL, 0, (void *)&boot, sizeof(boot), NULL);
+
+ if (probe == 0) /* official init */
+ device_printf(dev, "cyapa init status %02x\n", boot.stat);
+ else if (probe == 2)
+ device_printf(dev, "cyapa reset status %02x\n", boot.stat);
+
+done:
+ if (error)
+ device_printf(dev, "Unable to initialize\n");
+ return (error);
+}
+
+static int cyapa_probe(device_t);
+static int cyapa_attach(device_t);
+static int cyapa_detach(device_t);
+static void cyapa_cdevpriv_dtor(void*);
+
+static devclass_t cyapa_devclass;
+
+static device_method_t cyapa_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, cyapa_probe),
+ DEVMETHOD(device_attach, cyapa_attach),
+ DEVMETHOD(device_detach, cyapa_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t cyapa_driver = {
+ "cyapa",
+ cyapa_methods,
+ sizeof(struct cyapa_softc),
+};
+
+static d_open_t cyapaopen;
+static d_ioctl_t cyapaioctl;
+static d_read_t cyaparead;
+static d_write_t cyapawrite;
+static d_kqfilter_t cyapakqfilter;
+static d_poll_t cyapapoll;
+
+static struct cdevsw cyapa_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = cyapaopen,
+ .d_ioctl = cyapaioctl,
+ .d_read = cyaparead,
+ .d_write = cyapawrite,
+ .d_kqfilter = cyapakqfilter,
+ .d_poll = cyapapoll,
+};
+
+static int
+cyapa_probe(device_t dev)
+{
+ struct cyapa_cap cap;
+ int unit;
+ int addr;
+ int error;
+
+ addr = smbus_get_addr(dev);
+
+ /*
+ * 0x67 - cypress trackpad on the acer c720
+ * (other devices might use other ids).
+ */
+ if (addr != 0x67)
+ return (ENXIO);
+
+ unit = device_get_unit(dev);
+
+ error = init_device(dev, &cap, addr, 1);
+ if (error != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Cypress APA I2C Trackpad");
+
+ return (BUS_PROBE_VENDOR);
+}
+
+static int
+cyapa_attach(device_t dev)
+{
+ struct cyapa_softc *sc;
+ struct cyapa_cap cap;
+ int unit;
+ int addr;
+
+ sc = device_get_softc(dev);
+ sc->reporting_mode = 1;
+
+ unit = device_get_unit(dev);
+ addr = *((unsigned char*) device_get_ivars(dev));
+
+ if (init_device(dev, &cap, addr, 0))
+ return (ENXIO);
+
+ mtx_init(&sc->mutex, "cyapa", NULL, MTX_DEF);
+
+ sc->dev = dev;
+ sc->unit = unit;
+ sc->addr = addr;
+
+ knlist_init_mtx(&sc->selinfo.si_note, &sc->mutex);
+
+ sc->cap_resx = ((cap.max_abs_xy_high << 4) & 0x0F00) |
+ cap.max_abs_x_low;
+ sc->cap_resy = ((cap.max_abs_xy_high << 8) & 0x0F00) |
+ cap.max_abs_y_low;
+ sc->cap_phyx = ((cap.phy_siz_xy_high << 4) & 0x0F00) |
+ cap.phy_siz_x_low;
+ sc->cap_phyy = ((cap.phy_siz_xy_high << 8) & 0x0F00) |
+ cap.phy_siz_y_low;
+ sc->cap_buttons = cap.buttons;
+
+ device_printf(dev, "%5.5s-%6.6s-%2.2s buttons=%c%c%c res=%dx%d\n",
+ cap.prod_ida, cap.prod_idb, cap.prod_idc,
+ ((cap.buttons & CYAPA_FNGR_LEFT) ? 'L' : '-'),
+ ((cap.buttons & CYAPA_FNGR_MIDDLE) ? 'M' : '-'),
+ ((cap.buttons & CYAPA_FNGR_RIGHT) ? 'R' : '-'),
+ sc->cap_resx, sc->cap_resy);
+
+ sc->hw.buttons = 5;
+ sc->hw.iftype = MOUSE_IF_PS2;
+ sc->hw.type = MOUSE_MOUSE;
+ sc->hw.model = MOUSE_MODEL_INTELLI;
+ sc->hw.hwid = addr;
+
+ sc->mode.protocol = MOUSE_PROTO_PS2;
+ sc->mode.rate = 100;
+ sc->mode.resolution = 4;
+ sc->mode.accelfactor = 1;
+ sc->mode.level = 0;
+ sc->mode.packetsize = MOUSE_PS2_PACKETSIZE;
+
+ /* Setup input event tracking */
+ cyapa_set_power_mode(sc, CMD_POWER_MODE_IDLE);
+
+ /* Start the polling thread */
+ kthread_add(cyapa_poll_thread, sc, NULL, NULL,
+ 0, 0, "cyapa-poll");
+
+ sc->devnode = make_dev(&cyapa_cdevsw, unit,
+ UID_ROOT, GID_WHEEL, 0600, "cyapa%d", unit);
+
+ sc->devnode->si_drv1 = sc;
+
+ return (0);
+}
+
+static int
+cyapa_detach(device_t dev)
+{
+ struct cyapa_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ /* Cleanup poller thread */
+ cyapa_lock(sc);
+ while (sc->poll_thread_running) {
+ sc->detaching = 1;
+ mtx_sleep(&sc->detaching, &sc->mutex, PCATCH, "cyapadet", hz);
+ }
+ cyapa_unlock(sc);
+
+ destroy_dev(sc->devnode);
+
+ knlist_clear(&sc->selinfo.si_note, 0);
+ seldrain(&sc->selinfo);
+ knlist_destroy(&sc->selinfo.si_note);
+
+ mtx_destroy(&sc->mutex);
+
+ return (0);
+}
+
+/*
+ * USER DEVICE I/O FUNCTIONS
+ */
+static int
+cyapaopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct cyapa_cdevpriv *priv;
+ int error;
+
+ priv = malloc(sizeof(*priv), M_CYAPA, M_WAITOK | M_ZERO);
+ priv->sc = dev->si_drv1;
+
+ error = devfs_set_cdevpriv(priv, cyapa_cdevpriv_dtor);
+ if (error == 0) {
+ cyapa_lock(priv->sc);
+ priv->sc->count++;
+ cyapa_unlock(priv->sc);
+ }
+ else
+ free(priv, M_CYAPA);
+
+ return (error);
+}
+
+static void
+cyapa_cdevpriv_dtor(void *data)
+{
+ struct cyapa_cdevpriv *priv;
+
+ priv = data;
+ KASSERT(priv != NULL, ("cyapa cdevpriv should not be NULL!"));
+
+ cyapa_lock(priv->sc);
+ priv->sc->count--;
+ cyapa_unlock(priv->sc);
+
+ free(priv, M_CYAPA);
+}
+
+static int
+cyaparead(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct cyapa_softc *sc;
+ int error;
+ int didread;
+ size_t n;
+ char* ptr;
+
+ sc = dev->si_drv1;
+ /* If buffer is empty, load a new event if it is ready */
+ cyapa_lock(sc);
+again:
+ if (fifo_empty(&sc->rfifo) &&
+ (sc->data_signal || sc->delta_x || sc->delta_y ||
+ sc->track_but != sc->reported_but)) {
+ uint8_t c0;
+ uint16_t but;
+ int delta_x;
+ int delta_y;
+ int delta_z;
+
+ /* Accumulate delta_x, delta_y */
+ sc->data_signal = 0;
+ delta_x = sc->delta_x;
+ delta_y = sc->delta_y;
+ delta_z = sc->delta_z;
+ if (delta_x > 255) {
+ delta_x = 255;
+ sc->data_signal = 1;
+ }
+ if (delta_x < -256) {
+ delta_x = -256;
+ sc->data_signal = 1;
+ }
+ if (delta_y > 255) {
+ delta_y = 255;
+ sc->data_signal = 1;
+ }
+ if (delta_y < -256) {
+ delta_y = -256;
+ sc->data_signal = 1;
+ }
+ if (delta_z > 255) {
+ delta_z = 255;
+ sc->data_signal = 1;
+ }
+ if (delta_z < -256) {
+ delta_z = -256;
+ sc->data_signal = 1;
+ }
+ but = sc->track_but;
+
+ /* Adjust baseline for next calculation */
+ sc->delta_x -= delta_x;
+ sc->delta_y -= delta_y;
+ sc->delta_z -= delta_z;
+ sc->reported_but = but;
+
+ /*
+ * Fuzz reduces movement jitter by introducing some
+ * hysteresis. It operates without cumulative error so
+ * if you swish around quickly and return your finger to
+ * where it started, so to will the mouse.
+ */
+ delta_x = cyapa_fuzz(delta_x, &sc->fuzz_x);
+ delta_y = cyapa_fuzz(delta_y, &sc->fuzz_y);
+ delta_z = cyapa_fuzz(delta_z, &sc->fuzz_z);
+
+ /*
+ * Generate report
+ */
+ c0 = 0;
+ if (delta_x < 0)
+ c0 |= 0x10;
+ if (delta_y < 0)
+ c0 |= 0x20;
+ c0 |= 0x08;
+ if (but & CYAPA_FNGR_LEFT)
+ c0 |= 0x01;
+ if (but & CYAPA_FNGR_MIDDLE)
+ c0 |= 0x04;
+ if (but & CYAPA_FNGR_RIGHT)
+ c0 |= 0x02;
+
+ fifo_write_char(&sc->rfifo, c0);
+ fifo_write_char(&sc->rfifo, (uint8_t)delta_x);
+ fifo_write_char(&sc->rfifo, (uint8_t)delta_y);
+ switch(sc->zenabled) {
+ case 1:
+ /* Z axis all 8 bits */
+ fifo_write_char(&sc->rfifo, (uint8_t)delta_z);
+ break;
+ case 2:
+ /*
+ * Z axis low 4 bits + 4th button and 5th button
+ * (high 2 bits must be left 0). Auto-scale
+ * delta_z to fit to avoid a wrong-direction
+ * overflow (don't try to retain the remainder).
+ */
+ while (delta_z > 7 || delta_z < -8)
+ delta_z >>= 1;
+ c0 = (uint8_t)delta_z & 0x0F;
+ fifo_write_char(&sc->rfifo, c0);
+ break;
+ default:
+ /* basic PS/2 */
+ break;
+ }
+ cyapa_notify(sc);
+ }
+
+ /* Blocking / Non-blocking */
+ error = 0;
+ didread = (uio->uio_resid == 0);
+
+ while ((ioflag & IO_NDELAY) == 0 && fifo_empty(&sc->rfifo)) {
+ if (sc->data_signal)
+ goto again;
+ sc->blocked = 1;
+ error = mtx_sleep(&sc->blocked, &sc->mutex, PCATCH, "cyablk", 0);
+ if (error)
+ break;
+ }
+
+ /* Return any buffered data */
+ while (error == 0 && uio->uio_resid &&
+ (n = fifo_ready(&sc->rfifo)) > 0) {
+ if (n > uio->uio_resid)
+ n = uio->uio_resid;
+ ptr = fifo_read(&sc->rfifo, 0);
+ cyapa_unlock(sc);
+ error = uiomove(ptr, n, uio);
+ cyapa_lock(sc);
+ if (error)
+ break;
+ fifo_read(&sc->rfifo, n);
+ didread = 1;
+ }
+ cyapa_unlock(sc);
+
+ if (error == 0 && didread == 0) {
+ error = EWOULDBLOCK;
+ }
+ return (didread ? 0 : error);
+}
+
+static int
+cyapawrite(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct cyapa_softc *sc;
+ int error;
+ int cmd_completed;
+ size_t n;
+ uint8_t c0;
+ char* ptr;
+
+ sc = dev->si_drv1;
+again:
+ /*
+ * Copy data from userland. This will also cross-over the end
+ * of the fifo and keep filling.
+ */
+ cyapa_lock(sc);
+ while ((n = fifo_space(&sc->wfifo)) > 0 && uio->uio_resid) {
+ if (n > uio->uio_resid)
+ n = uio->uio_resid;
+ ptr = fifo_write(&sc->wfifo, 0);
+ cyapa_unlock(sc);
+ error = uiomove(ptr, n, uio);
+ cyapa_lock(sc);
+ if (error)
+ break;
+ fifo_write(&sc->wfifo, n);
+ }
+
+ /* Handle commands */
+ cmd_completed = (fifo_ready(&sc->wfifo) != 0);
+ while (fifo_ready(&sc->wfifo) && cmd_completed && error == 0) {
+ if (sc->ps2_cmd == 0)
+ sc->ps2_cmd = fifo_read_char(&sc->wfifo);
+ switch(sc->ps2_cmd) {
+ case 0xE6:
+ /* SET SCALING 1:1 */
+ sc->scaling_mode = 0;
+ fifo_write_char(&sc->rfifo, 0xFA);
+ break;
+ case 0xE7:
+ /* SET SCALING 2:1 */
+ sc->scaling_mode = 1;
+ fifo_write_char(&sc->rfifo, 0xFA);
+ break;
+ case 0xE8:
+ /* SET RESOLUTION +1 byte */
+ if (sc->ps2_acked == 0) {
+ sc->ps2_acked = 1;
+ fifo_write_char(&sc->rfifo, 0xFA);
+ }
+ if (fifo_ready(&sc->wfifo) == 0) {
+ cmd_completed = 0;
+ break;
+ }
+ sc->mode.resolution = fifo_read_char(&sc->wfifo);
+ fifo_write_char(&sc->rfifo, 0xFA);
+ break;
+ case 0xE9:
+ /*
+ * STATUS REQUEST
+ *
+ * byte1:
+ * bit 7 0
+ * bit 6 Mode (1=remote mode, 0=stream mode)
+ * bit 5 Enable (data reporting enabled)
+ * bit 4 Scaling (0=1:1 1=2:1)
+ * bit 3 0
+ * bit 2 LEFT BUTTON (1 if pressed)
+ * bit 1 MIDDLE BUTTON (1 if pressed)
+ * bit 0 RIGHT BUTTON (1 if pressed)
+ *
+ * byte2: resolution counts/mm
+ * byte3: sample rate
+ */
+ c0 = 0;
+ if (sc->remote_mode)
+ c0 |= 0x40;
+ if (sc->reporting_mode)
+ c0 |= 0x20;
+ if (sc->scaling_mode)
+ c0 |= 0x10;
+ if (sc->track_but & CYAPA_FNGR_LEFT)
+ c0 |= 0x04;
+ if (sc->track_but & CYAPA_FNGR_MIDDLE)
+ c0 |= 0x02;
+ if (sc->track_but & CYAPA_FNGR_RIGHT)
+ c0 |= 0x01;
+ fifo_write_char(&sc->rfifo, 0xFA);
+ fifo_write_char(&sc->rfifo, c0);
+ fifo_write_char(&sc->rfifo, 0x00);
+ fifo_write_char(&sc->rfifo, 100);
+ break;
+ case 0xEA:
+ /* Set stream mode and reset movement counters */
+ sc->remote_mode = 0;
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->delta_x = 0;
+ sc->delta_y = 0;
+ sc->delta_z = 0;
+ break;
+ case 0xEB:
+ /*
+ * Read Data (if in remote mode). If not in remote
+ * mode force an event.
+ */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->data_signal = 1;
+ break;
+ case 0xEC:
+ /* Reset Wrap Mode (ignored) */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ break;
+ case 0xEE:
+ /* Set Wrap Mode (ignored) */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ break;
+ case 0xF0:
+ /* Set Remote Mode */
+ sc->remote_mode = 1;
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->delta_x = 0;
+ sc->delta_y = 0;
+ sc->delta_z = 0;
+ break;
+ case 0xF2:
+ /*
+ * Get Device ID
+ *
+ * If we send 0x00 - normal PS/2 mouse, no Z-axis
+ *
+ * If we send 0x03 - Intellimouse, data packet has
+ * an additional Z movement byte (8 bits signed).
+ * (also reset movement counters)
+ *
+ * If we send 0x04 - Now includes z-axis and the
+ * 4th and 5th mouse buttons.
+ */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ switch(sc->zenabled) {
+ case 1:
+ fifo_write_char(&sc->rfifo, 0x03);
+ break;
+ case 2:
+ fifo_write_char(&sc->rfifo, 0x04);
+ break;
+ default:
+ fifo_write_char(&sc->rfifo, 0x00);
+ break;
+ }
+ sc->delta_x = 0;
+ sc->delta_y = 0;
+ sc->delta_z = 0;
+ break;
+ case 0xF3:
+ /*
+ * Set Sample Rate
+ *
+ * byte1: the sample rate
+ */
+ if (sc->ps2_acked == 0) {
+ sc->ps2_acked = 1;
+ fifo_write_char(&sc->rfifo, 0xFA);
+ }
+ if (fifo_ready(&sc->wfifo) == 0) {
+ cmd_completed = 0;
+ break;
+ }
+ sc->mode.rate = fifo_read_char(&sc->wfifo);
+ fifo_write_char(&sc->rfifo, 0xFA);
+
+ /*
+ * zenabling sequence: 200,100,80 (device id 0x03)
+ * 200,200,80 (device id 0x04)
+ *
+ * We support id 0x03 (no 4th or 5th button).
+ * We support id 0x04 (w/ 4th and 5th button).
+ */
+ if (sc->zenabled == 0 && sc->mode.rate == 200)
+ sc->zenabled = -1;
+ else if (sc->zenabled == -1 && sc->mode.rate == 100)
+ sc->zenabled = -2;
+ else if (sc->zenabled == -1 && sc->mode.rate == 200)
+ sc->zenabled = -3;
+ else if (sc->zenabled == -2 && sc->mode.rate == 80)
+ sc->zenabled = 1; /* z-axis mode */
+ else if (sc->zenabled == -3 && sc->mode.rate == 80)
+ sc->zenabled = 2; /* z-axis+but4/5 */
+ if (sc->mode.level)
+ sc->zenabled = 1;
+ break;
+ case 0xF4:
+ /* Enable data reporting. Only effects stream mode. */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->reporting_mode = 1;
+ break;
+ case 0xF5:
+ /*
+ * Disable data reporting. Only effects stream mode
+ * and is ignored right now.
+ */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->reporting_mode = 1;
+ break;
+ case 0xF6:
+ /*
+ * SET DEFAULTS
+ *
+ * (reset sampling rate, resolution, scaling and
+ * enter stream mode)
+ */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->mode.rate = 100;
+ sc->mode.resolution = 4;
+ sc->scaling_mode = 0;
+ sc->reporting_mode = 1;
+ sc->remote_mode = 0;
+ sc->delta_x = 0;
+ sc->delta_y = 0;
+ sc->delta_z = 0;
+ /* signal */
+ break;
+ case 0xFE:
+ /*
+ * RESEND
+ *
+ * Force a resend by guaranteeing that reported_but
+ * differs from track_but.
+ */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->data_signal = 1;
+ break;
+ case 0xFF:
+ /*
+ * RESET
+ */
+ fifo_reset(&sc->rfifo); /* should we do this? */
+ fifo_reset(&sc->wfifo); /* should we do this? */
+ fifo_write_char(&sc->rfifo, 0xFA);
+ sc->delta_x = 0;
+ sc->delta_y = 0;
+ sc->delta_z = 0;
+ sc->zenabled = 0;
+ sc->mode.level = 0;
+ break;
+ default:
+ printf("unknown command %02x\n", sc->ps2_cmd);
+ break;
+ }
+ if (cmd_completed) {
+ sc->ps2_cmd = 0;
+ sc->ps2_acked = 0;
+ }
+ cyapa_notify(sc);
+ }
+ cyapa_unlock(sc);
+ if (error == 0 && (cmd_completed || uio->uio_resid))
+ goto again;
+ return (error);
+}
+
+static void cyapafiltdetach(struct knote *);
+static int cyapafilt(struct knote *, long);
+
+static struct filterops cyapa_filtops = {
+ .f_isfd = 1,
+ .f_detach = cyapafiltdetach,
+ .f_event = cyapafilt
+};
+
+static int
+cyapakqfilter(struct cdev *dev, struct knote *kn)
+{
+ struct cyapa_softc *sc;
+ struct knlist *knlist;
+
+ sc = dev->si_drv1;
+
+ switch(kn->kn_filter) {
+ case EVFILT_READ:
+ kn->kn_fop = &cyapa_filtops;
+ kn->kn_hook = (void *)sc;
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ knlist = &sc->selinfo.si_note;
+ knlist_add(knlist, kn, 0);
+
+ return (0);
+}
+
+static int
+cyapapoll(struct cdev *dev, int events, struct thread *td)
+{
+ struct cyapa_softc *sc;
+ int revents;
+
+ sc = dev->si_drv1;
+ revents = 0;
+
+ cyapa_lock(sc);
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (sc->data_signal || !fifo_empty(&sc->rfifo))
+ revents = events & (POLLIN | POLLRDNORM);
+ else {
+ sc->isselect = 1;
+ selrecord(td, &sc->selinfo);
+ }
+ }
+ cyapa_unlock(sc);
+
+ return (revents);
+}
+
+static void
+cyapafiltdetach(struct knote *kn)
+{
+ struct cyapa_softc *sc;
+ struct knlist *knlist;
+
+ sc = (struct cyapa_softc *)kn->kn_hook;
+
+ knlist = &sc->selinfo.si_note;
+ knlist_remove(knlist, kn, 0);
+}
+
+static int
+cyapafilt(struct knote *kn, long hint)
+{
+ struct cyapa_softc *sc;
+ int ready;
+
+ sc = (struct cyapa_softc *)kn->kn_hook;
+
+ cyapa_lock(sc);
+ ready = fifo_ready(&sc->rfifo) || sc->data_signal;
+ cyapa_unlock(sc);
+
+ return (ready);
+}
+
+static int
+cyapaioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ struct cyapa_softc *sc;
+ int error;
+
+ sc = dev->si_drv1;
+ error = 0;
+
+ cyapa_lock(sc);
+ switch (cmd) {
+ case MOUSE_GETHWINFO:
+ *(mousehw_t *)data = sc->hw;
+ if (sc->mode.level == 0)
+ ((mousehw_t *)data)->model = MOUSE_MODEL_GENERIC;
+ break;
+
+ case MOUSE_GETMODE:
+ *(mousemode_t *)data = sc->mode;
+ ((mousemode_t *)data)->resolution =
+ MOUSE_RES_LOW - sc->mode.resolution;
+ switch (sc->mode.level) {
+ case 0:
+ ((mousemode_t *)data)->protocol = MOUSE_PROTO_PS2;
+ ((mousemode_t *)data)->packetsize =
+ MOUSE_PS2_PACKETSIZE;
+ break;
+ case 2:
+ ((mousemode_t *)data)->protocol = MOUSE_PROTO_PS2;
+ ((mousemode_t *)data)->packetsize =
+ MOUSE_PS2_PACKETSIZE + 1;
+ break;
+ }
+ break;
+
+ case MOUSE_GETLEVEL:
+ *(int *)data = sc->mode.level;
+ break;
+
+ case MOUSE_SETLEVEL:
+ if ((*(int *)data < 0) &&
+ (*(int *)data > 2)) {
+ error = EINVAL;
+ break;
+ }
+ sc->mode.level = *(int *)data ? 2 : 0;
+ sc->zenabled = sc->mode.level ? 1 : 0;
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ cyapa_unlock(sc);
+
+ return (error);
+}
+
+/*
+ * MAJOR SUPPORT FUNCTIONS
+ */
+static void
+cyapa_poll_thread(void *arg)
+{
+ struct cyapa_softc *sc;
+ struct cyapa_regs regs;
+ device_t bus; /* smbus */
+ int error;
+ int freq;
+ int isidle;
+ int pstate;
+ int npstate;
+ int last_reset;
+
+ sc = arg;
+ freq = cyapa_norm_freq;
+ isidle = 0;
+ pstate = CMD_POWER_MODE_IDLE;
+ last_reset = ticks;
+
+ bus = device_get_parent(sc->dev);
+
+ cyapa_lock(sc);
+ sc->poll_thread_running = 1;
+ cyapa_unlock(sc);
+
+ for (;;) {
+ error = smbus_request_bus(bus, sc->dev, SMB_WAIT);
+ if (error == 0) {
+ error = smbus_trans(bus, sc->addr, CMD_DEV_STATUS,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ NULL, 0,
+ (void *)®s, sizeof(regs), NULL);
+ if (error == 0) {
+ isidle = cyapa_raw_input(sc, ®s, freq);
+ }
+
+ /*
+ * For some reason the device can crap-out. If it
+ * drops back into bootstrap mode try to reinitialize
+ * it.
+ */
+ if (cyapa_reset ||
+ ((regs.stat & CYAPA_STAT_RUNNING) == 0 &&
+ (unsigned)(ticks - last_reset) > TIME_TO_RESET)) {
+ cyapa_reset = 0;
+ last_reset = ticks;
+ init_device(sc->dev, NULL, sc->addr, 2);
+ }
+ smbus_release_bus(bus, sc->dev);
+ }
+ pause("cyapw", hz / freq);
+ ++sc->poll_ticks;
+
+ if (sc->count == 0) {
+ freq = cyapa_idle_freq;
+ npstate = CMD_POWER_MODE_IDLE;
+ } else if (isidle) {
+ freq = cyapa_slow_freq;
+ npstate = CMD_POWER_MODE_IDLE;
+ } else {
+ freq = cyapa_norm_freq;
+ npstate = CMD_POWER_MODE_FULL;
+ }
+ if (pstate != npstate) {
+ pstate = npstate;
+ cyapa_set_power_mode(sc, pstate);
+ if (cyapa_debug) {
+ switch(pstate) {
+ case CMD_POWER_MODE_OFF:
+ printf("cyapa: power off\n");
+ break;
+ case CMD_POWER_MODE_IDLE:
+ printf("cyapa: power idle\n");
+ break;
+ case CMD_POWER_MODE_FULL:
+ printf("cyapa: power full\n");
+ break;
+ }
+ }
+ }
+
+ cyapa_lock(sc);
+ if (sc->detaching)
+ break;
+ cyapa_unlock(sc);
+ }
+ sc->poll_thread_running = 0;
+ cyapa_unlock(sc);
+ kthread_exit();
+}
+
+static int
+cyapa_raw_input(struct cyapa_softc *sc, struct cyapa_regs *regs, int freq)
+{
+ int nfingers;
+ int afingers; /* actual fingers after culling */
+ int i;
+ int j;
+ int k;
+ int isidle;
+ int thumbarea_begin;
+ int seen_thumb;
+ int x;
+ int y;
+ int z;
+ int newfinger;
+ int lessfingers;
+ int click_x;
+ int click_y;
+ uint16_t but; /* high bits used for simulated but4/but5 */
+
+ thumbarea_begin = sc->cap_resy -
+ ((sc->cap_resy * cyapa_thumbarea_percent) / 100);
+ click_x = click_y = 0;
+
+ /*
+ * If the device is not running the rest of the status
+ * means something else, set fingers to 0.
+ */
+ if ((regs->stat & CYAPA_STAT_RUNNING) == 0) {
+ regs->fngr = 0;
+ }
+
+ /* Process fingers/movement */
+ nfingers = CYAPA_FNGR_NUMFINGERS(regs->fngr);
+ afingers = nfingers;
+
+ if (cyapa_debug) {
+ printf("stat %02x buttons %c%c%c nfngrs=%d ",
+ regs->stat,
+ ((regs->fngr & CYAPA_FNGR_LEFT) ? 'L' : '-'),
+ ((regs->fngr & CYAPA_FNGR_MIDDLE) ? 'M' : '-'),
+ ((regs->fngr & CYAPA_FNGR_RIGHT) ? 'R' : '-'),
+ nfingers);
+ }
+
+ seen_thumb = 0;
+ for (i = 0; i < afingers; ) {
+ if (cyapa_debug) {
+ printf(" [x=%04d y=%04d p=%d i=%d]",
+ CYAPA_TOUCH_X(regs, i),
+ CYAPA_TOUCH_Y(regs, i),
+ CYAPA_TOUCH_P(regs, i),
+ regs->touch[i].id);
+ }
+ if ((CYAPA_TOUCH_Y(regs, i) > thumbarea_begin && seen_thumb) ||
+ CYAPA_TOUCH_P(regs, i) < cyapa_minpressure) {
+ --afingers;
+ if (i < afingers) {
+ regs->touch[i] = regs->touch[i+1];
+ continue;
+ }
+ } else {
+ if (CYAPA_TOUCH_Y(regs, i) > thumbarea_begin)
+ seen_thumb = 1;
+ }
+ ++i;
+ }
+ nfingers = afingers;
+
+ /* Tracking for local solutions */
+ cyapa_lock(sc);
+
+ /*
+ * Track timing for finger-downs. Used to detect false-3-finger
+ * button-down.
+ */
+ switch(afingers) {
+ case 0:
+ break;
+ case 1:
+ if (sc->track_nfingers == 0)
+ sc->finger1_ticks = sc->poll_ticks;
+ break;
+ case 2:
+ if (sc->track_nfingers <= 0)
+ sc->finger1_ticks = sc->poll_ticks;
+ if (sc->track_nfingers <= 1)
+ sc->finger2_ticks = sc->poll_ticks;
+ break;
+ case 3:
+ default:
+ if (sc->track_nfingers <= 0)
+ sc->finger1_ticks = sc->poll_ticks;
+ if (sc->track_nfingers <= 1)
+ sc->finger2_ticks = sc->poll_ticks;
+ if (sc->track_nfingers <= 2)
+ sc->finger3_ticks = sc->poll_ticks;
+ break;
+ }
+ newfinger = sc->track_nfingers < afingers;
+ lessfingers = sc->track_nfingers > afingers;
+ sc->track_nfingers = afingers;
+
+ /*
+ * Lookup and track finger indexes in the touch[] array.
+ */
+ if (afingers == 0) {
+ click_x = sc->track_x;
+ click_y = sc->track_y;
+ sc->track_x = -1;
+ sc->track_y = -1;
+ sc->track_z = -1;
+ sc->fuzz_x = 0;
+ sc->fuzz_y = 0;
+ sc->fuzz_z = 0;
+ sc->touch_x = -1;
+ sc->touch_y = -1;
+ sc->touch_z = -1;
+ sc->track_id = -1;
+ sc->track_but = 0;
+ i = 0;
+ j = 0;
+ k = 0;
+ } else {
+ /*
+ * The id assigned on touch can move around in the array,
+ * find it. If that finger is lifted up, assign some other
+ * finger for mouse tracking and reset track_x and track_y
+ * to avoid a mouse jump.
+ *
+ * If >= 2 fingers are down be sure not to assign i and
+ * j to the same index.
+ */
+ for (i = 0; i < nfingers; ++i) {
+ if (sc->track_id == regs->touch[i].id)
+ break;
+ }
+ if (i == nfingers) {
+ i = 0;
+ sc->track_x = -1;
+ sc->track_y = -1;
+ sc->track_z = -1;
+ while (CYAPA_TOUCH_Y(regs, i) >= thumbarea_begin &&
+ i < nfingers) ++i;
+ if (i == nfingers) {
+ i = 0;
+ }
+ sc->track_id = regs->touch[i].id;
+ }
+ else if ((sc->track_but ||
+ CYAPA_TOUCH_Y(regs, i) >= thumbarea_begin) &&
+ newfinger && afingers == 2) {
+ j = regs->touch[0].id == sc->track_id ? 1 : 0;
+ if (CYAPA_TOUCH_Y(regs, j) < thumbarea_begin) {
+ i = j;
+ sc->track_x = -1;
+ sc->track_y = -1;
+ sc->track_z = -1;
+ sc->track_id = regs->touch[i].id;
+ }
+ }
+ }
+
+ /* Two finger scrolling - reset after timeout */
+ if (sc->track_z != -1 && afingers != 2 &&
+ (sc->poll_ticks - sc->track_z_ticks) > cyapa_scroll_stick_ticks) {
+ sc->track_z = -1;
+ sc->track_z_ticks = 0;
+ }
+
+ /* Initiate two finger scrolling */
+ if (!(regs->fngr & CYAPA_FNGR_LEFT) &&
+ ((afingers && sc->track_z != -1) ||
+ (afingers == 2 && CYAPA_TOUCH_Y(regs, 0) < thumbarea_begin &&
+ CYAPA_TOUCH_Y(regs, 1) < thumbarea_begin))) {
+ if (afingers == 2 && (sc->poll_ticks - sc->finger2_ticks)
+ > cyapa_scroll_wait_ticks) {
+ z = (CYAPA_TOUCH_Y(regs, 0) +
+ CYAPA_TOUCH_Y(regs, 1)) >> 1;
+ sc->delta_z += z / ZSCALE - sc->track_z;
+ if (sc->track_z == -1) {
+ sc->delta_z = 0;
+ }
+ if (sc->touch_z == -1)
+ sc->touch_z = z; /* not used atm */
+ sc->track_z = z / ZSCALE;
+ sc->track_z_ticks = sc->poll_ticks;
+ }
+ } else if (afingers) {
+ /* Normal pad position reporting */
+ x = CYAPA_TOUCH_X(regs, i);
+ y = CYAPA_TOUCH_Y(regs, i);
+ click_x = x;
+ click_y = y;
+ if (sc->track_x != -1 && sc->track_y < thumbarea_begin &&
+ (afingers > 1 || (sc->poll_ticks - sc->finger1_ticks)
+ >= cyapa_move_min_ticks || freq < cyapa_norm_freq)) {
+ sc->delta_x += x - sc->track_x;
+ sc->delta_y -= y - sc->track_y;
+ if (sc->delta_x > sc->cap_resx)
+ sc->delta_x = sc->cap_resx;
+ if (sc->delta_x < -sc->cap_resx)
+ sc->delta_x = -sc->cap_resx;
+ if (sc->delta_y > sc->cap_resx)
+ sc->delta_y = sc->cap_resy;
+ if (sc->delta_y < -sc->cap_resy)
+ sc->delta_y = -sc->cap_resy;
+
+ if (abs(sc->delta_y) > sc->cap_resy / 2 ||
+ abs(sc->delta_x) > sc->cap_resx / 2) {
+ if (cyapa_debug)
+ printf("Detected jump by %i %i\n",
+ sc->delta_x, sc->delta_y);
+ sc->delta_x = sc->delta_y = 0;
+ }
+ }
+ if (sc->touch_x == -1) {
+ sc->touch_x = x;
+ sc->touch_y = y;
+ }
+ sc->track_x = x;
+ sc->track_y = y;
+ }
+
+ /* Select finger (L = 2/3x, M = 1/3u, R = 1/3d) */
+ int is_tapclick = (cyapa_enable_tapclick && lessfingers &&
+ afingers == 0 && sc->poll_ticks - sc->finger1_ticks
+ >= cyapa_tapclick_min_ticks &&
+ sc->poll_ticks - sc->finger1_ticks < cyapa_tapclick_max_ticks);
+
+ if (regs->fngr & CYAPA_FNGR_LEFT || is_tapclick) {
+ if (sc->track_but) {
+ but = sc->track_but;
+ } else if (afingers == 1) {
+ if (click_x < sc->cap_resx * 2 / 3)
+ but = CYAPA_FNGR_LEFT;
+ else if (click_y < sc->cap_resy / 2)
+ but = CYAPA_FNGR_MIDDLE;
+ else
+ but = CYAPA_FNGR_RIGHT;
+ } else if (is_tapclick) {
+ if (click_x < sc->cap_resx * 2 / 3 ||
+ cyapa_enable_tapclick < 2)
+ but = CYAPA_FNGR_LEFT;
+ else if (click_y < sc->cap_resy / 2 &&
+ cyapa_enable_tapclick > 2)
+ but = CYAPA_FNGR_MIDDLE;
+ else
+ but = CYAPA_FNGR_RIGHT;
+ } else {
+ but = CYAPA_FNGR_LEFT;
+ }
+ } else {
+ but = 0;
+ }
+
+ /*
+ * Detect state change from last reported state and
+ * determine if we have gone idle.
+ */
+ sc->track_but = but;
+ if (sc->delta_x || sc->delta_y || sc->delta_z ||
+ sc->track_but != sc->reported_but) {
+ sc->active_tick = ticks;
+ if (sc->remote_mode == 0 && sc->reporting_mode)
+ sc->data_signal = 1;
+ isidle = 0;
+ } else if ((unsigned)(ticks - sc->active_tick) >= TIME_TO_IDLE) {
+ sc->active_tick = ticks - TIME_TO_IDLE; /* prevent overflow */
+ isidle = 1;
+ } else {
+ isidle = 0;
+ }
+ cyapa_notify(sc);
+ cyapa_unlock(sc);
+
+ if (cyapa_debug)
+ printf("%i >> %i << %i\n", isidle, sc->track_id, sc->delta_y);
+ return (isidle);
+}
+
+static void
+cyapa_set_power_mode(struct cyapa_softc *sc, int mode)
+{
+ uint8_t data;
+ device_t bus;
+ int error;
+
+ bus = device_get_parent(sc->dev);
+ error = smbus_request_bus(bus, sc->dev, SMB_WAIT);
+ if (error == 0) {
+ error = smbus_trans(bus, sc->addr, CMD_POWER_MODE,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ NULL, 0, (void *)&data, 1, NULL);
+ data = (data & ~0xFC) | mode;
+ if (error == 0) {
+ error = smbus_trans(bus, sc->addr, CMD_POWER_MODE,
+ SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
+ (void *)&data, 1, NULL, 0, NULL);
+ }
+ smbus_release_bus(bus, sc->dev);
+ }
+}
+
+/*
+ * FIFO FUNCTIONS
+ */
+
+/*
+ * Returns non-zero if the fifo is empty
+ */
+static int
+fifo_empty(struct cyapa_fifo *fifo)
+{
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ return (fifo->rindex == fifo->windex);
+}
+
+/*
+ * Returns the number of characters available for reading from
+ * the fifo without wrapping the fifo buffer.
+ */
+static size_t
+fifo_ready(struct cyapa_fifo *fifo)
+{
+ size_t n;
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ n = CYAPA_BUFSIZE - (fifo->rindex & CYAPA_BUFMASK);
+ if (n > (size_t)(fifo->windex - fifo->rindex))
+ n = (size_t)(fifo->windex - fifo->rindex);
+ return (n);
+}
+
+/*
+ * Returns a read pointer into the fifo and then bumps
+ * rindex. The FIFO must have at least 'n' characters in
+ * it. The value (n) can cause the index to wrap but users
+ * of the buffer should never supply a value for (n) that wraps
+ * the buffer.
+ */
+static char *
+fifo_read(struct cyapa_fifo *fifo, size_t n)
+{
+ char *ptr;
+
+ CYAPA_LOCK_ASSERT(sc);
+ if (n > (CYAPA_BUFSIZE - (fifo->rindex & CYAPA_BUFMASK))) {
+ printf("fifo_read: overflow\n");
+ return (fifo->buf);
+ }
+ ptr = fifo->buf + (fifo->rindex & CYAPA_BUFMASK);
+ fifo->rindex += n;
+
+ return (ptr);
+}
+
+static uint8_t
+fifo_read_char(struct cyapa_fifo *fifo)
+{
+ uint8_t c;
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ if (fifo->rindex == fifo->windex) {
+ printf("fifo_read_char: overflow\n");
+ c = 0;
+ } else {
+ c = fifo->buf[fifo->rindex & CYAPA_BUFMASK];
+ ++fifo->rindex;
+ }
+ return (c);
+}
+
+
+/*
+ * Write a character to the FIFO. The character will be discarded
+ * if the FIFO is full.
+ */
+static void
+fifo_write_char(struct cyapa_fifo *fifo, uint8_t c)
+{
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ if (fifo->windex - fifo->rindex < CYAPA_BUFSIZE) {
+ fifo->buf[fifo->windex & CYAPA_BUFMASK] = c;
+ ++fifo->windex;
+ }
+}
+
+/*
+ * Return the amount of space available for writing without wrapping
+ * the fifo.
+ */
+static size_t
+fifo_space(struct cyapa_fifo *fifo)
+{
+ size_t n;
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ n = CYAPA_BUFSIZE - (fifo->windex & CYAPA_BUFMASK);
+ if (n > (size_t)(CYAPA_BUFSIZE - (fifo->windex - fifo->rindex)))
+ n = (size_t)(CYAPA_BUFSIZE - (fifo->windex - fifo->rindex));
+ return (n);
+}
+
+static char *
+fifo_write(struct cyapa_fifo *fifo, size_t n)
+{
+ char *ptr;
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ ptr = fifo->buf + (fifo->windex & CYAPA_BUFMASK);
+ fifo->windex += n;
+
+ return (ptr);
+}
+
+static void
+fifo_reset(struct cyapa_fifo *fifo)
+{
+
+ CYAPA_LOCK_ASSERT(sc);
+
+ fifo->rindex = 0;
+ fifo->windex = 0;
+}
+
+/*
+ * Fuzz handling
+ */
+static int
+cyapa_fuzz(int delta, int *fuzzp)
+{
+ int fuzz;
+
+ fuzz = *fuzzp;
+ if (fuzz >= 0 && delta < 0) {
+ ++delta;
+ --fuzz;
+ } else if (fuzz <= 0 && delta > 0) {
+ --delta;
+ ++fuzz;
+ }
+ *fuzzp = fuzz;
+
+ return (delta);
+}
+
+DRIVER_MODULE(cyapa, smbus, cyapa_driver, cyapa_devclass, NULL, NULL);
+MODULE_DEPEND(cyapa, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
+MODULE_VERSION(cyapa, 1);
Index: sys/modules/i2c/Makefile
===================================================================
--- sys/modules/i2c/Makefile
+++ sys/modules/i2c/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
SUBDIR =
-SUBDIR += controllers if_ic smbus iicbus iicbb iicsmb iic smb
+SUBDIR += controllers if_ic smbus iicbus iicbb iicsmb iic cyapa smb
.include <bsd.subdir.mk>
Index: sys/modules/i2c/cyapa/Makefile
===================================================================
--- /dev/null
+++ sys/modules/i2c/cyapa/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../dev/cyapa
+KMOD = cyapa
+SRCS = cyapa.c device_if.h bus_if.h smbus_if.h vnode_if.h
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 13, 12:50 PM (18 h, 46 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23676005
Default Alt Text
D3068.id7255.diff (54 KB)
Attached To
Mode
D3068: cyapa(4), driver for the Cypress APA I2C trackpad
Attached
Detach File
Event Timeline
Log In to Comment