[BACK]Return to xhci.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/usb/xhci.c between version 1.28 and 1.28.2.81

version 1.28, 2014/11/18 10:18:45 version 1.28.2.81, 2017/01/02 16:45:30
Line 26 
Line 26 
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */   */
   
   /*
    * USB rev 2.0 and rev 3.1 specification
    *  http://www.usb.org/developers/docs/
    * xHCI rev 1.1 specification
    *  http://www.intel.com/technology/usb/spec.htm
    */
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
   #ifdef _KERNEL_OPT
 #include "opt_usb.h"  #include "opt_usb.h"
   #endif
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
 #include <sys/kmem.h>  #include <sys/kmem.h>
 #include <sys/malloc.h>  
 #include <sys/device.h>  #include <sys/device.h>
 #include <sys/select.h>  #include <sys/select.h>
 #include <sys/proc.h>  #include <sys/proc.h>
Line 51  __KERNEL_RCSID(0, "$NetBSD$");
Line 59  __KERNEL_RCSID(0, "$NetBSD$");
 #include <dev/usb/usb.h>  #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>  #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdivar.h>  #include <dev/usb/usbdivar.h>
   #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbhist.h>  #include <dev/usb/usbhist.h>
 #include <dev/usb/usb_mem.h>  #include <dev/usb/usb_mem.h>
 #include <dev/usb/usb_quirks.h>  #include <dev/usb/usb_quirks.h>
   
 #include <dev/usb/xhcireg.h>  #include <dev/usb/xhcireg.h>
 #include <dev/usb/xhcivar.h>  #include <dev/usb/xhcivar.h>
 #include <dev/usb/usbroothub_subr.h>  #include <dev/usb/usbroothub.h>
   
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
 #ifndef XHCI_DEBUG  #ifndef XHCI_DEBUG
 #define xhcidebug 0  #define xhcidebug 0
 #else  #else /* !XHCI_DEBUG */
 static int xhcidebug = 0;  static int xhcidebug = 0;
   
 SYSCTL_SETUP(sysctl_hw_xhci_setup, "sysctl hw.xhci setup")  SYSCTL_SETUP(sysctl_hw_xhci_setup, "sysctl hw.xhci setup")
Line 93  fail:
Line 102  fail:
         aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);          aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
 }  }
   
 #endif /* XHCI_DEBUG */  #endif /* !XHCI_DEBUG */
 #endif /* USB_DEBUG */  #endif /* USB_DEBUG */
   
 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(xhcidebug,N,FMT,A,B,C,D)  #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(xhcidebug,N,FMT,A,B,C,D)
