反馈
显示另外 3 个
在 Windows 10 及更高版本中,API 提供从用户模式直接访问通用输入/输出 (GPIO) 、Inter-Integrated Circuit (I2C) 、串行外设接口 (SPI) 以及通用异步接收器-发送器 (UART) 。 开发板(如 Raspberry Pi 2)将公开这些连接的子集,这些连接支持使用自定义电路扩展基本计算模块来处理特定应用程序。 通常,只需使用 GPIO 引脚的一个子集和标头上公开的总线,即可与其他关键板载功能共享这些低级别总线。 若要保持系统稳定性,必须通过用户模式应用程序指定可供安全修改的引脚和总线。
本文档介绍如何在高级配置和电源接口 (ACPI) 中指定此配置,并提供工具来验证是否正确指定了配置。
重要
本文档的受众是统一可扩展固件接口 (UEFI) 和 ACPI 开发人员。 本文档假定其对 ACPI、ACPI 源语言 (ASL) 创作和 SpbCx/GpioClx 有一定的了解。
对 Windows 上低级别总线的用户模式访问通过现有 GpioClx
和 SpbCx
框架实现。 在 Windows IoT 核心版和 Windows 企业版上可用的新驱动程序(称为 RhProxy)会向用户模式公开 GpioClx
和 SpbCx
资源。 若要启用这些 API,必须在 ACPI 表(内含应向用户模式公开的每个 GPIO 和 SPB 资源)中声明用于 rhproxy 的设备节点。 本文档演示了编写和验证 ASL。
[](#asl-by-example)
演示 Raspberry Pi 2 上的 RhProxy 设备节点声明。 首先,在 \_SB 作用域中创建 ACPI 设备声明。
C++ 复制
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
}
接下来,声明应向用户模式公开的每个 GPIO 和 SPB 资源。 资源声明的顺序非常重要,因为使用资源索引将属性与资源关联起来。 如果公开了多个 I2C 或 SPI 总线,则第一个声明的总线被视为该类型的“默认”总线,并且将是 Windows.Devices.I2c.I2cController 和 Windows.Devices.Spi.SpiController 方法返回GetDefaultAsync()
的实例。
[](#spi)
Raspberry Pi 具有两条公开的 SPI 总线。 SPI0 有两条硬件芯片选择线,SPI1 有一条硬件芯片选择线。 每条总线的每条芯片选择线需要一个 SPISerialBus\(\) 资源声明。 以下两个 SPISerialBus 资源声明适用于 SPI0 上的两条芯片选择线。 DeviceSelection 字段包含驱动程序将其解释为硬件芯片选择线标识符的唯一值。 放入 DeviceSelection 字段中的确切值取决于驱动程序解释 ACPI 连接描述符的这一字段的方式。
备注
本文包含对术语“从属”的引用,这是 Microsoft 不再使用的术语。 在从软件中删除该术语后,我们会将其从本文中删除。
C++ 复制
// Index 0
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE0 - GPIO 8 - Pin 24
0, // Device selection (CE0)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 1
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE1 - GPIO 7 - Pin 26
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
软件如何知道这两个资源应该与同一总线关联? 总线友好名称和资源索引之间的映射在 DSD 中指定:
C++ 复制
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},
这将创建名为“SPI0”、具有两条芯片选择线的总线 – 资源索引 0 和 1。 若要声明 SPI 总线的功能,还需要更多属性。
C++ 复制
Package(2) { "SPI0-MinClockInHz", 7629 },
Package(2) { "SPI0-MaxClockInHz", 125000000 },
MinClockInHz 和 MaxClockInHz 属性指定控制器所支持的最小和最大时钟速度。 API 会阻止用户指定超出此范围的值。 会将时钟速度传递给连接描述符(ACPI 章节 6.4.3.8.2.2)的 _SPE 字段中的 SPB 驱动程序。
C++ 复制
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},
SupportedDataBitLengths 属性列出控制器所支持的数据位长度。 可以在用逗号分隔的列表中指定多个值。 API 会阻止用户指定不在此列表范围内的值。 会将数据位长度传递给连接描述符(ACPI 章节 6.4.3.8.2.2)的 _LEN 字段中的 SPB 驱动程序。
你可以将这些资源声明视为“模板”。 某些字段在系统启动时是固定的,而其他字段在运行时是动态指定的。 SPISerialBus 描述符的以下字段是固定的:
以下字段是由用户在运行时指定的值的占位符:
由于 SPI1 仅包含一条芯片选择线,因此单个 SPISerialBus()
资源如下声明:
C++ 复制
// Index 2
SPISerialBus( // SCKL - GPIO 21 - Pin 40
// MOSI - GPIO 20 - Pin 38
// MISO - GPIO 19 - Pin 35
// CE1 - GPIO 17 - Pin 11
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI1", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
随附友好名称声明(这是必需的)在 DSD 中指定,并引用此资源声明的索引。
C++ 复制
Package(2) { "bus-SPI-SPI1", Package() { 2 }},
这会创建名为“SPI1”的总线,并将其与资源索引 2 关联。
[](#spi-driver-requirements)
SpbCx
或与 SpbCx 兼容[](#i2c)
接下来,声明 I2C 资源。 Raspberry Pi 公开了引脚 3 和 5 上的一条 I2C 总线。
C++ 复制
// Index 3
I2CSerialBus( // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
0xFFFF, // SlaveAddress: placeholder
, // SlaveMode: default to ControllerInitiated
0, // ConnectionSpeed: placeholder
, // Addressing Mode: placeholder
"\\_SB.I2C1", // ResourceSource: I2C bus controller name
,
,
) // VendorData
随附友好名称声明(这是必需的)在 DSD 中指定:
C++ 复制
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
这将声明友好名称为“I2C1”、引用资源索引 3(它是以上声明的 I2CSerialBus() 资源的索引)的 I2C 总线。
I2CSerialBus\(\) 描述符的以下字段是固定的:
以下字段是由用户在运行时指定的值的占位符。
[](#i2c-driver-requirements)
[](#gpio)
接下来,声明向用户模式公开的所有 GPIO 引脚。 提供以下用于确定要公开的引脚的指南:
以下 ASL 块声明两个引脚 – GPIO4 和 GPIO5。 为了简明起见,此处未显示其他引脚。 附录 C 包含可以用于生成 GPIO 资源的 PowerShell 脚本示例。
C++ 复制
// Index 4 – GPIO 4
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 4 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 4 }
// Index 6 – GPIO 5
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 5 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 5 }
声明 GPIO 引脚时,必须遵守以下要求:
PinConfig 字段
启动期间,固件、UEFI 和驱动程序初始化代码不应改变处于通电状态的引脚的状态。 只有用户清楚附加到引脚的内容,从而知道哪些状态转换是安全的。 必须记录每个引脚的通电状态,以便用户可以设计与引脚正确交互的硬件。 启动期间,引脚不得意外改变状态。
[](#supported-drive-modes)
如果你的 GPIO 控制器除了支持内置的上拉和下拉电阻器之外,还支持高阻抗输入和 CMOS 输出,则必须使用可选 SupportedDriveModes 属性进行指定。
C++ 复制
Package (2) { “GPIO-SupportedDriveModes”, 0xf },
SupportedDriveModes 属性指示哪些驱动器模式受 GPIO 控制器支持。 在上述示例中,以下所有驱动器模式都受支持。 属性是以下值的位掩码:
标志值
驱动器模式
说明
0x1
InputHighImpedance
引脚支持高阻抗输入,对应于 ACPI 中的“PullNone”值。
0x2
InputPullUp
引脚支持内置的上拉电阻器,对应于 ACPI 中的“PullUp”值。
0x4
InputPullDown
引脚支持内置的下拉电阻器,对应于 ACPI 中的“PullDown”值。
0x8
OutputCmos
引脚支持生成很强的高电平和很强的低电平(相对于开漏)。
几乎所有 GPIO 控制器都支持 InputHighImpedance 和 OutputCmos。 如果未指定 SupportedDriveModes 属性,则这是默认设置。
如果 GPIO 信号在到达公开的标头之前经过电平位移器,请声明受 SOC 支持的驱动器模式,即使在外部标头上观察不到驱动器模式也是如此。 例如,如果引脚经过使引脚表现为具有电阻式上拉的开漏的双向电平位移器,你将永远不会在公开的标头上观察到高阻抗状态,即使该引脚配置为高阻抗输入也是如此。 你仍应声明引脚支持高阻抗输入。
[](#pin-numbering)
Windows 支持两种引脚编号方案:
C++ 复制
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },
UseDescriptorPinNumbers 属性会告诉 Windows 使用本机引脚编号而不是顺序引脚编号。 如果未指定 UseDescriptorPinNumbers 属性或其值为零,Windows 将默认使用顺序引脚编号。
如果使用本机引脚编号,还必须指定 PinCount 属性。
C++ 复制
Package (2) { “GPIO-PinCount”, 54 },
PinCount 属性应与通过 GpioClx
驱动程序的 CLIENT_QueryControllerBasicInformation 回调中的 TotalPins 属性返回的值相匹配。
选择与你的开发板的现有发布文档最兼容的编号方案。 例如,Raspberry Pi 使用本机引脚编号,因为许多现有的引出线图使用 BCM2835 引脚编号。 MinnowBoardMax 使用顺序引脚编号(因为有几个现有的引出线图),并且顺序引脚编号简化了开发人员体验(因为超过 200 个引脚中只公开了 10 个引脚)。 决定使用顺序引脚编号还是使用本机引脚编号应以减少开发人员混淆为目标。
[](#gpio-driver-requirements)
GpioClx
[](#uart)
如果 UART 驱动程序使用 SerCx
或 SerCx2
,则可以使用 rhproxy 向用户模式公开该驱动程序。 创建类型为 GUID_DEVINTERFACE_COMPORT
的设备接口的 UART 驱动程序无需使用 rhproxy。 收件箱 Serial.sys
驱动程序是这些情况之一。
若要向用户模式公开 SerCx
样式的 UART,请按照如下方法声明 UARTSerialBus
资源。
C++ 复制
// Index 2
UARTSerialBus( // Pin 17, 19 of JP1, for SIO_UART2
115200, // InitialBaudRate: in bits ber second
, // BitsPerByte: default to 8 bits
, // StopBits: Defaults to one bit
0xfc, // LinesInUse: 8 1-bit flags to declare line enabled
, // IsBigEndian: default to LittleEndian
, // Parity: Defaults to no parity
, // FlowControl: Defaults to no flow control
32, // ReceiveBufferSize
32, // TransmitBufferSize
"\\_SB.URT2", // ResourceSource: UART bus controller name
,
,
,
)
仅 ResourceSource 字段是固定的,而所有其他字段是由用户在运行时指定的值的占位符。
随附友好名称声明如下所示:
C++ 复制
Package(2) { "bus-UART-UART2", Package() { 2 }},
这会将友好名称“UART2”分配给控制器,该名称是用户用于从用户模式访问总线的标识符。
[](#runtime-pin-muxing)
引脚复用可以将同一物理引脚用于不同功能。 多个不同的芯片上外设(例如 I2C 控制器、SPI 控制器和 GPIO 控制器)可以路由到 SOC 上的同一物理引脚。 复用块控制哪项功能在任何给定时间在引脚上处于活动状态。 通常,固件负责在启动时建立功能分配,此分配通过启动会话保持静态。 运行时引脚复用允许在运行时重新配置引脚功能分配。 支持用户在运行时选择引脚的功能可加速开发(方法是支持用户快速重新配置开发板的引脚),同时使硬件可以支持范围更广的应用程序(相较于静态配置而言)。
无需编写任何其他代码,用户就可以使用对 GPIO、I2C、SPI 和 UART 的复用支持。 当用户使用 OpenPin\(\) 或 FromIdAsync\(\) 打开 GPIO 或总线时,基础物理引脚会自动复用为请求的功能。 如果其他功能已在使用该引脚,OpenPin\(\) 或 FromIdAsync\(\) 调用将失败。 当用户通过释放 GpioPin、I2cDevice、SpiDevice 或 SerialDevice 对象关闭设备时,会释放引脚,从而允许它们稍后供其他功能打开。
Windows 在 GpioClx、SpbCx 和 SerCx 框架中包含对引脚复用的内置支持。 当访问 GPIO 引脚或总线时,这些框架协同工作,以自动将引脚切换到正确的功能。 仲裁对引脚的访问,以防止在多个客户端之间发生冲突。 除了此内置支持,适用于引脚复用的接口和协议是通用的,可以进行扩展以支持其他设备和方案。
本文档首先介绍引脚复用所涉及的基础接口和协议,然后介绍如何将对引脚复用的支持添加到 GpioClx、SpbCx 和 SerCx 控制器驱动程序。
[](#pin-muxing-architecture)
本部分介绍引脚复用所涉及的基础接口和协议。 支持 GpioClx/SpbCx/SerCx 驱动程序的引脚复用不一定非要了解基础协议的知识。 有关如何支持 GpioCls/SpbCx/SerCx 驱动程序的引脚复用的详细信息,请参阅在 GpioClx 客户端驱动程序中实现引脚复用支持和在 SpbCx 和 SerCx 控制器驱动程序中使用复用支持。
通过多个组件的协作实现引脚复用。
MsftFunctionConfig()
资源的复用配置。 MsftFunctionConfig 资源表示的管脚中具有客户端所需的复用配置。 MsftFunctionConfig 资源包含功能编号、拉配置和管脚编号列表。 MsftFunctionConfig 资源提供给管脚复用客户端作为硬件资源,驱动程序在其 PrepareHardware 回调中接收这些资源(类似于 GPIO 和 SPB 连接资源)。 客户端接收可用于打开资源句柄的资源中心 ID。必须将/MsftInternal
命令行开关传递到asl.exe
,才能编译包含MsftFunctionConfig()
描述符的 ASL 文件,因为 ACPI 工作委员会当前正在审查这些描述符。 例如:asl.exe /MsftInternal dsdt.asl
引脚复用中涉及的操作顺序如下所示。
RESOURCE_HUB_CREATE_PATH_FROM_ID()
从资源 ID 创建路径,然后使用 ZwCreateFile () 、 IoGetDeviceObjectPointer () 或 WdfIoTargetOpen () ) 打开路径 (的句柄。RESOURCE_HUB_ID_FROM_FILE_NAME()
从文件路径提取资源中心 ID,然后查询资源中心以获取资源描述符。[](#protocol-description-for-pin-muxing-clients)
本部分介绍了客户端如何使用引脚复用功能。 这不适用于 SerCx
和 SpbCx
控制器驱动程序,因为框架会代表控制器驱动程序实现此协议。
[](#parsing-resources)
WDF 驱动程序在其 EvtDevicePrepareHardware () 例程中接收MsftFunctionConfig()
资源。 MsftFunctionConfig 资源可以由以下字段来标识:
C++ 复制
CM_PARTIAL_RESOURCE_DESCRIPTOR::Type = CmResourceTypeConnection
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Class = CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Type = CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG
EvtDevicePrepareHardware()
例程可能会提取 MsftFunctionConfig 资源,如下所示:
C++ 复制
EVT_WDF_DEVICE_PREPARE_HARDWARE evtDevicePrepareHardware;
_Use_decl_annotations_
NTSTATUS
evtDevicePrepareHardware (
WDFDEVICE WdfDevice,
WDFCMRESLIST ResourcesTranslated
)
{
PAGED_CODE();
LARGE_INTEGER connectionId;
ULONG functionConfigCount = 0;
const ULONG resourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
for (ULONG index = 0; index < resourceCount; ++index) {
const CM_PARTIAL_RESOURCE_DESCRIPTOR* resDescPtr =
WdfCmResourceListGetDescriptor(ResourcesTranslated, index);
switch (resDescPtr->Type) {
case CmResourceTypeConnection:
switch (resDescPtr->u.Connection.Class) {
case CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG:
switch (resDescPtr->u.Connection.Type) {
case CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG:
switch (functionConfigCount) {
case 0:
// save the connection ID
connectionId.LowPart = resDescPtr->u.Connection.IdLowPart;
connectionId.HighPart = resDescPtr->u.Connection.IdHighPart;
break;
} // switch (functionConfigCount)
++functionConfigCount;
break; // CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG
} // switch (resDescPtr->u.Connection.Type)
break; // CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
} // switch (resDescPtr->u.Connection.Class)
break;
} // switch
} // for (resource list)
if (functionConfigCount < 1) {
return STATUS_INVALID_DEVICE_CONFIGURATION;
}
// TODO: save connectionId in the device context for later use
return STATUS_SUCCESS;
}
[](#reserving-and-committing-resources)
当客户端想要复用管脚时,它会保留并提交 MsftFunctionConfig 资源。 以下示例演示客户端会如何保留并提交 MsftFunctionConfig 资源。
C++ 复制
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS AcquireFunctionConfigResource (
WDFDEVICE WdfDevice,
LARGE_INTEGER ConnectionId,
_Out_ WDFIOTARGET* ResourceHandlePtr
)
{
PAGED_CODE();
//
// Form the resource path from the connection ID
//
DECLARE_UNICODE_STRING_SIZE(resourcePath, RESOURCE_HUB_PATH_CHARS);
NTSTATUS status = RESOURCE_HUB_CREATE_PATH_FROM_ID(
&resourcePath,
ConnectionId.LowPart,
ConnectionId.HighPart);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Create a WDFIOTARGET
//
WDFIOTARGET resourceHandle;
status = WdfIoTargetCreate(WdfDevice, WDF_NO_ATTRIBUTES, &resourceHandle);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Reserve the resource by opening a WDFIOTARGET to the resource
//
WDF_IO_TARGET_OPEN_PARAMS openParams;
WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(
&openParams,
&resourcePath,
FILE_GENERIC_READ | FILE_GENERIC_WRITE);
status = WdfIoTargetOpen(resourceHandle, &openParams);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Commit the resource
//
status = WdfIoTargetSendIoctlSynchronously(
resourceHandle,
WDF_NO_HANDLE, // WdfRequest
IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS,
nullptr, // InputBuffer
nullptr, // OutputBuffer
nullptr, // RequestOptions
nullptr); // BytesReturned
if (!NT_SUCCESS(status)) {
WdfIoTargetClose(resourceHandle);
return status;
}
//
// Pins were successfully muxed, return the handle to the caller
//
*ResourceHandlePtr = resourceHandle;
return STATUS_SUCCESS;
}
驱动程序应该在它的其中一个上下文区域中存储 WDFIOTARGET,以便它可以稍后进行关闭。 当驱动程序准备释放复用配置时,它应该通过调用 WdfObjectDelete\(\) 或 WdfIoTargetClose\(\) 来关闭资源句柄(如果你打算重新使用 WDFIOTARGET)。
C++ 复制
WdfObjectDelete(resourceHandle);
当客户端关闭其资源句柄时,引脚将复用回其初始状态,现在可以由其他客户端获取。
[](#protocol-description-for-pin-muxing-servers)
本部分介绍引脚复用服务器如何向客户端公开其功能。 这不适用于 GpioClx
微型端口驱动程序,因为框架会代表客户端驱动程序实现此协议。 有关如何在客户端驱动程序中 GpioClx
支持引脚复用的详细信息,请参阅 在 GpioClx 客户端驱动程序中实现复用支持。
[](#handling-irp_mj_create-requests)
当客户端想要保留引脚复用资源时,它们会打开资源句柄。 引脚复用服务器通过资源中心的重分析操作来接收 IRP_MJ_CREATE 请求。 IRP_MJ_CREATE 请求的尾随路径组件包含资源中心 ID,该 ID 是十六进制格式的 64 位整数。 服务器应使用 RESOURCE_HUB_ID_FROM_FILE_NAME()
reshub.h 中的 从文件名中提取资源中心 ID,并将 IOCTL_RH_QUERY_CONNECTION_PROPERTIES 发送到资源中心以获取 MsftFunctionConfig()
描述符。
服务器应该验证描述符,然后从描述符中提取共享模式和引脚列表。 接下来,应该对引脚执行共享仲裁,在完成请求之前,如果成功,将该引脚标记为保留。
如果对引脚列表中的每个引脚成功执行共享仲裁,则共享仲裁总体成功。 应按如下方式对每个引脚进行仲裁:
在引脚已保留为共享时,
如果共享仲裁失败,应使用 STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE 完成请求。 如果共享仲裁成功,应使用 STATUS_SUCCESS 完成请求。
请注意,应从 MsftFunctionConfig 描述符而不是从 IrpSp->Parameters.Create.ShareAccess 中获取传入请求的共享模式。
[](#handling-ioctl_gpio_commit_function_config_pins-requests)
在客户端通过打开句柄成功保留了 MsftFunctionConfig 资源后,它可以发送 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 以请求服务器执行实际的硬件复用操作。 当服务器接收 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 时,对于引脚列表中的每个引脚,它应该
然后服务器应使用 STATUS_SUCCESS 完成请求。
FunctionNumber 的含义由服务器定义,据了解,MsftFunctionConfig 描述符是运用了服务器如何解释此字段这一方面的知识撰写的。
请记住,当关闭该句柄时,服务器必须将引脚恢复为收到 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 时引脚所使用的配置,因此服务器在修改引脚之前,可能需要保存这些引脚的状态。
[](#handling-irp_mj_close-requests)
当客户端不再需要复用资源时,它会关闭其句柄。 当服务器接收 IRP_MJ_CLOSE 请求时,它应该将引脚恢复为收到 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 时引脚所处的状态。 如果客户端从未发送 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS_,则无需执行任何操作。 接下来,服务器应该在执行共享仲裁后将引脚标记为可用,然后使用 _STATUS_SUCCESS 完成请求。 请确保正确同步 IRP_MJ_CLOSE 处理与 IRP_MJ_CREATE 处理。
[](#authoring-guidelines-for-acpi-tables)
本部分介绍如何将复用资源提供给客户端驱动程序。 请注意,你需要 Microsoft ASL 编译器版本 14327 或更高版本来编译包含 MsftFunctionConfig()
资源的表。 MsftFunctionConfig()
资源提供给引脚复用客户端作为硬件资源。 应将 MsftFunctionConfig()
资源提供给需要更改引脚复用的驱动程序,这些驱动程序通常是 SPB 和串行控制器驱动程序;但不应将该资源提供给 SPB 和串行外设驱动程序,因为该控制器驱动程序将处理复用配置。 MsftFunctionConfig()
ACPI 宏按如下方式定义:
C++ 复制
MsftFunctionConfig(Shared/Exclusive
PinPullConfig,
FunctionNumber,
ResourceSource,
ResourceSourceIndex,
ResourceConsumer/ResourceProducer,
VendorData) { Pin List }
PinPullConfig – 其中之一
以下示例演示一个管脚复用服务器可能会如何将 MsftFunctionConfig() 资源提供给 I2C 控制器驱动程序。
C++ 复制
Device(I2C1)
{
Name(_HID, "BCM2841")
Name(_CID, "BCMI2C")
Name(_UID, 0x1)
Method(_STA)
{
Return(0xf)
}
Method(_CRS, 0x0, NotSerialized)
{
Name(RBUF, ResourceTemplate()
{
Memory32Fixed(ReadWrite, 0x3F804000, 0x20)
Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) { 0x55 }
MsftFunctionConfig(Exclusive, PullUp, 4, "\\_SB.GPI0", 0, ResourceConsumer, ) { 2, 3 }
})
Return(RBUF)
}
}
除了控制器驱动程序通常所需的内存和中断资源,还要指定 MsftFunctionConfig()
资源。 此资源允许 I2C 控制器驱动程序将引脚 2 和 3(由 \_SB.GPIO0 处的设备节点进行管理)置于已启用上拉电阻器的功能 4 中。
[](#supporting-muxing-support-in-gpioclx-client-drivers)
GpioClx
具有对引脚复用的内置支持。 GpioClx 微型端口驱动程序(也称为“GpioClx 客户端驱动程序”),驱动 GPIO 控制器硬件。 从 Windows 10 内部版本 14327 开始,GpioClx 微型端口驱动程序可以通过实现两个新的 DDI 添加对引脚复用的支持:
GpioClx
调用以命令微型端口驱动程序应用指定的复用配置。GpioClx
调用以命令微型端口驱动程序恢复复用配置。有关这些例程的描述,请参阅 GpioClx 事件回调函数)。
除了这两个新的 DDI,应针对引脚复用兼容性审核现有 DDI:
例如,假设引脚的默认复用配置为 UART,则也可以将引脚用作 GPIO。 调用 CLIENT_ConnectIoPins 以连接用于 GPIO 的引脚时,它应该将该引脚复用为 GPIO;在 CLIENT_DisconnectIoPins 中,它应该将该引脚复用回 UART。 一般情况下,Disconnect 例程应撤消 Connect 例程执行的操作。
[](#supporting-muxing-in-spbcx-and-sercx-controller-drivers)
从 Windows 10 内部版本 14327 开始,SpbCx
和 SerCx
框架包含对引脚复用的内置支持,这允许在无需更改 SpbCx
和 SerCx
控制器驱动程序自身的任何代码的情况下,就可以使这些控制器驱动程序成为引脚复用客户端。 通过扩展,连接到支持复用的 SpbCx/SerCx 控制器驱动程序的任何 SpbCx/SerCx 外设驱动程序将触发引脚复用活动。
下图显示了每个组件之间的依存关系。 如你所见,引脚复用将依存关系从 SerCx 和 SpbCx 控制器驱动程序引入了 GPIO 驱动程序,它通常负责复用。
在设备初始化期间,SpbCx
和 SerCx
框架会解析作为硬件资源提供给设备的所有 MsftFunctionConfig()
资源。 然后 SpbCx/SerCx 按需获取和释放引脚复用资源。
SpbCx
在调用客户端驱动程序的 EvtSpbTargetConnect () 回调之前,在其_IRP_MJ_CREATE_处理程序中应用引脚复用配置。 如果无法应用复用配置,将不会调用控制器驱动程序的 EvtSpbTargetConnect()
回调。 因此,SPB 控制器驱动程序可能会假设在调用 EvtSpbTargetConnect()
时,引脚会复用为 SPB 功能。
SpbCx
在调用控制器驱动程序的 EvtSpbTargetDisconnect () 回调后,还原其_IRP_MJ_CLOSE_处理程序中的引脚复用配置。 结果是,每当外设驱动程序打开 SPB 控制器驱动程序的句柄时,引脚就会复用为 SPB 功能;当外设驱动程序关闭其句柄时,会复用回引脚。
SerCx
具有类似的行为。 SerCx
`MsftFunctionConfig()`在调用控制器驱动程序的 EvtSerCx2FileOpen () 回调之前,获取其 IRP_MJ_CREATE 处理程序中的所有资源,并在调用控制器驱动程序的 EvtSerCx2FileClose 回调之后释放其 IRP_MJ_CLOSE 处理程序中的所有资源。
适用于 SerCx
和 SpbCx
控制器驱动程序的动态引脚复用的含义就是:它们必须能够容忍在某些时候从 SPB/UART 功能复用回引脚。 控制器驱动程序需要假设:在调用 EvtSpbTargetConnect()
或 EvtSerCx2FileOpen()
之前,不会复用引脚。 在以下回调期间,引脚不必复用为 SPB/UART 功能。 以下列表虽然不完整,但呈现了控制器驱动程序所实现的最常用 PNP 例程。
[](#verification)
当你准备好测试 rhproxy 时,使用下面的分步过程将很有帮助。
SpbCx
、GpioClx
和 SerCx
控制器都正确加载和运行rhproxy
。 有些 Windows 版本没有此功能。ACPITABL.dat
编译并加载 rhproxy 节点rhproxy
设备节点是否存在rhproxy
是否加载和启动[](#verify-controller-drivers)
由于 rhproxy 将系统上的其他设备向用户模式公开,因此它仅在这些设备运行时工作。 第一步是验证这些设备(你希望公开的 I2C、SPI、GPIO 控制器)是否已经运行。
在命令提示符处,运行
ps 复制
devcon status *
查看输出并验证所有关注的设备是否都已启动。 如果设备出现问题代码,你需要找出设备未加载的原因。 所有设备均应在平台初始启动期间已启用。 SpbCx
、GpioClx
或 SerCx
控制器驱动程序的疑难解答已超出本文的介绍范围。
[](#verify-that-rhproxy-is-present-on-the-system)
验证系统中是否存在 rhproxy
服务。
ps 复制
reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy
如果此注册表项不存在,那么你的系统上就没有 rhproxy。 所有 IoT 核心版的内部版本和 Windows 企业版版本 15063 及更高版本均有 Rhproxy。
[](#compile-and-load-asl-with-acpitabldat)
现在你已创作了 rhproxy ASL 节点,应该编译并加载它了。 你可以将 rhproxy 节点编译为可附加到系统 ACPI 表的独立 AML 文件。 或者,如果你有权访问系统的 ACPI 源,则可以将 rhproxy 节点直接插入平台的 ACPI 表中。 但是,在初始启动时,使用 ACPITABL.dat
可能更方便。
创建名为“yourboard.asl”的文件,然后将 RHPX 设备节点放入 DefinitionBlock 中:
C++ 复制
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
Scope (\_SB)
{
Device(RHPX)
{
...
}
}
}
C:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerify
中下载 WDK 并找到 asl.exe
运行以下命令以生成 ACPITABL.dat:
ps 复制
asl.exe yourboard.asl
在在测系统上打开 testsigning:
ps 复制
bcdedit /set testsigning on
[](#verify-that-the-rhproxy-device-node-exists)
运行以下命令以枚举 rhproxy 设备节点。
ps 复制
devcon status *msft8000
Devcon 的输出应指示设备存在。 如果设备节点未显示,表示 ACPI 表未成功添加到系统。
[](#verify-that-rhproxy-is-loading-and-starting)
检查 rhproxy 的状态:
ps 复制
devcon status *msft8000
如果输出指示 rhproxy 已启动,则 rhproxy 已成功加载并启动。 如果你看到问题代码,则需要进行调查。 一些常见的问题代码有:
CM_PROB_WAITING_ON_DEPENDENCY
- 系统未启动 rhproxy,因为它的依赖项之一加载失败。 这表明传递到 rhproxy 的资源指向无效的 ACPI 节点,或目标设备未启动。 首先,请仔细检查是否所有设备都成功运行(请参阅上方的“验证控制器驱动程序”)。 然后,仔细检查 ASL,确保所有资源路径(例如,\_SB.I2C1
)正确无误并指向 DSDT 中的有效节点。CM_PROB_FAILED_START
- Rhproxy 启动失败,很可能是由于资源解析问题。 仔细检查 ASL 以及 DSD 中的资源索引,并验证 GPIO 资源是否按照引脚编号的升序顺序指定。[](#verify-that-the-expected-devices-are-exposed-to-user-mode)
现在 rhproxy 已经运行,它应该已经创建了可由用户模式访问的设备接口。 我们将使用几种命令行工具来枚举设备,并查看它们是否显示。
克隆 https://github.com/ms-iot/samples 存储库并生成 GpioTestTool
、I2cTestTool
、SpiTestTool
和 Mincomm
示例。 将工具复制到正在测试的设备,并使用以下命令枚举设备。
ps 复制
I2cTestTool.exe -list
SpiTestTool.exe -list
GpioTestTool.exe -list
MinComm.exe -list
你应该看到列出了你的设备和友好名称。 如果你看不到正确的设备和友好名称,请仔细检查你的 ASL。
[](#verify-each-device-on-the-command-line)
下一步是使用命令行工具打开设备并与之交互。
I2CTestTool 示例:
ps 复制
I2cTestTool.exe 0x55 I2C1
> write {1 2 3}
> read 3
> writeread {1 2 3} 3
SpiTestTool 示例:
ps 复制
SpiTestTool.exe -n SPI1
> write {1 2 3}
> read 3
GpioTestTool 示例:
ps 复制
GpioTestTool.exe 12
> setdrivemode output
> write 0
> write 1
> setdrivemode input
> read
> interrupt on
> interrupt off
MinComm (serial) 示例。 运行之前将 Rx 连接到 Tx:
ps 复制
MinComm "\\?\ACPI#FSCL0007#3#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\0000000000000006"
(type characters and see them echoed back)
[](#verify-each-device-from-a-uwp-app)
使用下面的示例验证从 UWP 工作的设备。
[](#run-the-hlk-tests)
下载 Hardware Lab Kit (HLK)。 提供以下测试:
当在 HLK 管理器中选择 rhproxy 设备节点时,将自动选择适用的测试。
在 HLK 管理器中,选择“资源中心代理设备”:
随后单击“测试”选项卡,然后依次选择 I2C WinRT、Gpio WinRT 和 Spi WinRT 测试。
单击“运行所选项”。 通过右键单击某个测试,然后单击“测试描述”可以获得有关每个测试的进一步文档。
[](#resources)
[](#appendix)
[](#appendix-a---raspberry-pi-asl-listing)
C++ 复制
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
Scope (\_SB)
{
//
// RHProxy Device Node to enable WinRT API
//
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
Name(_CRS, ResourceTemplate()
{
// Index 0
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE0 - GPIO 8 - Pin 24
0, // Device selection (CE0)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 1
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE1 - GPIO 7 - Pin 26
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 2
SPISerialBus( // SCKL - GPIO 21 - Pin 40
// MOSI - GPIO 20 - Pin 38
// MISO - GPIO 19 - Pin 35
// CE1 - GPIO 17 - Pin 11
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI1", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 3
I2CSerialBus( // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
0xFFFF, // SlaveAddress: placeholder
, // SlaveMode: default to ControllerInitiated
0, // ConnectionSpeed: placeholder
, // Addressing Mode: placeholder
"\\_SB.I2C1", // ResourceSource: I2C bus controller name
,
,
) // VendorData
// Index 4 - GPIO 4 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 4 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 4 }
// Index 6 - GPIO 5 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 5 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 5 }
// Index 8 - GPIO 6 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 6 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 6 }
// Index 10 - GPIO 12 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 12 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 12 }
// Index 12 - GPIO 13 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 13 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 13 }
// Index 14 - GPIO 16 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 16 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 16 }
// Index 16 - GPIO 18 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 18 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 18 }
// Index 18 - GPIO 22 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 22 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 22 }
// Index 20 - GPIO 23 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 23 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 23 }
// Index 22 - GPIO 24 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 24 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 24 }
// Index 24 - GPIO 25 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 25 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 25 }
// Index 26 - GPIO 26 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 26 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 26 }
// Index 28 - GPIO 27 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 27 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 27 }
// Index 30 - GPIO 35 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 35 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 35 }
// Index 32 - GPIO 47 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 47 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 47 }
})
Name(_DSD, Package()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package()
{
// Reference http://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
// SPI 0
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }}, // Index 0 & 1
Package(2) { "SPI0-MinClockInHz", 7629 }, // 7629 Hz
Package(2) { "SPI0-MaxClockInHz", 125000000 }, // 125 MHz
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
// SPI 1
Package(2) { "bus-SPI-SPI1", Package() { 2 }}, // Index 2
Package(2) { "SPI1-MinClockInHz", 30518 }, // 30518 Hz
Package(2) { "SPI1-MaxClockInHz", 125000000 }, // 125 MHz
Package(2) { "SPI1-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
// I2C1
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
// GPIO Pin Count and supported drive modes
Package (2) { "GPIO-PinCount", 54 },
Package (2) { "GPIO-UseDescriptorPinNumbers", 1 },
Package (2) { "GPIO-SupportedDriveModes", 0xf }, // InputHighImpedance, InputPullUp, InputPullDown, OutputCmos
}
})
}
}
}
[](#appendix-b---minnowboardmax-asl-listing)
另请参阅 MinnowBoard Max 引脚映射
C++ 复制
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
Scope (\_SB)
{
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
Name(_CRS, ResourceTemplate()
{
// Index 0
SPISerialBus( // Pin 5, 7, 9 , 11 of JP1 for SIO_SPI
1, // Device selection
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
8, // databit len
ControllerInitiated, // slave mode
8000000, // Connection speed
ClockPolarityLow, // Clock polarity
ClockPhaseSecond, // clock phase
"\\_SB.SPI1", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
ResourceConsumer, // Resource usage
JSPI, // DescriptorName: creates name for offset of resource descriptor
) // Vendor Data
// Index 1
I2CSerialBus( // Pin 13, 15 of JP1, for SIO_I2C5 (signal)
0xFF, // SlaveAddress: bus address
, // SlaveMode: default to ControllerInitiated
400000, // ConnectionSpeed: in Hz
, // Addressing Mode: default to 7 bit
"\\_SB.I2C6", // ResourceSource: I2C bus controller name (For MinnowBoard Max, hardware I2C5(0-based) is reported as ACPI I2C6(1-based))
,
,
JI2C, // Descriptor Name: creates name for offset of resource descriptor
) // VendorData
// Index 2
UARTSerialBus( // Pin 17, 19 of JP1, for SIO_UART2
115200, // InitialBaudRate: in bits ber second
, // BitsPerByte: default to 8 bits
, // StopBits: Defaults to one bit
0xfc, // LinesInUse: 8 1-bit flags to declare line enabled
, // IsBigEndian: default to LittleEndian
, // Parity: Defaults to no parity
, // FlowControl: Defaults to no flow control
32, // ReceiveBufferSize
32, // TransmitBufferSize
"\\_SB.URT2", // ResourceSource: UART bus controller name
,
,
UAR2, // DescriptorName: creates name for offset of resource descriptor
)
// Index 3
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {0} // Pin 21 of JP1 (GPIO_S5[00])
// Index 4
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {0}
// Index 5
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {1} // Pin 23 of JP1 (GPIO_S5[01])
// Index 6
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {1}
// Index 7
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {2} // Pin 25 of JP1 (GPIO_S5[02])
// Index 8
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {2}
// Index 9
UARTSerialBus( // Pin 6, 8, 10, 12 of JP1, for SIO_UART1
115200, // InitialBaudRate: in bits ber second
, // BitsPerByte: default to 8 bits
, // StopBits: Defaults to one bit
0xfc, // LinesInUse: 8 1-bit flags to declare line enabled
, // IsBigEndian: default to LittleEndian
, // Parity: Defaults to no parity
FlowControlHardware, // FlowControl: Defaults to no flow control
32, // ReceiveBufferSize
32, // TransmitBufferSize
"\\_SB.URT1", // ResourceSource: UART bus controller name
,
,
UAR1, // DescriptorName: creates name for offset of resource descriptor
)
// Index 10
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {62} // Pin 14 of JP1 (GPIO_SC[62])
// Index 11
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {62}
// Index 12
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {63} // Pin 16 of JP1 (GPIO_SC[63])
// Index 13
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {63}
// Index 14
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {65} // Pin 18 of JP1 (GPIO_SC[65])
// Index 15
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {65}
// Index 16
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {64} // Pin 20 of JP1 (GPIO_SC[64])
// Index 17
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {64}
// Index 18
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {94} // Pin 22 of JP1 (GPIO_SC[94])
// Index 19
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {94}
// Index 20
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {95} // Pin 24 of JP1 (GPIO_SC[95])
// Index 21
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {95}
// Index 22
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {54} // Pin 26 of JP1 (GPIO_SC[54])
// Index 23
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {54}
})
Name(_DSD, Package()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package()
{
// SPI Mapping
Package(2) { "bus-SPI-SPI0", Package() { 0 }},
Package(2) { "SPI0-MinClockInHz", 100000 },
Package(2) { "SPI0-MaxClockInHz", 15000000 },
// SupportedDataBitLengths takes a list of support data bit length
// Example : Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8, 7, 16 }},
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }},
// I2C Mapping
Package(2) { "bus-I2C-I2C5", Package() { 1 }},
// UART Mapping
Package(2) { "bus-UART-UART2", Package() { 2 }},
Package(2) { "bus-UART-UART1", Package() { 9 }},
}
})
}
}
}
[](#appendix-c---sample-powershell-script-to-generate-gpio-resources)
以下脚本可用于生成适用于 Raspberry Pi 的 GPIO 资源声明:
ps 复制
$pins = @(
@{PinNumber=4;PullConfig='PullUp'},
@{PinNumber=5;PullConfig='PullUp'},
@{PinNumber=6;PullConfig='PullUp'},
@{PinNumber=12;PullConfig='PullDown'},
@{PinNumber=13;PullConfig='PullDown'},
@{PinNumber=16;PullConfig='PullDown'},
@{PinNumber=18;PullConfig='PullDown'},
@{PinNumber=22;PullConfig='PullDown'},
@{PinNumber=23;PullConfig='PullDown'},
@{PinNumber=24;PullConfig='PullDown'},
@{PinNumber=25;PullConfig='PullDown'},
@{PinNumber=26;PullConfig='PullDown'},
@{PinNumber=27;PullConfig='PullDown'},
@{PinNumber=35;PullConfig='PullUp'},
@{PinNumber=47;PullConfig='PullUp'})
# generate the resources
$FIRST_RESOURCE_INDEX = 4
$resourceIndex = $FIRST_RESOURCE_INDEX
$pins | % {
$a = @"
// Index $resourceIndex - GPIO $($_.PinNumber) - $($_.Name)
GpioIO(Shared, $($_.PullConfig), , , , "\\_SB.GPI0", , , , ) { $($_.PinNumber) }
GpioInt(Edge, ActiveBoth, Shared, $($_.PullConfig), 0, "\\_SB.GPI0",) { $($_.PinNumber) }
"@
Write-Host $a
$resourceIndex += 2;
}
原网址: 访问
创建于: 2023-10-31 11:54:06
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论