Freigeben über


Behandeln von IOCTL_SPB_FULL_DUPLEX Anforderungen

Einige Busse, z. B. SPI, ermöglichen Lese- und Schreibübertragungen gleichzeitig zwischen dem Buscontroller und einem Gerät im Bus. Um diese Vollduplexübertragungen zu unterstützen, umfasst die Definition der E/A-Anforderungsschnittstelle für den einfachen Peripheriebus (SpB) optional den IOCTL_SPB_FULL_DUPLEX E/A-Steuercode (IOCTL). Nur SPB-Controllertreiber für Buscontroller, die Vollduplexübertragungen in Hardware implementieren, sollten die IOCTL_SPB_FULL_DUPLEX IOCTL unterstützen.

Wenn ein SPB-Controllertreiber E/A-Anforderungen für Vollduplexübertragungen unterstützt, sollte der Treiber für diese Anforderungen die IOCTL_SPB_FULL_DUPLEX IOCTL verwenden und die in diesem Thema vorgestellten Implementierungsrichtlinien befolgen. Der Zweck dieser Richtlinien besteht darin, ein einheitliches Verhalten auf allen Hardwareplattformen zu fördern, die IOCTL_SPB_FULL_DUPLEX Anforderungen unterstützen. Treiber für mit SPB verbundene Peripheriegeräte können sich dann auf diese Anforderungen verlassen, um ähnliche Ergebnisse zu erzielen, unabhängig davon, auf welcher Plattform sie ausgeführt werden.

Pufferanforderungen

Eine IOCTL_SPB_FULL_DUPLEX-Anforderung ist wie eine IOCTL_SPB_EXECUTE_SEQUENCE-Anforderung formatiert, jedoch mit den folgenden Einschränkungen:

  • Die SPB_TRANSFER_LIST-Struktur in der Anforderung muss genau zwei Einträge enthalten. Der erste Eintrag beschreibt einen Puffer, der Daten enthält, die auf das Gerät geschrieben werden sollen. Der zweite Eintrag beschreibt einen Puffer, der verwendet wird, um vom Gerät gelesene Daten zu halten.
  • Jede SPB_TRANSFER_LIST_ENTRY Struktur in der Übertragungsliste muss einen DelayInUs-Wert von 0 angeben.

Während einer Vollduplexübertragung beginnen die Lese- und Schreibübertragungen unisono. Das erste Byte der Schreibdaten wird gleichzeitig mit dem ersten Byte lesedaten über den Bus übertragen.

Die Schreib- und Lesepuffer in der IOCTL_SPB_FULL_DUPLEX Anforderung müssen nicht dieselbe Länge aufweisen.

Wenn der Lesepuffer kürzer als der Schreibpuffer ist, wird die vollduplexe Busübertragung fortgesetzt, bis der gesamte Inhalt des Schreibpuffers auf das Gerät geschrieben wurde. Nachdem der Lesepuffer voll ist, verwirft der Buscontroller alle zusätzlichen Daten, die vom Gerät empfangen werden, bis die vollduplexe Busübertragung abgeschlossen ist.

Wenn der Schreibpuffer kürzer als der Lesepuffer ist, wird die Vollduplex-Busübertragung fortgesetzt, bis der Lesepuffer voll ist. Nachdem der gesamte Inhalt des Schreibpuffers auf das Gerät geschrieben wurde, schreibt der Buscontroller Nullen auf das Gerät, bis die vollduplexe Busübertragung abgeschlossen ist.

Wenn die IOCTL_SPB_FULL_DUPLEX Anforderung erfolgreich abgeschlossen wird, legt der SPB-Controllertreiber das Statusmitglied des E/A-Statusblocks auf STATUS_SUCCESS fest und legt den Informationsmember auf die Gesamtanzahl der übertragenen Bytes (Bytes mit Lesezugriff plus geschriebene Bytes) während der Vollduplexübertragung fest. Der Count-Wert im Information-Member darf nie die Summe der Lesepuffergröße und der Schreibpuffergröße überschreiten.

Wenn der Lesepuffer kürzer als der Schreibpuffer ist, sollte der Count-Wert im Information-Member nicht die Datenbytes enthalten, die der Buscontroller vom Gerät liest (und verwirft), nachdem der Lesepuffer voll ist. Wenn beispielsweise eine Vollduplexübertragung mit einem 1-Byte-Schreibpuffer und einem 4-Byte-Lesepuffer erfolgreich abgeschlossen wird, sollte der Count-Wert 5 und nicht 8 sein. Wenn der Schreibpuffer kürzer als der Lesepuffer ist, sollte der Wert für die Anzahl nicht die Nullen enthalten, die nach dem Leeren des Schreibpuffers auf das Gerät geschrieben wurden.

Parameterüberprüfung

