svn commit: r304571 - head/sys/dev/usb/input

Hans Petter Selasky hselasky at FreeBSD.org
Sun Aug 21 18:37:23 UTC 2016


Author: hselasky
Date: Sun Aug 21 18:37:21 2016
New Revision: 304571
URL: https://svnweb.freebsd.org/changeset/base/304571

Log:
  Make the UKBD USB transfers double buffered and set them up one by one,
  so they are memory independent which allows for handling panics
  triggered by the keyboard driver itself, typically via CTRL+ALT+ESC
  sequences. Or if the USB keyboard driver was processing a key at the
  moment of panic. Allow UKBD to be attached while keyboard polling is active.
  
  Tested by:	Bruce Evans <bde at freebsd.org>
  MFC after:	1 week

Modified:
  head/sys/dev/usb/input/ukbd.c

Modified: head/sys/dev/usb/input/ukbd.c
==============================================================================
--- head/sys/dev/usb/input/ukbd.c	Sun Aug 21 18:12:49 2016	(r304570)
+++ head/sys/dev/usb/input/ukbd.c	Sun Aug 21 18:37:21 2016	(r304571)
@@ -108,7 +108,7 @@ SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollr
 #define	UKBD_NMOD                     8	/* units */
 #define	UKBD_NKEYCODE                 6	/* units */
 #define	UKBD_IN_BUF_SIZE  (2*(UKBD_NMOD + (2*UKBD_NKEYCODE)))	/* bytes */
-#define	UKBD_IN_BUF_FULL  (UKBD_IN_BUF_SIZE / 2)	/* bytes */
+#define	UKBD_IN_BUF_FULL  ((UKBD_IN_BUF_SIZE / 2) - 1)	/* bytes */
 #define	UKBD_NFKEY        (sizeof(fkey_tab)/sizeof(fkey_tab[0]))	/* units */
 #define	UKBD_BUFFER_SIZE	      64	/* bytes */
 
@@ -129,7 +129,8 @@ struct ukbd_data {
 };
 
 enum {
-	UKBD_INTR_DT,
+	UKBD_INTR_DT_0,
+	UKBD_INTR_DT_1,
 	UKBD_CTRL_LED,
 	UKBD_N_TRANSFER,
 };
@@ -478,7 +479,8 @@ ukbd_get_key(struct ukbd_softc *sc, uint
 	if (sc->sc_inputs == 0 &&
 	    (sc->sc_flags & UKBD_FLAG_GONE) == 0) {
 		/* start transfer, if not already started */
-		usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]);
+		usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]);
+		usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]);
 	}
 
 	if (sc->sc_flags & UKBD_FLAG_POLLING)
@@ -954,7 +956,16 @@ ukbd_set_leds_callback(struct usb_xfer *
 
 static const struct usb_config ukbd_config[UKBD_N_TRANSFER] = {
 
-	[UKBD_INTR_DT] = {
+	[UKBD_INTR_DT_0] = {
+		.type = UE_INTERRUPT,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+		.bufsize = 0,	/* use wMaxPacketSize */
+		.callback = &ukbd_intr_callback,
+	},
+
+	[UKBD_INTR_DT_1] = {
 		.type = UE_INTERRUPT,
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_IN,
@@ -1201,9 +1212,26 @@ ukbd_attach(device_t dev)
 
 	usb_callout_init_mtx(&sc->sc_callout, &Giant, 0);
 
+#ifdef UKBD_NO_POLLING
 	err = usbd_transfer_setup(uaa->device,
 	    &uaa->info.bIfaceIndex, sc->sc_xfer, ukbd_config,
 	    UKBD_N_TRANSFER, sc, &Giant);
+#else
+	/*
+	 * Setup the UKBD USB transfers one by one, so they are memory
+	 * independent which allows for handling panics triggered by
+	 * the keyboard driver itself, typically via CTRL+ALT+ESC
+	 * sequences. Or if the USB keyboard driver was processing a
+	 * key at the moment of panic.
+	 */
+	for (n = 0; n != UKBD_N_TRANSFER; n++) {
+		err = usbd_transfer_setup(uaa->device,
+		    &uaa->info.bIfaceIndex, sc->sc_xfer + n, ukbd_config + n,
+		    1, sc, &Giant);
+		if (err)
+			break;
+	}
+#endif
 
 	if (err) {
 		DPRINTF("error=%s\n", usbd_errstr(err));
@@ -1295,11 +1323,13 @@ ukbd_attach(device_t dev)
 			rate = 1000 / rate;
 
 		/* set new polling interval in ms */
-		usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT], rate);
+		usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_0], rate);
+		usbd_xfer_set_interval(sc->sc_xfer[UKBD_INTR_DT_1], rate);
 	}
 #endif
 	/* start the keyboard */
-	usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]);
+	usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_0]);
+	usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT_1]);
 
 	return (0);			/* success */
 
@@ -1325,7 +1355,8 @@ ukbd_detach(device_t dev)
 	/* kill any stuck keys */
 	if (sc->sc_flags & UKBD_FLAG_ATTACHED) {
 		/* stop receiving events from the USB keyboard */
-		usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT]);
+		usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_0]);
+		usbd_transfer_stop(sc->sc_xfer[UKBD_INTR_DT_1]);
 
 		/* release all leftover keys, if any */
 		memset(&sc->sc_ndata, 0, sizeof(sc->sc_ndata));
@@ -1979,7 +2010,7 @@ ukbd_poll(keyboard_t *kbd, int on)
 	 */
 	if (on)
 		sc->sc_polling++;
-	else
+	else if (sc->sc_polling > 0)
 		sc->sc_polling--;
 
 	if (sc->sc_polling != 0) {


More information about the svn-src-all mailing list