共用方式為


撰寫函式控制器用戶端驅動程式

本文說明函式控制器用戶端驅動程式在與 USB 函式控制器擴充功能互動時執行的各種工作。

重要 API

描述函式控制器用戶端驅動程式在與 USB 函式控制器擴充功能 (UFX) 互動時執行的各種工作。 UFX 和用戶端驅動程式會使用導出方法和事件回呼函式彼此通訊。 匯出方法(名為 UfxDeviceXxxUfxEndpointXxx)是由 UFX 匯出,並由用戶端驅動程式叫用。 回呼函式 (名為 EVT_UFX_Xxx)會在用戶端驅動程式中實作,並由 UFX 叫用。

UFX 會異步呼叫所有用戶端驅動程式的回呼函式,並針對每個物件一次執行一個回呼。 例如,有一個USB裝置物件和三個端點物件。 最多可以呼叫四個回呼函式(一個用於裝置,一個用於每個端點)。 針對每個回呼方法,UFX 會等到用戶端驅動程式呼叫 UfxDeviceEventComplete ,以指出驅動程式已完成要求。 UFX 在等候這些匯出時,唯一會接聽的其他匯出方法是 UfxDeviceNotifyHardwareFailure。 許多用戶端回呼函式都是選擇性的。 必要的函式如下所示:

初始化

  1. 當 Windows Driver Foundation (WDF) 叫用用戶端驅動程式的 EVT_WDF_DRIVER_DEVICE_ADD 回呼實作時,函式控制器用戶端驅動程式會啟動初始化程式。 在該實作中,用戶端驅動程序應該呼叫 UfxFdoInit ,然後呼叫 WdfDeviceCreate來建立裝置物件。
  2. 用戶端驅動程式會呼叫 UfxDeviceCreate 來建立USB裝置物件,並擷取UFXDEVICE句柄。
  3. 用戶端驅動程式會呼叫 UfxDeviceNotifyHardwareReady ,以向UFX指出它現在可以叫用客戶端驅動程式的回呼函式。
  4. UFX 會執行初始化工作,例如:

類別驅動程式通知

為了收到設定封包和總線狀態的通知,類別驅動程式應該傳送 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 之後只呼叫一次 detach。 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 回呼函式,以判斷裝置所連接的埠類型。 用戶端會呼叫 UfxDevicePortDetectCompleteUfxDevicePortDetectCompleteEx ,並使用 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裝置物件。 端點包含兩個架構佇列物件:傳輸佇列和命令佇列,這兩者只能在裝置處於 [設定] 狀態時存取(除了端點 0 之外,UFX 呼叫 之後才能存取EVT_UFX_DEVICE_HOST_CONNECT)。

裝置列舉

在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 會將狀態設定回 預設值 ,並 呼叫EVT_UFX_DEVICE_USB_STATE_CHANGE ,並通知類別驅動程式。 在接收SET_CONFIGURATION標準設定封包時,UFX 會將狀態設定為 [已設定]。

設定完成

如果選取的組態為 0,UFX 會清除介面連接點,並將狀態設定為 Addressed。 UFX 會將 IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE 要求傳送至客戶端驅動程式,以更新介面端點的 wMaxPacketSize 。 UFX 可確保所有介面端點佇列已經完成清除,並開始啟動介面端點佇列。 如果埠類型不是 UsbfnStandardDownstreamPortUsbfnChargingDownstreamPort,UFX 會將埠類型變更為 UsbfnStandardDownstreamPort ,並通知 Cad.sys;藉由呼叫 EVT_UFX_DEVICE_PORT_CHANGEEVT_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_INIOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKTIOCTL_INTERNAL_USBFN_TRANSFER_OUT 要求。 驗證每個要求之後,UFX 會將它轉送至適當的端點佇列,以由用戶端驅動程序處理。 用戶端驅動程式預期會執行額外的驗證。 用戶端驅動程式會在端點佇列上接收傳輸要求。 用戶端驅動程式可以從此佇列擷取所需的要求數目,以將總線使用率最大化。 用戶端驅動程序應該以狀態碼 STATUS_SUCCESS 完成成功的要求。 驅動程式應盡最大努力取消要求,並在取消時以STATUS_CANCELLED狀態完成已取消的要求。 如果傳遞無效的參數,客戶端驅動程式會使用 STATUS_INVALID_PARAMETER完成要求。

