次の方法で共有


GPIO、I2C、SPI へのユーザー モード アクセスを有効にする

Windows 10 以降では、API は、ユーザー モードから汎用入出力 (GPIO)、Inter-Integrated 回線 (I2C)、シリアル周辺機器インターフェイス (SPI)、ユニバーサル非同期レシーバー送信機 (UART) への直接アクセスを提供します。 Raspberry Pi 2 などの開発ボードでは、これらの接続のサブセットが公開されています。これにより、カスタム回線を使用してベース コンピューティング モジュールを拡張し、特定のアプリケーションに対処できます。 これらの低レベルのバスは、通常、他の重要なオンボード機能と共有され、ヘッダーに公開される GPIO ピンとバスのサブセットのみが含まれます。 システムの安定性を維持するには、ユーザー モード アプリケーションによる変更に安全なピンとバスを指定する必要があります。

このドキュメントでは、Advanced Configuration and Power Interface (ACPI) でこの構成を指定する方法について説明し、構成が正しく指定されたことを検証するためのツールを提供します。

Von Bedeutung

このドキュメントの対象ユーザーは、Unified Extensible Firmware Interface (UEFI) および ACPI 開発者です。 ACPI、ACPI ソース言語 (ASL) の作成、SpbCx/GpioClx に関する知識があるものとします。

Windows 上の低レベル のバスへのユーザー モード アクセスは、既存の GpioClxSpbCx フレームワークを通じて組み込まれます。 RhProxyと呼ばれる新しいドライバーは、Windows IoT Core と Windows Enterprise で使用でき、GpioClxSpbCx リソースをユーザー モードで公開します。 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 および windows.Devices.Spi.SpiController メソッドによって返されるインスタンスになります。

SPI

Raspberry Pi には、2 つの公開 SPI バスがあります。 SPI0 には 2 つのハードウェア チップ選択ラインがあり、SPI1 には 1 つのハードウェア チップ選択ラインがあります。 各バスのチップ選択行ごとに 1 つの SPISerialBus() リソース宣言が必要です。 次の 2 つの SPISerialBus リソース宣言は、SPI0 上の 2 つのチップ選択ライン用です。 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

ソフトウェアは、これら 2 つのリソースを同じバスに関連付ける必要があることをどのように認識していますか? バスフレンドリ名とリソース インデックスの間のマッピングは、DSD で指定されます。

Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},