Line 107  fail:
Line 116  fail:
   
 struct xhci_pipe {  struct xhci_pipe {
         struct usbd_pipe xp_pipe;          struct usbd_pipe xp_pipe;
           struct usb_task xp_async_task;
 };  };
   
 #define XHCI_INTR_ENDPT 1  
 #define XHCI_COMMAND_RING_TRBS 256  #define XHCI_COMMAND_RING_TRBS 256
 #define XHCI_EVENT_RING_TRBS 256  #define XHCI_EVENT_RING_TRBS 256
 #define XHCI_EVENT_RING_SEGMENTS 1  #define XHCI_EVENT_RING_SEGMENTS 1
 #define XHCI_TRB_3_ED_BIT XHCI_TRB_3_ISP_BIT  #define XHCI_TRB_3_ED_BIT XHCI_TRB_3_ISP_BIT
   
 static usbd_status xhci_open(usbd_pipe_handle);  static usbd_status xhci_open(struct usbd_pipe *);
   static void xhci_close_pipe(struct usbd_pipe *);
 static int xhci_intr1(struct xhci_softc * const);  static int xhci_intr1(struct xhci_softc * const);
 static void xhci_softintr(void *);  static void xhci_softintr(void *);
 static void xhci_poll(struct usbd_bus *);  static void xhci_poll(struct usbd_bus *);
 static usbd_status xhci_allocm(struct usbd_bus *, usb_dma_t *, uint32_t);  static struct usbd_xfer *xhci_allocx(struct usbd_bus *, unsigned int);
 static void xhci_freem(struct usbd_bus *, usb_dma_t *);  static void xhci_freex(struct usbd_bus *, struct usbd_xfer *);
 static usbd_xfer_handle xhci_allocx(struct usbd_bus *);  
 static void xhci_freex(struct usbd_bus *, usbd_xfer_handle);  
 static void xhci_get_lock(struct usbd_bus *, kmutex_t **);  static void xhci_get_lock(struct usbd_bus *, kmutex_t **);
 static usbd_status xhci_new_device(device_t, usbd_bus_handle, int, int, int,  static usbd_status xhci_new_device(device_t, struct usbd_bus *, int, int, int,
     struct usbd_port *);      struct usbd_port *);
   static int xhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
       void *, int);
   
 static usbd_status xhci_configure_endpoint(usbd_pipe_handle);  static usbd_status xhci_configure_endpoint(struct usbd_pipe *);
 static usbd_status xhci_unconfigure_endpoint(usbd_pipe_handle);  //static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
 static usbd_status xhci_reset_endpoint(usbd_pipe_handle);  static usbd_status xhci_reset_endpoint(struct usbd_pipe *);
 //static usbd_status xhci_stop_endpoint(usbd_pipe_handle);  static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
   
 static usbd_status xhci_set_dequeue(usbd_pipe_handle);  static void xhci_host_dequeue(struct xhci_ring * const);
   static usbd_status xhci_set_dequeue(struct usbd_pipe *);
   
 static usbd_status xhci_do_command(struct xhci_softc * const,  static usbd_status xhci_do_command(struct xhci_softc * const,
     struct xhci_trb * const, int);      struct xhci_trb * const, int);
 static usbd_status xhci_init_slot(struct xhci_softc * const, uint32_t,  static usbd_status xhci_do_command_locked(struct xhci_softc * const,
     int, int, int, int);      struct xhci_trb * const, int);
   static usbd_status xhci_init_slot(struct usbd_device *, uint32_t);
   static void xhci_free_slot(struct xhci_softc *, struct xhci_slot *, int, int);
   static usbd_status xhci_set_address(struct usbd_device *, uint32_t, bool);
 static usbd_status xhci_enable_slot(struct xhci_softc * const,  static usbd_status xhci_enable_slot(struct xhci_softc * const,
     uint8_t * const);      uint8_t * const);
   static usbd_status xhci_disable_slot(struct xhci_softc * const, uint8_t);
 static usbd_status xhci_address_device(struct xhci_softc * const,  static usbd_status xhci_address_device(struct xhci_softc * const,
     uint64_t, uint8_t, bool);      uint64_t, uint8_t, bool);
   static void xhci_set_dcba(struct xhci_softc * const, uint64_t, int);
 static usbd_status xhci_update_ep0_mps(struct xhci_softc * const,  static usbd_status xhci_update_ep0_mps(struct xhci_softc * const,
     struct xhci_slot * const, u_int);      struct xhci_slot * const, u_int);
 static usbd_status xhci_ring_init(struct xhci_softc * const,  static usbd_status xhci_ring_init(struct xhci_softc * const,
     struct xhci_ring * const, size_t, size_t);      struct xhci_ring * const, size_t, size_t);
 static void xhci_ring_free(struct xhci_softc * const, struct xhci_ring * const);  static void xhci_ring_free(struct xhci_softc * const, struct xhci_ring * const);
   
 static void xhci_noop(usbd_pipe_handle);  static void xhci_setup_ctx(struct usbd_pipe *);
   static void xhci_setup_route(struct usbd_pipe *, uint32_t *);
 static usbd_status xhci_root_ctrl_transfer(usbd_xfer_handle);  static void xhci_setup_tthub(struct usbd_pipe *, uint32_t *);
 static usbd_status xhci_root_ctrl_start(usbd_xfer_handle);  static void xhci_setup_maxburst(struct usbd_pipe *, uint32_t *);
 static void xhci_root_ctrl_abort(usbd_xfer_handle);  static uint32_t xhci_bival2ival(uint32_t, uint32_t);
 static void xhci_root_ctrl_close(usbd_pipe_handle);  
 static void xhci_root_ctrl_done(usbd_xfer_handle);  static void xhci_noop(struct usbd_pipe *);
   
 static usbd_status xhci_root_intr_transfer(usbd_xfer_handle);  static usbd_status xhci_root_intr_transfer(struct usbd_xfer *);
 static usbd_status xhci_root_intr_start(usbd_xfer_handle);  static usbd_status xhci_root_intr_start(struct usbd_xfer *);
 static void xhci_root_intr_abort(usbd_xfer_handle);  static void xhci_root_intr_abort(struct usbd_xfer *);
 static void xhci_root_intr_close(usbd_pipe_handle);  static void xhci_root_intr_close(struct usbd_pipe *);
 static void xhci_root_intr_done(usbd_xfer_handle);  static void xhci_root_intr_done(struct usbd_xfer *);
   
 static usbd_status xhci_device_ctrl_transfer(usbd_xfer_handle);  static usbd_status xhci_device_ctrl_transfer(struct usbd_xfer *);
 static usbd_status xhci_device_ctrl_start(usbd_xfer_handle);  static usbd_status xhci_device_ctrl_start(struct usbd_xfer *);
 static void xhci_device_ctrl_abort(usbd_xfer_handle);  static void xhci_device_ctrl_abort(struct usbd_xfer *);
 static void xhci_device_ctrl_close(usbd_pipe_handle);  static void xhci_device_ctrl_close(struct usbd_pipe *);
 static void xhci_device_ctrl_done(usbd_xfer_handle);  static void xhci_device_ctrl_done(struct usbd_xfer *);
   
 static usbd_status xhci_device_intr_transfer(usbd_xfer_handle);  static usbd_status xhci_device_intr_transfer(struct usbd_xfer *);
 static usbd_status xhci_device_intr_start(usbd_xfer_handle);  static usbd_status xhci_device_intr_start(struct usbd_xfer *);
 static void xhci_device_intr_abort(usbd_xfer_handle);  static void xhci_device_intr_abort(struct usbd_xfer *);
 static void xhci_device_intr_close(usbd_pipe_handle);  static void xhci_device_intr_close(struct usbd_pipe *);
 static void xhci_device_intr_done(usbd_xfer_handle);  static void xhci_device_intr_done(struct usbd_xfer *);
   
 static usbd_status xhci_device_bulk_transfer(usbd_xfer_handle);  static usbd_status xhci_device_bulk_transfer(struct usbd_xfer *);
 static usbd_status xhci_device_bulk_start(usbd_xfer_handle);  static usbd_status xhci_device_bulk_start(struct usbd_xfer *);
 static void xhci_device_bulk_abort(usbd_xfer_handle);  static void xhci_device_bulk_abort(struct usbd_xfer *);
 static void xhci_device_bulk_close(usbd_pipe_handle);  static void xhci_device_bulk_close(struct usbd_pipe *);
 static void xhci_device_bulk_done(usbd_xfer_handle);  static void xhci_device_bulk_done(struct usbd_xfer *);
   
 static void xhci_timeout(void *);  static void xhci_timeout(void *);
 static void xhci_timeout_task(void *);  static void xhci_timeout_task(void *);
   
 static const struct usbd_bus_methods xhci_bus_methods = {  static const struct usbd_bus_methods xhci_bus_methods = {
         .open_pipe = xhci_open,          .ubm_open = xhci_open,
         .soft_intr = xhci_softintr,          .ubm_softint = xhci_softintr,
         .do_poll = xhci_poll,          .ubm_dopoll = xhci_poll,
         .allocm = xhci_allocm,          .ubm_allocx = xhci_allocx,
         .freem = xhci_freem,          .ubm_freex = xhci_freex,
         .allocx = xhci_allocx,          .ubm_getlock = xhci_get_lock,
         .freex = xhci_freex,          .ubm_newdev = xhci_new_device,
         .get_lock = xhci_get_lock,          .ubm_rhctrl = xhci_roothub_ctrl,
         .new_device = xhci_new_device,  
 };  
   
 static const struct usbd_pipe_methods xhci_root_ctrl_methods = {  
         .transfer = xhci_root_ctrl_transfer,  
         .start = xhci_root_ctrl_start,  
         .abort = xhci_root_ctrl_abort,  
         .close = xhci_root_ctrl_close,  
         .cleartoggle = xhci_noop,  
         .done = xhci_root_ctrl_done,  
 };  };
   
 static const struct usbd_pipe_methods xhci_root_intr_methods = {  static const struct usbd_pipe_methods xhci_root_intr_methods = {
         .transfer = xhci_root_intr_transfer,          .upm_transfer = xhci_root_intr_transfer,
         .start = xhci_root_intr_start,          .upm_start = xhci_root_intr_start,
         .abort = xhci_root_intr_abort,          .upm_abort = xhci_root_intr_abort,
         .close = xhci_root_intr_close,          .upm_close = xhci_root_intr_close,
         .cleartoggle = xhci_noop,          .upm_cleartoggle = xhci_noop,
         .done = xhci_root_intr_done,          .upm_done = xhci_root_intr_done,
 };  };
   
   
 static const struct usbd_pipe_methods xhci_device_ctrl_methods = {  static const struct usbd_pipe_methods xhci_device_ctrl_methods = {
         .transfer = xhci_device_ctrl_transfer,          .upm_transfer = xhci_device_ctrl_transfer,
         .start = xhci_device_ctrl_start,          .upm_start = xhci_device_ctrl_start,
         .abort = xhci_device_ctrl_abort,          .upm_abort = xhci_device_ctrl_abort,
         .close = xhci_device_ctrl_close,          .upm_close = xhci_device_ctrl_close,
         .cleartoggle = xhci_noop,          .upm_cleartoggle = xhci_noop,
         .done = xhci_device_ctrl_done,          .upm_done = xhci_device_ctrl_done,
 };  };
   
 static const struct usbd_pipe_methods xhci_device_isoc_methods = {  static const struct usbd_pipe_methods xhci_device_isoc_methods = {
         .cleartoggle = xhci_noop,          .upm_cleartoggle = xhci_noop,
 };  };
   
 static const struct usbd_pipe_methods xhci_device_bulk_methods = {  static const struct usbd_pipe_methods xhci_device_bulk_methods = {
         .transfer = xhci_device_bulk_transfer,          .upm_transfer = xhci_device_bulk_transfer,
         .start = xhci_device_bulk_start,          .upm_start = xhci_device_bulk_start,
         .abort = xhci_device_bulk_abort,          .upm_abort = xhci_device_bulk_abort,
         .close = xhci_device_bulk_close,          .upm_close = xhci_device_bulk_close,
         .cleartoggle = xhci_noop,          .upm_cleartoggle = xhci_noop,
         .done = xhci_device_bulk_done,          .upm_done = xhci_device_bulk_done,
 };  };
   
 static const struct usbd_pipe_methods xhci_device_intr_methods = {  static const struct usbd_pipe_methods xhci_device_intr_methods = {
         .transfer = xhci_device_intr_transfer,          .upm_transfer = xhci_device_intr_transfer,
         .start = xhci_device_intr_start,          .upm_start = xhci_device_intr_start,
         .abort = xhci_device_intr_abort,          .upm_abort = xhci_device_intr_abort,
         .close = xhci_device_intr_close,          .upm_close = xhci_device_intr_close,
         .cleartoggle = xhci_noop,          .upm_cleartoggle = xhci_noop,
         .done = xhci_device_intr_done,          .upm_done = xhci_device_intr_done,
 };  };
   
 static inline uint32_t  static inline uint32_t
   xhci_read_1(const struct xhci_softc * const sc, bus_size_t offset)
   {
           return bus_space_read_1(sc->sc_iot, sc->sc_ioh, offset);
   }
   
   static inline uint32_t
 xhci_read_4(const struct xhci_softc * const sc, bus_size_t offset)  xhci_read_4(const struct xhci_softc * const sc, bus_size_t offset)
 {  {
         return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);          return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
 }  }
   
   static inline void
   xhci_write_1(const struct xhci_softc * const sc, bus_size_t offset,
       uint32_t value)
   {
           bus_space_write_1(sc->sc_iot, sc->sc_ioh, offset, value);
   }
   
 #if 0 /* unused */  #if 0 /* unused */
 static inline void  static inline void
 xhci_write_4(const struct xhci_softc * const sc, bus_size_t offset,  xhci_write_4(const struct xhci_softc * const sc, bus_size_t offset,
Line 279  xhci_op_write_4(const struct xhci_softc 
Line 298  xhci_op_write_4(const struct xhci_softc 
         bus_space_write_4(sc->sc_iot, sc->sc_obh, offset, value);          bus_space_write_4(sc->sc_iot, sc->sc_obh, offset, value);
 }  }
   
 #if 0 /* unused */  
 static inline uint64_t  static inline uint64_t
 xhci_op_read_8(const struct xhci_softc * const sc, bus_size_t offset)  xhci_op_read_8(const struct xhci_softc * const sc, bus_size_t offset)
 {  {
Line 299  xhci_op_read_8(const struct xhci_softc *
Line 317  xhci_op_read_8(const struct xhci_softc *
   
         return value;          return value;
 }  }
 #endif /* unused */  
   
 static inline void  static inline void
 xhci_op_write_8(const struct xhci_softc * const sc, bus_size_t offset,  xhci_op_write_8(const struct xhci_softc * const sc, bus_size_t offset,
Line 392  xhci_db_write_4(const struct xhci_softc 
Line 409  xhci_db_write_4(const struct xhci_softc 
 static inline uint8_t  static inline uint8_t
 xhci_ep_get_type(usb_endpoint_descriptor_t * const ed)  xhci_ep_get_type(usb_endpoint_descriptor_t * const ed)
 {  {
         u_int eptype;          u_int eptype = 0;
   
         switch (UE_GET_XFERTYPE(ed->bmAttributes)) {          switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
         case UE_CONTROL:          case UE_CONTROL:
Line 482  static inline void
Line 499  static inline void
 xhci_trb_put(struct xhci_trb * const trb, uint64_t parameter, uint32_t status,  xhci_trb_put(struct xhci_trb * const trb, uint64_t parameter, uint32_t status,
     uint32_t control)      uint32_t control)
 {  {
         trb->trb_0 = parameter;          trb->trb_0 = htole64(parameter);
         trb->trb_2 = status;          trb->trb_2 = htole32(status);
         trb->trb_3 = control;          trb->trb_3 = htole32(control);
   }
   
   static int
   xhci_trb_get_idx(struct xhci_ring *xr, uint64_t trb_0, int *idx)
   {
           /* base address of TRBs */
           bus_addr_t trbp = xhci_ring_trbp(xr, 0);
   
           /* trb_0 range sanity check */
           if (trb_0 == 0 || trb_0 < trbp ||
               (trb_0 - trbp) % sizeof(struct xhci_trb) != 0 ||
               (trb_0 - trbp) / sizeof(struct xhci_trb) >= xr->xr_ntrb) {
                   return 1;
           }
           *idx = (trb_0 - trbp) / sizeof(struct xhci_trb);
           return 0;
   }
   
   static unsigned int
   xhci_get_epstate(struct xhci_softc * const sc, struct xhci_slot * const xs,
       u_int dci)
   {
           uint32_t *cp;
   
           usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
           cp = xhci_slot_get_dcv(sc, xs, dci);
           return XHCI_EPCTX_0_EPSTATE_GET(le32toh(cp[0]));
 }  }
   
 /* --- */  /* --- */
Line 508  xhci_detach(struct xhci_softc *sc, int f
Line 552  xhci_detach(struct xhci_softc *sc, int f
                 rv = config_detach(sc->sc_child, flags);                  rv = config_detach(sc->sc_child, flags);
   
         if (rv != 0)          if (rv != 0)
                 return (rv);                  return rv;
   
         /* XXX unconfigure/free slots */          /* XXX unconfigure/free slots */
   
Line 520  xhci_detach(struct xhci_softc *sc, int f
Line 564  xhci_detach(struct xhci_softc *sc, int f
         xhci_op_write_8(sc, XHCI_CRCR, 0);          xhci_op_write_8(sc, XHCI_CRCR, 0);
         xhci_ring_free(sc, &sc->sc_cr);          xhci_ring_free(sc, &sc->sc_cr);
         cv_destroy(&sc->sc_command_cv);          cv_destroy(&sc->sc_command_cv);
           cv_destroy(&sc->sc_cmdbusy_cv);
   
         xhci_rt_write_4(sc, XHCI_ERSTSZ(0), 0);          xhci_rt_write_4(sc, XHCI_ERSTSZ(0), 0);
         xhci_rt_write_8(sc, XHCI_ERSTBA(0), 0);          xhci_rt_write_8(sc, XHCI_ERSTBA(0), 0);
Line 573  xhci_shutdown(device_t self, int flags)
Line 618  xhci_shutdown(device_t self, int flags)
         return false;          return false;
 }  }
   
   static int
   xhci_hc_reset(struct xhci_softc * const sc)
   {
           uint32_t usbcmd, usbsts;
           int i;
   
           /* Check controller not ready */
           for (i = 0; i < XHCI_WAIT_CNR; i++) {
                   usbsts = xhci_op_read_4(sc, XHCI_USBSTS);
                   if ((usbsts & XHCI_STS_CNR) == 0)
                           break;
                   usb_delay_ms(&sc->sc_bus, 1);
           }
           if (i >= XHCI_WAIT_CNR) {
                   aprint_error_dev(sc->sc_dev, "controller not ready timeout\n");
                   return EIO;
           }
   
           /* Halt controller */
           usbcmd = 0;
           xhci_op_write_4(sc, XHCI_USBCMD, usbcmd);
           usb_delay_ms(&sc->sc_bus, 1);
   
           /* Reset controller */
           usbcmd = XHCI_CMD_HCRST;
           xhci_op_write_4(sc, XHCI_USBCMD, usbcmd);
           for (i = 0; i < XHCI_WAIT_HCRST; i++) {
                   usbcmd = xhci_op_read_4(sc, XHCI_USBCMD);
                   if ((usbcmd & XHCI_CMD_HCRST) == 0)
                           break;
                   usb_delay_ms(&sc->sc_bus, 1);
           }
           if (i >= XHCI_WAIT_HCRST) {
                   aprint_error_dev(sc->sc_dev, "host controller reset timeout\n");
                   return EIO;
           }
   
           /* Check controller not ready */
           for (i = 0; i < XHCI_WAIT_CNR; i++) {
                   usbsts = xhci_op_read_4(sc, XHCI_USBSTS);
                   if ((usbsts & XHCI_STS_CNR) == 0)
                           break;
                   usb_delay_ms(&sc->sc_bus, 1);
           }
           if (i >= XHCI_WAIT_CNR) {
                   aprint_error_dev(sc->sc_dev,
                       "controller not ready timeout after reset\n");
                   return EIO;
           }
   
           return 0;
   }
   
   
 static void  static void
 hexdump(const char *msg, const void *base, size_t len)  hexdump(const char *msg, const void *base, size_t len)
Line 598  hexdump(const char *msg, const void *bas
Line 696  hexdump(const char *msg, const void *bas
                 if (cnt % 16 == 0)                  if (cnt % 16 == 0)
                         printf("\n");                          printf("\n");
         }          }
           if (cnt % 16 != 0)
                   printf("\n");
 #endif  #endif
 }  }
   
   /* Process extended capabilities */
   static void
   xhci_ecp(struct xhci_softc *sc, uint32_t hcc)
   {
           uint32_t ecp, ecr;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           ecp = XHCI_HCC_XECP(hcc) * 4;
           while (ecp != 0) {
                   ecr = xhci_read_4(sc, ecp);
                   aprint_debug_dev(sc->sc_dev, "ECR %x: %08x\n", ecp, ecr);
                   switch (XHCI_XECP_ID(ecr)) {
                   case XHCI_ID_PROTOCOLS: {
                           uint32_t w4, w8, wc;
                           uint16_t w2;
                           w2 = (ecr >> 16) & 0xffff;
                           w4 = xhci_read_4(sc, ecp + 4);
                           w8 = xhci_read_4(sc, ecp + 8);
                           wc = xhci_read_4(sc, ecp + 0xc);
                           aprint_debug_dev(sc->sc_dev,
                               " SP: %08x %08x %08x %08x\n", ecr, w4, w8, wc);
                           /* unused */
                           if (w4 == 0x20425355 && (w2 & 0xff00) == 0x0300) {
                                   sc->sc_ss_port_start = (w8 >> 0) & 0xff;;
                                   sc->sc_ss_port_count = (w8 >> 8) & 0xff;;
                           }
                           if (w4 == 0x20425355 && (w2 & 0xff00) == 0x0200) {
                                   sc->sc_hs_port_start = (w8 >> 0) & 0xff;
                                   sc->sc_hs_port_count = (w8 >> 8) & 0xff;
                           }
                           break;
                   }
                   case XHCI_ID_USB_LEGACY: {
                           uint8_t bios_sem;
   
                           /* Take host controller ownership from BIOS */
                           bios_sem = xhci_read_1(sc, ecp + XHCI_XECP_BIOS_SEM);
                           if (bios_sem) {
                                   /* sets xHCI to be owned by OS */
                                   xhci_write_1(sc, ecp + XHCI_XECP_OS_SEM, 1);
                                   aprint_debug_dev(sc->sc_dev,
                                       "waiting for BIOS to give up control\n");
                                   for (int i = 0; i < 5000; i++) {
                                           bios_sem = xhci_read_1(sc, ecp +
                                               XHCI_XECP_BIOS_SEM);
                                           if (bios_sem == 0)
                                                   break;
                                           DELAY(1000);
                                   }
                                   if (bios_sem) {
                                           aprint_error_dev(sc->sc_dev,
                                               "timed out waiting for BIOS\n");
                                   }
                           }
                           break;
                   }
                   default:
                           break;
                   }
                   ecr = xhci_read_4(sc, ecp);
                   if (XHCI_XECP_NEXT(ecr) == 0) {
                           ecp = 0;
                   } else {
                           ecp += XHCI_XECP_NEXT(ecr) * 4;
                   }
           }
   }
   
   #define XHCI_HCCPREV1_BITS      \
           "\177\020"      /* New bitmask */                       \
           "f\020\020XECP\0"                                       \
           "f\014\4MAXPSA\0"                                       \
           "b\013CFC\0"                                            \
           "b\012SEC\0"                                            \
           "b\011SBD\0"                                            \
           "b\010FSE\0"                                            \
           "b\7NSS\0"                                              \
           "b\6LTC\0"                                              \
           "b\5LHRC\0"                                             \
           "b\4PIND\0"                                             \
           "b\3PPC\0"                                              \
           "b\2CZC\0"                                              \
           "b\1BNC\0"                                              \
           "b\0AC64\0"                                             \
           "\0"
   #define XHCI_HCCV1_x_BITS       \
           "\177\020"      /* New bitmask */                       \
           "f\020\020XECP\0"                                       \
           "f\014\4MAXPSA\0"                                       \
           "b\013CFC\0"                                            \
           "b\012SEC\0"                                            \
           "b\011SPC\0"                                            \
           "b\010PAE\0"                                            \
           "b\7NSS\0"                                              \
           "b\6LTC\0"                                              \
           "b\5LHRC\0"                                             \
           "b\4PIND\0"                                             \
           "b\3PPC\0"                                              \
           "b\2CSZ\0"                                              \
           "b\1BNC\0"                                              \
           "b\0AC64\0"                                             \
           "\0"
   
 int  int
 xhci_init(struct xhci_softc *sc)  xhci_init(struct xhci_softc *sc)
 {  {
         bus_size_t bsz;          bus_size_t bsz;
         uint32_t cap, hcs1, hcs2, hcc, dboff, rtsoff;          uint32_t cap, hcs1, hcs2, hcs3, hcc, dboff, rtsoff;
         uint32_t ecp, ecr;          uint32_t pagesize, config;
         uint32_t usbcmd, usbsts, pagesize, config;          int i = 0;
         int i;  
         uint16_t hciversion;          uint16_t hciversion;
         uint8_t caplength;          uint8_t caplength;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         /* XXX Low/Full/High speeds for now */          sc->sc_bus.ub_revision = USBREV_3_0;
         sc->sc_bus.usbrev = USBREV_2_0;          sc->sc_bus.ub_usedma = true;
   
         cap = xhci_read_4(sc, XHCI_CAPLENGTH);          cap = xhci_read_4(sc, XHCI_CAPLENGTH);
         caplength = XHCI_CAP_CAPLENGTH(cap);          caplength = XHCI_CAP_CAPLENGTH(cap);
         hciversion = XHCI_CAP_HCIVERSION(cap);          hciversion = XHCI_CAP_HCIVERSION(cap);
   
         if ((hciversion < 0x0096) || (hciversion > 0x0100)) {          if (hciversion < XHCI_HCIVERSION_0_96 ||
               hciversion > XHCI_HCIVERSION_1_0) {
                 aprint_normal_dev(sc->sc_dev,                  aprint_normal_dev(sc->sc_dev,
                     "xHCI version %x.%x not known to be supported\n",                      "xHCI version %x.%x not known to be supported\n",
                     (hciversion >> 8) & 0xff, (hciversion >> 0) & 0xff);                      (hciversion >> 8) & 0xff, (hciversion >> 0) & 0xff);
Line 642  xhci_init(struct xhci_softc *sc)
Line 845  xhci_init(struct xhci_softc *sc)
         sc->sc_maxintrs = XHCI_HCS1_MAXINTRS(hcs1);          sc->sc_maxintrs = XHCI_HCS1_MAXINTRS(hcs1);
         sc->sc_maxports = XHCI_HCS1_MAXPORTS(hcs1);          sc->sc_maxports = XHCI_HCS1_MAXPORTS(hcs1);
         hcs2 = xhci_cap_read_4(sc, XHCI_HCSPARAMS2);          hcs2 = xhci_cap_read_4(sc, XHCI_HCSPARAMS2);
         (void)xhci_cap_read_4(sc, XHCI_HCSPARAMS3);          hcs3 = xhci_cap_read_4(sc, XHCI_HCSPARAMS3);
         hcc = xhci_cap_read_4(sc, XHCI_HCCPARAMS);          aprint_debug_dev(sc->sc_dev,
               "hcs1=%"PRIx32" hcs2=%"PRIx32" hcs3=%"PRIx32"\n", hcs1, hcs2, hcs3);
   
           hcc = xhci_cap_read_4(sc, XHCI_HCCPARAMS);
         sc->sc_ac64 = XHCI_HCC_AC64(hcc);          sc->sc_ac64 = XHCI_HCC_AC64(hcc);
         sc->sc_ctxsz = XHCI_HCC_CSZ(hcc) ? 64 : 32;          sc->sc_ctxsz = XHCI_HCC_CSZ(hcc) ? 64 : 32;
         aprint_debug_dev(sc->sc_dev, "ac64 %d ctxsz %d\n", sc->sc_ac64,  
             sc->sc_ctxsz);  
   
           char sbuf[128];
           if (hciversion < XHCI_HCIVERSION_1_0)
                   snprintb(sbuf, sizeof(sbuf), XHCI_HCCPREV1_BITS, hcc);
           else
                   snprintb(sbuf, sizeof(sbuf), XHCI_HCCV1_x_BITS, hcc);
           aprint_debug_dev(sc->sc_dev, "hcc=%s\n", sbuf);
         aprint_debug_dev(sc->sc_dev, "xECP %x\n", XHCI_HCC_XECP(hcc) * 4);          aprint_debug_dev(sc->sc_dev, "xECP %x\n", XHCI_HCC_XECP(hcc) * 4);
         ecp = XHCI_HCC_XECP(hcc) * 4;  
         while (ecp != 0) {          /* print PSI and take ownership from BIOS */
                 ecr = xhci_read_4(sc, ecp);          xhci_ecp(sc, hcc);
                 aprint_debug_dev(sc->sc_dev, "ECR %x: %08x\n", ecp, ecr);  
                 switch (XHCI_XECP_ID(ecr)) {  
                 case XHCI_ID_PROTOCOLS: {  
                         uint32_t w0, w4, w8;  
                         uint16_t w2;  
                         w0 = xhci_read_4(sc, ecp + 0);  
                         w2 = (w0 >> 16) & 0xffff;  
                         w4 = xhci_read_4(sc, ecp + 4);  
                         w8 = xhci_read_4(sc, ecp + 8);  
                         aprint_debug_dev(sc->sc_dev, "SP: %08x %08x %08x\n",  
                             w0, w4, w8);  
                         if (w4 == 0x20425355 && w2 == 0x0300) {  
                                 sc->sc_ss_port_start = (w8 >> 0) & 0xff;;  
                                 sc->sc_ss_port_count = (w8 >> 8) & 0xff;;  
                         }  
                         if (w4 == 0x20425355 && w2 == 0x0200) {  
                                 sc->sc_hs_port_start = (w8 >> 0) & 0xff;  
                                 sc->sc_hs_port_count = (w8 >> 8) & 0xff;  
                         }  
                         break;  
                 }  
                 default:  
                         break;  
                 }  
                 ecr = xhci_read_4(sc, ecp);  
                 if (XHCI_XECP_NEXT(ecr) == 0) {  
                         ecp = 0;  
                 } else {  
                         ecp += XHCI_XECP_NEXT(ecr) * 4;  
                 }  
         }  
   
         bsz = XHCI_PORTSC(sc->sc_maxports + 1);          bsz = XHCI_PORTSC(sc->sc_maxports + 1);
         if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, caplength, bsz,          if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, caplength, bsz,
Line 707  xhci_init(struct xhci_softc *sc)
Line 885  xhci_init(struct xhci_softc *sc)
                 return ENOMEM;                  return ENOMEM;
         }          }
   
         for (i = 0; i < 100; i++) {          int rv;
                 usbsts = xhci_op_read_4(sc, XHCI_USBSTS);          rv = xhci_hc_reset(sc);
                 if ((usbsts & XHCI_STS_CNR) == 0)          if (rv != 0) {
                         break;                  return rv;
                 usb_delay_ms(&sc->sc_bus, 1);  
         }  
         if (i >= 100)  
                 return EIO;  
   
         usbcmd = 0;  
         xhci_op_write_4(sc, XHCI_USBCMD, usbcmd);  
         usb_delay_ms(&sc->sc_bus, 1);  
   
         usbcmd = XHCI_CMD_HCRST;  
         xhci_op_write_4(sc, XHCI_USBCMD, usbcmd);  
         for (i = 0; i < 100; i++) {  
                 usbcmd = xhci_op_read_4(sc, XHCI_USBCMD);  
                 if ((usbcmd & XHCI_CMD_HCRST) == 0)  
                         break;  
                 usb_delay_ms(&sc->sc_bus, 1);  
         }          }
         if (i >= 100)  
                 return EIO;  
   
         for (i = 0; i < 100; i++) {          if (sc->sc_vendor_init)
                 usbsts = xhci_op_read_4(sc, XHCI_USBSTS);                  sc->sc_vendor_init(sc);
                 if ((usbsts & XHCI_STS_CNR) == 0)  
                         break;  
                 usb_delay_ms(&sc->sc_bus, 1);  
         }  
         if (i >= 100)  
                 return EIO;  
   
         pagesize = xhci_op_read_4(sc, XHCI_PAGESIZE);          pagesize = xhci_op_read_4(sc, XHCI_PAGESIZE);
         aprint_debug_dev(sc->sc_dev, "PAGESIZE 0x%08x\n", pagesize);          aprint_debug_dev(sc->sc_dev, "PAGESIZE 0x%08x\n", pagesize);
         pagesize = ffs(pagesize);          pagesize = ffs(pagesize);
         if (pagesize == 0)          if (pagesize == 0) {
                   aprint_error_dev(sc->sc_dev, "pagesize is 0\n");
                 return EIO;                  return EIO;
           }
         sc->sc_pgsz = 1 << (12 + (pagesize - 1));          sc->sc_pgsz = 1 << (12 + (pagesize - 1));
         aprint_debug_dev(sc->sc_dev, "sc_pgsz 0x%08x\n", (uint32_t)sc->sc_pgsz);          aprint_debug_dev(sc->sc_dev, "sc_pgsz 0x%08x\n", (uint32_t)sc->sc_pgsz);
         aprint_debug_dev(sc->sc_dev, "sc_maxslots 0x%08x\n",          aprint_debug_dev(sc->sc_dev, "sc_maxslots 0x%08x\n",
             (uint32_t)sc->sc_maxslots);              (uint32_t)sc->sc_maxslots);
           aprint_debug_dev(sc->sc_dev, "sc_maxports %d\n", sc->sc_maxports);
   
         usbd_status err;          usbd_status err;
   
Line 758  xhci_init(struct xhci_softc *sc)
Line 915  xhci_init(struct xhci_softc *sc)
                 err = usb_allocmem(&sc->sc_bus,                  err = usb_allocmem(&sc->sc_bus,
                     sizeof(uint64_t) * sc->sc_maxspbuf, sizeof(uint64_t),                      sizeof(uint64_t) * sc->sc_maxspbuf, sizeof(uint64_t),
                     &sc->sc_spbufarray_dma);                      &sc->sc_spbufarray_dma);
                 if (err)                  if (err) {
                         return err;                          aprint_error_dev(sc->sc_dev,
                               "spbufarray init fail, err %d\n", err);
                 sc->sc_spbuf_dma = kmem_zalloc(sizeof(*sc->sc_spbuf_dma) * sc->sc_maxspbuf, KM_SLEEP);                          return ENOMEM;
                   }
   
                   sc->sc_spbuf_dma = kmem_zalloc(sizeof(*sc->sc_spbuf_dma) *
                       sc->sc_maxspbuf, KM_SLEEP);
                 uint64_t *spbufarray = KERNADDR(&sc->sc_spbufarray_dma, 0);                  uint64_t *spbufarray = KERNADDR(&sc->sc_spbufarray_dma, 0);
                 for (i = 0; i < sc->sc_maxspbuf; i++) {                  for (i = 0; i < sc->sc_maxspbuf; i++) {
                         usb_dma_t * const dma = &sc->sc_spbuf_dma[i];                          usb_dma_t * const dma = &sc->sc_spbuf_dma[i];
                         /* allocate contexts */                          /* allocate contexts */
                         err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz,                          err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz,
                             sc->sc_pgsz, dma);                              sc->sc_pgsz, dma);
                         if (err)                          if (err) {
                                 return err;                                  aprint_error_dev(sc->sc_dev,
                                       "spbufarray_dma init fail, err %d\n", err);
                                   rv = ENOMEM;
                                   goto bad1;
                           }
                         spbufarray[i] = htole64(DMAADDR(dma, 0));                          spbufarray[i] = htole64(DMAADDR(dma, 0));
                         usb_syncmem(dma, 0, sc->sc_pgsz,                          usb_syncmem(dma, 0, sc->sc_pgsz,
                             BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);                              BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
                 }                  }
   
                 usb_syncmem(&sc->sc_spbufarray_dma, 0,                  usb_syncmem(&sc->sc_spbufarray_dma, 0,
                     sizeof(uint64_t) * sc->sc_maxspbuf, BUS_DMASYNC_PREWRITE);                      sizeof(uint64_t) * sc->sc_maxspbuf, BUS_DMASYNC_PREWRITE);
         }          }
   
Line 787  xhci_init(struct xhci_softc *sc)
Line 952  xhci_init(struct xhci_softc *sc)
         err = xhci_ring_init(sc, &sc->sc_cr, XHCI_COMMAND_RING_TRBS,          err = xhci_ring_init(sc, &sc->sc_cr, XHCI_COMMAND_RING_TRBS,
             XHCI_COMMAND_RING_SEGMENTS_ALIGN);              XHCI_COMMAND_RING_SEGMENTS_ALIGN);
         if (err) {          if (err) {
                 aprint_error_dev(sc->sc_dev, "command ring init fail\n");                  aprint_error_dev(sc->sc_dev, "command ring init fail, err %d\n",
                 return err;                      err);
                   rv = ENOMEM;
                   goto bad1;
         }          }
   
         err = xhci_ring_init(sc, &sc->sc_er, XHCI_EVENT_RING_TRBS,          err = xhci_ring_init(sc, &sc->sc_er, XHCI_EVENT_RING_TRBS,
             XHCI_EVENT_RING_SEGMENTS_ALIGN);              XHCI_EVENT_RING_SEGMENTS_ALIGN);
         if (err) {          if (err) {
                 aprint_error_dev(sc->sc_dev, "event ring init fail\n");                  aprint_error_dev(sc->sc_dev, "event ring init fail, err %d\n",
                 return err;                      err);
                   rv = ENOMEM;
                   goto bad2;
         }          }
   
         usb_dma_t *dma;          usb_dma_t *dma;
Line 805  xhci_init(struct xhci_softc *sc)
Line 974  xhci_init(struct xhci_softc *sc)
         dma = &sc->sc_eventst_dma;          dma = &sc->sc_eventst_dma;
         size = roundup2(XHCI_EVENT_RING_SEGMENTS * XHCI_ERSTE_SIZE,          size = roundup2(XHCI_EVENT_RING_SEGMENTS * XHCI_ERSTE_SIZE,
             XHCI_EVENT_RING_SEGMENT_TABLE_ALIGN);              XHCI_EVENT_RING_SEGMENT_TABLE_ALIGN);
         KASSERT(size <= (512 * 1024));          KASSERTMSG(size <= (512 * 1024), "eventst size %zu too large", size);
         align = XHCI_EVENT_RING_SEGMENT_TABLE_ALIGN;          align = XHCI_EVENT_RING_SEGMENT_TABLE_ALIGN;
         err = usb_allocmem(&sc->sc_bus, size, align, dma);          err = usb_allocmem(&sc->sc_bus, size, align, dma);
           if (err) {
                   aprint_error_dev(sc->sc_dev, "eventst init fail, err %d\n",
                       err);
                   rv = ENOMEM;
                   goto bad3;
           }
   
         memset(KERNADDR(dma, 0), 0, size);          memset(KERNADDR(dma, 0), 0, size);
         usb_syncmem(dma, 0, size, BUS_DMASYNC_PREWRITE);          usb_syncmem(dma, 0, size, BUS_DMASYNC_PREWRITE);
         aprint_debug_dev(sc->sc_dev, "eventst: %s %016jx %p %zx\n",          aprint_debug_dev(sc->sc_dev, "eventst: %016jx %p %zx\n",
             usbd_errstr(err),  
             (uintmax_t)DMAADDR(&sc->sc_eventst_dma, 0),              (uintmax_t)DMAADDR(&sc->sc_eventst_dma, 0),
             KERNADDR(&sc->sc_eventst_dma, 0),              KERNADDR(&sc->sc_eventst_dma, 0),
             sc->sc_eventst_dma.block->size);              sc->sc_eventst_dma.udma_block->size);
   
         dma = &sc->sc_dcbaa_dma;          dma = &sc->sc_dcbaa_dma;
         size = (1 + sc->sc_maxslots) * sizeof(uint64_t);          size = (1 + sc->sc_maxslots) * sizeof(uint64_t);
         KASSERT(size <= 2048);          KASSERTMSG(size <= 2048, "dcbaa size %zu too large", size);
         align = XHCI_DEVICE_CONTEXT_BASE_ADDRESS_ARRAY_ALIGN;          align = XHCI_DEVICE_CONTEXT_BASE_ADDRESS_ARRAY_ALIGN;
         err = usb_allocmem(&sc->sc_bus, size, align, dma);          err = usb_allocmem(&sc->sc_bus, size, align, dma);
           if (err) {
                   aprint_error_dev(sc->sc_dev, "dcbaa init fail, err %d\n", err);
                   rv = ENOMEM;
                   goto bad4;
           }
           aprint_debug_dev(sc->sc_dev, "dcbaa: %016jx %p %zx\n",
               (uintmax_t)DMAADDR(&sc->sc_dcbaa_dma, 0),
               KERNADDR(&sc->sc_dcbaa_dma, 0),
               sc->sc_dcbaa_dma.udma_block->size);
   
         memset(KERNADDR(dma, 0), 0, size);          memset(KERNADDR(dma, 0), 0, size);
         if (sc->sc_maxspbuf != 0) {          if (sc->sc_maxspbuf != 0) {
Line 832  xhci_init(struct xhci_softc *sc)
Line 1015  xhci_init(struct xhci_softc *sc)
                     htole64(DMAADDR(&sc->sc_spbufarray_dma, 0));                      htole64(DMAADDR(&sc->sc_spbufarray_dma, 0));
         }          }
         usb_syncmem(dma, 0, size, BUS_DMASYNC_PREWRITE);          usb_syncmem(dma, 0, size, BUS_DMASYNC_PREWRITE);
         aprint_debug_dev(sc->sc_dev, "dcbaa: %s %016jx %p %zx\n",  
             usbd_errstr(err),  
             (uintmax_t)DMAADDR(&sc->sc_dcbaa_dma, 0),  
             KERNADDR(&sc->sc_dcbaa_dma, 0),  
             sc->sc_dcbaa_dma.block->size);  
   
         sc->sc_slots = kmem_zalloc(sizeof(*sc->sc_slots) * sc->sc_maxslots,          sc->sc_slots = kmem_zalloc(sizeof(*sc->sc_slots) * sc->sc_maxslots,
             KM_SLEEP);              KM_SLEEP);
           if (sc->sc_slots == NULL) {
                   aprint_error_dev(sc->sc_dev, "slots init fail, err %d\n", err);
                   rv = ENOMEM;
                   goto bad;
           }
   
           sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,
               "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
           if (sc->sc_xferpool == NULL) {
                   aprint_error_dev(sc->sc_dev, "pool_cache init fail, err %d\n",
                       err);
                   rv = ENOMEM;
                   goto bad;
           }
   
         cv_init(&sc->sc_command_cv, "xhcicmd");          cv_init(&sc->sc_command_cv, "xhcicmd");
           cv_init(&sc->sc_cmdbusy_cv, "xhcicmdq");
           mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
           mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
   
           /* Set up the bus struct. */
           sc->sc_bus.ub_methods = &xhci_bus_methods;
           sc->sc_bus.ub_pipesize = sizeof(struct xhci_pipe);
   
         struct xhci_erste *erst;          struct xhci_erste *erst;
         erst = KERNADDR(&sc->sc_eventst_dma, 0);          erst = KERNADDR(&sc->sc_eventst_dma, 0);
         erst[0].erste_0 = htole64(xhci_ring_trbp(&sc->sc_er, 0));          erst[0].erste_0 = htole64(xhci_ring_trbp(&sc->sc_er, 0));
         erst[0].erste_2 = htole32(XHCI_EVENT_RING_TRBS);          erst[0].erste_2 = htole32(sc->sc_er.xr_ntrb);
         erst[0].erste_3 = htole32(0);          erst[0].erste_3 = htole32(0);
         usb_syncmem(&sc->sc_eventst_dma, 0,          usb_syncmem(&sc->sc_eventst_dma, 0,
             XHCI_ERSTE_SIZE * XHCI_EVENT_RING_SEGMENTS, BUS_DMASYNC_PREWRITE);              XHCI_ERSTE_SIZE * XHCI_EVENT_RING_SEGMENTS, BUS_DMASYNC_PREWRITE);
Line 865  xhci_init(struct xhci_softc *sc)
Line 1064  xhci_init(struct xhci_softc *sc)
 #endif  #endif
   
         xhci_rt_write_4(sc, XHCI_IMAN(0), XHCI_IMAN_INTR_ENA);          xhci_rt_write_4(sc, XHCI_IMAN(0), XHCI_IMAN_INTR_ENA);
         xhci_rt_write_4(sc, XHCI_IMOD(0), 0);          if ((sc->sc_quirks & XHCI_QUIRK_INTEL) != 0)
                   /* Intel xhci needs interrupt rate moderated. */
                   xhci_rt_write_4(sc, XHCI_IMOD(0), XHCI_IMOD_DEFAULT_LP);
           else
                   xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
           aprint_debug_dev(sc->sc_dev, "current IMOD %u\n",
               xhci_rt_read_4(sc, XHCI_IMOD(0)));
   
         xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */          xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
         aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",          aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
             xhci_op_read_4(sc, XHCI_USBCMD));              xhci_op_read_4(sc, XHCI_USBCMD));
   
         mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);          return 0;
         mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);  
         cv_init(&sc->sc_softwake_cv, "xhciab");  
   
         sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,   bad:
             "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);          if (sc->sc_xferpool) {
                   pool_cache_destroy(sc->sc_xferpool);
                   sc->sc_xferpool = NULL;
           }
   
         /* Set up the bus struct. */          if (sc->sc_slots) {
         sc->sc_bus.methods = &xhci_bus_methods;                  kmem_free(sc->sc_slots, sizeof(*sc->sc_slots) *
         sc->sc_bus.pipe_size = sizeof(struct xhci_pipe);                      sc->sc_maxslots);
                   sc->sc_slots = NULL;
           }
   
         return USBD_NORMAL_COMPLETION;          usb_freemem(&sc->sc_bus, &sc->sc_dcbaa_dma);
    bad4:
           usb_freemem(&sc->sc_bus, &sc->sc_eventst_dma);
    bad3:
           xhci_ring_free(sc, &sc->sc_er);
    bad2:
           xhci_ring_free(sc, &sc->sc_cr);
           i = sc->sc_maxspbuf;
    bad1:
           for (int j = 0; j < i; j++)
                   usb_freemem(&sc->sc_bus, &sc->sc_spbuf_dma[j]);
           usb_freemem(&sc->sc_bus, &sc->sc_spbufarray_dma);
   
           return rv;
 }  }
   
 int  int
Line 902  xhci_intr(void *v)
Line 1123  xhci_intr(void *v)
                 goto done;                  goto done;
   
         /* If we get an interrupt while polling, then just ignore it. */          /* If we get an interrupt while polling, then just ignore it. */
         if (sc->sc_bus.use_polling) {          if (sc->sc_bus.ub_usepolling) {
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 DPRINTFN(16, "ignored interrupt while polling", 0, 0, 0, 0);                  DPRINTFN(16, "ignored interrupt while polling", 0, 0, 0, 0);
 #endif  #endif
Line 937  xhci_intr1(struct xhci_softc * const sc)
Line 1158  xhci_intr1(struct xhci_softc * const sc)
   
         iman = xhci_rt_read_4(sc, XHCI_IMAN(0));          iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
         DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);          DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);
         if ((iman & XHCI_IMAN_INTR_PEND) == 0) {          iman |= XHCI_IMAN_INTR_PEND;
                 return 0;  
         }  
         xhci_rt_write_4(sc, XHCI_IMAN(0), iman);          xhci_rt_write_4(sc, XHCI_IMAN(0), iman);
         iman = xhci_rt_read_4(sc, XHCI_IMAN(0));          iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
         DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);          DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);
         usbsts = xhci_op_read_4(sc, XHCI_USBSTS);          usbsts = xhci_op_read_4(sc, XHCI_USBSTS);
         DPRINTFN(16, "USBSTS %08x", usbsts, 0, 0, 0);          DPRINTFN(16, "USBSTS %08x", usbsts, 0, 0, 0);
   
         sc->sc_bus.no_intrs++;  
         usb_schedsoftintr(&sc->sc_bus);          usb_schedsoftintr(&sc->sc_bus);
   
         return 1;          return 1;
 }  }
   
   /*
    * 3 port speed types used in USB stack
    *
    * usbdi speed
    *      definition: USB_SPEED_* in usb.h
    *      They are used in struct usbd_device in USB stack.
    *      ioctl interface uses these values too.
    * port_status speed
    *      definition: UPS_*_SPEED in usb.h
    *      They are used in usb_port_status_t and valid only for USB 2.0.
    *      Speed value is always 0 for Super Speed or more, and dwExtPortStatus
    *      of usb_port_status_ext_t indicates port speed.
    *      Note that some 3.0 values overlap with 2.0 values.
    *      (e.g. 0x200 means UPS_POER_POWER_SS in SS and
    *                  means UPS_LOW_SPEED in HS.)
    *      port status returned from hub also uses these values.
    *      On NetBSD UPS_OTHER_SPEED indicates port speed is super speed
    *      or more.
    * xspeed:
    *      definition: Protocol Speed ID (PSI) (xHCI 1.1 7.2.1)
    *      They are used in only slot context and PORTSC reg of xhci.
    *      The difference between usbdi speed and xspeed is
    *      that FS and LS values are swapped.
    */
   
   /* convert usbdi speed to xspeed */
   static int
   xhci_speed2xspeed(int speed)
   {
           switch (speed) {
           case USB_SPEED_LOW:     return 2;
           case USB_SPEED_FULL:    return 1;
           default:                return speed;
           }
   }
   
   #if 0
   /* convert xspeed to usbdi speed */
   static int
   xhci_xspeed2speed(int xspeed)
   {
           switch (xspeed) {
           case 1: return USB_SPEED_FULL;
           case 2: return USB_SPEED_LOW;
           default: return xspeed;
           }
   }
   #endif
   
   /* convert xspeed to port status speed */
   static int
   xhci_xspeed2psspeed(int xspeed)
   {
           switch (xspeed) {
           case 0: return 0;
           case 1: return UPS_FULL_SPEED;
           case 2: return UPS_LOW_SPEED;
           case 3: return UPS_HIGH_SPEED;
           default: return UPS_OTHER_SPEED;
           }
   }
   
   /*
    * Construct input contexts and issue TRB to open pipe.
    */
 static usbd_status  static usbd_status
 xhci_configure_endpoint(usbd_pipe_handle pipe)  xhci_configure_endpoint(struct usbd_pipe *pipe)
 {  {
         struct xhci_softc * const sc = pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
         struct xhci_slot * const xs = pipe->device->hci_private;          struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
         usb_endpoint_descriptor_t * const ed = pipe->endpoint->edesc;  
         const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);  
         struct xhci_trb trb;          struct xhci_trb trb;
         usbd_status err;          usbd_status err;
         uint32_t *cp;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(4, "dci %u epaddr 0x%02x attr 0x%02x",          DPRINTFN(4, "slot %u dci %u epaddr 0x%02x attr 0x%02x",
             dci, ed->bEndpointAddress, ed->bmAttributes, 0);              xs->xs_idx, dci, pipe->up_endpoint->ue_edesc->bEndpointAddress,
               pipe->up_endpoint->ue_edesc->bmAttributes);
   
         /* XXX ensure input context is available? */          /* XXX ensure input context is available? */
   
         memset(xhci_slot_get_icv(sc, xs, 0), 0, sc->sc_pgsz);          memset(xhci_slot_get_icv(sc, xs, 0), 0, sc->sc_pgsz);
   
         cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);          /* set up context */
         cp[0] = htole32(0);          xhci_setup_ctx(pipe);
         cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(dci));  
   
         /* set up input slot context */  
         cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));  
         cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));  
         cp[1] = htole32(0);  
         cp[2] = htole32(0);  
         cp[3] = htole32(0);  
   
         cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));  
         if (xfertype == UE_INTERRUPT) {  
         cp[0] = htole32(  
             XHCI_EPCTX_0_IVAL_SET(3) /* XXX */  
             );  
         cp[1] = htole32(  
             XHCI_EPCTX_1_CERR_SET(3) |  
             XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(pipe->endpoint->edesc)) |  
             XHCI_EPCTX_1_MAXB_SET(0) |  
             XHCI_EPCTX_1_MAXP_SIZE_SET(8) /* XXX */  
             );  
         cp[4] = htole32(  
                 XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)  
                 );  
         } else {  
         cp[0] = htole32(0);  
         cp[1] = htole32(  
             XHCI_EPCTX_1_CERR_SET(3) |  
             XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(pipe->endpoint->edesc)) |  
             XHCI_EPCTX_1_MAXB_SET(0) |  
             XHCI_EPCTX_1_MAXP_SIZE_SET(512) /* XXX */  
             );  
         }  
         *(uint64_t *)(&cp[2]) = htole64(  
             xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |  
             XHCI_EPCTX_2_DCS_SET(1));  
   
         /* sync input contexts before they are read from memory */  
         usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);  
         hexdump("input control context", xhci_slot_get_icv(sc, xs, 0),          hexdump("input control context", xhci_slot_get_icv(sc, xs, 0),
             sc->sc_ctxsz * 1);              sc->sc_ctxsz * 1);
         hexdump("input endpoint context", xhci_slot_get_icv(sc, xs,          hexdump("input endpoint context", xhci_slot_get_icv(sc, xs,
Line 1031  xhci_configure_endpoint(usbd_pipe_handle
Line 1275  xhci_configure_endpoint(usbd_pipe_handle
         return err;          return err;
 }  }
   
   #if 0
 static usbd_status  static usbd_status
 xhci_unconfigure_endpoint(usbd_pipe_handle pipe)  xhci_unconfigure_endpoint(struct usbd_pipe *pipe)
 {  {
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         struct xhci_slot * const xs = pipe->device->hci_private;          struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
 #endif  #endif
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
Line 1043  xhci_unconfigure_endpoint(usbd_pipe_hand
Line 1288  xhci_unconfigure_endpoint(usbd_pipe_hand
   
         return USBD_NORMAL_COMPLETION;          return USBD_NORMAL_COMPLETION;
 }  }
   #endif
   
   /* 4.6.8, 6.4.3.7 */
 static usbd_status  static usbd_status
 xhci_reset_endpoint(usbd_pipe_handle pipe)  xhci_reset_endpoint_locked(struct usbd_pipe *pipe)
 {  {
         struct xhci_softc * const sc = pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
         struct xhci_slot * const xs = pipe->device->hci_private;          struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
         struct xhci_trb trb;          struct xhci_trb trb;
         usbd_status err;          usbd_status err;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(4, "dci %u", dci, 0, 0, 0);          DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         trb.trb_0 = 0;          trb.trb_0 = 0;
         trb.trb_2 = 0;          trb.trb_2 = 0;
Line 1062  xhci_reset_endpoint(usbd_pipe_handle pip
Line 1311  xhci_reset_endpoint(usbd_pipe_handle pip
             XHCI_TRB_3_EP_SET(dci) |              XHCI_TRB_3_EP_SET(dci) |
             XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP);              XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP);
   
         err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);          err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
   
         return err;          return err;
 }  }
   
 #if 0  
 static usbd_status  static usbd_status
 xhci_stop_endpoint(usbd_pipe_handle pipe)  xhci_reset_endpoint(struct usbd_pipe *pipe)
   {
           struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
   
           mutex_enter(&sc->sc_lock);
           usbd_status ret = xhci_reset_endpoint_locked(pipe);
           mutex_exit(&sc->sc_lock);
   
           return ret;
   }
   
   /*
    * 4.6.9, 6.4.3.8
    * Stop execution of TDs on xfer ring.
    * Should be called with sc_lock held.
    */
   static usbd_status
   xhci_stop_endpoint(struct usbd_pipe *pipe)
 {  {
         struct xhci_softc * const sc = pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
         struct xhci_slot * const xs = pipe->device->hci_private;          struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
         struct xhci_trb trb;          struct xhci_trb trb;
         usbd_status err;          usbd_status err;
         const u_int dci = xhci_ep_get_dci(pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(4, "dci %u", dci, 0, 0, 0);          DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
   
         trb.trb_0 = 0;          KASSERT(mutex_owned(&sc->sc_lock));
   
           trb.trb_0 = 0;
         trb.trb_2 = 0;          trb.trb_2 = 0;
         trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |          trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
             XHCI_TRB_3_EP_SET(dci) |              XHCI_TRB_3_EP_SET(dci) |
             XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP);              XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP);
   
         err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);          err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
   
         return err;          return err;
 }  }
 #endif  
   
   /*
    * Set TR Dequeue Pointer.
    * xHCI 1.1  4.6.10  6.4.3.9
    * Purge all of the TRBs on ring and reinitialize ring.
    * Set TR dequeue Pointr to 0 and Cycle State to 1.
    * EPSTATE of endpoint must be ERROR or STOPPED, otherwise CONTEXT_STATE
    * error will be generated.
    */
 static usbd_status  static usbd_status
 xhci_set_dequeue(usbd_pipe_handle pipe)  xhci_set_dequeue_locked(struct usbd_pipe *pipe)
 {  {
         struct xhci_softc * const sc = pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
         struct xhci_slot * const xs = pipe->device->hci_private;          struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
         struct xhci_ring * const xr = &xs->xs_ep[dci].xe_tr;          struct xhci_ring * const xr = &xs->xs_ep[dci].xe_tr;
         struct xhci_trb trb;          struct xhci_trb trb;
         usbd_status err;          usbd_status err;
Line 1105  xhci_set_dequeue(usbd_pipe_handle pipe)
Line 1379  xhci_set_dequeue(usbd_pipe_handle pipe)
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);          DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
   
         memset(xr->xr_trb, 0, xr->xr_ntrb * XHCI_TRB_SIZE);          KASSERT(mutex_owned(&sc->sc_lock));
         usb_syncmem(&xr->xr_dma, 0, xr->xr_ntrb * XHCI_TRB_SIZE,  
             BUS_DMASYNC_PREWRITE);  
   
         xr->xr_ep = 0;          xhci_host_dequeue(xr);
         xr->xr_cs = 1;  
   
           /* set DCS */
         trb.trb_0 = xhci_ring_trbp(xr, 0) | 1; /* XXX */          trb.trb_0 = xhci_ring_trbp(xr, 0) | 1; /* XXX */
         trb.trb_2 = 0;          trb.trb_2 = 0;
         trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |          trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
             XHCI_TRB_3_EP_SET(dci) |              XHCI_TRB_3_EP_SET(dci) |
             XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE);              XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE);
   
         err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);          err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
   
         return err;          return err;
 }  }
   
 static usbd_status  static usbd_status
 xhci_open(usbd_pipe_handle pipe)  xhci_set_dequeue(struct usbd_pipe *pipe)
 {  {
         usbd_device_handle const dev = pipe->device;          struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
         struct xhci_softc * const sc = dev->bus->hci_private;  
         usb_endpoint_descriptor_t * const ed = pipe->endpoint->edesc;          mutex_enter(&sc->sc_lock);
           usbd_status ret = xhci_set_dequeue_locked(pipe);
           mutex_exit(&sc->sc_lock);
   
           return ret;
   }
   
   /*
    * Open new pipe: called from usbd_setup_pipe_flags.
    * Fills methods of pipe.
    * If pipe is not for ep0, calls configure_endpoint.
    */
   static usbd_status
   xhci_open(struct usbd_pipe *pipe)
   {
           struct usbd_device * const dev = pipe->up_dev;
           struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus);
           usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
         const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);          const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(1, "addr %d depth %d port %d speed %d",          DPRINTFN(1, "addr %d depth %d port %d speed %d", dev->ud_addr,
             dev->address, dev->depth, dev->powersrc->portno, dev->speed);              dev->ud_depth, dev->ud_powersrc->up_portno, dev->ud_speed);
           DPRINTFN(1, " dci %u type 0x%02x epaddr 0x%02x attr 0x%02x",
               xhci_ep_get_dci(ed), ed->bDescriptorType, ed->bEndpointAddress,
               ed->bmAttributes);
           DPRINTFN(1, " mps %u ival %u", UGETW(ed->wMaxPacketSize), ed->bInterval,
               0, 0);
   
         if (sc->sc_dying)          if (sc->sc_dying)
                 return USBD_IOERROR;                  return USBD_IOERROR;
   
         /* Root Hub */          /* Root Hub */
         if (dev->depth == 0 && dev->powersrc->portno == 0 &&          if (dev->ud_depth == 0 && dev->ud_powersrc->up_portno == 0) {
             dev->speed != USB_SPEED_SUPER) {  
                 switch (ed->bEndpointAddress) {                  switch (ed->bEndpointAddress) {
                 case USB_CONTROL_ENDPOINT:                  case USB_CONTROL_ENDPOINT:
                         pipe->methods = &xhci_root_ctrl_methods;                          pipe->up_methods = &roothub_ctrl_methods;
                         break;                          break;
                 case UE_DIR_IN | XHCI_INTR_ENDPT:                  case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
                         pipe->methods = &xhci_root_intr_methods;                          pipe->up_methods = &xhci_root_intr_methods;
                         break;                          break;
                 default:                  default:
                         pipe->methods = NULL;                          pipe->up_methods = NULL;
                         DPRINTFN(0, "bad bEndpointAddress 0x%02x",                          DPRINTFN(0, "bad bEndpointAddress 0x%02x",
                             ed->bEndpointAddress, 0, 0, 0);                              ed->bEndpointAddress, 0, 0, 0);
                         return USBD_INVAL;                          return USBD_INVAL;
Line 1159  xhci_open(usbd_pipe_handle pipe)
Line 1452  xhci_open(usbd_pipe_handle pipe)
   
         switch (xfertype) {          switch (xfertype) {
         case UE_CONTROL:          case UE_CONTROL:
                 pipe->methods = &xhci_device_ctrl_methods;                  pipe->up_methods = &xhci_device_ctrl_methods;
                 break;                  break;
         case UE_ISOCHRONOUS:          case UE_ISOCHRONOUS:
                 pipe->methods = &xhci_device_isoc_methods;                  pipe->up_methods = &xhci_device_isoc_methods;
                 return USBD_INVAL;                  return USBD_INVAL;
                 break;                  break;
         case UE_BULK:          case UE_BULK:
                 pipe->methods = &xhci_device_bulk_methods;                  pipe->up_methods = &xhci_device_bulk_methods;
                 break;                  break;
         case UE_INTERRUPT:          case UE_INTERRUPT:
                 pipe->methods = &xhci_device_intr_methods;                  pipe->up_methods = &xhci_device_intr_methods;
                 break;                  break;
         default:          default:
                 return USBD_IOERROR;                  return USBD_IOERROR;
Line 1177  xhci_open(usbd_pipe_handle pipe)
Line 1470  xhci_open(usbd_pipe_handle pipe)
         }          }
   
         if (ed->bEndpointAddress != USB_CONTROL_ENDPOINT)          if (ed->bEndpointAddress != USB_CONTROL_ENDPOINT)
                 xhci_configure_endpoint(pipe);                  return xhci_configure_endpoint(pipe);
   
         return USBD_NORMAL_COMPLETION;          return USBD_NORMAL_COMPLETION;
 }  }
   
   /*
    * Closes pipe, called from usbd_kill_pipe via close methods.
    * If the endpoint to be closed is ep0, disable_slot.
    * Should be called with sc_lock held.
    */
   static void
   xhci_close_pipe(struct usbd_pipe *pipe)
   {
           struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
           struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
           usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
           const u_int dci = xhci_ep_get_dci(ed);
           struct xhci_trb trb;
           uint32_t *cp;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           if (sc->sc_dying)
                   return;
   
           /* xs is uninitialized before xhci_init_slot */
           if (xs == NULL || xs->xs_idx == 0)
                   return;
   
           DPRINTFN(4, "pipe %p slot %u dci %u", pipe, xs->xs_idx, dci, 0);
   
           KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
           KASSERT(mutex_owned(&sc->sc_lock));
   
           if (pipe->up_dev->ud_depth == 0)
                   return;
   
           if (dci == XHCI_DCI_EP_CONTROL) {
                   DPRINTFN(4, "closing ep0", 0, 0, 0, 0);
                   xhci_disable_slot(sc, xs->xs_idx);
                   return;
           }
   
           if (xhci_get_epstate(sc, xs, dci) != XHCI_EPSTATE_STOPPED)
                   (void)xhci_stop_endpoint(pipe);
   
           /*
            * set appropriate bit to be dropped.
            * don't set DC bit to 1, otherwise all endpoints
            * would be deconfigured.
            */
           cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
           cp[0] = htole32(XHCI_INCTX_0_DROP_MASK(dci));
           cp[1] = htole32(0);
   
           /* XXX should be most significant one, not dci? */
           cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
           cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
   
           /* configure ep context performs an implicit dequeue */
           xhci_host_dequeue(&xs->xs_ep[dci].xe_tr);
   
           /* sync input contexts before they are read from memory */
           usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
   
           trb.trb_0 = xhci_slot_get_icp(sc, xs, 0);
           trb.trb_2 = 0;
           trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
               XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
   
           (void)xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
           usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
   }
   
   /*
    * Abort transfer.
    * Should be called with sc_lock held.
    */
   static void
   xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
   {
           struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
           struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
           const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
           DPRINTFN(4, "xfer %p pipe %p status %d",
               xfer, xfer->ux_pipe, status, 0);
   
           KASSERT(mutex_owned(&sc->sc_lock));
           ASSERT_SLEEPABLE();
   
           if (sc->sc_dying) {
                   /* If we're dying, just do the software part. */
                   DPRINTFN(4, "xfer %p dying %u", xfer, xfer->ux_status, 0, 0);
                   xfer->ux_status = status;
                   callout_halt(&xfer->ux_callout, &sc->sc_lock);
                   usb_transfer_complete(xfer);
                   return;
           }
   
           /*
            * If an abort is already in progress then just wait for it to
            * complete and return.
            */
           if (xfer->ux_hcflags & UXFER_ABORTING) {
                   DPRINTFN(4, "already aborting", 0, 0, 0, 0);
   #ifdef DIAGNOSTIC
                   if (status == USBD_TIMEOUT)
                           DPRINTFN(4, "TIMEOUT while aborting", 0, 0, 0, 0);
   #endif
                   /* Override the status which might be USBD_TIMEOUT. */
                   xfer->ux_status = status;
                   DPRINTFN(4, "xfer %p waiting for abort to finish", xfer, 0, 0,
                       0);
                   xfer->ux_hcflags |= UXFER_ABORTWAIT;
                   while (xfer->ux_hcflags & UXFER_ABORTING)
                           cv_wait(&xfer->ux_hccv, &sc->sc_lock);
                   return;
           }
           xfer->ux_hcflags |= UXFER_ABORTING;
   
           /*
            * Step 1: When cancelling a transfer make sure the timeout handler
            * didn't run or ran to the end and saw the USBD_CANCELLED status.
            * Otherwise we must have got here via a timeout.
            */
           if (status == USBD_CANCELLED) {
                   xfer->ux_status = status;
                   callout_halt(&xfer->ux_callout, &sc->sc_lock);
           } else {
                   KASSERT(xfer->ux_status == USBD_TIMEOUT);
           }
   
           /*
            * Step 2: Stop execution of TD on the ring.
            */
           switch (xhci_get_epstate(sc, xs, dci)) {
           case XHCI_EPSTATE_HALTED:
                   (void)xhci_reset_endpoint_locked(xfer->ux_pipe);
                   break;
           case XHCI_EPSTATE_STOPPED:
                   break;
           default:
                   (void)xhci_stop_endpoint(xfer->ux_pipe);
                   break;
           }
   #ifdef DIAGNOSTIC
           uint32_t epst = xhci_get_epstate(sc, xs, dci);
           if (epst != XHCI_EPSTATE_STOPPED)
                   DPRINTFN(4, "dci %u not stopped %u", dci, epst, 0, 0);
   #endif
   
           /*
            * Step 3: Remove any vestiges of the xfer from the ring.
            */
           xhci_set_dequeue_locked(xfer->ux_pipe);
   
           /*
            * Step 4: Notify completion to waiting xfers.
            */
           int wake = xfer->ux_hcflags & UXFER_ABORTWAIT;
           xfer->ux_hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
           usb_transfer_complete(xfer);
           if (wake) {
                   cv_broadcast(&xfer->ux_hccv);
           }
           DPRINTFN(14, "end", 0, 0, 0, 0);
   
           KASSERT(mutex_owned(&sc->sc_lock));
   }
   
   static void
   xhci_host_dequeue(struct xhci_ring * const xr)
   {
           /* When dequeueing the controller, update our struct copy too */
           memset(xr->xr_trb, 0, xr->xr_ntrb * XHCI_TRB_SIZE);
           usb_syncmem(&xr->xr_dma, 0, xr->xr_ntrb * XHCI_TRB_SIZE,
               BUS_DMASYNC_PREWRITE);
           memset(xr->xr_cookies, 0, xr->xr_ntrb * sizeof(*xr->xr_cookies));
   
           xr->xr_ep = 0;
           xr->xr_cs = 1;
   }
   
   /*
    * Recover STALLed endpoint.
    * xHCI 1.1 sect 4.10.2.1
    * Issue RESET_EP to recover halt condition and SET_TR_DEQUEUE to remove
    * all transfers on transfer ring.
    * These are done in thread context asynchronously.
    */
   static void
   xhci_clear_endpoint_stall_async_task(void *cookie)
   {
           struct usbd_xfer * const xfer = cookie;
           struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
           struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
           const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
           struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
           DPRINTFN(4, "xfer %p slot %u dci %u", xfer, xs->xs_idx, dci, 0);
   
           xhci_reset_endpoint(xfer->ux_pipe);
           xhci_set_dequeue(xfer->ux_pipe);
   
           mutex_enter(&sc->sc_lock);
           tr->is_halted = false;
           usb_transfer_complete(xfer);
           mutex_exit(&sc->sc_lock);
           DPRINTFN(4, "ends", 0, 0, 0, 0);
   }
   
   static usbd_status
   xhci_clear_endpoint_stall_async(struct usbd_xfer *xfer)
   {
           struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
           struct xhci_pipe * const xp = (struct xhci_pipe *)xfer->ux_pipe;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
           DPRINTFN(4, "xfer %p", xfer, 0, 0, 0);
   
           if (sc->sc_dying) {
                   return USBD_IOERROR;
           }
   
           usb_init_task(&xp->xp_async_task,
               xhci_clear_endpoint_stall_async_task, xfer, USB_TASKQ_MPSAFE);
           usb_add_task(xfer->ux_pipe->up_dev, &xp->xp_async_task, USB_TASKQ_HC);
           DPRINTFN(4, "ends", 0, 0, 0, 0);
   
           return USBD_NORMAL_COMPLETION;
   }
   
   /* Process roothub port status/change events and notify to uhub_intr. */
 static void  static void
 xhci_rhpsc(struct xhci_softc * const sc, u_int port)  xhci_rhpsc(struct xhci_softc * const sc, u_int port)
 {  {
         usbd_xfer_handle const xfer = sc->sc_intrxfer;          struct usbd_xfer * const xfer = sc->sc_intrxfer;
         uint8_t *p;          uint8_t *p;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(4, "port %u status change", port, 0, 0, 0);          DPRINTFN(4, "xhci%d: port %u status change", device_unit(sc->sc_dev),
               port, 0, 0);
   
         if (xfer == NULL)          if (xfer == NULL)
                 return;                  return;
   
         if (!(port >= sc->sc_hs_port_start &&          if (port > sc->sc_maxports)
             port < sc->sc_hs_port_start + sc->sc_hs_port_count))  
                 return;                  return;
   
         port -= sc->sc_hs_port_start;          p = xfer->ux_buf;
         port += 1;          memset(p, 0, xfer->ux_length);
         DPRINTFN(4, "hs port %u status change", port, 0, 0, 0);  
   
         p = KERNADDR(&xfer->dmabuf, 0);  
         memset(p, 0, xfer->length);  
         p[port/NBBY] |= 1 << (port%NBBY);          p[port/NBBY] |= 1 << (port%NBBY);
         xfer->actlen = xfer->length;          xfer->ux_actlen = xfer->ux_length;
         xfer->status = USBD_NORMAL_COMPLETION;          xfer->ux_status = USBD_NORMAL_COMPLETION;
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
 }  }
   
   /* Process Transfer Events */
 static void  static void
 xhci_handle_event(struct xhci_softc * const sc,  xhci_event_transfer(struct xhci_softc * const sc,
     const struct xhci_trb * const trb)      const struct xhci_trb * const trb)
 {  {
         uint64_t trb_0;          uint64_t trb_0;
         uint32_t trb_2, trb_3;          uint32_t trb_2, trb_3;
           uint8_t trbcode;
           u_int slot, dci;
           struct xhci_slot *xs;
           struct xhci_ring *xr;
           struct xhci_xfer *xx;
           struct usbd_xfer *xfer;
           usbd_status err;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         trb_0 = le64toh(trb->trb_0);          trb_0 = le64toh(trb->trb_0);
         trb_2 = le32toh(trb->trb_2);          trb_2 = le32toh(trb->trb_2);
         trb_3 = le32toh(trb->trb_3);          trb_3 = le32toh(trb->trb_3);
           trbcode = XHCI_TRB_2_ERROR_GET(trb_2);
           slot = XHCI_TRB_3_SLOT_GET(trb_3);
           dci = XHCI_TRB_3_EP_GET(trb_3);
           xs = &sc->sc_slots[slot];
           xr = &xs->xs_ep[dci].xe_tr;
   
         DPRINTFN(14, "event: %p 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,          /* sanity check */
             trb, trb_0, trb_2, trb_3);          KASSERTMSG(xs->xs_idx != 0 && xs->xs_idx <= sc->sc_maxslots,
               "invalid xs_idx %u slot %u", xs->xs_idx, slot);
   
           int idx = 0;
           if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
                   if (xhci_trb_get_idx(xr, trb_0, &idx)) {
                           DPRINTFN(0, "invalid trb_0 0x%"PRIx64, trb_0, 0, 0, 0);
                           return;
                   }
                   xx = xr->xr_cookies[idx];
   
         switch (XHCI_TRB_3_TYPE_GET(trb_3)){                  /* clear cookie of consumed TRB */
         case XHCI_TRB_EVENT_TRANSFER: {                  xr->xr_cookies[idx] = NULL;
                 u_int slot, dci;  
                 struct xhci_slot *xs;  
                 struct xhci_ring *xr;  
                 struct xhci_xfer *xx;  
                 usbd_xfer_handle xfer;  
                 usbd_status err;  
   
                 slot = XHCI_TRB_3_SLOT_GET(trb_3);                  /*
                 dci = XHCI_TRB_3_EP_GET(trb_3);                   * xx is NULL if pipe is opened but xfer is not started.
                    * It happens when stopping idle pipe.
                    */
                   if (xx == NULL || trbcode == XHCI_TRB_ERROR_LENGTH) {
                           DPRINTFN(1, "Ignore #%u: cookie %p cc %u dci %u",
                               idx, xx, trbcode, dci);
                           DPRINTFN(1, " orig TRB %"PRIx64" type %u", trb_0,
                               XHCI_TRB_3_TYPE_GET(le32toh(xr->xr_trb[idx].trb_3)),
                               0, 0);
                           return;
                   }
           } else {
                   /* When ED != 0, trb_0 is virtual addr of struct xhci_xfer. */
                   xx = (void *)(uintptr_t)(trb_0 & ~0x3);
           }
           /* XXX this may not happen */
           if (xx == NULL) {
                   DPRINTFN(1, "xfer done: xx is NULL", 0, 0, 0, 0);
                   return;
           }
           xfer = &xx->xx_xfer;
           /* XXX this may happen when detaching */
           if (xfer == NULL) {
                   DPRINTFN(1, "xx(%p)->xx_xfer is NULL trb_0 %#"PRIx64,
                       xx, trb_0, 0, 0);
                   return;
           }
           DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
           /* XXX I dunno why this happens */
           KASSERTMSG(xfer->ux_pipe != NULL, "xfer(%p)->ux_pipe is NULL", xfer);
   
           if (!xfer->ux_pipe->up_repeat &&
               SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) {
                   DPRINTFN(1, "xfer(%p)->pipe not queued", xfer, 0, 0, 0);
                   return;
           }
   
                 xs = &sc->sc_slots[slot];          /* 4.11.5.2 Event Data TRB */
                 xr = &xs->xs_ep[dci].xe_tr;          if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
                   DPRINTFN(14, "transfer Event Data: 0x%016"PRIx64" 0x%08"PRIx32
                       " %02x", trb_0, XHCI_TRB_2_REM_GET(trb_2), trbcode, 0);
                   if ((trb_0 & 0x3) == 0x3) {
                           xfer->ux_actlen = XHCI_TRB_2_REM_GET(trb_2);
                   }
           }
   
           switch (trbcode) {
           case XHCI_TRB_ERROR_SHORT_PKT:
           case XHCI_TRB_ERROR_SUCCESS:
                   /*
                    * A ctrl transfer can generate two events if it has a Data
                    * stage.  A short data stage can be OK and should not
                    * complete the transfer as the status stage needs to be
                    * performed.
                    *
                    * Note: Data and Status stage events point at same xfer.
                    * ux_actlen and ux_dmabuf will be passed to
                    * usb_transfer_complete after the Status stage event.
                    *
                    * It can be distingished which stage generates the event:
                    * + by checking least 3 bits of trb_0 if ED==1.
                    *   (see xhci_device_ctrl_start).
                    * + by checking the type of original TRB if ED==0.
                    *
                    * In addition, intr, bulk, and isoc transfer currently
                    * consists of single TD, so the "skip" is not needed.
                    * ctrl xfer uses EVENT_DATA, and others do not.
                    * Thus driver can switch the flow by checking ED bit.
                    */
                 if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {                  if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
                         xx = xr->xr_cookies[(trb_0 - xhci_ring_trbp(xr, 0))/                          if (xfer->ux_actlen == 0)
                             sizeof(struct xhci_trb)];                                  xfer->ux_actlen = xfer->ux_length -
                 } else {                                      XHCI_TRB_2_REM_GET(trb_2);
                         xx = (void *)(uintptr_t)(trb_0 & ~0x3);                          if (XHCI_TRB_3_TYPE_GET(le32toh(xr->xr_trb[idx].trb_3))
                               == XHCI_TRB_TYPE_DATA_STAGE) {
                                   return;
                           }
                   } else if ((trb_0 & 0x3) == 0x3) {
                           return;
                 }                  }
                 xfer = &xx->xx_xfer;                  err = USBD_NORMAL_COMPLETION;
                 DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);                  break;
           case XHCI_TRB_ERROR_STOPPED:
           case XHCI_TRB_ERROR_LENGTH:
           case XHCI_TRB_ERROR_STOPPED_SHORT:
                   /*
                    * don't complete the transfer being aborted
                    * as abort_xfer does instead.
                    */
                   if (xfer->ux_hcflags & UXFER_ABORTING) {
                           DPRINTFN(14, "ignore aborting xfer %p", xfer, 0, 0, 0);
                           return;
                   }
                   err = USBD_CANCELLED;
                   break;
           case XHCI_TRB_ERROR_STALL:
           case XHCI_TRB_ERROR_BABBLE:
                   DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0);
                   xr->is_halted = true;
                   err = USBD_STALLED;
                   /*
                    * Stalled endpoints can be recoverd by issuing
                    * command TRB TYPE_RESET_EP on xHCI instead of
                    * issuing request CLEAR_FEATURE UF_ENDPOINT_HALT
                    * on the endpoint. However, this function may be
                    * called from softint context (e.g. from umass),
                    * in that case driver gets KASSERT in cv_timedwait
                    * in xhci_do_command.
                    * To avoid this, this runs reset_endpoint and
                    * usb_transfer_complete in usb task thread
                    * asynchronously (and then umass issues clear
                    * UF_ENDPOINT_HALT).
                    */
                   xfer->ux_status = err;
                   callout_halt(&xfer->ux_callout, &sc->sc_lock);
                   xhci_clear_endpoint_stall_async(xfer);
                   return;
           default:
                   DPRINTFN(1, "ERR %u slot %u dci %u", trbcode, slot, dci, 0);
                   err = USBD_IOERROR;
                   break;
           }
           xfer->ux_status = err;
   
                 if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {          if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
                         DPRINTFN(14, "transfer event data: "                  if ((trb_0 & 0x3) == 0x0) {
                             "0x%016"PRIx64" 0x%08"PRIx32" %02x",                          callout_stop(&xfer->ux_callout);
                             trb_0, XHCI_TRB_2_REM_GET(trb_2),                          usb_transfer_complete(xfer);
                             XHCI_TRB_2_ERROR_GET(trb_2), 0);  
                         if ((trb_0 & 0x3) == 0x3) {  
                                 xfer->actlen = XHCI_TRB_2_REM_GET(trb_2);  
                         }  
                 }                  }
           } else {
                   callout_stop(&xfer->ux_callout);
                   usb_transfer_complete(xfer);
           }
   }
   
   /* Process Command complete events */
   static void
   xhci_event_cmd(struct xhci_softc * const sc, const struct xhci_trb * const trb)
   {
           uint64_t trb_0;
           uint32_t trb_2, trb_3;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
                 if (XHCI_TRB_2_ERROR_GET(trb_2) ==          KASSERT(mutex_owned(&sc->sc_lock));
   
           trb_0 = le64toh(trb->trb_0);
           trb_2 = le32toh(trb->trb_2);
           trb_3 = le32toh(trb->trb_3);
   
           if (trb_0 == sc->sc_command_addr) {
                   sc->sc_resultpending = false;
   
                   sc->sc_result_trb.trb_0 = trb_0;
                   sc->sc_result_trb.trb_2 = trb_2;
                   sc->sc_result_trb.trb_3 = trb_3;
                   if (XHCI_TRB_2_ERROR_GET(trb_2) !=
                     XHCI_TRB_ERROR_SUCCESS) {                      XHCI_TRB_ERROR_SUCCESS) {
                         xfer->actlen = xfer->length - XHCI_TRB_2_REM_GET(trb_2);                          DPRINTFN(1, "command completion "
                         err = USBD_NORMAL_COMPLETION;                              "failure: 0x%016"PRIx64" 0x%08"PRIx32" "
                 } else if (XHCI_TRB_2_ERROR_GET(trb_2) ==                              "0x%08"PRIx32, trb_0, trb_2, trb_3, 0);
                     XHCI_TRB_ERROR_SHORT_PKT) {  
                         xfer->actlen = xfer->length - XHCI_TRB_2_REM_GET(trb_2);  
                         err = USBD_NORMAL_COMPLETION;  
                 } else if (XHCI_TRB_2_ERROR_GET(trb_2) ==  
                     XHCI_TRB_ERROR_STALL) {  
                         err = USBD_STALLED;  
                         xr->is_halted = true;  
                         DPRINTFN(1, "ev: xfer done: err %u slot %u dci %u",  
                             XHCI_TRB_2_ERROR_GET(trb_2), slot, dci, 0);  
                 } else {  
                         err = USBD_IOERROR;  
                 }                  }
                 xfer->status = err;                  cv_signal(&sc->sc_command_cv);
           } else {
                   DPRINTFN(1, "spurious event: %p 0x%016"PRIx64" "
                       "0x%08"PRIx32" 0x%08"PRIx32, trb, trb_0,
                       trb_2, trb_3);
           }
   }
   
                 //mutex_enter(&sc->sc_lock); /* XXX ??? */  /*
                 if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {   * Process events.
                         if ((trb_0 & 0x3) == 0x0) {   * called from xhci_softintr
                                 usb_transfer_complete(xfer);   */
                         }  static void
                 } else {  xhci_handle_event(struct xhci_softc * const sc,
                         usb_transfer_complete(xfer);      const struct xhci_trb * const trb)
                 }  {
                 //mutex_exit(&sc->sc_lock); /* XXX ??? */          uint64_t trb_0;
           uint32_t trb_2, trb_3;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           trb_0 = le64toh(trb->trb_0);
           trb_2 = le32toh(trb->trb_2);
           trb_3 = le32toh(trb->trb_3);
   
           DPRINTFN(14, "event: %p 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
               trb, trb_0, trb_2, trb_3);
   
           /*
            * 4.11.3.1, 6.4.2.1
            * TRB Pointer is invalid for these completion codes.
            */
           switch (XHCI_TRB_2_ERROR_GET(trb_2)) {
           case XHCI_TRB_ERROR_RING_UNDERRUN:
           case XHCI_TRB_ERROR_RING_OVERRUN:
           case XHCI_TRB_ERROR_VF_RING_FULL:
                   return;
           default:
                   if (trb_0 == 0) {
                           return;
                 }                  }
                 break;                  break;
           }
   
           switch (XHCI_TRB_3_TYPE_GET(trb_3)) {
           case XHCI_TRB_EVENT_TRANSFER:
                   xhci_event_transfer(sc, trb);
                   break;
         case XHCI_TRB_EVENT_CMD_COMPLETE:          case XHCI_TRB_EVENT_CMD_COMPLETE:
                 if (trb_0 == sc->sc_command_addr) {                  xhci_event_cmd(sc, trb);
                         sc->sc_result_trb.trb_0 = trb_0;  
                         sc->sc_result_trb.trb_2 = trb_2;  
                         sc->sc_result_trb.trb_3 = trb_3;  
                         if (XHCI_TRB_2_ERROR_GET(trb_2) !=  
                             XHCI_TRB_ERROR_SUCCESS) {  
                                 DPRINTFN(1, "command completion "  
                                     "failure: 0x%016"PRIx64" 0x%08"PRIx32" "  
                                     "0x%08"PRIx32, trb_0, trb_2, trb_3, 0);  
                         }  
                         cv_signal(&sc->sc_command_cv);  
                 } else {  
                         DPRINTFN(1, "event: %p 0x%016"PRIx64" "  
                             "0x%08"PRIx32" 0x%08"PRIx32, trb, trb_0,  
                             trb_2, trb_3);  
                 }  
                 break;                  break;
         case XHCI_TRB_EVENT_PORT_STS_CHANGE:          case XHCI_TRB_EVENT_PORT_STS_CHANGE:
                 xhci_rhpsc(sc, (uint32_t)((trb_0 >> 24) & 0xff));                  xhci_rhpsc(sc, (uint32_t)((trb_0 >> 24) & 0xff));
Line 1321  static void
Line 1997  static void
 xhci_softintr(void *v)  xhci_softintr(void *v)
 {  {
         struct usbd_bus * const bus = v;          struct usbd_bus * const bus = v;
         struct xhci_softc * const sc = bus->hci_private;          struct xhci_softc * const sc = XHCI_BUS2SC(bus);
         struct xhci_ring * const er = &sc->sc_er;          struct xhci_ring * const er = &sc->sc_er;
         struct xhci_trb *trb;          struct xhci_trb *trb;
         int i, j, k;          int i, j, k;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
   
         i = er->xr_ep;          i = er->xr_ep;
         j = er->xr_cs;          j = er->xr_cs;
   
         DPRINTFN(16, "xr_ep %d xr_cs %d", i, j, 0, 0);          DPRINTFN(16, "er: xr_ep %d xr_cs %d", i, j, 0, 0);
   
         while (1) {          while (1) {
                 usb_syncmem(&er->xr_dma, XHCI_TRB_SIZE * i, XHCI_TRB_SIZE,                  usb_syncmem(&er->xr_dma, XHCI_TRB_SIZE * i, XHCI_TRB_SIZE,
Line 1345  xhci_softintr(void *v)
Line 2023  xhci_softintr(void *v)
                 xhci_handle_event(sc, trb);                  xhci_handle_event(sc, trb);
   
                 i++;                  i++;
                 if (i == XHCI_EVENT_RING_TRBS) {                  if (i == er->xr_ntrb) {
                         i = 0;                          i = 0;
                         j ^= 1;                          j ^= 1;
                 }                  }
Line 1365  xhci_softintr(void *v)
Line 2043  xhci_softintr(void *v)
 static void  static void
 xhci_poll(struct usbd_bus *bus)  xhci_poll(struct usbd_bus *bus)
 {  {
         struct xhci_softc * const sc = bus->hci_private;          struct xhci_softc * const sc = XHCI_BUS2SC(bus);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
Line 1376  xhci_poll(struct usbd_bus *bus)
Line 2054  xhci_poll(struct usbd_bus *bus)
         return;          return;
 }  }
   
 static usbd_status  static struct usbd_xfer *
 xhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size)  xhci_allocx(struct usbd_bus *bus, unsigned int nframes)
 {  
         struct xhci_softc * const sc = bus->hci_private;  
         usbd_status err;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();  
   
         err = usb_allocmem(&sc->sc_bus, size, 0, dma);  
 #if 0  
         if (err == USBD_NOMEM)  
                 err = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size);  
 #endif  
 #ifdef XHCI_DEBUG  
         if (err)  
                 DPRINTFN(1, "usb_allocmem(%u)=%d", err, size, 0, 0);  
 #endif  
   
         return err;  
 }  
   
 static void  
 xhci_freem(struct usbd_bus *bus, usb_dma_t *dma)  
 {  {
         struct xhci_softc * const sc = bus->hci_private;          struct xhci_softc * const sc = XHCI_BUS2SC(bus);
           struct usbd_xfer *xfer;
         XHCIHIST_FUNC(); XHCIHIST_CALLED();  
   
 #if 0  
         if (dma->block->flags & USB_DMA_RESERVE) {  
                 usb_reserve_freem(&sc->sc_dma_reserve, dma);  
                 return;  
         }  
 #endif  
         usb_freemem(&sc->sc_bus, dma);  
 }  
   
 static usbd_xfer_handle  
 xhci_allocx(struct usbd_bus *bus)  
 {  
         struct xhci_softc * const sc = bus->hci_private;  
         usbd_xfer_handle xfer;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
Line 1425  xhci_allocx(struct usbd_bus *bus)
Line 2066  xhci_allocx(struct usbd_bus *bus)
         if (xfer != NULL) {          if (xfer != NULL) {
                 memset(xfer, 0, sizeof(struct xhci_xfer));                  memset(xfer, 0, sizeof(struct xhci_xfer));
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 xfer->busy_free = XFER_BUSY;                  xfer->ux_state = XFER_BUSY;
 #endif  #endif
         }          }
   
Line 1433  xhci_allocx(struct usbd_bus *bus)
Line 2074  xhci_allocx(struct usbd_bus *bus)
 }  }
   
 static void  static void
 xhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)  xhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = bus->hci_private;          struct xhci_softc * const sc = XHCI_BUS2SC(bus);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (xfer->busy_free != XFER_BUSY) {          if (xfer->ux_state != XFER_BUSY) {
                 DPRINTFN(0, "xfer=%p not busy, 0x%08x",                  DPRINTFN(0, "xfer=%p not busy, 0x%08x",
                     xfer, xfer->busy_free, 0, 0);                      xfer, xfer->ux_state, 0, 0);
         }          }
         xfer->busy_free = XFER_FREE;          xfer->ux_state = XFER_FREE;
 #endif  #endif
         pool_cache_put(sc->sc_xferpool, xfer);          pool_cache_put(sc->sc_xferpool, xfer);
 }  }
Line 1452  xhci_freex(struct usbd_bus *bus, usbd_xf
Line 2093  xhci_freex(struct usbd_bus *bus, usbd_xf
 static void  static void
 xhci_get_lock(struct usbd_bus *bus, kmutex_t **lock)  xhci_get_lock(struct usbd_bus *bus, kmutex_t **lock)
 {  {
         struct xhci_softc * const sc = bus->hci_private;          struct xhci_softc * const sc = XHCI_BUS2SC(bus);
   
         *lock = &sc->sc_lock;          *lock = &sc->sc_lock;
 }  }
   
 extern u_int32_t usb_cookie_no;  extern uint32_t usb_cookie_no;
   
   /*
    * xHCI 4.3
    * Called when uhub_explore finds a new device (via usbd_new_device).
    * Port initialization and speed detection (4.3.1) are already done in uhub.c.
    * This function does:
    *   Allocate and construct dev structure of default endpoint (ep0).
    *   Allocate and open pipe of ep0.
    *   Enable slot and initialize slot context.
    *   Set Address.
    *   Read initial device descriptor.
    *   Determine initial MaxPacketSize (mps) by speed.
    *   Read full device descriptor.
    *   Register this device.
    * Finally state of device transitions ADDRESSED.
    */
 static usbd_status  static usbd_status
 xhci_new_device(device_t parent, usbd_bus_handle bus, int depth,  xhci_new_device(device_t parent, struct usbd_bus *bus, int depth,
     int speed, int port, struct usbd_port *up)      int speed, int port, struct usbd_port *up)
 {  {
         struct xhci_softc * const sc = bus->hci_private;          struct xhci_softc * const sc = XHCI_BUS2SC(bus);
         usbd_device_handle dev;          struct usbd_device *dev;
         usbd_status err;          usbd_status err;
         usb_device_descriptor_t *dd;          usb_device_descriptor_t *dd;
         struct usbd_device *hub;  
         struct usbd_device *adev;  
         int rhport = 0;  
         struct xhci_slot *xs;          struct xhci_slot *xs;
         uint32_t *cp;          uint32_t *cp;
         uint8_t slot;  
         uint8_t addr;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(4, "port=%d depth=%d speed=%d upport %d",          DPRINTFN(4, "port %u depth %u speed %u up %p", port, depth, speed, up);
                  port, depth, speed, up->portno);  
   
         dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO);          dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
         if (dev == NULL)          if (dev == NULL)
                 return USBD_NOMEM;                  return USBD_NOMEM;
   
         dev->bus = bus;          dev->ud_bus = bus;
           dev->ud_quirks = &usbd_no_quirk;
           dev->ud_addr = 0;
           dev->ud_ddesc.bMaxPacketSize = 0;
           dev->ud_depth = depth;
           dev->ud_powersrc = up;
           dev->ud_myhub = up->up_parent;
           dev->ud_speed = speed;
           dev->ud_langid = USBD_NOLANG;
           dev->ud_cookie.cookie = ++usb_cookie_no;
   
         /* Set up default endpoint handle. */          /* Set up default endpoint handle. */
         dev->def_ep.edesc = &dev->def_ep_desc;          dev->ud_ep0.ue_edesc = &dev->ud_ep0desc;
   
         /* Set up default endpoint descriptor. */  
         dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;  
         dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;  
         dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;  
         dev->def_ep_desc.bmAttributes = UE_CONTROL;  
         /* XXX */  
         if (speed == USB_SPEED_LOW)  
                 USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);  
         else  
                 USETW(dev->def_ep_desc.wMaxPacketSize, 64);  
         dev->def_ep_desc.bInterval = 0;  
   
         /* doesn't matter, just don't let it uninitialized */          /* doesn't matter, just don't let it uninitialized */
         dev->def_ep.datatoggle = 0;          dev->ud_ep0.ue_toggle = 0;
   
         DPRINTFN(4, "up %p portno %d", up, up->portno, 0, 0);          /* Set up default endpoint descriptor. */
           dev->ud_ep0desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
           dev->ud_ep0desc.bDescriptorType = UDESC_ENDPOINT;
           dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
           dev->ud_ep0desc.bmAttributes = UE_CONTROL;
           dev->ud_ep0desc.bInterval = 0;
   
         dev->quirks = &usbd_no_quirk;          /* 4.3,  4.8.2.1 */
         dev->address = 0;          switch (speed) {
         dev->ddesc.bMaxPacketSize = 0;          case USB_SPEED_SUPER:
         dev->depth = depth;          case USB_SPEED_SUPER_PLUS:
         dev->powersrc = up;                  USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET);
         dev->myhub = up->parent;                  break;
           case USB_SPEED_FULL:
         up->device = dev;                  /* XXX using 64 as initial mps of ep0 in FS */
           case USB_SPEED_HIGH:
         /* Locate root hub port */                  USETW(dev->ud_ep0desc.wMaxPacketSize, USB_2_MAX_CTRL_PACKET);
         for (adev = dev, hub = dev;                  break;
             hub != NULL;          case USB_SPEED_LOW:
             adev = hub, hub = hub->myhub) {          default:
                 DPRINTFN(4, "hub %p", hub, 0, 0, 0);                  USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET);
         }                  break;
         DPRINTFN(4, "hub %p", hub, 0, 0, 0);  
   
         if (hub != NULL) {  
                 for (int p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {  
                         if (hub->hub->ports[p].device == adev) {  
                                 rhport = p;  
                         }  
                 }  
         } else {  
                 rhport = port;  
         }  
         if (speed == USB_SPEED_SUPER) {  
                 rhport += sc->sc_ss_port_start - 1;  
         } else {  
                 rhport += sc->sc_hs_port_start - 1;  
         }          }
         DPRINTFN(4, "rhport %d", rhport, 0, 0, 0);  
   
         dev->speed = speed;          up->up_dev = dev;
         dev->langid = USBD_NOLANG;  
         dev->cookie.cookie = ++usb_cookie_no;  
   
         /* Establish the default pipe. */          /* Establish the default pipe. */
         err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,          err = usbd_setup_pipe(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
             &dev->default_pipe);              &dev->ud_pipe0);
         if (err) {          if (err) {
                 usbd_remove_device(dev, up);                  goto bad;
                 return (err);  
         }          }
   
         dd = &dev->ddesc;          dd = &dev->ud_ddesc;
   
         if ((depth == 0) && (port == 0)) {          if (depth == 0 && port == 0) {
                 KASSERT(bus->devices[dev->address] == NULL);                  KASSERT(bus->ub_devices[dev->ud_addr] == NULL);
                 bus->devices[dev->address] = dev;                  bus->ub_devices[dev->ud_addr] = dev;
                 err = usbd_get_initial_ddesc(dev, dd);                  err = usbd_get_initial_ddesc(dev, dd);
                 if (err)                  if (err) {
                         return err;                          DPRINTFN(1, "get_initial_ddesc %u", err, 0, 0, 0);
                           goto bad;
                   }
   
                 err = usbd_reload_device_desc(dev);                  err = usbd_reload_device_desc(dev);
                 if (err)                  if (err) {
                         return err;                          DPRINTFN(1, "reload desc %u", err, 0, 0, 0);
                           goto bad;
                   }
         } else {          } else {
                   uint8_t slot = 0;
   
                   /* 4.3.2 */
                 err = xhci_enable_slot(sc, &slot);                  err = xhci_enable_slot(sc, &slot);
                 if (err)                  if (err) {
                         return err;                          DPRINTFN(1, "enable slot %u", err, 0, 0, 0);
                 err = xhci_init_slot(sc, slot, depth, speed, port, rhport);                          goto bad;
                 if (err)                  }
                         return err;  
                 xs = &sc->sc_slots[slot];                  xs = &sc->sc_slots[slot];
                 dev->hci_private = xs;                  dev->ud_hcpriv = xs;
   
                   /* 4.3.3 initialize slot structure */
                   err = xhci_init_slot(dev, slot);
                   if (err) {
                           DPRINTFN(1, "init slot %u", err, 0, 0, 0);
                           dev->ud_hcpriv = NULL;
                           /*
                            * We have to disable_slot here because
                            * xs->xs_idx == 0 when xhci_init_slot fails,
                            * in that case usbd_remove_dev won't work.
                            */
                           mutex_enter(&sc->sc_lock);
                           xhci_disable_slot(sc, slot);
                           mutex_exit(&sc->sc_lock);
                           goto bad;
                   }
   
                   /* 4.3.4 Address Assignment */
                   err = xhci_set_address(dev, slot, false);
                   if (err) {
                           DPRINTFN(1, "set address w/o bsr %u", err, 0, 0, 0);
                           goto bad;
                   }
   
                   /* Allow device time to set new address */
                   usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
   
                 cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT);                  cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT);
                 //hexdump("slot context", cp, sc->sc_ctxsz);                  //hexdump("slot context", cp, sc->sc_ctxsz);
                 addr = XHCI_SCTX_3_DEV_ADDR_GET(cp[3]);                  uint8_t addr = XHCI_SCTX_3_DEV_ADDR_GET(le32toh(cp[3]));
                 DPRINTFN(4, "device address %u", addr, 0, 0, 0);                  DPRINTFN(4, "device address %u", addr, 0, 0, 0);
                 /* XXX ensure we know when the hardware does something                  /* XXX ensure we know when the hardware does something
                    we can't yet cope with */                     we can't yet cope with */
                 KASSERT(addr >= 1 && addr <= 127);                  KASSERTMSG(addr >= 1 && addr <= 127, "addr %d", addr);
                 dev->address = addr;                  dev->ud_addr = addr;
                 /* XXX dev->address not necessarily unique on bus */                  /* XXX dev->ud_addr not necessarily unique on bus */
                 KASSERT(bus->devices[dev->address] == NULL);                  KASSERT(bus->ub_devices[dev->ud_addr] == NULL);
                 bus->devices[dev->address] = dev;                  bus->ub_devices[dev->ud_addr] = dev;
   
                 err = usbd_get_initial_ddesc(dev, dd);                  err = usbd_get_initial_ddesc(dev, dd);
                 if (err)                  if (err) {
                         return err;                          DPRINTFN(1, "get_initial_ddesc %u", err, 0, 0, 0);
                           goto bad;
                   }
   
                 /* 4.8.2.1 */                  /* 4.8.2.1 */
                 if (speed == USB_SPEED_SUPER)                  if (USB_IS_SS(speed)) {
                         USETW(dev->def_ep_desc.wMaxPacketSize,                          if (dd->bMaxPacketSize != 9) {
                                   printf("%s: invalid mps 2^%u for SS ep0,"
                                       " using 512\n",
                                       device_xname(sc->sc_dev),
                                       dd->bMaxPacketSize);
                                   dd->bMaxPacketSize = 9;
                           }
                           USETW(dev->ud_ep0desc.wMaxPacketSize,
                             (1 << dd->bMaxPacketSize));                              (1 << dd->bMaxPacketSize));
                 else                  } else
                         USETW(dev->def_ep_desc.wMaxPacketSize,                          USETW(dev->ud_ep0desc.wMaxPacketSize,
                             dd->bMaxPacketSize);                              dd->bMaxPacketSize);
                 DPRINTFN(4, "bMaxPacketSize %u", dd->bMaxPacketSize, 0, 0, 0);                  DPRINTFN(4, "bMaxPacketSize %u", dd->bMaxPacketSize, 0, 0, 0);
                 xhci_update_ep0_mps(sc, xs,                  err = xhci_update_ep0_mps(sc, xs,
                     UGETW(dev->def_ep_desc.wMaxPacketSize));                      UGETW(dev->ud_ep0desc.wMaxPacketSize));
                 err = usbd_reload_device_desc(dev);                  if (err) {
                 if (err)                          DPRINTFN(1, "update mps of ep0 %u", err, 0, 0, 0);
                         return err;                          goto bad;
                   }
   
                 usbd_kill_pipe(dev->default_pipe);                  err = usbd_reload_device_desc(dev);
                 err = usbd_setup_pipe(dev, 0, &dev->def_ep,                  if (err) {
                     USBD_DEFAULT_INTERVAL, &dev->default_pipe);                          DPRINTFN(1, "reload desc %u", err, 0, 0, 0);
                           goto bad;
                   }
         }          }
   
         DPRINTFN(1, "adding unit addr=%d, rev=%02x,",          DPRINTFN(1, "adding unit addr=%d, rev=%02x,",
                 dev->address, UGETW(dd->bcdUSB), 0, 0);                  dev->ud_addr, UGETW(dd->bcdUSB), 0, 0);
         DPRINTFN(1, " class=%d, subclass=%d, protocol=%d,",          DPRINTFN(1, " class=%d, subclass=%d, protocol=%d,",
                 dd->bDeviceClass, dd->bDeviceSubClass,                  dd->bDeviceClass, dd->bDeviceSubClass,
                 dd->bDeviceProtocol, 0);                  dd->bDeviceProtocol, 0);
         DPRINTFN(1, " mps=%d, len=%d, noconf=%d, speed=%d",          DPRINTFN(1, " mps=%d, len=%d, noconf=%d, speed=%d",
                 dd->bMaxPacketSize, dd->bLength, dd->bNumConfigurations,                  dd->bMaxPacketSize, dd->bLength, dd->bNumConfigurations,
                 dev->speed);                  dev->ud_speed);
   
           usbd_get_device_strings(dev);
   
         usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);          usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);
   
         if ((depth == 0) && (port == 0)) {          if (depth == 0 && port == 0) {
                 usbd_attach_roothub(parent, dev);                  usbd_attach_roothub(parent, dev);
                 DPRINTFN(1, "root_hub %p", bus->root_hub, 0, 0, 0);                  DPRINTFN(1, "root hub %p", dev, 0, 0, 0);
                 return USBD_NORMAL_COMPLETION;                  return USBD_NORMAL_COMPLETION;
         }          }
   
   
         err = usbd_probe_and_attach(parent, dev, port, dev->address);          err = usbd_probe_and_attach(parent, dev, port, dev->ud_addr);
         if (err) {   bad:
           if (err != USBD_NORMAL_COMPLETION) {
                 usbd_remove_device(dev, up);                  usbd_remove_device(dev, up);
                 return (err);  
         }          }
   
         return USBD_NORMAL_COMPLETION;          return err;
 }  }
   
 static usbd_status  static usbd_status
