Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 23 Feb 2014 23:36:32 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r262417 - in head: share/man/man4 sys/dev/usb/input
Message-ID:  <201402232336.s1NNaWsX092656@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Sun Feb 23 23:36:32 2014
New Revision: 262417
URL: http://svnweb.freebsd.org/changeset/base/262417

Log:
  Update ATP driver:
  - Support for double-tap and drag.
  - Support for 2-finger horizontal scrolling which translates to page-back/forward events.
  - Single finger tap is equivalent to a left-button press.
  - Two-finger taps are mapped to the right-button click.
  - Three fingers are mapped to middle button.
  - Add sysctl to disable single finger tapping.
  - Fix for multiple open of /dev/atp0
  - Enhanced support for the Fountain/Geyser family by adding Geyser4.
  - Update manual page.
  
  Submitted by:	Rohit Grover <rgrover1@gmail.com>
  MFC after:	2 weeks

Modified:
  head/share/man/man4/atp.4
  head/sys/dev/usb/input/atp.c

Modified: head/share/man/man4/atp.4
==============================================================================
--- head/share/man/man4/atp.4	Sun Feb 23 23:33:11 2014	(r262416)
+++ head/share/man/man4/atp.4	Sun Feb 23 23:36:32 2014	(r262417)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2009 Rohit Grover <rgrover1 at gmail dot com>.
+.\" Copyright (c) 2014 Rohit Grover <rgrover1 at gmail dot com>.
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 7, 2014
+.Dd February 23, 2014
 .Dt ATP 4
 .Os
 .Sh NAME
@@ -41,8 +41,7 @@ your kernel configuration file:
 .Cd "device usb"
 .Ed
 .Pp
-Alternatively, to load the driver as a
-module at boot time, place the following line in
+Alternatively, to load the driver as a module at boot time, place the following line in
 .Xr loader.conf 5 :
 .Bd -literal -offset indent
 atp_load="YES"
@@ -50,24 +49,20 @@ atp_load="YES"
 .Sh DESCRIPTION
 The
 .Nm
-driver provides support for the Apple Internal Trackpad
-device found in many Apple laptops.
+driver provides support for the Apple Internal Trackpad device found in many
+Apple laptops. Older (Fountain/Geyser) and the newer (Wellspring) trackpad
+families are all supported through a unified driver.
+.Pp
+The driver simulates a three\-button mouse using multi\-finger tap detection.
+Single finger tap generates a left\-button click; two\-finger tap maps to the
+middle button; whereas a three\-finger tap gets treated as a right button
+click.
+.Pp
+There is support for 2-finger horizontal scrolling, which translates to
+page\-back/forward events.
 .Pp
-The driver simulates a three\-button mouse using multi\-finger tap
-detection.
-.
-A single\-finger tap generates a left button click;
-two\-finger tap maps to the middle button; whereas a three\-finger tap
-gets treated as a right button click.
-.
 A double\-tap followed by a drag is treated as a selection gesture; a
 virtual left\-button click is assumed for the lifespan of the drag.
-.
-.Nm
-attempts to filter away activity at the horizontal edges of the
-trackpad\-\-this is to keep unintentional palm movement from being
-considered as user input.
-.
 .Pp
 .Nm
 supports dynamic reconfiguration using
@@ -76,6 +71,28 @@ through nodes under
 .Nm hw.usb.atp .
 Pointer sensitivity can be controlled using the sysctl tunable
 .Nm hw.usb.atp.scale_factor .
