Partager via


Gestion des demandes de IOCTL_SPB_FULL_DUPLEX

Certains bus, tels que SPI, permettent aux transferts en lecture et en écriture de se produire simultanément entre le contrôleur de bus et un appareil sur le bus. Pour prendre en charge ces transferts en duplex intégral, la définition de l’interface de demande d’E/S du bus périphérique simple (SPB) inclut, en option, le code de contrôle d’E /S IOCTL_SPB_FULL_DUPLEX (IOCTL). Seuls les pilotes de contrôleur SPB pour les contrôleurs de bus qui implémentent des transferts duplex complets dans le matériel doivent prendre en charge le IOCTL_SPB_FULL_DUPLEX IOCTL.

Si un pilote de contrôleur SPB prend en charge les demandes d’E/S pour les transferts en duplex intégral, le pilote doit utiliser le IOCTL_SPB_FULL_DUPLEX IOCTL pour ces demandes et doit suivre les instructions d’implémentation présentées dans cette rubrique. L’objectif de ces instructions est d’encourager un comportement uniforme sur toutes les plateformes matérielles qui prennent en charge les demandes IOCTL_SPB_FULL_DUPLEX . Les pilotes pour les périphériques connectés à SPB peuvent ensuite s’appuyer sur ces demandes pour produire des résultats similaires, quelle que soit la plateforme sur laquelle ils s’exécutent.

Configuration requise pour la mémoire tampon

Une requête IOCTL_SPB_FULL_DUPLEX est mise en forme comme une requête IOCTL_SPB_EXECUTE_SEQUENCE , mais avec les contraintes suivantes :

  • La structure SPB_TRANSFER_LIST dans la requête doit contenir exactement deux entrées. La première entrée décrit une mémoire tampon qui contient des données à écrire sur l’appareil. La deuxième entrée décrit une mémoire tampon utilisée pour contenir les données lues à partir de l’appareil.
  • Chaque structure SPB_TRANSFER_LIST_ENTRY dans la liste de transferts doit spécifier une valeur DelayInUs de zéro.

Pendant un transfert en duplex intégral, les transferts en lecture et en écriture démarrent à l’unisson. Le premier octet de données d’écriture est transmis sur le bus en même temps que le premier octet de données lues.

Les mémoires tampons d’écriture et de lecture dans la requête IOCTL_SPB_FULL_DUPLEX ne doivent pas nécessairement avoir la même longueur.

Si la mémoire tampon de lecture est plus courte que la mémoire tampon d’écriture, le transfert de bus duplex intégral se poursuit jusqu’à ce que le contenu entier de la mémoire tampon d’écriture soit écrit sur l’appareil. Une fois que la mémoire tampon de lecture est pleine, le contrôleur de bus ignore toutes les données supplémentaires reçues de l’appareil jusqu’à la fin du transfert de bus duplex intégral.

Si la mémoire tampon d’écriture est plus courte que la mémoire tampon de lecture, le transfert de bus duplex intégral se poursuit jusqu’à ce que la mémoire tampon de lecture soit pleine. Une fois que l’intégralité du contenu de la mémoire tampon d’écriture a été écrite sur l’appareil, le contrôleur de bus écrit des zéros sur l’appareil jusqu’à ce que le transfert de bus duplex intégral se termine.

Si la demande IOCTL_SPB_FULL_DUPLEX se termine correctement, le pilote du contrôleur SPB définit le membre Status du bloc d’état d’E/S sur STATUS_SUCCESS et définit le membre Information sur le nombre total d’octets transférés (octets lus plus octets écrits) pendant le transfert en duplex intégral. La valeur du nombre dans le membre Information ne doit jamais dépasser la somme de la taille de la mémoire tampon de lecture et de la taille de la mémoire tampon d’écriture.

Si la mémoire tampon de lecture est plus courte que la mémoire tampon d’écriture, la valeur de nombre dans le membre Information ne doit pas inclure les octets de données que le contrôleur de bus lit à partir de l’appareil (et ignore) une fois que la mémoire tampon de lecture est pleine. Par exemple, si un transfert en duplex intégral avec une mémoire tampon d’écriture de 1 octet et une mémoire tampon de lecture de 4 octets se termine correctement, la valeur du nombre doit être 5, et non 8. De même, si la mémoire tampon d’écriture est plus courte que la mémoire tampon de lecture, la valeur de nombre ne doit pas inclure les zéros écrits sur l’appareil une fois la mémoire tampon d’écriture vidée.

Vérification des paramètres

