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

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

Diff for /src/sys/dev/usb/ehci.c between version 1.47.2.9 and 1.48

version 1.47.2.9, 2005/12/11 10:29:05 version 1.48, 2003/10/12 18:04:28
Line 1 
Line 1 
 /*      $NetBSD$ */  /*      $NetBSD$        */
   
 /*  /*
  * Copyright (c) 2004,2005 The NetBSD Foundation, Inc.   * TODO
    *  hold off explorations by companion controllers until ehci has started.
    */
   
   /*
    * Copyright (c) 2001 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
  *   *
  * This code is derived from software contributed to The NetBSD Foundation   * This code is derived from software contributed to The NetBSD Foundation
  * by Lennart Augustsson (lennart@augustsson.net) and by Charles M. Hannum.   * by Lennart Augustsson (lennart@augustsson.net).
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 46 
Line 51 
  *   *
  */   */
   
 /*  
  * TODO:  
  * 1) hold off explorations by companion controllers until ehci has started.  
  *  
  * 2) The EHCI driver lacks support for isochronous transfers, so  
  *    devices using them don't work.  
  *  
  * 3) The hub driver needs to handle and schedule the transaction translator,  
  *    to assign place in frame where different devices get to go. See chapter  
  *    on hubs in USB 2.0 for details.  
  *  
  * 4) command failures are not recovered correctly  
 */  
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
Line 88  __KERNEL_RCSID(0, "$NetBSD$");
Line 79  __KERNEL_RCSID(0, "$NetBSD$");
 #include <dev/usb/ehcivar.h>  #include <dev/usb/ehcivar.h>
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
 #define DPRINTF(x)      do { if (ehcidebug) printf x; } while(0)  #define DPRINTF(x)      if (ehcidebug) printf x
 #define DPRINTFN(n,x)   do { if (ehcidebug>(n)) printf x; } while (0)  #define DPRINTFN(n,x)   if (ehcidebug>(n)) printf x
 int ehcidebug = 0;  int ehcidebug = 0;
 #ifndef __NetBSD__  #ifndef __NetBSD__
 #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))  #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
Line 101  int ehcidebug = 0;
Line 92  int ehcidebug = 0;
   
 struct ehci_pipe {  struct ehci_pipe {
         struct usbd_pipe pipe;          struct usbd_pipe pipe;
         int nexttoggle;  
   
         ehci_soft_qh_t *sqh;          ehci_soft_qh_t *sqh;
         union {          union {
                 ehci_soft_qtd_t *qtd;                  ehci_soft_qtd_t *qtd;
Line 113  struct ehci_pipe {
Line 102  struct ehci_pipe {
                 struct {                  struct {
                         usb_dma_t reqdma;                          usb_dma_t reqdma;
                         u_int length;                          u_int length;
                           /*ehci_soft_qtd_t *setup, *data, *stat;*/
                 } ctl;                  } ctl;
                 /* Interrupt pipe */                  /* Interrupt pipe */
                 struct {                  /* XXX */
                         u_int length;  
                 } intr;  
                 /* Bulk pipe */                  /* Bulk pipe */
                 struct {                  struct {
                         u_int length;                          u_int length;
Line 185  Static void  ehci_device_isoc_done(usbd_
Line 173  Static void  ehci_device_isoc_done(usbd_
 Static void             ehci_device_clear_toggle(usbd_pipe_handle pipe);  Static void             ehci_device_clear_toggle(usbd_pipe_handle pipe);
 Static void             ehci_noop(usbd_pipe_handle pipe);  Static void             ehci_noop(usbd_pipe_handle pipe);
   
 Static int              ehci_str(usb_string_descriptor_t *, int, const char *);  Static int              ehci_str(usb_string_descriptor_t *, int, char *);
 Static void             ehci_pcd(ehci_softc_t *, usbd_xfer_handle);  Static void             ehci_pcd(ehci_softc_t *, usbd_xfer_handle);
 Static void             ehci_pcd_able(ehci_softc_t *, int);  Static void             ehci_pcd_able(ehci_softc_t *, int);
 Static void             ehci_pcd_enable(void *);  Static void             ehci_pcd_enable(void *);
Line 204  Static void  ehci_free_sqtd_chain(ehci_s
Line 192  Static void  ehci_free_sqtd_chain(ehci_s
   
 Static usbd_status      ehci_device_request(usbd_xfer_handle xfer);  Static usbd_status      ehci_device_request(usbd_xfer_handle xfer);
   
 Static usbd_status      ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *,  
                             int ival);  
   
 Static void             ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *);  Static void             ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *);
 Static void             ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *,  Static void             ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *,
                                     ehci_soft_qh_t *);                                      ehci_soft_qh_t *);
Line 218  Static void  ehci_abort_xfer(usbd_xfer_h
Line 203  Static void  ehci_abort_xfer(usbd_xfer_h
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
 Static void             ehci_dump_regs(ehci_softc_t *);  Static void             ehci_dump_regs(ehci_softc_t *);
 void                    ehci_dump(void);  Static void             ehci_dump(void);
 Static ehci_softc_t     *theehci;  Static ehci_softc_t     *theehci;
 Static void             ehci_dump_link(ehci_link_t, int);  Static void             ehci_dump_link(ehci_link_t, int);
 Static void             ehci_dump_sqtds(ehci_soft_qtd_t *);  Static void             ehci_dump_sqtds(ehci_soft_qtd_t *);
Line 307  Static struct usbd_pipe_methods ehci_dev
Line 292  Static struct usbd_pipe_methods ehci_dev
         ehci_device_isoc_done,          ehci_device_isoc_done,
 };  };
   
 static uint8_t revbits[EHCI_MAX_POLLRATE] = {  
 0x00,0x40,0x20,0x60,0x10,0x50,0x30,0x70,0x08,0x48,0x28,0x68,0x18,0x58,0x38,0x78,  
 0x04,0x44,0x24,0x64,0x14,0x54,0x34,0x74,0x0c,0x4c,0x2c,0x6c,0x1c,0x5c,0x3c,0x7c,  
 0x02,0x42,0x22,0x62,0x12,0x52,0x32,0x72,0x0a,0x4a,0x2a,0x6a,0x1a,0x5a,0x3a,0x7a,  
 0x06,0x46,0x26,0x66,0x16,0x56,0x36,0x76,0x0e,0x4e,0x2e,0x6e,0x1e,0x5e,0x3e,0x7e,  
 0x01,0x41,0x21,0x61,0x11,0x51,0x31,0x71,0x09,0x49,0x29,0x69,0x19,0x59,0x39,0x79,  
 0x05,0x45,0x25,0x65,0x15,0x55,0x35,0x75,0x0d,0x4d,0x2d,0x6d,0x1d,0x5d,0x3d,0x7d,  
 0x03,0x43,0x23,0x63,0x13,0x53,0x33,0x73,0x0b,0x4b,0x2b,0x6b,0x1b,0x5b,0x3b,0x7b,  
 0x07,0x47,0x27,0x67,0x17,0x57,0x37,0x77,0x0f,0x4f,0x2f,0x6f,0x1f,0x5f,0x3f,0x7f,  
 };  
   
 usbd_status  usbd_status
 ehci_init(ehci_softc_t *sc)  ehci_init(ehci_softc_t *sc)
 {  {
         u_int32_t vers, sparams, cparams, hcr;          u_int32_t version, sparams, cparams, hcr;
         u_int i;          u_int i;
         usbd_status err;          usbd_status err;
         ehci_soft_qh_t *sqh;          ehci_soft_qh_t *sqh;
         u_int ncomp;  
   
         DPRINTF(("ehci_init: start\n"));          DPRINTF(("ehci_init: start\n"));
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
Line 334  ehci_init(ehci_softc_t *sc)
Line 307  ehci_init(ehci_softc_t *sc)
   
         sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);          sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
   
         vers = EREAD2(sc, EHCI_HCIVERSION);          version = EREAD2(sc, EHCI_HCIVERSION);
         aprint_normal("%s: EHCI version %x.%x\n", USBDEVNAME(sc->sc_bus.bdev),          aprint_normal("%s: EHCI version %x.%x\n", USBDEVNAME(sc->sc_bus.bdev),
                vers >> 8, vers & 0xff);                 version >> 8, version & 0xff);
   
         sparams = EREAD4(sc, EHCI_HCSPARAMS);          sparams = EREAD4(sc, EHCI_HCSPARAMS);
         DPRINTF(("ehci_init: sparams=0x%x\n", sparams));          DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
         sc->sc_npcomp = EHCI_HCS_N_PCC(sparams);          sc->sc_npcomp = EHCI_HCS_N_PCC(sparams);
         ncomp = EHCI_HCS_N_CC(sparams);          if (EHCI_HCS_N_CC(sparams) != sc->sc_ncomp) {
         if (ncomp != sc->sc_ncomp) {  
                 aprint_error("%s: wrong number of companions (%d != %d)\n",                  aprint_error("%s: wrong number of companions (%d != %d)\n",
                        USBDEVNAME(sc->sc_bus.bdev),                         USBDEVNAME(sc->sc_bus.bdev),
                        ncomp, sc->sc_ncomp);                         EHCI_HCS_N_CC(sparams), sc->sc_ncomp);
 #if NOHCI == 0 || NUHCI == 0  #if NOHCI == 0 || NUHCI == 0
                 aprint_error("%s: ohci or uhci probably not configured\n",                  aprint_error("%s: ohci or uhci probably not configured\n",
                              USBDEVNAME(sc->sc_bus.bdev));                               USBDEVNAME(sc->sc_bus.bdev));
 #endif  #endif
                 if (ncomp < sc->sc_ncomp)                  return (USBD_IOERROR);
                         sc->sc_ncomp = ncomp;  
         }          }
         if (sc->sc_ncomp > 0) {          if (sc->sc_ncomp > 0) {
                 aprint_normal("%s: companion controller%s, %d port%s each:",                  aprint_normal("%s: companion controller%s, %d port%s each:",
Line 365  ehci_init(ehci_softc_t *sc)
Line 336  ehci_init(ehci_softc_t *sc)
         sc->sc_noport = EHCI_HCS_N_PORTS(sparams);          sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
         cparams = EREAD4(sc, EHCI_HCCPARAMS);          cparams = EREAD4(sc, EHCI_HCCPARAMS);
         DPRINTF(("ehci_init: cparams=0x%x\n", cparams));          DPRINTF(("ehci_init: cparams=0x%x\n", cparams));
         sc->sc_hasppc = EHCI_HCS_PPC(sparams);  
   
         if (EHCI_HCC_64BIT(cparams)) {          if (EHCI_HCC_64BIT(cparams)) {
                 /* MUST clear segment register if 64 bit capable. */                  /* MUST clear segment register if 64 bit capable. */
Line 374  ehci_init(ehci_softc_t *sc)
Line 344  ehci_init(ehci_softc_t *sc)
   
         sc->sc_bus.usbrev = USBREV_2_0;          sc->sc_bus.usbrev = USBREV_2_0;
   
         usb_setup_reserve(sc, &sc->sc_dma_reserve, sc->sc_bus.dmatag,  
             USB_MEM_RESERVE);  
   
         /* Reset the controller */          /* Reset the controller */
         DPRINTF(("%s: resetting\n", USBDEVNAME(sc->sc_bus.bdev)));          DPRINTF(("%s: resetting\n", USBDEVNAME(sc->sc_bus.bdev)));
         EOWRITE4(sc, EHCI_USBCMD, 0);   /* Halt controller */          EOWRITE4(sc, EHCI_USBCMD, 0);   /* Halt controller */
Line 394  ehci_init(ehci_softc_t *sc)
Line 361  ehci_init(ehci_softc_t *sc)
                 return (USBD_IOERROR);                  return (USBD_IOERROR);
         }          }
   
         /* XXX need proper intr scheduling */  
         sc->sc_rand = 96;  
   
         /* frame list size at default, read back what we got and use that */          /* frame list size at default, read back what we got and use that */
         switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) {          switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) {
         case 0: sc->sc_flsize = 1024; break;          case 0: sc->sc_flsize = 1024*4; break;
         case 1: sc->sc_flsize = 512; break;          case 1: sc->sc_flsize = 512*4; break;
         case 2: sc->sc_flsize = 256; break;          case 2: sc->sc_flsize = 256*4; break;
         case 3: return (USBD_IOERROR);          case 3: return (USBD_IOERROR);
         }          }
         err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t),          err = usb_allocmem(&sc->sc_bus, sc->sc_flsize,
             EHCI_FLALIGN_ALIGN, &sc->sc_fldma);                             EHCI_FLALIGN_ALIGN, &sc->sc_fldma);
         if (err)          if (err)
                 return (err);                  return (err);
         DPRINTF(("%s: flsize=%d\n", USBDEVNAME(sc->sc_bus.bdev),sc->sc_flsize));          DPRINTF(("%s: flsize=%d\n", USBDEVNAME(sc->sc_bus.bdev),sc->sc_flsize));
         sc->sc_flist = KERNADDR(&sc->sc_fldma, 0);  
         EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));  
   
         /* Set up the bus struct. */          /* Set up the bus struct. */
         sc->sc_bus.methods = &ehci_bus_methods;          sc->sc_bus.methods = &ehci_bus_methods;
Line 421  ehci_init(ehci_softc_t *sc)
Line 383  ehci_init(ehci_softc_t *sc)
   
         sc->sc_eintrs = EHCI_NORMAL_INTRS;          sc->sc_eintrs = EHCI_NORMAL_INTRS;
   
         /*  
          * Allocate the interrupt dummy QHs. These are arranged to give poll  
          * intervals that are powers of 2 times 1ms.  
          */  
         for (i = 0; i < EHCI_INTRQHS; i++) {  
                 sqh = ehci_alloc_sqh(sc);  
                 if (sqh == NULL) {  
                         err = USBD_NOMEM;  
                         goto bad1;  
                 }  
                 sc->sc_islots[i].sqh = sqh;  
         }  
         for (i = 0; i < EHCI_INTRQHS; i++) {  
                 sqh = sc->sc_islots[i].sqh;  
                 if (i == 0) {  
                         /* The last (1ms) QH terminates. */  
                         sqh->qh.qh_link = EHCI_NULL;  
                         sqh->next = NULL;  
                 } else {  
                         /* Otherwise the next QH has half the poll interval */  
                         sqh->next = sc->sc_islots[(i + 1) / 2 - 1].sqh;  
                         sqh->qh.qh_link = htole32(sqh->next->physaddr |  
                             EHCI_LINK_QH);  
                 }  
                 sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH));  
                 sqh->qh.qh_curqtd = EHCI_NULL;  
                 sqh->next = NULL;  
                 sqh->qh.qh_qtd.qtd_next = EHCI_NULL;  
                 sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;  
                 sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);  
                 sqh->sqtd = NULL;  
         }  
         /* Point the frame list at the last level (128ms). */  
         for (i = 0; i < sc->sc_flsize; i++) {  
                 int j;  
   
                 j = (i & ~(EHCI_MAX_POLLRATE-1)) |  
                     revbits[i & (EHCI_MAX_POLLRATE-1)];  
                 sc->sc_flist[j] = htole32(EHCI_LINK_QH |  
                     sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1,  
                     i)].sqh->physaddr);  
         }  
   
         /* Allocate dummy QH that starts the async list. */          /* Allocate dummy QH that starts the async list. */
         sqh = ehci_alloc_sqh(sc);          sqh = ehci_alloc_sqh(sc);
         if (sqh == NULL) {          if (sqh == NULL) {
Line 496  ehci_init(ehci_softc_t *sc)
Line 415  ehci_init(ehci_softc_t *sc)
   
         lockinit(&sc->sc_doorbell_lock, PZERO, "ehcidb", 0, 0);          lockinit(&sc->sc_doorbell_lock, PZERO, "ehcidb", 0, 0);
   
           /* Enable interrupts */
           EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
   
         /* Turn on controller */          /* Turn on controller */
         EOWRITE4(sc, EHCI_USBCMD,          EOWRITE4(sc, EHCI_USBCMD,
                  EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */                   EHCI_CMD_ITC_8 | /* 8 microframes */
                  (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |                   (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
                  EHCI_CMD_ASE |                   EHCI_CMD_ASE |
                  EHCI_CMD_PSE |                   /* EHCI_CMD_PSE | */
                  EHCI_CMD_RS);                   EHCI_CMD_RS);
   
         /* Take over port ownership */          /* Take over port ownership */
Line 518  ehci_init(ehci_softc_t *sc)
Line 440  ehci_init(ehci_softc_t *sc)
                 return (USBD_IOERROR);                  return (USBD_IOERROR);
         }          }
   
         /* Enable interrupts */  
         DPRINTFN(1,("ehci_init: enabling\n"));  
         EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);  
   
         return (USBD_NORMAL_COMPLETION);          return (USBD_NORMAL_COMPLETION);
   
 #if 0  #if 0
Line 543  ehci_intr(void *v)
Line 461  ehci_intr(void *v)
   
         /* If we get an interrupt while polling, then just ignore it. */          /* If we get an interrupt while polling, then just ignore it. */
         if (sc->sc_bus.use_polling) {          if (sc->sc_bus.use_polling) {
                 u_int32_t intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));  
   
                 if (intrs)  
                         EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */  
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n"));                  printf("ehci_intr: ignored interrupt while polling\n");
 #endif  #endif
                 return (0);                  return (0);
         }          }
