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