Project

General

Profile

Bug #1010 » usb.diff

mneumann, 05/19/2008 11:08 AM

View differences:

ehci.c 19 May 2008 11:21:42 -0000
static void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
static usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *,
ehci_softc_t *, int, int, usbd_xfer_handle,
ehci_soft_qtd_t *, ehci_soft_qtd_t *,
ehci_soft_qtd_t **, ehci_soft_qtd_t **);
static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *,
ehci_soft_qtd_t *);
static void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qh_t *,
ehci_soft_qtd_t *, ehci_soft_qtd_t *);
static usbd_status ehci_device_request(usbd_xfer_handle xfer);
......
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 *,
ehci_soft_qh_t *);
static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *);
static void ehci_activate_qh(ehci_soft_qh_t *, ehci_soft_qtd_t *);
static void ehci_sync_hc(ehci_softc_t *);
static void ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *);
......
ehci_device_isoc_done,
};
static usbd_status
ehci_hcreset(ehci_softc_t *sc)
{
u_int32_t hcr;
u_int i;
EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
for (i = 0; i < 100; i++) {
usb_delay_ms(&sc->sc_bus, 1);
hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
if (hcr)
break;
}
if (!hcr)
/*
* Fall through and try reset anyway even though
* Table 2-9 in the EHCI spec says this will result
* in undefined behavior.
*/
kprintf("%s: stop timeout\n",
device_get_nameunit(sc->sc_bus.bdev));
EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
for (i = 0; i < 100; i++) {
usb_delay_ms(&sc->sc_bus, 1);
hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET;
if (!hcr)
return (USBD_NORMAL_COMPLETION);
}
kprintf("%s: reset timeout\n", device_get_nameunit(sc->sc_bus.bdev));
return (USBD_IOERROR);
}
usbd_status
ehci_init(ehci_softc_t *sc)
{
u_int32_t vers, sparams, cparams, hcr;
u_int32_t version, sparams, cparams, hcr;
u_int i;
usbd_status err;
ehci_soft_qh_t *sqh;
......
sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
vers = EREAD2(sc, EHCI_HCIVERSION);
version = EREAD2(sc, EHCI_HCIVERSION);
kprintf("%s: EHCI version %x.%x\n", device_get_nameunit(sc->sc_bus.bdev),
vers >> 8, vers & 0xff);
version >> 8, version & 0xff);
sparams = EREAD4(sc, EHCI_HCSPARAMS);
DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
......
/* Reset the controller */
DPRINTF(("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev)));
EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
usb_delay_ms(&sc->sc_bus, 1);
EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
for (i = 0; i < 100; i++) {
usb_delay_ms(&sc->sc_bus, 1);
hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET;
if (!hcr)
break;
}
if (hcr) {
kprintf("%s: reset timeout\n",
device_get_nameunit(sc->sc_bus.bdev));
return (USBD_IOERROR);
}
err = ehci_hcreset(sc);
if (err != USBD_NORMAL_COMPLETION)
return (err);
/* frame list size at default, read back what we got and use that */
switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) {
......
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++) {
......
/* Fill the overlay qTD */
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;
sqh->qh.qh_qtd.qtd_status = htole32(0);
#ifdef EHCI_DEBUG
if (ehcidebug) {
ehci_dump_sqh(sqh);
......
{
ehci_softc_t *sc = v;
if (sc->sc_dying || (sc->sc_flags & EHCI_SCFLG_DONEINIT) == 0)
if (sc == NULL || sc->sc_dying)
return (0);
/* If we get an interrupt while polling, then just ignore it. */
......
DPRINTFN(20,("ehci_intr1: enter\n"));
/* In case the interrupt occurs before initialization has completed. */
if (sc == NULL) {
#ifdef DIAGNOSTIC
kprintf("ehci_intr1: sc == NULL\n");
#endif
return (0);
}
intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
if (!intrs)
return (0);
......
ehci_pcd_able(sc, 1);
}
/*
* XXX write back xfer data for architectures with a write-back
* data cache; this is a hack because usb is mis-architected
* in blindly mixing bus_dma w/ PIO.
*/
static __inline void
hacksync(usbd_xfer_handle xfer)
{
bus_dma_tag_t tag;
struct usb_dma_mapping *dmap;
if (xfer->length == 0)
return;
tag = xfer->pipe->device->bus->buffer_dmatag;
dmap = &xfer->dmamap;
bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE);
}
void
ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
{
......
pipe = xfer->pipe;
p = KERNADDR(&xfer->dmabuf, 0);
p = xfer->buffer;
m = min(sc->sc_noport, xfer->length * 8 - 1);
memset(p, 0, xfer->length);
for (i = 1; i <= m; i++) {
......
xfer->actlen = xfer->length;
xfer->status = USBD_NORMAL_COMPLETION;
hacksync(xfer); /* XXX to compensate for usb_transfer_complete */
usb_transfer_complete(xfer);
}
......
/* Schedule a callout to catch any dropped transactions. */
if ((sc->sc_flags & EHCI_SCFLG_LOSTINTRBUG) &&
!LIST_EMPTY(&sc->sc_intrhead))
callout_reset(&sc->sc_tmo_intrlist, hz / 5, ehci_intrlist_timeout,
sc);
callout_reset(&sc->sc_tmo_intrlist, hz / 5,
ehci_intrlist_timeout, sc);
#ifdef USB_USE_SOFTINTR
if (sc->sc_softwake) {
......
ehci_idone(struct ehci_xfer *ex)
{
usbd_xfer_handle xfer = &ex->xfer;
#ifdef USB_DEBUG
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
#endif
ehci_soft_qtd_t *sqtd, *lsqtd;
u_int32_t status = 0, nstatus = 0;
ehci_physaddr_t nextphys, altnextphys;
int actlen, cerr;
DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));
......
ehci_dump_sqtds(ex->sqtdstart);
#endif
/*
* Make sure that the QH overlay qTD does not reference any
* of the qTDs we are about to free. This is probably only
* necessary if the transfer is marked as HALTED.
*/
nextphys = EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_next));
altnextphys =
EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_altnext));
for (sqtd = ex->sqtdstart; sqtd != ex->sqtdend->nextqtd;
sqtd = sqtd->nextqtd) {
if (sqtd->physaddr == nextphys) {
epipe->sqh->qh.qh_qtd.qtd_next =
htole32(ex->sqtdend->nextqtd->physaddr);
DPRINTFN(4, ("ehci_idone: updated overlay next ptr\n"));
}
if (sqtd->physaddr == altnextphys) {
DPRINTFN(4,
("ehci_idone: updated overlay altnext ptr\n"));
epipe->sqh->qh.qh_qtd.qtd_altnext =
htole32(ex->sqtdend->nextqtd->physaddr);
}
}
/* The transfer is done, compute actual length and status. */
lsqtd = ex->sqtdend;
actlen = 0;
......
status = nstatus;
/* halt is ok if descriptor is last, and complete */
if (sqtd->qtd.qtd_next == EHCI_NULL &&
EHCI_QTD_GET_BYTES(status) == 0)
if (sqtd == lsqtd && EHCI_QTD_GET_BYTES(status) == 0)
status &= ~EHCI_QTD_HALTED;
if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)
actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
......
sc->sc_dying = 1;
EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
EOWRITE4(sc, EHCI_USBCMD, 0);
EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
(void) ehci_hcreset(sc);
callout_stop(&sc->sc_tmo_intrlist);
callout_stop(&sc->sc_tmo_pcd);
......
switch (why) {
case PWR_SUSPEND:
case PWR_STANDBY:
sc->sc_bus.use_polling++;
for (i = 1; i <= sc->sc_noport; i++) {
......
sc->sc_bus.use_polling--;
break;
case PWR_SOFTSUSPEND:
case PWR_SOFTSTANDBY:
case PWR_SOFTRESUME:
break;
}
crit_exit();
......
ehci_softc_t *sc = v;
DPRINTF(("ehci_shutdown: stopping the HC\n"));
EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
(void) ehci_hcreset(sc);
}
usbd_status
......
}
#endif
} else {
xfer = kmalloc(sizeof(struct ehci_xfer), M_USB, M_INTWAIT);
xfer = kmalloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT);
}
if (xfer != NULL) {
memset(xfer, 0, sizeof(struct ehci_xfer));
......
* debugger.
*/
void
ehci_dump(void)
ehci_dump()
{
ehci_dump_regs(theehci);
}
......
u_int32_t endp, endphub;
kprintf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
kprintf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd);
kprintf(" link="); ehci_dump_link(qh->qh_link, 1); kprintf("\n");
endp = le32toh(qh->qh_endp);
kprintf(" endp=0x%08x\n", endp);
......
EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
);
sqh->qh.qh_curqtd = EHCI_NULL;
/* Fill the overlay qTD */
sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
/* The overlay qTD was already set up by ehci_alloc_sqh(). */
sqh->qh.qh_qtd.qtd_status =
htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
......
ehci_sync_hc(sc);
}
/* Restart a QH following the addition of a qTD. */
void
ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
ehci_activate_qh(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
{
int i;
u_int32_t status;
KASSERT((sqtd->qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) == 0,
("ehci_activate_qh: already active"));
/* 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_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;
/* Set !HALTED && !ACTIVE to start execution, preserve some fields */
sqh->qh.qh_qtd.qtd_status = status;
/*
* When a QH is idle, the overlay qTD should be marked as not
* halted and not active. This causes the host controller to
* retrieve the real qTD on each pass (rather than just examinig
* the overlay), so it will notice when we activate the qTD.
*/
if (sqtd == sqh->sqtd) {
/* Check that the hardware is in the state we expect. */
if (EHCI_LINK_ADDR(le32toh(sqh->qh.qh_qtd.qtd_next)) !=
sqtd->physaddr) {
#ifdef EHCI_DEBUG
kprintf("ehci_activate_qh: unexpected next ptr\n");
ehci_dump_sqh(sqh);
ehci_dump_sqtds(sqh->sqtd);
#endif
sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
}
/* Ensure the flags are correct. */
sqh->qh.qh_qtd.qtd_status &= htole32(EHCI_QTD_PINGSTATE |
EHCI_QTD_TOGGLE_MASK);
}
/* Now activate the qTD. */
sqtd->qtd.qtd_status |= htole32(EHCI_QTD_ACTIVE);
}
/*
......
index = UGETW(req->wIndex);
if (len != 0)
buf = KERNADDR(&xfer->dmabuf, 0);
buf = xfer->buffer;
#define C(x,y) ((x) | ((y) << 8))
switch(C(req->bRequest, req->bmRequestType)) {
......
ret:
xfer->status = err;
crit_enter();
hacksync(xfer); /* XXX to compensate for usb_transfer_complete */
usb_transfer_complete(xfer);
crit_exit();
return (USBD_IN_PROGRESS);
......
ehci_alloc_sqh(ehci_softc_t *sc)
{
ehci_soft_qh_t *sqh;
ehci_soft_qtd_t *sqtd;
usbd_status err;
int i, offs;
usb_dma_t dma;
......
sc->sc_freeqhs = sqh;
}
}
/* Allocate the initial inactive sqtd. */
sqtd = ehci_alloc_sqtd(sc);
if (sqtd == NULL)
return (NULL);
sqtd->qtd.qtd_status = htole32(0);
sqtd->qtd.qtd_next = EHCI_NULL;
sqtd->qtd.qtd_altnext = EHCI_NULL;
sqh = sc->sc_freeqhs;
sc->sc_freeqhs = sqh->next;
memset(&sqh->qh, 0, sizeof(ehci_qh_t));
/* The overlay QTD should begin zeroed. */
sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
sqh->qh.qh_qtd.qtd_status = 0;
for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
sqh->qh.qh_qtd.qtd_buffer[i] = 0;
sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0;
}
sqh->next = NULL;
sqh->prev = NULL;
sqh->sqtd = sqtd;
sqh->inactivesqtd = sqtd;
return (sqh);
}
void
ehci_free_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh)
{
ehci_free_sqtd(sc, sqh->inactivesqtd);
sqh->next = sc->sc_freeqhs;
sc->sc_freeqhs = sqh;
}
......
crit_enter();
sqtd = sc->sc_freeqtds;
sc->sc_freeqtds = sqtd->nextqtd;
memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t));
sqtd->qtd.qtd_next = EHCI_NULL;
sqtd->qtd.qtd_altnext = EHCI_NULL;
sqtd->qtd.qtd_status = 0;
for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
sqtd->qtd.qtd_buffer[i] = 0;
sqtd->qtd.qtd_buffer_hi[i] = 0;
}
sqtd->nextqtd = NULL;
sqtd->xfer = NULL;
crit_exit();
......
usbd_status
ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
int alen, int rd, usbd_xfer_handle xfer,
ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep)
int alen, int rd, usbd_xfer_handle xfer, ehci_soft_qtd_t *start,
ehci_soft_qtd_t *newinactive, ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep)
{
ehci_soft_qtd_t *next, *cur;
ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys;
ehci_physaddr_t dataphys, nextphys;
u_int32_t qtdstatus;
int len, curlen, mps, offset;
int i, iscontrol;
usb_dma_t *dma = &xfer->dmabuf;
int adj, len, curlen, mps, offset, pagelen, seg, segoff;
int i, iscontrol, forceshort;
struct usb_dma_mapping *dma = &xfer->dmamap;
DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen));
......
len = alen;
iscontrol = (epipe->pipe.endpoint->edesc->bmAttributes & UE_XFERTYPE) ==
UE_CONTROL;
dataphys = DMAADDR(dma, 0);
dataphyslastpage = EHCI_PAGE(DMAADDR(dma, len - 1));
qtdstatus = EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
EHCI_QTD_SET_CERR(3)
......
/* BYTES set below */
;
mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
forceshort = ((xfer->flags & USBD_FORCE_SHORT_XFER) || len == 0) &&
len % mps == 0;
/*
* The control transfer data stage always starts with a toggle of 1.
* For other transfers we let the hardware track the toggle state.
......
if (iscontrol)
qtdstatus |= EHCI_QTD_SET_TOGGLE(1);
cur = ehci_alloc_sqtd(sc);
*sp = cur;
if (cur == NULL)
goto nomem;
for (;;) {
dataphyspage = EHCI_PAGE(dataphys);
/* XXX This is pretty broken: Because we do not allocate
* a contiguous buffer (contiguous in physical pages) we
* can only transfer one page in one go.
* So check whether the start and end of the buffer are on
* the same page.
if (start != NULL) {
/*
* If we are given a starting qTD, assume it is linked into
* an active QH so be careful not to mark it active.
*/
if (dataphyspage == dataphyslastpage) {
curlen = len;
cur = start;
*sp = cur;
qtdstatus &= ~EHCI_QTD_ACTIVE;
} else {
cur = ehci_alloc_sqtd(sc);
*sp = cur;
if (cur == NULL)
goto nomem;
}
seg = 0;
segoff = 0;
for (;;) {
curlen = 0;
/* The EHCI hardware can handle at most 5 pages. */
for (i = 0; i < EHCI_QTD_NBUFFERS && curlen < len; i++) {
KASSERT(seg < dma->nsegs,
("ehci_alloc_sqtd_chain: overrun"));
dataphys = dma->segs[seg].ds_addr + segoff;
pagelen = dma->segs[seg].ds_len - segoff;
if (pagelen > len - curlen)
pagelen = len - curlen;
if (pagelen > EHCI_PAGE_SIZE -
EHCI_PAGE_OFFSET(dataphys))
pagelen = EHCI_PAGE_SIZE -
EHCI_PAGE_OFFSET(dataphys);
segoff += pagelen;
if (segoff >= dma->segs[seg].ds_len) {
KASSERT(segoff == dma->segs[seg].ds_len,
("ehci_alloc_sqtd_chain: overlap"));
seg++;
segoff = 0;
}
cur->qtd.qtd_buffer[i] = htole32(dataphys);
cur->qtd.qtd_buffer_hi[i] = 0;
curlen += pagelen;
/*
* Must stop if there is any gap before or after
* the page boundary.
*/
if (EHCI_PAGE_OFFSET(dataphys + pagelen) != 0)
break;
if (seg < dma->nsegs && EHCI_PAGE_OFFSET(segoff +
dma->segs[seg].ds_addr) != 0)
break;
}
else {
/* See comment above (XXX) */
curlen = EHCI_PAGE_SIZE -
EHCI_PAGE_MASK(dataphys);
/* the length must be a multiple of the max size */
curlen -= curlen % mps;
DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, "
"curlen=%d\n", curlen));
KASSERT(curlen != 0, ("ehci_alloc_std: curlen == 0"));
}
DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x "
"dataphyslastpage=0x%08x len=%d curlen=%d\n",
dataphys, dataphyslastpage,
len, curlen));
/* Adjust down to a multiple of mps if not at the end. */
if (curlen < len && curlen % mps != 0) {
adj = curlen % mps;
curlen -= adj;
KASSERT(curlen > 0,
("ehci_alloc_sqtd_chain: need to copy"));
segoff -= adj;
if (segoff < 0) {
seg--;
segoff += dma->segs[seg].ds_len;
}
KASSERT(seg >= 0 && segoff >= 0,
("ehci_alloc_sqtd_chain: adjust to mps"));
}
len -= curlen;
if (len != 0) {
if (len != 0 || forceshort) {
next = ehci_alloc_sqtd(sc);
if (next == NULL)
goto nomem;
......
nextphys = EHCI_NULL;
}
for (i = 0; i * EHCI_PAGE_SIZE < curlen; i++) {
ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE;
if (i != 0) /* use offset only in first buffer */
a = EHCI_PAGE(a);
cur->qtd.qtd_buffer[i] = htole32(a);
cur->qtd.qtd_buffer_hi[i] = 0;
#ifdef DIAGNOSTIC
if (i >= EHCI_QTD_NBUFFERS) {
kprintf("ehci_alloc_sqtd_chain: i=%d\n", i);
goto nomem;
}
#endif
}
cur->nextqtd = next;
cur->qtd.qtd_next = cur->qtd.qtd_altnext = nextphys;
cur->qtd.qtd_next = nextphys;
/* Make sure to stop after a short transfer. */
cur->qtd.qtd_altnext = htole32(newinactive->physaddr);
cur->qtd.qtd_status =
htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen));
cur->xfer = xfer;
cur->len = curlen;
DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n",
dataphys, dataphys + curlen));
DPRINTFN(10,("ehci_alloc_sqtd_chain: curlen=%d\n", curlen));
if (iscontrol) {
/*
* adjust the toggle based on the number of packets
* in this qtd
*/
if (((curlen + mps - 1) / mps) & 1)
if ((((curlen + mps - 1) / mps) & 1) || curlen == 0)
qtdstatus ^= EHCI_QTD_TOGGLE_MASK;
}
if (len == 0)
break;
qtdstatus |= EHCI_QTD_ACTIVE;
if (len == 0) {
if (!forceshort)
break;
forceshort = 0;
}
DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n"));
offset += curlen;
dataphys = DMAADDR(dma, offset);
cur = next;
}
cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
......
return (USBD_NOMEM);
}
/* Free the chain starting at sqtd and end at the qTD before sqtdend */
static void
ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd,
ehci_soft_qtd_t *sqtdend)
ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qh_t *sqh,
ehci_soft_qtd_t *sqtd, ehci_soft_qtd_t *sqtdend)
{
ehci_soft_qtd_t *p;
ehci_soft_qtd_t *p, **prevp;
int i;
DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p sqtdend=%p\n",
sqtd, sqtdend));
/* First unlink the chain from the QH's software qTD list. */
prevp = &sqh->sqtd;
for (p = sqh->sqtd; p != NULL; p = p->nextqtd) {
if (p == sqtd) {
*prevp = sqtdend;
break;
}
prevp = &p->nextqtd;
}
KASSERT(p != NULL, ("ehci_free_sqtd_chain: chain not found"));
for (i = 0; sqtd != sqtdend; sqtd = p, i++) {
p = sqtd->nextqtd;
ehci_free_sqtd(sc, sqtd);
......
* have happened since the hardware runs concurrently.
* If the transaction has already happened we rely on the ordinary
* interrupt processing to process it.
* XXX This is most probably wrong.
*/
void
ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
......
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus;
ehci_soft_qh_t *sqh = epipe->sqh;
ehci_soft_qtd_t *sqtd, *snext, **psqtd;
ehci_soft_qtd_t *sqtd, *snext;
ehci_physaddr_t cur, us, next;
int hit;
int hit, i;
/* int count = 0; */
ehci_soft_qh_t *psqh;
......
/* We will change them to point here */
snext = exfer->sqtdend->nextqtd;
next = snext ? htole32(snext->physaddr) : EHCI_NULL;
next = htole32(snext->physaddr);
/*
* Now loop through any qTDs before us and keep track of the pointer
* that points to us for the end.
*/
psqtd = &sqh->sqtd;
sqtd = sqh->sqtd;
while (sqtd && sqtd != exfer->sqtdstart) {
hit |= (cur == sqtd->physaddr);
......
sqtd->qtd.qtd_next = next;
if (EHCI_LINK_ADDR(le32toh(sqtd->qtd.qtd_altnext)) == us)
sqtd->qtd.qtd_altnext = next;
psqtd = &sqtd->nextqtd;
sqtd = sqtd->nextqtd;
}
/* make the software pointer bypass us too */
*psqtd = exfer->sqtdend->nextqtd;
/*
* If we already saw the active one then we are pretty much done.
......
* (if there is one). We only need to do this if
* it was previously pointing to us.
*/
sqtd = exfer->sqtdstart;
for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
if (cur == sqtd->physaddr) {
hit++;
......
* that we are removing.
*/
if (hit) {
if (snext) {
ehci_set_qh_qtd(sqh, snext);
} else {
sqh->qh.qh_curqtd = 0; /* unlink qTDs */
sqh->qh.qh_qtd.qtd_status &=
htole32(EHCI_QTD_TOGGLE_MASK);
sqh->qh.qh_qtd.qtd_next =
sqh->qh.qh_qtd.qtd_altnext
= EHCI_NULL;
DPRINTFN(1,("ehci_abort_xfer: no hit\n"));
sqh->qh.qh_qtd.qtd_next = htole32(snext->physaddr);
sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
sqh->qh.qh_qtd.qtd_status &=
htole32(EHCI_QTD_TOGGLE_MASK);
for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
sqh->qh.qh_qtd.qtd_buffer[i] = 0;
sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0;
}
}
}
......
{
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;*/
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer));
......
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);
ehci_free_sqtd_chain(sc, epipe->sqh, ex->sqtdstart,
ex->sqtdend->nextqtd);
}
DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen));
......
usb_device_request_t *req = &xfer->request;
usbd_device_handle dev = epipe->pipe.device;
ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
int addr = dev->address;
ehci_soft_qtd_t *setup, *stat, *next;
ehci_soft_qtd_t *newinactive, *setup, *stat, *next;
ehci_soft_qh_t *sqh;
int isread;
int len;
......
DPRINTFN(3,("ehci_device_request: type=0x%02x, request=0x%02x, "
"wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
req->bmRequestType, req->bRequest, UGETW(req->wValue),
UGETW(req->wIndex), len, addr,
UGETW(req->wIndex), len, dev->address,
epipe->pipe.endpoint->edesc->bEndpointAddress));
setup = ehci_alloc_sqtd(sc);
if (setup == NULL) {
newinactive = ehci_alloc_sqtd(sc);
if (newinactive == NULL) {
err = USBD_NOMEM;
goto bad1;
}
newinactive->qtd.qtd_status = htole32(0);
newinactive->qtd.qtd_next = EHCI_NULL;
newinactive->qtd.qtd_altnext = EHCI_NULL;
stat = ehci_alloc_sqtd(sc);
if (stat == NULL) {
err = USBD_NOMEM;
......
}
sqh = epipe->sqh;
setup = sqh->inactivesqtd;
sqh->inactivesqtd = newinactive;
epipe->u.ctl.length = len;
/* Update device address and length since they may have changed
during the setup of the control pipe in usbd_new_device(). */
/* 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_QH_MPLMASK))) |
htole32(
EHCI_QH_SET_ADDR(addr) |
EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize))
);
/* Set up data transaction */
if (len != 0) {
ehci_soft_qtd_t *end;
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
&next, &end);
NULL, newinactive, &next, &end);
if (err)
goto bad3;
end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC);
end->nextqtd = stat;
end->qtd.qtd_next =
end->qtd.qtd_altnext = htole32(stat->physaddr);
end->qtd.qtd_next = htole32(stat->physaddr);
end->qtd.qtd_altnext = htole32(newinactive->physaddr);
} else {
next = stat;
}
memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req);
/* Clear toggle */
/* Clear toggle, and do not activate until complete */
setup->qtd.qtd_status = htole32(
EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |
EHCI_QTD_SET_CERR(3) |
EHCI_QTD_SET_TOGGLE(0) |
......
setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0));
setup->qtd.qtd_buffer_hi[0] = 0;
setup->nextqtd = next;
setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr);
setup->qtd.qtd_next = htole32(next->physaddr);
setup->qtd.qtd_altnext = htole32(newinactive->physaddr);
setup->xfer = xfer;
setup->len = sizeof *req;
......
);
stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */
stat->qtd.qtd_buffer_hi[0] = 0; /* XXX not needed? */
stat->nextqtd = NULL;
stat->qtd.qtd_next = stat->qtd.qtd_altnext = EHCI_NULL;
stat->nextqtd = newinactive;
stat->qtd.qtd_next = htole32(newinactive->physaddr);
stat->qtd.qtd_altnext = htole32(newinactive->physaddr);
stat->xfer = xfer;
stat->len = 0;
......
exfer->isdone = 0;
#endif
/* Insert qTD in QH list. */
/* Activate the new qTD in the QH list. */
crit_enter();
ehci_set_qh_qtd(sqh, setup);
ehci_activate_qh(sqh, setup);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
ehci_timeout, xfer);
......
return (USBD_NORMAL_COMPLETION);
bad3:
sqh->inactivesqtd = setup;
ehci_free_sqtd(sc, stat);
bad2:
ehci_free_sqtd(sc, setup);
ehci_free_sqtd(sc, newinactive);
bad1:
DPRINTFN(-1,("ehci_device_request: no memory\n"));
xfer->status = err;
......
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
usbd_device_handle dev = epipe->pipe.device;
ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
ehci_soft_qtd_t *data, *dataend;
ehci_soft_qtd_t *data, *dataend, *newinactive;
ehci_soft_qh_t *sqh;
usbd_status err;
int len, isread, endpt;
......
epipe->u.bulk.length = len;
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data,
&dataend);
newinactive = ehci_alloc_sqtd(sc);
if (newinactive == NULL) {
DPRINTFN(-1,("ehci_device_bulk_start: no sqtd memory\n"));
err = USBD_NOMEM;
xfer->status = err;
usb_transfer_complete(xfer);
return (err);
}
newinactive->qtd.qtd_status = htole32(0);
newinactive->qtd.qtd_next = EHCI_NULL;
newinactive->qtd.qtd_altnext = EHCI_NULL;
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
sqh->inactivesqtd, newinactive, &data, &dataend);
if (err) {
DPRINTFN(-1,("ehci_device_bulk_start: no memory\n"));
ehci_free_sqtd(sc, newinactive);
xfer->status = err;
usb_transfer_complete(xfer);
return (err);
}
dataend->nextqtd = newinactive;
dataend->qtd.qtd_next = htole32(newinactive->physaddr);
dataend->qtd.qtd_altnext = htole32(newinactive->physaddr);
sqh->inactivesqtd = newinactive;
#ifdef EHCI_DEBUG
if (ehcidebug > 5) {
......
#endif
crit_enter();
ehci_set_qh_qtd(sqh, data);
ehci_activate_qh(sqh, data);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
ehci_timeout, 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;*/
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n",
xfer, xfer->actlen));
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);
ehci_free_sqtd_chain(sc, epipe->sqh, ex->sqtdstart,
ex->sqtdend->nextqtd);
}
DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen));
......
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_qtd_t *data, *dataend, *newinactive;
ehci_soft_qh_t *sqh;
usbd_status err;
int len, isread, endpt;
......
epipe->u.intr.length = len;
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data,
&dataend);
newinactive = ehci_alloc_sqtd(sc);
if (newinactive == NULL) {
DPRINTFN(-1,("ehci_device_intr_start: no sqtd memory\n"));
err = USBD_NOMEM;
xfer->status = err;
usb_transfer_complete(xfer);
return (err);
}
newinactive->qtd.qtd_status = htole32(0);
newinactive->qtd.qtd_next = EHCI_NULL;
newinactive->qtd.qtd_altnext = EHCI_NULL;
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
sqh->inactivesqtd, newinactive, &data, &dataend);
if (err) {
DPRINTFN(-1, ("ehci_device_intr_start: no memory\n"));
xfer->status = err;
usb_transfer_complete(xfer);
return (err);
}
dataend->nextqtd = newinactive;
dataend->qtd.qtd_next = htole32(newinactive->physaddr);
dataend->qtd.qtd_altnext = htole32(newinactive->physaddr);
sqh->inactivesqtd = newinactive;
#ifdef EHCI_DEBUG
if (ehcidebug > 5) {
......
#endif
crit_enter();
ehci_set_qh_qtd(sqh, data);
ehci_activate_qh(sqh, data);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
ehci_timeout, 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_qtd_t *data, *dataend, *newinactive;
ehci_soft_qh_t *sqh;
usbd_status err;
int len, isread, endpt;
......
DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n",
xfer, xfer->actlen));
sqh = epipe->sqh;
if (xfer->pipe->repeat) {
ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
ehci_free_sqtd_chain(sc, sqh, ex->sqtdstart,
ex->sqtdend->nextqtd);
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;
newinactive = ehci_alloc_sqtd(sc);
if (newinactive == NULL) {
DPRINTFN(-1,
("ehci_device_intr_done: no sqtd memory\n"));
err = USBD_NOMEM;
xfer->status = err;
return;
}
newinactive->qtd.qtd_status = htole32(0);
newinactive->qtd.qtd_next = EHCI_NULL;
newinactive->qtd.qtd_altnext = EHCI_NULL;
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
&data, &dataend);
sqh->inactivesqtd, newinactive, &data, &dataend);
if (err) {
DPRINTFN(-1, ("ehci_device_intr_done: no memory\n"));
xfer->status = err;
return;
}
dataend->nextqtd = newinactive;
dataend->qtd.qtd_next = htole32(newinactive->physaddr);
dataend->qtd.qtd_altnext = htole32(newinactive->physaddr);
sqh->inactivesqtd = newinactive;
/* Set up interrupt info. */
exfer->sqtdstart = data;
......
#endif
crit_enter();
ehci_set_qh_qtd(sqh, data);
ehci_activate_qh(sqh, data);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle,
MS_TO_TICKS(xfer->timeout), ehci_timeout, xfer);
......
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);
ehci_free_sqtd_chain(sc, sqh, ex->sqtdstart,
ex->sqtdend->nextqtd);
}
#undef exfer
}
/************************/
static usbd_status
ehci_device_isoc_transfer(usbd_xfer_handle xfer)
{
return USBD_IOERROR;
}
static usbd_status
ehci_device_isoc_start(usbd_xfer_handle xfer)
{
return USBD_IOERROR;
}
static void
ehci_device_isoc_abort(usbd_xfer_handle xfer)
{
}
static void
ehci_device_isoc_close(usbd_pipe_handle pipe)
{
}
static void
ehci_device_isoc_done(usbd_xfer_handle xfer)
{
}
static usbd_status ehci_device_isoc_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; }
static usbd_status ehci_device_isoc_start(usbd_xfer_handle xfer) { return USBD_IOERROR; }
static void ehci_device_isoc_abort(usbd_xfer_handle xfer) { }
static void ehci_device_isoc_close(usbd_pipe_handle pipe) { }
static void ehci_device_isoc_done(usbd_xfer_handle xfer) { }
ehci_pci.c 19 May 2008 10:32:14 -0000
static const char *ehci_device_m5239 = "ALi M5239 USB 2.0 controller";
/* AMD */
#define PCI_EHCI_DEVICEID_8111 0x74631022
#define PCI_EHCI_DEVICEID_8111 0x10227463
#define PCI_EHCI_DEVICEID_CS5536 0x20951022
static const char *ehci_device_8111 = "AMD 8111 USB 2.0 controller";
static const char *ehci_device_CS5536 = "AMD CS5536 USB 2.0 controller";
......
#define PCI_EHCI_DEVICEID_6300 0x25ad8086
static const char *ehci_device_6300 = "Intel 6300ESB USB 2.0 controller";
#define PCI_EHCI_DEVICEID_ICH4 0x24cd8086
static const char *ehci_device_ich4 = "Intel 82801DB/L/M USB 2.0 controller";
static const char *ehci_device_ich4 = "Intel 82801DB/L/M (ICH4) USB 2.0 controller";
#define PCI_EHCI_DEVICEID_ICH5 0x24dd8086
static const char *ehci_device_ich5 = "Intel 82801EB/R USB 2.0 controller";
static const char *ehci_device_ich5 = "Intel 82801EB/R (ICH5) USB 2.0 controller";
#define PCI_EHCI_DEVICEID_ICH6 0x265c8086
static const char *ehci_device_ich6 = "Intel 82801FB USB 2.0 controller";
static const char *ehci_device_ich6 = "Intel 82801FB (ICH6) USB 2.0 controller";
#define PCI_EHCI_DEVICEID_ICH7 0x27cc8086
static const char *ehci_device_ich7 = "Intel 82801GB/R USB 2.0 controller";
static const char *ehci_device_ich7 = "Intel 82801GB/R (ICH7) USB 2.0 controller";
#define PCI_EHCI_DEVICEID_ICH8_A 0x28368086
static const char *ehci_device_ich8_a = "Intel 82801H (ICH8) USB 2.0 controller USB2-A";
#define PCI_EHCI_DEVICEID_ICH8_B 0x283a8086
static const char *ehci_device_ich8_b = "Intel 82801H (ICH8) USB 2.0 controller USB2-B";
#define PCI_EHCI_DEVICEID_ICH9_A 0x293a8086
#define PCI_EHCI_DEVICEID_ICH9_B 0x293c8086
static const char *ehci_device_ich9 = "Intel 82801I (ICH9) USB 2.0 controller";
#define PCI_EHCI_DEVICEID_63XX 0x268c8086
static const char *ehci_device_63XX = "Intel 63XXESB USB 2.0 controller";
/* NEC */
#define PCI_EHCI_DEVICEID_NEC 0x00e01033
......
#define DPRINTF(x)
#endif
static int ehci_pci_attach(device_t self);
static int ehci_pci_detach(device_t self);
static int ehci_pci_shutdown(device_t self);
static int ehci_pci_suspend(device_t self);
static int ehci_pci_resume(device_t self);
static device_attach_t ehci_pci_attach;
static device_detach_t ehci_pci_detach;
static device_shutdown_t ehci_pci_shutdown;
static device_suspend_t ehci_pci_suspend;
static device_resume_t ehci_pci_resume;
static void ehci_pci_givecontroller(device_t self);
static void ehci_pci_takecontroller(device_t self);
......
return (ehci_device_sb400);
case PCI_EHCI_DEVICEID_6300:
return (ehci_device_6300);
case PCI_EHCI_DEVICEID_63XX:
return (ehci_device_63XX);
case PCI_EHCI_DEVICEID_ICH4:
return (ehci_device_ich4);
case PCI_EHCI_DEVICEID_ICH5:
......
return (ehci_device_ich6);
case PCI_EHCI_DEVICEID_ICH7:
return (ehci_device_ich7);
case PCI_EHCI_DEVICEID_ICH8_A:
return (ehci_device_ich8_a);
case PCI_EHCI_DEVICEID_ICH8_B:
return (ehci_device_ich8_b);
case PCI_EHCI_DEVICEID_ICH9_A:
case PCI_EHCI_DEVICEID_ICH9_B:
return (ehci_device_ich9);
case PCI_EHCI_DEVICEID_NEC:
return (ehci_device_nec);
case PCI_EHCI_DEVICEID_NF2:
......
if (desc) {
device_set_desc(self, desc);
device_set_async_attach(self, TRUE);
return 0;
return BUS_PROBE_DEFAULT;
} else {
return ENXIO;
}
......
ehci_pci_attach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
devclass_t dc;
device_t parent;
device_t *neighbors;
device_t *nbus;
......
case PCI_USBREV_1_0:
case PCI_USBREV_1_1:
sc->sc_bus.usbrev = USBREV_UNKNOWN;
kprintf("pre-2.0 USB rev\n");
device_printf(self, "pre-2.0 USB rev\n");
return ENXIO;
case PCI_USBREV_2_0:
sc->sc_bus.usbrev = USBREV_2_0;
......
return ENXIO;
}
ncomp = 0;
dc = devclass_find("usb");
slot = pci_get_slot(self);
function = pci_get_function(self);
for (i = 0; i < count; i++) {
......
pci_get_function(neighbors[i]) < function) {
res = device_get_children(neighbors[i],
&nbus, &buscount);
if (res != 0 || buscount != 1)
if (res != 0)
continue;
bsc = device_get_softc(nbus[0]);
if (bsc == NULL || bsc->bdev == NULL)
if (buscount != 1) {
kfree(nbus, M_TEMP);
continue;
}
if (device_get_devclass(nbus[0]) != dc) {
kfree(nbus, M_TEMP);
continue;
}
bsc = device_get_softc(nbus[0]);
kfree(nbus, M_TEMP);
DPRINTF(("ehci_pci_attach: companion %s\n",
device_get_nameunit(bsc->bdev)));
sc->sc_comps[ncomp++] = bsc;
......
}
sc->sc_ncomp = ncomp;
/* Allocate a parent dma tag for DMA maps */
err = bus_dma_tag_create(/*XXX: bus_get_dma_tag(self)*/NULL, 1, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
&sc->sc_bus.parent_dmatag);
if (err) {
device_printf(self, "Could not allocate parent DMA tag (%d)\n",
err);
ehci_pci_detach(self);
return ENXIO;
}
/* Allocate a dma tag for transfer buffers */
err = bus_dma_tag_create(sc->sc_bus.parent_dmatag, 1, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
&sc->sc_bus.buffer_dmatag);
if (err) {
device_printf(self, "Could not allocate buffer DMA tag (%d)\n",
err);
ehci_pci_detach(self);
return ENXIO;
}
ehci_pci_takecontroller(self);
err = ehci_init(sc);
if (!err) {
......
*/
if (sc->iot && sc->ioh)
bus_space_write_4(sc->iot, sc->ioh, EHCI_USBINTR, 0);
if (sc->sc_bus.parent_dmatag != NULL)
bus_dma_tag_destroy(sc->sc_bus.parent_dmatag);
if (sc->sc_bus.buffer_dmatag != NULL)
bus_dma_tag_destroy(sc->sc_bus.buffer_dmatag);
if (sc->irq_res && sc->ih) {
int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
......
if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
continue;
legsup = eec;
pci_write_config(self, eecp, legsup | EHCI_LEGSUP_OSOWNED, 4);
if (legsup & EHCI_LEGSUP_BIOSOWNED) {
pci_write_config(self, eecp,
legsup | EHCI_LEGSUP_OSOWNED, 4);
kprintf("%s: waiting for BIOS to give up control\n",
device_get_nameunit(sc->sc_bus.bdev));
for (i = 0; i < 5000; i++) {
......
static void
ehci_pci_givecontroller(device_t self)
{
#if 0
ehci_softc_t *sc = device_get_softc(self);
u_int32_t cparams, eec, legsup;
int eecp;
......
legsup = eec;
pci_write_config(self, eecp, legsup & ~EHCI_LEGSUP_OSOWNED, 4);
}
#endif
}
static device_method_t ehci_methods[] = {
ehcivar.h 19 May 2008 10:17:44 -0000
struct ehci_soft_qh *next;
struct ehci_soft_qh *prev;
struct ehci_soft_qtd *sqtd;
struct ehci_soft_qtd *inactivesqtd;
ehci_physaddr_t physaddr;
int islot; /* Interrupt list slot. */
} ehci_soft_qh_t;
......
#define EXFER(xfer) ((struct ehci_xfer *)(xfer))
/* Information about an entry in the interrupt list. */
/*
* Information about an entry in the interrupt list.
*/
struct ehci_soft_islot {
ehci_soft_qh_t *sqh; /* Queue Head. */
};
#define EHCI_FRAMELIST_MAXCOUNT 1024
#define EHCI_IPOLLRATES 8 /* Poll rates (1ms, 2, 4, 8 .. 128) */
#define EHCI_IPOLLRATES 8 /* Poll rates (1ms, 2, 4, 8 ... 128) */
#define EHCI_INTRQHS ((1 << EHCI_IPOLLRATES) - 1)
#define EHCI_MAX_POLLRATE (1 << (EHCI_IPOLLRATES - 1))
#define EHCI_IQHIDX(lev, pos) \
hid.c 18 May 2008 17:51:14 -0000
{
struct hid_data *s;
s = kmalloc(sizeof *s, M_TEMP, M_INTWAIT|M_ZERO);
s = kmalloc(sizeof *s, M_TEMP, M_WAITOK|M_ZERO);
s->start = s->p = d;
s->end = (char *)d + len;
s->kindset = kindset;
......
c->loc.count = dval;
break;
case 10: /* Push */
hi = kmalloc(sizeof *hi, M_TEMP, M_INTWAIT);
hi = kmalloc(sizeof *hi, M_TEMP, M_WAITOK);
*hi = s->cur;
c->next = hi;
break;
ohci.c 19 May 2008 01:15:42 -0000
static usbd_status ohci_device_setintr(ohci_softc_t *sc,
struct ohci_pipe *pipe, int ival);
static usbd_status ohci_device_intr_insert(ohci_softc_t *sc,
usbd_xfer_handle xfer);
static int ohci_str(usb_string_descriptor_t *, int, const char *);
......
int alen, int rd, usbd_xfer_handle xfer,
ohci_soft_td_t *sp, ohci_soft_td_t **ep)
{
ohci_soft_td_t *next, *cur;
ohci_physaddr_t dataphys;
ohci_soft_td_t *next, *cur, *end;
ohci_physaddr_t dataphys, physend;
u_int32_t tdflags;
int offset = 0;
int len, curlen;
usb_dma_t *dma = &xfer->dmabuf;
int len, maxp, curlen, curlen2, seg, segoff;
struct usb_dma_mapping *dma = &xfer->dmamap;
u_int16_t flags = xfer->flags;
DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen));
len = alen;
cur = sp;
end = NULL;
maxp = UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize);
tdflags = htole32(
(rd ? OHCI_TD_IN : OHCI_TD_OUT) |
(flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) |
OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_SET_DI(6));
for (;;) {
seg = 0;
segoff = 0;
while (len > 0) {
next = ohci_alloc_std(sc);
if (next == NULL)
goto nomem;
dataphys = DMAADDR(dma, offset);
/*
* The OHCI hardware can handle at most one 4k crossing.
* XXX - currently we only allocate contigous buffers, but
* the OHCI spec says: If during the data transfer the buffer
* The OHCI spec says: If during the data transfer the buffer
* address contained in the HC's working copy of
* CurrentBufferPointer crosses a 4K boundary, the upper 20
* bits of Buffer End are copied to the working value of
......
* each TD except the last one must cover an exact multiple
* of the maximal packet length.
*/
if (OHCI_PAGE_OFFSET(dataphys) + len <= (2 * OHCI_PAGE_SIZE)) {
/* We can handle all that remains in this TD */
KASSERT(seg < dma->nsegs, ("ohci_alloc_std_chain: overrun"));
dataphys = dma->segs[seg].ds_addr + segoff;
curlen = dma->segs[seg].ds_len - segoff;
if (curlen > len)
curlen = len;
} else {
/* must use multiple TDs, fill as much as possible. */
physend = dataphys + curlen - 1;
if (OHCI_PAGE(dataphys) != OHCI_PAGE(physend)) {
/* Truncate to two OHCI pages if there are more. */
if (curlen > 2 * OHCI_PAGE_SIZE -
OHCI_PAGE_OFFSET(dataphys))
curlen = 2 * OHCI_PAGE_SIZE -
OHCI_PAGE_OFFSET(dataphys);
/* the length must be a multiple of the max size */
curlen -= curlen %
UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize);
KASSERT((curlen != 0), ("ohci_alloc_std: curlen == 0"));
... This diff was truncated because it exceeds the maximum size that can be displayed.
(1-1/2)