Função WdfDmaTransactionStopSystemTransfer (wdfdmatransaction.h)
[Aplica-se somente ao KMDF]
O método WdfDmaTransactionStopSystemTransfer tenta interromper uma transferência de DMA no modo sistema depois que a estrutura tiver chamado EvtProgramDma.
Sintaxe
void WdfDmaTransactionStopSystemTransfer(
[in] WDFDMATRANSACTION DmaTransaction
);
Parâmetros
[in] DmaTransaction
Um identificador para um objeto de transação DMA inicializado.
Retornar valor
Nenhum
Comentários
Somente um driver que usa o DMA do modo de sistema deve chamar WdfDmaTransactionStopSystemTransfer.
Um driver que usa o DMA de domínio de barramento é responsável por programar seu próprio controlador de DMA dedicado. No caso de um cancelamento de solicitação, tempo limite ou erro de dispositivo, o driver pode programar o controlador de DMA para interromper a transferência de dados.
Por outro lado, um driver que usa o DMA no modo de sistema deve contar com a HAL (camada de abstração de hardware) para programar o controlador de DMA compartilhado. Quando um driver chama WdfDmaTransactionStopSystemTransfer, a estrutura notifica o HAL de que a transferência deve ser interrompida e retorna imediatamente.
A estrutura em seguida chama a função de retorno de chamada EvtDmaTransactionDmaTransferComplete do driver, se o driver tiver fornecido um. Caso contrário, a estrutura retornará FALSE quando o driver chamar WdfDmaTransactionDmaCompleted.
Se o driver chamar esse método em um sistema operacional anterior a Windows 8, o verificador da estrutura relatará um erro.
Para obter mais informações sobre o DMA no modo de sistema, consulte Suporte System-Mode DMA.
Para obter mais informações sobre como cancelar transações de DMA, consulte Cancelando transações de DMA.
Exemplos
O exemplo de código a seguir mostra como um driver pode chamar WdfDmaTransactionStopSystemTransfer de uma função de retorno de chamada de evento EvtTimerFunc que ele registra para ser chamado se uma solicitação de E/S atingir o tempo limite.
VOID
MyTimerFunc(
__in WDFTIMER Timer
)
{
WDFREQUEST request = (WDFREQUEST) WdfTimerGetParentObject(Timer);
PREQUEST_CONTEXT requestContext = GetRequestContext(request);
//
// Begin the completion process. If we're the first to get here
// then stop the DMA transfer. The dma completion routine will
// take care of running down cancellation.
//
if (BeginCompletion(requestContext, STATUS_IO_TIMEOUT, false)) {
WdfDmaTransactionStopSystemTransfer(requestContext->DmaTransaction);
}
AttemptRequestCompletion(requestContext, false);
}
bool
BeginCompletion(
__in PREQUEST_CONTEXT RequestContext,
__in NTSTATUS CompletionStatus,
__in bool ForceStatusUpdate
)
{
bool completionStarted;
//
// Grab the object lock and mark the beginning of
// completion.
//
WdfSpinLockAcquire(RequestContext->Lock);
completionStarted = RequestContext->CompletionStarted;
RequestContext->CompletionStarted = true;
if ((completionStarted == false) ||
(ForceStatusUpdate == true)) {
RequestContext->CompletionStatus = CompletionStatus;
}
WdfSpinLockRelease(RequestContext->Lock);
return !completionStarted;
}
VOID
AttemptRequestCompletion(
__in PREQUEST_CONTEXT RequestContext,
__in bool TransferComplete
)
{
LONG refCount;
NT_ASSERTMSG("No thread has begun completion",
RequestContext->CompletionStarted == true);
if (TransferComplete) {
//
// Unmark the request cancelable. If that succeeds then drop the cancel reference
//
if (WdfRequestUnmarkCancelable(RequestContext->Request) == STATUS_SUCCESS) {
refCount = InterlockedDecrement(&(RequestContext->CompletionRefCount));
NT_ASSERTMSGW(L"Reference count should not have gone to zero yet",
refCount != 0);
}
//
// Stop the timer if it's been started.
//
if (RequestContext->TimerStarted == true) {
if (WdfTimerStop(RequestContext->Timer, FALSE) == TRUE) {
//
// The timer was queued but won't ever run. Drop its
// reference count.
//
refCount = InterlockedDecrement(&RequestContext->CompletionRefCount);
NT_ASSERTMSG("Completion reference count should not reach zero until "
L"this routine calls AttemptRequestCompletion",
refCount > 0);
}
}
}
//
// Drop this caller's reference. If that was the last one then
// complete the request.
//
refCount = InterlockedDecrement(&(RequestContext->CompletionRefCount));
if (refCount == 0) {
NT_ASSERTMSGW(L"Execution reference was released, but execution "
L"path did not set a completion status for the "
L"request",
RequestContext->CompletionStatus != STATUS_PENDING);
//
// Timers are disposed of at passive level. If we leave it attached to
// the request then we can hit a verifier issue, since the request
// needs to be immediately disposable at dispatch-level.
//
// Delete the timer now so that we can complete the request safely.
// At this point the timer has either expired or been successfully
// cancelled so there's no race with the timer routine.
//
if (RequestContext->Timer != NULL) {
WdfObjectDelete(RequestContext->Timer);
RequestContext->Timer = NULL;
}
WdfRequestComplete(RequestContext->Request,
RequestContext->CompletionStatus);
}
}
O exemplo de código a seguir mostra como um driver pode chamar WdfDmaTransactionStopSystemTransfer de uma função de retorno de chamada EvtRequestCancel . O driver anteriormente chamado WdfRequestMarkCancelableEx de seu manipulador de solicitação de E/S para registrar o retorno de chamada.
VOID
MyRequestCancel(
__in WDFREQUEST Request
)
{
PREQUEST_CONTEXT requestContext = GetRequestContext(Request);
LONG oldValue;
//
// Start completion
//
if (BeginCompletion(requestContext, STATUS_CANCELLED, false)) {
//
// Cancel the DMA transaction.
//
if (WdfDmaTransactionCancel(requestContext->DmaTransaction) == TRUE) {
//
// The transaction was stopped before EvtProgramDma could be
// called. Drop the I/O reference.
//
oldValue = InterlockedDecrement(&requestContext->CompletionRefCount);
NT_ASSERTMSG("Completion reference count should not reach zero until "
L"this routine calls AttemptRequestCompletion",
oldValue > 0);
NT_ASSERTMSG("Completion status should be cancelled",
requestContext->CompletionStatus == STATUS_CANCELLED);
}
else {
//
// The transaction couldn't be stopped before EvtProgramDma.
// Stop any running system DMA transfer.
//
WdfDmaTransactionStopSystemTransfer(requestContext->DmaTransaction);
}
}
AttemptRequestCompletion(requestContext, false);
}
Requisitos
Requisito | Valor |
---|---|
Cliente mínimo com suporte | Windows 8 |
Plataforma de Destino | Universal |
Versão mínima do KMDF | 1.11 |
Cabeçalho | wdfdmatransaction.h (inclua Wdf.h) |
Biblioteca | Wdf01000.sys (consulte Controle de versão da biblioteca de estrutura.) |
IRQL | <=DISPATCH_LEVEL |
Regras de conformidade de DDI | DriverCreate(kmdf) |