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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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
__drv_maxIRQL(DISPATCH_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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