これにより、"SPI0" という名前のバスが作成され、2 つのチップ選択ライン (リソース インデックス 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
  • スレーブモード
  • ResourceSource

次のフィールドは、実行時にユーザーによって指定された値のプレースホルダーです。

  • データビット長
  • 接続速度
  • クロック極性
  • クロックフェーズ

SPI1 には 1 つのチップ選択行のみが含まれるため、1 つの 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 に 1 つの 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() 記述子の次のフィールドは固定されています。

  • スレーブモード
  • ResourceSource

次のフィールドは、実行時にユーザーによって指定された値のプレースホルダーです。

  • SlaveAddress
  • 接続速度
  • アドレッシングモード

I2C ドライバーの要件

  • SpbCx を使用するか、SpbCx 互換である必要があります
  • MITT I2C テスト に合格している必要があります
  • 7 ビット アドレス指定をサポートする必要があります
  • 100kHz クロック速度をサポートする必要があります
  • 400kHz クロック速度をサポートする必要がある

GPIO

次に、ユーザー モードに公開されているすべての GPIO ピンを宣言します。 公開するピンを決定する際には、次のガイダンスを提供します。

  • 公開されているヘッダーのすべてのピンを定義します。
  • ボタンや LED などの便利なオンボード機能に接続されているピンを宣言します。
  • システム機能用に予約されているか、何にも接続されていないピンは宣言しないでください。

ASL の次のブロックでは、GPIO4 と GPIO5 の 2 つのピンが宣言されています。 簡潔にするために、他のピンはここには示されていません。 付録 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 リソースには、ピン リストにピン番号を 1 つだけ含む必要があります。
  • 両方の記述子の ShareType フィールドは Shared である必要があります
  • 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 入力プルアップ ピンは、ACPI の "プルアップ" 値に対応する組み込みのプルアップ抵抗をサポートします。
0x4 入力プルダウン ピンは、ACPI の "PullDown" 値に対応する組み込みのプルダウン抵抗をサポートします。
0x8 OutputCmos ピンは、(オープンドレインではなく)強い高値と強い安値の両方を生成することをサポートしています。

InputHighImpedance と OutputCmos は、ほぼすべての GPIO コントローラーでサポートされています。 SupportedDriveModes プロパティが指定されていない場合は、これが既定値です。

公開されたヘッダーに到達する前に GPIO 信号がレベル シフターを通過する場合は、外部ヘッダーでドライブ モードを監視できない場合でも、SOC でサポートされるドライブ モードを宣言します。 たとえば、ピンが双方向レベルシフターを通過し、抵抗プルアップでピンがオープンドレインとして表示される場合、ピンが高インピーダンス入力として構成されている場合でも、露出したヘッダーで高インピーダンス状態が観察されることはありません。 ピンが高インピーダンス入力をサポートしていることを宣言する必要があります。

ピン番号付け

Windows では、次の 2 つのピン番号付けスキームがサポートされています。

  • シーケンシャル ピン番号付け – ユーザーには 0、1、2 などの番号が、露出しているピンの数まで順に表示されます。 0 は ASL で宣言された最初の GpioIo リソース、1 は ASL で宣言された 2 番目の 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 プロパティから返される値と一致する必要があります。

ボードの既存の発行済みドキュメントと最も互換性のある番号付けスキームを選択します。 たとえば、Raspberry Pi では、既存のピン配置図の多くがBCM2835ピン番号を使用するため、ネイティブピン番号が使用されます。 MinnowBoardMax では、既存のピン配置図がほとんどないため、シーケンシャル ピン番号が使用されます。また、10 個のピンのみが 200 を超えるピンから公開されるため、シーケンシャル ピンの番号付けによって開発者エクスペリエンスが簡略化されます。 シーケンシャルピン番号またはネイティブピン番号を使用する決定は、開発者の混乱を減らすことを目的とするはずです。

GPIO ドライバーの要件

  • GpioClx を使用する必要があります
  • SOC 上のメモリ がマップされている必要があります
  • エミュレートされた ActiveBoth 割り込み処理を使用する必要があります

UART

UART ドライバーで SerCx または SerCx2を使用している場合は、rhproxy を使用してドライバーをユーザー モードに公開できます。 GUID_DEVINTERFACE_COMPORT タイプのデバイス インターフェイスを作成する UART ドライバーでは、rhproxy を使用する必要はありません。 受信トレイ Serial.sys ドライバーは、このようなケースの 1 つです。

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 またはバスを開くと、基になる物理ピンが要求された関数に自動的に多重化されます。 ピンが既に別の関数で使用されている場合、OpenPin() または FromIdAsync() の呼び出しは失敗します。 ユーザーが GpioPinI2cDeviceSpiDevice、または SerialDevice オブジェクトを破棄してデバイスを閉じると、ピンが解放され、後で別の機能に対して開かれます。

Windows には、GpioClxSpbCx、および SerCx フレームワークでのピンの多重化のサポートが組み込まれています。 これらのフレームワークは連携して、GPIO ピンまたはバスにアクセスしたときに、ピンを正しい機能に自動的に切り替えます。 ピンへのアクセスは、複数のクライアント間の競合を防ぐために裁定されます。 この組み込みのサポートに加えて、ピンの多重化用のインターフェイスとプロトコルは汎用であり、追加のデバイスやシナリオをサポートするように拡張できます。

このドキュメントでは、まず、ピンの多重化に関連する基になるインターフェイスとプロトコルについて説明してから、ピンの多重化のサポートを GpioClx、SpbCx、SerCx コントローラー ドライバーに追加する方法について説明します。

ピン多重化アーキテクチャ

このセクションでは、ピンの多重化に関連する基になるインターフェイスとプロトコルについて説明します。 基になるプロトコルに関する知識は、GpioClx/SpbCx/SerCx ドライバーを使用したピンの多重化をサポートするために必ずしも必要ではありません。 GpioCls/SpbCx/SerCx ドライバーでピンの多重化をサポートする方法の詳細については、「GpioClx クライアント ドライバーでのピンの多重化サポートの実装」および「SpbCx および SerCx コントローラー ドライバーでの多重化サポート」を参照してください。

ピンマルチプレクシングは、複数のコンポーネントの相互作用によって実現されます。

  • ピン多重化サーバー – これらは、ピンの多重化制御ブロックを制御するドライバーです。 ピン多重化サーバーは、(IRP_MJ_CREATEを介して) 多重化リソースを予約する要求、およびピンの機能を切り替える要求 (*IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS- 要求経由) を介して、クライアントからピンの多重化要求を受け取ります。 多重化ブロックは GPIO ブロックの一部である場合があるため、通常、ピンの多重化サーバーは GPIO ドライバーです。 多重化ブロックが別の周辺機器である場合でも、GPIO ドライバーは、多重化機能を配置するための論理的な場所です。
  • ピン多重化クライアント – これらはピン多重化を利用するドライバーです。 ピン多重化クライアントは、ACPI ファームウェアからピンの多重化リソースを受け取ります。 ピンの多重化リソースは接続リソースの一種であり、リソース ハブによって管理されます。 ピンの多重化クライアントは、リソースへのハンドルを開くことで、ピンの多重化リソースを予約します。 ハードウェアの変更を有効にするには、クライアントは IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 要求を送信して構成をコミットする必要があります。 クライアントはハンドルを閉じてピンの多重化リソースを解放します。その時点で、多重化構成は既定の状態に戻ります。
  • ACPI ファームウェア – MsftFunctionConfig() リソースを使用した多重化構成を指定します。 MsftFunctionConfig リソースは、クライアントが必要とする特定のピンおよびその多重化構成を表します。 MsftFunctionConfig リソースには、関数番号、プル構成、およびピン番号の一覧が含まれています。 MsftFunctionConfig リソースは、ピン マルチプレクサ クライアントにハードウェア リソースとして提供されます。このリソースは、GPIO および SPB 接続リソースと同様に、PrepareHardware コールバックでドライバーによって受信されます。 クライアントは、リソースへのハンドルを開くために使用できるリソース ハブ ID を受け取ります。

/MsftInternal コマンド ライン スイッチを asl.exe に渡して、MsftFunctionConfig() 記述子を含む ASL ファイルをコンパイルする必要があります。これらの記述子は現在、ACPI 作業委員会によって審査中であるためです。 例: asl.exe /MsftInternal dsdt.asl

ピンの多重化に関連する一連の操作を以下に示します。

ピン・マルチプレクシング クライアント サーバーのインタラクション

  1. クライアントは、EvtDevicePrepareHardware() コールバックで ACPI ファームウェアから MsftFunctionConfig リソースを受け取ります。
  2. クライアントは、リソース ハブ ヘルパー関数 RESOURCE_HUB_CREATE_PATH_FROM_ID() を使用してリソース ID からパスを作成し、パスへのハンドルを開きます (ZwCreateFile()IoGetDeviceObjectPointer()、または WdfIoTargetOpen()を使用)。
  3. サーバーは、RESOURCE_HUB_ID_FROM_FILE_NAME()リソース ハブ ヘルパー関数を使用してファイル パスからリソース ハブ ID を抽出し、リソース ハブにクエリを実行してリソース記述子を取得します。
  4. サーバーは、記述子内の各ピンに対して共有の判別を実行し、IRP_MJ_CREATE要求を完了します。
  5. クライアントは受信したハンドルに対し、IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS の要求を発行します。
  6. IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINSに応答して、サーバーは、指定された機能を各ピンでアクティブにすることで、ハードウェアの多重化操作を実行します。
  7. クライアントは、要求されたピンの多重化構成に依存する操作を続行します。
  8. クライアントがピンのマルチプレックスを必要としなくなったら、ハンドルをクローズします。
  9. 閉じているハンドルに応答して、サーバーはピンを初期状態に戻します。

ピンマルチプレクサクライアント向けプロトコルの説明

このセクションでは、クライアントがピンマルチプレクシング機能を利用する方法について説明します。 フレームワークはコントローラー ドライバーの代わりにこのプロトコルを実装するため、これは、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;
}

