Set the data toggle correctly, and use EHCI_QTD_DTC. This fixes problems with
my ALi-based drive enclosure (it works now, rather than failing to attach). Also seems to work with a GL811-based enclosure and an ASUS enclosure with a CD-RW, on both Intel and NEC controllers. Note: The ALi enclosure is currently very SLOW, due to some issue with taking too long to notice that the QTD is complete. This requires more investigation.
This commit is contained in:
parent
3cc9c970a3
commit
46d9c14fee
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ehci.c,v 1.54 2004/01/17 13:15:05 jdolecek Exp $ */
|
||||
/* $NetBSD: ehci.c,v 1.55 2004/06/22 05:25:10 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
@ -69,7 +69,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.54 2004/01/17 13:15:05 jdolecek Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.55 2004/06/22 05:25:10 mycroft Exp $");
|
||||
|
||||
#include "ohci.h"
|
||||
#include "uhci.h"
|
||||
@ -109,6 +109,8 @@ int ehcidebug = 0;
|
||||
|
||||
struct ehci_pipe {
|
||||
struct usbd_pipe pipe;
|
||||
int nexttoggle;
|
||||
|
||||
ehci_soft_qh_t *sqh;
|
||||
union {
|
||||
ehci_soft_qtd_t *qtd;
|
||||
@ -748,9 +750,7 @@ ehci_idone(struct ehci_xfer *ex)
|
||||
if (sqtd != NULL) {
|
||||
if (!(xfer->rqflags & URQ_REQUEST))
|
||||
printf("ehci_idone: need toggle update\n");
|
||||
#if 0
|
||||
epipe->nexttoggle = EHCI_TD_GET_DT(le32toh(std->td.td_token));
|
||||
#endif
|
||||
epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(status);
|
||||
}
|
||||
|
||||
status &= EHCI_QTD_STATERRS;
|
||||
@ -1058,7 +1058,7 @@ ehci_device_clear_toggle(usbd_pipe_handle pipe)
|
||||
if (ehcidebug)
|
||||
usbd_dump_pipe(pipe);
|
||||
#endif
|
||||
epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE);
|
||||
epipe->nexttoggle = 0;
|
||||
}
|
||||
|
||||
Static void
|
||||
@ -1217,6 +1217,8 @@ ehci_open(usbd_pipe_handle pipe)
|
||||
if (sc->sc_dying)
|
||||
return (USBD_IOERROR);
|
||||
|
||||
epipe->nexttoggle = 0;
|
||||
|
||||
if (addr == sc->sc_addr) {
|
||||
switch (ed->bEndpointAddress) {
|
||||
case USB_CONTROL_ENDPOINT:
|
||||
@ -1246,8 +1248,8 @@ ehci_open(usbd_pipe_handle pipe)
|
||||
sqh->qh.qh_endp = htole32(
|
||||
EHCI_QH_SET_ADDR(addr) |
|
||||
EHCI_QH_SET_ENDPT(ed->bEndpointAddress) |
|
||||
EHCI_QH_SET_EPS(speed) | /* XXX */
|
||||
/* XXX EHCI_QH_DTC ? */
|
||||
EHCI_QH_SET_EPS(speed) |
|
||||
EHCI_QH_DTC |
|
||||
EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
|
||||
(speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
|
||||
EHCI_QH_CTL : 0) |
|
||||
@ -2100,8 +2102,8 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
|
||||
ehci_soft_qtd_t *next, *cur;
|
||||
ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys;
|
||||
u_int32_t qtdstatus;
|
||||
int len, curlen;
|
||||
int i;
|
||||
int len, curlen, mps;
|
||||
int i, tog;
|
||||
usb_dma_t *dma = &xfer->dmabuf;
|
||||
|
||||
DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen));
|
||||
@ -2109,14 +2111,21 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
|
||||
len = alen;
|
||||
dataphys = DMAADDR(dma, 0);
|
||||
dataphyslastpage = EHCI_PAGE(dataphys + len - 1);
|
||||
#if 0
|
||||
printf("status=%08x toggle=%d\n", epipe->sqh->qh.qh_qtd.qtd_status,
|
||||
epipe->nexttoggle);
|
||||
#endif
|
||||
qtdstatus = htole32(
|
||||
EHCI_QTD_ACTIVE |
|
||||
EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
|
||||
EHCI_QTD_SET_CERR(3)
|
||||
/* IOC set below */
|
||||
/* BYTES set below */
|
||||
/* XXX Data toggle */
|
||||
);
|
||||
mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
|
||||
tog = epipe->nexttoggle;
|
||||
if (tog)
|
||||
qtdstatus |= EHCI_QTD_TOGGLE;
|
||||
|
||||
cur = ehci_alloc_sqtd(sc);
|
||||
*sp = cur;
|
||||
@ -2144,10 +2153,8 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
|
||||
curlen = len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX true for EHCI? */
|
||||
/* the length must be a multiple of the max size */
|
||||
curlen -= curlen % UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
|
||||
curlen -= curlen % mps;
|
||||
DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, "
|
||||
"curlen=%d\n", curlen));
|
||||
#ifdef DIAGNOSTIC
|
||||
@ -2192,6 +2199,12 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
|
||||
cur->len = curlen;
|
||||
DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n",
|
||||
dataphys, dataphys + curlen));
|
||||
/* adjust the toggle based on the number of packets in this
|
||||
qtd */
|
||||
if (((curlen + mps - 1) / mps) & 1) {
|
||||
tog ^= 1;
|
||||
qtdstatus ^= EHCI_QTD_TOGGLE;
|
||||
}
|
||||
if (len == 0)
|
||||
break;
|
||||
DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n"));
|
||||
@ -2200,6 +2213,7 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
|
||||
}
|
||||
cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
|
||||
*ep = cur;
|
||||
epipe->nexttoggle = tog;
|
||||
|
||||
DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
|
||||
*sp, *ep));
|
||||
@ -2515,26 +2529,24 @@ ehci_device_request(usbd_xfer_handle xfer)
|
||||
* 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. */
|
||||
/* XXXX Should not touch ED here! */
|
||||
sqh->qh.qh_endp =
|
||||
(sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QG_MPLMASK))) |
|
||||
(sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) |
|
||||
htole32(
|
||||
EHCI_QH_SET_ADDR(addr) |
|
||||
/* EHCI_QH_DTC | */
|
||||
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 */
|
||||
if (len != 0) {
|
||||
ehci_soft_qtd_t *end;
|
||||
|
||||
/* Start toggle at 1. */
|
||||
epipe->nexttoggle = 1;
|
||||
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
|
||||
&next, &end);
|
||||
if (err)
|
||||
@ -2542,14 +2554,14 @@ ehci_device_request(usbd_xfer_handle xfer)
|
||||
end->nextqtd = stat;
|
||||
end->qtd.qtd_next =
|
||||
end->qtd.qtd_altnext = htole32(stat->physaddr);
|
||||
/* Start toggle at 1. */
|
||||
/*next->qtd.td_flags |= htole32(EHCI_QTD_TOGGLE);*/
|
||||
} else {
|
||||
next = stat;
|
||||
}
|
||||
|
||||
memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req);
|
||||
|
||||
/* Clear toggle */
|
||||
sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE);
|
||||
setup->qtd.qtd_status = htole32(
|
||||
EHCI_QTD_ACTIVE |
|
||||
EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |
|
||||
@ -2567,6 +2579,7 @@ ehci_device_request(usbd_xfer_handle xfer)
|
||||
EHCI_QTD_ACTIVE |
|
||||
EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) |
|
||||
EHCI_QTD_SET_CERR(3) |
|
||||
EHCI_QTD_TOGGLE |
|
||||
EHCI_QTD_IOC
|
||||
);
|
||||
stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ehcireg.h,v 1.15 2004/06/12 16:02:42 mycroft Exp $ */
|
||||
/* $NetBSD: ehcireg.h,v 1.16 2004/06/22 05:25:10 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
@ -257,7 +257,7 @@ typedef struct {
|
||||
#define EHCI_QH_HRECL 0x00008000
|
||||
#define EHCI_QH_GET_MPL(x) (((x) >> 16) & 0x7ff) /* max packet len */
|
||||
#define EHCI_QH_SET_MPL(x) ((x) << 16)
|
||||
#define EHCI_QG_MPLMASK 0x07ff0000
|
||||
#define EHCI_QH_MPLMASK 0x07ff0000
|
||||
#define EHCI_QH_GET_CTL(x) (((x) >> 27) & 0x01) /* control endpoint */
|
||||
#define EHCI_QH_CTL 0x08000000
|
||||
#define EHCI_QH_GET_NRL(x) (((x) >> 28) & 0x0f) /* NAK reload */
|
||||
|
Loading…
Reference in New Issue
Block a user