1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxUsbDevice.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 "FxUsbDevice.tmh"
30 }
31
32 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
33 #define UCHAR_MAX (0xff)
34 #endif
35
FxUsbDeviceControlContext(__in FX_URB_TYPE FxUrbType)36 FxUsbDeviceControlContext::FxUsbDeviceControlContext(
37 __in FX_URB_TYPE FxUrbType
38 ) :
39 FxUsbRequestContext(FX_RCT_USB_CONTROL_REQUEST)
40 {
41 m_PartialMdl = NULL;
42 m_UnlockPages = FALSE;
43 m_USBDHandle = NULL;
44
45 if (FxUrbType == FxUrbTypeLegacy) {
46 m_Urb = &m_UrbLegacy;
47 }
48 else {
49 m_Urb = NULL;
50 }
51 }
52
~FxUsbDeviceControlContext(VOID)53 FxUsbDeviceControlContext::~FxUsbDeviceControlContext(
54 VOID
55 )
56 {
57 if (m_Urb && (m_Urb != &m_UrbLegacy)) {
58 USBD_UrbFree(m_USBDHandle, (PURB)m_Urb);
59 }
60 m_Urb = NULL;
61 m_USBDHandle = NULL;
62 }
63
64 __checkReturn
65 NTSTATUS
AllocateUrb(__in USBD_HANDLE USBDHandle)66 FxUsbDeviceControlContext::AllocateUrb(
67 __in USBD_HANDLE USBDHandle
68 )
69 {
70 NTSTATUS status;
71
72 ASSERT(USBDHandle != NULL);
73 ASSERT(m_Urb == NULL);
74
75 status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb);
76
77 if (!NT_SUCCESS(status)) {
78 goto Done;
79 }
80
81 m_USBDHandle = USBDHandle;
82
83 Done:
84 return status;
85 }
86
87 VOID
Dispose(VOID)88 FxUsbDeviceControlContext::Dispose(
89 VOID
90 )
91 {
92 if (m_Urb && (m_Urb != &m_UrbLegacy)){
93 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb);
94 m_Urb = NULL;
95 m_USBDHandle = NULL;
96 }
97 }
98
99 VOID
CopyParameters(__in FxRequestBase * Request)100 FxUsbDeviceControlContext::CopyParameters(
101 __in FxRequestBase* Request
102 )
103 {
104 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
105 m_CompletionParams.IoStatus.Information = m_Urb->TransferBufferLength;
106 m_UsbParameters.Parameters.DeviceControlTransfer.Length = m_Urb->TransferBufferLength;
107 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
108 m_CompletionParams.IoStatus.Information = m_UmUrb.UmUrbControlTransfer.TransferBufferLength;
109 m_UsbParameters.Parameters.DeviceControlTransfer.Length = m_UmUrb.UmUrbControlTransfer.TransferBufferLength;
110 #endif
111 FxUsbRequestContext::CopyParameters(Request); // __super call
112 }
113
114 VOID
ReleaseAndRestore(__in FxRequestBase * Request)115 FxUsbDeviceControlContext::ReleaseAndRestore(
116 __in FxRequestBase* Request
117 )
118 {
119 //
120 // Check now because Init will NULL out the field
121 //
122 if (m_PartialMdl != NULL) {
123 if (m_UnlockPages) {
124 Mx::MxUnlockPages(m_PartialMdl);
125 m_UnlockPages = FALSE;
126 }
127
128 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
129 FxMdlFree(Request->GetDriverGlobals(), m_PartialMdl);
130 #endif
131 m_PartialMdl = NULL;
132 }
133
134 FxUsbRequestContext::ReleaseAndRestore(Request); // __super call
135 }
136
137 USBD_STATUS
GetUsbdStatus(VOID)138 FxUsbDeviceControlContext::GetUsbdStatus(
139 VOID
140 )
141 {
142 return m_Urb->Hdr.Status;
143 }
144
FxUsbDeviceStringContext(__in FX_URB_TYPE FxUrbType)145 FxUsbDeviceStringContext::FxUsbDeviceStringContext(
146 __in FX_URB_TYPE FxUrbType
147 ) :
148 FxUsbRequestContext(FX_RCT_USB_STRING_REQUEST)
149 {
150 m_USBDHandle = NULL;
151 m_StringDescriptor = NULL;
152 m_StringDescriptorLength = 0;
153 RtlZeroMemory(&m_UrbLegacy, sizeof(m_UrbLegacy));
154
155 if (FxUrbType == FxUrbTypeLegacy) {
156 m_Urb = &m_UrbLegacy;
157 m_Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
158 m_Urb->Hdr.Length = sizeof(*m_Urb);
159 m_Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE;
160 }
161 else {
162 m_Urb = NULL;
163 }
164 }
165
~FxUsbDeviceStringContext(VOID)166 FxUsbDeviceStringContext::~FxUsbDeviceStringContext(
167 VOID
168 )
169 {
170 if (m_StringDescriptor != NULL) {
171 FxPoolFree(m_StringDescriptor);
172 m_StringDescriptor = NULL;
173 }
174
175 if (m_Urb && (m_Urb != &m_UrbLegacy)){
176 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb);
177 }
178 m_Urb = NULL;
179 m_USBDHandle = NULL;
180 }
181
182 __checkReturn
183 NTSTATUS
AllocateUrb(__in USBD_HANDLE USBDHandle)184 FxUsbDeviceStringContext::AllocateUrb(
185 __in USBD_HANDLE USBDHandle
186 )
187 {
188 NTSTATUS status;
189
190 ASSERT(USBDHandle != NULL);
191 ASSERT(m_Urb == NULL);
192
193 status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb);
194
195 if (!NT_SUCCESS(status)) {
196 goto Done;
197 }
198
199 m_USBDHandle = USBDHandle;
200
201 m_Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
202 m_Urb->Hdr.Length = sizeof(*m_Urb);
203 m_Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE;
204
205 Done:
206 return status;
207 }
208
209 VOID
Dispose(VOID)210 FxUsbDeviceStringContext::Dispose(
211 VOID
212 )
213 {
214 if (m_Urb && (m_Urb != &m_UrbLegacy)){
215 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb);
216 m_Urb = NULL;
217 m_USBDHandle = NULL;
218 }
219
220 }
221
222 VOID
CopyParameters(__in FxRequestBase * Request)223 FxUsbDeviceStringContext::CopyParameters(
224 __in FxRequestBase* Request
225 )
226 {
227 //
228 // Make sure we got an even number of bytes and that we got a header
229 //
230 if ((m_StringDescriptor->bLength & 0x1) ||
231 m_StringDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) {
232 m_CompletionParams.IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
233 }
234 else if (NT_SUCCESS(Request->GetSubmitFxIrp()->GetStatus())) {
235 //
236 // No matter what, indicate the required size to the caller
237 //
238 m_UsbParameters.Parameters.DeviceString.RequiredSize =
239 m_StringDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR);
240
241 if (m_UsbParameters.Parameters.DeviceString.RequiredSize >
242 m_RequestMemory->GetBufferSize()) {
243 //
244 // Too much string to fit into the buffer supplied by the client.
245 // Morph the status into a warning. Copy as much as we can.
246 //
247 m_CompletionParams.IoStatus.Status = STATUS_BUFFER_OVERFLOW;
248 RtlCopyMemory(m_RequestMemory->GetBuffer(),
249 &m_StringDescriptor->bString[0],
250 m_RequestMemory->GetBufferSize());
251 }
252 else {
253 //
254 // Everything fits, copy it over
255 //
256 m_CompletionParams.IoStatus.Information =
257 m_UsbParameters.Parameters.DeviceString.RequiredSize;
258
259 RtlCopyMemory(m_RequestMemory->GetBuffer(),
260 &m_StringDescriptor->bString[0],
261 m_UsbParameters.Parameters.DeviceString.RequiredSize);
262 }
263 }
264
265 FxUsbRequestContext::CopyParameters(Request); // __super call
266 }
267
268 VOID
SetUrbInfo(__in UCHAR StringIndex,__in USHORT LangID)269 FxUsbDeviceStringContext::SetUrbInfo(
270 __in UCHAR StringIndex,
271 __in USHORT LangID
272 )
273 {
274 SetUsbType(WdfUsbRequestTypeDeviceString);
275
276 ASSERT(m_StringDescriptor != NULL && m_StringDescriptorLength != 0);
277
278 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
279 m_Urb->TransferBuffer = m_StringDescriptor;
280 m_Urb->TransferBufferLength = m_StringDescriptorLength;
281
282 m_Urb->Index = StringIndex;
283 m_Urb->LanguageId = LangID;
284 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
285 m_UmUrb.UmUrbDescriptorRequest.Buffer = m_StringDescriptor;
286 m_UmUrb.UmUrbDescriptorRequest.BufferLength = m_StringDescriptorLength;
287
288 m_UmUrb.UmUrbDescriptorRequest.Index = StringIndex;
289 m_UmUrb.UmUrbDescriptorRequest.LanguageID = LangID;
290 #endif
291 }
292
293 USBD_STATUS
GetUsbdStatus(VOID)294 FxUsbDeviceStringContext::GetUsbdStatus(
295 VOID
296 )
297 {
298 return m_Urb->Hdr.Status;
299 }
300
301 _Must_inspect_result_
302 NTSTATUS
AllocateDescriptor(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in size_t BufferSize)303 FxUsbDeviceStringContext::AllocateDescriptor(
304 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
305 __in size_t BufferSize
306 )
307 {
308 PUSB_STRING_DESCRIPTOR pDescriptor;
309 size_t length;
310 NTSTATUS status;
311
312 if (BufferSize <= m_StringDescriptorLength) {
313 return STATUS_SUCCESS;
314 }
315
316 length = sizeof(USB_STRING_DESCRIPTOR) - sizeof(pDescriptor->bString[0]) +
317 BufferSize;
318
319 pDescriptor = (PUSB_STRING_DESCRIPTOR) FxPoolAllocate(
320 FxDriverGlobals,
321 NonPagedPool,
322 length);
323
324 if (pDescriptor == NULL) {
325 return STATUS_INSUFFICIENT_RESOURCES;
326 }
327
328 if (m_StringDescriptor != NULL) {
329 FxPoolFree(m_StringDescriptor);
330 }
331
332 RtlZeroMemory(pDescriptor, length);
333
334 m_StringDescriptor = pDescriptor;
335
336 status = RtlSizeTToULong(length, &m_StringDescriptorLength);
337
338 return status;
339 }
340
FxUsbUrb(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in USBD_HANDLE USBDHandle,__in_bcount (BufferSize)PVOID Buffer,__in size_t BufferSize)341 FxUsbUrb::FxUsbUrb(
342 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
343 __in USBD_HANDLE USBDHandle,
344 __in_bcount(BufferSize) PVOID Buffer,
345 __in size_t BufferSize
346 ) :
347 FxMemoryBufferPreallocated(FxDriverGlobals, sizeof(*this), Buffer, BufferSize),
348 m_USBDHandle(USBDHandle)
349 {
350 MarkDisposeOverride();
351 }
352
~FxUsbUrb()353 FxUsbUrb::~FxUsbUrb()
354 {
355 }
356
357 BOOLEAN
Dispose(VOID)358 FxUsbUrb::Dispose(
359 VOID
360 )
361 {
362 ASSERT(m_USBDHandle != NULL);
363 ASSERT(m_pBuffer != NULL);
364 USBD_UrbFree(m_USBDHandle, (PURB)m_pBuffer);
365 m_pBuffer = NULL;
366 m_USBDHandle = NULL;
367
368 return FxMemoryBufferPreallocated::Dispose(); // __super call
369 }
370
FxUsbDevice(__in PFX_DRIVER_GLOBALS FxDriverGlobals)371 FxUsbDevice::FxUsbDevice(
372 __in PFX_DRIVER_GLOBALS FxDriverGlobals
373 ) :
374 FxIoTarget(FxDriverGlobals, sizeof(FxUsbDevice), FX_TYPE_IO_TARGET_USB_DEVICE)
375 {
376 RtlZeroMemory(&m_DeviceDescriptor, sizeof(m_DeviceDescriptor));
377 RtlZeroMemory(&m_UsbdVersionInformation, sizeof(m_UsbdVersionInformation));
378
379 m_OnUSBD = FALSE;
380 m_Interfaces = NULL;;
381 m_NumInterfaces = 0;
382
383 m_Traits = 0;
384 m_HcdPortCapabilities = 0;
385 m_ControlPipe = NULL;
386 m_QueryBusTime = NULL;
387 m_BusInterfaceContext = NULL;
388 m_BusInterfaceDereference = NULL;
389 m_ConfigHandle = NULL;
390 m_ConfigDescriptor = NULL;
391
392 m_MismatchedInterfacesInConfigDescriptor = FALSE;
393
394 m_USBDHandle = NULL;
395 m_UrbType = FxUrbTypeLegacy;
396
397 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
398 m_pHostTargetFile = NULL;
399 m_WinUsbHandle = NULL;
400 #endif
401
402 MarkDisposeOverride(ObjectDoNotLock);
403 }
404
405 BOOLEAN
Dispose(VOID)406 FxUsbDevice::Dispose(
407 VOID
408 )
409 {
410 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
411 KeFlushQueuedDpcs();
412 #endif
413
414 if (m_USBDHandle) {
415 USBD_CloseHandle(m_USBDHandle);
416 m_USBDHandle = NULL;
417 }
418
419 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
420 IWudfDevice* device = NULL;
421 IWudfDeviceStack* devstack = NULL;
422
423 device = m_DeviceBase->GetDeviceObject();
424 devstack = device->GetDeviceStackInterface();
425
426 if (m_pHostTargetFile) {
427 devstack->CloseFile(m_pHostTargetFile);
428 SAFE_RELEASE(m_pHostTargetFile);
429 }
430 #endif
431
432 return FxIoTarget::Dispose(); // __super call
433 }
434
~FxUsbDevice()435 FxUsbDevice::~FxUsbDevice()
436 {
437 UCHAR i;
438
439 if (m_BusInterfaceDereference != NULL) {
440 m_BusInterfaceDereference(m_BusInterfaceContext);
441 m_BusInterfaceDereference = NULL;
442 }
443
444 if (m_ConfigDescriptor != NULL) {
445 FxPoolFree(m_ConfigDescriptor);
446 m_ConfigDescriptor = NULL;
447 }
448
449 for (i = 0; i < m_NumInterfaces; i++) {
450 ASSERT(m_Interfaces[i] == NULL);
451 }
452
453 if (m_Interfaces != NULL){
454 FxPoolFree(m_Interfaces);
455 m_Interfaces = NULL;
456 }
457
458 m_NumInterfaces = 0;
459 }
460
461 VOID
RemoveDeletedInterface(__in FxUsbInterface * Interface)462 FxUsbDevice::RemoveDeletedInterface(
463 __in FxUsbInterface* Interface
464 )
465 {
466 UCHAR i;
467
468 if (m_Interfaces == NULL) {
469 return;
470 }
471
472 for (i = 0; i < m_NumInterfaces; i++) {
473 if (m_Interfaces[i] == Interface) {
474 m_Interfaces[i] = NULL;
475 return;
476 }
477 }
478 }
479
480 VOID
GetInformation(__out PWDF_USB_DEVICE_INFORMATION Information)481 FxUsbDevice::GetInformation(
482 __out PWDF_USB_DEVICE_INFORMATION Information
483 )
484 {
485 Information->Traits = m_Traits;
486 Information->HcdPortCapabilities = m_HcdPortCapabilities;
487
488 RtlCopyMemory(&Information->UsbdVersionInformation,
489 &m_UsbdVersionInformation,
490 sizeof(m_UsbdVersionInformation));
491 }
492
493 ULONG
GetDefaultMaxTransferSize(VOID)494 FxUsbDevice::GetDefaultMaxTransferSize(
495 VOID
496 )
497 /*++
498
499 Routine Description:
500 Determines the default max transfer size based on the usb host controller
501 and OS we are running on. What it boils down to is that on XP and later
502 the usb core ignores the default max transfer size, but it does use the
503 value on Windows 2000. To make life fun, there is only one definition of
504 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE whose value changes depending on header
505 versioning. Since we are versioned for the latest OS, we do not pick up the
506 Win2k value by using the #define, rather we have to use the value that we
507 *would* have picked up if we were header versioned for Win2k.
508
509 NOTE: we could be on win2k with a usbport serviced stack. in this case,
510 usbport doesn't care about max transfer sizes
511
512 Arguments:
513 None
514
515 Return Value:
516 usb core and OS appropriate default max transfer size.
517
518 --*/
519 {
520 //
521 // On a usbport serviced stack (which can be running on Win2k) or on a
522 // usbd stack on XP and later. In any case, always use the current max
523 // transfer size definition.
524 //
525 return USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
526 }
527
528 _Must_inspect_result_
529 NTSTATUS
Start(VOID)530 FxUsbDevice::Start(
531 VOID
532 )
533 {
534 NTSTATUS status;
535
536 status = FxIoTarget::Start();
537
538 if (NT_SUCCESS(status)) {
539 FxRequestBase* pRequest;
540 LIST_ENTRY head, *ple;
541 ULONG i, iInterface;
542 FxUsbInterface *pUsbInterface;
543 KIRQL irql;
544
545 InitializeListHead(&head);
546
547 Lock(&irql);
548
549 //
550 // Iterate over all of the interfaces. For each pipe on each interface,
551 // grab all pended i/o for later submission.
552 //
553 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++){
554
555 pUsbInterface = m_Interfaces[iInterface];
556
557 for (i = 0; i < pUsbInterface->m_NumberOfConfiguredPipes; i++) {
558 pUsbInterface->m_ConfiguredPipes[i]->GotoStartState(&head);
559 }
560 }
561 Unlock(irql);
562
563 //
564 // Since we are going to reference the FxUsbPipe's outside of the
565 // lock and the interface can go away in the meantime, add a reference
566 // (multiple times perhaps) to each FxUsbPipe to make sure it sticks
567 // around.
568 //
569 for (ple = head.Flink; ple != &head; ple = ple->Flink) {
570 pRequest = FxRequestBase::_FromListEntry(ple);
571 pRequest->GetTarget()->ADDREF(this);
572 }
573
574 //
575 // Drain the list of pended requests.
576 //
577 while (!IsListEmpty(&head)) {
578 FxIoTarget* pTarget;
579
580 ple = RemoveHeadList(&head);
581
582 pRequest = FxRequestBase::_FromListEntry(ple);
583
584 pTarget = pRequest->GetTarget();
585
586 pTarget->SubmitPendedRequest(pRequest);
587
588 //
589 // Release the reference taken above when accumulating pended i/o.
590 //
591 pTarget->RELEASE(this);
592 }
593 }
594
595 return status;
596 }
597
598 #define STOP_TAG (PVOID) 'pots'
599
600 VOID
Stop(__in WDF_IO_TARGET_SENT_IO_ACTION Action)601 FxUsbDevice::Stop(
602 __in WDF_IO_TARGET_SENT_IO_ACTION Action
603 )
604 {
605 FxUsbInterface *pUsbInterface;
606 SINGLE_LIST_ENTRY head;
607 ULONG iPipe, iInterface;
608 KIRQL irql;
609
610 head.Next = NULL;
611
612 //
613 // Stop all of our own I/O first
614 //
615 FxIoTarget::Stop(Action);
616
617 //
618 // if we are just canceling i/o, then we just acquire the spin lock b/c
619 // we can be called at dispatch level for this action code.
620 //
621 if (Action != WdfIoTargetLeaveSentIoPending) {
622 ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
623
624 AcquireInterfaceIterationLock();
625 }
626
627 //
628 // Since we don't have to synchronize on the I/O already sent, just set
629 // each pipe's state to stop.
630 //
631 Lock(&irql);
632
633 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) {
634 pUsbInterface = m_Interfaces[iInterface];
635
636 if (pUsbInterface->m_ConfiguredPipes != NULL) {
637 for (iPipe = 0;
638 iPipe < pUsbInterface->m_NumberOfConfiguredPipes;
639 iPipe++) {
640
641 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) {
642 BOOLEAN wait;
643
644 wait = FALSE;
645
646 pUsbInterface->m_ConfiguredPipes[iPipe]->GotoStopState(
647 Action,
648 &head,
649 &wait,
650 TRUE
651 );
652 }
653 }
654 }
655 }
656 Unlock(irql);
657
658 //
659 // If we are leaving sent IO pending, the io target will set the IO
660 // completion event during stop even if there is still outstanding IO.
661 //
662
663 if (head.Next != NULL) {
664 _CancelSentRequests(&head);
665 }
666
667 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) {
668 pUsbInterface = m_Interfaces[iInterface];
669
670 if (pUsbInterface->m_ConfiguredPipes != NULL) {
671 //
672 // Iterate over the pipes and clean each one up
673 //
674 for (iPipe = 0;
675 iPipe < pUsbInterface->m_NumberOfConfiguredPipes;
676 iPipe++) {
677 //
678 // Same reason as above
679 //
680 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) {
681 pUsbInterface->m_ConfiguredPipes[iPipe]->
682 WaitForSentIoToComplete();
683 }
684 }
685 }
686 }
687
688 if (Action != WdfIoTargetLeaveSentIoPending) {
689 ReleaseInterfaceIterationLock();
690 }
691 }
692
693 VOID
Purge(__in WDF_IO_TARGET_PURGE_IO_ACTION Action)694 FxUsbDevice::Purge(
695 __in WDF_IO_TARGET_PURGE_IO_ACTION Action
696 )
697 {
698 FxUsbInterface *pUsbInterface;
699 SINGLE_LIST_ENTRY sentHead;
700 ULONG iPipe, iInterface;
701 KIRQL irql;
702
703 sentHead.Next = NULL;
704
705 //
706 // Purge all of our own I/O first
707 //
708 FxIoTarget::Purge(Action);
709
710 //
711 // if we are just canceling i/o, then we just acquire the spin lock b/c
712 // we can be called at dispatch level for this action code.
713 //
714 if (Action != WdfIoTargetPurgeIo) {
715 ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL);
716
717 AcquireInterfaceIterationLock();
718 }
719
720 //
721 // Since we don't have to synchronize on the I/O already sent, just set
722 // each pipe's state to purged.
723 //
724 Lock(&irql);
725
726 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) {
727 pUsbInterface = m_Interfaces[iInterface];
728
729 if (pUsbInterface->m_ConfiguredPipes != NULL) {
730 for (iPipe = 0;
731 iPipe < pUsbInterface->m_NumberOfConfiguredPipes;
732 iPipe++) {
733
734 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) {
735 BOOLEAN wait;
736 LIST_ENTRY pendedHead;
737
738 wait = FALSE;
739 InitializeListHead(&pendedHead);
740
741 pUsbInterface->m_ConfiguredPipes[iPipe]->GotoPurgeState(
742 Action,
743 &pendedHead,
744 &sentHead,
745 &wait,
746 TRUE
747 );
748
749 //
750 // Complete any requests pulled off from this pipe.
751 //
752 pUsbInterface->m_ConfiguredPipes[iPipe]->
753 CompletePendedRequestList(&pendedHead);
754 }
755 }
756 }
757 }
758 Unlock(irql);
759
760 //
761 // Cancel all sent requests.
762 //
763 _CancelSentRequests(&sentHead);
764
765 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) {
766 pUsbInterface = m_Interfaces[iInterface];
767
768 if (pUsbInterface->m_ConfiguredPipes != NULL) {
769 //
770 // Iterate over the pipes and clean each one up
771 //
772 for (iPipe = 0;
773 iPipe < pUsbInterface->m_NumberOfConfiguredPipes;
774 iPipe++) {
775 //
776 // Same reason as above
777 //
778 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) {
779 pUsbInterface->m_ConfiguredPipes[iPipe]->
780 WaitForSentIoToComplete();
781 }
782 }
783 }
784 }
785
786 if (Action != WdfIoTargetPurgeIo) {
787 ReleaseInterfaceIterationLock();
788 }
789 }
790
791 VOID
_CleanupPipesRequests(__in PLIST_ENTRY PendHead,__in PSINGLE_LIST_ENTRY SentHead)792 FxUsbDevice::_CleanupPipesRequests(
793 __in PLIST_ENTRY PendHead,
794 __in PSINGLE_LIST_ENTRY SentHead
795 )
796 {
797 while (!IsListEmpty(PendHead)) {
798 PLIST_ENTRY ple;
799 FxRequestBase* pRequest;
800
801 ple = RemoveHeadList(PendHead);
802
803 InitializeListHead(ple);
804
805 pRequest = FxRequestBase::_FromListEntry(ple);
806 pRequest->GetTarget()->CompletePendedRequest(pRequest);
807 }
808
809 _CancelSentRequests(SentHead);
810 }
811
812 VOID
PipesGotoRemoveState(__in BOOLEAN ForceRemovePipes)813 FxUsbDevice::PipesGotoRemoveState(
814 __in BOOLEAN ForceRemovePipes
815 )
816 {
817 SINGLE_LIST_ENTRY sentHead;
818 LIST_ENTRY pendHead, interfaceHead;
819 FxUsbInterface* pUsbInterface;
820 ULONG iPipe, intfIndex;
821 KIRQL irql;
822
823 sentHead.Next = NULL;
824 InitializeListHead(&pendHead);
825 InitializeListHead(&interfaceHead);
826
827 AcquireInterfaceIterationLock();
828
829 Lock(&irql);
830 for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++ ) {
831 pUsbInterface = m_Interfaces[intfIndex];
832
833 if (pUsbInterface->m_ConfiguredPipes != NULL) {
834 for (iPipe = 0;
835 iPipe < pUsbInterface->m_NumberOfConfiguredPipes;
836 iPipe++) {
837 BOOLEAN wait;
838
839 wait = FALSE;
840
841 //
842 // Pipe can be NULL if the interface is half initialized
843 //
844 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) {
845 pUsbInterface->m_ConfiguredPipes[iPipe]->GotoRemoveState(
846 WdfIoTargetDeleted,
847 &pendHead,
848 &sentHead,
849 TRUE,
850 &wait);
851
852 }
853 }
854 }
855 }
856 Unlock(irql);
857
858 //
859 // We cleanup requests no matter what the new state is because we complete all
860 // pended requests in the surprise removed case.
861 //
862 _CleanupPipesRequests(&pendHead, &sentHead);
863
864 //
865 // Only destroy child pipe objects when the parent is going away or the
866 // caller indicates that this is the desired action.
867 //
868 if (m_State == WdfIoTargetDeleted || ForceRemovePipes) {
869 for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++) {
870 pUsbInterface = m_Interfaces[intfIndex];
871
872 if (pUsbInterface->m_ConfiguredPipes != NULL) {
873 //
874 // Iterate over the pipes and clean each one up
875 //
876 for (iPipe = 0;
877 iPipe < pUsbInterface->m_NumberOfConfiguredPipes;
878 iPipe++) {
879 //
880 // Same reason as above
881 //
882 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) {
883 pUsbInterface->m_ConfiguredPipes[iPipe]->
884 WaitForSentIoToComplete();
885 }
886 }
887 }
888
889 pUsbInterface->CleanUpAndDelete(FALSE);
890 }
891 }
892
893 ReleaseInterfaceIterationLock();
894 }
895
896 _Must_inspect_result_
897 NTSTATUS
CreateInterfaces(VOID)898 FxUsbDevice::CreateInterfaces(
899 VOID
900 )
901 {
902 PFX_DRIVER_GLOBALS pFxDriverGlobals;
903 UCHAR descCountBitMap[UCHAR_MAX / sizeof(UCHAR)];
904 PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor;
905 UCHAR iInterface, numFound;
906 NTSTATUS status;
907 ULONG size;
908 ULONG totalLength;
909
910 pFxDriverGlobals = GetDriverGlobals();
911 status = STATUS_SUCCESS;
912 totalLength = m_ConfigDescriptor->wTotalLength;
913
914 //
915 // Make sure each PCOMMON_DESCRIPTOR_HEADER within the entire config descriptor is well formed.
916 // If successful, we can walk the config descriptor using common headers without any more top
917 // level error checking. Task specific checking of the specialized header types must still occur.
918 //
919 status = FxUsbValidateConfigDescriptorHeaders(
920 pFxDriverGlobals,
921 m_ConfigDescriptor,
922 m_ConfigDescriptor->wTotalLength
923 );
924
925 if (!NT_SUCCESS(status)) {
926 DoTraceLevelMessage(
927 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
928 "Validation of the config descriptor failed due to a bad common descriptor header, %!STATUS!",
929 status);
930 return status;
931 }
932
933 //
934 // Validate all interface descriptors in config descriptor are at least
935 // sizeof(USB_INTERFACE_DESCRIPTOR).
936 //
937
938
939
940
941
942 status = FxUsbValidateDescriptorType(
943 pFxDriverGlobals,
944 m_ConfigDescriptor,
945 m_ConfigDescriptor,
946 WDF_PTR_ADD_OFFSET(m_ConfigDescriptor, m_ConfigDescriptor->wTotalLength),
947 USB_INTERFACE_DESCRIPTOR_TYPE,
948 sizeof(USB_INTERFACE_DESCRIPTOR),
949 FxUsbValidateDescriptorOpAtLeast,
950 0
951 );
952
953 if (!NT_SUCCESS(status)) {
954 DoTraceLevelMessage(
955 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
956 "Validation of interface descriptors in config descriptor failed, %!STATUS!",
957 status);
958
959 return status;
960 }
961
962 if (m_ConfigDescriptor->bNumInterfaces == 0) {
963 //
964 // Use an array of one in the zero case
965 //
966 size = sizeof(FxUsbInterface*);
967 }
968 else {
969 size = sizeof(FxUsbInterface*) * m_ConfigDescriptor->bNumInterfaces;
970 }
971
972 //
973 // Allocate an array large enough to hold pointers to interfaces
974 //
975 m_Interfaces = (FxUsbInterface**)
976 FxPoolAllocate(pFxDriverGlobals, NonPagedPool, size);
977
978 if (m_Interfaces == NULL) {
979 status = STATUS_INSUFFICIENT_RESOURCES;
980
981 DoTraceLevelMessage(
982 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET,
983 "Could not allocate memory for %d interfaces, %!STATUS!",
984 m_ConfigDescriptor->bNumInterfaces, status);
985
986 goto Done;
987 }
988
989 RtlZeroMemory(m_Interfaces, size);
990 m_NumInterfaces = m_ConfigDescriptor->bNumInterfaces;
991
992 //
993 // Iterate over the desciptors again, this time allocating an FxUsbInterface
994 // for each one and capturing the interface information.
995 //
996 RtlZeroMemory(descCountBitMap, sizeof(descCountBitMap));
997 iInterface = 0;
998 numFound = 0;
999
1000 pInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType(
1001 m_ConfigDescriptor,
1002 m_ConfigDescriptor->wTotalLength,
1003 m_ConfigDescriptor,
1004 USB_INTERFACE_DESCRIPTOR_TYPE
1005 );
1006
1007 while (pInterfaceDescriptor != NULL &&
1008 iInterface < m_ConfigDescriptor->bNumInterfaces) {
1009
1010 //
1011 // This function will retun false if the bit wasn't already set
1012 //
1013 if (FxBitArraySet(descCountBitMap,
1014 pInterfaceDescriptor->bInterfaceNumber) == FALSE) {
1015 FxUsbInterface* pInterface;
1016
1017 pInterface = new (GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES)
1018 FxUsbInterface(pFxDriverGlobals,
1019 this,
1020 pInterfaceDescriptor);
1021
1022 if (pInterface == NULL) {
1023 status = STATUS_INSUFFICIENT_RESOURCES;
1024 DoTraceLevelMessage(
1025 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1026 "Could not allocate memory for interface object #%d, %!STATUS!",
1027 iInterface, status);
1028 goto Done;
1029 }
1030
1031 status = pInterface->Commit(WDF_NO_OBJECT_ATTRIBUTES, NULL, this);
1032
1033 //
1034 // This should never fail
1035 //
1036 ASSERT(NT_SUCCESS(status));
1037
1038 if (!NT_SUCCESS(status)) {
1039 goto Done;
1040 }
1041
1042 status = pInterface->CreateSettings();
1043 if (!NT_SUCCESS(status)) {
1044 goto Done;
1045 }
1046
1047 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
1048 status = pInterface->SetWinUsbHandle(iInterface);
1049 if (!NT_SUCCESS(status)) {
1050 goto Done;
1051 }
1052
1053 status = pInterface->MakeAndConfigurePipes(WDF_NO_OBJECT_ATTRIBUTES,
1054 pInterfaceDescriptor->bNumEndpoints);
1055 if (!NT_SUCCESS(status)) {
1056 goto Done;
1057 }
1058 #endif
1059
1060 m_Interfaces[iInterface] = pInterface;
1061
1062 iInterface++;
1063 }
1064
1065 pInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType(
1066 m_ConfigDescriptor,
1067 totalLength,
1068 WDF_PTR_ADD_OFFSET(pInterfaceDescriptor,
1069 pInterfaceDescriptor->bLength),
1070 USB_INTERFACE_DESCRIPTOR_TYPE
1071 );
1072 }
1073
1074 //
1075 // We cannot check for the error case of
1076 //
1077 // pInterfaceDescriptor != NULL &&
1078 // iInterface == m_ConfigDescriptor->bNumInterfaces
1079 //
1080 // Because if there are multiple alternative settings for the last interface
1081 // in the config descriptor, we will have hit the limit of interfaces
1082 // (correctly), but have found another pInterfaceDescriptor (the next alt
1083 // setting).
1084 //
1085
1086 //
1087 // We already logged and found the case where iInterface >= m_NumInterfaces.
1088 // Check for the case where we found too few interfaces and when we found
1089 // no interfaces even though the config descriptor says otherwise.
1090 //
1091 //
1092 if (iInterface == 0 && m_NumInterfaces > 0) {
1093 status = STATUS_INVALID_DEVICE_REQUEST;
1094
1095 DoTraceLevelMessage(
1096 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1097 "Config descriptor indicated there were %d interfaces, but did not "
1098 "find any interface descriptors in config descriptor %p, %!STATUS!",
1099 m_NumInterfaces, m_ConfigDescriptor, status);
1100 }
1101 else if (pInterfaceDescriptor != NULL && m_NumInterfaces == 0) {
1102 DoTraceLevelMessage(
1103 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET,
1104 "Config descriptor indicated there were 0 interfaces, but an interface "
1105 "descriptor was found");
1106
1107 m_MismatchedInterfacesInConfigDescriptor = TRUE;
1108 }
1109 else if (iInterface < m_NumInterfaces) {
1110 DoTraceLevelMessage(
1111 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1112 "Config descriptor indicated there were %d interfaces, only found "
1113 "%d interfaces", m_NumInterfaces, iInterface);
1114
1115 //
1116 // Instead of considering this an error, just use the number found.
1117 // This will not have an adverse affect elsewhere and since the framework
1118 // is probably more strict then previous USB code, this would have not
1119 // been found earlier by a WDM driver.
1120 //
1121 m_NumInterfaces = iInterface;
1122 }
1123
1124 Done:
1125 return status;
1126 }
1127
1128
1129 _Must_inspect_result_
1130 NTSTATUS
GetPortStatus(__out PULONG PortStatus)1131 FxUsbDevice::GetPortStatus(
1132 __out PULONG PortStatus
1133 )
1134 {
1135 NTSTATUS status;
1136
1137 FxInternalIoctlOthersContext context;
1138 FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS];
1139 FxSyncRequest syncRequest(GetDriverGlobals(), &context);
1140
1141 //
1142 // FxSyncRequest always succeesds for KM.
1143 //
1144 status = syncRequest.Initialize();
1145 if (!NT_SUCCESS(status)) {
1146 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1147 "Failed to initialize FxSyncRequest");
1148 return status;
1149 }
1150
1151 *PortStatus = 0;
1152 args[0].SetBuffer(PortStatus, 0);
1153 args[1].SetBuffer(NULL, 0);
1154 args[2].SetBuffer(NULL, 0);
1155
1156 status = FormatInternalIoctlOthersRequest(syncRequest.m_TrueRequest,
1157 IOCTL_INTERNAL_USB_GET_PORT_STATUS,
1158 args);
1159
1160 if (NT_SUCCESS(status)) {
1161 WDF_REQUEST_SEND_OPTIONS options;
1162
1163 WDF_REQUEST_SEND_OPTIONS_INIT(
1164 &options, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
1165
1166 status = SubmitSync(syncRequest.m_TrueRequest, &options);
1167 }
1168
1169 return status;
1170 }
1171
1172
1173
1174 BOOLEAN
IsEnabled(VOID)1175 FxUsbDevice::IsEnabled(
1176 VOID
1177 )
1178 {
1179 NTSTATUS status;
1180 ULONG portStatus;
1181 BOOLEAN enabled;
1182
1183 enabled = TRUE;
1184 status = GetPortStatus(&portStatus);
1185
1186 //
1187 // Inability to get STATUS_SUCCESS from GetPortStatus is more likely a resource
1188 // issue rather than a device issue so return FALSE from this function only if
1189 // we were able to read the PortStatus and the port was disabled.
1190 // What you don't want is to continuosly reset the device (by returning FALSE)
1191 // instead of resetting pipe (by returning TRUE) under low memory conditions.
1192 //
1193 if (NT_SUCCESS(status) && (portStatus & USBD_PORT_ENABLED) == 0) {
1194 enabled = FALSE;
1195 }
1196
1197 return enabled;
1198 }
1199
1200 _Must_inspect_result_
1201 NTSTATUS
IsConnected(VOID)1202 FxUsbDevice::IsConnected(
1203 VOID
1204 )
1205 {
1206 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
1207
1208
1209
1210
1211 return STATUS_UNSUCCESSFUL;
1212 #elif (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
1213 NTSTATUS status;
1214 ULONG portStatus;
1215
1216 status = GetPortStatus(&portStatus);
1217 if (NT_SUCCESS(status) && (portStatus & USBD_PORT_CONNECTED) == 0) {
1218 status = STATUS_DEVICE_DOES_NOT_EXIST;
1219 }
1220
1221 return status;
1222 #endif
1223 }
1224
1225 _Must_inspect_result_
1226 NTSTATUS
CyclePort(VOID)1227 FxUsbDevice::CyclePort(
1228 VOID
1229 )
1230 {
1231 FxIoContext context;
1232 FxSyncRequest request(GetDriverGlobals(), &context);
1233 NTSTATUS status;
1234
1235 //
1236 // FxSyncRequest always succeesds for KM.
1237 //
1238 status = request.Initialize();
1239 if (!NT_SUCCESS(status)) {
1240 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1241 "Failed to initialize FxSyncRequest");
1242 return status;
1243 }
1244
1245 status = FormatCycleRequest(request.m_TrueRequest);
1246
1247 if (NT_SUCCESS(status)) {
1248 CancelSentIo();
1249 status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL);
1250 //
1251 // NOTE: CyclePort causes the device to be removed and re-enumerated so
1252 // don't do anymore operations after this point.
1253 //
1254 }
1255
1256 return status;
1257 }
1258
1259 _Must_inspect_result_
1260 NTSTATUS
FormatCycleRequest(__in FxRequestBase * Request)1261 FxUsbDevice::FormatCycleRequest(
1262 __in FxRequestBase* Request
1263 )
1264 {
1265 FxRequestBuffer emptyBuffer;
1266
1267 return FormatIoctlRequest(Request,
1268 IOCTL_INTERNAL_USB_CYCLE_PORT,
1269 TRUE,
1270 &emptyBuffer,
1271 &emptyBuffer);
1272 }
1273
1274 _Must_inspect_result_
1275 NTSTATUS
GetConfigDescriptor(__out PVOID ConfigDescriptor,__inout PUSHORT ConfigDescriptorLength)1276 FxUsbDevice::GetConfigDescriptor(
1277 __out PVOID ConfigDescriptor,
1278 __inout PUSHORT ConfigDescriptorLength
1279 )
1280 {
1281 NTSTATUS status;
1282 USHORT copyLength;
1283
1284 if (ConfigDescriptor == NULL) {
1285 //
1286 // Caller wants length to allocate
1287 //
1288 *ConfigDescriptorLength = m_ConfigDescriptor->wTotalLength;
1289 return STATUS_BUFFER_TOO_SMALL;
1290 }
1291
1292 if (*ConfigDescriptorLength < m_ConfigDescriptor->wTotalLength) {
1293 //
1294 // Valid ConfigDescriptor passed in, but its too small. Copy as many
1295 // bytes as we can.
1296 //
1297 copyLength = *ConfigDescriptorLength;
1298 status = STATUS_BUFFER_TOO_SMALL;
1299 }
1300 else {
1301 copyLength = m_ConfigDescriptor->wTotalLength;
1302 status = STATUS_SUCCESS;
1303 }
1304
1305 //
1306 // Always indicate to the caller the number of required bytes or the
1307 // number of bytes we copied.
1308 //
1309 RtlCopyMemory(ConfigDescriptor, m_ConfigDescriptor, copyLength);
1310 *ConfigDescriptorLength = m_ConfigDescriptor->wTotalLength;
1311
1312 return status;
1313 }
1314
1315 _Must_inspect_result_
1316 NTSTATUS
SelectConfigDescriptor(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,__in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params)1317 FxUsbDevice::SelectConfigDescriptor(
1318 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
1319 __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params
1320 )
1321 {
1322 PUSBD_INTERFACE_LIST_ENTRY pInterfaces;
1323 PURB urb;
1324 NTSTATUS status;
1325 ULONG i, size;
1326 PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
1327 PUSB_INTERFACE_DESCRIPTOR* interfaceDescriptors;
1328 ULONG numInterfaces;
1329 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1330
1331 pFxDriverGlobals = GetDriverGlobals();
1332
1333 configurationDescriptor = Params->Types.Descriptor.ConfigurationDescriptor;
1334 interfaceDescriptors = Params->Types.Descriptor.InterfaceDescriptors;
1335 numInterfaces = Params->Types.Descriptor.NumInterfaceDescriptors;
1336
1337 for (i = 0; i < numInterfaces; i++) {
1338 if (interfaceDescriptors[i] == NULL) {
1339 return STATUS_INVALID_PARAMETER;
1340 }
1341 }
1342
1343 //
1344 // eventually size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (numInterfaces + 1)
1345 //
1346 status = RtlULongAdd(numInterfaces, 1, &size);
1347 if (!NT_SUCCESS(status)) {
1348 return status;
1349 }
1350
1351 status = RtlULongMult(size, sizeof(USBD_INTERFACE_LIST_ENTRY), &size);
1352 if (!NT_SUCCESS(status)) {
1353 return status;
1354 }
1355
1356 pInterfaces = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate(
1357 pFxDriverGlobals, NonPagedPool, size);
1358
1359 if (pInterfaces == NULL) {
1360 status = STATUS_INSUFFICIENT_RESOURCES;
1361
1362 DoTraceLevelMessage(
1363 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1364 "Could not allocate array of USBD_INTERFACE_LIST_ENTRY, %!STATUS!",
1365 status);
1366
1367 return status;
1368 }
1369
1370 RtlZeroMemory(pInterfaces, size);
1371
1372 for (i = 0; i < numInterfaces; i++) {
1373 pInterfaces[i].InterfaceDescriptor = interfaceDescriptors[i];
1374 }
1375
1376 if (configurationDescriptor == NULL) {
1377 configurationDescriptor = m_ConfigDescriptor;
1378 }
1379
1380 //
1381 // NOTE:
1382 //
1383 // Creating a config request using the caller's config descriptor does not
1384 // currently work if the provided config descriptor is not the same as the
1385 // descriptor reported by the device. It does not work because we try to
1386 // validate the interface number in the URB against an existing
1387 // FxUsbInterface (which is based on the config descriptor described by the
1388 // device, not the provided one), and if that validation fails, we return
1389 // !NT_SUCCESS from SelectConfig().
1390 //
1391 urb = FxUsbCreateConfigRequest(GetDriverGlobals(),
1392 configurationDescriptor,
1393 pInterfaces,
1394 GetDefaultMaxTransferSize());
1395 if (urb == NULL) {
1396 status = STATUS_INSUFFICIENT_RESOURCES;
1397 }
1398 else {
1399 status = SelectConfig(PipesAttributes, urb, FxUrbTypeLegacy, NULL);
1400 FxPoolFree(urb);
1401 urb = NULL;
1402 }
1403
1404 FxPoolFree(pInterfaces);
1405 pInterfaces = NULL;
1406
1407 return status;
1408 }
1409
1410 struct FxInterfacePipeInformation {
1411 //
1412 // Array of pipes
1413 //
1414 FxUsbPipe** Pipes;
1415
1416 //
1417 // Number of entries in Pipes
1418 //
1419 ULONG NumPipes;
1420 };
1421
1422 _Must_inspect_result_
1423 NTSTATUS
SelectConfig(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,__in PURB Urb,__in FX_URB_TYPE FxUrbType,__out_opt PUCHAR NumConfiguredInterfaces)1424 FxUsbDevice::SelectConfig(
1425 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
1426 __in PURB Urb,
1427 __in FX_URB_TYPE FxUrbType,
1428 __out_opt PUCHAR NumConfiguredInterfaces
1429 )
1430 /*++
1431
1432 Routine Description:
1433 Selects the configuration as described by the parameter Urb. If there is a
1434 previous active configuration, the WDFUSBPIPEs for it are stopped and
1435 destroyed before the new configuration is selected
1436
1437 Arguments:
1438 PipesAttributes - object attributes to apply to each created WDFUSBPIPE
1439
1440 Urb - the URB describing the configuration to select
1441
1442 Return Value:
1443 NTSTATUS
1444
1445 --*/
1446 {
1447 WDF_REQUEST_SEND_OPTIONS options;
1448 PUCHAR pCur, pEnd;
1449 PUSBD_INTERFACE_INFORMATION pIface;
1450 FxUsbPipe* pPipe;
1451 PURB pSelectUrb;
1452 NTSTATUS status;
1453 ULONG iPipe;
1454 USHORT maxNumPipes, size;
1455 UCHAR numPipes;
1456 FxInterfacePipeInformation* pPipeInfo;
1457 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1458 FxUsbInterface * pUsbInterface ;
1459 UCHAR intfIndex;
1460 FxIrp* irp;
1461
1462 pFxDriverGlobals = GetDriverGlobals();
1463 FxSyncRequest request(GetDriverGlobals(), NULL);
1464
1465 pIface = NULL;
1466 maxNumPipes = 0;
1467 size = 0;
1468 pPipeInfo = NULL;
1469 pSelectUrb = NULL;
1470
1471 //
1472 // Callers to this function have guaranteed that there are interfaces
1473 // reported on this device.
1474 //
1475 ASSERT(m_NumInterfaces != 0);
1476
1477 if (NumConfiguredInterfaces != NULL) {
1478 *NumConfiguredInterfaces = 0;
1479 }
1480
1481 //
1482 // FxSyncRequest always succeesds for KM but can fail for UM.
1483 //
1484 status = request.Initialize();
1485 if (!NT_SUCCESS(status)) {
1486 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1487 "Failed to initialize FxSyncRequest");
1488 goto Done;
1489 }
1490
1491 //
1492 // Allocate a PIRP for the select config and possible select interface(s)
1493 //
1494 status = request.m_TrueRequest->ValidateTarget(this);
1495 if (!NT_SUCCESS(status)) {
1496 goto Done;
1497 }
1498
1499 //
1500 // Allocate a pool for storing the FxUsbPipe ** before we
1501 // assign them to the Interfaces just in case all doesn't go well.
1502 //
1503 if (m_NumInterfaces == 0) {
1504 //
1505 // Use one in the zero case to make the logic simpler
1506 //
1507 size = sizeof(FxInterfacePipeInformation);
1508 }
1509 else {
1510 size = m_NumInterfaces * sizeof(FxInterfacePipeInformation);
1511 }
1512
1513 pPipeInfo = (FxInterfacePipeInformation*) FxPoolAllocate(
1514 pFxDriverGlobals, NonPagedPool, size
1515 );
1516
1517 if (pPipeInfo == NULL) {
1518 status = STATUS_INSUFFICIENT_RESOURCES;
1519 DoTraceLevelMessage(
1520 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1521 "Could not internal allocate tracking info for selecting a config on "
1522 "WDFUSBDEVICE 0x%p, %!STATUS!", GetHandle(), status);
1523 goto Done;
1524 }
1525
1526 RtlZeroMemory(pPipeInfo, size);
1527
1528 //
1529 // The following code and the one in select setting have a lot in common
1530 // but can't leverage on that as that sends the select interface URB down
1531 // Our goal is allocate the resources -- the pipes and the select setting URB
1532 // before sending down the select config URB so that the tear down is simpler.
1533 //
1534
1535 //
1536 // Each FxUsbInterface will need a FxUsbPipe* for each pipe contained in
1537 // the interface.
1538 //
1539 pCur = (PUCHAR) &Urb->UrbSelectConfiguration.Interface;
1540 pEnd = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length;
1541 intfIndex = 0;
1542
1543 for ( ; pCur < pEnd; pCur += pIface->Length, intfIndex++) {
1544 FxUsbPipe** ppPipes;
1545
1546 pIface = (PUSBD_INTERFACE_INFORMATION) pCur;
1547 if (pIface->NumberOfPipes > UCHAR_MAX) {
1548 status = STATUS_INVALID_DEVICE_REQUEST;
1549 DoTraceLevelMessage(
1550 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1551 "WDFUSBDEVICE supports a maximum of %d pipes per interface, "
1552 "USBD_INTERFACE_INFORMATION %p specified %d, %!STATUS!",
1553 UCHAR_MAX, pIface, pIface->NumberOfPipes, status);
1554 goto Done;
1555 }
1556
1557 pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber);
1558 if (pUsbInterface == NULL) {
1559 status = STATUS_INVALID_DEVICE_REQUEST;
1560 DoTraceLevelMessage(
1561 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1562 "Could not find an instance of an interface descriptor with "
1563 "InterfaceNumber %d, %!STATUS!",
1564 pIface->InterfaceNumber, status);
1565 goto Done;
1566 }
1567
1568 numPipes = (UCHAR) pIface->NumberOfPipes;
1569
1570 //
1571 // Track the maximum number of pipes we have seen in an interface in
1572 // case we need to allocate a select interface URB.
1573 //
1574 if (numPipes > maxNumPipes) {
1575 maxNumPipes = (USHORT) numPipes;
1576 }
1577
1578 if (numPipes > 0) {
1579 size = numPipes * sizeof(FxUsbPipe *);
1580 }
1581 else {
1582 //
1583 // It is valid to have an interface with zero pipes in it. In that
1584 // case, we just allocate one entry so that we have a valid array
1585 // and keep the remaining code simple.
1586 //
1587 size = sizeof(FxUsbPipe*);
1588 }
1589
1590 ppPipes = (FxUsbPipe**) FxPoolAllocate(
1591 pFxDriverGlobals,
1592 NonPagedPool,
1593 size
1594 );
1595
1596 if (ppPipes == NULL) {
1597 status = STATUS_INSUFFICIENT_RESOURCES;
1598 DoTraceLevelMessage(
1599 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1600 "Could not allocate memory for Pipes "
1601 "InterfaceNumber %d, %!STATUS!",
1602 pIface->InterfaceNumber, status);
1603 goto Done;
1604 }
1605
1606 RtlZeroMemory(ppPipes, size);
1607
1608 //
1609 // We store the pointer to the newly allocated arary in a temporary b/c
1610 // we can still fail and we don't want a half baked interface.
1611 //
1612
1613 pPipeInfo[intfIndex].Pipes = ppPipes;
1614 pPipeInfo[intfIndex].NumPipes = numPipes;
1615
1616 for (iPipe = 0; iPipe < numPipes; iPipe++) {
1617 ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes)
1618 FxUsbPipe(GetDriverGlobals(),this);
1619
1620 if (ppPipes[iPipe] == NULL) {
1621 status = STATUS_INSUFFICIENT_RESOURCES;
1622 DoTraceLevelMessage(
1623 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1624 "Could not allocate a pipe object, %!STATUS!", status);
1625 goto Done;
1626 }
1627
1628 pPipe = ppPipes[iPipe];
1629 status = pPipe->Init(m_Device);
1630 if (!NT_SUCCESS(status)) {
1631 DoTraceLevelMessage(
1632 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1633 "Could not Init the pipe object, %!STATUS!", status);
1634 goto Done;
1635 }
1636
1637 status = pPipe->Commit(PipesAttributes, NULL, pUsbInterface);
1638 if (!NT_SUCCESS(status)) {
1639 DoTraceLevelMessage(
1640 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1641 "Could not commit the pipe object, %!STATUS!", status);
1642 goto Done;
1643 }
1644 }
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654 if (pUsbInterface->IsInterfaceConfigured()) {
1655 CleanupInterfacePipesAndDelete(pUsbInterface);
1656 }
1657 }
1658
1659 //
1660 // If we are selecting more then one interface and at least one of them
1661 // has pipes in them, allocate a select interface URB that will be used
1662 // after the select config to select each interface. The select interface
1663 // URB will be big enough to select the largest interface in the group.
1664 //
1665 // The select interface URB is allocated before the select config so that
1666 // we know once the select config has completed successfully, we can be
1667 // guaranteed that we can select the interfaces we want and not have to
1668 // handle undoing the select config upon URB allocation failure.
1669 //
1670 if (m_NumInterfaces > 1 && maxNumPipes > 0) {
1671 size = GET_SELECT_INTERFACE_REQUEST_SIZE(maxNumPipes);
1672
1673 pSelectUrb = (PURB) FxPoolAllocate(GetDriverGlobals(),
1674 NonPagedPool,
1675 size
1676 );
1677
1678 if (pSelectUrb == NULL) {
1679 status = STATUS_INSUFFICIENT_RESOURCES;
1680 DoTraceLevelMessage(
1681 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1682 "Could not allocate a select interface URB, %!STATUS!", status);
1683 goto Done;
1684 }
1685
1686 RtlZeroMemory(pSelectUrb, size);
1687 }
1688
1689 //
1690 // Send the select config to the usb core
1691 //
1692 WDF_REQUEST_SEND_OPTIONS_INIT(&options,
1693 WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
1694 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(2));
1695
1696 FxFormatUsbRequest(request.m_TrueRequest, Urb, FxUrbType, m_USBDHandle);
1697 status = SubmitSync(request.m_TrueRequest, &options);
1698
1699 if (NT_SUCCESS(status)) {
1700 //
1701 // Save the config handle and store off all the pipes
1702 //
1703 m_ConfigHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
1704
1705 //
1706 // Initialize the first interface
1707 //
1708 pIface = &Urb->UrbSelectConfiguration.Interface;
1709
1710 pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber);
1711 pUsbInterface->SetNumConfiguredPipes((UCHAR)pIface->NumberOfPipes);
1712
1713 //
1714 // The interface now owns the array of pipes
1715 //
1716 pUsbInterface->SetConfiguredPipes(pPipeInfo[0].Pipes);
1717 pPipeInfo[0].Pipes = NULL;
1718 pPipeInfo[0].NumPipes = 0;
1719
1720 pUsbInterface->SetInfo(pIface);
1721
1722 //
1723 // Since this could be the only interface, set the index now, so if we
1724 // return the number of configured interfaces, it will be valid for the
1725 // single interface case.
1726 //
1727 intfIndex = 1;
1728
1729 //
1730 // If we have a more then one interface, we must select each of the addtional
1731 // interfaces after the select config because usbccgp (the generic parent
1732 // driver) didn't fill out all of the pipe info for IAD (interface
1733 // association descriptor) devices. The first interface is filled out
1734 // property, it is 2->N that are left blank.
1735 //
1736 // pSelectUrb can be equal to NULL and have more then one interface if
1737 // all interfaces have no pipes associated with them. In that case, we
1738 // still want to iterate over the remaining pipes so that we can
1739 // initialize our structures properly.
1740 //
1741 if (m_NumInterfaces > 1) {
1742 //
1743 // Loop over the interfaces again.
1744 //
1745 pCur = (PUCHAR) &Urb->UrbSelectConfiguration.Interface;
1746 pIface = (PUSBD_INTERFACE_INFORMATION) pCur;
1747 pEnd = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length;
1748
1749 //
1750 // Start at the 2nd one since the first is already selected
1751 //
1752 pCur += pIface->Length;
1753
1754 for ( ; pCur < pEnd; pCur += pIface->Length, intfIndex++) {
1755 #pragma prefast(suppress: __WARNING_UNUSED_POINTER_ASSIGNMENT, "pIface is used in the for loop in many places. It looks like a false positive")
1756 pIface = (PUSBD_INTERFACE_INFORMATION) pCur;
1757 ASSERT(pIface->NumberOfPipes <= maxNumPipes);
1758
1759 pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber);
1760 ASSERT(pUsbInterface != NULL);
1761
1762 //
1763 // Valid to have an interface with no pipes. If there are no
1764 // pipes, GET_SELECT_INTERFACE_REQUEST_SIZE will compute value
1765 // too small of a size to pass validation.
1766 //
1767 if (pIface->NumberOfPipes > 0) {
1768
1769 pUsbInterface->FormatSelectSettingUrb(
1770 pSelectUrb,
1771 (USHORT) pIface->NumberOfPipes,
1772 pIface->AlternateSetting
1773 );
1774 irp = request.m_TrueRequest->GetSubmitFxIrp();
1775 irp->Reuse(STATUS_SUCCESS);
1776
1777 request.m_TrueRequest->ClearFieldsForReuse();
1778 FxFormatUsbRequest(request.m_TrueRequest,
1779 pSelectUrb,
1780 FxUrbTypeLegacy,
1781 NULL);
1782
1783 status = SubmitSync(request.m_TrueRequest, &options);
1784 if (!NT_SUCCESS(status)) {
1785 DoTraceLevelMessage(
1786 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1787 "USB core failed Select Interface URB, %!STATUS!",
1788 status);
1789 goto Done;
1790 }
1791
1792 //
1793 // Copy the info back into the original select config URB
1794 //
1795
1796 RtlCopyMemory(pIface,
1797 &pSelectUrb->UrbSelectInterface.Interface,
1798 pSelectUrb->UrbSelectInterface.Interface.Length);
1799 }
1800
1801 //
1802 // Update the pointer to point to the new pipes with the pointer
1803 // to the pipes stored earlier.
1804 //
1805 ASSERT(pPipeInfo[intfIndex].NumPipes == pIface->NumberOfPipes);
1806 pUsbInterface->SetNumConfiguredPipes((UCHAR)pIface->NumberOfPipes);
1807
1808 //
1809 // The interface now owns the array of pipes
1810 //
1811 pUsbInterface->SetConfiguredPipes(pPipeInfo[intfIndex].Pipes);
1812 pPipeInfo[intfIndex].Pipes = NULL;
1813 pPipeInfo[intfIndex].NumPipes = 0;
1814
1815 //
1816 // SetInfo only after a successful select config so that we can
1817 // copy the USBD_PIPE_INFORMATION .
1818 //
1819 pUsbInterface->SetInfo(pIface);
1820 }
1821 }
1822
1823 if (NumConfiguredInterfaces != NULL) {
1824 *NumConfiguredInterfaces = intfIndex;
1825 }
1826 }
1827 else {
1828 DoTraceLevelMessage(
1829 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1830 "USB core failed Select Configuration, %!STATUS!", status);
1831 }
1832
1833 Done:
1834 if (pSelectUrb != NULL) {
1835 FxPoolFree(pSelectUrb);
1836 pSelectUrb = NULL;
1837 }
1838
1839 if (pPipeInfo != NULL) {
1840 //
1841 // Free all arrays that may have been allocated
1842 //
1843 for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++) {
1844 //
1845 // We can have NumPipes == 0 and still have an allocated array, so
1846 // use the array != NULL as the check.
1847 //
1848 if (pPipeInfo[intfIndex].Pipes != NULL) {
1849 //
1850 // Delete any pipes that might have been created
1851 //
1852 for (iPipe = 0; iPipe < pPipeInfo[intfIndex].NumPipes; iPipe++) {
1853 if (pPipeInfo[intfIndex].Pipes[iPipe] != NULL) {
1854 pPipeInfo[intfIndex].Pipes[iPipe]->DeleteFromFailedCreate();
1855 pPipeInfo[intfIndex].Pipes[iPipe] = NULL;
1856 }
1857 }
1858
1859 //
1860 // Now free the array itself and clear out the count
1861 //
1862 FxPoolFree(pPipeInfo[intfIndex].Pipes);
1863 pPipeInfo[intfIndex].Pipes = NULL;
1864 pPipeInfo[intfIndex].NumPipes = 0;
1865 }
1866 }
1867
1868 FxPoolFree(pPipeInfo);
1869 pPipeInfo = NULL;
1870 }
1871
1872 return status;
1873 }
1874
1875 _Must_inspect_result_
1876 NTSTATUS
Deconfig(VOID)1877 FxUsbDevice::Deconfig(
1878 VOID
1879 )
1880 {
1881 WDF_REQUEST_SEND_OPTIONS options;
1882 _URB_SELECT_CONFIGURATION urb;
1883
1884 FxSyncRequest request(GetDriverGlobals(), NULL);
1885 NTSTATUS status;
1886
1887 //
1888 // FxSyncRequest always succeesds for KM but can fail for UM.
1889 //
1890 status = request.Initialize();
1891 if (!NT_SUCCESS(status)) {
1892 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1893 "Failed to initialize FxSyncRequest");
1894 return status;
1895 }
1896
1897 status = request.m_TrueRequest->ValidateTarget(this);
1898 if (!NT_SUCCESS(status)) {
1899 return status;
1900 }
1901
1902 //
1903 // This will remove and free all interfaces and associated pipes
1904 //
1905 PipesGotoRemoveState(TRUE);
1906
1907 RtlZeroMemory(&urb, sizeof(urb));
1908
1909 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team");
1910 UsbBuildSelectConfigurationRequest((PURB) &urb, sizeof(urb), NULL);
1911 #pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team");
1912 FxFormatUsbRequest(request.m_TrueRequest, (PURB) &urb, FxUrbTypeLegacy, NULL);
1913
1914 WDF_REQUEST_SEND_OPTIONS_INIT(
1915 &options, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
1916
1917 status = SubmitSync(request.m_TrueRequest, &options);
1918
1919 return status;
1920 }
1921
1922 _Must_inspect_result_
1923 NTSTATUS
SelectConfigInterfaces(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,__in PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,__in_ecount (NumInterfaces)PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors,__in ULONG NumInterfaces)1924 FxUsbDevice::SelectConfigInterfaces(
1925 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
1926 __in PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
1927 __in_ecount(NumInterfaces) PUSB_INTERFACE_DESCRIPTOR* InterfaceDescriptors,
1928 __in ULONG NumInterfaces
1929 )
1930 {
1931 PUSBD_INTERFACE_LIST_ENTRY pInterfaces;
1932 PURB urb;
1933 NTSTATUS status;
1934 ULONG i, size;
1935 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1936
1937 pFxDriverGlobals = GetDriverGlobals();
1938
1939 //
1940 // eventually size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (NumInterfaces + 1)
1941 //
1942 status = RtlULongAdd(NumInterfaces, 1, &size);
1943 if (!NT_SUCCESS(status)) {
1944 return status;
1945 }
1946
1947 status = RtlULongMult(size, sizeof(USBD_INTERFACE_LIST_ENTRY), &size);
1948 if (!NT_SUCCESS(status)) {
1949 return status;
1950 }
1951
1952 for (i = 0; i < NumInterfaces; i++) {
1953 if (InterfaceDescriptors[i] == NULL) {
1954 return STATUS_INVALID_PARAMETER;
1955 }
1956 }
1957
1958 pInterfaces = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate(
1959 pFxDriverGlobals,
1960 NonPagedPool,
1961 size
1962 );
1963
1964 if (pInterfaces == NULL) {
1965 status = STATUS_INSUFFICIENT_RESOURCES;
1966
1967 DoTraceLevelMessage(
1968 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1969 "Could not allocate array of USBD_INTERFACE_LIST_ENTRY, %!STATUS!",
1970 status);
1971
1972 return status;
1973 }
1974
1975 RtlZeroMemory(pInterfaces, size);
1976
1977 for (i = 0; i < NumInterfaces; i++) {
1978 pInterfaces[i].InterfaceDescriptor = InterfaceDescriptors[i];
1979 }
1980
1981 if (ConfigurationDescriptor == NULL) {
1982 ConfigurationDescriptor = m_ConfigDescriptor;
1983 }
1984
1985 urb = FxUsbCreateConfigRequest(GetDriverGlobals(),
1986 ConfigurationDescriptor,
1987 pInterfaces,
1988 GetDefaultMaxTransferSize());
1989 if (urb == NULL) {
1990 status = STATUS_INSUFFICIENT_RESOURCES;
1991 }
1992 else {
1993 status = SelectConfig(PipesAttributes, urb, FxUrbTypeLegacy, NULL);
1994 FxPoolFree(urb);
1995 urb = NULL;
1996 }
1997
1998 FxPoolFree(pInterfaces);
1999 pInterfaces = NULL;
2000
2001 return status;
2002 }
2003
2004 FxUsbInterface *
GetInterfaceFromIndex(__in UCHAR InterfaceIndex)2005 FxUsbDevice::GetInterfaceFromIndex(
2006 __in UCHAR InterfaceIndex
2007 )
2008 {
2009 if (InterfaceIndex < m_NumInterfaces){
2010 return m_Interfaces[InterfaceIndex];
2011 }
2012
2013 return NULL;
2014 }
2015
2016 _Must_inspect_result_
2017 NTSTATUS
GetInterfaceNumberFromInterface(__in WDFUSBINTERFACE UsbInterface,__out PUCHAR InterfaceNumber)2018 FxUsbDevice::GetInterfaceNumberFromInterface(
2019 __in WDFUSBINTERFACE UsbInterface,
2020 __out PUCHAR InterfaceNumber
2021 )
2022 {
2023 FxUsbInterface * pUsbInterface;
2024
2025 FxObjectHandleGetPtr(GetDriverGlobals(),
2026 UsbInterface,
2027 FX_TYPE_USB_INTERFACE ,
2028 (PVOID*) &pUsbInterface);
2029
2030 *InterfaceNumber = pUsbInterface->GetInterfaceNumber();
2031
2032 return STATUS_SUCCESS;
2033 }
2034
2035 FxUsbInterface *
GetInterfaceFromNumber(__in UCHAR InterfaceNumber)2036 FxUsbDevice::GetInterfaceFromNumber(
2037 __in UCHAR InterfaceNumber
2038 )
2039 {
2040 ULONG i;
2041
2042 for (i = 0; i < m_NumInterfaces; i++) {
2043 if (m_Interfaces[i]->GetInterfaceNumber() == InterfaceNumber) {
2044 return m_Interfaces[i];
2045 }
2046 }
2047
2048 return NULL;
2049 }
2050
2051 VOID
CleanupInterfacePipesAndDelete(__in FxUsbInterface * UsbInterface)2052 FxUsbDevice::CleanupInterfacePipesAndDelete(
2053 __in FxUsbInterface * UsbInterface
2054 )
2055 {
2056 SINGLE_LIST_ENTRY sentHead;
2057 LIST_ENTRY pendHead;
2058 ULONG iPipe;
2059 FxUsbPipe *pPipe;
2060 KIRQL irql;
2061
2062 sentHead.Next = NULL;
2063 InitializeListHead(&pendHead);
2064
2065 AcquireInterfaceIterationLock();
2066
2067 Lock(&irql);
2068 for (iPipe = 0; iPipe < UsbInterface->m_NumberOfConfiguredPipes; iPipe++) {
2069 BOOLEAN wait;
2070
2071 wait = FALSE;
2072 pPipe = UsbInterface->m_ConfiguredPipes[iPipe];
2073 pPipe->GotoRemoveState(
2074 WdfIoTargetDeleted,
2075 &pendHead,
2076 &sentHead,
2077 TRUE,
2078 &wait);
2079 }
2080 Unlock(irql);
2081
2082 _CleanupPipesRequests(&pendHead, &sentHead);
2083
2084 for (iPipe = 0; iPipe < UsbInterface->m_NumberOfConfiguredPipes; iPipe++) {
2085 pPipe = UsbInterface->m_ConfiguredPipes[iPipe];
2086 pPipe->WaitForSentIoToComplete();
2087 }
2088
2089 UsbInterface->CleanUpAndDelete(FALSE);
2090
2091 ReleaseInterfaceIterationLock();
2092 }
2093
2094 VOID
CancelSentIo(VOID)2095 FxUsbDevice::CancelSentIo(
2096 VOID
2097 )
2098 {
2099 FxUsbInterface *pUsbInterface;
2100 ULONG iInterface, iPipe;
2101
2102 for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) {
2103 pUsbInterface = m_Interfaces[iInterface];
2104
2105 if (pUsbInterface->m_ConfiguredPipes != NULL) {
2106 for (iPipe = 0;
2107 iPipe < pUsbInterface->m_NumberOfConfiguredPipes;
2108 iPipe++) {
2109
2110 if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) {
2111 pUsbInterface->m_ConfiguredPipes[iPipe]->CancelSentIo();
2112 }
2113
2114 }
2115 }
2116 }
2117 FxIoTarget::CancelSentIo(); // __super call
2118 }
2119
2120 __checkReturn
2121 NTSTATUS
CreateUrb(__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__out WDFMEMORY * UrbMemory,__deref_opt_out_bcount (sizeof (URB))PURB * Urb)2122 FxUsbDevice::CreateUrb(
2123 __in_opt
2124 PWDF_OBJECT_ATTRIBUTES Attributes,
2125 __out
2126 WDFMEMORY* UrbMemory,
2127 __deref_opt_out_bcount(sizeof(URB))
2128 PURB* Urb
2129 )
2130 {
2131 NTSTATUS status;
2132 PURB urbLocal = NULL;
2133 PFX_DRIVER_GLOBALS pFxDriverGlobals;
2134 FxUsbUrb * pUrb = NULL;
2135 WDFMEMORY hMemory;
2136 FxObject* pParent;
2137
2138 //
2139 // Get the parent's globals if it is present, else use the ones for FxUsbDevice
2140 //
2141 pFxDriverGlobals = GetDriverGlobals();
2142 status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, Attributes);
2143
2144 if (NT_SUCCESS(status)) {
2145
2146 FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
2147 Attributes->ParentObject,
2148 FX_TYPE_OBJECT,
2149 (PVOID*)&pParent,
2150 &pFxDriverGlobals);
2151
2152 if (FALSE == IsObjectDisposedOnRemove(pParent)) {
2153 DoTraceLevelMessage(
2154 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
2155 "Urb must be parented to FxDevice or an IoAllocated Request");
2156 status = STATUS_INVALID_PARAMETER;
2157 goto Done;
2158 }
2159
2160 }
2161 else if (status == STATUS_WDF_PARENT_NOT_SPECIFIED) {
2162
2163 pFxDriverGlobals = GetDriverGlobals();
2164 pParent = this;
2165 status = STATUS_SUCCESS;
2166
2167 }
2168 else {
2169
2170 goto Done;
2171 }
2172
2173 status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
2174 if (!NT_SUCCESS(status)) {
2175 goto Done;
2176 }
2177
2178 FxPointerNotNull(pFxDriverGlobals, UrbMemory);
2179
2180 *UrbMemory = NULL;
2181
2182 status = USBD_UrbAllocate(m_USBDHandle, &urbLocal);
2183
2184 if (!NT_SUCCESS(status)) {
2185
2186 urbLocal = NULL;
2187 DoTraceLevelMessage(
2188 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
2189 "USBDEVICE Must have been created with Client Contract Version Info, %!STATUS!",
2190 status);
2191
2192 goto Done;
2193
2194 }
2195
2196 pUrb = new(pFxDriverGlobals, Attributes)
2197 FxUsbUrb(pFxDriverGlobals, m_USBDHandle, urbLocal, sizeof(URB));
2198
2199 if (pUrb == NULL) {
2200 status = STATUS_INSUFFICIENT_RESOURCES;
2201 goto Done;
2202 }
2203
2204 urbLocal = NULL;
2205
2206 status = pUrb->Commit(Attributes, (WDFOBJECT*)&hMemory, pParent);
2207
2208 if (!NT_SUCCESS(status)) {
2209 goto Done;
2210 }
2211
2212 *UrbMemory = hMemory;
2213
2214 if (Urb) {
2215 *Urb = (PURB) pUrb->GetBuffer();
2216 }
2217
2218 Done:
2219
2220 if (!NT_SUCCESS(status)) {
2221
2222 if (pUrb) {
2223 pUrb->DeleteFromFailedCreate();
2224 }
2225
2226 if (urbLocal) {
2227 USBD_UrbFree(m_USBDHandle, urbLocal);
2228 }
2229
2230 }
2231
2232 return status;
2233 }
2234
2235 __checkReturn
2236 NTSTATUS
CreateIsochUrb(__in_opt PWDF_OBJECT_ATTRIBUTES Attributes,__in ULONG NumberOfIsochPackets,__out WDFMEMORY * UrbMemory,__deref_opt_out_bcount (GET_ISOCH_URB_SIZE (NumberOfIsochPackets))PURB * Urb)2237 FxUsbDevice::CreateIsochUrb(
2238 __in_opt
2239 PWDF_OBJECT_ATTRIBUTES Attributes,
2240 __in
2241 ULONG NumberOfIsochPackets,
2242 __out
2243 WDFMEMORY* UrbMemory,
2244 __deref_opt_out_bcount(GET_ISOCH_URB_SIZE(NumberOfIsochPackets))
2245 PURB* Urb
2246 )
2247 {
2248 NTSTATUS status;
2249 PURB urbLocal = NULL;
2250 PFX_DRIVER_GLOBALS pFxDriverGlobals;
2251 FxUsbUrb * pUrb = NULL;
2252 WDFMEMORY hMemory;
2253 ULONG size;
2254 FxObject* pParent;
2255
2256 //
2257 // Get the parent's globals if it is present, else use the ones for FxUsbDevice
2258 //
2259 pFxDriverGlobals = GetDriverGlobals();
2260 status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, Attributes);
2261
2262 if (NT_SUCCESS(status)) {
2263
2264 FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals,
2265 Attributes->ParentObject,
2266 FX_TYPE_OBJECT,
2267 (PVOID*)&pParent,
2268 &pFxDriverGlobals);
2269
2270 if (FALSE == IsObjectDisposedOnRemove(pParent)) {
2271 DoTraceLevelMessage(
2272 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
2273 "Urb must be parented to FxDevice or IoAllocated Request");
2274 status = STATUS_INVALID_PARAMETER;
2275 goto Done;
2276 }
2277
2278 }
2279 else if (status == STATUS_WDF_PARENT_NOT_SPECIFIED) {
2280
2281 pFxDriverGlobals = GetDriverGlobals();
2282 pParent = this;
2283 status = STATUS_SUCCESS;
2284
2285 }
2286 else {
2287
2288 goto Done;
2289 }
2290
2291 status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes);
2292 if (!NT_SUCCESS(status)) {
2293 goto Done;
2294 }
2295
2296 FxPointerNotNull(pFxDriverGlobals, UrbMemory);
2297
2298 *UrbMemory = NULL;
2299
2300 status = USBD_IsochUrbAllocate(m_USBDHandle, NumberOfIsochPackets, &urbLocal);
2301
2302 if (!NT_SUCCESS(status)) {
2303
2304 urbLocal = NULL;
2305 DoTraceLevelMessage(
2306 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
2307 "USBDEVICE Must have been created with Client Contract Version Info, %!STATUS!",
2308 status);
2309
2310 goto Done;
2311
2312 }
2313
2314 size = GET_ISO_URB_SIZE(NumberOfIsochPackets);
2315
2316 pUrb = new(pFxDriverGlobals, Attributes)
2317 FxUsbUrb(pFxDriverGlobals, m_USBDHandle, urbLocal, size);
2318
2319 if (pUrb == NULL) {
2320 status = STATUS_INSUFFICIENT_RESOURCES;
2321 goto Done;
2322 }
2323
2324 urbLocal = NULL;
2325
2326 status = pUrb->Commit(Attributes, (WDFOBJECT*)&hMemory, pParent);
2327
2328 if (!NT_SUCCESS(status)) {
2329 goto Done;
2330 }
2331
2332 *UrbMemory = hMemory;
2333
2334 if (Urb) {
2335 *Urb = (PURB) pUrb->GetBuffer();
2336 }
2337
2338 Done:
2339
2340 if (!NT_SUCCESS(status)) {
2341
2342 if (pUrb) {
2343 pUrb->DeleteFromFailedCreate();
2344 }
2345
2346 if (urbLocal) {
2347 USBD_UrbFree(m_USBDHandle, urbLocal);
2348 }
2349
2350 }
2351
2352 return status;
2353 }
2354
2355 BOOLEAN
IsObjectDisposedOnRemove(__in FxObject * Object)2356 FxUsbDevice::IsObjectDisposedOnRemove(
2357 __in FxObject* Object
2358 )
2359 /*++
2360
2361 Routine Description:
2362 This routine determines if the Object being passed is guranteed to be disposed on a
2363 Pnp remove operation.
2364
2365 The object will be disposed on Pnp remove operation if it is a somewhere in the child
2366 tree of the FxDevice assocaited with this FxUsbDevice object, or in the child tree of an
2367 Io Allocated Request.
2368
2369 Arguments:
2370
2371 Object - The Object being checked
2372
2373 Return Value:
2374
2375 TRUE if the Object is guranteed to be disposed on a pnp remove operation
2376 FALSE otherwise.
2377
2378 --*/
2379 {
2380 FxObject * obj;
2381 FxObject * parent;
2382 BOOLEAN isObjectDisposedOnRemove = FALSE;
2383
2384 obj = Object;
2385
2386 //
2387 // By adding a reference now, we simulate what GetParentObjectReferenced
2388 // does later, thus allowing simple logic on when/how to release the
2389 // reference on exit.
2390 //
2391 obj->ADDREF(Object);
2392
2393 while (obj != NULL) {
2394
2395 if (obj == (FxObject*) m_Device) {
2396
2397 isObjectDisposedOnRemove = TRUE;
2398 break;
2399 }
2400
2401 if (FxObjectCheckType(obj, FX_TYPE_REQUEST)) {
2402
2403 FxRequestBase* request = (FxRequestBase*) obj;
2404 if (request->IsAllocatedFromIo()) {
2405
2406 isObjectDisposedOnRemove = TRUE;
2407 break;
2408 }
2409 }
2410
2411 parent = obj->GetParentObjectReferenced(Object);
2412
2413 //
2414 // Release the reference previously taken by the top of the function
2415 // or GetParentObjectReferenced in a previous pass in the loop.
2416 //
2417 obj->RELEASE(Object);
2418 obj = parent;
2419 }
2420
2421 if (obj != NULL) {
2422
2423 //
2424 // Release the reference previously taken by the top of the function
2425 // or GetParentObjectReferenced in a last pass in the loop.
2426 //
2427 obj->RELEASE(Object);
2428 }
2429
2430 return isObjectDisposedOnRemove;
2431 }
2432
2433 FX_URB_TYPE
GetFxUrbTypeForRequest(__in FxRequestBase * Request)2434 FxUsbDevice::GetFxUrbTypeForRequest(
2435 __in FxRequestBase* Request
2436 )
2437 /*++
2438
2439 Routine Description:
2440 This routine essentially determines whether this routine can use a urb allocated by
2441 the USBD_xxxUrbAllocate APIs
2442
2443 The USBD_xxxUrbAllocate APIs are only used for those requests that could be disposed at the
2444 time the client driver devnode is being removed.
2445
2446 If we cannot make that gurantee about that request, FxUrbTypeLegacy is returned and the
2447 USBD_xxxUrbAllocate api's must not be used to allocate an Urb.
2448
2449 Else FxUrbTypeUsbdAllocated is returned.
2450
2451 Arguments:
2452
2453 Request - FxRequest
2454
2455 Return Value:
2456
2457 FxUrbTypeUsbdAllocated, or FxUrbTypeLegacy
2458
2459 --*/
2460 {
2461 if (m_UrbType == FxUrbTypeLegacy) {
2462 return FxUrbTypeLegacy;
2463 }
2464
2465 if (Request->IsAllocatedFromIo()) {
2466 return FxUrbTypeUsbdAllocated;
2467 }
2468
2469 if (IsObjectDisposedOnRemove((FxObject*) Request)) {
2470 return FxUrbTypeUsbdAllocated;
2471 }
2472
2473 return FxUrbTypeLegacy;
2474 }
2475
2476