From owner-freebsd-bugs@FreeBSD.ORG Sun Jan 2 19:40:26 2005 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 3F5F116A4CE for ; Sun, 2 Jan 2005 19:40:26 +0000 (GMT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id EA37E43D46 for ; Sun, 2 Jan 2005 19:40:25 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.1/8.13.1) with ESMTP id j02JePkq068433 for ; Sun, 2 Jan 2005 19:40:25 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.1/8.13.1/Submit) id j02JeP7S068432; Sun, 2 Jan 2005 19:40:25 GMT (envelope-from gnats) Resent-Date: Sun, 2 Jan 2005 19:40:25 GMT Resent-Message-Id: <200501021940.j02JeP7S068432@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Jason Kuri Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C87A116A4CE for ; Sun, 2 Jan 2005 19:38:51 +0000 (GMT) Received: from www.freebsd.org (www.freebsd.org [216.136.204.117]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8A8EC43D2D for ; Sun, 2 Jan 2005 19:38:51 +0000 (GMT) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.13.1/8.13.1) with ESMTP id j02JcphE018227 for ; Sun, 2 Jan 2005 19:38:51 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.13.1/8.13.1/Submit) id j02Jcp2k018226; Sun, 2 Jan 2005 19:38:51 GMT (envelope-from nobody) Message-Id: <200501021938.j02Jcp2k018226@www.freebsd.org> Date: Sun, 2 Jan 2005 19:38:51 GMT From: Jason Kuri To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-2.3 Subject: kern/75725: [patch] better synaptics support for psm(4) X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jan 2005 19:40:26 -0000 >Number: 75725 >Category: kern >Synopsis: [patch] better synaptics support for psm(4) >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sun Jan 02 19:40:25 GMT 2005 >Closed-Date: >Last-Modified: >Originator: Jason Kuri >Release: 5.3-RELEASE >Organization: Oneway.com >Environment: FreeBSD keeper 5.3-RELEASE FreeBSD 5.3-RELEASE #0: Fri Dec 23 21:46:50 UTC 2004 jk@keeper:/usr/src/sys/i386/compile/ACER i386 >Description: >From the 5.3-TODO: "Synaptics updates to the psm(4) driver have resulted in poor interactivity for taps and button press events for some users." The synaptics support is disabled due to aiming problems. The patch attached fixes them. It also adds scroll button support and sysctls to control various thresholds (such as the pressure required for a tap to register / the switch point between high and low speed tracking modes, etc.) >How-To-Repeat: Turn on hw.psm.synaptics_support. Start X, try and grab a window corner to resize something. Try again. Curse. >Fix: I'm not sure how pasting a patch here will work, so I'll prefix this by providing a link to where the patch can be retrieved online: http://oneway.com/hx/psm-synaptics.diff --- below this line there be monsters --- --- /usr/src/sys/isa/psm.c.orig Fri Dec 24 01:22:51 2004 +++ /usr/src/sys/isa/psm.c Fri Dec 24 01:22:40 2004 @@ -182,6 +182,9 @@ int button; /* the latest button state */ int xold; /* previous absolute X position */ int yold; /* previous absolute Y position */ + int xaverage; /* average X position */ + int yaverage; /* average Y position */ + int squelch; /* level to filter movement data at low speed */ int zmax; /* maximum pressure value for touchpads */ int syncerrors; /* # of bytes discarded searching for sync */ int pkterrors; /* # of packets failed during quaranteen. */ @@ -234,8 +237,8 @@ #define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */ /* Tunables */ -static int synaptics_support = 0; -TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support); +static int synaptics_support = 1; +TUNABLE_INT("hw.psm.synaptics_support", (int *) &synaptics_support); /* for backward compatibility */ #define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t) @@ -2029,8 +2032,42 @@ SYSCTL_INT(_debug, OID_AUTO, psmpkterrthresh, CTLFLAG_RW, &psmpkterrthresh, 0, ""); +TUNABLE_INT("hw.psm.loglevel", (int *) &verbose); SYSCTL_INT(_debug, OID_AUTO, psmloglevel, CTLFLAG_RW, &verbose, 0, ""); +/* some sysctl additions to things that may need tuning at runtime */ +SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse"); + +static int psm_tap_threshold = PSM_TAP_THRESHOLD; +SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &psm_tap_threshold, 0, "touchpad tap threshold"); + +static int psm_tap_timeout = PSM_TAP_TIMEOUT; +SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &psm_tap_timeout, 0, "touchpad tap timeout"); + +/* synaptics_directional_scrolls - if non-zero, the directional + * pad scrolls, otherwise it registers as a middle-click. + */ +static int synaptics_directional_scrolls = 1; +SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_directional_scrolls, CTLFLAG_RW, &synaptics_directional_scrolls, 0, "directional pad scrolls (1=yes 0=3rd button)"); + +/* synaptics_low_speed_threshold - the number of touchpad units + * below-which we go into low-speed tracking mode. + */ +static int synaptics_low_speed_threshold = 20; +SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_low_speed_threshold, CTLFLAG_RW, &synaptics_low_speed_threshold, 0, "threshold between low and hi speed positioning"); + +/* synaptics_min_movement - the number of touchpad units below + * which we ignore altogether. + */ +static int synaptics_min_movement = 2; +SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_min_movement, CTLFLAG_RW, &synaptics_min_movement, 0, "ignore touchpad movements less than this"); + +/* 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. + */ +static int synaptics_squelch_level = 3; +SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_squelch_level, CTLFLAG_RW, &synaptics_squelch_level, 0, "squelch level for synaptics pads"); static void psmintr(void *arg) @@ -2205,7 +2242,7 @@ int w, x, y, z; int c; int l; - int x0, y0; + int x0, y0, xavg, yavg, xsensitivity, ysensitivity, sensitivity = 0; int s; packetbuf_t *pb; @@ -2579,6 +2616,30 @@ touchpad_buttons |= MOUSE_BUTTON5DOWN; } + /* In newer pads - bit 0x02 in the third byte of + * the packet indicates that we have an extended + * button press. + */ + if (pb->ipacket[3] & 0x02) { + /* if synaptics_directional_scrolls is not 1, we treat + * any of the scrolling directions as middle-click. + */ + if (synaptics_directional_scrolls) { + if (pb->ipacket[4] & 0x01) + touchpad_buttons |= MOUSE_BUTTON4DOWN; + if (pb->ipacket[5] & 0x01) + touchpad_buttons |= MOUSE_BUTTON5DOWN; + if (pb->ipacket[4] & 0x02) + touchpad_buttons |= MOUSE_BUTTON6DOWN; + if (pb->ipacket[5] & 0x02) + touchpad_buttons |= MOUSE_BUTTON7DOWN; + } else { + if ((pb->ipacket[4] & 0x0F) || (pb->ipacket[5] & 0x0F)) + touchpad_buttons |= MOUSE_BUTTON2DOWN; + } + + } + ms.button = touchpad_buttons | guest_buttons; /* There is a finger on the pad. */ @@ -2591,22 +2652,103 @@ pb->ipacket[5]; if (sc->flags & PSM_FLAGS_FINGERDOWN) { - x0 = (x0 + sc->xold * 3) / 4; - y0 = (y0 + sc->yold * 3) / 4; + 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>synaptics_low_speed_threshold || + x<-synaptics_low_speed_threshold) || + (y>synaptics_low_speed_threshold || + y<-synaptics_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<-synaptics_min_movement) + x=-1; + else if (x>synaptics_min_movement) + x=1; + else + x=0; + if (y < -synaptics_min_movement) + y=-1; + else if (y > synaptics_min_movement) + y=1; + else + y=0; - x = (x0 - sc->xold) * 10 / 85; - y = (y0 - sc->yold) * 10 / 85; + } } else { sc->flags |= PSM_FLAGS_FINGERDOWN; } + /* 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 synaptics_squelch_level packets is + * delivered, effectively slowing down the movement. + */ + sc->squelch += sensitivity; + if (sc->squelch < synaptics_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 > PSM_TAP_THRESHOLD && + if (sc->zmax > psm_tap_threshold && timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) { if (w == 0) ms.button |= MOUSE_BUTTON3DOWN; @@ -2617,8 +2759,8 @@ } sc->zmax = 0; - sc->taptimeout.tv_sec = PSM_TAP_TIMEOUT / 1000000; - sc->taptimeout.tv_usec = PSM_TAP_TIMEOUT % 1000000; + sc->taptimeout.tv_sec = psm_tap_timeout / 1000000; + sc->taptimeout.tv_usec = psm_tap_timeout % 1000000; timevaladd(&sc->taptimeout, &sc->lastsoftintr); } @@ -2637,6 +2779,8 @@ break; } + + /* scale values */ if (sc->mode.accelfactor >= 1) { if (x != 0) { @@ -3120,6 +3264,8 @@ kbdc = sc->kbdc; disable_aux_dev(kbdc); + sc->hw.buttons = 3; + sc->squelch=0; /* Just to be on the safe side */ set_mouse_scaling(kbdc, 1); @@ -3203,6 +3349,20 @@ printf(" capMultiFinger: %d\n", sc->synhw.capMultiFinger); printf(" capPalmDetect: %d\n", sc->synhw.capPalmDetect); } + + /* if we have bits set in status[0] & 0x70 - then we can load + * more information about buttons using query 0x09 + */ + if (status[0] & 0x70) { + if (mouse_ext_command(kbdc, 0x09) == 0) + return (FALSE); + if (get_mouse_status(kbdc, status, 0, 3) != 3) + return (FALSE); + sc->hw.buttons = ((status[1] & 0xf0)>>4) + 3; + if (verbose >= 2) + printf(" Additional Buttons: %d\n", sc->hw.buttons -3); + } + } else { sc->synhw.capExtended = 0; @@ -3242,8 +3402,6 @@ */ if (sc->synhw.capExtended && sc->synhw.capFourButtons) sc->hw.buttons = 4; - else - sc->hw.buttons = 3; return (TRUE); } >Release-Note: >Audit-Trail: >Unformatted: