Diff for /src/sys/bus/usb/uhci.c between versions 1.7 and 1.8

version 1.7, 2003/12/29 06:42:12 version 1.8, 2003/12/30 01:01:44
Line 1 Line 1
 /*  /*
  * $NetBSD: uhci.c,v 1.80 2000/01/19 01:16:38 augustss Exp $   * $NetBSD: uhci.c,v 1.80 2000/01/19 01:16:38 augustss Exp $
 * $FreeBSD: src/sys/dev/usb/uhci.c,v 1.40.2.11 2003/08/22 06:59:11 njl Exp $ * $NetBSD: uhci.c,v 1.170 2003/02/19 01:35:04 augustss Exp $
  * $FreeBSD: src/sys/dev/usb/uhci.c,v 1.149 2003/11/10 00:08:41 joe Exp $
  * $DragonFly$   * $DragonFly$
  */   */
   
   /*      Also already incorporated from NetBSD:
    *      $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $
    *      $NetBSD: uhci.c,v 1.173 2003/05/13 04:41:59 gson Exp $
    *      $NetBSD: uhci.c,v 1.175 2003/09/12 16:18:08 mycroft Exp $
    *      $NetBSD: uhci.c,v 1.176 2003/11/04 19:11:21 mycroft Exp $
    */
   
   
 /*  /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.   * Copyright (c) 1998 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
Line 45 Line 54
  * USB Universal Host Controller driver.   * USB Universal Host Controller driver.
  * Handles e.g. PIIX3 and PIIX4.   * Handles e.g. PIIX3 and PIIX4.
  *   *
 * UHCI spec: http://www.intel.com/design/usb/uhci11d.pdf * UHCI spec: http://developer.intel.com/design/USB/UHCI11D.htm
 * USB spec: http://www.usb.org/developers/data/usb11.pdf * USB spec: http://www.usb.org/developers/docs/usbspec.zip
  * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf   * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf
  *             ftp://download.intel.com/design/intarch/datashts/29056201.pdf   *             ftp://download.intel.com/design/intarch/datashts/29056201.pdf
  */   */
Line 59 Line 68
 #include <sys/device.h>  #include <sys/device.h>
 #include <sys/select.h>  #include <sys/select.h>
 #elif defined(__FreeBSD__)  #elif defined(__FreeBSD__)
   #include <sys/endian.h>
 #include <sys/module.h>  #include <sys/module.h>
 #include <sys/bus.h>  #include <sys/bus.h>
 #include <machine/bus_pio.h>  #include <machine/bus_pio.h>
Line 82 Line 92
 #include "uhcireg.h"  #include "uhcireg.h"
 #include "uhcivar.h"  #include "uhcivar.h"
   
   /* Use bandwidth reclamation for control transfers. Some devices choke on it. */
   /*#define UHCI_CTL_LOOP */
   
 #if defined(__FreeBSD__)  #if defined(__FreeBSD__)
 #include <machine/clock.h>  #include <machine/clock.h>
   
Line 97  struct cfdriver uhci_cd = { Line 110  struct cfdriver uhci_cd = {
 #endif  #endif
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
   uhci_softc_t *thesc;
 #define DPRINTF(x)      if (uhcidebug) printf x  #define DPRINTF(x)      if (uhcidebug) printf x
 #define DPRINTFN(n,x)   if (uhcidebug>(n)) printf x  #define DPRINTFN(n,x)   if (uhcidebug>(n)) printf x
 int uhcidebug = 0;  int uhcidebug = 0;
   int uhcinoloop = 0;
 SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci");  SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci");
 SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW,  SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW,
            &uhcidebug, 0, "uhci debug level");             &uhcidebug, 0, "uhci debug level");
   SYSCTL_INT(_hw_usb_uhci, OID_AUTO, loop, CTLFLAG_RW,
              &uhcinoloop, 0, "uhci noloop");
   #ifndef __NetBSD__
   #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
   #endif
 #else  #else
 #define DPRINTF(x)  #define DPRINTF(x)
 #define DPRINTFN(n,x)  #define DPRINTFN(n,x)
Line 112  SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug Line 132  SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug
  * The UHCI controller is little endian, so on big endian machines   * The UHCI controller is little endian, so on big endian machines
  * the data strored in memory needs to be swapped.   * the data strored in memory needs to be swapped.
  */   */
   #if defined(__OpenBSD__)
 #if BYTE_ORDER == BIG_ENDIAN  #if BYTE_ORDER == BIG_ENDIAN
#define LE(x) (bswap32(x))#define htole32(x) (bswap32(x))
 #define le32toh(x) (bswap32(x))
 #else  #else
#define LE(x) (x)#define htole32(x) (x)
 #define le32toh(x) (x)
 #endif
 #endif  #endif
   
 struct uhci_pipe {  struct uhci_pipe {
         struct usbd_pipe pipe;          struct usbd_pipe pipe;
         uhci_intr_info_t *iinfo;  
         int nexttoggle;          int nexttoggle;
   
           u_char aborting;
           usbd_xfer_handle abortstart, abortend;
   
         /* Info needed for different pipe kinds. */          /* Info needed for different pipe kinds. */
         union {          union {
                 /* Control pipe */                  /* Control pipe */
Line 134  struct uhci_pipe { Line 161  struct uhci_pipe {
                 /* Interrupt pipe */                  /* Interrupt pipe */
                 struct {                  struct {
                         int npoll;                          int npoll;
                           int isread;
                         uhci_soft_qh_t **qhs;                          uhci_soft_qh_t **qhs;
                 } intr;                  } intr;
                 /* Bulk pipe */                  /* Bulk pipe */
Line 150  struct uhci_pipe { Line 178  struct uhci_pipe {
         } u;          } u;
 };  };
   
/* Static void             uhci_globalreset(uhci_softc_t *);
 * The uhci_intr_info free list can be global since they containStatic usbd_status      uhci_portreset(uhci_softc_t*, int);
 * no dma specific data.  The other free lists do.Static void             uhci_reset(uhci_softc_t *);
 */#if defined(__NetBSD__) || defined(__OpenBSD__)
LIST_HEAD(, uhci_intr_info) uhci_ii_free;Static void             uhci_shutdown(void *v);
Static void             uhci_power(int, void *);
Static void             uhci_busreset(uhci_softc_t *);#endif
 Static usbd_status      uhci_run(uhci_softc_t *, int run);  Static usbd_status      uhci_run(uhci_softc_t *, int run);
Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);Static uhci_soft_td_t  *uhci_alloc_std(uhci_softc_t *);
 Static void             uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);  Static void             uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);
Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *);Static uhci_soft_qh_t  *uhci_alloc_sqh(uhci_softc_t *);
 Static void             uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *);  Static void             uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *);
 Static uhci_intr_info_t *uhci_alloc_intr_info(uhci_softc_t *);  
 Static void             uhci_free_intr_info(uhci_intr_info_t *ii);  
 #if 0  #if 0
 Static void             uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *,  Static void             uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *,
                                      uhci_intr_info_t *);                                         uhci_intr_info_t *);
 Static void             uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *);  Static void             uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *);
 #endif  #endif
   
Static void             uhci_free_std_chain(uhci_softc_t *, Static void             uhci_free_std_chain(uhci_softc_t *,
                                         uhci_soft_td_t *, uhci_soft_td_t *);                                            uhci_soft_td_t *, uhci_soft_td_t *);
 Static usbd_status      uhci_alloc_std_chain(struct uhci_pipe *,  Static usbd_status      uhci_alloc_std_chain(struct uhci_pipe *,
                            uhci_softc_t *, int, int, u_int16_t, usb_dma_t *,                             uhci_softc_t *, int, int, u_int16_t, usb_dma_t *,
                             uhci_soft_td_t **, uhci_soft_td_t **);                              uhci_soft_td_t **, uhci_soft_td_t **);
Static void             uhci_timo(void *);Static void             uhci_poll_hub(void *);
 Static void             uhci_waitintr(uhci_softc_t *, usbd_xfer_handle);  Static void             uhci_waitintr(uhci_softc_t *, usbd_xfer_handle);
 Static void             uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *);  Static void             uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *);
 Static void             uhci_idone(uhci_intr_info_t *);  Static void             uhci_idone(uhci_intr_info_t *);
   
 Static void             uhci_abort_xfer(usbd_xfer_handle, usbd_status status);  Static void             uhci_abort_xfer(usbd_xfer_handle, usbd_status status);
 Static void             uhci_abort_xfer_end(void *v);  
   
 Static void             uhci_timeout(void *);  Static void             uhci_timeout(void *);
Static void             uhci_lock_frames(uhci_softc_t *);Static void             uhci_timeout_task(void *);
Static void           uhci_unlock_frames(uhci_softc_t *);Static void             uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
Static void             uhci_add_ctrl(uhci_softc_t *, uhci_soft_qh_t *);Static void             uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
 Static void             uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);  Static void             uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);
Static void             uhci_remove_ctrl(uhci_softc_t *,uhci_soft_qh_t *);Static void             uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
 Static void             uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
 Static void             uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *);  Static void             uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *);
 Static int              uhci_str(usb_string_descriptor_t *, int, char *);  Static int              uhci_str(usb_string_descriptor_t *, int, char *);
   Static void             uhci_add_loop(uhci_softc_t *sc);
   Static void             uhci_rem_loop(uhci_softc_t *sc);
   
 Static usbd_status      uhci_setup_isoc(usbd_pipe_handle pipe);  Static usbd_status      uhci_setup_isoc(usbd_pipe_handle pipe);
 Static void             uhci_device_isoc_enter(usbd_xfer_handle);  Static void             uhci_device_isoc_enter(usbd_xfer_handle);
Line 205  Static usbd_status uhci_device_ctrl_tran Line 233  Static usbd_status uhci_device_ctrl_tran
 Static usbd_status      uhci_device_ctrl_start(usbd_xfer_handle);  Static usbd_status      uhci_device_ctrl_start(usbd_xfer_handle);
 Static void             uhci_device_ctrl_abort(usbd_xfer_handle);  Static void             uhci_device_ctrl_abort(usbd_xfer_handle);
 Static void             uhci_device_ctrl_close(usbd_pipe_handle);  Static void             uhci_device_ctrl_close(usbd_pipe_handle);
Static void             uhci_device_ctrl_done (usbd_xfer_handle);Static void             uhci_device_ctrl_done(usbd_xfer_handle);
   
 Static usbd_status      uhci_device_intr_transfer(usbd_xfer_handle);  Static usbd_status      uhci_device_intr_transfer(usbd_xfer_handle);
 Static usbd_status      uhci_device_intr_start(usbd_xfer_handle);  Static usbd_status      uhci_device_intr_start(usbd_xfer_handle);
 Static void             uhci_device_intr_abort(usbd_xfer_handle);  Static void             uhci_device_intr_abort(usbd_xfer_handle);
 Static void             uhci_device_intr_close(usbd_pipe_handle);  Static void             uhci_device_intr_close(usbd_pipe_handle);
Static void             uhci_device_intr_done (usbd_xfer_handle);Static void             uhci_device_intr_done(usbd_xfer_handle);
   
 Static usbd_status      uhci_device_bulk_transfer(usbd_xfer_handle);  Static usbd_status      uhci_device_bulk_transfer(usbd_xfer_handle);
 Static usbd_status      uhci_device_bulk_start(usbd_xfer_handle);  Static usbd_status      uhci_device_bulk_start(usbd_xfer_handle);
 Static void             uhci_device_bulk_abort(usbd_xfer_handle);  Static void             uhci_device_bulk_abort(usbd_xfer_handle);
 Static void             uhci_device_bulk_close(usbd_pipe_handle);  Static void             uhci_device_bulk_close(usbd_pipe_handle);
Static void             uhci_device_bulk_done (usbd_xfer_handle);Static void             uhci_device_bulk_done(usbd_xfer_handle);
   
 Static usbd_status      uhci_device_isoc_transfer(usbd_xfer_handle);  Static usbd_status      uhci_device_isoc_transfer(usbd_xfer_handle);
 Static usbd_status      uhci_device_isoc_start(usbd_xfer_handle);  Static usbd_status      uhci_device_isoc_start(usbd_xfer_handle);
 Static void             uhci_device_isoc_abort(usbd_xfer_handle);  Static void             uhci_device_isoc_abort(usbd_xfer_handle);
 Static void             uhci_device_isoc_close(usbd_pipe_handle);  Static void             uhci_device_isoc_close(usbd_pipe_handle);
Static void             uhci_device_isoc_done (usbd_xfer_handle);Static void             uhci_device_isoc_done(usbd_xfer_handle);
   
 Static usbd_status      uhci_root_ctrl_transfer(usbd_xfer_handle);  Static usbd_status      uhci_root_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status      uhci_root_ctrl_start(usbd_xfer_handle);  Static usbd_status      uhci_root_ctrl_start(usbd_xfer_handle);
 Static void             uhci_root_ctrl_abort(usbd_xfer_handle);  Static void             uhci_root_ctrl_abort(usbd_xfer_handle);
 Static void             uhci_root_ctrl_close(usbd_pipe_handle);  Static void             uhci_root_ctrl_close(usbd_pipe_handle);
   Static void             uhci_root_ctrl_done(usbd_xfer_handle);
   
 Static usbd_status      uhci_root_intr_transfer(usbd_xfer_handle);  Static usbd_status      uhci_root_intr_transfer(usbd_xfer_handle);
 Static usbd_status      uhci_root_intr_start(usbd_xfer_handle);  Static usbd_status      uhci_root_intr_start(usbd_xfer_handle);
 Static void             uhci_root_intr_abort(usbd_xfer_handle);  Static void             uhci_root_intr_abort(usbd_xfer_handle);
 Static void             uhci_root_intr_close(usbd_pipe_handle);  Static void             uhci_root_intr_close(usbd_pipe_handle);
Static void             uhci_root_intr_done (usbd_xfer_handle);Static void             uhci_root_intr_done(usbd_xfer_handle);
   
 Static usbd_status      uhci_open(usbd_pipe_handle);  Static usbd_status      uhci_open(usbd_pipe_handle);
 Static void             uhci_poll(struct usbd_bus *);  Static void             uhci_poll(struct usbd_bus *);
   Static void             uhci_softintr(void *);
   
 Static usbd_status      uhci_device_request(usbd_xfer_handle xfer);  Static usbd_status      uhci_device_request(usbd_xfer_handle xfer);
   
Static void             uhci_add_intr(uhci_softc_t *, int, uhci_soft_qh_t *);Static void             uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *);
Static void             uhci_remove_intr(uhci_softc_t *, int, uhci_soft_qh_t *);Static void             uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *);
Static usbd_status      uhci_device_setintr(uhci_softc_t *sc, Static usbd_status      uhci_device_setintr(uhci_softc_t *sc,
                             struct uhci_pipe *pipe, int ival);                              struct uhci_pipe *pipe, int ival);
   
 Static void             uhci_device_clear_toggle(usbd_pipe_handle pipe);  Static void             uhci_device_clear_toggle(usbd_pipe_handle pipe);
 Static void             uhci_noop(usbd_pipe_handle pipe);  Static void             uhci_noop(usbd_pipe_handle pipe);
   
   Static __inline__ uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *,
                                                       uhci_soft_qh_t *);
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
   Static void             uhci_dump_all(uhci_softc_t *);
 Static void             uhci_dumpregs(uhci_softc_t *);  Static void             uhci_dumpregs(uhci_softc_t *);
 Static void             uhci_dump_qhs(uhci_soft_qh_t *);  Static void             uhci_dump_qhs(uhci_soft_qh_t *);
 Static void             uhci_dump_qh(uhci_soft_qh_t *);  Static void             uhci_dump_qh(uhci_soft_qh_t *);
 Static void             uhci_dump_tds(uhci_soft_td_t *);  Static void             uhci_dump_tds(uhci_soft_td_t *);
 Static void             uhci_dump_td(uhci_soft_td_t *);  Static void             uhci_dump_td(uhci_soft_td_t *);
   Static void             uhci_dump_ii(uhci_intr_info_t *ii);
   void                    uhci_dump(void);
 #endif  #endif
   
#define UWRITE1(sc, r, x) bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x))#define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
#define UWRITE2(sc, r, x) bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x))                        BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
#define UWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x))#define UWRITE1(sc, r, x) \
#define UREAD1(sc, r) bus_space_read_1((sc)->iot, (sc)->ioh, (r)) do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \
#define UREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r)) } while (/*CONSTCOND*/0)
#define UREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r))#define UWRITE2(sc, r, x) \
  do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \
  } while (/*CONSTCOND*/0)
 #define UWRITE4(sc, r, x) \
  do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \
  } while (/*CONSTCOND*/0)
 #define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r)))
 #define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r)))
 #define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r)))
   
 #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)  #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
 #define UHCISTS(sc) UREAD2(sc, UHCI_STS)  #define UHCISTS(sc) UREAD2(sc, UHCI_STS)
   
#define UHCI_RESET_TIMEOUT 100  /* reset timeout */#define UHCI_RESET_TIMEOUT 100  /* ms, reset timeout */
   
 #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)  #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)
   
Line 275  Static void  uhci_dump_td(uhci_soft_td_t Line 319  Static void  uhci_dump_td(uhci_soft_td_t
   
 struct usbd_bus_methods uhci_bus_methods = {  struct usbd_bus_methods uhci_bus_methods = {
         uhci_open,          uhci_open,
           uhci_softintr,
         uhci_poll,          uhci_poll,
         uhci_allocm,          uhci_allocm,
         uhci_freem,          uhci_freem,
Line 282  struct usbd_bus_methods uhci_bus_methods Line 327  struct usbd_bus_methods uhci_bus_methods
         uhci_freex,          uhci_freex,
 };  };
   
struct usbd_pipe_methods uhci_root_ctrl_methods = {     struct usbd_pipe_methods uhci_root_ctrl_methods = {
         uhci_root_ctrl_transfer,          uhci_root_ctrl_transfer,
         uhci_root_ctrl_start,          uhci_root_ctrl_start,
         uhci_root_ctrl_abort,          uhci_root_ctrl_abort,
         uhci_root_ctrl_close,          uhci_root_ctrl_close,
         uhci_noop,          uhci_noop,
        0,        uhci_root_ctrl_done,
 };  };
   
struct usbd_pipe_methods uhci_root_intr_methods = {     struct usbd_pipe_methods uhci_root_intr_methods = {
         uhci_root_intr_transfer,          uhci_root_intr_transfer,
         uhci_root_intr_start,          uhci_root_intr_start,
         uhci_root_intr_abort,          uhci_root_intr_abort,
Line 336  struct usbd_pipe_methods uhci_device_iso Line 381  struct usbd_pipe_methods uhci_device_iso
         uhci_device_isoc_done,          uhci_device_isoc_done,
 };  };
   
   #define uhci_add_intr_info(sc, ii) \
           LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list)
   #define uhci_del_intr_info(ii) \
           do { \
                   LIST_REMOVE((ii), list); \
                   (ii)->list.le_prev = NULL; \
           } while (0)
   #define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL)
   
   Static __inline__ uhci_soft_qh_t *
   uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh)
   {
           DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh));
   
           for (; pqh->hlink != sqh; pqh = pqh->hlink) {
   #if defined(DIAGNOSTIC) || defined(USB_DEBUG)
                   if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) {
                           printf("uhci_find_prev_qh: QH not found\n");
                           return (NULL);
                   }
   #endif
           }
           return (pqh);
   }
   
 void  void
