[BACK]Return to ehci.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/ehci.c between version 1.181 and 1.181.6.17

version 1.181, 2011/07/01 23:48:20 version 1.181.6.17, 2012/03/11 01:52:28
Line 1 
Line 1 
 /*      $NetBSD$ */  /*      $NetBSD$ */
   
 /*  /*
  * Copyright (c) 2004-2008 The NetBSD Foundation, Inc.   * Copyright (c) 2004-2012 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
  *   *
  * This code is derived from software contributed to The NetBSD Foundation   * This code is derived from software contributed to The NetBSD Foundation
  * by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum and   * by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum,
  * Jeremy Morse (jeremy.morse@gmail.com).   * Jeremy Morse (jeremy.morse@gmail.com), Jared D. McNeill
    * (jmcneill@invisible.ca) and Matthew R. Green (mrg@eterna.com.au).
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 61  __KERNEL_RCSID(0, "$NetBSD$");
Line 62  __KERNEL_RCSID(0, "$NetBSD$");
 #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/malloc.h>  #include <sys/kmem.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>
 #include <sys/queue.h>  #include <sys/queue.h>
 #include <sys/mutex.h>  #include <sys/mutex.h>
 #include <sys/bus.h>  #include <sys/bus.h>
   #include <sys/cpu.h>
   
 #include <machine/endian.h>  #include <machine/endian.h>
   
Line 82  __KERNEL_RCSID(0, "$NetBSD$");
Line 84  __KERNEL_RCSID(0, "$NetBSD$");
 #include <dev/usb/usbroothub_subr.h>  #include <dev/usb/usbroothub_subr.h>
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
 #define DPRINTF(x)      do { if (ehcidebug) printf x; } while(0)  #include <sys/kprintf.h>
 #define DPRINTFN(n,x)   do { if (ehcidebug>(n)) printf x; } while (0)  static void
   ehciprintf(const char *fmt, ...)
   {
           va_list ap;
   
           va_start(ap, fmt);
           kprintf(fmt, TOLOG|TOCONS, NULL, NULL, ap);
           va_end(ap);
   }
   
   #define DPRINTF(x)      do { if (ehcidebug) ehciprintf x; } while(0)
   #define DPRINTFN(n,x)   do { if (ehcidebug>(n)) ehciprintf x; } while (0)
 int ehcidebug = 0;  int ehcidebug = 0;
 #else  #else
 #define DPRINTF(x)  #define DPRINTF(x)
Line 133  Static void  ehci_idone(struct ehci_xfer
Line 146  Static void  ehci_idone(struct ehci_xfer
 Static void             ehci_timeout(void *);  Static void             ehci_timeout(void *);
 Static void             ehci_timeout_task(void *);  Static void             ehci_timeout_task(void *);
 Static void             ehci_intrlist_timeout(void *);  Static void             ehci_intrlist_timeout(void *);
   Static void             ehci_doorbell(void *);
   Static void             ehci_pcd(void *);
   
 Static usbd_status      ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);  Static usbd_status      ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
 Static void             ehci_freem(struct usbd_bus *, usb_dma_t *);  Static void             ehci_freem(struct usbd_bus *, usb_dma_t *);
   
 Static usbd_xfer_handle ehci_allocx(struct usbd_bus *);  Static usbd_xfer_handle ehci_allocx(struct usbd_bus *);
 Static void             ehci_freex(struct usbd_bus *, usbd_xfer_handle);  Static void             ehci_freex(struct usbd_bus *, usbd_xfer_handle);
   Static void             ehci_get_lock(struct usbd_bus *, kmutex_t **);
   
 Static usbd_status      ehci_root_ctrl_transfer(usbd_xfer_handle);  Static usbd_status      ehci_root_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status      ehci_root_ctrl_start(usbd_xfer_handle);  Static usbd_status      ehci_root_ctrl_start(usbd_xfer_handle);
Line 179  Static void  ehci_device_isoc_done(usbd_
Line 195  Static void  ehci_device_isoc_done(usbd_
 Static void             ehci_device_clear_toggle(usbd_pipe_handle pipe);  Static void             ehci_device_clear_toggle(usbd_pipe_handle pipe);
 Static void             ehci_noop(usbd_pipe_handle pipe);  Static void             ehci_noop(usbd_pipe_handle pipe);
   
 Static void             ehci_pcd(ehci_softc_t *, usbd_xfer_handle);  
 Static void             ehci_disown(ehci_softc_t *, int, int);  Static void             ehci_disown(ehci_softc_t *, int, int);
   
 Static ehci_soft_qh_t  *ehci_alloc_sqh(ehci_softc_t *);  Static ehci_soft_qh_t  *ehci_alloc_sqh(ehci_softc_t *);
Line 205  Static usbd_status ehci_device_request(u
Line 220  Static usbd_status ehci_device_request(u
 Static usbd_status      ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *,  Static usbd_status      ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *,
                             int ival);                              int ival);
   
 Static void             ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *);  Static void             ehci_add_qh(ehci_softc_t *, ehci_soft_qh_t *,
                                       ehci_soft_qh_t *);
 Static void             ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *,  Static void             ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *,
                                     ehci_soft_qh_t *);                                      ehci_soft_qh_t *);
 Static void             ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *);  Static void             ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *);
Line 246  Static void  ehci_dump_exfer(struct ehci
Line 262  Static void  ehci_dump_exfer(struct ehci
 #define ehci_active_intr_list(ex) ((ex)->inext.tqe_prev != NULL)  #define ehci_active_intr_list(ex) ((ex)->inext.tqe_prev != NULL)
   
 Static const struct usbd_bus_methods ehci_bus_methods = {  Static const struct usbd_bus_methods ehci_bus_methods = {
         ehci_open,          .open_pipe =    ehci_open,
         ehci_softintr,          .soft_intr =    ehci_softintr,
         ehci_poll,          .do_poll =      ehci_poll,
         ehci_allocm,          .allocm =       ehci_allocm,
         ehci_freem,          .freem =        ehci_freem,
         ehci_allocx,          .allocx =       ehci_allocx,
         ehci_freex,          .freex =        ehci_freex,
           .get_lock =     ehci_get_lock,
 };  };
   
 Static const struct usbd_pipe_methods ehci_root_ctrl_methods = {  Static const struct usbd_pipe_methods ehci_root_ctrl_methods = {
         ehci_root_ctrl_transfer,          .transfer =     ehci_root_ctrl_transfer,
         ehci_root_ctrl_start,          .start =        ehci_root_ctrl_start,
         ehci_root_ctrl_abort,          .abort =        ehci_root_ctrl_abort,
         ehci_root_ctrl_close,          .close =        ehci_root_ctrl_close,
         ehci_noop,          .cleartoggle =  ehci_noop,
         ehci_root_ctrl_done,          .done =         ehci_root_ctrl_done,
 };  };
   
 Static const struct usbd_pipe_methods ehci_root_intr_methods = {  Static const struct usbd_pipe_methods ehci_root_intr_methods = {
         ehci_root_intr_transfer,          .transfer =     ehci_root_intr_transfer,
         ehci_root_intr_start,          .start =        ehci_root_intr_start,
         ehci_root_intr_abort,          .abort =        ehci_root_intr_abort,
         ehci_root_intr_close,          .close =        ehci_root_intr_close,
         ehci_noop,          .cleartoggle =  ehci_noop,
         ehci_root_intr_done,          .done =         ehci_root_intr_done,
 };  };
   
 Static const struct usbd_pipe_methods ehci_device_ctrl_methods = {  Static const struct usbd_pipe_methods ehci_device_ctrl_methods = {
         ehci_device_ctrl_transfer,          .transfer =     ehci_device_ctrl_transfer,
         ehci_device_ctrl_start,          .start =        ehci_device_ctrl_start,
         ehci_device_ctrl_abort,          .abort =        ehci_device_ctrl_abort,
         ehci_device_ctrl_close,          .close =        ehci_device_ctrl_close,
         ehci_noop,          .cleartoggle =  ehci_noop,
         ehci_device_ctrl_done,          .done =         ehci_device_ctrl_done,
 };  };
   
 Static const struct usbd_pipe_methods ehci_device_intr_methods = {  Static const struct usbd_pipe_methods ehci_device_intr_methods = {
         ehci_device_intr_transfer,          .transfer =     ehci_device_intr_transfer,
         ehci_device_intr_start,          .start =        ehci_device_intr_start,
         ehci_device_intr_abort,          .abort =        ehci_device_intr_abort,
         ehci_device_intr_close,          .close =        ehci_device_intr_close,
         ehci_device_clear_toggle,          .cleartoggle =  ehci_device_clear_toggle,
         ehci_device_intr_done,          .done =         ehci_device_intr_done,
 };  };
   
 Static const struct usbd_pipe_methods ehci_device_bulk_methods = {  Static const struct usbd_pipe_methods ehci_device_bulk_methods = {
         ehci_device_bulk_transfer,          .transfer =     ehci_device_bulk_transfer,
         ehci_device_bulk_start,          .start =        ehci_device_bulk_start,
         ehci_device_bulk_abort,          .abort =        ehci_device_bulk_abort,
         ehci_device_bulk_close,          .close =        ehci_device_bulk_close,
         ehci_device_clear_toggle,          .cleartoggle =  ehci_device_clear_toggle,
         ehci_device_bulk_done,          .done =         ehci_device_bulk_done,
 };  };
   
 Static const struct usbd_pipe_methods ehci_device_isoc_methods = {  Static const struct usbd_pipe_methods ehci_device_isoc_methods = {
         ehci_device_isoc_transfer,          .transfer =     ehci_device_isoc_transfer,
         ehci_device_isoc_start,          .start =        ehci_device_isoc_start,
         ehci_device_isoc_abort,          .abort =        ehci_device_isoc_abort,
         ehci_device_isoc_close,          .close =        ehci_device_isoc_close,
         ehci_noop,          .cleartoggle =  ehci_noop,
         ehci_device_isoc_done,          .done =         ehci_device_isoc_done,
 };  };
   
 static const uint8_t revbits[EHCI_MAX_POLLRATE] = {  static const uint8_t revbits[EHCI_MAX_POLLRATE] = {
Line 334  ehci_init(ehci_softc_t *sc)
Line 351  ehci_init(ehci_softc_t *sc)
         theehci = sc;          theehci = sc;
 #endif  #endif
   
           mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
           mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
           cv_init(&sc->sc_softwake_cv, "ehciab");
           cv_init(&sc->sc_doorbell, "ehcidi");
   
           sc->sc_doorbell_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
               ehci_doorbell, sc);
           sc->sc_pcd_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
               ehci_pcd, sc);
   
         sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);          sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
   
         vers = EREAD2(sc, EHCI_HCIVERSION);          vers = EREAD2(sc, EHCI_HCIVERSION);
Line 431  ehci_init(ehci_softc_t *sc)
Line 458  ehci_init(ehci_softc_t *sc)
   
         EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));          EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
   
         sc->sc_softitds = malloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *),          sc->sc_softitds = kmem_zalloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *),
                                         M_USB, M_NOWAIT | M_ZERO);                                       KM_SLEEP);
         if (sc->sc_softitds == NULL)          if (sc->sc_softitds == NULL)
                 return ENOMEM;                  return ENOMEM;
         LIST_INIT(&sc->sc_freeitds);          LIST_INIT(&sc->sc_freeitds);
         TAILQ_INIT(&sc->sc_intrhead);          TAILQ_INIT(&sc->sc_intrhead);
         mutex_init(&sc->sc_intrhead_lock, MUTEX_DEFAULT, IPL_USB);  
   
         /* Set up the bus struct. */          /* Set up the bus struct. */
         sc->sc_bus.methods = &ehci_bus_methods;          sc->sc_bus.methods = &ehci_bus_methods;
Line 522  ehci_init(ehci_softc_t *sc)
Line 548  ehci_init(ehci_softc_t *sc)
         sc->sc_async_head = sqh;          sc->sc_async_head = sqh;
         EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);          EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);
   
         callout_init(&(sc->sc_tmo_intrlist), 0);          callout_init(&sc->sc_tmo_intrlist, CALLOUT_MPSAFE);
   
         mutex_init(&sc->sc_doorbell_lock, MUTEX_DEFAULT, IPL_NONE);  
   
         /* Turn on controller */          /* Turn on controller */
         EOWRITE4(sc, EHCI_USBCMD,          EOWRITE4(sc, EHCI_USBCMD,
Line 567  int
Line 591  int
 ehci_intr(void *v)  ehci_intr(void *v)
 {  {
         ehci_softc_t *sc = v;          ehci_softc_t *sc = v;
           int ret = 0;
   
         if (sc == NULL || sc->sc_dying || !device_has_power(sc->sc_dev))          if (sc == NULL)
                 return (0);                  return 0;
   
           mutex_spin_enter(&sc->sc_intr_lock);
   
           if (sc->sc_dying || !device_has_power(sc->sc_dev))
                   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.use_polling) {
Line 580  ehci_intr(void *v)
Line 610  ehci_intr(void *v)
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n"));                  DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n"));
 #endif  #endif
                 return (0);                  goto done;
         }          }
   
         return (ehci_intr1(sc));          ret = ehci_intr1(sc);
   
   done:
           mutex_spin_exit(&sc->sc_intr_lock);
           return ret;
 }  }
   
 Static int  Static int
Line 601  ehci_intr1(ehci_softc_t *sc)
Line 635  ehci_intr1(ehci_softc_t *sc)
                 return (0);                  return (0);
         }          }
   
           KASSERT(mutex_owned(&sc->sc_intr_lock));
   
         intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));          intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
         if (!intrs)          if (!intrs)
                 return (0);                  return (0);
Line 613  ehci_intr1(ehci_softc_t *sc)
Line 649  ehci_intr1(ehci_softc_t *sc)
                 return (0);                  return (0);
   
         EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */          EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */
         sc->sc_bus.intr_context++;  
         sc->sc_bus.no_intrs++;          sc->sc_bus.no_intrs++;
         if (eintrs & EHCI_STS_IAA) {          if (eintrs & EHCI_STS_IAA) {
                 DPRINTF(("ehci_intr1: door bell\n"));                  DPRINTF(("ehci_intr1: door bell\n"));
                 wakeup(&sc->sc_async_head);                  kpreempt_disable();
                   softint_schedule(sc->sc_doorbell_si);
                   kpreempt_enable();
                 eintrs &= ~EHCI_STS_IAA;                  eintrs &= ~EHCI_STS_IAA;
         }          }
         if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) {          if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) {
Line 633  ehci_intr1(ehci_softc_t *sc)
Line 670  ehci_intr1(ehci_softc_t *sc)
                 /* XXX what else */                  /* XXX what else */
         }          }
         if (eintrs & EHCI_STS_PCD) {          if (eintrs & EHCI_STS_PCD) {
                 ehci_pcd(sc, sc->sc_intrxfer);                  kpreempt_disable();
                   softint_schedule(sc->sc_pcd_si);
                   kpreempt_enable();
                 eintrs &= ~EHCI_STS_PCD;                  eintrs &= ~EHCI_STS_PCD;
         }          }
   
         sc->sc_bus.intr_context--;  
   
         if (eintrs != 0) {          if (eintrs != 0) {
                 /* Block unprocessed interrupts. */                  /* Block unprocessed interrupts. */
                 sc->sc_eintrs &= ~eintrs;                  sc->sc_eintrs &= ~eintrs;
Line 650  ehci_intr1(ehci_softc_t *sc)
Line 687  ehci_intr1(ehci_softc_t *sc)
         return (1);          return (1);
 }  }
   
   Static void
   ehci_doorbell(void *addr)
   {
           ehci_softc_t *sc = addr;
   
           mutex_enter(&sc->sc_lock);
           cv_broadcast(&sc->sc_doorbell);
           mutex_exit(&sc->sc_lock);
   }
   
 Static void  Static void
 ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)  ehci_pcd(void *addr)
 {  {
           ehci_softc_t *sc = addr;
           usbd_xfer_handle xfer;
         usbd_pipe_handle pipe;          usbd_pipe_handle pipe;
         u_char *p;          u_char *p;
         int i, m;          int i, m;
   
           mutex_enter(&sc->sc_lock);
           xfer = sc->sc_intrxfer;
   
         if (xfer == NULL) {          if (xfer == NULL) {
                 /* Just ignore the change. */                  /* Just ignore the change. */
                 return;                  goto done;
         }          }
   
         pipe = xfer->pipe;          pipe = xfer->pipe;
Line 678  ehci_pcd(ehci_softc_t *sc, usbd_xfer_han
Line 729  ehci_pcd(ehci_softc_t *sc, usbd_xfer_han
         xfer->status = USBD_NORMAL_COMPLETION;          xfer->status = USBD_NORMAL_COMPLETION;
   
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
   
   done:
           mutex_exit(&sc->sc_lock);
 }  }
   
 Static void  Static void
Line 687  ehci_softintr(void *v)
Line 741  ehci_softintr(void *v)
         ehci_softc_t *sc = bus->hci_private;          ehci_softc_t *sc = bus->hci_private;
         struct ehci_xfer *ex, *nextex;          struct ehci_xfer *ex, *nextex;
   
         DPRINTFN(10,("%s: ehci_softintr (%d)\n", device_xname(sc->sc_dev),          KASSERT(sc->sc_bus.use_polling || mutex_owned(&sc->sc_lock));
                      sc->sc_bus.intr_context));  
   
         sc->sc_bus.intr_context++;          DPRINTFN(10,("%s: ehci_softintr\n", device_xname(sc->sc_dev)));
   
         /*          /*
          * The only explanation I can think of for why EHCI is as brain dead           * The only explanation I can think of for why EHCI is as brain dead
Line 706  ehci_softintr(void *v)
Line 759  ehci_softintr(void *v)
         /* Schedule a callout to catch any dropped transactions. */          /* Schedule a callout to catch any dropped transactions. */
         if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) &&          if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) &&
             !TAILQ_EMPTY(&sc->sc_intrhead))              !TAILQ_EMPTY(&sc->sc_intrhead))
                 callout_reset(&(sc->sc_tmo_intrlist),                  callout_reset(&sc->sc_tmo_intrlist,
                     (hz), (ehci_intrlist_timeout), (sc));                      hz, ehci_intrlist_timeout, sc);
   
 #ifdef USB_USE_SOFTINTR  
         if (sc->sc_softwake) {          if (sc->sc_softwake) {
                 sc->sc_softwake = 0;                  sc->sc_softwake = 0;
                 wakeup(&sc->sc_softwake);                  cv_broadcast(&sc->sc_softwake_cv);
         }          }
 #endif /* USB_USE_SOFTINTR */  
   
         sc->sc_bus.intr_context--;  
 }  }
   
 /* Check for an interrupt. */  /* Check for an interrupt. */
