//--------------------------------------------------------------------------- // // 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); // // AEC is a special filter we need both of the logical filters. // So AddRef for all FilterNodeInstances of all aec logical filters. // 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 { // // For reusable filters find the appropriate FilterNodeInstances and // AddRef. // 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 } } // // Otherwise create a FilterNodeInstance. // 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); // // ISSUE: 02/20/02 ALPERS // Can this IoRegisterPlugPlayNotification ever return // STATUS_NOT_IMPLEMENTED on XP? // This code does not make sense to me... // if(!NT_SUCCESS(Status)) { if(Status != STATUS_NOT_IMPLEMENTED) { goto exit; } // ISSUE: 02/20/02 ALPERS // According to Adrian Oney... // On Win2K/XP, when a driver passes in a handle // (EventCategoryTargetDeviceChange), PnP tries to find the hardware // backing that handle. It does this by sending a "homing beacon" IRP, // IRP_MN_QUERY_DEVICE_RELATIONS(TargetDeviceRelation). Filesystems // and legacy side-stacks typically forward this to the underlying // WDM stack. The PDO responds by identifying itself as the underlying // hardware. If a filesystem or legacy-stack fails this request // (or a broken WDM stack fails the request), then // STATUS_NOT_IMPLEMENTED would be returned. // // Therefore this ASSERT is inserted to see if we ever get // STATUS_NOT_IMPLEMENTED. // ASSERT(0); 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 // // ISSUE: 02/20/02 ALPERS // It is not clear to me yet what happens if the mutex times out. // We will return STATUS_TIMEOUT, then what. // Should we veto the removal if we cannot acquire the mutex?s // Status = KeWaitForMutexObject( &gMutex, Executive, KernelMode, FALSE, &li); if(Status != STATUS_TIMEOUT) { DeviceQueryRemove(); ReleaseMutex(); } else { DPF1(5, "TargetDeviceChangeNotification: FAILED %08x", Status); } } return(STATUS_SUCCESS); } //---------------------------------------------------------------------------