summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorn_hibma <n_hibma@FreeBSD.org>2000-08-07 00:04:53 +0000
committern_hibma <n_hibma@FreeBSD.org>2000-08-07 00:04:53 +0000
commit38a807f0b046f79d3d0290ceda8704ff3cf14559 (patch)
treeed469d252fee5261a77bc64b7bcf2927a46168b0 /sys/dev
parent7a93943baf71e64372d95defad2b70666a260193 (diff)
downloadFreeBSD-src-38a807f0b046f79d3d0290ceda8704ff3cf14559.zip
FreeBSD-src-38a807f0b046f79d3d0290ceda8704ff3cf14559.tar.gz
Save and restore the registers SOF and FRAMENUMBER on suspend. In some
cases the registers are not correctly set on resume. This solves the problem of USB failing after resuming a machine. Submitted by: mike+fbsd@medianstrip.net PR: 18261
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/uhci.c17
-rw-r--r--sys/dev/usb/uhcivar.h3
2 files changed, 15 insertions, 5 deletions
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 1095fe6..ea9a802 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -250,6 +250,7 @@ Static void uhci_dump_tds(uhci_soft_td_t *);
Static void uhci_dump_td(uhci_soft_td_t *);
#endif
+#define UWRITE1(sc, r, x) bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x))
#define UWRITE2(sc, r, x) bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x))
#define UWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x))
#define UREAD1(sc, r) bus_space_read_1((sc)->iot, (sc)->ioh, (r))
@@ -565,17 +566,17 @@ uhci_power(int why, void *v)
sc->sc_has_timo->timo_handle);
sc->sc_bus.use_polling++;
uhci_run(sc, 0); /* stop the controller */
+
+ /* save some state if BIOS doesn't */
+ sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);
+ sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);
+
UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */
usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
sc->sc_suspend = why;
sc->sc_bus.use_polling--;
DPRINTF(("uhci_power: cmd=0x%x\n", UREAD2(sc, UHCI_CMD)));
} else {
- /*
- * XXX We should really do much more here in case the
- * controller registers have been lost and BIOS has
- * not restored them.
- */
#ifdef DIAGNOSTIC
if (sc->sc_suspend == PWR_RESUME)
printf("uhci_power: weird, resume without suspend.\n");
@@ -584,6 +585,12 @@ uhci_power(int why, void *v)
sc->sc_suspend = why;
if (cmd & UHCI_CMD_RS)
uhci_run(sc, 0); /* in case BIOS has started it */
+
+ /* restore saved state */
+ UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
+ UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum);
+ UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
+
UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
diff --git a/sys/dev/usb/uhcivar.h b/sys/dev/usb/uhcivar.h
index 5e73e71..ead3495 100644
--- a/sys/dev/usb/uhcivar.h
+++ b/sys/dev/usb/uhcivar.h
@@ -154,6 +154,9 @@ typedef struct uhci_softc {
u_int8_t sc_addr; /* device address */
u_int8_t sc_conf; /* device configuration */
+ u_int8_t sc_saved_sof;
+ u_int16_t sc_saved_frnum;
+
char sc_isreset;
char sc_suspend;
OpenPOWER on IntegriCloud