Fin d’un transfert DMA
[S’applique uniquement à KMDF]
En règle générale, la fonction de rappel EvtInterruptDpc de votre pilote termine le traitement de chaque transfert DMA.
Tout d’abord, étant donné que plusieurs transactions DMA peuvent être en cours simultanément, la fonction de rappel EvtInterruptDpc doit déterminer la transaction DMA à laquelle le transfert terminé est associé. La fonction de rappel peut effectuer cette opération en récupérant le handle de transaction que le pilote a stocké lors du démarrage de la transaction DMA. Pour récupérer l’extension d’appareil, l’exemple PLX9x5x définit une fonction appelée PLxGetDeviceContext dans son fichier d’en-tête Private.h :
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, PLxGetDeviceContext)
Ensuite, dans le rappel EvtInterruptDpc du pilote, il effectue les opérations suivantes :
WDFDMATRANSACTION dmaTransaction;
PDEVICE_EXTENSION devExt;
...
devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));
...
dmaTransaction = devExt->WriteDmaTransaction;
Ensuite, la fonction de rappel EvtInterruptDpc doit informer l’infrastructure qu’un transfert est terminé, en appelant l’une des méthodes d’achèvement de transfert suivantes :
WdfDmaTransactionDmaCompleted, si le transfert s’est terminé correctement et que le matériel ne signale pas le nombre d’octets transférés.
WdfDmaTransactionDmaCompletedWithLength, si le transfert s’est terminé correctement et que le matériel signale un nombre d’octets transférés (ou un nombre d’octets non transférés), ou si le pilote a détecté une erreur et spécifie un nombre de transferts de zéro pour réessayer le transfert. Si le pilote spécifie un nombre de transferts de zéro, l’infrastructure soustrait zéro du nombre d’octets restant et envoie donc le même transfert à la fonction de rappel EvtProgramDma .
WdfDmaTransactionDmaCompletedFinal, si le matériel signale une condition de sous-exécution ou de défaillance.
Votre pilote peut appeler WdfDmaTransactionGetCurrentDmaTransferLength pour obtenir la longueur d’origine du transfert terminé. Cet appel est utile si votre appareil signale un nombre d’octets qui n’ont pas été transférés, car le pilote peut soustraire le nombre d’octets non transférés de la longueur de transfert d’origine, puis appeler WdfDmaTransactionGetCurrentDmaTransferLength pour signaler la taille de transfert réelle.
Chacune des méthodes d’achèvement de transfert précédentes informe l’infrastructure qu’un seul transfert DMA (et non la transaction DMA entière) est terminé. Une fois que votre pilote a appelé l’une de ces méthodes, le pilote vérifie la valeur de retour de la méthode pour voir si la transaction nécessite davantage de transferts :
Si la valeur de retour de la méthode d’achèvement est FALSE, l’infrastructure a déterminé que des transferts DMA supplémentaires sont nécessaires pour terminer le traitement de la transaction DMA.
En règle générale, la fonction de rappel EvtInterruptDpc du pilote retourne simplement. L’infrastructure appelle à nouveau la fonction de rappel EvtProgramDma du pilote, et la fonction de rappel peut programmer le matériel pour le transfert suivant.
Les méthodes d’achèvement du transfert fournissent une valeur status, qui est toujours STATUS_MORE_PROCESSING_REQUIRED dans ce cas.
Si la valeur de retour est TRUE, plus aucun transfert ne se produit pour la transaction DMA.
Les méthodes d’achèvement du transfert fournissent une valeur status. Si la valeur status est STATUS_SUCCESS, tous les transferts pour la transaction DMA sont terminés et le pilote doit effectuer la transaction DMA. Si la valeur status est autre chose, une erreur s’est produite et la transaction DMA n’a peut-être pas été effectuée.
Si la fonction de rappel EvtInterruptDpc détecte une erreur, généralement due à l’expiration d’un minuteur ou à une interruption matérielle signalant une erreur de transfert, le pilote peut redémarrer le transfert en cours de la transaction.
Pour redémarrer le transfert actuel de la transaction, la fonction de rappel EvtInterruptDpc du pilote peut appeler WdfDmaTransactionDmaCompletedWithLength avec le paramètre TransferedLength défini sur zéro.