summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/ohci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/ohci.c')
-rw-r--r--sys/dev/usb/ohci.c510
1 files changed, 324 insertions, 186 deletions
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 90f638a..aa21238 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,5 +1,5 @@
-/* $NetBSD: ohci.c,v 1.12 1998/11/30 21:39:20 augustss Exp $ */
-/* FreeBSD $Id: ohci.c,v 1.4 1998/12/14 09:32:23 n_hibma Exp $ */
+/* $NetBSD: ohci.c,v 1.21 1999/01/01 15:15:33 augustss Exp $ */
+/* FreeBSD $Id$ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -45,8 +45,6 @@
* USB spec: http://www.teleport.com/cgi-bin/mailmerge.cgi/~usb/cgiform.tpl
*/
-#include <dev/usb/usb_port.h>
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -62,6 +60,7 @@
#include <sys/select.h>
#include <machine/bus.h>
+#include <machine/endian.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -74,12 +73,21 @@
#if defined(__FreeBSD__)
#include <machine/clock.h>
-#include "dev/usb/queue.addendum.h"
#define delay(d) DELAY(d)
#endif
+/*
+ * The OHCI controller is little endian, so on big endian machines
+ * the data strored in memory needs to be swapped.
+ */
+#if BYTE_ORDER == BIG_ENDIAN
+#define LE(x) (bswap32(x))
+#else
+#define LE(x) (x)
+#endif
+
struct ohci_pipe;
ohci_soft_ed_t *ohci_alloc_sed __P((ohci_softc_t *));
@@ -93,6 +101,7 @@ void ohci_poll __P((struct usbd_bus *));
void ohci_waitintr __P((ohci_softc_t *, usbd_request_handle));
void ohci_rhsc __P((ohci_softc_t *, usbd_request_handle));
void ohci_process_done __P((ohci_softc_t *, ohci_physaddr_t));
+void ohci_ii_done __P((ohci_softc_t *, usbd_request_handle));
void ohci_ctrl_done __P((ohci_softc_t *, usbd_request_handle));
void ohci_intr_done __P((ohci_softc_t *, usbd_request_handle));
void ohci_bulk_done __P((ohci_softc_t *, usbd_request_handle));
@@ -105,22 +114,27 @@ void ohci_hash_rem_td __P((ohci_softc_t *, ohci_soft_td_t *));
ohci_soft_td_t *ohci_hash_find_td __P((ohci_softc_t *, ohci_physaddr_t));
usbd_status ohci_root_ctrl_transfer __P((usbd_request_handle));
+usbd_status ohci_root_ctrl_start __P((usbd_request_handle));
void ohci_root_ctrl_abort __P((usbd_request_handle));
void ohci_root_ctrl_close __P((usbd_pipe_handle));
usbd_status ohci_root_intr_transfer __P((usbd_request_handle));
+usbd_status ohci_root_intr_start __P((usbd_request_handle));
void ohci_root_intr_abort __P((usbd_request_handle));
void ohci_root_intr_close __P((usbd_pipe_handle));
usbd_status ohci_device_ctrl_transfer __P((usbd_request_handle));
+usbd_status ohci_device_ctrl_start __P((usbd_request_handle));
void ohci_device_ctrl_abort __P((usbd_request_handle));
void ohci_device_ctrl_close __P((usbd_pipe_handle));
usbd_status ohci_device_bulk_transfer __P((usbd_request_handle));
+usbd_status ohci_device_bulk_start __P((usbd_request_handle));
void ohci_device_bulk_abort __P((usbd_request_handle));
void ohci_device_bulk_close __P((usbd_pipe_handle));
usbd_status ohci_device_intr_transfer __P((usbd_request_handle));
+usbd_status ohci_device_intr_start __P((usbd_request_handle));
void ohci_device_intr_abort __P((usbd_request_handle));
void ohci_device_intr_close __P((usbd_pipe_handle));
usbd_status ohci_device_setintr __P((ohci_softc_t *sc,
@@ -187,6 +201,7 @@ struct ohci_pipe {
struct usbd_methods ohci_root_ctrl_methods = {
ohci_root_ctrl_transfer,
+ ohci_root_ctrl_start,
ohci_root_ctrl_abort,
ohci_root_ctrl_close,
0,
@@ -194,6 +209,7 @@ struct usbd_methods ohci_root_ctrl_methods = {
struct usbd_methods ohci_root_intr_methods = {
ohci_root_intr_transfer,
+ ohci_root_intr_start,
ohci_root_intr_abort,
ohci_root_intr_close,
0,
@@ -201,6 +217,7 @@ struct usbd_methods ohci_root_intr_methods = {
struct usbd_methods ohci_device_ctrl_methods = {
ohci_device_ctrl_transfer,
+ ohci_device_ctrl_start,
ohci_device_ctrl_abort,
ohci_device_ctrl_close,
0,
@@ -208,12 +225,14 @@ struct usbd_methods ohci_device_ctrl_methods = {
struct usbd_methods ohci_device_intr_methods = {
ohci_device_intr_transfer,
+ ohci_device_intr_start,
ohci_device_intr_abort,
ohci_device_intr_close,
};
struct usbd_methods ohci_device_bulk_methods = {
ohci_device_bulk_transfer,
+ ohci_device_bulk_start,
ohci_device_bulk_abort,
ohci_device_bulk_close,
0,
@@ -323,11 +342,12 @@ ohci_init(sc)
DPRINTF(("ohci_init: start\n"));
rev = OREAD4(sc, OHCI_REVISION);
- DEVICE_MSG(sc->sc_bus.bdev, ("OHCI version %d.%d%s\n",
+ printf("%s: OHCI version %d.%d%s\n", USBDEVNAME(sc->sc_bus.bdev),
OHCI_REV_HI(rev), OHCI_REV_LO(rev),
- OHCI_REV_LEGACY(rev) ? ", legacy support" : ""));
+ OHCI_REV_LEGACY(rev) ? ", legacy support" : "");
if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) {
- DEVICE_MSG(sc->sc_bus.bdev, ("unsupported OHCI revision\n"));
+ printf("%s: unsupported OHCI revision\n",
+ USBDEVNAME(sc->sc_bus.bdev));
return (USBD_INVAL);
}
@@ -349,13 +369,13 @@ ohci_init(sc)
r = USBD_NOMEM;
goto bad1;
}
- sc->sc_ctrl_head->ed->ed_flags |= OHCI_ED_SKIP;
+ sc->sc_ctrl_head->ed->ed_flags |= LE(OHCI_ED_SKIP);
sc->sc_bulk_head = ohci_alloc_sed(sc);
if (!sc->sc_bulk_head) {
r = USBD_NOMEM;
goto bad2;
}
- sc->sc_bulk_head->ed->ed_flags |= OHCI_ED_SKIP;
+ sc->sc_bulk_head->ed->ed_flags |= LE(OHCI_ED_SKIP);
/* Allocate all the dummy EDs that make up the interrupt tree. */
for (i = 0; i < OHCI_NO_EDS; i++) {
@@ -368,11 +388,11 @@ ohci_init(sc)
}
/* All ED fields are set to 0. */
sc->sc_eds[i] = sed;
- sed->ed->ed_flags |= OHCI_ED_SKIP;
+ sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
if (i != 0) {
psed = sc->sc_eds[(i-1) / 2];
sed->next = psed;
- sed->ed->ed_nexted = psed->physaddr;
+ sed->ed->ed_nexted = LE(psed->physaddr);
}
}
/*
@@ -381,7 +401,7 @@ ohci_init(sc)
*/
for (i = 0; i < OHCI_NO_INTRS; i++)
sc->sc_hcca->hcca_interrupt_table[revbits[i]] =
- sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr;
+ LE(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr);
/* Determine in what context we are running. */
ctl = OREAD4(sc, OHCI_CONTROL);
@@ -395,8 +415,8 @@ ohci_init(sc)
ctl = OREAD4(sc, OHCI_CONTROL);
}
if ((ctl & OHCI_IR) == 0) {
- DEVICE_MSG(sc->sc_bus.bdev,
- ("SMM does not respond, resetting\n"));
+ printf("%s: SMM does not respond, resetting\n",
+ USBDEVNAME(sc->sc_bus.bdev));
OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
goto reset;
}
@@ -411,9 +431,17 @@ ohci_init(sc)
DPRINTF(("ohci_init: cold started\n"));
reset:
/* Controller was cold started. */
- delay(USB_RESET_DELAY * 1000);
+ delay(USB_BUS_RESET_DELAY * 1000);
}
+ /*
+ * This reset should not be necessary according to the OHCI spec, but
+ * without it some controllers do not start.
+ */
+ DPRINTF(("%s: resetting\n", USBDEVNAME(sc->sc_bus.bdev)));
+ OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
+ delay(USB_BUS_RESET_DELAY * 1000);
+
/* We now own the host controller and the bus has been reset. */
ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL));
@@ -426,7 +454,7 @@ ohci_init(sc)
break;
}
if (hcr) {
- DEVICE_MSG(sc->sc_bus.bdev, ("reset timeout\n"));
+ printf("%s: reset timeout\n", USBDEVNAME(sc->sc_bus.bdev));
r = USBD_IOERROR;
goto bad3;
}
@@ -465,9 +493,6 @@ ohci_init(sc)
OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */
sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A));
- DEVICE_MSG(sc->sc_bus.bdev, ("%d downstream port%s\n",
- sc->sc_noport,
- sc->sc_noport != 1 ? "s" : ""));
#ifdef USB_DEBUG
if (ohcidebug > 5)
@@ -530,8 +555,8 @@ ohci_dumpregs(sc)
OREAD4(sc, OHCI_RH_PORT_STATUS(1)),
OREAD4(sc, OHCI_RH_PORT_STATUS(2)));
printf(" HCCA: frame_number=0x%04x done_head=0x%08x\n",
- sc->sc_hcca->hcca_frame_number,
- sc->sc_hcca->hcca_done_head);
+ LE(sc->sc_hcca->hcca_frame_number),
+ LE(sc->sc_hcca->hcca_done_head));
}
#endif
@@ -543,13 +568,15 @@ ohci_intr(p)
u_int32_t intrs, eintrs;
ohci_physaddr_t done;
- /* if attach is failed we get a NULL pointer here
- * XXX should be removed when pci_unmap_int is implemented
- */
- if ((sc == NULL) || (sc->sc_hcca == NULL))
+ /* In case the interrupt occurs before initialization has completed. */
+ if (sc == NULL || sc->sc_hcca == NULL) { /* NWH added sc==0 */
+#ifdef DIAGNOSTIC
+ printf("ohci_intr: sc->sc_hcca == NULL\n");
+#endif
return (0);
+ }
- done = sc->sc_hcca->hcca_done_head;
+ done = LE(sc->sc_hcca->hcca_done_head);
if (done != 0) {
intrs = OHCI_WDH;
if (done & OHCI_DONE_INTRS)
@@ -570,7 +597,7 @@ ohci_intr(p)
(u_int)eintrs));
if (eintrs & OHCI_SO) {
- DEVICE_MSG(sc->sc_bus.bdev, ("scheduling overrun\n"));
+ printf("%s: scheduling overrun\n",USBDEVNAME(sc->sc_bus.bdev));
/* XXX do what */
intrs &= ~OHCI_SO;
}
@@ -583,8 +610,8 @@ ohci_intr(p)
/* XXX process resume detect */
}
if (eintrs & OHCI_UE) {
- DEVICE_MSG(sc->sc_bus.bdev,
- ("unrecoverable error, controller halted\n"));
+ printf("%s: unrecoverable error, controller halted\n",
+ USBDEVNAME(sc->sc_bus.bdev));
OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
/* XXX what else */
}
@@ -621,6 +648,24 @@ ohci_rhsc_able(sc, on)
}
}
+#ifdef USB_DEBUG
+char *ohci_cc_strs[] = {
+ "NO_ERROR",
+ "CRC",
+ "BIT_STUFFING",
+ "DATA_TOGGLE_MISMATCH",
+ "STALL",
+ "DEVICE_NOT_RESPONDING",
+ "PID_CHECK_FAILURE",
+ "UNEXPECTED_PID",
+ "DATA_OVERRUN",
+ "DATA_UNDERRUN",
+ "BUFFER_OVERRUN",
+ "BUFFER_UNDERRUN",
+ "NOT_ACCESSED",
+};
+#endif
+
void
ohci_process_done(sc, done)
ohci_softc_t *sc;
@@ -633,7 +678,7 @@ ohci_process_done(sc, done)
DPRINTFN(10,("ohci_process_done: done=0x%08lx\n", (u_long)done));
/* Reverse the done list. */
- for (sdone = 0; done; done = std->td->td_nexttd) {
+ for (sdone = 0; done; done = LE(std->td->td_nexttd)) {
std = ohci_hash_find_td(sc, done);
std->dnext = sdone;
sdone = std;
@@ -649,38 +694,40 @@ ohci_process_done(sc, done)
for (std = sdone; std; std = std->dnext) {
reqh = std->reqh;
DPRINTFN(10, ("ohci_process_done: std=%p reqh=%p\n",std,reqh));
- cc = OHCI_TD_GET_CC(std->td->td_flags);
+ cc = OHCI_TD_GET_CC(LE(std->td->td_flags));
if (cc == OHCI_CC_NO_ERROR) {
if (std->td->td_cbp == 0)
len = std->len;
else
- len = std->td->td_be - std->td->td_cbp + 1;
- reqh->actlen += len;
- if (reqh->hcpriv == std) {
- switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
- case UE_CONTROL:
- ohci_ctrl_done(sc, reqh);
- break;
- case UE_INTERRUPT:
- ohci_intr_done(sc, reqh);
- break;
- case UE_BULK:
- ohci_bulk_done(sc, reqh);
- break;
- case UE_ISOCHRONOUS:
- printf("ohci_process_done: ISO done?\n");
- break;
+ len = LE(std->td->td_be) -
+ LE(std->td->td_cbp) + 1;
+ /*
+ * Only do a callback on the last stage of a transfer.
+ * Others have hcpriv = 0.
+ */
+ if ((reqh->pipe->endpoint->edesc->bmAttributes &
+ UE_XFERTYPE) == UE_CONTROL) {
+ /* For a control transfer the length is in
+ * the xfer stage */
+ if (reqh->hcpriv == std) {
+ reqh->status = USBD_NORMAL_COMPLETION;
+ ohci_ii_done(sc, reqh);
+ } else
+ reqh->actlen = len;
+ } else {
+ if (reqh->hcpriv == std) {
+ reqh->actlen = len;
+ reqh->status = USBD_NORMAL_COMPLETION;
+ ohci_ii_done(sc, reqh);
}
- /* And finally execute callback. */
- reqh->status = USBD_NORMAL_COMPLETION;
- reqh->xfercb(reqh);
}
} else {
ohci_soft_td_t *p, *n;
struct ohci_pipe *opipe =
(struct ohci_pipe *)reqh->pipe;
- DPRINTFN(-1,("ohci_process_done: error cc=%d\n",
- OHCI_TD_GET_CC(std->td->td_flags)));
+ DPRINTFN(-1,("ohci_process_done: error cc=%d (%s)\n",
+ OHCI_TD_GET_CC(LE(std->td->td_flags)),
+ ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td->td_flags))]));
/*
* Endpoint is halted. First unlink all the TDs
* belonging to the failed transfer, and then restart
@@ -691,14 +738,15 @@ ohci_process_done(sc, done)
ohci_hash_rem_td(sc, p);
ohci_free_std(sc, p);
}
- opipe->sed->ed->ed_headp = p->physaddr;/* clear halt */
+ /* clear halt */
+ opipe->sed->ed->ed_headp = LE(p->physaddr);
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
if (cc == OHCI_CC_STALL)
reqh->status = USBD_STALLED;
else
reqh->status = USBD_IOERROR;
- reqh->xfercb(reqh);
+ ohci_ii_done(sc, reqh);
}
ohci_hash_rem_td(sc, std);
ohci_free_std(sc, std);
@@ -706,6 +754,33 @@ ohci_process_done(sc, done)
}
void
+ohci_ii_done(sc, reqh)
+ ohci_softc_t *sc;
+ usbd_request_handle reqh;
+{
+ switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
+ case UE_CONTROL:
+ ohci_ctrl_done(sc, reqh);
+ usb_start_next(reqh->pipe);
+ break;
+ case UE_INTERRUPT:
+ ohci_intr_done(sc, reqh);
+ break;
+ case UE_BULK:
+ ohci_bulk_done(sc, reqh);
+ usb_start_next(reqh->pipe);
+ break;
+ case UE_ISOCHRONOUS:
+ printf("ohci_process_done: ISO done?\n");
+ usb_start_next(reqh->pipe);
+ break;
+ }
+
+ /* And finally execute callback. */
+ reqh->xfercb(reqh);
+}
+
+void
ohci_ctrl_done(sc, reqh)
ohci_softc_t *sc;
usbd_request_handle reqh;
@@ -727,11 +802,7 @@ ohci_ctrl_done(sc, reqh)
memcpy(reqh->buffer, KERNADDR(dma), len);
usb_freemem(sc->sc_dmatag, dma);
}
-#if defined(__NetBSD__)
- untimeout(ohci_timeout, reqh);
-#elif defined(__FreeBSD__)
- untimeout(ohci_timeout, reqh, reqh->timo_handle);
-#endif
+ usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);
}
void
@@ -760,23 +831,24 @@ ohci_intr_done(sc, reqh)
}
tail->reqh = 0;
- xfer->td->td_flags = OHCI_TD_IN | OHCI_TD_NOCC |
- OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY;
- xfer->td->td_cbp = DMAADDR(dma);
+ xfer->td->td_flags = LE(
+ OHCI_TD_IN | OHCI_TD_NOCC |
+ OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
+ if (reqh->flags & USBD_SHORT_XFER_OK)
+ xfer->td->td_flags |= LE(OHCI_TD_R);
+ xfer->td->td_cbp = LE(DMAADDR(dma));
xfer->nexttd = tail;
- xfer->td->td_nexttd = tail->physaddr;
- xfer->td->td_be = xfer->td->td_cbp + reqh->length - 1;
+ xfer->td->td_nexttd = LE(tail->physaddr);
+ xfer->td->td_be = LE(LE(xfer->td->td_cbp) + reqh->length - 1);
xfer->len = reqh->length;
xfer->reqh = reqh;
- reqh->actlen = 0;
- reqh->hcpriv = xfer;
-
ohci_hash_add_td(sc, xfer);
- sed->ed->ed_tailp = tail->physaddr;
+ sed->ed->ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
} else {
usb_freemem(sc->sc_dmatag, dma);
+ usb_start_next(reqh->pipe);
}
}
@@ -796,11 +868,7 @@ ohci_bulk_done(sc, reqh)
if (reqh->request.bmRequestType & UT_READ)
memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);
usb_freemem(sc->sc_dmatag, dma);
-#if defined(__NetBSD__)
- untimeout(ohci_timeout, reqh);
-#elif defined(__FreeBSD__)
- untimeout(ohci_timeout, reqh, reqh->timo_handle);
-#endif
+ usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);
}
void
@@ -841,6 +909,7 @@ ohci_rhsc(sc, reqh)
if (reqh->pipe->intrreqh != reqh) {
sc->sc_intrreqh = 0;
usb_freemem(sc->sc_dmatag, &opipe->u.intr.datadma);
+ usb_start_next(reqh->pipe);
}
}
@@ -860,7 +929,7 @@ ohci_waitintr(sc, reqh)
reqh->status = USBD_IN_PROGRESS;
for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) {
- delay(1000);
+ usb_delay_ms(&sc->sc_bus, 1);
intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs;
DPRINTFN(10,("ohci_waitintr: 0x%04x\n", intrs));
#ifdef USB_DEBUG
@@ -873,9 +942,12 @@ ohci_waitintr(sc, reqh)
return;
}
}
+
+ /* Timeout */
DPRINTF(("ohci_waitintr: timeout\n"));
reqh->status = USBD_TIMEOUT;
- reqh->xfercb(reqh);
+ ohci_ii_done(sc, reqh);
+ /* XXX should free TD */
}
void
@@ -908,7 +980,8 @@ ohci_device_request(reqh)
isread = req->bmRequestType & UT_READ;
len = UGETW(req->wLength);
- DPRINTFN(3,("ohci_device_control type=0x%02x, request=0x%02x, wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
+ DPRINTFN(3,("ohci_device_control 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,
opipe->pipe.endpoint->edesc->bEndpointAddress));
@@ -932,10 +1005,10 @@ ohci_device_request(reqh)
/* 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. */
- sed->ed->ed_flags =
- (sed->ed->ed_flags & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) |
- OHCI_ED_SET_FA(addr) |
- OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize));
+ sed->ed->ed_flags = LE(
+ (LE(sed->ed->ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) |
+ OHCI_ED_SET_FA(addr) |
+ OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize)));
/* Set up data transaction */
if (len != 0) {
@@ -947,13 +1020,14 @@ ohci_device_request(reqh)
r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);
if (r != USBD_NORMAL_COMPLETION)
goto bad4;
- xfer->td->td_flags =
+ xfer->td->td_flags = LE(
(isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC |
- OHCI_TD_TOGGLE_1 | OHCI_TD_NOINTR;
- xfer->td->td_cbp = DMAADDR(dmap);
+ OHCI_TD_TOGGLE_1 | OHCI_TD_NOINTR |
+ (reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0));
+ xfer->td->td_cbp = LE(DMAADDR(dmap));
xfer->nexttd = stat;
- xfer->td->td_nexttd = stat->physaddr;
- xfer->td->td_be = xfer->td->td_cbp + len - 1;
+ xfer->td->td_nexttd = LE(stat->physaddr);
+ xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1);
xfer->len = len;
xfer->reqh = reqh;
@@ -965,26 +1039,25 @@ ohci_device_request(reqh)
if (!isread && len != 0)
memcpy(KERNADDR(dmap), reqh->buffer, len);
- setup->td->td_flags = OHCI_TD_SETUP | OHCI_TD_NOCC |
- OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR;
- setup->td->td_cbp = DMAADDR(&opipe->u.ctl.reqdma);
+ setup->td->td_flags = LE(OHCI_TD_SETUP | OHCI_TD_NOCC |
+ OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR);
+ setup->td->td_cbp = LE(DMAADDR(&opipe->u.ctl.reqdma));
setup->nexttd = next;
- setup->td->td_nexttd = next->physaddr;
- setup->td->td_be = setup->td->td_cbp + sizeof *req - 1;
+ setup->td->td_nexttd = LE(next->physaddr);
+ setup->td->td_be = LE(LE(setup->td->td_cbp) + sizeof *req - 1);
setup->len = 0; /* XXX The number of byte we count */
setup->reqh = reqh;
- stat->td->td_flags =
+ stat->td->td_flags = LE(
(isread ? OHCI_TD_OUT : OHCI_TD_IN) | OHCI_TD_NOCC |
- OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1);
+ OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1));
stat->td->td_cbp = 0;
stat->nexttd = tail;
- stat->td->td_nexttd = tail->physaddr;
+ stat->td->td_nexttd = LE(tail->physaddr);
stat->td->td_be = 0;
stat->len = 0;
stat->reqh = reqh;
- reqh->actlen = 0;
reqh->hcpriv = stat;
#if USB_DEBUG
@@ -1001,17 +1074,12 @@ ohci_device_request(reqh)
if (len != 0)
ohci_hash_add_td(sc, xfer);
ohci_hash_add_td(sc, stat);
- sed->ed->ed_tailp = tail->physaddr;
+ sed->ed->ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
if (reqh->timeout && !sc->sc_bus.use_polling) {
-#if defined(__NetBSD__)
- timeout(ohci_timeout, reqh, MS_TO_TICKS(reqh->timeout));
-#elif defined(__FreeBSD__)
- callout_handle_init(&reqh->timo_handle);
- reqh->timo_handle = timeout(ohci_timeout, reqh,
- MS_TO_TICKS(reqh->timeout));
-#endif
+ usb_timeout(ohci_timeout, reqh,
+ MS_TO_TICKS(reqh->timeout), reqh->timo_handle);
}
splx(s);
@@ -1048,7 +1116,7 @@ ohci_add_ed(sed, head)
sed->next = head->next;
sed->ed->ed_nexted = head->ed->ed_nexted;
head->next = sed;
- head->ed->ed_nexted = sed->physaddr;
+ head->ed->ed_nexted = LE(sed->physaddr);
}
/*
@@ -1146,31 +1214,33 @@ void
ohci_dump_td(std)
ohci_soft_td_t *std;
{
- printf("TD(%p) at %08lx: %b delay=%d ec=%d cc=%d\ncbp=0x%08lx nexttd=0x%08lx be=0x%08lx\n",
+ printf("TD(%p) at %08lx: %b delay=%d ec=%d cc=%d\ncbp=0x%08lx "
+ "nexttd=0x%08lx be=0x%08lx\n",
std, (u_long)std->physaddr,
- (u_long)std->td->td_flags,
+ (u_long)LE(std->td->td_flags),
"\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE",
- OHCI_TD_GET_DI(std->td->td_flags),
- OHCI_TD_GET_EC(std->td->td_flags),
- OHCI_TD_GET_CC(std->td->td_flags),
- (u_long)std->td->td_cbp,
- (u_long)std->td->td_nexttd, (u_long)std->td->td_be);
+ OHCI_TD_GET_DI(LE(std->td->td_flags)),
+ OHCI_TD_GET_EC(LE(std->td->td_flags)),
+ OHCI_TD_GET_CC(LE(std->td->td_flags)),
+ (u_long)LE(std->td->td_cbp),
+ (u_long)LE(std->td->td_nexttd), (u_long)LE(std->td->td_be));
}
void
ohci_dump_ed(sed)
ohci_soft_ed_t *sed;
{
- printf("ED(%p) at %08lx: addr=%d endpt=%d maxp=%d %b\ntailp=0x%08lx headp=%b nexted=0x%08lx\n",
+ printf("ED(%p) at %08lx: addr=%d endpt=%d maxp=%d %b\ntailp=0x%08lx "
+ "headp=%b nexted=0x%08lx\n",
sed, (u_long)sed->physaddr,
- OHCI_ED_GET_FA(sed->ed->ed_flags),
- OHCI_ED_GET_EN(sed->ed->ed_flags),
- OHCI_ED_GET_MAXP(sed->ed->ed_flags),
- (u_long)sed->ed->ed_flags,
+ OHCI_ED_GET_FA(LE(sed->ed->ed_flags)),
+ OHCI_ED_GET_EN(LE(sed->ed->ed_flags)),
+ OHCI_ED_GET_MAXP(LE(sed->ed->ed_flags)),
+ (u_long)LE(sed->ed->ed_flags),
"\20\14OUT\15IN\16LOWSPEED\17SKIP\18ISO",
- (u_long)sed->ed->ed_tailp,
- (u_long)sed->ed->ed_headp, "\20\1HALT\2CARRY",
- (u_long)sed->ed->ed_nexted);
+ (u_long)LE(sed->ed->ed_tailp),
+ (u_long)LE(sed->ed->ed_headp), "\20\1HALT\2CARRY",
+ (u_long)LE(sed->ed->ed_nexted));
}
#endif
@@ -1210,15 +1280,15 @@ ohci_open(pipe)
goto bad1;
opipe->sed = sed;
opipe->tail = std;
- sed->ed->ed_flags =
+ sed->ed->ed_flags = LE(
OHCI_ED_SET_FA(addr) |
OHCI_ED_SET_EN(ed->bEndpointAddress) |
OHCI_ED_DIR_TD |
(dev->lowspeed ? OHCI_ED_SPEED : 0) |
((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS ?
OHCI_ED_FORMAT_ISO : OHCI_ED_FORMAT_GEN) |
- OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize));
- sed->ed->ed_headp = sed->ed->ed_tailp = std->physaddr;
+ OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize)));
+ sed->ed->ed_headp = sed->ed->ed_tailp = LE(std->physaddr);
switch (ed->bmAttributes & UE_XFERTYPE) {
case UE_CONTROL:
@@ -1315,7 +1385,6 @@ usb_hub_descriptor_t ohci_hubd = {
0,
0,
{0},
- {0},
};
int
@@ -1345,6 +1414,22 @@ usbd_status
ohci_root_ctrl_transfer(reqh)
usbd_request_handle reqh;
{
+ int s;
+ usbd_status r;
+
+ s = splusb();
+ r = usb_insert_transfer(reqh);
+ splx(s);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (ohci_root_ctrl_start(reqh));
+}
+
+usbd_status
+ohci_root_ctrl_start(reqh)
+ usbd_request_handle reqh;
+{
ohci_softc_t *sc = (ohci_softc_t *)reqh->pipe->device->bus;
usb_device_request_t *req;
void *buf;
@@ -1373,7 +1458,7 @@ ohci_root_ctrl_transfer(reqh)
case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
/*
- * DEVICE_REMOTE_WAKEUP and ENDPOINT_STALL are no-ops
+ * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
* for the integrated root hub.
*/
break;
@@ -1479,7 +1564,8 @@ ohci_root_ctrl_transfer(reqh)
case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
break;
case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
- DPRINTFN(8, ("ohci_root_ctrl_control: UR_CLEAR_PORT_FEATURE port=%d feature=%d\n",
+ DPRINTFN(8, ("ohci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
+ "port=%d feature=%d\n",
index, value));
if (index < 1 || index > sc->sc_noport) {
r = USBD_IOERROR;
@@ -1537,24 +1623,16 @@ ohci_root_ctrl_transfer(reqh)
v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
hubd = ohci_hubd;
hubd.bNbrPorts = sc->sc_noport;
- USETW(hubd.bHubCharacteristics,
+ USETW(hubd.wHubCharacteristics,
(v & OHCI_NPS ? UHD_PWR_NO_SWITCH :
v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL)
/* XXX overcurrent */
);
hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v);
v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B);
- if (sc->sc_noport < 8) {
- hubd.DeviceRemovable[0] = (u_int8_t)v;
- hubd.PortPowerCtrlMask[0] = (u_int8_t)(v >> 16);
- hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE;
- } else {
- hubd.DeviceRemovable[0] = (u_int8_t)v;
- hubd.DeviceRemovable[1] = (u_int8_t)(v>>8);
- hubd.PortPowerCtrlMask[1] = (u_int8_t)(v >> 16);
- hubd.PortPowerCtrlMask[2] = (u_int8_t)(v >> 24);
- hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + 2;
- }
+ for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)
+ hubd.DeviceRemovable[i++] = (u_int8_t)v;
+ hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
l = min(len, hubd.bDescLength);
totlen = l;
memcpy(buf, &hubd, l);
@@ -1606,10 +1684,11 @@ ohci_root_ctrl_transfer(reqh)
OWRITE4(sc, port, UPS_SUSPEND);
break;
case UHF_PORT_RESET:
- DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n", index));
+ DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n",
+ index));
OWRITE4(sc, port, UPS_RESET);
for (i = 0; i < 10; i++) {
- usbd_delay_ms(&sc->sc_bus, 10);
+ usb_delay_ms(&sc->sc_bus, 10);
if ((OREAD4(sc, port) & UPS_RESET) == 0)
break;
}
@@ -1617,7 +1696,8 @@ ohci_root_ctrl_transfer(reqh)
index, OREAD4(sc, port)));
break;
case UHF_PORT_POWER:
- DPRINTFN(2,("ohci_root_ctrl_transfer: set port power %d\n", index));
+ DPRINTFN(2,("ohci_root_ctrl_transfer: set port power "
+ "%d\n", index));
OWRITE4(sc, port, UPS_PORT_POWER);
break;
default:
@@ -1634,6 +1714,7 @@ ohci_root_ctrl_transfer(reqh)
ret:
reqh->status = r;
reqh->xfercb(reqh);
+ usb_start_next(reqh->pipe);
return (USBD_IN_PROGRESS);
}
@@ -1657,6 +1738,22 @@ usbd_status
ohci_root_intr_transfer(reqh)
usbd_request_handle reqh;
{
+ int s;
+ usbd_status r;
+
+ s = splusb();
+ r = usb_insert_transfer(reqh);
+ splx(s);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (ohci_root_intr_start(reqh));
+}
+
+usbd_status
+ohci_root_intr_start(reqh)
+ usbd_request_handle reqh;
+{
usbd_pipe_handle pipe = reqh->pipe;
ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
struct ohci_pipe *upipe = (struct ohci_pipe *)pipe;
@@ -1702,6 +1799,22 @@ usbd_status
ohci_device_ctrl_transfer(reqh)
usbd_request_handle reqh;
{
+ int s;
+ usbd_status r;
+
+ s = splusb();
+ r = usb_insert_transfer(reqh);
+ splx(s);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (ohci_device_ctrl_start(reqh));
+}
+
+usbd_status
+ohci_device_ctrl_start(reqh)
+ usbd_request_handle reqh;
+{
ohci_softc_t *sc = (ohci_softc_t *)reqh->pipe->device->bus;
usbd_status r;
@@ -1726,7 +1839,7 @@ ohci_device_ctrl_abort(reqh)
usbd_request_handle reqh;
{
/* XXX inactivate */
- usbd_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is finished */
+ usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is donw */
/* XXX call done */
}
@@ -1741,9 +1854,9 @@ ohci_device_ctrl_close(pipe)
int s;
s = splusb();
- sed->ed->ed_flags |= OHCI_ED_SKIP;
- if ((sed->ed->ed_tailp & OHCI_TAILMASK) != sed->ed->ed_headp)
- usbd_delay_ms(&sc->sc_bus, 2);
+ sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
+ if ((LE(sed->ed->ed_tailp) & OHCI_TAILMASK) != LE(sed->ed->ed_headp))
+ usb_delay_ms(&sc->sc_bus, 2);
ohci_rem_ed(sed, sc->sc_ctrl_head);
splx(s);
ohci_free_std(sc, opipe->tail);
@@ -1757,6 +1870,22 @@ usbd_status
ohci_device_bulk_transfer(reqh)
usbd_request_handle reqh;
{
+ int s;
+ usbd_status r;
+
+ s = splusb();
+ r = usb_insert_transfer(reqh);
+ splx(s);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (ohci_device_bulk_start(reqh));
+}
+
+usbd_status
+ohci_device_bulk_start(reqh)
+ usbd_request_handle reqh;
+{
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
usbd_device_handle dev = opipe->pipe.device;
ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
@@ -1792,23 +1921,23 @@ ohci_device_bulk_transfer(reqh)
tail->reqh = 0;
/* Update device address */
- sed->ed->ed_flags =
- (sed->ed->ed_flags & ~OHCI_ED_ADDRMASK) |
- OHCI_ED_SET_FA(addr);
+ sed->ed->ed_flags = LE(
+ (LE(sed->ed->ed_flags) & ~OHCI_ED_ADDRMASK) |
+ OHCI_ED_SET_FA(addr));
/* Set up data transaction */
xfer = opipe->tail;
- xfer->td->td_flags =
+ xfer->td->td_flags = LE(
(isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC |
- OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY;
- xfer->td->td_cbp = DMAADDR(dmap);
+ OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY |
+ (reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0));
+ xfer->td->td_cbp = LE(DMAADDR(dmap));
xfer->nexttd = tail;
- xfer->td->td_nexttd = tail->physaddr;
- xfer->td->td_be = xfer->td->td_cbp + len - 1;
+ xfer->td->td_nexttd = LE(tail->physaddr);
+ xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1);
xfer->len = len;
xfer->reqh = reqh;
- reqh->actlen = 0;
reqh->hcpriv = xfer;
if (!isread)
@@ -1817,17 +1946,12 @@ ohci_device_bulk_transfer(reqh)
/* Insert ED in schedule */
s = splusb();
ohci_hash_add_td(sc, xfer);
- sed->ed->ed_tailp = tail->physaddr;
+ sed->ed->ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
if (reqh->timeout && !sc->sc_bus.use_polling) {
-#if defined(__NetBSD__)
- timeout(ohci_timeout, reqh, MS_TO_TICKS(reqh->timeout));
-#elif defined(__FreeBSD__)
- callout_handle_init(&reqh->timo_handle);
- reqh->timo_handle = timeout(ohci_timeout, reqh,
- MS_TO_TICKS(reqh->timeout));
-#endif
+ usb_timeout(ohci_timeout, reqh,
+ MS_TO_TICKS(reqh->timeout), reqh->timo_handle);
}
splx(s);
@@ -1845,12 +1969,12 @@ ohci_device_bulk_abort(reqh)
usbd_request_handle reqh;
{
#if 0
- sed->ed->ed_flags |= OHCI_ED_SKIP;
- if ((sed->ed->ed_tailp & OHCI_TAILMASK) != sed->ed->ed_headp)
- usbd_delay_ms(reqh->pipe->device->bus, 2);
+ sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
+ if ((LE(sed->ed->ed_tailp) & OHCI_TAILMASK) != LE(sed->ed->ed_headp))
+ usb_delay_ms(reqh->pipe->device->bus, 2);
#endif
/* XXX inactivate */
- usbd_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is finished */
+ usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */
/* XXX call done */
}
@@ -1878,6 +2002,22 @@ usbd_status
ohci_device_intr_transfer(reqh)
usbd_request_handle reqh;
{
+ int s;
+ usbd_status r;
+
+ s = splusb();
+ r = usb_insert_transfer(reqh);
+ splx(s);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
+ else
+ return (ohci_device_intr_start(reqh));
+}
+
+usbd_status
+ohci_device_intr_start(reqh)
+ usbd_request_handle reqh;
+{
struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;
usbd_device_handle dev = opipe->pipe.device;
ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
@@ -1888,7 +2028,8 @@ ohci_device_intr_transfer(reqh)
int len;
int s;
- DPRINTFN(3, ("ohci_device_intr_transfer: reqh=%p buf=%p len=%d flags=%d priv=%p\n",
+ DPRINTFN(3, ("ohci_device_intr_transfer: reqh=%p buf=%p len=%d "
+ "flags=%d priv=%p\n",
reqh, reqh->buffer, reqh->length, reqh->flags, reqh->priv));
if (reqh->isreq)
@@ -1911,16 +2052,18 @@ ohci_device_intr_transfer(reqh)
if (r != USBD_NORMAL_COMPLETION)
goto ret2;
- xfer->td->td_flags = OHCI_TD_IN | OHCI_TD_NOCC |
- OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY;
- xfer->td->td_cbp = DMAADDR(dmap);
+ xfer->td->td_flags = LE(
+ OHCI_TD_IN | OHCI_TD_NOCC |
+ OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
+ if (reqh->flags & USBD_SHORT_XFER_OK)
+ xfer->td->td_flags |= LE(OHCI_TD_R);
+ xfer->td->td_cbp = LE(DMAADDR(dmap));
xfer->nexttd = tail;
- xfer->td->td_nexttd = tail->physaddr;
- xfer->td->td_be = xfer->td->td_cbp + len - 1;
+ xfer->td->td_nexttd = LE(tail->physaddr);
+ xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1);
xfer->len = len;
xfer->reqh = reqh;
- reqh->actlen = 0;
reqh->hcpriv = xfer;
#if USB_DEBUG
@@ -1934,20 +2077,15 @@ ohci_device_intr_transfer(reqh)
/* Insert ED in schedule */
s = splusb();
ohci_hash_add_td(sc, xfer);
- sed->ed->ed_tailp = tail->physaddr;
+ sed->ed->ed_tailp = LE(tail->physaddr);
opipe->tail = tail;
#if 0
if (reqh->timeout && !sc->sc_bus.use_polling) {
-#if defined(__NetBSD__)
- timeout(ohci_timeout, reqh, MS_TO_TICKS(reqh->timeout));
-#elif defined(__FreeBSD__)
- callout_handle_init(&reqh->timo_handle);
- reqh->timo_handle = timeout(ohci_timeout, reqh,
- MS_TO_TICKS(reqh->timeout));
-#endif
+ usb_timeout(ohci_timeout, reqh,
+ MS_TO_TICKS(reqh->timeout), reqh->timo_handle);
}
#endif
- sed->ed->ed_flags &= ~OHCI_ED_SKIP;
+ sed->ed->ed_flags &= LE(~OHCI_ED_SKIP);
splx(s);
#ifdef USB_DEBUG
@@ -1974,7 +2112,7 @@ ohci_device_intr_abort(reqh)
usbd_request_handle reqh;
{
/* XXX inactivate */
- usbd_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is finished */
+ usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */
if (reqh->pipe->intrreqh == reqh) {
DPRINTF(("ohci_device_intr_abort: remove\n"));
reqh->pipe->intrreqh = 0;
@@ -1998,9 +2136,9 @@ ohci_device_intr_close(pipe)
DPRINTFN(1,("ohci_device_intr_close: pipe=%p nslots=%d pos=%d\n",
pipe, nslots, pos));
s = splusb();
- sed->ed->ed_flags |= OHCI_ED_SKIP;
- if ((sed->ed->ed_tailp & OHCI_TAILMASK) != sed->ed->ed_headp)
- usbd_delay_ms(&sc->sc_bus, 2);
+ sed->ed->ed_flags |= LE(OHCI_ED_SKIP);
+ if ((sed->ed->ed_tailp & LE(OHCI_TAILMASK)) != sed->ed->ed_headp)
+ usb_delay_ms(&sc->sc_bus, 2);
for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next)
;
@@ -2071,7 +2209,7 @@ ohci_device_setintr(sc, opipe, ival)
sed->next = hsed->next;
sed->ed->ed_nexted = hsed->ed->ed_nexted;
hsed->next = sed;
- hsed->ed->ed_nexted = sed->physaddr;
+ hsed->ed->ed_nexted = LE(sed->physaddr);
splx(s);
for (j = 0; j < nslots; j++)
OpenPOWER on IntegriCloud