Index: sys/dev/atkbdc/psm.c =================================================================== RCS file: /home/dumbbell/projects/freebsd/cvs/src/sys/dev/atkbdc/psm.c,v retrieving revision 1.88 diff -u -r1.88 psm.c --- sys/dev/atkbdc/psm.c 5 Jan 2006 19:24:01 -0000 1.88 +++ sys/dev/atkbdc/psm.c 21 Feb 2006 00:51:16 -0000 @@ -165,14 +165,43 @@ #endif typedef struct synapticsinfo { - struct sysctl_ctx_list sysctl_ctx; - struct sysctl_oid *sysctl_tree; - int directional_scrolls; - int low_speed_threshold; - int min_movement; - int squelch_level; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + int directional_scrolls; + int min_pressure; + int max_pressure; + int max_width; + int queue_window; + int taphold_timeout; + int low_speed_threshold; + int high_speed_accel; + int min_movement; + int squelch_level; + int scroll_squelch_level; } synapticsinfo_t; +typedef struct synapticspacket { + int x; + int y; + int dx; + int dy; + int z; + int w; +} synapticspacket_t; + +#define SYNAPTICS_QUEUE_MAX_LEN 10 +typedef struct synapticsaction { + synapticspacket_t queue[SYNAPTICS_QUEUE_MAX_LEN]; + int queue_len; + int min_queue_len; + int start_x; + int start_y; + int squelch_x; + int squelch_y; + int fingers_nb; + int in_taphold; +} synapticsaction_t; + /* driver control block */ struct psm_softc { /* Driver status information */ int unit; @@ -186,6 +215,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 */ @@ -1251,6 +1281,16 @@ 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); @@ -2624,146 +2664,419 @@ } ms.button = touchpad_buttons | guest_buttons; - - /* There is a finger on the pad. */ - if ((w >= 4 && w <= 7) && (z >= 16 && z < 200)) { - x0 = ((pb->ipacket[3] & 0x10) << 8) | - ((pb->ipacket[1] & 0x0f) << 8) | - pb->ipacket[4]; - y0 = ((pb->ipacket[3] & 0x20) << 7) | - ((pb->ipacket[1] & 0xf0) << 4) | - pb->ipacket[5]; - - if (sc->flags & PSM_FLAGS_FINGERDOWN) { - x = x0 - sc->xold; - y = y0 - sc->yold; - - /* 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; - /* - * 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; - - } - } else { - sc->flags |= PSM_FLAGS_FINGERDOWN; + if (z != 0 || w != 0) { + VLOG(5, (LOG_DEBUG, + "psm%d/synaptics: ===> z=%d, w=%d\n", + sc->unit, z, w)); } - /* - * 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; - sc->zmax = imax(z, sc->zmax); - } else { - 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; + /* Handle tap hold. Once the action following a tap as + * started, don't check the timeout anymore. */ + 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 + * flag will be set to 0) or during the next + * action. */ + if (timevalcmp(&sc->lastsoftintr, + &sc->taptimeout, <=)) { + sc->synaction.in_taphold = 1; + + ms.button |= MOUSE_BUTTON1DOWN; + VLOG(5, (LOG_DEBUG, + "psm%d/synaptics: in tap hold\n", + sc->unit)); + } else { + 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); - } - - /* Use the extra buttons as a scrollwheel */ - if (ms.button & MOUSE_BUTTON4DOWN) - z = -1; - else if (ms.button & MOUSE_BUTTON5DOWN) - z = 1; - else - z = 0; + /* Check minimum pressure threshold. */ + if (sc->syninfo.min_pressure < 1) { + sc->syninfo.min_pressure = 1; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.min_pressure is " + "too LOW, reset to %d", + sc->syninfo.min_pressure)); + } + if (z >= sc->syninfo.min_pressure) { + int dx, dy; + int low_speed, accel, min_mvt, squelch_level; + int queue_window, max_pressure, max_width; + int vs_margin, scroll_level; + synapticsaction_t *action; + + /* Check sysctl values. */ + if (sc->syninfo.queue_window < 3) { + sc->syninfo.queue_window = 3; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.queue_window is " + "too LOW, reset to %d", + sc->syninfo.queue_window)); + } else if (sc->syninfo.queue_window > + SYNAPTICS_QUEUE_MAX_LEN) { + sc->syninfo.queue_window = + SYNAPTICS_QUEUE_MAX_LEN; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.queue_window is " + "too HIGH, reset to %d", + sc->syninfo.queue_window)); + } + if (sc->syninfo.low_speed_threshold < 0) { + sc->syninfo.low_speed_threshold = 0; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.low_speed_threshold is " + "NEGATIVE, reset to %d", + sc->syninfo.low_speed_threshold)); + } + if (sc->syninfo.high_speed_accel < 0) { + sc->syninfo.high_speed_accel = 0; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.high_speed_accel is " + "NEGATIVE, reset to %d", + sc->syninfo.high_speed_accel)); + } + if (sc->syninfo.min_movement < 1) { + sc->syninfo.min_movement = 1; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.min_movement is " + "too LOW, reset to %d", + sc->syninfo.min_movement)); + } + if (sc->syninfo.squelch_level < 1) { + sc->syninfo.squelch_level = 1; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.squelch_level is " + "too LOW, reset to %d", + sc->syninfo.squelch_level)); + } + if (sc->syninfo.max_pressure > 255) { + sc->syninfo.max_pressure = 255; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.max_pressure is " + "too HIGH, reset to %d", + sc->syninfo.max_pressure)); + } + if (sc->syninfo.max_width > 15) { + sc->syninfo.max_width = 15; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.max_width is " + "too HIGH, reset to %d", + sc->syninfo.max_width)); + } + if (sc->syninfo.scroll_squelch_level < 1) { + sc->syninfo.scroll_squelch_level = 1; + VLOG(1, (LOG_NOTICE, + "psm/synaptics: " + "hw.psm.synaptics.scroll_squelch_level is " + "too LOW, reset to %d", + sc->syninfo.squelch_level)); + } + + action = &(sc->synaction); + low_speed = sc->syninfo.low_speed_threshold; + accel = sc->syninfo.high_speed_accel; + min_mvt = sc->syninfo.min_movement; + squelch_level = sc->syninfo.squelch_level; + queue_window = sc->syninfo.queue_window; + max_pressure = sc->syninfo.max_pressure; + max_width = sc->syninfo.max_width; + vs_margin = sc->syninfo.directional_scrolls; + scroll_level = sc->syninfo.scroll_squelch_level; + + /* Read current absolute position. */ + x0 = ((pb->ipacket[3] & 0x10) << 8) | + ((pb->ipacket[1] & 0x0f) << 8) | + pb->ipacket[4]; + y0 = ((pb->ipacket[3] & 0x20) << 7) | + ((pb->ipacket[1] & 0xf0) << 4) | + pb->ipacket[5]; + VLOG(5, (LOG_DEBUG, + "psm%d/synaptics: x0=%d, y0=%d\n", + sc->unit, x0, y0)); + + /* Palm and multi fingers check. */ + if (sc->synhw.capMultiFinger && (w == 0 || w == 1)) { + //printf(" -> multifinger"); + /* Increase the queue length required before + * any move are processed, to avoid unwanted + * move with multifinger taps. */ + /* XXX Tester en augmentant aussi Z */ + /* XXX Si queue_len est déjà à 5-6, est-ce + * bon ? */ + action->min_queue_len = queue_window; + } else if (!( + (sc->synhw.capPalmDetect && + w >= 4 && w <= max_width) || + (!sc->synhw.capPalmDetect && z <= max_pressure) || + (sc->synhw.capPen && w == 2))) { + /* Ignore palm on the touchpad but + * the action isn't finished. */ + z = 0; + break; + } + + /* If the action is just beginning, init the + * structure and compute tap timeout. */ + if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) { + /* Init action. */ + action->queue_len = 0; + action->min_queue_len = 3 /* XXX sysctl */; + action->fingers_nb = 0; + action->squelch_x = action->squelch_y = 0; + + /* Store start coordinates. */ + action->start_x = x0; + action->start_y = y0; + + sc->xold = sc->yold = 0; + + /* Reset max Z and set timeout. */ + sc->zmax = 0; + sc->taptimeout.tv_sec = tap_timeout / 1000000; + sc->taptimeout.tv_usec = tap_timeout % 1000000; + timevaladd(&sc->taptimeout, &sc->lastsoftintr); + + sc->flags |= PSM_FLAGS_FINGERDOWN; + } + + /* Queue this new packet. */ + if (action->queue_len == SYNAPTICS_QUEUE_MAX_LEN) { + bcopy(&(action->queue[0]), &(action->queue[1]), + sizeof(action->queue[0]) * + (action->queue_len - 1)); + } else if (action->queue_len > 0) { + bcopy(&(action->queue[0]), &(action->queue[1]), + sizeof(action->queue[0]) * + action->queue_len); + } + action->queue[0].x = x0; + action->queue[0].y = y0; + action->queue[0].z = z; + action->queue[0].w = w; + if (action->queue_len > 0) { + action->queue[0].dx = x0 - action->queue[1].x; + action->queue[0].dy = y0 - action->queue[1].y; + } else { + action->queue[0].dx = 0; + action->queue[0].dy = 0; + } + if (action->queue_len < SYNAPTICS_QUEUE_MAX_LEN) + action->queue_len++; + + /* Update window. */ + queue_window = imin(queue_window, action->queue_len); + + /* For tap detection, we keep the maximum + * number of fingers and the maximum pressure. */ + switch (w) { + case 1: /* Three or more fingers. */ + sc->synaction.fingers_nb = + imax(sc->synaction.fingers_nb, 3); + z = 0; + break; + case 0: /* Two fingers. */ + sc->synaction.fingers_nb = + imax(sc->synaction.fingers_nb, 2); + z = 0; + break; + default: /* One finger (or undetectable). */ + sc->synaction.fingers_nb = + imax(sc->synaction.fingers_nb, 1); + } + sc->zmax = imax(sc->zmax, z); + + /* If in taphold, add left click. */ + if (action->in_taphold) { + ms.button |= MOUSE_BUTTON1DOWN; + VLOG(5, (LOG_DEBUG, + "psm%d/synaptics: in tap hold\n", + sc->unit)); + } + + /* Compute the new relative x & y. */ + if (queue_window >= action->min_queue_len) { + int i, dth; + + /* Long-term delta. */ + i = queue_window - 1; + dx = action->queue[0].x - action->queue[i].x; + dy = action->queue[0].y - action->queue[i].y; + + /* XXX Peut-être remettre la boucle pour le + * calcul du delta, en pondérant les valeurs + * en fonction de Z (pour nettoyer les fins + * de mouvement et les artefacts sur Y en + * mouvement lent). */ + + /* Long-term minimum delta required to + * switch to high-speed calculation. */ + dth = low_speed * queue_window; + VLOG(5, (LOG_DEBUG, + "psm%d/synaptics: " + " dx=%d, dy=%d, dth=%d\n", + sc->unit, dx, dy, dth)); + + /* Accelerate high-speed movement. */ + if (dx > dth || dx < -dth || + dy > dth || dy < -dth) { + /* XXX Tester avec une moyenne + * pondérée des deltas. */ + dx = action->queue[0].dx * + (queue_window - 1); + dx += (dx * accel / 100); + dy = action->queue[0].dy * + (action->queue_len - 1); + dy += (dy * accel / 100); + VLOG(5, (LOG_DEBUG, + "psm%d/synaptics: " + " dx=%d, dy=%d (HS)\n", + sc->unit, dx, dy)); + } + + /* XXX Comparer le dernier (ou 2 + * derniers deltas par rapport à la + * moyenne sur la queue et détecter + * l'arrêt d'un mouvement (pour éviter + * le temps de stabilisation du + * pointeur). */ + + xsensitivity = abs(dx) / min_mvt; + action->squelch_x += xsensitivity; + + ysensitivity = abs(dy) / min_mvt; + action->squelch_y += ysensitivity; + + VLOG(5, (LOG_DEBUG, + "psm%d/synaptics: " + " squelch_x=%d (%d), squelch_y=%d (%d)\n", + sc->unit, + action->squelch_x, xsensitivity, + action->squelch_y, ysensitivity)); + + /* XXX Peut-être remettre squelch à 0 + * au bout d'un certains nombre de + * paquets trop faible pour éviter + * un mouvement parasite au bout d'un + * moment. */ + if (action->squelch_x >= squelch_level) { + xavg = action->squelch_x / + squelch_level; + x = dx > 0 ? xavg : -xavg; + action->squelch_x = 0; + } + if (action->squelch_y >= squelch_level) { + yavg = action->squelch_y / + squelch_level; + y = dy > 0 ? yavg : -yavg; + action->squelch_y = 0; + } + VLOG(5, (LOG_DEBUG, "psm%d/synaptics: " + " x=%d, y=%d\n", sc->unit, x, y)); + + /* XXX Remove unused variables. */ + xavg = yavg = xsensitivity = ysensitivity = + sensitivity = 0; + + /* Reset z (used for pressure before). */ + z = 0; + + /* Virtual scrolling. */ + if (sc->syninfo.directional_scrolls && + (action->start_x <= vs_margin || + action->start_x >= 6143 - vs_margin || + action->start_y <= vs_margin || + action->start_y >= 6143 - vs_margin)) { + /* Horizontal scrolling. */ + if (sc->xold >= scroll_level) { + sc->xold = 0; + if (x > 0) { + /* Direction: right. */ + z = 2; + } else if (x < 0) { + /* Direction: left. */ + z = -2; + } + } else if (abs(x) > 0) { + sc->xold += abs(x); + } + + /* Vertical scrolling. */ + if (sc->yold >= scroll_level) { + sc->yold = 0; + if (y > 0) { + /* Direction: top. */ + z = -1; + } else if (y < 0) { + /* Direction: bottom. */ + z = 1; + } + } else if (abs(y) > 0) { + sc->yold += abs(y); + } + + /* Reset pointer movements. */ + x = y = 0; + } + } + } else if (sc->flags & PSM_FLAGS_FINGERDOWN) { + int in_taphold; + + /* Clear "Finger down" flag. */ + sc->flags &= ~PSM_FLAGS_FINGERDOWN; + + /* Reset tap hold state. */ + in_taphold = sc->synaction.in_taphold; + sc->synaction.in_taphold = 0; + + /* Reset z (used for pressure before). */ + z = 0; + + /* The last action is finished: check for tap. */ + if (sc->zmax > tap_threshold && + timevalcmp(&sc->lastsoftintr, + &sc->taptimeout, <=)) { + if (in_taphold) + /* In order for double-tap to work, + * we must delay any buttons push to + * the next packet. So we set back + * the "Finger down" flag. */ + sc->flags |= PSM_FLAGS_FINGERDOWN; + else if (sc->synaction.fingers_nb == 2) + ms.button |= MOUSE_BUTTON3DOWN; + else if (sc->synaction.fingers_nb == 3) + ms.button |= MOUSE_BUTTON2DOWN; + else { + ms.button |= MOUSE_BUTTON1DOWN; + + /* Initialize taphold timeout. */ + sc->synaction.in_taphold = 1; + sc->taptimeout.tv_sec = + sc->syninfo.taphold_timeout / + 1000000; + sc->taptimeout.tv_usec = + sc->syninfo.taphold_timeout % + 1000000; + timevaladd(&sc->taptimeout, + &sc->lastsoftintr); + } + } + } else { + /* Reset z (used for pressure before). */ + z = 0; + } - break; + break; case MOUSE_MODEL_GENERIC: default: @@ -3252,17 +3565,20 @@ if (!synaptics_support) return (FALSE); + /* XXX Convert sysctls to appropriate C types (like unsigned int) when + * relevant. */ + /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */ sysctl_ctx_init(&sc->syninfo.sysctl_ctx); sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx, SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD, 0, "Synaptics TouchPad"); - + /* * synaptics_directional_scrolls - if non-zero, the directional * pad scrolls, otherwise it registers as a middle-click. */ - sc->syninfo.directional_scrolls = 1; + sc->syninfo.directional_scrolls = 800; SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "directional_scrolls", CTLFLAG_RW, @@ -3270,21 +3586,60 @@ "directional pad scrolls (1=yes 0=3rd button)"); /* - * Synaptics_low_speed_threshold - the number of touchpad units + * synaptics_min_pressure/synaptics_max_pressure - minimum and maximum + * pressure to take a packet into account. + */ + 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 threshold for Synaptics TouchPads"); + 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 threshold for Synaptics TouchPads"); + + /* + * synaptics_max_width - maximum contact width allowed. + */ + 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 contact width threshold for Synaptics TouchPads"); + + /* + * synaptics_taphold_timeout - maximum time between a tap + * and a new action to maintain the left button down. + */ + sc->synaction.in_taphold = 0; + sc->syninfo.taphold_timeout = 200000; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "taphold_timeout", CTLFLAG_RW, + &sc->syninfo.taphold_timeout, 0, + "maximum time between a tap and an action to maintain left click"); + + /* + * synaptics_low_speed_threshold - the number of touchpad units * below-which we go into low-speed tracking mode. */ - sc->syninfo.low_speed_threshold = 20; + sc->syninfo.low_speed_threshold = 15; SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), - OID_AUTO, "low_speed_threshold", CTLFLAG_RW, + OID_AUTO, "low_speed_threshold", CTLFLAG_RW, &sc->syninfo.low_speed_threshold, 0, - "threshold between low and hi speed positioning"); + "threshold between low and hi speed positioning"); /* - * Synaptics_min_movement - the number of touchpad units below + * synaptics_min_movement - the number of touchpad units below * which we ignore altogether. */ - sc->syninfo.min_movement = 2; + sc->syninfo.min_movement = 7; SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "min_movement", CTLFLAG_RW, @@ -3292,19 +3647,61 @@ "ignore touchpad movements less than this"); /* - * Synaptics_squelch_level - level at which we squelch movement + * synaptics_squelch_level - level at which we squelch movement * packets. * * This effectively sends 1 out of every synaptics_squelch_level - * packets when * running in low-speed mode. + * packets when running in low-speed mode. */ - sc->syninfo.squelch_level=3; + sc->syninfo.squelch_level = 25; SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), - OID_AUTO, "squelch_level", CTLFLAG_RW, + OID_AUTO, "squelch_level", CTLFLAG_RW, &sc->syninfo.squelch_level, 0, "squelch level for synaptics touchpads"); + /* + * synaptics_high_speed_accel - acceleration factor for + * high speed movement. + * + * This is a percentage by which a delta in the coordinates is + * increased. + */ + sc->syninfo.high_speed_accel = 100; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "high_speed_accel", CTLFLAG_RW, + &sc->syninfo.high_speed_accel, 0, + "high speed acceleration factor for Synaptics TouchPads"); + + /* + * synaptics_queue_window - processing window on the packets + * queue. + * + * This indicated the maximum number of packets to take into account + * in the action's packets queue. + */ + sc->syninfo.queue_window = SYNAPTICS_QUEUE_MAX_LEN; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "queue_window", CTLFLAG_RW, + &sc->syninfo.queue_window, 0, + "packets queue window for Synaptics TouchPads"); + + /* + * synaptics_scroll_squelch_level - level at which we squelch movement + * packets for virtual scrolling. + * + * This effectively sends 1 out of every synaptics_scroll_squelch_level + * packets. + */ + sc->syninfo.scroll_squelch_level = 25; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), + OID_AUTO, "scroll_squelch_level", CTLFLAG_RW, + &sc->syninfo.scroll_squelch_level, 0, + "scroll squelch level for synaptics touchpads"); + kbdc = sc->kbdc; disable_aux_dev(kbdc); sc->hw.buttons = 3; @@ -3312,7 +3709,7 @@ /* Just to be on the safe side */ set_mouse_scaling(kbdc, 1); - + /* Identify the Touchpad version */ if (mouse_ext_command(kbdc, 0) == 0) return (FALSE); @@ -3409,7 +3806,9 @@ } else { sc->synhw.capExtended = 0; - + sc->synhw.capMultiFinger = 0; + sc->synhw.capPalmDetect = 0; + if (verbose >= 2) printf(" No extended capabilities\n"); } @@ -3439,7 +3838,7 @@ /* Reset the sampling rate */ set_mouse_sampling_rate(kbdc, 20); - /* + /* * Report the correct number of buttons * * XXX: I'm not sure this is used anywhere.