svn commit: r358215 - stable/11/sys/dev/usb/input

Hans Petter Selasky hselasky at FreeBSD.org
Fri Feb 21 08:59:21 UTC 2020


Author: hselasky
Date: Fri Feb 21 08:59:20 2020
New Revision: 358215
URL: https://svnweb.freebsd.org/changeset/base/358215

Log:
  MFC r304735 and r331692:
  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.
  
  PR:		226968
  Sponsored by:	Mellanox Technologies

Modified:
  stable/11/sys/dev/usb/input/ukbd.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/usb/input/ukbd.c
==============================================================================
--- stable/11/sys/dev/usb/input/ukbd.c	Fri Feb 21 08:48:24 2020	(r358214)
+++ stable/11/sys/dev/usb/input/ukbd.c	Fri Feb 21 08:59:20 2020	(r358215)
@@ -171,6 +171,8 @@ struct ukbd_softc {
 	struct evdev_dev *sc_evdev;
 #endif
 
+	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 */
@@ -190,7 +192,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
@@ -407,8 +408,26 @@ ukbd_any_key_pressed(struct ukbd_softc *sc)
 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, now, prec;
+
+	now = sbinuptime();
+
+	/* check if initial delay passed and fallback to key repeat delay */
+	if (sc->sc_delay == 0)
+		sc->sc_delay = sc->sc_kbd.kb_delay2;
+
+	/* compute timeout */
+	delay = SBT_1MS * sc->sc_delay;
+	sc->sc_co_basetime += delay;
+
+	/* check if we are running behind */
+	if (sc->sc_co_basetime < now)
+		sc->sc_co_basetime = now;
+
+	/* 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
@@ -528,7 +547,7 @@ ukbd_interrupt(struct ukbd_softc *sc)
 	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;
@@ -586,7 +605,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;
 				}
@@ -594,6 +613,12 @@ rfound:	;
 				break;
 			}
 		}
+		if (j == UKBD_NKEYCODE) {
+			/* New key - set initial delay and [re]start timer */
+			sc->sc_co_basetime = sbinuptime();
+			sc->sc_delay = sc->sc_kbd.kb_delay1;
+			ukbd_start_timer(sc);
+		}
 		ukbd_put_key(sc, key | KEY_PRESS);
 
 		/*
@@ -648,7 +673,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);
 
@@ -657,8 +683,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;
 	}
 }
 
@@ -844,12 +868,6 @@ ukbd_intr_callback(struct usb_xfer *xfer, usb_error_t 
 
 		ukbd_interrupt(sc);
 
-		if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) {
-			if (ukbd_any_key_pressed(sc)) {
-				ukbd_start_timer(sc);
-			}
-		}
-
 	case USB_ST_SETUP:
 tr_setup:
 		if (sc->sc_inputs < UKBD_IN_BUF_FULL) {
@@ -2087,7 +2105,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();
 


More information about the svn-src-all mailing list