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 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 /* #if USB_DEBUG */
131 static u_int atp_touch_timeout = ATP_TOUCH_TIMEOUT;
132 SYSCTL_INT(_hw_usb_atp, OID_AUTO, touch_timeout, CTLFLAG_RW, &atp_touch_timeout,
133 125000, "age threshold (in micros) for a touch");
135 static u_int atp_double_tap_threshold = ATP_DOUBLE_TAP_N_DRAG_THRESHOLD;
136 SYSCTL_INT(_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_device_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 (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 (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 /* #if 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 /* #if 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)
1168 atp_pspan spans[2][ATP_MAX_PSPANS_PER_AXIS];
1171 /* Copy unmatched pspans into the local arrays. */
1172 for (i = 0, nspans[X] = 0; i < n_xpspans; i++) {
1173 if (pspans_x[i].matched == FALSE) {
1174 spans[X][nspans[X]] = pspans_x[i];
1178 for (j = 0, nspans[Y] = 0; j < n_ypspans; j++) {
1179 if (pspans_y[j].matched == FALSE) {
1180 spans[Y][nspans[Y]] = pspans_y[j];
1185 if (nspans[X] == nspans[Y]) {
1186 /* Create new strokes from pairs of unmatched pspans */
1187 for (i = 0, j = 0; (i < nspans[X]) && (j < nspans[Y]); i++, j++)
1188 atp_add_stroke(sc, &spans[X][i], &spans[Y][j]);
1191 atp_axis repeat_axis; /* axis with multi-pspans */
1192 u_int repeat_count; /* repeat count for the multi-pspan*/
1193 u_int repeat_index = 0; /* index of the multi-span */
1195 repeat_axis = (nspans[X] > nspans[Y]) ? Y : X;
1196 repeat_count = abs(nspans[X] - nspans[Y]);
1197 for (i = 0; i < nspans[repeat_axis]; i++) {
1198 if (spans[repeat_axis][i].cum > cum) {
1200 cum = spans[repeat_axis][i].cum;
1204 /* Create new strokes from pairs of unmatched pspans */
1206 for (; (i < nspans[X]) && (j < nspans[Y]); i++, j++) {
1207 atp_add_stroke(sc, &spans[X][i], &spans[Y][j]);
1209 /* Take care to repeat at the multi-pspan. */
1210 if (repeat_count > 0) {
1211 if ((repeat_axis == X) &&
1212 (repeat_index == i)) {
1213 i--; /* counter loop increment */
1215 } else if ((repeat_axis == Y) &&
1216 (repeat_index == j)) {
1217 j--; /* counter loop increment */
1226 * Advance the state of this stroke--and update the out-parameter
1227 * 'movement' as a side-effect.
1230 atp_advance_stroke_state(struct atp_softc *sc, atp_stroke *stroke,
1231 boolean_t *movement)
1234 if (stroke->age <= atp_stroke_maturity_threshold) {
1235 /* Avoid noise from immature strokes. */
1236 stroke->components[X].delta_mickeys = 0;
1237 stroke->components[Y].delta_mickeys = 0;
1240 /* Revitalize stroke if it had previously been marked as a zombie. */
1241 if (stroke->flags & ATSF_ZOMBIE)
1242 stroke->flags &= ~ATSF_ZOMBIE;
1244 if (atp_compute_stroke_movement(stroke))
1247 if (stroke->type != ATP_STROKE_TOUCH)
1250 /* Convert touch strokes to slides upon detecting movement or age. */
1251 if (stroke->cum_movement >= atp_slide_min_movement) {
1252 atp_convert_to_slide(sc, stroke);
1254 /* If a touch stroke is found to be older than the
1255 * touch-timeout threshold, it should be converted to
1256 * a slide; except if there is a co-incident sibling
1257 * with a later creation time.
1259 * When multiple fingers make contact with the
1260 * touchpad, they are likely to be separated in their
1261 * times of incidence. During a multi-finger tap,
1262 * therefore, the last finger to make
1263 * contact--i.e. the one with the latest
1264 * 'ctime'--should be used to determine how the
1265 * touch-siblings get treated; otherwise older
1266 * siblings may lapse the touch-timeout and get
1267 * converted into slides prematurely. The following
1268 * loop determines if there exists another touch
1269 * stroke with a larger 'ctime' than the current
1270 * stroke (NOTE: zombies with a larger 'ctime' are
1271 * also considered) .
1275 for (i = 0; i < sc->sc_n_strokes; i++) {
1276 if ((&sc->sc_strokes[i] == stroke) ||
1277 (sc->sc_strokes[i].type != ATP_STROKE_TOUCH))
1280 if (timevalcmp(&sc->sc_strokes[i].ctime,
1284 if (i == sc->sc_n_strokes) {
1285 /* Found no other touch stroke with a larger 'ctime'. */
1286 struct timeval tdiff;
1288 /* Compute the stroke's age. */
1289 getmicrotime(&tdiff);
1290 if (timevalcmp(&tdiff, &stroke->ctime, >))
1291 timevalsub(&tdiff, &stroke->ctime);
1294 * If we are here, it is because getmicrotime
1295 * reported the current time as being behind
1296 * the stroke's start time; getmicrotime can
1303 if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) ||
1304 ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) &&
1306 (atp_touch_timeout % 1000000))))
1307 atp_convert_to_slide(sc, stroke);
1312 /* Switch a given touch stroke to being a slide. */
1314 atp_convert_to_slide(struct atp_softc *sc, atp_stroke *stroke)
1316 stroke->type = ATP_STROKE_SLIDE;
1318 /* Are we at the beginning of a double-click-n-drag? */
1319 if ((sc->sc_n_strokes == 1) &&
1320 ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) &&
1321 timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) {
1322 struct timeval delta;
1323 struct timeval window = {
1324 atp_double_tap_threshold / 1000000,
1325 atp_double_tap_threshold % 1000000
1328 delta = stroke->ctime;
1329 timevalsub(&delta, &sc->sc_reap_time);
1330 if (timevalcmp(&delta, &window, <=))
1331 sc->sc_state |= ATP_DOUBLE_TAP_DRAG;
1336 * Terminate a stroke. While SLIDE strokes are dropped, TOUCH strokes
1337 * are retained as zombies so as to reap all their siblings together;
1338 * this helps establish the number of fingers involved in the tap.
1341 atp_terminate_stroke(struct atp_softc *sc,
1342 u_int index) /* index of the stroke to be terminated */
1344 atp_stroke *s = &sc->sc_strokes[index];
1346 if (s->flags & ATSF_ZOMBIE) {
1350 if ((s->type == ATP_STROKE_TOUCH) &&
1351 (s->age > atp_stroke_maturity_threshold)) {
1352 s->flags |= ATSF_ZOMBIE;
1354 /* If no zombies exist, then prepare to reap zombies later. */
1355 if ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) {
1356 atp_setup_reap_time(sc, &s->ctime);
1357 sc->sc_state |= ATP_ZOMBIES_EXIST;
1360 /* Drop this stroke. */
1361 memcpy(&sc->sc_strokes[index], &sc->sc_strokes[index + 1],
1362 (sc->sc_n_strokes - index - 1) * sizeof(atp_stroke));
1366 * Reset the double-click-n-drag at the termination of
1369 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG;
1373 static __inline boolean_t
1374 atp_stroke_has_small_movement(const atp_stroke *stroke)
1376 return ((abs(stroke->components[X].delta_mickeys) <=
1377 atp_small_movement_threshold) &&
1378 (abs(stroke->components[Y].delta_mickeys) <=
1379 atp_small_movement_threshold));
1383 * Accumulate delta_mickeys into the component's 'pending' bucket; if
1384 * the aggregate exceeds the small_movement_threshold, then retain
1385 * delta_mickeys for later.
1387 static __inline void
1388 atp_update_pending_mickeys(atp_stroke_component *component)
1390 component->pending += component->delta_mickeys;
1391 if (abs(component->pending) <= atp_small_movement_threshold)
1392 component->delta_mickeys = 0;
1395 * Penalise pending mickeys for having accumulated
1396 * over short deltas. This operation has the effect of
1397 * scaling down the cumulative contribution of short
1400 component->pending -= (component->delta_mickeys << 1);
1406 atp_compute_smoothening_scale_ratio(atp_stroke *stroke, int *numerator,
1411 u_int vel_squared; /* Square of the velocity vector's magnitude. */
1412 u_int vel_squared_smooth;
1414 /* Table holding (10 * sqrt(x)) for x between 1 and 256. */
1415 static uint8_t sqrt_table[256] = {
1416 10, 14, 17, 20, 22, 24, 26, 28,
1417 30, 31, 33, 34, 36, 37, 38, 40,
1418 41, 42, 43, 44, 45, 46, 47, 48,
1419 50, 50, 51, 52, 53, 54, 55, 56,
1420 57, 58, 59, 60, 60, 61, 62, 63,
1421 64, 64, 65, 66, 67, 67, 68, 69,
1422 70, 70, 71, 72, 72, 73, 74, 74,
1423 75, 76, 76, 77, 78, 78, 79, 80,
1424 80, 81, 81, 82, 83, 83, 84, 84,
1425 85, 86, 86, 87, 87, 88, 88, 89,
1426 90, 90, 91, 91, 92, 92, 93, 93,
1427 94, 94, 95, 95, 96, 96, 97, 97,
1428 98, 98, 99, 100, 100, 100, 101, 101,
1429 102, 102, 103, 103, 104, 104, 105, 105,
1430 106, 106, 107, 107, 108, 108, 109, 109,
1431 110, 110, 110, 111, 111, 112, 112, 113,
1432 113, 114, 114, 114, 115, 115, 116, 116,
1433 117, 117, 117, 118, 118, 119, 119, 120,
1434 120, 120, 121, 121, 122, 122, 122, 123,
1435 123, 124, 124, 124, 125, 125, 126, 126,
1436 126, 127, 127, 128, 128, 128, 129, 129,
1437 130, 130, 130, 131, 131, 131, 132, 132,
1438 133, 133, 133, 134, 134, 134, 135, 135,
1439 136, 136, 136, 137, 137, 137, 138, 138,
1440 138, 139, 139, 140, 140, 140, 141, 141,
1441 141, 142, 142, 142, 143, 143, 143, 144,
1442 144, 144, 145, 145, 145, 146, 146, 146,
1443 147, 147, 147, 148, 148, 148, 149, 149,
1444 150, 150, 150, 150, 151, 151, 151, 152,
1445 152, 152, 153, 153, 153, 154, 154, 154,
1446 155, 155, 155, 156, 156, 156, 157, 157,
1447 157, 158, 158, 158, 159, 159, 159, 160
1449 const u_int N = sizeof(sqrt_table) / sizeof(sqrt_table[0]);
1451 dxdt = stroke->components[X].delta_mickeys;
1452 dydt = stroke->components[Y].delta_mickeys;
1454 *numerator = 0, *denominator = 0; /* default values. */
1456 /* Compute a smoothened magnitude_squared of the stroke's velocity. */
1457 vel_squared = dxdt * dxdt + dydt * dydt;
1458 vel_squared_smooth = (3 * stroke->velocity_squared + vel_squared) >> 2;
1459 stroke->velocity_squared = vel_squared_smooth; /* retained as history */
1460 if ((vel_squared == 0) || (vel_squared_smooth == 0))
1461 return; /* returning (numerator == 0) will imply zero movement*/
1464 * In order to determine the overall movement scale factor,
1465 * we're actually interested in the effect of smoothening upon
1466 * the *magnitude* of velocity; i.e. we need to compute the
1467 * square-root of (vel_squared_smooth / vel_squared) in the
1468 * form of a numerator and denominator.
1471 /* Keep within the bounds of the square-root table. */
1472 while ((vel_squared > N) || (vel_squared_smooth > N)) {
1473 /* Dividing uniformly by 2 won't disturb the final ratio. */
1475 vel_squared_smooth >>= 1;
1478 *numerator = sqrt_table[vel_squared_smooth - 1];
1479 *denominator = sqrt_table[vel_squared - 1];
1483 * Compute a smoothened value for the stroke's movement from
1484 * delta_mickeys in the X and Y components.
1487 atp_compute_stroke_movement(atp_stroke *stroke)
1489 int num; /* numerator of scale ratio */
1490 int denom; /* denominator of scale ratio */
1493 * Short movements are added first to the 'pending' bucket,
1494 * and then acted upon only when their aggregate exceeds a
1495 * threshold. This has the effect of filtering away movement
1498 if (atp_stroke_has_small_movement(stroke)) {
1499 atp_update_pending_mickeys(&stroke->components[X]);
1500 atp_update_pending_mickeys(&stroke->components[Y]);
1501 } else { /* large movement */
1502 /* clear away any pending mickeys if there are large movements*/
1503 stroke->components[X].pending = 0;
1504 stroke->components[Y].pending = 0;
1507 /* Get the scale ratio and smoothen movement. */
1508 atp_compute_smoothening_scale_ratio(stroke, &num, &denom);
1509 if ((num == 0) || (denom == 0)) {
1510 stroke->components[X].movement = 0;
1511 stroke->components[Y].movement = 0;
1512 stroke->velocity_squared >>= 1; /* Erode velocity_squared. */
1514 stroke->components[X].movement =
1515 (stroke->components[X].delta_mickeys * num) / denom;
1516 stroke->components[Y].movement =
1517 (stroke->components[Y].delta_mickeys * num) / denom;
1519 stroke->cum_movement +=
1520 abs(stroke->components[X].movement) +
1521 abs(stroke->components[Y].movement);
1524 return ((stroke->components[X].movement != 0) ||
1525 (stroke->components[Y].movement != 0));
1528 static __inline void
1529 atp_setup_reap_time(struct atp_softc *sc, struct timeval *tvp)
1531 struct timeval reap_window = {
1532 ATP_ZOMBIE_STROKE_REAP_WINDOW / 1000000,
1533 ATP_ZOMBIE_STROKE_REAP_WINDOW % 1000000
1536 microtime(&sc->sc_reap_time);
1537 timevaladd(&sc->sc_reap_time, &reap_window);
1539 sc->sc_reap_ctime = *tvp; /* ctime to reap */
1543 atp_reap_zombies(struct atp_softc *sc, u_int *n_reaped, u_int *reaped_xlocs)
1549 for (i = 0; i < sc->sc_n_strokes; i++) {
1550 struct timeval tdiff;
1552 stroke = &sc->sc_strokes[i];
1554 if ((stroke->flags & ATSF_ZOMBIE) == 0)
1557 /* Compare this stroke's ctime with the ctime being reaped. */
1558 if (timevalcmp(&stroke->ctime, &sc->sc_reap_ctime, >=)) {
1559 tdiff = stroke->ctime;
1560 timevalsub(&tdiff, &sc->sc_reap_ctime);
1562 tdiff = sc->sc_reap_ctime;
1563 timevalsub(&tdiff, &stroke->ctime);
1566 if ((tdiff.tv_sec > (ATP_COINCIDENCE_THRESHOLD / 1000000)) ||
1567 ((tdiff.tv_sec == (ATP_COINCIDENCE_THRESHOLD / 1000000)) &&
1568 (tdiff.tv_usec > (ATP_COINCIDENCE_THRESHOLD % 1000000)))) {
1569 continue; /* Skip non-siblings. */
1573 * Reap this sibling zombie stroke.
1576 if (reaped_xlocs != NULL)
1577 reaped_xlocs[*n_reaped] = stroke->components[X].loc;
1579 /* Erase the stroke from the sc. */
1580 memcpy(&stroke[i], &stroke[i + 1],
1581 (sc->sc_n_strokes - i - 1) * sizeof(atp_stroke));
1585 --i; /* Decr. i to keep it unchanged for the next iteration */
1588 DPRINTFN(ATP_LLEVEL_INFO, "reaped %u zombies\n", *n_reaped);
1590 /* There could still be zombies remaining in the system. */
1591 for (i = 0; i < sc->sc_n_strokes; i++) {
1592 stroke = &sc->sc_strokes[i];
1593 if (stroke->flags & ATSF_ZOMBIE) {
1594 DPRINTFN(ATP_LLEVEL_INFO, "zombies remain!\n");
1595 atp_setup_reap_time(sc, &stroke->ctime);
1600 /* If we reach here, then no more zombies remain. */
1601 sc->sc_state &= ~ATP_ZOMBIES_EXIST;
1605 /* Device methods. */
1606 static device_probe_t atp_probe;
1607 static device_attach_t atp_attach;
1608 static device_detach_t atp_detach;
1609 static usb_callback_t atp_intr;
1611 static const struct usb_config atp_config[ATP_N_TRANSFER] = {
1613 .type = UE_INTERRUPT,
1614 .endpoint = UE_ADDR_ANY,
1615 .direction = UE_DIR_IN,
1620 .bufsize = 0, /* use wMaxPacketSize */
1621 .callback = &atp_intr,
1625 .endpoint = 0, /* Control pipe */
1626 .direction = UE_DIR_ANY,
1627 .bufsize = sizeof(struct usb_device_request) + MODE_LENGTH,
1628 .callback = &atp_reset_callback,
1629 .interval = 0, /* no pre-delay */
1634 atp_probe(device_t self)
1636 struct usb_attach_arg *uaa = device_get_ivars(self);
1638 if (uaa->usb_mode != USB_MODE_HOST)
1641 if ((uaa->info.bInterfaceClass != UICLASS_HID) ||
1642 (uaa->info.bInterfaceProtocol != UIPROTO_MOUSE))
1645 return (usbd_lookup_id_by_uaa(atp_devs, sizeof(atp_devs), uaa));
1649 atp_attach(device_t dev)
1651 struct atp_softc *sc = device_get_softc(dev);
1652 struct usb_attach_arg *uaa = device_get_ivars(dev);
1655 DPRINTFN(ATP_LLEVEL_INFO, "sc=%p\n", sc);
1658 sc->sc_usb_device = uaa->device;
1661 * By default the touchpad behaves like an HID device, sending
1662 * packets with reportID = 2. Such reports contain only
1663 * limited information--they encode movement deltas and button
1664 * events,--but do not include data from the pressure
1665 * sensors. The device input mode can be switched from HID
1666 * reports to raw sensor data using vendor-specific USB
1667 * control commands; but first the mode must be read.
1669 err = atp_req_get_report(sc->sc_usb_device, sc->sc_mode_bytes);
1670 if (err != USB_ERR_NORMAL_COMPLETION) {
1671 DPRINTF("failed to read device mode (%d)\n", err);
1675 if (atp_set_device_mode(dev, RAW_SENSOR_MODE) != 0) {
1676 DPRINTF("failed to set mode to 'RAW_SENSOR' (%d)\n", err);
1680 mtx_init(&sc->sc_mutex, "atpmtx", NULL, MTX_DEF | MTX_RECURSE);
1682 err = usbd_transfer_setup(uaa->device,
1683 &uaa->info.bIfaceIndex, sc->sc_xfer, atp_config,
1684 ATP_N_TRANSFER, sc, &sc->sc_mutex);
1687 DPRINTF("error=%s\n", usbd_errstr(err));
1691 if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex,
1692 &atp_fifo_methods, &sc->sc_fifo,
1693 device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex,
1694 UID_ROOT, GID_OPERATOR, 0644)) {
1698 device_set_usb_desc(dev);
1700 sc->sc_params = &atp_dev_params[uaa->driver_info];
1702 sc->sc_hw.buttons = 3;
1703 sc->sc_hw.iftype = MOUSE_IF_USB;
1704 sc->sc_hw.type = MOUSE_PAD;
1705 sc->sc_hw.model = MOUSE_MODEL_GENERIC;
1707 sc->sc_mode.protocol = MOUSE_PROTO_MSC;
1708 sc->sc_mode.rate = -1;
1709 sc->sc_mode.resolution = MOUSE_RES_UNKNOWN;
1710 sc->sc_mode.accelfactor = 0;
1711 sc->sc_mode.level = 0;
1712 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
1713 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
1714 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
1718 sc->sc_left_margin = atp_mickeys_scale_factor;
1719 sc->sc_right_margin = (sc->sc_params->n_xsensors - 1) *
1720 atp_mickeys_scale_factor;
1730 atp_detach(device_t dev)
1732 struct atp_softc *sc;
1734 sc = device_get_softc(dev);
1735 if (sc->sc_state & ATP_ENABLED) {
1736 mtx_lock(&sc->sc_mutex);
1738 mtx_unlock(&sc->sc_mutex);
1741 usb_fifo_detach(&sc->sc_fifo);
1743 usbd_transfer_unsetup(sc->sc_xfer, ATP_N_TRANSFER);
1745 mtx_destroy(&sc->sc_mutex);
1751 atp_intr(struct usb_xfer *xfer, usb_error_t error)
1753 struct atp_softc *sc = usbd_xfer_softc(xfer);
1755 struct usb_page_cache *pc;
1756 uint8_t status_bits;
1757 atp_pspan pspans_x[ATP_MAX_PSPANS_PER_AXIS];
1758 atp_pspan pspans_y[ATP_MAX_PSPANS_PER_AXIS];
1759 u_int n_xpspans = 0, n_ypspans = 0;
1760 u_int reaped_xlocs[ATP_MAX_STROKES];
1761 u_int tap_fingers = 0;
1763 usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
1765 switch (USB_GET_STATE(xfer)) {
1766 case USB_ST_TRANSFERRED:
1767 if (len > sc->sc_params->data_len) {
1768 DPRINTFN(ATP_LLEVEL_ERROR,
1769 "truncating large packet from %u to %u bytes\n",
1770 len, sc->sc_params->data_len);
1771 len = sc->sc_params->data_len;
1773 if (len < sc->sc_params->data_len)
1776 pc = usbd_xfer_get_frame(xfer, 0);
1777 usbd_copy_out(pc, 0, sc->sensor_data, sc->sc_params->data_len);
1779 /* Interpret sensor data */
1780 atp_interpret_sensor_data(sc->sensor_data,
1781 sc->sc_params->n_xsensors, X, sc->cur_x,
1782 sc->sc_params->prot);
1783 atp_interpret_sensor_data(sc->sensor_data,
1784 sc->sc_params->n_ysensors, Y, sc->cur_y,
1785 sc->sc_params->prot);
1788 * If this is the initial update (from an untouched
1789 * pad), we should set the base values for the sensor
1790 * data; deltas with respect to these base values can
1791 * be used as pressure readings subsequently.
1793 status_bits = sc->sensor_data[sc->sc_params->data_len - 1];
1794 if ((sc->sc_params->prot == ATP_PROT_GEYSER3 &&
1795 (status_bits & ATP_STATUS_BASE_UPDATE)) ||
1796 !(sc->sc_state & ATP_VALID)) {
1797 memcpy(sc->base_x, sc->cur_x,
1798 sc->sc_params->n_xsensors * sizeof(*(sc->base_x)));
1799 memcpy(sc->base_y, sc->cur_y,
1800 sc->sc_params->n_ysensors * sizeof(*(sc->base_y)));
1801 sc->sc_state |= ATP_VALID;
1805 /* Get pressure readings and detect p-spans for both axes. */
1806 atp_get_pressures(sc->pressure_x, sc->cur_x, sc->base_x,
1807 sc->sc_params->n_xsensors);
1808 atp_detect_pspans(sc->pressure_x, sc->sc_params->n_xsensors,
1809 ATP_MAX_PSPANS_PER_AXIS,
1810 pspans_x, &n_xpspans);
1811 atp_get_pressures(sc->pressure_y, sc->cur_y, sc->base_y,
1812 sc->sc_params->n_ysensors);
1813 atp_detect_pspans(sc->pressure_y, sc->sc_params->n_ysensors,
1814 ATP_MAX_PSPANS_PER_AXIS,
1815 pspans_y, &n_ypspans);
1817 /* Update strokes with new pspans to detect movements. */
1818 sc->sc_status.flags &= ~MOUSE_POSCHANGED;
1819 if (atp_update_strokes(sc,
1820 pspans_x, n_xpspans,
1821 pspans_y, n_ypspans))
1822 sc->sc_status.flags |= MOUSE_POSCHANGED;
1824 /* Reap zombies if it is time. */
1825 if (sc->sc_state & ATP_ZOMBIES_EXIST) {
1829 if (timevalcmp(&now, &sc->sc_reap_time, >=))
1830 atp_reap_zombies(sc, &tap_fingers,
1834 sc->sc_status.flags &= ~MOUSE_STDBUTTONSCHANGED;
1835 sc->sc_status.obutton = sc->sc_status.button;
1837 /* Get the state of the physical buttton. */
1838 sc->sc_status.button = (status_bits & ATP_STATUS_BUTTON) ?
1839 MOUSE_BUTTON1DOWN : 0;
1840 if (sc->sc_status.button != 0) {
1841 /* Reset DOUBLE_TAP_N_DRAG if the button is pressed. */
1842 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG;
1843 } else if (sc->sc_state & ATP_DOUBLE_TAP_DRAG) {
1844 /* Assume a button-press with DOUBLE_TAP_N_DRAG. */
1845 sc->sc_status.button = MOUSE_BUTTON1DOWN;
1848 sc->sc_status.flags |=
1849 sc->sc_status.button ^ sc->sc_status.obutton;
1850 if (sc->sc_status.flags & MOUSE_STDBUTTONSCHANGED) {
1851 DPRINTFN(ATP_LLEVEL_INFO, "button %s\n",
1852 ((sc->sc_status.button & MOUSE_BUTTON1DOWN) ?
1853 "pressed" : "released"));
1854 } else if ((sc->sc_status.obutton == 0) &&
1855 (sc->sc_status.button == 0) &&
1856 (tap_fingers != 0)) {
1857 /* Ignore single-finger taps at the edges. */
1858 if ((tap_fingers == 1) &&
1859 ((reaped_xlocs[0] <= sc->sc_left_margin) ||
1860 (reaped_xlocs[0] > sc->sc_right_margin))) {
1863 DPRINTFN(ATP_LLEVEL_INFO,
1864 "tap_fingers: %u\n", tap_fingers);
1867 if (sc->sc_status.flags &
1868 (MOUSE_POSCHANGED | MOUSE_STDBUTTONSCHANGED)) {
1872 dx = 0, dy = 0, n_movements = 0;
1873 for (u_int i = 0; i < sc->sc_n_strokes; i++) {
1874 atp_stroke *stroke = &sc->sc_strokes[i];
1876 if ((stroke->components[X].movement) ||
1877 (stroke->components[Y].movement)) {
1878 dx += stroke->components[X].movement;
1879 dy += stroke->components[Y].movement;
1884 * Disregard movement if multiple
1885 * strokes record motion.
1887 if (n_movements != 1)
1890 sc->sc_status.dx += dx;
1891 sc->sc_status.dy += dy;
1892 atp_add_to_queue(sc, dx, -dy, sc->sc_status.button);
1895 if (tap_fingers != 0) {
1896 /* Add a pair of events (button-down and button-up). */
1897 switch (tap_fingers) {
1898 case 1: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON1DOWN);
1900 case 2: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON2DOWN);
1902 case 3: atp_add_to_queue(sc, 0, 0, MOUSE_BUTTON3DOWN);
1904 default: break;/* handle taps of only up to 3 fingers */
1906 atp_add_to_queue(sc, 0, 0, 0); /* button release */
1910 * The device continues to trigger interrupts at a
1911 * fast rate even after touchpad activity has
1912 * stopped. Upon detecting that the device has
1913 * remained idle beyond a threshold, we reinitialize
1914 * it to silence the interrupts.
1916 if ((sc->sc_status.flags == 0) &&
1917 (sc->sc_n_strokes == 0) &&
1918 (sc->sc_status.button == 0)) {
1920 if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) {
1921 DPRINTFN(ATP_LLEVEL_INFO, "idle\n");
1924 * Use the last frame before we go idle for
1925 * calibration on pads which do not send
1926 * calibration frames.
1928 if (sc->sc_params->prot < ATP_PROT_GEYSER3) {
1929 memcpy(sc->base_x, sc->cur_x,
1930 sc->sc_params->n_xsensors *
1931 sizeof(*(sc->base_x)));
1932 memcpy(sc->base_y, sc->cur_y,
1933 sc->sc_params->n_ysensors *
1934 sizeof(*(sc->base_y)));
1937 sc->sc_idlecount = 0;
1938 usbd_transfer_start(sc->sc_xfer[ATP_RESET]);
1941 sc->sc_idlecount = 0;
1946 /* check if we can put more data into the FIFO */
1947 if (usb_fifo_put_bytes_max(
1948 sc->sc_fifo.fp[USB_FIFO_RX]) != 0) {
1949 usbd_xfer_set_frame_len(xfer, 0,
1950 sc->sc_params->data_len);
1951 usbd_transfer_submit(xfer);
1955 default: /* Error */
1956 if (error != USB_ERR_CANCELLED) {
1957 /* try clear stall first */
1958 usbd_xfer_set_stall(xfer);
1968 atp_add_to_queue(struct atp_softc *sc, int dx, int dy, uint32_t buttons_in)
1970 uint32_t buttons_out;
1973 dx = imin(dx, 254); dx = imax(dx, -256);
1974 dy = imin(dy, 254); dy = imax(dy, -256);
1976 buttons_out = MOUSE_MSC_BUTTONS;
1977 if (buttons_in & MOUSE_BUTTON1DOWN)
1978 buttons_out &= ~MOUSE_MSC_BUTTON1UP;
1979 else if (buttons_in & MOUSE_BUTTON2DOWN)
1980 buttons_out &= ~MOUSE_MSC_BUTTON2UP;
1981 else if (buttons_in & MOUSE_BUTTON3DOWN)
1982 buttons_out &= ~MOUSE_MSC_BUTTON3UP;
1984 DPRINTFN(ATP_LLEVEL_INFO, "dx=%d, dy=%d, buttons=%x\n",
1985 dx, dy, buttons_out);
1987 /* Encode the mouse data in standard format; refer to mouse(4) */
1988 buf[0] = sc->sc_mode.syncmask[1];
1989 buf[0] |= buttons_out;
1992 buf[3] = dx - (dx >> 1);
1993 buf[4] = dy - (dy >> 1);
1994 /* Encode extra bytes for level 1 */
1995 if (sc->sc_mode.level == 1) {
1996 buf[5] = 0; /* dz */
1997 buf[6] = 0; /* dz - (dz / 2) */
1998 buf[7] = MOUSE_SYS_EXTBUTTONS; /* Extra buttons all up. */
2001 usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf,
2002 sc->sc_mode.packetsize, 1);
2006 atp_reset_buf(struct atp_softc *sc)
2008 /* reset read queue */
2009 usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]);
2013 atp_start_read(struct usb_fifo *fifo)
2015 struct atp_softc *sc = usb_fifo_softc(fifo);
2018 /* Check if we should override the default polling interval */
2019 rate = sc->sc_pollrate;
2020 /* Range check rate */
2023 /* Check for set rate */
2024 if ((rate > 0) && (sc->sc_xfer[ATP_INTR_DT] != NULL)) {
2025 /* Stop current transfer, if any */
2026 usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]);
2027 /* Set new interval */
2028 usbd_xfer_set_interval(sc->sc_xfer[ATP_INTR_DT], 1000 / rate);
2029 /* Only set pollrate once */
2030 sc->sc_pollrate = 0;
2033 usbd_transfer_start(sc->sc_xfer[ATP_INTR_DT]);
2037 atp_stop_read(struct usb_fifo *fifo)
2039 struct atp_softc *sc = usb_fifo_softc(fifo);
2041 usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]);
2046 atp_open(struct usb_fifo *fifo, int fflags)
2048 DPRINTFN(ATP_LLEVEL_INFO, "\n");
2050 if (fflags & FREAD) {
2051 struct atp_softc *sc = usb_fifo_softc(fifo);
2054 if (sc->sc_state & ATP_ENABLED)
2057 if (usb_fifo_alloc_buffer(fifo,
2058 ATP_FIFO_BUF_SIZE, ATP_FIFO_QUEUE_MAXLEN)) {
2062 rc = atp_enable(sc);
2064 usb_fifo_free_buffer(fifo);
2073 atp_close(struct usb_fifo *fifo, int fflags)
2075 if (fflags & FREAD) {
2076 struct atp_softc *sc = usb_fifo_softc(fifo);
2079 usb_fifo_free_buffer(fifo);
2084 atp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
2086 struct atp_softc *sc = usb_fifo_softc(fifo);
2090 mtx_lock(&sc->sc_mutex);
2093 case MOUSE_GETHWINFO:
2094 *(mousehw_t *)addr = sc->sc_hw;
2097 *(mousemode_t *)addr = sc->sc_mode;
2100 mode = *(mousemode_t *)addr;
2102 if (mode.level == -1)
2103 /* Don't change the current setting */
2105 else if ((mode.level < 0) || (mode.level > 1)) {
2109 sc->sc_mode.level = mode.level;
2110 sc->sc_pollrate = mode.rate;
2111 sc->sc_hw.buttons = 3;
2113 if (sc->sc_mode.level == 0) {
2114 sc->sc_mode.protocol = MOUSE_PROTO_MSC;
2115 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
2116 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
2117 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
2118 } else if (sc->sc_mode.level == 1) {
2119 sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
2120 sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
2121 sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
2122 sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
2126 case MOUSE_GETLEVEL:
2127 *(int *)addr = sc->sc_mode.level;
2129 case MOUSE_SETLEVEL:
2130 if (*(int *)addr < 0 || *(int *)addr > 1) {
2134 sc->sc_mode.level = *(int *)addr;
2135 sc->sc_hw.buttons = 3;
2137 if (sc->sc_mode.level == 0) {
2138 sc->sc_mode.protocol = MOUSE_PROTO_MSC;
2139 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
2140 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
2141 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
2142 } else if (sc->sc_mode.level == 1) {
2143 sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
2144 sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
2145 sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
2146 sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
2150 case MOUSE_GETSTATUS: {
2151 mousestatus_t *status = (mousestatus_t *)addr;
2153 *status = sc->sc_status;
2154 sc->sc_status.obutton = sc->sc_status.button;
2155 sc->sc_status.button = 0;
2156 sc->sc_status.dx = 0;
2157 sc->sc_status.dy = 0;
2158 sc->sc_status.dz = 0;
2160 if (status->dx || status->dy || status->dz)
2161 status->flags |= MOUSE_POSCHANGED;
2162 if (status->button != status->obutton)
2163 status->flags |= MOUSE_BUTTONSCHANGED;
2171 mtx_unlock(&sc->sc_mutex);
2176 atp_sysctl_scale_factor_handler(SYSCTL_HANDLER_ARGS)
2180 u_int prev_mickeys_scale_factor;
2182 prev_mickeys_scale_factor = atp_mickeys_scale_factor;
2184 tmp = atp_mickeys_scale_factor;
2185 error = sysctl_handle_int(oidp, &tmp, 0, req);
2186 if (error != 0 || req->newptr == NULL)
2189 if (tmp == prev_mickeys_scale_factor)
2190 return (0); /* no change */
2192 atp_mickeys_scale_factor = tmp;
2193 DPRINTFN(ATP_LLEVEL_INFO, "%s: resetting mickeys_scale_factor to %u\n",
2194 ATP_DRIVER_NAME, tmp);
2196 /* Update dependent thresholds. */
2197 if (atp_small_movement_threshold == (prev_mickeys_scale_factor >> 3))
2198 atp_small_movement_threshold = atp_mickeys_scale_factor >> 3;
2199 if (atp_max_delta_mickeys == ((3 * prev_mickeys_scale_factor) >> 1))
2200 atp_max_delta_mickeys = ((3 * atp_mickeys_scale_factor) >>1);
2201 if (atp_slide_min_movement == (prev_mickeys_scale_factor >> 3))
2202 atp_slide_min_movement = atp_mickeys_scale_factor >> 3;
2207 static device_method_t atp_methods[] = {
2208 /* Device interface */
2209 DEVMETHOD(device_probe, atp_probe),
2210 DEVMETHOD(device_attach, atp_attach),
2211 DEVMETHOD(device_detach, atp_detach),
2215 static driver_t atp_driver = {
2218 sizeof(struct atp_softc)
2221 static devclass_t atp_devclass;
2223 DRIVER_MODULE(atp, uhub, atp_driver, atp_devclass, NULL, 0);
2224 MODULE_DEPEND(atp, usb, 1, 1, 1);