Freigeben über


Grundlegendes Anrufmuster für DMA-Routinen der Version 3

Um eine DMA-Übertragung durchzuführen, die die Routinen in Version 3 der DMA-Betriebsschnittstelle verwendet, sollte Ihr Treiber die in der folgenden Liste beschriebenen Schritte ausführen. Diese Schritte gelten für untergeordnete Geräte und Busmastergeräte. Version 3 dieser Schnittstelle ist ab Windows 8 verfügbar. Weitere Informationen zu den Routinen in dieser Schnittstelle finden Sie unter DMA_OPERATIONS.

Schritt 1: Abrufen eines DMA-Adapterobjekts

In Vorbereitung auf eine DMA-Übertragung ruft der Treiber die IoGetDmaAdapter-Routine auf, um ein DMA-Adapterobjekt abzurufen. Ein DMA-Adapterobjekt ist ein Softwareobjekt, das entweder ein Busmastergerät oder eine Anforderungszeile auf einem System-DMA-Controller darstellt. Dieses Objekt enthält die DMA-Betriebsschnittstelle für den Bus, der zum Übertragen von Daten an oder vom Gerät verwendet wird. Darüber hinaus synchronisiert dieses Objekt den Zugriff des Treibers auf die freigegebenen Ressourcen, die zum Ausführen der Übertragung erforderlich sind. Weitere Informationen finden Sie in der Einführung in Adapterobjekte.

Schritt 2: Abrufen einer Beschreibung der erforderlichen DMA-Ressourcen

Der Treiber ruft die GetDmaTransferInfo-Routine auf, um eine Beschreibung der DMA-Ressourcen abzurufen, die für die Übertragung erforderlich sind.

Die Eingabeparameter für diesen Aufruf beschreiben den Speicherpuffer, der für die Übertragung verwendet werden soll, und die Richtung (Lese- oder Schreibzugriff) der Übertragung.

Die Ressourcenanforderungen, die von diesem Aufruf abgerufen werden, umfassen die Anzahl der Kartenregister und die Größe der Streuliste, die benötigt wird, um den Datenpuffer für die Übertragung zu beschreiben. Im nachfolgenden Aufruf der AllocateAdapterChannelEx-Routine (siehe Schritt 3) stellt der Treiber die Anzahl der Kartenregister als Eingabeparameter bereit.

Schritt 3: Anfordern der erforderlichen DMA-Ressourcen

Der Treiber ruft die AssignAdapterChannelEx-Routine auf, um Ressourcen zuzuweisen, die dem DMA-Adapterobjekt zugewiesen werden sollen. Zu diesen Ressourcen gehören ein DMA-Kanal und Kartenregister.

Ein AllocateAdapterChannelEx-Aufruf kann asynchron oder synchron sein.

Wenn das DMA_SYNCHRONOUS_CALLBACK Flag nicht festgelegt ist, ist der Aufruf asynchron. In diesem Fall verweist der ExecutionRoutine-Parameter auf eine vom Aufrufer bereitgestellte Ausführungsroutine, die aufgerufen wird, wenn die angeforderten Ressourcen verfügbar sind. Bei erfolgreicher Ausführung gibt ein asynchroner AllocateAdapterChannelEx-Aufruf STATUS_SUCCESS zurück, ohne auf die Ausführungsroutine zu warten.

Wenn das DMA_SYNCHRONOUS_CALLBACK Flag festgelegt ist, ist der AllocateAdapterChannelEx-Aufruf synchron. In diesem Fall ist der ExecutionRoutine-Parameter im Aufruf optional, und "AllocateAdapterChannelEx " verhält sich wie folgt:

  • Wenn ExecutionRoutine ungleich NULL ist und die DMA-Ressourcen sofort zugeordnet werden können, ruft AllocateAdapterChannelEx die Ausführungsroutine im Kontext des aufrufenden Threads auf. Nach Abschluss der Ausführung der Ausführungsroutine gibt AllocateAdapterChannelEx STATUS_SUCCESS zurück. Wenn die Ressourcen nicht sofort verfügbar sind, schlägt "AllocateAdapterChannelEx " fehl und gibt den Fehlerstatuscode STATUS_INSUFFICIENT_RESOURCES zurück.

  • Wenn ExecutionRoutine NULL ist und AllocateAdapterChannelEx sofort die DMA-Ressourcen zuordnen kann, gibt AllocateAdapterChannelEx STATUS_SUCCESS zurück. Wenn nicht sofort alle Ressourcen verfügbar sind, schlägt der Aufruf mit dem Fehlerstatuscode STATUS_INSUFFICIENT_RESOURCES fehl.

