Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Der Anruf des E/A-Managers an die Verteilerroutine eines Fahrers ist die erste Stufe bei der Erfüllung einer Geräte-E/A-Anforderung. Die StartIo-Routine ist die zweite Stufe. Jeder Gerätetreiber mit einer StartIo-Routine ruft IoStartPacket wahrscheinlich aus den DispatchRead - und DispatchWrite-Routinen auf, und normalerweise für eine Teilmenge der I/O-Steuerungscodes, die es in seiner DispatchDeviceControl-Routine unterstützt. Die IoStartPacket-Routine fügt das IRP zur vom System bereitgestellten Gerätewarteschlange hinzu, oder ruft, wenn die Warteschlange leer ist, sofort die StartIo-Routine des Treibers auf, um das IRP zu verarbeiten.
Sie können davon ausgehen, dass das Zielgerät nicht ausgelastet ist, wenn die StartIo-Routine eines Treibers aufgerufen wird. Dies liegt daran, dass der E/A-Manager StartIo unter zwei Umständen aufruft; Entweder eine der Dispatch-Routinen des Treibers hat nur IoStartPacket genannt, und die Gerätewarteschlange war leer, oder die DpcForIsr-Routine des Treibers schließt eine andere Anforderung ab und hat gerade IoStartNextPacket aufgerufen, um das nächste IRP zu dequeue.
Bevor die StartIo-Routine in einem höchsten Gerätetreiber aufgerufen wird, sollte die Dispatch-Routine dieses Treibers den Benutzerpuffer überprüft und gesperrt haben, falls erforderlich, um gültige zugeordnete Pufferadressen in der IRP-Warteschlange für die StartIo-Routine bereitzustellen. Wenn ein Gerätetreiber auf höchster Ebene seine Geräteobjekte für direkte E/A (oder für weder gepufferte noch direkte E/A) einrichtet, kann der Treiber das Sperren eines Benutzerpuffers nicht auf die StartIo-Routine zurückstellen. jede StartIo-Routine wird in einem beliebigen Threadkontext bei IRQL = DISPATCH_LEVEL aufgerufen.
Hinweis
Auf jeden Pufferspeicher, auf den von der StartIo-Routine eines Treibers zugegriffen werden soll, muss entweder gesperrt sein oder aus residentem, systemgebundenem Speicher zugewiesen werden und in einem beliebigen Thread-Kontext zugänglich sein.
Im Allgemeinen ist jede StartIo-Routine des Gerätetreibers auf niedrigerer Ebene dafür verantwortlich, IoGetCurrentIrpStackLocation mit dem Eingabe-IRP aufzurufen und dann die anforderungsspezifische Verarbeitung auszuführen, um den E/A-Vorgang auf seinem Gerät zu starten. Anforderungsspezifische Verarbeitung kann Folgendes umfassen:
Einrichten oder Aktualisieren von Statusinformationen zur aktuellen Anfrage, die der Treiber verwaltet. Die Statusinformationen können in der Geräteerweiterung des Zielgerätobjekts oder an anderer Stelle im vom Treiber zugewiesenen nicht seitengebundenen Pool gespeichert werden.
Wenn beispielsweise ein Gerätetreiber einen InterruptExpected Boolean für den aktuellen Übertragungsvorgang verwaltet, kann die StartIo-Routine diese Variable auf TRUE festlegen. Wenn der Treiber einen Timeoutzähler für den aktuellen Vorgang verwaltet, kann die StartIo-Routine diesen Wert einrichten, oder die StartIo-Routine kann die CustomTimerDpc-Routine des Treibers in die Warteschlange stellen.
Wenn die StartIo-Routine den Zugriff auf Statusinformationen oder Hardwareressourcen mit anderen Treiberroutinen teilt, müssen die Statusinformationen oder -ressourcen durch eine Drehungssperre geschützt werden. (Siehe Drehsperren.)
Wenn die StartIo-Routine Den Zugriff auf Statusinformationen oder Ressourcen mit der InterruptService-Routine des Treibers teilt, muss StartIoKeSynchronizeExecution verwenden, um eine SynchCritSection-Routine aufzurufen, die auf den Status oder die Ressourceninformationen zugreift. (Siehe Verwenden kritischer Abschnitte.)
Zuweisen einer Sequenznummer zum IRP, falls der Treiber beim Verarbeiten des IRP einen Geräte-E/A-Fehler protokollieren muss.
Weitere Informationen finden Sie unter Fehler beim Protokollieren.
Falls erforderlich, übersetzen Sie die Parameter im E/A-Stapel des Treibers in gerätespezifische Werte.
Beispielsweise muss ein Datenträgertreiber den Startsektor oder byte-Offset auf die physische Datenträgeradresse für einen Übertragungsvorgang berechnen und ob die angeforderte Länge der Übertragung eine bestimmte Sektorgrenze überschreitet oder die Übertragungskapazität seines physischen Geräts überschreitet.
Wenn der Treiber ein Wechselmediengerät steuert, überprüfen Sie vor der Programmierung des Geräts für E/A auf Medienänderungen. Benachrichtigen Sie das darüberliegende Dateisystem, wenn sich die Medien geändert haben.
Weitere Informationen finden Sie unter Unterstützen von Wechselmedien.
Wenn das Gerät DMA verwendet, sollten Sie prüfen, ob die angeforderte Länge (Anzahl der zu übertragenden Bytes, die sich im I/O-Stapel des I/O-Stapels des Treibers befinden) in Teilübertragungsvorgänge aufgeteilt werden sollte, wie in den Eingabe-/Ausgabetechniken erläutert, vorausgesetzt, dass ein eng gekoppelter Treiber große Übertragungen für den Gerätetreiber nicht vorab aufspreift.
Die StartIo-Routine eines solchen Gerätetreibers kann auch für das Aufrufen von KeFlushIoBuffers verantwortlich sein und, wenn der Treiber paketbasierte DMA verwendet, zum Aufrufen von AllocateAdapterChannel mit der AdapterControl-Routine des Treibers.
Weitere Informationen finden Sie in Adapterobjekte und DMA und Aufrechterhaltung der Cachekohärenz.
Falls das Gerät PIO verwendet, erfolgt das Zuordnen der virtuellen Basisadresse des Puffers, die im IRP bei >MdlAddress beschrieben ist, zu einer Systemraumadresse mit MmGetSystemAddressForMdlSafe.
Für Leseanforderungen kann die StartIo-Routine des Gerätetreibers für das Aufrufen von KeFlushIoBuffers verantwortlich sein, bevor PIO-Vorgänge beginnen. Weitere Informationen finden Sie unter Verwalten der Cachekohärenz .
Wenn ein nicht-WDM-Treiber ein Controllerobjekt verwendet, rufen Sie IoAllocateController auf, um seine ControllerControl-Routine zu registrieren.
Wenn der Treiber abbruchfähige IRPs verarbeitet, überprüfen Sie, ob die Eingabe-IRP bereits abgebrochen wurde.
Wenn ein Eingabe-IRP abgebrochen werden kann, bevor es vollständig verarbeitet wird, muss die StartIo-RoutineIoSetCancelRoutine mit dem IRP und dem Einstiegspunkt der Cancel-Routine des Treibers aufrufen. Die StartIo-Routine muss den Cancel-Spinlock für ihren Aufruf von IoSetCancelRoutine erwerben. Alternativ kann ein Treiber IoSetStartIoAttributes verwenden, um das NonCancelable-Attribut für die StartIo-Routine auf TRUE festzulegen. Dadurch wird verhindert, dass das System versucht, ein IRP abzubrechen, das von einem Aufruf an IoStartPacket an StartIo übergeben wurde.
In der Regel verfügt ein Treiber, der gepufferte E/A verwendet, über eine einfachere StartIo-Routine als eine, die direkte E/A verwendet. Treiber, die gepufferte E/A verwenden, übertragen kleine Datenmengen für jede Übertragungsanforderung, während solche, die direkte E/A (ob DMA oder PIO) verwenden, große Datenmengen in gesperrte Puffer oder aus diesen übertragen, die physische Seitenbegrenzungen im Systemspeicher überschreiten können.
Übergeordnete Treiber über physische Gerätetreiber legen in der Regel ihre Geräteobjekte so ein, dass sie mit denen ihrer jeweiligen Gerätetreiber übereinstimmen. Ein Treiber auf höchster Ebene, insbesondere ein Dateisystemtreiber, kann jedoch Geräteobjekte für weder direkte noch gepufferte E/A einrichten.
Treiber, die ihre Geräteobjekte für gepufferte E/A-Vorgänge einrichten, können sich darauf verlassen, dass der E/A-Manager in allen an den Treiber gesendeten IRPs gültige Puffer übergibt. Treiber auf niedrigerer Ebene, die Geräteobjekte für direkte E/A einrichten, können sich auf den Treiber der höchsten Ebene in ihrer Kette verlassen, um gültige Puffer in allen IRPs weiterzugeben, die über alle Zwischentreiber an den zugrunde liegenden niedrigen Gerätetreiber gesendet werden.
Verwenden von gepufferten E/A-Vorgängen in StartIo-Routinen
Wenn die DispatchRead-, DispatchWrite- oder DispatchDeviceControl-Routine eines Treibers feststellt, dass eine Anforderung gültig ist und IoStartPacket aufruft der E/A-Manager die StartIo-Routine des Treibers, um die IRP sofort zu verarbeiten, wenn die Gerätewarteschlange leer ist. Wenn die Warteschlange nicht leer ist, reiht IoStartPacket das IRP in die Warteschlange ein. Schließlich bewirkt ein Aufruf von IoStartNextPacket aus der DpcForIsr- oder CustomDpc-Routine des Treibers, dass der I/O-Manager die IRP aus der Warteschlange entfernt und die StartIo-Routine des Treibers aufruft.
Die StartIo-Routine ruft IoGetCurrentIrpStackLocation auf und bestimmt, welcher Vorgang ausgeführt werden muss, um die Anforderung zu erfüllen. Es bereitet das IRP in jeder erforderlichen Weise vor, bevor das physische Gerät für die Durchführung der Ein-/Ausgabe (E/A)-Anforderung programmiert wird.
Wenn der Zugriff auf das physische Gerät (oder die Geräteerweiterung) mit einer InterruptService-Routine synchronisiert werden muss, muss die StartIo-Routine eine SynchCritSection-Routine aufrufen, um die erforderliche Geräteprogrammierung durchzuführen. Weitere Informationen finden Sie unter Using Critical Sections.
Ein physischer Gerätetreiber, der gepufferte E/A verwendet, überträgt Daten entweder an oder aus einem Systemspeicherpuffer, der vom E/A-Manager zugewiesen wird, den der Treiber in jedem IRP bei Irp-AssociatedIrp.SystemBuffer> findet.
Verwenden von Direct I/O in StartIo-Routinen
Wenn die DispatchRead-, DispatchWrite- oder DispatchDeviceControl-Routine eines Treibers feststellt, dass eine Anforderung gültig ist und IoStartPacket aufruft der E/A-Manager die StartIo-Routine des Treibers, um die IRP sofort zu verarbeiten, wenn die Gerätewarteschlange leer ist. Wenn die Warteschlange nicht leer ist, wird das IRP von IoStartPacket in die Warteschlange gestellt. Schließlich bewirkt ein Aufruf von IoStartNextPacket aus der DpcForIsr- oder CustomDpc-Routine des Treibers, dass der I/O-Manager die IRP aus der Warteschlange entfernt und die StartIo-Routine des Treibers aufruft.
Die StartIo-Routine ruft IoGetCurrentIrpStackLocation auf und bestimmt, welcher Vorgang ausgeführt werden muss, um die Anforderung zu erfüllen. Es verarbeitet IRP auf beliebige Weise, z. B. durch das Aufteilen einer großen DMA-Übertragungsanforderung in Teilübertragungsbereiche und durch das Speichern des Zustands in Bezug auf die Länge einer eingehenden Übertragungsanforderung, die aufgeteilt werden muss. Anschließend wird das physische Gerät so programmiert, dass die E/A-Anforderung ausgeführt wird.
Wenn der Zugriff auf das physische Gerät (oder die Geräteerweiterung) mit dem ISR des Treibers synchronisiert werden muss, muss die StartIo-Routine eine vom Treiber bereitgestellte SynchCritSection-Routine verwenden, um die erforderliche Programmierung durchzuführen. Weitere Informationen finden Sie unter Using Critical Sections.
Jeder Treiber, der direkte E/A verwendet, liest Daten in einen gesperrten Puffer ein oder schreibt Daten aus einem gesperrten Puffer, der durch eine Speicherdeskriptorliste (MDL) beschrieben wird, und den der Treiber im IRP bei Irp-MdlAddress> findet. Ein solcher Treiber verwendet häufig gepufferte E/A für Gerätesteuerungsanforderungen. Weitere Informationen finden Sie unter Bearbeitung von Ein-/Ausgabesteuerungsanforderungen in StartIo-Routinen.
Der MDL-Typ ist ein undurchsichtiger Typ, auf den Treiber nicht direkt zugreifen. Stattdessen ordnen Treiber, die PIO verwenden, User-Space-Puffer durch Aufrufen von MmGetSystemAddressForMdlSafe mit Irp->MdlAddress als Parameter neu zu. Treiber, die DMA verwenden, übergeben außerdem Irp-MdlAddress>, um Routinen während ihrer Übertragungsvorgänge zu unterstützen, damit die Pufferadressen für ihre Geräte in logische Bereiche neu zugeordnet werden.
Es sei denn, dass ein eng gekoppelter Treiber auf einer höheren Ebene große DMA-Übertragungsanforderungen für den zugrunde liegenden Gerätetreiber aufteilt, muss die StartIo-Routine eines Gerätetreibers jede Übertragungsanforderung aufteilen, die größer ist, als sein Gerät in einem einzigen Übertragungsvorgang verwalten kann. Treiber, die System-DMA verwenden, müssen Übertragungsanforderungen aufteilen, die zu groß sind, damit der System-DMA-Controller oder ihre Geräte diese in einem einzigen Übertragungsvorgang verarbeiten können.
Wenn es sich bei dem Gerät um ein untergeordnetes DMA-Gerät handelt, muss der Treiber Übertragungen über einen System-DMA-Controller mit einem treiberzuordnungen Adapterobjekt synchronisieren, das den DMA-Kanal darstellt, und eine vom Treiber bereitgestellte AdapterControl-Routine . Der Treiber eines Busmaster-DMA-Geräts muss auch ein vom Treiber zugewiesenes Adapterobjekt verwenden, um seine Übertragungen zu synchronisieren. Zudem muss er eine AdapterControl-Routine bereitstellen, wenn er die paketbasierte DMA-Unterstützung des Systems verwendet, oder eine AdapterListControl-Routine, wenn er die Scatter/Gather-Unterstützung des Systems nutzt.
Je nach Design des Treibers kann es Übertragungs- und Gerätesteuerungsvorgänge auf einem physischen Gerät mit einem Controllerobjekt synchronisieren und eine ControllerControl-Routine bereitstellen.
Weitere Informationen finden Sie unter Adapterobjekte und DMA - und Controllerobjekte .
Verarbeitung von Ein-/Ausgabe-Steuerungsanforderungen in StartIo-Routinen
Im Allgemeinen werden nur eine Teilmenge der Geräte-E/A-Steuerungsanforderungen von der DispatchDeviceControl - oder DispatchInternalDeviceControl-Routine eines Treibers zur weiteren Verarbeitung durch die StartIo-Routine des Treibers übergeben. Die StartIo-Routine des Treibers muss nur gültige Gerätesteuerungsanforderungen verarbeiten, die Änderungen am Gerätezustand erfordern oder veränderliche Informationen zum aktuellen Gerätezustand zurückgeben.
Jeder neue Treiber muss den gleichen Satz öffentlicher E/A-Steuercodes wie alle anderen Treiber für dieselbe Art von Gerät unterstützen. Das System definiert öffentliche, gerätetypspezifische E/A-Steuercodes für IRP_MJ_DEVICE_CONTROL Anforderungen als gepufferte Anforderungen.
Daher machen physische Gerätetreiber Datenübertragungen an oder aus einem Systemspeicherpuffer, den jeder Treiber im IRP bei Irp-AssociatedIrp.SystemBuffer> für Gerätesteuerungsanforderungen findet. Selbst Treiber, die ihre Geräteobjekte für direkte E/A einrichten, verwenden gepufferte E/A,um Gerätesteuerungsanforderungen mit öffentlichen E/A-Steuercodes zu erfüllen.
Die Definition jedes E/A-Steuerelementcodes bestimmt, ob die für diese Anforderung übertragenen Daten gepuffert werden. Alle privat definierten E/A-Steuerungscodes für treiberspezifische IRP_MJ_INTERNAL_DEVICE_CONTROL-Anforderungen zwischen gekoppelten Treibern können einen Code mit der Methode Pufferung, der Methode Direkt oder der Methode Keine definieren. Im Allgemeinen sollte jeder privat definierte E/A-Steuerelementcode ohne Angabe einer Methode definiert werden, wenn ein eng gekoppelter Treiber auf höherer Ebene einen Puffer für diese Anforderung zuweisen muss.
Programmieren des Geräts für E/A-Vorgänge
In der Regel muss die StartIo-Routine in einem Gerätetreiber auf der niedrigsten Ebene den Zugriff auf alle Speicher- oder Geräteregister synchronisieren, die sie mit dem ISR des Treibers teilt, indem KeSynchronizeExecution verwendet wird, um eine vom Treiber bereitgestellte SynchCritSection-Routine aufzurufen. Die StartIo-Routine des Treibers verwendet die SynchCritSection-Routine , um das physische Gerät für E/A bei DIRQL tatsächlich zu programmieren. Weitere Informationen finden Sie unter Using Critical Sections.
Vor dem Aufrufen von KeSynchronizeExecution muss die StartIo-Routine alle für die Anforderung erforderlichen Vorverarbeitungen ausführen. Die Vorverarbeitung kann die Berechnung eines anfänglichen Teilübertragungsbereichs und das Speichern von Statusinformationen zur ursprünglichen Anforderung für andere Treiberroutinen umfassen.
Wenn ein Gerätetreiber DMA verwendet, ruft die StartIo-Routine in der Regel " AllocateAdapterChannel " mit einer vom Treiber bereitgestellten AdapterControl-Routine auf. Unter diesen Umständen verschiebt die StartIo-Routine die Verantwortung für die Programmierung des physischen Geräts in die AdapterControl-Routine . Es kann wiederum KeSynchronizeExecution aufrufen, damit eine vom Treiber bereitgestellte Routine SynchCritSection das Gerät für eine DMA-Übertragung programmiert.