Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Recognize port status changes.



details:   https://anonhg.NetBSD.org/src/rev/03940f2588f4
branches:  trunk
changeset: 517607:03940f2588f4
user:      augustss <augustss%NetBSD.org@localhost>
date:      Fri Nov 16 01:57:08 2001 +0000

description:
Recognize port status changes.
Hand over low and full speed devices to companion controller.

diffstat:

 sys/dev/usb/ehci.c    |  240 +++++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/usb/ehcireg.h |   14 ++-
 sys/dev/usb/ehcivar.h |    8 +-
 3 files changed, 246 insertions(+), 16 deletions(-)

diffs (truncated from 457 to 300 lines):

diff -r 0fefaf316b81 -r 03940f2588f4 sys/dev/usb/ehci.c
--- a/sys/dev/usb/ehci.c        Fri Nov 16 01:50:17 2001 +0000
+++ b/sys/dev/usb/ehci.c        Fri Nov 16 01:57:08 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ehci.c,v 1.5 2001/11/15 23:25:09 augustss Exp $        */
+/*     $NetBSD: ehci.c,v 1.6 2001/11/16 01:57:08 augustss Exp $        */
 
 /*
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -45,7 +45,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.5 2001/11/15 23:25:09 augustss Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.6 2001/11/16 01:57:08 augustss Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -71,7 +71,7 @@
 #ifdef EHCI_DEBUG
 #define DPRINTF(x)     if (ehcidebug) printf x
 #define DPRINTFN(n,x)  if (ehcidebug>(n)) printf x
-int ehcidebug = 5;
+int ehcidebug = 0;
 #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
 #else
 #define DPRINTF(x)
@@ -135,9 +135,15 @@
 Static void            ehci_noop(usbd_pipe_handle pipe);
 
 Static int             ehci_str(usb_string_descriptor_t *, int, char *);
+Static void            ehci_pcd(ehci_softc_t *, usbd_xfer_handle);
+Static void            ehci_pcd_able(ehci_softc_t *, int);
+Static void            ehci_pcd_enable(void *);
+Static void            ehci_disown(ehci_softc_t *, int, int);
 
 #ifdef EHCI_DEBUG
 Static void            ehci_dumpregs(ehci_softc_t *);
+Static void            ehci_dump(void);
+Static ehci_softc_t    *theehci;
 #endif
 
 #define EHCI_INTR_ENDPT 1
@@ -214,6 +220,9 @@
        usbd_status err;
 
        DPRINTF(("ehci_init: start\n"));
+#ifdef EHCI_DEBUG
+       theehci = sc;
+#endif
 
        sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
 
@@ -223,6 +232,7 @@
 
        sparams = EREAD4(sc, EHCI_HCSPARAMS);
        DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
+       sc->sc_npcomp = EHCI_HCS_N_PCC(sparams);
        if (EHCI_HCS_N_CC(sparams) != sc->sc_ncomp) {
                printf("%s: wrong number of companions (%d != %d)\n",
                       USBDEVNAME(sc->sc_bus.bdev),
@@ -273,6 +283,8 @@
                return (err);
        DPRINTF(("%s: flsize=%d\n", USBDEVNAME(sc->sc_bus.bdev),sc->sc_flsize));
 
+       usb_callout_init(sc->sc_tmo_pcd);
+
        /* Set up the bus struct. */
        sc->sc_bus.methods = &ehci_bus_methods;
        sc->sc_bus.pipe_size = sizeof(struct ehci_pipe);
@@ -280,13 +292,159 @@
        sc->sc_powerhook = powerhook_establish(ehci_power, sc);
        sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc);
 
+       sc->sc_eintrs = EHCI_NORMAL_INTRS;
+
+       /* Enable interrupts */
+       EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+
+       /* Turn on controller */
+       EOWRITE4(sc, EHCI_USBCMD,
+                EHCI_CMD_ITC_8 | /* 8 microframes */
+                (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);
+
        return (USBD_NORMAL_COMPLETION);
 }
 