Line 1647  xhci_ring_init(struct xhci_softc * const
Line 2329  xhci_ring_init(struct xhci_softc * const
         xr->xr_cookies = kmem_zalloc(sizeof(*xr->xr_cookies) * ntrb, KM_SLEEP);          xr->xr_cookies = kmem_zalloc(sizeof(*xr->xr_cookies) * ntrb, KM_SLEEP);
         xr->xr_trb = xhci_ring_trbv(xr, 0);          xr->xr_trb = xhci_ring_trbv(xr, 0);
         xr->xr_ntrb = ntrb;          xr->xr_ntrb = ntrb;
         xr->xr_ep = 0;  
         xr->xr_cs = 1;  
         memset(xr->xr_trb, 0, size);  
         usb_syncmem(&xr->xr_dma, 0, size, BUS_DMASYNC_PREWRITE);  
         xr->is_halted = false;          xr->is_halted = false;
           xhci_host_dequeue(xr);
   
         return USBD_NORMAL_COMPLETION;          return USBD_NORMAL_COMPLETION;
 }  }
Line 1677  xhci_ring_put(struct xhci_softc * const 
Line 2356  xhci_ring_put(struct xhci_softc * const 
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           KASSERTMSG(ntrbs <= XHCI_XFER_NTRB, "ntrbs %zu", ntrbs);
         for (i = 0; i < ntrbs; i++) {          for (i = 0; i < ntrbs; i++) {
                 DPRINTFN(12, "xr %p trbs %p num %zu", xr, trbs, i, 0);                  DPRINTFN(12, "xr %p trbs %p num %zu", xr, trbs, i, 0);
                 DPRINTFN(12, " %016"PRIx64" %08"PRIx32" %08"PRIx32,                  DPRINTFN(12, " %016"PRIx64" %08"PRIx32" %08"PRIx32,
                     trbs[i].trb_0, trbs[i].trb_2, trbs[i].trb_3, 0);                      trbs[i].trb_0, trbs[i].trb_2, trbs[i].trb_3, 0);
                 KASSERT(XHCI_TRB_3_TYPE_GET(trbs[i].trb_3) !=                  KASSERTMSG(XHCI_TRB_3_TYPE_GET(trbs[i].trb_3) !=
                     XHCI_TRB_TYPE_LINK);                      XHCI_TRB_TYPE_LINK, "trbs[%zu].trb3 %#x", i, trbs[i].trb_3);
         }          }
   
         DPRINTFN(12, "%p xr_ep 0x%x xr_cs %u", xr, xr->xr_ep, xr->xr_cs, 0);          DPRINTFN(12, "%p xr_ep 0x%x xr_cs %u", xr, xr->xr_ep, xr->xr_cs, 0);
Line 1704  xhci_ring_put(struct xhci_softc * const 
Line 2384  xhci_ring_put(struct xhci_softc * const 
          * The code should write the 'cycle' bit on the link trb AFTER           * The code should write the 'cycle' bit on the link trb AFTER
          * adding the other trb.           * adding the other trb.
          */           */
         if (ri + ntrbs >= (xr->xr_ntrb - 1)) {          u_int firstep = xr->xr_ep;
                 parameter = xhci_ring_trbp(xr, 0);          u_int firstcs = xr->xr_cs;
                 status = 0;  
                 control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |  
                     XHCI_TRB_3_TC_BIT | (cs ? XHCI_TRB_3_CYCLE_BIT : 0);  
                 xhci_trb_put(&xr->xr_trb[ri], htole64(parameter),  
                     htole32(status), htole32(control));  
                 usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * ri, XHCI_TRB_SIZE * 1,  
                     BUS_DMASYNC_PREWRITE);  
                 xr->xr_cookies[ri] = NULL;  
                 xr->xr_ep = 0;  
                 xr->xr_cs ^= 1;  
                 ri = xr->xr_ep;  
                 cs = xr->xr_cs;  
         }  
   
         ri++;  
   
         /* Write any subsequent TRB first */  
         for (i = 1; i < ntrbs; i++) {  
                 parameter = trbs[i].trb_0;  
                 status = trbs[i].trb_2;  
                 control = trbs[i].trb_3;  
   
                 if (cs) {          for (i = 0; i < ntrbs; ) {
                         control |= XHCI_TRB_3_CYCLE_BIT;                  u_int oldri = ri;
                   u_int oldcs = cs;
   
                   if (ri >= (xr->xr_ntrb - 1)) {
                           /* Put Link TD at the end of ring */
                           parameter = xhci_ring_trbp(xr, 0);
                           status = 0;
                           control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
                               XHCI_TRB_3_TC_BIT;
                           xr->xr_cookies[ri] = NULL;
                           xr->xr_ep = 0;
                           xr->xr_cs ^= 1;
                           ri = xr->xr_ep;
                           cs = xr->xr_cs;
                 } else {                  } else {
                         control &= ~XHCI_TRB_3_CYCLE_BIT;                          parameter = trbs[i].trb_0;
                           status = trbs[i].trb_2;
                           control = trbs[i].trb_3;
   
                           xr->xr_cookies[ri] = cookie;
                           ri++;
                           i++;
                 }                  }
                   /*
                 xhci_trb_put(&xr->xr_trb[ri], htole64(parameter),                   * If this is a first TRB, mark it invalid to prevent
                     htole32(status), htole32(control));                   * xHC from running it immediately.
                 usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * ri, XHCI_TRB_SIZE * 1,                   */
                     BUS_DMASYNC_PREWRITE);                  if (oldri == firstep) {
                 xr->xr_cookies[ri] = cookie;                          if (oldcs) {
                 ri++;                                  control &= ~XHCI_TRB_3_CYCLE_BIT;
         }                          } else {
                                   control |= XHCI_TRB_3_CYCLE_BIT;
         /* Write the first TRB last */                          }
         i = 0;  
         {  
                 parameter = trbs[i].trb_0;  
                 status = trbs[i].trb_2;  
                 control = trbs[i].trb_3;  
   
                 if (xr->xr_cs) {  
                         control |= XHCI_TRB_3_CYCLE_BIT;  
                 } else {                  } else {
                         control &= ~XHCI_TRB_3_CYCLE_BIT;                          if (oldcs) {
                                   control |= XHCI_TRB_3_CYCLE_BIT;
                           } else {
                                   control &= ~XHCI_TRB_3_CYCLE_BIT;
                           }
                 }                  }
                   xhci_trb_put(&xr->xr_trb[oldri], parameter, status, control);
                   usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * oldri,
                       XHCI_TRB_SIZE * 1, BUS_DMASYNC_PREWRITE);
           }
   
                 xhci_trb_put(&xr->xr_trb[xr->xr_ep], htole64(parameter),          /* Now invert cycle bit of first TRB */
                     htole32(status), htole32(control));          if (firstcs) {
                 usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * ri, XHCI_TRB_SIZE * 1,                  xr->xr_trb[firstep].trb_3 |= htole32(XHCI_TRB_3_CYCLE_BIT);
                     BUS_DMASYNC_PREWRITE);          } else {
                 xr->xr_cookies[xr->xr_ep] = cookie;                  xr->xr_trb[firstep].trb_3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
         }          }
           usb_syncmem(&xr->xr_dma, XHCI_TRB_SIZE * firstep,
               XHCI_TRB_SIZE * 1, BUS_DMASYNC_PREWRITE);
   
         xr->xr_ep = ri;          xr->xr_ep = ri;
         xr->xr_cs = cs;          xr->xr_cs = cs;