Line 727  ehci_check_intr(ehci_softc_t *sc, struct
Line 776  ehci_check_intr(ehci_softc_t *sc, struct
   
         DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex));          DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex));
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         attr = ex->xfer.pipe->endpoint->edesc->bmAttributes;          attr = ex->xfer.pipe->endpoint->edesc->bmAttributes;
         if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS)          if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS)
                 ehci_check_itd_intr(sc, ex);                  ehci_check_itd_intr(sc, ex);
Line 742  ehci_check_qh_intr(ehci_softc_t *sc, str
Line 793  ehci_check_qh_intr(ehci_softc_t *sc, str
         ehci_soft_qtd_t *sqtd, *lsqtd;          ehci_soft_qtd_t *sqtd, *lsqtd;
         __uint32_t status;          __uint32_t status;
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         if (ex->sqtdstart == NULL) {          if (ex->sqtdstart == NULL) {
                 printf("ehci_check_qh_intr: not valid sqtd\n");                  printf("ehci_check_qh_intr: not valid sqtd\n");
                 return;                  return;
Line 798  ehci_check_qh_intr(ehci_softc_t *sc, str
Line 851  ehci_check_qh_intr(ehci_softc_t *sc, str
 }  }
   
 Static void  Static void
 ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) {  ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
   {
         ehci_soft_itd_t *itd;          ehci_soft_itd_t *itd;
         int i;          int i;
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue))          if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue))
                 return;                  return;
   
Line 849  ehci_idone(struct ehci_xfer *ex)
Line 905  ehci_idone(struct ehci_xfer *ex)
 {  {
         usbd_xfer_handle xfer = &ex->xfer;          usbd_xfer_handle xfer = &ex->xfer;
         struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;          struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
           struct ehci_softc *sc = xfer->pipe->device->bus->hci_private;
         ehci_soft_qtd_t *sqtd, *lsqtd;          ehci_soft_qtd_t *sqtd, *lsqtd;
         u_int32_t status = 0, nstatus = 0;          u_int32_t status = 0, nstatus = 0;
         int actlen;          int actlen;
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));          DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         {          {
                 int s = splhigh();  
                 if (ex->isdone) {                  if (ex->isdone) {
                         splx(s);  
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
                         printf("ehci_idone: ex is done!\n   ");                          printf("ehci_idone: ex is done!\n   ");
                         ehci_dump_exfer(ex);                          ehci_dump_exfer(ex);
Line 868  ehci_idone(struct ehci_xfer *ex)
Line 926  ehci_idone(struct ehci_xfer *ex)
                         return;                          return;
                 }                  }
                 ex->isdone = 1;                  ex->isdone = 1;
                 splx(s);  
         }          }
 #endif  #endif
         if (xfer->status == USBD_CANCELLED ||          if (xfer->status == USBD_CANCELLED ||
Line 999  ehci_idone(struct ehci_xfer *ex)
Line 1056  ehci_idone(struct ehci_xfer *ex)
                 }                  }
                 /* XXX need to reset TT on missed microframe */                  /* XXX need to reset TT on missed microframe */
                 if (status & EHCI_QTD_MISSEDMICRO) {                  if (status & EHCI_QTD_MISSEDMICRO) {
                         ehci_softc_t *sc =  
                             xfer->pipe->device->bus->hci_private;  
   
                         printf("%s: missed microframe, TT reset not "                          printf("%s: missed microframe, TT reset not "
                             "implemented, hub might be inoperational\n",                              "implemented, hub might be inoperational\n",
                             device_xname(sc->sc_dev));                              device_xname(sc->sc_dev));
Line 1042  ehci_waitintr(ehci_softc_t *sc, usbd_xfe
Line 1096  ehci_waitintr(ehci_softc_t *sc, usbd_xfe
                         ehci_dump_regs(sc);                          ehci_dump_regs(sc);
 #endif  #endif
                 if (intrs) {                  if (intrs) {
                           mutex_spin_enter(&sc->sc_intr_lock);
                         ehci_intr1(sc);                          ehci_intr1(sc);
                           mutex_spin_exit(&sc->sc_intr_lock);
                         if (xfer->status != USBD_IN_PROGRESS)                          if (xfer->status != USBD_IN_PROGRESS)
                                 return;                                  return;
                 }                  }
Line 1051  ehci_waitintr(ehci_softc_t *sc, usbd_xfe
Line 1107  ehci_waitintr(ehci_softc_t *sc, usbd_xfe
         /* Timeout */          /* Timeout */
         DPRINTF(("ehci_waitintr: timeout\n"));          DPRINTF(("ehci_waitintr: timeout\n"));
         xfer->status = USBD_TIMEOUT;          xfer->status = USBD_TIMEOUT;
           mutex_enter(&sc->sc_lock);
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
           mutex_exit(&sc->sc_lock);
         /* XXX should free TD */          /* XXX should free TD */
 }  }
   
Line 1069  ehci_poll(struct usbd_bus *bus)
Line 1127  ehci_poll(struct usbd_bus *bus)
         }          }
 #endif  #endif
   
         if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs)          if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs) {
                   mutex_spin_enter(&sc->sc_intr_lock);
                 ehci_intr1(sc);                  ehci_intr1(sc);
                   mutex_spin_exit(&sc->sc_intr_lock);
           }
 }  }
   
 void  void
