mirror of
https://github.com/reactos/reactos.git
synced 2025-03-10 10:14:44 +00:00

Not all files are included, but these are necessary to compile cdrom driver. So far it can only be statically linked with drivers, a proper implementation requires wdfldr helper driver
2301 lines
50 KiB
C++
2301 lines
50 KiB
C++
/*++
|
|
|
|
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
|
|
);
|
|
|
|
// <begin> FxObject overrides
|
|
virtual
|
|
VOID
|
|
DeleteObject(
|
|
VOID
|
|
);
|
|
|
|
virtual
|
|
BOOLEAN
|
|
Dispose(
|
|
VOID
|
|
);
|
|
// <end> 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_
|