Abrufen der Verbindungseinstellungen für ein Gerät

Wenn Ihr SPB-Controllertreiber eine EvtSpbTargetConnect-Rückruffunktion registriert, ruft die SPB-Frameworkerweiterung (SpbCx) diese Funktion auf, wenn ein Client (Peripherietreiber) des Controllers eine IRP_MJ_CREATE Anforderung zum Öffnen einer logischen Verbindung mit einem Zielgerät im Bus sendet. Als Reaktion auf den EvtSpbTargetConnect-Rückruf sollte der SPB-Controllertreiber die SpbTargetGetConnectionParameters-Methode aufrufen, um die Verbindungseinstellungen für das Zielgerät abzurufen. Der SPB-Controllertreiber speichert diese Einstellungen und verwendet sie später für den Zugriff auf das Gerät als Reaktion auf E/A-Anforderungen vom Client.

Die Verbindungseinstellungen für ein Zielgerät auf einem I2C-Bus umfassen beispielsweise die Busadresse des Geräts, die Adressbreite (7 oder 10 Bit) und die Während des Zugriffs auf das Gerät zu verwendende Bustaktfrequenz. Der I2C-Controllertreiber verwendet diese Einstellungen, um den Controller für den Zugriff auf das Gerät über den I2C-Bus zu konfigurieren.

Ein SPB-Controllertreiber ruft SpbTargetGetConnectionParameters auf, um einen Zeiger auf einen seriellen Busverbindungsdeskriptor abzurufen, der die Verbindung eines Zielgeräts mit einem seriellen Bus vom Typ I2C oder SPI beschreibt. Dieser Deskriptor enthält Verbindungsinformationen, die für beide serielle Bustypen gemeinsam sind, und gefolgt von Informationen, die für den seriellen Bus spezifisch sind, mit dem das Gerät verbunden ist. Weitere Informationen zum Format für diesen Deskriptor finden Sie in der ACPI 5.0-Spezifikation.

Im folgenden Codebeispiel definiert ein I2C-Controllertreiber eine PNP_I2C_SERIAL_BUS_DESCRIPTOR-Struktur . Diese Struktur stellt einen I2C-Verbindungsdeskriptor für seriellen Bus dar. Dies ist der Begriff, den die ACPI 5.0-Spezifikation verwendet, um einen seriellen Busverbindungsdeskriptor zu beschreiben, auf den Verbindungseinstellungen folgen, die für den I2C-Bus spezifisch sind. Der erste Member der PNP_I2C_SERIAL_BUS_DESCRIPTOR-Struktur , SerialBusDescriptor, ist eine PNP_SERIAL_BUS_DESCRIPTOR-Struktur , die den seriellen Busverbindungsdeskriptor darstellt. Die Member ConnectionSpeed und SlaveAddress enthalten I2C-spezifische Verbindungseinstellungen.

#include <reshub.h>
#include <pshpack1.h>  

//
// See the ACPI 5.0 spec, section 6.4.3.8.2.1 (I2C Serial Bus Connection Descriptor).  
//
typedef struct _PNP_I2C_SERIAL_BUS_DESCRIPTOR {  
    PNP_SERIAL_BUS_DESCRIPTOR SerialBusDescriptor;  
    ULONG ConnectionSpeed;  
    USHORT SlaveAddress;  
    // Followed by optional vendor-specific data.
    // Followed by name of serial bus controller.
} PNP_I2C_SERIAL_BUS_DESCRIPTOR, *PPNP_I2C_SERIAL_BUS_DESCRIPTOR;  
  
#include <poppack.h>

Die Reshub.h-Headerdatei definiert die PNP_SERIAL_BUS_DESCRIPTOR-Struktur . Die Headerdateien pshpack1.h und poppack.h steuern den vom Compiler verwendeten Strukturausrichtungsmodus.

Ein I2C-Verbindungsdeskriptor für seriellen Bus ist eine gepackte Datenstruktur, in der benachbarte Felder an den nächsten Bytegrenzen ausgerichtet werden, ohne dass lückenlos dazwischen liegen. Daher kann ein ganzzahliger 16-Bit-Wert in diesem Deskriptor an einer ungeraden Bytegrenze beginnen. Im vorherigen Codebeispiel ist pshpack1.h enthalten, um den Compiler anweisen zu können, benachbarte Strukturelemente zu packen, und poppack.h weist den Compiler an, die Standardstrukturausrichtung fortzusetzen.

Der ConnectionSpeed-Member der PNP_I2C_SERIAL_BUS_DESCRIPTOR-Struktur gibt die Frequenz in Hertz an, mit der der I2C-Bus während des Zugriffs auf das Zielgerät takten soll. Das SlaveAddress-Element ist die Busadresse des Zielgeräts. Bei einigen I2C-Controllertreibern können dem SlaveAddress-Member optionale herstellerspezifische Daten folgen, aber diese Daten werden in diesem Codebeispiel nicht vom Treiber verwendet und sind daher nicht Teil der Strukturdefinition.

