I/O 転送シーケンス
SPB フレームワーク拡張機能 (SpbCx) では、I/O 転送シーケンスがサポートされています。 I/O 転送シーケンスは、1 つのアトミック バス操作として実行されるバス転送 (読み取りおよび書き込み操作) の順序付けされたセットです。 I/O 転送シーケンス内のすべての転送は、バス上の同じターゲット デバイスにアクセスします。 シーケンスの実行中は、SPB コントローラー ドライバーが I/O 転送シーケンスが完了する前に他のデバイスの I/O 要求を受信する場合でも、バス上の他のデバイスにアクセスすることはできません。
I/O 転送シーケンスの例として、書き込み読み取り操作があり、バス書き込み操作の後にバスの読み取り操作が続きます。 クライアント周辺機器ドライバーは、この種類のシーケンスを使用して、SPB に接続された周辺機器の関数選択レジスタに書き込み、選択したデバイス関数の値を読み取る場合があります。 これら 2 つの転送の長さは異なる場合があります。 たとえば、書き込み操作では 1 バイトのデータが転送され、読み取り操作では多数のバイトのデータが転送される場合があります。
I/O 転送シーケンスの種類
クライアントは、次のいずれかの方法で I/O 転送シーケンスを開始できます。
クライアントは、IOCTL_SPB_EXECUTE_SEQUENCE I/O 制御要求でシーケンス全体を指定できます。 この要求により、SPB コントローラー ドライバーは、転送シーケンスを実行するのに使用できるハードウェア固有のパフォーマンス最適化を使用できます。 詳細については、「単一の要求シーケンス 」を参照してください。
クライアントは、IOCTL_SPB_LOCK_CONTROLLER I/O 制御要求を送信して、シーケンスの開始時にコントローラーをロックし、シーケンスが完了したときに IOCTL_SPB_UNLOCK_CONTROLLER を送信できます。 コントローラーがロックされている間、クライアントはシーケンス内の読み取りまたは書き込み操作ごとに個別の I/O 要求 (IRP_MJ_READ または IRP_MJ_WRITE) を送信します。 詳細については、「クライアント実装シーケンス」を参照してください。
可能な限り、クライアントは IOCTL_SPB_EXECUTE_SEQUENCE 要求を使用する必要があります。これは高速でエラーが発生しにくく、他のクライアントがバスからロックアウトされる時間を大幅に短縮します。 ただし、クライアントは、シーケンス内の転送の 1 つで読み取られた値を確認する必要がある場合は、シーケンス内の後の転送を開始する前に、IOCTL_SPB_LOCK_CONTROLLER 要求と IOCTL_SPB_UNLOCK_CONTROLLER 要求を使用できます。 この場合、必要以上に長く他のクライアントをバスからロックしないように注意深く設計する必要があり、不適切に設計された周辺機器ドライバーによってシステム全体のパフォーマンスが低下する可能性があります。
単一要求シーケンス
パフォーマンスを向上するには、SPB コントローラー ドライバーが EvtSpbControllerIoSequence コールバック関数を実装して、IOCTL_SPB_EXECUTE_SEQUENCE 要求を処理する必要があります。 この方法では、SPB コントローラー ドライバーの複雑さが増しますが、他のクライアントがバスからロックアウトされている間に、一連の個々の読み取りおよび書き込み操作としてクライアントが I/O 転送シーケンスを実行する必要がなくなります。
Note
EvtSpbControllerIoSequence 関数の実装を強くお勧めします。Windows 8 の要件になる可能性があります。
転送シーケンスの実装は、単純な読み取り操作または書き込み操作の実装と似ていますが、シーケンス内の個々の転送間のシーケンス操作が格納された状態を更新する必要があります。 最初の転送が完了すると、SPB コントローラー ドライバーはシーケンスの状態を更新し、シーケンス内の次の転送を選択します。 シーケンスの状態はデバイス コンテキストに格納され、EvtSpbControllerIoSequence コールバックに渡される SPBREQUEST ハンドルが含まれます。 SPB コントローラー ドライバーは、このハンドルを使用して、シーケンス内の個々の転送のバッファー、長さ、方向、および位置パラメーターを取得します。 これらのパラメーターの取得の詳細については、「SpbRequestGetTransferParameters」を参照してください。
SPB コントローラー ドライバーは、要求された IOCTL_SPB_EXECUTE_SEQUENCE 操作を実行できない場合、エラー コードで要求を完了します。 このような障害が発生した場合、クライアントは任意でバスをロックすることができ、一連の単純な I/O 要求として I/O 転送シーケンスを明示的に実行してから、バスのロックを解除できます。 詳細については、「クライアント実装シーケンス」を参照してください。
SpbCx は、周辺機器ドライバーから受け取る IOCTL_SPB_XXX 要求のパラメーター チェックを行います。 IOCTL_SPB_EXECUTE_SEQUENCE 要求の場合、SpbCx は空のシーケンスと NULL バッファー ポインター、または長さ 0 のバッファーを含むシーケンスの両方を拒否します。
SPB コントローラー ドライバーは、シーケンス内の各転送の長さがドライバーで指定された制限を超えていないか確認する必要があります。 たとえば、Windows Driver Kit (WDK) の SkeletonI2C サンプル ドライバーは、4K バイトを超える転送を指定する IOCTL_SPB_EXECUTE_SEQUENCE 要求に失敗し、この要求の状態コードが STATUS_INVALID_PARAMETER に設定されます。 IOCTL_SPB_EXECUTE_SEQUENCE 要求のシーケンス操作を開始する前に、ドライバーは操作が正常に完了できることを確認するため、シーケンス内のすべての転送のパラメーターを検証する必要があります。
SpbCx は、EvtSpbControllerIoSequence コールバックの前に EvtSpbControllerLock コールバックを置くことはなく、EvtSpbControllerIoSequence コールバックの後に EvtSpbControllerUnlock コールバックが続くこともありません。
クライアント実装シーケンス
SPB コントローラー ドライバーのクライアントは、一連の単純な読み取りと書き込みとして I/O 転送シーケンスを明示的に実行できます。 クライアントは、カーネル モード ドライバーまたはバスに接続されている周辺機器を制御するユーザー モード ドライバーのいずれかを指定できます。 シーケンス内の最初の転送の前に、クライアントはターゲット デバイスに IOCTL_SPB_LOCK_CONTROLLER 要求を送信し、シーケンス内の転送間で関連のない他のバス アクセスが発生しないようにします。 次に、クライアントは IRP_MJ_READ と IRP_MJ_WRITE を送信し、シーケンスで転送を実行します。 最後に、クライアントはロックを解放する IOCTL_SPB_UNLOCK_CONTROLLER 要求を送信します。
シーケンス内の後の転送が以前の転送に依存している場合、クライアントはこの種類の I/O 転送シーケンスを実装する必要がある場合があります。 たとえば、最初の読み取りでは、残りの読み取りまたは書き込みバイト数を示す場合があります。 ただし、このような依存関係が存在しない場合、クライアントは SPB コントローラー ドライバーに IOCTL_SPB_EXECUTE_SEQUENCE 要求を送信する必要があります。これにより、シーケンスをより効率的に実行できます。
クライアント実装シーケンスを 開始する IOCTL_SPB_LOCK_CONTROLLER 要求と 、シーケンスを終了する IOCTL_SPB_UNLOCK_CONTROLLER 要求の間で、クライアントがターゲット デバイスに送信できる I/O 要求は、IRP_MJ_READ 要求と IRP_MJ_WRITE 要求だけです。 この規則に違反した場合は、エラーになります。
SPB ロックは、読み取りと書き込みのシーケンスがアトミック バス操作として実行されよう保証することにのみ使用され、その目的のために排他的に使用する必要があります。
詳細については、「クライアント実装シーケンスの処理」を参照してください。