Teknologian jakaminen

Windowsin USB-laiteohjainkehitys-prosessoi eräsiirtojen staattisia virtoja

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

USB 2.0:ssa ja aiemmissa laitteissa joukkopäätepiste voi lähettää tai vastaanottaa yksittäisen datavirran päätepisteen kautta. USB 3.0 -laitteissa joukkopäätepiste pystyy lähettämään ja vastaanottamaan useita tietovirtoja päätepisteen kautta.

Microsoftin Windowsissa toimittama USB-ohjainpino tukee useita suoratoistoja. Tämän ansiosta asiakasohjaimet voivat lähettää itsenäisiä I/O-pyyntöjä jokaiseen USB 3.0 -laitteen joukkopäätepisteeseen liittyvään virtaan ilman, että pyyntöjä sarjoitetaan eri tietovirroihin.

Asiakasohjaimelle tietovirta edustaa useita loogisia päätepisteitä, joilla on samat ominaisuudet. Pyynnön lähettämiseksi tiettyyn tietovirtaan asiakasohjain tarvitsee kahvan kyseiselle virralle (samanlainen kuin päätepisteen putken kahva). I/O-pyyntöjen suoratoiston URB on samanlainen kuin joukkopäätepisteiden I/O-pyyntöjen URB. Ainoa ero on putken kahva. Lähettääkseen I/O-pyynnön streamiin ajuri määrittää putkikahvan virrassa.

Laitteen määrityksen aikana asiakasohjain lähettää valintamäärityspyynnön ja valinnaisesti valintaliittymäpyynnön. Nämä pyynnöt hakevat joukon putkikahvoja käyttöliittymän toiminta-asetuksissa määritetyille päätepisteille. Virtatietoisissa päätepisteissä päätepisteputken kahvaa voidaan käyttää I/O-pyyntöjen lähettämiseen oletusvirtaan (ensimmäiseen tietovirtaan), kunnes ohjain avaa virran.

Jos asiakasohjain haluaa lähettää pyyntöjä muille kuin oletusvirralle, ohjaimen on avattava ja hankittava kahvat kaikille virroille. Tätä varten asiakasohjain lähettää avoimen streamin pyynnön määrittämällä avattavien tietovirtojen määrän. Kun asiakasohjain on lopettanut streamien käytön, ohjain voi päättää sulkea ne lähettämällä streamin sulkemispyynnön.

Kernel Mode Driver Framework (KMDF) ei tue natiivisti staattisia virtoja. Asiakasohjaimien on käytettävä Windows-ohjainmallia (WDM) streamien avaamiseen ja sulkemiseen. User-mode Driver Framework (UMDF) -asiakasohjaimet eivät voi käyttää staattista suoratoistoominaisuutta.

Seuraavassa saattaa olla joitain kommentteja, jotka on merkitty WDM-ohjaimet. Nämä ohjeet kuvaavat rutiineja WDM-pohjaiselle USB-asiakasohjaimelle, joka haluaa lähettää suoratoistopyyntöjä.

edellytykset

Ennen kuin asiakasohjain voi avata tai sulkea streamin, ohjaimella on oltava:

1. Kutsu WdfUsbTargetDeviceCreateWithParameters-metodi. Menetelmä vaatii USBD_CLIENT_CONTRACT_VERSION_602 asiakasprotokollan version. Määrittämällä tämän version asiakasohjaimen on noudatettava tiettyjä sääntöjä.

Soita hakeaksesi kehyksen USB-kohdelaiteobjektin WDFUSBDEVICE-kahvan. Kahva tarvitaan myöhempiä kutsuja avoimeen streamiin. Tyypillisesti asiakasohjain rekisteröi itsensä ohjaimen EVT_WDF_DEVICE_PREPARE_HARDWARE-tapahtuman takaisinkutsurutiiniin.

WDM-ohjain: Kutsu USBD_CreateHandle-rutiini ja hanki ohjaimen USB-ohjainpinoon rekisteröimä USBD-kahva.

2. Määritti laitteen ja hanki WDFUSBPIPE-putkikahvan massapäätepisteeseen, joka tukee suoratoistoa. Saadaksesi putken kahvan, kutsu WdfUsbInterfaceGetConfiguredPipe-menetelmä valitun kokoonpanon liitännän nykyisissä vaihtoehtoisissa asetuksissa.