Line 566  ehci_intr1(ehci_softc_t *sc)
Line 480  ehci_intr1(ehci_softc_t *sc)
         /* In case the interrupt occurs before initialization has completed. */          /* In case the interrupt occurs before initialization has completed. */
         if (sc == NULL) {          if (sc == NULL) {
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 printf("ehci_intr1: sc == NULL\n");                  printf("ehci_intr: sc == NULL\n");
 #endif  #endif
                 return (0);                  return (0);
         }          }
   
         intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));          intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
   
         if (!intrs)          if (!intrs)
                 return (0);                  return (0);
   
           EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */
         eintrs = intrs & sc->sc_eintrs;          eintrs = intrs & sc->sc_eintrs;
         DPRINTFN(7, ("ehci_intr1: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n",          DPRINTFN(7, ("ehci_intr: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n",
                      sc, (u_int)intrs, EOREAD4(sc, EHCI_USBSTS),                       sc, (u_int)intrs, EOREAD4(sc, EHCI_USBSTS),
                      (u_int)eintrs));                       (u_int)eintrs));
         if (!eintrs)          if (!eintrs)
                 return (0);                  return (0);
   
         EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */  
         sc->sc_bus.intr_context++;          sc->sc_bus.intr_context++;
         sc->sc_bus.no_intrs++;          sc->sc_bus.no_intrs++;
         if (eintrs & EHCI_STS_IAA) {          if (eintrs & EHCI_STS_IAA) {
Line 650  void
Line 565  void
 ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)  ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
 {  {
         usbd_pipe_handle pipe;          usbd_pipe_handle pipe;
           struct ehci_pipe *epipe;
         u_char *p;          u_char *p;
         int i, m;          int i, m;
   
Line 659  ehci_pcd(ehci_softc_t *sc, usbd_xfer_han
Line 575  ehci_pcd(ehci_softc_t *sc, usbd_xfer_han
         }          }
   
         pipe = xfer->pipe;          pipe = xfer->pipe;
           epipe = (struct ehci_pipe *)pipe;
   
         p = KERNADDR(&xfer->dmabuf, 0);          p = KERNADDR(&xfer->dmabuf, 0);
         m = min(sc->sc_noport, xfer->length * 8 - 1);          m = min(sc->sc_noport, xfer->length * 8 - 1);
Line 679  void
Line 596  void
 ehci_softintr(void *v)  ehci_softintr(void *v)
 {  {
         ehci_softc_t *sc = v;          ehci_softc_t *sc = v;
         struct ehci_xfer *ex, *nextex;          struct ehci_xfer *ex;
   
         DPRINTFN(10,("%s: ehci_softintr (%d)\n", USBDEVNAME(sc->sc_bus.bdev),          DPRINTFN(10,("%s: ehci_softintr (%d)\n", USBDEVNAME(sc->sc_bus.bdev),
                      sc->sc_bus.intr_context));                       sc->sc_bus.intr_context));
Line 692  ehci_softintr(void *v)
Line 609  ehci_softintr(void *v)
          * An interrupt just tells us that something is done, we have no           * An interrupt just tells us that something is done, we have no
          * clue what, so we need to scan through all active transfers. :-(           * clue what, so we need to scan through all active transfers. :-(
          */           */
         for (ex = LIST_FIRST(&sc->sc_intrhead); ex; ex = nextex) {          for (ex = LIST_FIRST(&sc->sc_intrhead); ex; ex = LIST_NEXT(ex, inext))
                 nextex = LIST_NEXT(ex, inext);  
                 ehci_check_intr(sc, ex);                  ehci_check_intr(sc, ex);
         }  
   
 #ifdef USB_USE_SOFTINTR  
         if (sc->sc_softwake) {          if (sc->sc_softwake) {
                 sc->sc_softwake = 0;                  sc->sc_softwake = 0;
                 wakeup(&sc->sc_softwake);                  wakeup(&sc->sc_softwake);
         }          }
 #endif /* USB_USE_SOFTINTR */  
   
         sc->sc_bus.intr_context--;          sc->sc_bus.intr_context--;
 }  }
Line 723  ehci_check_intr(ehci_softc_t *sc, struct
Line 636  ehci_check_intr(ehci_softc_t *sc, struct
         lsqtd = ex->sqtdend;          lsqtd = ex->sqtdend;
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (lsqtd == NULL) {          if (lsqtd == NULL) {
                 printf("ehci_check_intr: lsqtd==0\n");                  printf("ehci_check_intr: sqtd==0\n");
                 return;                  return;
         }          }
 #endif  #endif
Line 743  ehci_check_intr(ehci_softc_t *sc, struct
Line 656  ehci_check_intr(ehci_softc_t *sc, struct
                         if (status & EHCI_QTD_HALTED)                          if (status & EHCI_QTD_HALTED)
                                 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 (EHCI_QTD_GET_BYTES(status) != 0)                          if (EHCI_QTD_SET_BYTES(status) != 0)
                                 goto done;                                  goto done;
                 }                  }
                 DPRINTFN(12, ("ehci_check_intr: ex=%p std=%p still active\n",                  DPRINTFN(12, ("ehci_check_intr: ex=%p std=%p still active\n",
Line 760  void
Line 673  void
 ehci_idone(struct ehci_xfer *ex)  ehci_idone(struct ehci_xfer *ex)
 {  {
         usbd_xfer_handle xfer = &ex->xfer;          usbd_xfer_handle xfer = &ex->xfer;
   #ifdef EHCI_DEBUG
         struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;          struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
         ehci_soft_qtd_t *sqtd, *lsqtd;  #endif
         u_int32_t status = 0, nstatus = 0;          ehci_soft_qtd_t *sqtd;
           u_int32_t status = 0, nstatus;
         int actlen;          int actlen;
         uint pkts_left;  
   
         DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));          DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
Line 798  ehci_idone(struct ehci_xfer *ex)
Line 712  ehci_idone(struct ehci_xfer *ex)
 #endif  #endif
   
         /* The transfer is done, compute actual length and status. */          /* The transfer is done, compute actual length and status. */
         lsqtd = ex->sqtdend;  
         actlen = 0;          actlen = 0;
         for (sqtd = ex->sqtdstart; sqtd != lsqtd->nextqtd; sqtd=sqtd->nextqtd) {          for (sqtd = ex->sqtdstart; sqtd != NULL; sqtd = sqtd->nextqtd) {
                 nstatus = le32toh(sqtd->qtd.qtd_status);                  nstatus = le32toh(sqtd->qtd.qtd_status);
                 if (nstatus & EHCI_QTD_ACTIVE)                  if (nstatus & EHCI_QTD_ACTIVE)
                         break;                          break;
   
                 status = nstatus;                  status = nstatus;
                   /* halt is ok if descriptor is last, and complete */
                   if(sqtd->qtd.qtd_next == EHCI_NULL
                           && EHCI_QTD_GET_BYTES(status) == 0)
                           status &= ~EHCI_QTD_HALTED;
                 if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)                  if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)
                         actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);                          actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
         }          }
   
         /*          /* 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 (sqtd != NULL) {
          * The default pipe doesn't need it since control transfers                  if (!(xfer->rqflags & URQ_REQUEST))
          * start the toggle at 0 every time.                          printf("ehci_idone: need toggle update\n");
          */  
         if (sqtd != lsqtd->nextqtd &&  
             xfer->pipe->device->default_pipe != xfer->pipe) {  
                 printf("ehci_idone: need toggle update status=%08x nstatus=%08x\n", status, nstatus);  
 #if 0  #if 0
                 ehci_dump_sqh(epipe->sqh);                  epipe->nexttoggle = EHCI_TD_GET_DT(le32toh(std->td.td_token));
                 ehci_dump_sqtds(ex->sqtdstart);  
 #endif  #endif
                 epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus);  
         }          }
   
         /*          status &= EHCI_QTD_STATERRS;
          * For a short transfer we need to update the toggle for the missing  
          * packets within the qTD.  
          */  
         pkts_left = EHCI_QTD_GET_BYTES(status) /  
             UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);  
         epipe->nexttoggle ^= pkts_left % 2;  
   
         DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",          DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",
                            xfer->length, actlen, status));                             xfer->length, actlen, status));
         xfer->actlen = actlen;          xfer->actlen = actlen;
         if (status & EHCI_QTD_HALTED) {          if (status != 0) {
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
                 char sbuf[128];                  char sbuf[128];
   
                 bitmask_snprintf((u_int32_t)status,                  bitmask_snprintf((u_int32_t)status,
                                  "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR"                                   "\20\3MISSEDMICRO\4XACT\5BABBLE\6BABBLE"
                                  "\3MISSED\1PINGSTATE", sbuf, sizeof(sbuf));                                   "\7HALTED",
                                    sbuf, sizeof(sbuf));
   
                 DPRINTFN(2, ("ehci_idone: error, addr=%d, endpt=0x%02x, "                  DPRINTFN((status == EHCI_QTD_HALTED)*/*10*/2,
                            ("ehci_idone: error, addr=%d, endpt=0x%02x, "
                           "status 0x%s\n",                            "status 0x%s\n",
                           xfer->pipe->device->address,                            xfer->pipe->device->address,
                           xfer->pipe->endpoint->edesc->bEndpointAddress,                            xfer->pipe->endpoint->edesc->bEndpointAddress,
Line 854  ehci_idone(struct ehci_xfer *ex)
Line 760  ehci_idone(struct ehci_xfer *ex)
                         ehci_dump_sqtds(ex->sqtdstart);                          ehci_dump_sqtds(ex->sqtdstart);
                 }                  }
 #endif  #endif
                 /* low&full speed has an extra error flag */                  if (status == EHCI_QTD_HALTED)
                 if (EHCI_QH_GET_EPS(epipe->sqh->qh.qh_endp) !=  
                     EHCI_QH_SPEED_HIGH)  
                         status &= EHCI_QTD_STATERRS | EHCI_QTD_PINGSTATE;  
                 else  
                         status &= EHCI_QTD_STATERRS;  
                 if (status == 0) /* no other errors means a stall */  
                         xfer->status = USBD_STALLED;                          xfer->status = USBD_STALLED;
                 else                  else
                         xfer->status = USBD_IOERROR; /* more info XXX */                          xfer->status = USBD_IOERROR; /* more info XXX */
                 /* XXX need to reset TT on missed microframe */  
                 if (status & EHCI_QTD_MISSEDMICRO) {  
                         ehci_softc_t *sc = (ehci_softc_t *)  
                             xfer->pipe->device->bus;  
   
                         printf("%s: missed microframe, TT reset not "  
                             "implemented, hub might be inoperational\n",  
                             USBDEVNAME(sc->sc_bus.bdev));  
                 }  
         } else {          } else {
                 xfer->status = USBD_NORMAL_COMPLETION;                  xfer->status = USBD_NORMAL_COMPLETION;
         }          }
Line 889  ehci_idone(struct ehci_xfer *ex)
Line 780  ehci_idone(struct ehci_xfer *ex)
 void  void
 ehci_waitintr(ehci_softc_t *sc, usbd_xfer_handle xfer)  ehci_waitintr(ehci_softc_t *sc, usbd_xfer_handle xfer)
 {  {
         int timo;          int timo = xfer->timeout;
           int usecs;
         u_int32_t intrs;          u_int32_t intrs;
   
         xfer->status = USBD_IN_PROGRESS;          xfer->status = USBD_IN_PROGRESS;
         for (timo = xfer->timeout; timo >= 0; timo--) {          for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) {
                 usb_delay_ms(&sc->sc_bus, 1);                  usb_delay_ms(&sc->sc_bus, 1);
                 if (sc->sc_dying)                  if (sc->sc_dying)
                         break;                          break;
                 intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) &                  intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) &
                         sc->sc_eintrs;                          sc->sc_eintrs;
                 DPRINTFN(15,("ehci_waitintr: 0x%04x\n", intrs));                  DPRINTFN(15,("ehci_waitintr: 0x%04x\n", intrs));
 #ifdef EHCI_DEBUG  #ifdef OHCI_DEBUG
                 if (ehcidebug > 15)                  if (ehcidebug > 15)
                         ehci_dump_regs(sc);                          ehci_dump_regs(sc);
 #endif  #endif
Line 971  ehci_activate(device_ptr_t self, enum de
Line 863  ehci_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 985  ehci_activate(device_ptr_t self, enum de
Line 878  ehci_activate(device_ptr_t self, enum de
  * 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 interrupt context.  This is all right since we   * called from an intterupt context.  This is all right since we
  * are almost suspended anyway.   * are almost suspended anyway.
  */   */
 void  void
 ehci_power(int why, void *v)  ehci_power(int why, void *v)
 {  {
         ehci_softc_t *sc = v;          ehci_softc_t *sc = v;
         u_int32_t cmd, hcr;          //u_int32_t ctl;
         int s, i;          int s;
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
         DPRINTF(("ehci_power: sc=%p, why=%d\n", sc, why));          DPRINTF(("ehci_power: sc=%p, why=%d\n", sc, why));
         if (ehcidebug > 0)          ehci_dump_regs(sc);
                 ehci_dump_regs(sc);  
 #endif  #endif
   
         s = splhardusb();          s = splhardusb();
Line 1006  ehci_power(int why, void *v)
Line 898  ehci_power(int why, void *v)
         case PWR_SUSPEND:          case PWR_SUSPEND:
         case PWR_STANDBY:          case PWR_STANDBY:
                 sc->sc_bus.use_polling++;                  sc->sc_bus.use_polling++;
   #if 0
                 sc->sc_cmd = EOREAD4(sc, EHCI_USBCMD);  OOO
                   ctl = OREAD4(sc, EHCI_CONTROL) & ~EHCI_HCFS_MASK;
                 cmd = sc->sc_cmd & ~(EHCI_CMD_ASE | EHCI_CMD_PSE);                  if (sc->sc_control == 0) {
                 EOWRITE4(sc, EHCI_USBCMD, cmd);                          /*
                            * Preserve register values, in case that APM BIOS
                 for (i = 0; i < 100; i++) {                           * does not recover them.
                         hcr = EOREAD4(sc, EHCI_USBSTS) &                           */
                             (EHCI_STS_ASS | EHCI_STS_PSS);                          sc->sc_control = ctl;
                         if (hcr == 0)                          sc->sc_intre = OREAD4(sc, EHCI_INTERRUPT_ENABLE);
                                 break;  
   
                         usb_delay_ms(&sc->sc_bus, 1);  
                 }  
                 if (hcr != 0) {  
                         printf("%s: reset timeout\n",  
                             USBDEVNAME(sc->sc_bus.bdev));  
                 }  
   
                 cmd &= ~EHCI_CMD_RS;  
                 EOWRITE4(sc, EHCI_USBCMD, cmd);  
   
                 for (i = 0; i < 100; i++) {  
                         hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;  
                         if (hcr == EHCI_STS_HCH)  
                                 break;  
   
                         usb_delay_ms(&sc->sc_bus, 1);  
                 }  
                 if (hcr != EHCI_STS_HCH) {  
                         printf("%s: config timeout\n",  
                             USBDEVNAME(sc->sc_bus.bdev));  
                 }                  }
                   ctl |= EHCI_HCFS_SUSPEND;
                   OWRITE4(sc, EHCI_CONTROL, ctl);
   #endif
                   usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
                 sc->sc_bus.use_polling--;                  sc->sc_bus.use_polling--;
                 break;                  break;
   
         case PWR_RESUME:          case PWR_RESUME:
                 sc->sc_bus.use_polling++;                  sc->sc_bus.use_polling++;
   #if 0
                 /* restore things in case the bios sucks */  OOO
                 EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);                  /* Some broken BIOSes do not recover these values */
                 EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));                  OWRITE4(sc, EHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
                 EOWRITE4(sc, EHCI_ASYNCLISTADDR,                  OWRITE4(sc, EHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
                     sc->sc_async_head->physaddr | EHCI_LINK_QH);                  OWRITE4(sc, EHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
                 EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);                  if (sc->sc_intre)
                           OWRITE4(sc, EHCI_INTERRUPT_ENABLE,
                 EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd);                                  sc->sc_intre & (EHCI_ALL_INTRS | EHCI_MIE));
                   if (sc->sc_control)
                 for (i = 0; i < 100; i++) {                          ctl = sc->sc_control;
                         hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;                  else
                         if (hcr != EHCI_STS_HCH)                          ctl = OREAD4(sc, EHCI_CONTROL);
                                 break;                  ctl |= EHCI_HCFS_RESUME;
                   OWRITE4(sc, EHCI_CONTROL, ctl);
                         usb_delay_ms(&sc->sc_bus, 1);                  usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
                 }                  ctl = (ctl & ~EHCI_HCFS_MASK) | EHCI_HCFS_OPERATIONAL;
                 if (hcr == EHCI_STS_HCH) {                  OWRITE4(sc, EHCI_CONTROL, ctl);
                         printf("%s: config timeout\n",                  usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
                             USBDEVNAME(sc->sc_bus.bdev));                  sc->sc_control = sc->sc_intre = 0;
                 }  #endif
   
                 usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);  
   
                 sc->sc_bus.use_polling--;                  sc->sc_bus.use_polling--;
                 break;                  break;
         case PWR_SOFTSUSPEND:          case PWR_SOFTSUSPEND:
Line 1077  ehci_power(int why, void *v)
Line 946  ehci_power(int why, void *v)
                 break;                  break;
         }          }
         splx(s);          splx(s);
   
 #ifdef EHCI_DEBUG  
         DPRINTF(("ehci_power: sc=%p\n", sc));  
         if (ehcidebug > 0)  
                 ehci_dump_regs(sc);  
 #endif  
 }  }
   
 /*  /*
Line 1105  ehci_allocm(struct usbd_bus *bus, usb_dm
Line 968  ehci_allocm(struct usbd_bus *bus, usb_dm
         usbd_status err;          usbd_status err;
   
         err = usb_allocmem(&sc->sc_bus, size, 0, dma);          err = usb_allocmem(&sc->sc_bus, size, 0, dma);
         if (err == USBD_NOMEM)  
                 err = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size);  
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
         if (err)          if (err)
                 printf("ehci_allocm: usb_allocmem()=%d\n", err);                  printf("ehci_allocm: usb_allocmem()=%d\n", err);
Line 1119  ehci_freem(struct usbd_bus *bus, usb_dma
Line 980  ehci_freem(struct usbd_bus *bus, usb_dma
 {  {
         struct ehci_softc *sc = (struct ehci_softc *)bus;          struct ehci_softc *sc = (struct ehci_softc *)bus;
   
         if (dma->block->flags & USB_DMA_RESERVE) {  
                 usb_reserve_freem(&((struct ehci_softc *)bus)->sc_dma_reserve,  
                     dma);  
                 return;  
         }  
         usb_freemem(&sc->sc_bus, dma);          usb_freemem(&sc->sc_bus, dma);
 }  }
   
Line 1138  ehci_allocx(struct usbd_bus *bus)
Line 994  ehci_allocx(struct usbd_bus *bus)
                 SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);                  SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 if (xfer->busy_free != XFER_FREE) {                  if (xfer->busy_free != XFER_FREE) {
                         printf("ehci_allocx: xfer=%p not free, 0x%08x\n", xfer,                          printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer,
                                xfer->busy_free);                                 xfer->busy_free);
                 }                  }
 #endif  #endif
Line 1146  ehci_allocx(struct usbd_bus *bus)
Line 1002  ehci_allocx(struct usbd_bus *bus)
                 xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT);                  xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT);
         }          }
         if (xfer != NULL) {          if (xfer != NULL) {
                 memset(xfer, 0, sizeof(struct ehci_xfer));                  memset(xfer, 0, sizeof (struct ehci_xfer));
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 EXFER(xfer)->isdone = 1;                  EXFER(xfer)->isdone = 1;
                 xfer->busy_free = XFER_BUSY;                  xfer->busy_free = XFER_BUSY;
Line 1186  ehci_device_clear_toggle(usbd_pipe_handl
Line 1042  ehci_device_clear_toggle(usbd_pipe_handl
         if (ehcidebug)          if (ehcidebug)
                 usbd_dump_pipe(pipe);                  usbd_dump_pipe(pipe);
 #endif  #endif
         epipe->nexttoggle = 0;          epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE);
 }  }
   
 Static void  Static void
Line 1253  ehci_dump_sqtds(ehci_soft_qtd_t *sqtd)
Line 1109  ehci_dump_sqtds(ehci_soft_qtd_t *sqtd)
         stop = 0;          stop = 0;
         for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {          for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
                 ehci_dump_sqtd(sqtd);                  ehci_dump_sqtd(sqtd);
                 stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE);                  stop = sqtd->qtd.qtd_next & EHCI_LINK_TERMINATE;
         }          }
         if (sqtd)          if (sqtd)
                 printf("dump aborted, too many TDs\n");                  printf("dump aborted, too many TDs\n");
Line 1337  ehci_open(usbd_pipe_handle pipe)
Line 1193  ehci_open(usbd_pipe_handle pipe)
         ehci_soft_qh_t *sqh;          ehci_soft_qh_t *sqh;
         usbd_status err;          usbd_status err;
         int s;          int s;
         int ival, speed, naks;          int speed, naks;
         int hshubaddr, hshubport;  
   
         DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",          DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
                      pipe, addr, ed->bEndpointAddress, sc->sc_addr));                       pipe, addr, ed->bEndpointAddress, sc->sc_addr));
   
         if (dev->myhsport) {  
                 hshubaddr = dev->myhsport->parent->address;  
                 hshubport = dev->myhsport->portno;  
         } else {  
                 hshubaddr = 0;  
                 hshubport = 0;  
         }  
   
         if (sc->sc_dying)          if (sc->sc_dying)
                 return (USBD_IOERROR);                  return (USBD_IOERROR);
   
         epipe->nexttoggle = 0;  
   
         if (addr == sc->sc_addr) {          if (addr == sc->sc_addr) {
                 switch (ed->bEndpointAddress) {                  switch (ed->bEndpointAddress) {
                 case USB_CONTROL_ENDPOINT:                  case USB_CONTROL_ENDPOINT:
Line 1377  ehci_open(usbd_pipe_handle pipe)
Line 1222  ehci_open(usbd_pipe_handle pipe)
         case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break;          case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break;
         default: panic("ehci_open: bad device speed %d", dev->speed);          default: panic("ehci_open: bad device speed %d", dev->speed);
         }          }
         if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) {  
                 printf("%s: *** WARNING: opening low/full speed isoc device, "  
                        "this does not work yet.\n",  
                        USBDEVNAME(sc->sc_bus.bdev));  
                 DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n",  
                             hshubaddr, hshubport));  
                 return USBD_INVAL;  
         }  
   
         naks = 8;               /* XXX */          naks = 8;               /* XXX */
         sqh = ehci_alloc_sqh(sc);          sqh = ehci_alloc_sqh(sc);
         if (sqh == NULL)          if (sqh == NULL)
Line 1393  ehci_open(usbd_pipe_handle pipe)
Line 1229  ehci_open(usbd_pipe_handle pipe)
         /* qh_link filled when the QH is added */          /* qh_link filled when the QH is added */
         sqh->qh.qh_endp = htole32(          sqh->qh.qh_endp = htole32(
                 EHCI_QH_SET_ADDR(addr) |                  EHCI_QH_SET_ADDR(addr) |
                 EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |                  EHCI_QH_SET_ENDPT(ed->bEndpointAddress) |
                 EHCI_QH_SET_EPS(speed) |                  EHCI_QH_SET_EPS(speed) | /* XXX */
                 EHCI_QH_DTC |                  /* XXX EHCI_QH_DTC ? */
                 EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |                  EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
                 (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?                  (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
                  EHCI_QH_CTL : 0) |                   EHCI_QH_CTL : 0) |
                 EHCI_QH_SET_NRL(naks)                  EHCI_QH_SET_NRL(naks)
                 );                  );
         sqh->qh.qh_endphub = htole32(          sqh->qh.qh_endphub = htole32(
                 EHCI_QH_SET_MULT(1) |                  EHCI_QH_SET_MULT(1)
                 EHCI_QH_SET_HUBA(hshubaddr) |                  /* XXX TT stuff */
                 EHCI_QH_SET_PORT(hshubport) |                  /* XXX interrupt mask */
                 EHCI_QH_SET_CMASK(0x08) | /* XXX */  
                 EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x02 : 0)  
                 );                  );
         sqh->qh.qh_curqtd = EHCI_NULL;          sqh->qh.qh_curqtd = EHCI_NULL;
         /* Fill the overlay qTD */          /* Fill the overlay qTD */
