[3e7de30] | 1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
| 2 | |
---|
| 3 | /*- |
---|
| 4 | * Copyright (c) 2014 Rohit Grover |
---|
| 5 | * All rights reserved. |
---|
| 6 | * |
---|
| 7 | * Redistribution and use in source and binary forms, with or without |
---|
| 8 | * modification, are permitted provided that the following conditions |
---|
| 9 | * are met: |
---|
| 10 | * 1. Redistributions of source code must retain the above copyright |
---|
| 11 | * notice, this list of conditions and the following disclaimer. |
---|
| 12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 13 | * notice, this list of conditions and the following disclaimer in the |
---|
| 14 | * documentation and/or other materials provided with the distribution. |
---|
| 15 | * |
---|
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
---|
| 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
---|
| 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
| 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
| 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
| 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
| 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
| 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
| 26 | * SUCH DAMAGE. |
---|
| 27 | */ |
---|
| 28 | |
---|
| 29 | /* |
---|
| 30 | * Some tables, structures, definitions and constant values for the |
---|
| 31 | * touchpad protocol has been copied from Linux's |
---|
| 32 | * "drivers/input/mouse/bcm5974.c" which has the following copyright |
---|
| 33 | * holders under GPLv2. All device specific code in this driver has |
---|
| 34 | * been written from scratch. The decoding algorithm is based on |
---|
| 35 | * output from FreeBSD's usbdump. |
---|
| 36 | * |
---|
| 37 | * Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se) |
---|
| 38 | * Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com) |
---|
| 39 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) |
---|
| 40 | * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) |
---|
| 41 | * Copyright (C) 2005 Stelian Pop (stelian@popies.net) |
---|
| 42 | * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) |
---|
| 43 | * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) |
---|
| 44 | * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) |
---|
| 45 | * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) |
---|
| 46 | */ |
---|
| 47 | |
---|
| 48 | /* |
---|
| 49 | * Author's note: 'atp' supports two distinct families of Apple trackpad |
---|
| 50 | * products: the older Fountain/Geyser and the latest Wellspring trackpads. |
---|
| 51 | * The first version made its appearance with FreeBSD 8 and worked only with |
---|
| 52 | * the Fountain/Geyser hardware. A fork of this driver for Wellspring was |
---|
| 53 | * contributed by Huang Wen Hui. This driver unifies the Wellspring effort |
---|
| 54 | * and also improves upon the original work. |
---|
| 55 | * |
---|
| 56 | * I'm grateful to Stephan Scheunig, Angela Naegele, and Nokia IT-support |
---|
| 57 | * for helping me with access to hardware. Thanks also go to Nokia for |
---|
| 58 | * giving me an opportunity to do this work. |
---|
| 59 | */ |
---|
| 60 | |
---|
| 61 | #include <sys/cdefs.h> |
---|
| 62 | __FBSDID("$FreeBSD$"); |
---|
| 63 | |
---|
| 64 | #include <sys/stdint.h> |
---|
| 65 | #include <sys/stddef.h> |
---|
| 66 | #include <rtems/bsd/sys/param.h> |
---|
| 67 | #include <sys/types.h> |
---|
| 68 | #include <sys/systm.h> |
---|
| 69 | #include <sys/kernel.h> |
---|
| 70 | #include <sys/bus.h> |
---|
| 71 | #include <sys/module.h> |
---|
| 72 | #include <rtems/bsd/sys/lock.h> |
---|
| 73 | #include <sys/mutex.h> |
---|
| 74 | #include <sys/sysctl.h> |
---|
| 75 | #include <sys/malloc.h> |
---|
| 76 | #include <sys/conf.h> |
---|
| 77 | #include <sys/fcntl.h> |
---|
| 78 | #include <sys/file.h> |
---|
| 79 | #include <sys/selinfo.h> |
---|
| 80 | #include <sys/poll.h> |
---|
| 81 | |
---|
| 82 | #include <dev/usb/usb.h> |
---|
| 83 | #include <dev/usb/usbdi.h> |
---|
| 84 | #include <dev/usb/usbdi_util.h> |
---|
| 85 | #include <dev/usb/usbhid.h> |
---|
| 86 | |
---|
| 87 | #include <rtems/bsd/local/usbdevs.h> |
---|
| 88 | |
---|
| 89 | #define USB_DEBUG_VAR atp_debug |
---|
| 90 | #include <dev/usb/usb_debug.h> |
---|
| 91 | |
---|
| 92 | #include <sys/mouse.h> |
---|
| 93 | |
---|
| 94 | #define ATP_DRIVER_NAME "atp" |
---|
| 95 | |
---|
| 96 | /* |
---|
| 97 | * Driver specific options: the following options may be set by |
---|
| 98 | * `options' statements in the kernel configuration file. |
---|
| 99 | */ |
---|
| 100 | |
---|
| 101 | /* The divisor used to translate sensor reported positions to mickeys. */ |
---|
| 102 | #ifndef ATP_SCALE_FACTOR |
---|
| 103 | #define ATP_SCALE_FACTOR 16 |
---|
| 104 | #endif |
---|
| 105 | |
---|
| 106 | /* Threshold for small movement noise (in mickeys) */ |
---|
| 107 | #ifndef ATP_SMALL_MOVEMENT_THRESHOLD |
---|
| 108 | #define ATP_SMALL_MOVEMENT_THRESHOLD 30 |
---|
| 109 | #endif |
---|
| 110 | |
---|
| 111 | /* Threshold of instantaneous deltas beyond which movement is considered fast.*/ |
---|
| 112 | #ifndef ATP_FAST_MOVEMENT_TRESHOLD |
---|
| 113 | #define ATP_FAST_MOVEMENT_TRESHOLD 150 |
---|
| 114 | #endif |
---|
| 115 | |
---|
| 116 | /* |
---|
| 117 | * This is the age in microseconds beyond which a touch is considered |
---|
| 118 | * to be a slide; and therefore a tap event isn't registered. |
---|
| 119 | */ |
---|
| 120 | #ifndef ATP_TOUCH_TIMEOUT |
---|
| 121 | #define ATP_TOUCH_TIMEOUT 125000 |
---|
| 122 | #endif |
---|
| 123 | |
---|
| 124 | #ifndef ATP_IDLENESS_THRESHOLD |
---|
| 125 | #define ATP_IDLENESS_THRESHOLD 10 |
---|
| 126 | #endif |
---|
| 127 | |
---|
| 128 | #ifndef FG_SENSOR_NOISE_THRESHOLD |
---|
| 129 | #define FG_SENSOR_NOISE_THRESHOLD 2 |
---|
| 130 | #endif |
---|
| 131 | |
---|
| 132 | /* |
---|
| 133 | * A double-tap followed by a single-finger slide is treated as a |
---|
| 134 | * special gesture. The driver responds to this gesture by assuming a |
---|
| 135 | * virtual button-press for the lifetime of the slide. The following |
---|
| 136 | * threshold is the maximum time gap (in microseconds) between the two |
---|
| 137 | * tap events preceding the slide for such a gesture. |
---|
| 138 | */ |
---|
| 139 | #ifndef ATP_DOUBLE_TAP_N_DRAG_THRESHOLD |
---|
| 140 | #define ATP_DOUBLE_TAP_N_DRAG_THRESHOLD 200000 |
---|
| 141 | #endif |
---|
| 142 | |
---|
| 143 | /* |
---|
| 144 | * The wait duration in ticks after losing a touch contact before |
---|
| 145 | * zombied strokes are reaped and turned into button events. |
---|
| 146 | */ |
---|
| 147 | #define ATP_ZOMBIE_STROKE_REAP_INTERVAL (hz / 20) /* 50 ms */ |
---|
| 148 | |
---|
| 149 | /* The multiplier used to translate sensor reported positions to mickeys. */ |
---|
| 150 | #define FG_SCALE_FACTOR 380 |
---|
| 151 | |
---|
| 152 | /* |
---|
| 153 | * The movement threshold for a stroke; this is the maximum difference |
---|
| 154 | * in position which will be resolved as a continuation of a stroke |
---|
| 155 | * component. |
---|
| 156 | */ |
---|
| 157 | #define FG_MAX_DELTA_MICKEYS ((3 * (FG_SCALE_FACTOR)) >> 1) |
---|
| 158 | |
---|
| 159 | /* Distance-squared threshold for matching a finger with a known stroke */ |
---|
| 160 | #ifndef WSP_MAX_ALLOWED_MATCH_DISTANCE_SQ |
---|
| 161 | #define WSP_MAX_ALLOWED_MATCH_DISTANCE_SQ 1000000 |
---|
| 162 | #endif |
---|
| 163 | |
---|
| 164 | /* Ignore pressure spans with cumulative press. below this value. */ |
---|
| 165 | #define FG_PSPAN_MIN_CUM_PRESSURE 10 |
---|
| 166 | |
---|
| 167 | /* Maximum allowed width for pressure-spans.*/ |
---|
| 168 | #define FG_PSPAN_MAX_WIDTH 4 |
---|
| 169 | |
---|
| 170 | /* end of driver specific options */ |
---|
| 171 | |
---|
| 172 | /* Tunables */ |
---|
| 173 | static SYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB ATP"); |
---|
| 174 | |
---|
| 175 | #ifdef USB_DEBUG |
---|
| 176 | enum atp_log_level { |
---|
| 177 | ATP_LLEVEL_DISABLED = 0, |
---|
| 178 | ATP_LLEVEL_ERROR, |
---|
| 179 | ATP_LLEVEL_DEBUG, /* for troubleshooting */ |
---|
| 180 | ATP_LLEVEL_INFO, /* for diagnostics */ |
---|
| 181 | }; |
---|
| 182 | static int atp_debug = ATP_LLEVEL_ERROR; /* the default is to only log errors */ |
---|
| 183 | SYSCTL_INT(_hw_usb_atp, OID_AUTO, debug, CTLFLAG_RWTUN, |
---|
| 184 | &atp_debug, ATP_LLEVEL_ERROR, "ATP debug level"); |
---|
| 185 | #endif /* USB_DEBUG */ |
---|
| 186 | |
---|
| 187 | static u_int atp_touch_timeout = ATP_TOUCH_TIMEOUT; |
---|
| 188 | SYSCTL_UINT(_hw_usb_atp, OID_AUTO, touch_timeout, CTLFLAG_RWTUN, |
---|
| 189 | &atp_touch_timeout, 125000, "age threshold in microseconds for a touch"); |
---|
| 190 | |
---|
| 191 | static u_int atp_double_tap_threshold = ATP_DOUBLE_TAP_N_DRAG_THRESHOLD; |
---|
| 192 | SYSCTL_UINT(_hw_usb_atp, OID_AUTO, double_tap_threshold, CTLFLAG_RWTUN, |
---|
| 193 | &atp_double_tap_threshold, ATP_DOUBLE_TAP_N_DRAG_THRESHOLD, |
---|
| 194 | "maximum time in microseconds to allow association between a double-tap and " |
---|
| 195 | "drag gesture"); |
---|
| 196 | |
---|
| 197 | static u_int atp_mickeys_scale_factor = ATP_SCALE_FACTOR; |
---|
| 198 | static int atp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS); |
---|
| 199 | SYSCTL_PROC(_hw_usb_atp, OID_AUTO, scale_factor, CTLTYPE_UINT | CTLFLAG_RWTUN, |
---|
| 200 | &atp_mickeys_scale_factor, sizeof(atp_mickeys_scale_factor), |
---|
| 201 | atp_sysctl_scale_factor_handler, "IU", "movement scale factor"); |
---|
| 202 | |
---|
| 203 | static u_int atp_small_movement_threshold = ATP_SMALL_MOVEMENT_THRESHOLD; |
---|
| 204 | SYSCTL_UINT(_hw_usb_atp, OID_AUTO, small_movement, CTLFLAG_RWTUN, |
---|
| 205 | &atp_small_movement_threshold, ATP_SMALL_MOVEMENT_THRESHOLD, |
---|
| 206 | "the small movement black-hole for filtering noise"); |
---|
| 207 | |
---|
| 208 | static u_int atp_tap_minimum = 1; |
---|
| 209 | SYSCTL_UINT(_hw_usb_atp, OID_AUTO, tap_minimum, CTLFLAG_RWTUN, |
---|
| 210 | &atp_tap_minimum, 1, "Minimum number of taps before detection"); |
---|
| 211 | |
---|
| 212 | /* |
---|
| 213 | * Strokes which accumulate at least this amount of absolute movement |
---|
| 214 | * from the aggregate of their components are considered as |
---|
| 215 | * slides. Unit: mickeys. |
---|
| 216 | */ |
---|
| 217 | static u_int atp_slide_min_movement = 2 * ATP_SMALL_MOVEMENT_THRESHOLD; |
---|
| 218 | SYSCTL_UINT(_hw_usb_atp, OID_AUTO, slide_min_movement, CTLFLAG_RWTUN, |
---|
| 219 | &atp_slide_min_movement, 2 * ATP_SMALL_MOVEMENT_THRESHOLD, |
---|
| 220 | "strokes with at least this amt. of movement are considered slides"); |
---|
| 221 | |
---|
| 222 | /* |
---|
| 223 | * The minimum age of a stroke for it to be considered mature; this |
---|
| 224 | * helps filter movements (noise) from immature strokes. Units: interrupts. |
---|
| 225 | */ |
---|
| 226 | static u_int atp_stroke_maturity_threshold = 4; |
---|
| 227 | SYSCTL_UINT(_hw_usb_atp, OID_AUTO, stroke_maturity_threshold, CTLFLAG_RWTUN, |
---|
| 228 | &atp_stroke_maturity_threshold, 4, |
---|
| 229 | "the minimum age of a stroke for it to be considered mature"); |
---|
| 230 | |
---|
| 231 | typedef enum atp_trackpad_family { |
---|
| 232 | TRACKPAD_FAMILY_FOUNTAIN_GEYSER, |
---|
| 233 | TRACKPAD_FAMILY_WELLSPRING, |
---|
| 234 | TRACKPAD_FAMILY_MAX /* keep this at the tail end of the enumeration */ |
---|
| 235 | } trackpad_family_t; |
---|
| 236 | |
---|
| 237 | enum fountain_geyser_product { |
---|
| 238 | FOUNTAIN, |
---|
| 239 | GEYSER1, |
---|
| 240 | GEYSER1_17inch, |
---|
| 241 | GEYSER2, |
---|
| 242 | GEYSER3, |
---|
| 243 | GEYSER4, |
---|
| 244 | FOUNTAIN_GEYSER_PRODUCT_MAX /* keep this at the end */ |
---|
| 245 | }; |
---|
| 246 | |
---|
| 247 | enum wellspring_product { |
---|
| 248 | WELLSPRING1, |
---|
| 249 | WELLSPRING2, |
---|
| 250 | WELLSPRING3, |
---|
| 251 | WELLSPRING4, |
---|
| 252 | WELLSPRING4A, |
---|
| 253 | WELLSPRING5, |
---|
| 254 | WELLSPRING6A, |
---|
| 255 | WELLSPRING6, |
---|
| 256 | WELLSPRING5A, |
---|
| 257 | WELLSPRING7, |
---|
| 258 | WELLSPRING7A, |
---|
| 259 | WELLSPRING8, |
---|
| 260 | WELLSPRING_PRODUCT_MAX /* keep this at the end of the enumeration */ |
---|
| 261 | }; |
---|
| 262 | |
---|
| 263 | /* trackpad header types */ |
---|
| 264 | enum fountain_geyser_trackpad_type { |
---|
| 265 | FG_TRACKPAD_TYPE_GEYSER1, |
---|
| 266 | FG_TRACKPAD_TYPE_GEYSER2, |
---|
| 267 | FG_TRACKPAD_TYPE_GEYSER3, |
---|
| 268 | FG_TRACKPAD_TYPE_GEYSER4, |
---|
| 269 | }; |
---|
| 270 | enum wellspring_trackpad_type { |
---|
| 271 | WSP_TRACKPAD_TYPE1, /* plain trackpad */ |
---|
| 272 | WSP_TRACKPAD_TYPE2, /* button integrated in trackpad */ |
---|
| 273 | WSP_TRACKPAD_TYPE3 /* additional header fields since June 2013 */ |
---|
| 274 | }; |
---|
| 275 | |
---|
| 276 | /* |
---|
| 277 | * Trackpad family and product and family are encoded together in the |
---|
| 278 | * driver_info value associated with a trackpad product. |
---|
| 279 | */ |
---|
| 280 | #define N_PROD_BITS 8 /* Number of bits used to encode product */ |
---|
| 281 | #define ENCODE_DRIVER_INFO(FAMILY, PROD) \ |
---|
| 282 | (((FAMILY) << N_PROD_BITS) | (PROD)) |
---|
| 283 | #define DECODE_FAMILY_FROM_DRIVER_INFO(INFO) ((INFO) >> N_PROD_BITS) |
---|
| 284 | #define DECODE_PRODUCT_FROM_DRIVER_INFO(INFO) \ |
---|
| 285 | ((INFO) & ((1 << N_PROD_BITS) - 1)) |
---|
| 286 | |
---|
| 287 | #define FG_DRIVER_INFO(PRODUCT) \ |
---|
| 288 | ENCODE_DRIVER_INFO(TRACKPAD_FAMILY_FOUNTAIN_GEYSER, PRODUCT) |
---|
| 289 | #define WELLSPRING_DRIVER_INFO(PRODUCT) \ |
---|
| 290 | ENCODE_DRIVER_INFO(TRACKPAD_FAMILY_WELLSPRING, PRODUCT) |
---|
| 291 | |
---|
| 292 | /* |
---|
| 293 | * The following structure captures the state of a pressure span along |
---|
| 294 | * an axis. Each contact with the touchpad results in separate |
---|
| 295 | * pressure spans along the two axes. |
---|
| 296 | */ |
---|
| 297 | typedef struct fg_pspan { |
---|
| 298 | u_int width; /* in units of sensors */ |
---|
| 299 | u_int cum; /* cumulative compression (from all sensors) */ |
---|
| 300 | u_int cog; /* center of gravity */ |
---|
| 301 | u_int loc; /* location (scaled using the mickeys factor) */ |
---|
| 302 | boolean_t matched; /* to track pspans as they match against strokes. */ |
---|
| 303 | } fg_pspan; |
---|
| 304 | |
---|
| 305 | #define FG_MAX_PSPANS_PER_AXIS 3 |
---|
| 306 | #define FG_MAX_STROKES (2 * FG_MAX_PSPANS_PER_AXIS) |
---|
| 307 | |
---|
| 308 | #define WELLSPRING_INTERFACE_INDEX 1 |
---|
| 309 | |
---|
| 310 | /* trackpad finger data offsets, le16-aligned */ |
---|
| 311 | #define WSP_TYPE1_FINGER_DATA_OFFSET (13 * 2) |
---|
| 312 | #define WSP_TYPE2_FINGER_DATA_OFFSET (15 * 2) |
---|
| 313 | #define WSP_TYPE3_FINGER_DATA_OFFSET (19 * 2) |
---|
| 314 | |
---|
| 315 | /* trackpad button data offsets */ |
---|
| 316 | #define WSP_TYPE2_BUTTON_DATA_OFFSET 15 |
---|
| 317 | #define WSP_TYPE3_BUTTON_DATA_OFFSET 23 |
---|
| 318 | |
---|
| 319 | /* list of device capability bits */ |
---|
| 320 | #define HAS_INTEGRATED_BUTTON 1 |
---|
| 321 | |
---|
| 322 | /* trackpad finger structure - little endian */ |
---|
| 323 | struct wsp_finger_sensor_data { |
---|
| 324 | int16_t origin; /* zero when switching track finger */ |
---|
| 325 | int16_t abs_x; /* absolute x coordinate */ |
---|
| 326 | int16_t abs_y; /* absolute y coordinate */ |
---|
| 327 | int16_t rel_x; /* relative x coordinate */ |
---|
| 328 | int16_t rel_y; /* relative y coordinate */ |
---|
| 329 | int16_t tool_major; /* tool area, major axis */ |
---|
| 330 | int16_t tool_minor; /* tool area, minor axis */ |
---|
| 331 | int16_t orientation; /* 16384 when point, else 15 bit angle */ |
---|
| 332 | int16_t touch_major; /* touch area, major axis */ |
---|
| 333 | int16_t touch_minor; /* touch area, minor axis */ |
---|
| 334 | int16_t unused[3]; /* zeros */ |
---|
| 335 | int16_t multi; /* one finger: varies, more fingers: constant */ |
---|
| 336 | } __packed; |
---|
| 337 | |
---|
| 338 | typedef struct wsp_finger { |
---|
| 339 | /* to track fingers as they match against strokes. */ |
---|
| 340 | boolean_t matched; |
---|
| 341 | |
---|
| 342 | /* location (scaled using the mickeys factor) */ |
---|
| 343 | int x; |
---|
| 344 | int y; |
---|
| 345 | } wsp_finger_t; |
---|
| 346 | |
---|
| 347 | #define WSP_MAX_FINGERS 16 |
---|
| 348 | #define WSP_SIZEOF_FINGER_SENSOR_DATA sizeof(struct wsp_finger_sensor_data) |
---|
| 349 | #define WSP_SIZEOF_ALL_FINGER_DATA (WSP_MAX_FINGERS * \ |
---|
| 350 | WSP_SIZEOF_FINGER_SENSOR_DATA) |
---|
| 351 | #define WSP_MAX_FINGER_ORIENTATION 16384 |
---|
| 352 | |
---|
| 353 | #define ATP_SENSOR_DATA_BUF_MAX 1024 |
---|
| 354 | #if (ATP_SENSOR_DATA_BUF_MAX < ((WSP_MAX_FINGERS * 14 * 2) + \ |
---|
| 355 | WSP_TYPE3_FINGER_DATA_OFFSET)) |
---|
| 356 | /* note: 14 * 2 in the above is based on sizeof(struct wsp_finger_sensor_data)*/ |
---|
| 357 | #error "ATP_SENSOR_DATA_BUF_MAX is too small" |
---|
| 358 | #endif |
---|
| 359 | |
---|
| 360 | #define ATP_MAX_STROKES MAX(WSP_MAX_FINGERS, FG_MAX_STROKES) |
---|
| 361 | |
---|
| 362 | #define FG_MAX_XSENSORS 26 |
---|
| 363 | #define FG_MAX_YSENSORS 16 |
---|
| 364 | |
---|
| 365 | /* device-specific configuration */ |
---|
| 366 | struct fg_dev_params { |
---|
| 367 | u_int data_len; /* for sensor data */ |
---|
| 368 | u_int n_xsensors; |
---|
| 369 | u_int n_ysensors; |
---|
| 370 | enum fountain_geyser_trackpad_type prot; |
---|
| 371 | }; |
---|
| 372 | struct wsp_dev_params { |
---|
| 373 | uint8_t caps; /* device capability bitmask */ |
---|
| 374 | uint8_t tp_type; /* type of trackpad interface */ |
---|
| 375 | uint8_t finger_data_offset; /* offset to trackpad finger data */ |
---|
| 376 | }; |
---|
| 377 | |
---|
| 378 | static const struct fg_dev_params fg_dev_params[FOUNTAIN_GEYSER_PRODUCT_MAX] = { |
---|
| 379 | [FOUNTAIN] = { |
---|
| 380 | .data_len = 81, |
---|
| 381 | .n_xsensors = 16, |
---|
| 382 | .n_ysensors = 16, |
---|
| 383 | .prot = FG_TRACKPAD_TYPE_GEYSER1 |
---|
| 384 | }, |
---|
| 385 | [GEYSER1] = { |
---|
| 386 | .data_len = 81, |
---|
| 387 | .n_xsensors = 16, |
---|
| 388 | .n_ysensors = 16, |
---|
| 389 | .prot = FG_TRACKPAD_TYPE_GEYSER1 |
---|
| 390 | }, |
---|
| 391 | [GEYSER1_17inch] = { |
---|
| 392 | .data_len = 81, |
---|
| 393 | .n_xsensors = 26, |
---|
| 394 | .n_ysensors = 16, |
---|
| 395 | .prot = FG_TRACKPAD_TYPE_GEYSER1 |
---|
| 396 | }, |
---|
| 397 | [GEYSER2] = { |
---|
| 398 | .data_len = 64, |
---|
| 399 | .n_xsensors = 15, |
---|
| 400 | .n_ysensors = 9, |
---|
| 401 | .prot = FG_TRACKPAD_TYPE_GEYSER2 |
---|
| 402 | }, |
---|
| 403 | [GEYSER3] = { |
---|
| 404 | .data_len = 64, |
---|
| 405 | .n_xsensors = 20, |
---|
| 406 | .n_ysensors = 10, |
---|
| 407 | .prot = FG_TRACKPAD_TYPE_GEYSER3 |
---|
| 408 | }, |
---|
| 409 | [GEYSER4] = { |
---|
| 410 | .data_len = 64, |
---|
| 411 | .n_xsensors = 20, |
---|
| 412 | .n_ysensors = 10, |
---|
| 413 | .prot = FG_TRACKPAD_TYPE_GEYSER4 |
---|
| 414 | } |
---|
| 415 | }; |
---|
| 416 | |
---|
| 417 | static const STRUCT_USB_HOST_ID fg_devs[] = { |
---|
| 418 | /* PowerBooks Feb 2005, iBooks G4 */ |
---|
| 419 | { USB_VPI(USB_VENDOR_APPLE, 0x020e, FG_DRIVER_INFO(FOUNTAIN)) }, |
---|
| 420 | { USB_VPI(USB_VENDOR_APPLE, 0x020f, FG_DRIVER_INFO(FOUNTAIN)) }, |
---|
| 421 | { USB_VPI(USB_VENDOR_APPLE, 0x0210, FG_DRIVER_INFO(FOUNTAIN)) }, |
---|
| 422 | { USB_VPI(USB_VENDOR_APPLE, 0x030a, FG_DRIVER_INFO(FOUNTAIN)) }, |
---|
| 423 | { USB_VPI(USB_VENDOR_APPLE, 0x030b, FG_DRIVER_INFO(GEYSER1)) }, |
---|
| 424 | |
---|
| 425 | /* PowerBooks Oct 2005 */ |
---|
| 426 | { USB_VPI(USB_VENDOR_APPLE, 0x0214, FG_DRIVER_INFO(GEYSER2)) }, |
---|
| 427 | { USB_VPI(USB_VENDOR_APPLE, 0x0215, FG_DRIVER_INFO(GEYSER2)) }, |
---|
| 428 | { USB_VPI(USB_VENDOR_APPLE, 0x0216, FG_DRIVER_INFO(GEYSER2)) }, |
---|
| 429 | |
---|
| 430 | /* Core Duo MacBook & MacBook Pro */ |
---|
| 431 | { USB_VPI(USB_VENDOR_APPLE, 0x0217, FG_DRIVER_INFO(GEYSER3)) }, |
---|
| 432 | { USB_VPI(USB_VENDOR_APPLE, 0x0218, FG_DRIVER_INFO(GEYSER3)) }, |
---|
| 433 | { USB_VPI(USB_VENDOR_APPLE, 0x0219, FG_DRIVER_INFO(GEYSER3)) }, |
---|
| 434 | |
---|
| 435 | /* Core2 Duo MacBook & MacBook Pro */ |
---|
| 436 | { USB_VPI(USB_VENDOR_APPLE, 0x021a, FG_DRIVER_INFO(GEYSER4)) }, |
---|
| 437 | { USB_VPI(USB_VENDOR_APPLE, 0x021b, FG_DRIVER_INFO(GEYSER4)) }, |
---|
| 438 | { USB_VPI(USB_VENDOR_APPLE, 0x021c, FG_DRIVER_INFO(GEYSER4)) }, |
---|
| 439 | |
---|
| 440 | /* Core2 Duo MacBook3,1 */ |
---|
| 441 | { USB_VPI(USB_VENDOR_APPLE, 0x0229, FG_DRIVER_INFO(GEYSER4)) }, |
---|
| 442 | { USB_VPI(USB_VENDOR_APPLE, 0x022a, FG_DRIVER_INFO(GEYSER4)) }, |
---|
| 443 | { USB_VPI(USB_VENDOR_APPLE, 0x022b, FG_DRIVER_INFO(GEYSER4)) }, |
---|
| 444 | |
---|
| 445 | /* 17 inch PowerBook */ |
---|
| 446 | { USB_VPI(USB_VENDOR_APPLE, 0x020d, FG_DRIVER_INFO(GEYSER1_17inch)) }, |
---|
| 447 | }; |
---|
| 448 | |
---|
| 449 | static const struct wsp_dev_params wsp_dev_params[WELLSPRING_PRODUCT_MAX] = { |
---|
| 450 | [WELLSPRING1] = { |
---|
| 451 | .caps = 0, |
---|
| 452 | .tp_type = WSP_TRACKPAD_TYPE1, |
---|
| 453 | .finger_data_offset = WSP_TYPE1_FINGER_DATA_OFFSET, |
---|
| 454 | }, |
---|
| 455 | [WELLSPRING2] = { |
---|
| 456 | .caps = 0, |
---|
| 457 | .tp_type = WSP_TRACKPAD_TYPE1, |
---|
| 458 | .finger_data_offset = WSP_TYPE1_FINGER_DATA_OFFSET, |
---|
| 459 | }, |
---|
| 460 | [WELLSPRING3] = { |
---|
| 461 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 462 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 463 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 464 | }, |
---|
| 465 | [WELLSPRING4] = { |
---|
| 466 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 467 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 468 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 469 | }, |
---|
| 470 | [WELLSPRING4A] = { |
---|
| 471 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 472 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 473 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 474 | }, |
---|
| 475 | [WELLSPRING5] = { |
---|
| 476 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 477 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 478 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 479 | }, |
---|
| 480 | [WELLSPRING6] = { |
---|
| 481 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 482 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 483 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 484 | }, |
---|
| 485 | [WELLSPRING5A] = { |
---|
| 486 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 487 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 488 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 489 | }, |
---|
| 490 | [WELLSPRING6A] = { |
---|
| 491 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 492 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 493 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 494 | }, |
---|
| 495 | [WELLSPRING7] = { |
---|
| 496 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 497 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 498 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 499 | }, |
---|
| 500 | [WELLSPRING7A] = { |
---|
| 501 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 502 | .tp_type = WSP_TRACKPAD_TYPE2, |
---|
| 503 | .finger_data_offset = WSP_TYPE2_FINGER_DATA_OFFSET, |
---|
| 504 | }, |
---|
| 505 | [WELLSPRING8] = { |
---|
| 506 | .caps = HAS_INTEGRATED_BUTTON, |
---|
| 507 | .tp_type = WSP_TRACKPAD_TYPE3, |
---|
| 508 | .finger_data_offset = WSP_TYPE3_FINGER_DATA_OFFSET, |
---|
| 509 | }, |
---|
| 510 | }; |
---|
| 511 | |
---|
| 512 | #define ATP_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } |
---|
| 513 | |
---|
| 514 | /* TODO: STRUCT_USB_HOST_ID */ |
---|
| 515 | static const struct usb_device_id wsp_devs[] = { |
---|
| 516 | /* MacbookAir1.1 */ |
---|
| 517 | ATP_DEV(APPLE, WELLSPRING_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING1)), |
---|
| 518 | ATP_DEV(APPLE, WELLSPRING_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING1)), |
---|
| 519 | ATP_DEV(APPLE, WELLSPRING_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING1)), |
---|
| 520 | |
---|
| 521 | /* MacbookProPenryn, aka wellspring2 */ |
---|
| 522 | ATP_DEV(APPLE, WELLSPRING2_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING2)), |
---|
| 523 | ATP_DEV(APPLE, WELLSPRING2_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING2)), |
---|
| 524 | ATP_DEV(APPLE, WELLSPRING2_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING2)), |
---|
| 525 | |
---|
| 526 | /* Macbook5,1 (unibody), aka wellspring3 */ |
---|
| 527 | ATP_DEV(APPLE, WELLSPRING3_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING3)), |
---|
| 528 | ATP_DEV(APPLE, WELLSPRING3_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING3)), |
---|
| 529 | ATP_DEV(APPLE, WELLSPRING3_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING3)), |
---|
| 530 | |
---|
| 531 | /* MacbookAir3,2 (unibody), aka wellspring4 */ |
---|
| 532 | ATP_DEV(APPLE, WELLSPRING4_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING4)), |
---|
| 533 | ATP_DEV(APPLE, WELLSPRING4_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING4)), |
---|
| 534 | ATP_DEV(APPLE, WELLSPRING4_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING4)), |
---|
| 535 | |
---|
| 536 | /* MacbookAir3,1 (unibody), aka wellspring4 */ |
---|
| 537 | ATP_DEV(APPLE, WELLSPRING4A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING4A)), |
---|
| 538 | ATP_DEV(APPLE, WELLSPRING4A_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING4A)), |
---|
| 539 | ATP_DEV(APPLE, WELLSPRING4A_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING4A)), |
---|
| 540 | |
---|
| 541 | /* Macbook8 (unibody, March 2011) */ |
---|
| 542 | ATP_DEV(APPLE, WELLSPRING5_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING5)), |
---|
| 543 | ATP_DEV(APPLE, WELLSPRING5_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING5)), |
---|
| 544 | ATP_DEV(APPLE, WELLSPRING5_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING5)), |
---|
| 545 | |
---|
| 546 | /* MacbookAir4,1 (unibody, July 2011) */ |
---|
| 547 | ATP_DEV(APPLE, WELLSPRING6A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING6A)), |
---|
| 548 | ATP_DEV(APPLE, WELLSPRING6A_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING6A)), |
---|
| 549 | ATP_DEV(APPLE, WELLSPRING6A_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING6A)), |
---|
| 550 | |
---|
| 551 | /* MacbookAir4,2 (unibody, July 2011) */ |
---|
| 552 | ATP_DEV(APPLE, WELLSPRING6_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING6)), |
---|
| 553 | ATP_DEV(APPLE, WELLSPRING6_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING6)), |
---|
| 554 | ATP_DEV(APPLE, WELLSPRING6_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING6)), |
---|
| 555 | |
---|
| 556 | /* Macbook8,2 (unibody) */ |
---|
| 557 | ATP_DEV(APPLE, WELLSPRING5A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING5A)), |
---|
| 558 | ATP_DEV(APPLE, WELLSPRING5A_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING5A)), |
---|
| 559 | ATP_DEV(APPLE, WELLSPRING5A_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING5A)), |
---|
| 560 | |
---|
| 561 | /* MacbookPro10,1 (unibody, June 2012) */ |
---|
| 562 | /* MacbookPro11,? (unibody, June 2013) */ |
---|
| 563 | ATP_DEV(APPLE, WELLSPRING7_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING7)), |
---|
| 564 | ATP_DEV(APPLE, WELLSPRING7_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING7)), |
---|
| 565 | ATP_DEV(APPLE, WELLSPRING7_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING7)), |
---|
| 566 | |
---|
| 567 | /* MacbookPro10,2 (unibody, October 2012) */ |
---|
| 568 | ATP_DEV(APPLE, WELLSPRING7A_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING7A)), |
---|
| 569 | ATP_DEV(APPLE, WELLSPRING7A_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING7A)), |
---|
| 570 | ATP_DEV(APPLE, WELLSPRING7A_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING7A)), |
---|
| 571 | |
---|
| 572 | /* MacbookAir6,2 (unibody, June 2013) */ |
---|
| 573 | ATP_DEV(APPLE, WELLSPRING8_ANSI, WELLSPRING_DRIVER_INFO(WELLSPRING8)), |
---|
| 574 | ATP_DEV(APPLE, WELLSPRING8_ISO, WELLSPRING_DRIVER_INFO(WELLSPRING8)), |
---|
| 575 | ATP_DEV(APPLE, WELLSPRING8_JIS, WELLSPRING_DRIVER_INFO(WELLSPRING8)), |
---|
| 576 | }; |
---|
| 577 | |
---|
| 578 | typedef enum atp_stroke_type { |
---|
| 579 | ATP_STROKE_TOUCH, |
---|
| 580 | ATP_STROKE_SLIDE, |
---|
| 581 | } atp_stroke_type; |
---|
| 582 | |
---|
| 583 | typedef enum atp_axis { |
---|
| 584 | X = 0, |
---|
| 585 | Y = 1, |
---|
| 586 | NUM_AXES |
---|
| 587 | } atp_axis; |
---|
| 588 | |
---|
| 589 | #define ATP_FIFO_BUF_SIZE 8 /* bytes */ |
---|
| 590 | #define ATP_FIFO_QUEUE_MAXLEN 50 /* units */ |
---|
| 591 | |
---|
| 592 | enum { |
---|
| 593 | ATP_INTR_DT, |
---|
| 594 | ATP_RESET, |
---|
| 595 | ATP_N_TRANSFER, |
---|
| 596 | }; |
---|
| 597 | |
---|
| 598 | typedef struct fg_stroke_component { |
---|
| 599 | /* Fields encapsulating the pressure-span. */ |
---|
| 600 | u_int loc; /* location (scaled) */ |
---|
| 601 | u_int cum_pressure; /* cumulative compression */ |
---|
| 602 | u_int max_cum_pressure; /* max cumulative compression */ |
---|
| 603 | boolean_t matched; /*to track components as they match against pspans.*/ |
---|
| 604 | |
---|
| 605 | int delta_mickeys; /* change in location (un-smoothened movement)*/ |
---|
| 606 | } fg_stroke_component_t; |
---|
| 607 | |
---|
| 608 | /* |
---|
| 609 | * The following structure captures a finger contact with the |
---|
| 610 | * touchpad. A stroke comprises two p-span components and some state. |
---|
| 611 | */ |
---|
| 612 | typedef struct atp_stroke { |
---|
| 613 | TAILQ_ENTRY(atp_stroke) entry; |
---|
| 614 | |
---|
| 615 | atp_stroke_type type; |
---|
| 616 | uint32_t flags; /* the state of this stroke */ |
---|
| 617 | #define ATSF_ZOMBIE 0x1 |
---|
| 618 | boolean_t matched; /* to track match against fingers.*/ |
---|
| 619 | |
---|
| 620 | struct timeval ctime; /* create time; for coincident siblings. */ |
---|
| 621 | |
---|
| 622 | /* |
---|
| 623 | * Unit: interrupts; we maintain this value in |
---|
| 624 | * addition to 'ctime' in order to avoid the |
---|
| 625 | * expensive call to microtime() at every |
---|
| 626 | * interrupt. |
---|
| 627 | */ |
---|
| 628 | uint32_t age; |
---|
| 629 | |
---|
| 630 | /* Location */ |
---|
| 631 | int x; |
---|
| 632 | int y; |
---|
| 633 | |
---|
| 634 | /* Fields containing information about movement. */ |
---|
| 635 | int instantaneous_dx; /* curr. change in X location (un-smoothened) */ |
---|
| 636 | int instantaneous_dy; /* curr. change in Y location (un-smoothened) */ |
---|
| 637 | int pending_dx; /* cum. of pending short movements */ |
---|
| 638 | int pending_dy; /* cum. of pending short movements */ |
---|
| 639 | int movement_dx; /* interpreted smoothened movement */ |
---|
| 640 | int movement_dy; /* interpreted smoothened movement */ |
---|
| 641 | int cum_movement_x; /* cum. horizontal movement */ |
---|
| 642 | int cum_movement_y; /* cum. vertical movement */ |
---|
| 643 | |
---|
| 644 | /* |
---|
| 645 | * The following member is relevant only for fountain-geyser trackpads. |
---|
| 646 | * For these, there is the need to track pressure-spans and cumulative |
---|
| 647 | * pressures for stroke components. |
---|
| 648 | */ |
---|
| 649 | fg_stroke_component_t components[NUM_AXES]; |
---|
| 650 | } atp_stroke_t; |
---|
| 651 | |
---|
| 652 | struct atp_softc; /* forward declaration */ |
---|
| 653 | typedef void (*sensor_data_interpreter_t)(struct atp_softc *sc, u_int len); |
---|
| 654 | |
---|
| 655 | struct atp_softc { |
---|
| 656 | device_t sc_dev; |
---|
| 657 | struct usb_device *sc_usb_device; |
---|
| 658 | struct mtx sc_mutex; /* for synchronization */ |
---|
| 659 | struct usb_fifo_sc sc_fifo; |
---|
| 660 | |
---|
| 661 | #define MODE_LENGTH 8 |
---|
| 662 | char sc_mode_bytes[MODE_LENGTH]; /* device mode */ |
---|
| 663 | |
---|
| 664 | trackpad_family_t sc_family; |
---|
| 665 | const void *sc_params; /* device configuration */ |
---|
| 666 | sensor_data_interpreter_t sensor_data_interpreter; |
---|
| 667 | |
---|
| 668 | mousehw_t sc_hw; |
---|
| 669 | mousemode_t sc_mode; |
---|
| 670 | mousestatus_t sc_status; |
---|
| 671 | |
---|
| 672 | u_int sc_state; |
---|
| 673 | #define ATP_ENABLED 0x01 |
---|
| 674 | #define ATP_ZOMBIES_EXIST 0x02 |
---|
| 675 | #define ATP_DOUBLE_TAP_DRAG 0x04 |
---|
| 676 | #define ATP_VALID 0x08 |
---|
| 677 | |
---|
| 678 | struct usb_xfer *sc_xfer[ATP_N_TRANSFER]; |
---|
| 679 | |
---|
| 680 | u_int sc_pollrate; |
---|
| 681 | int sc_fflags; |
---|
| 682 | |
---|
| 683 | atp_stroke_t sc_strokes_data[ATP_MAX_STROKES]; |
---|
| 684 | TAILQ_HEAD(,atp_stroke) sc_stroke_free; |
---|
| 685 | TAILQ_HEAD(,atp_stroke) sc_stroke_used; |
---|
| 686 | u_int sc_n_strokes; |
---|
| 687 | |
---|
| 688 | struct callout sc_callout; |
---|
| 689 | |
---|
| 690 | /* |
---|
| 691 | * button status. Set to non-zero if the mouse-button is physically |
---|
| 692 | * pressed. This state variable is exposed through softc to allow |
---|
| 693 | * reap_sibling_zombies to avoid registering taps while the trackpad |
---|
| 694 | * button is pressed. |
---|
| 695 | */ |
---|
| 696 | uint8_t sc_ibtn; |
---|
| 697 | |
---|
| 698 | /* |
---|
| 699 | * Time when touch zombies were last reaped; useful for detecting |
---|
| 700 | * double-touch-n-drag. |
---|
| 701 | */ |
---|
| 702 | struct timeval sc_touch_reap_time; |
---|
| 703 | |
---|
| 704 | u_int sc_idlecount; |
---|
| 705 | |
---|
| 706 | /* Regarding the data transferred from t-pad in USB INTR packets. */ |
---|
| 707 | u_int sc_expected_sensor_data_len; |
---|
| 708 | uint8_t sc_sensor_data[ATP_SENSOR_DATA_BUF_MAX] __aligned(4); |
---|
| 709 | |
---|
| 710 | int sc_cur_x[FG_MAX_XSENSORS]; /* current sensor readings */ |
---|
| 711 | int sc_cur_y[FG_MAX_YSENSORS]; |
---|
| 712 | int sc_base_x[FG_MAX_XSENSORS]; /* base sensor readings */ |
---|
| 713 | int sc_base_y[FG_MAX_YSENSORS]; |
---|
| 714 | int sc_pressure_x[FG_MAX_XSENSORS]; /* computed pressures */ |
---|
| 715 | int sc_pressure_y[FG_MAX_YSENSORS]; |
---|
| 716 | fg_pspan sc_pspans_x[FG_MAX_PSPANS_PER_AXIS]; |
---|
| 717 | fg_pspan sc_pspans_y[FG_MAX_PSPANS_PER_AXIS]; |
---|
| 718 | }; |
---|
| 719 | |
---|
| 720 | /* |
---|
| 721 | * The last byte of the fountain-geyser sensor data contains status bits; the |
---|
| 722 | * following values define the meanings of these bits. |
---|
| 723 | * (only Geyser 3/4) |
---|
| 724 | */ |
---|
| 725 | enum geyser34_status_bits { |
---|
| 726 | FG_STATUS_BUTTON = (uint8_t)0x01, /* The button was pressed */ |
---|
| 727 | FG_STATUS_BASE_UPDATE = (uint8_t)0x04, /* Data from an untouched pad.*/ |
---|
| 728 | }; |
---|
| 729 | |
---|
| 730 | typedef enum interface_mode { |
---|
| 731 | RAW_SENSOR_MODE = (uint8_t)0x01, |
---|
| 732 | HID_MODE = (uint8_t)0x08 |
---|
| 733 | } interface_mode; |
---|
| 734 | |
---|
| 735 | |
---|
| 736 | /* |
---|
| 737 | * function prototypes |
---|
| 738 | */ |
---|
| 739 | static usb_fifo_cmd_t atp_start_read; |
---|
| 740 | static usb_fifo_cmd_t atp_stop_read; |
---|
| 741 | static usb_fifo_open_t atp_open; |
---|
| 742 | static usb_fifo_close_t atp_close; |
---|
| 743 | static usb_fifo_ioctl_t atp_ioctl; |
---|
| 744 | |
---|
| 745 | static struct usb_fifo_methods atp_fifo_methods = { |
---|
| 746 | .f_open = &atp_open, |
---|
| 747 | .f_close = &atp_close, |
---|
| 748 | .f_ioctl = &atp_ioctl, |
---|
| 749 | .f_start_read = &atp_start_read, |
---|
| 750 | .f_stop_read = &atp_stop_read, |
---|
| 751 | .basename[0] = ATP_DRIVER_NAME, |
---|
| 752 | }; |
---|
| 753 | |
---|
| 754 | /* device initialization and shutdown */ |
---|
| 755 | static usb_error_t atp_set_device_mode(struct atp_softc *, interface_mode); |
---|
| 756 | static void atp_reset_callback(struct usb_xfer *, usb_error_t); |
---|
| 757 | static int atp_enable(struct atp_softc *); |
---|
| 758 | static void atp_disable(struct atp_softc *); |
---|
| 759 | |
---|
| 760 | /* sensor interpretation */ |
---|
| 761 | static void fg_interpret_sensor_data(struct atp_softc *, u_int); |
---|
| 762 | static void fg_extract_sensor_data(const int8_t *, u_int, atp_axis, |
---|
| 763 | int *, enum fountain_geyser_trackpad_type); |
---|
| 764 | static void fg_get_pressures(int *, const int *, const int *, int); |
---|
| 765 | static void fg_detect_pspans(int *, u_int, u_int, fg_pspan *, u_int *); |
---|
| 766 | static void wsp_interpret_sensor_data(struct atp_softc *, u_int); |
---|
| 767 | |
---|
| 768 | /* movement detection */ |
---|
| 769 | static boolean_t fg_match_stroke_component(fg_stroke_component_t *, |
---|
| 770 | const fg_pspan *, atp_stroke_type); |
---|
| 771 | static void fg_match_strokes_against_pspans(struct atp_softc *, |
---|
| 772 | atp_axis, fg_pspan *, u_int, u_int); |
---|
| 773 | static boolean_t wsp_match_strokes_against_fingers(struct atp_softc *, |
---|
| 774 | wsp_finger_t *, u_int); |
---|
| 775 | static boolean_t fg_update_strokes(struct atp_softc *, fg_pspan *, u_int, |
---|
| 776 | fg_pspan *, u_int); |
---|
| 777 | static boolean_t wsp_update_strokes(struct atp_softc *, |
---|
| 778 | wsp_finger_t [WSP_MAX_FINGERS], u_int); |
---|
| 779 | static void fg_add_stroke(struct atp_softc *, const fg_pspan *, const fg_pspan *); |
---|
| 780 | static void fg_add_new_strokes(struct atp_softc *, fg_pspan *, |
---|
| 781 | u_int, fg_pspan *, u_int); |
---|
| 782 | static void wsp_add_stroke(struct atp_softc *, const wsp_finger_t *); |
---|
| 783 | static void atp_advance_stroke_state(struct atp_softc *, |
---|
| 784 | atp_stroke_t *, boolean_t *); |
---|
| 785 | static boolean_t atp_stroke_has_small_movement(const atp_stroke_t *); |
---|
| 786 | static void atp_update_pending_mickeys(atp_stroke_t *); |
---|
| 787 | static boolean_t atp_compute_stroke_movement(atp_stroke_t *); |
---|
| 788 | static void atp_terminate_stroke(struct atp_softc *, atp_stroke_t *); |
---|
| 789 | |
---|
| 790 | /* tap detection */ |
---|
| 791 | static boolean_t atp_is_horizontal_scroll(const atp_stroke_t *); |
---|
| 792 | static boolean_t atp_is_vertical_scroll(const atp_stroke_t *); |
---|
| 793 | static void atp_reap_sibling_zombies(void *); |
---|
| 794 | static void atp_convert_to_slide(struct atp_softc *, atp_stroke_t *); |
---|
| 795 | |
---|
| 796 | /* updating fifo */ |
---|
| 797 | static void atp_reset_buf(struct atp_softc *); |
---|
| 798 | static void atp_add_to_queue(struct atp_softc *, int, int, int, uint32_t); |
---|
| 799 | |
---|
| 800 | /* Device methods. */ |
---|
| 801 | static device_probe_t atp_probe; |
---|
| 802 | static device_attach_t atp_attach; |
---|
| 803 | static device_detach_t atp_detach; |
---|
| 804 | static usb_callback_t atp_intr; |
---|
| 805 | |
---|
| 806 | static const struct usb_config atp_xfer_config[ATP_N_TRANSFER] = { |
---|
| 807 | [ATP_INTR_DT] = { |
---|
| 808 | .type = UE_INTERRUPT, |
---|
| 809 | .endpoint = UE_ADDR_ANY, |
---|
| 810 | .direction = UE_DIR_IN, |
---|
| 811 | .flags = { |
---|
| 812 | .pipe_bof = 1, /* block pipe on failure */ |
---|
| 813 | .short_xfer_ok = 1, |
---|
| 814 | }, |
---|
| 815 | .bufsize = ATP_SENSOR_DATA_BUF_MAX, |
---|
| 816 | .callback = &atp_intr, |
---|
| 817 | }, |
---|
| 818 | [ATP_RESET] = { |
---|
| 819 | .type = UE_CONTROL, |
---|
| 820 | .endpoint = 0, /* Control pipe */ |
---|
| 821 | .direction = UE_DIR_ANY, |
---|
| 822 | .bufsize = sizeof(struct usb_device_request) + MODE_LENGTH, |
---|
| 823 | .callback = &atp_reset_callback, |
---|
| 824 | .interval = 0, /* no pre-delay */ |
---|
| 825 | }, |
---|
| 826 | }; |
---|
| 827 | |
---|
| 828 | static atp_stroke_t * |
---|
| 829 | atp_alloc_stroke(struct atp_softc *sc) |
---|
| 830 | { |
---|
| 831 | atp_stroke_t *pstroke; |
---|
| 832 | |
---|
| 833 | pstroke = TAILQ_FIRST(&sc->sc_stroke_free); |
---|
| 834 | if (pstroke == NULL) |
---|
| 835 | goto done; |
---|
| 836 | |
---|
| 837 | TAILQ_REMOVE(&sc->sc_stroke_free, pstroke, entry); |
---|
| 838 | memset(pstroke, 0, sizeof(*pstroke)); |
---|
| 839 | TAILQ_INSERT_TAIL(&sc->sc_stroke_used, pstroke, entry); |
---|
| 840 | |
---|
| 841 | sc->sc_n_strokes++; |
---|
| 842 | done: |
---|
| 843 | return (pstroke); |
---|
| 844 | } |
---|
| 845 | |
---|
| 846 | static void |
---|
| 847 | atp_free_stroke(struct atp_softc *sc, atp_stroke_t *pstroke) |
---|
| 848 | { |
---|
| 849 | if (pstroke == NULL) |
---|
| 850 | return; |
---|
| 851 | |
---|
| 852 | sc->sc_n_strokes--; |
---|
| 853 | |
---|
| 854 | TAILQ_REMOVE(&sc->sc_stroke_used, pstroke, entry); |
---|
| 855 | TAILQ_INSERT_TAIL(&sc->sc_stroke_free, pstroke, entry); |
---|
| 856 | } |
---|
| 857 | |
---|
| 858 | static void |
---|
| 859 | atp_init_stroke_pool(struct atp_softc *sc) |
---|
| 860 | { |
---|
| 861 | u_int x; |
---|
| 862 | |
---|
| 863 | TAILQ_INIT(&sc->sc_stroke_free); |
---|
| 864 | TAILQ_INIT(&sc->sc_stroke_used); |
---|
| 865 | |
---|
| 866 | sc->sc_n_strokes = 0; |
---|
| 867 | |
---|
| 868 | memset(&sc->sc_strokes_data, 0, sizeof(sc->sc_strokes_data)); |
---|
| 869 | |
---|
| 870 | for (x = 0; x != ATP_MAX_STROKES; x++) { |
---|
| 871 | TAILQ_INSERT_TAIL(&sc->sc_stroke_free, &sc->sc_strokes_data[x], |
---|
| 872 | entry); |
---|
| 873 | } |
---|
| 874 | } |
---|
| 875 | |
---|
| 876 | static usb_error_t |
---|
| 877 | atp_set_device_mode(struct atp_softc *sc, interface_mode newMode) |
---|
| 878 | { |
---|
| 879 | uint8_t mode_value; |
---|
| 880 | usb_error_t err; |
---|
| 881 | |
---|
| 882 | if ((newMode != RAW_SENSOR_MODE) && (newMode != HID_MODE)) |
---|
| 883 | return (USB_ERR_INVAL); |
---|
| 884 | |
---|
| 885 | if ((newMode == RAW_SENSOR_MODE) && |
---|
| 886 | (sc->sc_family == TRACKPAD_FAMILY_FOUNTAIN_GEYSER)) |
---|
| 887 | mode_value = (uint8_t)0x04; |
---|
| 888 | else |
---|
| 889 | mode_value = newMode; |
---|
| 890 | |
---|
| 891 | err = usbd_req_get_report(sc->sc_usb_device, NULL /* mutex */, |
---|
| 892 | sc->sc_mode_bytes, sizeof(sc->sc_mode_bytes), 0 /* interface idx */, |
---|
| 893 | 0x03 /* type */, 0x00 /* id */); |
---|
| 894 | if (err != USB_ERR_NORMAL_COMPLETION) { |
---|
| 895 | DPRINTF("Failed to read device mode (%d)\n", err); |
---|
| 896 | return (err); |
---|
| 897 | } |
---|
| 898 | |
---|
| 899 | if (sc->sc_mode_bytes[0] == mode_value) |
---|
| 900 | return (err); |
---|
| 901 | |
---|
| 902 | /* |
---|
| 903 | * XXX Need to wait at least 250ms for hardware to get |
---|
| 904 | * ready. The device mode handling appears to be handled |
---|
| 905 | * asynchronously and we should not issue these commands too |
---|
| 906 | * quickly. |
---|
| 907 | */ |
---|
| 908 | pause("WHW", hz / 4); |
---|
| 909 | |
---|
| 910 | sc->sc_mode_bytes[0] = mode_value; |
---|
| 911 | return (usbd_req_set_report(sc->sc_usb_device, NULL /* mutex */, |
---|
| 912 | sc->sc_mode_bytes, sizeof(sc->sc_mode_bytes), 0 /* interface idx */, |
---|
| 913 | 0x03 /* type */, 0x00 /* id */)); |
---|
| 914 | } |
---|
| 915 | |
---|
| 916 | static void |
---|
| 917 | atp_reset_callback(struct usb_xfer *xfer, usb_error_t error) |
---|
| 918 | { |
---|
| 919 | usb_device_request_t req; |
---|
| 920 | struct usb_page_cache *pc; |
---|
| 921 | struct atp_softc *sc = usbd_xfer_softc(xfer); |
---|
| 922 | |
---|
| 923 | uint8_t mode_value; |
---|
| 924 | if (sc->sc_family == TRACKPAD_FAMILY_FOUNTAIN_GEYSER) |
---|
| 925 | mode_value = 0x04; |
---|
| 926 | else |
---|
| 927 | mode_value = RAW_SENSOR_MODE; |
---|
| 928 | |
---|
| 929 | switch (USB_GET_STATE(xfer)) { |
---|
| 930 | case USB_ST_SETUP: |
---|
| 931 | sc->sc_mode_bytes[0] = mode_value; |
---|
| 932 | req.bmRequestType = UT_WRITE_CLASS_INTERFACE; |
---|
| 933 | req.bRequest = UR_SET_REPORT; |
---|
| 934 | USETW2(req.wValue, |
---|
| 935 | (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */); |
---|
| 936 | USETW(req.wIndex, 0); |
---|
| 937 | USETW(req.wLength, MODE_LENGTH); |
---|
| 938 | |
---|
| 939 | pc = usbd_xfer_get_frame(xfer, 0); |
---|
| 940 | usbd_copy_in(pc, 0, &req, sizeof(req)); |
---|
| 941 | pc = usbd_xfer_get_frame(xfer, 1); |
---|
| 942 | usbd_copy_in(pc, 0, sc->sc_mode_bytes, MODE_LENGTH); |
---|
| 943 | |
---|
| 944 | usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); |
---|
| 945 | usbd_xfer_set_frame_len(xfer, 1, MODE_LENGTH); |
---|
| 946 | usbd_xfer_set_frames(xfer, 2); |
---|
| 947 | usbd_transfer_submit(xfer); |
---|
| 948 | break; |
---|
| 949 | |
---|
| 950 | case USB_ST_TRANSFERRED: |
---|
| 951 | default: |
---|
| 952 | break; |
---|
| 953 | } |
---|
| 954 | } |
---|
| 955 | |
---|
| 956 | static int |
---|
| 957 | atp_enable(struct atp_softc *sc) |
---|
| 958 | { |
---|
| 959 | if (sc->sc_state & ATP_ENABLED) |
---|
| 960 | return (0); |
---|
| 961 | |
---|
| 962 | /* reset status */ |
---|
| 963 | memset(&sc->sc_status, 0, sizeof(sc->sc_status)); |
---|
| 964 | |
---|
| 965 | atp_init_stroke_pool(sc); |
---|
| 966 | |
---|
| 967 | sc->sc_state |= ATP_ENABLED; |
---|
| 968 | |
---|
| 969 | DPRINTFN(ATP_LLEVEL_INFO, "enabled atp\n"); |
---|
| 970 | return (0); |
---|
| 971 | } |
---|
| 972 | |
---|
| 973 | static void |
---|
| 974 | atp_disable(struct atp_softc *sc) |
---|
| 975 | { |
---|
| 976 | sc->sc_state &= ~(ATP_ENABLED | ATP_VALID); |
---|
| 977 | DPRINTFN(ATP_LLEVEL_INFO, "disabled atp\n"); |
---|
| 978 | } |
---|
| 979 | |
---|
| 980 | static void |
---|
| 981 | fg_interpret_sensor_data(struct atp_softc *sc, u_int data_len) |
---|
| 982 | { |
---|
| 983 | u_int n_xpspans = 0; |
---|
| 984 | u_int n_ypspans = 0; |
---|
| 985 | uint8_t status_bits; |
---|
| 986 | |
---|
| 987 | const struct fg_dev_params *params = |
---|
| 988 | (const struct fg_dev_params *)sc->sc_params; |
---|
| 989 | |
---|
| 990 | fg_extract_sensor_data(sc->sc_sensor_data, params->n_xsensors, X, |
---|
| 991 | sc->sc_cur_x, params->prot); |
---|
| 992 | fg_extract_sensor_data(sc->sc_sensor_data, params->n_ysensors, Y, |
---|
| 993 | sc->sc_cur_y, params->prot); |
---|
| 994 | |
---|
| 995 | /* |
---|
| 996 | * If this is the initial update (from an untouched |
---|
| 997 | * pad), we should set the base values for the sensor |
---|
| 998 | * data; deltas with respect to these base values can |
---|
| 999 | * be used as pressure readings subsequently. |
---|
| 1000 | */ |
---|
| 1001 | status_bits = sc->sc_sensor_data[params->data_len - 1]; |
---|
| 1002 | if (((params->prot == FG_TRACKPAD_TYPE_GEYSER3) || |
---|
| 1003 | (params->prot == FG_TRACKPAD_TYPE_GEYSER4)) && |
---|
| 1004 | ((sc->sc_state & ATP_VALID) == 0)) { |
---|
| 1005 | if (status_bits & FG_STATUS_BASE_UPDATE) { |
---|
| 1006 | memcpy(sc->sc_base_x, sc->sc_cur_x, |
---|
| 1007 | params->n_xsensors * sizeof(*sc->sc_base_x)); |
---|
| 1008 | memcpy(sc->sc_base_y, sc->sc_cur_y, |
---|
| 1009 | params->n_ysensors * sizeof(*sc->sc_base_y)); |
---|
| 1010 | sc->sc_state |= ATP_VALID; |
---|
| 1011 | return; |
---|
| 1012 | } |
---|
| 1013 | } |
---|
| 1014 | |
---|
| 1015 | /* Get pressure readings and detect p-spans for both axes. */ |
---|
| 1016 | fg_get_pressures(sc->sc_pressure_x, sc->sc_cur_x, sc->sc_base_x, |
---|
| 1017 | params->n_xsensors); |
---|
| 1018 | fg_detect_pspans(sc->sc_pressure_x, params->n_xsensors, |
---|
| 1019 | FG_MAX_PSPANS_PER_AXIS, sc->sc_pspans_x, &n_xpspans); |
---|
| 1020 | fg_get_pressures(sc->sc_pressure_y, sc->sc_cur_y, sc->sc_base_y, |
---|
| 1021 | params->n_ysensors); |
---|
| 1022 | fg_detect_pspans(sc->sc_pressure_y, params->n_ysensors, |
---|
| 1023 | FG_MAX_PSPANS_PER_AXIS, sc->sc_pspans_y, &n_ypspans); |
---|
| 1024 | |
---|
| 1025 | /* Update strokes with new pspans to detect movements. */ |
---|
| 1026 | if (fg_update_strokes(sc, sc->sc_pspans_x, n_xpspans, sc->sc_pspans_y, n_ypspans)) |
---|
| 1027 | sc->sc_status.flags |= MOUSE_POSCHANGED; |
---|
| 1028 | |
---|
| 1029 | sc->sc_ibtn = (status_bits & FG_STATUS_BUTTON) ? MOUSE_BUTTON1DOWN : 0; |
---|
| 1030 | sc->sc_status.button = sc->sc_ibtn; |
---|
| 1031 | |
---|
| 1032 | /* |
---|
| 1033 | * The Fountain/Geyser device continues to trigger interrupts |
---|
| 1034 | * at a fast rate even after touchpad activity has |
---|
| 1035 | * stopped. Upon detecting that the device has remained idle |
---|
| 1036 | * beyond a threshold, we reinitialize it to silence the |
---|
| 1037 | * interrupts. |
---|
| 1038 | */ |
---|
| 1039 | if ((sc->sc_status.flags == 0) && (sc->sc_n_strokes == 0)) { |
---|
| 1040 | sc->sc_idlecount++; |
---|
| 1041 | if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) { |
---|
| 1042 | /* |
---|
| 1043 | * Use the last frame before we go idle for |
---|
| 1044 | * calibration on pads which do not send |
---|
| 1045 | * calibration frames. |
---|
| 1046 | */ |
---|
| 1047 | const struct fg_dev_params *params = |
---|
| 1048 | (const struct fg_dev_params *)sc->sc_params; |
---|
| 1049 | |
---|
| 1050 | DPRINTFN(ATP_LLEVEL_INFO, "idle\n"); |
---|
| 1051 | |
---|
| 1052 | if (params->prot < FG_TRACKPAD_TYPE_GEYSER3) { |
---|
| 1053 | memcpy(sc->sc_base_x, sc->sc_cur_x, |
---|
| 1054 | params->n_xsensors * sizeof(*(sc->sc_base_x))); |
---|
| 1055 | memcpy(sc->sc_base_y, sc->sc_cur_y, |
---|
| 1056 | params->n_ysensors * sizeof(*(sc->sc_base_y))); |
---|
| 1057 | } |
---|
| 1058 | |
---|
| 1059 | sc->sc_idlecount = 0; |
---|
| 1060 | usbd_transfer_start(sc->sc_xfer[ATP_RESET]); |
---|
| 1061 | } |
---|
| 1062 | } else { |
---|
| 1063 | sc->sc_idlecount = 0; |
---|
| 1064 | } |
---|
| 1065 | } |
---|
| 1066 | |
---|
| 1067 | /* |
---|
| 1068 | * Interpret the data from the X and Y pressure sensors. This function |
---|
| 1069 | * is called separately for the X and Y sensor arrays. The data in the |
---|
| 1070 | * USB packet is laid out in the following manner: |
---|
| 1071 | * |
---|
| 1072 | * sensor_data: |
---|
| 1073 | * --,--,Y1,Y2,--,Y3,Y4,--,Y5,...,Y10, ... X1,X2,--,X3,X4 |
---|
| 1074 | * indices: 0 1 2 3 4 5 6 7 8 ... 15 ... 20 21 22 23 24 |
---|
| 1075 | * |
---|
| 1076 | * '--' (in the above) indicates that the value is unimportant. |
---|
| 1077 | * |
---|
| 1078 | * Information about the above layout was obtained from the |
---|
| 1079 | * implementation of the AppleTouch driver in Linux. |
---|
| 1080 | * |
---|
| 1081 | * parameters: |
---|
| 1082 | * sensor_data |
---|
| 1083 | * raw sensor data from the USB packet. |
---|
| 1084 | * num |
---|
| 1085 | * The number of elements in the array 'arr'. |
---|
| 1086 | * axis |
---|
| 1087 | * Axis of data to fetch |
---|
| 1088 | * arr |
---|
| 1089 | * The array to be initialized with the readings. |
---|
| 1090 | * prot |
---|
| 1091 | * The protocol to use to interpret the data |
---|
| 1092 | */ |
---|
| 1093 | static void |
---|
| 1094 | fg_extract_sensor_data(const int8_t *sensor_data, u_int num, atp_axis axis, |
---|
| 1095 | int *arr, enum fountain_geyser_trackpad_type prot) |
---|
| 1096 | { |
---|
| 1097 | u_int i; |
---|
| 1098 | u_int di; /* index into sensor data */ |
---|
| 1099 | |
---|
| 1100 | switch (prot) { |
---|
| 1101 | case FG_TRACKPAD_TYPE_GEYSER1: |
---|
| 1102 | /* |
---|
| 1103 | * For Geyser 1, the sensors are laid out in pairs |
---|
| 1104 | * every 5 bytes. |
---|
| 1105 | */ |
---|
| 1106 | for (i = 0, di = (axis == Y) ? 1 : 2; i < 8; di += 5, i++) { |
---|
| 1107 | arr[i] = sensor_data[di]; |
---|
| 1108 | arr[i+8] = sensor_data[di+2]; |
---|
| 1109 | if ((axis == X) && (num > 16)) |
---|
| 1110 | arr[i+16] = sensor_data[di+40]; |
---|
| 1111 | } |
---|
| 1112 | |
---|
| 1113 | break; |
---|
| 1114 | case FG_TRACKPAD_TYPE_GEYSER2: |
---|
| 1115 | for (i = 0, di = (axis == Y) ? 1 : 19; i < num; /* empty */ ) { |
---|
| 1116 | arr[i++] = sensor_data[di++]; |
---|
| 1117 | arr[i++] = sensor_data[di++]; |
---|
| 1118 | di++; |
---|
| 1119 | } |
---|
| 1120 | break; |
---|
| 1121 | case FG_TRACKPAD_TYPE_GEYSER3: |
---|
| 1122 | case FG_TRACKPAD_TYPE_GEYSER4: |
---|
| 1123 | for (i = 0, di = (axis == Y) ? 2 : 20; i < num; /* empty */ ) { |
---|
| 1124 | arr[i++] = sensor_data[di++]; |
---|
| 1125 | arr[i++] = sensor_data[di++]; |
---|
| 1126 | di++; |
---|
| 1127 | } |
---|
| 1128 | break; |
---|
| 1129 | default: |
---|
| 1130 | break; |
---|
| 1131 | } |
---|
| 1132 | } |
---|
| 1133 | |
---|
| 1134 | static void |
---|
| 1135 | fg_get_pressures(int *p, const int *cur, const int *base, int n) |
---|
| 1136 | { |
---|
| 1137 | int i; |
---|
| 1138 | |
---|
| 1139 | for (i = 0; i < n; i++) { |
---|
| 1140 | p[i] = cur[i] - base[i]; |
---|
| 1141 | if (p[i] > 127) |
---|
| 1142 | p[i] -= 256; |
---|
| 1143 | if (p[i] < -127) |
---|
| 1144 | p[i] += 256; |
---|
| 1145 | if (p[i] < 0) |
---|
| 1146 | p[i] = 0; |
---|
| 1147 | |
---|
| 1148 | /* |
---|
| 1149 | * Shave off pressures below the noise-pressure |
---|
| 1150 | * threshold; this will reduce the contribution from |
---|
| 1151 | * lower pressure readings. |
---|
| 1152 | */ |
---|
| 1153 | if ((u_int)p[i] <= FG_SENSOR_NOISE_THRESHOLD) |
---|
| 1154 | p[i] = 0; /* filter away noise */ |
---|
| 1155 | else |
---|
| 1156 | p[i] -= FG_SENSOR_NOISE_THRESHOLD; |
---|
| 1157 | } |
---|
| 1158 | } |
---|
| 1159 | |
---|
| 1160 | static void |
---|
| 1161 | fg_detect_pspans(int *p, u_int num_sensors, |
---|
| 1162 | u_int max_spans, /* max # of pspans permitted */ |
---|
| 1163 | fg_pspan *spans, /* finger spans */ |
---|
| 1164 | u_int *nspans_p) /* num spans detected */ |
---|
| 1165 | { |
---|
| 1166 | u_int i; |
---|
| 1167 | int maxp; /* max pressure seen within a span */ |
---|
| 1168 | u_int num_spans = 0; |
---|
| 1169 | |
---|
| 1170 | enum fg_pspan_state { |
---|
| 1171 | ATP_PSPAN_INACTIVE, |
---|
| 1172 | ATP_PSPAN_INCREASING, |
---|
| 1173 | ATP_PSPAN_DECREASING, |
---|
| 1174 | } state; /* state of the pressure span */ |
---|
| 1175 | |
---|
| 1176 | /* |
---|
| 1177 | * The following is a simple state machine to track |
---|
| 1178 | * the phase of the pressure span. |
---|
| 1179 | */ |
---|
| 1180 | memset(spans, 0, max_spans * sizeof(fg_pspan)); |
---|
| 1181 | maxp = 0; |
---|
| 1182 | state = ATP_PSPAN_INACTIVE; |
---|
| 1183 | for (i = 0; i < num_sensors; i++) { |
---|
| 1184 | if (num_spans >= max_spans) |
---|
| 1185 | break; |
---|
| 1186 | |
---|
| 1187 | if (p[i] == 0) { |
---|
| 1188 | if (state == ATP_PSPAN_INACTIVE) { |
---|
| 1189 | /* |
---|
| 1190 | * There is no pressure information for this |
---|
| 1191 | * sensor, and we aren't tracking a finger. |
---|
| 1192 | */ |
---|
| 1193 | continue; |
---|
| 1194 | } else { |
---|
| 1195 | state = ATP_PSPAN_INACTIVE; |
---|
| 1196 | maxp = 0; |
---|
| 1197 | num_spans++; |
---|
| 1198 | } |
---|
| 1199 | } else { |
---|
| 1200 | switch (state) { |
---|
| 1201 | case ATP_PSPAN_INACTIVE: |
---|
| 1202 | state = ATP_PSPAN_INCREASING; |
---|
| 1203 | maxp = p[i]; |
---|
| 1204 | break; |
---|
| 1205 | |
---|
| 1206 | case ATP_PSPAN_INCREASING: |
---|
| 1207 | if (p[i] > maxp) |
---|
| 1208 | maxp = p[i]; |
---|
| 1209 | else if (p[i] <= (maxp >> 1)) |
---|
| 1210 | state = ATP_PSPAN_DECREASING; |
---|
| 1211 | break; |
---|
| 1212 | |
---|
| 1213 | case ATP_PSPAN_DECREASING: |
---|
| 1214 | if (p[i] > p[i - 1]) { |
---|
| 1215 | /* |
---|
| 1216 | * This is the beginning of |
---|
| 1217 | * another span; change state |
---|
| 1218 | * to give the appearance that |
---|
| 1219 | * we're starting from an |
---|
| 1220 | * inactive span, and then |
---|
| 1221 | * re-process this reading in |
---|
| 1222 | * the next iteration. |
---|
| 1223 | */ |
---|
| 1224 | num_spans++; |
---|
| 1225 | state = ATP_PSPAN_INACTIVE; |
---|
| 1226 | maxp = 0; |
---|
| 1227 | i--; |
---|
| 1228 | continue; |
---|
| 1229 | } |
---|
| 1230 | break; |
---|
| 1231 | } |
---|
| 1232 | |
---|
| 1233 | /* Update the finger span with this reading. */ |
---|
| 1234 | spans[num_spans].width++; |
---|
| 1235 | spans[num_spans].cum += p[i]; |
---|
| 1236 | spans[num_spans].cog += p[i] * (i + 1); |
---|
| 1237 | } |
---|
| 1238 | } |
---|
| 1239 | if (state != ATP_PSPAN_INACTIVE) |
---|
| 1240 | num_spans++; /* close the last finger span */ |
---|
| 1241 | |
---|
| 1242 | /* post-process the spans */ |
---|
| 1243 | for (i = 0; i < num_spans; i++) { |
---|
| 1244 | /* filter away unwanted pressure spans */ |
---|
| 1245 | if ((spans[i].cum < FG_PSPAN_MIN_CUM_PRESSURE) || |
---|
| 1246 | (spans[i].width > FG_PSPAN_MAX_WIDTH)) { |
---|
| 1247 | if ((i + 1) < num_spans) { |
---|
| 1248 | memcpy(&spans[i], &spans[i + 1], |
---|
| 1249 | (num_spans - i - 1) * sizeof(fg_pspan)); |
---|
| 1250 | i--; |
---|
| 1251 | } |
---|
| 1252 | num_spans--; |
---|
| 1253 | continue; |
---|
| 1254 | } |
---|
| 1255 | |
---|
| 1256 | /* compute this span's representative location */ |
---|
| 1257 | spans[i].loc = spans[i].cog * FG_SCALE_FACTOR / |
---|
| 1258 | spans[i].cum; |
---|
| 1259 | |
---|
| 1260 | spans[i].matched = false; /* not yet matched against a stroke */ |
---|
| 1261 | } |
---|
| 1262 | |
---|
| 1263 | *nspans_p = num_spans; |
---|
| 1264 | } |
---|
| 1265 | |
---|
| 1266 | static void |
---|
| 1267 | wsp_interpret_sensor_data(struct atp_softc *sc, u_int data_len) |
---|
| 1268 | { |
---|
| 1269 | const struct wsp_dev_params *params = sc->sc_params; |
---|
| 1270 | wsp_finger_t fingers[WSP_MAX_FINGERS]; |
---|
| 1271 | struct wsp_finger_sensor_data *source_fingerp; |
---|
| 1272 | u_int n_source_fingers; |
---|
| 1273 | u_int n_fingers; |
---|
| 1274 | u_int i; |
---|
| 1275 | |
---|
| 1276 | /* validate sensor data length */ |
---|
| 1277 | if ((data_len < params->finger_data_offset) || |
---|
| 1278 | ((data_len - params->finger_data_offset) % |
---|
| 1279 | WSP_SIZEOF_FINGER_SENSOR_DATA) != 0) |
---|
| 1280 | return; |
---|
| 1281 | |
---|
| 1282 | /* compute number of source fingers */ |
---|
| 1283 | n_source_fingers = (data_len - params->finger_data_offset) / |
---|
| 1284 | WSP_SIZEOF_FINGER_SENSOR_DATA; |
---|
| 1285 | |
---|
| 1286 | if (n_source_fingers > WSP_MAX_FINGERS) |
---|
| 1287 | n_source_fingers = WSP_MAX_FINGERS; |
---|
| 1288 | |
---|
| 1289 | /* iterate over the source data collecting useful fingers */ |
---|
| 1290 | n_fingers = 0; |
---|
| 1291 | source_fingerp = (struct wsp_finger_sensor_data *)(sc->sc_sensor_data + |
---|
| 1292 | params->finger_data_offset); |
---|
| 1293 | |
---|
| 1294 | for (i = 0; i < n_source_fingers; i++, source_fingerp++) { |
---|
| 1295 | /* swap endianness, if any */ |
---|
| 1296 | if (le16toh(0x1234) != 0x1234) { |
---|
| 1297 | source_fingerp->origin = le16toh((uint16_t)source_fingerp->origin); |
---|
| 1298 | source_fingerp->abs_x = le16toh((uint16_t)source_fingerp->abs_x); |
---|
| 1299 | source_fingerp->abs_y = le16toh((uint16_t)source_fingerp->abs_y); |
---|
| 1300 | source_fingerp->rel_x = le16toh((uint16_t)source_fingerp->rel_x); |
---|
| 1301 | source_fingerp->rel_y = le16toh((uint16_t)source_fingerp->rel_y); |
---|
| 1302 | source_fingerp->tool_major = le16toh((uint16_t)source_fingerp->tool_major); |
---|
| 1303 | source_fingerp->tool_minor = le16toh((uint16_t)source_fingerp->tool_minor); |
---|
| 1304 | source_fingerp->orientation = le16toh((uint16_t)source_fingerp->orientation); |
---|
| 1305 | source_fingerp->touch_major = le16toh((uint16_t)source_fingerp->touch_major); |
---|
| 1306 | source_fingerp->touch_minor = le16toh((uint16_t)source_fingerp->touch_minor); |
---|
| 1307 | source_fingerp->multi = le16toh((uint16_t)source_fingerp->multi); |
---|
| 1308 | } |
---|
| 1309 | |
---|
| 1310 | /* check for minium threshold */ |
---|
| 1311 | if (source_fingerp->touch_major == 0) |
---|
| 1312 | continue; |
---|
| 1313 | |
---|
| 1314 | fingers[n_fingers].matched = false; |
---|
| 1315 | fingers[n_fingers].x = source_fingerp->abs_x; |
---|
| 1316 | fingers[n_fingers].y = -source_fingerp->abs_y; |
---|
| 1317 | |
---|
| 1318 | n_fingers++; |
---|
| 1319 | } |
---|
| 1320 | |
---|
| 1321 | if ((sc->sc_n_strokes == 0) && (n_fingers == 0)) |
---|
| 1322 | return; |
---|
| 1323 | |
---|
| 1324 | if (wsp_update_strokes(sc, fingers, n_fingers)) |
---|
| 1325 | sc->sc_status.flags |= MOUSE_POSCHANGED; |
---|
| 1326 | |
---|
| 1327 | switch(params->tp_type) { |
---|
| 1328 | case WSP_TRACKPAD_TYPE2: |
---|
| 1329 | sc->sc_ibtn = sc->sc_sensor_data[WSP_TYPE2_BUTTON_DATA_OFFSET]; |
---|
| 1330 | break; |
---|
| 1331 | case WSP_TRACKPAD_TYPE3: |
---|
| 1332 | sc->sc_ibtn = sc->sc_sensor_data[WSP_TYPE3_BUTTON_DATA_OFFSET]; |
---|
| 1333 | break; |
---|
| 1334 | default: |
---|
| 1335 | break; |
---|
| 1336 | } |
---|
| 1337 | sc->sc_status.button = sc->sc_ibtn ? MOUSE_BUTTON1DOWN : 0; |
---|
| 1338 | } |
---|
| 1339 | |
---|
| 1340 | /* |
---|
| 1341 | * Match a pressure-span against a stroke-component. If there is a |
---|
| 1342 | * match, update the component's state and return true. |
---|
| 1343 | */ |
---|
| 1344 | static boolean_t |
---|
| 1345 | fg_match_stroke_component(fg_stroke_component_t *component, |
---|
| 1346 | const fg_pspan *pspan, atp_stroke_type stroke_type) |
---|
| 1347 | { |
---|
| 1348 | int delta_mickeys; |
---|
| 1349 | u_int min_pressure; |
---|
| 1350 | |
---|
| 1351 | delta_mickeys = pspan->loc - component->loc; |
---|
| 1352 | |
---|
| 1353 | if (abs(delta_mickeys) > (int)FG_MAX_DELTA_MICKEYS) |
---|
| 1354 | return (false); /* the finger span is too far out; no match */ |
---|
| 1355 | |
---|
| 1356 | component->loc = pspan->loc; |
---|
| 1357 | |
---|
| 1358 | /* |
---|
| 1359 | * A sudden and significant increase in a pspan's cumulative |
---|
| 1360 | * pressure indicates the incidence of a new finger |
---|
| 1361 | * contact. This usually revises the pspan's |
---|
| 1362 | * centre-of-gravity, and hence the location of any/all |
---|
| 1363 | * matching stroke component(s). But such a change should |
---|
| 1364 | * *not* be interpreted as a movement. |
---|
| 1365 | */ |
---|
| 1366 | if (pspan->cum > ((3 * component->cum_pressure) >> 1)) |
---|
| 1367 | delta_mickeys = 0; |
---|
| 1368 | |
---|
| 1369 | component->cum_pressure = pspan->cum; |
---|
| 1370 | if (pspan->cum > component->max_cum_pressure) |
---|
| 1371 | component->max_cum_pressure = pspan->cum; |
---|
| 1372 | |
---|
| 1373 | /* |
---|
| 1374 | * Disregard the component's movement if its cumulative |
---|
| 1375 | * pressure drops below a fraction of the maximum; this |
---|
| 1376 | * fraction is determined based on the stroke's type. |
---|
| 1377 | */ |
---|
| 1378 | if (stroke_type == ATP_STROKE_TOUCH) |
---|
| 1379 | min_pressure = (3 * component->max_cum_pressure) >> 2; |
---|
| 1380 | else |
---|
| 1381 | min_pressure = component->max_cum_pressure >> 2; |
---|
| 1382 | if (component->cum_pressure < min_pressure) |
---|
| 1383 | delta_mickeys = 0; |
---|
| 1384 | |
---|
| 1385 | component->delta_mickeys = delta_mickeys; |
---|
| 1386 | return (true); |
---|
| 1387 | } |
---|
| 1388 | |
---|
| 1389 | static void |
---|
| 1390 | fg_match_strokes_against_pspans(struct atp_softc *sc, atp_axis axis, |
---|
| 1391 | fg_pspan *pspans, u_int n_pspans, u_int repeat_count) |
---|
| 1392 | { |
---|
| 1393 | atp_stroke_t *strokep; |
---|
| 1394 | u_int repeat_index = 0; |
---|
| 1395 | u_int i; |
---|
| 1396 | |
---|
| 1397 | /* Determine the index of the multi-span. */ |
---|
| 1398 | if (repeat_count) { |
---|
| 1399 | for (i = 0; i < n_pspans; i++) { |
---|
| 1400 | if (pspans[i].cum > pspans[repeat_index].cum) |
---|
| 1401 | repeat_index = i; |
---|
| 1402 | } |
---|
| 1403 | } |
---|
| 1404 | |
---|
| 1405 | TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { |
---|
| 1406 | if (strokep->components[axis].matched) |
---|
| 1407 | continue; /* skip matched components */ |
---|
| 1408 | |
---|
| 1409 | for (i = 0; i < n_pspans; i++) { |
---|
| 1410 | if (pspans[i].matched) |
---|
| 1411 | continue; /* skip matched pspans */ |
---|
| 1412 | |
---|
| 1413 | if (fg_match_stroke_component( |
---|
| 1414 | &strokep->components[axis], &pspans[i], |
---|
| 1415 | strokep->type)) { |
---|
| 1416 | |
---|
| 1417 | /* There is a match. */ |
---|
| 1418 | strokep->components[axis].matched = true; |
---|
| 1419 | |
---|
| 1420 | /* Take care to repeat at the multi-span. */ |
---|
| 1421 | if ((repeat_count > 0) && (i == repeat_index)) |
---|
| 1422 | repeat_count--; |
---|
| 1423 | else |
---|
| 1424 | pspans[i].matched = true; |
---|
| 1425 | |
---|
| 1426 | break; /* skip to the next strokep */ |
---|
| 1427 | } |
---|
| 1428 | } /* loop over pspans */ |
---|
| 1429 | } /* loop over strokes */ |
---|
| 1430 | } |
---|
| 1431 | |
---|
| 1432 | static boolean_t |
---|
| 1433 | wsp_match_strokes_against_fingers(struct atp_softc *sc, |
---|
| 1434 | wsp_finger_t *fingers, u_int n_fingers) |
---|
| 1435 | { |
---|
| 1436 | boolean_t movement = false; |
---|
| 1437 | atp_stroke_t *strokep; |
---|
| 1438 | u_int i; |
---|
| 1439 | |
---|
| 1440 | /* reset the matched status for all strokes */ |
---|
| 1441 | TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) |
---|
| 1442 | strokep->matched = false; |
---|
| 1443 | |
---|
| 1444 | for (i = 0; i != n_fingers; i++) { |
---|
| 1445 | u_int least_distance_sq = WSP_MAX_ALLOWED_MATCH_DISTANCE_SQ; |
---|
| 1446 | atp_stroke_t *strokep_best = NULL; |
---|
| 1447 | |
---|
| 1448 | TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { |
---|
| 1449 | int instantaneous_dx; |
---|
| 1450 | int instantaneous_dy; |
---|
| 1451 | u_int d_squared; |
---|
| 1452 | |
---|
| 1453 | if (strokep->matched) |
---|
| 1454 | continue; |
---|
| 1455 | |
---|
| 1456 | instantaneous_dx = fingers[i].x - strokep->x; |
---|
| 1457 | instantaneous_dy = fingers[i].y - strokep->y; |
---|
| 1458 | |
---|
| 1459 | /* skip strokes which are far away */ |
---|
| 1460 | d_squared = |
---|
| 1461 | (instantaneous_dx * instantaneous_dx) + |
---|
| 1462 | (instantaneous_dy * instantaneous_dy); |
---|
| 1463 | |
---|
| 1464 | if (d_squared < least_distance_sq) { |
---|
| 1465 | least_distance_sq = d_squared; |
---|
| 1466 | strokep_best = strokep; |
---|
| 1467 | } |
---|
| 1468 | } |
---|
| 1469 | |
---|
| 1470 | strokep = strokep_best; |
---|
| 1471 | |
---|
| 1472 | if (strokep != NULL) { |
---|
| 1473 | fingers[i].matched = true; |
---|
| 1474 | |
---|
| 1475 | strokep->matched = true; |
---|
| 1476 | strokep->instantaneous_dx = fingers[i].x - strokep->x; |
---|
| 1477 | strokep->instantaneous_dy = fingers[i].y - strokep->y; |
---|
| 1478 | strokep->x = fingers[i].x; |
---|
| 1479 | strokep->y = fingers[i].y; |
---|
| 1480 | |
---|
| 1481 | atp_advance_stroke_state(sc, strokep, &movement); |
---|
| 1482 | } |
---|
| 1483 | } |
---|
| 1484 | return (movement); |
---|
| 1485 | } |
---|
| 1486 | |
---|
| 1487 | /* |
---|
| 1488 | * Update strokes by matching against current pressure-spans. |
---|
| 1489 | * Return true if any movement is detected. |
---|
| 1490 | */ |
---|
| 1491 | static boolean_t |
---|
| 1492 | fg_update_strokes(struct atp_softc *sc, fg_pspan *pspans_x, |
---|
| 1493 | u_int n_xpspans, fg_pspan *pspans_y, u_int n_ypspans) |
---|
| 1494 | { |
---|
| 1495 | atp_stroke_t *strokep; |
---|
| 1496 | atp_stroke_t *strokep_next; |
---|
| 1497 | boolean_t movement = false; |
---|
| 1498 | u_int repeat_count = 0; |
---|
| 1499 | u_int i; |
---|
| 1500 | u_int j; |
---|
| 1501 | |
---|
| 1502 | /* Reset X and Y components of all strokes as unmatched. */ |
---|
| 1503 | TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { |
---|
| 1504 | strokep->components[X].matched = false; |
---|
| 1505 | strokep->components[Y].matched = false; |
---|
| 1506 | } |
---|
| 1507 | |
---|
| 1508 | /* |
---|
| 1509 | * Usually, the X and Y pspans come in pairs (the common case |
---|
| 1510 | * being a single pair). It is possible, however, that |
---|
| 1511 | * multiple contacts resolve to a single pspan along an |
---|
| 1512 | * axis, as illustrated in the following: |
---|
| 1513 | * |
---|
| 1514 | * F = finger-contact |
---|
| 1515 | * |
---|
| 1516 | * pspan pspan |
---|
| 1517 | * +-----------------------+ |
---|
| 1518 | * | . . | |
---|
| 1519 | * | . . | |
---|
| 1520 | * | . . | |
---|
| 1521 | * | . . | |
---|
| 1522 | * pspan |.........F......F | |
---|
| 1523 | * | | |
---|
| 1524 | * | | |
---|
| 1525 | * | | |
---|
| 1526 | * +-----------------------+ |
---|
| 1527 | * |
---|
| 1528 | * |
---|
| 1529 | * The above case can be detected by a difference in the |
---|
| 1530 | * number of X and Y pspans. When this happens, X and Y pspans |
---|
| 1531 | * aren't easy to pair or match against strokes. |
---|
| 1532 | * |
---|
| 1533 | * When X and Y pspans differ in number, the axis with the |
---|
| 1534 | * smaller number of pspans is regarded as having a repeating |
---|
| 1535 | * pspan (or a multi-pspan)--in the above illustration, the |
---|
| 1536 | * Y-axis has a repeating pspan. Our approach is to try to |
---|
| 1537 | * match the multi-pspan repeatedly against strokes. The |
---|
| 1538 | * difference between the number of X and Y pspans gives us a |
---|
| 1539 | * crude repeat_count for matching multi-pspans--i.e. the |
---|
| 1540 | * multi-pspan along the Y axis (above) has a repeat_count of 1. |
---|
| 1541 | */ |
---|
| 1542 | repeat_count = abs(n_xpspans - n_ypspans); |
---|
| 1543 | |
---|
| 1544 | fg_match_strokes_against_pspans(sc, X, pspans_x, n_xpspans, |
---|
| 1545 | (((repeat_count != 0) && ((n_xpspans < n_ypspans))) ? |
---|
| 1546 | repeat_count : 0)); |
---|
| 1547 | fg_match_strokes_against_pspans(sc, Y, pspans_y, n_ypspans, |
---|
| 1548 | (((repeat_count != 0) && (n_ypspans < n_xpspans)) ? |
---|
| 1549 | repeat_count : 0)); |
---|
| 1550 | |
---|
| 1551 | /* Update the state of strokes based on the above pspan matches. */ |
---|
| 1552 | TAILQ_FOREACH_SAFE(strokep, &sc->sc_stroke_used, entry, strokep_next) { |
---|
| 1553 | |
---|
| 1554 | if (strokep->components[X].matched && |
---|
| 1555 | strokep->components[Y].matched) { |
---|
| 1556 | strokep->matched = true; |
---|
| 1557 | strokep->instantaneous_dx = |
---|
| 1558 | strokep->components[X].delta_mickeys; |
---|
| 1559 | strokep->instantaneous_dy = |
---|
| 1560 | strokep->components[Y].delta_mickeys; |
---|
| 1561 | atp_advance_stroke_state(sc, strokep, &movement); |
---|
| 1562 | } else { |
---|
| 1563 | /* |
---|
| 1564 | * At least one component of this stroke |
---|
| 1565 | * didn't match against current pspans; |
---|
| 1566 | * terminate it. |
---|
| 1567 | */ |
---|
| 1568 | atp_terminate_stroke(sc, strokep); |
---|
| 1569 | } |
---|
| 1570 | } |
---|
| 1571 | |
---|
| 1572 | /* Add new strokes for pairs of unmatched pspans */ |
---|
| 1573 | for (i = 0; i < n_xpspans; i++) { |
---|
| 1574 | if (pspans_x[i].matched == false) break; |
---|
| 1575 | } |
---|
| 1576 | for (j = 0; j < n_ypspans; j++) { |
---|
| 1577 | if (pspans_y[j].matched == false) break; |
---|
| 1578 | } |
---|
| 1579 | if ((i < n_xpspans) && (j < n_ypspans)) { |
---|
| 1580 | #ifdef USB_DEBUG |
---|
| 1581 | if (atp_debug >= ATP_LLEVEL_INFO) { |
---|
| 1582 | printf("unmatched pspans:"); |
---|
| 1583 | for (; i < n_xpspans; i++) { |
---|
| 1584 | if (pspans_x[i].matched) |
---|
| 1585 | continue; |
---|
| 1586 | printf(" X:[loc:%u,cum:%u]", |
---|
| 1587 | pspans_x[i].loc, pspans_x[i].cum); |
---|
| 1588 | } |
---|
| 1589 | for (; j < n_ypspans; j++) { |
---|
| 1590 | if (pspans_y[j].matched) |
---|
| 1591 | continue; |
---|
| 1592 | printf(" Y:[loc:%u,cum:%u]", |
---|
| 1593 | pspans_y[j].loc, pspans_y[j].cum); |
---|
| 1594 | } |
---|
| 1595 | printf("\n"); |
---|
| 1596 | } |
---|
| 1597 | #endif /* USB_DEBUG */ |
---|
| 1598 | if ((n_xpspans == 1) && (n_ypspans == 1)) |
---|
| 1599 | /* The common case of a single pair of new pspans. */ |
---|
| 1600 | fg_add_stroke(sc, &pspans_x[0], &pspans_y[0]); |
---|
| 1601 | else |
---|
| 1602 | fg_add_new_strokes(sc, pspans_x, n_xpspans, |
---|
| 1603 | pspans_y, n_ypspans); |
---|
| 1604 | } |
---|
| 1605 | |
---|
| 1606 | #ifdef USB_DEBUG |
---|
| 1607 | if (atp_debug >= ATP_LLEVEL_INFO) { |
---|
| 1608 | TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { |
---|
| 1609 | printf(" %s%clc:%u,dm:%d,cum:%d,max:%d,%c" |
---|
| 1610 | ",%clc:%u,dm:%d,cum:%d,max:%d,%c", |
---|
| 1611 | (strokep->flags & ATSF_ZOMBIE) ? "zomb:" : "", |
---|
| 1612 | (strokep->type == ATP_STROKE_TOUCH) ? '[' : '<', |
---|
| 1613 | strokep->components[X].loc, |
---|
| 1614 | strokep->components[X].delta_mickeys, |
---|
| 1615 | strokep->components[X].cum_pressure, |
---|
| 1616 | strokep->components[X].max_cum_pressure, |
---|
| 1617 | (strokep->type == ATP_STROKE_TOUCH) ? ']' : '>', |
---|
| 1618 | (strokep->type == ATP_STROKE_TOUCH) ? '[' : '<', |
---|
| 1619 | strokep->components[Y].loc, |
---|
| 1620 | strokep->components[Y].delta_mickeys, |
---|
| 1621 | strokep->components[Y].cum_pressure, |
---|
| 1622 | strokep->components[Y].max_cum_pressure, |
---|
| 1623 | (strokep->type == ATP_STROKE_TOUCH) ? ']' : '>'); |
---|
| 1624 | } |
---|
| 1625 | if (TAILQ_FIRST(&sc->sc_stroke_used) != NULL) |
---|
| 1626 | printf("\n"); |
---|
| 1627 | } |
---|
| 1628 | #endif /* USB_DEBUG */ |
---|
| 1629 | return (movement); |
---|
| 1630 | } |
---|
| 1631 | |
---|
| 1632 | /* |
---|
| 1633 | * Update strokes by matching against current pressure-spans. |
---|
| 1634 | * Return true if any movement is detected. |
---|
| 1635 | */ |
---|
| 1636 | static boolean_t |
---|
| 1637 | wsp_update_strokes(struct atp_softc *sc, wsp_finger_t *fingers, u_int n_fingers) |
---|
| 1638 | { |
---|
| 1639 | boolean_t movement = false; |
---|
| 1640 | atp_stroke_t *strokep_next; |
---|
| 1641 | atp_stroke_t *strokep; |
---|
| 1642 | u_int i; |
---|
| 1643 | |
---|
| 1644 | if (sc->sc_n_strokes > 0) { |
---|
| 1645 | movement = wsp_match_strokes_against_fingers( |
---|
| 1646 | sc, fingers, n_fingers); |
---|
| 1647 | |
---|
| 1648 | /* handle zombie strokes */ |
---|
| 1649 | TAILQ_FOREACH_SAFE(strokep, &sc->sc_stroke_used, entry, strokep_next) { |
---|
| 1650 | if (strokep->matched) |
---|
| 1651 | continue; |
---|
| 1652 | atp_terminate_stroke(sc, strokep); |
---|
| 1653 | } |
---|
| 1654 | } |
---|
| 1655 | |
---|
| 1656 | /* initialize unmatched fingers as strokes */ |
---|
| 1657 | for (i = 0; i != n_fingers; i++) { |
---|
| 1658 | if (fingers[i].matched) |
---|
| 1659 | continue; |
---|
| 1660 | |
---|
| 1661 | wsp_add_stroke(sc, fingers + i); |
---|
| 1662 | } |
---|
| 1663 | return (movement); |
---|
| 1664 | } |
---|
| 1665 | |
---|
| 1666 | /* Initialize a stroke using a pressure-span. */ |
---|
| 1667 | static void |
---|
| 1668 | fg_add_stroke(struct atp_softc *sc, const fg_pspan *pspan_x, |
---|
| 1669 | const fg_pspan *pspan_y) |
---|
| 1670 | { |
---|
| 1671 | atp_stroke_t *strokep; |
---|
| 1672 | |
---|
| 1673 | strokep = atp_alloc_stroke(sc); |
---|
| 1674 | if (strokep == NULL) |
---|
| 1675 | return; |
---|
| 1676 | |
---|
| 1677 | /* |
---|
| 1678 | * Strokes begin as potential touches. If a stroke survives |
---|
| 1679 | * longer than a threshold, or if it records significant |
---|
| 1680 | * cumulative movement, then it is considered a 'slide'. |
---|
| 1681 | */ |
---|
| 1682 | strokep->type = ATP_STROKE_TOUCH; |
---|
| 1683 | strokep->matched = false; |
---|
| 1684 | microtime(&strokep->ctime); |
---|
| 1685 | strokep->age = 1; /* number of interrupts */ |
---|
| 1686 | strokep->x = pspan_x->loc; |
---|
| 1687 | strokep->y = pspan_y->loc; |
---|
| 1688 | |
---|
| 1689 | strokep->components[X].loc = pspan_x->loc; |
---|
| 1690 | strokep->components[X].cum_pressure = pspan_x->cum; |
---|
| 1691 | strokep->components[X].max_cum_pressure = pspan_x->cum; |
---|
| 1692 | strokep->components[X].matched = true; |
---|
| 1693 | |
---|
| 1694 | strokep->components[Y].loc = pspan_y->loc; |
---|
| 1695 | strokep->components[Y].cum_pressure = pspan_y->cum; |
---|
| 1696 | strokep->components[Y].max_cum_pressure = pspan_y->cum; |
---|
| 1697 | strokep->components[Y].matched = true; |
---|
| 1698 | |
---|
| 1699 | if (sc->sc_n_strokes > 1) { |
---|
| 1700 | /* Reset double-tap-n-drag if we have more than one strokes. */ |
---|
| 1701 | sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; |
---|
| 1702 | } |
---|
| 1703 | |
---|
| 1704 | DPRINTFN(ATP_LLEVEL_INFO, "[%u,%u], time: %u,%ld\n", |
---|
| 1705 | strokep->components[X].loc, |
---|
| 1706 | strokep->components[Y].loc, |
---|
| 1707 | (u_int)strokep->ctime.tv_sec, |
---|
| 1708 | (unsigned long int)strokep->ctime.tv_usec); |
---|
| 1709 | } |
---|
| 1710 | |
---|
| 1711 | static void |
---|
| 1712 | fg_add_new_strokes(struct atp_softc *sc, fg_pspan *pspans_x, |
---|
| 1713 | u_int n_xpspans, fg_pspan *pspans_y, u_int n_ypspans) |
---|
| 1714 | { |
---|
| 1715 | fg_pspan spans[2][FG_MAX_PSPANS_PER_AXIS]; |
---|
| 1716 | u_int nspans[2]; |
---|
| 1717 | u_int i; |
---|
| 1718 | u_int j; |
---|
| 1719 | |
---|
| 1720 | /* Copy unmatched pspans into the local arrays. */ |
---|
| 1721 | for (i = 0, nspans[X] = 0; i < n_xpspans; i++) { |
---|
| 1722 | if (pspans_x[i].matched == false) { |
---|
| 1723 | spans[X][nspans[X]] = pspans_x[i]; |
---|
| 1724 | nspans[X]++; |
---|
| 1725 | } |
---|
| 1726 | } |
---|
| 1727 | for (j = 0, nspans[Y] = 0; j < n_ypspans; j++) { |
---|
| 1728 | if (pspans_y[j].matched == false) { |
---|
| 1729 | spans[Y][nspans[Y]] = pspans_y[j]; |
---|
| 1730 | nspans[Y]++; |
---|
| 1731 | } |
---|
| 1732 | } |
---|
| 1733 | |
---|
| 1734 | if (nspans[X] == nspans[Y]) { |
---|
| 1735 | /* Create new strokes from pairs of unmatched pspans */ |
---|
| 1736 | for (i = 0, j = 0; (i < nspans[X]) && (j < nspans[Y]); i++, j++) |
---|
| 1737 | fg_add_stroke(sc, &spans[X][i], &spans[Y][j]); |
---|
| 1738 | } else { |
---|
| 1739 | u_int cum = 0; |
---|
| 1740 | atp_axis repeat_axis; /* axis with multi-pspans */ |
---|
| 1741 | u_int repeat_count; /* repeat count for the multi-pspan*/ |
---|
| 1742 | u_int repeat_index = 0; /* index of the multi-span */ |
---|
| 1743 | |
---|
| 1744 | repeat_axis = (nspans[X] > nspans[Y]) ? Y : X; |
---|
| 1745 | repeat_count = abs(nspans[X] - nspans[Y]); |
---|
| 1746 | for (i = 0; i < nspans[repeat_axis]; i++) { |
---|
| 1747 | if (spans[repeat_axis][i].cum > cum) { |
---|
| 1748 | repeat_index = i; |
---|
| 1749 | cum = spans[repeat_axis][i].cum; |
---|
| 1750 | } |
---|
| 1751 | } |
---|
| 1752 | |
---|
| 1753 | /* Create new strokes from pairs of unmatched pspans */ |
---|
| 1754 | i = 0, j = 0; |
---|
| 1755 | for (; (i < nspans[X]) && (j < nspans[Y]); i++, j++) { |
---|
| 1756 | fg_add_stroke(sc, &spans[X][i], &spans[Y][j]); |
---|
| 1757 | |
---|
| 1758 | /* Take care to repeat at the multi-pspan. */ |
---|
| 1759 | if (repeat_count > 0) { |
---|
| 1760 | if ((repeat_axis == X) && |
---|
| 1761 | (repeat_index == i)) { |
---|
| 1762 | i--; /* counter loop increment */ |
---|
| 1763 | repeat_count--; |
---|
| 1764 | } else if ((repeat_axis == Y) && |
---|
| 1765 | (repeat_index == j)) { |
---|
| 1766 | j--; /* counter loop increment */ |
---|
| 1767 | repeat_count--; |
---|
| 1768 | } |
---|
| 1769 | } |
---|
| 1770 | } |
---|
| 1771 | } |
---|
| 1772 | } |
---|
| 1773 | |
---|
| 1774 | /* Initialize a stroke from an unmatched finger. */ |
---|
| 1775 | static void |
---|
| 1776 | wsp_add_stroke(struct atp_softc *sc, const wsp_finger_t *fingerp) |
---|
| 1777 | { |
---|
| 1778 | atp_stroke_t *strokep; |
---|
| 1779 | |
---|
| 1780 | strokep = atp_alloc_stroke(sc); |
---|
| 1781 | if (strokep == NULL) |
---|
| 1782 | return; |
---|
| 1783 | |
---|
| 1784 | /* |
---|
| 1785 | * Strokes begin as potential touches. If a stroke survives |
---|
| 1786 | * longer than a threshold, or if it records significant |
---|
| 1787 | * cumulative movement, then it is considered a 'slide'. |
---|
| 1788 | */ |
---|
| 1789 | strokep->type = ATP_STROKE_TOUCH; |
---|
| 1790 | strokep->matched = true; |
---|
| 1791 | microtime(&strokep->ctime); |
---|
| 1792 | strokep->age = 1; /* number of interrupts */ |
---|
| 1793 | strokep->x = fingerp->x; |
---|
| 1794 | strokep->y = fingerp->y; |
---|
| 1795 | |
---|
| 1796 | /* Reset double-tap-n-drag if we have more than one strokes. */ |
---|
| 1797 | if (sc->sc_n_strokes > 1) |
---|
| 1798 | sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; |
---|
| 1799 | |
---|
| 1800 | DPRINTFN(ATP_LLEVEL_INFO, "[%d,%d]\n", strokep->x, strokep->y); |
---|
| 1801 | } |
---|
| 1802 | |
---|
| 1803 | static void |
---|
| 1804 | atp_advance_stroke_state(struct atp_softc *sc, atp_stroke_t *strokep, |
---|
| 1805 | boolean_t *movementp) |
---|
| 1806 | { |
---|
| 1807 | /* Revitalize stroke if it had previously been marked as a zombie. */ |
---|
| 1808 | if (strokep->flags & ATSF_ZOMBIE) |
---|
| 1809 | strokep->flags &= ~ATSF_ZOMBIE; |
---|
| 1810 | |
---|
| 1811 | strokep->age++; |
---|
| 1812 | if (strokep->age <= atp_stroke_maturity_threshold) { |
---|
| 1813 | /* Avoid noise from immature strokes. */ |
---|
| 1814 | strokep->instantaneous_dx = 0; |
---|
| 1815 | strokep->instantaneous_dy = 0; |
---|
| 1816 | } |
---|
| 1817 | |
---|
| 1818 | if (atp_compute_stroke_movement(strokep)) |
---|
| 1819 | *movementp = true; |
---|
| 1820 | |
---|
| 1821 | if (strokep->type != ATP_STROKE_TOUCH) |
---|
| 1822 | return; |
---|
| 1823 | |
---|
| 1824 | /* Convert touch strokes to slides upon detecting movement or age. */ |
---|
| 1825 | if ((abs(strokep->cum_movement_x) > atp_slide_min_movement) || |
---|
| 1826 | (abs(strokep->cum_movement_y) > atp_slide_min_movement)) |
---|
| 1827 | atp_convert_to_slide(sc, strokep); |
---|
| 1828 | else { |
---|
| 1829 | /* Compute the stroke's age. */ |
---|
| 1830 | struct timeval tdiff; |
---|
| 1831 | getmicrotime(&tdiff); |
---|
| 1832 | if (timevalcmp(&tdiff, &strokep->ctime, >)) { |
---|
| 1833 | timevalsub(&tdiff, &strokep->ctime); |
---|
| 1834 | |
---|
| 1835 | if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) || |
---|
| 1836 | ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) && |
---|
| 1837 | (tdiff.tv_usec >= (atp_touch_timeout % 1000000)))) |
---|
| 1838 | atp_convert_to_slide(sc, strokep); |
---|
| 1839 | } |
---|
| 1840 | } |
---|
| 1841 | } |
---|
| 1842 | |
---|
| 1843 | static boolean_t |
---|
| 1844 | atp_stroke_has_small_movement(const atp_stroke_t *strokep) |
---|
| 1845 | { |
---|
| 1846 | return (((u_int)abs(strokep->instantaneous_dx) <= |
---|
| 1847 | atp_small_movement_threshold) && |
---|
| 1848 | ((u_int)abs(strokep->instantaneous_dy) <= |
---|
| 1849 | atp_small_movement_threshold)); |
---|
| 1850 | } |
---|
| 1851 | |
---|
| 1852 | /* |
---|
| 1853 | * Accumulate instantaneous changes into the stroke's 'pending' bucket; if |
---|
| 1854 | * the aggregate exceeds the small_movement_threshold, then retain |
---|
| 1855 | * instantaneous changes for later. |
---|
| 1856 | */ |
---|
| 1857 | static void |
---|
| 1858 | atp_update_pending_mickeys(atp_stroke_t *strokep) |
---|
| 1859 | { |
---|
| 1860 | /* accumulate instantaneous movement */ |
---|
| 1861 | strokep->pending_dx += strokep->instantaneous_dx; |
---|
| 1862 | strokep->pending_dy += strokep->instantaneous_dy; |
---|
| 1863 | |
---|
| 1864 | #define UPDATE_INSTANTANEOUS_AND_PENDING(I, P) \ |
---|
| 1865 | if (abs((P)) <= atp_small_movement_threshold) \ |
---|
| 1866 | (I) = 0; /* clobber small movement */ \ |
---|
| 1867 | else { \ |
---|
| 1868 | if ((I) > 0) { \ |
---|
| 1869 | /* \ |
---|
| 1870 | * Round up instantaneous movement to the nearest \ |
---|
| 1871 | * ceiling. This helps preserve small mickey \ |
---|
| 1872 | * movements from being lost in following scaling \ |
---|
| 1873 | * operation. \ |
---|
| 1874 | */ \ |
---|
| 1875 | (I) = (((I) + (atp_mickeys_scale_factor - 1)) / \ |
---|
| 1876 | atp_mickeys_scale_factor) * \ |
---|
| 1877 | atp_mickeys_scale_factor; \ |
---|
| 1878 | \ |
---|
| 1879 | /* \ |
---|
| 1880 | * Deduct the rounded mickeys from pending mickeys. \ |
---|
| 1881 | * Note: we multiply by 2 to offset the previous \ |
---|
| 1882 | * accumulation of instantaneous movement into \ |
---|
| 1883 | * pending. \ |
---|
| 1884 | */ \ |
---|
| 1885 | (P) -= ((I) << 1); \ |
---|
| 1886 | \ |
---|
| 1887 | /* truncate pending to 0 if it becomes negative. */ \ |
---|
| 1888 | (P) = imax((P), 0); \ |
---|
| 1889 | } else { \ |
---|
| 1890 | /* \ |
---|
| 1891 | * Round down instantaneous movement to the nearest \ |
---|
| 1892 | * ceiling. This helps preserve small mickey \ |
---|
| 1893 | * movements from being lost in following scaling \ |
---|
| 1894 | * operation. \ |
---|
| 1895 | */ \ |
---|
| 1896 | (I) = (((I) - (atp_mickeys_scale_factor - 1)) / \ |
---|
| 1897 | atp_mickeys_scale_factor) * \ |
---|
| 1898 | atp_mickeys_scale_factor; \ |
---|
| 1899 | \ |
---|
| 1900 | /* \ |
---|
| 1901 | * Deduct the rounded mickeys from pending mickeys. \ |
---|
| 1902 | * Note: we multiply by 2 to offset the previous \ |
---|
| 1903 | * accumulation of instantaneous movement into \ |
---|
| 1904 | * pending. \ |
---|
| 1905 | */ \ |
---|
| 1906 | (P) -= ((I) << 1); \ |
---|
| 1907 | \ |
---|
| 1908 | /* truncate pending to 0 if it becomes positive. */ \ |
---|
| 1909 | (P) = imin((P), 0); \ |
---|
| 1910 | } \ |
---|
| 1911 | } |
---|
| 1912 | |
---|
| 1913 | UPDATE_INSTANTANEOUS_AND_PENDING(strokep->instantaneous_dx, |
---|
| 1914 | strokep->pending_dx); |
---|
| 1915 | UPDATE_INSTANTANEOUS_AND_PENDING(strokep->instantaneous_dy, |
---|
| 1916 | strokep->pending_dy); |
---|
| 1917 | } |
---|
| 1918 | |
---|
| 1919 | /* |
---|
| 1920 | * Compute a smoothened value for the stroke's movement from |
---|
| 1921 | * instantaneous changes in the X and Y components. |
---|
| 1922 | */ |
---|
| 1923 | static boolean_t |
---|
| 1924 | atp_compute_stroke_movement(atp_stroke_t *strokep) |
---|
| 1925 | { |
---|
| 1926 | /* |
---|
| 1927 | * Short movements are added first to the 'pending' bucket, |
---|
| 1928 | * and then acted upon only when their aggregate exceeds a |
---|
| 1929 | * threshold. This has the effect of filtering away movement |
---|
| 1930 | * noise. |
---|
| 1931 | */ |
---|
| 1932 | if (atp_stroke_has_small_movement(strokep)) |
---|
| 1933 | atp_update_pending_mickeys(strokep); |
---|
| 1934 | else { /* large movement */ |
---|
| 1935 | /* clear away any pending mickeys if there are large movements*/ |
---|
| 1936 | strokep->pending_dx = 0; |
---|
| 1937 | strokep->pending_dy = 0; |
---|
| 1938 | } |
---|
| 1939 | |
---|
| 1940 | /* scale movement */ |
---|
| 1941 | strokep->movement_dx = (strokep->instantaneous_dx) / |
---|
| 1942 | (int)atp_mickeys_scale_factor; |
---|
| 1943 | strokep->movement_dy = (strokep->instantaneous_dy) / |
---|
| 1944 | (int)atp_mickeys_scale_factor; |
---|
| 1945 | |
---|
| 1946 | if ((abs(strokep->instantaneous_dx) >= ATP_FAST_MOVEMENT_TRESHOLD) || |
---|
| 1947 | (abs(strokep->instantaneous_dy) >= ATP_FAST_MOVEMENT_TRESHOLD)) { |
---|
| 1948 | strokep->movement_dx <<= 1; |
---|
| 1949 | strokep->movement_dy <<= 1; |
---|
| 1950 | } |
---|
| 1951 | |
---|
| 1952 | strokep->cum_movement_x += strokep->movement_dx; |
---|
| 1953 | strokep->cum_movement_y += strokep->movement_dy; |
---|
| 1954 | |
---|
| 1955 | return ((strokep->movement_dx != 0) || (strokep->movement_dy != 0)); |
---|
| 1956 | } |
---|
| 1957 | |
---|
| 1958 | /* |
---|
| 1959 | * Terminate a stroke. Aside from immature strokes, a slide or touch is |
---|
| 1960 | * retained as a zombies so as to reap all their termination siblings |
---|
| 1961 | * together; this helps establish the number of fingers involved at the |
---|
| 1962 | * end of a multi-touch gesture. |
---|
| 1963 | */ |
---|
| 1964 | static void |
---|
| 1965 | atp_terminate_stroke(struct atp_softc *sc, atp_stroke_t *strokep) |
---|
| 1966 | { |
---|
| 1967 | if (strokep->flags & ATSF_ZOMBIE) |
---|
| 1968 | return; |
---|
| 1969 | |
---|
| 1970 | /* Drop immature strokes rightaway. */ |
---|
| 1971 | if (strokep->age <= atp_stroke_maturity_threshold) { |
---|
| 1972 | atp_free_stroke(sc, strokep); |
---|
| 1973 | return; |
---|
| 1974 | } |
---|
| 1975 | |
---|
| 1976 | strokep->flags |= ATSF_ZOMBIE; |
---|
| 1977 | sc->sc_state |= ATP_ZOMBIES_EXIST; |
---|
| 1978 | |
---|
| 1979 | callout_reset(&sc->sc_callout, ATP_ZOMBIE_STROKE_REAP_INTERVAL, |
---|
| 1980 | atp_reap_sibling_zombies, sc); |
---|
| 1981 | |
---|
| 1982 | /* |
---|
| 1983 | * Reset the double-click-n-drag at the termination of any |
---|
| 1984 | * slide stroke. |
---|
| 1985 | */ |
---|
| 1986 | if (strokep->type == ATP_STROKE_SLIDE) |
---|
| 1987 | sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; |
---|
| 1988 | } |
---|
| 1989 | |
---|
| 1990 | static boolean_t |
---|
| 1991 | atp_is_horizontal_scroll(const atp_stroke_t *strokep) |
---|
| 1992 | { |
---|
| 1993 | if (abs(strokep->cum_movement_x) < atp_slide_min_movement) |
---|
| 1994 | return (false); |
---|
| 1995 | if (strokep->cum_movement_y == 0) |
---|
| 1996 | return (true); |
---|
| 1997 | return (abs(strokep->cum_movement_x / strokep->cum_movement_y) >= 4); |
---|
| 1998 | } |
---|
| 1999 | |
---|
| 2000 | static boolean_t |
---|
| 2001 | atp_is_vertical_scroll(const atp_stroke_t *strokep) |
---|
| 2002 | { |
---|
| 2003 | if (abs(strokep->cum_movement_y) < atp_slide_min_movement) |
---|
| 2004 | return (false); |
---|
| 2005 | if (strokep->cum_movement_x == 0) |
---|
| 2006 | return (true); |
---|
| 2007 | return (abs(strokep->cum_movement_y / strokep->cum_movement_x) >= 4); |
---|
| 2008 | } |
---|
| 2009 | |
---|
| 2010 | static void |
---|
| 2011 | atp_reap_sibling_zombies(void *arg) |
---|
| 2012 | { |
---|
| 2013 | struct atp_softc *sc = (struct atp_softc *)arg; |
---|
| 2014 | u_int8_t n_touches_reaped = 0; |
---|
| 2015 | u_int8_t n_slides_reaped = 0; |
---|
| 2016 | u_int8_t n_horizontal_scrolls = 0; |
---|
| 2017 | u_int8_t n_vertical_scrolls = 0; |
---|
| 2018 | int horizontal_scroll = 0; |
---|
| 2019 | int vertical_scroll = 0; |
---|
| 2020 | atp_stroke_t *strokep; |
---|
| 2021 | atp_stroke_t *strokep_next; |
---|
| 2022 | |
---|
| 2023 | DPRINTFN(ATP_LLEVEL_INFO, "\n"); |
---|
| 2024 | |
---|
| 2025 | TAILQ_FOREACH_SAFE(strokep, &sc->sc_stroke_used, entry, strokep_next) { |
---|
| 2026 | if ((strokep->flags & ATSF_ZOMBIE) == 0) |
---|
| 2027 | continue; |
---|
| 2028 | |
---|
| 2029 | if (strokep->type == ATP_STROKE_TOUCH) { |
---|
| 2030 | n_touches_reaped++; |
---|
| 2031 | } else { |
---|
| 2032 | n_slides_reaped++; |
---|
| 2033 | |
---|
| 2034 | if (atp_is_horizontal_scroll(strokep)) { |
---|
| 2035 | n_horizontal_scrolls++; |
---|
| 2036 | horizontal_scroll += strokep->cum_movement_x; |
---|
| 2037 | } else if (atp_is_vertical_scroll(strokep)) { |
---|
| 2038 | n_vertical_scrolls++; |
---|
| 2039 | vertical_scroll += strokep->cum_movement_y; |
---|
| 2040 | } |
---|
| 2041 | } |
---|
| 2042 | |
---|
| 2043 | atp_free_stroke(sc, strokep); |
---|
| 2044 | } |
---|
| 2045 | |
---|
| 2046 | DPRINTFN(ATP_LLEVEL_INFO, "reaped %u zombies\n", |
---|
| 2047 | n_touches_reaped + n_slides_reaped); |
---|
| 2048 | sc->sc_state &= ~ATP_ZOMBIES_EXIST; |
---|
| 2049 | |
---|
| 2050 | /* No further processing necessary if physical button is depressed. */ |
---|
| 2051 | if (sc->sc_ibtn != 0) |
---|
| 2052 | return; |
---|
| 2053 | |
---|
| 2054 | if ((n_touches_reaped == 0) && (n_slides_reaped == 0)) |
---|
| 2055 | return; |
---|
| 2056 | |
---|
| 2057 | /* Add a pair of virtual button events (button-down and button-up) if |
---|
| 2058 | * the physical button isn't pressed. */ |
---|
| 2059 | if (n_touches_reaped != 0) { |
---|
| 2060 | if (n_touches_reaped < atp_tap_minimum) |
---|
| 2061 | return; |
---|
| 2062 | |
---|
| 2063 | switch (n_touches_reaped) { |
---|
| 2064 | case 1: |
---|
| 2065 | atp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON1DOWN); |
---|
| 2066 | microtime(&sc->sc_touch_reap_time); /* remember this time */ |
---|
| 2067 | break; |
---|
| 2068 | case 2: |
---|
| 2069 | atp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON3DOWN); |
---|
| 2070 | break; |
---|
| 2071 | case 3: |
---|
| 2072 | atp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON2DOWN); |
---|
| 2073 | break; |
---|
| 2074 | default: |
---|
| 2075 | /* we handle taps of only up to 3 fingers */ |
---|
| 2076 | return; |
---|
| 2077 | } |
---|
| 2078 | atp_add_to_queue(sc, 0, 0, 0, 0); /* button release */ |
---|
| 2079 | |
---|
| 2080 | } else if ((n_slides_reaped == 2) && (n_horizontal_scrolls == 2)) { |
---|
| 2081 | if (horizontal_scroll < 0) |
---|
| 2082 | atp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON4DOWN); |
---|
| 2083 | else |
---|
| 2084 | atp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON5DOWN); |
---|
| 2085 | atp_add_to_queue(sc, 0, 0, 0, 0); /* button release */ |
---|
| 2086 | } |
---|
| 2087 | } |
---|
| 2088 | |
---|
| 2089 | /* Switch a given touch stroke to being a slide. */ |
---|
| 2090 | static void |
---|
| 2091 | atp_convert_to_slide(struct atp_softc *sc, atp_stroke_t *strokep) |
---|
| 2092 | { |
---|
| 2093 | strokep->type = ATP_STROKE_SLIDE; |
---|
| 2094 | |
---|
| 2095 | /* Are we at the beginning of a double-click-n-drag? */ |
---|
| 2096 | if ((sc->sc_n_strokes == 1) && |
---|
| 2097 | ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) && |
---|
| 2098 | timevalcmp(&strokep->ctime, &sc->sc_touch_reap_time, >)) { |
---|
| 2099 | struct timeval delta; |
---|
| 2100 | struct timeval window = { |
---|
| 2101 | atp_double_tap_threshold / 1000000, |
---|
| 2102 | atp_double_tap_threshold % 1000000 |
---|
| 2103 | }; |
---|
| 2104 | |
---|
| 2105 | delta = strokep->ctime; |
---|
| 2106 | timevalsub(&delta, &sc->sc_touch_reap_time); |
---|
| 2107 | if (timevalcmp(&delta, &window, <=)) |
---|
| 2108 | sc->sc_state |= ATP_DOUBLE_TAP_DRAG; |
---|
| 2109 | } |
---|
| 2110 | } |
---|
| 2111 | |
---|
| 2112 | static void |
---|
| 2113 | atp_reset_buf(struct atp_softc *sc) |
---|
| 2114 | { |
---|
| 2115 | /* reset read queue */ |
---|
| 2116 | usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]); |
---|
| 2117 | } |
---|
| 2118 | |
---|
| 2119 | static void |
---|
| 2120 | atp_add_to_queue(struct atp_softc *sc, int dx, int dy, int dz, |
---|
| 2121 | uint32_t buttons_in) |
---|
| 2122 | { |
---|
| 2123 | uint32_t buttons_out; |
---|
| 2124 | uint8_t buf[8]; |
---|
| 2125 | |
---|
| 2126 | dx = imin(dx, 254); dx = imax(dx, -256); |
---|
| 2127 | dy = imin(dy, 254); dy = imax(dy, -256); |
---|
| 2128 | dz = imin(dz, 126); dz = imax(dz, -128); |
---|
| 2129 | |
---|
| 2130 | buttons_out = MOUSE_MSC_BUTTONS; |
---|
| 2131 | if (buttons_in & MOUSE_BUTTON1DOWN) |
---|
| 2132 | buttons_out &= ~MOUSE_MSC_BUTTON1UP; |
---|
| 2133 | else if (buttons_in & MOUSE_BUTTON2DOWN) |
---|
| 2134 | buttons_out &= ~MOUSE_MSC_BUTTON2UP; |
---|
| 2135 | else if (buttons_in & MOUSE_BUTTON3DOWN) |
---|
| 2136 | buttons_out &= ~MOUSE_MSC_BUTTON3UP; |
---|
| 2137 | |
---|
| 2138 | DPRINTFN(ATP_LLEVEL_INFO, "dx=%d, dy=%d, buttons=%x\n", |
---|
| 2139 | dx, dy, buttons_out); |
---|
| 2140 | |
---|
| 2141 | /* Encode the mouse data in standard format; refer to mouse(4) */ |
---|
| 2142 | buf[0] = sc->sc_mode.syncmask[1]; |
---|
| 2143 | buf[0] |= buttons_out; |
---|
| 2144 | buf[1] = dx >> 1; |
---|
| 2145 | buf[2] = dy >> 1; |
---|
| 2146 | buf[3] = dx - (dx >> 1); |
---|
| 2147 | buf[4] = dy - (dy >> 1); |
---|
| 2148 | /* Encode extra bytes for level 1 */ |
---|
| 2149 | if (sc->sc_mode.level == 1) { |
---|
| 2150 | buf[5] = dz >> 1; |
---|
| 2151 | buf[6] = dz - (dz >> 1); |
---|
| 2152 | buf[7] = (((~buttons_in) >> 3) & MOUSE_SYS_EXTBUTTONS); |
---|
| 2153 | } |
---|
| 2154 | |
---|
| 2155 | usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, |
---|
| 2156 | sc->sc_mode.packetsize, 1); |
---|
| 2157 | } |
---|
| 2158 | |
---|
| 2159 | static int |
---|
| 2160 | atp_probe(device_t self) |
---|
| 2161 | { |
---|
| 2162 | struct usb_attach_arg *uaa = device_get_ivars(self); |
---|
| 2163 | |
---|
| 2164 | if (uaa->usb_mode != USB_MODE_HOST) |
---|
| 2165 | return (ENXIO); |
---|
| 2166 | |
---|
| 2167 | if (uaa->info.bInterfaceClass != UICLASS_HID) |
---|
| 2168 | return (ENXIO); |
---|
| 2169 | /* |
---|
| 2170 | * Note: for some reason, the check |
---|
| 2171 | * (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) doesn't hold true |
---|
| 2172 | * for wellspring trackpads, so we've removed it from the common path. |
---|
| 2173 | */ |
---|
| 2174 | |
---|
| 2175 | if ((usbd_lookup_id_by_uaa(fg_devs, sizeof(fg_devs), uaa)) == 0) |
---|
| 2176 | return ((uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) ? |
---|
| 2177 | 0 : ENXIO); |
---|
| 2178 | |
---|
| 2179 | if ((usbd_lookup_id_by_uaa(wsp_devs, sizeof(wsp_devs), uaa)) == 0) |
---|
| 2180 | if (uaa->info.bIfaceIndex == WELLSPRING_INTERFACE_INDEX) |
---|
| 2181 | return (0); |
---|
| 2182 | |
---|
| 2183 | return (ENXIO); |
---|
| 2184 | } |
---|
| 2185 | |
---|
| 2186 | static int |
---|
| 2187 | atp_attach(device_t dev) |
---|
| 2188 | { |
---|
| 2189 | struct atp_softc *sc = device_get_softc(dev); |
---|
| 2190 | struct usb_attach_arg *uaa = device_get_ivars(dev); |
---|
| 2191 | usb_error_t err; |
---|
| 2192 | void *descriptor_ptr = NULL; |
---|
| 2193 | uint16_t descriptor_len; |
---|
| 2194 | unsigned long di; |
---|
| 2195 | |
---|
| 2196 | DPRINTFN(ATP_LLEVEL_INFO, "sc=%p\n", sc); |
---|
| 2197 | |
---|
| 2198 | sc->sc_dev = dev; |
---|
| 2199 | sc->sc_usb_device = uaa->device; |
---|
| 2200 | |
---|
| 2201 | /* Get HID descriptor */ |
---|
| 2202 | if (usbd_req_get_hid_desc(uaa->device, NULL, &descriptor_ptr, |
---|
| 2203 | &descriptor_len, M_TEMP, uaa->info.bIfaceIndex) != |
---|
| 2204 | USB_ERR_NORMAL_COMPLETION) |
---|
| 2205 | return (ENXIO); |
---|
| 2206 | |
---|
| 2207 | /* Get HID report descriptor length */ |
---|
| 2208 | sc->sc_expected_sensor_data_len = hid_report_size(descriptor_ptr, |
---|
| 2209 | descriptor_len, hid_input, NULL); |
---|
| 2210 | free(descriptor_ptr, M_TEMP); |
---|
| 2211 | |
---|
| 2212 | if ((sc->sc_expected_sensor_data_len <= 0) || |
---|
| 2213 | (sc->sc_expected_sensor_data_len > ATP_SENSOR_DATA_BUF_MAX)) { |
---|
| 2214 | DPRINTF("atp_attach: datalength invalid or too large: %d\n", |
---|
| 2215 | sc->sc_expected_sensor_data_len); |
---|
| 2216 | return (ENXIO); |
---|
| 2217 | } |
---|
| 2218 | |
---|
| 2219 | /* |
---|
| 2220 | * By default the touchpad behaves like an HID device, sending |
---|
| 2221 | * packets with reportID = 2. Such reports contain only |
---|
| 2222 | * limited information--they encode movement deltas and button |
---|
| 2223 | * events,--but do not include data from the pressure |
---|
| 2224 | * sensors. The device input mode can be switched from HID |
---|
| 2225 | * reports to raw sensor data using vendor-specific USB |
---|
| 2226 | * control commands. |
---|
| 2227 | */ |
---|
| 2228 | if ((err = atp_set_device_mode(sc, RAW_SENSOR_MODE)) != 0) { |
---|
| 2229 | DPRINTF("failed to set mode to 'RAW_SENSOR' (%d)\n", err); |
---|
| 2230 | return (ENXIO); |
---|
| 2231 | } |
---|
| 2232 | |
---|
| 2233 | mtx_init(&sc->sc_mutex, "atpmtx", NULL, MTX_DEF | MTX_RECURSE); |
---|
| 2234 | |
---|
| 2235 | di = USB_GET_DRIVER_INFO(uaa); |
---|
| 2236 | |
---|
| 2237 | sc->sc_family = DECODE_FAMILY_FROM_DRIVER_INFO(di); |
---|
| 2238 | |
---|
| 2239 | switch(sc->sc_family) { |
---|
| 2240 | case TRACKPAD_FAMILY_FOUNTAIN_GEYSER: |
---|
| 2241 | sc->sc_params = |
---|
| 2242 | &fg_dev_params[DECODE_PRODUCT_FROM_DRIVER_INFO(di)]; |
---|
| 2243 | sc->sensor_data_interpreter = fg_interpret_sensor_data; |
---|
| 2244 | break; |
---|
| 2245 | case TRACKPAD_FAMILY_WELLSPRING: |
---|
| 2246 | sc->sc_params = |
---|
| 2247 | &wsp_dev_params[DECODE_PRODUCT_FROM_DRIVER_INFO(di)]; |
---|
| 2248 | sc->sensor_data_interpreter = wsp_interpret_sensor_data; |
---|
| 2249 | break; |
---|
| 2250 | default: |
---|
| 2251 | goto detach; |
---|
| 2252 | } |
---|
| 2253 | |
---|
| 2254 | err = usbd_transfer_setup(uaa->device, |
---|
| 2255 | &uaa->info.bIfaceIndex, sc->sc_xfer, atp_xfer_config, |
---|
| 2256 | ATP_N_TRANSFER, sc, &sc->sc_mutex); |
---|
| 2257 | if (err) { |
---|
| 2258 | DPRINTF("error=%s\n", usbd_errstr(err)); |
---|
| 2259 | goto detach; |
---|
| 2260 | } |
---|
| 2261 | |
---|
| 2262 | if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex, |
---|
| 2263 | &atp_fifo_methods, &sc->sc_fifo, |
---|
| 2264 | device_get_unit(dev), -1, uaa->info.bIfaceIndex, |
---|
| 2265 | UID_ROOT, GID_OPERATOR, 0644)) { |
---|
| 2266 | goto detach; |
---|
| 2267 | } |
---|
| 2268 | |
---|
| 2269 | device_set_usb_desc(dev); |
---|
| 2270 | |
---|
| 2271 | sc->sc_hw.buttons = 3; |
---|
| 2272 | sc->sc_hw.iftype = MOUSE_IF_USB; |
---|
| 2273 | sc->sc_hw.type = MOUSE_PAD; |
---|
| 2274 | sc->sc_hw.model = MOUSE_MODEL_GENERIC; |
---|
| 2275 | sc->sc_hw.hwid = 0; |
---|
| 2276 | sc->sc_mode.protocol = MOUSE_PROTO_MSC; |
---|
| 2277 | sc->sc_mode.rate = -1; |
---|
| 2278 | sc->sc_mode.resolution = MOUSE_RES_UNKNOWN; |
---|
| 2279 | sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; |
---|
| 2280 | sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; |
---|
| 2281 | sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; |
---|
| 2282 | sc->sc_mode.accelfactor = 0; |
---|
| 2283 | sc->sc_mode.level = 0; |
---|
| 2284 | |
---|
| 2285 | sc->sc_state = 0; |
---|
| 2286 | sc->sc_ibtn = 0; |
---|
| 2287 | |
---|
| 2288 | callout_init_mtx(&sc->sc_callout, &sc->sc_mutex, 0); |
---|
| 2289 | |
---|
| 2290 | return (0); |
---|
| 2291 | |
---|
| 2292 | detach: |
---|
| 2293 | atp_detach(dev); |
---|
| 2294 | return (ENOMEM); |
---|
| 2295 | } |
---|
| 2296 | |
---|
| 2297 | static int |
---|
| 2298 | atp_detach(device_t dev) |
---|
| 2299 | { |
---|
| 2300 | struct atp_softc *sc; |
---|
| 2301 | |
---|
| 2302 | sc = device_get_softc(dev); |
---|
| 2303 | atp_set_device_mode(sc, HID_MODE); |
---|
| 2304 | |
---|
| 2305 | mtx_lock(&sc->sc_mutex); |
---|
| 2306 | callout_drain(&sc->sc_callout); |
---|
| 2307 | if (sc->sc_state & ATP_ENABLED) |
---|
| 2308 | atp_disable(sc); |
---|
| 2309 | mtx_unlock(&sc->sc_mutex); |
---|
| 2310 | |
---|
| 2311 | usb_fifo_detach(&sc->sc_fifo); |
---|
| 2312 | |
---|
| 2313 | usbd_transfer_unsetup(sc->sc_xfer, ATP_N_TRANSFER); |
---|
| 2314 | |
---|
| 2315 | mtx_destroy(&sc->sc_mutex); |
---|
| 2316 | |
---|
| 2317 | return (0); |
---|
| 2318 | } |
---|
| 2319 | |
---|
| 2320 | static void |
---|
| 2321 | atp_intr(struct usb_xfer *xfer, usb_error_t error) |
---|
| 2322 | { |
---|
| 2323 | struct atp_softc *sc = usbd_xfer_softc(xfer); |
---|
| 2324 | struct usb_page_cache *pc; |
---|
| 2325 | int len; |
---|
| 2326 | |
---|
| 2327 | usbd_xfer_status(xfer, &len, NULL, NULL, NULL); |
---|
| 2328 | |
---|
| 2329 | switch (USB_GET_STATE(xfer)) { |
---|
| 2330 | case USB_ST_TRANSFERRED: |
---|
| 2331 | pc = usbd_xfer_get_frame(xfer, 0); |
---|
| 2332 | usbd_copy_out(pc, 0, sc->sc_sensor_data, len); |
---|
| 2333 | if (len < sc->sc_expected_sensor_data_len) { |
---|
| 2334 | /* make sure we don't process old data */ |
---|
| 2335 | memset(sc->sc_sensor_data + len, 0, |
---|
| 2336 | sc->sc_expected_sensor_data_len - len); |
---|
| 2337 | } |
---|
| 2338 | |
---|
| 2339 | sc->sc_status.flags &= ~(MOUSE_STDBUTTONSCHANGED | |
---|
| 2340 | MOUSE_POSCHANGED); |
---|
| 2341 | sc->sc_status.obutton = sc->sc_status.button; |
---|
| 2342 | |
---|
| 2343 | (sc->sensor_data_interpreter)(sc, len); |
---|
| 2344 | |
---|
| 2345 | if (sc->sc_status.button != 0) { |
---|
| 2346 | /* Reset DOUBLE_TAP_N_DRAG if the button is pressed. */ |
---|
| 2347 | sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; |
---|
| 2348 | } else if (sc->sc_state & ATP_DOUBLE_TAP_DRAG) { |
---|
| 2349 | /* Assume a button-press with DOUBLE_TAP_N_DRAG. */ |
---|
| 2350 | sc->sc_status.button = MOUSE_BUTTON1DOWN; |
---|
| 2351 | } |
---|
| 2352 | |
---|
| 2353 | sc->sc_status.flags |= |
---|
| 2354 | sc->sc_status.button ^ sc->sc_status.obutton; |
---|
| 2355 | if (sc->sc_status.flags & MOUSE_STDBUTTONSCHANGED) { |
---|
| 2356 | DPRINTFN(ATP_LLEVEL_INFO, "button %s\n", |
---|
| 2357 | ((sc->sc_status.button & MOUSE_BUTTON1DOWN) ? |
---|
| 2358 | "pressed" : "released")); |
---|
| 2359 | } |
---|
| 2360 | |
---|
| 2361 | if (sc->sc_status.flags & (MOUSE_POSCHANGED | |
---|
| 2362 | MOUSE_STDBUTTONSCHANGED)) { |
---|
| 2363 | |
---|
| 2364 | atp_stroke_t *strokep; |
---|
| 2365 | u_int8_t n_movements = 0; |
---|
| 2366 | int dx = 0; |
---|
| 2367 | int dy = 0; |
---|
| 2368 | int dz = 0; |
---|
| 2369 | |
---|
| 2370 | TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { |
---|
| 2371 | if (strokep->flags & ATSF_ZOMBIE) |
---|
| 2372 | continue; |
---|
| 2373 | |
---|
| 2374 | dx += strokep->movement_dx; |
---|
| 2375 | dy += strokep->movement_dy; |
---|
| 2376 | if (strokep->movement_dx || |
---|
| 2377 | strokep->movement_dy) |
---|
| 2378 | n_movements++; |
---|
| 2379 | } |
---|
| 2380 | |
---|
| 2381 | /* average movement if multiple strokes record motion.*/ |
---|
| 2382 | if (n_movements > 1) { |
---|
| 2383 | dx /= (int)n_movements; |
---|
| 2384 | dy /= (int)n_movements; |
---|
| 2385 | } |
---|
| 2386 | |
---|
| 2387 | /* detect multi-finger vertical scrolls */ |
---|
| 2388 | if (n_movements >= 2) { |
---|
| 2389 | boolean_t all_vertical_scrolls = true; |
---|
| 2390 | TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { |
---|
| 2391 | if (strokep->flags & ATSF_ZOMBIE) |
---|
| 2392 | continue; |
---|
| 2393 | |
---|
| 2394 | if (!atp_is_vertical_scroll(strokep)) |
---|
| 2395 | all_vertical_scrolls = false; |
---|
| 2396 | } |
---|
| 2397 | if (all_vertical_scrolls) { |
---|
| 2398 | dz = dy; |
---|
| 2399 | dy = dx = 0; |
---|
| 2400 | } |
---|
| 2401 | } |
---|
| 2402 | |
---|
| 2403 | sc->sc_status.dx += dx; |
---|
| 2404 | sc->sc_status.dy += dy; |
---|
| 2405 | sc->sc_status.dz += dz; |
---|
| 2406 | atp_add_to_queue(sc, dx, -dy, -dz, sc->sc_status.button); |
---|
| 2407 | } |
---|
| 2408 | |
---|
| 2409 | case USB_ST_SETUP: |
---|
| 2410 | tr_setup: |
---|
| 2411 | /* check if we can put more data into the FIFO */ |
---|
| 2412 | if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) != 0) { |
---|
| 2413 | usbd_xfer_set_frame_len(xfer, 0, |
---|
| 2414 | sc->sc_expected_sensor_data_len); |
---|
| 2415 | usbd_transfer_submit(xfer); |
---|
| 2416 | } |
---|
| 2417 | break; |
---|
| 2418 | |
---|
| 2419 | default: /* Error */ |
---|
| 2420 | if (error != USB_ERR_CANCELLED) { |
---|
| 2421 | /* try clear stall first */ |
---|
| 2422 | usbd_xfer_set_stall(xfer); |
---|
| 2423 | goto tr_setup; |
---|
| 2424 | } |
---|
| 2425 | break; |
---|
| 2426 | } |
---|
| 2427 | } |
---|
| 2428 | |
---|
| 2429 | static void |
---|
| 2430 | atp_start_read(struct usb_fifo *fifo) |
---|
| 2431 | { |
---|
| 2432 | struct atp_softc *sc = usb_fifo_softc(fifo); |
---|
| 2433 | int rate; |
---|
| 2434 | |
---|
| 2435 | /* Check if we should override the default polling interval */ |
---|
| 2436 | rate = sc->sc_pollrate; |
---|
| 2437 | /* Range check rate */ |
---|
| 2438 | if (rate > 1000) |
---|
| 2439 | rate = 1000; |
---|
| 2440 | /* Check for set rate */ |
---|
| 2441 | if ((rate > 0) && (sc->sc_xfer[ATP_INTR_DT] != NULL)) { |
---|
| 2442 | /* Stop current transfer, if any */ |
---|
| 2443 | usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); |
---|
| 2444 | /* Set new interval */ |
---|
| 2445 | usbd_xfer_set_interval(sc->sc_xfer[ATP_INTR_DT], 1000 / rate); |
---|
| 2446 | /* Only set pollrate once */ |
---|
| 2447 | sc->sc_pollrate = 0; |
---|
| 2448 | } |
---|
| 2449 | |
---|
| 2450 | usbd_transfer_start(sc->sc_xfer[ATP_INTR_DT]); |
---|
| 2451 | } |
---|
| 2452 | |
---|
| 2453 | static void |
---|
| 2454 | atp_stop_read(struct usb_fifo *fifo) |
---|
| 2455 | { |
---|
| 2456 | struct atp_softc *sc = usb_fifo_softc(fifo); |
---|
| 2457 | usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); |
---|
| 2458 | } |
---|
| 2459 | |
---|
| 2460 | static int |
---|
| 2461 | atp_open(struct usb_fifo *fifo, int fflags) |
---|
| 2462 | { |
---|
| 2463 | struct atp_softc *sc = usb_fifo_softc(fifo); |
---|
| 2464 | |
---|
| 2465 | /* check for duplicate open, should not happen */ |
---|
| 2466 | if (sc->sc_fflags & fflags) |
---|
| 2467 | return (EBUSY); |
---|
| 2468 | |
---|
| 2469 | /* check for first open */ |
---|
| 2470 | if (sc->sc_fflags == 0) { |
---|
| 2471 | int rc; |
---|
| 2472 | if ((rc = atp_enable(sc)) != 0) |
---|
| 2473 | return (rc); |
---|
| 2474 | } |
---|
| 2475 | |
---|
| 2476 | if (fflags & FREAD) { |
---|
| 2477 | if (usb_fifo_alloc_buffer(fifo, |
---|
| 2478 | ATP_FIFO_BUF_SIZE, ATP_FIFO_QUEUE_MAXLEN)) { |
---|
| 2479 | return (ENOMEM); |
---|
| 2480 | } |
---|
| 2481 | } |
---|
| 2482 | |
---|
| 2483 | sc->sc_fflags |= (fflags & (FREAD | FWRITE)); |
---|
| 2484 | return (0); |
---|
| 2485 | } |
---|
| 2486 | |
---|
| 2487 | static void |
---|
| 2488 | atp_close(struct usb_fifo *fifo, int fflags) |
---|
| 2489 | { |
---|
| 2490 | struct atp_softc *sc = usb_fifo_softc(fifo); |
---|
| 2491 | if (fflags & FREAD) |
---|
| 2492 | usb_fifo_free_buffer(fifo); |
---|
| 2493 | |
---|
| 2494 | sc->sc_fflags &= ~(fflags & (FREAD | FWRITE)); |
---|
| 2495 | if (sc->sc_fflags == 0) { |
---|
| 2496 | atp_disable(sc); |
---|
| 2497 | } |
---|
| 2498 | } |
---|
| 2499 | |
---|
| 2500 | static int |
---|
| 2501 | atp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) |
---|
| 2502 | { |
---|
| 2503 | struct atp_softc *sc = usb_fifo_softc(fifo); |
---|
| 2504 | mousemode_t mode; |
---|
| 2505 | int error = 0; |
---|
| 2506 | |
---|
| 2507 | mtx_lock(&sc->sc_mutex); |
---|
| 2508 | |
---|
| 2509 | switch(cmd) { |
---|
| 2510 | case MOUSE_GETHWINFO: |
---|
| 2511 | *(mousehw_t *)addr = sc->sc_hw; |
---|
| 2512 | break; |
---|
| 2513 | case MOUSE_GETMODE: |
---|
| 2514 | *(mousemode_t *)addr = sc->sc_mode; |
---|
| 2515 | break; |
---|
| 2516 | case MOUSE_SETMODE: |
---|
| 2517 | mode = *(mousemode_t *)addr; |
---|
| 2518 | |
---|
| 2519 | if (mode.level == -1) |
---|
| 2520 | /* Don't change the current setting */ |
---|
| 2521 | ; |
---|
| 2522 | else if ((mode.level < 0) || (mode.level > 1)) { |
---|
| 2523 | error = EINVAL; |
---|
| 2524 | break; |
---|
| 2525 | } |
---|
| 2526 | sc->sc_mode.level = mode.level; |
---|
| 2527 | sc->sc_pollrate = mode.rate; |
---|
| 2528 | sc->sc_hw.buttons = 3; |
---|
| 2529 | |
---|
| 2530 | if (sc->sc_mode.level == 0) { |
---|
| 2531 | sc->sc_mode.protocol = MOUSE_PROTO_MSC; |
---|
| 2532 | sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; |
---|
| 2533 | sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; |
---|
| 2534 | sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; |
---|
| 2535 | } else if (sc->sc_mode.level == 1) { |
---|
| 2536 | sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; |
---|
| 2537 | sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; |
---|
| 2538 | sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; |
---|
| 2539 | sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; |
---|
| 2540 | } |
---|
| 2541 | atp_reset_buf(sc); |
---|
| 2542 | break; |
---|
| 2543 | case MOUSE_GETLEVEL: |
---|
| 2544 | *(int *)addr = sc->sc_mode.level; |
---|
| 2545 | break; |
---|
| 2546 | case MOUSE_SETLEVEL: |
---|
| 2547 | if ((*(int *)addr < 0) || (*(int *)addr > 1)) { |
---|
| 2548 | error = EINVAL; |
---|
| 2549 | break; |
---|
| 2550 | } |
---|
| 2551 | sc->sc_mode.level = *(int *)addr; |
---|
| 2552 | sc->sc_hw.buttons = 3; |
---|
| 2553 | |
---|
| 2554 | if (sc->sc_mode.level == 0) { |
---|
| 2555 | sc->sc_mode.protocol = MOUSE_PROTO_MSC; |
---|
| 2556 | sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; |
---|
| 2557 | sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; |
---|
| 2558 | sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; |
---|
| 2559 | } else if (sc->sc_mode.level == 1) { |
---|
| 2560 | sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; |
---|
| 2561 | sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; |
---|
| 2562 | sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; |
---|
| 2563 | sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; |
---|
| 2564 | } |
---|
| 2565 | atp_reset_buf(sc); |
---|
| 2566 | break; |
---|
| 2567 | case MOUSE_GETSTATUS: { |
---|
| 2568 | mousestatus_t *status = (mousestatus_t *)addr; |
---|
| 2569 | |
---|
| 2570 | *status = sc->sc_status; |
---|
| 2571 | sc->sc_status.obutton = sc->sc_status.button; |
---|
| 2572 | sc->sc_status.button = 0; |
---|
| 2573 | sc->sc_status.dx = 0; |
---|
| 2574 | sc->sc_status.dy = 0; |
---|
| 2575 | sc->sc_status.dz = 0; |
---|
| 2576 | |
---|
| 2577 | if (status->dx || status->dy || status->dz) |
---|
| 2578 | status->flags |= MOUSE_POSCHANGED; |
---|
| 2579 | if (status->button != status->obutton) |
---|
| 2580 | status->flags |= MOUSE_BUTTONSCHANGED; |
---|
| 2581 | break; |
---|
| 2582 | } |
---|
| 2583 | |
---|
| 2584 | default: |
---|
| 2585 | error = ENOTTY; |
---|
| 2586 | break; |
---|
| 2587 | } |
---|
| 2588 | |
---|
| 2589 | mtx_unlock(&sc->sc_mutex); |
---|
| 2590 | return (error); |
---|
| 2591 | } |
---|
| 2592 | |
---|
| 2593 | static int |
---|
| 2594 | atp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS) |
---|
| 2595 | { |
---|
| 2596 | int error; |
---|
| 2597 | u_int tmp; |
---|
| 2598 | |
---|
| 2599 | tmp = atp_mickeys_scale_factor; |
---|
| 2600 | error = sysctl_handle_int(oidp, &tmp, 0, req); |
---|
| 2601 | if (error != 0 || req->newptr == NULL) |
---|
| 2602 | return (error); |
---|
| 2603 | |
---|
| 2604 | if (tmp == atp_mickeys_scale_factor) |
---|
| 2605 | return (0); /* no change */ |
---|
| 2606 | if ((tmp == 0) || (tmp > (10 * ATP_SCALE_FACTOR))) |
---|
| 2607 | return (EINVAL); |
---|
| 2608 | |
---|
| 2609 | atp_mickeys_scale_factor = tmp; |
---|
| 2610 | DPRINTFN(ATP_LLEVEL_INFO, "%s: resetting mickeys_scale_factor to %u\n", |
---|
| 2611 | ATP_DRIVER_NAME, tmp); |
---|
| 2612 | |
---|
| 2613 | return (0); |
---|
| 2614 | } |
---|
| 2615 | |
---|
| 2616 | static devclass_t atp_devclass; |
---|
| 2617 | |
---|
| 2618 | static device_method_t atp_methods[] = { |
---|
| 2619 | DEVMETHOD(device_probe, atp_probe), |
---|
| 2620 | DEVMETHOD(device_attach, atp_attach), |
---|
| 2621 | DEVMETHOD(device_detach, atp_detach), |
---|
| 2622 | |
---|
| 2623 | DEVMETHOD_END |
---|
| 2624 | }; |
---|
| 2625 | |
---|
| 2626 | static driver_t atp_driver = { |
---|
| 2627 | .name = ATP_DRIVER_NAME, |
---|
| 2628 | .methods = atp_methods, |
---|
| 2629 | .size = sizeof(struct atp_softc) |
---|
| 2630 | }; |
---|
| 2631 | |
---|
| 2632 | DRIVER_MODULE(atp, uhub, atp_driver, atp_devclass, NULL, 0); |
---|
| 2633 | MODULE_DEPEND(atp, usb, 1, 1, 1); |
---|
| 2634 | MODULE_VERSION(atp, 1); |
---|
| 2635 | USB_PNP_HOST_INFO(fg_devs); |
---|
| 2636 | USB_PNP_HOST_INFO(wsp_devs); |
---|