WDM-ohjain: Hakee USBD-putken kahvan lähettämällä valintakonfiguraatio- tai valintaliittymäpyynnön.

Kuinka avata staattinen stream

1. Selvitä, tukevatko taustalla oleva USB-ohjainpino ja isäntäohjain staattista suoratoistoominaisuutta kutsumalla WdfUsbTargetDeviceQueryUsbCapability-menetelmää. Tyypillisesti asiakasohjaimet kutsuvat rutiineja ohjaimen EVT_WDF_DEVICE_PREPARE_HARDWARE-tapahtuman takaisinkutsurutiinissa.

WDM-ohjain: Kutsuu USBD_QueryUsbCapability-rutiinia. Tyypillisesti ohjain kysyy toiminnon, jota käytetään ohjaimen käynnistyslaiterutiinissa (IRP_MN_START_DEVICE).

Anna seuraavat tiedot:

  • USB-laiteobjektin kahva, joka haettiin edellisessä kutsussa WdfUsbTargetDeviceCreateWithParametersille, jota käytettiin asiakasohjaimen rekisteröintiin.

WDM-ajuri: Siirrä edellisessä kutsussa haettu USBD-kahva USBD_CreateHandlelle.

Jos asiakasohjain haluaa käyttää tiettyä ominaisuutta, ohjaimen on ensin tehtävä kysely taustalla olevasta USB-ohjainpinosta selvittääkseen, tukevatko ohjainpino ja isäntäohjain ominaisuutta. Jos ominaisuus on tuettu, vain silloin kuljettajan tulee lähettää pyyntö käyttää ominaisuutta. Tietyt pyynnöt edellyttävät URB:itä, kuten vaiheessa 5 käsitelty suoratoistotoiminto. Varmista näissä pyynnöissä, että käytät samaa kahvaa funktion kyselyyn ja URB:n varaamiseen. Tämä johtuu siitä, että ohjainpino käyttää kahvoja pitääkseen kirjaa tuetuista ominaisuuksista, joita ohjain voi käyttää.

Jos esimerkiksi USBD_HANDLE saatiin kutsumalla USBD_CreateHandle, ohjainpinoa kysytään kutsumalla USBD_QueryUsbCapability ja URB varataan kutsumalla USBD_UrbAllocate. Ohita sama USBD_HANDLE molemmissa puheluissa.

Jos kutsut KMDF-menetelmiä, WdfUsbTargetDeviceQueryUsbCapability- ja WdfUsbTargetDeviceCreateUrb, määritä sama WDFUSBDEVICE-kahva kehyksen kohdeobjektille näissä menetelmäkutsuissa.

  • GUID määritetty GUID_USB_CAPABILITY_STATIC_STREAMS;
  • Osoita lähtöpuskuriin (osoitti USHORT). Kun se on valmis, puskuri täytetään (virtojen enimmäismäärä) jokaisella isäntäohjaimen tukemalla päätepisteellä;
  • Tulostuspuskurin pituus tavuina. Virtojen pituus on sizeof (USHORT);

2. Arvioi palautettu NTSTATUS-arvo. Jos rutiini valmistuu onnistuneesti, palautetaan STATUS_SUCCESS ja staattista suoratoistotoimintoa tuetaan. Muussa tapauksessa menetelmä palauttaa oikean virhekoodin.

3. Määritä avattavien streamien määrä. Avattavien streamien enimmäismäärää rajoittaa:

  • Isäntäohjaimen tukemien streamien enimmäismäärä. WdfUsbTargetDeviceQueryUsbCapability (vastaanottaa WdfUsbTargetDeviceQueryUsbCapabilityUSBD_QueryUsbCapability) soittajan toimittamassa lähtöpuskurissa. Microsoftin tarjoama USB-ohjainpino tukee jopa 255 streamia. WdfUsbTargetDeviceQueryUsbCapability ottaa tämän rajan huomioon laskettaessa streamien määrää. Menetelmä ei koskaan palauta arvoa, joka on suurempi kuin 255.
  • Laitteen päätepisteen tukemien suoratoistojen enimmäismäärä. Saat tämän numeron tarkistamalla USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR päätepisteen täydentävän kuvauksen (Usbspec.h:ssa). Päätepisteen kumppanikuvaajan saamiseksi kokoonpanokuvaaja on jäsennettävä. Konfiguraatiokuvaajan saamiseksi asiakasohjaimen on kutsuttava WdfUsbTargetDeviceRetrieveConfigDescriptor-metodi. Apurirutiineja, USBD_ParseConfigurationDescriptorEx ja USBD_ParseDescriptor, on käytettävä.