Line 1439  ehci_open(usbd_pipe_handle pipe)
Line 1273  ehci_open(usbd_pipe_handle pipe)
                 break;                  break;
         case UE_INTERRUPT:          case UE_INTERRUPT:
                 pipe->methods = &ehci_device_intr_methods;                  pipe->methods = &ehci_device_intr_methods;
                 ival = pipe->interval;                  return (USBD_INVAL);
                 if (ival == USBD_DEFAULT_INTERVAL)  
                         ival = ed->bInterval;  
                 return (ehci_device_setintr(sc, sqh, ival));  
         case UE_ISOCHRONOUS:          case UE_ISOCHRONOUS:
                 pipe->methods = &ehci_device_isoc_methods;                  pipe->methods = &ehci_device_isoc_methods;
                 return (USBD_INVAL);                  return (USBD_INVAL);
Line 1501  ehci_rem_qh(ehci_softc_t *sc, ehci_soft_
Line 1332  ehci_rem_qh(ehci_softc_t *sc, ehci_soft_
 void  void
 ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)  ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
 {  {
         int i;          /* Halt while we are messing. */
         u_int32_t status;          sqh->qh.qh_qtd.qtd_status |= htole32(EHCI_QTD_HALTED);
   
         /* Save toggle bit and ping status. */  
         status = sqh->qh.qh_qtd.qtd_status &  
             htole32(EHCI_QTD_TOGGLE_MASK |  
                     EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE));  
         /* Set HALTED to make hw leave it alone. */  
         sqh->qh.qh_qtd.qtd_status =  
             htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED));  
         sqh->qh.qh_curqtd = 0;          sqh->qh.qh_curqtd = 0;
         sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);          sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
         sqh->qh.qh_qtd.qtd_altnext = 0;  
         for (i = 0; i < EHCI_QTD_NBUFFERS; i++)  
                 sqh->qh.qh_qtd.qtd_buffer[i] = 0;  
         sqh->sqtd = sqtd;          sqh->sqtd = sqtd;
         /* Set !HALTED && !ACTIVE to start execution, preserve some fields */          /* Keep toggle, clear the rest, including length. */
         sqh->qh.qh_qtd.qtd_status = status;          sqh->qh.qh_qtd.qtd_status &= htole32(EHCI_QTD_TOGGLE);
 }  }
   
 /*  /*
Line 1537  ehci_sync_hc(ehci_softc_t *sc)
Line 1357  ehci_sync_hc(ehci_softc_t *sc)
                 return;                  return;
         }          }
         DPRINTFN(2,("ehci_sync_hc: enter\n"));          DPRINTFN(2,("ehci_sync_hc: enter\n"));
         usb_lockmgr(&sc->sc_doorbell_lock, LK_EXCLUSIVE, NULL); /* get doorbell */          lockmgr(&sc->sc_doorbell_lock, LK_EXCLUSIVE, NULL); /* get doorbell */
         s = splhardusb();          s = splhardusb();
         /* ask for doorbell */          /* ask for doorbell */
         EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD);          EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD);
