使用自訂 IOCTL 的SPB_TRANSFER_LIST結構
如果您的簡單周邊匯流排 (SPB) 控制器驅動程式支援一或多個自訂 I/O 控制項 (IOCTL) 要求,請使用 SPB_TRANSFER_LIST 結構來描述這些要求的讀取和寫入緩衝區。 此結構提供一致的方式來描述要求中的緩衝區,並避免與METHOD_BUFFERED I/O 作業相關聯的緩衝區複製額外負荷。
如果您的自訂 IOCTL 要求使用 SPB_TRANSFER_LIST 結構,SPB 控制器驅動程式必須呼叫 SpbRequestCaptureIoOtherTransferList 方法,以在要求來源器的處理常式內容中擷取這些緩衝區。 您的驅動程式可以呼叫 SpbRequestGetTransferParameters 方法來存取這些緩衝區。
IOCTL_SPB_FULL_DUPLEX和IOCTL_SPB_EXECUTE_SEQUENCE要求,這些要求定義為SPB I/O 要求介面的一部分,請使用SPB_TRANSFER_LIST結構來描述其讀取和寫入緩衝區。 IOCTL_SPB_FULL_DUPLEX要求的SPB_TRANSFER_LIST結構描述寫入緩衝區和讀取緩衝區 (,順序) 要求。 IOCTL_SPB_EXECUTE_SEQUENCE要求的SPB_TRANSFER_LIST結構可以描述任意序列的讀取和寫入緩衝區。
同樣地,您可以定義自訂 IOCTL,以要求其 SPB_TRANSFER_LIST 結構使用一些讀取和寫入緩衝區的組合,並在可能需要的清單中指定緩衝區的任何順序。
Kernel-Mode Driver Foundation (SPB 周邊裝置的 KMDF) 驅動程式會呼叫 WdfIoTargetSendIoctlSynchronously 之類的方法,以將 IOCTL 要求傳送至 SPB 控制器。 這個方法具有 InputBuffer 和 OutputBuffer 參數。 某些裝置類型的驅動程式可能會使用這兩個參數分別指向 IOCTL 要求的寫入緩衝區和讀取緩衝區。 不過,若要將 IOCTL 要求傳送至 SPB 控制器,SPB 周邊設備磁碟機會將 InputBuffer 參數設定為指向指向 SPB_TRANSFER_LIST 結構的記憶體描述元。 此結構描述 I/O 控制作業所需的任何讀取或寫入緩衝區。 驅動程式會將 OutputBuffer 參數設定為 Null。
同樣地,SPB 周邊裝置的 User-Mode Driver Foundation (UMDF) 驅動程式會呼叫 IWDFIoTarget::FormatRequestForIoctl 等方法來格式化 I/O 控制作業的 I/O 要求。 此方法具有 pInputMemory 和 pOutputMemory 參數。 某些裝置類型的驅動程式可能會使用這兩個參數指向 IOCTL 要求的寫入緩衝區和讀取緩衝區。 不過,若要將 IOCTL 要求傳送至 SPB 控制器,SPB 周邊設備磁碟機會將 pInputMemory 參數設定為指向包含 SPB_TRANSFER_LIST 結構的記憶體物件。 此結構描述 I/O 控制作業所需的任何讀取或寫入緩衝區。 驅動程式會將 pOutputMemory 參數設定為 Null。
參數檢查和緩衝區擷取
當 SPB 架構延伸模組 (SpbCx) 收到 IOCTL_SPB_EXECUTE_SEQUENCE 要求時,SpbCx 會呼叫驅動程式的 EvtSpbControllerIoSequence 函式 ,將此要求傳遞至 SPB 控制器驅動程式。 在此呼叫之前,SpbCx 會檢查描述要求中緩衝區 的 SPB_TRANSFER_LIST 結構。 SpbCx 會在要求來源的進程內容中擷取這些緩衝區。 (使用者模式記憶體中的緩衝區只能在配置記憶體的進程存取。) 此外,SpbCx 會檢查要求中的參數值是否有效。
當 SpbCx 收到 IOCTL_SPB_FULL_DUPLEX 要求或自訂 IOCTL 要求時,SpbCx 會藉由呼叫驅動程式的 EvtSpbControllerIoOther 回呼函式,將此要求傳遞至 SPB 控制器驅動程式。 進行此呼叫之前,SpbCx 不會驗證要求中的參數值,也不會擷取來源器內容中的要求緩衝區。 這些要求的參數檢查和緩衝區擷取是 SPB 控制器驅動程式的責任。
如果 SPB 控制器驅動程式支援 IOCTL_SPB_FULL_DUPLEX 要求,或支援針對其緩衝區使用 SPB_TRANSFER_LIST 結構的任何自訂 IOCTL 要求,驅動程式必須實作 EvtIoInCallerCoNtext 回呼 函式。 驅動程式會在呼叫 SpbControllerSetIoOtherCallback 方法時,提供此函式的指標做為輸入參數,以註冊驅動程式的 EvtSpbControllerIoOther 回呼函式。 當 SpbCx 收到 IOCTL_SPB_FULL_DUPLEX 要求或自訂 IOCTL 要求時,SpbCx 會在來源器的內容中呼叫驅動程式的 EvtIoInCallerCoNtext 函式。 如果 IOCTL 要求使用 SPB_TRANSFER_LIST 結構, EvtIoInCallerCoNtext 函式會呼叫 SpbRequestCaptureIoOtherTransferList 方法來擷取要求中的緩衝區。 EvtIoInCallerCoNtext函式也可能執行要求的一些初步處理。
下列程式碼範例顯示 SPB 控制器驅動程式所實作的 EvtIoInCallerCoNtext 函式。
VOID
EvtIoInCallerContext(
_In_ WDFDEVICE SpbController,
_In_ WDFREQUEST FxRequest
)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_REQUEST_PARAMETERS fxParams;
WDF_REQUEST_PARAMETERS_INIT(&fxParams);
WdfRequestGetParameters(FxRequest, &fxParams);
if ((fxParams.Type != WdfRequestTypeDeviceControl) &&
(fxParams.Type != WdfRequestTypeDeviceControlInternal))
{
status = STATUS_NOT_SUPPORTED;
goto exit;
}
//
// The driver should check for custom IOCTLs that it handles.
// If the IOCTL is not recognized, complete the request with a
// status of STATUS_NOT_SUPPORTED.
//
switch (fxParams.Parameters.DeviceIoControl.IoControlCode)
{
...
default:
status = STATUS_NOT_SUPPORTED;
goto exit;
}
//
// The IOCTL is recognized. Capture the buffers in the request.
//
status = SpbRequestCaptureIoOtherTransferList((SPBREQUEST)FxRequest);
//
// If the capture fails, the driver must complete the request instead
// of placing it in the SPB controller's request queue.
//
if (!NT_SUCCESS(status))
{
goto exit;
}
status = WdfDeviceEnqueueRequest(SpbController, FxRequest);
if (!NT_SUCCESS(status))
{
goto exit;
}
exit:
if (!NT_SUCCESS(status))
{
WdfRequestComplete(FxRequest, status);
}
}
在上述程式碼範例中 switch
,語句會驗證要求是否包含 SPB 控制器驅動程式可辨識的 IOCTL。 (為了簡潔起見,語句的 switch
主體不會顯示。) Next, 呼叫 SpbRequestCaptureIoOtherTransferList 方法會擷取要求中的緩衝區。 如果此呼叫成功,則會將要求新增至 SPB 控制器的 I/O 佇列。 否則,要求會以錯誤狀態碼完成。
如需顯示 EvtSpbControllerIoOther 函式的參數檢查的程式碼範例,請參閱 處理IOCTL_SPB_FULL_DUPLEX要求。