Line 1085  ehci_childdet(device_t self, device_t ch
Line 1146  ehci_childdet(device_t self, device_t ch
 int  int
 ehci_detach(struct ehci_softc *sc, int flags)  ehci_detach(struct ehci_softc *sc, int flags)
 {  {
           usbd_xfer_handle xfer;
         int rv = 0;          int rv = 0;
   
         if (sc->sc_child != NULL)          if (sc->sc_child != NULL)
Line 1093  ehci_detach(struct ehci_softc *sc, int f
Line 1155  ehci_detach(struct ehci_softc *sc, int f
         if (rv != 0)          if (rv != 0)
                 return (rv);                  return (rv);
   
         callout_stop(&sc->sc_tmo_intrlist);          callout_halt(&sc->sc_tmo_intrlist, NULL);
           callout_destroy(&sc->sc_tmo_intrlist);
         usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */  
   
         /* XXX free other data structures XXX */          /* XXX free other data structures XXX */
         mutex_destroy(&sc->sc_doorbell_lock);          if (sc->sc_softitds)
         mutex_destroy(&sc->sc_intrhead_lock);                  kmem_free(sc->sc_softitds,
                       sc->sc_flsize * sizeof(ehci_soft_itd_t *));
           cv_destroy(&sc->sc_doorbell);
           cv_destroy(&sc->sc_softwake_cv);
   
           softint_disestablish(sc->sc_doorbell_si);
           softint_disestablish(sc->sc_pcd_si);
   
           while ((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) {
                   SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
                   kmem_free(xfer, sizeof(struct ehci_xfer));
           }
   
         EOWRITE4(sc, EHCI_CONFIGFLAG, 0);          EOWRITE4(sc, EHCI_CONFIGFLAG, 0);
   
Line 1135  bool
Line 1207  bool
 ehci_suspend(device_t dv, const pmf_qual_t *qual)  ehci_suspend(device_t dv, const pmf_qual_t *qual)
 {  {
         ehci_softc_t *sc = device_private(dv);          ehci_softc_t *sc = device_private(dv);
         int i, s;          int i;
         uint32_t cmd, hcr;          uint32_t cmd, hcr;
   
         s = splhardusb();          mutex_spin_enter(&sc->sc_intr_lock);
   
         sc->sc_bus.use_polling++;          sc->sc_bus.use_polling++;
           mutex_spin_exit(&sc->sc_intr_lock);
   
         for (i = 1; i <= sc->sc_noport; i++) {          for (i = 1; i <= sc->sc_noport; i++) {
                 cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR;                  cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR;
Line 1176  ehci_suspend(device_t dv, const pmf_qual
Line 1248  ehci_suspend(device_t dv, const pmf_qual
         if (hcr != EHCI_STS_HCH)          if (hcr != EHCI_STS_HCH)
                 printf("%s: config timeout\n", device_xname(dv));                  printf("%s: config timeout\n", device_xname(dv));
   
           mutex_spin_enter(&sc->sc_intr_lock);
         sc->sc_bus.use_polling--;          sc->sc_bus.use_polling--;
         splx(s);          mutex_spin_exit(&sc->sc_intr_lock);
   
         return true;          return true;
 }  }
Line 1296  ehci_allocx(struct usbd_bus *bus)
Line 1369  ehci_allocx(struct usbd_bus *bus)
                 }                  }
 #endif  #endif
         } else {          } else {
                 xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT);                  xfer = kmem_alloc(sizeof(struct ehci_xfer), KM_SLEEP);
         }          }
         if (xfer != NULL) {          if (xfer != NULL) {
                 memset(xfer, 0, sizeof(struct ehci_xfer));                  memset(xfer, 0, sizeof(struct ehci_xfer));
Line 1327  ehci_freex(struct usbd_bus *bus, usbd_xf
Line 1400  ehci_freex(struct usbd_bus *bus, usbd_xf
 }  }
   
 Static void  Static void
   ehci_get_lock(struct usbd_bus *bus, kmutex_t **lock)
   {
           struct ehci_softc *sc = bus->hci_private;
   
           *lock = &sc->sc_lock;
   }
   
   Static void
 ehci_device_clear_toggle(usbd_pipe_handle pipe)  ehci_device_clear_toggle(usbd_pipe_handle pipe)
 {  {
         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;          struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
Line 1540  ehci_open(usbd_pipe_handle pipe)
Line 1621  ehci_open(usbd_pipe_handle pipe)
         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;          struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
         ehci_soft_qh_t *sqh;          ehci_soft_qh_t *sqh;
         usbd_status err;          usbd_status err;
         int s;  
         int ival, speed, naks;          int ival, speed, naks;
         int hshubaddr, hshubport;          int hshubaddr, hshubport;
   
Line 1665  ehci_open(usbd_pipe_handle pipe)
Line 1745  ehci_open(usbd_pipe_handle pipe)
                 if (err)                  if (err)
                         goto bad;                          goto bad;
                 pipe->methods = &ehci_device_ctrl_methods;                  pipe->methods = &ehci_device_ctrl_methods;
                 s = splusb();                  mutex_enter(&sc->sc_lock);
                 ehci_add_qh(sqh, sc->sc_async_head);                  ehci_add_qh(sc, sqh, sc->sc_async_head);
                 splx(s);                  mutex_exit(&sc->sc_lock);
                 break;                  break;
         case UE_BULK:          case UE_BULK:
                 pipe->methods = &ehci_device_bulk_methods;                  pipe->methods = &ehci_device_bulk_methods;
                 s = splusb();                  mutex_enter(&sc->sc_lock);
                 ehci_add_qh(sqh, sc->sc_async_head);                  ehci_add_qh(sc, sqh, sc->sc_async_head);
                 splx(s);                  mutex_exit(&sc->sc_lock);
                 break;                  break;
         case UE_INTERRUPT:          case UE_INTERRUPT:
                 pipe->methods = &ehci_device_intr_methods;                  pipe->methods = &ehci_device_intr_methods;
Line 1725  ehci_open(usbd_pipe_handle pipe)
Line 1805  ehci_open(usbd_pipe_handle pipe)
 }  }
   
 /*  /*
  * Add an ED to the schedule.  Called at splusb().   * Add an ED to the schedule.  Called with USB lock held.
  */   */
 Static void  Static void
 ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)  ehci_add_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
 {  {
         SPLUSBCHECK;  
           KASSERT(mutex_owned(&sc->sc_lock));
   
         usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link),          usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link),
             sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE);              sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE);
Line 1752  ehci_add_qh(ehci_soft_qh_t *sqh, ehci_so
Line 1833  ehci_add_qh(ehci_soft_qh_t *sqh, ehci_so
 }  }
   
 /*  /*
  * Remove an ED from the schedule.  Called at splusb().   * Remove an ED from the schedule.  Called with USB lock held.
  */   */
 Static void  Static void
 ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)  ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
 {  {
         ehci_soft_qh_t *p;          ehci_soft_qh_t *p;
   
         SPLUSBCHECK;          KASSERT(mutex_owned(&sc->sc_lock));
   
         /* XXX */          /* XXX */
         for (p = head; p != NULL && p->next != sqh; p = p->next)          for (p = head; p != NULL && p->next != sqh; p = p->next)
                 ;                  ;
Line 1819  ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehc
Line 1901  ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehc
 Static void  Static void
 ehci_sync_hc(ehci_softc_t *sc)  ehci_sync_hc(ehci_softc_t *sc)
 {  {
         int s, error;          int error;
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         if (sc->sc_dying) {          if (sc->sc_dying) {
                 DPRINTFN(2,("ehci_sync_hc: dying\n"));                  DPRINTFN(2,("ehci_sync_hc: dying\n"));
                 return;                  return;
         }          }
         DPRINTFN(2,("ehci_sync_hc: enter\n"));          DPRINTFN(2,("ehci_sync_hc: enter\n"));
         mutex_enter(&sc->sc_doorbell_lock);     /* get doorbell */  
         s = splhardusb();  
         /* ask for doorbell */          /* ask for doorbell */
         EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD);          EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD);
         DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",          DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
                     EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));                      EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
         error = tsleep(&sc->sc_async_head, PZERO, "ehcidi", hz); /* bell wait */          error = cv_timedwait(&sc->sc_doorbell, &sc->sc_lock, hz); /* bell wait */
         DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",          DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
                     EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));                      EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
         splx(s);  
         mutex_exit(&sc->sc_doorbell_lock);      /* release doorbell */  
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (error)          if (error)
                 printf("ehci_sync_hc: tsleep() = %d\n", error);                  printf("ehci_sync_hc: cv_timedwait() = %d\n", error);
 #endif  #endif
         DPRINTFN(2,("ehci_sync_hc: exit\n"));          DPRINTFN(2,("ehci_sync_hc: exit\n"));
 }  }
   
 /*Call at splusb*/  
 Static void  Static void
 ehci_rem_free_itd_chain(ehci_softc_t *sc, struct ehci_xfer *exfer)  ehci_rem_free_itd_chain(ehci_softc_t *sc, struct ehci_xfer *exfer)
 {  {
Line 1974  Static const usb_hub_descriptor_t ehci_h
Line 2053  Static const usb_hub_descriptor_t ehci_h
 Static usbd_status  Static usbd_status
 ehci_root_ctrl_transfer(usbd_xfer_handle xfer)  ehci_root_ctrl_transfer(usbd_xfer_handle xfer)
 {  {
           ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
         usbd_status err;          usbd_status err;
   
         /* Insert last in queue. */          /* Insert last in queue. */
           mutex_enter(&sc->sc_lock);
         err = usb_insert_transfer(xfer);          err = usb_insert_transfer(xfer);
           mutex_exit(&sc->sc_lock);
         if (err)          if (err)
                 return (err);                  return (err);
   
Line 1992  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 2074  ehci_root_ctrl_start(usbd_xfer_handle xf
         usb_device_request_t *req;          usb_device_request_t *req;
         void *buf = NULL;          void *buf = NULL;
         int port, i;          int port, i;
         int s, len, value, index, l, totlen = 0;          int len, value, index, l, totlen = 0;
         usb_port_status_t ps;          usb_port_status_t ps;
         usb_hub_descriptor_t hubd;          usb_hub_descriptor_t hubd;
         usbd_status err;          usbd_status err;
Line 2414  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 2496  ehci_root_ctrl_start(usbd_xfer_handle xf
         xfer->actlen = totlen;          xfer->actlen = totlen;
         err = USBD_NORMAL_COMPLETION;          err = USBD_NORMAL_COMPLETION;
  ret:   ret:
           mutex_enter(&sc->sc_lock);
         xfer->status = err;          xfer->status = err;
         s = splusb();  
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         splx(s);          mutex_exit(&sc->sc_lock);
         return (USBD_IN_PROGRESS);          return (USBD_IN_PROGRESS);
 }  }
   
Line 2473  ehci_root_intr_done(usbd_xfer_handle xfe
Line 2555  ehci_root_intr_done(usbd_xfer_handle xfe
 Static usbd_status  Static usbd_status
 ehci_root_intr_transfer(usbd_xfer_handle xfer)  ehci_root_intr_transfer(usbd_xfer_handle xfer)
 {  {
           ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
         usbd_status err;          usbd_status err;
   
         /* Insert last in queue. */          /* Insert last in queue. */
           mutex_enter(&sc->sc_lock);
         err = usb_insert_transfer(xfer);          err = usb_insert_transfer(xfer);
           mutex_exit(&sc->sc_lock);
         if (err)          if (err)
                 return (err);                  return (err);
   
Line 2493  ehci_root_intr_start(usbd_xfer_handle xf
Line 2578  ehci_root_intr_start(usbd_xfer_handle xf
         if (sc->sc_dying)          if (sc->sc_dying)
                 return (USBD_IOERROR);                  return (USBD_IOERROR);
   
           mutex_enter(&sc->sc_lock);
         sc->sc_intrxfer = xfer;          sc->sc_intrxfer = xfer;
           mutex_exit(&sc->sc_lock);
   
         return (USBD_IN_PROGRESS);          return (USBD_IN_PROGRESS);
 }  }
Line 2502  ehci_root_intr_start(usbd_xfer_handle xf
Line 2589  ehci_root_intr_start(usbd_xfer_handle xf
 Static void  Static void
 ehci_root_intr_abort(usbd_xfer_handle xfer)  ehci_root_intr_abort(usbd_xfer_handle xfer)
 {  {
         int s;          ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
   
           KASSERT(mutex_owned(&sc->sc_lock));
         if (xfer->pipe->intrxfer == xfer) {          if (xfer->pipe->intrxfer == xfer) {
                 DPRINTF(("ehci_root_intr_abort: remove\n"));                  DPRINTF(("ehci_root_intr_abort: remove\n"));
                 xfer->pipe->intrxfer = NULL;                  xfer->pipe->intrxfer = NULL;
         }          }
         xfer->status = USBD_CANCELLED;          xfer->status = USBD_CANCELLED;
         s = splusb();  
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         splx(s);  
 }  }
   
 /* Close the root pipe. */  /* Close the root pipe. */
Line 2520  ehci_root_intr_close(usbd_pipe_handle pi
Line 2606  ehci_root_intr_close(usbd_pipe_handle pi
 {  {
         ehci_softc_t *sc = pipe->device->bus->hci_private;          ehci_softc_t *sc = pipe->device->bus->hci_private;
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         DPRINTF(("ehci_root_intr_close\n"));          DPRINTF(("ehci_root_intr_close\n"));
   
         sc->sc_intrxfer = NULL;          sc->sc_intrxfer = NULL;
Line 2578  ehci_free_sqh(ehci_softc_t *sc, ehci_sof
Line 2666  ehci_free_sqh(ehci_softc_t *sc, ehci_sof
 Static ehci_soft_qtd_t *  Static ehci_soft_qtd_t *
 ehci_alloc_sqtd(ehci_softc_t *sc)  ehci_alloc_sqtd(ehci_softc_t *sc)
 {  {
         ehci_soft_qtd_t *sqtd;          ehci_soft_qtd_t *sqtd = NULL;
         usbd_status err;          usbd_status err;
         int i, offs;          int i, offs;
         usb_dma_t dma;          usb_dma_t dma;
         int s;  
   
         if (sc->sc_freeqtds == NULL) {          if (sc->sc_freeqtds == NULL) {
                 DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));                  DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));
   
                 err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,                  err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,
                           EHCI_PAGE_SIZE, &dma);                            EHCI_PAGE_SIZE, &dma);
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
Line 2593  ehci_alloc_sqtd(ehci_softc_t *sc)
Line 2681  ehci_alloc_sqtd(ehci_softc_t *sc)
                         printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err);                          printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err);
 #endif  #endif
                 if (err)                  if (err)
                         return (NULL);                          goto done;
                 s = splusb();  
                 for(i = 0; i < EHCI_SQTD_CHUNK; i++) {                  for(i = 0; i < EHCI_SQTD_CHUNK; i++) {
                         offs = i * EHCI_SQTD_SIZE;                          offs = i * EHCI_SQTD_SIZE;
                         sqtd = KERNADDR(&dma, offs);                          sqtd = KERNADDR(&dma, offs);
                         sqtd->physaddr = DMAADDR(&dma, offs);                          sqtd->physaddr = DMAADDR(&dma, offs);
                         sqtd->dma = dma;                          sqtd->dma = dma;
                         sqtd->offs = offs;                          sqtd->offs = offs;
   
                         sqtd->nextqtd = sc->sc_freeqtds;                          sqtd->nextqtd = sc->sc_freeqtds;
                         sc->sc_freeqtds = sqtd;                          sc->sc_freeqtds = sqtd;
                 }                  }
                 splx(s);  
         }          }
   
         s = splusb();  
         sqtd = sc->sc_freeqtds;          sqtd = sc->sc_freeqtds;
         sc->sc_freeqtds = sqtd->nextqtd;          sc->sc_freeqtds = sqtd->nextqtd;
         memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t));          memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t));
         sqtd->nextqtd = NULL;          sqtd->nextqtd = NULL;
         sqtd->xfer = NULL;          sqtd->xfer = NULL;
         splx(s);  
   
   done:
         return (sqtd);          return (sqtd);
 }  }
   
 Static void  Static void
 ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)  ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
 {  {
         int s;  
   
         s = splusb();          KASSERT(mutex_owned(&sc->sc_lock));
   
         sqtd->nextqtd = sc->sc_freeqtds;          sqtd->nextqtd = sc->sc_freeqtds;
         sc->sc_freeqtds = sqtd;          sc->sc_freeqtds = sqtd;
         splx(s);  
 }  }
   
 Static usbd_status  Static usbd_status
Line 2794  ehci_alloc_itd(ehci_softc_t *sc)
Line 2880  ehci_alloc_itd(ehci_softc_t *sc)
 {  {
         struct ehci_soft_itd *itd, *freeitd;          struct ehci_soft_itd *itd, *freeitd;
         usbd_status err;          usbd_status err;
         int i, s, offs, frindex, previndex;          int i, offs, frindex, previndex;
         usb_dma_t dma;          usb_dma_t dma;
   
         s = splusb();          KASSERT(mutex_owned(&sc->sc_lock));
   
         /* Find an itd that wasn't freed this frame or last frame. This can          /* Find an itd that wasn't freed this frame or last frame. This can
          * discard itds that were freed before frindex wrapped around           * discard itds that were freed before frindex wrapped around
Line 2848  ehci_alloc_itd(ehci_softc_t *sc)
Line 2934  ehci_alloc_itd(ehci_softc_t *sc)
         itd->u.frame_list.prev = NULL;          itd->u.frame_list.prev = NULL;
         itd->xfer_next = NULL;          itd->xfer_next = NULL;
         itd->slot = 0;          itd->slot = 0;
         splx(s);  
   
         return itd;          return itd;
 }  }
Line 2856  ehci_alloc_itd(ehci_softc_t *sc)
Line 2941  ehci_alloc_itd(ehci_softc_t *sc)
 Static void  Static void
 ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd)  ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd)
 {  {
         int s;  
   
         s = splusb();          KASSERT(mutex_owned(&sc->sc_lock));
   
         LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list);          LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list);
         splx(s);  
 }  }
   
 /****************/  /****************/
Line 2875  ehci_close_pipe(usbd_pipe_handle pipe, e
Line 2959  ehci_close_pipe(usbd_pipe_handle pipe, e
         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;          struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
         ehci_softc_t *sc = pipe->device->bus->hci_private;          ehci_softc_t *sc = pipe->device->bus->hci_private;
         ehci_soft_qh_t *sqh = epipe->sqh;          ehci_soft_qh_t *sqh = epipe->sqh;
         int s;  
   
         s = splusb();          KASSERT(mutex_owned(&sc->sc_lock));
   
         ehci_rem_qh(sc, sqh, head);          ehci_rem_qh(sc, sqh, head);
         splx(s);  
         ehci_free_sqh(sc, epipe->sqh);          ehci_free_sqh(sc, epipe->sqh);
 }  }
   
Line 2893  ehci_close_pipe(usbd_pipe_handle pipe, e
Line 2976  ehci_close_pipe(usbd_pipe_handle pipe, e
  * If the transaction has already happened we rely on the ordinary   * If the transaction has already happened we rely on the ordinary
  * interrupt processing to process it.   * interrupt processing to process it.
  * XXX This is most probably wrong.   * XXX This is most probably wrong.
    * XXXMRG this doesn't make sense anymore.
  */   */
 Static void  Static void
 ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)  ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
Line 2904  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 2988  ehci_abort_xfer(usbd_xfer_handle xfer, u
         ehci_soft_qtd_t *sqtd;          ehci_soft_qtd_t *sqtd;
         ehci_physaddr_t cur;          ehci_physaddr_t cur;
         u_int32_t qhstatus;          u_int32_t qhstatus;
         int s;  
         int hit;          int hit;
         int wake;          int wake;
   
         DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));          DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         if (sc->sc_dying) {          if (sc->sc_dying) {
                 /* If we're dying, just do the software part. */                  /* If we're dying, just do the software part. */
                 s = splusb();  
                 xfer->status = status;  /* make software ignore it */                  xfer->status = status;  /* make software ignore it */
                 callout_stop(&xfer->timeout_handle);                  callout_stop(&xfer->timeout_handle);
                 usb_transfer_complete(xfer);                  usb_transfer_complete(xfer);
                 splx(s);  
                 return;                  return;
         }          }
   
         if (xfer->device->bus->intr_context)          if (cpu_intr_p() || cpu_softintr_p())
                 panic("ehci_abort_xfer: not in process context");                  panic("ehci_abort_xfer: not in process context");
   
         /*          /*
Line 2938  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 3021  ehci_abort_xfer(usbd_xfer_handle xfer, u
                 DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));                  DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));
                 xfer->hcflags |= UXFER_ABORTWAIT;                  xfer->hcflags |= UXFER_ABORTWAIT;
                 while (xfer->hcflags & UXFER_ABORTING)                  while (xfer->hcflags & UXFER_ABORTING)
                         tsleep(&xfer->hcflags, PZERO, "ehciaw", 0);                          cv_wait(&xfer->hccv, &sc->sc_lock);
                 return;                  return;
         }          }
         xfer->hcflags |= UXFER_ABORTING;          xfer->hcflags |= UXFER_ABORTING;
Line 2946  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 3029  ehci_abort_xfer(usbd_xfer_handle xfer, u
         /*          /*
          * Step 1: Make interrupt routine and hardware ignore xfer.           * Step 1: Make interrupt routine and hardware ignore xfer.
          */           */
         s = splusb();  
         xfer->status = status;  /* make software ignore it */          xfer->status = status;  /* make software ignore it */
         callout_stop(&xfer->timeout_handle);          callout_stop(&xfer->timeout_handle);
   
Line 2973  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 3055  ehci_abort_xfer(usbd_xfer_handle xfer, u
                 if (sqtd == exfer->sqtdend)                  if (sqtd == exfer->sqtdend)
                         break;                          break;
         }          }
         splx(s);  
   
         /*          /*
          * Step 2: Wait until we know hardware has finished any possible           * Step 2: Wait until we know hardware has finished any possible
Line 2981  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 3062  ehci_abort_xfer(usbd_xfer_handle xfer, u
          * has run.           * has run.
          */           */
         ehci_sync_hc(sc);          ehci_sync_hc(sc);
         s = splusb();  
 #ifdef USB_USE_SOFTINTR  
         sc->sc_softwake = 1;          sc->sc_softwake = 1;
 #endif /* USB_USE_SOFTINTR */  
         usb_schedsoftintr(&sc->sc_bus);          usb_schedsoftintr(&sc->sc_bus);
 #ifdef USB_USE_SOFTINTR          cv_wait(&sc->sc_softwake_cv, &sc->sc_lock);
         tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);  
 #endif /* USB_USE_SOFTINTR */  
         splx(s);  
   
         /*          /*
          * Step 3: Remove any vestiges of the xfer from the hardware.           * Step 3: Remove any vestiges of the xfer from the hardware.
Line 2998  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 3073  ehci_abort_xfer(usbd_xfer_handle xfer, u
          * the TDs of this xfer we check if the hardware points to           * the TDs of this xfer we check if the hardware points to
          * any of them.           * any of them.
          */           */
         s = splusb();           /* XXX why? */  
   
         usb_syncmem(&sqh->dma,          usb_syncmem(&sqh->dma,
             sqh->offs + offsetof(ehci_qh_t, qh_curqtd),              sqh->offs + offsetof(ehci_qh_t, qh_curqtd),
Line 3038  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 3112  ehci_abort_xfer(usbd_xfer_handle xfer, u
         wake = xfer->hcflags & UXFER_ABORTWAIT;          wake = xfer->hcflags & UXFER_ABORTWAIT;
         xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);          xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         if (wake)          if (wake) {
                 wakeup(&xfer->hcflags);                  cv_broadcast(&xfer->hccv);
           }
   
         splx(s);          KASSERT(mutex_owned(&sc->sc_lock));
 #undef exfer  #undef exfer
 }  }
   
Line 3053  ehci_abort_isoc_xfer(usbd_xfer_handle xf
Line 3128  ehci_abort_isoc_xfer(usbd_xfer_handle xf
         struct ehci_xfer *exfer;          struct ehci_xfer *exfer;
         ehci_softc_t *sc;          ehci_softc_t *sc;
         struct ehci_soft_itd *itd;          struct ehci_soft_itd *itd;
         int s, i, wake;          int i, wake;
   
         epipe = (struct ehci_pipe *) xfer->pipe;          epipe = (struct ehci_pipe *) xfer->pipe;
         exfer = EXFER(xfer);          exfer = EXFER(xfer);
Line 3061  ehci_abort_isoc_xfer(usbd_xfer_handle xf
Line 3136  ehci_abort_isoc_xfer(usbd_xfer_handle xf
   
         DPRINTF(("ehci_abort_isoc_xfer: xfer %p pipe %p\n", xfer, epipe));          DPRINTF(("ehci_abort_isoc_xfer: xfer %p pipe %p\n", xfer, epipe));
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         if (sc->sc_dying) {          if (sc->sc_dying) {
                 s = splusb();  
                 xfer->status = status;                  xfer->status = status;
                 callout_stop(&xfer->timeout_handle);                  callout_stop(&xfer->timeout_handle);
                 usb_transfer_complete(xfer);                  usb_transfer_complete(xfer);
                 splx(s);  
                 return;                  return;
         }          }
   
Line 3075  ehci_abort_isoc_xfer(usbd_xfer_handle xf
Line 3150  ehci_abort_isoc_xfer(usbd_xfer_handle xf
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 if (status == USBD_TIMEOUT)                  if (status == USBD_TIMEOUT)
                         printf("ehci_abort_xfer: TIMEOUT while aborting\n");                          printf("ehci_abort_isoc_xfer: TIMEOUT while aborting\n");
 #endif  #endif
   
                 xfer->status = status;                  xfer->status = status;
                 DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));                  DPRINTFN(2, ("ehci_abort_isoc_xfer: waiting for abort to finish\n"));
                 xfer->hcflags |= UXFER_ABORTWAIT;                  xfer->hcflags |= UXFER_ABORTWAIT;
                 while (xfer->hcflags & UXFER_ABORTING)                  while (xfer->hcflags & UXFER_ABORTING)
                         tsleep(&xfer->hcflags, PZERO, "ehciiaw", 0);                          cv_wait(&xfer->hccv, &sc->sc_lock);
                 return;                  goto done;
         }          }
         xfer->hcflags |= UXFER_ABORTING;          xfer->hcflags |= UXFER_ABORTING;
   
         xfer->status = status;          xfer->status = status;
         callout_stop(&xfer->timeout_handle);          callout_stop(&xfer->timeout_handle);
   
         s = splusb();  
         for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) {          for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) {
                 usb_syncmem(&itd->dma,                  usb_syncmem(&itd->dma,
                     itd->offs + offsetof(ehci_itd_t, itd_ctl),                      itd->offs + offsetof(ehci_itd_t, itd_ctl),
Line 3108  ehci_abort_isoc_xfer(usbd_xfer_handle xf
Line 3182  ehci_abort_isoc_xfer(usbd_xfer_handle xf
                     sizeof(itd->itd.itd_ctl),                      sizeof(itd->itd.itd_ctl),
                     BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);                      BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
         }          }
         splx(s);  
   
         s = splusb();  
 #ifdef USB_USE_SOFTINTR  
         sc->sc_softwake = 1;          sc->sc_softwake = 1;
 #endif /* USB_USE_SOFTINTR */  
         usb_schedsoftintr(&sc->sc_bus);          usb_schedsoftintr(&sc->sc_bus);
 #ifdef USB_USE_SOFTINTR          cv_wait(&sc->sc_softwake_cv, &sc->sc_lock);
         tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);  
 #endif /* USB_USE_SOFTINTR */  
         splx(s);  
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         exfer->isdone = 1;          exfer->isdone = 1;
Line 3126  ehci_abort_isoc_xfer(usbd_xfer_handle xf
Line 3193  ehci_abort_isoc_xfer(usbd_xfer_handle xf
         wake = xfer->hcflags & UXFER_ABORTWAIT;          wake = xfer->hcflags & UXFER_ABORTWAIT;
         xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);          xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         if (wake)          if (wake) {
                 wakeup(&xfer->hcflags);                  cv_broadcast(&xfer->hccv);
           }
   
   done:
           KASSERT(mutex_owned(&sc->sc_lock));
         return;          return;
 }  }
   
Line 3146  ehci_timeout(void *addr)
Line 3216  ehci_timeout(void *addr)
 #endif  #endif
   
         if (sc->sc_dying) {          if (sc->sc_dying) {
                   mutex_enter(&sc->sc_lock);
                 ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT);                  ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT);
                   mutex_exit(&sc->sc_lock);
                 return;                  return;
         }          }
   
Line 3160  Static void
Line 3232  Static void
 ehci_timeout_task(void *addr)  ehci_timeout_task(void *addr)
 {  {
         usbd_xfer_handle xfer = addr;          usbd_xfer_handle xfer = addr;
         int s;          ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
   
         DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer));          DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer));
   
         s = splusb();          mutex_enter(&sc->sc_lock);
         ehci_abort_xfer(xfer, USBD_TIMEOUT);          ehci_abort_xfer(xfer, USBD_TIMEOUT);
         splx(s);          mutex_exit(&sc->sc_lock);
 }  }
   
 /************************/  /************************/