Bei synchronen Aufrufen, die STATUS_SUCCESS zurückgeben, schreibt AllocateAdapterChannelEx die Basisadresse der zugeordneten Zuordnungsregister an die Adresse, auf die der MapRegisterBase-Parameter verweist, falls der MapRegisterBase-Parameter für AllocateAdapterChannelEx ungleich NULL ist. Wenn "ExecutionRoutine " NULL ist, muss MapRegisterBase nicht NULL sein. Wenn ExecutionRoutine ungleich NULL ist, ist der MapRegisterBase-Parameter für "AllocateAdapterChannelEx " optional, und die Ausführungsroutine empfängt die Basisadresse des Kartenregisters als Eingabeparameter.

Für asynchrone AllocateAdapterChannelEx-Aufrufe muss ExecutionRoutine nicht NULL sein, und die Ausführungsroutine empfängt die Basisadresse des Kartenregisters als Eingabeparameter.

In nachfolgenden Aufrufen der MapTransferEx-Routine (siehe Schritt 5) stellt der Treiber die Basisadresse des Kartenregisters als Eingabeparameter bereit.

Wenn ExecutionRoutine ungleich NULL ist, gibt die Ausführungsroutine einen Statuswert zurück, um die Anordnung der zugeordneten Ressourcen anzugeben. Bei System-DMA-Übertragungen muss dieser Rückgabewert KeepObject sein. Dieser Wert informiert das Betriebssystem, dass das Adapterobjekt (und alle zugeordneten Ressourcen) verwendet wird und nicht freigegeben werden sollte. Wenn keine Ausführungsroutine bereitgestellt wird, muss der Treiber stattdessen die FreeAdapterObject-Routine aufrufen und KeepObject als AllocationOption-Parameter angeben.

Schritt 4: Abbrechen der ausstehenden Ressourcenanforderung bei Bedarf

Nachdem ein AllocateAdapterChannelEx-Aufruf einen DMA-Adapter in die Warteschlange gestellt hat, um auf DMA-Ressourcen zu warten, kann der Treiber ggf. die CancelAdapterChannel-Routine aufrufen, um die ausstehende Ressourcenanforderung abzubrechen.

Wenn CancelAdapterChannel TRUE zurückgibt, wird die Ressourcenanforderung erfolgreich abgebrochen. Wenn eine Ausführungsroutine im AllocateAdapterChannelEx-Aufruf bereitgestellt wurde, wird diese Routine nicht ausgeführt.

Wenn CancelAdapterChannel FALSE zurückgibt, kann die Ressourcenanforderung nicht abgebrochen werden, da sie bereits erteilt wurde. Wenn eine Ausführungsroutine im AllocateAdapterChannelEx-Aufruf bereitgestellt wurde, wird diese Routine aufgerufen.

Schritt 5: Initialisieren der DMA-Ressourcen und Starten der DMA-Übertragung

Der Treiber ruft MapTransferEx auf, um die DMA-Ressourcen zu initialisieren und die DMA-Übertragung zu starten. Dieser Aufruf kann im selben Treiberthread auftreten, der " AllocateAdapterChannelEx" aufruft, oder es kann in der Ausführungsroutine auftreten, die der Treiber für "AllocateAdapterChannelEx" bereitstellt. Wenn mehr als ein MapTransferEx-Aufruf erforderlich ist, um den gesamten DMA-Datenpuffer zu übertragen, kann ein späterer MapTransferEx-Aufruf in der Abschlussroutine für den vorherigen MapTransferEx-Aufruf auftreten.

MapTransferEx unterstützt verkettete MDLs als Eingabeparameter. Jede MDL beschreibt einen Bereich des DMA-Puffers, der im virtuellen Speicher zusammenhängend ist. Wenn MapTransferEx die Scatter/Gather-Liste erstellt, verarbeitet es automatisch Übergänge von einem virtuell zusammenhängenden Pufferbereich zum nächsten, ohne dass ein Eingriff des Treibers erforderlich ist. Weitere Informationen finden Sie unter Using the MapTransferEx Routine.

