撰寫函式控制器用戶端驅動程式
本文說明函式控制器用戶端驅動程式在與UFX) (USB函數控制器擴充功能互動時執行的各種工作。
重要 API
描述函式控制器用戶端驅動程式在與UFX) (USB函式控制器擴充功能互動時執行的各種工作。 UFX 和用戶端驅動程式會使用導出方法和事件回呼函式彼此通訊。 名為 UfxDeviceXxx 或 UfxEndpointXxx) 的導出方法 (是由UFX匯出,並由客戶端驅動程式叫用。 回呼函式 (名為 EVT_UFX_Xxx) 會在用戶端驅動程式中實作,並由 UFX 叫用。
UFX 會以異步方式呼叫所有用戶端驅動程式的回呼函式,以及每個物件一次一個回呼。 例如,有一個USB裝置物件和三個端點物件。 最多四個回呼函式 (一個用於裝置,一次呼叫每個端點) 一個。 針對每個回呼方法,UFX 會等到用戶端驅動程式呼叫 UfxDeviceEventComplete ,以指出驅動程式已完成要求。 UFX 在等候這些導出時唯一接聽的其他導出方法是 UfxDeviceNotifyHardwareFailure。 許多用戶端回呼函式都是選擇性的。 必要的函式如下所示:
- EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD
- EVT_UFX_DEVICE_ENDPOINT_ADD
- EVT_UFX_DEVICE_HOST_CONNECT
- EVT_UFX_DEVICE_HOST_DISCONNECT
- EVT_UFX_DEVICE_ADDRESSED
初始化
- 當 Windows Driver Foundation (WDF) 叫用用戶端驅動程式的 EVT_WDF_DRIVER_DEVICE_ADD 回呼實作時,函式控制器客戶端驅動程式會啟動初始化程式。 在該實作中,用戶端驅動程序應該呼叫 UfxFdoInit ,然後藉由呼叫 WdfDeviceCreate來建立裝置物件。
- 用戶端驅動程式會呼叫 UfxDeviceCreate 來建立USB裝置物件,並擷取UFXDEVICE句柄。
- 用戶端驅動程式會呼叫 UfxDeviceNotifyHardwareReady ,向UFX指出它現在可以叫用客戶端驅動程式的回呼函式。
- UFX 會執行初始化工作,例如:
- UFX 會呼叫用戶端驅動程式 EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD 實作,以建立預設端點。
- UFX 會針對裝置支援的介面, (PDO) 建立子實體裝置物件。
- UFX 會在傳送 IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS 要求時等候裝置類別驅動程序啟用。 它也會等候客戶端驅動程式呼叫指出裝置已連結的 UfxDeviceNotifyAttach 。
類別驅動程式通知
若要收到設定封包和總線狀態的通知,類別驅動程式應該傳送 IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS 要求。 UFX 會將這些要求排入類別驅動程式特定的通知佇列。 從客戶端驅動程式收到有關總線事件的通知時,UFX 會從每個適當的佇列快顯並完成要求。 為了避免類別驅動程式遺漏通知,UFX 會保留類別驅動程式的固定大小通知佇列。
裝置連結和中斷連結事件
UFX 假設裝置中斷連結,直到函式控制器用戶端驅動程式呼叫 UfxDeviceNotifyAttach 為止。
在該呼叫之後,UFX 會將裝置狀態設定為 Powered ,如 USB 規格中所定義。 若要通知用戶端驅動程序狀態變更,UFX 會叫用用戶端驅動程式 的EVT_UFX_DEVICE_USB_STATE_CHANGE 實作。
UFX 會通知充電設備驅動器 (Cad.sys) 以協助充電裝置。 UFX 也會透過完成先前由類別驅動程式傳送 的IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 要求,通知類別驅動程式。
用戶端驅動程序必須在中斷鏈接總線時呼叫 UfxDeviceNotifyDetach 。 客戶端必須在每次呼叫 UfxDeviceNotifyAttach之後呼叫卸離一次。 UfxDeviceNotifyDetach 呼叫之後,如果這不是介面變更) ,UFX 會呼叫 EVT_UFX_DEVICE_HOST_DISCONNECT (。 UFX 接著會繼續進行所有清除工作,例如清除所有端點佇列和啟動預設端點佇列。 UFX 會 呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE ,並藉由完成 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 要求來通知類別驅動程式。
硬體失敗
如果發生硬體錯誤,客戶端驅動程序應該呼叫 UfxDeviceNotifyHardwareFailure。 回應中,UFX 會卸載裝置堆疊,並可能藉由呼叫用戶端驅動程式 的 EVT_UFX_DEVICE_CONTROLLER_RESET,嘗試從這種情況中復原。 客戶端應該將控制器重設為其初始狀態。 如果發生另一個硬體故障,客戶端應該再次呼叫 UfxDeviceNotifyHardwareFailure。 第二次呼叫時,UFX 會記錄其狀態和錯誤檢查。
埠偵測
埠偵測是由UFX執行。 它會呼叫函式控制器用戶端驅動程式 的EVT_UFX_DEVICE_PORT_DETECT 回呼函式,以判斷裝置所連接的埠類型。 用戶端會呼叫 UfxDevicePortDetectComplete 或 UfxDevicePortDetectCompleteEx ,並使用 USBFN_PORT_TYPE中定義的其中一個埠類型來回應。
如果客戶端無法判斷埠的類型,客戶端應該回報 UsbfnUnknownPort。 如果埠未知或下游埠,UFX 會呼叫用戶端驅動程式 的 EVT_UFX_DEVICE_HOST_CONNECT 函式。 UFX 會接聽總線一段時間。 如果埠未知,但有流量,例如設定封包,則 UFX 會假設 UsbfnStandardDownstreamPort。 否則,UFX 會將埠指派為 UsbfnInvalidDedicatedChargingPort。 判斷埠類型之後,UFX 會通知 Cad.sys,並呼叫用戶端驅動程式 的 EVT_UFX_DEVICE_PORT_CHANGE 函式。 在函式中,用戶端驅動程式預期會變更硬體狀態以符合UFX埠類型。
端點建立
UFX 會呼叫用戶端驅動程式 的 EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD ,以建立預設端點 (端點 0) ,以便處理主機所傳送的設定封包。 UFX 會藉由呼叫 EVT_UFX_DEVICE_ENDPOINT_ADD 來建立其他端點。 UFX 只會在用戶端驅動程式呼叫 UfxDeviceNotifyHardwareReady 之後建立端點。 在這些回呼函式中,用戶端驅動程式預期會呼叫 UfxEndpointCreate 至端點物件,並取得其UFXENDPOINT句柄。 UFX 會將父系設定為與端點所屬介面相關聯的類別驅動程式 PDO。 默認端點的父系是USB裝置物件。 端點包含兩個架構佇列物件:傳輸佇列和命令 Queue,這兩者只能在裝置處於 「已設定」狀態 (時存取,但端點 0 除外,可在 UFX 呼叫 之後存取,EVT_UFX_DEVICE_HOST_CONNECT) 。
- 命令佇列要求
- IOCTL_INTERNAL_USBFN_GET_PIPE_STATE
- IOCTL_INTERNAL_USBFN_SET_PIPE_STATE
- IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE
- 傳輸佇列要求
- IOCTL_INTERNAL_USBFN_TRANSFER_IN
- IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT
- IOCTL_INTERNAL_USBFN_TRANSFER_OUT
- IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN
- IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT
裝置列舉
UFX 呼叫驅動程式 EVT_UFX_DEVICE_HOST_CONNECT之前,用戶端驅動程式不應該允許連線到主機。 當客戶端驅動程式呼叫 UfxDeviceNotifyReset 時,就會開始裝置列舉。 在 [預設 ] 狀態中,UFX 會處理標準安裝封包。
重設
UFX 會清除所有端點佇列,並將 IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE 要求傳送至客戶端驅動程式,以更新端點 0 的 wMaxPacketSize 。 UFX 會啟動預設端點的佇列,並將狀態設定為 [預設]。
Default
UFX 會呼叫用戶端驅動程式 的 EVT_UFX_DEVICE_USB_STATE_CHANGE 函式。 它也會通知類別驅動程序狀態。 在UFX收到標準設定封包SET_ADDRESS之後,UFX 會將狀態設定為 Addressed。
解決
UFX 會呼叫用戶端驅動程式 的 EVT_UFX_DEVICE_ADDRESSED 函式,向用戶端指出應該使用的位址。 - 如果位址為 0,UFX 會將狀態設定回 Default ,並呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE ,並通知類別驅動程式。 收到標準安裝封包SET_CONFIGURATION時,UFX 會將狀態設定為 [已設定]。
已設定
如果選取的組態為 0,UFX 會清除介面連接點,並將狀態設定為 Addressed。 UFX 會將 IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE 要求傳送至客戶端驅動程式,以更新介面端點的 wMaxPacketSize 。 UFX 可確保所有介面連接點佇列都已完成清除和啟動介面連接點佇列。 如果埠類型不是 UsbfnStandardDownstreamPort 或 UsbfnChargingDownstreamPort,UFX 會將埠類型變更為 UsbfnStandardDownstreamPort ,並通知 Cad.sys;藉由呼叫 EVT_UFX_DEVICE_PORT_CHANGE 和 EVT_UFX_DEVICE_USB_STATE_CHANGE 來更新狀態,以用戶端驅動程式;已設定狀態的類別驅動程式。
標準控制傳輸
UFX 可以在呼叫 EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD 之後,隨時處理預設端點上的控制傳輸,而用戶端驅動程式會使用此端點來建立預設端點。 所有控制傳輸都是以8位元組設定封包開始。 若要將安裝封包傳送至主機,用戶端驅動程序應該呼叫 UfxEndpointNotifySetup。 UFX 會完成標準控制傳輸。 如果有與控制傳輸相關聯的數據,UFX 會視需要從預設控制端點讀取和寫入。
非標準控制傳輸
如果UFX無法處理控制傳輸,則會藉由完成 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 要求,將傳輸轉送至適當的類別驅動程式。 控制傳輸可以發生在端點描述項中定義為控制端點的任何端點上。 預設控制端點以外的端點控制傳輸一律為非標準控制傳輸。 如果控制端點是預設的控制端點,UFX 會通知設定封包的類別驅動程式,這些封包標示為該類別驅動程式的類別要求。 如果控制端點屬於介面,則UFX會通知與該介面相關聯的類別驅動程式。 如有必要,類別驅動程式應該從控制端點讀取和寫入。
資料傳輸
數據傳輸是由類別驅動程式起始,方法是傳送 IOCTL_INTERNAL_USBFN_TRANSFER_IN、 IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT或 IOCTL_INTERNAL_USBFN_TRANSFER_OUT 要求。 驗證每個要求之後,UFX 會將它轉送到客戶端驅動程式要處理的適當端點佇列。 用戶端驅動程式預期會執行額外的驗證。 用戶端驅動程式會在端點佇列上接收傳輸要求。 用戶端驅動程式可以從此佇列擷取所需的要求數目,以將總線使用率最大化。 用戶端驅動程序應該使用 STATUS_SUCCESS 完成成功的要求。 驅動程式應該盡最大努力取消要求,並在取消時完成已取消的要求,並STATUS_CANCELLED。 如果傳遞了無效的參數,客戶端驅動程式會以STATUS_INVALID_PARAMETER完成要求。
控制傳輸
控制傳輸從8位元組設定封包開始。 若要將安裝封包傳送至主機,用戶端驅動程序應該呼叫 UfxEndpointNotifySetup。 UFX 會藉由完成通知要求,通知非標準控制傳輸的類別驅動程式。 用戶端和UFX都會使用 IOCTL_INTERNAL_USBFN_TRANSFER_IN、 IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT或 IOCTL_INTERNAL_USBFN_TRANSFER_OUT 來讀取和寫入預設控制端點。 不過,介面可以定義其他控制端點,只有對應的類別驅動程式可以使用。 控制端點可以停止以回應設定封包。 類別驅動程式會傳送 IOCTL_INTERNAL_USBFN_SET_PIPE_STATE 要求來停止端點。 硬體或客戶端驅動程式預期會在傳送停止之後立即繼續端點上的流量。 控制端點也可以傳送和接收長度為零的封包, (ZLP) ,而不需要任何先前的數據。 用戶端驅動程式和UFX可以使用 IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN 和 IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT來執行此動作。
大量和中斷傳輸
大量傳輸保證數據傳遞,並用來傳送大量數據。 您可以使用 IOCTL_INTERNAL_USBFN_TRANSFER_IN、 IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT或 IOCTL_INTERNAL_USBFN_TRANSFER_OUT,在大量端點上傳送傳輸。 大量端點可能會停止,類似於使用 IOCTL_INTERNAL_USBFN_SET_PIPE_STATE控制端點。 用戶端驅動程式預期會傳送 STALL 封包,以回應所有主機要求並保存 IOCTL 要求。 不同於控制端點,停止的大量端點會維持停止狀態,直到明確清除停止狀態為止。
中斷傳輸 中斷傳輸就像大量傳輸,但有保證的延遲。 中斷傳輸具有與大量傳輸相同的介面,但沒有串流功能。
等時傳輸
用戶端驅動程式不預期支援此版本的時序傳輸。
電源管理
用戶端驅動程式擁有電源管理的所有層面。 因為回呼函式是異步的,所以用戶端驅動程式預期會回到適當的電源狀態,並在呼叫適當的事件完成導出函式之前完成要求,例如 UfxDeviceEventComplete。
如果 USBFN_DEVICE_STATE 中定義的裝置狀態 () 為 UsbfnDeviceStateSuspended 和 UsbfnDeviceStateAttached,且尚未回報埠類型,則 UFX 處於正常運作狀態。 或者,UFX 回報 USBFN_PORT_TYPE) UsbfnStandardDownstreamPort 或 UsbfnChargingDownstreamPort 中定義的埠 (類型。
UFX 會呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE 或 EVT_UFX_DEVICE_PORT_CHANGE 實作,以進入並結束工作狀態。 當客戶端驅動程式呼叫 UfxDeviceEventComplete 時,工作狀態的轉換完成。
在工作狀態中,UFX 可能會呼叫任何回呼。 雖然不是處於工作狀態,但UFX只會呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE 以進入工作狀態; 如果支援) ,EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL 暫停期間發出遠端喚醒 (。
裝置暫停
當總線上沒有流量 3 毫秒時,就會發生裝置暫停。 在此情況下,用戶端驅動程式必須藉由呼叫 UfxDeviceNotifySuspend 和 UfxDeviceNotifyResume 來通知 UFX。 在接收這些呼叫時,UFX 呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE ,並藉由完成 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 要求來通知類別驅動程式。 如果裝置支援遠端喚醒並由主機啟用,UFX 可能會在暫停時呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE 來發出遠端喚醒訊號。