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