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