リソースの予約とコミット

クライアントは、ピンを多重化する必要がある場合、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 を格納する必要があります。 ドライバーが多重化構成を解放する準備ができたら、WdfObjectDelete()呼び出してリソース ハンドルを閉じる必要があります。WDFIOTARGET を再利用する場合は WdfIoTargetClose() を します。

    WdfObjectDelete(resourceHandle);

クライアントがリソース ハンドルを閉じると、ピンは初期状態に戻され、別のクライアントによって取得できるようになります。

ピンマルチプレクシングサーバーのプロトコル説明

このセクションでは、ピンの多重化サーバーがその機能をクライアントに公開する方法について説明します。 フレームワークはクライアント ドライバーの代わりにこのプロトコルを実装するため、これは GpioClx ミニポート ドライバーには適用されません。 GpioClx クライアント ドライバーでピンの多重化をサポートする方法の詳細については、「GpioClx クライアント ドライバーでの多重化のサポートの実装」を参照してください。

IRP_MJ_CREATE要求の処理

クライアントは、ピンの多重化リソースを予約する際、そのリソースにアクセスするためのハンドルを開きます。 ピンの多重化サーバーは、リソース ハブからの再解析操作を介して IRP_MJ_CREATE 要求を受け取ります。 IRP_MJ_CREATE 要求の末尾のパス コンポーネントには、リソース ハブ ID が含まれています。リソース ハブ ID は、16 進数形式の 64 ビット整数です。 サーバーは 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 記述子から取得する必要があることに注意してください。

IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINSに関する要求の処理

クライアントは、ハンドルを開いて MsftFunctionConfig リソースを正常に予約した後、IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS を送信して、実際のハードウェア多重化操作を実行するようにサーバーに要求できます。 サーバーが 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要求の処理

クライアントが多重化リソースを必要としなくなると、そのハンドルを閉じます。 サーバーは、IRP_MJ_CLOSE 要求を受信すると、ピンを、IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS 受信時の状態に戻す必要があります。 クライアントが IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINSを送信しなかった場合、アクションは必要ありません。 その後、サーバーは、共有調停に関してピンを使用可能としてマークし、STATUS_SUCCESSで要求を完了する必要があります。 IRP_MJ_CLOSE 処理と IRP_MJ_CREATE 処理を正しく同期してください。

ACPI テーブルの作成ガイドライン

このセクションでは、多重化リソースをクライアント ドライバーに提供する方法について説明します。 MsftFunctionConfig() リソースを含むテーブルをコンパイルするには、Microsoft ASL コンパイラ ビルド 14327 以降が必要です。 MsftFunctionConfig() リソースは、ピンマルチプレクサクライアントにハードウェアリソースとして提供されます。 MsftFunctionConfig() リソースは、ピンの多重化の変更を必要とするドライバー (通常は SPB ドライバーとシリアル コントローラー ドライバー) に提供する必要がありますが、コントローラー ドライバーは多重化構成を処理するため、SPB およびシリアル周辺機器ドライバーには提供しないでください。 MsftFunctionConfig() ACPI マクロは次のように定義されます。

  MsftFunctionConfig(Shared/Exclusive
                PinPullConfig,
                FunctionNumber,
                ResourceSource,
                ResourceSourceIndex,
                ResourceConsumer/ResourceProducer,
                VendorData) { Pin List }

  • 共有/排他 – 排他的な場合、このピンは一度に 1 つのクライアントによって取得できます。 共有されている場合、複数の共有クライアントがリソースを取得できます。 複数の調整されていないクライアントが変更可能なリソースにアクセスすることを許可すると、データ競合が発生し、予測できない結果になる可能性があるため、常にこれを排他的に設定してください。
  • PinPullConfig – 次のいずれか
    • PullDefault – SOC で定義された電源オンの既定のプル構成を使用する
    • プルアップ – プルアップ抵抗を有効にする
    • プルダウン - プルダウン抵抗を有効にする
    • PullNone – すべてのプル抵抗を無効にする
  • FunctionNumber – マルチプレクサにプログラムするファンクションナンバー。
  • ResourceSource – ピンマルチプレクササーバーのACPI名前空間パス
  • ResourceSourceIndex – これを 0 に設定します
  • ResourceConsumer/ResourceProducer – これを ResourceConsumer に設定します
  • VendorData – ピンマルチプレクササーバーによって意味が定義されている省略可能なバイナリデータ。 通常、これは空白のままにする必要があります
  • Pin List – 構成が適用されるピン番号のコンマ区切りリスト。 ピンの多重化サーバーが GpioClx ドライバーである場合、これらは GPIO ピン番号であり、GpioIo 記述子のピン番号と同じ意味を持ちます。

次の例は、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 を配置できます。ピン 2 と 3 は、デバイス ノードによって \_SB に管理されます。GPIO0 – 機能 4 でプルアップ抵抗が有効になっています。

GpioClx クライアント ドライバーでの多重化サポートの提供

