1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxUsbDeviceAPI.cpp
8 
9 Abstract:
10 
11 
12 Author:
13 
14 Environment:
15 
16     Both kernel and user mode
17 
18 Revision History:
19 
20 --*/
21 
22 #include "fxusbpch.hpp"
23 
24 extern "C" {
25 #include "FxUsbDeviceAPI.tmh"
26 }
27 
28 //
29 // Extern "C" all APIs
30 //
31 extern "C" {
32 
33 _Must_inspect_result_
34 __drv_maxIRQL(PASSIVE_LEVEL)
35 NTSTATUS
36 WDFAPI
37 FxUsbTargetDeviceCreate(
38     __in
39     PFX_DRIVER_GLOBALS FxDriverGlobals,
40     __in
41     FxDeviceBase* Device,
42     __in
43     ULONG USBDClientContractVersion,
44     __in_opt
45     PWDF_OBJECT_ATTRIBUTES Attributes,
46     __out
47     WDFUSBDEVICE* UsbDevice
48     )
49 /*++
50 
51 Routine Description:
52     Creates a WDFUSBDEVICE handle for the client.
53 
54 Arguments:
55 
56     Device - FxDeviceBase object
57 
58     USBDClientContractVersion - The USBD Client Contract version of the client driver
59 
60     UsbDevice - Pointer which will receive the created handle
61 
62 Return Value:
63     STATUS_SUCCESS - success
64     STATUS_INSUFFICIENT_RESOURCES - no memory available
65     ...
66 
67   --*/
68 {
69     FxUsbDevice* pUsbDevice;
70     NTSTATUS status;
71 
72     //
73     // Basic parameter validation
74     //
75 
76     FxPointerNotNull(FxDriverGlobals, UsbDevice);
77     *UsbDevice = NULL;
78 
79     status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL);
80     if (!NT_SUCCESS(status)) {
81         return status;
82     }
83 
84     status = FxValidateObjectAttributes(FxDriverGlobals,
85                                         Attributes,
86                                         FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
87     if (!NT_SUCCESS(status)) {
88         return status;
89     }
90 
91     pUsbDevice = new(FxDriverGlobals, Attributes) FxUsbDevice(FxDriverGlobals);
92     if (pUsbDevice == NULL) {
93         return STATUS_INSUFFICIENT_RESOURCES;
94     }
95 
96     //
97     // Perform all init and handle creation functions.  Check for error at the
98     // end and clean up there.
99     //
100     status = pUsbDevice->Init(Device);
101 
102     if (NT_SUCCESS(status)) {
103         WDFOBJECT device;
104 
105         device = NULL;
106 
107         status = pUsbDevice->InitDevice(USBDClientContractVersion);
108 
109         if (NT_SUCCESS(status)) {
110             status = pUsbDevice->CreateInterfaces();
111         }
112 
113         if (NT_SUCCESS(status)) {
114             status = Device->AddIoTarget(pUsbDevice);
115         }
116 
117         if (NT_SUCCESS(status)) {
118             status = pUsbDevice->Commit(Attributes, &device, Device);
119         }
120 
121         if (NT_SUCCESS(status)) {
122             *UsbDevice = (WDFUSBDEVICE) device;
123         }
124     }
125 
126     if (!NT_SUCCESS(status)) {
127         //
128         // And now free it
129         //
130         pUsbDevice->DeleteFromFailedCreate();
131     }
132 
133     return status;
134 }
135 
136 _Must_inspect_result_
137 __drv_maxIRQL(PASSIVE_LEVEL)
138 NTSTATUS
139 WDFAPI
140 WDFEXPORT(WdfUsbTargetDeviceCreate)(
141     __in
142     PWDF_DRIVER_GLOBALS DriverGlobals,
143     __in
144     WDFDEVICE Device,
145     __in_opt
146     PWDF_OBJECT_ATTRIBUTES Attributes,
147     __out
148     WDFUSBDEVICE* UsbDevice
149     )
150 /*++
151 
152 Routine Description:
153     Creates a WDFUSBDEVICE handle for the client.
154 
155 Arguments:
156     Device - WDFDEVICE handle to which we are attaching the WDFUSBDEVICE handle
157         to
158     PUsbDevice - Pointer which will receive the created handle
159 
160 Return Value:
161     STATUS_SUCCESS - success
162     STATUS_INSUFFICIENT_RESOURCES - no memory available
163     ...
164 
165   --*/
166 {
167     DDI_ENTRY();
168 
169     PFX_DRIVER_GLOBALS pFxDriverGlobals;
170     FxDeviceBase* pDevice;
171 
172     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
173                                    Device,
174                                    FX_TYPE_DEVICE_BASE,
175                                    (PVOID*)&pDevice,
176                                    &pFxDriverGlobals);
177 
178     return FxUsbTargetDeviceCreate(pFxDriverGlobals,
179                                    pDevice,
180                                    USBD_CLIENT_CONTRACT_VERSION_INVALID,
181                                    Attributes,
182                                    UsbDevice);
183 }
184 
185 __checkReturn
186 __drv_maxIRQL(PASSIVE_LEVEL)
187 NTSTATUS
188 WDFAPI
189 WDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)(
190     __in
191     PWDF_DRIVER_GLOBALS DriverGlobals,
192     __in
193     WDFDEVICE Device,
194     __in
195     PWDF_USB_DEVICE_CREATE_CONFIG Config,
196     __in_opt
197     PWDF_OBJECT_ATTRIBUTES Attributes,
198     __out
199     WDFUSBDEVICE* UsbDevice
200     )
201 /*++
202 
203 Routine Description:
204     Creates a WDFUSBDEVICE handle for the client.
205 
206 Arguments:
207     Device - WDFDEVICE handle to which we are attaching the WDFUSBDEVICE handle
208         to
209     PUsbDevice - Pointer which will receive the created handle
210 
211 Return Value:
212     STATUS_SUCCESS - success
213     STATUS_INSUFFICIENT_RESOURCES - no memory available
214     ...
215 
216   --*/
217 {
218     DDI_ENTRY();
219 
220     PFX_DRIVER_GLOBALS pFxDriverGlobals;
221     FxDeviceBase* pDevice;
222     NTSTATUS status;
223 
224     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
225                                    Device,
226                                    FX_TYPE_DEVICE_BASE,
227                                    (PVOID*)&pDevice,
228                                    &pFxDriverGlobals);
229 
230     FxPointerNotNull(pFxDriverGlobals, Config);
231 
232     if (Config->Size != sizeof(WDF_USB_DEVICE_CREATE_CONFIG)) {
233         status = STATUS_INFO_LENGTH_MISMATCH;
234 
235         DoTraceLevelMessage(
236             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
237             "WDF_USB_DEVICE_CREATE_CONFIG Size 0x%x, expected 0x%x, %!STATUS!",
238             Config->Size, sizeof(WDF_USB_DEVICE_CREATE_CONFIG), status);
239 
240         return status;
241     }
242 
243     return FxUsbTargetDeviceCreate(pFxDriverGlobals,
244                                    pDevice,
245                                    Config->USBDClientContractVersion,
246                                    Attributes,
247                                    UsbDevice);
248 }
249 
250 _Must_inspect_result_
251 __drv_maxIRQL(DISPATCH_LEVEL)
252 NTSTATUS
253 WDFAPI
254 WDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)(
255     __in
256     PWDF_DRIVER_GLOBALS DriverGlobals,
257     __in
258     WDFUSBDEVICE UsbDevice,
259     __out
260     PWDF_USB_DEVICE_INFORMATION Information
261     )
262 {
263     DDI_ENTRY();
264 
265     PFX_DRIVER_GLOBALS pFxDriverGlobals;
266     FxUsbDevice* pUsbDevice;
267     NTSTATUS status;
268 
269     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
270                                    UsbDevice,
271                                    FX_TYPE_IO_TARGET_USB_DEVICE,
272                                    (PVOID*) &pUsbDevice,
273                                    &pFxDriverGlobals);
274 
275     FxPointerNotNull(pFxDriverGlobals, Information);
276 
277     if (Information->Size != sizeof(WDF_USB_DEVICE_INFORMATION)) {
278         status = STATUS_INFO_LENGTH_MISMATCH;
279         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
280                             "Information size %d, expected %d %!STATUS!",
281                             Information->Size, sizeof(WDF_USB_DEVICE_INFORMATION),
282                             status);
283         return status;
284     }
285 
286     pUsbDevice->GetInformation(Information);
287 
288     return STATUS_SUCCESS;
289 }
290 
291 __drv_maxIRQL(PASSIVE_LEVEL)
292 VOID
293 WDFAPI
294 WDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)(
295     __in
296     PWDF_DRIVER_GLOBALS DriverGlobals,
297     __in
298     WDFUSBDEVICE UsbDevice,
299     __out
300     PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor
301     )
302 {
303     DDI_ENTRY();
304 
305     PFX_DRIVER_GLOBALS pFxDriverGlobals;
306     FxUsbDevice* pUsbDevice;
307     NTSTATUS status;
308 
309     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
310                                    UsbDevice,
311                                    FX_TYPE_IO_TARGET_USB_DEVICE,
312                                    (PVOID*) &pUsbDevice,
313                                    &pFxDriverGlobals);
314 
315     FxPointerNotNull(pFxDriverGlobals, UsbDeviceDescriptor);
316 
317     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
318     if (!NT_SUCCESS(status)) {
319         return;
320     }
321 
322     pUsbDevice->CopyDeviceDescriptor(UsbDeviceDescriptor);
323 }
324 
325 _Must_inspect_result_
326 __drv_maxIRQL(PASSIVE_LEVEL)
327 NTSTATUS
328 WDFAPI
329 WDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)(
330     __in
331     PWDF_DRIVER_GLOBALS DriverGlobals,
332     __in
333     WDFUSBDEVICE UsbDevice,
334     __out_bcount_part_opt(*ConfigDescriptorLength, *ConfigDescriptorLength)
335     PVOID ConfigDescriptor,
336     __inout
337     PUSHORT ConfigDescriptorLength
338     )
339 {
340     DDI_ENTRY();
341 
342     PFX_DRIVER_GLOBALS pFxDriverGlobals;
343     FxUsbDevice* pUsbDevice;
344     NTSTATUS status;
345 
346     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
347                                    UsbDevice,
348                                    FX_TYPE_IO_TARGET_USB_DEVICE,
349                                    (PVOID*) &pUsbDevice,
350                                    &pFxDriverGlobals);
351 
352     FxPointerNotNull(pFxDriverGlobals, ConfigDescriptorLength);
353 
354     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
355     if (!NT_SUCCESS(status)) {
356         return status;
357     }
358 
359     return pUsbDevice->GetConfigDescriptor(ConfigDescriptor,
360                                            ConfigDescriptorLength);
361 }
362 
363 _Must_inspect_result_
364 __drv_maxIRQL(PASSIVE_LEVEL)
365 NTSTATUS
366 WDFAPI
367 WDFEXPORT(WdfUsbTargetDeviceQueryString)(
368     __in
369     PWDF_DRIVER_GLOBALS DriverGlobals,
370     __in
371     WDFUSBDEVICE UsbDevice,
372     __in_opt
373     WDFREQUEST Request,
374     __in_opt
375     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
376     __out_ecount_opt(*NumCharacters)
377     PUSHORT String,
378     __inout
379     PUSHORT NumCharacters,
380     __in
381     UCHAR StringIndex,
382     __in_opt
383     USHORT LangID
384     )
385 {
386     DDI_ENTRY();
387 
388     PFX_DRIVER_GLOBALS pFxDriverGlobals;
389     FxUsbDevice* pUsbDevice;
390     NTSTATUS status;
391 
392     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
393                                    UsbDevice,
394                                    FX_TYPE_IO_TARGET_USB_DEVICE,
395                                    (PVOID*) &pUsbDevice,
396                                    &pFxDriverGlobals);
397 
398     FxPointerNotNull(pFxDriverGlobals, NumCharacters);
399 
400     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
401     if (!NT_SUCCESS(status)) {
402         return status;
403     }
404 
405     status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions);
406     if (!NT_SUCCESS(status)) {
407         return status;
408     }
409 
410     status = pUsbDevice->GetString(String,
411                                    NumCharacters,
412                                    StringIndex,
413                                    LangID,
414                                    Request,
415                                    RequestOptions);
416 
417     return status;
418 }
419 
420 _Must_inspect_result_
421 __drv_maxIRQL(PASSIVE_LEVEL)
422 NTSTATUS
423 WDFAPI
424 WDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)(
425     __in
426     PWDF_DRIVER_GLOBALS DriverGlobals,
427     __in
428     WDFUSBDEVICE UsbDevice,
429     __in_opt
430     PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes,
431     __out
432     WDFMEMORY*   StringMemory,
433     __out_opt
434     PUSHORT NumCharacters,
435     __in
436     UCHAR StringIndex,
437     __in_opt
438     USHORT LangID
439     )
440 {
441     DDI_ENTRY();
442 
443     PFX_DRIVER_GLOBALS pFxDriverGlobals;
444     WDFMEMORY hMemory;
445     FxUsbDevice* pUsbDevice;
446     NTSTATUS status;
447     USHORT numChars = 0;
448 
449     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
450                                    UsbDevice,
451                                    FX_TYPE_IO_TARGET_USB_DEVICE,
452                                    (PVOID*) &pUsbDevice,
453                                    &pFxDriverGlobals);
454 
455     FxPointerNotNull(pFxDriverGlobals, StringMemory);
456 
457     *StringMemory = NULL;
458     if (NumCharacters != NULL) {
459         *NumCharacters = 0;
460     }
461 
462     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
463     if (!NT_SUCCESS(status)) {
464         return status;
465     }
466 
467     status = FxValidateObjectAttributes(pFxDriverGlobals, StringMemoryAttributes);
468     if (!NT_SUCCESS(status)) {
469         return status;
470     }
471 
472     status = pUsbDevice->GetString(NULL, &numChars, StringIndex, LangID);
473 
474     if (NT_SUCCESS(status) && numChars > 0) {
475         FxMemoryObject* pBuffer;
476 
477         status = FxMemoryObject::_Create(pFxDriverGlobals,
478                                          StringMemoryAttributes,
479                                          NonPagedPool,
480                                          pFxDriverGlobals->Tag,
481                                          numChars * sizeof(WCHAR),
482                                          &pBuffer);
483 
484         if (!NT_SUCCESS(status)) {
485             return STATUS_INSUFFICIENT_RESOURCES;
486         }
487 
488         status = pBuffer->Commit(StringMemoryAttributes,
489                                  (WDFOBJECT*)&hMemory);
490 
491         if (NT_SUCCESS(status)) {
492             status = pUsbDevice->GetString((PUSHORT) pBuffer->GetBuffer(),
493                                            &numChars,
494                                            StringIndex,
495                                            LangID);
496 
497             if (NT_SUCCESS(status)) {
498                 if (NumCharacters != NULL) {
499                     *NumCharacters  = numChars;
500                 }
501                 *StringMemory = hMemory;
502             }
503         }
504 
505         if (!NT_SUCCESS(status)) {
506             //
507             // There can only be one context on this object right now,
508             // so just clear out the one.
509             //
510             pBuffer->DeleteFromFailedCreate();
511         }
512     }
513 
514     return status;
515 }
516 
517 _Must_inspect_result_
518 __drv_maxIRQL(DISPATCH_LEVEL)
519 NTSTATUS
520 WDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)(
521     __in
522     PWDF_DRIVER_GLOBALS DriverGlobals,
523     __in
524     WDFUSBDEVICE UsbDevice,
525     __in
526     WDFREQUEST Request,
527     __in
528     WDFMEMORY Memory,
529     __in_opt
530     PWDFMEMORY_OFFSET Offset,
531     __in
532     UCHAR StringIndex,
533     __in_opt
534     USHORT LangID
535     )
536 /*++
537 
538 Routine Description:
539     Formats a request so that it can be used to query for a string  from the
540     device.
541 
542 Arguments:
543     UsbDevice - device to be queried
544 
545     Request - request to format
546 
547     Memory - memory to write the string into
548 
549 
550 Return Value:
551 
552 
553   --*/
554 
555 {
556     DDI_ENTRY();
557 
558     PFX_DRIVER_GLOBALS pFxDriverGlobals;
559     IFxMemory* pMemory;
560     FxUsbDevice* pUsbDevice;
561     FxRequestBuffer buf;
562     FxRequest* pRequest;
563     NTSTATUS status;
564     size_t bufferSize;
565 
566     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
567                                    UsbDevice,
568                                    FX_TYPE_IO_TARGET_USB_DEVICE,
569                                    (PVOID*) &pUsbDevice,
570                                    &pFxDriverGlobals);
571 
572     DoTraceLevelMessage(
573         pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
574         "WDFUSBDEVICE %p, WDFREQUEST %p, WDFMEMORY %p, StringIndex %d, LandID 0x%x",
575         UsbDevice, Request, Memory, StringIndex, LangID);
576 
577     FxObjectHandleGetPtr(pFxDriverGlobals,
578                          Memory,
579                          IFX_TYPE_MEMORY,
580                          (PVOID*) &pMemory);
581 
582     FxObjectHandleGetPtr(pFxDriverGlobals,
583                          Request,
584                          FX_TYPE_REQUEST,
585                          (PVOID*) &pRequest);
586 
587     status = pMemory->ValidateMemoryOffsets(Offset);
588     if (!NT_SUCCESS(status)) {
589         return status;
590     }
591 
592     buf.SetMemory(pMemory, Offset);
593 
594     bufferSize = buf.GetBufferLength();
595 
596     //
597     // the string descriptor is array of WCHARs so the buffer being used must be
598     // of an integral number of them.
599     //
600     if ((bufferSize % sizeof(WCHAR)) != 0) {
601         status = STATUS_INVALID_PARAMETER;
602 
603         DoTraceLevelMessage(
604             pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
605             "WDFMEMORY %p length must be even number of WCHARs, but is %I64d in "
606             "length, %!STATUS!",
607             Memory, bufferSize, status);
608 
609         return status;
610     }
611 
612     //
613     // While the length in the descriptor (bLength) is a byte, so the requested
614     // buffer cannot be bigger then that, do not check the bufferSize < 0xFF.
615     // We don't check because the driver can be using the WDFMEMORY as a part
616     // of a larger structure.
617     //
618 
619     //
620     // Format the request
621     //
622     status = pUsbDevice->FormatStringRequest(pRequest, &buf, StringIndex, LangID);
623 
624     if (NT_SUCCESS(status)) {
625         FxUsbDeviceStringContext* pContext;
626 
627         pContext = (FxUsbDeviceStringContext*) pRequest->GetContext();
628         pContext->m_UsbParameters.Parameters.DeviceString.Buffer = Memory;
629         pContext->m_UsbParameters.Parameters.DeviceString.StringIndex = StringIndex;
630         pContext->m_UsbParameters.Parameters.DeviceString.LangID = LangID;
631     }
632 
633     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
634                         "WDFUSBDEVICE %p, WDFREQUEST %p, WDFMEMORY %p, %!STATUS!",
635                         UsbDevice, Request, Memory, status);
636 
637     return status;
638 }
639 
640 _Must_inspect_result_
641 __drv_maxIRQL(PASSIVE_LEVEL)
642 NTSTATUS
643 WDFAPI
644 WDFEXPORT(WdfUsbTargetDeviceSelectConfig)(
645     __in
646     PWDF_DRIVER_GLOBALS DriverGlobals,
647     __in
648     WDFUSBDEVICE UsbDevice,
649     __in_opt
650     PWDF_OBJECT_ATTRIBUTES PipesAttributes,
651     __inout
652     PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
653     )
654 {
655     DDI_ENTRY();
656 
657     PFX_DRIVER_GLOBALS pFxDriverGlobals;
658     FxUsbDevice* pUsbDevice;
659     NTSTATUS status;
660 
661     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
662                                    UsbDevice,
663                                    FX_TYPE_IO_TARGET_USB_DEVICE,
664                                    (PVOID*) &pUsbDevice,
665                                    &pFxDriverGlobals);
666 
667     FxPointerNotNull(pFxDriverGlobals, Params);
668 
669     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
670     if (!NT_SUCCESS(status)) {
671         return status;
672     }
673 
674     if (Params->Size != sizeof(WDF_USB_DEVICE_SELECT_CONFIG_PARAMS)) {
675         status = STATUS_INFO_LENGTH_MISMATCH;
676         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
677                             "Params size %d, expected %d %!STATUS!",
678                             Params->Size, sizeof(WDF_USB_DEVICE_SELECT_CONFIG_PARAMS),
679                             status);
680         return status;
681     }
682 
683     //
684     // Sanity check the Type value as well to be in range.
685     //
686     if (Params->Type < WdfUsbTargetDeviceSelectConfigTypeDeconfig
687         ||
688         Params->Type > WdfUsbTargetDeviceSelectConfigTypeUrb) {
689 
690         status = STATUS_INVALID_PARAMETER;
691 
692         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
693                             "Params Type %d not a valid value, %!STATUS!",
694                             Params->Size, status);
695 
696         return status;
697     }
698 
699 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
700     if ((Params->Type == WdfUsbTargetDeviceSelectConfigTypeDeconfig) ||
701         (Params->Type == WdfUsbTargetDeviceSelectConfigTypeUrb) ||
702         (Params->Type == WdfUsbTargetDeviceSelectConfigTypeInterfacesDescriptor)) {
703         status = STATUS_NOT_SUPPORTED;
704 
705         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
706                             "Params Type %d not supported for UMDF, %!STATUS!",
707                             Params->Type, status);
708 
709         return status;
710 
711     }
712 #endif
713 
714     status = FxValidateObjectAttributes(pFxDriverGlobals,
715                                         PipesAttributes,
716                                         FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);
717     if (!NT_SUCCESS(status)) {
718         return status;
719     }
720 
721     if (pUsbDevice->HasMismatchedInterfacesInConfigDescriptor()) {
722         //
723         // Config descriptor reported zero interfaces, but we found an
724         // interface descriptor in it.
725         //
726         status = STATUS_INVALID_DEVICE_REQUEST;
727 
728         DoTraceLevelMessage(
729             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
730             "WDFUSBDEVICE %p number of interfaces found in the config descriptor "
731             "does not match bNumInterfaces in config descriptor, failing config "
732             "operation %!WdfUsbTargetDeviceSelectConfigType!, %!STATUS!",
733             UsbDevice, Params->Type, status);
734 
735         return status;
736     }
737     else if (pUsbDevice->GetNumInterfaces() == 0) {
738         //
739         // Special case the zero interface case and exit early
740         //
741         status = STATUS_SUCCESS;
742 
743         DoTraceLevelMessage(
744             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
745             "WDFUSBDEVICE %p succeeding config operation "
746             "%!WdfUsbTargetDeviceSelectConfigType! on zero interfaces "
747             "immediately, %!STATUS!", UsbDevice, Params->Type, status);
748 
749         return status;
750     }
751 
752     switch (Params->Type) {
753 
754 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
755 
756     case WdfUsbTargetDeviceSelectConfigTypeDeconfig:
757         status = pUsbDevice->Deconfig();
758         break;
759 
760     case WdfUsbTargetDeviceSelectConfigTypeInterfacesDescriptor:
761         if (Params->Types.Descriptor.InterfaceDescriptors == NULL ||
762             Params->Types.Descriptor.NumInterfaceDescriptors == 0) {
763             status = STATUS_INVALID_PARAMETER;
764             DoTraceLevelMessage(
765                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
766                 "Either  InterfaceDescriptor is NULL or  NumInterfaceDescriptors is zero "
767                 "WDFUSBDEVICE %p InterfaceDescriptor %p NumInterfaceDescriptors 0x%x"
768                 "%!WdfUsbTargetDeviceSelectConfigType! %!STATUS!", UsbDevice,
769                 Params->Types.Descriptor.InterfaceDescriptors,
770                 Params->Types.Descriptor.NumInterfaceDescriptors,
771                 Params->Type,
772                 status);
773 
774         }
775         else {
776             status = pUsbDevice->SelectConfigDescriptor(
777                 PipesAttributes,
778                 Params);
779         }
780         break;
781 
782     case WdfUsbTargetDeviceSelectConfigTypeUrb:
783         //
784         // Since the USBD macro's dont include the  USBD_PIPE_INFORMATION for 0 EP's,
785         // make the length check to use
786         // sizeof(struct _URB_SELECT_CONFIGURATION) - sizeof(USBD_PIPE_INFORMATION)
787         //
788         if (Params->Types.Urb.Urb == NULL ||
789             Params->Types.Urb.Urb->UrbHeader.Function != URB_FUNCTION_SELECT_CONFIGURATION ||
790             Params->Types.Urb.Urb->UrbHeader.Length <
791                (sizeof(struct _URB_SELECT_CONFIGURATION) - sizeof(USBD_PIPE_INFORMATION))) {
792             status = STATUS_INVALID_PARAMETER;
793             DoTraceLevelMessage(
794                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
795                 "Either URB passed in was NULL or the URB Function or Length was invalid "
796                 " WDFUSBDEVICE %p Urb 0x%p "
797                 "%!WdfUsbTargetDeviceSelectConfigType!"
798                 " %!STATUS!", UsbDevice,
799                 Params->Types.Urb.Urb,
800                 Params->Type,
801                 status);
802 
803         }
804         else {
805             status = pUsbDevice->SelectConfig(
806                                               PipesAttributes,
807                                               Params->Types.Urb.Urb,
808                                               FxUrbTypeLegacy,
809                                               NULL);
810         }
811         break;
812 
813 #endif
814 
815 
816 
817 
818 
819     case WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs:
820         if (Params->Types.MultiInterface.Pairs == NULL) {
821             status = STATUS_INVALID_PARAMETER;
822 
823             DoTraceLevelMessage(
824                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
825                 "WDFUSBDEVICE %p SettingPairs Array passed is NULL, %!STATUS!",
826                 pUsbDevice->GetHandle(),status);
827 
828             break;
829         }
830         else if (Params->Types.MultiInterface.NumberInterfaces !=
831                                         pUsbDevice->GetNumInterfaces()) {
832             status = STATUS_INVALID_PARAMETER;
833 
834             DoTraceLevelMessage(
835                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
836                 "WDFUSBDEVICE %p MultiInterface.NumberInterfaces %d != %d "
837                 "(reported num interfaces), %!STATUS!",
838                 pUsbDevice->GetHandle(),
839                 Params->Types.MultiInterface.NumberInterfaces,
840                 pUsbDevice->GetNumInterfaces(), status);
841 
842             break;
843         }
844 
845         //    ||      ||   Fall through     ||        ||
846         //    \/      \/                    \/        \/
847     case WdfUsbTargetDeviceSelectConfigTypeMultiInterface:
848 
849         //
850         // Validate SettingIndexes passed-in
851         //
852         for (ULONG i = 0;
853              i < Params->Types.MultiInterface.NumberInterfaces;
854              i++) {
855 
856             PWDF_USB_INTERFACE_SETTING_PAIR  pair;
857             FxUsbInterface * pUsbInterface;
858             UCHAR numSettings;
859 
860             pair = &(Params->Types.MultiInterface.Pairs[i]);
861 
862             FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
863                                  pair->UsbInterface,
864                                  FX_TYPE_USB_INTERFACE,
865                                  (PVOID*) &pUsbInterface);
866 
867             numSettings = pUsbInterface->GetNumSettings();
868 
869             if (pair->SettingIndex >= numSettings) {
870                 status = STATUS_INVALID_PARAMETER;
871 
872                 DoTraceLevelMessage(
873                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
874                     "WDFUSBDEVICE %p SettingPairs contains invalid SettingIndex"
875                     " for WDFUSBINTERFACE %p. Setting index passed in: %d, "
876                     "max index: %d, returning %!STATUS!",
877                     pUsbDevice->GetHandle(),
878                     pair->UsbInterface,
879                     pair->SettingIndex,
880                     pUsbInterface->GetNumSettings() - 1,
881                     status);
882 
883                 return status;
884             }
885         }
886 
887         status = pUsbDevice->SelectConfigMulti(
888             PipesAttributes,
889             Params);
890         break;
891 
892     case WdfUsbTargetDeviceSelectConfigTypeSingleInterface:
893         status = pUsbDevice->SelectConfigSingle(   //vm changed name from  SelectConfigAuto
894             PipesAttributes,
895             Params);
896         break;
897 
898     default:
899         status = STATUS_INVALID_PARAMETER;
900     }
901 
902     return status;
903 }
904 
905 
906 __drv_maxIRQL(DISPATCH_LEVEL)
907 UCHAR
908 WDFAPI
909 WDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)(
910     __in
911     PWDF_DRIVER_GLOBALS DriverGlobals,
912     __in
913     WDFUSBDEVICE UsbDevice
914     )
915 {
916     DDI_ENTRY();
917 
918     FxUsbDevice* pUsbDevice;
919 
920     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
921                          UsbDevice,
922                          FX_TYPE_IO_TARGET_USB_DEVICE,
923                          (PVOID*) &pUsbDevice);
924 
925     return pUsbDevice->GetNumInterfaces();
926 }
927 
928 
929 __drv_maxIRQL(DISPATCH_LEVEL)
930 USBD_CONFIGURATION_HANDLE
931 WDFAPI
932 WDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle)(
933     __in
934     PWDF_DRIVER_GLOBALS DriverGlobals,
935     __in
936     WDFUSBDEVICE UsbDevice
937     )
938 {
939     DDI_ENTRY();
940 
941     FxUsbDevice* pUsbDevice;
942 
943     FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
944                          UsbDevice,
945                          FX_TYPE_IO_TARGET_USB_DEVICE,
946                          (PVOID*) &pUsbDevice);
947 
948     return pUsbDevice->GetConfigHandle();
949 }
950 
951 _Must_inspect_result_
952 __drv_maxIRQL(PASSIVE_LEVEL)
953 NTSTATUS
954 WDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)(
955     __in
956     PWDF_DRIVER_GLOBALS DriverGlobals,
957     __in
958     WDFUSBDEVICE UsbDevice,
959     __in_opt
960     WDFREQUEST Request,
961     __in_opt
962     PWDF_REQUEST_SEND_OPTIONS RequestOptions,
963     __in
964     PWDF_USB_CONTROL_SETUP_PACKET SetupPacket,
965     __in_opt
966     PWDF_MEMORY_DESCRIPTOR MemoryDescriptor,
967     __out_opt
968     PULONG BytesTransferred
969     )
970 /*++
971 
972 Routine Description:
973     Synchronously sends a control transfer to the default control pipe on the
974     device.
975 
976 Arguments:
977     UsbDevice - the target representing the device
978 
979     Request - Request whose PIRP to use
980 
981     RequestOptions - options to use when sending the request
982 
983     SetupPacket - control setup packet to be used in the transfer
984 
985     MemoryDescriptor - memory to use in the transfer after the setup packet
986 
987     BytesTransferred - number of bytes sent to or by the device
988 
989 Return Value:
990     NTSTATUS
991 
992   --*/
993 {
994     DDI_ENTRY();
995 
996     PFX_DRIVER_GLOBALS pFxDriverGlobals;
997     FxUsbDevice* pUsbDevice;
998     NTSTATUS status;
999     FxRequestBuffer buf;
1000 
1001     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1002                                    UsbDevice,
1003                                    FX_TYPE_IO_TARGET_USB_DEVICE,
1004                                    (PVOID*) &pUsbDevice,
1005                                    &pFxDriverGlobals);
1006 
1007     FxUsbDeviceControlContext context(FxUrbTypeLegacy);
1008 
1009     FxSyncRequest request(pFxDriverGlobals, &context, Request);
1010 
1011     //
1012     // FxSyncRequest always succeesds for KM but can fail for UM.
1013     //
1014     status = request.Initialize();
1015     if (!NT_SUCCESS(status)) {
1016         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1017                             "Failed to initialize FxSyncRequest");
1018         return status;
1019     }
1020 
1021     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1022                         "WDFUSBDEVICE %p control transfer sync", UsbDevice);
1023 
1024     FxPointerNotNull(pFxDriverGlobals, SetupPacket);
1025 
1026     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1027     if (!NT_SUCCESS(status)) {
1028         return status;
1029     }
1030 
1031     status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions);
1032     if (!NT_SUCCESS(status)) {
1033         return status;
1034     }
1035 
1036     status = buf.ValidateMemoryDescriptor(
1037         pFxDriverGlobals,
1038         MemoryDescriptor,
1039         MemoryDescriptorNullAllowed | MemoryDescriptorNoBufferAllowed
1040         );
1041 
1042     if (!NT_SUCCESS(status)) {
1043         return status;
1044     }
1045 
1046     status = pUsbDevice->FormatControlRequest(request.m_TrueRequest,
1047                                               SetupPacket,
1048                                               &buf);
1049 
1050     if (NT_SUCCESS(status)) {
1051         DoTraceLevelMessage(
1052             pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1053             "WDFUSBDEVICE %p, WDFREQUEST %p being submitted",
1054             UsbDevice, request.m_TrueRequest->GetTraceObjectHandle());
1055 
1056         status = pUsbDevice->SubmitSync(request.m_TrueRequest, RequestOptions);
1057 
1058         if (BytesTransferred != NULL) {
1059             if (NT_SUCCESS(status)) {
1060 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
1061                 *BytesTransferred = context.m_Urb->TransferBufferLength;
1062 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
1063                 *BytesTransferred = context.m_UmUrb.UmUrbControlTransfer.TransferBufferLength;
1064 #endif
1065             }
1066             else {
1067                 *BytesTransferred = 0;
1068             }
1069         }
1070     }
1071 
1072     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1073                         "WDFUSBDEVICE %p, %!STATUS!", UsbDevice, status);
1074 
1075     return status;
1076 }
1077 
1078 _Must_inspect_result_
1079 __drv_maxIRQL(DISPATCH_LEVEL)
1080 NTSTATUS
1081 WDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)(
1082     __in
1083     PWDF_DRIVER_GLOBALS DriverGlobals,
1084     __in
1085     WDFUSBDEVICE UsbDevice,
1086     __in
1087     WDFREQUEST Request,
1088     __in
1089     PWDF_USB_CONTROL_SETUP_PACKET SetupPacket,
1090     __in_opt
1091     WDFMEMORY TransferMemory,
1092     __in_opt
1093     PWDFMEMORY_OFFSET TransferOffset
1094     )
1095 /*++
1096 
1097 Routine Description:
1098     Formats a request so that a control transfer can be sent to the device
1099     after this call returns successfully.
1100 
1101 Arguments:
1102     UsbDevice - the target representing the device
1103 
1104     Request - Request to format
1105 
1106     SetupPacket - control setup packet to be used in the transfer
1107 
1108     TransferMemory - memory to use in the transfer after the setup packet
1109 
1110     TransferOffset - offset into TransferMemory and size override for transfer
1111                      length
1112 
1113 Return Value:
1114     NTSTATUS
1115 
1116   --*/
1117 {
1118     DDI_ENTRY();
1119 
1120     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1121     IFxMemory* pMemory;
1122     FxUsbDevice* pUsbDevice;
1123     FxRequestBuffer buf;
1124     FxRequest* pRequest;
1125     NTSTATUS status;
1126 
1127     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1128                                    UsbDevice,
1129                                    FX_TYPE_IO_TARGET_USB_DEVICE,
1130                                    (PVOID*) &pUsbDevice,
1131                                    &pFxDriverGlobals);
1132 
1133     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1134                         "WDFUSBDEVICE %p, WDFREQUEST %p, WDFMEMORY %p",
1135                         UsbDevice, Request, TransferMemory);
1136 
1137     FxPointerNotNull(pFxDriverGlobals, SetupPacket);
1138 
1139     if (TransferMemory != NULL) {
1140         FxObjectHandleGetPtr(pFxDriverGlobals,
1141                              TransferMemory,
1142                              IFX_TYPE_MEMORY,
1143                              (PVOID*) &pMemory);
1144 
1145         status = pMemory->ValidateMemoryOffsets(TransferOffset);
1146         if (!NT_SUCCESS(status)) {
1147             return status;
1148         }
1149 
1150         buf.SetMemory(pMemory, TransferOffset);
1151     }
1152     else {
1153         pMemory = NULL;
1154     }
1155 
1156     FxObjectHandleGetPtr(pFxDriverGlobals,
1157                          Request,
1158                          FX_TYPE_REQUEST,
1159                          (PVOID*) &pRequest);
1160 
1161     status = pUsbDevice->FormatControlRequest(pRequest, SetupPacket, &buf);
1162 
1163     if (NT_SUCCESS(status)) {
1164         FxUsbDeviceControlContext* pContext;
1165 
1166         pContext = (FxUsbDeviceControlContext*) pRequest->GetContext();
1167 
1168         RtlCopyMemory(
1169             &pContext->m_UsbParameters.Parameters.DeviceControlTransfer.SetupPacket,
1170             SetupPacket,
1171             sizeof(*SetupPacket)
1172             );
1173 
1174         if (pMemory != NULL) {
1175             pContext->m_UsbParameters.Parameters.DeviceControlTransfer.Buffer =
1176                 TransferMemory;
1177         }
1178     }
1179 
1180     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET,
1181                         "format control request WDFUSBDEVICE %p, WDFREQWUEST %p, WDFMEMORY %p, %!STATUS!",
1182                         UsbDevice, Request, TransferMemory, status);
1183 
1184     return status;
1185 }
1186 
1187 _Must_inspect_result_
1188 __drv_maxIRQL(PASSIVE_LEVEL)
1189 NTSTATUS
1190 WDFAPI
1191 WDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)(
1192     __in
1193     PWDF_DRIVER_GLOBALS DriverGlobals,
1194     __in
1195     WDFUSBDEVICE UsbDevice
1196     )
1197 {
1198     DDI_ENTRY();
1199 
1200     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1201     FxUsbDevice* pUsbDevice;
1202     NTSTATUS status;
1203 
1204     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1205                                    UsbDevice,
1206                                    FX_TYPE_IO_TARGET_USB_DEVICE,
1207                                    (PVOID*) &pUsbDevice,
1208                                    &pFxDriverGlobals);
1209 
1210     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
1211     if (!NT_SUCCESS(status)) {
1212         return status;
1213     }
1214 
1215     status = pUsbDevice->Reset();
1216 
1217     return status;
1218 }
1219 
1220 #pragma warning(disable:28285)
1221 __checkReturn
1222 __drv_maxIRQL(DISPATCH_LEVEL)
1223 NTSTATUS
1224 WDFAPI
1225 WDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb)(
1226     __in
1227     PWDF_DRIVER_GLOBALS DriverGlobals,
1228     __in
1229     WDFUSBDEVICE UsbDevice,
1230     __in_opt
1231     PWDF_OBJECT_ATTRIBUTES Attributes,
1232     __in
1233     ULONG NumberOfIsochPackets,
1234     __out
1235     WDFMEMORY* UrbMemory,
1236     __deref_opt_out_bcount(GET_ISOCH_URB_SIZE(NumberOfIsochPackets))
1237     PURB* Urb
1238     )
1239 /*++
1240 
1241 Routine Description:
1242     Creates a WDFUSBDEVICE handle for the client.
1243 
1244 Arguments:
1245     Attributes - Attributes associated with this object
1246 
1247     NumberOfIsochPacket - Maximum number of Isoch packets that will be programmed into this Urb
1248 
1249     UrbMemory - The returned handle to the caller for the allocated Urb
1250 
1251     Urb - (opt) Pointer to the associated urb buffer.
1252 
1253 Return Value:
1254     STATUS_INVALID_PARAMETER - any required parameters are not present/invalid
1255 
1256     STATUS_INVALID_DEVICE_STATE - If the client did not specify a client contract verion while
1257         creating the WDFUSBDEVICE
1258 
1259     STATUS_INSUFFICIENT_RESOURCES - could not allocated the object that backs
1260         the handle
1261 
1262     STATUS_SUCCESS - success
1263 
1264     ...
1265 
1266   --*/
1267 {
1268     DDI_ENTRY();
1269 
1270     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1271     FxUsbDevice* pUsbDevice;
1272     NTSTATUS status;
1273 
1274     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1275                                    UsbDevice,
1276                                    FX_TYPE_IO_TARGET_USB_DEVICE,
1277                                    (PVOID*) &pUsbDevice,
1278                                    &pFxDriverGlobals);
1279 
1280     //
1281     // Basic parameter validation
1282     //
1283     FxPointerNotNull(pFxDriverGlobals, UrbMemory);
1284 
1285     if (pUsbDevice->GetUSBDHandle() == NULL) {
1286         status = STATUS_INVALID_DEVICE_STATE;
1287 
1288         DoTraceLevelMessage(
1289             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1290             "USBDEVICE Must have been created with Client Contract Verion Info, %!STATUS!",
1291             status);
1292 
1293         return status;
1294     }
1295 
1296     status = pUsbDevice->CreateIsochUrb(Attributes,
1297                                         NumberOfIsochPackets,
1298                                         UrbMemory,
1299                                         Urb);
1300 
1301     return status;
1302 }
1303 
1304 __drv_maxIRQL(DISPATCH_LEVEL)
1305 WDFUSBINTERFACE
1306 WDFAPI
1307 WDFEXPORT(WdfUsbTargetDeviceGetInterface)(
1308     __in
1309     PWDF_DRIVER_GLOBALS DriverGlobals,
1310     __in
1311     WDFUSBDEVICE UsbDevice,
1312     __in
1313     UCHAR InterfaceIndex
1314     )
1315 /*++
1316 
1317 Routine Description:
1318 
1319 
1320 Arguments:
1321 
1322 Return Value:
1323 
1324 
1325   --*/
1326 
1327 {
1328     DDI_ENTRY();
1329 
1330     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1331     FxUsbDevice* pUsbDevice;
1332     FxUsbInterface *pUsbInterface;
1333 
1334     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1335                                    UsbDevice,
1336                                    FX_TYPE_IO_TARGET_USB_DEVICE,
1337                                    (PVOID*) &pUsbDevice,
1338                                    &pFxDriverGlobals);
1339 
1340     pUsbInterface = pUsbDevice->GetInterfaceFromIndex(InterfaceIndex);
1341 
1342     if (pUsbInterface != NULL) {
1343         return pUsbInterface->GetHandle();
1344     }
1345     else {
1346         DoTraceLevelMessage(
1347             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1348             "WDFUSBDEVICE %p has %d interfaces, index %d requested, returning "
1349             "NULL handle",
1350             UsbDevice, pUsbDevice->GetNumInterfaces(), InterfaceIndex);
1351 
1352         return NULL;
1353     }
1354 }
1355 
1356 _Must_inspect_result_
1357 __drv_maxIRQL(PASSIVE_LEVEL)
1358 NTSTATUS
1359 WDFAPI
1360 WDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)(
1361     __in
1362     PWDF_DRIVER_GLOBALS DriverGlobals,
1363     __in
1364     WDFUSBDEVICE UsbDevice,
1365     __in
1366     CONST GUID* CapabilityType,
1367     __in
1368     ULONG CapabilityBufferLength,
1369     __drv_when(CapabilityBufferLength == 0, __out_opt)
1370     __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength))
1371     __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength))
1372     PVOID CapabilityBuffer,
1373     __out_opt
1374     __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength))
1375     PULONG ResultLength
1376     )
1377 /*++
1378 
1379 Routine Description:
1380     Queries USB capability for the device. Such capabilities are available
1381     only with USB 3.0 stack. On earlier stacks this API will fail with
1382     STATUS_NOT_IMPLEMENTED
1383 
1384 Arguments:
1385     UsbDevice - Device whose capability is to be queried.
1386 
1387     CapabilityType - Type of capability as defined by
1388                      IOCTL_INTERNAL_USB_GET_USB_CAPABILITY
1389 
1390     CapabilityBufferLength - Length of Capability buffer
1391 
1392     CapabilityBuffer - Buffer for capability. Can be NULL if
1393                        CapabilitiyBufferLength is 0
1394 
1395     ResultLength - Actual length of the capability. This parameter is optional.
1396 
1397 Return Value:
1398     STATUS_SUCCESS - success
1399     STATUS_NOT_IMPLEMENTED - Capabilties are not supported by USB stack
1400     STATUS_INSUFFICIENT_RESOURCES - no memory available
1401     ...
1402 
1403   --*/
1404 {
1405     DDI_ENTRY();
1406 
1407     NTSTATUS status;
1408     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1409     FxUsbDevice* pUsbDevice;
1410 
1411     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
1412                                    UsbDevice,
1413                                    FX_TYPE_IO_TARGET_USB_DEVICE,
1414                                    (PVOID*) &pUsbDevice,
1415                                    &pFxDriverGlobals);
1416 
1417     if (CapabilityBufferLength > 0) {
1418         FxPointerNotNull(pFxDriverGlobals, CapabilityBuffer);
1419     }
1420 
1421     status = pUsbDevice->QueryUsbCapability(CapabilityType,
1422                                             CapabilityBufferLength,
1423                                             CapabilityBuffer,
1424                                             ResultLength);
1425     return status;
1426 }
1427 
1428 } // extern "C"
1429