In Example 8–1, xxstart() is used as the callback function and the per-device state structure is given as its argument. xxstart() attempts to start the command. If the command cannot be started because resources are not available, xxstart() is scheduled to be called sometime later, when resources might be available.
Because xxstart() is used as a DMA callback, it must follow these rules imposed on DMA callbacks:
It must not assume that resources are available (it must try to allocate them again).
It must indicate to the system whether allocation succeeded by returning DDI_DMA_CALLBACK_RUNOUT if it fails to allocate resources (and needs to be called again later) or DDI_DMA_CALLBACK_DONE indicating success (so no further callback is necessary).
static int xxstart(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg; struct device_reg *regp; int flags; mutex_enter(&xsp->mu); if (xsp->busy) { /* transfer in progress */ mutex_exit(&xsp->mu); return (DDI_DMA_CALLBACK_RUNOUT); } xsp->busy = 1; regp = xsp->regp; if (transfer is a read) { flags = DDI_DMA_READ; } else { flags = DDI_DMA_WRITE; } mutex_exit(&xsp->mu); if (ddi_dma_buf_bind_handle(xsp->handle,xsp->bp,flags, xxstart, (caddr_t)xsp, &cookie, &ccount) != DDI_DMA_MAPPED) { /* really should check all return values in a switch */ mutex_enter(&xsp->mu); xsp->busy=0; mutex_exit(&xsp->mu); return (DDI_DMA_CALLBACK_RUNOUT); } ... program the DMA engine ... return (DDI_DMA_CALLBACK_DONE); }