Lines Matching +full:touch +full:- +full:hold +full:- +full:ms
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
39 * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
42 * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
44 * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
56 * I'm grateful to Stephan Scheunig, Angela Naegele, and Nokia IT-support
117 * This is the age in microseconds beyond which a touch is considered
133 * A double-tap followed by a single-finger slide is treated as a
135 * virtual button-press for the lifetime of the slide. The following
144 * The wait duration in ticks after losing a touch contact before
147 #define ATP_ZOMBIE_STROKE_REAP_INTERVAL (hz / 20) /* 50 ms */
159 /* Distance-squared threshold for matching a finger with a known stroke */
167 /* Maximum allowed width for pressure-spans.*/
190 &atp_touch_timeout, 125000, "age threshold in microseconds for a touch");
195 "maximum time in microseconds to allow association between a double-tap and "
209 "the small movement black-hole for filtering noise");
288 ((INFO) & ((1 << N_PROD_BITS) - 1))
313 /* trackpad finger data offsets, le16-aligned */
325 /* trackpad finger structure - little endian */
335 int16_t touch_major; /* touch area, major axis */
336 int16_t touch_minor; /* touch area, minor axis */
368 /* device-specific configuration */
601 /* Fields encapsulating the pressure-span. */
607 int delta_mickeys; /* change in location (un-smoothened movement)*/
612 * touchpad. A stroke comprises two p-span components and some state.
637 int instantaneous_dx; /* curr. change in X location (un-smoothened) */
638 int instantaneous_dy; /* curr. change in Y location (un-smoothened) */
647 * The following member is relevant only for fountain-geyser trackpads.
648 * For these, there is the need to track pressure-spans and cumulative
693 * button status. Set to non-zero if the mouse-button is physically
701 * Time when touch zombies were last reaped; useful for detecting
702 * double-touch-n-drag.
708 /* Regarding the data transferred from t-pad in USB INTR packets. */
723 * The last byte of the fountain-geyser sensor data contains status bits; the
825 .interval = 0, /* no pre-delay */
834 pstroke = TAILQ_FIRST(&sc->sc_stroke_free); in atp_alloc_stroke()
838 TAILQ_REMOVE(&sc->sc_stroke_free, pstroke, entry); in atp_alloc_stroke()
840 TAILQ_INSERT_TAIL(&sc->sc_stroke_used, pstroke, entry); in atp_alloc_stroke()
842 sc->sc_n_strokes++; in atp_alloc_stroke()
853 sc->sc_n_strokes--; in atp_free_stroke()
855 TAILQ_REMOVE(&sc->sc_stroke_used, pstroke, entry); in atp_free_stroke()
856 TAILQ_INSERT_TAIL(&sc->sc_stroke_free, pstroke, entry); in atp_free_stroke()
864 TAILQ_INIT(&sc->sc_stroke_free); in atp_init_stroke_pool()
865 TAILQ_INIT(&sc->sc_stroke_used); in atp_init_stroke_pool()
867 sc->sc_n_strokes = 0; in atp_init_stroke_pool()
869 memset(&sc->sc_strokes_data, 0, sizeof(sc->sc_strokes_data)); in atp_init_stroke_pool()
872 TAILQ_INSERT_TAIL(&sc->sc_stroke_free, &sc->sc_strokes_data[x], in atp_init_stroke_pool()
887 (sc->sc_family == TRACKPAD_FAMILY_FOUNTAIN_GEYSER)) in atp_set_device_mode()
892 err = usbd_req_get_report(sc->sc_usb_device, NULL /* mutex */, in atp_set_device_mode()
893 sc->sc_mode_bytes, sizeof(sc->sc_mode_bytes), 0 /* interface idx */, in atp_set_device_mode()
900 if (sc->sc_mode_bytes[0] == mode_value) in atp_set_device_mode()
904 * XXX Need to wait at least 250ms for hardware to get in atp_set_device_mode()
911 sc->sc_mode_bytes[0] = mode_value; in atp_set_device_mode()
912 return (usbd_req_set_report(sc->sc_usb_device, NULL /* mutex */, in atp_set_device_mode()
913 sc->sc_mode_bytes, sizeof(sc->sc_mode_bytes), 0 /* interface idx */, in atp_set_device_mode()
925 if (sc->sc_family == TRACKPAD_FAMILY_FOUNTAIN_GEYSER) in atp_reset_callback()
932 sc->sc_mode_bytes[0] = mode_value; in atp_reset_callback()
943 usbd_copy_in(pc, 0, sc->sc_mode_bytes, MODE_LENGTH); in atp_reset_callback()
960 if (sc->sc_state & ATP_ENABLED) in atp_enable()
964 memset(&sc->sc_status, 0, sizeof(sc->sc_status)); in atp_enable()
968 sc->sc_state |= ATP_ENABLED; in atp_enable()
977 sc->sc_state &= ~(ATP_ENABLED | ATP_VALID); in atp_disable()
989 (const struct fg_dev_params *)sc->sc_params; in fg_interpret_sensor_data()
991 fg_extract_sensor_data(sc->sc_sensor_data, params->n_xsensors, X, in fg_interpret_sensor_data()
992 sc->sc_cur_x, params->prot); in fg_interpret_sensor_data()
993 fg_extract_sensor_data(sc->sc_sensor_data, params->n_ysensors, Y, in fg_interpret_sensor_data()
994 sc->sc_cur_y, params->prot); in fg_interpret_sensor_data()
1002 status_bits = sc->sc_sensor_data[params->data_len - 1]; in fg_interpret_sensor_data()
1003 if (((params->prot == FG_TRACKPAD_TYPE_GEYSER3) || in fg_interpret_sensor_data()
1004 (params->prot == FG_TRACKPAD_TYPE_GEYSER4)) && in fg_interpret_sensor_data()
1005 ((sc->sc_state & ATP_VALID) == 0)) { in fg_interpret_sensor_data()
1007 memcpy(sc->sc_base_x, sc->sc_cur_x, in fg_interpret_sensor_data()
1008 params->n_xsensors * sizeof(*sc->sc_base_x)); in fg_interpret_sensor_data()
1009 memcpy(sc->sc_base_y, sc->sc_cur_y, in fg_interpret_sensor_data()
1010 params->n_ysensors * sizeof(*sc->sc_base_y)); in fg_interpret_sensor_data()
1011 sc->sc_state |= ATP_VALID; in fg_interpret_sensor_data()
1016 /* Get pressure readings and detect p-spans for both axes. */ in fg_interpret_sensor_data()
1017 fg_get_pressures(sc->sc_pressure_x, sc->sc_cur_x, sc->sc_base_x, in fg_interpret_sensor_data()
1018 params->n_xsensors); in fg_interpret_sensor_data()
1019 fg_detect_pspans(sc->sc_pressure_x, params->n_xsensors, in fg_interpret_sensor_data()
1020 FG_MAX_PSPANS_PER_AXIS, sc->sc_pspans_x, &n_xpspans); in fg_interpret_sensor_data()
1021 fg_get_pressures(sc->sc_pressure_y, sc->sc_cur_y, sc->sc_base_y, in fg_interpret_sensor_data()
1022 params->n_ysensors); in fg_interpret_sensor_data()
1023 fg_detect_pspans(sc->sc_pressure_y, params->n_ysensors, in fg_interpret_sensor_data()
1024 FG_MAX_PSPANS_PER_AXIS, sc->sc_pspans_y, &n_ypspans); in fg_interpret_sensor_data()
1027 if (fg_update_strokes(sc, sc->sc_pspans_x, n_xpspans, sc->sc_pspans_y, n_ypspans)) in fg_interpret_sensor_data()
1028 sc->sc_status.flags |= MOUSE_POSCHANGED; in fg_interpret_sensor_data()
1030 sc->sc_ibtn = (status_bits & FG_STATUS_BUTTON) ? MOUSE_BUTTON1DOWN : 0; in fg_interpret_sensor_data()
1031 sc->sc_status.button = sc->sc_ibtn; in fg_interpret_sensor_data()
1040 if ((sc->sc_status.flags == 0) && (sc->sc_n_strokes == 0)) { in fg_interpret_sensor_data()
1041 sc->sc_idlecount++; in fg_interpret_sensor_data()
1042 if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) { in fg_interpret_sensor_data()
1049 (const struct fg_dev_params *)sc->sc_params; in fg_interpret_sensor_data()
1053 if (params->prot < FG_TRACKPAD_TYPE_GEYSER3) { in fg_interpret_sensor_data()
1054 memcpy(sc->sc_base_x, sc->sc_cur_x, in fg_interpret_sensor_data()
1055 params->n_xsensors * sizeof(*(sc->sc_base_x))); in fg_interpret_sensor_data()
1056 memcpy(sc->sc_base_y, sc->sc_cur_y, in fg_interpret_sensor_data()
1057 params->n_ysensors * sizeof(*(sc->sc_base_y))); in fg_interpret_sensor_data()
1060 sc->sc_idlecount = 0; in fg_interpret_sensor_data()
1061 usbd_transfer_start(sc->sc_xfer[ATP_RESET]); in fg_interpret_sensor_data()
1064 sc->sc_idlecount = 0; in fg_interpret_sensor_data()
1074 * --,--,Y1,Y2,--,Y3,Y4,--,Y5,...,Y10, ... X1,X2,--,X3,X4
1077 * '--' (in the above) indicates that the value is unimportant.
1141 p[i] = cur[i] - base[i]; in fg_get_pressures()
1143 p[i] -= 256; in fg_get_pressures()
1144 if (p[i] < -127) in fg_get_pressures()
1150 * Shave off pressures below the noise-pressure in fg_get_pressures()
1157 p[i] -= FG_SENSOR_NOISE_THRESHOLD; in fg_get_pressures()
1215 if (p[i] > p[i - 1]) { in fg_detect_pspans()
1222 * re-process this reading in in fg_detect_pspans()
1228 i--; in fg_detect_pspans()
1243 /* post-process the spans */ in fg_detect_pspans()
1250 (num_spans - i - 1) * sizeof(fg_pspan)); in fg_detect_pspans()
1251 i--; in fg_detect_pspans()
1253 num_spans--; in fg_detect_pspans()
1270 const struct wsp_dev_params *params = sc->sc_params; in wsp_interpret_sensor_data()
1278 if ((data_len < params->finger_data_offset) || in wsp_interpret_sensor_data()
1279 ((data_len - params->finger_data_offset) % in wsp_interpret_sensor_data()
1284 n_source_fingers = (data_len - params->finger_data_offset) / in wsp_interpret_sensor_data()
1292 source_fingerp = (struct wsp_finger_sensor_data *)(sc->sc_sensor_data + in wsp_interpret_sensor_data()
1293 params->finger_data_offset); in wsp_interpret_sensor_data()
1298 source_fingerp->origin = le16toh((uint16_t)source_fingerp->origin); in wsp_interpret_sensor_data()
1299 source_fingerp->abs_x = le16toh((uint16_t)source_fingerp->abs_x); in wsp_interpret_sensor_data()
1300 source_fingerp->abs_y = le16toh((uint16_t)source_fingerp->abs_y); in wsp_interpret_sensor_data()
1301 source_fingerp->rel_x = le16toh((uint16_t)source_fingerp->rel_x); in wsp_interpret_sensor_data()
1302 source_fingerp->rel_y = le16toh((uint16_t)source_fingerp->rel_y); in wsp_interpret_sensor_data()
1303 source_fingerp->tool_major = le16toh((uint16_t)source_fingerp->tool_major); in wsp_interpret_sensor_data()
1304 source_fingerp->tool_minor = le16toh((uint16_t)source_fingerp->tool_minor); in wsp_interpret_sensor_data()
1305 source_fingerp->orientation = le16toh((uint16_t)source_fingerp->orientation); in wsp_interpret_sensor_data()
1306 source_fingerp->touch_major = le16toh((uint16_t)source_fingerp->touch_major); in wsp_interpret_sensor_data()
1307 source_fingerp->touch_minor = le16toh((uint16_t)source_fingerp->touch_minor); in wsp_interpret_sensor_data()
1308 source_fingerp->multi = le16toh((uint16_t)source_fingerp->multi); in wsp_interpret_sensor_data()
1312 if (source_fingerp->touch_major == 0) in wsp_interpret_sensor_data()
1316 fingers[n_fingers].x = source_fingerp->abs_x; in wsp_interpret_sensor_data()
1317 fingers[n_fingers].y = -source_fingerp->abs_y; in wsp_interpret_sensor_data()
1322 if ((sc->sc_n_strokes == 0) && (n_fingers == 0)) in wsp_interpret_sensor_data()
1326 sc->sc_status.flags |= MOUSE_POSCHANGED; in wsp_interpret_sensor_data()
1328 switch(params->tp_type) { in wsp_interpret_sensor_data()
1330 sc->sc_ibtn = sc->sc_sensor_data[WSP_TYPE2_BUTTON_DATA_OFFSET]; in wsp_interpret_sensor_data()
1333 sc->sc_ibtn = sc->sc_sensor_data[WSP_TYPE3_BUTTON_DATA_OFFSET]; in wsp_interpret_sensor_data()
1338 sc->sc_status.button = sc->sc_ibtn ? MOUSE_BUTTON1DOWN : 0; in wsp_interpret_sensor_data()
1342 * Match a pressure-span against a stroke-component. If there is a
1352 delta_mickeys = pspan->loc - component->loc; in fg_match_stroke_component()
1357 component->loc = pspan->loc; in fg_match_stroke_component()
1363 * centre-of-gravity, and hence the location of any/all in fg_match_stroke_component()
1367 if (pspan->cum > ((3 * component->cum_pressure) >> 1)) in fg_match_stroke_component()
1370 component->cum_pressure = pspan->cum; in fg_match_stroke_component()
1371 if (pspan->cum > component->max_cum_pressure) in fg_match_stroke_component()
1372 component->max_cum_pressure = pspan->cum; in fg_match_stroke_component()
1380 min_pressure = (3 * component->max_cum_pressure) >> 2; in fg_match_stroke_component()
1382 min_pressure = component->max_cum_pressure >> 2; in fg_match_stroke_component()
1383 if (component->cum_pressure < min_pressure) in fg_match_stroke_component()
1386 component->delta_mickeys = delta_mickeys; in fg_match_stroke_component()
1398 /* Determine the index of the multi-span. */ in fg_match_strokes_against_pspans()
1406 TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { in fg_match_strokes_against_pspans()
1407 if (strokep->components[axis].matched) in fg_match_strokes_against_pspans()
1415 &strokep->components[axis], &pspans[i], in fg_match_strokes_against_pspans()
1416 strokep->type)) { in fg_match_strokes_against_pspans()
1418 strokep->components[axis].matched = true; in fg_match_strokes_against_pspans()
1420 /* Take care to repeat at the multi-span. */ in fg_match_strokes_against_pspans()
1422 repeat_count--; in fg_match_strokes_against_pspans()
1441 TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) in wsp_match_strokes_against_fingers()
1442 strokep->matched = false; in wsp_match_strokes_against_fingers()
1448 TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { in wsp_match_strokes_against_fingers()
1453 if (strokep->matched) in wsp_match_strokes_against_fingers()
1456 instantaneous_dx = fingers[i].x - strokep->x; in wsp_match_strokes_against_fingers()
1457 instantaneous_dy = fingers[i].y - strokep->y; in wsp_match_strokes_against_fingers()
1475 strokep->matched = true; in wsp_match_strokes_against_fingers()
1476 strokep->instantaneous_dx = fingers[i].x - strokep->x; in wsp_match_strokes_against_fingers()
1477 strokep->instantaneous_dy = fingers[i].y - strokep->y; in wsp_match_strokes_against_fingers()
1478 strokep->x = fingers[i].x; in wsp_match_strokes_against_fingers()
1479 strokep->y = fingers[i].y; in wsp_match_strokes_against_fingers()
1488 * Update strokes by matching against current pressure-spans.
1503 TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { in fg_update_strokes()
1504 strokep->components[X].matched = false; in fg_update_strokes()
1505 strokep->components[Y].matched = false; in fg_update_strokes()
1514 * F = finger-contact in fg_update_strokes()
1517 * +-----------------------+ in fg_update_strokes()
1526 * +-----------------------+ in fg_update_strokes()
1535 * pspan (or a multi-pspan)--in the above illustration, the in fg_update_strokes()
1536 * Y-axis has a repeating pspan. Our approach is to try to in fg_update_strokes()
1537 * match the multi-pspan repeatedly against strokes. The in fg_update_strokes()
1539 * crude repeat_count for matching multi-pspans--i.e. the in fg_update_strokes()
1540 * multi-pspan along the Y axis (above) has a repeat_count of 1. in fg_update_strokes()
1542 repeat_count = abs(n_xpspans - n_ypspans); in fg_update_strokes()
1552 TAILQ_FOREACH_SAFE(strokep, &sc->sc_stroke_used, entry, strokep_next) { in fg_update_strokes()
1553 if (strokep->components[X].matched && in fg_update_strokes()
1554 strokep->components[Y].matched) { in fg_update_strokes()
1555 strokep->matched = true; in fg_update_strokes()
1556 strokep->instantaneous_dx = in fg_update_strokes()
1557 strokep->components[X].delta_mickeys; in fg_update_strokes()
1558 strokep->instantaneous_dy = in fg_update_strokes()
1559 strokep->components[Y].delta_mickeys; in fg_update_strokes()
1607 TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { in fg_update_strokes()
1610 (strokep->flags & ATSF_ZOMBIE) ? "zomb:" : "", in fg_update_strokes()
1611 (strokep->type == ATP_STROKE_TOUCH) ? '[' : '<', in fg_update_strokes()
1612 strokep->components[X].loc, in fg_update_strokes()
1613 strokep->components[X].delta_mickeys, in fg_update_strokes()
1614 strokep->components[X].cum_pressure, in fg_update_strokes()
1615 strokep->components[X].max_cum_pressure, in fg_update_strokes()
1616 (strokep->type == ATP_STROKE_TOUCH) ? ']' : '>', in fg_update_strokes()
1617 (strokep->type == ATP_STROKE_TOUCH) ? '[' : '<', in fg_update_strokes()
1618 strokep->components[Y].loc, in fg_update_strokes()
1619 strokep->components[Y].delta_mickeys, in fg_update_strokes()
1620 strokep->components[Y].cum_pressure, in fg_update_strokes()
1621 strokep->components[Y].max_cum_pressure, in fg_update_strokes()
1622 (strokep->type == ATP_STROKE_TOUCH) ? ']' : '>'); in fg_update_strokes()
1624 if (TAILQ_FIRST(&sc->sc_stroke_used) != NULL) in fg_update_strokes()
1632 * Update strokes by matching against current pressure-spans.
1644 if (sc->sc_n_strokes > 0) { in wsp_update_strokes()
1649 TAILQ_FOREACH_SAFE(strokep, &sc->sc_stroke_used, entry, strokep_next) { in wsp_update_strokes()
1650 if (strokep->matched) in wsp_update_strokes()
1666 /* Initialize a stroke using a pressure-span. */
1682 strokep->type = ATP_STROKE_TOUCH; in fg_add_stroke()
1683 strokep->matched = false; in fg_add_stroke()
1684 microtime(&strokep->ctime); in fg_add_stroke()
1685 strokep->age = 1; /* number of interrupts */ in fg_add_stroke()
1686 strokep->x = pspan_x->loc; in fg_add_stroke()
1687 strokep->y = pspan_y->loc; in fg_add_stroke()
1689 strokep->components[X].loc = pspan_x->loc; in fg_add_stroke()
1690 strokep->components[X].cum_pressure = pspan_x->cum; in fg_add_stroke()
1691 strokep->components[X].max_cum_pressure = pspan_x->cum; in fg_add_stroke()
1692 strokep->components[X].matched = true; in fg_add_stroke()
1694 strokep->components[Y].loc = pspan_y->loc; in fg_add_stroke()
1695 strokep->components[Y].cum_pressure = pspan_y->cum; in fg_add_stroke()
1696 strokep->components[Y].max_cum_pressure = pspan_y->cum; in fg_add_stroke()
1697 strokep->components[Y].matched = true; in fg_add_stroke()
1699 if (sc->sc_n_strokes > 1) { in fg_add_stroke()
1700 /* Reset double-tap-n-drag if we have more than one strokes. */ in fg_add_stroke()
1701 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; in fg_add_stroke()
1705 strokep->components[X].loc, in fg_add_stroke()
1706 strokep->components[Y].loc, in fg_add_stroke()
1707 (u_int)strokep->ctime.tv_sec, in fg_add_stroke()
1708 (unsigned long int)strokep->ctime.tv_usec); in fg_add_stroke()
1740 atp_axis repeat_axis; /* axis with multi-pspans */ in fg_add_new_strokes()
1741 u_int repeat_count; /* repeat count for the multi-pspan*/ in fg_add_new_strokes()
1742 u_int repeat_index = 0; /* index of the multi-span */ in fg_add_new_strokes()
1745 repeat_count = abs(nspans[X] - nspans[Y]); in fg_add_new_strokes()
1758 /* Take care to repeat at the multi-pspan. */ in fg_add_new_strokes()
1762 i--; /* counter loop increment */ in fg_add_new_strokes()
1763 repeat_count--; in fg_add_new_strokes()
1766 j--; /* counter loop increment */ in fg_add_new_strokes()
1767 repeat_count--; in fg_add_new_strokes()
1789 strokep->type = ATP_STROKE_TOUCH; in wsp_add_stroke()
1790 strokep->matched = true; in wsp_add_stroke()
1791 microtime(&strokep->ctime); in wsp_add_stroke()
1792 strokep->age = 1; /* number of interrupts */ in wsp_add_stroke()
1793 strokep->x = fingerp->x; in wsp_add_stroke()
1794 strokep->y = fingerp->y; in wsp_add_stroke()
1796 /* Reset double-tap-n-drag if we have more than one strokes. */ in wsp_add_stroke()
1797 if (sc->sc_n_strokes > 1) in wsp_add_stroke()
1798 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; in wsp_add_stroke()
1800 DPRINTFN(ATP_LLEVEL_INFO, "[%d,%d]\n", strokep->x, strokep->y); in wsp_add_stroke()
1808 if (strokep->flags & ATSF_ZOMBIE) in atp_advance_stroke_state()
1809 strokep->flags &= ~ATSF_ZOMBIE; in atp_advance_stroke_state()
1811 strokep->age++; in atp_advance_stroke_state()
1812 if (strokep->age <= atp_stroke_maturity_threshold) { in atp_advance_stroke_state()
1814 strokep->instantaneous_dx = 0; in atp_advance_stroke_state()
1815 strokep->instantaneous_dy = 0; in atp_advance_stroke_state()
1821 if (strokep->type != ATP_STROKE_TOUCH) in atp_advance_stroke_state()
1824 /* Convert touch strokes to slides upon detecting movement or age. */ in atp_advance_stroke_state()
1825 if ((abs(strokep->cum_movement_x) > atp_slide_min_movement) || in atp_advance_stroke_state()
1826 (abs(strokep->cum_movement_y) > atp_slide_min_movement)) in atp_advance_stroke_state()
1832 if (timevalcmp(&tdiff, &strokep->ctime, >)) { in atp_advance_stroke_state()
1833 timevalsub(&tdiff, &strokep->ctime); in atp_advance_stroke_state()
1846 return (((u_int)abs(strokep->instantaneous_dx) <= in atp_stroke_has_small_movement()
1848 ((u_int)abs(strokep->instantaneous_dy) <= in atp_stroke_has_small_movement()
1861 strokep->pending_dx += strokep->instantaneous_dx; in atp_update_pending_mickeys()
1862 strokep->pending_dy += strokep->instantaneous_dy; in atp_update_pending_mickeys()
1875 (I) = (((I) + (atp_mickeys_scale_factor - 1)) / \ in atp_update_pending_mickeys()
1885 (P) -= ((I) << 1); \ in atp_update_pending_mickeys()
1896 (I) = (((I) - (atp_mickeys_scale_factor - 1)) / \ in atp_update_pending_mickeys()
1906 (P) -= ((I) << 1); \ in atp_update_pending_mickeys()
1913 UPDATE_INSTANTANEOUS_AND_PENDING(strokep->instantaneous_dx, in atp_update_pending_mickeys()
1914 strokep->pending_dx); in atp_update_pending_mickeys()
1915 UPDATE_INSTANTANEOUS_AND_PENDING(strokep->instantaneous_dy, in atp_update_pending_mickeys()
1916 strokep->pending_dy); in atp_update_pending_mickeys()
1936 strokep->pending_dx = 0; in atp_compute_stroke_movement()
1937 strokep->pending_dy = 0; in atp_compute_stroke_movement()
1941 strokep->movement_dx = (strokep->instantaneous_dx) / in atp_compute_stroke_movement()
1943 strokep->movement_dy = (strokep->instantaneous_dy) / in atp_compute_stroke_movement()
1946 if ((abs(strokep->instantaneous_dx) >= ATP_FAST_MOVEMENT_TRESHOLD) || in atp_compute_stroke_movement()
1947 (abs(strokep->instantaneous_dy) >= ATP_FAST_MOVEMENT_TRESHOLD)) { in atp_compute_stroke_movement()
1948 strokep->movement_dx <<= 1; in atp_compute_stroke_movement()
1949 strokep->movement_dy <<= 1; in atp_compute_stroke_movement()
1952 strokep->cum_movement_x += strokep->movement_dx; in atp_compute_stroke_movement()
1953 strokep->cum_movement_y += strokep->movement_dy; in atp_compute_stroke_movement()
1955 return ((strokep->movement_dx != 0) || (strokep->movement_dy != 0)); in atp_compute_stroke_movement()
1959 * Terminate a stroke. Aside from immature strokes, a slide or touch is
1962 * end of a multi-touch gesture.
1967 if (strokep->flags & ATSF_ZOMBIE) in atp_terminate_stroke()
1971 if (strokep->age <= atp_stroke_maturity_threshold) { in atp_terminate_stroke()
1976 strokep->flags |= ATSF_ZOMBIE; in atp_terminate_stroke()
1977 sc->sc_state |= ATP_ZOMBIES_EXIST; in atp_terminate_stroke()
1979 callout_reset(&sc->sc_callout, ATP_ZOMBIE_STROKE_REAP_INTERVAL, in atp_terminate_stroke()
1983 * Reset the double-click-n-drag at the termination of any in atp_terminate_stroke()
1986 if (strokep->type == ATP_STROKE_SLIDE) in atp_terminate_stroke()
1987 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; in atp_terminate_stroke()
1993 if (abs(strokep->cum_movement_x) < atp_slide_min_movement) in atp_is_horizontal_scroll()
1995 if (strokep->cum_movement_y == 0) in atp_is_horizontal_scroll()
1997 return (abs(strokep->cum_movement_x / strokep->cum_movement_y) >= 4); in atp_is_horizontal_scroll()
2003 if (abs(strokep->cum_movement_y) < atp_slide_min_movement) in atp_is_vertical_scroll()
2005 if (strokep->cum_movement_x == 0) in atp_is_vertical_scroll()
2007 return (abs(strokep->cum_movement_y / strokep->cum_movement_x) >= 4); in atp_is_vertical_scroll()
2023 TAILQ_FOREACH_SAFE(strokep, &sc->sc_stroke_used, entry, strokep_next) { in atp_reap_sibling_zombies()
2024 if ((strokep->flags & ATSF_ZOMBIE) == 0) in atp_reap_sibling_zombies()
2027 if (strokep->type == ATP_STROKE_TOUCH) { in atp_reap_sibling_zombies()
2034 horizontal_scroll += strokep->cum_movement_x; in atp_reap_sibling_zombies()
2043 sc->sc_state &= ~ATP_ZOMBIES_EXIST; in atp_reap_sibling_zombies()
2046 if (sc->sc_ibtn != 0) in atp_reap_sibling_zombies()
2052 /* Add a pair of virtual button events (button-down and button-up) if in atp_reap_sibling_zombies()
2061 microtime(&sc->sc_touch_reap_time); /* remember this time */ in atp_reap_sibling_zombies()
2084 /* Switch a given touch stroke to being a slide. */
2088 strokep->type = ATP_STROKE_SLIDE; in atp_convert_to_slide()
2090 /* Are we at the beginning of a double-click-n-drag? */ in atp_convert_to_slide()
2091 if ((sc->sc_n_strokes == 1) && in atp_convert_to_slide()
2092 ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) && in atp_convert_to_slide()
2093 timevalcmp(&strokep->ctime, &sc->sc_touch_reap_time, >)) { in atp_convert_to_slide()
2100 delta = strokep->ctime; in atp_convert_to_slide()
2101 timevalsub(&delta, &sc->sc_touch_reap_time); in atp_convert_to_slide()
2103 sc->sc_state |= ATP_DOUBLE_TAP_DRAG; in atp_convert_to_slide()
2111 usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]); in atp_reset_buf()
2121 dx = imin(dx, 254); dx = imax(dx, -256); in atp_add_to_queue()
2122 dy = imin(dy, 254); dy = imax(dy, -256); in atp_add_to_queue()
2123 dz = imin(dz, 126); dz = imax(dz, -128); in atp_add_to_queue()
2137 buf[0] = sc->sc_mode.syncmask[1]; in atp_add_to_queue()
2141 buf[3] = dx - (dx >> 1); in atp_add_to_queue()
2142 buf[4] = dy - (dy >> 1); in atp_add_to_queue()
2144 if (sc->sc_mode.level == 1) { in atp_add_to_queue()
2146 buf[6] = dz - (dz >> 1); in atp_add_to_queue()
2150 usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, in atp_add_to_queue()
2151 sc->sc_mode.packetsize, 1); in atp_add_to_queue()
2159 if (uaa->usb_mode != USB_MODE_HOST) in atp_probe()
2162 if (uaa->info.bInterfaceClass != UICLASS_HID) in atp_probe()
2166 * (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) doesn't hold true in atp_probe()
2171 return ((uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) ? in atp_probe()
2175 if (uaa->info.bIfaceIndex == WELLSPRING_INTERFACE_INDEX) in atp_probe()
2193 sc->sc_dev = dev; in atp_attach()
2194 sc->sc_usb_device = uaa->device; in atp_attach()
2197 if (usbd_req_get_hid_desc(uaa->device, NULL, &descriptor_ptr, in atp_attach()
2198 &descriptor_len, M_TEMP, uaa->info.bIfaceIndex) != in atp_attach()
2203 sc->sc_expected_sensor_data_len = hid_report_size_max(descriptor_ptr, in atp_attach()
2207 if ((sc->sc_expected_sensor_data_len <= 0) || in atp_attach()
2208 (sc->sc_expected_sensor_data_len > ATP_SENSOR_DATA_BUF_MAX)) { in atp_attach()
2210 sc->sc_expected_sensor_data_len); in atp_attach()
2215 sc->sc_family = DECODE_FAMILY_FROM_DRIVER_INFO(di); in atp_attach()
2220 * limited information--they encode movement deltas and button in atp_attach()
2221 * events,--but do not include data from the pressure in atp_attach()
2223 * reports to raw sensor data using vendor-specific USB in atp_attach()
2228 if ((sc->sc_family == TRACKPAD_FAMILY_FOUNTAIN_GEYSER) && in atp_attach()
2236 mtx_init(&sc->sc_mutex, "atpmtx", NULL, MTX_DEF | MTX_RECURSE); in atp_attach()
2238 switch(sc->sc_family) { in atp_attach()
2240 sc->sc_params = in atp_attach()
2242 sc->sensor_data_interpreter = fg_interpret_sensor_data; in atp_attach()
2245 sc->sc_params = in atp_attach()
2247 sc->sensor_data_interpreter = wsp_interpret_sensor_data; in atp_attach()
2253 err = usbd_transfer_setup(uaa->device, in atp_attach()
2254 &uaa->info.bIfaceIndex, sc->sc_xfer, atp_xfer_config, in atp_attach()
2255 ATP_N_TRANSFER, sc, &sc->sc_mutex); in atp_attach()
2261 if (usb_fifo_attach(sc->sc_usb_device, sc, &sc->sc_mutex, in atp_attach()
2262 &atp_fifo_methods, &sc->sc_fifo, in atp_attach()
2263 device_get_unit(dev), -1, uaa->info.bIfaceIndex, in atp_attach()
2270 sc->sc_hw.buttons = 3; in atp_attach()
2271 sc->sc_hw.iftype = MOUSE_IF_USB; in atp_attach()
2272 sc->sc_hw.type = MOUSE_PAD; in atp_attach()
2273 sc->sc_hw.model = MOUSE_MODEL_GENERIC; in atp_attach()
2274 sc->sc_hw.hwid = 0; in atp_attach()
2275 sc->sc_mode.protocol = MOUSE_PROTO_MSC; in atp_attach()
2276 sc->sc_mode.rate = -1; in atp_attach()
2277 sc->sc_mode.resolution = MOUSE_RES_UNKNOWN; in atp_attach()
2278 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; in atp_attach()
2279 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; in atp_attach()
2280 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; in atp_attach()
2281 sc->sc_mode.accelfactor = 0; in atp_attach()
2282 sc->sc_mode.level = 0; in atp_attach()
2284 sc->sc_state = 0; in atp_attach()
2285 sc->sc_ibtn = 0; in atp_attach()
2287 callout_init_mtx(&sc->sc_callout, &sc->sc_mutex, 0); in atp_attach()
2304 mtx_lock(&sc->sc_mutex); in atp_detach()
2305 callout_drain(&sc->sc_callout); in atp_detach()
2306 if (sc->sc_state & ATP_ENABLED) in atp_detach()
2308 mtx_unlock(&sc->sc_mutex); in atp_detach()
2310 usb_fifo_detach(&sc->sc_fifo); in atp_detach()
2312 usbd_transfer_unsetup(sc->sc_xfer, ATP_N_TRANSFER); in atp_detach()
2314 mtx_destroy(&sc->sc_mutex); in atp_detach()
2331 usbd_copy_out(pc, 0, sc->sc_sensor_data, len); in atp_intr()
2332 if (len < sc->sc_expected_sensor_data_len) { in atp_intr()
2334 memset(sc->sc_sensor_data + len, 0, in atp_intr()
2335 sc->sc_expected_sensor_data_len - len); in atp_intr()
2338 sc->sc_status.flags &= ~(MOUSE_STDBUTTONSCHANGED | in atp_intr()
2340 sc->sc_status.obutton = sc->sc_status.button; in atp_intr()
2342 (sc->sensor_data_interpreter)(sc, len); in atp_intr()
2344 if (sc->sc_status.button != 0) { in atp_intr()
2346 sc->sc_state &= ~ATP_DOUBLE_TAP_DRAG; in atp_intr()
2347 } else if (sc->sc_state & ATP_DOUBLE_TAP_DRAG) { in atp_intr()
2348 /* Assume a button-press with DOUBLE_TAP_N_DRAG. */ in atp_intr()
2349 sc->sc_status.button = MOUSE_BUTTON1DOWN; in atp_intr()
2352 sc->sc_status.flags |= in atp_intr()
2353 sc->sc_status.button ^ sc->sc_status.obutton; in atp_intr()
2354 if (sc->sc_status.flags & MOUSE_STDBUTTONSCHANGED) { in atp_intr()
2356 ((sc->sc_status.button & MOUSE_BUTTON1DOWN) ? in atp_intr()
2360 if (sc->sc_status.flags & (MOUSE_POSCHANGED | in atp_intr()
2368 TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { in atp_intr()
2369 if (strokep->flags & ATSF_ZOMBIE) in atp_intr()
2372 dx += strokep->movement_dx; in atp_intr()
2373 dy += strokep->movement_dy; in atp_intr()
2374 if (strokep->movement_dx || in atp_intr()
2375 strokep->movement_dy) in atp_intr()
2385 /* detect multi-finger vertical scrolls */ in atp_intr()
2388 TAILQ_FOREACH(strokep, &sc->sc_stroke_used, entry) { in atp_intr()
2389 if (strokep->flags & ATSF_ZOMBIE) in atp_intr()
2401 sc->sc_status.dx += dx; in atp_intr()
2402 sc->sc_status.dy += dy; in atp_intr()
2403 sc->sc_status.dz += dz; in atp_intr()
2404 atp_add_to_queue(sc, dx, -dy, -dz, sc->sc_status.button); in atp_intr()
2410 if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) != 0) { in atp_intr()
2412 sc->sc_expected_sensor_data_len); in atp_intr()
2434 rate = sc->sc_pollrate; in atp_start_read()
2439 if ((rate > 0) && (sc->sc_xfer[ATP_INTR_DT] != NULL)) { in atp_start_read()
2441 usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); in atp_start_read()
2443 usbd_xfer_set_interval(sc->sc_xfer[ATP_INTR_DT], 1000 / rate); in atp_start_read()
2445 sc->sc_pollrate = 0; in atp_start_read()
2448 usbd_transfer_start(sc->sc_xfer[ATP_INTR_DT]); in atp_start_read()
2455 usbd_transfer_stop(sc->sc_xfer[ATP_INTR_DT]); in atp_stop_read()
2464 if (sc->sc_fflags & fflags) in atp_open()
2468 if (sc->sc_fflags == 0) { in atp_open()
2481 sc->sc_fflags |= (fflags & (FREAD | FWRITE)); in atp_open()
2492 sc->sc_fflags &= ~(fflags & (FREAD | FWRITE)); in atp_close()
2493 if (sc->sc_fflags == 0) { in atp_close()
2505 mtx_lock(&sc->sc_mutex); in atp_ioctl()
2509 *(mousehw_t *)addr = sc->sc_hw; in atp_ioctl()
2512 *(mousemode_t *)addr = sc->sc_mode; in atp_ioctl()
2517 if (mode.level == -1) in atp_ioctl()
2524 sc->sc_mode.level = mode.level; in atp_ioctl()
2525 sc->sc_pollrate = mode.rate; in atp_ioctl()
2526 sc->sc_hw.buttons = 3; in atp_ioctl()
2528 if (sc->sc_mode.level == 0) { in atp_ioctl()
2529 sc->sc_mode.protocol = MOUSE_PROTO_MSC; in atp_ioctl()
2530 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; in atp_ioctl()
2531 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; in atp_ioctl()
2532 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; in atp_ioctl()
2533 } else if (sc->sc_mode.level == 1) { in atp_ioctl()
2534 sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; in atp_ioctl()
2535 sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; in atp_ioctl()
2536 sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; in atp_ioctl()
2537 sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; in atp_ioctl()
2542 *(int *)addr = sc->sc_mode.level; in atp_ioctl()
2549 sc->sc_mode.level = *(int *)addr; in atp_ioctl()
2550 sc->sc_hw.buttons = 3; in atp_ioctl()
2552 if (sc->sc_mode.level == 0) { in atp_ioctl()
2553 sc->sc_mode.protocol = MOUSE_PROTO_MSC; in atp_ioctl()
2554 sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; in atp_ioctl()
2555 sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; in atp_ioctl()
2556 sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; in atp_ioctl()
2557 } else if (sc->sc_mode.level == 1) { in atp_ioctl()
2558 sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; in atp_ioctl()
2559 sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; in atp_ioctl()
2560 sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; in atp_ioctl()
2561 sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; in atp_ioctl()
2568 *status = sc->sc_status; in atp_ioctl()
2569 sc->sc_status.obutton = sc->sc_status.button; in atp_ioctl()
2570 sc->sc_status.button = 0; in atp_ioctl()
2571 sc->sc_status.dx = 0; in atp_ioctl()
2572 sc->sc_status.dy = 0; in atp_ioctl()
2573 sc->sc_status.dz = 0; in atp_ioctl()
2575 if (status->dx || status->dy || status->dz) in atp_ioctl()
2576 status->flags |= MOUSE_POSCHANGED; in atp_ioctl()
2577 if (status->button != status->obutton) in atp_ioctl()
2578 status->flags |= MOUSE_BUTTONSCHANGED; in atp_ioctl()
2587 mtx_unlock(&sc->sc_mutex); in atp_ioctl()
2599 if (error != 0 || req->newptr == NULL) in atp_sysctl_scale_factor_handler()