From owner-svn-src-head@FreeBSD.ORG Sun Feb 23 23:36:32 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id CCCAF192; Sun, 23 Feb 2014 23:36:32 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id B5C941225; Sun, 23 Feb 2014 23:36:32 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s1NNaWFq092658; Sun, 23 Feb 2014 23:36:32 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s1NNaWsX092656; Sun, 23 Feb 2014 23:36:32 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201402232336.s1NNaWsX092656@svn.freebsd.org> From: Hans Petter Selasky Date: Sun, 23 Feb 2014 23:36:32 +0000 (UTC) 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 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 23 Feb 2014 23:36:32 -0000 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 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 . +.\" Copyright (c) 2014 Rohit Grover . .\" 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 __FBSDID("$FreeBSD$"); +#include +#include #include +#include #include #include -#include +#include #include #include #include -#include +#include +#include #include #include #include #include #include -#include -#include #include #include #include #include + #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 ***