Freigeben über


Atomic Bus-Vorgänge

Um bestimmte Hardwarefunktionen eines mit SPB verbundenen Peripheriegeräts zu verwenden, muss ein Client des SPB-Controllers (d. h. ein Peripherietreiber) möglicherweise eine Sequenz von Datenübertragungen zum und vom Gerät als Atombusvorgang durchführen. Die Übertragungssequenz ist atomar, da kein anderer Client Daten zu oder von einem Gerät im Bus übertragen kann, bis die Sequenz abgeschlossen ist.

Die typische Möglichkeit für einen Client, eine Übertragungssequenz als Atombusvorgang auszuführen, besteht darin, eine IOCTL_SPB_EXECUTE_SEQUENCE-Anforderung an das Zielgerät zu senden. In dieser Anforderung gibt der Client die Sequenz als Liste einfacher Lese- und Schreibübertragungen an. Die Liste kann eine beliebige Länge aufweisen. Die Lese- und Schreibvorgänge werden in der Reihenfolge ausgeführt, in der sie aufgelistet sind, und jeder Lese- oder Schreibzugriff kann eine beliebige Anzahl von Bytes übertragen. Die meisten SPB-Controller unterstützen IOCTL_SPB_EXECUTE_SEQUENCE Anforderungen.

SPB-Controllersperren

Eine weniger häufige Methode zum Ausführen einer atomaren Übertragungssequenz ist die Verwendung einer SPB-Controllersperre. Ein Client sendet eine IOCTL_SPB_LOCK_CONTROLLER Anforderung zum Abrufen der Sperre und eine IOCTL_SPB_UNLOCK_CONTROLLER Anforderung zum Freigeben der Sperre. Wenn ein Client die Controllersperre hält, wird jede Sequenz einfacher Lese- und Schreibanforderungen (IRP_MJ_READ und IRP_MJ_WRITE), die der Client an das Gerät sendet, als atomischer Vorgang auf dem Bus ausgeführt.

Die meisten mit SPB verbundenen Peripheriegeräte erfordern keine Controllersperren, und die meisten SPB-Controllertreiber implementieren keine Unterstützung für diese Sperren. Einige Clients müssen jedoch möglicherweise Controllersperren verwenden, um auf Geräte mit ungewöhnlichen Features zuzugreifen.

Beispielsweise kann ein Gerät Gerätefunktionen implementieren, auf die nur über Lese-/Änderungs-Schreibvorgänge zugegriffen werden kann, die auf dem Bus atomar sind. Um einen solchen Vorgang auszuführen, sendet der Client die folgenden vier E/A-Anforderungen (in der angegebenen Reihenfolge):

  1. IOCTL_SPB_LOCK_CONTROLLER – Abrufen der Controllersperre.
  2. IRP_MJ_READ : Liest einen Datenblock von einem Zielgerät.
  3. IRP_MJ_WRITE : Schreiben Sie die geänderten Daten zurück auf das Gerät.
  4. IOCTL_SPB_UNLOCK_CONTROLLER : Lassen Sie die Controllersperre los.

Nach dem Lesevorgang in der vorherigen Liste interpretiert der Client die Daten, die vom Gerät gelesen wurden, und ändert die Daten, bevor er sie zurück auf das Gerät schreibt.

Nur wenige mit SPB verbundene Geräte verfügen jedoch über Features, die Controllersperren erfordern. Für die meisten Geräte, die Atombusvorgänge erfordern, sind IOCTL_SPB_EXECUTE_SEQUENCE Anforderungen ausreichend.

Verwechseln Sie SPB-Controllersperren nicht mit SPB-Verbindungssperren. In dem atypischen Fall, in dem zwei Clients den Zugriff auf dasselbe mit SPB verbundene Peripheriegerät gemeinsam nutzen, kann jeder Client eine Verbindungssperre verwenden, um vorübergehend exklusiven Zugriff auf das Gerät zu erhalten. Weitere Informationen finden Sie unter SPB-Verbindungssperren.

Hardwarebussignale

Um eine IOCTL_SPB_EXECUTE_SEQUENCE-Anforderung zu verarbeiten, konfiguriert ein SPB-Controllertreiber die Controllerhardware so, dass während der Übertragungssequenz die entsprechenden Signale auf dem Bus generiert werden. Peripheriegeräte, die an den Bus angeschlossen sind, können diese Signale verwenden, um zu erkennen, wann ein Atombusbetrieb im Gange ist. Der Satz von Hardwaresignalen, die ein SPB-Controller verwendet, um eine Übertragungssequenz als Atombusvorgang auszuführen, hängt vom Bustyp ab.

Bei einemI2C-Bus startet der Controller eine Sequenz, indem er ein Startbit auf dem Bus überträgt, und beendet eine Sequenz durch Übertragung eines Stoppbits. Zwischen den Start- und Stoppbits erfolgt die Sequenz der Datenübertragungen zum und vom Gerät als einzelner Atombusvorgang. Mit Ausnahme der endgültigen Übertragung in der Sequenz folgt auf jede Übertragung einI2C-Neustartvorgang (ein wiederholtes Startbit, dem kein Stoppbit vorangestellt ist).

Bei einem SPI-Bus startet der Controller eine Sequenz, indem er die Chipauswahllinie an das Zielgerät angibt, und beendet die Sequenz, indem die Chipauswahllinie deassert wird. Indem die Chip-Select-Linie während einer Sequenz von Datenübertragungen über den Bus kontinuierlich bestätigt wird, werden die Übertragungen als einzelner Atombusbetrieb durchgeführt.