Bien que les requêtes IOCTL_SPB_EXECUTE_SEQUENCE et IOCTL_SPB_FULL_DUPLEX aient des formats similaires, elles sont gérées différemment par l’extension de l’infrastructure SPB (SpbCx). Pour la requête IOCTL_SPB_EXECUTE_SEQUENCE , SpbCx valide les valeurs de paramètre dans la demande et capture les mémoires tampons de la requête dans le contexte de processus de l’initiateur de la demande. SpbCx transmet IOCTL_SPB_EXECUTE_SEQUENCE requêtes au pilote du contrôleur SPB via la fonction de rappel EvtSpbControllerIoSequence du pilote, qui est dédiée à ces requêtes.

En revanche, SpbCx traite la requête IOCTL_SPB_FULL_DUPLEX comme une requête IOCTL personnalisée définie par le pilote. SpbCx transmet IOCTL_SPB_FULL_DUPLEX demandes au pilote du contrôleur SPB par le biais de la fonction de rappel EvtSpbControllerIoOther du pilote, qui gère également toutes les demandes IOCTL personnalisées que le pilote prend en charge. SpbCx n’effectue aucune vérification des paramètres ni capture de mémoire tampon pour ces requêtes. Le pilote est responsable de la vérification des paramètres ou de la capture de mémoire tampon qui peut être nécessaire pour les demandes IOCTL que le pilote reçoit via sa fonction EvtSpbControllerIoOther . Pour activer la capture de mémoire tampon, le pilote doit fournir une fonction de rappel EvtIoInCallerContext lorsque le pilote inscrit sa fonction EvtSpbControllerIoOther . Pour plus d’informations, consultez Utilisation de la structure SPB_TRANSFER_LIST pour les IOCTL personnalisés.

En règle générale, le pilote de contrôleur SPB valide les valeurs de paramètre dans une requête IOCTL_SPB_FULL_DUPLEX dans la fonction EvtSpbControllerIoOther au lieu de dans la fonction EvtIoInCallerContext . L’exemple de code suivant montre comment le pilote peut implémenter la vérification des paramètres. Dans cet exemple, le pilote vérifie que les exigences de paramètres suivantes sont remplies :

  • La liste de transferts de la demande contient exactement deux entrées.
  • La première entrée de la liste de transfert concerne une mémoire tampon d’écriture et la deuxième pour une mémoire tampon de lecture.
  • La valeur DelayInUs pour les deux entrées est zéro.
//
// Validate the transfer count.
//

SPB_REQUEST_PARAMETERS params;
SPB_REQUEST_PARAMETERS_INIT(&params);
SpbRequestGetParameters(SpbRequest, &params);

if (params.SequenceTransferCount != 2)
{
    //
    // The full-duplex request must have 
    // exactly two transfer descriptors.
    //
    
    status = STATUS_INVALID_PARAMETER;        
    goto exit;
}

//
// Retrieve the write and read transfer descriptors.
//

const ULONG fullDuplexWriteIndex = 0;
const ULONG fullDuplexReadIndex = 1;

SPB_TRANSFER_DESCRIPTOR writeDescriptor;
SPB_TRANSFER_DESCRIPTOR readDescriptor;
PMDL pWriteMdl;
PMDL pReadMdl;

SPB_TRANSFER_DESCRIPTOR_INIT(&writeDescriptor);
SPB_TRANSFER_DESCRIPTOR_INIT(&readDescriptor);

SpbRequestGetTransferParameters(
    SpbRequest, 
    fullDuplexWriteIndex, 
    &writeDescriptor,
    &pWriteMdl);

SpbRequestGetTransferParameters(
    SpbRequest, 
    fullDuplexReadIndex, 
    &readDescriptor,
    &pReadMdl);
    
//
// Validate the transfer direction of each descriptor.
//

if ((writeDescriptor.Direction != SpbTransferDirectionToDevice) ||
    (readDescriptor.Direction != SpbTransferDirectionFromDevice))
{
    //
    // For full-duplex I/O, the direction of the first transfer
    // must be SpbTransferDirectionToDevice, and the direction
    // of the second must be SpbTransferDirectionFromDevice.
    //
    
    status = STATUS_INVALID_PARAMETER;
    goto exit;
}

//
// Validate the delay for each transfer descriptor.
//

if ((writeDescriptor.DelayInUs != 0) || (readDescriptor.DelayInUs != 0))
{
    //
    // The write and read buffers for full-duplex I/O are transferred
    // simultaneously over the bus. The delay parameter in each transfer
    // descriptor must be set to 0.
    //
    
    status = STATUS_INVALID_PARAMETER;
    goto exit;
}

MyDriverPerformFullDuplexTransfer(
    pDevice, 
    pRequest,
    writeDescriptor,
    pWriteMdl,
    readDescriptor,
    pReadMdl);

Après avoir vérifié les valeurs des paramètres, l’exemple de code précédent appelle une routine interne au pilote, nommée MyDriverPerformFullDuplexTransfer, pour lancer le transfert d’E/S en duplex intégral.