Condividi tramite


Come ottenere le impostazioni di connessione per un dispositivo

Se il driver del controller SPB registra una funzione di callback EvtSpbTargetConnect , l'estensione del framework SPB (SpbCx) chiama questa funzione quando un client (driver periferico) del controller invia una richiesta di IRP_MJ_CREATE per aprire una connessione logica a un dispositivo di destinazione nel bus. In risposta al callback EvtSpbTargetConnect , il driver del controller SPB deve chiamare il metodo SpbTargetGetConnectionParameters per ottenere le impostazioni di connessione per il dispositivo di destinazione. Il driver del controller SPB archivia queste impostazioni e li usa in un secondo momento per accedere al dispositivo in risposta alle richieste di I/O dal client.

Ad esempio, le impostazioni di connessione per un dispositivo di destinazione in un bus I2C includono l'indirizzo del bus del dispositivo, la larghezza dell'indirizzo (7 o 10 bit) e la frequenza dell'orologio del bus da usare durante gli accessi del dispositivo. Il driver del controller I2C usa queste impostazioni per configurare il controller per accedere al dispositivo sul bus I2C.

Un driver del controller SPB chiama SpbTargetGetConnectionParameters per ottenere un puntatore a un descrittore di connessione del bus seriale che descrive la connessione di un dispositivo di destinazione a un bus seriale di tipo I2C o SPI. Questo descrittore contiene informazioni di connessione comuni a entrambi i tipi di bus di serie ed è seguito da informazioni specifiche del bus seriale a cui è connesso il dispositivo. Per altre informazioni sul formato per questo descrittore, vedere la specifica ACPI 5.0.

Nell'esempio di codice seguente un driver controller I2C definisce una struttura PNP_I2C_SERIAL_BUS_DESCRIPTOR . Questa struttura rappresenta un descrittore di connessione del bus seriale I2C, ovvero il termine la specifica ACPI 5.0 usa per descrivere un descrittore di connessione del bus seriale seguito da impostazioni di connessione specifiche del bus I2C. Il primo membro della struttura PNP_I2C_SERIAL_BUS_DESCRIPTOR , SerialBusDescriptor, è una struttura PNP_SERIAL_BUS_DESCRIPTOR che rappresenta il descrittore di connessione del bus seriale. I membri ConnectionSpeed e SlaveAddress contengono impostazioni di connessione specifiche di I2C.

#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>

Il file di intestazione reshub.h definisce la struttura PNP_SERIAL_BUS_DESCRIPTOR . I file di intestazione pshpack1.h e poppack.h controllano la modalità di allineamento della struttura usata dal compilatore.

Un descrittore di connessione del bus seriale I2C è una struttura di dati confezionata in cui i campi adiacenti sono allineati ai limiti di byte più vicini, senza intervenire sulle lacune. Di conseguenza, un valore intero a 16 bit in questo descrittore potrebbe iniziare su un limite di byte dispari. Nell'esempio di codice precedente, pshpack1.h è incluso per indicare al compilatore di inserire membri della struttura adiacenti e poppack.h indica al compilatore di riprendere l'allineamento predefinito della struttura.

Il membro ConnectionSpeed della struttura PNP_I2C_SERIAL_BUS_DESCRIPTOR specifica la frequenza, in Hertz, in cui orologio il bus I2C durante gli accessi del dispositivo di destinazione. Il membro SlaveAddress è l'indirizzo del bus del dispositivo di destinazione. Per alcuni driver del controller I2C, il membro SlaveAddress potrebbe essere seguito da dati specifici del fornitore facoltativi, ma questi dati non vengono usati dal driver in questo esempio di codice ed è pertanto non parte della definizione della struttura.

Nell'esempio di codice seguente il driver controller I2C dell'esempio precedente implementa una GetTargetSettings routine che chiama SpbTargetGetConnectionParameters per ottenere le impostazioni di connessione per un dispositivo di destinazione nel bus I2C. Il parametro di input di destinazione per questa routine è un handle per il dispositivo di destinazione. Il parametro di output Settings è un puntatore a una struttura SPB_CONNECTION_PARAMETERS allocata dal driver a cui la routine scrive un set di parametri di connessione. Questi parametri includono un puntatore alle impostazioni di connessione richieste.

#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;
}

Nell'esempio di codice precedente SpbTargetGetConnectionParameters scrive i parametri di connessione nella struttura allocata dal Params driver. Il membro ConnectionParameters di Params punti a una struttura RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER (definita in reshub.h), il cui membro ConnectionProperties è il primo byte del descrittore di connessione del bus seriale. I byte rimanenti di questo descrittore seguono immediatamente il membro ConnectionProperties . Il buffer a cui fa riferimento il membro ConnectionParameters di Params è sufficiente per contenere la struttura RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER più i byte descrittori che seguono questa struttura.

La routine implementata dal GetTargetSettings driver nell'esempio di codice precedente esegue i controlli dei parametri seguenti sui parametri di connessione ricevuti da SpbTargetGetConnectionParameters:

  • Verifica che le dimensioni del descrittore di connessione del bus seriale contenute nella struttura RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER siano almeno sizeof(PNP_SERIAL_BUS_DESCRIPTOR).
  • Verifica che il primo byte del descrittore di connessione del bus seriale sia impostato su SERIAL_BUS_DESCRIPTOR (valore costante 0x8e), come richiesto dalla specifica ACPI 5.0.
  • Verifica che il tipo di bus seriale nel descrittore di connessione del bus seriale sia impostato su I2C_SERIAL_BUS_TYPE (valore costante 0x01), che identifica il tipo di bus seriale come I2C.

Alla fine dell'esempio di codice precedente, la struttura *Settings contiene le impostazioni di connessione (indirizzo del bus, larghezza dell'indirizzo e frequenza dell'orologio del bus) per il dispositivo di destinazione. Il driver del controller I2C usa queste impostazioni di connessione per configurare il controller per accedere al dispositivo.