uhci_busreset(uhci_softc_t *sc)uhci_globalreset(uhci_softc_t *sc)
 {  {
         UHCICMD(sc, UHCI_CMD_GRESET);   /* global reset */          UHCICMD(sc, UHCI_CMD_GRESET);   /* global reset */
         usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */          usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */
Line 349  uhci_init(uhci_softc_t *sc) Line 419  uhci_init(uhci_softc_t *sc)
 {  {
         usbd_status err;          usbd_status err;
         int i, j;          int i, j;
        uhci_soft_qh_t *csqh, *bsqh, *sqh;        uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh;
         uhci_soft_td_t *std;          uhci_soft_td_t *std;
   
         DPRINTFN(1,("uhci_init: start\n"));          DPRINTFN(1,("uhci_init: start\n"));
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
           thesc = sc;
   
         if (uhcidebug > 2)          if (uhcidebug > 2)
                 uhci_dumpregs(sc);                  uhci_dumpregs(sc);
 #endif  #endif
   
         uhci_run(sc, 0);                        /* stop the controller */  
         UWRITE2(sc, UHCI_INTR, 0);              /* disable interrupts */          UWRITE2(sc, UHCI_INTR, 0);              /* disable interrupts */
        uhci_globalreset(sc);                      /* reset the controller */
        uhci_busreset(sc);        uhci_reset(sc);
   
         /* Allocate and initialize real frame array. */          /* Allocate and initialize real frame array. */
        err = usb_allocmem(&sc->sc_bus,         err = usb_allocmem(&sc->sc_bus,
                   UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),                    UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
                   UHCI_FRAMELIST_ALIGN, &sc->sc_dma);                    UHCI_FRAMELIST_ALIGN, &sc->sc_dma);
         if (err)          if (err)
Line 374  uhci_init(uhci_softc_t *sc) Line 445  uhci_init(uhci_softc_t *sc)
         UWRITE2(sc, UHCI_FRNUM, 0);             /* set frame number to 0 */          UWRITE2(sc, UHCI_FRNUM, 0);             /* set frame number to 0 */
         UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/          UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/
   
           /*
            * Allocate a TD, inactive, that hangs from the last QH.
            * This is to avoid a bug in the PIIX that makes it run berserk
            * otherwise.
            */
           std = uhci_alloc_std(sc);
           if (std == NULL)
                   return (USBD_NOMEM);
           std->link.std = NULL;
           std->td.td_link = htole32(UHCI_PTR_T);
           std->td.td_status = htole32(0); /* inactive */
           std->td.td_token = htole32(0);
           std->td.td_buffer = htole32(0);
   
           /* Allocate the dummy QH marking the end and used for looping the QHs.*/
           lsqh = uhci_alloc_sqh(sc);
           if (lsqh == NULL)
                   return (USBD_NOMEM);
           lsqh->hlink = NULL;
           lsqh->qh.qh_hlink = htole32(UHCI_PTR_T);        /* end of QH chain */
           lsqh->elink = std;
           lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD);
           sc->sc_last_qh = lsqh;
   
         /* Allocate the dummy QH where bulk traffic will be queued. */          /* Allocate the dummy QH where bulk traffic will be queued. */
         bsqh = uhci_alloc_sqh(sc);          bsqh = uhci_alloc_sqh(sc);
         if (bsqh == NULL)          if (bsqh == NULL)
                 return (USBD_NOMEM);                  return (USBD_NOMEM);
        bsqh->qh.qh_hlink = LE(UHCI_PTR_T);     /* end of QH chain */        bsqh->hlink = lsqh;
        bsqh->qh.qh_elink = LE(UHCI_PTR_T);        bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH);
         bsqh->elink = NULL;
         bsqh->qh.qh_elink = htole32(UHCI_PTR_T);
         sc->sc_bulk_start = sc->sc_bulk_end = bsqh;          sc->sc_bulk_start = sc->sc_bulk_end = bsqh;
   
        /* Allocate the dummy QH where control traffic will be queued. */        /* Allocate dummy QH where high speed control traffic will be queued. */
        csqh = uhci_alloc_sqh(sc);        chsqh = uhci_alloc_sqh(sc);
        if (csqh == NULL)        if (chsqh == NULL)
                 return (USBD_NOMEM);
         chsqh->hlink = bsqh;
         chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
         chsqh->elink = NULL;
         chsqh->qh.qh_elink = htole32(UHCI_PTR_T);
         sc->sc_hctl_start = sc->sc_hctl_end = chsqh;
 
         /* Allocate dummy QH where control traffic will be queued. */
         clsqh = uhci_alloc_sqh(sc);
         if (clsqh == NULL)
                 return (USBD_NOMEM);                  return (USBD_NOMEM);
        csqh->hlink = bsqh;        clsqh->hlink = bsqh;
        csqh->qh.qh_hlink = LE(bsqh->physaddr | UHCI_PTR_Q);        clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH);
        csqh->qh.qh_elink = LE(UHCI_PTR_T);        clsqh->elink = NULL;
        sc->sc_ctl_start = sc->sc_ctl_end = csqh;        clsqh->qh.qh_elink = htole32(UHCI_PTR_T);
         sc->sc_lctl_start = sc->sc_lctl_end = clsqh;
   
        /*         /*
          * Make all (virtual) frame list pointers point to the interrupt           * Make all (virtual) frame list pointers point to the interrupt
          * queue heads and the interrupt queue heads at the control           * queue heads and the interrupt queue heads at the control
          * queue head and point the physical frame list to the virtual.           * queue head and point the physical frame list to the virtual.
Line 402  uhci_init(uhci_softc_t *sc) Line 510  uhci_init(uhci_softc_t *sc)
                 if (std == NULL || sqh == NULL)                  if (std == NULL || sqh == NULL)
                         return (USBD_NOMEM);                          return (USBD_NOMEM);
                 std->link.sqh = sqh;                  std->link.sqh = sqh;
                std->td.td_link = LE(sqh->physaddr | UHCI_PTR_Q);
                std->td.td_status = LE(UHCI_TD_IOS);  /* iso, inactive */                std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH);
                std->td.td_xtoken = LE(0);                std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
                std->td.td_buffer = LE(0);                std->td.td_token = htole32(0);
                sqh->hlink = csqh;                std->td.td_buffer = htole32(0);
                sqh->qh.qh_hlink = LE(csqh->physaddr | UHCI_PTR_Q);                sqh->hlink = clsqh;
                sqh->elink = 0;                sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH);
                sqh->qh.qh_elink = LE(UHCI_PTR_T);                sqh->elink = NULL;
                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
                 sc->sc_vframes[i].htd = std;                  sc->sc_vframes[i].htd = std;
                 sc->sc_vframes[i].etd = std;                  sc->sc_vframes[i].etd = std;
                 sc->sc_vframes[i].hqh = sqh;                  sc->sc_vframes[i].hqh = sqh;
                 sc->sc_vframes[i].eqh = sqh;                  sc->sc_vframes[i].eqh = sqh;
                for (j = i;                 for (j = i;
                     j < UHCI_FRAMELIST_COUNT;                      j < UHCI_FRAMELIST_COUNT;
                     j += UHCI_VFRAMELIST_COUNT)                     j += UHCI_VFRAMELIST_COUNT) {
                        sc->sc_pframes[j] = LE(std->physaddr);                        sc->sc_pframes[j] = htole32(std->physaddr);
                 }
         }          }
   
         LIST_INIT(&sc->sc_intrhead);          LIST_INIT(&sc->sc_intrhead);
   
         SIMPLEQ_INIT(&sc->sc_free_xfers);          SIMPLEQ_INIT(&sc->sc_free_xfers);
   
           usb_callout_init(sc->sc_poll_handle);
   
         /* Set up the bus struct. */          /* Set up the bus struct. */
         sc->sc_bus.methods = &uhci_bus_methods;          sc->sc_bus.methods = &uhci_bus_methods;
         sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);          sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
   
   #if defined(__NetBSD__) || defined(__OpenBSD__)
         sc->sc_suspend = PWR_RESUME;          sc->sc_suspend = PWR_RESUME;
 #if defined(__NetBSD__)  
         sc->sc_powerhook = powerhook_establish(uhci_power, sc);          sc->sc_powerhook = powerhook_establish(uhci_power, sc);
         sc->sc_shutdownhook = shutdownhook_establish(uhci_shutdown, sc);          sc->sc_shutdownhook = shutdownhook_establish(uhci_shutdown, sc);
 #endif  #endif
         DPRINTFN(1,("uhci_init: enabling\n"));          DPRINTFN(1,("uhci_init: enabling\n"));
        UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |         UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
                 UHCI_INTR_IOCE | UHCI_INTR_SPIE);       /* enable interrupts */                  UHCI_INTR_IOCE | UHCI_INTR_SPIE);       /* enable interrupts */
   
         UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */          UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */
Line 452  uhci_activate(device_ptr_t self, enum de Line 564  uhci_activate(device_ptr_t self, enum de
         switch (act) {          switch (act) {
         case DVACT_ACTIVATE:          case DVACT_ACTIVATE:
                 return (EOPNOTSUPP);                  return (EOPNOTSUPP);
                 break;  
   
         case DVACT_DEACTIVATE:          case DVACT_DEACTIVATE:
                 if (sc->sc_child != NULL)                  if (sc->sc_child != NULL)
Line 470  uhci_detach(struct uhci_softc *sc, int f Line 581  uhci_detach(struct uhci_softc *sc, int f
   
         if (sc->sc_child != NULL)          if (sc->sc_child != NULL)
                 rv = config_detach(sc->sc_child, flags);                  rv = config_detach(sc->sc_child, flags);
        
         if (rv != 0)          if (rv != 0)
                 return (rv);                  return (rv);
   
#if defined(__NetBSD__)#if defined(__NetBSD__) || defined(__OpenBSD__)
         powerhook_disestablish(sc->sc_powerhook);          powerhook_disestablish(sc->sc_powerhook);
         shutdownhook_disestablish(sc->sc_shutdownhook);          shutdownhook_disestablish(sc->sc_shutdownhook);
 #endif  #endif
Line 484  uhci_detach(struct uhci_softc *sc, int f Line 595  uhci_detach(struct uhci_softc *sc, int f
                 xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);                  xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
                 if (xfer == NULL)                  if (xfer == NULL)
                         break;                          break;
                SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next);                SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
                 free(xfer, M_USB);                  free(xfer, M_USB);
        }                               }
   
         /* XXX free other data structures XXX */          /* XXX free other data structures XXX */
   
Line 497  uhci_detach(struct uhci_softc *sc, int f Line 608  uhci_detach(struct uhci_softc *sc, int f
 usbd_status  usbd_status
 uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)  uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
 {  {
        return (usb_allocmem(&((struct uhci_softc *)bus)->sc_bus, size, 0,        return (usb_allocmem(bus, size, 0, dma));
                             dma)); 
 }  }
   
 void  void
 uhci_freem(struct usbd_bus *bus, usb_dma_t *dma)  uhci_freem(struct usbd_bus *bus, usb_dma_t *dma)
 {  {
        usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma);        usb_freemem(bus, dma);
 }  }
   
 usbd_xfer_handle  usbd_xfer_handle
Line 514  uhci_allocx(struct usbd_bus *bus) Line 624  uhci_allocx(struct usbd_bus *bus)
         usbd_xfer_handle xfer;          usbd_xfer_handle xfer;
   
         xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);          xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
        if (xfer != NULL)        if (xfer != NULL) {
                SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next);                SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
        else#ifdef DIAGNOSTIC
                xfer = malloc(sizeof(*xfer), M_USB, M_NOWAIT);                if (xfer->busy_free != XFER_FREE) {
        if (xfer != NULL)                        printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer,
                memset(xfer, 0, sizeof *xfer);                               xfer->busy_free);
                 }
 #endif
         } else {
                 xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT);
         }
         if (xfer != NULL) {
                 memset(xfer, 0, sizeof (struct uhci_xfer));
                 UXFER(xfer)->iinfo.sc = sc;
 #ifdef DIAGNOSTIC
                 UXFER(xfer)->iinfo.isdone = 1;
                 xfer->busy_free = XFER_BUSY;
 #endif
         }
         return (xfer);          return (xfer);
 }  }
   
Line 528  uhci_freex(struct usbd_bus *bus, usbd_xf Line 651  uhci_freex(struct usbd_bus *bus, usbd_xf
 {  {
         struct uhci_softc *sc = (struct uhci_softc *)bus;          struct uhci_softc *sc = (struct uhci_softc *)bus;
   
   #ifdef DIAGNOSTIC
           if (xfer->busy_free != XFER_BUSY) {
                   printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer,
                          xfer->busy_free);
                   return;
           }
           xfer->busy_free = XFER_FREE;
           if (!UXFER(xfer)->iinfo.isdone) {
                   printf("uhci_freex: !isdone\n");
                   return;
           }
   #endif
         SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);          SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
 }  }
   
Line 547  uhci_shutdown(void *v) Line 682  uhci_shutdown(void *v)
  * Handle suspend/resume.   * Handle suspend/resume.
  *   *
  * We need to switch to polling mode here, because this routine is   * We need to switch to polling mode here, because this routine is
 * called from an intterupt context.  This is all right since we * called from an interrupt context.  This is all right since we
  * are almost suspended anyway.   * are almost suspended anyway.
  */   */
 void  void
Line 557  uhci_power(int why, void *v) Line 692  uhci_power(int why, void *v)
         int cmd;          int cmd;
         int s;          int s;
   
        s = splusb();        s = splhardusb();
         cmd = UREAD2(sc, UHCI_CMD);          cmd = UREAD2(sc, UHCI_CMD);
   
        DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n",         DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n",
                  sc, why, sc->sc_suspend, cmd));                   sc, why, sc->sc_suspend, cmd));
   
         if (why != PWR_RESUME) {          if (why != PWR_RESUME) {
Line 568  uhci_power(int why, void *v) Line 703  uhci_power(int why, void *v)
                 if (uhcidebug > 2)                  if (uhcidebug > 2)
                         uhci_dumpregs(sc);                          uhci_dumpregs(sc);
 #endif  #endif
                if (sc->sc_has_timo != NULL)                if (sc->sc_intr_xfer != NULL)
                        usb_untimeout(uhci_timo, sc->sc_has_timo                        usb_uncallout(sc->sc_poll_handle, uhci_poll_hub,
                                      sc->sc_has_timo->timo_handle);                            sc->sc_intr_xfer);
                 sc->sc_bus.use_polling++;                  sc->sc_bus.use_polling++;
                 uhci_run(sc, 0); /* stop the controller */                  uhci_run(sc, 0); /* stop the controller */
   
Line 578  uhci_power(int why, void *v) Line 713  uhci_power(int why, void *v)
                 sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);                  sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);
                 sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);                  sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);
   
                   UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */
   
                 UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */                  UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */
                 usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);                  usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
                 sc->sc_suspend = why;                  sc->sc_suspend = why;
Line 601  uhci_power(int why, void *v) Line 738  uhci_power(int why, void *v)
                 UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */                  UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
                 usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);                  usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
                 UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */                  UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
                UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |                 UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
                         UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */                          UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
                 UHCICMD(sc, UHCI_CMD_MAXP);                  UHCICMD(sc, UHCI_CMD_MAXP);
                 uhci_run(sc, 1); /* and start traffic again */                  uhci_run(sc, 1); /* and start traffic again */
                 usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);                  usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
                 sc->sc_bus.use_polling--;                  sc->sc_bus.use_polling--;
                if (sc->sc_has_timo != NULL)                if (sc->sc_intr_xfer != NULL)
                        usb_timeout(uhci_timo, sc->sc_has_timo,                         usb_callout(sc->sc_poll_handle, sc->sc_ival,
                                    sc->sc_ival, sc->sc_has_timo->timo_handle);                                    uhci_poll_hub, sc->sc_intr_xfer);
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
                 if (uhcidebug > 2)                  if (uhcidebug > 2)
                         uhci_dumpregs(sc);                          uhci_dumpregs(sc);
Line 638  uhci_dumpregs(uhci_softc_t *sc) Line 775  uhci_dumpregs(uhci_softc_t *sc)
 void  void
 uhci_dump_td(uhci_soft_td_t *p)  uhci_dump_td(uhci_soft_td_t *p)
 {  {
           char sbuf[128], sbuf2[128];
   
         DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx "          DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx "
                      "token=0x%08lx buffer=0x%08lx\n",                       "token=0x%08lx buffer=0x%08lx\n",
                      p, (long)p->physaddr,                       p, (long)p->physaddr,
                     (long)LE(p->td.td_link),                     (long)le32toh(p->td.td_link),
                     (long)LE(p->td.td_status),                     (long)le32toh(p->td.td_status),
                     (long)LE(p->td.td_xtoken),                     (long)le32toh(p->td.td_token),
                     (long)LE(p->td.td_buffer)));                     (long)le32toh(p->td.td_buffer)));
        DPRINTFN(-1,("  %b %b,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d,"
                     "D=%d,maxlen=%d\n",        bitmask_snprintf((u_int32_t)le32toh(p->td.td_link), "\20\1T\2Q\3VF",
                     (int)LE(p->td.td_link),                        sbuf, sizeof(sbuf));
                     "\20\1T\2Q\3VF",        bitmask_snprintf((u_int32_t)le32toh(p->td.td_status),
                     (int)LE(p->td.td_status),                        "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
                     "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"                        "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",
                     "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",                        sbuf2, sizeof(sbuf2));
                     UHCI_TD_GET_ERRCNT(LE(p->td.td_status)),
                     UHCI_TD_GET_ACTLEN(LE(p->td.td_status)),        DPRINTFN(-1,("  %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d,"
                     UHCI_TD_GET_PID(LE(p->td.td_xtoken)),                    "D=%d,maxlen=%d\n", sbuf, sbuf2,
                     UHCI_TD_GET_DEVADDR(LE(p->td.td_xtoken)),                    UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)),
                     UHCI_TD_GET_ENDPT(LE(p->td.td_xtoken)),                    UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)),
                     UHCI_TD_GET_DT(LE(p->td.td_xtoken)),                    UHCI_TD_GET_PID(le32toh(p->td.td_token)),
                     UHCI_TD_GET_MAXLEN(LE(p->td.td_xtoken))));                    UHCI_TD_GET_DEVADDR(le32toh(p->td.td_token)),
                     UHCI_TD_GET_ENDPT(le32toh(p->td.td_token)),
                     UHCI_TD_GET_DT(le32toh(p->td.td_token)),
                     UHCI_TD_GET_MAXLEN(le32toh(p->td.td_token))));
 }  }
   
 void  void
 uhci_dump_qh(uhci_soft_qh_t *sqh)  uhci_dump_qh(uhci_soft_qh_t *sqh)
 {  {
         DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh,          DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh,
            (int)sqh->physaddr, LE(sqh->qh.qh_hlink), LE(sqh->qh.qh_elink)));                (int)sqh->physaddr, le32toh(sqh->qh.qh_hlink),
                 le32toh(sqh->qh.qh_elink)));
 }  }
   