Line 1547  ehci_sync_hc(ehci_softc_t *sc)
Line 1367  ehci_sync_hc(ehci_softc_t *sc)
         DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",          DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
                     EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));                      EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
         splx(s);          splx(s);
         usb_lockmgr(&sc->sc_doorbell_lock, LK_RELEASE, NULL); /* release doorbell */          lockmgr(&sc->sc_doorbell_lock, LK_RELEASE, NULL); /* release doorbell */
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (error)          if (error)
                 printf("ehci_sync_hc: tsleep() = %d\n", error);                  printf("ehci_sync_hc: tsleep() = %d\n", error);
Line 1630  Static usb_hub_descriptor_t ehci_hubd = 
Line 1450  Static usb_hub_descriptor_t ehci_hubd = 
 };  };
   
 Static int  Static int
 ehci_str(usb_string_descriptor_t *p, int l, const char *s)  ehci_str(p, l, s)
           usb_string_descriptor_t *p;
           int l;
           char *s;
 {  {
         int i;          int i;
   
Line 1686  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1509  ehci_root_ctrl_start(usbd_xfer_handle xf
 #endif  #endif
         req = &xfer->request;          req = &xfer->request;
   
         DPRINTFN(4,("ehci_root_ctrl_start: type=0x%02x request=%02x\n",          DPRINTFN(4,("ehci_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 1713  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1536  ehci_root_ctrl_start(usbd_xfer_handle xf
                 }                  }
                 break;                  break;
         case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):          case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
                 DPRINTFN(8,("ehci_root_ctrl_start: wValue=0x%04x\n", value));                  DPRINTFN(8,("ehci_root_ctrl_control wValue=0x%04x\n", value));
                 switch(value >> 8) {                  switch(value >> 8) {
                 case UDESC_DEVICE:                  case UDESC_DEVICE:
                         if ((value & 0xff) != 0) {                          if ((value & 0xff) != 0) {
Line 1767  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1590  ehci_root_ctrl_start(usbd_xfer_handle xf
                         *(u_int8_t *)buf = 0;                          *(u_int8_t *)buf = 0;
                         totlen = 1;                          totlen = 1;
                         switch (value & 0xff) {                          switch (value & 0xff) {
                         case 0: /* Language table */  
                                 totlen = ehci_str(buf, len, "\001");  
                                 break;  
                         case 1: /* Vendor */                          case 1: /* Vendor */
                                 totlen = ehci_str(buf, len, sc->sc_vendor);                                  totlen = ehci_str(buf, len, sc->sc_vendor);
                                 break;                                  break;
Line 1831  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1651  ehci_root_ctrl_start(usbd_xfer_handle xf
         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):          case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
                 break;                  break;
         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):          case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
                 DPRINTFN(4, ("ehci_root_ctrl_start: UR_CLEAR_PORT_FEATURE "                  DPRINTFN(8, ("ehci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
                              "port=%d feature=%d\n",                               "port=%d feature=%d\n",
                              index, value));                               index, value));
                 if (index < 1 || index > sc->sc_noport) {                  if (index < 1 || index > sc->sc_noport) {
Line 1839  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1659  ehci_root_ctrl_start(usbd_xfer_handle xf
                         goto ret;                          goto ret;
                 }                  }
                 port = EHCI_PORTSC(index);                  port = EHCI_PORTSC(index);
                 v = EOREAD4(sc, port);                  v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
                 DPRINTFN(4, ("ehci_root_ctrl_start: portsc=0x%08x\n", v));  
                 v &= ~EHCI_PS_CLEAR;  
                 switch(value) {                  switch(value) {
                 case UHF_PORT_ENABLE:                  case UHF_PORT_ENABLE:
                         EOWRITE4(sc, port, v &~ EHCI_PS_PE);                          EOWRITE4(sc, port, v &~ EHCI_PS_PE);
Line 1850  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1668  ehci_root_ctrl_start(usbd_xfer_handle xf
                         EOWRITE4(sc, port, v &~ EHCI_PS_SUSP);                          EOWRITE4(sc, port, v &~ EHCI_PS_SUSP);
                         break;                          break;
                 case UHF_PORT_POWER:                  case UHF_PORT_POWER:
                         if (sc->sc_hasppc)                          EOWRITE4(sc, port, v &~ EHCI_PS_PP);
                                 EOWRITE4(sc, port, v &~ EHCI_PS_PP);  
                         break;                          break;
                 case UHF_PORT_TEST:                  case UHF_PORT_TEST:
                         DPRINTFN(2,("ehci_root_ctrl_start: clear port test "                          DPRINTFN(2,("ehci_root_ctrl_transfer: clear port test "
                                     "%d\n", index));                                      "%d\n", index));
                         break;                          break;
                 case UHF_PORT_INDICATOR:                  case UHF_PORT_INDICATOR:
                         DPRINTFN(2,("ehci_root_ctrl_start: clear port ind "                          DPRINTFN(2,("ehci_root_ctrl_transfer: clear port ind "
                                     "%d\n", index));                                      "%d\n", index));
                         EOWRITE4(sc, port, v &~ EHCI_PS_PIC);                          EOWRITE4(sc, port, v &~ EHCI_PS_PIC);
                         break;                          break;
Line 1875  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1692  ehci_root_ctrl_start(usbd_xfer_handle xf
                         EOWRITE4(sc, port, v | EHCI_PS_OCC);                          EOWRITE4(sc, port, v | EHCI_PS_OCC);
                         break;                          break;
                 case UHF_C_PORT_RESET:                  case UHF_C_PORT_RESET:
                         sc->sc_isreset[index] = 0;                          sc->sc_isreset = 0;
                         break;                          break;
                 default:                  default:
                         err = USBD_IOERROR;                          err = USBD_IOERROR;
Line 1898  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1715  ehci_root_ctrl_start(usbd_xfer_handle xf
 #endif  #endif
                 break;                  break;
         case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):          case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
                 if ((value & 0xff) != 0) {                  if (value != 0) {
                         err = USBD_IOERROR;                          err = USBD_IOERROR;
                         goto ret;                          goto ret;
                 }                  }
Line 1907  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1724  ehci_root_ctrl_start(usbd_xfer_handle xf
                 v = EOREAD4(sc, EHCI_HCSPARAMS);                  v = EOREAD4(sc, EHCI_HCSPARAMS);
                 USETW(hubd.wHubCharacteristics,                  USETW(hubd.wHubCharacteristics,
                     EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH |                      EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH |
                     EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS))                      EHCI_HCS_P_INCICATOR(EREAD4(sc, EHCI_HCSPARAMS))
                         ? UHD_PORT_IND : 0);                          ? UHD_PORT_IND : 0);
                 hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */                  hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */
                 for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)                  for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)
Line 1926  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1743  ehci_root_ctrl_start(usbd_xfer_handle xf
                 totlen = len;                  totlen = len;
                 break;                  break;
         case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):          case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
                 DPRINTFN(8,("ehci_root_ctrl_start: get port status i=%d\n",                  DPRINTFN(8,("ehci_root_ctrl_transfer: get port status i=%d\n",
                             index));                              index));
                 if (index < 1 || index > sc->sc_noport) {                  if (index < 1 || index > sc->sc_noport) {
                         err = USBD_IOERROR;                          err = USBD_IOERROR;
Line 1937  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1754  ehci_root_ctrl_start(usbd_xfer_handle xf
                         goto ret;                          goto ret;
                 }                  }
                 v = EOREAD4(sc, EHCI_PORTSC(index));                  v = EOREAD4(sc, EHCI_PORTSC(index));
                 DPRINTFN(8,("ehci_root_ctrl_start: port status=0x%04x\n",                  DPRINTFN(8,("ehci_root_ctrl_transfer: port status=0x%04x\n",
                             v));                              v));
                 i = UPS_HIGH_SPEED;                  i = UPS_HIGH_SPEED;
                 if (v & EHCI_PS_CS)     i |= UPS_CURRENT_CONNECT_STATUS;                  if (v & EHCI_PS_CS)     i |= UPS_CURRENT_CONNECT_STATUS;
Line 1951  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1768  ehci_root_ctrl_start(usbd_xfer_handle xf
                 if (v & EHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;                  if (v & EHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
                 if (v & EHCI_PS_PEC)    i |= UPS_C_PORT_ENABLED;                  if (v & EHCI_PS_PEC)    i |= UPS_C_PORT_ENABLED;
                 if (v & EHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;                  if (v & EHCI_PS_OCC)    i |= UPS_C_OVERCURRENT_INDICATOR;
                 if (sc->sc_isreset[index]) i |= UPS_C_PORT_RESET;                  if (sc->sc_isreset)     i |= UPS_C_PORT_RESET;
                 USETW(ps.wPortChange, i);                  USETW(ps.wPortChange, i);
                 l = min(len, sizeof ps);                  l = min(len, sizeof ps);
                 memcpy(buf, &ps, l);                  memcpy(buf, &ps, l);
Line 1968  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1785  ehci_root_ctrl_start(usbd_xfer_handle xf
                         goto ret;                          goto ret;
                 }                  }
                 port = EHCI_PORTSC(index);                  port = EHCI_PORTSC(index);
                 v = EOREAD4(sc, port);                  v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
                 DPRINTFN(4, ("ehci_root_ctrl_start: portsc=0x%08x\n", v));  
                 v &= ~EHCI_PS_CLEAR;  
                 switch(value) {                  switch(value) {
                 case UHF_PORT_ENABLE:                  case UHF_PORT_ENABLE:
                         EOWRITE4(sc, port, v | EHCI_PS_PE);                          EOWRITE4(sc, port, v | EHCI_PS_PE);
Line 1979  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1794  ehci_root_ctrl_start(usbd_xfer_handle xf
                         EOWRITE4(sc, port, v | EHCI_PS_SUSP);                          EOWRITE4(sc, port, v | EHCI_PS_SUSP);
                         break;                          break;
                 case UHF_PORT_RESET:                  case UHF_PORT_RESET:
                         DPRINTFN(5,("ehci_root_ctrl_start: reset port %d\n",                          DPRINTFN(5,("ehci_root_ctrl_transfer: reset port %d\n",
                                     index));                                      index));
                         if (EHCI_PS_IS_LOWSPEED(v)) {                          if (EHCI_PS_IS_LOWSPEED(v)) {
                                 /* Low speed device, give up ownership. */                                  /* Low speed device, give up ownership. */
Line 2015  ehci_root_ctrl_start(usbd_xfer_handle xf
Line 1830  ehci_root_ctrl_start(usbd_xfer_handle xf
                                 ehci_disown(sc, index, 0);                                  ehci_disown(sc, index, 0);
                                 break;                                  break;
                         }                          }
                         sc->sc_isreset[index] = 1;                          sc->sc_isreset = 1;
                         DPRINTF(("ehci port %d reset, status = 0x%08x\n",                          DPRINTF(("ehci port %d reset, status = 0x%08x\n",
                                  index, v));                                   index, v));
                         break;                          break;
                 case UHF_PORT_POWER:                  case UHF_PORT_POWER:
                         DPRINTFN(2,("ehci_root_ctrl_start: set port power "                          DPRINTFN(2,("ehci_root_ctrl_transfer: set port power "
                                     "%d (has PPC = %d)\n", index,                                      "%d\n", index));
                                     sc->sc_hasppc));                          EOWRITE4(sc, port, v | EHCI_PS_PP);
                         if (sc->sc_hasppc)  
                                 EOWRITE4(sc, port, v | EHCI_PS_PP);  
                         break;                          break;
                 case UHF_PORT_TEST:                  case UHF_PORT_TEST:
                         DPRINTFN(2,("ehci_root_ctrl_start: set port test "                          DPRINTFN(2,("ehci_root_ctrl_transfer: set port test "
                                     "%d\n", index));                                      "%d\n", index));
                         break;                          break;
                 case UHF_PORT_INDICATOR:                  case UHF_PORT_INDICATOR:
                         DPRINTFN(2,("ehci_root_ctrl_start: set port ind "                          DPRINTFN(2,("ehci_root_ctrl_transfer: set port ind "
                                     "%d\n", index));                                      "%d\n", index));
                         EOWRITE4(sc, port, v | EHCI_PS_PIC);                          EOWRITE4(sc, port, v | EHCI_PS_PIC);
                         break;                          break;
Line 2271  ehci_alloc_sqtd_chain(struct ehci_pipe *
Line 2084  ehci_alloc_sqtd_chain(struct ehci_pipe *
         ehci_soft_qtd_t *next, *cur;          ehci_soft_qtd_t *next, *cur;
         ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys;          ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys;
         u_int32_t qtdstatus;          u_int32_t qtdstatus;
         int len, curlen, mps;          int len, curlen;
         int i, tog;          int i;
         usb_dma_t *dma = &xfer->dmabuf;          usb_dma_t *dma = &xfer->dmabuf;
         u_int16_t flags = xfer->flags;  
   
         DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen));          DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen));
   
         len = alen;          len = alen;
         dataphys = DMAADDR(dma, 0);          dataphys = DMAADDR(dma, 0);
         dataphyslastpage = EHCI_PAGE(dataphys + len - 1);          dataphyslastpage = EHCI_PAGE(dataphys + len - 1);
         qtdstatus = EHCI_QTD_ACTIVE |          qtdstatus = htole32(
               EHCI_QTD_ACTIVE |
             EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |              EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
             EHCI_QTD_SET_CERR(3)              EHCI_QTD_SET_CERR(3)
             /* IOC set below */              /* IOC set below */
             /* BYTES set below */              /* BYTES set below */
             ;              /* XXX Data toggle */
         mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);              );
         tog = epipe->nexttoggle;  
         qtdstatus |= EHCI_QTD_SET_TOGGLE(tog);  
   
         cur = ehci_alloc_sqtd(sc);          cur = ehci_alloc_sqtd(sc);
         *sp = cur;          *sp = cur;
Line 2317  ehci_alloc_sqtd_chain(struct ehci_pipe *
Line 2128  ehci_alloc_sqtd_chain(struct ehci_pipe *
                                 curlen = len;                                  curlen = len;
                         }                          }
 #endif  #endif
   
                           /* XXX true for EHCI? */
                         /* the length must be a multiple of the max size */                          /* the length must be a multiple of the max size */
                         curlen -= curlen % mps;                          curlen -= curlen % UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
                         DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, "                          DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, "
                                     "curlen=%d\n", curlen));                                      "curlen=%d\n", curlen));
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                         if (curlen == 0)                          if (curlen == 0)
                                 panic("ehci_alloc_sqtd_chain: curlen == 0");                                  panic("ehci_alloc_std: curlen == 0");
 #endif  #endif
                 }                  }
                 DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x "                  DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x "
Line 2332  ehci_alloc_sqtd_chain(struct ehci_pipe *
Line 2145  ehci_alloc_sqtd_chain(struct ehci_pipe *
                             len, curlen));                              len, curlen));
                 len -= curlen;                  len -= curlen;
   
                 /*                  if (len != 0) {
                  * Allocate another transfer if there's more data left,  
                  * or if force last short transfer flag is set and we're  
                  * allocating a multiple of the max packet size.  
                  */  
                 if (len != 0 ||  
                     ((curlen % mps) == 0 && !rd && curlen != 0 &&  
                      (flags & USBD_FORCE_SHORT_XFER))) {  
                         next = ehci_alloc_sqtd(sc);                          next = ehci_alloc_sqtd(sc);
                         if (next == NULL)                          if (next == NULL)
                                 goto nomem;                                  goto nomem;
                         nextphys = htole32(next->physaddr);                          nextphys = next->physaddr;
                 } else {                  } else {
                         next = NULL;                          next = NULL;
                         nextphys = EHCI_NULL;                          nextphys = EHCI_NULL;
                 }                  }
   
                 for (i = 0; i * EHCI_PAGE_SIZE <                  for (i = 0; i * EHCI_PAGE_SIZE < curlen; i++) {
                             curlen + EHCI_PAGE_OFFSET(dataphys); i++) {  
                         ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE;                          ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE;
                         if (i != 0) /* use offset only in first buffer */                          if (i != 0) /* use offset only in first buffer */
                                 a = EHCI_PAGE(a);                                  a = EHCI_PAGE(a);
Line 2364  ehci_alloc_sqtd_chain(struct ehci_pipe *
Line 2169  ehci_alloc_sqtd_chain(struct ehci_pipe *
 #endif  #endif
                 }                  }
                 cur->nextqtd = next;                  cur->nextqtd = next;
                 cur->qtd.qtd_next = cur->qtd.qtd_altnext = nextphys;                  cur->qtd.qtd_next = cur->qtd.qtd_altnext = htole32(nextphys);
                 cur->qtd.qtd_status =                  cur->qtd.qtd_status =
                     htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen));                      qtdstatus | htole32(EHCI_QTD_SET_BYTES(curlen));
                 cur->xfer = xfer;                  cur->xfer = xfer;
                 cur->len = curlen;                  cur->len = curlen;
                 DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n",                  DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n",
                             dataphys, dataphys + curlen));                              dataphys, dataphys + curlen));
                 /* adjust the toggle based on the number of packets in this                  if (len == 0)
                    qtd */  
                 if (((curlen + mps - 1) / mps) & 1) {  
                         tog ^= 1;  
                         qtdstatus ^= EHCI_QTD_TOGGLE_MASK;  
                 }  
                 if (next == NULL)  
                         break;                          break;
                 DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n"));                  DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n"));
                 dataphys += curlen;                  dataphys += curlen;
Line 2385  ehci_alloc_sqtd_chain(struct ehci_pipe *
Line 2184  ehci_alloc_sqtd_chain(struct ehci_pipe *
         }          }
         cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);          cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
         *ep = cur;          *ep = cur;
         epipe->nexttoggle = tog;  
   
         DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",          DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
                      *sp, *ep));                       *sp, *ep));
