aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2016-09-09 06:51:49 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2016-09-09 06:51:49 +0000
commit02a0b99cd08756fba07393b2f6abe9d96dffb733 (patch)
tree5872bbcc99659f320a376f6073525d45979b655f
parent5b4770cc138cd9160eef62a0df9c3ff65e241532 (diff)
downloadsrc-02a0b99cd08756fba07393b2f6abe9d96dffb733.tar.gz
src-02a0b99cd08756fba07393b2f6abe9d96dffb733.zip
MFC r303765 and r304571:
Keep a reference count on USB keyboard polling to allow recursive cngrab() during a panic for example, similar to what the AT-keyboard driver is doing. 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.
Notes
Notes: svn path=/stable/8/; revision=305647
-rw-r--r--sys/dev/usb/input/ukbd.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c
index 453957578dac..f5543397ffbb 100644
--- a/sys/dev/usb/input/ukbd.c
+++ b/sys/dev/usb/input/ukbd.c
@@ -107,7 +107,7 @@ TUNABLE_INT("hw.usb.ukbd.no_leds", &ukbd_no_leds);
#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 */
@@ -128,7 +128,8 @@ struct ukbd_data {
};
enum {
- UKBD_INTR_DT,
+ UKBD_INTR_DT_0,
+ UKBD_INTR_DT_1,
UKBD_CTRL_LED,
UKBD_N_TRANSFER,
};
@@ -198,6 +199,7 @@ struct ukbd_softc {
int sc_state; /* shift/lock key state */
int sc_accents; /* accent key index (> 0) */
int sc_poll_tick_last;
+ int sc_polling; /* polling recursion count */
int sc_led_size;
int sc_kbd_size;
@@ -470,7 +472,8 @@ ukbd_get_key(struct ukbd_softc *sc, uint8_t wait)
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 (ukbd_polls_other_thread(sc))
@@ -941,7 +944,16 @@ ukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error)
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,
@@ -1187,9 +1199,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));
@@ -1280,7 +1309,8 @@ ukbd_attach(device_t dev)
/* 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]);
mtx_unlock(&Giant);
return (0); /* success */
@@ -1307,7 +1337,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));
@@ -2041,7 +2072,16 @@ ukbd_poll(keyboard_t *kbd, int on)
return (retval);
}
- if (on) {
+ /*
+ * Keep a reference count on polling to allow recursive
+ * cngrab() during a panic for example.
+ */
+ if (on)
+ sc->sc_polling++;
+ else if (sc->sc_polling > 0)
+ sc->sc_polling--;
+
+ if (sc->sc_polling != 0) {
sc->sc_flags |= UKBD_FLAG_POLLING;
sc->sc_poll_thread = curthread;
} else {