341 lines
8.3 KiB
C++
341 lines
8.3 KiB
C++
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Module: fni.cpp
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
// Filter Node Instance
|
||
|
//
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
// Development Team:
|
||
|
// Mike McLaughlin
|
||
|
//
|
||
|
// History: Date Author Comment
|
||
|
//
|
||
|
// To Do: Date Author Comment
|
||
|
//
|
||
|
//@@END_MSINTERNAL
|
||
|
//
|
||
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
||
|
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
||
|
// PURPOSE.
|
||
|
//
|
||
|
// Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
#include "common.h"
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
CFilterNodeInstance::~CFilterNodeInstance(
|
||
|
)
|
||
|
{
|
||
|
Assert(this);
|
||
|
DPF1(95, "~CFilterNodeInstance: %08x", this);
|
||
|
RemoveListCheck();
|
||
|
UnregisterTargetDeviceChangeNotification();
|
||
|
//
|
||
|
// if hFilter == NULL && pFileObject != NULL
|
||
|
// it means that this filter instance is for a GFX
|
||
|
// do not try to dereference the file object in that case
|
||
|
//
|
||
|
if( (hFilter != NULL) && (pFileObject != NULL) ) {
|
||
|
AssertFileObject(pFileObject);
|
||
|
ObDereferenceObject(pFileObject);
|
||
|
}
|
||
|
if(hFilter != NULL) {
|
||
|
AssertStatus(ZwClose(hFilter));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
CFilterNodeInstance::Create(
|
||
|
PFILTER_NODE_INSTANCE *ppFilterNodeInstance,
|
||
|
PLOGICAL_FILTER_NODE pLogicalFilterNode,
|
||
|
PDEVICE_NODE pDeviceNode,
|
||
|
BOOL fReuseInstance
|
||
|
)
|
||
|
{
|
||
|
PFILTER_NODE_INSTANCE pFilterNodeInstance = NULL;
|
||
|
PLOGICAL_FILTER_NODE pLogicalFilterNode2;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
|
||
|
Assert(pLogicalFilterNode);
|
||
|
Assert(pLogicalFilterNode->pFilterNode);
|
||
|
|
||
|
if(pLogicalFilterNode->GetType() & FILTER_TYPE_AEC) {
|
||
|
FOR_EACH_LIST_ITEM(
|
||
|
&pLogicalFilterNode->pFilterNode->lstLogicalFilterNode,
|
||
|
pLogicalFilterNode2) {
|
||
|
|
||
|
FOR_EACH_LIST_ITEM(
|
||
|
&pLogicalFilterNode2->lstFilterNodeInstance,
|
||
|
pFilterNodeInstance) {
|
||
|
|
||
|
pFilterNodeInstance->AddRef();
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
goto exit;
|
||
|
|
||
|
} END_EACH_LIST_ITEM
|
||
|
|
||
|
} END_EACH_LIST_ITEM
|
||
|
}
|
||
|
else {
|
||
|
if(fReuseInstance) {
|
||
|
FOR_EACH_LIST_ITEM(
|
||
|
&pLogicalFilterNode->lstFilterNodeInstance,
|
||
|
pFilterNodeInstance) {
|
||
|
|
||
|
if(pDeviceNode == NULL ||
|
||
|
pDeviceNode == pFilterNodeInstance->pDeviceNode) {
|
||
|
pFilterNodeInstance->AddRef();
|
||
|
ASSERT(NT_SUCCESS(Status));
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
} END_EACH_LIST_ITEM
|
||
|
}
|
||
|
}
|
||
|
Status = Create(&pFilterNodeInstance, pLogicalFilterNode->pFilterNode);
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
goto exit;
|
||
|
}
|
||
|
pFilterNodeInstance->pDeviceNode = pDeviceNode;
|
||
|
pFilterNodeInstance->AddList(&pLogicalFilterNode->lstFilterNodeInstance);
|
||
|
exit:
|
||
|
*ppFilterNodeInstance = pFilterNodeInstance;
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
CFilterNodeInstance::Create(
|
||
|
PFILTER_NODE_INSTANCE *ppFilterNodeInstance,
|
||
|
PFILTER_NODE pFilterNode
|
||
|
)
|
||
|
{
|
||
|
PFILTER_NODE_INSTANCE pFilterNodeInstance = NULL;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
|
||
|
Assert(pFilterNode);
|
||
|
pFilterNodeInstance = new FILTER_NODE_INSTANCE;
|
||
|
if(pFilterNodeInstance == NULL) {
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
goto exit;
|
||
|
}
|
||
|
pFilterNodeInstance->pFilterNode = pFilterNode;
|
||
|
pFilterNodeInstance->AddRef();
|
||
|
|
||
|
|
||
|
if(pFilterNode->GetType() & FILTER_TYPE_GFX) {
|
||
|
//
|
||
|
// if it is a GFX do not try to open the device, just re-use
|
||
|
// the file object which we cached during AddGfx
|
||
|
//
|
||
|
pFilterNodeInstance->pFileObject = pFilterNode->GetFileObject();
|
||
|
pFilterNodeInstance->hFilter = NULL;
|
||
|
Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// if it is not a GFX go ahead and open the device.
|
||
|
//
|
||
|
Status = pFilterNode->OpenDevice(&pFilterNodeInstance->hFilter);
|
||
|
}
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
DPF2(10, "CFilterNodeInstance::Create OpenDevice Failed: %08x FN: %08x",
|
||
|
Status,
|
||
|
pFilterNode);
|
||
|
pFilterNodeInstance->hFilter = NULL;
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
if (pFilterNodeInstance->hFilter) {
|
||
|
Status = ObReferenceObjectByHandle(
|
||
|
pFilterNodeInstance->hFilter,
|
||
|
GENERIC_READ | GENERIC_WRITE,
|
||
|
NULL,
|
||
|
KernelMode,
|
||
|
(PVOID*)&pFilterNodeInstance->pFileObject,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
Trap();
|
||
|
pFilterNodeInstance->pFileObject = NULL;
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
AssertFileObject(pFilterNodeInstance->pFileObject);
|
||
|
Status = pFilterNodeInstance->RegisterTargetDeviceChangeNotification();
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
goto exit;
|
||
|
}
|
||
|
DPF2(95, "CFilterNodeInstance::Create %08x FN: %08x",
|
||
|
pFilterNodeInstance,
|
||
|
pFilterNode);
|
||
|
exit:
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
if (pFilterNodeInstance) {
|
||
|
pFilterNodeInstance->Destroy();
|
||
|
}
|
||
|
pFilterNodeInstance = NULL;
|
||
|
}
|
||
|
*ppFilterNodeInstance = pFilterNodeInstance;
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
CFilterNodeInstance::RegisterTargetDeviceChangeNotification(
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
ASSERT(gpDeviceInstance != NULL);
|
||
|
ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL);
|
||
|
ASSERT(pNotificationHandle == NULL);
|
||
|
|
||
|
Status = IoRegisterPlugPlayNotification(
|
||
|
EventCategoryTargetDeviceChange,
|
||
|
0,
|
||
|
pFileObject,
|
||
|
gpDeviceInstance->pPhysicalDeviceObject->DriverObject,
|
||
|
(NTSTATUS (*)(PVOID, PVOID))
|
||
|
CFilterNodeInstance::TargetDeviceChangeNotification,
|
||
|
this,
|
||
|
&pNotificationHandle);
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
if(Status != STATUS_NOT_IMPLEMENTED) {
|
||
|
goto exit;
|
||
|
}
|
||
|
Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
DPF2(100, "RegisterTargetDeviceChangeNotification: FNI: %08x PFO: %08x",
|
||
|
this,
|
||
|
this->pFileObject);
|
||
|
exit:
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CFilterNodeInstance::UnregisterTargetDeviceChangeNotification(
|
||
|
)
|
||
|
{
|
||
|
HANDLE hNotification;
|
||
|
|
||
|
DPF1(100, "UnregisterTargetDeviceChangeNotification: FNI: %08x", this);
|
||
|
hNotification = pNotificationHandle;
|
||
|
if(hNotification != NULL) {
|
||
|
pNotificationHandle = NULL;
|
||
|
IoUnregisterPlugPlayNotification(hNotification);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
CFilterNodeInstance::DeviceQueryRemove(
|
||
|
)
|
||
|
{
|
||
|
PGRAPH_NODE_INSTANCE pGraphNodeInstance;
|
||
|
PDEVICE_NODE pDeviceNode;
|
||
|
PGRAPH_NODE pGraphNode;
|
||
|
|
||
|
FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
|
||
|
|
||
|
FOR_EACH_LIST_ITEM(&pDeviceNode->lstGraphNode, pGraphNode) {
|
||
|
|
||
|
FOR_EACH_LIST_ITEM(
|
||
|
&pGraphNode->lstGraphNodeInstance,
|
||
|
pGraphNodeInstance) {
|
||
|
|
||
|
for(ULONG n = 0;
|
||
|
n < pGraphNodeInstance->Topology.TopologyNodesCount;
|
||
|
n++) {
|
||
|
pGraphNodeInstance->
|
||
|
papFilterNodeInstanceTopologyTable[n]->Destroy();
|
||
|
|
||
|
pGraphNodeInstance->
|
||
|
papFilterNodeInstanceTopologyTable[n] = NULL;
|
||
|
}
|
||
|
|
||
|
} END_EACH_LIST_ITEM
|
||
|
|
||
|
} END_EACH_LIST_ITEM
|
||
|
|
||
|
} END_EACH_LIST_ITEM
|
||
|
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
CFilterNodeInstance::TargetDeviceChangeNotification(
|
||
|
IN PTARGET_DEVICE_REMOVAL_NOTIFICATION pNotification,
|
||
|
IN PFILTER_NODE_INSTANCE pFilterNodeInstance
|
||
|
)
|
||
|
{
|
||
|
DPF3(5, "TargetDeviceChangeNotification: FNI: %08x PFO: %08x %s",
|
||
|
pFilterNodeInstance,
|
||
|
pNotification->FileObject,
|
||
|
DbgGuid2Sz(&pNotification->Event));
|
||
|
|
||
|
if(IsEqualGUID(
|
||
|
&pNotification->Event,
|
||
|
&GUID_TARGET_DEVICE_REMOVE_COMPLETE) ||
|
||
|
IsEqualGUID(
|
||
|
&pNotification->Event,
|
||
|
&GUID_TARGET_DEVICE_QUERY_REMOVE)) {
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
LARGE_INTEGER li = {0, 10000}; // wait for 1 ms
|
||
|
|
||
|
Status = KeWaitForMutexObject(
|
||
|
&gMutex,
|
||
|
Executive,
|
||
|
KernelMode,
|
||
|
FALSE,
|
||
|
&li);
|
||
|
|
||
|
if(Status != STATUS_TIMEOUT) {
|
||
|
|
||
|
DeviceQueryRemove();
|
||
|
ReleaseMutex();
|
||
|
}
|
||
|
else {
|
||
|
DPF1(5, "TargetDeviceChangeNotification: FAILED %08x", Status);
|
||
|
}
|
||
|
}
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
ENUMFUNC
|
||
|
CFilterNodeInstance::Dump(
|
||
|
)
|
||
|
{
|
||
|
if(this == NULL) {
|
||
|
return(STATUS_CONTINUE);
|
||
|
}
|
||
|
if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
|
||
|
dprintf("FNI: %08x cRef %02x FO %08x H %08x DN %08x FN %08x NH %08x\n",
|
||
|
this,
|
||
|
cReference,
|
||
|
pFileObject,
|
||
|
hFilter,
|
||
|
pDeviceNode,
|
||
|
pFilterNode,
|
||
|
pNotificationHandle);
|
||
|
dprintf(" %s\n", pFilterNode->DumpName());
|
||
|
}
|
||
|
return(STATUS_CONTINUE);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//---------------------------------------------------------------------------
|