atp.c revision 200241
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 200241 2009-12-08 00:52:59Z rpaulo $"); 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 *, 440200241Srpaulo const atp_pspan *, atp_stroke_type); 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 *); 461200241Srpaulostatic void atp_convert_to_slide(struct atp_softc *, atp_stroke *); 462199086Srpaulo 463199086Srpaulo/* updating fifo */ 464199086Srpaulostatic void atp_reset_buf(struct atp_softc *sc); 465199086Srpaulostatic void atp_add_to_queue(struct atp_softc *, int, int, uint32_t); 466199086Srpaulo 467199086Srpaulo 468199086Srpaulousb_error_t 469199086Srpauloatp_req_get_report(struct usb_device *udev, void *data) 470199086Srpaulo{ 471199086Srpaulo struct usb_device_request req; 472199086Srpaulo 473199086Srpaulo req.bmRequestType = UT_READ_CLASS_INTERFACE; 474199086Srpaulo req.bRequest = UR_GET_REPORT; 475199086Srpaulo USETW2(req.wValue, (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */); 476199086Srpaulo USETW(req.wIndex, 0); 477199086Srpaulo USETW(req.wLength, MODE_LENGTH); 478199086Srpaulo 479199086Srpaulo return (usbd_do_request(udev, NULL /* mutex */, &req, data)); 480199086Srpaulo} 481199086Srpaulo 482199086Srpaulostatic int 483199086Srpauloatp_set_device_mode(device_t dev, interface_mode mode) 484199086Srpaulo{ 485199086Srpaulo struct atp_softc *sc; 486199086Srpaulo usb_device_request_t req; 487199086Srpaulo usb_error_t err; 488199086Srpaulo 489199086Srpaulo if ((mode != RAW_SENSOR_MODE) && (mode != HID_MODE)) 490199086Srpaulo return (ENXIO); 491199086Srpaulo 492199086Srpaulo sc = device_get_softc(dev); 493199086Srpaulo 494199086Srpaulo sc->sc_mode_bytes[0] = mode; 495199086Srpaulo req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 496199086Srpaulo req.bRequest = UR_SET_REPORT; 497199086Srpaulo USETW2(req.wValue, (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */); 498199086Srpaulo USETW(req.wIndex, 0); 499199086Srpaulo USETW(req.wLength, MODE_LENGTH); 500199086Srpaulo err = usbd_do_request(sc->sc_usb_device, NULL, &req, sc->sc_mode_bytes); 501199086Srpaulo if (err != USB_ERR_NORMAL_COMPLETION) 502199086Srpaulo return (ENXIO); 503199086Srpaulo 504199086Srpaulo return (0); 505199086Srpaulo} 506199086Srpaulo 507199680Sthompsavoid 508199680Sthompsaatp_reset_callback(struct usb_xfer *xfer, usb_error_t error) 509199680Sthompsa{ 510199680Sthompsa usb_device_request_t req; 511199680Sthompsa struct usb_page_cache *pc; 512199680Sthompsa struct atp_softc *sc = usbd_xfer_softc(xfer); 513199680Sthompsa 514199680Sthompsa switch (USB_GET_STATE(xfer)) { 515199680Sthompsa case USB_ST_SETUP: 516199680Sthompsa sc->sc_mode_bytes[0] = RAW_SENSOR_MODE; 517199680Sthompsa req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 518199680Sthompsa req.bRequest = UR_SET_REPORT; 519199680Sthompsa USETW2(req.wValue, 520199680Sthompsa (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */); 521199680Sthompsa USETW(req.wIndex, 0); 522199680Sthompsa USETW(req.wLength, MODE_LENGTH); 523199680Sthompsa 524199680Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 525199680Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 526199680Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 527199680Sthompsa usbd_copy_in(pc, 0, sc->sc_mode_bytes, MODE_LENGTH); 528199680Sthompsa 529199680Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 530199680Sthompsa usbd_xfer_set_frame_len(xfer, 1, MODE_LENGTH); 531199680Sthompsa usbd_xfer_set_frames(xfer, 2); 532199680Sthompsa usbd_transfer_submit(xfer); 533199680Sthompsa break; 534199680Sthompsa 535199680Sthompsa case USB_ST_TRANSFERRED: 536199680Sthompsa default: 537199680Sthompsa break; 538199680Sthompsa } 539199680Sthompsa} 540199680Sthompsa 541199086Srpaulostatic int 542199086Srpauloatp_enable(struct atp_softc *sc) 543199086Srpaulo{ 544199086Srpaulo /* Allocate the dynamic buffers */ 545199086Srpaulo if (atp_softc_populate(sc) != 0) { 546199086Srpaulo atp_softc_unpopulate(sc); 547199086Srpaulo return (ENOMEM); 548199086Srpaulo } 549199086Srpaulo 550199086Srpaulo /* reset status */ 551199086Srpaulo memset(sc->sc_strokes, 0, sizeof(sc->sc_strokes)); 552199086Srpaulo sc->sc_n_strokes = 0; 553199086Srpaulo memset(&sc->sc_status, 0, sizeof(sc->sc_status)); 554199086Srpaulo sc->sc_idlecount = 0; 555199086Srpaulo sc->sc_state |= ATP_ENABLED; 556199086Srpaulo 557199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "enabled atp\n"); 558199086Srpaulo return (0); 559199086Srpaulo} 560199086Srpaulo 561199086Srpaulostatic void 562199086Srpauloatp_disable(struct atp_softc *sc) 563199086Srpaulo{ 564199086Srpaulo atp_softc_unpopulate(sc); 565199086Srpaulo 566199151Snwhitehorn sc->sc_state &= ~(ATP_ENABLED | ATP_VALID); 567199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "disabled atp\n"); 568199086Srpaulo} 569199086Srpaulo 570199086Srpaulo/* Allocate dynamic memory for some fields in softc. */ 571199086Srpaulostatic int 572199086Srpauloatp_softc_populate(struct atp_softc *sc) 573199086Srpaulo{ 574199086Srpaulo const struct atp_dev_params *params = sc->sc_params; 575199086Srpaulo 576199086Srpaulo if (params == NULL) { 577199086Srpaulo DPRINTF("params uninitialized!\n"); 578199086Srpaulo return (ENXIO); 579199086Srpaulo } 580199086Srpaulo if (params->data_len) { 581199086Srpaulo sc->sensor_data = malloc(params->data_len * sizeof(int8_t), 582199086Srpaulo M_USB, M_WAITOK); 583199086Srpaulo if (sc->sensor_data == NULL) { 584199086Srpaulo DPRINTF("mem for sensor_data\n"); 585199086Srpaulo return (ENXIO); 586199086Srpaulo } 587199086Srpaulo } 588199086Srpaulo 589199086Srpaulo if (params->n_xsensors != 0) { 590199086Srpaulo sc->base_x = malloc(params->n_xsensors * sizeof(*(sc->base_x)), 591199086Srpaulo M_USB, M_WAITOK); 592199086Srpaulo if (sc->base_x == NULL) { 593199086Srpaulo DPRINTF("mem for sc->base_x\n"); 594199086Srpaulo return (ENXIO); 595199086Srpaulo } 596199086Srpaulo 597199086Srpaulo sc->cur_x = malloc(params->n_xsensors * sizeof(*(sc->cur_x)), 598199086Srpaulo M_USB, M_WAITOK); 599199086Srpaulo if (sc->cur_x == NULL) { 600199086Srpaulo DPRINTF("mem for sc->cur_x\n"); 601199086Srpaulo return (ENXIO); 602199086Srpaulo } 603199086Srpaulo 604199086Srpaulo sc->pressure_x = 605199086Srpaulo malloc(params->n_xsensors * sizeof(*(sc->pressure_x)), 606199086Srpaulo M_USB, M_WAITOK); 607199086Srpaulo if (sc->pressure_x == NULL) { 608199086Srpaulo DPRINTF("mem. for pressure_x\n"); 609199086Srpaulo return (ENXIO); 610199086Srpaulo } 611199086Srpaulo } 612199086Srpaulo 613199086Srpaulo if (params->n_ysensors != 0) { 614199086Srpaulo sc->base_y = malloc(params->n_ysensors * sizeof(*(sc->base_y)), 615199086Srpaulo M_USB, M_WAITOK); 616199086Srpaulo if (sc->base_y == NULL) { 617199086Srpaulo DPRINTF("mem for base_y\n"); 618199086Srpaulo return (ENXIO); 619199086Srpaulo } 620199086Srpaulo 621199086Srpaulo sc->cur_y = malloc(params->n_ysensors * sizeof(*(sc->cur_y)), 622199086Srpaulo M_USB, M_WAITOK); 623199086Srpaulo if (sc->cur_y == NULL) { 624199086Srpaulo DPRINTF("mem for cur_y\n"); 625199086Srpaulo return (ENXIO); 626199086Srpaulo } 627199086Srpaulo 628199086Srpaulo sc->pressure_y = 629199086Srpaulo malloc(params->n_ysensors * sizeof(*(sc->pressure_y)), 630199086Srpaulo M_USB, M_WAITOK); 631199086Srpaulo if (sc->pressure_y == NULL) { 632199086Srpaulo DPRINTF("mem. for pressure_y\n"); 633199086Srpaulo return (ENXIO); 634199086Srpaulo } 635199086Srpaulo } 636199086Srpaulo 637199086Srpaulo return (0); 638199086Srpaulo} 639199086Srpaulo 640199086Srpaulo/* Free dynamic memory allocated for some fields in softc. */ 641199086Srpaulostatic void 642199086Srpauloatp_softc_unpopulate(struct atp_softc *sc) 643199086Srpaulo{ 644199086Srpaulo const struct atp_dev_params *params = sc->sc_params; 645199086Srpaulo 646199086Srpaulo if (params == NULL) { 647199086Srpaulo return; 648199086Srpaulo } 649199086Srpaulo if (params->n_xsensors != 0) { 650199086Srpaulo if (sc->base_x != NULL) { 651199086Srpaulo free(sc->base_x, M_USB); 652199086Srpaulo sc->base_x = NULL; 653199086Srpaulo } 654199086Srpaulo 655199086Srpaulo if (sc->cur_x != NULL) { 656199086Srpaulo free(sc->cur_x, M_USB); 657199086Srpaulo sc->cur_x = NULL; 658199086Srpaulo } 659199086Srpaulo 660199086Srpaulo if (sc->pressure_x != NULL) { 661199086Srpaulo free(sc->pressure_x, M_USB); 662199086Srpaulo sc->pressure_x = NULL; 663199086Srpaulo } 664199086Srpaulo } 665199086Srpaulo if (params->n_ysensors != 0) { 666199086Srpaulo if (sc->base_y != NULL) { 667199086Srpaulo free(sc->base_y, M_USB); 668199086Srpaulo sc->base_y = NULL; 669199086Srpaulo } 670199086Srpaulo 671199086Srpaulo if (sc->cur_y != NULL) { 672199086Srpaulo free(sc->cur_y, M_USB); 673199086Srpaulo sc->cur_y = NULL; 674199086Srpaulo } 675199086Srpaulo 676199086Srpaulo if (sc->pressure_y != NULL) { 677199086Srpaulo free(sc->pressure_y, M_USB); 678199086Srpaulo sc->pressure_y = NULL; 679199086Srpaulo } 680199086Srpaulo } 681199086Srpaulo if (sc->sensor_data != NULL) { 682199086Srpaulo free(sc->sensor_data, M_USB); 683199086Srpaulo sc->sensor_data = NULL; 684199086Srpaulo } 685199086Srpaulo} 686199086Srpaulo 687199086Srpaulo/* 688199086Srpaulo * Interpret the data from the X and Y pressure sensors. This function 689199086Srpaulo * is called separately for the X and Y sensor arrays. The data in the 690199086Srpaulo * USB packet is laid out in the following manner: 691199086Srpaulo * 692199086Srpaulo * sensor_data: 693199086Srpaulo * --,--,Y1,Y2,--,Y3,Y4,--,Y5,...,Y10, ... X1,X2,--,X3,X4 694199086Srpaulo * indices: 0 1 2 3 4 5 6 7 8 ... 15 ... 20 21 22 23 24 695199086Srpaulo * 696199086Srpaulo * '--' (in the above) indicates that the value is unimportant. 697199086Srpaulo * 698199086Srpaulo * Information about the above layout was obtained from the 699199086Srpaulo * implementation of the AppleTouch driver in Linux. 700199086Srpaulo * 701199086Srpaulo * parameters: 702199086Srpaulo * sensor_data 703199086Srpaulo * raw sensor data from the USB packet. 704199086Srpaulo * num 705199086Srpaulo * The number of elements in the array 'arr'. 706199151Snwhitehorn * axis 707199151Snwhitehorn * Axis of data to fetch 708199086Srpaulo * arr 709199086Srpaulo * The array to be initialized with the readings. 710199151Snwhitehorn * prot 711199151Snwhitehorn * The protocol to use to interpret the data 712199086Srpaulo */ 713199086Srpaulostatic __inline void 714199151Snwhitehornatp_interpret_sensor_data(const int8_t *sensor_data, u_int num, atp_axis axis, 715199151Snwhitehorn int *arr, atp_protocol prot) 716199086Srpaulo{ 717199086Srpaulo u_int i; 718199086Srpaulo u_int di; /* index into sensor data */ 719199086Srpaulo 720199151Snwhitehorn switch (prot) { 721199151Snwhitehorn case ATP_PROT_GEYSER1: 722199151Snwhitehorn /* 723199151Snwhitehorn * For Geyser 1, the sensors are laid out in pairs 724199151Snwhitehorn * every 5 bytes. 725199151Snwhitehorn */ 726199151Snwhitehorn for (i = 0, di = (axis == Y) ? 1 : 2; i < 8; di += 5, i++) { 727199151Snwhitehorn arr[i] = sensor_data[di]; 728199151Snwhitehorn arr[i+8] = sensor_data[di+2]; 729200241Srpaulo if (axis == X && num > 16) 730199151Snwhitehorn arr[i+16] = sensor_data[di+40]; 731199151Snwhitehorn } 732199151Snwhitehorn 733199151Snwhitehorn break; 734199151Snwhitehorn case ATP_PROT_GEYSER2: 735199151Snwhitehorn case ATP_PROT_GEYSER3: 736199151Snwhitehorn for (i = 0, di = (axis == Y) ? 2 : 20; i < num; /* empty */ ) { 737199151Snwhitehorn arr[i++] = sensor_data[di++]; 738199151Snwhitehorn arr[i++] = sensor_data[di++]; 739199151Snwhitehorn di++; 740199151Snwhitehorn } 741199151Snwhitehorn break; 742199086Srpaulo } 743199086Srpaulo} 744199086Srpaulo 745199086Srpaulostatic __inline void 746199086Srpauloatp_get_pressures(int *p, const int *cur, const int *base, int n) 747199086Srpaulo{ 748199086Srpaulo int i; 749199086Srpaulo 750199086Srpaulo for (i = 0; i < n; i++) { 751199086Srpaulo p[i] = cur[i] - base[i]; 752199086Srpaulo if (p[i] > 127) 753199086Srpaulo p[i] -= 256; 754199086Srpaulo if (p[i] < -127) 755199086Srpaulo p[i] += 256; 756199086Srpaulo if (p[i] < 0) 757199086Srpaulo p[i] = 0; 758199086Srpaulo 759199086Srpaulo /* 760199086Srpaulo * Shave off pressures below the noise-pressure 761199086Srpaulo * threshold; this will reduce the contribution from 762199086Srpaulo * lower pressure readings. 763199086Srpaulo */ 764199086Srpaulo if (p[i] <= atp_sensor_noise_threshold) 765199086Srpaulo p[i] = 0; /* filter away noise */ 766199086Srpaulo else 767199086Srpaulo p[i] -= atp_sensor_noise_threshold; 768199086Srpaulo } 769199086Srpaulo} 770199086Srpaulo 771199086Srpaulostatic void 772199086Srpauloatp_detect_pspans(int *p, u_int num_sensors, 773199086Srpaulo u_int max_spans, /* max # of pspans permitted */ 774199086Srpaulo atp_pspan *spans, /* finger spans */ 775199086Srpaulo u_int *nspans_p) /* num spans detected */ 776199086Srpaulo{ 777199086Srpaulo u_int i; 778199086Srpaulo int maxp; /* max pressure seen within a span */ 779199086Srpaulo u_int num_spans = 0; 780199086Srpaulo 781199086Srpaulo enum atp_pspan_state { 782199086Srpaulo ATP_PSPAN_INACTIVE, 783199086Srpaulo ATP_PSPAN_INCREASING, 784199086Srpaulo ATP_PSPAN_DECREASING, 785199086Srpaulo } state; /* state of the pressure span */ 786199086Srpaulo 787199086Srpaulo /* 788199086Srpaulo * The following is a simple state machine to track 789199086Srpaulo * the phase of the pressure span. 790199086Srpaulo */ 791199086Srpaulo memset(spans, 0, max_spans * sizeof(atp_pspan)); 792199086Srpaulo maxp = 0; 793199086Srpaulo state = ATP_PSPAN_INACTIVE; 794199086Srpaulo for (i = 0; i < num_sensors; i++) { 795199086Srpaulo if (num_spans >= max_spans) 796199086Srpaulo break; 797199086Srpaulo 798199086Srpaulo if (p[i] == 0) { 799199086Srpaulo if (state == ATP_PSPAN_INACTIVE) { 800199086Srpaulo /* 801199086Srpaulo * There is no pressure information for this 802199086Srpaulo * sensor, and we aren't tracking a finger. 803199086Srpaulo */ 804199086Srpaulo continue; 805199086Srpaulo } else { 806199086Srpaulo state = ATP_PSPAN_INACTIVE; 807199086Srpaulo maxp = 0; 808199086Srpaulo num_spans++; 809199086Srpaulo } 810199086Srpaulo } else { 811199086Srpaulo switch (state) { 812199086Srpaulo case ATP_PSPAN_INACTIVE: 813199086Srpaulo state = ATP_PSPAN_INCREASING; 814199086Srpaulo maxp = p[i]; 815199086Srpaulo break; 816199086Srpaulo 817199086Srpaulo case ATP_PSPAN_INCREASING: 818199086Srpaulo if (p[i] > maxp) 819199086Srpaulo maxp = p[i]; 820199086Srpaulo else if (p[i] <= (maxp >> 1)) 821199086Srpaulo state = ATP_PSPAN_DECREASING; 822199086Srpaulo break; 823199086Srpaulo 824199086Srpaulo case ATP_PSPAN_DECREASING: 825199086Srpaulo if (p[i] > p[i - 1]) { 826199086Srpaulo /* 827199086Srpaulo * This is the beginning of 828199086Srpaulo * another span; change state 829199086Srpaulo * to give the appearance that 830199086Srpaulo * we're starting from an 831199086Srpaulo * inactive span, and then 832199086Srpaulo * re-process this reading in 833199086Srpaulo * the next iteration. 834199086Srpaulo */ 835199086Srpaulo num_spans++; 836199086Srpaulo state = ATP_PSPAN_INACTIVE; 837199086Srpaulo maxp = 0; 838199086Srpaulo i--; 839199086Srpaulo continue; 840199086Srpaulo } 841199086Srpaulo break; 842199086Srpaulo } 843199086Srpaulo 844199086Srpaulo /* Update the finger span with this reading. */ 845199086Srpaulo spans[num_spans].width++; 846199086Srpaulo spans[num_spans].cum += p[i]; 847199086Srpaulo spans[num_spans].cog += p[i] * (i + 1); 848199086Srpaulo } 849199086Srpaulo } 850199086Srpaulo if (state != ATP_PSPAN_INACTIVE) 851199086Srpaulo num_spans++; /* close the last finger span */ 852199086Srpaulo 853199086Srpaulo /* post-process the spans */ 854199086Srpaulo for (i = 0; i < num_spans; i++) { 855199086Srpaulo /* filter away unwanted pressure spans */ 856199086Srpaulo if ((spans[i].cum < atp_pspan_min_cum_pressure) || 857199086Srpaulo (spans[i].width > atp_pspan_max_width)) { 858199086Srpaulo if ((i + 1) < num_spans) { 859199086Srpaulo memcpy(&spans[i], &spans[i + 1], 860199086Srpaulo (num_spans - i - 1) * sizeof(atp_pspan)); 861199086Srpaulo i--; 862199086Srpaulo } 863199086Srpaulo num_spans--; 864199086Srpaulo continue; 865199086Srpaulo } 866199086Srpaulo 867199086Srpaulo /* compute this span's representative location */ 868199086Srpaulo spans[i].loc = spans[i].cog * atp_mickeys_scale_factor / 869199086Srpaulo spans[i].cum; 870199086Srpaulo 871199086Srpaulo spans[i].matched = FALSE; /* not yet matched against a stroke */ 872199086Srpaulo } 873199086Srpaulo 874199086Srpaulo *nspans_p = num_spans; 875199086Srpaulo} 876199086Srpaulo 877199086Srpaulo/* 878199086Srpaulo * Match a pressure-span against a stroke-component. If there is a 879199086Srpaulo * match, update the component's state and return TRUE. 880199086Srpaulo */ 881199086Srpaulostatic boolean_t 882199086Srpauloatp_match_stroke_component(atp_stroke_component *component, 883200241Srpaulo const atp_pspan *pspan, atp_stroke_type stroke_type) 884199086Srpaulo{ 885200241Srpaulo int delta_mickeys; 886200241Srpaulo u_int min_pressure; 887199086Srpaulo 888200241Srpaulo delta_mickeys = pspan->loc - component->loc; 889200241Srpaulo 890199086Srpaulo if (abs(delta_mickeys) > atp_max_delta_mickeys) 891199086Srpaulo return (FALSE); /* the finger span is too far out; no match */ 892199086Srpaulo 893199086Srpaulo component->loc = pspan->loc; 894200241Srpaulo 895200241Srpaulo /* 896200241Srpaulo * A sudden and significant increase in a pspan's cumulative 897200241Srpaulo * pressure indicates the incidence of a new finger 898200241Srpaulo * contact. This usually revises the pspan's 899200241Srpaulo * centre-of-gravity, and hence the location of any/all 900200241Srpaulo * matching stroke component(s). But such a change should 901200241Srpaulo * *not* be interpreted as a movement. 902200241Srpaulo */ 903200241Srpaulo if (pspan->cum > ((3 * component->cum_pressure) >> 1)) 904200241Srpaulo delta_mickeys = 0; 905200241Srpaulo 906199086Srpaulo component->cum_pressure = pspan->cum; 907199086Srpaulo if (pspan->cum > component->max_cum_pressure) 908199086Srpaulo component->max_cum_pressure = pspan->cum; 909199086Srpaulo 910199086Srpaulo /* 911200241Srpaulo * Disregard the component's movement if its cumulative 912200241Srpaulo * pressure drops below a fraction of the maximum; this 913200241Srpaulo * fraction is determined based on the stroke's type. 914199086Srpaulo */ 915200241Srpaulo if (stroke_type == ATP_STROKE_TOUCH) 916200241Srpaulo min_pressure = (3 * component->max_cum_pressure) >> 2; 917200241Srpaulo else 918200241Srpaulo min_pressure = component->max_cum_pressure >> 2; 919200241Srpaulo if (component->cum_pressure < min_pressure) 920199086Srpaulo delta_mickeys = 0; 921199086Srpaulo 922199086Srpaulo component->delta_mickeys = delta_mickeys; 923199086Srpaulo return (TRUE); 924199086Srpaulo} 925199086Srpaulo 926199086Srpaulostatic void 927199086Srpauloatp_match_strokes_against_pspans(struct atp_softc *sc, atp_axis axis, 928199086Srpaulo atp_pspan *pspans, u_int n_pspans, u_int repeat_count) 929199086Srpaulo{ 930199086Srpaulo u_int i, j; 931199086Srpaulo u_int repeat_index = 0; 932199086Srpaulo 933199086Srpaulo /* Determine the index of the multi-span. */ 934199086Srpaulo if (repeat_count) { 935199086Srpaulo u_int cum = 0; 936199086Srpaulo for (i = 0; i < n_pspans; i++) { 937199086Srpaulo if (pspans[i].cum > cum) { 938199086Srpaulo repeat_index = i; 939199086Srpaulo cum = pspans[i].cum; 940199086Srpaulo } 941199086Srpaulo } 942199086Srpaulo } 943199086Srpaulo 944199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 945199086Srpaulo atp_stroke *stroke = &sc->sc_strokes[i]; 946199086Srpaulo if (stroke->components[axis].matched) 947199086Srpaulo continue; /* skip matched components */ 948199086Srpaulo 949199086Srpaulo for (j = 0; j < n_pspans; j++) { 950199086Srpaulo if (pspans[j].matched) 951199086Srpaulo continue; /* skip matched pspans */ 952199086Srpaulo 953199086Srpaulo if (atp_match_stroke_component( 954200241Srpaulo &stroke->components[axis], &pspans[j], 955200241Srpaulo stroke->type)) { 956199086Srpaulo /* There is a match. */ 957199086Srpaulo stroke->components[axis].matched = TRUE; 958199086Srpaulo 959199086Srpaulo /* Take care to repeat at the multi-span. */ 960199086Srpaulo if ((repeat_count > 0) && (j == repeat_index)) 961199086Srpaulo repeat_count--; 962199086Srpaulo else 963199086Srpaulo pspans[j].matched = TRUE; 964199086Srpaulo 965199086Srpaulo break; /* skip to the next stroke */ 966199086Srpaulo } 967199086Srpaulo } /* loop over pspans */ 968199086Srpaulo } /* loop over strokes */ 969199086Srpaulo} 970199086Srpaulo 971199086Srpaulo/* 972199086Srpaulo * Update strokes by matching against current pressure-spans. 973199086Srpaulo * Return TRUE if any movement is detected. 974199086Srpaulo */ 975199086Srpaulostatic boolean_t 976199086Srpauloatp_update_strokes(struct atp_softc *sc, atp_pspan *pspans_x, 977199086Srpaulo u_int n_xpspans, atp_pspan *pspans_y, u_int n_ypspans) 978199086Srpaulo{ 979199086Srpaulo u_int i, j; 980199086Srpaulo atp_stroke *stroke; 981199086Srpaulo boolean_t movement = FALSE; 982199086Srpaulo u_int repeat_count = 0; 983199086Srpaulo 984199086Srpaulo /* Reset X and Y components of all strokes as unmatched. */ 985199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 986199086Srpaulo stroke = &sc->sc_strokes[i]; 987199086Srpaulo stroke->components[X].matched = FALSE; 988199086Srpaulo stroke->components[Y].matched = FALSE; 989199086Srpaulo } 990199086Srpaulo 991199086Srpaulo /* 992199086Srpaulo * Usually, the X and Y pspans come in pairs (the common case 993199086Srpaulo * being a single pair). It is possible, however, that 994199086Srpaulo * multiple contacts resolve to a single pspan along an 995199086Srpaulo * axis, as illustrated in the following: 996199086Srpaulo * 997199086Srpaulo * F = finger-contact 998199086Srpaulo * 999199086Srpaulo * pspan pspan 1000199086Srpaulo * +-----------------------+ 1001199086Srpaulo * | . . | 1002199086Srpaulo * | . . | 1003199086Srpaulo * | . . | 1004199086Srpaulo * | . . | 1005199086Srpaulo * pspan |.........F......F | 1006199086Srpaulo * | | 1007199086Srpaulo * | | 1008199086Srpaulo * | | 1009199086Srpaulo * +-----------------------+ 1010199086Srpaulo * 1011199086Srpaulo * 1012199086Srpaulo * The above case can be detected by a difference in the 1013199086Srpaulo * number of X and Y pspans. When this happens, X and Y pspans 1014199086Srpaulo * aren't easy to pair or match against strokes. 1015199086Srpaulo * 1016199086Srpaulo * When X and Y pspans differ in number, the axis with the 1017199086Srpaulo * smaller number of pspans is regarded as having a repeating 1018199086Srpaulo * pspan (or a multi-pspan)--in the above illustration, the 1019199086Srpaulo * Y-axis has a repeating pspan. Our approach is to try to 1020199086Srpaulo * match the multi-pspan repeatedly against strokes. The 1021199086Srpaulo * difference between the number of X and Y pspans gives us a 1022199086Srpaulo * crude repeat_count for matching multi-pspans--i.e. the 1023199086Srpaulo * multi-pspan along the Y axis (above) has a repeat_count of 1. 1024199086Srpaulo */ 1025199086Srpaulo repeat_count = abs(n_xpspans - n_ypspans); 1026199086Srpaulo 1027199086Srpaulo atp_match_strokes_against_pspans(sc, X, pspans_x, n_xpspans, 1028199086Srpaulo (((repeat_count != 0) && ((n_xpspans < n_ypspans))) ? 1029199086Srpaulo repeat_count : 0)); 1030199086Srpaulo atp_match_strokes_against_pspans(sc, Y, pspans_y, n_ypspans, 1031199086Srpaulo (((repeat_count != 0) && (n_ypspans < n_xpspans)) ? 1032199086Srpaulo repeat_count : 0)); 1033199086Srpaulo 1034199086Srpaulo /* Update the state of strokes based on the above pspan matches. */ 1035199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1036199086Srpaulo stroke = &sc->sc_strokes[i]; 1037199086Srpaulo if (stroke->components[X].matched && 1038199086Srpaulo stroke->components[Y].matched) { 1039199086Srpaulo atp_advance_stroke_state(sc, stroke, &movement); 1040199086Srpaulo } else { 1041199086Srpaulo /* 1042199086Srpaulo * At least one component of this stroke 1043199086Srpaulo * didn't match against current pspans; 1044199086Srpaulo * terminate it. 1045199086Srpaulo */ 1046199086Srpaulo atp_terminate_stroke(sc, i); 1047199086Srpaulo } 1048199086Srpaulo } 1049199086Srpaulo 1050199086Srpaulo /* Add new strokes for pairs of unmatched pspans */ 1051199086Srpaulo for (i = 0; i < n_xpspans; i++) { 1052199086Srpaulo if (pspans_x[i].matched == FALSE) break; 1053199086Srpaulo } 1054199086Srpaulo for (j = 0; j < n_ypspans; j++) { 1055199086Srpaulo if (pspans_y[j].matched == FALSE) break; 1056199086Srpaulo } 1057199086Srpaulo if ((i < n_xpspans) && (j < n_ypspans)) { 1058199086Srpaulo#if USB_DEBUG 1059199086Srpaulo if (atp_debug >= ATP_LLEVEL_INFO) { 1060199086Srpaulo printf("unmatched pspans:"); 1061199086Srpaulo for (; i < n_xpspans; i++) { 1062199086Srpaulo if (pspans_x[i].matched) 1063199086Srpaulo continue; 1064199086Srpaulo printf(" X:[loc:%u,cum:%u]", 1065199086Srpaulo pspans_x[i].loc, pspans_x[i].cum); 1066199086Srpaulo } 1067199086Srpaulo for (; j < n_ypspans; j++) { 1068199086Srpaulo if (pspans_y[j].matched) 1069199086Srpaulo continue; 1070199086Srpaulo printf(" Y:[loc:%u,cum:%u]", 1071199086Srpaulo pspans_y[j].loc, pspans_y[j].cum); 1072199086Srpaulo } 1073199086Srpaulo printf("\n"); 1074199086Srpaulo } 1075199086Srpaulo#endif /* #if USB_DEBUG */ 1076199086Srpaulo if ((n_xpspans == 1) && (n_ypspans == 1)) 1077199086Srpaulo /* The common case of a single pair of new pspans. */ 1078199086Srpaulo atp_add_stroke(sc, &pspans_x[0], &pspans_y[0]); 1079199086Srpaulo else 1080199086Srpaulo atp_add_new_strokes(sc, 1081199086Srpaulo pspans_x, n_xpspans, 1082199086Srpaulo pspans_y, n_ypspans); 1083199086Srpaulo } 1084199086Srpaulo 1085199086Srpaulo#if USB_DEBUG 1086199086Srpaulo if (atp_debug >= ATP_LLEVEL_INFO) { 1087199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1088199086Srpaulo atp_stroke *stroke = &sc->sc_strokes[i]; 1089199086Srpaulo 1090200241Srpaulo printf(" %s%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c" 1091200241Srpaulo ",%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c", 1092199086Srpaulo (stroke->flags & ATSF_ZOMBIE) ? "zomb:" : "", 1093199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<', 1094199086Srpaulo stroke->components[X].loc, 1095199086Srpaulo stroke->components[X].delta_mickeys, 1096199086Srpaulo stroke->components[X].pending, 1097200241Srpaulo stroke->components[X].cum_pressure, 1098200241Srpaulo stroke->components[X].max_cum_pressure, 1099199086Srpaulo stroke->components[X].movement, 1100199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>', 1101199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<', 1102199086Srpaulo stroke->components[Y].loc, 1103199086Srpaulo stroke->components[Y].delta_mickeys, 1104199086Srpaulo stroke->components[Y].pending, 1105200241Srpaulo stroke->components[Y].cum_pressure, 1106200241Srpaulo stroke->components[Y].max_cum_pressure, 1107199086Srpaulo stroke->components[Y].movement, 1108199086Srpaulo (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>'); 1109199086Srpaulo } 1110199086Srpaulo if (sc->sc_n_strokes) 1111199086Srpaulo printf("\n"); 1112199086Srpaulo } 1113199086Srpaulo#endif /* #if USB_DEBUG */ 1114199086Srpaulo 1115199086Srpaulo return (movement); 1116199086Srpaulo} 1117199086Srpaulo 1118199086Srpaulo/* Initialize a stroke using a pressure-span. */ 1119199086Srpaulostatic __inline void 1120199086Srpauloatp_add_stroke(struct atp_softc *sc, const atp_pspan *pspan_x, 1121199086Srpaulo const atp_pspan *pspan_y) 1122199086Srpaulo{ 1123199086Srpaulo atp_stroke *stroke; 1124199086Srpaulo 1125199086Srpaulo if (sc->sc_n_strokes >= ATP_MAX_STROKES) 1126199086Srpaulo return; 1127199086Srpaulo stroke = &sc->sc_strokes[sc->sc_n_strokes]; 1128199086Srpaulo 1129199086Srpaulo memset(stroke, 0, sizeof(atp_stroke)); 1130199086Srpaulo 1131199086Srpaulo /* 1132199086Srpaulo * Strokes begin as potential touches. If a stroke survives 1133199086Srpaulo * longer than a threshold, or if it records significant 1134199086Srpaulo * cumulative movement, then it is considered a 'slide'. 1135199086Srpaulo */ 1136199086Srpaulo stroke->type = ATP_STROKE_TOUCH; 1137199086Srpaulo microtime(&stroke->ctime); 1138199086Srpaulo stroke->age = 1; /* Unit: interrupts */ 1139199086Srpaulo 1140199086Srpaulo stroke->components[X].loc = pspan_x->loc; 1141199086Srpaulo stroke->components[X].cum_pressure = pspan_x->cum; 1142199086Srpaulo stroke->components[X].max_cum_pressure = pspan_x->cum; 1143199086Srpaulo stroke->components[X].matched = TRUE; 1144199086Srpaulo 1145199086Srpaulo stroke->components[Y].loc = pspan_y->loc; 1146199086Srpaulo stroke->components[Y].cum_pressure = pspan_y->cum; 1147199086Srpaulo stroke->components[Y].max_cum_pressure = pspan_y->cum; 1148199086Srpaulo stroke->components[Y].matched = TRUE; 1149199086Srpaulo 1150199086Srpaulo sc->sc_n_strokes++; 1151199086Srpaulo if (sc->sc_n_strokes > 1) { 1152199086Srpaulo /* Reset double-tap-n-drag if we have more than one strokes. */ 1153199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1154199086Srpaulo } 1155199086Srpaulo 1156199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "[%u,%u], time: %u,%ld\n", 1157199086Srpaulo stroke->components[X].loc, 1158199086Srpaulo stroke->components[Y].loc, 1159199086Srpaulo (unsigned int)stroke->ctime.tv_sec, 1160199086Srpaulo (unsigned long int)stroke->ctime.tv_usec); 1161199086Srpaulo} 1162199086Srpaulo 1163199086Srpaulostatic void 1164199086Srpauloatp_add_new_strokes(struct atp_softc *sc, atp_pspan *pspans_x, 1165199086Srpaulo u_int n_xpspans, atp_pspan *pspans_y, u_int n_ypspans) 1166199086Srpaulo{ 1167199086Srpaulo int i, j; 1168199086Srpaulo atp_pspan spans[2][ATP_MAX_PSPANS_PER_AXIS]; 1169199086Srpaulo u_int nspans[2]; 1170199086Srpaulo 1171199086Srpaulo /* Copy unmatched pspans into the local arrays. */ 1172199086Srpaulo for (i = 0, nspans[X] = 0; i < n_xpspans; i++) { 1173199086Srpaulo if (pspans_x[i].matched == FALSE) { 1174199086Srpaulo spans[X][nspans[X]] = pspans_x[i]; 1175199086Srpaulo nspans[X]++; 1176199086Srpaulo } 1177199086Srpaulo } 1178199086Srpaulo for (j = 0, nspans[Y] = 0; j < n_ypspans; j++) { 1179199086Srpaulo if (pspans_y[j].matched == FALSE) { 1180199086Srpaulo spans[Y][nspans[Y]] = pspans_y[j]; 1181199086Srpaulo nspans[Y]++; 1182199086Srpaulo } 1183199086Srpaulo } 1184199086Srpaulo 1185199086Srpaulo if (nspans[X] == nspans[Y]) { 1186199086Srpaulo /* Create new strokes from pairs of unmatched pspans */ 1187199086Srpaulo for (i = 0, j = 0; (i < nspans[X]) && (j < nspans[Y]); i++, j++) 1188199086Srpaulo atp_add_stroke(sc, &spans[X][i], &spans[Y][j]); 1189199086Srpaulo } else { 1190199086Srpaulo u_int cum = 0; 1191199086Srpaulo atp_axis repeat_axis; /* axis with multi-pspans */ 1192199086Srpaulo u_int repeat_count; /* repeat count for the multi-pspan*/ 1193199086Srpaulo u_int repeat_index = 0; /* index of the multi-span */ 1194199086Srpaulo 1195199086Srpaulo repeat_axis = (nspans[X] > nspans[Y]) ? Y : X; 1196199086Srpaulo repeat_count = abs(nspans[X] - nspans[Y]); 1197199086Srpaulo for (i = 0; i < nspans[repeat_axis]; i++) { 1198199086Srpaulo if (spans[repeat_axis][i].cum > cum) { 1199199086Srpaulo repeat_index = i; 1200199086Srpaulo cum = spans[repeat_axis][i].cum; 1201199086Srpaulo } 1202199086Srpaulo } 1203199086Srpaulo 1204199086Srpaulo /* Create new strokes from pairs of unmatched pspans */ 1205199086Srpaulo i = 0, j = 0; 1206199086Srpaulo for (; (i < nspans[X]) && (j < nspans[Y]); i++, j++) { 1207199086Srpaulo atp_add_stroke(sc, &spans[X][i], &spans[Y][j]); 1208199086Srpaulo 1209199086Srpaulo /* Take care to repeat at the multi-pspan. */ 1210199086Srpaulo if (repeat_count > 0) { 1211199086Srpaulo if ((repeat_axis == X) && 1212199086Srpaulo (repeat_index == i)) { 1213199086Srpaulo i--; /* counter loop increment */ 1214199086Srpaulo repeat_count--; 1215199086Srpaulo } else if ((repeat_axis == Y) && 1216199086Srpaulo (repeat_index == j)) { 1217199086Srpaulo j--; /* counter loop increment */ 1218199086Srpaulo repeat_count--; 1219199086Srpaulo } 1220199086Srpaulo } 1221199086Srpaulo } 1222199086Srpaulo } 1223199086Srpaulo} 1224199086Srpaulo 1225199086Srpaulo/* 1226199086Srpaulo * Advance the state of this stroke--and update the out-parameter 1227199086Srpaulo * 'movement' as a side-effect. 1228199086Srpaulo */ 1229199086Srpaulovoid 1230199086Srpauloatp_advance_stroke_state(struct atp_softc *sc, atp_stroke *stroke, 1231199086Srpaulo boolean_t *movement) 1232199086Srpaulo{ 1233199086Srpaulo stroke->age++; 1234199086Srpaulo if (stroke->age <= atp_stroke_maturity_threshold) { 1235199086Srpaulo /* Avoid noise from immature strokes. */ 1236199086Srpaulo stroke->components[X].delta_mickeys = 0; 1237199086Srpaulo stroke->components[Y].delta_mickeys = 0; 1238199086Srpaulo } 1239199086Srpaulo 1240199086Srpaulo /* Revitalize stroke if it had previously been marked as a zombie. */ 1241199086Srpaulo if (stroke->flags & ATSF_ZOMBIE) 1242199086Srpaulo stroke->flags &= ~ATSF_ZOMBIE; 1243199086Srpaulo 1244199086Srpaulo if (atp_compute_stroke_movement(stroke)) 1245199086Srpaulo *movement = TRUE; 1246199086Srpaulo 1247200241Srpaulo if (stroke->type != ATP_STROKE_TOUCH) 1248200241Srpaulo return; 1249200241Srpaulo 1250199086Srpaulo /* Convert touch strokes to slides upon detecting movement or age. */ 1251200241Srpaulo if (stroke->cum_movement >= atp_slide_min_movement) { 1252200241Srpaulo atp_convert_to_slide(sc, stroke); 1253200241Srpaulo } else { 1254200241Srpaulo /* If a touch stroke is found to be older than the 1255200241Srpaulo * touch-timeout threshold, it should be converted to 1256200241Srpaulo * a slide; except if there is a co-incident sibling 1257200241Srpaulo * with a later creation time. 1258200241Srpaulo * 1259200241Srpaulo * When multiple fingers make contact with the 1260200241Srpaulo * touchpad, they are likely to be separated in their 1261200241Srpaulo * times of incidence. During a multi-finger tap, 1262200241Srpaulo * therefore, the last finger to make 1263200241Srpaulo * contact--i.e. the one with the latest 1264200241Srpaulo * 'ctime'--should be used to determine how the 1265200241Srpaulo * touch-siblings get treated; otherwise older 1266200241Srpaulo * siblings may lapse the touch-timeout and get 1267200241Srpaulo * converted into slides prematurely. The following 1268200241Srpaulo * loop determines if there exists another touch 1269200241Srpaulo * stroke with a larger 'ctime' than the current 1270200241Srpaulo * stroke (NOTE: zombies with a larger 'ctime' are 1271200241Srpaulo * also considered) . 1272200241Srpaulo */ 1273199086Srpaulo 1274200241Srpaulo u_int i; 1275200241Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1276200241Srpaulo if ((&sc->sc_strokes[i] == stroke) || 1277200241Srpaulo (sc->sc_strokes[i].type != ATP_STROKE_TOUCH)) 1278200241Srpaulo continue; 1279200241Srpaulo 1280200241Srpaulo if (timevalcmp(&sc->sc_strokes[i].ctime, 1281200241Srpaulo &stroke->ctime, >)) 1282200241Srpaulo break; 1283199086Srpaulo } 1284200241Srpaulo if (i == sc->sc_n_strokes) { 1285200241Srpaulo /* Found no other touch stroke with a larger 'ctime'. */ 1286200241Srpaulo struct timeval tdiff; 1287199086Srpaulo 1288200241Srpaulo /* Compute the stroke's age. */ 1289200241Srpaulo getmicrotime(&tdiff); 1290200241Srpaulo if (timevalcmp(&tdiff, &stroke->ctime, >)) 1291200241Srpaulo timevalsub(&tdiff, &stroke->ctime); 1292200241Srpaulo else { 1293200241Srpaulo /* 1294200241Srpaulo * If we are here, it is because getmicrotime 1295200241Srpaulo * reported the current time as being behind 1296200241Srpaulo * the stroke's start time; getmicrotime can 1297200241Srpaulo * be imprecise. 1298200241Srpaulo */ 1299200241Srpaulo tdiff.tv_sec = 0; 1300200241Srpaulo tdiff.tv_usec = 0; 1301200241Srpaulo } 1302199086Srpaulo 1303200241Srpaulo if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) || 1304200241Srpaulo ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) && 1305200241Srpaulo (tdiff.tv_usec >= 1306200241Srpaulo (atp_touch_timeout % 1000000)))) 1307200241Srpaulo atp_convert_to_slide(sc, stroke); 1308199086Srpaulo } 1309199086Srpaulo } 1310199086Srpaulo} 1311199086Srpaulo 1312200241Srpaulo/* Switch a given touch stroke to being a slide. */ 1313200241Srpaulovoid 1314200241Srpauloatp_convert_to_slide(struct atp_softc *sc, atp_stroke *stroke) 1315200241Srpaulo{ 1316200241Srpaulo stroke->type = ATP_STROKE_SLIDE; 1317200241Srpaulo 1318200241Srpaulo /* Are we at the beginning of a double-click-n-drag? */ 1319200241Srpaulo if ((sc->sc_n_strokes == 1) && 1320200241Srpaulo ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) && 1321200241Srpaulo timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) { 1322200241Srpaulo struct timeval delta; 1323200241Srpaulo struct timeval window = { 1324200241Srpaulo atp_double_tap_threshold / 1000000, 1325200241Srpaulo atp_double_tap_threshold % 1000000 1326200241Srpaulo }; 1327200241Srpaulo 1328200241Srpaulo delta = stroke->ctime; 1329200241Srpaulo timevalsub(&delta, &sc->sc_reap_time); 1330200241Srpaulo if (timevalcmp(&delta, &window, <=)) 1331200241Srpaulo sc->sc_state |= ATP_DOUBLE_TAP_DRAG; 1332200241Srpaulo } 1333200241Srpaulo} 1334200241Srpaulo 1335199086Srpaulo/* 1336199086Srpaulo * Terminate a stroke. While SLIDE strokes are dropped, TOUCH strokes 1337199086Srpaulo * are retained as zombies so as to reap all their siblings together; 1338199086Srpaulo * this helps establish the number of fingers involved in the tap. 1339199086Srpaulo */ 1340199086Srpaulostatic void 1341199086Srpauloatp_terminate_stroke(struct atp_softc *sc, 1342199086Srpaulo u_int index) /* index of the stroke to be terminated */ 1343199086Srpaulo{ 1344199086Srpaulo atp_stroke *s = &sc->sc_strokes[index]; 1345199086Srpaulo 1346199086Srpaulo if (s->flags & ATSF_ZOMBIE) { 1347199086Srpaulo return; 1348199086Srpaulo } 1349199086Srpaulo 1350199086Srpaulo if ((s->type == ATP_STROKE_TOUCH) && 1351199086Srpaulo (s->age > atp_stroke_maturity_threshold)) { 1352199086Srpaulo s->flags |= ATSF_ZOMBIE; 1353199086Srpaulo 1354199086Srpaulo /* If no zombies exist, then prepare to reap zombies later. */ 1355199086Srpaulo if ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) { 1356199086Srpaulo atp_setup_reap_time(sc, &s->ctime); 1357199086Srpaulo sc->sc_state |= ATP_ZOMBIES_EXIST; 1358199086Srpaulo } 1359199086Srpaulo } else { 1360199086Srpaulo /* Drop this stroke. */ 1361199086Srpaulo memcpy(&sc->sc_strokes[index], &sc->sc_strokes[index + 1], 1362199086Srpaulo (sc->sc_n_strokes - index - 1) * sizeof(atp_stroke)); 1363199086Srpaulo sc->sc_n_strokes--; 1364199086Srpaulo 1365199086Srpaulo /* 1366199086Srpaulo * Reset the double-click-n-drag at the termination of 1367199086Srpaulo * any slide stroke. 1368199086Srpaulo */ 1369199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1370199086Srpaulo } 1371199086Srpaulo} 1372199086Srpaulo 1373199086Srpaulostatic __inline boolean_t 1374199086Srpauloatp_stroke_has_small_movement(const atp_stroke *stroke) 1375199086Srpaulo{ 1376199086Srpaulo return ((abs(stroke->components[X].delta_mickeys) <= 1377199086Srpaulo atp_small_movement_threshold) && 1378199086Srpaulo (abs(stroke->components[Y].delta_mickeys) <= 1379199086Srpaulo atp_small_movement_threshold)); 1380199086Srpaulo} 1381199086Srpaulo 1382199086Srpaulo/* 1383199086Srpaulo * Accumulate delta_mickeys into the component's 'pending' bucket; if 1384199086Srpaulo * the aggregate exceeds the small_movement_threshold, then retain 1385199086Srpaulo * delta_mickeys for later. 1386199086Srpaulo */ 1387199086Srpaulostatic __inline void 1388199086Srpauloatp_update_pending_mickeys(atp_stroke_component *component) 1389199086Srpaulo{ 1390199086Srpaulo component->pending += component->delta_mickeys; 1391199086Srpaulo if (abs(component->pending) <= atp_small_movement_threshold) 1392199086Srpaulo component->delta_mickeys = 0; 1393199086Srpaulo else { 1394199086Srpaulo /* 1395199086Srpaulo * Penalise pending mickeys for having accumulated 1396199086Srpaulo * over short deltas. This operation has the effect of 1397199086Srpaulo * scaling down the cumulative contribution of short 1398199086Srpaulo * movements. 1399199086Srpaulo */ 1400199086Srpaulo component->pending -= (component->delta_mickeys << 1); 1401199086Srpaulo } 1402199086Srpaulo} 1403199086Srpaulo 1404199086Srpaulo 1405199086Srpaulostatic void 1406199086Srpauloatp_compute_smoothening_scale_ratio(atp_stroke *stroke, int *numerator, 1407199086Srpaulo int *denominator) 1408199086Srpaulo{ 1409199086Srpaulo int dxdt; 1410199086Srpaulo int dydt; 1411199086Srpaulo u_int vel_squared; /* Square of the velocity vector's magnitude. */ 1412199086Srpaulo u_int vel_squared_smooth; 1413199086Srpaulo 1414199086Srpaulo /* Table holding (10 * sqrt(x)) for x between 1 and 256. */ 1415199086Srpaulo static uint8_t sqrt_table[256] = { 1416199086Srpaulo 10, 14, 17, 20, 22, 24, 26, 28, 1417199086Srpaulo 30, 31, 33, 34, 36, 37, 38, 40, 1418199086Srpaulo 41, 42, 43, 44, 45, 46, 47, 48, 1419199086Srpaulo 50, 50, 51, 52, 53, 54, 55, 56, 1420199086Srpaulo 57, 58, 59, 60, 60, 61, 62, 63, 1421199086Srpaulo 64, 64, 65, 66, 67, 67, 68, 69, 1422199086Srpaulo 70, 70, 71, 72, 72, 73, 74, 74, 1423199086Srpaulo 75, 76, 76, 77, 78, 78, 79, 80, 1424199086Srpaulo 80, 81, 81, 82, 83, 83, 84, 84, 1425199086Srpaulo 85, 86, 86, 87, 87, 88, 88, 89, 1426199086Srpaulo 90, 90, 91, 91, 92, 92, 93, 93, 1427199086Srpaulo 94, 94, 95, 95, 96, 96, 97, 97, 1428199086Srpaulo 98, 98, 99, 100, 100, 100, 101, 101, 1429199086Srpaulo 102, 102, 103, 103, 104, 104, 105, 105, 1430199086Srpaulo 106, 106, 107, 107, 108, 108, 109, 109, 1431199086Srpaulo 110, 110, 110, 111, 111, 112, 112, 113, 1432199086Srpaulo 113, 114, 114, 114, 115, 115, 116, 116, 1433199086Srpaulo 117, 117, 117, 118, 118, 119, 119, 120, 1434199086Srpaulo 120, 120, 121, 121, 122, 122, 122, 123, 1435199086Srpaulo 123, 124, 124, 124, 125, 125, 126, 126, 1436199086Srpaulo 126, 127, 127, 128, 128, 128, 129, 129, 1437199086Srpaulo 130, 130, 130, 131, 131, 131, 132, 132, 1438199086Srpaulo 133, 133, 133, 134, 134, 134, 135, 135, 1439199086Srpaulo 136, 136, 136, 137, 137, 137, 138, 138, 1440199086Srpaulo 138, 139, 139, 140, 140, 140, 141, 141, 1441199086Srpaulo 141, 142, 142, 142, 143, 143, 143, 144, 1442199086Srpaulo 144, 144, 145, 145, 145, 146, 146, 146, 1443199086Srpaulo 147, 147, 147, 148, 148, 148, 149, 149, 1444199086Srpaulo 150, 150, 150, 150, 151, 151, 151, 152, 1445199086Srpaulo 152, 152, 153, 153, 153, 154, 154, 154, 1446199086Srpaulo 155, 155, 155, 156, 156, 156, 157, 157, 1447199086Srpaulo 157, 158, 158, 158, 159, 159, 159, 160 1448199086Srpaulo }; 1449199086Srpaulo const u_int N = sizeof(sqrt_table) / sizeof(sqrt_table[0]); 1450199086Srpaulo 1451199086Srpaulo dxdt = stroke->components[X].delta_mickeys; 1452199086Srpaulo dydt = stroke->components[Y].delta_mickeys; 1453199086Srpaulo 1454199086Srpaulo *numerator = 0, *denominator = 0; /* default values. */ 1455199086Srpaulo 1456199086Srpaulo /* Compute a smoothened magnitude_squared of the stroke's velocity. */ 1457199086Srpaulo vel_squared = dxdt * dxdt + dydt * dydt; 1458199086Srpaulo vel_squared_smooth = (3 * stroke->velocity_squared + vel_squared) >> 2; 1459199086Srpaulo stroke->velocity_squared = vel_squared_smooth; /* retained as history */ 1460199086Srpaulo if ((vel_squared == 0) || (vel_squared_smooth == 0)) 1461199086Srpaulo return; /* returning (numerator == 0) will imply zero movement*/ 1462199086Srpaulo 1463199086Srpaulo /* 1464199086Srpaulo * In order to determine the overall movement scale factor, 1465199086Srpaulo * we're actually interested in the effect of smoothening upon 1466199086Srpaulo * the *magnitude* of velocity; i.e. we need to compute the 1467199086Srpaulo * square-root of (vel_squared_smooth / vel_squared) in the 1468199086Srpaulo * form of a numerator and denominator. 1469199086Srpaulo */ 1470199086Srpaulo 1471199086Srpaulo /* Keep within the bounds of the square-root table. */ 1472199086Srpaulo while ((vel_squared > N) || (vel_squared_smooth > N)) { 1473199086Srpaulo /* Dividing uniformly by 2 won't disturb the final ratio. */ 1474199086Srpaulo vel_squared >>= 1; 1475199086Srpaulo vel_squared_smooth >>= 1; 1476199086Srpaulo } 1477199086Srpaulo 1478199086Srpaulo *numerator = sqrt_table[vel_squared_smooth - 1]; 1479199086Srpaulo *denominator = sqrt_table[vel_squared - 1]; 1480199086Srpaulo} 1481199086Srpaulo 1482199086Srpaulo/* 1483199086Srpaulo * Compute a smoothened value for the stroke's movement from 1484199086Srpaulo * delta_mickeys in the X and Y components. 1485199086Srpaulo */ 1486199086Srpaulostatic boolean_t 1487199086Srpauloatp_compute_stroke_movement(atp_stroke *stroke) 1488199086Srpaulo{ 1489199086Srpaulo int num; /* numerator of scale ratio */ 1490199086Srpaulo int denom; /* denominator of scale ratio */ 1491199086Srpaulo 1492199086Srpaulo /* 1493199086Srpaulo * Short movements are added first to the 'pending' bucket, 1494199086Srpaulo * and then acted upon only when their aggregate exceeds a 1495199086Srpaulo * threshold. This has the effect of filtering away movement 1496199086Srpaulo * noise. 1497199086Srpaulo */ 1498199086Srpaulo if (atp_stroke_has_small_movement(stroke)) { 1499199086Srpaulo atp_update_pending_mickeys(&stroke->components[X]); 1500199086Srpaulo atp_update_pending_mickeys(&stroke->components[Y]); 1501199086Srpaulo } else { /* large movement */ 1502199086Srpaulo /* clear away any pending mickeys if there are large movements*/ 1503199086Srpaulo stroke->components[X].pending = 0; 1504199086Srpaulo stroke->components[Y].pending = 0; 1505199086Srpaulo } 1506199086Srpaulo 1507199086Srpaulo /* Get the scale ratio and smoothen movement. */ 1508199086Srpaulo atp_compute_smoothening_scale_ratio(stroke, &num, &denom); 1509199086Srpaulo if ((num == 0) || (denom == 0)) { 1510199086Srpaulo stroke->components[X].movement = 0; 1511199086Srpaulo stroke->components[Y].movement = 0; 1512199086Srpaulo stroke->velocity_squared >>= 1; /* Erode velocity_squared. */ 1513199086Srpaulo } else { 1514199086Srpaulo stroke->components[X].movement = 1515199086Srpaulo (stroke->components[X].delta_mickeys * num) / denom; 1516199086Srpaulo stroke->components[Y].movement = 1517199086Srpaulo (stroke->components[Y].delta_mickeys * num) / denom; 1518199086Srpaulo 1519199086Srpaulo stroke->cum_movement += 1520199086Srpaulo abs(stroke->components[X].movement) + 1521199086Srpaulo abs(stroke->components[Y].movement); 1522199086Srpaulo } 1523199086Srpaulo 1524199086Srpaulo return ((stroke->components[X].movement != 0) || 1525199086Srpaulo (stroke->components[Y].movement != 0)); 1526199086Srpaulo} 1527199086Srpaulo 1528199086Srpaulostatic __inline void 1529199086Srpauloatp_setup_reap_time(struct atp_softc *sc, struct timeval *tvp) 1530199086Srpaulo{ 1531199086Srpaulo struct timeval reap_window = { 1532199086Srpaulo ATP_ZOMBIE_STROKE_REAP_WINDOW / 1000000, 1533199086Srpaulo ATP_ZOMBIE_STROKE_REAP_WINDOW % 1000000 1534199086Srpaulo }; 1535199086Srpaulo 1536199086Srpaulo microtime(&sc->sc_reap_time); 1537199086Srpaulo timevaladd(&sc->sc_reap_time, &reap_window); 1538199086Srpaulo 1539199086Srpaulo sc->sc_reap_ctime = *tvp; /* ctime to reap */ 1540199086Srpaulo} 1541199086Srpaulo 1542199086Srpaulostatic void 1543199086Srpauloatp_reap_zombies(struct atp_softc *sc, u_int *n_reaped, u_int *reaped_xlocs) 1544199086Srpaulo{ 1545199086Srpaulo u_int i; 1546199086Srpaulo atp_stroke *stroke; 1547199086Srpaulo 1548199086Srpaulo *n_reaped = 0; 1549199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1550199086Srpaulo struct timeval tdiff; 1551199086Srpaulo 1552199086Srpaulo stroke = &sc->sc_strokes[i]; 1553199086Srpaulo 1554199086Srpaulo if ((stroke->flags & ATSF_ZOMBIE) == 0) 1555199086Srpaulo continue; 1556199086Srpaulo 1557199086Srpaulo /* Compare this stroke's ctime with the ctime being reaped. */ 1558199086Srpaulo if (timevalcmp(&stroke->ctime, &sc->sc_reap_ctime, >=)) { 1559199086Srpaulo tdiff = stroke->ctime; 1560199086Srpaulo timevalsub(&tdiff, &sc->sc_reap_ctime); 1561199086Srpaulo } else { 1562199086Srpaulo tdiff = sc->sc_reap_ctime; 1563199086Srpaulo timevalsub(&tdiff, &stroke->ctime); 1564199086Srpaulo } 1565199086Srpaulo 1566199086Srpaulo if ((tdiff.tv_sec > (ATP_COINCIDENCE_THRESHOLD / 1000000)) || 1567199086Srpaulo ((tdiff.tv_sec == (ATP_COINCIDENCE_THRESHOLD / 1000000)) && 1568199086Srpaulo (tdiff.tv_usec > (ATP_COINCIDENCE_THRESHOLD % 1000000)))) { 1569199086Srpaulo continue; /* Skip non-siblings. */ 1570199086Srpaulo } 1571199086Srpaulo 1572199086Srpaulo /* 1573199086Srpaulo * Reap this sibling zombie stroke. 1574199086Srpaulo */ 1575199086Srpaulo 1576199086Srpaulo if (reaped_xlocs != NULL) 1577199086Srpaulo reaped_xlocs[*n_reaped] = stroke->components[X].loc; 1578199086Srpaulo 1579199086Srpaulo /* Erase the stroke from the sc. */ 1580199086Srpaulo memcpy(&stroke[i], &stroke[i + 1], 1581199086Srpaulo (sc->sc_n_strokes - i - 1) * sizeof(atp_stroke)); 1582199086Srpaulo sc->sc_n_strokes--; 1583199086Srpaulo 1584199086Srpaulo *n_reaped += 1; 1585199086Srpaulo --i; /* Decr. i to keep it unchanged for the next iteration */ 1586199086Srpaulo } 1587199086Srpaulo 1588199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "reaped %u zombies\n", *n_reaped); 1589199086Srpaulo 1590199086Srpaulo /* There could still be zombies remaining in the system. */ 1591199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1592199086Srpaulo stroke = &sc->sc_strokes[i]; 1593199086Srpaulo if (stroke->flags & ATSF_ZOMBIE) { 1594199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "zombies remain!\n"); 1595199086Srpaulo atp_setup_reap_time(sc, &stroke->ctime); 1596199086Srpaulo return; 1597199086Srpaulo } 1598199086Srpaulo } 1599199086Srpaulo 1600199086Srpaulo /* If we reach here, then no more zombies remain. */ 1601199086Srpaulo sc->sc_state &= ~ATP_ZOMBIES_EXIST; 1602199086Srpaulo} 1603199086Srpaulo 1604199086Srpaulo 1605199086Srpaulo/* Device methods. */ 1606199086Srpaulostatic device_probe_t atp_probe; 1607199086Srpaulostatic device_attach_t atp_attach; 1608199086Srpaulostatic device_detach_t atp_detach; 1609199086Srpaulostatic usb_callback_t atp_intr; 1610199086Srpaulo 1611199086Srpaulostatic const struct usb_config atp_config[ATP_N_TRANSFER] = { 1612199086Srpaulo [ATP_INTR_DT] = { 1613199086Srpaulo .type = UE_INTERRUPT, 1614199086Srpaulo .endpoint = UE_ADDR_ANY, 1615199086Srpaulo .direction = UE_DIR_IN, 1616199086Srpaulo .flags = { 1617199086Srpaulo .pipe_bof = 1, 1618199086Srpaulo .short_xfer_ok = 1, 1619199086Srpaulo }, 1620199086Srpaulo .bufsize = 0, /* use wMaxPacketSize */ 1621199086Srpaulo .callback = &atp_intr, 1622199086Srpaulo }, 1623199680Sthompsa [ATP_RESET] = { 1624199680Sthompsa .type = UE_CONTROL, 1625199680Sthompsa .endpoint = 0, /* Control pipe */ 1626199680Sthompsa .direction = UE_DIR_ANY, 1627199680Sthompsa .bufsize = sizeof(struct usb_device_request) + MODE_LENGTH, 1628199680Sthompsa .callback = &atp_reset_callback, 1629199680Sthompsa .interval = 0, /* no pre-delay */ 1630199680Sthompsa }, 1631199086Srpaulo}; 1632199086Srpaulo 1633199086Srpaulostatic int 1634199086Srpauloatp_probe(device_t self) 1635199086Srpaulo{ 1636199086Srpaulo struct usb_attach_arg *uaa = device_get_ivars(self); 1637199086Srpaulo 1638199086Srpaulo if (uaa->usb_mode != USB_MODE_HOST) 1639199086Srpaulo return (ENXIO); 1640199086Srpaulo 1641199086Srpaulo if ((uaa->info.bInterfaceClass != UICLASS_HID) || 1642199086Srpaulo (uaa->info.bInterfaceProtocol != UIPROTO_MOUSE)) 1643199086Srpaulo return (ENXIO); 1644199086Srpaulo 1645199680Sthompsa return (usbd_lookup_id_by_uaa(atp_devs, sizeof(atp_devs), uaa)); 1646199086Srpaulo} 1647199086Srpaulo 1648199086Srpaulostatic int 1649199086Srpauloatp_attach(device_t dev) 1650199086Srpaulo{ 1651199086Srpaulo struct atp_softc *sc = device_get_softc(dev); 1652199086Srpaulo struct usb_attach_arg *uaa = device_get_ivars(dev); 1653199086Srpaulo usb_error_t err; 1654199086Srpaulo 1655199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "sc=%p\n", sc); 1656199086Srpaulo 1657199086Srpaulo sc->sc_dev = dev; 1658199086Srpaulo sc->sc_usb_device = uaa->device; 1659199086Srpaulo 1660199086Srpaulo /* 1661199086Srpaulo * By default the touchpad behaves like an HID device, sending 1662199086Srpaulo * packets with reportID = 2. Such reports contain only 1663199086Srpaulo * limited information--they encode movement deltas and button 1664199086Srpaulo * events,--but do not include data from the pressure 1665199086Srpaulo * sensors. The device input mode can be switched from HID 1666199086Srpaulo * reports to raw sensor data using vendor-specific USB 1667199086Srpaulo * control commands; but first the mode must be read. 1668199086Srpaulo */ 1669199086Srpaulo err = atp_req_get_report(sc->sc_usb_device, sc->sc_mode_bytes); 1670199086Srpaulo if (err != USB_ERR_NORMAL_COMPLETION) { 1671199086Srpaulo DPRINTF("failed to read device mode (%d)\n", err); 1672199086Srpaulo return (ENXIO); 1673199086Srpaulo } 1674199086Srpaulo 1675199086Srpaulo if (atp_set_device_mode(dev, RAW_SENSOR_MODE) != 0) { 1676199086Srpaulo DPRINTF("failed to set mode to 'RAW_SENSOR' (%d)\n", err); 1677199086Srpaulo return (ENXIO); 1678199086Srpaulo } 1679199086Srpaulo 1680199086Srpaulo mtx_init(&sc->sc_mutex, "atpmtx", NULL, MTX_DEF | MTX_RECURSE); 1681199086Srpaulo 1682199086Srpaulo err = usbd_transfer_setup(uaa->device, 1683199086Srpaulo &uaa->info.bIfaceIndex, sc->sc_xfer, atp_config, 1684199086Srpaulo ATP_N_TRANSFER, sc, &sc->sc_mutex); 1685199086Srpaulo 1686199086Srpaulo if (err) { 1687199086Srpaulo DPRINTF("error=%s\n", usbd_errstr(err)); 1688199086Srpaulo goto detach; 1689199086Srpaulo } 1690199086Srpaulo 1691199086Srpaulo if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex, 1692199086Srpaulo &atp_fifo_methods, &sc->sc_fifo, 1693199086Srpaulo device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex, 1694199086Srpaulo UID_ROOT, GID_OPERATOR, 0644)) { 1695199086Srpaulo goto detach; 1696199086Srpaulo } 1697199086Srpaulo 1698199086Srpaulo device_set_usb_desc(dev); 1699199086Srpaulo 1700199086Srpaulo sc->sc_params = &atp_dev_params[uaa->driver_info]; 1701199086Srpaulo 1702199086Srpaulo sc->sc_hw.buttons = 3; 1703199086Srpaulo sc->sc_hw.iftype = MOUSE_IF_USB; 1704199086Srpaulo sc->sc_hw.type = MOUSE_PAD; 1705199086Srpaulo sc->sc_hw.model = MOUSE_MODEL_GENERIC; 1706199086Srpaulo sc->sc_hw.hwid = 0; 1707199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 1708199086Srpaulo sc->sc_mode.rate = -1; 1709199086Srpaulo sc->sc_mode.resolution = MOUSE_RES_UNKNOWN; 1710199086Srpaulo sc->sc_mode.accelfactor = 0; 1711199086Srpaulo sc->sc_mode.level = 0; 1712199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 1713199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 1714199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 1715199086Srpaulo 1716199086Srpaulo sc->sc_state = 0; 1717199086Srpaulo 1718199086Srpaulo sc->sc_left_margin = atp_mickeys_scale_factor; 1719199086Srpaulo sc->sc_right_margin = (sc->sc_params->n_xsensors - 1) * 1720199086Srpaulo atp_mickeys_scale_factor; 1721199086Srpaulo 1722199086Srpaulo return (0); 1723199086Srpaulo 1724199086Srpaulodetach: 1725199086Srpaulo atp_detach(dev); 1726199086Srpaulo return (ENOMEM); 1727199086Srpaulo} 1728199086Srpaulo 1729199086Srpaulostatic int 1730199086Srpauloatp_detach(device_t dev) 1731199086Srpaulo{ 1732199086Srpaulo struct atp_softc *sc; 1733199086Srpaulo 1734199086Srpaulo sc = device_get_softc(dev); 1735199086Srpaulo if (sc->sc_state & ATP_ENABLED) { 1736199086Srpaulo mtx_lock(&sc->sc_mutex); 1737199086Srpaulo atp_disable(sc); 1738199086Srpaulo mtx_unlock(&sc->sc_mutex); 1739199086Srpaulo } 1740199086Srpaulo 1741199086Srpaulo usb_fifo_detach(&sc->sc_fifo); 1742199086Srpaulo 1743199086Srpaulo usbd_transfer_unsetup(sc->sc_xfer, ATP_N_TRANSFER); 1744199086Srpaulo 1745199086Srpaulo mtx_destroy(&sc->sc_mutex); 1746199086Srpaulo 1747199086Srpaulo return (0); 1748199086Srpaulo} 1749199086Srpaulo 1750199086Srpaulostatic void 1751199086Srpauloatp_intr(struct usb_xfer *xfer, usb_error_t error) 1752199086Srpaulo{ 1753199086Srpaulo struct atp_softc *sc = usbd_xfer_softc(xfer); 1754199086Srpaulo int len; 1755199086Srpaulo struct usb_page_cache *pc; 1756199086Srpaulo uint8_t status_bits; 1757199086Srpaulo atp_pspan pspans_x[ATP_MAX_PSPANS_PER_AXIS]; 1758199086Srpaulo atp_pspan pspans_y[ATP_MAX_PSPANS_PER_AXIS]; 1759199086Srpaulo u_int n_xpspans = 0, n_ypspans = 0; 1760199086Srpaulo u_int reaped_xlocs[ATP_MAX_STROKES]; 1761199086Srpaulo u_int tap_fingers = 0; 1762199086Srpaulo 1763199086Srpaulo usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 1764199086Srpaulo 1765199086Srpaulo switch (USB_GET_STATE(xfer)) { 1766199086Srpaulo case USB_ST_TRANSFERRED: 1767199086Srpaulo if (len > sc->sc_params->data_len) { 1768199086Srpaulo DPRINTFN(ATP_LLEVEL_ERROR, 1769199086Srpaulo "truncating large packet from %u to %u bytes\n", 1770199086Srpaulo len, sc->sc_params->data_len); 1771199086Srpaulo len = sc->sc_params->data_len; 1772199086Srpaulo } 1773199151Snwhitehorn if (len < sc->sc_params->data_len) 1774199086Srpaulo goto tr_setup; 1775199086Srpaulo 1776199086Srpaulo pc = usbd_xfer_get_frame(xfer, 0); 1777199086Srpaulo usbd_copy_out(pc, 0, sc->sensor_data, sc->sc_params->data_len); 1778199086Srpaulo 1779199086Srpaulo /* Interpret sensor data */ 1780199086Srpaulo atp_interpret_sensor_data(sc->sensor_data, 1781199151Snwhitehorn sc->sc_params->n_xsensors, X, sc->cur_x, 1782199151Snwhitehorn sc->sc_params->prot); 1783199086Srpaulo atp_interpret_sensor_data(sc->sensor_data, 1784199151Snwhitehorn sc->sc_params->n_ysensors, Y, sc->cur_y, 1785199151Snwhitehorn sc->sc_params->prot); 1786199086Srpaulo 1787199086Srpaulo /* 1788199086Srpaulo * If this is the initial update (from an untouched 1789199086Srpaulo * pad), we should set the base values for the sensor 1790199086Srpaulo * data; deltas with respect to these base values can 1791199086Srpaulo * be used as pressure readings subsequently. 1792199086Srpaulo */ 1793199086Srpaulo status_bits = sc->sensor_data[sc->sc_params->data_len - 1]; 1794199151Snwhitehorn if ((sc->sc_params->prot == ATP_PROT_GEYSER3 && 1795200241Srpaulo (status_bits & ATP_STATUS_BASE_UPDATE)) || 1796199151Snwhitehorn !(sc->sc_state & ATP_VALID)) { 1797199086Srpaulo memcpy(sc->base_x, sc->cur_x, 1798199086Srpaulo sc->sc_params->n_xsensors * sizeof(*(sc->base_x))); 1799199086Srpaulo memcpy(sc->base_y, sc->cur_y, 1800199086Srpaulo sc->sc_params->n_ysensors * sizeof(*(sc->base_y))); 1801199151Snwhitehorn sc->sc_state |= ATP_VALID; 1802199086Srpaulo goto tr_setup; 1803199086Srpaulo } 1804199086Srpaulo 1805199086Srpaulo /* Get pressure readings and detect p-spans for both axes. */ 1806199086Srpaulo atp_get_pressures(sc->pressure_x, sc->cur_x, sc->base_x, 1807199086Srpaulo sc->sc_params->n_xsensors); 1808199086Srpaulo atp_detect_pspans(sc->pressure_x, sc->sc_params->n_xsensors, 1809199086Srpaulo ATP_MAX_PSPANS_PER_AXIS, 1810199086Srpaulo pspans_x, &n_xpspans); 1811199086Srpaulo atp_get_pressures(sc->pressure_y, sc->cur_y, sc->base_y, 1812199086Srpaulo sc->sc_params->n_ysensors); 1813199086Srpaulo atp_detect_pspans(sc->pressure_y, sc->sc_params->n_ysensors, 1814199086Srpaulo ATP_MAX_PSPANS_PER_AXIS, 1815199086Srpaulo pspans_y, &n_ypspans); 1816199086Srpaulo 1817199086Srpaulo /* Update strokes with new pspans to detect movements. */ 1818199086Srpaulo sc->sc_status.flags &= ~MOUSE_POSCHANGED; 1819199086Srpaulo if (atp_update_strokes(sc, 1820199086Srpaulo pspans_x, n_xpspans, 1821199086Srpaulo pspans_y, n_ypspans)) 1822199086Srpaulo sc->sc_status.flags |= MOUSE_POSCHANGED; 1823199086Srpaulo 1824199086Srpaulo /* Reap zombies if it is time. */ 1825199086Srpaulo if (sc->sc_state & ATP_ZOMBIES_EXIST) { 1826199086Srpaulo struct timeval now; 1827199086Srpaulo 1828199086Srpaulo getmicrotime(&now); 1829199086Srpaulo if (timevalcmp(&now, &sc->sc_reap_time, >=)) 1830199086Srpaulo atp_reap_zombies(sc, &tap_fingers, 1831199086Srpaulo reaped_xlocs); 1832199086Srpaulo } 1833199086Srpaulo 1834199086Srpaulo sc->sc_status.flags &= ~MOUSE_STDBUTTONSCHANGED; 1835199086Srpaulo sc->sc_status.obutton = sc->sc_status.button; 1836199086Srpaulo 1837199086Srpaulo /* Get the state of the physical buttton. */ 1838199086Srpaulo sc->sc_status.button = (status_bits & ATP_STATUS_BUTTON) ? 1839199086Srpaulo MOUSE_BUTTON1DOWN : 0; 1840199086Srpaulo if (sc->sc_status.button != 0) { 1841199086Srpaulo /* Reset DOUBLE_TAP_N_DRAG if the button is pressed. */ 1842199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1843199086Srpaulo } else if (sc->sc_state & ATP_DOUBLE_TAP_DRAG) { 1844199086Srpaulo /* Assume a button-press with DOUBLE_TAP_N_DRAG. */ 1845199086Srpaulo sc->sc_status.button = MOUSE_BUTTON1DOWN; 1846199086Srpaulo } 1847199086Srpaulo 1848199086Srpaulo sc->sc_status.flags |= 1849199086Srpaulo sc->sc_status.button ^ sc->sc_status.obutton; 1850199086Srpaulo if (sc->sc_status.flags & MOUSE_STDBUTTONSCHANGED) { 1851199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "button %s\n", 1852199086Srpaulo ((sc->sc_status.button & MOUSE_BUTTON1DOWN) ? 1853199086Srpaulo "pressed" : "released")); 1854199086Srpaulo } else if ((sc->sc_status.obutton == 0) && 1855199086Srpaulo (sc->sc_status.button == 0) && 1856199086Srpaulo (tap_fingers != 0)) { 1857199086Srpaulo /* Ignore single-finger taps at the edges. */ 1858199086Srpaulo if ((tap_fingers == 1) && 1859199086Srpaulo ((reaped_xlocs[0] <= sc->sc_left_margin) || 1860199086Srpaulo (reaped_xlocs[0] > sc->sc_right_margin))) { 1861199086Srpaulo tap_fingers = 0; 1862199086Srpaulo } 1863199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, 1864199086Srpaulo "tap_fingers: %u\n", tap_fingers); 1865199086Srpaulo } 1866199086Srpaulo 1867199086Srpaulo if (sc->sc_status.flags & 1868199086Srpaulo (MOUSE_POSCHANGED | MOUSE_STDBUTTONSCHANGED)) { 1869199086Srpaulo int dx, dy; 1870199086Srpaulo u_int n_movements; 1871199086Srpaulo 1872199086Srpaulo dx = 0, dy = 0, n_movements = 0; 1873199086Srpaulo for (u_int i = 0; i < sc->sc_n_strokes; i++) { 1874199086Srpaulo atp_stroke *stroke = &sc->sc_strokes[i]; 1875199086Srpaulo 1876199086Srpaulo if ((stroke->components[X].movement) || 1877199086Srpaulo (stroke->components[Y].movement)) { 1878199086Srpaulo dx += stroke->components[X].movement; 1879199086Srpaulo dy += stroke->components[Y].movement; 1880199086Srpaulo n_movements++; 1881199086Srpaulo } 1882199086Srpaulo } 1883199086Srpaulo /* 1884199086Srpaulo * Disregard movement if multiple 1885199086Srpaulo * strokes record motion. 1886199086Srpaulo */ 1887199086Srpaulo if (n_movements != 1) 1888199086Srpaulo dx = 0, dy = 0; 1889199086Srpaulo 1890199086Srpaulo sc->sc_status.dx += dx; 1891199086Srpaulo sc->sc_status.dy += dy; 1892199086Srpaulo atp_add_to_queue(sc, dx, -dy, sc->sc_status.button); 1893199086Srpaulo } 1894199086Srpaulo 1895199086Srpaulo if (tap_fingers != 0) { 1896199086Srpaulo /* Add a pair of events (button-down and button-up). */ 1897199086Srpaulo switch (tap_fingers) { 1898199086Srpaulo case 1: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON1DOWN); 1899199086Srpaulo break; 1900199086Srpaulo case 2: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON2DOWN); 1901199086Srpaulo break; 1902199086Srpaulo case 3: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON3DOWN); 1903199086Srpaulo break; 1904199086Srpaulo default: break;/* handle taps of only up to 3 fingers */ 1905199086Srpaulo } 1906199086Srpaulo atp_add_to_queue(sc, 0, 0, 0); /* button release */ 1907199086Srpaulo } 1908199086Srpaulo 1909199086Srpaulo /* 1910199086Srpaulo * The device continues to trigger interrupts at a 1911199086Srpaulo * fast rate even after touchpad activity has 1912199086Srpaulo * stopped. Upon detecting that the device has 1913199086Srpaulo * remained idle beyond a threshold, we reinitialize 1914199086Srpaulo * it to silence the interrupts. 1915199086Srpaulo */ 1916199086Srpaulo if ((sc->sc_status.flags == 0) && 1917199086Srpaulo (sc->sc_n_strokes == 0) && 1918199086Srpaulo (sc->sc_status.button == 0)) { 1919199086Srpaulo sc->sc_idlecount++; 1920199086Srpaulo if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) { 1921199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "idle\n"); 1922199948Snwhitehorn 1923199948Snwhitehorn /* 1924199948Snwhitehorn * Use the last frame before we go idle for 1925199948Snwhitehorn * calibration on pads which do not send 1926199948Snwhitehorn * calibration frames. 1927199948Snwhitehorn */ 1928199948Snwhitehorn if (sc->sc_params->prot < ATP_PROT_GEYSER3) { 1929199948Snwhitehorn memcpy(sc->base_x, sc->cur_x, 1930199948Snwhitehorn sc->sc_params->n_xsensors * 1931199948Snwhitehorn sizeof(*(sc->base_x))); 1932199948Snwhitehorn memcpy(sc->base_y, sc->cur_y, 1933199948Snwhitehorn sc->sc_params->n_ysensors * 1934199948Snwhitehorn sizeof(*(sc->base_y))); 1935199948Snwhitehorn } 1936199948Snwhitehorn 1937199151Snwhitehorn sc->sc_idlecount = 0; 1938199680Sthompsa usbd_transfer_start(sc->sc_xfer[ATP_RESET]); 1939199086Srpaulo } 1940199086Srpaulo } else { 1941199086Srpaulo sc->sc_idlecount = 0; 1942199086Srpaulo } 1943199086Srpaulo 1944199086Srpaulo case USB_ST_SETUP: 1945199086Srpaulo tr_setup: 1946199086Srpaulo /* check if we can put more data into the FIFO */ 1947199086Srpaulo if (usb_fifo_put_bytes_max( 1948199086Srpaulo sc->sc_fifo.fp[USB_FIFO_RX]) != 0) { 1949199086Srpaulo usbd_xfer_set_frame_len(xfer, 0, 1950199151Snwhitehorn sc->sc_params->data_len); 1951199086Srpaulo usbd_transfer_submit(xfer); 1952199086Srpaulo } 1953199086Srpaulo break; 1954199086Srpaulo 1955199086Srpaulo default: /* Error */ 1956199086Srpaulo if (error != USB_ERR_CANCELLED) { 1957199086Srpaulo /* try clear stall first */ 1958199086Srpaulo usbd_xfer_set_stall(xfer); 1959199086Srpaulo goto tr_setup; 1960199086Srpaulo } 1961199086Srpaulo break; 1962199086Srpaulo } 1963199086Srpaulo 1964199086Srpaulo return; 1965199086Srpaulo} 1966199086Srpaulo 1967199086Srpaulostatic void 1968199086Srpauloatp_add_to_queue(struct atp_softc *sc, int dx, int dy, uint32_t buttons_in) 1969199086Srpaulo{ 1970199086Srpaulo uint32_t buttons_out; 1971199086Srpaulo uint8_t buf[8]; 1972199086Srpaulo 1973199086Srpaulo dx = imin(dx, 254); dx = imax(dx, -256); 1974199086Srpaulo dy = imin(dy, 254); dy = imax(dy, -256); 1975199086Srpaulo 1976199086Srpaulo buttons_out = MOUSE_MSC_BUTTONS; 1977199086Srpaulo if (buttons_in & MOUSE_BUTTON1DOWN) 1978199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON1UP; 1979199086Srpaulo else if (buttons_in & MOUSE_BUTTON2DOWN) 1980199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON2UP; 1981199086Srpaulo else if (buttons_in & MOUSE_BUTTON3DOWN) 1982199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON3UP; 1983199086Srpaulo 1984199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "dx=%d, dy=%d, buttons=%x\n", 1985199086Srpaulo dx, dy, buttons_out); 1986199086Srpaulo 1987199086Srpaulo /* Encode the mouse data in standard format; refer to mouse(4) */ 1988199086Srpaulo buf[0] = sc->sc_mode.syncmask[1]; 1989199086Srpaulo buf[0] |= buttons_out; 1990199086Srpaulo buf[1] = dx >> 1; 1991199086Srpaulo buf[2] = dy >> 1; 1992199086Srpaulo buf[3] = dx - (dx >> 1); 1993199086Srpaulo buf[4] = dy - (dy >> 1); 1994199086Srpaulo /* Encode extra bytes for level 1 */ 1995199086Srpaulo if (sc->sc_mode.level == 1) { 1996199086Srpaulo buf[5] = 0; /* dz */ 1997199086Srpaulo buf[6] = 0; /* dz - (dz / 2) */ 1998199086Srpaulo buf[7] = MOUSE_SYS_EXTBUTTONS; /* Extra buttons all up. */ 1999199086Srpaulo } 2000199086Srpaulo 2001199086Srpaulo usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, 2002199086Srpaulo sc->sc_mode.packetsize, 1); 2003199086Srpaulo} 2004199086Srpaulo 2005199086Srpaulostatic void 2006199086Srpauloatp_reset_buf(struct atp_softc *sc) 2007199086Srpaulo{ 2008199086Srpaulo /* reset read queue */ 2009199086Srpaulo usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]); 2010199086Srpaulo} 2011199086Srpaulo 2012199086Srpaulostatic void 2013199086Srpauloatp_start_read(struct usb_fifo *fifo) 2014199086Srpaulo{ 2015199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2016199086Srpaulo int rate; 2017199086Srpaulo 2018199086Srpaulo /* Check if we should override the default polling interval */ 2019199086Srpaulo rate = sc->sc_pollrate; 2020199086Srpaulo /* Range check rate */ 2021199086Srpaulo if (rate > 1000) 2022199086Srpaulo rate = 1000; 2023199086Srpaulo /* Check for set rate */ 2024199086Srpaulo if ((rate > 0) && (sc->sc_xfer[ATP_INTR_DT] != NULL)) { 2025199086Srpaulo /* Stop current transfer, if any */ 2026199086Srpaulo usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); 2027199086Srpaulo /* Set new interval */ 2028199086Srpaulo usbd_xfer_set_interval(sc->sc_xfer[ATP_INTR_DT], 1000 / rate); 2029199086Srpaulo /* Only set pollrate once */ 2030199086Srpaulo sc->sc_pollrate = 0; 2031199086Srpaulo } 2032199086Srpaulo 2033199086Srpaulo usbd_transfer_start(sc->sc_xfer[ATP_INTR_DT]); 2034199086Srpaulo} 2035199086Srpaulo 2036199086Srpaulostatic void 2037199086Srpauloatp_stop_read(struct usb_fifo *fifo) 2038199086Srpaulo{ 2039199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2040199086Srpaulo 2041199086Srpaulo usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); 2042199086Srpaulo} 2043199086Srpaulo 2044199086Srpaulo 2045199086Srpaulostatic int 2046199086Srpauloatp_open(struct usb_fifo *fifo, int fflags) 2047199086Srpaulo{ 2048199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "\n"); 2049199086Srpaulo 2050199086Srpaulo if (fflags & FREAD) { 2051199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2052199086Srpaulo int rc; 2053199086Srpaulo 2054199086Srpaulo if (sc->sc_state & ATP_ENABLED) 2055199086Srpaulo return (EBUSY); 2056199086Srpaulo 2057199086Srpaulo if (usb_fifo_alloc_buffer(fifo, 2058199086Srpaulo ATP_FIFO_BUF_SIZE, ATP_FIFO_QUEUE_MAXLEN)) { 2059199086Srpaulo return (ENOMEM); 2060199086Srpaulo } 2061199086Srpaulo 2062199086Srpaulo rc = atp_enable(sc); 2063199086Srpaulo if (rc != 0) { 2064199086Srpaulo usb_fifo_free_buffer(fifo); 2065199086Srpaulo return (rc); 2066199086Srpaulo } 2067199086Srpaulo } 2068199086Srpaulo 2069199086Srpaulo return (0); 2070199086Srpaulo} 2071199086Srpaulo 2072199086Srpaulostatic void 2073199086Srpauloatp_close(struct usb_fifo *fifo, int fflags) 2074199086Srpaulo{ 2075199086Srpaulo if (fflags & FREAD) { 2076199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2077199086Srpaulo 2078199086Srpaulo atp_disable(sc); 2079199086Srpaulo usb_fifo_free_buffer(fifo); 2080199086Srpaulo } 2081199086Srpaulo} 2082199086Srpaulo 2083199086Srpauloint 2084199086Srpauloatp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) 2085199086Srpaulo{ 2086199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2087199086Srpaulo mousemode_t mode; 2088199086Srpaulo int error = 0; 2089199086Srpaulo 2090199086Srpaulo mtx_lock(&sc->sc_mutex); 2091199086Srpaulo 2092199086Srpaulo switch(cmd) { 2093199086Srpaulo case MOUSE_GETHWINFO: 2094199086Srpaulo *(mousehw_t *)addr = sc->sc_hw; 2095199086Srpaulo break; 2096199086Srpaulo case MOUSE_GETMODE: 2097199086Srpaulo *(mousemode_t *)addr = sc->sc_mode; 2098199086Srpaulo break; 2099199086Srpaulo case MOUSE_SETMODE: 2100199086Srpaulo mode = *(mousemode_t *)addr; 2101199086Srpaulo 2102199086Srpaulo if (mode.level == -1) 2103199086Srpaulo /* Don't change the current setting */ 2104199086Srpaulo ; 2105199086Srpaulo else if ((mode.level < 0) || (mode.level > 1)) { 2106199086Srpaulo error = EINVAL; 2107199086Srpaulo goto done; 2108199086Srpaulo } 2109199086Srpaulo sc->sc_mode.level = mode.level; 2110199086Srpaulo sc->sc_pollrate = mode.rate; 2111199086Srpaulo sc->sc_hw.buttons = 3; 2112199086Srpaulo 2113199086Srpaulo if (sc->sc_mode.level == 0) { 2114199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 2115199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 2116199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 2117199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 2118199086Srpaulo } else if (sc->sc_mode.level == 1) { 2119199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 2120199086Srpaulo sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 2121199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 2122199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 2123199086Srpaulo } 2124199086Srpaulo atp_reset_buf(sc); 2125199086Srpaulo break; 2126199086Srpaulo case MOUSE_GETLEVEL: 2127199086Srpaulo *(int *)addr = sc->sc_mode.level; 2128199086Srpaulo break; 2129199086Srpaulo case MOUSE_SETLEVEL: 2130199086Srpaulo if (*(int *)addr < 0 || *(int *)addr > 1) { 2131199086Srpaulo error = EINVAL; 2132199086Srpaulo goto done; 2133199086Srpaulo } 2134199086Srpaulo sc->sc_mode.level = *(int *)addr; 2135199086Srpaulo sc->sc_hw.buttons = 3; 2136199086Srpaulo 2137199086Srpaulo if (sc->sc_mode.level == 0) { 2138199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 2139199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 2140199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 2141199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 2142199086Srpaulo } else if (sc->sc_mode.level == 1) { 2143199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 2144199086Srpaulo sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 2145199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 2146199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 2147199086Srpaulo } 2148199086Srpaulo atp_reset_buf(sc); 2149199086Srpaulo break; 2150199086Srpaulo case MOUSE_GETSTATUS: { 2151199086Srpaulo mousestatus_t *status = (mousestatus_t *)addr; 2152199086Srpaulo 2153199086Srpaulo *status = sc->sc_status; 2154199086Srpaulo sc->sc_status.obutton = sc->sc_status.button; 2155199086Srpaulo sc->sc_status.button = 0; 2156199086Srpaulo sc->sc_status.dx = 0; 2157199086Srpaulo sc->sc_status.dy = 0; 2158199086Srpaulo sc->sc_status.dz = 0; 2159199086Srpaulo 2160199086Srpaulo if (status->dx || status->dy || status->dz) 2161199086Srpaulo status->flags |= MOUSE_POSCHANGED; 2162199086Srpaulo if (status->button != status->obutton) 2163199086Srpaulo status->flags |= MOUSE_BUTTONSCHANGED; 2164199086Srpaulo break; 2165199086Srpaulo } 2166199086Srpaulo default: 2167199086Srpaulo error = ENOTTY; 2168199086Srpaulo } 2169199086Srpaulo 2170199086Srpaulodone: 2171199086Srpaulo mtx_unlock(&sc->sc_mutex); 2172199086Srpaulo return (error); 2173199086Srpaulo} 2174199086Srpaulo 2175199086Srpaulostatic int 2176199086Srpauloatp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS) 2177199086Srpaulo{ 2178199086Srpaulo int error; 2179199086Srpaulo u_int tmp; 2180199086Srpaulo u_int prev_mickeys_scale_factor; 2181199086Srpaulo 2182199086Srpaulo prev_mickeys_scale_factor = atp_mickeys_scale_factor; 2183199086Srpaulo 2184199086Srpaulo tmp = atp_mickeys_scale_factor; 2185199086Srpaulo error = sysctl_handle_int(oidp, &tmp, 0, req); 2186199086Srpaulo if (error != 0 || req->newptr == NULL) 2187199086Srpaulo return (error); 2188199086Srpaulo 2189199086Srpaulo if (tmp == prev_mickeys_scale_factor) 2190199086Srpaulo return (0); /* no change */ 2191199086Srpaulo 2192199086Srpaulo atp_mickeys_scale_factor = tmp; 2193199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "%s: resetting mickeys_scale_factor to %u\n", 2194199086Srpaulo ATP_DRIVER_NAME, tmp); 2195199086Srpaulo 2196199086Srpaulo /* Update dependent thresholds. */ 2197199086Srpaulo if (atp_small_movement_threshold == (prev_mickeys_scale_factor >> 3)) 2198199086Srpaulo atp_small_movement_threshold = atp_mickeys_scale_factor >> 3; 2199199086Srpaulo if (atp_max_delta_mickeys == ((3 * prev_mickeys_scale_factor) >> 1)) 2200199086Srpaulo atp_max_delta_mickeys = ((3 * atp_mickeys_scale_factor) >>1); 2201199086Srpaulo if (atp_slide_min_movement == (prev_mickeys_scale_factor >> 3)) 2202199086Srpaulo atp_slide_min_movement = atp_mickeys_scale_factor >> 3; 2203199086Srpaulo 2204199086Srpaulo return (0); 2205199086Srpaulo} 2206199086Srpaulo 2207199086Srpaulostatic device_method_t atp_methods[] = { 2208199086Srpaulo /* Device interface */ 2209199086Srpaulo DEVMETHOD(device_probe, atp_probe), 2210199086Srpaulo DEVMETHOD(device_attach, atp_attach), 2211199086Srpaulo DEVMETHOD(device_detach, atp_detach), 2212199086Srpaulo { 0, 0 } 2213199086Srpaulo}; 2214199086Srpaulo 2215199086Srpaulostatic driver_t atp_driver = { 2216199086Srpaulo ATP_DRIVER_NAME, 2217199086Srpaulo atp_methods, 2218199086Srpaulo sizeof(struct atp_softc) 2219199086Srpaulo}; 2220199086Srpaulo 2221199086Srpaulostatic devclass_t atp_devclass; 2222199086Srpaulo 2223199086SrpauloDRIVER_MODULE(atp, uhub, atp_driver, atp_devclass, NULL, 0); 2224199086SrpauloMODULE_DEPEND(atp, usb, 1, 1, 1); 2225