summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/usb/input/ukbd.c47
1 files changed, 39 insertions, 8 deletions
diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c
index 506ee45..54ddd16 100644
--- a/sys/dev/usb/input/ukbd.c
+++ b/sys/dev/usb/input/ukbd.c
@@ -111,7 +111,7 @@ TUNABLE_INT("hw.usb.ukbd.pollrate", &ukbd_pollrate);
#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 */
@@ -132,7 +132,8 @@ struct ukbd_data {
};
enum {
- UKBD_INTR_DT,
+ UKBD_INTR_DT_0,
+ UKBD_INTR_DT_1,
UKBD_CTRL_LED,
UKBD_N_TRANSFER,
};
@@ -481,7 +482,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 (sc->sc_flags & UKBD_FLAG_POLLING)
@@ -957,7 +959,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,
@@ -1204,9 +1215,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));
@@ -1298,11 +1326,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 */
@@ -1328,7 +1358,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));
@@ -1993,7 +2024,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) {
OpenPOWER on IntegriCloud