VOID FxPkgIo::AddIoQueue( __inout FxIoQueue* IoQueue ) { PLIST_ENTRY listHead, le; FxIoQueue* queue; KIRQL irql; FxIoQueueNode* listNode; CCHAR queueIndex, curIndex; listHead = &m_IoQueueListHead; queueIndex = FxDevice::GetCxDriverIndex(IoQueue->GetCxDeviceInfo()); Lock(&irql); ASSERT(IoQueue->m_IoPkgListNode.IsNodeType(FxIoQueueNodeTypeQueue)); // // Insert new queue in sorted list; search from last to first. // for (le = listHead->Blink; le != listHead; le = le->Blink) { // // Skip any nodes that are not queues. They can be bookmarks for // in-progress flush operations. // listNode = FxIoQueueNode::_FromListEntry(le); if (listNode->IsNodeType(FxIoQueueNodeTypeQueue) == FALSE) { continue; } // // Get current queue's driver index. // queue = FxIoQueue::_FromIoPkgListEntry(le); curIndex = FxDevice::GetCxDriverIndex(queue->GetCxDeviceInfo()); // // Queues are inserted in order at the end of its allowed range. // if (curIndex < queueIndex || curIndex == queueIndex) { break; } } InsertHeadList(le, &IoQueue->m_IoPkgListNode.m_ListEntry); if (m_PowerStateOn) { IoQueue->SetPowerState(FxIoQueuePowerOn); } else { IoQueue->SetPowerState(FxIoQueuePowerOff); if (m_QueuesAreShuttingDown) { // Clear accept requests IoQueue->SetStateForShutdown(); } } Unlock(irql); return; }
NTSTATUS WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( __in PWDF_DRIVER_GLOBALS DriverGlobals, __in WDFDEVICE Device, __in MdIrp Irp, __in WDFQUEUE Queue, __in ULONG Flags ) { FxIoQueue *queue; FxDevice *device; PFX_DRIVER_GLOBALS fxDriverGlobals; PIO_STACK_LOCATION stack; NTSTATUS status; FxIoInCallerContext* ioInCallerCtx; queue = NULL; ioInCallerCtx = NULL; FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), Device, FX_TYPE_DEVICE, (PVOID*) &device); fxDriverGlobals = device->GetDriverGlobals(); FX_TRACK_DRIVER(fxDriverGlobals); FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), Queue, FX_TYPE_QUEUE, (PVOID*)&queue); FxPointerNotNull(fxDriverGlobals, Irp); // // If the caller is a preprocess routine, the contract for this DDI is just like IoCallDriver. // The caller sets up their stack location and then the DDI advances to the next stack // location. This means that the caller either has to call IoSkipCurrentIrpStackLocation // or IoCopyCurrentIrpStackLocationToNext before calling this DDI. // if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP) { IoSetNextIrpStackLocation(Irp); } // // Verifier checks. // status = VerifyWdfDeviceWdmDispatchIrpToIoQueue(fxDriverGlobals, device, Irp, queue, Flags); if(!NT_SUCCESS(status)) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } // // Adjust stack if IRP needs to be forwarded to parent device. // if (device->m_ParentDevice == queue->GetDevice()) { IoCopyCurrentIrpStackLocationToNext(Irp); IoSetNextIrpStackLocation(Irp); // // From now on use new device. // device = device->m_ParentDevice; // // Save a pointer to the device object for this request so that it can // be used later in completion. // stack = IoGetCurrentIrpStackLocation(Irp); stack->DeviceObject = device->GetDeviceObject(); } // // Get in-context caller callback if required. // if (Flags & WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK) { ioInCallerCtx = device->m_PkgIo->GetIoInCallerContextCallback( queue->GetCxDeviceInfo()); } // // DispatchStep2 will convert the IRP into a WDFREQUEST, queue it and if // possible dispatch the request to the driver. // return device->m_PkgIo->DispatchStep2(Irp, ioInCallerCtx, queue); }
VOID FxIoTargetSelf::Send( _In_ MdIrp Irp ) /*++ Routine Description: send an MdIrp to the Self IO Target. Arguments: MdIrp for IRP_MJ_READ, IRP_MJ_WRITE, or IRP_MJ_DEVICE_CONTROL Returns: VOID Implementation Note: Function body inspired by WdfDeviceWdmDispatchIrpToIoQueue API. --*/ { FxIrp irp(Irp); FxIoQueue* queue; NTSTATUS status; UCHAR majorFunction; FxIoInCallerContext* ioInCallerCtx; #if (FX_CORE_MODE == FX_CORE_USER_MODE) // // Prepare the request to forward to the inteternal target. // (static_cast<IWudfIoIrp2*>(Irp))->PrepareToForwardToSelf(); #else // // Set Next Stack Location // irp.SetNextIrpStackLocation(); // // Set Device Object. // irp.SetCurrentDeviceObject(m_Device->GetDeviceObject()); #endif majorFunction = irp.GetMajorFunction(); // // Retrieve Queue // queue = GetDispatchQueue(majorFunction); if (queue == NULL) { DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Send WDFIOTARGET %p, No Dispatch Queue Found for Major Function %d", GetObjectHandle(), majorFunction); status = STATUS_INVALID_DEVICE_STATE; goto Fail; } // // Only read/writes/ctrls/internal_ctrls IRPs are allowed to be sent to // Self IO Target // if (m_Device->GetDispatchPackage(majorFunction) != m_Device->m_PkgIo) { status = STATUS_INVALID_PARAMETER; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, "Only Read/Write/Control/Internal-Control IRPs can be " "forwarded to Self IO Target 0x%p, %!IRPMJ!, " "IRP_MN %x, Device 0x%p, %!STATUS!", GetHandle(), majorFunction, irp.GetMinorFunction(), m_Device->GetObjectHandle(), status); FxVerifierDbgBreakPoint(GetDriverGlobals()); goto Fail; } // // Retrieve the InContextCallback function // ioInCallerCtx = m_Device->m_PkgIo->GetIoInCallerContextCallback( queue->GetCxDeviceInfo()); // // DispatchStep2 will convert the IRP into a WDFREQUEST, queue it and if // possible dispatch the request to the driver. // If a failure occurs, DispatchStep2 completes teh Irp // (VOID) m_Device->m_PkgIo->DispatchStep2(Irp, ioInCallerCtx, queue); return; Fail: irp.SetStatus(status); irp.SetInformation(0); irp.CompleteRequest(IO_NO_INCREMENT); return; }
FORCEINLINE _Must_inspect_result_ NTSTATUS __fastcall FxPkgIo::DispatchStep1( __inout MdIrp Irp, __in WDFCONTEXT DispatchContext ) /*++ Routine Description: Checks for any registered dynamic dispatch callbacks that handles this type of request, else selects the default queue based on the IRP's major code. Arguments: Irp - WDM request. DispatchContext - Is the next FxIrpDynamicDispatchInfo element. Return Value: Irp's status. --*/ { NTSTATUS status; FxIrp fxIrp(Irp); ASSERT(((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); ASSERT(fxIrp.GetMajorFunction() <= IRP_MJ_MAXIMUM_FUNCTION); // // Look for I/O dynamic dispatch callbacks. // if ((PLIST_ENTRY)DispatchContext != &m_DynamicDispatchInfoListHead) { int index; index = FxIrpDynamicDispatchInfo::Mj2Index(fxIrp.GetMajorFunction()); // // Only read/writes/ctrls/internal_ctrls IRPs are allowed, i.e., request cannot // IRP type in its callback. // if (index >= (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax) { status = STATUS_INVALID_PARAMETER; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, "Driver cannot change the IRP type in its dispatch " "callback Irp 0x%p, %!IRPMJ!, IRP_MN %x, Device 0x%p, " "%!STATUS!", Irp, fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), m_Device->GetHandle(), status); FxVerifierDbgBreakPoint(GetDriverGlobals()); goto CompleteIrp; } // // Verifier checks. // status = VerifyDispatchContext(GetDriverGlobals(), DispatchContext); if( !NT_SUCCESS(status)) { goto CompleteIrp; } do { FxIrpDynamicDispatchInfo* info; info = CONTAINING_RECORD(DispatchContext, FxIrpDynamicDispatchInfo, ListEntry); // // Advance to next node. // DispatchContext = (WDFCONTEXT)(((PLIST_ENTRY)DispatchContext)->Flink); ASSERT(((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); ASSERT(fxIrp.GetMajorFunction() == IRP_MJ_READ || fxIrp.GetMajorFunction() == IRP_MJ_WRITE || fxIrp.GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || fxIrp.GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); // // If registered, invoke dispatch callback for this major function. // ASSERT(index < (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax); if (NULL != info->Dispatch[index].EvtDeviceDynamicDispatch) { return info->Dispatch[index].EvtDeviceDynamicDispatch( m_Device->GetHandle(), fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), fxIrp.GetParameterIoctlCode(), info->Dispatch[index].DriverContext, reinterpret_cast<PIRP> (fxIrp.GetIrp()), (WDFCONTEXT)((ULONG_PTR)DispatchContext | FX_IN_DISPATCH_CALLBACK) ); } } while ((PLIST_ENTRY)DispatchContext != &m_DynamicDispatchInfoListHead); } // // Only now push these local variables on the stack, this is to keep the // stack from growing unnecessarily in the dynamic dispatch path above. // FxIoQueue* queue; FxIoInCallerContext* ioInCallerCtx; // // Get the queue from the dispatch-table // queue = m_DispatchTable[fxIrp.GetMajorFunction()]; if (queue == NULL) { ioInCallerCtx = GetIoInCallerContextCallback(NULL); if (ioInCallerCtx->m_Method == NULL) { // // No queue configured yet, fail request unless the driver is a filter. // if (m_Filter) { goto Forward; } status = STATUS_INVALID_DEVICE_REQUEST; DoTraceLevelMessage( GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, "No queue configured for WDFDEVICE 0x%p, failing IRP 0x%p," " %!STATUS!", m_Device->GetHandle(), Irp, status); goto CompleteIrp; } } else { ioInCallerCtx = GetIoInCallerContextCallback(queue->GetCxDeviceInfo()); } // // If the driver is filter and queue is a default-queue then before // calling the queue, we should make sure the queue can dispatch // requests to the driver. If the queue cannot dispatch request, // we should forward it down to the lower driver ourself. // This is to cover the scenario where the driver has registered only // type specific handler and expect the framework to auto-forward other // requests. // if (m_Filter && ioInCallerCtx->m_Method == NULL && queue == m_DefaultQueue && queue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)fxIrp.GetMajorFunction()) == FALSE) { // // Default queue doesn't have callback events registered to // handle this request. So forward it down. // goto Forward; } // // Finally queue request. // return DispatchStep2(Irp, ioInCallerCtx, queue); Forward: fxIrp.SkipCurrentIrpStackLocation(); return fxIrp.CallDriver(m_Device->GetAttachedDevice()); CompleteIrp: fxIrp.SetStatus(status); fxIrp.SetInformation(0); fxIrp.CompleteRequest(IO_NO_INCREMENT); return status; }