控制傳輸

控制傳輸從8位元組設定封包開始。 若要將安裝封包傳送至主機,用戶端驅動程序應該呼叫 UfxEndpointNotifySetup。 UFX 透過完成通知請求來告知類別驅動程式有非標準控制傳輸。 用戶端和UFX都會使用 IOCTL_INTERNAL_USBFN_TRANSFER_INIOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKTIOCTL_INTERNAL_USBFN_TRANSFER_OUT 來讀取和寫入預設控制端點。 不過,介面可以定義其他控制端點,而此端點只能使用對應的類別驅動程式。 控制端點可以暫停操作以回應設定封包。 類別驅動程式會傳送 IOCTL_INTERNAL_USBFN_SET_PIPE_STATE 要求來停止端點。 硬體或客戶端驅動程式預期會在傳送停止之後立即繼續端點上的流量。 控制端點也可以傳送和接收長度為零的封包(ZLP),而不需要任何先前的數據。 用戶端驅動程式和UFX可以使用 IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_INIOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT來執行此動作。

批量傳輸和中斷傳輸

大量傳輸可保證數據傳遞,並用來傳送大量數據。 您可以使用 IOCTL_INTERNAL_USBFN_TRANSFER_INIOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKTIOCTL_INTERNAL_USBFN_TRANSFER_OUT 在批量端點上傳送傳輸。 大量端點可能會停止,類似於使用 IOCTL_INTERNAL_USBFN_SET_PIPE_STATE控制端點。 用戶端驅動程式預期會傳送 STALL 封包,以回應所有主機要求並保存 IOCTL 要求。 與控制端點不同,當大容量端點停滯時,會保持停滯狀態,直到其停止狀態被明確清除為止。

中斷傳輸就像大量傳輸,但具有保證的延遲性。 中斷傳輸具有與大量傳輸相同的介面,但沒有串流功能。

同步傳輸

用戶端驅動程式不應該支援此版本的不時針傳輸。

電源管理

用戶端驅動程式擁有電源管理的所有層面。 由於回呼函式是異步的,因此用戶端驅動程序應該會回到適當的電源狀態,並在呼叫適當的事件完成導出函式之前完成要求,例如 UfxDeviceEventComplete

如果裝置狀態( USBFN_DEVICE_STATE中定義)為 UsbfnDeviceStateSuspendedUsbfnDeviceStateAttached,且未回報埠類型,UFX 會處於工作狀態。 或者,UFX 已報告埠類型(定義於 USBFN_PORT_TYPEUsbfnStandardDownstreamPortUsbfnChargingDownstreamPort

UFX 會呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGEEVT_UFX_DEVICE_PORT_CHANGE 實作,進入並結束工作狀態。 當客戶端驅動程式呼叫 UfxDeviceEventComplete 時,工作狀態的轉換完成。

在工作狀態中,UFX 可能會呼叫任何回呼函數。 雖然不是處於工作狀態,但UFX只會呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE 以進入工作狀態; EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL 暫停期間發出遠端喚醒(如果支援)。

裝置暫停

當總線上 3 毫秒沒有流量時,裝置進入暫停狀態。 在此情況下,客戶端驅動程式必須在偵測到暫停和繼續時,通過呼叫 UfxDeviceNotifySuspendUfxDeviceNotifyResume 來通知 UFX。 在收到這些呼叫時,UFX 會 呼叫EVT_UFX_DEVICE_USB_STATE_CHANGE ,並藉由完成 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 要求來通知類別驅動程式。 如果裝置支援遠端喚醒並由主機啟用,UFX 可能會在暫停時呼叫 EVT_UFX_DEVICE_USB_STATE_CHANGE 來發出遠端喚醒訊號。