windows-nt/Source/XPSP1/NT/drivers/wdm/audio/sysaudio/dn.cpp
2020-09-26 16:20:57 +08:00

555 lines
13 KiB
C++

//---------------------------------------------------------------------------
//
// Module: dn.cpp
//
// Description:
//
// DeviceNode Class
//
//@@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"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
PLIST_DEVICE_NODE gplstDeviceNode = NULL;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#pragma INIT_CODE
#pragma INIT_DATA
NTSTATUS
InitializeDeviceNode(
)
{
if(gplstDeviceNode == NULL) {
gplstDeviceNode = new LIST_DEVICE_NODE;
if(gplstDeviceNode == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
}
#ifdef DEBUG
if(gplstConnectNode == NULL) {
gplstConnectNode = new LIST_CONNECT_NODE;
if(gplstConnectNode == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
}
if(gplstPinNodeInstance == NULL) {
gplstPinNodeInstance = new LIST_PIN_NODE_INSTANCE;
if(gplstPinNodeInstance == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
}
if(gplstFilterInstance == NULL) {
gplstFilterInstance = new LIST_DATA_FILTER_INSTANCE;
if(gplstFilterInstance == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
}
#endif
return(STATUS_SUCCESS);
}
#pragma PAGEABLE_CODE
#pragma PAGEABLE_DATA
VOID
UninitializeDeviceNode(
)
{
delete gplstDeviceNode;
gplstDeviceNode = NULL;
#ifdef DEBUG
ASSERT(gplstConnectNode->IsLstEmpty());
delete gplstConnectNode;
gplstConnectNode = NULL;
ASSERT(gplstPinNodeInstance->IsLstEmpty());
delete gplstPinNodeInstance;
gplstPinNodeInstance = NULL;
delete gplstFilterInstance;
gplstFilterInstance = NULL;
#endif
}
//---------------------------------------------------------------------------
CDeviceNode::CDeviceNode(
)
{
ASSERT(gplstDeviceNode != NULL);
AddListEnd(gplstDeviceNode);
DPF1(50, "CDeviceNode: %08x", this);
}
CDeviceNode::~CDeviceNode(
)
{
PFILTER_INSTANCE pFilterInstance;
ULONG i;
Assert(this);
RemoveList();
if (pFilterNode) {
pFilterNode->pDeviceNode = NULL;
}
delete pShingleInstance;
FOR_EACH_LIST_ITEM_DELETE(&lstFilterInstance, pFilterInstance) {
ASSERT(pFilterInstance->GetDeviceNode() == this);
pFilterInstance->SetDeviceNode(NULL);
} END_EACH_LIST_ITEM
if(papVirtualSourceData != NULL) {
for(i = 0; i < cVirtualSourceData; i++) {
delete papVirtualSourceData[i];
}
delete papVirtualSourceData;
}
for(i = 0; i < MAX_SYSAUDIO_DEFAULT_TYPE; i++) {
if(apShingleInstance[i] != NULL) {
if(apShingleInstance[i]->GetDeviceNode() == this) {
apShingleInstance[i]->SetDeviceNode(NULL);
}
}
}
delete pFilterNodeVirtual;
DPF1(50, "~CFilterNode: %08x", this);
}
NTSTATUS
CDeviceNode::Create(
PFILTER_NODE pFilterNode
)
{
NTSTATUS Status = STATUS_SUCCESS;
Assert(this);
Assert(pFilterNode);
this->pFilterNode = pFilterNode;
Status = Update();
if(!NT_SUCCESS(Status)) {
goto exit;
}
pShingleInstance = new SHINGLE_INSTANCE(FLAGS_COMBINE_PINS);
if(pShingleInstance == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
Status = pShingleInstance->Create(this, (LPGUID)&KSCATEGORY_AUDIO_DEVICE);
if(!NT_SUCCESS(Status)) {
goto exit;
}
exit:
return(Status);
}
NTSTATUS
CDeviceNode::Update(
)
{
NTSTATUS Status = STATUS_SUCCESS;
PFILTER_NODE pFilterNodeNext;
ULONG i;
Assert(this);
Assert(pFilterNode);
DPF2(50, "CDeviceNode::Update DN %08x %s", this, DumpName());
lstGraphNode.DestroyList();
lstLogicalFilterNode.DestroyList();
delete pFilterNodeVirtual;
pFilterNodeVirtual = NULL;
if(papVirtualSourceData != NULL) {
for(i = 0; i < cVirtualSourceData; i++) {
delete papVirtualSourceData[i];
}
delete papVirtualSourceData;
papVirtualSourceData = NULL;
}
if(gcVirtualSources != 0) {
papVirtualSourceData = new PVIRTUAL_SOURCE_DATA[gcVirtualSources];
if(papVirtualSourceData == NULL) {
Trap();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
for(i = 0; i < gcVirtualSources; i++) {
papVirtualSourceData[i] = new VIRTUAL_SOURCE_DATA(this);
if(papVirtualSourceData[i] == NULL) {
Trap();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
}
}
cVirtualSourceData = gcVirtualSources;
Status = AddLogicalFilterNode(pFilterNode);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
FOR_EACH_LIST_ITEM(&pFilterNode->lstConnectedFilterNode, pFilterNodeNext) {
Status = AddLogicalFilterNode(pFilterNodeNext);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
} END_EACH_LIST_ITEM
Status = CreateVirtualMixer(this);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
if(pShingleInstance != NULL) {
Status = pShingleInstance->SetDeviceNode(this);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
}
exit:
return(Status);
}
NTSTATUS
CDeviceNode::AddLogicalFilterNode(
PFILTER_NODE pFilterNode
)
{
PLOGICAL_FILTER_NODE pLogicalFilterNode;
NTSTATUS Status = STATUS_SUCCESS;
Status = VirtualizeTopology(this, pFilterNode);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
FOR_EACH_LIST_ITEM(
&pFilterNode->lstLogicalFilterNode,
pLogicalFilterNode) {
DPF2(60, "AddLogicalFilterNode: %08x, DN: %08x",
pLogicalFilterNode,
this);
Status = pLogicalFilterNode->AddList(&lstLogicalFilterNode);
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
pLogicalFilterNode->RemoveList(gplstLogicalFilterNode);
} END_EACH_LIST_ITEM
exit:
return(Status);
}
NTSTATUS
CDeviceNode::CreateGraphNodes(
)
{
PGRAPH_NODE pGraphNode, pGraphNodeMixer;
NTSTATUS Status = STATUS_SUCCESS;
Assert(this);
if(lstGraphNode.IsLstEmpty()) {
pGraphNode = new GRAPH_NODE(this, 0);
if(pGraphNode == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
Trap();
goto exit;
}
Status = pGraphNode->Create();
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
//
// Create a special GraphNode that points to the same renderer or
// capturer, but is marked with the "mixer topology" flag so the
// pins and topology created for this GraphNode is the virtual mixer
// topology for the mixer driver.
//
pGraphNodeMixer = new GRAPH_NODE(this, FLAGS_MIXER_TOPOLOGY);
if(pGraphNodeMixer == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
Trap();
goto exit;
}
Status = pGraphNodeMixer->Create();
if(!NT_SUCCESS(Status)) {
Trap();
goto exit;
}
}
exit:
if(!NT_SUCCESS(Status)) {
Trap();
lstGraphNode.DestroyList();
}
return(Status);
}
NTSTATUS
CDeviceNode::GetIndexByDevice(
OUT PULONG pIndex
)
{
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
PDEVICE_NODE pDeviceNode;
UINT iDevice;
if(this == NULL) {
ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
goto exit;
}
iDevice = 0;
FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
if(pDeviceNode == this) { // This is the one!
*pIndex = iDevice;
Status = STATUS_SUCCESS;
goto exit;
}
iDevice++;
} END_EACH_LIST_ITEM
ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
exit:
return(Status);
}
VOID
CDeviceNode::SetPreferredStatus(
KSPROPERTY_SYSAUDIO_DEFAULT_TYPE DeviceType,
BOOL Enable
)
{
PFILTER_NODE_INSTANCE pFilterNodeInstance=NULL;
KSAUDIO_PREFERRED_STATUS PreferredStatus;
PFILE_OBJECT pFileObject;
KSPROPERTY PreferredStatusProperty;
NTSTATUS Status;
ULONG BytesReturned;
Status = CFilterNodeInstance::Create(&pFilterNodeInstance, this->pFilterNode);
if (!NT_SUCCESS(Status)) {
DPF1(0, "SetPreferredStatus : Create filterinstance failed with status = 0x%08x", Status);
goto exit;
}
pFileObject = pFilterNodeInstance->pFileObject;
ASSERT(pFileObject);
//
// Form the IOCTL packet & send it down
//
PreferredStatusProperty.Set = KSPROPSETID_Audio;
PreferredStatusProperty.Id = KSPROPERTY_AUDIO_PREFERRED_STATUS;
PreferredStatusProperty.Flags = KSPROPERTY_TYPE_SET;
PreferredStatus.Enable = Enable;
PreferredStatus.DeviceType = DeviceType;
PreferredStatus.Flags = 0;
PreferredStatus.Reserved = 0;
DPF(60,"Sending preferred Status to:");
DPF1(60," FriendlyName = %s", DbgUnicode2Sz(this->pFilterNode->GetFriendlyName()));
DPF1(60," DI = %s", DbgUnicode2Sz(this->pFilterNode->GetDeviceInterface()));
DPF1(60," Enable = 0x%08x", Enable);
DPF1(60," DeviceType = 0x%08x", DeviceType);
//
// We actually throw away the status we got back from the device.
// Even if this failed we will still continue setting the device to be the
// preferred device
//
Status = KsSynchronousIoControlDevice(pFileObject,
KernelMode,
IOCTL_KS_PROPERTY,
&PreferredStatusProperty,
sizeof(PreferredStatusProperty),
&PreferredStatus,
sizeof(PreferredStatus),
&BytesReturned);
exit:
if (pFilterNodeInstance) {
pFilterNodeInstance->Destroy();
}
}
NTSTATUS
GetDeviceByIndex(
IN UINT Index,
OUT PDEVICE_NODE *ppDeviceNode
)
{
PDEVICE_NODE pDeviceNode;
NTSTATUS Status;
UINT iDevice;
iDevice = 0;
FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
if(iDevice++ == Index) { // This is the one!
*ppDeviceNode = pDeviceNode;
Status = STATUS_SUCCESS;
goto exit;
}
} END_EACH_LIST_ITEM
Status = STATUS_INVALID_DEVICE_REQUEST;
exit:
return(Status);
}
//---------------------------------------------------------------------------
VOID
DestroyAllGraphs(
)
{
PDEVICE_NODE pDeviceNode;
DPF(50, "DestroyAllGraphs");
FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
pDeviceNode->lstGraphNode.DestroyList();
} END_EACH_LIST_ITEM
#ifdef DEBUG
ASSERT(gplstConnectNode->IsLstEmpty());
ASSERT(gplstPinNodeInstance->IsLstEmpty());
#endif
}
//---------------------------------------------------------------------------
#ifdef DEBUG
ULONG nDevice = 0;
ENUMFUNC
CDeviceNode::Dump()
{
// .sd .si .sg
if(ulDebugFlags &
(DEBUG_FLAGS_DEVICE |
DEBUG_FLAGS_INSTANCE |
DEBUG_FLAGS_GRAPH |
DEBUG_FLAGS_OBJECT)) {
if(ulDebugNumber == MAXULONG || ulDebugNumber == nDevice) {
if(ulDebugFlags & DEBUG_FLAGS_ADDRESS) {
dprintf("%d: %08x %s\n", nDevice, this, DumpName());
}
else {
dprintf("%d: %s\n", nDevice, DumpName());
}
if(ulDebugFlags & (DEBUG_FLAGS_DEVICE | DEBUG_FLAGS_OBJECT)) {
// .sdv
if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
dprintf("DN: %08x FN %08x SHI %08x FNV %08x\n",
this,
pFilterNode,
pShingleInstance,
pFilterNodeVirtual);
dprintf(" %s\n", DumpDeviceInterface());
// .sdv no l
if((ulDebugFlags & DEBUG_FLAGS_LOGICAL_FILTER) == 0) {
dprintf(" lstLFN:");
lstLogicalFilterNode.DumpAddress();
dprintf("\n");
}
// .sdv no g
if((ulDebugFlags & DEBUG_FLAGS_GRAPH) == 0) {
dprintf(" lstGN:");
lstGraphNode.DumpAddress();
dprintf("\n");
}
// .sdv no i
if((ulDebugFlags & DEBUG_FLAGS_INSTANCE) == 0) {
dprintf(" lstFI:");
lstFilterInstance.DumpAddress();
dprintf("\n");
}
dprintf(" papVSD: ");
// .sdvx
if(ulDebugFlags & DEBUG_FLAGS_DETAILS) {
dprintf("\n");
for(ULONG i = 0; i < cVirtualSourceData; i++) {
papVirtualSourceData[i]->Dump();
}
}
else {
for(ULONG i = 0; i < cVirtualSourceData; i++) {
dprintf("%08x ", papVirtualSourceData[i]);
}
dprintf("\n");
}
}
// .sdl
if(ulDebugFlags & DEBUG_FLAGS_LOGICAL_FILTER) {
lstLogicalFilterNode.Dump();
}
}
// .sg
if(ulDebugFlags & DEBUG_FLAGS_GRAPH) {
lstGraphNode.Dump();
}
// .si
if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
lstFilterInstance.Dump();
}
if(ulDebugFlags &
(DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_PIN | DEBUG_FLAGS_TOPOLOGY)) {
dprintf("\n");
}
}
nDevice++;
}
return(STATUS_CONTINUE);
}
#endif
//---------------------------------------------------------------------------