Line 1768  xhci_ring_put(struct xhci_softc * const 
Line 2448  xhci_ring_put(struct xhci_softc * const 
         DPRINTFN(12, "%p xr_ep 0x%x xr_cs %u", xr, xr->xr_ep, xr->xr_cs, 0);          DPRINTFN(12, "%p xr_ep 0x%x xr_cs %u", xr, xr->xr_ep, xr->xr_cs, 0);
 }  }
   
   /*
    * Stop execution commands, purge all commands on command ring, and
    * rewind dequeue pointer.
    */
   static void
   xhci_abort_command(struct xhci_softc *sc)
   {
           struct xhci_ring * const cr = &sc->sc_cr;
           uint64_t crcr;
           int i;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
           DPRINTFN(14, "command %#"PRIx64" timeout, aborting",
               sc->sc_command_addr, 0, 0, 0);
   
           mutex_enter(&cr->xr_lock);
   
           /* 4.6.1.2 Aborting a Command */
           crcr = xhci_op_read_8(sc, XHCI_CRCR);
           xhci_op_write_8(sc, XHCI_CRCR, crcr | XHCI_CRCR_LO_CA);
   
           for (i = 0; i < 500; i++) {
                   crcr = xhci_op_read_8(sc, XHCI_CRCR);
                   if ((crcr & XHCI_CRCR_LO_CRR) == 0)
                           break;
                   usb_delay_ms(&sc->sc_bus, 1);
           }
           if ((crcr & XHCI_CRCR_LO_CRR) != 0) {
                   DPRINTFN(1, "Command Abort timeout", 0, 0, 0, 0);
                   /* reset HC here? */
           }
   
           /* reset command ring dequeue pointer */
           cr->xr_ep = 0;
           cr->xr_cs = 1;
           xhci_op_write_8(sc, XHCI_CRCR, xhci_ring_trbp(cr, 0) | cr->xr_cs);
   
           mutex_exit(&cr->xr_lock);
   }
   
   /*
    * Put a command on command ring, ring bell, set timer, and cv_timedwait.
    * Command completion is notified by cv_signal from xhci_event_cmd()
    * (called from xhci_softint), or timed-out.
    * The completion code is copied to sc->sc_result_trb in xhci_event_cmd(),
    * then do_command examines it.
    */
 static usbd_status  static usbd_status
 xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,  xhci_do_command_locked(struct xhci_softc * const sc,
     int timeout)      struct xhci_trb * const trb, int timeout)
 {  {
         struct xhci_ring * const cr = &sc->sc_cr;          struct xhci_ring * const cr = &sc->sc_cr;
         usbd_status err;          usbd_status err;
Line 1779  xhci_do_command(struct xhci_softc * cons
Line 2506  xhci_do_command(struct xhci_softc * cons
         DPRINTFN(12, "input: 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,          DPRINTFN(12, "input: 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
             trb->trb_0, trb->trb_2, trb->trb_3, 0);              trb->trb_0, trb->trb_2, trb->trb_3, 0);
   
         mutex_enter(&sc->sc_lock);          KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
           KASSERT(mutex_owned(&sc->sc_lock));
   
         KASSERT(sc->sc_command_addr == 0);          while (sc->sc_command_addr != 0)
         sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);                  cv_wait(&sc->sc_cmdbusy_cv, &sc->sc_lock);
   
           /*
            * If enqueue pointer points at last of ring, it's Link TRB,
            * command TRB will be stored in 0th TRB.
            */
           if (cr->xr_ep == cr->xr_ntrb - 1)
                   sc->sc_command_addr = xhci_ring_trbp(cr, 0);
           else
                   sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
   
           sc->sc_resultpending = true;
   
         mutex_enter(&cr->xr_lock);          mutex_enter(&cr->xr_lock);
         xhci_ring_put(sc, cr, NULL, trb, 1);          xhci_ring_put(sc, cr, NULL, trb, 1);
Line 1790  xhci_do_command(struct xhci_softc * cons
Line 2529  xhci_do_command(struct xhci_softc * cons
   
         xhci_db_write_4(sc, XHCI_DOORBELL(0), 0);          xhci_db_write_4(sc, XHCI_DOORBELL(0), 0);
   
         if (cv_timedwait(&sc->sc_command_cv, &sc->sc_lock,          while (sc->sc_resultpending) {
             MAX(1, mstohz(timeout))) == EWOULDBLOCK) {                  if (cv_timedwait(&sc->sc_command_cv, &sc->sc_lock,
                 err = USBD_TIMEOUT;                      MAX(1, mstohz(timeout))) == EWOULDBLOCK) {
                 goto timedout;                          xhci_abort_command(sc);
                           err = USBD_TIMEOUT;
                           goto timedout;
                   }
         }          }
   
         trb->trb_0 = sc->sc_result_trb.trb_0;          trb->trb_0 = sc->sc_result_trb.trb_0;
Line 1817  xhci_do_command(struct xhci_softc * cons
Line 2559  xhci_do_command(struct xhci_softc * cons
         }          }
   
 timedout:  timedout:
           sc->sc_resultpending = false;
         sc->sc_command_addr = 0;          sc->sc_command_addr = 0;
         mutex_exit(&sc->sc_lock);          cv_broadcast(&sc->sc_cmdbusy_cv);
   
         return err;          return err;
 }  }
   
 static usbd_status  static usbd_status
   xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
       int timeout)
   {
   
           mutex_enter(&sc->sc_lock);
           usbd_status ret = xhci_do_command_locked(sc, trb, timeout);
           mutex_exit(&sc->sc_lock);
   
           return ret;
   }
   
   static usbd_status
 xhci_enable_slot(struct xhci_softc * const sc, uint8_t * const slotp)  xhci_enable_slot(struct xhci_softc * const sc, uint8_t * const slotp)
 {  {
         struct xhci_trb trb;          struct xhci_trb trb;
Line 1844  xhci_enable_slot(struct xhci_softc * con
Line 2600  xhci_enable_slot(struct xhci_softc * con
         return err;          return err;
 }  }
   
   /*
    * xHCI 4.6.4
    * Deallocate ring and device/input context DMA buffers, and disable_slot.
    * All endpoints in the slot should be stopped.
    * Should be called with sc_lock held.
    */
   static usbd_status
   xhci_disable_slot(struct xhci_softc * const sc, uint8_t slot)
   {
           struct xhci_trb trb;
           struct xhci_slot *xs;
           usbd_status err;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           if (sc->sc_dying)
                   return USBD_IOERROR;
   
           trb.trb_0 = 0;
           trb.trb_2 = 0;
           trb.trb_3 = htole32(
                   XHCI_TRB_3_SLOT_SET(slot) |
                   XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT));
   
           err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
   
           if (!err) {
                   xs = &sc->sc_slots[slot];
                   if (xs->xs_idx != 0) {
                           xhci_free_slot(sc, xs, XHCI_DCI_SLOT + 1, 32);
                           xhci_set_dcba(sc, 0, slot);
                           memset(xs, 0, sizeof(*xs));
                   }
           }
   
           return err;
   }
   
   /*
    * Set address of device and transition slot state from ENABLED to ADDRESSED
    * if Block Setaddress Request (BSR) is false.
    * If BSR==true, transition slot state from ENABLED to DEFAULT.
    * see xHCI 1.1  4.5.3, 3.3.4
    * Should be called without sc_lock held.
    */
 static usbd_status  static usbd_status
 xhci_address_device(struct xhci_softc * const sc,  xhci_address_device(struct xhci_softc * const sc,
     uint64_t icp, uint8_t slot_id, bool bsr)      uint64_t icp, uint8_t slot_id, bool bsr)
Line 1860  xhci_address_device(struct xhci_softc * 
Line 2661  xhci_address_device(struct xhci_softc * 
             (bsr ? XHCI_TRB_3_BSR_BIT : 0);              (bsr ? XHCI_TRB_3_BSR_BIT : 0);
   
         err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);          err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
   
           if (XHCI_TRB_2_ERROR_GET(trb.trb_2) == XHCI_TRB_ERROR_NO_SLOTS)
                   err = USBD_NO_ADDR;
   
         return err;          return err;
 }  }
   
Line 1892  xhci_update_ep0_mps(struct xhci_softc * 
Line 2697  xhci_update_ep0_mps(struct xhci_softc * 
             XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX);              XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX);
   
         err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);          err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
         KASSERT(err == USBD_NORMAL_COMPLETION); /* XXX */  
         return err;          return err;
 }  }
   
