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 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 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 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