Line 2457  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 2255  ehci_abort_xfer(usbd_xfer_handle xfer, u
         u_int32_t qhstatus;          u_int32_t qhstatus;
         int s;          int s;
         int hit;          int hit;
         int wake;  
   
         DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));          DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
   
Line 2475  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 2272  ehci_abort_xfer(usbd_xfer_handle xfer, u
                 panic("ehci_abort_xfer: not in process context");                  panic("ehci_abort_xfer: not in process context");
   
         /*          /*
          * If an abort is already in progress then just wait for it to  
          * complete and return.  
          */  
         if (xfer->hcflags & UXFER_ABORTING) {  
                 DPRINTFN(2, ("ehci_abort_xfer: already aborting\n"));  
 #ifdef DIAGNOSTIC  
                 if (status == USBD_TIMEOUT)  
                         printf("ehci_abort_xfer: TIMEOUT while aborting\n");  
 #endif  
                 /* Override the status which might be USBD_TIMEOUT. */  
                 xfer->status = status;  
                 DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));  
                 xfer->hcflags |= UXFER_ABORTWAIT;  
                 while (xfer->hcflags & UXFER_ABORTING)  
                         tsleep(&xfer->hcflags, PZERO, "ehciaw", 0);  
                 return;  
         }  
         xfer->hcflags |= UXFER_ABORTING;  
   
         /*  
          * Step 1: Make interrupt routine and hardware ignore xfer.           * Step 1: Make interrupt routine and hardware ignore xfer.
          */           */
         s = splusb();          s = splusb();