Line 1910  xhci_set_dcba(struct xhci_softc * const 
Line 2714  xhci_set_dcba(struct xhci_softc * const 
             BUS_DMASYNC_PREWRITE);              BUS_DMASYNC_PREWRITE);
 }  }
   
   /*
    * Allocate device and input context DMA buffer, and
    * TRB DMA buffer for each endpoint.
    */
 static usbd_status  static usbd_status
 xhci_init_slot(struct xhci_softc * const sc, uint32_t slot, int depth,  xhci_init_slot(struct usbd_device *dev, uint32_t slot)
     int speed, int port, int rhport)  
 {  {
           struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus);
         struct xhci_slot *xs;          struct xhci_slot *xs;
         usbd_status err;          usbd_status err;
         u_int dci;          u_int dci;
         uint32_t *cp;  
         uint32_t mps;  
         uint32_t xspeed;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(4, "slot %u depth %d speed %d",          DPRINTFN(4, "slot %u", slot, 0, 0, 0);
             slot, depth, speed, 0);  
         DPRINTFN(4, " port %d rhport %d",  
             port, rhport, 0, 0);  
   
         switch (speed) {  
         case USB_SPEED_LOW:  
                 xspeed = 2;  
                 mps = USB_MAX_IPACKET;  
                 break;  
         case USB_SPEED_FULL:  
                 xspeed = 1;  
                 mps = 64;  
                 break;  
         case USB_SPEED_HIGH:  
                 xspeed = 3;  
                 mps = USB_2_MAX_CTRL_PACKET;  
                 break;  
         case USB_SPEED_SUPER:  
                 xspeed = 4;  
                 mps = USB_3_MAX_CTRL_PACKET;  
                 break;  
         default:  
                 DPRINTFN(0, "impossible speed: %x", speed, 0, 0, 0);  
                 return USBD_INVAL;  
         }  
   
         xs = &sc->sc_slots[slot];          xs = &sc->sc_slots[slot];
         xs->xs_idx = slot;  
   
         /* allocate contexts */          /* allocate contexts */
         err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,          err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,
Line 1962  xhci_init_slot(struct xhci_softc * const
Line 2741  xhci_init_slot(struct xhci_softc * const
         err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,          err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,
             &xs->xs_ic_dma);              &xs->xs_ic_dma);
         if (err)          if (err)
                 return err;                  goto bad1;
         memset(KERNADDR(&xs->xs_ic_dma, 0), 0, sc->sc_pgsz);          memset(KERNADDR(&xs->xs_ic_dma, 0), 0, sc->sc_pgsz);
   
         for (dci = 0; dci < 32; dci++) {          for (dci = 0; dci < 32; dci++) {
Line 1974  xhci_init_slot(struct xhci_softc * const
Line 2753  xhci_init_slot(struct xhci_softc * const
                     XHCI_TRANSFER_RING_TRBS, XHCI_TRB_ALIGN);                      XHCI_TRANSFER_RING_TRBS, XHCI_TRB_ALIGN);
                 if (err) {                  if (err) {
                         DPRINTFN(0, "ring init failure", 0, 0, 0, 0);                          DPRINTFN(0, "ring init failure", 0, 0, 0, 0);
                         return err;                          goto bad2;
                 }                  }
         }          }
   
         /* set up initial input control context */   bad2:
         cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);          if (err == USBD_NORMAL_COMPLETION) {
         cp[0] = htole32(0);                  xs->xs_idx = slot;
         cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(XHCI_DCI_EP_CONTROL)|          } else {
             XHCI_INCTX_1_ADD_MASK(XHCI_DCI_SLOT));                  xhci_free_slot(sc, xs, XHCI_DCI_SLOT + 1, dci);
           }
   
           return err;
   
    bad1:
           usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
           xs->xs_idx = 0;
           return err;
   }
   
   static void
   xhci_free_slot(struct xhci_softc *sc, struct xhci_slot *xs, int start_dci,
       int end_dci)
   {
           u_int dci;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
           DPRINTFN(4, "slot %u start %u end %u", xs->xs_idx, start_dci, end_dci,
               0);
   
           for (dci = start_dci; dci < end_dci; dci++) {
                   xhci_ring_free(sc, &xs->xs_ep[dci].xe_tr);
                   memset(&xs->xs_ep[dci], 0, sizeof(xs->xs_ep[dci]));
           }
           usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
           usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
           xs->xs_idx = 0;
   }
   
   /*
    * Setup slot context, set Device Context Base Address, and issue
    * Set Address Device command.
    */
   static usbd_status
   xhci_set_address(struct usbd_device *dev, uint32_t slot, bool bsr)
   {
           struct xhci_softc * const sc = XHCI_BUS2SC(dev->ud_bus);
           struct xhci_slot *xs;
           usbd_status err;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
           DPRINTFN(4, "slot %u bsr %u", slot, bsr, 0, 0);
   
           xs = &sc->sc_slots[slot];
   
           xhci_setup_ctx(dev->ud_pipe0);
   
           hexdump("input context", xhci_slot_get_icv(sc, xs, 0),
               sc->sc_ctxsz * 3);
   
           xhci_set_dcba(sc, DMAADDR(&xs->xs_dc_dma, 0), slot);
   
           err = xhci_address_device(sc, xhci_slot_get_icp(sc, xs, 0), slot, bsr);
   
           usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
           hexdump("output context", xhci_slot_get_dcv(sc, xs, 0),
               sc->sc_ctxsz * 2);
   
           return err;
   }
   
   /*
    * 4.8.2, 6.2.3.2
    * construct slot/endpoint context parameters and do syncmem
    */
   static void
   xhci_setup_ctx(struct usbd_pipe *pipe)
   {
           struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
           struct usbd_device *dev = pipe->up_dev;
           struct xhci_slot * const xs = dev->ud_hcpriv;
           usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
           const u_int dci = xhci_ep_get_dci(ed);
           const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
           uint32_t *cp;
           uint16_t mps = UGETW(ed->wMaxPacketSize);
           uint8_t speed = dev->ud_speed;
           uint8_t ival = ed->bInterval;
   
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
           DPRINTFN(4, "pipe %p: slot %u dci %u speed %u", pipe, xs->xs_idx, dci,
               speed);
   
           /* set up initial input control context */
           cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
           cp[0] = htole32(0);
           cp[1] = htole32(XHCI_INCTX_1_ADD_MASK(dci));
           if (dci == XHCI_DCI_EP_CONTROL)
                   cp[1] |= htole32(XHCI_INCTX_1_ADD_MASK(XHCI_DCI_SLOT));
           cp[7] = htole32(0);
   
           /* set up input slot context */
           cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
           cp[0] =
               XHCI_SCTX_0_CTX_NUM_SET(dci) |
               XHCI_SCTX_0_SPEED_SET(xhci_speed2xspeed(speed));
           cp[1] = 0;
           cp[2] = XHCI_SCTX_2_IRQ_TARGET_SET(0);
           cp[3] = 0;
           xhci_setup_route(pipe, cp);
           xhci_setup_tthub(pipe, cp);
   
           cp[0] = htole32(cp[0]);
           cp[1] = htole32(cp[1]);
           cp[2] = htole32(cp[2]);
           cp[3] = htole32(cp[3]);
   
           /* set up input endpoint context */
           cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));
           cp[0] =
               XHCI_EPCTX_0_EPSTATE_SET(0) |
               XHCI_EPCTX_0_MULT_SET(0) |
               XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
               XHCI_EPCTX_0_LSA_SET(0) |
               XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(0);
           cp[1] =
               XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(ed)) |
               XHCI_EPCTX_1_HID_SET(0) |
               XHCI_EPCTX_1_MAXB_SET(0);
   
           if (xfertype != UE_ISOCHRONOUS)
                   cp[1] |= XHCI_EPCTX_1_CERR_SET(3);
   
           if (xfertype == UE_CONTROL)
                   cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); /* 6.2.3 */
           else if (USB_IS_SS(speed))
                   cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(mps);
           else
                   cp[4] = XHCI_EPCTX_4_AVG_TRB_LEN_SET(UE_GET_SIZE(mps));
   
           xhci_setup_maxburst(pipe, cp);
   
           switch (xfertype) {
           case UE_CONTROL:
                   break;
           case UE_BULK:
                   /* XXX Set MaxPStreams, HID, and LSA if streams enabled */
                   break;
           case UE_INTERRUPT:
                   if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
                           ival = pipe->up_interval;
   
                   ival = xhci_bival2ival(ival, speed);
                   cp[0] |= XHCI_EPCTX_0_IVAL_SET(ival);
                   break;
           case UE_ISOCHRONOUS:
                   if (pipe->up_interval != USBD_DEFAULT_INTERVAL)
                           ival = pipe->up_interval;
   
         /* set up input slot context */                  /* xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6 */
         cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));                  if (speed == USB_SPEED_FULL)
         cp[0] = htole32(                          ival += 3; /* 1ms -> 125us */
                 XHCI_SCTX_0_CTX_NUM_SET(1) |                  ival--;
                 XHCI_SCTX_0_SPEED_SET(xspeed)                  cp[0] |= XHCI_EPCTX_0_IVAL_SET(ival);
                 );                  break;
         cp[1] = htole32(          default:
                 XHCI_SCTX_1_RH_PORT_SET(rhport)                  break;
                 );          }
         cp[2] = htole32(          DPRINTFN(4, "setting ival %u MaxBurst %#x",
                 XHCI_SCTX_2_IRQ_TARGET_SET(0)              XHCI_EPCTX_0_IVAL_GET(cp[0]), XHCI_EPCTX_1_MAXB_GET(cp[1]), 0, 0);
                 );  
         cp[3] = htole32(0);  
   
         /* set up input EP0 context */          /* rewind TR dequeue pointer in xHC */
         cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_EP_CONTROL));  
         cp[0] = htole32(0);  
         cp[1] = htole32(  
                 XHCI_EPCTX_1_MAXP_SIZE_SET(mps) |  
                 XHCI_EPCTX_1_EPTYPE_SET(4) |  
                 XHCI_EPCTX_1_CERR_SET(3)  
                 );  
         /* can't use xhci_ep_get_dci() yet? */          /* can't use xhci_ep_get_dci() yet? */
         *(uint64_t *)(&cp[2]) = htole64(          *(uint64_t *)(&cp[2]) = htole64(
             xhci_ring_trbp(&xs->xs_ep[XHCI_DCI_EP_CONTROL].xe_tr, 0) |              xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
             XHCI_EPCTX_2_DCS_SET(1));              XHCI_EPCTX_2_DCS_SET(1));
         cp[4] = htole32(  
                 XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)          cp[0] = htole32(cp[0]);
                 );          cp[1] = htole32(cp[1]);
           cp[4] = htole32(cp[4]);
   
           /* rewind TR dequeue pointer in driver */
           struct xhci_ring *xr = &xs->xs_ep[dci].xe_tr;
           mutex_enter(&xr->xr_lock);
           xhci_host_dequeue(xr);
           mutex_exit(&xr->xr_lock);
   
         /* sync input contexts before they are read from memory */          /* sync input contexts before they are read from memory */
         usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);          usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
         hexdump("input context", xhci_slot_get_icv(sc, xs, 0),  }
             sc->sc_ctxsz * 3);  
   
         xhci_set_dcba(sc, DMAADDR(&xs->xs_dc_dma, 0), slot);  /*
    * Setup route string and roothub port of given device for slot context
    */
   static void
   xhci_setup_route(struct usbd_pipe *pipe, uint32_t *cp)
   {
           struct usbd_device *dev = pipe->up_dev;
           struct usbd_port *up = dev->ud_powersrc;
           struct usbd_device *hub;
           struct usbd_device *adev;
           uint8_t rhport = 0;
           uint32_t route = 0;
   
         err = xhci_address_device(sc, xhci_slot_get_icp(sc, xs, 0), slot,          XHCIHIST_FUNC(); XHCIHIST_CALLED();
             false);  
   
         usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);          /* Locate root hub port and Determine route string */
         hexdump("output context", xhci_slot_get_dcv(sc, xs, 0),          /* 4.3.3 route string does not include roothub port */
             sc->sc_ctxsz * 2);          for (hub = dev; hub != NULL; hub = hub->ud_myhub) {
                   uint32_t dep;
   
         return err;                  DPRINTFN(4, "hub %p depth %d upport %p upportno %d",
 }                      hub, hub->ud_depth, hub->ud_powersrc,
                       hub->ud_powersrc ? hub->ud_powersrc->up_portno : -1);
   
 /* ----- */                  if (hub->ud_powersrc == NULL)
                           break;
                   dep = hub->ud_depth;
                   if (dep == 0)
                           break;
                   rhport = hub->ud_powersrc->up_portno;
                   if (dep > USB_HUB_MAX_DEPTH)
                           continue;
   
                   route |=
                       (rhport > UHD_SS_NPORTS_MAX ? UHD_SS_NPORTS_MAX : rhport)
                       << ((dep - 1) * 4);
           }
           route = route >> 4;
           DPRINTFN(4, "rhport %u Route %05x hub %p", rhport, route, hub, 0);
   
           /* Locate port on upstream high speed hub */
           for (adev = dev, hub = up->up_parent;
                hub != NULL && hub->ud_speed != USB_SPEED_HIGH;
                adev = hub, hub = hub->ud_myhub)
                   ;
           if (hub) {
                   int p;
                   for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
                           if (hub->ud_hub->uh_ports[p].up_dev == adev) {
                                   dev->ud_myhsport = &hub->ud_hub->uh_ports[p];
                                   goto found;
                           }
                   }
                   panic("%d: cannot find HS port", __func__);
           found:
                   DPRINTFN(4, "high speed port %d", p, 0, 0, 0);
           } else {
                   dev->ud_myhsport = NULL;
           }
   
           cp[0] |= XHCI_SCTX_0_ROUTE_SET(route);
           cp[1] |= XHCI_SCTX_1_RH_PORT_SET(rhport);
   }
   
   /*
    * Setup whether device is hub, whether device uses MTT, and
    * TT informations if it uses MTT.
    */
 static void  static void
 xhci_noop(usbd_pipe_handle pipe)  xhci_setup_tthub(struct usbd_pipe *pipe, uint32_t *cp)
 {  {
           struct usbd_device *dev = pipe->up_dev;
           usb_device_descriptor_t * const dd = &dev->ud_ddesc;
           uint32_t speed = dev->ud_speed;
           uint8_t tthubslot, ttportnum;
           bool ishub;
           bool usemtt;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }  
   
 /* root hub descriptors */          /*
            * 6.2.2, Table 57-60, 6.2.2.1, 6.2.2.2
            * tthubslot:
            *   This is the slot ID of parent HS hub
            *   if LS/FS device is connected && connected through HS hub.
            *   This is 0 if device is not LS/FS device ||
            *   parent hub is not HS hub ||
            *   attached to root hub.
            * ttportnum:
            *   This is the downstream facing port of parent HS hub
            *   if LS/FS device is connected.
            *   This is 0 if device is not LS/FS device ||
            *   parent hub is not HS hub ||
            *   attached to root hub.
            */
           if (dev->ud_myhsport != NULL &&
               dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
               (dev->ud_myhub != NULL &&
                dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
               (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
                   ttportnum = dev->ud_myhsport->up_portno;
                   tthubslot = dev->ud_myhsport->up_parent->ud_addr;
           } else {
                   ttportnum = 0;
                   tthubslot = 0;
           }
           DPRINTFN(4, "myhsport %p ttportnum=%d tthubslot=%d",
               dev->ud_myhsport, ttportnum, tthubslot, 0);
   
 static const usb_device_descriptor_t xhci_devd = {          /* ishub is valid after reading UDESC_DEVICE */
         USB_DEVICE_DESCRIPTOR_SIZE,          ishub = (dd->bDeviceClass == UDCLASS_HUB);
         UDESC_DEVICE,           /* type */  
         {0x00, 0x02},           /* USB version */  
         UDCLASS_HUB,            /* class */  
         UDSUBCLASS_HUB,         /* subclass */  
         UDPROTO_HSHUBSTT,       /* protocol */  
         64,                     /* max packet */  
         {0},{0},{0x00,0x01},    /* device id */  
         1,2,0,                  /* string indexes */  
         1                       /* # of configurations */  
 };  
   
 static const usb_device_qualifier_t xhci_odevd = {          /* dev->ud_hub is valid after reading UDESC_HUB */
         USB_DEVICE_DESCRIPTOR_SIZE,          if (ishub && dev->ud_hub) {
         UDESC_DEVICE_QUALIFIER, /* type */                  usb_hub_descriptor_t *hd = &dev->ud_hub->uh_hubdesc;
         {0x00, 0x02},           /* USB version */                  uint8_t ttt =
         UDCLASS_HUB,            /* class */                      __SHIFTOUT(UGETW(hd->wHubCharacteristics), UHD_TT_THINK);
         UDSUBCLASS_HUB,         /* subclass */  
         UDPROTO_FSHUB,          /* protocol */  
         64,                     /* max packet */  
         1,                      /* # of configurations */  
         0  
 };  
   
 static const usb_config_descriptor_t xhci_confd = {                  cp[1] |= XHCI_SCTX_1_NUM_PORTS_SET(hd->bNbrPorts);
         USB_CONFIG_DESCRIPTOR_SIZE,                  cp[2] |= XHCI_SCTX_2_TT_THINK_TIME_SET(ttt);
         UDESC_CONFIG,                  DPRINTFN(4, "nports=%d ttt=%d", hd->bNbrPorts, ttt, 0, 0);
         {USB_CONFIG_DESCRIPTOR_SIZE +          }
          USB_INTERFACE_DESCRIPTOR_SIZE +  
          USB_ENDPOINT_DESCRIPTOR_SIZE},  
         1,  
         1,  
         0,  
         UC_ATTR_MBO | UC_SELF_POWERED,  
         0                      /* max power */  
 };  
   
 static const usb_interface_descriptor_t xhci_ifcd = {  #define IS_TTHUB(dd) \
         USB_INTERFACE_DESCRIPTOR_SIZE,      ((dd)->bDeviceProtocol == UDPROTO_HSHUBSTT || \
         UDESC_INTERFACE,       (dd)->bDeviceProtocol == UDPROTO_HSHUBMTT)
         0,  
         0,  
         1,  
         UICLASS_HUB,  
         UISUBCLASS_HUB,  
         UIPROTO_HSHUBSTT,  
         0  
 };  
   
 static const usb_endpoint_descriptor_t xhci_endpd = {          /*
         USB_ENDPOINT_DESCRIPTOR_SIZE,           * MTT flag is set if
         UDESC_ENDPOINT,           * 1. this is HS hub && MTT is enabled
         UE_DIR_IN | XHCI_INTR_ENDPT,           *  or
         UE_INTERRUPT,           * 2. this is not hub && this is LS or FS device &&
         {8, 0},                 /* max packet */           *    MTT of parent HS hub (and its parent, too) is enabled
         12           */
 };          if (ishub && speed == USB_SPEED_HIGH && IS_TTHUB(dd))
                   usemtt = true;
           else if (!ishub &&
                (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) &&
                dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
                (dev->ud_myhub != NULL &&
                 dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
                dev->ud_myhsport != NULL &&
                IS_TTHUB(&dev->ud_myhsport->up_parent->ud_ddesc))
                   usemtt = true;
           else
                   usemtt = false;
           DPRINTFN(4, "class %u proto %u ishub %d usemtt %d",
               dd->bDeviceClass, dd->bDeviceProtocol, ishub, usemtt);
   
 static const usb_hub_descriptor_t xhci_hubd = {  #undef IS_TTHUB
         USB_HUB_DESCRIPTOR_SIZE,  
         UDESC_HUB,  
         0,  
         {0,0},  
         0,  
         0,  
         {""},  
         {""},  
 };  
   
 /* root hub control */          cp[0] |=
               XHCI_SCTX_0_HUB_SET(ishub ? 1 : 0) |
               XHCI_SCTX_0_MTT_SET(usemtt ? 1 : 0);
           cp[2] |=
               XHCI_SCTX_2_TT_HUB_SID_SET(tthubslot) |
               XHCI_SCTX_2_TT_PORT_NUM_SET(ttportnum);
   }
   
 static usbd_status  /* set up params for periodic endpoint */
 xhci_root_ctrl_transfer(usbd_xfer_handle xfer)  static void
   xhci_setup_maxburst(struct usbd_pipe *pipe, uint32_t *cp)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct usbd_device *dev = pipe->up_dev;
         usbd_status err;          usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
           const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
           usbd_desc_iter_t iter;
           const usb_cdc_descriptor_t *cdcd;
           uint32_t maxb = 0;
           uint16_t mps = UGETW(ed->wMaxPacketSize);
           uint8_t speed = dev->ud_speed;
           uint8_t ep;
   
           /* config desc is NULL when opening ep0 */
           if (dev == NULL || dev->ud_cdesc == NULL)
                   goto no_cdcd;
           cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(dev,
               UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
           if (cdcd == NULL)
                   goto no_cdcd;
           usb_desc_iter_init(dev, &iter);
           iter.cur = (const void *)cdcd;
   
           /* find endpoint_ss_comp desc for ep of this pipe */
           for (ep = 0;;) {
                   cdcd = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
                   if (cdcd == NULL)
                           break;
                   if (ep == 0 && cdcd->bDescriptorType == UDESC_ENDPOINT) {
                           ep = ((const usb_endpoint_descriptor_t *)cdcd)->
                               bEndpointAddress;
                           if (UE_GET_ADDR(ep) ==
                               UE_GET_ADDR(ed->bEndpointAddress)) {
                                   cdcd = (const usb_cdc_descriptor_t *)
                                       usb_desc_iter_next(&iter);
                                   break;
                           }
                           ep = 0;
                   }
           }
           if (cdcd != NULL && cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
                   const usb_endpoint_ss_comp_descriptor_t * esscd =
                       (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
                   maxb = esscd->bMaxBurst;
           }
   
    no_cdcd:
           /* 6.2.3.4,  4.8.2.4 */
           if (USB_IS_SS(speed)) {
                   /* USB 3.1  9.6.6 */
                   cp[1] |= XHCI_EPCTX_1_MAXP_SIZE_SET(mps);
                   /* USB 3.1  9.6.7 */
                   cp[1] |= XHCI_EPCTX_1_MAXB_SET(maxb);
   #ifdef notyet
                   if (xfertype == UE_ISOCHRONOUS) {
                   }
                   if (XHCI_HCC2_LEC(sc->sc_hcc2) != 0) {
                           /* use ESIT */
                           cp[4] |= XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(x);
                           cp[0] |= XHCI_EPCTX_0_MAX_ESIT_PAYLOAD_HI_SET(x);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();                          /* XXX if LEC = 1, set ESIT instead */
                           cp[0] |= XHCI_EPCTX_0_MULT_SET(0);
                   } else {
                           /* use ival */
                   }
   #endif
           } else {
                   /* USB 2.0  9.6.6 */
                   cp[1] |= XHCI_EPCTX_1_MAXP_SIZE_SET(UE_GET_SIZE(mps));
   
         /* Insert last in queue. */                  /* 6.2.3.4 */
         mutex_enter(&sc->sc_lock);                  if (speed == USB_SPEED_HIGH &&
         err = usb_insert_transfer(xfer);                     (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)) {
         mutex_exit(&sc->sc_lock);                          maxb = UE_GET_TRANS(mps);
         if (err)                  } else {
                 return err;                          /* LS/FS or HS CTRL or HS BULK */
                           maxb = 0;
                   }
                   cp[1] |= XHCI_EPCTX_1_MAXB_SET(maxb);
           }
   }
   
         /* Pipe isn't running, start first */  /*
         return (xhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));   * Convert endpoint bInterval value to endpoint context interval value
    * for Interrupt pipe.
    * xHCI 6.2.3.6 Table 65, USB 2.0 9.6.6
    */
   static uint32_t
   xhci_bival2ival(uint32_t ival, uint32_t speed)
   {
           if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
                   int i;
   
                   /*
                    * round ival down to "the nearest base 2 multiple of
                    * bInterval * 8".
                    * bInterval is at most 255 as its type is uByte.
                    * 255(ms) = 2040(x 125us) < 2^11, so start with 10.
                    */
                   for (i = 10; i > 0; i--) {
                           if ((ival * 8) >= (1 << i))
                                   break;
                   }
                   ival = i;
           } else {
                   /* Interval = bInterval-1 for SS/HS */
                   ival--;
           }
   
           return ival;
 }  }
   
 static usbd_status  /* ----- */
 xhci_root_ctrl_start(usbd_xfer_handle xfer)  
   static void
   xhci_noop(struct usbd_pipe *pipe)
   {
           XHCIHIST_FUNC(); XHCIHIST_CALLED();
   }
   
   /*
    * Process root hub request.
    */
   static int
   xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
       void *buf, int buflen)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_BUS2SC(bus);
         usb_port_status_t ps;          usb_port_status_t ps;
         usb_device_request_t *req;  
         void *buf = NULL;  
         usb_hub_descriptor_t hubd;  
         usbd_status err;  
         int len, value, index;  
         int l, totlen = 0;          int l, totlen = 0;
           uint16_t len, value, index;
         int port, i;          int port, i;
         uint32_t v;          uint32_t v;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         if (sc->sc_dying)          if (sc->sc_dying)
                 return USBD_IOERROR;                  return -1;
   
         req = &xfer->request;  
   
           len = UGETW(req->wLength);
         value = UGETW(req->wValue);          value = UGETW(req->wValue);
         index = UGETW(req->wIndex);          index = UGETW(req->wIndex);
         len = UGETW(req->wLength);  
   
         if (len != 0)  
                 buf = KERNADDR(&xfer->dmabuf, 0);  
   
         DPRINTFN(12, "rhreq: %04x %04x %04x %04x",          DPRINTFN(12, "rhreq: %04x %04x %04x %04x",
             req->bmRequestType | (req->bRequest << 8), value, index, len);              req->bmRequestType | (req->bRequest << 8), value, index, len);
   
 #define C(x,y) ((x) | ((y) << 8))  #define C(x,y) ((x) | ((y) << 8))
         switch(C(req->bRequest, req->bmRequestType)) {          switch (C(req->bRequest, req->bmRequestType)) {
         case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):  
         case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):  
         case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):  
                 /*  
                  * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops  
                  * for the integrated root hub.  
                  */  
                 break;  
         case C(UR_GET_CONFIG, UT_READ_DEVICE):  
                 if (len > 0) {  
                         *(uint8_t *)buf = sc->sc_conf;  
                         totlen = 1;  
                 }  
                 break;  
         case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):          case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
                 DPRINTFN(8, "getdesc: wValue=0x%04x", value, 0, 0, 0);                  DPRINTFN(8, "getdesc: wValue=0x%04x", value, 0, 0, 0);
                 if (len == 0)                  if (len == 0)
                         break;                          break;
                 switch(value >> 8) {                  switch (value) {
                 case UDESC_DEVICE:                  case C(0, UDESC_DEVICE): {
                         if ((value & 0xff) != 0) {                          usb_device_descriptor_t devd;
                                 err = USBD_IOERROR;                          totlen = min(buflen, sizeof(devd));
                                 goto ret;                          memcpy(&devd, buf, totlen);
                         }                          USETW(devd.idVendor, sc->sc_id_vendor);
                         totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);                          memcpy(buf, &devd, totlen);
                         memcpy(buf, &xhci_devd, min(l, sizeof(xhci_devd)));  
                         break;  
                 case UDESC_DEVICE_QUALIFIER:  
                         if ((value & 0xff) != 0) {  
                         }  
                         totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);  
                         memcpy(buf, &xhci_odevd, min(l, sizeof(xhci_odevd)));  
                         break;  
                 case UDESC_OTHER_SPEED_CONFIGURATION:  
                 case UDESC_CONFIG:  
                         if ((value & 0xff) != 0) {  
                                 err = USBD_IOERROR;  
                                 goto ret;  
                         }  
                         totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);  
                         memcpy(buf, &xhci_confd, min(l, sizeof(xhci_confd)));  
                         ((usb_config_descriptor_t *)buf)->bDescriptorType =  
                             value >> 8;  
                         buf = (char *)buf + l;  
                         len -= l;  
                         l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);  
                         totlen += l;  
                         memcpy(buf, &xhci_ifcd, min(l, sizeof(xhci_ifcd)));  
                         buf = (char *)buf + l;  
                         len -= l;  
                         l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);  
                         totlen += l;  
                         memcpy(buf, &xhci_endpd, min(l, sizeof(xhci_endpd)));  
                         break;                          break;
                 case UDESC_STRING:                  }
 #define sd ((usb_string_descriptor_t *)buf)  #define sd ((usb_string_descriptor_t *)buf)
                         switch (value & 0xff) {                  case C(1, UDESC_STRING):
                         case 0: /* Language table */                          /* Vendor */
                                 totlen = usb_makelangtbl(sd, len);                          totlen = usb_makestrdesc(sd, len, sc->sc_vendor);
                                 break;                          break;
                         case 1: /* Vendor */                  case C(2, UDESC_STRING):
                                 totlen = usb_makestrdesc(sd, len, "NetBSD");                          /* Product */
                                 break;                          totlen = usb_makestrdesc(sd, len, "xHCI Root Hub");
                         case 2: /* Product */  
                                 totlen = usb_makestrdesc(sd, len,  
                                     "xHCI Root Hub");  
                                 break;  
                         }  
 #undef sd  
                         break;                          break;
   #undef sd
                 default:                  default:
                         err = USBD_IOERROR;                          /* default from usbroothub */
                         goto ret;                          return buflen;
                 }  
                 break;  
         case C(UR_GET_INTERFACE, UT_READ_INTERFACE):  
                 if (len > 0) {  
                         *(uint8_t *)buf = 0;  
                         totlen = 1;  
                 }  
                 break;  
         case C(UR_GET_STATUS, UT_READ_DEVICE):  
                 if (len > 1) {  
                         USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);  
                         totlen = 2;  
                 }  
                 break;  
         case C(UR_GET_STATUS, UT_READ_INTERFACE):  
         case C(UR_GET_STATUS, UT_READ_ENDPOINT):  
                 if (len > 1) {  
                         USETW(((usb_status_t *)buf)->wStatus, 0);  
                         totlen = 2;  
                 }  
                 break;  
         case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):  
                 if (value >= USB_MAX_DEVICES) {  
                         err = USBD_IOERROR;  
                         goto ret;  
                 }  
                 //sc->sc_addr = value;  
                 break;  
         case C(UR_SET_CONFIG, UT_WRITE_DEVICE):  
                 if (value != 0 && value != 1) {  
                         err = USBD_IOERROR;  
                         goto ret;  
                 }                  }
                 sc->sc_conf = value;  
                 break;  
         case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):  
                 break;  
         case C(UR_SET_FEATURE, UT_WRITE_DEVICE):  
         case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):  
         case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):  
                 err = USBD_IOERROR;  
                 goto ret;  
         case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):  
                 break;  
         case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):  
                 break;                  break;
   
         /* Hub requests */          /* Hub requests */
         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):          case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
                 break;                  break;
           /* Clear Port Feature request */
         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):          case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
                 DPRINTFN(4, "UR_CLEAR_PORT_FEATURE port=%d feature=%d",                  DPRINTFN(4, "UR_CLEAR_PORT_FEATURE port=%d feature=%d",
                              index, value, 0, 0);                               index, value, 0, 0);
                 if (index < 1 || index > sc->sc_hs_port_count) {                  if (index < 1 || index > sc->sc_maxports) {
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 }                  }
                 port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);                  port = XHCI_PORTSC(index);
                 v = xhci_op_read_4(sc, port);                  v = xhci_op_read_4(sc, port);
                 DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);                  DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
                 v &= ~XHCI_PS_CLEAR;                  v &= ~XHCI_PS_CLEAR;
                 switch (value) {                  switch (value) {
                 case UHF_PORT_ENABLE:                  case UHF_PORT_ENABLE:
                         xhci_op_write_4(sc, port, v &~ XHCI_PS_PED);                          xhci_op_write_4(sc, port, v & ~XHCI_PS_PED);
                         break;                          break;
                 case UHF_PORT_SUSPEND:                  case UHF_PORT_SUSPEND:
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 case UHF_PORT_POWER:                  case UHF_PORT_POWER:
                         break;                          break;
                 case UHF_PORT_TEST:                  case UHF_PORT_TEST:
                 case UHF_PORT_INDICATOR:                  case UHF_PORT_INDICATOR:
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 case UHF_C_PORT_CONNECTION:                  case UHF_C_PORT_CONNECTION:
                         xhci_op_write_4(sc, port, v | XHCI_PS_CSC);                          xhci_op_write_4(sc, port, v | XHCI_PS_CSC);
                         break;                          break;
                 case UHF_C_PORT_ENABLE:                  case UHF_C_PORT_ENABLE:
                 case UHF_C_PORT_SUSPEND:                  case UHF_C_PORT_SUSPEND:
                 case UHF_C_PORT_OVER_CURRENT:                  case UHF_C_PORT_OVER_CURRENT:
                         err = USBD_IOERROR;                          return -1;
                         goto ret;                  case UHF_C_BH_PORT_RESET:
                           xhci_op_write_4(sc, port, v | XHCI_PS_WRC);
                           break;
                 case UHF_C_PORT_RESET:                  case UHF_C_PORT_RESET:
                         xhci_op_write_4(sc, port, v | XHCI_PS_PRC);                          xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
                         break;                          break;
                   case UHF_C_PORT_LINK_STATE:
                           xhci_op_write_4(sc, port, v | XHCI_PS_PLC);
                           break;
                   case UHF_C_PORT_CONFIG_ERROR:
                           xhci_op_write_4(sc, port, v | XHCI_PS_CEC);
                           break;
                 default:                  default:
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 }                  }
   
                 break;                  break;
         case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):          case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
                 if (len == 0)                  if (len == 0)
                         break;                          break;
                 if ((value & 0xff) != 0) {                  if ((value & 0xff) != 0) {
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 }                  }
                 hubd = xhci_hubd;                  usb_hub_descriptor_t hubd;
                 hubd.bNbrPorts = sc->sc_hs_port_count;  
                   totlen = min(buflen, sizeof(hubd));
                   memcpy(&hubd, buf, totlen);
                   hubd.bNbrPorts = sc->sc_maxports;
                 USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);                  USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
                 hubd.bPwrOn2PwrGood = 200;                  hubd.bPwrOn2PwrGood = 200;
                 for (i = 0, l = sc->sc_maxports; l > 0; i++, l -= 8)                  for (i = 0, l = sc->sc_maxports; l > 0; i++, l -= 8)
                         hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */                          hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */
                 hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;                  hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
                 l = min(len, hubd.bDescLength);                  totlen = min(totlen, hubd.bDescLength);
                 totlen = l;                  memcpy(buf, &hubd, totlen);
                 memcpy(buf, &hubd, l);  
                 break;                  break;
         case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):          case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
                 if (len != 4) {                  if (len != 4) {
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 }                  }
                 memset(buf, 0, len); /* ? XXX */                  memset(buf, 0, len); /* ? XXX */
                 totlen = len;                  totlen = len;
                 break;                  break;
           /* Get Port Status request */
         case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):          case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
                 DPRINTFN(8, "get port status i=%d", index, 0, 0, 0);                  DPRINTFN(8, "get port status i=%d", index, 0, 0, 0);
                 if (index < 1 || index > sc->sc_maxports) {                  if (index < 1 || index > sc->sc_maxports) {
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 }                  }
                 if (len != 4) {                  if (len != 4) {
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 }  
                 v = xhci_op_read_4(sc, XHCI_PORTSC(sc->sc_hs_port_start - 1 +  
                     index));  
                 DPRINTFN(4, "READ_CLASS_OTHER GET_STATUS PORTSC %d (%d) %08x",  
                     index, sc->sc_hs_port_start - 1 + index, v, 0);  
                 switch (XHCI_PS_SPEED_GET(v)) {  
                 case 1:  
                         i = UPS_FULL_SPEED;  
                         break;  
                 case 2:  
                         i = UPS_LOW_SPEED;  
                         break;  
                 case 3:  
                         i = UPS_HIGH_SPEED;  
                         break;  
                 default:  
                         i = 0;  
                         break;  
                 }                  }
                   v = xhci_op_read_4(sc, XHCI_PORTSC(index));
                   DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
                   i = xhci_xspeed2psspeed(XHCI_PS_SPEED_GET(v));
                 if (v & XHCI_PS_CCS)    i |= UPS_CURRENT_CONNECT_STATUS;                  if (v & XHCI_PS_CCS)    i |= UPS_CURRENT_CONNECT_STATUS;
                 if (v & XHCI_PS_PED)    i |= UPS_PORT_ENABLED;                  if (v & XHCI_PS_PED)    i |= UPS_PORT_ENABLED;
                 if (v & XHCI_PS_OCA)    i |= UPS_OVERCURRENT_INDICATOR;                  if (v & XHCI_PS_OCA)    i |= UPS_OVERCURRENT_INDICATOR;
                 //if (v & XHCI_PS_SUSP) i |= UPS_SUSPEND;                  //if (v & XHCI_PS_SUSP) i |= UPS_SUSPEND;
                 if (v & XHCI_PS_PR)     i |= UPS_RESET;                  if (v & XHCI_PS_PR)     i |= UPS_RESET;
                 if (v & XHCI_PS_PP)     i |= UPS_PORT_POWER;                  if (v & XHCI_PS_PP) {
                           if (i & UPS_OTHER_SPEED)
                                           i |= UPS_PORT_POWER_SS;
                           else
                                           i |= UPS_PORT_POWER;
                   }
                   if (i & UPS_OTHER_SPEED)
                           i |= UPS_PORT_LS_SET(XHCI_PS_PLS_GET(v));
                   if (sc->sc_vendor_port_status)
                           i = sc->sc_vendor_port_status(sc, v, i);
                 USETW(ps.wPortStatus, i);                  USETW(ps.wPortStatus, i);
                 i = 0;                  i = 0;
                 if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;                  if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
                 if (v & XHCI_PS_PEC)    i |= UPS_C_PORT_ENABLED;                  if (v & XHCI_PS_PEC)    i |= UPS_C_PORT_ENABLED;
                 if (v & XHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;                  if (v & XHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;
                 if (v & XHCI_PS_PRC)    i |= UPS_C_PORT_RESET;                  if (v & XHCI_PS_PRC)    i |= UPS_C_PORT_RESET;
                   if (v & XHCI_PS_WRC)    i |= UPS_C_BH_PORT_RESET;
                   if (v & XHCI_PS_PLC)    i |= UPS_C_PORT_LINK_STATE;
                   if (v & XHCI_PS_CEC)    i |= UPS_C_PORT_CONFIG_ERROR;
                 USETW(ps.wPortChange, i);                  USETW(ps.wPortChange, i);
                 l = min(len, sizeof ps);                  totlen = min(len, sizeof(ps));
                 memcpy(buf, &ps, l);                  memcpy(buf, &ps, totlen);
                 totlen = l;  
                 break;                  break;
         case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):          case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
                 err = USBD_IOERROR;                  return -1;
                 goto ret;          case C(UR_SET_HUB_DEPTH, UT_WRITE_CLASS_DEVICE):
                   break;
         case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):          case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
                 break;                  break;
         case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):          /* Set Port Feature request */
                 if (index < 1 || index > sc->sc_hs_port_count) {          case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): {
                         err = USBD_IOERROR;                  int optval = (index >> 8) & 0xff;
                         goto ret;                  index &= 0xff;
                   if (index < 1 || index > sc->sc_maxports) {
                           return -1;
                 }                  }
                 port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);                  port = XHCI_PORTSC(index);
                 v = xhci_op_read_4(sc, port);                  v = xhci_op_read_4(sc, port);
                 DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);                  DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
                 v &= ~XHCI_PS_CLEAR;                  v &= ~XHCI_PS_CLEAR;
