如何获取设备的连接设置

如果 SPB 控制器驱动程序注册了 EvtSpbTargetConnect 回调函数,则当客户端 (外围驱动程序) 控制器发送IRP_MJ_CREATE请求以打开与总线上目标设备的逻辑连接时,SPB 框架扩展 (SpbCx) 调用此函数。 为了响应 EvtSpbTargetConnect 回调,SPB 控制器驱动程序应调用 SpbTargetGetConnectionParameters 方法来获取目标设备的连接设置。 SPB 控制器驱动程序存储这些设置,并在以后使用它们来访问设备,以响应来自客户端的 I/O 请求。

例如,I2C 总线上目标设备的连接设置包括设备的总线地址、 (7 位或 10 位) 的地址宽度,以及访问设备期间要使用的总线时钟频率。 I2C 控制器驱动程序使用这些设置将控制器配置为通过 I2C 总线访问设备。

SPB 控制器驱动程序调用 SpbTargetGetConnectionParameters 以获取指向 串行总线连接描述符 的指针,描述目标设备与 I2C 或 SPI 类型的串行总线的连接。 此描述符包含两种串行总线类型通用的连接信息,后跟特定于设备所连接到的串行总线的信息。 有关此描述符的格式的详细信息,请参阅 ACPI 5.0 规范

在以下代码示例中,I2C 控制器驱动程序定义 PNP_I2C_SERIAL_BUS_DESCRIPTOR 结构。 此结构表示 I2C 串行总线连接描述符,ACPI 5.0 规范用来描述串行总线连接描述符的术语,后跟特定于 I2C 总线的连接设置。 PNP_I2C_SERIAL_BUS_DESCRIPTOR 结构的第一个成员 SerialBusDescriptor 是表示串行总线连接描述符的PNP_SERIAL_BUS_DESCRIPTOR结构。 ConnectionSpeedSlaveAddress 成员包含特定于 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>

reshub.h 头文件定义 PNP_SERIAL_BUS_DESCRIPTOR 结构。 pshpack1.h 和 poppack.h 头文件控制编译器使用的结构对齐模式。

I2C 串行总线连接描述符是一种打包的数据结构,其中相邻字段与最近的字节边界对齐,而不会干预间隙。 因此,此描述符中的 16 位整数值可能从奇数字节边界开始。 在前面的代码示例中,包含 pshpack1.h 以告知编译器打包相邻结构成员,poppack.h 指示编译器恢复默认结构对齐。

PNP_I2C_SERIAL_BUS_DESCRIPTOR 结构的 ConnectionSpeed 成员指定频率(以 Hertz 为单位),在访问目标设备期间为 I2C 总线时钟。 SlaveAddress 成员是目标设备的总线地址。 对于某些 I2C 控制器驱动程序, SlaveAddress 成员可能后跟特定于供应商的可选数据,但此代码示例中驱动程序未使用此数据,因此不是结构定义的一部分。

在下面的代码示例中,上一示例中的 I2C 控制器驱动程序实现一个 GetTargetSettings 例程,该例程调用 SpbTargetGetConnectionParameters 以获取 I2C 总线上目标设备的连接设置。 此例程 的目标 输入参数是目标设备的句柄。 Settings 输出参数是指向驱动程序分配的SPB_CONNECTION_PARAMETERS结构的指针,例程将一组连接参数写入其中。 这些参数包括指向请求的连接设置的指针。

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

在前面的代码示例中, SpbTargetGetConnectionParameters 将连接参数写入驱动程序分配 Params 的结构。 的 ConnectionParameters 成员Params指向 reshub.h () 中定义的RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER结构,其 ConnectionProperties 成员是串行总线连接描述符的第一个字节;此描述符的剩余字节紧跟 ConnectionProperties 成员。 ConnectionParameters 成员指向的Params缓冲区足够大,足以包含RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER结构以及此结构后面的描述符字节。

上述代码示例中驱动程序实现 GetTargetSettings 的例程对从 SpbTargetGetConnectionParameters 接收的连接参数执行以下参数检查:

  • 验证 包含在 RH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER 结构中的串行总线连接描述符 的大小是否至少 为 (PNP_SERIAL_BUS_DESCRIPTOR) 。
  • 根据 ACPI 5.0 规范的要求,验证串行总线连接描述符的第一个字节是否设置为SERIAL_BUS_DESCRIPTOR (常量值0x8e) 。
  • 验证串行总线连接描述符中的串行总线类型是否设置为I2C_SERIAL_BUS_TYPE (常量值0x01) ,这将串行总线类型标识为 I2C。

在前面的代码示例末尾,*Settings 结构包含目标设备的连接设置 (总线地址、地址宽度和总线时钟频率) 。 I2C 控制器驱动程序使用这些连接设置来配置控制器以访问设备。