Updated API documentation
This commit is contained in:
+475
-19
@@ -9,7 +9,20 @@ Module Name:
|
||||
|
||||
Abstract:
|
||||
|
||||
Companion file to Dmf_BusFilter.c.
|
||||
Public API for the DMF Bus Filter extension. This module intercepts the
|
||||
IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations completion path of a WDF FDO
|
||||
and splices a proxy WDM filter device object onto every child PDO reported
|
||||
by the underlying bus driver. The filter sits between the bus driver's PDO
|
||||
and the child devnode's FDO, giving the client driver visibility into PnP,
|
||||
power, and I/O traffic for each child.
|
||||
|
||||
Typical client driver usage flow:
|
||||
|
||||
1. DriverEntry: fill in DMF_BusFilter_CONFIG, call DMF_BusFilter_Initialize.
|
||||
2. EvtDriverDeviceAdd: call DMF_BusFilter_DeviceAdd.
|
||||
3. EvtDeviceReleaseHardware or EvtCleanupCallback: call
|
||||
DMF_BusFilter_DeviceCleanup to drain and destroy any remaining proxy
|
||||
child devices and prevent resource leaks.
|
||||
|
||||
Environment:
|
||||
|
||||
@@ -26,10 +39,42 @@ Environment:
|
||||
|
||||
#if defined(DMF_KERNEL_MODE)
|
||||
|
||||
// Declare an opaque handle representing a filtered PDO.
|
||||
// Opaque handle representing a filtered child PDO. Passed to client callbacks
|
||||
// and to the DMF_BusFilter_Wdm*Get accessor functions.
|
||||
//
|
||||
DECLARE_HANDLE(DMFBUSCHILDDEVICE);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_PreBusDeviceAdd
|
||||
|
||||
Purpose:
|
||||
|
||||
Called by DMF_BusFilter_DeviceAdd before the bus filter FDO is created.
|
||||
The client may customize DeviceInit (e.g. set PnP capabilities, set power
|
||||
policy) and optionally allocate a PDMFDEVICE_INIT if it wants to use DMF
|
||||
modules on the bus FDO.
|
||||
|
||||
If the client allocates *DmfDeviceInit it must NOT free it; the library
|
||||
takes ownership regardless of success or failure.
|
||||
|
||||
Arguments:
|
||||
|
||||
Driver - The WDFDRIVER for this driver.
|
||||
DeviceInit - The WDFDEVICE_INIT being prepared for the bus FDO.
|
||||
Attributes - WDF_OBJECT_ATTRIBUTES to apply to the created device.
|
||||
The client may set a context type or parent here.
|
||||
DmfDeviceInit - On output: optionally set to a PDMFDEVICE_INIT if the
|
||||
client uses DMF modules. Pass NULL if not needed.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS or an error status. A non-success value aborts
|
||||
DMF_BusFilter_DeviceAdd.
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_PreBusDeviceAdd)
|
||||
_IRQL_requires_same_
|
||||
@@ -42,6 +87,32 @@ EVT_DMF_BusFilter_PreBusDeviceAdd(
|
||||
_Outptr_result_maybenull_ PDMFDEVICE_INIT* DmfDeviceInit
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_PostBusDeviceAdd
|
||||
|
||||
Purpose:
|
||||
|
||||
Called by DMF_BusFilter_DeviceAdd after the bus filter FDO has been
|
||||
successfully created. The client may perform any post-creation
|
||||
initialization that requires a valid WDFDEVICE handle, such as creating
|
||||
I/O queues or registering interfaces.
|
||||
|
||||
Arguments:
|
||||
|
||||
Device - The newly created bus filter WDFDEVICE.
|
||||
DmfDeviceInit - The PDMFDEVICE_INIT that was optionally allocated in
|
||||
EVT_DMF_BusFilter_PreBusDeviceAdd, or NULL if the client
|
||||
did not request DMF module support.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS or an error status. A non-success value aborts
|
||||
DMF_BusFilter_DeviceAdd and causes the device object to be deleted.
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_PostBusDeviceAdd)
|
||||
_IRQL_requires_same_
|
||||
@@ -52,6 +123,38 @@ EVT_DMF_BusFilter_PostBusDeviceAdd(
|
||||
_In_opt_ PDMFDEVICE_INIT DmfDeviceInit
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_DeviceAdd
|
||||
|
||||
Purpose:
|
||||
|
||||
Called when a proxy WDM filter device object has been created and attached
|
||||
to a newly discovered child PDO. The filter is already in the stack (attached
|
||||
above the PDO) when this callback fires. The client may associate per-child
|
||||
state or WDF objects with the ChildDevice handle at this point.
|
||||
|
||||
If the callback returns a non-success status the library immediately
|
||||
detaches and deletes the proxy filter device; the child ChildDevice handle
|
||||
becomes invalid.
|
||||
|
||||
NOTE: The IRQL annotation is APC_LEVEL because this callback is invoked
|
||||
from Relations_AddDevice, which runs at PASSIVE_LEVEL but holds no spinlock.
|
||||
The annotation is intentionally conservative; in practice this callback
|
||||
fires at PASSIVE_LEVEL.
|
||||
|
||||
Arguments:
|
||||
|
||||
Device - The parent bus filter WDFDEVICE.
|
||||
ChildDevice - Opaque handle representing the newly created proxy child.
|
||||
|
||||
IRQL: <= APC_LEVEL (in practice: PASSIVE_LEVEL)
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS, or an error status to abort creation of this proxy child.
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_DeviceAdd)
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
@@ -62,6 +165,33 @@ EVT_DMF_BusFilter_DeviceAdd(
|
||||
_In_ DMFBUSCHILDDEVICE ChildDevice
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_DeviceRemove
|
||||
|
||||
Purpose:
|
||||
|
||||
Called when a proxy child device is about to be destroyed. This fires both
|
||||
during the normal IRP_MN_REMOVE_DEVICE path and during forced teardown in
|
||||
DMF_BusFilter_DeviceCleanup. At this point in-flight I/O to the child has
|
||||
already been drained (via IO_REMOVE_LOCK) so the child is quiescent.
|
||||
|
||||
The callback must not attempt to forward any IRPs to the child or access
|
||||
the child's WDM stack; both are being torn down. After this callback
|
||||
returns the ChildDevice handle is deleted by the library.
|
||||
|
||||
Arguments:
|
||||
|
||||
Device - The parent bus filter WDFDEVICE.
|
||||
ChildDevice - Opaque handle for the proxy child being removed.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_DeviceRemove)
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
@@ -72,6 +202,33 @@ EVT_DMF_BusFilter_DeviceRemove(
|
||||
_In_ DMFBUSCHILDDEVICE ChildDevice
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_DeviceStarted
|
||||
|
||||
Purpose:
|
||||
|
||||
Called after the library has successfully forwarded IRP_MN_START_DEVICE
|
||||
to the lower stack and the lower driver returned success. The Irp is still
|
||||
held by the library and will be completed after this callback returns; the
|
||||
client must not complete it.
|
||||
|
||||
The client may use this callback to perform any work that requires the
|
||||
child device to be in the started state (e.g. sending I/O, enabling
|
||||
interfaces).
|
||||
|
||||
Arguments:
|
||||
|
||||
ChildDevice - Opaque handle for the proxy child that has started.
|
||||
Irp - The IRP_MN_START_DEVICE IRP (for inspection only).
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_DeviceStarted)
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
@@ -82,6 +239,32 @@ EVT_DMF_BusFilter_DeviceStarted(
|
||||
_In_ IRP* Irp
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_DeviceEnumerated
|
||||
|
||||
Purpose:
|
||||
|
||||
Called when IRP_MN_DEVICE_ENUMERATED reaches the proxy child device.
|
||||
This minor code is sent by the PnP manager after the device has been
|
||||
enumerated and its instance ID has been assigned. It is informational;
|
||||
the library always forwards the IRP to the lower stack after this
|
||||
callback returns.
|
||||
|
||||
The client must not complete the IRP.
|
||||
|
||||
Arguments:
|
||||
|
||||
ChildDevice - Opaque handle for the proxy child being enumerated.
|
||||
Irp - The IRP_MN_DEVICE_ENUMERATED IRP (for inspection only).
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_DeviceEnumerated)
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
@@ -92,6 +275,38 @@ EVT_DMF_BusFilter_DeviceEnumerated(
|
||||
_In_ IRP* Irp
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_DeviceQueryId
|
||||
|
||||
Purpose:
|
||||
|
||||
Called when IRP_MN_QUERY_ID reaches the proxy child device. The client
|
||||
may inspect or modify the IRP stack location and set IoStatus fields to
|
||||
supply identity strings (hardware ID, instance ID, etc.).
|
||||
|
||||
Return Value contract (load-bearing):
|
||||
|
||||
TRUE - The client has fully handled the IRP (set IoStatus.Status and
|
||||
Information). The library completes the IRP without forwarding
|
||||
it to the lower stack.
|
||||
|
||||
FALSE - The client did not handle the IRP. The library forwards it
|
||||
synchronously to the lower driver with IoForwardIrpSynchronously,
|
||||
then completes it with the lower driver's status.
|
||||
|
||||
Arguments:
|
||||
|
||||
ChildDevice - Opaque handle for the proxy child.
|
||||
Irp - The IRP_MN_QUERY_ID IRP.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if the client handled the IRP; FALSE to let the library forward it.
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_DeviceQueryId)
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
@@ -102,6 +317,38 @@ EVT_DMF_BusFilter_DeviceQueryId(
|
||||
_In_ IRP* Irp
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Callback: EVT_DMF_BusFilter_DeviceQueryInterface
|
||||
|
||||
Purpose:
|
||||
|
||||
Called when IRP_MN_QUERY_INTERFACE reaches the proxy child device. The
|
||||
client may fill in the interface struct pointed to by the IRP stack
|
||||
location's Parameters.QueryInterface field.
|
||||
|
||||
Return Value contract (load-bearing):
|
||||
|
||||
TRUE - The client has fully handled the IRP (set IoStatus.Status and
|
||||
filled in the interface). The library completes the IRP without
|
||||
forwarding it to the lower stack.
|
||||
|
||||
FALSE - The client did not handle the IRP. The library forwards it
|
||||
synchronously to the lower driver with IoForwardIrpSynchronously,
|
||||
then completes it with the lower driver's status.
|
||||
|
||||
Arguments:
|
||||
|
||||
ChildDevice - Opaque handle for the proxy child.
|
||||
Irp - The IRP_MN_QUERY_INTERFACE IRP.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if the client handled the IRP; FALSE to let the library forward it.
|
||||
|
||||
--*/
|
||||
typedef
|
||||
_Function_class_(EVT_DMF_BusFilter_DeviceQueryInterface)
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
@@ -112,53 +359,117 @@ EVT_DMF_BusFilter_DeviceQueryInterface(
|
||||
_In_ IRP* Irp
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Structure: DMF_BusFilter_CONFIG
|
||||
|
||||
Purpose:
|
||||
|
||||
Configuration block passed to DMF_BusFilter_Initialize. The client fills
|
||||
this in (using DMF_BusFilter_CONFIG_INIT to zero-initialize it first) and
|
||||
sets optional callback pointers before calling Initialize.
|
||||
|
||||
All EVT_* callback pointers are optional; set only the ones the client
|
||||
needs. The library silently skips callbacks that are NULL.
|
||||
|
||||
Fields:
|
||||
|
||||
DriverObject - The WDM DRIVER_OBJECT for this driver. Required.
|
||||
|
||||
DeviceType - Device type passed to IoCreateDevice for each
|
||||
proxy child filter DO. If 0, the library inherits
|
||||
the type from the PDO (FILE_DEVICE_UNKNOWN is the
|
||||
typical PDO type for USB devices). Leaving this at
|
||||
0 is recommended for most bus filter scenarios.
|
||||
|
||||
DeviceCharacteristics - Characteristics flags passed to IoCreateDevice.
|
||||
FILE_AUTOGENERATED_DEVICE_NAME,
|
||||
FILE_CHARACTERISTIC_TS_DEVICE,
|
||||
FILE_CHARACTERISTIC_WEBDAV_DEVICE,
|
||||
FILE_DEVICE_IS_MOUNTED, and FILE_VIRTUAL_VOLUME
|
||||
are masked off by the library before use.
|
||||
|
||||
EvtPreBusDeviceAdd - Optional. See EVT_DMF_BusFilter_PreBusDeviceAdd.
|
||||
EvtPostBusDeviceAdd - Optional. See EVT_DMF_BusFilter_PostBusDeviceAdd.
|
||||
EvtDeviceAdd - Optional. See EVT_DMF_BusFilter_DeviceAdd.
|
||||
EvtDeviceRemove - Optional. See EVT_DMF_BusFilter_DeviceRemove.
|
||||
EvtDeviceStarted - Optional. See EVT_DMF_BusFilter_DeviceStarted.
|
||||
EvtDeviceEnumerated - Optional. See EVT_DMF_BusFilter_DeviceEnumerated.
|
||||
EvtDeviceQueryId - Optional. See EVT_DMF_BusFilter_DeviceQueryId.
|
||||
EvtDeviceQueryInterface - Optional. See EVT_DMF_BusFilter_DeviceQueryInterface.
|
||||
|
||||
--*/
|
||||
typedef struct
|
||||
{
|
||||
// The driver object.
|
||||
//
|
||||
//
|
||||
_In_ DRIVER_OBJECT* DriverObject;
|
||||
|
||||
// The device type.
|
||||
//
|
||||
// Device type for proxy child filter DOs. 0 inherits from the PDO.
|
||||
//
|
||||
_In_ DEVICE_TYPE DeviceType;
|
||||
|
||||
// The device characteristics.
|
||||
//
|
||||
// Device characteristics for proxy child filter DOs.
|
||||
//
|
||||
_In_ ULONG DeviceCharacteristics;
|
||||
|
||||
// Called before bus device object is created.
|
||||
//
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_PreBusDeviceAdd* EvtPreBusDeviceAdd;
|
||||
|
||||
// Called after bus device object was created.
|
||||
//
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_PostBusDeviceAdd* EvtPostBusDeviceAdd;
|
||||
|
||||
// Called when child proxy device was created.
|
||||
//
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_DeviceAdd* EvtDeviceAdd;
|
||||
|
||||
// Called when child proxy device gets removed.
|
||||
//
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_DeviceRemove* EvtDeviceRemove;
|
||||
|
||||
// Called when IRP_MN_START_DEVICE is set to child device.
|
||||
//
|
||||
// Called when IRP_MN_START_DEVICE is sent to the child device.
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_DeviceStarted* EvtDeviceStarted;
|
||||
|
||||
// Called when IRP_MN_DEVICE_ENUMERATED is sent to child device.
|
||||
//
|
||||
// Called when IRP_MN_DEVICE_ENUMERATED is sent to the child device.
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_DeviceEnumerated* EvtDeviceEnumerated;
|
||||
|
||||
// Called when IRP_MN_QUERY_ID is sent to child device.
|
||||
//
|
||||
// Called when IRP_MN_QUERY_ID is sent to the child device.
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_DeviceQueryId* EvtDeviceQueryId;
|
||||
|
||||
// Called when IRP_MN_QUERY_INTERFACE is sent to child device.
|
||||
//
|
||||
// Called when IRP_MN_QUERY_INTERFACE is sent to the child device.
|
||||
//
|
||||
_In_opt_ EVT_DMF_BusFilter_DeviceQueryInterface* EvtDeviceQueryInterface;
|
||||
} DMF_BusFilter_CONFIG;
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Zero-initializes a DMF_BusFilter_CONFIG structure and sets the required
|
||||
DriverObject field. The client must call this before setting any optional
|
||||
callback pointers and before passing the config to DMF_BusFilter_Initialize.
|
||||
|
||||
All optional callback pointers default to NULL (disabled). DeviceType
|
||||
defaults to 0, which causes the library to inherit the device type from
|
||||
each child PDO at attach time.
|
||||
|
||||
Arguments:
|
||||
|
||||
BusFilterConfig - Pointer to the config structure to initialize.
|
||||
DriverObject - The WDM DRIVER_OBJECT for this driver.
|
||||
|
||||
IRQL: Any (typically PASSIVE_LEVEL from DriverEntry)
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
__forceinline
|
||||
VOID
|
||||
DMF_BusFilter_CONFIG_INIT(
|
||||
@@ -171,6 +482,34 @@ DMF_BusFilter_CONFIG_INIT(
|
||||
BusFilterConfig->DriverObject = DriverObject;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initializes the bus filter library for the current driver. Must be called
|
||||
once from DriverEntry, after WdfDriverCreate returns, and before the first
|
||||
call to DMF_BusFilter_DeviceAdd.
|
||||
|
||||
Internally this routine hooks the driver's entire MajorFunction dispatch
|
||||
table so that IRPs sent to proxy child device objects are intercepted. It
|
||||
also stores the client's configuration for use in subsequent callbacks.
|
||||
|
||||
Arguments:
|
||||
|
||||
BusFilterConfig - Pointer to a fully populated DMF_BusFilter_CONFIG.
|
||||
The caller retains ownership but the library keeps a
|
||||
copy for the lifetime of the driver.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS, or:
|
||||
STATUS_INVALID_PARAMETER - BusFilterConfig or DriverObject is NULL.
|
||||
STATUS_NOT_SUPPORTED - WdfGetDriver returned NULL (WDF not yet ready).
|
||||
Any WDF context-allocation failure.
|
||||
|
||||
--*/
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
_Must_inspect_result_
|
||||
NTSTATUS
|
||||
@@ -178,23 +517,140 @@ DMF_BusFilter_Initialize(
|
||||
_In_ DMF_BusFilter_CONFIG* BusFilterConfig
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
WDF EvtDriverDeviceAdd callback implementation for the bus filter FDO.
|
||||
The client should register this function as its EvtDriverDeviceAdd (or
|
||||
call it directly from a wrapper). It creates the bus filter WDF device,
|
||||
installs the bus-relations IRP preprocessor, and initializes the internal
|
||||
child-device list.
|
||||
|
||||
DMF_BusFilter_Initialize must have been called before this function.
|
||||
|
||||
Arguments:
|
||||
|
||||
Driver - The WDFDRIVER.
|
||||
DeviceInit - The WDFDEVICE_INIT prepared by the framework.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
STATUS_SUCCESS, or a failure status from WdfDeviceCreate or supporting
|
||||
framework calls. On failure any partially created device is cleaned up.
|
||||
|
||||
--*/
|
||||
EVT_WDF_DRIVER_DEVICE_ADD DMF_BusFilter_DeviceAdd;
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Returns the WDM DEVICE_OBJECT that represents the proxy child filter
|
||||
device itself (the filter DO created by IoCreateDevice inside this
|
||||
library). Use this to obtain the raw WDM object when the WDF handle
|
||||
is not sufficient.
|
||||
|
||||
Arguments:
|
||||
|
||||
ChildDevice - Opaque handle for a proxy child device.
|
||||
|
||||
Return Value:
|
||||
|
||||
The proxy filter DEVICE_OBJECT, or NULL if the context is missing.
|
||||
|
||||
--*/
|
||||
PDEVICE_OBJECT
|
||||
DMF_BusFilter_WdmDeviceObjectGet(
|
||||
_In_ DMFBUSCHILDDEVICE ChildDevice
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Returns the WDM DEVICE_OBJECT to which the proxy child filter is attached
|
||||
(i.e. the result of IoAttachDeviceToDeviceStackSafe -- typically the PDO
|
||||
itself or the topmost device in the PDO's stack at attach time). This is
|
||||
the object that IRPs are forwarded to when the filter does not handle them.
|
||||
|
||||
Arguments:
|
||||
|
||||
ChildDevice - Opaque handle for a proxy child device.
|
||||
|
||||
Return Value:
|
||||
|
||||
The attached (lower) DEVICE_OBJECT, or NULL if the child has an
|
||||
unrecognised signature or a missing context.
|
||||
|
||||
--*/
|
||||
PDEVICE_OBJECT
|
||||
DMF_BusFilter_WdmAttachedDeviceGet(
|
||||
_In_ DMFBUSCHILDDEVICE ChildDevice
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Returns the Physical Device Object (PDO) associated with a proxy child
|
||||
device. This is the PDO reported by the bus driver in the
|
||||
DEVICE_RELATIONS array that caused this proxy child to be created.
|
||||
|
||||
Arguments:
|
||||
|
||||
ChildDevice - Opaque handle for a proxy child device.
|
||||
|
||||
Return Value:
|
||||
|
||||
The PDO DEVICE_OBJECT, or NULL if the child has an unrecognised
|
||||
signature or a missing context.
|
||||
|
||||
--*/
|
||||
PDEVICE_OBJECT
|
||||
DMF_BusFilter_WdmPhysicalDeviceGet(
|
||||
_In_ DMFBUSCHILDDEVICE ChildDevice
|
||||
);
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Tears down all proxy child filter devices still associated with the bus
|
||||
device. The client MUST call this from its EvtDeviceReleaseHardware or
|
||||
EvtCleanupCallback to prevent WDM device object leaks. Without this call,
|
||||
any child devices remaining in the internal list at unload time will be
|
||||
leaked and will fault when the I/O manager later dereferences them.
|
||||
|
||||
Under normal PnP operation the list is already empty when this function
|
||||
runs (IRP_MN_REMOVE_DEVICE has been dispatched to every child). This
|
||||
function is a safety net for abnormal paths such as surprise removal of
|
||||
the parent before all children received REMOVE.
|
||||
|
||||
The function first waits for any outstanding bus-relations work items to
|
||||
drain (preventing a race with a pending passive-level Relations_AddDevice
|
||||
call), then for each remaining child:
|
||||
- Acquires the per-child IO_REMOVE_LOCK to drain in-flight I/O.
|
||||
- Calls EvtDeviceRemove (if set).
|
||||
- Detaches and deletes the proxy filter device in the mandatory order.
|
||||
|
||||
If a child's IO_REMOVE_LOCK cannot be acquired (STATUS_DELETE_PENDING),
|
||||
it means a concurrent IRP_MN_REMOVE_DEVICE is already processing that
|
||||
child; this function skips it and lets the REMOVE path handle teardown.
|
||||
|
||||
Arguments:
|
||||
|
||||
Device - The bus filter WDFDEVICE whose proxy children should be cleaned up.
|
||||
|
||||
IRQL: PASSIVE_LEVEL
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
VOID
|
||||
DMF_BusFilter_DeviceCleanup(
|
||||
|
||||
Reference in New Issue
Block a user