#if 1
#if 0 
 void  void
uhci_dump()uhci_dump(void)
 {  {
        uhci_softc_t *sc = uhci;        uhci_dump_all(thesc);
 }
 #endif
   
   void
   uhci_dump_all(uhci_softc_t *sc)
   {
         uhci_dumpregs(sc);          uhci_dumpregs(sc);
         printf("intrs=%d\n", sc->sc_bus.no_intrs);          printf("intrs=%d\n", sc->sc_bus.no_intrs);
        printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);        /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/
        uhci_dump_qh(sc->sc_ctl_start->qh.hlink);        uhci_dump_qh(sc->sc_lctl_start);
 }  }
 #endif  
   
   
 void  void
 uhci_dump_qhs(uhci_soft_qh_t *sqh)  uhci_dump_qhs(uhci_soft_qh_t *sqh)
Line 703  uhci_dump_qhs(uhci_soft_qh_t *sqh) Line 848  uhci_dump_qhs(uhci_soft_qh_t *sqh)
          */           */
   
   
        if (sqh->hlink != NULL && !(sqh->qh.qh_hlink & UHCI_PTR_T))        if (sqh->hlink != NULL && !(le32toh(sqh->qh.qh_hlink) & UHCI_PTR_T))
                 uhci_dump_qhs(sqh->hlink);                  uhci_dump_qhs(sqh->hlink);
         else          else
                 DPRINTF(("No QH\n"));                  DPRINTF(("No QH\n"));
   
        if (sqh->elink != NULL && !(sqh->qh.qh_elink & UHCI_PTR_T))        if (sqh->elink != NULL && !(le32toh(sqh->qh.qh_elink) & UHCI_PTR_T))
                 uhci_dump_tds(sqh->elink);                  uhci_dump_tds(sqh->elink);
         else          else
                 DPRINTF(("No TD\n"));                  DPRINTF(("No TD\n"));
Line 727  uhci_dump_tds(uhci_soft_td_t *std) Line 872  uhci_dump_tds(uhci_soft_td_t *std)
                  * printing the free list in case the queue/TD has                   * printing the free list in case the queue/TD has
                  * already been moved there (seatbelt).                   * already been moved there (seatbelt).
                  */                   */
                if (td->td.td_link & UHCI_PTR_T ||                if (le32toh(td->td.td_link) & UHCI_PTR_T ||
                    td->td.td_link == 0)                    le32toh(td->td.td_link) == 0)
                         break;                          break;
         }          }
 }  }
   
   Static void
   uhci_dump_ii(uhci_intr_info_t *ii)
   {
           usbd_pipe_handle pipe;
           usb_endpoint_descriptor_t *ed;
           usbd_device_handle dev;
   
   #ifdef DIAGNOSTIC
   #define DONE ii->isdone
   #else
   #define DONE 0
   #endif
           if (ii == NULL) {
                   printf("ii NULL\n");
                   return;
           }
           if (ii->xfer == NULL) {
                   printf("ii %p: done=%d xfer=NULL\n",
                          ii, DONE);
                   return;
           }
           pipe = ii->xfer->pipe;
           if (pipe == NULL) {
                   printf("ii %p: done=%d xfer=%p pipe=NULL\n",
                          ii, DONE, ii->xfer);
                   return;
           }
           if (pipe->endpoint == NULL) {
                   printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n",
                          ii, DONE, ii->xfer, pipe);
                   return;
           }
           if (pipe->device == NULL) {
                   printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n",
                          ii, DONE, ii->xfer, pipe);
                   return;
           }
           ed = pipe->endpoint->edesc;
           dev = pipe->device;
           printf("ii %p: done=%d xfer=%p dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n",
                  ii, DONE, ii->xfer, dev,
                  UGETW(dev->ddesc.idVendor),
                  UGETW(dev->ddesc.idProduct),
                  dev->address, pipe,
                  ed->bEndpointAddress, ed->bmAttributes);
   #undef DONE
   }
   
   void uhci_dump_iis(struct uhci_softc *sc);
   void
   uhci_dump_iis(struct uhci_softc *sc)
   {
           uhci_intr_info_t *ii;
   
           printf("intr_info list:\n");
           for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))
                   uhci_dump_ii(ii);
   }
   
   void iidump(void);
   void iidump(void) { uhci_dump_iis(thesc); }
   
 #endif  #endif
   
 /*  /*
Line 739  uhci_dump_tds(uhci_soft_td_t *std) Line 947  uhci_dump_tds(uhci_soft_td_t *std)
  * from the root controller interrupt pipe for port status change.   * from the root controller interrupt pipe for port status change.
  */   */
 void  void
uhci_timo(void *addr)uhci_poll_hub(void *addr)
 {  {
         usbd_xfer_handle xfer = addr;          usbd_xfer_handle xfer = addr;
         usbd_pipe_handle pipe = xfer->pipe;          usbd_pipe_handle pipe = xfer->pipe;
Line 747  uhci_timo(void *addr) Line 955  uhci_timo(void *addr)
         int s;          int s;
         u_char *p;          u_char *p;
   
        DPRINTFN(20, ("uhci_timo\n"));        DPRINTFN(20, ("uhci_poll_hub\n"));
   
        usb_timeout(uhci_timo, xfer, sc->sc_ival, xfer->timo_handle);        usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer);
   
         p = KERNADDR(&xfer->dmabuf, 0);          p = KERNADDR(&xfer->dmabuf, 0);
         p[0] = 0;          p[0] = 0;
Line 764  uhci_timo(void *addr) Line 972  uhci_timo(void *addr)
         xfer->actlen = 1;          xfer->actlen = 1;
         xfer->status = USBD_NORMAL_COMPLETION;          xfer->status = USBD_NORMAL_COMPLETION;
         s = splusb();          s = splusb();
         xfer->hcpriv = 0;  
         xfer->device->bus->intr_context++;          xfer->device->bus->intr_context++;
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         xfer->device->bus->intr_context--;          xfer->device->bus->intr_context--;
Line 777  uhci_root_intr_done(usbd_xfer_handle xfe Line 984  uhci_root_intr_done(usbd_xfer_handle xfe
 }  }
   
 void  void
uhci_lock_frames(uhci_softc_t *sc)uhci_root_ctrl_done(usbd_xfer_handle xfer)
 {  {
        int s = splusb();}
   
        while (sc->sc_vflock & UHCI_HAS_LOCK) {/*
                sc->sc_vflock |= UHCI_WANT_LOCK; * Let the last QH loop back to the high speed control transfer QH.
                tsleep(&sc->sc_vflock, 0, "uhcqhl", 0); * This is what intel calls "bandwidth reclamation" and improves
  * USB performance a lot for some devices.
  * If we are already looping, just count it.
  */
 void
 uhci_add_loop(uhci_softc_t *sc) {
 #ifdef USB_DEBUG
         if (uhcinoloop)
                 return;
 #endif
         if (++sc->sc_loops == 1) {
                 DPRINTFN(5,("uhci_start_loop: add\n"));
                 /* Note, we don't loop back the soft pointer. */
                 sc->sc_last_qh->qh.qh_hlink =
                     htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH);
         }          }
         sc->sc_vflock = UHCI_HAS_LOCK;  
         splx(s);  
 }  }
   
 void  void
uhci_unlock_frames(uhci_softc_t *sc)uhci_rem_loop(uhci_softc_t *sc) {
{#ifdef USB_DEBUG
        int s = splusb();        if (uhcinoloop)
                return;
        sc->sc_vflock &= ~UHCI_HAS_LOCK;#endif
        if (sc->sc_vflock & UHCI_WANT_LOCK)        if (--sc->sc_loops == 0) {
                wakeup(&sc->sc_vflock);                DPRINTFN(5,("uhci_end_loop: remove\n"));
        splx(s);                sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T);
         }
 }  }
   
/*/* Add high speed control QH, called at splusb(). */
 * Allocate an interrupt information struct.  A free list is keptvoid
 * for fast allocation.uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
 */ 
uhci_intr_info_t * 
uhci_alloc_intr_info(uhci_softc_t *sc) 
 {  {
        uhci_intr_info_t *ii;        uhci_soft_qh_t *eqh;
   
        ii = LIST_FIRST(&uhci_ii_free);        SPLUSBCHECK;
        if (ii) 
                LIST_REMOVE(ii, list); 
        else { 
                ii = malloc(sizeof(uhci_intr_info_t), M_USBHC, M_NOWAIT); 
        } 
        ii->sc = sc; 
#if defined(__FreeBSD__) 
        callout_handle_init(&ii->timeout_handle); 
#endif 
   
        return ii;        DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh));
         eqh = sc->sc_hctl_end;
         sqh->hlink       = eqh->hlink;
         sqh->qh.qh_hlink = eqh->qh.qh_hlink;
         eqh->hlink       = sqh;
         eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
         sc->sc_hctl_end = sqh;
 #ifdef UHCI_CTL_LOOP
         uhci_add_loop(sc);
 #endif
 }  }
   
   /* Remove high speed control QH, called at splusb(). */
 void  void
uhci_free_intr_info(uhci_intr_info_t *ii)uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
 {  {
        LIST_INSERT_HEAD(&uhci_ii_free, ii, list); /* and put on free list */        uhci_soft_qh_t *pqh;
 
         SPLUSBCHECK;
 
         DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh));
 #ifdef UHCI_CTL_LOOP
         uhci_rem_loop(sc);
 #endif
         /*
          * The T bit should be set in the elink of the QH so that the HC
          * doesn't follow the pointer.  This condition may fail if the
          * the transferred packet was short so that the QH still points
          * at the last used TD.
          * In this case we set the T bit and wait a little for the HC
          * to stop looking at the TD.
          */
         if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
                 delay(UHCI_QH_REMOVE_DELAY);
         }
 
         pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
         pqh->hlink = sqh->hlink;
         pqh->qh.qh_hlink = sqh->qh.qh_hlink;
         delay(UHCI_QH_REMOVE_DELAY);
         if (sc->sc_hctl_end == sqh)
                 sc->sc_hctl_end = pqh;
 }  }
   
/* Add control QH, called at splusb(). *//* Add low speed control QH, called at splusb(). */
 void  void
uhci_add_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
 {  {
         uhci_soft_qh_t *eqh;          uhci_soft_qh_t *eqh;
   
         SPLUSBCHECK;          SPLUSBCHECK;
   
        DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh));        DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh));
        eqh = sc->sc_ctl_end;        eqh = sc->sc_lctl_end;
        sqh->hlink       = eqh->hlink;        sqh->hlink = eqh->hlink;
         sqh->qh.qh_hlink = eqh->qh.qh_hlink;          sqh->qh.qh_hlink = eqh->qh.qh_hlink;
        eqh->hlink       = sqh;        eqh->hlink = sqh;
        eqh->qh.qh_hlink = LE(sqh->physaddr | UHCI_PTR_Q);        eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
        sc->sc_ctl_end = sqh;        sc->sc_lctl_end = sqh;
 }  }
   
/* Remove control QH, called at splusb(). *//* Remove low speed control QH, called at splusb(). */
 void  void
uhci_remove_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
 {  {
         uhci_soft_qh_t *pqh;          uhci_soft_qh_t *pqh;
   
         SPLUSBCHECK;          SPLUSBCHECK;
   
        DPRINTFN(10, ("uhci_remove_ctrl: sqh=%p\n", sqh));        DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh));
        for (pqh = sc->sc_ctl_start; pqh->hlink != sqh; pqh=pqh->hlink)        /* See comment in uhci_remove_hs_ctrl() */
#if defined(DIAGNOSTIC) || defined(USB_DEBUG)                   if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
                if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) {                sqh->qh.qh_elink = htole32(UHCI_PTR_T);
                        printf("uhci_remove_ctrl: QH not found\n");                delay(UHCI_QH_REMOVE_DELAY);
                        return;        }
                }        pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
#else        pqh->hlink = sqh->hlink;
                ; 
#endif 
        pqh->hlink       = sqh->hlink; 
         pqh->qh.qh_hlink = sqh->qh.qh_hlink;          pqh->qh.qh_hlink = sqh->qh.qh_hlink;
        if (sc->sc_ctl_end == sqh)        delay(UHCI_QH_REMOVE_DELAY);
                sc->sc_ctl_end = pqh;        if (sc->sc_lctl_end == sqh)
                 sc->sc_lctl_end = pqh;
 }  }
   
 /* Add bulk QH, called at splusb(). */  /* Add bulk QH, called at splusb(). */
Line 880  uhci_add_bulk(uhci_softc_t *sc, uhci_sof Line 1122  uhci_add_bulk(uhci_softc_t *sc, uhci_sof
   
         DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));          DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));
         eqh = sc->sc_bulk_end;          eqh = sc->sc_bulk_end;
        sqh->hlink       = eqh->hlink;        sqh->hlink = eqh->hlink;
         sqh->qh.qh_hlink = eqh->qh.qh_hlink;          sqh->qh.qh_hlink = eqh->qh.qh_hlink;
        eqh->hlink       = sqh;        eqh->hlink = sqh;
        eqh->qh.qh_hlink = LE(sqh->physaddr | UHCI_PTR_Q);        eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
         sc->sc_bulk_end = sqh;          sc->sc_bulk_end = sqh;
           uhci_add_loop(sc);
 }  }
   
 /* Remove bulk QH, called at splusb(). */  /* Remove bulk QH, called at splusb(). */
Line 896  uhci_remove_bulk(uhci_softc_t *sc, uhci_ Line 1139  uhci_remove_bulk(uhci_softc_t *sc, uhci_
         SPLUSBCHECK;          SPLUSBCHECK;
   
         DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));          DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));
        for (pqh = sc->sc_bulk_start; pqh->hlink != sqh; pqh = pqh->hlink)        uhci_rem_loop(sc);
#if defined(DIAGNOSTIC) || defined(USB_DEBUG)                   /* See comment in uhci_remove_hs_ctrl() */
                if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) {        if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
                        printf("uhci_remove_bulk: QH not found\n");                sqh->qh.qh_elink = htole32(UHCI_PTR_T);
                        return;                delay(UHCI_QH_REMOVE_DELAY);
                }        }
#else        pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh);
                ; 
#endif 
         pqh->hlink       = sqh->hlink;          pqh->hlink       = sqh->hlink;
         pqh->qh.qh_hlink = sqh->qh.qh_hlink;          pqh->qh.qh_hlink = sqh->qh.qh_hlink;
           delay(UHCI_QH_REMOVE_DELAY);
         if (sc->sc_bulk_end == sqh)          if (sc->sc_bulk_end == sqh)
                 sc->sc_bulk_end = pqh;                  sc->sc_bulk_end = pqh;
 }  }
   
   Static int uhci_intr1(uhci_softc_t *);
   
 int  int
 uhci_intr(void *arg)  uhci_intr(void *arg)
 {  {
         uhci_softc_t *sc = arg;          uhci_softc_t *sc = arg;
   
           if (sc->sc_dying)
                   return (0);
   
           DPRINTFN(15,("uhci_intr: real interrupt\n"));
           if (sc->sc_bus.use_polling) {
   #ifdef DIAGNOSTIC
                   printf("uhci_intr: ignored interrupt while polling\n");
   #endif
                   return (0);
           }
           return (uhci_intr1(sc));
   }
   
   int
   uhci_intr1(uhci_softc_t *sc)
   {
   
         int status;          int status;
         int ack;          int ack;
         uhci_intr_info_t *ii;  
   
         /*          /*
          * It can happen that an interrupt will be delivered to           * It can happen that an interrupt will be delivered to
Line 937  uhci_intr(void *arg) Line 1198  uhci_intr(void *arg)
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         if (uhcidebug > 15) {          if (uhcidebug > 15) {
                DPRINTF(("%s: uhci_intr\n", USBDEVNAME(sc->sc_bus.bdev)));                DPRINTF(("%s: uhci_intr1\n", USBDEVNAME(sc->sc_bus.bdev)));
                 uhci_dumpregs(sc);                  uhci_dumpregs(sc);
         }          }
 #endif  #endif
        status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS;
        status = UREAD2(sc, UHCI_STS); 
         if (status == 0)        /* The interrupt was not for us. */          if (status == 0)        /* The interrupt was not for us. */
                 return (0);                  return (0);
   
Line 951  uhci_intr(void *arg) Line 1211  uhci_intr(void *arg)
                 printf("uhci_intr: suspended sts=0x%x\n", status);                  printf("uhci_intr: suspended sts=0x%x\n", status);
 #endif  #endif
   
           if (sc->sc_suspend != PWR_RESUME) {
                   printf("%s: interrupt while not operating ignored\n",
                          USBDEVNAME(sc->sc_bus.bdev));
                   UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */
                   return (0);
           }
   
         ack = 0;          ack = 0;
         if (status & UHCI_STS_USBINT)          if (status & UHCI_STS_USBINT)
                 ack |= UHCI_STS_USBINT;                  ack |= UHCI_STS_USBINT;
Line 958  uhci_intr(void *arg) Line 1225  uhci_intr(void *arg)
                 ack |= UHCI_STS_USBEI;                  ack |= UHCI_STS_USBEI;
         if (status & UHCI_STS_RD) {          if (status & UHCI_STS_RD) {
                 ack |= UHCI_STS_RD;                  ack |= UHCI_STS_RD;
   #ifdef USB_DEBUG
                 printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev));                  printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev));
   #endif
         }          }
         if (status & UHCI_STS_HSE) {          if (status & UHCI_STS_HSE) {
                 ack |= UHCI_STS_HSE;                  ack |= UHCI_STS_HSE;
Line 966  uhci_intr(void *arg) Line 1235  uhci_intr(void *arg)
         }          }
         if (status & UHCI_STS_HCPE) {          if (status & UHCI_STS_HCPE) {
                 ack |= UHCI_STS_HCPE;                  ack |= UHCI_STS_HCPE;
                printf("%s: host controller process error\n",                 printf("%s: host controller process error\n",
                        USBDEVNAME(sc->sc_bus.bdev));                         USBDEVNAME(sc->sc_bus.bdev));
         }          }
         if (status & UHCI_STS_HCH) {          if (status & UHCI_STS_HCH) {
                 /* no acknowledge needed */                  /* no acknowledge needed */
                printf("%s: host controller halted\n",                 if (!sc->sc_dying) {
                       USBDEVNAME(sc->sc_bus.bdev));                        printf("%s: host controller halted\n",
                             USBDEVNAME(sc->sc_bus.bdev));
 #ifdef USB_DEBUG
                         uhci_dump_all(sc);
 #endif
                 }
                 sc->sc_dying = 1;
         }          }
   
        if (ack)    /* acknowledge the ints */        if (!ack)
                UWRITE2(sc, UHCI_STS, ack);                return (0);     /* nothing to acknowledge */
        else    /* nothing to acknowledge */        UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */
                return (0); 
   
         sc->sc_bus.intr_context++;  
         sc->sc_bus.no_intrs++;          sc->sc_bus.no_intrs++;
           usb_schedsoftintr(&sc->sc_bus);
   
           DPRINTFN(15, ("%s: uhci_intr: exit\n", USBDEVNAME(sc->sc_bus.bdev)));
   
           return (1);
   }
   
   void
   uhci_softintr(void *v)
   {
           uhci_softc_t *sc = v;
           uhci_intr_info_t *ii;
   
           DPRINTFN(10,("%s: uhci_softintr (%d)\n", USBDEVNAME(sc->sc_bus.bdev),
                        sc->sc_bus.intr_context));
   
           sc->sc_bus.intr_context++;
   
         /*          /*
          * Interrupts on UHCI really suck.  When the host controller           * Interrupts on UHCI really suck.  When the host controller
Line 994  uhci_intr(void *arg) Line 1284  uhci_intr(void *arg)
          * We scan all interrupt descriptors to see if any have           * We scan all interrupt descriptors to see if any have
          * completed.           * completed.
          */           */
        for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))        LIST_FOREACH(ii, &sc->sc_intrhead, list)
                 uhci_check_intr(sc, ii);                  uhci_check_intr(sc, ii);
   
        DPRINTFN(10, ("%s: uhci_intr: exit\n", USBDEVNAME(sc->sc_bus.bdev)));#ifdef USB_USE_SOFTINTR
         if (sc->sc_softwake) {
                 sc->sc_softwake = 0;
                 wakeup(&sc->sc_softwake);
         }
 #endif /* USB_USE_SOFTINTR */
   
         sc->sc_bus.intr_context--;          sc->sc_bus.intr_context--;
   
         return (1);  
 }  }
   
 /* Check for an interrupt. */  /* Check for an interrupt. */
