1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxUsbDeviceKm.cpp
8 
9 Abstract:
10 
11 Author:
12 
13 Environment:
14 
15     kernel mode only
16 
17 Revision History:
18 
19 --*/
20 
21 extern "C" {
22 #include <initguid.h>
23 }
24 
25 #include "fxusbpch.hpp"
26 
27 
28 extern "C" {
29 #include "FxUsbDeviceKm.tmh"
30 }
31 
32 
33 
34 
35 
36 
37 
38 #define UCHAR_MAX (0xff)
39 
40 
41 _Must_inspect_result_
42 NTSTATUS
43 FxUsbDevice::InitDevice(
44     __in ULONG USBDClientContractVersionForWdfClient
45     )
46 {
47     URB urb;
48     FxSyncRequest request(GetDriverGlobals(), NULL);
49     WDF_REQUEST_SEND_OPTIONS options;
50     NTSTATUS status;
51     ULONG size;
52 
53     RtlZeroMemory(&urb, sizeof(urb));
54 
55     if (USBDClientContractVersionForWdfClient != USBD_CLIENT_CONTRACT_VERSION_INVALID) {
56 
57         //
58         // Register with USBDEX.lib
59         //
60         status = USBD_CreateHandle(m_InStackDevice,
61                                    m_TargetDevice,
62                                    USBDClientContractVersionForWdfClient,
63                                    GetDriverGlobals()->Tag,
64                                    &m_USBDHandle);
65 
66         if (!NT_SUCCESS(status)) {
67             DoTraceLevelMessage(
68                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
69                 "USBD_CreateHandle failed, %!STATUS!", status);
70             goto Done;
71         }
72 
73         m_UrbType = FxUrbTypeUsbdAllocated;
74     }
75 
76     status = request.m_TrueRequest->ValidateTarget(this);
77     if (!NT_SUCCESS(status)) {
78         goto Done;
79     }
80 
81     UsbBuildGetDescriptorRequest(&urb,
82                                  sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
83                                  USB_DEVICE_DESCRIPTOR_TYPE,
84                                  0,
85                                  0,
86                                  &m_DeviceDescriptor,
87                                  NULL,
88                                  sizeof(m_DeviceDescriptor),
89                                  NULL);
90 
91     FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
92 
93     WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0);
94     WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(5));
95 
96     status = SubmitSync(request.m_TrueRequest, &options);
97     if (!NT_SUCCESS(status)) {
98         DoTraceLevelMessage(
99             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
100             "Could not retrieve device descriptor, %!STATUS!", status);
101         goto Done;
102     }
103 
104     //
105     // After successfully completing any default control URB, USBD/usbport fills
106     // in the PipeHandle field of the URB (it is the same offset in every URB,
107     // which this CASSERT verifies.  Since USBD_DEFAULT_PIPE_TRANSFER is not
108     // supported by USBD (it is by USBPORT), this is the prescribed way of getting
109     // the default control pipe so that you can set the PipeHandle field in
110     // _URB_CONTROL_TRANSFER.
111     //
112     WDFCASSERT(FIELD_OFFSET(_URB_CONTROL_TRANSFER, PipeHandle) ==
113                FIELD_OFFSET(_URB_CONTROL_DESCRIPTOR_REQUEST, Reserved));
114 
115     m_ControlPipe = urb.UrbControlDescriptorRequest.Reserved;
116 
117     USB_CONFIGURATION_DESCRIPTOR config;
118 
119     RtlZeroMemory(&config, sizeof(config));
120     size = sizeof(config);
121 
122     UsbBuildGetDescriptorRequest(&urb,
123                                  sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
124                                  USB_CONFIGURATION_DESCRIPTOR_TYPE,
125                                  0,
126                                  0,
127                                  &config,
128                                  NULL,
129                                  size,
130                                  NULL);
131 
132     request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS);
133     request.m_TrueRequest->ClearFieldsForReuse();
134     FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
135 
136     status = SubmitSync(request.m_TrueRequest, &options);
137     if (!NT_SUCCESS(status)) {
138         DoTraceLevelMessage(
139             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
140             "Could not retrieve config descriptor size, %!STATUS!", status);
141         goto Done;
142     }
143     else if (urb.UrbControlDescriptorRequest.TransferBufferLength == 0) {
144         //
145         // Not enough info returned
146         //
147         status = STATUS_UNSUCCESSFUL;
148 
149         DoTraceLevelMessage(
150             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
151             "Could not retrieve config descriptor size, zero bytes transferred, "
152             " %!STATUS!", status);
153 
154         goto Done;
155     }
156     else if (config.wTotalLength < size) {
157         //
158         // Not enough info returned
159         //
160         status = STATUS_UNSUCCESSFUL;
161 
162         DoTraceLevelMessage(
163             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
164             "Could not retrieve config descriptor size, config.wTotalLength %d < "
165             "sizeof(config descriptor) (%d), %!STATUS!",
166             config.wTotalLength, size, status);
167 
168         goto Done;
169     }
170 
171     //
172     // Allocate an additional memory at the end of the buffer so if we
173     // accidentily access fields beyond the end of the buffer we don't crash
174 
175     //
176 
177 
178 
179 
180 
181     size = config.wTotalLength;
182     ULONG paddedSize = size + sizeof(USB_DEVICE_DESCRIPTOR);
183 
184     m_ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)
185         FxPoolAllocate(GetDriverGlobals(),
186                        NonPagedPool,
187                        paddedSize);
188 
189     if (m_ConfigDescriptor == NULL) {
190         status = STATUS_INSUFFICIENT_RESOURCES;
191 
192         DoTraceLevelMessage(
193             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
194             "Could not allocate %d bytes for config descriptor, %!STATUS!",
195             paddedSize, status);
196 
197         goto Done;
198     }
199 
200     RtlZeroMemory(m_ConfigDescriptor, paddedSize);
201 
202     UsbBuildGetDescriptorRequest(&urb,
203                                  sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
204                                  USB_CONFIGURATION_DESCRIPTOR_TYPE,
205                                  0,
206                                  0,
207                                  m_ConfigDescriptor,
208                                  NULL,
209                                  size,
210                                  NULL);
211 
212     request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS);
213     request.m_TrueRequest->ClearFieldsForReuse();
214     FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
215 
216     status = SubmitSync(request.m_TrueRequest, &options);
217     if (!NT_SUCCESS(status)) {
218         DoTraceLevelMessage(
219             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
220             "Could not retrieve config descriptor, %!STATUS!", status);
221         goto Done;
222     } else if(m_ConfigDescriptor->wTotalLength != size) {
223         //
224         // Invalid wTotalLength
225         //
226         status = STATUS_DEVICE_DATA_ERROR;
227         DoTraceLevelMessage(
228             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
229             "Defective USB device reported two different config descriptor "
230             "wTotalLength values: %d and %d, %!STATUS!",
231             size, m_ConfigDescriptor->wTotalLength, status);
232         goto Done;
233     }
234 
235     //
236     // Check to see if we are wait wake capable
237     //
238     if (m_ConfigDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) {
239         m_Traits |= WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE;
240     }
241 
242     //
243     // Check to see if we are self or bus powered
244     //
245     USHORT deviceStatus;
246 
247     UsbBuildGetStatusRequest(&urb,
248                              URB_FUNCTION_GET_STATUS_FROM_DEVICE,
249                              0,
250                              &deviceStatus,
251                              NULL,
252                              NULL);
253 
254     request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS);
255     request.m_TrueRequest->ClearFieldsForReuse();
256     FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL);
257 
258     status = SubmitSync(request.m_TrueRequest, &options);
259     if (NT_SUCCESS(status) && (deviceStatus & USB_GETSTATUS_SELF_POWERED)) {
260         m_Traits |= WDF_USB_DEVICE_TRAIT_SELF_POWERED;
261     }
262 
263     //
264     // Revert back to success b/c we don't care if the usb device get status
265     // fails
266     //
267     status = STATUS_SUCCESS;
268 
269     USB_BUS_INTERFACE_USBDI_V1 busIf;
270 
271     RtlZeroMemory(&busIf, sizeof(busIf));
272 
273     //
274     // All PNP irps must have this initial status
275     //
276     request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED);
277     request.m_TrueRequest->ClearFieldsForReuse();
278 
279     FxQueryInterface::_FormatIrp(
280         request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(),
281         &USB_BUS_INTERFACE_USBDI_GUID,
282         (PINTERFACE) &busIf,
283         sizeof(busIf),
284         USB_BUSIF_USBDI_VERSION_1);
285 
286     request.m_TrueRequest->VerifierSetFormatted();
287 
288     status = SubmitSync(request.m_TrueRequest);
289 
290     if (!NT_SUCCESS(status)) {
291         //
292         // Retry with the older interface
293         //
294         RtlZeroMemory(&busIf, sizeof(busIf));
295 
296         //
297         // All PNP irps must have this initial status
298         //
299 
300         request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED);
301         request.m_TrueRequest->ClearFieldsForReuse();
302 
303         FxQueryInterface::_FormatIrp(
304             request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(),
305             &USB_BUS_INTERFACE_USBDI_GUID,
306             (PINTERFACE) &busIf,
307             sizeof(USB_BUS_INTERFACE_USBDI_V0),
308             USB_BUSIF_USBDI_VERSION_0);
309 
310         request.m_TrueRequest->VerifierSetFormatted();
311 
312         status = SubmitSync(request.m_TrueRequest);
313     }
314 
315     if (NT_SUCCESS(status)) {
316         //
317         // Need to check for NULL b/c we may have only retrieved the V0 interface
318         //
319         if (busIf.IsDeviceHighSpeed != NULL &&
320             busIf.IsDeviceHighSpeed(busIf.BusContext)) {
321             m_Traits |= WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED;
322         }
323 
324         //
325         // Stash these off for later
326         //
327         m_QueryBusTime = busIf.QueryBusTime;
328         m_BusInterfaceContext = busIf.BusContext;
329         m_BusInterfaceDereference = busIf.InterfaceDereference;
330 
331         ASSERT(busIf.GetUSBDIVersion != NULL);
332         busIf.GetUSBDIVersion(busIf.BusContext,
333                               &m_UsbdVersionInformation,
334                               &m_HcdPortCapabilities);
335     }
336     else if (status == STATUS_NOT_SUPPORTED) {
337         //
338         // We will only use m_ControlPipe on stacks which do not support
339         // USBD_DEFAULT_PIPE_TRANSFER.  If all the QIs failed, then we know
340         // definitively that we are running on USBD and we need m_ControlPipe
341         // to be != NULL for later control transfers
342         //
343         ASSERT(m_ControlPipe != NULL);
344 
345         m_OnUSBD = TRUE;
346 
347         //
348         // The QI failed with not supported, do not return error
349         //
350         status = STATUS_SUCCESS;
351     }
352     else {
353         DoTraceLevelMessage(
354             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
355             "Query Interface for bus returned error, %!STATUS!", status);
356     }
357 
358 Done:
359 
360     return status;
361 }
362 
363 _Must_inspect_result_
364 NTSTATUS
365 FxUsbDevice::GetString(
366     __in_ecount(*NumCharacters) PUSHORT String,
367     __in PUSHORT NumCharacters,
368     __in UCHAR StringIndex,
369     __in_opt USHORT LangID,
370     __in_opt WDFREQUEST Request,
371     __in_opt PWDF_REQUEST_SEND_OPTIONS Options
372     )
373 {
374     PUSB_STRING_DESCRIPTOR pDescriptor;
375     PVOID buffer;
376     _URB_CONTROL_DESCRIPTOR_REQUEST urb;
377     WDF_REQUEST_SEND_OPTIONS options, *pOptions;
378     USB_COMMON_DESCRIPTOR common;
379     ULONG length;
380     NTSTATUS status;
381 
382     FxSyncRequest request(GetDriverGlobals(), NULL, Request);
383 
384     //
385     // FxSyncRequest always succeesds for KM.
386     //
387     status = request.Initialize();
388     if (!NT_SUCCESS(status)) {
389         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
390                             "Failed to initialize FxSyncRequest");
391         return status;
392     }
393 
394     buffer = NULL;
395 
396     status = request.m_TrueRequest->ValidateTarget(this);
397     if (!NT_SUCCESS(status)) {
398         goto Done;
399     }
400 
401     RtlZeroMemory(&urb, sizeof(urb));
402 
403     if (String != NULL) {
404         length = sizeof(USB_STRING_DESCRIPTOR) + (*NumCharacters - 1) * sizeof(WCHAR);
405 
406         buffer = FxPoolAllocate(GetDriverGlobals(),
407                                 NonPagedPool,
408                                 length);
409 
410         if (buffer == NULL) {
411             status = STATUS_INSUFFICIENT_RESOURCES;
412             goto Done;
413         }
414 
415         RtlZeroMemory(buffer, length);
416         pDescriptor = (PUSB_STRING_DESCRIPTOR) buffer;
417     }
418     else {
419         RtlZeroMemory(&common, sizeof(common));
420 
421         length = sizeof(USB_COMMON_DESCRIPTOR);
422         pDescriptor = (PUSB_STRING_DESCRIPTOR) &common;
423     }
424 
425     UsbBuildGetDescriptorRequest((PURB) &urb,
426                                  sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
427                                  USB_STRING_DESCRIPTOR_TYPE,
428                                  StringIndex,
429                                  LangID,
430                                  pDescriptor,
431                                  NULL,
432                                  length,
433                                  NULL);
434 
435     if (Options != NULL) {
436         pOptions = Options;
437     }
438     else {
439         WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0);
440         WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options,
441                                              WDF_REL_TIMEOUT_IN_SEC(2));
442 
443         pOptions = &options;
444     }
445 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team")
446     FxFormatUsbRequest(request.m_TrueRequest, (PURB) &urb, FxUrbTypeLegacy, NULL);
447     status = SubmitSync(request.m_TrueRequest, pOptions);
448 
449     if (NT_SUCCESS(status)) {
450         USHORT numChars;
451 
452         //
453         // Make sure we got an even number of bytes and that we got a header
454         //
455         if ((pDescriptor->bLength & 0x1) ||
456             pDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) {
457             status = STATUS_DEVICE_DATA_ERROR;
458         }
459         else {
460             //
461             // bLength is the length of the entire descriptor.  Subtract off
462             // the descriptor header and then divide by the size of a WCHAR.
463             //
464             numChars =
465                 (pDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(WCHAR);
466 
467             if (String != NULL) {
468                 if (*NumCharacters >= numChars) {
469                     length = numChars * sizeof(WCHAR);
470                 }
471                 else {
472                     length = *NumCharacters * sizeof(WCHAR);
473                     status = STATUS_BUFFER_OVERFLOW;
474                 }
475 
476                 *NumCharacters = numChars;
477                 RtlCopyMemory(String, pDescriptor->bString, length);
478             }
479             else {
480                 *NumCharacters = numChars;
481             }
482         }
483     }
484 
485     if (buffer != NULL) {
486         FxPoolFree(buffer);
487     }
488 
489 Done:
490 
491     return status;
492 }
493 
494 _Must_inspect_result_
495 NTSTATUS
496 FxUsbDevice::FormatStringRequest(
497     __in FxRequestBase* Request,
498     __in FxRequestBuffer *RequestBuffer,
499     __in UCHAR StringIndex,
500     __in USHORT LangID
501     )
502 /*++
503 
504 Routine Description:
505     Formats a request to retrieve a string from a string descriptor
506 
507 Arguments:
508     Request - request to format
509 
510     RequestBuffer - Buffer to be filled in when the request has completed
511 
512     StringIndex - index of the string
513 
514     LandID - language ID of the string to be retrieved
515 
516 Return Value:
517     NTSTATUS
518 
519   --*/
520 {
521     FxUsbDeviceStringContext* pContext;
522     NTSTATUS status;
523     FX_URB_TYPE urbType;
524 
525     status = Request->ValidateTarget(this);
526     if (!NT_SUCCESS(status)) {
527         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
528                             "WDFUSBDEVICE %p, Request %p, setting target failed, "
529                             "%!STATUS!", GetHandle(), Request, status);
530 
531         return status;
532     }
533 
534     if (Request->HasContextType(FX_RCT_USB_STRING_REQUEST)) {
535         pContext = (FxUsbDeviceStringContext*) Request->GetContext();
536     }
537     else {
538 
539         urbType = GetFxUrbTypeForRequest(Request);
540         pContext = new(GetDriverGlobals()) FxUsbDeviceStringContext(urbType);
541         if (pContext == NULL) {
542             return STATUS_INSUFFICIENT_RESOURCES;
543         }
544 
545         if (urbType == FxUrbTypeUsbdAllocated) {
546             status = pContext->AllocateUrb(m_USBDHandle);
547             if (!NT_SUCCESS(status)) {
548                 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
549                     "FxUsbDeviceStringContext::AllocateUrb failed, %!STATUS!", status);
550                 delete pContext;
551                 return status;
552             }
553 
554             //
555             // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is
556             // important to release those resorces before the devnode is removed. Those
557             // resoruces are removed at the time Request is disposed.
558             //
559             Request->EnableContextDisposeNotification();
560         }
561 
562         Request->SetContext(pContext);
563     }
564 
565     status = pContext->AllocateDescriptor(GetDriverGlobals(),
566                                           RequestBuffer->GetBufferLength());
567     if (!NT_SUCCESS(status)) {
568         return status;
569     }
570 
571     pContext->StoreAndReferenceMemory(RequestBuffer);
572     pContext->SetUrbInfo(StringIndex, LangID);
573 
574     if (pContext->m_Urb == &pContext->m_UrbLegacy) {
575         urbType = FxUrbTypeLegacy;
576     }
577     else {
578         urbType = FxUrbTypeUsbdAllocated;
579     }
580 
581     FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle);
582 
583     return STATUS_SUCCESS;
584 }
585 
586 _Must_inspect_result_
587 NTSTATUS
588 FxUsbDevice::FormatControlRequest(
589     __in FxRequestBase* Request,
590     __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket,
591     __in FxRequestBuffer *RequestBuffer
592     )
593 {
594     FxUsbDeviceControlContext* pContext;
595     NTSTATUS status;
596     size_t bufferSize;
597     FX_URB_TYPE urbType;
598 
599     bufferSize = RequestBuffer->GetBufferLength();
600 
601     //
602     // We can only transfer 2 bytes worth of data, so if the buffer is larger,
603     // fail here.
604     //
605     if (bufferSize > 0xFFFF) {
606         DoTraceLevelMessage(
607             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
608             "Control transfer buffer is limited to 0xFFFF bytes in size, "
609             "%I64d requested ", bufferSize);
610 
611         return STATUS_INVALID_PARAMETER;
612     }
613 
614     status = Request->ValidateTarget(this);
615     if (!NT_SUCCESS(status)) {
616         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
617                             "WDFUSBDEVICE %p, Request %p, setting target failed, "
618                             "%!STATUS!", GetHandle(), Request, status);
619 
620         return status;
621     }
622 
623     if (Request->HasContextType(FX_RCT_USB_CONTROL_REQUEST)) {
624         pContext = (FxUsbDeviceControlContext*) Request->GetContext();
625     }
626     else {
627 
628         urbType = GetFxUrbTypeForRequest(Request);
629         pContext = new(GetDriverGlobals()) FxUsbDeviceControlContext(urbType);
630         if (pContext == NULL) {
631             return STATUS_INSUFFICIENT_RESOURCES;
632         }
633 
634         if (urbType == FxUrbTypeUsbdAllocated) {
635             status = pContext->AllocateUrb(m_USBDHandle);
636             if (!NT_SUCCESS(status)) {
637                 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
638                                     "FxUsbDeviceControlContext::AllocateUrb Failed, %!STATUS!", status);
639 
640                 delete pContext;
641                 return status;
642             }
643             //
644             // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is
645             // important to release those resorces before the devnode is removed. Those
646             // resoruces are removed at the time Request is disposed.
647             //
648             Request->EnableContextDisposeNotification();
649         }
650 
651         Request->SetContext(pContext);
652     }
653 
654     if (RequestBuffer->HasMdl()) {
655         PMDL pMdl;
656 
657         pMdl = NULL;
658         ASSERT(pContext->m_PartialMdl == NULL);
659 
660         status = RequestBuffer->GetOrAllocateMdl(GetDriverGlobals(),
661                                                  &pMdl,
662                                                  &pContext->m_PartialMdl,
663                                                  &pContext->m_UnlockPages,
664                                                  IoModifyAccess);
665 
666         if (!NT_SUCCESS(status)) {
667             return status;
668         }
669 
670         ASSERT(pMdl != NULL);
671     }
672 
673     pContext->StoreAndReferenceMemory(this, RequestBuffer, SetupPacket);
674 
675     if (pContext->m_Urb == &pContext->m_UrbLegacy) {
676         urbType = FxUrbTypeLegacy;
677     }
678     else {
679         urbType = FxUrbTypeUsbdAllocated;
680     }
681 
682     FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle);
683 
684     return STATUS_SUCCESS;
685 }
686 
687 VOID
688 FxUsbDeviceControlContext::StoreAndReferenceMemory(
689     __in FxUsbDevice* Device,
690     __in FxRequestBuffer* Buffer,
691     __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket
692     )
693 {
694     SetUsbType(WdfUsbRequestTypeDeviceControlTransfer);
695 
696     RtlZeroMemory(m_Urb, sizeof(*m_Urb));
697 
698     m_Urb->Hdr.Function = URB_FUNCTION_CONTROL_TRANSFER;
699     m_Urb->Hdr.Length = sizeof(*m_Urb);
700 
701     __super::StoreAndReferenceMemory(Buffer);
702 
703     //
704     // Set the values using what is stored in the buffer
705     //
706     Buffer->AssignValues(&m_Urb->TransferBuffer,
707                          &m_Urb->TransferBufferMDL,
708                          &m_Urb->TransferBufferLength);
709 
710     RtlCopyMemory(&m_Urb->SetupPacket[0],
711                   &SetupPacket->Generic.Bytes[0],
712                   sizeof(m_Urb->SetupPacket));
713 
714     //
715     // also indicate the length of the buffer in the header
716     //
717     ((PWDF_USB_CONTROL_SETUP_PACKET) &m_Urb->SetupPacket[0])->Packet.wLength =
718         (USHORT) m_Urb->TransferBufferLength;
719 
720     //
721     // Control transfers are always short OK.  USBD_TRANSFER_DIRECTION_IN may
722     // be OR'ed in later.
723     //
724     m_Urb->TransferFlags = USBD_SHORT_TRANSFER_OK;
725 
726     //
727     // Get the direction out of the setup packet
728     //
729     if (SetupPacket->Packet.bm.Request.Dir == BMREQUEST_DEVICE_TO_HOST) {
730         m_Urb->TransferFlags |= USBD_TRANSFER_DIRECTION_IN;
731     }
732 
733     if (Device->OnUSBD()) {
734         m_Urb->PipeHandle = Device->GetControlPipeHandle();
735     }
736     else {
737         //
738         // USBPORT supports this flag
739         //
740         m_Urb->TransferFlags |= USBD_DEFAULT_PIPE_TRANSFER;
741     }
742 
743     //
744     // If we have built a partial MDL, use that instead.  TransferBufferLength
745     // is still valid because the Offsets or length in Buffer will have been
746     // used to create this PartialMdl by the caller.
747     //
748     if (m_PartialMdl != NULL) {
749         m_Urb->TransferBufferMDL = m_PartialMdl;
750     }
751 }
752 
753 _Must_inspect_result_
754 NTSTATUS
755 FxUsbDevice::QueryUsbCapability(
756     __in
757     CONST GUID* CapabilityType,
758     __in
759     ULONG CapabilityBufferLength,
760     __drv_when(CapabilityBufferLength == 0, __out_opt)
761     __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength))
762     __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength))
763     PVOID CapabilityBuffer,
764     __out_opt
765     __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength))
766     PULONG ResultLength
767    )
768 {
769     NTSTATUS status;
770 
771     if (ResultLength != NULL) {
772         *ResultLength = 0;
773     }
774 
775     if (GetUSBDHandle() == NULL) {
776         status = STATUS_INVALID_DEVICE_STATE;
777 
778         DoTraceLevelMessage(
779             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
780             "WDFUSBDEVICE must have been created using WdfUsbTargetDeviceCreateWithParameters, %!STATUS!",
781             status);
782 
783         return status;
784     }
785 
786     status = USBD_QueryUsbCapability(m_USBDHandle,
787                                      CapabilityType,
788                                      CapabilityBufferLength,
789                                      (PUCHAR) CapabilityBuffer,
790                                      ResultLength);
791 
792     if (!NT_SUCCESS(status)) {
793         DoTraceLevelMessage(
794             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
795             "Could not retrieve capability %!GUID!, %!STATUS!",
796             CapabilityType, status);
797         goto exit;
798     }
799 
800 exit:
801     return status;
802 }
803 
804 _Must_inspect_result_
805 NTSTATUS
806 FxUsbDevice::SelectConfigSingle(
807     __in PWDF_OBJECT_ATTRIBUTES PipeAttributes,
808     __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
809     )
810 /*++
811 
812 Routine Description:
813     This will configure the single inteface case and pick up the first available
814     setting. If there are multiple settings on  a single interface device
815     and the driver wants to pick one then the driver should use the multinterface
816     option to initialize.
817 
818     This takes care of the simplest case only.  Configuring a multi interface
819     device as a single interface device would be treated as an error.  There is
820     duplication of code with the multi case but it is better to keep these two
821     separate especially if more gets added.
822 
823 Arguments:
824 
825 
826 Return Value:
827     NTSTATUS
828 
829   --*/
830 {
831     //
832     // The array needs an extra element which is zero'd out to mark the end
833     //
834     USBD_INTERFACE_LIST_ENTRY listEntry[2];
835     PURB urb;
836     NTSTATUS status;
837 
838     RtlZeroMemory(&Params->Types.SingleInterface,
839                   sizeof(Params->Types.SingleInterface));
840 
841     if (m_NumInterfaces > 1) {
842         status = STATUS_INVALID_PARAMETER;
843 
844         DoTraceLevelMessage(
845             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
846             "WDFUSBDEVICE %p cannot be auto configured for a single interface "
847             "since there are %d interfaces on the device, %!STATUS!",
848             GetHandle(), m_NumInterfaces, status);
849 
850         return status;
851     }
852 
853     RtlZeroMemory(&listEntry[0], sizeof(listEntry));
854 
855     //
856     // Use AlternateSetting 0 by default
857     //
858     listEntry[0].InterfaceDescriptor = m_Interfaces[0]->GetSettingDescriptor(0);
859 
860     if (listEntry[0].InterfaceDescriptor == NULL) {
861         DoTraceLevelMessage(
862             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
863             "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for "
864             "bInterfaceNumber %d", GetHandle(),
865             m_Interfaces[0]->m_InterfaceNumber);
866 
867         return STATUS_INVALID_PARAMETER;
868     }
869 
870     urb = FxUsbCreateConfigRequest(GetDriverGlobals(),
871                                    m_ConfigDescriptor,
872                                    &listEntry[0],
873                                    GetDefaultMaxTransferSize());
874 
875     if (urb == NULL) {
876         status = STATUS_INSUFFICIENT_RESOURCES;
877     }
878     else {
879         status = SelectConfig(PipeAttributes, urb, FxUrbTypeLegacy, NULL);
880 
881         if (NT_SUCCESS(status)) {
882             Params->Types.SingleInterface.NumberConfiguredPipes  =
883                  m_Interfaces[0]->GetNumConfiguredPipes();
884 
885             Params->Types.SingleInterface.ConfiguredUsbInterface =
886                 m_Interfaces[0]->GetHandle();
887         }
888 
889         FxPoolFree(urb);
890         urb = NULL;
891     }
892 
893     return status;
894 }
895 
896 _Must_inspect_result_
897 NTSTATUS
898 FxUsbDevice::SelectConfigMulti(
899     __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
900     __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
901     )
902 /*++
903 
904 Routine Description:
905     Selects the configuration as described by the parameter Params.  If there is a
906     previous active configuration, the WDFUSBPIPEs for it are stopped and
907     destroyed before the new configuration is selected
908 
909 Arguments:
910     PipesAttributes - object attributes to apply to each created WDFUSBPIPE
911 
912     Params -
913 
914 Return Value:
915     NTSTATUS
916 
917   --*/
918 {
919     PUSBD_INTERFACE_LIST_ENTRY pList;
920     PURB urb;
921     NTSTATUS status;
922     ULONG size;
923     UCHAR i;
924     PFX_DRIVER_GLOBALS pFxDriverGlobals;
925 
926     pFxDriverGlobals = GetDriverGlobals();
927 
928     Params->Types.MultiInterface.NumberOfConfiguredInterfaces = 0;
929 
930     //
931     // The array needs an extra element which is zero'd out to mark the end
932     //
933     size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (m_NumInterfaces + 1);
934     pList = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate(
935         pFxDriverGlobals,
936         NonPagedPool,
937         size
938         );
939 
940     if (pList == NULL) {
941         return STATUS_INSUFFICIENT_RESOURCES;
942     }
943 
944     RtlZeroMemory(pList, size);
945 
946     if (Params->Type == WdfUsbTargetDeviceSelectConfigTypeMultiInterface) {
947         for (i = 0; i < m_NumInterfaces; i++) {
948             pList[i].InterfaceDescriptor =
949                 m_Interfaces[i]->GetSettingDescriptor(0);
950 
951             if (pList[i].InterfaceDescriptor == NULL) {
952                 DoTraceLevelMessage(
953                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
954                     "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for "
955                     "bInterfaceNumber %d", GetHandle(),
956                     m_Interfaces[i]->m_InterfaceNumber);
957 
958                 status = STATUS_INVALID_PARAMETER;
959                 goto Done;
960             }
961         }
962     }
963     else {
964         //
965         // Type is WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs
966         //
967         UCHAR interfacePairsNum = 0;
968         UCHAR bitArray[UCHAR_MAX/sizeof(UCHAR)];
969 
970         //
971         // initialize the bit array
972         //
973         RtlZeroMemory(bitArray, sizeof(bitArray));
974         //
975         // Build a list of descriptors from the Setting pairs
976         // passed in by the user. There could be interfaces not
977         // covered in the setting/interface pairs array passed.
978         // If that is the case return STATUS_INVALID_PARAMETER
979         //
980         for (i = 0; i < Params->Types.MultiInterface.NumberInterfaces ; i++) {
981             PWDF_USB_INTERFACE_SETTING_PAIR settingPair;
982             UCHAR interfaceNumber;
983             UCHAR altSettingIndex;
984 
985             settingPair = &Params->Types.MultiInterface.Pairs[i];
986 
987             status = GetInterfaceNumberFromInterface(
988                 settingPair->UsbInterface,
989                 &interfaceNumber
990                 );
991 
992             //
993             //convert the interface handle to interface number
994             //
995             if (NT_SUCCESS(status)) {
996                 altSettingIndex = settingPair->SettingIndex;
997 
998                 //
999                 // do the following only if the bit is not already set
1000                 //
1001                 if (FxBitArraySet(&bitArray[0], interfaceNumber) == FALSE) {
1002                     pList[interfacePairsNum].InterfaceDescriptor =
1003                          FxUsbParseConfigurationDescriptor(
1004                              m_ConfigDescriptor,
1005                              interfaceNumber,
1006                              altSettingIndex
1007                              );
1008 
1009                     if (pList[interfacePairsNum].InterfaceDescriptor == NULL) {
1010                         status = STATUS_INVALID_PARAMETER;
1011                         DoTraceLevelMessage(
1012                             GetDriverGlobals(), TRACE_LEVEL_ERROR,
1013                             TRACINGIOTARGET,
1014                             "WDFUSBDEVICE %p could not retrieve "
1015                             "AlternateSetting %d for "
1016                             "bInterfaceNumber %d, returning %!STATUS!",
1017                             GetHandle(),
1018                             altSettingIndex, interfaceNumber, status);
1019                         goto Done;
1020                     }
1021 
1022                     interfacePairsNum++;
1023                 }
1024             }
1025             else {
1026                 goto Done;
1027             }
1028         }
1029 
1030         //
1031         // Check if there are any interfaces not specified by the array. If
1032         // there are, then select setting 0 for them.
1033         //
1034         if (m_NumInterfaces > interfacePairsNum) {
1035             status = STATUS_INVALID_PARAMETER;
1036             DoTraceLevelMessage(
1037                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1038                 "WDFUSBDEVICE %p interface pairs set (%d) is not equal to actual "
1039                 "# of interfaces (%d) reported by the device, %!STATUS!",
1040                 GetObjectHandle(), interfacePairsNum, m_NumInterfaces, status);
1041             goto Done;
1042         }
1043     } //WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs
1044 
1045     urb = FxUsbCreateConfigRequest(
1046         GetDriverGlobals(),
1047         m_ConfigDescriptor,
1048         pList,
1049         GetDefaultMaxTransferSize()
1050         );
1051 
1052     if (urb == NULL) {
1053         status = STATUS_INSUFFICIENT_RESOURCES;
1054     }
1055     else {
1056         status = SelectConfig(
1057             PipesAttributes,
1058             urb,
1059             FxUrbTypeLegacy,
1060             &Params->Types.MultiInterface.NumberOfConfiguredInterfaces);
1061 
1062         FxPoolFree(urb);
1063         urb = NULL;
1064     }
1065 
1066 Done:
1067     FxPoolFree(pList);
1068     pList = NULL;
1069 
1070     return status;
1071 }
1072 
1073 _Must_inspect_result_
1074 NTSTATUS
1075 FxUsbDevice::Reset(
1076     VOID
1077     )
1078 {
1079     FxIoContext context;
1080     FxSyncRequest request(GetDriverGlobals(), &context);
1081     FxRequestBuffer emptyBuffer;
1082     NTSTATUS status;
1083 
1084     //
1085     // FxSyncRequest always succeesds for KM.
1086     //
1087     status = request.Initialize();
1088     if (!NT_SUCCESS(status)) {
1089         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1090                             "Failed to initialize FxSyncRequest");
1091         return status;
1092     }
1093 
1094     status = FormatIoctlRequest(request.m_TrueRequest,
1095                                 IOCTL_INTERNAL_USB_RESET_PORT,
1096                                 TRUE,
1097                                 &emptyBuffer,
1098                                 &emptyBuffer);
1099     if (NT_SUCCESS(status)) {
1100         CancelSentIo();
1101         status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL);
1102     }
1103 
1104     return status;
1105 }
1106 
1107 
1108