atp.c revision 199680
1199086Srpaulo/*- 2199086Srpaulo * Copyright (c) 2009 Rohit Grover 3199086Srpaulo * All rights reserved. 4199086Srpaulo * 5199086Srpaulo * Redistribution and use in source and binary forms, with or without 6199086Srpaulo * modification, are permitted provided that the following conditions 7199086Srpaulo * are met: 8199086Srpaulo * 1. Redistributions of source code must retain the above copyright 9199086Srpaulo * notice, this list of conditions and the following disclaimer. 10199086Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11199086Srpaulo * notice, this list of conditions and the following disclaimer in the 12199086Srpaulo * documentation and/or other materials provided with the distribution. 13199086Srpaulo * 14199086Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15199086Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16199086Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17199086Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18199086Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19199086Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20199086Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21199086Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22199086Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23199086Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24199086Srpaulo * SUCH DAMAGE. 25199086Srpaulo */ 26199086Srpaulo 27199086Srpaulo#include <sys/cdefs.h> 28199086Srpaulo__FBSDID("$FreeBSD: head/sys/dev/usb/input/atp.c 199680 2009-11-22 21:53:09Z thompsa $"); 29199086Srpaulo 30199086Srpaulo#include <sys/param.h> 31199086Srpaulo#include <sys/systm.h> 32199086Srpaulo#include <sys/kernel.h> 33199086Srpaulo#include <sys/malloc.h> 34199086Srpaulo#include <sys/module.h> 35199086Srpaulo#include <sys/lock.h> 36199086Srpaulo#include <sys/mutex.h> 37199086Srpaulo#include <sys/bus.h> 38199086Srpaulo#include <sys/conf.h> 39199086Srpaulo#include <sys/fcntl.h> 40199086Srpaulo#include <sys/file.h> 41199086Srpaulo#include <sys/selinfo.h> 42199086Srpaulo#include <sys/poll.h> 43199086Srpaulo#include <sys/sysctl.h> 44199086Srpaulo#include <sys/uio.h> 45199086Srpaulo 46199086Srpaulo#include <dev/usb/usb.h> 47199086Srpaulo#include <dev/usb/usbdi.h> 48199086Srpaulo#include <dev/usb/usbdi_util.h> 49199086Srpaulo#include <dev/usb/usbhid.h> 50199086Srpaulo#include "usbdevs.h" 51199086Srpaulo 52199086Srpaulo#define USB_DEBUG_VAR atp_debug 53199086Srpaulo#include <dev/usb/usb_debug.h> 54199086Srpaulo 55199086Srpaulo#include <sys/mouse.h> 56199086Srpaulo 57199086Srpaulo#define ATP_DRIVER_NAME "atp" 58199086Srpaulo 59199086Srpaulo/* 60199086Srpaulo * Driver specific options: the following options may be set by 61199086Srpaulo * `options' statements in the kernel configuration file. 62199086Srpaulo */ 63199086Srpaulo 64199086Srpaulo/* The multiplier used to translate sensor reported positions to mickeys. */ 65199086Srpaulo#ifndef ATP_SCALE_FACTOR 66199086Srpaulo#define ATP_SCALE_FACTOR 48 67199086Srpaulo#endif 68199086Srpaulo 69199086Srpaulo/* 70199086Srpaulo * This is the age (in microseconds) beyond which a touch is 71199086Srpaulo * considered to be a slide; and therefore a tap event isn't registered. 72199086Srpaulo */ 73199086Srpaulo#ifndef ATP_TOUCH_TIMEOUT 74199086Srpaulo#define ATP_TOUCH_TIMEOUT 125000 75199086Srpaulo#endif 76199086Srpaulo 77199086Srpaulo/* 78199086Srpaulo * A double-tap followed by a single-finger slide is treated as a 79199086Srpaulo * special gesture. The driver responds to this gesture by assuming a 80199086Srpaulo * virtual button-press for the lifetime of the slide. The following 81199086Srpaulo * threshold is the maximum time gap (in microseconds) between the two 82199086Srpaulo * tap events preceding the slide for such a gesture. 83199086Srpaulo */ 84199086Srpaulo#ifndef ATP_DOUBLE_TAP_N_DRAG_THRESHOLD 85199086Srpaulo#define ATP_DOUBLE_TAP_N_DRAG_THRESHOLD 200000 86199086Srpaulo#endif 87199086Srpaulo 88199086Srpaulo/* 89199086Srpaulo * The device provides us only with pressure readings from an array of 90199086Srpaulo * X and Y sensors; for our algorithms, we need to interpret groups 91199086Srpaulo * (typically pairs) of X and Y readings as being related to a single 92199086Srpaulo * finger stroke. We can relate X and Y readings based on their times 93199086Srpaulo * of incidence. The coincidence window should be at least 10000us 94199086Srpaulo * since it is used against values from getmicrotime(), which has a 95199086Srpaulo * precision of around 10ms. 96199086Srpaulo */ 97199086Srpaulo#ifndef ATP_COINCIDENCE_THRESHOLD 98199086Srpaulo#define ATP_COINCIDENCE_THRESHOLD 40000 /* unit: microseconds */ 99199086Srpaulo#if ATP_COINCIDENCE_THRESHOLD > 100000 100199086Srpaulo#error "ATP_COINCIDENCE_THRESHOLD too large" 101199086Srpaulo#endif 102199086Srpaulo#endif /* #ifndef ATP_COINCIDENCE_THRESHOLD */ 103199086Srpaulo 104199086Srpaulo/* 105199086Srpaulo * The wait duration (in microseconds) after losing a touch contact 106199086Srpaulo * before zombied strokes are reaped and turned into button events. 107199086Srpaulo */ 108199086Srpaulo#define ATP_ZOMBIE_STROKE_REAP_WINDOW 50000 109199086Srpaulo#if ATP_ZOMBIE_STROKE_REAP_WINDOW > 100000 110199086Srpaulo#error "ATP_ZOMBIE_STROKE_REAP_WINDOW too large" 111199086Srpaulo#endif 112199086Srpaulo 113199086Srpaulo/* end of driver specific options */ 114199086Srpaulo 115199086Srpaulo 116199086Srpaulo/* Tunables */ 117199086SrpauloSYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB atp"); 118199086Srpaulo 119199086Srpaulo#if USB_DEBUG 120199086Srpauloenum atp_log_level { 121199086Srpaulo ATP_LLEVEL_DISABLED = 0, 122199086Srpaulo ATP_LLEVEL_ERROR, 123199086Srpaulo ATP_LLEVEL_DEBUG, /* for troubleshooting */ 124199086Srpaulo ATP_LLEVEL_INFO, /* for diagnostics */ 125199086Srpaulo}; 126199086Srpaulostatic int atp_debug = ATP_LLEVEL_ERROR; /* the default is to only log errors */ 127199086SrpauloSYSCTL_INT(_hw_usb_atp, OID_AUTO, debug, CTLFLAG_RW, 128199086Srpaulo &atp_debug, ATP_LLEVEL_ERROR, "ATP debug level"); 129199086Srpaulo#endif /* #if USB_DEBUG */ 130199086Srpaulo 131199086Srpaulostatic u_int atp_touch_timeout = ATP_TOUCH_TIMEOUT; 132199086SrpauloSYSCTL_INT(_hw_usb_atp, OID_AUTO, touch_timeout, CTLFLAG_RW, &atp_touch_timeout, 133199086Srpaulo 125000, "age threshold (in micros) for a touch"); 134199086Srpaulo 135199086Srpaulostatic u_int atp_double_tap_threshold = ATP_DOUBLE_TAP_N_DRAG_THRESHOLD; 136199086SrpauloSYSCTL_INT(_hw_usb_atp, OID_AUTO, double_tap_threshold, CTLFLAG_RW, 137199086Srpaulo &atp_double_tap_threshold, ATP_DOUBLE_TAP_N_DRAG_THRESHOLD, 138199086Srpaulo "maximum time (in micros) between a double-tap"); 139199086Srpaulo 140199086Srpaulostatic u_int atp_mickeys_scale_factor = ATP_SCALE_FACTOR; 141199086Srpaulostatic int atp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS); 142199086SrpauloSYSCTL_PROC(_hw_usb_atp, OID_AUTO, scale_factor, CTLTYPE_UINT | CTLFLAG_RW, 143199086Srpaulo &atp_mickeys_scale_factor, sizeof(atp_mickeys_scale_factor), 144199086Srpaulo atp_sysctl_scale_factor_handler, "IU", "movement scale factor"); 145199086Srpaulo 146199086Srpaulostatic u_int atp_small_movement_threshold = ATP_SCALE_FACTOR >> 3; 147199086SrpauloSYSCTL_UINT(_hw_usb_atp, OID_AUTO, small_movement, CTLFLAG_RW, 148199086Srpaulo &atp_small_movement_threshold, ATP_SCALE_FACTOR >> 3, 149199086Srpaulo "the small movement black-hole for filtering noise"); 150199086Srpaulo/* 151199086Srpaulo * The movement threshold for a stroke; this is the maximum difference 152199086Srpaulo * in position which will be resolved as a continuation of a stroke 153199086Srpaulo * component. 154199086Srpaulo */ 155199086Srpaulostatic u_int atp_max_delta_mickeys = ((3 * ATP_SCALE_FACTOR) >> 1); 156199086SrpauloSYSCTL_UINT(_hw_usb_atp, OID_AUTO, max_delta_mickeys, CTLFLAG_RW, 157199086Srpaulo &atp_max_delta_mickeys, ((3 * ATP_SCALE_FACTOR) >> 1), 158199086Srpaulo "max. mickeys-delta which will match against an existing stroke"); 159199086Srpaulo/* 160199086Srpaulo * Strokes which accumulate at least this amount of absolute movement 161199086Srpaulo * from the aggregate of their components are considered as 162199086Srpaulo * slides. Unit: mickeys. 163199086Srpaulo */ 164199086Srpaulostatic u_int atp_slide_min_movement = (ATP_SCALE_FACTOR >> 3); 165199086SrpauloSYSCTL_UINT(_hw_usb_atp, OID_AUTO, slide_min_movement, CTLFLAG_RW, 166199086Srpaulo &atp_slide_min_movement, (ATP_SCALE_FACTOR >> 3), 167199086Srpaulo "strokes with at least this amt. of movement are considered slides"); 168199086Srpaulo 169199086Srpaulo/* 170199086Srpaulo * The minimum age of a stroke for it to be considered mature; this 171199086Srpaulo * helps filter movements (noise) from immature strokes. Units: interrupts. 172199086Srpaulo */ 173199086Srpaulostatic u_int atp_stroke_maturity_threshold = 2; 174199086SrpauloSYSCTL_UINT(_hw_usb_atp, OID_AUTO, stroke_maturity_threshold, CTLFLAG_RW, 175199086Srpaulo &atp_stroke_maturity_threshold, 2, 176199086Srpaulo "the minimum age of a stroke for it to be considered mature"); 177199086Srpaulo 178199086Srpaulo/* Accept pressure readings from sensors only if above this value. */ 179199086Srpaulostatic u_int atp_sensor_noise_threshold = 2; 180199086SrpauloSYSCTL_UINT(_hw_usb_atp, OID_AUTO, sensor_noise_threshold, CTLFLAG_RW, 181199086Srpaulo &atp_sensor_noise_threshold, 2, 182199086Srpaulo "accept pressure readings from sensors only if above this value"); 183199086Srpaulo 184199086Srpaulo/* Ignore pressure spans with cumulative press. below this value. */ 185199086Srpaulostatic u_int atp_pspan_min_cum_pressure = 10; 186199086SrpauloSYSCTL_UINT(_hw_usb_atp, OID_AUTO, pspan_min_cum_pressure, CTLFLAG_RW, 187199086Srpaulo &atp_pspan_min_cum_pressure, 10, 188199086Srpaulo "ignore pressure spans with cumulative press. below this value"); 189199086Srpaulo 190199086Srpaulo/* Maximum allowed width for pressure-spans.*/ 191199086Srpaulostatic u_int atp_pspan_max_width = 4; 192199086SrpauloSYSCTL_UINT(_hw_usb_atp, OID_AUTO, pspan_max_width, CTLFLAG_RW, 193199086Srpaulo &atp_pspan_max_width, 4, 194199086Srpaulo "maximum allowed width (in sensors) for pressure-spans"); 195199086Srpaulo 196199151Snwhitehorn/* We support three payload protocols */ 197199151Snwhitehorntypedef enum { 198199151Snwhitehorn ATP_PROT_GEYSER1, 199199151Snwhitehorn ATP_PROT_GEYSER2, 200199151Snwhitehorn ATP_PROT_GEYSER3, 201199151Snwhitehorn} atp_protocol; 202199086Srpaulo 203199086Srpaulo/* Define the various flavours of devices supported by this driver. */ 204199086Srpauloenum { 205199086Srpaulo ATP_DEV_PARAMS_0, 206199151Snwhitehorn ATP_DEV_PARAMS_PBOOK, 207199151Snwhitehorn ATP_DEV_PARAMS_PBOOK_15A, 208199151Snwhitehorn ATP_DEV_PARAMS_PBOOK_17, 209199086Srpaulo ATP_N_DEV_PARAMS 210199086Srpaulo}; 211199086Srpaulostruct atp_dev_params { 212199086Srpaulo u_int data_len; /* for sensor data */ 213199086Srpaulo u_int n_xsensors; 214199086Srpaulo u_int n_ysensors; 215199151Snwhitehorn atp_protocol prot; 216199086Srpaulo} atp_dev_params[ATP_N_DEV_PARAMS] = { 217199086Srpaulo [ATP_DEV_PARAMS_0] = { 218199086Srpaulo .data_len = 64, 219199086Srpaulo .n_xsensors = 20, 220199151Snwhitehorn .n_ysensors = 10, 221199151Snwhitehorn .prot = ATP_PROT_GEYSER3 222199086Srpaulo }, 223199151Snwhitehorn [ATP_DEV_PARAMS_PBOOK] = { 224199151Snwhitehorn .data_len = 81, 225199151Snwhitehorn .n_xsensors = 16, 226199151Snwhitehorn .n_ysensors = 16, 227199151Snwhitehorn .prot = ATP_PROT_GEYSER1 228199151Snwhitehorn }, 229199151Snwhitehorn [ATP_DEV_PARAMS_PBOOK_15A] = { 230199151Snwhitehorn .data_len = 64, 231199151Snwhitehorn .n_xsensors = 15, 232199151Snwhitehorn .n_ysensors = 9, 233199151Snwhitehorn .prot = ATP_PROT_GEYSER2 234199151Snwhitehorn }, 235199151Snwhitehorn [ATP_DEV_PARAMS_PBOOK_17] = { 236199151Snwhitehorn .data_len = 81, 237199151Snwhitehorn .n_xsensors = 26, 238199151Snwhitehorn .n_ysensors = 16, 239199151Snwhitehorn .prot = ATP_PROT_GEYSER1 240199151Snwhitehorn }, 241199086Srpaulo}; 242199086Srpaulo 243199086Srpaulostatic const struct usb_device_id atp_devs[] = { 244199086Srpaulo /* Core Duo MacBook & MacBook Pro */ 245199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x0217, ATP_DEV_PARAMS_0) }, 246199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x0218, ATP_DEV_PARAMS_0) }, 247199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x0219, ATP_DEV_PARAMS_0) }, 248199086Srpaulo 249199086Srpaulo /* Core2 Duo MacBook & MacBook Pro */ 250199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x021a, ATP_DEV_PARAMS_0) }, 251199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x021b, ATP_DEV_PARAMS_0) }, 252199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x021c, ATP_DEV_PARAMS_0) }, 253199086Srpaulo 254199086Srpaulo /* Core2 Duo MacBook3,1 */ 255199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x0229, ATP_DEV_PARAMS_0) }, 256199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x022a, ATP_DEV_PARAMS_0) }, 257199086Srpaulo { USB_VPI(USB_VENDOR_APPLE, 0x022b, ATP_DEV_PARAMS_0) }, 258199151Snwhitehorn 259199151Snwhitehorn /* 12 inch PowerBook and iBook */ 260199151Snwhitehorn { USB_VPI(USB_VENDOR_APPLE, 0x030a, ATP_DEV_PARAMS_PBOOK) }, 261199151Snwhitehorn { USB_VPI(USB_VENDOR_APPLE, 0x030b, ATP_DEV_PARAMS_PBOOK) }, 262199151Snwhitehorn 263199151Snwhitehorn /* 15 inch PowerBook */ 264199151Snwhitehorn { USB_VPI(USB_VENDOR_APPLE, 0x020e, ATP_DEV_PARAMS_PBOOK) }, 265199151Snwhitehorn { USB_VPI(USB_VENDOR_APPLE, 0x020f, ATP_DEV_PARAMS_PBOOK) }, 266199151Snwhitehorn { USB_VPI(USB_VENDOR_APPLE, 0x0215, ATP_DEV_PARAMS_PBOOK_15A) }, 267199151Snwhitehorn 268199151Snwhitehorn /* 17 inch PowerBook */ 269199151Snwhitehorn { USB_VPI(USB_VENDOR_APPLE, 0x020d, ATP_DEV_PARAMS_PBOOK_17) }, 270199151Snwhitehorn 271199086Srpaulo}; 272199086Srpaulo 273199086Srpaulo/* 274199086Srpaulo * The following structure captures the state of a pressure span along 275199086Srpaulo * an axis. Each contact with the touchpad results in separate 276199086Srpaulo * pressure spans along the two axes. 277199086Srpaulo */ 278199086Srpaulotypedef struct atp_pspan { 279199086Srpaulo u_int width; /* in units of sensors */ 280199086Srpaulo u_int cum; /* cumulative compression (from all sensors) */ 281199086Srpaulo u_int cog; /* center of gravity */ 282199086Srpaulo u_int loc; /* location (scaled using the mickeys factor) */ 283199086Srpaulo boolean_t matched; /* to track pspans as they match against strokes. */ 284199086Srpaulo} atp_pspan; 285199086Srpaulo 286199086Srpaulotypedef enum atp_stroke_type { 287199086Srpaulo ATP_STROKE_TOUCH, 288199086Srpaulo ATP_STROKE_SLIDE, 289199086Srpaulo} atp_stroke_type; 290199086Srpaulo 291199086Srpaulo#define ATP_MAX_PSPANS_PER_AXIS 3 292199086Srpaulo 293199086Srpaulotypedef struct atp_stroke_component { 294199086Srpaulo /* Fields encapsulating the pressure-span. */ 295199086Srpaulo u_int loc; /* location (scaled) */ 296199086Srpaulo u_int cum_pressure; /* cumulative compression */ 297199086Srpaulo u_int max_cum_pressure; /* max cumulative compression */ 298199086Srpaulo boolean_t matched; /*to track components as they match against pspans.*/ 299199086Srpaulo 300199086Srpaulo /* Fields containing information about movement. */ 301199086Srpaulo int delta_mickeys; /* change in location (un-smoothened movement)*/ 302199086Srpaulo int pending; /* cum. of pending short movements */ 303199086Srpaulo int movement; /* current smoothened movement */ 304199086Srpaulo} atp_stroke_component; 305199086Srpaulo 306199086Srpaulotypedef enum atp_axis { 307199086Srpaulo X = 0, 308199086Srpaulo Y = 1 309199086Srpaulo} atp_axis; 310199086Srpaulo 311199086Srpaulo#define ATP_MAX_STROKES (2 * ATP_MAX_PSPANS_PER_AXIS) 312199086Srpaulo 313199086Srpaulo/* 314199086Srpaulo * The following structure captures a finger contact with the 315199086Srpaulo * touchpad. A stroke comprises two p-span components and some state. 316199086Srpaulo */ 317199086Srpaulotypedef struct atp_stroke { 318199086Srpaulo atp_stroke_type type; 319199086Srpaulo struct timeval ctime; /* create time; for coincident siblings. */ 320199086Srpaulo u_int age; /* 321199086Srpaulo * Unit: interrupts; we maintain 322199086Srpaulo * this value in addition to 323199086Srpaulo * 'ctime' in order to avoid the 324199086Srpaulo * expensive call to microtime() 325199086Srpaulo * at every interrupt. 326199086Srpaulo */ 327199086Srpaulo 328199086Srpaulo atp_stroke_component components[2]; 329199086Srpaulo u_int velocity_squared; /* 330199086Srpaulo * Average magnitude (squared) 331199086Srpaulo * of recent velocity. 332199086Srpaulo */ 333199086Srpaulo u_int cum_movement; /* cum. absolute movement so far */ 334199086Srpaulo 335199086Srpaulo uint32_t flags; /* the state of this stroke */ 336199086Srpaulo#define ATSF_ZOMBIE 0x1 337199086Srpaulo} atp_stroke; 338199086Srpaulo 339199086Srpaulo#define ATP_FIFO_BUF_SIZE 8 /* bytes */ 340199086Srpaulo#define ATP_FIFO_QUEUE_MAXLEN 50 /* units */ 341199086Srpaulo 342199086Srpauloenum { 343199086Srpaulo ATP_INTR_DT, 344199680Sthompsa ATP_RESET, 345199086Srpaulo ATP_N_TRANSFER, 346199086Srpaulo}; 347199086Srpaulo 348199086Srpaulostruct atp_softc { 349199086Srpaulo device_t sc_dev; 350199086Srpaulo struct usb_device *sc_usb_device; 351199086Srpaulo#define MODE_LENGTH 8 352199086Srpaulo char sc_mode_bytes[MODE_LENGTH]; /* device mode */ 353199086Srpaulo struct mtx sc_mutex; /* for synchronization */ 354199086Srpaulo struct usb_xfer *sc_xfer[ATP_N_TRANSFER]; 355199086Srpaulo struct usb_fifo_sc sc_fifo; 356199086Srpaulo 357199086Srpaulo struct atp_dev_params *sc_params; 358199086Srpaulo 359199086Srpaulo mousehw_t sc_hw; 360199086Srpaulo mousemode_t sc_mode; 361199086Srpaulo u_int sc_pollrate; 362199086Srpaulo mousestatus_t sc_status; 363199086Srpaulo u_int sc_state; 364199086Srpaulo#define ATP_ENABLED 0x01 365199086Srpaulo#define ATP_ZOMBIES_EXIST 0x02 366199086Srpaulo#define ATP_DOUBLE_TAP_DRAG 0x04 367199151Snwhitehorn#define ATP_VALID 0x08 368199086Srpaulo 369199086Srpaulo u_int sc_left_margin; 370199086Srpaulo u_int sc_right_margin; 371199086Srpaulo 372199086Srpaulo atp_stroke sc_strokes[ATP_MAX_STROKES]; 373199086Srpaulo u_int sc_n_strokes; 374199086Srpaulo 375199086Srpaulo int8_t *sensor_data; /* from interrupt packet */ 376199086Srpaulo int *base_x; /* base sensor readings */ 377199086Srpaulo int *base_y; 378199086Srpaulo int *cur_x; /* current sensor readings */ 379199086Srpaulo int *cur_y; 380199086Srpaulo int *pressure_x; /* computed pressures */ 381199086Srpaulo int *pressure_y; 382199086Srpaulo 383199086Srpaulo u_int sc_idlecount; /* preceding idle interrupts */ 384199086Srpaulo#define ATP_IDLENESS_THRESHOLD 10 385199086Srpaulo 386199086Srpaulo struct timeval sc_reap_time; 387199086Srpaulo struct timeval sc_reap_ctime; /*ctime of siblings to be reaped*/ 388199086Srpaulo}; 389199086Srpaulo 390199086Srpaulo/* 391199086Srpaulo * The last byte of the sensor data contains status bits; the 392199086Srpaulo * following values define the meanings of these bits. 393199086Srpaulo */ 394199086Srpauloenum atp_status_bits { 395199086Srpaulo ATP_STATUS_BUTTON = (uint8_t)0x01, /* The button was pressed */ 396199086Srpaulo ATP_STATUS_BASE_UPDATE = (uint8_t)0x04, /* Data from an untouched pad.*/ 397199086Srpaulo}; 398199086Srpaulo 399199086Srpaulotypedef enum interface_mode { 400199086Srpaulo RAW_SENSOR_MODE = (uint8_t)0x04, 401199086Srpaulo HID_MODE = (uint8_t)0x08 402199086Srpaulo} interface_mode; 403199086Srpaulo 404199086Srpaulo/* 405199086Srpaulo * function prototypes 406199086Srpaulo */ 407199086Srpaulostatic usb_fifo_cmd_t atp_start_read; 408199086Srpaulostatic usb_fifo_cmd_t atp_stop_read; 409199086Srpaulostatic usb_fifo_open_t atp_open; 410199086Srpaulostatic usb_fifo_close_t atp_close; 411199086Srpaulostatic usb_fifo_ioctl_t atp_ioctl; 412199086Srpaulo 413199086Srpaulostatic struct usb_fifo_methods atp_fifo_methods = { 414199086Srpaulo .f_open = &atp_open, 415199086Srpaulo .f_close = &atp_close, 416199086Srpaulo .f_ioctl = &atp_ioctl, 417199086Srpaulo .f_start_read = &atp_start_read, 418199086Srpaulo .f_stop_read = &atp_stop_read, 419199086Srpaulo .basename[0] = ATP_DRIVER_NAME, 420199086Srpaulo}; 421199086Srpaulo 422199086Srpaulo/* device initialization and shutdown */ 423199086Srpaulostatic usb_error_t atp_req_get_report(struct usb_device *udev, void *data); 424199086Srpaulostatic int atp_set_device_mode(device_t dev, interface_mode mode); 425199680Sthompsastatic void atp_reset_callback(struct usb_xfer *, usb_error_t); 426199086Srpaulostatic int atp_enable(struct atp_softc *sc); 427199086Srpaulostatic void atp_disable(struct atp_softc *sc); 428199086Srpaulostatic int atp_softc_populate(struct atp_softc *); 429199086Srpaulostatic void atp_softc_unpopulate(struct atp_softc *); 430199086Srpaulo 431199086Srpaulo/* sensor interpretation */ 432199151Snwhitehornstatic __inline void atp_interpret_sensor_data(const int8_t *, u_int, atp_axis, 433199151Snwhitehorn int *, atp_protocol); 434199086Srpaulostatic __inline void atp_get_pressures(int *, const int *, const int *, int); 435199086Srpaulostatic void atp_detect_pspans(int *, u_int, u_int, atp_pspan *, 436199086Srpaulo u_int *); 437199086Srpaulo 438199086Srpaulo/* movement detection */ 439199086Srpaulostatic boolean_t atp_match_stroke_component(atp_stroke_component *, 440199086Srpaulo const atp_pspan *); 441199086Srpaulostatic void atp_match_strokes_against_pspans(struct atp_softc *, 442199086Srpaulo atp_axis, atp_pspan *, u_int, u_int); 443199086Srpaulostatic boolean_t atp_update_strokes(struct atp_softc *, 444199086Srpaulo atp_pspan *, u_int, atp_pspan *, u_int); 445199086Srpaulostatic __inline void atp_add_stroke(struct atp_softc *, const atp_pspan *, 446199086Srpaulo const atp_pspan *); 447199086Srpaulostatic void atp_add_new_strokes(struct atp_softc *, atp_pspan *, 448199086Srpaulo u_int, atp_pspan *, u_int); 449199086Srpaulostatic void atp_advance_stroke_state(struct atp_softc *, 450199086Srpaulo atp_stroke *, boolean_t *); 451199086Srpaulostatic void atp_terminate_stroke(struct atp_softc *, u_int); 452199086Srpaulostatic __inline boolean_t atp_stroke_has_small_movement(const atp_stroke *); 453199086Srpaulostatic __inline void atp_update_pending_mickeys(atp_stroke_component *); 454199086Srpaulostatic void atp_compute_smoothening_scale_ratio(atp_stroke *, int *, 455199086Srpaulo int *); 456199086Srpaulostatic boolean_t atp_compute_stroke_movement(atp_stroke *); 457199086Srpaulo 458199086Srpaulo/* tap detection */ 459199086Srpaulostatic __inline void atp_setup_reap_time(struct atp_softc *, struct timeval *); 460199086Srpaulostatic void atp_reap_zombies(struct atp_softc *, u_int *, u_int *); 461199086Srpaulo 462199086Srpaulo/* updating fifo */ 463199086Srpaulostatic void atp_reset_buf(struct atp_softc *sc); 464199086Srpaulostatic void atp_add_to_queue(struct atp_softc *, int, int, uint32_t); 465199086Srpaulo 466199086Srpaulo 467199086Srpaulousb_error_t 468199086Srpauloatp_req_get_report(struct usb_device *udev, void *data) 469199086Srpaulo{ 470199086Srpaulo struct usb_device_request req; 471199086Srpaulo 472199086Srpaulo req.bmRequestType = UT_READ_CLASS_INTERFACE; 473199086Srpaulo req.bRequest = UR_GET_REPORT; 474199086Srpaulo USETW2(req.wValue, (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */); 475199086Srpaulo USETW(req.wIndex, 0); 476199086Srpaulo USETW(req.wLength, MODE_LENGTH); 477199086Srpaulo 478199086Srpaulo return (usbd_do_request(udev, NULL /* mutex */, &req, data)); 479199086Srpaulo} 480199086Srpaulo 481199086Srpaulostatic int 482199086Srpauloatp_set_device_mode(device_t dev, interface_mode mode) 483199086Srpaulo{ 484199086Srpaulo struct atp_softc *sc; 485199086Srpaulo usb_device_request_t req; 486199086Srpaulo usb_error_t err; 487199086Srpaulo 488199086Srpaulo if ((mode != RAW_SENSOR_MODE) && (mode != HID_MODE)) 489199086Srpaulo return (ENXIO); 490199086Srpaulo 491199086Srpaulo sc = device_get_softc(dev); 492199086Srpaulo 493199086Srpaulo sc->sc_mode_bytes[0] = mode; 494199086Srpaulo req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 495199086Srpaulo req.bRequest = UR_SET_REPORT; 496199086Srpaulo USETW2(req.wValue, (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */); 497199086Srpaulo USETW(req.wIndex, 0); 498199086Srpaulo USETW(req.wLength, MODE_LENGTH); 499199086Srpaulo err = usbd_do_request(sc->sc_usb_device, NULL, &req, sc->sc_mode_bytes); 500199086Srpaulo if (err != USB_ERR_NORMAL_COMPLETION) 501199086Srpaulo return (ENXIO); 502199086Srpaulo 503199086Srpaulo return (0); 504199086Srpaulo} 505199086Srpaulo 506199680Sthompsavoid 507199680Sthompsaatp_reset_callback(struct usb_xfer *xfer, usb_error_t error) 508199680Sthompsa{ 509199680Sthompsa usb_device_request_t req; 510199680Sthompsa struct usb_page_cache *pc; 511199680Sthompsa struct atp_softc *sc = usbd_xfer_softc(xfer); 512199680Sthompsa 513199680Sthompsa switch (USB_GET_STATE(xfer)) { 514199680Sthompsa case USB_ST_SETUP: 515199680Sthompsa sc->sc_mode_bytes[0] = RAW_SENSOR_MODE; 516199680Sthompsa req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 517199680Sthompsa req.bRequest = UR_SET_REPORT; 518199680Sthompsa USETW2(req.wValue, 519199680Sthompsa (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */); 520199680Sthompsa USETW(req.wIndex, 0); 521199680Sthompsa USETW(req.wLength, MODE_LENGTH); 522199680Sthompsa 523199680Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 524199680Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 525199680Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 526199680Sthompsa usbd_copy_in(pc, 0, sc->sc_mode_bytes, MODE_LENGTH); 527199680Sthompsa 528199680Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 529199680Sthompsa usbd_xfer_set_frame_len(xfer, 1, MODE_LENGTH); 530199680Sthompsa usbd_xfer_set_frames(xfer, 2); 531199680Sthompsa usbd_transfer_submit(xfer); 532199680Sthompsa break; 533199680Sthompsa 534199680Sthompsa case USB_ST_TRANSFERRED: 535199680Sthompsa default: 536199680Sthompsa break; 537199680Sthompsa } 538199680Sthompsa} 539199680Sthompsa 540199086Srpaulostatic int 541199086Srpauloatp_enable(struct atp_softc *sc) 542199086Srpaulo{ 543199086Srpaulo /* Allocate the dynamic buffers */ 544199086Srpaulo if (atp_softc_populate(sc) != 0) { 545199086Srpaulo atp_softc_unpopulate(sc); 546199086Srpaulo return (ENOMEM); 547199086Srpaulo } 548199086Srpaulo 549199086Srpaulo /* reset status */ 550199086Srpaulo memset(sc->sc_strokes, 0, sizeof(sc->sc_strokes)); 551199086Srpaulo sc->sc_n_strokes = 0; 552199086Srpaulo memset(&sc->sc_status, 0, sizeof(sc->sc_status)); 553199086Srpaulo sc->sc_idlecount = 0; 554199086Srpaulo sc->sc_state |= ATP_ENABLED; 555199086Srpaulo 556199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "enabled atp\n"); 557199086Srpaulo return (0); 558199086Srpaulo} 559199086Srpaulo 560199086Srpaulostatic void 561199086Srpauloatp_disable(struct atp_softc *sc) 562199086Srpaulo{ 563199086Srpaulo atp_softc_unpopulate(sc); 564199086Srpaulo 565199151Snwhitehorn sc->sc_state &= ~(ATP_ENABLED | ATP_VALID); 566199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "disabled atp\n"); 567199086Srpaulo} 568199086Srpaulo 569199086Srpaulo/* Allocate dynamic memory for some fields in softc. */ 570199086Srpaulostatic int 571199086Srpauloatp_softc_populate(struct atp_softc *sc) 572199086Srpaulo{ 573199086Srpaulo const struct atp_dev_params *params = sc->sc_params; 574199086Srpaulo 575199086Srpaulo if (params == NULL) { 576199086Srpaulo DPRINTF("params uninitialized!\n"); 577199086Srpaulo return (ENXIO); 578199086Srpaulo } 579199086Srpaulo if (params->data_len) { 580199086Srpaulo sc->sensor_data = malloc(params->data_len * sizeof(int8_t), 581199086Srpaulo M_USB, M_WAITOK); 582199086Srpaulo if (sc->sensor_data == NULL) { 583199086Srpaulo DPRINTF("mem for sensor_data\n"); 584199086Srpaulo return (ENXIO); 585199086Srpaulo } 586199086Srpaulo } 587199086Srpaulo 588199086Srpaulo if (params->n_xsensors != 0) { 589199086Srpaulo sc->base_x = malloc(params->n_xsensors * sizeof(*(sc->base_x)), 590199086Srpaulo M_USB, M_WAITOK); 591199086Srpaulo if (sc->base_x == NULL) { 592199086Srpaulo DPRINTF("mem for sc->base_x\n"); 593199086Srpaulo return (ENXIO); 594199086Srpaulo } 595199086Srpaulo 596199086Srpaulo sc->cur_x = malloc(params->n_xsensors * sizeof(*(sc->cur_x)), 597199086Srpaulo M_USB, M_WAITOK); 598199086Srpaulo if (sc->cur_x == NULL) { 599199086Srpaulo DPRINTF("mem for sc->cur_x\n"); 600199086Srpaulo return (ENXIO); 601199086Srpaulo } 602199086Srpaulo 603199086Srpaulo sc->pressure_x = 604199086Srpaulo malloc(params->n_xsensors * sizeof(*(sc->pressure_x)), 605199086Srpaulo M_USB, M_WAITOK); 606199086Srpaulo if (sc->pressure_x == NULL) { 607199086Srpaulo DPRINTF("mem. for pressure_x\n"); 608199086Srpaulo return (ENXIO); 609199086Srpaulo } 610199086Srpaulo } 611199086Srpaulo 612199086Srpaulo if (params->n_ysensors != 0) { 613199086Srpaulo sc->base_y = malloc(params->n_ysensors * sizeof(*(sc->base_y)), 614199086Srpaulo M_USB, M_WAITOK); 615199086Srpaulo if (sc->base_y == NULL) { 616199086Srpaulo DPRINTF("mem for base_y\n"); 617199086Srpaulo return (ENXIO); 618199086Srpaulo } 619199086Srpaulo 620199086Srpaulo sc->cur_y = malloc(params->n_ysensors * sizeof(*(sc->cur_y)), 621199086Srpaulo M_USB, M_WAITOK); 622199086Srpaulo if (sc->cur_y == NULL) { 623199086Srpaulo DPRINTF("mem for cur_y\n"); 624199086Srpaulo return (ENXIO); 625199086Srpaulo } 626199086Srpaulo 627199086Srpaulo sc->pressure_y = 628199086Srpaulo malloc(params->n_ysensors * sizeof(*(sc->pressure_y)), 629199086Srpaulo M_USB, M_WAITOK); 630199086Srpaulo if (sc->pressure_y == NULL) { 631199086Srpaulo DPRINTF("mem. for pressure_y\n"); 632199086Srpaulo return (ENXIO); 633199086Srpaulo } 634199086Srpaulo } 635199086Srpaulo 636199086Srpaulo return (0); 637199086Srpaulo} 638199086Srpaulo 639199086Srpaulo/* Free dynamic memory allocated for some fields in softc. */ 640199086Srpaulostatic void 641199086Srpauloatp_softc_unpopulate(struct atp_softc *sc) 642199086Srpaulo{ 643199086Srpaulo const struct atp_dev_params *params = sc->sc_params; 644199086Srpaulo 645199086Srpaulo if (params == NULL) { 646199086Srpaulo return; 647199086Srpaulo } 648199086Srpaulo if (params->n_xsensors != 0) { 649199086Srpaulo if (sc->base_x != NULL) { 650199086Srpaulo free(sc->base_x, M_USB); 651199086Srpaulo sc->base_x = NULL; 652199086Srpaulo } 653199086Srpaulo 654199086Srpaulo if (sc->cur_x != NULL) { 655199086Srpaulo free(sc->cur_x, M_USB); 656199086Srpaulo sc->cur_x = NULL; 657199086Srpaulo } 658199086Srpaulo 659199086Srpaulo if (sc->pressure_x != NULL) { 660199086Srpaulo free(sc->pressure_x, M_USB); 661199086Srpaulo sc->pressure_x = NULL; 662199086Srpaulo } 663199086Srpaulo } 664199086Srpaulo if (params->n_ysensors != 0) { 665199086Srpaulo if (sc->base_y != NULL) { 666199086Srpaulo free(sc->base_y, M_USB); 667199086Srpaulo sc->base_y = NULL; 668199086Srpaulo } 669199086Srpaulo 670199086Srpaulo if (sc->cur_y != NULL) { 671199086Srpaulo free(sc->cur_y, M_USB); 672199086Srpaulo sc->cur_y = NULL; 673199086Srpaulo } 674199086Srpaulo 675199086Srpaulo if (sc->pressure_y != NULL) { 676199086Srpaulo free(sc->pressure_y, M_USB); 677199086Srpaulo sc->pressure_y = NULL; 678199086Srpaulo } 679199086Srpaulo } 680199086Srpaulo if (sc->sensor_data != NULL) { 681199086Srpaulo free(sc->sensor_data, M_USB); 682199086Srpaulo sc->sensor_data = NULL; 683199086Srpaulo } 684199086Srpaulo} 685199086Srpaulo 686199086Srpaulo/* 687199086Srpaulo * Interpret the data from the X and Y pressure sensors. This function 688199086Srpaulo * is called separately for the X and Y sensor arrays. The data in the 689199086Srpaulo * USB packet is laid out in the following manner: 690199086Srpaulo * 691199086Srpaulo * sensor_data: 692199086Srpaulo * --,--,Y1,Y2,--,Y3,Y4,--,Y5,...,Y10, ... X1,X2,--,X3,X4 693199086Srpaulo * indices: 0 1 2 3 4 5 6 7 8 ... 15 ... 20 21 22 23 24 694199086Srpaulo * 695199086Srpaulo * '--' (in the above) indicates that the value is unimportant. 696199086Srpaulo * 697199086Srpaulo * Information about the above layout was obtained from the 698199086Srpaulo * implementation of the AppleTouch driver in Linux. 699199086Srpaulo * 700199086Srpaulo * parameters: 701199086Srpaulo * sensor_data 702199086Srpaulo * raw sensor data from the USB packet. 703199086Srpaulo * num 704199086Srpaulo * The number of elements in the array 'arr'. 705199151Snwhitehorn * axis 706199151Snwhitehorn * Axis of data to fetch 707199086Srpaulo * arr 708199086Srpaulo * The array to be initialized with the readings. 709199151Snwhitehorn * prot 710199151Snwhitehorn * The protocol to use to interpret the data 711199086Srpaulo */ 712199086Srpaulostatic __inline void 713199151Snwhitehornatp_interpret_sensor_data(const int8_t *sensor_data, u_int num, atp_axis axis, 714199151Snwhitehorn int *arr, atp_protocol prot) 715199086Srpaulo{ 716199086Srpaulo u_int i; 717199086Srpaulo u_int di; /* index into sensor data */ 718199086Srpaulo 719199151Snwhitehorn switch (prot) { 720199151Snwhitehorn case ATP_PROT_GEYSER1: 721199151Snwhitehorn /* 722199151Snwhitehorn * For Geyser 1, the sensors are laid out in pairs 723199151Snwhitehorn * every 5 bytes. 724199151Snwhitehorn */ 725199151Snwhitehorn for (i = 0, di = (axis == Y) ? 1 : 2; i < 8; di += 5, i++) { 726199151Snwhitehorn arr[i] = sensor_data[di]; 727199151Snwhitehorn arr[i+8] = sensor_data[di+2]; 728199151Snwhitehorn if (axis == X && num > 16) 729199151Snwhitehorn arr[i+16] = sensor_data[di+40]; 730199151Snwhitehorn } 731199151Snwhitehorn 732199151Snwhitehorn break; 733199151Snwhitehorn case ATP_PROT_GEYSER2: 734199151Snwhitehorn case ATP_PROT_GEYSER3: 735199151Snwhitehorn for (i = 0, di = (axis == Y) ? 2 : 20; i < num; /* empty */ ) { 736199151Snwhitehorn arr[i++] = sensor_data[di++]; 737199151Snwhitehorn arr[i++] = sensor_data[di++]; 738199151Snwhitehorn di++; 739199151Snwhitehorn } 740199151Snwhitehorn break; 741199086Srpaulo } 742199086Srpaulo} 743199086Srpaulo 744199086Srpaulostatic __inline void 745199086Srpauloatp_get_pressures(int *p, const int *cur, const int *base, int n) 746199086Srpaulo{ 747199086Srpaulo int i; 748199086Srpaulo 749199086Srpaulo for (i = 0; i < n; i++) { 750199086Srpaulo p[i] = cur[i] - base[i]; 751199086Srpaulo if (p[i] > 127) 752199086Srpaulo p[i] -= 256; 753199086Srpaulo if (p[i] < -127) 754199086Srpaulo p[i] += 256; 755199086Srpaulo if (p[i] < 0) 756199086Srpaulo p[i] = 0; 757199086Srpaulo 758199086Srpaulo /* 759199086Srpaulo * Shave off pressures below the noise-pressure 760199086Srpaulo * threshold; this will reduce the contribution from 761199086Srpaulo * lower pressure readings. 762199086Srpaulo */ 763199086Srpaulo if (p[i] <= atp_sensor_noise_threshold) 764199086Srpaulo p[i] = 0; /* filter away noise */ 765199086Srpaulo else 766199086Srpaulo p[i] -= atp_sensor_noise_threshold; 767199086Srpaulo } 768199086Srpaulo} 769199086Srpaulo 770199086Srpaulostatic void 771199086Srpauloatp_detect_pspans(int *p, u_int num_sensors, 772199086Srpaulo u_int max_spans, /* max # of pspans permitted */ 773199086Srpaulo atp_pspan *spans, /* finger spans */ 774199086Srpaulo u_int *nspans_p) /* num spans detected */ 775199086Srpaulo{ 776199086Srpaulo u_int i; 777199086Srpaulo int maxp; /* max pressure seen within a span */ 778199086Srpaulo u_int num_spans = 0; 779199086Srpaulo 780199086Srpaulo enum atp_pspan_state { 781199086Srpaulo ATP_PSPAN_INACTIVE, 782199086Srpaulo ATP_PSPAN_INCREASING, 783199086Srpaulo ATP_PSPAN_DECREASING, 784199086Srpaulo } state; /* state of the pressure span */ 785199086Srpaulo 786199086Srpaulo /* 787199086Srpaulo * The following is a simple state machine to track 788199086Srpaulo * the phase of the pressure span. 789199086Srpaulo */ 790199086Srpaulo memset(spans, 0, max_spans * sizeof(atp_pspan)); 791199086Srpaulo maxp = 0; 792199086Srpaulo state = ATP_PSPAN_INACTIVE; 793199086Srpaulo for (i = 0; i < num_sensors; i++) { 794199086Srpaulo if (num_spans >= max_spans) 795199086Srpaulo break; 796199086Srpaulo 797199086Srpaulo if (p[i] == 0) { 798199086Srpaulo if (state == ATP_PSPAN_INACTIVE) { 799199086Srpaulo /* 800199086Srpaulo * There is no pressure information for this 801199086Srpaulo * sensor, and we aren't tracking a finger. 802199086Srpaulo */ 803199086Srpaulo continue; 804199086Srpaulo } else { 805199086Srpaulo state = ATP_PSPAN_INACTIVE; 806199086Srpaulo maxp = 0; 807199086Srpaulo num_spans++; 808199086Srpaulo } 809199086Srpaulo } else { 810199086Srpaulo switch (state) { 811199086Srpaulo case ATP_PSPAN_INACTIVE: 812199086Srpaulo state = ATP_PSPAN_INCREASING; 813199086Srpaulo maxp = p[i]; 814199086Srpaulo break; 815199086Srpaulo 816199086Srpaulo case ATP_PSPAN_INCREASING: 817199086Srpaulo if (p[i] > maxp) 818199086Srpaulo maxp = p[i]; 819199086Srpaulo else if (p[i] <= (maxp >> 1)) 820199086Srpaulo state = ATP_PSPAN_DECREASING; 821199086Srpaulo break; 822199086Srpaulo 823199086Srpaulo case ATP_PSPAN_DECREASING: 824199086Srpaulo if (p[i] > p[i - 1]) { 825199086Srpaulo /* 826199086Srpaulo * This is the beginning of 827199086Srpaulo * another span; change state 828199086Srpaulo * to give the appearance that 829199086Srpaulo * we're starting from an 830199086Srpaulo * inactive span, and then 831199086Srpaulo * re-process this reading in 832199086Srpaulo * the next iteration. 833199086Srpaulo */ 834199086Srpaulo num_spans++; 835199086Srpaulo state = ATP_PSPAN_INACTIVE; 836199086Srpaulo maxp = 0; 837199086Srpaulo i--; 838199086Srpaulo continue; 839199086Srpaulo } 840199086Srpaulo break; 841199086Srpaulo } 842199086Srpaulo 843199086Srpaulo /* Update the finger span with this reading. */ 844199086Srpaulo spans[num_spans].width++; 845199086Srpaulo spans[num_spans].cum += p[i]; 846199086Srpaulo spans[num_spans].cog += p[i] * (i + 1); 847199086Srpaulo } 848199086Srpaulo } 849199086Srpaulo if (state != ATP_PSPAN_INACTIVE) 850199086Srpaulo num_spans++; /* close the last finger span */ 851199086Srpaulo 852199086Srpaulo /* post-process the spans */ 853199086Srpaulo for (i = 0; i < num_spans; i++) { 854199086Srpaulo /* filter away unwanted pressure spans */ 855199086Srpaulo if ((spans[i].cum < atp_pspan_min_cum_pressure) || 856199086Srpaulo (spans[i].width > atp_pspan_max_width)) { 857199086Srpaulo if ((i + 1) < num_spans) { 858199086Srpaulo memcpy(&spans[i], &spans[i + 1], 859199086Srpaulo (num_spans - i - 1) * sizeof(atp_pspan)); 860199086Srpaulo i--; 861199086Srpaulo } 862199086Srpaulo num_spans--; 863199086Srpaulo continue; 864199086Srpaulo } 865199086Srpaulo 866199086Srpaulo /* compute this span's representative location */ 867199086Srpaulo spans[i].loc = spans[i].cog * atp_mickeys_scale_factor / 868199086Srpaulo spans[i].cum; 869199086Srpaulo 870199086Srpaulo spans[i].matched = FALSE; /* not yet matched against a stroke */ 871199086Srpaulo } 872199086Srpaulo 873199086Srpaulo *nspans_p = num_spans; 874199086Srpaulo} 875199086Srpaulo 876199086Srpaulo/* 877199086Srpaulo * Match a pressure-span against a stroke-component. If there is a 878199086Srpaulo * match, update the component's state and return TRUE. 879199086Srpaulo */ 880199086Srpaulostatic boolean_t 881199086Srpauloatp_match_stroke_component(atp_stroke_component *component, 882199086Srpaulo const atp_pspan *pspan) 883199086Srpaulo{ 884199086Srpaulo int delta_mickeys = pspan->loc - component->loc; 885199086Srpaulo 886199086Srpaulo if (abs(delta_mickeys) > atp_max_delta_mickeys) 887199086Srpaulo return (FALSE); /* the finger span is too far out; no match */ 888199086Srpaulo 889199086Srpaulo component->loc = pspan->loc; 890199086Srpaulo component->cum_pressure = pspan->cum; 891199086Srpaulo if (pspan->cum > component->max_cum_pressure) 892199086Srpaulo component->max_cum_pressure = pspan->cum; 893199086Srpaulo 894199086Srpaulo /* 895199086Srpaulo * If the cumulative pressure drops below a quarter of the max, 896199086Srpaulo * then disregard the component's movement. 897199086Srpaulo */ 898199086Srpaulo if (component->cum_pressure < (component->max_cum_pressure >> 2)) 899199086Srpaulo delta_mickeys = 0; 900199086Srpaulo 901199086Srpaulo component->delta_mickeys = delta_mickeys; 902199086Srpaulo return (TRUE); 903199086Srpaulo} 904199086Srpaulo 905199086Srpaulostatic void 906199086Srpauloatp_match_strokes_against_pspans(struct atp_softc *sc, atp_axis axis, 907199086Srpaulo atp_pspan *pspans, u_int n_pspans, u_int repeat_count) 908199086Srpaulo{ 909199086Srpaulo u_int i, j; 910199086Srpaulo u_int repeat_index = 0; 911199086Srpaulo 912199086Srpaulo /* Determine the index of the multi-span. */ 913199086Srpaulo if (repeat_count) { 914199086Srpaulo u_int cum = 0; 915199086Srpaulo for (i = 0; i < n_pspans; i++) { 916199086Srpaulo if (pspans[i].cum > cum) { 917199086Srpaulo repeat_index = i; 918199086Srpaulo cum = pspans[i].cum; 919199086Srpaulo } 920199086Srpaulo } 921199086Srpaulo } 922199086Srpaulo 923199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 924199086Srpaulo atp_stroke *stroke = &sc->sc_strokes[i]; 925199086Srpaulo if (stroke->components[axis].matched) 926199086Srpaulo continue; /* skip matched components */ 927199086Srpaulo 928199086Srpaulo for (j = 0; j < n_pspans; j++) { 929199086Srpaulo if (pspans[j].matched) 930199086Srpaulo continue; /* skip matched pspans */ 931199086Srpaulo 932199086Srpaulo if (atp_match_stroke_component( 933199086Srpaulo &stroke->components[axis], &pspans[j])) { 934199086Srpaulo /* There is a match. */ 935199086Srpaulo stroke->components[axis].matched = TRUE; 936199086Srpaulo 937199086Srpaulo /* Take care to repeat at the multi-span. */ 938199086Srpaulo if ((repeat_count > 0) && (j == repeat_index)) 939199086Srpaulo repeat_count--; 940199086Srpaulo else 941199086Srpaulo pspans[j].matched = TRUE; 942199086Srpaulo 943199086Srpaulo break; /* skip to the next stroke */ 944199086Srpaulo } 945199086Srpaulo } /* loop over pspans */ 946199086Srpaulo } /* loop over strokes */ 947199086Srpaulo} 948199086Srpaulo 949199086Srpaulo/* 950199086Srpaulo * Update strokes by matching against current pressure-spans. 951199086Srpaulo * Return TRUE if any movement is detected. 952199086Srpaulo */ 953199086Srpaulostatic boolean_t 954199086Srpauloatp_update_strokes(struct atp_softc *sc, atp_pspan *pspans_x, 955199086Srpaulo u_int n_xpspans, atp_pspan *pspans_y, u_int n_ypspans) 956199086Srpaulo{ 957199086Srpaulo u_int i, j; 958199086Srpaulo atp_stroke *stroke; 959199086Srpaulo boolean_t movement = FALSE; 960199086Srpaulo u_int repeat_count = 0; 961199086Srpaulo 962199086Srpaulo /* Reset X and Y components of all strokes as unmatched. */ 963199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 964199086Srpaulo stroke = &sc->sc_strokes[i]; 965199086Srpaulo stroke->components[X].matched = FALSE; 966199086Srpaulo stroke->components[Y].matched = FALSE; 967199086Srpaulo } 968199086Srpaulo 969199086Srpaulo /* 970199086Srpaulo * Usually, the X and Y pspans come in pairs (the common case 971199086Srpaulo * being a single pair). It is possible, however, that 972199086Srpaulo * multiple contacts resolve to a single pspan along an 973199086Srpaulo * axis, as illustrated in the following: 974199086Srpaulo * 975199086Srpaulo * F = finger-contact 976199086Srpaulo * 977199086Srpaulo * pspan pspan 978199086Srpaulo * +-----------------------+ 979199086Srpaulo * | . . | 980199086Srpaulo * | . . | 981199086Srpaulo * | . . | 982199086Srpaulo * | . . | 983199086Srpaulo * pspan |.........F......F | 984199086Srpaulo * | | 985199086Srpaulo * | | 986199086Srpaulo * | | 987199086Srpaulo * +-----------------------+ 988199086Srpaulo * 989199086Srpaulo * 990199086Srpaulo * The above case can be detected by a difference in the 991199086Srpaulo * number of X and Y pspans. When this happens, X and Y pspans 992199086Srpaulo * aren't easy to pair or match against strokes. 993199086Srpaulo * 994199086Srpaulo * When X and Y pspans differ in number, the axis with the 995199086Srpaulo * smaller number of pspans is regarded as having a repeating 996199086Srpaulo * pspan (or a multi-pspan)--in the above illustration, the 997199086Srpaulo * Y-axis has a repeating pspan. Our approach is to try to 998199086Srpaulo * match the multi-pspan repeatedly against strokes. The 999199086Srpaulo * difference between the number of X and Y pspans gives us a 1000199086Srpaulo * crude repeat_count for matching multi-pspans--i.e. the 1001199086Srpaulo * multi-pspan along the Y axis (above) has a repeat_count of 1. 1002199086Srpaulo */ 1003199086Srpaulo repeat_count = abs(n_xpspans - n_ypspans); 1004199086Srpaulo 1005199086Srpaulo atp_match_strokes_against_pspans(sc, X, pspans_x, n_xpspans, 1006199086Srpaulo (((repeat_count != 0) && ((n_xpspans < n_ypspans))) ? 1007199086Srpaulo repeat_count : 0)); 1008199086Srpaulo atp_match_strokes_against_pspans(sc, Y, pspans_y, n_ypspans, 1009199086Srpaulo (((repeat_count != 0) && (n_ypspans < n_xpspans)) ? 1010199086Srpaulo repeat_count : 0)); 1011199086Srpaulo 1012199086Srpaulo /* Update the state of strokes based on the above pspan matches. */ 1013199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1014199086Srpaulo stroke = &sc->sc_strokes[i]; 1015199086Srpaulo if (stroke->components[X].matched && 1016199086Srpaulo stroke->components[Y].matched) { 1017199086Srpaulo atp_advance_stroke_state(sc, stroke, &movement); 1018199086Srpaulo } else { 1019199086Srpaulo /* 1020199086Srpaulo * At least one component of this stroke 1021199086Srpaulo * didn't match against current pspans; 1022199086Srpaulo * terminate it. 1023199086Srpaulo */ 1024199086Srpaulo atp_terminate_stroke(sc, i); 1025199086Srpaulo } 1026199086Srpaulo } 1027199086Srpaulo 1028199086Srpaulo /* Add new strokes for pairs of unmatched pspans */ 1029199086Srpaulo for (i = 0; i < n_xpspans; i++) { 1030199086Srpaulo if (pspans_x[i].matched == FALSE) break; 1031199086Srpaulo } 1032199086Srpaulo for (j = 0; j < n_ypspans; j++) { 1033199086Srpaulo if (pspans_y[j].matched == FALSE) break; 1034199086Srpaulo } 1035199086Srpaulo if ((i < n_xpspans) && (j < n_ypspans)) { 1036199086Srpaulo#if USB_DEBUG 1037199086Srpaulo if (atp_debug >= ATP_LLEVEL_INFO) { 1038199086Srpaulo printf("unmatched pspans:"); 1039199086Srpaulo for (; i < n_xpspans; i++) { 1040199086Srpaulo if (pspans_x[i].matched) 1041199086Srpaulo continue; 1042199086Srpaulo printf(" X:[loc:%u,cum:%u]", 1043199086Srpaulo pspans_x[i].loc, pspans_x[i].cum); 1044199086Srpaulo } 1045199086Srpaulo for (; j < n_ypspans; j++) { 1046199086Srpaulo if (pspans_y[j].matched) 1047199086Srpaulo continue; 1048199086Srpaulo printf(" Y:[loc:%u,cum:%u]", 1049199086Srpaulo pspans_y[j].loc, pspans_y[j].cum); 1050199086Srpaulo } 1051199086Srpaulo printf("\n"); 1052199086Srpaulo } 1053199086Srpaulo#endif /* #if USB_DEBUG */ 1054199086Srpaulo if ((n_xpspans == 1) && (n_ypspans == 1)) 1055199086Srpaulo /* The common case of a single pair of new pspans. */ 1056199086Srpaulo atp_add_stroke(sc, &pspans_x[0], &pspans_y[0]); 1057199086Srpaulo else 1058199086Srpaulo atp_add_new_strokes(sc, 1059199086Srpaulo pspans_x, n_xpspans, 1060199086Srpaulo pspans_y, n_ypspans); 1061199086Srpaulo } 1062199086Srpaulo 1063199086Srpaulo#if USB_DEBUG 1064199086Srpaulo if (atp_debug >= ATP_LLEVEL_INFO) { 1065199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1066199086Srpaulo atp_stroke *stroke = &sc->sc_strokes[i]; 1067199086Srpaulo 1068199086Srpaulo printf(" %s%clc:%u,dm:%d,pnd:%d,mv:%d%c" 1069199086Srpaulo ",%clc:%u,dm:%d,pnd:%d,mv:%d%c", 1070199086Srpaulo (stroke->flags & ATSF_ZOMBIE) ? "zomb:" : "", 1071199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<', 1072199086Srpaulo stroke->components[X].loc, 1073199086Srpaulo stroke->components[X].delta_mickeys, 1074199086Srpaulo stroke->components[X].pending, 1075199086Srpaulo stroke->components[X].movement, 1076199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>', 1077199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<', 1078199086Srpaulo stroke->components[Y].loc, 1079199086Srpaulo stroke->components[Y].delta_mickeys, 1080199086Srpaulo stroke->components[Y].pending, 1081199086Srpaulo stroke->components[Y].movement, 1082199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>'); 1083199086Srpaulo } 1084199086Srpaulo if (sc->sc_n_strokes) 1085199086Srpaulo printf("\n"); 1086199086Srpaulo } 1087199086Srpaulo#endif /* #if USB_DEBUG */ 1088199086Srpaulo 1089199086Srpaulo return (movement); 1090199086Srpaulo} 1091199086Srpaulo 1092199086Srpaulo/* Initialize a stroke using a pressure-span. */ 1093199086Srpaulostatic __inline void 1094199086Srpauloatp_add_stroke(struct atp_softc *sc, const atp_pspan *pspan_x, 1095199086Srpaulo const atp_pspan *pspan_y) 1096199086Srpaulo{ 1097199086Srpaulo atp_stroke *stroke; 1098199086Srpaulo 1099199086Srpaulo if (sc->sc_n_strokes >= ATP_MAX_STROKES) 1100199086Srpaulo return; 1101199086Srpaulo stroke = &sc->sc_strokes[sc->sc_n_strokes]; 1102199086Srpaulo 1103199086Srpaulo memset(stroke, 0, sizeof(atp_stroke)); 1104199086Srpaulo 1105199086Srpaulo /* 1106199086Srpaulo * Strokes begin as potential touches. If a stroke survives 1107199086Srpaulo * longer than a threshold, or if it records significant 1108199086Srpaulo * cumulative movement, then it is considered a 'slide'. 1109199086Srpaulo */ 1110199086Srpaulo stroke->type = ATP_STROKE_TOUCH; 1111199086Srpaulo microtime(&stroke->ctime); 1112199086Srpaulo stroke->age = 1; /* Unit: interrupts */ 1113199086Srpaulo 1114199086Srpaulo stroke->components[X].loc = pspan_x->loc; 1115199086Srpaulo stroke->components[X].cum_pressure = pspan_x->cum; 1116199086Srpaulo stroke->components[X].max_cum_pressure = pspan_x->cum; 1117199086Srpaulo stroke->components[X].matched = TRUE; 1118199086Srpaulo 1119199086Srpaulo stroke->components[Y].loc = pspan_y->loc; 1120199086Srpaulo stroke->components[Y].cum_pressure = pspan_y->cum; 1121199086Srpaulo stroke->components[Y].max_cum_pressure = pspan_y->cum; 1122199086Srpaulo stroke->components[Y].matched = TRUE; 1123199086Srpaulo 1124199086Srpaulo sc->sc_n_strokes++; 1125199086Srpaulo if (sc->sc_n_strokes > 1) { 1126199086Srpaulo /* Reset double-tap-n-drag if we have more than one strokes. */ 1127199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1128199086Srpaulo } 1129199086Srpaulo 1130199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "[%u,%u], time: %u,%ld\n", 1131199086Srpaulo stroke->components[X].loc, 1132199086Srpaulo stroke->components[Y].loc, 1133199086Srpaulo (unsigned int)stroke->ctime.tv_sec, 1134199086Srpaulo (unsigned long int)stroke->ctime.tv_usec); 1135199086Srpaulo} 1136199086Srpaulo 1137199086Srpaulostatic void 1138199086Srpauloatp_add_new_strokes(struct atp_softc *sc, atp_pspan *pspans_x, 1139199086Srpaulo u_int n_xpspans, atp_pspan *pspans_y, u_int n_ypspans) 1140199086Srpaulo{ 1141199086Srpaulo int i, j; 1142199086Srpaulo atp_pspan spans[2][ATP_MAX_PSPANS_PER_AXIS]; 1143199086Srpaulo u_int nspans[2]; 1144199086Srpaulo 1145199086Srpaulo /* Copy unmatched pspans into the local arrays. */ 1146199086Srpaulo for (i = 0, nspans[X] = 0; i < n_xpspans; i++) { 1147199086Srpaulo if (pspans_x[i].matched == FALSE) { 1148199086Srpaulo spans[X][nspans[X]] = pspans_x[i]; 1149199086Srpaulo nspans[X]++; 1150199086Srpaulo } 1151199086Srpaulo } 1152199086Srpaulo for (j = 0, nspans[Y] = 0; j < n_ypspans; j++) { 1153199086Srpaulo if (pspans_y[j].matched == FALSE) { 1154199086Srpaulo spans[Y][nspans[Y]] = pspans_y[j]; 1155199086Srpaulo nspans[Y]++; 1156199086Srpaulo } 1157199086Srpaulo } 1158199086Srpaulo 1159199086Srpaulo if (nspans[X] == nspans[Y]) { 1160199086Srpaulo /* Create new strokes from pairs of unmatched pspans */ 1161199086Srpaulo for (i = 0, j = 0; (i < nspans[X]) && (j < nspans[Y]); i++, j++) 1162199086Srpaulo atp_add_stroke(sc, &spans[X][i], &spans[Y][j]); 1163199086Srpaulo } else { 1164199086Srpaulo u_int cum = 0; 1165199086Srpaulo atp_axis repeat_axis; /* axis with multi-pspans */ 1166199086Srpaulo u_int repeat_count; /* repeat count for the multi-pspan*/ 1167199086Srpaulo u_int repeat_index = 0; /* index of the multi-span */ 1168199086Srpaulo 1169199086Srpaulo repeat_axis = (nspans[X] > nspans[Y]) ? Y : X; 1170199086Srpaulo repeat_count = abs(nspans[X] - nspans[Y]); 1171199086Srpaulo for (i = 0; i < nspans[repeat_axis]; i++) { 1172199086Srpaulo if (spans[repeat_axis][i].cum > cum) { 1173199086Srpaulo repeat_index = i; 1174199086Srpaulo cum = spans[repeat_axis][i].cum; 1175199086Srpaulo } 1176199086Srpaulo } 1177199086Srpaulo 1178199086Srpaulo /* Create new strokes from pairs of unmatched pspans */ 1179199086Srpaulo i = 0, j = 0; 1180199086Srpaulo for (; (i < nspans[X]) && (j < nspans[Y]); i++, j++) { 1181199086Srpaulo atp_add_stroke(sc, &spans[X][i], &spans[Y][j]); 1182199086Srpaulo 1183199086Srpaulo /* Take care to repeat at the multi-pspan. */ 1184199086Srpaulo if (repeat_count > 0) { 1185199086Srpaulo if ((repeat_axis == X) && 1186199086Srpaulo (repeat_index == i)) { 1187199086Srpaulo i--; /* counter loop increment */ 1188199086Srpaulo repeat_count--; 1189199086Srpaulo } else if ((repeat_axis == Y) && 1190199086Srpaulo (repeat_index == j)) { 1191199086Srpaulo j--; /* counter loop increment */ 1192199086Srpaulo repeat_count--; 1193199086Srpaulo } 1194199086Srpaulo } 1195199086Srpaulo } 1196199086Srpaulo } 1197199086Srpaulo} 1198199086Srpaulo 1199199086Srpaulo/* 1200199086Srpaulo * Advance the state of this stroke--and update the out-parameter 1201199086Srpaulo * 'movement' as a side-effect. 1202199086Srpaulo */ 1203199086Srpaulovoid 1204199086Srpauloatp_advance_stroke_state(struct atp_softc *sc, atp_stroke *stroke, 1205199086Srpaulo boolean_t *movement) 1206199086Srpaulo{ 1207199086Srpaulo stroke->age++; 1208199086Srpaulo if (stroke->age <= atp_stroke_maturity_threshold) { 1209199086Srpaulo /* Avoid noise from immature strokes. */ 1210199086Srpaulo stroke->components[X].delta_mickeys = 0; 1211199086Srpaulo stroke->components[Y].delta_mickeys = 0; 1212199086Srpaulo } 1213199086Srpaulo 1214199086Srpaulo /* Revitalize stroke if it had previously been marked as a zombie. */ 1215199086Srpaulo if (stroke->flags & ATSF_ZOMBIE) 1216199086Srpaulo stroke->flags &= ~ATSF_ZOMBIE; 1217199086Srpaulo 1218199086Srpaulo if (atp_compute_stroke_movement(stroke)) 1219199086Srpaulo *movement = TRUE; 1220199086Srpaulo 1221199086Srpaulo /* Convert touch strokes to slides upon detecting movement or age. */ 1222199086Srpaulo if (stroke->type == ATP_STROKE_TOUCH) { 1223199086Srpaulo struct timeval tdiff; 1224199086Srpaulo 1225199086Srpaulo /* Compute the stroke's age. */ 1226199086Srpaulo getmicrotime(&tdiff); 1227199086Srpaulo if (timevalcmp(&tdiff, &stroke->ctime, >)) 1228199086Srpaulo timevalsub(&tdiff, &stroke->ctime); 1229199086Srpaulo else { 1230199086Srpaulo /* 1231199086Srpaulo * If we are here, it is because getmicrotime 1232199086Srpaulo * reported the current time as being behind 1233199086Srpaulo * the stroke's start time; getmicrotime can 1234199086Srpaulo * be imprecise. 1235199086Srpaulo */ 1236199086Srpaulo tdiff.tv_sec = 0; 1237199086Srpaulo tdiff.tv_usec = 0; 1238199086Srpaulo } 1239199086Srpaulo 1240199086Srpaulo if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) || 1241199086Srpaulo ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) && 1242199086Srpaulo (tdiff.tv_usec > atp_touch_timeout)) || 1243199086Srpaulo (stroke->cum_movement >= atp_slide_min_movement)) { 1244199086Srpaulo /* Switch this stroke to being a slide. */ 1245199086Srpaulo stroke->type = ATP_STROKE_SLIDE; 1246199086Srpaulo 1247199086Srpaulo /* Are we at the beginning of a double-click-n-drag? */ 1248199086Srpaulo if ((sc->sc_n_strokes == 1) && 1249199086Srpaulo ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) && 1250199086Srpaulo timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) { 1251199086Srpaulo struct timeval delta; 1252199086Srpaulo struct timeval window = { 1253199086Srpaulo atp_double_tap_threshold / 1000000, 1254199086Srpaulo atp_double_tap_threshold % 1000000 1255199086Srpaulo }; 1256199086Srpaulo 1257199086Srpaulo delta = stroke->ctime; 1258199086Srpaulo timevalsub(&delta, &sc->sc_reap_time); 1259199086Srpaulo if (timevalcmp(&delta, &window, <=)) 1260199086Srpaulo sc->sc_state |= ATP_DOUBLE_TAP_DRAG; 1261199086Srpaulo } 1262199086Srpaulo } 1263199086Srpaulo } 1264199086Srpaulo} 1265199086Srpaulo 1266199086Srpaulo/* 1267199086Srpaulo * Terminate a stroke. While SLIDE strokes are dropped, TOUCH strokes 1268199086Srpaulo * are retained as zombies so as to reap all their siblings together; 1269199086Srpaulo * this helps establish the number of fingers involved in the tap. 1270199086Srpaulo */ 1271199086Srpaulostatic void 1272199086Srpauloatp_terminate_stroke(struct atp_softc *sc, 1273199086Srpaulo u_int index) /* index of the stroke to be terminated */ 1274199086Srpaulo{ 1275199086Srpaulo atp_stroke *s = &sc->sc_strokes[index]; 1276199086Srpaulo 1277199086Srpaulo if (s->flags & ATSF_ZOMBIE) { 1278199086Srpaulo return; 1279199086Srpaulo } 1280199086Srpaulo 1281199086Srpaulo if ((s->type == ATP_STROKE_TOUCH) && 1282199086Srpaulo (s->age > atp_stroke_maturity_threshold)) { 1283199086Srpaulo s->flags |= ATSF_ZOMBIE; 1284199086Srpaulo 1285199086Srpaulo /* If no zombies exist, then prepare to reap zombies later. */ 1286199086Srpaulo if ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) { 1287199086Srpaulo atp_setup_reap_time(sc, &s->ctime); 1288199086Srpaulo sc->sc_state |= ATP_ZOMBIES_EXIST; 1289199086Srpaulo } 1290199086Srpaulo } else { 1291199086Srpaulo /* Drop this stroke. */ 1292199086Srpaulo memcpy(&sc->sc_strokes[index], &sc->sc_strokes[index + 1], 1293199086Srpaulo (sc->sc_n_strokes - index - 1) * sizeof(atp_stroke)); 1294199086Srpaulo sc->sc_n_strokes--; 1295199086Srpaulo 1296199086Srpaulo /* 1297199086Srpaulo * Reset the double-click-n-drag at the termination of 1298199086Srpaulo * any slide stroke. 1299199086Srpaulo */ 1300199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1301199086Srpaulo } 1302199086Srpaulo} 1303199086Srpaulo 1304199086Srpaulostatic __inline boolean_t 1305199086Srpauloatp_stroke_has_small_movement(const atp_stroke *stroke) 1306199086Srpaulo{ 1307199086Srpaulo return ((abs(stroke->components[X].delta_mickeys) <= 1308199086Srpaulo atp_small_movement_threshold) && 1309199086Srpaulo (abs(stroke->components[Y].delta_mickeys) <= 1310199086Srpaulo atp_small_movement_threshold)); 1311199086Srpaulo} 1312199086Srpaulo 1313199086Srpaulo/* 1314199086Srpaulo * Accumulate delta_mickeys into the component's 'pending' bucket; if 1315199086Srpaulo * the aggregate exceeds the small_movement_threshold, then retain 1316199086Srpaulo * delta_mickeys for later. 1317199086Srpaulo */ 1318199086Srpaulostatic __inline void 1319199086Srpauloatp_update_pending_mickeys(atp_stroke_component *component) 1320199086Srpaulo{ 1321199086Srpaulo component->pending += component->delta_mickeys; 1322199086Srpaulo if (abs(component->pending) <= atp_small_movement_threshold) 1323199086Srpaulo component->delta_mickeys = 0; 1324199086Srpaulo else { 1325199086Srpaulo /* 1326199086Srpaulo * Penalise pending mickeys for having accumulated 1327199086Srpaulo * over short deltas. This operation has the effect of 1328199086Srpaulo * scaling down the cumulative contribution of short 1329199086Srpaulo * movements. 1330199086Srpaulo */ 1331199086Srpaulo component->pending -= (component->delta_mickeys << 1); 1332199086Srpaulo } 1333199086Srpaulo} 1334199086Srpaulo 1335199086Srpaulo 1336199086Srpaulostatic void 1337199086Srpauloatp_compute_smoothening_scale_ratio(atp_stroke *stroke, int *numerator, 1338199086Srpaulo int *denominator) 1339199086Srpaulo{ 1340199086Srpaulo int dxdt; 1341199086Srpaulo int dydt; 1342199086Srpaulo u_int vel_squared; /* Square of the velocity vector's magnitude. */ 1343199086Srpaulo u_int vel_squared_smooth; 1344199086Srpaulo 1345199086Srpaulo /* Table holding (10 * sqrt(x)) for x between 1 and 256. */ 1346199086Srpaulo static uint8_t sqrt_table[256] = { 1347199086Srpaulo 10, 14, 17, 20, 22, 24, 26, 28, 1348199086Srpaulo 30, 31, 33, 34, 36, 37, 38, 40, 1349199086Srpaulo 41, 42, 43, 44, 45, 46, 47, 48, 1350199086Srpaulo 50, 50, 51, 52, 53, 54, 55, 56, 1351199086Srpaulo 57, 58, 59, 60, 60, 61, 62, 63, 1352199086Srpaulo 64, 64, 65, 66, 67, 67, 68, 69, 1353199086Srpaulo 70, 70, 71, 72, 72, 73, 74, 74, 1354199086Srpaulo 75, 76, 76, 77, 78, 78, 79, 80, 1355199086Srpaulo 80, 81, 81, 82, 83, 83, 84, 84, 1356199086Srpaulo 85, 86, 86, 87, 87, 88, 88, 89, 1357199086Srpaulo 90, 90, 91, 91, 92, 92, 93, 93, 1358199086Srpaulo 94, 94, 95, 95, 96, 96, 97, 97, 1359199086Srpaulo 98, 98, 99, 100, 100, 100, 101, 101, 1360199086Srpaulo 102, 102, 103, 103, 104, 104, 105, 105, 1361199086Srpaulo 106, 106, 107, 107, 108, 108, 109, 109, 1362199086Srpaulo 110, 110, 110, 111, 111, 112, 112, 113, 1363199086Srpaulo 113, 114, 114, 114, 115, 115, 116, 116, 1364199086Srpaulo 117, 117, 117, 118, 118, 119, 119, 120, 1365199086Srpaulo 120, 120, 121, 121, 122, 122, 122, 123, 1366199086Srpaulo 123, 124, 124, 124, 125, 125, 126, 126, 1367199086Srpaulo 126, 127, 127, 128, 128, 128, 129, 129, 1368199086Srpaulo 130, 130, 130, 131, 131, 131, 132, 132, 1369199086Srpaulo 133, 133, 133, 134, 134, 134, 135, 135, 1370199086Srpaulo 136, 136, 136, 137, 137, 137, 138, 138, 1371199086Srpaulo 138, 139, 139, 140, 140, 140, 141, 141, 1372199086Srpaulo 141, 142, 142, 142, 143, 143, 143, 144, 1373199086Srpaulo 144, 144, 145, 145, 145, 146, 146, 146, 1374199086Srpaulo 147, 147, 147, 148, 148, 148, 149, 149, 1375199086Srpaulo 150, 150, 150, 150, 151, 151, 151, 152, 1376199086Srpaulo 152, 152, 153, 153, 153, 154, 154, 154, 1377199086Srpaulo 155, 155, 155, 156, 156, 156, 157, 157, 1378199086Srpaulo 157, 158, 158, 158, 159, 159, 159, 160 1379199086Srpaulo }; 1380199086Srpaulo const u_int N = sizeof(sqrt_table) / sizeof(sqrt_table[0]); 1381199086Srpaulo 1382199086Srpaulo dxdt = stroke->components[X].delta_mickeys; 1383199086Srpaulo dydt = stroke->components[Y].delta_mickeys; 1384199086Srpaulo 1385199086Srpaulo *numerator = 0, *denominator = 0; /* default values. */ 1386199086Srpaulo 1387199086Srpaulo /* Compute a smoothened magnitude_squared of the stroke's velocity. */ 1388199086Srpaulo vel_squared = dxdt * dxdt + dydt * dydt; 1389199086Srpaulo vel_squared_smooth = (3 * stroke->velocity_squared + vel_squared) >> 2; 1390199086Srpaulo stroke->velocity_squared = vel_squared_smooth; /* retained as history */ 1391199086Srpaulo if ((vel_squared == 0) || (vel_squared_smooth == 0)) 1392199086Srpaulo return; /* returning (numerator == 0) will imply zero movement*/ 1393199086Srpaulo 1394199086Srpaulo /* 1395199086Srpaulo * In order to determine the overall movement scale factor, 1396199086Srpaulo * we're actually interested in the effect of smoothening upon 1397199086Srpaulo * the *magnitude* of velocity; i.e. we need to compute the 1398199086Srpaulo * square-root of (vel_squared_smooth / vel_squared) in the 1399199086Srpaulo * form of a numerator and denominator. 1400199086Srpaulo */ 1401199086Srpaulo 1402199086Srpaulo /* Keep within the bounds of the square-root table. */ 1403199086Srpaulo while ((vel_squared > N) || (vel_squared_smooth > N)) { 1404199086Srpaulo /* Dividing uniformly by 2 won't disturb the final ratio. */ 1405199086Srpaulo vel_squared >>= 1; 1406199086Srpaulo vel_squared_smooth >>= 1; 1407199086Srpaulo } 1408199086Srpaulo 1409199086Srpaulo *numerator = sqrt_table[vel_squared_smooth - 1]; 1410199086Srpaulo *denominator = sqrt_table[vel_squared - 1]; 1411199086Srpaulo} 1412199086Srpaulo 1413199086Srpaulo/* 1414199086Srpaulo * Compute a smoothened value for the stroke's movement from 1415199086Srpaulo * delta_mickeys in the X and Y components. 1416199086Srpaulo */ 1417199086Srpaulostatic boolean_t 1418199086Srpauloatp_compute_stroke_movement(atp_stroke *stroke) 1419199086Srpaulo{ 1420199086Srpaulo int num; /* numerator of scale ratio */ 1421199086Srpaulo int denom; /* denominator of scale ratio */ 1422199086Srpaulo 1423199086Srpaulo /* 1424199086Srpaulo * Short movements are added first to the 'pending' bucket, 1425199086Srpaulo * and then acted upon only when their aggregate exceeds a 1426199086Srpaulo * threshold. This has the effect of filtering away movement 1427199086Srpaulo * noise. 1428199086Srpaulo */ 1429199086Srpaulo if (atp_stroke_has_small_movement(stroke)) { 1430199086Srpaulo atp_update_pending_mickeys(&stroke->components[X]); 1431199086Srpaulo atp_update_pending_mickeys(&stroke->components[Y]); 1432199086Srpaulo } else { /* large movement */ 1433199086Srpaulo /* clear away any pending mickeys if there are large movements*/ 1434199086Srpaulo stroke->components[X].pending = 0; 1435199086Srpaulo stroke->components[Y].pending = 0; 1436199086Srpaulo } 1437199086Srpaulo 1438199086Srpaulo /* Get the scale ratio and smoothen movement. */ 1439199086Srpaulo atp_compute_smoothening_scale_ratio(stroke, &num, &denom); 1440199086Srpaulo if ((num == 0) || (denom == 0)) { 1441199086Srpaulo stroke->components[X].movement = 0; 1442199086Srpaulo stroke->components[Y].movement = 0; 1443199086Srpaulo stroke->velocity_squared >>= 1; /* Erode velocity_squared. */ 1444199086Srpaulo } else { 1445199086Srpaulo stroke->components[X].movement = 1446199086Srpaulo (stroke->components[X].delta_mickeys * num) / denom; 1447199086Srpaulo stroke->components[Y].movement = 1448199086Srpaulo (stroke->components[Y].delta_mickeys * num) / denom; 1449199086Srpaulo 1450199086Srpaulo stroke->cum_movement += 1451199086Srpaulo abs(stroke->components[X].movement) + 1452199086Srpaulo abs(stroke->components[Y].movement); 1453199086Srpaulo } 1454199086Srpaulo 1455199086Srpaulo return ((stroke->components[X].movement != 0) || 1456199086Srpaulo (stroke->components[Y].movement != 0)); 1457199086Srpaulo} 1458199086Srpaulo 1459199086Srpaulostatic __inline void 1460199086Srpauloatp_setup_reap_time(struct atp_softc *sc, struct timeval *tvp) 1461199086Srpaulo{ 1462199086Srpaulo struct timeval reap_window = { 1463199086Srpaulo ATP_ZOMBIE_STROKE_REAP_WINDOW / 1000000, 1464199086Srpaulo ATP_ZOMBIE_STROKE_REAP_WINDOW % 1000000 1465199086Srpaulo }; 1466199086Srpaulo 1467199086Srpaulo microtime(&sc->sc_reap_time); 1468199086Srpaulo timevaladd(&sc->sc_reap_time, &reap_window); 1469199086Srpaulo 1470199086Srpaulo sc->sc_reap_ctime = *tvp; /* ctime to reap */ 1471199086Srpaulo} 1472199086Srpaulo 1473199086Srpaulostatic void 1474199086Srpauloatp_reap_zombies(struct atp_softc *sc, u_int *n_reaped, u_int *reaped_xlocs) 1475199086Srpaulo{ 1476199086Srpaulo u_int i; 1477199086Srpaulo atp_stroke *stroke; 1478199086Srpaulo 1479199086Srpaulo *n_reaped = 0; 1480199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1481199086Srpaulo struct timeval tdiff; 1482199086Srpaulo 1483199086Srpaulo stroke = &sc->sc_strokes[i]; 1484199086Srpaulo 1485199086Srpaulo if ((stroke->flags & ATSF_ZOMBIE) == 0) 1486199086Srpaulo continue; 1487199086Srpaulo 1488199086Srpaulo /* Compare this stroke's ctime with the ctime being reaped. */ 1489199086Srpaulo if (timevalcmp(&stroke->ctime, &sc->sc_reap_ctime, >=)) { 1490199086Srpaulo tdiff = stroke->ctime; 1491199086Srpaulo timevalsub(&tdiff, &sc->sc_reap_ctime); 1492199086Srpaulo } else { 1493199086Srpaulo tdiff = sc->sc_reap_ctime; 1494199086Srpaulo timevalsub(&tdiff, &stroke->ctime); 1495199086Srpaulo } 1496199086Srpaulo 1497199086Srpaulo if ((tdiff.tv_sec > (ATP_COINCIDENCE_THRESHOLD / 1000000)) || 1498199086Srpaulo ((tdiff.tv_sec == (ATP_COINCIDENCE_THRESHOLD / 1000000)) && 1499199086Srpaulo (tdiff.tv_usec > (ATP_COINCIDENCE_THRESHOLD % 1000000)))) { 1500199086Srpaulo continue; /* Skip non-siblings. */ 1501199086Srpaulo } 1502199086Srpaulo 1503199086Srpaulo /* 1504199086Srpaulo * Reap this sibling zombie stroke. 1505199086Srpaulo */ 1506199086Srpaulo 1507199086Srpaulo if (reaped_xlocs != NULL) 1508199086Srpaulo reaped_xlocs[*n_reaped] = stroke->components[X].loc; 1509199086Srpaulo 1510199086Srpaulo /* Erase the stroke from the sc. */ 1511199086Srpaulo memcpy(&stroke[i], &stroke[i + 1], 1512199086Srpaulo (sc->sc_n_strokes - i - 1) * sizeof(atp_stroke)); 1513199086Srpaulo sc->sc_n_strokes--; 1514199086Srpaulo 1515199086Srpaulo *n_reaped += 1; 1516199086Srpaulo --i; /* Decr. i to keep it unchanged for the next iteration */ 1517199086Srpaulo } 1518199086Srpaulo 1519199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "reaped %u zombies\n", *n_reaped); 1520199086Srpaulo 1521199086Srpaulo /* There could still be zombies remaining in the system. */ 1522199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1523199086Srpaulo stroke = &sc->sc_strokes[i]; 1524199086Srpaulo if (stroke->flags & ATSF_ZOMBIE) { 1525199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "zombies remain!\n"); 1526199086Srpaulo atp_setup_reap_time(sc, &stroke->ctime); 1527199086Srpaulo return; 1528199086Srpaulo } 1529199086Srpaulo } 1530199086Srpaulo 1531199086Srpaulo /* If we reach here, then no more zombies remain. */ 1532199086Srpaulo sc->sc_state &= ~ATP_ZOMBIES_EXIST; 1533199086Srpaulo} 1534199086Srpaulo 1535199086Srpaulo 1536199086Srpaulo/* Device methods. */ 1537199086Srpaulostatic device_probe_t atp_probe; 1538199086Srpaulostatic device_attach_t atp_attach; 1539199086Srpaulostatic device_detach_t atp_detach; 1540199086Srpaulostatic usb_callback_t atp_intr; 1541199086Srpaulo 1542199086Srpaulostatic const struct usb_config atp_config[ATP_N_TRANSFER] = { 1543199086Srpaulo [ATP_INTR_DT] = { 1544199086Srpaulo .type = UE_INTERRUPT, 1545199086Srpaulo .endpoint = UE_ADDR_ANY, 1546199086Srpaulo .direction = UE_DIR_IN, 1547199086Srpaulo .flags = { 1548199086Srpaulo .pipe_bof = 1, 1549199086Srpaulo .short_xfer_ok = 1, 1550199086Srpaulo }, 1551199086Srpaulo .bufsize = 0, /* use wMaxPacketSize */ 1552199086Srpaulo .callback = &atp_intr, 1553199086Srpaulo }, 1554199680Sthompsa [ATP_RESET] = { 1555199680Sthompsa .type = UE_CONTROL, 1556199680Sthompsa .endpoint = 0, /* Control pipe */ 1557199680Sthompsa .direction = UE_DIR_ANY, 1558199680Sthompsa .bufsize = sizeof(struct usb_device_request) + MODE_LENGTH, 1559199680Sthompsa .callback = &atp_reset_callback, 1560199680Sthompsa .interval = 0, /* no pre-delay */ 1561199680Sthompsa }, 1562199086Srpaulo}; 1563199086Srpaulo 1564199086Srpaulostatic int 1565199086Srpauloatp_probe(device_t self) 1566199086Srpaulo{ 1567199086Srpaulo struct usb_attach_arg *uaa = device_get_ivars(self); 1568199086Srpaulo 1569199086Srpaulo if (uaa->usb_mode != USB_MODE_HOST) 1570199086Srpaulo return (ENXIO); 1571199086Srpaulo 1572199086Srpaulo if ((uaa->info.bInterfaceClass != UICLASS_HID) || 1573199086Srpaulo (uaa->info.bInterfaceProtocol != UIPROTO_MOUSE)) 1574199086Srpaulo return (ENXIO); 1575199086Srpaulo 1576199680Sthompsa return (usbd_lookup_id_by_uaa(atp_devs, sizeof(atp_devs), uaa)); 1577199086Srpaulo} 1578199086Srpaulo 1579199086Srpaulostatic int 1580199086Srpauloatp_attach(device_t dev) 1581199086Srpaulo{ 1582199086Srpaulo struct atp_softc *sc = device_get_softc(dev); 1583199086Srpaulo struct usb_attach_arg *uaa = device_get_ivars(dev); 1584199086Srpaulo usb_error_t err; 1585199086Srpaulo 1586199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "sc=%p\n", sc); 1587199086Srpaulo 1588199086Srpaulo sc->sc_dev = dev; 1589199086Srpaulo sc->sc_usb_device = uaa->device; 1590199086Srpaulo 1591199086Srpaulo /* 1592199086Srpaulo * By default the touchpad behaves like an HID device, sending 1593199086Srpaulo * packets with reportID = 2. Such reports contain only 1594199086Srpaulo * limited information--they encode movement deltas and button 1595199086Srpaulo * events,--but do not include data from the pressure 1596199086Srpaulo * sensors. The device input mode can be switched from HID 1597199086Srpaulo * reports to raw sensor data using vendor-specific USB 1598199086Srpaulo * control commands; but first the mode must be read. 1599199086Srpaulo */ 1600199086Srpaulo err = atp_req_get_report(sc->sc_usb_device, sc->sc_mode_bytes); 1601199086Srpaulo if (err != USB_ERR_NORMAL_COMPLETION) { 1602199086Srpaulo DPRINTF("failed to read device mode (%d)\n", err); 1603199086Srpaulo return (ENXIO); 1604199086Srpaulo } 1605199086Srpaulo 1606199086Srpaulo if (atp_set_device_mode(dev, RAW_SENSOR_MODE) != 0) { 1607199086Srpaulo DPRINTF("failed to set mode to 'RAW_SENSOR' (%d)\n", err); 1608199086Srpaulo return (ENXIO); 1609199086Srpaulo } 1610199086Srpaulo 1611199086Srpaulo mtx_init(&sc->sc_mutex, "atpmtx", NULL, MTX_DEF | MTX_RECURSE); 1612199086Srpaulo 1613199086Srpaulo err = usbd_transfer_setup(uaa->device, 1614199086Srpaulo &uaa->info.bIfaceIndex, sc->sc_xfer, atp_config, 1615199086Srpaulo ATP_N_TRANSFER, sc, &sc->sc_mutex); 1616199086Srpaulo 1617199086Srpaulo if (err) { 1618199086Srpaulo DPRINTF("error=%s\n", usbd_errstr(err)); 1619199086Srpaulo goto detach; 1620199086Srpaulo } 1621199086Srpaulo 1622199086Srpaulo if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex, 1623199086Srpaulo &atp_fifo_methods, &sc->sc_fifo, 1624199086Srpaulo device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex, 1625199086Srpaulo UID_ROOT, GID_OPERATOR, 0644)) { 1626199086Srpaulo goto detach; 1627199086Srpaulo } 1628199086Srpaulo 1629199086Srpaulo device_set_usb_desc(dev); 1630199086Srpaulo 1631199086Srpaulo sc->sc_params = &atp_dev_params[uaa->driver_info]; 1632199086Srpaulo 1633199086Srpaulo sc->sc_hw.buttons = 3; 1634199086Srpaulo sc->sc_hw.iftype = MOUSE_IF_USB; 1635199086Srpaulo sc->sc_hw.type = MOUSE_PAD; 1636199086Srpaulo sc->sc_hw.model = MOUSE_MODEL_GENERIC; 1637199086Srpaulo sc->sc_hw.hwid = 0; 1638199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 1639199086Srpaulo sc->sc_mode.rate = -1; 1640199086Srpaulo sc->sc_mode.resolution = MOUSE_RES_UNKNOWN; 1641199086Srpaulo sc->sc_mode.accelfactor = 0; 1642199086Srpaulo sc->sc_mode.level = 0; 1643199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 1644199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 1645199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 1646199086Srpaulo 1647199086Srpaulo sc->sc_state = 0; 1648199086Srpaulo 1649199086Srpaulo sc->sc_left_margin = atp_mickeys_scale_factor; 1650199086Srpaulo sc->sc_right_margin = (sc->sc_params->n_xsensors - 1) * 1651199086Srpaulo atp_mickeys_scale_factor; 1652199086Srpaulo 1653199086Srpaulo return (0); 1654199086Srpaulo 1655199086Srpaulodetach: 1656199086Srpaulo atp_detach(dev); 1657199086Srpaulo return (ENOMEM); 1658199086Srpaulo} 1659199086Srpaulo 1660199086Srpaulostatic int 1661199086Srpauloatp_detach(device_t dev) 1662199086Srpaulo{ 1663199086Srpaulo struct atp_softc *sc; 1664199086Srpaulo 1665199086Srpaulo sc = device_get_softc(dev); 1666199086Srpaulo if (sc->sc_state & ATP_ENABLED) { 1667199086Srpaulo mtx_lock(&sc->sc_mutex); 1668199086Srpaulo atp_disable(sc); 1669199086Srpaulo mtx_unlock(&sc->sc_mutex); 1670199086Srpaulo } 1671199086Srpaulo 1672199086Srpaulo usb_fifo_detach(&sc->sc_fifo); 1673199086Srpaulo 1674199086Srpaulo usbd_transfer_unsetup(sc->sc_xfer, ATP_N_TRANSFER); 1675199086Srpaulo 1676199086Srpaulo mtx_destroy(&sc->sc_mutex); 1677199086Srpaulo 1678199086Srpaulo return (0); 1679199086Srpaulo} 1680199086Srpaulo 1681199086Srpaulostatic void 1682199086Srpauloatp_intr(struct usb_xfer *xfer, usb_error_t error) 1683199086Srpaulo{ 1684199086Srpaulo struct atp_softc *sc = usbd_xfer_softc(xfer); 1685199086Srpaulo int len; 1686199086Srpaulo struct usb_page_cache *pc; 1687199086Srpaulo uint8_t status_bits; 1688199086Srpaulo atp_pspan pspans_x[ATP_MAX_PSPANS_PER_AXIS]; 1689199086Srpaulo atp_pspan pspans_y[ATP_MAX_PSPANS_PER_AXIS]; 1690199086Srpaulo u_int n_xpspans = 0, n_ypspans = 0; 1691199086Srpaulo u_int reaped_xlocs[ATP_MAX_STROKES]; 1692199086Srpaulo u_int tap_fingers = 0; 1693199086Srpaulo 1694199086Srpaulo usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 1695199086Srpaulo 1696199086Srpaulo switch (USB_GET_STATE(xfer)) { 1697199086Srpaulo case USB_ST_TRANSFERRED: 1698199086Srpaulo if (len > sc->sc_params->data_len) { 1699199086Srpaulo DPRINTFN(ATP_LLEVEL_ERROR, 1700199086Srpaulo "truncating large packet from %u to %u bytes\n", 1701199086Srpaulo len, sc->sc_params->data_len); 1702199086Srpaulo len = sc->sc_params->data_len; 1703199086Srpaulo } 1704199151Snwhitehorn if (len < sc->sc_params->data_len) 1705199086Srpaulo goto tr_setup; 1706199086Srpaulo 1707199086Srpaulo pc = usbd_xfer_get_frame(xfer, 0); 1708199086Srpaulo usbd_copy_out(pc, 0, sc->sensor_data, sc->sc_params->data_len); 1709199086Srpaulo 1710199086Srpaulo /* Interpret sensor data */ 1711199086Srpaulo atp_interpret_sensor_data(sc->sensor_data, 1712199151Snwhitehorn sc->sc_params->n_xsensors, X, sc->cur_x, 1713199151Snwhitehorn sc->sc_params->prot); 1714199086Srpaulo atp_interpret_sensor_data(sc->sensor_data, 1715199151Snwhitehorn sc->sc_params->n_ysensors, Y, sc->cur_y, 1716199151Snwhitehorn sc->sc_params->prot); 1717199086Srpaulo 1718199086Srpaulo /* 1719199086Srpaulo * If this is the initial update (from an untouched 1720199086Srpaulo * pad), we should set the base values for the sensor 1721199086Srpaulo * data; deltas with respect to these base values can 1722199086Srpaulo * be used as pressure readings subsequently. 1723199086Srpaulo */ 1724199086Srpaulo status_bits = sc->sensor_data[sc->sc_params->data_len - 1]; 1725199151Snwhitehorn if ((sc->sc_params->prot == ATP_PROT_GEYSER3 && 1726199151Snwhitehorn (status_bits & ATP_STATUS_BASE_UPDATE)) || 1727199151Snwhitehorn !(sc->sc_state & ATP_VALID)) { 1728199086Srpaulo memcpy(sc->base_x, sc->cur_x, 1729199086Srpaulo sc->sc_params->n_xsensors * sizeof(*(sc->base_x))); 1730199086Srpaulo memcpy(sc->base_y, sc->cur_y, 1731199086Srpaulo sc->sc_params->n_ysensors * sizeof(*(sc->base_y))); 1732199151Snwhitehorn sc->sc_state |= ATP_VALID; 1733199086Srpaulo goto tr_setup; 1734199086Srpaulo } 1735199086Srpaulo 1736199086Srpaulo /* Get pressure readings and detect p-spans for both axes. */ 1737199086Srpaulo atp_get_pressures(sc->pressure_x, sc->cur_x, sc->base_x, 1738199086Srpaulo sc->sc_params->n_xsensors); 1739199086Srpaulo atp_detect_pspans(sc->pressure_x, sc->sc_params->n_xsensors, 1740199086Srpaulo ATP_MAX_PSPANS_PER_AXIS, 1741199086Srpaulo pspans_x, &n_xpspans); 1742199086Srpaulo atp_get_pressures(sc->pressure_y, sc->cur_y, sc->base_y, 1743199086Srpaulo sc->sc_params->n_ysensors); 1744199086Srpaulo atp_detect_pspans(sc->pressure_y, sc->sc_params->n_ysensors, 1745199086Srpaulo ATP_MAX_PSPANS_PER_AXIS, 1746199086Srpaulo pspans_y, &n_ypspans); 1747199086Srpaulo 1748199086Srpaulo /* Update strokes with new pspans to detect movements. */ 1749199086Srpaulo sc->sc_status.flags &= ~MOUSE_POSCHANGED; 1750199086Srpaulo if (atp_update_strokes(sc, 1751199086Srpaulo pspans_x, n_xpspans, 1752199086Srpaulo pspans_y, n_ypspans)) 1753199086Srpaulo sc->sc_status.flags |= MOUSE_POSCHANGED; 1754199086Srpaulo 1755199086Srpaulo /* Reap zombies if it is time. */ 1756199086Srpaulo if (sc->sc_state & ATP_ZOMBIES_EXIST) { 1757199086Srpaulo struct timeval now; 1758199086Srpaulo 1759199086Srpaulo getmicrotime(&now); 1760199086Srpaulo if (timevalcmp(&now, &sc->sc_reap_time, >=)) 1761199086Srpaulo atp_reap_zombies(sc, &tap_fingers, 1762199086Srpaulo reaped_xlocs); 1763199086Srpaulo } 1764199086Srpaulo 1765199086Srpaulo sc->sc_status.flags &= ~MOUSE_STDBUTTONSCHANGED; 1766199086Srpaulo sc->sc_status.obutton = sc->sc_status.button; 1767199086Srpaulo 1768199086Srpaulo /* Get the state of the physical buttton. */ 1769199086Srpaulo sc->sc_status.button = (status_bits & ATP_STATUS_BUTTON) ? 1770199086Srpaulo MOUSE_BUTTON1DOWN : 0; 1771199086Srpaulo if (sc->sc_status.button != 0) { 1772199086Srpaulo /* Reset DOUBLE_TAP_N_DRAG if the button is pressed. */ 1773199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1774199086Srpaulo } else if (sc->sc_state & ATP_DOUBLE_TAP_DRAG) { 1775199086Srpaulo /* Assume a button-press with DOUBLE_TAP_N_DRAG. */ 1776199086Srpaulo sc->sc_status.button = MOUSE_BUTTON1DOWN; 1777199086Srpaulo } 1778199086Srpaulo 1779199086Srpaulo sc->sc_status.flags |= 1780199086Srpaulo sc->sc_status.button ^ sc->sc_status.obutton; 1781199086Srpaulo if (sc->sc_status.flags & MOUSE_STDBUTTONSCHANGED) { 1782199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "button %s\n", 1783199086Srpaulo ((sc->sc_status.button & MOUSE_BUTTON1DOWN) ? 1784199086Srpaulo "pressed" : "released")); 1785199086Srpaulo } else if ((sc->sc_status.obutton == 0) && 1786199086Srpaulo (sc->sc_status.button == 0) && 1787199086Srpaulo (tap_fingers != 0)) { 1788199086Srpaulo /* Ignore single-finger taps at the edges. */ 1789199086Srpaulo if ((tap_fingers == 1) && 1790199086Srpaulo ((reaped_xlocs[0] <= sc->sc_left_margin) || 1791199086Srpaulo (reaped_xlocs[0] > sc->sc_right_margin))) { 1792199086Srpaulo tap_fingers = 0; 1793199086Srpaulo } 1794199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, 1795199086Srpaulo "tap_fingers: %u\n", tap_fingers); 1796199086Srpaulo } 1797199086Srpaulo 1798199086Srpaulo if (sc->sc_status.flags & 1799199086Srpaulo (MOUSE_POSCHANGED | MOUSE_STDBUTTONSCHANGED)) { 1800199086Srpaulo int dx, dy; 1801199086Srpaulo u_int n_movements; 1802199086Srpaulo 1803199086Srpaulo dx = 0, dy = 0, n_movements = 0; 1804199086Srpaulo for (u_int i = 0; i < sc->sc_n_strokes; i++) { 1805199086Srpaulo atp_stroke *stroke = &sc->sc_strokes[i]; 1806199086Srpaulo 1807199086Srpaulo if ((stroke->components[X].movement) || 1808199086Srpaulo (stroke->components[Y].movement)) { 1809199086Srpaulo dx += stroke->components[X].movement; 1810199086Srpaulo dy += stroke->components[Y].movement; 1811199086Srpaulo n_movements++; 1812199086Srpaulo } 1813199086Srpaulo } 1814199086Srpaulo /* 1815199086Srpaulo * Disregard movement if multiple 1816199086Srpaulo * strokes record motion. 1817199086Srpaulo */ 1818199086Srpaulo if (n_movements != 1) 1819199086Srpaulo dx = 0, dy = 0; 1820199086Srpaulo 1821199086Srpaulo sc->sc_status.dx += dx; 1822199086Srpaulo sc->sc_status.dy += dy; 1823199086Srpaulo atp_add_to_queue(sc, dx, -dy, sc->sc_status.button); 1824199086Srpaulo } 1825199086Srpaulo 1826199086Srpaulo if (tap_fingers != 0) { 1827199086Srpaulo /* Add a pair of events (button-down and button-up). */ 1828199086Srpaulo switch (tap_fingers) { 1829199086Srpaulo case 1: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON1DOWN); 1830199086Srpaulo break; 1831199086Srpaulo case 2: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON2DOWN); 1832199086Srpaulo break; 1833199086Srpaulo case 3: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON3DOWN); 1834199086Srpaulo break; 1835199086Srpaulo default: break;/* handle taps of only up to 3 fingers */ 1836199086Srpaulo } 1837199086Srpaulo atp_add_to_queue(sc, 0, 0, 0); /* button release */ 1838199086Srpaulo } 1839199086Srpaulo 1840199086Srpaulo /* 1841199086Srpaulo * The device continues to trigger interrupts at a 1842199086Srpaulo * fast rate even after touchpad activity has 1843199086Srpaulo * stopped. Upon detecting that the device has 1844199086Srpaulo * remained idle beyond a threshold, we reinitialize 1845199086Srpaulo * it to silence the interrupts. 1846199086Srpaulo */ 1847199086Srpaulo if ((sc->sc_status.flags == 0) && 1848199086Srpaulo (sc->sc_n_strokes == 0) && 1849199086Srpaulo (sc->sc_status.button == 0)) { 1850199086Srpaulo sc->sc_idlecount++; 1851199086Srpaulo if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) { 1852199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "idle\n"); 1853199151Snwhitehorn sc->sc_idlecount = 0; 1854199680Sthompsa usbd_transfer_start(sc->sc_xfer[ATP_RESET]); 1855199086Srpaulo } 1856199086Srpaulo } else { 1857199086Srpaulo sc->sc_idlecount = 0; 1858199086Srpaulo } 1859199086Srpaulo 1860199086Srpaulo case USB_ST_SETUP: 1861199086Srpaulo tr_setup: 1862199086Srpaulo /* check if we can put more data into the FIFO */ 1863199086Srpaulo if (usb_fifo_put_bytes_max( 1864199086Srpaulo sc->sc_fifo.fp[USB_FIFO_RX]) != 0) { 1865199086Srpaulo usbd_xfer_set_frame_len(xfer, 0, 1866199151Snwhitehorn sc->sc_params->data_len); 1867199086Srpaulo usbd_transfer_submit(xfer); 1868199086Srpaulo } 1869199086Srpaulo break; 1870199086Srpaulo 1871199086Srpaulo default: /* Error */ 1872199086Srpaulo if (error != USB_ERR_CANCELLED) { 1873199086Srpaulo /* try clear stall first */ 1874199086Srpaulo usbd_xfer_set_stall(xfer); 1875199086Srpaulo goto tr_setup; 1876199086Srpaulo } 1877199086Srpaulo break; 1878199086Srpaulo } 1879199086Srpaulo 1880199086Srpaulo return; 1881199086Srpaulo} 1882199086Srpaulo 1883199086Srpaulostatic void 1884199086Srpauloatp_add_to_queue(struct atp_softc *sc, int dx, int dy, uint32_t buttons_in) 1885199086Srpaulo{ 1886199086Srpaulo uint32_t buttons_out; 1887199086Srpaulo uint8_t buf[8]; 1888199086Srpaulo 1889199086Srpaulo dx = imin(dx, 254); dx = imax(dx, -256); 1890199086Srpaulo dy = imin(dy, 254); dy = imax(dy, -256); 1891199086Srpaulo 1892199086Srpaulo buttons_out = MOUSE_MSC_BUTTONS; 1893199086Srpaulo if (buttons_in & MOUSE_BUTTON1DOWN) 1894199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON1UP; 1895199086Srpaulo else if (buttons_in & MOUSE_BUTTON2DOWN) 1896199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON2UP; 1897199086Srpaulo else if (buttons_in & MOUSE_BUTTON3DOWN) 1898199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON3UP; 1899199086Srpaulo 1900199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "dx=%d, dy=%d, buttons=%x\n", 1901199086Srpaulo dx, dy, buttons_out); 1902199086Srpaulo 1903199086Srpaulo /* Encode the mouse data in standard format; refer to mouse(4) */ 1904199086Srpaulo buf[0] = sc->sc_mode.syncmask[1]; 1905199086Srpaulo buf[0] |= buttons_out; 1906199086Srpaulo buf[1] = dx >> 1; 1907199086Srpaulo buf[2] = dy >> 1; 1908199086Srpaulo buf[3] = dx - (dx >> 1); 1909199086Srpaulo buf[4] = dy - (dy >> 1); 1910199086Srpaulo /* Encode extra bytes for level 1 */ 1911199086Srpaulo if (sc->sc_mode.level == 1) { 1912199086Srpaulo buf[5] = 0; /* dz */ 1913199086Srpaulo buf[6] = 0; /* dz - (dz / 2) */ 1914199086Srpaulo buf[7] = MOUSE_SYS_EXTBUTTONS; /* Extra buttons all up. */ 1915199086Srpaulo } 1916199086Srpaulo 1917199086Srpaulo usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, 1918199086Srpaulo sc->sc_mode.packetsize, 1); 1919199086Srpaulo} 1920199086Srpaulo 1921199086Srpaulostatic void 1922199086Srpauloatp_reset_buf(struct atp_softc *sc) 1923199086Srpaulo{ 1924199086Srpaulo /* reset read queue */ 1925199086Srpaulo usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]); 1926199086Srpaulo} 1927199086Srpaulo 1928199086Srpaulostatic void 1929199086Srpauloatp_start_read(struct usb_fifo *fifo) 1930199086Srpaulo{ 1931199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 1932199086Srpaulo int rate; 1933199086Srpaulo 1934199086Srpaulo /* Check if we should override the default polling interval */ 1935199086Srpaulo rate = sc->sc_pollrate; 1936199086Srpaulo /* Range check rate */ 1937199086Srpaulo if (rate > 1000) 1938199086Srpaulo rate = 1000; 1939199086Srpaulo /* Check for set rate */ 1940199086Srpaulo if ((rate > 0) && (sc->sc_xfer[ATP_INTR_DT] != NULL)) { 1941199086Srpaulo /* Stop current transfer, if any */ 1942199086Srpaulo usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); 1943199086Srpaulo /* Set new interval */ 1944199086Srpaulo usbd_xfer_set_interval(sc->sc_xfer[ATP_INTR_DT], 1000 / rate); 1945199086Srpaulo /* Only set pollrate once */ 1946199086Srpaulo sc->sc_pollrate = 0; 1947199086Srpaulo } 1948199086Srpaulo 1949199086Srpaulo usbd_transfer_start(sc->sc_xfer[ATP_INTR_DT]); 1950199086Srpaulo} 1951199086Srpaulo 1952199086Srpaulostatic void 1953199086Srpauloatp_stop_read(struct usb_fifo *fifo) 1954199086Srpaulo{ 1955199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 1956199086Srpaulo 1957199086Srpaulo usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); 1958199086Srpaulo} 1959199086Srpaulo 1960199086Srpaulo 1961199086Srpaulostatic int 1962199086Srpauloatp_open(struct usb_fifo *fifo, int fflags) 1963199086Srpaulo{ 1964199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "\n"); 1965199086Srpaulo 1966199086Srpaulo if (fflags & FREAD) { 1967199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 1968199086Srpaulo int rc; 1969199086Srpaulo 1970199086Srpaulo if (sc->sc_state & ATP_ENABLED) 1971199086Srpaulo return (EBUSY); 1972199086Srpaulo 1973199086Srpaulo if (usb_fifo_alloc_buffer(fifo, 1974199086Srpaulo ATP_FIFO_BUF_SIZE, ATP_FIFO_QUEUE_MAXLEN)) { 1975199086Srpaulo return (ENOMEM); 1976199086Srpaulo } 1977199086Srpaulo 1978199086Srpaulo rc = atp_enable(sc); 1979199086Srpaulo if (rc != 0) { 1980199086Srpaulo usb_fifo_free_buffer(fifo); 1981199086Srpaulo return (rc); 1982199086Srpaulo } 1983199086Srpaulo } 1984199086Srpaulo 1985199086Srpaulo return (0); 1986199086Srpaulo} 1987199086Srpaulo 1988199086Srpaulostatic void 1989199086Srpauloatp_close(struct usb_fifo *fifo, int fflags) 1990199086Srpaulo{ 1991199086Srpaulo if (fflags & FREAD) { 1992199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 1993199086Srpaulo 1994199086Srpaulo atp_disable(sc); 1995199086Srpaulo usb_fifo_free_buffer(fifo); 1996199086Srpaulo } 1997199086Srpaulo} 1998199086Srpaulo 1999199086Srpauloint 2000199086Srpauloatp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) 2001199086Srpaulo{ 2002199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2003199086Srpaulo mousemode_t mode; 2004199086Srpaulo int error = 0; 2005199086Srpaulo 2006199086Srpaulo mtx_lock(&sc->sc_mutex); 2007199086Srpaulo 2008199086Srpaulo switch(cmd) { 2009199086Srpaulo case MOUSE_GETHWINFO: 2010199086Srpaulo *(mousehw_t *)addr = sc->sc_hw; 2011199086Srpaulo break; 2012199086Srpaulo case MOUSE_GETMODE: 2013199086Srpaulo *(mousemode_t *)addr = sc->sc_mode; 2014199086Srpaulo break; 2015199086Srpaulo case MOUSE_SETMODE: 2016199086Srpaulo mode = *(mousemode_t *)addr; 2017199086Srpaulo 2018199086Srpaulo if (mode.level == -1) 2019199086Srpaulo /* Don't change the current setting */ 2020199086Srpaulo ; 2021199086Srpaulo else if ((mode.level < 0) || (mode.level > 1)) { 2022199086Srpaulo error = EINVAL; 2023199086Srpaulo goto done; 2024199086Srpaulo } 2025199086Srpaulo sc->sc_mode.level = mode.level; 2026199086Srpaulo sc->sc_pollrate = mode.rate; 2027199086Srpaulo sc->sc_hw.buttons = 3; 2028199086Srpaulo 2029199086Srpaulo if (sc->sc_mode.level == 0) { 2030199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 2031199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 2032199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 2033199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 2034199086Srpaulo } else if (sc->sc_mode.level == 1) { 2035199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 2036199086Srpaulo sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 2037199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 2038199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 2039199086Srpaulo } 2040199086Srpaulo atp_reset_buf(sc); 2041199086Srpaulo break; 2042199086Srpaulo case MOUSE_GETLEVEL: 2043199086Srpaulo *(int *)addr = sc->sc_mode.level; 2044199086Srpaulo break; 2045199086Srpaulo case MOUSE_SETLEVEL: 2046199086Srpaulo if (*(int *)addr < 0 || *(int *)addr > 1) { 2047199086Srpaulo error = EINVAL; 2048199086Srpaulo goto done; 2049199086Srpaulo } 2050199086Srpaulo sc->sc_mode.level = *(int *)addr; 2051199086Srpaulo sc->sc_hw.buttons = 3; 2052199086Srpaulo 2053199086Srpaulo if (sc->sc_mode.level == 0) { 2054199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 2055199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 2056199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 2057199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 2058199086Srpaulo } else if (sc->sc_mode.level == 1) { 2059199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 2060199086Srpaulo sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 2061199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 2062199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 2063199086Srpaulo } 2064199086Srpaulo atp_reset_buf(sc); 2065199086Srpaulo break; 2066199086Srpaulo case MOUSE_GETSTATUS: { 2067199086Srpaulo mousestatus_t *status = (mousestatus_t *)addr; 2068199086Srpaulo 2069199086Srpaulo *status = sc->sc_status; 2070199086Srpaulo sc->sc_status.obutton = sc->sc_status.button; 2071199086Srpaulo sc->sc_status.button = 0; 2072199086Srpaulo sc->sc_status.dx = 0; 2073199086Srpaulo sc->sc_status.dy = 0; 2074199086Srpaulo sc->sc_status.dz = 0; 2075199086Srpaulo 2076199086Srpaulo if (status->dx || status->dy || status->dz) 2077199086Srpaulo status->flags |= MOUSE_POSCHANGED; 2078199086Srpaulo if (status->button != status->obutton) 2079199086Srpaulo status->flags |= MOUSE_BUTTONSCHANGED; 2080199086Srpaulo break; 2081199086Srpaulo } 2082199086Srpaulo default: 2083199086Srpaulo error = ENOTTY; 2084199086Srpaulo } 2085199086Srpaulo 2086199086Srpaulodone: 2087199086Srpaulo mtx_unlock(&sc->sc_mutex); 2088199086Srpaulo return (error); 2089199086Srpaulo} 2090199086Srpaulo 2091199086Srpaulostatic int 2092199086Srpauloatp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS) 2093199086Srpaulo{ 2094199086Srpaulo int error; 2095199086Srpaulo u_int tmp; 2096199086Srpaulo u_int prev_mickeys_scale_factor; 2097199086Srpaulo 2098199086Srpaulo prev_mickeys_scale_factor = atp_mickeys_scale_factor; 2099199086Srpaulo 2100199086Srpaulo tmp = atp_mickeys_scale_factor; 2101199086Srpaulo error = sysctl_handle_int(oidp, &tmp, 0, req); 2102199086Srpaulo if (error != 0 || req->newptr == NULL) 2103199086Srpaulo return (error); 2104199086Srpaulo 2105199086Srpaulo if (tmp == prev_mickeys_scale_factor) 2106199086Srpaulo return (0); /* no change */ 2107199086Srpaulo 2108199086Srpaulo atp_mickeys_scale_factor = tmp; 2109199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "%s: resetting mickeys_scale_factor to %u\n", 2110199086Srpaulo ATP_DRIVER_NAME, tmp); 2111199086Srpaulo 2112199086Srpaulo /* Update dependent thresholds. */ 2113199086Srpaulo if (atp_small_movement_threshold == (prev_mickeys_scale_factor >> 3)) 2114199086Srpaulo atp_small_movement_threshold = atp_mickeys_scale_factor >> 3; 2115199086Srpaulo if (atp_max_delta_mickeys == ((3 * prev_mickeys_scale_factor) >> 1)) 2116199086Srpaulo atp_max_delta_mickeys = ((3 * atp_mickeys_scale_factor) >>1); 2117199086Srpaulo if (atp_slide_min_movement == (prev_mickeys_scale_factor >> 3)) 2118199086Srpaulo atp_slide_min_movement = atp_mickeys_scale_factor >> 3; 2119199086Srpaulo 2120199086Srpaulo return (0); 2121199086Srpaulo} 2122199086Srpaulo 2123199086Srpaulostatic device_method_t atp_methods[] = { 2124199086Srpaulo /* Device interface */ 2125199086Srpaulo DEVMETHOD(device_probe, atp_probe), 2126199086Srpaulo DEVMETHOD(device_attach, atp_attach), 2127199086Srpaulo DEVMETHOD(device_detach, atp_detach), 2128199086Srpaulo { 0, 0 } 2129199086Srpaulo}; 2130199086Srpaulo 2131199086Srpaulostatic driver_t atp_driver = { 2132199086Srpaulo ATP_DRIVER_NAME, 2133199086Srpaulo atp_methods, 2134199086Srpaulo sizeof(struct atp_softc) 2135199086Srpaulo}; 2136199086Srpaulo 2137199086Srpaulostatic devclass_t atp_devclass; 2138199086Srpaulo 2139199086SrpauloDRIVER_MODULE(atp, uhub, atp_driver, atp_devclass, NULL, 0); 2140199086SrpauloMODULE_DEPEND(atp, usb, 1, 1, 1); 2141