GpioClx には、ピンの多重化のサポートが組み込まれています。 GpioClx ミニポート ドライバー ("GpioClx クライアント ドライバー" とも呼ばれます) は、GPIO コントローラー ハードウェアを駆動します。 Windows 10 ビルド 14327 の時点で、GpioClx ミニポート ドライバーは、2 つの新しい DDI を実装することで、ピンの多重化のサポートを追加できます。

  • CLIENT_ConnectFunctionConfigPins は、GpioClx によって呼び出され、指定された多重化構成をミニポートドライバーが適用するよう指示します。
  • CLIENT_DisconnectFunctionConfigPins – GpioClx が呼び出し、ミニポートドライバーに多重化構成を元に戻す命令を実行します。

これらのルーチンの説明については、「GpioClx イベント コールバック関数の」を参照してください。

これら 2 つの新しい DDI に加えて、ピン マルチプレクサの互換性のために既存の DDI を監査するべきです。

  • CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt – CLIENT_ConnectIoPinsは、ミニポート ドライバーに GPIO 入力または出力のセット ピンを構成するように命令するために GpioClx によって呼び出されます。 GPIO は MsftFunctionConfig と相互に排他的です。つまり、GPIO と MsftFunctionConfig に対してピンが同時に接続されることはありません。 ピンのデフォルトの機能は必ずしも GPIO である必要はないため、ConnectIoPins が呼び出された場合でも、ピンが必ずしも GPIO に多重化されるわけではありません。 ConnectIoPins は、多重化操作を含め、ピンを GPIO IO に対応させるために必要なすべての操作を実行する必要があります。 割り込みは GPIO 入力の特殊なケースと考えることができるため、CLIENT_ConnectInterrupt も同様に動作する必要があります。
  • CLIENT_DisconnectIoPins/CLIENT_DisconnectInterrupt – これらのルーチンは、PreserveConfiguration フラグが指定されていない限り、CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt が呼び出されたときの状態にピンを返す必要があります。 ピンの方向を既定の状態に戻すことに加えて、ミニポートは各ピンの多重化状態を、_Connect ルーチンが呼び出されたときの状態に戻す必要があります。

たとえば、ピンの既定の多重化構成が UART であり、ピンを GPIO としても使用できるものとします。 CLIENT_ConnectIoPinsが呼び出されてGPIOのピンを接続する場合、それをGPIOに多重化する必要があります。CLIENT_DisconnectIoPinsが呼び出される場合には、それをUARTに多重化し直す必要があります。 一般に、切断ルーチンは、Connect ルーチンによって実行される操作を元に戻す必要があります。

SpbCx および SerCx コントローラー ドライバーでのマルチプレクシングのサポート

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() コールバックを呼び出す直前に、IRP_MJ_CREATE ハンドラー内のすべての リソースを取得し、コントローラー ドライバーの EvtSerCx2FileClose コールバックを呼び出した直後に、IRP_MJ_CLOSE ハンドラー内のすべてのリソースを解放します。

SerCx および SpbCx コントローラー ドライバーの動的ピン多重化の影響は、ドライバーが特定の時点で SPB/UART 機能以外にピンが多重化されることを許容できなければならないということです。 コントローラードライバーは、EvtSpbTargetConnect() または EvtSerCx2FileOpen() が呼び出されるまでピンが多重化されないことを前提とする必要があります。 ピンは、次のコールバック中に SPB/UART 機能にマルチプレックスする必要はありません。 以下は完全な一覧ではありませんが、コントローラー ドライバーによって実装される最も一般的な PNP ルーチンを表しています。

  • ドライバーエントリ
  • EvtDriverDeviceAdd
  • EvtDevicePrepareHardware/EvtDeviceReleaseHardware
  • EvtDeviceD0Entry/EvtDeviceD0Exit

検証

rhproxy をテストする準備ができたら、次の手順を使用すると便利です。

  1. SpbCxGpioClx、および SerCx コントローラー ドライバーが正しく読み込んで動作していることを確認します
  2. rhproxy がシステムに存在することを確認します。 Windows の一部のエディションとビルドには含まれていません。
  3. ACPITABL.dat を使用して rhproxy ノードをコンパイルして読み込む
  4. rhproxy デバイス ノードが存在することを確認する
  5. rhproxy が読み込んで開始していることを確認する
  6. 想定されるデバイスがユーザー モードに公開されていることを確認する
  7. コマンド ラインから各デバイスと対話できることを確認する
  8. UWP アプリから各デバイスと対話できることを確認する
  9. HLK テストを実行する

コントローラー ドライバーを確認する

