/*++ Copyright (c) Microsoft Corporation Module Name: FxDevice.hpp Abstract: This is the definition of the FxDevice object. Author: Environment: Both kernel and user mode Revision History: --*/ #ifndef _FXDEVICE_H_ #define _FXDEVICE_H_ #include "fxcxdeviceinit.hpp" #include "fxdeviceinit.hpp" #include "fxtelemetry.hpp" struct FxWdmDeviceExtension { #if (FX_CORE_MODE == FX_CORE_USER_MODE) WUDF_IO_REMOVE_LOCK IoRemoveLock; #else IO_REMOVE_LOCK IoRemoveLock; #endif ULONG RemoveLockOptionFlags; }; // // The following enum is used in serializing packet based DMA transactions. // According to the DDK docs: // Only one DMA request can be queued for a device object at any // one time. Therefore, the driver should not call AllocateAdapterChannel // again for another DMA operation on the same device object until the // AdapterControl routine has completed execution. In addition, // a driver must not call AllocateAdapterChannel from within its // AdapterControl routine. // // This is because when AllocateAdapterChannel blocks waiting for // map registers, it obtains its wait context block from the device object. // If AllocateAdapterChannel is then called through a different adapter // object attached to the same device the wait block will be reused and the // map register wait list will be corrupted. // // For this reason, we need to make sure that for a device used in creating // DMA enablers, there can be only one packet base DMA transaction // queued at any one time. // // In WDM, one can workaround this limitation by creating dummy deviceobject. // We can also workaround this limitation by creating a control-device on the // side for additional enabler objects. Since packet based multi-channel // devices are rarity these days, IMO, we will defer this feature until there // is a big demand for it. // enum FxDmaPacketTransactionStatus { FxDmaPacketTransactionCompleted =0, FxDmaPacketTransactionPending, }; // // The following enum is used in determining whether the RemLock for a device // object needs to be held while processing an IRP. For processing certain // IRPs, it might not be necessary to hold the RemLock, but it might be // necessary to just test whether the RemLock can be acquired and released. // enum FxDeviceRemLockAction { FxDeviceRemLockNotRequired = 0, FxDeviceRemLockRequired, FxDeviceRemLockTestValid, FxDeviceRemLockOptIn }; enum FxPropertyType { FxDeviceProperty = 0, FxInterfaceProperty, }; // // This mask is used to validate the WdfDeviceWdmDispatchIrp's Flags. // #define FX_DISPATCH_IRP_TO_IO_QUEUE_FLAGS_MASK \ (WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK |\ WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP) // // The following inline functions are used for extracting the normalized file // object class value and checking the file object class's flags. // WDF_FILEOBJECT_CLASS __inline FxFileObjectClassNormalize( __in WDF_FILEOBJECT_CLASS FileObjectClass ) { return (WDF_FILEOBJECT_CLASS)(FileObjectClass & ~WdfFileObjectCanBeOptional); } BOOLEAN __inline FxIsFileObjectOptional( __in WDF_FILEOBJECT_CLASS FileObjectClass ) { return (FileObjectClass & WdfFileObjectCanBeOptional) ? TRUE : FALSE; } // // Base class for all devices. // class FxDeviceBase : public FxNonPagedObject, public IFxHasCallbacks { protected: FxDeviceBase( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in FxDriver* Driver, __in WDFTYPE Type, __in USHORT Size ); ~FxDeviceBase( VOID ); VOID Init( __in MdDeviceObject DeviceObject, __in MdDeviceObject AttachedDevice, __in MdDeviceObject PhysicalDevice ); public: NTSTATUS ConfigureConstraints( __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes ); // begin IFxHasCallbacks overrides VOID GetConstraints( __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel, __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope ) ; FxCallbackLock* GetCallbackLockPtr( __out_opt FxObject** LockObject ); // end IFxHasCallbacks overrides __inline FxDriver* GetDriver( VOID ) { return m_Driver; } MdDeviceObject __inline GetDeviceObject( VOID ) { return m_DeviceObject.GetObject(); } __inline MxDeviceObject* GetMxDeviceObject( VOID ) { return &m_DeviceObject; } ULONG __inline GetDeviceObjectFlags( VOID ) { return m_DeviceObject.GetFlags(); } VOID __inline SetDeviceObjectFlags( _In_ ULONG Flags ) { m_DeviceObject.SetFlags(Flags); } MdDeviceObject __inline GetAttachedDevice( VOID ) { return m_AttachedDevice.GetObject(); } ULONG __inline GetAttachedDeviceObjectFlags( VOID ) { return m_AttachedDevice.GetFlags(); } MdDeviceObject __inline GetPhysicalDevice( VOID ) { return m_PhysicalDevice.GetObject(); } WDFDEVICE __inline GetHandle( VOID ) { return (WDFDEVICE) GetObjectHandle(); } virtual _Must_inspect_result_ NTSTATUS AddIoTarget( __inout FxIoTarget* IoTarget ) { UNREFERENCED_PARAMETER(IoTarget); // // Intentionally does nothing // return STATUS_SUCCESS; } virtual VOID RemoveIoTarget( __inout FxIoTarget* IoTarget ) { // // Intentionally does nothing // UNREFERENCED_PARAMETER(IoTarget); } virtual _Must_inspect_result_ NTSTATUS AllocateEnumInfo( VOID ) { return STATUS_SUCCESS; } virtual VOID AddChildList( __inout FxChildList* List ) { // // Intentionally does nothing // UNREFERENCED_PARAMETER(List); } virtual VOID RemoveChildList( __inout FxChildList* List ) { // // Intentionally does nothing // UNREFERENCED_PARAMETER(List); } virtual _Must_inspect_result_ NTSTATUS AllocateDmaEnablerList( VOID ) { return STATUS_SUCCESS; } virtual VOID AddDmaEnabler( __inout FxDmaEnabler* Enabler ) { // // Intentionally does nothing // UNREFERENCED_PARAMETER(Enabler); } virtual VOID RemoveDmaEnabler( __inout FxDmaEnabler* Enabler ) { // // Intentionally does nothing // UNREFERENCED_PARAMETER(Enabler); } virtual VOID SetDeviceTelemetryInfoFlags( _In_ FxDeviceInfoFlags Flag ) { // // Intentionally does nothing // UNREFERENCED_PARAMETER(Flag); } __inline _Must_inspect_result_ NTSTATUS AcquireDmaPacketTransaction( VOID ) { // // Set the status to Pending only if the previous transaction is Completed. // if (InterlockedCompareExchange( &m_DmaPacketTransactionStatus, FxDmaPacketTransactionPending, FxDmaPacketTransactionCompleted) == FxDmaPacketTransactionCompleted) { return STATUS_SUCCESS; } else { return STATUS_WDF_BUSY; } } __inline VOID ReleaseDmaPacketTransaction( VOID ) { LONG val; val = InterlockedExchange(&m_DmaPacketTransactionStatus, FxDmaPacketTransactionCompleted); ASSERT(val == FxDmaPacketTransactionPending); // To catch double release UNREFERENCED_PARAMETER(val); } VOID AddToDisposeList( __inout FxObject* Object ) { m_DisposeList->Add(Object); } // begin FxObject overrides _Must_inspect_result_ NTSTATUS QueryInterface( __inout FxQueryInterfaceParams* Params ); // end FxObject overrides static FxDeviceBase* _SearchForDevice( __in FxObject* Object, __out_opt IFxHasCallbacks** Callbacks ); static FxDeviceBase* _SearchForDevice( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in_opt PWDF_OBJECT_ATTRIBUTES Attributes ); _Must_inspect_result_ NTSTATUS QueryForInterface( __in const GUID* InterfaceType, __out PINTERFACE Interface, __in USHORT Size, __in USHORT Version, __in PVOID InterfaceSpecificData, __in_opt MdDeviceObject TargetDevice = NULL ); __inline MdDeviceObject GetAttachedDeviceReference( VOID ) { return Mx::MxGetAttachedDeviceReference(m_DeviceObject.GetObject()); } virtual FxIoTarget* GetDefaultIoTarget( VOID ) { return NULL; } _Must_inspect_result_ NTSTATUS AllocateTarget( _Out_ FxIoTarget** Target, _In_ BOOLEAN SelfTarget ); // // Note: these fields are carefully aligned to minimize space. If you add // additional fields make sure to insert them correctly. Always // double check your assumptions by loading the amd64 image and // comparing the size of this type before and after. For example the // m_RequestLookasideList is aligned on SYSTEM_CACHE_ALIGNMENT_SIZE (64/128), // a simple change can increase the size by 64/128 bytes. // public: // // This is used to defer items that must be cleaned up at passive // level, and FxDevice waits on this list to empty in DeviceRemove. // FxDisposeList* m_DisposeList; protected: FxDriver* m_Driver; MxDeviceObject m_DeviceObject; MxDeviceObject m_AttachedDevice; MxDeviceObject m_PhysicalDevice; FxCallbackLock* m_CallbackLockPtr; FxObject* m_CallbackLockObjectPtr; WDF_EXECUTION_LEVEL m_ExecutionLevel; WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope; // // Used to serialize packet dma transactions on this device. // LONG m_DmaPacketTransactionStatus; }; class FxDevice : public FxDeviceBase { friend VOID GetTriageInfo(VOID); friend class FxDriver; friend class FxIrp; friend class FxFileObject; friend class FxPkgPnp; // // Note: these fields are carefully aligned to minimize space. If you add // additional fileds make sure to insert them correctly. Always // double check your assumptions by loading the amd64 image and // comparing the size of this type before and after. For example the // m_RequestLookasideList is aligned on SYSTEM_CACHE_ALIGNMENT_SIZE (64/128), // a simple change can increase the size by 64/128 bytes. // private: // // Maintain the current device states. // WDF_DEVICE_PNP_STATE m_CurrentPnpState; WDF_DEVICE_POWER_STATE m_CurrentPowerState; WDF_DEVICE_POWER_POLICY_STATE m_CurrentPowerPolicyState; // // Store the IO type for read/write // WDF_DEVICE_IO_TYPE m_ReadWriteIoType; // // Bit-flags, see FxDeviceCallbackFlags for definitions. // BYTE m_CallbackFlags; // TRUE if a Filter BOOLEAN m_Filter; // // If TRUE, DO_POWER_PAGABLE can be set on m_DeviceObject->Flags if we are // not in a special usage path. // // ***Ignored for filters*** // BOOLEAN m_PowerPageableCapable; // // TRUE if the parent is removed while the child is still around // BOOLEAN m_ParentWaitingOnChild; // // TRUE if the device only allows one create to succeed at any given time // BOOLEAN m_Exclusive; // // More deterministic the m_PkgPnp == NULL since m_PkgPnp can be == NULL // if there is an allocation failure and during deletion due to insufficient // resources we need to know if the device is legacy or not. // BOOLEAN m_Legacy; // // If TRUE, m_DeviceObject was deleted in FxDevice::DeleteObject and should // not be deleted again later in the destroy path. // BOOLEAN m_DeviceObjectDeleted; // // This boost will be used in IoCompleteRequest // for read, write and ioctl requests if the client driver // completes the request without specifying the boost. // // CHAR m_DefaultPriorityBoost; static const CHAR m_PriorityBoosts[]; public: // // Track the parent if applicable // CfxDevice *m_ParentDevice; // // Properties used during Device Creation // // // Store the device name that is used during device creation. // UNICODE_STRING m_DeviceName; UNICODE_STRING m_SymbolicLinkName; // // Store the name of the resource that is used to store the MOF data // UNICODE_STRING m_MofResourceName; // // When reporting a PDO via query device relations, there is a period of // time where it is an "official" PDO as recognized by the pnp subsystem. // In that period of time, we cannot use the soon to be PDO in any export // which expects a PDO as an input parameter. Once this is set to TRUE, // the PDO can be used for such exports. // // No need to use a lock when comparing against this field. Once set, it // will never revert back to FALSE. // // This field is always TRUE for FDOs (in relation to the PDO for its stack). // BOOLEAN m_PdoKnown; // // If TRUE, then create/cleanup/close are forwarded down the stack // If FALSE, then create/cleanup/close are completed at this device // BOOLEAN m_AutoForwardCleanupClose; // // If TRUE, an Io Target to the client itself is created to support // Self Io Targets. // BOOLEAN m_SelfIoTargetNeeded; private: // // bit-map of device info for Telemetry // USHORT m_DeviceTelemetryInfoFlags; public: WDF_FILEOBJECT_CLASS m_FileObjectClass; FxSpinLockTransactionedList m_IoTargetsList; // // We'll maintain the prepreocess 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_PreprocessInfoListHead; // // Optional, list of additional class extension settings. // LIST_ENTRY m_CxDeviceInfoListHead; protected: // // This is used by the FxFileObject class to manage // the list of FxFileObject's for this FxDevice // LIST_ENTRY m_FileObjectListHead; // // Lookaside list to allocate FxRequests from // NPAGED_LOOKASIDE_LIST m_RequestLookasideList; // // Total size of an FxRequest + driver context LookasideList element. // size_t m_RequestLookasideListElementSize; // // Object attributes to apply to each FxRequest* returned by // m_RequestLookasideList // WDF_OBJECT_ATTRIBUTES m_RequestAttributes; public: // // This is the set of packages used by this device. I am simply using // FxPackage pointers rather than using the actual types because I want // to allow fredom for FDOs, PDOs, and control objects to use // differnet packages. // FxPkgIo* m_PkgIo; FxPkgPnp* m_PkgPnp; FxPkgGeneral* m_PkgGeneral; FxWmiIrpHandler* m_PkgWmi; FxDefaultIrpHandler* m_PkgDefault; // // Note on approaches to having mode-agnoctic code that works for KM and UM // and avoids code with lots of #ifdef which becomes a maintenance nightmare. // To avoid #ifdef such as below, one approach would have been to have a // base class with common data members and virtual funtions , and have // derived classes for km and um,each having data members specific to their // mode, implementing virtual funcions in mode specific manner. This // approach was not taken for following reasons: // // 1. Avoid confusion between logical hierarchy and organizational hierarchy // of objects. E.g. fdo and pdo package is derived from pnp package (logical // hierarchy). However, both pdo and fdo package can also be organized into // fdokm/fdoum deriving from fdo, and pdokm/pdoum deriving from pdo for km // and um flavors, and that would be organizational hierarchy. Mixing these // two approaches may create more confusion. If we were to extend the // classes in future (for whatever reason), this may become more complex. // // 2. Even with organizational hierarchy, we need to have #ifdef at the // point of creation. // // Luckily, we don't have many objects that need to be have mode specific // data members (currently only FxDevice and interrupt to some extent). // Note that member functions are already implemented in mode specific // manner, for example, FxDevice::CreateDevice is implemented for UM and KM // in FxDeviceUm.cpp and FxDeviceKm.cpp. So #ifdef usage is not a whole lot // but we can definitely improve on it. // // With the current approach, we can do better by avoiding #ifdef as much as // possible. We can achieve that with better abstraction, but also having // host provide more interfaces so as to mimic closely those interfaces // that kernel provides would also help (this way framework has to maintain // less info, because it can always get it from host the way kernel // framework would). // #if (FX_CORE_MODE == FX_CORE_USER_MODE) public: // // On failed create during AddDevice, KMDF sends a simulated remove event // to pnp state machine and thereafter detaches from stack so that windows // I/O manager can't send a remove irp. UMDF imitates windows I/O manager // in that when AddDevice sent by host is failed by driver, host sends a // simulated remove irp to Fx so that it can cleanup. // // This causes a conflict in merged code because for UMDF, Fx doesn't // detach from stack as part of remove event (since lifetime of umdf stack // is controlled by host including detach and deletiton), so unless we // prevent, Fx will end up processing remove event twice, once by Pnp sm's // simulated event and another by host simulated remove irp. // // The solution is to allow one remove event to be processed and that would // be Fx's remove event (to minimize disparity between KM and UM Fx). The // field below tracks the fact that create failed and allows the Fx remove // event to be processed and then also allows the device object to detach // before returning from failure so that host is not able to send simulated // remove to the device. // BOOLEAN m_CleanupFromFailedCreate; // // This object implements the IFxMessageDispatch that contains entry points // to driver, and is used by host to dispatch irp and other messages. // FxMessageDispatch* m_Dispatcher; // //Weak reference to host side device stack // IWudfDeviceStack* m_DevStack; // // PnP devinode hw key handle // HKEY m_PdoDevKey; // // Device key registry path // PWSTR m_DeviceKeyPath; // // Kernel redirector's side object name. // PWSTR m_KernelDeviceName; // // PDO Instance ID // PWSTR m_DeviceInstanceId; // // The retrieval mode and i/o type preferences requested // by this device. Note that ReadWriteIoType is common to both KMDF and UMDF // so no new UM-specific field is required. // UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL m_RetrievalMode; WDF_DEVICE_IO_TYPE m_IoctlIoType; ULONG m_DirectTransferThreshold; // // Tells whether hardware access is allowed. // WDF_DIRECT_HARDWARE_ACCESS_TYPE m_DirectHardwareAccess; // // Tells whether hardware register read/write is done using user-mode // mapped virtual addresses // WDF_REGISTER_ACCESS_MODE_TYPE m_RegisterAccessMode; // // File object policy set through INF directive // WDF_FILE_OBJECT_POLICY_TYPE m_FileObjectPolicy; // // Fs context use policy set through INF directive // WDF_FS_CONTEXT_USE_POLICY_TYPE m_FsContextUsePolicy; // // Thread pool for interrupt servicing // FxInterruptThreadpool* m_InteruptThreadpool; #endif // (FX_CORE_MODE == FX_CORE_USER_MODE) private: // // A method called by the constructor(s) to initialize the device state. // VOID SetInitialState( VOID ); _Must_inspect_result_ NTSTATUS PreprocessIrp( __in MdIrp Irp ); _Must_inspect_result_ NTSTATUS DeleteDeviceFromFailedCreateNoDelete( __in NTSTATUS FailedStatus, __in BOOLEAN UseStateMachine ); VOID SetFilterIoType( VOID ); static MdCompletionRoutineType _CompletionRoutineForRemlockMaintenance; static _Must_inspect_result_ NTSTATUS _AcquireOptinRemoveLock( __in MdDeviceObject DeviceObject, __in MdIrp Irp ); VOID DestructorInternal( VOID ); NTSTATUS WmiPkgRegister( VOID ); VOID WmiPkgDeregister( VOID ); VOID WmiPkgCleanup( VOID ); public: FxDevice( __in FxDriver *ArgDriver ); ~FxDevice( VOID ); static _Must_inspect_result_ NTSTATUS _Create( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDFDEVICE_INIT* DeviceInit, __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes, __out FxDevice** Device ); _Must_inspect_result_ NTSTATUS DeleteDeviceFromFailedCreate( __in NTSTATUS FailedStatus, __in BOOLEAN UseStateMachine ); __inline FxPackage* GetDispatchPackage( __in UCHAR MajorFunction ) { switch (MajorFunction) { case IRP_MJ_CREATE: case IRP_MJ_CLOSE: case IRP_MJ_CLEANUP: case IRP_MJ_SHUTDOWN: return (FxPackage*) m_PkgGeneral; case IRP_MJ_READ: case IRP_MJ_WRITE: case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_INTERNAL_DEVICE_CONTROL: return (FxPackage*) m_PkgIo; case IRP_MJ_SYSTEM_CONTROL: return (FxPackage*) m_PkgWmi; case IRP_MJ_PNP: case IRP_MJ_POWER: if (m_PkgPnp != NULL) { return (FxPackage*) m_PkgPnp; } else { return (FxPackage*) m_PkgDefault; } break; default: return (FxPackage*) m_PkgDefault; } } MdRemoveLock GetRemoveLock( VOID ); static FxDeviceRemLockAction __inline _RequiresRemLock( __in UCHAR MajorCode, __in UCHAR MinorCode ) { switch (MajorCode) { // // We require remove locks for power irps because they can show // up after the device has been removed if the Power subysystem has // taken a reference on the device object that raced with the // remove irp (or if we are attached above the power policy owner // and the power policy owner requests a power irp during remove // processing. // // What it boils down to is that we do it for power because // that is the only valid irp which can be sent with an outstanding // reference w/out coordination to the device's pnp state. We // assume that for all other irps, the sender has synchronized with // the pnp state of the device. // // We also acquire the remove lock for WMI IRPs because they can // come into the stack while we are processing a remove. For // instance, a WMI irp can come into the stack to the attached // device before it has a change to process the remove device and // unregister with WMI. // // PNP irps can come in at any time as well. For instance, query // device relations for removal or ejection relations can be sent // at any time (and there are pnp stress tests which send them // during remove). // case IRP_MJ_PNP: // // We special case remove device and only acquire the remove lock // in the minor code handler itself. If handled remove device in // the normal way and there was a preprocess routine for it, then // we could deadlock if the irp was dispatched back to KMDF in the // preprocess routine with an extra outstandling remlock acquire // (which won't be released until the preprocess routine returns, // which will be too late). // if (MinorCode == IRP_MN_REMOVE_DEVICE) { return FxDeviceRemLockTestValid; } case IRP_MJ_POWER: case IRP_MJ_SYSTEM_CONTROL: return FxDeviceRemLockRequired; default: #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) return FxDeviceRemLockOptIn; #else // // There is no forseeable scenario where a UMDF driver would need to // need to support remove lock for IO IRPs. While this ifdef can be safely // removed and UMDF can also return FxDeviceRemLockOptIn, that is // being avoided here so that the caller does not need to test the // remove lock flags for IO which would never be set. // return FxDeviceRemLockNotRequired; #endif } } static FxDevice* GetFxDevice( __in MdDeviceObject DeviceObject ); MdDeviceObject __inline GetSafePhysicalDevice( VOID ) { // // Makes sure that the PDO we think we have is // 1) reported to pnp (m_PdoKnown check) // 2) actually there (m_PhysicalDevice != NULL check) // if (m_PdoKnown && m_PhysicalDevice.GetObject() != NULL) { return m_PhysicalDevice.GetObject(); } else { return NULL; } } static _Must_inspect_result_ NTSTATUS STDCALL Dispatch( __in MdDeviceObject DeviceObject, __in MdIrp OriginalIrp ); #if (FX_CORE_MODE==FX_CORE_USER_MODE) static VOID DispatchUm( _In_ MdDeviceObject DeviceObject, _In_ MdIrp Irp, _In_opt_ IUnknown* Context ); static VOID DispatchWithLockUm( _In_ MdDeviceObject DeviceObject, _In_ MdIrp Irp, _In_opt_ IUnknown* Context ); VOID SetInterruptThreadpool( _In_ FxInterruptThreadpool* Pool ) { m_InteruptThreadpool = Pool; } FxInterruptThreadpool* GetInterruptThreadpool( VOID ) { return m_InteruptThreadpool; } #endif // (FX_CORE_MODE == FX_CORE_USER_MODE) static _Must_inspect_result_ NTSTATUS STDCALL DispatchWithLock( __in MdDeviceObject DeviceObject, __in MdIrp OriginalIrp ); _Must_inspect_result_ NTSTATUS DispatchPreprocessedIrp( __in MdIrp Irp, __in PVOID DispatchContext ); __inline WDF_DEVICE_IO_TYPE GetIoType( VOID ) { return m_ReadWriteIoType; } __inline WDF_DEVICE_IO_TYPE GetIoTypeForReadWriteBufferAccess( VOID ) { #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) return m_ReadWriteIoType; #else // // For UM, both buffer-copy and direct-access i/o buffer access types // follow the same storage and retrieval model in internal structures // as in buffered I/O so always return WdfDeviceIoBuffered. // return WdfDeviceIoBuffered; #endif } __inline CHAR GetDefaultPriorityBoost( VOID ) { return m_DefaultPriorityBoost; } // // Return FileObjectClass // __inline WDF_FILEOBJECT_CLASS GetFileObjectClass( VOID ) { return m_FileObjectClass; } // // Configuration time fileobject support setting // __inline VOID SetFileObjectClass( __in WDF_FILEOBJECT_CLASS FileObjectClass ) { m_FileObjectClass = FileObjectClass; } VOID InstallPackage( __inout FxPackage *Package ); __inline WDF_DEVICE_PNP_STATE GetDevicePnpState( ) { return m_CurrentPnpState; } __inline WDF_DEVICE_POWER_STATE GetDevicePowerState( ) { return m_CurrentPowerState; } __inline WDF_DEVICE_POWER_POLICY_STATE GetDevicePowerPolicyState( ) { return m_CurrentPowerPolicyState; } __inline VOID SetDevicePnpState( __in WDF_DEVICE_PNP_STATE DeviceState ) { m_CurrentPnpState = DeviceState; } __inline VOID SetDevicePowerState( __in WDF_DEVICE_POWER_STATE DeviceState ) { m_CurrentPowerState = DeviceState; } __inline VOID SetDevicePowerPolicyState( __in WDF_DEVICE_POWER_POLICY_STATE DeviceState ) { m_CurrentPowerPolicyState = DeviceState; } __inline BOOLEAN IsPnp( VOID ) { return m_PkgPnp != NULL ? TRUE : FALSE; } __inline BOOLEAN IsLegacy( VOID ) { return m_Legacy; } __inline BOOLEAN IsExclusive( VOID ) { return m_Exclusive; } __inline BOOLEAN IsFdo( VOID ) { return m_PkgPnp->GetType() == FX_TYPE_PACKAGE_FDO; } __inline FxPkgFdo* GetFdoPkg( VOID ) { return (FxPkgFdo*) m_PkgPnp; } __inline BOOLEAN IsPdo( VOID ) { return (IsPnp() && m_PkgPnp->GetType() == FX_TYPE_PACKAGE_PDO); } __inline FxPkgPdo* GetPdoPkg( VOID ) { return (FxPkgPdo*) m_PkgPnp; } _Must_inspect_result_ NTSTATUS CreateDevice( __in PWDFDEVICE_INIT DeviceInit ); __inline VOID SetParentWaitingOnRemoval( VOID ) { m_ParentWaitingOnChild = TRUE; } // // There are really three steps in device creation. // // - Creating the device // - Creating the device object that goes with the device (Initialize) // - Finilizing the initialization after packages are installed, attached, // etc. VOID FinishInitializing( VOID ); VOID Destroy( VOID ); // FxObject overrides virtual VOID DeleteObject( VOID ); virtual BOOLEAN Dispose( VOID ); // FxObject overrides __inline PWDF_OBJECT_ATTRIBUTES GetRequestAttributes( VOID ) { return &m_RequestAttributes; } PVOID AllocateRequestMemory( __in_opt PWDF_OBJECT_ATTRIBUTES Attributes ); VOID FreeRequestMemory( __in FxRequest* Request ); // begin FxDeviceBase overrides virtual _Must_inspect_result_ NTSTATUS AddIoTarget( __inout FxIoTarget* IoTarget ); virtual VOID RemoveIoTarget( __inout FxIoTarget* IoTarget ); virtual _Must_inspect_result_ NTSTATUS AllocateEnumInfo( VOID ); virtual VOID AddChildList( __inout FxChildList* List ); virtual VOID RemoveChildList( __inout FxChildList* List ); virtual _Must_inspect_result_ NTSTATUS AllocateDmaEnablerList( VOID ); virtual VOID AddDmaEnabler( __inout FxDmaEnabler* Enabler ); virtual VOID RemoveDmaEnabler( __inout FxDmaEnabler* Enabler ); virtual FxIoTarget* GetDefaultIoTarget( VOID ); FxIoTargetSelf* GetSelfIoTarget( VOID ); virtual _Must_inspect_result_ NTSTATUS QueryInterface( __inout FxQueryInterfaceParams* Params ); // end FxDeviceBase overrides // // Filter Driver Support // __inline BOOLEAN IsFilter() { return m_Filter; } _Must_inspect_result_ NTSTATUS SetFilter( __in BOOLEAN Value ); __inline BOOLEAN IsPowerPageableCapable( VOID ) { return m_PowerPageableCapable; } _Must_inspect_result_ NTSTATUS Initialize( __in PWDFDEVICE_INIT DeviceInit, __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes ); VOID ConfigureAutoForwardCleanupClose( __in PWDFDEVICE_INIT DeviceInit ); _Must_inspect_result_ NTSTATUS PostInitialize( VOID ); _Must_inspect_result_ NTSTATUS PdoInitialize( __in PWDFDEVICE_INIT DeviceInit ); _Must_inspect_result_ NTSTATUS FdoInitialize( __in PWDFDEVICE_INIT DeviceInit ); _Must_inspect_result_ NTSTATUS ControlDeviceInitialize( __in PWDFDEVICE_INIT DeviceInit ); VOID ControlDeviceDelete( VOID ) { // // FxDevice::DeleteObject() has already run, so we must call the super // class's version of DeleteObject(); // ASSERT(m_DeviceObjectDeleted); FxDeviceBase::DeleteObject(); // __super call } _Must_inspect_result_ NTSTATUS OpenSettingsKey( __out HANDLE* Key, __in ACCESS_MASK DesiredAccess = STANDARD_RIGHTS_ALL ); VOID DeleteSymbolicLink( VOID ); __inline BYTE GetCallbackFlagsLocked( VOID ) { return m_CallbackFlags; } __inline BYTE GetCallbackFlags( VOID ) { BYTE flags; KIRQL irql; Lock(&irql); flags = GetCallbackFlagsLocked(); Unlock(irql); return flags; } __inline VOID SetCallbackFlagsLocked( __in BYTE Flags ) { m_CallbackFlags |= Flags; } __inline VOID SetCallbackFlags( __in BYTE Flags ) { KIRQL irql; Lock(&irql); SetCallbackFlagsLocked(Flags); Unlock(irql); } __inline VOID ClearCallbackFlagsLocked( __in BYTE Flags ) { m_CallbackFlags &= ~Flags; } __inline VOID ClearCallbackFlags( __in BYTE Flags ) { KIRQL irql; Lock(&irql); ClearCallbackFlagsLocked(Flags); Unlock(irql); } FxCxDeviceInfo* GetCxDeviceInfo( __in FxDriver* CxDriver ) { FxCxDeviceInfo* cxDeviceInfo; PLIST_ENTRY next; // // Check if we are using I/O class extensions. // for (next = m_CxDeviceInfoListHead.Flink; next != &m_CxDeviceInfoListHead; next = next->Flink) { cxDeviceInfo = CONTAINING_RECORD(next, FxCxDeviceInfo, ListEntry); if (cxDeviceInfo->Driver == CxDriver) { return cxDeviceInfo; } } return NULL; } __inline BOOLEAN IsCxDriverInIoPath( __in FxDriver* CxDriver ) { return (GetCxDeviceInfo(CxDriver) != NULL) ? TRUE : FALSE; } __inline BOOLEAN IsCxInIoPath( VOID ) { return IsListEmpty(&m_CxDeviceInfoListHead) ? FALSE : TRUE; } #if DBG __inline FxCxDeviceInfo* GetFirstCxDeviceInfo( VOID ) { if (IsListEmpty(&m_CxDeviceInfoListHead)) { return NULL; } else { return CONTAINING_RECORD(m_CxDeviceInfoListHead.Flink, FxCxDeviceInfo, ListEntry); } } __inline FxCxDeviceInfo* GetNextCxDeviceInfo( __in FxCxDeviceInfo* CxDeviceInfo ) { ASSERT(CxDeviceInfo != NULL); if (CxDeviceInfo->ListEntry.Flink == &m_CxDeviceInfoListHead) { return NULL; } else { return CONTAINING_RECORD(CxDeviceInfo->ListEntry.Flink, FxCxDeviceInfo, ListEntry); } } #endif __inline static CCHAR GetCxDriverIndex( __in FxCxDeviceInfo* CxDeviceInfo ) { if (CxDeviceInfo != NULL) { return CxDeviceInfo->Index; } else { return 0; } } __inline FxDriver* GetCxDriver( __in FxCxDeviceInfo* CxDeviceInfo ) { if (CxDeviceInfo != NULL) { return CxDeviceInfo->Driver; } else { return GetDriver(); } } #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) static __inline NTSTATUS _OpenDeviceRegistryKey( _In_ MdDeviceObject DeviceObject, _In_ ULONG DevInstKeyType, _In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE DevInstRegKey ); __inline static NTSTATUS _GetDeviceProperty( _In_ MdDeviceObject DeviceObject, _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, _In_ ULONG BufferLength, _Out_opt_ PVOID PropertyBuffer, _Out_ PULONG ResultLength ); #elif (FX_CORE_MODE == FX_CORE_USER_MODE) static NTSTATUS _OpenDeviceRegistryKey( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, _In_ IWudfDeviceStack* DeviceStack, _In_ PWSTR DriverName, _In_ ULONG DevInstKeyType, _In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE DevInstRegKey ); static NTSTATUS _GetDeviceProperty( _In_ PVOID DeviceStack, _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, _In_ ULONG BufferLength, _Out_opt_ PVOID PropertyBuffer, _Out_ PULONG ResultLength ); #endif static _Must_inspect_result_ NTSTATUS _ValidateOpenKeyParams( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, _In_opt_ PWDFDEVICE_INIT DeviceInit, _In_opt_ FxDevice* Device ); static _Must_inspect_result_ NTSTATUS _OpenKey( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, _In_opt_ PWDFDEVICE_INIT DeviceInit, _In_opt_ FxDevice* Device, _In_ ULONG DeviceInstanceKeyType, _In_ ACCESS_MASK DesiredAccess, _In_opt_ PWDF_OBJECT_ATTRIBUTES KeyAttributes, _Out_ WDFKEY* Key ); static _Must_inspect_result_ NTSTATUS _AllocAndQueryProperty( _In_ PFX_DRIVER_GLOBALS Globals, _In_opt_ PWDFDEVICE_INIT DeviceInit, _In_opt_ FxDevice* Device, _In_opt_ MdDeviceObject RemotePdo, _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, _In_ POOL_TYPE PoolType, _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, _Out_ WDFMEMORY* PropertyMemory ); static _Must_inspect_result_ NTSTATUS _QueryProperty( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, _In_opt_ PWDFDEVICE_INIT DeviceInit, _In_opt_ FxDevice* Device, _In_opt_ MdDeviceObject RemotePdo, _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, _In_ ULONG BufferLength, _Out_opt_ PVOID PropertyBuffer, _Out_opt_ PULONG ResultLength ); static VOID STDCALL _InterfaceReferenceNoOp( __in_opt PVOID Context ) { // NoOp reference stub for query interface UNREFERENCED_PARAMETER(Context); } static VOID STDCALL _InterfaceDereferenceNoOp( __in_opt PVOID Context ) { // NoOp dereference stub for query interface UNREFERENCED_PARAMETER(Context); } static FxWdmDeviceExtension* _GetFxWdmExtension( __in MdDeviceObject DeviceObject ); BOOLEAN IsRemoveLockEnabledForIo( VOID ); VOID FxLogDeviceStartTelemetryEvent( VOID ) { // LogDeviceStartTelemetryEvent(GetDriverGlobals(), this); __REACTOS__ : no-op } virtual VOID SetDeviceTelemetryInfoFlags( _In_ FxDeviceInfoFlags Flag ) { m_DeviceTelemetryInfoFlags |= Flag; } USHORT GetDeviceTelemetryInfoFlags( VOID ) { return m_DeviceTelemetryInfoFlags; } __inline CHAR GetStackSize( VOID ) { return m_DeviceObject.GetStackSize(); } __inline VOID SetStackSize( _In_ CHAR Size ) { m_DeviceObject.SetStackSize(Size); } NTSTATUS UpdateInterruptThreadpoolLimits( VOID ) { return STATUS_SUCCESS; } FxCmResList* GetTranslatedResources( ) { return m_PkgPnp->GetTranslatedResourceList(); } VOID DetachDevice( VOID ); VOID InvalidateDeviceState( VOID ); NTSTATUS CreateSymbolicLink( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, _In_ PCUNICODE_STRING SymbolicLinkName ); VOID SetCleanupFromFailedCreate( BOOLEAN Value ) { #if (FX_CORE_MODE == FX_CORE_USER_MODE) m_CleanupFromFailedCreate = Value; #else UNREFERENCED_PARAMETER(Value); #endif } BOOLEAN IsInterfaceRegistered( _In_ const GUID* InterfaceClassGUID, _In_opt_ PCUNICODE_STRING RefString ); static _Must_inspect_result_ NTSTATUS _AllocAndQueryPropertyEx( _In_ PFX_DRIVER_GLOBALS DriverGlobals, _In_opt_ PWDFDEVICE_INIT DeviceInit, _In_opt_ FxDevice* Device, _In_ PVOID PropertyData, _In_ FxPropertyType FxPropertyType, _In_ POOL_TYPE PoolType, _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, _Out_ WDFMEMORY* PropertyMemory, _Out_ PDEVPROPTYPE PropertyType ); static _Must_inspect_result_ NTSTATUS _QueryPropertyEx( _In_ PFX_DRIVER_GLOBALS DriverGlobals, _In_opt_ PWDFDEVICE_INIT DeviceInit, _In_opt_ FxDevice* Device, _In_ PVOID PropertyData, _In_ FxPropertyType FxPropertyType, _In_ ULONG BufferLength, _Out_ PVOID PropertyBuffer, _Out_ PULONG ResultLength, _Out_ PDEVPROPTYPE PropertyType ); _Must_inspect_result_ NTSTATUS OpenDevicemapKeyWorker( _In_ PFX_DRIVER_GLOBALS pFxDriverGlobals, _In_ PCUNICODE_STRING KeyName, _In_ ACCESS_MASK DesiredAccess, _In_ FxRegKey* pKey ); _Must_inspect_result_ NTSTATUS AssignProperty ( _In_ PVOID PropertyData, _In_ FxPropertyType FxPropertyType, _In_ DEVPROPTYPE Type, _In_ ULONG BufferLength, _In_opt_ PVOID PropertyBuffer ); #if (FX_CORE_MODE==FX_CORE_USER_MODE) _Must_inspect_result_ NTSTATUS FxValidateInterfacePropertyData( _In_ PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData ); VOID GetDeviceStackIoType ( _Out_ WDF_DEVICE_IO_TYPE* ReadWriteIoType, _Out_ WDF_DEVICE_IO_TYPE* IoControlIoType ); __inline UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL GetRetrievalMode( VOID ) { return m_RetrievalMode; } __inline WDF_DEVICE_IO_TYPE GetPreferredRWTransferMode( VOID ) { return m_ReadWriteIoType; } __inline WDF_DEVICE_IO_TYPE GetPreferredIoctlTransferMode( VOID ) { return m_IoctlIoType; } __inline ULONG GetDirectTransferThreshold( VOID ) { return m_DirectTransferThreshold; } static VOID GetPreferredTransferMode( _In_ MdDeviceObject DeviceObject, _Out_ UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL *RetrievalMode, _Out_ WDF_DEVICE_IO_TYPE *RWPreference, _Out_ WDF_DEVICE_IO_TYPE *IoctlPreference ); NTSTATUS ProcessWmiPowerQueryOrSetData ( _In_ RdWmiPowerAction Action, _Out_ BOOLEAN * QueryResult ); static WUDF_INTERFACE_CONTEXT RemoteInterfaceArrival ( _In_ IWudfDevice * DeviceObject, _In_ LPCGUID DeviceInterfaceGuid, _In_ PCWSTR SymbolicLink ); static void RemoteInterfaceRemoval ( _In_ IWudfDevice * DeviceObject, _In_ WUDF_INTERFACE_CONTEXT RemoteInterfaceID ); static void PoFxDevicePowerRequired ( _In_ MdDeviceObject DeviceObject ); static void PoFxDevicePowerNotRequired ( _In_ MdDeviceObject DeviceObject ); static BOOL TransportQueryId ( _In_ IWudfDevice * DeviceObject, _In_ DWORD Id, _In_ PVOID DataBuffer, _In_ SIZE_T cbDataBufferSize ); static NTSTATUS NtStatusFromHr ( _In_ IWudfDeviceStack * DevStack, _In_ HRESULT Hr ); NTSTATUS NtStatusFromHr ( _In_ HRESULT Hr ); IWudfDeviceStack* GetDeviceStack( VOID ); IWudfDeviceStack2 * GetDeviceStack2( VOID ); VOID RetrieveDeviceRegistrySettings( VOID ); BOOLEAN IsDirectHardwareAccessAllowed( ) { return (m_DirectHardwareAccess == WdfAllowDirectHardwareAccess); } BOOLEAN IsInterruptAccessAllowed( VOID ) { // // Allow access to interrupts if the device has any connection resources, // regardless of the UmdfDirectHardwareAccess INF directive. // return IsDirectHardwareAccessAllowed() || GetTranslatedResources()->HasConnectionResources(); } BOOLEAN AreRegistersMappedToUsermode( VOID ) { return (m_RegisterAccessMode == WdfRegisterAccessUsingUserModeMapping); } PVOID GetPseudoAddressFromSystemAddress( __in PVOID SystemAddress ) { return SystemAddress; } PVOID GetSystemAddressFromPseudoAddress( __in PVOID PseudoAddress ) { return PseudoAddress; } static ULONG __inline GetLength( __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size ) { ULONG length = 0; switch(Size) { case WdfDeviceHwAccessTargetSizeUchar: length = sizeof(UCHAR); break; case WdfDeviceHwAccessTargetSizeUshort: length = sizeof(USHORT); break; case WdfDeviceHwAccessTargetSizeUlong: length = sizeof(ULONG); break; case WdfDeviceHwAccessTargetSizeUlong64: length = sizeof(ULONG64); break; default: ASSERT(FALSE); } return length; } BOOL IsRegister( __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type ) { if (Type == WdfDeviceHwAccessTargetTypeRegister || Type == WdfDeviceHwAccessTargetTypeRegisterBuffer) { return TRUE; } return FALSE; } BOOL IsPort( __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type ) { if (Type == WdfDeviceHwAccessTargetTypePort || Type == WdfDeviceHwAccessTargetTypePortBuffer) { return TRUE; } return FALSE; } BOOL IsBufferType( __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type ) { if (Type == WdfDeviceHwAccessTargetTypeRegisterBuffer || Type == WdfDeviceHwAccessTargetTypePortBuffer) { return TRUE; } return FALSE; } SIZE_T ReadRegister( __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, __in PVOID Register ); VOID ReadRegisterBuffer( __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, __in PVOID Register, __out_ecount_full(Count) PVOID Buffer, __in ULONG Count ); VOID WriteRegister( __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, __in PVOID Register, __in SIZE_T Value ); VOID WriteRegisterBuffer( __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, __in PVOID Register, __in_ecount(Count) PVOID Buffer, __in ULONG Count ); VOID RetrieveDeviceInfoRegistrySettings( _Out_ PCWSTR* GroupId, _Out_ PUMDF_DRIVER_REGSITRY_INFO DeviceRegInfo ); #endif // (FX_CORE_MODE == FX_CORE_USER_MODE) }; class FxMpDevice : public FxDeviceBase { public: FxMpDevice( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in FxDriver* Driver, __in MdDeviceObject DeviceObject, __in MdDeviceObject AttachedDevice, __in MdDeviceObject PDO ) : FxDeviceBase(FxDriverGlobals, Driver, FX_TYPE_MP_DEVICE, sizeof(*this)) { Init(DeviceObject, AttachedDevice, PDO); m_DefaultTarget = NULL; Mx::MxReferenceObject(m_DeviceObject.GetObject()); MarkDisposeOverride(ObjectDoNotLock); } // begin FxObject overrides BOOLEAN Dispose( VOID ) { // // Important that the cleanup routine be called while the MdDeviceObject // is valid! // CallCleanup(); // // Manually destroy the children now so that by the time we wait on the // dispose empty out, all of the children will have been added to it. // DestroyChildren(); if (m_DisposeList != NULL) { m_DisposeList->WaitForEmpty(); } // // No device object to delete since the caller's own the // WDM device. Simulate what FxDevice::Destroy does by NULL'ing out the // device objects. // Mx::MxDereferenceObject(m_DeviceObject.GetObject()); m_DeviceObject = NULL; m_AttachedDevice = NULL; return FALSE; } // end FxObject overrides // begin FxDeviceBase overrides virtual FxIoTarget* GetDefaultIoTarget( VOID ) { return m_DefaultTarget; } // end FxDeviceBase overrides public: // // Default I/O target for this miniport device // FxIoTarget *m_DefaultTarget; }; #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) #include "fxdevicekm.hpp" #else #include "fxdeviceum.hpp" #endif #endif // _FXDEVICE_H_