Line 2421  xhci_root_ctrl_start(usbd_xfer_handle xf
Line 3420  xhci_root_ctrl_start(usbd_xfer_handle xf
                         /* XXX suspend */                          /* XXX suspend */
                         break;                          break;
                 case UHF_PORT_RESET:                  case UHF_PORT_RESET:
                         v &= ~ (XHCI_PS_PED | XHCI_PS_PR);                          v &= ~(XHCI_PS_PED | XHCI_PS_PR);
                         xhci_op_write_4(sc, port, v | XHCI_PS_PR);                          xhci_op_write_4(sc, port, v | XHCI_PS_PR);
                         /* Wait for reset to complete. */                          /* Wait for reset to complete. */
                         usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);                          usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
                         if (sc->sc_dying) {                          if (sc->sc_dying) {
                                 err = USBD_IOERROR;                                  return -1;
                                 goto ret;  
                         }                          }
                         v = xhci_op_read_4(sc, port);                          v = xhci_op_read_4(sc, port);
                         if (v & XHCI_PS_PR) {                          if (v & XHCI_PS_PR) {
Line 2443  xhci_root_ctrl_start(usbd_xfer_handle xf
Line 3441  xhci_root_ctrl_start(usbd_xfer_handle xf
                 case UHF_C_PORT_RESET:                  case UHF_C_PORT_RESET:
                         xhci_op_write_4(sc, port, v | XHCI_PS_PRC);                          xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
                         break;                          break;
                   case UHF_PORT_U1_TIMEOUT:
                           if (XHCI_PS_SPEED_GET(v) < XHCI_PS_SPEED_SS) {
                                   return -1;
                           }
                           port = XHCI_PORTPMSC(index);
                           v = xhci_op_read_4(sc, port);
                           v &= ~XHCI_PM3_U1TO_SET(0xff);
                           v |= XHCI_PM3_U1TO_SET(optval);
                           xhci_op_write_4(sc, port, v);
                           break;
                   case UHF_PORT_U2_TIMEOUT:
                           if (XHCI_PS_SPEED_GET(v) < XHCI_PS_SPEED_SS) {
                                   return -1;
                           }
                           port = XHCI_PORTPMSC(index);
                           v = xhci_op_read_4(sc, port);
                           v &= ~XHCI_PM3_U2TO_SET(0xff);
                           v |= XHCI_PM3_U2TO_SET(optval);
                           xhci_op_write_4(sc, port, v);
                           break;
                 default:                  default:
                         err = USBD_IOERROR;                          return -1;
                         goto ret;  
                 }                  }
           }
                 break;                  break;
         case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):          case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
         case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):          case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):
