1 // 2 // Copyright (C) Microsoft. All rights reserved. 3 // 4 #include "fxusbpch.hpp" 5 6 extern "C" { 7 #include "FxUsbPipeUm.tmh" 8 } 9 10 #include "Fxglobals.h" 11 12 VOID 13 FxUsbPipeRequestContext::SetInfo( 14 __in WDF_USB_REQUEST_TYPE Type, 15 __in WINUSB_INTERFACE_HANDLE WinUsbHandle, 16 __in UCHAR PipeId, 17 __in USHORT Function 18 ) 19 { 20 RtlZeroMemory(&m_UmUrb, sizeof(m_UmUrb)); 21 22 m_UmUrb.UmUrbPipeRequest.Hdr.InterfaceHandle = WinUsbHandle; 23 m_UmUrb.UmUrbPipeRequest.Hdr.Function = Function; 24 m_UmUrb.UmUrbPipeRequest.Hdr.Length = sizeof(m_UmUrb.UmUrbPipeRequest); 25 26 m_UmUrb.UmUrbPipeRequest.PipeID = PipeId; 27 28 SetUsbType(Type); 29 } 30 31 VOID 32 FxUsbPipeTransferContext::StoreAndReferenceMemory( 33 __in FxRequestBuffer* Buffer 34 ) 35 /*++ 36 37 Routine Description: 38 virtual function which stores and references memory if it is an FxObject 39 and then fills in the appropriate fields in the URB. 40 41 Arguments: 42 Buffer - union which can be many types of memory 43 44 Return Value: 45 None 46 47 --*/ 48 { 49 RtlZeroMemory(&m_UmUrb, sizeof(m_UmUrb)); 50 51 m_UmUrb.UmUrbHeader.Function = UMURB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; 52 m_UmUrb.UmUrbHeader.Length = sizeof(_UMURB_BULK_OR_INTERRUPT_TRANSFER); 53 54 FxUsbRequestContext::StoreAndReferenceMemory(Buffer); // __super call 55 56 Buffer->AssignValues(&m_UmUrb.UmUrbBulkOrInterruptTransfer.TransferBuffer, 57 NULL, 58 &m_UmUrb.UmUrbBulkOrInterruptTransfer.TransferBufferLength); 59 } 60 61 VOID 62 FxUsbPipeContinuousReader::_ReadWorkItem( 63 __in MdDeviceObject /*DeviceObject*/, 64 __in_opt PVOID Context 65 ) 66 { 67 FxUsbPipeRepeatReader * pRepeater; 68 pRepeater = (FxUsbPipeRepeatReader *)Context; 69 70 pRepeater->RequestIrp->Forward(); 71 } 72 73 _Must_inspect_result_ 74 NTSTATUS 75 FxUsbPipeContinuousReader::Config( 76 __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, 77 __in size_t TotalBufferLength 78 ) 79 { 80 PFX_DRIVER_GLOBALS pFxDriverGlobals; 81 WDF_OBJECT_ATTRIBUTES attributes; 82 NTSTATUS status; 83 LONG i; 84 85 pFxDriverGlobals = m_Pipe->GetDriverGlobals(); 86 87 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 88 if (TotalBufferLength <= MAXUSHORT) { 89 m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) 90 FxNPagedLookasideList(pFxDriverGlobals, pFxDriverGlobals->Tag); 91 } 92 else { 93 m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) 94 FxNPagedLookasideListFromPool(pFxDriverGlobals, pFxDriverGlobals->Tag); 95 } 96 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 97 m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) 98 FxNPagedLookasideList(pFxDriverGlobals, pFxDriverGlobals->Tag); 99 #endif 100 101 if (m_Lookaside == NULL) { 102 return STATUS_INSUFFICIENT_RESOURCES; 103 } 104 105 if (Config->BufferAttributes == NULL) { 106 WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 107 } 108 else { 109 RtlCopyMemory(&attributes, 110 Config->BufferAttributes, 111 sizeof(WDF_OBJECT_ATTRIBUTES)); 112 } 113 114 // 115 // By specifying the loookaside as the parent for the memory objects that 116 // will be created, when we destroy the lookaside list, we will destroy any 117 // outstanding memory objects that have been allocated. This can happen if 118 // we initialize the repeater, but never send any i/o. (Normally the 119 // memory object would be freed when the read completes.) 120 // 121 attributes.ParentObject = m_Lookaside->GetObjectHandle(); 122 123 status = m_Lookaside->Initialize(TotalBufferLength, &attributes); 124 if (!NT_SUCCESS(status)) { 125 return status; 126 } 127 128 status = FxSystemWorkItem::_Create(pFxDriverGlobals, 129 m_Pipe->m_Device->GetDeviceObject(), 130 &m_WorkItem 131 ); 132 if (!NT_SUCCESS(status)) { 133 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 134 "Could not allocate workitem: %!STATUS!", status); 135 return status; 136 } 137 138 m_Offsets.BufferLength = Config->TransferLength; 139 m_Offsets.BufferOffset = Config->HeaderLength; 140 141 for (i = 0; i < m_NumReaders; i++) { 142 FxUsbPipeRepeatReader* pRepeater; 143 144 pRepeater = &m_Readers[i]; 145 146 pRepeater->Parent = this; 147 148 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 149 KeInitializeDpc(&pRepeater->Dpc, _FxUsbPipeContinuousReadDpc, NULL); 150 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 151 pRepeater->m_ReadWorkItem.Allocate(m_Pipe->m_Device->GetDeviceObject()); 152 #endif 153 154 // 155 // This will allocate the PIRP 156 // 157 status = FxRequest::_Create(pFxDriverGlobals, 158 WDF_NO_OBJECT_ATTRIBUTES, 159 NULL, 160 m_Pipe, 161 FxRequestOwnsIrp, 162 FxRequestConstructorCallerIsFx, 163 &pRepeater->Request); 164 165 if (!NT_SUCCESS(status)) { 166 return status; 167 } 168 169 pRepeater->RequestIrp = pRepeater->Request->GetSubmitIrp(); 170 171 // 172 // Initialize the event before FormatRepeater clears it 173 // 174 status = pRepeater->ReadCompletedEvent.Initialize(NotificationEvent, TRUE); 175 176 if (!NT_SUCCESS(status)) { 177 DoTraceLevelMessage( 178 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 179 "Could not initialize ReadCompletedEvent: %!STATUS!", 180 status); 181 182 return status; 183 } 184 185 // 186 // This will allocate the context 187 // 188 status = FormatRepeater(pRepeater); 189 190 if (!NT_SUCCESS(status)) { 191 return status; 192 } 193 } 194 195 return STATUS_SUCCESS; 196 } 197 198 VOID 199 FxUsbPipe::InitPipe( 200 __in PWINUSB_PIPE_INFORMATION PipeInfo, 201 __in UCHAR InterfaceNumber, 202 __in FxUsbInterface* UsbInterface 203 ) 204 { 205 RtlCopyMemory(&m_PipeInformationUm, PipeInfo, sizeof(m_PipeInformationUm)); 206 m_InterfaceNumber = InterfaceNumber; 207 208 if (m_UsbInterface != NULL) { 209 m_UsbInterface->RELEASE(this); 210 m_UsbInterface = NULL; 211 } 212 213 m_UsbInterface = UsbInterface; 214 m_UsbInterface->ADDREF(this); 215 } 216 217 _Must_inspect_result_ 218 NTSTATUS 219 FxUsbPipe::FormatTransferRequest( 220 __in FxRequestBase* Request, 221 __in FxRequestBuffer* Buffer, 222 __in ULONG TransferFlags 223 ) 224 { 225 FxUsbPipeTransferContext* pContext; 226 NTSTATUS status; 227 size_t bufferSize; 228 ULONG dummyLength; 229 230 // 231 // Make sure request is for the right type 232 // 233 if (!(IsType(WdfUsbPipeTypeBulk) || IsType(WdfUsbPipeTypeInterrupt))) { 234 status = STATUS_INVALID_DEVICE_REQUEST; 235 236 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 237 "WDFUSBPIPE %p not the right type, %!STATUS!", 238 GetHandle(), status); 239 240 return status; 241 } 242 243 bufferSize = Buffer->GetBufferLength(); 244 245 status = RtlSizeTToULong(bufferSize, &dummyLength); 246 if (!NT_SUCCESS(status)) { 247 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 248 "WDFUSBPIPE %p, buffer size truncated, %!STATUS!", 249 GetHandle(), status); 250 return status; 251 } 252 253 // 254 // On reads, check to make sure the read in value is an integral number of 255 // packet sizes 256 // 257 if (TransferFlags & USBD_TRANSFER_DIRECTION_IN) { 258 if (IsInEndpoint() == FALSE) { 259 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 260 "Pipe %p, sending __in transaction on a __out endpoint", 261 this); 262 263 return STATUS_INVALID_DEVICE_REQUEST; 264 } 265 266 if (m_CheckPacketSize && 267 (bufferSize % m_PipeInformationUm.MaximumPacketSize) != 0) { 268 return STATUS_INVALID_BUFFER_SIZE; 269 } 270 } 271 else { 272 if (IsOutEndpoint() == FALSE) { 273 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 274 "Pipe %p, sending __out transaction on an __in endpoint", 275 this); 276 277 return STATUS_INVALID_DEVICE_REQUEST; 278 } 279 } 280 281 status = Request->ValidateTarget(this); 282 if (!NT_SUCCESS(status)) { 283 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 284 "Pipe %p, Request %p, setting target failed, " 285 "status %!STATUS!", this, Request, status); 286 287 return status; 288 } 289 290 if (Request->HasContextType(FX_RCT_USB_PIPE_XFER)) { 291 pContext = (FxUsbPipeTransferContext*) Request->GetContext(); 292 } 293 else { 294 pContext = new(GetDriverGlobals()) FxUsbPipeTransferContext(FxUrbTypeLegacy); 295 if (pContext == NULL) { 296 return STATUS_INSUFFICIENT_RESOURCES; 297 } 298 299 Request->SetContext(pContext); 300 } 301 302 pContext->StoreAndReferenceMemory(Buffer); 303 304 pContext->m_UmUrb.UmUrbHeader.InterfaceHandle = m_UsbInterface->m_WinUsbHandle; 305 306 pContext->m_UmUrb.UmUrbBulkOrInterruptTransfer.PipeID = m_PipeInformationUm.PipeId; 307 pContext->m_UmUrb.UmUrbBulkOrInterruptTransfer.InPipe = IsInEndpoint(); 308 309 FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_UsbDevice->m_pHostTargetFile); 310 311 return STATUS_SUCCESS; 312 } 313 314 VOID 315 FxUsbPipe::GetInformation( 316 __out PWDF_USB_PIPE_INFORMATION PipeInformation 317 ) 318 { 319 320 321 322 323 PipeInformation->MaximumPacketSize = m_PipeInformationUm.MaximumPacketSize; 324 PipeInformation->EndpointAddress = m_PipeInformationUm.PipeId; 325 PipeInformation->Interval = m_PipeInformationUm.Interval; 326 PipeInformation->PipeType = _UsbdPipeTypeToWdf(m_PipeInformationUm.PipeType); 327 PipeInformation->SettingIndex = m_UsbInterface->GetConfiguredSettingIndex(); 328 } 329 330 WDF_USB_PIPE_TYPE 331 FxUsbPipe::GetType( 332 VOID 333 ) 334 { 335 return _UsbdPipeTypeToWdf(m_PipeInformationUm.PipeType); 336 } 337 338 BOOLEAN 339 FxUsbPipe::IsType( 340 __in WDF_USB_PIPE_TYPE Type 341 ) 342 { 343 return _UsbdPipeTypeToWdf(m_PipeInformationUm.PipeType) == Type ? TRUE : FALSE; 344 } 345 346