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