PERFORCE change 135146 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Feb 10 03:53:27 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=135146
Change 135146 by hselasky at hselasky_laptop001 on 2008/02/10 11:53:05
Add more documentation to "usb_transfer.c".
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#112 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#112 (text+ko) ====
@@ -68,6 +68,11 @@
#ifdef USB_DEBUG
+/*------------------------------------------------------------------------*
+ * usbd_dump_iface
+ *
+ * This function dumps information about an USB interface.
+ *------------------------------------------------------------------------*/
void
usbd_dump_iface(struct usbd_interface *iface)
{
@@ -80,6 +85,11 @@
return;
}
+/*------------------------------------------------------------------------*
+ * usbd_dump_device
+ *
+ * This function dumps information about an USB device.
+ *------------------------------------------------------------------------*/
void
usbd_dump_device(struct usbd_device *udev)
{
@@ -96,6 +106,11 @@
return;
}
+/*------------------------------------------------------------------------*
+ * usbd_dump_queue
+ *
+ * This function dumps the USB transfer that are queued up on an USB pipe.
+ *------------------------------------------------------------------------*/
void
usbd_dump_queue(struct usbd_pipe *pipe)
{
@@ -108,6 +123,11 @@
return;
}
+/*------------------------------------------------------------------------*
+ * usbd_dump_pipe
+ *
+ * This function dumps information about an USB pipe.
+ *------------------------------------------------------------------------*/
void
usbd_dump_pipe(struct usbd_pipe *pipe)
{
@@ -129,6 +149,11 @@
return;
}
+/*------------------------------------------------------------------------*
+ * usbd_dump_xfer
+ *
+ * This function dumps information about an USB transfer.
+ *------------------------------------------------------------------------*/
void
usbd_dump_xfer(struct usbd_xfer *xfer)
{
@@ -182,8 +207,16 @@
EA_MASK = (UE_DIR_IN | UE_DIR_OUT | UE_ADDR),
};
+ /*
+ * According to the USB specification not all bits are used
+ * for the endpoint address. Mask away the reserved bits:
+ */
ea_val &= EA_MASK;
+ /*
+ * Iterate accross all the USB pipes searching for a match
+ * based on the endpoint address:
+ */
for (; pipe != pipe_end; pipe++) {
if (pipe->edesc == NULL) {
@@ -195,7 +228,9 @@
}
}
- /* do the mask and check the value */
+ /*
+ * The default pipe is always present and is checked separately:
+ */
if ((udev->default_pipe.edesc) &&
((udev->default_pipe.edesc->bEndpointAddress & EA_MASK) == ea_val)) {
pipe = &udev->default_pipe;
@@ -272,8 +307,11 @@
type_val = (setup->type & UE_XFERTYPE);
}
- /* NOTE: pipes are searched from the beginning */
-
+ /*
+ * Iterate accross all the USB pipes searching for a match
+ * based on the endpoint address. Note that we are searching
+ * the pipes from the beginning of the "udev->pipes" array.
+ */
for (; pipe != pipe_end; pipe++) {
if ((pipe->edesc == NULL) ||
@@ -393,7 +431,13 @@
}
/*------------------------------------------------------------------------*
- * usbd_transfer_setup_sub - transfer setup subroutine
+ * usbd_transfer_setup_sub - transfer setup subroutine
+ *
+ * This function must be called from the "xfer_setup" callback of the
+ * USB Host or Device controller driver when setting up an USB
+ * transfer. This function will setup correct packet sizes, buffer
+ * sizes, flags and more, that are stored in the "usbd_xfer"
+ * structure.
*------------------------------------------------------------------------*/
void
usbd_transfer_setup_sub(struct usbd_setup_params *parm)
@@ -412,8 +456,10 @@
uint8_t type;
uint8_t zmps;
- /* sanity check */
-
+ /*
+ * Sanity check. The following parameters must be initialized before
+ * calling this function.
+ */
if ((parm->hc_max_packet_size == 0) ||
(parm->hc_max_packet_count == 0) ||
(parm->hc_max_frame_size == 0)) {
@@ -779,10 +825,15 @@
/*------------------------------------------------------------------------*
* usbd_transfer_setup - setup an array of USB transfers
*
- * NOTE: must always call unsetup after setup
+ * NOTE: You must always call "usbd_transfer_unsetup" after calling
+ * "usbd_transfer_setup" if success was returned.
+ *
+ * The idea is that the USB device driver should pre-allocate all its
+ * transfers by one call to this function.
*
- * The idea is that the USB device driver should pre-allocate all
- * its transfers by one call to this function.
+ * Return values:
+ * 0: Success
+ * Else: Failure
*------------------------------------------------------------------------*/
usbd_status_t
usbd_transfer_setup(struct usbd_device *udev,
@@ -856,7 +907,10 @@
while (1) {
if (buf) {
-
+ /*
+ * Initialize the "usbd_memory_info" structure,
+ * which is common for all our USB transfers.
+ */
info = USBD_ADD_BYTES(buf, 0);
info->memory_base = buf;
@@ -875,6 +929,8 @@
LIST_INIT(&(info->done_head));
+ /* create a callback thread */
+
if (usb_thread_create
(&usbd_callback_intr_td, info,
&(info->done_thread), "USB interrupt thread")) {
@@ -898,12 +954,8 @@
} else {
parm.curr_setup_sub = &(setup->md);
}
-
+ /* skip USB transfers without callbacks: */
if (parm.curr_setup_sub->callback == NULL) {
- /*
- * Skip USB transfers without
- * callbacks !
- */
continue;
}
/* see if there is a matching endpoint */
@@ -920,11 +972,15 @@
/* store current setup pointer */
parm.curr_setup = setup;
- /* align data to 8 byte boundary */
+ /* align data properly */
parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
if (buf) {
+ /*
+ * Common initialization of the
+ * "usbd_xfer" structure.
+ */
xfer = USBD_ADD_BYTES(buf, parm.size[0]);
ppxfer[n] = xfer;
@@ -940,7 +996,13 @@
usb_callout_init_mtx(&xfer->timeout_handle, xfer->usb_mtx,
CALLOUT_RETURNUNLOCKED);
} else {
- /* dummy xfer */
+ /*
+ * Setup a dummy xfer, hence we are
+ * writing to the "usbd_xfer"
+ * structure pointed to by "xfer"
+ * before we have allocated any
+ * memory:
+ */
xfer = &dummy;
bzero(&dummy, sizeof(dummy));
refcount++;
@@ -951,11 +1013,24 @@
xfer->pipe = pipe;
if (buf) {
+ /*
+ * Increment the pipe 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 "pipe->refcount" if you
+ * want more information.
+ */
xfer->pipe->refcount++;
}
parm.methods = xfer->pipe->methods;
parm.curr_xfer = xfer;
+ /*
+ * Call the Host or Device controller transfer setup
+ * routine:
+ */
(udev->bus->methods->xfer_setup) (&parm);
if (parm.err) {
@@ -970,7 +1045,7 @@
/* no transfers - nothing to do ! */
goto done;
}
- /* align data to 8 byte boundary */
+ /* align data properly */
parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
@@ -992,7 +1067,7 @@
parm.size[0] += ((uint8_t *)parm.dma_tag_p) -
((uint8_t *)0);
- /* align data to 8 byte boundary */
+ /* align data properly */
parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
@@ -1001,7 +1076,7 @@
parm.size[0] += ((uint8_t *)parm.dma_page_ptr) -
((uint8_t *)0);
- /* align data to 8 byte boundary */
+ /* align data properly */
parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
@@ -1020,7 +1095,7 @@
parm.size[2] = parm.size[0];
- /* align data to 8 byte boundary */
+ /* align data properly */
parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
parm.size[6] = parm.size[0];
@@ -1028,7 +1103,7 @@
parm.size[0] += ((uint8_t *)parm.xfer_length_ptr) -
((uint8_t *)0);
- /* align data to 8 byte boundary */
+ /* align data properly */
parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
/* allocate zeroed memory */
@@ -1084,7 +1159,10 @@
if (bus->methods->get_dma_delay) {
(bus->methods->get_dma_delay) (bus, &temp);
- /* round up and convert to milliseconds */
+ /*
+ * Round up and convert to milliseconds. Note that we use
+ * 1024 milliseconds per second. to save a division.
+ */
temp += 0x3FF;
temp /= 0x400;
}
@@ -1125,10 +1203,7 @@
pc++;
}
- /*
- * free DMA maps in all
- * "xfer->frbuffers"
- */
+ /* free DMA maps in all "xfer->frbuffers" */
pc = info->xfer_page_cache_start;
while (pc != info->xfer_page_cache_end) {
usbd_pc_dmamap_destroy(pc);
@@ -1140,10 +1215,8 @@
info->dma_tag_max);
/*
- * free the "memory_base" last,
- * hence the "info" structure is
- * contained within the
- * "memory_base"!
+ * free the "memory_base" last, hence the "info" structure is
+ * contained within the "memory_base"!
*/
free(info->memory_base, M_USB);
return;
@@ -1152,9 +1225,9 @@
/*------------------------------------------------------------------------*
* usbd_transfer_unsetup - unsetup/free an array of USB transfers
*
- * NOTE: if the transfer was in progress, the callback will
- * called with "xfer->error=USBD_ERR_CANCELLED", before this
- * function returns
+ * NOTE: All USB transfers in progress will get called back passing
+ * the error code "USBD_ERR_CANCELLED" before this function
+ * returns.
*------------------------------------------------------------------------*/
void
usbd_transfer_unsetup(struct usbd_xfer **pxfer, uint16_t n_setup)
@@ -1245,6 +1318,16 @@
/*------------------------------------------------------------------------*
* usbd_std_root_transfer - factored out code
+ *
+ * This function is basically used for the Virtual Root HUB, end can
+ * emulate control, bulk and interrupt endpoints. Data is exchanged
+ * using the "std->ptr" and "std->len" fields, that allows kernel
+ * virtual memory to be transferred. All state is kept in the
+ * structure pointed to by the "std" argument passed to this
+ * function. The "func" argument points to a function that is called
+ * back in the various states, so that the application using this
+ * function can get a chance to select the outcome. The "func"
+ * function is allowed to sleep, exiting all mutexes.
*------------------------------------------------------------------------*/
void
usbd_std_root_transfer(struct usbd_std_root_transfer *std,
@@ -1270,7 +1353,9 @@
/* signal that we plan to do the callback */
xfer->usb_thread = td;
+ /* check for control transfer */
if (xfer->flags_int.control_xfr) {
+ /* check if we are transferring the SETUP packet */
if (xfer->flags_int.control_hdr) {
/* copy out the USB request */
@@ -1314,8 +1399,7 @@
if (std->err) {
goto done;
}
- /* transfer data */
-
+ /* Transfer data. Iterate accross all frames. */
while (xfer->aframes != xfer->nframes) {
len = xfer->frlengths[xfer->aframes];
@@ -1355,6 +1439,7 @@
if (std->err) {
goto done;
}
+ /* check if the control transfer is complete */
if (xfer->flags_int.control_xfr &&
!xfer->flags_int.control_act) {
@@ -1385,7 +1470,15 @@
}
/*------------------------------------------------------------------------*
- * usbd_control_transfer_init
+ * usbd_control_transfer_init - factored out code
+ *
+ * In USB Device Mode we have to wait for the SETUP packet which
+ * containst the "usb_device_request_t" structure, before we can
+ * transfer any data. In USB Host Mode we already have the SETUP
+ * packet at the moment the USB transfer is started. This leads us to
+ * having to setup the USB transfer at two different places in
+ * time. This function just contains factored out control transfer
+ * initialisation code, so that we don't duplicate the code.
*------------------------------------------------------------------------*/
static void
usbd_control_transfer_init(struct usbd_xfer *xfer)
@@ -1412,8 +1505,13 @@
/*------------------------------------------------------------------------*
* usbd_start_hardware_sub
*
- * To support split control transfers we need a special wrapper which
- * this function implements.
+ * This function handles initialisation of control transfers. Control
+ * transfers are special in that regard that they can both transmit
+ * and receive data.
+ *
+ * Return values:
+ * 0: Success
+ * Else: Failure
*------------------------------------------------------------------------*/
static uint8_t
usbd_start_hardware_sub(struct usbd_xfer *xfer)
@@ -1530,10 +1628,10 @@
/* time to execute the STATUS stage */
xfer->flags_int.control_act = 0;
}
- return (0);
+ return (0); /* success */
error:
- return (1);
+ return (1); /* failure */
}
/*------------------------------------------------------------------------*
@@ -1556,6 +1654,8 @@
/*------------------------------------------------------------------------*
* usbd_start_hardware - start USB hardware for the given transfer
+ *
+ * This function should only be called from the USB callback.
*------------------------------------------------------------------------*/
void
usbd_start_hardware(struct usbd_xfer *xfer)
@@ -1874,6 +1974,9 @@
/*------------------------------------------------------------------------*
* usbd_bdma_pre_sync
+ *
+ * This function handles DMA synchronisation that must be done before
+ * an USB transfer is started.
*------------------------------------------------------------------------*/
void
usbd_bdma_pre_sync(struct usbd_xfer *xfer)
@@ -1908,6 +2011,9 @@
/*------------------------------------------------------------------------*
* usbd_bdma_post_sync
+ *
+ * This function handles DMA synchronisation that must be done after
+ * an USB transfer is complete.
*------------------------------------------------------------------------*/
void
usbd_bdma_post_sync(struct usbd_xfer *xfer)
@@ -1943,7 +2049,7 @@
* NOTE: Calling this function more than one time will only
* result in a single transfer start, until the USB transfer
* completes.
- * NOTE: if "use_polling" is set in "xfer->flags", then this
+ * NOTE: If "use_polling" is set in "xfer->flags", then this
* function will spin until transfer is completed
*------------------------------------------------------------------------*/
void
@@ -2848,6 +2954,9 @@
/*------------------------------------------------------------------------*
* usbd_do_request_callback
+ *
+ * This function is the USB callback for generic USB Host control
+ * transfers.
*------------------------------------------------------------------------*/
static void
usbd_do_request_callback(struct usbd_xfer *xfer)
@@ -2869,6 +2978,9 @@
/*------------------------------------------------------------------------*
* usbd_handle_request_callback
+ *
+ * This function is the USB callback for generic USB Device control
+ * transfers.
*------------------------------------------------------------------------*/
static void
usbd_handle_request_callback(struct usbd_xfer *xfer)
@@ -3897,7 +4009,7 @@
/*------------------------------------------------------------------------*
* usbd_clear_data_toggle - factored out code
*
- * NOTE: the job of this function is not to reset the hardware data toggle.
+ * NOTE: the intention of this function is not to reset the hardware data toggle.
*------------------------------------------------------------------------*/
void
usbd_clear_data_toggle(struct usbd_device *udev, struct usbd_pipe *pipe)
@@ -3922,6 +4034,22 @@
* Return values:
* 0: In progress
* Else: Finished
+ *
+ * Clear stall config example:
+ *
+ * static const struct usbd_config my_clearstall = {
+ * .type = UE_CONTROL,
+ * .endpoint = 0,
+ * .direction = UE_DIR_ANY,
+ * .interval = 50, //50 milliseconds
+ * .bufsize = sizeof(usb_device_request_t),
+ * .mh.timeout = 1000, //1.000 seconds
+ * .mh.flags = { },
+ * .mh.callback = &my_clear_stall_callback, //**
+ * };
+ *
+ * ** "my_clear_stall_callback" calls "usbd_clear_stall_callback"
+ * passing the correct parameters.
*------------------------------------------------------------------------*/
uint8_t
usbd_clear_stall_callback(struct usbd_xfer *xfer1,
@@ -3988,20 +4116,6 @@
return (1); /* Clear Stall Finished */
}
-/* Clear stall config (example):
- *
- * static const struct usbd_config my_clearstall = {
- * .type = UE_CONTROL,
- * .endpoint = 0,
- * .direction = UE_DIR_ANY,
- * .interval = 50, //50 milliseconds
- * .bufsize = sizeof(usb_device_request_t),
- * .mh.timeout = 1000, //1.000 seconds
- * .mh.flags = { },
- * .mh.callback = &my_clear_stall_callback,
- * };
- */
-
/*------------------------------------------------------------------------*
* usbd_do_poll
*
More information about the p4-projects
mailing list