Index: sys/dev/atkbdc/psm.c =================================================================== RCS file: /home/dumbbell/projects/freebsd/cvs-mirror/src/sys/dev/atkbdc/psm.c,v retrieving revision 1.94 diff -u -r1.94 psm.c --- sys/dev/atkbdc/psm.c 25 Feb 2008 13:57:18 -0000 1.94 +++ sys/dev/atkbdc/psm.c 5 Mar 2008 15:35:03 -0000 @@ -171,8 +171,47 @@ int low_speed_threshold; int min_movement; int squelch_level; + int min_pressure; + int max_pressure; + int max_width; + int window_min; + int window_max; + int weight_current; + int weight_previous; + int weight_len_squared; + int div_min; + int div_max; + int div_len; + int tap_max_delta; + int tap_min_queue; + int taphold_timeout; } synapticsinfo_t; +typedef struct synapticspacket { + int x; + int y; +} synapticspacket_t; + +#define SYNAPTICS_PACKETQUEUE 10 +#define SYNAPTICS_QUEUE_CURSOR(x) \ + (x + SYNAPTICS_PACKETQUEUE) % SYNAPTICS_PACKETQUEUE + +typedef struct synapticsaction { + synapticspacket_t queue[SYNAPTICS_PACKETQUEUE]; + int queue_len; + int queue_cursor; + int window_min; + int start_x; + int start_y; + double avg_dx; + double avg_dy; + double squelch_x; + double squelch_y; + int fingers_nb; + int tap_button; + int in_taphold; +} synapticsaction_t; + /* driver control block */ struct psm_softc { /* Driver status information */ int unit; @@ -186,6 +225,7 @@ mousehw_t hw; /* hardware information */ synapticshw_t synhw; /* Synaptics-specific hardware information */ synapticsinfo_t syninfo; /* Synaptics-specific configuration */ + synapticsaction_t synaction; /* Synaptics-specific action context */ mousemode_t mode; /* operation mode */ mousemode_t dflt_mode; /* default operation mode */ mousestatus_t status; /* accumulated mouse movement */ @@ -769,6 +809,34 @@ { int stat[3]; + /* + * FIXME: Synaptics TouchPad seems to go back to Relative Mode with + * no obvious reason. Thus we check the current mode and restore the + * Absolute Mode if it was cleared. + * + * The previous hack at the end of psmprobe() wasn't efficient when + * moused(8) was restarted. + * + * A Reset (FF) or Set Defaults (F6) command would clear the + * Absolute Mode bit. But a verbose boot or debug.psm.loglevel=5 + * doesn't show any evidence of such a command. + */ + if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) { + mouse_ext_command(sc->kbdc, 1); + get_mouse_status(sc->kbdc, stat, 0, 3); + if (stat[1] == 0x47 && stat[2] == 0x40) { + /* Set the mode byte -- request wmode where available */ + if (sc->synhw.capExtended) + mouse_ext_command(sc->kbdc, 0xc1); + else + mouse_ext_command(sc->kbdc, 0xc0); + set_mouse_sampling_rate(sc->kbdc, 20); + VLOG(5, (LOG_DEBUG, + "psm%d: Synaptis Absolute Mode hopefully restored\n", + sc->unit)); + } + } + /* enable the mouse device */ if (!enable_aux_dev(sc->kbdc)) { /* MOUSE ERROR: failed to enable the mouse because: @@ -1251,16 +1319,6 @@ endprobe(ENXIO); } - /* - * Synaptics TouchPad seems to go back to Relative Mode after - * the previous set_controller_command_byte() call; by issueing - * a Read Mode Byte command, the touchpad is in Absolute Mode - * again. - */ - if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) { - mouse_ext_command(sc->kbdc, 1); - } - /* done */ kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS); kbdc_lock(sc->kbdc, FALSE); @@ -2235,7 +2293,7 @@ int w, x, y, z; int c; int l; - int x0, y0, xavg, yavg, xsensitivity, ysensitivity, sensitivity = 0; + int x0, y0; int s; packetbuf_t *pb; @@ -2560,22 +2618,44 @@ (pb->ipacket[3] & 0xc8) != 0xc0) goto NEXT; - x = y = x0 = y0 = 0; + x = y = 0; - /* Pressure value. */ + /* + * Pressure value. + * Interpretation: + * z = 0 No finger contact + * z = 10 Finger hovering near the pad + * z = 30 Very light finger contact + * z = 80 Normal finger contact + * z = 110 Very heavy finger contact + * z = 200 Finger lying flat on pad surface + * z = 255 Maximum reportable Z + */ z = pb->ipacket[2]; - /* Finger width value */ + /* + * Finger width value. + * Interpretation: + * w = 0 Two finger on the pad (capMultiFinger needed) + * w = 1 Three or more fingers (capMultiFinger needed) + * w = 2 Pen (instead of finger) (capPen needed) + * w = 3 Reserved (passthrough?) + * w = 4-7 Finger of normal width (capPalmDetect needed) + * w = 8-14 Very wide finger or palm (capPalmDetect needed) + * w = 15 Maximum reportable width (capPalmDetect needed) + */ + /* XXX Is checking capExtended enough? */ if (sc->synhw.capExtended) { w = ((pb->ipacket[0] & 0x30) >> 2) | ((pb->ipacket[0] & 0x04) >> 1) | ((pb->ipacket[3] & 0x04) >> 2); } else { - /* Assume a finger of regular width */ + /* Assume a finger of regular width. */ w = 4; } - /* Handle packets from the guest device */ + /* Handle packets from the guest device. */ + /* XXX Documentation? */ if (w == 3 && sc->synhw.capPassthrough) { x = ((pb->ipacket[1] & 0x10) ? pb->ipacket[4] - 256 : pb->ipacket[4]); @@ -2592,7 +2672,7 @@ guest_buttons |= MOUSE_BUTTON3DOWN; ms.button = touchpad_buttons | guest_buttons; - break; + goto SYNAPTICS_END; } /* Button presses */ @@ -2614,6 +2694,7 @@ * the packet indicates that we have an extended * button press. */ + /* XXX Documentation? */ if (pb->ipacket[3] & 0x02) { /* * if directional_scrolls is not 1, we treat @@ -2636,9 +2717,54 @@ } ms.button = touchpad_buttons | guest_buttons; - - /* There is a finger on the pad. */ - if ((w >= 4 && w <= 7) && (z >= 16 && z < 200)) { + + /* Check pressure to detect a real wanted action on the + * touchpad. */ + if (z >= sc->syninfo.min_pressure) { + synapticsaction_t *synaction; + int cursor, peer, window; + int dx, dy, dxp, dyp; + int max_width, max_pressure; + int window_min, window_max; + int weight_current, weight_previous, weight_len_squared; + int div_min, div_max, div_len; + int len, weight_previous2, div; + + /* Read sysctl. */ + /* XXX Verify values? */ + max_width = sc->syninfo.max_width; + max_pressure = sc->syninfo.max_pressure; + window_min = sc->syninfo.window_min; + window_max = sc->syninfo.window_max; + weight_current = sc->syninfo.weight_current; + weight_previous = sc->syninfo.weight_previous; + weight_len_squared = sc->syninfo.weight_len_squared; + div_min = sc->syninfo.div_min; + div_max = sc->syninfo.div_max; + div_len = sc->syninfo.div_len; + + /* Palm detection. */ + if (!( + (sc->synhw.capMultiFinger && (w == 0 || w == 1)) || + (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) || + (!sc->synhw.capPalmDetect && z <= max_pressure) || + (sc->synhw.capPen && w == 2))) { + /* + * We consider the packet irrelevant for the current + * action when: + * - the width isn't comprised in: + * [4; max_width] + * - the pressure isn't comprised in: + * [min_pressure; max_pressure] + * - pen aren't supported but w is 2 + * + * Note that this doesn't terminate the current action. + */ + VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", w)); + goto SYNAPTICS_END; + } + + /* Read current absolute position. */ x0 = ((pb->ipacket[3] & 0x10) << 8) | ((pb->ipacket[1] & 0x0f) << 8) | pb->ipacket[4]; @@ -2646,127 +2772,240 @@ ((pb->ipacket[1] & 0xf0) << 4) | pb->ipacket[5]; - if (sc->flags & PSM_FLAGS_FINGERDOWN) { - x = x0 - sc->xold; - y = y0 - sc->yold; + VLOG(5, (LOG_DEBUG, "synaptics: ipacket: [%d, %d]\n", + x0, y0)); - /* we compute averages of x and y movement */ - if (sc->xaverage == 0) - sc->xaverage=x; - - if (sc->yaverage == 0) - sc->yaverage=y; - - xavg = sc->xaverage; - yavg = sc->yaverage; - - sc->xaverage = (xavg + x) >> 1; - sc->yaverage = (yavg + y) >> 1; - - /* - * then use the averages to compute a sensitivity level - * in each dimension - */ - xsensitivity = (sc->xaverage - xavg); - if (xsensitivity < 0) - xsensitivity = -xsensitivity; - - ysensitivity = (sc->yaverage - yavg); - if (ysensitivity < 0) - ysensitivity = -ysensitivity; - - /* - * The sensitivity level is higher the faster the finger - * is moving. It also tends to be higher in the middle - * of a touchpad motion than on either end - * - * Note - sensitivity gets to 0 when moving slowly - so - * we add 1 to it to give it a meaningful value in that case. - */ - sensitivity = (xsensitivity & ysensitivity)+1; + synaction = &(sc->synaction); - /* - * If either our x or y change is greater than our - * hi/low speed threshold - we do the high-speed - * absolute to relative calculation otherwise we - * do the low-speed calculation. - */ - if ((x>sc->syninfo.low_speed_threshold || - x<-sc->syninfo.low_speed_threshold) || - (y>sc->syninfo.low_speed_threshold || - y<-sc->syninfo.low_speed_threshold)) { - x0 = (x0 + sc->xold * 3) / 4; - y0 = (y0 + sc->yold * 3) / 4; - x = (x0 - sc->xold) * 10 / 85; - y = (y0 - sc->yold) * 10 / 85; - } else { - /* - * This is the low speed calculation. - * We simply check to see if our movement - * is more than our minimum movement threshold - * and if it is - set the movement to 1 in the - * correct direction. - * NOTE - Normally this would result in pointer - * movement that was WAY too fast. This works - * due to the movement squelch we do later. - */ - if (x < -sc->syninfo.min_movement) - x = -1; - else if (x > sc->syninfo.min_movement) - x = 1; - else - x = 0; - if (y < -sc->syninfo.min_movement) - y = -1; - else if (y > sc->syninfo.min_movement) - y = 1; - else - y = 0; + /* If the action is just beginning, init the structure and + * compute tap timeout. */ + if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) { + VLOG(3, (LOG_DEBUG, "synaptics: ----\n")); + + /* Store the first point of this action. */ + synaction->start_x = x0; + synaction->start_y = y0; + dx = dy = 0; + + /* Initialize queue. */ + synaction->queue_cursor = SYNAPTICS_PACKETQUEUE; + synaction->queue_len = 0; + synaction->window_min = window_min; + + /* Reset average. */ + synaction->avg_dx = 0; + synaction->avg_dy = 0; + + /* Reset squelch. */ + synaction->squelch_x = 0; + synaction->squelch_y = 0; + + /* Reset pressure peak. */ + sc->zmax = 0; + + /* Reset fingers count. */ + synaction->fingers_nb = 0; + + /* Compute tap timeout. */ + sc->taptimeout.tv_sec = tap_timeout / 1000000; + sc->taptimeout.tv_usec = tap_timeout % 1000000; + timevaladd(&sc->taptimeout, &sc->lastsoftintr); - } - } else { sc->flags |= PSM_FLAGS_FINGERDOWN; + } else { + /* Calculate the current delta. */ + cursor = synaction->queue_cursor; + dx = x0 - synaction->queue[cursor].x; + dy = y0 - synaction->queue[cursor].y; } - /* - * ok - the squelch process. Take our sensitivity value - * and add it to the current squelch value - if squelch - * is less than our squelch threshold we kill the movement, - * otherwise we reset squelch and pass the movement through. - * Since squelch is cumulative - when mouse movement is slow - * (around sensitivity 1) the net result is that only - * 1 out of every squelch_level packets is - * delivered, effectively slowing down the movement. - */ - sc->squelch += sensitivity; - if (sc->squelch < sc->syninfo.squelch_level) { - x = 0; - y = 0; - } else - sc->squelch = 0; - - sc->xold = x0; - sc->yold = y0; + /* Queue this new packet. */ + cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1); + synaction->queue[cursor].x = x0; + synaction->queue[cursor].y = y0; + synaction->queue_cursor = cursor; + if (synaction->queue_len < SYNAPTICS_PACKETQUEUE) + synaction->queue_len++; + VLOG(5, (LOG_DEBUG, + "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n", + cursor, x0, y0, dx, dy)); + + /* For tap, we keep the maximum number of fingers and the + * pressure peak. Also with multiple fingers, we increase + * the minimum window. */ + switch (w) { + case 1: /* Three or more fingers. */ + synaction->fingers_nb = imax(3, synaction->fingers_nb); + synaction->window_min = window_max; + break; + case 0: /* Two fingers. */ + synaction->fingers_nb = imax(2, synaction->fingers_nb); + synaction->window_min = window_max; + break; + default: /* One finger or undetectable. */ + synaction->fingers_nb = imax(1, synaction->fingers_nb); + } sc->zmax = imax(z, sc->zmax); - } else { + + /* If in tap-hold, add the recorded button. */ + if (synaction->in_taphold) + ms.button |= synaction->tap_button; + + /* Do we have enough packets to consider this a movement? */ + if (synaction->queue_len < synaction->window_min) + goto SYNAPTICS_END; + + /* Calculate weights for the average operands and + * the divider. Both depend on the distance between + * the current packet and a previous one (based on the + * window width). */ + window = imin(synaction->queue_len, window_max); + peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1); + dxp = abs(x0 - synaction->queue[peer].x) + 1; + dyp = abs(y0 - synaction->queue[peer].y) + 1; + len = (dxp * dxp) + (dyp * dyp); + weight_previous2 = weight_len_squared * weight_previous / len; + weight_previous2 = imin(weight_previous, weight_previous2); + + len = (dxp + dyp) / 2; + div = div_len * div_max / len; + div = imin(div_max, div); + div = imax(div_min, div); + + VLOG(5, (LOG_DEBUG, + "synaptics: peer=%d, len=%d, weight=%d, div=%d\n", + peer, len, weight_previous2, div)); + + /* Compute averages. */ + synaction->avg_dx = + (weight_current * dx + + weight_previous2 * synaction->avg_dx) / + (weight_current + weight_previous2); + + synaction->avg_dy = + (weight_current * dy + + weight_previous2 * synaction->avg_dy) / + (weight_current + weight_previous2); + + VLOG(5, (LOG_DEBUG, + "synaptics: avg_dx~=%d, avg_dy~=%d\n", + (int)synaction->avg_dx, (int)synaction->avg_dy)); + + /* Use these averages to calculate x & y. */ + synaction->squelch_x += synaction->avg_dx; + x = (int)synaction->squelch_x / div; + synaction->squelch_x -= (int)synaction->squelch_x / div * div; + + synaction->squelch_y += synaction->avg_dy; + y = (int)synaction->squelch_y / div; + synaction->squelch_y -= (int)synaction->squelch_y / div * div; + + VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n", + dx, dy, x, y)); + } else if (sc->flags & PSM_FLAGS_FINGERDOWN) { + /* An action is currently taking place but the pressure + * dropped under the minimum, putting an end to it. */ + synapticsaction_t *synaction; + int taphold_timeout, dx, dy, tap_max_delta; + + synaction = &(sc->synaction); + dx = abs(synaction->queue[synaction->queue_cursor].x - + synaction->start_x); + dy = abs(synaction->queue[synaction->queue_cursor].y - + synaction->start_y); + + /* Max delta is disabled for multi-fingers tap. */ + if (synaction->fingers_nb > 1) + tap_max_delta = imax(dx, dy); + else + tap_max_delta = sc->syninfo.tap_max_delta; + sc->flags &= ~PSM_FLAGS_FINGERDOWN; - if (sc->zmax > tap_threshold && - timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) { - if (w == 0) - ms.button |= MOUSE_BUTTON3DOWN; - else if (w == 1) - ms.button |= MOUSE_BUTTON2DOWN; - else - ms.button |= MOUSE_BUTTON1DOWN; + /* Check for tap. */ + VLOG(3, (LOG_DEBUG, + "synaptics: zmax=%d, dx=%d, dy=%d, " + "delta=%d, fingers=%d, queue=%d\n", + sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb, + synaction->queue_len)); + if (sc->zmax >= tap_threshold && + timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) && + dx <= tap_max_delta && dy <= tap_max_delta && + synaction->queue_len >= sc->syninfo.tap_min_queue) { + /* + * We have a tap if: + * - the maximum pressure went over tap_threshold + * - the action ended before tap_timeout + * + * To handle tap-hold, we must delay any button push to + * the next action. + */ + if (synaction->in_taphold) { + /* This is the second and last tap of a double tap + * action, not a tap-hold */ + synaction->in_taphold = 0; + + /* For double-tap to work: + * - no button press is emitted (to simulate a + * button release) + * - PSM_FLAGS_FINGERDOWN is set to force the next + * packet to emit a button press) + */ + VLOG(2, (LOG_DEBUG, + "synaptics: button RELEASE: %d\n", + synaction->tap_button)); + sc->flags |= PSM_FLAGS_FINGERDOWN; + } else { + /* This is the first tap: we set the tap-hold state + * and notify the button down event. */ + synaction->in_taphold = 1; + taphold_timeout = sc->syninfo.taphold_timeout; + sc->taptimeout.tv_sec = taphold_timeout / 1000000; + sc->taptimeout.tv_usec = taphold_timeout % 1000000; + timevaladd(&sc->taptimeout, &sc->lastsoftintr); + + switch (synaction->fingers_nb) { + case 3: + synaction->tap_button = MOUSE_BUTTON2DOWN; + break; + case 2: + synaction->tap_button = MOUSE_BUTTON3DOWN; + break; + default: + synaction->tap_button = MOUSE_BUTTON1DOWN; + } + VLOG(2, (LOG_DEBUG, + "synaptics: button PRESS: %d\n", + synaction->tap_button)); + ms.button |= synaction->tap_button; + } + } else { + /* Not enough pressure or timeout: reset tap-hold state. */ + if (synaction->in_taphold) { + VLOG(2, (LOG_DEBUG, + "synaptics: button RELEASE: %d\n", + synaction->tap_button)); + synaction->in_taphold = 0; + } else { + VLOG(2, (LOG_DEBUG, "synaptics: not a tap-hold\n")); + } + } + } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && + sc->synaction.in_taphold) { + /* For a tap-hold to work, the button must remain down at + * least until timeout (where the in_taphold flags will be + * cleared) or during the next action. */ + if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) { + ms.button |= sc->synaction.tap_button; + } else { + VLOG(2, (LOG_DEBUG, + "synaptics: button RELEASE: %d\n", + sc->synaction.tap_button)); + sc->synaction.in_taphold = 0; } - - sc->zmax = 0; - sc->taptimeout.tv_sec = tap_timeout / 1000000; - sc->taptimeout.tv_usec = tap_timeout % 1000000; - timevaladd(&sc->taptimeout, &sc->lastsoftintr); } +SYNAPTICS_END: /* Use the extra buttons as a scrollwheel */ if (ms.button & MOUSE_BUTTON4DOWN) z = -1; @@ -3291,6 +3530,8 @@ /* * Synaptics_low_speed_threshold - the number of touchpad units * below-which we go into low-speed tracking mode. + * + * XXX Deprecated. */ sc->syninfo.low_speed_threshold = 20; SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, @@ -3302,6 +3543,8 @@ /* * Synaptics_min_movement - the number of touchpad units below * which we ignore altogether. + * + * XXX Deprecated. */ sc->syninfo.min_movement = 2; SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, @@ -3316,6 +3559,8 @@ * * This effectively sends 1 out of every synaptics_squelch_level * packets when * running in low-speed mode. + * + * XXX Deprecated. */ sc->syninfo.squelch_level=3; SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, @@ -3324,7 +3569,174 @@ &sc->syninfo.squelch_level, 0, "squelch level for synaptics touchpads"); + /* + * Synaptics_min_pressure - minimum pressure required to start an + * action. + * + * The pressure ranges from 0 to 255. + */ + sc->syninfo.min_pressure = 16; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "min_pressure", CTLFLAG_RW, + &sc->syninfo.min_pressure, 0, + "minimum pressure to start an action"); + + /* + * Synaptics_max_pressure - maximum pressure above which a packet is + * ignored. + * + * This is the case for an accidental contact with the palm for example. + */ + sc->syninfo.max_pressure = 220; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "max_pressure", CTLFLAG_RW, + &sc->syninfo.max_pressure, 0, + "maximum pressure to detect palm"); + + /* + * Synaptics_max_width - maximum finger width above which a packet + * is ignored. + * + * See max_pressure above. + * + * The width ranges from 4 to 15. + */ + sc->syninfo.max_width = 10; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "max_width", CTLFLAG_RW, + &sc->syninfo.max_width, 0, + "maximum finger width to detect palm"); + + /* + * Synaptics_window_min - minimum number of packets to consider a + * real movement. + * + * The window ranges from 0 to SYNAPTICS_PACKETQUEUE. + */ + sc->syninfo.window_min = 4; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "window_min", CTLFLAG_RW, + &sc->syninfo.window_min, 0, + "minimum window size to start an action"); + + /* + * Synaptics_window_max - maximum number of packets to use to + * calculate the movement. + * + * The window ranges from 0 to SYNAPTICS_PACKETQUEUE. + */ + sc->syninfo.window_max = 10; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "window_max", CTLFLAG_RW, + &sc->syninfo.window_max, 0, + "maximum window size"); + + /* + * Synaptics_weight_current - weight of the current delta in the + * average. + */ + sc->syninfo.weight_current = 3; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "weight_current", CTLFLAG_RW, + &sc->syninfo.weight_current, 0, + "weight for the current movement"); + + /* + * Synaptics_weight_previous - weight of the previous data in the + * average. + */ + sc->syninfo.weight_previous = 6; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "weight_previous", CTLFLAG_RW, + &sc->syninfo.weight_previous, 0, + "weight for the previous movements"); + + /* + * Synaptics_weight_len_squared - length squared of the longest + * segment which uses the full weight_previous. Above this, the + * longer the segment, the smaller the weight_previous. + */ + sc->syninfo.weight_len_squared = 2000; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "weight_len_squared", CTLFLAG_RW, + &sc->syninfo.weight_len_squared, 0, + "length squared for segments where weight_previous starts to decrease"); + + /* + * Synaptics_div_min - divisor for long segment. + */ + sc->syninfo.div_min = 9; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "div_min", CTLFLAG_RW, + &sc->syninfo.div_min, 0, + "divider with fast movements"); + + /* + * Synaptics_div_max - divisor for short segment. See div_min above. + */ + sc->syninfo.div_max = 17; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "div_max", CTLFLAG_RW, + &sc->syninfo.div_max, 0, + "divider with slow movements"); + + /* + * Synaptics_div_len - length of the longest segment which uses the + * full div_max. Above this, the longer the segment, the smaller the + * divisor. + */ + sc->syninfo.div_len = 100; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "div_len", CTLFLAG_RW, + &sc->syninfo.div_len, 0, + "length squared for segments where div_max starts to decrease"); + + /* + * Synaptics_tap_max_delta - length of the segment above which a tap + * is ignored. + */ + sc->syninfo.tap_max_delta = 80; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "tap_max_delta", CTLFLAG_RW, + &sc->syninfo.tap_max_delta, 0, + "tap maximum delta"); + + /* + * Synaptics_tap_min_queue - number of packets required to consider + * a tap. + */ + sc->syninfo.tap_min_queue = 2; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "tap_min_queue", CTLFLAG_RW, + &sc->syninfo.tap_min_queue, 0, + "tap minimum queue length"); + + /* + * Synaptics_taphold_timeout - timeout for tap-hold action. + */ + sc->synaction.in_taphold = 0; + sc->syninfo.taphold_timeout = tap_timeout; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "taphold_timeout", CTLFLAG_RW, + &sc->syninfo.taphold_timeout, 0, + "tap-hold timeout"); + kbdc = sc->kbdc; + VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n")); disable_aux_dev(kbdc); sc->hw.buttons = 3; sc->squelch = 0; @@ -3454,8 +3866,6 @@ mouse_ext_command(kbdc, 0xc1); else mouse_ext_command(kbdc, 0xc0); - - /* Reset the sampling rate */ set_mouse_sampling_rate(kbdc, 20); /* @@ -3466,6 +3876,8 @@ if (sc->synhw.capExtended && sc->synhw.capFourButtons) sc->hw.buttons = 4; + VLOG(3, (LOG_DEBUG, "synaptics: END init\n")); + return (TRUE); }