Voit määrittää virtojen enimmäismäärän valitsemalla pienempi kahdesta isäntäohjaimen ja päätepisteen tukemasta arvosta.

4. Varaa joukko n-elementtejä USBD_STREAM_INFORMATION-rakenteita, missä n on avattavien tietovirtojen määrä. Asiakasohjain on vastuussa tämän taulukon vapauttamisesta sen jälkeen, kun ohjain on käyttänyt streamia.

5. Varaa avoimen virran pyynnölle URB kutsumalla WdfUsbTargetDeviceCreateUrb-menetelmää. Jos puhelu päättyy onnistuneesti, menetelmä hakee WDF-muistiobjektin ja USB-ohjainpinon allokoiman URB-rakenteen osoitteen.

WDM-ohjain: Kutsuu USBD_UrbAllocate-rutiinia.

6. Aseta avoimen streamin pyynnön URB-muoto. URB käyttää _URB_OPEN_STATIC_STREAMS-rakennetta pyyntöjen määrittämiseen. URB:n muotoilemiseen tarvitset:

  • USBD-putken kahva, joka osoittaa päätepisteeseen. Jos WDF-putkiobjekti on olemassa, voit saada USBD-putkikahvan kutsumalla WdfUsbTargetPipeWdmGetPipeHandle-menetelmää.
  • Luotu vaiheessa 4 (stream array)
  • Osoitin (vaihe 5) luotuun URB-rakenteeseen.

Muotoile URB soittamalla UsbBuildOpenStaticStreamsRequest ja välitä vaaditut tiedot parametriarvoina. Varmista, että UsbBuildOpenStaticStreamsRequestille määritetty streamien määrä ei ylitä tuettujen suoratoistojen enimmäismäärää.

7. Lähetä URB WDF-pyyntöobjektina kutsumalla WdfRequestSend-menetelmää. Jos haluat lähettää pyynnön synkronisesti, kutsu sen sijaan menetelmää WdfUsbTargetDeviceSendUrbSynchronously.

WDM-ohjain: yhdistää URB:n IRP:hen ja lähettää IRP:n USB-ohjainpinoon.

8. Kun pyyntö on valmis, tarkista pyynnön tila.Jos USB-ohjaimen pinopyyntö epäonnistuu, URB-tila sisältää asiaankuuluvan virhekoodin.

Jos pyynnön tila (IRP- tai WDF-pyyntöobjekti) osoittaa USBD_STATUS_SUCCESS, pyyntö on suoritettu onnistuneesti. Joukko USBD_STREAM_INFORMATION-rakenteita vastaanotettu, kun tarkistus on valmis. Taulukko on täytetty pyydetyn streamin tiedoilla. USB-ohjainpino täyttää jokaisen taulukon rakenteen tietovirtatiedoilla, kuten USBD_PIPE_HANDLE vastaanotetun kahvan, virran tunnisteen ja numeerisen enimmäissiirtokoon. Stream voi nyt siirtää tietoja.

Avoimen streamin pyyntöjä varten on allokoitava URB:t ja taulukot. Kun avoimen virran pyyntö on suoritettu, asiakasohjaimen on vapautettava URB kutsumalla WdfObjectDelete-menetelmä kyseisessä WDF-muistiobjektissa. Jos ajuri lähettää pyynnön synkronisesti kutsumalla WdfUsbTargetDeviceSendUrbSynchronously, WDF-muistiobjekti on vapautettava menetelmän palattua. Jos asiakasohjain lähettää pyynnön asynkronisesti kutsumalla WdfRequestSendiä, ohjaimen on vapautettava WDF-muistiobjekti pyyntöön liittyvässä ohjaimen toteuttamassa viimeistelyrutiinissa.

Tietovirtataulukko voidaan vapauttaa sen jälkeen, kun asiakasohjain on lopettanut virran käytön, tai se voidaan tallentaa I/O-pyyntöjä varten. Alla olevassa koodiesimerkissä ohjain tallentaa virtataulukon laitekontekstiin. Ajuri vapauttaa laitekontekstin ennen laiteobjektin vapauttamista.

