summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/usb/controller/ehci.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/usb/controller/ehci.c')
-rw-r--r--freebsd/sys/dev/usb/controller/ehci.c375
1 files changed, 161 insertions, 214 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,
};