DMA 回调不能取消。取消 DMA 回调需要在驱动程序的 detach(9E) 入口点中附加一些代码。如果存在任何未完成的回调,则 detach() 例程一定不会返回 DDI_SUCCESS。请参见示例 9–6。发生 DMA 回调时,detach() 例程必须等待回调运行。回调完成时,detach() 必须防止回调自行重新安排。通过状态结构中的附加字段可以防止重新安排回调,如以下示例所示。
static int xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) { /* ... */ mutex_enter(&xsp->callback_mutex); xsp->cancel_callbacks = 1; while (xsp->callback_count > 0) { cv_wait(&xsp->callback_cv, &xsp->callback_mutex); } mutex_exit(&xsp->callback_mutex); /* ... */ } static int xxstrategy(struct buf *bp) { /* ... */ mutex_enter(&xsp->callback_mutex); xsp->bp = bp; error = ddi_dma_buf_bind_handle(xsp->handle, xsp->bp, flags, xxdmacallback, (caddr_t)xsp, &cookie, &ccount); if (error == DDI_DMA_NORESOURCES) xsp->callback_count++; mutex_exit(&xsp->callback_mutex); /* ... */ } static int xxdmacallback(caddr_t callbackarg) { struct xxstate *xsp = (struct xxstate *)callbackarg; /* ... */ mutex_enter(&xsp->callback_mutex); if (xsp->cancel_callbacks) { /* do not reschedule, in process of detaching */ xsp->callback_count--; if (xsp->callback_count == 0) cv_signal(&xsp->callback_cv); mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_DONE); /* don't reschedule it */ } /* * Presumably at this point the device is still active * and will not be detached until the DMA has completed. * A return of 0 means try again later */ error = ddi_dma_buf_bind_handle(xsp->handle, xsp->bp, flags, DDI_DMA_DONTWAIT, NULL, &cookie, &ccount); if (error == DDI_DMA_MAPPED) { /* Program the DMA engine. */ xsp->callback_count--; mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_DONE); } if (error != DDI_DMA_NORESOURCES) { xsp->callback_count--; mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_DONE); } mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_RUNOUT); }