Line 2454  xhci_root_ctrl_start(usbd_xfer_handle xf
Line 3472  xhci_root_ctrl_start(usbd_xfer_handle xf
         case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):          case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):
                 break;                  break;
         default:          default:
                 err = USBD_IOERROR;                  /* default from usbroothub */
                 goto ret;                  return buflen;
         }          }
         xfer->actlen = totlen;  
         err = USBD_NORMAL_COMPLETION;  
 ret:  
         xfer->status = err;  
         mutex_enter(&sc->sc_lock);  
         usb_transfer_complete(xfer);  
         mutex_exit(&sc->sc_lock);  
         return USBD_IN_PROGRESS;  
 }  
   
   
 static void  
 xhci_root_ctrl_abort(usbd_xfer_handle xfer)  
 {  
         XHCIHIST_FUNC(); XHCIHIST_CALLED();  
         /* Nothing to do, all transfers are synchronous. */  
 }  
   
   
 static void  
 xhci_root_ctrl_close(usbd_pipe_handle pipe)  
 {  
         XHCIHIST_FUNC(); XHCIHIST_CALLED();  
         /* Nothing to do. */  
 }  
   
 static void          return totlen;
 xhci_root_ctrl_done(usbd_xfer_handle xfer)  
 {  
         XHCIHIST_FUNC(); XHCIHIST_CALLED();  
   
         xfer->hcpriv = NULL;  
 }  }
   
 /* root hub interrupt */  /* root hub interrupt */
   
 static usbd_status  static usbd_status
 xhci_root_intr_transfer(usbd_xfer_handle xfer)  xhci_root_intr_transfer(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
         usbd_status err;          usbd_status err;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
Line 2509  xhci_root_intr_transfer(usbd_xfer_handle
Line 3497  xhci_root_intr_transfer(usbd_xfer_handle
                 return err;                  return err;
   
         /* Pipe isn't running, start first */          /* Pipe isn't running, start first */
         return (xhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return xhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }  }
   
   /* Wait for roothub port status/change */
 static usbd_status  static usbd_status
 xhci_root_intr_start(usbd_xfer_handle xfer)  xhci_root_intr_start(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
Line 2530  xhci_root_intr_start(usbd_xfer_handle xf
Line 3519  xhci_root_intr_start(usbd_xfer_handle xf
 }  }
   
 static void  static void
 xhci_root_intr_abort(usbd_xfer_handle xfer)  xhci_root_intr_abort(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         KASSERT(mutex_owned(&sc->sc_lock));          KASSERT(mutex_owned(&sc->sc_lock));
         KASSERT(xfer->pipe->intrxfer == xfer);          KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
   
         DPRINTFN(1, "remove", 0, 0, 0, 0);  
   
         sc->sc_intrxfer = NULL;          sc->sc_intrxfer = NULL;
   
         xfer->status = USBD_CANCELLED;          xfer->ux_status = USBD_CANCELLED;
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
 }  }
   
 static void  static void
 xhci_root_intr_close(usbd_pipe_handle pipe)  xhci_root_intr_close(struct usbd_pipe *pipe)
 {  {
         struct xhci_softc * const sc = pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
Line 2560  xhci_root_intr_close(usbd_pipe_handle pi
Line 3547  xhci_root_intr_close(usbd_pipe_handle pi
 }  }
   
 static void  static void
 xhci_root_intr_done(usbd_xfer_handle xfer)  xhci_root_intr_done(struct usbd_xfer *xfer)
 {  {
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         xfer->hcpriv = NULL;  
 }  }
   
 /* -------------- */  /* -------------- */
 /* device control */  /* device control */
   
 static usbd_status  static usbd_status
 xhci_device_ctrl_transfer(usbd_xfer_handle xfer)  xhci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
         usbd_status err;          usbd_status err;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
Line 2583  xhci_device_ctrl_transfer(usbd_xfer_hand
Line 3569  xhci_device_ctrl_transfer(usbd_xfer_hand
         err = usb_insert_transfer(xfer);          err = usb_insert_transfer(xfer);
         mutex_exit(&sc->sc_lock);          mutex_exit(&sc->sc_lock);
         if (err)          if (err)
                 return (err);                  return err;
   
         /* Pipe isn't running, start first */          /* Pipe isn't running, start first */
         return (xhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return xhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }  }
   
 static usbd_status  static usbd_status
 xhci_device_ctrl_start(usbd_xfer_handle xfer)  xhci_device_ctrl_start(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
         struct xhci_slot * const xs = xfer->pipe->device->hci_private;          struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(xfer->pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
         struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;          struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;
         struct xhci_xfer * const xx = (void *)xfer;          struct xhci_xfer * const xx = XHCI_XFER2XXFER(xfer);
         usb_device_request_t * const req = &xfer->request;          usb_device_request_t * const req = &xfer->ux_request;
         const bool isread = UT_GET_DIR(req->bmRequestType) == UT_READ;          const int isread = usbd_xfer_isread(xfer);
         const uint32_t len = UGETW(req->wLength);          const uint32_t len = UGETW(req->wLength);
         usb_dma_t * const dma = &xfer->dmabuf;          usb_dma_t * const dma = &xfer->ux_dmabuf;
         uint64_t parameter;          uint64_t parameter;
         uint32_t status;          uint32_t status;
         uint32_t control;          uint32_t control;
Line 2611  xhci_device_ctrl_start(usbd_xfer_handle 
Line 3597  xhci_device_ctrl_start(usbd_xfer_handle 
             req->bmRequestType | (req->bRequest << 8), UGETW(req->wValue),              req->bmRequestType | (req->bRequest << 8), UGETW(req->wValue),
             UGETW(req->wIndex), UGETW(req->wLength));              UGETW(req->wIndex), UGETW(req->wLength));
   
         /* XXX */  
         if (tr->is_halted) {  
                 xhci_reset_endpoint(xfer->pipe);  
                 tr->is_halted = false;  
                 xhci_set_dequeue(xfer->pipe);  
         }  
   
         /* we rely on the bottom bits for extra info */          /* we rely on the bottom bits for extra info */
         KASSERT(((uintptr_t)xfer & 0x3) == 0x0);          KASSERTMSG(((uintptr_t)xfer & 0x3) == 0x0, "xfer %zx",
               (uintptr_t) xfer);
   
         KASSERT((xfer->rqflags & URQ_REQUEST) != 0);          KASSERT((xfer->ux_rqflags & URQ_REQUEST) != 0);
   
         i = 0;          i = 0;
   
         /* setup phase */          /* setup phase */
         memcpy(&parameter, req, sizeof(*req));          memcpy(&parameter, req, sizeof(parameter));
         parameter = le64toh(parameter);  
         status = XHCI_TRB_2_IRQ_SET(0) | XHCI_TRB_2_BYTES_SET(sizeof(*req));          status = XHCI_TRB_2_IRQ_SET(0) | XHCI_TRB_2_BYTES_SET(sizeof(*req));
         control = ((len == 0) ? XHCI_TRB_3_TRT_NONE :          control = ((len == 0) ? XHCI_TRB_3_TRT_NONE :
              (isread ? XHCI_TRB_3_TRT_IN : XHCI_TRB_3_TRT_OUT)) |               (isread ? XHCI_TRB_3_TRT_IN : XHCI_TRB_3_TRT_OUT)) |
Line 2635  xhci_device_ctrl_start(usbd_xfer_handle 
Line 3614  xhci_device_ctrl_start(usbd_xfer_handle 
             XHCI_TRB_3_IDT_BIT;              XHCI_TRB_3_IDT_BIT;
         xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);          xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
   
         if (len == 0)          if (len != 0) {
                 goto no_data;                  /* data phase */
                   parameter = DMAADDR(dma, 0);
         /* data phase */                  KASSERTMSG(len <= 0x10000, "len %d", len);
         parameter = DMAADDR(dma, 0);                  status = XHCI_TRB_2_IRQ_SET(0) |
         KASSERT(len <= 0x10000);                      XHCI_TRB_2_TDSZ_SET(1) |
         status = XHCI_TRB_2_IRQ_SET(0) |                      XHCI_TRB_2_BYTES_SET(len);
             XHCI_TRB_2_TDSZ_SET(1) |                  control = (isread ? XHCI_TRB_3_DIR_IN : 0) |
             XHCI_TRB_2_BYTES_SET(len);                      XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE) |
         control = (isread ? XHCI_TRB_3_DIR_IN : 0) |                      (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) |
             XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE) |                      XHCI_TRB_3_IOC_BIT;
             XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_ENT_BIT;                  xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
         xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);          }
   
         parameter = (uintptr_t)xfer | 0x3;  
         status = XHCI_TRB_2_IRQ_SET(0);  
         control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVENT_DATA) |  
             XHCI_TRB_3_IOC_BIT;  
         xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);  
   
 no_data:  
         parameter = 0;          parameter = 0;
         status = XHCI_TRB_2_IRQ_SET(0);          status = XHCI_TRB_2_IRQ_SET(0);
         /* the status stage has inverted direction */          /* the status stage has inverted direction */
         control = ((isread && (len > 0)) ? 0 : XHCI_TRB_3_DIR_IN) |          control = ((isread && (len > 0)) ? 0 : XHCI_TRB_3_DIR_IN) |
             XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE) |              XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STATUS_STAGE) |
             XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_ENT_BIT;  
         xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);  
   
         parameter = (uintptr_t)xfer | 0x0;  
         status = XHCI_TRB_2_IRQ_SET(0);  
         control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVENT_DATA) |  
             XHCI_TRB_3_IOC_BIT;              XHCI_TRB_3_IOC_BIT;
         xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);          xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
   
           if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
                   callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
                       xhci_timeout, xfer);
           }
           xfer->ux_status = USBD_IN_PROGRESS;
   
         mutex_enter(&tr->xr_lock);          mutex_enter(&tr->xr_lock);
         xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);          xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);
         mutex_exit(&tr->xr_lock);          mutex_exit(&tr->xr_lock);
   
         xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);          xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
   
         if (xfer->timeout && !sc->sc_bus.use_polling) {  
                 callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout),  
                     xhci_timeout, xfer);  
         }  
   
         if (sc->sc_bus.use_polling) {  
                 DPRINTFN(1, "polling", 0, 0, 0, 0);  
                 //xhci_waitintr(sc, xfer);  
         }  
   
         return USBD_IN_PROGRESS;          return USBD_IN_PROGRESS;
 }  }
   
 static void  static void
 xhci_device_ctrl_done(usbd_xfer_handle xfer)  xhci_device_ctrl_done(struct usbd_xfer *xfer)
 {  {
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
           usb_device_request_t *req = &xfer->ux_request;
           int len = UGETW(req->wLength);
           int rd = req->bmRequestType & UT_READ;
   
         callout_stop(&xfer->timeout_handle); /* XXX wrong place */          if (len)
                   usb_syncmem(&xfer->ux_dmabuf, 0, len,
                       rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 }  }
   
 static void  static void
 xhci_device_ctrl_abort(usbd_xfer_handle xfer)  xhci_device_ctrl_abort(struct usbd_xfer *xfer)
 {  {
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           xhci_abort_xfer(xfer, USBD_CANCELLED);
 }  }
   
 static void  static void
 xhci_device_ctrl_close(usbd_pipe_handle pipe)  xhci_device_ctrl_close(struct usbd_pipe *pipe)
 {  {
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           xhci_close_pipe(pipe);
 }  }
   
 /* ----------------- */  /* ------------------ */
 /* device isochronus */  /* device isochronous */
   
 /* ----------- */  /* ----------- */
 /* device bulk */  /* device bulk */
   
 static usbd_status  static usbd_status
 xhci_device_bulk_transfer(usbd_xfer_handle xfer)  xhci_device_bulk_transfer(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
         usbd_status err;          usbd_status err;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
Line 2735  xhci_device_bulk_transfer(usbd_xfer_hand
Line 3705  xhci_device_bulk_transfer(usbd_xfer_hand
          * Pipe isn't running (otherwise err would be USBD_INPROG),           * Pipe isn't running (otherwise err would be USBD_INPROG),
          * so start it first.           * so start it first.
          */           */
         return (xhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return xhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }  }
   
 static usbd_status  static usbd_status
 xhci_device_bulk_start(usbd_xfer_handle xfer)  xhci_device_bulk_start(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
         struct xhci_slot * const xs = xfer->pipe->device->hci_private;          struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(xfer->pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
         struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;          struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;
         struct xhci_xfer * const xx = (void *)xfer;          struct xhci_xfer * const xx = XHCI_XFER2XXFER(xfer);
         const uint32_t len = xfer->length;          const uint32_t len = xfer->ux_length;
         usb_dma_t * const dma = &xfer->dmabuf;          usb_dma_t * const dma = &xfer->ux_dmabuf;
         uint64_t parameter;          uint64_t parameter;
         uint32_t status;          uint32_t status;
         uint32_t control;          uint32_t control;
Line 2760  xhci_device_bulk_start(usbd_xfer_handle 
Line 3730  xhci_device_bulk_start(usbd_xfer_handle 
         if (sc->sc_dying)          if (sc->sc_dying)
                 return USBD_IOERROR;                  return USBD_IOERROR;
   
         KASSERT((xfer->rqflags & URQ_REQUEST) == 0);          KASSERT((xfer->ux_rqflags & URQ_REQUEST) == 0);
   
         parameter = DMAADDR(dma, 0);          parameter = DMAADDR(dma, 0);
         /*          /*
Line 2774  xhci_device_bulk_start(usbd_xfer_handle 
Line 3744  xhci_device_bulk_start(usbd_xfer_handle 
          * data block be sent.           * data block be sent.
          * The earlier documentation differs, I don't know how it behaves.           * The earlier documentation differs, I don't know how it behaves.
          */           */
         KASSERT(len <= 0x10000);          KASSERTMSG(len <= 0x10000, "len %d", len);
         status = XHCI_TRB_2_IRQ_SET(0) |          status = XHCI_TRB_2_IRQ_SET(0) |
             XHCI_TRB_2_TDSZ_SET(1) |              XHCI_TRB_2_TDSZ_SET(1) |
             XHCI_TRB_2_BYTES_SET(len);              XHCI_TRB_2_BYTES_SET(len);
         control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) |          control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) |
             XHCI_TRB_3_ISP_BIT | XHCI_TRB_3_IOC_BIT;              (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) |
               XHCI_TRB_3_IOC_BIT;
         xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);          xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
   
           if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
                   callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
                       xhci_timeout, xfer);
           }
           xfer->ux_status = USBD_IN_PROGRESS;
   
         mutex_enter(&tr->xr_lock);          mutex_enter(&tr->xr_lock);
         xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);          xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);
         mutex_exit(&tr->xr_lock);          mutex_exit(&tr->xr_lock);
   
         xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);          xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
   
         if (sc->sc_bus.use_polling) {  
                 DPRINTFN(1, "polling", 0, 0, 0, 0);  
                 //xhci_waitintr(sc, xfer);  
         }  
   
         return USBD_IN_PROGRESS;          return USBD_IN_PROGRESS;
 }  }
   
 static void  static void
 xhci_device_bulk_done(usbd_xfer_handle xfer)  xhci_device_bulk_done(struct usbd_xfer *xfer)
 {  {
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         struct xhci_slot * const xs = xfer->pipe->device->hci_private;          struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(xfer->pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
 #endif  #endif
         const u_int endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;          const int isread = usbd_xfer_isread(xfer);
         const bool isread = UE_GET_DIR(endpt) == UE_DIR_IN;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         DPRINTFN(15, "%p slot %u dci %u", xfer, xs->xs_idx, dci, 0);          DPRINTFN(15, "%p slot %u dci %u", xfer, xs->xs_idx, dci, 0);
   
         callout_stop(&xfer->timeout_handle); /* XXX wrong place */          usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
   
         usb_syncmem(&xfer->dmabuf, 0, xfer->length,  
             isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);              isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   
   
 }  }
   
 static void  static void
 xhci_device_bulk_abort(usbd_xfer_handle xfer)  xhci_device_bulk_abort(struct usbd_xfer *xfer)
 {  {
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           xhci_abort_xfer(xfer, USBD_CANCELLED);
 }  }
   
 static void  static void
 xhci_device_bulk_close(usbd_pipe_handle pipe)  xhci_device_bulk_close(struct usbd_pipe *pipe)
 {  {
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
           xhci_close_pipe(pipe);
 }  }
   
 /* --------------- */  /* ---------------- */
 /* device intrrupt */  /* device interrupt */
   
 static usbd_status  static usbd_status
 xhci_device_intr_transfer(usbd_xfer_handle xfer)  xhci_device_intr_transfer(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
         usbd_status err;          usbd_status err;
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
Line 2852  xhci_device_intr_transfer(usbd_xfer_hand
Line 3823  xhci_device_intr_transfer(usbd_xfer_hand
          * Pipe isn't running (otherwise err would be USBD_INPROG),           * Pipe isn't running (otherwise err would be USBD_INPROG),
          * so start it first.           * so start it first.
          */           */
         return (xhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return xhci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }  }
   
 static usbd_status  static usbd_status
 xhci_device_intr_start(usbd_xfer_handle xfer)  xhci_device_intr_start(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;          struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
         struct xhci_slot * const xs = xfer->pipe->device->hci_private;          struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(xfer->pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
         struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;          struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;
         struct xhci_xfer * const xx = (void *)xfer;          struct xhci_xfer * const xx = XHCI_XFER2XXFER(xfer);
         const uint32_t len = xfer->length;          const uint32_t len = xfer->ux_length;
         usb_dma_t * const dma = &xfer->dmabuf;          usb_dma_t * const dma = &xfer->ux_dmabuf;
         uint64_t parameter;          uint64_t parameter;
         uint32_t status;          uint32_t status;
         uint32_t control;          uint32_t control;
Line 2877  xhci_device_intr_start(usbd_xfer_handle 
Line 3848  xhci_device_intr_start(usbd_xfer_handle 
         if (sc->sc_dying)          if (sc->sc_dying)
                 return USBD_IOERROR;                  return USBD_IOERROR;
   
         KASSERT((xfer->rqflags & URQ_REQUEST) == 0);          KASSERT((xfer->ux_rqflags & URQ_REQUEST) == 0);
   
         parameter = DMAADDR(dma, 0);          parameter = DMAADDR(dma, 0);
         KASSERT(len <= 0x10000);          KASSERTMSG(len <= 0x10000, "len %d", len);
         status = XHCI_TRB_2_IRQ_SET(0) |          status = XHCI_TRB_2_IRQ_SET(0) |
             XHCI_TRB_2_TDSZ_SET(1) |              XHCI_TRB_2_TDSZ_SET(1) |
             XHCI_TRB_2_BYTES_SET(len);              XHCI_TRB_2_BYTES_SET(len);
         control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) |          control = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL) |
             XHCI_TRB_3_ISP_BIT | XHCI_TRB_3_IOC_BIT;              (usbd_xfer_isread(xfer) ? XHCI_TRB_3_ISP_BIT : 0) |
               XHCI_TRB_3_IOC_BIT;
         xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);          xhci_trb_put(&xx->xx_trb[i++], parameter, status, control);
   
           if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
                   callout_reset(&xfer->ux_callout, mstohz(xfer->ux_timeout),
                       xhci_timeout, xfer);
           }
           xfer->ux_status = USBD_IN_PROGRESS;
   
         mutex_enter(&tr->xr_lock);          mutex_enter(&tr->xr_lock);
         xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);          xhci_ring_put(sc, tr, xfer, xx->xx_trb, i);
         mutex_exit(&tr->xr_lock);          mutex_exit(&tr->xr_lock);
   
         xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);          xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
   
         if (sc->sc_bus.use_polling) {  
                 DPRINTFN(1, "polling", 0, 0, 0, 0);  
                 //xhci_waitintr(sc, xfer);  
         }  
   
         return USBD_IN_PROGRESS;          return USBD_IN_PROGRESS;
 }  }
   
 static void  static void
 xhci_device_intr_done(usbd_xfer_handle xfer)  xhci_device_intr_done(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc __diagused =          struct xhci_softc * const sc __diagused = XHCI_XFER2SC(xfer);
                 xfer->pipe->device->bus->hci_private;  
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         struct xhci_slot * const xs = xfer->pipe->device->hci_private;          struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
         const u_int dci = xhci_ep_get_dci(xfer->pipe->endpoint->edesc);          const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_edesc);
 #endif  #endif
         const u_int endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;          const int isread = usbd_xfer_isread(xfer);
         const bool isread = UE_GET_DIR(endpt) == UE_DIR_IN;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         DPRINTFN(15, "%p slot %u dci %u", xfer, xs->xs_idx, dci, 0);          DPRINTFN(15, "%p slot %u dci %u", xfer, xs->xs_idx, dci, 0);
   
         KASSERT(sc->sc_bus.use_polling || mutex_owned(&sc->sc_lock));          KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
   
         usb_syncmem(&xfer->dmabuf, 0, xfer->length,          usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
             isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);              isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
   
 #if 0  
         device_printf(sc->sc_dev, "");  
         for (size_t i = 0; i < xfer->length; i++) {  
                 printf(" %02x", ((uint8_t const *)xfer->buffer)[i]);  
         }  
         printf("\n");  
 #endif  
   
         if (xfer->pipe->repeat) {  
                 xfer->status = xhci_device_intr_start(xfer);  
         } else {  
                 callout_stop(&xfer->timeout_handle); /* XXX */  
         }  
   
 }  }
   
 static void  static void
 xhci_device_intr_abort(usbd_xfer_handle xfer)  xhci_device_intr_abort(struct usbd_xfer *xfer)
 {  {
         struct xhci_softc * const sc __diagused =          struct xhci_softc * const sc __diagused = XHCI_XFER2SC(xfer);
                                     xfer->pipe->device->bus->hci_private;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
   
         KASSERT(mutex_owned(&sc->sc_lock));          KASSERT(mutex_owned(&sc->sc_lock));
         DPRINTFN(15, "%p", xfer, 0, 0, 0);          DPRINTFN(15, "%p", xfer, 0, 0, 0);
         KASSERT(xfer->pipe->intrxfer == xfer);          KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
         xfer->status = USBD_CANCELLED;          xhci_abort_xfer(xfer, USBD_CANCELLED);
         usb_transfer_complete(xfer);  
 }  }
   
 static void  static void
 xhci_device_intr_close(usbd_pipe_handle pipe)  xhci_device_intr_close(struct usbd_pipe *pipe)
 {  {
         //struct xhci_softc * const sc = pipe->device->bus->hci_private;          //struct xhci_softc * const sc = XHCI_PIPE2SC(pipe);
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
         DPRINTFN(15, "%p", pipe, 0, 0, 0);          DPRINTFN(15, "%p", pipe, 0, 0, 0);
   
         xhci_unconfigure_endpoint(pipe);          xhci_close_pipe(pipe);
 }  }
   
 /* ------------ */  /* ------------ */
