FreeBSD/sys/dev/usb/usb_busdma.c
/*------------------------------------------------------------------------*
 *	usb_bdma_work_loop
 *
 * This function handles loading of virtual buffers into DMA and is
 * only called when "dma_refcount" is zero.
 *------------------------------------------------------------------------*/
usb_bdma_work_loop
This function handles loading of virtual buffers into DMA and is
only called when "dma_refcount" is zero.
usb_bdma_work_loop This function handles loading of virtual buffers into DMA and is only called when " dma_refcount " is zero .
void
usb_bdma_work_loop(struct usb_xfer_queue *pq)
{
	struct usb_xfer_root *info;
	struct usb_xfer *xfer;
	usb_frcount_t nframes;
	xfer = pq->curr;
	info = xfer->xroot;
	mtx_assert(info->xfer_mtx, MA_OWNED);
	if (xfer->error) {
		USB_BUS_LOCK(info->bus);
		usbd_transfer_done(xfer, 0);
		USB_BUS_UNLOCK(info->bus);
		return;
	}
	if (!xfer->flags_int.bdma_setup) {
		struct usb_page *pg;
		usb_frlength_t frlength_0;
		uint8_t isread;
		xfer->flags_int.bdma_setup = 1;
		info->dma_error = 0;
		if (xfer->flags_int.isochronous_xfr) {
			nframes = 1;
			frlength_0 = xfer->sumlen;
		} else {
			nframes = xfer->nframes;
			frlength_0 = xfer->frlengths[0];
		}
		isread = USB_GET_DATA_ISREAD(xfer);
		pg = xfer->dma_page_ptr;
		if (xfer->flags_int.control_xfr &&
		    xfer->flags_int.control_hdr) {
			if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
				xfer->frbuffers[0].isread = 1;
			} else {
				xfer->frbuffers[0].isread = 0;
			}
		} else {
			xfer->frbuffers[0].isread = isread;
		}
		xfer->frbuffers[0].page_start = pg;
		info->dma_nframes = nframes;
		info->dma_currframe = 0;
		info->dma_frlength_0 = frlength_0;
		pg += (frlength_0 / USB_PAGE_SIZE);
		pg += 2;
		while (--nframes > 0) {
			xfer->frbuffers[nframes].isread = isread;
			xfer->frbuffers[nframes].page_start = pg;
			pg += (xfer->frlengths[nframes] / USB_PAGE_SIZE);
			pg += 2;
		}
	}
	if (info->dma_error) {
		USB_BUS_LOCK(info->bus);
		usbd_transfer_done(xfer, USB_ERR_DMA_LOAD_FAILED);
		USB_BUS_UNLOCK(info->bus);
		return;
	}
	if (info->dma_currframe != info->dma_nframes) {
		if (info->dma_currframe == 0) {
			usb_pc_load_mem(xfer->frbuffers,
			    info->dma_frlength_0, 0);
		} else {
			nframes = info->dma_currframe;
			usb_pc_load_mem(xfer->frbuffers + nframes,
			    xfer->frlengths[nframes], 0);
		}
		info->dma_currframe++;
		return;
	}
	usb_bdma_pre_sync(xfer);
	usb_command_wrapper(pq, NULL);
	usbd_pipe_enter(xfer);
}
void usb_bdma_work_loop ( struct usb_xfer_queue * pq ) { struct usb_xfer_root * info ; struct usb_xfer * xfer ; usb_frcount_t nframes ; xfer = pq -> curr ; info = xfer -> xroot ; mtx_assert ( info -> xfer_mtx , MA_OWNED ) ; if ( xfer -> error ) { USB_BUS_LOCK ( info -> bus ) ; usbd_transfer_done ( xfer , 0 ) ; USB_BUS_UNLOCK ( info -> bus ) ; return ; } if ( ! xfer -> flags_int . bdma_setup ) { struct usb_page * pg ; usb_frlength_t frlength_0 ; uint8_t isread ; xfer -> flags_int . bdma_setup = 1 ; info -> dma_error = 0 ; if ( xfer -> flags_int . isochronous_xfr ) { nframes = 1 ; frlength_0 = xfer -> sumlen ; } else { nframes = xfer -> nframes ; frlength_0 = xfer -> frlengths [ 0 ] ; } isread = USB_GET_DATA_ISREAD ( xfer ) ; pg = xfer -> dma_page_ptr ; if ( xfer -> flags_int . control_xfr && xfer -> flags_int . control_hdr ) { if ( xfer -> flags_int . usb_mode == USB_MODE_DEVICE ) { xfer -> frbuffers [ 0 ] . isread = 1 ; } else { xfer -> frbuffers [ 0 ] . isread = 0 ; } } else { xfer -> frbuffers [ 0 ] . isread = isread ; } xfer -> frbuffers [ 0 ] . page_start = pg ; info -> dma_nframes = nframes ; info -> dma_currframe = 0 ; info -> dma_frlength_0 = frlength_0 ; pg += ( frlength_0 / USB_PAGE_SIZE ) ; pg += 2 ; while ( -- nframes > 0 ) { xfer -> frbuffers [ nframes ] . isread = isread ; xfer -> frbuffers [ nframes ] . page_start = pg ; pg += ( xfer -> frlengths [ nframes ] / USB_PAGE_SIZE ) ; pg += 2 ; } } if ( info -> dma_error ) { USB_BUS_LOCK ( info -> bus ) ; usbd_transfer_done ( xfer , USB_ERR_DMA_LOAD_FAILED ) ; USB_BUS_UNLOCK ( info -> bus ) ; return ; } if ( info -> dma_currframe != info -> dma_nframes ) { if ( info -> dma_currframe == 0 ) { usb_pc_load_mem ( xfer -> frbuffers , info -> dma_frlength_0 , 0 ) ; } else { nframes = info -> dma_currframe ; usb_pc_load_mem ( xfer -> frbuffers + nframes , xfer -> frlengths [ nframes ] , 0 ) ; } info -> dma_currframe ++ ; return ; } usb_bdma_pre_sync ( xfer ) ; usb_command_wrapper ( pq , NULL ) ; usbd_pipe_enter ( xfer ) ; }
usb_bdma_work_loop
 This function handles loading of virtual buffers into DMA and is
 only called when "dma_refcount" is zero.
usb_bdma_work_loop This function handles loading of virtual buffers into DMA and is only called when " dma_refcount " is zero .
/* some error happened */ /* reset BUS-DMA load state */ /* only one frame buffer */ /* can be multiple frame buffers */ /*
		 * Set DMA direction first. This is needed to
		 * select the correct cache invalidate and cache
		 * flush operations.
		 */ /* special case */ /* The device controller writes to memory */ /* The host controller reads from memory */ /* default case */ /*
		 * Setup the "page_start" pointer which points to an array of
		 * USB pages where information about the physical address of a
		 * page will be stored. Also initialise the "isread" field of
		 * the USB page caches.
		 */ /* special case */ /* default case */ /* advance frame index */ /* go ahead */ /* start loading next USB transfer, if any */ /* finally start the hardware */