1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxUsbInterface.cpp
8
9 Abstract:
10
11 Author:
12
13 Environment:
14
15 Both kernel and user mode
16
17 Revision History:
18
19 --*/
20
21 #include "fxusbpch.hpp"
22
23 extern "C" {
24 #include "FxUsbInterface.tmh"
25 }
26
FxUsbInterface(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxUsbDevice * UsbDevice,__in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor)27 FxUsbInterface::FxUsbInterface(
28 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
29 __in FxUsbDevice* UsbDevice,
30 __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
31 ) :
32 FxNonPagedObject(FX_TYPE_USB_INTERFACE ,sizeof(FxUsbInterface), FxDriverGlobals),
33 m_UsbDevice(UsbDevice)
34 {
35 m_UsbDevice->ADDREF(this);
36
37 m_InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
38 m_Protocol = InterfaceDescriptor->bInterfaceProtocol;
39 m_Class = InterfaceDescriptor->bInterfaceClass;
40 m_SubClass = InterfaceDescriptor->bInterfaceSubClass;
41
42 m_CurAlternateSetting = 0;
43 m_NumSettings = 0;
44 m_NumberOfConfiguredPipes = 0;
45 m_ConfiguredPipes = NULL;
46 m_Settings = NULL;
47
48 MarkNoDeleteDDI(ObjectDoNotLock);
49 }
50
~FxUsbInterface()51 FxUsbInterface::~FxUsbInterface()
52 {
53 ULONG i;
54
55 m_UsbDevice->RemoveDeletedInterface(this);
56
57 for (i = 0; i < m_NumberOfConfiguredPipes; i++) {
58 ASSERT(m_ConfiguredPipes[i] == NULL);
59 }
60
61 if (m_ConfiguredPipes != NULL) {
62 FxPoolFree(m_ConfiguredPipes);
63 m_ConfiguredPipes = NULL;
64 }
65
66 m_NumberOfConfiguredPipes = 0;
67
68 if (m_Settings != NULL) {
69 FxPoolFree(m_Settings);
70 m_Settings = NULL;
71 }
72
73 //
74 // Release the reference taken in the constructor
75 //
76 m_UsbDevice->RELEASE(this);
77 }
78
79 VOID
CleanUpAndDelete(__in BOOLEAN Failure)80 FxUsbInterface::CleanUpAndDelete(
81 __in BOOLEAN Failure
82 )
83 /*++
84
85 Routine Description:
86 Deletes the pipes contained on the interface.
87
88 Arguments:
89 Failure - if TRUE, the pipes were never exposed to the client, so any attributes
90 are cleared before deletion (via DeleteFromFailedCreate)
91
92 Assumes:
93 FxUsbDevice::InterfaceIterationLock is held by the caller
94
95 Return Value:
96 None
97
98 --*/
99 {
100 FxUsbPipe** pPipes;
101 ULONG numPipes;
102 KIRQL irql;
103 ULONG i;
104
105 //
106 // Capture the values, clear them out of the object and then clean them up
107 // outside of the lock.
108 //
109 m_UsbDevice->Lock(&irql);
110
111 pPipes = m_ConfiguredPipes;
112 numPipes = m_NumberOfConfiguredPipes;
113
114 m_ConfiguredPipes = NULL;
115 m_NumberOfConfiguredPipes = 0;
116
117 m_UsbDevice->Unlock(irql);
118
119 if (pPipes != NULL) {
120 for (i = 0; i < numPipes; i++) {
121 if (pPipes[i] != NULL) {
122 if (Failure) {
123 //
124 // FxIoTarget::Remove will be called in FxIoTarget::Dispose()
125 //
126 pPipes[i]->DeleteFromFailedCreate();
127 }
128 else {
129 pPipes[i]->DeleteObject();
130 }
131 }
132 else {
133 //
134 // No more pointers to delete, break out of the loop
135 //
136 break;
137 }
138 }
139
140 FxPoolFree(pPipes);
141 pPipes = NULL;
142 }
143 }
144
145 VOID
RemoveDeletedPipe(__in FxUsbPipe * Pipe)146 FxUsbInterface::RemoveDeletedPipe(
147 __in FxUsbPipe* Pipe
148 )
149 {
150 ULONG i;
151
152 if (m_ConfiguredPipes == NULL) {
153 return;
154 }
155
156 for (i = 0; i < m_NumberOfConfiguredPipes; i++) {
157 if (m_ConfiguredPipes[i] == Pipe) {
158 m_ConfiguredPipes[i] = NULL;
159 return;
160 }
161 }
162 }
163
164 VOID
SetInfo(__in PUSBD_INTERFACE_INFORMATION InterfaceInfo)165 FxUsbInterface::SetInfo(
166 __in PUSBD_INTERFACE_INFORMATION InterfaceInfo
167 )
168 /*++
169
170 Routine Description:
171 Captures the alternate from the interface information into this structure
172 and then assigns info to all the created pipes.
173
174 Arguments:
175 InterfaceInfo - info to capture
176
177 Return Value:
178 None
179
180 --*/
181 {
182 UCHAR i;
183
184 ASSERT(m_InterfaceNumber == InterfaceInfo->InterfaceNumber);
185
186 m_CurAlternateSetting = InterfaceInfo->AlternateSetting;
187
188 for (i = 0; i < m_NumberOfConfiguredPipes ; i++) {
189 m_ConfiguredPipes[i]->InitPipe(&InterfaceInfo->Pipes[i],
190 InterfaceInfo->InterfaceNumber,
191 this);
192 }
193 }
194
195 _Must_inspect_result_
196 NTSTATUS
CreateSettings(VOID)197 FxUsbInterface::CreateSettings(
198 VOID
199 )
200 /*++
201
202 Routine Description:
203 1) Find the max number of settings for the interface
204 2) Allocate an array for the settings
205 3) Create a setting object for each setting and initialize
206
207 Arguments:
208 None
209
210 Return Value:
211 NTSTATUS
212
213 --*/
214 {
215 PUSB_INTERFACE_DESCRIPTOR pDescriptor;
216 ULONG size;
217 UCHAR i;
218
219 //
220 // No need to validate the size of the interface descriptor since FxUsbDevice::CreateInterfaces
221 // has already done so
222 //
223 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType(
224 m_UsbDevice->m_ConfigDescriptor,
225 m_UsbDevice->m_ConfigDescriptor->wTotalLength,
226 m_UsbDevice->m_ConfigDescriptor,
227 USB_INTERFACE_DESCRIPTOR_TYPE
228 );
229
230 //
231 // Calculate the number of settings for this interface
232 //
233 while (pDescriptor != NULL) {
234 if (m_InterfaceNumber == pDescriptor->bInterfaceNumber) {
235 m_NumSettings++;
236 }
237 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType(
238 m_UsbDevice->m_ConfigDescriptor,
239 m_UsbDevice->m_ConfigDescriptor->wTotalLength,
240 WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength),
241 USB_INTERFACE_DESCRIPTOR_TYPE
242 );
243 }
244 size = sizeof(FxUsbInterfaceSetting) * m_NumSettings;
245 m_Settings = (FxUsbInterfaceSetting *) FxPoolAllocate(
246 GetDriverGlobals(), NonPagedPool, size);
247
248 if (m_Settings == NULL) {
249 DoTraceLevelMessage(
250 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
251 "Could not allocate memory for %d settings for bInterfaceNumber %d "
252 "(Protocol %d, Class %d, SubClass %d), %!STATUS!",
253 m_NumSettings, m_InterfaceNumber, m_Protocol, m_Class, m_SubClass,
254 STATUS_INSUFFICIENT_RESOURCES);
255
256 return STATUS_INSUFFICIENT_RESOURCES;
257 }
258
259 RtlZeroMemory(m_Settings, size);
260
261 //
262 // Add all the settings for this interface
263 //
264 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType(
265 m_UsbDevice->m_ConfigDescriptor,
266 m_UsbDevice->m_ConfigDescriptor->wTotalLength,
267 m_UsbDevice->m_ConfigDescriptor,
268 USB_INTERFACE_DESCRIPTOR_TYPE
269 );
270
271 while (pDescriptor != NULL) {
272 if (m_InterfaceNumber == pDescriptor->bInterfaceNumber) {
273 if (pDescriptor->bAlternateSetting < m_NumSettings) {
274 m_Settings[pDescriptor->bAlternateSetting].InterfaceDescriptor = pDescriptor;
275 }
276 else {
277 DoTraceLevelMessage(
278 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
279 "Interface Number %d does not have contiguous alternate settings,"
280 "expected %d settings, found alt setting %d, %!STATUS!",
281 pDescriptor->bInterfaceNumber, m_NumSettings,
282 pDescriptor->bAlternateSetting, STATUS_INVALID_DEVICE_REQUEST);
283
284 return STATUS_INVALID_DEVICE_REQUEST;
285 }
286 }
287
288 pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType(
289 m_UsbDevice->m_ConfigDescriptor,
290 m_UsbDevice->m_ConfigDescriptor->wTotalLength,
291 WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength),
292 USB_INTERFACE_DESCRIPTOR_TYPE
293 );
294 }
295
296 for (i = 0; i < m_NumSettings; i++) {
297
298 if (m_Settings[i].InterfaceDescriptor == NULL) {
299 DoTraceLevelMessage(
300 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
301 "Interface Number %d does not have contiguous alternate settings,"
302 "expected consecutive %d settings, but alt setting %d missing "
303 "%!STATUS!", m_InterfaceNumber, m_NumSettings, i,
304 STATUS_INVALID_DEVICE_REQUEST);
305
306 return STATUS_INVALID_DEVICE_REQUEST;
307 }
308
309 //
310 // Only validate the endpoints if the interface reports it has some. We don't
311 // want to validate EP descriptors that may be after the interface descriptor
312 // that are never used because bNumEndpoints doesn't indicate they are present.
313 //
314 if (m_Settings[i].InterfaceDescriptor->bNumEndpoints > 0) {
315 PVOID pRelativeEnd;
316 NTSTATUS status;
317
318 //
319 // Validate that each endpoint descriptor is the correct size for this alt setting.
320 // We will use the next inteface descriptor as the end, and if this is the last
321 // interface descriptor, use the end of the config descriptor as our end.
322 //
323 pRelativeEnd = FxUsbFindDescriptorType(
324 m_UsbDevice->m_ConfigDescriptor,
325 m_UsbDevice->m_ConfigDescriptor->wTotalLength,
326 m_Settings[i].InterfaceDescriptor,
327 USB_INTERFACE_DESCRIPTOR_TYPE
328 );
329
330 if (pRelativeEnd == NULL) {
331 //
332 // This is the last alt setting in the config descriptor, use the end of the
333 // config descriptor as our end
334 //
335 pRelativeEnd = WDF_PTR_ADD_OFFSET(m_UsbDevice->m_ConfigDescriptor,
336 m_UsbDevice->m_ConfigDescriptor->wTotalLength);
337 }
338
339 //
340 // Limit the number of endpoints validated to bNumEndpoints. In theory
341 // there could be EP descriptors after N EP descriptors that are never
342 // used, thus we don't want to risk valdiating them and failing them
343 // (ie an app compat concern, in a perfect world we would validate them)
344 //
345 status = FxUsbValidateDescriptorType(
346 GetDriverGlobals(),
347 m_UsbDevice->m_ConfigDescriptor,
348 m_Settings[i].InterfaceDescriptor,
349 pRelativeEnd,
350 USB_ENDPOINT_DESCRIPTOR_TYPE,
351 sizeof(USB_ENDPOINT_DESCRIPTOR),
352 FxUsbValidateDescriptorOpAtLeast,
353 m_Settings[i].InterfaceDescriptor->bNumEndpoints
354 );
355
356 if (!NT_SUCCESS(status)) {
357 DoTraceLevelMessage(
358 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
359 "Interface Number %d does not have a valid endpoint descriptor,"
360 "%!STATUS!", m_InterfaceNumber, status);
361
362 return status;
363 }
364 }
365 }
366
367 return STATUS_SUCCESS;
368 }
369
370 _Must_inspect_result_
371 NTSTATUS
SelectSettingByIndex(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,__in UCHAR SettingIndex)372 FxUsbInterface::SelectSettingByIndex(
373 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
374 __in UCHAR SettingIndex
375 )
376 /*++
377
378 Routine Description:
379 Setlects a setting by alternate setting index.
380
381 Arguments:
382 PipesAttributes - optional attributes to apply to each of the created pipes
383
384 SettingIndex - alternate setting index to use
385
386 Return Value:
387 NTSTATUS
388
389 --*/
390 {
391 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
392 PURB urb;
393 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
394 UMURB urb;
395 PUSB_INTERFACE_DESCRIPTOR interfaceDesc;
396 #endif
397 FxUsbInterfaceSetting entry;
398 UCHAR numEP;
399 NTSTATUS status;
400 USHORT size;
401
402 status = STATUS_SUCCESS;
403
404 //
405 // We should have at least 1 setting on the interface
406 //
407 ASSERT(m_NumSettings != 0);
408
409 //
410 // If m_NumberOfConfiguredPipes == 0 then it also tells us that
411 // the interface wasn't configured. So it can keep track of configuredness
412 // of the interface. Could there be a case when the selected setting has 0
413 // EP's. Due to the above case we use m_InterfaceConfigured.
414 //
415 if (IsInterfaceConfigured() && m_CurAlternateSetting == SettingIndex) {
416 return STATUS_SUCCESS;
417 }
418
419 //
420 // Check for an invalid alternate setting
421 //
422 if (SettingIndex >= m_NumSettings){
423 return STATUS_INVALID_PARAMETER;
424 }
425
426 RtlCopyMemory(&entry, &m_Settings[SettingIndex], sizeof(entry));
427
428 //
429 // Create the configured pipes
430 //
431 numEP = entry.InterfaceDescriptor->bNumEndpoints;
432
433 size = GET_SELECT_INTERFACE_REQUEST_SIZE(numEP);
434
435 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
436 urb = (PURB) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size);
437
438 if (urb == NULL) {
439 status = STATUS_INSUFFICIENT_RESOURCES;
440 }
441 else {
442 FormatSelectSettingUrb(urb, numEP, SettingIndex);
443
444 status = SelectSetting(PipesAttributes, urb);
445
446 FxPoolFree(urb);
447 urb = NULL;
448 }
449 #elif (FX_CORE_MODE == FX_CORE_USER_MODE)
450 RtlZeroMemory(&urb, sizeof(UMURB));
451
452 urb.UmUrbSelectInterface.Hdr.InterfaceHandle = m_WinUsbHandle;
453 urb.UmUrbSelectInterface.Hdr.Function = UMURB_FUNCTION_SELECT_INTERFACE;
454 urb.UmUrbSelectInterface.Hdr.Length = sizeof(_UMURB_SELECT_INTERFACE);
455
456 urb.UmUrbSelectInterface.AlternateSetting = SettingIndex;
457
458 status = m_UsbDevice->SendSyncUmUrb(&urb, 2);
459
460 if (NT_SUCCESS(status)) {
461 RtlZeroMemory(&urb, sizeof(UMURB));
462
463 urb.UmUrbInterfaceInformation.Hdr.InterfaceHandle = m_WinUsbHandle;
464 urb.UmUrbInterfaceInformation.Hdr.Function = UMURB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE;
465 urb.UmUrbInterfaceInformation.Hdr.Length = sizeof(_UMURB_INTERFACE_INFORMATION);
466
467 urb.UmUrbInterfaceInformation.AlternateSetting = SettingIndex;
468
469 status = m_UsbDevice->SendSyncUmUrb(&urb, 2);
470
471 if (NT_SUCCESS(status)) {
472 interfaceDesc = &urb.UmUrbInterfaceInformation.UsbInterfaceDescriptor;
473
474 m_Settings[SettingIndex].InterfaceDescriptorAlloc = *interfaceDesc;
475
476 m_CurAlternateSetting = SettingIndex;
477
478 MakeAndConfigurePipes(PipesAttributes, interfaceDesc->bNumEndpoints);
479 }
480 }
481 #endif
482
483 return status;
484 }
485
486 _Must_inspect_result_
487 NTSTATUS
SelectSettingByDescriptor(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,__in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor)488 FxUsbInterface::SelectSettingByDescriptor(
489 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
490 __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
491 )
492 /*++
493
494 Routine Description:
495 Selects an alternate setting by using a USB interface descriptor
496
497 Arguments:
498 PipesAttributes - optional attributes to apply to each of the created pipes
499
500 Return Value:
501 NTSTATUS
502
503 --*/
504 {
505 PURB urb;
506 NTSTATUS status;
507 USHORT size;
508
509 if (IsInterfaceConfigured() &&
510 (m_CurAlternateSetting == InterfaceDescriptor->bAlternateSetting)) {
511 //
512 // Don't do anything
513 //
514 return STATUS_SUCCESS;
515 }
516
517 if (InterfaceDescriptor->bInterfaceNumber != m_InterfaceNumber) {
518 status = STATUS_INVALID_PARAMETER;
519
520 DoTraceLevelMessage(
521 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
522 "WDFUSBINTERFACE %p has interface num %d, select setting by "
523 "descriptor specified interface num %d, %!STATUS!",
524 GetHandle(), m_InterfaceNumber,
525 InterfaceDescriptor->bInterfaceNumber, status
526 );
527
528 return status;
529 }
530
531 size = GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints);
532
533 urb = (PURB) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size);
534
535 if (urb == NULL) {
536 status = STATUS_INSUFFICIENT_RESOURCES;
537 }
538 else {
539 FormatSelectSettingUrb(
540 urb,
541 InterfaceDescriptor->bNumEndpoints,
542 InterfaceDescriptor->bAlternateSetting
543 );
544
545 status = SelectSetting(PipesAttributes, urb);
546
547 FxPoolFree(urb);
548 }
549
550 return status;
551 }
552
553 _Must_inspect_result_
554 NTSTATUS
CheckAndSelectSettingByIndex(__in UCHAR SettingIndex)555 FxUsbInterface::CheckAndSelectSettingByIndex(
556 __in UCHAR SettingIndex
557 )
558 /*++
559
560 Routine Description:
561 Checks if the give SettingIndex is the current alternate setting
562 and if not, selects that setting
563
564 Arguments:
565 SettingIndex - Alternate setting
566
567 Return Value:
568 NTSTATUS
569
570 --*/
571 {
572 if (GetConfiguredSettingIndex() != SettingIndex) {
573 return SelectSettingByIndex(NULL,
574 SettingIndex);
575 }
576 else {
577 return STATUS_SUCCESS;
578 }
579 }
580
581 _Must_inspect_result_
582 NTSTATUS
SelectSetting(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,__in PURB Urb)583 FxUsbInterface::SelectSetting(
584 __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
585 __in PURB Urb
586 )
587 /*++
588
589 Routine Description:
590 Worker function which all top level SelectSetting DDIs call into. This will
591 1) preallocate all required objects so that we can return failure before
592 we make any undoable changes to the device's state
593 2) send the select interface URB to the device
594 3) initialize all created objects
595
596 Arguments:
597 PipesAttributes - optional attributes to apply to all created pipes
598
599 Urb - Urb to send to the device
600
601 Return Value:
602 NTSTATUS
603
604 --*/
605 {
606 FxSyncRequest request(GetDriverGlobals(), NULL);
607 LIST_ENTRY pendHead;
608 FxUsbPipe* pPipe;
609 NTSTATUS status;
610 UCHAR iPipe, numPipes;
611 WDF_REQUEST_SEND_OPTIONS options;
612 FxUsbPipe ** ppPipes;
613 ULONG size;
614
615 //
616 // FxSyncRequest always succeesds for KM but can fail for UM.
617 //
618 status = request.Initialize();
619 if (!NT_SUCCESS(status)) {
620 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
621 "Failed to initialize FxSyncRequest");
622 return status;
623 }
624
625 //
626 // Subtract the size of the embedded pipe.
627 //
628 const ULONG interfaceStructSize = sizeof(Urb->UrbSelectInterface.Interface) -
629 sizeof(USBD_PIPE_INFORMATION);
630
631 //
632 // This check will happen twice for SelectSettingByInterface/Descriptor.
633 //
634 // We could just do it here, but the above two functions will unnecessarily
635 // have to build an URB.
636 //
637 if (IsInterfaceConfigured() &&
638 m_CurAlternateSetting ==
639 Urb->UrbSelectInterface.Interface.AlternateSetting) {
640 //
641 // don't do anything
642 //
643 return STATUS_SUCCESS;
644 }
645
646 InitializeListHead(&pendHead);
647 numPipes = 0;
648 ppPipes = NULL;
649
650 if (Urb->UrbSelectInterface.Hdr.Length < interfaceStructSize) {
651 status = STATUS_INVALID_PARAMETER;
652 DoTraceLevelMessage(
653 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
654 "Urb header length 0x%x is less than expected 0x%x"
655 "%!STATUS!", Urb->UrbSelectInterface.Hdr.Length, interfaceStructSize,status
656 );
657 return status;
658 }
659
660 status = request.m_TrueRequest->ValidateTarget(m_UsbDevice);
661 if (!NT_SUCCESS(status)) {
662 goto Done;
663 }
664
665 //
666 // Urb->UrbSelectInterface.Interface.NumberOfPipes is set when the URB
667 // completes. So, we must compute the number of pipes being requested based
668 // on the size of the structure and its Length (as set by the caller).
669 // To calculate the number of pipes we need to account for the
670 // embedded pipe in the structure.
671 //
672 numPipes = (UCHAR) ((Urb->UrbSelectInterface.Interface.Length -
673 interfaceStructSize) /
674 sizeof(USBD_PIPE_INFORMATION)
675 );
676
677 if (numPipes > 0) {
678 size = numPipes * sizeof(FxUsbPipe *);
679 }
680 else {
681 //
682 // It is valid to have an interface with zero pipes in it. In that
683 // case, we just allocate one entry so that we have a valid array
684 // and keep the remaining code simple.
685 //
686 size = sizeof(FxUsbPipe*);
687 }
688
689 //
690 // If the interface is already configured don't do anything with the old
691 // settings till we allocate new.
692 //
693 ppPipes = (FxUsbPipe **) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size);
694
695 if (ppPipes == NULL) {
696 status = STATUS_INSUFFICIENT_RESOURCES;
697 DoTraceLevelMessage(
698 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
699 "Unable to allocate memory %!STATUS!"
700 , status);
701 goto Done;
702 }
703
704 RtlZeroMemory(ppPipes, size);
705
706 for (iPipe = 0; iPipe < numPipes; iPipe++) {
707 ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes)
708 FxUsbPipe(GetDriverGlobals(),m_UsbDevice);
709
710 if (ppPipes[iPipe] == NULL) {
711 status = STATUS_INSUFFICIENT_RESOURCES;
712 DoTraceLevelMessage(
713 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
714 "Unable to allocate memory for the pipes %!STATUS!", status);
715 goto Done;
716 }
717
718 pPipe = ppPipes[iPipe];
719
720 status = pPipe->Init(m_UsbDevice->m_Device);
721 if (!NT_SUCCESS(status)) {
722 DoTraceLevelMessage(
723 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
724 "Init pipe failed %!STATUS!", status);
725 goto Done;
726 }
727
728 status = pPipe->Commit(PipesAttributes, NULL, this);
729
730 if (!NT_SUCCESS(status)) {
731 DoTraceLevelMessage(
732 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
733 "Commit pipe failed %!STATUS!", status);
734 goto Done;
735 }
736 }
737
738 if (IsInterfaceConfigured()) {
739 //
740 // Delete the old pipes
741 //
742 m_UsbDevice->CleanupInterfacePipesAndDelete(this);
743 }
744
745
746 WDF_REQUEST_SEND_OPTIONS_INIT(&options,
747 WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
748
749 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(2));
750
751 FxFormatUsbRequest(request.m_TrueRequest, Urb, FxUrbTypeLegacy, NULL);
752 status = m_UsbDevice->SubmitSync(request.m_TrueRequest, &options, NULL);
753
754 //
755 // If select interface URB fails we are at the point of no return and we
756 // will end up with no configured pipes.
757 //
758 if (NT_SUCCESS(status)) {
759 SetNumConfiguredPipes(numPipes);
760 SetConfiguredPipes(ppPipes);
761 SetInfo(&Urb->UrbSelectInterface.Interface);
762 }
763
764 Done:
765 if (!NT_SUCCESS(status)) {
766 if (ppPipes != NULL) {
767 ASSERT(ppPipes != m_ConfiguredPipes);
768
769 for (iPipe = 0; iPipe < numPipes; iPipe++) {
770 if (ppPipes[iPipe] != NULL) {
771 ppPipes[iPipe]->DeleteFromFailedCreate();
772 }
773 }
774
775 FxPoolFree(ppPipes);
776 ppPipes = NULL;
777 }
778 }
779
780 return status;
781 }
782
783 VOID
FormatSelectSettingUrb(__in_bcount (GET_SELECT_INTERFACE_REQUEST_SIZE (NumEndpoints))PURB Urb,__in USHORT NumEndpoints,__in UCHAR SettingNumber)784 FxUsbInterface::FormatSelectSettingUrb(
785 __in_bcount(GET_SELECT_INTERFACE_REQUEST_SIZE(NumEndpoints)) PURB Urb,
786 __in USHORT NumEndpoints,
787 __in UCHAR SettingNumber
788 )
789 /*++
790
791 Routine Description:
792 Format a URB for selecting an interface's new setting. Note this will setup
793 the URB header and all pipes' information in the URB's array of pipe infos.
794
795 This function exists as a method of FxUsbDevice instead of FxUsbInterface
796 because in the case of a select config where we manually select setting 0
797 on interfaces 2...N we don't have an FxUsbInterface pointer
798
799 Arguments:
800 Urb - the URB to format. It is assumed the caller allocated a large enough
801 URB to contain NumEndpoints
802
803 NumEndpoints - number of endpoints in the new setting
804
805 InterfaceNum - interface number for the interface
806
807 SettingNumber - setting number on the interface
808
809 --*/
810 {
811 ULONG defaultMaxTransferSize;
812 USHORT size;
813 UCHAR i;
814
815 size = GET_SELECT_INTERFACE_REQUEST_SIZE(NumEndpoints);
816
817 RtlZeroMemory(Urb, size);
818
819 //
820 // Setup the URB, format the request, and send it
821 //
822 UsbBuildSelectInterfaceRequest(Urb,
823 size,
824 m_UsbDevice->m_ConfigHandle,
825 m_InterfaceNumber,
826 SettingNumber);
827
828 defaultMaxTransferSize = m_UsbDevice->GetDefaultMaxTransferSize();
829
830 Urb->UrbSelectInterface.Interface.Length =
831 GET_USBD_INTERFACE_SIZE(NumEndpoints);
832
833 Urb->UrbSelectInterface.Interface.NumberOfPipes = NumEndpoints;
834
835 for (i = 0; i < NumEndpoints; i++) {
836
837 //
838 // Make sure that the Interface Length conveys the exact number of EP's
839 //
840 ASSERT(
841 &Urb->UrbSelectInterface.Interface.Pipes[i] <
842 WDF_PTR_ADD_OFFSET(&Urb->UrbSelectInterface.Interface,
843 Urb->UrbSelectInterface.Interface.Length)
844 );
845
846 Urb->UrbSelectInterface.Interface.Pipes[i].PipeFlags = 0x0;
847 Urb->UrbSelectInterface.Interface.Pipes[i].MaximumTransferSize =
848 defaultMaxTransferSize;
849 }
850 }
851
852 VOID
GetEndpointInformation(__in UCHAR SettingIndex,__in UCHAR EndpointIndex,__in PWDF_USB_PIPE_INFORMATION PipeInfo)853 FxUsbInterface::GetEndpointInformation(
854 __in UCHAR SettingIndex,
855 __in UCHAR EndpointIndex,
856 __in PWDF_USB_PIPE_INFORMATION PipeInfo
857 )
858 /*++
859
860 Routine Description:
861 The layout of the config descriptor is such that each interface+setting pair
862 is followed by the endpoints for that interface+setting pair. Keep track of
863 the index.
864
865 Arguments:
866 SettingIndex - alternate setting to get info for
867
868 EndpointIndex - index into the number endpoints for this interface+setting
869
870 PipeInfo - Info to return
871
872 Return Value:
873 None
874
875 --*/
876 {
877 PUCHAR pEnd, pCur;
878 PUSB_INTERFACE_DESCRIPTOR pInterfaceDesc;
879 PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc;
880 UCHAR curEndpointIndex;
881 BOOLEAN endPointFound;
882
883 pInterfaceDesc = NULL;
884 curEndpointIndex = 0;
885 endPointFound = FALSE;
886
887 //
888 // Extract the interface descriptor for the alternate setting for the interface
889 //
890 pInterfaceDesc = GetSettingDescriptor(SettingIndex);
891
892 if (pInterfaceDesc == NULL) {
893 return;
894 }
895
896 pEnd = (PUCHAR) WDF_PTR_ADD_OFFSET(
897 m_UsbDevice->m_ConfigDescriptor,
898 m_UsbDevice->m_ConfigDescriptor->wTotalLength
899 );
900
901 //
902 // Start from the descriptor after current one
903 //
904 pCur = (PUCHAR) WDF_PTR_ADD_OFFSET(pInterfaceDesc, pInterfaceDesc->bLength);
905
906 //
907 // Iterate through the list of EP descriptors following the interface descriptor
908 // we just found and get the endpoint descriptor which matches the endpoint
909 // index or we hit another interface descriptor
910 //
911 // We have already validated that the descriptor headers are well formed and within
912 // the config descriptor bounds
913 //
914 while (pCur < pEnd) {
915 PUSB_COMMON_DESCRIPTOR pCommonDesc = (PUSB_COMMON_DESCRIPTOR) pCur;
916
917 //
918 // If we hit the next interface no way we can find the EndPoint
919 //
920 if (pCommonDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) {
921 break;
922 }
923
924 if (pCommonDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) {
925 //
926 // Size of pEndpointDesc has been validated by CreateSettings() and
927 // is within the config descriptor
928 //
929 pEndpointDesc = (PUSB_ENDPOINT_DESCRIPTOR) pCommonDesc;
930
931 if (EndpointIndex == curEndpointIndex) {
932 CopyEndpointFieldsFromDescriptor(PipeInfo,
933 pEndpointDesc,
934 SettingIndex);
935 break;
936 }
937
938 curEndpointIndex++;
939 }
940
941 //
942 // Advance past this descriptor
943 //
944 pCur += pCommonDesc->bLength;
945 }
946 }
947
948 ULONG
DetermineDefaultMaxTransferSize(VOID)949 FxUsbInterface::DetermineDefaultMaxTransferSize(
950 VOID
951 )
952 /*++
953
954 Routine Description:
955 Returns the maximum transfer size of an endpoint
956
957 Arguments:
958 None
959
960 Return Value:
961 max transfer size
962
963 --*/
964 {
965 if (m_UsbDevice->m_Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) {
966 return FxUsbPipeHighSpeedMaxTransferSize;
967 }
968 else {
969 return FxUsbPipeLowSpeedMaxTransferSize;
970 }
971 }
972
973 VOID
CopyEndpointFieldsFromDescriptor(__in PWDF_USB_PIPE_INFORMATION PipeInfo,__in PUSB_ENDPOINT_DESCRIPTOR EndpointDesc,__in UCHAR SettingIndex)974 FxUsbInterface::CopyEndpointFieldsFromDescriptor(
975 __in PWDF_USB_PIPE_INFORMATION PipeInfo,
976 __in PUSB_ENDPOINT_DESCRIPTOR EndpointDesc,
977 __in UCHAR SettingIndex
978 )
979 /*++
980
981 Routine Description:
982 Copy informatoin out of the usb endpoint descriptor into this object
983
984 Arguments:
985 PipeInfo - information to return
986
987 EndpointDesc - descriptor to copy from
988
989 SettingIndex - alternate setting this information is for
990
991 Return Value:
992 None
993
994 --*/
995 {
996 PipeInfo->MaximumPacketSize = EndpointDesc->wMaxPacketSize;
997 PipeInfo->EndpointAddress = EndpointDesc->bEndpointAddress;
998 PipeInfo->Interval = EndpointDesc->bInterval;
999
1000 //
1001 // Extract the lower 2 bits which contain the EP type
1002 //
1003 PipeInfo->PipeType = FxUsbPipe::_UsbdPipeTypeToWdf(
1004 (USBD_PIPE_TYPE) (EndpointDesc->bmAttributes & 0x03)
1005 );
1006
1007 //
1008 // Filling in a default value since the EndpointDescriptor doesn't contain it
1009 //
1010 if (PipeInfo->PipeType == WdfUsbPipeTypeControl) {
1011 PipeInfo->MaximumTransferSize = FxUsbPipeControlMaxTransferSize;
1012 }
1013 else {
1014 PipeInfo->MaximumTransferSize = DetermineDefaultMaxTransferSize();
1015 }
1016
1017 PipeInfo->SettingIndex = SettingIndex;
1018 }
1019
1020 WDFUSBPIPE
GetConfiguredPipe(__in UCHAR PipeIndex,__out_opt PWDF_USB_PIPE_INFORMATION PipeInfo)1021 FxUsbInterface::GetConfiguredPipe(
1022 __in UCHAR PipeIndex,
1023 __out_opt PWDF_USB_PIPE_INFORMATION PipeInfo
1024 )
1025 /*++
1026
1027 Routine Description:
1028 Return the WDFUSBPIPE for the given index
1029
1030 Arguments:
1031 PipeIndex - index into the number of configured pipes for the interface
1032
1033 PipeInfo - optional information to return about the returned pipe
1034
1035 Return Value:
1036 valid WDFUSBPIPE handle or NULL on error
1037
1038 --*/
1039 {
1040 if (PipeIndex >= m_NumberOfConfiguredPipes) {
1041 return NULL;
1042 }
1043 else {
1044 if (PipeInfo != NULL) {
1045 m_ConfiguredPipes[PipeIndex]->GetInformation(PipeInfo);
1046 }
1047
1048 return m_ConfiguredPipes[PipeIndex]->GetHandle();
1049 }
1050 }
1051
1052 VOID
GetDescriptor(__in PUSB_INTERFACE_DESCRIPTOR UsbInterfaceDescriptor,__in UCHAR SettingIndex)1053 FxUsbInterface::GetDescriptor(
1054 __in PUSB_INTERFACE_DESCRIPTOR UsbInterfaceDescriptor,
1055 __in UCHAR SettingIndex
1056 )
1057 /*++
1058
1059 Routine Description:
1060 Copies the descriptor back to the caller
1061
1062 Arguments:
1063 UsbInterfaceDescriptor - descriptor pointer to fill in
1064
1065 SettingIndex - alternate setting that the caller is interested in
1066
1067 Return Value:
1068 None
1069
1070 --*/
1071 {
1072 if (SettingIndex >= m_NumSettings) {
1073 RtlZeroMemory(UsbInterfaceDescriptor,
1074 sizeof(*UsbInterfaceDescriptor));
1075 }
1076 else {
1077 RtlCopyMemory(UsbInterfaceDescriptor,
1078 m_Settings[SettingIndex].InterfaceDescriptor,
1079 sizeof(*UsbInterfaceDescriptor));
1080 }
1081 }
1082
1083 UCHAR
GetConfiguredSettingIndex(VOID)1084 FxUsbInterface::GetConfiguredSettingIndex(
1085 VOID
1086 )
1087 /*++
1088
1089 Routine Description:
1090 Returns the currently configured setting index for the interface
1091
1092 Arguments:
1093 None
1094
1095 Return Value:
1096 Currently configured Index
1097
1098 --*/
1099
1100 {
1101 if (IsInterfaceConfigured()) {
1102 return m_CurAlternateSetting;
1103 }
1104 else {
1105 DoTraceLevelMessage(
1106 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
1107 "WDFUSBINTERFACE %p not configured, cannot retrieve configured "
1108 "setting index", GetHandle());
1109
1110 FxVerifierDbgBreakPoint(GetDriverGlobals());
1111
1112 return 0;
1113 }
1114 }
1115
1116 UCHAR
GetNumEndpoints(__in UCHAR SettingIndex)1117 FxUsbInterface::GetNumEndpoints(
1118 __in UCHAR SettingIndex
1119 )
1120 /*++
1121
1122 Routine Description:
1123 Returns the number of endpoints on a given alternate interface
1124
1125 Arguments:
1126 SettingIndex - index of the alternate setting
1127
1128 Return Value:
1129 Number of endpoints or 0 on error
1130
1131 --*/
1132 {
1133 if (SettingIndex >= m_NumSettings) {
1134 return 0;
1135 }
1136 else {
1137 return m_Settings[SettingIndex].InterfaceDescriptor->bNumEndpoints;
1138 }
1139 }
1140
1141 PUSB_INTERFACE_DESCRIPTOR
GetSettingDescriptor(__in UCHAR Setting)1142 FxUsbInterface::GetSettingDescriptor(
1143 __in UCHAR Setting
1144 )
1145 /*++
1146
1147 Routine Description:
1148 Returns the device's interface descriptor for the given alternate setting
1149
1150 Arguments:
1151 Setting - AlternateSetting desired
1152
1153 Return Value:
1154 USB interface descriptor or NULL on failure
1155
1156 --*/
1157 {
1158 UCHAR i;
1159
1160 for (i = 0; i < m_NumSettings; i++) {
1161 if (m_Settings[i].InterfaceDescriptor->bAlternateSetting == Setting) {
1162 return m_Settings[i].InterfaceDescriptor;
1163 }
1164 }
1165
1166 return NULL;
1167 }
1168
1169