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

497 lines
11 KiB
C++

//---------------------------------------------------------------------------
//
// Module: shi.cpp
//
// Description:
//
// Shingle Instance 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"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
const WCHAR cwstrDefaultDevicePath[] =
REGSTR_PATH_MULTIMEDIA_AUDIO_DEFAULT_DEVICE;
const WCHAR cwstrDefaultMidiDevicePath[] =
REGSTR_PATH_MULTIMEDIA_MIDI_DEFAULT_DEVICE;
const WCHAR cwstrPlayback[] = REGSTR_VAL_DEFAULT_PLAYBACK_DEVICE;
const WCHAR cwstrRecord[] = REGSTR_VAL_DEFAULT_RECORD_DEVICE;
const WCHAR cwstrMidi[] = REGSTR_VAL_DEFAULT_MIDI_DEVICE;
const WCHAR cwstrFilterTypeName[] = KSSTRING_Filter;
const WCHAR cwstrPlaybackShingleName[] = L"PLAYBACK";
const WCHAR cwstrRecordShingleName[] = L"RECORD";
const WCHAR cwstrMidiShingleName[] = L"MIDI";
const WCHAR cwstrMixerShingleName[] = L"MIXER";
#ifdef DEBUG
const WCHAR cwstrPinsShingleName[] = L"PINS";
#endif
PSHINGLE_INSTANCE apShingleInstance[] = {
NULL, // KSPROPERTY_SYSAUDIO_NORMAL_DEFAULT
NULL, // KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT
NULL, // KSPROPERTY_SYSAUDIO_RECORD_DEFAULT
NULL, // KSPROPERTY_SYSAUDIO_MIDI_DEFAULT
NULL, // KSPROPERTY_SYSAUDIO_MIXER_DEFAULT
#ifdef DEBUG
NULL,
#endif
};
ULONG aulFlags[] = {
FLAGS_COMBINE_PINS | GN_FLAGS_PLAYBACK | GN_FLAGS_RECORD | GN_FLAGS_MIDI,
FLAGS_COMBINE_PINS | GN_FLAGS_PLAYBACK,
FLAGS_COMBINE_PINS | GN_FLAGS_RECORD,
FLAGS_COMBINE_PINS | GN_FLAGS_MIDI,
FLAGS_MIXER_TOPOLOGY | GN_FLAGS_PLAYBACK | GN_FLAGS_RECORD | GN_FLAGS_MIDI,
#ifdef DEBUG
GN_FLAGS_PLAYBACK,
#endif
};
PCWSTR apcwstrRegistryPath[] = {
NULL,
cwstrDefaultDevicePath,
cwstrDefaultDevicePath,
cwstrDefaultMidiDevicePath,
NULL,
#ifdef DEBUG
cwstrDefaultDevicePath,
#endif
};
PCWSTR apcwstrRegistryValue[] = {
NULL,
cwstrPlayback,
cwstrRecord,
cwstrMidi,
NULL,
#ifdef DEBUG
cwstrPlayback,
#endif
};
PCWSTR apcwstrReference[] = {
cwstrFilterTypeName,
cwstrPlaybackShingleName,
cwstrRecordShingleName,
cwstrMidiShingleName,
cwstrMixerShingleName,
#ifdef DEBUG
cwstrPinsShingleName,
#endif
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
NTSTATUS
CShingleInstance::InitializeShingle(
)
{
NTSTATUS Status = STATUS_SUCCESS;
int i;
for(i = 0; i < SIZEOF_ARRAY(apShingleInstance); i++) {
apShingleInstance[i] = new SHINGLE_INSTANCE(
aulFlags[i],
apcwstrRegistryPath[i],
apcwstrRegistryValue[i]);
if(apShingleInstance[i] == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
Status = apShingleInstance[i]->CreateCreateItem(apcwstrReference[i]);
if(!NT_SUCCESS(Status)) {
goto exit;
}
}
Status = QueueWorkList(
CShingleInstance::InitializeShingleWorker,
NULL,
NULL);
if(!NT_SUCCESS(Status)) {
goto exit;
}
exit:
if(!NT_SUCCESS(Status)) {
UninitializeShingle();
}
return(Status);
}
VOID
CShingleInstance::UninitializeShingle(
)
{
int i;
for(i = 0; i < SIZEOF_ARRAY(apShingleInstance); i++) {
delete apShingleInstance[i];
apShingleInstance[i] = NULL;
}
}
NTSTATUS
CShingleInstance::InitializeShingleWorker(
PVOID pReference1,
PVOID pReference2
)
{
NTSTATUS Status;
Status = apShingleInstance[KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT]->Create(
NULL,
(LPGUID)&KSCATEGORY_PREFERRED_WAVEOUT_DEVICE);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = apShingleInstance[KSPROPERTY_SYSAUDIO_RECORD_DEFAULT]->Create(
NULL,
(LPGUID)&KSCATEGORY_PREFERRED_WAVEIN_DEVICE);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = apShingleInstance[KSPROPERTY_SYSAUDIO_MIDI_DEFAULT]->Create(
NULL,
(LPGUID)&KSCATEGORY_PREFERRED_MIDIOUT_DEVICE);
if(!NT_SUCCESS(Status)) {
goto exit;
}
exit:
return(Status);
}
//---------------------------------------------------------------------------
CShingleInstance::CShingleInstance(
ULONG ulFlags,
PCWSTR pcwstrRegistryPath,
PCWSTR pcwstrRegistryValue
)
{
this->ulFlags = ulFlags;
this->pcwstrRegistryPath = pcwstrRegistryPath;
this->pcwstrRegistryValue = pcwstrRegistryValue;
}
CShingleInstance::~CShingleInstance(
)
{
PKSOBJECT_CREATE_ITEM pCreateItem;
DPF1(60, "~CShingleInstance: %08x", this);
ASSERT(this != NULL);
Assert(this);
DestroyDeviceInterface();
FOR_EACH_LIST_ITEM(&lstCreateItem, pCreateItem) {
DestroyCreateItem(pCreateItem);
} END_EACH_LIST_ITEM
}
NTSTATUS
CShingleInstance::Create(
IN PDEVICE_NODE pDeviceNode,
IN LPGUID pguidClass
)
{
NTSTATUS Status = STATUS_SUCCESS;
static ULONG cShingles = 0;
this->pDeviceNode = pDeviceNode;
swprintf(wstrReference, L"SAD%d", cShingles++);
Status = CreateCreateItem(wstrReference);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = CreateDeviceInterface(pguidClass, wstrReference);
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF2(60, "CShingleInstance::Create: %08x DN: %08x", this, pDeviceNode);
exit:
return(Status);
}
NTSTATUS
CShingleInstance::SetDeviceNode(
IN PDEVICE_NODE pDeviceNode
)
{
NTSTATUS Status = STATUS_SUCCESS;
DisableDeviceInterface();
this->pDeviceNode = pDeviceNode;
Status = EnableDeviceInterface();
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF2(60, "CShingleInstance::SetDeviceNode: %08x DN: %08x",
this,
pDeviceNode);
exit:
return(Status);
}
NTSTATUS
CShingleInstance::CreateCreateItem(
IN PCWSTR pcwstrReference
)
{
PKSOBJECT_CREATE_ITEM pCreateItem = NULL;
NTSTATUS Status = STATUS_SUCCESS;
pCreateItem = new KSOBJECT_CREATE_ITEM;
if(pCreateItem == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
pCreateItem->Create = CFilterInstance::FilterDispatchCreate;
pCreateItem->Context = this;
RtlInitUnicodeString(&pCreateItem->ObjectClass, pcwstrReference);
Status = KsAllocateObjectCreateItem(
gpDeviceInstance->pDeviceHeader,
pCreateItem,
FALSE,
NULL);
if(!NT_SUCCESS(Status)) {
pCreateItem->ObjectClass.Buffer = NULL;
goto exit;
}
Status = lstCreateItem.AddList(pCreateItem);
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF3(60, "CSHI::CreateItem SHI %08x CI %08x %s",
this,
pCreateItem,
DbgUnicode2Sz((PWSTR)pcwstrReference));
exit:
if(!NT_SUCCESS(Status)) {
DestroyCreateItem(pCreateItem);
}
return(Status);
}
ENUMFUNC
CShingleInstance::DestroyCreateItem(
IN PKSOBJECT_CREATE_ITEM pCreateItem
)
{
if(pCreateItem != NULL) {
if(pCreateItem->ObjectClass.Buffer != NULL) {
KsFreeObjectCreateItem(
gpDeviceInstance->pDeviceHeader,
&pCreateItem->ObjectClass);
}
delete pCreateItem;
}
return(STATUS_CONTINUE);
}
NTSTATUS
CShingleInstance::CreateDeviceInterface(
IN LPGUID pguidClass,
IN PCWSTR pcwstrReference
)
{
UNICODE_STRING ustrReference;
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(gpDeviceInstance != NULL);
ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL);
ASSERT(gpDeviceInstance->pDeviceHeader != NULL);
ASSERT(this->ustrSymbolicLinkName.Buffer == NULL);
RtlInitUnicodeString(&ustrReference, pcwstrReference);
Status = IoRegisterDeviceInterface(
gpDeviceInstance->pPhysicalDeviceObject,
pguidClass,
&ustrReference,
&this->ustrSymbolicLinkName);
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = EnableDeviceInterface();
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF3(60, "CSHI::CreateDeviceInterface: %08x %s %s",
this,
DbgGuid2Sz(pguidClass),
DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer));
exit:
return(Status);
}
NTSTATUS
CShingleInstance::EnableDeviceInterface(
)
{
NTSTATUS Status = STATUS_SUCCESS;
PWSTR pwstrFriendlyName = L"";
UNICODE_STRING ustrValueName;
UNICODE_STRING ustrValue;
HANDLE hkey = NULL;
if(this->ustrSymbolicLinkName.Buffer == NULL) {
ASSERT(NT_SUCCESS(Status));
goto exit;
}
//
// Put the proxy's CLSID in the new device interface
//
Status = IoOpenDeviceInterfaceRegistryKey(
&this->ustrSymbolicLinkName,
STANDARD_RIGHTS_ALL,
&hkey);
if(!NT_SUCCESS(Status)) {
goto exit;
}
RtlInitUnicodeString(&ustrValueName, L"CLSID");
RtlInitUnicodeString(&ustrValue, L"{17CCA71B-ECD7-11D0-B908-00A0C9223196}");
Status = ZwSetValueKey(
hkey,
&ustrValueName,
0,
REG_SZ,
ustrValue.Buffer,
ustrValue.Length);
if(!NT_SUCCESS(Status)) {
goto exit;
}
//
// Set the friendly name into the new device interface
//
if(pDeviceNode != NULL) {
Assert(pDeviceNode);
if(pDeviceNode->GetFriendlyName() != NULL) {
pwstrFriendlyName = pDeviceNode->GetFriendlyName();
}
else {
DPF(5, "CSHI::EnableDeviceInterface no friendly name");
}
}
RtlInitUnicodeString(&ustrValueName, L"FriendlyName");
Status = ZwSetValueKey(
hkey,
&ustrValueName,
0,
REG_SZ,
pwstrFriendlyName,
(wcslen(pwstrFriendlyName) * sizeof(WCHAR)) + sizeof(UNICODE_NULL));
if(!NT_SUCCESS(Status)) {
goto exit;
}
Status = IoSetDeviceInterfaceState(&this->ustrSymbolicLinkName, TRUE);
if(!NT_SUCCESS(Status)) {
goto exit;
}
DPF2(60, "CSHI::EnableDeviceInterface: %08x %s",
this,
DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer));
exit:
if(hkey != NULL) {
ZwClose(hkey);
}
return(Status);
}
VOID
CShingleInstance::DisableDeviceInterface(
)
{
Assert(this);
DPF1(60, "CSHI::DisableDeviceInterface %08x", this);
if(this->ustrSymbolicLinkName.Buffer != NULL) {
DPF1(60, "CSHI::DisableDeviceInterface %s",
DbgUnicode2Sz(this->ustrSymbolicLinkName.Buffer));
IoSetDeviceInterfaceState(&this->ustrSymbolicLinkName, FALSE);
}
}
VOID
CShingleInstance::DestroyDeviceInterface(
)
{
DisableDeviceInterface();
RtlFreeUnicodeString(&this->ustrSymbolicLinkName);
this->ustrSymbolicLinkName.Buffer = NULL;
}
//---------------------------------------------------------------------------
#ifdef DEBUG
ENUMFUNC
CShingleInstance::Dump()
{
PKSOBJECT_CREATE_ITEM pCreateItem;
dprintf("SHI: %08x DN %08x ulFlags %08x\n", this, pDeviceNode, ulFlags);
if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
dprintf(" lstCreateItem:");
FOR_EACH_LIST_ITEM(&lstCreateItem, pCreateItem) {
dprintf(" %08x", pCreateItem);
} END_EACH_LIST_ITEM
dprintf("\n");
dprintf(" %s\n", DbgUnicode2Sz(ustrSymbolicLinkName.Buffer));
dprintf(" %s\n", DbgUnicode2Sz((PWSTR)pcwstrRegistryPath));
dprintf(" %s\n", DbgUnicode2Sz((PWSTR)pcwstrRegistryValue));
}
return(STATUS_CONTINUE);
}
#endif