Line 3174  ehci_timeout_task(void *addr)
Line 3246  ehci_timeout_task(void *addr)
 Static usbd_status  Static usbd_status
 ehci_device_ctrl_transfer(usbd_xfer_handle xfer)  ehci_device_ctrl_transfer(usbd_xfer_handle xfer)
 {  {
           ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
         usbd_status err;          usbd_status err;
   
         /* Insert last in queue. */          /* Insert last in queue. */
           mutex_enter(&sc->sc_lock);
         err = usb_insert_transfer(xfer);          err = usb_insert_transfer(xfer);
           mutex_exit(&sc->sc_lock);
         if (err)          if (err)
                 return (err);                  return (err);
   
Line 3203  ehci_device_ctrl_start(usbd_xfer_handle 
Line 3278  ehci_device_ctrl_start(usbd_xfer_handle 
 #endif  #endif
   
         err = ehci_device_request(xfer);          err = ehci_device_request(xfer);
         if (err)          if (err) {
                 return (err);                  return (err);
           }
   
         if (sc->sc_bus.use_polling)          if (sc->sc_bus.use_polling)
                 ehci_waitintr(sc, xfer);                  ehci_waitintr(sc, xfer);
   
         return (USBD_IN_PROGRESS);          return (USBD_IN_PROGRESS);
 }  }
   
Line 3223  ehci_device_ctrl_done(usbd_xfer_handle x
Line 3300  ehci_device_ctrl_done(usbd_xfer_handle x
   
         DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer));          DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer));
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!(xfer->rqflags & URQ_REQUEST)) {          if (!(xfer->rqflags & URQ_REQUEST)) {
                 panic("ehci_ctrl_done: not a request");                  panic("ehci_ctrl_done: not a request");
         }          }
 #endif  #endif
   
         mutex_enter(&sc->sc_intrhead_lock);  
         if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {          if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
                 ehci_del_intr_list(sc, ex);     /* remove from active list */                  ehci_del_intr_list(sc, ex);     /* remove from active list */
                 ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);                  ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