Line 1018  uhci_check_intr(uhci_softc_t *sc, uhci_i Line 1311  uhci_check_intr(uhci_softc_t *sc, uhci_i
                 return;                  return;
         }          }
 #endif  #endif
           if (ii->xfer->status == USBD_CANCELLED ||
               ii->xfer->status == USBD_TIMEOUT) {
                   DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer));
                   return;
           }
   
         if (ii->stdstart == NULL)          if (ii->stdstart == NULL)
                 return;                  return;
         lstd = ii->stdend;          lstd = ii->stdend;
Line 1029  uhci_check_intr(uhci_softc_t *sc, uhci_i Line 1328  uhci_check_intr(uhci_softc_t *sc, uhci_i
 #endif  #endif
         /*           /* 
          * If the last TD is still active we need to check whether there           * If the last TD is still active we need to check whether there
         * is a an error somewhere in the middle, or whether there was a         * is an error somewhere in the middle, or whether there was a
          * short packet (SPD and not ACTIVE).           * short packet (SPD and not ACTIVE).
          */           */
        if (LE(lstd->td.td_status) & UHCI_TD_ACTIVE) {        if (le32toh(lstd->td.td_status) & UHCI_TD_ACTIVE) {
                DPRINTFN(15, ("uhci_check_intr: active ii=%p\n", ii));                DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii));
                 for (std = ii->stdstart; std != lstd; std = std->link.std) {                  for (std = ii->stdstart; std != lstd; std = std->link.std) {
                        status = LE(std->td.td_status);                        status = le32toh(std->td.td_status);
                         /* If there's an active TD the xfer isn't done. */                          /* If there's an active TD the xfer isn't done. */
                         if (status & UHCI_TD_ACTIVE)                          if (status & UHCI_TD_ACTIVE)
                                 break;                                  break;
                         /* Any kind of error makes the xfer done. */                          /* Any kind of error makes the xfer done. */
                         if (status & UHCI_TD_STALLED)                          if (status & UHCI_TD_STALLED)
                                 goto done;                                  goto done;
                        /*                        /* We want short packets, and it is short: it's done */
                         * We want short packets, 
                         * and it is short: it's done 
                         */ 
                         if ((status & UHCI_TD_SPD) &&                          if ((status & UHCI_TD_SPD) &&
                             UHCI_TD_GET_ACTLEN(status) <                              UHCI_TD_GET_ACTLEN(status) <
                            UHCI_TD_GET_MAXLEN(LE(std->td.td_xtoken)))                            UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token))) {
                                 goto done;                                  goto done;
                           }
                 }                  }
                DPRINTFN(15, ("uhci_check_intr: ii=%p std=%p still active\n",                DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n",
                    ii, ii->stdstart));                        ii, ii->stdstart));
                 return;                  return;
         }          }
 done:  done:
        DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii));
        usb_untimeout(uhci_timeout, ii, ii->timeout_handle);        usb_uncallout(ii->xfer->timeout_handle, uhci_timeout, ii);
         uhci_idone(ii);          uhci_idone(ii);
 }  }
   
Line 1071  uhci_idone(uhci_intr_info_t *ii) Line 1368  uhci_idone(uhci_intr_info_t *ii)
         u_int32_t status = 0, nstatus;          u_int32_t status = 0, nstatus;
         int actlen;          int actlen;
   
           DPRINTFN(12, ("uhci_idone: ii=%p\n", ii));
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         {          {
                 int s = splhigh();                  int s = splhigh();
                 if (ii->isdone) {                  if (ii->isdone) {
                         splx(s);                          splx(s);
   #ifdef USB_DEBUG
                           printf("uhci_idone: ii is done!\n   ");
                           uhci_dump_ii(ii);
   #else
                         printf("uhci_idone: ii=%p is done!\n", ii);                          printf("uhci_idone: ii=%p is done!\n", ii);
   #endif
                         return;                          return;
                 }                  }
                 ii->isdone = 1;                  ii->isdone = 1;
Line 1084  uhci_idone(uhci_intr_info_t *ii) Line 1387  uhci_idone(uhci_intr_info_t *ii)
         }          }
 #endif  #endif
   
         if (xfer->status == USBD_CANCELLED ||  
             xfer->status == USBD_TIMEOUT) {  
                 DPRINTF(("uhci_idone: aborted xfer=%p\n", xfer));  
                 return;  
         }  
   
         if (xfer->nframes != 0) {          if (xfer->nframes != 0) {
                 /* Isoc transfer, do things differently. */                  /* Isoc transfer, do things differently. */
                 uhci_soft_td_t **stds = upipe->u.iso.stds;                  uhci_soft_td_t **stds = upipe->u.iso.stds;
                int i, n, nframes;                int i, n, nframes, len;
   
                 DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii));                  DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii));
   
                 nframes = xfer->nframes;                  nframes = xfer->nframes;
                 actlen = 0;                  actlen = 0;
                n = xfer->hcprivint;                n = UXFER(xfer)->curframe;
                 for (i = 0; i < nframes; i++) {                  for (i = 0; i < nframes; i++) {
                         std = stds[n];                          std = stds[n];
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
Line 1110  uhci_idone(uhci_intr_info_t *ii) Line 1407  uhci_idone(uhci_intr_info_t *ii)
 #endif  #endif
                         if (++n >= UHCI_VFRAMELIST_COUNT)                          if (++n >= UHCI_VFRAMELIST_COUNT)
                                 n = 0;                                  n = 0;
                        status = LE(std->td.td_status);                        status = le32toh(std->td.td_status);
                        actlen += UHCI_TD_GET_ACTLEN(status);                        len = UHCI_TD_GET_ACTLEN(status);
                         xfer->frlengths[i] = len;
                         actlen += len;
                 }                  }
                 upipe->u.iso.inuse -= nframes;                  upipe->u.iso.inuse -= nframes;
                 xfer->actlen = actlen;                  xfer->actlen = actlen;
                 xfer->status = USBD_NORMAL_COMPLETION;                  xfer->status = USBD_NORMAL_COMPLETION;
                xfer->hcpriv = ii;                goto end;
                usb_transfer_complete(xfer); 
                return; 
         }          }
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
Line 1131  uhci_idone(uhci_intr_info_t *ii) Line 1428  uhci_idone(uhci_intr_info_t *ii)
         /* The transfer is done, compute actual length and status. */          /* The transfer is done, compute actual length and status. */
         actlen = 0;          actlen = 0;
         for (std = ii->stdstart; std != NULL; std = std->link.std) {          for (std = ii->stdstart; std != NULL; std = std->link.std) {
                nstatus = LE(std->td.td_status);                nstatus = le32toh(std->td.td_status);
                 if (nstatus & UHCI_TD_ACTIVE)                  if (nstatus & UHCI_TD_ACTIVE)
                         break;                          break;
   
                 status = nstatus;                  status = nstatus;
                if (UHCI_TD_GET_PID(LE(std->td.td_xtoken)) != UHCI_TD_PID_SETUP)                if (UHCI_TD_GET_PID(le32toh(std->td.td_token)) !=
                     UHCI_TD_PID_SETUP) {
                         actlen += UHCI_TD_GET_ACTLEN(status);                          actlen += UHCI_TD_GET_ACTLEN(status);
                   } else {
                           /*
                            * UHCI will report CRCTO in addition to a STALL or NAK
                            * for a SETUP transaction.  See section 3.2.2, "TD
                            * CONTROL AND STATUS".
                            */
                           if (status & (UHCI_TD_STALLED | UHCI_TD_NAK))
                                   status &= ~UHCI_TD_CRCTO;
                   }
   
         }          }
         /* If there are left over TDs we need to update the toggle. */          /* If there are left over TDs we need to update the toggle. */
         if (std != NULL)          if (std != NULL)
                upipe->nexttoggle = UHCI_TD_GET_DT(LE(std->td.td_xtoken));                upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token));
   
         status &= UHCI_TD_ERROR;          status &= UHCI_TD_ERROR;
        DPRINTFN(10, ("uhci_check_intr: actlen=%d, status=0x%x\n",         DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n",
                       actlen, status));                        actlen, status));
         xfer->actlen = actlen;          xfer->actlen = actlen;
         if (status != 0) {          if (status != 0) {
   #ifdef USB_DEBUG
                   char sbuf[128];
   
                   bitmask_snprintf((u_int32_t)status,
                                   "\20\22BITSTUFF\23CRCTO\24NAK\25"
                                   "BABBLE\26DBUFFER\27STALLED\30ACTIVE",
                                   sbuf, sizeof(sbuf));
   
                 DPRINTFN((status == UHCI_TD_STALLED)*10,                  DPRINTFN((status == UHCI_TD_STALLED)*10,
                          ("uhci_idone: error, addr=%d, endpt=0x%02x, "                           ("uhci_idone: error, addr=%d, endpt=0x%02x, "
                          "status 0x%b\n",                          "status 0x%s\n",
                           xfer->pipe->device->address,                            xfer->pipe->device->address,
                           xfer->pipe->endpoint->edesc->bEndpointAddress,                            xfer->pipe->endpoint->edesc->bEndpointAddress,
                          (int)status,                           sbuf));
                          "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"#endif
                          "STALLED\30ACTIVE")); 
                 if (status == UHCI_TD_STALLED)                  if (status == UHCI_TD_STALLED)
                         xfer->status = USBD_STALLED;                          xfer->status = USBD_STALLED;
                 else                  else
Line 1163  uhci_idone(uhci_intr_info_t *ii) Line 1478  uhci_idone(uhci_intr_info_t *ii)
         } else {          } else {
                 xfer->status = USBD_NORMAL_COMPLETION;                  xfer->status = USBD_NORMAL_COMPLETION;
         }          }
        xfer->hcpriv = ii;
  end:
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
           DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii));
 }  }
   
 /*  /*
Line 1174  void Line 1491  void
 uhci_timeout(void *addr)  uhci_timeout(void *addr)
 {  {
         uhci_intr_info_t *ii = addr;          uhci_intr_info_t *ii = addr;
           struct uhci_xfer *uxfer = UXFER(ii->xfer);
           struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe;
           uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
   
        DPRINTF(("uhci_timeout: ii=%p\n", ii));        DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer));
   
#ifdef USB_DEBUG        if (sc->sc_dying) {
        if (uhcidebug > 10)                uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT);
                uhci_dump_tds(ii->stdstart);                return;
#endif        }
   
        ii->xfer->device->bus->intr_context++;        /* Execute the abort in a process context. */
        uhci_abort_xfer(ii->xfer, USBD_TIMEOUT);        usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer);
        ii->xfer->device->bus->intr_context--;        usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task);
 }
 
 void
 uhci_timeout_task(void *addr)
 {
         usbd_xfer_handle xfer = addr;
         int s;
 
         DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer));
 
         s = splusb();
         uhci_abort_xfer(xfer, USBD_TIMEOUT);
         splx(s);
 }  }
   
 /*  /*
Line 1206  uhci_waitintr(uhci_softc_t *sc, usbd_xfe Line 1539  uhci_waitintr(uhci_softc_t *sc, usbd_xfe
                 usb_delay_ms(&sc->sc_bus, 1);                  usb_delay_ms(&sc->sc_bus, 1);
                 DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS)));                  DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS)));
                 if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT)                  if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT)
                        uhci_intr(sc);                        uhci_intr1(sc);
                 if (xfer->status != USBD_IN_PROGRESS)                  if (xfer->status != USBD_IN_PROGRESS)
                         return;                          return;
         }          }
Line 1214  uhci_waitintr(uhci_softc_t *sc, usbd_xfe Line 1547  uhci_waitintr(uhci_softc_t *sc, usbd_xfe
         /* Timeout */          /* Timeout */
         DPRINTF(("uhci_waitintr: timeout\n"));          DPRINTF(("uhci_waitintr: timeout\n"));
         for (ii = LIST_FIRST(&sc->sc_intrhead);          for (ii = LIST_FIRST(&sc->sc_intrhead);
             ii != NULL && ii->xfer != xfer;              ii != NULL && ii->xfer != xfer;
              ii = LIST_NEXT(ii, list))               ii = LIST_NEXT(ii, list))
                 ;                  ;
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (ii == NULL)          if (ii == NULL)
                panic("uhci_waitintr: lost intr_info\n");                panic("uhci_waitintr: lost intr_info");
 #endif  #endif
         uhci_idone(ii);          uhci_idone(ii);
 }  }
Line 1230  uhci_poll(struct usbd_bus *bus) Line 1563  uhci_poll(struct usbd_bus *bus)
         uhci_softc_t *sc = (uhci_softc_t *)bus;          uhci_softc_t *sc = (uhci_softc_t *)bus;
   
         if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT)          if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT)
                uhci_intr(sc);                uhci_intr1(sc);
 }  }
   
 #if 0  
 void  void
