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$"); 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 */ 117227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB atp"); 118199086Srpaulo 119207077Sthompsa#ifdef 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"); 129207077Sthompsa#endif /* USB_DEBUG */ 130199086Srpaulo 131199086Srpaulostatic u_int atp_touch_timeout = ATP_TOUCH_TIMEOUT; 132217323SmdfSYSCTL_UINT(_hw_usb_atp, OID_AUTO, touch_timeout, CTLFLAG_RW, 133217323Smdf &atp_touch_timeout, 125000, "age threshold (in micros) for a touch"); 134199086Srpaulo 135199086Srpaulostatic u_int atp_double_tap_threshold = ATP_DOUBLE_TAP_N_DRAG_THRESHOLD; 136217323SmdfSYSCTL_UINT(_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 243223486Shselaskystatic const STRUCT_USB_HOST_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 */ 764233774Shselasky if ((u_int)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 890233774Shselasky if ((u_int)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)) { 1058207077Sthompsa#ifdef 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 } 1075207077Sthompsa#endif /* 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 1085207077Sthompsa#ifdef 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 } 1113207077Sthompsa#endif /* 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 atp_pspan spans[2][ATP_MAX_PSPANS_PER_AXIS]; 1168233774Shselasky u_int nspans[2]; 1169233774Shselasky u_int i; 1170233774Shselasky u_int j; 1171199086Srpaulo 1172199086Srpaulo /* Copy unmatched pspans into the local arrays. */ 1173199086Srpaulo for (i = 0, nspans[X] = 0; i < n_xpspans; i++) { 1174199086Srpaulo if (pspans_x[i].matched == FALSE) { 1175199086Srpaulo spans[X][nspans[X]] = pspans_x[i]; 1176199086Srpaulo nspans[X]++; 1177199086Srpaulo } 1178199086Srpaulo } 1179199086Srpaulo for (j = 0, nspans[Y] = 0; j < n_ypspans; j++) { 1180199086Srpaulo if (pspans_y[j].matched == FALSE) { 1181199086Srpaulo spans[Y][nspans[Y]] = pspans_y[j]; 1182199086Srpaulo nspans[Y]++; 1183199086Srpaulo } 1184199086Srpaulo } 1185199086Srpaulo 1186199086Srpaulo if (nspans[X] == nspans[Y]) { 1187199086Srpaulo /* Create new strokes from pairs of unmatched pspans */ 1188199086Srpaulo for (i = 0, j = 0; (i < nspans[X]) && (j < nspans[Y]); i++, j++) 1189199086Srpaulo atp_add_stroke(sc, &spans[X][i], &spans[Y][j]); 1190199086Srpaulo } else { 1191199086Srpaulo u_int cum = 0; 1192199086Srpaulo atp_axis repeat_axis; /* axis with multi-pspans */ 1193199086Srpaulo u_int repeat_count; /* repeat count for the multi-pspan*/ 1194199086Srpaulo u_int repeat_index = 0; /* index of the multi-span */ 1195199086Srpaulo 1196199086Srpaulo repeat_axis = (nspans[X] > nspans[Y]) ? Y : X; 1197199086Srpaulo repeat_count = abs(nspans[X] - nspans[Y]); 1198199086Srpaulo for (i = 0; i < nspans[repeat_axis]; i++) { 1199199086Srpaulo if (spans[repeat_axis][i].cum > cum) { 1200199086Srpaulo repeat_index = i; 1201199086Srpaulo cum = spans[repeat_axis][i].cum; 1202199086Srpaulo } 1203199086Srpaulo } 1204199086Srpaulo 1205199086Srpaulo /* Create new strokes from pairs of unmatched pspans */ 1206199086Srpaulo i = 0, j = 0; 1207199086Srpaulo for (; (i < nspans[X]) && (j < nspans[Y]); i++, j++) { 1208199086Srpaulo atp_add_stroke(sc, &spans[X][i], &spans[Y][j]); 1209199086Srpaulo 1210199086Srpaulo /* Take care to repeat at the multi-pspan. */ 1211199086Srpaulo if (repeat_count > 0) { 1212199086Srpaulo if ((repeat_axis == X) && 1213199086Srpaulo (repeat_index == i)) { 1214199086Srpaulo i--; /* counter loop increment */ 1215199086Srpaulo repeat_count--; 1216199086Srpaulo } else if ((repeat_axis == Y) && 1217199086Srpaulo (repeat_index == j)) { 1218199086Srpaulo j--; /* counter loop increment */ 1219199086Srpaulo repeat_count--; 1220199086Srpaulo } 1221199086Srpaulo } 1222199086Srpaulo } 1223199086Srpaulo } 1224199086Srpaulo} 1225199086Srpaulo 1226199086Srpaulo/* 1227199086Srpaulo * Advance the state of this stroke--and update the out-parameter 1228199086Srpaulo * 'movement' as a side-effect. 1229199086Srpaulo */ 1230199086Srpaulovoid 1231199086Srpauloatp_advance_stroke_state(struct atp_softc *sc, atp_stroke *stroke, 1232199086Srpaulo boolean_t *movement) 1233199086Srpaulo{ 1234199086Srpaulo stroke->age++; 1235199086Srpaulo if (stroke->age <= atp_stroke_maturity_threshold) { 1236199086Srpaulo /* Avoid noise from immature strokes. */ 1237199086Srpaulo stroke->components[X].delta_mickeys = 0; 1238199086Srpaulo stroke->components[Y].delta_mickeys = 0; 1239199086Srpaulo } 1240199086Srpaulo 1241199086Srpaulo /* Revitalize stroke if it had previously been marked as a zombie. */ 1242199086Srpaulo if (stroke->flags & ATSF_ZOMBIE) 1243199086Srpaulo stroke->flags &= ~ATSF_ZOMBIE; 1244199086Srpaulo 1245199086Srpaulo if (atp_compute_stroke_movement(stroke)) 1246199086Srpaulo *movement = TRUE; 1247199086Srpaulo 1248200241Srpaulo if (stroke->type != ATP_STROKE_TOUCH) 1249200241Srpaulo return; 1250200241Srpaulo 1251199086Srpaulo /* Convert touch strokes to slides upon detecting movement or age. */ 1252200241Srpaulo if (stroke->cum_movement >= atp_slide_min_movement) { 1253200241Srpaulo atp_convert_to_slide(sc, stroke); 1254200241Srpaulo } else { 1255200241Srpaulo /* If a touch stroke is found to be older than the 1256200241Srpaulo * touch-timeout threshold, it should be converted to 1257200241Srpaulo * a slide; except if there is a co-incident sibling 1258200241Srpaulo * with a later creation time. 1259200241Srpaulo * 1260200241Srpaulo * When multiple fingers make contact with the 1261200241Srpaulo * touchpad, they are likely to be separated in their 1262200241Srpaulo * times of incidence. During a multi-finger tap, 1263200241Srpaulo * therefore, the last finger to make 1264200241Srpaulo * contact--i.e. the one with the latest 1265200241Srpaulo * 'ctime'--should be used to determine how the 1266200241Srpaulo * touch-siblings get treated; otherwise older 1267200241Srpaulo * siblings may lapse the touch-timeout and get 1268200241Srpaulo * converted into slides prematurely. The following 1269200241Srpaulo * loop determines if there exists another touch 1270200241Srpaulo * stroke with a larger 'ctime' than the current 1271200241Srpaulo * stroke (NOTE: zombies with a larger 'ctime' are 1272200241Srpaulo * also considered) . 1273200241Srpaulo */ 1274199086Srpaulo 1275200241Srpaulo u_int i; 1276200241Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1277200241Srpaulo if ((&sc->sc_strokes[i] == stroke) || 1278200241Srpaulo (sc->sc_strokes[i].type != ATP_STROKE_TOUCH)) 1279200241Srpaulo continue; 1280200241Srpaulo 1281200241Srpaulo if (timevalcmp(&sc->sc_strokes[i].ctime, 1282200241Srpaulo &stroke->ctime, >)) 1283200241Srpaulo break; 1284199086Srpaulo } 1285200241Srpaulo if (i == sc->sc_n_strokes) { 1286200241Srpaulo /* Found no other touch stroke with a larger 'ctime'. */ 1287200241Srpaulo struct timeval tdiff; 1288199086Srpaulo 1289200241Srpaulo /* Compute the stroke's age. */ 1290200241Srpaulo getmicrotime(&tdiff); 1291200241Srpaulo if (timevalcmp(&tdiff, &stroke->ctime, >)) 1292200241Srpaulo timevalsub(&tdiff, &stroke->ctime); 1293200241Srpaulo else { 1294200241Srpaulo /* 1295200241Srpaulo * If we are here, it is because getmicrotime 1296200241Srpaulo * reported the current time as being behind 1297200241Srpaulo * the stroke's start time; getmicrotime can 1298200241Srpaulo * be imprecise. 1299200241Srpaulo */ 1300200241Srpaulo tdiff.tv_sec = 0; 1301200241Srpaulo tdiff.tv_usec = 0; 1302200241Srpaulo } 1303199086Srpaulo 1304200241Srpaulo if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) || 1305200241Srpaulo ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) && 1306200241Srpaulo (tdiff.tv_usec >= 1307200241Srpaulo (atp_touch_timeout % 1000000)))) 1308200241Srpaulo atp_convert_to_slide(sc, stroke); 1309199086Srpaulo } 1310199086Srpaulo } 1311199086Srpaulo} 1312199086Srpaulo 1313200241Srpaulo/* Switch a given touch stroke to being a slide. */ 1314200241Srpaulovoid 1315200241Srpauloatp_convert_to_slide(struct atp_softc *sc, atp_stroke *stroke) 1316200241Srpaulo{ 1317200241Srpaulo stroke->type = ATP_STROKE_SLIDE; 1318200241Srpaulo 1319200241Srpaulo /* Are we at the beginning of a double-click-n-drag? */ 1320200241Srpaulo if ((sc->sc_n_strokes == 1) && 1321200241Srpaulo ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) && 1322200241Srpaulo timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) { 1323200241Srpaulo struct timeval delta; 1324200241Srpaulo struct timeval window = { 1325200241Srpaulo atp_double_tap_threshold / 1000000, 1326200241Srpaulo atp_double_tap_threshold % 1000000 1327200241Srpaulo }; 1328200241Srpaulo 1329200241Srpaulo delta = stroke->ctime; 1330200241Srpaulo timevalsub(&delta, &sc->sc_reap_time); 1331200241Srpaulo if (timevalcmp(&delta, &window, <=)) 1332200241Srpaulo sc->sc_state |= ATP_DOUBLE_TAP_DRAG; 1333200241Srpaulo } 1334200241Srpaulo} 1335200241Srpaulo 1336199086Srpaulo/* 1337199086Srpaulo * Terminate a stroke. While SLIDE strokes are dropped, TOUCH strokes 1338199086Srpaulo * are retained as zombies so as to reap all their siblings together; 1339199086Srpaulo * this helps establish the number of fingers involved in the tap. 1340199086Srpaulo */ 1341199086Srpaulostatic void 1342199086Srpauloatp_terminate_stroke(struct atp_softc *sc, 1343199086Srpaulo u_int index) /* index of the stroke to be terminated */ 1344199086Srpaulo{ 1345199086Srpaulo atp_stroke *s = &sc->sc_strokes[index]; 1346199086Srpaulo 1347199086Srpaulo if (s->flags & ATSF_ZOMBIE) { 1348199086Srpaulo return; 1349199086Srpaulo } 1350199086Srpaulo 1351199086Srpaulo if ((s->type == ATP_STROKE_TOUCH) && 1352199086Srpaulo (s->age > atp_stroke_maturity_threshold)) { 1353199086Srpaulo s->flags |= ATSF_ZOMBIE; 1354199086Srpaulo 1355199086Srpaulo /* If no zombies exist, then prepare to reap zombies later. */ 1356199086Srpaulo if ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) { 1357199086Srpaulo atp_setup_reap_time(sc, &s->ctime); 1358199086Srpaulo sc->sc_state |= ATP_ZOMBIES_EXIST; 1359199086Srpaulo } 1360199086Srpaulo } else { 1361199086Srpaulo /* Drop this stroke. */ 1362199086Srpaulo memcpy(&sc->sc_strokes[index], &sc->sc_strokes[index + 1], 1363199086Srpaulo (sc->sc_n_strokes - index - 1) * sizeof(atp_stroke)); 1364199086Srpaulo sc->sc_n_strokes--; 1365199086Srpaulo 1366199086Srpaulo /* 1367199086Srpaulo * Reset the double-click-n-drag at the termination of 1368199086Srpaulo * any slide stroke. 1369199086Srpaulo */ 1370199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1371199086Srpaulo } 1372199086Srpaulo} 1373199086Srpaulo 1374199086Srpaulostatic __inline boolean_t 1375199086Srpauloatp_stroke_has_small_movement(const atp_stroke *stroke) 1376199086Srpaulo{ 1377233774Shselasky return (((u_int)abs(stroke->components[X].delta_mickeys) <= 1378199086Srpaulo atp_small_movement_threshold) && 1379233774Shselasky ((u_int)abs(stroke->components[Y].delta_mickeys) <= 1380199086Srpaulo atp_small_movement_threshold)); 1381199086Srpaulo} 1382199086Srpaulo 1383199086Srpaulo/* 1384199086Srpaulo * Accumulate delta_mickeys into the component's 'pending' bucket; if 1385199086Srpaulo * the aggregate exceeds the small_movement_threshold, then retain 1386199086Srpaulo * delta_mickeys for later. 1387199086Srpaulo */ 1388199086Srpaulostatic __inline void 1389199086Srpauloatp_update_pending_mickeys(atp_stroke_component *component) 1390199086Srpaulo{ 1391199086Srpaulo component->pending += component->delta_mickeys; 1392233774Shselasky if ((u_int)abs(component->pending) <= atp_small_movement_threshold) 1393199086Srpaulo component->delta_mickeys = 0; 1394199086Srpaulo else { 1395199086Srpaulo /* 1396199086Srpaulo * Penalise pending mickeys for having accumulated 1397199086Srpaulo * over short deltas. This operation has the effect of 1398199086Srpaulo * scaling down the cumulative contribution of short 1399199086Srpaulo * movements. 1400199086Srpaulo */ 1401199086Srpaulo component->pending -= (component->delta_mickeys << 1); 1402199086Srpaulo } 1403199086Srpaulo} 1404199086Srpaulo 1405199086Srpaulo 1406199086Srpaulostatic void 1407199086Srpauloatp_compute_smoothening_scale_ratio(atp_stroke *stroke, int *numerator, 1408199086Srpaulo int *denominator) 1409199086Srpaulo{ 1410199086Srpaulo int dxdt; 1411199086Srpaulo int dydt; 1412199086Srpaulo u_int vel_squared; /* Square of the velocity vector's magnitude. */ 1413199086Srpaulo u_int vel_squared_smooth; 1414199086Srpaulo 1415199086Srpaulo /* Table holding (10 * sqrt(x)) for x between 1 and 256. */ 1416199086Srpaulo static uint8_t sqrt_table[256] = { 1417199086Srpaulo 10, 14, 17, 20, 22, 24, 26, 28, 1418199086Srpaulo 30, 31, 33, 34, 36, 37, 38, 40, 1419199086Srpaulo 41, 42, 43, 44, 45, 46, 47, 48, 1420199086Srpaulo 50, 50, 51, 52, 53, 54, 55, 56, 1421199086Srpaulo 57, 58, 59, 60, 60, 61, 62, 63, 1422199086Srpaulo 64, 64, 65, 66, 67, 67, 68, 69, 1423199086Srpaulo 70, 70, 71, 72, 72, 73, 74, 74, 1424199086Srpaulo 75, 76, 76, 77, 78, 78, 79, 80, 1425199086Srpaulo 80, 81, 81, 82, 83, 83, 84, 84, 1426199086Srpaulo 85, 86, 86, 87, 87, 88, 88, 89, 1427199086Srpaulo 90, 90, 91, 91, 92, 92, 93, 93, 1428199086Srpaulo 94, 94, 95, 95, 96, 96, 97, 97, 1429199086Srpaulo 98, 98, 99, 100, 100, 100, 101, 101, 1430199086Srpaulo 102, 102, 103, 103, 104, 104, 105, 105, 1431199086Srpaulo 106, 106, 107, 107, 108, 108, 109, 109, 1432199086Srpaulo 110, 110, 110, 111, 111, 112, 112, 113, 1433199086Srpaulo 113, 114, 114, 114, 115, 115, 116, 116, 1434199086Srpaulo 117, 117, 117, 118, 118, 119, 119, 120, 1435199086Srpaulo 120, 120, 121, 121, 122, 122, 122, 123, 1436199086Srpaulo 123, 124, 124, 124, 125, 125, 126, 126, 1437199086Srpaulo 126, 127, 127, 128, 128, 128, 129, 129, 1438199086Srpaulo 130, 130, 130, 131, 131, 131, 132, 132, 1439199086Srpaulo 133, 133, 133, 134, 134, 134, 135, 135, 1440199086Srpaulo 136, 136, 136, 137, 137, 137, 138, 138, 1441199086Srpaulo 138, 139, 139, 140, 140, 140, 141, 141, 1442199086Srpaulo 141, 142, 142, 142, 143, 143, 143, 144, 1443199086Srpaulo 144, 144, 145, 145, 145, 146, 146, 146, 1444199086Srpaulo 147, 147, 147, 148, 148, 148, 149, 149, 1445199086Srpaulo 150, 150, 150, 150, 151, 151, 151, 152, 1446199086Srpaulo 152, 152, 153, 153, 153, 154, 154, 154, 1447199086Srpaulo 155, 155, 155, 156, 156, 156, 157, 157, 1448199086Srpaulo 157, 158, 158, 158, 159, 159, 159, 160 1449199086Srpaulo }; 1450199086Srpaulo const u_int N = sizeof(sqrt_table) / sizeof(sqrt_table[0]); 1451199086Srpaulo 1452199086Srpaulo dxdt = stroke->components[X].delta_mickeys; 1453199086Srpaulo dydt = stroke->components[Y].delta_mickeys; 1454199086Srpaulo 1455199086Srpaulo *numerator = 0, *denominator = 0; /* default values. */ 1456199086Srpaulo 1457199086Srpaulo /* Compute a smoothened magnitude_squared of the stroke's velocity. */ 1458199086Srpaulo vel_squared = dxdt * dxdt + dydt * dydt; 1459199086Srpaulo vel_squared_smooth = (3 * stroke->velocity_squared + vel_squared) >> 2; 1460199086Srpaulo stroke->velocity_squared = vel_squared_smooth; /* retained as history */ 1461199086Srpaulo if ((vel_squared == 0) || (vel_squared_smooth == 0)) 1462199086Srpaulo return; /* returning (numerator == 0) will imply zero movement*/ 1463199086Srpaulo 1464199086Srpaulo /* 1465199086Srpaulo * In order to determine the overall movement scale factor, 1466199086Srpaulo * we're actually interested in the effect of smoothening upon 1467199086Srpaulo * the *magnitude* of velocity; i.e. we need to compute the 1468199086Srpaulo * square-root of (vel_squared_smooth / vel_squared) in the 1469199086Srpaulo * form of a numerator and denominator. 1470199086Srpaulo */ 1471199086Srpaulo 1472199086Srpaulo /* Keep within the bounds of the square-root table. */ 1473199086Srpaulo while ((vel_squared > N) || (vel_squared_smooth > N)) { 1474199086Srpaulo /* Dividing uniformly by 2 won't disturb the final ratio. */ 1475199086Srpaulo vel_squared >>= 1; 1476199086Srpaulo vel_squared_smooth >>= 1; 1477199086Srpaulo } 1478199086Srpaulo 1479199086Srpaulo *numerator = sqrt_table[vel_squared_smooth - 1]; 1480199086Srpaulo *denominator = sqrt_table[vel_squared - 1]; 1481199086Srpaulo} 1482199086Srpaulo 1483199086Srpaulo/* 1484199086Srpaulo * Compute a smoothened value for the stroke's movement from 1485199086Srpaulo * delta_mickeys in the X and Y components. 1486199086Srpaulo */ 1487199086Srpaulostatic boolean_t 1488199086Srpauloatp_compute_stroke_movement(atp_stroke *stroke) 1489199086Srpaulo{ 1490199086Srpaulo int num; /* numerator of scale ratio */ 1491199086Srpaulo int denom; /* denominator of scale ratio */ 1492199086Srpaulo 1493199086Srpaulo /* 1494199086Srpaulo * Short movements are added first to the 'pending' bucket, 1495199086Srpaulo * and then acted upon only when their aggregate exceeds a 1496199086Srpaulo * threshold. This has the effect of filtering away movement 1497199086Srpaulo * noise. 1498199086Srpaulo */ 1499199086Srpaulo if (atp_stroke_has_small_movement(stroke)) { 1500199086Srpaulo atp_update_pending_mickeys(&stroke->components[X]); 1501199086Srpaulo atp_update_pending_mickeys(&stroke->components[Y]); 1502199086Srpaulo } else { /* large movement */ 1503199086Srpaulo /* clear away any pending mickeys if there are large movements*/ 1504199086Srpaulo stroke->components[X].pending = 0; 1505199086Srpaulo stroke->components[Y].pending = 0; 1506199086Srpaulo } 1507199086Srpaulo 1508199086Srpaulo /* Get the scale ratio and smoothen movement. */ 1509199086Srpaulo atp_compute_smoothening_scale_ratio(stroke, &num, &denom); 1510199086Srpaulo if ((num == 0) || (denom == 0)) { 1511199086Srpaulo stroke->components[X].movement = 0; 1512199086Srpaulo stroke->components[Y].movement = 0; 1513199086Srpaulo stroke->velocity_squared >>= 1; /* Erode velocity_squared. */ 1514199086Srpaulo } else { 1515199086Srpaulo stroke->components[X].movement = 1516199086Srpaulo (stroke->components[X].delta_mickeys * num) / denom; 1517199086Srpaulo stroke->components[Y].movement = 1518199086Srpaulo (stroke->components[Y].delta_mickeys * num) / denom; 1519199086Srpaulo 1520199086Srpaulo stroke->cum_movement += 1521199086Srpaulo abs(stroke->components[X].movement) + 1522199086Srpaulo abs(stroke->components[Y].movement); 1523199086Srpaulo } 1524199086Srpaulo 1525199086Srpaulo return ((stroke->components[X].movement != 0) || 1526199086Srpaulo (stroke->components[Y].movement != 0)); 1527199086Srpaulo} 1528199086Srpaulo 1529199086Srpaulostatic __inline void 1530199086Srpauloatp_setup_reap_time(struct atp_softc *sc, struct timeval *tvp) 1531199086Srpaulo{ 1532199086Srpaulo struct timeval reap_window = { 1533199086Srpaulo ATP_ZOMBIE_STROKE_REAP_WINDOW / 1000000, 1534199086Srpaulo ATP_ZOMBIE_STROKE_REAP_WINDOW % 1000000 1535199086Srpaulo }; 1536199086Srpaulo 1537199086Srpaulo microtime(&sc->sc_reap_time); 1538199086Srpaulo timevaladd(&sc->sc_reap_time, &reap_window); 1539199086Srpaulo 1540199086Srpaulo sc->sc_reap_ctime = *tvp; /* ctime to reap */ 1541199086Srpaulo} 1542199086Srpaulo 1543199086Srpaulostatic void 1544199086Srpauloatp_reap_zombies(struct atp_softc *sc, u_int *n_reaped, u_int *reaped_xlocs) 1545199086Srpaulo{ 1546199086Srpaulo u_int i; 1547199086Srpaulo atp_stroke *stroke; 1548199086Srpaulo 1549199086Srpaulo *n_reaped = 0; 1550199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1551199086Srpaulo struct timeval tdiff; 1552199086Srpaulo 1553199086Srpaulo stroke = &sc->sc_strokes[i]; 1554199086Srpaulo 1555199086Srpaulo if ((stroke->flags & ATSF_ZOMBIE) == 0) 1556199086Srpaulo continue; 1557199086Srpaulo 1558199086Srpaulo /* Compare this stroke's ctime with the ctime being reaped. */ 1559199086Srpaulo if (timevalcmp(&stroke->ctime, &sc->sc_reap_ctime, >=)) { 1560199086Srpaulo tdiff = stroke->ctime; 1561199086Srpaulo timevalsub(&tdiff, &sc->sc_reap_ctime); 1562199086Srpaulo } else { 1563199086Srpaulo tdiff = sc->sc_reap_ctime; 1564199086Srpaulo timevalsub(&tdiff, &stroke->ctime); 1565199086Srpaulo } 1566199086Srpaulo 1567199086Srpaulo if ((tdiff.tv_sec > (ATP_COINCIDENCE_THRESHOLD / 1000000)) || 1568199086Srpaulo ((tdiff.tv_sec == (ATP_COINCIDENCE_THRESHOLD / 1000000)) && 1569199086Srpaulo (tdiff.tv_usec > (ATP_COINCIDENCE_THRESHOLD % 1000000)))) { 1570199086Srpaulo continue; /* Skip non-siblings. */ 1571199086Srpaulo } 1572199086Srpaulo 1573199086Srpaulo /* 1574199086Srpaulo * Reap this sibling zombie stroke. 1575199086Srpaulo */ 1576199086Srpaulo 1577199086Srpaulo if (reaped_xlocs != NULL) 1578199086Srpaulo reaped_xlocs[*n_reaped] = stroke->components[X].loc; 1579199086Srpaulo 1580199086Srpaulo /* Erase the stroke from the sc. */ 1581199086Srpaulo memcpy(&stroke[i], &stroke[i + 1], 1582199086Srpaulo (sc->sc_n_strokes - i - 1) * sizeof(atp_stroke)); 1583199086Srpaulo sc->sc_n_strokes--; 1584199086Srpaulo 1585199086Srpaulo *n_reaped += 1; 1586199086Srpaulo --i; /* Decr. i to keep it unchanged for the next iteration */ 1587199086Srpaulo } 1588199086Srpaulo 1589199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "reaped %u zombies\n", *n_reaped); 1590199086Srpaulo 1591199086Srpaulo /* There could still be zombies remaining in the system. */ 1592199086Srpaulo for (i = 0; i < sc->sc_n_strokes; i++) { 1593199086Srpaulo stroke = &sc->sc_strokes[i]; 1594199086Srpaulo if (stroke->flags & ATSF_ZOMBIE) { 1595199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "zombies remain!\n"); 1596199086Srpaulo atp_setup_reap_time(sc, &stroke->ctime); 1597199086Srpaulo return; 1598199086Srpaulo } 1599199086Srpaulo } 1600199086Srpaulo 1601199086Srpaulo /* If we reach here, then no more zombies remain. */ 1602199086Srpaulo sc->sc_state &= ~ATP_ZOMBIES_EXIST; 1603199086Srpaulo} 1604199086Srpaulo 1605199086Srpaulo 1606199086Srpaulo/* Device methods. */ 1607199086Srpaulostatic device_probe_t atp_probe; 1608199086Srpaulostatic device_attach_t atp_attach; 1609199086Srpaulostatic device_detach_t atp_detach; 1610199086Srpaulostatic usb_callback_t atp_intr; 1611199086Srpaulo 1612199086Srpaulostatic const struct usb_config atp_config[ATP_N_TRANSFER] = { 1613199086Srpaulo [ATP_INTR_DT] = { 1614199086Srpaulo .type = UE_INTERRUPT, 1615199086Srpaulo .endpoint = UE_ADDR_ANY, 1616199086Srpaulo .direction = UE_DIR_IN, 1617199086Srpaulo .flags = { 1618199086Srpaulo .pipe_bof = 1, 1619199086Srpaulo .short_xfer_ok = 1, 1620199086Srpaulo }, 1621199086Srpaulo .bufsize = 0, /* use wMaxPacketSize */ 1622199086Srpaulo .callback = &atp_intr, 1623199086Srpaulo }, 1624199680Sthompsa [ATP_RESET] = { 1625199680Sthompsa .type = UE_CONTROL, 1626199680Sthompsa .endpoint = 0, /* Control pipe */ 1627199680Sthompsa .direction = UE_DIR_ANY, 1628199680Sthompsa .bufsize = sizeof(struct usb_device_request) + MODE_LENGTH, 1629199680Sthompsa .callback = &atp_reset_callback, 1630199680Sthompsa .interval = 0, /* no pre-delay */ 1631199680Sthompsa }, 1632199086Srpaulo}; 1633199086Srpaulo 1634199086Srpaulostatic int 1635199086Srpauloatp_probe(device_t self) 1636199086Srpaulo{ 1637199086Srpaulo struct usb_attach_arg *uaa = device_get_ivars(self); 1638199086Srpaulo 1639199086Srpaulo if (uaa->usb_mode != USB_MODE_HOST) 1640199086Srpaulo return (ENXIO); 1641199086Srpaulo 1642199086Srpaulo if ((uaa->info.bInterfaceClass != UICLASS_HID) || 1643199086Srpaulo (uaa->info.bInterfaceProtocol != UIPROTO_MOUSE)) 1644199086Srpaulo return (ENXIO); 1645199086Srpaulo 1646199680Sthompsa return (usbd_lookup_id_by_uaa(atp_devs, sizeof(atp_devs), uaa)); 1647199086Srpaulo} 1648199086Srpaulo 1649199086Srpaulostatic int 1650199086Srpauloatp_attach(device_t dev) 1651199086Srpaulo{ 1652199086Srpaulo struct atp_softc *sc = device_get_softc(dev); 1653199086Srpaulo struct usb_attach_arg *uaa = device_get_ivars(dev); 1654199086Srpaulo usb_error_t err; 1655199086Srpaulo 1656199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "sc=%p\n", sc); 1657199086Srpaulo 1658199086Srpaulo sc->sc_dev = dev; 1659199086Srpaulo sc->sc_usb_device = uaa->device; 1660199086Srpaulo 1661199086Srpaulo /* 1662199086Srpaulo * By default the touchpad behaves like an HID device, sending 1663199086Srpaulo * packets with reportID = 2. Such reports contain only 1664199086Srpaulo * limited information--they encode movement deltas and button 1665199086Srpaulo * events,--but do not include data from the pressure 1666199086Srpaulo * sensors. The device input mode can be switched from HID 1667199086Srpaulo * reports to raw sensor data using vendor-specific USB 1668199086Srpaulo * control commands; but first the mode must be read. 1669199086Srpaulo */ 1670199086Srpaulo err = atp_req_get_report(sc->sc_usb_device, sc->sc_mode_bytes); 1671199086Srpaulo if (err != USB_ERR_NORMAL_COMPLETION) { 1672199086Srpaulo DPRINTF("failed to read device mode (%d)\n", err); 1673199086Srpaulo return (ENXIO); 1674199086Srpaulo } 1675199086Srpaulo 1676199086Srpaulo if (atp_set_device_mode(dev, RAW_SENSOR_MODE) != 0) { 1677199086Srpaulo DPRINTF("failed to set mode to 'RAW_SENSOR' (%d)\n", err); 1678199086Srpaulo return (ENXIO); 1679199086Srpaulo } 1680199086Srpaulo 1681199086Srpaulo mtx_init(&sc->sc_mutex, "atpmtx", NULL, MTX_DEF | MTX_RECURSE); 1682199086Srpaulo 1683199086Srpaulo err = usbd_transfer_setup(uaa->device, 1684199086Srpaulo &uaa->info.bIfaceIndex, sc->sc_xfer, atp_config, 1685199086Srpaulo ATP_N_TRANSFER, sc, &sc->sc_mutex); 1686199086Srpaulo 1687199086Srpaulo if (err) { 1688199086Srpaulo DPRINTF("error=%s\n", usbd_errstr(err)); 1689199086Srpaulo goto detach; 1690199086Srpaulo } 1691199086Srpaulo 1692199086Srpaulo if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex, 1693199086Srpaulo &atp_fifo_methods, &sc->sc_fifo, 1694233774Shselasky device_get_unit(dev), -1, uaa->info.bIfaceIndex, 1695199086Srpaulo UID_ROOT, GID_OPERATOR, 0644)) { 1696199086Srpaulo goto detach; 1697199086Srpaulo } 1698199086Srpaulo 1699199086Srpaulo device_set_usb_desc(dev); 1700199086Srpaulo 1701199086Srpaulo sc->sc_params = &atp_dev_params[uaa->driver_info]; 1702199086Srpaulo 1703199086Srpaulo sc->sc_hw.buttons = 3; 1704199086Srpaulo sc->sc_hw.iftype = MOUSE_IF_USB; 1705199086Srpaulo sc->sc_hw.type = MOUSE_PAD; 1706199086Srpaulo sc->sc_hw.model = MOUSE_MODEL_GENERIC; 1707199086Srpaulo sc->sc_hw.hwid = 0; 1708199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 1709199086Srpaulo sc->sc_mode.rate = -1; 1710199086Srpaulo sc->sc_mode.resolution = MOUSE_RES_UNKNOWN; 1711199086Srpaulo sc->sc_mode.accelfactor = 0; 1712199086Srpaulo sc->sc_mode.level = 0; 1713199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 1714199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 1715199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 1716199086Srpaulo 1717199086Srpaulo sc->sc_state = 0; 1718199086Srpaulo 1719199086Srpaulo sc->sc_left_margin = atp_mickeys_scale_factor; 1720199086Srpaulo sc->sc_right_margin = (sc->sc_params->n_xsensors - 1) * 1721199086Srpaulo atp_mickeys_scale_factor; 1722199086Srpaulo 1723199086Srpaulo return (0); 1724199086Srpaulo 1725199086Srpaulodetach: 1726199086Srpaulo atp_detach(dev); 1727199086Srpaulo return (ENOMEM); 1728199086Srpaulo} 1729199086Srpaulo 1730199086Srpaulostatic int 1731199086Srpauloatp_detach(device_t dev) 1732199086Srpaulo{ 1733199086Srpaulo struct atp_softc *sc; 1734199086Srpaulo 1735199086Srpaulo sc = device_get_softc(dev); 1736199086Srpaulo if (sc->sc_state & ATP_ENABLED) { 1737199086Srpaulo mtx_lock(&sc->sc_mutex); 1738199086Srpaulo atp_disable(sc); 1739199086Srpaulo mtx_unlock(&sc->sc_mutex); 1740199086Srpaulo } 1741199086Srpaulo 1742199086Srpaulo usb_fifo_detach(&sc->sc_fifo); 1743199086Srpaulo 1744199086Srpaulo usbd_transfer_unsetup(sc->sc_xfer, ATP_N_TRANSFER); 1745199086Srpaulo 1746199086Srpaulo mtx_destroy(&sc->sc_mutex); 1747199086Srpaulo 1748199086Srpaulo return (0); 1749199086Srpaulo} 1750199086Srpaulo 1751199086Srpaulostatic void 1752199086Srpauloatp_intr(struct usb_xfer *xfer, usb_error_t error) 1753199086Srpaulo{ 1754199086Srpaulo struct atp_softc *sc = usbd_xfer_softc(xfer); 1755199086Srpaulo int len; 1756199086Srpaulo struct usb_page_cache *pc; 1757199086Srpaulo uint8_t status_bits; 1758199086Srpaulo atp_pspan pspans_x[ATP_MAX_PSPANS_PER_AXIS]; 1759199086Srpaulo atp_pspan pspans_y[ATP_MAX_PSPANS_PER_AXIS]; 1760199086Srpaulo u_int n_xpspans = 0, n_ypspans = 0; 1761199086Srpaulo u_int reaped_xlocs[ATP_MAX_STROKES]; 1762199086Srpaulo u_int tap_fingers = 0; 1763199086Srpaulo 1764199086Srpaulo usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 1765199086Srpaulo 1766199086Srpaulo switch (USB_GET_STATE(xfer)) { 1767199086Srpaulo case USB_ST_TRANSFERRED: 1768233774Shselasky if (len > (int)sc->sc_params->data_len) { 1769199086Srpaulo DPRINTFN(ATP_LLEVEL_ERROR, 1770199086Srpaulo "truncating large packet from %u to %u bytes\n", 1771199086Srpaulo len, sc->sc_params->data_len); 1772199086Srpaulo len = sc->sc_params->data_len; 1773199086Srpaulo } 1774233774Shselasky if (len < (int)sc->sc_params->data_len) 1775199086Srpaulo goto tr_setup; 1776199086Srpaulo 1777199086Srpaulo pc = usbd_xfer_get_frame(xfer, 0); 1778199086Srpaulo usbd_copy_out(pc, 0, sc->sensor_data, sc->sc_params->data_len); 1779199086Srpaulo 1780199086Srpaulo /* Interpret sensor data */ 1781199086Srpaulo atp_interpret_sensor_data(sc->sensor_data, 1782199151Snwhitehorn sc->sc_params->n_xsensors, X, sc->cur_x, 1783199151Snwhitehorn sc->sc_params->prot); 1784199086Srpaulo atp_interpret_sensor_data(sc->sensor_data, 1785199151Snwhitehorn sc->sc_params->n_ysensors, Y, sc->cur_y, 1786199151Snwhitehorn sc->sc_params->prot); 1787199086Srpaulo 1788199086Srpaulo /* 1789199086Srpaulo * If this is the initial update (from an untouched 1790199086Srpaulo * pad), we should set the base values for the sensor 1791199086Srpaulo * data; deltas with respect to these base values can 1792199086Srpaulo * be used as pressure readings subsequently. 1793199086Srpaulo */ 1794199086Srpaulo status_bits = sc->sensor_data[sc->sc_params->data_len - 1]; 1795199151Snwhitehorn if ((sc->sc_params->prot == ATP_PROT_GEYSER3 && 1796200241Srpaulo (status_bits & ATP_STATUS_BASE_UPDATE)) || 1797199151Snwhitehorn !(sc->sc_state & ATP_VALID)) { 1798199086Srpaulo memcpy(sc->base_x, sc->cur_x, 1799199086Srpaulo sc->sc_params->n_xsensors * sizeof(*(sc->base_x))); 1800199086Srpaulo memcpy(sc->base_y, sc->cur_y, 1801199086Srpaulo sc->sc_params->n_ysensors * sizeof(*(sc->base_y))); 1802199151Snwhitehorn sc->sc_state |= ATP_VALID; 1803199086Srpaulo goto tr_setup; 1804199086Srpaulo } 1805199086Srpaulo 1806199086Srpaulo /* Get pressure readings and detect p-spans for both axes. */ 1807199086Srpaulo atp_get_pressures(sc->pressure_x, sc->cur_x, sc->base_x, 1808199086Srpaulo sc->sc_params->n_xsensors); 1809199086Srpaulo atp_detect_pspans(sc->pressure_x, sc->sc_params->n_xsensors, 1810199086Srpaulo ATP_MAX_PSPANS_PER_AXIS, 1811199086Srpaulo pspans_x, &n_xpspans); 1812199086Srpaulo atp_get_pressures(sc->pressure_y, sc->cur_y, sc->base_y, 1813199086Srpaulo sc->sc_params->n_ysensors); 1814199086Srpaulo atp_detect_pspans(sc->pressure_y, sc->sc_params->n_ysensors, 1815199086Srpaulo ATP_MAX_PSPANS_PER_AXIS, 1816199086Srpaulo pspans_y, &n_ypspans); 1817199086Srpaulo 1818199086Srpaulo /* Update strokes with new pspans to detect movements. */ 1819199086Srpaulo sc->sc_status.flags &= ~MOUSE_POSCHANGED; 1820199086Srpaulo if (atp_update_strokes(sc, 1821199086Srpaulo pspans_x, n_xpspans, 1822199086Srpaulo pspans_y, n_ypspans)) 1823199086Srpaulo sc->sc_status.flags |= MOUSE_POSCHANGED; 1824199086Srpaulo 1825199086Srpaulo /* Reap zombies if it is time. */ 1826199086Srpaulo if (sc->sc_state & ATP_ZOMBIES_EXIST) { 1827199086Srpaulo struct timeval now; 1828199086Srpaulo 1829199086Srpaulo getmicrotime(&now); 1830199086Srpaulo if (timevalcmp(&now, &sc->sc_reap_time, >=)) 1831199086Srpaulo atp_reap_zombies(sc, &tap_fingers, 1832199086Srpaulo reaped_xlocs); 1833199086Srpaulo } 1834199086Srpaulo 1835199086Srpaulo sc->sc_status.flags &= ~MOUSE_STDBUTTONSCHANGED; 1836199086Srpaulo sc->sc_status.obutton = sc->sc_status.button; 1837199086Srpaulo 1838199086Srpaulo /* Get the state of the physical buttton. */ 1839199086Srpaulo sc->sc_status.button = (status_bits & ATP_STATUS_BUTTON) ? 1840199086Srpaulo MOUSE_BUTTON1DOWN : 0; 1841199086Srpaulo if (sc->sc_status.button != 0) { 1842199086Srpaulo /* Reset DOUBLE_TAP_N_DRAG if the button is pressed. */ 1843199086Srpaulo sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; 1844199086Srpaulo } else if (sc->sc_state & ATP_DOUBLE_TAP_DRAG) { 1845199086Srpaulo /* Assume a button-press with DOUBLE_TAP_N_DRAG. */ 1846199086Srpaulo sc->sc_status.button = MOUSE_BUTTON1DOWN; 1847199086Srpaulo } 1848199086Srpaulo 1849199086Srpaulo sc->sc_status.flags |= 1850199086Srpaulo sc->sc_status.button ^ sc->sc_status.obutton; 1851199086Srpaulo if (sc->sc_status.flags & MOUSE_STDBUTTONSCHANGED) { 1852199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "button %s\n", 1853199086Srpaulo ((sc->sc_status.button & MOUSE_BUTTON1DOWN) ? 1854199086Srpaulo "pressed" : "released")); 1855199086Srpaulo } else if ((sc->sc_status.obutton == 0) && 1856199086Srpaulo (sc->sc_status.button == 0) && 1857199086Srpaulo (tap_fingers != 0)) { 1858199086Srpaulo /* Ignore single-finger taps at the edges. */ 1859199086Srpaulo if ((tap_fingers == 1) && 1860199086Srpaulo ((reaped_xlocs[0] <= sc->sc_left_margin) || 1861199086Srpaulo (reaped_xlocs[0] > sc->sc_right_margin))) { 1862199086Srpaulo tap_fingers = 0; 1863199086Srpaulo } 1864199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, 1865199086Srpaulo "tap_fingers: %u\n", tap_fingers); 1866199086Srpaulo } 1867199086Srpaulo 1868199086Srpaulo if (sc->sc_status.flags & 1869199086Srpaulo (MOUSE_POSCHANGED | MOUSE_STDBUTTONSCHANGED)) { 1870199086Srpaulo int dx, dy; 1871199086Srpaulo u_int n_movements; 1872199086Srpaulo 1873199086Srpaulo dx = 0, dy = 0, n_movements = 0; 1874199086Srpaulo for (u_int i = 0; i < sc->sc_n_strokes; i++) { 1875199086Srpaulo atp_stroke *stroke = &sc->sc_strokes[i]; 1876199086Srpaulo 1877199086Srpaulo if ((stroke->components[X].movement) || 1878199086Srpaulo (stroke->components[Y].movement)) { 1879199086Srpaulo dx += stroke->components[X].movement; 1880199086Srpaulo dy += stroke->components[Y].movement; 1881199086Srpaulo n_movements++; 1882199086Srpaulo } 1883199086Srpaulo } 1884199086Srpaulo /* 1885199086Srpaulo * Disregard movement if multiple 1886199086Srpaulo * strokes record motion. 1887199086Srpaulo */ 1888199086Srpaulo if (n_movements != 1) 1889199086Srpaulo dx = 0, dy = 0; 1890199086Srpaulo 1891199086Srpaulo sc->sc_status.dx += dx; 1892199086Srpaulo sc->sc_status.dy += dy; 1893199086Srpaulo atp_add_to_queue(sc, dx, -dy, sc->sc_status.button); 1894199086Srpaulo } 1895199086Srpaulo 1896199086Srpaulo if (tap_fingers != 0) { 1897199086Srpaulo /* Add a pair of events (button-down and button-up). */ 1898199086Srpaulo switch (tap_fingers) { 1899199086Srpaulo case 1: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON1DOWN); 1900199086Srpaulo break; 1901199086Srpaulo case 2: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON2DOWN); 1902199086Srpaulo break; 1903199086Srpaulo case 3: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON3DOWN); 1904199086Srpaulo break; 1905199086Srpaulo default: break;/* handle taps of only up to 3 fingers */ 1906199086Srpaulo } 1907199086Srpaulo atp_add_to_queue(sc, 0, 0, 0); /* button release */ 1908199086Srpaulo } 1909199086Srpaulo 1910199086Srpaulo /* 1911199086Srpaulo * The device continues to trigger interrupts at a 1912199086Srpaulo * fast rate even after touchpad activity has 1913199086Srpaulo * stopped. Upon detecting that the device has 1914199086Srpaulo * remained idle beyond a threshold, we reinitialize 1915199086Srpaulo * it to silence the interrupts. 1916199086Srpaulo */ 1917199086Srpaulo if ((sc->sc_status.flags == 0) && 1918199086Srpaulo (sc->sc_n_strokes == 0) && 1919199086Srpaulo (sc->sc_status.button == 0)) { 1920199086Srpaulo sc->sc_idlecount++; 1921199086Srpaulo if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) { 1922199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "idle\n"); 1923199948Snwhitehorn 1924199948Snwhitehorn /* 1925199948Snwhitehorn * Use the last frame before we go idle for 1926199948Snwhitehorn * calibration on pads which do not send 1927199948Snwhitehorn * calibration frames. 1928199948Snwhitehorn */ 1929199948Snwhitehorn if (sc->sc_params->prot < ATP_PROT_GEYSER3) { 1930199948Snwhitehorn memcpy(sc->base_x, sc->cur_x, 1931199948Snwhitehorn sc->sc_params->n_xsensors * 1932199948Snwhitehorn sizeof(*(sc->base_x))); 1933199948Snwhitehorn memcpy(sc->base_y, sc->cur_y, 1934199948Snwhitehorn sc->sc_params->n_ysensors * 1935199948Snwhitehorn sizeof(*(sc->base_y))); 1936199948Snwhitehorn } 1937199948Snwhitehorn 1938199151Snwhitehorn sc->sc_idlecount = 0; 1939199680Sthompsa usbd_transfer_start(sc->sc_xfer[ATP_RESET]); 1940199086Srpaulo } 1941199086Srpaulo } else { 1942199086Srpaulo sc->sc_idlecount = 0; 1943199086Srpaulo } 1944199086Srpaulo 1945199086Srpaulo case USB_ST_SETUP: 1946199086Srpaulo tr_setup: 1947199086Srpaulo /* check if we can put more data into the FIFO */ 1948199086Srpaulo if (usb_fifo_put_bytes_max( 1949199086Srpaulo sc->sc_fifo.fp[USB_FIFO_RX]) != 0) { 1950199086Srpaulo usbd_xfer_set_frame_len(xfer, 0, 1951199151Snwhitehorn sc->sc_params->data_len); 1952199086Srpaulo usbd_transfer_submit(xfer); 1953199086Srpaulo } 1954199086Srpaulo break; 1955199086Srpaulo 1956199086Srpaulo default: /* Error */ 1957199086Srpaulo if (error != USB_ERR_CANCELLED) { 1958199086Srpaulo /* try clear stall first */ 1959199086Srpaulo usbd_xfer_set_stall(xfer); 1960199086Srpaulo goto tr_setup; 1961199086Srpaulo } 1962199086Srpaulo break; 1963199086Srpaulo } 1964199086Srpaulo 1965199086Srpaulo return; 1966199086Srpaulo} 1967199086Srpaulo 1968199086Srpaulostatic void 1969199086Srpauloatp_add_to_queue(struct atp_softc *sc, int dx, int dy, uint32_t buttons_in) 1970199086Srpaulo{ 1971199086Srpaulo uint32_t buttons_out; 1972199086Srpaulo uint8_t buf[8]; 1973199086Srpaulo 1974199086Srpaulo dx = imin(dx, 254); dx = imax(dx, -256); 1975199086Srpaulo dy = imin(dy, 254); dy = imax(dy, -256); 1976199086Srpaulo 1977199086Srpaulo buttons_out = MOUSE_MSC_BUTTONS; 1978199086Srpaulo if (buttons_in & MOUSE_BUTTON1DOWN) 1979199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON1UP; 1980199086Srpaulo else if (buttons_in & MOUSE_BUTTON2DOWN) 1981199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON2UP; 1982199086Srpaulo else if (buttons_in & MOUSE_BUTTON3DOWN) 1983199086Srpaulo buttons_out &= ~MOUSE_MSC_BUTTON3UP; 1984199086Srpaulo 1985199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "dx=%d, dy=%d, buttons=%x\n", 1986199086Srpaulo dx, dy, buttons_out); 1987199086Srpaulo 1988199086Srpaulo /* Encode the mouse data in standard format; refer to mouse(4) */ 1989199086Srpaulo buf[0] = sc->sc_mode.syncmask[1]; 1990199086Srpaulo buf[0] |= buttons_out; 1991199086Srpaulo buf[1] = dx >> 1; 1992199086Srpaulo buf[2] = dy >> 1; 1993199086Srpaulo buf[3] = dx - (dx >> 1); 1994199086Srpaulo buf[4] = dy - (dy >> 1); 1995199086Srpaulo /* Encode extra bytes for level 1 */ 1996199086Srpaulo if (sc->sc_mode.level == 1) { 1997199086Srpaulo buf[5] = 0; /* dz */ 1998199086Srpaulo buf[6] = 0; /* dz - (dz / 2) */ 1999199086Srpaulo buf[7] = MOUSE_SYS_EXTBUTTONS; /* Extra buttons all up. */ 2000199086Srpaulo } 2001199086Srpaulo 2002199086Srpaulo usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, 2003199086Srpaulo sc->sc_mode.packetsize, 1); 2004199086Srpaulo} 2005199086Srpaulo 2006199086Srpaulostatic void 2007199086Srpauloatp_reset_buf(struct atp_softc *sc) 2008199086Srpaulo{ 2009199086Srpaulo /* reset read queue */ 2010199086Srpaulo usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]); 2011199086Srpaulo} 2012199086Srpaulo 2013199086Srpaulostatic void 2014199086Srpauloatp_start_read(struct usb_fifo *fifo) 2015199086Srpaulo{ 2016199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2017199086Srpaulo int rate; 2018199086Srpaulo 2019199086Srpaulo /* Check if we should override the default polling interval */ 2020199086Srpaulo rate = sc->sc_pollrate; 2021199086Srpaulo /* Range check rate */ 2022199086Srpaulo if (rate > 1000) 2023199086Srpaulo rate = 1000; 2024199086Srpaulo /* Check for set rate */ 2025199086Srpaulo if ((rate > 0) && (sc->sc_xfer[ATP_INTR_DT] != NULL)) { 2026199086Srpaulo /* Stop current transfer, if any */ 2027199086Srpaulo usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); 2028199086Srpaulo /* Set new interval */ 2029199086Srpaulo usbd_xfer_set_interval(sc->sc_xfer[ATP_INTR_DT], 1000 / rate); 2030199086Srpaulo /* Only set pollrate once */ 2031199086Srpaulo sc->sc_pollrate = 0; 2032199086Srpaulo } 2033199086Srpaulo 2034199086Srpaulo usbd_transfer_start(sc->sc_xfer[ATP_INTR_DT]); 2035199086Srpaulo} 2036199086Srpaulo 2037199086Srpaulostatic void 2038199086Srpauloatp_stop_read(struct usb_fifo *fifo) 2039199086Srpaulo{ 2040199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2041199086Srpaulo 2042199086Srpaulo usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); 2043199086Srpaulo} 2044199086Srpaulo 2045199086Srpaulo 2046199086Srpaulostatic int 2047199086Srpauloatp_open(struct usb_fifo *fifo, int fflags) 2048199086Srpaulo{ 2049199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "\n"); 2050199086Srpaulo 2051199086Srpaulo if (fflags & FREAD) { 2052199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2053199086Srpaulo int rc; 2054199086Srpaulo 2055199086Srpaulo if (sc->sc_state & ATP_ENABLED) 2056199086Srpaulo return (EBUSY); 2057199086Srpaulo 2058199086Srpaulo if (usb_fifo_alloc_buffer(fifo, 2059199086Srpaulo ATP_FIFO_BUF_SIZE, ATP_FIFO_QUEUE_MAXLEN)) { 2060199086Srpaulo return (ENOMEM); 2061199086Srpaulo } 2062199086Srpaulo 2063199086Srpaulo rc = atp_enable(sc); 2064199086Srpaulo if (rc != 0) { 2065199086Srpaulo usb_fifo_free_buffer(fifo); 2066199086Srpaulo return (rc); 2067199086Srpaulo } 2068199086Srpaulo } 2069199086Srpaulo 2070199086Srpaulo return (0); 2071199086Srpaulo} 2072199086Srpaulo 2073199086Srpaulostatic void 2074199086Srpauloatp_close(struct usb_fifo *fifo, int fflags) 2075199086Srpaulo{ 2076199086Srpaulo if (fflags & FREAD) { 2077199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2078199086Srpaulo 2079199086Srpaulo atp_disable(sc); 2080199086Srpaulo usb_fifo_free_buffer(fifo); 2081199086Srpaulo } 2082199086Srpaulo} 2083199086Srpaulo 2084199086Srpauloint 2085199086Srpauloatp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) 2086199086Srpaulo{ 2087199086Srpaulo struct atp_softc *sc = usb_fifo_softc(fifo); 2088199086Srpaulo mousemode_t mode; 2089199086Srpaulo int error = 0; 2090199086Srpaulo 2091199086Srpaulo mtx_lock(&sc->sc_mutex); 2092199086Srpaulo 2093199086Srpaulo switch(cmd) { 2094199086Srpaulo case MOUSE_GETHWINFO: 2095199086Srpaulo *(mousehw_t *)addr = sc->sc_hw; 2096199086Srpaulo break; 2097199086Srpaulo case MOUSE_GETMODE: 2098199086Srpaulo *(mousemode_t *)addr = sc->sc_mode; 2099199086Srpaulo break; 2100199086Srpaulo case MOUSE_SETMODE: 2101199086Srpaulo mode = *(mousemode_t *)addr; 2102199086Srpaulo 2103199086Srpaulo if (mode.level == -1) 2104199086Srpaulo /* Don't change the current setting */ 2105199086Srpaulo ; 2106199086Srpaulo else if ((mode.level < 0) || (mode.level > 1)) { 2107199086Srpaulo error = EINVAL; 2108199086Srpaulo goto done; 2109199086Srpaulo } 2110199086Srpaulo sc->sc_mode.level = mode.level; 2111199086Srpaulo sc->sc_pollrate = mode.rate; 2112199086Srpaulo sc->sc_hw.buttons = 3; 2113199086Srpaulo 2114199086Srpaulo if (sc->sc_mode.level == 0) { 2115199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 2116199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 2117199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 2118199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 2119199086Srpaulo } else if (sc->sc_mode.level == 1) { 2120199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 2121199086Srpaulo sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 2122199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 2123199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 2124199086Srpaulo } 2125199086Srpaulo atp_reset_buf(sc); 2126199086Srpaulo break; 2127199086Srpaulo case MOUSE_GETLEVEL: 2128199086Srpaulo *(int *)addr = sc->sc_mode.level; 2129199086Srpaulo break; 2130199086Srpaulo case MOUSE_SETLEVEL: 2131199086Srpaulo if (*(int *)addr < 0 || *(int *)addr > 1) { 2132199086Srpaulo error = EINVAL; 2133199086Srpaulo goto done; 2134199086Srpaulo } 2135199086Srpaulo sc->sc_mode.level = *(int *)addr; 2136199086Srpaulo sc->sc_hw.buttons = 3; 2137199086Srpaulo 2138199086Srpaulo if (sc->sc_mode.level == 0) { 2139199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_MSC; 2140199086Srpaulo sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 2141199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 2142199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 2143199086Srpaulo } else if (sc->sc_mode.level == 1) { 2144199086Srpaulo sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 2145199086Srpaulo sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 2146199086Srpaulo sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 2147199086Srpaulo sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 2148199086Srpaulo } 2149199086Srpaulo atp_reset_buf(sc); 2150199086Srpaulo break; 2151199086Srpaulo case MOUSE_GETSTATUS: { 2152199086Srpaulo mousestatus_t *status = (mousestatus_t *)addr; 2153199086Srpaulo 2154199086Srpaulo *status = sc->sc_status; 2155199086Srpaulo sc->sc_status.obutton = sc->sc_status.button; 2156199086Srpaulo sc->sc_status.button = 0; 2157199086Srpaulo sc->sc_status.dx = 0; 2158199086Srpaulo sc->sc_status.dy = 0; 2159199086Srpaulo sc->sc_status.dz = 0; 2160199086Srpaulo 2161199086Srpaulo if (status->dx || status->dy || status->dz) 2162199086Srpaulo status->flags |= MOUSE_POSCHANGED; 2163199086Srpaulo if (status->button != status->obutton) 2164199086Srpaulo status->flags |= MOUSE_BUTTONSCHANGED; 2165199086Srpaulo break; 2166199086Srpaulo } 2167199086Srpaulo default: 2168199086Srpaulo error = ENOTTY; 2169199086Srpaulo } 2170199086Srpaulo 2171199086Srpaulodone: 2172199086Srpaulo mtx_unlock(&sc->sc_mutex); 2173199086Srpaulo return (error); 2174199086Srpaulo} 2175199086Srpaulo 2176199086Srpaulostatic int 2177199086Srpauloatp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS) 2178199086Srpaulo{ 2179199086Srpaulo int error; 2180199086Srpaulo u_int tmp; 2181199086Srpaulo u_int prev_mickeys_scale_factor; 2182199086Srpaulo 2183199086Srpaulo prev_mickeys_scale_factor = atp_mickeys_scale_factor; 2184199086Srpaulo 2185199086Srpaulo tmp = atp_mickeys_scale_factor; 2186199086Srpaulo error = sysctl_handle_int(oidp, &tmp, 0, req); 2187199086Srpaulo if (error != 0 || req->newptr == NULL) 2188199086Srpaulo return (error); 2189199086Srpaulo 2190199086Srpaulo if (tmp == prev_mickeys_scale_factor) 2191199086Srpaulo return (0); /* no change */ 2192199086Srpaulo 2193199086Srpaulo atp_mickeys_scale_factor = tmp; 2194199086Srpaulo DPRINTFN(ATP_LLEVEL_INFO, "%s: resetting mickeys_scale_factor to %u\n", 2195199086Srpaulo ATP_DRIVER_NAME, tmp); 2196199086Srpaulo 2197199086Srpaulo /* Update dependent thresholds. */ 2198199086Srpaulo if (atp_small_movement_threshold == (prev_mickeys_scale_factor >> 3)) 2199199086Srpaulo atp_small_movement_threshold = atp_mickeys_scale_factor >> 3; 2200199086Srpaulo if (atp_max_delta_mickeys == ((3 * prev_mickeys_scale_factor) >> 1)) 2201199086Srpaulo atp_max_delta_mickeys = ((3 * atp_mickeys_scale_factor) >>1); 2202199086Srpaulo if (atp_slide_min_movement == (prev_mickeys_scale_factor >> 3)) 2203199086Srpaulo atp_slide_min_movement = atp_mickeys_scale_factor >> 3; 2204199086Srpaulo 2205199086Srpaulo return (0); 2206199086Srpaulo} 2207199086Srpaulo 2208199086Srpaulostatic device_method_t atp_methods[] = { 2209199086Srpaulo /* Device interface */ 2210199086Srpaulo DEVMETHOD(device_probe, atp_probe), 2211199086Srpaulo DEVMETHOD(device_attach, atp_attach), 2212199086Srpaulo DEVMETHOD(device_detach, atp_detach), 2213199086Srpaulo { 0, 0 } 2214199086Srpaulo}; 2215199086Srpaulo 2216199086Srpaulostatic driver_t atp_driver = { 2217233774Shselasky .name = ATP_DRIVER_NAME, 2218233774Shselasky .methods = atp_methods, 2219233774Shselasky .size = sizeof(struct atp_softc) 2220199086Srpaulo}; 2221199086Srpaulo 2222199086Srpaulostatic devclass_t atp_devclass; 2223199086Srpaulo 2224199086SrpauloDRIVER_MODULE(atp, uhub, atp_driver, atp_devclass, NULL, 0); 2225199086SrpauloMODULE_DEPEND(atp, usb, 1, 1, 1); 2226212122SthompsaMODULE_VERSION(atp, 1); 2227