From owner-p4-projects@FreeBSD.ORG Sun Feb 10 11:53:27 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 5D9F516A46C; Sun, 10 Feb 2008 11:53:27 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1F15216A417 for ; Sun, 10 Feb 2008 11:53:27 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 0DD9513C474 for ; Sun, 10 Feb 2008 11:53:27 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m1ABrQSR003744 for ; Sun, 10 Feb 2008 11:53:27 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m1ABrQSw003741 for perforce@freebsd.org; Sun, 10 Feb 2008 11:53:26 GMT (envelope-from hselasky@FreeBSD.org) Date: Sun, 10 Feb 2008 11:53:26 GMT Message-Id: <200802101153.m1ABrQSw003741@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 135146 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 10 Feb 2008 11:53:27 -0000 http://perforce.freebsd.org/chv.cgi?CH=135146 Change 135146 by hselasky@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 *