EinI2C-Beispielgerät

Ein typisches Peripheriegerät auf einem I2C-Bus kann mehrere interne Gerätefunktionen implementieren. Für den Zugriff auf einige dieser Funktionen kann ein Client IOCTL_SPB_EXECUTE_SEQUENCE Anforderungen verwenden.

Beispielsweise kann einI2C-Peripheriegerät die folgenden beiden internen Register enthalten:

  • Ein Funktionsadressenregister , in das der Client die interne Adresse der Gerätefunktion schreibt, auf die zugegriffen werden soll.
  • Ein Datenregister , über das der Client Daten aus der angegebenen Funktionsadresse liest oder in die angegebene Funktionsadresse schreibt.

Das I2C-Peripheriegerät in diesem Beispiel interpretiert das erste Byte, das nach einem Startbit in das Gerät geschrieben wird, als Funktionsadresse, die in das Funktionsadressenregister geladen werden soll. Alle zusätzlichen Bytes, die vor Ablauf der Sequenz an oder vom Gerät übertragen werden (wie durch das Stoppbit angegeben), werden vom Gerät als Daten behandelt, die über das Datenregister übertragen werden sollen.

Um einen Schreibvorgang auszuführen, sendet der Client eine Schreibanforderung (IRP_MJ_WRITE), bei der das erste Byte im Schreibpuffer die Funktionsadresse ist und die verbleibenden Bytes im Puffer Daten sind, die in die Funktionsadresse geschrieben werden sollen.

Das Lesen vom Gerät ist komplizierter. Angenommen, dasI2C-Gerät in diesem Beispiel unterstützt ein Feature "Schnelles Lesen", das das Funktionsadressenregister automatisch auf den Standardwert 0 zurücksetzt, wenn ein Stoppbit im Bus erkannt wird. Mit dieser Funktion kann der Client die Daten aus der Funktionsadresse 0 lesen, ohne zuerst in das Funktionsadressenregister schreiben zu müssen. Dieses Feature kann die Geschwindigkeit von Gerätelesevorgängen verbessern, insbesondere wenn die meisten Lesevorgänge von der Funktionsadresse 0 stammen und relativ kurz sind.

Um jedoch einen Datenblock aus einer Funktionsadresse ungleich null zu lesen, muss der Client vor dem Lesen des Datenblocks aus dem Datenregister weiterhin ein Byte in das Funktionsadressenregister schreiben. Der Client muss diese Schreib- und Leseübertragungen als atomischen Busvorgang durchführen, um zu verhindern, dass der Buscontroller nach dem Schreiben in das Funktionsadressenregister und vor dem Lesen aus dem Datenregister ein Stoppbit überträgt. Andernfalls bewirkt das Stoppbit, dass die Daten aus der Funktionsadresse 0 statt aus der Funktionsadresse ungleich null gelesen werden.

Die folgende Liste beschreibt die Reihe von E/A-Anforderungen, die ein Client in diesem Beispiel an dasI2C-Gerät sendet, um einen Lese-/Änderungs-Schreibvorgang für Daten auszuführen, die sich an einer Funktionsadresse ungleich null auf dem Gerät befinden:

  1. IOCTL_SPB_EXECUTE_SEQUENCE : Führen Sie eine E/A-Übertragungssequenz aus, um Daten vom Gerät zu lesen. Die erste Übertragung in dieser Sequenz ist ein Byteschreibvorgang in das Funktions-Adressregister. Die zweite Übertragung in der Sequenz ist ein Lesevorgang einer bestimmten Anzahl von Bytes aus der ausgewählten Funktionsadresse. Diese beiden Übertragungen werden atomar im Bus durchgeführt.
  2. IRP_MJ_WRITE : Schreiben von Daten auf das Gerät. Das erste Byte im Schreibpuffer für diese Anforderung ist der Wert, der in das Funktionsadressenregister geschrieben werden soll. Die verbleibenden Bytes im Puffer sind Daten, die in die ausgewählte Funktionsadresse geschrieben werden sollen.

Stattdessen können andere Anforderungsmuster verwendet werden, um diesen Lese-,Änderungs-/Schreibvorgang auszuführen. Beispielsweise kann die IRP_MJ_WRITE-Anforderung in Schritt 2 durch eine IOCTL_SPB_EXECUTE_SEQUENCE-Anforderung ersetzt werden, die zwei Datenübertragungen angibt, bei denen es sich bei beiden um Schreibvorgänge handelt. Die erste Übertragung in der Sequenz lädt ein Byte in das Funktions-Adressregister. Bei der zweiten Übertragung werden die Datenbytes in die ausgewählte Funktionsadresse geschrieben. Diese Anforderung erfordert im Gegensatz zur IRP_MJ_WRITE-Anforderung in Schritt 2 nicht, dass der Client das Funktionsadressenbyte und die Datenbytes im gleichen Schreibpuffer kombiniert.

Zum Ausführen eines Lese-/Änderungs-Schreibvorgangs für die Funktionsadresse 0 auf diesem Gerät kann die IOCTL_SPB_EXECUTE_SEQUENCE-Anforderung in Schritt 1 der vorherigen Liste durch eine einfache Leseanforderung (IRP_MJ_READ) ersetzt werden.