GUID_DEVICE_RESET_INTERFACE_STANDARD の操作
GUID_DEVICE_RESET_INTERFACE_STANDARD インターフェイスは、正常に機能しないデバイスのリセットと復旧をファンクション ドライバーが試行するための標準的な方法を定義します。
このインターフェイスでは、次の 2 種類のデバイス リセットを使用できます。
関数レベルのデバイス リセット (FLDR)。 この場合、リセット操作は特定のデバイスに制限され、他のデバイスには表示されません。 デバイスはリセットを通じてバスに接続され続け、リセット後に有効な状態 (初期状態) に戻ります。 この種類のリセットは、システムに与える影響が最小です。
- この種類のリセットは、バス ドライバーまたは ACPI ファームウェアによって実装できます。 バス ドライバーは、バスの仕様が要件を満たすインバンド リセット メカニズムを定義する場合は、関数レベルのリセットを実装できます。 ACPI ファームウェアは、必要に応じて、バス ドライバー定義の関数レベルのリセットを独自の実装でオーバーライドできます。
プラットフォーム レベルのデバイス リセット (PLDR)。 この場合、リセット操作により、デバイスがバスにないことが報告されます。 リセット操作は、特定のデバイスと、同じ電源レールまたはリセットラインを介して接続されている他のすべてのデバイスに影響します。 この種類のリセットは、システムに与える影響が最大です。 OS は、影響を受けるすべてのデバイスのスタックを破棄して再構築し、すべてが空の状態から再起動されるようにします。
Windows 10 以降では、 HKLM\SYSTEM\CurrentControlSet\Control\Pnp
キーの下にある次のレジストリ エントリによってリセット操作が構成されます。
DeviceResetRetryInterval: リセット操作が開始されるまでの期間。 既定値は 3 秒です 最小値は 100 ミリ妙で、最大値は 30 秒 です。
DeviceResetMaximumRetries: リセット操作が試行された回数。
Note
GUID_DEVICE_RESET_INTERFACE_STANDARD インターフェイスは、Windows 10 以降で使用できます。
デバイス リセット インターフェイスの使用
関数ドライバーは、デバイスが正しく機能していないことを検出した場合は、最初に関数レベルのリセットを試みる必要があります。 関数レベルのリセットで問題が解決しない場合、ドライバーはプラットフォーム レベルのリセットを試みることができます。 ただし、プラットフォーム レベルのリセットは、最終的なオプションとしてのみ使用する必要があります。
このインターフェイスに対してクエリを実行するために、デバイス ドライバーは、ドライバー スタックへ IRP_MN_QUERY_INTERFACE IRP を送信します。 この IRP の場合、ドライバーは InterfaceType 入力パラメーターを GUID_DEVICE_RESET_INTERFACE_STANDARD に設定します。 IRP が正常に完了すると、インターフェイス出力パラメーターは、DEVICE_RESET_INTERFACE_STANDARD 構造体へのポインターです。 この構造体には、関数レベルまたはプラットフォーム レベルのリセットを要求するために使用できる DeviceReset ルーチンへのポインターが含まれています。
ファンクション ドライバーでのデバイス リセット インターフェイスのサポート
デバイス リセット インターフェイスをサポートするには、デバイス スタックが次の要件を満たしている必要があります。
ファンクション ドライバーは、IRP_MN_QUERY_REMOVE_DEVICE、IRP_MN_REMOVE_DEVICE、およびIRP_MN_SURPRISE_REMOVAL を適切に処理する必要があります。
ほとんどの場合、ドライバーが IRP_MN_QUERY_REMOVE_DEVICE を受け取ると、デバイスを安全に削除できるように成功を返す必要があります。 ただし、デバイスがメモリ バッファーへの書き込みループでスタックしている場合など、デバイスを安全に停止できない場合があります。 このような場合、ドライバーは IRP_MN_QUERY_REMOVE_DEVICE に STATUS_DEVICE_HUNG を返す必要があります。 PnP マネージャーは、IRP_MN_QUERY_REMOVE_DEVICE と IRP_MN_REMOVE_DEVICE プロセスを続行しますが、その特定のスタックは IRP_MN_REMOVE_DEVICE を受け取りません。 代わりに、デバイススタックは、デバイスがリセットされた後に IRP_MN_SURPRISE_REMOVAL を受け取ります。
これらの IRP の詳細については、以下を参照してください。
IRP_MN_QUERY_REMOVE_DEVICE 要求の処理
フィルター ドライバーでのデバイス リセット インターフェイスのサポート
フィルター ドライバーは、インターフェイスの種類が GUID_DEVICE_RESET_INTERFACE_STANDARD のIRP_MN_QUERY_INTERFACE IRP をインターセプトする可能性があります。 これにより、GUID_DEVICE_RESET_INTERFACE_STANDARD インターフェイスに引き続き委任できますが、リセット操作の前または後にデバイス固有の操作を実行できます。 または、独自のリセット操作を提供するために、バス ドライバーによって返される GUID_DEVICE_RESET_INTERFACE_STANDARD インターフェイスを独自のインターフェイスでオーバーライドすることもできます。
バス ドライバーでのデバイス リセット インターフェイスのサポート
デバイス リセット プロセスに参加するバス ドライバー (つまり、リセットを要求しているデバイスに関連付けられているバス ドライバーと、リセット要求に応答しているデバイスに関連付けられているバス ドライバー) は、次のいずれかの要件を満たす必要があります。
ホットプラグ対応である必要があります。 バス ドライバーは、通知なしにバスから取り外されたデバイスと、バスに接続されているデバイスを検出できる必要があります。
または、GUID_REENUMERATE_SELF_INTERFACE_STANDARD インターフェイスを実装する必要があります。 これにより、デバイスがバスからプルされ、再接続されるのをシミュレートします。 このインターフェイスは、組み込みのバス ドライバー (PCI や SDBUS など) でサポートされています。 そのため、リセット対象のデバイスでこれらのバスのいずれかが使用されている場合は、バス ドライバーを変更する必要はありません。
WDF ベースのバス ドライバーの場合、WDF フレームワークはドライバーの代わりにGUID_REENUMERATE_SELF_INTERFACE_STANDARD インターフェイスを登録します。 そのため、これらのドライバーにこのインターフェイスを登録する必要はありません。 バス ドライバーは、子デバイスが再列挙される前にいくつかの操作を実行する必要がある場合は、EvtChildListDeviceReenumerated コールバック ルーチンに登録し、そのルーチンで操作を実行する必要があります。 このコールバック ルーチンはすべての PDO に対して並列で呼び出される可能性があるため、ルーチン内のコードは競合状態から保護する必要がある場合があります。
ACPI ファームウェア: 関数レベルのリセット
関数レベルのデバイスのリセットをサポートするには、デバイス スコープ内で_RSTメソッドが定義されている必要があります。 このメソッドが存在する場合、そのデバイスに対する、バス ドライバーによる関数レベルのデバイス リセット (存在する場合) の実装をオーバーライドします。 _RST メソッドを実行するときは、そのデバイスのみをリセットする必要があり、他のデバイスには影響を与えてはなりません。 さらに、デバイスはバス上で接続された状態を維持する必要があります。
ACPI ファームウェア: プラットフォーム レベルのリセット
プラットフォーム レベルのデバイス リセットをサポートするには、次の 2 つのオプションがあります。
ACPI ファームウェアは、_RST メソッドを実装する PowerResource を定義できます。このリセット メソッドの影響を受けるすべてのデバイスは、デバイス スコープで定義された_PRR オブジェクトを介してこの PowerResource を参照できます。
デバイスは、_PR3 オブジェクトを宣言できます。 この場合、ACPI ドライバーは D3cold 電源循環を使用してリセットを実行し、デバイス間のリセット依存関係は、_PR3 オブジェクトから決定されます。
_PRR オブジェクトがデバイス スコープに存在する場合、ACPI ドライバーは、参照されている PowerResource の_RST メソッドを使用してリセットを実行します。 _PRR オブジェクトが定義されていないが、_PR3 オブジェクトが定義されている場合、ACPI ドライバーは D3cold 電源循環を使用してリセットを実行します。 _PRRまたは_PR3オブジェクトが定義されていない場合、デバイスはプラットフォーム レベルのリセットをサポートせず、ACPI ドライバーはプラットフォーム レベルのリセットが使用できないと報告します。
テスト システムでの ACPI ファームウェアの確認
デバイスのリセットと回復をサポートするドライバーをテストするには、次の手順に従います。 この手順では、この例の ASL ファイルを使用していることを前提としています。
DefinitionBlock("SSDT.AML", "SSDT", 0x01, "XyzOEM", "TestTabl", 0x00001000)
{
Scope(\_SB_)
{
PowerResource(PWFR, 0x5, 0x0)
{
Method(_RST, 0x0, NotSerialized) { }
// Placeholder methods as power resources need _ON, _OFF, _STA.
Method(_STA, 0x0, NotSerialized)
{
Return(0xF)
}
Method(_ON_, 0x0, NotSerialized) { }
Method(_OFF, 0x0, NotSerialized) { }
} // PowerResource()
} // Scope (\_SB_)
// Assumes WiFi device is declared under \_SB.XYZ.
Scope(\_SB_.XYZ.WIFI)
{
// Declare PWFR as WiFi reset power rail
Name(_PRR, Package(One)
{
\_SB_.PWFR
})
} // Scope (\_SB)
}
- Asl.exeなどの ASL コンパイラを使用して、テスト ASL ファイルを AML にコンパイルします。 実行可能ファイルは、Windows Driver Kit (WDK) に含まれています。
Asl <test>.asl
上記のコマンドは SSDT.aml を生成します。
SSDT.aml の名前を acpitabl.dat に変更します。
acpitabl.datをテスト システムの %systemroot%\system32 にコピーします。
テスト システムでテスト署名を有効にします。
bcdedit /set testsigning on
テスト システムを再起動します。
テーブルがロードされていることを確認します。 Windows デバッガーでは、次のコマンドを使用します。
- !acpicache
- SSDT テーブルの dt _DESCRIPTION_HEADER アドレス
0: kd> !acpicache
Dumping cached ACPI tables...
SSDT @(ffffffffffd03018) Rev: 0x1 Len: 0x000043 TableID: TestTabl
XSDT @(ffffffffffd05018) Rev: 0x1 Len: 0x000114 TableID: HSW-FFRD
...
...
0: kd> dt _DESCRIPTION_HEADER ffffffffffd03018
ACPI!_DESCRIPTION_HEADER
+0x000 Signature : 0x54445353
+0x004 Length : 0x43
+0x008 Revision : 0x1 ''
+0x009 Checksum : 0x37 '7'
+0x00a OEMID : [6] "XyzOEM"
+0x010 OEMTableID : [8] "TestTabl"
+0x018 OEMRevision : 0x1000
+0x01c CreatorID : [4] "MSFT"
+0x020 CreatorRev : 0x5000000