2 * Copyright (c) 2009 Rohit Grover
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
36 #include <sys/mutex.h>
39 #include <sys/fcntl.h>
41 #include <sys/selinfo.h>
43 #include <sys/sysctl.h>
46 #include <dev/usb/usb.h>
47 #include <dev/usb/usbdi.h>
48 #include <dev/usb/usbdi_util.h>
49 #include <dev/usb/usbhid.h>
52 #define USB_DEBUG_VAR atp_debug
53 #include <dev/usb/usb_debug.h>
55 #include <sys/mouse.h>
57 #define ATP_DRIVER_NAME "atp"
60 * Driver specific options: the following options may be set by
61 * `options' statements in the kernel configuration file.
64 /* The multiplier used to translate sensor reported positions to mickeys. */
65 #ifndef ATP_SCALE_FACTOR
66 #define ATP_SCALE_FACTOR 48
70 * This is the age (in microseconds) beyond which a touch is
71 * considered to be a slide; and therefore a tap event isn't registered.
73 #ifndef ATP_TOUCH_TIMEOUT
74 #define ATP_TOUCH_TIMEOUT 125000
78 * A double-tap followed by a single-finger slide is treated as a
79 * special gesture. The driver responds to this gesture by assuming a
80 * virtual button-press for the lifetime of the slide. The following
81 * threshold is the maximum time gap (in microseconds) between the two
82 * tap events preceding the slide for such a gesture.
84 #ifndef ATP_DOUBLE_TAP_N_DRAG_THRESHOLD
85 #define ATP_DOUBLE_TAP_N_DRAG_THRESHOLD 200000
89 * The device provides us only with pressure readings from an array of
90 * X and Y sensors; for our algorithms, we need to interpret groups
91 * (typically pairs) of X and Y readings as being related to a single
92 * finger stroke. We can relate X and Y readings based on their times
93 * of incidence. The coincidence window should be at least 10000us
94 * since it is used against values from getmicrotime(), which has a
95 * precision of around 10ms.
97 #ifndef ATP_COINCIDENCE_THRESHOLD
98 #define ATP_COINCIDENCE_THRESHOLD 40000 /* unit: microseconds */
99 #if ATP_COINCIDENCE_THRESHOLD > 100000
100 #error "ATP_COINCIDENCE_THRESHOLD too large"
102 #endif /* #ifndef ATP_COINCIDENCE_THRESHOLD */
105 * The wait duration (in microseconds) after losing a touch contact
106 * before zombied strokes are reaped and turned into button events.
108 #define ATP_ZOMBIE_STROKE_REAP_WINDOW 50000
109 #if ATP_ZOMBIE_STROKE_REAP_WINDOW > 100000
110 #error "ATP_ZOMBIE_STROKE_REAP_WINDOW too large"
113 /* end of driver specific options */
117 static SYSCTL_NODE(_hw_usb, OID_AUTO, atp, CTLFLAG_RW, 0, "USB atp");
121 ATP_LLEVEL_DISABLED = 0,
123 ATP_LLEVEL_DEBUG, /* for troubleshooting */
124 ATP_LLEVEL_INFO, /* for diagnostics */
126 static int atp_debug = ATP_LLEVEL_ERROR; /* the default is to only log errors */
127 SYSCTL_INT(_hw_usb_atp, OID_AUTO, debug, CTLFLAG_RW,
128 &atp_debug, ATP_LLEVEL_ERROR, "ATP debug level");
129 #endif /* USB_DEBUG */
131 static u_int atp_touch_timeout = ATP_TOUCH_TIMEOUT;
132 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, touch_timeout, CTLFLAG_RW,
133 &atp_touch_timeout, 125000, "age threshold (in micros) for a touch");
135 static u_int atp_double_tap_threshold = ATP_DOUBLE_TAP_N_DRAG_THRESHOLD;
136 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, double_tap_threshold, CTLFLAG_RW,
137 &atp_double_tap_threshold, ATP_DOUBLE_TAP_N_DRAG_THRESHOLD,
138 "maximum time (in micros) between a double-tap");
140 static u_int atp_mickeys_scale_factor = ATP_SCALE_FACTOR;
141 static int atp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS);
142 SYSCTL_PROC(_hw_usb_atp, OID_AUTO, scale_factor, CTLTYPE_UINT | CTLFLAG_RW,
143 &atp_mickeys_scale_factor, sizeof(atp_mickeys_scale_factor),
144 atp_sysctl_scale_factor_handler, "IU", "movement scale factor");
146 static u_int atp_small_movement_threshold = ATP_SCALE_FACTOR >> 3;
147 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, small_movement, CTLFLAG_RW,
148 &atp_small_movement_threshold, ATP_SCALE_FACTOR >> 3,
149 "the small movement black-hole for filtering noise");
151 * The movement threshold for a stroke; this is the maximum difference
152 * in position which will be resolved as a continuation of a stroke
155 static u_int atp_max_delta_mickeys = ((3 * ATP_SCALE_FACTOR) >> 1);
156 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, max_delta_mickeys, CTLFLAG_RW,
157 &atp_max_delta_mickeys, ((3 * ATP_SCALE_FACTOR) >> 1),
158 "max. mickeys-delta which will match against an existing stroke");
160 * Strokes which accumulate at least this amount of absolute movement
161 * from the aggregate of their components are considered as
162 * slides. Unit: mickeys.
164 static u_int atp_slide_min_movement = (ATP_SCALE_FACTOR >> 3);
165 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, slide_min_movement, CTLFLAG_RW,
166 &atp_slide_min_movement, (ATP_SCALE_FACTOR >> 3),
167 "strokes with at least this amt. of movement are considered slides");
170 * The minimum age of a stroke for it to be considered mature; this
171 * helps filter movements (noise) from immature strokes. Units: interrupts.
173 static u_int atp_stroke_maturity_threshold = 2;
174 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, stroke_maturity_threshold, CTLFLAG_RW,
175 &atp_stroke_maturity_threshold, 2,
176 "the minimum age of a stroke for it to be considered mature");
178 /* Accept pressure readings from sensors only if above this value. */
179 static u_int atp_sensor_noise_threshold = 2;
180 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, sensor_noise_threshold, CTLFLAG_RW,
181 &atp_sensor_noise_threshold, 2,
182 "accept pressure readings from sensors only if above this value");
184 /* Ignore pressure spans with cumulative press. below this value. */
185 static u_int atp_pspan_min_cum_pressure = 10;
186 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, pspan_min_cum_pressure, CTLFLAG_RW,
187 &atp_pspan_min_cum_pressure, 10,
188 "ignore pressure spans with cumulative press. below this value");
190 /* Maximum allowed width for pressure-spans.*/
191 static u_int atp_pspan_max_width = 4;
192 SYSCTL_UINT(_hw_usb_atp, OID_AUTO, pspan_max_width, CTLFLAG_RW,
193 &atp_pspan_max_width, 4,
194 "maximum allowed width (in sensors) for pressure-spans");
196 /* We support three payload protocols */
203 /* Define the various flavours of devices supported by this driver. */
206 ATP_DEV_PARAMS_PBOOK,
207 ATP_DEV_PARAMS_PBOOK_15A,
208 ATP_DEV_PARAMS_PBOOK_17,
211 struct atp_dev_params {
212 u_int data_len; /* for sensor data */
216 } atp_dev_params[ATP_N_DEV_PARAMS] = {
217 [ATP_DEV_PARAMS_0] = {
221 .prot = ATP_PROT_GEYSER3
223 [ATP_DEV_PARAMS_PBOOK] = {
227 .prot = ATP_PROT_GEYSER1
229 [ATP_DEV_PARAMS_PBOOK_15A] = {
233 .prot = ATP_PROT_GEYSER2
235 [ATP_DEV_PARAMS_PBOOK_17] = {
239 .prot = ATP_PROT_GEYSER1
243 static const STRUCT_USB_HOST_ID atp_devs[] = {
244 /* Core Duo MacBook & MacBook Pro */
245 { USB_VPI(USB_VENDOR_APPLE, 0x0217, ATP_DEV_PARAMS_0) },
246 { USB_VPI(USB_VENDOR_APPLE, 0x0218, ATP_DEV_PARAMS_0) },
247 { USB_VPI(USB_VENDOR_APPLE, 0x0219, ATP_DEV_PARAMS_0) },
249 /* Core2 Duo MacBook & MacBook Pro */
250 { USB_VPI(USB_VENDOR_APPLE, 0x021a, ATP_DEV_PARAMS_0) },
251 { USB_VPI(USB_VENDOR_APPLE, 0x021b, ATP_DEV_PARAMS_0) },
252 { USB_VPI(USB_VENDOR_APPLE, 0x021c, ATP_DEV_PARAMS_0) },
254 /* Core2 Duo MacBook3,1 */
255 { USB_VPI(USB_VENDOR_APPLE, 0x0229, ATP_DEV_PARAMS_0) },
256 { USB_VPI(USB_VENDOR_APPLE, 0x022a, ATP_DEV_PARAMS_0) },
257 { USB_VPI(USB_VENDOR_APPLE, 0x022b, ATP_DEV_PARAMS_0) },
259 /* 12 inch PowerBook and iBook */
260 { USB_VPI(USB_VENDOR_APPLE, 0x030a, ATP_DEV_PARAMS_PBOOK) },
261 { USB_VPI(USB_VENDOR_APPLE, 0x030b, ATP_DEV_PARAMS_PBOOK) },
263 /* 15 inch PowerBook */
264 { USB_VPI(USB_VENDOR_APPLE, 0x020e, ATP_DEV_PARAMS_PBOOK) },
265 { USB_VPI(USB_VENDOR_APPLE, 0x020f, ATP_DEV_PARAMS_PBOOK) },
266 { USB_VPI(USB_VENDOR_APPLE, 0x0215, ATP_DEV_PARAMS_PBOOK_15A) },
268 /* 17 inch PowerBook */
269 { USB_VPI(USB_VENDOR_APPLE, 0x020d, ATP_DEV_PARAMS_PBOOK_17) },
274 * The following structure captures the state of a pressure span along
275 * an axis. Each contact with the touchpad results in separate
276 * pressure spans along the two axes.
278 typedef struct atp_pspan {
279 u_int width; /* in units of sensors */
280 u_int cum; /* cumulative compression (from all sensors) */
281 u_int cog; /* center of gravity */
282 u_int loc; /* location (scaled using the mickeys factor) */
283 boolean_t matched; /* to track pspans as they match against strokes. */
286 typedef enum atp_stroke_type {
291 #define ATP_MAX_PSPANS_PER_AXIS 3
293 typedef struct atp_stroke_component {
294 /* Fields encapsulating the pressure-span. */
295 u_int loc; /* location (scaled) */
296 u_int cum_pressure; /* cumulative compression */
297 u_int max_cum_pressure; /* max cumulative compression */
298 boolean_t matched; /*to track components as they match against pspans.*/
300 /* Fields containing information about movement. */
301 int delta_mickeys; /* change in location (un-smoothened movement)*/
302 int pending; /* cum. of pending short movements */
303 int movement; /* current smoothened movement */
304 } atp_stroke_component;
306 typedef enum atp_axis {
311 #define ATP_MAX_STROKES (2 * ATP_MAX_PSPANS_PER_AXIS)
314 * The following structure captures a finger contact with the
315 * touchpad. A stroke comprises two p-span components and some state.
317 typedef struct atp_stroke {
318 atp_stroke_type type;
319 struct timeval ctime; /* create time; for coincident siblings. */
321 * Unit: interrupts; we maintain
322 * this value in addition to
323 * 'ctime' in order to avoid the
324 * expensive call to microtime()
325 * at every interrupt.
328 atp_stroke_component components[2];
329 u_int velocity_squared; /*
330 * Average magnitude (squared)
331 * of recent velocity.
333 u_int cum_movement; /* cum. absolute movement so far */
335 uint32_t flags; /* the state of this stroke */
336 #define ATSF_ZOMBIE 0x1
339 #define ATP_FIFO_BUF_SIZE 8 /* bytes */
340 #define ATP_FIFO_QUEUE_MAXLEN 50 /* units */
350 struct usb_device *sc_usb_device;
351 #define MODE_LENGTH 8
352 char sc_mode_bytes[MODE_LENGTH]; /* device mode */
353 struct mtx sc_mutex; /* for synchronization */
354 struct usb_xfer *sc_xfer[ATP_N_TRANSFER];
355 struct usb_fifo_sc sc_fifo;
357 struct atp_dev_params *sc_params;
362 mousestatus_t sc_status;
364 #define ATP_ENABLED 0x01
365 #define ATP_ZOMBIES_EXIST 0x02
366 #define ATP_DOUBLE_TAP_DRAG 0x04
367 #define ATP_VALID 0x08
369 u_int sc_left_margin;
370 u_int sc_right_margin;
372 atp_stroke sc_strokes[ATP_MAX_STROKES];
375 int8_t *sensor_data; /* from interrupt packet */
376 int *base_x; /* base sensor readings */
378 int *cur_x; /* current sensor readings */
380 int *pressure_x; /* computed pressures */
383 u_int sc_idlecount; /* preceding idle interrupts */
384 #define ATP_IDLENESS_THRESHOLD 10
386 struct timeval sc_reap_time;
387 struct timeval sc_reap_ctime; /*ctime of siblings to be reaped*/
391 * The last byte of the sensor data contains status bits; the
392 * following values define the meanings of these bits.
394 enum atp_status_bits {
395 ATP_STATUS_BUTTON = (uint8_t)0x01, /* The button was pressed */
396 ATP_STATUS_BASE_UPDATE = (uint8_t)0x04, /* Data from an untouched pad.*/
399 typedef enum interface_mode {
400 RAW_SENSOR_MODE = (uint8_t)0x04,
401 HID_MODE = (uint8_t)0x08
405 * function prototypes
407 static usb_fifo_cmd_t atp_start_read;
408 static usb_fifo_cmd_t atp_stop_read;
409 static usb_fifo_open_t atp_open;
410 static usb_fifo_close_t atp_close;
411 static usb_fifo_ioctl_t atp_ioctl;
413 static struct usb_fifo_methods atp_fifo_methods = {
415 .f_close = &atp_close,
416 .f_ioctl = &atp_ioctl,
417 .f_start_read = &atp_start_read,
418 .f_stop_read = &atp_stop_read,
419 .basename[0] = ATP_DRIVER_NAME,
422 /* device initialization and shutdown */
423 static usb_error_t atp_req_get_report(struct usb_device *udev, void *data);
424 static int atp_set_device_mode(device_t dev, interface_mode mode);
425 static void atp_reset_callback(struct usb_xfer *, usb_error_t);
426 static int atp_enable(struct atp_softc *sc);
427 static void atp_disable(struct atp_softc *sc);
428 static int atp_softc_populate(struct atp_softc *);
429 static void atp_softc_unpopulate(struct atp_softc *);
431 /* sensor interpretation */
432 static __inline void atp_interpret_sensor_data(const int8_t *, u_int, atp_axis,
433 int *, atp_protocol);
434 static __inline void atp_get_pressures(int *, const int *, const int *, int);
435 static void atp_detect_pspans(int *, u_int, u_int, atp_pspan *,
438 /* movement detection */
439 static boolean_t atp_match_stroke_component(atp_stroke_component *,
440 const atp_pspan *, atp_stroke_type);
441 static void atp_match_strokes_against_pspans(struct atp_softc *,
442 atp_axis, atp_pspan *, u_int, u_int);
443 static boolean_t atp_update_strokes(struct atp_softc *,
444 atp_pspan *, u_int, atp_pspan *, u_int);
445 static __inline void atp_add_stroke(struct atp_softc *, const atp_pspan *,
447 static void atp_add_new_strokes(struct atp_softc *, atp_pspan *,
448 u_int, atp_pspan *, u_int);
449 static void atp_advance_stroke_state(struct atp_softc *,
450 atp_stroke *, boolean_t *);
451 static void atp_terminate_stroke(struct atp_softc *, u_int);
452 static __inline boolean_t atp_stroke_has_small_movement(const atp_stroke *);
453 static __inline void atp_update_pending_mickeys(atp_stroke_component *);
454 static void atp_compute_smoothening_scale_ratio(atp_stroke *, int *,
456 static boolean_t atp_compute_stroke_movement(atp_stroke *);
459 static __inline void atp_setup_reap_time(struct atp_softc *, struct timeval *);
460 static void atp_reap_zombies(struct atp_softc *, u_int *, u_int *);
461 static void atp_convert_to_slide(struct atp_softc *, atp_stroke *);
464 static void atp_reset_buf(struct atp_softc *sc);
465 static void atp_add_to_queue(struct atp_softc *, int, int, uint32_t);
469 atp_req_get_report(struct usb_device *udev, void *data)
471 struct usb_device_request req;
473 req.bmRequestType = UT_READ_CLASS_INTERFACE;
474 req.bRequest = UR_GET_REPORT;
475 USETW2(req.wValue, (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */);
476 USETW(req.wIndex, 0);
477 USETW(req.wLength, MODE_LENGTH);
479 return (usbd_do_request(udev, NULL /* mutex */, &req, data));
483 atp_set_device_mode(device_t dev, interface_mode mode)
485 struct atp_softc *sc;
486 usb_device_request_t req;
489 if ((mode != RAW_SENSOR_MODE) && (mode != HID_MODE))
492 sc = device_get_softc(dev);
494 sc->sc_mode_bytes[0] = mode;
495 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
496 req.bRequest = UR_SET_REPORT;
497 USETW2(req.wValue, (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */);
498 USETW(req.wIndex, 0);
499 USETW(req.wLength, MODE_LENGTH);
500 err = usbd_do_request(sc->sc_usb_device, NULL, &req, sc->sc_mode_bytes);
501 if (err != USB_ERR_NORMAL_COMPLETION)
508 atp_reset_callback(struct usb_xfer *xfer, usb_error_t error)
510 usb_device_request_t req;
511 struct usb_page_cache *pc;
512 struct atp_softc *sc = usbd_xfer_softc(xfer);
514 switch (USB_GET_STATE(xfer)) {
516 sc->sc_mode_bytes[0] = RAW_SENSOR_MODE;
517 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
518 req.bRequest = UR_SET_REPORT;
520 (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */);
521 USETW(req.wIndex, 0);
522 USETW(req.wLength, MODE_LENGTH);
524 pc = usbd_xfer_get_frame(xfer, 0);
525 usbd_copy_in(pc, 0, &req, sizeof(req));
526 pc = usbd_xfer_get_frame(xfer, 1);
527 usbd_copy_in(pc, 0, sc->sc_mode_bytes, MODE_LENGTH);
529 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
530 usbd_xfer_set_frame_len(xfer, 1, MODE_LENGTH);
531 usbd_xfer_set_frames(xfer, 2);
532 usbd_transfer_submit(xfer);
535 case USB_ST_TRANSFERRED:
542 atp_enable(struct atp_softc *sc)
544 /* Allocate the dynamic buffers */
545 if (atp_softc_populate(sc) != 0) {
546 atp_softc_unpopulate(sc);
551 memset(sc->sc_strokes, 0, sizeof(sc->sc_strokes));
552 sc->sc_n_strokes = 0;
553 memset(&sc->sc_status, 0, sizeof(sc->sc_status));
554 sc->sc_idlecount = 0;
555 sc->sc_state |= ATP_ENABLED;
557 DPRINTFN(ATP_LLEVEL_INFO, "enabled atp\n");
562 atp_disable(struct atp_softc *sc)
564 atp_softc_unpopulate(sc);
566 sc->sc_state &= ~(ATP_ENABLED | ATP_VALID);
567 DPRINTFN(ATP_LLEVEL_INFO, "disabled atp\n");
570 /* Allocate dynamic memory for some fields in softc. */
572 atp_softc_populate(struct atp_softc *sc)
574 const struct atp_dev_params *params = sc->sc_params;
576 if (params == NULL) {
577 DPRINTF("params uninitialized!\n");
580 if (params->data_len) {
581 sc->sensor_data = malloc(params->data_len * sizeof(int8_t),
583 if (sc->sensor_data == NULL) {
584 DPRINTF("mem for sensor_data\n");
589 if (params->n_xsensors != 0) {
590 sc->base_x = malloc(params->n_xsensors * sizeof(*(sc->base_x)),
592 if (sc->base_x == NULL) {
593 DPRINTF("mem for sc->base_x\n");
597 sc->cur_x = malloc(params->n_xsensors * sizeof(*(sc->cur_x)),
599 if (sc->cur_x == NULL) {
600 DPRINTF("mem for sc->cur_x\n");
605 malloc(params->n_xsensors * sizeof(*(sc->pressure_x)),
607 if (sc->pressure_x == NULL) {
608 DPRINTF("mem. for pressure_x\n");
613 if (params->n_ysensors != 0) {
614 sc->base_y = malloc(params->n_ysensors * sizeof(*(sc->base_y)),
616 if (sc->base_y == NULL) {
617 DPRINTF("mem for base_y\n");
621 sc->cur_y = malloc(params->n_ysensors * sizeof(*(sc->cur_y)),
623 if (sc->cur_y == NULL) {
624 DPRINTF("mem for cur_y\n");
629 malloc(params->n_ysensors * sizeof(*(sc->pressure_y)),
631 if (sc->pressure_y == NULL) {
632 DPRINTF("mem. for pressure_y\n");
640 /* Free dynamic memory allocated for some fields in softc. */
642 atp_softc_unpopulate(struct atp_softc *sc)
644 const struct atp_dev_params *params = sc->sc_params;
646 if (params == NULL) {
649 if (params->n_xsensors != 0) {
650 if (sc->base_x != NULL) {
651 free(sc->base_x, M_USB);
655 if (sc->cur_x != NULL) {
656 free(sc->cur_x, M_USB);
660 if (sc->pressure_x != NULL) {
661 free(sc->pressure_x, M_USB);
662 sc->pressure_x = NULL;
665 if (params->n_ysensors != 0) {
666 if (sc->base_y != NULL) {
667 free(sc->base_y, M_USB);
671 if (sc->cur_y != NULL) {
672 free(sc->cur_y, M_USB);
676 if (sc->pressure_y != NULL) {
677 free(sc->pressure_y, M_USB);
678 sc->pressure_y = NULL;
681 if (sc->sensor_data != NULL) {
682 free(sc->sensor_data, M_USB);
683 sc->sensor_data = NULL;
688 * Interpret the data from the X and Y pressure sensors. This function
689 * is called separately for the X and Y sensor arrays. The data in the
690 * USB packet is laid out in the following manner:
693 * --,--,Y1,Y2,--,Y3,Y4,--,Y5,...,Y10, ... X1,X2,--,X3,X4
694 * indices: 0 1 2 3 4 5 6 7 8 ... 15 ... 20 21 22 23 24
696 * '--' (in the above) indicates that the value is unimportant.
698 * Information about the above layout was obtained from the
699 * implementation of the AppleTouch driver in Linux.
703 * raw sensor data from the USB packet.
705 * The number of elements in the array 'arr'.
707 * Axis of data to fetch
709 * The array to be initialized with the readings.
711 * The protocol to use to interpret the data
714 atp_interpret_sensor_data(const int8_t *sensor_data, u_int num, atp_axis axis,
715 int *arr, atp_protocol prot)
718 u_int di; /* index into sensor data */
721 case ATP_PROT_GEYSER1:
723 * For Geyser 1, the sensors are laid out in pairs
726 for (i = 0, di = (axis == Y) ? 1 : 2; i < 8; di += 5, i++) {
727 arr[i] = sensor_data[di];
728 arr[i+8] = sensor_data[di+2];
729 if (axis == X && num > 16)
730 arr[i+16] = sensor_data[di+40];
734 case ATP_PROT_GEYSER2:
735 case ATP_PROT_GEYSER3:
736 for (i = 0, di = (axis == Y) ? 2 : 20; i < num; /* empty */ ) {
737 arr[i++] = sensor_data[di++];
738 arr[i++] = sensor_data[di++];
746 atp_get_pressures(int *p, const int *cur, const int *base, int n)
750 for (i = 0; i < n; i++) {
751 p[i] = cur[i] - base[i];
760 * Shave off pressures below the noise-pressure
761 * threshold; this will reduce the contribution from
762 * lower pressure readings.
764 if ((u_int)p[i] <= atp_sensor_noise_threshold)
765 p[i] = 0; /* filter away noise */
767 p[i] -= atp_sensor_noise_threshold;
772 atp_detect_pspans(int *p, u_int num_sensors,
773 u_int max_spans, /* max # of pspans permitted */
774 atp_pspan *spans, /* finger spans */
775 u_int *nspans_p) /* num spans detected */
778 int maxp; /* max pressure seen within a span */
781 enum atp_pspan_state {
783 ATP_PSPAN_INCREASING,
784 ATP_PSPAN_DECREASING,
785 } state; /* state of the pressure span */
788 * The following is a simple state machine to track
789 * the phase of the pressure span.
791 memset(spans, 0, max_spans * sizeof(atp_pspan));
793 state = ATP_PSPAN_INACTIVE;
794 for (i = 0; i < num_sensors; i++) {
795 if (num_spans >= max_spans)
799 if (state == ATP_PSPAN_INACTIVE) {
801 * There is no pressure information for this
802 * sensor, and we aren't tracking a finger.
806 state = ATP_PSPAN_INACTIVE;
812 case ATP_PSPAN_INACTIVE:
813 state = ATP_PSPAN_INCREASING;
817 case ATP_PSPAN_INCREASING:
820 else if (p[i] <= (maxp >> 1))
821 state = ATP_PSPAN_DECREASING;
824 case ATP_PSPAN_DECREASING:
825 if (p[i] > p[i - 1]) {
827 * This is the beginning of
828 * another span; change state
829 * to give the appearance that
830 * we're starting from an
831 * inactive span, and then
832 * re-process this reading in
833 * the next iteration.
836 state = ATP_PSPAN_INACTIVE;
844 /* Update the finger span with this reading. */
845 spans[num_spans].width++;
846 spans[num_spans].cum += p[i];
847 spans[num_spans].cog += p[i] * (i + 1);
850 if (state != ATP_PSPAN_INACTIVE)
851 num_spans++; /* close the last finger span */
853 /* post-process the spans */
854 for (i = 0; i < num_spans; i++) {
855 /* filter away unwanted pressure spans */
856 if ((spans[i].cum < atp_pspan_min_cum_pressure) ||
857 (spans[i].width > atp_pspan_max_width)) {
858 if ((i + 1) < num_spans) {
859 memcpy(&spans[i], &spans[i + 1],
860 (num_spans - i - 1) * sizeof(atp_pspan));
867 /* compute this span's representative location */
868 spans[i].loc = spans[i].cog * atp_mickeys_scale_factor /
871 spans[i].matched = FALSE; /* not yet matched against a stroke */
874 *nspans_p = num_spans;
878 * Match a pressure-span against a stroke-component. If there is a
879 * match, update the component's state and return TRUE.
882 atp_match_stroke_component(atp_stroke_component *component,
883 const atp_pspan *pspan, atp_stroke_type stroke_type)
888 delta_mickeys = pspan->loc - component->loc;
890 if ((u_int)abs(delta_mickeys) > atp_max_delta_mickeys)
891 return (FALSE); /* the finger span is too far out; no match */
893 component->loc = pspan->loc;
896 * A sudden and significant increase in a pspan's cumulative
897 * pressure indicates the incidence of a new finger
898 * contact. This usually revises the pspan's
899 * centre-of-gravity, and hence the location of any/all
900 * matching stroke component(s). But such a change should
901 * *not* be interpreted as a movement.
903 if (pspan->cum > ((3 * component->cum_pressure) >> 1))
906 component->cum_pressure = pspan->cum;
907 if (pspan->cum > component->max_cum_pressure)
908 component->max_cum_pressure = pspan->cum;
911 * Disregard the component's movement if its cumulative
912 * pressure drops below a fraction of the maximum; this
913 * fraction is determined based on the stroke's type.
915 if (stroke_type == ATP_STROKE_TOUCH)
916 min_pressure = (3 * component->max_cum_pressure) >> 2;
918 min_pressure = component->max_cum_pressure >> 2;
919 if (component->cum_pressure < min_pressure)
922 component->delta_mickeys = delta_mickeys;
927 atp_match_strokes_against_pspans(struct atp_softc *sc, atp_axis axis,
928 atp_pspan *pspans, u_int n_pspans, u_int repeat_count)
931 u_int repeat_index = 0;
933 /* Determine the index of the multi-span. */
936 for (i = 0; i < n_pspans; i++) {
937 if (pspans[i].cum > cum) {
944 for (i = 0; i < sc->sc_n_strokes; i++) {
945 atp_stroke *stroke = &sc->sc_strokes[i];
946 if (stroke->components[axis].matched)
947 continue; /* skip matched components */
949 for (j = 0; j < n_pspans; j++) {
950 if (pspans[j].matched)
951 continue; /* skip matched pspans */
953 if (atp_match_stroke_component(
954 &stroke->components[axis], &pspans[j],
956 /* There is a match. */
957 stroke->components[axis].matched = TRUE;
959 /* Take care to repeat at the multi-span. */
960 if ((repeat_count > 0) && (j == repeat_index))
963 pspans[j].matched = TRUE;
965 break; /* skip to the next stroke */
967 } /* loop over pspans */
968 } /* loop over strokes */
972 * Update strokes by matching against current pressure-spans.
973 * Return TRUE if any movement is detected.
976 atp_update_strokes(struct atp_softc *sc, atp_pspan *pspans_x,
977 u_int n_xpspans, atp_pspan *pspans_y, u_int n_ypspans)
981 boolean_t movement = FALSE;
982 u_int repeat_count = 0;
984 /* Reset X and Y components of all strokes as unmatched. */
985 for (i = 0; i < sc->sc_n_strokes; i++) {
986 stroke = &sc->sc_strokes[i];
987 stroke->components[X].matched = FALSE;
988 stroke->components[Y].matched = FALSE;
992 * Usually, the X and Y pspans come in pairs (the common case
993 * being a single pair). It is possible, however, that
994 * multiple contacts resolve to a single pspan along an
995 * axis, as illustrated in the following:
1000 * +-----------------------+
1005 * pspan |.........F......F |
1009 * +-----------------------+
1012 * The above case can be detected by a difference in the
1013 * number of X and Y pspans. When this happens, X and Y pspans
1014 * aren't easy to pair or match against strokes.
1016 * When X and Y pspans differ in number, the axis with the
1017 * smaller number of pspans is regarded as having a repeating
1018 * pspan (or a multi-pspan)--in the above illustration, the
1019 * Y-axis has a repeating pspan. Our approach is to try to
1020 * match the multi-pspan repeatedly against strokes. The
1021 * difference between the number of X and Y pspans gives us a
1022 * crude repeat_count for matching multi-pspans--i.e. the
1023 * multi-pspan along the Y axis (above) has a repeat_count of 1.
1025 repeat_count = abs(n_xpspans - n_ypspans);
1027 atp_match_strokes_against_pspans(sc, X, pspans_x, n_xpspans,
1028 (((repeat_count != 0) && ((n_xpspans < n_ypspans))) ?
1030 atp_match_strokes_against_pspans(sc, Y, pspans_y, n_ypspans,
1031 (((repeat_count != 0) && (n_ypspans < n_xpspans)) ?
1034 /* Update the state of strokes based on the above pspan matches. */
1035 for (i = 0; i < sc->sc_n_strokes; i++) {
1036 stroke = &sc->sc_strokes[i];
1037 if (stroke->components[X].matched &&
1038 stroke->components[Y].matched) {
1039 atp_advance_stroke_state(sc, stroke, &movement);
1042 * At least one component of this stroke
1043 * didn't match against current pspans;
1046 atp_terminate_stroke(sc, i);
1050 /* Add new strokes for pairs of unmatched pspans */
1051 for (i = 0; i < n_xpspans; i++) {
1052 if (pspans_x[i].matched == FALSE) break;
1054 for (j = 0; j < n_ypspans; j++) {
1055 if (pspans_y[j].matched == FALSE) break;
1057 if ((i < n_xpspans) && (j < n_ypspans)) {
1059 if (atp_debug >= ATP_LLEVEL_INFO) {
1060 printf("unmatched pspans:");
1061 for (; i < n_xpspans; i++) {
1062 if (pspans_x[i].matched)
1064 printf(" X:[loc:%u,cum:%u]",
1065 pspans_x[i].loc, pspans_x[i].cum);
1067 for (; j < n_ypspans; j++) {
1068 if (pspans_y[j].matched)
1070 printf(" Y:[loc:%u,cum:%u]",
1071 pspans_y[j].loc, pspans_y[j].cum);
1075 #endif /* USB_DEBUG */
1076 if ((n_xpspans == 1) && (n_ypspans == 1))
1077 /* The common case of a single pair of new pspans. */
1078 atp_add_stroke(sc, &pspans_x[0], &pspans_y[0]);
1080 atp_add_new_strokes(sc,
1081 pspans_x, n_xpspans,
1082 pspans_y, n_ypspans);
1086 if (atp_debug >= ATP_LLEVEL_INFO) {
1087 for (i = 0; i < sc->sc_n_strokes; i++) {
1088 atp_stroke *stroke = &sc->sc_strokes[i];
1090 printf(" %s%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c"
1091 ",%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c",
1092 (stroke->flags & ATSF_ZOMBIE) ? "zomb:" : "",
1093 (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<',
1094 stroke->components[X].loc,
1095 stroke->components[X].delta_mickeys,
1096 stroke->components[X].pending,
1097 stroke->components[X].cum_pressure,
1098 stroke->components[X].max_cum_pressure,
1099 stroke->components[X].movement,
1100 (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>',
1101 (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<',
1102 stroke->components[Y].loc,
1103 stroke->components[Y].delta_mickeys,
1104 stroke->components[Y].pending,
1105 stroke->components[Y].cum_pressure,
1106 stroke->components[Y].max_cum_pressure,
1107 stroke->components[Y].movement,
1108 (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>');
1110 if (sc->sc_n_strokes)
1113 #endif /* USB_DEBUG */
1118 /* Initialize a stroke using a pressure-span. */
1119 static __inline void
1120 atp_add_stroke(struct atp_softc *sc, const atp_pspan *pspan_x,
1121 const atp_pspan *pspan_y)
1125 if (sc->sc_n_strokes >= ATP_MAX_STROKES)
1127 stroke = &sc->sc_strokes[sc->sc_n_strokes];
1129 memset(stroke, 0, sizeof(atp_stroke));
1132 * Strokes begin as potential touches. If a stroke survives
1133 * longer than a threshold, or if it records significant
1134 * cumulative movement, then it is considered a 'slide'.
1136 stroke->type = ATP_STROKE_TOUCH;
1137 microtime(&stroke->ctime);
1138 stroke->age = 1; /* Unit: interrupts */
1140 stroke->components[X].loc = pspan_x->loc;
1141 stroke->components[X].cum_pressure = pspan_x->cum;
1142 stroke->components[X].max_cum_pressure = pspan_x->cum;
1143 stroke->components[X].matched = TRUE;
1145 stroke->components[Y].loc = pspan_y->loc;
1146 stroke->components[Y].cum_pressure = pspan_y->cum;
1147 stroke->components[Y].max_cum_pressure = pspan_y->cum;
1148 stroke->components[Y].matched = TRUE;
1151 if (sc->sc_n_strokes > 1) {
1152 /* Reset double-tap-n-drag if we have more than one strokes. */
1153 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG;
1156 DPRINTFN(ATP_LLEVEL_INFO, "[%u,%u], time: %u,%ld\n",
1157 stroke->components[X].loc,
1158 stroke->components[Y].loc,
1159 (unsigned int)stroke->ctime.tv_sec,
1160 (unsigned long int)stroke->ctime.tv_usec);
1164 atp_add_new_strokes(struct atp_softc *sc, atp_pspan *pspans_x,
1165 u_int n_xpspans, atp_pspan *pspans_y, u_int n_ypspans)
1167 atp_pspan spans[2][ATP_MAX_PSPANS_PER_AXIS];
1172 /* Copy unmatched pspans into the local arrays. */
1173 for (i = 0, nspans[X] = 0; i < n_xpspans; i++) {
1174 if (pspans_x[i].matched == FALSE) {
1175 spans[X][nspans[X]] = pspans_x[i];
1179 for (j = 0, nspans[Y] = 0; j < n_ypspans; j++) {
1180 if (pspans_y[j].matched == FALSE) {
1181 spans[Y][nspans[Y]] = pspans_y[j];
1186 if (nspans[X] == nspans[Y]) {
1187 /* Create new strokes from pairs of unmatched pspans */
1188 for (i = 0, j = 0; (i < nspans[X]) && (j < nspans[Y]); i++, j++)
1189 atp_add_stroke(sc, &spans[X][i], &spans[Y][j]);
1192 atp_axis repeat_axis; /* axis with multi-pspans */
1193 u_int repeat_count; /* repeat count for the multi-pspan*/
1194 u_int repeat_index = 0; /* index of the multi-span */
1196 repeat_axis = (nspans[X] > nspans[Y]) ? Y : X;
1197 repeat_count = abs(nspans[X] - nspans[Y]);
1198 for (i = 0; i < nspans[repeat_axis]; i++) {
1199 if (spans[repeat_axis][i].cum > cum) {
1201 cum = spans[repeat_axis][i].cum;
1205 /* Create new strokes from pairs of unmatched pspans */
1207 for (; (i < nspans[X]) && (j < nspans[Y]); i++, j++) {
1208 atp_add_stroke(sc, &spans[X][i], &spans[Y][j]);
1210 /* Take care to repeat at the multi-pspan. */
1211 if (repeat_count > 0) {
1212 if ((repeat_axis == X) &&
1213 (repeat_index == i)) {
1214 i--; /* counter loop increment */
1216 } else if ((repeat_axis == Y) &&
1217 (repeat_index == j)) {
1218 j--; /* counter loop increment */
1227 * Advance the state of this stroke--and update the out-parameter
1228 * 'movement' as a side-effect.
1231 atp_advance_stroke_state(struct atp_softc *sc, atp_stroke *stroke,
1232 boolean_t *movement)
1235 if (stroke->age <= atp_stroke_maturity_threshold) {
1236 /* Avoid noise from immature strokes. */
1237 stroke->components[X].delta_mickeys = 0;
1238 stroke->components[Y].delta_mickeys = 0;
1241 /* Revitalize stroke if it had previously been marked as a zombie. */
1242 if (stroke->flags & ATSF_ZOMBIE)
1243 stroke->flags &= ~ATSF_ZOMBIE;
1245 if (atp_compute_stroke_movement(stroke))
1248 if (stroke->type != ATP_STROKE_TOUCH)
1251 /* Convert touch strokes to slides upon detecting movement or age. */
1252 if (stroke->cum_movement >= atp_slide_min_movement) {
1253 atp_convert_to_slide(sc, stroke);
1255 /* If a touch stroke is found to be older than the
1256 * touch-timeout threshold, it should be converted to
1257 * a slide; except if there is a co-incident sibling
1258 * with a later creation time.
1260 * When multiple fingers make contact with the
1261 * touchpad, they are likely to be separated in their
1262 * times of incidence. During a multi-finger tap,
1263 * therefore, the last finger to make
1264 * contact--i.e. the one with the latest
1265 * 'ctime'--should be used to determine how the
1266 * touch-siblings get treated; otherwise older
1267 * siblings may lapse the touch-timeout and get
1268 * converted into slides prematurely. The following
1269 * loop determines if there exists another touch
1270 * stroke with a larger 'ctime' than the current
1271 * stroke (NOTE: zombies with a larger 'ctime' are
1272 * also considered) .
1276 for (i = 0; i < sc->sc_n_strokes; i++) {
1277 if ((&sc->sc_strokes[i] == stroke) ||
1278 (sc->sc_strokes[i].type != ATP_STROKE_TOUCH))
1281 if (timevalcmp(&sc->sc_strokes[i].ctime,
1285 if (i == sc->sc_n_strokes) {
1286 /* Found no other touch stroke with a larger 'ctime'. */
1287 struct timeval tdiff;
1289 /* Compute the stroke's age. */
1290 getmicrotime(&tdiff);
1291 if (timevalcmp(&tdiff, &stroke->ctime, >))
1292 timevalsub(&tdiff, &stroke->ctime);
1295 * If we are here, it is because getmicrotime
1296 * reported the current time as being behind
1297 * the stroke's start time; getmicrotime can
1304 if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) ||
1305 ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) &&
1307 (atp_touch_timeout % 1000000))))
1308 atp_convert_to_slide(sc, stroke);
1313 /* Switch a given touch stroke to being a slide. */
1315 atp_convert_to_slide(struct atp_softc *sc, atp_stroke *stroke)
1317 stroke->type = ATP_STROKE_SLIDE;
1319 /* Are we at the beginning of a double-click-n-drag? */
1320 if ((sc->sc_n_strokes == 1) &&
1321 ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) &&
1322 timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) {
1323 struct timeval delta;
1324 struct timeval window = {
1325 atp_double_tap_threshold / 1000000,
1326 atp_double_tap_threshold % 1000000
1329 delta = stroke->ctime;
1330 timevalsub(&delta, &sc->sc_reap_time);
1331 if (timevalcmp(&delta, &window, <=))
1332 sc->sc_state |= ATP_DOUBLE_TAP_DRAG;
1337 * Terminate a stroke. While SLIDE strokes are dropped, TOUCH strokes
1338 * are retained as zombies so as to reap all their siblings together;
1339 * this helps establish the number of fingers involved in the tap.
1342 atp_terminate_stroke(struct atp_softc *sc,
1343 u_int index) /* index of the stroke to be terminated */
1345 atp_stroke *s = &sc->sc_strokes[index];
1347 if (s->flags & ATSF_ZOMBIE) {
1351 if ((s->type == ATP_STROKE_TOUCH) &&
1352 (s->age > atp_stroke_maturity_threshold)) {
1353 s->flags |= ATSF_ZOMBIE;
1355 /* If no zombies exist, then prepare to reap zombies later. */
1356 if ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) {
1357 atp_setup_reap_time(sc, &s->ctime);
1358 sc->sc_state |= ATP_ZOMBIES_EXIST;
1361 /* Drop this stroke. */
1362 memcpy(&sc->sc_strokes[index], &sc->sc_strokes[index + 1],
1363 (sc->sc_n_strokes - index - 1) * sizeof(atp_stroke));
1367 * Reset the double-click-n-drag at the termination of
1370 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG;
1374 static __inline boolean_t
1375 atp_stroke_has_small_movement(const atp_stroke *stroke)
1377 return (((u_int)abs(stroke->components[X].delta_mickeys) <=
1378 atp_small_movement_threshold) &&
1379 ((u_int)abs(stroke->components[Y].delta_mickeys) <=
1380 atp_small_movement_threshold));
1384 * Accumulate delta_mickeys into the component's 'pending' bucket; if
1385 * the aggregate exceeds the small_movement_threshold, then retain
1386 * delta_mickeys for later.
1388 static __inline void
1389 atp_update_pending_mickeys(atp_stroke_component *component)
1391 component->pending += component->delta_mickeys;
1392 if ((u_int)abs(component->pending) <= atp_small_movement_threshold)
1393 component->delta_mickeys = 0;
1396 * Penalise pending mickeys for having accumulated
1397 * over short deltas. This operation has the effect of
1398 * scaling down the cumulative contribution of short
1401 component->pending -= (component->delta_mickeys << 1);
1407 atp_compute_smoothening_scale_ratio(atp_stroke *stroke, int *numerator,
1412 u_int vel_squared; /* Square of the velocity vector's magnitude. */
1413 u_int vel_squared_smooth;
1415 /* Table holding (10 * sqrt(x)) for x between 1 and 256. */
1416 static uint8_t sqrt_table[256] = {
1417 10, 14, 17, 20, 22, 24, 26, 28,
1418 30, 31, 33, 34, 36, 37, 38, 40,
1419 41, 42, 43, 44, 45, 46, 47, 48,
1420 50, 50, 51, 52, 53, 54, 55, 56,
1421 57, 58, 59, 60, 60, 61, 62, 63,
1422 64, 64, 65, 66, 67, 67, 68, 69,
1423 70, 70, 71, 72, 72, 73, 74, 74,
1424 75, 76, 76, 77, 78, 78, 79, 80,
1425 80, 81, 81, 82, 83, 83, 84, 84,
1426 85, 86, 86, 87, 87, 88, 88, 89,
1427 90, 90, 91, 91, 92, 92, 93, 93,
1428 94, 94, 95, 95, 96, 96, 97, 97,
1429 98, 98, 99, 100, 100, 100, 101, 101,
1430 102, 102, 103, 103, 104, 104, 105, 105,
1431 106, 106, 107, 107, 108, 108, 109, 109,
1432 110, 110, 110, 111, 111, 112, 112, 113,
1433 113, 114, 114, 114, 115, 115, 116, 116,
1434 117, 117, 117, 118, 118, 119, 119, 120,
1435 120, 120, 121, 121, 122, 122, 122, 123,
1436 123, 124, 124, 124, 125, 125, 126, 126,
1437 126, 127, 127, 128, 128, 128, 129, 129,
1438 130, 130, 130, 131, 131, 131, 132, 132,
1439 133, 133, 133, 134, 134, 134, 135, 135,
1440 136, 136, 136, 137, 137, 137, 138, 138,
1441 138, 139, 139, 140, 140, 140, 141, 141,
1442 141, 142, 142, 142, 143, 143, 143, 144,
1443 144, 144, 145, 145, 145, 146, 146, 146,
1444 147, 147, 147, 148, 148, 148, 149, 149,
1445 150, 150, 150, 150, 151, 151, 151, 152,
1446 152, 152, 153, 153, 153, 154, 154, 154,
1447 155, 155, 155, 156, 156, 156, 157, 157,
1448 157, 158, 158, 158, 159, 159, 159, 160
1450 const u_int N = sizeof(sqrt_table) / sizeof(sqrt_table[0]);
1452 dxdt = stroke->components[X].delta_mickeys;
1453 dydt = stroke->components[Y].delta_mickeys;
1455 *numerator = 0, *denominator = 0; /* default values. */
1457 /* Compute a smoothened magnitude_squared of the stroke's velocity. */
1458 vel_squared = dxdt * dxdt + dydt * dydt;
1459 vel_squared_smooth = (3 * stroke->velocity_squared + vel_squared) >> 2;
1460 stroke->velocity_squared = vel_squared_smooth; /* retained as history */
1461 if ((vel_squared == 0) || (vel_squared_smooth == 0))
1462 return; /* returning (numerator == 0) will imply zero movement*/
1465 * In order to determine the overall movement scale factor,
1466 * we're actually interested in the effect of smoothening upon
1467 * the *magnitude* of velocity; i.e. we need to compute the
1468 * square-root of (vel_squared_smooth / vel_squared) in the
1469 * form of a numerator and denominator.
1472 /* Keep within the bounds of the square-root table. */
1473 while ((vel_squared > N) || (vel_squared_smooth > N)) {
1474 /* Dividing uniformly by 2 won't disturb the final ratio. */
1476 vel_squared_smooth >>= 1;
1479 *numerator = sqrt_table[vel_squared_smooth - 1];
1480 *denominator = sqrt_table[vel_squared - 1];
1484 * Compute a smoothened value for the stroke's movement from
1485 * delta_mickeys in the X and Y components.
1488 atp_compute_stroke_movement(atp_stroke *stroke)
1490 int num; /* numerator of scale ratio */
1491 int denom; /* denominator of scale ratio */
1494 * Short movements are added first to the 'pending' bucket,
1495 * and then acted upon only when their aggregate exceeds a
1496 * threshold. This has the effect of filtering away movement
1499 if (atp_stroke_has_small_movement(stroke)) {
1500 atp_update_pending_mickeys(&stroke->components[X]);
1501 atp_update_pending_mickeys(&stroke->components[Y]);
1502 } else { /* large movement */
1503 /* clear away any pending mickeys if there are large movements*/
1504 stroke->components[X].pending = 0;
1505 stroke->components[Y].pending = 0;
1508 /* Get the scale ratio and smoothen movement. */
1509 atp_compute_smoothening_scale_ratio(stroke, &num, &denom);
1510 if ((num == 0) || (denom == 0)) {
1511 stroke->components[X].movement = 0;
1512 stroke->components[Y].movement = 0;
1513 stroke->velocity_squared >>= 1; /* Erode velocity_squared. */
1515 stroke->components[X].movement =
1516 (stroke->components[X].delta_mickeys * num) / denom;
1517 stroke->components[Y].movement =
1518 (stroke->components[Y].delta_mickeys * num) / denom;
1520 stroke->cum_movement +=
1521 abs(stroke->components[X].movement) +
1522 abs(stroke->components[Y].movement);
1525 return ((stroke->components[X].movement != 0) ||
1526 (stroke->components[Y].movement != 0));
1529 static __inline void
1530 atp_setup_reap_time(struct atp_softc *sc, struct timeval *tvp)
1532 struct timeval reap_window = {
1533 ATP_ZOMBIE_STROKE_REAP_WINDOW / 1000000,
1534 ATP_ZOMBIE_STROKE_REAP_WINDOW % 1000000
1537 microtime(&sc->sc_reap_time);
1538 timevaladd(&sc->sc_reap_time, &reap_window);
1540 sc->sc_reap_ctime = *tvp; /* ctime to reap */
1544 atp_reap_zombies(struct atp_softc *sc, u_int *n_reaped, u_int *reaped_xlocs)
1550 for (i = 0; i < sc->sc_n_strokes; i++) {
1551 struct timeval tdiff;
1553 stroke = &sc->sc_strokes[i];
1555 if ((stroke->flags & ATSF_ZOMBIE) == 0)
1558 /* Compare this stroke's ctime with the ctime being reaped. */
1559 if (timevalcmp(&stroke->ctime, &sc->sc_reap_ctime, >=)) {
1560 tdiff = stroke->ctime;
1561 timevalsub(&tdiff, &sc->sc_reap_ctime);
1563 tdiff = sc->sc_reap_ctime;
1564 timevalsub(&tdiff, &stroke->ctime);
1567 if ((tdiff.tv_sec > (ATP_COINCIDENCE_THRESHOLD / 1000000)) ||
1568 ((tdiff.tv_sec == (ATP_COINCIDENCE_THRESHOLD / 1000000)) &&
1569 (tdiff.tv_usec > (ATP_COINCIDENCE_THRESHOLD % 1000000)))) {
1570 continue; /* Skip non-siblings. */
1574 * Reap this sibling zombie stroke.
1577 if (reaped_xlocs != NULL)
1578 reaped_xlocs[*n_reaped] = stroke->components[X].loc;
1580 /* Erase the stroke from the sc. */
1581 memcpy(&stroke[i], &stroke[i + 1],
1582 (sc->sc_n_strokes - i - 1) * sizeof(atp_stroke));
1586 --i; /* Decr. i to keep it unchanged for the next iteration */
1589 DPRINTFN(ATP_LLEVEL_INFO, "reaped %u zombies\n", *n_reaped);
1591 /* There could still be zombies remaining in the system. */
1592 for (i = 0; i < sc->sc_n_strokes; i++) {
1593 stroke = &sc->sc_strokes[i];
1594 if (stroke->flags & ATSF_ZOMBIE) {
1595 DPRINTFN(ATP_LLEVEL_INFO, "zombies remain!\n");
1596 atp_setup_reap_time(sc, &stroke->ctime);
1601 /* If we reach here, then no more zombies remain. */
1602 sc->sc_state &= ~ATP_ZOMBIES_EXIST;
1606 /* Device methods. */
1607 static device_probe_t atp_probe;
1608 static device_attach_t atp_attach;
1609 static device_detach_t atp_detach;
1610 static usb_callback_t atp_intr;
1612 static const struct usb_config atp_config[ATP_N_TRANSFER] = {
1614 .type = UE_INTERRUPT,
1615 .endpoint = UE_ADDR_ANY,
1616 .direction = UE_DIR_IN,
1621 .bufsize = 0, /* use wMaxPacketSize */
1622 .callback = &atp_intr,
1626 .endpoint = 0, /* Control pipe */
1627 .direction = UE_DIR_ANY,
1628 .bufsize = sizeof(struct usb_device_request) + MODE_LENGTH,
1629 .callback = &atp_reset_callback,
1630 .interval = 0, /* no pre-delay */
1635 atp_probe(device_t self)
1637 struct usb_attach_arg *uaa = device_get_ivars(self);
1639 if (uaa->usb_mode != USB_MODE_HOST)
1642 if ((uaa->info.bInterfaceClass != UICLASS_HID) ||
1643 (uaa->info.bInterfaceProtocol != UIPROTO_MOUSE))
1646 return (usbd_lookup_id_by_uaa(atp_devs, sizeof(atp_devs), uaa));
1650 atp_attach(device_t dev)
1652 struct atp_softc *sc = device_get_softc(dev);
1653 struct usb_attach_arg *uaa = device_get_ivars(dev);
1656 DPRINTFN(ATP_LLEVEL_INFO, "sc=%p\n", sc);
1659 sc->sc_usb_device = uaa->device;
1662 * By default the touchpad behaves like an HID device, sending
1663 * packets with reportID = 2. Such reports contain only
1664 * limited information--they encode movement deltas and button
1665 * events,--but do not include data from the pressure
1666 * sensors. The device input mode can be switched from HID
1667 * reports to raw sensor data using vendor-specific USB
1668 * control commands; but first the mode must be read.
1670 err = atp_req_get_report(sc->sc_usb_device, sc->sc_mode_bytes);
1671 if (err != USB_ERR_NORMAL_COMPLETION) {
1672 DPRINTF("failed to read device mode (%d)\n", err);
1676 if (atp_set_device_mode(dev, RAW_SENSOR_MODE) != 0) {
1677 DPRINTF("failed to set mode to 'RAW_SENSOR' (%d)\n", err);
1681 mtx_init(&sc->sc_mutex, "atpmtx", NULL, MTX_DEF | MTX_RECURSE);
1683 err = usbd_transfer_setup(uaa->device,
1684 &uaa->info.bIfaceIndex, sc->sc_xfer, atp_config,
1685 ATP_N_TRANSFER, sc, &sc->sc_mutex);
1688 DPRINTF("error=%s\n", usbd_errstr(err));
1692 if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex,
1693 &atp_fifo_methods, &sc->sc_fifo,
1694 device_get_unit(dev), -1, uaa->info.bIfaceIndex,
1695 UID_ROOT, GID_OPERATOR, 0644)) {
1699 device_set_usb_desc(dev);
1701 sc->sc_params = &atp_dev_params[uaa->driver_info];
1703 sc->sc_hw.buttons = 3;
1704 sc->sc_hw.iftype = MOUSE_IF_USB;
1705 sc->sc_hw.type = MOUSE_PAD;
1706 sc->sc_hw.model = MOUSE_MODEL_GENERIC;
1708 sc->sc_mode.protocol = MOUSE_PROTO_MSC;
1709 sc->sc_mode.rate = -1;
1710 sc->sc_mode.resolution = MOUSE_RES_UNKNOWN;
1711 sc->sc_mode.accelfactor = 0;
1712 sc->sc_mode.level = 0;
1713 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
1714 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
1715 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
1719 sc->sc_left_margin = atp_mickeys_scale_factor;
1720 sc->sc_right_margin = (sc->sc_params->n_xsensors - 1) *
1721 atp_mickeys_scale_factor;
1731 atp_detach(device_t dev)
1733 struct atp_softc *sc;
1735 sc = device_get_softc(dev);
1736 if (sc->sc_state & ATP_ENABLED) {
1737 mtx_lock(&sc->sc_mutex);
1739 mtx_unlock(&sc->sc_mutex);
1742 usb_fifo_detach(&sc->sc_fifo);
1744 usbd_transfer_unsetup(sc->sc_xfer, ATP_N_TRANSFER);
1746 mtx_destroy(&sc->sc_mutex);
1752 atp_intr(struct usb_xfer *xfer, usb_error_t error)
1754 struct atp_softc *sc = usbd_xfer_softc(xfer);
1756 struct usb_page_cache *pc;
1757 uint8_t status_bits;
1758 atp_pspan pspans_x[ATP_MAX_PSPANS_PER_AXIS];
1759 atp_pspan pspans_y[ATP_MAX_PSPANS_PER_AXIS];
1760 u_int n_xpspans = 0, n_ypspans = 0;
1761 u_int reaped_xlocs[ATP_MAX_STROKES];
1762 u_int tap_fingers = 0;
1764 usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
1766 switch (USB_GET_STATE(xfer)) {
1767 case USB_ST_TRANSFERRED:
1768 if (len > (int)sc->sc_params->data_len) {
1769 DPRINTFN(ATP_LLEVEL_ERROR,
1770 "truncating large packet from %u to %u bytes\n",
1771 len, sc->sc_params->data_len);
1772 len = sc->sc_params->data_len;
1774 if (len < (int)sc->sc_params->data_len)
1777 pc = usbd_xfer_get_frame(xfer, 0);
1778 usbd_copy_out(pc, 0, sc->sensor_data, sc->sc_params->data_len);
1780 /* Interpret sensor data */
1781 atp_interpret_sensor_data(sc->sensor_data,
1782 sc->sc_params->n_xsensors, X, sc->cur_x,
1783 sc->sc_params->prot);
1784 atp_interpret_sensor_data(sc->sensor_data,
1785 sc->sc_params->n_ysensors, Y, sc->cur_y,
1786 sc->sc_params->prot);
1789 * If this is the initial update (from an untouched
1790 * pad), we should set the base values for the sensor
1791 * data; deltas with respect to these base values can
1792 * be used as pressure readings subsequently.
1794 status_bits = sc->sensor_data[sc->sc_params->data_len - 1];
1795 if ((sc->sc_params->prot == ATP_PROT_GEYSER3 &&
1796 (status_bits & ATP_STATUS_BASE_UPDATE)) ||
1797 !(sc->sc_state & ATP_VALID)) {
1798 memcpy(sc->base_x, sc->cur_x,
1799 sc->sc_params->n_xsensors * sizeof(*(sc->base_x)));
1800 memcpy(sc->base_y, sc->cur_y,
1801 sc->sc_params->n_ysensors * sizeof(*(sc->base_y)));
1802 sc->sc_state |= ATP_VALID;
1806 /* Get pressure readings and detect p-spans for both axes. */
1807 atp_get_pressures(sc->pressure_x, sc->cur_x, sc->base_x,
1808 sc->sc_params->n_xsensors);
1809 atp_detect_pspans(sc->pressure_x, sc->sc_params->n_xsensors,
1810 ATP_MAX_PSPANS_PER_AXIS,
1811 pspans_x, &n_xpspans);
1812 atp_get_pressures(sc->pressure_y, sc->cur_y, sc->base_y,
1813 sc->sc_params->n_ysensors);
1814 atp_detect_pspans(sc->pressure_y, sc->sc_params->n_ysensors,
1815 ATP_MAX_PSPANS_PER_AXIS,
1816 pspans_y, &n_ypspans);
1818 /* Update strokes with new pspans to detect movements. */
1819 sc->sc_status.flags &= ~MOUSE_POSCHANGED;
1820 if (atp_update_strokes(sc,
1821 pspans_x, n_xpspans,
1822 pspans_y, n_ypspans))
1823 sc->sc_status.flags |= MOUSE_POSCHANGED;
1825 /* Reap zombies if it is time. */
1826 if (sc->sc_state & ATP_ZOMBIES_EXIST) {
1830 if (timevalcmp(&now, &sc->sc_reap_time, >=))
1831 atp_reap_zombies(sc, &tap_fingers,
1835 sc->sc_status.flags &= ~MOUSE_STDBUTTONSCHANGED;
1836 sc->sc_status.obutton = sc->sc_status.button;
1838 /* Get the state of the physical buttton. */
1839 sc->sc_status.button = (status_bits & ATP_STATUS_BUTTON) ?
1840 MOUSE_BUTTON1DOWN : 0;
1841 if (sc->sc_status.button != 0) {
1842 /* Reset DOUBLE_TAP_N_DRAG if the button is pressed. */
1843 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG;
1844 } else if (sc->sc_state & ATP_DOUBLE_TAP_DRAG) {
1845 /* Assume a button-press with DOUBLE_TAP_N_DRAG. */
1846 sc->sc_status.button = MOUSE_BUTTON1DOWN;
1849 sc->sc_status.flags |=
1850 sc->sc_status.button ^ sc->sc_status.obutton;
1851 if (sc->sc_status.flags & MOUSE_STDBUTTONSCHANGED) {
1852 DPRINTFN(ATP_LLEVEL_INFO, "button %s\n",
1853 ((sc->sc_status.button & MOUSE_BUTTON1DOWN) ?
1854 "pressed" : "released"));
1855 } else if ((sc->sc_status.obutton == 0) &&
1856 (sc->sc_status.button == 0) &&
1857 (tap_fingers != 0)) {
1858 /* Ignore single-finger taps at the edges. */
1859 if ((tap_fingers == 1) &&
1860 ((reaped_xlocs[0] <= sc->sc_left_margin) ||
1861 (reaped_xlocs[0] > sc->sc_right_margin))) {
1864 DPRINTFN(ATP_LLEVEL_INFO,
1865 "tap_fingers: %u\n", tap_fingers);
1868 if (sc->sc_status.flags &
1869 (MOUSE_POSCHANGED | MOUSE_STDBUTTONSCHANGED)) {
1873 dx = 0, dy = 0, n_movements = 0;
1874 for (u_int i = 0; i < sc->sc_n_strokes; i++) {
1875 atp_stroke *stroke = &sc->sc_strokes[i];
1877 if ((stroke->components[X].movement) ||
1878 (stroke->components[Y].movement)) {
1879 dx += stroke->components[X].movement;
1880 dy += stroke->components[Y].movement;
1885 * Disregard movement if multiple
1886 * strokes record motion.
1888 if (n_movements != 1)
1891 sc->sc_status.dx += dx;
1892 sc->sc_status.dy += dy;
1893 atp_add_to_queue(sc, dx, -dy, sc->sc_status.button);
1896 if (tap_fingers != 0) {
1897 /* Add a pair of events (button-down and button-up). */
1898 switch (tap_fingers) {
1899 case 1: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON1DOWN);
1901 case 2: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON2DOWN);
1903 case 3: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON3DOWN);
1905 default: break;/* handle taps of only up to 3 fingers */
1907 atp_add_to_queue(sc, 0, 0, 0); /* button release */
1911 * The device continues to trigger interrupts at a
1912 * fast rate even after touchpad activity has
1913 * stopped. Upon detecting that the device has
1914 * remained idle beyond a threshold, we reinitialize
1915 * it to silence the interrupts.
1917 if ((sc->sc_status.flags == 0) &&
1918 (sc->sc_n_strokes == 0) &&
1919 (sc->sc_status.button == 0)) {
1921 if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) {
1922 DPRINTFN(ATP_LLEVEL_INFO, "idle\n");
1925 * Use the last frame before we go idle for
1926 * calibration on pads which do not send
1927 * calibration frames.
1929 if (sc->sc_params->prot < ATP_PROT_GEYSER3) {
1930 memcpy(sc->base_x, sc->cur_x,
1931 sc->sc_params->n_xsensors *
1932 sizeof(*(sc->base_x)));
1933 memcpy(sc->base_y, sc->cur_y,
1934 sc->sc_params->n_ysensors *
1935 sizeof(*(sc->base_y)));
1938 sc->sc_idlecount = 0;
1939 usbd_transfer_start(sc->sc_xfer[ATP_RESET]);
1942 sc->sc_idlecount = 0;
1947 /* check if we can put more data into the FIFO */
1948 if (usb_fifo_put_bytes_max(
1949 sc->sc_fifo.fp[USB_FIFO_RX]) != 0) {
1950 usbd_xfer_set_frame_len(xfer, 0,
1951 sc->sc_params->data_len);
1952 usbd_transfer_submit(xfer);
1956 default: /* Error */
1957 if (error != USB_ERR_CANCELLED) {
1958 /* try clear stall first */
1959 usbd_xfer_set_stall(xfer);
1969 atp_add_to_queue(struct atp_softc *sc, int dx, int dy, uint32_t buttons_in)
1971 uint32_t buttons_out;
1974 dx = imin(dx, 254); dx = imax(dx, -256);
1975 dy = imin(dy, 254); dy = imax(dy, -256);
1977 buttons_out = MOUSE_MSC_BUTTONS;
1978 if (buttons_in & MOUSE_BUTTON1DOWN)
1979 buttons_out &= ~MOUSE_MSC_BUTTON1UP;
1980 else if (buttons_in & MOUSE_BUTTON2DOWN)
1981 buttons_out &= ~MOUSE_MSC_BUTTON2UP;
1982 else if (buttons_in & MOUSE_BUTTON3DOWN)
1983 buttons_out &= ~MOUSE_MSC_BUTTON3UP;
1985 DPRINTFN(ATP_LLEVEL_INFO, "dx=%d, dy=%d, buttons=%x\n",
1986 dx, dy, buttons_out);
1988 /* Encode the mouse data in standard format; refer to mouse(4) */
1989 buf[0] = sc->sc_mode.syncmask[1];
1990 buf[0] |= buttons_out;
1993 buf[3] = dx - (dx >> 1);
1994 buf[4] = dy - (dy >> 1);
1995 /* Encode extra bytes for level 1 */
1996 if (sc->sc_mode.level == 1) {
1997 buf[5] = 0; /* dz */
1998 buf[6] = 0; /* dz - (dz / 2) */
1999 buf[7] = MOUSE_SYS_EXTBUTTONS; /* Extra buttons all up. */
2002 usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf,
2003 sc->sc_mode.packetsize, 1);
2007 atp_reset_buf(struct atp_softc *sc)
2009 /* reset read queue */
2010 usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]);
2014 atp_start_read(struct usb_fifo *fifo)
2016 struct atp_softc *sc = usb_fifo_softc(fifo);
2019 /* Check if we should override the default polling interval */
2020 rate = sc->sc_pollrate;
2021 /* Range check rate */
2024 /* Check for set rate */
2025 if ((rate > 0) && (sc->sc_xfer[ATP_INTR_DT] != NULL)) {
2026 /* Stop current transfer, if any */
2027 usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]);
2028 /* Set new interval */
2029 usbd_xfer_set_interval(sc->sc_xfer[ATP_INTR_DT], 1000 / rate);
2030 /* Only set pollrate once */
2031 sc->sc_pollrate = 0;
2034 usbd_transfer_start(sc->sc_xfer[ATP_INTR_DT]);
2038 atp_stop_read(struct usb_fifo *fifo)
2040 struct atp_softc *sc = usb_fifo_softc(fifo);
2042 usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]);
2047 atp_open(struct usb_fifo *fifo, int fflags)
2049 DPRINTFN(ATP_LLEVEL_INFO, "\n");
2051 if (fflags & FREAD) {
2052 struct atp_softc *sc = usb_fifo_softc(fifo);
2055 if (sc->sc_state & ATP_ENABLED)
2058 if (usb_fifo_alloc_buffer(fifo,
2059 ATP_FIFO_BUF_SIZE, ATP_FIFO_QUEUE_MAXLEN)) {
2063 rc = atp_enable(sc);
2065 usb_fifo_free_buffer(fifo);
2074 atp_close(struct usb_fifo *fifo, int fflags)
2076 if (fflags & FREAD) {
2077 struct atp_softc *sc = usb_fifo_softc(fifo);
2080 usb_fifo_free_buffer(fifo);
2085 atp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
2087 struct atp_softc *sc = usb_fifo_softc(fifo);
2091 mtx_lock(&sc->sc_mutex);
2094 case MOUSE_GETHWINFO:
2095 *(mousehw_t *)addr = sc->sc_hw;
2098 *(mousemode_t *)addr = sc->sc_mode;
2101 mode = *(mousemode_t *)addr;
2103 if (mode.level == -1)
2104 /* Don't change the current setting */
2106 else if ((mode.level < 0) || (mode.level > 1)) {
2110 sc->sc_mode.level = mode.level;
2111 sc->sc_pollrate = mode.rate;
2112 sc->sc_hw.buttons = 3;
2114 if (sc->sc_mode.level == 0) {
2115 sc->sc_mode.protocol = MOUSE_PROTO_MSC;
2116 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
2117 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
2118 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
2119 } else if (sc->sc_mode.level == 1) {
2120 sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
2121 sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
2122 sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
2123 sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
2127 case MOUSE_GETLEVEL:
2128 *(int *)addr = sc->sc_mode.level;
2130 case MOUSE_SETLEVEL:
2131 if (*(int *)addr < 0 || *(int *)addr > 1) {
2135 sc->sc_mode.level = *(int *)addr;
2136 sc->sc_hw.buttons = 3;
2138 if (sc->sc_mode.level == 0) {
2139 sc->sc_mode.protocol = MOUSE_PROTO_MSC;
2140 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
2141 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
2142 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
2143 } else if (sc->sc_mode.level == 1) {
2144 sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
2145 sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
2146 sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
2147 sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
2151 case MOUSE_GETSTATUS: {
2152 mousestatus_t *status = (mousestatus_t *)addr;
2154 *status = sc->sc_status;
2155 sc->sc_status.obutton = sc->sc_status.button;
2156 sc->sc_status.button = 0;
2157 sc->sc_status.dx = 0;
2158 sc->sc_status.dy = 0;
2159 sc->sc_status.dz = 0;
2161 if (status->dx || status->dy || status->dz)
2162 status->flags |= MOUSE_POSCHANGED;
2163 if (status->button != status->obutton)
2164 status->flags |= MOUSE_BUTTONSCHANGED;
2172 mtx_unlock(&sc->sc_mutex);
2177 atp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS)
2181 u_int prev_mickeys_scale_factor;
2183 prev_mickeys_scale_factor = atp_mickeys_scale_factor;
2185 tmp = atp_mickeys_scale_factor;
2186 error = sysctl_handle_int(oidp, &tmp, 0, req);
2187 if (error != 0 || req->newptr == NULL)
2190 if (tmp == prev_mickeys_scale_factor)
2191 return (0); /* no change */
2193 atp_mickeys_scale_factor = tmp;
2194 DPRINTFN(ATP_LLEVEL_INFO, "%s: resetting mickeys_scale_factor to %u\n",
2195 ATP_DRIVER_NAME, tmp);
2197 /* Update dependent thresholds. */
2198 if (atp_small_movement_threshold == (prev_mickeys_scale_factor >> 3))
2199 atp_small_movement_threshold = atp_mickeys_scale_factor >> 3;
2200 if (atp_max_delta_mickeys == ((3 * prev_mickeys_scale_factor) >> 1))
2201 atp_max_delta_mickeys = ((3 * atp_mickeys_scale_factor) >>1);
2202 if (atp_slide_min_movement == (prev_mickeys_scale_factor >> 3))
2203 atp_slide_min_movement = atp_mickeys_scale_factor >> 3;
2208 static device_method_t atp_methods[] = {
2209 /* Device interface */
2210 DEVMETHOD(device_probe, atp_probe),
2211 DEVMETHOD(device_attach, atp_attach),
2212 DEVMETHOD(device_detach, atp_detach),
2216 static driver_t atp_driver = {
2217 .name = ATP_DRIVER_NAME,
2218 .methods = atp_methods,
2219 .size = sizeof(struct atp_softc)
2222 static devclass_t atp_devclass;
2224 DRIVER_MODULE(atp, uhub, atp_driver, atp_devclass, NULL, 0);
2225 MODULE_DEPEND(atp, usb, 1, 1, 1);
2226 MODULE_VERSION(atp, 1);