+Smaller values of
+.Fa scale_factor
+result in faster movement.
+.
+A simple high-pass filter is used to reduce contributions
+from small movements; the threshold for this filter may be controlled by
+.Nm hw.usb.atp.small_movement .
+.
+The maximum tolerable duration of a touch gesture is controlled by
+.Nm hw.usb.atp.touch_timeout
+(in microseconds); beyond this period, touches are considered to be slides.
+(This conversion also happens when a finger stroke accumulates at least
+.Nm hw.usb.atp.slide_min_movement
+movement (in mickeys).
+.
+The maximum time (in microseconds) to allow an association between a double-
+tap and drag gesture may be controlled by
+.Nm hw.usb.atp.double_tap_threshold .
+.
+Should one want to disable tap detection and rely only upon physical button
+presses, set the following sysctl to a value of 2
+.Nm hw.usb.atp.tap_minimum .
 .
 .Sh HARDWARE
 The
@@ -84,6 +101,8 @@ driver provides support for the followin
 .Pp
 .Bl -bullet -compact
 .It
+PowerBooks, iBooks (IDs: 0x020e, 0x020f, 0x0210, 0x0214, 0x0215, 0x0216)
+.It
 Core Duo MacBook & MacBook Pro (IDs: 0x0217, 0x0218, 0x0219)
 .It
 Core2 Duo MacBook & MacBook Pro (IDs: 0x021a, 0x021b, 0x021c)
@@ -95,6 +114,14 @@ Core2 Duo MacBook3,1 (IDs: 0x0229, 0x022
 15 inch PowerBook (IDs: 0x020e, 0x020f, 0x0215)
 .It
 17 inch PowerBook (ID: 0x020d)
+.It
+Almost all recent Macbook-Pros and Airs (IDs: 0x0223, 0x0223, 0x0224, 0x0224,
+0x0225, 0x0225, 0x0230, 0x0230, 0x0231, 0x0231, 0x0232, 0x0232, 0x0236,
+0x0236, 0x0237, 0x0237, 0x0238, 0x0238, 0x023f, 0x023f, 0x0240, 0x0241,
+0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, 0x0249, 0x024a, 0x024b,
+0x024c, 0x024d, 0x024e, 0x0252, 0x0252, 0x0253, 0x0253, 0x0254, 0x0254,
+0x0259, 0x025a, 0x025b, 0x0262, 0x0262, 0x0263, 0x0264, 0x0290, 0x0291,
+0x0292)
 .El
 .Pp
 To discover the product\-id of a touchpad, search for 'Trackpad' in the

Modified: head/sys/dev/usb/input/atp.c
==============================================================================
--- head/sys/dev/usb/input/atp.c	Sun Feb 23 23:33:11 2014	(r262416)
+++ head/sys/dev/usb/input/atp.c	Sun Feb 23 23:36:32 2014	(r262417)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2009 Rohit Grover
+ * Copyright (c) 2014 Rohit Grover
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,29 +24,64 @@
  * SUCH DAMAGE.
  */
 
+/*
+ * Some tables, structures, definitions and constant values for the
+ * touchpad protocol has been copied from Linux's
+ * "drivers/input/mouse/bcm5974.c" which has the following copyright
+ * holders under GPLv2. All device specific code in this driver has
+ * been written from scratch. The decoding algorithm is based on
+ * output from FreeBSD's usbdump.
+ *
+ * Copyright (C) 2008      Henrik Rydberg (rydberg@euromail.se)
+ * Copyright (C) 2008      Scott Shawcroft (scott.shawcroft@gmail.com)
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
+ * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
+ * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
+ * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
+ * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
+ * Copyright (C) 2006      Nicolas Boichat (nicolas@boichat.ch)
+ */
+
+/*
+ * Author's note: 'atp' supports two distinct families of Apple trackpad
+ * products: the older Fountain/Geyser and the latest Wellspring trackpads.
+ * The first version made its appearance with FreeBSD 8 and worked only with
+ * the Fountain/Geyser hardware. A fork of this driver for Wellspring was
+ * contributed by Huang Wen Hui. This driver unifies the Wellspring effort
+ * and also improves upon the original work.
+ *
+ * I'm grateful to Stephan Scheunig, Angela Naegele, and Nokia IT-support
+ * for helping me with access to hardware. Thanks also go to Nokia for
+ * giving me an opportunity to do this work.
+ */
+
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/stdint.h>
+#include <sys/stddef.h>
 #include <sys/param.h>
+#include <sys/types.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/bus.h>
 #include <sys/module.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
-#include <sys/bus.h>
+#include <sys/sysctl.h>
+#include <sys/malloc.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/file.h>
 #include <sys/selinfo.h>
 #include <sys/poll.h>
-#include <sys/sysctl.h>
-#include <sys/uio.h>
 
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbhid.h>
+
 #include "usbdevs.h"
 
 #define USB_DEBUG_VAR atp_debug
@@ -61,17 +96,35 @@ __FBSDID("$FreeBSD$");
  * `options' statements in the kernel configuration file.
  */
 
-/* The multiplier used to translate sensor reported positions to mickeys. */
+/* The divisor used to translate sensor reported positions to mickeys. */
 #ifndef ATP_SCALE_FACTOR
-#define ATP_SCALE_FACTOR 48
+#define ATP_SCALE_FACTOR                  16
+#endif
+
+/* Threshold for small movement noise (in mickeys) */
+#ifndef ATP_SMALL_MOVEMENT_THRESHOLD
+#define ATP_SMALL_MOVEMENT_THRESHOLD      30
+#endif
+
+/* Threshold of instantaneous deltas beyond which movement is considered fast.*/
+#ifndef ATP_FAST_MOVEMENT_TRESHOLD
+#define ATP_FAST_MOVEMENT_TRESHOLD        150
 #endif
 
 /*
- * This is the age (in microseconds) beyond which a touch is
- * considered to be a slide; and therefore a tap event isn't registered.
+ * This is the age in microseconds beyond which a touch is considered
+ * to be a slide; and therefore a tap event isn't registered.
  */
 #ifndef ATP_TOUCH_TIMEOUT
-#define ATP_TOUCH_TIMEOUT 125000
+#define ATP_TOUCH_TIMEOUT                 125000
+#endif
+
+#ifndef ATP_IDLENESS_THRESHOLD
+#define	ATP_IDLENESS_THRESHOLD 10
+#endif
+
+#ifndef FG_SENSOR_NOISE_THRESHOLD
+#define FG_SENSOR_NOISE_THRESHOLD 2
 #endif
 
 /*
@@ -82,39 +135,40 @@ __FBSDID("$FreeBSD$");
  * tap events preceding the slide for such a gesture.
  */
 #ifndef ATP_DOUBLE_TAP_N_DRAG_THRESHOLD
-#define ATP_DOUBLE_TAP_N_DRAG_THRESHOLD 200000
+#define ATP_DOUBLE_TAP_N_DRAG_THRESHOLD   200000
 #endif
 
 /*
- * The device provides us only with pressure readings from an array of
- * X and Y sensors; for our algorithms, we need to interpret groups
- * (typically pairs) of X and Y readings as being related to a single
- * finger stroke. We can relate X and Y readings based on their times
- * of incidence. The coincidence window should be at least 10000us
- * since it is used against values from getmicrotime(), which has a
- * precision of around 10ms.
- */
-#ifndef ATP_COINCIDENCE_THRESHOLD
-#define ATP_COINCIDENCE_THRESHOLD  40000 /* unit: microseconds */
-#if ATP_COINCIDENCE_THRESHOLD > 100000
-#error "ATP_COINCIDENCE_THRESHOLD too large"
-#endif
-#endif /* #ifndef ATP_COINCIDENCE_THRESHOLD */
+ * The wait duration in ticks after losing a touch contact before
+ * zombied strokes are reaped and turned into button events.
+ */
+#define ATP_ZOMBIE_STROKE_REAP_INTERVAL   (hz / 20)	/* 50 ms */
+
+/* The multiplier used to translate sensor reported positions to mickeys. */
+#define FG_SCALE_FACTOR                   380
 
 /*
- * The wait duration (in microseconds) after losing a touch contact
- * before zombied strokes are reaped and turned into button events.
+ * The movement threshold for a stroke; this is the maximum difference
+ * in position which will be resolved as a continuation of a stroke
+ * component.
  */
-#define ATP_ZOMBIE_STROKE_REAP_WINDOW   50000
-#if ATP_ZOMBIE_STROKE_REAP_WINDOW > 100000
-#error "ATP_ZOMBIE_STROKE_REAP_WINDOW too large"
+#define FG_MAX_DELTA_MICKEYS             ((3 * (FG_SCALE_FACTOR)) >> 1)
+
+/* Distance-squared threshold for matching a finger with a known stroke */
+#ifndef WSP_MAX_ALLOWED_MATCH_DISTANCE_SQ
+#define WSP_MAX_ALLOWED_MATCH_DISTANCE_SQ 1000000
 #endif
 
-/* end of driver specific options */
+/* Ignore pressure spans with cumulative press. below this value. */
+#define FG_PSPAN_MIN_CUM_PRESSURE         10
+
+/* Maximum allowed width for pressure-spans.*/
+#define FG_PSPAN_MAX_WIDTH                4
 
+/* end of driver specific options */
 
 /* Tunables */
-static SYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB atp");
+static SYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB ATP");
 
 #ifdef USB_DEBUG
 enum atp_log_level {
@@ -130,12 +184,13 @@ SYSCTL_INT(_hw_usb_atp, OID_AUTO, debug,
 
 static u_int atp_touch_timeout = ATP_TOUCH_TIMEOUT;
 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, touch_timeout, CTLFLAG_RW,
-    &atp_touch_timeout, 125000, "age threshold (in micros) for a touch");
+    &atp_touch_timeout, 125000, "age threshold in microseconds for a touch");
 
 static u_int atp_double_tap_threshold = ATP_DOUBLE_TAP_N_DRAG_THRESHOLD;
 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, double_tap_threshold, CTLFLAG_RW,
     &atp_double_tap_threshold, ATP_DOUBLE_TAP_N_DRAG_THRESHOLD,
-    "maximum time (in micros) between a double-tap");
+    "maximum time in microseconds to allow association between a double-tap and "
+    "drag gesture");
 
 static u_int atp_mickeys_scale_factor = ATP_SCALE_FACTOR;
 static int atp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS);
@@ -143,264 +198,538 @@ SYSCTL_PROC(_hw_usb_atp, OID_AUTO, scale
     &atp_mickeys_scale_factor, sizeof(atp_mickeys_scale_factor),
     atp_sysctl_scale_factor_handler, "IU", "movement scale factor");
 
-static u_int atp_small_movement_threshold = ATP_SCALE_FACTOR >> 3;
+static u_int atp_small_movement_threshold = ATP_SMALL_MOVEMENT_THRESHOLD;
 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, small_movement, CTLFLAG_RW,
-    &atp_small_movement_threshold, ATP_SCALE_FACTOR >> 3,
+    &atp_small_movement_threshold, ATP_SMALL_MOVEMENT_THRESHOLD,
     "the small movement black-hole for filtering noise");
-/*
- * The movement threshold for a stroke; this is the maximum difference
- * in position which will be resolved as a continuation of a stroke
- * component.
- */
-static u_int atp_max_delta_mickeys = ((3 * ATP_SCALE_FACTOR) >> 1);
-SYSCTL_UINT(_hw_usb_atp, OID_AUTO, max_delta_mickeys, CTLFLAG_RW,
-    &atp_max_delta_mickeys, ((3 * ATP_SCALE_FACTOR) >> 1),
-    "max. mickeys-delta which will match against an existing stroke");
+
+static u_int atp_tap_minimum = 1;
+SYSCTL_UINT(_hw_usb_atp, OID_AUTO, tap_minimum, CTLFLAG_RW,
+    &atp_tap_minimum, 1, "Minimum number of taps before detection");
+
 /*
  * Strokes which accumulate at least this amount of absolute movement
  * from the aggregate of their components are considered as
  * slides. Unit: mickeys.
  */
-static u_int atp_slide_min_movement = (ATP_SCALE_FACTOR >> 3);
+static u_int atp_slide_min_movement = 2 * ATP_SMALL_MOVEMENT_THRESHOLD;
 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, slide_min_movement, CTLFLAG_RW,
-    &atp_slide_min_movement, (ATP_SCALE_FACTOR >> 3),
+    &atp_slide_min_movement, 2 * ATP_SMALL_MOVEMENT_THRESHOLD,
     "strokes with at least this amt. of movement are considered slides");
 
 /*
  * The minimum age of a stroke for it to be considered mature; this
  * helps filter movements (noise) from immature strokes. Units: interrupts.
  */
-static u_int atp_stroke_maturity_threshold = 2;
+static u_int atp_stroke_maturity_threshold = 4;
 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, stroke_maturity_threshold, CTLFLAG_RW,
-    &atp_stroke_maturity_threshold, 2,
+    &atp_stroke_maturity_threshold, 4,
     "the minimum age of a stroke for it to be considered mature");
 
-/* Accept pressure readings from sensors only if above this value. */
-static u_int atp_sensor_noise_threshold = 2;
-SYSCTL_UINT(_hw_usb_atp, OID_AUTO, sensor_noise_threshold, CTLFLAG_RW,
-    &atp_sensor_noise_threshold, 2,
-    "accept pressure readings from sensors only if above this value");
+typedef enum atp_trackpad_family {
+	TRACKPAD_FAMILY_FOUNTAIN_GEYSER,
+	TRACKPAD_FAMILY_WELLSPRING,
+	TRACKPAD_FAMILY_MAX /* keep this at the tail end of the enumeration */
+} trackpad_family_t;
+
+enum fountain_geyser_product {
+	FOUNTAIN,
+	GEYSER1,
+	GEYSER1_17inch,
+	GEYSER2,
+	GEYSER3,
+	GEYSER4,
+	FOUNTAIN_GEYSER_PRODUCT_MAX /* keep this at the end */
+};
 
-/* Ignore pressure spans with cumulative press. below this value. */
-static u_int atp_pspan_min_cum_pressure = 10;
-SYSCTL_UINT(_hw_usb_atp, OID_AUTO, pspan_min_cum_pressure, CTLFLAG_RW,
-    &atp_pspan_min_cum_pressure, 10,
-    "ignore pressure spans with cumulative press. below this value");
+enum wellspring_product {
+	WELLSPRING1,
+	WELLSPRING2,
+	WELLSPRING3,
+	WELLSPRING4,
+	WELLSPRING4A,
+	WELLSPRING5,
+	WELLSPRING6A,
+	WELLSPRING6,
+	WELLSPRING5A,
+	WELLSPRING7,
+	WELLSPRING7A,
+	WELLSPRING8,
+	WELLSPRING_PRODUCT_MAX /* keep this at the end of the enumeration */
+};
 
-/* Maximum allowed width for pressure-spans.*/
-static u_int atp_pspan_max_width = 4;
-SYSCTL_UINT(_hw_usb_atp, OID_AUTO, pspan_max_width, CTLFLAG_RW,
-    &atp_pspan_max_width, 4,
-    "maximum allowed width (in sensors) for pressure-spans");
-
-/* We support three payload protocols */
-typedef enum {
-	ATP_PROT_GEYSER1,
-	ATP_PROT_GEYSER2,
-	ATP_PROT_GEYSER3,
-} atp_protocol;
+/* trackpad header types */
+enum fountain_geyser_trackpad_type {
+	FG_TRACKPAD_TYPE_GEYSER1,
+	FG_TRACKPAD_TYPE_GEYSER2,
+	FG_TRACKPAD_TYPE_GEYSER3,
+	FG_TRACKPAD_TYPE_GEYSER4,
+};
+enum wellspring_trackpad_type {
+	WSP_TRACKPAD_TYPE1,      /* plain trackpad */
+	WSP_TRACKPAD_TYPE2,      /* button integrated in trackpad */
+	WSP_TRACKPAD_TYPE3       /* additional header fields since June 2013 */
+};
 
-/* Define the various flavours of devices supported by this driver. */
-enum {
-	ATP_DEV_PARAMS_0,
-	ATP_DEV_PARAMS_PBOOK,
-	ATP_DEV_PARAMS_PBOOK_15A,
-	ATP_DEV_PARAMS_PBOOK_17,
-	ATP_N_DEV_PARAMS
+/*
+ * Trackpad family and product and family are encoded together in the
+ * driver_info value associated with a trackpad product.
+ */
+#define N_PROD_BITS 8  /* Number of bits used to encode product */
+#define ENCODE_DRIVER_INFO(FAMILY, PROD)      \
+    (((FAMILY) << N_PROD_BITS) | (PROD))
+#define DECODE_FAMILY_FROM_DRIVER_INFO(INFO)  ((INFO) >> N_PROD_BITS)
+#define DECODE_PRODUCT_FROM_DRIVER_INFO(INFO) \
+    ((INFO) & ((1 << N_PROD_BITS) - 1))
+
+#define FG_DRIVER_INFO(PRODUCT)               \
+    ENCODE_DRIVER_INFO(TRACKPAD_FAMILY_FOUNTAIN_GEYSER, PRODUCT)
+#define WELLSPRING_DRIVER_INFO(PRODUCT)       \
+    ENCODE_DRIVER_INFO(TRACKPAD_FAMILY_WELLSPRING, PRODUCT)
+
+/*
+ * The following structure captures the state of a pressure span along
+ * an axis. Each contact with the touchpad results in separate
+ * pressure spans along the two axes.
+ */
+typedef struct fg_pspan {
+	u_int width;       /* in units of sensors */
+	u_int cum;         /* cumulative compression (from all sensors) */
+	u_int cog;         /* center of gravity */
+	u_int loc;         /* location (scaled using the mickeys factor) */
+	boolean_t matched; /* to track pspans as they match against strokes. */
+} fg_pspan;
+
+#define FG_MAX_PSPANS_PER_AXIS 3
+#define FG_MAX_STROKES         (2 * FG_MAX_PSPANS_PER_AXIS)
+
+#define WELLSPRING_INTERFACE_INDEX 1
+
+/* trackpad finger data offsets, le16-aligned */
+#define WSP_TYPE1_FINGER_DATA_OFFSET  (13 * 2)
+#define WSP_TYPE2_FINGER_DATA_OFFSET  (15 * 2)
+#define WSP_TYPE3_FINGER_DATA_OFFSET  (19 * 2)
+
+/* trackpad button data offsets */
+#define WSP_TYPE2_BUTTON_DATA_OFFSET   15
+#define WSP_TYPE3_BUTTON_DATA_OFFSET   23
+
+/* list of device capability bits */
+#define HAS_INTEGRATED_BUTTON   1
+
+/* trackpad finger structure - little endian */
+struct wsp_finger_sensor_data {
+	int16_t origin;       /* zero when switching track finger */
+	int16_t abs_x;        /* absolute x coordinate */
+	int16_t abs_y;        /* absolute y coordinate */
+	int16_t rel_x;        /* relative x coordinate */
+	int16_t rel_y;        /* relative y coordinate */
+	int16_t tool_major;   /* tool area, major axis */
+	int16_t tool_minor;   /* tool area, minor axis */
+	int16_t orientation;  /* 16384 when point, else 15 bit angle */
+	int16_t touch_major;  /* touch area, major axis */
+	int16_t touch_minor;  /* touch area, minor axis */
+	int16_t unused[3];    /* zeros */
+	int16_t multi;        /* one finger: varies, more fingers: constant */
+} __packed;
+
+typedef struct wsp_finger {
+	/* to track fingers as they match against strokes. */
+	boolean_t matched;
+
+	/* location (scaled using the mickeys factor) */
+	int x;
+	int y;
+} wsp_finger_t;
+
+#define WSP_MAX_FINGERS               16
+#define WSP_SIZEOF_FINGER_SENSOR_DATA sizeof(struct wsp_finger_sensor_data)
+#define WSP_SIZEOF_ALL_FINGER_DATA    (WSP_MAX_FINGERS * \
+				       WSP_SIZEOF_FINGER_SENSOR_DATA)
+#define WSP_MAX_FINGER_ORIENTATION    16384
+
+#define ATP_SENSOR_DATA_BUF_MAX       1024
+#if (ATP_SENSOR_DATA_BUF_MAX < ((WSP_MAX_FINGERS * 14 * 2) + \
+				WSP_TYPE3_FINGER_DATA_OFFSET))
+/* note: 14 * 2 in the above is based on sizeof(struct wsp_finger_sensor_data)*/
+#error "ATP_SENSOR_DATA_BUF_MAX is too small"
+#endif
+
+#define ATP_MAX_STROKES               MAX(WSP_MAX_FINGERS, FG_MAX_STROKES)
+
+#define FG_MAX_XSENSORS 26
+#define FG_MAX_YSENSORS 16
+
+/* device-specific configuration */
+struct fg_dev_params {
+	u_int                              data_len;   /* for sensor data */
+	u_int                              n_xsensors;
+	u_int                              n_ysensors;
+	enum fountain_geyser_trackpad_type prot;
 };
-struct atp_dev_params {
-	u_int            data_len;   /* for sensor data */
-	u_int            n_xsensors;
-	u_int            n_ysensors;
-	atp_protocol     prot;
-} atp_dev_params[ATP_N_DEV_PARAMS] = {
-	[ATP_DEV_PARAMS_0] = {
-		.data_len   = 64,
-		.n_xsensors = 20,
-		.n_ysensors = 10,
-		.prot       = ATP_PROT_GEYSER3
+struct wsp_dev_params {
+	uint8_t  caps;               /* device capability bitmask */
+	uint8_t  tp_type;            /* type of trackpad interface */
+	uint8_t  finger_data_offset; /* offset to trackpad finger data */
+};
+
+static const struct fg_dev_params fg_dev_params[FOUNTAIN_GEYSER_PRODUCT_MAX] = {
+	[FOUNTAIN] = {
+		.data_len   = 81,
+		.n_xsensors = 16,
+		.n_ysensors = 16,
+		.prot       = FG_TRACKPAD_TYPE_GEYSER1
 	},
-	[ATP_DEV_PARAMS_PBOOK] = {
+	[GEYSER1] = {
 		.data_len   = 81,
 		.n_xsensors = 16,
 		.n_ysensors = 16,
-		.prot       = ATP_PROT_GEYSER1
+		.prot       = FG_TRACKPAD_TYPE_GEYSER1
 	},
-	[ATP_DEV_PARAMS_PBOOK_15A] = {
+	[GEYSER1_17inch] = {
+		.data_len   = 81,
+		.n_xsensors = 26,
+		.n_ysensors = 16,
+		.prot       = FG_TRACKPAD_TYPE_GEYSER1
+	},
+	[GEYSER2] = {
 		.data_len   = 64,
 		.n_xsensors = 15,
 		.n_ysensors = 9,
-		.prot       = ATP_PROT_GEYSER2
+		.prot       = FG_TRACKPAD_TYPE_GEYSER2
 	},
-	[ATP_DEV_PARAMS_PBOOK_17] = {
-		.data_len   = 81,
-		.n_xsensors = 26,
-		.n_ysensors = 16,
-		.prot       = ATP_PROT_GEYSER1
+	[GEYSER3] = {
+		.data_len   = 64,
+		.n_xsensors = 20,
+		.n_ysensors = 10,
+		.prot       = FG_TRACKPAD_TYPE_GEYSER3
 	},
+	[GEYSER4] = {
+		.data_len   = 64,
+		.n_xsensors = 20,
+		.n_ysensors = 10,
+		.prot       = FG_TRACKPAD_TYPE_GEYSER4
+	}
 };
 
-static const STRUCT_USB_HOST_ID atp_devs[] = {
+static const STRUCT_USB_HOST_ID fg_devs[] = {
+	/* PowerBooks Feb 2005, iBooks G4 */
+	{ USB_VPI(USB_VENDOR_APPLE, 0x020e, FG_DRIVER_INFO(FOUNTAIN)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x020f, FG_DRIVER_INFO(FOUNTAIN)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0210, FG_DRIVER_INFO(FOUNTAIN)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x030a, FG_DRIVER_INFO(FOUNTAIN)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x030b, FG_DRIVER_INFO(GEYSER1)) },
+
+	/* PowerBooks Oct 2005 */
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0214, FG_DRIVER_INFO(GEYSER2)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0215, FG_DRIVER_INFO(GEYSER2)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0216, FG_DRIVER_INFO(GEYSER2)) },
+
 	/* Core Duo MacBook & MacBook Pro */
-	{ USB_VPI(USB_VENDOR_APPLE, 0x0217, ATP_DEV_PARAMS_0) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x0218, ATP_DEV_PARAMS_0) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x0219, ATP_DEV_PARAMS_0) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0217, FG_DRIVER_INFO(GEYSER3)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0218, FG_DRIVER_INFO(GEYSER3)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0219, FG_DRIVER_INFO(GEYSER3)) },
 
 	/* Core2 Duo MacBook & MacBook Pro */
-	{ USB_VPI(USB_VENDOR_APPLE, 0x021a, ATP_DEV_PARAMS_0) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x021b, ATP_DEV_PARAMS_0) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x021c, ATP_DEV_PARAMS_0) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x021a, FG_DRIVER_INFO(GEYSER4)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x021b, FG_DRIVER_INFO(GEYSER4)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x021c, FG_DRIVER_INFO(GEYSER4)) },
 
 	/* Core2 Duo MacBook3,1 */
-	{ USB_VPI(USB_VENDOR_APPLE, 0x0229, ATP_DEV_PARAMS_0) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x022a, ATP_DEV_PARAMS_0) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x022b, ATP_DEV_PARAMS_0) },
-
-	/* 12 inch PowerBook and iBook */
-	{ USB_VPI(USB_VENDOR_APPLE, 0x030a, ATP_DEV_PARAMS_PBOOK) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x030b, ATP_DEV_PARAMS_PBOOK) },
-
-	/* 15 inch PowerBook */
-	{ USB_VPI(USB_VENDOR_APPLE, 0x020e, ATP_DEV_PARAMS_PBOOK) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x020f, ATP_DEV_PARAMS_PBOOK) },
-	{ USB_VPI(USB_VENDOR_APPLE, 0x0215, ATP_DEV_PARAMS_PBOOK_15A) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0229, FG_DRIVER_INFO(GEYSER4)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x022a, FG_DRIVER_INFO(GEYSER4)) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x022b, FG_DRIVER_INFO(GEYSER4)) },
 
 	/* 17 inch PowerBook */
-	{ USB_VPI(USB_VENDOR_APPLE, 0x020d, ATP_DEV_PARAMS_PBOOK_17) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x020d, FG_DRIVER_INFO(GEYSER1_17inch)) },
+};
 
+static const struct wsp_dev_params wsp_dev_params[WELLSPRING_PRODUCT_MAX] = {
+	[WELLSPRING1] = {
+		.caps       = 0,
+		.tp_type    = WSP_TRACKPAD_TYPE1,
+		.finger_data_offset  = WSP_TYPE1_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING2] = {
+		.caps       = 0,
+		.tp_type    = WSP_TRACKPAD_TYPE1,
+		.finger_data_offset  = WSP_TYPE1_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING3] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING4] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING4A] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING5] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING6] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING5A] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING6A] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING7] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING7A] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE2,
+		.finger_data_offset  = WSP_TYPE2_FINGER_DATA_OFFSET,
+	},
+	[WELLSPRING8] = {
+		.caps       = HAS_INTEGRATED_BUTTON,
+		.tp_type    = WSP_TRACKPAD_TYPE3,
+		.finger_data_offset  = WSP_TYPE3_FINGER_DATA_OFFSET,
+	},
 };
 
-/*
- * The following structure captures the state of a pressure span along
- * an axis. Each contact with the touchpad results in separate
- * pressure spans along the two axes.
- */
-typedef struct atp_pspan {
-	u_int width;   /* in units of sensors */
-	u_int cum;     /* cumulative compression (from all sensors) */
-	u_int cog;     /* center of gravity */
-	u_int loc;     /* location (scaled using the mickeys factor) */
-	boolean_t matched; /* to track pspans as they match against strokes. */
-} atp_pspan;
+#define ATP_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
+
+static const STRUCT_USB_HOST_ID wsp_devs[] = {
+	/* MacbookAir1.1 */
+	ATP_DEV(APPLE, WELLSPRING_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING1)),
+	ATP_DEV(APPLE, WELLSPRING_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING1)),
+	ATP_DEV(APPLE, WELLSPRING_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING1)),
+
+	/* MacbookProPenryn, aka wellspring2 */
+	ATP_DEV(APPLE, WELLSPRING2_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING2)),
+	ATP_DEV(APPLE, WELLSPRING2_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING2)),
+	ATP_DEV(APPLE, WELLSPRING2_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING2)),
+
+	/* Macbook5,1 (unibody), aka wellspring3 */
+	ATP_DEV(APPLE, WELLSPRING3_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING3)),
+	ATP_DEV(APPLE, WELLSPRING3_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING3)),
+	ATP_DEV(APPLE, WELLSPRING3_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING3)),
+
+	/* MacbookAir3,2 (unibody), aka wellspring4 */
+	ATP_DEV(APPLE, WELLSPRING4_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING4)),
+	ATP_DEV(APPLE, WELLSPRING4_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING4)),
+	ATP_DEV(APPLE, WELLSPRING4_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING4)),
+
+	/* MacbookAir3,1 (unibody), aka wellspring4 */
+	ATP_DEV(APPLE, WELLSPRING4A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING4A)),
+	ATP_DEV(APPLE, WELLSPRING4A_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING4A)),
+	ATP_DEV(APPLE, WELLSPRING4A_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING4A)),
+
+	/* Macbook8 (unibody, March 2011) */
+	ATP_DEV(APPLE, WELLSPRING5_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING5)),
+	ATP_DEV(APPLE, WELLSPRING5_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING5)),
+	ATP_DEV(APPLE, WELLSPRING5_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING5)),
+
+	/* MacbookAir4,1 (unibody, July 2011) */
+	ATP_DEV(APPLE, WELLSPRING6A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING6A)),
+	ATP_DEV(APPLE, WELLSPRING6A_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING6A)),
+	ATP_DEV(APPLE, WELLSPRING6A_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING6A)),
+
+	/* MacbookAir4,2 (unibody, July 2011) */
+	ATP_DEV(APPLE, WELLSPRING6_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING6)),
+	ATP_DEV(APPLE, WELLSPRING6_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING6)),
+	ATP_DEV(APPLE, WELLSPRING6_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING6)),
+
+	/* Macbook8,2 (unibody) */
+	ATP_DEV(APPLE, WELLSPRING5A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING5A)),
+	ATP_DEV(APPLE, WELLSPRING5A_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING5A)),
+	ATP_DEV(APPLE, WELLSPRING5A_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING5A)),
+
+	/* MacbookPro10,1 (unibody, June 2012) */
+	/* MacbookPro11,? (unibody, June 2013) */
+	ATP_DEV(APPLE, WELLSPRING7_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING7)),
+	ATP_DEV(APPLE, WELLSPRING7_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING7)),
+	ATP_DEV(APPLE, WELLSPRING7_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING7)),
+
+	/* MacbookPro10,2 (unibody, October 2012) */
+	ATP_DEV(APPLE, WELLSPRING7A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING7A)),
+	ATP_DEV(APPLE, WELLSPRING7A_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING7A)),
+	ATP_DEV(APPLE, WELLSPRING7A_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING7A)),
+
+	/* MacbookAir6,2 (unibody, June 2013) */
+	ATP_DEV(APPLE, WELLSPRING8_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING8)),
+	ATP_DEV(APPLE, WELLSPRING8_ISO,  WELLSPRING_DRIVER_INFO(WELLSPRING8)),
+	ATP_DEV(APPLE, WELLSPRING8_JIS,  WELLSPRING_DRIVER_INFO(WELLSPRING8)),
+};
 
 typedef enum atp_stroke_type {
 	ATP_STROKE_TOUCH,
 	ATP_STROKE_SLIDE,
 } atp_stroke_type;
 
-#define ATP_MAX_PSPANS_PER_AXIS 3
+typedef enum atp_axis {
+	X = 0,
+	Y = 1,
+	NUM_AXES
+} atp_axis;
+
+#define ATP_FIFO_BUF_SIZE        8 /* bytes */
+#define ATP_FIFO_QUEUE_MAXLEN   50 /* units */
+
+enum {
+	ATP_INTR_DT,
+	ATP_RESET,
+	ATP_N_TRANSFER,
+};
 
-typedef struct atp_stroke_component {
+typedef struct fg_stroke_component {
 	/* Fields encapsulating the pressure-span. */
 	u_int loc;              /* location (scaled) */
 	u_int cum_pressure;     /* cumulative compression */
 	u_int max_cum_pressure; /* max cumulative compression */
 	boolean_t matched; /*to track components as they match against pspans.*/
 
-	/* Fields containing information about movement. */
 	int   delta_mickeys;    /* change in location (un-smoothened movement)*/
-	int   pending;          /* cum. of pending short movements */
-	int   movement;         /* current smoothened movement */
-} atp_stroke_component;
-
-typedef enum atp_axis {
-	X = 0,
-	Y = 1
-} atp_axis;
-
-#define ATP_MAX_STROKES         (2 * ATP_MAX_PSPANS_PER_AXIS)
+} fg_stroke_component_t;
 
 /*
  * The following structure captures a finger contact with the
  * touchpad. A stroke comprises two p-span components and some state.
  */
 typedef struct atp_stroke {
-	atp_stroke_type      type;
-	struct timeval       ctime; /* create time; for coincident siblings. */
-	u_int                age;   /*
-				     * Unit: interrupts; we maintain
-				     * this value in addition to
-				     * 'ctime' in order to avoid the
-				     * expensive call to microtime()
-				     * at every interrupt.
-				     */
-
-	atp_stroke_component components[2];
-	u_int                velocity_squared; /*
-						* Average magnitude (squared)
-						* of recent velocity.
-						*/
-	u_int                cum_movement; /* cum. absolute movement so far */
-
-	uint32_t             flags;  /* the state of this stroke */
-#define ATSF_ZOMBIE          0x1
-} atp_stroke;
+	TAILQ_ENTRY(atp_stroke) entry;
 
-#define ATP_FIFO_BUF_SIZE        8 /* bytes */
-#define ATP_FIFO_QUEUE_MAXLEN   50 /* units */
+	atp_stroke_type type;
+	uint32_t        flags; /* the state of this stroke */
+#define ATSF_ZOMBIE 0x1
+	boolean_t       matched;          /* to track match against fingers.*/
 
-enum {
-	ATP_INTR_DT,
-	ATP_RESET,
-	ATP_N_TRANSFER,
-};
+	struct timeval  ctime; /* create time; for coincident siblings. */
+
+	/*
+	 * Unit: interrupts; we maintain this value in
+	 * addition to 'ctime' in order to avoid the
+	 * expensive call to microtime() at every
+	 * interrupt.
+	 */
+	uint32_t age;
+
+	/* Location */
+	int x;
+	int y;
+
+	/* Fields containing information about movement. */
+	int   instantaneous_dx; /* curr. change in X location (un-smoothened) */
+	int   instantaneous_dy; /* curr. change in Y location (un-smoothened) */
+	int   pending_dx;       /* cum. of pending short movements */
+	int   pending_dy;       /* cum. of pending short movements */
+	int   movement_dx;      /* interpreted smoothened movement */
+	int   movement_dy;      /* interpreted smoothened movement */
+	int   cum_movement_x;   /* cum. horizontal movement */
+	int   cum_movement_y;   /* cum. vertical movement */
+
+	/*
+	 * The following member is relevant only for fountain-geyser trackpads.
+	 * For these, there is the need to track pressure-spans and cumulative
+	 * pressures for stroke components.
+	 */
+	fg_stroke_component_t components[NUM_AXES];
+} atp_stroke_t;
+
+struct atp_softc; /* forward declaration */
+typedef void (*sensor_data_interpreter_t)(struct atp_softc *sc, u_int len);
 
 struct atp_softc {
-	device_t               sc_dev;
-	struct usb_device     *sc_usb_device;
-#define MODE_LENGTH 8
-	char                   sc_mode_bytes[MODE_LENGTH]; /* device mode */
-	struct mtx             sc_mutex; /* for synchronization */
-	struct usb_xfer       *sc_xfer[ATP_N_TRANSFER];
-	struct usb_fifo_sc     sc_fifo;
-
-	struct atp_dev_params *sc_params;
-
-	mousehw_t              sc_hw;
-	mousemode_t            sc_mode;
-	u_int                  sc_pollrate;
-	mousestatus_t          sc_status;
-	u_int                  sc_state;
-#define ATP_ENABLED            0x01
-#define ATP_ZOMBIES_EXIST      0x02
-#define ATP_DOUBLE_TAP_DRAG    0x04
-#define ATP_VALID              0x08
-
-	u_int                  sc_left_margin;
-	u_int                  sc_right_margin;
-
-	atp_stroke             sc_strokes[ATP_MAX_STROKES];
-	u_int                  sc_n_strokes;
-
-	int8_t                *sensor_data; /* from interrupt packet */
-	int                   *base_x;      /* base sensor readings */
-	int                   *base_y;
-	int                   *cur_x;       /* current sensor readings */
-	int                   *cur_y;
-	int                   *pressure_x;  /* computed pressures */
-	int                   *pressure_y;
+	device_t            sc_dev;
+	struct usb_device  *sc_usb_device;
+	struct mtx          sc_mutex; /* for synchronization */
+	struct usb_fifo_sc  sc_fifo;
+
+#define	MODE_LENGTH 8
+	char                sc_mode_bytes[MODE_LENGTH]; /* device mode */
+
+	trackpad_family_t   sc_family;
+	const void         *sc_params; /* device configuration */
+	sensor_data_interpreter_t sensor_data_interpreter;
+
+	mousehw_t           sc_hw;
+	mousemode_t         sc_mode;
+	mousestatus_t       sc_status;
+
+	u_int               sc_state;
+#define ATP_ENABLED          0x01
+#define ATP_ZOMBIES_EXIST    0x02
+#define ATP_DOUBLE_TAP_DRAG  0x04
+#define ATP_VALID            0x08
+
+	struct usb_xfer    *sc_xfer[ATP_N_TRANSFER];
+
+	u_int               sc_pollrate;
+	int                 sc_fflags;
+
+	atp_stroke_t        sc_strokes_data[ATP_MAX_STROKES];
+	TAILQ_HEAD(,atp_stroke) sc_stroke_free;
+	TAILQ_HEAD(,atp_stroke) sc_stroke_used;
+	u_int               sc_n_strokes;
 
-	u_int                  sc_idlecount; /* preceding idle interrupts */
-#define ATP_IDLENESS_THRESHOLD 10
+	struct callout	    sc_callout;
 
-	struct timeval         sc_reap_time;
-	struct timeval         sc_reap_ctime; /*ctime of siblings to be reaped*/
+	/*
+	 * button status. Set to non-zero if the mouse-button is physically
+	 * pressed. This state variable is exposed through softc to allow
+	 * reap_sibling_zombies to avoid registering taps while the trackpad
+	 * button is pressed.
+         */
+	uint8_t             sc_ibtn;
+
+	/*
+	 * Time when touch zombies were last reaped; useful for detecting
+	 * double-touch-n-drag.
+	 */
+	struct timeval      sc_touch_reap_time;
+
+	u_int	            sc_idlecount;
+
+	/* Regarding the data transferred from t-pad in USB INTR packets. */
+	u_int   sc_expected_sensor_data_len;
+	uint8_t sc_sensor_data[ATP_SENSOR_DATA_BUF_MAX] __aligned(4);
+
+	int      sc_cur_x[FG_MAX_XSENSORS];      /* current sensor readings */
+	int      sc_cur_y[FG_MAX_YSENSORS];
+	int      sc_base_x[FG_MAX_XSENSORS];     /* base sensor readings */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402232336.s1NNaWsX092656>