Line 2970  xhci_device_intr_close(usbd_pipe_handle 
Line 3924  xhci_device_intr_close(usbd_pipe_handle 
 static void  static void
 xhci_timeout(void *addr)  xhci_timeout(void *addr)
 {  {
         struct xhci_xfer * const xx = addr;  
         usbd_xfer_handle const xfer = &xx->xx_xfer;  
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
           struct xhci_xfer * const xx = addr;
           struct usbd_xfer * const xfer = &xx->xx_xfer;
           struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
           bool timeout = false;
   
           mutex_enter(&sc->sc_lock);
         if (sc->sc_dying) {          if (sc->sc_dying) {
                   mutex_exit(&sc->sc_lock);
                 return;                  return;
         }          }
           if (xfer->ux_status != USBD_CANCELLED) {
                   xfer->ux_status = USBD_TIMEOUT;
                   timeout = true;
           }
           mutex_exit(&sc->sc_lock);
   
           if (timeout) {
                   struct usbd_device *dev = xfer->ux_pipe->up_dev;
   
         usb_init_task(&xx->xx_abort_task, xhci_timeout_task, addr,                  /* Execute the abort in a process context. */
             USB_TASKQ_MPSAFE);                  usb_init_task(&xfer->ux_aborttask, xhci_timeout_task, xfer,
         usb_add_task(xx->xx_xfer.pipe->device, &xx->xx_abort_task,                      USB_TASKQ_MPSAFE);
             USB_TASKQ_HC);                  usb_add_task(dev, &xfer->ux_aborttask, USB_TASKQ_HC);
           }
 }  }
   
 static void  static void
 xhci_timeout_task(void *addr)  xhci_timeout_task(void *addr)
 {  {
         usbd_xfer_handle const xfer = addr;  
         struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;  
   
         XHCIHIST_FUNC(); XHCIHIST_CALLED();          XHCIHIST_FUNC(); XHCIHIST_CALLED();
           struct usbd_xfer * const xfer = addr;
           struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
   
         mutex_enter(&sc->sc_lock);          mutex_enter(&sc->sc_lock);
 #if 0          KASSERT(xfer->ux_status == USBD_TIMEOUT);
         xhci_abort_xfer(xfer, USBD_TIMEOUT);          xhci_abort_xfer(xfer, USBD_TIMEOUT);
 #else  
         xfer->status = USBD_TIMEOUT;  
         usb_transfer_complete(xfer);  
 #endif  
         mutex_exit(&sc->sc_lock);          mutex_exit(&sc->sc_lock);
 }  }

Legend:
Removed from v.1.28  
changed lines
  Added in v.1.28.2.81

CVSweb <webmaster@jp.NetBSD.org>