DMA コールバックを取り消すことはできません。DMA コールバックを取り消すには、ドライバの detach (9E) エントリポイントにコードを追加する必要があります。未処理のコールバックが存在する場合は、detach() ルーチンが DDI_SUCCESS を返すことはありません。Example 9–6を参照してください。DMA コールバックが発生すると、detach() ルーチンはコールバックが実行されるのを待つ必要があります。コールバックが完了したら、detach() はコールバックが再スケジュールを行わないようにする必要があります。次の例に示すように、状態構造体で追加のフィールドを指定することによって、コールバックが再スケジュールを行わないようにすることができます。
使用例 9-6 DMA コールバックの取り消し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);
}