1*8a978a17SVictor Perevertkin /*++
2*8a978a17SVictor Perevertkin 
3*8a978a17SVictor Perevertkin Copyright (c) Microsoft Corporation
4*8a978a17SVictor Perevertkin 
5*8a978a17SVictor Perevertkin Module Name:
6*8a978a17SVictor Perevertkin 
7*8a978a17SVictor Perevertkin     FxUsbInterfaceUm.cpp
8*8a978a17SVictor Perevertkin 
9*8a978a17SVictor Perevertkin Abstract:
10*8a978a17SVictor Perevertkin 
11*8a978a17SVictor Perevertkin Author:
12*8a978a17SVictor Perevertkin 
13*8a978a17SVictor Perevertkin Environment:
14*8a978a17SVictor Perevertkin 
15*8a978a17SVictor Perevertkin     user mode only
16*8a978a17SVictor Perevertkin 
17*8a978a17SVictor Perevertkin Revision History:
18*8a978a17SVictor Perevertkin 
19*8a978a17SVictor Perevertkin --*/
20*8a978a17SVictor Perevertkin 
21*8a978a17SVictor Perevertkin #include "fxusbpch.hpp"
22*8a978a17SVictor Perevertkin 
23*8a978a17SVictor Perevertkin extern "C" {
24*8a978a17SVictor Perevertkin #include "FxUsbInterfaceUm.tmh"
25*8a978a17SVictor Perevertkin }
26*8a978a17SVictor Perevertkin 
27*8a978a17SVictor Perevertkin NTSTATUS
SetWinUsbHandle(_In_ UCHAR FrameworkInterfaceIndex)28*8a978a17SVictor Perevertkin FxUsbInterface::SetWinUsbHandle(
29*8a978a17SVictor Perevertkin     _In_ UCHAR FrameworkInterfaceIndex
30*8a978a17SVictor Perevertkin )
31*8a978a17SVictor Perevertkin {
32*8a978a17SVictor Perevertkin     NTSTATUS status = STATUS_SUCCESS;
33*8a978a17SVictor Perevertkin     UMURB urb;
34*8a978a17SVictor Perevertkin 
35*8a978a17SVictor Perevertkin     if (m_InterfaceNumber != FrameworkInterfaceIndex) {
36*8a978a17SVictor Perevertkin         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET,
37*8a978a17SVictor Perevertkin                             "Composite device detected: Converting absolute interface "
38*8a978a17SVictor Perevertkin                             "index %d to relative interface index %d", m_InterfaceNumber,
39*8a978a17SVictor Perevertkin                             FrameworkInterfaceIndex);
40*8a978a17SVictor Perevertkin     }
41*8a978a17SVictor Perevertkin 
42*8a978a17SVictor Perevertkin     if (FrameworkInterfaceIndex == 0) {
43*8a978a17SVictor Perevertkin         m_WinUsbHandle = m_UsbDevice->m_WinUsbHandle;
44*8a978a17SVictor Perevertkin     }
45*8a978a17SVictor Perevertkin     else {
46*8a978a17SVictor Perevertkin         RtlZeroMemory(&urb, sizeof(UMURB));
47*8a978a17SVictor Perevertkin 
48*8a978a17SVictor Perevertkin         urb.UmUrbGetAssociatedInterface.Hdr.InterfaceHandle = m_UsbDevice->m_WinUsbHandle;
49*8a978a17SVictor Perevertkin         urb.UmUrbGetAssociatedInterface.Hdr.Function = UMURB_FUNCTION_GET_ASSOCIATED_INTERFACE;
50*8a978a17SVictor Perevertkin         urb.UmUrbGetAssociatedInterface.Hdr.Length = sizeof(_UMURB_GET_ASSOCIATED_INTERFACE);
51*8a978a17SVictor Perevertkin 
52*8a978a17SVictor Perevertkin         //
53*8a978a17SVictor Perevertkin         // If this is using the WinUSB dispatcher, this will ultimately call
54*8a978a17SVictor Perevertkin         // WinUsb_GetAssociatedInterface which expects a 0-based index but starts
55*8a978a17SVictor Perevertkin         // counting from index 1. To get the handle for interface n, we pass n-1
56*8a978a17SVictor Perevertkin         // and WinUSB will return the handle for (n-1)+1.
57*8a978a17SVictor Perevertkin         //
58*8a978a17SVictor Perevertkin         // The NativeUSB dispatcher ultimately calls WdfUsbTargetDeviceGetInterface.
59*8a978a17SVictor Perevertkin         // Unlike WinUSB.sys, this starts counting from index zero. The NativeUSB
60*8a978a17SVictor Perevertkin         // dispatcher expects this framework quirk and adjusts accordingly. See
61*8a978a17SVictor Perevertkin         // WudfNativeUsbDispatcher.cpp for more information.
62*8a978a17SVictor Perevertkin         //
63*8a978a17SVictor Perevertkin         // The actual interface number may differ from the interface index in
64*8a978a17SVictor Perevertkin         // composite devices. In all cases, the interface index (starting from zero)
65*8a978a17SVictor Perevertkin         // must be used.
66*8a978a17SVictor Perevertkin         //
67*8a978a17SVictor Perevertkin         urb.UmUrbGetAssociatedInterface.InterfaceIndex = FrameworkInterfaceIndex - 1;
68*8a978a17SVictor Perevertkin 
69*8a978a17SVictor Perevertkin         status = m_UsbDevice->SendSyncUmUrb(&urb, 5);
70*8a978a17SVictor Perevertkin 
71*8a978a17SVictor Perevertkin         if (NT_SUCCESS(status)) {
72*8a978a17SVictor Perevertkin             m_WinUsbHandle = urb.UmUrbGetAssociatedInterface.InterfaceHandle;
73*8a978a17SVictor Perevertkin         }
74*8a978a17SVictor Perevertkin         else {
75*8a978a17SVictor Perevertkin             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
76*8a978a17SVictor Perevertkin                                 "Failed to retrieve WinUsb interface handle");
77*8a978a17SVictor Perevertkin             m_WinUsbHandle = NULL;
78*8a978a17SVictor Perevertkin         }
79*8a978a17SVictor Perevertkin     }
80*8a978a17SVictor Perevertkin 
81*8a978a17SVictor Perevertkin     return status;
82*8a978a17SVictor Perevertkin }
83*8a978a17SVictor Perevertkin 
84*8a978a17SVictor Perevertkin NTSTATUS
MakeAndConfigurePipes(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes,__in UCHAR NumPipes)85*8a978a17SVictor Perevertkin FxUsbInterface::MakeAndConfigurePipes(
86*8a978a17SVictor Perevertkin     __in PWDF_OBJECT_ATTRIBUTES PipesAttributes,
87*8a978a17SVictor Perevertkin     __in UCHAR NumPipes
88*8a978a17SVictor Perevertkin     )
89*8a978a17SVictor Perevertkin {
90*8a978a17SVictor Perevertkin     NTSTATUS status = STATUS_SUCCESS;
91*8a978a17SVictor Perevertkin     UCHAR iPipe;
92*8a978a17SVictor Perevertkin     FxUsbPipe* pPipe;
93*8a978a17SVictor Perevertkin     FxUsbPipe** ppPipes;
94*8a978a17SVictor Perevertkin     //
95*8a978a17SVictor Perevertkin     // Zero pipes are a valid configuration, this simplifies the code below.
96*8a978a17SVictor Perevertkin     //
97*8a978a17SVictor Perevertkin     ULONG size = (NumPipes == 0 ? 1 : NumPipes) * sizeof(FxUsbPipe*);
98*8a978a17SVictor Perevertkin     UMURB urb;
99*8a978a17SVictor Perevertkin 
100*8a978a17SVictor Perevertkin     ppPipes = (FxUsbPipe**)FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size);
101*8a978a17SVictor Perevertkin     if (ppPipes == NULL) {
102*8a978a17SVictor Perevertkin         status = STATUS_INSUFFICIENT_RESOURCES;
103*8a978a17SVictor Perevertkin         DoTraceLevelMessage(
104*8a978a17SVictor Perevertkin             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
105*8a978a17SVictor Perevertkin             "Unable to allocate memory %!STATUS!", status);
106*8a978a17SVictor Perevertkin         goto Done;
107*8a978a17SVictor Perevertkin     }
108*8a978a17SVictor Perevertkin 
109*8a978a17SVictor Perevertkin     RtlZeroMemory(ppPipes, size);
110*8a978a17SVictor Perevertkin 
111*8a978a17SVictor Perevertkin     for (iPipe = 0; iPipe < NumPipes; iPipe++) {
112*8a978a17SVictor Perevertkin         ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes)
113*8a978a17SVictor Perevertkin             FxUsbPipe(GetDriverGlobals(), m_UsbDevice);
114*8a978a17SVictor Perevertkin 
115*8a978a17SVictor Perevertkin         if (ppPipes[iPipe] == NULL) {
116*8a978a17SVictor Perevertkin             status = STATUS_INSUFFICIENT_RESOURCES;
117*8a978a17SVictor Perevertkin             DoTraceLevelMessage(
118*8a978a17SVictor Perevertkin                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
119*8a978a17SVictor Perevertkin                 "Unable to allocate memory for the pipes %!STATUS!", status);
120*8a978a17SVictor Perevertkin             goto Done;
121*8a978a17SVictor Perevertkin         }
122*8a978a17SVictor Perevertkin 
123*8a978a17SVictor Perevertkin         pPipe = ppPipes[iPipe];
124*8a978a17SVictor Perevertkin 
125*8a978a17SVictor Perevertkin         status = pPipe->Init(m_UsbDevice->m_Device);
126*8a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
127*8a978a17SVictor Perevertkin             DoTraceLevelMessage(
128*8a978a17SVictor Perevertkin                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
129*8a978a17SVictor Perevertkin                 "Init pipe failed  %!STATUS!", status);
130*8a978a17SVictor Perevertkin             goto Done;
131*8a978a17SVictor Perevertkin         }
132*8a978a17SVictor Perevertkin 
133*8a978a17SVictor Perevertkin         status = pPipe->Commit(PipesAttributes, NULL, this);
134*8a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
135*8a978a17SVictor Perevertkin             DoTraceLevelMessage(
136*8a978a17SVictor Perevertkin                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
137*8a978a17SVictor Perevertkin                 "Commit pipe failed  %!STATUS!", status);
138*8a978a17SVictor Perevertkin             goto Done;
139*8a978a17SVictor Perevertkin         }
140*8a978a17SVictor Perevertkin     }
141*8a978a17SVictor Perevertkin 
142*8a978a17SVictor Perevertkin     if (IsInterfaceConfigured()) {
143*8a978a17SVictor Perevertkin         //
144*8a978a17SVictor Perevertkin         // Delete the old pipes
145*8a978a17SVictor Perevertkin         //
146*8a978a17SVictor Perevertkin         m_UsbDevice->CleanupInterfacePipesAndDelete(this);
147*8a978a17SVictor Perevertkin     }
148*8a978a17SVictor Perevertkin 
149*8a978a17SVictor Perevertkin     SetNumConfiguredPipes(NumPipes);
150*8a978a17SVictor Perevertkin     SetConfiguredPipes(ppPipes);
151*8a978a17SVictor Perevertkin 
152*8a978a17SVictor Perevertkin     for (iPipe = 0; iPipe < m_NumberOfConfiguredPipes ; iPipe++) {
153*8a978a17SVictor Perevertkin         RtlZeroMemory(&urb, sizeof(UMURB));
154*8a978a17SVictor Perevertkin 
155*8a978a17SVictor Perevertkin         urb.UmUrbQueryPipe.Hdr.InterfaceHandle = m_WinUsbHandle;
156*8a978a17SVictor Perevertkin         urb.UmUrbQueryPipe.Hdr.Function = UMURB_FUNCTION_QUERY_PIPE;
157*8a978a17SVictor Perevertkin         urb.UmUrbQueryPipe.Hdr.Length = sizeof(_UMURB_QUERY_PIPE);
158*8a978a17SVictor Perevertkin 
159*8a978a17SVictor Perevertkin         urb.UmUrbQueryPipe.AlternateSetting = m_CurAlternateSetting;
160*8a978a17SVictor Perevertkin         urb.UmUrbQueryPipe.PipeID = iPipe;
161*8a978a17SVictor Perevertkin 
162*8a978a17SVictor Perevertkin         status = m_UsbDevice->SendSyncUmUrb(&urb, 2);
163*8a978a17SVictor Perevertkin 
164*8a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
165*8a978a17SVictor Perevertkin             DoTraceLevelMessage(
166*8a978a17SVictor Perevertkin                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
167*8a978a17SVictor Perevertkin                 "Send UMURB_FUNCTION_QUERY_PIPE failed  %!STATUS!", status);
168*8a978a17SVictor Perevertkin             goto Done;
169*8a978a17SVictor Perevertkin         }
170*8a978a17SVictor Perevertkin 
171*8a978a17SVictor Perevertkin         m_ConfiguredPipes[iPipe]->InitPipe(&urb.UmUrbQueryPipe.PipeInformation,
172*8a978a17SVictor Perevertkin                                            m_InterfaceNumber,
173*8a978a17SVictor Perevertkin                                            this);
174*8a978a17SVictor Perevertkin     }
175*8a978a17SVictor Perevertkin 
176*8a978a17SVictor Perevertkin Done:
177*8a978a17SVictor Perevertkin     if (!NT_SUCCESS(status)) {
178*8a978a17SVictor Perevertkin         if (ppPipes != NULL) {
179*8a978a17SVictor Perevertkin             ASSERT(ppPipes != m_ConfiguredPipes);
180*8a978a17SVictor Perevertkin 
181*8a978a17SVictor Perevertkin             for (iPipe = 0; iPipe < NumPipes; iPipe++) {
182*8a978a17SVictor Perevertkin                 if (ppPipes[iPipe] != NULL) {
183*8a978a17SVictor Perevertkin                     ppPipes[iPipe]->DeleteFromFailedCreate();
184*8a978a17SVictor Perevertkin                 }
185*8a978a17SVictor Perevertkin             }
186*8a978a17SVictor Perevertkin 
187*8a978a17SVictor Perevertkin             FxPoolFree(ppPipes);
188*8a978a17SVictor Perevertkin             ppPipes = NULL;
189*8a978a17SVictor Perevertkin         }
190*8a978a17SVictor Perevertkin     }
191*8a978a17SVictor Perevertkin 
192*8a978a17SVictor Perevertkin     return status;
193*8a978a17SVictor Perevertkin }
194*8a978a17SVictor Perevertkin 
195*8a978a17SVictor Perevertkin NTSTATUS
UpdatePipeAttributes(__in PWDF_OBJECT_ATTRIBUTES PipesAttributes)196*8a978a17SVictor Perevertkin FxUsbInterface::UpdatePipeAttributes(
197*8a978a17SVictor Perevertkin     __in PWDF_OBJECT_ATTRIBUTES PipesAttributes
198*8a978a17SVictor Perevertkin     )
199*8a978a17SVictor Perevertkin {
200*8a978a17SVictor Perevertkin     NTSTATUS status = STATUS_SUCCESS;
201*8a978a17SVictor Perevertkin     UCHAR iPipe;
202*8a978a17SVictor Perevertkin     FxUsbPipe** ppPipes;
203*8a978a17SVictor Perevertkin     UCHAR numberOfPipes;
204*8a978a17SVictor Perevertkin 
205*8a978a17SVictor Perevertkin     numberOfPipes = m_NumberOfConfiguredPipes;
206*8a978a17SVictor Perevertkin     ppPipes = m_ConfiguredPipes;
207*8a978a17SVictor Perevertkin 
208*8a978a17SVictor Perevertkin     for (iPipe = 0; iPipe < numberOfPipes; iPipe++) {
209*8a978a17SVictor Perevertkin         status = FxObjectAllocateContext(ppPipes[iPipe],
210*8a978a17SVictor Perevertkin                                          PipesAttributes,
211*8a978a17SVictor Perevertkin                                          TRUE,
212*8a978a17SVictor Perevertkin                                          NULL);
213*8a978a17SVictor Perevertkin         if (!NT_SUCCESS(status)) {
214*8a978a17SVictor Perevertkin             DoTraceLevelMessage(
215*8a978a17SVictor Perevertkin                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET,
216*8a978a17SVictor Perevertkin                 "UpdatePipeAttributes failed  %!STATUS!", status);
217*8a978a17SVictor Perevertkin             break;
218*8a978a17SVictor Perevertkin         }
219*8a978a17SVictor Perevertkin     }
220*8a978a17SVictor Perevertkin 
221*8a978a17SVictor Perevertkin     //
222*8a978a17SVictor Perevertkin     // Pipe attributes are updated as part of select
223*8a978a17SVictor Perevertkin     // config and it is ok for the client driver to configure
224*8a978a17SVictor Perevertkin     // twice with the same attributes. In a similar scenario,
225*8a978a17SVictor Perevertkin     // KMDF will return STATUS_SUCCESS, so we should do the
226*8a978a17SVictor Perevertkin     // same for UMDF for consistency
227*8a978a17SVictor Perevertkin     //
228*8a978a17SVictor Perevertkin     if (status == STATUS_OBJECT_NAME_EXISTS) {
229*8a978a17SVictor Perevertkin         status = STATUS_SUCCESS;
230*8a978a17SVictor Perevertkin     }
231*8a978a17SVictor Perevertkin 
232*8a978a17SVictor Perevertkin     return status;
233*8a978a17SVictor Perevertkin }
234*8a978a17SVictor Perevertkin 
235