summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/usb
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 11:33:00 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-04 15:28:21 +0100
commitaf5333e0a02b2295304d4e029b15ee15a4fe2b3a (patch)
treec5c43680d374f58b487eeeaf18fb7ec6b84ba074 /freebsd/sys/dev/usb
parentBUS_SPACE(9): Use simple memory model for ARM (diff)
downloadrtems-libbsd-af5333e0a02b2295304d4e029b15ee15a4fe2b3a.tar.bz2
Update to FreeBSD 8.4
Diffstat (limited to 'freebsd/sys/dev/usb')
-rw-r--r--freebsd/sys/dev/usb/controller/ehci.c375
-rw-r--r--freebsd/sys/dev/usb/controller/ehci.h12
-rw-r--r--freebsd/sys/dev/usb/controller/ohci.c117
-rw-r--r--freebsd/sys/dev/usb/controller/ohci.h11
-rw-r--r--freebsd/sys/dev/usb/controller/ohcireg.h7
-rw-r--r--freebsd/sys/dev/usb/controller/usb_controller.c331
-rw-r--r--freebsd/sys/dev/usb/quirk/usb_quirk.c84
-rw-r--r--freebsd/sys/dev/usb/quirk/usb_quirk.h12
-rw-r--r--freebsd/sys/dev/usb/storage/umass.c91
-rw-r--r--freebsd/sys/dev/usb/usb.h50
-rw-r--r--freebsd/sys/dev/usb/usb_bus.h18
-rw-r--r--freebsd/sys/dev/usb/usb_busdma.c19
-rw-r--r--freebsd/sys/dev/usb/usb_cdc.h7
-rw-r--r--freebsd/sys/dev/usb/usb_controller.h64
-rw-r--r--freebsd/sys/dev/usb/usb_core.c1
-rw-r--r--freebsd/sys/dev/usb/usb_debug.c137
-rw-r--r--freebsd/sys/dev/usb/usb_debug.h24
-rw-r--r--freebsd/sys/dev/usb/usb_dev.c88
-rw-r--r--freebsd/sys/dev/usb/usb_dev.h1
-rw-r--r--freebsd/sys/dev/usb/usb_device.c396
-rw-r--r--freebsd/sys/dev/usb/usb_device.h86
-rw-r--r--freebsd/sys/dev/usb/usb_dynamic.c1
-rw-r--r--freebsd/sys/dev/usb/usb_error.c1
-rw-r--r--freebsd/sys/dev/usb/usb_freebsd.h5
-rw-r--r--freebsd/sys/dev/usb/usb_generic.c76
-rw-r--r--freebsd/sys/dev/usb/usb_handle_request.c36
-rw-r--r--freebsd/sys/dev/usb/usb_hid.c51
-rw-r--r--freebsd/sys/dev/usb/usb_hub.c363
-rw-r--r--freebsd/sys/dev/usb/usb_hub.h14
-rw-r--r--freebsd/sys/dev/usb/usb_ioctl.h44
-rw-r--r--freebsd/sys/dev/usb/usb_lookup.c115
-rw-r--r--freebsd/sys/dev/usb/usb_mbuf.c1
-rw-r--r--freebsd/sys/dev/usb/usb_msctest.c186
-rw-r--r--freebsd/sys/dev/usb/usb_msctest.h2
-rw-r--r--freebsd/sys/dev/usb/usb_parse.c1
-rw-r--r--freebsd/sys/dev/usb/usb_pf.h120
-rw-r--r--freebsd/sys/dev/usb/usb_process.c24
-rw-r--r--freebsd/sys/dev/usb/usb_process.h6
-rw-r--r--freebsd/sys/dev/usb/usb_request.c365
-rw-r--r--freebsd/sys/dev/usb/usb_request.h6
-rw-r--r--freebsd/sys/dev/usb/usb_transfer.c260
-rw-r--r--freebsd/sys/dev/usb/usb_util.c23
-rw-r--r--freebsd/sys/dev/usb/usbdi.h54
-rw-r--r--freebsd/sys/dev/usb/usbhid.h6
44 files changed, 2514 insertions, 1177 deletions
diff --git a/freebsd/sys/dev/usb/controller/ehci.c b/freebsd/sys/dev/usb/controller/ehci.c
index 8a98f608..d126e9a9 100644
--- a/freebsd/sys/dev/usb/controller/ehci.c
+++ b/freebsd/sys/dev/usb/controller/ehci.c
@@ -56,7 +56,6 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -98,20 +97,20 @@ static int ehciiaadbug = 0;
static int ehcilostintrbug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
&ehcidebug, 0, "Debug level");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, no_hs, CTLFLAG_RW,
- &ehcinohighspeed, 0, "Disable High Speed USB");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, iaadbug, CTLFLAG_RW,
- &ehciiaadbug, 0, "Enable doorbell bug workaround");
-SYSCTL_INT(_hw_usb_ehci, OID_AUTO, lostintrbug, CTLFLAG_RW,
- &ehcilostintrbug, 0, "Enable lost interrupt bug workaround");
-
TUNABLE_INT("hw.usb.ehci.debug", &ehcidebug);
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, no_hs, CTLFLAG_RW | CTLFLAG_TUN,
+ &ehcinohighspeed, 0, "Disable High Speed USB");
TUNABLE_INT("hw.usb.ehci.no_hs", &ehcinohighspeed);
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, iaadbug, CTLFLAG_RW | CTLFLAG_TUN,
+ &ehciiaadbug, 0, "Enable doorbell bug workaround");
TUNABLE_INT("hw.usb.ehci.iaadbug", &ehciiaadbug);
+SYSCTL_INT(_hw_usb_ehci, OID_AUTO, lostintrbug, CTLFLAG_RW | CTLFLAG_TUN,
+ &ehcilostintrbug, 0, "Enable lost interrupt bug workaround");
TUNABLE_INT("hw.usb.ehci.lostintrbug", &ehcilostintrbug);
+
static void ehci_dump_regs(ehci_softc_t *sc);
static void ehci_dump_sqh(ehci_softc_t *sc, ehci_qh_t *sqh);
@@ -191,7 +190,7 @@ ehci_reset(ehci_softc_t *sc)
EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
for (i = 0; i < 100; i++) {
- usb_pause_mtx(NULL, hz / 1000);
+ usb_pause_mtx(NULL, hz / 128);
hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET;
if (!hcr) {
if (sc->sc_flags & (EHCI_SCFLG_SETMODE | EHCI_SCFLG_BIGEMMIO)) {
@@ -215,7 +214,7 @@ ehci_reset(ehci_softc_t *sc)
return (0);
}
}
- device_printf(sc->sc_bus.bdev, "reset timeout\n");
+ device_printf(sc->sc_bus.bdev, "Reset timeout\n");
return (USB_ERR_IOERROR);
}
@@ -227,7 +226,7 @@ ehci_hcreset(ehci_softc_t *sc)
EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
for (i = 0; i < 100; i++) {
- usb_pause_mtx(NULL, hz / 1000);
+ usb_pause_mtx(NULL, hz / 128);
hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
if (hcr)
break;
@@ -240,7 +239,60 @@ ehci_hcreset(ehci_softc_t *sc)
*/
device_printf(sc->sc_bus.bdev, "stop timeout\n");
- return ehci_reset(sc);
+ return (ehci_reset(sc));
+}
+
+static int
+ehci_init_sub(struct ehci_softc *sc)
+{
+ struct usb_page_search buf_res;
+ uint32_t cparams;
+ uint32_t hcr;
+ uint8_t i;
+
+ cparams = EREAD4(sc, EHCI_HCCPARAMS);
+
+ DPRINTF("cparams=0x%x\n", cparams);
+
+ if (EHCI_HCC_64BIT(cparams)) {
+ DPRINTF("HCC uses 64-bit structures\n");
+
+ /* MUST clear segment register if 64 bit capable */
+ EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
+ }
+
+ usbd_get_page(&sc->sc_hw.pframes_pc, 0, &buf_res);
+ EOWRITE4(sc, EHCI_PERIODICLISTBASE, buf_res.physaddr);
+
+ usbd_get_page(&sc->sc_hw.async_start_pc, 0, &buf_res);
+ EOWRITE4(sc, EHCI_ASYNCLISTADDR, buf_res.physaddr | EHCI_LINK_QH);
+
+ /* enable interrupts */
+ EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+
+ /* turn on controller */
+ EOWRITE4(sc, EHCI_USBCMD,
+ EHCI_CMD_ITC_1 | /* 1 microframes interrupt delay */
+ (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
+ EHCI_CMD_ASE |
+ EHCI_CMD_PSE |
+ EHCI_CMD_RS);
+
+ /* Take over port ownership */
+ EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
+
+ for (i = 0; i < 100; i++) {
+ usb_pause_mtx(NULL, hz / 128);
+ hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
+ if (!hcr) {
+ break;
+ }
+ }
+ if (hcr) {
+ device_printf(sc->sc_bus.bdev, "Run timeout\n");
+ return (USB_ERR_IOERROR);
+ }
+ return (USB_ERR_NORMAL_COMPLETION);
}
usb_error_t
@@ -249,8 +301,6 @@ ehci_init(ehci_softc_t *sc)
struct usb_page_search buf_res;
uint32_t version;
uint32_t sparams;
- uint32_t cparams;
- uint32_t hcr;
uint16_t i;
uint16_t x;
uint16_t y;
@@ -262,6 +312,8 @@ ehci_init(ehci_softc_t *sc)
usb_callout_init_mtx(&sc->sc_tmo_pcd, &sc->sc_bus.bus_mtx, 0);
usb_callout_init_mtx(&sc->sc_tmo_poll, &sc->sc_bus.bus_mtx, 0);
+ sc->sc_offs = EHCI_CAPLENGTH(EREAD4(sc, EHCI_CAPLEN_HCIVERSION));
+
#ifdef USB_DEBUG
if (ehciiaadbug)
sc->sc_flags |= EHCI_SCFLG_IAADBUG;
@@ -272,8 +324,6 @@ ehci_init(ehci_softc_t *sc)
}
#endif
- sc->sc_offs = EHCI_CAPLENGTH(EREAD4(sc, EHCI_CAPLEN_HCIVERSION));
-
version = EHCI_HCIVERSION(EREAD4(sc, EHCI_CAPLEN_HCIVERSION));
device_printf(sc->sc_bus.bdev, "EHCI version %x.%x\n",
version >> 8, version & 0xff);
@@ -282,15 +332,6 @@ ehci_init(ehci_softc_t *sc)
DPRINTF("sparams=0x%x\n", sparams);
sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
- cparams = EREAD4(sc, EHCI_HCCPARAMS);
- DPRINTF("cparams=0x%x\n", cparams);
-
- if (EHCI_HCC_64BIT(cparams)) {
- DPRINTF("HCC uses 64-bit structures\n");
-
- /* MUST clear segment register if 64 bit capable */
- EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
- }
sc->sc_bus.usbrev = USB_REV_2_0;
/* Reset the controller */
@@ -467,9 +508,6 @@ ehci_init(ehci_softc_t *sc)
[i & (EHCI_VIRTUAL_FRAMELIST_COUNT - 1)]->itd_self;
}
}
- /* setup sync list pointer */
- EOWRITE4(sc, EHCI_PERIODICLISTBASE, buf_res.physaddr);
-
usbd_get_page(&sc->sc_hw.async_start_pc, 0, &buf_res);
if (1) {
@@ -514,35 +552,8 @@ ehci_init(ehci_softc_t *sc)
}
#endif
- /* setup async list pointer */
- EOWRITE4(sc, EHCI_ASYNCLISTADDR, buf_res.physaddr | EHCI_LINK_QH);
-
-
- /* enable interrupts */
- EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
-
- /* turn on controller */
- EOWRITE4(sc, EHCI_USBCMD,
- EHCI_CMD_ITC_1 | /* 1 microframes interrupt delay */
- (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
- EHCI_CMD_ASE |
- EHCI_CMD_PSE |
- EHCI_CMD_RS);
-
- /* Take over port ownership */
- EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
-
- for (i = 0; i < 100; i++) {
- usb_pause_mtx(NULL, hz / 1000);
- hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
- if (!hcr) {
- break;
- }
- }
- if (hcr) {
- device_printf(sc->sc_bus.bdev, "run timeout\n");
- return (USB_ERR_IOERROR);
- }
+ /* finial setup */
+ err = ehci_init_sub(sc);
if (!err) {
/* catch any lost interrupts */
@@ -576,137 +587,28 @@ ehci_detach(ehci_softc_t *sc)
usb_callout_drain(&sc->sc_tmo_poll);
}
-void
+static void
ehci_suspend(ehci_softc_t *sc)
{
- uint32_t cmd;
- uint32_t hcr;
- uint8_t i;
-
- USB_BUS_LOCK(&sc->sc_bus);
-
- for (i = 1; i <= sc->sc_noport; i++) {
- cmd = EOREAD4(sc, EHCI_PORTSC(i));
- if (((cmd & EHCI_PS_PO) == 0) &&
- ((cmd & EHCI_PS_PE) == EHCI_PS_PE)) {
- EOWRITE4(sc, EHCI_PORTSC(i),
- cmd | EHCI_PS_SUSP);
- }
- }
-
- sc->sc_cmd = EOREAD4(sc, EHCI_USBCMD);
-
- cmd = sc->sc_cmd & ~(EHCI_CMD_ASE | EHCI_CMD_PSE);
- EOWRITE4(sc, EHCI_USBCMD, cmd);
-
- for (i = 0; i < 100; i++) {
- hcr = EOREAD4(sc, EHCI_USBSTS) &
- (EHCI_STS_ASS | EHCI_STS_PSS);
-
- if (hcr == 0) {
- break;
- }
- usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000);
- }
-
- if (hcr != 0) {
- device_printf(sc->sc_bus.bdev, "reset timeout\n");
- }
- cmd &= ~EHCI_CMD_RS;
- EOWRITE4(sc, EHCI_USBCMD, cmd);
-
- for (i = 0; i < 100; i++) {
- hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
- if (hcr == EHCI_STS_HCH) {
- break;
- }
- usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000);
- }
+ DPRINTF("stopping the HC\n");
- if (hcr != EHCI_STS_HCH) {
- device_printf(sc->sc_bus.bdev,
- "config timeout\n");
- }
- USB_BUS_UNLOCK(&sc->sc_bus);
+ /* reset HC */
+ ehci_hcreset(sc);
}
-void
+static void
ehci_resume(ehci_softc_t *sc)
{
- struct usb_page_search buf_res;
- uint32_t cmd;
- uint32_t hcr;
- uint8_t i;
-
- USB_BUS_LOCK(&sc->sc_bus);
-
- /* restore things in case the bios doesn't */
- EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
-
- usbd_get_page(&sc->sc_hw.pframes_pc, 0, &buf_res);
- EOWRITE4(sc, EHCI_PERIODICLISTBASE, buf_res.physaddr);
-
- usbd_get_page(&sc->sc_hw.async_start_pc, 0, &buf_res);
- EOWRITE4(sc, EHCI_ASYNCLISTADDR, buf_res.physaddr | EHCI_LINK_QH);
-
- EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
-
- hcr = 0;
- for (i = 1; i <= sc->sc_noport; i++) {
- cmd = EOREAD4(sc, EHCI_PORTSC(i));
- if (((cmd & EHCI_PS_PO) == 0) &&
- ((cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP)) {
- EOWRITE4(sc, EHCI_PORTSC(i),
- cmd | EHCI_PS_FPR);
- hcr = 1;
- }
- }
-
- if (hcr) {
- usb_pause_mtx(&sc->sc_bus.bus_mtx,
- USB_MS_TO_TICKS(USB_RESUME_WAIT));
-
- for (i = 1; i <= sc->sc_noport; i++) {
- cmd = EOREAD4(sc, EHCI_PORTSC(i));
- if (((cmd & EHCI_PS_PO) == 0) &&
- ((cmd & EHCI_PS_SUSP) == EHCI_PS_SUSP)) {
- EOWRITE4(sc, EHCI_PORTSC(i),
- cmd & ~EHCI_PS_FPR);
- }
- }
- }
- EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd);
-
- for (i = 0; i < 100; i++) {
- hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
- if (hcr != EHCI_STS_HCH) {
- break;
- }
- usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000);
- }
- if (hcr == EHCI_STS_HCH) {
- device_printf(sc->sc_bus.bdev, "config timeout\n");
- }
-
- USB_BUS_UNLOCK(&sc->sc_bus);
+ /* reset HC */
+ ehci_hcreset(sc);
- usb_pause_mtx(NULL,
- USB_MS_TO_TICKS(USB_RESUME_WAIT));
+ /* setup HC */
+ ehci_init_sub(sc);
/* catch any lost interrupts */
ehci_do_poll(&sc->sc_bus);
}
-void
-ehci_shutdown(ehci_softc_t *sc)
-{
- DPRINTF("stopping the HC\n");
-
- if (ehci_hcreset(sc)) {
- DPRINTF("reset failed!\n");
- }
-}
-
#ifdef USB_DEBUG
static void
ehci_dump_regs(ehci_softc_t *sc)
@@ -1183,6 +1085,28 @@ _ehci_remove_qh(ehci_qh_t *sqh, ehci_qh_t *last)
return (last);
}
+static void
+ehci_data_toggle_update(struct usb_xfer *xfer, uint16_t actlen, uint16_t xlen)
+{
+ uint16_t rem;
+ uint8_t dt;
+
+ /* count number of full packets */
+ dt = (actlen / xfer->max_packet_size) & 1;
+
+ /* compute remainder */
+ rem = actlen % xfer->max_packet_size;
+
+ if (rem > 0)
+ dt ^= 1; /* short packet at the end */
+ else if (actlen != xlen)
+ dt ^= 1; /* zero length packet at the end */
+ else if (xlen == 0)
+ dt ^= 1; /* zero length transfer */
+
+ xfer->endpoint->toggle_next ^= dt;
+}
+
static usb_error_t
ehci_non_isoc_done_sub(struct usb_xfer *xfer)
{
@@ -1216,7 +1140,10 @@ ehci_non_isoc_done_sub(struct usb_xfer *xfer)
status |= EHCI_QTD_HALTED;
} else if (xfer->aframes != xfer->nframes) {
xfer->frlengths[xfer->aframes] += td->len - len;
+ /* manually update data toggle */
+ ehci_data_toggle_update(xfer, td->len - len, td->len);
}
+
/* Check for last transfer */
if (((void *)td) == xfer->td_transfer_last) {
td = NULL;
@@ -1298,9 +1225,6 @@ ehci_non_isoc_done(struct usb_xfer *xfer)
status = hc32toh(sc, qh->qh_qtd.qtd_status);
- xfer->endpoint->toggle_next =
- (status & EHCI_QTD_TOGGLE_MASK) ? 1 : 0;
-
/* reset scanner */
xfer->td_transfer_cache = xfer->td_transfer_first;
@@ -1879,6 +1803,8 @@ ehci_setup_standard_chain(struct usb_xfer *xfer, ehci_qh_t **qh_last)
if (xfer->flags_int.control_xfr) {
if (xfer->flags_int.control_hdr) {
+ xfer->endpoint->toggle_next = 0;
+
temp.qtd_status &=
htohc32(temp.sc, EHCI_QTD_SET_CERR(3));
temp.qtd_status |= htohc32(temp.sc,
@@ -2474,9 +2400,9 @@ ehci_device_isoc_fs_open(struct usb_xfer *xfer)
EHCI_SITD_SET_HUBA(xfer->xroot->udev->hs_hub_addr) |
EHCI_SITD_SET_PORT(xfer->xroot->udev->hs_port_no);
- if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) {
+ if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN)
sitd_portaddr |= EHCI_SITD_SET_DIR_IN;
- }
+
sitd_portaddr = htohc32(sc, sitd_portaddr);
/* initialize all TD's */
@@ -2512,9 +2438,6 @@ ehci_device_isoc_fs_enter(struct usb_xfer *xfer)
{
struct usb_page_search buf_res;
ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus);
- struct usb_fs_isoc_schedule *fss_start;
- struct usb_fs_isoc_schedule *fss_end;
- struct usb_fs_isoc_schedule *fss;
ehci_sitd_t *td;
ehci_sitd_t *td_last = NULL;
ehci_sitd_t **pp_last;
@@ -2526,7 +2449,6 @@ ehci_device_isoc_fs_enter(struct usb_xfer *xfer)
uint16_t tlen;
uint8_t sa;
uint8_t sb;
- uint8_t error;
#ifdef USB_DEBUG
uint8_t once = 1;
@@ -2571,9 +2493,8 @@ ehci_device_isoc_fs_enter(struct usb_xfer *xfer)
* pre-compute when the isochronous transfer will be finished:
*/
xfer->isoc_time_complete =
- usbd_fs_isoc_schedule_isoc_time_expand
- (xfer->xroot->udev, &fss_start, &fss_end, nframes) + buf_offset +
- xfer->nframes;
+ usb_isoc_time_expand(&sc->sc_bus, nframes) +
+ buf_offset + xfer->nframes;
/* get the real number of frames */
@@ -2596,19 +2517,14 @@ ehci_device_isoc_fs_enter(struct usb_xfer *xfer)
xfer->qh_pos = xfer->endpoint->isoc_next;
- fss = fss_start + (xfer->qh_pos % USB_ISOC_TIME_MAX);
-
while (nframes--) {
if (td == NULL) {
panic("%s:%d: out of TD's\n",
__FUNCTION__, __LINE__);
}
- if (pp_last >= &sc->sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) {
+ if (pp_last >= &sc->sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT])
pp_last = &sc->sc_isoc_fs_p_last[0];
- }
- if (fss >= fss_end) {
- fss = fss_start;
- }
+
/* reuse sitd_portaddr and sitd_back from last transfer */
if (*plen > xfer->max_frame_size) {
@@ -2623,17 +2539,19 @@ ehci_device_isoc_fs_enter(struct usb_xfer *xfer)
#endif
*plen = xfer->max_frame_size;
}
- /*
- * We currently don't care if the ISOCHRONOUS schedule is
- * full!
- */
- error = usbd_fs_isoc_schedule_alloc(fss, &sa, *plen);
- if (error) {
+
+ /* allocate a slot */
+
+ sa = usbd_fs_isoc_schedule_alloc_slot(xfer,
+ xfer->isoc_time_complete - nframes - 1);
+
+ if (sa == 255) {
/*
- * The FULL speed schedule is FULL! Set length
- * to zero.
+ * Schedule is FULL, set length to zero:
*/
+
*plen = 0;
+ sa = USB_FS_ISOC_UFRAME_MAX - 1;
}
if (*plen) {
/*
@@ -2713,7 +2631,6 @@ ehci_device_isoc_fs_enter(struct usb_xfer *xfer)
pp_last++;
plen++;
- fss++;
td_last = td;
td = td->obj_next;
}
@@ -2723,11 +2640,29 @@ ehci_device_isoc_fs_enter(struct usb_xfer *xfer)
/* update isoc_next */
xfer->endpoint->isoc_next = (pp_last - &sc->sc_isoc_fs_p_last[0]) &
(EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
+
+ /*
+ * We don't allow cancelling of the SPLIT transaction USB FULL
+ * speed transfer, because it disturbs the bandwidth
+ * computation algorithm.
+ */
+ xfer->flags_int.can_cancel_immed = 0;
}
static void
ehci_device_isoc_fs_start(struct usb_xfer *xfer)
{
+ /*
+ * We don't allow cancelling of the SPLIT transaction USB FULL
+ * speed transfer, because it disturbs the bandwidth
+ * computation algorithm.
+ */
+ xfer->flags_int.can_cancel_immed = 0;
+
+ /* set a default timeout */
+ if (xfer->timeout == 0)
+ xfer->timeout = 500; /* ms */
+
/* put transfer on interrupt queue */
ehci_transfer_intr_enqueue(xfer);
}
@@ -3087,13 +3022,8 @@ static const struct ehci_config_desc ehci_confd = {
static const
struct usb_hub_descriptor ehci_hubd =
{
- 0, /* dynamic length */
- UDESC_HUB,
- 0,
- {0, 0},
- 0,
- 0,
- {0},
+ .bDescLength = 0, /* dynamic length */
+ .bDescriptorType = UDESC_HUB,
};
static void
@@ -3348,7 +3278,7 @@ ehci_roothub_exec(struct usb_device *udev,
break;
case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
len = 16;
- bzero(sc->sc_hub_desc.temp, 16);
+ memset(sc->sc_hub_desc.temp, 0, 16);
break;
case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
DPRINTFN(9, "get port status i=%d\n",
@@ -3441,7 +3371,7 @@ ehci_roothub_exec(struct usb_device *udev,
/* Wait for reset to complete. */
usb_pause_mtx(&sc->sc_bus.bus_mtx,
- USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY));
+ USB_MS_TO_TICKS(usb_port_root_reset_delay));
/* Terminate reset sequence. */
if (!(sc->sc_flags & EHCI_SCFLG_NORESTERM))
@@ -3887,8 +3817,24 @@ ehci_device_suspend(struct usb_device *udev)
}
USB_BUS_UNLOCK(udev->bus);
+}
- return;
+static void
+ehci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
+{
+ struct ehci_softc *sc = EHCI_BUS2SC(bus);
+
+ switch (state) {
+ case USB_HW_POWER_SUSPEND:
+ case USB_HW_POWER_SHUTDOWN:
+ ehci_suspend(sc);
+ break;
+ case USB_HW_POWER_RESUME:
+ ehci_resume(sc);
+ break;
+ default:
+ break;
+ }
}
static void
@@ -3934,6 +3880,7 @@ struct usb_bus_methods ehci_bus_methods =
.device_resume = ehci_device_resume,
.device_suspend = ehci_device_suspend,
.set_hw_power = ehci_set_hw_power,
+ .set_hw_power_sleep = ehci_set_hw_power_sleep,
.roothub_exec = ehci_roothub_exec,
.xfer_poll = ehci_do_poll,
};
diff --git a/freebsd/sys/dev/usb/controller/ehci.h b/freebsd/sys/dev/usb/controller/ehci.h
index 19d32426..a64d48a0 100644
--- a/freebsd/sys/dev/usb/controller/ehci.h
+++ b/freebsd/sys/dev/usb/controller/ehci.h
@@ -14,13 +14,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -340,8 +333,6 @@ typedef struct ehci_softc {
uint32_t sc_terminate_self; /* TD short packet termination pointer */
uint32_t sc_eintrs;
- uint32_t sc_cmd; /* shadow of cmd register during
- * suspend */
uint16_t sc_intr_stat[EHCI_VIRTUAL_FRAMELIST_COUNT];
uint16_t sc_id_vendor; /* vendor ID for root hub */
@@ -478,9 +469,6 @@ usb_bus_mem_cb_t ehci_iterate_hw_softc;
usb_error_t ehci_reset(ehci_softc_t *sc);
usb_error_t ehci_init(ehci_softc_t *sc);
void ehci_detach(struct ehci_softc *sc);
-void ehci_suspend(struct ehci_softc *sc);
-void ehci_resume(struct ehci_softc *sc);
-void ehci_shutdown(ehci_softc_t *sc);
void ehci_interrupt(ehci_softc_t *sc);
#endif /* _EHCI_H_ */
diff --git a/freebsd/sys/dev/usb/controller/ohci.c b/freebsd/sys/dev/usb/controller/ohci.c
index 6390156a..19ecf296 100644
--- a/freebsd/sys/dev/usb/controller/ohci.c
+++ b/freebsd/sys/dev/usb/controller/ohci.c
@@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -84,9 +83,8 @@ __FBSDID("$FreeBSD$");
static int ohcidebug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci");
-SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
&ohcidebug, 0, "ohci debug level");
-
TUNABLE_INT("hw.usb.ohci.debug", &ohcidebug);
static void ohci_dumpregs(ohci_softc_t *);
@@ -169,7 +167,7 @@ ohci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
}
static usb_error_t
-ohci_controller_init(ohci_softc_t *sc)
+ohci_controller_init(ohci_softc_t *sc, int do_suspend)
{
struct usb_page_search buf_res;
uint32_t i;
@@ -236,6 +234,11 @@ reset:
}
#endif
+ if (do_suspend) {
+ OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_SUSPEND);
+ return (USB_ERR_NORMAL_COMPLETION);
+ }
+
/* The controller is now in SUSPEND state, we have 2ms to finish. */
/* set up HC registers */
@@ -418,13 +421,12 @@ ohci_init(ohci_softc_t *sc)
sc->sc_bus.usbrev = USB_REV_1_0;
- if (ohci_controller_init(sc)) {
+ if (ohci_controller_init(sc, 0) != 0)
return (USB_ERR_INVAL);
- } else {
- /* catch any lost interrupts */
- ohci_do_poll(&sc->sc_bus);
- return (USB_ERR_NORMAL_COMPLETION);
- }
+
+ /* catch any lost interrupts */
+ ohci_do_poll(&sc->sc_bus);
+ return (USB_ERR_NORMAL_COMPLETION);
}
/*
@@ -448,75 +450,32 @@ ohci_detach(struct ohci_softc *sc)
usb_callout_drain(&sc->sc_tmo_rhsc);
}
-/* NOTE: suspend/resume is called from
- * interrupt context and cannot sleep!
- */
-void
+static void
ohci_suspend(ohci_softc_t *sc)
{
- uint32_t ctl;
-
- USB_BUS_LOCK(&sc->sc_bus);
+ DPRINTF("\n");
#ifdef USB_DEBUG
- DPRINTF("\n");
- if (ohcidebug > 2) {
+ if (ohcidebug > 2)
ohci_dumpregs(sc);
- }
#endif
- ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK;
- if (sc->sc_control == 0) {
- /*
- * Preserve register values, in case that APM BIOS
- * does not recover them.
- */
- sc->sc_control = ctl;
- sc->sc_intre = OREAD4(sc, OHCI_INTERRUPT_ENABLE);
- }
- ctl |= OHCI_HCFS_SUSPEND;
- OWRITE4(sc, OHCI_CONTROL, ctl);
-
- usb_pause_mtx(&sc->sc_bus.bus_mtx,
- USB_MS_TO_TICKS(USB_RESUME_WAIT));
-
- USB_BUS_UNLOCK(&sc->sc_bus);
+ /* reset HC and leave it suspended */
+ ohci_controller_init(sc, 1);
}
-void
+static void
ohci_resume(ohci_softc_t *sc)
{
- uint32_t ctl;
+ DPRINTF("\n");
#ifdef USB_DEBUG
- DPRINTF("\n");
- if (ohcidebug > 2) {
+ if (ohcidebug > 2)
ohci_dumpregs(sc);
- }
#endif
- /* some broken BIOSes never initialize the Controller chip */
- ohci_controller_init(sc);
-
- USB_BUS_LOCK(&sc->sc_bus);
- if (sc->sc_intre) {
- OWRITE4(sc, OHCI_INTERRUPT_ENABLE,
- sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE));
- }
- if (sc->sc_control)
- ctl = sc->sc_control;
- else
- ctl = OREAD4(sc, OHCI_CONTROL);
- ctl |= OHCI_HCFS_RESUME;
- OWRITE4(sc, OHCI_CONTROL, ctl);
- usb_pause_mtx(&sc->sc_bus.bus_mtx,
- USB_MS_TO_TICKS(USB_RESUME_DELAY));
- ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL;
- OWRITE4(sc, OHCI_CONTROL, ctl);
- usb_pause_mtx(&sc->sc_bus.bus_mtx,
- USB_MS_TO_TICKS(USB_RESUME_RECOVERY));
- sc->sc_control = sc->sc_intre = 0;
- USB_BUS_UNLOCK(&sc->sc_bus);
+ /* some broken BIOSes never initialize the Controller chip */
+ ohci_controller_init(sc, 0);
/* catch any lost interrupts */
ohci_do_poll(&sc->sc_bus);
@@ -2122,13 +2081,8 @@ struct ohci_config_desc ohci_confd =
static const
struct usb_hub_descriptor ohci_hubd =
{
- 0, /* dynamic length */
- UDESC_HUB,
- 0,
- {0, 0},
- 0,
- 0,
- {0},
+ .bDescLength = 0, /* dynamic length */
+ .bDescriptorType = UDESC_HUB,
};
static usb_error_t
@@ -2350,7 +2304,7 @@ ohci_roothub_exec(struct usb_device *udev,
case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
len = 16;
- bzero(sc->sc_hub_desc.temp, 16);
+ memset(sc->sc_hub_desc.temp, 0, 16);
break;
case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
DPRINTFN(9, "get port status i=%d\n",
@@ -2391,7 +2345,7 @@ ohci_roothub_exec(struct usb_device *udev,
for (v = 0;; v++) {
if (v < 12) {
usb_pause_mtx(&sc->sc_bus.bus_mtx,
- USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY));
+ USB_MS_TO_TICKS(usb_port_root_reset_delay));
if ((OREAD4(sc, port) & UPS_RESET) == 0) {
break;
@@ -2716,6 +2670,24 @@ ohci_device_suspend(struct usb_device *udev)
}
static void
+ohci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
+{
+ struct ohci_softc *sc = OHCI_BUS2SC(bus);
+
+ switch (state) {
+ case USB_HW_POWER_SUSPEND:
+ case USB_HW_POWER_SHUTDOWN:
+ ohci_suspend(sc);
+ break;
+ case USB_HW_POWER_RESUME:
+ ohci_resume(sc);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
ohci_set_hw_power(struct usb_bus *bus)
{
struct ohci_softc *sc = OHCI_BUS2SC(bus);
@@ -2759,6 +2731,7 @@ struct usb_bus_methods ohci_bus_methods =
.device_resume = ohci_device_resume,
.device_suspend = ohci_device_suspend,
.set_hw_power = ohci_set_hw_power,
+ .set_hw_power_sleep = ohci_set_hw_power_sleep,
.roothub_exec = ohci_roothub_exec,
.xfer_poll = ohci_do_poll,
};
diff --git a/freebsd/sys/dev/usb/controller/ohci.h b/freebsd/sys/dev/usb/controller/ohci.h
index c878af07..fad1a9fe 100644
--- a/freebsd/sys/dev/usb/controller/ohci.h
+++ b/freebsd/sys/dev/usb/controller/ohci.h
@@ -15,13 +15,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -250,8 +243,6 @@ typedef struct ohci_softc {
bus_space_handle_t sc_io_hdl;
uint32_t sc_eintrs; /* enabled interrupts */
- uint32_t sc_control; /* Preserved during suspend/standby */
- uint32_t sc_intre;
uint16_t sc_intr_stat[OHCI_NO_EDS];
uint16_t sc_id_vendor;
@@ -269,8 +260,6 @@ usb_bus_mem_cb_t ohci_iterate_hw_softc;
usb_error_t ohci_init(ohci_softc_t *sc);
void ohci_detach(struct ohci_softc *sc);
-void ohci_suspend(ohci_softc_t *sc);
-void ohci_resume(ohci_softc_t *sc);
void ohci_interrupt(ohci_softc_t *sc);
#endif /* _OHCI_H_ */
diff --git a/freebsd/sys/dev/usb/controller/ohcireg.h b/freebsd/sys/dev/usb/controller/ohcireg.h
index 9127a02a..7f14875c 100644
--- a/freebsd/sys/dev/usb/controller/ohcireg.h
+++ b/freebsd/sys/dev/usb/controller/ohcireg.h
@@ -15,13 +15,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/freebsd/sys/dev/usb/controller/usb_controller.c b/freebsd/sys/dev/usb/controller/usb_controller.c
index f4220daf..ce3263dd 100644
--- a/freebsd/sys/dev/usb/controller/usb_controller.c
+++ b/freebsd/sys/dev/usb/controller/usb_controller.c
@@ -36,7 +36,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -63,12 +62,17 @@
#include <dev/usb/usb_controller.h>
#include <dev/usb/usb_bus.h>
+#include <dev/usb/usb_pf.h>
+#include <rtems/bsd/local/usb_if.h>
/* function prototypes */
static device_probe_t usb_probe;
static device_attach_t usb_attach;
static device_detach_t usb_detach;
+static device_suspend_t usb_suspend;
+static device_resume_t usb_resume;
+static device_shutdown_t usb_shutdown;
static void usb_attach_sub(device_t, struct usb_bus *);
@@ -85,8 +89,18 @@ SYSCTL_INT(_hw_usb_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb_ctrl_debug, 0,
#ifndef __rtems__
static int usb_no_boot_wait = 0;
TUNABLE_INT("hw.usb.no_boot_wait", &usb_no_boot_wait);
-SYSCTL_INT(_hw_usb, OID_AUTO, no_boot_wait, CTLFLAG_RDTUN, &usb_no_boot_wait, 0,
- "No device enumerate waiting at boot.");
+SYSCTL_INT(_hw_usb, OID_AUTO, no_boot_wait, CTLFLAG_RD|CTLFLAG_TUN, &usb_no_boot_wait, 0,
+ "No USB device enumerate waiting at boot.");
+
+static int usb_no_suspend_wait = 0;
+TUNABLE_INT("hw.usb.no_suspend_wait", &usb_no_suspend_wait);
+SYSCTL_INT(_hw_usb, OID_AUTO, no_suspend_wait, CTLFLAG_RW|CTLFLAG_TUN,
+ &usb_no_suspend_wait, 0, "No USB device waiting at system suspend.");
+
+static int usb_no_shutdown_wait = 0;
+TUNABLE_INT("hw.usb.no_shutdown_wait", &usb_no_shutdown_wait);
+SYSCTL_INT(_hw_usb, OID_AUTO, no_shutdown_wait, CTLFLAG_RW|CTLFLAG_TUN,
+ &usb_no_shutdown_wait, 0, "No USB device waiting at system shutdown.");
#endif /* __rtems__ */
static devclass_t usb_devclass;
@@ -95,9 +109,9 @@ static device_method_t usb_methods[] = {
DEVMETHOD(device_probe, usb_probe),
DEVMETHOD(device_attach, usb_attach),
DEVMETHOD(device_detach, usb_detach),
- DEVMETHOD(device_suspend, bus_generic_suspend),
- DEVMETHOD(device_resume, bus_generic_resume),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, usb_suspend),
+ DEVMETHOD(device_resume, usb_resume),
+ DEVMETHOD(device_shutdown, usb_shutdown),
{0, 0}
};
@@ -190,12 +204,12 @@ usb_detach(device_t dev)
usb_root_mount_rel(bus);
USB_BUS_LOCK(bus);
- if (usb_proc_msignal(&bus->explore_proc,
- &bus->detach_msg[0], &bus->detach_msg[1])) {
- /* ignore */
- }
- /* Wait for detach to complete */
+ /* Queue detach job */
+ usb_proc_msignal(&bus->explore_proc,
+ &bus->detach_msg[0], &bus->detach_msg[1]);
+
+ /* Wait for detach to complete */
usb_proc_mwait(&bus->explore_proc,
&bus->detach_msg[0], &bus->detach_msg[1]);
@@ -214,6 +228,96 @@ usb_detach(device_t dev)
usb_proc_free(&bus->control_xfer_proc);
+#if USB_HAVE_PF
+ usbpf_detach(bus);
+#endif
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_suspend
+ *------------------------------------------------------------------------*/
+static int
+usb_suspend(device_t dev)
+{
+ struct usb_bus *bus = device_get_softc(dev);
+
+ DPRINTF("\n");
+
+ if (bus == NULL) {
+ /* was never setup properly */
+ return (0);
+ }
+
+ USB_BUS_LOCK(bus);
+ usb_proc_msignal(&bus->explore_proc,
+ &bus->suspend_msg[0], &bus->suspend_msg[1]);
+#ifndef __rtems__
+ if (usb_no_suspend_wait == 0) {
+ /* wait for suspend callback to be executed */
+ usb_proc_mwait(&bus->explore_proc,
+ &bus->suspend_msg[0], &bus->suspend_msg[1]);
+ }
+#endif /* __rtems__ */
+ USB_BUS_UNLOCK(bus);
+
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_resume
+ *------------------------------------------------------------------------*/
+static int
+usb_resume(device_t dev)
+{
+ struct usb_bus *bus = device_get_softc(dev);
+
+ DPRINTF("\n");
+
+ if (bus == NULL) {
+ /* was never setup properly */
+ return (0);
+ }
+
+ USB_BUS_LOCK(bus);
+ usb_proc_msignal(&bus->explore_proc,
+ &bus->resume_msg[0], &bus->resume_msg[1]);
+ USB_BUS_UNLOCK(bus);
+
+ return (0);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_shutdown
+ *------------------------------------------------------------------------*/
+static int
+usb_shutdown(device_t dev)
+{
+ struct usb_bus *bus = device_get_softc(dev);
+
+ DPRINTF("\n");
+
+ if (bus == NULL) {
+ /* was never setup properly */
+ return (0);
+ }
+
+ device_printf(bus->bdev, "Controller shutdown\n");
+
+ USB_BUS_LOCK(bus);
+#ifndef __rtems__
+ usb_proc_msignal(&bus->explore_proc,
+ &bus->shutdown_msg[0], &bus->shutdown_msg[1]);
+ if (usb_no_shutdown_wait == 0) {
+ /* wait for shutdown callback to be executed */
+ usb_proc_mwait(&bus->explore_proc,
+ &bus->shutdown_msg[0], &bus->shutdown_msg[1]);
+ }
+#endif /* __rtems__ */
+ USB_BUS_UNLOCK(bus);
+
+ device_printf(bus->bdev, "Controller shutdown complete\n");
+
return (0);
}
@@ -231,6 +335,9 @@ usb_bus_explore(struct usb_proc_msg *pm)
bus = ((struct usb_bus_msg *)pm)->bus;
udev = bus->devices[USB_ROOT_HUB_ADDR];
+ if (bus->no_explore != 0)
+ return;
+
if (udev && udev->hub) {
if (bus->do_probe) {
@@ -301,6 +408,168 @@ usb_bus_detach(struct usb_proc_msg *pm)
bus->bdev = NULL;
}
+/*------------------------------------------------------------------------*
+ * usb_bus_suspend
+ *
+ * This function is used to suspend the USB contoller.
+ *------------------------------------------------------------------------*/
+static void
+usb_bus_suspend(struct usb_proc_msg *pm)
+{
+ struct usb_bus *bus;
+ struct usb_device *udev;
+ usb_error_t err;
+ uint8_t do_unlock;
+
+ bus = ((struct usb_bus_msg *)pm)->bus;
+ udev = bus->devices[USB_ROOT_HUB_ADDR];
+
+ if (udev == NULL || bus->bdev == NULL)
+ return;
+
+ USB_BUS_UNLOCK(bus);
+
+ /*
+ * We use the shutdown event here because the suspend and
+ * resume events are reserved for the USB port suspend and
+ * resume. The USB system suspend is implemented like full
+ * shutdown and all connected USB devices will be disconnected
+ * subsequently. At resume all USB devices will be
+ * re-connected again.
+ */
+
+ bus_generic_shutdown(bus->bdev);
+
+ do_unlock = usbd_enum_lock(udev);
+
+ err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
+ if (err)
+ device_printf(bus->bdev, "Could not unconfigure root HUB\n");
+
+ USB_BUS_LOCK(bus);
+ bus->hw_power_state = 0;
+ bus->no_explore = 1;
+ USB_BUS_UNLOCK(bus);
+
+ if (bus->methods->set_hw_power != NULL)
+ (bus->methods->set_hw_power) (bus);
+
+ if (bus->methods->set_hw_power_sleep != NULL)
+ (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SUSPEND);
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
+ USB_BUS_LOCK(bus);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_bus_resume
+ *
+ * This function is used to resume the USB contoller.
+ *------------------------------------------------------------------------*/
+static void
+usb_bus_resume(struct usb_proc_msg *pm)
+{
+ struct usb_bus *bus;
+ struct usb_device *udev;
+ usb_error_t err;
+ uint8_t do_unlock;
+
+ bus = ((struct usb_bus_msg *)pm)->bus;
+ udev = bus->devices[USB_ROOT_HUB_ADDR];
+
+ if (udev == NULL || bus->bdev == NULL)
+ return;
+
+ USB_BUS_UNLOCK(bus);
+
+ do_unlock = usbd_enum_lock(udev);
+#if 0
+ DEVMETHOD(usb_take_controller, NULL); /* dummy */
+#endif
+ USB_TAKE_CONTROLLER(device_get_parent(bus->bdev));
+
+ USB_BUS_LOCK(bus);
+ bus->hw_power_state =
+ USB_HW_POWER_CONTROL |
+ USB_HW_POWER_BULK |
+ USB_HW_POWER_INTERRUPT |
+ USB_HW_POWER_ISOC |
+ USB_HW_POWER_NON_ROOT_HUB;
+ bus->no_explore = 0;
+ USB_BUS_UNLOCK(bus);
+
+ if (bus->methods->set_hw_power_sleep != NULL)
+ (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_RESUME);
+
+ if (bus->methods->set_hw_power != NULL)
+ (bus->methods->set_hw_power) (bus);
+
+ /* restore USB configuration to index 0 */
+ err = usbd_set_config_index(udev, 0);
+ if (err)
+ device_printf(bus->bdev, "Could not configure root HUB\n");
+
+ /* probe and attach */
+ err = usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY);
+ if (err) {
+ device_printf(bus->bdev, "Could not probe and "
+ "attach root HUB\n");
+ }
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
+ USB_BUS_LOCK(bus);
+}
+
+/*------------------------------------------------------------------------*
+ * usb_bus_shutdown
+ *
+ * This function is used to shutdown the USB contoller.
+ *------------------------------------------------------------------------*/
+static void
+usb_bus_shutdown(struct usb_proc_msg *pm)
+{
+ struct usb_bus *bus;
+ struct usb_device *udev;
+ usb_error_t err;
+ uint8_t do_unlock;
+
+ bus = ((struct usb_bus_msg *)pm)->bus;
+ udev = bus->devices[USB_ROOT_HUB_ADDR];
+
+ if (udev == NULL || bus->bdev == NULL)
+ return;
+
+ USB_BUS_UNLOCK(bus);
+
+ bus_generic_shutdown(bus->bdev);
+
+ do_unlock = usbd_enum_lock(udev);
+
+ err = usbd_set_config_index(udev, USB_UNCONFIG_INDEX);
+ if (err)
+ device_printf(bus->bdev, "Could not unconfigure root HUB\n");
+
+ USB_BUS_LOCK(bus);
+ bus->hw_power_state = 0;
+ bus->no_explore = 1;
+ USB_BUS_UNLOCK(bus);
+
+ if (bus->methods->set_hw_power != NULL)
+ (bus->methods->set_hw_power) (bus);
+
+ if (bus->methods->set_hw_power_sleep != NULL)
+ (bus->methods->set_hw_power_sleep) (bus, USB_HW_POWER_SHUTDOWN);
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
+ USB_BUS_LOCK(bus);
+}
+
static void
usb_power_wdog(void *arg)
{
@@ -370,7 +639,7 @@ usb_bus_attach(struct usb_proc_msg *pm)
case USB_REV_3_0:
speed = USB_SPEED_SUPER;
- device_printf(bus->bdev, "4.8Gbps Super Speed USB v3.0\n");
+ device_printf(bus->bdev, "5.0Gbps Super Speed USB v3.0\n");
break;
default:
@@ -379,8 +648,6 @@ usb_bus_attach(struct usb_proc_msg *pm)
return;
}
- USB_BUS_UNLOCK(bus);
-
/* default power_mask value */
bus->hw_power_state =
USB_HW_POWER_CONTROL |
@@ -389,13 +656,15 @@ usb_bus_attach(struct usb_proc_msg *pm)
USB_HW_POWER_ISOC |
USB_HW_POWER_NON_ROOT_HUB;
+ USB_BUS_UNLOCK(bus);
+
/* make sure power is set at least once */
if (bus->methods->set_hw_power != NULL) {
(bus->methods->set_hw_power) (bus);
}
- /* Allocate the Root USB device */
+ /* allocate the Root USB device */
child = usb_alloc_device(bus->bdev, bus, NULL, 0, 0, 1,
speed, USB_MODE_HOST);
@@ -442,6 +711,9 @@ usb_attach_sub(device_t dev, struct usb_bus *bus)
usb_devclass_ptr = devclass_find("usbus");
mtx_unlock(&Giant);
+#if USB_HAVE_PF
+ usbpf_attach(bus);
+#endif
/* Initialise USB process messages */
bus->explore_msg[0].hdr.pm_callback = &usb_bus_explore;
bus->explore_msg[0].bus = bus;
@@ -458,31 +730,44 @@ usb_attach_sub(device_t dev, struct usb_bus *bus)
bus->attach_msg[1].hdr.pm_callback = &usb_bus_attach;
bus->attach_msg[1].bus = bus;
+ bus->suspend_msg[0].hdr.pm_callback = &usb_bus_suspend;
+ bus->suspend_msg[0].bus = bus;
+ bus->suspend_msg[1].hdr.pm_callback = &usb_bus_suspend;
+ bus->suspend_msg[1].bus = bus;
+
+ bus->resume_msg[0].hdr.pm_callback = &usb_bus_resume;
+ bus->resume_msg[0].bus = bus;
+ bus->resume_msg[1].hdr.pm_callback = &usb_bus_resume;
+ bus->resume_msg[1].bus = bus;
+
+ bus->shutdown_msg[0].hdr.pm_callback = &usb_bus_shutdown;
+ bus->shutdown_msg[0].bus = bus;
+ bus->shutdown_msg[1].hdr.pm_callback = &usb_bus_shutdown;
+ bus->shutdown_msg[1].bus = bus;
+
/* Create USB explore and callback processes */
if (usb_proc_create(&bus->giant_callback_proc,
&bus->bus_mtx, pname, USB_PRI_MED)) {
- printf("WARNING: Creation of USB Giant "
+ device_printf(dev, "WARNING: Creation of USB Giant "
"callback process failed.\n");
} else if (usb_proc_create(&bus->non_giant_callback_proc,
&bus->bus_mtx, pname, USB_PRI_HIGH)) {
- printf("WARNING: Creation of USB non-Giant "
+ device_printf(dev, "WARNING: Creation of USB non-Giant "
"callback process failed.\n");
} else if (usb_proc_create(&bus->explore_proc,
&bus->bus_mtx, pname, USB_PRI_MED)) {
- printf("WARNING: Creation of USB explore "
+ device_printf(dev, "WARNING: Creation of USB explore "
"process failed.\n");
} else if (usb_proc_create(&bus->control_xfer_proc,
&bus->bus_mtx, pname, USB_PRI_MED)) {
- printf("WARNING: Creation of USB control transfer "
+ device_printf(dev, "WARNING: Creation of USB control transfer "
"process failed.\n");
} else {
/* Get final attach going */
USB_BUS_LOCK(bus);
- if (usb_proc_msignal(&bus->explore_proc,
- &bus->attach_msg[0], &bus->attach_msg[1])) {
- /* ignore */
- }
+ usb_proc_msignal(&bus->explore_proc,
+ &bus->attach_msg[0], &bus->attach_msg[1]);
USB_BUS_UNLOCK(bus);
/* Do initial explore */
diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.c b/freebsd/sys/dev/usb/quirk/usb_quirk.c
index 6f50452b..6ae14acf 100644
--- a/freebsd/sys/dev/usb/quirk/usb_quirk.c
+++ b/freebsd/sys/dev/usb/quirk/usb_quirk.c
@@ -36,7 +36,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -97,11 +96,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(SILICONPORTALS, YAPPHONE, 0x100, 0x100, UQ_AU_INP_ASYNC),
USB_QUIRK(LOGITECH, UN53B, 0x0000, 0xffff, UQ_NO_STRINGS),
USB_QUIRK(ELSA, MODEM1, 0x0000, 0xffff, UQ_CFG_INDEX_1),
-
- /*
- * XXX The following quirks should have a more specific revision
- * number:
- */
+ /* Quirks for printer devices */
USB_QUIRK(HP, 895C, 0x0000, 0xffff, UQ_BROKEN_BIDIR),
USB_QUIRK(HP, 880C, 0x0000, 0xffff, UQ_BROKEN_BIDIR),
USB_QUIRK(HP, 815C, 0x0000, 0xffff, UQ_BROKEN_BIDIR),
@@ -130,6 +125,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(METAGEEK2, WISPYDBX, 0x0000, 0xffff, UQ_KBD_IGNORE, UQ_HID_IGNORE),
USB_QUIRK(TENX, UAUDIO0, 0x0101, 0x0101, UQ_AUDIO_SWAP_LR),
/* MS keyboards do weird things */
+ USB_QUIRK(MICROSOFT, NATURAL4000, 0x0000, 0xFFFF, UQ_KBD_BOOTPROTO),
USB_QUIRK(MICROSOFT, WLINTELLIMOUSE, 0x0000, 0xffff, UQ_MS_LEADING_BYTE),
/* umodem(4) device quirks */
USB_QUIRK(METRICOM, RICOCHET_GS, 0x100, 0x100, UQ_ASSUME_CM_OVER_DATA),
@@ -139,7 +135,9 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(SIEMENS2, ES75, 0x000, 0x000, UQ_ASSUME_CM_OVER_DATA),
USB_QUIRK(QUALCOMM, CDMA_MSM, 0x0000, 0xffff, UQ_ASSUME_CM_OVER_DATA),
USB_QUIRK(QUALCOMM2, CDMA_MSM, 0x0000, 0xffff, UQ_ASSUME_CM_OVER_DATA),
+ USB_QUIRK(CURITEL, UM150, 0x0000, 0xffff, UQ_ASSUME_CM_OVER_DATA),
USB_QUIRK(CURITEL, UM175, 0x0000, 0xffff, UQ_ASSUME_CM_OVER_DATA),
+ USB_QUIRK(VERTEX, VW110L, 0x0000, 0xffff, UQ_ASSUME_CM_OVER_DATA),
/* USB Mass Storage Class Quirks */
USB_QUIRK_VP(USB_VENDOR_ASAHIOPTICAL, 0, UQ_MSC_NO_RS_CLEAR_UA,
@@ -154,12 +152,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(AIPTEK, POCKETCAM3M, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
- USB_QUIRK(AIPTEK2, SUNPLUS_TECH, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ALCOR, SDCR_6335, 0x0000, 0xffff, UQ_MSC_NO_TEST_UNIT_READY,
- UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ALCOR, SDCR_6362, 0x0000, 0xffff, UQ_MSC_NO_TEST_UNIT_READY,
- UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ALCOR, AU6390, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(ALCOR, UMCR_9361, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN),
USB_QUIRK(ALCOR, TRANSCEND, 0x0142, 0x0142, UQ_MSC_FORCE_WIRE_BBB,
@@ -181,22 +173,21 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(CENTURY, EX35QUAT, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ,
UQ_MSC_NO_START_STOP, UQ_MSC_IGNORE_RESIDUE),
- USB_QUIRK(CENTURY, EX35SW4_SB4, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(CYPRESS, XX6830XX, 0x0000, 0xffff, UQ_MSC_NO_GETMAXLUN,
UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(DESKNOTE, UCR_61S2B, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(DMI, CFSM_RW, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI,
UQ_MSC_NO_GETMAXLUN),
- USB_QUIRK(DMI, DISK, 0x000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+ USB_QUIRK(EMTEC, RUF2PS, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(EPSON, STYLUS_875DC, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
USB_QUIRK(EPSON, STYLUS_895, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN),
USB_QUIRK(FEIYA, 5IN1, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
+ USB_QUIRK(FEIYA, ELANGO, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(FREECOM, DVD, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
- USB_QUIRK(FREECOM, HDD, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(FUJIPHOTO, MASS0100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I,
UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_RS_CLEAR_UA, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(GENESYS, GL641USB2IDE, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -240,7 +231,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(IOMEGA, ZIP100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI,
UQ_MSC_NO_TEST_UNIT_READY), /* XXX ZIP drives can also use ATAPI */
- USB_QUIRK(JMICRON, JM20336, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(JMICRON, JM20337, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI,
UQ_MSC_NO_SYNC_CACHE),
@@ -287,8 +277,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
UQ_MSC_FORCE_PROTO_ATAPI),
USB_QUIRK(MYSON, HEDEN, 0x0000, 0xffff, UQ_MSC_IGNORE_RESIDUE,
UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(MYSON, HEDEN_8813, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(MYSON, STARREADER, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(NEODIO, ND3260, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ),
USB_QUIRK(NETAC, CF_CARD, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -315,7 +303,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
USB_QUIRK(ONSPEC, READER, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(ONSPEC, UCF100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
- UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_INQUIRY | UQ_MSC_NO_GETMAXLUN),
+ UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_INQUIRY, UQ_MSC_NO_GETMAXLUN),
USB_QUIRK(ONSPEC2, IMAGEMATE_SDDR55, 0x0000, 0xffff,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN),
USB_QUIRK(PANASONIC, KXL840AN, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -325,7 +313,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK(PANASONIC, KXLCB35AN, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(PANASONIC, LS120CAM, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_UFI),
- USB_QUIRK(PHILIPS, SPE3030CC, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(PLEXTOR, 40_12_40U, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_TEST_UNIT_READY),
USB_QUIRK(PNY, ATTACHE2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -336,7 +323,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
USB_QUIRK_VP(USB_VENDOR_SAMSUNG_TECHWIN,
USB_PRODUCT_SAMSUNG_TECHWIN_DIGIMAX_410, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
- USB_QUIRK(SAMSUNG, YP_U4, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(SANDISK, SDDR05A, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_READ_CAP_OFFBY1,
UQ_MSC_NO_GETMAXLUN),
@@ -353,6 +339,8 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_IGNORE_RESIDUE),
USB_QUIRK(SANDISK, SDDR31, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_READ_CAP_OFFBY1),
+ USB_QUIRK(SANDISK, IMAGEMATE_SDDR289, 0x0000, 0xffff,
+ UQ_MSC_NO_SYNC_CACHE, UQ_MSC_NO_GETMAXLUN),
USB_QUIRK(SCANLOGIC, SL11R, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_INQUIRY),
USB_QUIRK(SHUTTLE, EUSB, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I,
@@ -456,12 +444,39 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
UQ_MSC_FORCE_PROTO_ATAPI),
USB_QUIRK(MEIZU, M6_SL, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ACTIONS, MP4, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
- UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ASUS, GMSC, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(CHIPSBANK, USBMEMSTICK, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(CHIPSBANK, USBMEMSTICK1, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(NEWLINK, USB2IDEBRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
+
+ /* Non-standard USB MIDI devices */
+ USB_QUIRK(ROLAND, UM1, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, SC8850, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, SD90, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, UM880N, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, UA100, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, UM4, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, U8, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, UM2, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, SC8820, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, PC300, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, SK500, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, SCD70, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, UM550, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, SD20, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, SD80, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(ROLAND, UA700, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(MEDELI, DD305, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI, UQ_MATCH_VENDOR_ONLY),
+
+ /* Non-standard USB AUDIO devices */
+ USB_QUIRK(MAUDIO, FASTTRACKULTRA, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(MAUDIO, FASTTRACKULTRA8R, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+
+ /*
+ * Quirks for manufacturers which USB devices does not respond
+ * after issuing non-supported commands:
+ */
+ USB_QUIRK(ALCOR, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MSC_NO_TEST_UNIT_READY, UQ_MATCH_VENDOR_ONLY),
+ USB_QUIRK(APPLE, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
+ USB_QUIRK(FEIYA, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
+ USB_QUIRK(REALTEK, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
+ USB_QUIRK(INITIO, DUMMY, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE, UQ_MATCH_VENDOR_ONLY),
};
#undef USB_QUIRK_VP
#undef USB_QUIRK
@@ -480,6 +495,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = {
[UQ_HID_IGNORE] = "UQ_HID_IGNORE",
[UQ_KBD_IGNORE] = "UQ_KBD_IGNORE",
[UQ_KBD_BOOTPROTO] = "UQ_KBD_BOOTPROTO",
+ [UQ_UMS_IGNORE] = "UQ_UMS_IGNORE",
[UQ_MS_BAD_CLASS] = "UQ_MS_BAD_CLASS",
[UQ_MS_LEADING_BYTE] = "UQ_MS_LEADING_BYTE",
[UQ_MS_REVZ] = "UQ_MS_REVZ",
@@ -526,6 +542,9 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = {
[UQ_MSC_EJECT_SAEL_M460] = "UQ_MSC_EJECT_SAEL_M460",
[UQ_MSC_EJECT_HUAWEISCSI] = "UQ_MSC_EJECT_HUAWEISCSI",
[UQ_MSC_EJECT_TCT] = "UQ_MSC_EJECT_TCT",
+ [UQ_BAD_MIDI] = "UQ_BAD_MIDI",
+ [UQ_AU_VENDOR_CLASS] = "UQ_AU_VENDOR_CLASS",
+ [UQ_SINGLE_CMD_MIDI] = "UQ_SINGLE_CMD_MIDI",
};
/*------------------------------------------------------------------------*
@@ -553,9 +572,9 @@ usb_test_quirk_by_info(const struct usbd_lookup_info *info, uint16_t quirk)
uint16_t x;
uint16_t y;
- if (quirk == UQ_NONE) {
- return (0);
- }
+ if (quirk == UQ_NONE)
+ goto done;
+
mtx_lock(&usb_quirk_mtx);
for (x = 0; x != USB_DEV_QUIRKS_MAX; x++) {
@@ -589,7 +608,8 @@ usb_test_quirk_by_info(const struct usbd_lookup_info *info, uint16_t quirk)
break;
}
mtx_unlock(&usb_quirk_mtx);
- return (0);
+done:
+ return (0); /* no quirk match */
}
static struct usb_quirk_entry *
@@ -770,7 +790,7 @@ usb_quirk_ioctl(unsigned long cmd, caddr_t data,
}
if (x == USB_SUB_QUIRKS_MAX) {
/* all quirk entries are unused - release */
- memset(pqe, 0, sizeof(pqe));
+ memset(pqe, 0, sizeof(*pqe));
}
mtx_unlock(&usb_quirk_mtx);
return (0); /* success */
diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.h b/freebsd/sys/dev/usb/quirk/usb_quirk.h
index 522b15a4..f2c10dd8 100644
--- a/freebsd/sys/dev/usb/quirk/usb_quirk.h
+++ b/freebsd/sys/dev/usb/quirk/usb_quirk.h
@@ -29,7 +29,7 @@
enum {
/*
- * Keep in sync with theusb_quirk_str usb_quirk.c, and with the
+ * Keep in sync with usb_quirk_str in usb_quirk.c, and with
* share/man/man4/usb_quirk.4
*/
UQ_NONE, /* not a valid quirk */
@@ -49,6 +49,7 @@ enum {
UQ_HID_IGNORE, /* device should be ignored by hid class */
UQ_KBD_IGNORE, /* device should be ignored by kbd class */
UQ_KBD_BOOTPROTO, /* device should set the boot protocol */
+ UQ_UMS_IGNORE, /* device should be ignored by ums class */
UQ_MS_BAD_CLASS, /* doesn't identify properly */
UQ_MS_LEADING_BYTE, /* mouse sends an unknown leading byte */
UQ_MS_REVZ, /* mouse has Z-axis reversed */
@@ -64,7 +65,10 @@ enum {
UQ_CFG_INDEX_0, /* select configuration index 0 by default */
UQ_ASSUME_CM_OVER_DATA, /* assume cm over data feature */
- /* USB Mass Storage Quirks. See "storage/umass.c" for a detailed description. */
+ /*
+ * USB Mass Storage Quirks. See "storage/umass.c" for a
+ * detailed description.
+ */
UQ_MSC_NO_TEST_UNIT_READY, /* send start/stop instead of TUR */
UQ_MSC_NO_RS_CLEAR_UA, /* does not reset Unit Att. */
UQ_MSC_NO_START_STOP, /* does not support start/stop */
@@ -100,6 +104,10 @@ enum {
UQ_MSC_EJECT_HUAWEISCSI, /* ejects after Huawei SCSI command */
UQ_MSC_EJECT_TCT, /* ejects after TCT SCSI command */
+ UQ_BAD_MIDI, /* device claims MIDI class, but isn't */
+ UQ_AU_VENDOR_CLASS, /* audio device uses vendor and not audio class */
+ UQ_SINGLE_CMD_MIDI, /* at most one command per USB packet */
+
USB_QUIRK_MAX
};
diff --git a/freebsd/sys/dev/usb/storage/umass.c b/freebsd/sys/dev/usb/storage/umass.c
index f59062d9..9c448466 100644
--- a/freebsd/sys/dev/usb/storage/umass.c
+++ b/freebsd/sys/dev/usb/storage/umass.c
@@ -112,7 +112,6 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -177,9 +176,8 @@ __FBSDID("$FreeBSD$");
static int umass_debug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass");
-SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
&umass_debug, 0, "umass debug level");
-
TUNABLE_INT("hw.usb.umass.debug", &umass_debug);
#else
#define DIF(...) do { } while (0)
@@ -726,6 +724,11 @@ MODULE_VERSION(umass, 1);
* USB device probe/attach/detach
*/
+static const STRUCT_USB_HOST_ID __used umass_devs[] = {
+ /* generic mass storage class */
+ {USB_IFACE_CLASS(UICLASS_MASS),},
+};
+
static uint16_t
umass_get_proto(struct usb_interface *iface)
{
@@ -787,6 +790,7 @@ umass_probe_proto(device_t dev, struct usb_attach_arg *uaa)
uint32_t proto = umass_get_proto(uaa->iface);
memset(&ret, 0, sizeof(ret));
+ ret.error = BUS_PROBE_GENERIC;
/* Search for protocol enforcement */
@@ -875,10 +879,6 @@ umass_probe(device_t dev)
if (uaa->usb_mode != USB_MODE_HOST) {
return (ENXIO);
}
- if (uaa->use_generic == 0) {
- /* give other drivers a try first */
- return (ENXIO);
- }
temp = umass_probe_proto(dev, uaa);
return (temp.error);
@@ -894,7 +894,7 @@ umass_attach(device_t dev)
int32_t err;
/*
- * NOTE: the softc struct is bzero-ed in device_set_driver.
+ * NOTE: the softc struct is cleared in device_set_driver.
* We can safely call umass_detach without specifically
* initializing the struct.
*/
@@ -1028,12 +1028,6 @@ umass_attach(device_t dev)
sc->cam_scsi_sense.opcode = REQUEST_SENSE;
sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY;
- /*
- * some devices need a delay after that the configuration value is
- * set to function properly:
- */
- usb_pause_mtx(NULL, hz);
-
/* register the SIM */
err = umass_cam_attach_sim(sc);
if (err) {
@@ -1316,11 +1310,13 @@ umass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
}
sc->cbw.bCDBLength = sc->sc_transfer.cmd_len;
- bcopy(sc->sc_transfer.cmd_data, sc->cbw.CBWCDB,
+ memcpy(sc->cbw.CBWCDB, sc->sc_transfer.cmd_data,
sc->sc_transfer.cmd_len);
- bzero(sc->sc_transfer.cmd_data + sc->sc_transfer.cmd_len,
- sizeof(sc->cbw.CBWCDB) - sc->sc_transfer.cmd_len);
+ memset(sc->sc_transfer.cmd_data +
+ sc->sc_transfer.cmd_len, 0,
+ sizeof(sc->cbw.CBWCDB) -
+ sc->sc_transfer.cmd_len);
DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw));
@@ -1491,9 +1487,9 @@ umass_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
/* Zero missing parts of the CSW: */
- if (actlen < sizeof(sc->csw)) {
- bzero(&sc->csw, sizeof(sc->csw));
- }
+ if (actlen < (int)sizeof(sc->csw))
+ memset(&sc->csw, 0, sizeof(sc->csw));
+
pc = usbd_xfer_get_frame(xfer, 0);
usbd_copy_out(pc, 0, &sc->csw, actlen);
@@ -1856,9 +1852,23 @@ umass_t_cbi_command_callback(struct usb_xfer *xfer, usb_error_t error)
break;
default: /* Error */
- umass_tr_error(xfer, error);
- /* skip reset */
- sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
+ /*
+ * STALL on the control pipe can be result of the command error.
+ * Attempt to clear this STALL same as for bulk pipe also
+ * results in command completion interrupt, but ASC/ASCQ there
+ * look like not always valid, so don't bother about it.
+ */
+ if ((error == USB_ERR_STALLED) ||
+ (sc->sc_transfer.callback == &umass_cam_cb)) {
+ sc->sc_transfer.ccb = NULL;
+ (sc->sc_transfer.callback)
+ (sc, ccb, sc->sc_transfer.data_len,
+ STATUS_CMD_UNKNOWN);
+ } else {
+ umass_tr_error(xfer, error);
+ /* skip reset */
+ sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
+ }
break;
}
}
@@ -2011,7 +2021,7 @@ umass_t_cbi_status_callback(struct usb_xfer *xfer, usb_error_t error)
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
- if (actlen < sizeof(sc->sbl)) {
+ if (actlen < (int)sizeof(sc->sbl)) {
goto tr_setup;
}
pc = usbd_xfer_get_frame(xfer, 0);
@@ -2616,17 +2626,9 @@ umass_cam_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
/*
* The wire protocol failed and will hopefully have
* recovered. We return an error to CAM and let CAM
- * retry the command if necessary. In case of SCSI IO
- * commands we ask the CAM layer to check the
- * condition first. This is a quick hack to make
- * certain devices work.
+ * retry the command if necessary.
*/
- if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
- ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
- ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
- } else {
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- }
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
xpt_done(ccb);
break;
}
@@ -2761,7 +2763,7 @@ umass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
if (sc->sc_quirks & NO_TEST_UNIT_READY) {
DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
"to START_UNIT\n");
- bzero(sc->sc_transfer.cmd_data, cmd_len);
+ memset(sc->sc_transfer.cmd_data, 0, cmd_len);
sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
sc->sc_transfer.cmd_data[4] = SSS_START;
return (1);
@@ -2774,14 +2776,14 @@ umass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
* information.
*/
if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
- bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
+ memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
return (1);
}
break;
}
- bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
+ memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
return (1);
}
@@ -2816,10 +2818,11 @@ umass_rbc_transform(struct umass_softc *sc, uint8_t *cmd_ptr, uint8_t cmd_len)
case REQUEST_SENSE:
case PREVENT_ALLOW:
- bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
+ memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
if ((sc->sc_quirks & RBC_PAD_TO_12) && (cmd_len < 12)) {
- bzero(sc->sc_transfer.cmd_data + cmd_len, 12 - cmd_len);
+ memset(sc->sc_transfer.cmd_data + cmd_len,
+ 0, 12 - cmd_len);
cmd_len = 12;
}
sc->sc_transfer.cmd_len = cmd_len;
@@ -2847,7 +2850,7 @@ umass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
sc->sc_transfer.cmd_len = UFI_COMMAND_LENGTH;
/* Zero the command data */
- bzero(sc->sc_transfer.cmd_data, UFI_COMMAND_LENGTH);
+ memset(sc->sc_transfer.cmd_data, 0, UFI_COMMAND_LENGTH);
switch (cmd_ptr[0]) {
/*
@@ -2904,7 +2907,7 @@ umass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
return (0); /* failure */
}
- bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
+ memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
return (1); /* success */
}
@@ -2925,7 +2928,7 @@ umass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
sc->sc_transfer.cmd_len = ATAPI_COMMAND_LENGTH;
/* Zero the command data */
- bzero(sc->sc_transfer.cmd_data, ATAPI_COMMAND_LENGTH);
+ memset(sc->sc_transfer.cmd_data, 0, ATAPI_COMMAND_LENGTH);
switch (cmd_ptr[0]) {
/*
@@ -2939,7 +2942,7 @@ umass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
* information.
*/
if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
- bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
+ memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
return (1);
@@ -3000,7 +3003,7 @@ umass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
break;
}
- bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
+ memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
return (1); /* success */
}
diff --git a/freebsd/sys/dev/usb/usb.h b/freebsd/sys/dev/usb/usb.h
index 433a0471..2f216d27 100644
--- a/freebsd/sys/dev/usb/usb.h
+++ b/freebsd/sys/dev/usb/usb.h
@@ -93,31 +93,29 @@ MALLOC_DECLARE(M_USBHC);
#define USB_POWER_MODE_SUSPEND 3 /* force suspend */
#define USB_POWER_MODE_RESUME 4 /* force resume */
-#if 0
/* These are the values from the USB specification. */
-#define USB_PORT_RESET_DELAY 10 /* ms */
-#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
-#define USB_PORT_RESET_RECOVERY 10 /* ms */
-#define USB_PORT_POWERUP_DELAY 100 /* ms */
-#define USB_PORT_RESUME_DELAY 20 /* ms */
-#define USB_SET_ADDRESS_SETTLE 2 /* ms */
-#define USB_RESUME_DELAY (20*5) /* ms */
-#define USB_RESUME_WAIT 10 /* ms */
-#define USB_RESUME_RECOVERY 10 /* ms */
-#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
-#else
+#define USB_PORT_RESET_DELAY_SPEC 10 /* ms */
+#define USB_PORT_ROOT_RESET_DELAY_SPEC 50 /* ms */
+#define USB_PORT_RESET_RECOVERY_SPEC 10 /* ms */
+#define USB_PORT_POWERUP_DELAY_SPEC 100 /* ms */
+#define USB_PORT_RESUME_DELAY_SPEC 20 /* ms */
+#define USB_SET_ADDRESS_SETTLE_SPEC 2 /* ms */
+#define USB_RESUME_DELAY_SPEC (20*5) /* ms */
+#define USB_RESUME_WAIT_SPEC 10 /* ms */
+#define USB_RESUME_RECOVERY_SPEC 10 /* ms */
+#define USB_EXTRA_POWER_UP_TIME_SPEC 0 /* ms */
+
/* Allow for marginal and non-conforming devices. */
-#define USB_PORT_RESET_DELAY 50 /* ms */
-#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
-#define USB_PORT_RESET_RECOVERY 250 /* ms */
-#define USB_PORT_POWERUP_DELAY 300 /* ms */
-#define USB_PORT_RESUME_DELAY (20*2) /* ms */
-#define USB_SET_ADDRESS_SETTLE 10 /* ms */
-#define USB_RESUME_DELAY (50*5) /* ms */
-#define USB_RESUME_WAIT 50 /* ms */
-#define USB_RESUME_RECOVERY 50 /* ms */
-#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
-#endif
+#define USB_PORT_RESET_DELAY 50 /* ms */
+#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
+#define USB_PORT_RESET_RECOVERY 250 /* ms */
+#define USB_PORT_POWERUP_DELAY 300 /* ms */
+#define USB_PORT_RESUME_DELAY (20*2) /* ms */
+#define USB_SET_ADDRESS_SETTLE 10 /* ms */
+#define USB_RESUME_DELAY (50*5) /* ms */
+#define USB_RESUME_WAIT 50 /* ms */
+#define USB_RESUME_RECOVERY 50 /* ms */
+#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
#define USB_MIN_POWER 100 /* mA */
#define USB_MAX_POWER 500 /* mA */
@@ -323,7 +321,7 @@ struct usb_devcap_usb2ext_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDevCapabilityType;
- uByte bmAttributes;
+ uDWord bmAttributes;
#define USB_V2EXT_LPM 0x02
} __packed;
typedef struct usb_devcap_usb2ext_descriptor usb_devcap_usb2ext_descriptor_t;
@@ -336,7 +334,7 @@ struct usb_devcap_ss_descriptor {
uWord wSpeedsSupported;
uByte bFunctionalitySupport;
uByte bU1DevExitLat;
- uByte bU2DevExitLat;
+ uWord wU2DevExitLat;
} __packed;
typedef struct usb_devcap_ss_descriptor usb_devcap_ss_descriptor_t;
@@ -686,7 +684,9 @@ struct usb_port_status {
#define UPS_PORT_LS_HOT_RST 0x09
#define UPS_PORT_LS_COMP_MODE 0x0A
#define UPS_PORT_LS_LOOPBACK 0x0B
+#define UPS_PORT_LS_RESUME 0x0F
#define UPS_PORT_POWER 0x0100
+#define UPS_PORT_POWER_SS 0x0200 /* super-speed only */
#define UPS_LOW_SPEED 0x0200
#define UPS_HIGH_SPEED 0x0400
#define UPS_OTHER_SPEED 0x0600 /* currently FreeBSD specific */
diff --git a/freebsd/sys/dev/usb/usb_bus.h b/freebsd/sys/dev/usb/usb_bus.h
index c9840fcb..459219bd 100644
--- a/freebsd/sys/dev/usb/usb_bus.h
+++ b/freebsd/sys/dev/usb/usb_bus.h
@@ -71,6 +71,9 @@ struct usb_bus {
struct usb_bus_msg explore_msg[2];
struct usb_bus_msg detach_msg[2];
struct usb_bus_msg attach_msg[2];
+ struct usb_bus_msg suspend_msg[2];
+ struct usb_bus_msg resume_msg[2];
+ struct usb_bus_msg shutdown_msg[2];
/*
* This mutex protects the USB hardware:
*/
@@ -88,6 +91,8 @@ struct usb_bus {
struct usb_bus_methods *methods; /* filled by HC driver */
struct usb_device **devices;
+ struct ifnet *ifp; /* only for USB Packet Filter */
+
usb_power_mask_t hw_power_state; /* see USB_HW_POWER_XXX */
usb_size_t uframe_usage[USB_HS_MICRO_FRAMES_MAX];
@@ -98,17 +103,8 @@ struct usb_bus {
enum usb_revision usbrev; /* USB revision. See "USB_REV_XXX". */
uint8_t devices_max; /* maximum number of USB devices */
- uint8_t do_probe; /* set if USB BUS should be re-probed */
-
- /*
- * The scratch area can only be used inside the explore thread
- * belonging to the give serial bus.
- */
- union {
- struct usb_hw_ep_scratch hw_ep_scratch[1];
- struct usb_temp_setup temp_setup[1];
- uint8_t data[255];
- } scratch[1];
+ uint8_t do_probe; /* set if USB should be re-probed */
+ uint8_t no_explore; /* don't explore USB ports */
};
#endif /* _USB_BUS_H_ */
diff --git a/freebsd/sys/dev/usb/usb_busdma.c b/freebsd/sys/dev/usb/usb_busdma.c
index e08bcbd3..4aa8e1f4 100644
--- a/freebsd/sys/dev/usb/usb_busdma.c
+++ b/freebsd/sys/dev/usb/usb_busdma.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -83,9 +82,9 @@ void
usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset,
struct usb_page_search *res)
{
+#if USB_HAVE_BUSDMA
struct usb_page *page;
-#if USB_HAVE_BUSDMA
if (pc->page_start) {
/* Case 1 - something has been loaded into DMA */
@@ -111,7 +110,7 @@ usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset,
res->length = USB_PAGE_SIZE - offset;
res->physaddr = page->physaddr + offset;
} else {
- res->length = 0 - 1;
+ res->length = (usb_size_t)-1;
res->physaddr = page->physaddr + offset;
}
if (!pc->buffer) {
@@ -126,7 +125,7 @@ usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset,
/* Case 2 - Plain PIO */
res->buffer = USB_ADD_BYTES(pc->buffer, offset);
- res->length = 0 - 1;
+ res->length = (usb_size_t)-1;
#if USB_HAVE_BUSDMA
res->physaddr = 0;
#endif
@@ -148,7 +147,7 @@ usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset,
if (buf_res.length > len) {
buf_res.length = len;
}
- bcopy(ptr, buf_res.buffer, buf_res.length);
+ memcpy(buf_res.buffer, ptr, buf_res.length);
offset += buf_res.length;
len -= buf_res.length;
@@ -270,7 +269,7 @@ usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset,
if (res.length > len) {
res.length = len;
}
- bcopy(res.buffer, ptr, res.length);
+ memcpy(ptr, res.buffer, res.length);
offset += res.length;
len -= res.length;
@@ -328,7 +327,7 @@ usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
if (res.length > len) {
res.length = len;
}
- bzero(res.buffer, res.length);
+ memset(res.buffer, 0, res.length);
offset += res.length;
len -= res.length;
@@ -563,7 +562,7 @@ usb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg,
bus_dmamem_free(utag->tag, ptr, map);
goto error;
}
- bzero(ptr, size);
+ memset(ptr, 0, size);
usb_pc_cpu_flush(pc);
@@ -800,7 +799,7 @@ usb_dma_tag_setup(struct usb_dma_parent_tag *udpt,
struct mtx *mtx, usb_dma_callback_t *func,
uint8_t ndmabits, uint8_t nudt)
{
- bzero(udpt, sizeof(*udpt));
+ memset(udpt, 0, sizeof(*udpt));
/* sanity checking */
if ((nudt == 0) ||
@@ -821,7 +820,7 @@ usb_dma_tag_setup(struct usb_dma_parent_tag *udpt,
udpt->dma_bits = ndmabits;
while (nudt--) {
- bzero(udt, sizeof(*udt));
+ memset(udt, 0, sizeof(*udt));
udt->tag_parent = udpt;
udt++;
}
diff --git a/freebsd/sys/dev/usb/usb_cdc.h b/freebsd/sys/dev/usb/usb_cdc.h
index 23fd111c..b8f59fae 100644
--- a/freebsd/sys/dev/usb/usb_cdc.h
+++ b/freebsd/sys/dev/usb/usb_cdc.h
@@ -17,13 +17,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
diff --git a/freebsd/sys/dev/usb/usb_controller.h b/freebsd/sys/dev/usb/usb_controller.h
index 6b15dab9..ad871913 100644
--- a/freebsd/sys/dev/usb/usb_controller.h
+++ b/freebsd/sys/dev/usb/usb_controller.h
@@ -40,7 +40,6 @@ struct usb_page_cache;
struct usb_setup_params;
struct usb_hw_ep_profile;
struct usb_fs_isoc_schedule;
-struct usb_config_descriptor;
struct usb_endpoint_descriptor;
/* typedefs */
@@ -66,7 +65,7 @@ struct usb_bus_methods {
void (*device_suspend) (struct usb_device *);
void (*device_resume) (struct usb_device *);
void (*set_hw_power) (struct usb_bus *);
-
+ void (*set_hw_power_sleep) (struct usb_bus *, uint32_t);
/*
* The following flag is set if one or more control transfers are
* active:
@@ -92,6 +91,18 @@ struct usb_bus_methods {
* are present on the given USB bus:
*/
#define USB_HW_POWER_NON_ROOT_HUB 0x10
+ /*
+ * The following flag is set if we are suspending
+ */
+#define USB_HW_POWER_SUSPEND 0x20
+ /*
+ * The following flag is set if we are resuming
+ */
+#define USB_HW_POWER_RESUME 0x40
+ /*
+ * The following flag is set if we are shutting down
+ */
+#define USB_HW_POWER_SHUTDOWN 0x60
/* USB Device mode only - Mandatory */
@@ -169,57 +180,14 @@ struct usb_hw_ep_profile {
uint8_t support_out:1; /* OUT-token is supported */
};
-/*
- * The following structure is used when trying to allocate hardware
- * endpoints for an USB configuration in USB device side mode.
- */
-struct usb_hw_ep_scratch_sub {
- const struct usb_hw_ep_profile *pf;
- uint16_t max_frame_size;
- uint8_t hw_endpoint_out;
- uint8_t hw_endpoint_in;
- uint8_t needs_ep_type;
- uint8_t needs_in:1;
- uint8_t needs_out:1;
-};
-
-/*
- * The following structure is used when trying to allocate hardware
- * endpoints for an USB configuration in USB device side mode.
- */
-struct usb_hw_ep_scratch {
- struct usb_hw_ep_scratch_sub ep[USB_EP_MAX];
- struct usb_hw_ep_scratch_sub *ep_max;
- struct usb_config_descriptor *cd;
- struct usb_device *udev;
- struct usb_bus_methods *methods;
- uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16];
- uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16];
-};
-
-/*
- * The following structure is used when generating USB descriptors
- * from USB templates.
- */
-struct usb_temp_setup {
- void *buf;
- usb_size_t size;
- enum usb_dev_speed usb_speed;
- uint8_t self_powered;
- uint8_t bNumEndpoints;
- uint8_t bInterfaceNumber;
- uint8_t bAlternateSetting;
- uint8_t bConfigurationValue;
- usb_error_t err;
-};
-
/* prototypes */
void usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb);
uint8_t usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, usb_bus_mem_cb_t *cb);
void usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb);
uint16_t usb_isoc_time_expand(struct usb_bus *bus, uint16_t isoc_time_curr);
-uint16_t usbd_fs_isoc_schedule_isoc_time_expand(struct usb_device *udev, struct usb_fs_isoc_schedule **pp_start, struct usb_fs_isoc_schedule **pp_end, uint16_t isoc_time);
-uint8_t usbd_fs_isoc_schedule_alloc(struct usb_fs_isoc_schedule *fss, uint8_t *pstart, uint16_t len);
+#if USB_HAVE_TT_SUPPORT
+uint8_t usbd_fs_isoc_schedule_alloc_slot(struct usb_xfer *isoc_xfer, uint16_t isoc_time);
+#endif
#endif /* _USB_CONTROLLER_H_ */
diff --git a/freebsd/sys/dev/usb/usb_core.c b/freebsd/sys/dev/usb/usb_core.c
index 38504363..27e07adf 100644
--- a/freebsd/sys/dev/usb/usb_core.c
+++ b/freebsd/sys/dev/usb/usb_core.c
@@ -40,7 +40,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
diff --git a/freebsd/sys/dev/usb/usb_debug.c b/freebsd/sys/dev/usb/usb_debug.c
index 40dafa20..159bf7ea 100644
--- a/freebsd/sys/dev/usb/usb_debug.c
+++ b/freebsd/sys/dev/usb/usb_debug.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -66,11 +65,59 @@
int usb_debug = 0;
SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW, 0, "USB debugging");
-SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
&usb_debug, 0, "Debug level");
-
TUNABLE_INT("hw.usb.debug", &usb_debug);
+#ifdef USB_DEBUG
+/*
+ * Sysctls to modify timings/delays
+ */
+static SYSCTL_NODE(_hw_usb, OID_AUTO, timings, CTLFLAG_RW, 0, "Timings");
+static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS);
+
+TUNABLE_INT("hw.usb.timings.port_reset_delay", (int *)&usb_port_reset_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_port_reset_delay, sizeof(usb_port_reset_delay),
+ usb_timings_sysctl_handler, "IU", "Port Reset Delay");
+TUNABLE_INT("hw.usb.timings.port_root_reset_delay", (int *)&usb_port_root_reset_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_root_reset_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_port_root_reset_delay, sizeof(usb_port_root_reset_delay),
+ usb_timings_sysctl_handler, "IU", "Root Port Reset Delay");
+TUNABLE_INT("hw.usb.timings.port_reset_recovery", (int *)&usb_port_reset_recovery);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_reset_recovery, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_port_reset_recovery, sizeof(usb_port_reset_recovery),
+ usb_timings_sysctl_handler, "IU", "Port Reset Recovery");
+TUNABLE_INT("hw.usb.timings.port_powerup_delay", (int *)&usb_port_powerup_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_powerup_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_port_powerup_delay, sizeof(usb_port_powerup_delay),
+ usb_timings_sysctl_handler, "IU", "Port PowerUp Delay");
+TUNABLE_INT("hw.usb.timings.port_resume_delay", (int *)&usb_port_resume_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, port_resume_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_port_resume_delay, sizeof(usb_port_resume_delay),
+ usb_timings_sysctl_handler, "IU", "Port Resume Delay");
+TUNABLE_INT("hw.usb.timings.set_address_settle", (int *)&usb_set_address_settle);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, set_address_settle, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_set_address_settle, sizeof(usb_set_address_settle),
+ usb_timings_sysctl_handler, "IU", "Set Address Settle");
+TUNABLE_INT("hw.usb.timings.resume_delay", (int *)&usb_resume_delay);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_delay, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_resume_delay, sizeof(usb_resume_delay),
+ usb_timings_sysctl_handler, "IU", "Resume Delay");
+TUNABLE_INT("hw.usb.timings.resume_wait", (int *)&usb_resume_wait);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_wait, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_resume_wait, sizeof(usb_resume_wait),
+ usb_timings_sysctl_handler, "IU", "Resume Wait");
+TUNABLE_INT("hw.usb.timings.resume_recovery", (int *)&usb_resume_recovery);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, resume_recovery, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_resume_recovery, sizeof(usb_resume_recovery),
+ usb_timings_sysctl_handler, "IU", "Resume Recovery");
+TUNABLE_INT("hw.usb.timings.extra_power_up_time", (int *)&usb_extra_power_up_time);
+SYSCTL_PROC(_hw_usb_timings, OID_AUTO, extra_power_up_time, CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_TUN,
+ &usb_extra_power_up_time, sizeof(usb_extra_power_up_time),
+ usb_timings_sysctl_handler, "IU", "Extra PowerUp Time");
+#endif
+
/*------------------------------------------------------------------------*
* usb_dump_iface
*
@@ -177,3 +224,87 @@ usb_dump_xfer(struct usb_xfer *xfer)
xfer->endpoint->edesc->bEndpointAddress,
xfer->endpoint->edesc->bmAttributes);
}
+
+#ifdef USB_DEBUG
+unsigned int usb_port_reset_delay = USB_PORT_RESET_DELAY;
+unsigned int usb_port_root_reset_delay = USB_PORT_ROOT_RESET_DELAY;
+unsigned int usb_port_reset_recovery = USB_PORT_RESET_RECOVERY;
+unsigned int usb_port_powerup_delay = USB_PORT_POWERUP_DELAY;
+unsigned int usb_port_resume_delay = USB_PORT_RESUME_DELAY;
+unsigned int usb_set_address_settle = USB_SET_ADDRESS_SETTLE;
+unsigned int usb_resume_delay = USB_RESUME_DELAY;
+unsigned int usb_resume_wait = USB_RESUME_WAIT;
+unsigned int usb_resume_recovery = USB_RESUME_RECOVERY;
+unsigned int usb_extra_power_up_time = USB_EXTRA_POWER_UP_TIME;
+
+/*------------------------------------------------------------------------*
+ * usb_timings_sysctl_handler
+ *
+ * This function updates timings variables, adjusting them where necessary.
+ *------------------------------------------------------------------------*/
+static int usb_timings_sysctl_handler(SYSCTL_HANDLER_ARGS)
+{
+ int error = 0;
+ unsigned int val;
+
+ /*
+ * Attempt to get a coherent snapshot by making a copy of the data.
+ */
+ if (arg1)
+ val = *(unsigned int *)arg1;
+ else
+ val = arg2;
+ error = SYSCTL_OUT(req, &val, sizeof(int));
+ if (error || !req->newptr)
+ return (error);
+
+ if (!arg1)
+ return EPERM;
+
+ error = SYSCTL_IN(req, &val, sizeof(unsigned int));
+ if (error)
+ return (error);
+
+ /*
+ * Now make sure the values are decent, and certainly no lower than
+ * what the USB spec prescribes.
+ */
+ unsigned int *p = (unsigned int *)arg1;
+ if (p == &usb_port_reset_delay) {
+ if (val < USB_PORT_RESET_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_root_reset_delay) {
+ if (val < USB_PORT_ROOT_RESET_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_reset_recovery) {
+ if (val < USB_PORT_RESET_RECOVERY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_powerup_delay) {
+ if (val < USB_PORT_POWERUP_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_port_resume_delay) {
+ if (val < USB_PORT_RESUME_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_set_address_settle) {
+ if (val < USB_SET_ADDRESS_SETTLE_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_resume_delay) {
+ if (val < USB_RESUME_DELAY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_resume_wait) {
+ if (val < USB_RESUME_WAIT_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_resume_recovery) {
+ if (val < USB_RESUME_RECOVERY_SPEC)
+ return (EINVAL);
+ } else if (p == &usb_extra_power_up_time) {
+ if (val < USB_EXTRA_POWER_UP_TIME_SPEC)
+ return (EINVAL);
+ } else {
+ /* noop */
+ }
+
+ *p = val;
+ return 0;
+}
+#endif
diff --git a/freebsd/sys/dev/usb/usb_debug.h b/freebsd/sys/dev/usb/usb_debug.h
index 8718c89b..038ba7f4 100644
--- a/freebsd/sys/dev/usb/usb_debug.h
+++ b/freebsd/sys/dev/usb/usb_debug.h
@@ -59,4 +59,28 @@ void usb_dump_queue(struct usb_endpoint *ep);
void usb_dump_endpoint(struct usb_endpoint *ep);
void usb_dump_xfer(struct usb_xfer *xfer);
+#ifdef USB_DEBUG
+extern unsigned int usb_port_reset_delay;
+extern unsigned int usb_port_root_reset_delay;
+extern unsigned int usb_port_reset_recovery;
+extern unsigned int usb_port_powerup_delay;
+extern unsigned int usb_port_resume_delay;
+extern unsigned int usb_set_address_settle;
+extern unsigned int usb_resume_delay;
+extern unsigned int usb_resume_wait;
+extern unsigned int usb_resume_recovery;
+extern unsigned int usb_extra_power_up_time;
+#else
+#define usb_port_reset_delay USB_PORT_RESET_DELAY
+#define usb_port_root_reset_delay USB_PORT_ROOT_RESET_DELAY
+#define usb_port_reset_recovery USB_PORT_RESET_RECOVERY
+#define usb_port_powerup_delay USB_PORT_POWERUP_DELAY
+#define usb_port_resume_delay USB_PORT_RESUME_DELAY
+#define usb_set_address_settle USB_SET_ADDRESS_SETTLE
+#define usb_resume_delay USB_RESUME_DELAY
+#define usb_resume_wait USB_RESUME_WAIT
+#define usb_resume_recovery USB_RESUME_RECOVERY
+#define usb_extra_power_up_time USB_EXTRA_POWER_UP_TIME
+#endif
+
#endif /* _USB_DEBUG_H_ */
diff --git a/freebsd/sys/dev/usb/usb_dev.c b/freebsd/sys/dev/usb/usb_dev.c
index eaad5952..a22de719 100644
--- a/freebsd/sys/dev/usb/usb_dev.c
+++ b/freebsd/sys/dev/usb/usb_dev.c
@@ -37,7 +37,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -87,9 +86,8 @@
static int usb_fifo_debug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, dev, CTLFLAG_RW, 0, "USB device");
-SYSCTL_INT(_hw_usb_dev, OID_AUTO, debug, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb_dev, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
&usb_fifo_debug, 0, "Debug Level");
-
TUNABLE_INT("hw.usb.dev.debug", &usb_fifo_debug);
#endif
@@ -220,10 +218,10 @@ usb_ref_device(struct usb_cdev_privdata *cpd,
mtx_unlock(&usb_ref_lock);
/*
- * We need to grab the sx-lock before grabbing the
- * FIFO refs to avoid deadlock at detach!
+ * We need to grab the enumeration SX-lock before
+ * grabbing the FIFO refs to avoid deadlock at detach!
*/
- usbd_enum_lock(cpd->udev);
+ crd->do_unlock = usbd_enum_lock(cpd->udev);
mtx_lock(&usb_ref_lock);
@@ -284,9 +282,10 @@ usb_ref_device(struct usb_cdev_privdata *cpd,
return (0);
error:
- if (crd->is_uref) {
+ if (crd->do_unlock)
usbd_enum_unlock(cpd->udev);
+ if (crd->is_uref) {
if (--(cpd->udev->refcount) == 0) {
cv_signal(&cpd->udev->ref_cv);
}
@@ -338,7 +337,7 @@ usb_unref_device(struct usb_cdev_privdata *cpd,
DPRINTFN(2, "cpd=%p is_uref=%d\n", cpd, crd->is_uref);
- if (crd->is_uref)
+ if (crd->do_unlock)
usbd_enum_unlock(cpd->udev);
mtx_lock(&usb_ref_lock);
@@ -916,10 +915,23 @@ usb_close(void *arg)
DPRINTFN(2, "cpd=%p\n", cpd);
- err = usb_ref_device(cpd, &refs, 1);
- if (err) {
- free(cpd, M_USBDEV);
- return;
+ err = usb_ref_device(cpd, &refs, 0);
+ if (err)
+ goto done;
+
+ /*
+ * If this function is not called directly from the root HUB
+ * thread, there is usually a need to lock the enumeration
+ * lock. Check this.
+ */
+ if (!usbd_enum_is_locked(cpd->udev)) {
+
+ DPRINTFN(2, "Locking enumeration\n");
+
+ /* reference device */
+ err = usb_usb_ref_device(cpd, &refs);
+ if (err)
+ goto done;
}
if (cpd->fflags & FREAD) {
usb_fifo_close(refs.rxfifo, cpd->fflags);
@@ -927,10 +939,9 @@ usb_close(void *arg)
if (cpd->fflags & FWRITE) {
usb_fifo_close(refs.txfifo, cpd->fflags);
}
-
usb_unref_device(cpd, &refs);
+done:
free(cpd, M_USBDEV);
- return;
}
static void
@@ -1646,14 +1657,13 @@ usb_fifo_check_methods(struct usb_fifo_methods *pm)
int
usb_fifo_attach(struct usb_device *udev, void *priv_sc,
struct mtx *priv_mtx, struct usb_fifo_methods *pm,
- struct usb_fifo_sc *f_sc, uint16_t unit, uint16_t subunit,
+ struct usb_fifo_sc *f_sc, uint16_t unit, int16_t subunit,
uint8_t iface_index, uid_t uid, gid_t gid, int mode)
{
struct usb_fifo *f_tx;
struct usb_fifo *f_rx;
char devname[32];
uint8_t n;
- struct usb_fs_privdata* pd;
f_sc->fp[USB_FIFO_TX] = NULL;
f_sc->fp[USB_FIFO_RX] = NULL;
@@ -1724,7 +1734,7 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc,
if (pm->basename[n] == NULL) {
continue;
}
- if (subunit == 0xFFFF) {
+ if (subunit < 0) {
if (snprintf(devname, sizeof(devname),
"%s%u%s", pm->basename[n],
unit, pm->postfix[n] ?
@@ -1733,7 +1743,7 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc,
}
} else {
if (snprintf(devname, sizeof(devname),
- "%s%u.%u%s", pm->basename[n],
+ "%s%u.%d%s", pm->basename[n],
unit, subunit, pm->postfix[n] ?
pm->postfix[n] : "")) {
/* ignore */
@@ -1751,22 +1761,10 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc,
usb_alloc_symlink(devname);
}
- /*
- * Initialize device private data - this is used to find the
- * actual USB device itself.
- */
- pd = malloc(sizeof(struct usb_fs_privdata), M_USBDEV, M_WAITOK | M_ZERO);
- pd->bus_index = device_get_unit(udev->bus->bdev);
- pd->dev_index = udev->device_index;
- pd->ep_addr = -1; /* not an endpoint */
- pd->fifo_index = f_tx->fifo_index & f_rx->fifo_index;
- pd->mode = FREAD|FWRITE;
-
- /* Now, create the device itself */
- f_sc->dev = make_dev(&usb_devsw, 0, uid, gid, mode,
- "%s", devname);
- /* XXX setting si_drv1 and creating the device is not atomic! */
- f_sc->dev->si_drv1 = pd;
+ /* Create the device */
+ f_sc->dev = usb_make_dev(udev, devname, -1,
+ f_tx->fifo_index & f_rx->fifo_index,
+ FREAD|FWRITE, uid, gid, mode);
}
DPRINTFN(2, "attached %p/%p\n", f_tx, f_rx);
@@ -1815,14 +1813,8 @@ usb_fifo_free_buffer(struct usb_fifo *f)
}
/* reset queues */
- bzero(&f->free_q, sizeof(f->free_q));
- bzero(&f->used_q, sizeof(f->used_q));
-}
-
-static void
-usb_fifo_cleanup(void* ptr)
-{
- free(ptr, M_USBDEV);
+ memset(&f->free_q, 0, sizeof(f->free_q));
+ memset(&f->used_q, 0, sizeof(f->used_q));
}
void
@@ -1837,11 +1829,9 @@ usb_fifo_detach(struct usb_fifo_sc *f_sc)
f_sc->fp[USB_FIFO_TX] = NULL;
f_sc->fp[USB_FIFO_RX] = NULL;
- if (f_sc->dev != NULL) {
- destroy_dev_sched_cb(f_sc->dev,
- usb_fifo_cleanup, f_sc->dev->si_drv1);
- f_sc->dev = NULL;
- }
+ usb_destroy_dev(f_sc->dev);
+
+ f_sc->dev = NULL;
DPRINTFN(2, "detached %p\n", f_sc);
}
@@ -1923,7 +1913,7 @@ usb_fifo_put_data_linear(struct usb_fifo *f, void *ptr,
io_len = MIN(len, m->cur_data_len);
- bcopy(ptr, m->cur_data_ptr, io_len);
+ memcpy(m->cur_data_ptr, ptr, io_len);
m->cur_data_len = io_len;
ptr = USB_ADD_BYTES(ptr, io_len);
@@ -2066,7 +2056,7 @@ usb_fifo_get_data_linear(struct usb_fifo *f, void *ptr,
io_len = MIN(len, m->cur_data_len);
- bcopy(m->cur_data_ptr, ptr, io_len);
+ memcpy(ptr, m->cur_data_ptr, io_len);
len -= io_len;
ptr = USB_ADD_BYTES(ptr, io_len);
diff --git a/freebsd/sys/dev/usb/usb_dev.h b/freebsd/sys/dev/usb/usb_dev.h
index aa9197f5..9a7cf210 100644
--- a/freebsd/sys/dev/usb/usb_dev.h
+++ b/freebsd/sys/dev/usb/usb_dev.h
@@ -82,6 +82,7 @@ struct usb_cdev_refdata {
uint8_t is_write; /* location has write access */
uint8_t is_uref; /* USB refcount decr. needed */
uint8_t is_usbfs; /* USB-FS is active */
+ uint8_t do_unlock; /* USB enum unlock needed */
};
struct usb_fs_privdata {
diff --git a/freebsd/sys/dev/usb/usb_device.c b/freebsd/sys/dev/usb/usb_device.c
index a2db2727..a38e3d1c 100644
--- a/freebsd/sys/dev/usb/usb_device.c
+++ b/freebsd/sys/dev/usb/usb_device.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -90,7 +89,7 @@ static void usb_init_endpoint(struct usb_device *, uint8_t,
struct usb_endpoint *);
static void usb_unconfigure(struct usb_device *, uint8_t);
static void usb_detach_device_sub(struct usb_device *, device_t *,
- uint8_t);
+ char **, uint8_t);
static uint8_t usb_probe_and_attach_sub(struct usb_device *,
struct usb_attach_arg *);
static void usb_init_attach_arg(struct usb_device *,
@@ -100,13 +99,13 @@ static void usb_suspend_resume_sub(struct usb_device *, device_t,
static void usbd_clear_stall_proc(struct usb_proc_msg *_pm);
static usb_error_t usb_config_parse(struct usb_device *, uint8_t, uint8_t);
static void usbd_set_device_strings(struct usb_device *);
-#if USB_HAVE_UGEN
+#if USB_HAVE_DEVCTL
static void usb_notify_addq(const char *type, struct usb_device *);
+#endif
+#if USB_HAVE_UGEN
static void usb_fifo_free_wrap(struct usb_device *, uint8_t, uint8_t);
-static struct cdev *usb_make_dev(struct usb_device *, int, int);
static void usb_cdev_create(struct usb_device *);
static void usb_cdev_free(struct usb_device *);
-static void usb_cdev_cleanup(void *);
#endif
/* This variable is global to allow easy access to it: */
@@ -115,7 +114,7 @@ int usb_template = 0;
#ifndef __rtems__
TUNABLE_INT("hw.usb.usb_template", &usb_template);
-SYSCTL_INT(_hw_usb, OID_AUTO, template, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, template, CTLFLAG_RW | CTLFLAG_TUN,
&usb_template, 0, "Selected USB device side template");
#endif /* __rtems__ */
@@ -126,11 +125,11 @@ static int usb_lang_mask = 0x00FF;
#ifndef __rtems__
TUNABLE_INT("hw.usb.usb_lang_id", &usb_lang_id);
-SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_id, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_id, CTLFLAG_RW | CTLFLAG_TUN,
&usb_lang_id, 0, "Preferred USB language ID");
TUNABLE_INT("hw.usb.usb_lang_mask", &usb_lang_mask);
-SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_mask, CTLFLAG_RW,
+SYSCTL_INT(_hw_usb, OID_AUTO, usb_lang_mask, CTLFLAG_RW | CTLFLAG_TUN,
&usb_lang_mask, 0, "Preferred USB language mask");
#endif /* __rtems__ */
@@ -450,13 +449,8 @@ usb_unconfigure(struct usb_device *udev, uint8_t flag)
{
uint8_t do_unlock;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
/* detach all interface drivers */
usb_detach_device(udev, USB_IFACE_INDEX_ANY, flag);
@@ -519,13 +513,8 @@ usbd_set_config_index(struct usb_device *udev, uint8_t index)
DPRINTFN(6, "udev=%p index=%d\n", udev, index);
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
usb_unconfigure(udev, 0);
@@ -757,10 +746,13 @@ usb_config_parse(struct usb_device *udev, uint8_t iface_index, uint8_t cmd)
if (do_init) {
/* setup the USB interface structure */
iface->idesc = id;
- /* default setting */
- iface->parent_iface_index = USB_IFACE_INDEX_ANY;
/* set alternate index */
iface->alt_index = alt_index;
+ /* set default interface parent */
+ if (iface_index == USB_IFACE_INDEX_ANY) {
+ iface->parent_iface_index =
+ USB_IFACE_INDEX_ANY;
+ }
}
DPRINTFN(5, "found idesc nendpt=%d\n", id->bNumEndpoints);
@@ -875,13 +867,9 @@ usbd_set_alt_interface_index(struct usb_device *udev,
usb_error_t err;
uint8_t do_unlock;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
+
if (iface == NULL) {
err = USB_ERR_INVAL;
goto done;
@@ -918,7 +906,6 @@ usbd_set_alt_interface_index(struct usb_device *udev,
done:
if (do_unlock)
usbd_enum_unlock(udev);
-
return (err);
}
@@ -1039,9 +1026,10 @@ usb_reset_iface_endpoints(struct usb_device *udev, uint8_t iface_index)
*------------------------------------------------------------------------*/
static void
usb_detach_device_sub(struct usb_device *udev, device_t *ppdev,
- uint8_t flag)
+ char **ppnpinfo, uint8_t flag)
{
device_t dev;
+ char *pnpinfo;
int err;
dev = *ppdev;
@@ -1073,11 +1061,17 @@ usb_detach_device_sub(struct usb_device *udev, device_t *ppdev,
goto error;
}
}
+
+ pnpinfo = *ppnpinfo;
+ if (pnpinfo != NULL) {
+ *ppnpinfo = NULL;
+ free(pnpinfo, M_USBDEV);
+ }
return;
error:
/* Detach is not allowed to fail in the USB world */
- panic("A USB driver would not detach\n");
+ panic("usb_detach_device_sub: A USB driver would not detach\n");
}
/*------------------------------------------------------------------------*
@@ -1126,7 +1120,8 @@ usb_detach_device(struct usb_device *udev, uint8_t iface_index,
/* looks like the end of the USB interfaces */
break;
}
- usb_detach_device_sub(udev, &iface->subdev, flag);
+ usb_detach_device_sub(udev, &iface->subdev,
+ &iface->pnpinfo, flag);
}
}
@@ -1228,17 +1223,20 @@ usbd_set_parent_iface(struct usb_device *udev, uint8_t iface_index,
{
struct usb_interface *iface;
+ if (udev == NULL) {
+ /* nothing to do */
+ return;
+ }
iface = usbd_get_iface(udev, iface_index);
- if (iface) {
+ if (iface != NULL)
iface->parent_iface_index = parent_index;
- }
}
static void
usb_init_attach_arg(struct usb_device *udev,
struct usb_attach_arg *uaa)
{
- bzero(uaa, sizeof(*uaa));
+ memset(uaa, 0, sizeof(*uaa));
uaa->device = udev;
uaa->usb_mode = udev->flags.usb_mode;
@@ -1278,13 +1276,8 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
DPRINTF("udev == NULL\n");
return (USB_ERR_INVAL);
}
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
if (udev->curr_config_index == USB_UNCONFIG_INDEX) {
/* do nothing - no configuration has been set */
@@ -1294,6 +1287,21 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
usb_init_attach_arg(udev, &uaa);
+ /*
+ * If the whole USB device is targeted, invoke the USB event
+ * handler(s):
+ */
+ if (iface_index == USB_IFACE_INDEX_ANY) {
+
+ EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa);
+
+ if (uaa.dev_state != UAA_DEV_READY) {
+ /* leave device unconfigured */
+ usb_unconfigure(udev, 0);
+ goto done;
+ }
+ }
+
/* Check if only one interface should be probed: */
if (iface_index != USB_IFACE_INDEX_ANY) {
i = iface_index;
@@ -1331,7 +1339,6 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
uaa.info.bIfaceIndex = i;
uaa.info.bIfaceNum =
iface->idesc->bInterfaceNumber;
- uaa.use_generic = 0;
uaa.driver_info = 0; /* reset driver_info */
DPRINTFN(2, "iclass=%u/%u/%u iindex=%u/%u\n",
@@ -1341,32 +1348,22 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
uaa.info.bIfaceIndex,
uaa.info.bIfaceNum);
- /* try specific interface drivers first */
-
- if (usb_probe_and_attach_sub(udev, &uaa)) {
- /* ignore */
- }
- /* try generic interface drivers last */
-
- uaa.use_generic = 1;
- uaa.driver_info = 0; /* reset driver_info */
-
- if (usb_probe_and_attach_sub(udev, &uaa)) {
- /* ignore */
- }
- }
+ usb_probe_and_attach_sub(udev, &uaa);
- if (uaa.temp_dev) {
- /* remove the last created child; it is unused */
-
- if (device_delete_child(udev->parent_dev, uaa.temp_dev)) {
+ /*
+ * Remove the leftover child, if any, to enforce that
+ * a new nomatch devd event is generated for the next
+ * interface if no driver is found:
+ */
+ if (uaa.temp_dev == NULL)
+ continue;
+ if (device_delete_child(udev->parent_dev, uaa.temp_dev))
DPRINTFN(0, "device delete child failed\n");
- }
+ uaa.temp_dev = NULL;
}
done:
if (do_unlock)
usbd_enum_unlock(udev);
-
return (0);
}
@@ -1490,12 +1487,12 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
struct usb_device *adev;
struct usb_device *hub;
uint8_t *scratch_ptr;
- size_t scratch_size;
usb_error_t err;
uint8_t device_index;
uint8_t config_index;
uint8_t config_quirk;
uint8_t set_config_failed;
+ uint8_t do_unlock;
DPRINTF("parent_dev=%p, bus=%p, parent_hub=%p, depth=%u, "
"port_index=%u, port_no=%u, speed=%u, usb_mode=%u\n",
@@ -1530,11 +1527,8 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
return (NULL);
}
/* initialise our SX-lock */
- sx_init_flags(&udev->ctrl_sx, "USB device SX lock", SX_DUPOK);
-
- /* initialise our SX-lock */
sx_init_flags(&udev->enum_sx, "USB config SX lock", SX_DUPOK);
- sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_DUPOK);
+ sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_NOWITNESS);
cv_init(&udev->ctrlreq_cv, "WCTRL");
cv_init(&udev->ref_cv, "UGONE");
@@ -1618,10 +1612,12 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
LIST_INIT(&udev->pd_list);
/* Create the control endpoint device */
- udev->ctrl_dev = usb_make_dev(udev, 0, FREAD|FWRITE);
+ udev->ctrl_dev = usb_make_dev(udev, NULL, 0, 0,
+ FREAD|FWRITE, UID_ROOT, GID_OPERATOR, 0600);
/* Create a link from /dev/ugenX.X to the default endpoint */
- make_dev_alias(udev->ctrl_dev, "%s", udev->ugen_name);
+ if (udev->ctrl_dev != NULL)
+ make_dev_alias(udev->ctrl_dev->cdev, "%s", udev->ugen_name);
#endif
/* Initialise device */
if (bus->methods->device_init != NULL) {
@@ -1712,8 +1708,11 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
* device descriptor. If no strings are present there we
* simply disable all USB strings.
*/
- scratch_ptr = udev->bus->scratch[0].data;
- scratch_size = sizeof(udev->bus->scratch[0].data);
+
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
+
+ scratch_ptr = udev->scratch.data;
if (udev->ddesc.iManufacturer ||
udev->ddesc.iProduct ||
@@ -1738,7 +1737,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
mask = usb_lang_mask;
/* align length correctly */
- scratch_ptr[0] &= ~1;
+ scratch_ptr[0] &= ~1U;
/* fix compiler warning */
langid = 0;
@@ -1759,6 +1758,9 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
udev->langid = langid;
}
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
/* assume 100mA bus powered for now. Changed when configured. */
udev->power = USB_MIN_POWER;
/* fetch the vendor and product strings from the device */
@@ -1842,12 +1844,20 @@ repeat_set_config:
}
}
}
-#ifndef __rtems__
- EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa);
-#endif /* __rtems__ */
- if (uaa.dev_state != UAA_DEV_READY) {
- /* leave device unconfigured */
- usb_unconfigure(udev, 0);
+ if (set_config_failed == 0 && config_index == 0 &&
+ usb_test_quirk(&uaa, UQ_MSC_NO_SYNC_CACHE) == 0 &&
+ usb_test_quirk(&uaa, UQ_MSC_NO_GETMAXLUN) == 0) {
+
+ /*
+ * Try to figure out if there are any MSC quirks we
+ * should apply automatically:
+ */
+ err = usb_msc_auto_quirk(udev, 0);
+
+ if (err != 0) {
+ set_config_failed = 1;
+ goto repeat_set_config;
+ }
}
config_done:
@@ -1866,7 +1876,9 @@ config_done:
printf("%s: <%s> at %s\n", udev->ugen_name,
usb_get_manufacturer(udev),
device_get_nameunit(udev->bus->bdev));
+#endif
+#if USB_HAVE_DEVCTL
usb_notify_addq("ATTACH", udev);
#endif
done:
@@ -1881,11 +1893,12 @@ done:
}
#if USB_HAVE_UGEN
-static struct cdev *
-usb_make_dev(struct usb_device *udev, int ep, int mode)
+struct usb_fs_privdata *
+usb_make_dev(struct usb_device *udev, const char *devname, int ep,
+ int fi, int rwmode, uid_t uid, gid_t gid, int mode)
{
struct usb_fs_privdata* pd;
- char devname[20];
+ char buffer[32];
/* Store information to locate ourselves again later */
pd = malloc(sizeof(struct usb_fs_privdata), M_USBDEV,
@@ -1893,16 +1906,39 @@ usb_make_dev(struct usb_device *udev, int ep, int mode)
pd->bus_index = device_get_unit(udev->bus->bdev);
pd->dev_index = udev->device_index;
pd->ep_addr = ep;
- pd->mode = mode;
+ pd->fifo_index = fi;
+ pd->mode = rwmode;
/* Now, create the device itself */
- snprintf(devname, sizeof(devname), "%u.%u.%u",
- pd->bus_index, pd->dev_index, pd->ep_addr);
- pd->cdev = make_dev(&usb_devsw, 0, UID_ROOT,
- GID_OPERATOR, 0600, USB_DEVICE_DIR "/%s", devname);
+ if (devname == NULL) {
+ devname = buffer;
+ snprintf(buffer, sizeof(buffer), USB_DEVICE_DIR "/%u.%u.%u",
+ pd->bus_index, pd->dev_index, pd->ep_addr);
+ }
+
+ pd->cdev = make_dev(&usb_devsw, 0, uid, gid, mode, "%s", devname);
+
+ if (pd->cdev == NULL) {
+ DPRINTFN(0, "Failed to create device %s\n", devname);
+ free(pd, M_USBDEV);
+ return (NULL);
+ }
+
+ /* XXX setting si_drv1 and creating the device is not atomic! */
pd->cdev->si_drv1 = pd;
- return (pd->cdev);
+ return (pd);
+}
+
+void
+usb_destroy_dev(struct usb_fs_privdata *pd)
+{
+ if (pd == NULL)
+ return;
+
+ destroy_dev(pd->cdev);
+
+ free(pd, M_USBDEV);
}
static void
@@ -1912,7 +1948,6 @@ usb_cdev_create(struct usb_device *udev)
struct usb_endpoint_descriptor *ed;
struct usb_descriptor *desc;
struct usb_fs_privdata* pd;
- struct cdev *dev;
int inmode, outmode, inmask, outmask, mode;
uint8_t ep;
@@ -1954,14 +1989,16 @@ usb_cdev_create(struct usb_device *udev)
/* Create all available endpoints except EP0 */
for (ep = 1; ep < 16; ep++) {
- mode = inmask & (1 << ep) ? inmode : 0;
- mode |= outmask & (1 << ep) ? outmode : 0;
+ mode = (inmask & (1 << ep)) ? inmode : 0;
+ mode |= (outmask & (1 << ep)) ? outmode : 0;
if (mode == 0)
continue; /* no IN or OUT endpoint */
- dev = usb_make_dev(udev, ep, mode);
- pd = dev->si_drv1;
- LIST_INSERT_HEAD(&udev->pd_list, pd, pd_next);
+ pd = usb_make_dev(udev, NULL, ep, 0,
+ mode, UID_ROOT, GID_OPERATOR, 0600);
+
+ if (pd != NULL)
+ LIST_INSERT_HEAD(&udev->pd_list, pd, pd_next);
}
}
@@ -1969,25 +2006,16 @@ static void
usb_cdev_free(struct usb_device *udev)
{
struct usb_fs_privdata* pd;
- struct cdev* pcdev;
DPRINTFN(2, "Freeing device nodes\n");
while ((pd = LIST_FIRST(&udev->pd_list)) != NULL) {
KASSERT(pd->cdev->si_drv1 == pd, ("privdata corrupt"));
- pcdev = pd->cdev;
- pd->cdev = NULL;
LIST_REMOVE(pd, pd_next);
- if (pcdev != NULL)
- destroy_dev_sched_cb(pcdev, usb_cdev_cleanup, pd);
- }
-}
-static void
-usb_cdev_cleanup(void* arg)
-{
- free(arg, M_USBDEV);
+ usb_destroy_dev(pd);
+ }
}
#endif
@@ -2012,9 +2040,11 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
bus = udev->bus;
usb_set_device_state(udev, USB_STATE_DETACHED);
-#if USB_HAVE_UGEN
+#if USB_HAVE_DEVCTL
usb_notify_addq("DETACH", udev);
+#endif
+#if USB_HAVE_UGEN
printf("%s: <%s> at %s (disconnected)\n", udev->ugen_name,
usb_get_manufacturer(udev), device_get_nameunit(bus->bdev));
@@ -2041,8 +2071,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
}
mtx_unlock(&usb_ref_lock);
- destroy_dev_sched_cb(udev->ctrl_dev, usb_cdev_cleanup,
- udev->ctrl_dev->si_drv1);
+ usb_destroy_dev(udev->ctrl_dev);
#endif
if (udev->flags.usb_mode == USB_MODE_DEVICE) {
@@ -2068,7 +2097,6 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
&udev->cs_msg[0], &udev->cs_msg[1]);
USB_BUS_UNLOCK(udev->bus);
- sx_destroy(&udev->ctrl_sx);
sx_destroy(&udev->enum_sx);
sx_destroy(&udev->sr_sx);
@@ -2231,9 +2259,13 @@ usbd_set_device_strings(struct usb_device *udev)
size_t temp_size;
uint16_t vendor_id;
uint16_t product_id;
+ uint8_t do_unlock;
+
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
- temp_ptr = (char *)udev->bus->scratch[0].data;
- temp_size = sizeof(udev->bus->scratch[0].data);
+ temp_ptr = (char *)udev->scratch.data;
+ temp_size = sizeof(udev->scratch.data);
vendor_id = UGETW(udd->idVendor);
product_id = UGETW(udd->idProduct);
@@ -2288,6 +2320,9 @@ usbd_set_device_strings(struct usb_device *udev)
snprintf(temp_ptr, temp_size, "product 0x%04x", product_id);
udev->product = strdup(temp_ptr, M_USB);
}
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
}
/*
@@ -2350,8 +2385,22 @@ uint8_t
usb_test_quirk(const struct usb_attach_arg *uaa, uint16_t quirk)
{
uint8_t found;
+ uint8_t x;
+
+ if (quirk == UQ_NONE)
+ return (0);
+
+ /* search the automatic per device quirks first */
+
+ for (x = 0; x != USB_MAX_AUTO_QUIRK; x++) {
+ if (uaa->device->autoQuirk[x] == quirk)
+ return (1);
+ }
+
+ /* search global quirk table, if any */
found = (usb_test_quirk_p) (&uaa->info, quirk);
+
return (found);
}
@@ -2381,7 +2430,7 @@ usbd_get_device_index(struct usb_device *udev)
return (udev->device_index);
}
-#if USB_HAVE_UGEN
+#if USB_HAVE_DEVCTL
/*------------------------------------------------------------------------*
* usb_notify_addq
*
@@ -2417,29 +2466,37 @@ usb_notify_addq_compat(const char *type, struct usb_device *udev)
/* String it all together. */
snprintf(data, buf_size,
"%s"
+#if USB_HAVE_UGEN
"%s "
+#endif
+ "at port=%u "
"vendor=0x%04x "
"product=0x%04x "
"devclass=0x%02x "
"devsubclass=0x%02x "
"sernum=\"%s\" "
"release=0x%04x "
- "at "
- "port=%u "
- "on "
- "%s\n",
+#if USB_HAVE_UGEN
+ "on %s\n"
+#endif
+ "",
ntype,
+#if USB_HAVE_UGEN
udev->ugen_name,
+#endif
+ udev->port_no,
UGETW(udev->ddesc.idVendor),
UGETW(udev->ddesc.idProduct),
udev->ddesc.bDeviceClass,
udev->ddesc.bDeviceSubClass,
usb_get_serial(udev),
- UGETW(udev->ddesc.bcdDevice),
- udev->port_no,
- udev->parent_hub != NULL ?
+ UGETW(udev->ddesc.bcdDevice)
+#if USB_HAVE_UGEN
+ , udev->parent_hub != NULL ?
udev->parent_hub->ugen_name :
- device_get_nameunit(device_get_parent(udev->bus->bdev)));
+ device_get_nameunit(device_get_parent(udev->bus->bdev))
+#endif
+ );
devctl_queue_data(data);
}
@@ -2459,7 +2516,10 @@ usb_notify_addq(const char *type, struct usb_device *udev)
/* announce the device */
sb = sbuf_new_auto();
sbuf_printf(sb,
+#if USB_HAVE_UGEN
+ "ugen=%s "
"cdev=%s "
+#endif
"vendor=0x%04x "
"product=0x%04x "
"devclass=0x%02x "
@@ -2468,8 +2528,14 @@ usb_notify_addq(const char *type, struct usb_device *udev)
"release=0x%04x "
"mode=%s "
"port=%u "
- "parent=%s\n",
+#if USB_HAVE_UGEN
+ "parent=%s"
+#endif
+ "",
+#if USB_HAVE_UGEN
udev->ugen_name,
+ udev->ugen_name,
+#endif
UGETW(udev->ddesc.idVendor),
UGETW(udev->ddesc.idProduct),
udev->ddesc.bDeviceClass,
@@ -2477,10 +2543,13 @@ usb_notify_addq(const char *type, struct usb_device *udev)
usb_get_serial(udev),
UGETW(udev->ddesc.bcdDevice),
(udev->flags.usb_mode == USB_MODE_HOST) ? "host" : "device",
- udev->port_no,
- udev->parent_hub != NULL ?
- udev->parent_hub->ugen_name :
- device_get_nameunit(device_get_parent(udev->bus->bdev)));
+ udev->port_no
+#if USB_HAVE_UGEN
+ , udev->parent_hub != NULL ?
+ udev->parent_hub->ugen_name :
+ device_get_nameunit(device_get_parent(udev->bus->bdev))
+#endif
+ );
sbuf_finish(sb);
devctl_notify("USB", "DEVICE", type, sbuf_data(sb));
sbuf_delete(sb);
@@ -2495,7 +2564,10 @@ usb_notify_addq(const char *type, struct usb_device *udev)
sb = sbuf_new_auto();
sbuf_printf(sb,
+#if USB_HAVE_UGEN
+ "ugen=%s "
"cdev=%s "
+#endif
"vendor=0x%04x "
"product=0x%04x "
"devclass=0x%02x "
@@ -2507,8 +2579,11 @@ usb_notify_addq(const char *type, struct usb_device *udev)
"endpoints=%d "
"intclass=0x%02x "
"intsubclass=0x%02x "
- "intprotocol=0x%02x\n",
+ "intprotocol=0x%02x",
+#if USB_HAVE_UGEN
+ udev->ugen_name,
udev->ugen_name,
+#endif
UGETW(udev->ddesc.idVendor),
UGETW(udev->ddesc.idProduct),
udev->ddesc.bDeviceClass,
@@ -2526,7 +2601,9 @@ usb_notify_addq(const char *type, struct usb_device *udev)
sbuf_delete(sb);
}
}
+#endif
+#if USB_HAVE_UGEN
/*------------------------------------------------------------------------*
* usb_fifo_free_wrap
*
@@ -2633,11 +2710,17 @@ usbd_device_attached(struct usb_device *udev)
return (udev->state > USB_STATE_DETACHED);
}
-/* The following function locks enumerating the given USB device. */
-
-void
+/*
+ * The following function locks enumerating the given USB device. If
+ * the lock is already grabbed this function returns zero. Else a
+ * non-zero value is returned.
+ */
+uint8_t
usbd_enum_lock(struct usb_device *udev)
{
+ if (sx_xlocked(&udev->enum_sx))
+ return (0);
+
sx_xlock(&udev->enum_sx);
sx_xlock(&udev->sr_sx);
/*
@@ -2646,6 +2729,7 @@ usbd_enum_lock(struct usb_device *udev)
* locked multiple times.
*/
mtx_lock(&Giant);
+ return (1);
}
/* The following function unlocks enumerating the given USB device. */
@@ -2691,3 +2775,51 @@ usbd_enum_is_locked(struct usb_device *udev)
{
return (sx_xlocked(&udev->enum_sx));
}
+
+/*
+ * The following function is used to set the per-interface specific
+ * plug and play information. The string referred to by the pnpinfo
+ * argument can safely be freed after calling this function. The
+ * pnpinfo of an interface will be reset at device detach or when
+ * passing a NULL argument to this function. This function
+ * returns zero on success, else a USB_ERR_XXX failure code.
+ */
+
+usb_error_t
+usbd_set_pnpinfo(struct usb_device *udev, uint8_t iface_index, const char *pnpinfo)
+{
+ struct usb_interface *iface;
+
+ iface = usbd_get_iface(udev, iface_index);
+ if (iface == NULL)
+ return (USB_ERR_INVAL);
+
+ if (iface->pnpinfo != NULL) {
+ free(iface->pnpinfo, M_USBDEV);
+ iface->pnpinfo = NULL;
+ }
+
+ if (pnpinfo == NULL || pnpinfo[0] == 0)
+ return (0); /* success */
+
+ iface->pnpinfo = strdup(pnpinfo, M_USBDEV);
+ if (iface->pnpinfo == NULL)
+ return (USB_ERR_NOMEM);
+
+ return (0); /* success */
+}
+
+usb_error_t
+usbd_add_dynamic_quirk(struct usb_device *udev, uint16_t quirk)
+{
+ uint8_t x;
+
+ for (x = 0; x != USB_MAX_AUTO_QUIRK; x++) {
+ if (udev->autoQuirk[x] == 0 ||
+ udev->autoQuirk[x] == quirk) {
+ udev->autoQuirk[x] = quirk;
+ return (0); /* success */
+ }
+ }
+ return (USB_ERR_NOMEM);
+}
diff --git a/freebsd/sys/dev/usb/usb_device.h b/freebsd/sys/dev/usb/usb_device.h
index c8bc5eb9..03ddf1e6 100644
--- a/freebsd/sys/dev/usb/usb_device.h
+++ b/freebsd/sys/dev/usb/usb_device.h
@@ -27,8 +27,18 @@
#ifndef _USB_DEVICE_H_
#define _USB_DEVICE_H_
-struct usb_symlink; /* UGEN */
+#ifndef USB_GLOBAL_INCLUDE_FILE
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_transfer.h>
+#endif
+
+struct usb_bus_methods;
+struct usb_config_descriptor;
struct usb_device; /* linux compat */
+struct usb_fs_privdata;
+struct usb_hw_ep_profile;
+struct usb_symlink; /* UGEN */
#define USB_CTRL_XFER_MAX 2
@@ -107,13 +117,70 @@ struct usb_power_save {
};
/*
+ * The following structure is used when trying to allocate hardware
+ * endpoints for an USB configuration in USB device side mode.
+ */
+struct usb_hw_ep_scratch_sub {
+ const struct usb_hw_ep_profile *pf;
+ uint16_t max_frame_size;
+ uint8_t hw_endpoint_out;
+ uint8_t hw_endpoint_in;
+ uint8_t needs_ep_type;
+ uint8_t needs_in:1;
+ uint8_t needs_out:1;
+};
+
+/*
+ * The following structure is used when trying to allocate hardware
+ * endpoints for an USB configuration in USB device side mode.
+ */
+struct usb_hw_ep_scratch {
+ struct usb_hw_ep_scratch_sub ep[USB_EP_MAX];
+ struct usb_hw_ep_scratch_sub *ep_max;
+ struct usb_config_descriptor *cd;
+ struct usb_device *udev;
+ struct usb_bus_methods *methods;
+ uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16];
+ uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16];
+};
+
+/*
+ * The following structure is used when generating USB descriptors
+ * from USB templates.
+ */
+struct usb_temp_setup {
+ void *buf;
+ usb_size_t size;
+ enum usb_dev_speed usb_speed;
+ uint8_t self_powered;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bConfigurationValue;
+ usb_error_t err;
+};
+
+/*
+ * The scratch area for USB devices. Access to this structure is
+ * protected by the enumeration SX lock.
+ */
+union usb_device_scratch {
+ struct usb_hw_ep_scratch hw_ep_scratch[1];
+ struct usb_temp_setup temp_setup[1];
+ struct {
+ struct usb_xfer dummy;
+ struct usb_setup_params parm;
+ } xfer_setup[1];
+ uint8_t data[255];
+};
+
+/*
* The following structure defines an USB device. There exists one of
* these structures for every USB device.
*/
struct usb_device {
struct usb_clear_stall_msg cs_msg[2]; /* generic clear stall
* messages */
- struct sx ctrl_sx;
struct sx enum_sx;
struct sx sr_sx;
struct mtx device_mtx;
@@ -135,7 +202,7 @@ struct usb_device {
#if USB_HAVE_UGEN
struct usb_fifo *fifo[USB_FIFO_MAX];
struct usb_symlink *ugen_symlink; /* our generic symlink */
- struct cdev *ctrl_dev; /* Control Endpoint 0 device node */
+ struct usb_fs_privdata *ctrl_dev; /* Control Endpoint 0 device node */
LIST_HEAD(,usb_fs_privdata) pd_list;
char ugen_name[20]; /* name of ugenX.X device */
#endif
@@ -187,6 +254,12 @@ struct usb_device {
struct usb_host_endpoint *linux_endpoint_end;
uint16_t devnum;
#endif
+
+ uint32_t clear_stall_errors; /* number of clear-stall failures */
+
+ uint16_t autoQuirk[USB_MAX_AUTO_QUIRK]; /* dynamic quirks */
+
+ union usb_device_scratch scratch;
};
/* globals */
@@ -200,6 +273,11 @@ struct usb_device *usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
struct usb_device *parent_hub, uint8_t depth,
uint8_t port_index, uint8_t port_no,
enum usb_dev_speed speed, enum usb_hc_mode mode);
+#if USB_HAVE_UGEN
+struct usb_fs_privdata *usb_make_dev(struct usb_device *, const char *,
+ int, int, int, uid_t, gid_t, int);
+void usb_destroy_dev(struct usb_fs_privdata *);
+#endif
usb_error_t usb_probe_and_attach(struct usb_device *udev,
uint8_t iface_index);
void usb_detach_device(struct usb_device *, uint8_t, uint8_t);
@@ -218,7 +296,7 @@ struct usb_endpoint *usb_endpoint_foreach(struct usb_device *udev, struct usb_en
void usb_set_device_state(struct usb_device *, enum usb_dev_state);
enum usb_dev_state usb_get_device_state(struct usb_device *);
-void usbd_enum_lock(struct usb_device *);
+uint8_t usbd_enum_lock(struct usb_device *);
void usbd_enum_unlock(struct usb_device *);
void usbd_sr_lock(struct usb_device *);
void usbd_sr_unlock(struct usb_device *);
diff --git a/freebsd/sys/dev/usb/usb_dynamic.c b/freebsd/sys/dev/usb/usb_dynamic.c
index cb54d10f..31e78225 100644
--- a/freebsd/sys/dev/usb/usb_dynamic.c
+++ b/freebsd/sys/dev/usb/usb_dynamic.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
diff --git a/freebsd/sys/dev/usb/usb_error.c b/freebsd/sys/dev/usb/usb_error.c
index 4505490d..9f6e4569 100644
--- a/freebsd/sys/dev/usb/usb_error.c
+++ b/freebsd/sys/dev/usb/usb_error.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
diff --git a/freebsd/sys/dev/usb/usb_freebsd.h b/freebsd/sys/dev/usb/usb_freebsd.h
index 3045ec32..8f9bb4c6 100644
--- a/freebsd/sys/dev/usb/usb_freebsd.h
+++ b/freebsd/sys/dev/usb/usb_freebsd.h
@@ -34,6 +34,7 @@
/* Default USB configuration */
#ifndef __rtems__
#define USB_HAVE_UGEN 1
+#define USB_HAVE_DEVCTL 1
#define USB_HAVE_BUSDMA 1
#define USB_HAVE_COMPAT_LINUX 1
#define USB_HAVE_USER_IO 1
@@ -41,6 +42,7 @@
#define USB_HAVE_TT_SUPPORT 1
#define USB_HAVE_POWERD 1
#define USB_HAVE_MSCTEST 1
+#define USB_HAVE_PF 1
#endif /* __rtems__ */
#define USB_TD_GET_PROC(td) (td)->td_proc
@@ -58,6 +60,9 @@
#define USB_HUB_MAX_DEPTH 5
#define USB_EP0_BUFSIZE 1024 /* bytes */
+#define USB_CS_RESET_LIMIT 20 /* failures = 20 * 50 ms = 1sec */
+
+#define USB_MAX_AUTO_QUIRK 4 /* maximum number of dynamic quirks */
typedef uint32_t usb_timeout_t; /* milliseconds */
typedef uint32_t usb_frlength_t; /* bytes */
diff --git a/freebsd/sys/dev/usb/usb_generic.c b/freebsd/sys/dev/usb/usb_generic.c
index 60b24794..4e439e15 100644
--- a/freebsd/sys/dev/usb/usb_generic.c
+++ b/freebsd/sys/dev/usb/usb_generic.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -130,9 +129,8 @@ struct usb_fifo_methods usb_ugen_methods = {
static int ugen_debug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB generic");
-SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW, &ugen_debug,
+SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &ugen_debug,
0, "Debug level");
-
TUNABLE_INT("hw.usb.ugen.debug", &ugen_debug);
#endif
@@ -243,7 +241,7 @@ ugen_open_pipe_write(struct usb_fifo *f)
/* transfers are already opened */
return (0);
}
- bzero(usb_config, sizeof(usb_config));
+ memset(usb_config, 0, sizeof(usb_config));
usb_config[1].type = UE_CONTROL;
usb_config[1].endpoint = 0;
@@ -311,7 +309,7 @@ ugen_open_pipe_read(struct usb_fifo *f)
/* transfers are already opened */
return (0);
}
- bzero(usb_config, sizeof(usb_config));
+ memset(usb_config, 0, sizeof(usb_config));
usb_config[1].type = UE_CONTROL;
usb_config[1].endpoint = 0;
@@ -717,13 +715,20 @@ ugen_get_cdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd)
return (error);
}
+/*
+ * This function is called having the enumeration SX locked which
+ * protects the scratch area used.
+ */
static int
ugen_get_sdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd)
{
- void *ptr = f->udev->bus->scratch[0].data;
- uint16_t size = sizeof(f->udev->bus->scratch[0].data);
+ void *ptr;
+ uint16_t size;
int error;
+ ptr = f->udev->scratch.data;
+ size = sizeof(f->udev->scratch.data);
+
if (usbd_req_get_string_desc(f->udev, NULL, ptr,
size, ugd->ugd_lang_id, ugd->ugd_string_index)) {
error = EINVAL;
@@ -955,18 +960,22 @@ ugen_re_enumerate(struct usb_fifo *f)
}
if (udev->flags.usb_mode != USB_MODE_HOST) {
/* not possible in device side mode */
+ DPRINTFN(6, "device mode\n");
return (ENOTTY);
}
+ if (udev->parent_hub == NULL) {
+ /* the root HUB cannot be re-enumerated */
+ DPRINTFN(6, "cannot reset root HUB\n");
+ return (EINVAL);
+ }
/* make sure all FIFO's are gone */
/* else there can be a deadlock */
if (ugen_fs_uninit(f)) {
/* ignore any errors */
DPRINTFN(6, "no FIFOs\n");
}
- if (udev->re_enumerate_wait == 0) {
- udev->re_enumerate_wait = 1;
- usb_needs_explore(udev->bus, 0);
- }
+ /* start re-enumeration of device */
+ usbd_start_re_enumerate(udev);
return (0);
}
@@ -1396,10 +1405,12 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
} u;
struct usb_endpoint *ep;
struct usb_endpoint_descriptor *ed;
+ struct usb_xfer *xfer;
int error = 0;
uint8_t iface_index;
uint8_t isread;
uint8_t ep_index;
+ uint8_t pre_scale;
u.addr = addr;
@@ -1421,11 +1432,11 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
case USB_FS_START:
error = ugen_fs_copy_in(f, u.pstart->ep_index);
- if (error) {
+ if (error)
break;
- }
mtx_lock(f->priv_mtx);
- usbd_transfer_start(f->fs_xfer[u.pstart->ep_index]);
+ xfer = f->fs_xfer[u.pstart->ep_index];
+ usbd_transfer_start(xfer);
mtx_unlock(f->priv_mtx);
break;
@@ -1435,7 +1446,19 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
break;
}
mtx_lock(f->priv_mtx);
- usbd_transfer_stop(f->fs_xfer[u.pstop->ep_index]);
+ xfer = f->fs_xfer[u.pstart->ep_index];
+ if (usbd_transfer_pending(xfer)) {
+ usbd_transfer_stop(xfer);
+ /*
+ * Check if the USB transfer was stopped
+ * before it was even started. Else a cancel
+ * callback will be pending.
+ */
+ if (!xfer->flags_int.transferring) {
+ ugen_fs_set_complete(xfer->priv_sc,
+ USB_P2U(xfer->priv_fifo));
+ }
+ }
mtx_unlock(f->priv_mtx);
break;
@@ -1451,6 +1474,12 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
if (u.popen->max_bufsize > USB_FS_MAX_BUFSIZE) {
u.popen->max_bufsize = USB_FS_MAX_BUFSIZE;
}
+ if (u.popen->max_frames & USB_FS_MAX_FRAMES_PRE_SCALE) {
+ pre_scale = 1;
+ u.popen->max_frames &= ~USB_FS_MAX_FRAMES_PRE_SCALE;
+ } else {
+ pre_scale = 0;
+ }
if (u.popen->max_frames > USB_FS_MAX_FRAMES) {
u.popen->max_frames = USB_FS_MAX_FRAMES;
break;
@@ -1471,13 +1500,15 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
}
iface_index = ep->iface_index;
- bzero(usb_config, sizeof(usb_config));
+ memset(usb_config, 0, sizeof(usb_config));
usb_config[0].type = ed->bmAttributes & UE_XFERTYPE;
usb_config[0].endpoint = ed->bEndpointAddress & UE_ADDR;
usb_config[0].direction = ed->bEndpointAddress & (UE_DIR_OUT | UE_DIR_IN);
usb_config[0].interval = USB_DEFAULT_INTERVAL;
usb_config[0].flags.proxy_buffer = 1;
+ if (pre_scale != 0)
+ usb_config[0].flags.pre_scale_frames = 1;
usb_config[0].callback = &ugen_ctrl_fs_callback;
usb_config[0].timeout = 0; /* no timeout */
usb_config[0].frames = u.popen->max_frames;
@@ -1519,6 +1550,10 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
f->fs_xfer[u.popen->ep_index]->max_frame_size;
u.popen->max_bufsize =
f->fs_xfer[u.popen->ep_index]->max_data_length;
+ /* update number of frames */
+ u.popen->max_frames =
+ f->fs_xfer[u.popen->ep_index]->nframes;
+ /* store index of endpoint */
f->fs_xfer[u.popen->ep_index]->priv_fifo =
((uint8_t *)0) + u.popen->ep_index;
} else {
@@ -2139,7 +2174,16 @@ ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
break;
}
+ /*
+ * Detach the currently attached driver.
+ */
usb_detach_device(f->udev, n, 0);
+
+ /*
+ * Set parent to self, this should keep attach away
+ * until the next set configuration event.
+ */
+ usbd_set_parent_iface(f->udev, n, n);
break;
case USB_SET_POWER_MODE:
diff --git a/freebsd/sys/dev/usb/usb_handle_request.c b/freebsd/sys/dev/usb/usb_handle_request.c
index 97d30394..d1df80a1 100644
--- a/freebsd/sys/dev/usb/usb_handle_request.c
+++ b/freebsd/sys/dev/usb/usb_handle_request.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -148,6 +147,7 @@ usb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no)
{
struct usb_device *udev = xfer->xroot->udev;
usb_error_t err = 0;
+ uint8_t do_unlock;
/*
* We need to protect against other threads doing probe and
@@ -155,7 +155,8 @@ usb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no)
*/
USB_XFER_UNLOCK(xfer);
- usbd_enum_lock(udev);
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
if (conf_no == USB_UNCONFIG_NO) {
conf_no = USB_UNCONFIG_INDEX;
@@ -178,7 +179,8 @@ usb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no)
goto done;
}
done:
- usbd_enum_unlock(udev);
+ if (do_unlock)
+ usbd_enum_unlock(udev);
USB_XFER_LOCK(xfer);
return (err);
}
@@ -190,13 +192,8 @@ usb_check_alt_setting(struct usb_device *udev,
uint8_t do_unlock;
usb_error_t err = 0;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc))
err = USB_ERR_INVAL;
@@ -225,6 +222,7 @@ usb_handle_iface_request(struct usb_xfer *xfer,
int error;
uint8_t iface_index;
uint8_t temp_state;
+ uint8_t do_unlock;
if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
iface_index = req.wIndex[0]; /* unicast */
@@ -238,7 +236,8 @@ usb_handle_iface_request(struct usb_xfer *xfer,
*/
USB_XFER_UNLOCK(xfer);
- usbd_enum_lock(udev);
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
error = ENXIO;
@@ -354,17 +353,20 @@ tr_repeat:
goto tr_stalled;
}
tr_valid:
- usbd_enum_unlock(udev);
+ if (do_unlock)
+ usbd_enum_unlock(udev);
USB_XFER_LOCK(xfer);
return (0);
tr_short:
- usbd_enum_unlock(udev);
+ if (do_unlock)
+ usbd_enum_unlock(udev);
USB_XFER_LOCK(xfer);
return (USB_ERR_SHORT_XFER);
tr_stalled:
- usbd_enum_unlock(udev);
+ if (do_unlock)
+ usbd_enum_unlock(udev);
USB_XFER_LOCK(xfer);
return (USB_ERR_STALLED);
}
@@ -440,8 +442,10 @@ usb_handle_remote_wakeup(struct usb_xfer *xfer, uint8_t is_on)
USB_BUS_UNLOCK(bus);
+#if USB_HAVE_POWERD
/* In case we are out of sync, update the power state. */
usb_bus_power_update(udev->bus);
+#endif
return (0); /* success */
}
@@ -467,7 +471,6 @@ usb_handle_request(struct usb_xfer *xfer)
uint16_t rem; /* data remainder */
uint16_t max_len; /* max fragment length */
uint16_t wValue;
- uint16_t wIndex;
uint8_t state;
uint8_t is_complete = 1;
usb_error_t err;
@@ -533,11 +536,10 @@ usb_handle_request(struct usb_xfer *xfer)
/* get some request fields decoded */
wValue = UGETW(req.wValue);
- wIndex = UGETW(req.wIndex);
DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x "
"off=0x%x rem=0x%x, state=%d\n", req.bmRequestType,
- req.bRequest, wValue, wIndex, off, rem, state);
+ req.bRequest, wValue, UGETW(req.wIndex), off, rem, state);
/* demultiplex the control request */
diff --git a/freebsd/sys/dev/usb/usb_hid.c b/freebsd/sys/dev/usb/usb_hid.c
index e99cdb0b..0dc146df 100644
--- a/freebsd/sys/dev/usb/usb_hid.c
+++ b/freebsd/sys/dev/usb/usb_hid.c
@@ -21,13 +21,6 @@ __FBSDID("$FreeBSD$");
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -50,7 +43,6 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -435,7 +427,7 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
s->loc_size = dval & mask;
break;
case 8:
- hid_switch_rid(s, c, dval);
+ hid_switch_rid(s, c, dval & mask);
break;
case 9:
/* mask because value is unsigned */
@@ -622,7 +614,7 @@ hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, uint8_t *id)
* hid_locate
*------------------------------------------------------------------------*/
int
-hid_locate(const void *desc, usb_size_t size, uint32_t u, enum hid_kind k,
+hid_locate(const void *desc, usb_size_t size, int32_t u, enum hid_kind k,
uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id)
{
struct hid_data *d;
@@ -712,10 +704,47 @@ hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, struct hid_location *l
}
/*------------------------------------------------------------------------*
+ * hid_put_data
+ *------------------------------------------------------------------------*/
+void
+hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
+ struct hid_location *loc, unsigned int value)
+{
+ uint32_t hpos = loc->pos;
+ uint32_t hsize = loc->size;
+ uint64_t data;
+ uint64_t mask;
+ uint32_t rpos;
+ uint8_t n;
+
+ DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
+
+ /* Range check and limit */
+ if (hsize == 0)
+ return;
+ if (hsize > 32)
+ hsize = 32;
+
+ /* Put data in a safe way */
+ rpos = (hpos / 8);
+ n = (hsize + 7) / 8;
+ data = ((uint64_t)value) << (hpos % 8);
+ mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
+ rpos += n;
+ while (n--) {
+ rpos--;
+ if (rpos < len) {
+ buf[rpos] &= ~(mask >> (8 * n));
+ buf[rpos] |= (data >> (8 * n));
+ }
+ }
+}
+
+/*------------------------------------------------------------------------*
* hid_is_collection
*------------------------------------------------------------------------*/
int
-hid_is_collection(const void *desc, usb_size_t size, uint32_t usage)
+hid_is_collection(const void *desc, usb_size_t size, int32_t usage)
{
struct hid_data *hd;
struct hid_item hi;
diff --git a/freebsd/sys/dev/usb/usb_hub.c b/freebsd/sys/dev/usb/usb_hub.c
index c20bde30..c5887797 100644
--- a/freebsd/sys/dev/usb/usb_hub.c
+++ b/freebsd/sys/dev/usb/usb_hub.c
@@ -40,7 +40,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -80,9 +79,8 @@
static int uhub_debug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB");
-SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW, &uhub_debug, 0,
+SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &uhub_debug, 0,
"Debug level");
-
TUNABLE_INT("hw.usb.uhub.debug", &uhub_debug);
#endif
@@ -112,6 +110,7 @@ struct uhub_softc {
#define UHUB_PROTO(sc) ((sc)->sc_udev->ddesc.bDeviceProtocol)
#define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB)
#define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT)
+#define UHUB_IS_MULTI_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBMTT)
#define UHUB_IS_SUPER_SPEED(sc) (UHUB_PROTO(sc) == UDPROTO_SSHUB)
/* prototypes for type checking: */
@@ -243,11 +242,18 @@ uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up)
/* check if device should be re-enumerated */
if (child->flags.usb_mode == USB_MODE_HOST) {
- usbd_enum_lock(child);
+ uint8_t do_unlock;
+
+ do_unlock = usbd_enum_lock(child);
if (child->re_enumerate_wait) {
- err = usbd_set_config_index(child, USB_UNCONFIG_INDEX);
- if (err == 0)
- err = usbd_req_re_enumerate(child, NULL);
+ err = usbd_set_config_index(child,
+ USB_UNCONFIG_INDEX);
+ if (err != 0) {
+ DPRINTF("Unconfigure failed: "
+ "%s: Ignored.\n",
+ usbd_errstr(err));
+ }
+ err = usbd_req_re_enumerate(child, NULL);
if (err == 0)
err = usbd_set_config_index(child, 0);
if (err == 0) {
@@ -257,7 +263,8 @@ uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up)
child->re_enumerate_wait = 0;
err = 0;
}
- usbd_enum_unlock(child);
+ if (do_unlock)
+ usbd_enum_unlock(child);
}
/* check if probe and attach should be done */
@@ -325,6 +332,7 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
enum usb_dev_speed speed;
enum usb_hc_mode mode;
usb_error_t err;
+ uint16_t power_mask;
uint8_t timeout;
DPRINTF("reattaching port %d\n", portno);
@@ -367,10 +375,27 @@ repeat:
}
/* check if there is no power on the port and print a warning */
- if (!(sc->sc_st.port_status & UPS_PORT_POWER)) {
+ switch (udev->speed) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ case USB_SPEED_LOW:
+ power_mask = UPS_PORT_POWER;
+ break;
+ case USB_SPEED_SUPER:
+ if (udev->parent_hub == NULL)
+ power_mask = UPS_PORT_POWER;
+ else
+ power_mask = UPS_PORT_POWER_SS;
+ break;
+ default:
+ power_mask = 0;
+ break;
+ }
+ if (!(sc->sc_st.port_status & power_mask)) {
DPRINTF("WARNING: strange, connected port %d "
"has no power\n", portno);
}
+
/* check if the device is in Host Mode */
if (!(sc->sc_st.port_status & UPS_PORT_MODE_DEVICE)) {
@@ -394,7 +419,7 @@ repeat:
/* wait for maximum device power up time */
usb_pause_mtx(NULL,
- USB_MS_TO_TICKS(USB_PORT_POWERUP_DELAY));
+ USB_MS_TO_TICKS(usb_port_powerup_delay));
/* reset port, which implies enabling it */
@@ -607,12 +632,15 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
}
} else {
switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) {
- case UPS_PORT_LS_U0:
- case UPS_PORT_LS_U1:
+ case UPS_PORT_LS_U3:
+ is_suspend = 1;
+ break;
+ case UPS_PORT_LS_SS_INA:
+ usbd_req_warm_reset_port(udev, NULL, portno);
is_suspend = 0;
break;
default:
- is_suspend = 1;
+ is_suspend = 0;
break;
}
}
@@ -629,8 +657,7 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
*/
if (is_suspend == 0)
usb_dev_resume_peer(child);
- else if ((child->flags.usb_mode == USB_MODE_DEVICE) ||
- (usb_device_20_compatible(child) == 0))
+ else if (child->flags.usb_mode == USB_MODE_DEVICE)
usb_dev_suspend_peer(child);
}
done:
@@ -688,6 +715,7 @@ uhub_explore(struct usb_device *udev)
usb_error_t err;
uint8_t portno;
uint8_t x;
+ uint8_t do_unlock;
hub = udev->hub;
sc = hub->hubsoftc;
@@ -704,6 +732,13 @@ uhub_explore(struct usb_device *udev)
DPRINTF("Device is suspended!\n");
return (0);
}
+
+ /*
+ * Make sure we don't race against user-space applications
+ * like LibUSB:
+ */
+ do_unlock = usbd_enum_lock(udev);
+
for (x = 0; x != hub->nports; x++) {
up = hub->ports + x;
portno = x + 1;
@@ -765,7 +800,8 @@ uhub_explore(struct usb_device *udev)
break;
}
}
- if (sc->sc_st.port_change & (UPS_C_SUSPEND | UPS_C_PORT_LINK_STATE)) {
+ if (sc->sc_st.port_change & (UPS_C_SUSPEND |
+ UPS_C_PORT_LINK_STATE)) {
err = uhub_suspend_resume_port(sc, portno);
if (err) {
/* most likely the HUB is gone */
@@ -781,6 +817,9 @@ uhub_explore(struct usb_device *udev)
up->restartcnt = 0;
}
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
/* initial status checked */
sc->sc_flags |= UHUB_FLAG_DID_EXPLORE;
@@ -916,6 +955,16 @@ uhub_attach(device_t dev)
"bus powered HUB. HUB ignored\n");
goto error;
}
+
+ if (UHUB_IS_MULTI_TT(sc)) {
+ err = usbd_set_alt_interface_index(udev, 0, 1);
+ if (err) {
+ device_printf(dev, "MTT could not be enabled\n");
+ goto error;
+ }
+ device_printf(dev, "MTT enabled\n");
+ }
+
/* get HUB descriptor */
DPRINTFN(2, "Getting HUB descriptor\n");
@@ -936,7 +985,7 @@ uhub_attach(device_t dev)
/* get power delay */
pwrdly = ((hubdesc20.bPwrOn2PwrGood * UHD_PWRON_FACTOR) +
- USB_EXTRA_POWER_UP_TIME);
+ usb_extra_power_up_time);
/* get complete HUB descriptor */
if (nports >= 8) {
@@ -981,7 +1030,7 @@ uhub_attach(device_t dev)
/* get power delay */
pwrdly = ((hubdesc30.bPwrOn2PwrGood * UHD_PWRON_FACTOR) +
- USB_EXTRA_POWER_UP_TIME);
+ usb_extra_power_up_time);
/* get complete HUB descriptor */
if (nports >= 8) {
@@ -1010,7 +1059,7 @@ uhub_attach(device_t dev)
/* default number of ports */
nports = 1;
/* default power delay */
- pwrdly = ((10 * UHD_PWRON_FACTOR) + USB_EXTRA_POWER_UP_TIME);
+ pwrdly = ((10 * UHD_PWRON_FACTOR) + usb_extra_power_up_time);
break;
}
if (nports == 0) {
@@ -1025,10 +1074,6 @@ uhub_attach(device_t dev)
}
udev->hub = hub;
-#if USB_HAVE_TT_SUPPORT
- /* init FULL-speed ISOCHRONOUS schedule */
- usbd_fs_isoc_schedule_init_all(hub->fs_isoc_schedule);
-#endif
/* initialize HUB structure */
hub->hubsoftc = sc;
hub->explore = &uhub_explore;
@@ -1332,15 +1377,21 @@ uhub_child_pnpinfo_string(device_t parent, device_t child,
"devclass=0x%02x devsubclass=0x%02x "
"sernum=\"%s\" "
"release=0x%04x "
- "intclass=0x%02x intsubclass=0x%02x",
+ "mode=%s "
+ "intclass=0x%02x intsubclass=0x%02x "
+ "intprotocol=0x%02x " "%s%s",
UGETW(res.udev->ddesc.idVendor),
UGETW(res.udev->ddesc.idProduct),
res.udev->ddesc.bDeviceClass,
res.udev->ddesc.bDeviceSubClass,
usb_get_serial(res.udev),
UGETW(res.udev->ddesc.bcdDevice),
+ (res.udev->flags.usb_mode == USB_MODE_HOST) ? "host" : "device",
iface->idesc->bInterfaceClass,
- iface->idesc->bInterfaceSubClass);
+ iface->idesc->bInterfaceSubClass,
+ iface->idesc->bInterfaceProtocol,
+ iface->pnpinfo ? " " : "",
+ iface->pnpinfo ? iface->pnpinfo : "");
} else {
if (buflen) {
buf[0] = '\0';
@@ -1393,7 +1444,7 @@ static uint8_t
usb_intr_find_best_slot(usb_size_t *ptr, uint8_t start,
uint8_t end, uint8_t mask)
{
- usb_size_t min = 0 - 1;
+ usb_size_t min = (usb_size_t)-1;
usb_size_t sum;
uint8_t x;
uint8_t y;
@@ -1618,42 +1669,6 @@ usb_hs_bandwidth_free(struct usb_xfer *xfer)
}
/*------------------------------------------------------------------------*
- * usbd_fs_isoc_schedule_init_sub
- *
- * This function initialises an USB FULL speed isochronous schedule
- * entry.
- *------------------------------------------------------------------------*/
-#if USB_HAVE_TT_SUPPORT
-static void
-usbd_fs_isoc_schedule_init_sub(struct usb_fs_isoc_schedule *fss)
-{
- fss->total_bytes = (USB_FS_ISOC_UFRAME_MAX *
- USB_FS_BYTES_PER_HS_UFRAME);
- fss->frame_bytes = (USB_FS_BYTES_PER_HS_UFRAME);
- fss->frame_slot = 0;
-}
-#endif
-
-/*------------------------------------------------------------------------*
- * usbd_fs_isoc_schedule_init_all
- *
- * This function will reset the complete USB FULL speed isochronous
- * bandwidth schedule.
- *------------------------------------------------------------------------*/
-#if USB_HAVE_TT_SUPPORT
-void
-usbd_fs_isoc_schedule_init_all(struct usb_fs_isoc_schedule *fss)
-{
- struct usb_fs_isoc_schedule *fss_end = fss + USB_ISOC_TIME_MAX;
-
- while (fss != fss_end) {
- usbd_fs_isoc_schedule_init_sub(fss);
- fss++;
- }
-}
-#endif
-
-/*------------------------------------------------------------------------*
* usb_isoc_time_expand
*
* This function will expand the time counter from 7-bit to 16-bit.
@@ -1685,114 +1700,130 @@ usb_isoc_time_expand(struct usb_bus *bus, uint16_t isoc_time_curr)
}
/*------------------------------------------------------------------------*
- * usbd_fs_isoc_schedule_isoc_time_expand
+ * usbd_fs_isoc_schedule_alloc_slot
*
- * This function does multiple things. First of all it will expand the
- * passed isochronous time, which is the return value. Then it will
- * store where the current FULL speed isochronous schedule is
- * positioned in time and where the end is. See "pp_start" and
- * "pp_end" arguments.
+ * This function will allocate bandwidth for an isochronous FULL speed
+ * transaction in the FULL speed schedule.
*
* Returns:
- * Expanded version of "isoc_time".
- *
- * NOTE: This function depends on being called regularly with
- * intervals less than "USB_ISOC_TIME_MAX".
+ * <8: Success
+ * Else: Error
*------------------------------------------------------------------------*/
#if USB_HAVE_TT_SUPPORT
-uint16_t
-usbd_fs_isoc_schedule_isoc_time_expand(struct usb_device *udev,
- struct usb_fs_isoc_schedule **pp_start,
- struct usb_fs_isoc_schedule **pp_end,
- uint16_t isoc_time)
+uint8_t
+usbd_fs_isoc_schedule_alloc_slot(struct usb_xfer *isoc_xfer, uint16_t isoc_time)
{
- struct usb_fs_isoc_schedule *fss_end;
- struct usb_fs_isoc_schedule *fss_a;
- struct usb_fs_isoc_schedule *fss_b;
- struct usb_hub *hs_hub;
+ struct usb_xfer *xfer;
+ struct usb_xfer *pipe_xfer;
+ struct usb_bus *bus;
+ usb_frlength_t len;
+ usb_frlength_t data_len;
+ uint16_t delta;
+ uint16_t slot;
+ uint8_t retval;
- isoc_time = usb_isoc_time_expand(udev->bus, isoc_time);
+ data_len = 0;
+ slot = 0;
- hs_hub = udev->parent_hs_hub->hub;
+ bus = isoc_xfer->xroot->bus;
- if (hs_hub != NULL) {
+ TAILQ_FOREACH(xfer, &bus->intr_q.head, wait_entry) {
- fss_a = hs_hub->fs_isoc_schedule +
- (hs_hub->isoc_last_time % USB_ISOC_TIME_MAX);
+ /* skip self, if any */
- hs_hub->isoc_last_time = isoc_time;
+ if (xfer == isoc_xfer)
+ continue;
+
+ /* check if this USB transfer is going through the same TT */
+
+ if (xfer->xroot->udev->parent_hs_hub !=
+ isoc_xfer->xroot->udev->parent_hs_hub) {
+ continue;
+ }
+ if ((isoc_xfer->xroot->udev->parent_hs_hub->
+ ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT) &&
+ (xfer->xroot->udev->hs_port_no !=
+ isoc_xfer->xroot->udev->hs_port_no)) {
+ continue;
+ }
+ if (xfer->endpoint->methods != isoc_xfer->endpoint->methods)
+ continue;
- fss_b = hs_hub->fs_isoc_schedule +
- (isoc_time % USB_ISOC_TIME_MAX);
+ /* check if isoc_time is part of this transfer */
- fss_end = hs_hub->fs_isoc_schedule + USB_ISOC_TIME_MAX;
+ delta = xfer->isoc_time_complete - isoc_time;
+ if (delta > 0 && delta <= xfer->nframes) {
+ delta = xfer->nframes - delta;
- *pp_start = hs_hub->fs_isoc_schedule;
- *pp_end = fss_end;
+ len = xfer->frlengths[delta];
+ len += 8;
+ len *= 7;
+ len /= 6;
- while (fss_a != fss_b) {
- if (fss_a == fss_end) {
- fss_a = hs_hub->fs_isoc_schedule;
+ data_len += len;
+ }
+
+ /* check double buffered transfers */
+
+ TAILQ_FOREACH(pipe_xfer, &xfer->endpoint->endpoint_q.head,
+ wait_entry) {
+
+ /* skip self, if any */
+
+ if (pipe_xfer == isoc_xfer)
continue;
+
+ /* check if isoc_time is part of this transfer */
+
+ delta = pipe_xfer->isoc_time_complete - isoc_time;
+ if (delta > 0 && delta <= pipe_xfer->nframes) {
+ delta = pipe_xfer->nframes - delta;
+
+ len = pipe_xfer->frlengths[delta];
+ len += 8;
+ len *= 7;
+ len /= 6;
+
+ data_len += len;
}
- usbd_fs_isoc_schedule_init_sub(fss_a);
- fss_a++;
}
+ }
- } else {
-
- *pp_start = NULL;
- *pp_end = NULL;
+ while (data_len >= USB_FS_BYTES_PER_HS_UFRAME) {
+ data_len -= USB_FS_BYTES_PER_HS_UFRAME;
+ slot++;
}
- return (isoc_time);
-}
-#endif
-/*------------------------------------------------------------------------*
- * usbd_fs_isoc_schedule_alloc
- *
- * This function will allocate bandwidth for an isochronous FULL speed
- * transaction in the FULL speed schedule. The microframe slot where
- * the transaction should be started is stored in the byte pointed to
- * by "pstart". The "len" argument specifies the length of the
- * transaction in bytes.
- *
- * Returns:
- * 0: Success
- * Else: Error
- *------------------------------------------------------------------------*/
-#if USB_HAVE_TT_SUPPORT
-uint8_t
-usbd_fs_isoc_schedule_alloc(struct usb_fs_isoc_schedule *fss,
- uint8_t *pstart, uint16_t len)
-{
- uint8_t slot = fss->frame_slot;
+ /* check for overflow */
+
+ if (slot >= USB_FS_ISOC_UFRAME_MAX)
+ return (255);
- /* Compute overhead and bit-stuffing */
+ retval = slot;
- len += 8;
+ delta = isoc_xfer->isoc_time_complete - isoc_time;
+ if (delta > 0 && delta <= isoc_xfer->nframes) {
+ delta = isoc_xfer->nframes - delta;
- len *= 7;
- len /= 6;
+ len = isoc_xfer->frlengths[delta];
+ len += 8;
+ len *= 7;
+ len /= 6;
- if (len > fss->total_bytes) {
- *pstart = 0; /* set some dummy value */
- return (1); /* error */
+ data_len += len;
}
- if (len > 0) {
- fss->total_bytes -= len;
+ while (data_len >= USB_FS_BYTES_PER_HS_UFRAME) {
+ data_len -= USB_FS_BYTES_PER_HS_UFRAME;
+ slot++;
+ }
- while (len >= fss->frame_bytes) {
- len -= fss->frame_bytes;
- fss->frame_bytes = USB_FS_BYTES_PER_HS_UFRAME;
- fss->frame_slot++;
- }
+ /* check for overflow */
- fss->frame_bytes -= len;
- }
- *pstart = slot;
- return (0); /* success */
+ if (slot >= USB_FS_ISOC_UFRAME_MAX)
+ return (255);
+
+ return (retval);
}
#endif
@@ -2046,7 +2077,6 @@ usb_peer_should_wakeup(struct usb_device *udev)
(udev->pwr_save.write_refs != 0) ||
((udev->pwr_save.read_refs != 0) &&
(udev->flags.usb_mode == USB_MODE_HOST) &&
- (usb_device_20_compatible(udev) != 0) &&
(usb_peer_can_wakeup(udev) == 0)));
}
@@ -2112,7 +2142,7 @@ usb_bus_powerd(struct usb_bus *bus)
/* reset counters */
- mintime = 0 - 1;
+ mintime = (usb_ticks_t)-1;
type_refs[0] = 0;
type_refs[1] = 0;
type_refs[2] = 0;
@@ -2149,7 +2179,7 @@ usb_bus_powerd(struct usb_bus *bus)
}
}
- if (mintime >= (1 * hz)) {
+ if (mintime >= (usb_ticks_t)(1 * hz)) {
/* recompute power masks */
DPRINTF("Recomputing power masks\n");
bus->hw_power_state = 0;
@@ -2226,10 +2256,18 @@ usb_dev_resume_peer(struct usb_device *udev)
DPRINTFN(0, "Resuming port failed\n");
return;
}
+ } else {
+ /* resume current port (Valid in Host and Device Mode) */
+ err = usbd_req_set_port_link_state(udev->parent_hub,
+ NULL, udev->port_no, UPS_PORT_LS_U0);
+ if (err) {
+ DPRINTFN(0, "Resuming port failed\n");
+ return;
+ }
}
/* resume settle time */
- usb_pause_mtx(NULL, USB_MS_TO_TICKS(USB_PORT_RESUME_DELAY));
+ usb_pause_mtx(NULL, USB_MS_TO_TICKS(usb_port_resume_delay));
if (bus->methods->device_resume != NULL) {
/* resume USB device on the USB controller */
@@ -2267,8 +2305,7 @@ usb_dev_resume_peer(struct usb_device *udev)
usbd_sr_unlock(udev);
/* check if peer has wakeup capability */
- if (usb_peer_can_wakeup(udev) &&
- usb_device_20_compatible(udev)) {
+ if (usb_peer_can_wakeup(udev)) {
/* clear remote wakeup */
err = usbd_req_clear_device_feature(udev,
NULL, UF_DEVICE_REMOTE_WAKEUP);
@@ -2329,8 +2366,7 @@ repeat:
}
}
- if (usb_peer_can_wakeup(udev) &&
- usb_device_20_compatible(udev)) {
+ if (usb_peer_can_wakeup(udev)) {
/*
* This request needs to be done before we set
* "udev->flags.self_suspended":
@@ -2362,8 +2398,7 @@ repeat:
USB_BUS_UNLOCK(udev->bus);
if (err != 0) {
- if (usb_peer_can_wakeup(udev) &&
- usb_device_20_compatible(udev)) {
+ if (usb_peer_can_wakeup(udev)) {
/* allow device to do remote wakeup */
err = usbd_req_clear_device_feature(udev,
NULL, UF_DEVICE_REMOTE_WAKEUP);
@@ -2385,7 +2420,7 @@ repeat:
NULL, udev->port_no, UHF_PORT_SUSPEND);
/* resume settle time */
- usb_pause_mtx(NULL, USB_MS_TO_TICKS(USB_PORT_RESUME_DELAY));
+ usb_pause_mtx(NULL, USB_MS_TO_TICKS(usb_port_resume_delay));
}
DPRINTF("Suspend was cancelled!\n");
return;
@@ -2419,6 +2454,14 @@ repeat:
DPRINTFN(0, "Suspending port failed\n");
return;
}
+ } else {
+ /* suspend current port */
+ err = usbd_req_set_port_link_state(udev->parent_hub,
+ NULL, udev->port_no, UPS_PORT_LS_U3);
+ if (err) {
+ DPRINTFN(0, "Suspending port failed\n");
+ return;
+ }
}
udev = udev->parent_hub;
@@ -2472,3 +2515,19 @@ usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode)
/* use fixed power mode given by hardware driver */
return (temp);
}
+
+/*------------------------------------------------------------------------*
+ * usbd_start_re_enumerate
+ *
+ * This function starts re-enumeration of the given USB device. This
+ * function does not need to be called BUS-locked. This function does
+ * not wait until the re-enumeration is completed.
+ *------------------------------------------------------------------------*/
+void
+usbd_start_re_enumerate(struct usb_device *udev)
+{
+ if (udev->re_enumerate_wait == 0) {
+ udev->re_enumerate_wait = 1;
+ usb_needs_explore(udev->bus, 0);
+ }
+}
diff --git a/freebsd/sys/dev/usb/usb_hub.h b/freebsd/sys/dev/usb/usb_hub.h
index 0f595997..23a1fa4f 100644
--- a/freebsd/sys/dev/usb/usb_hub.h
+++ b/freebsd/sys/dev/usb/usb_hub.h
@@ -38,22 +38,9 @@ struct usb_port {
};
/*
- * The following structure defines how many bytes are
- * left in an 1ms USB time slot.
- */
-struct usb_fs_isoc_schedule {
- uint16_t total_bytes;
- uint8_t frame_bytes;
- uint8_t frame_slot;
-};
-
-/*
* The following structure defines an USB HUB.
*/
struct usb_hub {
-#if USB_HAVE_TT_SUPPORT
- struct usb_fs_isoc_schedule fs_isoc_schedule[USB_ISOC_TIME_MAX];
-#endif
struct usb_device *hubudev; /* the HUB device */
usb_error_t (*explore) (struct usb_device *hub);
void *hubsoftc;
@@ -68,7 +55,6 @@ struct usb_hub {
void usb_hs_bandwidth_alloc(struct usb_xfer *xfer);
void usb_hs_bandwidth_free(struct usb_xfer *xfer);
-void usbd_fs_isoc_schedule_init_all(struct usb_fs_isoc_schedule *fss);
void usb_bus_port_set_device(struct usb_bus *bus, struct usb_port *up,
struct usb_device *udev, uint8_t device_index);
struct usb_device *usb_bus_port_get_device(struct usb_bus *bus,
diff --git a/freebsd/sys/dev/usb/usb_ioctl.h b/freebsd/sys/dev/usb/usb_ioctl.h
index f9018e28..9af6ee5c 100644
--- a/freebsd/sys/dev/usb/usb_ioctl.h
+++ b/freebsd/sys/dev/usb/usb_ioctl.h
@@ -39,15 +39,37 @@
#define USB_DEVICE_NAME "usbctl"
#define USB_DEVICE_DIR "usb"
#define USB_GENERIC_NAME "ugen"
+#define USB_TEMPLATE_SYSCTL "hw.usb.template" /* integer type */
+
+/* Definition of valid template sysctl values */
+
+enum {
+ USB_TEMP_MSC, /* USB Mass Storage */
+ USB_TEMP_CDCE, /* USB CDC Ethernet */
+ USB_TEMP_MTP, /* Message Transfer Protocol */
+ USB_TEMP_MODEM, /* USB CDC Modem */
+ USB_TEMP_AUDIO, /* USB Audio */
+ USB_TEMP_KBD, /* USB Keyboard */
+ USB_TEMP_MOUSE, /* USB Mouse */
+ USB_TEMP_MAX,
+};
struct usb_read_dir {
+#ifdef COMPAT_32BIT
+ uint64_t urd_data;
+#else
void *urd_data;
+#endif
uint32_t urd_startentry;
uint32_t urd_maxlen;
};
struct usb_ctl_request {
+#ifdef COMPAT_32BIT
+ uint64_t ucr_data;
+#else
void *ucr_data;
+#endif
uint16_t ucr_flags;
uint16_t ucr_actlen; /* actual length transferred */
uint8_t ucr_addr; /* zero - currently not used */
@@ -60,7 +82,11 @@ struct usb_alt_interface {
};
struct usb_gen_descriptor {
+#ifdef COMPAT_32BIT
+ uint64_t ugd_data;
+#else
void *ugd_data;
+#endif
uint16_t ugd_lang_id;
uint16_t ugd_maxlen;
uint16_t ugd_actlen;
@@ -126,9 +152,14 @@ struct usb_fs_endpoint {
* NOTE: isochronous USB transfer only use one buffer, but can have
* multiple frame lengths !
*/
+#ifdef COMPAT_32BIT
+ uint64_t ppBuffer;
+ uint64_t pLength;
+#else
void **ppBuffer; /* pointer to userland buffers */
uint32_t *pLength; /* pointer to frame lengths, updated
* to actual length */
+#endif
uint32_t nFrames; /* number of frames */
uint32_t aFrames; /* actual number of frames */
uint16_t flags;
@@ -150,7 +181,11 @@ struct usb_fs_endpoint {
struct usb_fs_init {
/* userland pointer to endpoints structure */
+#ifdef COMPAT_32BIT
+ uint64_t pEndpoints;
+#else
struct usb_fs_endpoint *pEndpoints;
+#endif
/* maximum number of endpoints */
uint8_t ep_index_max;
};
@@ -162,8 +197,9 @@ struct usb_fs_uninit {
struct usb_fs_open {
#define USB_FS_MAX_BUFSIZE (1 << 18)
uint32_t max_bufsize;
-#define USB_FS_MAX_FRAMES (1 << 12)
- uint32_t max_frames;
+#define USB_FS_MAX_FRAMES (1U << 12)
+#define USB_FS_MAX_FRAMES_PRE_SCALE (1U << 31) /* for ISOCHRONOUS transfers */
+ uint32_t max_frames; /* read and write */
uint16_t max_packet_length; /* read only */
uint8_t dev_index; /* currently unused */
uint8_t ep_index;
@@ -253,6 +289,10 @@ struct usb_gen_quirk {
#define USB_GET_CM_OVER_DATA _IOR ('U', 180, int)
#define USB_SET_CM_OVER_DATA _IOW ('U', 181, int)
+/* GPIO control */
+#define USB_GET_GPIO _IOR ('U', 182, int)
+#define USB_SET_GPIO _IOW ('U', 183, int)
+
/* USB file system interface */
#define USB_FS_START _IOW ('U', 192, struct usb_fs_start)
#define USB_FS_STOP _IOW ('U', 193, struct usb_fs_stop)
diff --git a/freebsd/sys/dev/usb/usb_lookup.c b/freebsd/sys/dev/usb/usb_lookup.c
index b7ce2522..ed752fed 100644
--- a/freebsd/sys/dev/usb/usb_lookup.c
+++ b/freebsd/sys/dev/usb/usb_lookup.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -45,6 +44,8 @@
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>
+#include <sys/limits.h>
+#include <sys/endian.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -108,13 +109,6 @@ usbd_lookup_id_by_info(const struct usb_device_id *id, usb_size_t sizeof_id,
(id->bDeviceProtocol != info->bDeviceProtocol)) {
continue;
}
- if ((info->bDeviceClass == 0xFF) &&
- (!(id->match_flag_vendor)) &&
- ((id->match_flag_int_class) ||
- (id->match_flag_int_subclass) ||
- (id->match_flag_int_protocol))) {
- continue;
- }
if ((id->match_flag_int_class) &&
(id->bInterfaceClass != info->bInterfaceClass)) {
continue;
@@ -154,3 +148,108 @@ usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id,
}
return (ENXIO);
}
+
+/*------------------------------------------------------------------------*
+ * Export the USB device ID format we use to userspace tools.
+ *------------------------------------------------------------------------*/
+#if BYTE_ORDER == BIG_ENDIAN
+#define U16_XOR "8"
+#define U32_XOR "12"
+#define U64_XOR "56"
+#define U8_BITFIELD_XOR "7"
+#define U16_BITFIELD_XOR "15"
+#define U32_BITFIELD_XOR "31"
+#define U64_BITFIELD_XOR "63"
+#else
+#define U16_XOR "0"
+#define U32_XOR "0"
+#define U64_XOR "0"
+#define U8_BITFIELD_XOR "0"
+#define U16_BITFIELD_XOR "0"
+#define U32_BITFIELD_XOR "0"
+#define U64_BITFIELD_XOR "0"
+#endif
+
+#if USB_HAVE_COMPAT_LINUX
+#define MFL_SIZE "1"
+#else
+#define MFL_SIZE "0"
+#endif
+
+#ifdef KLD_MODULE
+static const char __section("bus_autoconf_format") __used usb_id_format[] = {
+
+ /* Declare that three different sections use the same format */
+
+ "usb_host_id{256,:}"
+ "usb_device_id{256,:}"
+ "usb_dual_id{256,:}"
+
+ /* List size of fields in the usb_device_id structure */
+
+#if ULONG_MAX >= 0xFFFFFFFFUL
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+#if ULONG_MAX >= 0xFFFFFFFFFFFFFFFFULL
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+ "unused{0,8}"
+#endif
+#else
+#error "Please update code."
+#endif
+
+ "idVendor[0]{" U16_XOR ",8}"
+ "idVendor[1]{" U16_XOR ",8}"
+ "idProduct[0]{" U16_XOR ",8}"
+ "idProduct[1]{" U16_XOR ",8}"
+ "bcdDevice_lo[0]{" U16_XOR ",8}"
+ "bcdDevice_lo[1]{" U16_XOR ",8}"
+ "bcdDevice_hi[0]{" U16_XOR ",8}"
+ "bcdDevice_hi[1]{" U16_XOR ",8}"
+
+ "bDeviceClass{0,8}"
+ "bDeviceSubClass{0,8}"
+ "bDeviceProtocol{0,8}"
+ "bInterfaceClass{0,8}"
+ "bInterfaceSubClass{0,8}"
+ "bInterfaceProtocol{0,8}"
+
+ "mf_vendor{" U8_BITFIELD_XOR ",1}"
+ "mf_product{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_lo{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_hi{" U8_BITFIELD_XOR ",1}"
+
+ "mf_dev_class{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_subclass{" U8_BITFIELD_XOR ",1}"
+ "mf_dev_protocol{" U8_BITFIELD_XOR ",1}"
+ "mf_int_class{" U8_BITFIELD_XOR ",1}"
+
+ "mf_int_subclass{" U8_BITFIELD_XOR ",1}"
+ "mf_int_protocol{" U8_BITFIELD_XOR ",1}"
+ "unused{" U8_BITFIELD_XOR ",6}"
+
+ "mfl_vendor{" U16_XOR "," MFL_SIZE "}"
+ "mfl_product{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_lo{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_hi{" U16_XOR "," MFL_SIZE "}"
+
+ "mfl_dev_class{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_subclass{" U16_XOR "," MFL_SIZE "}"
+ "mfl_dev_protocol{" U16_XOR "," MFL_SIZE "}"
+ "mfl_int_class{" U16_XOR "," MFL_SIZE "}"
+
+ "mfl_int_subclass{" U16_XOR "," MFL_SIZE "}"
+ "mfl_int_protocol{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+ "unused{" U16_XOR "," MFL_SIZE "}"
+};
+#endif
diff --git a/freebsd/sys/dev/usb/usb_mbuf.c b/freebsd/sys/dev/usb/usb_mbuf.c
index f2649679..c6ee8ee5 100644
--- a/freebsd/sys/dev/usb/usb_mbuf.c
+++ b/freebsd/sys/dev/usb/usb_mbuf.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
diff --git a/freebsd/sys/dev/usb/usb_msctest.c b/freebsd/sys/dev/usb/usb_msctest.c
index 77f199be..018809d7 100644
--- a/freebsd/sys/dev/usb/usb_msctest.c
+++ b/freebsd/sys/dev/usb/usb_msctest.c
@@ -2,7 +2,7 @@
/* $FreeBSD$ */
/*-
- * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
+ * Copyright (c) 2008,2011 Hans Petter Selasky. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -42,7 +42,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -87,7 +86,10 @@ enum {
DIR_NONE,
};
+#define SCSI_MAX_LEN 0x100
#define SCSI_INQ_LEN 0x24
+#define SCSI_SENSE_LEN 0xFF
+
static uint8_t scsi_test_unit_ready[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static uint8_t scsi_inquiry[] = { 0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00 };
static uint8_t scsi_rezero_init[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -100,6 +102,10 @@ static uint8_t scsi_huawei_eject[] = { 0x11, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
static uint8_t scsi_tct_eject[] = { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 };
+static uint8_t scsi_sync_cache[] = { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+static uint8_t scsi_request_sense[] = { 0x03, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#define BULK_SIZE 64 /* dummy */
#define ERR_CSW_FAILED -1
@@ -153,7 +159,7 @@ struct bbb_transfer {
uint8_t status_try;
int error;
- uint8_t buffer[256];
+ uint8_t buffer[SCSI_MAX_LEN] __aligned(4);
};
static usb_callback_t bbb_command_callback;
@@ -167,7 +173,7 @@ static void bbb_done(struct bbb_transfer *, int);
static void bbb_transfer_start(struct bbb_transfer *, uint8_t);
static void bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t,
uint8_t);
-static uint8_t bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
+static int bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
void *, size_t, void *, size_t, usb_timeout_t);
static struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t);
static void bbb_detach(struct bbb_transfer *);
@@ -179,6 +185,7 @@ static const struct usb_config bbb_config[ST_MAX] = {
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.bufsize = sizeof(struct bbb_cbw),
+ .flags = {.ext_buffer = 1,},
.callback = &bbb_command_callback,
.timeout = 4 * USB_MS_HZ, /* 4 seconds */
},
@@ -188,7 +195,7 @@ static const struct usb_config bbb_config[ST_MAX] = {
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.bufsize = BULK_SIZE,
- .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
+ .flags = {.ext_buffer = 1,.proxy_buffer = 1,.short_xfer_ok = 1,},
.callback = &bbb_data_read_callback,
.timeout = 4 * USB_MS_HZ, /* 4 seconds */
},
@@ -207,7 +214,7 @@ static const struct usb_config bbb_config[ST_MAX] = {
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.bufsize = BULK_SIZE,
- .flags = {.proxy_buffer = 1,},
+ .flags = {.ext_buffer = 1,.proxy_buffer = 1,},
.callback = &bbb_data_write_callback,
.timeout = 4 * USB_MS_HZ, /* 4 seconds */
},
@@ -226,7 +233,7 @@ static const struct usb_config bbb_config[ST_MAX] = {
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.bufsize = sizeof(struct bbb_csw),
- .flags = {.short_xfer_ok = 1,},
+ .flags = {.ext_buffer = 1,.short_xfer_ok = 1,},
.callback = &bbb_status_callback,
.timeout = 1 * USB_MS_HZ, /* 1 second */
},
@@ -414,7 +421,8 @@ static void
bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct bbb_transfer *sc = usbd_xfer_softc(xfer);
- int actlen, sumlen;
+ int actlen;
+ int sumlen;
usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
@@ -423,7 +431,7 @@ bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
/* very simple status check */
- if (actlen < sizeof(sc->csw)) {
+ if (actlen < (int)sizeof(sc->csw)) {
bbb_done(sc, USB_ERR_SHORT_XFER);
} else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) {
bbb_done(sc, 0); /* success */
@@ -458,7 +466,7 @@ bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
-static uint8_t
+static int
bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
void *data_ptr, size_t data_len, void *cmd_ptr, size_t cmd_len,
usb_timeout_t data_timeout)
@@ -471,8 +479,8 @@ bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
sc->data_timeout = (data_timeout + USB_MS_HZ);
sc->actlen = 0;
sc->cmd_len = cmd_len;
- bzero(&sc->cbw.CBWCDB, sizeof(sc->cbw.CBWCDB));
- bcopy(cmd_ptr, &sc->cbw.CBWCDB, cmd_len);
+ memset(&sc->cbw.CBWCDB, 0, sizeof(sc->cbw.CBWCDB));
+ memcpy(&sc->cbw.CBWCDB, cmd_ptr, cmd_len);
DPRINTFN(1, "SCSI cmd = %*D\n", (int)cmd_len, &sc->cbw.CBWCDB, ":");
mtx_lock(&sc->mtx);
@@ -492,6 +500,19 @@ bbb_attach(struct usb_device *udev, uint8_t iface_index)
struct usb_interface_descriptor *id;
struct bbb_transfer *sc;
usb_error_t err;
+ uint8_t do_unlock;
+
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
+
+ /*
+ * Make sure any driver which is hooked up to this interface,
+ * like umass is gone:
+ */
+ usb_detach_device(udev, iface_index, 0);
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
iface = usbd_get_iface(udev, iface_index);
if (iface == NULL)
@@ -552,9 +573,10 @@ int
usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index)
{
struct bbb_transfer *sc;
- usb_error_t err;
- uint8_t timeout, is_cdrom;
+ uint8_t timeout;
+ uint8_t is_cdrom;
uint8_t sid_type;
+ int err;
sc = bbb_attach(udev, iface_index);
if (sc == NULL)
@@ -580,6 +602,142 @@ usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index)
return (is_cdrom);
}
+static uint8_t
+usb_msc_get_max_lun(struct usb_device *udev, uint8_t iface_index)
+{
+ struct usb_device_request req;
+ usb_error_t err;
+ uint8_t buf = 0;
+
+
+ /* The Get Max Lun command is a class-specific request. */
+ req.bmRequestType = UT_READ_CLASS_INTERFACE;
+ req.bRequest = 0xFE; /* GET_MAX_LUN */
+ USETW(req.wValue, 0);
+ req.wIndex[0] = iface_index;
+ req.wIndex[1] = 0;
+ USETW(req.wLength, 1);
+
+ err = usbd_do_request(udev, NULL, &req, &buf);
+ if (err)
+ buf = 0;
+
+ return (buf);
+}
+
+usb_error_t
+usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index)
+{
+ struct bbb_transfer *sc;
+ uint8_t timeout;
+ uint8_t is_no_direct;
+ uint8_t sid_type;
+ int err;
+
+ sc = bbb_attach(udev, iface_index);
+ if (sc == NULL)
+ return (0);
+
+ /*
+ * Some devices need a delay after that the configuration
+ * value is set to function properly:
+ */
+ usb_pause_mtx(NULL, hz);
+
+ if (usb_msc_get_max_lun(udev, iface_index) == 0) {
+ DPRINTF("Device has only got one LUN.\n");
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_GETMAXLUN);
+ }
+
+ is_no_direct = 1;
+ for (timeout = 4; timeout; timeout--) {
+ err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
+ SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
+ USB_MS_HZ);
+
+ if (err == 0 && sc->actlen > 0) {
+ sid_type = sc->buffer[0] & 0x1F;
+ if (sid_type == 0x00)
+ is_no_direct = 0;
+ break;
+ } else if (err != ERR_CSW_FAILED)
+ break; /* non retryable error */
+ usb_pause_mtx(NULL, hz);
+ }
+
+ if (is_no_direct) {
+ DPRINTF("Device is not direct access.\n");
+ goto done;
+ }
+
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
+ USB_MS_HZ);
+
+ if (err != 0) {
+
+ if (err != ERR_CSW_FAILED)
+ goto error;
+ }
+
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_sync_cache, sizeof(scsi_sync_cache),
+ USB_MS_HZ);
+
+ if (err != 0) {
+
+ if (err != ERR_CSW_FAILED)
+ goto error;
+
+ DPRINTF("Device doesn't handle synchronize cache\n");
+
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
+ }
+
+ /* clear sense status of any failed commands on the device */
+
+ err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
+ SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
+ USB_MS_HZ);
+
+ DPRINTF("Inquiry = %d\n", err);
+
+ if (err != 0) {
+
+ if (err != ERR_CSW_FAILED)
+ goto error;
+ }
+
+ err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
+ SCSI_SENSE_LEN, &scsi_request_sense,
+ sizeof(scsi_request_sense), USB_MS_HZ);
+
+ DPRINTF("Request sense = %d\n", err);
+
+ if (err != 0) {
+
+ if (err != ERR_CSW_FAILED)
+ goto error;
+ }
+
+done:
+ bbb_detach(sc);
+ return (0);
+
+error:
+ bbb_detach(sc);
+
+ DPRINTF("Device did not respond, enabling all quirks\n");
+
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_TEST_UNIT_READY);
+
+ /* Need to re-enumerate the device */
+ usbd_req_re_enumerate(udev, NULL);
+
+ return (USB_ERR_STALLED);
+}
+
usb_error_t
usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
{
diff --git a/freebsd/sys/dev/usb/usb_msctest.h b/freebsd/sys/dev/usb/usb_msctest.h
index 807d5f5d..e4a717fe 100644
--- a/freebsd/sys/dev/usb/usb_msctest.h
+++ b/freebsd/sys/dev/usb/usb_msctest.h
@@ -40,5 +40,7 @@ int usb_iface_is_cdrom(struct usb_device *udev,
uint8_t iface_index);
usb_error_t usb_msc_eject(struct usb_device *udev,
uint8_t iface_index, int method);
+usb_error_t usb_msc_auto_quirk(struct usb_device *udev,
+ uint8_t iface_index);
#endif /* _USB_MSCTEST_H_ */
diff --git a/freebsd/sys/dev/usb/usb_parse.c b/freebsd/sys/dev/usb/usb_parse.c
index 6b055db7..f2529d12 100644
--- a/freebsd/sys/dev/usb/usb_parse.c
+++ b/freebsd/sys/dev/usb/usb_parse.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
diff --git a/freebsd/sys/dev/usb/usb_pf.h b/freebsd/sys/dev/usb/usb_pf.h
new file mode 100644
index 00000000..9d51e98c
--- /dev/null
+++ b/freebsd/sys/dev/usb/usb_pf.h
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 1990, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_USB_PF_H
+#define _DEV_USB_PF_H
+
+struct usbpf_pkthdr {
+ uint32_t up_totlen; /* Total length including all headers */
+ uint32_t up_busunit; /* Host controller unit number */
+ uint8_t up_address; /* USB device index */
+ uint8_t up_mode; /* Mode of transfer */
+#define USBPF_MODE_HOST 0
+#define USBPF_MODE_DEVICE 1
+ uint8_t up_type; /* points SUBMIT / DONE */
+ uint8_t up_xfertype; /* Transfer type, see USB2.0 spec. */
+ uint32_t up_flags; /* Transfer flags */
+#define USBPF_FLAG_FORCE_SHORT_XFER (1 << 0)
+#define USBPF_FLAG_SHORT_XFER_OK (1 << 1)
+#define USBPF_FLAG_SHORT_FRAMES_OK (1 << 2)
+#define USBPF_FLAG_PIPE_BOF (1 << 3)
+#define USBPF_FLAG_PROXY_BUFFER (1 << 4)
+#define USBPF_FLAG_EXT_BUFFER (1 << 5)
+#define USBPF_FLAG_MANUAL_STATUS (1 << 6)
+#define USBPF_FLAG_NO_PIPE_OK (1 << 7)
+#define USBPF_FLAG_STALL_PIPE (1 << 8)
+ uint32_t up_status; /* Transfer status */
+#define USBPF_STATUS_OPEN (1 << 0)
+#define USBPF_STATUS_TRANSFERRING (1 << 1)
+#define USBPF_STATUS_DID_DMA_DELAY (1 << 2)
+#define USBPF_STATUS_DID_CLOSE (1 << 3)
+#define USBPF_STATUS_DRAINING (1 << 4)
+#define USBPF_STATUS_STARTED (1 << 5)
+#define USBPF_STATUS_BW_RECLAIMED (1 << 6)
+#define USBPF_STATUS_CONTROL_XFR (1 << 7)
+#define USBPF_STATUS_CONTROL_HDR (1 << 8)
+#define USBPF_STATUS_CONTROL_ACT (1 << 9)
+#define USBPF_STATUS_CONTROL_STALL (1 << 10)
+#define USBPF_STATUS_SHORT_FRAMES_OK (1 << 11)
+#define USBPF_STATUS_SHORT_XFER_OK (1 << 12)
+#define USBPF_STATUS_BDMA_ENABLE (1 << 13)
+#define USBPF_STATUS_BDMA_NO_POST_SYNC (1 << 14)
+#define USBPF_STATUS_BDMA_SETUP (1 << 15)
+#define USBPF_STATUS_ISOCHRONOUS_XFR (1 << 16)
+#define USBPF_STATUS_CURR_DMA_SET (1 << 17)
+#define USBPF_STATUS_CAN_CANCEL_IMMED (1 << 18)
+#define USBPF_STATUS_DOING_CALLBACK (1 << 19)
+ uint32_t up_error; /* USB error, see USB_ERR_XXX */
+ uint32_t up_interval; /* For interrupt and isoc (ms) */
+ uint32_t up_frames; /* Number of following frames */
+ uint32_t up_packet_size; /* Packet size used */
+ uint32_t up_packet_count; /* Packet count used */
+ uint32_t up_endpoint; /* USB endpoint / stream ID */
+ uint8_t up_speed; /* USB speed, see USB_SPEED_XXX */
+ /* sizeof(struct usbpf_pkthdr) == 128 bytes */
+ uint8_t up_reserved[83];
+};
+
+struct usbpf_framehdr {
+ /*
+ * The frame length field excludes length of frame header and
+ * any alignment.
+ */
+ uint32_t length;
+#define USBPF_FRAME_ALIGN(x) (((x) + 3) & ~3)
+ uint32_t flags;
+#define USBPF_FRAMEFLAG_READ (1 << 0)
+#define USBPF_FRAMEFLAG_DATA_FOLLOWS (1 << 1)
+};
+
+#define USBPF_HDR_LEN 128 /* bytes */
+#define USBPF_FRAME_HDR_LEN 8 /* bytes */
+
+extern uint8_t usbpf_pkthdr_size_ok[
+ (sizeof(struct usbpf_pkthdr) == USBPF_HDR_LEN) ? 1 : -1];
+extern uint8_t usbpf_framehdr_size_ok[
+ (sizeof(struct usbpf_framehdr) == USBPF_FRAME_HDR_LEN) ? 1 : -1];
+
+#define USBPF_XFERTAP_SUBMIT 0
+#define USBPF_XFERTAP_DONE 1
+
+#ifdef _KERNEL
+void usbpf_attach(struct usb_bus *);
+void usbpf_detach(struct usb_bus *);
+void usbpf_xfertap(struct usb_xfer *, int);
+#endif
+
+#endif
diff --git a/freebsd/sys/dev/usb/usb_process.c b/freebsd/sys/dev/usb/usb_process.c
index 8cb00473..99e2d306 100644
--- a/freebsd/sys/dev/usb/usb_process.c
+++ b/freebsd/sys/dev/usb/usb_process.c
@@ -36,7 +36,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -70,11 +69,17 @@ static int usb_pcount;
#define USB_THREAD_CREATE(f, s, p, ...) \
kproc_kthread_add((f), (s), &usbproc, (p), RFHIGHPID, \
0, "usb", __VA_ARGS__)
+#if (__FreeBSD_version >= 900000)
+#define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check()
+#else
+#define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check(curthread)
+#endif
#define USB_THREAD_SUSPEND(p) kthread_suspend(p,0)
#define USB_THREAD_EXIT(err) kthread_exit()
#else
#define USB_THREAD_CREATE(f, s, p, ...) \
kthread_create((f), (s), (p), RFHIGHPID, 0, __VA_ARGS__)
+#define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check(curproc)
#define USB_THREAD_SUSPEND(p) kthread_suspend(p,0)
#define USB_THREAD_EXIT(err) kthread_exit(err)
#endif
@@ -83,9 +88,8 @@ static int usb_pcount;
static int usb_proc_debug;
SYSCTL_NODE(_hw_usb, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process");
-SYSCTL_INT(_hw_usb_proc, OID_AUTO, debug, CTLFLAG_RW, &usb_proc_debug, 0,
+SYSCTL_INT(_hw_usb_proc, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &usb_proc_debug, 0,
"Debug level");
-
TUNABLE_INT("hw.usb.proc.debug", &usb_proc_debug);
#endif
@@ -101,6 +105,11 @@ usb_process(void *arg)
struct usb_proc_msg *pm;
struct thread *td;
+ /* in case of attach error, check for suspended */
+#ifndef __rtems__
+ USB_THREAD_SUSPEND_CHECK();
+#endif /* __rtems__ */
+
/* adjust priority */
td = curthread;
#ifndef __rtems__
@@ -365,7 +374,12 @@ usb_proc_is_gone(struct usb_process *up)
if (up->up_gone)
return (1);
- mtx_assert(up->up_mtx, MA_OWNED);
+ /*
+ * Allow calls when up_mtx is NULL, before the USB process
+ * structure is initialised.
+ */
+ if (up->up_mtx != NULL)
+ mtx_assert(up->up_mtx, MA_OWNED);
return (0);
}
@@ -471,7 +485,7 @@ usb_proc_drain(struct usb_process *up)
/*------------------------------------------------------------------------*
* usb_proc_rewakeup
*
- * This function is called to re-wakeup the the given USB
+ * This function is called to re-wakeup the given USB
* process. This usually happens after that the USB system has been in
* polling mode, like during a panic. This function must be called
* having "up->up_mtx" locked.
diff --git a/freebsd/sys/dev/usb/usb_process.h b/freebsd/sys/dev/usb/usb_process.h
index b4159af1..23cf6607 100644
--- a/freebsd/sys/dev/usb/usb_process.h
+++ b/freebsd/sys/dev/usb/usb_process.h
@@ -27,11 +27,13 @@
#ifndef _USB_PROCESS_H_
#define _USB_PROCESS_H_
+#include <sys/interrupt.h>
#include <sys/priority.h>
+#include <sys/runq.h>
/* defines */
-#define USB_PRI_HIGH PI_NET
-#define USB_PRI_MED PI_DISK
+#define USB_PRI_HIGH PI_SWI(SWI_NET)
+#define USB_PRI_MED PI_SWI(SWI_CAMBIO)
#define USB_PROC_WAIT_TIMEOUT 2
#define USB_PROC_WAIT_DRAIN 1
diff --git a/freebsd/sys/dev/usb/usb_request.c b/freebsd/sys/dev/usb/usb_request.c
index 8d17c202..cb3b030c 100644
--- a/freebsd/sys/dev/usb/usb_request.c
+++ b/freebsd/sys/dev/usb/usb_request.c
@@ -36,7 +36,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -70,22 +69,19 @@
#include <dev/usb/usb_bus.h>
#include <sys/ctype.h>
-#ifdef USB_DEBUG
-static int usb_pr_poll_delay = USB_PORT_RESET_DELAY;
-static int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY;
+static int usb_no_cs_fail;
-SYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW,
- &usb_pr_poll_delay, 0, "USB port reset poll delay in ms");
-SYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW,
- &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms");
+SYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RW,
+ &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set");
+#ifdef USB_DEBUG
#ifdef USB_REQ_DEBUG
/* The following structures are used in connection to fault injection. */
struct usb_ctrl_debug {
int bus_index; /* target bus */
int dev_index; /* target address */
int ds_fail; /* fail data stage */
- int ss_fail; /* fail data stage */
+ int ss_fail; /* fail status stage */
int ds_delay; /* data stage delay in ms */
int ss_delay; /* status stage delay in ms */
int bmRequestType_value;
@@ -241,6 +237,10 @@ usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
+tr_transferred:
+ /* reset error counter */
+ udev->clear_stall_errors = 0;
+
if (ep == NULL)
goto tr_setup; /* device was unconfigured */
if (ep->edesc &&
@@ -292,8 +292,30 @@ tr_setup:
goto tr_setup;
default:
- if (xfer->error == USB_ERR_CANCELLED) {
+ if (error == USB_ERR_CANCELLED)
break;
+
+ DPRINTF("Clear stall failed.\n");
+
+ /*
+ * Some VMs like VirtualBox always return failure on
+ * clear-stall which we sometimes should just ignore.
+ */
+ if (usb_no_cs_fail)
+ goto tr_transferred;
+ if (udev->clear_stall_errors == USB_CS_RESET_LIMIT)
+ goto tr_setup;
+
+ if (error == USB_ERR_TIMEOUT) {
+ udev->clear_stall_errors = USB_CS_RESET_LIMIT;
+ DPRINTF("Trying to re-enumerate.\n");
+ usbd_start_re_enumerate(udev);
+ } else {
+ udev->clear_stall_errors++;
+ if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) {
+ DPRINTF("Trying to re-enumerate.\n");
+ usbd_start_re_enumerate(udev);
+ }
}
goto tr_setup;
}
@@ -362,9 +384,8 @@ usbd_get_hr_func(struct usb_device *udev)
* than 30 seconds is treated like a 30 second timeout. This USB stack
* does not allow control requests without a timeout.
*
- * NOTE: This function is thread safe. All calls to
- * "usbd_do_request_flags" will be serialised by the use of an
- * internal "sx_lock".
+ * NOTE: This function is thread safe. All calls to "usbd_do_request_flags"
+ * will be serialized by the use of the USB device enumeration lock.
*
* Returns:
* 0: Success
@@ -388,7 +409,7 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
uint16_t length;
uint16_t temp;
uint16_t acttemp;
- uint8_t enum_locked;
+ uint8_t do_unlock;
if (timeout < 50) {
/* timeout is too small */
@@ -400,8 +421,6 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
}
length = UGETW(req->wLength);
- enum_locked = usbd_enum_is_locked(udev);
-
DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
"wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
udev, req->bmRequestType, req->bRequest,
@@ -432,17 +451,16 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
}
/*
- * We need to allow suspend and resume at this point, else the
- * control transfer will timeout if the device is suspended!
+ * Grab the USB device enumeration SX-lock serialization is
+ * achieved when multiple threads are involved:
*/
- if (enum_locked)
- usbd_sr_unlock(udev);
+ do_unlock = usbd_enum_lock(udev);
/*
- * Grab the default sx-lock so that serialisation
- * is achieved when multiple threads are involved:
+ * We need to allow suspend and resume at this point, else the
+ * control transfer will timeout if the device is suspended!
*/
- sx_xlock(&udev->ctrl_sx);
+ usbd_sr_unlock(udev);
hr_func = usbd_get_hr_func(udev);
@@ -489,7 +507,7 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
}
} else
#endif
- bcopy(desc, data, length);
+ memcpy(data, desc, length);
}
goto done; /* success */
}
@@ -686,10 +704,10 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
USB_XFER_UNLOCK(xfer);
done:
- sx_xunlock(&udev->ctrl_sx);
+ usbd_sr_lock(udev);
- if (enum_locked)
- usbd_sr_lock(udev);
+ if (do_unlock)
+ usbd_enum_unlock(udev);
if ((mtx != NULL) && (mtx != &Giant))
mtx_lock(mtx);
@@ -757,52 +775,52 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
struct usb_port_status ps;
usb_error_t err;
uint16_t n;
+ uint16_t status;
+ uint16_t change;
-#ifdef USB_DEBUG
- uint16_t pr_poll_delay;
- uint16_t pr_recovery_delay;
+ DPRINTF("\n");
-#endif
- err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET);
- if (err) {
+ /* clear any leftover port reset changes first */
+ usbd_req_clear_port_feature(
+ udev, mtx, port, UHF_C_PORT_RESET);
+
+ /* assert port reset on the given port */
+ err = usbd_req_set_port_feature(
+ udev, mtx, port, UHF_PORT_RESET);
+
+ /* check for errors */
+ if (err)
goto done;
- }
#ifdef USB_DEBUG
- /* range check input parameters */
- pr_poll_delay = usb_pr_poll_delay;
- if (pr_poll_delay < 1) {
- pr_poll_delay = 1;
- } else if (pr_poll_delay > 1000) {
- pr_poll_delay = 1000;
- }
- pr_recovery_delay = usb_pr_recovery_delay;
- if (pr_recovery_delay > 1000) {
- pr_recovery_delay = 1000;
- }
#endif
n = 0;
while (1) {
-#ifdef USB_DEBUG
/* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
- n += pr_poll_delay;
-#else
- /* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
- n += USB_PORT_RESET_DELAY;
-#endif
+ usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay));
+ n += usb_port_reset_delay;
err = usbd_req_get_port_status(udev, mtx, &ps, port);
- if (err) {
+ if (err)
goto done;
- }
+
+ status = UGETW(ps.wPortStatus);
+ change = UGETW(ps.wPortChange);
+
/* if the device disappeared, just give up */
- if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
+ if (!(status & UPS_CURRENT_CONNECT_STATUS))
goto done;
- }
+
/* check if reset is complete */
- if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
+ if (change & UPS_C_PORT_RESET)
break;
- }
+
+ /*
+ * Some Virtual Machines like VirtualBox 4.x fail to
+ * generate a port reset change event. Check if reset
+ * is no longer asserted.
+ */
+ if (!(status & UPS_RESET))
+ break;
+
/* check for timeout */
if (n > 1000) {
n = 0;
@@ -813,21 +831,16 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
/* clear port reset first */
err = usbd_req_clear_port_feature(
udev, mtx, port, UHF_C_PORT_RESET);
- if (err) {
+ if (err)
goto done;
- }
+
/* check for timeout */
if (n == 0) {
err = USB_ERR_TIMEOUT;
goto done;
}
-#ifdef USB_DEBUG
- /* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
-#else
/* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
-#endif
+ usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery));
done:
DPRINTFN(2, "port %d reset returning error=%s\n",
@@ -849,57 +862,64 @@ done:
* disabled.
*------------------------------------------------------------------------*/
usb_error_t
-usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
+usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx,
+ uint8_t port)
{
struct usb_port_status ps;
usb_error_t err;
uint16_t n;
+ uint16_t status;
+ uint16_t change;
-#ifdef USB_DEBUG
- uint16_t pr_poll_delay;
- uint16_t pr_recovery_delay;
+ DPRINTF("\n");
-#endif
- err = usbd_req_set_port_feature(udev, mtx, port, UHF_BH_PORT_RESET);
- if (err) {
+ err = usbd_req_get_port_status(udev, mtx, &ps, port);
+ if (err)
goto done;
+
+ status = UGETW(ps.wPortStatus);
+
+ switch (UPS_PORT_LINK_STATE_GET(status)) {
+ case UPS_PORT_LS_U3:
+ case UPS_PORT_LS_COMP_MODE:
+ case UPS_PORT_LS_LOOPBACK:
+ case UPS_PORT_LS_SS_INA:
+ break;
+ default:
+ DPRINTF("Wrong state for warm reset\n");
+ return (0);
}
-#ifdef USB_DEBUG
- /* range check input parameters */
- pr_poll_delay = usb_pr_poll_delay;
- if (pr_poll_delay < 1) {
- pr_poll_delay = 1;
- } else if (pr_poll_delay > 1000) {
- pr_poll_delay = 1000;
- }
- pr_recovery_delay = usb_pr_recovery_delay;
- if (pr_recovery_delay > 1000) {
- pr_recovery_delay = 1000;
- }
-#endif
+
+ /* clear any leftover warm port reset changes first */
+ usbd_req_clear_port_feature(udev, mtx,
+ port, UHF_C_BH_PORT_RESET);
+
+ /* set warm port reset */
+ err = usbd_req_set_port_feature(udev, mtx,
+ port, UHF_BH_PORT_RESET);
+ if (err)
+ goto done;
+
n = 0;
while (1) {
-#ifdef USB_DEBUG
- /* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
- n += pr_poll_delay;
-#else
/* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
- n += USB_PORT_RESET_DELAY;
-#endif
+ usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay));
+ n += usb_port_reset_delay;
err = usbd_req_get_port_status(udev, mtx, &ps, port);
- if (err) {
+ if (err)
goto done;
- }
+
+ status = UGETW(ps.wPortStatus);
+ change = UGETW(ps.wPortChange);
+
/* if the device disappeared, just give up */
- if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
+ if (!(status & UPS_CURRENT_CONNECT_STATUS))
goto done;
- }
+
/* check if reset is complete */
- if (UGETW(ps.wPortChange) & UPS_C_BH_PORT_RESET) {
+ if (change & UPS_C_BH_PORT_RESET)
break;
- }
+
/* check for timeout */
if (n > 1000) {
n = 0;
@@ -910,21 +930,16 @@ usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
/* clear port reset first */
err = usbd_req_clear_port_feature(
udev, mtx, port, UHF_C_BH_PORT_RESET);
- if (err) {
+ if (err)
goto done;
- }
+
/* check for timeout */
if (n == 0) {
err = USB_ERR_TIMEOUT;
goto done;
}
-#ifdef USB_DEBUG
- /* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
-#else
/* wait for the device to recover from reset */
- usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
-#endif
+ usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery));
done:
DPRINTFN(2, "port %d warm reset returning error=%s\n",
@@ -1119,14 +1134,21 @@ usbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf,
}
/*
- * Filter by default - we don't allow greater and less than
- * signs because they might confuse the dmesg printouts!
+ * Filter by default - We only allow alphanumerical
+ * and a few more to avoid any problems with scripts
+ * and daemons.
*/
- if ((*s == '<') || (*s == '>') || (!isprint(*s))) {
- /* silently skip bad character */
- continue;
+ if (isalpha(*s) ||
+ isdigit(*s) ||
+ *s == '-' ||
+ *s == '+' ||
+ *s == ' ' ||
+ *s == '.' ||
+ *s == ',') {
+ /* allowed */
+ s++;
}
- s++;
+ /* silently skip bad character */
}
*s = 0; /* zero terminate resulting string */
return (USB_ERR_NORMAL_COMPLETION);
@@ -1222,7 +1244,7 @@ usbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx,
goto done;
}
/* Extra sanity checking */
- if (UGETW(d->wTotalLength) < sizeof(*d)) {
+ if (UGETW(d->wTotalLength) < (uint16_t)sizeof(*d)) {
err = USB_ERR_INVAL;
}
done:
@@ -1476,7 +1498,7 @@ usbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr)
done:
/* allow device time to set new address */
usb_pause_mtx(mtx,
- USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE));
+ USB_MS_TO_TICKS(usb_set_address_settle));
return (err);
}
@@ -1725,7 +1747,7 @@ usbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data,
struct usb_interface *iface = usbd_get_iface(udev, iface_index);
struct usb_device_request req;
- if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) {
+ if ((iface == NULL) || (iface->idesc == NULL)) {
return (USB_ERR_INVAL);
}
DPRINTFN(5, "len=%d\n", len);
@@ -1932,6 +1954,27 @@ usbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx)
return (USB_ERR_INVAL);
}
retry:
+ /*
+ * Try to reset the High Speed parent HUB of a LOW- or FULL-
+ * speed device, if any.
+ */
+ if (udev->parent_hs_hub != NULL &&
+ udev->speed != USB_SPEED_HIGH) {
+ DPRINTF("Trying to reset parent High Speed TT.\n");
+ err = usbd_req_reset_tt(udev->parent_hs_hub, NULL,
+ udev->hs_port_no);
+ if (err) {
+ DPRINTF("Resetting parent High "
+ "Speed TT failed (%s).\n",
+ usbd_errstr(err));
+ }
+ }
+
+ /* Try to warm reset first */
+ if (parent_hub->speed == USB_SPEED_SUPER)
+ usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no);
+
+ /* Try to reset the parent HUB port. */
err = usbd_req_reset_port(parent_hub, mtx, udev->port_no);
if (err) {
DPRINTFN(0, "addr=%d, port reset failed, %s\n",
@@ -2029,3 +2072,89 @@ usbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx,
USETW(req.wLength, 0);
return (usbd_do_request(udev, mtx, &req, 0));
}
+
+/*------------------------------------------------------------------------*
+ * usbd_req_reset_tt
+ *
+ * Returns:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+usb_error_t
+usbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
+ uint8_t port)
+{
+ struct usb_device_request req;
+
+ /* For single TT HUBs the port should be 1 */
+
+ if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
+ udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
+ port = 1;
+
+ req.bmRequestType = UT_WRITE_CLASS_OTHER;
+ req.bRequest = UR_RESET_TT;
+ USETW(req.wValue, 0);
+ req.wIndex[0] = port;
+ req.wIndex[1] = 0;
+ USETW(req.wLength, 0);
+ return (usbd_do_request(udev, mtx, &req, 0));
+}
+
+/*------------------------------------------------------------------------*
+ * usbd_req_clear_tt_buffer
+ *
+ * For single TT HUBs the port should be 1.
+ *
+ * Returns:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+usb_error_t
+usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
+ uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint)
+{
+ struct usb_device_request req;
+ uint16_t wValue;
+
+ /* For single TT HUBs the port should be 1 */
+
+ if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
+ udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
+ port = 1;
+
+ wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) |
+ ((endpoint & 0x80) << 8) | ((type & 3) << 12);
+
+ req.bmRequestType = UT_WRITE_CLASS_OTHER;
+ req.bRequest = UR_CLEAR_TT_BUFFER;
+ USETW(req.wValue, wValue);
+ req.wIndex[0] = port;
+ req.wIndex[1] = 0;
+ USETW(req.wLength, 0);
+ return (usbd_do_request(udev, mtx, &req, 0));
+}
+
+/*------------------------------------------------------------------------*
+ * usbd_req_set_port_link_state
+ *
+ * USB 3.0 specific request
+ *
+ * Returns:
+ * 0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+usb_error_t
+usbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx,
+ uint8_t port, uint8_t link_state)
+{
+ struct usb_device_request req;
+
+ req.bmRequestType = UT_WRITE_CLASS_OTHER;
+ req.bRequest = UR_SET_FEATURE;
+ USETW(req.wValue, UHF_PORT_LINK_STATE);
+ req.wIndex[0] = port;
+ req.wIndex[1] = link_state;
+ USETW(req.wLength, 0);
+ return (usbd_do_request(udev, mtx, &req, 0));
+}
diff --git a/freebsd/sys/dev/usb/usb_request.h b/freebsd/sys/dev/usb/usb_request.h
index 12f373d5..74823af2 100644
--- a/freebsd/sys/dev/usb/usb_request.h
+++ b/freebsd/sys/dev/usb/usb_request.h
@@ -85,5 +85,11 @@ usb_error_t usbd_req_set_hub_u2_timeout(struct usb_device *udev,
struct mtx *mtx, uint8_t port, uint8_t timeout);
usb_error_t usbd_req_set_hub_depth(struct usb_device *udev,
struct mtx *mtx, uint16_t depth);
+usb_error_t usbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
+ uint8_t port);
+usb_error_t usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
+ uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint);
+usb_error_t usbd_req_set_port_link_state(struct usb_device *udev,
+ struct mtx *mtx, uint8_t port, uint8_t link_state);
#endif /* _USB_REQUEST_H_ */
diff --git a/freebsd/sys/dev/usb/usb_transfer.c b/freebsd/sys/dev/usb/usb_transfer.c
index 17a492e5..a8b0b0ac 100644
--- a/freebsd/sys/dev/usb/usb_transfer.c
+++ b/freebsd/sys/dev/usb/usb_transfer.c
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- */
+ */
#include <sys/stdint.h>
#include <sys/stddef.h>
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -45,6 +44,7 @@
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>
+#include <sys/proc.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -62,6 +62,7 @@
#include <dev/usb/usb_controller.h>
#include <dev/usb/usb_bus.h>
+#include <dev/usb/usb_pf.h>
#ifdef __rtems__
#include <machine/rtems-bsd-cache.h>
#endif /* __rtems__ */
@@ -228,12 +229,12 @@ usbd_transfer_setup_sub_malloc(struct usb_setup_params *parm,
* Try multi-allocation chunks to reduce the number of DMA
* allocations, hence DMA allocations are slow.
*/
- if (size >= PAGE_SIZE) {
+ if (size >= USB_PAGE_SIZE) {
n_dma_pc = count;
n_obj = 1;
} else {
/* compute number of objects per page */
- n_obj = (PAGE_SIZE / size);
+ n_obj = (USB_PAGE_SIZE / size);
/*
* Compute number of DMA chunks, rounded up
* to nearest one:
@@ -483,6 +484,8 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm)
xfer->fps_shift--;
if (xfer->fps_shift > 3)
xfer->fps_shift = 3;
+ if (xfer->flags.pre_scale_frames != 0)
+ xfer->nframes <<= (3 - xfer->fps_shift);
break;
}
@@ -674,9 +677,13 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm)
}
xfer->max_data_length -= REQ_SIZE;
}
- /* setup "frlengths" */
+ /*
+ * Setup "frlengths" and shadow "frlengths" for keeping the
+ * initial frame lengths when a USB transfer is complete. This
+ * information is useful when computing isochronous offsets.
+ */
xfer->frlengths = parm->xfer_length_ptr;
- parm->xfer_length_ptr += n_frlengths;
+ parm->xfer_length_ptr += 2 * n_frlengths;
/* setup "frbuffers" */
xfer->frbuffers = parm->xfer_page_cache_ptr;
@@ -833,20 +840,17 @@ usbd_transfer_setup(struct usb_device *udev,
const struct usb_config *setup_start, uint16_t n_setup,
void *priv_sc, struct mtx *xfer_mtx)
{
- struct usb_xfer dummy;
- struct usb_setup_params parm;
const struct usb_config *setup_end = setup_start + n_setup;
const struct usb_config *setup;
+ struct usb_setup_params *parm;
struct usb_endpoint *ep;
struct usb_xfer_root *info;
struct usb_xfer *xfer;
void *buf = NULL;
+ usb_error_t error = 0;
uint16_t n;
uint16_t refcount;
-
- parm.err = 0;
- refcount = 0;
- info = NULL;
+ uint8_t do_unlock;
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"usbd_transfer_setup can sleep!");
@@ -865,31 +869,40 @@ usbd_transfer_setup(struct usb_device *udev,
DPRINTFN(6, "using global lock\n");
xfer_mtx = &Giant;
}
- /* sanity checks */
+
+ /* more sanity checks */
+
for (setup = setup_start, n = 0;
setup != setup_end; setup++, n++) {
if (setup->bufsize == (usb_frlength_t)-1) {
- parm.err = USB_ERR_BAD_BUFSIZE;
+ error = USB_ERR_BAD_BUFSIZE;
DPRINTF("invalid bufsize\n");
}
if (setup->callback == NULL) {
- parm.err = USB_ERR_NO_CALLBACK;
+ error = USB_ERR_NO_CALLBACK;
DPRINTF("no callback\n");
}
ppxfer[n] = NULL;
}
- if (parm.err) {
- goto done;
- }
- bzero(&parm, sizeof(parm));
+ if (error)
+ return (error);
+
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
+
+ refcount = 0;
+ info = NULL;
- parm.udev = udev;
- parm.speed = usbd_get_speed(udev);
- parm.hc_max_packet_count = 1;
+ parm = &udev->scratch.xfer_setup[0].parm;
+ memset(parm, 0, sizeof(*parm));
- if (parm.speed >= USB_SPEED_MAX) {
- parm.err = USB_ERR_INVAL;
+ parm->udev = udev;
+ parm->speed = usbd_get_speed(udev);
+ parm->hc_max_packet_count = 1;
+
+ if (parm->speed >= USB_SPEED_MAX) {
+ parm->err = USB_ERR_INVAL;
goto done;
}
/* setup all transfers */
@@ -904,22 +917,22 @@ usbd_transfer_setup(struct usb_device *udev,
info = USB_ADD_BYTES(buf, 0);
info->memory_base = buf;
- info->memory_size = parm.size[0];
+ info->memory_size = parm->size[0];
#if USB_HAVE_BUSDMA
- info->dma_page_cache_start = USB_ADD_BYTES(buf, parm.size[4]);
- info->dma_page_cache_end = USB_ADD_BYTES(buf, parm.size[5]);
+ info->dma_page_cache_start = USB_ADD_BYTES(buf, parm->size[4]);
+ info->dma_page_cache_end = USB_ADD_BYTES(buf, parm->size[5]);
#endif
- info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm.size[5]);
- info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm.size[2]);
+ info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm->size[5]);
+ info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm->size[2]);
cv_init(&info->cv_drain, "WDRAIN");
info->xfer_mtx = xfer_mtx;
#if USB_HAVE_BUSDMA
usb_dma_tag_setup(&info->dma_parent_tag,
- parm.dma_tag_p, udev->bus->dma_parent_tag[0].tag,
- xfer_mtx, &usb_bdma_done_event, 32, parm.dma_tag_max);
+ parm->dma_tag_p, udev->bus->dma_parent_tag[0].tag,
+ xfer_mtx, &usb_bdma_done_event, 32, parm->dma_tag_max);
#endif
info->bus = udev->bus;
@@ -954,9 +967,9 @@ usbd_transfer_setup(struct usb_device *udev,
}
/* reset sizes */
- parm.size[0] = 0;
- parm.buf = buf;
- parm.size[0] += sizeof(info[0]);
+ parm->size[0] = 0;
+ parm->buf = buf;
+ parm->size[0] += sizeof(info[0]);
for (setup = setup_start, n = 0;
setup != setup_end; setup++, n++) {
@@ -975,22 +988,22 @@ usbd_transfer_setup(struct usb_device *udev,
if ((setup->usb_mode != USB_MODE_DUAL) &&
(setup->usb_mode != udev->flags.usb_mode))
continue;
- parm.err = USB_ERR_NO_PIPE;
+ parm->err = USB_ERR_NO_PIPE;
goto done;
}
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store current setup pointer */
- parm.curr_setup = setup;
+ parm->curr_setup = setup;
if (buf) {
/*
* Common initialization of the
* "usb_xfer" structure.
*/
- xfer = USB_ADD_BYTES(buf, parm.size[0]);
+ xfer = USB_ADD_BYTES(buf, parm->size[0]);
xfer->address = udev->address;
xfer->priv_sc = priv_sc;
xfer->xroot = info;
@@ -1005,26 +1018,26 @@ usbd_transfer_setup(struct usb_device *udev,
* before we have allocated any
* memory:
*/
- xfer = &dummy;
- bzero(&dummy, sizeof(dummy));
+ xfer = &udev->scratch.xfer_setup[0].dummy;
+ memset(xfer, 0, sizeof(*xfer));
refcount++;
}
/* set transfer endpoint pointer */
xfer->endpoint = ep;
- parm.size[0] += sizeof(xfer[0]);
- parm.methods = xfer->endpoint->methods;
- parm.curr_xfer = xfer;
+ parm->size[0] += sizeof(xfer[0]);
+ parm->methods = xfer->endpoint->methods;
+ parm->curr_xfer = xfer;
/*
* Call the Host or Device controller transfer
* setup routine:
*/
- (udev->bus->methods->xfer_setup) (&parm);
+ (udev->bus->methods->xfer_setup) (parm);
/* check for error */
- if (parm.err)
+ if (parm->err)
goto done;
if (buf) {
@@ -1039,7 +1052,7 @@ usbd_transfer_setup(struct usb_device *udev,
*/
USB_BUS_LOCK(info->bus);
if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX)
- parm.err = USB_ERR_INVAL;
+ parm->err = USB_ERR_INVAL;
xfer->endpoint->refcount_alloc++;
@@ -1062,22 +1075,22 @@ usbd_transfer_setup(struct usb_device *udev,
}
/* check for error */
- if (parm.err)
+ if (parm->err)
goto done;
}
- if (buf || parm.err) {
+ if (buf != NULL || parm->err != 0)
goto done;
- }
- if (refcount == 0) {
- /* no transfers - nothing to do ! */
+
+ /* if no transfers, nothing to do */
+ if (refcount == 0)
goto done;
- }
+
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
- parm.size[1] = parm.size[0];
+ parm->size[1] = parm->size[0];
/*
* The number of DMA tags required depends on
@@ -1085,72 +1098,72 @@ usbd_transfer_setup(struct usb_device *udev,
* for maximum number of DMA tags per endpoint
* is two.
*/
- parm.dma_tag_max += 2 * MIN(n_setup, USB_EP_MAX);
+ parm->dma_tag_max += 2 * MIN(n_setup, USB_EP_MAX);
/*
* DMA tags for QH, TD, Data and more.
*/
- parm.dma_tag_max += 8;
+ parm->dma_tag_max += 8;
- parm.dma_tag_p += parm.dma_tag_max;
+ parm->dma_tag_p += parm->dma_tag_max;
- parm.size[0] += ((uint8_t *)parm.dma_tag_p) -
+ parm->size[0] += ((uint8_t *)parm->dma_tag_p) -
((uint8_t *)0);
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
- parm.size[3] = parm.size[0];
+ parm->size[3] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.dma_page_ptr) -
+ parm->size[0] += ((uint8_t *)parm->dma_page_ptr) -
((uint8_t *)0);
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
- parm.size[4] = parm.size[0];
+ parm->size[4] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.dma_page_cache_ptr) -
+ parm->size[0] += ((uint8_t *)parm->dma_page_cache_ptr) -
((uint8_t *)0);
/* store end offset temporarily */
- parm.size[5] = parm.size[0];
+ parm->size[5] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.xfer_page_cache_ptr) -
+ parm->size[0] += ((uint8_t *)parm->xfer_page_cache_ptr) -
((uint8_t *)0);
/* store end offset temporarily */
- parm.size[2] = parm.size[0];
+ parm->size[2] = parm->size[0];
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
- parm.size[6] = parm.size[0];
+ parm->size[6] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.xfer_length_ptr) -
+ parm->size[0] += ((uint8_t *)parm->xfer_length_ptr) -
((uint8_t *)0);
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* allocate zeroed memory */
- buf = malloc(parm.size[0], M_USB, M_WAITOK | M_ZERO);
+ buf = malloc(parm->size[0], M_USB, M_WAITOK | M_ZERO);
if (buf == NULL) {
- parm.err = USB_ERR_NOMEM;
+ parm->err = USB_ERR_NOMEM;
DPRINTFN(0, "cannot allocate memory block for "
"configuration (%d bytes)\n",
- parm.size[0]);
+ parm->size[0]);
goto done;
}
- parm.dma_tag_p = USB_ADD_BYTES(buf, parm.size[1]);
- parm.dma_page_ptr = USB_ADD_BYTES(buf, parm.size[3]);
- parm.dma_page_cache_ptr = USB_ADD_BYTES(buf, parm.size[4]);
- parm.xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm.size[5]);
- parm.xfer_length_ptr = USB_ADD_BYTES(buf, parm.size[6]);
+ parm->dma_tag_p = USB_ADD_BYTES(buf, parm->size[1]);
+ parm->dma_page_ptr = USB_ADD_BYTES(buf, parm->size[3]);
+ parm->dma_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[4]);
+ parm->xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[5]);
+ parm->xfer_length_ptr = USB_ADD_BYTES(buf, parm->size[6]);
}
done:
@@ -1166,10 +1179,17 @@ done:
usbd_transfer_unsetup_sub(info, 0);
}
}
- if (parm.err) {
+
+ /* check if any errors happened */
+ if (parm->err)
usbd_transfer_unsetup(ppxfer, n_setup);
- }
- return (parm.err);
+
+ error = parm->err;
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
+ return (error);
}
/*------------------------------------------------------------------------*
@@ -1178,7 +1198,9 @@ done:
static void
usbd_transfer_unsetup_sub(struct usb_xfer_root *info, uint8_t needs_delay)
{
+#if USB_HAVE_BUSDMA
struct usb_page_cache *pc;
+#endif
USB_BUS_LOCK_ASSERT(info->bus, MA_OWNED);
@@ -1605,9 +1627,12 @@ usbd_transfer_submit(struct usb_xfer *xfer)
USB_BUS_UNLOCK(bus);
return;
}
- /* compute total transfer length */
+ /* compute some variables */
for (x = 0; x != xfer->nframes; x++) {
+ /* make a copy of the frlenghts[] */
+ xfer->frlengths[x + xfer->max_frame_count] = xfer->frlengths[x];
+ /* compute total transfer length */
xfer->sumlen += xfer->frlengths[x];
if (xfer->sumlen < xfer->frlengths[x]) {
/* length wrapped around */
@@ -1699,11 +1724,12 @@ usbd_pipe_enter(struct usb_xfer *xfer)
DPRINTF("enter\n");
+ /* the transfer can now be cancelled */
+ xfer->flags_int.can_cancel_immed = 1;
+
/* enter the transfer */
(ep->methods->enter) (xfer);
- xfer->flags_int.can_cancel_immed = 1;
-
/* check for transfer error */
if (xfer->error) {
/* some error has happened */
@@ -1940,6 +1966,17 @@ usbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex)
return (&xfer->frbuffers[frindex]);
}
+void *
+usbd_xfer_get_frame_buffer(struct usb_xfer *xfer, usb_frcount_t frindex)
+{
+ struct usb_page_search page_info;
+
+ KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
+
+ usbd_get_page(&xfer->frbuffers[frindex], 0, &page_info);
+ return (page_info.buffer);
+}
+
/*------------------------------------------------------------------------*
* usbd_xfer_get_fps_shift
*
@@ -1996,6 +2033,22 @@ usbd_xfer_frame_data(struct usb_xfer *xfer, usb_frcount_t frindex,
*len = xfer->frlengths[frindex];
}
+/*------------------------------------------------------------------------*
+ * usbd_xfer_old_frame_length
+ *
+ * This function returns the framelength of the given frame at the
+ * time the transfer was submitted. This function can be used to
+ * compute the starting data pointer of the next isochronous frame
+ * when an isochronous transfer has completed.
+ *------------------------------------------------------------------------*/
+usb_frlength_t
+usbd_xfer_old_frame_length(struct usb_xfer *xfer, usb_frcount_t frindex)
+{
+ KASSERT(frindex < xfer->max_frame_count, ("frame index overflow"));
+
+ return (xfer->frlengths[frindex + xfer->max_frame_count]);
+}
+
void
usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes,
int *nframes)
@@ -2226,6 +2279,10 @@ usbd_callback_wrapper(struct usb_xfer_queue *pq)
}
}
+#if USB_HAVE_PF
+ if (xfer->usb_state != USB_ST_SETUP)
+ usbpf_xfertap(xfer, USBPF_XFERTAP_DONE);
+#endif
/* call processing routine */
(xfer->callback) (xfer, xfer->error);
@@ -2413,12 +2470,18 @@ usbd_transfer_start_cb(void *arg)
DPRINTF("start\n");
- /* start the transfer */
- (ep->methods->start) (xfer);
+#if USB_HAVE_PF
+ usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT);
+#endif
+ /* the transfer can now be cancelled */
xfer->flags_int.can_cancel_immed = 1;
- /* check for error */
+ /* start USB transfer, if no error */
+ if (xfer->error == 0)
+ (ep->methods->start) (xfer);
+
+ /* check for transfer error */
if (xfer->error) {
/* some error has happened */
usbd_transfer_done(xfer, 0);
@@ -2590,12 +2653,17 @@ usbd_pipe_start(struct usb_xfer_queue *pq)
}
DPRINTF("start\n");
- /* start USB transfer */
- (ep->methods->start) (xfer);
-
+#if USB_HAVE_PF
+ usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT);
+#endif
+ /* the transfer can now be cancelled */
xfer->flags_int.can_cancel_immed = 1;
- /* check for error */
+ /* start USB transfer, if no error */
+ if (xfer->error == 0)
+ (ep->methods->start) (xfer);
+
+ /* check for transfer error */
if (xfer->error) {
/* some error has happened */
usbd_transfer_done(xfer, 0);
@@ -2690,7 +2758,8 @@ usbd_callback_wrapper_sub(struct usb_xfer *xfer)
(bus->methods->start_dma_delay) (xfer);
} else {
usbd_transfer_timeout_ms(xfer,
- (void *)&usb_dma_delay_done_cb, temp);
+ (void (*)(void *))&usb_dma_delay_done_cb,
+ temp);
}
USB_BUS_UNLOCK(bus);
return (1); /* wait for new callback */
@@ -2921,6 +2990,11 @@ repeat:
usbd_transfer_unsetup(udev->ctrl_xfer, USB_CTRL_XFER_MAX);
/*
+ * Reset clear stall error counter.
+ */
+ udev->clear_stall_errors = 0;
+
+ /*
* Try to setup a new USB transfer for the
* default control endpoint:
*/
diff --git a/freebsd/sys/dev/usb/usb_util.c b/freebsd/sys/dev/usb/usb_util.c
index 14c0476a..aeafa8a5 100644
--- a/freebsd/sys/dev/usb/usb_util.c
+++ b/freebsd/sys/dev/usb/usb_util.c
@@ -34,7 +34,6 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/linker_set.h>
#include <sys/module.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
@@ -99,6 +98,7 @@ device_set_usb_desc(device_t dev)
struct usb_interface *iface;
char *temp_p;
usb_error_t err;
+ uint8_t do_unlock;
if (dev == NULL) {
/* should not happen */
@@ -120,19 +120,26 @@ device_set_usb_desc(device_t dev)
err = 0;
}
- temp_p = (char *)udev->bus->scratch[0].data;
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
- if (!err) {
+ temp_p = (char *)udev->scratch.data;
+
+ if (err == 0) {
/* try to get the interface string ! */
- err = usbd_req_get_string_any
- (udev, NULL, temp_p,
- sizeof(udev->bus->scratch), iface->idesc->iInterface);
+ err = usbd_req_get_string_any(udev, NULL, temp_p,
+ sizeof(udev->scratch.data),
+ iface->idesc->iInterface);
}
- if (err) {
+ if (err != 0) {
/* use default description */
usb_devinfo(udev, temp_p,
- sizeof(udev->bus->scratch));
+ sizeof(udev->scratch.data));
}
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
device_set_desc_copy(dev, temp_p);
device_printf(dev, "<%s> on %s\n", temp_p,
device_get_nameunit(udev->bus->bdev));
diff --git a/freebsd/sys/dev/usb/usbdi.h b/freebsd/sys/dev/usb/usbdi.h
index 1c2d412b..245777f0 100644
--- a/freebsd/sys/dev/usb/usbdi.h
+++ b/freebsd/sys/dev/usb/usbdi.h
@@ -37,6 +37,7 @@ struct usb_page_search;
struct usb_process;
struct usb_proc_msg;
struct usb_mbuf;
+struct usb_fs_privdata;
struct mbuf;
typedef enum { /* keep in sync with usb_errstr_table */
@@ -171,6 +172,7 @@ struct usb_interface {
struct usb_host_interface *cur_altsetting;
struct usb_device *linux_udev;
void *bsd_priv_sc; /* device specific information */
+ char *pnpinfo; /* additional PnP-info for this interface */
uint8_t num_altsetting; /* number of alternate settings */
uint8_t bsd_iface_index;
};
@@ -194,6 +196,16 @@ struct usb_xfer_flags {
uint8_t stall_pipe:1; /* set if the endpoint belonging to
* this USB transfer should be stalled
* before starting this transfer! */
+ uint8_t pre_scale_frames:1; /* "usb_config->frames" is
+ * assumed to give the
+ * buffering time in
+ * milliseconds and is
+ * converted into the nearest
+ * number of frames when the
+ * USB transfer is setup. This
+ * option only has effect for
+ * ISOCHRONOUS transfers.
+ */
};
/*
@@ -217,6 +229,27 @@ struct usb_config {
};
/*
+ * Use these macro when defining USB device ID arrays if you want to
+ * have your driver module automatically loaded in host, device or
+ * both modes respectivly:
+ */
+#ifndef __rtems__
+#define STRUCT_USB_HOST_ID \
+ struct usb_device_id __section("usb_host_id")
+#define STRUCT_USB_DEVICE_ID \
+ struct usb_device_id __section("usb_device_id")
+#define STRUCT_USB_DUAL_ID \
+ struct usb_device_id __section("usb_dual_id")
+#else /* __rtems__ */
+#define STRUCT_USB_HOST_ID \
+ struct usb_device_id
+#define STRUCT_USB_DEVICE_ID \
+ struct usb_device_id
+#define STRUCT_USB_DUAL_ID \
+ struct usb_device_id
+#endif /* __rtems__ */
+
+/*
* The following structure is used when looking up an USB driver for
* an USB device. It is inspired by the Linux structure called
* "usb_device_id".
@@ -247,12 +280,15 @@ struct usb_device_id {
uint8_t match_flag_product:1;
uint8_t match_flag_dev_lo:1;
uint8_t match_flag_dev_hi:1;
+
uint8_t match_flag_dev_class:1;
uint8_t match_flag_dev_subclass:1;
uint8_t match_flag_dev_protocol:1;
uint8_t match_flag_int_class:1;
+
uint8_t match_flag_int_subclass:1;
uint8_t match_flag_int_protocol:1;
+ uint8_t match_flag_unused:6;
#if USB_HAVE_COMPAT_LINUX
/* which fields to match against */
@@ -268,7 +304,10 @@ struct usb_device_id {
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#endif
-};
+} __aligned(32);
+
+/* check that the size of the structure above is correct */
+extern char usb_device_id_assert[(sizeof(struct usb_device_id) == 32) ? 1 : -1];
#define USB_VENDOR(vend) \
.match_flag_vendor = 1, .idVendor = (vend)
@@ -346,7 +385,6 @@ struct usb_attach_arg {
struct usb_interface *iface; /* current interface */
enum usb_hc_mode usb_mode; /* host or device mode */
uint8_t port;
- uint8_t use_generic; /* hint for generic drivers */
uint8_t dev_state;
#define UAA_DEV_READY 0
#define UAA_DEV_DISABLED 1
@@ -421,7 +459,7 @@ struct usb_fifo_methods {
struct usb_fifo_sc {
struct usb_fifo *fp[2];
- struct cdev* dev;
+ struct usb_fs_privdata *dev;
};
const char *usbd_errstr(usb_error_t error);
@@ -444,6 +482,10 @@ enum usb_hc_mode usbd_get_mode(struct usb_device *udev);
enum usb_dev_speed usbd_get_speed(struct usb_device *udev);
void device_set_usb_desc(device_t dev);
void usb_pause_mtx(struct mtx *mtx, int _ticks);
+usb_error_t usbd_set_pnpinfo(struct usb_device *udev,
+ uint8_t iface_index, const char *pnpinfo);
+usb_error_t usbd_add_dynamic_quirk(struct usb_device *udev,
+ uint16_t quirk);
const struct usb_device_id *usbd_lookup_id_by_info(
const struct usb_device_id *id, usb_size_t sizeof_id,
@@ -483,10 +525,13 @@ void usbd_set_power_mode(struct usb_device *udev, uint8_t power_mode);
uint8_t usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode);
uint8_t usbd_device_attached(struct usb_device *udev);
+usb_frlength_t
+ usbd_xfer_old_frame_length(struct usb_xfer *xfer, usb_frcount_t frindex);
void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen,
int *aframes, int *nframes);
struct usb_page_cache *usbd_xfer_get_frame(struct usb_xfer *xfer,
usb_frcount_t frindex);
+void *usbd_xfer_get_frame_buffer(struct usb_xfer *, usb_frcount_t);
void *usbd_xfer_softc(struct usb_xfer *xfer);
void *usbd_xfer_get_priv(struct usb_xfer *xfer);
void usbd_xfer_set_priv(struct usb_xfer *xfer, void *);
@@ -528,10 +573,11 @@ void usbd_m_copy_in(struct usb_page_cache *cache, usb_frlength_t dst_offset,
struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len);
void usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
usb_frlength_t len);
+void usbd_start_re_enumerate(struct usb_device *udev);
int usb_fifo_attach(struct usb_device *udev, void *priv_sc,
struct mtx *priv_mtx, struct usb_fifo_methods *pm,
- struct usb_fifo_sc *f_sc, uint16_t unit, uint16_t subunit,
+ struct usb_fifo_sc *f_sc, uint16_t unit, int16_t subunit,
uint8_t iface_index, uid_t uid, gid_t gid, int mode);
void usb_fifo_detach(struct usb_fifo_sc *f_sc);
int usb_fifo_alloc_buffer(struct usb_fifo *f, uint32_t bufsize,
diff --git a/freebsd/sys/dev/usb/usbhid.h b/freebsd/sys/dev/usb/usbhid.h
index c07454f7..f40232aa 100644
--- a/freebsd/sys/dev/usb/usbhid.h
+++ b/freebsd/sys/dev/usb/usbhid.h
@@ -226,14 +226,16 @@ void hid_end_parse(struct hid_data *s);
int hid_get_item(struct hid_data *s, struct hid_item *h);
int hid_report_size(const void *buf, usb_size_t len, enum hid_kind k,
uint8_t *id);
-int hid_locate(const void *desc, usb_size_t size, uint32_t usage,
+int hid_locate(const void *desc, usb_size_t size, int32_t usage,
enum hid_kind kind, uint8_t index, struct hid_location *loc,
uint32_t *flags, uint8_t *id);
int32_t hid_get_data(const uint8_t *buf, usb_size_t len,
struct hid_location *loc);
uint32_t hid_get_data_unsigned(const uint8_t *buf, usb_size_t len,
struct hid_location *loc);
-int hid_is_collection(const void *desc, usb_size_t size, uint32_t usage);
+void hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
+ struct hid_location *loc, unsigned int value);
+int hid_is_collection(const void *desc, usb_size_t size, int32_t usage);
struct usb_hid_descriptor *hid_get_descriptor_from_usb(
struct usb_config_descriptor *cd,
struct usb_interface_descriptor *id);