weird usb problem

Hans Petter Selasky hselasky at c2i.net
Tue Aug 9 20:15:44 GMT 2005


On Tuesday 09 August 2005 21:12, Maksim Yevmenkin wrote:
>
> > > beetle% diff -u10 ehci.c.orig ehci.c
> > > --- ehci.c.orig Sat May 28 21:42:27 2005
> > > +++ ehci.c      Tue Aug  9 09:53:13 2005
> > > @@ -632,20 +632,21 @@
> > >                 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);
> >
> > You need to clear the PCD interrupt bit here, because it is possibly
> > still set, and enabling bits in the interrupt mask does not generate
> > another interrupt!
> >
> >          /* acknowledge any PCD interrupt */
> >          EOWRITE4(sc, EHCI_USBSTS, EHCI_STS_PCD);
> >
> > > +       ehci_pcd(sc, sc->sc_intrxfer);
> > >  }
>
> oops, my bad. i did not realize i have to use  EHCI_USBSTS and not
> EHCI_USBINTR (as in ehci_pcd_able()), so the diff  looks like

Yes, but there is no need to change anything in ehci_pcd_able(). It should 
write interrupt mask first, then if you enable the interrupt, clear the 
status bit before finishing the root interrupt transfer.

>
> beetle% diff -u10 ehci.c.orig ehci.c
> --- ehci.c.orig Sat May 28 21:42:27 2005
> +++ ehci.c      Tue Aug  9 11:47:17 2005
> @@ -632,20 +632,25 @@
>                 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);
> +
> +       /* acknowledge any PCD interrupt */
> +       EOWRITE4(sc, EHCI_USBSTS, EHCI_STS_PCD);
> +
> +       ehci_pcd(sc, sc->sc_intrxfer);
>  }
>
>  void
>   ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
>  {
>         usbd_pipe_handle pipe;
>         u_char *p;
>         int i, m;
>
>         if (xfer == NULL) {
>

This looks right. Only one thing. There might be some missing "spl/splx" 
lines, if this code is supposed to be used on NetBSD for example. Hence 
FreeBSD will lock Giant before calling the callback, there is no problem.

>
> ok, i have tried this and  *nothing* happened when i plug the usb 2.0
> device. no debug output whatsoever.

If there is no pcd change interrupt the device is not detected at all.


>
> i just got an usb extension cable with _proper_sized_ usb plug and
> tried it, and it just worked. i will make a clean build without any
> ehci(4) changes to see if the problem still there.

Try connecting a lowspeed USB device to an external USB 2.0 hub first. Then 
connect the external hub to the root hub. It is important that you connect 
the devices to the HUB first. On my computer you need that patch I have 
suggested, else no devices on the external HUB are detected at all. And that 
is just due to lost interrupts.



Maybe you can patch the OHCI driver too?

Here is what my driver looks like:

static void
ohci_rhsc_enable(ohci_softc_t *sc)
{
        struct mtx *priv_mtx;
        struct usbd_xfer *xfer;

        DPRINTFN(4, ("\n"));

        mtx_lock(&sc->sc_bus.mtx);

        sc->sc_eintrs |= OHCI_RHSC;
        OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC);

        /* acknowledge any RHSC interrupt */
        OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC);

        ...


I suggest something like this in the old driver:

void
ohci_rhsc_enable(void *v_sc)
{
        ohci_softc_t *sc = v_sc;
        int s;

        s = splhardusb(); // not sure if this is right
        ohci_rhsc_able(sc, 1);

        /* acknowledge any RHSC interrupt */
        OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC);

        ohci_rhsc(sc, sc->sc_intrxfer);

        splx(s);
        return;
}

--HPS


More information about the freebsd-usb mailing list