Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Add suspend/resume handling to the UHCI driver.



details:   https://anonhg.NetBSD.org/src/rev/12fbcd613e24
branches:  trunk
changeset: 474032:12fbcd613e24
user:      augustss <augustss%NetBSD.org@localhost>
date:      Sat Jun 26 08:30:17 1999 +0000

description:
Add suspend/resume handling to the UHCI driver.
Currently it only works if the BIOS saves enough state of the controller.
Once I find a machine with a dumber BIOS I'll try to improve that.

diffstat:

 sys/dev/usb/uhci.c    |  105 +++++++++++++++++++++++++++++++++++++++++--------
 sys/dev/usb/uhcivar.h |    6 ++-
 sys/dev/usb/usb.h     |   10 +++-
 3 files changed, 100 insertions(+), 21 deletions(-)

diffs (266 lines):

diff -r 1667a7accfa5 -r 12fbcd613e24 sys/dev/usb/uhci.c
--- a/sys/dev/usb/uhci.c        Sat Jun 26 08:25:25 1999 +0000
+++ b/sys/dev/usb/uhci.c        Sat Jun 26 08:30:17 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uhci.c,v 1.29 1999/06/09 17:04:45 augustss Exp $       */
+/*     $NetBSD: uhci.c,v 1.30 1999/06/26 08:30:17 augustss Exp $       */
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -124,6 +124,7 @@
 LIST_HEAD(, uhci_intr_info) uhci_ii_free;
 
 void           uhci_busreset __P((uhci_softc_t *));
+void           uhci_power __P((int, void *));
 usbd_status    uhci_run __P((uhci_softc_t *, int run));
 uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *));
 void           uhci_free_std __P((uhci_softc_t *, uhci_soft_td_t *));
@@ -294,16 +295,9 @@
        int i, j;
        uhci_soft_qh_t *csqh, *bsqh, *sqh;
        uhci_soft_td_t *std;
-       usb_dma_t dma;
-       static int uhci_global_init_done = 0;
 
        DPRINTFN(1,("uhci_init: start\n"));
 
-       if (!uhci_global_init_done) {
-               uhci_global_init_done = 1;
-               LIST_INIT(&uhci_ii_free);
-       }
-
 #if defined(USB_DEBUG)
        if (uhcidebug > 2)
                uhci_dumpregs(sc);
@@ -317,12 +311,12 @@
        /* Allocate and initialize real frame array. */
        r = usb_allocmem(sc->sc_dmatag, 
                         UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
-                        UHCI_FRAMELIST_ALIGN, &dma);
+                        UHCI_FRAMELIST_ALIGN, &sc->sc_dma);
        if (r != USBD_NORMAL_COMPLETION)
                return (r);
-       sc->sc_pframes = KERNADDR(&dma);
+       sc->sc_pframes = KERNADDR(&sc->sc_dma);
        UWRITE2(sc, UHCI_FRNUM, 0);             /* set frame number to 0 */
-       UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&dma)); /* set frame list */
+       UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma)); /* set frame list */
 
        /* Allocate the dummy QH where bulk traffic will be queued. */
        bsqh = uhci_alloc_sqh(sc);
@@ -377,6 +371,9 @@
        sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
        sc->sc_bus.do_poll = uhci_poll;
 
+       sc->sc_suspend = PWR_RESUME;
+       (void)powerhook_establish(uhci_power, sc);
+
        DPRINTFN(1,("uhci_init: enabling\n"));
        UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | 
                UHCI_INTR_IOCE | UHCI_INTR_SPIE);       /* enable interrupts */
@@ -384,6 +381,68 @@
        return (uhci_run(sc, 1));               /* and here we go... */
 }
 
+/*
+ * Handle suspend/resume.
+ *
+ * Must use delay() here since we are called from an interrupt
+ * context, but since we are close to being inactive anyway
+ * it doesn't matter.
+ */
+void
+uhci_power(why, v)
+       int why;
+       void *v;
+{
+       uhci_softc_t *sc = v;
+       int cmd;
+       int s;
+
+       s = splusb();
+       cmd = UREAD2(sc, UHCI_CMD);
+
+       DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n", 
+                sc, why, sc->sc_suspend, cmd));
+
+       if (why != PWR_RESUME) {
+#if defined(USB_DEBUG)
+               if (uhcidebug > 2)
+                       uhci_dumpregs(sc);
+#endif
+               if (sc->sc_has_timo)
+                       usb_untimeout(uhci_timo, sc->sc_has_timo, 
+                                     sc->sc_has_timo->timo_handle);
+               uhci_run(sc, 0); /* stop the controller */
+               UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */
+               delay(USB_RESUME_WAIT * 1000);
+               sc->sc_suspend = why;
+               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.
+                */
+               sc->sc_suspend = why;
+               if (cmd & UHCI_CMD_RS)
+                       uhci_run(sc, 0); /* in case BIOS has started it */
+               UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
+               delay(USB_RESUME_DELAY * 1000);
+               UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
+               UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | 
+                       UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
+               uhci_run(sc, 1); /* and start traffic again */
+               delay(USB_RESUME_RECOVERY * 1000);
+               if (sc->sc_has_timo)
+                       usb_timeout(uhci_timo, sc->sc_has_timo, 
+                                   sc->sc_ival, sc->sc_has_timo->timo_handle);
+#if defined(USB_DEBUG)
+               if (uhcidebug > 2)
+                       uhci_dumpregs(sc);
+#endif
+       }
+       splx(s);
+}
+
 #ifdef USB_DEBUG
 static void
 uhci_dumpregs(sc)