Im folgenden Codebeispiel implementiert der I2C-Controllertreiber aus dem vorherigen Beispiel eine GetTargetSettings Routine, die SpbTargetGetConnectionParameters aufruft , um die Verbindungseinstellungen für ein Zielgerät im I2C-Bus abzurufen. Der Target-Eingabeparameter für diese Routine ist ein Handle für das Zielgerät. Der Einstellungsausgabeparameter ist ein Zeiger auf eine vom Treiber zugewiesene SPB_CONNECTION_PARAMETERS Struktur, in die die Routine einen Satz von Verbindungsparametern schreibt. Diese Parameter enthalten einen Zeiger auf die angeforderten Verbindungseinstellungen.

#define I2C_SERIAL_BUS_TYPE 0x01
#define I2C_SERIAL_BUS_SPECIFIC_FLAG_10BIT_ADDRESS 0x0001

typedef enum _I2C_ADDRESS_MODE
{
    AddressMode7Bit,
    AddressMode10Bit
} I2C_ADDRESS_MODE, *PI2C_ADDRESS_MODE;
  
typedef struct _I2C_TARGET_SETTINGS
{
    ULONG  ClockFrequency;
    ULONG  Address;
    I2C_ADDRESS_MODE  AddressMode;
} I2C_TARGET_SETTINGS, *PI2C_TARGET_SETTINGS;

NTSTATUS
GetTargetSettings(_In_ SPBTARGET Target, _Out_ PI2C_TARGET_SETTINGS Settings)
{
    PRH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER Connection = NULL;
    SPB_CONNECTION_PARAMETERS Params;

    SPB_CONNECTION_PARAMETERS_INIT(&Params);
    SpbTargetGetConnectionParameters(Target, &Params);
    Connection = (PRH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER)Params.ConnectionParameters;
    if (Connection->PropertiesLength < sizeof(PNP_SERIAL_BUS_DESCRIPTOR))
    {
        return STATUS_INVALID_PARAMETER;
    }

    PPNP_SERIAL_BUS_DESCRIPTOR Descriptor;

    Descriptor = (PPNP_SERIAL_BUS_DESCRIPTOR)Connection->ConnectionProperties;
    if (Descriptor->Tag != SERIAL_BUS_DESCRIPTOR ||
        Descriptor->SerialBusType != I2C_SERIAL_BUS_TYPE)
    {
        return STATUS_INVALID_PARAMETER;
    }

    PPNP_I2C_SERIAL_BUS_DESCRIPTOR I2CDescriptor;
    USHORT I2CFlags;

    I2CDescriptor = (PPNP_I2C_SERIAL_BUS_DESCRIPTOR)Connection->ConnectionProperties;
    Settings->Address = (ULONG)I2CDescriptor->SlaveAddress;
    I2CFlags = I2CDescriptor->SerialBusDescriptor.TypeSpecificFlags;
    Settings->AddressMode = 
                ((I2CFlags & I2C_SERIAL_BUS_SPECIFIC_FLAG_10BIT_ADDRESS) == 0) ? AddressMode7Bit : AddressMode10Bit;

    Settings->ClockFrequency = I2CDescriptor->ConnectionSpeed;

    return STATUS_SUCCESS;
}

Im vorherigen Codebeispiel schreibt SpbTargetGetConnectionParameters die Verbindungsparameter in die vom Treiber zugewiesene Params Struktur. Das ConnectionParameters-Element von Params verweist auf eine RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER-Struktur (definiert in reshub.h), deren ConnectionProperties-Member das erste Byte des seriellen Bus-Verbindungsdeskriptors ist. Die verbleibenden Bytes dieses Deskriptors folgen unmittelbar dem ConnectionProperties-Element . Der Puffer, auf den der ConnectionParameters-Member von Params verweist, ist groß genug, um die RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER-Struktur plus die Deskriptorbytes zu enthalten, die dieser Struktur folgen.

Die vom Treiber implementierte GetTargetSettings Routine im vorherigen Codebeispiel führt die folgenden Parameterüberprüfungen für die verbindungsparameter aus, die von SpbTargetGetConnectionParameters empfangen werden:

  • Überprüft, ob die Größe des seriellen Busverbindungsdeskriptors in der RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER-Struktur mindestens sizeof(PNP_SERIAL_BUS_DESCRIPTOR) ist.
  • Überprüft, ob das erste Byte des Seriellen Busverbindungsdeskriptors auf SERIAL_BUS_DESCRIPTOR (konstanter Wert 0x8e) festgelegt ist, wie in der ACPI 5.0-Spezifikation erforderlich.
  • Überprüft, ob der serielle Bustyp im Seriellen Busverbindungsdeskriptor auf I2C_SERIAL_BUS_TYPE (konstanter Wert 0x01) festgelegt ist, der den seriellen Bustyp als I2C identifiziert.

Am Ende des vorherigen Codebeispiels enthält die *Settings -Struktur die Verbindungseinstellungen (Busadresse, Adressbreite und Bustaktfrequenz) für das Zielgerät. Der I2C-Controllertreiber verwendet diese Verbindungseinstellungen, um den Controller für den Zugriff auf das Gerät zu konfigurieren.