Kuinka siirtää tietoja tiettyyn streamiin
Tiedonsiirtopyynnön lähettämiseksi tiettyyn tietovirtaan tarvitaan WDF-pyyntöobjekti. Tyypillisesti asiakasohjaimien ei tarvitse varata WDF-pyyntöobjekteja. Kun I/O-manageri vastaanottaa pyynnön sovelluksesta, I/O-manageri luo pyynnölle IRP:n. Puitteet sieppasivat IRP:n. Tämän jälkeen kehys varaa WDF-pyyntöobjektin edustamaan IRP:tä. Tämän jälkeen kehys välittää WDF-pyyntöobjektin asiakasohjaimelle. Asiakasohjain voi sitten liittää pyyntöobjektin tiedonsiirto-URB:hen ja lähettää sen USB-ohjainpinoon.

Jos asiakasohjain ei vastaanota WDF-pyyntöobjektia viitekehyksestä ja haluaa lähettää pyynnön asynkronisesti, ohjaimen on varattava WDF-pyyntöobjekti kutsumalla WdfRequestCreate-menetelmää. Muotoile uusi objekti kutsumalla WdfUsbTargetPipeFormatRequestForUrb ja lähetä pyyntö kutsumalla WdfRequestSend.

Synkronisessa tapauksessa WDF-pyyntöobjektin välittäminen on valinnaista.

Tietojen siirtämiseksi streamiin on käytettävä URB:tä. URB on alustettava kutsumalla WdfUsbTargetPipeFormatRequestForUrb.

Streamit eivät tue seuraavia WDF-menetelmiä:

  • WdfUsbTargetPipeFormatRequestForRead
  • WdfUsbTargetPipeFormatRequestForWrite
  • WdfUsbTargetPipeReadSynchronously
  • WdfUsbTargetPipeWriteSynchronously

Seuraava menettely olettaa, että asiakasohjain vastaanottaa pyyntöobjektin viitekehyksestä.

  1. Varaa URB kutsumalla WdfUsbTargetDeviceCreateUrb. Tämä menetelmä varaa WDF-muistiobjektin, joka sisältää juuri varatun URB:n. Asiakasohjaimet voivat allokoida URB:n jokaiselle I/O-pyynnölle tai allokoida URB:n ja käyttää sitä samantyyppisiin pyyntöihin.
  2. Muotoile URB joukkosiirtoa varten soittamalla UsbBuildInterruptOrBulkTransferRequest. Määritä PipeHandle-parametrissa virran kahva. Virtauskahva saadaan edellisestä pyynnöstä, kuten on kuvattu kohdassa Staattisen virran avaaminen.
  3. Muotoile WDF-pyyntöobjekti kutsumalla WdfUsbTargetPipeFormatRequestForUrb-metodia. Määritä kutsussa tiedonsiirto URB:n sisältävä WDF-muistiobjekti. Muistiobjekti allokoitiin vaiheessa 1.
  4. Lähetä URB WDF-pyynnönä kutsumalla WdfRequestSend tai WdfUsbTargetPipeSendUrbSynchronously. Jos kutsut WdfRequestSendiä, sinun on määritettävä viimeistelyrutiini kutsumalla WdfRequestSetCompletionRoutine, jotta asiakasohjain voidaan ilmoittaa, kun asynkroninen toiminto on valmis. Tiedonsiirto URB on vapautettava viimeistelyrutiinissa.

WDM-ohjain: Varaa URB:n kutsumalla USBD_UrbAllocate ja alustaa sen joukkosiirtoa varten (katso _URB_BULK_OR_INTERRUPT_TRANSFER). Voit muotoilla URB:n kutsumalla UsbBuildInterruptOrBulkTransferRequest tai muotoilemalla URB-rakenteen manuaalisesti. Määritä virran kahva URB:n UrbBulkOrInterruptTransfer.PipeHandle-jäsenessä.

Staattisen virran sulkeminen

Asiakasohjain voi sulkea streamin, kun ohjain on lopettanut sen käytön. Suoratoistopyynnön sulkeminen on kuitenkin valinnaista. USB-ohjainpino sulkee kaikki streamit, kun streamiin liittyvää päätepistettä ei ole määritetty. Päätepisteitä ei määritetä, kun valitaan vaihtoehtoinen kokoonpano tai käyttöliittymä, poistetaan laitetta jne. Jos asiakasohjain haluaa avata eri määrän streameja, sen on suljettava streamit. Lähetä streamin sulkemispyyntö:

