最佳做法:使用 URB
本主題描述用戶端驅動程式的最佳做法,以配置、建置和傳送 URB 至隨附于Windows 8的 USB 驅動程式堆疊。
Windows 8包含新的 USB 驅動程式堆疊,以支援通用序列匯流排 (USB) 3.0 裝置。 新的 USB 3.0 驅動程式堆疊會根據 USB 3.0 規格實作數個新功能。 此外,驅動程式堆疊包含其他功能,可讓用戶端驅動程式有效率地執行一般工作。 例如,新的驅動程式堆疊接受鏈結的 MDL,可讓用戶端驅動程式在實體記憶體中的不連續分頁中傳送傳輸緩衝區。
在用戶端驅動程式可以使用 USB 驅動程式堆疊的新功能進行Windows 8之前,驅動程式必須先向 Windows 針對裝置載入的基礎 USB 驅動程式堆疊註冊本身。 若要註冊用戶端驅動程式,請呼叫 USBD_CreateHandle 並指定 合約版本。 如果用戶端驅動程式是要建置、執行和使用Windows 8的改進功能和新功能,用戶端合約版本就會USBD_CLIENT_CONTRACT_VERSION_602。
針對USBD_CLIENT_CONTRACT_VERSION_602版用戶端驅動程式,USB 驅動程式堆疊會假設用戶端驅動程式符合下列規則集:
- 請勿使用過時或不正確管道控制碼來傳送 I/O 要求
- 藉由在 Windows 8 中呼叫配置常式來配置 URI
- 請勿重複使用與擱置要求相關聯的作用中 URL
- 請勿使用大於 8 的輪詢期間進行高速和 SuperSpeed 等時針傳輸
- 確定每個畫面的封包數目是多個封包數目
- 在記載的 IRQL 層級呼叫常式
- 相關主題
USB 驅動程式堆疊會對收到的要求執行驗證,並盡可能處理違規。 無法這麼做可能會導致未定義的行為。
請勿使用過時或不正確管道控制碼來傳送 I/O 要求
用戶端驅動程式 不得 使用過時管道控制碼,將 I/O 要求傳送至 USB 驅動程式堆疊。 過時管道控制碼是指在要求中取得的管道控制碼,以選取組態、介面或裝置中不再選取的替代設定。 為了避免管線控制碼過時,每次用戶端驅動程式選取設定或介面時,驅動程式必須重新整理其管道控制碼快取, (通常儲存在裝置內容) 。 某些競爭條件也會造成過時的管道控點。 例如,用戶端驅動程式會使用所選介面上的管道控制碼來傳送 I/O 要求。 在要求完成之前,用戶端驅動程式會選取不使用與使用中管道控制碼相關聯的相同端點的替代設定。 這兩個擱置的要求都可能會導致競爭條件使管道控制碼無效。
藉由在 Windows 8 中呼叫配置常式來配置 URI
Windows 8提供配置、建置及發行 USB 要求區塊的新常式, (URL) 。 若要配置 URB,Windows 驅動程式模型 (WDM) 用戶端驅動程式必須一律使用下列清單中所示的新常式:
- USBD_UrbAllocate
- USBD_IsochUrbAllocate
- USBD_SelectConfigUrbAllocateAndBuild
- USBD_SelectInterfaceUrbAllocateAndBuild
- USBD_UrbFree
- USBD_AssignUrbToIoStackLocation
上述清單中的常式可能會將不透明的 URB 內容附加至配置的 URB,以改善追蹤和處理。 用戶端驅動程式無法檢視或修改 URB 內容的內容。 如需Windows 8中 URB 配置的詳細資訊,請參閱配置和建置 URB。
如果 Windows 驅動程式架構 (WDF) 在註冊期間將其版本識別為USBD_CLIENT_CONTRACT_VERSION_602 (,請參閱 WdfUsbTargetDeviceCreateWithParameters) ,USB 驅動程式堆疊會預期用戶端驅動程式會呼叫新的 WdfUsbTargetDeviceCreateUrb來配置 URB 的記憶體。
請勿重複使用與擱置要求相關聯的作用中 URL
USB 驅動程式堆疊會刻意檢查是否偵測到與 URB 相關聯的要求之前已重新提交的作用中 URB。 只要要求擱置,且尚未呼叫用戶端驅動程式的 IRP 完成常式,URB 就會處於作用中狀態。 請勿在作用中的 URB 上執行下列工作。
- 請勿針對另一個要求重新提交使用中的 URB, (將 URB 與另一個 IRP) 產生關聯。
- 請勿修改使用中 URB 的內容。
- 請勿釋出使用中的 URB。
呼叫用戶端驅動程式完成常式之後,驅動程式可以針對完成常式內的特定要求類型重新提交 URI。 下列規則適用于重新提交:
用戶端驅動程式不得針對選取組態要求以外的任何類型的要求重複使用由 USBD_SelectConfigUrbAllocateAndBuild 配置的 URB,以選取相同的組態。
用戶端驅動程式不得針對選取介面要求以外的任何類型的要求重複使用由 USBD_SelectInterfaceUrbAllocateAndBuild 配置的 URB,以在介面中選取相同的替代設定。 For an example, see Remarks in USBD_SelectInterfaceUrbAllocateAndBuild.
由 USBD_IsochUrbAllocate 配置的 URB 必須只針對連續傳輸要求重複使用。 相反地,針對其他類型的 I/O 要求配置的 URB, (控制、大量或中斷) 不得用於連續要求。
例如,用戶端驅動程式會為大量傳輸要求配置並建置 URB 結構。 用戶端驅動程式也想要將資料傳送至裝置中的連續端點。 大量傳輸要求完成之後,用戶端驅動程式 不得 重新格式化並提交 URB 以取得不連續的要求。 這是因為與連續要求相關聯的 URB 會根據封包數目而具有可變長度。 此外,必須在框架界限上啟動和結束封包。 針對大量傳輸 (配置的 URB) 可能不符合異時傳輸所需的緩衝區配置,而且要求可能會失敗。
由 USBD_UrbAllocate 配置的 URB 不得針對時序、選取組態或選取介面要求重複使用。 您可以重複使用 URB 來選取 Null 組態,以停用裝置中的選取組態。 URB 不得為使用中,而且用戶端驅動程式必須呼叫 UsbBuildSelectConfigurationRequest 宏並在 ConfigurationDescriptor 參數中傳遞 Null,以重新格式化 URB。
重新提交 URB 之前,用戶端驅動程式必須使用針對要求類型定義的適當 UsbBuildXxx 宏重新格式化 URB。 驅動程式必須格式化 URB,因為 USB 堆疊可能已經改變其部分內容。
例如,假設驅動程式呼叫 UsbBuildInterruptOrBulkTransferRequest 來初始化 URB 以進行大量傳輸要求, (請參閱 _URB_BULK_OR_INTERRUPT_TRANSFER) 。 如果驅動程式將URB結構的TransferBufferMDL成員初始化為 Null,USB 驅動程式堆疊會使用傳輸緩衝區指定的TransferBuffer,在 中與裝置交換資料,而不是 MDL。 不過,在內部,USB 驅動程式堆疊可能會建立 MDL、將 MDL 的指標儲存在 TransferBufferMDL中,並使用 MDL 將資料向下傳遞堆疊。 即使 USB 驅動程式堆疊釋放 MDL 記憶體,當用戶端驅動程式在完成常式中處理 URB 時, TransferBufferMDL 可能不是 Null。 為了確保 URB 的成員已正確格式化,驅動程式必須針對 呼叫 UsbBuildInterruptOrBulkTransferRequest ,才能提交要求之前重新格式化 URB,
請勿使用大於 8 的輪詢期間進行高速和 SuperSpeed 等時針傳輸
USB 驅動程式堆疊支援高速和 SuperSpeed 連續管道,輪詢期間號碼為 1、2、4 或 8。 用戶端驅動程式不得將 IO 傳送至期間大於 8 的端點。 這樣做可能會導致錯誤檢查。
確定每個畫面的封包數目是多個封包數目
針對高速和 SuperSpeed 連續傳輸,每個畫面的連續封包數目會計算為 8 / 輪詢期間。 用戶端驅動程式必須確定 URB 中指定的 NumberOfPackets 值 (看到 _URB_ISOCH_TRANSFER) 是每個畫面的多個封包數目。
USB 驅動程式堆疊不支援連續傳輸 URI, 其中 NumberOfPackets 不是每個畫面的封包數目倍數。
在記載的 IRQL 層級呼叫常式
如果您將用戶端驅動程式註冊為合約版本USBD_CLIENT_CONTRACT_VERSION_602,USB 驅動程式堆疊會假設用戶端驅動程式在適當的 IRQL 層級傳送要求。 如果用戶端驅動程式在DISPATCH_LEVEL傳送要求,則應該在PASSIVE_LEVEL傳送。 收到要求時,在某些情況下,USB 驅動程式堆疊會驗證 IRQL 值,並失敗要求。 不過,在其他情況下,USB 驅動程式堆疊可能會產生錯誤檢查。