+Static int ehci_intr1(ehci_softc_t *);
+
 int
 ehci_intr(void *v)
 {
-       return (0);
+       ehci_softc_t *sc = v;
+
+       /* If we get an interrupt while polling, then just ignore it. */
+       if (sc->sc_bus.use_polling) {
+#ifdef DIAGNOSTIC
+               printf("ehci_intr: ignored interrupt while polling\n");
+#endif
+               return (0);
+       }
+
+       return (ehci_intr1(sc)); 
+}
+
+Static int
+ehci_intr1(ehci_softc_t *sc)
+{
+       u_int32_t intrs, eintrs;
+
+       DPRINTFN(20,("ehci_intr1: enter\n"));
+
+       /* In case the interrupt occurs before initialization has completed. */
+       if (sc == NULL) {
+#ifdef DIAGNOSTIC
+               printf("ehci_intr: sc == NULL\n");
+#endif
+               return (0);
+       }
+
+       intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
+
+       if (!intrs)
+               return (0);
+
+       EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */
+       eintrs = intrs & sc->sc_eintrs;
+       DPRINTFN(7, ("ehci_intr: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n", 
+                    sc, (u_int)intrs, EOREAD4(sc, EHCI_USBSTS),
+                    (u_int)eintrs));
+       if (!eintrs)
+               return (0);
+
+       sc->sc_bus.intr_context++;
+       sc->sc_bus.no_intrs++;
+       if (eintrs & EHCI_STS_INT) {
+               DPRINTF(("ehci_intr1: something is done\n"));
+               eintrs &= ~EHCI_STS_INT;
+       }
+       if (eintrs & EHCI_STS_ERRINT) {
+               DPRINTF(("ehci_intr1: some error\n"));
+               eintrs &= ~EHCI_STS_HSE;
+       }
+       if (eintrs & EHCI_STS_HSE) {
+               printf("%s: unrecoverable error, controller halted\n",
+                      USBDEVNAME(sc->sc_bus.bdev));
+               /* XXX what else */
+       }
+       if (eintrs & EHCI_STS_PCD) {
+               ehci_pcd(sc, sc->sc_intrxfer);
+               /* 
+                * Disable PCD interrupt for now, because it will be
+                * on until the port has been reset.
+                */
+               ehci_pcd_able(sc, 0);
+               /* Do not allow RHSC interrupts > 1 per second */
+                usb_callout(sc->sc_tmo_pcd, hz, ehci_pcd_enable, sc);
+               eintrs &= ~EHCI_STS_PCD;
+       }
+
+       sc->sc_bus.intr_context--;
+
+       if (eintrs != 0) {
+               /* Block unprocessed interrupts. */
+               sc->sc_eintrs &= ~eintrs;
+               EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+               printf("%s: blocking intrs 0x%x\n",
+                      USBDEVNAME(sc->sc_bus.bdev), eintrs);
+       }
+
+       return (1);
+}
+
+void
+ehci_pcd_able(ehci_softc_t *sc, int on)
+{
+       DPRINTFN(4, ("ehci_pcd_able: on=%d\n", on));
+       if (on)
+               sc->sc_eintrs |= EHCI_STS_PCD;
+       else
+               sc->sc_eintrs &= ~EHCI_STS_PCD;
+       EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+}
+
+void
+ehci_pcd_enable(void *v_sc)
+{
+       ehci_softc_t *sc = v_sc;
+
+       ehci_pcd_able(sc, 1);
+}
+
+void
+ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
+{
+       usbd_pipe_handle pipe;
+       struct ehci_pipe *opipe;
+       u_char *p;
+       int i, m;
+
+       if (xfer == NULL) {
+               /* Just ignore the change. */
+               return;
+       }
+
+       pipe = xfer->pipe;
+       opipe = (struct ehci_pipe *)pipe;
+
+       p = KERNADDR(&xfer->dmabuf);
+       m = min(sc->sc_noport, xfer->length * 8 - 1);
+       memset(p, 0, xfer->length);
+       for (i = 1; i <= m; i++) {
+               /* Pick out CHANGE bits from the status reg. */
+               if (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR)
+                       p[i/8] |= 1 << (i%8);
+       }
+       DPRINTF(("ehci_pcd: change=0x%02x\n", *p));
+       xfer->actlen = xfer->length;
+       xfer->status = USBD_NORMAL_COMPLETION;
+
+       usb_transfer_complete(xfer);
 }
 
 void
@@ -298,21 +456,19 @@
 void
 ehci_poll(struct usbd_bus *bus)
 {
-#if 0
        ehci_softc_t *sc = (ehci_softc_t *)bus;
 #ifdef EHCI_DEBUG
        static int last;
        int new;
-       new = OREAD4(sc, EHCI_INTERRUPT_STATUS);
+       new = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
        if (new != last) {
                DPRINTFN(10,("ehci_poll: intrs=0x%04x\n", new));
                last = new;
        }
 #endif
 
-       if (OREAD4(sc, EHCI_INTERRUPT_STATUS) & sc->sc_eintrs)
+       if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs)
                ehci_intr1(sc);
-#endif
 }
 
 int
@@ -326,6 +482,8 @@
        if (rv != 0)
                return (rv);
 
+       usb_uncallout(sc->sc_tmo_pcd, ehci_pcd_enable, sc);
+
        if (sc->sc_powerhook != NULL)
                powerhook_disestablish(sc->sc_powerhook);
        if (sc->sc_shutdownhook != NULL)
@@ -506,7 +664,20 @@
 void
 ehci_dumpregs(ehci_softc_t *sc)
 {
-       // OOO
+       int i;
+       printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
+              EOREAD4(sc, EHCI_USBCMD),
+              EOREAD4(sc, EHCI_USBSTS),
+              EOREAD4(sc, EHCI_USBINTR));
+       for (i = 1; i <= sc->sc_noport; i++)
+               printf("port %d status=0x%08x\n", i, 
+                      EOREAD4(sc, EHCI_PORTSC(i)));
+}
+
+void
+ehci_dump()
+{
+       ehci_dumpregs(theehci);
 }
 #endif
 
@@ -906,7 +1077,7 @@
                        EOWRITE4(sc, port, v | EHCI_PS_OCC);
                        break;
                case UHF_C_PORT_RESET:
-                       /* how? */
+                       sc->sc_isreset = 0;
                        break;
                default:
                        err = USBD_IOERROR;
@@ -921,7 +1092,7 @@
                case UHF_C_PORT_RESET:
                        /* Enable RHSC interrupt if condition is cleared. */
                        if ((OREAD4(sc, port) >> 16) == 0)
-                               ehci_rhsc_able(sc, 1);



Home | Main Index | Thread Index | Old Index