處理IOCTL_SPB_FULL_DUPLEX要求
某些匯流排,例如 SPI,可同時在匯流排控制器與匯流排上的裝置之間進行讀取和寫入傳輸。 為了支援這些全雙工傳輸,簡單周邊匯流排 (SPB) I/O 要求介面的定義包括,IOCTL_SPB_FULL_DUPLEX I/O 控制程式碼 (IOCTL) 。 只有在硬體中實作全雙工傳輸之匯流排控制器的 SPB 控制器驅動程式應該支援 IOCTL_SPB_FULL_DUPLEX IOCTL。
如果 SPB 控制器驅動程式支援全雙工傳輸的 I/O 要求,驅動程式應該針對這些要求使用 IOCTL_SPB_FULL_DUPLEX IOCTL,並遵循本主題中提供的實作指導方針。 這些指導方針的目的是鼓勵所有支援 IOCTL_SPB_FULL_DUPLEX 要求的硬體平臺統一行為。 接著,SPB 連線周邊裝置的驅動程式可以依賴這些要求來產生類似的結果,而不論它們執行的平臺為何。
緩衝區需求
IOCTL_SPB_FULL_DUPLEX要求的格式與IOCTL_SPB_EXECUTE_SEQUENCE要求相同,但具有下列條件約束:
- 要求中的 SPB_TRANSFER_LIST 結構必須只包含兩個專案。 第一個專案描述緩衝區,其中包含要寫入裝置的資料。 第二個專案描述用來保存從裝置讀取資料的緩衝區。
- 傳輸清單中的每個 SPB_TRANSFER_LIST_ENTRY 結構都必須指定 零的 DelayInUs 值。
在全雙工傳輸期間,讀取和寫入傳輸會以一致方式啟動。 寫入資料的第一個位元組會與讀取資料的第一個位元組同時透過匯流排傳輸。
IOCTL_SPB_FULL_DUPLEX 要求中的 寫入和讀取緩衝區不需要相同長度。
如果讀取緩衝區比寫入緩衝區短,則完整雙工匯流排傳輸會繼續,直到寫入緩衝區的整個內容寫入裝置為止。 讀取緩衝區已滿之後,匯流排控制器會捨棄從裝置接收的所有額外資料,直到全雙工匯流排傳輸完成為止。
如果寫入緩衝區比讀取緩衝區短,則完整雙工匯流排傳輸會繼續,直到讀取緩衝區已滿為止。 寫入緩衝區的整個內容寫入裝置之後,匯流排控制器會將零寫入裝置,直到全雙工匯流排傳輸完成為止。
如果 IOCTL_SPB_FULL_DUPLEX 要求順利完成,SPB 控制器驅動程式會將 I/O 狀態欄塊的 Status 成員設定 為 STATUS_SUCCESS,並將 Information 成員設定為在全雙工傳輸期間所傳送的位元組總數 (位元組,加上寫入) 的位元組。 資訊成員中的計數值不應超過讀取緩衝區大小和寫入緩衝區大小的總和。
如果讀取緩衝區比寫入緩衝區短, 資訊 成員中的計數值不應包含匯流排控制器從裝置讀取的資料位元組 (,並在讀取緩衝區滿後捨棄) 。 例如,如果具有 1 位元組寫入緩衝區且 4 位元組讀取緩衝區的完整雙工傳輸順利完成,則計數值應該是 5,而不是 8。 同樣地,如果寫入緩衝區比讀取緩衝區短,計數值就不應該在寫入緩衝區清空之後包含寫入裝置的零。
參數檢查
雖然 IOCTL_SPB_EXECUTE_SEQUENCE 和 IOCTL_SPB_FULL_DUPLEX 要求具有類似的格式,但 SPB 架構延伸模組 (SpbCx) 會以不同的方式處理它們。 針對 IOCTL_SPB_EXECUTE_SEQUENCE 要求,SpbCx 會驗證要求中的參數值,並在要求原始程式的進程內容中擷取要求的緩衝區。 SpbCx 會透過驅動程式的EvtSpbControllerIoSequence回呼函式,將IOCTL_SPB_EXECUTE_SEQUENCE要求傳遞至 SPB 控制器驅動程式,此函式專用於這些要求。
相反地,SpbCx 會將 IOCTL_SPB_FULL_DUPLEX 要求視為自訂、驅動程式定義的 IOCTL 要求。 SpbCx 會透過驅動程式的EvtSpbControllerIoOther回呼函式,將IOCTL_SPB_FULL_DUPLEX要求傳遞給 SPB 控制器驅動程式,同時處理驅動程式支援的任何自訂 IOCTL 要求。 SpbCx 不會針對這些要求進行參數檢查或緩衝區擷取。 驅動程式負責處理驅動程式透過 其 EvtSpbControllerIoOther 函式接收之 IOCTL 要求可能需要的任何參數檢查或緩衝區擷取。 若要啟用緩衝區擷取,驅動程式必須在驅動程式註冊其 EvtSpbControllerIoOther函式時提供EvtIoInCallerCoNtext回呼函式。 如需詳細資訊,請參閱 使用自訂 IOCTLs 的 SPB_TRANSFER_LIST 結構。
一般而言,SPB 控制器驅動程式會驗證EvtSpbControllerIoOther函式中IOCTL_SPB_FULL_DUPLEX要求中的參數值,而不是在 EvtIoInCallerCoNtext函式中。 下列程式碼範例示範驅動程式如何實作參數檢查。 在此範例中,驅動程式會確認符合下列參數需求:
- 要求中的傳輸清單只包含兩個專案。
- 傳輸清單中的第一個專案是用於寫入緩衝區,而第二個專案則用於讀取緩衝區。
- 這兩個專案的 DelayInUs 值為零。
//
// Validate the transfer count.
//
SPB_REQUEST_PARAMETERS params;
SPB_REQUEST_PARAMETERS_INIT(¶ms);
SpbRequestGetParameters(SpbRequest, ¶ms);
if (params.SequenceTransferCount != 2)
{
//
// The full-duplex request must have
// exactly two transfer descriptors.
//
status = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// Retrieve the write and read transfer descriptors.
//
const ULONG fullDuplexWriteIndex = 0;
const ULONG fullDuplexReadIndex = 1;
SPB_TRANSFER_DESCRIPTOR writeDescriptor;
SPB_TRANSFER_DESCRIPTOR readDescriptor;
PMDL pWriteMdl;
PMDL pReadMdl;
SPB_TRANSFER_DESCRIPTOR_INIT(&writeDescriptor);
SPB_TRANSFER_DESCRIPTOR_INIT(&readDescriptor);
SpbRequestGetTransferParameters(
SpbRequest,
fullDuplexWriteIndex,
&writeDescriptor,
&pWriteMdl);
SpbRequestGetTransferParameters(
SpbRequest,
fullDuplexReadIndex,
&readDescriptor,
&pReadMdl);
//
// Validate the transfer direction of each descriptor.
//
if ((writeDescriptor.Direction != SpbTransferDirectionToDevice) ||
(readDescriptor.Direction != SpbTransferDirectionFromDevice))
{
//
// For full-duplex I/O, the direction of the first transfer
// must be SpbTransferDirectionToDevice, and the direction
// of the second must be SpbTransferDirectionFromDevice.
//
status = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// Validate the delay for each transfer descriptor.
//
if ((writeDescriptor.DelayInUs != 0) || (readDescriptor.DelayInUs != 0))
{
//
// The write and read buffers for full-duplex I/O are transferred
// simultaneously over the bus. The delay parameter in each transfer
// descriptor must be set to 0.
//
status = STATUS_INVALID_PARAMETER;
goto exit;
}
MyDriverPerformFullDuplexTransfer(
pDevice,
pRequest,
writeDescriptor,
pWriteMdl,
readDescriptor,
pReadMdl);
檢查參數值之後,上述程式碼範例會呼叫名為 MyDriverPerformFullDuplexTransfer
的驅動程式內部常式,以起始全雙工 I/O 傳輸。