<div dir="ltr">From: Yurii Shevtsov <<a href="mailto:ungetch@gmail.com">ungetch@gmail.com</a>><br>Subject: [PATCH] Pulled and ported DWC OTG driver for RPi from FreeBSD. Modified USB sources during porting. Added driver to build by waf and make<br><br>---<br> Makefile                                           |    3 +<br> freebsd/sys/arm/broadcom/bcm2835/bcm283x_dwc_fdt.c |  116 +<br> freebsd/sys/dev/usb/controller/dwc_otg.c           | 4903 ++++++++++++++++++++<br> freebsd/sys/dev/usb/controller/dwc_otg.h           |  223 +<br> freebsd/sys/dev/usb/controller/dwc_otg_fdt.c       |  235 +<br> freebsd/sys/dev/usb/controller/dwc_otg_fdt.h       |   39 +<br> freebsd/sys/dev/usb/controller/dwc_otgreg.h        |  800 ++++<br> freebsd/sys/dev/usb/usb.h                          |    9 +<br> freebsd/sys/dev/usb/usb_bus.h                      |    3 +<br> freebsd/sys/dev/usb/usb_core.c                     |    7 +<br> freebsd/sys/dev/usb/usb_core.h                     |    8 +<br> rtemsbsd/include/bsp/nexus-devices.h               |   19 +<br> rtemsbsd/include/machine/rtems-bsd-sysinit.h       |    3 +<br> wscript                                            |    3 +<br> 14 files changed, 6371 insertions(+), 0 deletions(-)<br> create mode 100644 freebsd/sys/arm/broadcom/bcm2835/bcm283x_dwc_fdt.c<br> create mode 100644 freebsd/sys/dev/usb/controller/dwc_otg.c<br> create mode 100644 freebsd/sys/dev/usb/controller/dwc_otg.h<br> create mode 100644 freebsd/sys/dev/usb/controller/dwc_otg_fdt.c<br> create mode 100644 freebsd/sys/dev/usb/controller/dwc_otg_fdt.h<br> create mode 100644 freebsd/sys/dev/usb/controller/dwc_otgreg.h<br><br>diff --git a/Makefile b/Makefile<br>index da2a5ef..02964d3 100644<br>--- a/Makefile<br>+++ b/Makefile<br>@@ -186,6 +186,7 @@ LIB_C_FILES += freebsd/sys/dev/tsec/if_tsec.c<br> LIB_C_FILES += freebsd/sys/dev/cadence/if_cgem.c<br> LIB_C_FILES += freebsd/sys/dev/dwc/if_dwc.c<br> LIB_C_FILES += freebsd/sys/arm/xilinx/zy7_slcr.c<br>+LIB_C_FILES += freebsd/sys/arm/broadcom/bcm2835/bcm283x_dwc_fdt.c<br> LIB_C_FILES += freebsd/sys/dev/random/harvest.c<br> LIB_C_FILES += freebsd/sys/netinet/tcp_hostcache.c<br> LIB_C_FILES += freebsd/sys/dev/led/led.c<br>@@ -244,6 +245,8 @@ LIB_C_FILES += freebsd/sys/dev/usb/usb_process.c<br> LIB_C_FILES += freebsd/sys/dev/usb/usb_request.c<br> LIB_C_FILES += freebsd/sys/dev/usb/usb_transfer.c<br> LIB_C_FILES += freebsd/sys/dev/usb/usb_util.c<br>+LIB_C_FILES += freebsd/sys/dev/usb/controller/dwc_otg.c<br>+LIB_C_FILES += freebsd/sys/dev/usb/controller/dwc_otg_fdt.c<br> LIB_C_FILES += freebsd/sys/dev/usb/controller/ohci.c<br> LIB_C_FILES += freebsd/sys/dev/usb/controller/ehci.c<br> LIB_C_FILES += freebsd/sys/dev/usb/controller/usb_controller.c<br>diff --git a/freebsd/sys/arm/broadcom/bcm2835/bcm283x_dwc_fdt.c b/freebsd/sys/arm/broadcom/bcm2835/bcm283x_dwc_fdt.c<br>new file mode 100644<br>index 0000000..71ff670<br>--- /dev/null<br>+++ b/freebsd/sys/arm/broadcom/bcm2835/bcm283x_dwc_fdt.c<br>@@ -0,0 +1,116 @@<br>+#include <machine/rtems-bsd-kernel-space.h><br>+/*<br>+ * Copyright 2015 Andrew Turner.<br>+ * All rights reserved.<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions are<br>+ * met:<br>+ *<br>+ *  1. Redistributions of source code must retain the above copyright<br>+ *     notice, this list of conditions and the following disclaimer.<br>+ *  2. Redistributions in binary form must reproduce the above copyright<br>+ *     notice, this list of conditions and the following disclaimer in the<br>+ *     documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR<br>+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE<br>+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR<br>+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,<br>+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR<br>+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF<br>+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>+ */<br>+<br>+#include <sys/cdefs.h><br>+__FBSDID("$FreeBSD$");<br>+<br>+#include <rtems/bsd/sys/param.h><br>+#include <sys/kernel.h><br>+#include <sys/bus.h><br>+#include <sys/callout.h><br>+#include <sys/condvar.h><br>+#include <sys/module.h><br>+<br>+#ifndef __rtems__<br>+#include <dev/ofw/ofw_bus_subr.h><br>+#endif<br>+<br>+#include <dev/usb/usb.h><br>+#include <dev/usb/usbdi.h><br>+<br>+#include <dev/usb/usb_busdma.h><br>+#include <dev/usb/usb_process.h><br>+<br>+#include <dev/usb/usb_controller.h><br>+#include <dev/usb/usb_bus.h><br>+<br>+#include <dev/usb/controller/dwc_otg.h><br>+#include <dev/usb/controller/dwc_otg_fdt.h><br>+<br>+#ifndef __rtems__<br>+#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h><br>+#else<br>+#include <bsp/vc.h><br>+#endif<br>+<br>+static device_probe_t bcm283x_dwc_otg_probe;<br>+static device_attach_t bcm283x_dwc_otg_attach;<br>+<br>+static int<br>+bcm283x_dwc_otg_probe(device_t dev)<br>+{<br>+<br>+    #ifndef __rtems__<br>+    if (!ofw_bus_status_okay(dev))<br>+        return (ENXIO);<br>+<br>+    if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-usb"))<br>+        return (ENXIO);<br>+    #endif<br>+        <br>+    device_set_desc(dev, "DWC OTG 2.0 integrated USB controller (bcm283x)");<br>+<br>+    return (BUS_PROBE_VENDOR);<br>+}<br>+<br>+static int<br>+bcm283x_dwc_otg_attach(device_t dev)<br>+{<br>+    #ifndef __rtems__<br>+    bcm2835_mbox_set_power_state(dev, BCM2835_MBOX_POWER_ID_USB_HCD, TRUE);<br>+    #else<br>+    bcm2835_set_power_state_entries entries;<br>+    entries.dev_id = bcm2835_mailbox_power_udid_usb_hcd;<br>+    entries.state = BCM2835_MAILBOX_SET_POWER_STATE_REQ_ON<br>+                    | BCM2835_MAILBOX_SET_POWER_STATE_REQ_WAIT;<br>+    int ret = bcm2835_mailbox_set_power_state(&entries);<br>+    if (ret) return ENXIO;<br>+    #endif<br>+    return (dwc_otg_attach(dev));<br>+}<br>+<br>+static device_method_t bcm283x_dwc_otg_methods[] = {<br>+    /* bus interface */<br>+    DEVMETHOD(device_probe, bcm283x_dwc_otg_probe),<br>+    DEVMETHOD(device_attach, bcm283x_dwc_otg_attach),<br>+<br>+    DEVMETHOD_END<br>+};<br>+<br>+static devclass_t bcm283x_dwc_otg_devclass;<br>+<br>+DEFINE_CLASS_1(bcm283x_dwcotg, bcm283x_dwc_otg_driver, bcm283x_dwc_otg_methods,<br>+    sizeof(struct dwc_otg_fdt_softc), dwc_otg_driver);<br>+#ifndef __rtems__<br>+DRIVER_MODULE(bcm283x_dwcotg, simplebus, bcm283x_dwc_otg_driver,<br>+    bcm283x_dwc_otg_devclass, 0, 0);<br>+#else<br>+DRIVER_MODULE(bcm283x_dwcotg, nexus, bcm283x_dwc_otg_driver,<br>+    bcm283x_dwc_otg_devclass, 0, 0);<br>+#endif<br>+MODULE_DEPEND(bcm283x_dwcotg, usb, 1, 1, 1);<br>diff --git a/freebsd/sys/dev/usb/controller/dwc_otg.c b/freebsd/sys/dev/usb/controller/dwc_otg.c<br>new file mode 100644<br>index 0000000..f84a896<br>--- /dev/null<br>+++ b/freebsd/sys/dev/usb/controller/dwc_otg.c<br>@@ -0,0 +1,4903 @@<br>+#include <machine/rtems-bsd-kernel-space.h><br>+/*-<br>+ * Copyright (c) 2012 Hans Petter Selasky. All rights reserved.<br>+ * Copyright (c) 2010-2011 Aleksandr Rybalko. All rights reserved.<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>+ * SUCH DAMAGE.<br>+ */<br>+<br>+/*<br>+ * This file contains the driver for the DesignWare series USB 2.0 OTG<br>+ * Controller.<br>+ */<br>+<br>+/*<br>+ * LIMITATION: Drivers must be bound to all OUT endpoints in the<br>+ * active configuration for this driver to work properly. Blocking any<br>+ * OUT endpoint will block all OUT endpoints including the control<br>+ * endpoint. Usually this is not a problem.<br>+ */<br>+<br>+/*<br>+ * NOTE: Writing to non-existing registers appears to cause an<br>+ * internal reset.<br>+ */<br>+#include <sys/cdefs.h><br>+__FBSDID("$FreeBSD$");<br>+<br>+#include <sys/stdint.h><br>+#include <sys/stddef.h><br>+#include <rtems/bsd/sys/param.h><br>+#include <sys/queue.h><br>+#include <rtems/bsd/sys/types.h><br>+#include <sys/systm.h><br>+#include <sys/kernel.h><br>+#include <sys/bus.h><br>+#include <sys/module.h><br>+#include <rtems/bsd/sys/lock.h><br>+#include <sys/mutex.h><br>+#include <sys/condvar.h><br>+#include <sys/sysctl.h><br>+#include <sys/sx.h><br>+#include <rtems/bsd/sys/unistd.h><br>+#include <sys/callout.h><br>+#include <sys/malloc.h><br>+#include <sys/priv.h><br>+<br>+#include <dev/usb/usb.h><br>+#include <dev/usb/usbdi.h><br>+<br>+#define    USB_DEBUG_VAR dwc_otg_debug<br>+<br>+#include <dev/usb/usb_core.h><br>+#include <dev/usb/usb_debug.h><br>+#include <dev/usb/usb_busdma.h><br>+#include <dev/usb/usb_process.h><br>+#include <dev/usb/usb_transfer.h><br>+#include <dev/usb/usb_device.h><br>+#include <dev/usb/usb_hub.h><br>+#include <dev/usb/usb_util.h><br>+<br>+#include <dev/usb/usb_controller.h><br>+#include <dev/usb/usb_bus.h><br>+<br>+#include <dev/usb/controller/dwc_otg.h><br>+#include <dev/usb/controller/dwc_otgreg.h><br>+<br>+#define    DWC_OTG_BUS2SC(bus) \<br>+   ((struct dwc_otg_softc *)(((uint8_t *)(bus)) - \<br>+    ((uint8_t *)&(((struct dwc_otg_softc *)0)->sc_bus))))<br>+<br>+#define    DWC_OTG_PC2UDEV(pc) \<br>+   (USB_DMATAG_TO_XROOT((pc)->tag_parent)->udev)<br>+<br>+#define    DWC_OTG_MSK_GINT_ENABLED    \<br>+   (GINTMSK_ENUMDONEMSK |        \<br>+   GINTMSK_USBRSTMSK |            \<br>+   GINTMSK_USBSUSPMSK |            \<br>+   GINTMSK_IEPINTMSK |            \<br>+   GINTMSK_SESSREQINTMSK |        \<br>+   GINTMSK_RXFLVLMSK |            \<br>+   GINTMSK_HCHINTMSK |            \<br>+   GINTMSK_OTGINTMSK |            \<br>+   GINTMSK_PRTINTMSK)<br>+<br>+#define    DWC_OTG_MSK_GINT_THREAD_IRQ                \<br>+   (GINTSTS_USBRST | GINTSTS_ENUMDONE | GINTSTS_PRTINT |    \<br>+   GINTSTS_WKUPINT | GINTSTS_USBSUSP | GINTMSK_OTGINTMSK |    \<br>+   GINTSTS_SESSREQINT)<br>+<br>+#define    DWC_OTG_PHY_ULPI 0<br>+#define    DWC_OTG_PHY_HSIC 1<br>+#define    DWC_OTG_PHY_INTERNAL 2<br>+<br>+#ifndef DWC_OTG_PHY_DEFAULT<br>+#define    DWC_OTG_PHY_DEFAULT DWC_OTG_PHY_ULPI<br>+#endif<br>+<br>+static int dwc_otg_phy_type = DWC_OTG_PHY_DEFAULT;<br>+<br>+static SYSCTL_NODE(_hw_usb, OID_AUTO, dwc_otg, CTLFLAG_RW, 0, "USB DWC OTG");<br>+SYSCTL_INT(_hw_usb_dwc_otg, OID_AUTO, phy_type, CTLFLAG_RDTUN,<br>+    &dwc_otg_phy_type, 0, "DWC OTG PHY TYPE - 0/1/2 - ULPI/HSIC/INTERNAL");<br>+<br>+#ifdef USB_DEBUG<br>+static int dwc_otg_debug;<br>+<br>+SYSCTL_INT(_hw_usb_dwc_otg, OID_AUTO, debug, CTLFLAG_RWTUN,<br>+    &dwc_otg_debug, 0, "DWC OTG debug level");<br>+#endif<br>+<br>+#define    DWC_OTG_INTR_ENDPT 1<br>+<br>+/* prototypes */<br>+<br>+extern struct usb_bus_methods dwc_otg_bus_methods;<br>+extern struct usb_pipe_methods dwc_otg_device_non_isoc_methods;<br>+extern struct usb_pipe_methods dwc_otg_device_isoc_methods;<br>+<br>+static dwc_otg_cmd_t dwc_otg_setup_rx;<br>+static dwc_otg_cmd_t dwc_otg_data_rx;<br>+static dwc_otg_cmd_t dwc_otg_data_tx;<br>+static dwc_otg_cmd_t dwc_otg_data_tx_sync;<br>+<br>+static dwc_otg_cmd_t dwc_otg_host_setup_tx;<br>+static dwc_otg_cmd_t dwc_otg_host_data_tx;<br>+static dwc_otg_cmd_t dwc_otg_host_data_rx;<br>+<br>+static void dwc_otg_device_done(struct usb_xfer *, usb_error_t);<br>+static void dwc_otg_do_poll(struct usb_bus *);<br>+static void dwc_otg_standard_done(struct usb_xfer *);<br>+static void dwc_otg_root_intr(struct dwc_otg_softc *);<br>+static void dwc_otg_interrupt_poll_locked(struct dwc_otg_softc *);<br>+static void dwc_otg_host_channel_disable(struct dwc_otg_softc *, uint8_t);<br>+<br>+/*<br>+ * Here is a configuration that the chip supports.<br>+ */<br>+struct usb_hw_ep_profile dwc_otg_ep_profile[1] = {<br>+<br>+    [0] = {<br>+        .max_in_frame_size = 64,/* fixed */<br>+        .max_out_frame_size = 64,    /* fixed */<br>+        .is_simplex = 1,<br>+        .support_control = 1,<br>+    }<br>+};<br>+<br>+static void<br>+dwc_otg_get_hw_ep_profile(struct usb_device *udev,<br>+    const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)<br>+{<br>+    struct dwc_otg_softc *sc;<br>+<br>+    sc = DWC_OTG_BUS2SC(udev->bus);<br>+<br>+    if (ep_addr < sc->sc_dev_ep_max)<br>+        *ppf = &sc->sc_hw_ep_profile[ep_addr].usb;<br>+    else<br>+        *ppf = NULL;<br>+}<br>+<br>+static int<br>+dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode)<br>+{<br>+    struct dwc_otg_profile *pf;<br>+    uint32_t fifo_size;<br>+    uint32_t fifo_regs;<br>+    uint32_t tx_start;<br>+    uint8_t x;<br>+<br>+    fifo_size = sc->sc_fifo_size;<br>+<br>+    /*<br>+     * NOTE: Reserved fixed size area at end of RAM, which must<br>+     * not be allocated to the FIFOs:<br>+     */<br>+    fifo_regs = 4 * 16;<br>+<br>+    if (fifo_size < fifo_regs) {<br>+        DPRINTF("Too little FIFO\n");<br>+        return (EINVAL);<br>+    }<br>+<br>+    /* subtract FIFO regs from total once */<br>+    fifo_size -= fifo_regs;<br>+<br>+    /* split equally for IN and OUT */<br>+    fifo_size /= 2;<br>+<br>+    /* align to 4 bytes boundary */<br>+    fifo_size &= ~3;<br>+<br>+    /* set global receive FIFO size */<br>+    DWC_OTG_WRITE_4(sc, DOTG_GRXFSIZ, fifo_size / 4);<br>+<br>+    tx_start = fifo_size;<br>+<br>+    if (fifo_size < 64) {<br>+        DPRINTFN(-1, "Not enough data space for EP0 FIFO.\n");<br>+        return (EINVAL);<br>+    }<br>+<br>+    /* disable any leftover host channels */<br>+    for (x = 0; x != sc->sc_host_ch_max; x++) {<br>+        if (sc->sc_chan_state[x].wait_sof == 0)<br>+            continue;<br>+        dwc_otg_host_channel_disable(sc, x);<br>+    }<br>+<br>+    if (mode == DWC_MODE_HOST) {<br>+<br>+        /* reset active endpoints */<br>+        sc->sc_active_rx_ep = 0;<br>+<br>+        /* split equally for periodic and non-periodic */<br>+        fifo_size /= 2;<br>+<br>+        /* align to 4 bytes boundary */<br>+        fifo_size &= ~3;<br>+<br>+        DWC_OTG_WRITE_4(sc, DOTG_GNPTXFSIZ,<br>+            ((fifo_size / 4) << 16) |<br>+            (tx_start / 4));<br>+<br>+        tx_start += fifo_size;<br>+<br>+        for (x = 0; x != sc->sc_host_ch_max; x++) {<br>+            /* disable all host interrupts */<br>+            DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x),<br>+                HCINT_DEFAULT_MASK);<br>+        }<br>+<br>+        DWC_OTG_WRITE_4(sc, DOTG_HPTXFSIZ,<br>+            ((fifo_size / 4) << 16) |<br>+            (tx_start / 4));<br>+<br>+        /* reset host channel state */<br>+        memset(sc->sc_chan_state, 0, sizeof(sc->sc_chan_state));<br>+<br>+        /* reset FIFO TX levels */<br>+        sc->sc_tx_cur_p_level = 0;<br>+        sc->sc_tx_cur_np_level = 0;<br>+<br>+        /* store maximum periodic and non-periodic FIFO TX size */<br>+        sc->sc_tx_max_size = fifo_size;<br>+<br>+        /* enable all host channel interrupts */<br>+        DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK,<br>+            (1U << sc->sc_host_ch_max) - 1U);<br>+    }<br>+<br>+    if (mode == DWC_MODE_DEVICE) {<br>+<br>+        DWC_OTG_WRITE_4(sc, DOTG_GNPTXFSIZ,<br>+        (0x10 << 16) | (tx_start / 4));<br>+        fifo_size -= 0x40;<br>+        tx_start += 0x40;<br>+<br>+        /* setup control endpoint profile */<br>+        sc->sc_hw_ep_profile[0].usb = dwc_otg_ep_profile[0];<br>+<br>+        /* reset active endpoints */<br>+        sc->sc_active_rx_ep = 1;<br>+<br>+        for (x = 1; x != sc->sc_dev_ep_max; x++) {<br>+<br>+        pf = sc->sc_hw_ep_profile + x;<br>+<br>+        pf->usb.max_out_frame_size = 1024 * 3;<br>+        pf->usb.is_simplex = 0;    /* assume duplex */<br>+        pf->usb.support_bulk = 1;<br>+        pf->usb.support_interrupt = 1;<br>+        pf->usb.support_isochronous = 1;<br>+        pf->usb.support_out = 1;<br>+<br>+        if (x < sc->sc_dev_in_ep_max) {<br>+            uint32_t limit;<br>+<br>+            limit = (x == 1) ? MIN(DWC_OTG_TX_MAX_FIFO_SIZE,<br>+                DWC_OTG_MAX_TXN) : MIN(DWC_OTG_MAX_TXN / 2,<br>+                DWC_OTG_TX_MAX_FIFO_SIZE);<br>+<br>+            /* see if there is enough FIFO space */<br>+            if (limit <= fifo_size) {<br>+                pf->max_buffer = limit;<br>+                pf->usb.support_in = 1;<br>+            } else {<br>+                limit = MIN(DWC_OTG_TX_MAX_FIFO_SIZE, 0x40);<br>+                if (limit <= fifo_size) {<br>+                    pf->usb.support_in = 1;<br>+                } else {<br>+                    pf->usb.is_simplex = 1;<br>+                    limit = 0;<br>+                }<br>+            }<br>+            /* set FIFO size */<br>+            DWC_OTG_WRITE_4(sc, DOTG_DIEPTXF(x),<br>+                ((limit / 4) << 16) | (tx_start / 4));<br>+            tx_start += limit;<br>+            fifo_size -= limit;<br>+            pf->usb.max_in_frame_size = limit;<br>+        } else {<br>+            pf->usb.is_simplex = 1;<br>+        }<br>+<br>+        DPRINTF("FIFO%d = IN:%d / OUT:%d\n", x,<br>+            pf->usb.max_in_frame_size,<br>+            pf->usb.max_out_frame_size);<br>+        }<br>+    }<br>+<br>+    /* reset RX FIFO */<br>+    DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL,<br>+        GRSTCTL_RXFFLSH);<br>+<br>+    if (mode != DWC_MODE_OTG) {<br>+        /* reset all TX FIFOs */<br>+        DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL,<br>+            GRSTCTL_TXFIFO(0x10) |<br>+            GRSTCTL_TXFFLSH);<br>+    } else {<br>+        /* reset active endpoints */<br>+        sc->sc_active_rx_ep = 0;<br>+<br>+        /* reset periodic and non-periodic FIFO TX size */<br>+        sc->sc_tx_max_size = fifo_size;<br>+<br>+        /* reset host channel state */<br>+        memset(sc->sc_chan_state, 0, sizeof(sc->sc_chan_state));<br>+<br>+        /* reset FIFO TX levels */<br>+        sc->sc_tx_cur_p_level = 0;<br>+        sc->sc_tx_cur_np_level = 0;<br>+    }<br>+    return (0);<br>+}<br>+<br>+static void<br>+dwc_otg_update_host_frame_interval(struct dwc_otg_softc *sc)<br>+{<br>+<br>+  /*<br>+   * Disabled until further. Assuming that the register is already<br>+   * programmed correctly by the boot loader.<br>+   */<br>+#if 0<br>+    uint32_t temp;<br>+<br>+    /* setup HOST frame interval register, based on existing value */<br>+    temp = DWC_OTG_READ_4(sc, DOTG_HFIR) & HFIR_FRINT_MASK;<br>+    if (temp >= 10000)<br>+        temp /= 1000;<br>+    else<br>+        temp /= 125;<br>+<br>+    /* figure out nearest X-tal value */<br>+    if (temp >= 54)<br>+        temp = 60;    /* MHz */<br>+    else if (temp >= 39)<br>+        temp = 48;    /* MHz */<br>+    else<br>+        temp = 30;    /* MHz */<br>+<br>+    if (sc->sc_flags.status_high_speed)<br>+        temp *= 125;<br>+    else<br>+        temp *= 1000;<br>+<br>+    DPRINTF("HFIR=0x%08x\n", temp);<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HFIR, temp);<br>+#endif<br>+}<br>+<br>+static void<br>+dwc_otg_clocks_on(struct dwc_otg_softc *sc)<br>+{<br>+    if (sc->sc_flags.clocks_off &&<br>+        sc->sc_flags.port_powered) {<br>+<br>+        DPRINTFN(5, "\n");<br>+<br>+        /* TODO - platform specific */<br>+<br>+        sc->sc_flags.clocks_off = 0;<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_clocks_off(struct dwc_otg_softc *sc)<br>+{<br>+    if (!sc->sc_flags.clocks_off) {<br>+<br>+        DPRINTFN(5, "\n");<br>+<br>+        /* TODO - platform specific */<br>+<br>+        sc->sc_flags.clocks_off = 1;<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_pull_up(struct dwc_otg_softc *sc)<br>+{<br>+    uint32_t temp;<br>+<br>+    /* pullup D+, if possible */<br>+<br>+    if (!sc->sc_flags.d_pulled_up &&<br>+        sc->sc_flags.port_powered) {<br>+        sc->sc_flags.d_pulled_up = 1;<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_DCTL);<br>+        temp &= ~DCTL_SFTDISCON;<br>+        DWC_OTG_WRITE_4(sc, DOTG_DCTL, temp);<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_pull_down(struct dwc_otg_softc *sc)<br>+{<br>+    uint32_t temp;<br>+<br>+    /* pulldown D+, if possible */<br>+<br>+    if (sc->sc_flags.d_pulled_up) {<br>+        sc->sc_flags.d_pulled_up = 0;<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_DCTL);<br>+        temp |= DCTL_SFTDISCON;<br>+        DWC_OTG_WRITE_4(sc, DOTG_DCTL, temp);<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_enable_sof_irq(struct dwc_otg_softc *sc)<br>+{<br>+    /* In device mode we don't use the SOF interrupt */<br>+    if (sc->sc_flags.status_device_mode != 0 ||<br>+        (sc->sc_irq_mask & GINTMSK_SOFMSK) != 0)<br>+        return;<br>+    sc->sc_irq_mask |= GINTMSK_SOFMSK;<br>+    DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+}<br>+<br>+static void<br>+dwc_otg_resume_irq(struct dwc_otg_softc *sc)<br>+{<br>+    if (sc->sc_flags.status_suspend) {<br>+        /* update status bits */<br>+        sc->sc_flags.status_suspend = 0;<br>+        sc->sc_flags.change_suspend = 1;<br>+<br>+        if (sc->sc_flags.status_device_mode) {<br>+            /*<br>+             * Disable resume interrupt and enable suspend<br>+             * interrupt:<br>+             */<br>+            sc->sc_irq_mask &= ~GINTMSK_WKUPINTMSK;<br>+            sc->sc_irq_mask |= GINTMSK_USBSUSPMSK;<br>+            DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+        }<br>+<br>+        /* complete root HUB interrupt endpoint */<br>+        dwc_otg_root_intr(sc);<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_suspend_irq(struct dwc_otg_softc *sc)<br>+{<br>+    if (!sc->sc_flags.status_suspend) {<br>+        /* update status bits */<br>+        sc->sc_flags.status_suspend = 1;<br>+        sc->sc_flags.change_suspend = 1;<br>+<br>+        if (sc->sc_flags.status_device_mode) {<br>+            /*<br>+             * Disable suspend interrupt and enable resume<br>+             * interrupt:<br>+             */<br>+            sc->sc_irq_mask &= ~GINTMSK_USBSUSPMSK;<br>+            sc->sc_irq_mask |= GINTMSK_WKUPINTMSK;<br>+            DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+        }<br>+<br>+        /* complete root HUB interrupt endpoint */<br>+        dwc_otg_root_intr(sc);<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_wakeup_peer(struct dwc_otg_softc *sc)<br>+{<br>+    if (!sc->sc_flags.status_suspend)<br>+        return;<br>+<br>+    DPRINTFN(5, "Remote wakeup\n");<br>+<br>+    if (sc->sc_flags.status_device_mode) {<br>+        uint32_t temp;<br>+<br>+        /* enable remote wakeup signalling */<br>+        temp = DWC_OTG_READ_4(sc, DOTG_DCTL);<br>+        temp |= DCTL_RMTWKUPSIG;<br>+        DWC_OTG_WRITE_4(sc, DOTG_DCTL, temp);<br>+<br>+        /* Wait 8ms for remote wakeup to complete. */<br>+        usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125);<br>+<br>+        temp &= ~DCTL_RMTWKUPSIG;<br>+        DWC_OTG_WRITE_4(sc, DOTG_DCTL, temp);<br>+    } else {<br>+        /* enable USB port */<br>+        DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0);<br>+<br>+        /* wait 10ms */<br>+        usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);<br>+<br>+        /* resume port */<br>+        sc->sc_hprt_val |= HPRT_PRTRES;<br>+        DWC_OTG_WRITE_4(sc, DOTG_HPRT, sc->sc_hprt_val);<br>+<br>+        /* Wait 100ms for resume signalling to complete. */<br>+        usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 10);<br>+<br>+        /* clear suspend and resume */<br>+        sc->sc_hprt_val &= ~(HPRT_PRTSUSP | HPRT_PRTRES);<br>+        DWC_OTG_WRITE_4(sc, DOTG_HPRT, sc->sc_hprt_val);<br>+<br>+        /* Wait 4ms */<br>+        usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 250);<br>+    }<br>+<br>+    /* need to fake resume IRQ */<br>+    dwc_otg_resume_irq(sc);<br>+}<br>+<br>+static void<br>+dwc_otg_set_address(struct dwc_otg_softc *sc, uint8_t addr)<br>+{<br>+    uint32_t temp;<br>+<br>+    DPRINTFN(5, "addr=%d\n", addr);<br>+<br>+    temp = DWC_OTG_READ_4(sc, DOTG_DCFG);<br>+    temp &= ~DCFG_DEVADDR_SET(0x7F);<br>+    temp |= DCFG_DEVADDR_SET(addr);<br>+    DWC_OTG_WRITE_4(sc, DOTG_DCFG, temp);<br>+}<br>+<br>+static void<br>+dwc_otg_common_rx_ack(struct dwc_otg_softc *sc)<br>+{<br>+    DPRINTFN(5, "RX status clear\n");<br>+<br>+    /* enable RX FIFO level interrupt */<br>+    sc->sc_irq_mask |= GINTMSK_RXFLVLMSK;<br>+    DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+<br>+    /* clear cached status */<br>+    sc->sc_last_rx_status = 0;<br>+}<br>+<br>+static void<br>+dwc_otg_clear_hcint(struct dwc_otg_softc *sc, uint8_t x)<br>+{<br>+    uint32_t hcint;<br>+<br>+    /* clear all pending interrupts */<br>+    hcint = DWC_OTG_READ_4(sc, DOTG_HCINT(x));<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), hcint);<br>+<br>+    /* clear buffered interrupts */<br>+    sc->sc_chan_state[x].hcint = 0;<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_host_channel_alloc(struct dwc_otg_softc *sc, struct dwc_otg_td *td, uint8_t is_out)<br>+{<br>+    uint32_t tx_p_size;<br>+    uint32_t tx_np_size;<br>+    uint8_t x;<br>+<br>+    if (td->channel < DWC_OTG_MAX_CHANNELS)<br>+        return (0);        /* already allocated */<br>+<br>+    /* check if device is suspended */<br>+    if (DWC_OTG_PC2UDEV(td->pc)->flags.self_suspended != 0)<br>+        return (1);        /* busy - cannot transfer data */<br>+<br>+    /* compute needed TX FIFO size */<br>+    if (is_out != 0) {<br>+        if (td->ep_type == UE_ISOCHRONOUS) {<br>+            tx_p_size = td->max_packet_size;<br>+            tx_np_size = 0;<br>+            if (td->hcsplt != 0 && tx_p_size > HCSPLT_XACTLEN_BURST)<br>+                tx_p_size = HCSPLT_XACTLEN_BURST;<br>+            if ((sc->sc_tx_cur_p_level + tx_p_size) > sc->sc_tx_max_size) {<br>+                DPRINTF("Too little FIFO space\n");<br>+                return (1);    /* too little FIFO */<br>+            }<br>+        } else {<br>+            tx_p_size = 0;<br>+            tx_np_size = td->max_packet_size;<br>+            if (td->hcsplt != 0 && tx_np_size > HCSPLT_XACTLEN_BURST)<br>+                tx_np_size = HCSPLT_XACTLEN_BURST;<br>+            if ((sc->sc_tx_cur_np_level + tx_np_size) > sc->sc_tx_max_size) {<br>+                DPRINTF("Too little FIFO space\n");<br>+                return (1);    /* too little FIFO */<br>+            }<br>+        }<br>+    } else {<br>+        /* not a TX transaction */<br>+        tx_p_size = 0;<br>+        tx_np_size = 0;<br>+    }<br>+<br>+    for (x = 0; x != sc->sc_host_ch_max; x++) {<br>+        if (sc->sc_chan_state[x].allocated != 0)<br>+            continue;<br>+        /* check if channel is still enabled */<br>+        if (sc->sc_chan_state[x].wait_sof != 0)<br>+            continue;<br>+<br>+        sc->sc_chan_state[x].allocated = 1;<br>+        sc->sc_chan_state[x].tx_p_size = tx_p_size;<br>+        sc->sc_chan_state[x].tx_np_size = tx_np_size;<br>+<br>+        /* keep track of used TX FIFO, if any */<br>+        sc->sc_tx_cur_p_level += tx_p_size;<br>+        sc->sc_tx_cur_np_level += tx_np_size;<br>+<br>+        /* clear interrupts */<br>+        dwc_otg_clear_hcint(sc, x);<br>+<br>+        DPRINTF("CH=%d HCCHAR=0x%08x "<br>+            "HCSPLT=0x%08x\n", x, td->hcchar, td->hcsplt);<br>+<br>+        /* set active channel */<br>+        sc->sc_active_rx_ep |= (1 << x);<br>+<br>+        /* set channel */<br>+        td->channel = x;<br>+<br>+        return (0);    /* allocated */<br>+    }<br>+    /* wait a bit */<br>+    dwc_otg_enable_sof_irq(sc);<br>+    return (1);    /* busy */<br>+}<br>+<br>+static void<br>+dwc_otg_host_channel_free(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint8_t x;<br>+<br>+    if (td->channel >= DWC_OTG_MAX_CHANNELS)<br>+        return;        /* already freed */<br>+<br>+    /* free channel */<br>+    x = td->channel;<br>+    td->channel = DWC_OTG_MAX_CHANNELS;<br>+<br>+    DPRINTF("CH=%d\n", x);<br>+<br>+    /*<br>+     * We need to let programmed host channels run till complete<br>+     * else the host channel will stop functioning. Assume that<br>+     * after a fixed given amount of time the host channel is no<br>+     * longer doing any USB traffic:<br>+     */<br>+    if (td->ep_type == UE_ISOCHRONOUS) {<br>+        /* double buffered */<br>+        sc->sc_chan_state[x].wait_sof = DWC_OTG_SLOT_IDLE_MAX;<br>+    } else {<br>+        /* single buffered */<br>+        sc->sc_chan_state[x].wait_sof = DWC_OTG_SLOT_IDLE_MIN;<br>+    }<br>+<br>+    sc->sc_chan_state[x].allocated = 0;<br>+<br>+    /* ack any pending messages */<br>+    if (sc->sc_last_rx_status != 0 &&<br>+        GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) == x) {<br>+        dwc_otg_common_rx_ack(sc);<br>+    }<br>+<br>+    /* clear active channel */<br>+    sc->sc_active_rx_ep &= ~(1 << x);<br>+}<br>+<br>+static void<br>+dwc_otg_host_dump_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    /* dump any pending messages */<br>+    if (sc->sc_last_rx_status != 0) {<br>+        if (td->channel < DWC_OTG_MAX_CHANNELS &&<br>+            td->channel == GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status)) {<br>+            dwc_otg_common_rx_ack(sc);<br>+        }<br>+    }<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_host_setup_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    struct usb_device_request req __aligned(4);<br>+    uint32_t hcint;<br>+    uint32_t hcchar;<br>+    uint8_t delta;<br>+<br>+    dwc_otg_host_dump_rx(sc, td);<br>+<br>+    if (td->channel < DWC_OTG_MAX_CHANNELS) {<br>+        hcint = sc->sc_chan_state[td->channel].hcint;<br>+<br>+        DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n",<br>+            td->channel, td->state, hcint,<br>+            DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)),<br>+            DWC_OTG_READ_4(sc, DOTG_HCTSIZ(td->channel)));<br>+    } else {<br>+        hcint = 0;<br>+        goto check_state;<br>+    }<br>+<br>+    if (hcint & (HCINT_RETRY |<br>+        HCINT_ACK | HCINT_NYET)) {<br>+        /* give success bits priority over failure bits */<br>+    } else if (hcint & HCINT_STALL) {<br>+        DPRINTF("CH=%d STALL\n", td->channel);<br>+        td->error_stall = 1;<br>+        td->error_any = 1;<br>+        goto complete;<br>+    } else if (hcint & HCINT_ERRORS) {<br>+        DPRINTF("CH=%d ERROR\n", td->channel);<br>+        td->errcnt++;<br>+        if (td->hcsplt != 0 || td->errcnt >= 3) {<br>+            td->error_any = 1;<br>+            goto complete;<br>+        }<br>+    }<br>+<br>+    if (hcint & (HCINT_ERRORS | HCINT_RETRY |<br>+        HCINT_ACK | HCINT_NYET)) {<br>+        if (!(hcint & HCINT_ERRORS))<br>+            td->errcnt = 0;<br>+    }<br>+<br>+check_state:<br>+    switch (td->state) {<br>+    case DWC_CHAN_ST_START:<br>+        goto send_pkt;<br>+<br>+    case DWC_CHAN_ST_WAIT_ANE:<br>+        if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            goto send_pkt;<br>+        } else if (hcint & (HCINT_ACK | HCINT_NYET)) {<br>+            td->offset += td->tx_bytes;<br>+            td->remainder -= td->tx_bytes;<br>+            td->toggle = 1;<br>+            td->tt_scheduled = 0;<br>+            goto complete;<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_S_ANE:<br>+        if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            goto send_pkt;<br>+        } else if (hcint & (HCINT_ACK | HCINT_NYET)) {<br>+            goto send_cpkt;<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_C_ANE:<br>+        if (hcint & HCINT_NYET) {<br>+            goto send_cpkt;<br>+        } else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            goto send_pkt;<br>+        } else if (hcint & HCINT_ACK) {<br>+            td->offset += td->tx_bytes;<br>+            td->remainder -= td->tx_bytes;<br>+            td->toggle = 1;<br>+            goto complete;<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_C_PKT:<br>+        goto send_cpkt;<br>+<br>+    default:<br>+        break;<br>+    }<br>+    goto busy;<br>+<br>+send_pkt:<br>+    /* free existing channel, if any */<br>+    dwc_otg_host_channel_free(sc, td);<br>+<br>+    if (sizeof(req) != td->remainder) {<br>+        td->error_any = 1;<br>+        goto complete;<br>+    }<br>+<br>+    if (td->hcsplt != 0) {<br>+        delta = td->tt_start_slot - sc->sc_last_frame_num - 1;<br>+        if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) {<br>+            td->state = DWC_CHAN_ST_START;<br>+            goto busy;<br>+        }<br>+        delta = sc->sc_last_frame_num - td->tt_start_slot;<br>+        if (delta > 5) {<br>+            /* missed it */<br>+            td->tt_scheduled = 0;<br>+            td->state = DWC_CHAN_ST_START;<br>+            goto busy;<br>+        }<br>+    }<br>+<br>+    /* allocate a new channel */<br>+    if (dwc_otg_host_channel_alloc(sc, td, 1)) {<br>+        td->state = DWC_CHAN_ST_START;<br>+        goto busy;<br>+    }<br>+<br>+    if (td->hcsplt != 0) {<br>+        td->hcsplt &= ~HCSPLT_COMPSPLT;<br>+        td->state = DWC_CHAN_ST_WAIT_S_ANE;<br>+    } else {<br>+        td->state = DWC_CHAN_ST_WAIT_ANE;<br>+    }<br>+<br>+    usbd_copy_out(td->pc, 0, &req, sizeof(req));<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel),<br>+        (sizeof(req) << HCTSIZ_XFERSIZE_SHIFT) |<br>+        (1 << HCTSIZ_PKTCNT_SHIFT) |<br>+        (HCTSIZ_PID_SETUP << HCTSIZ_PID_SHIFT));<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt);<br>+<br>+    hcchar = td->hcchar;<br>+    hcchar &= ~(HCCHAR_EPDIR_IN | HCCHAR_EPTYPE_MASK);<br>+    hcchar |= UE_CONTROL << HCCHAR_EPTYPE_SHIFT;<br>+<br>+    /* must enable channel before writing data to FIFO */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar);<br>+<br>+    /* transfer data into FIFO */<br>+    bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,<br>+        DOTG_DFIFO(td->channel), (uint32_t *)&req, sizeof(req) / 4);<br>+<br>+    /* wait until next slot before trying complete split */<br>+    td->tt_complete_slot = sc->sc_last_frame_num + 1;<br>+<br>+    /* store number of bytes transmitted */<br>+    td->tx_bytes = sizeof(req);<br>+    goto busy;<br>+<br>+send_cpkt:<br>+    /* free existing channel, if any */<br>+    dwc_otg_host_channel_free(sc, td);<br>+<br>+    delta = td->tt_complete_slot - sc->sc_last_frame_num - 1;<br>+    if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) {<br>+        td->state = DWC_CHAN_ST_WAIT_C_PKT;<br>+        goto busy;<br>+    }<br>+    delta = sc->sc_last_frame_num - td->tt_start_slot;<br>+    if (delta > DWC_OTG_TT_SLOT_MAX) {<br>+        /* we missed the service interval */<br>+        if (td->ep_type != UE_ISOCHRONOUS)<br>+            td->error_any = 1;<br>+        goto complete;<br>+    }<br>+    /* allocate a new channel */<br>+    if (dwc_otg_host_channel_alloc(sc, td, 0)) {<br>+        td->state = DWC_CHAN_ST_WAIT_C_PKT;<br>+        goto busy;<br>+    }<br>+<br>+    /* wait until next slot before trying complete split */<br>+    td->tt_complete_slot = sc->sc_last_frame_num + 1;<br>+<br>+    td->hcsplt |= HCSPLT_COMPSPLT;<br>+    td->state = DWC_CHAN_ST_WAIT_C_ANE;<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel),<br>+        (HCTSIZ_PID_SETUP << HCTSIZ_PID_SHIFT));<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt);<br>+<br>+    hcchar = td->hcchar;<br>+    hcchar &= ~(HCCHAR_EPDIR_IN | HCCHAR_EPTYPE_MASK);<br>+    hcchar |= UE_CONTROL << HCCHAR_EPTYPE_SHIFT;<br>+<br>+    /* must enable channel before writing data to FIFO */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar);<br>+<br>+busy:<br>+    return (1);    /* busy */<br>+<br>+complete:<br>+    dwc_otg_host_channel_free(sc, td);<br>+    return (0);    /* complete */<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_setup_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    struct usb_device_request req __aligned(4);<br>+    uint32_t temp;<br>+    uint16_t count;<br>+<br>+    /* check endpoint status */<br>+<br>+    if (sc->sc_last_rx_status == 0)<br>+        goto not_complete;<br>+<br>+    if (GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) != 0)<br>+        goto not_complete;<br>+<br>+    if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) !=<br>+        GRXSTSRD_DPID_DATA0) {<br>+        /* release FIFO */<br>+        dwc_otg_common_rx_ack(sc);<br>+        goto not_complete;<br>+    }<br>+<br>+    if ((sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) !=<br>+        GRXSTSRD_STP_DATA) {<br>+        /* release FIFO */<br>+        dwc_otg_common_rx_ack(sc);<br>+        goto not_complete;<br>+    }<br>+<br>+    DPRINTFN(5, "GRXSTSR=0x%08x\n", sc->sc_last_rx_status);<br>+<br>+    /* clear did stall */<br>+    td->did_stall = 0;<br>+<br>+    /* get the packet byte count */<br>+    count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status);<br>+<br>+    /* verify data length */<br>+    if (count != td->remainder) {<br>+        DPRINTFN(0, "Invalid SETUP packet "<br>+            "length, %d bytes\n", count);<br>+        /* release FIFO */<br>+        dwc_otg_common_rx_ack(sc);<br>+        goto not_complete;<br>+    }<br>+    if (count != sizeof(req)) {<br>+        DPRINTFN(0, "Unsupported SETUP packet "<br>+            "length, %d bytes\n", count);<br>+        /* release FIFO */<br>+        dwc_otg_common_rx_ack(sc);<br>+        goto not_complete;<br>+    }<br>+<br>+    /* copy in control request */<br>+    memcpy(&req, sc->sc_rx_bounce_buffer, sizeof(req));<br>+<br>+    /* copy data into real buffer */<br>+    usbd_copy_in(td->pc, 0, &req, sizeof(req));<br>+<br>+    td->offset = sizeof(req);<br>+    td->remainder = 0;<br>+<br>+    /* sneak peek the set address */<br>+    if ((req.bmRequestType == UT_WRITE_DEVICE) &&<br>+        (req.bRequest == UR_SET_ADDRESS)) {<br>+        /* must write address before ZLP */<br>+        dwc_otg_set_address(sc, req.wValue[0] & 0x7F);<br>+    }<br>+<br>+    /* don't send any data by default */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DIEPTSIZ(0),<br>+        DXEPTSIZ_SET_NPKT(0) | <br>+        DXEPTSIZ_SET_NBYTES(0));<br>+<br>+    temp = sc->sc_in_ctl[0];<br>+<br>+    /* enable IN endpoint */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(0),<br>+        temp | DIEPCTL_EPENA);<br>+    DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(0),<br>+        temp | DIEPCTL_SNAK);<br>+<br>+    /* reset IN endpoint buffer */<br>+    DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL,<br>+        GRSTCTL_TXFIFO(0) |<br>+        GRSTCTL_TXFFLSH);<br>+<br>+    /* acknowledge RX status */<br>+    dwc_otg_common_rx_ack(sc);<br>+    return (0);            /* complete */<br>+<br>+not_complete:<br>+    /* abort any ongoing transfer, before enabling again */<br>+<br>+    temp = sc->sc_out_ctl[0];<br>+<br>+    temp |= DOEPCTL_EPENA |<br>+        DOEPCTL_SNAK;<br>+<br>+    /* enable OUT endpoint */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(0), temp);<br>+<br>+    if (!td->did_stall) {<br>+        td->did_stall = 1;<br>+<br>+        DPRINTFN(5, "stalling IN and OUT direction\n");<br>+<br>+        /* set stall after enabling endpoint */<br>+        DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(0),<br>+            temp | DOEPCTL_STALL);<br>+<br>+        temp = sc->sc_in_ctl[0];<br>+<br>+        /* set stall assuming endpoint is enabled */<br>+        DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(0),<br>+            temp | DIEPCTL_STALL);<br>+    }<br>+<br>+    /* setup number of buffers to receive */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DOEPTSIZ(0),<br>+        DXEPTSIZ_SET_MULTI(3) |<br>+        DXEPTSIZ_SET_NPKT(1) | <br>+        DXEPTSIZ_SET_NBYTES(sizeof(req)));<br>+<br>+    return (1);            /* not complete */<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_host_rate_check_interrupt(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint8_t delta;<br>+<br>+    delta = sc->sc_tmr_val - td->tmr_val;<br>+    if (delta >= 128)<br>+        return (1);    /* busy */<br>+<br>+    td->tmr_val = sc->sc_tmr_val + td->tmr_res;<br>+<br>+    /* set toggle, if any */<br>+    if (td->set_toggle) {<br>+        td->set_toggle = 0;<br>+        td->toggle = 1;<br>+    }<br>+    return (0);<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_host_rate_check(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    if (td->ep_type == UE_ISOCHRONOUS) {<br>+        /* non TT isochronous traffic */<br>+        if ((td->tmr_val != 0) ||<br>+            (sc->sc_last_frame_num & (td->tmr_res - 1))) {<br>+            goto busy;<br>+        }<br>+        td->tmr_val = 1;    /* executed */<br>+        td->toggle = 0;<br>+<br>+    } else if (td->ep_type == UE_INTERRUPT) {<br>+        if (!td->tt_scheduled)<br>+            goto busy;<br>+        td->tt_scheduled = 0;<br>+    } else if (td->did_nak >= DWC_OTG_NAK_MAX) {<br>+        goto busy;<br>+    } else if (td->set_toggle) {<br>+        td->set_toggle = 0;<br>+        td->toggle = 1;<br>+    }<br>+    return (0);<br>+busy:<br>+    return (1);<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_host_data_rx_sub(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint32_t count;<br>+    uint8_t channel;<br>+<br>+    /* check endpoint status */<br>+    if (sc->sc_last_rx_status == 0)<br>+        goto busy;<br>+<br>+    channel = td->channel;<br>+    if (channel >= DWC_OTG_MAX_CHANNELS)<br>+        goto busy;<br>+<br>+    if (GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) != channel)<br>+        goto busy;<br>+<br>+    switch (sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) {<br>+    case GRXSTSRH_IN_DATA:<br>+<br>+        DPRINTF("DATA ST=%d STATUS=0x%08x\n",<br>+            (int)td->state, (int)sc->sc_last_rx_status);<br>+<br>+        if (sc->sc_chan_state[channel].hcint & HCINT_SOFTWARE_ONLY) {<br>+            /*<br>+             * When using SPLIT transactions on interrupt<br>+             * endpoints, sometimes data occurs twice.<br>+             */<br>+            DPRINTF("Data already received\n");<br>+            break;<br>+        }<br>+<br>+        /* get the packet byte count */<br>+        count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status);<br>+<br>+        /* check for isochronous transfer or high-speed bandwidth endpoint */<br>+        if (td->ep_type == UE_ISOCHRONOUS || td->max_packet_count > 1) {<br>+            if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) != GRXSTSRD_DPID_DATA0) {<br>+                td->tt_xactpos = HCSPLT_XACTPOS_MIDDLE;<br>+            } else {<br>+                td->tt_xactpos = HCSPLT_XACTPOS_BEGIN;<br>+<br>+                /* verify the packet byte count */<br>+                if (count < td->max_packet_size) {<br>+                    /* we have a short packet */<br>+                    td->short_pkt = 1;<br>+                    td->got_short = 1;<br>+                }<br>+            }<br>+            td->toggle = 0;<br>+        } else {<br>+            /* verify the packet byte count */<br>+            if (count != td->max_packet_size) {<br>+                if (count < td->max_packet_size) {<br>+                    /* we have a short packet */<br>+                    td->short_pkt = 1;<br>+                    td->got_short = 1;<br>+                } else {<br>+                    /* invalid USB packet */<br>+                    td->error_any = 1;<br>+              <br>+                    /* release FIFO */<br>+                    dwc_otg_common_rx_ack(sc);<br>+                    goto complete;<br>+                }<br>+            }<br>+            td->toggle ^= 1;<br>+            td->tt_scheduled = 0;<br>+        }<br>+<br>+        /* verify the packet byte count */<br>+        if (count > td->remainder) {<br>+            /* invalid USB packet */<br>+            td->error_any = 1;<br>+<br>+            /* release FIFO */<br>+            dwc_otg_common_rx_ack(sc);<br>+            goto complete;<br>+        }<br>+<br>+        usbd_copy_in(td->pc, td->offset,<br>+            sc->sc_rx_bounce_buffer, count);<br>+<br>+        td->remainder -= count;<br>+        td->offset += count;<br>+        sc->sc_chan_state[channel].hcint |= HCINT_SOFTWARE_ONLY;<br>+        break;<br>+    default:<br>+        break;<br>+    }<br>+    /* release FIFO */<br>+    dwc_otg_common_rx_ack(sc);<br>+busy:<br>+    return (0);<br>+complete:<br>+    return (1);<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_host_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint32_t hcint;<br>+    uint32_t hcchar;<br>+    uint8_t delta;<br>+    uint8_t channel;<br>+<br>+    channel = td->channel;<br>+<br>+    if (channel < DWC_OTG_MAX_CHANNELS) {<br>+        hcint = sc->sc_chan_state[channel].hcint;<br>+<br>+        DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n",<br>+            channel, td->state, hcint,<br>+            DWC_OTG_READ_4(sc, DOTG_HCCHAR(channel)),<br>+            DWC_OTG_READ_4(sc, DOTG_HCTSIZ(channel)));<br>+<br>+        /* check interrupt bits */<br>+        if (hcint & (HCINT_RETRY |<br>+            HCINT_ACK | HCINT_NYET)) {<br>+            /* give success bits priority over failure bits */<br>+        } else if (hcint & HCINT_STALL) {<br>+            DPRINTF("CH=%d STALL\n", channel);<br>+            td->error_stall = 1;<br>+            td->error_any = 1;<br>+            goto complete;<br>+        } else if (hcint & HCINT_ERRORS) {<br>+            DPRINTF("CH=%d ERROR\n", channel);<br>+            td->errcnt++;<br>+            if (td->hcsplt != 0 || td->errcnt >= 3) {<br>+                if (td->ep_type != UE_ISOCHRONOUS) {<br>+                    td->error_any = 1;<br>+                    goto complete;<br>+                }<br>+            }<br>+        }<br>+<br>+        /* check channels for data, if any */<br>+        if (dwc_otg_host_data_rx_sub(sc, td))<br>+            goto complete;<br>+<br>+        /* refresh interrupt status */<br>+        hcint = sc->sc_chan_state[channel].hcint;<br>+<br>+        if (hcint & (HCINT_ERRORS | HCINT_RETRY |<br>+            HCINT_ACK | HCINT_NYET)) {<br>+            if (!(hcint & HCINT_ERRORS))<br>+                td->errcnt = 0;<br>+        }<br>+    } else {<br>+        hcint = 0;<br>+    }<br>+<br>+    switch (td->state) {<br>+    case DWC_CHAN_ST_START:<br>+        if (td->hcsplt != 0)<br>+            goto receive_spkt;<br>+        else<br>+            goto receive_pkt;<br>+<br>+    case DWC_CHAN_ST_WAIT_ANE:<br>+        if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            if (td->ep_type == UE_INTERRUPT) {<br>+                /*<br>+                 * The USB specification does not<br>+                 * mandate a particular data toggle<br>+                 * value for USB INTERRUPT<br>+                 * transfers. Switch the data toggle<br>+                 * value to receive the packet<br>+                 * correctly:<br>+                 */<br>+                if (hcint & HCINT_DATATGLERR) {<br>+                    DPRINTF("Retrying packet due to "<br>+                        "data toggle error\n");<br>+                    td->toggle ^= 1;<br>+                    goto receive_pkt;<br>+                }<br>+            }<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            if (td->hcsplt != 0)<br>+                goto receive_spkt;<br>+            else<br>+                goto receive_pkt;<br>+        } else if (hcint & HCINT_NYET) {<br>+            if (td->hcsplt != 0) {<br>+                /* try again */<br>+                goto receive_pkt;<br>+            } else {<br>+                /* not a valid token for IN endpoints */<br>+                td->error_any = 1;<br>+                goto complete;<br>+            }<br>+        } else if (hcint & HCINT_ACK) {<br>+            /* wait for data - ACK arrived first */<br>+            if (!(hcint & HCINT_SOFTWARE_ONLY))<br>+                goto busy;<br>+<br>+            if (td->ep_type == UE_ISOCHRONOUS) {<br>+                /* check if we are complete */<br>+                if ((td->remainder == 0) ||<br>+                    (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN)) {<br>+                    goto complete;<br>+                }<br>+                /* get another packet */<br>+                goto receive_pkt;<br>+            } else {<br>+                /* check if we are complete */<br>+                if ((td->remainder == 0) || (td->got_short != 0)) {<br>+                    if (td->short_pkt)<br>+                        goto complete;<br>+<br>+                    /*<br>+                     * Else need to receive a zero length<br>+                     * packet.<br>+                     */<br>+                }<br>+                td->tt_scheduled = 0;<br>+                td->did_nak = 0;<br>+                if (td->hcsplt != 0)<br>+                    goto receive_spkt;<br>+                else<br>+                    goto receive_pkt;<br>+            }<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_S_ANE:<br>+        /*<br>+         * NOTE: The DWC OTG hardware provides a fake ACK in<br>+         * case of interrupt and isochronous transfers:<br>+         */ <br>+        if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            goto receive_spkt;<br>+        } else if (hcint & HCINT_NYET) {<br>+            td->tt_scheduled = 0;<br>+            goto receive_spkt;<br>+        } else if (hcint & HCINT_ACK) {<br>+            td->did_nak = 0;<br>+            goto receive_pkt;<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_C_PKT:<br>+        goto receive_pkt;<br>+<br>+    default:<br>+        break;<br>+    }<br>+    goto busy;<br>+<br>+receive_pkt:<br>+    /* free existing channel, if any */<br>+    dwc_otg_host_channel_free(sc, td);<br>+<br>+      if (td->hcsplt != 0) {<br>+        delta = td->tt_complete_slot - sc->sc_last_frame_num - 1;<br>+        if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) {<br>+            td->state = DWC_CHAN_ST_WAIT_C_PKT;<br>+            goto busy;<br>+        }<br>+        delta = sc->sc_last_frame_num - td->tt_start_slot;<br>+        if (delta > DWC_OTG_TT_SLOT_MAX) {<br>+            if (td->ep_type != UE_ISOCHRONOUS) {<br>+                /* we missed the service interval */<br>+                td->error_any = 1;<br>+            }<br>+            goto complete;<br>+        }<br>+        /* complete split */<br>+        td->hcsplt |= HCSPLT_COMPSPLT;<br>+    } else if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN &&<br>+        dwc_otg_host_rate_check(sc, td)) {<br>+        td->state = DWC_CHAN_ST_WAIT_C_PKT;<br>+        goto busy;<br>+    }<br>+<br>+    /* allocate a new channel */<br>+    if (dwc_otg_host_channel_alloc(sc, td, 0)) {<br>+        td->state = DWC_CHAN_ST_WAIT_C_PKT;<br>+        goto busy;<br>+    }<br>+<br>+    channel = td->channel;<br>+<br>+    /* set toggle, if any */<br>+    if (td->set_toggle) {<br>+        td->set_toggle = 0;<br>+        td->toggle = 1;<br>+    }<br>+<br>+    td->state = DWC_CHAN_ST_WAIT_ANE;<br>+<br>+    /* receive one packet */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+        (td->max_packet_size << HCTSIZ_XFERSIZE_SHIFT) |<br>+        (1 << HCTSIZ_PKTCNT_SHIFT) |<br>+        (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) :<br>+        (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)));<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt);<br>+<br>+    hcchar = td->hcchar;<br>+    hcchar |= HCCHAR_EPDIR_IN;<br>+<br>+    /* receive complete split ASAP */<br>+    if ((sc->sc_last_frame_num & 1) != 0)<br>+        hcchar |= HCCHAR_ODDFRM;<br>+    else<br>+        hcchar &= ~HCCHAR_ODDFRM;<br>+<br>+    /* must enable channel before data can be received */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar);<br>+<br>+    /* wait until next slot before trying complete split */<br>+    td->tt_complete_slot = sc->sc_last_frame_num + 1;<br>+<br>+    goto busy;<br>+<br>+receive_spkt:<br>+    /* free existing channel(s), if any */<br>+    dwc_otg_host_channel_free(sc, td);<br>+<br>+    delta = td->tt_start_slot - sc->sc_last_frame_num - 1;<br>+    if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) {<br>+        td->state = DWC_CHAN_ST_START;<br>+        goto busy;<br>+    }<br>+    delta = sc->sc_last_frame_num - td->tt_start_slot;<br>+    if (delta > 5) {<br>+        /* missed it */<br>+        td->tt_scheduled = 0;<br>+        td->state = DWC_CHAN_ST_START;<br>+        goto busy;<br>+    }<br>+<br>+    /* allocate a new channel */<br>+    if (dwc_otg_host_channel_alloc(sc, td, 0)) {<br>+        td->state = DWC_CHAN_ST_START;<br>+        goto busy;<br>+    }<br>+<br>+    channel = td->channel;<br>+<br>+    td->hcsplt &= ~HCSPLT_COMPSPLT;<br>+    td->state = DWC_CHAN_ST_WAIT_S_ANE;<br>+<br>+    /* receive one packet */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+        (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT));<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt);<br>+<br>+    /* send after next SOF event */<br>+    if ((sc->sc_last_frame_num & 1) == 0)<br>+        td->hcchar |= HCCHAR_ODDFRM;<br>+    else<br>+        td->hcchar &= ~HCCHAR_ODDFRM;<br>+<br>+    hcchar = td->hcchar;<br>+    hcchar |= HCCHAR_EPDIR_IN;<br>+<br>+    /* wait until next slot before trying complete split */<br>+    td->tt_complete_slot = sc->sc_last_frame_num + 1;<br>+<br>+    /* must enable channel before data can be received */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar);<br>+busy:<br>+    return (1);    /* busy */<br>+<br>+complete:<br>+    dwc_otg_host_channel_free(sc, td);<br>+    return (0);    /* complete */<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_data_rx(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint32_t temp;<br>+    uint16_t count;<br>+    uint8_t got_short;<br>+<br>+    got_short = 0;<br>+<br>+    /* check endpoint status */<br>+    if (sc->sc_last_rx_status == 0)<br>+        goto not_complete;<br>+<br>+    if (GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) != td->ep_no)<br>+        goto not_complete;<br>+<br>+    /* check for SETUP packet */<br>+    if ((sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) ==<br>+        GRXSTSRD_STP_DATA) {<br>+        if (td->remainder == 0) {<br>+            /*<br>+             * We are actually complete and have<br>+             * received the next SETUP<br>+             */<br>+            DPRINTFN(5, "faking complete\n");<br>+            return (0);    /* complete */<br>+        }<br>+        /*<br>+         * USB Host Aborted the transfer.<br>+         */<br>+        td->error_any = 1;<br>+        return (0);        /* complete */<br>+    }<br>+<br>+    if ((sc->sc_last_rx_status & GRXSTSRD_PKTSTS_MASK) !=<br>+        GRXSTSRD_OUT_DATA) {<br>+        /* release FIFO */<br>+        dwc_otg_common_rx_ack(sc);<br>+        goto not_complete;<br>+    }<br>+<br>+    /* get the packet byte count */<br>+    count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status);<br>+<br>+    /* verify the packet byte count */<br>+    if (count != td->max_packet_size) {<br>+        if (count < td->max_packet_size) {<br>+            /* we have a short packet */<br>+            td->short_pkt = 1;<br>+            got_short = 1;<br>+        } else {<br>+            /* invalid USB packet */<br>+            td->error_any = 1;<br>+<br>+            /* release FIFO */<br>+            dwc_otg_common_rx_ack(sc);<br>+            return (0);    /* we are complete */<br>+        }<br>+    }<br>+    /* verify the packet byte count */<br>+    if (count > td->remainder) {<br>+        /* invalid USB packet */<br>+        td->error_any = 1;<br>+<br>+        /* release FIFO */<br>+        dwc_otg_common_rx_ack(sc);<br>+        return (0);        /* we are complete */<br>+    }<br>+<br>+    usbd_copy_in(td->pc, td->offset, sc->sc_rx_bounce_buffer, count);<br>+    td->remainder -= count;<br>+    td->offset += count;<br>+<br>+    /* release FIFO */<br>+    dwc_otg_common_rx_ack(sc);<br>+<br>+    temp = sc->sc_out_ctl[td->ep_no];<br>+<br>+    /* check for isochronous mode */<br>+    if ((temp & DIEPCTL_EPTYPE_MASK) ==<br>+        (DIEPCTL_EPTYPE_ISOC << DIEPCTL_EPTYPE_SHIFT)) {<br>+        /* toggle odd or even frame bit */<br>+        if (temp & DIEPCTL_SETD1PID) {<br>+            temp &= ~DIEPCTL_SETD1PID;<br>+            temp |= DIEPCTL_SETD0PID;<br>+        } else {<br>+            temp &= ~DIEPCTL_SETD0PID;<br>+            temp |= DIEPCTL_SETD1PID;<br>+        }<br>+        sc->sc_out_ctl[td->ep_no] = temp;<br>+    }<br>+<br>+    /* check if we are complete */<br>+    if ((td->remainder == 0) || got_short) {<br>+        if (td->short_pkt) {<br>+            /* we are complete */<br>+            return (0);<br>+        }<br>+        /* else need to receive a zero length packet */<br>+    }<br>+<br>+not_complete:<br>+<br>+    temp = sc->sc_out_ctl[td->ep_no];<br>+<br>+    temp |= DOEPCTL_EPENA | DOEPCTL_CNAK;<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(td->ep_no), temp);<br>+<br>+    /* enable SETUP and transfer complete interrupt */<br>+    if (td->ep_no == 0) {<br>+        DWC_OTG_WRITE_4(sc, DOTG_DOEPTSIZ(0),<br>+            DXEPTSIZ_SET_NPKT(1) | <br>+            DXEPTSIZ_SET_NBYTES(td->max_packet_size));<br>+    } else {<br>+        /* allow reception of multiple packets */<br>+        DWC_OTG_WRITE_4(sc, DOTG_DOEPTSIZ(td->ep_no),<br>+            DXEPTSIZ_SET_MULTI(1) |<br>+            DXEPTSIZ_SET_NPKT(4) | <br>+            DXEPTSIZ_SET_NBYTES(4 *<br>+            ((td->max_packet_size + 3) & ~3)));<br>+    }<br>+    return (1);            /* not complete */<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_host_data_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint32_t count;<br>+    uint32_t hcint;<br>+    uint32_t hcchar;<br>+    uint8_t delta;<br>+    uint8_t channel;<br>+<br>+    dwc_otg_host_dump_rx(sc, td);<br>+<br>+    channel = td->channel;<br>+<br>+    if (channel < DWC_OTG_MAX_CHANNELS) {<br>+        hcint = sc->sc_chan_state[channel].hcint;<br>+<br>+        DPRINTF("CH=%d ST=%d HCINT=0x%08x HCCHAR=0x%08x HCTSIZ=0x%08x\n",<br>+            channel, td->state, hcint,<br>+            DWC_OTG_READ_4(sc, DOTG_HCCHAR(channel)),<br>+            DWC_OTG_READ_4(sc, DOTG_HCTSIZ(channel)));<br>+<br>+        if (hcint & (HCINT_RETRY |<br>+            HCINT_ACK | HCINT_NYET)) {<br>+            /* give success bits priority over failure bits */<br>+        } else if (hcint & HCINT_STALL) {<br>+            DPRINTF("CH=%d STALL\n", channel);<br>+            td->error_stall = 1;<br>+            td->error_any = 1;<br>+            goto complete;<br>+        } else if (hcint & HCINT_ERRORS) {<br>+            DPRINTF("CH=%d ERROR\n", channel);<br>+            td->errcnt++;<br>+            if (td->hcsplt != 0 || td->errcnt >= 3) {<br>+                td->error_any = 1;<br>+                goto complete;<br>+            }<br>+        }<br>+<br>+        if (hcint & (HCINT_ERRORS | HCINT_RETRY |<br>+            HCINT_ACK | HCINT_NYET)) {<br>+<br>+            if (!(hcint & HCINT_ERRORS))<br>+                td->errcnt = 0;<br>+        }<br>+    } else {<br>+        hcint = 0;<br>+    }<br>+<br>+    switch (td->state) {<br>+    case DWC_CHAN_ST_START:<br>+        goto send_pkt;<br>+<br>+    case DWC_CHAN_ST_WAIT_ANE:<br>+        if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            goto send_pkt;<br>+        } else if (hcint & (HCINT_ACK | HCINT_NYET)) {<br>+            td->offset += td->tx_bytes;<br>+            td->remainder -= td->tx_bytes;<br>+            td->toggle ^= 1;<br>+            td->did_nak = 0;<br>+            td->tt_scheduled = 0;<br>+<br>+            /* check remainder */<br>+            if (td->remainder == 0) {<br>+                if (td->short_pkt)<br>+                    goto complete;<br>+<br>+                /*<br>+                 * Else we need to transmit a short<br>+                 * packet:<br>+                 */<br>+            }<br>+            goto send_pkt;<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_S_ANE:<br>+        if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            goto send_pkt;<br>+        } else if (hcint & (HCINT_ACK | HCINT_NYET)) {<br>+            td->did_nak = 0;<br>+            goto send_cpkt;<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_C_ANE:<br>+        if (hcint & HCINT_NYET) {<br>+            goto send_cpkt;<br>+        } else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {<br>+            td->did_nak++;<br>+            td->tt_scheduled = 0;<br>+            goto send_pkt;<br>+        } else if (hcint & HCINT_ACK) {<br>+            td->offset += td->tx_bytes;<br>+            td->remainder -= td->tx_bytes;<br>+            td->toggle ^= 1;<br>+            td->did_nak = 0;<br>+            td->tt_scheduled = 0;<br>+<br>+            /* check remainder */<br>+            if (td->remainder == 0) {<br>+                if (td->short_pkt)<br>+                    goto complete;<br>+<br>+                /* else we need to transmit a short packet */<br>+            }<br>+            goto send_pkt;<br>+        }<br>+        break;<br>+<br>+    case DWC_CHAN_ST_WAIT_C_PKT:<br>+        goto send_cpkt;<br>+<br>+    case DWC_CHAN_ST_TX_WAIT_ISOC:<br>+<br>+        /* Check if isochronous OUT traffic is complete */<br>+        if ((hcint & HCINT_HCH_DONE_MASK) == 0)<br>+            break;<br>+<br>+        td->offset += td->tx_bytes;<br>+        td->remainder -= td->tx_bytes;<br>+<br>+        if (td->hcsplt != 0 || td->remainder == 0)<br>+            goto complete;<br>+<br>+        /* check for next packet */<br>+        if (td->max_packet_count > 1)<br>+            td->tt_xactpos++;<br>+<br>+        /* free existing channel, if any */<br>+        dwc_otg_host_channel_free(sc, td);<br>+<br>+        td->state = DWC_CHAN_ST_TX_PKT_ISOC;<br>+<br>+        /* FALLTHROUGH */<br>+<br>+    case DWC_CHAN_ST_TX_PKT_ISOC:<br>+        if (dwc_otg_host_channel_alloc(sc, td, 1))<br>+            break;<br>+        channel = td->channel;<br>+        goto send_isoc_pkt;<br>+    default:<br>+        break;<br>+    }<br>+    goto busy;<br>+<br>+send_pkt:<br>+    /* free existing channel(s), if any */<br>+    dwc_otg_host_channel_free(sc, td);<br>+<br>+    if (td->hcsplt != 0) {<br>+        delta = td->tt_start_slot - sc->sc_last_frame_num - 1;<br>+        if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) {<br>+            td->state = DWC_CHAN_ST_START;<br>+            goto busy;<br>+        }<br>+        delta = sc->sc_last_frame_num - td->tt_start_slot;<br>+        if (delta > 5) {<br>+            /* missed it */<br>+            td->tt_scheduled = 0;<br>+            td->state = DWC_CHAN_ST_START;<br>+            goto busy;<br>+        }<br>+    } else if (dwc_otg_host_rate_check(sc, td)) {<br>+        td->state = DWC_CHAN_ST_START;<br>+        goto busy;<br>+    }<br>+<br>+    /* allocate a new channel */<br>+    if (dwc_otg_host_channel_alloc(sc, td, 1)) {<br>+        td->state = DWC_CHAN_ST_START;<br>+        goto busy;<br>+    }<br>+<br>+    channel = td->channel;<br>+<br>+    /* set toggle, if any */<br>+    if (td->set_toggle) {<br>+        td->set_toggle = 0;<br>+        td->toggle = 1;<br>+    }<br>+<br>+    if (td->ep_type == UE_ISOCHRONOUS) {<br>+send_isoc_pkt:<br>+        /* Isochronous OUT transfers don't have any ACKs */<br>+        td->state = DWC_CHAN_ST_TX_WAIT_ISOC;<br>+        td->hcsplt &= ~HCSPLT_COMPSPLT;<br>+        if (td->hcsplt != 0) {<br>+            /* get maximum transfer length */<br>+            count = td->remainder;<br>+            if (count > HCSPLT_XACTLEN_BURST) {<br>+                DPRINTF("TT overflow\n");<br>+                td->error_any = 1;<br>+                goto complete;<br>+            }<br>+            /* Update transaction position */<br>+            td->hcsplt &= ~HCSPLT_XACTPOS_MASK;<br>+            td->hcsplt |= (HCSPLT_XACTPOS_ALL << HCSPLT_XACTPOS_SHIFT);<br>+        } else {<br>+            /* send one packet at a time */<br>+            count = td->max_packet_size;<br>+            if (td->remainder < count) {<br>+                /* we have a short packet */<br>+                td->short_pkt = 1;<br>+                count = td->remainder;<br>+            }<br>+        }<br>+    } else if (td->hcsplt != 0) {<br>+<br>+        td->hcsplt &= ~HCSPLT_COMPSPLT;<br>+<br>+        /* Wait for ACK/NAK/ERR from TT */<br>+        td->state = DWC_CHAN_ST_WAIT_S_ANE;<br>+<br>+        /* send one packet at a time */<br>+        count = td->max_packet_size;<br>+        if (td->remainder < count) {<br>+            /* we have a short packet */<br>+            td->short_pkt = 1;<br>+            count = td->remainder;<br>+        }<br>+    } else {<br>+        /* Wait for ACK/NAK/STALL from device */<br>+        td->state = DWC_CHAN_ST_WAIT_ANE;<br>+<br>+        /* send one packet at a time */<br>+        count = td->max_packet_size;<br>+        if (td->remainder < count) {<br>+            /* we have a short packet */<br>+            td->short_pkt = 1;<br>+            count = td->remainder;<br>+        }<br>+    }<br>+<br>+    /* check for High-Speed multi-packets */<br>+    if ((td->hcsplt == 0) && (td->max_packet_count > 1)) {<br>+        if (td->npkt == 0) {<br>+            if (td->remainder >= (3 * td->max_packet_size))<br>+                td->npkt = 3;<br>+            else if (td->remainder >= (2 * td->max_packet_size))<br>+                td->npkt = 2;<br>+            else<br>+                td->npkt = 1;<br>+<br>+            if (td->npkt > td->max_packet_count)<br>+                td->npkt = td->max_packet_count;<br>+<br>+            td->tt_xactpos = 1;    /* overload */<br>+        }<br>+        if (td->tt_xactpos == td->npkt) {<br>+            if (td->npkt == 1) {<br>+                DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+                    (count << HCTSIZ_XFERSIZE_SHIFT) |<br>+                    (1 << HCTSIZ_PKTCNT_SHIFT) |<br>+                    (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT));<br>+            } else if (td->npkt == 2) {<br>+                DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+                    (count << HCTSIZ_XFERSIZE_SHIFT) |<br>+                    (1 << HCTSIZ_PKTCNT_SHIFT) |<br>+                    (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT));<br>+            } else {<br>+                DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+                    (count << HCTSIZ_XFERSIZE_SHIFT) |<br>+                    (1 << HCTSIZ_PKTCNT_SHIFT) |<br>+                    (HCTSIZ_PID_DATA2 << HCTSIZ_PID_SHIFT));<br>+            }<br>+            td->npkt = 0;<br>+        } else {<br>+            DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+                (count << HCTSIZ_XFERSIZE_SHIFT) |<br>+                (1 << HCTSIZ_PKTCNT_SHIFT) |<br>+                (HCTSIZ_PID_MDATA << HCTSIZ_PID_SHIFT));<br>+        }<br>+    } else {<br>+        /* TODO: HCTSIZ_DOPNG */<br>+<br>+        DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+            (count << HCTSIZ_XFERSIZE_SHIFT) |<br>+            (1 << HCTSIZ_PKTCNT_SHIFT) |<br>+            (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) :<br>+            (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)));<br>+    }<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt);<br>+<br>+    hcchar = td->hcchar;<br>+    hcchar &= ~HCCHAR_EPDIR_IN;<br>+<br>+    /* send after next SOF event */<br>+    if ((sc->sc_last_frame_num & 1) == 0)<br>+        hcchar |= HCCHAR_ODDFRM;<br>+    else<br>+        hcchar &= ~HCCHAR_ODDFRM;<br>+<br>+    /* must enable before writing data to FIFO */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar);<br>+<br>+    if (count != 0) {<br>+<br>+        /* clear topmost word before copy */<br>+        sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0;<br>+<br>+        /* copy out data */<br>+        usbd_copy_out(td->pc, td->offset,<br>+            sc->sc_tx_bounce_buffer, count);<br>+<br>+        /* transfer data into FIFO */<br>+        bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,<br>+            DOTG_DFIFO(channel),<br>+            sc->sc_tx_bounce_buffer, (count + 3) / 4);<br>+    }<br>+<br>+    /* store number of bytes transmitted */<br>+    td->tx_bytes = count;<br>+    goto busy;<br>+<br>+send_cpkt:<br>+    /* free existing channel, if any */<br>+    dwc_otg_host_channel_free(sc, td);<br>+<br>+    delta = td->tt_complete_slot - sc->sc_last_frame_num - 1;<br>+    if (td->tt_scheduled == 0 || delta < DWC_OTG_TT_SLOT_MAX) {<br>+        td->state = DWC_CHAN_ST_WAIT_C_PKT;<br>+        goto busy;<br>+    }<br>+    delta = sc->sc_last_frame_num - td->tt_start_slot;<br>+    if (delta > DWC_OTG_TT_SLOT_MAX) {<br>+        /* we missed the service interval */<br>+        if (td->ep_type != UE_ISOCHRONOUS)<br>+            td->error_any = 1;<br>+        goto complete;<br>+    }<br>+<br>+    /* allocate a new channel */<br>+    if (dwc_otg_host_channel_alloc(sc, td, 0)) {<br>+        td->state = DWC_CHAN_ST_WAIT_C_PKT;<br>+        goto busy;<br>+    }<br>+<br>+    channel = td->channel;<br>+<br>+     td->hcsplt |= HCSPLT_COMPSPLT;<br>+    td->state = DWC_CHAN_ST_WAIT_C_ANE;<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(channel),<br>+        (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT));<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(channel), td->hcsplt);<br>+<br>+    hcchar = td->hcchar;<br>+    hcchar &= ~HCCHAR_EPDIR_IN;<br>+<br>+    /* receive complete split ASAP */<br>+    if ((sc->sc_last_frame_num & 1) != 0)<br>+        hcchar |= HCCHAR_ODDFRM;<br>+    else<br>+        hcchar &= ~HCCHAR_ODDFRM;<br>+<br>+    /* must enable channel before data can be received */<br>+    DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar);<br>+<br>+    /* wait until next slot before trying complete split */<br>+    td->tt_complete_slot = sc->sc_last_frame_num + 1;<br>+busy:<br>+    return (1);    /* busy */<br>+<br>+complete:<br>+    dwc_otg_host_channel_free(sc, td);<br>+    return (0);    /* complete */<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_data_tx(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint32_t max_buffer;<br>+    uint32_t count;<br>+    uint32_t fifo_left;<br>+    uint32_t mpkt;<br>+    uint32_t temp;<br>+    uint8_t to;<br>+<br>+    to = 3;                /* don't loop forever! */<br>+<br>+    max_buffer = sc->sc_hw_ep_profile[td->ep_no].max_buffer;<br>+<br>+repeat:<br>+    /* check for for endpoint 0 data */<br>+<br>+    temp = sc->sc_last_rx_status;<br>+<br>+    if ((td->ep_no == 0) && (temp != 0) &&<br>+        (GRXSTSRD_CHNUM_GET(temp) == 0)) {<br>+<br>+        if ((temp & GRXSTSRD_PKTSTS_MASK) !=<br>+            GRXSTSRD_STP_DATA) {<br>+<br>+            /* dump data - wrong direction */<br>+            dwc_otg_common_rx_ack(sc);<br>+        } else {<br>+            /*<br>+             * The current transfer was cancelled<br>+             * by the USB Host:<br>+             */<br>+            td->error_any = 1;<br>+            return (0);        /* complete */<br>+        }<br>+    }<br>+<br>+    /* fill in more TX data, if possible */<br>+    if (td->tx_bytes != 0) {<br>+<br>+        uint16_t cpkt;<br>+<br>+        /* check if packets have been transferred */<br>+        temp = DWC_OTG_READ_4(sc, DOTG_DIEPTSIZ(td->ep_no));<br>+<br>+        /* get current packet number */<br>+        cpkt = DXEPTSIZ_GET_NPKT(temp);<br>+<br>+        if (cpkt >= td->npkt) {<br>+            fifo_left = 0;<br>+        } else {<br>+            if (max_buffer != 0) {<br>+                fifo_left = (td->npkt - cpkt) *<br>+                    td->max_packet_size;<br>+<br>+                if (fifo_left > max_buffer)<br>+                    fifo_left = max_buffer;<br>+            } else {<br>+                fifo_left = td->max_packet_size;<br>+            }<br>+        }<br>+<br>+        count = td->tx_bytes;<br>+        if (count > fifo_left)<br>+            count = fifo_left;<br>+<br>+        if (count != 0) {<br>+<br>+            /* clear topmost word before copy */<br>+            sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0;<br>+<br>+            /* copy out data */<br>+            usbd_copy_out(td->pc, td->offset,<br>+                sc->sc_tx_bounce_buffer, count);<br>+<br>+            /* transfer data into FIFO */<br>+            bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,<br>+                DOTG_DFIFO(td->ep_no),<br>+                sc->sc_tx_bounce_buffer, (count + 3) / 4);<br>+<br>+            td->tx_bytes -= count;<br>+            td->remainder -= count;<br>+            td->offset += count;<br>+            td->npkt = cpkt;<br>+        }<br>+        if (td->tx_bytes != 0)<br>+            goto not_complete;<br>+<br>+        /* check remainder */<br>+        if (td->remainder == 0) {<br>+            if (td->short_pkt)<br>+                return (0);    /* complete */<br>+<br>+            /* else we need to transmit a short packet */<br>+        }<br>+    }<br>+<br>+    if (!to--)<br>+        goto not_complete;<br>+<br>+    /* check if not all packets have been transferred */<br>+    temp = DWC_OTG_READ_4(sc, DOTG_DIEPTSIZ(td->ep_no));<br>+<br>+    if (DXEPTSIZ_GET_NPKT(temp) != 0) {<br>+<br>+        DPRINTFN(5, "busy ep=%d npkt=%d DIEPTSIZ=0x%08x "<br>+            "DIEPCTL=0x%08x\n", td->ep_no,<br>+            DXEPTSIZ_GET_NPKT(temp),<br>+            temp, DWC_OTG_READ_4(sc, DOTG_DIEPCTL(td->ep_no)));<br>+<br>+        goto not_complete;<br>+    }<br>+<br>+    DPRINTFN(5, "rem=%u ep=%d\n", td->remainder, td->ep_no);<br>+<br>+    /* try to optimise by sending more data */<br>+    if ((max_buffer != 0) && ((td->max_packet_size & 3) == 0)) {<br>+<br>+        /* send multiple packets at the same time */<br>+        mpkt = max_buffer / td->max_packet_size;<br>+<br>+        if (mpkt > 0x3FE)<br>+            mpkt = 0x3FE;<br>+<br>+        count = td->remainder;<br>+        if (count > 0x7FFFFF)<br>+            count = 0x7FFFFF - (0x7FFFFF % td->max_packet_size);<br>+<br>+        td->npkt = count / td->max_packet_size;<br>+<br>+        /*<br>+         * NOTE: We could use 0x3FE instead of "mpkt" in the<br>+         * check below to get more throughput, but then we<br>+         * have a dependency towards non-generic chip features<br>+         * to disable the TX-FIFO-EMPTY interrupts on a per<br>+         * endpoint basis. Increase the maximum buffer size of<br>+         * the IN endpoint to increase the performance.<br>+         */<br>+        if (td->npkt > mpkt) {<br>+            td->npkt = mpkt;<br>+            count = td->max_packet_size * mpkt;<br>+        } else if ((count == 0) || (count % td->max_packet_size)) {<br>+            /* we are transmitting a short packet */<br>+            td->npkt++;<br>+            td->short_pkt = 1;<br>+        }<br>+    } else {<br>+        /* send one packet at a time */<br>+        mpkt = 1;<br>+        count = td->max_packet_size;<br>+        if (td->remainder < count) {<br>+            /* we have a short packet */<br>+            td->short_pkt = 1;<br>+            count = td->remainder;<br>+        }<br>+        td->npkt = 1;<br>+    }<br>+    DWC_OTG_WRITE_4(sc, DOTG_DIEPTSIZ(td->ep_no),<br>+        DXEPTSIZ_SET_MULTI(1) |<br>+        DXEPTSIZ_SET_NPKT(td->npkt) | <br>+        DXEPTSIZ_SET_NBYTES(count));<br>+<br>+    /* make room for buffering */<br>+    td->npkt += mpkt;<br>+<br>+    temp = sc->sc_in_ctl[td->ep_no];<br>+<br>+    /* check for isochronous mode */<br>+    if ((temp & DIEPCTL_EPTYPE_MASK) ==<br>+        (DIEPCTL_EPTYPE_ISOC << DIEPCTL_EPTYPE_SHIFT)) {<br>+        /* toggle odd or even frame bit */<br>+        if (temp & DIEPCTL_SETD1PID) {<br>+            temp &= ~DIEPCTL_SETD1PID;<br>+            temp |= DIEPCTL_SETD0PID;<br>+        } else {<br>+            temp &= ~DIEPCTL_SETD0PID;<br>+            temp |= DIEPCTL_SETD1PID;<br>+        }<br>+        sc->sc_in_ctl[td->ep_no] = temp;<br>+    }<br>+<br>+    /* must enable before writing data to FIFO */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(td->ep_no), temp |<br>+        DIEPCTL_EPENA | DIEPCTL_CNAK);<br>+<br>+    td->tx_bytes = count;<br>+<br>+    /* check remainder */<br>+    if (td->tx_bytes == 0 &&<br>+        td->remainder == 0) {<br>+        if (td->short_pkt)<br>+            return (0);    /* complete */<br>+<br>+        /* else we need to transmit a short packet */<br>+    }<br>+    goto repeat;<br>+<br>+not_complete:<br>+    return (1);            /* not complete */<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_data_tx_sync(struct dwc_otg_softc *sc, struct dwc_otg_td *td)<br>+{<br>+    uint32_t temp;<br>+<br>+    /*<br>+     * If all packets are transferred we are complete:<br>+     */<br>+    temp = DWC_OTG_READ_4(sc, DOTG_DIEPTSIZ(td->ep_no));<br>+<br>+    /* check that all packets have been transferred */<br>+    if (DXEPTSIZ_GET_NPKT(temp) != 0) {<br>+        DPRINTFN(5, "busy ep=%d\n", td->ep_no);<br>+        goto not_complete;<br>+    }<br>+    return (0);<br>+<br>+not_complete:<br>+<br>+    /* we only want to know if there is a SETUP packet or free IN packet */<br>+<br>+    temp = sc->sc_last_rx_status;<br>+<br>+    if ((td->ep_no == 0) && (temp != 0) &&<br>+        (GRXSTSRD_CHNUM_GET(temp) == 0)) {<br>+<br>+        if ((temp & GRXSTSRD_PKTSTS_MASK) ==<br>+            GRXSTSRD_STP_DATA) {<br>+            DPRINTFN(5, "faking complete\n");<br>+            /*<br>+             * Race condition: We are complete!<br>+             */<br>+            return (0);<br>+        } else {<br>+            /* dump data - wrong direction */<br>+            dwc_otg_common_rx_ack(sc);<br>+        }<br>+    }<br>+    return (1);            /* not complete */<br>+}<br>+<br>+static void<br>+dwc_otg_xfer_do_fifo(struct dwc_otg_softc *sc, struct usb_xfer *xfer)<br>+{<br>+    struct dwc_otg_td *td;<br>+    uint8_t toggle;<br>+    uint8_t tmr_val;<br>+    uint8_t tmr_res;<br>+<br>+    DPRINTFN(9, "\n");<br>+<br>+    td = xfer->td_transfer_cache;<br>+    if (td == NULL)<br>+        return;<br>+<br>+    while (1) {<br>+        if ((td->func) (sc, td)) {<br>+            /* operation in progress */<br>+            break;<br>+        }<br>+        if (((void *)td) == xfer->td_transfer_last) {<br>+            goto done;<br>+        }<br>+        if (td->error_any) {<br>+            goto done;<br>+        } else if (td->remainder > 0) {<br>+            /*<br>+             * We had a short transfer. If there is no alternate<br>+             * next, stop processing !<br>+             */<br>+            if (!td->alt_next)<br>+                goto done;<br>+        }<br>+<br>+        /*<br>+         * Fetch the next transfer descriptor and transfer<br>+         * some flags to the next transfer descriptor<br>+         */<br>+        tmr_res = td->tmr_res;<br>+        tmr_val = td->tmr_val;<br>+        toggle = td->toggle;<br>+        td = td->obj_next;<br>+        xfer->td_transfer_cache = td;<br>+        td->toggle = toggle;    /* transfer toggle */<br>+        td->tmr_res = tmr_res;<br>+        td->tmr_val = tmr_val;<br>+    }<br>+    return;<br>+<br>+done:<br>+    xfer->td_transfer_cache = NULL;<br>+    sc->sc_xfer_complete = 1;<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_xfer_do_complete_locked(struct dwc_otg_softc *sc, struct usb_xfer *xfer)<br>+{<br>+    struct dwc_otg_td *td;<br>+<br>+    DPRINTFN(9, "\n");<br>+<br>+    td = xfer->td_transfer_cache;<br>+    if (td == NULL) {<br>+        /* compute all actual lengths */<br>+        dwc_otg_standard_done(xfer);<br>+        return (1);<br>+    }<br>+    return (0);<br>+}<br>+<br>+static void<br>+dwc_otg_timer(void *_sc)<br>+{<br>+    struct dwc_otg_softc *sc = _sc;<br>+    struct usb_xfer *xfer;<br>+    struct dwc_otg_td *td;<br>+<br>+    USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);<br>+<br>+    DPRINTF("\n");<br>+<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+<br>+    /* increment timer value */<br>+    sc->sc_tmr_val++;<br>+<br>+    TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {<br>+        td = xfer->td_transfer_cache;<br>+        if (td != NULL) {<br>+            /* reset NAK counter */ <br>+            td->did_nak = 0;<br>+        }<br>+    }<br>+<br>+    /* enable SOF interrupt, which will poll jobs */<br>+    dwc_otg_enable_sof_irq(sc);<br>+<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+<br>+    if (sc->sc_timer_active) {<br>+        /* restart timer */<br>+        usb_callout_reset(&sc->sc_timer,<br>+            hz / (1000 / DWC_OTG_HOST_TIMER_RATE),<br>+            &dwc_otg_timer, sc);<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_timer_start(struct dwc_otg_softc *sc)<br>+{<br>+    if (sc->sc_timer_active != 0)<br>+        return;<br>+<br>+    sc->sc_timer_active = 1;<br>+<br>+    /* restart timer */<br>+    usb_callout_reset(&sc->sc_timer,<br>+        hz / (1000 / DWC_OTG_HOST_TIMER_RATE),<br>+        &dwc_otg_timer, sc);<br>+}<br>+<br>+static void<br>+dwc_otg_timer_stop(struct dwc_otg_softc *sc)<br>+{<br>+    if (sc->sc_timer_active == 0)<br>+        return;<br>+<br>+    sc->sc_timer_active = 0;<br>+<br>+    /* stop timer */<br>+    usb_callout_stop(&sc->sc_timer);<br>+}<br>+<br>+static void<br>+dwc_otg_host_channel_disable(struct dwc_otg_softc *sc, uint8_t x)<br>+{<br>+    uint32_t hcchar;<br>+<br>+    hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x));<br>+<br>+    /* disable host channel, if any */<br>+    if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) {<br>+        /* disable channel */<br>+        DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x),<br>+            HCCHAR_CHENA | HCCHAR_CHDIS);<br>+        /* wait for chip to get its brains in order */<br>+        sc->sc_chan_state[x].wait_sof = 2;<br>+    }<br>+<br>+    /* release TX FIFO usage, if any */<br>+    sc->sc_tx_cur_p_level -= sc->sc_chan_state[x].tx_p_size;<br>+    sc->sc_tx_cur_np_level -= sc->sc_chan_state[x].tx_np_size;<br>+<br>+    /* don't release TX FIFO usage twice */<br>+    sc->sc_chan_state[x].tx_p_size = 0;<br>+    sc->sc_chan_state[x].tx_np_size = 0;<br>+}<br>+<br>+static uint16_t<br>+dwc_otg_compute_isoc_rx_tt_slot(struct dwc_otg_tt_info *pinfo)<br>+{<br>+    if (pinfo->slot_index < DWC_OTG_TT_SLOT_MAX)<br>+        pinfo->slot_index++;<br>+    return (pinfo->slot_index);<br>+}<br>+<br>+static uint8_t<br>+dwc_otg_update_host_transfer_schedule_locked(struct dwc_otg_softc *sc)<br>+{<br>+    TAILQ_HEAD(, usb_xfer) head;<br>+    struct usb_xfer *xfer;<br>+    struct usb_xfer *xfer_next;<br>+    struct dwc_otg_td *td;<br>+    uint16_t temp;<br>+    uint16_t slot;<br>+    uint8_t x;<br>+<br>+    temp = DWC_OTG_READ_4(sc, DOTG_HFNUM) & DWC_OTG_FRAME_MASK;<br>+<br>+    if (sc->sc_last_frame_num == temp)<br>+        return (0);<br>+<br>+    sc->sc_last_frame_num = temp;<br>+<br>+    TAILQ_INIT(&head);<br>+<br>+    for (x = 0; x != sc->sc_host_ch_max; x++) {<br>+        if (sc->sc_chan_state[x].wait_sof == 0)<br>+            continue;<br>+<br>+        sc->sc_needsof = 1;<br>+        if (--(sc->sc_chan_state[x].wait_sof) == 0)<br>+            dwc_otg_host_channel_disable(sc, x);<br>+    }<br>+<br>+    if ((temp & 7) == 0) {<br>+<br>+        /* reset the schedule */<br>+        memset(sc->sc_tt_info, 0, sizeof(sc->sc_tt_info));<br>+<br>+        TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {<br>+            td = xfer->td_transfer_cache;<br>+            if (td == NULL || td->ep_type != UE_ISOCHRONOUS)<br>+                continue;<br>+<br>+            /* check for IN direction */<br>+            if ((td->hcchar & HCCHAR_EPDIR_IN) != 0)<br>+                continue;<br>+<br>+            /* execute more frames */<br>+            td->tmr_val = 0;<br>+<br>+            sc->sc_needsof = 1;<br>+<br>+            if (td->hcsplt == 0 || td->tt_scheduled != 0)<br>+                continue;<br>+<br>+            /* compute slot */<br>+            slot = dwc_otg_compute_isoc_rx_tt_slot(<br>+                sc->sc_tt_info + td->tt_index);<br>+            if (slot > 3) {<br>+                /* <br>+                 * Not enough time to get complete<br>+                 * split executed.<br>+                 */<br>+                continue;<br>+            }<br>+            /* Delayed start */<br>+            td->tt_start_slot = temp + slot;<br>+            td->tt_scheduled = 1;<br>+            TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry);<br>+            TAILQ_INSERT_TAIL(&head, xfer, wait_entry);<br>+        }<br>+<br>+        TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {<br>+            td = xfer->td_transfer_cache;<br>+            if (td == NULL || td->ep_type != UE_ISOCHRONOUS)<br>+                continue;<br>+<br>+            /* check for OUT direction */<br>+            if ((td->hcchar & HCCHAR_EPDIR_IN) == 0)<br>+                continue;<br>+<br>+            /* execute more frames */<br>+            td->tmr_val = 0;<br>+<br>+            sc->sc_needsof = 1;<br>+<br>+            if (td->hcsplt == 0 || td->tt_scheduled != 0)<br>+                continue;<br>+<br>+            /* Start ASAP */<br>+            td->tt_start_slot = temp;<br>+            td->tt_scheduled = 1;<br>+            TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry);<br>+            TAILQ_INSERT_TAIL(&head, xfer, wait_entry);<br>+        }<br>+<br>+        TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {<br>+            td = xfer->td_transfer_cache;<br>+            if (td == NULL || td->ep_type != UE_INTERRUPT)<br>+                continue;<br>+<br>+            if (td->tt_scheduled != 0) {<br>+                sc->sc_needsof = 1;<br>+                continue;<br>+            }<br>+<br>+            if (dwc_otg_host_rate_check_interrupt(sc, td))<br>+                continue;<br>+<br>+            if (td->hcsplt == 0) {<br>+                sc->sc_needsof = 1;<br>+                td->tt_scheduled = 1;<br>+                continue;<br>+            }<br>+<br>+            /* start ASAP */<br>+            td->tt_start_slot = temp;<br>+            sc->sc_needsof = 1;<br>+            td->tt_scheduled = 1;<br>+            TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry);<br>+            TAILQ_INSERT_TAIL(&head, xfer, wait_entry);<br>+        }<br>+<br>+        TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {<br>+            td = xfer->td_transfer_cache;<br>+            if (td == NULL ||<br>+                td->ep_type != UE_CONTROL ||<br>+                td->did_nak >= DWC_OTG_NAK_MAX) {<br>+                continue;<br>+            }<br>+<br>+            sc->sc_needsof = 1;<br>+<br>+            if (td->hcsplt == 0 || td->tt_scheduled != 0)<br>+                continue;<br>+<br>+            /* start ASAP */<br>+            td->tt_start_slot = temp;<br>+            td->tt_scheduled = 1;<br>+            TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry);<br>+            TAILQ_INSERT_TAIL(&head, xfer, wait_entry);<br>+        }<br>+    }<br>+    if ((temp & 7) < 6) {<br>+        TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {<br>+            td = xfer->td_transfer_cache;<br>+            if (td == NULL ||<br>+                td->ep_type != UE_BULK ||<br>+                td->did_nak >= DWC_OTG_NAK_MAX) {<br>+                continue;<br>+            }<br>+<br>+            sc->sc_needsof = 1;<br>+<br>+            if (td->hcsplt == 0 || td->tt_scheduled != 0)<br>+                continue;<br>+<br>+            /* start ASAP */<br>+            td->tt_start_slot = temp;<br>+            td->tt_scheduled = 1;<br>+            TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry);<br>+            TAILQ_INSERT_TAIL(&head, xfer, wait_entry);<br>+        }<br>+    }<br>+<br>+    /* Put TT transfers in execution order at the end */<br>+    TAILQ_CONCAT(&sc->sc_bus.intr_q.head, &head, wait_entry);<br>+<br>+    /* move all TT transfers in front, keeping the current order */<br>+    TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {<br>+        td = xfer->td_transfer_cache;<br>+        if (td == NULL || td->hcsplt == 0)<br>+            continue;<br>+        TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry);<br>+        TAILQ_INSERT_TAIL(&head, xfer, wait_entry);<br>+    }<br>+    TAILQ_CONCAT(&head, &sc->sc_bus.intr_q.head, wait_entry);<br>+    TAILQ_CONCAT(&sc->sc_bus.intr_q.head, &head, wait_entry);<br>+<br>+    /* put non-TT BULK transfers last */<br>+    TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {<br>+        td = xfer->td_transfer_cache;<br>+        if (td == NULL || td->hcsplt != 0 || td->ep_type != UE_BULK)<br>+            continue;<br>+        TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry);<br>+        TAILQ_INSERT_TAIL(&head, xfer, wait_entry);<br>+    }<br>+    TAILQ_CONCAT(&sc->sc_bus.intr_q.head, &head, wait_entry);<br>+<br>+    if ((temp & 7) == 0) {<br>+<br>+        DPRINTFN(12, "SOF interrupt #%d, needsof=%d\n",<br>+            (int)temp, (int)sc->sc_needsof);<br>+<br>+        /* update SOF IRQ mask */<br>+        if (sc->sc_irq_mask & GINTMSK_SOFMSK) {<br>+            if (sc->sc_needsof == 0) {<br>+                sc->sc_irq_mask &= ~GINTMSK_SOFMSK; <br>+                DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+            }<br>+        } else {<br>+            if (sc->sc_needsof != 0) {<br>+                sc->sc_irq_mask |= GINTMSK_SOFMSK; <br>+                DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+            }<br>+        }<br>+<br>+        /* clear need SOF flag */<br>+        sc->sc_needsof = 0;<br>+    }<br>+    return (1);<br>+}<br>+<br>+static void<br>+dwc_otg_interrupt_poll_locked(struct dwc_otg_softc *sc)<br>+{<br>+    struct usb_xfer *xfer;<br>+    uint32_t temp;<br>+    uint8_t got_rx_status;<br>+    uint8_t x;<br>+<br>+repeat:<br>+    /* get all channel interrupts */<br>+    for (x = 0; x != sc->sc_host_ch_max; x++) {<br>+        temp = DWC_OTG_READ_4(sc, DOTG_HCINT(x));<br>+        if (temp != 0) {<br>+            DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), temp);<br>+            temp &= ~HCINT_SOFTWARE_ONLY;<br>+            sc->sc_chan_state[x].hcint |= temp;<br>+        }<br>+    }<br>+<br>+    if (sc->sc_last_rx_status == 0) {<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_GINTSTS);<br>+        if (temp & GINTSTS_RXFLVL) {<br>+            /* pop current status */<br>+            sc->sc_last_rx_status =<br>+                DWC_OTG_READ_4(sc, DOTG_GRXSTSPD);<br>+        }<br>+<br>+        if (sc->sc_last_rx_status != 0) {<br>+<br>+            uint8_t ep_no;<br>+<br>+            temp = sc->sc_last_rx_status &<br>+                GRXSTSRD_PKTSTS_MASK;<br>+<br>+            /* non-data messages we simply skip */<br>+            if (temp != GRXSTSRD_STP_DATA &&<br>+                temp != GRXSTSRD_OUT_DATA) {<br>+                dwc_otg_common_rx_ack(sc);<br>+                goto repeat;<br>+            }<br>+<br>+            temp = GRXSTSRD_BCNT_GET(<br>+                sc->sc_last_rx_status);<br>+            ep_no = GRXSTSRD_CHNUM_GET(<br>+                sc->sc_last_rx_status);<br>+<br>+            /* receive data, if any */<br>+            if (temp != 0) {<br>+                DPRINTF("Reading %d bytes from ep %d\n", temp, ep_no);<br>+                bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,<br>+                    DOTG_DFIFO(ep_no),<br>+                    sc->sc_rx_bounce_buffer, (temp + 3) / 4);<br>+            }<br>+<br>+            /* check if we should dump the data */<br>+            if (!(sc->sc_active_rx_ep & (1U << ep_no))) {<br>+                dwc_otg_common_rx_ack(sc);<br>+                goto repeat;<br>+            }<br>+<br>+            got_rx_status = 1;<br>+<br>+            DPRINTFN(5, "RX status = 0x%08x: ch=%d pid=%d bytes=%d sts=%d\n",<br>+                sc->sc_last_rx_status, ep_no,<br>+                (sc->sc_last_rx_status >> 15) & 3,<br>+                GRXSTSRD_BCNT_GET(sc->sc_last_rx_status),<br>+                (sc->sc_last_rx_status >> 17) & 15);<br>+        } else {<br>+            got_rx_status = 0;<br>+        }<br>+    } else {<br>+        uint8_t ep_no;<br>+<br>+        ep_no = GRXSTSRD_CHNUM_GET(<br>+            sc->sc_last_rx_status);<br>+<br>+        /* check if we should dump the data */<br>+        if (!(sc->sc_active_rx_ep & (1U << ep_no))) {<br>+            dwc_otg_common_rx_ack(sc);<br>+            goto repeat;<br>+        }<br>+<br>+        got_rx_status = 1;<br>+    }<br>+<br>+    /* execute FIFOs */<br>+    TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry)<br>+        dwc_otg_xfer_do_fifo(sc, xfer);<br>+<br>+    if (got_rx_status) {<br>+        /* check if data was consumed */<br>+        if (sc->sc_last_rx_status == 0)<br>+            goto repeat;<br>+<br>+        /* disable RX FIFO level interrupt */<br>+        sc->sc_irq_mask &= ~GINTMSK_RXFLVLMSK;<br>+        DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+    }<br>+<br>+    if (sc->sc_flags.status_device_mode == 0 && sc->sc_xfer_complete == 0) {<br>+        /* update host transfer schedule, so that new transfers can be issued */<br>+        if (dwc_otg_update_host_transfer_schedule_locked(sc))<br>+            goto repeat;<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_interrupt_complete_locked(struct dwc_otg_softc *sc)<br>+{<br>+    struct usb_xfer *xfer;<br>+repeat:<br>+    /* scan for completion events */<br>+    TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {<br>+        if (dwc_otg_xfer_do_complete_locked(sc, xfer))<br>+            goto repeat;<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_vbus_interrupt(struct dwc_otg_softc *sc, uint8_t is_on)<br>+{<br>+    DPRINTFN(5, "vbus = %u\n", is_on);<br>+<br>+    /*<br>+     * If the USB host mode is forced, then assume VBUS is always<br>+     * present else rely on the input to this function:<br>+     */<br>+    if ((is_on != 0) || (sc->sc_mode == DWC_MODE_HOST)) {<br>+<br>+        if (!sc->sc_flags.status_vbus) {<br>+            sc->sc_flags.status_vbus = 1;<br>+<br>+            /* complete root HUB interrupt endpoint */<br>+<br>+            dwc_otg_root_intr(sc);<br>+        }<br>+    } else {<br>+        if (sc->sc_flags.status_vbus) {<br>+            sc->sc_flags.status_vbus = 0;<br>+            sc->sc_flags.status_bus_reset = 0;<br>+            sc->sc_flags.status_suspend = 0;<br>+            sc->sc_flags.change_suspend = 0;<br>+            sc->sc_flags.change_connect = 1;<br>+<br>+            /* complete root HUB interrupt endpoint */<br>+<br>+            dwc_otg_root_intr(sc);<br>+        }<br>+    }<br>+}<br>+<br>+int<br>+dwc_otg_filter_interrupt(void *arg)<br>+{<br>+    struct dwc_otg_softc *sc = arg;<br>+    int retval = FILTER_HANDLED;<br>+    uint32_t status;<br>+<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+<br>+    /* read and clear interrupt status */<br>+    status = DWC_OTG_READ_4(sc, DOTG_GINTSTS);<br>+<br>+    /* clear interrupts we are handling here */<br>+    DWC_OTG_WRITE_4(sc, DOTG_GINTSTS, status & ~DWC_OTG_MSK_GINT_THREAD_IRQ);<br>+<br>+    /* check for USB state change interrupts */<br>+    if ((status & DWC_OTG_MSK_GINT_THREAD_IRQ) != 0)<br>+        retval = FILTER_SCHEDULE_THREAD;<br>+<br>+    /* clear all IN endpoint interrupts */<br>+    if (status & GINTSTS_IEPINT) {<br>+        uint32_t temp;<br>+        uint8_t x;<br>+<br>+        for (x = 0; x != sc->sc_dev_in_ep_max; x++) {<br>+            temp = DWC_OTG_READ_4(sc, DOTG_DIEPINT(x));<br>+            if (temp & DIEPMSK_XFERCOMPLMSK) {<br>+                DWC_OTG_WRITE_4(sc, DOTG_DIEPINT(x),<br>+                    DIEPMSK_XFERCOMPLMSK);<br>+            }<br>+        }<br>+    }<br>+<br>+    /* poll FIFOs, if any */<br>+    dwc_otg_interrupt_poll_locked(sc);<br>+<br>+    if (sc->sc_xfer_complete != 0)<br>+        retval = FILTER_SCHEDULE_THREAD;<br>+<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+<br>+    return (retval);<br>+}<br>+<br>+void<br>+dwc_otg_interrupt(void *arg)<br>+{<br>+    struct dwc_otg_softc *sc = arg;<br>+    uint32_t status;<br>+<br>+    USB_BUS_LOCK(&sc->sc_bus);<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+<br>+    /* read and clear interrupt status */<br>+    status = DWC_OTG_READ_4(sc, DOTG_GINTSTS);<br>+<br>+    /* clear interrupts we are handling here */<br>+    DWC_OTG_WRITE_4(sc, DOTG_GINTSTS, status & DWC_OTG_MSK_GINT_THREAD_IRQ);<br>+<br>+    DPRINTFN(14, "GINTSTS=0x%08x HAINT=0x%08x HFNUM=0x%08x\n",<br>+        status, DWC_OTG_READ_4(sc, DOTG_HAINT),<br>+        DWC_OTG_READ_4(sc, DOTG_HFNUM));<br>+<br>+    if (status & GINTSTS_USBRST) {<br>+<br>+        /* set correct state */<br>+        sc->sc_flags.status_device_mode = 1;<br>+        sc->sc_flags.status_bus_reset = 0;<br>+        sc->sc_flags.status_suspend = 0;<br>+        sc->sc_flags.change_suspend = 0;<br>+        sc->sc_flags.change_connect = 1;<br>+<br>+        /* Disable SOF interrupt */<br>+        sc->sc_irq_mask &= ~GINTMSK_SOFMSK;<br>+        DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+<br>+        /* complete root HUB interrupt endpoint */<br>+        dwc_otg_root_intr(sc);<br>+    }<br>+<br>+    /* check for any bus state change interrupts */<br>+    if (status & GINTSTS_ENUMDONE) {<br>+<br>+        uint32_t temp;<br>+<br>+        DPRINTFN(5, "end of reset\n");<br>+<br>+        /* set correct state */<br>+        sc->sc_flags.status_device_mode = 1;<br>+        sc->sc_flags.status_bus_reset = 1;<br>+        sc->sc_flags.status_suspend = 0;<br>+        sc->sc_flags.change_suspend = 0;<br>+        sc->sc_flags.change_connect = 1;<br>+        sc->sc_flags.status_low_speed = 0;<br>+        sc->sc_flags.port_enabled = 1;<br>+<br>+        /* reset FIFOs */<br>+        (void) dwc_otg_init_fifo(sc, DWC_MODE_DEVICE);<br>+<br>+        /* reset function address */<br>+        dwc_otg_set_address(sc, 0);<br>+<br>+        /* figure out enumeration speed */<br>+        temp = DWC_OTG_READ_4(sc, DOTG_DSTS);<br>+        if (DSTS_ENUMSPD_GET(temp) == DSTS_ENUMSPD_HI)<br>+            sc->sc_flags.status_high_speed = 1;<br>+        else<br>+            sc->sc_flags.status_high_speed = 0;<br>+<br>+        /*<br>+         * Disable resume and SOF interrupt, and enable<br>+         * suspend and RX frame interrupt:<br>+         */<br>+        sc->sc_irq_mask &= ~(GINTMSK_WKUPINTMSK | GINTMSK_SOFMSK);<br>+        sc->sc_irq_mask |= GINTMSK_USBSUSPMSK;<br>+        DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+<br>+        /* complete root HUB interrupt endpoint */<br>+        dwc_otg_root_intr(sc);<br>+    }<br>+<br>+    if (status & GINTSTS_PRTINT) {<br>+        uint32_t hprt;<br>+<br>+        hprt = DWC_OTG_READ_4(sc, DOTG_HPRT);<br>+<br>+        /* clear change bits */<br>+        DWC_OTG_WRITE_4(sc, DOTG_HPRT, (hprt & (<br>+            HPRT_PRTPWR | HPRT_PRTENCHNG |<br>+            HPRT_PRTCONNDET | HPRT_PRTOVRCURRCHNG)) |<br>+            sc->sc_hprt_val);<br>+<br>+        DPRINTFN(12, "GINTSTS=0x%08x, HPRT=0x%08x\n", status, hprt);<br>+<br>+        sc->sc_flags.status_device_mode = 0;<br>+<br>+        if (hprt & HPRT_PRTCONNSTS)<br>+            sc->sc_flags.status_bus_reset = 1;<br>+        else<br>+            sc->sc_flags.status_bus_reset = 0;<br>+<br>+        if (hprt & HPRT_PRTENCHNG)<br>+            sc->sc_flags.change_enabled = 1;<br>+<br>+        if (hprt & HPRT_PRTENA)<br>+            sc->sc_flags.port_enabled = 1;<br>+        else<br>+            sc->sc_flags.port_enabled = 0;<br>+<br>+        if (hprt & HPRT_PRTOVRCURRCHNG)<br>+            sc->sc_flags.change_over_current = 1;<br>+<br>+        if (hprt & HPRT_PRTOVRCURRACT)<br>+            sc->sc_flags.port_over_current = 1;<br>+        else<br>+            sc->sc_flags.port_over_current = 0;<br>+<br>+        if (hprt & HPRT_PRTPWR)<br>+            sc->sc_flags.port_powered = 1;<br>+        else<br>+            sc->sc_flags.port_powered = 0;<br>+<br>+        if (((hprt & HPRT_PRTSPD_MASK)<br>+            >> HPRT_PRTSPD_SHIFT) == HPRT_PRTSPD_LOW)<br>+            sc->sc_flags.status_low_speed = 1;<br>+        else<br>+            sc->sc_flags.status_low_speed = 0;<br>+<br>+        if (((hprt & HPRT_PRTSPD_MASK)<br>+            >> HPRT_PRTSPD_SHIFT) == HPRT_PRTSPD_HIGH)<br>+            sc->sc_flags.status_high_speed = 1;<br>+        else<br>+            sc->sc_flags.status_high_speed = 0;<br>+<br>+        if (hprt & HPRT_PRTCONNDET)<br>+            sc->sc_flags.change_connect = 1;<br>+<br>+        if (hprt & HPRT_PRTSUSP)<br>+            dwc_otg_suspend_irq(sc);<br>+        else<br>+            dwc_otg_resume_irq(sc);<br>+<br>+        /* complete root HUB interrupt endpoint */<br>+        dwc_otg_root_intr(sc);<br>+<br>+        /* update host frame interval */<br>+        dwc_otg_update_host_frame_interval(sc);<br>+    }<br>+<br>+    /*<br>+     * If resume and suspend is set at the same time we interpret<br>+     * that like RESUME. Resume is set when there is at least 3<br>+     * milliseconds of inactivity on the USB BUS.<br>+     */<br>+    if (status & GINTSTS_WKUPINT) {<br>+<br>+        DPRINTFN(5, "resume interrupt\n");<br>+<br>+        dwc_otg_resume_irq(sc);<br>+<br>+    } else if (status & GINTSTS_USBSUSP) {<br>+<br>+        DPRINTFN(5, "suspend interrupt\n");<br>+<br>+        dwc_otg_suspend_irq(sc);<br>+    }<br>+    /* check VBUS */<br>+    if (status & (GINTSTS_USBSUSP |<br>+        GINTSTS_USBRST |<br>+        GINTMSK_OTGINTMSK |<br>+        GINTSTS_SESSREQINT)) {<br>+        uint32_t temp;<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_GOTGCTL);<br>+<br>+        DPRINTFN(5, "GOTGCTL=0x%08x\n", temp);<br>+<br>+        dwc_otg_vbus_interrupt(sc,<br>+            (temp & (GOTGCTL_ASESVLD | GOTGCTL_BSESVLD)) ? 1 : 0);<br>+    }<br>+<br>+    if (sc->sc_xfer_complete != 0) {<br>+        sc->sc_xfer_complete = 0;<br>+<br>+        /* complete FIFOs, if any */<br>+        dwc_otg_interrupt_complete_locked(sc);<br>+<br>+        if (sc->sc_flags.status_device_mode == 0) {<br>+            /* update host transfer schedule, so that new transfers can be issued */<br>+            if (dwc_otg_update_host_transfer_schedule_locked(sc))<br>+                dwc_otg_interrupt_poll_locked(sc);<br>+        }<br>+    }<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+    USB_BUS_UNLOCK(&sc->sc_bus);<br>+}<br>+<br>+static void<br>+dwc_otg_setup_standard_chain_sub(struct dwc_otg_std_temp *temp)<br>+{<br>+    struct dwc_otg_td *td;<br>+<br>+    /* get current Transfer Descriptor */<br>+    td = temp->td_next;<br>+    temp->td = td;<br>+<br>+    /* prepare for next TD */<br>+    temp->td_next = td->obj_next;<br>+<br>+    /* fill out the Transfer Descriptor */<br>+    td->func = temp->func;<br>+    td->pc = temp->pc;<br>+    td->offset = temp->offset;<br>+    td->remainder = temp->len;<br>+    td->tx_bytes = 0;<br>+    td->error_any = 0;<br>+    td->error_stall = 0;<br>+    td->npkt = 0;<br>+    td->did_stall = temp->did_stall;<br>+    td->short_pkt = temp->short_pkt;<br>+    td->alt_next = temp->setup_alt_next;<br>+    td->set_toggle = 0;<br>+    td->got_short = 0;<br>+    td->did_nak = 0;<br>+    td->channel = DWC_OTG_MAX_CHANNELS;<br>+    td->state = 0;<br>+    td->errcnt = 0;<br>+    td->tt_scheduled = 0;<br>+    td->tt_xactpos = HCSPLT_XACTPOS_BEGIN;<br>+}<br>+<br>+static void<br>+dwc_otg_setup_standard_chain(struct usb_xfer *xfer)<br>+{<br>+    struct dwc_otg_std_temp temp;<br>+    struct dwc_otg_td *td;<br>+    uint32_t x;<br>+    uint8_t need_sync;<br>+    uint8_t is_host;<br>+<br>+    DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",<br>+        xfer->address, UE_GET_ADDR(xfer->endpointno),<br>+        xfer->sumlen, usbd_get_speed(xfer->xroot->udev));<br>+<br>+    temp.max_frame_size = xfer->max_frame_size;<br>+<br>+    td = xfer->td_start[0];<br>+    xfer->td_transfer_first = td;<br>+    xfer->td_transfer_cache = td;<br>+<br>+    /* setup temp */<br>+<br>+    temp.pc = NULL;<br>+    <a href="http://temp.td">temp.td</a> = NULL;<br>+    temp.td_next = xfer->td_start[0];<br>+    temp.offset = 0;<br>+    temp.setup_alt_next = xfer->flags_int.short_frames_ok ||<br>+        xfer->flags_int.isochronous_xfr;<br>+    temp.did_stall = !xfer->flags_int.control_stall;<br>+<br>+    is_host = (xfer->xroot->udev->flags.usb_mode == USB_MODE_HOST);<br>+<br>+    /* check if we should prepend a setup message */<br>+<br>+    if (xfer->flags_int.control_xfr) {<br>+        if (xfer->flags_int.control_hdr) {<br>+<br>+            if (is_host)<br>+                temp.func = &dwc_otg_host_setup_tx;<br>+            else<br>+                temp.func = &dwc_otg_setup_rx;<br>+<br>+            temp.len = xfer->frlengths[0];<br>+            temp.pc = xfer->frbuffers + 0;<br>+            temp.short_pkt = temp.len ? 1 : 0;<br>+<br>+            /* check for last frame */<br>+            if (xfer->nframes == 1) {<br>+                /* no STATUS stage yet, SETUP is last */<br>+                if (xfer->flags_int.control_act)<br>+                    temp.setup_alt_next = 0;<br>+            }<br>+<br>+            dwc_otg_setup_standard_chain_sub(&temp);<br>+        }<br>+        x = 1;<br>+    } else {<br>+        x = 0;<br>+    }<br>+<br>+    if (x != xfer->nframes) {<br>+        if (xfer->endpointno & UE_DIR_IN) {<br>+            if (is_host) {<br>+                temp.func = &dwc_otg_host_data_rx;<br>+                need_sync = 0;<br>+            } else {<br>+                temp.func = &dwc_otg_data_tx;<br>+                need_sync = 1;<br>+            }<br>+        } else {<br>+            if (is_host) {<br>+                temp.func = &dwc_otg_host_data_tx;<br>+                need_sync = 0;<br>+            } else {<br>+                temp.func = &dwc_otg_data_rx;<br>+                need_sync = 0;<br>+            }<br>+        }<br>+<br>+        /* setup "pc" pointer */<br>+        temp.pc = xfer->frbuffers + x;<br>+    } else {<br>+        need_sync = 0;<br>+    }<br>+    while (x != xfer->nframes) {<br>+<br>+        /* DATA0 / DATA1 message */<br>+<br>+        temp.len = xfer->frlengths[x];<br>+<br>+        x++;<br>+<br>+        if (x == xfer->nframes) {<br>+            if (xfer->flags_int.control_xfr) {<br>+                if (xfer->flags_int.control_act) {<br>+                    temp.setup_alt_next = 0;<br>+                }<br>+            } else {<br>+                temp.setup_alt_next = 0;<br>+            }<br>+        }<br>+        if (temp.len == 0) {<br>+<br>+            /* make sure that we send an USB packet */<br>+<br>+            temp.short_pkt = 0;<br>+<br>+        } else {<br>+<br>+            /* regular data transfer */<br>+<br>+            temp.short_pkt = (xfer->flags.force_short_xfer ? 0 : 1);<br>+        }<br>+<br>+        dwc_otg_setup_standard_chain_sub(&temp);<br>+<br>+        if (xfer->flags_int.isochronous_xfr) {<br>+            temp.offset += temp.len;<br>+        } else {<br>+            /* get next Page Cache pointer */<br>+            temp.pc = xfer->frbuffers + x;<br>+        }<br>+    }<br>+<br>+    if (xfer->flags_int.control_xfr) {<br>+<br>+        /* always setup a valid "pc" pointer for status and sync */<br>+        temp.pc = xfer->frbuffers + 0;<br>+        temp.len = 0;<br>+        temp.short_pkt = 0;<br>+        temp.setup_alt_next = 0;<br>+<br>+        /* check if we need to sync */<br>+        if (need_sync) {<br>+            /* we need a SYNC point after TX */<br>+            temp.func = &dwc_otg_data_tx_sync;<br>+            dwc_otg_setup_standard_chain_sub(&temp);<br>+        }<br>+<br>+        /* check if we should append a status stage */<br>+        if (!xfer->flags_int.control_act) {<br>+<br>+            /*<br>+             * Send a DATA1 message and invert the current<br>+             * endpoint direction.<br>+             */<br>+            if (xfer->endpointno & UE_DIR_IN) {<br>+                if (is_host) {<br>+                    temp.func = &dwc_otg_host_data_tx;<br>+                    need_sync = 0;<br>+                } else {<br>+                    temp.func = &dwc_otg_data_rx;<br>+                    need_sync = 0;<br>+                }<br>+            } else {<br>+                if (is_host) {<br>+                    temp.func = &dwc_otg_host_data_rx;<br>+                    need_sync = 0;<br>+                } else {<br>+                    temp.func = &dwc_otg_data_tx;<br>+                    need_sync = 1;<br>+                }<br>+            }<br>+<br>+            dwc_otg_setup_standard_chain_sub(&temp);<br>+<br>+            /* data toggle should be DATA1 */<br>+            td = <a href="http://temp.td">temp.td</a>;<br>+            td->set_toggle = 1;<br>+<br>+            if (need_sync) {<br>+                /* we need a SYNC point after TX */<br>+                temp.func = &dwc_otg_data_tx_sync;<br>+                dwc_otg_setup_standard_chain_sub(&temp);<br>+            }<br>+        }<br>+    } else {<br>+        /* check if we need to sync */<br>+        if (need_sync) {<br>+<br>+            temp.pc = xfer->frbuffers + 0;<br>+            temp.len = 0;<br>+            temp.short_pkt = 0;<br>+            temp.setup_alt_next = 0;<br>+<br>+            /* we need a SYNC point after TX */<br>+            temp.func = &dwc_otg_data_tx_sync;<br>+            dwc_otg_setup_standard_chain_sub(&temp);<br>+        }<br>+    }<br>+<br>+    /* must have at least one frame! */<br>+    td = <a href="http://temp.td">temp.td</a>;<br>+    xfer->td_transfer_last = td;<br>+<br>+    if (is_host) {<br>+<br>+        struct dwc_otg_softc *sc;<br>+        uint32_t hcchar;<br>+        uint32_t hcsplt;<br>+<br>+        sc = DWC_OTG_BUS2SC(xfer->xroot->bus);<br>+<br>+        /* get first again */<br>+        td = xfer->td_transfer_first;<br>+        td->toggle = (xfer->endpoint->toggle_next ? 1 : 0);<br>+<br>+        hcchar =<br>+            (xfer->address << HCCHAR_DEVADDR_SHIFT) |<br>+            ((xfer->endpointno & UE_ADDR) << HCCHAR_EPNUM_SHIFT) |<br>+            (xfer->max_packet_size << HCCHAR_MPS_SHIFT) |<br>+            HCCHAR_CHENA;<br>+<br>+        /*<br>+         * We are not always able to meet the timing<br>+         * requirements of the USB interrupt endpoint's<br>+         * complete split token, when doing transfers going<br>+         * via a transaction translator. Use the CONTROL<br>+         * transfer type instead of the INTERRUPT transfer<br>+         * type in general, as a means to workaround<br>+         * that. This trick should work for both FULL and LOW<br>+         * speed USB traffic going through a TT. For non-TT<br>+         * traffic it works aswell. The reason for using<br>+         * CONTROL type instead of BULK is that some TTs might<br>+         * reject LOW speed BULK traffic.<br>+         */<br>+        if (td->ep_type == UE_INTERRUPT)<br>+            hcchar |= (UE_CONTROL << HCCHAR_EPTYPE_SHIFT);<br>+        else<br>+            hcchar |= (td->ep_type << HCCHAR_EPTYPE_SHIFT);<br>+<br>+        if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_LOW)<br>+            hcchar |= HCCHAR_LSPDDEV;<br>+        if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN)<br>+            hcchar |= HCCHAR_EPDIR_IN;<br>+<br>+        switch (xfer->xroot->udev->speed) {<br>+        case USB_SPEED_FULL:<br>+        case USB_SPEED_LOW:<br>+            /* check if root HUB port is running High Speed */<br>+            if (xfer->xroot->udev->parent_hs_hub != NULL) {<br>+                hcsplt = HCSPLT_SPLTENA |<br>+                    (xfer->xroot->udev->hs_port_no <<<br>+                    HCSPLT_PRTADDR_SHIFT) |<br>+                    (xfer->xroot->udev->hs_hub_addr <<<br>+                    HCSPLT_HUBADDR_SHIFT);<br>+            } else {<br>+                hcsplt = 0;<br>+            }<br>+            if (td->ep_type == UE_INTERRUPT) {<br>+                uint32_t ival;<br>+                ival = xfer->interval / DWC_OTG_HOST_TIMER_RATE;<br>+                if (ival == 0)<br>+                    ival = 1;<br>+                else if (ival > 127)<br>+                    ival = 127;<br>+                td->tmr_val = sc->sc_tmr_val + ival;<br>+                td->tmr_res = ival;<br>+            } else if (td->ep_type == UE_ISOCHRONOUS) {<br>+                td->tmr_val = 0;<br>+                td->tmr_res = 1;<br>+            } else {<br>+                td->tmr_val = 0;<br>+                td->tmr_res = 0;<br>+            }<br>+            break;<br>+        case USB_SPEED_HIGH:<br>+            hcsplt = 0;<br>+            if (td->ep_type == UE_INTERRUPT) {<br>+                uint32_t ival;<br>+#if 0<br>+                hcchar |= ((xfer->max_packet_count & 3)<br>+                    << HCCHAR_MC_SHIFT);<br>+#endif<br>+                ival = xfer->interval / DWC_OTG_HOST_TIMER_RATE;<br>+                if (ival == 0)<br>+                    ival = 1;<br>+                else if (ival > 127)<br>+                    ival = 127;<br>+                td->tmr_val = sc->sc_tmr_val + ival;<br>+                td->tmr_res = ival;<br>+            } else if (td->ep_type == UE_ISOCHRONOUS) {<br>+                hcchar |= ((xfer->max_packet_count & 3)<br>+                    << HCCHAR_MC_SHIFT);<br>+                td->tmr_val = 0;<br>+                td->tmr_res = 1 << usbd_xfer_get_fps_shift(xfer);<br>+            } else {<br>+                td->tmr_val = 0;<br>+                td->tmr_res = 0;<br>+            }<br>+            break;<br>+        default:<br>+            hcsplt = 0;<br>+            td->tmr_val = 0;<br>+            td->tmr_res = 0;<br>+            break;<br>+        }<br>+<br>+        /* store configuration in all TD's */<br>+        while (1) {<br>+            td->hcchar = hcchar;<br>+            td->hcsplt = hcsplt;<br>+<br>+            if (((void *)td) == xfer->td_transfer_last)<br>+                break;<br>+<br>+            td = td->obj_next;<br>+        }<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_timeout(void *arg)<br>+{<br>+    struct usb_xfer *xfer = arg;<br>+<br>+    DPRINTF("xfer=%p\n", xfer);<br>+<br>+    USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);<br>+<br>+    /* transfer is transferred */<br>+    dwc_otg_device_done(xfer, USB_ERR_TIMEOUT);<br>+}<br>+<br>+static void<br>+dwc_otg_start_standard_chain(struct usb_xfer *xfer)<br>+{<br>+    struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);<br>+    struct usb_xfer_root *xroot;<br>+    struct dwc_otg_td *td;<br>+<br>+    DPRINTFN(9, "\n");<br>+<br>+    /*<br>+     * Poll one time in device mode, which will turn on the<br>+     * endpoint interrupts. Else wait for SOF interrupt in host<br>+     * mode.<br>+     */<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+<br>+    if (sc->sc_flags.status_device_mode != 0) {<br>+        dwc_otg_xfer_do_fifo(sc, xfer);<br>+        if (dwc_otg_xfer_do_complete_locked(sc, xfer))<br>+            goto done;<br>+    }<br>+<br>+    /* put transfer on interrupt queue */<br>+    usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);<br>+<br>+    /* start timeout, if any */<br>+    if (xfer->timeout != 0) {<br>+        usbd_transfer_timeout_ms(xfer,<br>+            &dwc_otg_timeout, xfer->timeout);<br>+    }<br>+<br>+    if (sc->sc_flags.status_device_mode != 0)<br>+        goto done;<br>+<br>+    /* enable SOF interrupt, if any */<br>+    dwc_otg_enable_sof_irq(sc);<br>+<br>+    td = xfer->td_transfer_cache;<br>+    if (td->ep_type != UE_BULK)<br>+        goto done;<br>+<br>+    xroot = xfer->xroot;<br>+<br>+    /*<br>+     * Optimise the ping-pong effect by waking up other BULK<br>+     * transfers belonging to the same device group:<br>+     */<br>+    TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {<br>+        td = xfer->td_transfer_cache;<br>+        if (td == NULL || td->ep_type != UE_BULK || xfer->xroot != xroot)<br>+            continue;<br>+        /* reset NAK counter */ <br>+        td->did_nak = 0;<br>+    }<br>+done:<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+}<br>+<br>+static void<br>+dwc_otg_root_intr(struct dwc_otg_softc *sc)<br>+{<br>+    DPRINTFN(9, "\n");<br>+<br>+    USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);<br>+<br>+    /* set port bit */<br>+    sc->sc_hub_idata[0] = 0x02;    /* we only have one port */<br>+<br>+    uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,<br>+        sizeof(sc->sc_hub_idata));<br>+}<br>+<br>+static usb_error_t<br>+dwc_otg_standard_done_sub(struct usb_xfer *xfer)<br>+{<br>+    struct dwc_otg_td *td;<br>+    uint32_t len;<br>+    usb_error_t error;<br>+<br>+    DPRINTFN(9, "\n");<br>+<br>+    td = xfer->td_transfer_cache;<br>+<br>+    do {<br>+        len = td->remainder;<br>+<br>+        /* store last data toggle */<br>+        xfer->endpoint->toggle_next = td->toggle;<br>+<br>+        if (xfer->aframes != xfer->nframes) {<br>+            /*<br>+             * Verify the length and subtract<br>+             * the remainder from "frlengths[]":<br>+             */<br>+            if (len > xfer->frlengths[xfer->aframes]) {<br>+                td->error_any = 1;<br>+            } else {<br>+                xfer->frlengths[xfer->aframes] -= len;<br>+            }<br>+        }<br>+        /* Check for transfer error */<br>+        if (td->error_any) {<br>+            /* the transfer is finished */<br>+            error = (td->error_stall ?<br>+                USB_ERR_STALLED : USB_ERR_IOERROR);<br>+            td = NULL;<br>+            break;<br>+        }<br>+        /* Check for short transfer */<br>+        if (len > 0) {<br>+            if (xfer->flags_int.short_frames_ok ||<br>+                xfer->flags_int.isochronous_xfr) {<br>+                /* follow alt next */<br>+                if (td->alt_next) {<br>+                    td = td->obj_next;<br>+                } else {<br>+                    td = NULL;<br>+                }<br>+            } else {<br>+                /* the transfer is finished */<br>+                td = NULL;<br>+            }<br>+            error = 0;<br>+            break;<br>+        }<br>+        td = td->obj_next;<br>+<br>+        /* this USB frame is complete */<br>+        error = 0;<br>+        break;<br>+<br>+    } while (0);<br>+<br>+    /* update transfer cache */<br>+<br>+    xfer->td_transfer_cache = td;<br>+<br>+    return (error);<br>+}<br>+<br>+static void<br>+dwc_otg_standard_done(struct usb_xfer *xfer)<br>+{<br>+    usb_error_t err = 0;<br>+<br>+    DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n",<br>+        xfer, xfer->endpoint);<br>+<br>+    /* reset scanner */<br>+<br>+    xfer->td_transfer_cache = xfer->td_transfer_first;<br>+<br>+    if (xfer->flags_int.control_xfr) {<br>+<br>+        if (xfer->flags_int.control_hdr) {<br>+<br>+            err = dwc_otg_standard_done_sub(xfer);<br>+        }<br>+        xfer->aframes = 1;<br>+<br>+        if (xfer->td_transfer_cache == NULL) {<br>+            goto done;<br>+        }<br>+    }<br>+    while (xfer->aframes != xfer->nframes) {<br>+<br>+        err = dwc_otg_standard_done_sub(xfer);<br>+        xfer->aframes++;<br>+<br>+        if (xfer->td_transfer_cache == NULL) {<br>+            goto done;<br>+        }<br>+    }<br>+<br>+    if (xfer->flags_int.control_xfr &&<br>+        !xfer->flags_int.control_act) {<br>+<br>+        err = dwc_otg_standard_done_sub(xfer);<br>+    }<br>+done:<br>+    dwc_otg_device_done(xfer, err);<br>+}<br>+<br>+/*------------------------------------------------------------------------*<br>+ *    dwc_otg_device_done<br>+ *<br>+ * NOTE: this function can be called more than one time on the<br>+ * same USB transfer!<br>+ *------------------------------------------------------------------------*/<br>+static void<br>+dwc_otg_device_done(struct usb_xfer *xfer, usb_error_t error)<br>+{<br>+    struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);<br>+<br>+    DPRINTFN(9, "xfer=%p, endpoint=%p, error=%d\n",<br>+        xfer, xfer->endpoint, error);<br>+<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+<br>+    if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {<br>+        /* Interrupts are cleared by the interrupt handler */<br>+    } else {<br>+        struct dwc_otg_td *td;<br>+<br>+        td = xfer->td_transfer_cache;<br>+         if (td != NULL)<br>+            dwc_otg_host_channel_free(sc, td);<br>+    }<br>+    /* dequeue transfer and start next transfer */<br>+    usbd_transfer_done(xfer, error);<br>+<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+}<br>+<br>+static void<br>+dwc_otg_xfer_stall(struct usb_xfer *xfer)<br>+{<br>+    dwc_otg_device_done(xfer, USB_ERR_STALLED);<br>+}<br>+<br>+#ifndef __rtems__<br>+static void<br>+dwc_otg_set_stall(struct usb_device *udev,<br>+    struct usb_endpoint *ep, uint8_t *did_stall)<br>+#else<br>+static void<br>+dwc_otg_set_stall(struct usb_device *udev, struct usb_xfer *xfer,<br>+    struct usb_endpoint *ep, uint8_t *did_stall)<br>+#endif<br>+{<br>+    struct dwc_otg_softc *sc;<br>+    uint32_t temp;<br>+    uint32_t reg;<br>+    uint8_t ep_no;<br>+<br>+    USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);<br>+<br>+    /* check mode */<br>+    if (udev->flags.usb_mode != USB_MODE_DEVICE) {<br>+        /* not supported */<br>+        return;<br>+    }<br>+<br>+    sc = DWC_OTG_BUS2SC(udev->bus);<br>+<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+<br>+    /* get endpoint address */<br>+    ep_no = ep->edesc->bEndpointAddress;<br>+<br>+    DPRINTFN(5, "endpoint=0x%x\n", ep_no);<br>+<br>+    if (ep_no & UE_DIR_IN) {<br>+        reg = DOTG_DIEPCTL(ep_no & UE_ADDR);<br>+        temp = sc->sc_in_ctl[ep_no & UE_ADDR];<br>+    } else {<br>+        reg = DOTG_DOEPCTL(ep_no & UE_ADDR);<br>+        temp = sc->sc_out_ctl[ep_no & UE_ADDR];<br>+    }<br>+<br>+    /* disable and stall endpoint */<br>+    DWC_OTG_WRITE_4(sc, reg, temp | DOEPCTL_EPDIS);<br>+    DWC_OTG_WRITE_4(sc, reg, temp | DOEPCTL_STALL);<br>+<br>+    /* clear active OUT ep */<br>+    if (!(ep_no & UE_DIR_IN)) {<br>+<br>+        sc->sc_active_rx_ep &= ~(1U << (ep_no & UE_ADDR));<br>+<br>+        if (sc->sc_last_rx_status != 0 &&<br>+            (ep_no & UE_ADDR) == GRXSTSRD_CHNUM_GET(<br>+            sc->sc_last_rx_status)) {<br>+            /* dump data */<br>+            dwc_otg_common_rx_ack(sc);<br>+            /* poll interrupt */<br>+            dwc_otg_interrupt_poll_locked(sc);<br>+            dwc_otg_interrupt_complete_locked(sc);<br>+        }<br>+    }<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+    #ifdef __rtems__<br>+    if (xfer != NULL)<br>+        dwc_otg_xfer_stall(xfer);<br>+    #endif<br>+}<br>+<br>+static void<br>+dwc_otg_clear_stall_sub_locked(struct dwc_otg_softc *sc, uint32_t mps,<br>+    uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir)<br>+{<br>+    uint32_t reg;<br>+    uint32_t temp;<br>+<br>+    if (ep_type == UE_CONTROL) {<br>+        /* clearing stall is not needed */<br>+        return;<br>+    }<br>+<br>+    if (ep_dir) {<br>+        reg = DOTG_DIEPCTL(ep_no);<br>+    } else {<br>+        reg = DOTG_DOEPCTL(ep_no);<br>+        sc->sc_active_rx_ep |= (1U << ep_no);<br>+    }<br>+<br>+    /* round up and mask away the multiplier count */<br>+    mps = (mps + 3) & 0x7FC;<br>+<br>+    if (ep_type == UE_BULK) {<br>+        temp = DIEPCTL_EPTYPE_SET(<br>+            DIEPCTL_EPTYPE_BULK) |<br>+            DIEPCTL_USBACTEP;<br>+    } else if (ep_type == UE_INTERRUPT) {<br>+        temp = DIEPCTL_EPTYPE_SET(<br>+            DIEPCTL_EPTYPE_INTERRUPT) |<br>+            DIEPCTL_USBACTEP;<br>+    } else {<br>+        temp = DIEPCTL_EPTYPE_SET(<br>+            DIEPCTL_EPTYPE_ISOC) |<br>+            DIEPCTL_USBACTEP;<br>+    }<br>+<br>+    temp |= DIEPCTL_MPS_SET(mps);<br>+    temp |= DIEPCTL_TXFNUM_SET(ep_no);<br>+<br>+    if (ep_dir)<br>+        sc->sc_in_ctl[ep_no] = temp;<br>+    else<br>+        sc->sc_out_ctl[ep_no] = temp;<br>+<br>+    DWC_OTG_WRITE_4(sc, reg, temp | DOEPCTL_EPDIS);<br>+    DWC_OTG_WRITE_4(sc, reg, temp | DOEPCTL_SETD0PID);<br>+    DWC_OTG_WRITE_4(sc, reg, temp | DIEPCTL_SNAK);<br>+<br>+    /* we only reset the transmit FIFO */<br>+    if (ep_dir) {<br>+        DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL,<br>+            GRSTCTL_TXFIFO(ep_no) |<br>+            GRSTCTL_TXFFLSH);<br>+<br>+        DWC_OTG_WRITE_4(sc,<br>+            DOTG_DIEPTSIZ(ep_no), 0);<br>+    }<br>+<br>+    /* poll interrupt */<br>+    dwc_otg_interrupt_poll_locked(sc);<br>+    dwc_otg_interrupt_complete_locked(sc);<br>+}<br>+<br>+static void<br>+dwc_otg_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)<br>+{<br>+    struct dwc_otg_softc *sc;<br>+    struct usb_endpoint_descriptor *ed;<br>+<br>+    DPRINTFN(5, "endpoint=%p\n", ep);<br>+<br>+    USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);<br>+<br>+    /* check mode */<br>+    if (udev->flags.usb_mode != USB_MODE_DEVICE) {<br>+        /* not supported */<br>+        return;<br>+    }<br>+    /* get softc */<br>+    sc = DWC_OTG_BUS2SC(udev->bus);<br>+<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+<br>+    /* get endpoint descriptor */<br>+    ed = ep->edesc;<br>+<br>+    /* reset endpoint */<br>+    dwc_otg_clear_stall_sub_locked(sc,<br>+        UGETW(ed->wMaxPacketSize),<br>+        (ed->bEndpointAddress & UE_ADDR),<br>+        (ed->bmAttributes & UE_XFERTYPE),<br>+        (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));<br>+<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+}<br>+<br>+static void<br>+dwc_otg_device_state_change(struct usb_device *udev)<br>+{<br>+    struct dwc_otg_softc *sc;<br>+    uint8_t x;<br>+<br>+    /* check mode */<br>+    if (udev->flags.usb_mode != USB_MODE_DEVICE) {<br>+        /* not supported */<br>+        return;<br>+    }<br>+<br>+    /* get softc */<br>+    sc = DWC_OTG_BUS2SC(udev->bus);<br>+<br>+    /* deactivate all other endpoint but the control endpoint */<br>+    if (udev->state == USB_STATE_CONFIGURED ||<br>+        udev->state == USB_STATE_ADDRESSED) {<br>+<br>+        USB_BUS_LOCK(&sc->sc_bus);<br>+<br>+        for (x = 1; x != sc->sc_dev_ep_max; x++) {<br>+<br>+            if (x < sc->sc_dev_in_ep_max) {<br>+                DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(x),<br>+                    DIEPCTL_EPDIS);<br>+                DWC_OTG_WRITE_4(sc, DOTG_DIEPCTL(x), 0);<br>+            }<br>+<br>+            DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(x),<br>+                DOEPCTL_EPDIS);<br>+            DWC_OTG_WRITE_4(sc, DOTG_DOEPCTL(x), 0);<br>+        }<br>+        USB_BUS_UNLOCK(&sc->sc_bus);<br>+    }<br>+}<br>+<br>+int<br>+dwc_otg_init(struct dwc_otg_softc *sc)<br>+{<br>+    uint32_t temp;<br>+<br>+    DPRINTF("start\n");<br>+<br>+    /* set up the bus structure */<br>+    sc->sc_bus.usbrev = USB_REV_2_0;<br>+    sc->sc_bus.methods = &dwc_otg_bus_methods;<br>+<br>+    usb_callout_init_mtx(&sc->sc_timer,<br>+        &sc->sc_bus.bus_mtx, 0);<br>+<br>+    USB_BUS_LOCK(&sc->sc_bus);<br>+<br>+    /* turn on clocks */<br>+    dwc_otg_clocks_on(sc);<br>+<br>+    temp = DWC_OTG_READ_4(sc, DOTG_GSNPSID);<br>+    DPRINTF("Version = 0x%08x\n", temp);<br>+<br>+    /* disconnect */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DCTL,<br>+        DCTL_SFTDISCON);<br>+<br>+    /* wait for host to detect disconnect */<br>+    usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 32);<br>+<br>+    DWC_OTG_WRITE_4(sc, DOTG_GRSTCTL,<br>+        GRSTCTL_CSFTRST);<br>+<br>+    /* wait a little bit for block to reset */<br>+    usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 128);<br>+<br>+    switch (sc->sc_mode) {<br>+    case DWC_MODE_DEVICE:<br>+        temp = GUSBCFG_FORCEDEVMODE;<br>+        break;<br>+    case DWC_MODE_HOST:<br>+        temp = GUSBCFG_FORCEHOSTMODE;<br>+        break;<br>+    default:<br>+        temp = 0;<br>+        break;<br>+    }<br>+<br>+    /* select HSIC, ULPI or internal PHY mode */<br>+    switch (dwc_otg_phy_type) {<br>+    case DWC_OTG_PHY_HSIC:<br>+        DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG,<br>+            GUSBCFG_PHYIF |<br>+            GUSBCFG_TRD_TIM_SET(5) | temp);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GOTGCTL,<br>+            0x000000EC);<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_GLPMCFG);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG,<br>+            temp & ~GLPMCFG_HSIC_CONN);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG,<br>+            temp | GLPMCFG_HSIC_CONN);<br>+        break;<br>+    case DWC_OTG_PHY_ULPI:<br>+        DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG,<br>+            GUSBCFG_ULPI_UTMI_SEL |<br>+            GUSBCFG_TRD_TIM_SET(5) | temp);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GOTGCTL, 0);<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_GLPMCFG);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG,<br>+            temp & ~GLPMCFG_HSIC_CONN);<br>+        break;<br>+    case DWC_OTG_PHY_INTERNAL:<br>+        DWC_OTG_WRITE_4(sc, DOTG_GUSBCFG,<br>+            GUSBCFG_PHYSEL |<br>+            GUSBCFG_TRD_TIM_SET(5) | temp);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GOTGCTL, 0);<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_GLPMCFG);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GLPMCFG,<br>+            temp & ~GLPMCFG_HSIC_CONN);<br>+<br>+        temp = DWC_OTG_READ_4(sc, DOTG_GGPIO);<br>+        temp &= ~(DOTG_GGPIO_NOVBUSSENS | DOTG_GGPIO_I2CPADEN);<br>+        temp |= (DOTG_GGPIO_VBUSASEN | DOTG_GGPIO_VBUSBSEN |<br>+            DOTG_GGPIO_PWRDWN);<br>+        DWC_OTG_WRITE_4(sc, DOTG_GGPIO, temp);<br>+        break;<br>+    default:<br>+        break;<br>+    }<br>+<br>+    /* clear global nak */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DCTL,<br>+        DCTL_CGOUTNAK |<br>+        DCTL_CGNPINNAK);<br>+<br>+    /* disable USB port */<br>+    DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0xFFFFFFFF);<br>+<br>+    /* wait 10ms */<br>+    usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);<br>+<br>+    /* enable USB port */<br>+    DWC_OTG_WRITE_4(sc, DOTG_PCGCCTL, 0);<br>+<br>+    /* wait 10ms */<br>+    usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);<br>+<br>+    temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG3);<br>+<br>+    sc->sc_fifo_size = 4 * GHWCFG3_DFIFODEPTH_GET(temp);<br>+<br>+    temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG2);<br>+<br>+    sc->sc_dev_ep_max = GHWCFG2_NUMDEVEPS_GET(temp);<br>+<br>+    if (sc->sc_dev_ep_max > DWC_OTG_MAX_ENDPOINTS)<br>+        sc->sc_dev_ep_max = DWC_OTG_MAX_ENDPOINTS;<br>+<br>+    sc->sc_host_ch_max = GHWCFG2_NUMHSTCHNL_GET(temp);<br>+<br>+    if (sc->sc_host_ch_max > DWC_OTG_MAX_CHANNELS)<br>+        sc->sc_host_ch_max = DWC_OTG_MAX_CHANNELS;<br>+<br>+    temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG4);<br>+<br>+    sc->sc_dev_in_ep_max = GHWCFG4_NUM_IN_EP_GET(temp);<br>+<br>+    DPRINTF("Total FIFO size = %d bytes, Device EPs = %d/%d Host CHs = %d\n",<br>+        sc->sc_fifo_size, sc->sc_dev_ep_max, sc->sc_dev_in_ep_max,<br>+        sc->sc_host_ch_max);<br>+<br>+    /* setup FIFO */<br>+    if (dwc_otg_init_fifo(sc, sc->sc_mode)) {<br>+        USB_BUS_UNLOCK(&sc->sc_bus);<br>+        return (EINVAL);<br>+    }<br>+<br>+    /* enable interrupts */<br>+    sc->sc_irq_mask = DWC_OTG_MSK_GINT_ENABLED;<br>+    DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);<br>+<br>+    if (sc->sc_mode == DWC_MODE_OTG || sc->sc_mode == DWC_MODE_DEVICE) {<br>+<br>+        /* enable all endpoint interrupts */<br>+        temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG2);<br>+        if (temp & GHWCFG2_MPI) {<br>+            uint8_t x;<br>+<br>+            DPRINTF("Disable Multi Process Interrupts\n");<br>+<br>+            for (x = 0; x != sc->sc_dev_in_ep_max; x++) {<br>+                DWC_OTG_WRITE_4(sc, DOTG_DIEPEACHINTMSK(x), 0);<br>+                DWC_OTG_WRITE_4(sc, DOTG_DOEPEACHINTMSK(x), 0);<br>+            }<br>+            DWC_OTG_WRITE_4(sc, DOTG_DEACHINTMSK, 0);<br>+        }<br>+        DWC_OTG_WRITE_4(sc, DOTG_DIEPMSK,<br>+            DIEPMSK_XFERCOMPLMSK);<br>+        DWC_OTG_WRITE_4(sc, DOTG_DOEPMSK, 0);<br>+        DWC_OTG_WRITE_4(sc, DOTG_DAINTMSK, 0xFFFF);<br>+    }<br>+<br>+    if (sc->sc_mode == DWC_MODE_OTG || sc->sc_mode == DWC_MODE_HOST) {<br>+        /* setup clocks */<br>+        temp = DWC_OTG_READ_4(sc, DOTG_HCFG);<br>+        temp &= ~(HCFG_FSLSSUPP | HCFG_FSLSPCLKSEL_MASK);<br>+        temp |= (1 << HCFG_FSLSPCLKSEL_SHIFT);<br>+        DWC_OTG_WRITE_4(sc, DOTG_HCFG, temp);<br>+    }<br>+<br>+    /* only enable global IRQ */<br>+    DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG,<br>+        GAHBCFG_GLBLINTRMSK);<br>+<br>+    /* turn off clocks */<br>+    dwc_otg_clocks_off(sc);<br>+<br>+    /* read initial VBUS state */<br>+<br>+    temp = DWC_OTG_READ_4(sc, DOTG_GOTGCTL);<br>+<br>+    DPRINTFN(5, "GOTCTL=0x%08x\n", temp);<br>+<br>+    dwc_otg_vbus_interrupt(sc,<br>+        (temp & (GOTGCTL_ASESVLD | GOTGCTL_BSESVLD)) ? 1 : 0);<br>+<br>+    USB_BUS_UNLOCK(&sc->sc_bus);<br>+<br>+    /* catch any lost interrupts */<br>+<br>+    dwc_otg_do_poll(&sc->sc_bus);<br>+<br>+    return (0);            /* success */<br>+}<br>+<br>+void<br>+dwc_otg_uninit(struct dwc_otg_softc *sc)<br>+{<br>+    USB_BUS_LOCK(&sc->sc_bus);<br>+<br>+    /* stop host timer */<br>+    dwc_otg_timer_stop(sc);<br>+<br>+    /* set disconnect */<br>+    DWC_OTG_WRITE_4(sc, DOTG_DCTL,<br>+        DCTL_SFTDISCON);<br>+<br>+    /* turn off global IRQ */<br>+    DWC_OTG_WRITE_4(sc, DOTG_GAHBCFG, 0);<br>+<br>+    sc->sc_flags.port_enabled = 0;<br>+    sc->sc_flags.port_powered = 0;<br>+    sc->sc_flags.status_vbus = 0;<br>+    sc->sc_flags.status_bus_reset = 0;<br>+    sc->sc_flags.status_suspend = 0;<br>+    sc->sc_flags.change_suspend = 0;<br>+    sc->sc_flags.change_connect = 1;<br>+<br>+    dwc_otg_pull_down(sc);<br>+    dwc_otg_clocks_off(sc);<br>+<br>+    USB_BUS_UNLOCK(&sc->sc_bus);<br>+<br>+    usb_callout_drain(&sc->sc_timer);<br>+}<br>+<br>+static void<br>+dwc_otg_suspend(struct dwc_otg_softc *sc)<br>+{<br>+    return;<br>+}<br>+<br>+static void<br>+dwc_otg_resume(struct dwc_otg_softc *sc)<br>+{<br>+    return;<br>+}<br>+<br>+static void<br>+dwc_otg_do_poll(struct usb_bus *bus)<br>+{<br>+    struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(bus);<br>+<br>+    USB_BUS_LOCK(&sc->sc_bus);<br>+    USB_BUS_SPIN_LOCK(&sc->sc_bus);<br>+    dwc_otg_interrupt_poll_locked(sc);<br>+    dwc_otg_interrupt_complete_locked(sc);<br>+    if (sc->sc_flags.status_device_mode == 0) {<br>+        /* update host transfer schedule, so that new transfers can be issued */<br>+        if (dwc_otg_update_host_transfer_schedule_locked(sc))<br>+            dwc_otg_interrupt_poll_locked(sc);<br>+    }<br>+    USB_BUS_SPIN_UNLOCK(&sc->sc_bus);<br>+    USB_BUS_UNLOCK(&sc->sc_bus);<br>+}<br>+<br>+/*------------------------------------------------------------------------*<br>+ * DWC OTG bulk support<br>+ * DWC OTG control support<br>+ * DWC OTG interrupt support<br>+ *------------------------------------------------------------------------*/<br>+static void<br>+dwc_otg_device_non_isoc_open(struct usb_xfer *xfer)<br>+{<br>+}<br>+<br>+static void<br>+dwc_otg_device_non_isoc_close(struct usb_xfer *xfer)<br>+{<br>+    dwc_otg_device_done(xfer, USB_ERR_CANCELLED);<br>+}<br>+<br>+static void<br>+dwc_otg_device_non_isoc_enter(struct usb_xfer *xfer)<br>+{<br>+}<br>+<br>+static void<br>+dwc_otg_device_non_isoc_start(struct usb_xfer *xfer)<br>+{<br>+    /* setup TDs */<br>+    dwc_otg_setup_standard_chain(xfer);<br>+    dwc_otg_start_standard_chain(xfer);<br>+}<br>+<br>+struct usb_pipe_methods dwc_otg_device_non_isoc_methods =<br>+{<br>+    .open = dwc_otg_device_non_isoc_open,<br>+    .close = dwc_otg_device_non_isoc_close,<br>+    .enter = dwc_otg_device_non_isoc_enter,<br>+    .start = dwc_otg_device_non_isoc_start,<br>+};<br>+<br>+/*------------------------------------------------------------------------*<br>+ * DWC OTG full speed isochronous support<br>+ *------------------------------------------------------------------------*/<br>+static void<br>+dwc_otg_device_isoc_open(struct usb_xfer *xfer)<br>+{<br>+}<br>+<br>+static void<br>+dwc_otg_device_isoc_close(struct usb_xfer *xfer)<br>+{<br>+    dwc_otg_device_done(xfer, USB_ERR_CANCELLED);<br>+}<br>+<br>+static void<br>+dwc_otg_device_isoc_enter(struct usb_xfer *xfer)<br>+{<br>+}<br>+<br>+static void<br>+dwc_otg_device_isoc_start(struct usb_xfer *xfer)<br>+{<br>+    struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);<br>+    uint32_t temp;<br>+    uint32_t msframes;<br>+    uint32_t framenum;<br>+    uint8_t shift = usbd_xfer_get_fps_shift(xfer);<br>+<br>+    DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",<br>+        xfer, xfer->endpoint->isoc_next, xfer->nframes);<br>+<br>+    if (xfer->xroot->udev->flags.usb_mode == USB_MODE_HOST) {<br>+        temp = DWC_OTG_READ_4(sc, DOTG_HFNUM);<br>+<br>+        /* get the current frame index */<br>+        framenum = (temp & HFNUM_FRNUM_MASK);<br>+    } else {<br>+        temp = DWC_OTG_READ_4(sc, DOTG_DSTS);<br>+<br>+        /* get the current frame index */<br>+        framenum = DSTS_SOFFN_GET(temp);<br>+    }<br>+<br>+    if (xfer->xroot->udev->parent_hs_hub != NULL)<br>+        framenum /= 8;<br>+<br>+    framenum &= DWC_OTG_FRAME_MASK;<br>+<br>+    /*<br>+     * Compute number of milliseconds worth of data traffic for<br>+     * this USB transfer:<br>+     */ <br>+    if (xfer->xroot->udev->speed == USB_SPEED_HIGH)<br>+        msframes = ((xfer->nframes << shift) + 7) / 8;<br>+    else<br>+        msframes = xfer->nframes;<br>+<br>+    /*<br>+     * check if the frame index is within the window where the frames<br>+     * will be inserted<br>+     */<br>+    temp = (framenum - xfer->endpoint->isoc_next) & DWC_OTG_FRAME_MASK;<br>+<br>+    if ((xfer->endpoint->is_synced == 0) || (temp < msframes)) {<br>+        /*<br>+         * If there is data underflow or the pipe queue is<br>+         * empty we schedule the transfer a few frames ahead<br>+         * of the current frame position. Else two isochronous<br>+         * transfers might overlap.<br>+         */<br>+        xfer->endpoint->isoc_next = (framenum + 3) & DWC_OTG_FRAME_MASK;<br>+        xfer->endpoint->is_synced = 1;<br>+        DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);<br>+    }<br>+    /*<br>+     * compute how many milliseconds the insertion is ahead of the<br>+     * current frame position:<br>+     */<br>+    temp = (xfer->endpoint->isoc_next - framenum) & DWC_OTG_FRAME_MASK;<br>+<br>+    /*<br>+     * pre-compute when the isochronous transfer will be finished:<br>+     */<br>+    xfer->isoc_time_complete =<br>+        usb_isoc_time_expand(&sc->sc_bus, framenum) + temp + msframes;<br>+<br>+    /* setup TDs */<br>+    dwc_otg_setup_standard_chain(xfer);<br>+<br>+    /* compute frame number for next insertion */<br>+    xfer->endpoint->isoc_next += msframes;<br>+<br>+    /* start TD chain */<br>+    dwc_otg_start_standard_chain(xfer);<br>+}<br>+<br>+struct usb_pipe_methods dwc_otg_device_isoc_methods =<br>+{<br>+    .open = dwc_otg_device_isoc_open,<br>+    .close = dwc_otg_device_isoc_close,<br>+    .enter = dwc_otg_device_isoc_enter,<br>+    .start = dwc_otg_device_isoc_start,<br>+};<br>+<br>+/*------------------------------------------------------------------------*<br>+ * DWC OTG root control support<br>+ *------------------------------------------------------------------------*<br>+ * Simulate a hardware HUB by handling all the necessary requests.<br>+ *------------------------------------------------------------------------*/<br>+<br>+struct usb_device_descriptor dwc_otg_devd = {<br>+    .bLength = sizeof(struct usb_device_descriptor),<br>+    .bDescriptorType = UDESC_DEVICE,<br>+    .bcdUSB = {0x00, 0x02},<br>+    .bDeviceClass = UDCLASS_HUB,<br>+    .bDeviceSubClass = UDSUBCLASS_HUB,<br>+    .bDeviceProtocol = UDPROTO_HSHUBSTT,<br>+    .bMaxPacketSize = 64,<br>+    .bcdDevice = {0x00, 0x01},<br>+    .iManufacturer = 1,<br>+    .iProduct = 2,<br>+    .bNumConfigurations = 1,<br>+};<br>+<br>+struct dwc_otg_config_desc dwc_otg_confd = {<br>+    .confd = {<br>+        .bLength = sizeof(struct usb_config_descriptor),<br>+        .bDescriptorType = UDESC_CONFIG,<br>+        .wTotalLength[0] = sizeof(dwc_otg_confd),<br>+        .bNumInterface = 1,<br>+        .bConfigurationValue = 1,<br>+        .iConfiguration = 0,<br>+        .bmAttributes = UC_SELF_POWERED,<br>+        .bMaxPower = 0,<br>+    },<br>+    .ifcd = {<br>+        .bLength = sizeof(struct usb_interface_descriptor),<br>+        .bDescriptorType = UDESC_INTERFACE,<br>+        .bNumEndpoints = 1,<br>+        .bInterfaceClass = UICLASS_HUB,<br>+        .bInterfaceSubClass = UISUBCLASS_HUB,<br>+        .bInterfaceProtocol = 0,<br>+    },<br>+    .endpd = {<br>+        .bLength = sizeof(struct usb_endpoint_descriptor),<br>+        .bDescriptorType = UDESC_ENDPOINT,<br>+        .bEndpointAddress = (UE_DIR_IN | DWC_OTG_INTR_ENDPT),<br>+        .bmAttributes = UE_INTERRUPT,<br>+        .wMaxPacketSize[0] = 8,<br>+        .bInterval = 255,<br>+    },<br>+};<br>+<br>+#define    HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }<br>+<br>+struct usb_hub_descriptor_min dwc_otg_hubd = {<br>+    .bDescLength = sizeof(dwc_otg_hubd),<br>+    .bDescriptorType = UDESC_HUB,<br>+    .bNbrPorts = 1,<br>+    HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)),<br>+    .bPwrOn2PwrGood = 50,<br>+    .bHubContrCurrent = 0,<br>+    .DeviceRemovable = {0},        /* port is removable */<br>+};<br>+<br>+#define    STRING_VENDOR \<br>+  "D\0W\0C\0O\0T\0G"<br>+<br>+#define    STRING_PRODUCT \<br>+  "O\0T\0G\0 \0R\0o\0o\0t\0 \0H\0U\0B"<br>+<br>+USB_MAKE_STRING_DESC(STRING_VENDOR, dwc_otg_vendor);<br>+USB_MAKE_STRING_DESC(STRING_PRODUCT, dwc_otg_product);<br>+<br>+static usb_error_t<br>+dwc_otg_roothub_exec(struct usb_device *udev,<br>+    struct usb_device_request *req, const void **pptr, uint16_t *plength)<br>+{<br>+    struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(udev->bus);<br>+    const void *ptr;<br>+    uint16_t len;<br>+    uint16_t value;<br>+    uint16_t index;<br>+    usb_error_t err;<br>+<br>+    USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);<br>+<br>+    /* buffer reset */<br>+    ptr = (const void *)&sc->sc_hub_temp;<br>+    len = 0;<br>+    err = 0;<br>+<br>+    value = UGETW(req->wValue);<br>+    index = UGETW(req->wIndex);<br>+<br>+    /* demultiplex the control request */<br>+<br>+    switch (req->bmRequestType) {<br>+    case UT_READ_DEVICE:<br>+        switch (req->bRequest) {<br>+        case UR_GET_DESCRIPTOR:<br>+            goto tr_handle_get_descriptor;<br>+        case UR_GET_CONFIG:<br>+            goto tr_handle_get_config;<br>+        case UR_GET_STATUS:<br>+            goto tr_handle_get_status;<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_WRITE_DEVICE:<br>+        switch (req->bRequest) {<br>+        case UR_SET_ADDRESS:<br>+            goto tr_handle_set_address;<br>+        case UR_SET_CONFIG:<br>+            goto tr_handle_set_config;<br>+        case UR_CLEAR_FEATURE:<br>+            goto tr_valid;    /* nop */<br>+        case UR_SET_DESCRIPTOR:<br>+            goto tr_valid;    /* nop */<br>+        case UR_SET_FEATURE:<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_WRITE_ENDPOINT:<br>+        switch (req->bRequest) {<br>+        case UR_CLEAR_FEATURE:<br>+            switch (UGETW(req->wValue)) {<br>+            case UF_ENDPOINT_HALT:<br>+                goto tr_handle_clear_halt;<br>+            case UF_DEVICE_REMOTE_WAKEUP:<br>+                goto tr_handle_clear_wakeup;<br>+            default:<br>+                goto tr_stalled;<br>+            }<br>+            break;<br>+        case UR_SET_FEATURE:<br>+            switch (UGETW(req->wValue)) {<br>+            case UF_ENDPOINT_HALT:<br>+                goto tr_handle_set_halt;<br>+            case UF_DEVICE_REMOTE_WAKEUP:<br>+                goto tr_handle_set_wakeup;<br>+            default:<br>+                goto tr_stalled;<br>+            }<br>+            break;<br>+        case UR_SYNCH_FRAME:<br>+            goto tr_valid;    /* nop */<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_READ_ENDPOINT:<br>+        switch (req->bRequest) {<br>+        case UR_GET_STATUS:<br>+            goto tr_handle_get_ep_status;<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_WRITE_INTERFACE:<br>+        switch (req->bRequest) {<br>+        case UR_SET_INTERFACE:<br>+            goto tr_handle_set_interface;<br>+        case UR_CLEAR_FEATURE:<br>+            goto tr_valid;    /* nop */<br>+        case UR_SET_FEATURE:<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_READ_INTERFACE:<br>+        switch (req->bRequest) {<br>+        case UR_GET_INTERFACE:<br>+            goto tr_handle_get_interface;<br>+        case UR_GET_STATUS:<br>+            goto tr_handle_get_iface_status;<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_WRITE_CLASS_INTERFACE:<br>+    case UT_WRITE_VENDOR_INTERFACE:<br>+        /* XXX forward */<br>+        break;<br>+<br>+    case UT_READ_CLASS_INTERFACE:<br>+    case UT_READ_VENDOR_INTERFACE:<br>+        /* XXX forward */<br>+        break;<br>+<br>+    case UT_WRITE_CLASS_DEVICE:<br>+        switch (req->bRequest) {<br>+        case UR_CLEAR_FEATURE:<br>+            goto tr_valid;<br>+        case UR_SET_DESCRIPTOR:<br>+        case UR_SET_FEATURE:<br>+            break;<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_WRITE_CLASS_OTHER:<br>+        switch (req->bRequest) {<br>+        case UR_CLEAR_FEATURE:<br>+            goto tr_handle_clear_port_feature;<br>+        case UR_SET_FEATURE:<br>+            goto tr_handle_set_port_feature;<br>+        case UR_CLEAR_TT_BUFFER:<br>+        case UR_RESET_TT:<br>+        case UR_STOP_TT:<br>+            goto tr_valid;<br>+<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_READ_CLASS_OTHER:<br>+        switch (req->bRequest) {<br>+        case UR_GET_TT_STATE:<br>+            goto tr_handle_get_tt_state;<br>+        case UR_GET_STATUS:<br>+            goto tr_handle_get_port_status;<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+<br>+    case UT_READ_CLASS_DEVICE:<br>+        switch (req->bRequest) {<br>+        case UR_GET_DESCRIPTOR:<br>+            goto tr_handle_get_class_descriptor;<br>+        case UR_GET_STATUS:<br>+            goto tr_handle_get_class_status;<br>+<br>+        default:<br>+            goto tr_stalled;<br>+        }<br>+        break;<br>+    default:<br>+        goto tr_stalled;<br>+    }<br>+    goto tr_valid;<br>+<br>+tr_handle_get_descriptor:<br>+    switch (value >> 8) {<br>+    case UDESC_DEVICE:<br>+        if (value & 0xff) {<br>+            goto tr_stalled;<br>+        }<br>+        len = sizeof(dwc_otg_devd);<br>+        ptr = (const void *)&dwc_otg_devd;<br>+        goto tr_valid;<br>+    case UDESC_CONFIG:<br>+        if (value & 0xff) {<br>+            goto tr_stalled;<br>+        }<br>+        len = sizeof(dwc_otg_confd);<br>+        ptr = (const void *)&dwc_otg_confd;<br>+        goto tr_valid;<br>+    case UDESC_STRING:<br>+        switch (value & 0xff) {<br>+        case 0:        /* Language table */<br>+            len = sizeof(usb_string_lang_en);<br>+            ptr = (const void *)&usb_string_lang_en;<br>+            goto tr_valid;<br>+<br>+        case 1:        /* Vendor */<br>+            len = sizeof(dwc_otg_vendor);<br>+            ptr = (const void *)&dwc_otg_vendor;<br>+            goto tr_valid;<br>+<br>+        case 2:        /* Product */<br>+            len = sizeof(dwc_otg_product);<br>+            ptr = (const void *)&dwc_otg_product;<br>+            goto tr_valid;<br>+        default:<br>+            break;<br>+        }<br>+        break;<br>+    default:<br>+        goto tr_stalled;<br>+    }<br>+    goto tr_stalled;<br>+<br>+tr_handle_get_config:<br>+    len = 1;<br>+    sc->sc_hub_temp.wValue[0] = sc->sc_conf;<br>+    goto tr_valid;<br>+<br>+tr_handle_get_status:<br>+    len = 2;<br>+    USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);<br>+    goto tr_valid;<br>+<br>+tr_handle_set_address:<br>+    if (value & 0xFF00) {<br>+        goto tr_stalled;<br>+    }<br>+    sc->sc_rt_addr = value;<br>+    goto tr_valid;<br>+<br>+tr_handle_set_config:<br>+    if (value >= 2) {<br>+        goto tr_stalled;<br>+    }<br>+    sc->sc_conf = value;<br>+    goto tr_valid;<br>+<br>+tr_handle_get_interface:<br>+    len = 1;<br>+    sc->sc_hub_temp.wValue[0] = 0;<br>+    goto tr_valid;<br>+<br>+tr_handle_get_tt_state:<br>+tr_handle_get_class_status:<br>+tr_handle_get_iface_status:<br>+tr_handle_get_ep_status:<br>+    len = 2;<br>+    USETW(sc->sc_hub_temp.wValue, 0);<br>+    goto tr_valid;<br>+<br>+tr_handle_set_halt:<br>+tr_handle_set_interface:<br>+tr_handle_set_wakeup:<br>+tr_handle_clear_wakeup:<br>+tr_handle_clear_halt:<br>+    goto tr_valid;<br>+<br>+tr_handle_clear_port_feature:<br>+    if (index != 1)<br>+        goto tr_stalled;<br>+<br>+    DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);<br>+<br>+    switch (value) {<br>+    case UHF_PORT_SUSPEND:<br>+        dwc_otg_wakeup_peer(sc);<br>+        break;<br>+<br>+    case UHF_PORT_ENABLE:<br>+        if (sc->sc_flags.status_device_mode == 0) {<br>+            DWC_OTG_WRITE_4(sc, DOTG_HPRT,<br>+                sc->sc_hprt_val | HPRT_PRTENA);<br>+        }<br>+        sc->sc_flags.port_enabled = 0;<br>+        break;<br>+<br>+    case UHF_C_PORT_RESET:<br>+        sc->sc_flags.change_reset = 0;<br>+        break;<br>+<br>+    case UHF_C_PORT_ENABLE:<br>+        sc->sc_flags.change_enabled = 0;<br>+        break;<br>+<br>+    case UHF_C_PORT_OVER_CURRENT:<br>+        sc->sc_flags.change_over_current = 0;<br>+        break;<br>+<br>+    case UHF_PORT_TEST:<br>+    case UHF_PORT_INDICATOR:<br>+        /* nops */<br>+        break;<br>+<br>+    case UHF_PORT_POWER:<br>+        sc->sc_flags.port_powered = 0;<br>+        if (sc->sc_mode == DWC_MODE_HOST || sc->sc_mode == DWC_MODE_OTG) {<br>+            sc->sc_hprt_val = 0;<br>+            DWC_OTG_WRITE_4(sc, DOTG_HPRT, HPRT_PRTENA);<br>+        }<br>+        dwc_otg_pull_down(sc);<br>+        dwc_otg_clocks_off(sc);<br>+        break;<br>+<br>+    case UHF_C_PORT_CONNECTION:<br>+        /* clear connect change flag */<br>+        sc->sc_flags.change_connect = 0;<br>+        break;<br>+<br>+    case UHF_C_PORT_SUSPEND:<br>+        sc->sc_flags.change_suspend = 0;<br>+        break;<br>+<br>+    default:<br>+        err = USB_ERR_IOERROR;<br>+        goto done;<br>+    }<br>+    goto tr_valid;<br>+<br>+tr_handle_set_port_feature:<br>+    if (index != 1) {<br>+        goto tr_stalled;<br>+    }<br>+    DPRINTFN(9, "UR_SET_PORT_FEATURE\n");<br>+<br>+    switch (value) {<br>+    case UHF_PORT_ENABLE:<br>+        break;<br>+<br>+    case UHF_PORT_SUSPEND:<br>+        if (sc->sc_flags.status_device_mode == 0) {<br>+            /* set suspend BIT */<br>+            sc->sc_hprt_val |= HPRT_PRTSUSP;<br>+            DWC_OTG_WRITE_4(sc, DOTG_HPRT, sc->sc_hprt_val);<br>+<br>+            /* generate HUB suspend event */<br>+            dwc_otg_suspend_irq(sc);<br>+        }<br>+        break;<br>+<br>+    case UHF_PORT_RESET:<br>+        if (sc->sc_flags.status_device_mode == 0) {<br>+<br>+            DPRINTF("PORT RESET\n");<br>+<br>+            /* enable PORT reset */<br>+            DWC_OTG_WRITE_4(sc, DOTG_HPRT, sc->sc_hprt_val | HPRT_PRTRST);<br>+<br>+            /* Wait 62.5ms for reset to complete */<br>+            usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 16);<br>+<br>+            DWC_OTG_WRITE_4(sc, DOTG_HPRT, sc->sc_hprt_val);<br>+<br>+            /* Wait 62.5ms for reset to complete */<br>+            usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 16);<br>+<br>+            /* reset FIFOs */<br>+            (void) dwc_otg_init_fifo(sc, DWC_MODE_HOST);<br>+<br>+            sc->sc_flags.change_reset = 1;<br>+        } else {<br>+            err = USB_ERR_IOERROR;<br>+        }<br>+        break;<br>+<br>+    case UHF_PORT_TEST:<br>+    case UHF_PORT_INDICATOR:<br>+        /* nops */<br>+        break;<br>+    case UHF_PORT_POWER:<br>+        sc->sc_flags.port_powered = 1;<br>+        if (sc->sc_mode == DWC_MODE_HOST || sc->sc_mode == DWC_MODE_OTG) {<br>+            sc->sc_hprt_val |= HPRT_PRTPWR;<br>+            DWC_OTG_WRITE_4(sc, DOTG_HPRT, sc->sc_hprt_val);<br>+        }<br>+        if (sc->sc_mode == DWC_MODE_DEVICE || sc->sc_mode == DWC_MODE_OTG) {<br>+            /* pull up D+, if any */<br>+            dwc_otg_pull_up(sc);<br>+        }<br>+        break;<br>+    default:<br>+        err = USB_ERR_IOERROR;<br>+        goto done;<br>+    }<br>+    goto tr_valid;<br>+<br>+tr_handle_get_port_status:<br>+<br>+    DPRINTFN(9, "UR_GET_PORT_STATUS\n");<br>+<br>+    if (index != 1)<br>+        goto tr_stalled;<br>+<br>+    if (sc->sc_flags.status_vbus)<br>+        dwc_otg_clocks_on(sc);<br>+    else<br>+        dwc_otg_clocks_off(sc);<br>+<br>+    /* Select Device Side Mode */<br>+<br>+    if (sc->sc_flags.status_device_mode) {<br>+        value = UPS_PORT_MODE_DEVICE;<br>+        dwc_otg_timer_stop(sc);<br>+    } else {<br>+        value = 0;<br>+        dwc_otg_timer_start(sc);<br>+    }<br>+<br>+    if (sc->sc_flags.status_high_speed)<br>+        value |= UPS_HIGH_SPEED;<br>+    else if (sc->sc_flags.status_low_speed)<br>+        value |= UPS_LOW_SPEED;<br>+<br>+    if (sc->sc_flags.port_powered)<br>+        value |= UPS_PORT_POWER;<br>+<br>+    if (sc->sc_flags.port_enabled)<br>+        value |= UPS_PORT_ENABLED;<br>+<br>+    if (sc->sc_flags.port_over_current)<br>+        value |= UPS_OVERCURRENT_INDICATOR;<br>+<br>+    if (sc->sc_flags.status_vbus &&<br>+        sc->sc_flags.status_bus_reset)<br>+        value |= UPS_CURRENT_CONNECT_STATUS;<br>+<br>+    if (sc->sc_flags.status_suspend)<br>+        value |= UPS_SUSPEND;<br>+<br>+    USETW(sc->sc_hub_temp.ps.wPortStatus, value);<br>+<br>+    value = 0;<br>+<br>+    if (sc->sc_flags.change_connect)<br>+        value |= UPS_C_CONNECT_STATUS;<br>+    if (sc->sc_flags.change_suspend)<br>+        value |= UPS_C_SUSPEND;<br>+    if (sc->sc_flags.change_reset)<br>+        value |= UPS_C_PORT_RESET;<br>+    if (sc->sc_flags.change_over_current)<br>+        value |= UPS_C_OVERCURRENT_INDICATOR;<br>+<br>+    USETW(sc->sc_hub_temp.ps.wPortChange, value);<br>+    len = sizeof(sc-><a href="http://sc_hub_temp.ps">sc_hub_temp.ps</a>);<br>+    goto tr_valid;<br>+<br>+tr_handle_get_class_descriptor:<br>+    if (value & 0xFF) {<br>+        goto tr_stalled;<br>+    }<br>+    ptr = (const void *)&dwc_otg_hubd;<br>+    len = sizeof(dwc_otg_hubd);<br>+    goto tr_valid;<br>+<br>+tr_stalled:<br>+    err = USB_ERR_STALLED;<br>+tr_valid:<br>+done:<br>+    *plength = len;<br>+    *pptr = ptr;<br>+    return (err);<br>+}<br>+<br>+static void<br>+dwc_otg_xfer_setup(struct usb_setup_params *parm)<br>+{<br>+    struct usb_xfer *xfer;<br>+    void *last_obj;<br>+    uint32_t ntd;<br>+    uint32_t n;<br>+    uint8_t ep_no;<br>+    uint8_t ep_type;<br>+<br>+    xfer = parm->curr_xfer;<br>+<br>+    /*<br>+     * NOTE: This driver does not use any of the parameters that<br>+     * are computed from the following values. Just set some<br>+     * reasonable dummies:<br>+     */<br>+    parm->hc_max_packet_size = 0x500;<br>+    parm->hc_max_packet_count = 3;<br>+    parm->hc_max_frame_size = 3 * 0x500;<br>+<br>+    usbd_transfer_setup_sub(parm);<br>+<br>+    /*<br>+     * compute maximum number of TDs<br>+     */<br>+    ep_type = (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE);<br>+<br>+    if (ep_type == UE_CONTROL) {<br>+<br>+        ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */<br>+            + 1 /* SYNC 2 */ + 1 /* SYNC 3 */;<br>+    } else {<br>+<br>+        ntd = xfer->nframes + 1 /* SYNC */ ;<br>+    }<br>+<br>+    /*<br>+     * check if "usbd_transfer_setup_sub" set an error<br>+     */<br>+    if (parm->err)<br>+        return;<br>+<br>+    /*<br>+     * allocate transfer descriptors<br>+     */<br>+    last_obj = NULL;<br>+<br>+    ep_no = xfer->endpointno & UE_ADDR;<br>+<br>+    /*<br>+     * Check for a valid endpoint profile in USB device mode:<br>+     */<br>+    if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {<br>+        const struct usb_hw_ep_profile *pf;<br>+<br>+        dwc_otg_get_hw_ep_profile(parm->udev, &pf, ep_no);<br>+<br>+        if (pf == NULL) {<br>+            /* should not happen */<br>+            parm->err = USB_ERR_INVAL;<br>+            return;<br>+        }<br>+    }<br>+<br>+    /* align data */<br>+    parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));<br>+<br>+    for (n = 0; n != ntd; n++) {<br>+<br>+        struct dwc_otg_td *td;<br>+<br>+        if (parm->buf) {<br>+<br>+            td = USB_ADD_BYTES(parm->buf, parm->size[0]);<br>+<br>+            /* compute shared bandwidth resource index for TT */<br>+            if (parm->udev->parent_hs_hub != NULL && parm->udev->speed != USB_SPEED_HIGH) {<br>+                if (parm->udev->parent_hs_hub->ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT)<br>+                    td->tt_index = parm->udev->device_index;<br>+                else<br>+                    td->tt_index = parm->udev->parent_hs_hub->device_index;<br>+            } else {<br>+                td->tt_index = parm->udev->device_index;<br>+            }<br>+<br>+            /* init TD */<br>+            td->max_packet_size = xfer->max_packet_size;<br>+            td->max_packet_count = xfer->max_packet_count;<br>+            td->ep_no = ep_no;<br>+            td->ep_type = ep_type;<br>+            td->obj_next = last_obj;<br>+<br>+            last_obj = td;<br>+        }<br>+        parm->size[0] += sizeof(*td);<br>+    }<br>+<br>+    xfer->td_start[0] = last_obj;<br>+}<br>+<br>+static void<br>+dwc_otg_xfer_unsetup(struct usb_xfer *xfer)<br>+{<br>+    return;<br>+}<br>+<br>+static void<br>+dwc_otg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,<br>+    struct usb_endpoint *ep)<br>+{<br>+    struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(udev->bus);<br>+<br>+    DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d,%d)\n",<br>+        ep, udev->address,<br>+        edesc->bEndpointAddress, udev->flags.usb_mode,<br>+        sc->sc_rt_addr, udev->device_index);<br>+<br>+    if (udev->device_index != sc->sc_rt_addr) {<br>+<br>+        if (udev->flags.usb_mode == USB_MODE_DEVICE) {<br>+            if (udev->speed != USB_SPEED_FULL &&<br>+                udev->speed != USB_SPEED_HIGH) {<br>+                /* not supported */<br>+                return;<br>+            }<br>+        } else {<br>+            if (udev->speed == USB_SPEED_HIGH) {<br>+                if ((UGETW(edesc->wMaxPacketSize) >> 11) & 3) {<br>+                    /* high bandwidth endpoint - not tested */<br>+                    DPRINTF("High Bandwidth Endpoint - not tested\n");<br>+                    return;<br>+                }<br>+            }<br>+        }<br>+        if ((edesc->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)<br>+            ep->methods = &dwc_otg_device_isoc_methods;<br>+        else<br>+            ep->methods = &dwc_otg_device_non_isoc_methods;<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)<br>+{<br>+    struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(bus);<br>+<br>+    switch (state) {<br>+    case USB_HW_POWER_SUSPEND:<br>+        dwc_otg_suspend(sc);<br>+        break;<br>+    case USB_HW_POWER_SHUTDOWN:<br>+        dwc_otg_uninit(sc);<br>+        break;<br>+    case USB_HW_POWER_RESUME:<br>+        dwc_otg_resume(sc);<br>+        break;<br>+    default:<br>+        break;<br>+    }<br>+}<br>+<br>+static void<br>+dwc_otg_get_dma_delay(struct usb_device *udev, uint32_t *pus)<br>+{<br>+    /* DMA delay - wait until any use of memory is finished */<br>+    *pus = (2125);            /* microseconds */<br>+}<br>+<br>+static void<br>+dwc_otg_device_resume(struct usb_device *udev)<br>+{<br>+    DPRINTF("\n");<br>+<br>+    /* poll all transfers again to restart resumed ones */<br>+    dwc_otg_do_poll(udev->bus);<br>+}<br>+<br>+static void<br>+dwc_otg_device_suspend(struct usb_device *udev)<br>+{<br>+    DPRINTF("\n");<br>+}<br>+<br>+struct usb_bus_methods dwc_otg_bus_methods =<br>+{<br>+    .endpoint_init = &dwc_otg_ep_init,<br>+    .xfer_setup = &dwc_otg_xfer_setup,<br>+    .xfer_unsetup = &dwc_otg_xfer_unsetup,<br>+    .get_hw_ep_profile = &dwc_otg_get_hw_ep_profile,<br>+    #ifndef __rtems__<br>+    .xfer_stall = &dwc_otg_xfer_stall,<br>+    #endif<br>+    .set_stall = &dwc_otg_set_stall,<br>+    .clear_stall = &dwc_otg_clear_stall,<br>+    .roothub_exec = &dwc_otg_roothub_exec,<br>+    .xfer_poll = &dwc_otg_do_poll,<br>+    .device_state_change = &dwc_otg_device_state_change,<br>+    .set_hw_power_sleep = &dwc_otg_set_hw_power_sleep,<br>+    .get_dma_delay = &dwc_otg_get_dma_delay,<br>+    .device_resume = &dwc_otg_device_resume,<br>+    .device_suspend = &dwc_otg_device_suspend,<br>+};<br>diff --git a/freebsd/sys/dev/usb/controller/dwc_otg.h b/freebsd/sys/dev/usb/controller/dwc_otg.h<br>new file mode 100755<br>index 0000000..52b3b91<br>--- /dev/null<br>+++ b/freebsd/sys/dev/usb/controller/dwc_otg.h<br>@@ -0,0 +1,223 @@<br>+/* $FreeBSD$ */<br>+/*-<br>+ * Copyright (c) 2012 Hans Petter Selasky. All rights reserved.<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>+ * SUCH DAMAGE.<br>+ */<br>+<br>+#ifndef _DWC_OTG_H_<br>+#define    _DWC_OTG_H_<br>+<br>+#define    DWC_OTG_MAX_DEVICES MIN(USB_MAX_DEVICES, 32)<br>+#define    DWC_OTG_FRAME_MASK 0x7FF<br>+#define    DWC_OTG_MAX_TXP 4<br>+#define    DWC_OTG_MAX_TXN (0x200 * DWC_OTG_MAX_TXP)<br>+#define    DWC_OTG_MAX_CHANNELS 16<br>+#define    DWC_OTG_MAX_ENDPOINTS 16<br>+#define    DWC_OTG_HOST_TIMER_RATE 10 /* ms */<br>+#define    DWC_OTG_TT_SLOT_MAX 8<br>+#define    DWC_OTG_SLOT_IDLE_MAX 3<br>+#define    DWC_OTG_SLOT_IDLE_MIN 2<br>+#define    DWC_OTG_NAK_MAX 8    /* 1 ms */<br>+#ifndef DWC_OTG_TX_MAX_FIFO_SIZE<br>+#define    DWC_OTG_TX_MAX_FIFO_SIZE DWC_OTG_MAX_TXN<br>+#endif<br>+<br>+#define    DWC_OTG_READ_4(sc, reg) \<br>+  bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)<br>+<br>+#define    DWC_OTG_WRITE_4(sc, reg, data)    \<br>+  bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data)<br>+<br>+struct dwc_otg_td;<br>+struct dwc_otg_softc;<br>+<br>+typedef uint8_t (dwc_otg_cmd_t)(struct dwc_otg_softc *sc, struct dwc_otg_td *td);<br>+<br>+struct dwc_otg_td {<br>+    struct dwc_otg_td *obj_next;<br>+    dwc_otg_cmd_t *func;<br>+    struct usb_page_cache *pc;<br>+    uint32_t tx_bytes;<br>+    uint32_t offset;<br>+    uint32_t remainder;<br>+    uint32_t hcchar;        /* HOST CFG */<br>+    uint32_t hcsplt;        /* HOST CFG */<br>+    uint16_t max_packet_size;    /* packet_size */<br>+    uint16_t npkt;<br>+    uint8_t max_packet_count;    /* packet_count */<br>+    uint8_t errcnt;<br>+    uint8_t tmr_res;<br>+    uint8_t tmr_val;<br>+    uint8_t did_nak;        /* NAK counter */<br>+    uint8_t    ep_no;<br>+    uint8_t ep_type;<br>+    uint8_t channel;<br>+    uint8_t tt_index;        /* TT data */<br>+    uint8_t tt_start_slot;        /* TT data */<br>+    uint8_t tt_complete_slot;    /* TT data */<br>+    uint8_t tt_xactpos;        /* TT data */<br>+    uint8_t state;<br>+#define    DWC_CHAN_ST_START 0<br>+#define    DWC_CHAN_ST_WAIT_ANE 1<br>+#define    DWC_CHAN_ST_WAIT_S_ANE 2<br>+#define    DWC_CHAN_ST_WAIT_C_ANE 3<br>+#define    DWC_CHAN_ST_WAIT_C_PKT 4<br>+#define    DWC_CHAN_ST_TX_PKT_ISOC 5<br>+#define    DWC_CHAN_ST_TX_WAIT_ISOC 6<br>+    uint8_t    error_any:1;<br>+    uint8_t    error_stall:1;<br>+    uint8_t    alt_next:1;<br>+    uint8_t    short_pkt:1;<br>+    uint8_t    did_stall:1;<br>+    uint8_t toggle:1;<br>+    uint8_t set_toggle:1;<br>+    uint8_t got_short:1;<br>+    uint8_t tt_scheduled:1;<br>+};<br>+<br>+struct dwc_otg_tt_info {<br>+    uint8_t slot_index;<br>+};<br>+<br>+struct dwc_otg_std_temp {<br>+    dwc_otg_cmd_t *func;<br>+    struct usb_page_cache *pc;<br>+    struct dwc_otg_td *td;<br>+    struct dwc_otg_td *td_next;<br>+    uint32_t len;<br>+    uint32_t offset;<br>+    uint16_t max_frame_size;<br>+    uint8_t    short_pkt;<br>+<br>+    /*<br>+     * short_pkt = 0: transfer should be short terminated<br>+     * short_pkt = 1: transfer should not be short terminated<br>+     */<br>+    uint8_t    setup_alt_next;<br>+    uint8_t did_stall;<br>+    uint8_t bulk_or_control;<br>+};<br>+<br>+struct dwc_otg_config_desc {<br>+    struct usb_config_descriptor confd;<br>+    struct usb_interface_descriptor ifcd;<br>+    struct usb_endpoint_descriptor endpd;<br>+} __packed;<br>+<br>+union dwc_otg_hub_temp {<br>+    uWord    wValue;<br>+    struct usb_port_status ps;<br>+};<br>+<br>+struct dwc_otg_flags {<br>+    uint8_t    change_connect:1;<br>+    uint8_t    change_suspend:1;<br>+    uint8_t change_reset:1;<br>+    uint8_t change_enabled:1;<br>+    uint8_t change_over_current:1;<br>+    uint8_t    status_suspend:1;    /* set if suspended */<br>+    uint8_t    status_vbus:1;        /* set if present */<br>+    uint8_t    status_bus_reset:1;    /* set if reset complete */<br>+    uint8_t    status_high_speed:1;    /* set if High Speed is selected */<br>+    uint8_t    status_low_speed:1;    /* set if Low Speed is selected */<br>+    uint8_t status_device_mode:1;    /* set if device mode */<br>+    uint8_t    self_powered:1;<br>+    uint8_t    clocks_off:1;<br>+    uint8_t    port_powered:1;<br>+    uint8_t    port_enabled:1;<br>+    uint8_t port_over_current:1;<br>+    uint8_t    d_pulled_up:1;<br>+};<br>+<br>+struct dwc_otg_profile {<br>+    struct usb_hw_ep_profile usb;<br>+    uint16_t max_buffer;<br>+};<br>+<br>+struct dwc_otg_chan_state {<br>+    uint16_t allocated;<br>+    uint16_t wait_sof;<br>+    uint32_t hcint;<br>+    uint16_t tx_p_size;    /* periodic */<br>+    uint16_t tx_np_size;    /* non-periodic */<br>+};<br>+<br>+struct dwc_otg_softc {<br>+    struct usb_bus sc_bus;<br>+    union dwc_otg_hub_temp sc_hub_temp;<br>+    struct dwc_otg_profile sc_hw_ep_profile[DWC_OTG_MAX_ENDPOINTS];<br>+    struct dwc_otg_tt_info sc_tt_info[DWC_OTG_MAX_DEVICES];<br>+    struct usb_callout sc_timer;<br>+<br>+    struct usb_device *sc_devices[DWC_OTG_MAX_DEVICES];<br>+    struct resource *sc_io_res;<br>+    struct resource *sc_irq_res;<br>+    void   *sc_intr_hdl;<br>+    bus_size_t sc_io_size;<br>+    bus_space_tag_t sc_io_tag;<br>+    bus_space_handle_t sc_io_hdl;<br>+<br>+    uint32_t sc_rx_bounce_buffer[1024 / 4];<br>+    uint32_t sc_tx_bounce_buffer[MAX(512 * DWC_OTG_MAX_TXP, 1024) / 4];<br>+<br>+    uint32_t sc_fifo_size;<br>+    uint32_t sc_tx_max_size;<br>+    uint32_t sc_tx_cur_p_level;    /* periodic */<br>+    uint32_t sc_tx_cur_np_level;    /* non-periodic */<br>+    uint32_t sc_irq_mask;<br>+    uint32_t sc_last_rx_status;<br>+    uint32_t sc_out_ctl[DWC_OTG_MAX_ENDPOINTS];<br>+    uint32_t sc_in_ctl[DWC_OTG_MAX_ENDPOINTS];<br>+    struct dwc_otg_chan_state sc_chan_state[DWC_OTG_MAX_CHANNELS];<br>+    uint32_t sc_tmr_val;<br>+    uint32_t sc_hprt_val;<br>+    uint32_t sc_xfer_complete;<br>+<br>+    uint16_t sc_active_rx_ep;<br>+    uint16_t sc_last_frame_num;<br>+<br>+    uint8_t sc_timer_active;<br>+    uint8_t    sc_dev_ep_max;<br>+    uint8_t sc_dev_in_ep_max;<br>+    uint8_t    sc_host_ch_max;<br>+    uint8_t sc_needsof;<br>+    uint8_t    sc_rt_addr;        /* root HUB address */<br>+    uint8_t    sc_conf;        /* root HUB config */<br>+    uint8_t sc_mode;        /* mode of operation */<br>+#define    DWC_MODE_OTG 0        /* both modes */<br>+#define    DWC_MODE_DEVICE 1    /* device only */<br>+#define    DWC_MODE_HOST  2    /* host only */<br>+<br>+    uint8_t    sc_hub_idata[1];<br>+<br>+    struct dwc_otg_flags sc_flags;<br>+};<br>+<br>+/* prototypes */<br>+<br>+driver_filter_t dwc_otg_filter_interrupt;<br>+driver_intr_t dwc_otg_interrupt;<br>+int dwc_otg_init(struct dwc_otg_softc *);<br>+void dwc_otg_uninit(struct dwc_otg_softc *);<br>+<br>+#endif        /* _DWC_OTG_H_ */<br>diff --git a/freebsd/sys/dev/usb/controller/dwc_otg_fdt.c b/freebsd/sys/dev/usb/controller/dwc_otg_fdt.c<br>new file mode 100644<br>index 0000000..1ebb6f0<br>--- /dev/null<br>+++ b/freebsd/sys/dev/usb/controller/dwc_otg_fdt.c<br>@@ -0,0 +1,235 @@<br>+#include <machine/rtems-bsd-kernel-space.h><br>+/*-<br>+ * Copyright (c) 2012 Hans Petter Selasky. All rights reserved.<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>+ * SUCH DAMAGE.<br>+ */<br>+<br>+#include <sys/cdefs.h><br>+__FBSDID("$FreeBSD$");<br>+<br>+#include <rtems/bsd/sys/param.h><br>+#include <sys/systm.h><br>+#include <sys/bus.h><br>+#include <sys/condvar.h><br>+#include <sys/kernel.h><br>+#include <rtems/bsd/sys/lock.h><br>+#include <sys/malloc.h><br>+#include <sys/module.h><br>+#include <sys/mutex.h><br>+#include <sys/rman.h><br>+<br>+#ifndef __rtems__<br>+#include <dev/ofw/openfirm.h><br>+#include <dev/ofw/ofw_bus.h><br>+#include <dev/ofw/ofw_bus_subr.h><br>+#endif<br>+<br>+#include <dev/usb/usb.h><br>+#include <dev/usb/usbdi.h><br>+<br>+#include <dev/usb/usb_core.h><br>+#include <dev/usb/usb_busdma.h><br>+#include <dev/usb/usb_process.h><br>+#include <dev/usb/usb_util.h><br>+<br>+#include <dev/usb/usb_controller.h><br>+#include <dev/usb/usb_bus.h><br>+<br>+#include <dev/usb/controller/dwc_otg.h><br>+#include <dev/usb/controller/dwc_otg_fdt.h><br>+<br>+static device_probe_t dwc_otg_probe;<br>+static device_detach_t dwc_otg_detach;<br>+<br>+static int<br>+dwc_otg_probe(device_t dev)<br>+{<br>+<br>+    #ifndef __rtems__<br>+    if (!ofw_bus_status_okay(dev))<br>+        return (ENXIO);<br>+<br>+    if (!ofw_bus_is_compatible(dev, "synopsys,designware-hs-otg2"))<br>+        return (ENXIO);<br>+    #endif<br>+    <br>+    device_set_desc(dev, "DWC OTG 2.0 integrated USB controller");<br>+<br>+    return (BUS_PROBE_DEFAULT);<br>+}<br>+<br>+int<br>+dwc_otg_attach(device_t dev)<br>+{<br>+    struct dwc_otg_fdt_softc *sc = device_get_softc(dev);<br>+    char usb_mode[24];<br>+    int err;<br>+    int rid;<br>+<br>+    /* initialise some bus fields */<br>+    sc->sc_otg.sc_bus.parent = dev;<br>+    sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;<br>+    sc->sc_otg.sc_bus.devices_max = DWC_OTG_MAX_DEVICES;<br>+    #ifndef __rtems__<br>+    sc->sc_otg.sc_bus.dma_bits = 32;<br>+    #endif<br>+    <br>+    #ifndef __rtems__<br>+    /* get USB mode, if any */<br>+    if (OF_getprop(ofw_bus_get_node(dev), "dr_mode",<br>+        &usb_mode, sizeof(usb_mode)) > 0) {<br>+<br>+        /* ensure proper zero termination */<br>+        usb_mode[sizeof(usb_mode) - 1] = 0;<br>+<br>+        if (strcasecmp(usb_mode, "host") == 0)<br>+            sc->sc_otg.sc_mode = DWC_MODE_HOST;<br>+        else if (strcasecmp(usb_mode, "peripheral") == 0)<br>+            sc->sc_otg.sc_mode = DWC_MODE_DEVICE;<br>+        else if (strcasecmp(usb_mode, "otg") != 0) {<br>+            device_printf(dev, "Invalid FDT dr_mode: %s\n",<br>+                usb_mode);<br>+        }<br>+    }<br>+    #else<br>+    sc->sc_otg.sc_mode = DWC_MODE_HOST;<br>+    #endif<br>+<br>+    /* get all DMA memory */<br>+    if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus,<br>+        USB_GET_DMA_TAG(dev), NULL)) {<br>+        return (ENOMEM);<br>+    }<br>+    rid = 0;<br>+    sc->sc_otg.sc_io_res =<br>+        bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);<br>+<br>+    if (!(sc->sc_otg.sc_io_res)) {<br>+        err = ENOMEM;<br>+        goto error;<br>+    }<br>+    sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);<br>+    sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);<br>+    sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res);<br>+<br>+    rid = 0;<br>+    sc->sc_otg.sc_irq_res =<br>+        bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);<br>+    if (sc->sc_otg.sc_irq_res == NULL)<br>+        goto error;<br>+<br>+    sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);<br>+    if (sc->sc_otg.sc_bus.bdev == NULL)<br>+        goto error;<br>+<br>+    device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);<br>+<br>+    err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE,<br>+        &dwc_otg_filter_interrupt, &dwc_otg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);<br>+    if (err) {<br>+        sc->sc_otg.sc_intr_hdl = NULL;<br>+        goto error;<br>+    }<br>+    err = dwc_otg_init(&sc->sc_otg);<br>+    if (err == 0) {<br>+        err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);<br>+    }<br>+    if (err)<br>+        goto error;<br>+<br>+<br>+    return (0);<br>+<br>+error:<br>+    dwc_otg_detach(dev);<br>+    return (ENXIO);<br>+}<br>+<br>+static int<br>+dwc_otg_detach(device_t dev)<br>+{<br>+    struct dwc_otg_fdt_softc *sc = device_get_softc(dev);<br>+    device_t bdev;<br>+    int err;<br>+<br>+    if (sc->sc_otg.sc_bus.bdev) {<br>+        bdev = sc->sc_otg.sc_bus.bdev;<br>+        device_detach(bdev);<br>+        device_delete_child(dev, bdev);<br>+    }<br>+    /* during module unload there are lots of children leftover */<br>+    device_delete_children(dev);<br>+<br>+    if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {<br>+        /*<br>+         * only call dwc_otg_uninit() after dwc_otg_init()<br>+         */<br>+        dwc_otg_uninit(&sc->sc_otg);<br>+<br>+        err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,<br>+            sc->sc_otg.sc_intr_hdl);<br>+        sc->sc_otg.sc_intr_hdl = NULL;<br>+    }<br>+    /* free IRQ channel, if any */<br>+    if (sc->sc_otg.sc_irq_res) {<br>+        bus_release_resource(dev, SYS_RES_IRQ, 0,<br>+            sc->sc_otg.sc_irq_res);<br>+        sc->sc_otg.sc_irq_res = NULL;<br>+    }<br>+    /* free memory resource, if any */<br>+    if (sc->sc_otg.sc_io_res) {<br>+        bus_release_resource(dev, SYS_RES_MEMORY, 0,<br>+            sc->sc_otg.sc_io_res);<br>+        sc->sc_otg.sc_io_res = NULL;<br>+    }<br>+    usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);<br>+<br>+    return (0);<br>+}<br>+<br>+static device_method_t dwc_otg_methods[] = {<br>+    /* Device interface */<br>+    DEVMETHOD(device_probe, dwc_otg_probe),<br>+    DEVMETHOD(device_attach, dwc_otg_attach),<br>+    DEVMETHOD(device_detach, dwc_otg_detach),<br>+    DEVMETHOD(device_suspend, bus_generic_suspend),<br>+    DEVMETHOD(device_resume, bus_generic_resume),<br>+    DEVMETHOD(device_shutdown, bus_generic_shutdown),<br>+<br>+    DEVMETHOD_END<br>+};<br>+<br>+driver_t dwc_otg_driver = {<br>+    .name = "dwcotg",<br>+    .methods = dwc_otg_methods,<br>+    .size = sizeof(struct dwc_otg_fdt_softc),<br>+};<br>+<br>+static devclass_t dwc_otg_devclass;<br>+<br>+#ifndef __rtems__<br>+DRIVER_MODULE(dwcotg, simplebus, dwc_otg_driver, dwc_otg_devclass, 0, 0);<br>+#else<br>+DRIVER_MODULE(dwcotg, nexus, dwc_otg_driver, dwc_otg_devclass, 0, 0);<br>+#endif<br>+MODULE_DEPEND(dwcotg, usb, 1, 1, 1);<br>diff --git a/freebsd/sys/dev/usb/controller/dwc_otg_fdt.h b/freebsd/sys/dev/usb/controller/dwc_otg_fdt.h<br>new file mode 100755<br>index 0000000..9e01118<br>--- /dev/null<br>+++ b/freebsd/sys/dev/usb/controller/dwc_otg_fdt.h<br>@@ -0,0 +1,39 @@<br>+/*-<br>+ * Copyright (c) 2012 Hans Petter Selasky. All rights reserved.<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>+ * SUCH DAMAGE.<br>+ *<br>+ * $FreeBSD$<br>+ */<br>+<br>+#ifndef _DWC_OTG_FDT_H_<br>+#define    _DWC_OTG_FDT_H_<br>+<br>+struct dwc_otg_fdt_softc {<br>+    struct dwc_otg_softc sc_otg;    /* must be first */<br>+};<br>+<br>+extern driver_t dwc_otg_driver;<br>+<br>+device_attach_t dwc_otg_attach;<br>+<br>+#endif<br>diff --git a/freebsd/sys/dev/usb/controller/dwc_otgreg.h b/freebsd/sys/dev/usb/controller/dwc_otgreg.h<br>new file mode 100755<br>index 0000000..8ab3582<br>--- /dev/null<br>+++ b/freebsd/sys/dev/usb/controller/dwc_otgreg.h<br>@@ -0,0 +1,800 @@<br>+/* $FreeBSD$ */<br>+<br>+/*-<br>+ * Copyright (c) 2010,2011 Aleksandr Rybalko. All rights reserved.<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>+ * SUCH DAMAGE.<br>+ */<br>+<br>+#ifndef _DWC_OTGREG_H_<br>+#define    _DWC_OTGREG_H_<br>+<br>+#define    DOTG_GOTGCTL        0x0000<br>+#define    DOTG_GOTGINT        0x0004<br>+#define    DOTG_GAHBCFG        0x0008<br>+#define    DOTG_GUSBCFG        0x000C<br>+#define    DOTG_GRSTCTL        0x0010<br>+#define    DOTG_GINTSTS        0x0014<br>+#define    DOTG_GINTMSK        0x0018<br>+#define    DOTG_GRXSTSRD        0x001C<br>+#define    DOTG_GRXSTSRH        0x001C<br>+#define    DOTG_GRXSTSPD        0x0020<br>+#define    DOTG_GRXSTSPH        0x0020<br>+#define    DOTG_GRXFSIZ        0x0024<br>+#define    DOTG_GNPTXFSIZ        0x0028<br>+#define    DOTG_GNPTXSTS        0x002C<br>+#define    DOTG_GI2CCTL        0x0030<br>+#define    DOTG_GPVNDCTL        0x0034<br>+#define    DOTG_GGPIO        0x0038<br>+#define    DOTG_GUID        0x003C<br>+#define    DOTG_GSNPSID        0x0040<br>+#define    DOTG_GHWCFG1        0x0044<br>+#define    DOTG_GHWCFG2        0x0048<br>+#define    DOTG_GHWCFG3        0x004C<br>+#define    DOTG_GHWCFG4        0x0050<br>+#define    DOTG_GLPMCFG        0x0054<br>+#define    DOTG_GPWRDN        0x0058<br>+#define    DOTG_GDFIFOCFG        0x005C<br>+#define    DOTG_GADPCTL        0x0060<br>+<br>+#define    DOTG_HPTXFSIZ        0x0100<br>+/* start from 0x104, but fifo0 not exists */<br>+#define    DOTG_DPTXFSIZ(fifo)    (0x0100 + (4*(fifo)))<br>+#define    DOTG_DIEPTXF(fifo)    (0x0100 + (4*(fifo)))<br>+<br>+#define    DOTG_HCFG        0x0400<br>+#define    DOTG_HFIR        0x0404<br>+#define    DOTG_HFNUM        0x0408<br>+#define    DOTG_HPTXSTS        0x0410<br>+#define    DOTG_HAINT        0x0414<br>+#define    DOTG_HAINTMSK        0x0418<br>+#define    DOTG_HPRT        0x0440<br>+<br>+#define    DOTG_HCCHAR(ch)        (0x0500 + (32*(ch)))<br>+#define    DOTG_HCSPLT(ch)        (0x0504 + (32*(ch)))<br>+#define    DOTG_HCINT(ch)        (0x0508 + (32*(ch)))<br>+#define    DOTG_HCINTMSK(ch)    (0x050C + (32*(ch)))<br>+#define    DOTG_HCTSIZ(ch)        (0x0510 + (32*(ch)))<br>+#define    DOTG_HCDMA(ch)        (0x0514 + (32*(ch)))<br>+#define    DOTG_HCDMAI(ch)        (0x0514 + (32*(ch)))<br>+#define    DOTG_HCDMAO(ch)        (0x0514 + (32*(ch)))<br>+#define    DOTG_HCDMAB(ch)        (0x051C + (32*(ch)))<br>+<br>+/* Device Mode */<br>+#define    DOTG_DCFG        0x0800<br>+#define    DOTG_DCTL        0x0804<br>+#define    DOTG_DSTS        0x0808<br>+#define    DOTG_DIEPMSK        0x0810<br>+#define    DOTG_DOEPMSK        0x0814<br>+#define    DOTG_DAINT        0x0818<br>+#define    DOTG_DAINTMSK        0x081C<br>+#define    DOTG_DTKNQR1        0x0820<br>+#define    DOTG_DTKNQR2        0x0824<br>+#define    DOTG_DVBUSDIS        0x0828<br>+#define    DOTG_DVBUSPULSE        0x082C<br>+#define    DOTG_DTHRCTL        0x0830<br>+#define    DOTG_DTKNQR4        0x0834<br>+#define    DOTG_DIEPEMPMSK        0x0834<br>+#define    DOTG_DEACHINT        0x0838<br>+#define    DOTG_DEACHINTMSK    0x083C<br>+#define    DOTG_DIEPEACHINTMSK(ch)    (0x0840 + (4*(ch)))<br>+#define    DOTG_DOEPEACHINTMSK(ch)    (0x0880 + (4*(ch)))<br>+<br>+#define    DOTG_DIEPCTL(ep)    (0x0900 + (32*(ep)))<br>+#define    DOTG_DIEPINT(ep)    (0x0908 + (32*(ep)))<br>+#define    DOTG_DIEPTSIZ(ep)    (0x0910 + (32*(ep)))<br>+#define    DOTG_DIEPDMA(ep)    (0x0914 + (32*(ep)))<br>+#define    DOTG_DTXFSTS(ep)    (0x0918 + (32*(ep)))<br>+#define    DOTG_DIEPDMAB(ep)    (0x091c + (32*(ep)))<br>+<br>+#define    DOTG_DOEPCTL(ep)    (0x0B00 + (32*(ep)))<br>+#define    DOTG_DOEPFN(ep)        (0x0B04 + (32*(ep)))<br>+#define    DOTG_DOEPINT(ep)    (0x0B08 + (32*(ep)))<br>+#define    DOTG_DOEPTSIZ(ep)    (0x0B10 + (32*(ep)))<br>+#define    DOTG_DOEPDMA(ep)    (0x0B14 + (32*(ep)))<br>+#define    DOTG_DOEPDMAB(ep)    (0x0B1c + (32*(ep)))<br>+/* End Device Mode */<br>+<br>+/* Host Mode<br>+#define    DOTG_CTL_STATUS        0x0800<br>+#define    DOTG_DMA0_INB_CHN0    0x0818<br>+#define    DOTG_DMA0_INB_CHN1    0x0820<br>+#define    DOTG_DMA0_INB_CHN2    0x0828<br>+#define    DOTG_DVBUSDIS        0x0828<br>+#define    DOTG_DVBUSPULSE        0x082c<br>+#define    DOTG_DMA0_INB_CHN3    0x0830<br>+#define    DOTG_DMA0_INB_CHN4    0x0838<br>+#define    DOTG_DMA0_INB_CHN5    0x0840<br>+#define    DOTG_DMA0_INB_CHN6    0x0848<br>+#define    DOTG_DMA0_INB_CHN7    0x0850<br>+#define    DOTG_DMA0_OUTB_CHN0    0x0858<br>+#define    DOTG_DMA0_OUTB_CHN1    0x0860<br>+#define    DOTG_DMA0_OUTB_CHN2    0x0868<br>+#define    DOTG_DMA0_OUTB_CHN3    0x0870<br>+#define    DOTG_DMA0_OUTB_CHN4    0x0878<br>+#define    DOTG_DMA0_OUTB_CHN5    0x0880<br>+#define    DOTG_DMA0_OUTB_CHN6    0x0888<br>+#define    DOTG_DMA0_OUTB_CHN7    0x0890<br>+ End Host Mode */<br>+<br>+/* Power and clock gating CSR */<br>+<br>+#define    DOTG_PCGCCTL        0x0E00<br>+<br>+/* FIFO access registers (PIO-mode) */<br>+<br>+#define    DOTG_DFIFO(n)        (0x1000 + (0x1000 * (n)))<br>+<br>+#define    GOTGCTL_CHIRP_ON        (1<<27)<br>+#define    GOTGCTL_BSESVLD            (1<<19)<br>+#define    GOTGCTL_ASESVLD            (1<<18)<br>+#define    GOTGCTL_DBNCTIME        (1<<17)<br>+#define    GOTGCTL_CONIDSTS        (1<<16)<br>+#define    GOTGCTL_DEVHNPEN        (1<<11)<br>+#define    GOTGCTL_HSTSETHNPEN        (1<<10)<br>+#define    GOTGCTL_HNPREQ            (1<<9)<br>+#define    GOTGCTL_HSTNEGSCS        (1<<8)<br>+#define    GOTGCTL_SESREQ            (1<<1)<br>+#define    GOTGCTL_SESREQSCS        (1<<0)<br>+<br>+#define    GOTGCTL_DBNCEDONE        (1<<19)<br>+#define    GOTGCTL_ADEVTOUTCHG        (1<<18)<br>+#define    GOTGCTL_HSTNEGDET        (1<<17)<br>+#define    GOTGCTL_HSTNEGSUCSTSCHG        (1<<9)<br>+#define    GOTGCTL_SESREQSUCSTSCHG        (1<<8)<br>+#define    GOTGCTL_SESENDDET        (1<<2)<br>+<br>+#define    GAHBCFG_PTXFEMPLVL        (1<<8)<br>+#define    GAHBCFG_NPTXFEMPLVL        (1<<7)<br>+#define    GAHBCFG_DMAEN            (1<<5)<br>+#define    GAHBCFG_HBSTLEN_MASK        0x0000001e<br>+#define    GAHBCFG_HBSTLEN_SHIFT        1<br>+#define    GAHBCFG_GLBLINTRMSK        (1<<0)<br>+<br>+#define    GUSBCFG_CORRUPTTXPACKET        (1<<31)<br>+#define    GUSBCFG_FORCEDEVMODE        (1<<30)<br>+#define    GUSBCFG_FORCEHOSTMODE        (1<<29)<br>+#define    GUSBCFG_NO_PULLUP        (1<<27)<br>+#define    GUSBCFG_IC_USB_CAP        (1<<26)<br>+#define    GUSBCFG_TERMSELDLPULSE        (1<<22)<br>+#define    GUSBCFG_ULPIEXTVBUSINDICATOR    (1<<21)<br>+#define    GUSBCFG_ULPIEXTVBUSDRV        (1<<20)<br>+#define    GUSBCFG_ULPICLKSUSM        (1<<19)<br>+#define    GUSBCFG_ULPIAUTORES        (1<<18)<br>+#define    GUSBCFG_ULPIFSLS        (1<<17)<br>+#define    GUSBCFG_OTGI2CSEL        (1<<16)<br>+#define    GUSBCFG_PHYLPWRCLKSEL        (1<<15)<br>+#define    GUSBCFG_USBTRDTIM_MASK        0x00003c00<br>+#define    GUSBCFG_USBTRDTIM_SHIFT        10<br>+#define    GUSBCFG_TRD_TIM_SET(x)        (((x) & 15) << 10)<br>+#define    GUSBCFG_HNPCAP            (1<<9)<br>+#define    GUSBCFG_SRPCAP            (1<<8)<br>+#define    GUSBCFG_DDRSEL            (1<<7)<br>+#define    GUSBCFG_PHYSEL            (1<<6)<br>+#define    GUSBCFG_FSINTF            (1<<5)<br>+#define    GUSBCFG_ULPI_UTMI_SEL        (1<<4)<br>+#define    GUSBCFG_PHYIF            (1<<3)<br>+#define    GUSBCFG_TOUTCAL_MASK        0x00000007<br>+#define    GUSBCFG_TOUTCAL_SHIFT        0<br>+<br>+/* STM32F4 */<br>+#define    DOTG_GGPIO_NOVBUSSENS        (1 << 21)<br>+#define    DOTG_GGPIO_SOFOUTEN        (1 << 20)<br>+#define    DOTG_GGPIO_VBUSBSEN        (1 << 19)<br>+#define    DOTG_GGPIO_VBUSASEN        (1 << 18)<br>+#define    DOTG_GGPIO_I2CPADEN        (1 << 17)<br>+#define    DOTG_GGPIO_PWRDWN        (1 << 16)<br>+<br>+#define    GRSTCTL_AHBIDLE            (1<<31)<br>+#define    GRSTCTL_DMAREQ            (1<<30)<br>+#define    GRSTCTL_TXFNUM_MASK        0x000007c0<br>+#define    GRSTCTL_TXFNUM_SHIFT        6<br>+#define    GRSTCTL_TXFIFO(n)        (((n) & 31) << 6)<br>+#define    GRSTCTL_TXFFLSH            (1<<5)<br>+#define    GRSTCTL_RXFFLSH            (1<<4)<br>+#define    GRSTCTL_INTKNQFLSH        (1<<3)<br>+#define    GRSTCTL_FRMCNTRRST        (1<<2)<br>+#define    GRSTCTL_HSFTRST            (1<<1)<br>+#define    GRSTCTL_CSFTRST            (1<<0)<br>+<br>+#define    GINTSTS_WKUPINT            (1<<31)<br>+#define    GINTSTS_SESSREQINT        (1<<30)<br>+#define    GINTSTS_DISCONNINT        (1<<29)<br>+#define    GINTSTS_CONIDSTSCHNG        (1<<28)<br>+#define    GINTSTS_LPM            (1<<27)<br>+#define    GINTSTS_PTXFEMP            (1<<26)<br>+#define    GINTSTS_HCHINT            (1<<25)<br>+#define    GINTSTS_PRTINT            (1<<24)<br>+#define    GINTSTS_RESETDET        (1<<23)<br>+#define    GINTSTS_FETSUSP            (1<<22)<br>+#define    GINTSTS_INCOMPLP        (1<<21)<br>+#define    GINTSTS_INCOMPISOIN        (1<<20)<br>+#define    GINTSTS_OEPINT            (1<<19)<br>+#define    GINTSTS_IEPINT            (1<<18)<br>+#define    GINTSTS_EPMIS            (1<<17)<br>+#define    GINTSTS_RESTORE_DONE        (1<<16)<br>+#define    GINTSTS_EOPF            (1<<15)<br>+#define    GINTSTS_ISOOUTDROP        (1<<14)<br>+#define    GINTSTS_ENUMDONE        (1<<13)<br>+#define    GINTSTS_USBRST            (1<<12)<br>+#define    GINTSTS_USBSUSP            (1<<11)<br>+#define    GINTSTS_ERLYSUSP        (1<<10)<br>+#define    GINTSTS_I2CINT            (1<<9)<br>+#define    GINTSTS_ULPICKINT        (1<<8)<br>+#define    GINTSTS_GOUTNAKEFF        (1<<7)<br>+#define    GINTSTS_GINNAKEFF        (1<<6)<br>+#define    GINTSTS_NPTXFEMP        (1<<5)<br>+#define    GINTSTS_RXFLVL            (1<<4)<br>+#define    GINTSTS_SOF            (1<<3)<br>+#define    GINTSTS_OTGINT            (1<<2)<br>+#define    GINTSTS_MODEMIS            (1<<1)<br>+#define    GINTSTS_CURMOD            (1<<0)<br>+<br>+#define    GINTMSK_WKUPINTMSK        (1<<31)<br>+#define    GINTMSK_SESSREQINTMSK        (1<<30)<br>+#define    GINTMSK_DISCONNINTMSK        (1<<29)<br>+#define    GINTMSK_CONIDSTSCHNGMSK        (1<<28)<br>+#define    GINTMSK_PTXFEMPMSK        (1<<26)<br>+#define    GINTMSK_HCHINTMSK        (1<<25)<br>+#define    GINTMSK_PRTINTMSK        (1<<24)<br>+#define    GINTMSK_FETSUSPMSK        (1<<22)<br>+#define    GINTMSK_INCOMPLPMSK        (1<<21)<br>+#define    GINTMSK_INCOMPISOINMSK        (1<<20)<br>+#define    GINTMSK_OEPINTMSK        (1<<19)<br>+#define    GINTMSK_IEPINTMSK        (1<<18)<br>+#define    GINTMSK_EPMISMSK        (1<<17)<br>+#define    GINTMSK_EOPFMSK            (1<<15)<br>+#define    GINTMSK_ISOOUTDROPMSK        (1<<14)<br>+#define    GINTMSK_ENUMDONEMSK        (1<<13)<br>+#define    GINTMSK_USBRSTMSK        (1<<12)<br>+#define    GINTMSK_USBSUSPMSK        (1<<11)<br>+#define    GINTMSK_ERLYSUSPMSK        (1<<10)<br>+#define    GINTMSK_I2CINTMSK        (1<<9)<br>+#define    GINTMSK_ULPICKINTMSK        (1<<8)<br>+#define    GINTMSK_GOUTNAKEFFMSK        (1<<7)<br>+#define    GINTMSK_GINNAKEFFMSK        (1<<6)<br>+#define    GINTMSK_NPTXFEMPMSK        (1<<5)<br>+#define    GINTMSK_RXFLVLMSK        (1<<4)<br>+#define    GINTMSK_SOFMSK            (1<<3)<br>+#define    GINTMSK_OTGINTMSK        (1<<2)<br>+#define    GINTMSK_MODEMISMSK        (1<<1)<br>+#define    GINTMSK_CURMODMSK        (1<<0)<br>+<br>+#define    GRXSTSRH_PKTSTS_MASK        0x001e0000<br>+#define    GRXSTSRH_PKTSTS_SHIFT        17<br>+#define    GRXSTSRH_DPID_MASK        0x00018000<br>+#define    GRXSTSRH_DPID_SHIFT        15<br>+#define    GRXSTSRH_BCNT_MASK        0x00007ff0<br>+#define    GRXSTSRH_BCNT_SHIFT        4<br>+#define    GRXSTSRH_CHNUM_MASK        0x0000000f<br>+#define    GRXSTSRH_CHNUM_SHIFT        0<br>+<br>+#define    GRXSTSRD_FN_MASK        0x01e00000<br>+#define    GRXSTSRD_FN_GET(x)        (((x) >> 21) & 15)<br>+#define    GRXSTSRD_FN_SHIFT        21<br>+#define    GRXSTSRD_PKTSTS_MASK        0x001e0000<br>+#define    GRXSTSRD_PKTSTS_SHIFT        17<br>+#define    GRXSTSRH_IN_DATA        (2<<17)<br>+#define    GRXSTSRH_IN_COMPLETE        (3<<17)<br>+#define    GRXSTSRH_DT_ERROR        (5<<17)<br>+#define    GRXSTSRH_HALTED            (7<<17)<br>+#define    GRXSTSRD_GLOB_OUT_NAK        (1<<17)<br>+#define    GRXSTSRD_OUT_DATA        (2<<17)<br>+#define    GRXSTSRD_OUT_COMPLETE        (3<<17)<br>+#define    GRXSTSRD_STP_COMPLETE        (4<<17)<br>+#define    GRXSTSRD_STP_DATA        (6<<17)<br>+#define    GRXSTSRD_DPID_MASK        0x00018000<br>+#define    GRXSTSRD_DPID_SHIFT        15<br>+#define    GRXSTSRD_DPID_DATA0        (0<<15)<br>+#define    GRXSTSRD_DPID_DATA1        (2<<15)<br>+#define    GRXSTSRD_DPID_DATA2        (1<<15)<br>+#define    GRXSTSRD_DPID_MDATA        (3<<15)<br>+#define    GRXSTSRD_BCNT_MASK        0x00007ff0<br>+#define    GRXSTSRD_BCNT_GET(x)        (((x) >> 4) & 0x7FF)<br>+#define    GRXSTSRD_BCNT_SHIFT        4<br>+#define    GRXSTSRD_CHNUM_MASK        0x0000000f<br>+#define    GRXSTSRD_CHNUM_GET(x)        ((x) & 15)<br>+#define    GRXSTSRD_CHNUM_SHIFT        0<br>+<br>+#define    GRXFSIZ_RXFDEP_MASK        0x0000ffff<br>+#define    GRXFSIZ_RXFDEP_SHIFT        0<br>+<br>+#define    GNPTXFSIZ_NPTXFDEP_MASK        0xffff0000<br>+#define    GNPTXFSIZ_NPTXFDEP_SHIFT    0<br>+#define    GNPTXFSIZ_NPTXFSTADDR_MASK    0x0000ffff<br>+#define    GNPTXFSIZ_NPTXFSTADDR_SHIFT    16<br>+<br>+#define    GNPTXSTS_NPTXQTOP_SHIFT        24<br>+#define    GNPTXSTS_NPTXQTOP_MASK        0x7f000000<br>+#define    GNPTXSTS_NPTXQSPCAVAIL_SHIFT    16<br>+#define    GNPTXSTS_NPTXQSPCAVAIL_MASK    0x00ff0000<br>+#define    GNPTXSTS_NPTXFSPCAVAIL_SHIFT    0<br>+#define    GNPTXSTS_NPTXFSPCAVAIL_MASK    0x0000ffff<br>+<br>+#define    GI2CCTL_BSYDNE_SC        (1<<31)<br>+#define    GI2CCTL_RW            (1<<30)<br>+#define    GI2CCTL_I2CDATSE0        (1<<28)<br>+#define    GI2CCTL_I2CDEVADR_SHIFT        26<br>+#define    GI2CCTL_I2CDEVADR_MASK        0x0c000000<br>+#define    GI2CCTL_I2CSUSPCTL        (1<<25)<br>+#define    GI2CCTL_ACK            (1<<24)<br>+#define    GI2CCTL_I2CEN            (1<<23)<br>+#define    GI2CCTL_ADDR_SHIFT        16<br>+#define    GI2CCTL_ADDR_MASK        0x007f0000<br>+#define    GI2CCTL_REGADDR_SHIFT        8<br>+#define    GI2CCTL_REGADDR_MASK        0x0000ff00<br>+#define    GI2CCTL_RWDATA_SHIFT        0<br>+#define    GI2CCTL_RWDATA_MASK        0x000000ff<br>+<br>+#define    GPVNDCTL_DISULPIDRVR        (1<<31)<br>+#define    GPVNDCTL_VSTSDONE        (1<<27)<br>+#define    GPVNDCTL_VSTSBSY        (1<<26)<br>+#define    GPVNDCTL_NEWREGREQ        (1<<25)<br>+#define    GPVNDCTL_REGWR            (1<<22)<br>+#define    GPVNDCTL_REGADDR_SHIFT        16<br>+#define    GPVNDCTL_REGADDR_MASK        0x003f0000<br>+#define    GPVNDCTL_VCTRL_SHIFT        8<br>+#define    GPVNDCTL_VCTRL_MASK        0x0000ff00<br>+#define    GPVNDCTL_REGDATA_SHIFT        0<br>+#define    GPVNDCTL_REGDATA_MASK        0x000000ff<br>+<br>+#define    GGPIO_GPO_SHIFT            16<br>+#define    GGPIO_GPO_MASK            0xffff0000<br>+#define    GGPIO_GPI_SHIFT            0<br>+#define    GGPIO_GPI_MASK            0x0000ffff<br>+<br>+#define    GHWCFG1_GET_DIR(x, n)        (((x) >> (2 * (n))) & 3)<br>+#define    GHWCFG1_BIDIR            0<br>+#define    GHWCFG1_IN            1<br>+#define    GHWCFG1_OUT            2<br>+<br>+#define    GHWCFG2_TKNQDEPTH_SHIFT        26<br>+#define    GHWCFG2_TKNQDEPTH_MASK        0x7c000000<br>+#define    GHWCFG2_PTXQDEPTH_SHIFT        24<br>+#define    GHWCFG2_PTXQDEPTH_MASK        0x03000000<br>+#define    GHWCFG2_NPTXQDEPTH_SHIFT    22<br>+#define    GHWCFG2_NPTXQDEPTH_MASK        0x00c00000<br>+#define    GHWCFG2_MPI            (1<<20)<br>+#define    GHWCFG2_DYNFIFOSIZING        (1<<19)<br>+#define    GHWCFG2_PERIOSUPPORT        (1<<18)<br>+#define    GHWCFG2_NUMHSTCHNL_SHIFT    14<br>+#define    GHWCFG2_NUMHSTCHNL_MASK        0x0003c000<br>+#define    GHWCFG2_NUMHSTCHNL_GET(x)    ((((x) >> 14) & 15) + 1)<br>+#define    GHWCFG2_NUMDEVEPS_SHIFT        10<br>+#define    GHWCFG2_NUMDEVEPS_MASK        0x00003c00<br>+#define    GHWCFG2_NUMDEVEPS_GET(x)    ((((x) >> 10) & 15) + 1)<br>+#define    GHWCFG2_FSPHYTYPE_SHIFT        8<br>+#define    GHWCFG2_FSPHYTYPE_MASK        0x00000300<br>+#define    GHWCFG2_HSPHYTYPE_SHIFT        6<br>+#define    GHWCFG2_HSPHYTYPE_MASK        0x000000c0<br>+#define    GHWCFG2_SINGPNT            (1<<5)<br>+#define    GHWCFG2_OTGARCH_SHIFT        3<br>+#define    GHWCFG2_OTGARCH_MASK        0x00000018<br>+#define    GHWCFG2_OTGMODE_SHIFT        0<br>+#define    GHWCFG2_OTGMODE_MASK        0x00000007<br>+<br>+#define    GHWCFG3_DFIFODEPTH_SHIFT    16<br>+#define    GHWCFG3_DFIFODEPTH_MASK        0xffff0000<br>+#define    GHWCFG3_DFIFODEPTH_GET(x)    ((x) >> 16)<br>+#define    GHWCFG3_RSTTYPE            (1<<11)<br>+#define    GHWCFG3_OPTFEATURE        (1<<10)<br>+#define    GHWCFG3_VNDCTLSUPT        (1<<9)<br>+#define    GHWCFG3_I2CINTSEL        (1<<8)<br>+#define    GHWCFG3_OTGEN            (1<<7)<br>+#define    GHWCFG3_PKTSIZEWIDTH_SHIFT    4<br>+#define    GHWCFG3_PKTSIZEWIDTH_MASK    0x00000070<br>+#define    GHWCFG3_PKTSIZE_GET(x)        (0x10<<(((x) >> 4) & 7))<br>+#define    GHWCFG3_XFERSIZEWIDTH_SHIFT    0<br>+#define    GHWCFG3_XFERSIZEWIDTH_MASK    0x0000000f<br>+#define    GHWCFG3_XFRRSIZE_GET(x)        (0x400<<(((x) >> 0) & 15))<br>+<br>+#define    GHWCFG4_NUM_IN_EP_GET(x)    ((((x) >> 26) & 15) + 1)<br>+#define    GHWCFG4_SESSENDFLTR        (1<<24)<br>+#define    GHWCFG4_BVALIDFLTR        (1<<23)<br>+#define    GHWCFG4_AVALIDFLTR        (1<<22)<br>+#define    GHWCFG4_VBUSVALIDFLTR        (1<<21)<br>+#define    GHWCFG4_IDDGFLTR        (1<<20)<br>+#define    GHWCFG4_NUMCTLEPS_SHIFT        16<br>+#define    GHWCFG4_NUMCTLEPS_MASK        0x000f0000<br>+#define    GHWCFG4_NUMCTLEPS_GET(x)    (((x) >> 16) & 15)<br>+#define    GHWCFG4_PHYDATAWIDTH_SHIFT    14<br>+#define    GHWCFG4_PHYDATAWIDTH_MASK    0x0000c000<br>+#define    GHWCFG4_AHBFREQ            (1<<5)<br>+#define    GHWCFG4_ENABLEPWROPT        (1<<4)<br>+#define    GHWCFG4_NUMDEVPERIOEPS_SHIFT    0<br>+#define    GHWCFG4_NUMDEVPERIOEPS_MASK    0x0000000f<br>+#define    GHWCFG4_NUMDEVPERIOEPS_GET(x)    (((x) >> 0) & 15)<br>+<br>+#define    GLPMCFG_HSIC_CONN        (1<<30)<br>+<br>+#define    GPWRDN_BVALID            (1<<22)<br>+#define    GPWRDN_IDDIG            (1<<21)<br>+#define    GPWRDN_CONNDET_INT        (1<<14)<br>+#define    GPWRDN_CONNDET            (1<<13)<br>+#define    GPWRDN_DISCONN_INT        (1<<12)<br>+#define    GPWRDN_DISCONN            (1<<11)<br>+#define    GPWRDN_RESETDET_INT        (1<<10)<br>+#define    GPWRDN_RESETDET            (1<<9)<br>+#define    GPWRDN_LINESTATE_INT        (1<<8)<br>+#define    GPWRDN_LINESTATE        (1<<7)<br>+#define    GPWRDN_DISABLE_VBUS        (1<<6)<br>+#define    GPWRDN_POWER_DOWN        (1<<5)<br>+#define    GPWRDN_POWER_DOWN_RST        (1<<4)<br>+#define    GPWRDN_POWER_DOWN_CLAMP        (1<<3)<br>+#define    GPWRDN_RESTORE            (1<<2)<br>+#define    GPWRDN_PMU_ACTIVE        (1<<1)<br>+#define    GPWRDN_PMU_IRQ_SEL        (1<<0)<br>+<br>+#define    HPTXFSIZ_PTXFSIZE_SHIFT        16<br>+#define    HPTXFSIZ_PTXFSIZE_MASK        0xffff0000<br>+#define    HPTXFSIZ_PTXFSTADDR_SHIFT    0<br>+#define    HPTXFSIZ_PTXFSTADDR_MASK    0x0000ffff<br>+<br>+#define    DPTXFSIZN_DPTXFSIZE_SHIFT    16<br>+#define    DPTXFSIZN_DPTXFSIZE_MASK    0xffff0000<br>+#define    DPTXFSIZN_PTXFSTADDR_SHIFT    0<br>+#define    DPTXFSIZN_PTXFSTADDR_MASK    0x0000ffff<br>+<br>+#define    DIEPTXFN_INEPNTXFDEP_SHIFT    16<br>+#define    DIEPTXFN_INEPNTXFDEP_MASK    0xffff0000<br>+#define    DIEPTXFN_INEPNTXFSTADDR_SHIFT    0<br>+#define    DIEPTXFN_INEPNTXFSTADDR_MASK    0x0000ffff<br>+<br>+#define    HCFG_MODECHANGERDY        (1<<31)<br>+#define    HCFG_PERSCHEDENABLE        (1<<26)<br>+#define    HCFG_FLENTRIES_SHIFT        24<br>+#define    HCFG_FLENTRIES_MASK        0x03000000<br>+#define    HCFG_FLENTRIES_8        (0)<br>+#define    HCFG_FLENTRIES_16        (1)<br>+#define    HCFG_FLENTRIES_32        (2)<br>+#define    HCFG_FLENTRIES_64        (3)<br>+#define    HCFG_MULTISEGDMA        (1<<23)<br>+#define    HCFG_32KHZSUSPEND        (1<<7)<br>+#define    HCFG_FSLSSUPP            (1<<2)<br>+#define    HCFG_FSLSPCLKSEL_SHIFT        0<br>+#define    HCFG_FSLSPCLKSEL_MASK        0x00000003<br>+<br>+#define    HFIR_RELOADCTRL            (1<<16)<br>+#define    HFIR_FRINT_SHIFT        0<br>+#define    HFIR_FRINT_MASK            0x0000ffff<br>+<br>+#define    HFNUM_FRREM_SHIFT        16<br>+#define    HFNUM_FRREM_MASK        0xffff0000<br>+#define    HFNUM_FRNUM_SHIFT        0<br>+#define    HFNUM_FRNUM_MASK        0x0000ffff<br>+<br>+#define    HPTXSTS_ODD            (1<<31)<br>+#define    HPTXSTS_CHAN_SHIFT        27<br>+#define    HPTXSTS_CHAN_MASK        0x78000000<br>+#define    HPTXSTS_TOKEN_SHIFT        25<br>+#define    HPTXSTS_TOKEN_MASK        0x06000000<br>+#define    HPTXSTS_TOKEN_ZL        0<br>+#define    HPTXSTS_TOKEN_PING        1<br>+#define    HPTXSTS_TOKEN_DISABLE        2<br>+#define    HPTXSTS_TERMINATE        (1<<24)<br>+#define    HPTXSTS_PTXQSPCAVAIL_SHIFT    16<br>+#define    HPTXSTS_PTXQSPCAVAIL_MASK    0x00ff0000<br>+#define    HPTXSTS_PTXFSPCAVAIL_SHIFT    0<br>+#define    HPTXSTS_PTXFSPCAVAIL_MASK    0x0000ffff<br>+<br>+#define    HAINT_HAINT_SHIFT        0<br>+#define    HAINT_HAINT_MASK        0x0000ffff<br>+#define    HAINTMSK_HAINTMSK_SHIFT        0<br>+#define    HAINTMSK_HAINTMSK_MASK        0x0000ffff<br>+<br>+#define    HPRT_PRTSPD_SHIFT        17<br>+#define    HPRT_PRTSPD_MASK        0x00060000<br>+#define    HPRT_PRTSPD_HIGH        0<br>+#define    HPRT_PRTSPD_FULL        1<br>+#define    HPRT_PRTSPD_LOW            2<br>+#define    HPRT_PRTSPD_MASK        0x00060000<br>+#define    HPRT_PRTTSTCTL_SHIFT        13<br>+#define    HPRT_PRTTSTCTL_MASK        0x0001e000<br>+#define    HPRT_PRTPWR            (1<<12)<br>+#define    HPRT_PRTLNSTS_SHIFT        10<br>+#define    HPRT_PRTLNSTS_MASK        0x00000c00<br>+#define    HPRT_PRTRST            (1<<8)<br>+#define    HPRT_PRTSUSP            (1<<7)<br>+#define    HPRT_PRTRES            (1<<6)<br>+#define    HPRT_PRTOVRCURRCHNG        (1<<5)<br>+#define    HPRT_PRTOVRCURRACT        (1<<4)<br>+#define    HPRT_PRTENCHNG            (1<<3)<br>+#define    HPRT_PRTENA            (1<<2)<br>+#define    HPRT_PRTCONNDET            (1<<1)<br>+#define    HPRT_PRTCONNSTS            (1<<0)<br>+<br>+#define    HCCHAR_CHENA            (1<<31)<br>+#define    HCCHAR_CHDIS            (1<<30)<br>+#define    HCCHAR_ODDFRM            (1<<29)<br>+#define    HCCHAR_DEVADDR_SHIFT        22<br>+#define    HCCHAR_DEVADDR_MASK        0x1fc00000<br>+#define    HCCHAR_MC_SHIFT            20<br>+#define    HCCHAR_MC_MASK            0x00300000<br>+#define    HCCHAR_EPTYPE_SHIFT        18<br>+#define    HCCHAR_EPTYPE_MASK        0x000c0000<br>+#define    HCCHAR_LSPDDEV            (1<<17)<br>+#define    HCCHAR_EPDIR            (1<<15)<br>+#define    HCCHAR_EPDIR_IN            (1<<15)<br>+#define    HCCHAR_EPDIR_OUT        0<br>+#define    HCCHAR_EPNUM_SHIFT        11<br>+#define    HCCHAR_EPNUM_MASK        0x00007800<br>+#define    HCCHAR_MPS_SHIFT        0<br>+#define    HCCHAR_MPS_MASK            0x000007ff<br>+<br>+#define    HCSPLT_SPLTENA            (1<<31)<br>+#define    HCSPLT_COMPSPLT            (1<<16)<br>+#define    HCSPLT_XACTPOS_SHIFT        14<br>+#define    HCSPLT_XACTPOS_MASK        0x0000c000<br>+#define    HCSPLT_XACTPOS_MIDDLE        0<br>+#define    HCSPLT_XACTPOS_LAST        1<br>+#define    HCSPLT_XACTPOS_BEGIN        2<br>+#define    HCSPLT_XACTPOS_ALL        3<br>+#define    HCSPLT_XACTLEN_BURST        1023    /* bytes */<br>+#define    HCSPLT_HUBADDR_SHIFT        7<br>+#define    HCSPLT_HUBADDR_MASK        0x00003f80<br>+#define    HCSPLT_PRTADDR_SHIFT        0<br>+#define    HCSPLT_PRTADDR_MASK        0x0000007f<br>+<br>+#define    HCINT_ERRORS \<br>+    (HCINT_BBLERR | HCINT_XACTERR)<br>+#define    HCINT_RETRY \<br>+    (HCINT_DATATGLERR | HCINT_FRMOVRUN | HCINT_NAK)<br>+#define    HCINT_DEFAULT_MASK \<br>+  (HCINT_STALL | HCINT_BBLERR | \<br>+   HCINT_XACTERR | HCINT_NAK | HCINT_ACK | HCINT_NYET | \<br>+   HCINT_CHHLTD | HCINT_FRMOVRUN | \<br>+   HCINT_DATATGLERR)<br>+#define    HCINT_HCH_DONE_MASK \<br>+  (HCINT_ACK | HCINT_RETRY | HCINT_NYET | \<br>+   HCINT_ERRORS | HCINT_STALL | HCINT_SOFTWARE_ONLY)<br>+<br>+#define    HCINT_SOFTWARE_ONLY        (1<<20)    /* BSD only */<br>+#define    HCINT_DATATGLERR        (1<<10)<br>+#define    HCINT_FRMOVRUN            (1<<9)<br>+#define    HCINT_BBLERR            (1<<8)<br>+#define    HCINT_XACTERR            (1<<7)<br>+#define    HCINT_NYET            (1<<6)<br>+#define    HCINT_ACK            (1<<5)<br>+#define    HCINT_NAK            (1<<4)<br>+#define    HCINT_STALL            (1<<3)<br>+#define    HCINT_AHBERR            (1<<2)<br>+#define    HCINT_CHHLTD            (1<<1)<br>+#define    HCINT_XFERCOMPL            (1<<0)<br>+<br>+#define    HCINTMSK_DATATGLERRMSK        (1<<10)<br>+#define    HCINTMSK_FRMOVRUNMSK        (1<<9)<br>+#define    HCINTMSK_BBLERRMSK        (1<<8)<br>+#define    HCINTMSK_XACTERRMSK        (1<<7)<br>+#define    HCINTMSK_NYETMSK        (1<<6)<br>+#define    HCINTMSK_ACKMSK            (1<<5)<br>+#define    HCINTMSK_NAKMSK            (1<<4)<br>+#define    HCINTMSK_STALLMSK        (1<<3)<br>+#define    HCINTMSK_AHBERRMSK        (1<<2)<br>+#define    HCINTMSK_CHHLTDMSK        (1<<1)<br>+#define    HCINTMSK_XFERCOMPLMSK        (1<<0)<br>+<br>+#define    HCTSIZ_DOPNG            (1<<31)<br>+#define    HCTSIZ_PID_SHIFT        29<br>+#define    HCTSIZ_PID_MASK            0x60000000<br>+#define    HCTSIZ_PID_DATA0        0<br>+#define    HCTSIZ_PID_DATA2        1<br>+#define    HCTSIZ_PID_DATA1        2<br>+#define    HCTSIZ_PID_MDATA        3<br>+#define    HCTSIZ_PID_SETUP        3<br>+#define    HCTSIZ_PKTCNT_SHIFT        19<br>+#define    HCTSIZ_PKTCNT_MASK        0x1ff80000<br>+#define    HCTSIZ_XFERSIZE_SHIFT        0<br>+#define    HCTSIZ_XFERSIZE_MASK        0x0007ffff<br>+<br>+#define    DCFG_EPMISCNT_SHIFT        18<br>+#define    DCFG_EPMISCNT_MASK        0x007c0000<br>+#define    DCFG_PERFRINT_SHIFT        11<br>+#define    DCFG_PERFRINT_MASK        0x00001800<br>+#define    DCFG_DEVADDR_SHIFT        4<br>+#define    DCFG_DEVADDR_MASK        0x000007f0<br>+#define    DCFG_DEVADDR_SET(x)        (((x) & 0x7F) << 4)<br>+#define    DCFG_NZSTSOUTHSHK        (1<<2)<br>+#define    DCFG_DEVSPD_SHIFT        0<br>+#define    DCFG_DEVSPD_MASK        0x00000003<br>+#define    DCFG_DEVSPD_SET(x)        ((x) & 0x3)<br>+#define    DCFG_DEVSPD_HI            0<br>+#define    DCFG_DEVSPD_FULL20        1<br>+#define    DCFG_DEVSPD_FULL10        3<br>+<br>+#define    DCTL_PWRONPRGDONE        (1<<11)<br>+#define    DCTL_CGOUTNAK            (1<<10)<br>+#define    DCTL_SGOUTNAK            (1<<9)<br>+#define    DCTL_CGNPINNAK            (1<<8)<br>+#define    DCTL_SGNPINNAK            (1<<7)<br>+#define    DCTL_TSTCTL_SHIFT        4<br>+#define    DCTL_TSTCTL_MASK        0x00000070<br>+#define    DCTL_GOUTNAKSTS            (1<<3)<br>+#define    DCTL_GNPINNAKSTS        (1<<2)<br>+#define    DCTL_SFTDISCON            (1<<1)<br>+#define    DCTL_RMTWKUPSIG            (1<<0)<br>+<br>+#define    DSTS_SOFFN_SHIFT        8<br>+#define    DSTS_SOFFN_MASK            0x003fff00<br>+#define    DSTS_SOFFN_GET(x)        (((x) >> 8) & 0x3FFF)<br>+#define    DSTS_ERRTICERR            (1<<3)<br>+#define    DSTS_ENUMSPD_SHIFT        1<br>+#define    DSTS_ENUMSPD_MASK        0x00000006<br>+#define    DSTS_ENUMSPD_GET(x)        (((x) >> 1) & 3)<br>+#define    DSTS_ENUMSPD_HI            0<br>+#define    DSTS_ENUMSPD_FULL20        1<br>+#define    DSTS_ENUMSPD_LOW10        2<br>+#define    DSTS_ENUMSPD_FULL10        3<br>+#define    DSTS_SUSPSTS            (1<<0)<br>+<br>+#define    DIEPMSK_TXFIFOUNDRNMSK        (1<<8)<br>+#define    DIEPMSK_INEPNAKEFFMSK        (1<<6)<br>+#define    DIEPMSK_INTKNEPMISMSK        (1<<5)<br>+#define    DIEPMSK_INTKNTXFEMPMSK        (1<<4)<br>+#define    DIEPMSK_FIFOEMPTY        (1<<4)<br>+#define    DIEPMSK_TIMEOUTMSK        (1<<3)<br>+#define    DIEPMSK_AHBERRMSK        (1<<2)<br>+#define    DIEPMSK_EPDISBLDMSK        (1<<1)<br>+#define    DIEPMSK_XFERCOMPLMSK        (1<<0)<br>+<br>+#define    DOEPMSK_OUTPKTERRMSK        (1<<8)<br>+#define    DOEPMSK_BACK2BACKSETUP        (1<<6)<br>+#define    DOEPMSK_OUTTKNEPDISMSK        (1<<4)<br>+#define    DOEPMSK_FIFOEMPTY        (1<<4)<br>+#define    DOEPMSK_SETUPMSK        (1<<3)<br>+#define    DOEPMSK_AHBERRMSK        (1<<2)<br>+#define    DOEPMSK_EPDISBLDMSK        (1<<1)<br>+#define    DOEPMSK_XFERCOMPLMSK        (1<<0)<br>+<br>+#define    DIEPINT_TXFIFOUNDRN        (1<<8)<br>+#define    DIEPINT_INEPNAKEFF        (1<<6)<br>+#define    DIEPINT_INTKNEPMIS        (1<<5)<br>+#define    DIEPINT_INTKNTXFEMP        (1<<4)<br>+#define    DIEPINT_TIMEOUT            (1<<3)<br>+#define    DIEPINT_AHBERR            (1<<2)<br>+#define    DIEPINT_EPDISBLD        (1<<1)<br>+#define    DIEPINT_XFERCOMPL        (1<<0)<br>+<br>+#define    DOEPINT_OUTPKTERR        (1<<8)<br>+#define    DOEPINT_BACK2BACKSETUP        (1<<6)<br>+#define    DOEPINT_OUTTKNEPDIS        (1<<4)<br>+#define    DOEPINT_SETUP            (1<<3)<br>+#define    DOEPINT_AHBERR            (1<<2)<br>+#define    DOEPINT_EPDISBLD        (1<<1)<br>+#define    DOEPINT_XFERCOMPL        (1<<0)<br>+<br>+#define    DAINT_INEPINT_MASK        0xffff0000<br>+#define    DAINT_INEPINT_SHIFT        0<br>+#define    DAINT_OUTEPINT_MASK        0x0000ffff<br>+#define    DAINT_OUTEPINT_SHIFT        16<br>+<br>+#define    DAINTMSK_INEPINT_MASK        0xffff0000<br>+#define    DAINTMSK_INEPINT_SHIFT        0<br>+#define    DAINTMSK_OUTEPINT_MASK        0x0000ffff<br>+#define    DAINTMSK_OUTEPINT_SHIFT        16<br>+<br>+#define    DTKNQR1_EPTKN_SHIFT        8<br>+#define    DTKNQR1_EPTKN_MASK        0xffffff00<br>+#define    DTKNQR1_WRAPBIT            (1<<7)<br>+#define    DTKNQR1_INTKNWPTR_SHIFT        0<br>+#define    DTKNQR1_INTKNWPTR_MASK        0x0000001f<br>+<br>+#define    DVBUSDIS_DVBUSDIS_SHIFT        0<br>+#define    DVBUSDIS_DVBUSDIS_MASK        0x0000ffff<br>+<br>+#define    DVBUSPULSE_DVBUSPULSE_SHIFT    0<br>+#define    DVBUSPULSE_DVBUSPULSE_MASK    0x00000fff<br>+<br>+#define    DTHRCTL_ARBPRKEN        (1<<27)<br>+#define    DTHRCTL_RXTHRLEN_SHIFT        17<br>+#define    DTHRCTL_RXTHRLEN_MASK        0x03fe0000<br>+#define    DTHRCTL_RXTHREN            (1<<16)<br>+#define    DTHRCTL_TXTHRLEN_SHIFT        2<br>+#define    DTHRCTL_TXTHRLEN_MASK        0x000007fc<br>+#define    DTHRCTL_ISOTHREN        (1<<1)<br>+#define    DTHRCTL_NONISOTHREN        (1<<0)<br>+<br>+#define    DIEPEMPMSK_INEPTXFEMPMSK_SHIFT    0<br>+#define    DIEPEMPMSK_INEPTXFEMPMSK_MASK    0x0000ffff<br>+<br>+#define    DIEPCTL_EPENA            (1<<31)<br>+#define    DIEPCTL_EPDIS            (1<<30)<br>+#define    DIEPCTL_SETD1PID        (1<<29)<br>+#define    DIEPCTL_SETD0PID        (1<<28)<br>+#define    DIEPCTL_SNAK            (1<<27)<br>+#define    DIEPCTL_CNAK            (1<<26)<br>+#define    DIEPCTL_TXFNUM_SHIFT        22<br>+#define    DIEPCTL_TXFNUM_MASK        0x03c00000<br>+#define    DIEPCTL_TXFNUM_SET(n)        (((n) & 15) << 22)<br>+#define    DIEPCTL_STALL            (1<<21)<br>+#define    DIEPCTL_EPTYPE_SHIFT        18<br>+#define    DIEPCTL_EPTYPE_MASK        0x000c0000<br>+#define    DIEPCTL_EPTYPE_SET(n)        (((n) & 3) << 18)<br>+#define    DIEPCTL_EPTYPE_CONTROL        0<br>+#define    DIEPCTL_EPTYPE_ISOC        1<br>+#define    DIEPCTL_EPTYPE_BULK        2<br>+#define    DIEPCTL_EPTYPE_INTERRUPT    3<br>+#define    DIEPCTL_NAKSTS            (1<<17)<br>+#define    DIEPCTL_USBACTEP        (1<<15)<br>+#define    DIEPCTL_NEXTEP_SHIFT        11<br>+#define    DIEPCTL_NEXTEP_MASK        0x00007800<br>+#define    DIEPCTL_MPS_SHIFT        0<br>+#define    DIEPCTL_MPS_MASK        0x000007ff<br>+#define    DIEPCTL_MPS_SET(n)        ((n) & 0x7FF)<br>+#define    DIEPCTL_MPS_64            (0<<0)<br>+#define    DIEPCTL_MPS_32            (1<<0)<br>+#define    DIEPCTL_MPS_16            (2<<0)<br>+#define    DIEPCTL_MPS_8            (3<<0)<br>+<br>+#define    DOEPCTL_EPENA            (1<<31)<br>+#define    DOEPCTL_EPDIS            (1<<30)<br>+#define    DOEPCTL_SETD1PID        (1<<29)<br>+#define    DOEPCTL_SETD0PID        (1<<28)<br>+#define    DOEPCTL_SNAK            (1<<27)<br>+#define    DOEPCTL_CNAK            (1<<26)<br>+#define    DOEPCTL_FNUM_SET(n)        (((n) & 15) << 22)<br>+#define    DOEPCTL_STALL            (1<<21)<br>+#define    DOEPCTL_EPTYPE_SHIFT        18<br>+#define    DOEPCTL_EPTYPE_MASK        0x000c0000<br>+#define    DOEPCTL_EPTYPE_SET(n)        (((n) & 3) << 18)<br>+#define    DOEPCTL_NAKSTS            (1<<17)<br>+#define    DOEPCTL_USBACTEP        (1<<15)<br>+#define    DOEPCTL_MPS_SHIFT        0<br>+#define    DOEPCTL_MPS_MASK        0x000007ff<br>+#define    DOEPCTL_MPS_SET(n)        ((n) & 0x7FF)<br>+#define    DOEPCTL_MPS_64            (0<<0)<br>+#define    DOEPCTL_MPS_32            (1<<0)<br>+#define    DOEPCTL_MPS_16            (2<<0)<br>+#define    DOEPCTL_MPS_8            (3<<0)<br>+<br>+/* common bits */<br>+#define    DXEPINT_TXFEMP            (1<<7)<br>+#define    DXEPINT_SETUP            (1<<3)<br>+#define    DXEPINT_XFER_COMPL        (1<<0)<br>+<br>+#define    DIEPTSIZ_XFERSIZE_MASK        0x0007ffff<br>+#define    DIEPTSIZ_XFERSIZE_SHIFT        0<br>+#define    DIEPTSIZ_PKTCNT_MASK        0x1ff80000<br>+#define    DIEPTSIZ_PKTCNT_SHIFT        19<br>+#define    DIEPTSIZ_MC_MASK        0x60000000<br>+#define    DIEPTSIZ_MC_SHIFT        29<br>+<br>+#define    DOEPTSIZ_XFERSIZE_MASK        0x0007ffff<br>+#define    DOEPTSIZ_XFERSIZE_SHIFT        0<br>+#define    DOEPTSIZ_PKTCNT_MASK        0x1ff80000<br>+#define    DOEPTSIZ_PKTCNT_SHIFT        19<br>+#define    DOEPTSIZ_MC_MASK        0x60000000<br>+#define    DOEPTSIZ_MC_SHIFT        29<br>+<br>+/* common bits */<br>+#define    DXEPTSIZ_SET_MULTI(n)        (((n) & 3) << 29)<br>+#define    DXEPTSIZ_SET_NPKT(n)        (((n) & 0x3FF) << 19)<br>+#define    DXEPTSIZ_GET_NPKT(n)        (((n) >> 19) & 0x3FF)<br>+#define    DXEPTSIZ_SET_NBYTES(n)        (((n) & 0x7FFFFF) << 0)<br>+#define    DXEPTSIZ_GET_NBYTES(n)        (((n) >> 0) & 0x7FFFFF)<br>+<br>+/* generic endpoint mask */<br>+<br>+#define    ENDPOINT_MASK(x,in) \<br>+    ((in) ? (1U << ((x) & 15U)) : \<br>+     (0x10000U << ((x) & 15U)))<br>+<br>+#endif                    /* _DWC_OTGREG_H_ */<br>diff --git a/freebsd/sys/dev/usb/usb.h b/freebsd/sys/dev/usb/usb.h<br>index bb5a60c..c090d71 100644<br>--- a/freebsd/sys/dev/usb/usb.h<br>+++ b/freebsd/sys/dev/usb/usb.h<br>@@ -572,6 +572,15 @@ static const struct name name = {    \<br>   .bData = { m },            \<br> }<br> <br>+#ifdef __rtems__<br>+struct usb_string_lang {<br>+    uByte bLength;<br>+    uByte bDescriptorType;<br>+    uByte bData[2];<br>+} __packed;<br>+typedef struct usb_string_lang usb_string_lang_t;<br>+#endif<br>+<br> struct usb_hub_descriptor {<br>     uByte    bDescLength;<br>     uByte    bDescriptorType;<br>diff --git a/freebsd/sys/dev/usb/usb_bus.h b/freebsd/sys/dev/usb/usb_bus.h<br>index 0a7350c..e3d546f 100644<br>--- a/freebsd/sys/dev/usb/usb_bus.h<br>+++ b/freebsd/sys/dev/usb/usb_bus.h<br>@@ -85,6 +85,9 @@ struct usb_bus {<br>      * This mutex protects the USB hardware:<br>      */<br>     struct mtx bus_mtx;<br>+    #ifdef __rtems__<br>+    struct mtx bus_spin_lock;<br>+    #endif<br>     struct usb_xfer_queue intr_q;<br>     struct usb_callout power_wdog;    /* power management */<br> <br>diff --git a/freebsd/sys/dev/usb/usb_core.c b/freebsd/sys/dev/usb/usb_core.c<br>index 80f5ecd..8d5c609 100644<br>--- a/freebsd/sys/dev/usb/usb_core.c<br>+++ b/freebsd/sys/dev/usb/usb_core.c<br>@@ -54,6 +54,13 @@<br> #include <dev/usb/usb.h><br> #include <dev/usb/usbdi.h><br> <br>+#ifdef __rtems__<br>+const struct usb_string_lang usb_string_lang_en = {<br>+    sizeof(usb_string_lang_en), UDESC_STRING,<br>+    { 0x09, 0x04 } /* American English */<br>+};<br>+#endif<br>+<br> MALLOC_DEFINE(M_USB, "USB", "USB");<br> MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");<br> MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");<br>diff --git a/freebsd/sys/dev/usb/usb_core.h b/freebsd/sys/dev/usb/usb_core.h<br>index 287e69f..8a2ab19 100644<br>--- a/freebsd/sys/dev/usb/usb_core.h<br>+++ b/freebsd/sys/dev/usb/usb_core.h<br>@@ -44,6 +44,11 @@<br> #define    USB_BUS_LOCK(_b)        mtx_lock(&(_b)->bus_mtx)<br> #define    USB_BUS_UNLOCK(_b)        mtx_unlock(&(_b)->bus_mtx)<br> #define    USB_BUS_LOCK_ASSERT(_b, _t)    mtx_assert(&(_b)->bus_mtx, _t)<br>+#ifdef __rtems__<br>+#define    USB_BUS_SPIN_LOCK(_b)        mtx_lock_spin(&(_b)->bus_spin_lock)<br>+#define    USB_BUS_SPIN_UNLOCK(_b)        mtx_unlock_spin(&(_b)->bus_spin_lock)<br>+#define    USB_BUS_SPIN_LOCK_ASSERT(_b, _t)    mtx_assert(&(_b)->bus_spin_lock, _t)<br>+#endif<br> #define    USB_XFER_LOCK(_x)        mtx_lock((_x)->xroot->xfer_mtx)<br> #define    USB_XFER_UNLOCK(_x)        mtx_unlock((_x)->xroot->xfer_mtx)<br> #define    USB_XFER_LOCK_ASSERT(_x, _t)    mtx_assert((_x)->xroot->xfer_mtx, _t)<br>@@ -176,6 +181,9 @@ struct usb_xfer {<br> /* external variables */<br> <br> extern struct mtx usb_ref_lock;<br>+#ifdef __rtems__<br>+extern const struct usb_string_lang usb_string_lang_en;<br>+#endif<br> <br> /* typedefs */<br> <br>diff --git a/rtemsbsd/include/bsp/nexus-devices.h b/rtemsbsd/include/bsp/nexus-devices.h<br>index 6ccf726..58e26b2 100644<br>--- a/rtemsbsd/include/bsp/nexus-devices.h<br>+++ b/rtemsbsd/include/bsp/nexus-devices.h<br>@@ -125,6 +125,25 @@ SYSINIT_DRIVER_REFERENCE(lem, pci);<br> SYSINIT_DRIVER_REFERENCE(igb, pci);<br> SYSINIT_DRIVER_REFERENCE(em, pci);<br> <br>+#elif defined(LIBBSP_ARM_RASPBERRYPI_BSP_H)<br>+<br>+#include <bsp/irq.h><br>+<br>+static const rtems_bsd_device_resource bcm283x_dwcotg_res[] = {<br>+    {<br>+        .type = RTEMS_BSD_RES_MEMORY,<br>+        .start_request = 0,<br>+        .start_actual = 0x00980000<br>+    }, {<br>+        .type = RTEMS_BSD_RES_IRQ,<br>+        .start_request = 0,<br>+        .start_actual = 17<br>+    }<br>+};<br>+<br>+RTEMS_BSD_DEFINE_NEXUS_DEVICE(bcm283x_dwcotg, 0, RTEMS_ARRAY_SIZE(bcm283x_dwcotg_res),<br>+    &bcm283x_dwcotg_res[0]);<br>+<br> #elif defined(LIBBSP_POWERPC_QORIQ_BSP_H)<br> <br> #if !QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)<br>diff --git a/rtemsbsd/include/machine/rtems-bsd-sysinit.h b/rtemsbsd/include/machine/rtems-bsd-sysinit.h<br>index c8af236..3e2fc02 100644<br>--- a/rtemsbsd/include/machine/rtems-bsd-sysinit.h<br>+++ b/rtemsbsd/include/machine/rtems-bsd-sysinit.h<br>@@ -56,6 +56,9 @@<br>     SYSINIT_DRIVER_REFERENCE(ehci, nexus); \<br>     SYSINIT_DRIVER_REFERENCE(usbus, ehci)<br> <br>+#define SYSINIT_NEED_USB_BCM283X_DWC_OTG \<br>+    SYSINIT_DRIVER_REFERENCE(bcm283x_dwcotg, nexus)<br>+<br> #define SYSINIT_NEED_USB_MASS_STORAGE \<br>     SYSINIT_DRIVER_REFERENCE(umass, uhub)<br> <br>diff --git a/wscript b/wscript<br>index 8c0c242..85de476 100644<br>--- a/wscript<br>+++ b/wscript<br>@@ -626,6 +626,7 @@ def build(bld):<br>     libbsd_use += ["objs06"]<br> <br>     source = ['freebsd/sys/arm/xilinx/zy7_slcr.c',<br>+              'freebsd/sys/arm/broadcom/bcm2835/bcm283x_dwc_fdt.c',<br>               'freebsd/sys/cam/cam.c',<br>               'freebsd/sys/cam/scsi/scsi_all.c',<br>               'freebsd/sys/contrib/altq/altq/altq_cbq.c',<br>@@ -710,6 +711,8 @@ def build(bld):<br>               'freebsd/sys/dev/sdhci/sdhci.c',<br>               'freebsd/sys/dev/smc/if_smc.c',<br>               'freebsd/sys/dev/tsec/if_tsec.c',<br>+              'freebsd/sys/dev/usb/controller/dwc_otg.c',<br>+              'freebsd/sys/dev/usb/controller/dwc_otg_fdt.c',<br>               'freebsd/sys/dev/usb/controller/ehci.c',<br>               'freebsd/sys/dev/usb/controller/ohci.c',<br>               'freebsd/sys/dev/usb/controller/usb_controller.c',<br>-- <br>1.7.1<br><br><br></div>