Line 2516  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 2293  ehci_abort_xfer(usbd_xfer_handle xfer, u
          */           */
         ehci_sync_hc(sc);          ehci_sync_hc(sc);
         s = splusb();          s = splusb();
 #ifdef USB_USE_SOFTINTR  
         sc->sc_softwake = 1;          sc->sc_softwake = 1;
 #endif /* USB_USE_SOFTINTR */  
         usb_schedsoftintr(&sc->sc_bus);          usb_schedsoftintr(&sc->sc_bus);
 #ifdef USB_USE_SOFTINTR  
         tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);          tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
 #endif /* USB_USE_SOFTINTR */  
         splx(s);          splx(s);
   
         /*          /*
Line 2556  ehci_abort_xfer(usbd_xfer_handle xfer, u
Line 2329  ehci_abort_xfer(usbd_xfer_handle xfer, u
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         exfer->isdone = 1;          exfer->isdone = 1;
 #endif  #endif
         wake = xfer->hcflags & UXFER_ABORTWAIT;  
         xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);  
         usb_transfer_complete(xfer);          usb_transfer_complete(xfer);
         if (wake)  
                 wakeup(&xfer->hcflags);  
   
         splx(s);          splx(s);
 #undef exfer  #undef exfer
Line 2705  ehci_device_request(usbd_xfer_handle xfe
Line 2474  ehci_device_request(usbd_xfer_handle xfe
         isread = req->bmRequestType & UT_READ;          isread = req->bmRequestType & UT_READ;
         len = UGETW(req->wLength);          len = UGETW(req->wLength);
   
         DPRINTFN(3,("ehci_device_request: type=0x%02x, request=0x%02x, "          DPRINTFN(3,("ehci_device_control type=0x%02x, request=0x%02x, "
                     "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",                      "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
                     req->bmRequestType, req->bRequest, UGETW(req->wValue),                      req->bmRequestType, req->bRequest, UGETW(req->wValue),
                     UGETW(req->wIndex), len, addr,                      UGETW(req->wIndex), len, addr,
Line 2725  ehci_device_request(usbd_xfer_handle xfe
Line 2494  ehci_device_request(usbd_xfer_handle xfe
         sqh = epipe->sqh;          sqh = epipe->sqh;
         epipe->u.ctl.length = len;          epipe->u.ctl.length = len;
   
         /* Update device address and length since they may have changed          /* XXX
            during the setup of the control pipe in usbd_new_device(). */           * Since we're messing with the QH we must know the HC is in sync.
            * This needs to go away since it slows down control transfers.
            * Removing it entails:
            *  - fill the QH only once with addr & wMaxPacketSize
            *  - put the correct data toggles in the qtds and set DTC
            */
           /* ehci_sync_hc(sc); */
           /* Update device address and length since they may have changed. */
         /* XXX This only needs to be done once, but it's too early in open. */          /* XXX This only needs to be done once, but it's too early in open. */
         /* XXXX Should not touch ED here! */          /* XXXX Should not touch ED here! */
         sqh->qh.qh_endp =          sqh->qh.qh_endp =
             (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) |              (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QG_MPLMASK))) |
             htole32(              htole32(
              EHCI_QH_SET_ADDR(addr) |               EHCI_QH_SET_ADDR(addr) |
                /* EHCI_QH_DTC | */
              EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize))               EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize))
             );              );
           /* Clear toggle */
           sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE);
   
         /* Set up data transaction */          /* Set up data transaction */
         if (len != 0) {          if (len != 0) {
                 ehci_soft_qtd_t *end;                  ehci_soft_qtd_t *end;
   
                 /* Start toggle at 1. */  
                 epipe->nexttoggle = 1;  
                 err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,                  err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
                           &next, &end);                            &next, &end);
                 if (err)                  if (err)
                         goto bad3;                          goto bad3;
                 end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC);  
                 end->nextqtd = stat;                  end->nextqtd = stat;
                 end->qtd.qtd_next =                  end->qtd.qtd_next =
                 end->qtd.qtd_altnext = htole32(stat->physaddr);                  end->qtd.qtd_altnext = htole32(stat->physaddr);
                   /* Start toggle at 1. */
                   /*next->qtd.td_flags |= htole32(EHCI_QTD_TOGGLE);*/
         } else {          } else {
                 next = stat;                  next = stat;
         }          }
   
         memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req);          memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req);
   
         /* Clear toggle */  
         setup->qtd.qtd_status = htole32(          setup->qtd.qtd_status = htole32(
             EHCI_QTD_ACTIVE |              EHCI_QTD_ACTIVE |
             EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |              EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |
             EHCI_QTD_SET_CERR(3) |              EHCI_QTD_SET_CERR(3) |
             EHCI_QTD_SET_TOGGLE(0) |  
             EHCI_QTD_SET_BYTES(sizeof *req)              EHCI_QTD_SET_BYTES(sizeof *req)
             );              );
         setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0));          setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0));