Line 3239  ehci_device_ctrl_done(usbd_xfer_handle x
Line 3317  ehci_device_ctrl_done(usbd_xfer_handle x
                         usb_syncmem(&xfer->dmabuf, 0, len,                          usb_syncmem(&xfer->dmabuf, 0, len,
                             rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);                              rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
         }          }
         mutex_exit(&sc->sc_intrhead_lock);  
   
         DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen));          DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen));
 }  }
Line 3259  ehci_device_ctrl_close(usbd_pipe_handle 
Line 3336  ehci_device_ctrl_close(usbd_pipe_handle 
         ehci_softc_t *sc = pipe->device->bus->hci_private;          ehci_softc_t *sc = pipe->device->bus->hci_private;
         /*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/          /*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe));          DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe));
   
         ehci_close_pipe(pipe, sc->sc_async_head);          ehci_close_pipe(pipe, sc->sc_async_head);
 }  }
   
Line 3277  ehci_device_request(usbd_xfer_handle xfe
Line 3357  ehci_device_request(usbd_xfer_handle xfe
         int isread;          int isread;
         int len;          int len;
         usbd_status err;          usbd_status err;
         int s;  
   
         isread = req->bmRequestType & UT_READ;          isread = req->bmRequestType & UT_READ;
         len = UGETW(req->wLength);          len = UGETW(req->wLength);
Line 3299  ehci_device_request(usbd_xfer_handle xfe
Line 3378  ehci_device_request(usbd_xfer_handle xfe
                 goto bad2;                  goto bad2;
         }          }
   
           mutex_enter(&sc->sc_lock);
   
         sqh = epipe->sqh;          sqh = epipe->sqh;
         epipe->u.ctl.length = len;          epipe->u.ctl.length = len;
   
Line 3387  ehci_device_request(usbd_xfer_handle xfe
Line 3468  ehci_device_request(usbd_xfer_handle xfe
 #endif  #endif
   
         /* Insert qTD in QH list. */          /* Insert qTD in QH list. */
         s = splusb();  
         ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */          ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */
         if (xfer->timeout && !sc->sc_bus.use_polling) {          if (xfer->timeout && !sc->sc_bus.use_polling) {
                 callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)),                  callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout),
                     (ehci_timeout), (xfer));                      ehci_timeout, xfer);
         }          }
         mutex_enter(&sc->sc_intrhead_lock);  
         ehci_add_intr_list(sc, exfer);          ehci_add_intr_list(sc, exfer);
         mutex_exit(&sc->sc_intrhead_lock);  
         xfer->status = USBD_IN_PROGRESS;          xfer->status = USBD_IN_PROGRESS;
         splx(s);          mutex_exit(&sc->sc_lock);
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
         if (ehcidebug > 10) {          if (ehcidebug > 10) {
Line 3414  ehci_device_request(usbd_xfer_handle xfe
Line 3492  ehci_device_request(usbd_xfer_handle xfe
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
   
  bad3:   bad3:
           mutex_exit(&sc->sc_lock);
         ehci_free_sqtd(sc, stat);          ehci_free_sqtd(sc, stat);
  bad2:   bad2:
         ehci_free_sqtd(sc, setup);          ehci_free_sqtd(sc, setup);
  bad1:   bad1:
         DPRINTFN(-1,("ehci_device_request: no memory\n"));          DPRINTFN(-1,("ehci_device_request: no memory\n"));
           mutex_enter(&sc->sc_lock);
         xfer->status = err;          xfer->status = err;
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
           mutex_exit(&sc->sc_lock);
         return (err);          return (err);
 #undef exfer  #undef exfer
 }  }
Line 3440  Static void
Line 3521  Static void
 ehci_intrlist_timeout(void *arg)  ehci_intrlist_timeout(void *arg)
 {  {
         ehci_softc_t *sc = arg;          ehci_softc_t *sc = arg;
         int s = splusb();  
   
         DPRINTF(("ehci_intrlist_timeout\n"));          DPRINTF(("ehci_intrlist_timeout\n"));
         usb_schedsoftintr(&sc->sc_bus);          usb_schedsoftintr(&sc->sc_bus);
   
         splx(s);  
 }  }
   
 /************************/  /************************/
Line 3453  ehci_intrlist_timeout(void *arg)
Line 3531  ehci_intrlist_timeout(void *arg)
 Static usbd_status  Static usbd_status
 ehci_device_bulk_transfer(usbd_xfer_handle xfer)  ehci_device_bulk_transfer(usbd_xfer_handle xfer)
 {  {
           ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
         usbd_status err;          usbd_status err;
   
         /* Insert last in queue. */          /* Insert last in queue. */
           mutex_enter(&sc->sc_lock);
         err = usb_insert_transfer(xfer);          err = usb_insert_transfer(xfer);
           mutex_exit(&sc->sc_lock);
         if (err)          if (err)
                 return (err);                  return (err);
   
Line 3475  ehci_device_bulk_start(usbd_xfer_handle 
Line 3556  ehci_device_bulk_start(usbd_xfer_handle 
         ehci_soft_qh_t *sqh;          ehci_soft_qh_t *sqh;
         usbd_status err;          usbd_status err;
         int len, isread, endpt;          int len, isread, endpt;
         int s;  
   
         DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n",          DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n",
                      xfer, xfer->length, xfer->flags));                       xfer, xfer->length, xfer->flags));
Line 3488  ehci_device_bulk_start(usbd_xfer_handle 
Line 3568  ehci_device_bulk_start(usbd_xfer_handle 
                 panic("ehci_device_bulk_start: a request");                  panic("ehci_device_bulk_start: a request");
 #endif  #endif
   
           mutex_enter(&sc->sc_lock);
   
         len = xfer->length;          len = xfer->length;
         endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;          endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
         isread = UE_GET_DIR(endpt) == UE_DIR_IN;          isread = UE_GET_DIR(endpt) == UE_DIR_IN;
Line 3501  ehci_device_bulk_start(usbd_xfer_handle 
Line 3583  ehci_device_bulk_start(usbd_xfer_handle 
                 DPRINTFN(-1,("ehci_device_bulk_transfer: no memory\n"));                  DPRINTFN(-1,("ehci_device_bulk_transfer: no memory\n"));
                 xfer->status = err;                  xfer->status = err;
                 usb_transfer_complete(xfer);                  usb_transfer_complete(xfer);
                   mutex_exit(&sc->sc_lock);
                 return (err);                  return (err);
         }          }
   
Line 3522  ehci_device_bulk_start(usbd_xfer_handle 
Line 3605  ehci_device_bulk_start(usbd_xfer_handle 
         exfer->isdone = 0;          exfer->isdone = 0;
 #endif  #endif
   
         s = splusb();  
         ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */          ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
         if (xfer->timeout && !sc->sc_bus.use_polling) {          if (xfer->timeout && !sc->sc_bus.use_polling) {
                 callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)),                  callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout),
                     (ehci_timeout), (xfer));                      ehci_timeout, xfer);
         }          }
         mutex_enter(&sc->sc_intrhead_lock);  
         ehci_add_intr_list(sc, exfer);          ehci_add_intr_list(sc, exfer);
         mutex_exit(&sc->sc_intrhead_lock);  
         xfer->status = USBD_IN_PROGRESS;          xfer->status = USBD_IN_PROGRESS;
         splx(s);          mutex_exit(&sc->sc_lock);
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
         if (ehcidebug > 10) {          if (ehcidebug > 10) {
Line 3573  ehci_device_bulk_close(usbd_pipe_handle 
Line 3653  ehci_device_bulk_close(usbd_pipe_handle 
         ehci_softc_t *sc = pipe->device->bus->hci_private;          ehci_softc_t *sc = pipe->device->bus->hci_private;
         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;          struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe));          DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe));
         pipe->endpoint->datatoggle = epipe->nexttoggle;          pipe->endpoint->datatoggle = epipe->nexttoggle;
         ehci_close_pipe(pipe, sc->sc_async_head);          ehci_close_pipe(pipe, sc->sc_async_head);
Line 3590  ehci_device_bulk_done(usbd_xfer_handle x
Line 3672  ehci_device_bulk_done(usbd_xfer_handle x
         DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n",          DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n",
                      xfer, xfer->actlen));                       xfer, xfer->actlen));
   
         mutex_enter(&sc->sc_intrhead_lock);          KASSERT(mutex_owned(&sc->sc_lock));
   
         if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {          if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
                 ehci_del_intr_list(sc, ex);     /* remove from active list */                  ehci_del_intr_list(sc, ex);     /* remove from active list */
                 ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);                  ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
                 usb_syncmem(&xfer->dmabuf, 0, xfer->length,                  usb_syncmem(&xfer->dmabuf, 0, xfer->length,
                     rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);                      rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
         }          }
         mutex_exit(&sc->sc_intrhead_lock);  
   
         DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen));          DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen));
 }  }
