Sichere digitale Anforderungen, die erweiterte E/A verwenden
Secure Digital (SD)-Anforderungen, die mehr als nur ein paar Bytes Daten lesen oder schreiben, müssen einen erweiterten E/A-Befehl verwenden (in der SD-Spezifikation als CMD53 bezeichnet). Der erweiterte E/A-Befehl weist den Bustreiber an, Daten über die DAT-Zeilen des SD-Karte zu übertragen. Die Merkmale einer Datenübertragung hängen von den Funktionen des SD-Controllers ab. Für instance lassen einige Controller nur programmierbare E/A (PIO) zu, andere ermöglichen den direkten Speicherzugriff (DMA). Für maximale Kompatibilität zwischen verschiedenen SD-Controllertypen sollten Gerätetreiber das Anforderungspaket mit einem Zeiger auf eine MDL laden, die den Datenpuffer beschreibt. Der Gerätetreiber muss eine eigene MDL erstellen, es sei denn, ein Treiber in einer höheren Ebene erstellt die MDL und übergibt sie an den Gerätetreiber.
Das folgende Codebeispiel zeigt, wie ein Treiber eine erweiterte E/A-Anforderung mithilfe eines datenpuffers ausführen kann, der von einer MDL beschrieben wird. Dieses Codebeispiel ähnelt dem in Secure Digital Requests That Use Direct E/O beschriebenen direkten E/A-Codebeispiel. Daher kann es hilfreich sein, das direkte E/A-Codebeispiel vor dem Studium des erweiterten E/A-Codebeispiels zu untersuchen.
Der Hauptunterschied zwischen den beiden Beispielen besteht darin, dass das erweiterte E/A-Codebeispiel veranschaulicht, wie MDLs mit einer SD-Anforderung verwendet werden. Es gibt auch geringfügige Unterschiede in der Art und Weise, wie Deskriptoren und Anforderungspakete für direkte und erweiterte E/A-Vorgänge definiert werden.
const SDCMD_DESCRIPTOR WriteIoExtendedDesc =
{SDCMD_IO_RW_EXTENDED, SDCC_STANDARD,
SDTD_WRITE, SDTT_SINGLE_BLOCK, SDRT_1};
// first, get an MDL to map the data. Call IoAllocateMdl to
// allocate an MDL and pass in a pointer to a buffer
// allocated from the non-paged pool.
mdl = IoAllocateMdl(Data, Length, FALSE, FALSE, NULL);
if (mdl == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool (mdl);
// next, allocate a request packet for the arguments of the command
sdrp = ExAllocatePool(NonPagedPool, sizeof(SDBUS_REQUEST_PACKET));
if (!sdrp) {
IoFreeMdl(mdl);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(sdrp, sizeof(SDBUS_REQUEST_PACKET));
sdrp->RequestFunction = SDRF_DEVICE_COMMAND;
sdrp->Parameters.DeviceCommand.CmdDesc =
WriteIoExtendedDesc;
// then, set up the argument and command descriptor
sdIoArgument.u.AsULONG = 0;
sdIoArgument.u.bits.Address = Offset;
// retrieve function number, the driver previously initialized
// this value with the SdBus GetProperty call
sdIoArgument.u.bits.Function = pDevExt->FunctionNumber;
sdIoArgument.u.bits.WriteToDevice = 1;
sdrp->Parameters.DeviceCommand.Argument =
sdIoArgument.u.AsULONG;
sdrp->Parameters.DeviceCommand.Mdl = mdl;
sdrp->Parameters.DeviceCommand.Length = Length;
// finally, submit the request
status = SdBusSubmitRequest(pDevExt->BusInterface.Context,sdrp);
IoFreeMdl(mdl);
ExFreePool(sdrp);
Dieses Codebeispiel umfasst die folgenden Schritte:
Initialisieren des Deskriptors
Der erste Schritt beim Senden einer Gerätebefehlsanforderung besteht darin, eine SD-Befehlsbeschreibung zu definieren, SDCMD_DESCRIPTOR. Der Deskriptor im Codebeispiel definiert einen erweiterten E/A-Schreibvorgang mit den folgenden Elementen:
Element BESCHREIBUNG Der vom Deskriptor definierte Vorgang führt einen erweiterten E/A-Schreibvorgang aus, sodass der Wert des Befehlscodes SDCMD_IO_RW_DIRECT wird.
Erweiterte E/A-Schreibvorgänge gehören zum Standardbefehlssatz (Befehlscodes 0 bis 63), sodass der diesem Element des Deskriptors zugewiesene Wert SDCC_STANDARD ist.
Schreibvorgänge erfordern eine Übertragung vom Host auf das Gerät, sodass der diesem Member des Deskriptors zugewiesene Wert SDTD_WRITE ist.
Der Deskriptor für einen erweiterten E/A-Schreibvorgang muss einen Übertragungstyp enthalten. Das Codebeispiel gibt einen einzelnen Blockschreibvorgang SDTT_SINGLE_BLOCK an, der angibt, dass der Host einen Datenblock auf das Gerät schreibt. Der Treiber hat die Größe eines Blocks durch einen vorherigen SET_BLOCKLEN-Befehl festgelegt (in diesem Codebeispiel nicht dargestellt). Eine Erläuterung des Befehls SET_BLOCKLEN und des SDTT_SINGLE_BLOCK Übertragungstyps finden Sie unter Die Spezifikation der MultiMedia Card , veröffentlicht vom technischen Komitee der MultiMedia Card Association (MMCA).
Der Deskriptor gibt einen Antworttyp von SDRT_1 an, der eine R1-Standardantwort auf den Befehl angibt und status Daten enthält. Eine Erläuterung der R1-Antwort finden Sie in der MultiMedia Card Association-Spezifikation .
Einrichten der MDL
Rufen Sie IoAllocateMdl auf, um eine MDL zuzuweisen, und übergeben Sie einen Zeiger an einen Puffer, der aus einem nicht ausgelagerten Pool zugewiesen wurde. Als Nächstes übernimmt die MmBuildMdlForNonPagedPool-Routine die neu zugewiesene MDL, die einen virtuellen Speicherpuffer im Pool ohne Auslagerung angibt, und aktualisiert ihn, um die zugrunde liegenden physischen Seiten zu beschreiben. Aufrufer von MmBuildMdlForNonPagedPool müssen unter IRQL <= DISPATCH_LEVEL ausgeführt werden.
Initialisieren Sie das Anforderungspaket , indem Sie die folgenden Schritte ausführen:
Definieren Sie die Anforderungsfunktion:
Nach dem Erstellen eines SD-Deskriptors initialisiert das Codebeispiel das Anforderungspaket SDBUS_REQUEST_PACKET. Das RequestFunction-Element des Anforderungspakets gibt an, ob die Anforderung einen Gerätebefehl (Wert von SDRF_DEVICE_COMMAND) oder einen Eigenschaftsvorgang (Wert von SDRF_GET_PROPERTY oder SDRF_SET_PROPERTY) enthält. Das Codebeispiel sendet einen Gerätebefehl, sodass der RequestFunction-Member auf SDRF_DEVICE_COMMAND festgelegt wird.
Laden Sie den Befehlsdeskriptor. Als Nächstes speichert das Codebeispiel den neu initialisierten Deskriptor im Parameters.DeviceCommand.CmdDesc-Member des Anforderungspakets.
Initialisieren Sie das Lese-/Schreibargument:
Das Anforderungspaket enthält eine SD_RW_DIRECT_ARGUMENT-Struktur mit dem Speicherort, an den der Bustreiber schreibt. Diese Struktur speichert auch die Nummer der Funktion, aus deren E/A-Speicherplatz der Bustreiber liest. Im Codebeispiel wird die Funktionsnummer aus der Geräteerweiterung abgerufen. Dies bedeutet, dass der Treiber diese Informationen zuvor aus dem Karte abgerufen hat (wahrscheinlich, als er das Gerät mit einer SDRF_GET_PROPERTY-Anforderung gestartet und in der Geräteerweiterung gespeichert hat.
Übermitteln der Anforderung
Nach dem Initialisieren des Deskriptors und des Anforderungspakets verwendet das Beispiel die synchrone Anforderungsroutine SdBusSubmitRequest , um die Anforderung zu übermitteln. Es übergibt das Anforderungspaket und die Schnittstellenkontextinformationen, die das System dem Treiber beim Öffnen der SD-Schnittstelle bereitgestellt hat. Da es sich um eine synchrone Anforderung handelt, muss der Treiber bei IRQL unter DISPATCH_LEVEL ausgeführt werden.
Ergebnisse des Befehls
Da im Codebeispiel ein direkter E/A-Befehl verwendet wird, ist kein anderer Datenpuffer als das Feld ResponseData im SD-Anforderungspaket enthalten.
Das Codebeispiel weist einen Datenübertragungspuffer aus einem nicht ausgelagerten Pool zu. Ein Treiber kann PagedPool für einen Datenübertragungspuffer verwenden, sofern er die Seiten sperrt. Treiber müssen jedoch immer Datenübertragungspuffer aus nicht ausgelagerten Pools zuordnen, wenn sie SDRF_GET_PROPERTY und SDRF_SET_PROPERTY Anforderungen ausführen. Treiber müssen auch SD-Anforderungspakete aus einem nicht ausgelagerten Pool zuordnen, da die Vervollständigungsroutine des IRP, das die SD-Anforderung begleitet, möglicherweise in einem Verzögerten Prozeduraufruf (DPC) ausgeführt wird.
Für alle Arten von Anforderungen bietet die Zuweisung von Puffern aus nicht ausgelagerten Pools Leistungsvorteile, wenn die Puffer klein sind und der Treiber sie kurz hält.