summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2009-07-30 00:14:34 +0000
committeralfred <alfred@FreeBSD.org>2009-07-30 00:14:34 +0000
commite04ffbb8b67e9f6a83ea4fee6093b81757856740 (patch)
tree70f797d0bf1c82684e3af814290a60f4963b5fbf
parent7a35d7e44d54802800910fd41a22bff7d5c038e8 (diff)
downloadFreeBSD-src-e04ffbb8b67e9f6a83ea4fee6093b81757856740.zip
FreeBSD-src-e04ffbb8b67e9f6a83ea4fee6093b81757856740.tar.gz
USB CORE:
- Add minimum polling support to drive UMASS and UKBD in case of panic. - Add extra check to ukbd probe to fix problem about mouse devices attaching like keyboards. - P4 ID: 166148 Submitted by: hps Approved by: re
-rw-r--r--sys/dev/usb/controller/at91dci.c1
-rw-r--r--sys/dev/usb/controller/atmegadci.c1
-rw-r--r--sys/dev/usb/controller/avr32dci.c1
-rw-r--r--sys/dev/usb/controller/ehci.c1
-rw-r--r--sys/dev/usb/controller/musb_otg.c1
-rw-r--r--sys/dev/usb/controller/ohci.c1
-rw-r--r--sys/dev/usb/controller/uhci.c1
-rw-r--r--sys/dev/usb/controller/uss820dci.c1
-rw-r--r--sys/dev/usb/input/ukbd.c157
-rw-r--r--sys/dev/usb/usb_controller.h3
-rw-r--r--sys/dev/usb/usb_transfer.c96
11 files changed, 222 insertions, 42 deletions
diff --git a/sys/dev/usb/controller/at91dci.c b/sys/dev/usb/controller/at91dci.c
index 210f0e7..d9f8e40 100644
--- a/sys/dev/usb/controller/at91dci.c
+++ b/sys/dev/usb/controller/at91dci.c
@@ -2326,4 +2326,5 @@ struct usb_bus_methods at91dci_bus_methods =
.set_stall = &at91dci_set_stall,
.clear_stall = &at91dci_clear_stall,
.roothub_exec = &at91dci_roothub_exec,
+ .xfer_poll = &at91dci_do_poll,
};
diff --git a/sys/dev/usb/controller/atmegadci.c b/sys/dev/usb/controller/atmegadci.c
index 47e27b5..9b60ad7 100644
--- a/sys/dev/usb/controller/atmegadci.c
+++ b/sys/dev/usb/controller/atmegadci.c
@@ -2143,4 +2143,5 @@ struct usb_bus_methods atmegadci_bus_methods =
.set_stall = &atmegadci_set_stall,
.clear_stall = &atmegadci_clear_stall,
.roothub_exec = &atmegadci_roothub_exec,
+ .xfer_poll = &atmegadci_do_poll,
};
diff --git a/sys/dev/usb/controller/avr32dci.c b/sys/dev/usb/controller/avr32dci.c
index 156f286..f251f91 100644
--- a/sys/dev/usb/controller/avr32dci.c
+++ b/sys/dev/usb/controller/avr32dci.c
@@ -2081,4 +2081,5 @@ struct usb_bus_methods avr32dci_bus_methods =
.set_stall = &avr32dci_set_stall,
.clear_stall = &avr32dci_clear_stall,
.roothub_exec = &avr32dci_roothub_exec,
+ .xfer_poll = &avr32dci_do_poll,
};
diff --git a/sys/dev/usb/controller/ehci.c b/sys/dev/usb/controller/ehci.c
index a326a73..30c9bb9 100644
--- a/sys/dev/usb/controller/ehci.c
+++ b/sys/dev/usb/controller/ehci.c
@@ -3828,4 +3828,5 @@ struct usb_bus_methods ehci_bus_methods =
.device_suspend = ehci_device_suspend,
.set_hw_power = ehci_set_hw_power,
.roothub_exec = ehci_roothub_exec,
+ .xfer_poll = ehci_do_poll,
};
diff --git a/sys/dev/usb/controller/musb_otg.c b/sys/dev/usb/controller/musb_otg.c
index 81332d7..60d29dd 100644
--- a/sys/dev/usb/controller/musb_otg.c
+++ b/sys/dev/usb/controller/musb_otg.c
@@ -2736,4 +2736,5 @@ struct usb_bus_methods musbotg_bus_methods =
.set_stall = &musbotg_set_stall,
.clear_stall = &musbotg_clear_stall,
.roothub_exec = &musbotg_roothub_exec,
+ .xfer_poll = &musbotg_do_poll,
};
diff --git a/sys/dev/usb/controller/ohci.c b/sys/dev/usb/controller/ohci.c
index 1e4c317..30592c1 100644
--- a/sys/dev/usb/controller/ohci.c
+++ b/sys/dev/usb/controller/ohci.c
@@ -2756,4 +2756,5 @@ struct usb_bus_methods ohci_bus_methods =
.device_suspend = ohci_device_suspend,
.set_hw_power = ohci_set_hw_power,
.roothub_exec = ohci_roothub_exec,
+ .xfer_poll = ohci_do_poll,
};
diff --git a/sys/dev/usb/controller/uhci.c b/sys/dev/usb/controller/uhci.c
index 77e95d3..2a2ff1c 100644
--- a/sys/dev/usb/controller/uhci.c
+++ b/sys/dev/usb/controller/uhci.c
@@ -3251,4 +3251,5 @@ struct usb_bus_methods uhci_bus_methods =
.device_suspend = uhci_device_suspend,
.set_hw_power = uhci_set_hw_power,
.roothub_exec = uhci_roothub_exec,
+ .xfer_poll = uhci_do_poll,
};
diff --git a/sys/dev/usb/controller/uss820dci.c b/sys/dev/usb/controller/uss820dci.c
index 1016ed6..62fa8df 100644
--- a/sys/dev/usb/controller/uss820dci.c
+++ b/sys/dev/usb/controller/uss820dci.c
@@ -2360,4 +2360,5 @@ struct usb_bus_methods uss820dci_bus_methods =
.set_stall = &uss820dci_set_stall,
.clear_stall = &uss820dci_clear_stall,
.roothub_exec = &uss820dci_roothub_exec,
+ .xfer_poll = &uss820dci_do_poll,
};
diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c
index 29546a5..0d09ad4 100644
--- a/sys/dev/usb/input/ukbd.c
+++ b/sys/dev/usb/input/ukbd.c
@@ -299,6 +299,28 @@ ukbd_put_key(struct ukbd_softc *sc, uint32_t key)
}
}
+static void
+ukbd_do_poll(struct ukbd_softc *sc, uint8_t wait)
+{
+ DPRINTFN(2, "polling\n");
+
+ while (sc->sc_inputs == 0) {
+
+ usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER);
+
+ DELAY(1000); /* delay 1 ms */
+
+ sc->sc_time_ms++;
+
+ /* support repetition of keys: */
+
+ ukbd_interrupt(sc);
+
+ if (!wait)
+ break;
+ }
+}
+
static int32_t
ukbd_get_key(struct ukbd_softc *sc, uint8_t wait)
{
@@ -311,24 +333,7 @@ ukbd_get_key(struct ukbd_softc *sc, uint8_t wait)
usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]);
}
if (sc->sc_flags & UKBD_FLAG_POLLING) {
- DPRINTFN(2, "polling\n");
-
- while (sc->sc_inputs == 0) {
-
- usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER);
-
- DELAY(1000); /* delay 1 ms */
-
- sc->sc_time_ms++;
-
- /* support repetition of keys: */
-
- ukbd_interrupt(sc);
-
- if (!wait) {
- break;
- }
- }
+ ukbd_do_poll(sc, wait);
}
if (sc->sc_inputs == 0) {
c = -1;
@@ -706,7 +711,15 @@ ukbd_probe(device_t dev)
if (error)
return (ENXIO);
+ /*
+ * NOTE: we currently don't support USB mouse and USB keyboard
+ * on the same USB endpoint.
+ */
if (hid_is_collection(d_ptr, d_len,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) {
+ /* most likely a mouse */
+ error = ENXIO;
+ } else if (hid_is_collection(d_ptr, d_len,
HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) {
if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
error = ENXIO;
@@ -983,6 +996,14 @@ ukbd_lock(keyboard_t *kbd, int lock)
static int
ukbd_enable(keyboard_t *kbd)
{
+ if (!mtx_owned(&Giant)) {
+ /* XXX cludge */
+ int retval;
+ mtx_lock(&Giant);
+ retval = ukbd_enable(kbd);
+ mtx_unlock(&Giant);
+ return (retval);
+ }
mtx_assert(&Giant, MA_OWNED);
KBD_ACTIVATE(kbd);
return (0);
@@ -992,6 +1013,14 @@ ukbd_enable(keyboard_t *kbd)
static int
ukbd_disable(keyboard_t *kbd)
{
+ if (!mtx_owned(&Giant)) {
+ /* XXX cludge */
+ int retval;
+ mtx_lock(&Giant);
+ retval = ukbd_disable(kbd);
+ mtx_unlock(&Giant);
+ return (retval);
+ }
mtx_assert(&Giant, MA_OWNED);
KBD_DEACTIVATE(kbd);
return (0);
@@ -1003,14 +1032,26 @@ ukbd_check(keyboard_t *kbd)
{
struct ukbd_softc *sc = kbd->kb_data;
- if (!mtx_owned(&Giant)) {
- return (0); /* XXX */
+ if (!KBD_IS_ACTIVE(kbd))
+ return (0);
+
+ if (sc->sc_flags & UKBD_FLAG_POLLING) {
+ if (!mtx_owned(&Giant)) {
+ /* XXX cludge */
+ int retval;
+ mtx_lock(&Giant);
+ retval = ukbd_check(kbd);
+ mtx_unlock(&Giant);
+ return (retval);
+ }
+ ukbd_do_poll(sc, 0);
+ } else {
+ /* XXX the keyboard layer requires Giant */
+ if (!mtx_owned(&Giant))
+ return (0);
}
mtx_assert(&Giant, MA_OWNED);
- if (!KBD_IS_ACTIVE(kbd)) {
- return (0);
- }
#ifdef UKBD_EMULATE_ATSCANCODE
if (sc->sc_buffered_char[0]) {
return (1);
@@ -1028,14 +1069,25 @@ ukbd_check_char(keyboard_t *kbd)
{
struct ukbd_softc *sc = kbd->kb_data;
- if (!mtx_owned(&Giant)) {
- return (0); /* XXX */
+ if (!KBD_IS_ACTIVE(kbd))
+ return (0);
+
+ if (sc->sc_flags & UKBD_FLAG_POLLING) {
+ if (!mtx_owned(&Giant)) {
+ /* XXX cludge */
+ int retval;
+ mtx_lock(&Giant);
+ retval = ukbd_check_char(kbd);
+ mtx_unlock(&Giant);
+ return (retval);
+ }
+ } else {
+ /* XXX the keyboard layer requires Giant */
+ if (!mtx_owned(&Giant))
+ return (0);
}
mtx_assert(&Giant, MA_OWNED);
- if (!KBD_IS_ACTIVE(kbd)) {
- return (0);
- }
if ((sc->sc_composed_char > 0) &&
(!(sc->sc_flags & UKBD_FLAG_COMPOSE))) {
return (1);
@@ -1056,9 +1108,22 @@ ukbd_read(keyboard_t *kbd, int wait)
uint32_t scancode;
#endif
+ if (!KBD_IS_ACTIVE(kbd))
+ return (-1);
- if (!mtx_owned(&Giant)) {
- return -1; /* XXX */
+ if (sc->sc_flags & UKBD_FLAG_POLLING) {
+ if (!mtx_owned(&Giant)) {
+ /* XXX cludge */
+ int retval;
+ mtx_lock(&Giant);
+ retval = ukbd_read(kbd, wait);
+ mtx_unlock(&Giant);
+ return (retval);
+ }
+ } else {
+ /* XXX the keyboard layer requires Giant */
+ if (!mtx_owned(&Giant))
+ return (-1);
}
mtx_assert(&Giant, MA_OWNED);
@@ -1077,9 +1142,9 @@ ukbd_read(keyboard_t *kbd, int wait)
/* XXX */
usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1);
- if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) {
- return -1;
- }
+ if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1))
+ return (-1);
+
++(kbd->kb_count);
#ifdef UKBD_EMULATE_ATSCANCODE
@@ -1107,8 +1172,23 @@ ukbd_read_char(keyboard_t *kbd, int wait)
uint32_t scancode;
#endif
- if (!mtx_owned(&Giant)) {
- return (NOKEY); /* XXX */
+
+ if (!KBD_IS_ACTIVE(kbd))
+ return (NOKEY);
+
+ if (sc->sc_flags & UKBD_FLAG_POLLING) {
+ if (!mtx_owned(&Giant)) {
+ /* XXX cludge */
+ int retval;
+ mtx_lock(&Giant);
+ retval = ukbd_read_char(kbd, wait);
+ mtx_unlock(&Giant);
+ return (retval);
+ }
+ } else {
+ /* XXX the keyboard layer requires Giant */
+ if (!mtx_owned(&Giant))
+ return (NOKEY);
}
mtx_assert(&Giant, MA_OWNED);
@@ -1485,7 +1565,12 @@ ukbd_poll(keyboard_t *kbd, int on)
struct ukbd_softc *sc = kbd->kb_data;
if (!mtx_owned(&Giant)) {
- return (0); /* XXX */
+ /* XXX cludge */
+ int retval;
+ mtx_lock(&Giant);
+ retval = ukbd_poll(kbd, on);
+ mtx_unlock(&Giant);
+ return (retval);
}
mtx_assert(&Giant, MA_OWNED);
diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h
index fbdfe31..6e35542 100644
--- a/sys/dev/usb/usb_controller.h
+++ b/sys/dev/usb/usb_controller.h
@@ -99,6 +99,9 @@ struct usb_bus_methods {
void (*set_stall) (struct usb_device *udev, struct usb_xfer *xfer, struct usb_endpoint *ep, uint8_t *did_stall);
void (*clear_stall) (struct usb_device *udev, struct usb_endpoint *ep);
+ /* Optional transfer polling support */
+
+ void (*xfer_poll) (struct usb_bus *);
};
/*
diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c
index 04b462e..3c466fb 100644
--- a/sys/dev/usb/usb_transfer.c
+++ b/sys/dev/usb/usb_transfer.c
@@ -2853,15 +2853,99 @@ usbd_clear_stall_callback(struct usb_xfer *xfer1,
return (1); /* Clear Stall Finished */
}
+/*------------------------------------------------------------------------*
+ * usbd_transfer_poll
+ *
+ * The following function gets called from the USB keyboard driver and
+ * UMASS when the system has paniced.
+ *
+ * NOTE: It is currently not possible to resume normal operation on
+ * the USB controller which has been polled, due to clearing of the
+ * "up_dsleep" and "up_msleep" flags.
+ *------------------------------------------------------------------------*/
void
usbd_transfer_poll(struct usb_xfer **ppxfer, uint16_t max)
{
- static uint8_t once = 0;
- /* polling is currently not supported */
- if (!once) {
- once = 1;
- printf("usbd_transfer_poll: USB polling is "
- "not supported!\n");
+ struct usb_xfer *xfer;
+ struct usb_xfer_root *xroot;
+ struct usb_device *udev;
+ struct usb_proc_msg *pm;
+ uint16_t n;
+ uint16_t drop_bus;
+ uint16_t drop_xfer;
+
+ for (n = 0; n != max; n++) {
+ /* Extra checks to avoid panic */
+ xfer = ppxfer[n];
+ if (xfer == NULL)
+ continue; /* no USB transfer */
+ xroot = xfer->xroot;
+ if (xroot == NULL)
+ continue; /* no USB root */
+ udev = xroot->udev;
+ if (udev == NULL)
+ continue; /* no USB device */
+ if (udev->bus == NULL)
+ continue; /* no BUS structure */
+ if (udev->bus->methods == NULL)
+ continue; /* no BUS methods */
+ if (udev->bus->methods->xfer_poll == NULL)
+ continue; /* no poll method */
+
+ /* make sure that the BUS mutex is not locked */
+ drop_bus = 0;
+ while (mtx_owned(&xroot->udev->bus->bus_mtx)) {
+ mtx_unlock(&xroot->udev->bus->bus_mtx);
+ drop_bus++;
+ }
+
+ /* make sure that the transfer mutex is not locked */
+ drop_xfer = 0;
+ while (mtx_owned(xroot->xfer_mtx)) {
+ mtx_unlock(xroot->xfer_mtx);
+ drop_xfer++;
+ }
+
+ /* Make sure cv_signal() and cv_broadcast() is not called */
+ udev->bus->control_xfer_proc.up_dsleep = 0;
+ udev->bus->control_xfer_proc.up_msleep = 0;
+ udev->bus->explore_proc.up_dsleep = 0;
+ udev->bus->explore_proc.up_msleep = 0;
+ udev->bus->giant_callback_proc.up_dsleep = 0;
+ udev->bus->giant_callback_proc.up_msleep = 0;
+ udev->bus->non_giant_callback_proc.up_dsleep = 0;
+ udev->bus->non_giant_callback_proc.up_msleep = 0;
+
+ /* poll USB hardware */
+ (udev->bus->methods->xfer_poll) (udev->bus);
+
+ USB_BUS_LOCK(xroot->bus);
+
+ /* check for clear stall */
+ if (udev->default_xfer[1] != NULL) {
+
+ /* poll clear stall start */
+ pm = &udev->cs_msg[0].hdr;
+ (pm->pm_callback) (pm);
+ /* poll clear stall done thread */
+ pm = &udev->default_xfer[1]->
+ xroot->done_m[0].hdr;
+ (pm->pm_callback) (pm);
+ }
+
+ /* poll done thread */
+ pm = &xroot->done_m[0].hdr;
+ (pm->pm_callback) (pm);
+
+ USB_BUS_UNLOCK(xroot->bus);
+
+ /* restore transfer mutex */
+ while (drop_xfer--)
+ mtx_lock(xroot->xfer_mtx);
+
+ /* restore BUS mutex */
+ while (drop_bus--)
+ mtx_lock(&xroot->udev->bus->bus_mtx);
}
}
OpenPOWER on IntegriCloud