Bei einer System-DMA-Übertragung kann ein Zeiger auf eine DMA-Abschlussroutine im optionalen DmaCompletionRoutine-Parameter an MapTransferEx übergeben werden. Diese Routine ist geplant, auf Dispatch-Ebene als Reaktion auf einen Interrupt vom DMA-Controller des Systems ausgeführt zu werden, der anzeigt, dass die DMA-Übertragung abgeschlossen ist.

Wenn MapTransferEx die gesamte angeforderte Übertragungsgröße nicht zuordnen kann, wird der Ausgabeparameter *Length auf die zugeordnete Länge festgelegt und STATUS_SUCCESS zurückgegeben.

Schritt 6: Führen Sie bei Bedarf hardwarespezifische Vorgänge aus

MapTransferEx gibt STATUS_SUCCESS zurück, um anzugeben, dass die DMA-Übertragung erfolgreich initiiert wird. Auf einigen Plattformen muss der Treiber möglicherweise eine zusätzliche Aktion ausführen, außerhalb des MapTransferEx-Aufrufs , um die Übertragung zu starten, aber diese Art von verzögerter Start ist für alle Plattformen nicht erforderlich. Treiber dürfen nicht von solchen Verzögerungen für Entscheidungen über die Verwendung und das Freigeben zugeordneter Ressourcen abhängen.

Die Routinen in der DMA-Operationsschnittstelle verwalten die Cachekohärenz für DMA-Übertragungen auf eine Weise, die für die Treiber transparent ist, die diese Routinen verwenden. Auf Plattformen, die die Cachekoherenz in der Hardware nicht erzwingen, stellt MapTransferEx sicher, dass Prozessordatencaches vor Schreibvorgängen (Speicher-zu-Gerät)-Übertragungen geleert werden. Bei Lesevorgängen (Geräte-zu-Speicher-Übertragungen) werden die Caches während des Aufrufs der FlushAdapterBuffersEx-Routine (siehe Schritt 8) ungültig, die jedem MapTransferEx-Aufruf folgt.

Schritt 7: Empfangen einer Benachrichtigung, wenn die DMA-Übertragung abgeschlossen ist

Wenn eine DMA-Übertragung abgeschlossen ist, wird der Treiber auf eine der folgenden beiden Arten benachrichtigt:

  • Eine Unterbrechung des Gerätetreibers für ein Bus-Master-Gerät
  • Ausführung der vom Treiber bereitgestellten Abschlussroutine für ein untergeordnetes Gerät, das einen System-DMA-Controller verwendet

Bei einer System-DMA-Übertragung kann ein Treiber eine Abschlussroutine als Eingabeparameter an MapTransferEx bereitstellen.

Schritt 8: Leeren aller Daten, die im Cache verbleiben

Nach Abschluss der DMA-Übertragung muss der Treiber die FlushAdapterBuffersEx-Routine aufrufen, um alle Daten zu leeren, die im Cache verbleiben. Der Treiber muss FlushAdapterBuffersEx nach jedem MapTransferEx-Aufruf aufrufen.

Wenn ein MapTransferEx-Aufruf nur einen Teil des DMA-Datenpuffers zuordnet, muss der Treiber MapTransferEx erneut aufrufen, um die verbleibenden Daten zuzuordnen. Eine komplexe Übertragung erfordert möglicherweise mehrere MapTransferEx-Aufrufe . Wiederholen Sie für jeden zusätzlichen MapTransferEx-Aufruf die Schritte 5 bis 8.

Schritt 9: Freigeben des DMA-Kanals und Kartenregister

Nachdem der gesamte DMA-Datenpuffer erfolgreich zugeordnet und die endgültige Übertragung abgeschlossen ist, muss der Treiber die FreeAdapterChannel-Routine aufrufen, um den DMA-Kanal und alle zuvor zugeordneten Kartenregister freizustellen.

Schritt 10: Freigeben des DMA-Adapterobjekts

Nachdem alle DMA-Übertragungen abgeschlossen sind und alle zuvor zugeordneten Kartenregister freigegeben werden, ruft der Treiber die PutDmaAdapter-Routine auf, um das Adapterobjekt freizugeben.