@@ -655,6 +714,10 @@
        }
 #endif
        status = UREAD2(sc, UHCI_STS);
+#ifdef DIAGNOSTIC
+       if (sc->sc_suspend != PWR_RESUME)
+               printf("uhci_intr: suspended sts=0x%x\n", status);
+#endif
        ret = 0;
        if (status & UHCI_STS_USBINT) {
                UWRITE2(sc, UHCI_STS, UHCI_STS_USBINT); /* acknowledge */
@@ -933,17 +996,15 @@
 
        run = run != 0;
        s = splusb();
-       running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
-       if (run == running) {
-               splx(s);
-               return (USBD_NORMAL_COMPLETION);
-       }
-       UWRITE2(sc, UHCI_CMD, run ? UHCI_CMD_RS : 0);
+       DPRINTF(("uhci_run: setting run=%d\n", run));
+       UHCICMD(sc, run ? UHCI_CMD_RS : 0);
        for(n = 0; n < 10; n++) {
                running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
                /* return when we've entered the state we want */
                if (run == running) {
                        splx(s);
+                       DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n",
+                                UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS)));
                        return (USBD_NORMAL_COMPLETION);
                }
                usb_delay_ms(&sc->sc_bus, 1);
@@ -2552,7 +2613,10 @@
 uhci_root_ctrl_close(pipe)
        usbd_pipe_handle pipe;
 {
+       uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
+
        usb_untimeout(uhci_timo, pipe->intrreqh, pipe->intrreqh->timo_handle);
+       sc->sc_has_timo = 0;
        DPRINTF(("uhci_root_ctrl_close\n"));
 }
 
@@ -2561,7 +2625,10 @@
 uhci_root_intr_abort(reqh)
        usbd_request_handle reqh;
 {
+       uhci_softc_t *sc = (uhci_softc_t *)reqh->pipe->device->bus;
+
        usb_untimeout(uhci_timo, reqh, reqh->timo_handle);
+       sc->sc_has_timo = 0;
 }
 
 usbd_status
@@ -2607,6 +2674,7 @@
 
        sc->sc_ival = MS_TO_TICKS(reqh->pipe->endpoint->edesc->bInterval);
        usb_timeout(uhci_timo, reqh, sc->sc_ival, reqh->timo_handle);
+       sc->sc_has_timo = reqh;
        return (USBD_IN_PROGRESS);
 }
 
@@ -2615,7 +2683,10 @@
 uhci_root_intr_close(pipe)
        usbd_pipe_handle pipe;
 {
+       uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
+
        usb_untimeout(uhci_timo, pipe->intrreqh, pipe->intrreqh->timo_handle);
+       sc->sc_has_timo = 0;
        DPRINTF(("uhci_root_intr_close\n"));
 }
 
diff -r 1667a7accfa5 -r 12fbcd613e24 sys/dev/usb/uhcivar.h
--- a/sys/dev/usb/uhcivar.h     Sat Jun 26 08:25:25 1999 +0000
+++ b/sys/dev/usb/uhcivar.h     Sat Jun 26 08:30:17 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uhcivar.h,v 1.6 1999/05/20 09:52:35 augustss Exp $     */
+/*     $NetBSD: uhcivar.h,v 1.7 1999/06/26 08:30:18 augustss Exp $     */
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -129,6 +129,7 @@
 #endif /* defined(__FreeBSD__) */
 
        uhci_physaddr_t *sc_pframes;
+       usb_dma_t sc_dma;
        struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT];
 
        uhci_soft_qh_t *sc_ctl_start;   /* dummy QH for control */
@@ -145,6 +146,9 @@
 
        char sc_isreset;
 
+       char sc_suspend;
+       usbd_request_handle sc_has_timo;
+
        int sc_intrs;
        LIST_HEAD(, uhci_intr_info) sc_intrhead;
 
diff -r 1667a7accfa5 -r 12fbcd613e24 sys/dev/usb/usb.h
--- a/sys/dev/usb/usb.h Sat Jun 26 08:25:25 1999 +0000
+++ b/sys/dev/usb/usb.h Sat Jun 26 08:30:17 1999 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: usb.h,v 1.21 1999/05/18 23:42:56 thorpej Exp $ */
+/*     $NetBSD: usb.h,v 1.22 1999/06/26 08:30:18 augustss Exp $        */
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -375,20 +375,24 @@
 #define USB_PORT_RESET_SETTLE  10  /* ms */
 #define USB_PORT_POWERUP_DELAY 100 /* ms */
 #define USB_SET_ADDRESS_SETTLE 2   /* ms */
+#define USB_RESUME_TIME                (20*5)  /* ms */
+#define USB_RESUME_WAIT                10  /* ms */
+#define USB_RESUME_RECOVERY    10  /* ms */
 #else
 /* Allow for marginal (i.e. non-conforming) devices. */
 #define USB_PORT_RESET_DELAY   50  /* ms */
 #define USB_PORT_RESET_RECOVERY        50  /* ms */
 #define USB_PORT_POWERUP_DELAY 200 /* 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 */
 #endif
 
 #define USB_MIN_POWER          100 /* mA */
 #define USB_MAX_POWER          500 /* mA */
 
-
 #define USB_BUS_RESET_DELAY    100 /* ms XXX?*/
-#define USB_RESUME_DELAY       10  /* ms XXX?*/
 
 /*** ioctl() related stuff ***/
 



Home | Main Index | Thread Index | Old Index