如何获取设备的连接设置
如果 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结构。 ConnectionSpeed 和 SlaveAddress 成员包含特定于 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 控制器驱动程序使用这些连接设置来配置控制器以访问设备。