Compartilhar via


Como obter as configurações de conexão de um dispositivo

Se o driver do controlador SPB registrar uma função de retorno de chamada EvtSpbTargetConnect , a extensão da estrutura SPB (SpbCx) chamará essa função quando um cliente (driver periférico) do controlador enviar uma solicitação IRP_MJ_CREATE para abrir uma conexão lógica com um dispositivo de destino no barramento. Em resposta ao retorno de chamada EvtSpbTargetConnect , o driver do controlador SPB deve chamar o método SpbTargetGetConnectionParameters para obter as configurações de conexão para o dispositivo de destino. O driver do controlador SPB armazena essas configurações e as usa posteriormente para acessar o dispositivo em resposta a solicitações de E/S do cliente.

Por exemplo, as configurações de conexão para um dispositivo de destino em um barramento I2C incluem o endereço do barramento do dispositivo, a largura do endereço (7 ou 10 bits) e a frequência do relógio do barramento a ser usada durante os acessos do dispositivo. O driver do controlador I2C usa essas configurações para configurar o controlador para acessar o dispositivo no barramento I2C.

Um driver de controlador SPB chama SpbTargetGetConnectionParameters para obter um ponteiro para um descritor de conexão de barramento serial que descreve a conexão de um dispositivo de destino com um barramento serial do tipo I2C ou SPI. Esse descritor contém informações de conexão comuns a ambos os tipos de barramento serial e é seguido por informações específicas do barramento serial ao qual o dispositivo está conectado. Para obter mais informações sobre o formato desse descritor, consulte a especificação ACPI 5.0.

No exemplo de código a seguir, um driver de controlador I2C define uma estrutura de PNP_I2C_SERIAL_BUS_DESCRIPTOR . Essa estrutura representa um descritor de conexão de barramento serial I2C, que é o termo que a especificação ACPI 5.0 usa para descrever um descritor de conexão de barramento serial seguido por configurações de conexão específicas para o barramento I2C. O primeiro membro da estrutura de PNP_I2C_SERIAL_BUS_DESCRIPTOR , SerialBusDescriptor, é uma estrutura PNP_SERIAL_BUS_DESCRIPTOR que representa o descritor de conexão do barramento serial. Os membros ConnectionSpeed e SlaveAddress contêm configurações de conexão específicas de 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>

O arquivo de cabeçalho reshub.h define a estrutura PNP_SERIAL_BUS_DESCRIPTOR . Os arquivos de cabeçalho pshpack1.h e poppack.h controlam o modo de alinhamento da estrutura usado pelo compilador.

Um descritor de conexão de barramento serial I2C é uma estrutura de dados empacotada na qual os campos adjacentes são alinhados aos limites de bytes mais próximos, sem lacunas intermediárias. Como resultado, um valor inteiro de 16 bits nesse descritor pode começar em um limite de bytes ímpar. No exemplo de código anterior, pshpack1.h é incluído para instruir o compilador a empacotar membros de estrutura adjacentes e poppack.h informa ao compilador para retomar o alinhamento da estrutura padrão.

O membro ConnectionSpeed da estrutura PNP_I2C_SERIAL_BUS_DESCRIPTOR especifica a frequência, em Hertz, na qual marcar o barramento I2C durante os acessos do dispositivo de destino. O membro SlaveAddress é o endereço do barramento do dispositivo de destino. Para alguns drivers de controlador I2C, o membro SlaveAddress pode ser seguido por dados opcionais específicos do fornecedor, mas esses dados não são usados pelo driver neste exemplo de código e, portanto, não fazem parte da definição de estrutura.

No exemplo de código a seguir, o driver do controlador I2C do exemplo anterior implementa uma GetTargetSettings rotina que chama SpbTargetGetConnectionParameters para obter as configurações de conexão de um dispositivo de destino no barramento I2C. O parâmetro de entrada de destino para essa rotina é um identificador para o dispositivo de destino. O parâmetro de saída Configurações é um ponteiro para uma estrutura de SPB_CONNECTION_PARAMETERS alocada pelo driver na qual a rotina grava um conjunto de parâmetros de conexão. Esses parâmetros incluem um ponteiro para as configurações de conexão solicitadas.

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

No exemplo de código anterior, SpbTargetGetConnectionParameters grava os parâmetros de conexão na estrutura alocada pelo Params driver. O membro ConnectionParameters de Params aponta para uma estrutura de RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER (definida em reshub.h), cujo membro ConnectionProperties é o primeiro byte do descritor de conexão de barramento serial; os bytes restantes desse descritor imediatamente seguem o membro ConnectionProperties . O buffer apontado pelo membro ConnectionParameters de Params é grande o suficiente para conter a estrutura RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER mais os bytes do descritor que seguem essa estrutura.

A rotina implementada pelo GetTargetSettings driver no exemplo de código anterior executa as seguintes verificações de parâmetro nos parâmetros de conexão recebidos de SpbTargetGetConnectionParameters:

  • Verifica se o tamanho do descritor de conexão de barramento serial contido na estrutura RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER é pelo menos sizeof(PNP_SERIAL_BUS_DESCRIPTOR).
  • Verifica se o primeiro byte do descritor de conexão de barramento serial está definido como SERIAL_BUS_DESCRIPTOR (valor constante 0x8e), conforme exigido pela especificação ACPI 5.0.
  • Verifica se o tipo de barramento serial no descritor de conexão de barramento serial está definido como I2C_SERIAL_BUS_TYPE (valor constante 0x01), que identifica o tipo de barramento serial como I2C.

No final do exemplo de código anterior, a estrutura *Settings contém as configurações de conexão (endereço do barramento, largura do endereço e frequência do relógio do barramento) para o dispositivo de destino. O driver do controlador I2C usa essas configurações de conexão para configurar o controlador para acessar o dispositivo.