summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2016-09-09 06:36:43 +0000
committerhselasky <hselasky@FreeBSD.org>2016-09-09 06:36:43 +0000
commitce50eef2158ca812c96f7f264f160ad59e85490d (patch)
treefe9950b24c8ab5d6210a65a98244306733e4da36
parent5303a41e72409143ca5ed4abc80502f4bbb90e33 (diff)
downloadFreeBSD-src-ce50eef2158ca812c96f7f264f160ad59e85490d.zip
FreeBSD-src-ce50eef2158ca812c96f7f264f160ad59e85490d.tar.gz
MFC r304571:
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.
-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 42d96cf..6cc2f75 100644
--- a/sys/dev/usb/input/ukbd.c
+++ b/sys/dev/usb/input/ukbd.c
@@ -108,7 +108,7 @@ SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, pollrate, CTLFLAG_RWTUN,
#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, 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)
@@ -954,7 +956,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,
@@ -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));
@@ -1990,7 +2021,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