Line 2775  ehci_device_request(usbd_xfer_handle xfe
Line 2551  ehci_device_request(usbd_xfer_handle xfe
             EHCI_QTD_ACTIVE |              EHCI_QTD_ACTIVE |
             EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) |              EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) |
             EHCI_QTD_SET_CERR(3) |              EHCI_QTD_SET_CERR(3) |
             EHCI_QTD_SET_TOGGLE(1) |  
             EHCI_QTD_IOC              EHCI_QTD_IOC
             );              );
         stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */          stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */
Line 2868  ehci_device_bulk_start(usbd_xfer_handle 
Line 2643  ehci_device_bulk_start(usbd_xfer_handle 
         int len, isread, endpt;          int len, isread, endpt;
         int s;          int s;
   
         DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n",          DPRINTFN(2, ("ehci_device_bulk_transfer: xfer=%p len=%d flags=%d\n",
                      xfer, xfer->length, xfer->flags));                       xfer, xfer->length, xfer->flags));
   
         if (sc->sc_dying)          if (sc->sc_dying)
Line 2876  ehci_device_bulk_start(usbd_xfer_handle 
Line 2651  ehci_device_bulk_start(usbd_xfer_handle 
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (xfer->rqflags & URQ_REQUEST)          if (xfer->rqflags & URQ_REQUEST)
                 panic("ehci_device_bulk_start: a request");                  panic("ehci_device_bulk_transfer: a request");
 #endif  #endif
   
         len = xfer->length;          len = xfer->length;
Line 2897  ehci_device_bulk_start(usbd_xfer_handle 
Line 2672  ehci_device_bulk_start(usbd_xfer_handle 
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
         if (ehcidebug > 5) {          if (ehcidebug > 5) {
                 DPRINTF(("ehci_device_bulk_start: data(1)\n"));                  DPRINTF(("ehci_device_bulk_transfer: data(1)\n"));
                 ehci_dump_sqh(sqh);                  ehci_dump_sqh(sqh);
                 ehci_dump_sqtds(data);                  ehci_dump_sqtds(data);
         }          }
Line 2908  ehci_device_bulk_start(usbd_xfer_handle 
Line 2683  ehci_device_bulk_start(usbd_xfer_handle 
         exfer->sqtdend = dataend;          exfer->sqtdend = dataend;
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!exfer->isdone) {          if (!exfer->isdone) {
                 printf("ehci_device_bulk_start: not done, ex=%p\n", exfer);                  printf("ehci_device_bulk_transfer: not done, ex=%p\n", exfer);
         }          }
         exfer->isdone = 0;          exfer->isdone = 0;
 #endif  #endif
Line 2925  ehci_device_bulk_start(usbd_xfer_handle 
Line 2700  ehci_device_bulk_start(usbd_xfer_handle 
   
 #ifdef EHCI_DEBUG  #ifdef EHCI_DEBUG
         if (ehcidebug > 10) {          if (ehcidebug > 10) {
                 DPRINTF(("ehci_device_bulk_start: data(2)\n"));                  DPRINTF(("ehci_device_bulk_transfer: data(2)\n"));
                 delay(10000);                  delay(10000);
                 DPRINTF(("ehci_device_bulk_start: data(3)\n"));                  DPRINTF(("ehci_device_bulk_transfer: data(3)\n"));
                 ehci_dump_regs(sc);                  ehci_dump_regs(sc);
 #if 0  #if 0
                 printf("async_head:\n");                  printf("async_head:\n");
Line 2985  ehci_device_bulk_done(usbd_xfer_handle x
Line 2760  ehci_device_bulk_done(usbd_xfer_handle x
   
 /************************/  /************************/
   
 Static usbd_status  Static usbd_status      ehci_device_intr_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; }
 ehci_device_setintr(ehci_softc_t *sc, ehci_soft_qh_t *sqh, int ival)  Static usbd_status      ehci_device_intr_start(usbd_xfer_handle xfer) { return USBD_IOERROR; }
 {  Static void             ehci_device_intr_abort(usbd_xfer_handle xfer) { }
         struct ehci_soft_islot *isp;  Static void             ehci_device_intr_close(usbd_pipe_handle pipe) { }
         int islot, lev;  Static void             ehci_device_intr_done(usbd_xfer_handle xfer) { }
   
         /* Find a poll rate that is large enough. */  
         for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--)  
                 if (EHCI_ILEV_IVAL(lev) <= ival)  
                         break;  
   
         /* Pick an interrupt slot at the right level. */  
         /* XXX could do better than picking at random */  
         sc->sc_rand = (sc->sc_rand + 191) % sc->sc_flsize;  
         islot = EHCI_IQHIDX(lev, sc->sc_rand);  
   
         sqh->islot = islot;  
         isp = &sc->sc_islots[islot];  
         ehci_add_qh(sqh, isp->sqh);  
   
         return (USBD_NORMAL_COMPLETION);  
 }  
   
 Static usbd_status  
 ehci_device_intr_transfer(usbd_xfer_handle xfer)  
 {  
         usbd_status err;  
   
         /* Insert last in queue. */  
         err = usb_insert_transfer(xfer);  
         if (err)  
                 return (err);  
   
         /*  
          * Pipe isn't running (otherwise err would be USBD_INPROG),  
          * so start it first.  
          */  
         return (ehci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));  
 }  
   
 Static usbd_status  
 ehci_device_intr_start(usbd_xfer_handle xfer)  
 {  
 #define exfer EXFER(xfer)  
         struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;  
         usbd_device_handle dev = xfer->pipe->device;  
         ehci_softc_t *sc = (ehci_softc_t *)dev->bus;  
         ehci_soft_qtd_t *data, *dataend;  
         ehci_soft_qh_t *sqh;  
         usbd_status err;  
         int len, isread, endpt;  
         int s;  
   
         DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n",  
             xfer, xfer->length, xfer->flags));  
   
         if (sc->sc_dying)  
                 return (USBD_IOERROR);  
   
 #ifdef DIAGNOSTIC  
         if (xfer->rqflags & URQ_REQUEST)  
                 panic("ehci_device_intr_start: a request");  
 #endif  
   
         len = xfer->length;  
         endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;  
         isread = UE_GET_DIR(endpt) == UE_DIR_IN;  
         sqh = epipe->sqh;  
   
         epipe->u.intr.length = len;  
   
         err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data,  
             &dataend);  
         if (err) {  
                 DPRINTFN(-1, ("ehci_device_intr_start: no memory\n"));  
                 xfer->status = err;  
                 usb_transfer_complete(xfer);  
                 return (err);  
         }  
   
 #ifdef EHCI_DEBUG  
         if (ehcidebug > 5) {  
                 DPRINTF(("ehci_device_intr_start: data(1)\n"));  
                 ehci_dump_sqh(sqh);  
                 ehci_dump_sqtds(data);  
         }  
 #endif  
   
         /* Set up interrupt info. */  
         exfer->sqtdstart = data;  
         exfer->sqtdend = dataend;  
 #ifdef DIAGNOSTIC  
         if (!exfer->isdone) {  
                 printf("ehci_device_intr_start: not done, ex=%p\n", exfer);  
         }  
         exfer->isdone = 0;  
 #endif  
   
         s = splusb();  
         ehci_set_qh_qtd(sqh, data);  
         if (xfer->timeout && !sc->sc_bus.use_polling) {  
                 usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),  
                     ehci_timeout, xfer);  
         }  
         ehci_add_intr_list(sc, exfer);  
         xfer->status = USBD_IN_PROGRESS;  
         splx(s);  
   
 #ifdef EHCI_DEBUG  
         if (ehcidebug > 10) {  
                 DPRINTF(("ehci_device_intr_start: data(2)\n"));  
                 delay(10000);  
                 DPRINTF(("ehci_device_intr_start: data(3)\n"));  
                 ehci_dump_regs(sc);  
                 printf("sqh:\n");  
                 ehci_dump_sqh(sqh);  
                 ehci_dump_sqtds(data);  
         }  
 #endif  
   
         if (sc->sc_bus.use_polling)  
                 ehci_waitintr(sc, xfer);  
   
         return (USBD_IN_PROGRESS);  
 #undef exfer  
 }  
   
 Static void  
 ehci_device_intr_abort(usbd_xfer_handle xfer)  
 {  
         DPRINTFN(1, ("ehci_device_intr_abort: xfer=%p\n", xfer));  
         if (xfer->pipe->intrxfer == xfer) {  
                 DPRINTFN(1, ("echi_device_intr_abort: remove\n"));  
                 xfer->pipe->intrxfer = NULL;  
         }  
         ehci_abort_xfer(xfer, USBD_CANCELLED);  
 }  
   
 Static void  
 ehci_device_intr_close(usbd_pipe_handle pipe)  
 {  
         ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;  
         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;  
         struct ehci_soft_islot *isp;  
   
         isp = &sc->sc_islots[epipe->sqh->islot];  
         ehci_close_pipe(pipe, isp->sqh);  
 }  
   
 Static void  
 ehci_device_intr_done(usbd_xfer_handle xfer)  
 {  
 #define exfer EXFER(xfer)  
         struct ehci_xfer *ex = EXFER(xfer);  
         ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;  
         struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;  
         ehci_soft_qtd_t *data, *dataend;  
         ehci_soft_qh_t *sqh;  
         usbd_status err;  
         int len, isread, endpt, s;  
   
         DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n",  
             xfer, xfer->actlen));  
   
         if (xfer->pipe->repeat) {  
                 ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);  
   
                 len = epipe->u.intr.length;  
                 xfer->length = len;  
                 endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;  
                 isread = UE_GET_DIR(endpt) == UE_DIR_IN;  
                 sqh = epipe->sqh;  
   
                 err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,  
                     &data, &dataend);  
                 if (err) {  
                         DPRINTFN(-1, ("ehci_device_intr_done: no memory\n"));  
                         xfer->status = err;  
                         return;  
                 }  
   
                 /* Set up interrupt info. */  
                 exfer->sqtdstart = data;  
                 exfer->sqtdend = dataend;  
 #ifdef DIAGNOSTIC  
                 if (!exfer->isdone) {  
                         printf("ehci_device_intr_done: not done, ex=%p\n",  
                             exfer);  
                 }  
                 exfer->isdone = 0;  
 #endif  
   
                 s = splusb();  
                 ehci_set_qh_qtd(sqh, data);  
                 if (xfer->timeout && !sc->sc_bus.use_polling) {  
                         usb_callout(xfer->timeout_handle,  
                             mstohz(xfer->timeout), ehci_timeout, xfer);  
                 }  
                 splx(s);  
   
                 xfer->status = USBD_IN_PROGRESS;  
         } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {  
                 ehci_del_intr_list(ex); /* remove from active list */  
                 ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);  
         }  
 #undef exfer  
 }  
   
 /************************/  /************************/
   

Legend:
Removed from v.1.47.2.9  
changed lines
  Added in v.1.48

CVSweb <webmaster@jp.NetBSD.org>