1. Varaa URB-rakenne kutsumalla WdfUsbTargetDeviceCreateUrb.

2. Aseta URB-muoto suoratoistopyynnön sulkemista varten. URB-rakenteen UrbPipeRequest-jäsen on _URB_PIPE_REQUEST-rakenne. Täytä sen jäsenet seuraavasti:

  • Pakollinen URB_FUNCTION_CLOSE_STATIC_STREAMS_URB_PIPE_REQUEST Hdr-jäsen
  • PipeHandle-osan on oltava kahva, joka sisältää päätepisteen, jota käytetään virran avaamiseen.

3. Lähetä URB WDF-pyynnönä soittamalla WdfUsbTargetDeviceSendUrbSynchronously.

Sulje kahva pyytää sulkemaan kaikki asiakasohjaimen aiemmin avaamat virrat. Asiakasohjain ei voi käyttää pyyntöjä tietyn virran sulkemiseen päätepisteessä.

Parhaat käytännöt staattisten suoratoistopyyntöjen lähettämiseen

USB-ohjainpino tarkistaa vastaanotetun URB:n. Vahvistusvirheiden välttämiseksi toimi seuraavasti:

  • Älä lähetä avoimen streamin tai streamin sulkemispyyntöjä päätepisteille, jotka eivät tue streameja. Soita WDM-ohjaimen WdfUsbTargetDeviceQueryUsbCapability-palveluun (USBD_QueryUsbCapability) määrittääksesi staattisen suoratoiston tuen ja lähettääksesi suoratoistopyyntöjä vain, jos päätepiste tukee sitä.
  • Älä pyydä enempää streameja (avoimia) kuin tuettujen streamien enimmäismäärä tai lähetä pyyntöä määrittämättä suoratoistojen määrää. Virtojen määrä määräytyy USB-ohjainpinon ja laitteen päätepisteen tukemien streamien lukumäärän perusteella.
  • Älä lähetä avoimen streamin pyyntöä päätepisteeseen, jolla on jo avoin stream.
  • Älä lähetä streamin sulkemispyyntöä päätepisteeseen, jossa ei ole avointa streamia.
  • Kun olet avannut staattisen virran päätepisteelle, älä lähetä I/O-pyyntöjä käyttämällä päätepisteputken kahvaa, joka on saatu valintakokoonpanon tai valintaliittymäpyynnön kautta. Tämä on totta, vaikka staattinen virta olisi suljettu.
Nollaa ja keskeytä liukuhihnatoiminnot

Joskus siirrot päätepisteeseen tai päätepisteestä voivat epäonnistua. Tällaiset virheet voivat johtua päätepisteen tai isäntäohjaimen virheolosuhteista, kuten pysäytys- tai pysäytystila. Virhetilan poistamiseksi asiakasohjain ensin peruuttaa odottavan siirron ja nollaa sitten päätepisteeseen liittyvän putken. Odottavan siirron peruuttamiseksi asiakasohjain voi lähettää keskeytysputken pyynnön. Putken nollaamiseksi asiakasohjaimen on lähetettävä putken nollauspyyntö.

Suoratoiston keskeyttämis- ja reset-pipe-pyyntöjä ei tueta joukkopäätepisteeseen liittyville yksittäisille virroille. Jos siirto tietyssä stream-putkessa epäonnistuu, isäntäohjain lopettaa kaikkien muiden putkien siirrot Virhetilanteen korjaamiseksi, asiakasohjaimen on peruutettava siirto jokaiseen tietovirtaan putken kahva, joka lähettää nollauspyynnön joukkopäätepisteeseen. Tätä pyyntöä varten asiakasohjaimen on määritettävä päätepisteen putken kahva rakenteessa _URB_PIPE_REQUEST ja asetettava URB-funktioksi (Hdr.Function) URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL.

Täydellinen esimerkki