rhproxy はシステム上の他のデバイスをユーザー モードに公開するため、これらのデバイスが既に動作している場合にのみ機能します。 最初の手順では、公開する I2C、SPI、GPIO コントローラーのデバイスが既に動作していることを確認します。

コマンド プロンプトで実行します。

devcon status *

出力を確認し、対象のすべてのデバイスが開始されていることを確認します。 デバイスに問題のあるコードがある場合は、そのデバイスが読み込まれていない理由をトラブルシューティングする必要があります。 すべてのデバイスは、最初のプラットフォームの起動中に有効になっている必要があります。 SpbCxGpioClx、または 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 ソースにアクセスできる場合は、rhproxy ノードをプラットフォームの ACPI テーブルに直接挿入できます。 しかし、初期段階においては ACPITABL.datを使用する方が簡単な場合があります。

  1. yourboard.asl という名前のファイルを作成し、RHPX デバイス ノードを DefinitionBlock 内に配置します。

    DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
    {
        Scope (\_SB)
        {
            Device(RHPX)
            {
            ...
            }
        }
    }
    
  2. WDK をダウンロードし、asl.exeC:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerify を見つける

  3. 次のコマンドを実行して、ACPITABL.datを生成します。

    asl.exe yourboard.asl
    
  4. 結果のACPITABL.dat ファイルをテスト対象のシステム上の c:\windows\system32 にコピーします。

  5. テスト対象のシステムで testsigning を有効にします。

    bcdedit /set testsigning on
    
  6. テスト対象のシステムを再起動します。 システムは、ACPITABL.datで定義されている ACPI テーブルをシステム ファームウェア テーブルに追加します。

rhproxy デバイス ノードが存在することを確認する

次のコマンドを実行して、rhproxy デバイス ノードを列挙します。

devcon status *msft8000

devcon の出力は、デバイスが存在することを示す必要があります。 デバイス ノードが存在しない場合、ACPI テーブルはシステムに正常に追加されませんでした。

rhproxy が読み込んで起動していることを確認する

rhproxy の状態を確認します。

devcon status *msft8000

出力が rhproxy が開始されたことを示す場合、rhproxy は読み込まれ、正常に開始されました。 問題のあるコードが表示された場合は、調査する必要があります。 いくつかの一般的な問題コードは次のとおりです。

  • 問題 51 - CM_PROB_WAITING_ON_DEPENDENCY - 依存関係の 1 つが読み込みに失敗したため、システムが rhproxy を開始していません。 つまり、rhproxy に渡されたリソースが無効な ACPI ノードを指しているか、ターゲット デバイスが起動していません。 まず、すべてのデバイスが正常に実行されていることを再確認します (上記の「コントローラー ドライバーの確認」を参照してください)。 次に、ASL を再確認し、すべてのリソース パス (\_SB.I2C1など) が正しく、DSDT 内の有効なノードを指していることを確認します。
  • 問題 10 - CM_PROB_FAILED_START - Rhproxy を開始できませんでした。リソース解析の問題が原因である可能性が最も高いです。 ASL を確認し、DSD のリソース インデックスをもう一度確認した上で、GPIO リソースがピン番号の昇順で指定されていることを確認します。

想定されるデバイスがユーザー モードに公開されていることを確認する

rhproxy が実行されたので、ユーザー モードでアクセスできるデバイス インターフェイスが作成されているはずです。 いくつかのコマンド ライン ツールを使用して、デバイスを列挙し、デバイスが存在することを確認します。

https://github.com/ms-iot/samples リポジトリを複製し、GpioTestToolI2cTestToolSpiTestTool、および 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)をダウンロードします。 次のテストを使用できます。

HLK マネージャーで rhproxy デバイス ノードを選択すると、該当するテストが自動的に選択されます。

HLK マネージャーで、[リソース ハブ プロキシ デバイス] を選択します。

[リソース ハブ プロキシ デバイス] オプションが選択された [選択] タブを示す Windows Hardware Lab Kit のスクリーンショット。

次に、[テスト] タブをクリックし、I2C WinRT、Gpio WinRT、Spi WinRT テストを選択します。

[テスト] タブを示す Windows ハードウェア ラボ キットのスクリーンショット。[G P I O Win R T 機能テストとストレス テスト] オプションが選択されています。

[選択済みを実行] をクリックします。 各テストの詳細なドキュメントは、テストを右クリックして [テストの説明] をクリックすることで入手できます。

リソース

付録

付録 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 Maxのピンマッピング も参照してください。

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