Partager via


Opérations de bus atomique

Pour utiliser certaines fonctionnalités matérielles d’un périphérique connecté à SPB, un client du contrôleur SPB (autrement dit, un pilote périphérique) peut avoir besoin d’effectuer une séquence de transferts de données vers et depuis l’appareil en tant qu’opération de bus atomique. La séquence de transfert est atomique, car aucun autre client ne peut transférer des données vers ou depuis un appareil sur le bus jusqu’à ce que la séquence se termine.

La façon classique pour un client d’effectuer une séquence de transfert en tant qu’opération de bus atomique consiste à envoyer une demande de IOCTL_SPB_EXECUTE_SEQUENCE à l’appareil cible. Dans cette demande, le client spécifie la séquence sous la forme d’une liste de transferts de lecture et d’écriture simples. La liste peut être de longueur arbitraire. Les lectures et les écritures sont effectuées dans l’ordre dans lequel elles sont répertoriées, et chaque lecture ou écriture peut transférer un nombre arbitraire d’octets. La plupart des contrôleurs SPB prennent en charge les requêtes IOCTL_SPB_EXECUTE_SEQUENCE .

Verrous du contrôleur SPB

Un moyen moins courant d’effectuer une séquence de transfert atomique consiste à utiliser un verrou de contrôleur SPB. Un client envoie une demande de IOCTL_SPB_LOCK_CONTROLLER pour acquérir le verrou et une demande de IOCTL_SPB_UNLOCK_CONTROLLER pour libérer le verrou. Lorsqu’un client contient le verrou du contrôleur, toute séquence de requêtes de lecture et d’écriture simples (IRP_MJ_READ et IRP_MJ_WRITE) envoyées par le client à l’appareil est effectuée en tant qu’opération atomique sur le bus.

La plupart des périphériques connectés à SPB ne nécessitent pas de verrous de contrôleur, et la plupart des pilotes de contrôleur SPB n’implémentent pas la prise en charge de ces verrous. Toutefois, quelques clients peuvent avoir besoin d’utiliser des verrous de contrôleur pour accéder aux appareils qui ont des fonctionnalités inhabituelles.

Par exemple, un appareil peut implémenter des fonctions accessibles uniquement via des opérations de lecture-modification-écriture qui sont atomiques sur le bus. Pour effectuer une telle opération, le client envoie les quatre demandes d’E/S suivantes (dans l’ordre indiqué) :

  1. IOCTL_SPB_LOCK_CONTROLLER : acquérir le verrou du contrôleur.
  2. IRP_MJ_READ : lire un bloc de données à partir d’un appareil cible.
  3. IRP_MJ_WRITE : réécrire les données modifiées sur l’appareil.
  4. IOCTL_SPB_UNLOCK_CONTROLLER : relâchez le verrou du contrôleur.

Après l’opération de lecture dans la liste précédente, le client interprète les données lues à partir de l’appareil et modifie les données avant de les réécrire sur l’appareil.

Peu d'appareils connectés à SPB ont des fonctionnalités qui nécessitent des verrous de contrôleur. Pour la plupart des appareils qui nécessitent des opérations de bus atomiques, les requêtes IOCTL_SPB_EXECUTE_SEQUENCE sont suffisantes.

Ne confondez pas les verrous de contrôleur SPB avec les verrous de connexion SPB. Dans le cas atypique dans lequel deux clients partagent l’accès au même périphérique connecté à SPB, l’un ou l’autre client peut utiliser un verrou de connexion pour obtenir temporairement un accès exclusif à l’appareil. Pour plus d’informations, consultez Verrous de connexion SPB.

Signaux de bus matériels

Pour gérer une requête IOCTL_SPB_EXECUTE_SEQUENCE , un pilote de contrôleur SPB configure le matériel du contrôleur pour générer les signaux appropriés sur le bus pendant la séquence de transfert. Les périphériques attachés au bus peuvent s’appuyer sur ces signaux pour détecter lorsqu’une opération de bus atomique est en cours. L’ensemble de signaux matériels qu’un contrôleur SPB utilise pour effectuer une séquence de transfert en tant qu’opération de bus atomique dépend du type de bus.

Pour un bus I2C, le contrôleur démarre une séquence en transmettant un bit de début sur le bus, puis termine une séquence en transmettant un bit d’arrêt. Entre les bits de début et d’arrêt, la séquence de transferts de données vers et depuis l’appareil est effectuée en tant qu’opération de bus atomique unique. À l’exception du transfert final dans la séquence, chaque transfert est suivi d’une opération de redémarrage I2C (un bit de démarrage répété qui n’est pas précédé d’un bit d’arrêt).