Seuraava koodiesimerkki havainnollistaa streamin avaamisen.

  1. NTSTATUS
  2. OpenStreams (
  3. _In_ WDFDEVICE Device,
  4. _In_ WDFUSBPIPE Pipe)
  5. {
  6. NTSTATUS status;
  7. PDEVICE_CONTEXT deviceContext;
  8. PPIPE_CONTEXT pipeContext;
  9. USHORT cStreams = 0;
  10. USBD_PIPE_HANDLE usbdPipeHandle;
  11. WDFMEMORY urbMemory = NULL;
  12. PURB urb = NULL;
  13. PAGED_CODE();
  14. deviceContext =GetDeviceContext(Device);
  15. pipeContext = GetPipeContext (Pipe);
  16. if (deviceContext->MaxStreamsController == 0)
  17. {
  18. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  19. "%!FUNC! Static streams are not supported.");
  20. status = STATUS_NOT_SUPPORTED;
  21. goto Exit;
  22. }
  23. // If static streams are not supported, number of streams supported is zero.
  24. if (pipeContext->MaxStreamsSupported == 0)
  25. {
  26. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  27. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  28. "%!FUNC! Static streams are not supported by the endpoint.");
  29. goto Exit;
  30. }
  31. // Determine the number of streams to open.
  32. // Compare the number of streams supported by the endpoint with the
  33. // number of streams supported by the host controller, and choose the
  34. // lesser of the two values. The deviceContext->MaxStreams value was
  35. // obtained in a previous call to WdfUsbTargetDeviceQueryUsbCapability
  36. // that determined whether or not static streams is supported and
  37. // retrieved the maximum number of streams supported by the
  38. // host controller. The device context stores the values for IN and OUT
  39. // endpoints.
  40. // Allocate an array of USBD_STREAM_INFORMATION structures to store handles to streams.
  41. // The number of elements in the array is the number of streams to open.
  42. // The code snippet stores the array in its device context.
  43. cStreams = min(deviceContext->MaxStreamsController, pipeContext->MaxStreamsSupported);
  44. // Allocate an array of streams associated with the IN bulk endpoint
  45. // This array is released in CloseStreams.
  46. pipeContext->StreamInfo = (PUSBD_STREAM_INFORMATION) ExAllocatePoolWithTag (
  47. NonPagedPool,
  48. sizeof (USBD_STREAM_INFORMATION) * cStreams,
  49. USBCLIENT_TAG);
  50. if (pipeContext->StreamInfo == NULL)
  51. {
  52. status = STATUS_INSUFFICIENT_RESOURCES;
  53. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  54. "%!FUNC! Could not allocate stream information array.");
  55. goto Exit;
  56. }
  57. RtlZeroMemory (pipeContext->StreamInfo,
  58. sizeof (USBD_STREAM_INFORMATION) * cStreams);
  59. // Get USBD pipe handle from the WDF target pipe object. The client driver received the
  60. // endpoint pipe handles during device configuration.
  61. usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle (Pipe);
  62. // Allocate an URB for the open streams request.
  63. // WdfUsbTargetDeviceCreateUrb returns the address of the
  64. // newly allocated URB and the WDFMemory object that
  65. // contains the URB.
  66. status = WdfUsbTargetDeviceCreateUrb (
  67. deviceContext->UsbDevice,
  68. NULL,
  69. &urbMemory,
  70. &urb);
  71. if (status != STATUS_SUCCESS)
  72. {
  73. TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
  74. "%!FUNC! Could not allocate URB for an open-streams request.");
  75. goto Exit;
  76. }
  77. // Format the URB for the open-streams request.
  78. // The UsbBuildOpenStaticStreamsRequest inline function formats the URB by specifying the
  79. // pipe handle to the entire bulk endpoint, number of streams to open, and the array of stream structures.
  80. UsbBuildOpenStaticStreamsRequest (
  81. urb,
  82. usbdPipeHandle,
  83. (USHORT)cStreams,
  84. pipeContext->StreamInfo);
  85. // Send the request synchronously.
  86. // Upon completion, the USB driver stack populates the array of with handles to streams.
  87. status = WdfUsbTargetPipeSendUrbSynchronously (
  88. Pipe,
  89. NULL,
  90. NULL,
  91. urb);
  92. if (status != STATUS_SUCCESS)
  93. {
  94. goto Exit;
  95. }
  96. Exit:
  97. if (urbMemory)
  98. {
  99. WdfObjectDelete (urbMemory);
  100. }
  101. return status;
  102. }