/*++ Copyright (c) Microsoft Corporation Module Name: FxPkgIo.hpp Abstract: This module implements the I/O package for the driver frameworks. Author: Environment: Both kernel and user mode Revision History: --*/ #ifndef _FXPKGIO_H_ #define _FXPKGIO_H_ #include "fxpkgioshared.hpp" #include "fxirpdynamicdispatchinfo.hpp" #include "fxdevicecallbacks.hpp" #include "fxcxdeviceinfo.hpp" // // This flag is or-ed with a pointer value that is ptr aligned, only lower 2 bits are available. // #define FX_IN_DISPATCH_CALLBACK 0x00000001 enum FxIoIteratorList { FxIoQueueIteratorListInvalid = 0, FxIoQueueIteratorListPowerOn, FxIoQueueIteratorListPowerOff, }; #define IO_ITERATOR_FLUSH_TAG (PVOID) 'sulf' #define IO_ITERATOR_POWER_TAG (PVOID) 'ewop' // // This class is allocated by the driver frameworks manager // PER DEVICE, and is not package global, but per device global, // data. // // This is similar to the NT DeviceExtension. // class FxPkgIo : public FxPackage { private: FxIoQueue* m_DefaultQueue; // // This is the list of IoQueue objects allocated by the driver // and associated with this device. The IoPackage instance // will release these references automatically when the device // is removed. // LIST_ENTRY m_IoQueueListHead; // // This is the forwarding table // FxIoQueue* m_DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1]; // // This is the seed value used to pass to the // FxRandom for testing forward progress // ULONG m_RandomSeed; // TRUE if behave as a filter (forward default requests) BOOLEAN m_Filter; BOOLEAN m_PowerStateOn; // // TRUE if queues are shutting down (surprise_remove/remove in progress). // BOOLEAN m_QueuesAreShuttingDown; // // We'll maintain the dynamic dispatch table "per device" so that it is possible // to have different callbacks for each device. // Note that each device may be associted with multiple class extension in the future. // LIST_ENTRY m_DynamicDispatchInfoListHead; // // If !=NULL, a pre-process callback was registered // FxIoInCallerContext m_InCallerContextCallback; public: FxPkgIo( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in CfxDevice *Device ); ~FxPkgIo(); // // Package manager dispatch entries // _Must_inspect_result_ virtual NTSTATUS Dispatch( __inout MdIrp Irp ); // // Returns the Top level queue for the Io based on the Irp MajorFunction // FxIoQueue* GetDispatchQueue( _In_ UCHAR MajorFunction ) { return m_DispatchTable[MajorFunction]; } // Do not specify argument names FX_DECLARE_VF_FUNCTION_P1( NTSTATUS, VerifyDispatchContext, _In_ WDFCONTEXT ); // // Api's supplied by this package // _Must_inspect_result_ NTSTATUS __fastcall DispatchStep1( __inout MdIrp Irp, __in WDFCONTEXT DispatchContext ); _Must_inspect_result_ NTSTATUS __fastcall DispatchStep2( __inout MdIrp Irp, __in_opt FxIoInCallerContext* IoInCallerCtx, __in_opt FxIoQueue* Queue ); /*++ Routine Description: Initializes the default queue, and allows the driver to pass configuration information. The driver callbacks registered in this call are used to supply the callbacks for the driver default I/O queue. Arguments: hDevice - Pointer Device Object Return Value: NTSTATUS --*/ _Must_inspect_result_ NTSTATUS InitializeDefaultQueue( __in CfxDevice * Device, __inout FxIoQueue * Queue ); // // Register the I/O in-caller context callback // __inline VOID SetIoInCallerContextCallback( __inout PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext ) { m_InCallerContextCallback.m_Method = EvtIoInCallerContext; } // Do not specify argument names FX_DECLARE_VF_FUNCTION_P2( NTSTATUS, VerifyEnqueueRequestUpdateFlags, _In_ FxRequest*, _Inout_ SHORT* ); // Do not specify argument names FX_DECLARE_VF_FUNCTION_P2( VOID, VerifyEnqueueRequestRestoreFlags, _In_ FxRequest*, _In_ SHORT ); // // Enqueue a request to the I/O processing pipeline // from the device driver // _Must_inspect_result_ NTSTATUS EnqueueRequest( __in CfxDevice* Device, __inout FxRequest* pRequest ); FxDriver* GetDriver( VOID ); __inline CfxDevice* GetDevice( VOID ) { return m_Device; } __inline FxIoQueue* GetDefaultQueue( VOID ) { return m_DefaultQueue; } __inline BOOLEAN IsFilter( VOID ) { return m_Filter; } // // This is called as a result of a power management state // that requests that all I/O in progress stop. // // // FxIoStopProcessingForPowerHold: // the function returns when the driver has acknowledged that it has // stopped all I/O processing, but may have outstanding "in-flight" requests // that have not been completed. // // FxIoStopProcessingForPowerPurge: // the function returns when all requests have been completed and/or // cancelled., and there are no more in-flight requests. // // Any queues not marked as PowerManaged will be left alone. // // This is called on a PASSIVE_LEVEL thread that can block until // I/O has been stopped, or completed/cancelled. // _Must_inspect_result_ NTSTATUS StopProcessingForPower( __in FxIoStopProcessingForPowerAction Action ); // // This is called to start, or resume processing when PNP/Power // resources have been supplied to the device driver. // // The driver is notified of resumption for any in-flight I/O. // _Must_inspect_result_ NTSTATUS ResumeProcessingForPower(); // // This is called on a device which has been restarted from the removed // state. It will reset purged queues so that they can accept new requests // when ResumeProcessingForPower is called afterwards. // VOID ResetStateForRestart( VOID ); // // Called by CfxDevice when WdfDeviceSetFilter is called. // _Must_inspect_result_ NTSTATUS SetFilter( __in BOOLEAN Value ); // // Create an IoQueue and associate it with the FxIoPkg per device // instance. // _Must_inspect_result_ NTSTATUS CreateQueue( __in PWDF_IO_QUEUE_CONFIG Config, __in PWDF_OBJECT_ATTRIBUTES QueueAttributes, __in_opt FxDriver* Caller, __deref_out FxIoQueue** ppQueue ); VOID RemoveQueueReferences( __inout FxIoQueue* pQueue ); _Must_inspect_result_ NTSTATUS ConfigureDynamicDispatching( __in UCHAR MajorFunction, __in_opt FxCxDeviceInfo* CxDeviceInfo, __in PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDispatch, __in_opt WDFCONTEXT DriverContext ); _Must_inspect_result_ NTSTATUS ConfigureForwarding( __inout FxIoQueue* TargetQueue, __in WDF_REQUEST_TYPE RequestType ); _Must_inspect_result_ NTSTATUS FlushAllQueuesByFileObject( __in MdFileObject FileObject ); __inline VOID RequestCompletedCallback( __in FxRequest* Request ) { UNREFERENCED_PARAMETER(Request); // // If this is called, the driver called WDFREQUEST.Complete // from the PreProcess callback handler. // // Since we have a handler, the FXREQUEST object will // dereference itself upon return from this callback, which // will destroy the final reference count. // } __inline BOOLEAN IsTopLevelQueue( __in FxIoQueue* Queue ) { UCHAR index; for (index = 0; index <= IRP_MJ_MAXIMUM_FUNCTION; index++) { if (m_DispatchTable[index] == Queue) { return TRUE; } } return FALSE; } NTSTATUS DispathToInCallerContextCallback( __in FxIoInCallerContext *InCallerContextInfo, __in FxRequest *Request, __inout MdIrp Irp ); __inline FxIoInCallerContext* GetIoInCallerContextCallback( __in_opt FxCxDeviceInfo* CxDeviceInfo ) { if (CxDeviceInfo != NULL) { return &CxDeviceInfo->IoInCallerContextCallback; } else { return &m_InCallerContextCallback; } } private: VOID AddIoQueue( __inout FxIoQueue* IoQueue ); VOID RemoveIoQueue( __inout FxIoQueue* IoQueue ); FxIoQueue* GetFirstIoQueueLocked( __in FxIoQueueNode* QueueBookmark, __in PVOID Tag ); FxIoQueue* GetNextIoQueueLocked( __in FxIoQueueNode* QueueBookmark, __in PVOID Tag ); VOID GetIoQueueListLocked( __in PSINGLE_LIST_ENTRY SListHead, __inout FxIoIteratorList ListType ); _Must_inspect_result_ NTSTATUS VerifierFreeRequestToTestForwardProgess( __in FxRequest* Request ); }; #endif // _FXPKGIO_H