Programmation du matériel DMA
[S’applique à KMDF uniquement]
Cette rubrique décrit les fonctionnalités qu’un pilote KMDF pour un appareil DMA master bus fournit généralement dans sa fonction de rappel d’événement EvtProgramDma. Si votre pilote utilise la prise en charge DMA de l’infrastructure, il doit fournir ce rappel. Ces informations s’appliquent également à un pilote KMDF pour un appareil DMA en mode système qui a une interruption matérielle.
La fonction de rappel EvtProgramDma , appelée irQL = DISPATCH_LEVEL, programme l’appareil pour démarrer un transfert DMA. Les paramètres d’entrée de cette fonction de rappel fournissent la direction du transfert (entrée ou sortie) et une liste de points/regroupements. Si le transfert se compose d’un seul paquet, la liste de points/regroupements contient un seul élément.
La fonction de rappel EvtProgramDma programme l’appareil à l’aide des ressources matérielles que la fonction de rappel EvtDevicePrepareHardware du pilote a reçues. Si la fonction de rappel EvtProgramDma programme correctement le matériel, elle retourne TRUE.
Une fois que le matériel a terminé le transfert DMA, il émet généralement une interruption et le système appelle la fonction de rappel EvtInterruptIsr du pilote. La fonction de rappel EvtInterruptIsr du pilote est généralement :
Efface l’interruption matérielle.
Enregistre les informations de contexte de l’interruption si nécessaire. Ces informations peuvent être perdues une fois que la fonction de rappel est retournée et que le système diminue l’IRQL (car l’abaissement de l’IRQL permet des interruptions supplémentaires).
Appelle WdfInterruptQueueDpcForIsr pour planifier une fonction de rappel EvtInterruptDpc .
La fonction de rappel EvtInterruptDpctermine le transfert DMA à l’aide des informations de contexte que la fonction de rappel EvtInterruptIsr a enregistrées.
Si la fonction de rappel EvtProgramDma détecte une erreur, le pilote peut arrêter la transaction.
Pour arrêter une transaction lorsque le pilote détecte une erreur, la fonction de rappel EvtProgramDma doit :
Appelez WdfDmaTransactionDmaCompletedFinal.
Appelez WdfObjectDelete pour supprimer l’objet de transaction DMA ou appelez WdfDmaTransactionRelease pour libérer et réutiliser l’objet de transaction DMA.
Ressaisisez la demande d’E/ S ou terminez la demande d’E/S, si la transaction est associée à un objet de demande d’infrastructure. Pour récupérer un handle à la demande, le pilote peut appeler WdfDmaTransactionGetRequest.
Retourne false.
Les étapes 1 et 4 sont illustrées dans l’exemple de code suivant, extrait de la fonction de rappel EvtProgramDma de l’exemple PLX9x5x pour les demandes de lecture dans le fichier Read.c.
// If errors occur in the EvtProgramDma callback,
// release the DMA transaction object and complete the request.
if (errors) {
NTSTATUS status;
//
// Must abort the transaction before deleting.
//
(VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
ASSERT(NT_SUCCESS(status));
PLxReadRequestComplete( Transaction, STATUS_INVALID_DEVICE_STATE );
TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
"<-- PLxEvtProgramReadDma: errors ****");
return FALSE;
}
L’exemple appelle la fonction PLxReadRequestComplete pour effectuer les étapes 2 et 3 :
VOID
PLxReadRequestComplete(
IN WDFDMATRANSACTION DmaTransaction,
IN NTSTATUS Status
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
WDFREQUEST request;
size_t bytesTransferred;
//
// Get the associated request from the transaction.
//
request = WdfDmaTransactionGetRequest(DmaTransaction);
ASSERT(request);
//
// Get the final bytes transferred count.
//
bytesTransferred = WdfDmaTransactionGetBytesTransferred( DmaTransaction );
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
"PLxReadRequestComplete: Request %p, Status %!STATUS!, "
"bytes transferred %d\n",
request, Status, (int) bytesTransferred );
WdfDmaTransactionRelease(DmaTransaction);
//
// Complete this Request.
//
WdfRequestCompleteWithInformation( request, Status, bytesTransferred);
}