Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895//// Copyright (C) Microsoft. All rights reserved.//#include "fxusbpch.hpp"
extern "C" {#if defined(EVENT_TRACING)#include "FxUsbPipe.tmh"#endif}
#include "fxglobals.h"//// NOTE: There are 3 different paths Requests could be sent to the lower driver// 1) In case of reposting a successfully completed Request use the Dpc which calls SendIo.// 2) For a failed completion use a workitem which works if the IoTarget is in Started state.// 3) On moving to the start state the Repeater requests are inserted into the// Iotargets Pended Queue directly.//// The function ResubmitRepeater calls SubmitLocked. If the action we get back// from SubmitLocked is "SubmitSend", (SubmitQueued is treated as failure because// of WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND flag) we are guaranteed to// call IoCallDriver in the workitem or the DPC and hence the completion routine// being called.// This is very important because we increment the m_IoCount in SubmitLocked and// decrement in the completion routine. So if there was a code path where// SubmitLocked was called and IoCallDriver(hence the completion routine) wasn't,// the IoTarget could stop responding in Dispose.//
FxUsbPipeContinuousReader::FxUsbPipeContinuousReader( __in FxUsbPipe* Pipe, __in UCHAR NumReaders ) : m_NumReaders(NumReaders), m_NumFailedReaders(0){ m_WorkItem = NULL; m_WorkItemRerunContext = NULL; m_WorkItemThread = NULL; m_WorkItemFlags = 0; m_WorkItemQueued = FALSE; m_ReadersSubmitted = FALSE;
m_Lookaside = NULL; m_Pipe = Pipe;
m_TargetDevice = m_Pipe->GetTargetDevice();
RtlZeroMemory(&m_Readers[0], m_NumReaders * sizeof(FxUsbPipeRepeatReader));}
FxUsbPipeContinuousReader::~FxUsbPipeContinuousReader(){ LONG i;
FxUsbPipeRepeatReader * reader = &m_Readers[0];
// // It is impoortant to delete the requests before the lookaside because the // requests may have outstanding references on memory objects allocated by // the lookaside. The lookaside will not be truly deleted until the oustanding // memory object allocations are also freed. // for (i = 0; i < m_NumReaders; i++) { if (reader[i].Request != NULL) { DeleteMemory(reader[i].Request);
reader[i].Request->DeleteObject(); reader[i].Request = NULL; }
#if (FX_CORE_MODE == FX_CORE_USER_MODE) reader[i].ReadCompletedEvent.Uninitialize(); reader[i].m_ReadWorkItem.Free();#endif }
if (m_Lookaside != NULL) { m_Lookaside->DeleteObject(); }
if (m_WorkItem != NULL) { m_WorkItem->DeleteObject(); m_WorkItem = NULL; }}
BOOLEANFxUsbPipeContinuousReader::QueueWorkItemLocked( __in FxUsbPipeRepeatReader* Repeater ){ BOOLEAN queued; PFX_DRIVER_GLOBALS fxDriverGlobals;
queued = FALSE; fxDriverGlobals = m_Pipe->GetDriverGlobals();
if (m_Pipe->m_State == WdfIoTargetStarted && m_WorkItemQueued == FALSE) { // // No item queued, queue it up now. // DoTraceLevelMessage( fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader queueing work item to recover " "from failed allocation", m_Pipe->GetHandle());
if (m_WorkItem->Enqueue(_FxUsbPipeRequestWorkItemThunk, Repeater)) { m_WorkItemQueued = TRUE; queued = TRUE; } else { DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, "Could not Queue workitem"); } }
// // We only want to queue the work item while the target is in the // started state. If it is not started, then we are no longer sending // i/o and we should not queue the work item to try to restart. // if (FALSE == queued) { DoTraceLevelMessage( fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader not queueing work item," "WorkItemQueued = %d, target state %!WDF_IO_TARGET_STATE!", m_Pipe->GetHandle(), m_WorkItemQueued, m_Pipe->m_State); }
return queued;}
ULONGFxUsbPipeContinuousReader::ResubmitRepeater( __in FxUsbPipeRepeatReader* Repeater, __out NTSTATUS* Status ){ PFX_DRIVER_GLOBALS pFxDriverGlobals; NTSTATUS status; ULONG action; KIRQL irql;
action = 0; pFxDriverGlobals = m_Pipe->GetDriverGlobals(); status = STATUS_UNSUCCESSFUL;
// // Reformat and allocate any new needed buffers // status = FormatRepeater(Repeater);
m_Pipe->Lock(&irql);
// // Do not re-submit repeaters if there is a queued/running work-item to // reset pipe. Work-item will restart this repeater later. // This check needs to be done after the FormatRepeater() call above to // prevent a race condition where we are not detecting when the repeater // is cancelled. // if (m_WorkItemQueued) { // // Return an error and no action flags to let the caller know that // this request was not sent. // status = STATUS_CANCELLED;
DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p is being reset, continuous reader %p FxRequest %p" " PIRP %p is deferred for later.", m_Pipe->GetHandle(), Repeater, Repeater->Request, Repeater->RequestIrp); } else if (NT_SUCCESS(status)) { // // Get ready to re-submit the repeater. // action = m_Pipe->SubmitLocked( Repeater->Request, NULL, WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND );
if (action & SubmitSend) { // // Clear the event only if we are going to send the request // Repeater->ReadCompletedEvent.Clear(); } else if (action & SubmitQueued) { // // Request got canceled asynchronously. The other thread is now // responsible for calling its completion callback. // status = STATUS_CANCELLED; } else { // // Submit failed (which is expected when we are changing the target // state or when the request is canceled). It should always be an // error. // status = Repeater->Request->GetFxIrp()->GetStatus(); ASSERT(!NT_SUCCESS(status)); } } else { // // Could not allocate a new buffer // Repeater->Request->GetFxIrp()->SetStatus(status);
DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader, format failed, %!STATUS!, " "repeater %p", m_Pipe->GetHandle(), status, Repeater);
if (m_Pipe->m_State == WdfIoTargetStarted) { m_NumFailedReaders++; ASSERT(m_NumFailedReaders <= m_NumReaders);
if (m_NumFailedReaders == m_NumReaders) { // // Queue a work item to clear problem. // QueueWorkItemLocked(Repeater); } else { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader, buffer alloc failed, but " "there are %d readers left out of a max of %d", m_Pipe->GetHandle(), m_NumReaders - m_NumFailedReaders, m_NumReaders);
// // There are still other pending readers, just use those for // now. // DO_NOTHING(); } } else { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader, buffer alloc failed, but not " "in started state", m_Pipe->GetHandle()); } }
m_Pipe->Unlock(irql);
*Status = status;
return action;}
VOIDFxUsbPipeContinuousReader::_FxUsbPipeRequestComplete( __in WDFREQUEST Request, __in WDFIOTARGET Target, __in PWDF_REQUEST_COMPLETION_PARAMS Params, __in WDFCONTEXT Context ){ FxUsbPipeRepeatReader* pRepeater; FxUsbPipeContinuousReader* pThis; FxUsbPipe* pPipe; NTSTATUS status; ULONG action; BOOLEAN readCompletedEventSet;
UNREFERENCED_PARAMETER(Request); UNREFERENCED_PARAMETER(Params);
readCompletedEventSet = FALSE; action = 0; pRepeater = (FxUsbPipeRepeatReader*) Context; pThis = (FxUsbPipeContinuousReader*) pRepeater->Parent; pPipe = pThis->m_Pipe;
status = pRepeater->Request->GetFxIrp()->GetStatus();
if (NT_SUCCESS(status)) { PWDF_USB_REQUEST_COMPLETION_PARAMS params;
params = pRepeater->Request->GetContext()-> m_CompletionParams.Parameters.Usb.Completion;
pThis->m_ReadCompleteCallback((WDFUSBPIPE) Target, params->Parameters.PipeRead.Buffer, params->Parameters.PipeRead.Length, pThis->m_ReadCompleteContext);
// // This will release the reference on the read memory and allocate a new // one // action = pThis->ResubmitRepeater(pRepeater, &status); } else if (status != STATUS_CANCELLED) { KIRQL irql;
DoTraceLevelMessage( pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader FxRequest %p PIRP %p returned with " "%!STATUS!", pPipe->GetHandle(), pRepeater->Request , pRepeater->RequestIrp, status);
pPipe->Lock(&irql);
pRepeater->ReadCompletedEvent.Set(); readCompletedEventSet = TRUE;
// // Queue a work item to clear problem. // pThis->QueueWorkItemLocked(pRepeater);
pPipe->Unlock(irql);
ASSERT(!NT_SUCCESS(status)); } else { // // I/O was cancelled, which means internally it was cancelled so don't // do anything. // DoTraceLevelMessage( pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader %p FxRequest %p PIRP %p canceled", pPipe->GetHandle(), pRepeater, pRepeater->Request , pRepeater->RequestIrp);
DO_NOTHING(); }
if (action & SubmitSend) {
// // We don't want to recurse on the same stack and overflow it. // This is especially true if the device is pushing a lot of data and // usb is completing everything within its dpc as soon as we send the // read down. Eventually on a chk build, we will be nailed for running // in one DPC for too long. // // As a slower alternative, we could queue a work item and resubmit the // read from there. //
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) BOOLEAN result; result = KeInsertQueueDpc(&pRepeater->Dpc, NULL, NULL);
// // The DPC should never be currently queued when we try to queue it. // ASSERT(result != FALSE);#else pRepeater->m_ReadWorkItem.Enqueue((PMX_WORKITEM_ROUTINE)_ReadWorkItem, pRepeater);#endif UNREFERENCED_PARAMETER(status); //for fre build
} else if (action & SubmitQueued) { // // I/O got canceled asynchronously; the other thread is now // responsible for re-invoking this completion routine. // ASSERT(STATUS_CANCELLED == status);
DoTraceLevelMessage( pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p continuous reader %p FxRequest %p PIRP %p got" " asynchronously canceled", pPipe->GetHandle(), pRepeater, pRepeater->Request , pRepeater->RequestIrp);
DO_NOTHING(); } else if (FALSE == readCompletedEventSet) { ASSERT(!NT_SUCCESS(status)); // // We are not sending the request and it is not queued so signal that // it is done. // pRepeater->ReadCompletedEvent.Set(); }}
VOIDFxUsbPipeContinuousReader::FxUsbPipeRequestWorkItemHandler( __in FxUsbPipeRepeatReader* FailedRepeater ){ FxUsbDevice* pDevice; NTSTATUS status, failedStatus; USBD_STATUS usbdStatus; LONG i; KIRQL irql; BOOLEAN restart; FxRequestContext* context; PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; PFX_DRIVER_GLOBALS pFxDriverGlobals;
pFxDriverGlobals = m_Pipe->GetDriverGlobals();
// // Get failed info. // failedStatus = FailedRepeater->Request->GetStatus();
// // Context is allocated at config time and gets reused so context // will never be NULL. // context = FailedRepeater->Request->GetContext(); usbCompletionParams = context->m_CompletionParams.Parameters.Usb.Completion;
// // In case FormatRepeater fails to allocate memory usbCompletionParams // pointer is not set. // // usbCompletionParams are part of the context and // not really allocated at the time of every Format but // the pointer gets cleared by request->Reuse and gets set again by // context->SetUsbType. // // In FormatRepeater, context->SetUsbType is skipped // if a memory failure occurs before this step. // // Hence retrieve usbdStatus only when usbCompletionParams is set. // if (usbCompletionParams) { usbdStatus = usbCompletionParams->UsbdStatus; } else { // // Set usbdStatus to success as we didn't receive a failure from // USB stack. // // This path is reached during memory allocation failure. In such // case failedStatus would already be set appropriately. (usbdStatus // and failedStatus are passed to m_ReadersFailedCallback below.) // usbdStatus = STATUS_SUCCESS; }
// // No read requests should be in progress when the framework calls the // EvtUsbTargetPipeReadersFailed callback function. This is part of the // contract so that the Driver doesn't need to bother with the // Completion calllback while taking corrective action. // CancelRepeaters(); pDevice = m_Pipe->m_UsbDevice;
if (m_ReadersFailedCallback != NULL) { // // Save the current thread object pointer. This value is // used for not deadlocking when misbehaved drivers (< v1.9) call // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback // ASSERT(NULL == m_WorkItemThread); m_WorkItemThread = Mx::MxGetCurrentThread();
restart = m_ReadersFailedCallback( (WDFUSBPIPE) m_Pipe->GetHandle(), failedStatus, usbdStatus );
m_WorkItemThread = NULL; } else { // // By default, we restart the readers // restart = TRUE; }
if (restart) { status = pDevice->IsConnected();
if (NT_SUCCESS(status)) {
// // for v1.9 or higher use the error recovery procedure prescribed // by the USB team. // if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) {
if (pDevice->IsEnabled()) { // // Reset the pipe if port status is enabled // m_Pipe->Reset(); } else { // // Reset the device if port status is disabled // status = pDevice->Reset(); } } else { // // Reset the device if port status is disabled // status = pDevice->Reset(); } } else { // // if port status is disconnected we would get back // a !NT_SUCCESS. This would mean that we would not // send the readers again and treat it like a failed reader. // DO_NOTHING(); }
} else { // // By setting status to !NT_SUCCESS, we will not send the readers // again and treat it like a failed reader. // status = STATUS_UNSUCCESSFUL; }
// // Work item is no longer queued. We set this before resubmitting the // repeaters so that if they all complete and fail, we will requeue the // work item. // m_Pipe->Lock(&irql); m_WorkItemQueued = FALSE; m_Pipe->Unlock(irql);
if (NT_SUCCESS(status)) { ULONG action;
// // Reset the count to zero. This is safe since we stopped all the // readers at the beginning of this function. // m_NumFailedReaders = 0;
// // restart the readers // for (i = 0; i < m_NumReaders; i++) { FxUsbPipeRepeatReader* pRepeater;
pRepeater = &m_Readers[i];
action = ResubmitRepeater(pRepeater, &status);
if (action & SubmitSend) { // // Ignore the return value because once we have sent the // request, we want all processing to be done in the // completion routine. // (void) pRepeater->Request->GetSubmitFxIrp()->CallDriver(m_Pipe->m_TargetDevice); } } }}
VOIDFxUsbPipeContinuousReader::_FxUsbPipeRequestWorkItemThunk( __in PVOID Context )/* Only one work-item can be in-progress at any given time and only one additional work-item can be queued at any given time. This logic and m_WorkItemQueued makes this happen.*/{ FxUsbPipeRepeatReader* pFailedRepeater; FxUsbPipeContinuousReader* pThis; FxUsbPipe* pPipe; KIRQL irql; BOOLEAN rerun, inprogress;
pFailedRepeater = (FxUsbPipeRepeatReader*) Context; pThis = (FxUsbPipeContinuousReader*) pFailedRepeater->Parent; pPipe = pThis->m_Pipe;
// // Check if a work item is already in progress. // pPipe->Lock(&irql); if (pThis->m_WorkItemFlags & FX_USB_WORKITEM_IN_PROGRESS) { // // Yes, just let the other thread re-run this logic. // inprogress = TRUE;
ASSERT((pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) == 0); pThis->m_WorkItemFlags |= FX_USB_WORKITEM_RERUN;
ASSERT(NULL == pThis->m_WorkItemRerunContext); pThis->m_WorkItemRerunContext = Context; } else { // // No, it not running. // inprogress = FALSE;
pThis->m_WorkItemFlags |= FX_USB_WORKITEM_IN_PROGRESS; ASSERT((pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) == 0); } pPipe->Unlock(irql);
if (inprogress) { return; }
// // OK, this thread is responsible for running the work item logic. // do { // // Cleanup and restart the repeters. // pThis->FxUsbPipeRequestWorkItemHandler(pFailedRepeater);
// // Check if callback needs to be re-run. // pPipe->Lock(&irql); if (pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) { // // Yes, a new work item was requested while it was already running. // rerun = TRUE;
pThis->m_WorkItemFlags &= ~FX_USB_WORKITEM_RERUN;
ASSERT(pThis->m_WorkItemRerunContext != NULL); pFailedRepeater = (FxUsbPipeRepeatReader*)pThis->m_WorkItemRerunContext; pThis->m_WorkItemRerunContext = NULL;
ASSERT(pThis == (FxUsbPipeContinuousReader*)pFailedRepeater->Parent); } else { // // No, all done. // rerun = FALSE;
ASSERT(pThis->m_WorkItemFlags & FX_USB_WORKITEM_IN_PROGRESS); pThis->m_WorkItemFlags &= ~FX_USB_WORKITEM_IN_PROGRESS;
ASSERT(NULL == pThis->m_WorkItemRerunContext); } pPipe->Unlock(irql);
} while (rerun);}
PVOIDFxUsbPipeContinuousReader::operator new( __in size_t Size, __in PFX_DRIVER_GLOBALS FxDriverGlobals, __range(1, NUM_PENDING_READS_MAX) ULONG NumReaders ){ ASSERT(NumReaders >= 1);
return FxPoolAllocate( FxDriverGlobals, NonPagedPool, Size + (NumReaders-1) * sizeof(FxUsbPipeRepeatReader) );}
_Must_inspect_result_NTSTATUSFxUsbPipeContinuousReader::FormatRepeater( __in FxUsbPipeRepeatReader* Repeater ){ WDF_REQUEST_REUSE_PARAMS params; FxRequestBuffer buf; FxUsbPipeTransferContext* pContext; FxMemoryObject* pMemory; FxRequest* pRequest; NTSTATUS status;
pRequest = Repeater->Request; // // The repeater owns the request memory. If there is a memory on the // context, delete it now. the memory will still be referencable since // it will still have a reference against it until FormatTransferRequest is // called or the request is freed and the context releases its references // DeleteMemory(pRequest);
WDF_REQUEST_REUSE_PARAMS_INIT(¶ms, 0, STATUS_NOT_SUPPORTED);
pRequest->Reuse(¶ms);
// // pMemory will be deleted when either // a) The request completes // or // b) The continuous reader is destroyed and we delete the lookaside. since // the lookaside is the parent object for pMemory, pMemory will be disposed // of when the parent is Disposed // status = m_Lookaside->Allocate(&pMemory); if (!NT_SUCCESS(status)) { FxRequestContext* pContext;
pContext = pRequest->GetContext(); if (pContext != NULL ) { pContext->m_RequestMemory = NULL; }
return STATUS_INSUFFICIENT_RESOURCES; }
RtlZeroMemory(pMemory->GetBuffer(), pMemory->GetBufferSize());
buf.SetMemory(pMemory, &m_Offsets);
status = m_Pipe->FormatTransferRequest( pRequest, &buf, USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK );
if (!NT_SUCCESS(status)) { // // In the case of failure, the context in the request will delete the // memory. If there is no context, delete the memory here. // if (pRequest->GetContext() == NULL) { // // Use DeleteFromFailedCreate because the driver never saw the // buffer, so they shouldn't be told about it going away. // pMemory->DeleteFromFailedCreate(); }
return status; }
pContext = (FxUsbPipeTransferContext*) pRequest->GetContext(); pContext->SetUsbType(WdfUsbRequestTypePipeRead); pContext->m_UsbParameters.Parameters.PipeRead.Buffer = (WDFMEMORY) pMemory->GetObjectHandle();
pRequest->SetCompletionRoutine(_FxUsbPipeRequestComplete, Repeater); return status;}
VOIDFxUsbPipeContinuousReader::CancelRepeaters( VOID ){ LONG i;
Mx::MxEnterCriticalRegion();
for (i = 0; i < m_NumReaders; i++) { m_Readers[i].Request->Cancel(); m_Pipe->GetDriverGlobals()->WaitForSignal( m_Readers[i].ReadCompletedEvent.GetSelfPointer(), "waiting for continuous reader to finish, WDFUSBPIPE", m_Pipe->GetHandle(), m_Pipe->GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, WaitSignalBreakUnderVerifier);
}
Mx::MxLeaveCriticalRegion(); // // Checking for IO Count <= 1 is not a good idea here because there could be always other IO // besides that from the continous reader going on the Read Pipe. //}
FxUsbPipeTransferContext::FxUsbPipeTransferContext( __in FX_URB_TYPE FxUrbType ) : FxUsbRequestContext(FX_RCT_USB_PIPE_XFER){ m_UnlockPages = FALSE; m_PartialMdl = NULL; m_USBDHandle = NULL;
if (FxUrbType == FxUrbTypeLegacy) { m_Urb = &m_UrbLegacy; } else { m_Urb = NULL; }
}
FxUsbPipeTransferContext::~FxUsbPipeTransferContext( VOID ){ if (m_Urb && (m_Urb != &m_UrbLegacy)) { USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); } m_Urb = NULL; m_USBDHandle = NULL;}
__checkReturnNTSTATUSFxUsbPipeTransferContext::AllocateUrb( __in USBD_HANDLE USBDHandle ){ NTSTATUS status;
if (m_Urb) { status = STATUS_INVALID_DEVICE_STATE; goto Done; }
status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb);
if (!NT_SUCCESS(status)) { goto Done; }
m_USBDHandle = USBDHandle;
Done: return status;}
VOIDFxUsbPipeTransferContext::Dispose( VOID ){ if (m_Urb && (m_Urb != &m_UrbLegacy)){ USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); m_Urb = NULL; m_USBDHandle = NULL; }}
VOIDFxUsbPipeTransferContext::ReleaseAndRestore( __in FxRequestBase* Request ){#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) // // Check now because Init will NULL out the field // if (m_PartialMdl != NULL) { if (m_UnlockPages) { MmUnlockPages(m_PartialMdl); m_UnlockPages = FALSE; }
FxMdlFree(Request->GetDriverGlobals(), m_PartialMdl); m_PartialMdl = NULL; }#endif FxUsbRequestContext::ReleaseAndRestore(Request); // __super call}
VOIDFxUsbPipeTransferContext::CopyParameters( __in FxRequestBase* Request ){ m_CompletionParams.IoStatus.Information = GetUrbTransferLength();
// // If both are at the same offset, we don't have to compare type for // Read or Write // WDFCASSERT(FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeRead.Length) == FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeWrite.Length));
m_UsbParameters.Parameters.PipeRead.Length = GetUrbTransferLength(); FxUsbRequestContext::CopyParameters(Request); // __super call}
VOIDFxUsbPipeTransferContext::SetUrbInfo( __in USBD_PIPE_HANDLE PipeHandle, __in ULONG TransferFlags ){ m_Urb->TransferFlags = TransferFlags; m_Urb->PipeHandle = PipeHandle;}
USBD_STATUSFxUsbPipeTransferContext::GetUsbdStatus( VOID ){ return m_Urb->Hdr.Status;}
FxUsbUrbContext::FxUsbUrbContext( VOID ) : FxUsbRequestContext(FX_RCT_USB_URB_REQUEST), m_pUrb(NULL){}
USBD_STATUSFxUsbUrbContext::GetUsbdStatus( VOID ){ return m_pUrb == NULL ? 0 : m_pUrb->UrbHeader.Status;}
VOIDFxUsbUrbContext::StoreAndReferenceMemory( __in FxRequestBuffer* Buffer ){ ULONG dummy;
FxUsbRequestContext::StoreAndReferenceMemory(Buffer);
// // make sure it is framework managed memory or raw PVOID // ASSERT(Buffer->DataType == FxRequestBufferMemory || Buffer->DataType == FxRequestBufferBuffer);
Buffer->AssignValues((PVOID*) &m_pUrb, NULL, &dummy);}
VOIDFxUsbUrbContext::ReleaseAndRestore( __in FxRequestBase* Request ){ m_pUrb = NULL; FxUsbRequestContext::ReleaseAndRestore(Request); // __super call}
FxUsbPipeRequestContext::FxUsbPipeRequestContext( __in FX_URB_TYPE FxUrbType ) : FxUsbRequestContext(FX_RCT_USB_PIPE_REQUEST){ m_USBDHandle = NULL;
if (FxUrbType == FxUrbTypeLegacy) { m_Urb = &m_UrbLegacy; } else { m_Urb = NULL; }}
FxUsbPipeRequestContext::~FxUsbPipeRequestContext( VOID ){ if (m_Urb && (m_Urb != &m_UrbLegacy)) { USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); } m_Urb = NULL; m_USBDHandle = NULL;}
__checkReturnNTSTATUSFxUsbPipeRequestContext::AllocateUrb( __in USBD_HANDLE USBDHandle ){ NTSTATUS status;
if (m_Urb) { status = STATUS_INVALID_DEVICE_STATE; goto Done; }
status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb);
if (!NT_SUCCESS(status)) { goto Done; }
m_USBDHandle = USBDHandle;
Done: return status;}
VOIDFxUsbPipeRequestContext::Dispose( VOID ){ if (m_Urb && (m_Urb != &m_UrbLegacy)){ USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); m_Urb = NULL; m_USBDHandle = NULL; }}
VOIDFxUsbPipeRequestContext::SetInfo( __in WDF_USB_REQUEST_TYPE Type, __in USBD_PIPE_HANDLE PipeHandle, __in USHORT Function ){ RtlZeroMemory(m_Urb, sizeof(*m_Urb)); m_Urb->Hdr.Length = sizeof(*m_Urb); m_Urb->Hdr.Function = Function; m_Urb->PipeHandle = PipeHandle;
SetUsbType(Type);}
USBD_STATUSFxUsbPipeRequestContext::GetUsbdStatus( VOID ){ return m_Urb->Hdr.Status;}
FxUsbPipe::FxUsbPipe( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in FxUsbDevice* UsbDevice ) : FxIoTarget(FxDriverGlobals, sizeof(FxUsbPipe), FX_TYPE_IO_TARGET_USB_PIPE), m_UsbDevice(UsbDevice){ InitializeListHead(&m_ListEntry); RtlZeroMemory(&m_PipeInformation, sizeof(m_PipeInformation));#if (FX_CORE_MODE == FX_CORE_USER_MODE) RtlZeroMemory(&m_PipeInformationUm, sizeof(m_PipeInformationUm));#endif m_InterfaceNumber = 0; m_Reader = NULL; m_UsbInterface = NULL; m_CheckPacketSize = TRUE; m_USBDHandle = UsbDevice->m_USBDHandle; m_UrbType = UsbDevice->m_UrbType;
MarkNoDeleteDDI(ObjectDoNotLock);}
VOIDFxUsbPipe::InitPipe( __in PUSBD_PIPE_INFORMATION PipeInfo, __in UCHAR InterfaceNumber, __in FxUsbInterface* UsbInterface ){ RtlCopyMemory(&m_PipeInformation, PipeInfo, sizeof(m_PipeInformation)); m_InterfaceNumber = InterfaceNumber;
if (m_UsbInterface != NULL) { m_UsbInterface->RELEASE(this); m_UsbInterface = NULL; }
m_UsbInterface = UsbInterface; m_UsbInterface->ADDREF(this);}
FxUsbPipe::~FxUsbPipe(){ if (m_UsbInterface != NULL) { m_UsbInterface->RemoveDeletedPipe(this); m_UsbInterface->RELEASE(this); }
ASSERT(IsListEmpty(&m_ListEntry));}
BOOLEANFxUsbPipe::Dispose(){ BOOLEAN callCleanup;
// // Call base class: callbacks, terminates I/Os, etc. // callCleanup = FxIoTarget::Dispose(); // __super call
// // Don't need the reader anymore. The reader is deleted after calling the // parent class Dispose() to preserve the existing deletion order (it was // deleted in the Pipe's dtor() before this change). // if (m_Reader != NULL) { delete m_Reader;
// // By doing this assignment we prevent misbehaved drivers // from crashing the system when they call WdfIoTargetStop from their // usb pipe's destroy callback. // m_Reader = NULL; }
return callCleanup;}
_Must_inspect_result_NTSTATUSFxUsbPipe::GotoStartState( __in PLIST_ENTRY RequestListHead, __in BOOLEAN Lock ){ NTSTATUS status; LONG i;
if (m_Reader != NULL) { if (m_Reader->m_ReadersSubmitted == FALSE) { ASSERT(IsListEmpty(&m_SentIoListHead));
for (i = 0; i < m_Reader->m_NumReaders; i++) { FxRequest* pRequest;
pRequest = m_Reader->m_Readers[i].Request;
UNREFERENCED_PARAMETER(pRequest); //for fre build ASSERT(IsListEmpty(&pRequest->m_ListEntry)); ASSERT(pRequest->m_DrainSingleEntry.Next == NULL); } } }
status = FxIoTarget::GotoStartState(RequestListHead, Lock);
if (m_Reader == NULL || !NT_SUCCESS(status)) { return status; }
// // Add the repeater requests to the list head so that they are sent by the // caller of this function when this function returns IFF they have not yet // been queued. (They can be queued on a start -> start transition.) // if (m_Reader->m_ReadersSubmitted == FALSE) { for (i = 0; i < m_Reader->m_NumReaders; i++) { // // This will clear ReadCompletedEvent as well // status = m_Reader->FormatRepeater(&m_Reader->m_Readers[i]);
if (!NT_SUCCESS(status)) { return status; } }
// // Reset the number of failed readers in case we had failure in a // previously started state. // m_Reader->m_NumFailedReaders = 0;
for (i = 0; i < m_Reader->m_NumReaders; i++) { FxRequest* pRequest;
pRequest = m_Reader->m_Readers[i].Request; pRequest->SetTarget(this); pRequest->ADDREF(this);
// // NOTE: This is an elusive backdoor to send the Request down // since it is inserted directly into the IoTargets pended list. // The IoTarget is not started so we add the request to the // pended list so that it is processed when the IoTarget starts. // m_Reader->m_Pipe->IncrementIoCount(); InsertTailList(RequestListHead, &pRequest->m_ListEntry);
// // Clear the event only when we know it will be submitted to the // target. It will be set when the request is submitted to the // target and the submit fails or if it is cancelled. // m_Reader->m_Readers[i].ReadCompletedEvent.Clear(); }
m_Reader->m_ReadersSubmitted = TRUE; }
return status;}
VOIDFxUsbPipe::GotoStopState( __in WDF_IO_TARGET_SENT_IO_ACTION Action, __in PSINGLE_LIST_ENTRY SentRequestListHead, __out PBOOLEAN Wait, __in BOOLEAN LockSelf ){ KIRQL irql; PFX_DRIVER_GLOBALS pFxDriverGlobals;
irql = PASSIVE_LEVEL; pFxDriverGlobals = GetDriverGlobals();
if (LockSelf) { Lock(&irql); }
if (m_Reader != NULL) { // // If we are a continuous reader, always cancel the sent io so that we // can resubmit it later on a restart. // DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p converting stop action %!WDF_IO_TARGET_SENT_IO_ACTION!" " to %!WDF_IO_TARGET_SENT_IO_ACTION!", GetHandle(), Action, WdfIoTargetCancelSentIo);
Action = WdfIoTargetCancelSentIo; }
FxIoTarget::GotoStopState(Action, SentRequestListHead, Wait, FALSE); // __super call
if (m_Reader != NULL) { // // The continuous reader requests are no longer enqueued. Remember that // state, so when we restart, we resend them. // m_Reader->m_ReadersSubmitted = FALSE;
// // Log a message when misbehaved drivers call WdfIoTargetStop // from EvtUsbTargetPipeReadersFailed callback. // if (m_Reader->m_WorkItemThread == Mx::MxGetCurrentThread()) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, "WDFUSBPIPE %p is stopped from EvtUsbTargetPipeReadersFailed" " callback", GetHandle());
if (pFxDriverGlobals->IsVerificationEnabled(1, 9, OkForDownLevel)) { FxVerifierDbgBreakPoint(pFxDriverGlobals); } }
// // Do not deadlock when misbehaved drivers (< v1.9) call // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback. // if (m_Reader->m_WorkItemThread != Mx::MxGetCurrentThread() || pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { // // Make sure work item is done. It is possible for the upper class // to return wait = false if the list of sent requests is empty. We // still want to wait anyway for making sure work item is not about // to run or it is running. // *Wait = TRUE; } }
if (LockSelf) { Unlock(irql); }}
VOIDFxUsbPipe::GotoPurgeState( __in WDF_IO_TARGET_PURGE_IO_ACTION Action, __in PLIST_ENTRY PendedRequestListHead, __in PSINGLE_LIST_ENTRY SentRequestListHead, __out PBOOLEAN Wait, __in BOOLEAN LockSelf ){ KIRQL irql; PFX_DRIVER_GLOBALS pFxDriverGlobals;
irql = PASSIVE_LEVEL; pFxDriverGlobals = GetDriverGlobals();
if (LockSelf) { Lock(&irql); }
if (m_Reader != NULL) { // // If we are a continuous reader, always wait for the sent io, so that we // can resubmit it later on a restart. // DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, "WDFUSBPIPE %p converting purge action %!WDF_IO_TARGET_PURGE_IO_ACTION!" " to %!WDF_IO_TARGET_PURGE_IO_ACTION!", GetHandle(), Action, WdfIoTargetPurgeIoAndWait);
Action = WdfIoTargetPurgeIoAndWait; }
FxIoTarget::GotoPurgeState(Action, // __super call PendedRequestListHead, SentRequestListHead, Wait, FALSE);
if (m_Reader != NULL) { // // The continuous reader requests are no longer enqueued. Remember that // state, so when we restart, we resend them. // m_Reader->m_ReadersSubmitted = FALSE;
// // Log a message when misbehaved drivers call WdfIoTargetPurge // from EvtUsbTargetPipeReadersFailed callback. // if (m_Reader->m_WorkItemThread == Mx::MxGetCurrentThread()) { DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, "WDFUSBPIPE %p is purged from EvtUsbTargetPipeReadersFailed" " callback", GetHandle());
FxVerifierDbgBreakPoint(pFxDriverGlobals); }
// // Make sure work item is done. It is possible for the upper class // to return wait = false if the list of sent requests is empty. We // still want to wait anyway for making sure work item is not about // to run or it is running. // *Wait = TRUE; }
if (LockSelf) { Unlock(irql); }}
VOIDFxUsbPipe::GotoRemoveState( __in WDF_IO_TARGET_STATE NewState, __in PLIST_ENTRY PendedRequestListHead, __in PSINGLE_LIST_ENTRY SentRequestListHead, __in BOOLEAN LockSelf, __out PBOOLEAN Wait ){ KIRQL irql;
irql = PASSIVE_LEVEL;
if (LockSelf) { Lock(&irql); }
if (m_Reader != NULL && m_Reader->m_ReadersSubmitted && WdfIoTargetStarted == m_State) { // // Driver forgot to stop the pipe on D0Exit. // DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "WDFUSBPIPE %p was not stopped in EvtDeviceD0Exit callback", GetHandle());
if (GetDriverGlobals()->IsVerificationEnabled(1,9,OkForDownLevel)) { FxVerifierDbgBreakPoint(GetDriverGlobals()); } }
FxIoTarget::GotoRemoveState(NewState, // __super call PendedRequestListHead, SentRequestListHead, FALSE, Wait); if (m_Reader != NULL) { // // Make sure work item is done. It is possible for the upper class to // return wait = false if the list of sent requests is empty. We still // want to wait anyway for making sure work item is not about to run or // it is running. // *Wait = TRUE; }
if (LockSelf) { Unlock(irql); }}
VOIDFxUsbPipe::WaitForSentIoToComplete( VOID ){ if (m_Reader != NULL) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFUSBPIPE %p, waiting for continuous reader work item to complete", GetHandle());
// // First, wait for the work item to complete if it is running. // // NOTE: We don't wait for the DPC to complete because // they are flushed in FxUsbDevice::Dispose // m_Reader->m_WorkItem->WaitForExit();
DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFUSBPIPE %p, cancelling for continuous reader (max of %d)", GetHandle(), m_Reader->m_NumReaders);
// // Now that the work item is not running, make sure all the readers are // truly canceled and *NOT* in the pended queue. In between the call to // GotoStopState and here, the work item could have run and retried to // send the I/O. // m_Reader->CancelRepeaters(); }
DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFUSBPIPE %p, waiting for all i/o to complete", GetHandle());
// // Finally, let the parent class wait for all I/O to complete // FxIoTarget::WaitForSentIoToComplete(); // __super call}
_Must_inspect_result_NTSTATUSFxUsbPipe::InitContinuousReader( __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, __in size_t TotalBufferLength ){ FxUsbPipeContinuousReader* pReader; NTSTATUS status; UCHAR numReaders;
pReader = NULL;
if (m_Reader != NULL) { status = STATUS_INVALID_DEVICE_STATE;
DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Continuous reader already initialized on WDFUSBPIPE %p %!STATUS!", GetHandle(), status);
return status; }
numReaders = Config->NumPendingReads;
if (numReaders == 0) { numReaders = NUM_PENDING_READS_DEFAULT; } else if (numReaders > NUM_PENDING_READS_MAX) { numReaders = NUM_PENDING_READS_MAX; }
pReader = new(GetDriverGlobals(), numReaders) FxUsbPipeContinuousReader(this, numReaders);
if (pReader == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
// // Allocate all of the structurs and objects required // status = pReader->Config(Config, TotalBufferLength);
if (!NT_SUCCESS(status)) { delete pReader; return status; }
pReader->m_ReadCompleteCallback = Config->EvtUsbTargetPipeReadComplete; pReader->m_ReadCompleteContext = Config->EvtUsbTargetPipeReadCompleteContext;
pReader->m_ReadersFailedCallback = Config->EvtUsbTargetPipeReadersFailed;
if (InterlockedCompareExchangePointer((PVOID*) &m_Reader, pReader, NULL) == NULL) { // // We set the field, do nothing. // DO_NOTHING(); } else { // // Some other thread came in and set the field, free our allocation. // delete pReader; }
return STATUS_SUCCESS;}
_Must_inspect_result_NTSTATUSFxUsbPipe::_FormatTransfer( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in WDFUSBPIPE Pipe, __in WDFREQUEST Request, __in_opt WDFMEMORY TransferMemory, __in_opt PWDFMEMORY_OFFSET TransferOffsets, __in ULONG Flags ){ FxRequestBuffer buf; IFxMemory* pMemory; FxUsbPipe* pUsbPipe; FxRequest* pRequest; NTSTATUS status;
FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, Pipe, FX_TYPE_IO_TARGET_USB_PIPE, (PVOID*) &pUsbPipe, &FxDriverGlobals);
FxObjectHandleGetPtr(FxDriverGlobals, Request, FX_TYPE_REQUEST, (PVOID*) &pRequest);
// // We allow zero length transfers (which are indicated by TransferMemory == NULL) // if (TransferMemory != NULL) { FxObjectHandleGetPtr(FxDriverGlobals, TransferMemory, IFX_TYPE_MEMORY, (PVOID*) &pMemory);
status = pMemory->ValidateMemoryOffsets(TransferOffsets); if (!NT_SUCCESS(status)) { goto Done; }
buf.SetMemory(pMemory, TransferOffsets); } else { pMemory = NULL; }
status = pUsbPipe->FormatTransferRequest(pRequest, &buf, Flags);
if (NT_SUCCESS(status)) { FxUsbPipeTransferContext* pContext;
pContext = (FxUsbPipeTransferContext*) pRequest->GetContext();
// // By assuming the fields are at the same offset, we can use simpler // logic (w/out comparisons for type) to set them. // WDFCASSERT( FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeWrite.Buffer) == FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeRead.Buffer) );
WDFCASSERT( FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeWrite.Offset) == FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeRead.Offset) );
pContext->m_UsbParameters.Parameters.PipeWrite.Buffer = TransferMemory; pContext->m_UsbParameters.Parameters.PipeWrite.Length = buf.GetBufferLength();
pContext->m_UsbParameters.Parameters.PipeWrite.Offset = (TransferOffsets != NULL) ? TransferOffsets->BufferOffset : 0; pContext->SetUsbType( (Flags & USBD_TRANSFER_DIRECTION_IN) ? WdfUsbRequestTypePipeRead : WdfUsbRequestTypePipeWrite ); }
Done: DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFUSBPIPE %p, WDFREQUEST %p, WDFMEMORY %p, %!STATUS!", Pipe, Request, TransferMemory, status);
return status;}
_Must_inspect_result_NTSTATUSFxUsbPipe::_SendTransfer( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in WDFUSBPIPE Pipe, __in_opt WDFREQUEST Request, __in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions, __in_opt PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, __out_opt PULONG BytesTransferred, __in ULONG Flags ){ FxRequestBuffer buf; FxUsbPipe* pUsbPipe; NTSTATUS status;
FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, Pipe, FX_TYPE_IO_TARGET_USB_PIPE, (PVOID*) &pUsbPipe, &FxDriverGlobals);
FxUsbPipeTransferContext context(FxUrbTypeLegacy);
FxSyncRequest request(FxDriverGlobals, &context, Request);
// // FxSyncRequest always succeesds for KM but can fail for UM. // status = request.Initialize(); if (!NT_SUCCESS(status)) { DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Failed to initialize FxSyncRequest"); return status; }
if (BytesTransferred != NULL) { *BytesTransferred = 0; }
status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); if (!NT_SUCCESS(status)) { return status; }
status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions); if (!NT_SUCCESS(status)) { return status; }
// // We allow zero length writes (which are indicated by MemoryDescriptor == NULL) // if (MemoryDescriptor != NULL) { status = buf.ValidateMemoryDescriptor(FxDriverGlobals, MemoryDescriptor); if (!NT_SUCCESS(status)) { return status; } }
status = pUsbPipe->FormatTransferRequest(request.m_TrueRequest, &buf, Flags);
if (NT_SUCCESS(status)) { DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFUSBPIPE %p, WDFREQUEST %p being submitted", Pipe, request.m_TrueRequest->GetTraceObjectHandle());
status = pUsbPipe->SubmitSync(request.m_TrueRequest, RequestOptions);
// // Even on error we want to set this value. USBD should be clearing // it if the transfer fails. // if (BytesTransferred != NULL) { *BytesTransferred = context.GetUrbTransferLength(); } }
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, "WDFUSBPIPE %p, %!STATUS!", Pipe, status);
return status;}
_Must_inspect_result_NTSTATUSFxUsbPipe::FormatAbortRequest( __in FxRequestBase* Request ){ FxUsbPipeRequestContext* pContext; NTSTATUS status; FX_URB_TYPE urbType;
status = Request->ValidateTarget(this); if (!NT_SUCCESS(status)) { DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Pipe %p, Request %p, setting target failed, " "status %!STATUS!", this, Request, status);
return status; }
if (Request->HasContextType(FX_RCT_USB_PIPE_REQUEST)) { pContext = (FxUsbPipeRequestContext*) Request->GetContext(); } else {
urbType = m_UsbDevice->GetFxUrbTypeForRequest(Request); pContext = new(GetDriverGlobals()) FxUsbPipeRequestContext(urbType); if (pContext == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) if (urbType == FxUrbTypeUsbdAllocated) { status = pContext->AllocateUrb(m_USBDHandle); if (!NT_SUCCESS(status)) { delete pContext; return status; } // // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is // important to release those resorces before the devnode is removed. Those // resoruces are removed at the time Request is disposed. // Request->EnableContextDisposeNotification(); }#endif
Request->SetContext(pContext); }
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) pContext->SetInfo(WdfUsbRequestTypePipeAbort, m_PipeInformation.PipeHandle, URB_FUNCTION_ABORT_PIPE);
if (pContext->m_Urb == &pContext->m_UrbLegacy) { urbType = FxUrbTypeLegacy; } else { urbType = FxUrbTypeUsbdAllocated; }
FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle);#elif (FX_CORE_MODE == FX_CORE_USER_MODE) pContext->SetInfo(WdfUsbRequestTypePipeAbort, m_UsbInterface->m_WinUsbHandle, m_PipeInformationUm.PipeId, UMURB_FUNCTION_ABORT_PIPE); FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbPipeRequest.Hdr, m_UsbDevice->m_pHostTargetFile);#endif
return STATUS_SUCCESS;}
_Must_inspect_result_NTSTATUSFxUsbPipe::FormatResetRequest( __in FxRequestBase* Request ){ FxUsbPipeRequestContext* pContext; NTSTATUS status; FX_URB_TYPE urbType;
status = Request->ValidateTarget(this); if (!NT_SUCCESS(status)) { DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Pipe %p, Request %p, setting target failed, " "status %!STATUS!", this, Request, status);
return status; }
if (Request->HasContextType(FX_RCT_USB_PIPE_REQUEST)) { pContext = (FxUsbPipeRequestContext*) Request->GetContext(); } else { urbType = m_UsbDevice->GetFxUrbTypeForRequest(Request); pContext = new(GetDriverGlobals()) FxUsbPipeRequestContext(urbType); if (pContext == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) if (urbType == FxUrbTypeUsbdAllocated) { status = pContext->AllocateUrb(m_USBDHandle); if (!NT_SUCCESS(status)) { delete pContext; return status; } // // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is // important to release those resorces before the devnode is removed. Those // resoruces are removed at the time Request is disposed. // Request->EnableContextDisposeNotification(); }#endif
Request->SetContext(pContext); }
#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) // // URB_FUNCTION_RESET_PIPE and URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL // are the same value // pContext->SetInfo(WdfUsbRequestTypePipeReset, m_PipeInformation.PipeHandle, URB_FUNCTION_RESET_PIPE);
if (pContext->m_Urb == &pContext->m_UrbLegacy) { urbType = FxUrbTypeLegacy; } else { urbType = FxUrbTypeUsbdAllocated; }
FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle);#elif (FX_CORE_MODE == FX_CORE_USER_MODE) pContext->SetInfo(WdfUsbRequestTypePipeReset, m_UsbInterface->m_WinUsbHandle, m_PipeInformationUm.PipeId, UMURB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL); FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbPipeRequest.Hdr, m_UsbDevice->m_pHostTargetFile);#endif
return STATUS_SUCCESS;}
NTSTATUSFxUsbPipe::Reset( VOID ){ FxUsbPipeRequestContext context(FxUrbTypeLegacy);
FxSyncRequest request(GetDriverGlobals(), &context); NTSTATUS status;
// // FxSyncRequest always succeesds for KM but can fail for UM. // status = request.Initialize(); if (!NT_SUCCESS(status)) { DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Failed to initialize FxSyncRequest"); return status; }
status = FormatResetRequest(request.m_TrueRequest); if (NT_SUCCESS(status)) { if (m_Reader != NULL) { // // This assumes that no other I/O besides reader I/O is going on. // m_Reader->CancelRepeaters(); } else { CancelSentIo(); } status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL); } return status;}