Pour un bus SPI, le contrôleur démarre une séquence en activant la ligne de sélection de puce vers le périphérique cible et met fin à la séquence en désactivant la ligne de sélection de puce. En conservant la ligne de sélection de puce en continu pendant une séquence de transferts de données sur le bus, les transferts sont effectués comme une opération de bus atomique unique.

Exemple d’appareil I2C

Un périphérique classique sur un bus I2C peut implémenter plusieurs fonctions d’appareil interne. Pour accéder à certaines de ces fonctions, un client peut utiliser des requêtes IOCTL_SPB_EXECUTE_SEQUENCE .

Par exemple, un périphérique I2C peut contenir les deux registres internes suivants :

  • Registre d’adresses de fonction dans lequel le client écrit l’adresse interne de la fonction d’appareil à accéder.
  • Registre de données par le biais duquel le client lit les données depuis ou écrit des données dans l’adresse de fonction spécifiée.

L’appareil périphérique I2C dans cet exemple interprète le premier octet écrit sur l’appareil après un bit de démarrage pour être une adresse de fonction à charger dans le registre d’adresses de fonction. Tous les octets supplémentaires transférés vers ou depuis l’appareil avant la fin de la séquence (comme indiqué par le bit d’arrêt) sont traités par l’appareil comme des données à transférer via le registre des données.

Pour effectuer une opération d’écriture, le client envoie une requête d’écriture (IRP_MJ_WRITE) dans laquelle le premier octet de la mémoire tampon d’écriture est l’adresse de la fonction, et les octets restants dans la mémoire tampon sont des données à écrire dans l’adresse de fonction.

La lecture à partir de l’appareil est plus compliquée. Supposons que l’appareil I2C dans cet exemple prend en charge une fonctionnalité de « lecture rapide » qui réinitialise automatiquement le registre d’adresses de fonction à sa valeur par défaut, 0, lorsqu’un bit d’arrêt est détecté sur le bus. Avec cette fonctionnalité, le client peut lire les données de l’adresse de fonction 0 sans avoir à écrire dans le registre d’adresses de fonction. Cette fonctionnalité peut améliorer la vitesse des opérations de lecture des appareils, en particulier si la plupart des lectures proviennent de l’adresse de fonction 0 et sont relativement courtes.

Toutefois, pour lire un bloc de données à partir d’une adresse de fonction différente de zéro, le client doit toujours écrire un octet dans le registre d’adresses de fonction avant de lire le bloc de données du registre de données. Le client doit effectuer ces transferts d’écriture et de lecture en tant qu’opération de bus atomique pour empêcher le contrôleur de bus de transmettre un bit d’arrêt après l’écriture au registre d’adresses de fonction et avant la lecture à partir du registre de données. Sinon, le bit d’arrêt entraîne la lecture des données à partir de l’adresse de fonction 0 au lieu d'une adresse de fonction non nulle.

La liste suivante décrit la série de demandes d’E/S qu’un client envoie à l’appareil I2C dans cet exemple pour effectuer une opération en lecture-modification-écriture sur les données situées à une adresse de fonction différente de zéro de l’appareil :

  1. IOCTL_SPB_EXECUTE_SEQUENCE : effectuez une séquence de transfert d’E/S pour lire des données à partir de l’appareil. Le premier transfert dans cette séquence est une écriture d’octets dans le registre d’adresses de fonction. Le deuxième transfert dans la séquence est une lecture d’un certain nombre d’octets de l’adresse de fonction sélectionnée. Ces deux transferts sont effectués de manière atomique sur le bus.
  2. IRP_MJ_WRITE : écrire des données sur l’appareil. Le premier octet de la mémoire tampon d’écriture pour cette requête est la valeur à écrire dans le registre d’adresses de fonction. Les octets restants dans la mémoire tampon sont des données à écrire dans l’adresse de fonction sélectionnée.

D’autres modèles de requêtes peuvent être utilisés à la place pour effectuer cette opération de lecture-modification-écriture. Par exemple, la demande de IRP_MJ_WRITE à l’étape 2 peut être remplacée par une demande de IOCTL_SPB_EXECUTE_SEQUENCE qui spécifie deux transferts de données, qui sont tous deux des écritures. Le premier transfert de la séquence charge un octet dans le registre d’adresses de fonction. Le deuxième transfert écrit les octets de données dans l’adresse de fonction sélectionnée. Cette requête, contrairement à la requête IRP_MJ_WRITE à l’étape 2, ne nécessite pas que le client combine l’octet d’adresse de fonction et les octets de données dans la même mémoire tampon d’écriture.

Pour effectuer une lecture-écriture sur l’adresse de fonction 0 dans cet appareil, la demande IOCTL_SPB_EXECUTE_SEQUENCE à l’étape 1 de la liste précédente peut être remplacée par une demande de lecture simple (IRP_MJ_READ).