Windows 10 이상에서는 사용자 모드에서 GPIO(범용 입력/출력), I2C(Inter-Integrated 회로), SPI(직렬 주변 장치 인터페이스) 및 UART(유니버설 비동기 수신기 송신기)로 직접 액세스할 수 있는 API가 제공됩니다. Raspberry Pi 2와 같은 개발 보드는 이러한 연결의 하위 집합을 노출하므로 사용자 지정 회로를 사용하여 기본 컴퓨팅 모듈을 확장하여 특정 애플리케이션을 처리할 수 있습니다. 이러한 낮은 수준의 버스는 일반적으로 헤더에 노출되는 GPIO 핀 및 버스의 하위 집합만 있는 다른 중요한 온보드 함수와 공유됩니다. 시스템 안정성을 유지하려면 사용자 모드 애플리케이션에서 수정하기에 안전한 핀과 버스를 지정해야 합니다.
이 문서에서는 ACPI(고급 구성 및 전원 인터페이스)에서 이 구성을 지정하는 방법을 설명하고 구성이 올바르게 지정되었는지 확인하는 도구를 제공합니다.
중요합니다
이 문서의 대상은 UEFI(Unified Extensible Firmware Interface) 및 ACPI 개발자입니다. ACPI, ASL(ACPI 원본 언어) 작성 및 SpbCx/GpioClx에 대해 잘 알고 있다고 가정합니다.
Windows의 저수준 버스에 대한 사용자 모드 액세스는 기존의 GpioClx 및 SpbCx 프레임워크를 통해 처리됩니다. Windows IoT Core 및 Windows Enterprise에서 사용할 수 있는 RhProxy라는 새 드라이버는 GpioClx 및 SpbCx 리소스를 사용자 모드에 노출합니다. API를 사용하도록 설정하려면 사용자 모드에 노출되어야 하는 각 GPIO 및 SPB 리소스를 사용하여 ACPI 테이블에서 rhproxy에 대한 디바이스 노드를 선언해야 합니다. 이 문서에서는 ASL 작성 및 확인을 안내합니다.
예제별 ASL
Raspberry Pi 2에서 rhproxy 디바이스 노드 선언을 살펴보겠습니다. 먼저 \_SB 범위에서 ACPI 디바이스 선언을 만듭니다.
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
}
- _HID – 하드웨어 ID입니다. 이를 공급업체별 하드웨어 ID로 설정합니다.
- _CID – 호환 ID입니다. "MSFT8000"이어야 합니다.
- _UID – 고유 ID입니다. 1로 설정합니다.
다음으로 사용자 모드에 노출되어야 하는 각 GPIO 및 SPB 리소스를 선언합니다. 리소스 인덱스가 리소스와 속성을 연결하는 데 사용되므로 리소스가 선언되는 순서가 중요합니다. 노출되는 I2C 또는 SPI 버스가 여러 개 있는 경우 첫 번째 선언된 버스는 해당 유형의 '기본' 버스로 간주되며 Windows.Devices.I2c.I2cController
SPI
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 }},
이렇게 하면 "SPI0"이라는 이름의 버스가 만들어지고, 두 개의 칩 선택선이 있는 리소스 인덱스 0과 1이 생성됩니다. 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 설명자의 다음 필드는 고정되어 있습니다.
- 장치 선택
- 장치 선택 극성
- WireMode
- 슬레이브 모드
- 자원소스
다음 필드는 런타임에 사용자가 지정한 값에 대한 자리 표시자입니다.
- 데이터 비트 길이
- 연결 속도
- 클럭 극성
- ClockPhase
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와 연결됩니다.
SPI 드라이버 요구 사항
-
SpbCx사용하거나 SpbCx와 호환되어야 합니다. - MITT SPI 테스트 통과해야 합니다.
- 4Mhz 클록 속도를 지원해야 합니다.
- 8비트 데이터 길이를 지원해야 합니다.
- 모든 SPI 모드(0, 1, 2, 3)를 지원해야 합니다.
I2C
다음으로, 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 }},
리소스 인덱스 3을 참조하는 "I2C1"이라는 이름의 I2C 버스를 선언하며, 이 인덱스는 위에서 선언한 I2CSerialBus() 리소스의 인덱스입니다.
I2CSerialBus() 설명자의 다음 필드가 수정되었습니다.
- 슬레이브 모드
- 자원소스
다음 필드는 런타임에 사용자가 지정한 값의 자리 표시자입니다.
- 슬레이브어드레스
- 연결 속도
- 어드레싱 모드
I2C 드라이버 요구 사항
- SpbCx를 사용하거나 SpbCx 호환이어야 합니다.
- 반드시 MITT I2C 테스트을 통과해야 합니다.
- 7비트 주소 지정을 지원해야 합니다.
- 100kHz 클록 속도를 지원해야 합니다.
- 400kHz 클록 속도를 지원해야 합니다.
GPIO
다음으로, 사용자 모드에 노출되는 모든 GPIO 핀을 선언합니다. 노출할 핀을 결정하는 다음 지침을 제공합니다.
- 노출된 헤더에서 모든 핀을 선언합니다.
- 단추 및 LED와 같은 유용한 온보드 함수에 연결된 핀을 선언합니다.
- 시스템 함수용으로 예약되거나 아무것도 연결되지 않은 핀을 선언하지 마세요.
다음 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 핀을 선언할 때 다음 요구 사항을 준수해야 합니다.
- 메모리 매핑된 GPIO 컨트롤러만 지원됩니다. I2C/SPI를 통해 인터페이스되는 GPIO 컨트롤러는 지원되지 않습니다. 컨트롤러 드라이버가 CLIENT_QueryControllerBasicInformation 콜백에 대한 응답으로 CLIENT_CONTROLLER_BASIC_INFORMATION 구조에서 MemoryMappedController 플래그를 설정하는 경우, 그것은 메모리 매핑된 컨트롤러입니다.
- 각 핀에는 GpioIO 및 GpioInt 리소스가 모두 필요합니다. GpioInt 리소스는 GpioIO 리소스 바로 뒤에 있어야 하며 동일한 핀 번호를 참조해야 합니다.
- GPIO 리소스는 핀 번호를 늘려 정렬해야 합니다.
- 각 GpioIO 및 GpioInt 리소스는 핀 목록에 정확히 하나의 핀 번호를 포함해야 합니다.
- 두 설명자의 ShareType 필드는 모두 공유되어야 합니다.
- GpioInt 설명자의 EdgeLevel 필드는 Edge여야 합니다.
- GpioInt 설명자의 ActiveLevel 필드는 ActiveBoth여야 합니다.
- PinConfig 필드
- GpioIO 및 GpioInt 설명자 모두에서 동일해야 합니다.
- PullUp, PullDown 또는 PullNone 중 하나여야 합니다. PullDefault일 수 없습니다.
- 끌어오기 구성은 핀의 전원 켜기 상태와 일치해야 합니다. 전원 켜기 상태에서 지정된 끌어오기 모드로 핀을 배치해도 핀의 상태가 변경되지 않아야 합니다. 예를 들어 데이터시트에서 핀에 풀업이 제공되도록 지정하는 경우 PinConfig를 PullUp으로 지정합니다.
펌웨어, UEFI 및 드라이버 초기화 코드는 부팅 중에 핀의 상태를 전원 켜기 상태에서 변경해서는 안 됩니다. 사용자만 핀에 연결된 항목 및 따라서 어떤 상태 전환이 안전한지 알고 있습니다. 사용자가 핀과 올바르게 인터페이스하는 하드웨어를 디자인할 수 있도록 각 핀의 전원 켜기 상태를 문서화해야 합니다. 부팅하는 동안 핀이 예기치 않게 상태를 변경해서는 안됩니다.
지원되는 드라이브 모드
GPIO 컨트롤러가 높은 임피댄스 입력 및 CMOS 출력 외에도 기본 제공 풀업 및 풀다운 저항기를 지원하는 경우 선택적 SupportedDriveModes 속성으로 이를 지정해야 합니다.
Package (2) { “GPIO-SupportedDriveModes”, 0xf },
SupportedDriveModes 속성은 GPIO 컨트롤러에서 지원되는 드라이브 모드를 나타냅니다. 위의 예제에서는 다음 드라이브 모드가 모두 지원됩니다. 속성은 다음 값의 비트 마스크입니다.
| 플래그 값 | 드라이브 모드 | 설명 |
|---|---|---|
| 0x1 | 입력 고임피던스 | 핀은 ACPI의 "PullNone" 값에 해당하는 높은 임피던스 입력을 지원합니다. |
| 0x2 | InputPullUp (인풋풀업) | 핀은 ACPI의 "PullUp" 값에 해당하는 기본 제공 풀업 저항기를 지원합니다. |
| 0x4 | 입력 드롭다운 | 핀은 ACPI의 "PullDown" 값에 해당하는 내장된 풀다운 저항기를 지원합니다. |
| 0x8 | OutputCmos | 핀은 오픈 드레인과는 달리 강한 신호를 출력할 수 있는 높은 상태와 낮은 상태를 모두 지원합니다. |
InputHighImpedance 및 OutputCmos는 거의 모든 GPIO 컨트롤러에서 지원됩니다. SupportedDriveModes 속성을 지정하지 않으면 기본값입니다.
GPIO 신호가 외부 헤더에 도달하기 전에 레벨 시프터를 통과하는 경우, 외부 헤더에서 드라이브 모드를 관찰할 수 없더라도 SOC에서 지원하는 드라이브 모드를 선언해야 합니다. 예를 들어 핀이 양방향 레벨 시프터를 통과하여 핀이 저항 풀업으로 열린 드레인으로 표시되는 경우 핀이 고임피던스 입력으로 구성된 경우에도 드러난 헤더에서 고임피던스 상태를 관찰하지 않습니다. 핀이 여전히 고임피던스 입력을 지원한다고 선언해야 합니다.
핀 번호 매기기
Windows는 다음 두 개의 핀 번호 매기기 체계를 지원합니다.
- 순차 핀 번호 매기기 – 사용자에게 0, 1, 2와 같은 숫자가 표시됩니다. 노출된 핀 수까지입니다. 0은 ASL에 선언된 첫 번째 GpioIo 리소스이고, 1은 ASL에 선언된 두 번째 GpioIo 리소스입니다.
- 네이티브 핀 번호 매기기 – 사용자에게 GpioIo 설명자에 지정된 핀 번호가 표시됩니다(예: 4, 5, 12, 13, ...
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },
UseDescriptorPinNumbers 속성은 순차 핀 번호 매기기 대신 네이티브 핀 번호 매기기를 사용하도록 Windows에 지시합니다. UseDescriptorPinNumbers 속성이 지정되지 않았거나 값이 0이면 Windows는 기본적으로 순차 핀 번호 매기기로 설정됩니다.
네이티브 핀 번호 매기기를 사용하는 경우 PinCount 속성도 지정해야 합니다.
Package (2) { “GPIO-PinCount”, 54 },
PinCount 속성은 드라이버의 CLIENT_QueryControllerBasicInformation 콜백에서 GpioClx 속성을 통해 반환된 값과 일치해야 합니다.
보드에 대해 게시된 기존 설명서와 가장 호환되는 번호 매기기 체계를 선택합니다. 예를 들어 대부분의 기존 핀아웃 다이어그램은 BCM2835 핀 번호를 사용하기 때문에 Raspberry Pi는 네이티브 핀 번호 매기기를 사용합니다. MinnowBoardMax는 기존 핀아웃 다이어그램이 거의 없기 때문에 순차 핀 번호 매기기를 사용하며, 200개 이상의 핀에서 10개의 핀만 노출되므로 순차 핀 번호 매기기가 개발자 환경을 간소화합니다. 순차적 또는 네이티브 핀 번호 매기기를 사용하는 결정은 개발자의 혼란을 줄이는 것을 목표로 해야 합니다.
GPIO 드라이버 요구 사항
-
GpioClx사용해야 합니다. - SoC 내 메모리가 매핑되어야 합니다.
- 에뮬레이트된 ActiveBoth 인터럽트 처리를 사용해야 합니다.
UART
UART 드라이버가 SerCx 또는 SerCx2사용하는 경우 rhproxy를 사용하여 드라이버를 사용자 모드에 노출할 수 있습니다.
GUID_DEVINTERFACE_COMPORT 유형의 디바이스 인터페이스를 만드는 UART 드라이버는 rhproxy를 사용할 필요가 없습니다. 받은 편지함 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에서 동일한 물리적 핀으로 라우팅될 수 있습니다. mux 블록은 지정된 시간에 핀에서 활성 상태인 함수를 제어합니다. 일반적으로 펌웨어는 부팅 시 함수 할당을 설정해야 하며 이 할당은 부팅 세션을 통해 정적으로 유지됩니다. 런타임 핀 멀티플렉싱은 실행 중에 핀 기능 할당을 재구성할 수 있는 기능을 추가합니다. 사용자가 런타임에 핀의 기능을 선택할 수 있도록 하면 사용자가 보드의 핀을 신속하게 다시 구성할 수 있으므로 개발 속도가 빨라지고 하드웨어가 정적 구성보다 광범위한 애플리케이션을 지원할 수 있습니다.
사용자는 추가 코드를 작성하지 않고 GPIO, I2C, SPI 및 UART에 대한 muxing 지원을 사용합니다. 사용자가 OpenPin() 또는 FromIdAsync()를 사용하여 GPIO 또는 버스를 열면, 기본 물리 핀이 요청된 기능에 자동으로 멀티플렉싱됩니다. 핀이 다른 함수에서 이미 사용 중인 경우 OpenPin() 또는 FromIdAsync() 호출이 실패합니다. 사용자가 GpioPin, I2cDevice, SpiDevice또는 SerialDevice 개체를 삭제하여 디바이스를 닫으면 핀이 해제되어 나중에 다른 함수에 대해 열 수 있습니다.
Windows에는 GpioClx, SpbCx및 SerCx 프레임워크의 핀 muxing에 대한 내장된 지원이 포함되어 있습니다. 이러한 프레임워크는 GPIO 핀 또는 버스에 액세스할 때 핀을 올바른 함수로 자동으로 전환하기 위해 함께 작동합니다. 핀에 대한 액세스는 여러 클라이언트 간의 충돌을 방지하기 위해 중재됩니다. 이 기본 제공된 지원 외에도, 핀 멀티플렉싱에 대한 인터페이스 및 프로토콜은 범용적으로 설계되어 있으며, 추가적인 디바이스 및 시나리오를 지원하도록 확장할 수 있습니다.
이 문서에서는 먼저 핀 muxing과 관련된 기본 인터페이스 및 프로토콜에 대해 설명한 다음 GpioClx, SpbCx 및 SerCx 컨트롤러 드라이버에 핀 muxing에 대한 지원을 추가하는 방법을 설명합니다.
핀 멀티플렉싱 아키텍처
이 부분에서는 핀 멀티플렉싱과 관련된 기본 인터페이스 및 프로토콜에 대해 설명합니다. GpioClx/SpbCx/SerCx 드라이버로 핀 다중화를 지원하기 위해서는 기본 프로토콜에 대한 지식이 반드시 필요하지는 않습니다. GpioClx/SpbCx/SerCx 드라이버에서 핀 다중화 지원 방법에 대한 자세한 내용은 GpioClx 클라이언트 드라이버에서 핀 다중화 지원 구현 및 SpbCx 및 SerCx 컨트롤러 드라이버에서 다중화 지원 사용를 참조하세요.
핀 멀티플렉싱은 여러 구성 요소의 협력을 통해 수행됩니다.
- 핀 멀티플렉싱 서버 – 이는 핀 멀티플렉싱 제어 블록을 제어하는 드라이버입니다. 핀 muxing 서버는 클라이언트로부터 핀 muxing 요청을 받습니다. 이는 muxing 리소스를 예약하기 위한 요청(IRP_MJ_CREATE를 통해) 및 핀의 기능 전환 요청(*IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS를 통해)을 통해 이루어집니다. 핀 멀티플렉싱 서버는 보통 GPIO 드라이버입니다. 종종 멀티플렉싱 블록이 GPIO 블록의 일부이기 때문입니다. 멀티플렉싱 블록이 별도의 주변 장치인 경우에도 GPIO 드라이버는 멀티플렉싱 기능을 배치하기에 논리적인 위치입니다.
- 핀 멀티플렉싱 클라이언트 – 핀 멀티플렉싱을 사용하는 드라이버입니다. 핀 멀티플렉싱 클라이언트는 ACPI 펌웨어에서 핀 멀티플렉싱 리소스를 받습니다. 핀 다중화 자원은 연결 자원의 한 종류이며 자원 허브에서 관리됩니다. 핀 멀티플렉싱 클라이언트는 리소스의 핸들을 열어서 핀 멀티플렉싱 리소스를 예약합니다. 하드웨어 변경을 적용하려면 클라이언트는 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 요청을 보내어 구성을 확정해야 합니다. 클라이언트는 핸들을 닫아 핀 멀티플렉싱 리소스를 반납합니다. 이때 멀티플렉싱 구성은 기본 상태로 되돌아갑니다.
- ACPI 펌웨어 –
MsftFunctionConfig()리소스를 사용하는 muxing 구성을 지정합니다. MsftFunctionConfig 리소스는 클라이언트에서 muxing 구성이 필요한 핀을 표현합니다. MsftFunctionConfig 리소스에는 함수 번호, 끌어오기 구성 및 핀 번호 목록이 포함됩니다. MsftFunctionConfig 리소스는 핀 멀티플렉싱 클라이언트에게 하드웨어 리소스로 제공되며, 이는 GPIO 및 SPB 연결 리소스와 유사하게 PrepareHardware 콜백 함수에서 드라이버가 수신합니다. 클라이언트는 리소스에 대한 핸들을 여는 데 사용할 수 있는 리소스 허브 ID를 받습니다.
ASL 파일에
/MsftInternal설명자가 포함되어 있고, 이러한 설명자는 현재 ACPI 작업 위원회에서 검토 중이므로, 해당 파일을 컴파일하려면asl.exe에MsftFunctionConfig()명령줄 스위치를 전달해야 합니다. 예:asl.exe /MsftInternal dsdt.asl
핀 멀티플렉싱과 관련된 작업 순서는 다음과 같습니다.
- 클라이언트는 EvtDevicePrepareHardware() 콜백의 ACPI 펌웨어에서 MsftFunctionConfig 리소스를 받습니다.
- 클라이언트는
RESOURCE_HUB_CREATE_PATH_FROM_ID()리소스 허브 도우미 함수를 사용하여 리소스 ID에서 경로를 만든 다음 경로에 대한 핸들을 엽니다(ZwCreateFile(), IoGetDeviceObjectPointer()또는 WdfIoTargetOpen()). - 서버는
RESOURCE_HUB_ID_FROM_FILE_NAME()리소스 허브 도우미 함수를 사용하여 파일 경로에서 리소스 허브 ID를 추출한 다음 리소스 허브를 쿼리하여 리소스 설명자를 가져옵니다. - 서버는 설명자의 각 핀에 대해 공유 중재를 수행하며, IRP_MJ_CREATE 요청을 완료합니다.
- 클라이언트는 수신된 핸들에서 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 요청을 실행합니다.
- IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS에 대응하여, 서버는 하드웨어 기능 설정을 각 핀에서 지정된 함수를 활성화함으로써 수행합니다.
- 클라이언트는 요청된 핀 멀티플렉싱 구성에 따라 작업을 수행합니다.
- 클라이언트가 더 이상 핀을 다중화할 필요가 없으면 핸들을 닫습니다.
- 핸들이 닫히는 것에 대한 응답으로 서버는 핀을 초기 상태로 되돌려 줍니다.
핀 멀티플렉싱 클라이언트를 위한 프로토콜 설명
이 섹션에서는 클라이언트가 핀 멀티플렉싱 기능을 사용하는 방법을 설명합니다. 프레임워크는 컨트롤러 드라이버를 대신하여 이 프로토콜을 구현하므로 SerCx 및 SpbCx 컨트롤러 드라이버에는 적용되지 않습니다.
리소스 구문 분석
WDF 드라이버는 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;
}
리소스 예약 및 커밋
클라이언트가 핀을 mux하려는 경우 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을 컨텍스트 영역 중 하나에 저장해야 합니다. 드라이버가 muxing 구성을 해제할 준비가 되면, 리소스 핸들을 닫기 위해 WdfObjectDelete()를 호출하거나, WDFIOTARGET을 다시 사용할 계획이 있는 경우엔 WdfIoTargetClose()를 호출해야 합니다.
WdfObjectDelete(resourceHandle);
클라이언트가 리소스 핸들을 닫으면, 핀은 초기 상태로 다시 설정되어 다른 클라이언트가 이를 획득할 수 있게 됩니다.
핀 다중화 서버에 대한 프로토콜 설명
이 섹션에서는 핀 멀티플렉싱 서버가 그 기능을 클라이언트에 제공하는 방법을 설명합니다. 프레임워크는 클라이언트 드라이버를 대신하여 이 프로토콜을 구현하므로 GpioClx 미니포트 드라이버에는 적용되지 않습니다.
GpioClx 클라이언트 드라이버에서 핀 muxing을 지원하는 방법에 대한 자세한 내용은 GpioClx 클라이언트 드라이버muxing 지원 구현을 참조하세요.
IRP_MJ_CREATE 요청 처리
클라이언트가 핀 다중화 리소스를 예약하려는 경우, 해당 리소스에 대한 핸들을 엽니다. 핀 멀티플렉싱 서버는 리소스 허브의 재분석 작업을 통해 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상태로 요청이 완료되어야 합니다.
들어오는 요청의 공유 모드는 이 아니라 MsftFunctionConfig 설명자에서 가져와야 합니다. IrpSp>Parameters.Create.ShareAccess.
IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 요청 처리
클라이언트가 핸들을 열어 MsftFunctionConfig 리소스를 성공적으로 예약한 후에는 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 보내서 서버에 실제 하드웨어 muxing 작업을 수행하도록 요청할 수 있습니다. 서버가 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS를 받으면, 핀 목록에 있는 각 핀에 대해 적용해야 합니다.
- PNP_FUNCTION_CONFIG_DESCRIPTOR 구조체의 PinConfiguration 멤버에 지정된 끌어오기 모드를 하드웨어로 설정합니다.
- PNP_FUNCTION_CONFIG_DESCRIPTOR 구조체의 FunctionNumber 멤버가 지정한 함수로 핀의 기능을 설정합니다.
서버는 STATUS_SUCCESS사용하여 요청을 완료해야 합니다.
FunctionNumber의 의미는 서버에 의해 정의되며, MsftFunctionConfig 설명자는 서버가 이 필드를 해석하는 방법에 대한 지식으로 작성된 것으로 이해됩니다.
핸들이 닫힐 경우, 서버는 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS를 받을 때의 핀 구성으로 되돌려야 하므로, 핀을 수정하기 전에 핀의 상태를 저장해야 할 수 있습니다.
IRP_MJ_CLOSE 요청 처리
클라이언트가 더 이상 muxing 리소스를 필요로 하지 않을 때, 클라이언트는 그 핸들(handle)을 닫습니다. 서버가 IRP_MJ_CLOSE 요청을 받으면, 핀은 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 요청을 받았을 당시의 상태로 되돌려야 합니다. 클라이언트가 IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS보내지 않은 경우 아무 작업도 필요하지 않습니다. 그런 다음 서버는 공유 중재와 관련하여 핀을 사용 가능한 것으로 표시하고 STATUS_SUCCESS요청을 완료해야 합니다. IRP_MJ_CLOSE 처리를 IRP_MJ_CREATE 처리와 올바르게 동기화해야 합니다.
ACPI 테이블에 대한 작성 지침
이 섹션에서는 클라이언트 드라이버에 muxing 리소스를 제공하는 방법을 설명합니다.
MsftFunctionConfig() 리소스가 포함된 테이블을 컴파일하려면 Microsoft ASL 컴파일러 빌드 14327 이상이 필요합니다.
MsftFunctionConfig() 리소스는 핀 멀티플렉싱 클라이언트에 하드웨어 리소스로 제공됩니다.
MsftFunctionConfig() 리소스는 일반적으로 핀 muxing 변경이 필요한 SPB 및 직렬 컨트롤러 드라이버에 제공해야 하지만, 컨트롤러 드라이버가 muxing 구성을 처리하므로 SPB 및 직렬 주변 장치 드라이버에는 제공되지 않아야 합니다.
MsftFunctionConfig() ACPI 매크로는 다음과 같이 정의됩니다.
MsftFunctionConfig(Shared/Exclusive
PinPullConfig,
FunctionNumber,
ResourceSource,
ResourceSourceIndex,
ResourceConsumer/ResourceProducer,
VendorData) { Pin List }
- 공유/배타적 – 배타적인 경우, 이 핀은 한 번에 하나의 클라이언트만 사용할 수 있습니다. 공유되는 경우 여러 공유 클라이언트가 리소스를 획득할 수 있습니다. 조정되지 않은 여러 클라이언트가 변경 가능한 리소스에 액세스할 수 있도록 허용하면 데이터 경합이 발생하므로 예측할 수 없는 결과가 발생할 수 있으므로 항상 이 값을 배타로 설정합니다.
- PinPullConfig – 다음 중 하나
- PullDefault – SOC 정의 전원 켜기 기본 끌어오기 구성 사용
- PullUp – 풀업 저항기 사용
- 풀다운 – 풀다운 저항기 활성화
- PullNone – 모든 끌어오기 저항기 사용 안 함
- FunctionNumber – mux로 프로그래밍할 함수 번호입니다.
- ResourceSource – 핀 멀티플렉싱 서버의 ACPI 네임스페이스 경로
- ResourceSourceIndex – 0으로 설정
- ResourceConsumer/ResourceProducer – ResourceConsumer로 설정하십시오.
- VendorData – 핀 멀티플렉싱 서버에 의해 의미가 정의되는 선택적 이진 데이터입니다. 일반적으로 빈칸으로 남겨 두어야 합니다.
- 핀 목록 - 구성이 적용되는 핀 번호의 쉼표로 구분된 목록입니다. 핀 멀티플렉싱 서버가 GpioClx 드라이버인 경우, 이것은 GPIO 핀 번호이며, GpioIo 설명자의 핀 번호와 동일한 의미를 갖습니다.
다음 예제에서는 I2C 컨트롤러 드라이버에 MsftFunctionConfig() 리소스를 제공하는 방법을 보여 줍니다.
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 컨트롤러 드라이버가 \_SB.GPIO0 장치 노드에서 관리하는 핀 2와 3을 풀업 저항기가 활성화된 함수 4로 설정할 수 있습니다.
GpioClx 클라이언트 드라이버에서 muxing 지원 제공하기
GpioClx는 핀 다중화를 기본 지원합니다. GpioClx 미니포트 드라이버("GpioClx 클라이언트 드라이버"라고도 함)는 GPIO 컨트롤러 하드웨어를 구동합니다. Windows 10 빌드 14327부터 GpioClx 미니포트 드라이버는 두 개의 새로운 DDI를 구현하여 핀 다중화에 대한 지원을 추가할 수 있습니다.
- CLIENT_ConnectFunctionConfigPins – 미니포트 드라이버가 지정된 멀티플렉싱 구성을 적용하도록 하기 위해
GpioClx에 의해 호출됩니다. - CLIENT_DisconnectFunctionConfigPins –
GpioClx이 호출하여 미니포트 드라이버에게 muxing 구성을 되돌리도록 명령합니다.
이러한 루틴에 대한 설명은 GpioClx 이벤트 콜백 함수 참조하세요.
이 두 가지 새로운 DDI 외에도 핀 멀티플렉싱 호환성을 확인하기 위해 기존 DDI를 점검해야 합니다.
- CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt – GpioClx는 미니포트 드라이버에게 GPIO 입력 또는 출력 용도로 사용할 핀 세트를 구성하도록 명령하기 위해 CLIENT_ConnectIoPins를 호출합니다. GPIO는 MsftFunctionConfig와 함께 사용할 수 없습니다. 즉, GPIO 및 MsftFunctionConfig에 핀이 동시에 연결되지 않습니다. 핀의 기본 함수로 GPIO일 필요가 없으므로, ConnectIoPins가 호출될 때 반드시 핀이 GPIO로 전환되는 것은 아닐 수 있습니다. ConnectIoPins는 muxing 작업을 포함하여 GPIO IO에 대해 핀을 준비하는 데 필요한 모든 작업을 수행하는 데 필요합니다. 인터럽트는 GPIO 입력의 특별한 경우로 간주될 수 있으므로 CLIENT_ConnectInterrupt 비슷하게 동작해야 합니다.
- CLIENT_DisconnectIoPins/CLIENT_DisconnectInterrupt – PreserveConfiguration 플래그를 지정하지 않는 한 이러한 루틴은 CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt 호출될 때의 상태로 핀을 반환해야 합니다. 핀의 방향을 기본 상태로 되돌리는 것 외에도 미니포트는 각 핀의 muxing 상태를 _Connect 루틴이 호출되었을 때의 상태로 되돌려야 합니다.
예를 들어 핀의 기본 muxing 구성이 UART이고 핀을 GPIO로 사용할 수도 있다고 가정합니다. GPIO 핀을 연결하기 위해 CLIENT_ConnectIoPins가 호출되면 핀을 GPIO로 멀티플렉스해야 하며, CLIENT_DisconnectIoPins에서는 핀을 UART로 다시 멀티플렉스해야 합니다. 일반적으로 연결 끊기 루틴은 연결 루틴에서 수행하는 작업을 실행 취소해야 합니다.
SpbCx 및 SerCx 컨트롤러 드라이버에서 muxing 지원
Windows 10 빌드 14327 기준으로, SpbCx 및 SerCx 프레임워크에는 핀 멀티플렉싱에 대한 기본 지원이 포함되어 있어, SpbCx 및 SerCx 컨트롤러 드라이버가 코드 변경 없이 핀 멀티플렉싱 클라이언트로 작동할 수 있습니다. 확장하여, muxing 기능이 있는 SpbCx/SerCx 컨트롤러 드라이버에 연결하는 SpbCx/SerCx 주변 드라이버는 핀 muxing 활동을 트리거합니다.
다음 다이어그램에서는 이러한 각 구성 요소 간의 종속성을 보여 줍니다. 여기에서 볼 수 있듯이, 일반적으로 muxing을 담당하는 GPIO 드라이버에 SerCx 및 SpbCx 컨트롤러 드라이버가 종속되는 관계가 핀 muxing에 의해 형성됩니다.
핀 멀티플렉싱 의존성
디바이스 초기화 시, 디바이스에 하드웨어 리소스로 제공된 모든 SpbCx 리소스를 SerCx 및 MsftFunctionConfig() 프레임워크가 구문 분석합니다. SpbCx/SerCx는 요청 시 핀 멀티플렉싱 리소스를 획득하고 해제합니다.
SpbCx 클라이언트 드라이버의 EvtSpbTargetConnect() 콜백을 호출하기 직전에 IRP_MJ_CREATE 처리기에 핀 멀티플렉싱 구성을 적용합니다. muxing 구성을 적용할 수 없는 경우 컨트롤러 드라이버의 EvtSpbTargetConnect() 콜백이 호출되지 않습니다. 따라서 SPB 컨트롤러 드라이버는 EvtSpbTargetConnect()가 호출될 때까지 핀이 SPB 함수로 멀티플렉싱된다고 가정할 수 있습니다.
SpbCx는 컨트롤러 드라이버의 EvtSpbTargetDisconnect() 콜백을 호출한 직후, IRP_MJ_CLOSE 핸들러에서 핀 muxing 구성을 복원합니다. 그 결과, 주변 드라이버가 SPB 컨트롤러 드라이버에 대한 핸들을 열 때마다 핀이 SPB 기능으로 멀티플렉싱되고, 주변 드라이버가 핸들을 닫으면 멀티플렉싱이 제거됩니다.
SerCx 비슷하게 동작합니다.
SerCx 컨트롤러 드라이버의 MsftFunctionConfig() 콜백을 호출하기 직전에 IRP_MJ_CREATE 처리기에서 모든 리소스를 획득하고 컨트롤러 드라이버의 EvtSerCx2FileClose 콜백을 호출한 직후 IRP_MJ_CLOSE 처리기의 모든 리소스를 해제합니다.
SerCx 및 SpbCx 컨트롤러 드라이버에 대한 동적 핀 멀티플렉싱의 의미는 드라이버가 특정 시점에서 SPB/UART 기능에서 벗어나 다른 기능으로 멀티플렉싱될 수 있는 핀을 수용할 수 있어야 한다는 것입니다. 컨트롤러 드라이버는 EvtSpbTargetConnect() 또는 EvtSerCx2FileOpen()이 호출될 때까지 핀이 다중화되지 않는다고 가정해야 합니다. 핀은 다음 콜백 함수가 호출되는 동안 SPB/UART 기능에 멀티플렉싱될 필요가 없습니다. 다음은 전체 목록이 아니지만 컨트롤러 드라이버에서 구현하는 가장 일반적인 PNP 루틴을 나타냅니다.
- DriverEntry (드라이버 엔트리)
- EvtDriverDeviceAdd
- EvtDevicePrepareHardware/EvtDeviceReleaseHardware
- EvtDeviceD0Entry/EvtDeviceD0Exit
확인
rhproxy를 테스트할 준비가 되면 다음 단계별 절차를 사용하는 것이 좋습니다.
- 각
SpbCx,GpioClx및SerCx컨트롤러 드라이버가 올바르게 로드되고 작동하는지 확인합니다. - 시스템에
rhproxy이(가) 있는지 확인하십시오. Windows의 일부 버전 및 빌드에는 해당 버전이 없습니다. -
ACPITABL.dat사용하여 rhproxy 노드 컴파일 및 로드 -
rhproxy디바이스 노드가 있는지 확인합니다. -
rhproxy로드 및 시작 중인지 확인합니다. - 예상 디바이스가 사용자 모드에 노출되는지 확인
- 명령줄에서 각 디바이스와 상호 작용할 수 있는지 확인합니다.
- UWP 앱에서 각 디바이스와 상호 작용할 수 있는지 확인
- HLK 테스트 실행
컨트롤러 드라이버 확인
rhproxy는 시스템의 다른 디바이스를 사용자 모드에 노출하므로 해당 디바이스가 이미 작동하는 경우에만 작동합니다. 첫 번째 단계는 노출하려는 I2C, SPI, GPIO 컨트롤러와 같은 디바이스가 이미 작동하는지 확인하는 것입니다.
명령 프롬프트에서 실행합니다.
devcon status *
출력을 확인하고 관심 있는 모든 디바이스가 시작되었는지 확인합니다. 디바이스에 문제 코드가 있는 경우 해당 디바이스가 로드되지 않는 이유를 해결해야 합니다. 초기 플랫폼 설정 시 모든 디바이스가 이미 사용하도록 설정되어 있어야 했습니다.
SpbCx, GpioClx또는 SerCx 컨트롤러 드라이버 문제 해결은 이 문서의 범위를 벗어습니다.
rhproxy가 시스템에 있는지 확인합니다.
rhproxy 서비스가 시스템에 있는지 확인합니다.
reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy
reg 키가 없으면 시스템에 rhproxy가 존재하지 않습니다. Rhproxy는 IoT Core 및 Windows Enterprise 빌드 15063 이상의 모든 빌드에 있습니다.
ACPITABL.dat 사용하여 ASL 컴파일 및 로드
이제 rhproxy ASL 노드를 작성했으므로 컴파일하고 로드해야 합니다. rhproxy 노드를 시스템 ACPI 테이블에 추가할 수 있는 독립 실행형 AML 파일로 컴파일할 수 있습니다. 또는 시스템의 ACPI 원본에 액세스할 수 있는 경우 플랫폼의 ACPI 테이블에 직접 rhproxy 노드를 삽입할 수 있습니다. 그러나 초기 가져오기 중에는 ACPITABL.dat사용하는 것이 더 쉬울 수 있습니다.
yourboard.asl이라는 파일을 만들고 DEFINITIONBlock 내에 RHPX 디바이스 노드를 배치합니다.
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1) { Scope (\_SB) { Device(RHPX) { ... } } }WDK을 다운로드하고
asl.exe에서C:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerify를 찾으세요.다음 명령을 실행하여 ACPITABL.dat 생성합니다.
asl.exe yourboard.asl테스트 중인 시스템의 c:\windows\system32에 결과 ACPITABL.dat 파일을 복사합니다.
테스트 중인 시스템에서 테스트 서명 켜기:
bcdedit /set testsigning on테스트 중인 시스템을 다시 부팅합니다. 시스템은 ACPITABL.dat 정의된 ACPI 테이블을 시스템 펌웨어 테이블에 추가합니다.
rhproxy 디바이스 노드가 있는지 확인합니다.
다음 명령을 실행하여 rhproxy 디바이스 노드를 열거합니다.
devcon status *msft8000
devcon의 출력은 디바이스가 있음을 나타내야 합니다. 디바이스 노드가 없으면 ACPI 테이블이 시스템에 성공적으로 추가되지 않았습니다.
rhproxy가 로드되고 시작 중인지 확인합니다.
rhproxy의 상태를 확인합니다.
devcon status *msft8000
출력에 rhproxy가 시작되었음을 나타내는 경우 rhproxy가 로드되고 성공적으로 시작되었습니다. 문제 코드가 표시되면 조사해야 합니다. 몇 가지 일반적인 문제 코드는 다음과 같습니다.
- 문제 51 -
CM_PROB_WAITING_ON_DEPENDENCY종속성 중 하나가 로드되지 않아 시스템이 rhproxy를 시작하지 않습니다. 즉, rhproxy로 전달된 리소스가 잘못된 ACPI 노드를 가리키거나 대상 디바이스가 시작되지 않습니다. 먼저 모든 디바이스가 성공적으로 실행되고 있는지 다시 확인합니다(위의 '컨트롤러 드라이버 확인' 참조). 그런 다음 ASL을 다시 확인하고 모든 리소스 경로(예:\_SB.I2C1)가 올바른지 확인하고 DSDT의 유효한 노드를 가리킵니다. - 문제 10 -
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 앱에서 각 디바이스 확인
다음 샘플을 사용하여 디바이스가 UWP에서 작동하는지 확인합니다.
HLK 테스트 실행
하드웨어 랩 키트(HLK)을 다운로드하십시오. 다음 테스트는 사용할 수 있습니다.
- GPIO WinRT 기능 및 스트레스 테스트
- I2C WinRT 쓰기 테스트(EEPROM 필수)
- I2C WinRT 읽기 테스트 (EEPROM 필요)
- I2C WinRT 존재하지 않는 슬레이브 주소 테스트
- I2C WinRT 고급 기능 테스트(mbed LPC1768 필수)
- SPI WinRT 클럭 주파수 확인 테스트(mbed LPC1768 필수)
- SPI WinRT IO 전송 테스트 (mbed LPC1768 필수)
- SPI WinRT Stride 확인 테스트
- SPI WinRT 전송 간격 탐지 테스트(mbed LPC1768 필수)
HLK 관리자에서 rhproxy 디바이스 노드를 선택하면 해당 테스트가 자동으로 선택됩니다.
HLK 관리자에서 "리소스 허브 프록시 디바이스"를 선택합니다.
그런 다음 테스트 탭을 클릭하고 I2C WinRT, Gpio WinRT 및 Spi WinRT 테스트를 선택합니다.
선택된 항목 실행을 클릭합니다. 각 테스트에 대한 추가 설명서는 테스트를 마우스 오른쪽 단추로 클릭하고 "테스트 설명"을 클릭하여 사용할 수 있습니다.
리소스
- ACPI 5.0 사양
- Asl.exe(Microsoft ASL 컴파일러)
- Windows.Devices.Gpio
- Windows.Devices.I2c
- Windows.Devices.Spi
- Windows.Devices.SerialCommunication
- 테스트 작성 및 실행 프레임워크(TAEF)
- SpbCx
- GpioClx
- SerCx
- MITT I2C 테스트
- GpioTestTool
- I2cTestTool
- SpiTestTool
- MinComm(직렬)
- HLK(하드웨어 랩 키트)
부록
부록 A - Raspberry Pi ASL 목록
Raspberry Pi 2 및 3 핀 매핑도 참조하세요.
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
}
})
}
}
}
부록 B - MinnowBoardMax ASL 목록
MinnowBoard 최대 핀 매핑
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 }},
}
})
}
}
}
부록 C - GPIO 리소스를 생성하는 샘플 Powershell 스크립트
다음 스크립트를 사용하여 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;
}