UMDF ベースのドライバーでのデータ バッファーへのアクセス
ドライバーが、読み取り、書き込み、デバイス I/O 制御のいずれかの要求を受け取るとき、要求オブジェクトには、入力バッファーと出力バッファーのいずれか、またはその両方が含まれています (デバイス I/O 制御要求には、入力、出力、または入力/出力のバッファーが 2 つ用意されているものも少数あります)。
入力バッファーには、ドライバーが必要とする情報が含まれています。書き込み要求の場合、この情報は、通常、関数ドライバーがデバイスに送信する必要のあるデータです。デバイス I/O 制御要求の場合、入力バッファーには、ドライバーが実行する必要がある操作の種類を示す情報が含まれている場合があります。
出力バッファーは、ドライバーから情報を受け取ります。読み取り要求の場合、この情報は、通常、関数ドライバーがデバイスから受け取るデータです。デバイス I/O 制御要求の場合、出力バッファーは、要求の I/O 制御コードによって指定された状態などの情報を受け取る場合があります。
ドライバーが要求のデータ バッファーにアクセスするために使用する技術は、ドライバーがデバイスのデータ バッファーにアクセスする方式によって異なります。UMDF では、以下のバッファー アクセス方式がサポートされています。
Version 1.9 より前のバージョンの UMDF では、バッファー付き I/O アクセス方式のみがサポートされています。それらのバージョンの UMDF を使用する UMDF ベースのドライバーでは、読み取り、書き込み、およびデバイス I/O 制御のすべての要求に対してバッファー付き I/O 方式のみを使用できます。I/O 要求のデータ バッファーにアクセスするには、オブジェクト メソッドの IWDFIoRequest::GetInputMemory および IWDFIoRequest::GetOutputMemory を使用する必要があります。
Version 1.9 以降の UMDF では、UMDF ベースのドライバーでバッファー付き I/O と直接 I/O の 2 種類のアクセス方式を使用できるようになりました。Version 1.9 以降の UMDF 用に作成された UMDF ドライバーでは、オブジェクト メソッドの IWDFIoRequest2::RetrieveInputBuffer、IWDFIoRequest2::RetrieveInputMemory、IWDFIoRequest2::RetrieveOutputBuffer、または IWDFIoRequest2::RetrieveOutputMemory を使用してデータ バッファーにアクセスする必要があります。
3 番目のアクセス方式は、バッファー付きでも直接でもない I/O と呼ばれます。このアクセス方式は、UMDF ベースのドライバーでは使用できません。ただし、このアクセス方式の一部の I/O 要求を UMDF のバージョンでサポートされている方式に変換することはできます。
UMDF ベースのドライバーは、ほとんどの場合、バッファー付き I/O が使用されていても直接 I/O が使用されていても、同じ UMDF オブジェクト メソッドを呼び出してデータ バッファーにアクセスします。通常は、直接 I/O の方がバッファー付き I/O より高いパフォーマンスが得られます。
以降では、次の内容について説明します。
優先的に使用するバッファー アクセス方式と優先的に使用するバッファー取得モードを指定する方法
使用するバッファー方式と取得モードが UMDF で選択されるしくみ
UMDF で使用されているバッファー アクセス方式をドライバーで取得する方法
バッファー付き I/O、直接 I/O、およびバッファー付きでも直接でもない I/O の各バッファー アクセス方式を使用するためのガイドライン
優先的に使用するバッファー アクセス方式の指定
Version 1.9 以降の UMDF では、バッファー付き I/O と直接 I/O の両方のアクセス方式がサポートされています。ドライバーで、デバイスのすべての読み取り、書き込み、およびデバイス I/O 制御の要求に対して優先的に使用するアクセス方式を指定するには、IWDFDriver::CreateDevice を呼び出してデバイス オブジェクトを作成する前に、IWDFDeviceInitialize2::SetIoTypePreference を呼び出します。たとえば、ドライバーがいずれかのデバイスについて、読み取り要求と書き込み要求に対してバッファー付き I/O 方式のみを優先的に使用するように指定している場合、UMDF ドライバー ホスト プロセスは、そのデバイスのドライバーに読み取り要求および書き込み要求を送信するときに、バッファー付き I/O 方式を使用します。直接 I/O を優先的に使用するように指定している場合は、可能であれば直接 I/O が使用されます。どのような場合に UMDF で直接 I/O が使用されるかについては、「UMDF で I/O 要求のバッファー アクセス方式が選択されるしくみ」を参照してください。
ドライバーでは、サポートする各デバイスについて、バッファー付き I/O、直接 I/O、またはバッファー付きでも直接でもない I/O のどのアクセス方式を優先的に使用するかを指定できます。読み取り要求と書き込み要求に使用するアクセス方式と、デバイス I/O 制御要求に使用するアクセス方式に、別のアクセス方式を指定することもできます。優先的に使用するアクセス方式を指定しない場合は、バッファー付きアクセス方式が使用されます。
デバイス I/O 制御要求の場合、I/O 制御コード (IOCTL) でバッファー アクセス方式が指定されます (IOCTL によるアクセス方式の指定の詳細については、「I/O 制御コードの定義」(英語の可能性あり) を参照してください)。ただし、IOCTL で指定されたアクセス方式が UMDF で使用されるとは限りません。
Version 1.9 より前のバージョンの UMDF では、すべての I/O 制御要求に対して常にバッファー付きアクセス方式が使用されます。
Version 1.9 以降の UMDF では、IOCTL でバッファー付き I/O が指定された場合はバッファー付き I/O アクセス方式が使用されます。IOCTL で 直接 I/O が指定された場合は、ドライバーが IWDFDeviceInitialize2::SetIoTypePreference を呼び出して直接 I/O を優先的に使用するように指定していれば、直接 I/O が使用される可能性があります (「UMDF で I/O 要求のバッファー アクセス方式が選択されるしくみ」で説明するように、バッファー付き I/O が使用される可能性もあります)。"バッファー付きでも直接でもない I/O" 方式を指定する IOCTL が UMDF でどのようにサポートされるかについては、「UMDF ドライバーでのバッファー付きでも直接でもない I/O の使用」を参照してください。
バッファー取得モードの指定
Version 1.9 より前のバージョンの UMDF は、常に、I/O 要求を受信するとすぐに I/O 要求のバッファーを (UMDF ドライバー ホスト プロセスにコピーして) ドライバーが使用できるようにします。このバッファー取得モードを "即時取得" と呼びます。エラーが発生した場合は、失敗を表す状態値を設定してその I/O 要求を完了します。この場合、その I/O 要求はドライバーに送信されません。
Version 1.9 以降の UMDF では、即時取得と "遅延取得" の両方のバッファー取得モードがサポートされています。遅延取得モードでは、ドライバーがバッファーにアクセスしようとするまで、I/O 要求のバッファーはドライバー ホスト プロセスにコピーされません。エラーが発生した場合は、バッファー アクセス関数がドライバーにエラー状態の値を返します。
バッファー取得モードは、ドライバーで各デバイスに対して IWDFDeviceInitialize2::SetIoTypePreference を呼び出すときに指定できます。バッファー取得モードを指定する際には、次のルールに従ってください。
直接 I/O アクセス方式を指定する場合は、遅延取得モードを指定する必要があります。直接 I/O で使用できるのは遅延取得だけです。
Version 1.9 以降の UMDF を対象とするドライバーでは、バッファー付き I/O と直接 I/O のどちらのアクセス方式を選択するかに関係なく、すべての I/O 要求に対して遅延取得モードを指定する必要があります。遅延取得では、ドライバーが使用しないバッファーにはアクセスしないため、パフォーマンスが向上します。
バッファー取得モードを指定しない場合は、即時取得が使用されます。
ドライバー スタックのすべての UMDF ベース ドライバーが同じ取得モードを使用する必要があります。即時取得を指定するドライバーと遅延取得を指定するドライバーが混在している場合は、即時取得が使用されます。
UMDF で I/O 要求のバッファー アクセス方式が選択されるしくみ
ドライバーで IWDFDeviceInitialize2::SetIoTypePreference を呼び出して指定したアクセス方式が、 UMDF で使用されるとは限りません。UMDF では、使用するアクセス方式が次のルールに従って決定されます。
ドライバー スタックのすべての UMDF ベース ドライバーが、デバイスのバッファーへのアクセスに同じ方式を使用する必要があります。特定のデバイスで、バッファー付き I/O か直接 I/O を優先的に使用するドライバーと、バッファー付き I/O のみを優先的に使用するドライバーが検出された場合、すべてのドライバーに対してバッファー付き I/O が使用されます。バッファー付き I/O のみを優先的に使用するドライバーと直接 I/O のみを優先的に使用するドライバーがスタックに混在している場合は、システム イベント ログにイベントが記録されて、ドライバー スタックが開始されません。
ドライバーで IWDFDevice2::GetDeviceStackIoTypePreference を呼び出すと、UMDF がデバイスの読み取り/書き込み要求と I/O 制御要求に割り当てたバッファー アクセス方式を確認できます。
ドライバーで IWDFDeviceInitialize2::SetIoTypePreference を呼び出して直接アクセス方式を指定した場合でも、デバイスの 1 つ以上の要求に対して、パフォーマンスを向上させるためにバッファー付きアクセス方式が使用されることがあります。たとえば、直接アクセスのためにバッファーをマップするよりドライバーのバッファーにデータをコピーした方が早いような小さなバッファーに対しては、バッファー付きアクセスが使用されます。
レジストリで REG_DWORD 型の DirectTransferThreshold 値を設定して、UMDF でデバイスに対して直接 I/O が使用されるバッファー サイズの下限 (KB) を指定することもできます。たとえば、UMDF で 2 KB 未満のすべてのバッファーに対してバッファー付き I/O が使用されるようにするには、DirectTransferThreshold を "2" に設定します。DirectTransferThreshold 値は、デバイスのハードウェア キーの下の、デバイスの Device Parameters\WUDF サブキーの下にあります。通常は、このレジストリ値を指定する必要はありません。UMDF では、最適なパフォーマンスが得られる値が使用されます。
メモリ ページの境界で開始および終了するバッファー領域に対してのみ、直接 I/O が使用されます。バッファーの先頭または終端がページの境界にない場合、バッファーのその部分に対してはバッファー付き I/O が使用されます。つまり、複数の I/O 要求で構成される大きなデータ転送に対しては、バッファー付き I/O と直接 I/O の両方が使用される可能性があります。
デバイス I/O 制御要求では、I/O 制御コード (IOCTL) で直接 I/O が指定されていて、デバイスのすべての UMDF ベース ドライバーが IWDFDeviceInitialize2::SetIoTypePreference を呼び出して直接アクセス方式を指定している場合にのみ、直接 I/O が使用されます。
ドライバーは、バッファー アクセス方式に関係なく、同じ要求オブジェクト メソッドを使用してデータ バッファーにアクセスします。したがって、通常は、特定の I/O 要求に対して UMDF でバッファー付き I/O が使用されるか直接 I/O が使用されるかをドライバーで特定する必要はありません。
ドライバーで I/O 要求のアクセス方式を取得する方法
使用されるアクセス方式がわかるとデバイスとドライバーのパフォーマンスを改善できる場合もあります。そのような場合は、ドライバーで IWDFIoRequest2::GetEffectiveIoType を呼び出すことによって、I/O 要求のバッファー アクセス方式を取得できます。
たとえば、通常は直接 I/O を使用するスループットの高いデバイスがあったとします。デバイスで直接 I/O が使用されている場合、ドライバーでは、アプリケーションで指定されたパラメーターを検証前にローカル ドライバー メモリにコピーして、検証後にアプリケーションによって変更されないようにする必要があります。
しかし、バッファー付き I/O を使用するバッファーをドライバーが受け取る場合もあります。その場合、バッファー付き I/O バッファーは既にコピーされているため、アプリケーションがデータを変更することはできません。そのため、ドライバーでパラメーターを検証前にコピーする必要はありません。したがって、ドライバーで各要求のバッファー アクセス方式をチェックして、パラメーターを検証前にコピーする必要があるかどうかを確認する必要があります。
UMDF ドライバーでのバッファー付き I/O の使用
ドライバーがバッファー付き I/O を使用している場合、ドライバー ホスト プロセスは、ドライバーがアクセスできる単一の中間バッファーを作成します。
書き込み要求の場合、ドライバー ホスト プロセスは、ドライバー スタックを呼び出す前に、呼び出し元アプリケーションの入力バッファーから入力情報を転送します。ドライバーは、通常、中間バッファーから入力情報を読み取り、それをデバイスに書き込みます。
読み取り要求の場合、ドライバーは、通常、デバイスから情報を読み取り、それを中間バッファーに保存します。ドライバー ホスト プロセスは、出力情報を中間バッファーからコピーして、アプリケーションの出力バッファーに書き込みます。
バッファー付き I/O を選択する状況に関するガイドラインについては、「WDF_DEVICE_IO_TYPE」(英語の可能性あり) を参照してください。
即時バッファー取得モードを使用するドライバーは、IWDFIoRequest::GetInputMemory と IWDFIoRequest::GetOutputMemory を使用してバッファーにアクセスする必要があります。
遅延バッファー取得モードを使用するドライバーは、IWDFIoRequest2::RetrieveInputBuffer、IWDFIoRequest2::RetrieveInputMemory、IWDFIoRequest2::RetrieveOutputBuffer、または IWDFIoRequest2::RetrieveOutputMemory を呼び出してバッファーにアクセスできます。
UMDF ドライバーでの直接 I/O の使用
ドライバーが直接 I/O を使用している場合、ドライバー ホスト プロセスは、I/O 要求の送信元 (通常はユーザー モードのアプリケーション) が指定したバッファー領域にアクセスできるかどうかを検証し、そのバッファー領域を物理メモリにロックして、ドライバーがバッファー領域に直接アクセスできるようにします。
直接 I/O を選択する状況に関するガイドラインについては、「WDF_DEVICE_IO_TYPE」(英語の可能性あり) を参照してください。
ドライバーでバッファーにアクセスするには、IWDFIoRequest2::RetrieveInputBuffer、IWDFIoRequest2::RetrieveInputMemory、IWDFIoRequest2::RetrieveOutputBuffer、または IWDFIoRequest2::RetrieveOutputMemory を呼び出します。
UMDF ドライバーでのバッファー付きでも直接でもない I/O の使用
"バッファー付きでも直接でもない I/O" と呼ばれるバッファー アクセス方式 ("どちらでもない" 方式) を使用すると、ドライバーがアプリケーションの要求バッファー ポインターに直接アクセスできます。このアクセス方式は、UMDF ベースのドライバーでは使用できません。
しかし、一部のデバイス I/O 制御コード (IOCTL) の定義では、要求で "どちらでもない" 方式を使用するように指定されています。UMDF では、そのようなデバイス I/O 制御要求のバッファー アクセス方式をバッファー付き I/O または直接 I/O に変換することもできます。次の手順で設定してください。
ドライバーの INF ファイルの INF DDInstall セクションに、UmdfMethodNeitherAction ディレクティブを含めます。このディレクティブの値を設定することにより、"どちらでもない" アクセス方式を使用するデバイス I/O 制御要求をドライバーに渡すように UMDF に指定できます (そうしないと、UMDF はそれらの I/O 要求をエラー状態値を使用して完了します)。
UMDF に用意されているバッファー付き I/O 用または直接 I/O 用のオブジェクト メソッドを使用して、I/O 要求のバッファーにアクセスします。
"どちらでもない" アクセス方式を使用する IOCTL 要求をサポートするのは、UMDF でそのアクセス方式をバッファー付き I/O か直接 I/O に変換できることがわかっている場合だけにしてください。たとえば、「I/O 制御コードのバッファーの記述」(英語の可能性あり) で説明されているバッファーの指定のルールに従っていない独自の要求が IOCTL で指定されている場合は、UMDF でバッファーを変換できません。