Line 3622  ehci_device_setintr(ehci_softc_t *sc, eh
Line 3704  ehci_device_setintr(ehci_softc_t *sc, eh
   
         sqh->islot = islot;          sqh->islot = islot;
         isp = &sc->sc_islots[islot];          isp = &sc->sc_islots[islot];
         ehci_add_qh(sqh, isp->sqh);          mutex_enter(&sc->sc_lock);
           ehci_add_qh(sc, sqh, isp->sqh);
           mutex_exit(&sc->sc_lock);
   
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
 }  }
Line 3630  ehci_device_setintr(ehci_softc_t *sc, eh
Line 3714  ehci_device_setintr(ehci_softc_t *sc, eh
 Static usbd_status  Static usbd_status
 ehci_device_intr_transfer(usbd_xfer_handle xfer)  ehci_device_intr_transfer(usbd_xfer_handle xfer)
 {  {
           ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
         usbd_status err;          usbd_status err;
   
         /* Insert last in queue. */          /* Insert last in queue. */
           mutex_enter(&sc->sc_lock);
         err = usb_insert_transfer(xfer);          err = usb_insert_transfer(xfer);
           mutex_exit(&sc->sc_lock);
         if (err)          if (err)
                 return (err);                  return (err);
   
Line 3655  ehci_device_intr_start(usbd_xfer_handle 
Line 3742  ehci_device_intr_start(usbd_xfer_handle 
         ehci_soft_qh_t *sqh;          ehci_soft_qh_t *sqh;
         usbd_status err;          usbd_status err;
         int len, isread, endpt;          int len, isread, endpt;
         int s;  
   
         DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n",          DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n",
             xfer, xfer->length, xfer->flags));              xfer, xfer->length, xfer->flags));
Line 3668  ehci_device_intr_start(usbd_xfer_handle 
Line 3754  ehci_device_intr_start(usbd_xfer_handle 
                 panic("ehci_device_intr_start: a request");                  panic("ehci_device_intr_start: a request");
 #endif  #endif
   
           mutex_enter(&sc->sc_lock);
   
         len = xfer->length;          len = xfer->length;
         endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;          endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
         isread = UE_GET_DIR(endpt) == UE_DIR_IN;          isread = UE_GET_DIR(endpt) == UE_DIR_IN;
Line 3681  ehci_device_intr_start(usbd_xfer_handle 
Line 3769  ehci_device_intr_start(usbd_xfer_handle 
                 DPRINTFN(-1, ("ehci_device_intr_start: no memory\n"));                  DPRINTFN(-1, ("ehci_device_intr_start: no memory\n"));
                 xfer->status = err;                  xfer->status = err;
                 usb_transfer_complete(xfer);                  usb_transfer_complete(xfer);
                   mutex_exit(&sc->sc_lock);
                 return (err);                  return (err);
         }          }
   
Line 3702  ehci_device_intr_start(usbd_xfer_handle 
Line 3791  ehci_device_intr_start(usbd_xfer_handle 
         exfer->isdone = 0;          exfer->isdone = 0;
 #endif  #endif
   
         s = splusb();  
         ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */          ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
         if (xfer->timeout && !sc->sc_bus.use_polling) {          if (xfer->timeout && !sc->sc_bus.use_polling) {
                 callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)),                  callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout),
                     (ehci_timeout), (xfer));                      ehci_timeout, xfer);
         }          }
         mutex_enter(&sc->sc_intrhead_lock);  
         ehci_add_intr_list(sc, exfer);          ehci_add_intr_list(sc, exfer);
         mutex_exit(&sc->sc_intrhead_lock);  
         xfer->status = USBD_IN_PROGRESS;          xfer->status = USBD_IN_PROGRESS;
         splx(s);          mutex_exit(&sc->sc_lock);
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
         if (ehcidebug > 10) {          if (ehcidebug > 10) {
Line 3756  ehci_device_intr_close(usbd_pipe_handle 
Line 3842  ehci_device_intr_close(usbd_pipe_handle 
         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;          struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
         struct ehci_soft_islot *isp;          struct ehci_soft_islot *isp;
   
           KASSERT(mutex_owned(&sc->sc_lock));
   
         isp = &sc->sc_islots[epipe->sqh->islot];          isp = &sc->sc_islots[epipe->sqh->islot];
         ehci_close_pipe(pipe, isp->sqh);          ehci_close_pipe(pipe, isp->sqh);
 }  }
Line 3770  ehci_device_intr_done(usbd_xfer_handle x
Line 3858  ehci_device_intr_done(usbd_xfer_handle x
         ehci_soft_qtd_t *data, *dataend;          ehci_soft_qtd_t *data, *dataend;
         ehci_soft_qh_t *sqh;          ehci_soft_qh_t *sqh;
         usbd_status err;          usbd_status err;
         int len, isread, endpt, s;          int len, isread, endpt;
   
         DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n",          DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n",
             xfer, xfer->actlen));              xfer, xfer->actlen));
   
         mutex_enter(&sc->sc_intrhead_lock);          KASSERT(mutex_owned(&sc->sc_lock));
   
         if (xfer->pipe->repeat) {          if (xfer->pipe->repeat) {
                 ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);                  ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
   
Line 3792  ehci_device_intr_done(usbd_xfer_handle x
Line 3881  ehci_device_intr_done(usbd_xfer_handle x
                 if (err) {                  if (err) {
                         DPRINTFN(-1, ("ehci_device_intr_done: no memory\n"));                          DPRINTFN(-1, ("ehci_device_intr_done: no memory\n"));
                         xfer->status = err;                          xfer->status = err;
                         mutex_exit(&sc->sc_intrhead_lock);  
                         return;                          return;
                 }                  }
   
Line 3807  ehci_device_intr_done(usbd_xfer_handle x
Line 3895  ehci_device_intr_done(usbd_xfer_handle x
                 exfer->isdone = 0;                  exfer->isdone = 0;
 #endif  #endif
   
                 s = splusb();  
                 ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */                  ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
                 if (xfer->timeout && !sc->sc_bus.use_polling) {                  if (xfer->timeout && !sc->sc_bus.use_polling) {
                         callout_reset(&(xfer->timeout_handle),                          callout_reset(&xfer->timeout_handle,
                             (mstohz(xfer->timeout)), (ehci_timeout), (xfer));                              mstohz(xfer->timeout), ehci_timeout, xfer);
                 }                  }
                 splx(s);  
   
                 xfer->status = USBD_IN_PROGRESS;                  xfer->status = USBD_IN_PROGRESS;
         } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {          } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
Line 3824  ehci_device_intr_done(usbd_xfer_handle x
Line 3910  ehci_device_intr_done(usbd_xfer_handle x
                 usb_syncmem(&xfer->dmabuf, 0, xfer->length,                  usb_syncmem(&xfer->dmabuf, 0, xfer->length,
                     isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);                      isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
         }          }
         mutex_exit(&sc->sc_intrhead_lock);  
 #undef exfer  #undef exfer
 }  }
   
Line 3833  ehci_device_intr_done(usbd_xfer_handle x
Line 3918  ehci_device_intr_done(usbd_xfer_handle x
 Static usbd_status  Static usbd_status
 ehci_device_isoc_transfer(usbd_xfer_handle xfer)  ehci_device_isoc_transfer(usbd_xfer_handle xfer)
 {  {
           ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
         usbd_status err;          usbd_status err;
   
           mutex_enter(&sc->sc_lock);
         err = usb_insert_transfer(xfer);          err = usb_insert_transfer(xfer);
           mutex_exit(&sc->sc_lock);
         if (err && err != USBD_IN_PROGRESS)          if (err && err != USBD_IN_PROGRESS)
                 return err;                  return err;
   
Line 3852  ehci_device_isoc_start(usbd_xfer_handle 
Line 3940  ehci_device_isoc_start(usbd_xfer_handle 
         ehci_soft_itd_t *itd, *prev, *start, *stop;          ehci_soft_itd_t *itd, *prev, *start, *stop;
         usb_dma_t *dma_buf;          usb_dma_t *dma_buf;
         int i, j, k, frames, uframes, ufrperframe;          int i, j, k, frames, uframes, ufrperframe;
         int s, trans_count, offs, total_length;          int trans_count, offs, total_length;
         int frindex;          int frindex;
   
         start = NULL;          start = NULL;
Line 4036  ehci_device_isoc_start(usbd_xfer_handle 
Line 4124  ehci_device_isoc_start(usbd_xfer_handle 
          * more than the period frame list.           * more than the period frame list.
          */           */
   
         s = splusb();          mutex_enter(&sc->sc_lock);
   
         /* Start inserting frames */          /* Start inserting frames */
         if (epipe->u.isoc.cur_xfers > 0) {          if (epipe->u.isoc.cur_xfers > 0) {
Line 4102  ehci_device_isoc_start(usbd_xfer_handle 
Line 4190  ehci_device_isoc_start(usbd_xfer_handle 
         exfer->sqtdstart = NULL;          exfer->sqtdstart = NULL;
         exfer->sqtdstart = NULL;          exfer->sqtdstart = NULL;
   
         mutex_enter(&sc->sc_intrhead_lock);  
         ehci_add_intr_list(sc, exfer);          ehci_add_intr_list(sc, exfer);
         mutex_exit(&sc->sc_intrhead_lock);  
         xfer->status = USBD_IN_PROGRESS;          xfer->status = USBD_IN_PROGRESS;
         xfer->done = 0;          xfer->done = 0;
         splx(s);          mutex_exit(&sc->sc_lock);
   
         if (sc->sc_bus.use_polling) {          if (sc->sc_bus.use_polling) {
                 printf("Starting ehci isoc xfer with polling. Bad idea?\n");                  printf("Starting ehci isoc xfer with polling. Bad idea?\n");
Line 4136  ehci_device_isoc_done(usbd_xfer_handle x
Line 4222  ehci_device_isoc_done(usbd_xfer_handle x
         struct ehci_xfer *exfer;          struct ehci_xfer *exfer;
         ehci_softc_t *sc;          ehci_softc_t *sc;
         struct ehci_pipe *epipe;          struct ehci_pipe *epipe;
         int s;  
   
         exfer = EXFER(xfer);          exfer = EXFER(xfer);
         sc = xfer->pipe->device->bus->hci_private;          sc = xfer->pipe->device->bus->hci_private;
         epipe = (struct ehci_pipe *) xfer->pipe;          epipe = (struct ehci_pipe *) xfer->pipe;
   
         s = splusb();          KASSERT(mutex_owned(&sc->sc_lock));
   
         epipe->u.isoc.cur_xfers--;          epipe->u.isoc.cur_xfers--;
         mutex_enter(&sc->sc_intrhead_lock);  
         if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) {          if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) {
                 ehci_del_intr_list(sc, exfer);                  ehci_del_intr_list(sc, exfer);
                 ehci_rem_free_itd_chain(sc, exfer);                  ehci_rem_free_itd_chain(sc, exfer);
         }          }
         mutex_exit(&sc->sc_intrhead_lock);  
         splx(s);  
   
         usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE |          usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE |
                     BUS_DMASYNC_POSTREAD);                      BUS_DMASYNC_POSTREAD);

Legend:
Removed from v.1.181  
changed lines
  Added in v.1.181.6.17

CVSweb <webmaster@jp.NetBSD.org>