共用方式為


如何將數據傳輸至 USB 等時點

本主題描述客戶端驅動程式如何建置 USB 要求區塊 (URB) ,以在 USB 裝置中同步端點來回傳輸數據。

通用序列總線 (USB) 裝置可以支援連續的端點,以穩定速率傳輸時間相依的數據,例如音訊/視訊串流。 若要傳輸數據,用戶端驅動程式會發出要求,以讀取或寫入數據到連續端點。 因此,主控制器會定期輪詢裝置來起始一個連續傳輸,以傳送或接收數據。

針對高速和全速裝置,輪詢是使用 (IN/OUT) 令牌封包來完成。 當端點準備好傳送數據時,裝置會傳送數據來回應其中一個 IN 令牌封包。 若要寫入裝置,主機控制器會傳送 OUT 令牌封包,後面接著數據封包。 主機控制器或裝置不會傳送任何交握封包,因此不會保證傳遞。 因為主控制器不會嘗試重試傳輸,所以如果發生錯誤,數據可能會遺失。

若為連續傳輸,主機控制器會在總線上保留特定時間週期。 若要管理連續端點的保留時間,時間會分成連續的邏輯 chuck,稱為 總線間隔。 總線間隔單位取決於總線速度。

針對完整速度,總線間隔是 框架。 框架的長度為 1 毫秒。

針對高速和 SuperSpeed,總線間隔是微框架。 微框架的長度為 125 微秒。 八個連續的微框架構成一個高速或 SuperSpeed 框架。

異時傳輸是以封包為基礎。 本主題中的 連續封包 一詞是指以一個總線間隔傳輸的數據量。 端點的特性會決定每個封包的大小是固定的,並由端點的特性決定。

用戶端驅動程式會建立要求的 URB,並將 URB 提交至 USB 驅動程式堆疊,以啟動不連續的傳輸。 要求是由 USB 驅動程式堆疊中的其中一個較低驅動程序處理。 收到 URB 時,USB 驅動程式堆疊會執行一組驗證,並排程要求的交易。 針對完整速度,每個總線間隔中要傳輸的連續封包會包含在網路上的單一交易中。 某些高速裝置允許在總線間隔內進行多個交易。 在此情況下,客戶端驅動程式可以在單一要求中傳送或接收更多數據, (URB) 。 超級裝置支援多個交易和高載傳輸,允許每個總線間隔更多的位元組。 如需高載傳輸的詳細資訊,請參閱 USB 3.0 規格頁面 9-42。

開始之前

在建立連續傳輸的要求之前,您必須有針對異時點開啟管道的相關信息。

使用 Windows 驅動程式模型 (WDM) 例程的用戶端驅動程式,在USBD_INTERFACE_LIST_ENTRY陣列的其中一個USBD_PIPE_INFORMATION結構中具有管道資訊。 用戶端驅動程式在驅動程式先前的要求中取得該數位,以選取裝置中的組態或介面。

Windows Driver Framework (WDF) 用戶端驅動程式必須取得架構目標管道對象的參考,並呼叫 WdfUsbTargetPipeGetInformation 以取得 WDF_USB_PIPE_INFORMATION 結構中的管道資訊。

