> 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.

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;
> 
> 

Reply via email to