svn commit: r213491 - user/weongyo/usb/sys/dev/usb
Weongyo Jeong
weongyo at FreeBSD.org
Wed Oct 6 19:32:12 UTC 2010
Author: weongyo
Date: Wed Oct 6 19:32:12 2010
New Revision: 213491
URL: http://svn.freebsd.org/changeset/base/213491
Log:
A code cleanup of usbd_transfer_setup() to remove `while (1)'. It's
seperated into two step and added comments what each step's doing.
Modified:
user/weongyo/usb/sys/dev/usb/usb_transfer.c
Modified: user/weongyo/usb/sys/dev/usb/usb_transfer.c
==============================================================================
--- user/weongyo/usb/sys/dev/usb/usb_transfer.c Wed Oct 6 18:51:22 2010 (r213490)
+++ user/weongyo/usb/sys/dev/usb/usb_transfer.c Wed Oct 6 19:32:12 2010 (r213491)
@@ -700,20 +700,16 @@ usbd_transfer_setup(struct usb_device *u
const struct usb_config *setup_end = setup_start + n_setup;
const struct usb_config *setup;
struct usb_endpoint *ep;
- struct usb_xfer_root *info;
+ struct usb_xfer_root *info = NULL;
struct usb_xfer *xfer;
+ enum usb_dev_speed speed = usbd_get_speed(udev);
void *buf = NULL;
uint16_t n;
- uint16_t refcount;
-
- parm.err = 0;
- refcount = 0;
- info = NULL;
+ uint16_t refcount = 0;
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"usbd_transfer_setup can sleep!");
- /* do some checking first */
if (n_setup == 0) {
DPRINTFN(6, "setup array has zero length!\n");
return (USB_ERR_INVAL);
@@ -722,293 +718,312 @@ usbd_transfer_setup(struct usb_device *u
DPRINTFN(6, "ifaces array is NULL!\n");
return (USB_ERR_INVAL);
}
+ if (speed >= USB_SPEED_MAX) {
+ DPRINTFN(6, "invalid USB speed (%d)\n", speed);
+ return (USB_ERR_INVAL);
+ }
if (xfer_mtx == NULL) {
DPRINTFN(6, "using global lock\n");
xfer_mtx = &Giant;
}
- /* sanity checks */
- for (setup = setup_start, n = 0;
- setup != setup_end; setup++, n++) {
+
+ /*
+ * To set up USB xfer structures, usbd_transfer_setup() has TWO step
+ * approach. In step 1 it handles exceptional cases, calculates
+ * the buffer size and set `struct usb_setup_params' structure
+ * properly before going into step 2. In step 2 it's doing real job
+ * to set up a xfer.
+ */
+
+ bzero(&parm, sizeof(parm));
+ parm.udev = udev;
+ parm.speed = speed;
+ parm.hc_max_packet_count = 1;
+ parm.buf = NULL;
+ parm.needbufsize = sizeof(info[0]);
+
+ /*
+ * Step 1: handle exceptional cases and calculate the buffer size.
+ *
+ * Please see parm.needbufsize and parm.bufoffset[] carefully to set
+ * up the buffer layout. It'd finally allocate just one virtually
+ * linear kernel buffer which has several sections for DMA page
+ * structures, xfer page structures and etc.
+ */
+
+ for (setup = setup_start, n = 0; setup != setup_end; setup++, n++) {
if (setup->bufsize == (usb_frlength_t)-1) {
- parm.err = USB_ERR_BAD_BUFSIZE;
DPRINTF("invalid bufsize\n");
+ parm.err = USB_ERR_BAD_BUFSIZE;
+ goto done;
}
if (setup->callback == NULL) {
- parm.err = USB_ERR_NO_CALLBACK;
DPRINTF("no callback\n");
+ parm.err = USB_ERR_NO_CALLBACK;
+ goto done;
}
- ppxfer[n] = NULL;
- }
+ USB_ASSERT(ppxfer[n] == NULL, ("ppxfer[%d] != NULL", n));
- if (parm.err)
- goto done;
- bzero(&parm, sizeof(parm));
+ /* see if there is a matching endpoint */
+ ep = usbd_get_endpoint(udev, ifaces[setup->if_index], setup);
+ if (ep == NULL || ep->methods == NULL) {
+ if ((setup->flags & USBD_NO_PIPE_OK) != 0)
+ continue;
+ if (setup->usb_mode != USB_MODE_DUAL &&
+ setup->usb_mode != udev->flags.usb_mode)
+ continue;
+ parm.err = USB_ERR_NO_PIPE;
+ goto done;
+ }
- parm.udev = udev;
- parm.speed = usbd_get_speed(udev);
- parm.hc_max_packet_count = 1;
+ /* align data properly */
+ parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
- if (parm.speed >= USB_SPEED_MAX) {
- parm.err = USB_ERR_INVAL;
- goto done;
- }
- /* setup all transfers */
- while (1) {
- if (buf) {
- /*
- * Initialize the "usb_xfer_root" structure,
- * which is common for all our USB transfers.
- */
- info = USB_ADD_BYTES(buf, 0);
+ /* store current setup pointer */
+ parm.curr_setup = setup;
- info->memory_base = buf;
- info->memory_size = parm.needbufsize;
+ /*
+ * Setup a dummy xfer, hence we are writing to the "usb_xfer"
+ * structure pointed to by "xfer" before we have allocated any
+ * memory:
+ */
+ xfer = &dummy;
+ bzero(&dummy, sizeof(dummy));
+ refcount++;
+
+ /* set transfer endpoint pointer */
+ xfer->endpoint = ep;
+
+ parm.needbufsize += sizeof(xfer[0]);
+ parm.methods = xfer->endpoint->methods;
+ parm.curr_xfer = xfer;
-#if USB_HAVE_BUSDMA
- info->dma_page_cache_start = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_DMA_PAGECACHE]);
- info->dma_page_cache_end = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_XFER_PAGECACHE]);
-#endif
- info->xfer_page_cache_start = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_XFER_PAGECACHE]);
- info->xfer_page_cache_end = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_XFER_PAGECACHE_END]);
+ /*
+ * Call the Host or Device controller transfer
+ * setup routine:
+ */
+ (udev->bus->methods->xfer_setup) (&parm);
+ if (parm.err)
+ goto done;
+ }
+ USB_ASSERT(refcount != 0, ("refcount == 0"));
- cv_init(&info->cv_drain, "WDRAIN");
+ /* align data properly */
+ parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
- info->xfer_mtx = xfer_mtx;
-#if USB_HAVE_BUSDMA
- usb_dma_tag_setup(&info->dma_parent_tag,
- parm.dma_tag_p, udev->bus->dma_parent_tag[0].tag,
- xfer_mtx, &usb_bdma_done_event, 32, parm.dma_tag_max);
-#endif
+ /* store offset temporarily */
+ parm.bufoffset[USB_SETUP_DMA_TAG] = parm.needbufsize;
- info->bus = udev->bus;
- info->udev = udev;
+ /*
+ * The number of DMA tags required depends on the number of endpoints.
+ * The current estimate for maximum number of DMA tags per endpoint
+ * is two.
+ */
+ parm.dma_tag_max += 2 * MIN(n_setup, USB_EP_MAX);
- TAILQ_INIT(&info->done_q.head);
- info->done_q.command = &usbd_callback_wrapper;
-#if USB_HAVE_BUSDMA
- TAILQ_INIT(&info->dma_q.head);
- info->dma_q.command = &usb_bdma_work_loop;
-#endif
- TASK_INIT(&info->done_task, 0, usb_callback_proc, info);
+ /*
+ * DMA tags for QH, TD, Data and more.
+ */
+ parm.dma_tag_max += 8;
- /*
- * In device side mode control endpoint
- * requests need to run from a separate
- * context, else there is a chance of
- * deadlock!
- */
- if (setup_start == usb_control_ep_cfg)
- info->done_tq = udev->bus->control_xfer_tq;
- else if (xfer_mtx == &Giant)
- info->done_tq = udev->bus->giant_callback_tq;
- else
- info->done_tq =
- udev->bus->non_giant_callback_tq;
- }
- /* reset sizes */
- parm.needbufsize = 0;
- parm.buf = buf;
- parm.needbufsize += sizeof(info[0]);
-
- for (setup = setup_start, n = 0;
- setup != setup_end; setup++, n++) {
- /* skip USB transfers without callbacks: */
- if (setup->callback == NULL)
- continue;
- /* see if there is a matching endpoint */
- ep = usbd_get_endpoint(udev,
- ifaces[setup->if_index], setup);
-
- if (ep == NULL || ep->methods == NULL) {
- if ((setup->flags & USBD_NO_PIPE_OK) != 0)
- continue;
- if (setup->usb_mode != USB_MODE_DUAL &&
- setup->usb_mode != udev->flags.usb_mode)
- continue;
- parm.err = USB_ERR_NO_PIPE;
- goto done;
- }
+ parm.dma_tag_p += parm.dma_tag_max;
- /* align data properly */
- parm.needbufsize = roundup(parm.needbufsize,
- USB_HOST_ALIGN);
+ parm.needbufsize += ((uint8_t *)parm.dma_tag_p) - ((uint8_t *)0);
- /* store current setup pointer */
- parm.curr_setup = setup;
+ /* align data properly */
+ parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
- if (buf) {
- /*
- * Common initialization of the
- * "usb_xfer" structure.
- */
- xfer = USB_ADD_BYTES(buf, parm.needbufsize);
- xfer->address = udev->address;
- xfer->priv_sc = priv_sc;
- xfer->xroot = info;
+ /* store offset temporarily */
+ parm.bufoffset[USB_SETUP_DMA_PAGE] = parm.needbufsize;
- usb_callout_init_mtx(&xfer->timeout_handle,
- &udev->bus->bus_mtx, 0);
- } else {
- /*
- * Setup a dummy xfer, hence we are
- * writing to the "usb_xfer"
- * structure pointed to by "xfer"
- * before we have allocated any
- * memory:
- */
- xfer = &dummy;
- bzero(&dummy, sizeof(dummy));
- refcount++;
- }
+ parm.needbufsize += ((uint8_t *)parm.dma_page_ptr) - ((uint8_t *)0);
- /* set transfer endpoint pointer */
- xfer->endpoint = ep;
+ /* align data properly */
+ parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
- parm.needbufsize += sizeof(xfer[0]);
- parm.methods = xfer->endpoint->methods;
- parm.curr_xfer = xfer;
+ /* store offset temporarily */
+ parm.bufoffset[USB_SETUP_DMA_PAGECACHE] = parm.needbufsize;
- /*
- * Call the Host or Device controller transfer
- * setup routine:
- */
- (udev->bus->methods->xfer_setup) (&parm);
+ parm.needbufsize += ((uint8_t *)parm.dma_page_cache_ptr) -
+ ((uint8_t *)0);
- /* check for error */
- if (parm.err)
- goto done;
+ /* store end offset temporarily */
+ parm.bufoffset[USB_SETUP_XFER_PAGECACHE] = parm.needbufsize;
- if (buf) {
- /*
- * Increment the endpoint refcount. This
- * basically prevents setting a new
- * configuration and alternate setting
- * when USB transfers are in use on
- * the given interface. Search the USB
- * code for "endpoint->refcount_alloc" if you
- * want more information.
- */
- USB_BUS_LOCK(info->bus);
- if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX)
- parm.err = USB_ERR_INVAL;
-
- xfer->endpoint->refcount_alloc++;
-
- if (xfer->endpoint->refcount_alloc == 0)
- panic("usbd_transfer_setup(): Refcount wrapped to zero\n");
- USB_BUS_UNLOCK(info->bus);
+ parm.needbufsize += ((uint8_t *)parm.xfer_page_cache_ptr) -
+ ((uint8_t *)0);
- /*
- * Whenever we set ppxfer[] then we
- * also need to increment the
- * "setup_refcount":
- */
- info->setup_refcount++;
+ /* store end offset temporarily */
+ parm.bufoffset[USB_SETUP_XFER_PAGECACHE_END] = parm.needbufsize;
- /*
- * Transfer is successfully setup and
- * can be used:
- */
- ppxfer[n] = xfer;
- }
+ /* align data properly */
+ parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
- /* check for error */
- if (parm.err)
- goto done;
- }
+ parm.bufoffset[USB_SETUP_XFERLEN] = parm.needbufsize;
- if (buf || parm.err)
- goto done;
- if (refcount == 0) {
- /* no transfers - nothing to do ! */
- goto done;
- }
- /* align data properly */
- parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
-
- /* store offset temporarily */
- parm.bufoffset[USB_SETUP_DMA_TAG] = parm.needbufsize;
-
- /*
- * The number of DMA tags required depends on
- * the number of endpoints. The current estimate
- * for maximum number of DMA tags per endpoint
- * is two.
- */
- parm.dma_tag_max += 2 * MIN(n_setup, USB_EP_MAX);
+ parm.needbufsize += ((uint8_t *)parm.xfer_length_ptr) - ((uint8_t *)0);
- /*
- * DMA tags for QH, TD, Data and more.
- */
- parm.dma_tag_max += 8;
+ /* align data properly */
+ parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
- parm.dma_tag_p += parm.dma_tag_max;
+ /* allocate zeroed memory */
+ buf = malloc(parm.needbufsize, M_USB, M_WAITOK | M_ZERO);
- parm.needbufsize += ((uint8_t *)parm.dma_tag_p) -
- ((uint8_t *)0);
+ if (buf == NULL) {
+ parm.err = USB_ERR_NOMEM;
+ DPRINTFN(0, "cannot allocate memory block for "
+ "configuration (%d bytes)\n", parm.needbufsize);
+ goto done;
+ }
+ parm.dma_tag_p = USB_ADD_BYTES(buf, parm.bufoffset[USB_SETUP_DMA_TAG]);
+ parm.dma_page_ptr = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_DMA_PAGE]);
+ parm.dma_page_cache_ptr = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_DMA_PAGECACHE]);
+ parm.xfer_page_cache_ptr = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_XFER_PAGECACHE]);
+ parm.xfer_length_ptr = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_XFERLEN]);
- /* align data properly */
- parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
+ /*
+ * Step 2: fills the allocated buffer with valid values.
+ *
+ * The allocated buffer at above would have all informations and
+ * USB buffers to send or receive USB transfers.
+ */
- /* store offset temporarily */
- parm.bufoffset[USB_SETUP_DMA_PAGE] = parm.needbufsize;
+ /*
+ * Initialize the "usb_xfer_root" structure, which is common for all
+ * our USB transfers.
+ */
+ info = USB_ADD_BYTES(buf, 0);
- parm.needbufsize += ((uint8_t *)parm.dma_page_ptr) -
- ((uint8_t *)0);
+ info->memory_base = buf;
+ info->memory_size = parm.needbufsize;
- /* align data properly */
- parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
+#if USB_HAVE_BUSDMA
+ info->dma_page_cache_start = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_DMA_PAGECACHE]);
+ info->dma_page_cache_end = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_XFER_PAGECACHE]);
+#endif
+ info->xfer_page_cache_start = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_XFER_PAGECACHE]);
+ info->xfer_page_cache_end = USB_ADD_BYTES(buf,
+ parm.bufoffset[USB_SETUP_XFER_PAGECACHE_END]);
- /* store offset temporarily */
- parm.bufoffset[USB_SETUP_DMA_PAGECACHE] = parm.needbufsize;
+ cv_init(&info->cv_drain, "WDRAIN");
- parm.needbufsize += ((uint8_t *)parm.dma_page_cache_ptr) -
- ((uint8_t *)0);
+ info->xfer_mtx = xfer_mtx;
+#if USB_HAVE_BUSDMA
+ usb_dma_tag_setup(&info->dma_parent_tag,
+ parm.dma_tag_p, udev->bus->dma_parent_tag[0].tag,
+ xfer_mtx, &usb_bdma_done_event, 32, parm.dma_tag_max);
+#endif
- /* store end offset temporarily */
- parm.bufoffset[USB_SETUP_XFER_PAGECACHE] = parm.needbufsize;
+ info->bus = udev->bus;
+ info->udev = udev;
- parm.needbufsize += ((uint8_t *)parm.xfer_page_cache_ptr) -
- ((uint8_t *)0);
+ TAILQ_INIT(&info->done_q.head);
+ info->done_q.command = &usbd_callback_wrapper;
+#if USB_HAVE_BUSDMA
+ TAILQ_INIT(&info->dma_q.head);
+ info->dma_q.command = &usb_bdma_work_loop;
+#endif
+ TASK_INIT(&info->done_task, 0, usb_callback_proc, info);
- /* store end offset temporarily */
- parm.bufoffset[USB_SETUP_XFER_PAGECACHE_END] = parm.needbufsize;
+ /*
+ * In device side mode control endpoint requests need to run from
+ * a separate context, else there is a chance of deadlock!
+ */
+ if (setup_start == usb_control_ep_cfg)
+ info->done_tq = udev->bus->control_xfer_tq;
+ else if (xfer_mtx == &Giant)
+ info->done_tq = udev->bus->giant_callback_tq;
+ else
+ info->done_tq = udev->bus->non_giant_callback_tq;
+
+ /* reset sizes */
+ parm.needbufsize = 0;
+ parm.buf = buf;
+ parm.needbufsize += sizeof(info[0]);
+
+ for (setup = setup_start, n = 0; setup != setup_end; setup++, n++) {
+ /* see if there is a matching endpoint */
+ ep = usbd_get_endpoint(udev, ifaces[setup->if_index], setup);
+ if (ep == NULL || ep->methods == NULL) {
+ if ((setup->flags & USBD_NO_PIPE_OK) != 0)
+ continue;
+ if (setup->usb_mode != USB_MODE_DUAL &&
+ setup->usb_mode != udev->flags.usb_mode)
+ continue;
+ /* never happen */
+ panic("no pipe");
+ }
/* align data properly */
parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
- parm.bufoffset[USB_SETUP_XFERLEN] = parm.needbufsize;
+ /* store current setup pointer */
+ parm.curr_setup = setup;
- parm.needbufsize += ((uint8_t *)parm.xfer_length_ptr) -
- ((uint8_t *)0);
+ /* Common initialization of the "usb_xfer" structure. */
+ xfer = USB_ADD_BYTES(buf, parm.needbufsize);
+ xfer->address = udev->address;
+ xfer->priv_sc = priv_sc;
+ xfer->xroot = info;
+
+ usb_callout_init_mtx(&xfer->timeout_handle,
+ &udev->bus->bus_mtx, 0);
+
+ /* set transfer endpoint pointer */
+ xfer->endpoint = ep;
+
+ parm.needbufsize += sizeof(xfer[0]);
+ parm.methods = xfer->endpoint->methods;
+ parm.curr_xfer = xfer;
- /* align data properly */
- parm.needbufsize = roundup(parm.needbufsize, USB_HOST_ALIGN);
+ /*
+ * Call the Host or Device controller transfer
+ * setup routine:
+ */
+ (udev->bus->methods->xfer_setup) (&parm);
- /* allocate zeroed memory */
- buf = malloc(parm.needbufsize, M_USB, M_WAITOK | M_ZERO);
+ /* check for error */
+ if (parm.err)
+ goto done;
- if (buf == NULL) {
- parm.err = USB_ERR_NOMEM;
- DPRINTFN(0, "cannot allocate memory block for "
- "configuration (%d bytes)\n",
- parm.needbufsize);
+ /*
+ * Increment the endpoint refcount. This basically prevents
+ * setting a new configuration and alternate setting
+ * when USB transfers are in use on the given interface.
+ * Search the USB code for "endpoint->refcount_alloc" if you
+ * want more information.
+ */
+ USB_BUS_LOCK(info->bus);
+ if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX) {
+ USB_BUS_UNLOCK(info->bus);
+ parm.err = USB_ERR_INVAL;
goto done;
}
- parm.dma_tag_p = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_DMA_TAG]);
- parm.dma_page_ptr = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_DMA_PAGE]);
- parm.dma_page_cache_ptr = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_DMA_PAGECACHE]);
- parm.xfer_page_cache_ptr = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_XFER_PAGECACHE]);
- parm.xfer_length_ptr = USB_ADD_BYTES(buf,
- parm.bufoffset[USB_SETUP_XFERLEN]);
+
+ xfer->endpoint->refcount_alloc++;
+
+ if (xfer->endpoint->refcount_alloc == 0)
+ panic("usbd_transfer_setup(): Refcount wrapped"
+ " to zero\n");
+ USB_BUS_UNLOCK(info->bus);
+
+ /*
+ * Whenever we set ppxfer[] then we also need to increment the
+ * "setup_refcount":
+ */
+ info->setup_refcount++;
+
+ /*
+ * Transfer is successfully setup and can be used:
+ */
+ ppxfer[n] = xfer;
}
done:
More information about the svn-src-user
mailing list