uhci_reset(void *p)uhci_reset(uhci_softc_t *sc)
 {  {
         uhci_softc_t *sc = p;  
         int n;          int n;
   
         UHCICMD(sc, UHCI_CMD_HCRESET);          UHCICMD(sc, UHCI_CMD_HCRESET);
         /* The reset bit goes low when the controller is done. */          /* The reset bit goes low when the controller is done. */
        for (n = 0; n < UHCI_RESET_TIMEOUT &&         for (n = 0; n < UHCI_RESET_TIMEOUT &&
                     (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)                      (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)
                delay(100);                usb_delay_ms(&sc->sc_bus, 1);
         if (n >= UHCI_RESET_TIMEOUT)          if (n >= UHCI_RESET_TIMEOUT)
                printf("%s: controller did not reset\n",                 printf("%s: controller did not reset\n",
                        USBDEVNAME(sc->sc_bus.bdev));                         USBDEVNAME(sc->sc_bus.bdev));
 }  }
 #endif  
   
 usbd_status  usbd_status
 uhci_run(uhci_softc_t *sc, int run)  uhci_run(uhci_softc_t *sc, int run)
Line 1258  uhci_run(uhci_softc_t *sc, int run) Line 1588  uhci_run(uhci_softc_t *sc, int run)
         u_int16_t cmd;          u_int16_t cmd;
   
         run = run != 0;          run = run != 0;
        s = splusb();        s = splhardusb();
         DPRINTF(("uhci_run: setting run=%d\n", run));          DPRINTF(("uhci_run: setting run=%d\n", run));
         cmd = UREAD2(sc, UHCI_CMD);          cmd = UREAD2(sc, UHCI_CMD);
         if (run)          if (run)
Line 1309  uhci_alloc_std(uhci_softc_t *sc) Line 1639  uhci_alloc_std(uhci_softc_t *sc)
                         return (0);                          return (0);
                 for(i = 0; i < UHCI_STD_CHUNK; i++) {                  for(i = 0; i < UHCI_STD_CHUNK; i++) {
                         offs = i * UHCI_STD_SIZE;                          offs = i * UHCI_STD_SIZE;
                        std = (uhci_soft_td_t *)((char *)KERNADDR(&dma, offs));                        std = KERNADDR(&dma, offs);
                         std->physaddr = DMAADDR(&dma, offs);                          std->physaddr = DMAADDR(&dma, offs);
                         std->link.std = sc->sc_freetds;                          std->link.std = sc->sc_freetds;
                         sc->sc_freetds = std;                          sc->sc_freetds = std;
Line 1326  uhci_free_std(uhci_softc_t *sc, uhci_sof Line 1656  uhci_free_std(uhci_softc_t *sc, uhci_sof
 {  {
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
 #define TD_IS_FREE 0x12345678  #define TD_IS_FREE 0x12345678
        if (std->td.td_xtoken == LE(TD_IS_FREE)) {        if (le32toh(std->td.td_token) == TD_IS_FREE) {
                 printf("uhci_free_std: freeing free TD %p\n", std);                  printf("uhci_free_std: freeing free TD %p\n", std);
                 return;                  return;
         }          }
        std->td.td_xtoken = LE(TD_IS_FREE);        std->td.td_token = htole32(TD_IS_FREE);
 #endif  #endif
         std->link.std = sc->sc_freetds;          std->link.std = sc->sc_freetds;
         sc->sc_freetds = std;          sc->sc_freetds = std;
Line 1352  uhci_alloc_sqh(uhci_softc_t *sc) Line 1682  uhci_alloc_sqh(uhci_softc_t *sc)
                         return (0);                          return (0);
                 for(i = 0; i < UHCI_SQH_CHUNK; i++) {                  for(i = 0; i < UHCI_SQH_CHUNK; i++) {
                         offs = i * UHCI_SQH_SIZE;                          offs = i * UHCI_SQH_SIZE;
                        sqh = (uhci_soft_qh_t *)((char *)KERNADDR(&dma, offs));                        sqh = KERNADDR(&dma, offs);
                         sqh->physaddr = DMAADDR(&dma, offs);                          sqh->physaddr = DMAADDR(&dma, offs);
                         sqh->hlink = sc->sc_freeqhs;                          sqh->hlink = sc->sc_freeqhs;
                         sc->sc_freeqhs = sqh;                          sc->sc_freeqhs = sqh;
Line 1371  uhci_free_sqh(uhci_softc_t *sc, uhci_sof Line 1701  uhci_free_sqh(uhci_softc_t *sc, uhci_sof
         sc->sc_freeqhs = sqh;          sc->sc_freeqhs = sqh;
 }  }
   
 #if 0  
 /*   
  * Enter a list of transfers onto a control queue.  
  * Called at splusb()   
  */  
 void  
 uhci_enter_ctl_q(uhci_softc_t *sc, uhci_soft_qh_t *sqh, uhci_intr_info_t *ii)  
 {  
         DPRINTFN(5, ("uhci_enter_ctl_q: sqh=%p\n", sqh));  
   
 }  
 #endif  
   
 void  void
 uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std,  uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std,
        uhci_soft_td_t *stdend)                    uhci_soft_td_t *stdend)
 {  {
         uhci_soft_td_t *p;          uhci_soft_td_t *p;
   
Line 1397  uhci_free_std_chain(uhci_softc_t *sc, uh Line 1714  uhci_free_std_chain(uhci_softc_t *sc, uh
 }  }
   
 usbd_status  usbd_status
uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc,uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
        int len, int rd, u_int16_t flags, usb_dma_t *dma,                     int rd, u_int16_t flags, usb_dma_t *dma,
        uhci_soft_td_t **sp, uhci_soft_td_t **ep)                     uhci_soft_td_t **sp, uhci_soft_td_t **ep)
 {  {
         uhci_soft_td_t *p, *lastp;          uhci_soft_td_t *p, *lastp;
         uhci_physaddr_t lastlink;          uhci_physaddr_t lastlink;
Line 1408  uhci_alloc_std_chain(struct uhci_pipe *u Line 1725  uhci_alloc_std_chain(struct uhci_pipe *u
         int addr = upipe->pipe.device->address;          int addr = upipe->pipe.device->address;
         int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;          int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
   
        DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d ls=%d "        DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d "
                      "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len,                       "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len,
                      upipe->pipe.device->lowspeed, flags));                      upipe->pipe.device->speed, flags));
         maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);          maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);
         if (maxp == 0) {          if (maxp == 0) {
                 printf("uhci_alloc_std_chain: maxp=0\n");                  printf("uhci_alloc_std_chain: maxp=0\n");
Line 1429  uhci_alloc_std_chain(struct uhci_pipe *u Line 1746  uhci_alloc_std_chain(struct uhci_pipe *u
         if (ntd % 2 == 0)          if (ntd % 2 == 0)
                 tog ^= 1;                  tog ^= 1;
         upipe->nexttoggle = tog ^ 1;          upipe->nexttoggle = tog ^ 1;
        lastp = 0;        lastp = NULL;
         lastlink = UHCI_PTR_T;          lastlink = UHCI_PTR_T;
         ntd--;          ntd--;
         status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);          status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
        if (upipe->pipe.device->lowspeed)        if (upipe->pipe.device->speed == USB_SPEED_LOW)
                 status |= UHCI_TD_LS;                  status |= UHCI_TD_LS;
         if (flags & USBD_SHORT_XFER_OK)          if (flags & USBD_SHORT_XFER_OK)
                 status |= UHCI_TD_SPD;                  status |= UHCI_TD_SPD;
         for (i = ntd; i >= 0; i--) {          for (i = ntd; i >= 0; i--) {
                 p = uhci_alloc_std(sc);                  p = uhci_alloc_std(sc);
                 if (p == NULL) {                  if (p == NULL) {
                        uhci_free_std_chain(sc, lastp, 0);                        uhci_free_std_chain(sc, lastp, NULL);
                         return (USBD_NOMEM);                          return (USBD_NOMEM);
                 }                  }
                 p->link.std = lastp;                  p->link.std = lastp;
                if (lastlink == UHCI_PTR_T)                p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD);
                        p->td.td_link = LE(lastlink); 
                else 
                        p->td.td_link = LE(lastlink|UHCI_PTR_VF); 
                 lastp = p;                  lastp = p;
                 lastlink = p->physaddr;                  lastlink = p->physaddr;
                p->td.td_status = LE(status);                p->td.td_status = htole32(status);
                 if (i == ntd) {                  if (i == ntd) {
                         /* last TD */                          /* last TD */
                         l = len % maxp;                          l = len % maxp;
Line 1459  uhci_alloc_std_chain(struct uhci_pipe *u Line 1773  uhci_alloc_std_chain(struct uhci_pipe *u
                         *ep = p;                          *ep = p;
                 } else                  } else
                         l = maxp;                          l = maxp;
                p->td.td_xtoken =                 p->td.td_token =
                    LE(rd ? UHCI_TD_IN (l, endpt, addr, tog) :                        htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) :
                            UHCI_TD_OUT(l, endpt, addr, tog));                                     UHCI_TD_OUT(l, endpt, addr, tog));
                p->td.td_buffer = LE(DMAADDR(dma, i * maxp));                p->td.td_buffer = htole32(DMAADDR(dma, i * maxp));
                 tog ^= 1;                  tog ^= 1;
         }          }
         *sp = lastp;          *sp = lastp;
        DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",         DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",
                       upipe->nexttoggle));                        upipe->nexttoggle));
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
 }  }
Line 1493  uhci_device_bulk_transfer(usbd_xfer_hand Line 1807  uhci_device_bulk_transfer(usbd_xfer_hand
         if (err)          if (err)
                 return (err);                  return (err);
   
        /* Pipe isn't running (otherwise err would be USBD_INPROG),        /*
         * start first         * Pipe isn't running (otherwise err would be USBD_INPROG),
          * so start it first.
          */           */
         return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
 }  }
Line 1505  uhci_device_bulk_start(usbd_xfer_handle Line 1820  uhci_device_bulk_start(usbd_xfer_handle
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
         usbd_device_handle dev = upipe->pipe.device;          usbd_device_handle dev = upipe->pipe.device;
         uhci_softc_t *sc = (uhci_softc_t *)dev->bus;          uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
        uhci_intr_info_t *ii = upipe->iinfo;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         uhci_soft_td_t *data, *dataend;          uhci_soft_td_t *data, *dataend;
         uhci_soft_qh_t *sqh;          uhci_soft_qh_t *sqh;
         usbd_status err;          usbd_status err;
         int len, isread, endpt;          int len, isread, endpt;
         int s;          int s;
   
        DPRINTFN(3, ("uhci_device_bulk_transfer: xfer=%p len=%d flags=%d\n",        DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n",
                     xfer, xfer->length, xfer->flags));                     xfer, xfer->length, xfer->flags, ii));
 
         if (sc->sc_dying)
                 return (USBD_IOERROR);
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (xfer->rqflags & URQ_REQUEST)          if (xfer->rqflags & URQ_REQUEST)
                panic("uhci_device_bulk_transfer: a request\n");                panic("uhci_device_bulk_transfer: a request");
 #endif  #endif
   
         len = xfer->length;          len = xfer->length;
        endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;        endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
         isread = UE_GET_DIR(endpt) == UE_DIR_IN;          isread = UE_GET_DIR(endpt) == UE_DIR_IN;
         sqh = upipe->u.bulk.sqh;          sqh = upipe->u.bulk.sqh;
   
Line 1532  uhci_device_bulk_start(usbd_xfer_handle Line 1850  uhci_device_bulk_start(usbd_xfer_handle
                                    &xfer->dmabuf, &data, &dataend);                                     &xfer->dmabuf, &data, &dataend);
         if (err)          if (err)
                 return (err);                  return (err);
        dataend->td.td_status |= LE(UHCI_TD_IOC);        dataend->td.td_status |= htole32(UHCI_TD_IOC);
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         if (uhcidebug > 8) {          if (uhcidebug > 8) {
Line 1545  uhci_device_bulk_start(usbd_xfer_handle Line 1863  uhci_device_bulk_start(usbd_xfer_handle
         ii->xfer = xfer;          ii->xfer = xfer;
         ii->stdstart = data;          ii->stdstart = data;
         ii->stdend = dataend;          ii->stdend = dataend;
 #if defined(__FreeBSD__)  
         callout_handle_init(&ii->timeout_handle);  
 #endif  
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!ii->isdone) {          if (!ii->isdone) {
                 printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii);                  printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii);
Line 1556  uhci_device_bulk_start(usbd_xfer_handle Line 1871  uhci_device_bulk_start(usbd_xfer_handle
 #endif  #endif
   
         sqh->elink = data;          sqh->elink = data;
        sqh->qh.qh_elink = LE(data->physaddr);        sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
        sqh->intr_info = ii; 
   
         s = splusb();          s = splusb();
         uhci_add_bulk(sc, sqh);          uhci_add_bulk(sc, sqh);
        LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);        uhci_add_intr_info(sc, ii);
   
         if (xfer->timeout && !sc->sc_bus.use_polling) {          if (xfer->timeout && !sc->sc_bus.use_polling) {
                usb_timeout(uhci_timeout, ii, MS_TO_TICKS(xfer->timeout),                usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
                            ii->timeout_handle);                            uhci_timeout, ii);
         }          }
           xfer->status = USBD_IN_PROGRESS;
         splx(s);          splx(s);
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
Line 1590  uhci_device_bulk_abort(usbd_xfer_handle Line 1905  uhci_device_bulk_abort(usbd_xfer_handle
         uhci_abort_xfer(xfer, USBD_CANCELLED);          uhci_abort_xfer(xfer, USBD_CANCELLED);
 }  }
   
   /*
    * Abort a device request.
    * If this routine is called at splusb() it guarantees that the request
    * will be removed from the hardware scheduling and that the callback
    * for it will be called with USBD_CANCELLED status.
    * It's impossible to guarantee that the requested transfer will not
    * have happened since the hardware runs concurrently.
    * If the transaction has already happened we rely on the ordinary
    * interrupt processing to process it.
    */
 void  void
 uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)  uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
 {  {
           uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
        uhci_intr_info_t *ii = upipe->iinfo;        uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
         uhci_soft_td_t *std;          uhci_soft_td_t *std;
           int s;
   
         DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));          DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
   
        /* Make interrupt routine ignore it, */        if (sc->sc_dying) {
        xfer->status = status;                /* If we're dying, just do the software part. */
                 s = splusb();
                 xfer->status = status;  /* make software ignore it */
                 usb_uncallout(xfer->timeout_handle, uhci_timeout, xfer);
                 usb_transfer_complete(xfer);
                 splx(s);
                 return;
         }
   
        /* don't timeout, */        if (xfer->device->bus->intr_context /* || !curproc REMOVED DFly */)
        usb_untimeout(uhci_timeout, ii, ii->timeout_handle);                panic("uhci_abort_xfer: not in process context");
   
        /* make hardware ignore it, */        /*
        for (std = ii->stdstart; std != 0; std = std->link.std)         * Step 1: Make interrupt routine and hardware ignore xfer.
                std->td.td_status &= LE(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));         */
         s = splusb();
         xfer->status = status;  /* make software ignore it */
         usb_uncallout(xfer->timeout_handle, uhci_timeout, ii);
         DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
         for (std = ii->stdstart; std != NULL; std = std->link.std)
                 std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
         splx(s);
   
        xfer->hcpriv = ii;        /*
          * Step 2: Wait until we know hardware has finished any possible
          * use of the xfer.  Also make sure the soft interrupt routine
          * has run.
          */
         usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */
         s = splusb();
 #ifdef USB_USE_SOFTINTR
         sc->sc_softwake = 1;
 #endif /* USB_USE_SOFTINTR */
         usb_schedsoftintr(&sc->sc_bus);
 #ifdef USB_USE_SOFTINTR
         DPRINTFN(1,("uhci_abort_xfer: tsleep\n"));
         tsleep(&sc->sc_softwake, 0, "uhciab", 0);
 #endif /* USB_USE_SOFTINTR */
         splx(s);
   
#if 1        /*
        /* Make sure hardware has completed. */         * Step 3: Execute callback.
        if (xfer->device->bus->intr_context) {         */
                /* We have no process context, so we can't use tsleep(). */        xfer->hcpriv = ii;
                timeout(uhci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND); 
        } else { 
#if defined(DIAGNOSTIC) && defined(__FreeBSD__) 
                KASSERT(mycpu->gd_intr_nesting_level == 0, 
                        ("ohci_abort_req in interrupt context")); 
#endif 
                usb_delay_ms(xfer->pipe->device->bus, 1); 
                /* and call final part of interrupt handler. */ 
                uhci_abort_xfer_end(xfer); 
        } 
#else 
        delay(1000); 
        uhci_abort_xfer_end(xfer); 
#endif 
} 
   
void        DPRINTFN(1,("uhci_abort_xfer: callback\n"));
uhci_abort_xfer_end(void *v) 
{ 
        usbd_xfer_handle xfer = v; 
        int s; 
   
         s = splusb();          s = splusb();
   #ifdef DIAGNOSTIC
           ii->isdone = 1;
   #endif
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         splx(s);          splx(s);
 }  }
Line 1651  uhci_device_bulk_close(usbd_pipe_handle Line 1991  uhci_device_bulk_close(usbd_pipe_handle
         uhci_softc_t *sc = (uhci_softc_t *)dev->bus;          uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
   
         uhci_free_sqh(sc, upipe->u.bulk.sqh);          uhci_free_sqh(sc, upipe->u.bulk.sqh);
         uhci_free_intr_info(upipe->iinfo);  
         /* XXX free other resources */  
 }  }
   
 usbd_status  usbd_status
Line 1665  uhci_device_ctrl_transfer(usbd_xfer_hand Line 2003  uhci_device_ctrl_transfer(usbd_xfer_hand
         if (err)          if (err)
                 return (err);                  return (err);
   
        /* Pipe isn't running (otherwise err would be USBD_INPROG),        /*
         * start first         * Pipe isn't running (otherwise err would be USBD_INPROG),
          * so start it first.
          */           */
         return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
 }  }
Line 1677  uhci_device_ctrl_start(usbd_xfer_handle Line 2016  uhci_device_ctrl_start(usbd_xfer_handle
         uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;          uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
         usbd_status err;          usbd_status err;
   
           if (sc->sc_dying)
                   return (USBD_IOERROR);
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!(xfer->rqflags & URQ_REQUEST))          if (!(xfer->rqflags & URQ_REQUEST))
                panic("uhci_device_ctrl_transfer: not a request\n");                panic("uhci_device_ctrl_transfer: not a request");
 #endif  #endif
   
         err = uhci_device_request(xfer);          err = uhci_device_request(xfer);
Line 1701  uhci_device_intr_transfer(usbd_xfer_hand Line 2043  uhci_device_intr_transfer(usbd_xfer_hand
         if (err)          if (err)
                 return (err);                  return (err);
   
        /* Pipe isn't running (otherwise err would be USBD_INPROG),        /*
         * start first         * Pipe isn't running (otherwise err would be USBD_INPROG),
          * so start it first.
          */           */
         return (uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return (uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
 }  }
Line 1713  uhci_device_intr_start(usbd_xfer_handle Line 2056  uhci_device_intr_start(usbd_xfer_handle
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
         usbd_device_handle dev = upipe->pipe.device;          usbd_device_handle dev = upipe->pipe.device;
         uhci_softc_t *sc = (uhci_softc_t *)dev->bus;          uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
        uhci_intr_info_t *ii = upipe->iinfo;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         uhci_soft_td_t *data, *dataend;          uhci_soft_td_t *data, *dataend;
         uhci_soft_qh_t *sqh;          uhci_soft_qh_t *sqh;
         usbd_status err;          usbd_status err;
           int isread, endpt;
         int i, s;          int i, s;
   
           if (sc->sc_dying)
                   return (USBD_IOERROR);
   
         DPRINTFN(3,("uhci_device_intr_transfer: xfer=%p len=%d flags=%d\n",          DPRINTFN(3,("uhci_device_intr_transfer: xfer=%p len=%d flags=%d\n",
                     xfer, xfer->length, xfer->flags));                      xfer, xfer->length, xfer->flags));
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (xfer->rqflags & URQ_REQUEST)          if (xfer->rqflags & URQ_REQUEST)
                panic("uhci_device_intr_transfer: a request\n");                panic("uhci_device_intr_transfer: a request");
 #endif  #endif
   
        err = uhci_alloc_std_chain(upipe, sc, xfer->length, 1, xfer->flags,        endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
                                   &xfer->dmabuf, &data, &dataend);        isread = UE_GET_DIR(endpt) == UE_DIR_IN;
         sqh = upipe->u.bulk.sqh;
 
         upipe->u.intr.isread = isread;
 
         err = uhci_alloc_std_chain(upipe, sc, xfer->length, isread,
                                    xfer->flags, &xfer->dmabuf, &data,
                                    &dataend);
         if (err)          if (err)
                 return (err);                  return (err);
        dataend->td.td_status |= LE(UHCI_TD_IOC);        dataend->td.td_status |= htole32(UHCI_TD_IOC);
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         if (uhcidebug > 10) {          if (uhcidebug > 10) {
Line 1746  uhci_device_intr_start(usbd_xfer_handle Line 2100  uhci_device_intr_start(usbd_xfer_handle
         ii->xfer = xfer;          ii->xfer = xfer;
         ii->stdstart = data;          ii->stdstart = data;
         ii->stdend = dataend;          ii->stdend = dataend;
 #if defined(__FreeBSD__)  
         callout_handle_init(&ii->timeout_handle);  
 #endif  
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!ii->isdone) {          if (!ii->isdone) {
                 printf("uhci_device_intr_transfer: not done, ii=%p\n", ii);                  printf("uhci_device_intr_transfer: not done, ii=%p\n", ii);
Line 1756  uhci_device_intr_start(usbd_xfer_handle Line 2107  uhci_device_intr_start(usbd_xfer_handle
         ii->isdone = 0;          ii->isdone = 0;
 #endif  #endif
   
        DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n",         DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n",
                      upipe->u.intr.qhs[0]));                       upipe->u.intr.qhs[0]));
         for (i = 0; i < upipe->u.intr.npoll; i++) {          for (i = 0; i < upipe->u.intr.npoll; i++) {
                 sqh = upipe->u.intr.qhs[i];                  sqh = upipe->u.intr.qhs[i];
                 sqh->elink = data;                  sqh->elink = data;
                sqh->qh.qh_elink = LE(data->physaddr);                sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
         }          }
           uhci_add_intr_info(sc, ii);
           xfer->status = USBD_IN_PROGRESS;
         splx(s);          splx(s);
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
Line 1788  uhci_device_ctrl_abort(usbd_xfer_handle Line 2141  uhci_device_ctrl_abort(usbd_xfer_handle
 void  void
 uhci_device_ctrl_close(usbd_pipe_handle pipe)  uhci_device_ctrl_close(usbd_pipe_handle pipe)
 {  {
         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;  
   
         uhci_free_intr_info(upipe->iinfo);  
         /* XXX free other resources? */  
 }  }
   
 /* Abort a device interrupt request. */  /* Abort a device interrupt request. */
Line 1801  uhci_device_intr_abort(usbd_xfer_handle Line 2150  uhci_device_intr_abort(usbd_xfer_handle
         DPRINTFN(1,("uhci_device_intr_abort: xfer=%p\n", xfer));          DPRINTFN(1,("uhci_device_intr_abort: xfer=%p\n", xfer));
         if (xfer->pipe->intrxfer == xfer) {          if (xfer->pipe->intrxfer == xfer) {
                 DPRINTFN(1,("uhci_device_intr_abort: remove\n"));                  DPRINTFN(1,("uhci_device_intr_abort: remove\n"));
                xfer->pipe->intrxfer = 0;                xfer->pipe->intrxfer = NULL;
         }          }
         uhci_abort_xfer(xfer, USBD_CANCELLED);          uhci_abort_xfer(xfer, USBD_CANCELLED);
 }  }
Line 1812  uhci_device_intr_close(usbd_pipe_handle Line 2161  uhci_device_intr_close(usbd_pipe_handle
 {  {
         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
         uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;          uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
        int i, s, npoll;        int i, npoll;
        int s;
        upipe->iinfo->stdstart = 0;             /* inactive */ 
   
         /* Unlink descriptors from controller data structures. */          /* Unlink descriptors from controller data structures. */
         npoll = upipe->u.intr.npoll;          npoll = upipe->u.intr.npoll;
        uhci_lock_frames(sc);        s = splusb();
         for (i = 0; i < npoll; i++)          for (i = 0; i < npoll; i++)
                uhci_remove_intr(sc, upipe->u.intr.qhs[i]->pos,                 uhci_remove_intr(sc, upipe->u.intr.qhs[i]);
                                 upipe->u.intr.qhs[i]);        splx(s);
        uhci_unlock_frames(sc); 
   
        /*         /*
          * We now have to wait for any activity on the physical           * We now have to wait for any activity on the physical
          * descriptors to stop.           * descriptors to stop.
          */           */
Line 1834  uhci_device_intr_close(usbd_pipe_handle Line 2181  uhci_device_intr_close(usbd_pipe_handle
                 uhci_free_sqh(sc, upipe->u.intr.qhs[i]);                  uhci_free_sqh(sc, upipe->u.intr.qhs[i]);
         free(upipe->u.intr.qhs, M_USBHC);          free(upipe->u.intr.qhs, M_USBHC);
   
         s = splusb();  
         LIST_REMOVE(upipe->iinfo, list);        /* remove from active list */  
         splx(s);  
         uhci_free_intr_info(upipe->iinfo);  
   
         /* XXX free other resources */          /* XXX free other resources */
 }  }
   
Line 1851  uhci_device_request(usbd_xfer_handle xfe Line 2193  uhci_device_request(usbd_xfer_handle xfe
         uhci_softc_t *sc = (uhci_softc_t *)dev->bus;          uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
         int addr = dev->address;          int addr = dev->address;
         int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;          int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
        uhci_intr_info_t *ii = upipe->iinfo;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         uhci_soft_td_t *setup, *data, *stat, *next, *dataend;          uhci_soft_td_t *setup, *data, *stat, *next, *dataend;
         uhci_soft_qh_t *sqh;          uhci_soft_qh_t *sqh;
         int len;          int len;
Line 1866  uhci_device_request(usbd_xfer_handle xfe Line 2208  uhci_device_request(usbd_xfer_handle xfe
                     UGETW(req->wIndex), UGETW(req->wLength),                      UGETW(req->wIndex), UGETW(req->wLength),
                     addr, endpt));                      addr, endpt));
   
        ls = dev->lowspeed ? UHCI_TD_LS : 0;        ls = dev->speed == USB_SPEED_LOW ? UHCI_TD_LS : 0;
         isread = req->bmRequestType & UT_READ;          isread = req->bmRequestType & UT_READ;
         len = UGETW(req->wLength);          len = UGETW(req->wLength);
   
Line 1883  uhci_device_request(usbd_xfer_handle xfe Line 2225  uhci_device_request(usbd_xfer_handle xfe
                         return (err);                          return (err);
                 next = data;                  next = data;
                 dataend->link.std = stat;                  dataend->link.std = stat;
                dataend->td.td_link = LE(stat->physaddr | UHCI_PTR_VF);                dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
         } else {          } else {
                 next = stat;                  next = stat;
         }          }
Line 1892  uhci_device_request(usbd_xfer_handle xfe Line 2234  uhci_device_request(usbd_xfer_handle xfe
         memcpy(KERNADDR(&upipe->u.ctl.reqdma, 0), req, sizeof *req);          memcpy(KERNADDR(&upipe->u.ctl.reqdma, 0), req, sizeof *req);
   
         setup->link.std = next;          setup->link.std = next;
        setup->td.td_link = LE(next->physaddr | UHCI_PTR_VF);        setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
        setup->td.td_status = LE(UHCI_TD_SET_ERRCNT(3) | ls | UHCI_TD_ACTIVE);        setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
        setup->td.td_xtoken = LE(UHCI_TD_SETUP(sizeof *req, endpt, addr));                UHCI_TD_ACTIVE);
        setup->td.td_buffer = LE(DMAADDR(&upipe->u.ctl.reqdma, 0));        setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof *req, endpt, addr));
        setup->td.td_buffer = htole32(DMAADDR(&upipe->u.ctl.reqdma, 0));
        stat->link.std = 0;        stat->link.std = NULL;
        stat->td.td_link = LE(UHCI_PTR_T);        stat->td.td_link = htole32(UHCI_PTR_T);
        stat->td.td_status = LE(UHCI_TD_SET_ERRCNT(3) | ls |         stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
                 UHCI_TD_ACTIVE | UHCI_TD_IOC);                  UHCI_TD_ACTIVE | UHCI_TD_IOC);
        stat->td.td_xtoken = 
                LE(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :        stat->td.td_token =
                            UHCI_TD_IN (0, endpt, addr, 1));                htole32(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
        stat->td.td_buffer = LE(0);                                 UHCI_TD_IN (0, endpt, addr, 1));
         stat->td.td_buffer = htole32(0);
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         if (uhcidebug > 10) {          if (uhcidebug > 10) {
Line 1917  uhci_device_request(usbd_xfer_handle xfe Line 2260  uhci_device_request(usbd_xfer_handle xfe
         ii->xfer = xfer;          ii->xfer = xfer;
         ii->stdstart = setup;          ii->stdstart = setup;
         ii->stdend = stat;          ii->stdend = stat;
 #if defined(__FreeBSD__)  
         callout_handle_init(&ii->timeout_handle);  
 #endif  
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!ii->isdone) {          if (!ii->isdone) {
                 printf("uhci_device_request: not done, ii=%p\n", ii);                  printf("uhci_device_request: not done, ii=%p\n", ii);
Line 1928  uhci_device_request(usbd_xfer_handle xfe Line 2268  uhci_device_request(usbd_xfer_handle xfe
 #endif  #endif
   
         sqh->elink = setup;          sqh->elink = setup;
        sqh->qh.qh_elink = LE(setup->physaddr);        sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
        sqh->intr_info = ii; 
   
         s = splusb();          s = splusb();
        uhci_add_ctrl(sc, sqh);        if (dev->speed == USB_SPEED_LOW)
        LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);                uhci_add_ls_ctrl(sc, sqh);
         else
                 uhci_add_hs_ctrl(sc, sqh);
         uhci_add_intr_info(sc, ii);
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
         if (uhcidebug > 12) {          if (uhcidebug > 12) {
                 uhci_soft_td_t *std;                  uhci_soft_td_t *std;
Line 1943  uhci_device_request(usbd_xfer_handle xfe Line 2285  uhci_device_request(usbd_xfer_handle xfe
                 uhci_physaddr_t link;                  uhci_physaddr_t link;
                 DPRINTF(("uhci_enter_ctl_q: follow from [0]\n"));                  DPRINTF(("uhci_enter_ctl_q: follow from [0]\n"));
                 for (std = sc->sc_vframes[0].htd, link = 0;                  for (std = sc->sc_vframes[0].htd, link = 0;
                     (link & UHCI_PTR_Q) == 0;                     (link & UHCI_PTR_QH) == 0;
                      std = std->link.std) {                       std = std->link.std) {
                        link = LE(std->td.td_link);                        link = le32toh(std->td.td_link);
                         uhci_dump_td(std);                          uhci_dump_td(std);
                 }                  }
                 sxqh = (uhci_soft_qh_t *)std;                  sxqh = (uhci_soft_qh_t *)std;
                 uhci_dump_qh(sxqh);                  uhci_dump_qh(sxqh);
                 for (xqh = sxqh;                  for (xqh = sxqh;
                      xqh != NULL;                       xqh != NULL;
                     xqh = (maxqh++ == 5 || xqh->hlink==sxqh ||                      xqh = (maxqh++ == 5 || xqh->hlink == sxqh ||
                            xqh->hlink==xqh ? NULL : xqh->hlink)) {                            xqh->hlink == xqh ? NULL : xqh->hlink)) {
                         uhci_dump_qh(xqh);                          uhci_dump_qh(xqh);
                 }                  }
                 DPRINTF(("Enqueued QH:\n"));                  DPRINTF(("Enqueued QH:\n"));
Line 1962  uhci_device_request(usbd_xfer_handle xfe Line 2304  uhci_device_request(usbd_xfer_handle xfe
         }          }
 #endif  #endif
         if (xfer->timeout && !sc->sc_bus.use_polling) {          if (xfer->timeout && !sc->sc_bus.use_polling) {
                usb_timeout(uhci_timeout, ii,                usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
                            MS_TO_TICKS(xfer->timeout), ii->timeout_handle);                            uhci_timeout, ii);
         }          }
           xfer->status = USBD_IN_PROGRESS;
         splx(s);          splx(s);
   
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
Line 1989  uhci_device_isoc_transfer(usbd_xfer_hand Line 2332  uhci_device_isoc_transfer(usbd_xfer_hand
         /* insert into schedule, */          /* insert into schedule, */
         uhci_device_isoc_enter(xfer);          uhci_device_isoc_enter(xfer);
   
        /* and put on interrupt list if the pipe wasn't running */        /* and start if the pipe wasn't running */
         if (!err)          if (!err)
                 uhci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue));                  uhci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
   
Line 2003  uhci_device_isoc_enter(usbd_xfer_handle Line 2346  uhci_device_isoc_enter(usbd_xfer_handle
         usbd_device_handle dev = upipe->pipe.device;          usbd_device_handle dev = upipe->pipe.device;
         uhci_softc_t *sc = (uhci_softc_t *)dev->bus;          uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
         struct iso *iso = &upipe->u.iso;          struct iso *iso = &upipe->u.iso;
        uhci_soft_td_t *std;            uhci_soft_td_t *std;
         u_int32_t buf, len, status;          u_int32_t buf, len, status;
         int s, i, next, nframes;          int s, i, next, nframes;
   
Line 2011  uhci_device_isoc_enter(usbd_xfer_handle Line 2354  uhci_device_isoc_enter(usbd_xfer_handle
                     "nframes=%d\n",                      "nframes=%d\n",
                     iso->inuse, iso->next, xfer, xfer->nframes));                      iso->inuse, iso->next, xfer, xfer->nframes));
   
           if (sc->sc_dying)
                   return;
   
         if (xfer->status == USBD_IN_PROGRESS) {          if (xfer->status == USBD_IN_PROGRESS) {
                 /* This request has already been entered into the frame list */                  /* This request has already been entered into the frame list */
                   printf("uhci_device_isoc_enter: xfer=%p in frame list\n", xfer);
                 /* XXX */                  /* XXX */
         }          }
   
Line 2029  uhci_device_isoc_enter(usbd_xfer_handle Line 2376  uhci_device_isoc_enter(usbd_xfer_handle
         }          }
   
         xfer->status = USBD_IN_PROGRESS;          xfer->status = USBD_IN_PROGRESS;
        xfer->hcprivint = next;        UXFER(xfer)->curframe = next;
   
         buf = DMAADDR(&xfer->dmabuf, 0);          buf = DMAADDR(&xfer->dmabuf, 0);
        status = LE(UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |        status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
                                        UHCI_TD_ACTIVE |                                     UHCI_TD_ACTIVE |
                                        UHCI_TD_IOS));                                     UHCI_TD_IOS);
         nframes = xfer->nframes;          nframes = xfer->nframes;
         s = splusb();          s = splusb();
         for (i = 0; i < nframes; i++) {          for (i = 0; i < nframes; i++) {
Line 2042  uhci_device_isoc_enter(usbd_xfer_handle Line 2389  uhci_device_isoc_enter(usbd_xfer_handle
                 if (++next >= UHCI_VFRAMELIST_COUNT)                  if (++next >= UHCI_VFRAMELIST_COUNT)
                         next = 0;                          next = 0;
                 len = xfer->frlengths[i];                  len = xfer->frlengths[i];
                std->td.td_buffer = LE(buf);                std->td.td_buffer = htole32(buf);
                 if (i == nframes - 1)                  if (i == nframes - 1)
                        status |= LE(UHCI_TD_IOC);                        status |= UHCI_TD_IOC;
                std->td.td_status = status;                std->td.td_status = htole32(status);
                std->td.td_xtoken &= LE(~UHCI_TD_MAXLEN_MASK);                std->td.td_token &= htole32(~UHCI_TD_MAXLEN_MASK);
                std->td.td_xtoken |= LE(UHCI_TD_SET_MAXLEN(len));                std->td.td_token |= htole32(UHCI_TD_SET_MAXLEN(len));
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
                 if (uhcidebug > 5) {                  if (uhcidebug > 5) {
                         DPRINTFN(5,("uhci_device_isoc_enter: TD %d\n", i));                          DPRINTFN(5,("uhci_device_isoc_enter: TD %d\n", i));
Line 2067  uhci_device_isoc_start(usbd_xfer_handle Line 2414  uhci_device_isoc_start(usbd_xfer_handle
 {  {
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
         uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;          uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
        uhci_intr_info_t *ii = upipe->iinfo;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         uhci_soft_td_t *end;          uhci_soft_td_t *end;
         int s, i;          int s, i;
   
           DPRINTFN(5,("uhci_device_isoc_start: xfer=%p\n", xfer));
   
           if (sc->sc_dying)
                   return (USBD_IOERROR);
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (xfer->status != USBD_IN_PROGRESS)          if (xfer->status != USBD_IN_PROGRESS)
                 printf("uhci_device_isoc_start: not in progress %p\n", xfer);                  printf("uhci_device_isoc_start: not in progress %p\n", xfer);
 #endif  #endif
   
         /* Find the last TD */          /* Find the last TD */
        i = xfer->hcprivint + xfer->nframes;        i = UXFER(xfer)->curframe + xfer->nframes;
         if (i >= UHCI_VFRAMELIST_COUNT)          if (i >= UHCI_VFRAMELIST_COUNT)
                 i -= UHCI_VFRAMELIST_COUNT;                  i -= UHCI_VFRAMELIST_COUNT;
         end = upipe->u.iso.stds[i];          end = upipe->u.iso.stds[i];
   
   #ifdef DIAGNOSTIC
           if (end == NULL) {
                   printf("uhci_device_isoc_start: end == NULL\n");
                   return (USBD_INVAL);
           }
   #endif
   
         s = splusb();          s = splusb();
        
         /* Set up interrupt info. */          /* Set up interrupt info. */
         ii->xfer = xfer;          ii->xfer = xfer;
         ii->stdstart = end;          ii->stdstart = end;
         ii->stdend = end;          ii->stdend = end;
 #if defined(__FreeBSD__)  
         callout_handle_init(&ii->timeout_handle);  
 #endif  
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
        if (!ii->isdone) {        if (!ii->isdone)
                 printf("uhci_device_isoc_start: not done, ii=%p\n", ii);                  printf("uhci_device_isoc_start: not done, ii=%p\n", ii);
         }  
         ii->isdone = 0;          ii->isdone = 0;
 #endif  #endif
        LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);        uhci_add_intr_info(sc, ii);
        
         splx(s);          splx(s);
   
         return (USBD_IN_PROGRESS);          return (USBD_IN_PROGRESS);
Line 2108  void Line 2463  void
 uhci_device_isoc_abort(usbd_xfer_handle xfer)  uhci_device_isoc_abort(usbd_xfer_handle xfer)
 {  {
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
         uhci_intr_info_t *ii = upipe->iinfo;  
         uhci_soft_td_t **stds = upipe->u.iso.stds;          uhci_soft_td_t **stds = upipe->u.iso.stds;
         uhci_soft_td_t *std;          uhci_soft_td_t *std;
        int i, n, nframes;        int i, n, s, nframes, maxlen, len;
 
         s = splusb();
 
         /* Transfer is already done. */
         if (xfer->status != USBD_NOT_STARTED &&
             xfer->status != USBD_IN_PROGRESS) {
                 splx(s);
                 return;
         }
   
        /* Make interrupt routine ignore it, */        /* Give xfer the requested abort code. */
         xfer->status = USBD_CANCELLED;          xfer->status = USBD_CANCELLED;
   
         /* make hardware ignore it, */          /* make hardware ignore it, */
         nframes = xfer->nframes;          nframes = xfer->nframes;
        n = xfer->hcprivint;        n = UXFER(xfer)->curframe;
         maxlen = 0;
         for (i = 0; i < nframes; i++) {          for (i = 0; i < nframes; i++) {
                 std = stds[n];                  std = stds[n];
                std->td.td_status &= LE(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));                std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
                 len = UHCI_TD_GET_MAXLEN(le32toh(std->td.td_token));
                 if (len > maxlen)
                         maxlen = len;
                 if (++n >= UHCI_VFRAMELIST_COUNT)                  if (++n >= UHCI_VFRAMELIST_COUNT)
                         n = 0;                          n = 0;
         }          }
   
        xfer->hcpriv = ii;        /* and wait until we are sure the hardware has finished. */
         delay(maxlen);
   
        /* make sure hardware has completed, */#ifdef DIAGNOSTIC
        if (xfer->device->bus->intr_context) {        UXFER(xfer)->iinfo.isdone = 1;
                /* We have no process context, so we can't use tsleep(). */#endif
                timeout(uhci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND);        /* Run callback and remove from interrupt list. */
        } else {        usb_transfer_complete(xfer);
                usb_delay_ms(xfer->pipe->device->bus, 1);
                /* and call final part of interrupt handler. */        splx(s);
                uhci_abort_xfer_end(xfer); 
        } 
 }  }
   
 void  void
Line 2147  uhci_device_isoc_close(usbd_pipe_handle Line 2513  uhci_device_isoc_close(usbd_pipe_handle
         uhci_softc_t *sc = (uhci_softc_t *)dev->bus;          uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
         uhci_soft_td_t *std, *vstd;          uhci_soft_td_t *std, *vstd;
         struct iso *iso;          struct iso *iso;
        int i;        int i, s;
   
         /*          /*
          * Make sure all TDs are marked as inactive.           * Make sure all TDs are marked as inactive.
Line 2158  uhci_device_isoc_close(usbd_pipe_handle Line 2524  uhci_device_isoc_close(usbd_pipe_handle
         iso = &upipe->u.iso;          iso = &upipe->u.iso;
   
         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++)          for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++)
                iso->stds[i]->td.td_status &= LE(~UHCI_TD_ACTIVE);                iso->stds[i]->td.td_status &= htole32(~UHCI_TD_ACTIVE);
         usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */          usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */
   
        uhci_lock_frames(sc);        s = splusb();
         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {          for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
                 std = iso->stds[i];                  std = iso->stds[i];
                 for (vstd = sc->sc_vframes[i].htd;                  for (vstd = sc->sc_vframes[i].htd;
Line 2171  uhci_device_isoc_close(usbd_pipe_handle Line 2537  uhci_device_isoc_close(usbd_pipe_handle
                 if (vstd == NULL) {                  if (vstd == NULL) {
                         /*panic*/                          /*panic*/
                         printf("uhci_device_isoc_close: %p not found\n", std);                          printf("uhci_device_isoc_close: %p not found\n", std);
                        uhci_unlock_frames(sc);                        splx(s);
                         return;                          return;
                 }                  }
                 vstd->link = std->link;                  vstd->link = std->link;
                 vstd->td.td_link = std->td.td_link;                  vstd->td.td_link = std->td.td_link;
                 uhci_free_std(sc, std);                  uhci_free_std(sc, std);
         }          }
        uhci_unlock_frames(sc);        splx(s);
   
         free(iso->stds, M_USBHC);          free(iso->stds, M_USBHC);
 }  }
Line 2195  uhci_setup_isoc(usbd_pipe_handle pipe) Line 2561  uhci_setup_isoc(usbd_pipe_handle pipe)
         uhci_soft_td_t *std, *vstd;          uhci_soft_td_t *std, *vstd;
         u_int32_t token;          u_int32_t token;
         struct iso *iso;          struct iso *iso;
        int i;        int i, s;
   
         iso = &upipe->u.iso;          iso = &upipe->u.iso;
         iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *),          iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *),
                            M_USBHC, M_WAITOK);                             M_USBHC, M_WAITOK);
   
        token = LE(rd ? UHCI_TD_IN (0, endpt, addr, 0) :        token = rd ? UHCI_TD_IN (0, endpt, addr, 0) :
                        UHCI_TD_OUT(0, endpt, addr, 0));                     UHCI_TD_OUT(0, endpt, addr, 0);
   
         /* Allocate the TDs and mark as inactive; */          /* Allocate the TDs and mark as inactive; */
         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {          for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
                 std = uhci_alloc_std(sc);                  std = uhci_alloc_std(sc);
                 if (std == 0)                  if (std == 0)
                         goto bad;                          goto bad;
                std->td.td_status = LE(UHCI_TD_IOS);  /* iso, inactive */                std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
                std->td.td_xtoken = token;                std->td.td_token = htole32(token);
                 iso->stds[i] = std;                  iso->stds[i] = std;
         }          }
   
         /* Insert TDs into schedule. */          /* Insert TDs into schedule. */
        uhci_lock_frames(sc);        s = splusb();
         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {          for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
                 std = iso->stds[i];                  std = iso->stds[i];
                 vstd = sc->sc_vframes[i].htd;                  vstd = sc->sc_vframes[i].htd;
                 std->link = vstd->link;                  std->link = vstd->link;
                 std->td.td_link = vstd->td.td_link;                  std->td.td_link = vstd->td.td_link;
                 vstd->link.std = std;                  vstd->link.std = std;
                vstd->td.td_link = LE(std->physaddr);                vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD);
         }          }
        uhci_unlock_frames(sc);        splx(s);
   
         iso->next = -1;          iso->next = -1;
         iso->inuse = 0;          iso->inuse = 0;
Line 2241  uhci_setup_isoc(usbd_pipe_handle pipe) Line 2607  uhci_setup_isoc(usbd_pipe_handle pipe)
 void  void
 uhci_device_isoc_done(usbd_xfer_handle xfer)  uhci_device_isoc_done(usbd_xfer_handle xfer)
 {  {
        uhci_intr_info_t *ii = xfer->hcpriv;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
   
         DPRINTFN(4, ("uhci_isoc_done: length=%d\n", xfer->actlen));          DPRINTFN(4, ("uhci_isoc_done: length=%d\n", xfer->actlen));
   
           if (ii->xfer != xfer)
                   /* Not on interrupt list, ignore it. */
                   return;
   
           if (!uhci_active_intr_info(ii))
                   return;
   
   #ifdef DIAGNOSTIC
           if (xfer->busy_free != XFER_BUSY) {
                   printf("uhci_device_isoc_done: xfer=%p not busy 0x%08x\n",
                          xfer, xfer->busy_free);
                   return;
           }
   
           if (ii->stdend == NULL) {
                   printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer);
   #ifdef USB_DEBUG
                   uhci_dump_ii(ii);
   #endif
                   return;
           }
   #endif
   
         /* Turn off the interrupt since it is active even if the TD is not. */          /* Turn off the interrupt since it is active even if the TD is not. */
        ii->stdend->td.td_status &= LE(~UHCI_TD_IOC);        ii->stdend->td.td_status &= htole32(~UHCI_TD_IOC);
 
         uhci_del_intr_info(ii); /* remove from active list */
   
        LIST_REMOVE(ii, list);  /* remove from active list */#ifdef DIAGNOSTIC
         if (ii->stdend == NULL) {
                 printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer);
 #ifdef USB_DEBUG
                 uhci_dump_ii(ii);
 #endif
                 return;
         }
 #endif
 }  }
   
 void  void
 uhci_device_intr_done(usbd_xfer_handle xfer)  uhci_device_intr_done(usbd_xfer_handle xfer)
 {  {
        uhci_intr_info_t *ii = xfer->hcpriv;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         uhci_softc_t *sc = ii->sc;          uhci_softc_t *sc = ii->sc;
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
         uhci_soft_qh_t *sqh;          uhci_soft_qh_t *sqh;
         int i, npoll;          int i, npoll;
   
        DPRINTFN(5, ("uhci_intr_done: length=%d\n", xfer->actlen));        DPRINTFN(5, ("uhci_device_intr_done: length=%d\n", xfer->actlen));
   
         npoll = upipe->u.intr.npoll;          npoll = upipe->u.intr.npoll;
         for(i = 0; i < npoll; i++) {          for(i = 0; i < npoll; i++) {
                 sqh = upipe->u.intr.qhs[i];                  sqh = upipe->u.intr.qhs[i];
                sqh->elink = 0;                sqh->elink = NULL;
                sqh->qh.qh_elink = LE(UHCI_PTR_T);                sqh->qh.qh_elink = htole32(UHCI_PTR_T);
         }          }
        uhci_free_std_chain(sc, ii->stdstart, 0);        uhci_free_std_chain(sc, ii->stdstart, NULL);
   
         /* XXX Wasteful. */          /* XXX Wasteful. */
         if (xfer->pipe->repeat) {          if (xfer->pipe->repeat) {
                 uhci_soft_td_t *data, *dataend;                  uhci_soft_td_t *data, *dataend;
   
                   DPRINTFN(5,("uhci_device_intr_done: requeing\n"));
   
                 /* This alloc cannot fail since we freed the chain above. */                  /* This alloc cannot fail since we freed the chain above. */
                uhci_alloc_std_chain(upipe, sc, xfer->length, 1, xfer->flags,                uhci_alloc_std_chain(upipe, sc, xfer->length,
                                      upipe->u.intr.isread, xfer->flags,
                                      &xfer->dmabuf, &data, &dataend);                                       &xfer->dmabuf, &data, &dataend);
                dataend->td.td_status |= LE(UHCI_TD_IOC);                dataend->td.td_status |= htole32(UHCI_TD_IOC);
   
 #ifdef USB_DEBUG  #ifdef USB_DEBUG
                 if (uhcidebug > 10) {                  if (uhcidebug > 10) {
Line 2289  uhci_device_intr_done(usbd_xfer_handle x Line 2691  uhci_device_intr_done(usbd_xfer_handle x
   
                 ii->stdstart = data;                  ii->stdstart = data;
                 ii->stdend = dataend;                  ii->stdend = dataend;
 #if defined(__FreeBSD__)  
                 callout_handle_init(&ii->timeout_handle);  
 #endif  
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 if (!ii->isdone) {                  if (!ii->isdone) {
                         printf("uhci_device_intr_done: not done, ii=%p\n", ii);                          printf("uhci_device_intr_done: not done, ii=%p\n", ii);
Line 2301  uhci_device_intr_done(usbd_xfer_handle x Line 2700  uhci_device_intr_done(usbd_xfer_handle x
                 for (i = 0; i < npoll; i++) {                  for (i = 0; i < npoll; i++) {
                         sqh = upipe->u.intr.qhs[i];                          sqh = upipe->u.intr.qhs[i];
                         sqh->elink = data;                          sqh->elink = data;
                        sqh->qh.qh_elink = LE(data->physaddr);                        sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
                 }                  }
                   xfer->status = USBD_IN_PROGRESS;
                   /* The ii is already on the examined list, just leave it. */
         } else {          } else {
                ii->stdstart = 0;       /* mark as inactive */                DPRINTFN(5,("uhci_device_intr_done: removing\n"));
                 if (uhci_active_intr_info(ii))
                         uhci_del_intr_info(ii);
         }          }
 }  }
   
Line 2312  uhci_device_intr_done(usbd_xfer_handle x Line 2715  uhci_device_intr_done(usbd_xfer_handle x
 void  void
 uhci_device_ctrl_done(usbd_xfer_handle xfer)  uhci_device_ctrl_done(usbd_xfer_handle xfer)
 {  {
        uhci_intr_info_t *ii = xfer->hcpriv;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         uhci_softc_t *sc = ii->sc;          uhci_softc_t *sc = ii->sc;
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!(xfer->rqflags & URQ_REQUEST))          if (!(xfer->rqflags & URQ_REQUEST))
                panic("uhci_ctrl_done: not a request\n");                panic("uhci_device_ctrl_done: not a request");
 #endif  #endif
   
        LIST_REMOVE(ii, list);  /* remove from active list */        if (!uhci_active_intr_info(ii))
                 return;
   
        uhci_remove_ctrl(sc, upipe->u.ctl.sqh);        uhci_del_intr_info(ii); /* remove from active list */
 
         if (upipe->pipe.device->speed == USB_SPEED_LOW)
                 uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh);
         else
                 uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh);
   
         if (upipe->u.ctl.length != 0)          if (upipe->u.ctl.length != 0)
                 uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend);                  uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend);
   
        DPRINTFN(5, ("uhci_ctrl_done: length=%d\n", xfer->actlen));        DPRINTFN(5, ("uhci_device_ctrl_done: length=%d\n", xfer->actlen));
 }  }
   
 /* Deallocate request data structures */  /* Deallocate request data structures */
 void  void
 uhci_device_bulk_done(usbd_xfer_handle xfer)  uhci_device_bulk_done(usbd_xfer_handle xfer)
 {  {
        uhci_intr_info_t *ii = xfer->hcpriv;        uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
         uhci_softc_t *sc = ii->sc;          uhci_softc_t *sc = ii->sc;
         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;          struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
   
        LIST_REMOVE(ii, list);      /* remove from active list */        DPRINTFN(5,("uhci_device_bulk_done: xfer=%p ii=%p sc=%p upipe=%p\n",
                     xfer, ii, sc, upipe));
 
         if (!uhci_active_intr_info(ii))
                 return;
 
         uhci_del_intr_info(ii);      /* remove from active list */
   
         uhci_remove_bulk(sc, upipe->u.bulk.sqh);          uhci_remove_bulk(sc, upipe->u.bulk.sqh);
   
        uhci_free_std_chain(sc, ii->stdstart, 0);        uhci_free_std_chain(sc, ii->stdstart, NULL);
   
        DPRINTFN(5, ("uhci_bulk_done: length=%d\n", xfer->actlen));        DPRINTFN(5, ("uhci_device_bulk_done: length=%d\n", xfer->actlen));
 }  }
   
 /* Add interrupt QH, called with vflock. */  /* Add interrupt QH, called with vflock. */
 void  void
uhci_add_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh)uhci_add_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
 {  {
        struct uhci_vframe *vf = &sc->sc_vframes[n];        struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
         uhci_soft_qh_t *eqh;          uhci_soft_qh_t *eqh;
   
        DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", n, sqh));        DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", sqh->pos, sqh));
 
         eqh = vf->eqh;          eqh = vf->eqh;
         sqh->hlink       = eqh->hlink;          sqh->hlink       = eqh->hlink;
         sqh->qh.qh_hlink = eqh->qh.qh_hlink;          sqh->qh.qh_hlink = eqh->qh.qh_hlink;
         eqh->hlink       = sqh;          eqh->hlink       = sqh;
        eqh->qh.qh_hlink = LE(sqh->physaddr | UHCI_PTR_Q);        eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
         vf->eqh = sqh;          vf->eqh = sqh;
         vf->bandwidth++;          vf->bandwidth++;
 }  }
   
/* Remove interrupt QH, called with vflock. *//* Remove interrupt QH. */
 void  void
uhci_remove_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh)uhci_remove_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
 {  {
        struct uhci_vframe *vf = &sc->sc_vframes[n];        struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
         uhci_soft_qh_t *pqh;          uhci_soft_qh_t *pqh;
   
        DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", n, sqh));        DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", sqh->pos, sqh));
   
        for (pqh = vf->hqh; pqh->hlink != sqh; pqh = pqh->hlink)        /* See comment in uhci_remove_ctrl() */
#if defined(DIAGNOSTIC) || defined(USB_DEBUG)                   if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
                if (LE(pqh->qh.qh_hlink) & UHCI_PTR_T) {                sqh->qh.qh_elink = htole32(UHCI_PTR_T);
                        DPRINTF(("uhci_remove_intr: QH not found\n"));                delay(UHCI_QH_REMOVE_DELAY);
                        return;        }
                }
#else        pqh = uhci_find_prev_qh(vf->hqh, sqh);
                ; 
#endif 
         pqh->hlink       = sqh->hlink;          pqh->hlink       = sqh->hlink;
         pqh->qh.qh_hlink = sqh->qh.qh_hlink;          pqh->qh.qh_hlink = sqh->qh.qh_hlink;
           delay(UHCI_QH_REMOVE_DELAY);
         if (vf->eqh == sqh)          if (vf->eqh == sqh)
                 vf->eqh = pqh;                  vf->eqh = pqh;
         vf->bandwidth--;          vf->bandwidth--;
Line 2397  uhci_device_setintr(uhci_softc_t *sc, st Line 2812  uhci_device_setintr(uhci_softc_t *sc, st
         int i, npoll, s;          int i, npoll, s;
         u_int bestbw, bw, bestoffs, offs;          u_int bestbw, bw, bestoffs, offs;
   
        DPRINTFN(2, ("uhci_setintr: pipe=%p\n", upipe));        DPRINTFN(2, ("uhci_device_setintr: pipe=%p\n", upipe));
         if (ival == 0) {          if (ival == 0) {
                 printf("uhci_setintr: 0 interval\n");                  printf("uhci_setintr: 0 interval\n");
                 return (USBD_INVAL);                  return (USBD_INVAL);
Line 2406  uhci_device_setintr(uhci_softc_t *sc, st Line 2821  uhci_device_setintr(uhci_softc_t *sc, st
         if (ival > UHCI_VFRAMELIST_COUNT)          if (ival > UHCI_VFRAMELIST_COUNT)
                 ival = UHCI_VFRAMELIST_COUNT;                  ival = UHCI_VFRAMELIST_COUNT;
         npoll = (UHCI_VFRAMELIST_COUNT + ival - 1) / ival;          npoll = (UHCI_VFRAMELIST_COUNT + ival - 1) / ival;
        DPRINTFN(2, ("uhci_setintr: ival=%d npoll=%d\n", ival, npoll));        DPRINTFN(2, ("uhci_device_setintr: ival=%d npoll=%d\n", ival, npoll));
   
         upipe->u.intr.npoll = npoll;          upipe->u.intr.npoll = npoll;
        upipe->u.intr.qhs =         upipe->u.intr.qhs =
                 malloc(npoll * sizeof(uhci_soft_qh_t *), M_USBHC, M_WAITOK);                  malloc(npoll * sizeof(uhci_soft_qh_t *), M_USBHC, M_WAITOK);
   
        /*         /*
          * Figure out which offset in the schedule that has most           * Figure out which offset in the schedule that has most
          * bandwidth left over.           * bandwidth left over.
          */           */
Line 2425  uhci_device_setintr(uhci_softc_t *sc, st Line 2840  uhci_device_setintr(uhci_softc_t *sc, st
                         bestoffs = offs;                          bestoffs = offs;
                 }                  }
         }          }
        DPRINTFN(1, ("uhci_setintr: bw=%d offs=%d\n", bestbw, bestoffs));        DPRINTFN(1, ("uhci_device_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
   
         upipe->iinfo->stdstart = 0;  
         for(i = 0; i < npoll; i++) {          for(i = 0; i < npoll; i++) {
                 upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);                  upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
                sqh->elink = 0;                sqh->elink = NULL;
                sqh->qh.qh_elink = LE(UHCI_PTR_T);                sqh->qh.qh_elink = htole32(UHCI_PTR_T);
                 sqh->pos = MOD(i * ival + bestoffs);                  sqh->pos = MOD(i * ival + bestoffs);
                 sqh->intr_info = upipe->iinfo;  
         }          }
 #undef MOD  #undef MOD
   
         s = splusb();          s = splusb();
         LIST_INSERT_HEAD(&sc->sc_intrhead, upipe->iinfo, list);  
         splx(s);  
   
         uhci_lock_frames(sc);  
         /* Enter QHs into the controller data structures. */          /* Enter QHs into the controller data structures. */
         for(i = 0; i < npoll; i++)          for(i = 0; i < npoll; i++)
                uhci_add_intr(sc, upipe->u.intr.qhs[i]->pos,                 uhci_add_intr(sc, upipe->u.intr.qhs[i]);
                              upipe->u.intr.qhs[i]);        splx(s);
        uhci_unlock_frames(sc); 
   
        DPRINTFN(5, ("uhci_setintr: returns %p\n", upipe));        DPRINTFN(5, ("uhci_device_setintr: returns %p\n", upipe));
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
 }  }
   
Line 2463  uhci_open(usbd_pipe_handle pipe) Line 2871  uhci_open(usbd_pipe_handle pipe)
         int ival;          int ival;
   
         DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",          DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
                     pipe, pipe->device->address,                      pipe, pipe->device->address,
                      ed->bEndpointAddress, sc->sc_addr));                       ed->bEndpointAddress, sc->sc_addr));
   
           upipe->aborting = 0;
           upipe->nexttoggle = 0;
   
         if (pipe->device->address == sc->sc_addr) {          if (pipe->device->address == sc->sc_addr) {
                 switch (ed->bEndpointAddress) {                  switch (ed->bEndpointAddress) {
                 case USB_CONTROL_ENDPOINT:                  case USB_CONTROL_ENDPOINT:
Line 2477  uhci_open(usbd_pipe_handle pipe) Line 2889  uhci_open(usbd_pipe_handle pipe)
                         return (USBD_INVAL);                          return (USBD_INVAL);
                 }                  }
         } else {          } else {
                 upipe->iinfo = uhci_alloc_intr_info(sc);  
                 if (upipe->iinfo == 0)  
                         return (USBD_NOMEM);  
                 switch (ed->bmAttributes & UE_XFERTYPE) {                  switch (ed->bmAttributes & UE_XFERTYPE) {
                 case UE_CONTROL:                  case UE_CONTROL:
                         pipe->methods = &uhci_device_ctrl_methods;                          pipe->methods = &uhci_device_ctrl_methods;
Line 2497  uhci_open(usbd_pipe_handle pipe) Line 2906  uhci_open(usbd_pipe_handle pipe)
                                 uhci_free_std(sc, upipe->u.ctl.setup);                                  uhci_free_std(sc, upipe->u.ctl.setup);
                                 goto bad;                                  goto bad;
                         }                          }
                        err = usb_allocmem(&sc->sc_bus,                         err = usb_allocmem(&sc->sc_bus,
                                  sizeof(usb_device_request_t),                                   sizeof(usb_device_request_t),
                                   0, &upipe->u.ctl.reqdma);                                    0, &upipe->u.ctl.reqdma);
                         if (err) {                          if (err) {
                                 uhci_free_sqh(sc, upipe->u.ctl.sqh);                                  uhci_free_sqh(sc, upipe->u.ctl.sqh);
Line 2527  uhci_open(usbd_pipe_handle pipe) Line 2936  uhci_open(usbd_pipe_handle pipe)
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
   
  bad:   bad:
         uhci_free_intr_info(upipe->iinfo);  
         return (USBD_NOMEM);          return (USBD_NOMEM);
 }  }
   
Line 2609  uhci_str(usb_string_descriptor_t *p, int Line 3017  uhci_str(usb_string_descriptor_t *p, int
 }  }
   
 /*  /*
    * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also
    * enables the port, and also states that SET_FEATURE(PORT_ENABLE)
    * should not be used by the USB subsystem.  As we cannot issue a
    * SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port
    * will be enabled as part of the reset.
    *
    * On the VT83C572, the port cannot be successfully enabled until the
    * outstanding "port enable change" and "connection status change"
    * events have been reset.
    */
   Static usbd_status
   uhci_portreset(uhci_softc_t *sc, int index)
   {
           int lim, port, x;
   
           if (index == 1)
                   port = UHCI_PORTSC1;
           else if (index == 2)
                   port = UHCI_PORTSC2;
           else
                   return (USBD_IOERROR);
   
           x = URWMASK(UREAD2(sc, port));
           UWRITE2(sc, port, x | UHCI_PORTSC_PR);
   
           usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
   
           DPRINTFN(3,("uhci port %d reset, status0 = 0x%04x\n",
                       index, UREAD2(sc, port)));
   
           x = URWMASK(UREAD2(sc, port));
           UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
   
           delay(100);
   
           DPRINTFN(3,("uhci port %d reset, status1 = 0x%04x\n",
                       index, UREAD2(sc, port)));
   
           x = URWMASK(UREAD2(sc, port));
           UWRITE2(sc, port, x  | UHCI_PORTSC_PE);
   
           for (lim = 10; --lim > 0;) {
                   usb_delay_ms(&sc->sc_bus, USB_PORT_RESET_DELAY);
   
                   x = UREAD2(sc, port);
   
                   DPRINTFN(3,("uhci port %d iteration %u, status = 0x%04x\n",
                               index, lim, x));
   
                   if (!(x & UHCI_PORTSC_CCS)) {
                           /*
                            * No device is connected (or was disconnected
                            * during reset).  Consider the port reset.
                            * The delay must be long enough to ensure on
                            * the initial iteration that the device
                            * connection will have been registered.  50ms
                            * appears to be sufficient, but 20ms is not.
                            */
                           DPRINTFN(3,("uhci port %d loop %u, device detached\n",
                                       index, lim));
                           break;
                   }
   
                   if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) {
                           /*
                            * Port enabled changed and/or connection
                            * status changed were set.  Reset either or
                            * both raised flags (by writing a 1 to that
                            * bit), and wait again for state to settle.
                            */
                           UWRITE2(sc, port, URWMASK(x) |
                                   (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)));
                           continue;
                   }
   
                   if (x & UHCI_PORTSC_PE)
                           /* Port is enabled */
                           break;
   
                   UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE);
           }
   
           DPRINTFN(3,("uhci port %d reset, status2 = 0x%04x\n",
                       index, UREAD2(sc, port)));
   
           if (lim <= 0) {
                   DPRINTFN(1,("uhci port %d reset timed out\n", index));
                   return (USBD_TIMEOUT);
           }
   
           sc->sc_isreset = 1;
           return (USBD_NORMAL_COMPLETION);
   }
   
   /*
  * Simulate a hardware hub by handling all the necessary requests.   * Simulate a hardware hub by handling all the necessary requests.
  */   */
 usbd_status  usbd_status
Line 2621  uhci_root_ctrl_transfer(usbd_xfer_handle Line 3124  uhci_root_ctrl_transfer(usbd_xfer_handle
         if (err)          if (err)
                 return (err);                  return (err);
   
        /* Pipe isn't running (otherwise err would be USBD_INPROG),        /*
         * start first         * Pipe isn't running (otherwise err would be USBD_INPROG),
          * so start it first.
          */           */
         return (uhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return (uhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
 }  }
Line 2638  uhci_root_ctrl_start(usbd_xfer_handle xf Line 3142  uhci_root_ctrl_start(usbd_xfer_handle xf
         usb_port_status_t ps;          usb_port_status_t ps;
         usbd_status err;          usbd_status err;
   
           if (sc->sc_dying)
                   return (USBD_IOERROR);
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!(xfer->rqflags & URQ_REQUEST))          if (!(xfer->rqflags & URQ_REQUEST))
                panic("uhci_root_ctrl_transfer: not a request\n");                panic("uhci_root_ctrl_transfer: not a request");
 #endif  #endif
         req = &xfer->request;          req = &xfer->request;
   
        DPRINTFN(2,("uhci_root_ctrl_control type=0x%02x request=%02x\n",         DPRINTFN(2,("uhci_root_ctrl_control type=0x%02x request=%02x\n",
                     req->bmRequestType, req->bRequest));                      req->bmRequestType, req->bRequest));
   
         len = UGETW(req->wLength);          len = UGETW(req->wLength);
Line 2659  uhci_root_ctrl_start(usbd_xfer_handle xf Line 3166  uhci_root_ctrl_start(usbd_xfer_handle xf
         case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):          case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
         case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):          case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
         case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):          case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
                /*                 /*
                  * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops                   * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
                  * for the integrated root hub.                   * for the integrated root hub.
                  */                   */
Line 2780  uhci_root_ctrl_start(usbd_xfer_handle xf Line 3287  uhci_root_ctrl_start(usbd_xfer_handle xf
                 }                  }
                 switch(value) {                  switch(value) {
                 case UHF_PORT_ENABLE:                  case UHF_PORT_ENABLE:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x & ~UHCI_PORTSC_PE);                          UWRITE2(sc, port, x & ~UHCI_PORTSC_PE);
                         break;                          break;
                 case UHF_PORT_SUSPEND:                  case UHF_PORT_SUSPEND:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP);                          UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP);
                         break;                          break;
                 case UHF_PORT_RESET:                  case UHF_PORT_RESET:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);                          UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
                         break;                          break;
                 case UHF_C_PORT_CONNECTION:                  case UHF_C_PORT_CONNECTION:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x | UHCI_PORTSC_CSC);                          UWRITE2(sc, port, x | UHCI_PORTSC_CSC);
                         break;                          break;
                 case UHF_C_PORT_ENABLE:                  case UHF_C_PORT_ENABLE:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x | UHCI_PORTSC_POEDC);                          UWRITE2(sc, port, x | UHCI_PORTSC_POEDC);
                         break;                          break;
                 case UHF_C_PORT_OVER_CURRENT:                  case UHF_C_PORT_OVER_CURRENT:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x | UHCI_PORTSC_OCIC);                          UWRITE2(sc, port, x | UHCI_PORTSC_OCIC);
                         break;                          break;
                 case UHF_C_PORT_RESET:                  case UHF_C_PORT_RESET:
Line 2827  uhci_root_ctrl_start(usbd_xfer_handle xf Line 3334  uhci_root_ctrl_start(usbd_xfer_handle xf
                         goto ret;                          goto ret;
                 }                  }
                 if (len > 0) {                  if (len > 0) {
                        *(u_int8_t *)buf =                         *(u_int8_t *)buf =
                                 (UREAD2(sc, port) & UHCI_PORTSC_LS) >>                                  (UREAD2(sc, port) & UHCI_PORTSC_LS) >>
                                 UHCI_PORTSC_LS_SHIFT;                                  UHCI_PORTSC_LS_SHIFT;
                         totlen = 1;                          totlen = 1;
Line 2865  uhci_root_ctrl_start(usbd_xfer_handle xf Line 3372  uhci_root_ctrl_start(usbd_xfer_handle xf
                 }                  }
                 x = UREAD2(sc, port);                  x = UREAD2(sc, port);
                 status = change = 0;                  status = change = 0;
                if (x & UHCI_PORTSC_CCS  )                if (x & UHCI_PORTSC_CCS)
                         status |= UPS_CURRENT_CONNECT_STATUS;                          status |= UPS_CURRENT_CONNECT_STATUS;
                if (x & UHCI_PORTSC_CSC                  if (x & UHCI_PORTSC_CSC)
                         change |= UPS_C_CONNECT_STATUS;                          change |= UPS_C_CONNECT_STATUS;
                if (x & UHCI_PORTSC_PE                   if (x & UHCI_PORTSC_PE)
                         status |= UPS_PORT_ENABLED;                          status |= UPS_PORT_ENABLED;
                if (x & UHCI_PORTSC_POEDC)                 if (x & UHCI_PORTSC_POEDC)
                         change |= UPS_C_PORT_ENABLED;                          change |= UPS_C_PORT_ENABLED;
                if (x & UHCI_PORTSC_OCI                  if (x & UHCI_PORTSC_OCI)
                         status |= UPS_OVERCURRENT_INDICATOR;                          status |= UPS_OVERCURRENT_INDICATOR;
                if (x & UHCI_PORTSC_OCIC                 if (x & UHCI_PORTSC_OCIC)
                         change |= UPS_C_OVERCURRENT_INDICATOR;                          change |= UPS_C_OVERCURRENT_INDICATOR;
                if (x & UHCI_PORTSC_SUSP                 if (x & UHCI_PORTSC_SUSP)
                         status |= UPS_SUSPEND;                          status |= UPS_SUSPEND;
                if (x & UHCI_PORTSC_LSDA                 if (x & UHCI_PORTSC_LSDA)
                         status |= UPS_LOW_SPEED;                          status |= UPS_LOW_SPEED;
                 status |= UPS_PORT_POWER;                  status |= UPS_PORT_POWER;
                 if (sc->sc_isreset)                  if (sc->sc_isreset)
Line 2906  uhci_root_ctrl_start(usbd_xfer_handle xf Line 3413  uhci_root_ctrl_start(usbd_xfer_handle xf
                 }                  }
                 switch(value) {                  switch(value) {
                 case UHF_PORT_ENABLE:                  case UHF_PORT_ENABLE:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x | UHCI_PORTSC_PE);                          UWRITE2(sc, port, x | UHCI_PORTSC_PE);
                         break;                          break;
                 case UHF_PORT_SUSPEND:                  case UHF_PORT_SUSPEND:
                        x = UREAD2(sc, port);                        x = URWMASK(UREAD2(sc, port));
                         UWRITE2(sc, port, x | UHCI_PORTSC_SUSP);                          UWRITE2(sc, port, x | UHCI_PORTSC_SUSP);
                         break;                          break;
                 case UHF_PORT_RESET:                  case UHF_PORT_RESET:
                        x = UREAD2(sc, port);                        err = uhci_portreset(sc, index);
                        UWRITE2(sc, port, x | UHCI_PORTSC_PR);                        goto ret;
                        usb_delay_ms(&sc->sc_bus, 10); 
                        UWRITE2(sc, port, x & ~UHCI_PORTSC_PR); 
                        delay(100); 
                        x = UREAD2(sc, port); 
                        UWRITE2(sc, port, x  | UHCI_PORTSC_PE); 
                        delay(100); 
                        DPRINTFN(3,("uhci port %d reset, status = 0x%04x\n", 
                                    index, UREAD2(sc, port))); 
                        sc->sc_isreset = 1; 
                        break; 
                 case UHF_PORT_POWER:                  case UHF_PORT_POWER:
                         /* Pretend we turned on power */                          /* Pretend we turned on power */
                         err = USBD_NORMAL_COMPLETION;                          err = USBD_NORMAL_COMPLETION;
Line 2951  uhci_root_ctrl_start(usbd_xfer_handle xf Line 3448  uhci_root_ctrl_start(usbd_xfer_handle xf
         err = USBD_NORMAL_COMPLETION;          err = USBD_NORMAL_COMPLETION;
  ret:   ret:
         xfer->status = err;          xfer->status = err;
         xfer->hcpriv = 0;  
         s = splusb();          s = splusb();
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         splx(s);          splx(s);
Line 2978  uhci_root_intr_abort(usbd_xfer_handle xf Line 3474  uhci_root_intr_abort(usbd_xfer_handle xf
 {  {
         uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;          uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
   
        usb_untimeout(uhci_timo, xfer, xfer->timo_handle);        usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, xfer);
        sc->sc_has_timo = NULL;        sc->sc_intr_xfer = NULL;
   
         if (xfer->pipe->intrxfer == xfer) {          if (xfer->pipe->intrxfer == xfer) {
                 DPRINTF(("uhci_root_intr_abort: remove\n"));                  DPRINTF(("uhci_root_intr_abort: remove\n"));
                 xfer->pipe->intrxfer = 0;                  xfer->pipe->intrxfer = 0;
         }          }
         xfer->status = USBD_CANCELLED;          xfer->status = USBD_CANCELLED;
   #ifdef DIAGNOSTIC
           UXFER(xfer)->iinfo.isdone = 1;
   #endif
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
 }  }
   
Line 2999  uhci_root_intr_transfer(usbd_xfer_handle Line 3498  uhci_root_intr_transfer(usbd_xfer_handle
         if (err)          if (err)
                 return (err);                  return (err);
   
        /* Pipe isn't running (otherwise err would be USBD_INPROG),        /*
         * start first         * Pipe isn't running (otherwise err would be USBD_INPROG),
          * so start it first.
          */           */
         return (uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));          return (uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
 }  }
Line 3012  uhci_root_intr_start(usbd_xfer_handle xf Line 3512  uhci_root_intr_start(usbd_xfer_handle xf
         usbd_pipe_handle pipe = xfer->pipe;          usbd_pipe_handle pipe = xfer->pipe;
         uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;          uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
   
        DPRINTFN(3, ("uhci_root_intr_transfer: xfer=%p len=%d flags=%d\n",        DPRINTFN(3, ("uhci_root_intr_start: xfer=%p len=%d flags=%d\n",
                      xfer, xfer->length, xfer->flags));                       xfer, xfer->length, xfer->flags));
   
           if (sc->sc_dying)
                   return (USBD_IOERROR);
   
         sc->sc_ival = MS_TO_TICKS(xfer->pipe->endpoint->edesc->bInterval);          sc->sc_ival = MS_TO_TICKS(xfer->pipe->endpoint->edesc->bInterval);
        usb_timeout(uhci_timo, xfer, sc->sc_ival, xfer->timo_handle);        usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer);
        sc->sc_has_timo = xfer;        sc->sc_intr_xfer = xfer;
         return (USBD_IN_PROGRESS);          return (USBD_IN_PROGRESS);
 }  }
   
Line 3027  uhci_root_intr_close(usbd_pipe_handle pi Line 3530  uhci_root_intr_close(usbd_pipe_handle pi
 {  {
         uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;          uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
   
        usb_untimeout(uhci_timo, pipe->intrxfer, pipe->intrxfer->timo_handle);        usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, sc->sc_intr_xfer);
        sc->sc_has_timo = NULL;        sc->sc_intr_xfer = NULL;
         DPRINTF(("uhci_root_intr_close\n"));          DPRINTF(("uhci_root_intr_close\n"));
 }  }

Removed from v.1.7  
changed lines
  Added in v.1.8