On Fri, Oct 03, 2014 at 07:58:11PM +0200, Mark Kettenis wrote:
> > Date: Thu, 2 Oct 2014 12:20:14 +0200
> > From: Martin Pieuchot <[email protected]>
> >
> > Our USB stack contains a hack needed for ehci(4) and ohci(4) that
> > breaks xhci(4). The diff below moves this hack in these drivers,
> > and makes it possible to have a working xhci(4) in GENERIC.
> >
> > I'd like this diff to be tested on as much machines as possible, because
> > the code path it touches is very sensible. This also matters if you are
> > using uhci(4)!
> >
> > Please test and report back.
>
> Works fine for me on my old i386 Mac mini with usb keyboard and mouse
> and two usb disks. Diff makes sense to me as well.
Works ok for me on x230.
>
> ok kettenis@
>
> > Index: ehci.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/usb/ehci.c,v
> > retrieving revision 1.168
> > diff -u -p -r1.168 ehci.c
> > --- ehci.c 1 Sep 2014 08:13:02 -0000 1.168
> > +++ ehci.c 2 Oct 2014 09:30:28 -0000
> > @@ -99,6 +99,7 @@ struct ehci_pipe {
> > u_int8_t ehci_reverse_bits(u_int8_t, int);
> >
> > usbd_status ehci_open(struct usbd_pipe *);
> > +int ehci_setaddr(struct usbd_device *, int);
> > void ehci_poll(struct usbd_bus *);
> > void ehci_softintr(void *);
> > int ehci_intr1(struct ehci_softc *);
> > @@ -215,7 +216,7 @@ void ehci_dump_exfer(struct ehci_xfer *
> >
> > struct usbd_bus_methods ehci_bus_methods = {
> > .open_pipe = ehci_open,
> > - .dev_setaddr = usbd_set_address,
> > + .dev_setaddr = ehci_setaddr,
> > .soft_intr = ehci_softintr,
> > .do_poll = ehci_poll,
> > .allocx = ehci_allocx,
> > @@ -603,6 +604,40 @@ ehci_pcd(struct ehci_softc *sc, struct u
> > xfer->status = USBD_NORMAL_COMPLETION;
> >
> > usb_transfer_complete(xfer);
> > +}
> > +
> > +/*
> > + * Work around the half configured control (default) pipe when setting
> > + * the address of a device.
> > + *
> > + * Because a single QH is setup per endpoint in ehci_open(), and the
> > + * control pipe is configured before we could have set the address
> > + * of the device or read the wMaxPacketSize of the endpoint, we have
> > + * to re-open the pipe twice here.
> > + */
> > +int
> > +ehci_setaddr(struct usbd_device *dev, int addr)
> > +{
> > + /* Root Hub */
> > + if (dev->depth == 0)
> > + return (0);
> > +
> > + /* Re-establish the default pipe with the new max packet size. */
> > + ehci_close_pipe(dev->default_pipe);
> > + if (ehci_open(dev->default_pipe))
> > + return (EINVAL);
> > +
> > + if (usbd_set_address(dev, addr))
> > + return (1);
> > +
> > + dev->address = addr;
> > +
> > + /* Re-establish the default pipe with the new address. */
> > + ehci_close_pipe(dev->default_pipe);
> > + if (ehci_open(dev->default_pipe))
> > + return (EINVAL);
> > +
> > + return (0);
> > }
> >
> > void
> > Index: ohci.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/usb/ohci.c,v
> > retrieving revision 1.139
> > diff -u -p -r1.139 ohci.c
> > --- ohci.c 10 Aug 2014 11:18:57 -0000 1.139
> > +++ ohci.c 2 Oct 2014 09:33:03 -0000
> > @@ -88,6 +88,7 @@ usbd_status ohci_alloc_std_chain(struct
> > struct ohci_soft_td **);
> >
> > usbd_status ohci_open(struct usbd_pipe *);
> > +int ohci_setaddr(struct usbd_device *, int);
> > void ohci_poll(struct usbd_bus *);
> > void ohci_softintr(void *);
> > void ohci_waitintr(struct ohci_softc *, struct usbd_xfer *);
> > @@ -232,7 +233,7 @@ struct ohci_pipe {
> >
> > struct usbd_bus_methods ohci_bus_methods = {
> > .open_pipe = ohci_open,
> > - .dev_setaddr = usbd_set_address,
> > + .dev_setaddr = ohci_setaddr,
> > .soft_intr = ohci_softintr,
> > .do_poll = ohci_poll,
> > .allocx = ohci_allocx,
> > @@ -2003,6 +2004,40 @@ ohci_open(struct usbd_pipe *pipe)
> > bad0:
> > return (USBD_NOMEM);
> >
> > +}
> > +
> > +/*
> > + * Work around the half configured control (default) pipe when setting
> > + * the address of a device.
> > + *
> > + * Because a single ED is setup per endpoint in ohci_open(), and the
> > + * control pipe is configured before we could have set the address
> > + * of the device or read the wMaxPacketSize of the endpoint, we have
> > + * to re-open the pipe twice here.
> > + */
> > +int
> > +ohci_setaddr(struct usbd_device *dev, int addr)
> > +{
> > + /* Root Hub */
> > + if (dev->depth == 0)
> > + return (0);
> > +
> > + /* Re-establish the default pipe with the new max packet size. */
> > + ohci_device_ctrl_close(dev->default_pipe);
> > + if (ohci_open(dev->default_pipe))
> > + return (EINVAL);
> > +
> > + if (usbd_set_address(dev, addr))
> > + return (1);
> > +
> > + dev->address = addr;
> > +
> > + /* Re-establish the default pipe with the new address. */
> > + ohci_device_ctrl_close(dev->default_pipe);
> > + if (ohci_open(dev->default_pipe))
> > + return (EINVAL);
> > +
> > + return (0);
> > }
> >
> > /*
> > Index: usb_subr.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/usb/usb_subr.c,v
> > retrieving revision 1.109
> > diff -u -p -r1.109 usb_subr.c
> > --- usb_subr.c 1 Oct 2014 08:29:01 -0000 1.109
> > +++ usb_subr.c 2 Oct 2014 09:24:18 -0000
> > @@ -901,8 +901,8 @@ usbd_probe_and_attach(struct device *par
> > "error=%s\n", parent->dv_xname, port,
> > addr, usbd_errstr(err)));
> > #else
> > - printf("%s: port %d, set config at addr %d failed\n",
> > - parent->dv_xname, port, addr);
> > + printf("%s: port %d, set config %d at addr %d failed\n",
> > + parent->dv_xname, port, confi, addr);
> > #endif
> >
> > goto fail;
> > @@ -1160,23 +1160,6 @@ usbd_new_device(struct device *parent, s
> >
> > USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
> >
> > - /* Re-establish the default pipe with the new max packet size. */
> > - usbd_close_pipe(dev->default_pipe);
> > - err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
> > - &dev->default_pipe);
> > - if (err) {
> > - usb_free_device(dev);
> > - up->device = NULL;
> > - return (err);
> > - }
> > -
> > - err = usbd_reload_device_desc(dev);
> > - if (err) {
> > - usb_free_device(dev);
> > - up->device = NULL;
> > - return (err);
> > - }
> > -
> > /* Set the address if the HC didn't do it already. */
> > if (bus->methods->dev_setaddr != NULL &&
> > bus->methods->dev_setaddr(dev, addr)) {
> > @@ -1192,10 +1175,7 @@ usbd_new_device(struct device *parent, s
> > dev->address = addr;
> > bus->devices[addr] = dev;
> >
> > - /* Re-establish the default pipe with the new address. */
> > - usbd_close_pipe(dev->default_pipe);
> > - err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
> > - &dev->default_pipe);
> > + err = usbd_reload_device_desc(dev);
> > if (err) {
> > usb_free_device(dev);
> > up->device = NULL;
> >
> >
>