1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxUsbDeviceUm.cpp
8
9 Abstract:
10
11 Author:
12
13 Environment:
14
15 User mode only
16
17 Revision History:
18
19 --*/
20 extern "C" {
21 #include <initguid.h>
22
23 }
24 #include "fxusbpch.hpp"
25 extern "C" {
26 #include "FxUsbDeviceUm.tmh"
27 }
28
29 _Must_inspect_result_
30 NTSTATUS
SendSyncRequest(__in FxSyncRequest * Request,__in ULONGLONG Time)31 FxUsbDevice::SendSyncRequest(
32 __in FxSyncRequest* Request,
33 __in ULONGLONG Time
34 )
35 {
36 NTSTATUS status;
37 WDF_REQUEST_SEND_OPTIONS options;
38
39 WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0);
40 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(Time));
41
42 status = SubmitSync(Request->m_TrueRequest, &options);
43 if (!NT_SUCCESS(status)) {
44 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
45 "FxUsbDevice SubmitSync failed");
46 goto Done;
47 }
48
49 Done:
50 return status;
51 }
52
53 _Must_inspect_result_
54 NTSTATUS
SendSyncUmUrb(__inout PUMURB Urb,__in ULONGLONG Time,__in_opt WDFREQUEST Request,__in_opt PWDF_REQUEST_SEND_OPTIONS Options)55 FxUsbDevice::SendSyncUmUrb(
56 __inout PUMURB Urb,
57 __in ULONGLONG Time,
58 __in_opt WDFREQUEST Request,
59 __in_opt PWDF_REQUEST_SEND_OPTIONS Options
60 )
61 {
62 NTSTATUS status;
63 WDF_REQUEST_SEND_OPTIONS options;
64 FxSyncRequest request(GetDriverGlobals(), NULL, Request);
65
66 status = request.Initialize();
67 if (!NT_SUCCESS(status)) {
68 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
69 "Failed to initialize FxSyncRequest");
70 return status;
71 }
72
73 if (NULL == Options) {
74 Options = &options;
75 }
76
77 WDF_REQUEST_SEND_OPTIONS_INIT(Options, 0);
78 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(Options, WDF_REL_TIMEOUT_IN_SEC(Time));
79
80 status = request.m_TrueRequest->ValidateTarget(this);
81 if (NT_SUCCESS(status)) {
82 FxUsbUmFormatRequest(request.m_TrueRequest, &Urb->UmUrbHeader, m_pHostTargetFile);
83 status = SubmitSync(request.m_TrueRequest, Options);
84 if (!NT_SUCCESS(status)) {
85 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
86 "FxUsbDevice SubmitSync failed");
87 return status;
88 }
89 }
90
91 return status;
92 }
93
94 _Must_inspect_result_
95 NTSTATUS
InitDevice(__in ULONG USBDClientContractVersionForWdfClient)96 FxUsbDevice::InitDevice(
97 __in ULONG USBDClientContractVersionForWdfClient
98 )
99 {
100 HRESULT hr = S_OK;
101 NTSTATUS status = STATUS_SUCCESS;
102
103 IWudfDevice* device = NULL;
104 IWudfDeviceStack2* devstack2 = NULL;
105
106 UMURB urb;
107 USB_CONFIGURATION_DESCRIPTOR config;
108 USHORT wTotalLength = 0;
109
110 FxRequestBuffer buf;
111 FxUsbDeviceControlContext context(FxUrbTypeLegacy);
112
113 WDF_USB_CONTROL_SETUP_PACKET setupPacket;
114 USHORT deviceStatus = 0;
115 UCHAR deviceSpeed = 0;
116
117 FxSyncRequest request(GetDriverGlobals(), NULL);
118 FxSyncRequest request2(GetDriverGlobals(), &context);
119
120
121
122
123 UNREFERENCED_PARAMETER(USBDClientContractVersionForWdfClient);
124
125 status = request.Initialize();
126 if (!NT_SUCCESS(status)) {
127 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
128 "Failed to initialize FxSyncRequest");
129 goto Done;
130 }
131
132 status = request2.Initialize();
133 if (!NT_SUCCESS(status)) {
134 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
135 "Failed to initialize second FxSyncRequest");
136 goto Done;
137 }
138
139 status = request.m_TrueRequest->ValidateTarget(this);
140 if (!NT_SUCCESS(status)) {
141 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
142 "Failed to validate FxSyncRequest target");
143 goto Done;
144 }
145
146 status = request2.m_TrueRequest->ValidateTarget(this);
147 if (!NT_SUCCESS(status)) {
148 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
149 "Failed to validate second FxSyncRequest target");
150 goto Done;
151 }
152
153 RtlZeroMemory(&urb, sizeof(urb));
154
155 device = m_DeviceBase->GetDeviceObject();
156 devstack2 = m_Device->GetDeviceStack2();
157
158 if (m_pHostTargetFile == NULL) {
159
160 //
161 // Opens a handle on the reflector for USB side-band communication
162 // based on the currently selected dispatcher type.
163 //
164 hr = devstack2->OpenUSBCommunicationChannel(device,
165 device->GetAttachedDevice(),
166 &m_pHostTargetFile);
167
168 if (SUCCEEDED(hr)) {
169 m_WinUsbHandle = (WINUSB_INTERFACE_HANDLE)m_pHostTargetFile->GetCreateContext();
170 }
171 }
172
173 //
174 // Get USB device descriptor
175 //
176 FxUsbUmInitDescriptorUrb(&urb,
177 m_WinUsbHandle,
178 USB_DEVICE_DESCRIPTOR_TYPE,
179 sizeof(m_DeviceDescriptor),
180 &m_DeviceDescriptor);
181 FxUsbUmFormatRequest(request.m_TrueRequest,
182 &urb.UmUrbHeader,
183 m_pHostTargetFile,
184 TRUE);
185 status = SendSyncRequest(&request, 5);
186 if (!NT_SUCCESS(status)) {
187 goto Done;
188 }
189
190 //
191 // Get USB configuration descriptor
192 //
193 FxUsbUmInitDescriptorUrb(&urb,
194 m_WinUsbHandle,
195 USB_CONFIGURATION_DESCRIPTOR_TYPE,
196 sizeof(config),
197 &config);
198 FxUsbUmFormatRequest(request.m_TrueRequest,
199 &urb.UmUrbHeader,
200 m_pHostTargetFile,
201 TRUE);
202 status = SendSyncRequest(&request, 5);
203 if (!NT_SUCCESS(status)) {
204 goto Done;
205 }
206
207 if (config.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
208
209 //
210 // Not enough info returned
211 //
212 status = STATUS_UNSUCCESSFUL;
213 DoTraceLevelMessage(
214 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
215 "Could not retrieve config descriptor size, config.wTotalLength %d < "
216 "sizeof(config descriptor) (%d), %!STATUS!",
217 config.wTotalLength, sizeof(USB_CONFIGURATION_DESCRIPTOR), status);
218 goto Done;
219 }
220
221 wTotalLength = config.wTotalLength;
222 m_ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)
223 FxPoolAllocate(GetDriverGlobals(),
224 NonPagedPool,
225 wTotalLength);
226 if (NULL == m_ConfigDescriptor) {
227 status = STATUS_INSUFFICIENT_RESOURCES;
228 DoTraceLevelMessage(
229 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
230 "Could not allocate %d bytes for config descriptor, %!STATUS!",
231 sizeof(USB_CONFIGURATION_DESCRIPTOR), status);
232 goto Done;
233 }
234
235 //
236 // Get USB configuration descriptor and subsequent interface descriptors, etc.
237 //
238 FxUsbUmInitDescriptorUrb(&urb,
239 m_WinUsbHandle,
240 USB_CONFIGURATION_DESCRIPTOR_TYPE,
241 wTotalLength,
242 m_ConfigDescriptor);
243 FxUsbUmFormatRequest(request.m_TrueRequest,
244 &urb.UmUrbHeader,
245 m_pHostTargetFile,
246 TRUE);
247 status = SendSyncRequest(&request, 5);
248 if (!NT_SUCCESS(status)) {
249 goto Done;
250 } else if (m_ConfigDescriptor->wTotalLength != wTotalLength) {
251 //
252 // Invalid wTotalLength
253 //
254 status = STATUS_DEVICE_DATA_ERROR;
255 DoTraceLevelMessage(
256 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
257 "Defective USB device reported two different config descriptor "
258 "wTotalLength values: %d and %d, %!STATUS!",
259 wTotalLength, m_ConfigDescriptor->wTotalLength, status);
260 goto Done;
261 }
262
263 m_NumInterfaces = m_ConfigDescriptor->bNumInterfaces;
264
265 //
266 // Check to see if we are wait wake capable
267 //
268 if (m_ConfigDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) {
269 m_Traits |= WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE;
270 }
271
272 //
273 // Get the device status to check if device is self-powered.
274 //
275 WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(&setupPacket,
276 BmRequestToDevice,
277 0); // Device status
278
279 buf.SetBuffer(&deviceStatus, sizeof(USHORT));
280
281 status = FormatControlRequest(request2.m_TrueRequest,
282 &setupPacket,
283 &buf);
284 if (!NT_SUCCESS(status)) {
285 goto Done;
286 }
287
288 status = SendSyncRequest(&request2, 5);
289 if (!NT_SUCCESS(status)) {
290 goto Done;
291 }
292
293 if (deviceStatus & USB_GETSTATUS_SELF_POWERED) {
294 m_Traits |= WDF_USB_DEVICE_TRAIT_SELF_POWERED;
295 }
296
297 //
298 // Get device speed information.
299 //
300 FxUsbUmInitInformationUrb(&urb,
301 m_WinUsbHandle,
302 sizeof(UCHAR),
303 &deviceSpeed);
304 FxUsbUmFormatRequest(request.m_TrueRequest,
305 &urb.UmUrbHeader,
306 m_pHostTargetFile,
307 TRUE);
308 status = SendSyncRequest(&request, 5);
309 if (!NT_SUCCESS(status)) {
310 goto Done;
311 }
312
313 if (deviceSpeed == 3) {
314 m_Traits |= WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED;
315 }
316
317 //
318 // User-mode events must be initialized manually.
319 //
320 status = m_InterfaceIterationLock.Initialize();
321 if (!NT_SUCCESS(status)) {
322 goto Done;
323 }
324
325 Done:
326 return status;
327 }
328
329
330
331
332 _Must_inspect_result_
333 NTSTATUS
GetString(__in_ecount (* NumCharacters)PUSHORT String,__in PUSHORT NumCharacters,__in UCHAR StringIndex,__in_opt USHORT LangID,__in_opt WDFREQUEST Request,__in_opt PWDF_REQUEST_SEND_OPTIONS Options)334 FxUsbDevice::GetString(
335 __in_ecount(*NumCharacters) PUSHORT String,
336 __in PUSHORT NumCharacters,
337 __in UCHAR StringIndex,
338 __in_opt USHORT LangID,
339 __in_opt WDFREQUEST Request,
340 __in_opt PWDF_REQUEST_SEND_OPTIONS Options
341 )
342 {
343 UMURB urb;
344 PUSB_STRING_DESCRIPTOR pDescriptor;
345 PVOID buffer = NULL;
346 USB_COMMON_DESCRIPTOR common;
347 ULONG length;
348 NTSTATUS status;
349
350 if (String != NULL) {
351 length = sizeof(USB_STRING_DESCRIPTOR) + (*NumCharacters - 1) * sizeof(WCHAR);
352
353 buffer = FxPoolAllocate(GetDriverGlobals(),
354 NonPagedPool,
355 length);
356
357 if (buffer == NULL) {
358 status = STATUS_INSUFFICIENT_RESOURCES;
359 goto Done;
360 }
361
362 RtlZeroMemory(buffer, length);
363 pDescriptor = (PUSB_STRING_DESCRIPTOR) buffer;
364 }
365 else {
366 RtlZeroMemory(&common, sizeof(common));
367
368 length = sizeof(USB_COMMON_DESCRIPTOR);
369 pDescriptor = (PUSB_STRING_DESCRIPTOR) &common;
370 }
371
372 FxUsbUmInitDescriptorUrb(&urb,
373 m_WinUsbHandle,
374 USB_STRING_DESCRIPTOR_TYPE,
375 length,
376 pDescriptor);
377 urb.UmUrbDescriptorRequest.Index = StringIndex;
378 urb.UmUrbDescriptorRequest.LanguageID = LangID;
379
380 status = SendSyncUmUrb(&urb, 2, Request, Options);
381 if (NT_SUCCESS(status)) {
382 USHORT numChars;
383
384 //
385 // Make sure we got an even number of bytes and that we got a header
386 //
387 if ((pDescriptor->bLength & 0x1) ||
388 pDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) {
389 status = STATUS_DEVICE_DATA_ERROR;
390 }
391 else {
392 //
393 // bLength is the length of the entire descriptor. Subtract off
394 // the descriptor header and then divide by the size of a WCHAR.
395 //
396 numChars =
397 (pDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(WCHAR);
398
399 if (String != NULL) {
400 if (*NumCharacters >= numChars) {
401 length = numChars * sizeof(WCHAR);
402 }
403 else {
404 length = *NumCharacters * sizeof(WCHAR);
405 status = STATUS_BUFFER_OVERFLOW;
406 }
407
408 *NumCharacters = numChars;
409 RtlCopyMemory(String, pDescriptor->bString, length);
410 }
411 else {
412 *NumCharacters = numChars;
413 }
414 }
415 }
416
417 if (buffer != NULL) {
418 FxPoolFree(buffer);
419 }
420
421 Done:
422
423 return status;
424 }
425
426 _Must_inspect_result_
427 NTSTATUS
FormatStringRequest(__in FxRequestBase * Request,__in FxRequestBuffer * RequestBuffer,__in UCHAR StringIndex,__in USHORT LangID)428 FxUsbDevice::FormatStringRequest(
429 __in FxRequestBase* Request,
430 __in FxRequestBuffer *RequestBuffer,
431 __in UCHAR StringIndex,
432 __in USHORT LangID
433 )
434 /*++
435
436 Routine Description:
437 Formats a request to retrieve a string from a string descriptor
438
439 Arguments:
440 Request - request to format
441
442 RequestBuffer - Buffer to be filled in when the request has completed
443
444 StringIndex - index of the string
445
446 LandID - language ID of the string to be retrieved
447
448 Return Value:
449 NTSTATUS
450
451 --*/
452 {
453 NTSTATUS status;
454 FxUsbDeviceStringContext* pContext;
455
456 status = Request->ValidateTarget(this);
457 if (NT_SUCCESS(status)) {
458 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
459 "WDFUSBDEVICE %p, Request %p, setting target failed, "
460 "%!STATUS!", GetHandle(), Request, status);
461
462 return status;
463 }
464
465 if (Request->HasContextType(FX_RCT_USB_STRING_REQUEST)) {
466 pContext = (FxUsbDeviceStringContext*) Request->GetContext();
467 }
468 else {
469 pContext = new(GetDriverGlobals()) FxUsbDeviceStringContext(FxUrbTypeLegacy);
470 if (pContext == NULL) {
471 return STATUS_INSUFFICIENT_RESOURCES;
472 }
473
474 Request->SetContext(pContext);
475 }
476
477 FxUsbUmInitDescriptorUrb(&pContext->m_UmUrb,
478 m_WinUsbHandle,
479 USB_STRING_DESCRIPTOR_TYPE,
480 0,
481 NULL);
482
483 status = pContext->AllocateDescriptor(GetDriverGlobals(),
484 RequestBuffer->GetBufferLength());
485 if (!NT_SUCCESS(status)) {
486 return status;
487 }
488
489 pContext->StoreAndReferenceMemory(RequestBuffer);
490 pContext->SetUrbInfo(StringIndex, LangID);
491
492 FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_pHostTargetFile);
493
494 return STATUS_SUCCESS;
495 }
496
497 _Must_inspect_result_
498 NTSTATUS
FormatControlRequest(__in FxRequestBase * Request,__in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket,__in FxRequestBuffer * RequestBuffer)499 FxUsbDevice::FormatControlRequest(
500 __in FxRequestBase* Request,
501 __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket,
502 __in FxRequestBuffer *RequestBuffer
503 )
504 {
505 FxUsbDeviceControlContext* pContext;
506 NTSTATUS status;
507 size_t bufferSize;
508
509 bufferSize = RequestBuffer->GetBufferLength();
510
511 //
512 // We can only transfer 2 bytes worth of data, so if the buffer is larger,
513 // fail here.
514 //
515 if (bufferSize > 0xFFFF) {
516 DoTraceLevelMessage(
517 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
518 "Control transfer buffer is limited to 0xFFFF bytes in size, "
519 "%I64d requested ", bufferSize);
520
521 return STATUS_INVALID_PARAMETER;
522 }
523
524 status = Request->ValidateTarget(this);
525 if (!NT_SUCCESS(status)) {
526 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
527 "WDFUSBDEVICE %p, Request %p, setting target failed, "
528 "%!STATUS!", GetHandle(), Request, status);
529 return status;
530 }
531
532 if (Request->HasContextType(FX_RCT_USB_CONTROL_REQUEST)) {
533 pContext = (FxUsbDeviceControlContext*) Request->GetContext();
534 }
535 else {
536 pContext = new(GetDriverGlobals()) FxUsbDeviceControlContext(FxUrbTypeLegacy);
537 if (pContext == NULL) {
538 return STATUS_INSUFFICIENT_RESOURCES;
539 }
540
541 Request->SetContext(pContext);
542 }
543
544 FxUsbUmInitControlTransferUrb(&pContext->m_UmUrb,
545 m_WinUsbHandle,
546 0,
547 NULL);
548
549 pContext->StoreAndReferenceMemory(this, RequestBuffer, SetupPacket);
550
551 FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_pHostTargetFile);
552
553 return STATUS_SUCCESS;
554 }
555
556 VOID
StoreAndReferenceMemory(__in FxUsbDevice * Device,__in FxRequestBuffer * Buffer,__in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket)557 FxUsbDeviceControlContext::StoreAndReferenceMemory(
558 __in FxUsbDevice* Device,
559 __in FxRequestBuffer* Buffer,
560 __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket
561 )
562 {
563 SetUsbType(WdfUsbRequestTypeDeviceControlTransfer);
564
565 FxUsbRequestContext::StoreAndReferenceMemory(Buffer); // __super call
566
567 //
568 // Convert WDF_USB_CONTROL_SETUP_PACKET to WINUSB_SETUP_PACKET
569 //
570 m_UmUrb.UmUrbControlTransfer.SetupPacket.RequestType = SetupPacket->Packet.bm.Byte;
571 m_UmUrb.UmUrbControlTransfer.SetupPacket.Request = SetupPacket->Packet.bRequest;
572 m_UmUrb.UmUrbControlTransfer.SetupPacket.Value = SetupPacket->Packet.wValue.Value;
573 m_UmUrb.UmUrbControlTransfer.SetupPacket.Index = SetupPacket->Packet.wIndex.Value;
574
575 //
576 // Set the TransferBuffer values using what is stored in the Buffer
577 //
578 Buffer->AssignValues(&m_UmUrb.UmUrbControlTransfer.TransferBuffer,
579 NULL,
580 &m_UmUrb.UmUrbControlTransfer.TransferBufferLength);
581
582 m_UmUrb.UmUrbControlTransfer.SetupPacket.Length =
583 (USHORT)m_UmUrb.UmUrbControlTransfer.TransferBufferLength;
584 }
585
586 _Must_inspect_result_
587 NTSTATUS
588 FxUsbDevice::QueryUsbCapability(
589 __in
590 CONST GUID* CapabilityType,
591 __in
592 ULONG CapabilityBufferLength,
593 __drv_when(CapabilityBufferLength == 0, __out_opt)
594 __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength))
595 __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength))
596 PVOID CapabilityBuffer,
597 __out_opt
598 __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength))
599 PULONG ResultLength
600 )
601 {
602 NTSTATUS status;
603
604 if (ResultLength != NULL) {
605 *ResultLength = 0;
606 }
607
608 //
609 // We cannot send an actual query to the USB stack through winusb.
610 // However, we have the information to handle this query. It is not
611 // ideal to implement this API in this manner because we are making
612 // assumptions about the behavior of USB stack that can change in future.
613 // However, it is too late in the OS cycle to implement a correct solution.
614 // The ideal way is for winusb to expose this information. We should
615 // revisit this API in blue+1
616 //
617 if (RtlCompareMemory(CapabilityType,
618 &GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE,
619 sizeof(GUID)) == sizeof(GUID)) {
620 if (m_Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) {
621 status = STATUS_SUCCESS;
622 } else {
623 status = STATUS_NOT_SUPPORTED;
624 }
625 }
626 else if (RtlCompareMemory(CapabilityType,
627 &GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE,
628 sizeof(GUID)) == sizeof(GUID)) {
629 if (m_DeviceDescriptor.bcdUSB >= 0x300) {
630 status = STATUS_SUCCESS;
631 } else {
632 status = STATUS_NOT_SUPPORTED;
633 }
634 }
635 else if (RtlCompareMemory(CapabilityType,
636 &GUID_USB_CAPABILITY_SELECTIVE_SUSPEND,
637 sizeof(GUID)) == sizeof(GUID)) {
638 //
639 // Both EHCI as well as XHCI stack support selective suspend.
640 // Since XHCI UCX interface is not open, there aren't any
641 // third party controller drivers to worry about. This can
642 // of course change in future
643 //
644 status = STATUS_SUCCESS;
645 }
646 else if (RtlCompareMemory(CapabilityType,
647 &GUID_USB_CAPABILITY_FUNCTION_SUSPEND,
648 sizeof(GUID)) == sizeof(GUID)) {
649 //
650 // Note that a SuperSpeed device will report a bcdUSB of 2.1
651 // when working on a 2.0 port. Therefore a bcdUSB of 3.0 also
652 // indicates that the device is actually working on 3.0, in
653 // which case we always support function suspend
654 //
655 if (m_DeviceDescriptor.bcdUSB >= 0x300) {
656 status = STATUS_SUCCESS;
657 } else {
658 status = STATUS_NOT_SUPPORTED;
659 }
660 }
661 else {
662 //
663 // We do not support chained MDLs or streams for a UMDF driver
664 // GUID_USB_CAPABILITY_CHAINED_MDLS
665 // GUID_USB_CAPABILITY_STATIC_STREAMS
666 //
667 status = STATUS_NOT_SUPPORTED;
668 }
669
670 return status;
671 }
672
673 _Must_inspect_result_
674 NTSTATUS
SelectConfigSingle(__in PWDF_OBJECT_ATTRIBUTES PipeAttributes,__in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params)675 FxUsbDevice::SelectConfigSingle(
676 __in PWDF_OBJECT_ATTRIBUTES PipeAttributes,
677 __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
678 )
679 /*++
680
681 Routine Description:
682 Since the device is already configured, all this routine
683 does is to make sure the alternate setting 0 is selected,
684 in case the client driver selected some other alternate
685 setting after the initial configuration
686
687 Arguments:
688
689
690 Return Value:
691 NTSTATUS
692
693 --*/
694 {
695 NTSTATUS status;
696
697 RtlZeroMemory(&Params->Types.SingleInterface,
698 sizeof(Params->Types.SingleInterface));
699
700 if (m_NumInterfaces > 1) {
701 status = STATUS_INVALID_PARAMETER;
702
703 DoTraceLevelMessage(
704 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
705 "WDFUSBDEVICE %p cannot be auto configured for a single interface "
706 "since there are %d interfaces on the device, %!STATUS!",
707 GetHandle(), m_NumInterfaces, status);
708
709 return status;
710 }
711
712 //
713 // Use AlternateSetting 0 by default
714 //
715 if (m_Interfaces[0]->GetSettingDescriptor(0) == NULL) {
716 DoTraceLevelMessage(
717 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
718 "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for "
719 "bInterfaceNumber %d", GetHandle(),
720 m_Interfaces[0]->m_InterfaceNumber);
721
722 return STATUS_INVALID_PARAMETER;
723 }
724
725 status = m_Interfaces[0]->CheckAndSelectSettingByIndex(0);
726
727 if (!NT_SUCCESS(status)) {
728 DoTraceLevelMessage(
729 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
730 "WDFUSBDEVICE %p set AlternateSetting 0 for interface 0"
731 "failed, %!STATUS!", GetHandle(), status);
732
733 return status;
734 }
735
736 if (PipeAttributes) {
737 status = m_Interfaces[0]->UpdatePipeAttributes(PipeAttributes);
738 }
739
740 Params->Types.SingleInterface.ConfiguredUsbInterface =
741 m_Interfaces[0]->GetHandle();
742
743 Params->Types.SingleInterface.NumberConfiguredPipes =
744 m_Interfaces[0]->GetNumConfiguredPipes();
745
746 return status;
747 }
748
749 _Must_inspect_result_
750 NTSTATUS
SelectConfigMulti(__in PWDF_OBJECT_ATTRIBUTES PipeAttributes,__in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params)751 FxUsbDevice::SelectConfigMulti(
752 __in PWDF_OBJECT_ATTRIBUTES PipeAttributes,
753 __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
754 )
755 /*++
756
757 Routine Description:
758 Since the device is already configured, all this routine
759 does is to make sure the alternate setting 0 is selected
760 for all interfaces, in case the client driver selected some
761 other alternate setting after the initial configuration
762
763
764 Arguments:
765 PipeAttributes - Should be NULL
766
767 Params -
768
769 Return Value:
770 NTSTATUS
771
772 --*/
773 {
774 FxUsbInterface * pUsbInterface;
775 NTSTATUS status;
776 UCHAR i;
777 PFX_DRIVER_GLOBALS pFxDriverGlobals;
778
779 pFxDriverGlobals = GetDriverGlobals();
780
781 Params->Types.MultiInterface.NumberOfConfiguredInterfaces = 0;
782
783 if (Params->Type == WdfUsbTargetDeviceSelectConfigTypeMultiInterface) {
784 for (i = 0; i < m_NumInterfaces; i++) {
785
786 if (m_Interfaces[i]->GetSettingDescriptor(0) == NULL) {
787 DoTraceLevelMessage(
788 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
789 "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for "
790 "bInterfaceNumber %d", GetHandle(),
791 m_Interfaces[i]->m_InterfaceNumber);
792
793 status = STATUS_INVALID_PARAMETER;
794 goto Done;
795 }
796
797 status = m_Interfaces[i]->CheckAndSelectSettingByIndex(0);
798 if (!NT_SUCCESS(status)) {
799 DoTraceLevelMessage(
800 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
801 "WDFUSBDEVICE %p set AlternateSetting 0 for bInterfaceNumber %d"
802 "failed, %!STATUS!",
803 GetHandle(), m_Interfaces[i]->m_InterfaceNumber, status);
804 goto Done;
805 }
806 if (PipeAttributes) {
807 status = m_Interfaces[i]->UpdatePipeAttributes(PipeAttributes);
808 }
809 }
810 }
811 else {
812 //
813 // Type is WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs
814 //
815 UCHAR interfacePairsNum = 0;
816 UCHAR bitArray[UCHAR_MAX/sizeof(UCHAR)];
817
818 //
819 // initialize the bit array
820 //
821 RtlZeroMemory(bitArray, sizeof(bitArray));
822 //
823 // Build a list of descriptors from the Setting pairs
824 // passed in by the user. There could be interfaces not
825 // covered in the setting/interface pairs array passed.
826 // If that is the case return STATUS_INVALID_PARAMETER
827 //
828 for (i = 0; i < Params->Types.MultiInterface.NumberInterfaces ; i++) {
829 PWDF_USB_INTERFACE_SETTING_PAIR settingPair;
830 UCHAR interfaceNumber;
831 UCHAR altSettingIndex;
832
833 settingPair = &Params->Types.MultiInterface.Pairs[i];
834
835 FxObjectHandleGetPtr(GetDriverGlobals(),
836 settingPair->UsbInterface,
837 FX_TYPE_USB_INTERFACE ,
838 (PVOID*) &pUsbInterface);
839
840 interfaceNumber = pUsbInterface->GetInterfaceNumber();
841 altSettingIndex = settingPair->SettingIndex;
842
843 //
844 // do the following only if the bit is not already set
845 //
846 if (FxBitArraySet(&bitArray[0], interfaceNumber) == FALSE) {
847
848 if (pUsbInterface->GetSettingDescriptor(altSettingIndex) == NULL) {
849 status = STATUS_INVALID_PARAMETER;
850 DoTraceLevelMessage(
851 GetDriverGlobals(), TRACE_LEVEL_ERROR,
852 TRACINGIOTARGET,
853 "WDFUSBDEVICE %p could not retrieve "
854 "AlternateSetting %d for "
855 "bInterfaceNumber %d, returning %!STATUS!",
856 GetHandle(),
857 altSettingIndex, interfaceNumber, status);
858 goto Done;
859 }
860
861 interfacePairsNum++;
862
863 //
864 // Ensure alternate setting 0 is selected
865 //
866 status = pUsbInterface->CheckAndSelectSettingByIndex(
867 settingPair->SettingIndex);
868
869 if (!NT_SUCCESS(status)) {
870 DoTraceLevelMessage(
871 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
872 "WDFUSBDEVICE %p set AlternateSetting %d for bInterfaceNumber %d"
873 "failed, %!STATUS!",
874 GetHandle(), altSettingIndex, m_Interfaces[i]->m_InterfaceNumber,
875 status);
876 goto Done;
877 }
878
879 if (PipeAttributes) {
880 status = pUsbInterface->UpdatePipeAttributes(PipeAttributes);
881 }
882 }
883
884 }
885
886 if (m_NumInterfaces > interfacePairsNum) {
887 status = STATUS_INVALID_PARAMETER;
888 DoTraceLevelMessage(
889 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
890 "WDFUSBDEVICE %p interface pairs set (%d) is not equal to actual "
891 "# of interfaces (%d) reported by the device, %!STATUS!",
892 GetObjectHandle(), interfacePairsNum, m_NumInterfaces, status);
893 goto Done;
894 }
895 } //WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs
896
897 status = STATUS_SUCCESS;
898 Params->Types.MultiInterface.NumberOfConfiguredInterfaces = m_NumInterfaces;
899
900 Done:
901 return status;
902 }
903
904
905 _Must_inspect_result_
906 NTSTATUS
Reset(VOID)907 FxUsbDevice::Reset(
908 VOID
909 )
910 {
911 UMURB urb;
912 NTSTATUS status;
913
914 RtlZeroMemory(&urb, sizeof(UMURB));
915
916 urb.UmUrbSelectInterface.Hdr.Function = UMURB_FUNCTION_RESET_PORT;
917 urb.UmUrbSelectInterface.Hdr.Length = sizeof(_UMURB_HEADER);
918
919 status = SendSyncUmUrb(&urb, 2);
920
921 return status;
922 }
923
924