From 2b58bea7c0f5553e9753f0d440725eeec3b67bb9 Mon Sep 17 00:00:00 2001 From: Ian Dowse Date: Thu, 8 Dec 2005 03:08:17 +0000 Subject: [PATCH] Reorder the calling of the completion callback and the transfer "done" method so that for non-repeat operations we have completely finished with the transfer by the time the callback is invoked. This makes it possible to recycle a transfer from within the callback routine for the same transfer. Previously this almost worked, but with OHCI controllers calling the "done" method after the callback would zero out some important fields needed by the recycled transfer. Only some usb peripheral drivers such as ucom appear to rely on the ability to reuse a transfer from its callback. MFC after: 1 week --- sys/dev/usb/usbdi.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c index adefde3057d..8246b939c9f 100644 --- a/sys/dev/usb/usbdi.c +++ b/sys/dev/usb/usbdi.c @@ -847,17 +847,21 @@ usb_transfer_complete(usbd_xfer_handle xfer) xfer->status = USBD_SHORT_XFER; } - if (xfer->callback) - xfer->callback(xfer, xfer->priv, xfer->status); - -#ifdef DIAGNOSTIC - if (pipe->methods->done != NULL) + /* + * For repeat operations, call the callback first, as the xfer + * will not go away and the "done" method may modify it. Otherwise + * reverse the order in case the callback wants to free or reuse + * the xfer. + */ + if (repeat) { + if (xfer->callback) + xfer->callback(xfer, xfer->priv, xfer->status); pipe->methods->done(xfer); - else - printf("usb_transfer_complete: pipe->methods->done == NULL\n"); -#else - pipe->methods->done(xfer); -#endif + } else { + pipe->methods->done(xfer); + if (xfer->callback) + xfer->callback(xfer, xfer->priv, xfer->status); + } if (sync && !polling) wakeup(xfer);