NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/42979: Data toggle issues in usb(4), slhci(4), uhci(4) and ehci(4)



The following reply was made to PR kern/42979; it has been noted by GNATS.

From: Yorick Hardy <yorickhardy%gmail.com@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: 
Subject: Re: kern/42979: Data toggle issues in usb(4), slhci(4), uhci(4) and 
ehci(4)
Date: Sat, 24 Apr 2010 07:16:26 +0200

 Updated patch to fix the ohci problem pointed out by
 Jonathan Kollasch on current-users.
 
 -- 
 Kind regards,
 
 Yorick Hardy
 
 Index: sys/dev/ic/sl811hs.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ic/sl811hs.c,v
 retrieving revision 1.25
 diff -u -r1.25 sl811hs.c
 --- sys/dev/ic/sl811hs.c       25 Nov 2009 14:28:50 -0000      1.25
 +++ sys/dev/ic/sl811hs.c       20 Apr 2010 07:23:24 -0000
 @@ -280,7 +280,7 @@
        struct gcq      ap;             /* All pipes */
        struct gcq      to;             /* Timeout list */
        struct gcq      xq;             /* Xfer queues */
 -      unsigned int    pflags;         /* Pipe flags */
 +      unsigned int    *pflags;        /* Pipe flags */
  #define PF_GONE               (0x01)          /* Pipe is on disabled device */
  #define PF_TOGGLE     (0x02)          /* Data toggle status */
  #define PF_LS         (0x04)          /* Pipe is low speed */
 @@ -433,6 +433,7 @@
  void slhci_freem(struct usbd_bus *, usb_dma_t *);
  struct usbd_xfer * slhci_allocx(struct usbd_bus *);
  void slhci_freex(struct usbd_bus *, struct usbd_xfer *);
 +void slhci_clear_all_toggle(struct usbd_bus *, struct usbd_device *);
  
  usbd_status slhci_transfer(struct usbd_xfer *);
  usbd_status slhci_start(struct usbd_xfer *);
 @@ -685,6 +686,7 @@
        slhci_freem,
        slhci_allocx,
        slhci_freex,
 +      slhci_clear_all_toggle,
  };
  
  const struct usbd_pipe_methods slhci_pipe_methods = {
 @@ -849,6 +851,15 @@
        free(xfer, M_USB);
  }
  
 +void slhci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
 +{
 +      struct slhci_softc *sc = bus->hci_private;
 +      int i;
 +
 +      for (i = 0; i < 2*USB_MAX_ENDPOINTS; i++)
 +              sc->pflags[dev->address][i] &= ~PF_TOGGLE;
 +}
 +
  usbd_status
  slhci_transfer(struct usbd_xfer *xfer)
  {
 @@ -923,7 +934,7 @@
        spipe->newlen[1] = min(xfer->length, max_packet);
  
        if (spipe->ptype == PT_BULK || spipe->ptype == PT_INTR) {
 -              if (spipe->pflags & PF_TOGGLE)
 +              if (*(spipe->pflags) & PF_TOGGLE)
                        spipe->control |= SL11_EPCTRL_DATATOGGLE;
                spipe->tregs[LEN] = spipe->newlen[1];
                if (spipe->tregs[LEN]) 
 @@ -971,10 +982,10 @@
         * same place shares constants. Index 0 is "short length" for bulk and 
         * ctrl data and 1 is "full length" for ctrl data (bulk/intr are 
         * already set to full length). */
 -      if (spipe->pflags & PF_LS) {
 +      if (*(spipe->pflags) & PF_LS) {
                /* Setting PREAMBLE for directly connnected LS devices will
                 * lock up the chip. */
 -              if (spipe->pflags & PF_PREAMBLE)
 +              if (*(spipe->pflags) & PF_PREAMBLE)
                        spipe->control |= SL11_EPCTRL_PREAMBLE;
                if (max_packet <= 8) {
                        spipe->bustime = SLHCI_LS_CONST + 
 @@ -1031,6 +1042,7 @@
        usb_endpoint_descriptor_t *ed;
        struct slhci_transfers *t;
        unsigned int max_packet, pmaxpkt;
 +      int epaddr;
  
        dev = pipe->device;
        sc = dev->bus->hci_private;
 @@ -1041,7 +1053,13 @@
        DLOG(D_TRACE, "slhci_open(addr=%d,ep=%d,rootaddr=%d)",
                dev->address, ed->bEndpointAddress, t->rootaddr, 0);
  
 -      spipe->pflags = 0;
 +      epaddr = UE_GET_ADDR(ed->bEndpointAddress);
 +      if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
 +              epaddr += USB_MAX_ENDPOINTS;
 +
 +      spipe->pflags = &(sc->pflags[dev->address][epaddr]);
 +
 +      *(spipe->pflags) &= PF_TOGGLE; /* clear all flags except toggle */
        spipe->frame = 0;
        spipe->lastframe = 0;
        spipe->xfer = NULL;
 @@ -1058,9 +1076,9 @@
        max_packet = UGETW(ed->wMaxPacketSize);
  
        if (dev->speed == USB_SPEED_LOW) {
 -              spipe->pflags |= PF_LS;
 +              *(spipe->pflags) |= PF_LS;
                if (dev->myhub->address != t->rootaddr) {
 -                      spipe->pflags |= PF_PREAMBLE;
 +                      *(spipe->pflags) |= PF_PREAMBLE;
                        if (!slhci_try_lsvh)
                                return slhci_lock_call(sc, &slhci_lsvh_warn, 
                                    spipe, NULL);
 @@ -1291,7 +1309,7 @@
        DLOG(D_TRACE, "%s toggle spipe %p", pnames(spipe->ptype), 
            spipe,0,0);
  
 -      spipe->pflags &= ~PF_TOGGLE;
 +      *(spipe->pflags) &= ~PF_TOGGLE;
  
  #ifdef DIAGNOSTIC
        if (spipe->xfer != NULL) {
 @@ -2085,7 +2103,7 @@
  status_setup:
                        /* CTRL_DATA swaps direction in PID then jumps here */
                        spipe->tregs[LEN] = 0;
 -                      if (spipe->pflags & PF_LS)
 +                      if (*(spipe->pflags) & PF_LS)
                                spipe->bustime = SLHCI_LS_CONST;
                        else
                                spipe->bustime = SLHCI_FS_CONST;
 @@ -2140,9 +2158,9 @@
                         * current setting will apply to the next 
                         * transfer. */ 
                        if (spipe->control & SL11_EPCTRL_DATATOGGLE)
 -                              spipe->pflags |= PF_TOGGLE;
 +                              *(spipe->pflags) |= PF_TOGGLE;
                        else
 -                              spipe->pflags &= ~PF_TOGGLE;
 +                              *(spipe->pflags) &= ~PF_TOGGLE;
  
                        head = Q_CALLBACKS;
                }
 @@ -2373,7 +2391,7 @@
        SLHCI_MAINLOCKASSERT(sc);
  
        if (__predict_false(t->flags & F_DISABLED) || 
 -          __predict_false(spipe->pflags & PF_GONE)) {
 +          __predict_false(*(spipe->pflags) & PF_GONE)) {
                DLOG(D_MSG, "slhci_enter_xfer: DISABLED or GONE", 0,0,0,0);
                spipe->xfer->status = USBD_CANCELLED; 
        }
 @@ -2799,7 +2817,7 @@
        /* Cancel all pipes.  Note that not all of these may be on the 
         * callback queue yet; some could be in slhci_start, for example. */
        FOREACH_AP(q, t, spipe) {
 -              spipe->pflags = PF_GONE;
 +              *(spipe->pflags) = PF_GONE;
                spipe->pipe.repeat = 0;
                spipe->pipe.aborting = 1;
                if (spipe->xfer != NULL)
 @@ -2928,7 +2946,7 @@
        t = &sc->sc_transfers;
        max_packet = UGETW(spipe->pipe.endpoint->edesc->wMaxPacketSize);
  
 -      if (spipe->pflags & PF_LS)
 +      if (*(spipe->pflags) & PF_LS)
                bustime = SLHCI_LS_CONST + SLHCI_LS_DATA_TIME(max_packet);
        else
                bustime = SLHCI_FS_CONST + SLHCI_FS_DATA_TIME(max_packet);
 @@ -3612,7 +3630,7 @@
            "AP" : "", gcq_onlist(&spipe->to) ? "TO" : "", 
            gcq_onlist(&spipe->xq) ? "XQ" : "");
        DDOLOG("spipe: xfer %p buffer %p pflags %#x ptype %s",
 -          spipe->xfer, spipe->buffer, spipe->pflags, pnames(spipe->ptype));
 +          spipe->xfer, spipe->buffer, *(spipe->pflags), pnames(spipe->ptype));
  }
  
  void
 Index: sys/dev/ic/sl811hsvar.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ic/sl811hsvar.h,v
 retrieving revision 1.6
 diff -u -r1.6 sl811hsvar.h
 --- sys/dev/ic/sl811hsvar.h    12 May 2009 14:25:18 -0000      1.6
 +++ sys/dev/ic/sl811hsvar.h    20 Apr 2010 07:23:24 -0000
 @@ -83,6 +83,9 @@
  
        uint8_t                 sc_ier;         /* enabled interrupts */
        uint8_t                 sc_stride;      /* port stride */
 +
 +      /* Pipe flags for each endpoint for each device */
 +      unsigned int            pflags[USB_MAX_DEVICES][2*USB_MAX_ENDPOINTS];
  };
  
  /* last preinit arguments are: max current (in mA, not mA/2), port stride */
 Index: sys/dev/usb/ehci.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/ehci.c,v
 retrieving revision 1.166
 diff -u -r1.166 ehci.c
 --- sys/dev/usb/ehci.c 24 Feb 2010 22:38:09 -0000      1.166
 +++ sys/dev/usb/ehci.c 20 Apr 2010 07:23:25 -0000
 @@ -91,7 +91,6 @@
  
  struct ehci_pipe {
        struct usbd_pipe pipe;
 -      int nexttoggle;
  
        ehci_soft_qh_t *sqh;
        union {
 @@ -120,6 +119,32 @@
        } u;
  };
  
 +#define EHCI_NEXTTOGGLE(epipe) \
 +      ((ehci_softc_t*)((epipe)->pipe.device->bus->hci_private)) \
 +              ->nexttoggle[(epipe)->pipe.device->address]
 +
 +#define EHCI_PIPE_ENDPOINT_ADDR(epipe) \
 +      UE_GET_ADDR((epipe)->pipe.endpoint->edesc->bEndpointAddress)
 +
 +#define EHCI_PIPE_ENDPOINT_DIR(epipe) \
 +      UE_GET_DIR((epipe)->pipe.endpoint->edesc->bEndpointAddress)
 +
 +#define EHCI_NEXTTOGGLE_BIT(epipe) \
 +      ((EHCI_PIPE_ENDPOINT_DIR(epipe) == UE_DIR_OUT) ? \
 +              (0x00000001 << EHCI_PIPE_ENDPOINT_ADDR(epipe)) : \
 +              (0x00010000 << EHCI_PIPE_ENDPOINT_ADDR(epipe)))
 +
 +#define EHCI_NEXTTOGGLE_SET(epipe) \
 +      SET(EHCI_NEXTTOGGLE(epipe), EHCI_NEXTTOGGLE_BIT(epipe))
 +
 +#define EHCI_NEXTTOGGLE_ISSET(epipe) \
 +      ISSET(EHCI_NEXTTOGGLE(epipe), EHCI_NEXTTOGGLE_BIT(epipe))
 +
 +#define EHCI_NEXTTOGGLE_GET(epipe) ((EHCI_NEXTTOGGLE_ISSET(epipe))?1:0)
 +
 +#define EHCI_NEXTTOGGLE_CLR(epipe) \
 +      CLR(EHCI_NEXTTOGGLE(epipe), EHCI_NEXTTOGGLE_BIT(epipe))
 +
  Static usbd_status    ehci_open(usbd_pipe_handle);
  Static void           ehci_poll(struct usbd_bus *);
  Static void           ehci_softintr(void *);
 @@ -139,6 +164,9 @@
  Static usbd_xfer_handle       ehci_allocx(struct usbd_bus *);
  Static void           ehci_freex(struct usbd_bus *, usbd_xfer_handle);
  
 +Static void           ehci_clear_all_toggle(struct usbd_bus *,
 +                                              struct usbd_device *);
 +
  Static usbd_status    ehci_root_ctrl_transfer(usbd_xfer_handle);
  Static usbd_status    ehci_root_ctrl_start(usbd_xfer_handle);
  Static void           ehci_root_ctrl_abort(usbd_xfer_handle);
 @@ -252,6 +280,7 @@
        ehci_freem,
        ehci_allocx,
        ehci_freex,
 +      ehci_clear_all_toggle,
  };
  
  Static const struct usbd_pipe_methods ehci_root_ctrl_methods = {
 @@ -533,6 +562,10 @@
                return (USBD_IOERROR);
        }
  
 +      /* initialize all data toggles to zero */
 +      for (i = 0; i < USB_MAX_DEVICES; i++)
 +              sc->nexttoggle[i] = 0;
 +
        /* Enable interrupts */
        DPRINTFN(1,("ehci_init: enabling\n"));
        EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
 @@ -953,7 +986,10 @@
                ehci_dump_sqh(epipe->sqh);
                ehci_dump_sqtds(ex->sqtdstart);
  #endif
 -              epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus);
 +              if (EHCI_QTD_GET_TOGGLE(nstatus))
 +                      EHCI_NEXTTOGGLE_SET(epipe);
 +              else
 +                      EHCI_NEXTTOGGLE_CLR(epipe);
        }
  
        DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",
 @@ -1318,6 +1354,14 @@
  }
  
  Static void
 +ehci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
 +{
 +      struct ehci_softc *sc = bus->hci_private;
 +
 +      sc->nexttoggle[dev->address] = 0;
 +}
 +
 +Static void
  ehci_device_clear_toggle(usbd_pipe_handle pipe)
  {
        struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
 @@ -1328,7 +1372,7 @@
        if (ehcidebug)
                usbd_dump_pipe(pipe);
  #endif
 -      epipe->nexttoggle = 0;
 +      EHCI_NEXTTOGGLE_CLR(epipe);
  }
  
  Static void
 @@ -1549,8 +1593,6 @@
        if (sc->sc_dying)
                return (USBD_IOERROR);
  
 -      epipe->nexttoggle = 0;
 -
        if (addr == sc->sc_addr) {
                switch (ed->bEndpointAddress) {
                case USB_CONTROL_ENDPOINT:
 @@ -2597,7 +2639,7 @@
            /* BYTES set below */
            ;
        mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
 -      tog = epipe->nexttoggle;
 +      tog = EHCI_NEXTTOGGLE_GET(epipe);
        qtdstatus |= EHCI_QTD_SET_TOGGLE(tog);
  
        cur = ehci_alloc_sqtd(sc);
 @@ -2702,7 +2744,10 @@
        usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd),
            BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        *ep = cur;
 -      epipe->nexttoggle = tog;
 +      if (tog)
 +              EHCI_NEXTTOGGLE_SET(epipe);
 +      else
 +              EHCI_NEXTTOGGLE_CLR(epipe);
  
        DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
                     *sp, *ep));
 @@ -2846,9 +2891,11 @@
        ehci_soft_qtd_t *sqtd;
        ehci_physaddr_t cur;
        u_int32_t qhstatus;
 +      u_int32_t nstatus;
        int s;
        int hit;
        int wake;
 +      int fixdt;
  
        DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
  
 @@ -2902,11 +2949,21 @@
            sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
            sizeof(sqh->qh.qh_qtd.qtd_status),
            BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 -      for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
 +      for (sqtd = exfer->sqtdstart, fixdt = 1; ; sqtd = sqtd->nextqtd) {
                usb_syncmem(&sqtd->dma,
                    sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
                    sizeof(sqtd->qtd.qtd_status),
                    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
 +              nstatus = le32toh(sqtd->qtd.qtd_status);
 +              if (fixdt && (nstatus & EHCI_QTD_ACTIVE)
 +                        && ((sqtd != exfer->sqtdend->nextqtd)
 +                            || EHCI_QTD_GET_BYTES(nstatus))) {
 +                      if (EHCI_QTD_GET_TOGGLE(nstatus))
 +                              EHCI_NEXTTOGGLE_SET(epipe);
 +                      else
 +                              EHCI_NEXTTOGGLE_CLR(epipe);
 +                      fixdt = 0;
 +              }
                sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED);
                usb_syncmem(&sqtd->dma,
                    sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
 @@ -3260,7 +3317,7 @@
                ehci_soft_qtd_t *end;
  
                /* Start toggle at 1. */
 -              epipe->nexttoggle = 1;
 +              EHCI_NEXTTOGGLE_SET(epipe);
                err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
                          &next, &end);
                if (err)
 Index: sys/dev/usb/ehcivar.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/ehcivar.h,v
 retrieving revision 1.36
 diff -u -r1.36 ehcivar.h
 --- sys/dev/usb/ehcivar.h      24 Feb 2010 22:38:09 -0000      1.36
 +++ sys/dev/usb/ehcivar.h      20 Apr 2010 07:23:25 -0000
 @@ -167,6 +167,9 @@
        device_t sc_child; /* /dev/usb# device */
        char sc_dying;
        struct usb_dma_reserve sc_dma_reserve;
 +
 +      /* data toggles for each endpoint of each device */
 +      u_int32_t nexttoggle[USB_MAX_DEVICES];
  } ehci_softc_t;
  
  #define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
 Index: sys/dev/usb/uhci.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/uhci.c,v
 retrieving revision 1.232
 diff -u -r1.232 uhci.c
 --- sys/dev/usb/uhci.c 24 Feb 2010 22:38:09 -0000      1.232
 +++ sys/dev/usb/uhci.c 20 Apr 2010 07:23:26 -0000
 @@ -91,7 +91,6 @@
  
  struct uhci_pipe {
        struct usbd_pipe pipe;
 -      int nexttoggle;
  
        u_char aborting;
        usbd_xfer_handle abortstart, abortend;
 @@ -125,6 +124,32 @@
        } u;
  };
  
 +#define UHCI_NEXTTOGGLE(upipe) \
 +      ((uhci_softc_t*)((upipe)->pipe.device->bus->hci_private)) \
 +              ->nexttoggle[(upipe)->pipe.device->address]
 +
 +#define UHCI_PIPE_ENDPOINT_ADDR(upipe) \
 +      UE_GET_ADDR((upipe)->pipe.endpoint->edesc->bEndpointAddress)
 +
 +#define UHCI_PIPE_ENDPOINT_DIR(upipe) \
 +      UE_GET_DIR((upipe)->pipe.endpoint->edesc->bEndpointAddress)
 +
 +#define UHCI_NEXTTOGGLE_BIT(upipe) \
 +      ((UHCI_PIPE_ENDPOINT_DIR(upipe) == UE_DIR_OUT) ? \
 +              (0x00000001 << UHCI_PIPE_ENDPOINT_ADDR(upipe)) : \
 +              (0x00010000 << UHCI_PIPE_ENDPOINT_ADDR(upipe)))
 +
 +#define UHCI_NEXTTOGGLE_SET(upipe) \
 +      SET(UHCI_NEXTTOGGLE(upipe), UHCI_NEXTTOGGLE_BIT(upipe))
 +
 +#define UHCI_NEXTTOGGLE_ISSET(upipe) \
 +      ISSET(UHCI_NEXTTOGGLE(upipe), UHCI_NEXTTOGGLE_BIT(upipe))
 +
 +#define UHCI_NEXTTOGGLE_GET(upipe) ((UHCI_NEXTTOGGLE_ISSET(upipe))?1:0)
 +
 +#define UHCI_NEXTTOGGLE_CLR(upipe) \
 +      CLR(UHCI_NEXTTOGGLE(upipe), UHCI_NEXTTOGGLE_BIT(upipe))
 +
  Static void           uhci_globalreset(uhci_softc_t *);
  Static usbd_status    uhci_portreset(uhci_softc_t*, int);
  Static void           uhci_reset(uhci_softc_t *);
 @@ -171,6 +196,9 @@
  Static usbd_xfer_handle       uhci_allocx(struct usbd_bus *);
  Static void           uhci_freex(struct usbd_bus *, usbd_xfer_handle);
  
 +Static void           uhci_clear_all_toggle(struct usbd_bus *,
 +                                              struct usbd_device *);
 +
  Static usbd_status    uhci_device_ctrl_transfer(usbd_xfer_handle);
  Static usbd_status    uhci_device_ctrl_start(usbd_xfer_handle);
  Static void           uhci_device_ctrl_abort(usbd_xfer_handle);
 @@ -287,6 +315,7 @@
        uhci_freem,
        uhci_allocx,
        uhci_freex,
 +      uhci_clear_all_toggle,
  };
  
  const struct usbd_pipe_methods uhci_root_ctrl_methods = {
 @@ -529,6 +558,10 @@
  
        UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */
  
 +      /* initialize all data toggles to zero */
 +      for (i = 0; i < USB_MAX_DEVICES; i++)
 +              sc->nexttoggle[i] = 0;
 +
        DPRINTFN(1,("uhci_init: enabling\n"));
  
        err =  uhci_run(sc, 1);         /* and here we go... */
 @@ -683,6 +716,14 @@
        SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
  }
  
 +Static void
 +uhci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
 +{
 +      struct uhci_softc *sc = bus->hci_private;
 +
 +      sc->nexttoggle[dev->address] = 0;
 +}
 +
  /*
   * Handle suspend/resume.
   *
 @@ -1564,8 +1605,12 @@
                }
        }
        /* If there are left over TDs we need to update the toggle. */
 -      if (std != NULL)
 -              upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token));
 +      if (std != NULL) {
 +              if (UHCI_TD_GET_DT(le32toh(std->td.td_token)))
 +                      UHCI_NEXTTOGGLE_SET(upipe);
 +              else
 +                      UHCI_NEXTTOGGLE_CLR(upipe);
 +      }
  
        status &= UHCI_TD_ERROR;
        DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n",
 @@ -1884,10 +1929,13 @@
                DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n"));
                return (USBD_NORMAL_COMPLETION);
        }
 -      tog = upipe->nexttoggle;
 +      tog = UHCI_NEXTTOGGLE_GET(upipe);
        if (ntd % 2 == 0)
                tog ^= 1;
 -      upipe->nexttoggle = tog ^ 1;
 +      if (tog ^ 1)
 +              UHCI_NEXTTOGGLE_SET(upipe);
 +      else
 +              UHCI_NEXTTOGGLE_CLR(upipe);
        lastp = NULL;
        lastlink = UHCI_PTR_T;
        ntd--;
 @@ -1928,7 +1976,7 @@
        }
        *sp = lastp;
        DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",
 -                    upipe->nexttoggle));
 +                    UHCI_NEXTTOGGLE_GET(upipe)));
        return (USBD_NORMAL_COMPLETION);
  }
  
 @@ -1936,7 +1984,7 @@
  uhci_device_clear_toggle(usbd_pipe_handle pipe)
  {
        struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
 -      upipe->nexttoggle = 0;
 +      UHCI_NEXTTOGGLE_CLR(upipe);
  }
  
  void
 @@ -2077,6 +2125,7 @@
        uhci_soft_td_t *std;
        int s;
        int wake;
 +      int fixdt;
  
        DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
  
 @@ -2120,11 +2169,18 @@
        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) {
 +      for (std = ii->stdstart, fixdt = 1; std != NULL; std = std->link.std) {
                usb_syncmem(&std->dma,
                    std->offs + offsetof(uhci_td_t, td_status),
                    sizeof(std->td.td_status),
                    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
 +              if (fixdt && (le32toh(std->td.td_status) & UHCI_TD_ACTIVE)) {
 +                      if (UHCI_TD_GET_DT(le32toh(std->td.td_token)))
 +                              UHCI_NEXTTOGGLE_SET(upipe);
 +                      else
 +                              UHCI_NEXTTOGGLE_CLR(upipe);
 +                      fixdt = 0;
 +              }
                std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
                usb_syncmem(&std->dma,
                    std->offs + offsetof(uhci_td_t, td_status),
 @@ -2409,7 +2465,7 @@
  
        /* Set up data transaction */
        if (len != 0) {
 -              upipe->nexttoggle = 1;
 +              UHCI_NEXTTOGGLE_SET(upipe);
                err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
                                           &xfer->dmabuf, &data, &dataend);
                if (err)
 @@ -3183,7 +3239,6 @@
                     ed->bEndpointAddress, sc->sc_addr));
  
        upipe->aborting = 0;
 -      upipe->nexttoggle = 0;
  
        if (pipe->device->address == sc->sc_addr) {
                switch (ed->bEndpointAddress) {
 Index: sys/dev/usb/uhcivar.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/uhcivar.h,v
 retrieving revision 1.47
 diff -u -r1.47 uhcivar.h
 --- sys/dev/usb/uhcivar.h      24 Feb 2010 22:38:09 -0000      1.47
 +++ sys/dev/usb/uhcivar.h      20 Apr 2010 07:23:26 -0000
 @@ -181,6 +181,8 @@
  #ifdef __NetBSD__
        struct usb_dma_reserve sc_dma_reserve;
  #endif
 +      /* data toggles for each endpoint of each device */
 +      u_int32_t nexttoggle[USB_MAX_DEVICES];
  } uhci_softc_t;
  
  usbd_status   uhci_init(uhci_softc_t *);
 Index: sys/dev/usb/usb_subr.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/usb_subr.c,v
 retrieving revision 1.167
 diff -u -r1.167 usb_subr.c
 --- sys/dev/usb/usb_subr.c     12 Nov 2009 20:11:35 -0000      1.167
 +++ sys/dev/usb/usb_subr.c     20 Apr 2010 07:23:26 -0000
 @@ -698,6 +698,9 @@
                }
        }
  
 +      /* this is a configuration event, so reset all data toggles */
 +      dev->bus->methods->clear_all_toggle(dev->bus, dev);
 +
        return (USBD_NORMAL_COMPLETION);
  
   bad:
 Index: sys/dev/usb/usbdi.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/usbdi.c,v
 retrieving revision 1.127
 diff -u -r1.127 usbdi.c
 --- sys/dev/usb/usbdi.c        16 Jan 2010 17:03:03 -0000      1.127
 +++ sys/dev/usb/usbdi.c        20 Apr 2010 07:23:31 -0000
 @@ -669,7 +669,14 @@
        USETW(req.wValue, iface->idesc->bAlternateSetting);
        USETW(req.wIndex, iface->idesc->bInterfaceNumber);
        USETW(req.wLength, 0);
 -      return (usbd_do_request(iface->device, &req, 0));
 +      err = usbd_do_request(iface->device, &req, 0);
 +
 +      /* this is a configuration event, so reset all data toggles */
 +      if (!err)
 +              iface->device->bus->methods
 +                      ->clear_all_toggle(iface->device->bus, iface->device);
 +
 +      return err;
  }
  
  int
 Index: sys/dev/usb/usbdivar.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/usbdivar.h,v
 retrieving revision 1.91
 diff -u -r1.91 usbdivar.h
 --- sys/dev/usb/usbdivar.h     12 Nov 2009 20:11:35 -0000      1.91
 +++ sys/dev/usb/usbdivar.h     20 Apr 2010 07:23:31 -0000
 @@ -57,6 +57,8 @@
        void                  (*freem)(struct usbd_bus *, usb_dma_t *);
        struct usbd_xfer *    (*allocx)(struct usbd_bus *);
        void                  (*freex)(struct usbd_bus *, struct usbd_xfer *);
 +      void                  (*clear_all_toggle)(struct usbd_bus *,
 +                                                      struct usbd_device *);
  };
  
  struct usbd_pipe_methods {
 Index: ./sys/dev/usb/ohci.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/usb/ohci.c,v
 retrieving revision 1.206
 diff -u -r1.206 ohci.c
 --- ./sys/dev/usb/ohci.c       24 Feb 2010 22:38:09 -0000      1.206
 +++ ./sys/dev/usb/ohci.c       24 Apr 2010 05:11:38 -0000
 @@ -134,6 +134,9 @@
  Static usbd_xfer_handle       ohci_allocx(struct usbd_bus *);
  Static void           ohci_freex(struct usbd_bus *, usbd_xfer_handle);
  
 +Static void           ohci_clear_all_toggle(struct usbd_bus *,
 +                                              struct usbd_device *);
 +
  Static usbd_status    ohci_root_ctrl_transfer(usbd_xfer_handle);
  Static usbd_status    ohci_root_ctrl_start(usbd_xfer_handle);
  Static void           ohci_root_ctrl_abort(usbd_xfer_handle);
 @@ -273,6 +276,7 @@
        ohci_freem,
        ohci_allocx,
        ohci_freex,
 +      ohci_clear_all_toggle,
  };
  
  Static const struct usbd_pipe_methods ohci_root_ctrl_methods = {
 @@ -983,6 +987,18 @@
        SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
  }
  
 +Static void
 +ohci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
 +{
 +      struct ohci_softc *sc = bus->hci_private;
 +      struct ohci_soft_ed *ed = sc->sc_bulk_head;
 +      while (ed != NULL) {
 +              if (OHCI_ED_GET_FA(ed->ed.ed_flags) == dev->address)
 +                      ed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY);
 +              ed = ed->next;
 +      }
 +}
 +
  /*
   * Shut down the controller when the system is going down.
   */
 


Home | Main Index | Thread Index | Old Index