summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorjoe <joe@FreeBSD.org>2002-03-16 12:06:01 +0000
committerjoe <joe@FreeBSD.org>2002-03-16 12:06:01 +0000
commit622a58e08c7c4092c072fb433592a3d245a5c520 (patch)
tree179ca82ef7a1d5434adeeef8fd553c8a68043464 /sys/dev
parent688687434f7b4bf689cb76a2bfdbcbc2b34bf03d (diff)
downloadFreeBSD-src-622a58e08c7c4092c072fb433592a3d245a5c520.zip
FreeBSD-src-622a58e08c7c4092c072fb433592a3d245a5c520.tar.gz
Huge merge from NetBSD:
usbdi.c (1.61): =================================================================== revision 1.61 date: 2000/01/31 20:13:07; author: augustss; lines: +20 -4 Change the way the HC done method is invoked a little. =================================================================== usbdi.c (1.65): =================================================================== revision 1.65 date: 2000/03/08 15:34:10; author: augustss; lines: +4 -2 Get the status right when a polled transfer times out. =================================================================== ohci.c (1.79), uhci.c (1.89), uhcivar.h (1.24), usb_port.h (1.22), usbdivar.h (1.48): =================================================================== date: 2000/03/23 07:01:46; author: thorpej; New callout mechanism with two major improvements over the old timeout()/untimeout() API: - Clients supply callout handle storage, thus eliminating problems of resource allocation. - Insertion and removal of callouts is constant time, important as this facility is used quite a lot in the kernel. The old timeout()/untimeout() API has been removed from the kernel. =================================================================== uhci.c (1.80), usbdi.c (1.66): =================================================================== date: 2000/03/23 18:59:10; author: thorpej; Shake out some bugs from the callout changes. =================================================================== ohci.c (1.80), uhci.c (1.91), uhcivar.h (1.25), usb_port.h (1.23), usbdi.c (1.67), usbdivar.h (1.49): =================================================================== date: 2000/03/24 22:03:30; author: augustss; Some cleanup and renaming of the callouts used in USB drivers. =================================================================== uhci.c (1.92), uhcivar.h (1.26): =================================================================== date: 2000/03/24 22:57:58; author: augustss; Two major changes: Make each xfer have its own intr_info. This is necessary if we want to queue multiple xfers on an endpoint. This should get rid of the (mostly harmless) DIAGNOSTICs about intr_infos (not) being done. Change (again!) how xfers are aborted. Aborting a TD is a nightmare on the braindead UHCI controller. (Unless you stop the HC, thereby losing isoc traffic.) Hopefully I got it right this time. =================================================================== usbdivar.h (1.50): =================================================================== revision 1.50 date: 2000/03/25 00:10:19; author: augustss; lines: +4 -2 GC an unsued field and add some DIAGNOSTIC in xfer. =================================================================== ums.c: Use the callout functions instead of the timeout ones. uhci.c (1.93): =================================================================== revision 1.93 date: 2000/03/25 00:11:21; author: augustss; lines: +26 -1 Add more DIAGNOSTIC when aborting isoc. =================================================================== uhci.c (1.94), usbdivar.h (1.51): =================================================================== date: 2000/03/25 07:13:05; author: augustss; More DIAGNOSTIC. Initialize a callout handle I forgot. =================================================================== uhci.c (1.95): =================================================================== revision 1.95 date: 2000/03/25 07:23:12; author: augustss; Exp; lines: +24 -7 Improve uhci_dump_ii(). =================================================================== ohci.c (1.81), uhci.c (1.96), uhcivar.h (1.27), usb_subr.c (1.68), usbdi.c (1.68), usbdivar.h (1.52): =================================================================== date: 2000/03/25 18:02:33; author: augustss; Rename and move around callout handles to make it more sane. Add some DIAGNOSTIC. Fix buglet in isoc abort on UHCI. =================================================================== uhci.c (1.98): =================================================================== revision 1.98 date: 2000/03/27 07:39:48; author: augustss; lines: +12 -4 Make it compile without DIAGNOSTIC. =================================================================== uhci.c (1.99): =================================================================== revision 1.99 date: 2000/03/27 08:01:09; author: augustss; lines: +1 -5 Remove some debug nonsense. =================================================================== uhci.c (1.100): =================================================================== revision 1.100 date: 2000/03/27 09:41:36; author: augustss; lines: +13 -3 Don't mess with QH in bulk abort for the moment. =================================================================== uhci.c (1.102): =================================================================== revision 1.102 date: 2000/03/27 22:42:57; author: augustss; lines: +66 -26 Be a little more careful when aborting. Preallocate some TDs for large buffers. =================================================================== uhci.c (1.103): =================================================================== date: 2000/03/28 09:47:10; author: augustss; lines: +11 -1 Another patch for xfer abort... XXX The current xfer queueing and aborting semantics should really XXX be changed. It cannot be implemented in a sane way on UHCI. XXX One day when I have lots of time I'll redesign it... =================================================================== uhci.c (1.104): Correct a debug message. uhci.c (1.105): Be more defensive in a DIAGNOSTIC test. uhci.c (1.106): =================================================================== revision 1.106 date: 2000/03/29 01:49:13; author: augustss; lines: +14 -309 *SIGH* Revert back to the old method of aborting xfers. I had tested the new stuff for two months now, but as soon as I commited it the problems started to appear. Murphy, no doubt... =================================================================== usb_subr.c (1.70), usbdi.c (1.71), usbdivar.h (1.53): =================================================================== revision 1.70 date: 2000/03/29 01:45:20; author: augustss; lines: +2 -1 Do not accept new xfers for queuing while a pipe is aborting. ===================================================================
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/ohci.c19
-rw-r--r--sys/dev/usb/uhci.c522
-rw-r--r--sys/dev/usb/uhcivar.h22
-rw-r--r--sys/dev/usb/ums.c15
-rw-r--r--sys/dev/usb/usb_port.h20
-rw-r--r--sys/dev/usb/usb_subr.c4
-rw-r--r--sys/dev/usb/usbdi.c42
-rw-r--r--sys/dev/usb/usbdivar.h17
8 files changed, 368 insertions, 293 deletions
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 63792a1..cecc642 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ohci.c,v 1.74 2000/02/29 21:37:00 augustss Exp $ */
+/* $NetBSD: ohci.c,v 1.81 2000/03/25 18:02:32 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -1175,7 +1175,7 @@ ohci_softintr(struct usbd_bus *bus)
continue;
}
cc = OHCI_TD_GET_CC(le32toh(std->td.td_flags));
- usb_untimeout(ohci_timeout, xfer, xfer->timo_handle);
+ usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer);
if (xfer->status == USBD_CANCELLED ||
xfer->status == USBD_TIMEOUT) {
DPRINTF(("ohci_process_done: cancel/timeout, xfer=%p\n",
@@ -1510,8 +1510,8 @@ ohci_device_request(usbd_xfer_handle xfer)
opipe->tail.td = tail;
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_timeout(ohci_timeout, xfer,
- MS_TO_TICKS(xfer->timeout), xfer->timo_handle);
+ usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ ohci_timeout, xfer);
}
splx(s);
@@ -1700,6 +1700,7 @@ ohci_open(usbd_pipe_handle pipe)
DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
pipe, addr, ed->bEndpointAddress, sc->sc_addr));
+
if (addr == sc->sc_addr) {
switch (ed->bEndpointAddress) {
case USB_CONTROL_ENDPOINT:
@@ -1844,7 +1845,7 @@ ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
xfer->status = status;
- usb_untimeout(ohci_timeout, xfer, xfer->timo_handle);
+ usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer);
sed = opipe->sed;
sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* force hardware skip */
@@ -1856,7 +1857,9 @@ ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
#if 1
if (xfer->device->bus->intr_context) {
/* We have no process context, so we can't use tsleep(). */
- timeout(ohci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND);
+ usb_callout(xfer->pipe->abort_handle,
+ hz / USB_FRAMES_PER_SECOND, ohci_abort_xfer_end, xfer);
+
} else {
#if defined(DIAGNOSTIC) && defined(__i386__) && defined(__FreeBSD__)
KASSERT(curthread->td_intr_nesting_level == 0,
@@ -2527,8 +2530,8 @@ ohci_device_bulk_start(usbd_xfer_handle xfer)
sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_timeout(ohci_timeout, xfer,
- MS_TO_TICKS(xfer->timeout), xfer->timo_handle);
+ usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ ohci_timeout, xfer);
}
#if 0
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index d01c131..d6b2da1 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uhci.c,v 1.88 2000/03/16 12:40:51 tsutsui Exp $ */
+/* $NetBSD: uhci.c,v 1.106 2000/03/29 01:49:13 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -124,8 +124,11 @@ int uhcinoloop = 0;
struct uhci_pipe {
struct usbd_pipe pipe;
- uhci_intr_info_t *iinfo;
int nexttoggle;
+
+ u_char aborting;
+ usbd_xfer_handle abortstart, abortend;
+
/* Info needed for different pipe kinds. */
union {
/* Control pipe */
@@ -154,12 +157,6 @@ struct uhci_pipe {
} u;
};
-/*
- * The uhci_intr_info free list can be global since they contain
- * no dma specific data. The other free lists do.
- */
-Static LIST_HEAD(, uhci_intr_info) uhci_ii_free;
-
Static void uhci_busreset(uhci_softc_t *);
#if 0
Static void uhci_reset(uhci_softc_t *);
@@ -169,25 +166,20 @@ Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);
Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);
Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *);
Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *);
-Static uhci_intr_info_t *uhci_alloc_intr_info(uhci_softc_t *);
-Static void uhci_free_intr_info(uhci_intr_info_t *ii);
Static void uhci_free_std_chain(uhci_softc_t *,
uhci_soft_td_t *, uhci_soft_td_t *);
Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *,
uhci_softc_t *, int, int, u_int16_t, usb_dma_t *,
uhci_soft_td_t **, uhci_soft_td_t **);
-Static void uhci_timo(void *);
+Static void uhci_poll_hub(void *);
Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle);
Static void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *);
Static void uhci_idone(uhci_intr_info_t *);
Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status);
-Static void uhci_abort_xfer_end(void *v);
Static void uhci_timeout(void *);
-Static void uhci_lock_frames(uhci_softc_t *);
-Static void uhci_unlock_frames(uhci_softc_t *);
Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);
@@ -249,8 +241,8 @@ Static void uhci_softintr(struct usbd_bus *);
Static usbd_status uhci_device_request(usbd_xfer_handle xfer);
-Static void uhci_add_intr(uhci_softc_t *, int, uhci_soft_qh_t *);
-Static void uhci_remove_intr(uhci_softc_t *, int, uhci_soft_qh_t *);
+Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *);
+Static void uhci_remove_intr(uhci_softc_t*, uhci_soft_qh_t*);
Static usbd_status uhci_device_setintr(uhci_softc_t *sc,
struct uhci_pipe *pipe, int ival);
@@ -260,7 +252,6 @@ Static void uhci_noop(usbd_pipe_handle pipe);
Static __inline__ uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *,
uhci_soft_qh_t *);
-
#ifdef UHCI_DEBUG
Static void uhci_dump_all(uhci_softc_t *);
Static void uhci_dumpregs(uhci_softc_t *);
@@ -352,6 +343,11 @@ struct usbd_pipe_methods uhci_device_isoc_methods = {
uhci_device_isoc_done,
};
+#define uhci_add_intr_info(sc, ii) \
+ LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list);
+#define uhci_del_intr_info(ii) \
+ LIST_REMOVE((ii), list)
+
Static __inline__ uhci_soft_qh_t *
uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh)
{
@@ -495,6 +491,8 @@ uhci_init(uhci_softc_t *sc)
SIMPLEQ_INIT(&sc->sc_free_xfers);
+ usb_callout_init(sc->sc_poll_handle);
+
/* Set up the bus struct. */
sc->sc_bus.methods = &uhci_bus_methods;
sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
@@ -569,8 +567,32 @@ uhci_detach(struct uhci_softc *sc, int flags)
usbd_status
uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
{
- return (usb_allocmem(&((struct uhci_softc *)bus)->sc_bus, size, 0,
- dma));
+ struct uhci_softc *sc = (struct uhci_softc *)bus;
+ u_int32_t n;
+
+ /*
+ * XXX
+ * Since we are allocating a buffer we can assume that we will
+ * need TDs for it. Since we don't want to alolocate those from
+ * an interrupt context, we allocate them here and free them again.
+ * This is no guarantee that we'll get the TDs next time...
+ */
+ n = size / 8;
+ if (n > 16) {
+ u_int32_t i;
+ uhci_soft_td_t **stds;
+ DPRINTF(("uhci_allocm: get %d TDs\n", n));
+ stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP, M_NOWAIT);
+ memset(stds, 0, sizeof(uhci_soft_td_t *) * n);
+ for(i=0; i < n; i++)
+ stds[i] = uhci_alloc_std(sc);
+ for(i=0; i < n; i++)
+ if (stds[i] != NULL)
+ uhci_free_std(sc, stds[i]);
+ free(stds, M_TEMP);
+ }
+
+ return (usb_allocmem(&sc->sc_bus, size, 0, dma));
}
void
@@ -586,12 +608,27 @@ uhci_allocx(struct usbd_bus *bus)
usbd_xfer_handle xfer;
xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
- if (xfer != NULL)
+ if (xfer != NULL) {
SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, xfer, next);
- else
- xfer = malloc(sizeof(*xfer), M_USB, M_NOWAIT);
- if (xfer != NULL)
- memset(xfer, 0, sizeof *xfer);
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_FREE) {
+ printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer,
+ xfer->busy_free);
+ }
+#endif
+ } else {
+ xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT);
+ }
+ if (xfer != NULL) {
+ memset(xfer, 0, sizeof (struct uhci_xfer));
+ UXFER(xfer)->iinfo.sc = sc;
+#ifdef DIAGNOSTIC
+ UXFER(xfer)->iinfo.isdone = 1;
+#endif
+ }
+#ifdef DIAGNOSTIC
+ xfer->busy_free = XFER_BUSY;
+#endif
return (xfer);
}
@@ -600,6 +637,18 @@ uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
{
struct uhci_softc *sc = (struct uhci_softc *)bus;
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_BUSY) {
+ printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer,
+ xfer->busy_free);
+ return;
+ }
+ xfer->busy_free = XFER_FREE;
+ if (!UXFER(xfer)->iinfo.isdone) {
+ printf("uhci_freex: !isdone\n");
+ return;
+ }
+#endif
SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
}
@@ -640,9 +689,9 @@ uhci_power(int why, void *v)
if (uhcidebug > 2)
uhci_dumpregs(sc);
#endif
- if (sc->sc_has_timo != NULL)
- usb_untimeout(uhci_timo, sc->sc_has_timo,
- sc->sc_has_timo->timo_handle);
+ if (sc->sc_intr_xfer != NULL)
+ usb_uncallout(sc->sc_poll_handle, uhci_poll_hub,
+ sc->sc_intr_xfer);
sc->sc_bus.use_polling++;
uhci_run(sc, 0); /* stop the controller */
@@ -678,9 +727,9 @@ uhci_power(int why, void *v)
uhci_run(sc, 1); /* and start traffic again */
usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
sc->sc_bus.use_polling--;
- if (sc->sc_has_timo != NULL)
- usb_timeout(uhci_timo, sc->sc_has_timo,
- sc->sc_ival, sc->sc_has_timo->timo_handle);
+ if (sc->sc_intr_xfer != NULL)
+ usb_callout(sc->sc_poll_handle, sc->sc_ival,
+ uhci_poll_hub, sc->sc_intr_xfer);
#ifdef UHCI_DEBUG
if (uhcidebug > 2)
uhci_dumpregs(sc);
@@ -747,6 +796,60 @@ uhci_dump(void)
{
uhci_dump_all(thesc);
}
+
+void
+uhci_dump_ii(uhci_intr_info_t *ii)
+{
+ usbd_pipe_handle pipe;
+ usb_endpoint_descriptor_t *ed;
+ usbd_device_handle dev;
+
+#ifdef DIAGNOSTIC
+#define DONE ii->isdone
+#else
+#define DONE 0
+#endif
+ if (ii == NULL) {
+ printf("ii NULL\n");
+ return;
+ }
+ if (ii->xfer == NULL) {
+ printf("ii %p: done=%d xfer=NULL\n",
+ ii, DONE);
+ return;
+ }
+ pipe = ii->xfer->pipe;
+ if (pipe == NULL) {
+ printf("ii %p: done=%d xfer=%p pipe=NULL\n",
+ ii, DONE, ii->xfer);
+ return;
+ }
+ ed = pipe->endpoint->edesc;
+ dev = pipe->device;
+ printf("ii %p: done=%d xfer=%p dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n",
+ ii, DONE, ii->xfer, dev,
+ UGETW(dev->ddesc.idVendor),
+ UGETW(dev->ddesc.idProduct),
+ dev->address, pipe,
+ ed->bEndpointAddress, ed->bmAttributes);
+#undef DONE
+}
+
+void uhci_dump_iis(struct uhci_softc *);
+void
+uhci_dump_iis(sc)
+ struct uhci_softc *sc;
+{
+ uhci_intr_info_t *ii;
+
+ printf("intr_info list:\n");
+ for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))
+ uhci_dump_ii(ii);
+}
+
+void iidump(void);
+void iidump() { uhci_dump_iis(thesc); }
+
#endif
void
@@ -864,7 +967,7 @@ uhci_dump_ii(uhci_intr_info_t *ii)
* from the root controller interrupt pipe for port status change.
*/
void
-uhci_timo(void *addr)
+uhci_poll_hub(void *addr)
{
usbd_xfer_handle xfer = addr;
usbd_pipe_handle pipe = xfer->pipe;
@@ -872,9 +975,9 @@ uhci_timo(void *addr)
int s;
u_char *p;
- DPRINTFN(20, ("uhci_timo\n"));
+ DPRINTFN(20, ("uhci_poll_hub\n"));
- usb_timeout(uhci_timo, xfer, sc->sc_ival, xfer->timo_handle);
+ usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer);
p = KERNADDR(&xfer->dmabuf, 0);
p[0] = 0;
@@ -889,7 +992,6 @@ uhci_timo(void *addr)
xfer->actlen = 1;
xfer->status = USBD_NORMAL_COMPLETION;
s = splusb();
- xfer->hcpriv = 0;
xfer->device->bus->intr_context++;
usb_transfer_complete(xfer);
xfer->device->bus->intr_context--;
@@ -906,59 +1008,6 @@ uhci_root_ctrl_done(usbd_xfer_handle xfer)
{
}
-void
-uhci_lock_frames(uhci_softc_t *sc)
-{
- int s = splusb();
-
- while (sc->sc_vflock & UHCI_HAS_LOCK) {
- sc->sc_vflock |= UHCI_WANT_LOCK;
- tsleep(&sc->sc_vflock, PRIBIO, "uhcqhl", 0);
- }
- sc->sc_vflock = UHCI_HAS_LOCK;
- splx(s);
-}
-
-void
-uhci_unlock_frames(uhci_softc_t *sc)
-{
- int s = splusb();
-
- sc->sc_vflock &= ~UHCI_HAS_LOCK;
- if (sc->sc_vflock & UHCI_WANT_LOCK)
- wakeup(&sc->sc_vflock);
- splx(s);
-}
-
-/*
- * Allocate an interrupt information struct. A free list is kept
- * for fast allocation.
- */
-uhci_intr_info_t *
-uhci_alloc_intr_info(uhci_softc_t *sc)
-{
- uhci_intr_info_t *ii;
-
- ii = LIST_FIRST(&uhci_ii_free);
- if (ii)
- LIST_REMOVE(ii, list);
- else {
- ii = malloc(sizeof(uhci_intr_info_t), M_USBHC, M_NOWAIT);
- }
- ii->sc = sc;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
-
- return ii;
-}
-
-void
-uhci_free_intr_info(uhci_intr_info_t *ii)
-{
- LIST_INSERT_HEAD(&uhci_ii_free, ii, list); /* and put on free list */
-}
-
/*
* Let the last QH loop back to the high speed control transfer QH.
* This is what intel calls "bandwidth reclamation" and improves
@@ -1283,7 +1332,7 @@ uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii)
}
done:
DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii));
- usb_untimeout(uhci_timeout, ii, ii->timeout_handle);
+ usb_uncallout(ii->xfer->timeout_handle, uhci_timeout, ii);
uhci_idone(ii);
}
@@ -1331,7 +1380,7 @@ uhci_idone(uhci_intr_info_t *ii)
nframes = xfer->nframes;
actlen = 0;
- n = xfer->hcprivint;
+ n = UXFER(xfer)->curframe;
for (i = 0; i < nframes; i++) {
std = stds[n];
#ifdef UHCI_DEBUG
@@ -1348,7 +1397,6 @@ uhci_idone(uhci_intr_info_t *ii)
upipe->u.iso.inuse -= nframes;
xfer->actlen = actlen;
xfer->status = USBD_NORMAL_COMPLETION;
- xfer->hcpriv = ii;
usb_transfer_complete(xfer);
return;
}
@@ -1404,8 +1452,6 @@ uhci_idone(uhci_intr_info_t *ii)
} else {
xfer->status = USBD_NORMAL_COMPLETION;
}
- xfer->hcpriv = ii;
-
usb_transfer_complete(xfer);
DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii));
}
@@ -1733,7 +1779,7 @@ uhci_device_bulk_start(usbd_xfer_handle xfer)
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
- uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_soft_td_t *data, *dataend;
uhci_soft_qh_t *sqh;
usbd_status err;
@@ -1752,7 +1798,7 @@ uhci_device_bulk_start(usbd_xfer_handle xfer)
#endif
len = xfer->length;
- endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
+ endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
isread = UE_GET_DIR(endpt) == UE_DIR_IN;
sqh = upipe->u.bulk.sqh;
@@ -1776,28 +1822,24 @@ uhci_device_bulk_start(usbd_xfer_handle xfer)
ii->xfer = xfer;
ii->stdstart = data;
ii->stdend = dataend;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
#ifdef DIAGNOSTIC
- if (!ii->isdone) {
+ if (!ii->isdone)
printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii);
- }
ii->isdone = 0;
#endif
sqh->elink = data;
sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
- sqh->intr_info = ii;
s = splusb();
uhci_add_bulk(sc, sqh);
- LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);
+ uhci_add_intr_info(sc, ii);
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_timeout(uhci_timeout, ii, MS_TO_TICKS(xfer->timeout),
- ii->timeout_handle);
+ usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ uhci_timeout, ii);
}
+ xfer->status = USBD_IN_PROGRESS;
splx(s);
#ifdef UHCI_DEBUG
@@ -1821,20 +1863,34 @@ uhci_device_bulk_abort(usbd_xfer_handle xfer)
uhci_abort_xfer(xfer, USBD_CANCELLED);
}
+/*
+ * XXX This way of aborting is neither safe, nor good.
+ * But it will have to do until I figure out what to do.
+ * I apologize for the delay().
+ */
void
uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
{
- struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
- uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_soft_td_t *std;
+ int s;
DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
+ s = splusb();
+
+ /* Transfer is already done. */
+ if (xfer->status != USBD_NOT_STARTED &&
+ xfer->status != USBD_IN_PROGRESS) {
+ splx(s);
+ return;
+ }
+
/* Make interrupt routine ignore it, */
xfer->status = status;
/* don't timeout, */
- usb_untimeout(uhci_timeout, ii, ii->timeout_handle);
+ usb_uncallout(xfer->timeout_handle, uhci_timeout, ii);
/* make hardware ignore it, */
for (std = ii->stdstart; std != NULL; std = std->link.std)
@@ -1842,34 +1898,13 @@ uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
xfer->hcpriv = ii;
-#if 1
- /* Make sure hardware has completed. */
- if (xfer->device->bus->intr_context) {
- /* We have no process context, so we can't use tsleep(). */
- timeout(uhci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND);
- } else {
-#if defined(DIAGNOSTIC) && defined(__i386__) && defined(__FreeBSD__)
- KASSERT(curthread->td_intr_nesting_level == 0,
- ("ohci_abort_req in interrupt context"));
-#endif
- usb_delay_ms(xfer->pipe->device->bus, 1);
- /* and call final part of interrupt handler. */
- uhci_abort_xfer_end(xfer);
- }
-#else
- delay(1000);
- uhci_abort_xfer_end(xfer);
-#endif
-}
-
-void
-uhci_abort_xfer_end(void *v)
-{
- usbd_xfer_handle xfer = v;
- int s;
+ splx(s);
s = splusb();
- usb_transfer_complete(xfer);
+
+#ifdef DIAGNOSTIC
+ ii->isdone = 1;
+#endif
splx(s);
}
@@ -1882,7 +1917,6 @@ uhci_device_bulk_close(usbd_pipe_handle pipe)
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
uhci_free_sqh(sc, upipe->u.bulk.sqh);
- uhci_free_intr_info(upipe->iinfo);
}
usbd_status
@@ -1895,7 +1929,7 @@ uhci_device_ctrl_transfer(usbd_xfer_handle xfer)
if (err)
return (err);
- /*
+ /*
* Pipe isn't running (otherwise err would be USBD_INPROG),
* so start it first.
*/
@@ -1948,7 +1982,7 @@ uhci_device_intr_start(usbd_xfer_handle xfer)
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
- uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_soft_td_t *data, *dataend;
uhci_soft_qh_t *sqh;
usbd_status err;
@@ -1984,13 +2018,9 @@ uhci_device_intr_start(usbd_xfer_handle xfer)
ii->xfer = xfer;
ii->stdstart = data;
ii->stdend = dataend;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
#ifdef DIAGNOSTIC
- if (!ii->isdone) {
+ if (!ii->isdone)
printf("uhci_device_intr_transfer: not done, ii=%p\n", ii);
- }
ii->isdone = 0;
#endif
@@ -2001,6 +2031,8 @@ uhci_device_intr_start(usbd_xfer_handle xfer)
sqh->elink = data;
sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
}
+ uhci_add_intr_info(sc, ii);
+ xfer->status = USBD_IN_PROGRESS;
splx(s);
#ifdef UHCI_DEBUG
@@ -2026,10 +2058,6 @@ uhci_device_ctrl_abort(usbd_xfer_handle xfer)
void
uhci_device_ctrl_close(usbd_pipe_handle pipe)
{
- struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
-
- uhci_free_intr_info(upipe->iinfo);
- /* XXX free other resources? */
}
/* Abort a device interrupt request. */
@@ -2050,17 +2078,15 @@ uhci_device_intr_close(usbd_pipe_handle pipe)
{
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
- int i, s, npoll;
-
- upipe->iinfo->stdstart = 0; /* inactive */
+ int i, npoll;
+ int s;
/* Unlink descriptors from controller data structures. */
npoll = upipe->u.intr.npoll;
- uhci_lock_frames(sc);
+ s = splusb();
for (i = 0; i < npoll; i++)
- uhci_remove_intr(sc, upipe->u.intr.qhs[i]->pos,
- upipe->u.intr.qhs[i]);
- uhci_unlock_frames(sc);
+ uhci_remove_intr(sc, upipe->u.intr.qhs[i]);
+ splx(s);
/*
* We now have to wait for any activity on the physical
@@ -2072,11 +2098,6 @@ uhci_device_intr_close(usbd_pipe_handle pipe)
uhci_free_sqh(sc, upipe->u.intr.qhs[i]);
free(upipe->u.intr.qhs, M_USBHC);
- s = splusb();
- LIST_REMOVE(upipe->iinfo, list); /* remove from active list */
- splx(s);
- uhci_free_intr_info(upipe->iinfo);
-
/* XXX free other resources */
}
@@ -2089,7 +2110,7 @@ uhci_device_request(usbd_xfer_handle xfer)
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
int addr = dev->address;
int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
- uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_soft_td_t *setup, *data, *stat, *next, *dataend;
uhci_soft_qh_t *sqh;
int len;
@@ -2156,26 +2177,21 @@ uhci_device_request(usbd_xfer_handle xfer)
ii->xfer = xfer;
ii->stdstart = setup;
ii->stdend = stat;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
#ifdef DIAGNOSTIC
- if (!ii->isdone) {
+ if (!ii->isdone)
printf("uhci_device_request: not done, ii=%p\n", ii);
- }
ii->isdone = 0;
#endif
sqh->elink = setup;
sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
- sqh->intr_info = ii;
s = splusb();
if (dev->speed == USB_SPEED_LOW)
uhci_add_ls_ctrl(sc, sqh);
else
uhci_add_hs_ctrl(sc, sqh);
- LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);
+ uhci_add_intr_info(sc, ii);
#ifdef UHCI_DEBUG
if (uhcidebug > 12) {
uhci_soft_td_t *std;
@@ -2204,9 +2220,10 @@ uhci_device_request(usbd_xfer_handle xfer)
}
#endif
if (xfer->timeout && !sc->sc_bus.use_polling) {
- usb_timeout(uhci_timeout, ii,
- MS_TO_TICKS(xfer->timeout), ii->timeout_handle);
+ usb_callout(xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
+ uhci_timeout, ii);
}
+ xfer->status = USBD_IN_PROGRESS;
splx(s);
return (USBD_NORMAL_COMPLETION);
@@ -2275,7 +2292,7 @@ uhci_device_isoc_enter(usbd_xfer_handle xfer)
}
xfer->status = USBD_IN_PROGRESS;
- xfer->hcprivint = next;
+ UXFER(xfer)->curframe = next;
buf = DMAADDR(&xfer->dmabuf, 0);
status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
@@ -2313,7 +2330,7 @@ uhci_device_isoc_start(usbd_xfer_handle xfer)
{
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
- uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_soft_td_t *end;
int s, i;
@@ -2328,7 +2345,7 @@ uhci_device_isoc_start(usbd_xfer_handle xfer)
#endif
/* Find the last TD */
- i = xfer->hcprivint + xfer->nframes;
+ i = UXFER(xfer)->curframe + xfer->nframes;
if (i >= UHCI_VFRAMELIST_COUNT)
i -= UHCI_VFRAMELIST_COUNT;
end = upipe->u.iso.stds[i];
@@ -2346,15 +2363,12 @@ uhci_device_isoc_start(usbd_xfer_handle xfer)
ii->xfer = xfer;
ii->stdstart = end;
ii->stdend = end;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
#ifdef DIAGNOSTIC
if (!ii->isdone)
printf("uhci_device_isoc_start: not done, ii=%p\n", ii);
ii->isdone = 0;
#endif
- LIST_INSERT_HEAD(&sc->sc_intrhead, ii, list);
+ uhci_add_intr_info(sc, ii);
splx(s);
@@ -2365,35 +2379,45 @@ void
uhci_device_isoc_abort(usbd_xfer_handle xfer)
{
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
- uhci_intr_info_t *ii = upipe->iinfo;
uhci_soft_td_t **stds = upipe->u.iso.stds;
uhci_soft_td_t *std;
- int i, n, nframes;
-
- /* Make interrupt routine ignore it, */
+ int i, n, s, nframes, maxlen, len;
+
+ s = splusb();
+
+ /* Transfer is already done. */
+ if (xfer->status != USBD_NOT_STARTED &&
+ xfer->status != USBD_IN_PROGRESS) {
+ splx(s);
+ return;
+ }
+
+ /* Give xfer the requested abort code. */
xfer->status = USBD_CANCELLED;
/* make hardware ignore it, */
nframes = xfer->nframes;
- n = xfer->hcprivint;
+ n = UXFER(xfer)->curframe;
+ maxlen = 0;
for (i = 0; i < nframes; i++) {
std = stds[n];
std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
+ len = UHCI_TD_GET_MAXLEN(std->td.td_token);
+ if (len > maxlen)
+ maxlen = len;
if (++n >= UHCI_VFRAMELIST_COUNT)
n = 0;
}
+ /* and wait until we are sure the hardware has finished. */
+ delay(maxlen);
- xfer->hcpriv = ii;
-
- /* make sure hardware has completed, */
- if (xfer->device->bus->intr_context) {
- /* We have no process context, so we can't use tsleep(). */
- timeout(uhci_abort_xfer_end, xfer, hz / USB_FRAMES_PER_SECOND);
- } else {
- usb_delay_ms(xfer->pipe->device->bus, 1);
- /* and call final part of interrupt handler. */
- uhci_abort_xfer_end(xfer);
- }
+#ifdef DIAGNOSTIC
+ UXFER(xfer)->iinfo.isdone = 1;
+#endif
+ /* Run callback and remove from interrupt list. */
+ usb_transfer_complete(xfer);
+
+ splx(s);
}
void
@@ -2404,7 +2428,7 @@ uhci_device_isoc_close(usbd_pipe_handle pipe)
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
uhci_soft_td_t *std, *vstd;
struct iso *iso;
- int i;
+ int i, s;
/*
* Make sure all TDs are marked as inactive.
@@ -2418,7 +2442,7 @@ uhci_device_isoc_close(usbd_pipe_handle pipe)
iso->stds[i]->td.td_status &= htole32(~UHCI_TD_ACTIVE);
usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */
- uhci_lock_frames(sc);
+ s = splusb();
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
std = iso->stds[i];
for (vstd = sc->sc_vframes[i].htd;
@@ -2428,14 +2452,14 @@ uhci_device_isoc_close(usbd_pipe_handle pipe)
if (vstd == NULL) {
/*panic*/
printf("uhci_device_isoc_close: %p not found\n", std);
- uhci_unlock_frames(sc);
+ splx(s);
return;
}
vstd->link = std->link;
vstd->td.td_link = std->td.td_link;
uhci_free_std(sc, std);
}
- uhci_unlock_frames(sc);
+ splx(s);
free(iso->stds, M_USBHC);
}
@@ -2452,7 +2476,7 @@ uhci_setup_isoc(usbd_pipe_handle pipe)
uhci_soft_td_t *std, *vstd;
u_int32_t token;
struct iso *iso;
- int i;
+ int i, s;
iso = &upipe->u.iso;
iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *),
@@ -2472,7 +2496,7 @@ uhci_setup_isoc(usbd_pipe_handle pipe)
}
/* Insert TDs into schedule. */
- uhci_lock_frames(sc);
+ s = splusb();
for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
std = iso->stds[i];
vstd = sc->sc_vframes[i].htd;
@@ -2481,7 +2505,7 @@ uhci_setup_isoc(usbd_pipe_handle pipe)
vstd->link.std = std;
vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD);
}
- uhci_unlock_frames(sc);
+ splx(s);
iso->next = -1;
iso->inuse = 0;
@@ -2499,14 +2523,34 @@ uhci_setup_isoc(usbd_pipe_handle pipe)
void
uhci_device_isoc_done(usbd_xfer_handle xfer)
{
- uhci_intr_info_t *ii = xfer->hcpriv;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
DPRINTFN(4, ("uhci_isoc_done: length=%d\n", xfer->actlen));
+ if (ii->xfer != xfer)
+ /* Not on interrupt list, ignore it. */
+ return;
+
+#ifdef DIAGNOSTIC
+ if (xfer->busy_free != XFER_BUSY) {
+ printf("uhci_device_isoc_done: xfer=%p not busy 0x%08x\n",
+ xfer, xfer->busy_free);
+ return;
+ }
+
+ if (ii->stdend == NULL) {
+ printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer);
+#ifdef UHCI_DEBUG
+ uhci_dump_ii(ii);
+#endif
+ return;
+ }
+#endif
+
/* Turn off the interrupt since it is active even if the TD is not. */
ii->stdend->td.td_status &= htole32(~UHCI_TD_IOC);
- LIST_REMOVE(ii, list); /* remove from active list */
+ uhci_del_intr_info(ii); /* remove from active list */
#ifdef DIAGNOSTIC
if (ii->stdend == NULL) {
@@ -2522,7 +2566,7 @@ uhci_device_isoc_done(usbd_xfer_handle xfer)
void
uhci_device_intr_done(usbd_xfer_handle xfer)
{
- uhci_intr_info_t *ii = xfer->hcpriv;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_softc_t *sc = ii->sc;
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
uhci_soft_qh_t *sqh;
@@ -2559,9 +2603,6 @@ uhci_device_intr_done(usbd_xfer_handle xfer)
ii->stdstart = data;
ii->stdend = dataend;
-#if defined(__FreeBSD__)
- callout_handle_init(&ii->timeout_handle);
-#endif
#ifdef DIAGNOSTIC
if (!ii->isdone) {
printf("uhci_device_intr_done: not done, ii=%p\n", ii);
@@ -2573,9 +2614,11 @@ uhci_device_intr_done(usbd_xfer_handle xfer)
sqh->elink = data;
sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
}
+ xfer->status = USBD_IN_PROGRESS;
+ /* The ii is already on the examined list, just leave it. */
} else {
- ii->stdstart = 0; /* mark as inactive */
DPRINTFN(5,("uhci_device_intr_done: removing\n"));
+ uhci_del_intr_info(ii);
}
}
@@ -2583,7 +2626,7 @@ uhci_device_intr_done(usbd_xfer_handle xfer)
void
uhci_device_ctrl_done(usbd_xfer_handle xfer)
{
- uhci_intr_info_t *ii = xfer->hcpriv;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_softc_t *sc = ii->sc;
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
@@ -2592,7 +2635,7 @@ uhci_device_ctrl_done(usbd_xfer_handle xfer)
panic("uhci_ctrl_done: not a request\n");
#endif
- LIST_REMOVE(ii, list); /* remove from active list */
+ uhci_del_intr_info(ii); /* remove from active list */
if (upipe->pipe.device->speed == USB_SPEED_LOW)
uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh);
@@ -2609,11 +2652,11 @@ uhci_device_ctrl_done(usbd_xfer_handle xfer)
void
uhci_device_bulk_done(usbd_xfer_handle xfer)
{
- uhci_intr_info_t *ii = xfer->hcpriv;
+ uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
uhci_softc_t *sc = ii->sc;
struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
- LIST_REMOVE(ii, list); /* remove from active list */
+ uhci_del_intr_info(ii); /* remove from active list */
uhci_remove_bulk(sc, upipe->u.bulk.sqh);
@@ -2624,12 +2667,13 @@ uhci_device_bulk_done(usbd_xfer_handle xfer)
/* Add interrupt QH, called with vflock. */
void
-uhci_add_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh)
+uhci_add_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
{
- struct uhci_vframe *vf = &sc->sc_vframes[n];
+ struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
uhci_soft_qh_t *eqh;
- DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", n, sqh));
+ DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", sqh->pos, sqh));
+
eqh = vf->eqh;
sqh->hlink = eqh->hlink;
sqh->qh.qh_hlink = eqh->qh.qh_hlink;
@@ -2641,12 +2685,12 @@ uhci_add_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh)
/* Remove interrupt QH, called with vflock. */
void
-uhci_remove_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh)
+uhci_remove_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
{
- struct uhci_vframe *vf = &sc->sc_vframes[n];
+ struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
uhci_soft_qh_t *pqh;
- DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", n, sqh));
+ DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", sqh->pos, sqh));
/* See comment in uhci_remove_ctrl() */
if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
@@ -2654,15 +2698,7 @@ uhci_remove_intr(uhci_softc_t *sc, int n, uhci_soft_qh_t *sqh)
delay(UHCI_QH_REMOVE_DELAY);
}
- for (pqh = vf->hqh; pqh->hlink != sqh; pqh = pqh->hlink)
-#if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
- if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) {
- DPRINTF(("uhci_remove_intr: QH not found\n"));
- return;
- }
-#else
- ;
-#endif
+ pqh = uhci_find_prev_qh(vf->hqh, sqh);
pqh->hlink = sqh->hlink;
pqh->qh.qh_hlink = sqh->qh.qh_hlink;
delay(UHCI_QH_REMOVE_DELAY);
@@ -2708,26 +2744,19 @@ uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *upipe, int ival)
}
DPRINTFN(1, ("uhci_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
- upipe->iinfo->stdstart = 0;
for(i = 0; i < npoll; i++) {
upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
sqh->elink = NULL;
sqh->qh.qh_elink = htole32(UHCI_PTR_T);
sqh->pos = MOD(i * ival + bestoffs);
- sqh->intr_info = upipe->iinfo;
}
#undef MOD
s = splusb();
- LIST_INSERT_HEAD(&sc->sc_intrhead, upipe->iinfo, list);
- splx(s);
-
- uhci_lock_frames(sc);
/* Enter QHs into the controller data structures. */
for(i = 0; i < npoll; i++)
- uhci_add_intr(sc, upipe->u.intr.qhs[i]->pos,
- upipe->u.intr.qhs[i]);
- uhci_unlock_frames(sc);
+ uhci_add_intr(sc, upipe->u.intr.qhs[i]);
+ splx(s)
DPRINTFN(5, ("uhci_setintr: returns %p\n", upipe));
return (USBD_NORMAL_COMPLETION);
@@ -2746,6 +2775,10 @@ uhci_open(usbd_pipe_handle pipe)
DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
pipe, pipe->device->address,
ed->bEndpointAddress, sc->sc_addr));
+
+ upipe->aborting = 0;
+ upipe->nexttoggle = 0;
+
if (pipe->device->address == sc->sc_addr) {
switch (ed->bEndpointAddress) {
case USB_CONTROL_ENDPOINT:
@@ -2758,9 +2791,6 @@ uhci_open(usbd_pipe_handle pipe)
return (USBD_INVAL);
}
} else {
- upipe->iinfo = uhci_alloc_intr_info(sc);
- if (upipe->iinfo == 0)
- return (USBD_NOMEM);
switch (ed->bmAttributes & UE_XFERTYPE) {
case UE_CONTROL:
pipe->methods = &uhci_device_ctrl_methods;
@@ -2808,7 +2838,6 @@ uhci_open(usbd_pipe_handle pipe)
return (USBD_NORMAL_COMPLETION);
bad:
- uhci_free_intr_info(upipe->iinfo);
return (USBD_NOMEM);
}
@@ -3236,7 +3265,6 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
err = USBD_NORMAL_COMPLETION;
ret:
xfer->status = err;
- xfer->hcpriv = 0;
s = splusb();
usb_transfer_complete(xfer);
splx(s);
@@ -3263,14 +3291,17 @@ uhci_root_intr_abort(usbd_xfer_handle xfer)
{
uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
- usb_untimeout(uhci_timo, xfer, xfer->timo_handle);
- sc->sc_has_timo = NULL;
-
+ usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, xfer);
+ sc->sc_intr_xfer = NULL;
+
if (xfer->pipe->intrxfer == xfer) {
DPRINTF(("uhci_root_intr_abort: remove\n"));
xfer->pipe->intrxfer = 0;
}
xfer->status = USBD_CANCELLED;
+#ifdef DIAGNOSTIC
+ UXFER(xfer)->iinfo.isdone = 1;
+#endif
usb_transfer_complete(xfer);
}
@@ -3284,8 +3315,9 @@ uhci_root_intr_transfer(usbd_xfer_handle xfer)
if (err)
return (err);
- /* Pipe isn't running (otherwise err would be USBD_INPROG),
- * start first
+ /*
+ * Pipe isn't running (otherwise err would be USBD_INPROG),
+ * so start it first.
*/
return (uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
}
@@ -3304,8 +3336,8 @@ uhci_root_intr_start(usbd_xfer_handle xfer)
return (USBD_IOERROR);
sc->sc_ival = MS_TO_TICKS(xfer->pipe->endpoint->edesc->bInterval);
- usb_timeout(uhci_timo, xfer, sc->sc_ival, xfer->timo_handle);
- sc->sc_has_timo = xfer;
+ usb_callout(sc->sc_poll_handle, sc->sc_ival, uhci_poll_hub, xfer);
+ sc->sc_intr_xfer = xfer;
return (USBD_IN_PROGRESS);
}
@@ -3315,7 +3347,7 @@ uhci_root_intr_close(usbd_pipe_handle pipe)
{
uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
- usb_untimeout(uhci_timo, pipe->intrxfer, pipe->intrxfer->timo_handle);
- sc->sc_has_timo = NULL;
+ usb_uncallout(sc->sc_poll_handle, uhci_poll_hub, sc->sc_intr_xfer);
+ sc->sc_intr_xfer = NULL;
DPRINTF(("uhci_root_intr_close\n"));
}
diff --git a/sys/dev/usb/uhcivar.h b/sys/dev/usb/uhcivar.h
index fd9425a..dadd81c 100644
--- a/sys/dev/usb/uhcivar.h
+++ b/sys/dev/usb/uhcivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: uhcivar.h,v 1.22 2000/01/26 10:04:39 augustss Exp $ */
+/* $NetBSD: uhcivar.h,v 1.27 2000/03/25 18:02:33 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -75,14 +75,19 @@ typedef struct uhci_intr_info {
uhci_soft_td_t *stdstart;
uhci_soft_td_t *stdend;
LIST_ENTRY(uhci_intr_info) list;
-#if defined(__FreeBSD__)
- struct callout_handle timeout_handle;
-#endif /* defined(__FreeBSD__) */
#ifdef DIAGNOSTIC
int isdone;
#endif
} uhci_intr_info_t;
+struct uhci_xfer {
+ struct usbd_xfer xfer;
+ uhci_intr_info_t iinfo;
+ int curframe;
+};
+
+#define UXFER(xfer) ((struct uhci_xfer *)(xfer))
+
/*
* Extra information that we need for a TD.
*/
@@ -109,8 +114,6 @@ struct uhci_soft_qh {
uhci_soft_td_t *elink; /* soft version of qh_elink */
uhci_physaddr_t physaddr; /* QH's physical address. */
int pos; /* Timeslot position */
- uhci_intr_info_t *intr_info; /* Who to call on completion. */
-/* XXX should try to shrink with 4 bytes to fit into 32 bytes */
};
/* See comment about UHCI_STD_SIZE. */
#define UHCI_SQH_SIZE ((sizeof (struct uhci_soft_qh) + UHCI_QH_ALIGN - 1) / UHCI_QH_ALIGN * UHCI_QH_ALIGN)
@@ -170,11 +173,8 @@ typedef struct uhci_softc {
/* Info for the root hub interrupt channel. */
int sc_ival; /* time between root hub intrs */
- usbd_xfer_handle sc_has_timo; /* root hub interrupt transfer */
-
- char sc_vflock; /* for lock virtual frame list */
-#define UHCI_HAS_LOCK 1
-#define UHCI_WANT_LOCK 2
+ usbd_xfer_handle sc_intr_xfer; /* root hub interrupt transfer */
+ usb_callout_t sc_poll_handle;
char sc_vendor[16]; /* vendor string for root hub */
int sc_id_vendor; /* vendor ID for root hub */
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index bb7193d..9355d82 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -97,7 +97,7 @@ struct ums_softc {
struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
struct hid_location *sc_loc_btn;
- struct callout_handle timeout_handle; /* for spurious button ups */
+ usb_callout_t callout_handle; /* for spurious button ups */
int sc_enabled;
int sc_disconnected; /* device is gone */
@@ -470,12 +470,11 @@ ums_intr(xfer, addr, status)
*/
if (sc->flags & UMS_SPUR_BUT_UP &&
dx == 0 && dy == 0 && dz == 0 && buttons == 0) {
- usb_timeout(ums_add_to_queue_timeout, (void *) sc,
- MS_TO_TICKS(50 /*msecs*/), sc->timeout_handle);
+ usb_callout(sc->callout_handle, MS_TO_TICKS(50 /*msecs*/),
+ ums_add_to_queue_timeout, (void *) sc);
} else {
- usb_untimeout(ums_add_to_queue_timeout, (void *) sc,
- sc->timeout_handle);
-
+ usb_uncallout(sc->callout_handle,
+ ums_add_to_queue_timeout, (void *) sc);
ums_add_to_queue(sc, dx, dy, dz, buttons);
}
}
@@ -556,7 +555,7 @@ ums_enable(v)
sc->status.button = sc->status.obutton = 0;
sc->status.dx = sc->status.dy = sc->status.dz = 0;
- callout_handle_init(&sc->timeout_handle);
+ callout_handle_init((struct callout_handle *)&sc->callout_handle);
/* Set up interrupt pipe. */
err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
@@ -578,7 +577,7 @@ ums_disable(priv)
{
struct ums_softc *sc = priv;
- usb_untimeout(ums_add_to_queue_timeout, sc, sc->timeout_handle);
+ usb_uncallout(sc->callout_handle, ums_add_to_queue_timeout, sc);
/* Disable interrupts. */
usbd_abort_pipe(sc->sc_intrpipe);
diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h
index 1f4b191..f0d3aaa 100644
--- a/sys/dev/usb/usb_port.h
+++ b/sys/dev/usb/usb_port.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_port.h,v 1.15 1999/11/16 12:04:28 augustss Exp $ */
+/* $NetBSD: usb_port.h,v 1.23 2000/03/24 22:03:32 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -81,8 +81,10 @@ typedef struct device *device_ptr_t;
u_int offs; \
} usb_dma_t
-#define usb_timeout(f, d, t, h) timeout((f), (d), (t))
-#define usb_untimeout(f, d, h) untimeout((f), (d))
+typedef struct callout usb_callout_t;
+#define usb_callout_init(h) callout_handle_init(&(h))
+#define usb_callout(h, t, f, d) ((h) = timeout((f), (d), (t)))
+#define usb_uncallout(h, f, d) untimeout((f), (d))
#define logprintf printf
@@ -203,8 +205,10 @@ typedef struct device device_ptr_t;
u_int offs; \
} usb_dma_t
-#define usb_timeout(f, d, t, h) timeout((f), (d), (t))
-#define usb_untimeout(f, d, h) untimeout((f), (d))
+typedef char usb_callout_t;
+#define usb_callout_init(h)
+#define usb_callout(h, t, f, d) timeout((f), (d), (t))
+#define usb_uncallout(h, f, d) untimeout((f), (d))
#define USB_DECLARE_DRIVER(dname) \
int __CONCAT(dname,_match)(struct device *, void *, void *); \
@@ -320,8 +324,10 @@ typedef struct thread *usb_proc_ptr;
#define config_pending_incr()
#define config_pending_decr()
-#define usb_timeout(f, d, t, h) ((h) = timeout((f), (d), (t)))
-#define usb_untimeout(f, d, h) untimeout((f), (d), (h))
+typedef struct callout usb_callout_t;
+#define usb_callout_init(h) callout_init(&(h), 0)
+#define usb_callout(h, t, f, d) callout_reset(&(h), (t), (f), (d))
+#define usb_uncallout(h, f, d) callout_stop(&(h))
#define clalloc(p, s, x) (clist_alloc_cblocks((p), (s), (s)), 0)
#define clfree(p) clist_free_cblocks((p))
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index d35a621..4932e88 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_subr.c,v 1.76 2000/04/27 15:26:50 augustss Exp $ */
+/* $NetBSD: usb_subr.c,v 1.70 2000/03/29 01:45:20 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -696,9 +696,11 @@ usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface,
p->refcnt = 1;
p->intrxfer = 0;
p->running = 0;
+ p->aborting = 0;
p->repeat = 0;
p->interval = ival;
SIMPLEQ_INIT(&p->queue);
+ usb_callout_init(p->abort_handle);
err = dev->bus->methods->open_pipe(p);
if (err) {
DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error="
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 368b695..1ce6fd1 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi.c,v 1.60 2000/01/19 00:23:58 augustss Exp $ */
+/* $NetBSD: usbdi.c,v 1.71 2000/03/29 01:45:21 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -237,6 +237,12 @@ usbd_close_pipe(pipe)
LIST_REMOVE(pipe, next);
pipe->endpoint->refcnt--;
pipe->methods->close(pipe);
+#if defined(__NetBSD__) && defined(DIAGNOSTIC)
+ if (callout_pending(&pipe->abort_handle)) {
+ callout_stop(&pipe->abort_handle);
+ printf("usbd_close_pipe: abort_handle pending");
+ }
+#endif
if (pipe->intrxfer != NULL)
usbd_free_xfer(pipe->intrxfer);
free(pipe, M_USB);
@@ -261,6 +267,9 @@ usbd_transfer(xfer)
#endif
xfer->done = 0;
+ if (pipe->aborting)
+ return (USBD_CANCELLED);
+
size = xfer->length;
/* If there is no buffer, allocate one. */
if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) {
@@ -314,8 +323,10 @@ usbd_transfer(xfer)
if (xfer->done)
break;
}
- if (!xfer->done)
+ if (!xfer->done) {
pipe->methods->abort(xfer);
+ xfer->status = USBD_TIMEOUT;
+ }
} else
/* XXX End hack XXX */
tsleep(xfer, PRIBIO, "usbsyn", 0);
@@ -381,6 +392,7 @@ usbd_alloc_xfer(dev)
if (xfer == NULL)
return (NULL);
xfer->device = dev;
+ usb_callout_init(xfer->timeout_handle);
DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer));
return (xfer);
}
@@ -392,6 +404,12 @@ usbd_free_xfer(xfer)
DPRINTFN(5,("usbd_free_xfer: %p\n", xfer));
if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
usbd_free_buffer(xfer);
+#if defined(__NetBSD__) && defined(DIAGNOSTIC)
+ if (callout_pending(&xfer->timeout_handle)) {
+ callout_stop(&xfer->timeout_handle);
+ printf("usbd_free_xfer: timout_handle pending");
+ }
+#endif
xfer->device->bus->methods->freex(xfer->device->bus, xfer);
return (USBD_NORMAL_COMPLETION);
}
@@ -607,13 +625,11 @@ usbd_clear_endpoint_stall_async(pipe)
}
void
-usbd_clear_endpoint_toggle(pipe)
- usbd_pipe_handle pipe;
+usbd_clear_endpoint_toggle(usbd_pipe_handle pipe)
{
pipe->methods->cleartoggle(pipe);
}
-
usbd_status
usbd_endpoint_count(iface, count)
usbd_interface_handle iface;
@@ -752,6 +768,7 @@ usbd_ar_pipe(pipe)
usbd_dump_queue(pipe);
#endif
pipe->repeat = 0;
+ pipe->aborting = 1;
while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) {
DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n",
pipe, xfer, pipe->methods));
@@ -759,6 +776,7 @@ usbd_ar_pipe(pipe)
pipe->methods->abort(xfer);
/* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
}
+ pipe->aborting = 0;
return (USBD_NORMAL_COMPLETION);
}
@@ -809,9 +827,6 @@ usb_transfer_complete(xfer)
}
}
- if (pipe->methods->done != NULL)
- pipe->methods->done(xfer);
-
if (!repeat) {
/* Remove request from queue. */
#ifdef DIAGNOSTIC
@@ -821,6 +836,8 @@ usb_transfer_complete(xfer)
#endif
SIMPLEQ_REMOVE_HEAD(&pipe->queue, xfer, next);
}
+ DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n",
+ repeat, SIMPLEQ_FIRST(&pipe->queue)));
/* Count completed transfers. */
++pipe->device->bus->stats.uds_requests
@@ -837,6 +854,15 @@ usb_transfer_complete(xfer)
if (xfer->callback)
xfer->callback(xfer, xfer->priv, xfer->status);
+#ifdef DIAGNOSTIC
+ if (pipe->methods->done != NULL)
+ pipe->methods->done(xfer);
+ else
+ printf("usb_transfer_complete: pipe->methods->done == NULL\n");
+#else
+ pipe->methods->done(xfer);
+#endif
+
if ((xfer->flags & USBD_SYNCHRONOUS) && !polling)
wakeup(xfer);
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 4ad129d..74f5e5e 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdivar.h,v 1.47 2000/02/22 11:30:56 augustss Exp $ */
+/* $NetBSD: usbdivar.h,v 1.53 2000/03/29 01:45:21 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -38,6 +38,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/callout.h>
+
/* From usb_mem.h */
DECLARE_USB_DMA_T;
@@ -156,6 +158,7 @@ struct usbd_pipe {
struct usbd_endpoint *endpoint;
int refcnt;
char running;
+ char aborting;
SIMPLEQ_HEAD(, usbd_xfer) queue;
LIST_ENTRY(usbd_pipe) next;
@@ -163,6 +166,8 @@ struct usbd_pipe {
char repeat;
int interval;
+ usb_callout_t abort_handle;
+
/* Filled by HC driver. */
struct usbd_pipe_methods *methods;
};
@@ -178,6 +183,11 @@ struct usbd_xfer {
usbd_status status;
usbd_callback callback;
__volatile char done;
+#ifdef DIAGNOSTIC
+ u_int32_t busy_free;
+#define XFER_FREE 0x46524545
+#define XFER_BUSY 0x42555357
+#endif
/* For control pipe */
usb_device_request_t request;
@@ -198,11 +208,8 @@ struct usbd_xfer {
SIMPLEQ_ENTRY(usbd_xfer) next;
void *hcpriv; /* private use by the HC driver */
- int hcprivint;
-#if defined(__FreeBSD__)
- struct callout_handle timo_handle;
-#endif
+ usb_callout_t timeout_handle;
};
void usbd_init(void);
OpenPOWER on IntegriCloud