1 // 2 // Copyright (C) Microsoft. All rights reserved. 3 // 4 #include "fxusbpch.hpp" 5 6 extern "C" { 7 #include "FxUsbPipe.tmh" 8 } 9 10 #include "Fxglobals.h" 11 // 12 // NOTE: There are 3 different paths Requests could be sent to the lower driver 13 // 1) In case of reposting a successfully completed Request use the Dpc which calls SendIo. 14 // 2) For a failed completion use a workitem which works if the IoTarget is in Started state. 15 // 3) On moving to the start state the Repeater requests are inserted into the 16 // Iotargets Pended Queue directly. 17 // 18 // The function ResubmitRepeater calls SubmitLocked. If the action we get back 19 // from SubmitLocked is "SubmitSend", (SubmitQueued is treated as failure because 20 // of WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND flag) we are guaranteed to 21 // call IoCallDriver in the workitem or the DPC and hence the completion routine 22 // being called. 23 // This is very important because we increment the m_IoCount in SubmitLocked and 24 // decrement in the completion routine. So if there was a code path where 25 // SubmitLocked was called and IoCallDriver(hence the completion routine) wasn't, 26 // the IoTarget could stop responding in Dispose. 27 // 28 29 30 FxUsbPipeContinuousReader::FxUsbPipeContinuousReader( 31 __in FxUsbPipe* Pipe, 32 __in UCHAR NumReaders 33 ) : 34 m_NumReaders(NumReaders), 35 m_NumFailedReaders(0) 36 { 37 m_WorkItem = NULL; 38 m_WorkItemRerunContext = NULL; 39 m_WorkItemThread = NULL; 40 m_WorkItemFlags = 0; 41 m_WorkItemQueued = FALSE; 42 m_ReadersSubmitted = FALSE; 43 44 m_Lookaside = NULL; 45 m_Pipe = Pipe; 46 47 m_TargetDevice = m_Pipe->GetTargetDevice(); 48 49 RtlZeroMemory(&m_Readers[0], m_NumReaders * sizeof(FxUsbPipeRepeatReader)); 50 } 51 52 FxUsbPipeContinuousReader::~FxUsbPipeContinuousReader() 53 { 54 LONG i; 55 56 FxUsbPipeRepeatReader * reader = &m_Readers[0]; 57 58 // 59 // It is impoortant to delete the requests before the lookaside because the 60 // requests may have outstanding references on memory objects allocated by 61 // the lookaside. The lookaside will not be truly deleted until the oustanding 62 // memory object allocations are also freed. 63 // 64 for (i = 0; i < m_NumReaders; i++) { 65 if (reader[i].Request != NULL) { 66 DeleteMemory(reader[i].Request); 67 68 reader[i].Request->DeleteObject(); 69 reader[i].Request = NULL; 70 } 71 72 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 73 reader[i].ReadCompletedEvent.Uninitialize(); 74 reader[i].m_ReadWorkItem.Free(); 75 #endif 76 } 77 78 if (m_Lookaside != NULL) { 79 m_Lookaside->DeleteObject(); 80 } 81 82 if (m_WorkItem != NULL) { 83 m_WorkItem->DeleteObject(); 84 m_WorkItem = NULL; 85 } 86 } 87 88 BOOLEAN 89 FxUsbPipeContinuousReader::QueueWorkItemLocked( 90 __in FxUsbPipeRepeatReader* Repeater 91 ) 92 { 93 BOOLEAN queued; 94 PFX_DRIVER_GLOBALS fxDriverGlobals; 95 96 queued = FALSE; 97 fxDriverGlobals = m_Pipe->GetDriverGlobals(); 98 99 if (m_Pipe->m_State == WdfIoTargetStarted && m_WorkItemQueued == FALSE) { 100 // 101 // No item queued, queue it up now. 102 // 103 DoTraceLevelMessage( 104 fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 105 "WDFUSBPIPE %p continuous reader queueing work item to recover " 106 "from failed allocation", m_Pipe->GetHandle()); 107 108 if (m_WorkItem->Enqueue(_FxUsbPipeRequestWorkItemThunk, Repeater)) { 109 m_WorkItemQueued = TRUE; 110 queued = TRUE; 111 } 112 else { 113 DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 114 "Could not Queue workitem"); 115 } 116 } 117 118 // 119 // We only want to queue the work item while the target is in the 120 // started state. If it is not started, then we are no longer sending 121 // i/o and we should not queue the work item to try to restart. 122 // 123 if (FALSE == queued) { 124 DoTraceLevelMessage( 125 fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 126 "WDFUSBPIPE %p continuous reader not queueing work item," 127 "WorkItemQueued = %d, target state %!WDF_IO_TARGET_STATE!", 128 m_Pipe->GetHandle(), m_WorkItemQueued, m_Pipe->m_State); 129 } 130 131 return queued; 132 } 133 134 ULONG 135 FxUsbPipeContinuousReader::ResubmitRepeater( 136 __in FxUsbPipeRepeatReader* Repeater, 137 __out NTSTATUS* Status 138 ) 139 { 140 PFX_DRIVER_GLOBALS pFxDriverGlobals; 141 NTSTATUS status; 142 ULONG action; 143 KIRQL irql; 144 145 action = 0; 146 pFxDriverGlobals = m_Pipe->GetDriverGlobals(); 147 status = STATUS_UNSUCCESSFUL; 148 149 // 150 // Reformat and allocate any new needed buffers 151 // 152 status = FormatRepeater(Repeater); 153 154 m_Pipe->Lock(&irql); 155 156 // 157 // Do not re-submit repeaters if there is a queued/running work-item to 158 // reset pipe. Work-item will restart this repeater later. 159 // This check needs to be done after the FormatRepeater() call above to 160 // prevent a race condition where we are not detecting when the repeater 161 // is cancelled. 162 // 163 if (m_WorkItemQueued) { 164 // 165 // Return an error and no action flags to let the caller know that 166 // this request was not sent. 167 // 168 status = STATUS_CANCELLED; 169 170 DoTraceLevelMessage( 171 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 172 "WDFUSBPIPE %p is being reset, continuous reader %p FxRequest %p" 173 " PIRP %p is deferred for later.", 174 m_Pipe->GetHandle(), Repeater, Repeater->Request, 175 Repeater->RequestIrp); 176 } 177 else if (NT_SUCCESS(status)) { 178 // 179 // Get ready to re-submit the repeater. 180 // 181 action = m_Pipe->SubmitLocked( 182 Repeater->Request, 183 NULL, 184 WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND 185 ); 186 187 if (action & SubmitSend) { 188 // 189 // Clear the event only if we are going to send the request 190 // 191 Repeater->ReadCompletedEvent.Clear(); 192 } 193 else if (action & SubmitQueued) { 194 // 195 // Request got canceled asynchronously. The other thread is now 196 // responsible for calling its completion callback. 197 // 198 status = STATUS_CANCELLED; 199 } 200 else { 201 // 202 // Submit failed (which is expected when we are changing the target 203 // state or when the request is canceled). It should always be an 204 // error. 205 // 206 status = Repeater->Request->GetFxIrp()->GetStatus(); 207 ASSERT(!NT_SUCCESS(status)); 208 } 209 } 210 else { 211 // 212 // Could not allocate a new buffer 213 // 214 Repeater->Request->GetFxIrp()->SetStatus(status); 215 216 DoTraceLevelMessage( 217 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 218 "WDFUSBPIPE %p continuous reader, format failed, %!STATUS!, " 219 "repeater %p", m_Pipe->GetHandle(), status, Repeater); 220 221 if (m_Pipe->m_State == WdfIoTargetStarted) { 222 m_NumFailedReaders++; 223 ASSERT(m_NumFailedReaders <= m_NumReaders); 224 225 if (m_NumFailedReaders == m_NumReaders) { 226 // 227 // Queue a work item to clear problem. 228 // 229 QueueWorkItemLocked(Repeater); 230 } 231 else { 232 DoTraceLevelMessage( 233 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 234 "WDFUSBPIPE %p continuous reader, buffer alloc failed, but " 235 "there are %d readers left out of a max of %d", 236 m_Pipe->GetHandle(), m_NumReaders - m_NumFailedReaders, 237 m_NumReaders); 238 239 // 240 // There are still other pending readers, just use those for 241 // now. 242 // 243 DO_NOTHING(); 244 } 245 } 246 else { 247 DoTraceLevelMessage( 248 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 249 "WDFUSBPIPE %p continuous reader, buffer alloc failed, but not " 250 "in started state", m_Pipe->GetHandle()); 251 } 252 } 253 254 m_Pipe->Unlock(irql); 255 256 *Status = status; 257 258 return action; 259 } 260 261 VOID 262 FxUsbPipeContinuousReader::_FxUsbPipeRequestComplete( 263 __in WDFREQUEST Request, 264 __in WDFIOTARGET Target, 265 __in PWDF_REQUEST_COMPLETION_PARAMS Params, 266 __in WDFCONTEXT Context 267 ) 268 { 269 FxUsbPipeRepeatReader* pRepeater; 270 FxUsbPipeContinuousReader* pThis; 271 FxUsbPipe* pPipe; 272 NTSTATUS status; 273 ULONG action; 274 BOOLEAN readCompletedEventSet; 275 276 UNREFERENCED_PARAMETER(Request); 277 UNREFERENCED_PARAMETER(Params); 278 279 readCompletedEventSet = FALSE; 280 action = 0; 281 pRepeater = (FxUsbPipeRepeatReader*) Context; 282 pThis = (FxUsbPipeContinuousReader*) pRepeater->Parent; 283 pPipe = pThis->m_Pipe; 284 285 status = pRepeater->Request->GetFxIrp()->GetStatus(); 286 287 if (NT_SUCCESS(status)) { 288 PWDF_USB_REQUEST_COMPLETION_PARAMS params; 289 290 params = pRepeater->Request->GetContext()-> 291 m_CompletionParams.Parameters.Usb.Completion; 292 293 pThis->m_ReadCompleteCallback((WDFUSBPIPE) Target, 294 params->Parameters.PipeRead.Buffer, 295 params->Parameters.PipeRead.Length, 296 pThis->m_ReadCompleteContext); 297 298 // 299 // This will release the reference on the read memory and allocate a new 300 // one 301 // 302 action = pThis->ResubmitRepeater(pRepeater, &status); 303 } 304 else if (status != STATUS_CANCELLED) { 305 KIRQL irql; 306 307 DoTraceLevelMessage( 308 pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 309 "WDFUSBPIPE %p continuous reader FxRequest %p PIRP %p returned with " 310 "%!STATUS!", pPipe->GetHandle(), pRepeater->Request , 311 pRepeater->RequestIrp, status); 312 313 314 pPipe->Lock(&irql); 315 316 pRepeater->ReadCompletedEvent.Set(); 317 readCompletedEventSet = TRUE; 318 319 // 320 // Queue a work item to clear problem. 321 // 322 pThis->QueueWorkItemLocked(pRepeater); 323 324 pPipe->Unlock(irql); 325 326 ASSERT(!NT_SUCCESS(status)); 327 } 328 else { 329 // 330 // I/O was cancelled, which means internally it was cancelled so don't 331 // do anything. 332 // 333 DoTraceLevelMessage( 334 pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 335 "WDFUSBPIPE %p continuous reader %p FxRequest %p PIRP %p canceled", 336 pPipe->GetHandle(), pRepeater, pRepeater->Request , pRepeater->RequestIrp); 337 338 DO_NOTHING(); 339 } 340 341 if (action & SubmitSend) { 342 343 // 344 // We don't want to recurse on the same stack and overflow it. 345 // This is especially true if the device is pushing a lot of data and 346 // usb is completing everything within its dpc as soon as we send the 347 // read down. Eventually on a chk build, we will be nailed for running 348 // in one DPC for too long. 349 // 350 // As a slower alternative, we could queue a work item and resubmit the 351 // read from there. 352 // 353 354 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 355 BOOLEAN result; 356 result = KeInsertQueueDpc(&pRepeater->Dpc, NULL, NULL); 357 358 // 359 // The DPC should never be currently queued when we try to queue it. 360 // 361 ASSERT(result != FALSE); 362 #else 363 pRepeater->m_ReadWorkItem.Enqueue((PMX_WORKITEM_ROUTINE)_ReadWorkItem, pRepeater); 364 #endif 365 UNREFERENCED_PARAMETER(status); //for fre build 366 367 } 368 else if (action & SubmitQueued) { 369 // 370 // I/O got canceled asynchronously; the other thread is now 371 // responsible for re-invoking this completion routine. 372 // 373 ASSERT(STATUS_CANCELLED == status); 374 375 DoTraceLevelMessage( 376 pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 377 "WDFUSBPIPE %p continuous reader %p FxRequest %p PIRP %p got" 378 " asynchronously canceled", 379 pPipe->GetHandle(), pRepeater, pRepeater->Request , 380 pRepeater->RequestIrp); 381 382 DO_NOTHING(); 383 } 384 else if (FALSE == readCompletedEventSet) { 385 ASSERT(!NT_SUCCESS(status)); 386 // 387 // We are not sending the request and it is not queued so signal that 388 // it is done. 389 // 390 pRepeater->ReadCompletedEvent.Set(); 391 } 392 } 393 394 VOID 395 FxUsbPipeContinuousReader::FxUsbPipeRequestWorkItemHandler( 396 __in FxUsbPipeRepeatReader* FailedRepeater 397 ) 398 { 399 FxUsbDevice* pDevice; 400 NTSTATUS status, failedStatus; 401 USBD_STATUS usbdStatus; 402 LONG i; 403 KIRQL irql; 404 BOOLEAN restart; 405 FxRequestContext* context; 406 PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; 407 PFX_DRIVER_GLOBALS pFxDriverGlobals; 408 409 pFxDriverGlobals = m_Pipe->GetDriverGlobals(); 410 411 // 412 // Get failed info. 413 // 414 failedStatus = FailedRepeater->Request->GetStatus(); 415 416 // 417 // Context is allocated at config time and gets reused so context 418 // will never be NULL. 419 // 420 context = FailedRepeater->Request->GetContext(); 421 usbCompletionParams = context->m_CompletionParams.Parameters.Usb.Completion; 422 423 // 424 // In case FormatRepeater fails to allocate memory usbCompletionParams 425 // pointer is not set. 426 // 427 // usbCompletionParams are part of the context and 428 // not really allocated at the time of every Format but 429 // the pointer gets cleared by request->Reuse and gets set again by 430 // context->SetUsbType. 431 // 432 // In FormatRepeater, context->SetUsbType is skipped 433 // if a memory failure occurs before this step. 434 // 435 // Hence retrieve usbdStatus only when usbCompletionParams is set. 436 // 437 if (usbCompletionParams) { 438 usbdStatus = usbCompletionParams->UsbdStatus; 439 } 440 else { 441 // 442 // Set usbdStatus to success as we didn't receive a failure from 443 // USB stack. 444 // 445 // This path is reached during memory allocation failure. In such 446 // case failedStatus would already be set appropriately. (usbdStatus 447 // and failedStatus are passed to m_ReadersFailedCallback below.) 448 // 449 usbdStatus = STATUS_SUCCESS; 450 } 451 452 // 453 // No read requests should be in progress when the framework calls the 454 // EvtUsbTargetPipeReadersFailed callback function. This is part of the 455 // contract so that the Driver doesn't need to bother with the 456 // Completion calllback while taking corrective action. 457 // 458 CancelRepeaters(); 459 pDevice = m_Pipe->m_UsbDevice; 460 461 if (m_ReadersFailedCallback != NULL) { 462 // 463 // Save the current thread object pointer. This value is 464 // used for not deadlocking when misbehaved drivers (< v1.9) call 465 // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback 466 // 467 ASSERT(NULL == m_WorkItemThread); 468 m_WorkItemThread = Mx::MxGetCurrentThread(); 469 470 restart = m_ReadersFailedCallback( 471 (WDFUSBPIPE) m_Pipe->GetHandle(), 472 failedStatus, 473 usbdStatus 474 ); 475 476 m_WorkItemThread = NULL; 477 } 478 else { 479 // 480 // By default, we restart the readers 481 // 482 restart = TRUE; 483 } 484 485 if (restart) { 486 status = pDevice->IsConnected(); 487 488 if (NT_SUCCESS(status)) { 489 490 // 491 // for v1.9 or higher use the error recovery procedure prescribed 492 // by the USB team. 493 // 494 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { 495 496 if (pDevice->IsEnabled()) { 497 // 498 // Reset the pipe if port status is enabled 499 // 500 m_Pipe->Reset(); 501 } 502 else { 503 // 504 // Reset the device if port status is disabled 505 // 506 status = pDevice->Reset(); 507 } 508 } 509 else { 510 // 511 // Reset the device if port status is disabled 512 // 513 status = pDevice->Reset(); 514 } 515 } 516 else { 517 // 518 // if port status is disconnected we would get back 519 // a !NT_SUCCESS. This would mean that we would not 520 // send the readers again and treat it like a failed reader. 521 // 522 DO_NOTHING(); 523 } 524 525 } 526 else { 527 // 528 // By setting status to !NT_SUCCESS, we will not send the readers 529 // again and treat it like a failed reader. 530 // 531 status = STATUS_UNSUCCESSFUL; 532 } 533 534 // 535 // Work item is no longer queued. We set this before resubmitting the 536 // repeaters so that if they all complete and fail, we will requeue the 537 // work item. 538 // 539 m_Pipe->Lock(&irql); 540 m_WorkItemQueued = FALSE; 541 m_Pipe->Unlock(irql); 542 543 if (NT_SUCCESS(status)) { 544 ULONG action; 545 546 // 547 // Reset the count to zero. This is safe since we stopped all the 548 // readers at the beginning of this function. 549 // 550 m_NumFailedReaders = 0; 551 552 // 553 // restart the readers 554 // 555 for (i = 0; i < m_NumReaders; i++) { 556 FxUsbPipeRepeatReader* pRepeater; 557 558 pRepeater = &m_Readers[i]; 559 560 action = ResubmitRepeater(pRepeater, &status); 561 562 if (action & SubmitSend) { 563 // 564 // Ignore the return value because once we have sent the 565 // request, we want all processing to be done in the 566 // completion routine. 567 // 568 (void) pRepeater->Request->GetSubmitFxIrp()->CallDriver(m_Pipe->m_TargetDevice); 569 } 570 } 571 } 572 } 573 574 VOID 575 FxUsbPipeContinuousReader::_FxUsbPipeRequestWorkItemThunk( 576 __in PVOID Context 577 ) 578 /* 579 Only one work-item can be in-progress at any given time and 580 only one additional work-item can be queued at any given time. 581 This logic and m_WorkItemQueued makes this happen. 582 */ 583 { 584 FxUsbPipeRepeatReader* pFailedRepeater; 585 FxUsbPipeContinuousReader* pThis; 586 FxUsbPipe* pPipe; 587 KIRQL irql; 588 BOOLEAN rerun, inprogress; 589 590 pFailedRepeater = (FxUsbPipeRepeatReader*) Context; 591 pThis = (FxUsbPipeContinuousReader*) pFailedRepeater->Parent; 592 pPipe = pThis->m_Pipe; 593 594 // 595 // Check if a work item is already in progress. 596 // 597 pPipe->Lock(&irql); 598 if (pThis->m_WorkItemFlags & FX_USB_WORKITEM_IN_PROGRESS) { 599 // 600 // Yes, just let the other thread re-run this logic. 601 // 602 inprogress = TRUE; 603 604 ASSERT((pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) == 0); 605 pThis->m_WorkItemFlags |= FX_USB_WORKITEM_RERUN; 606 607 ASSERT(NULL == pThis->m_WorkItemRerunContext); 608 pThis->m_WorkItemRerunContext = Context; 609 } 610 else { 611 // 612 // No, it not running. 613 // 614 inprogress = FALSE; 615 616 pThis->m_WorkItemFlags |= FX_USB_WORKITEM_IN_PROGRESS; 617 ASSERT((pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) == 0); 618 } 619 pPipe->Unlock(irql); 620 621 if (inprogress) { 622 return; 623 } 624 625 // 626 // OK, this thread is responsible for running the work item logic. 627 // 628 do { 629 // 630 // Cleanup and restart the repeters. 631 // 632 pThis->FxUsbPipeRequestWorkItemHandler(pFailedRepeater); 633 634 // 635 // Check if callback needs to be re-run. 636 // 637 pPipe->Lock(&irql); 638 if (pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) { 639 // 640 // Yes, a new work item was requested while it was already running. 641 // 642 rerun = TRUE; 643 644 pThis->m_WorkItemFlags &= ~FX_USB_WORKITEM_RERUN; 645 646 ASSERT(pThis->m_WorkItemRerunContext != NULL); 647 pFailedRepeater = (FxUsbPipeRepeatReader*)pThis->m_WorkItemRerunContext; 648 pThis->m_WorkItemRerunContext = NULL; 649 650 ASSERT(pThis == (FxUsbPipeContinuousReader*)pFailedRepeater->Parent); 651 } 652 else { 653 // 654 // No, all done. 655 // 656 rerun = FALSE; 657 658 ASSERT(pThis->m_WorkItemFlags & FX_USB_WORKITEM_IN_PROGRESS); 659 pThis->m_WorkItemFlags &= ~FX_USB_WORKITEM_IN_PROGRESS; 660 661 ASSERT(NULL == pThis->m_WorkItemRerunContext); 662 } 663 pPipe->Unlock(irql); 664 665 } 666 while (rerun); 667 } 668 669 PVOID 670 FxUsbPipeContinuousReader::operator new( 671 __in size_t Size, 672 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 673 __range(1, NUM_PENDING_READS_MAX) ULONG NumReaders 674 ) 675 { 676 ASSERT(NumReaders >= 1); 677 678 return FxPoolAllocate( 679 FxDriverGlobals, 680 NonPagedPool, 681 Size + (NumReaders-1) * sizeof(FxUsbPipeRepeatReader) 682 ); 683 } 684 685 _Must_inspect_result_ 686 NTSTATUS 687 FxUsbPipeContinuousReader::FormatRepeater( 688 __in FxUsbPipeRepeatReader* Repeater 689 ) 690 { 691 WDF_REQUEST_REUSE_PARAMS params; 692 FxRequestBuffer buf; 693 FxUsbPipeTransferContext* pContext; 694 FxMemoryObject* pMemory; 695 FxRequest* pRequest; 696 NTSTATUS status; 697 698 pRequest = Repeater->Request; 699 // 700 // The repeater owns the request memory. If there is a memory on the 701 // context, delete it now. the memory will still be referencable since 702 // it will still have a reference against it until FormatTransferRequest is 703 // called or the request is freed and the context releases its references 704 // 705 DeleteMemory(pRequest); 706 707 WDF_REQUEST_REUSE_PARAMS_INIT(¶ms, 0, STATUS_NOT_SUPPORTED); 708 709 pRequest->Reuse(¶ms); 710 711 // 712 // pMemory will be deleted when either 713 // a) The request completes 714 // or 715 // b) The continuous reader is destroyed and we delete the lookaside. since 716 // the lookaside is the parent object for pMemory, pMemory will be disposed 717 // of when the parent is Disposed 718 // 719 status = m_Lookaside->Allocate(&pMemory); 720 if (!NT_SUCCESS(status)) { 721 FxRequestContext* pContext; 722 723 pContext = pRequest->GetContext(); 724 if (pContext != NULL ) { 725 pContext->m_RequestMemory = NULL; 726 } 727 728 return STATUS_INSUFFICIENT_RESOURCES; 729 } 730 731 RtlZeroMemory(pMemory->GetBuffer(), pMemory->GetBufferSize()); 732 733 buf.SetMemory(pMemory, &m_Offsets); 734 735 status = m_Pipe->FormatTransferRequest( 736 pRequest, 737 &buf, 738 USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK 739 ); 740 741 if (!NT_SUCCESS(status)) { 742 // 743 // In the case of failure, the context in the request will delete the 744 // memory. If there is no context, delete the memory here. 745 // 746 if (pRequest->GetContext() == NULL) { 747 // 748 // Use DeleteFromFailedCreate because the driver never saw the 749 // buffer, so they shouldn't be told about it going away. 750 // 751 pMemory->DeleteFromFailedCreate(); 752 } 753 754 return status; 755 } 756 757 pContext = (FxUsbPipeTransferContext*) pRequest->GetContext(); 758 pContext->SetUsbType(WdfUsbRequestTypePipeRead); 759 pContext->m_UsbParameters.Parameters.PipeRead.Buffer = (WDFMEMORY) 760 pMemory->GetObjectHandle(); 761 762 pRequest->SetCompletionRoutine(_FxUsbPipeRequestComplete, Repeater); 763 return status; 764 } 765 766 767 VOID 768 FxUsbPipeContinuousReader::CancelRepeaters( 769 VOID 770 ) 771 { 772 LONG i; 773 774 Mx::MxEnterCriticalRegion(); 775 776 for (i = 0; i < m_NumReaders; i++) { 777 m_Readers[i].Request->Cancel(); 778 m_Pipe->GetDriverGlobals()->WaitForSignal( 779 m_Readers[i].ReadCompletedEvent.GetSelfPointer(), 780 "waiting for continuous reader to finish, WDFUSBPIPE", 781 m_Pipe->GetHandle(), 782 m_Pipe->GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, 783 WaitSignalBreakUnderVerifier); 784 785 } 786 787 Mx::MxLeaveCriticalRegion(); 788 // 789 // Checking for IO Count <= 1 is not a good idea here because there could be always other IO 790 // besides that from the continous reader going on the Read Pipe. 791 // 792 } 793 794 FxUsbPipeTransferContext::FxUsbPipeTransferContext( 795 __in FX_URB_TYPE FxUrbType 796 ) : 797 FxUsbRequestContext(FX_RCT_USB_PIPE_XFER) 798 { 799 m_UnlockPages = FALSE; 800 m_PartialMdl = NULL; 801 m_USBDHandle = NULL; 802 803 if (FxUrbType == FxUrbTypeLegacy) { 804 m_Urb = &m_UrbLegacy; 805 } 806 else { 807 m_Urb = NULL; 808 } 809 810 } 811 812 FxUsbPipeTransferContext::~FxUsbPipeTransferContext( 813 VOID 814 ) 815 { 816 if (m_Urb && (m_Urb != &m_UrbLegacy)) { 817 USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); 818 } 819 m_Urb = NULL; 820 m_USBDHandle = NULL; 821 } 822 823 __checkReturn 824 NTSTATUS 825 FxUsbPipeTransferContext::AllocateUrb( 826 __in USBD_HANDLE USBDHandle 827 ) 828 { 829 NTSTATUS status; 830 831 if (m_Urb) { 832 status = STATUS_INVALID_DEVICE_STATE; 833 goto Done; 834 } 835 836 status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); 837 838 if (!NT_SUCCESS(status)) { 839 goto Done; 840 } 841 842 m_USBDHandle = USBDHandle; 843 844 Done: 845 return status; 846 } 847 848 VOID 849 FxUsbPipeTransferContext::Dispose( 850 VOID 851 ) 852 { 853 if (m_Urb && (m_Urb != &m_UrbLegacy)){ 854 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); 855 m_Urb = NULL; 856 m_USBDHandle = NULL; 857 } 858 } 859 860 VOID 861 FxUsbPipeTransferContext::ReleaseAndRestore( 862 __in FxRequestBase* Request 863 ) 864 { 865 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 866 // 867 // Check now because Init will NULL out the field 868 // 869 if (m_PartialMdl != NULL) { 870 if (m_UnlockPages) { 871 MmUnlockPages(m_PartialMdl); 872 m_UnlockPages = FALSE; 873 } 874 875 FxMdlFree(Request->GetDriverGlobals(), m_PartialMdl); 876 m_PartialMdl = NULL; 877 } 878 #endif 879 FxUsbRequestContext::ReleaseAndRestore(Request); // __super call 880 } 881 882 VOID 883 FxUsbPipeTransferContext::CopyParameters( 884 __in FxRequestBase* Request 885 ) 886 { 887 m_CompletionParams.IoStatus.Information = GetUrbTransferLength(); 888 889 // 890 // If both are at the same offset, we don't have to compare type for 891 // Read or Write 892 // 893 WDFCASSERT(FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, 894 Parameters.PipeRead.Length) == 895 FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, 896 Parameters.PipeWrite.Length)); 897 898 m_UsbParameters.Parameters.PipeRead.Length = GetUrbTransferLength(); 899 FxUsbRequestContext::CopyParameters(Request); // __super call 900 } 901 902 VOID 903 FxUsbPipeTransferContext::SetUrbInfo( 904 __in USBD_PIPE_HANDLE PipeHandle, 905 __in ULONG TransferFlags 906 ) 907 { 908 m_Urb->TransferFlags = TransferFlags; 909 m_Urb->PipeHandle = PipeHandle; 910 } 911 912 USBD_STATUS 913 FxUsbPipeTransferContext::GetUsbdStatus( 914 VOID 915 ) 916 { 917 return m_Urb->Hdr.Status; 918 } 919 920 FxUsbUrbContext::FxUsbUrbContext( 921 VOID 922 ) : 923 FxUsbRequestContext(FX_RCT_USB_URB_REQUEST), 924 m_pUrb(NULL) 925 { 926 } 927 928 USBD_STATUS 929 FxUsbUrbContext::GetUsbdStatus( 930 VOID 931 ) 932 { 933 return m_pUrb == NULL ? 0 : m_pUrb->UrbHeader.Status; 934 } 935 936 VOID 937 FxUsbUrbContext::StoreAndReferenceMemory( 938 __in FxRequestBuffer* Buffer 939 ) 940 { 941 ULONG dummy; 942 943 FxUsbRequestContext::StoreAndReferenceMemory(Buffer); 944 945 // 946 // make sure it is framework managed memory or raw PVOID 947 // 948 ASSERT(Buffer->DataType == FxRequestBufferMemory || 949 Buffer->DataType == FxRequestBufferBuffer); 950 951 Buffer->AssignValues((PVOID*) &m_pUrb, NULL, &dummy); 952 } 953 954 VOID 955 FxUsbUrbContext::ReleaseAndRestore( 956 __in FxRequestBase* Request 957 ) 958 { 959 m_pUrb = NULL; 960 FxUsbRequestContext::ReleaseAndRestore(Request); // __super call 961 } 962 963 964 FxUsbPipeRequestContext::FxUsbPipeRequestContext( 965 __in FX_URB_TYPE FxUrbType 966 ) : 967 FxUsbRequestContext(FX_RCT_USB_PIPE_REQUEST) 968 { 969 m_USBDHandle = NULL; 970 971 if (FxUrbType == FxUrbTypeLegacy) { 972 m_Urb = &m_UrbLegacy; 973 } 974 else { 975 m_Urb = NULL; 976 } 977 } 978 979 FxUsbPipeRequestContext::~FxUsbPipeRequestContext( 980 VOID 981 ) 982 { 983 if (m_Urb && (m_Urb != &m_UrbLegacy)) { 984 USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); 985 } 986 m_Urb = NULL; 987 m_USBDHandle = NULL; 988 } 989 990 __checkReturn 991 NTSTATUS 992 FxUsbPipeRequestContext::AllocateUrb( 993 __in USBD_HANDLE USBDHandle 994 ) 995 { 996 NTSTATUS status; 997 998 if (m_Urb) { 999 status = STATUS_INVALID_DEVICE_STATE; 1000 goto Done; 1001 } 1002 1003 status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); 1004 1005 if (!NT_SUCCESS(status)) { 1006 goto Done; 1007 } 1008 1009 m_USBDHandle = USBDHandle; 1010 1011 Done: 1012 return status; 1013 } 1014 1015 VOID 1016 FxUsbPipeRequestContext::Dispose( 1017 VOID 1018 ) 1019 { 1020 if (m_Urb && (m_Urb != &m_UrbLegacy)){ 1021 USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); 1022 m_Urb = NULL; 1023 m_USBDHandle = NULL; 1024 } 1025 } 1026 1027 VOID 1028 FxUsbPipeRequestContext::SetInfo( 1029 __in WDF_USB_REQUEST_TYPE Type, 1030 __in USBD_PIPE_HANDLE PipeHandle, 1031 __in USHORT Function 1032 ) 1033 { 1034 RtlZeroMemory(m_Urb, sizeof(*m_Urb)); 1035 m_Urb->Hdr.Length = sizeof(*m_Urb); 1036 m_Urb->Hdr.Function = Function; 1037 m_Urb->PipeHandle = PipeHandle; 1038 1039 SetUsbType(Type); 1040 } 1041 1042 USBD_STATUS 1043 FxUsbPipeRequestContext::GetUsbdStatus( 1044 VOID 1045 ) 1046 { 1047 return m_Urb->Hdr.Status; 1048 } 1049 1050 FxUsbPipe::FxUsbPipe( 1051 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 1052 __in FxUsbDevice* UsbDevice 1053 ) : 1054 FxIoTarget(FxDriverGlobals, sizeof(FxUsbPipe), FX_TYPE_IO_TARGET_USB_PIPE), 1055 m_UsbDevice(UsbDevice) 1056 { 1057 InitializeListHead(&m_ListEntry); 1058 RtlZeroMemory(&m_PipeInformation, sizeof(m_PipeInformation)); 1059 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 1060 RtlZeroMemory(&m_PipeInformationUm, sizeof(m_PipeInformationUm)); 1061 #endif 1062 m_InterfaceNumber = 0; 1063 m_Reader = NULL; 1064 m_UsbInterface = NULL; 1065 m_CheckPacketSize = TRUE; 1066 m_USBDHandle = UsbDevice->m_USBDHandle; 1067 m_UrbType = UsbDevice->m_UrbType; 1068 1069 MarkNoDeleteDDI(ObjectDoNotLock); 1070 } 1071 1072 VOID 1073 FxUsbPipe::InitPipe( 1074 __in PUSBD_PIPE_INFORMATION PipeInfo, 1075 __in UCHAR InterfaceNumber, 1076 __in FxUsbInterface* UsbInterface 1077 ) 1078 { 1079 RtlCopyMemory(&m_PipeInformation, PipeInfo, sizeof(m_PipeInformation)); 1080 m_InterfaceNumber = InterfaceNumber; 1081 1082 if (m_UsbInterface != NULL) { 1083 m_UsbInterface->RELEASE(this); 1084 m_UsbInterface = NULL; 1085 } 1086 1087 m_UsbInterface = UsbInterface; 1088 m_UsbInterface->ADDREF(this); 1089 } 1090 1091 FxUsbPipe::~FxUsbPipe() 1092 { 1093 if (m_UsbInterface != NULL) { 1094 m_UsbInterface->RemoveDeletedPipe(this); 1095 m_UsbInterface->RELEASE(this); 1096 } 1097 1098 ASSERT(IsListEmpty(&m_ListEntry)); 1099 } 1100 1101 BOOLEAN 1102 FxUsbPipe::Dispose() 1103 { 1104 BOOLEAN callCleanup; 1105 1106 // 1107 // Call base class: callbacks, terminates I/Os, etc. 1108 // 1109 callCleanup = FxIoTarget::Dispose(); // __super call 1110 1111 // 1112 // Don't need the reader anymore. The reader is deleted after calling the 1113 // parent class Dispose() to preserve the existing deletion order (it was 1114 // deleted in the Pipe's dtor() before this change). 1115 // 1116 if (m_Reader != NULL) 1117 { 1118 delete m_Reader; 1119 1120 // 1121 // By doing this assignment we prevent misbehaved drivers 1122 // from crashing the system when they call WdfIoTargetStop from their 1123 // usb pipe's destroy callback. 1124 // 1125 m_Reader = NULL; 1126 } 1127 1128 return callCleanup; 1129 } 1130 1131 _Must_inspect_result_ 1132 NTSTATUS 1133 FxUsbPipe::GotoStartState( 1134 __in PLIST_ENTRY RequestListHead, 1135 __in BOOLEAN Lock 1136 ) 1137 { 1138 NTSTATUS status; 1139 LONG i; 1140 1141 if (m_Reader != NULL) { 1142 if (m_Reader->m_ReadersSubmitted == FALSE) { 1143 ASSERT(IsListEmpty(&m_SentIoListHead)); 1144 1145 for (i = 0; i < m_Reader->m_NumReaders; i++) { 1146 FxRequest* pRequest; 1147 1148 pRequest = m_Reader->m_Readers[i].Request; 1149 1150 UNREFERENCED_PARAMETER(pRequest); //for fre build 1151 ASSERT(IsListEmpty(&pRequest->m_ListEntry)); 1152 ASSERT(pRequest->m_DrainSingleEntry.Next == NULL); 1153 } 1154 } 1155 } 1156 1157 status = FxIoTarget::GotoStartState(RequestListHead, Lock); 1158 1159 if (m_Reader == NULL || !NT_SUCCESS(status)) { 1160 return status; 1161 } 1162 1163 // 1164 // Add the repeater requests to the list head so that they are sent by the 1165 // caller of this function when this function returns IFF they have not yet 1166 // been queued. (They can be queued on a start -> start transition.) 1167 // 1168 if (m_Reader->m_ReadersSubmitted == FALSE) { 1169 for (i = 0; i < m_Reader->m_NumReaders; i++) { 1170 // 1171 // This will clear ReadCompletedEvent as well 1172 // 1173 status = m_Reader->FormatRepeater(&m_Reader->m_Readers[i]); 1174 1175 if (!NT_SUCCESS(status)) { 1176 return status; 1177 } 1178 } 1179 1180 // 1181 // Reset the number of failed readers in case we had failure in a 1182 // previously started state. 1183 // 1184 m_Reader->m_NumFailedReaders = 0; 1185 1186 for (i = 0; i < m_Reader->m_NumReaders; i++) { 1187 FxRequest* pRequest; 1188 1189 pRequest = m_Reader->m_Readers[i].Request; 1190 pRequest->SetTarget(this); 1191 pRequest->ADDREF(this); 1192 1193 // 1194 // NOTE: This is an elusive backdoor to send the Request down 1195 // since it is inserted directly into the IoTargets pended list. 1196 // The IoTarget is not started so we add the request to the 1197 // pended list so that it is processed when the IoTarget starts. 1198 // 1199 m_Reader->m_Pipe->IncrementIoCount(); 1200 InsertTailList(RequestListHead, &pRequest->m_ListEntry); 1201 1202 // 1203 // Clear the event only when we know it will be submitted to the 1204 // target. It will be set when the request is submitted to the 1205 // target and the submit fails or if it is cancelled. 1206 // 1207 m_Reader->m_Readers[i].ReadCompletedEvent.Clear(); 1208 } 1209 1210 m_Reader->m_ReadersSubmitted = TRUE; 1211 } 1212 1213 return status; 1214 } 1215 1216 VOID 1217 FxUsbPipe::GotoStopState( 1218 __in WDF_IO_TARGET_SENT_IO_ACTION Action, 1219 __in PSINGLE_LIST_ENTRY SentRequestListHead, 1220 __out PBOOLEAN Wait, 1221 __in BOOLEAN LockSelf 1222 ) 1223 { 1224 KIRQL irql; 1225 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1226 1227 irql = PASSIVE_LEVEL; 1228 pFxDriverGlobals = GetDriverGlobals(); 1229 1230 if (LockSelf) { 1231 Lock(&irql); 1232 } 1233 1234 if (m_Reader != NULL) { 1235 // 1236 // If we are a continuous reader, always cancel the sent io so that we 1237 // can resubmit it later on a restart. 1238 // 1239 DoTraceLevelMessage( 1240 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 1241 "WDFUSBPIPE %p converting stop action %!WDF_IO_TARGET_SENT_IO_ACTION!" 1242 " to %!WDF_IO_TARGET_SENT_IO_ACTION!", GetHandle(), Action, 1243 WdfIoTargetCancelSentIo); 1244 1245 Action = WdfIoTargetCancelSentIo; 1246 } 1247 1248 FxIoTarget::GotoStopState(Action, SentRequestListHead, Wait, FALSE); // __super call 1249 1250 if (m_Reader != NULL) { 1251 // 1252 // The continuous reader requests are no longer enqueued. Remember that 1253 // state, so when we restart, we resend them. 1254 // 1255 m_Reader->m_ReadersSubmitted = FALSE; 1256 1257 // 1258 // Log a message when misbehaved drivers call WdfIoTargetStop 1259 // from EvtUsbTargetPipeReadersFailed callback. 1260 // 1261 if (m_Reader->m_WorkItemThread == Mx::MxGetCurrentThread()) { 1262 DoTraceLevelMessage( 1263 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1264 "WDFUSBPIPE %p is stopped from EvtUsbTargetPipeReadersFailed" 1265 " callback", GetHandle()); 1266 1267 if (pFxDriverGlobals->IsVerificationEnabled(1, 9, OkForDownLevel)) { 1268 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1269 } 1270 } 1271 1272 // 1273 // Do not deadlock when misbehaved drivers (< v1.9) call 1274 // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback. 1275 // 1276 if (m_Reader->m_WorkItemThread != Mx::MxGetCurrentThread() || 1277 pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { 1278 // 1279 // Make sure work item is done. It is possible for the upper class 1280 // to return wait = false if the list of sent requests is empty. We 1281 // still want to wait anyway for making sure work item is not about 1282 // to run or it is running. 1283 // 1284 *Wait = TRUE; 1285 } 1286 } 1287 1288 if (LockSelf) { 1289 Unlock(irql); 1290 } 1291 } 1292 1293 VOID 1294 FxUsbPipe::GotoPurgeState( 1295 __in WDF_IO_TARGET_PURGE_IO_ACTION Action, 1296 __in PLIST_ENTRY PendedRequestListHead, 1297 __in PSINGLE_LIST_ENTRY SentRequestListHead, 1298 __out PBOOLEAN Wait, 1299 __in BOOLEAN LockSelf 1300 ) 1301 { 1302 KIRQL irql; 1303 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1304 1305 irql = PASSIVE_LEVEL; 1306 pFxDriverGlobals = GetDriverGlobals(); 1307 1308 if (LockSelf) { 1309 Lock(&irql); 1310 } 1311 1312 if (m_Reader != NULL) { 1313 // 1314 // If we are a continuous reader, always wait for the sent io, so that we 1315 // can resubmit it later on a restart. 1316 // 1317 DoTraceLevelMessage( 1318 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, 1319 "WDFUSBPIPE %p converting purge action %!WDF_IO_TARGET_PURGE_IO_ACTION!" 1320 " to %!WDF_IO_TARGET_PURGE_IO_ACTION!", GetHandle(), Action, 1321 WdfIoTargetPurgeIoAndWait); 1322 1323 Action = WdfIoTargetPurgeIoAndWait; 1324 } 1325 1326 FxIoTarget::GotoPurgeState(Action, // __super call 1327 PendedRequestListHead, 1328 SentRequestListHead, 1329 Wait, 1330 FALSE); 1331 1332 if (m_Reader != NULL) { 1333 // 1334 // The continuous reader requests are no longer enqueued. Remember that 1335 // state, so when we restart, we resend them. 1336 // 1337 m_Reader->m_ReadersSubmitted = FALSE; 1338 1339 // 1340 // Log a message when misbehaved drivers call WdfIoTargetPurge 1341 // from EvtUsbTargetPipeReadersFailed callback. 1342 // 1343 if (m_Reader->m_WorkItemThread == Mx::MxGetCurrentThread()) { 1344 DoTraceLevelMessage( 1345 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1346 "WDFUSBPIPE %p is purged from EvtUsbTargetPipeReadersFailed" 1347 " callback", GetHandle()); 1348 1349 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1350 } 1351 1352 // 1353 // Make sure work item is done. It is possible for the upper class 1354 // to return wait = false if the list of sent requests is empty. We 1355 // still want to wait anyway for making sure work item is not about 1356 // to run or it is running. 1357 // 1358 *Wait = TRUE; 1359 } 1360 1361 if (LockSelf) { 1362 Unlock(irql); 1363 } 1364 } 1365 1366 VOID 1367 FxUsbPipe::GotoRemoveState( 1368 __in WDF_IO_TARGET_STATE NewState, 1369 __in PLIST_ENTRY PendedRequestListHead, 1370 __in PSINGLE_LIST_ENTRY SentRequestListHead, 1371 __in BOOLEAN LockSelf, 1372 __out PBOOLEAN Wait 1373 ) 1374 { 1375 KIRQL irql; 1376 1377 irql = PASSIVE_LEVEL; 1378 1379 if (LockSelf) { 1380 Lock(&irql); 1381 } 1382 1383 if (m_Reader != NULL && m_Reader->m_ReadersSubmitted && 1384 WdfIoTargetStarted == m_State) { 1385 // 1386 // Driver forgot to stop the pipe on D0Exit. 1387 // 1388 DoTraceLevelMessage( 1389 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1390 "WDFUSBPIPE %p was not stopped in EvtDeviceD0Exit callback", 1391 GetHandle()); 1392 1393 if (GetDriverGlobals()->IsVerificationEnabled(1,9,OkForDownLevel)) { 1394 FxVerifierDbgBreakPoint(GetDriverGlobals()); 1395 } 1396 } 1397 1398 FxIoTarget::GotoRemoveState(NewState, // __super call 1399 PendedRequestListHead, 1400 SentRequestListHead, 1401 FALSE, 1402 Wait); 1403 if (m_Reader != NULL) { 1404 // 1405 // Make sure work item is done. It is possible for the upper class to 1406 // return wait = false if the list of sent requests is empty. We still 1407 // want to wait anyway for making sure work item is not about to run or 1408 // it is running. 1409 // 1410 *Wait = TRUE; 1411 } 1412 1413 if (LockSelf) { 1414 Unlock(irql); 1415 } 1416 } 1417 1418 VOID 1419 FxUsbPipe::WaitForSentIoToComplete( 1420 VOID 1421 ) 1422 { 1423 if (m_Reader != NULL) { 1424 DoTraceLevelMessage( 1425 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1426 "WDFUSBPIPE %p, waiting for continuous reader work item to complete", 1427 GetHandle()); 1428 1429 // 1430 // First, wait for the work item to complete if it is running. 1431 // 1432 // NOTE: We don't wait for the DPC to complete because 1433 // they are flushed in FxUsbDevice::Dispose 1434 // 1435 m_Reader->m_WorkItem->WaitForExit(); 1436 1437 DoTraceLevelMessage( 1438 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1439 "WDFUSBPIPE %p, cancelling for continuous reader (max of %d)", 1440 GetHandle(), m_Reader->m_NumReaders); 1441 1442 // 1443 // Now that the work item is not running, make sure all the readers are 1444 // truly canceled and *NOT* in the pended queue. In between the call to 1445 // GotoStopState and here, the work item could have run and retried to 1446 // send the I/O. 1447 // 1448 m_Reader->CancelRepeaters(); 1449 } 1450 1451 DoTraceLevelMessage( 1452 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1453 "WDFUSBPIPE %p, waiting for all i/o to complete", GetHandle()); 1454 1455 // 1456 // Finally, let the parent class wait for all I/O to complete 1457 // 1458 FxIoTarget::WaitForSentIoToComplete(); // __super call 1459 } 1460 1461 _Must_inspect_result_ 1462 NTSTATUS 1463 FxUsbPipe::InitContinuousReader( 1464 __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, 1465 __in size_t TotalBufferLength 1466 ) 1467 { 1468 FxUsbPipeContinuousReader* pReader; 1469 NTSTATUS status; 1470 UCHAR numReaders; 1471 1472 pReader = NULL; 1473 1474 if (m_Reader != NULL) { 1475 status = STATUS_INVALID_DEVICE_STATE; 1476 1477 DoTraceLevelMessage( 1478 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1479 "Continuous reader already initialized on WDFUSBPIPE %p %!STATUS!", 1480 GetHandle(), status); 1481 1482 return status; 1483 } 1484 1485 numReaders = Config->NumPendingReads; 1486 1487 if (numReaders == 0) { 1488 numReaders = NUM_PENDING_READS_DEFAULT; 1489 } 1490 else if (numReaders > NUM_PENDING_READS_MAX) { 1491 numReaders = NUM_PENDING_READS_MAX; 1492 } 1493 1494 pReader = new(GetDriverGlobals(), numReaders) 1495 FxUsbPipeContinuousReader(this, numReaders); 1496 1497 if (pReader == NULL) { 1498 return STATUS_INSUFFICIENT_RESOURCES; 1499 } 1500 1501 // 1502 // Allocate all of the structurs and objects required 1503 // 1504 status = pReader->Config(Config, TotalBufferLength); 1505 1506 if (!NT_SUCCESS(status)) { 1507 delete pReader; 1508 return status; 1509 } 1510 1511 pReader->m_ReadCompleteCallback = Config->EvtUsbTargetPipeReadComplete; 1512 pReader->m_ReadCompleteContext = Config->EvtUsbTargetPipeReadCompleteContext; 1513 1514 pReader->m_ReadersFailedCallback = Config->EvtUsbTargetPipeReadersFailed; 1515 1516 if (InterlockedCompareExchangePointer((PVOID*) &m_Reader, 1517 pReader, 1518 NULL) == NULL) { 1519 // 1520 // We set the field, do nothing. 1521 // 1522 DO_NOTHING(); 1523 } 1524 else { 1525 // 1526 // Some other thread came in and set the field, free our allocation. 1527 // 1528 delete pReader; 1529 } 1530 1531 return STATUS_SUCCESS; 1532 } 1533 1534 _Must_inspect_result_ 1535 NTSTATUS 1536 FxUsbPipe::_FormatTransfer( 1537 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 1538 __in WDFUSBPIPE Pipe, 1539 __in WDFREQUEST Request, 1540 __in_opt WDFMEMORY TransferMemory, 1541 __in_opt PWDFMEMORY_OFFSET TransferOffsets, 1542 __in ULONG Flags 1543 ) 1544 { 1545 FxRequestBuffer buf; 1546 IFxMemory* pMemory; 1547 FxUsbPipe* pUsbPipe; 1548 FxRequest* pRequest; 1549 NTSTATUS status; 1550 1551 FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, 1552 Pipe, 1553 FX_TYPE_IO_TARGET_USB_PIPE, 1554 (PVOID*) &pUsbPipe, 1555 &FxDriverGlobals); 1556 1557 FxObjectHandleGetPtr(FxDriverGlobals, 1558 Request, 1559 FX_TYPE_REQUEST, 1560 (PVOID*) &pRequest); 1561 1562 // 1563 // We allow zero length transfers (which are indicated by TransferMemory == NULL) 1564 // 1565 if (TransferMemory != NULL) { 1566 FxObjectHandleGetPtr(FxDriverGlobals, 1567 TransferMemory, 1568 IFX_TYPE_MEMORY, 1569 (PVOID*) &pMemory); 1570 1571 status = pMemory->ValidateMemoryOffsets(TransferOffsets); 1572 if (!NT_SUCCESS(status)) { 1573 goto Done; 1574 } 1575 1576 buf.SetMemory(pMemory, TransferOffsets); 1577 } 1578 else { 1579 pMemory = NULL; 1580 } 1581 1582 status = pUsbPipe->FormatTransferRequest(pRequest, &buf, Flags); 1583 1584 if (NT_SUCCESS(status)) { 1585 FxUsbPipeTransferContext* pContext; 1586 1587 pContext = (FxUsbPipeTransferContext*) pRequest->GetContext(); 1588 1589 // 1590 // By assuming the fields are at the same offset, we can use simpler 1591 // logic (w/out comparisons for type) to set them. 1592 // 1593 WDFCASSERT( 1594 FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeWrite.Buffer) == 1595 FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeRead.Buffer) 1596 ); 1597 1598 WDFCASSERT( 1599 FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeWrite.Offset) == 1600 FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeRead.Offset) 1601 ); 1602 1603 pContext->m_UsbParameters.Parameters.PipeWrite.Buffer = TransferMemory; 1604 pContext->m_UsbParameters.Parameters.PipeWrite.Length = buf.GetBufferLength(); 1605 1606 pContext->m_UsbParameters.Parameters.PipeWrite.Offset = 1607 (TransferOffsets != NULL) ? TransferOffsets->BufferOffset 1608 : 0; 1609 pContext->SetUsbType( 1610 (Flags & USBD_TRANSFER_DIRECTION_IN) ? WdfUsbRequestTypePipeRead 1611 : WdfUsbRequestTypePipeWrite 1612 ); 1613 } 1614 1615 Done: 1616 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1617 "WDFUSBPIPE %p, WDFREQUEST %p, WDFMEMORY %p, %!STATUS!", 1618 Pipe, Request, TransferMemory, status); 1619 1620 return status; 1621 } 1622 1623 _Must_inspect_result_ 1624 NTSTATUS 1625 FxUsbPipe::_SendTransfer( 1626 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 1627 __in WDFUSBPIPE Pipe, 1628 __in_opt WDFREQUEST Request, 1629 __in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions, 1630 __in_opt PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, 1631 __out_opt PULONG BytesTransferred, 1632 __in ULONG Flags 1633 ) 1634 { 1635 FxRequestBuffer buf; 1636 FxUsbPipe* pUsbPipe; 1637 NTSTATUS status; 1638 1639 FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, 1640 Pipe, 1641 FX_TYPE_IO_TARGET_USB_PIPE, 1642 (PVOID*) &pUsbPipe, 1643 &FxDriverGlobals); 1644 1645 FxUsbPipeTransferContext context(FxUrbTypeLegacy); 1646 1647 FxSyncRequest request(FxDriverGlobals, &context, Request); 1648 1649 // 1650 // FxSyncRequest always succeesds for KM but can fail for UM. 1651 // 1652 status = request.Initialize(); 1653 if (!NT_SUCCESS(status)) { 1654 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1655 "Failed to initialize FxSyncRequest"); 1656 return status; 1657 } 1658 1659 if (BytesTransferred != NULL) { 1660 *BytesTransferred = 0; 1661 } 1662 1663 status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); 1664 if (!NT_SUCCESS(status)) { 1665 return status; 1666 } 1667 1668 status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions); 1669 if (!NT_SUCCESS(status)) { 1670 return status; 1671 } 1672 1673 // 1674 // We allow zero length writes (which are indicated by MemoryDescriptor == NULL) 1675 // 1676 if (MemoryDescriptor != NULL) { 1677 status = buf.ValidateMemoryDescriptor(FxDriverGlobals, MemoryDescriptor); 1678 if (!NT_SUCCESS(status)) { 1679 return status; 1680 } 1681 } 1682 1683 status = pUsbPipe->FormatTransferRequest(request.m_TrueRequest, &buf, Flags); 1684 1685 if (NT_SUCCESS(status)) { 1686 DoTraceLevelMessage( 1687 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1688 "WDFUSBPIPE %p, WDFREQUEST %p being submitted", 1689 Pipe, request.m_TrueRequest->GetTraceObjectHandle()); 1690 1691 status = pUsbPipe->SubmitSync(request.m_TrueRequest, RequestOptions); 1692 1693 // 1694 // Even on error we want to set this value. USBD should be clearing 1695 // it if the transfer fails. 1696 // 1697 if (BytesTransferred != NULL) { 1698 *BytesTransferred = context.GetUrbTransferLength(); 1699 } 1700 } 1701 1702 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1703 "WDFUSBPIPE %p, %!STATUS!", Pipe, status); 1704 1705 return status; 1706 } 1707 1708 _Must_inspect_result_ 1709 NTSTATUS 1710 FxUsbPipe::FormatAbortRequest( 1711 __in FxRequestBase* Request 1712 ) 1713 { 1714 FxUsbPipeRequestContext* pContext; 1715 NTSTATUS status; 1716 FX_URB_TYPE urbType; 1717 1718 status = Request->ValidateTarget(this); 1719 if (!NT_SUCCESS(status)) { 1720 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1721 "Pipe %p, Request %p, setting target failed, " 1722 "status %!STATUS!", this, Request, status); 1723 1724 return status; 1725 } 1726 1727 if (Request->HasContextType(FX_RCT_USB_PIPE_REQUEST)) { 1728 pContext = (FxUsbPipeRequestContext*) Request->GetContext(); 1729 } 1730 else { 1731 1732 urbType = m_UsbDevice->GetFxUrbTypeForRequest(Request); 1733 pContext = new(GetDriverGlobals()) FxUsbPipeRequestContext(urbType); 1734 if (pContext == NULL) { 1735 return STATUS_INSUFFICIENT_RESOURCES; 1736 } 1737 1738 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1739 if (urbType == FxUrbTypeUsbdAllocated) { 1740 status = pContext->AllocateUrb(m_USBDHandle); 1741 if (!NT_SUCCESS(status)) { 1742 delete pContext; 1743 return status; 1744 } 1745 // 1746 // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is 1747 // important to release those resorces before the devnode is removed. Those 1748 // resoruces are removed at the time Request is disposed. 1749 // 1750 Request->EnableContextDisposeNotification(); 1751 } 1752 #endif 1753 1754 Request->SetContext(pContext); 1755 } 1756 1757 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1758 pContext->SetInfo(WdfUsbRequestTypePipeAbort, 1759 m_PipeInformation.PipeHandle, 1760 URB_FUNCTION_ABORT_PIPE); 1761 1762 if (pContext->m_Urb == &pContext->m_UrbLegacy) { 1763 urbType = FxUrbTypeLegacy; 1764 } 1765 else { 1766 urbType = FxUrbTypeUsbdAllocated; 1767 } 1768 1769 FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); 1770 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 1771 pContext->SetInfo(WdfUsbRequestTypePipeAbort, 1772 m_UsbInterface->m_WinUsbHandle, 1773 m_PipeInformationUm.PipeId, 1774 UMURB_FUNCTION_ABORT_PIPE); 1775 FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbPipeRequest.Hdr, m_UsbDevice->m_pHostTargetFile); 1776 #endif 1777 1778 return STATUS_SUCCESS; 1779 } 1780 1781 _Must_inspect_result_ 1782 NTSTATUS 1783 FxUsbPipe::FormatResetRequest( 1784 __in FxRequestBase* Request 1785 ) 1786 { 1787 FxUsbPipeRequestContext* pContext; 1788 NTSTATUS status; 1789 FX_URB_TYPE urbType; 1790 1791 status = Request->ValidateTarget(this); 1792 if (!NT_SUCCESS(status)) { 1793 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1794 "Pipe %p, Request %p, setting target failed, " 1795 "status %!STATUS!", this, Request, status); 1796 1797 return status; 1798 } 1799 1800 if (Request->HasContextType(FX_RCT_USB_PIPE_REQUEST)) { 1801 pContext = (FxUsbPipeRequestContext*) Request->GetContext(); 1802 } 1803 else { 1804 urbType = m_UsbDevice->GetFxUrbTypeForRequest(Request); 1805 pContext = new(GetDriverGlobals()) FxUsbPipeRequestContext(urbType); 1806 if (pContext == NULL) { 1807 return STATUS_INSUFFICIENT_RESOURCES; 1808 } 1809 1810 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1811 if (urbType == FxUrbTypeUsbdAllocated) { 1812 status = pContext->AllocateUrb(m_USBDHandle); 1813 if (!NT_SUCCESS(status)) { 1814 delete pContext; 1815 return status; 1816 } 1817 // 1818 // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is 1819 // important to release those resorces before the devnode is removed. Those 1820 // resoruces are removed at the time Request is disposed. 1821 // 1822 Request->EnableContextDisposeNotification(); 1823 } 1824 #endif 1825 1826 Request->SetContext(pContext); 1827 } 1828 1829 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1830 // 1831 // URB_FUNCTION_RESET_PIPE and URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 1832 // are the same value 1833 // 1834 pContext->SetInfo(WdfUsbRequestTypePipeReset, 1835 m_PipeInformation.PipeHandle, 1836 URB_FUNCTION_RESET_PIPE); 1837 1838 if (pContext->m_Urb == &pContext->m_UrbLegacy) { 1839 urbType = FxUrbTypeLegacy; 1840 } 1841 else { 1842 urbType = FxUrbTypeUsbdAllocated; 1843 } 1844 1845 FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); 1846 #elif (FX_CORE_MODE == FX_CORE_USER_MODE) 1847 pContext->SetInfo(WdfUsbRequestTypePipeReset, 1848 m_UsbInterface->m_WinUsbHandle, 1849 m_PipeInformationUm.PipeId, 1850 UMURB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL); 1851 FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbPipeRequest.Hdr, m_UsbDevice->m_pHostTargetFile); 1852 #endif 1853 1854 return STATUS_SUCCESS; 1855 } 1856 1857 NTSTATUS 1858 FxUsbPipe::Reset( 1859 VOID 1860 ) 1861 { 1862 FxUsbPipeRequestContext context(FxUrbTypeLegacy); 1863 1864 FxSyncRequest request(GetDriverGlobals(), &context); 1865 NTSTATUS status; 1866 1867 // 1868 // FxSyncRequest always succeesds for KM but can fail for UM. 1869 // 1870 status = request.Initialize(); 1871 if (!NT_SUCCESS(status)) { 1872 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1873 "Failed to initialize FxSyncRequest"); 1874 return status; 1875 } 1876 1877 status = FormatResetRequest(request.m_TrueRequest); 1878 if (NT_SUCCESS(status)) { 1879 if (m_Reader != NULL) { 1880 // 1881 // This assumes that no other I/O besides reader I/O is going on. 1882 // 1883 m_Reader->CancelRepeaters(); 1884 } 1885 else { 1886 CancelSentIo(); 1887 } 1888 status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL); 1889 } 1890 return status; 1891 } 1892 1893