From owner-svn-src-all@freebsd.org Wed Aug 24 05:54:13 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 1E328BC4231; Wed, 24 Aug 2016 05:54:13 +0000 (UTC) (envelope-from bde@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D28D1176B; Wed, 24 Aug 2016 05:54:12 +0000 (UTC) (envelope-from bde@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u7O5sCKG065448; Wed, 24 Aug 2016 05:54:12 GMT (envelope-from bde@FreeBSD.org) Received: (from bde@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u7O5sCQf065447; Wed, 24 Aug 2016 05:54:12 GMT (envelope-from bde@FreeBSD.org) Message-Id: <201608240554.u7O5sCQf065447@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: bde set sender to bde@FreeBSD.org using -f From: Bruce Evans Date: Wed, 24 Aug 2016 05:54:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r304735 - head/sys/dev/usb/input X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Aug 2016 05:54:13 -0000 Author: bde Date: Wed Aug 24 05:54:11 2016 New Revision: 304735 URL: https://svnweb.freebsd.org/changeset/base/304735 Log: Fix key delay and repeat, part 2. Use sbintime_t timeouts with precision control to get very accurate timing. It costs little to always ask for about 1% accuracy, and the not so new event timer implementation usual delivers that, and when it can't it gets much closer than our previous coarse timeouts and buggy simple countdown. The 2 fastest atkbd repeat rates have periods 34 and 38 msec, and ukbd pretended to support rates in between these. This requires sub-microsecond precision and accuracy even to handle the 4 msec difference very well, but ukbd asked the timeout subsystem for timeouts of 25 msec and the buggy simple countdown of this gave a a wide range of precisions and accuracies depending on HZ and other timer configuration (sometimes better than 25 msec but usually more like 50 msec). We now ask for and usually get precision and accuracy of about 1% for each repeat and much better on average. The 1% accuracy is overkill. Rounding of 30 cps to 34 msec instead of 33 already gives an error of +2% instead of -1%, and ut AT keyboards on PS/2 interfaces have similar errors. A timeout is now scheduled for every keypress and release. This allows some simplifications that are not done. It allows removing the timeout scheduling for exiting polled mode where it was unsafe in ddb mode. This is done. Exiting polled mode had some problems with extra repeats. Now exiting polled mode lets an extra timeout fire and the state is fudged so that the timeout handler does very little. The sc->time_ms variable is unsigned to avoid overflow. Differences of it need to be signed. Signed comparisons were emulated by testing an emulated sign bits. This only works easily for '<' comparisonss, but we now need a '<=' comparison. Change the difference variable to signed and use a signed comparison. Using unsigned types here didn't prevent overflow bugs but just reduced them. Overflow occurs with n repeats at the silly repeat period of [U]INT_MAX / n. The old countdown had an off by 1 error, and the simplifications would simply count down 1 to 0 and not need to accumulate possibly-large repeat repeats. Modified: head/sys/dev/usb/input/ukbd.c Modified: head/sys/dev/usb/input/ukbd.c ============================================================================== --- head/sys/dev/usb/input/ukbd.c Wed Aug 24 05:01:20 2016 (r304734) +++ head/sys/dev/usb/input/ukbd.c Wed Aug 24 05:54:11 2016 (r304735) @@ -163,6 +163,8 @@ struct ukbd_softc { struct usb_interface *sc_iface; struct usb_xfer *sc_xfer[UKBD_N_TRANSFER]; + sbintime_t sc_co_basetime; + int sc_delay; uint32_t sc_ntime[UKBD_NKEYCODE]; uint32_t sc_otime[UKBD_NKEYCODE]; uint32_t sc_input[UKBD_IN_BUF_SIZE]; /* input buffer */ @@ -182,7 +184,6 @@ struct ukbd_softc { #define UKBD_FLAG_APPLE_EJECT 0x00000040 #define UKBD_FLAG_APPLE_FN 0x00000080 #define UKBD_FLAG_APPLE_SWAP 0x00000100 -#define UKBD_FLAG_TIMER_RUNNING 0x00000200 #define UKBD_FLAG_CTRL_L 0x00000400 #define UKBD_FLAG_CTRL_R 0x00000800 #define UKBD_FLAG_SHIFT_L 0x00001000 @@ -393,8 +394,14 @@ ukbd_any_key_pressed(struct ukbd_softc * static void ukbd_start_timer(struct ukbd_softc *sc) { - sc->sc_flags |= UKBD_FLAG_TIMER_RUNNING; - usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc); + sbintime_t delay, prec; + + delay = SBT_1MS * sc->sc_delay; + sc->sc_co_basetime += delay; + /* This is rarely called, so prefer precision to efficiency. */ + prec = qmin(delay >> 7, SBT_1MS * 10); + callout_reset_sbt(&sc->sc_callout.co, sc->sc_co_basetime, prec, + ukbd_timeout, sc, C_ABSOLUTE); } static void @@ -503,10 +510,11 @@ ukbd_get_key(struct ukbd_softc *sc, uint static void ukbd_interrupt(struct ukbd_softc *sc) { + struct timeval ctv; uint32_t n_mod; uint32_t o_mod; uint32_t now = sc->sc_time_ms; - uint32_t dtime; + int32_t dtime; uint8_t key; uint8_t i; uint8_t j; @@ -564,7 +572,7 @@ rfound: ; sc->sc_ntime[i] = sc->sc_otime[j]; dtime = (sc->sc_otime[j] - now); - if (!(dtime & 0x80000000)) { + if (dtime > 0) { /* time has not elapsed */ goto pfound; } @@ -572,6 +580,15 @@ rfound: ; break; } } + if (j < UKBD_NKEYCODE) { + /* Old key repeating. */ + sc->sc_delay = sc->sc_kbd.kb_delay2; + } else { + /* New key. */ + microuptime(&ctv); + sc->sc_co_basetime = tvtosbt(ctv); + sc->sc_delay = sc->sc_kbd.kb_delay1; + } ukbd_put_key(sc, key | KEY_PRESS); /* @@ -626,7 +643,8 @@ ukbd_timeout(void *arg) UKBD_LOCK_ASSERT(); - sc->sc_time_ms += 25; /* milliseconds */ + sc->sc_time_ms += sc->sc_delay; + sc->sc_delay = 0; ukbd_interrupt(sc); @@ -635,8 +653,6 @@ ukbd_timeout(void *arg) if (ukbd_any_key_pressed(sc) || (sc->sc_inputs != 0)) { ukbd_start_timer(sc); - } else { - sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING; } } @@ -822,10 +838,8 @@ ukbd_intr_callback(struct usb_xfer *xfer ukbd_interrupt(sc); - if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) { - if (ukbd_any_key_pressed(sc)) { - ukbd_start_timer(sc); - } + if (ukbd_any_key_pressed(sc)) { + ukbd_start_timer(sc); } case USB_ST_SETUP: @@ -2016,7 +2030,7 @@ ukbd_poll(keyboard_t *kbd, int on) sc->sc_poll_thread = curthread; } else { sc->sc_flags &= ~UKBD_FLAG_POLLING; - ukbd_start_timer(sc); /* start timer */ + sc->sc_delay = 0; } UKBD_UNLOCK();