根據管道資訊,判斷這組資訊:

  • 主控制器可以傳送多少數據到每個封包中的管道。

    用戶端驅動程式可以在要求中傳送的數據量不能超過主機控制器可以傳送或接收端點的最大位元組數目。 位元組數目上限是由 USBD_PIPE_INFORMATIONWDF_USB_PIPE_INFORMATION 結構的 MaximumPacketSize 成員表示。 USB 驅動程式堆疊會在選取組態或選取介面要求期間設定 MaximumPacketSize 值。

    針對完整速度裝置, MaximumPacketSize 衍生自端點描述元 wMaxPacketSize 字段的前 11 位,這表示端點可以在交易中傳送或接收的最大位元組數目。 針對完整速度裝置,控制器會針對每個總線間隔傳送一筆交易。

    在高速同步傳輸中,如果端點允許,主機控制器可以在總線間隔內傳送其他交易。 額外的交易數目是由裝置設定,並以 wMaxPacketSize 的位 12..11 表示。 該數位可以是 0、1 或 2。 如果 12..11 表示 0,端點不支援每個微框架的其他交易。 如果數位為 1,則主控制器可以傳送額外的交易 (每個微框架) 兩筆交易總數;2 表示每個微框架) 總共有三筆交易 (兩個額外的交易。 USB 驅動程式堆疊所設定 的 MaximumPacketSize 值包含可在其他交易中傳送的位元組數目。

    對於 SuperSpeed 同步傳輸,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR (某些值请参阅 Usbspec.h) 很重要。 USB 驅動程式堆疊會使用這些值來計算總線間隔中的位元元組數目上限。

    • 端點隨附描述元的 Isochronous.Mult 字段。 在 SuperSpeed 的同步傳輸中,其他交易 (類似於高速裝置) 稱為高載交易。 Mult 值表示端點支援的高載交易數目上限。 服務間隔中最多可以有三個高載交易 (索引為 0 到 2) 。

    • 端點隨附描述項的 bMaxBurst 欄位。 這個值表示可在單一高載交易中存在的 wMaxPacketSize 區塊數目。 在高載交易中,最多可以有16個區塊 (索引為0到15個) 。

    • wBytesPerInterval 指出主機可以在總線間隔中傳送或接收的位元組總數。 即使每個總線間隔的最大位元元組數目可以計算為 (bMaxBurst+1) * (Mult+1) * wMaxPacketSize,USB 3.0 規格還是建議改用 wBytesPerInterval 值。 wBytesPerInterval 值必須小於或等於該計算值。

      重要

      針對客戶端驅動程式,上述的值僅供資訊使用。 驅動程式一律必須使用端點描述元的 MaximumPacketSize 值來判斷傳輸緩衝區的配置。

  • 端點傳送或接收數據的頻率為何?

    Interval 成員可用來判斷端點可以傳送或接收數據的頻率。 裝置會設定該值,而客戶端驅動程式無法加以變更。 USB 驅動程式堆疊會使用另一個數位來判斷將連續封包插入數據流的頻率:輪詢期間,其衍生自 Interval 值。

    針對全速傳輸, 間隔 和輪詢期間值一律為 1;USB 驅動程式堆疊會忽略其他值。

    下表顯示高速和超級傳輸的 Interval 和計算輪詢期間:

    間隔 輪詢期間 (2Interval-1)
    1 1;每一個總線間隔都會傳輸數據。
    2 2;數據會每秒傳輸一次總線間隔。
    3 4;數據會每隔四個總線間隔傳輸一次。
    4 8;數據會每隔八個總線間隔傳輸一次。
  • 每個總線速度封包數目的限制為何。

    在 URB 中,您只能針對完整速度裝置傳送最多 255 個連續封包;適用於高速和超級裝置之 URB 中的 1024 封包。 您在 URB 中傳送的封包數目必須是每個框架中封包數目的倍數。

    輪詢期間 高速/SuperSpeed 的封包數目
    1 8 的倍數
    2 4 的倍數
    3 2 的倍數
    4 任何

請考慮使用 wMaxPacketSize 的範例完整速度端點為 1,023。 在此範例中,應用程式提供的緩衝區為 25,575 個字節。 該緩衝區的傳輸需要 25 個連續封包, (25575/1023) 。

請考慮在端點描述元中指出下列特性的高速端點範例。

  • wMaxPacketSize 為 1,024。
  • 位12..11表示兩個額外的交易。
  • 間隔 為 1。

在用戶端驅動程式選取設定之後,isochronous 管道的 MaximumPacketSize 表示總交易數 * wMaxPacketSize) 3,072 (個字節。 其他交易可讓客戶端驅動程式在每個微框架中傳輸 3,072 個字節,並在一個框架中總共傳輸 24,576 個字節。 下圖顯示在一個微框架中傳輸非連續封包的頻率,以進行高速傳輸。

連續傳輸間隔、輪詢期間和封包的圖表。

請考慮範例 SuperSpeed 端點,其中包含端點和 SuperSpeed 端點隨附描述項中指出的特性:

  • wMaxPacketSize 為 1,024。
  • bMaxBurst 為 15。
  • 間隔 為 1。
  • Isochronous.Mult 為 2。
  • wBytesPerInterval 為 45000。

在上述範例中,即使最大位元元組數可以計算為 wMaxPacketSize * (bMaxBurst +1) * (Mult + 1) 導致 49,152 個字節,裝置會將值限制為 45,000 個字節的 wBytesPerInterval 值。 該值也會反映在 MaximumPacketSize 45,000 中。 用戶端驅動程式只能使用 MaximumPacketSize 值。 在此範例中,要求可以分成三個高載交易。 前兩個高載交易分別包含16個 wMaxPacketSize區塊。 最後一個高載交易包含12個區塊來保存剩餘的位元組。 此影像顯示透過超速傳輸的連續封包所傳輸的輪詢間隔和位元組。

超速傳輸間隔、輪詢期間和封包的圖表。

若要建置異時傳輸的要求:

  1. 取得每個連續封包的大小。
  2. 判斷每個畫面的連續封包數目。
  3. 計算保存整個傳輸緩衝區所需的連續封包數目。
  4. 配置 URB 結構來描述傳輸的詳細數據。
  5. 指定每個連續封包的詳細數據,例如封包位移。

如需傳送連續傳輸要求的完整程式碼範例,請參閱USBSAMP。

本主題中的這個範例可簡化異時傳輸的USBSAMP實作。 此範例會計算傳輸所需的總框架數。 根據可以在框架中傳送的數據量,傳輸緩衝區會分成較小的區塊大小位元組。

下列程式會詳細說明上述步驟,並顯示用戶端驅動程式可用來建置和傳送高速等時點之異動傳輸要求的計算和例程。 程式中所使用的值是以稍早所述的範例端點特性為基礎。

步驟 1:取得連續封包的大小

藉由檢查管道的 MaximumPacketSize 值,判斷不連續封包的大小。

針對全速傳輸,異時封包的大小是您可以在一個框架中傳輸的位元元組數目。 針對高速和超級傳輸,非時序封包的大小是可在一個微框架中傳輸的位元組總數。 這些值會以管道的 MaximumPacketSize 表示。

在此範例中, MaximumPacketSize 是每個畫面 1023 個字節, (完整速度) ;每個微框架 3072 個字節 (高速) ;每個微框架 45,000 個字節 (SuperSpeed) 。

注意

MaximumPacketSize 值表示連續封包允許的大小上限。 用戶端驅動程式可以將每個不連續封包的大小設定為小於 MaximumPacketSize 值的任何值。

步驟 2:決定每個畫面的連續封包數目

針對全速傳輸,您會在每個畫面中傳送一個連續封包。

針對高速和超級傳輸,此值必須衍生自 Interval 值。 在此範例中,Interval 是 1。 因此,每一框架的連續封包數目必須有8個。 如需其他 Interval 值,請參閱必要條件一節中的表格。

步驟 3:計算保存整個傳輸緩衝區所需的連續封包數目

計算傳輸整個緩衝區所需的連續封包數目。 這個值可以藉由將傳輸緩衝區的長度除以連續封包的大小來計算。

在此範例中,我們假設每個連續封包的大小都是 MaximumPacketSize ,而傳輸緩衝區長度是 MaximumPacketSize 值的倍數。

例如,針對完整速度傳輸,提供的緩衝區為 25,575 個字節需要 25 個連續封包, (25575/1023) 。 針對高速傳輸,大小為 24,576 的緩衝區分成八個連續封包, (24576 /3072) 傳輸。 針對 SuperSpeed,大小為 360,000 個字節的緩衝區適用於八個連續封包, (360000/45000) 。

用戶端驅動程式應該驗證這些需求:

  • 連續封包數目必須是每個畫面的封包數目的倍數。
  • 進行傳輸所需的非時序封包數目上限不得超過 255 個完整速度裝置;適用於高速或超級裝置的 1024。

步驟 4:配置 URB 結構以描述傳輸的詳細數據

  1. 在非分頁集區中配置 URB 結構。

    如果您的用戶端驅動程式使用 WDM 例程,如果您有 Windows 驅動程式套件 (WDK) ,則驅動程式必須呼叫 Windows 8 USBD_IsochUrbAllocate。 用戶端驅動程式可以使用例程,以 Windows Vista 和更新版本的 Windows 作業系統為目標。 如果您沒有適用於 Windows 8 的 WDK,或用戶端驅動程式適用於舊版的作業系統,您可以呼叫 ExAllocatePoolWithTag,在堆疊或非分頁集區中配置結構。

    WDF 用戶端驅動程式可以呼叫 WdfUsbTargetDeviceCreateIsochUrb 方法來配置 URB 結構的記憶體。

  2. URB 結構的 UrbIsochronousTransfer 成員會指向描述異時傳輸詳細數據的_URB_ISOCH_TRANSFER結構。 初始化下列 UrbIsochronousTransfer 成員,如下所示:

    • UrbIsochronousTransfer.Hdr.Length 成員設定為 URB 的大小。 若要取得 URB 的大小,請呼叫 GET_ISO_URB_SIZE 宏,並指定封包數目。

    • UrbIsochronousTransfer.Hdr.Function 成員設定為 URB_FUNCTION_ISOCH_TRANSFER

    • UrbIsochronousTransfer.NumberOfPackets 成員設定為連續封包的數目。

    • UrbIsochronousTransfer.PipeHandle 設定為與端點相關聯之管道的不透明句柄。 請確定管道控點是通用序列總線所使用的 USBD 管道句柄, (USB) 驅動程式堆疊。

      若要取得 USBD 管道句柄,WDF 用戶端驅動程式可以呼叫 WdfUsbTargetPipeWdmGetPipeHandle 方法,並將 WDFUSBPIPE 句柄指定給架構的管道物件。 WDM 用戶端驅動程序必須使用在 USBD_PIPE_INFORMATION 結構的 PipeHandle 成員中取得的相同句柄。

    • 指定傳輸的方向。 將 UrbIsochronousTransfer.TransferFlags 設定為USBD_TRANSFER_DIRECTION_IN,以從裝置讀取) (無時差 IN 傳輸;USBD_TRANSFER_DIRECTION_OUT寫入裝置) (異時輸出傳輸。

    • UrbIsochronousTransfer 中指定USBD_START_ISO_TRANSFER_ASAP旗標。TransferFlags。 旗標會指示 USB 驅動程式堆疊在下一個適當的框架中傳送傳輸。 在客戶端驅動程式第一次傳送此管道的異時 URB 時,驅動程式堆疊會儘快在 URB 中傳送連續封包。 USB 驅動程式堆疊會追蹤下一個框架,以用於該管道上的後續 URI。 如果傳送後續使用USBD_START_ISO_TRANSFER_ASAP旗標的後續非時序 URB 有延遲,驅動程式堆疊會將該 URB 的某些或所有封包視為晚期,且不會傳輸這些封包。

      如果堆棧在完成該管道先前的 URB 之後,該堆疊未收到 1024 個畫面的連續 URB,則 USB 驅動程式堆疊會重設其USBD_START_ISO_TRANSFER_ASAP開始畫面追蹤。 您可以指定開始畫面,而不是指定USBD_START_ISO_TRANSFER_ASAP旗標。 如需詳細資訊,請參閱<備註>一節。

    • 指定傳輸緩衝區及其大小。 您可以在 UrbIsochronousTransfer.TransferBuffer 或描述 UrbIsochronousTransfer.TransferBufferMDL 中緩衝區的 MDL 設定指標。

      若要擷取傳輸緩衝區的 MDL,WDF 用戶端驅動程式可以根據傳輸的方向呼叫 WdfRequestRetrieveOutputWdmMdlWdfRequestRetrieveInputWdmMdl

步驟 5:指定傳輸中每個連續封包的詳細數據

USB 驅動程式堆疊會配置夠大的新 URB 結構,以保存每個連續封包的相關信息,但不會配置封包中包含的數據。 在 URB 結構中, UrbIsochronousTransfer.IsoPacket 成員是 USBD_ISO_PACKET_DESCRIPTOR 數位,描述傳輸中每個連續封包的詳細數據。 封包必須連續。 陣列中的元素數目必須是URB的 UrbIsochronousTransfer.NumberOfPackets 成員中指定的無時差封包數目。

針對高速傳輸,陣列中的每個元素都會與一個微框架中的一個連續封包相互關聯。 針對完整速度,每個元素都會與一個在一個框架中傳輸的連續封包相互關聯。

針對每個元素,指定每個異時差封包的位元組位移,從要求的整個傳輸緩衝區開始。 您可以藉由設定 UrbIsochronousTransfer.IsoPacket[i] 來指定該值。位移 成員。 USB 驅動程式堆疊會使用指定的值來追蹤要傳送或接收的數據量。

設定 Full-Speed 傳輸的位移

例如,這些是完整速度傳輸緩衝區的陣列專案。 在完整速度中,客戶端驅動程式有一個框架可傳輸一個連續封包,最多 1,023 個字節。 25,575 個字節的傳輸緩衝區可以保留 25 個連續封包,每個長度為 1,023 個字節。 整個緩衝區總共需要25個畫面格。

Frame 1 IsoPacket [0].Offset = 0 (start address)
Frame 2 IsoPacket [1].Offset = 1023
Frame 3 IsoPacket [2].Offset = 2046
Frame 4 IsoPacket [3].Offset = 3069
...
Frame 25 IsoPacket [24].Offset = 24552

Total length transferred is 25,575 bytes.

設定 High-Speed 傳輸的位移

例如,這些是高速傳輸緩衝區的數位專案。 此範例假設緩衝區為 24,576 個字節,而用戶端驅動程式有一個框架可傳輸八個連續封包,每 3,072 個字節。

Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 3072
Microframe 3 IsoPacket [2].Offset = 6144
Microframe 4 IsoPacket [3].Offset = 9216
Microframe 5 IsoPacket [4].Offset = 12288
Microframe 6 IsoPacket [5].Offset = 15360
Microframe 7 IsoPacket [6].Offset = 18432
Microframe 8 IsoPacket [7].Offset = 21504

Total length transferred is 24,576 bytes.

設定 SuperSpeed 傳輸的位移

例如,這是 SuperSpeed 的數位移。 您可以在一個畫面中傳送最多 45,000 個字節。 大小為 360,000 的傳輸緩衝區符合八個微框架。

Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 45000
Microframe 3 IsoPacket [2].Offset = 90000
Microframe 4 IsoPacket [3].Offset = 135000
Microframe 5 IsoPacket [4].Offset = 180000
Microframe 6 IsoPacket [5].Offset = 225000
Microframe 7 IsoPacket [6].Offset = 270000
Microframe 8 IsoPacket [7].Offset = 315000

Total length transferred is 360,000 bytes.

UrbIsochronousTransfer.IsoPacket[i]。Length 成員不表示不同時序 URB 的每個封包長度。 IsoPacket[i]。USB 驅動程式堆疊會更新長度,以指出從裝置接收的實際位元元組數目,以進行連續 IN 傳輸。 若為連續 OUT 傳輸,驅動程式堆疊會忽略 IsoPacket[i] 中設定的值。長度

指定傳輸的起始 USB 框架編號

URB 的 UrbIsochronousTransfer.StartFrame 成員會指定傳輸的起始 USB 畫面編號。 用戶端驅動程式提交 URB 的時間,以及 USB 驅動程式堆疊處理 URB 的時間,一律會有延遲。 因此,客戶端驅動程序應該一律指定比驅動程式提交 URB 時目前框架晚的開始畫面格。 若要擷取目前的框架號碼,客戶端驅動程式可以將URB_FUNCTION_GET_CURRENT_FRAME_NUMBER要求傳送至USB驅動程式堆疊 , (_URB_GET_CURRENT_FRAME_NUMBER) 。

對於等時傳輸,目前畫面格與 StartFrame 值之間的絕對差異必須小於 USBD_ISO_START_FRAME_RANGE。 如果 StartFrame 不在適當的範圍內,USB 驅動程式 堆疊會將 URB 標頭的狀態成員設定 (請參閱 _URB_HEADER) USBD_STATUS_BAD_START_FRAME並捨棄整個 URB。

URB 中指定的 StartFrame 值表示傳輸 URB 之第一個時序封包的畫面編號。 後續封包的框架編號取決於端點的總線速度和輪詢期間值。 例如,若為完整速度傳輸,則會在 StartFrame 中傳輸第一個封包;第二個封包會在 StartFrame+1 中傳輸,依此類歸。 USB 驅動程式堆疊傳輸時序封包的方式,在畫面格中會以完整速度傳輸,如下所示:

Frame (StartFrame)   IsoPacket [0]
Frame (StartFrame+1) IsoPacket [1]
Frame (StartFrame+2) IsoPacket [2]
Frame (StartFrame+3) IsoPacket [3]
...

對於間隔值為 1 的高速裝置,畫面編號會每八個微框架變更一次。 USB 驅動程式堆疊在畫面格中傳輸時序封包的方式如下所示:

Frame (StartFrame) Microframe 1 IsoPacket [0]
...
Frame (StartFrame) Microframe 8 IsoPacket [7]
Frame (StartFrame+1) Microframe 1 IsoPacket [8]
...
Frame (StartFrame+1) Microframe 8 IsoPacket [15]
Frame (StartFrame+2) Microframe 1 IsoPacket [16]
...
Frame (StartFrame+2) Microframe 8 IsoPacket [23]

當 USB 驅動程式堆疊處理 URB 時,驅動程式會捨棄 URB 中框架編號低於目前框架編號的所有等時封包。 驅動程式堆疊會將每個捨棄封包的封包描述元的 Status 成員設定為USBD_STATUS_ISO_NA_LATE_USBPORT、USBD_STATUS_ISO_NOT_ACCESSED_BY_HW或USBD_STATUS_ISO_NOT_ACCESSED_LATE。 即使會捨棄 URB 中的某些封包,驅動程式堆疊仍會嘗試只傳輸框架編號高於目前框架編號的封包。

在高速傳輸中,有效 StartFrame 成員的檢查會稍微複雜一點,因為 USB 驅動程式堆疊會將每個隨機封包載入高速微框架中;不過, StartFrame 中的值是指 1 毫秒 (全速) 畫面編號,而不是微框架。 例如,如果 URB 中記錄的 StartFrame 值小於目前的框架,驅動程式堆疊可以捨棄多達八個封包。 捨棄的封包確切數目取決於與時序管道相關聯的輪詢期間。

等時傳輸範例

下列程式代碼範例示範如何為全速、高速和超速度傳輸建立等時傳輸的 URB。

#define MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED 1024
#define MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED 255

NTSTATUS CreateIsochURB  ( PDEVICE_OBJECT         DeviceObject,
                          PUSBD_PIPE_INFORMATION  PipeInfo,
                          ULONG                   TotalLength,
                          PMDL                    RequestMDL,
                          PURB                    Urb)
{
    PDEVICE_EXTENSION        deviceExtension;
    ULONG                    numberOfPackets;
    ULONG                    numberOfFrames;
    ULONG                    isochPacketSize = 0;
    ULONG                    transferSizePerFrame;
    ULONG                    currentFrameNumber;
    size_t                   urbSize;
    ULONG                    index;
    NTSTATUS                 ntStatus;

    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

    isochPacketSize = PipeInfo->MaximumPacketSize;

    // For high-speed transfers
    if (deviceExtension->IsDeviceHighSpeed || deviceExtension->IsDeviceSuperSpeed)
    {
        // Ideally you can pre-calculate numberOfPacketsPerFrame for the Pipe and
        // store it in the pipe context.

        switch (PipeInfo->Interval)
        {
        case 1:
            // Transfer period is every microframe (eight times a frame).
            numberOfPacketsPerFrame = 8;
            break;

        case 2:
            // Transfer period is every 2 microframes (four times a frame).
            numberOfPacketsPerFrame = 4;
            break;

        case 3:
            // Transfer period is every 4 microframes (twice in a frame).
            numperOfPacketsPerFrame = 2;
            break;

        case 4:
        default:
            // Transfer period is every 8 microframes (once in a frame).
            numberOfPacketsPerFrame = 1;
            break;
        }

        //Calculate the number of packets.
        numberOfPackets = TotalLength / isochPacketSize;

        if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED)
        {
            // Number of packets cannot be  greater than 1021.
            ntStatus = STATUS_INVALID_PARAMETER;
            goto Exit;
        }

        if (numberOfPackets % numberOfPacketsPerFrame != 0)
        {

            // Number of packets should be a multiple of numberOfPacketsPerFrame
            ntStatus = STATUS_INVALID_PARAMETER;
            goto Exit;
        }

    }
    else if (deviceExtension->IsDeviceFullSpeed)
    {
        //For full-speed transfers
        // Microsoft USB stack only supports bInterval value of 1 for
        // full-speed isochronous endpoints.

        //Calculate the number of packets.
        numberOfPacketsPerFrame = 1;

        numberOfPackets = TotalLength / isochPacketSize;

        if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED)
        {
            // Number of packets cannot be greater than 255.
            ntStatus = STATUS_INVALID_PARAMETER;
            goto Exit;
        }
    }

    // Allocate an isochronous URB for the transfer
    ntStatus = USBD_IsochUrbAllocate (deviceExtension->UsbdHandle,
        numberOfPackets,
        &Urb);

    if (!NT_SUCCESS(ntStatus))
    {
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    urbSize = GET_ISO_URB_SIZE(numberOfPackets);

    Urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) urbSize;
    Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
    Urb->UrbIsochronousTransfer.PipeHandle = PipeInfo->PipeHandle;

    if (USB_ENDPOINT_DIRECTION_IN(PipeInfo->EndpointAddress))
    {
        Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
    }
    else
    {
        Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
    }

    Urb->UrbIsochronousTransfer.TransferBufferLength = TotalLength;
    Urb->UrbIsochronousTransfer.TransferBufferMDL = RequestMDL;
    Urb->UrbIsochronousTransfer.NumberOfPackets = numberOfPackets;
    Urb->UrbIsochronousTransfer.UrbLink = NULL;

    // Set the offsets for every packet for reads/writes

    for (index = 0; index < numberOfPackets; index++)
    {
        Urb->UrbIsochronousTransfer.IsoPacket[index].Offset = index * isochPacketSize;
    }

    // Length is a return value for isochronous IN transfers.
    // Length is ignored by the USB driver stack for isochronous OUT transfers.

    Urb->UrbIsochronousTransfer.IsoPacket[index].Length = 0;
    Urb->UrbIsochronousTransfer.IsoPacket[index].Status = 0;

    // Set the USBD_START_ISO_TRANSFER_ASAP. The USB driver stack will calculate the start frame.
    // StartFrame value set by the client driver is ignored.
    Urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;

Exit:

    return ntStatus;
}