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