학습
모듈
Troubleshoot device driver failures - Training
This module focuses on the role of device drivers and troubleshooting problems that pertain to them.
Windows 10 이상에서는 API를 사용자 모드에서 GPIO(범용 입력/출력), I2C(Inter-Integrated Circuit), SPI(직렬 주변 장치 인터페이스) 및 UART(범용 비동기 수신기-송신기)로 직접 액세스할 수 있습니다. Raspberry Pi 2와 같은 개발 보드는 사용자 지정 회로로 기본 컴퓨팅 모듈을 확장하여 특정 애플리케이션을 처리할 수 있도록 하는 이러한 연결 일부를 노출합니다. 이러한 낮은 수준의 버스는 일반적으로 헤더에 노출되는 GPIO 핀 및 버스의 하위 집합만 있는 다른 중요한 온보드 함수와 공유됩니다. 시스템의 안정성을 유지하기 위해서는 사용자 모드 애플리케이션에서 수정하기에 안전한 핀 및 버스를 지정해야 합니다.
이 문서는 ACPI(고급 구성 및 전원 인터페이스)에서 이 구성을 지정하는 방법을 설명하고 구성이 올바르게 지정되었는지 확인하기 위한 도구를 제공합니다.
중요
이 문서의 대상은 UEFI(통일 확장 펌웨어 인터페이스) 및 ACPI 개발자입니다. 이러한 개발자는 ACPI, ASL(ACPI 원본 언어) 제작 및 SpbCx/GpioClx에 대해 어느 정도 친숙한 것으로 간주됩니다.
Windows의 낮은 수준 버스에 대한 사용자 모드 액세스는 기존의 GpioClx
및 SpbCx
프레임워크를 통해 연결됩니다. Windows IoT Core 및 Windows Enterprise에서 사용할 수 있는 RhProxy라는 새 드라이버는 GpioClx
및 SpbCx
리소스를 사용자 모드에 공개합니다. 이 API를 사용하도록 설정하려면 사용자 모드에 공개해야 하는 각 GPIO 및 SPB 리소스를 사용하여 ACPI 테이블에서 rhproxy에 대한 디바이스 노드를 선언해야 합니다. 이 문서는 ASL 작성 및 확인을 안내합니다.
Raspberry Pi 2에서 rhproxy 디바이스 노드 선언을 살펴봅니다. 먼저 \_SB 범위에서 ACPI 디바이스 선언을 만듭니다.
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
}
다음으로 사용자 모드에 노출해야 하는 각 GPIO 및 SPB 리소스를 선언합니다. 리소스 인덱스는 리소스와 속성을 연결하는 데 사용되므로 리소스가 선언되는 순서가 중요합니다. 여러 I2C 또는 SPI 버스가 노출되는 경우 첫 번째 선언된 버스는 해당 유형의 '기본' 버스로 간주되며 Windows.Devices.I2c.I2cController 및 Windows.Devices.Spi.SpiController의 GetDefaultAsync()
메서드에서 반환되는 인스턴스가 됩니다.
Raspberry Pi에는 두 대의 노출된 SPI 버스가 있습니다. SPI0에는 두 개의 하드웨어 칩 선택 라인이 있고 SPI1에는 하나의 하드웨어 칩 선택 라인이 있습니다. 각 버스의 각 칩 선택 라인에 대해 하나의 SPISerialBus() 리소스 선언이 필요합니다. 다음 두 SPISerialBus 리소스 선언은 SPI0의 두 칩 선택 라인에 대한 것입니다. DeviceSelection 필드는 드라이버가 하드웨어 칩 선택 줄 식별자로 해석하는 고유한 값을 포함합니다. DeviceSelection 필드에 입력한 정확한 값은 드라이버가 ACPI 연결 설명자의 이 필드를 해석하는 방법에 따라 달라집니다.
참고
이 문서는 Microsoft가 용납하지 않고 새 제품 및 설명서에서 사용을 중지한 용어인 슬레이브에 대한 참조를 포함합니다. 소프트웨어에서 용어가 제거되면 이 문서에서 해당 용어가 제거됩니다.
// 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에 버스 이름 및 리소스 인덱스 간의 매핑이 지정됩니다.
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},
이렇게 하면 리소스 인덱스 0과 1이라는 두 개의 칩 선택 라인이 있는 "SPI0"이라는 버스가 만들어집니다. SPI 버스의 기능을 선언하려면 몇 가지 속성이 추가로 필요합니다.
Package(2) { "SPI0-MinClockInHz", 7629 },
Package(2) { "SPI0-MaxClockInHz", 125000000 },
MinClockInHz 및 MaxClockInHz 속성은 컨트롤러에서 지원하는 최소 및 최대 클록 속도를 지정합니다. API는 사용자가 이 범위를 벗어난 값을 지정하지 못하도록 합니다. 시계 속도는 연결 설명자의 _SPE 필드에 있는 SPB 드라이버에 전달됩니다(ACPI 섹션 6.4.3.8.2.2).
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},
SupportedDataBitLengths 속성은 컨트롤러에서 지원하는 데이터 비트 길이를 나열합니다. 쉼표로 구분된 목록에 여러 값을 지정할 수 있습니다. API는 사용자가 이 목록을 벗어난 값을 지정하지 못하도록 합니다. 데이터 비트 길이는 연결 설명자의 _LEN 필드에 있는 SPB 드라이버에 전달됩니다(ACPI 섹션 6.4.3.8.2.2).
이러한 리소스 선언은 "템플릿"으로 간주될 수 있습니다. 일부 필드는 시스템 부팅 시 고정되며 다른 필드는 런타임에 동적으로 지정됩니다. SPISerialBus 설명자의 다음의 필드가 수정되었습니다.
다음의 필드는 런타임에 사용자가 지정한 값에 대한 자리 표시자입니다.
SPI1에는 단일 칩 선택 라인만 포함되므로 단일 SPISerialBus()
리소스가 선언됩니다.
// 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에 지정되며 이 리소스 선언의 인덱스를 참조합니다.
Package(2) { "bus-SPI-SPI1", Package() { 2 }},
이렇게 하면 "SPI1"이라는 버스가 만들어지고 리소스 인덱스 2와 연결됩니다.
SpbCx
을(를) 사용하거나 SpbCx 호환이 가능해야 합니다다음으로, I2C 리소스를 선언합니다. Raspberry Pi는 핀 3과 5에 단일 I2C 버스를 노출합니다.
// 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에 지정됩니다.
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
위에서 선언한 I2CSerialBus() 리소스의 인덱스인 리소스 인덱스 3을 참조하는 이름이 "I2C1"로 지정된 I2C 버스를 선언합니다.
I2CSerialBus() 설명자의 다음의 필드가 수정되었습니다.
다음의 필드는 런타임에 사용자가 지정한 값에 대한 자리 표시자입니다.
다음으로 사용자 모드에 노출되는 모든 GPIO 핀을 선언합니다. 노출할 핀을 결정하는 다음의 지침을 제공합니다.
다음의 ASL 블록은 GPIO4 및 GPIO5의 두 핀을 선언합니다. 다른 핀은 간결함을 위해 여기에 표시되지 않습니다. 부록 C에는 GPIO 리소스를 생성하는 데 사용할 수 있는 샘플 PowerShell 스크립트가 포함되어 있습니다.
// 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 핀을 선언할 때 다음의 요구 사항을 준수해야 합니다.
펌웨어, UEFI 및 드라이버 초기화 코드는 부팅 중에 핀의 상태를 전원 켜기 상태에서 변경해서는 안 됩니다. 사용자만 핀에 연결된 항목 및 따라서 어떤 상태 전환이 안전한지 알고 있습니다. 각 핀의 전원 켜기 상태를 문서화하여 사용자가 핀과 올바르게 인터페이스하는 하드웨어를 디자인할 수 있도록 해야 합니다. 부팅하는 동안 핀이 예기치 않게 상태를 변경해서는 안됩니다.
GPIO 컨트롤러가 높은 임피댄스 입력 및 CMOS 출력 외에도 기본 제공 풀업 및 풀다운 저항기를 지원하는 경우 선택적 SupportedDriveModes 속성으로 이를 지정해야 합니다.
Package (2) { “GPIO-SupportedDriveModes”, 0xf },
SupportedDriveModes 속성은 GPIO 컨트롤러에서 지원되는 드라이브 모드를 나타냅니다. 위의 예시에서는 다음의 드라이브 모드가 모두 지원됩니다. 속성은 다음 값의 비트 마스크입니다.
플래그 값 | 드라이브 모드 | 설명 |
---|---|---|
0x1 | InputHighImpedance | 핀이 ACPI의 "PullNone" 값에 해당하는 높은 임피던스 입력을 지원합니다. |
0x2 | InputPullUp | 핀이 ACPI의 "PullUp" 값에 해당하는 기본 제공 풀업 저항기를 지원합니다. |
0x4 | InputPullDown | 핀이 ACPI의 "PullDown" 값에 해당하는 기본 제공 풀다운 저항기를 지원합니다. |
0x8 | OutputCmos | 핀은 (오픈 드레이닝과는 달리) 강한 최고 및 강한 최저값을 모두 생성하도록 지원합니다. |
InputHighImpedance 및 OutputCmos는 거의 모든 GPIO 컨트롤러에서 지원됩니다. SupportedDriveModes 속성을 지정하지 않으면 기본값입니다.
노출된 헤더에 도달하기 전에 GPIO 신호가 수준 시프트를 통과하는 경우, 드라이브 모드가 외부 헤더에서 관찰할 수 없는 경우에도 SOC에서 지원하는 드라이브 모드를 선언합니다. 예를 들어 핀이 양방향 수준 시프터를 통과하여 핀이 저항적 풀업으로 열린 드레인으로 표시되는 경우, 핀이 높은 임피든스 입력으로 구성된 경우라도 노출된 헤더에서 높은 임피다스 상태를 관찰하지 않습니다. 핀이 높은 임피댄스 입력을 지원한다고 선언해야 합니다.
Windows는 다음과 같은 두 개의 핀 번호 매기기 체계를 지원합니다.
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },
UseDescriptorPinNumbers 속성은 Windows에 순차 핀 번호 매기기 대신 네이티브 핀 번호 매기기를 사용하도록 지시합니다. UseDescriptorPinNumbers 속성이 지정되지 않았거나 값이 0이면 Windows는 기본적으로 순차 핀 번호 매기기로 설정됩니다.
네이티브 핀 번호 매기기를 사용하는 경우, PinCount 속성도 지정해야 합니다.
Package (2) { “GPIO-PinCount”, 54 },
PinCount 속성은 GpioClx
드라이버의 CLIENT_QueryControllerBasicInformation 콜백에서 TotalPins 속성을 통해 반환된 값과 일치해야 합니다.
보드에 대해 게시된 기존 설명서와 가장 호환되는 번호 매기기 체계를 선택합니다. 예를 들어 대부분의 기존 핀아웃 다이어그램은 BCM2835 핀 번호를 사용하기 때문에 Raspberry Pi는 네이티브 핀 번호 매기기를 사용합니다. MinnowBoardMax는 기존 핀아웃 다이어그램이 거의 없기 때문에 순차 핀 번호 매기기를 사용하며, 200개 이상의 핀에서 10개의 핀만 노출되므로 순차 핀 번호 매기기가 개발자 환경을 간소화합니다. 순차적 또는 네이티브 핀 번호 매기기를 사용하는 결정은 개발자의 혼란을 줄이는 것을 목표로 해야 합니다.
GpioClx
을(를) 사용해야 합니다.UART 드라이버가 SerCx
또는 SerCx2
(을)를 사용하는 경우, rhproxy를 사용하여 사용자 모드에 드라이버를 노출할 수 있습니다. rhproxy는 GUID_DEVINTERFACE_COMPORT
형식의 디바이스 인터페이스를 만드는 UART 드라이버에서는 사용할 필요가 없습니다. 받은 편지함 Serial.sys
드라이버는 이러한 경우 중 하나입니다.
SerCx
스타일 UART를 사용자 모드에 노출하려면 다음과 같이 UARTSerialBus
리소스를 선언합니다.
// 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 필드만 고정되지만 다른 모든 필드는 런타임에 사용자가 지정한 값의 자리 표시자입니다.
함께 제공되는 이름 선언은 다음과 같습니다.
Package(2) { "bus-UART-UART2", Package() { 2 }},
이 이름 선언은 사용자가 사용자 모드에서 버스에 액세스하는 데 사용하는 식별자에 해당하는 식별 이름 “UART2”를 컨트롤러에 할당합니다.
핀 먹싱은 다른 함수에 동일한 실제 핀을 사용하는 기능입니다. I2C 컨트롤러, SPI 컨트롤러 및 GPIO 컨트롤러와 같은 여러 다른 온칩 주변 장치는 SOC에서 동일한 물리적 핀으로 라우팅될 수 있습니다. 먹스 블록은 지정된 시간에 핀에서 활성 상태인 함수를 제어합니다. 일반적으로 펌웨어는 부팅 시 함수 할당을 설정해야 하며, 이 할당은 부팅 세션을 통해 정적으로 유지됩니다. 런타임 핀 먹싱은 런타임에 핀 함수 할당을 다시 구성하는 기능을 추가합니다. 사용자가 런타임에 핀의 기능을 선택할 수 있도록 하면 사용자가 보드의 핀을 신속하게 다시 구성할 수 있으므로 개발 속도가 빨라지고 하드웨어가 정적 구성보다 광범위한 애플리케이션을 지원할 수 있습니다.
사용자는 GPIO, I2C, SPI 및 UART에 대한 먹싱 지원을 추가 코드를 작성하지 않고 사용합니다. 사용자가 OpenPin() 또는 FromIdAsync()를 사용하여 GPIO 또는 버스를 열면 기본 물리적 핀이 요청된 함수에 자동으로 muxed됩니다. 핀이 다른 함수에서 이미 사용 중인 경우, OpenPin() 또는 FromIdAsync() 호출은 실패합니다. 사용자가 GpioPin, I2cDevice, SpiDevice 또는 SerialDevice 개체를 삭제하여 장치를 닫으면 핀이 해제되어 나중에 다른 함수에 대해 열 수 있습니다.
Windows는 GpioClx, SpbCx 및 SerCx 프레임워크의 핀 먹싱에 대한 기본 제공 지원을 포함합니다. 이러한 프레임워크는 GPIO 핀 또는 버스에 액세스할 때 핀을 올바른 함수로 자동으로 전환하기 위해 함께 작동합니다. 핀에 대한 액세스는 여러 클라이언트 간의 충돌을 방지하기 위해 중재됩니다. 이 기본 제공 지원 외에도 핀 먹싱에 대한 인터페이스 및 프로토콜은 범용이며 추가 장치 및 시나리오를 지원하도록 확장할 수 있습니다.
이 문서는 먼저 핀 먹싱과 관련된 기본 인터페이스 및 프로토콜에 대해 설명한 다음 GpioClx, SpbCx 및 SerCx 컨트롤러 드라이버에 핀 먹싱에 대한 지원을 추가하는 방법을 설명합니다.
이 섹션은 핀 먹싱과 관련된 기본 인터페이스 및 프로토콜에 대해 설명합니다. 기본 프로토콜에 대한 지식은 GpioClx/SpbCx/SerCx 드라이버로 핀 먹싱을 지원하기 위해 반드시 필요한 것은 아닙니다. GpioCls/SpbCx/SerCx 드라이버로 핀 먹싱을 지원하는 방법에 대한 자세한 정보는 GpioClx 클라이언트 드라이버에서 핀 먹싱 지원 구현하기 및 SpbCx 및 SerCx 컨트롤러 드라이버에서 먹싱 지원 사용하기를 참조하세요.
핀 먹싱은 여러 구성 요소의 협력을 통해 수행됩니다.
MsftFunctionConfig()
리소스가 포함된 먹싱 구성을 지정합니다. MsftFunctionConfig 리소스는 클라이언트에서 먹싱 구성이 필요한 핀을 표현합니다. MsftFunctionConfig 리소스는 함수 번호, 끌어오기 구성 및 핀 번호 목록을 포함합니다. MsftFunctionConfig 리소스는 먹싱 클라이언트를 하드웨어 리소스로 고정하기 위해 제공되며, 이는 GPIO 및 SPB 연결 리소스와 유사하게 PrepareHardware 콜백의 드라이버에서 수신합니다. 클라이언트는 리소스에 대한 핸들을 여는 데 사용할 수 있는 리소스 허브 ID를 받습니다.이러한 설명자는 현재 ACPI 작업 위원회의 검토를 받고 있으므로
MsftFunctionConfig()
설명자를 포함하는 ASL 파일을 컴파일하려면/MsftInternal
명령줄 스위치를asl.exe
(으)로 전달해야 합니다. 예시:asl.exe /MsftInternal dsdt.asl
핀 먹싱과 관련된 작업 시퀀스는 다음과 같습니다.
RESOURCE_HUB_CREATE_PATH_FROM_ID()
을(를) 사용하여 리소스 ID에서 경로를 만든 다음 경로에 대한 핸들을 엽니다(ZwCreateFile(), IoGetDeviceObjectPointer() 또는 WdfIoTargetOpen() 사용).RESOURCE_HUB_ID_FROM_FILE_NAME()
을(를) 사용하여 파일 경로에서 리소스 허브 ID를 추출한 다음, 리소스 허브를 쿼리하여 리소스 설명자를 가져옵니다.이 섹션은 클라이언트가 핀 먹싱 기능을 사용하는 방법에 대해 설명합니다. 프레임워크는 컨트롤러 드라이버를 대신하여 이 프로토콜을 구현하므로 이 프로토콜은 SerCx
컨트롤러 드라이버 및 SpbCx
컨트롤러 드라이버에 적용되지 않습니다.
WDF 드라이버는 EvtDevicePrepareHardware() 루틴에서 MsftFunctionConfig()
리소스를 받습니다. MsftFunctionConfig 리소스는 다음의 필드로 식별할 수 있습니다.
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 리소스를 추출할 수 있습니다.
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;
}
클라이언트가 먹싱 핀을 사용하려는 경우, MsftFunctionConfig 리소스를 예약하고 커밋합니다. 다음의 예시는 클라이언트가 MsftFunctionConfig 리소스를 예약하고 커밋하는 방법을 보여 줍니다.
_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을 컨텍스트 영역 중 하나에 저장해야 합니다. 드라이버가 먹싱 구성을 해제할 준비가 되면 WDFIOTARGET을 다시 사용하려는 경우 WdfObjectDelete()또는 WdfIoTargetClose()를 호출하여 리소스 핸들을 닫아야 합니다.
WdfObjectDelete(resourceHandle);
클라이언트가 리소스 핸들을 닫으면 핀이 초기 상태로 다시 muxed되고 다른 클라이언트에서 획득할 수 있습니다.
이 섹션은 핀 먹싱 서버가 해당 기능을 클라이언트에 노출하는 방법에 대해 설명합니다. 프레임워크는 클라이언트 드라이버를 대신하여 이 프로토콜을 구현하므로 GpioClx
미니포트 드라이버에는 적용되지 않습니다. GpioClx
클라이언트 드라이버에서 핀 먹싱을 지원하는 방법에 대해 자세히 알아보려면 GpioClx 클라이언트 드라이버에서 먹싱 지원 구현하기를 참조하세요.
클라이언트는 핀 먹싱 리소스를 예약하려는 경우 리소스에 대한 핸들을 엽니다. 핀 먹싱 서버는 리소스 허브에서 재분석 작업을 통해 IRP_MJ_CREATE 요청을 받습니다. IRP_MJ_CREATE 요청의 후행 경로 구성 요소에는 16진수 형식의 64비트 정수인 리소스 허브 ID가 포함됩니다. 서버는 reshub.h에서 RESOURCE_HUB_ID_FROM_FILE_NAME()
을(를) 사용하여 파일 이름에서 리소스 허브 ID를 추출하고 IOCTL_RH_QUERY_CONNECTION_PROPERTIES 리소스 허브로 보내 MsftFunctionConfig()
설명자를 가져와야 합니다.
서버는 설명자의 유효성을 검사하고 설명자에서 공유 모드 및 핀 목록을 추출해야 합니다. 그런 다음 핀에 대한 공유 중재를 수행해야 하며, 성공하면 요청을 완료하기 전에 핀을 예약된 것으로 표시합니다.
공유 중재는 핀 목록의 각 핀에 대해 공유 중재가 성공하면 전반적으로 성공합니다. 각 핀은 다음과 같이 중재되어야 합니다.
공유 중재가 실패하면 STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE 요청을 완료해야 합니다. 공유 중재가 성공하면 요청이 STATUS_SUCCESS로 완료되어야 합니다.
수신 요청의 공유 모드는 IrpSp->Parameters.Create.ShareAccess가 아닌 MsftFunctionConfig 설명자에서 가져옵니다.
클라이언트가 핸들을 열어 MsftFunctionConfig 리소스를 성공적으로 예약한 후에는 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 보내서 서버에 실제 하드웨어 먹싱 작업을 수행하도록 요청할 수 있습니다. 서버가 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS를 받으면 핀 목록의 각 핀에 대해
그런 다음 서버는 STATUS_SUCCESS를 사용하여 요청을 완료해야 합니다.
FunctionNumber의 의미는 서버에 의해 정의되며, MsftFunctionConfig 설명자는 서버가 이 필드를 해석하는 방법에 대한 지식으로 작성된 것으로 이해됩니다.
핸들이 닫힌 경우 서버는 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS를 받을 때 있던 구성에 핀을 되돌리기 해야 하므로 서버에서 핀의 상태를 저장해야 수정할 수 있습니다.
클라이언트에 더 이상 먹싱 리소스가 필요하지 않으면, 해당 핸들은 닫힙니다. 서버가 IRP_MJ_CLOSE 요청을 받으면 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS가 수신되었을 때의 상태로 핀을 되돌리기 합니다. 클라이언트가 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS를 보내지 않은 경우 아무 작업도 필요하지 않습니다. 그런 다음 서버는 공유 중재와 관련하여 핀을 사용 가능한 것으로 표시하고 STATUS_SUCCESS 요청을 완료해야 합니다. IRP_MJ_CLOSE 처리를 IRP_MJ_CREATE 처리와 올바르게 동기화해야 합니다.
이 섹션은 클라이언트 드라이버에 먹싱 리소스를 제공하는 방법을 설명합니다. MsftFunctionConfig()
리소스가 포함된 테이블을 컴파일하려면 Microsoft ASL 컴파일러 빌드 14327 이상이 필요합니다. MsftFunctionConfig()
리소스는 핀 먹싱 클라이언트에 하드웨어 리소스로 제공됩니다. MsftFunctionConfig()
리소스는 일반적으로 핀 먹싱 변경이 필요한 드라이버(일반적으로 SPB 및 직렬 컨트롤러 드라이버)에 제공되어야 하며 SPB 및 직렬 주변 장치 드라이버의 경우 컨트롤러 드라이버에서 먹싱 구성을 처리하므로 제공될 필요가 없습니다.
MsftFunctionConfig()
ACPI 매크로는 다음과 같이 정의됩니다.
MsftFunctionConfig(Shared/Exclusive
PinPullConfig,
FunctionNumber,
ResourceSource,
ResourceSourceIndex,
ResourceConsumer/ResourceProducer,
VendorData) { Pin List }
다음의 예시는 MsftFunctionConfig() 리소스를 I2C 컨트롤러 드라이버에 제공하는 방법을 보여 줍니다.
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을 기능 4의 \_SB.GPIO0에 추가할 수 있도록 합니다.
GpioClx
에서는 기본적으로 핀 muxing을 지원합니다. GpioClx 미니포트 드라이버("GpioClx 클라이언트 드라이버"라고도 함)는 GPIO 컨트롤러 하드웨어를 구동합니다. Windows 10 빌드 14327을 기준으로 GpioClx 미니포트 드라이버는 두 개의 새 DDI를 구현하여 핀 muxing에 대한 지원을 추가할 수 있습니다.
GpioClx
로 호출하여 지정된 muxing 구성을 적용하도록 미니포트 드라이버에 명령합니다.GpioClx
로 호출하여 muxing 구성을 되돌리도록 미니포트 드라이버에 명령합니다.이러한 루틴에 대한 설명은 GpioClx 이벤트 콜백 함수를 참조하세요.
이러한 두 가지 새로운 DDI 외에도 핀 muxing 호환성을 위해 기존의 DDI를 감사해야 합니다.
예를 들어 핀의 기본 muxing 구성이 UART이고 핀을 GPIO로 사용할 수도 있다고 가정합니다. gpIO용 핀을 연결하기 위해 CLIENT_ConnectIoPins가 호출되면 GPIO에 핀을 mux하고 CLIENT_DisconnectIoPins 핀을 UART에 다시 mux해야 합니다. 일반적으로 Disconnect 루틴은 Connect 루틴에 의해 완료된 작업을 실행 취소합니다.
Windows 10 빌드 14327을 기준으로, SpbCx
및 SerCx
프레임워크에는 컨트롤러 드라이버 자체에 대한 코드 변경 없이 SpbCx
및 SerCx
컨트롤러 드라이버가 muxing 클라이언트를 고정할 수 있도록 하는 핀 muxing에 대한 기본 제공 지원이 포함되어 있습니다. 더 나아가, muxing 사용 SpbCx/SerCx 컨트롤러 드라이버에 연결하는 SpbCx/SerCx 주변 장치 드라이버는 핀 muxing 작업을 트리거합니다.
다음의 다이어그램은 이러한 각 구성 요소 간의 종속성을 보여 줍니다. 여기에서 볼 수 있듯이 핀 muxing은 일반적으로 muxing을 담당하는 GPIO 드라이버에 SerCx 및 SpbCx 컨트롤러 드라이버의 종속성을 도입합니다.
디바이스 초기화 시 SpbCx
및 SerCx
프레임워크는 하드웨어 리소스로 제공된 모든 MsftFunctionConfig()
리소스를 디바이스에 구문 분석합니다. 요청 시 SpbCx/SerCx는 핀 muxing 리소스를 획득하고 해제합니다.
SpbCx
은(는) 클라이언트 드라이버의 EvtSpbTargetConnect() 콜백을 호출하기 바로 전에 해당 IRP_MJ_CREATE 처리기에 핀 muxing 구성을 적용합니다. muxing 구성을 적용할 수 없는 경우 컨트롤러 드라이버의 EvtSpbTargetConnect()
콜백이 호출되지 않습니다. 따라서 SPB 컨트롤러 드라이버는 EvtSpbTargetConnect()
이(가) 호출될 때까지 핀이 SPB 함수에 muxed된다고 가정할 수 있습니다.
SpbCx
은(는) 컨트롤러 드라이버의 EvtSpbTargetDisconnect() 콜백을 호출한 직후에 해당 IRP_MJ_CLOSE에서 핀 muxing 구성을 되돌립니다. 그 결과 주변 드라이버가 SPB 컨트롤러 드라이버에 대한 핸들을 열 때마다 핀이 SPB 함수에 muxed되고 주변 드라이버가 핸들을 닫을 때 muxed가 제거됩니다.
SerCx
은(는) 비슷하게 동작합니다. SerCx
은(는) 컨트롤러 드라이버의 EvtSerCx2FileOpen() 콜백을 호출하기 바로 전에 해당 IRP_MJ_CREATE 처리기의 모든 MsftFunctionConfig()
리소스를 획득하고, 컨트롤러 드라이버의 EvtSerCx2FileClose 콜백을 호출한 직후에 해당 IRP_MJ_CLOSE 처리기의 모든 리소스를 해제합니다.
SerCx
및 SpbCx
컨트롤러 드라이버에 대한 동적 핀 muxing의 의미는 특정 시간에 SPB/UART 함수에서 멀리 muxed되는 핀을 허용할 수 있어야 한다는 것입니다. 컨트롤러 드라이버는 EvtSpbTargetConnect()
또는 EvtSerCx2FileOpen()
이(가) 호출될 때까지 핀이 muxed되지 않는다고 가정해야 합니다. 핀은 다음 콜백 중에 SPB/UART 함수에 muxed할 필요가 없습니다. 다음은 전체 목록이 아니지만 컨트롤러 드라이버에서 구현하는 가장 일반적인 PNP 루틴을 나타냅니다.
rhproxy 테스트가 준비되면 다음과 같이 단계별 절차를 사용하는 것이 좋습니다.
SpbCx
, GpioClx
및 SerCx
컨트롤러 드라이버가 올바르게 로드 및 작동 중인지 확인하기rhproxy
이(가) 시스템에 존재하는지 확인합니다. Windows의 일부 버전 및 빌드에는 없습니다.ACPITABL.dat
을(를) 사용하여 rhproxy 노드를 컴파일 및 로드하기rhproxy
디바이스 노드가 존재하는지 확인하기rhproxy
이(가) 로드 및 시작 중인지 확인하기rhproxy는 시스템의 다른 디바이스들을 사용자 모드에 노출하기 때문에 이러한 디바이스들이 이미 작동 중인 경우에만 작동합니다. 첫 번째 단계로 이러한 디바이스들, 즉 노출하고 싶은 I2C, SPI, GPIO 컨트롤러가 이미 작동 중인지 확인합니다.
명령 프롬프트에서 실행합니다
devcon status *
출력을 살펴보고 원하는 모든 디바이스들이 시작되었는지 확인합니다. 디바이스에 문제 코드가 있는 경우 해당 디바이스가 로드되지 않는 이유를 해결해야 합니다. 초기 플랫폼 가져오기 중에 모든 디바이스를 사용하도록 설정해야 합니다. SpbCx
, GpioClx
또는 SerCx
컨트롤러 드라이버의 문제 해결 방법은 이 문서의 범위를 벗어납니다.
rhproxy
서비스가 시스템에 존재하는지 확인합니다.
reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy
reg 키가 존재하지 않으면 시스템에 rhproxy가 존재하지 않습니다. 모든 IoT Core 빌드와 Windows Enterprise 빌드 15063 이상에는 rhproxy가 존재합니다.
rhproxy ASL 노드를 작성했다면 이제는 이를 컴파일하고 로드할 차례입니다. 시스템 ACPI 테이블에 추가할 수 있는 독립 실행형 AML 파일로 rhproxy 노드를 컴파일할 수 있습니다. 또는 시스템의 ACPI 소스에 액세스할 수 있는 경우 플랫폼의 ACPI 테이블에 직접 rhproxy 노드를 삽입할 수 있습니다. 그러나 초기 가져오기 중 ACPITABL.dat
을(를) 사용하는 것이 더 쉬울 수 있습니다.
yourboard.asl이라는 파일을 만들고 DEFINITIONBlock 내에 RHPX 디바이스 노드를 배치합니다.
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
Scope (\_SB)
{
Device(RHPX)
{
...
}
}
}
WDK를 다운로드하고 C:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerify
에서 asl.exe
찾기
다음의 명령을 실행하여 ACPITABL.dat를 생성합니다.
asl.exe yourboard.asl
테스트 중인 시스템의 c:\windows\system32에 결과 ACPITABL.dat 파일을 복사합니다.
테스트 중인 시스템에서 테스트 서명 켜기:
bcdedit /set testsigning on
테스트 중인 시스템을 다시 부팅합니다. 시스템은 ACPITABL.dat 정의된 ACPI 테이블을 시스템 펌웨어 테이블에 추가합니다.
다음의 명령을 실행하여 rhproxy 디바이스 노드를 열거합니다.
devcon status *msft8000
devcon의 출력에는 디바이스의 존재 여부가 표시되어야 합니다. 디바이스 노드가 존재하지 않으면 ACPI 테이블이 시스템에 제대로 추가되지 않습니다.
다음과 같이 rhproxy의 상태를 확인합니다.
devcon status *msft8000
rhproxy가 시작된 것으로 출력에 나타나면 rhproxy가 제대로 로드 및 시작된 것입니다. 문제 코드가 없으면 조사를 해야 합니다. 몇 가지 일반적인 문제 코드는 다음과 같습니다.
CM_PROB_WAITING_ON_DEPENDENCY
- 종속 프로그램 중 하나가 로드에 실패하였기 때문에 시스템에서 rhproxy가 시작되지 않고 있습니다. 이는 곧 리소스가 유효하지 않은 ACPI 노드로 rhproxy 지점을 전달했거나 대상 디바이스가 시작되지 않고 있다는 뜻입니다. 먼저, 모든 디바이스들이 제대로 실행되고 있는지 다시 확인합니다(위의 ‘컨트롤러 드라이버 확인’ 참조). 그런 다음, ASL을 다시 확인하여 모든 리소스 경로(예시: \_SB.I2C1
)가 올바르고 DSDT의 유효한 노드를 가리키는지 확인합니다.CM_PROB_FAILED_START
- 리소스 구문 분석 문제로 인해 rhproxy가 시작하지 못했을 가능성이 높습니다. ASL을 검토해서 DSD에서 리소스 인덱스를 다시 확인하고 GPIO 리소스의 핀 번호 순서가 증가하도록 지정되었는지 확인합니다.rhproxy가 실행 중이면 사용자 모드에서 액세스가 가능한 디바이스 인터페이스가 생성된 것입니다. 몇 가지 명령줄 도구를 사용하여 디바이스를 열거하고 이들이 존재하는지 확인하게 됩니다.
https://github.com/ms-iot/samples 리포지토리를 복제하고 GpioTestTool
, I2cTestTool
, SpiTestTool
및 Mincomm
샘플을 빌드합니다. 테스트 동안 디바이스로 도구를 복사하고 다음 명령을 사용하여 디바이스를 열거합니다.
I2cTestTool.exe -list
SpiTestTool.exe -list
GpioTestTool.exe -list
MinComm.exe -list
디바이스와 식별 이름이 나열되어 보일 것입니다. 올바른 디바이스와 식별 이름이 보이지 않으면 ASL을 다시 확인합니다.
다음 단계로 명령줄 도구를 사용하여 디바이스를 열고 디바이스와 상호 작용합니다.
I2CTestTool 예시:
I2cTestTool.exe 0x55 I2C1
> write {1 2 3}
> read 3
> writeread {1 2 3} 3
SpiTestTool 예시:
SpiTestTool.exe -n SPI1
> write {1 2 3}
> read 3
GpioTestTool 예시:
GpioTestTool.exe 12
> setdrivemode output
> write 0
> write 1
> setdrivemode input
> read
> interrupt on
> interrupt off
MinComm(직렬) 예시. 실행 전 Rx를 Tx에 연결합니다.
MinComm "\\?\ACPI#FSCL0007#3#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\0000000000000006"
(type characters and see them echoed back)
다음의 샘플을 사용하여 UWP에서 디바이스의 작동 여부를 확인합니다.
하드웨어 랩 키트(HLK)를 다운로드합니다. 다음의 테스트를 사용할 수 있습니다.
HLK 관리자에서 rhproxy 디바이스 노드를 선택하면 해당 테스트가 자동으로 선택됩니다.
HLK 관리자에서 다음의 "리소스 허브 프록시 디바이스"를 선택합니다.
그런 다음 테스트 탭을 클릭하고 I2C WinRT, Gpio WinRT 및 Spi WinRT 테스트를 선택합니다.
선택 항목 실행을 클릭합니다. 각 테스트에 대한 추가 설명서는 테스트를 마우스 우클릭하고 "테스트 설명"을 클릭하여 사용할 수 있습니다.
Raspberry Pi 2 & 3 Pin 매핑도 참조하세요.
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
}
})
}
}
}
MinnowBoard Max Pin Mappings도 참조하세요.
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 }},
}
})
}
}
}
다음의 스크립트를 사용하여 Raspberry Pi에 대한 GPIO 리소스 선언을 생성할 수 있습니다.
$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;
}
학습
모듈
Troubleshoot device driver failures - Training
This module focuses on the role of device drivers and troubleshooting problems that pertain to them.
설명서
I2C WinRT 읽기 테스트(EEPROM 필요)
MITT의 I2C 컨트롤러 테스트 - Windows drivers
MITT 소프트웨어 패키지에 포함된 I2C 테스트 모듈을 사용하여 I2C 컨트롤러 및 해당 드라이버에 대한 데이터 전송을 테스트할 수 있습니다. MITT 보드는 I2C 버스에 연결된 클라이언트 디바이스 역할을 합니다.
범용 I/O(GPIO) - Windows drivers
SoC(System on a Chip) 통합 회로는 GPIO(범용 I/O) 핀을 광범위하게 사용합니다.
MITT의 SPI 테스트 - Windows drivers
MITT 소프트웨어 패키지에 포함된 SPI 테스트 모듈입니다.