661 lines
19 KiB
C
661 lines
19 KiB
C
/*++
|
|
|
|
Copyright (c) Nefarius Software Solutions e.U. All rights reserved.
|
|
Licensed under the MIT license.
|
|
|
|
Module Name:
|
|
|
|
Dmf_BusFilter.h
|
|
|
|
Abstract:
|
|
|
|
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:
|
|
|
|
Kernel-mode Driver Framework
|
|
|
|
--*/
|
|
|
|
#pragma once
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Bus Filter support
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
#if defined(DMF_KERNEL_MODE)
|
|
|
|
// 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_
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
|
NTSTATUS
|
|
EVT_DMF_BusFilter_PreBusDeviceAdd(
|
|
_In_ WDFDRIVER Driver,
|
|
_Inout_ PWDFDEVICE_INIT DeviceInit,
|
|
_Out_ WDF_OBJECT_ATTRIBUTES* Attributes,
|
|
_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_
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
|
NTSTATUS
|
|
EVT_DMF_BusFilter_PostBusDeviceAdd(
|
|
_In_ WDFDEVICE Device,
|
|
_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)
|
|
_IRQL_requires_same_
|
|
NTSTATUS
|
|
EVT_DMF_BusFilter_DeviceAdd(
|
|
_In_ WDFDEVICE Device,
|
|
_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)
|
|
_IRQL_requires_same_
|
|
VOID
|
|
EVT_DMF_BusFilter_DeviceRemove(
|
|
_In_ WDFDEVICE Device,
|
|
_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)
|
|
_IRQL_requires_same_
|
|
VOID
|
|
EVT_DMF_BusFilter_DeviceStarted(
|
|
_In_ DMFBUSCHILDDEVICE ChildDevice,
|
|
_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)
|
|
_IRQL_requires_same_
|
|
VOID
|
|
EVT_DMF_BusFilter_DeviceEnumerated(
|
|
_In_ DMFBUSCHILDDEVICE ChildDevice,
|
|
_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)
|
|
_IRQL_requires_same_
|
|
BOOLEAN
|
|
EVT_DMF_BusFilter_DeviceQueryId(
|
|
_In_ DMFBUSCHILDDEVICE ChildDevice,
|
|
_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)
|
|
_IRQL_requires_same_
|
|
BOOLEAN
|
|
EVT_DMF_BusFilter_DeviceQueryInterface(
|
|
_In_ DMFBUSCHILDDEVICE ChildDevice,
|
|
_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;
|
|
|
|
// Device type for proxy child filter DOs. 0 inherits from the PDO.
|
|
//
|
|
_In_ DEVICE_TYPE DeviceType;
|
|
|
|
// 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 sent to the child device.
|
|
//
|
|
_In_opt_ EVT_DMF_BusFilter_DeviceStarted* EvtDeviceStarted;
|
|
|
|
// 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 the child device.
|
|
//
|
|
_In_opt_ EVT_DMF_BusFilter_DeviceQueryId* EvtDeviceQueryId;
|
|
|
|
// 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(
|
|
_Out_ DMF_BusFilter_CONFIG* BusFilterConfig,
|
|
_In_ PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
RtlZeroMemory(BusFilterConfig,
|
|
sizeof(DMF_BusFilter_CONFIG));
|
|
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
|
|
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(
|
|
_In_ WDFDEVICE Device
|
|
);
|
|
|
|
#endif // defined(DMF_KERNEL_MODE)
|