Obwohl die IOCTL_SPB_EXECUTE_SEQUENCE - und IOCTL_SPB_FULL_DUPLEX-Anforderungen ähnliche Formate aufweisen, werden sie von der SPB-Frameworkerweiterung (SpbCx) unterschiedlich behandelt. Für die IOCTL_SPB_EXECUTE_SEQUENCE Anforderung überprüft SpbCx die Parameterwerte in der Anforderung und erfasst die Puffer der Anforderung im Prozesskontext des Anforderungserstellers. SpbCx übergibt IOCTL_SPB_EXECUTE_SEQUENCE Anforderungen an den SPB-Controllertreiber über die EvtSpbControllerIoSequence-Rückruffunktion des Treibers, die für diese Anforderungen dedizierte ist.

Im Gegensatz dazu behandelt SpbCx die IOCTL_SPB_FULL_DUPLEX-Anforderung als benutzerdefinierte, vom Treiber definierte IOCTL-Anforderung. SpbCx übergibt IOCTL_SPB_FULL_DUPLEX Anforderungen an den SPB-Controllertreiber über die EvtSpbControllerIoOther-Rückruffunktion des Treibers, die auch alle vom Treiber unterstützten benutzerdefinierten IOCTL-Anforderungen verarbeitet. SpbCx führt keine Parameterüberprüfung oder Puffererfassung für diese Anforderungen durch. Der Treiber ist für alle Parameterüberprüfungen oder Puffererfassungen verantwortlich, die möglicherweise für die IOCTL-Anforderungen erforderlich sind, die der Treiber über seine EvtSpbControllerIoOther-Funktion empfängt . Um die Puffererfassung zu aktivieren, muss der Treiber eine EvtIoInCallerContext-Rückruffunktion bereitstellen, wenn der Treiber seine EvtSpbControllerIoOther-Funktion registriert. Weitere Informationen finden Sie unter Verwenden der SPB_TRANSFER_LIST-Struktur für benutzerdefinierte IOCTLs.

In der Regel überprüft der SPB-Controllertreiber die Parameterwerte in einer IOCTL_SPB_FULL_DUPLEX-Anforderung in der Funktion EvtSpbControllerIoOther und nicht in der Funktion EvtIoInCallerContext . Das folgende Codebeispiel zeigt, wie der Treiber die Parameterüberprüfung implementieren kann. In diesem Beispiel überprüft der Treiber, ob die folgenden Parameteranforderungen erfüllt sind:

  • Die Übertragungsliste in der Anforderung enthält genau zwei Einträge.
  • Der erste Eintrag in der Übertragungsliste ist für einen Schreibpuffer und der zweite für einen Lesepuffer.
  • Der DelayInUs-Wert für beide Einträge ist 0.
//
// Validate the transfer count.
//

SPB_REQUEST_PARAMETERS params;
SPB_REQUEST_PARAMETERS_INIT(&params);
SpbRequestGetParameters(SpbRequest, &params);

if (params.SequenceTransferCount != 2)
{
    //
    // The full-duplex request must have 
    // exactly two transfer descriptors.
    //
    
    status = STATUS_INVALID_PARAMETER;        
    goto exit;
}

//
// Retrieve the write and read transfer descriptors.
//

const ULONG fullDuplexWriteIndex = 0;
const ULONG fullDuplexReadIndex = 1;

SPB_TRANSFER_DESCRIPTOR writeDescriptor;
SPB_TRANSFER_DESCRIPTOR readDescriptor;
PMDL pWriteMdl;
PMDL pReadMdl;

SPB_TRANSFER_DESCRIPTOR_INIT(&writeDescriptor);
SPB_TRANSFER_DESCRIPTOR_INIT(&readDescriptor);

SpbRequestGetTransferParameters(
    SpbRequest, 
    fullDuplexWriteIndex, 
    &writeDescriptor,
    &pWriteMdl);

SpbRequestGetTransferParameters(
    SpbRequest, 
    fullDuplexReadIndex, 
    &readDescriptor,
    &pReadMdl);
    
//
// Validate the transfer direction of each descriptor.
//

if ((writeDescriptor.Direction != SpbTransferDirectionToDevice) ||
    (readDescriptor.Direction != SpbTransferDirectionFromDevice))
{
    //
    // For full-duplex I/O, the direction of the first transfer
    // must be SpbTransferDirectionToDevice, and the direction
    // of the second must be SpbTransferDirectionFromDevice.
    //
    
    status = STATUS_INVALID_PARAMETER;
    goto exit;
}

//
// Validate the delay for each transfer descriptor.
//

if ((writeDescriptor.DelayInUs != 0) || (readDescriptor.DelayInUs != 0))
{
    //
    // The write and read buffers for full-duplex I/O are transferred
    // simultaneously over the bus. The delay parameter in each transfer
    // descriptor must be set to 0.
    //
    
    status = STATUS_INVALID_PARAMETER;
    goto exit;
}

MyDriverPerformFullDuplexTransfer(
    pDevice, 
    pRequest,
    writeDescriptor,
    pWriteMdl,
    readDescriptor,
    pReadMdl);

Nach der Überprüfung der Parameterwerte ruft das vorherige Codebeispiel eine treiberinterne Routine namens MyDriverPerformFullDuplexTransferauf, um die Vollduplex-E/A-Übertragung zu initiieren.