mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
863 lines
24 KiB
863 lines
24 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Module: notify.cpp
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
//@@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 GUID *apguidCategories[] = {
|
|
&KSCATEGORY_AUDIO,
|
|
&KSCATEGORY_AUDIO_GFX,
|
|
&KSCATEGORY_TOPOLOGY,
|
|
&KSCATEGORY_BRIDGE,
|
|
&KSCATEGORY_RENDER,
|
|
&KSCATEGORY_CAPTURE,
|
|
&KSCATEGORY_MIXER,
|
|
&KSCATEGORY_DATATRANSFORM,
|
|
&KSCATEGORY_ACOUSTIC_ECHO_CANCEL,
|
|
&KSCATEGORY_INTERFACETRANSFORM,
|
|
&KSCATEGORY_MEDIUMTRANSFORM,
|
|
&KSCATEGORY_DATACOMPRESSOR,
|
|
&KSCATEGORY_DATADECOMPRESSOR,
|
|
&KSCATEGORY_COMMUNICATIONSTRANSFORM,
|
|
&KSCATEGORY_SPLITTER,
|
|
&KSCATEGORY_AUDIO_SPLITTER,
|
|
&KSCATEGORY_SYNTHESIZER,
|
|
#ifdef KSCATEGORY_DRM_DESCRAMBLE
|
|
&KSCATEGORY_DRM_DESCRAMBLE,
|
|
#endif
|
|
#ifdef KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR
|
|
&KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR,
|
|
#endif
|
|
};
|
|
|
|
ULONG aulFilterType[] = {
|
|
FILTER_TYPE_AUDIO,
|
|
FILTER_TYPE_GFX,
|
|
FILTER_TYPE_TOPOLOGY,
|
|
FILTER_TYPE_BRIDGE,
|
|
FILTER_TYPE_RENDERER,
|
|
FILTER_TYPE_CAPTURER,
|
|
FILTER_TYPE_MIXER,
|
|
FILTER_TYPE_DATA_TRANSFORM,
|
|
FILTER_TYPE_AEC,
|
|
FILTER_TYPE_INTERFACE_TRANSFORM,
|
|
FILTER_TYPE_MEDIUM_TRANSFORM,
|
|
FILTER_TYPE_DATA_TRANSFORM,
|
|
FILTER_TYPE_DATA_TRANSFORM,
|
|
FILTER_TYPE_COMMUNICATION_TRANSFORM,
|
|
FILTER_TYPE_SPLITTER,
|
|
FILTER_TYPE_SPLITTER,
|
|
FILTER_TYPE_SYNTHESIZER,
|
|
#ifdef KSCATEGORY_DRM_DESCRAMBLE
|
|
FILTER_TYPE_DRM_DESCRAMBLE,
|
|
#endif
|
|
#ifdef KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR
|
|
FILTER_TYPE_MIC_ARRAY_PROCESSOR,
|
|
#endif
|
|
};
|
|
|
|
PVOID pNotificationHandle = NULL;
|
|
PVOID pNotificationHandle2 = NULL;
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
RegisterForPlugPlayNotifications(
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
DPF(50, "RegisterForPlugPlayNotifications");
|
|
ASSERT(gpDeviceInstance != NULL);
|
|
ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL);
|
|
|
|
Status = IoRegisterPlugPlayNotification(
|
|
EventCategoryDeviceInterfaceChange,
|
|
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
|
(LPGUID)&KSCATEGORY_AUDIO,
|
|
gpDeviceInstance->pPhysicalDeviceObject->DriverObject,
|
|
(NTSTATUS (*)(PVOID, PVOID))AudioDeviceInterfaceNotification,
|
|
NULL,
|
|
&pNotificationHandle);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
//
|
|
// For compatibility with Intel AEC which isn't registered in the AUDIO
|
|
// category, sysaudio needs to hook the AEC category.
|
|
//
|
|
Status = IoRegisterPlugPlayNotification(
|
|
EventCategoryDeviceInterfaceChange,
|
|
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
|
(LPGUID)&KSCATEGORY_ACOUSTIC_ECHO_CANCEL,
|
|
gpDeviceInstance->pPhysicalDeviceObject->DriverObject,
|
|
(NTSTATUS (*)(PVOID, PVOID))AudioDeviceInterfaceNotification,
|
|
NULL,
|
|
&pNotificationHandle2);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
UnregisterForPlugPlayNotifications(
|
|
)
|
|
{
|
|
if(pNotificationHandle != NULL) {
|
|
IoUnregisterPlugPlayNotification(pNotificationHandle);
|
|
}
|
|
if(pNotificationHandle2 != NULL) {
|
|
IoUnregisterPlugPlayNotification(pNotificationHandle2);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DecrementAddRemoveCount(
|
|
)
|
|
{
|
|
if(InterlockedDecrement(&glPendingAddDelete) == 0) {
|
|
DPF(50, "DecrementAddRemoveCount: sending event");
|
|
KsGenerateEventList(
|
|
NULL,
|
|
KSEVENT_SYSAUDIO_ADDREMOVE_DEVICE,
|
|
&gEventQueue,
|
|
KSEVENTS_SPINLOCK,
|
|
&gEventLock);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
AddFilterWorker(
|
|
PWSTR pwstrDeviceInterface,
|
|
PVOID pReference
|
|
)
|
|
{
|
|
AddFilter(pwstrDeviceInterface, NULL);
|
|
ExFreePool(pwstrDeviceInterface);
|
|
DecrementAddRemoveCount();
|
|
|
|
// Dereference sysaudio FDO.
|
|
ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
DeleteFilterWorker(
|
|
PWSTR pwstrDeviceInterface,
|
|
PVOID pReference
|
|
)
|
|
{
|
|
DeleteFilter(pwstrDeviceInterface);
|
|
ExFreePool(pwstrDeviceInterface);
|
|
DecrementAddRemoveCount();
|
|
|
|
// Dereference sysaudio FDO.
|
|
ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
AudioDeviceInterfaceNotification(
|
|
IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION pNotification,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PWSTR pwstrDeviceInterface;
|
|
|
|
DPF1(50, "AudioDeviceInterfaceNotification: (%s)",
|
|
DbgUnicode2Sz(pNotification->SymbolicLinkName->Buffer));
|
|
|
|
//
|
|
// SECURITY NOTE:
|
|
// We trust the Buffer, because it is passed to us as part of notification
|
|
// from PnP subsystem.
|
|
//
|
|
pwstrDeviceInterface = (PWSTR)
|
|
ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
(wcslen(pNotification->SymbolicLinkName->Buffer) + 1) * sizeof(WCHAR),
|
|
'ASYS');
|
|
|
|
if(pwstrDeviceInterface == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
// The notification sends null terminated unicode strings
|
|
wcscpy(pwstrDeviceInterface, pNotification->SymbolicLinkName->Buffer);
|
|
|
|
if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
|
|
//
|
|
// Keep a reference so that PnP does not REMOVE the device
|
|
// when the Worker thread is running.
|
|
// If the thread is scheduled successfully, it will remove the reference
|
|
// when exiting.
|
|
//
|
|
ObReferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
|
|
|
|
InterlockedIncrement(&glPendingAddDelete);
|
|
Status = QueueWorkList(
|
|
(UTIL_PFN)AddFilterWorker,
|
|
pwstrDeviceInterface,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
|
|
}
|
|
}
|
|
else if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) {
|
|
//
|
|
// Keep a reference so that PnP does not REMOVE the device
|
|
// when the Worker thread is running.
|
|
// If the thread is scheduled successfully, it will remove the reference
|
|
// when exiting.
|
|
//
|
|
ObReferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
|
|
|
|
InterlockedIncrement(&glPendingAddDelete);
|
|
Status = QueueWorkList(
|
|
(UTIL_PFN)DeleteFilterWorker,
|
|
pwstrDeviceInterface,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ObDereferenceObject(gpDeviceInstance->pFunctionalDeviceObject);
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// SECURITY NOTE:
|
|
// Sysaudio is registering only for EventCategoryDeviceInterfaceChange.
|
|
// This should send ARRIVAL and REMOVAL.
|
|
// If anything else comes up, we will return SUCCESS.
|
|
// However we are making sure that pwstrDeviceInterface is not leaked.
|
|
//
|
|
ExFreePool(pwstrDeviceInterface);
|
|
}
|
|
|
|
exit:
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(pwstrDeviceInterface);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AddFilter(
|
|
PWSTR pwstrDeviceInterface,
|
|
PFILTER_NODE *ppFilterNode // if !NULL, physical connection addfilter
|
|
)
|
|
{
|
|
PFILTER_NODE pFilterNodeDuplicate = NULL;
|
|
PFILTER_NODE pFilterNode = NULL;
|
|
UNICODE_STRING ustrFilterName;
|
|
UNICODE_STRING ustrAliasName;
|
|
UNICODE_STRING ustrName;
|
|
NTSTATUS Status;
|
|
ULONG fulType;
|
|
int i;
|
|
|
|
DPF1(50, "AddFilter: (%s)", DbgUnicode2Sz(pwstrDeviceInterface));
|
|
|
|
fulType = 0;
|
|
RtlInitUnicodeString(&ustrFilterName, pwstrDeviceInterface);
|
|
|
|
//
|
|
// For each Interface in apguidCategories, get interface alias of
|
|
// the new device. Check for duplicate interfaces.
|
|
//
|
|
for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
|
|
Status = IoGetDeviceInterfaceAlias(
|
|
&ustrFilterName,
|
|
apguidCategories[i],
|
|
&ustrAliasName);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
HANDLE hAlias;
|
|
|
|
Status = OpenDevice(ustrAliasName.Buffer, &hAlias);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
DPF2(100, "AddFilter: alias (%s) aulFilterType %08x",
|
|
DbgUnicode2Sz(ustrAliasName.Buffer),
|
|
aulFilterType[i]);
|
|
|
|
fulType |= aulFilterType[i];
|
|
ZwClose(hAlias);
|
|
|
|
if(pFilterNodeDuplicate == NULL) {
|
|
FOR_EACH_LIST_ITEM(gplstFilterNode, pFilterNode) {
|
|
if(pFilterNode->GetDeviceInterface() == NULL) {
|
|
continue;
|
|
}
|
|
RtlInitUnicodeString(
|
|
&ustrName,
|
|
pFilterNode->GetDeviceInterface());
|
|
|
|
if(RtlEqualUnicodeString(
|
|
&ustrAliasName,
|
|
&ustrName,
|
|
TRUE)) {
|
|
DPF(50, "AddFilter: dup");
|
|
pFilterNodeDuplicate = pFilterNode;
|
|
break;
|
|
}
|
|
} END_EACH_LIST_ITEM
|
|
}
|
|
}
|
|
else {
|
|
DPF1(10, "AddFilter: OpenDevice FAILED on alias (%s)",
|
|
DbgUnicode2Sz(ustrAliasName.Buffer));
|
|
}
|
|
RtlFreeUnicodeString(&ustrAliasName);
|
|
}
|
|
}
|
|
|
|
pFilterNode = pFilterNodeDuplicate;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Create a new Filter_Node if this is not a duplicate.
|
|
//
|
|
if(pFilterNodeDuplicate == NULL) {
|
|
pFilterNode = new FILTER_NODE(fulType);
|
|
if(pFilterNode == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
Status = pFilterNode->Create(pwstrDeviceInterface);
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
Status = pFilterNode->DuplicateForCapture();
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
DPF1(50, "AddFilter: new CFilterNode fulType %08x", fulType);
|
|
}
|
|
|
|
//
|
|
// If this is called from Interface Notification Callback,
|
|
// create a new DeviceNode for the new FilterNode.
|
|
//
|
|
if(ppFilterNode == NULL) {
|
|
if(pFilterNode->GetType() & FILTER_TYPE_ENDPOINT) {
|
|
|
|
//
|
|
// Check if a DeviceNode has already been created for
|
|
// this FilterNode.
|
|
//
|
|
if (NULL != pFilterNodeDuplicate &&
|
|
NULL != pFilterNodeDuplicate->pDeviceNode) {
|
|
DPF1(5, "Duplicate FilterNode %X. Skip DeviceNode Create",
|
|
pFilterNode);
|
|
}
|
|
else {
|
|
pFilterNode->pDeviceNode = new DEVICE_NODE;
|
|
if(pFilterNode->pDeviceNode == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
Status = pFilterNode->pDeviceNode->Create(pFilterNode);
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DPF(50, "AddFilter: DestroyAllGraphs");
|
|
DestroyAllGraphs();
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if(!NT_SUCCESS(Status)) {
|
|
DPF2(5, "AddFilter: FAILED (%s) %08x",
|
|
DbgUnicode2Sz(pwstrDeviceInterface),
|
|
Status);
|
|
|
|
if(pFilterNode != NULL && pFilterNodeDuplicate == NULL) {
|
|
delete pFilterNode;
|
|
pFilterNode = NULL;
|
|
}
|
|
}
|
|
if(ppFilterNode != NULL) {
|
|
*ppFilterNode = pFilterNode;
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
DeleteFilter(
|
|
PWSTR pwstrDeviceInterface
|
|
)
|
|
{
|
|
UNICODE_STRING ustrFilterName;
|
|
UNICODE_STRING ustrAliasName;
|
|
UNICODE_STRING ustrName;
|
|
PFILTER_NODE pFilterNode;
|
|
NTSTATUS Status;
|
|
int i;
|
|
|
|
DPF1(50, "DeleteFilter: (%s)", DbgUnicode2Sz(pwstrDeviceInterface));
|
|
|
|
RtlInitUnicodeString(&ustrFilterName, pwstrDeviceInterface);
|
|
|
|
//
|
|
// First delete all filter nodes which have the device interface which is
|
|
// going away
|
|
//
|
|
FOR_EACH_LIST_ITEM_DELETE(gplstFilterNode, pFilterNode) {
|
|
if(pFilterNode->GetDeviceInterface() == NULL) {
|
|
continue;
|
|
}
|
|
RtlInitUnicodeString(
|
|
&ustrName,
|
|
pFilterNode->GetDeviceInterface());
|
|
|
|
if(RtlEqualUnicodeString(
|
|
&ustrFilterName,
|
|
&ustrName,
|
|
TRUE)) {
|
|
delete pFilterNode;
|
|
DELETE_LIST_ITEM(gplstFilterNode);
|
|
}
|
|
} END_EACH_LIST_ITEM
|
|
|
|
for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
|
|
|
|
//
|
|
// According to PnP group, it is perfectly safe to ask for aliases
|
|
// during removal. The interface itself will be enabled or disabled. But
|
|
// we will still get the correct aliases.
|
|
//
|
|
Status = IoGetDeviceInterfaceAlias(
|
|
&ustrFilterName,
|
|
apguidCategories[i],
|
|
&ustrAliasName);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
FOR_EACH_LIST_ITEM_DELETE(gplstFilterNode, pFilterNode) {
|
|
|
|
if(pFilterNode->GetDeviceInterface() == NULL) {
|
|
continue;
|
|
}
|
|
RtlInitUnicodeString(
|
|
&ustrName,
|
|
pFilterNode->GetDeviceInterface());
|
|
|
|
if(RtlEqualUnicodeString(
|
|
&ustrAliasName,
|
|
&ustrName,
|
|
TRUE)) {
|
|
delete pFilterNode;
|
|
DELETE_LIST_ITEM(gplstFilterNode);
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
RtlFreeUnicodeString(&ustrAliasName);
|
|
}
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
#define GFX_VERBOSE_LEVEL 50
|
|
|
|
NTSTATUS AddGfx(
|
|
PSYSAUDIO_GFX pSysaudioGfx
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PFILE_OBJECT pFileObject;
|
|
PFILTER_NODE pFilterNode;
|
|
ULONG Flags;
|
|
PWSTR pwstrDeviceName;
|
|
ULONG Length;
|
|
ULONG GfxOrderBase, GfxOrderCeiling;
|
|
|
|
pFileObject = NULL;
|
|
pwstrDeviceName = NULL;
|
|
pFilterNode = NULL;
|
|
GfxOrderBase = GfxOrderCeiling = 0;
|
|
|
|
DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Request to add Gfx %x", pSysaudioGfx);
|
|
DPF1(GFX_VERBOSE_LEVEL, " hGfx = %x", pSysaudioGfx->hGfx);
|
|
DPF1(GFX_VERBOSE_LEVEL, " ulOrder = %x", pSysaudioGfx->ulOrder);
|
|
DPF1(GFX_VERBOSE_LEVEL, " ulType = %x", pSysaudioGfx->ulType);
|
|
DPF1(GFX_VERBOSE_LEVEL, " Flags = %x", pSysaudioGfx->ulFlags);
|
|
|
|
//
|
|
// validate type to be Capture or Render (use public include file!!!)
|
|
//
|
|
if ((pSysaudioGfx->ulType != GFX_DEVICETYPE_RENDER) && (pSysaudioGfx->ulType != GFX_DEVICETYPE_CAPTURE)) {
|
|
Trap();
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Setup GFX Order's base & ceiling for future usage
|
|
//
|
|
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_RENDER) {
|
|
GfxOrderBase = ORDER_RENDER_GFX_FIRST;
|
|
GfxOrderCeiling = ORDER_RENDER_GFX_LAST;
|
|
}
|
|
|
|
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_CAPTURE) {
|
|
GfxOrderBase = ORDER_CAPTURE_GFX_FIRST;
|
|
GfxOrderCeiling = ORDER_CAPTURE_GFX_LAST;
|
|
}
|
|
|
|
ASSERT(GfxOrderBase);
|
|
ASSERT(GfxOrderCeiling);
|
|
|
|
//
|
|
// validate that order is within range
|
|
//
|
|
if (pSysaudioGfx->ulOrder >= (GfxOrderCeiling - GfxOrderBase)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Allocate a Filter Node for the new GFX
|
|
//
|
|
pFilterNode = new FILTER_NODE(FILTER_TYPE_GFX);
|
|
if(pFilterNode == NULL) {
|
|
Trap();
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
pFilterNode->SetRenderCaptureFlags(pSysaudioGfx->ulType);
|
|
|
|
//
|
|
// Copy the Device Name (on which the gfx needs to be attached) into a local copy for our own use
|
|
//
|
|
Status = SafeCopyStringFromOffset(pSysaudioGfx, pSysaudioGfx->ulDeviceNameOffset, &pwstrDeviceName);
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
|
|
DPF1(GFX_VERBOSE_LEVEL, " On DI = %s", DbgUnicode2Sz(pwstrDeviceName));
|
|
|
|
//
|
|
// Make sure that there are no other GFXes with the same order on this device
|
|
//
|
|
|
|
if ((FindGfx(pFilterNode,
|
|
0, // wild card for handle
|
|
pwstrDeviceName,
|
|
pSysaudioGfx->ulOrder+GfxOrderBase))) {
|
|
delete pwstrDeviceName;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get the FileObject of the GFX for future use
|
|
//
|
|
Status = ObReferenceObjectByHandle(
|
|
pSysaudioGfx->hGfx,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
NULL,
|
|
KernelMode,
|
|
(PVOID*)&pFileObject,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
delete pwstrDeviceName;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Add the device name string to global memory to be freed
|
|
//
|
|
Status = pFilterNode->lstFreeMem.AddList(pwstrDeviceName);
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
delete pwstrDeviceName;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Indicate that this Gfx needs be loaded only on the device pointed to be pwstrDeviceName
|
|
//
|
|
Status = pFilterNode->AddDeviceInterfaceMatch(pwstrDeviceName);
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set the Gfx order in the filter node
|
|
//
|
|
pFilterNode->SetOrder(pSysaudioGfx->ulOrder+GfxOrderBase);
|
|
|
|
//
|
|
// Profile the GFX and create pin infos, logical filter nodes etc
|
|
//
|
|
Status = pFilterNode->ProfileFilter(pFileObject);
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Fix the GFX glitching problem. Send the property blindly to GFX
|
|
// filter. KS will handle the property.
|
|
// Failures are not important, ignore them.
|
|
//
|
|
SetKsFrameHolding(pFileObject);
|
|
|
|
exit:
|
|
if(!NT_SUCCESS(Status)) {
|
|
DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Failed, Status = %x", Status);
|
|
if(pFilterNode != NULL) {
|
|
delete pFilterNode;
|
|
pFilterNode = NULL;
|
|
}
|
|
if(pFileObject != NULL) {
|
|
ObDereferenceObject(pFileObject);
|
|
}
|
|
}
|
|
else {
|
|
|
|
DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Added GFX FilterNode %x", pFilterNode);
|
|
DPF1(GFX_VERBOSE_LEVEL, " order = %x", pFilterNode->GetOrder());
|
|
DPF1(GFX_VERBOSE_LEVEL, " type = %x", pFilterNode->GetType());
|
|
DPF1(GFX_VERBOSE_LEVEL, " flags = %x", pFilterNode->GetFlags());
|
|
|
|
//
|
|
// Setup file handle details for later use of
|
|
// the user mode handle passed in
|
|
//
|
|
pFilterNode->SetFileDetails(pSysaudioGfx->hGfx,
|
|
pFileObject,
|
|
PsGetCurrentProcess());
|
|
//
|
|
// Force a rebuild of graph nodes
|
|
//
|
|
DestroyAllGraphs();
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS RemoveGfx(
|
|
PSYSAUDIO_GFX pSysaudioGfx
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PFILE_OBJECT pFileObject=NULL;
|
|
PFILTER_NODE pFilterNode;
|
|
ULONG Flags;
|
|
PWSTR pwstrDeviceName;
|
|
ULONG Length;
|
|
ULONG GfxOrderBase, GfxOrderCeiling;
|
|
|
|
GfxOrderBase = GfxOrderCeiling = 0;
|
|
pwstrDeviceName = NULL;
|
|
|
|
DPF1(GFX_VERBOSE_LEVEL, "RemoveGfx :: Request to remove Gfx %x", pSysaudioGfx);
|
|
DPF1(GFX_VERBOSE_LEVEL, " hGfx = %x", pSysaudioGfx->hGfx);
|
|
DPF1(GFX_VERBOSE_LEVEL, " ulOrder = %x", pSysaudioGfx->ulOrder);
|
|
DPF1(GFX_VERBOSE_LEVEL, " ulType = %x", pSysaudioGfx->ulType);
|
|
DPF1(GFX_VERBOSE_LEVEL, " Flags = %x", pSysaudioGfx->ulFlags);
|
|
|
|
//
|
|
// validate type to be Capture or Render (use public include file!!!)
|
|
//
|
|
if ((pSysaudioGfx->ulType != GFX_DEVICETYPE_RENDER) && (pSysaudioGfx->ulType != GFX_DEVICETYPE_CAPTURE)) {
|
|
Trap();
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Setup GFX Order's base & ceiling for future usage
|
|
//
|
|
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_RENDER) {
|
|
GfxOrderBase = ORDER_RENDER_GFX_FIRST;
|
|
GfxOrderCeiling = ORDER_RENDER_GFX_LAST;
|
|
}
|
|
|
|
if (pSysaudioGfx->ulType == GFX_DEVICETYPE_CAPTURE ) {
|
|
GfxOrderBase = ORDER_CAPTURE_GFX_FIRST;
|
|
GfxOrderCeiling = ORDER_CAPTURE_GFX_LAST;
|
|
}
|
|
|
|
ASSERT(GfxOrderBase);
|
|
ASSERT(GfxOrderCeiling);
|
|
|
|
//
|
|
// Copy the Device Name (on which the gfx needs to be attached) into a local copy for our own use
|
|
//
|
|
Status = SafeCopyStringFromOffset(pSysaudioGfx, pSysaudioGfx->ulDeviceNameOffset, &pwstrDeviceName);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
|
|
DPF1(GFX_VERBOSE_LEVEL, " On DI = %s", DbgUnicode2Sz(pwstrDeviceName));
|
|
|
|
//
|
|
// Find the FilterNode for the Gfx
|
|
//
|
|
|
|
if ((pFilterNode = FindGfx(NULL,
|
|
pSysaudioGfx->hGfx,
|
|
pwstrDeviceName,
|
|
pSysaudioGfx->ulOrder+GfxOrderBase)) == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Should we validate the FileHandle Value?
|
|
//
|
|
|
|
//
|
|
// Dereference the file object
|
|
//
|
|
Status = pFilterNode->ClearFileDetails();
|
|
exit:
|
|
if(!NT_SUCCESS(Status)) {
|
|
DPF1(GFX_VERBOSE_LEVEL, "RemoveGfx :: Failed, Status = %x", Status);
|
|
Trap();
|
|
}
|
|
else {
|
|
delete pFilterNode;
|
|
}
|
|
delete pwstrDeviceName;
|
|
return(Status);
|
|
}
|
|
|
|
PFILTER_NODE
|
|
FindGfx(
|
|
PFILTER_NODE pnewFilterNode,
|
|
HANDLE hGfx,
|
|
PWSTR pwstrDeviceName,
|
|
ULONG GfxOrder
|
|
)
|
|
{
|
|
PFILTER_NODE pFilterNode;
|
|
ULONG DeviceCount;
|
|
UNICODE_STRING usInDevice, usfnDevice;
|
|
PWSTR pwstr;
|
|
|
|
|
|
DPF2(90, "FindGfx:: Looking for GFX with order = %x attached to %s)", GfxOrder, DbgUnicode2Sz(pwstrDeviceName));
|
|
|
|
FOR_EACH_LIST_ITEM(gplstFilterNode, pFilterNode) {
|
|
|
|
//
|
|
// Skip the one we just added
|
|
//
|
|
if (pFilterNode == pnewFilterNode) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check whether this pFilterNode matches the Gfx we are looking for
|
|
//
|
|
if (pFilterNode->DoesGfxMatch(hGfx, pwstrDeviceName, GfxOrder)) {
|
|
return (pFilterNode);
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
NTSTATUS
|
|
SafeCopyStringFromOffset(
|
|
PVOID pBasePointer,
|
|
ULONG Offset,
|
|
PWSTR *String
|
|
)
|
|
{
|
|
ULONG Length;
|
|
PWSTR pwstrString = NULL;
|
|
|
|
*String = NULL;
|
|
|
|
__try {
|
|
Length = wcslen( (PWSTR)(((CHAR *)pBasePointer)+Offset)) + 1;
|
|
pwstrString = new(WCHAR[Length]) ;
|
|
|
|
if(pwstrString == NULL) {
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
wcscpy(pwstrString,(PWSTR)(((CHAR *)pBasePointer)+Offset));
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Trap();
|
|
delete [] pwstrString;
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
*String = pwstrString;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
GetFilterTypeFromGuid(
|
|
IN LPGUID pguid,
|
|
OUT PULONG pfulType
|
|
)
|
|
{
|
|
int i;
|
|
for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
|
|
if (memcmp (apguidCategories[i], pguid, sizeof(GUID)) == 0) {
|
|
*pfulType |= aulFilterType[i];
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
}
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// End of File: notify.cpp
|
|
//---------------------------------------------------------------------------
|