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.
934 lines
27 KiB
934 lines
27 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Module: pins.c
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
//@@BEGIN_MSINTERNAL
|
|
// Development Team:
|
|
// S.Mohanraj
|
|
//
|
|
// 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"
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
static const WCHAR AllocatorTypeName[] = KSSTRING_Allocator;
|
|
static const WCHAR ClockTypeName[] = KSSTRING_Clock;
|
|
|
|
DEFINE_KSCREATE_DISPATCH_TABLE(PinCreateItems)
|
|
{
|
|
DEFINE_KSCREATE_ITEM(AllocatorDispatchCreate, AllocatorTypeName, 0),
|
|
DEFINE_KSCREATE_ITEM(CClockInstance::ClockDispatchCreate, ClockTypeName, 0),
|
|
};
|
|
|
|
DEFINE_KSDISPATCH_TABLE(
|
|
PinDispatchTable,
|
|
CPinInstance::PinDispatchIoControl, // Ioctl
|
|
DispatchInvalidDeviceRequest, // Read
|
|
CInstance::DispatchForwardIrp, // Write
|
|
DispatchInvalidDeviceRequest, // Flush
|
|
CPinInstance::PinDispatchClose, // Close
|
|
DispatchInvalidDeviceRequest, // QuerySecurity
|
|
DispatchInvalidDeviceRequest, // SetSeturity
|
|
DispatchFastIoDeviceControlFailure, // FastDeviceIoControl
|
|
DispatchFastReadFailure, // FastRead
|
|
DispatchFastWriteFailure // FastWrite
|
|
);
|
|
|
|
DEFINE_KSPROPERTY_TABLE(SysaudioPinPropertyHandlers) {
|
|
DEFINE_KSPROPERTY_ITEM(
|
|
KSPROPERTY_SYSAUDIO_TOPOLOGY_CONNECTION_INDEX, // idProperty
|
|
GetTopologyConnectionIndex, // pfnGetHandler
|
|
sizeof(KSPROPERTY), // cbMinGetPropertyInput
|
|
sizeof(ULONG), // cbMinGetDataInput
|
|
NULL, // pfnSetHandler
|
|
NULL, // Values
|
|
0, // RelationsCount
|
|
NULL, // Relations
|
|
NULL, // SupportHandler
|
|
0 // SerializedSize
|
|
),
|
|
DEFINE_KSPROPERTY_ITEM(
|
|
KSPROPERTY_SYSAUDIO_ATTACH_VIRTUAL_SOURCE, // idProperty
|
|
NULL, // pfnGetHandler
|
|
sizeof(SYSAUDIO_ATTACH_VIRTUAL_SOURCE), // cbMinGetPropertyInput
|
|
0, // cbMinGetDataInput
|
|
AttachVirtualSource, // pfnSetHandler
|
|
NULL, // Values
|
|
0, // RelationsCount
|
|
NULL, // Relations
|
|
NULL, // SupportHandler
|
|
0 // SerializedSize
|
|
),
|
|
DEFINE_KSPROPERTY_ITEM(
|
|
KSPROPERTY_SYSAUDIO_PIN_VOLUME_NODE, // idProperty
|
|
GetPinVolumeNode, // pfnGetHandler
|
|
sizeof(KSPROPERTY), // cbMinGetPropertyInput
|
|
sizeof(ULONG), // cbMinGetDataInput
|
|
NULL, // pfnSetHandler
|
|
NULL, // Values
|
|
0, // RelationsCount
|
|
NULL, // Relations
|
|
NULL, // SupportHandler
|
|
0 // SerializedSize
|
|
),
|
|
};
|
|
|
|
DEFINE_KSPROPERTY_TABLE(PinConnectionHandlers) {
|
|
DEFINE_KSPROPERTY_ITEM(
|
|
KSPROPERTY_CONNECTION_STATE, // idProperty
|
|
CPinInstance::PinStateHandler, // pfnGetHandler
|
|
sizeof(KSPROPERTY), // cbMinGetPropertyInput
|
|
sizeof(ULONG), // cbMinGetDataInput
|
|
CPinInstance::PinStateHandler, // pfnSetHandler
|
|
NULL, // Values
|
|
0, // RelationsCount
|
|
NULL, // Relations
|
|
NULL, // SupportHandler
|
|
0 // SerializedSize
|
|
)
|
|
};
|
|
|
|
DEFINE_KSPROPERTY_TABLE (AudioPinPropertyHandlers)
|
|
{
|
|
DEFINE_KSPROPERTY_ITEM(
|
|
KSPROPERTY_AUDIO_VOLUMELEVEL,
|
|
PinVirtualPropertyHandler,
|
|
sizeof(KSNODEPROPERTY_AUDIO_CHANNEL),
|
|
sizeof(LONG),
|
|
PinVirtualPropertyHandler,
|
|
&PropertyValuesVolume,
|
|
0,
|
|
NULL,
|
|
(PFNKSHANDLER)PinVirtualPropertySupportHandler,
|
|
0
|
|
)
|
|
};
|
|
|
|
DEFINE_KSPROPERTY_SET_TABLE(PinPropertySet)
|
|
{
|
|
DEFINE_KSPROPERTY_SET(
|
|
&KSPROPSETID_Connection, // Set
|
|
SIZEOF_ARRAY(PinConnectionHandlers), // PropertiesCount
|
|
PinConnectionHandlers, // PropertyItem
|
|
0, // FastIoCount
|
|
NULL // FastIoTable
|
|
),
|
|
DEFINE_KSPROPERTY_SET(
|
|
&KSPROPSETID_Sysaudio_Pin, // Set
|
|
SIZEOF_ARRAY(SysaudioPinPropertyHandlers), // PropertiesCount
|
|
SysaudioPinPropertyHandlers, // PropertyItem
|
|
0, // FastIoCount
|
|
NULL // FastIoTable
|
|
),
|
|
DEFINE_KSPROPERTY_SET(
|
|
&KSPROPSETID_Audio, // Set
|
|
SIZEOF_ARRAY(AudioPinPropertyHandlers), // PropertiesCount
|
|
AudioPinPropertyHandlers, // PropertyItem
|
|
0, // FastIoCount
|
|
NULL // FastIoTable
|
|
)
|
|
};
|
|
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
|
|
CPinInstance::CPinInstance(
|
|
IN PPARENT_INSTANCE pParentInstance
|
|
) : CInstance(pParentInstance)
|
|
{
|
|
}
|
|
|
|
CPinInstance::~CPinInstance(
|
|
)
|
|
{
|
|
PGRAPH_NODE_INSTANCE pGraphNodeInstance;
|
|
|
|
Assert(this);
|
|
Assert(pFilterInstance);
|
|
DPF1(100, "~CPinInstance: %08x", this);
|
|
if(pStartNodeInstance != NULL) {
|
|
pGraphNodeInstance = pFilterInstance->pGraphNodeInstance;
|
|
if(pGraphNodeInstance != NULL) {
|
|
Assert(pGraphNodeInstance);
|
|
ASSERT(PinId < pGraphNodeInstance->cPins);
|
|
ASSERT(pGraphNodeInstance->pacPinInstances != NULL);
|
|
ASSERT(pGraphNodeInstance->pacPinInstances[PinId].CurrentCount > 0);
|
|
|
|
pGraphNodeInstance->pacPinInstances[PinId].CurrentCount--;
|
|
}
|
|
else {
|
|
DPF2(10, "~CPinInstance PI %08x FI %08x no GNI",
|
|
this,
|
|
pFilterInstance);
|
|
}
|
|
pStartNodeInstance->Destroy();
|
|
}
|
|
else {
|
|
DPF2(10, "~CPinInstance PI %08x FI %08x no SNI",
|
|
this,
|
|
pFilterInstance);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
CPinInstance::PinDispatchCreate(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PGRAPH_NODE_INSTANCE pGraphNodeInstance;
|
|
PPIN_INSTANCE pPinInstance = NULL;
|
|
PKSPIN_CONNECT pPinConnect = NULL;
|
|
NTSTATUS Status;
|
|
|
|
::GrabMutex();
|
|
|
|
Status = GetRelatedGraphNodeInstance(pIrp, &pGraphNodeInstance);
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
Assert(pGraphNodeInstance);
|
|
ASSERT(pGraphNodeInstance->pacPinInstances != NULL);
|
|
ASSERT(pGraphNodeInstance->paPinDescriptors != NULL);
|
|
|
|
//
|
|
// Get the PinConnect structure from KS.
|
|
// This function will copy creation parameters to pPinConnect.
|
|
// Also do a basic connectibility testing by comparing KSDATAFORMAT of
|
|
// pin descriptors and the request.
|
|
//
|
|
Status = KsValidateConnectRequest(
|
|
pIrp,
|
|
pGraphNodeInstance->cPins,
|
|
pGraphNodeInstance->paPinDescriptors,
|
|
&pPinConnect);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
#ifdef DEBUG
|
|
DPF1(60, "PinDispatchCreate: KsValidateConnectReq FAILED %08x", Status);
|
|
if(pPinConnect != NULL) {
|
|
DumpPinConnect(60, pPinConnect);
|
|
}
|
|
#endif
|
|
goto exit;
|
|
}
|
|
ASSERT(pPinConnect->PinId < pGraphNodeInstance->cPins);
|
|
|
|
#ifdef DEBUG
|
|
DPF(60, "PinDispatchCreate:");
|
|
DumpPinConnect(60, pPinConnect);
|
|
#endif
|
|
// Check the pin instance count
|
|
if(!pGraphNodeInstance->IsPinInstances(pPinConnect->PinId)) {
|
|
DPF4(60, "PinDispatchCreate: not enough ins GNI %08x #%d C %d P %d",
|
|
pGraphNodeInstance,
|
|
pPinConnect->PinId,
|
|
pGraphNodeInstance->pacPinInstances[pPinConnect->PinId].CurrentCount,
|
|
pGraphNodeInstance->pacPinInstances[pPinConnect->PinId].PossibleCount);
|
|
Status = STATUS_DEVICE_BUSY;
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate per pin instance data
|
|
pPinInstance = new PIN_INSTANCE(
|
|
&pGraphNodeInstance->pFilterInstance->ParentInstance);
|
|
if(pPinInstance == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
// Setup the pin's instance data
|
|
pPinInstance->ulVolumeNodeNumber = MAXULONG;
|
|
pPinInstance->pFilterInstance = pGraphNodeInstance->pFilterInstance;
|
|
pPinInstance->PinId = pPinConnect->PinId;
|
|
|
|
Status = pPinInstance->DispatchCreate(
|
|
pIrp,
|
|
(UTIL_PFN)PinDispatchCreateKP,
|
|
pPinConnect,
|
|
SIZEOF_ARRAY(PinCreateItems),
|
|
PinCreateItems,
|
|
&PinDispatchTable);
|
|
|
|
pPinConnect->PinId = pPinInstance->PinId;
|
|
if(!NT_SUCCESS(Status)) {
|
|
#ifdef DEBUG
|
|
DPF1(60, "PinDispatchCreate: FAILED: %08x ", Status);
|
|
DumpPinConnect(60, pPinConnect);
|
|
#endif
|
|
goto exit;
|
|
}
|
|
// Increment the reference count on this pin
|
|
ASSERT(pPinInstance->pStartNodeInstance != NULL);
|
|
ASSERT(pGraphNodeInstance->pacPinInstances != NULL);
|
|
pGraphNodeInstance->pacPinInstances[pPinInstance->PinId].CurrentCount++;
|
|
exit:
|
|
if(!NT_SUCCESS(Status)) {
|
|
delete pPinInstance;
|
|
}
|
|
::ReleaseMutex();
|
|
|
|
pIrp->IoStatus.Status = Status;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
CPinInstance::PinDispatchCreateKP(
|
|
PPIN_INSTANCE pPinInstance,
|
|
PKSPIN_CONNECT pPinConnect
|
|
)
|
|
{
|
|
PWAVEFORMATEX pWaveFormatExRequested = NULL;
|
|
PFILTER_INSTANCE pFilterInstance;
|
|
PSTART_NODE pStartNode;
|
|
NTSTATUS Status;
|
|
|
|
Assert(pPinInstance);
|
|
pFilterInstance = pPinInstance->pFilterInstance;
|
|
Assert(pFilterInstance);
|
|
ASSERT(pPinInstance->PinId < pFilterInstance->pGraphNodeInstance->cPins);
|
|
ASSERT(pPinConnect->PinId < pFilterInstance->pGraphNodeInstance->cPins);
|
|
|
|
|
|
if(IsEqualGUID(
|
|
&PKSDATAFORMAT(pPinConnect + 1)->Specifier,
|
|
&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) {
|
|
pWaveFormatExRequested =
|
|
&PKSDATAFORMAT_WAVEFORMATEX(pPinConnect + 1)->WaveFormatEx;
|
|
}
|
|
else if(IsEqualGUID(
|
|
&PKSDATAFORMAT(pPinConnect + 1)->Specifier,
|
|
&KSDATAFORMAT_SPECIFIER_DSOUND)) {
|
|
pWaveFormatExRequested =
|
|
&PKSDATAFORMAT_DSOUND(pPinConnect + 1)->BufferDesc.WaveFormatEx;
|
|
}
|
|
|
|
if(pWaveFormatExRequested != NULL) {
|
|
// Fix SampleSize if zero
|
|
if(PKSDATAFORMAT(pPinConnect + 1)->SampleSize == 0) {
|
|
PKSDATAFORMAT(pPinConnect + 1)->SampleSize =
|
|
pWaveFormatExRequested->nBlockAlign;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try each start node until success
|
|
//
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
//
|
|
// First loop through all the start nodes which are not marked SECONDPASS
|
|
// and try to create a StartNodeInstance
|
|
//
|
|
FOR_EACH_LIST_ITEM(
|
|
pFilterInstance->pGraphNodeInstance->aplstStartNode[pPinInstance->PinId],
|
|
pStartNode) {
|
|
|
|
Assert(pStartNode);
|
|
Assert(pFilterInstance);
|
|
|
|
if(pStartNode->ulFlags & STARTNODE_FLAGS_SECONDPASS) {
|
|
continue;
|
|
}
|
|
|
|
if(pFilterInstance->pGraphNodeInstance->IsGraphValid(
|
|
pStartNode,
|
|
pPinInstance->PinId)) {
|
|
|
|
Status = CStartNodeInstance::Create(
|
|
pPinInstance,
|
|
pStartNode,
|
|
pPinConnect,
|
|
pWaveFormatExRequested,
|
|
NULL);
|
|
if(NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
//
|
|
// If first pass failed to create an instance try all the second pass
|
|
// StartNodes in the list. This is being done for creating paths with no GFX
|
|
// because we created a path with AEC and no GFX earlier.
|
|
//
|
|
FOR_EACH_LIST_ITEM(
|
|
pFilterInstance->pGraphNodeInstance->aplstStartNode[pPinInstance->PinId],
|
|
pStartNode) {
|
|
|
|
Assert(pStartNode);
|
|
Assert(pFilterInstance);
|
|
|
|
if((pStartNode->ulFlags & STARTNODE_FLAGS_SECONDPASS) == 0) {
|
|
continue;
|
|
}
|
|
|
|
if(pFilterInstance->pGraphNodeInstance->IsGraphValid(
|
|
pStartNode,
|
|
pPinInstance->PinId)) {
|
|
|
|
Status = CStartNodeInstance::Create(
|
|
pPinInstance,
|
|
pStartNode,
|
|
pPinConnect,
|
|
pWaveFormatExRequested,
|
|
NULL);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
} END_EACH_LIST_ITEM
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
Status = pPinInstance->SetNextFileObject(
|
|
pPinInstance->pStartNodeInstance->pPinNodeInstance->hPin);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
CPinInstance::PinDispatchClose(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PPIN_INSTANCE pPinInstance;
|
|
|
|
::GrabMutex();
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
|
|
pPinInstance = (PPIN_INSTANCE)pIrpStack->FileObject->FsContext;
|
|
Assert(pPinInstance);
|
|
pIrpStack->FileObject->FsContext = NULL;
|
|
delete pPinInstance;
|
|
|
|
::ReleaseMutex();
|
|
|
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
CPinInstance::PinDispatchIoControl(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
PSTART_NODE_INSTANCE pStartNodeInstance;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PKSPROPERTY pProperty = NULL;
|
|
PPIN_INSTANCE pPinInstance;
|
|
BOOL fProperty = FALSE;
|
|
ULONG ulFlags = 0;
|
|
|
|
#ifdef DEBUG
|
|
DumpIoctl(pIrp, "Pin");
|
|
#endif
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
switch(pIrpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_KS_PROPERTY:
|
|
fProperty = TRUE;
|
|
break;
|
|
|
|
case IOCTL_KS_ENABLE_EVENT:
|
|
case IOCTL_KS_DISABLE_EVENT:
|
|
case IOCTL_KS_METHOD:
|
|
break;
|
|
|
|
default:
|
|
return(DispatchForwardIrp(pDeviceObject, pIrp));
|
|
}
|
|
|
|
::GrabMutex();
|
|
|
|
pPinInstance = (PPIN_INSTANCE)pIrpStack->FileObject->FsContext;
|
|
Status = pPinInstance->GetStartNodeInstance(&pStartNodeInstance);
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
Assert(pPinInstance->pFilterInstance);
|
|
Assert(pPinInstance->pFilterInstance->pGraphNodeInstance);
|
|
|
|
if(pIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
|
|
sizeof(KSPROPERTY)) {
|
|
|
|
__try {
|
|
if(pIrp->AssociatedIrp.SystemBuffer == NULL) {
|
|
pProperty = (PKSPROPERTY)
|
|
(pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer);
|
|
|
|
// Validate the pointers if the client is not trusted.
|
|
if(pIrp->RequestorMode != KernelMode) {
|
|
ProbeForWrite(
|
|
pProperty,
|
|
pIrpStack->Parameters.DeviceIoControl.InputBufferLength,
|
|
sizeof(BYTE));
|
|
}
|
|
}
|
|
else {
|
|
pProperty =
|
|
(PKSPROPERTY)((PUCHAR)pIrp->AssociatedIrp.SystemBuffer +
|
|
((pIrpStack->Parameters.DeviceIoControl.OutputBufferLength +
|
|
FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT));
|
|
}
|
|
ulFlags = pProperty->Flags;
|
|
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Trap();
|
|
Status = GetExceptionCode();
|
|
DPF1(5, "PinDispatchIoControl: Exception %08x", Status);
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// This check allows the actual node or filter return the set's
|
|
// supported, etc. instead of always return only the sets sysaudio
|
|
// supports.
|
|
//
|
|
if(ulFlags & KSPROPERTY_TYPE_TOPOLOGY) {
|
|
if(fProperty) {
|
|
if((ulFlags & (KSPROPERTY_TYPE_GET |
|
|
KSPROPERTY_TYPE_SET |
|
|
KSPROPERTY_TYPE_BASICSUPPORT)) == 0) {
|
|
|
|
// NOTE: ForwardIrpNode releases gMutex
|
|
return(ForwardIrpNode(
|
|
pIrp,
|
|
pProperty,
|
|
pPinInstance->pFilterInstance,
|
|
pPinInstance));
|
|
}
|
|
}
|
|
else {
|
|
// NOTE: ForwardIrpNode releases gMutex
|
|
return(ForwardIrpNode(
|
|
pIrp,
|
|
pProperty,
|
|
pPinInstance->pFilterInstance,
|
|
pPinInstance));
|
|
}
|
|
}
|
|
}
|
|
|
|
switch(pIrpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_KS_PROPERTY:
|
|
|
|
Status = KsPropertyHandler(
|
|
pIrp,
|
|
SIZEOF_ARRAY(PinPropertySet),
|
|
(PKSPROPERTY_SET)PinPropertySet);
|
|
|
|
if(Status != STATUS_NOT_FOUND &&
|
|
Status != STATUS_PROPSET_NOT_FOUND) {
|
|
break;
|
|
}
|
|
// Fall through if property not found
|
|
|
|
case IOCTL_KS_ENABLE_EVENT:
|
|
case IOCTL_KS_DISABLE_EVENT:
|
|
case IOCTL_KS_METHOD:
|
|
|
|
// NOTE: ForwardIrpNode releases gMutex
|
|
return(ForwardIrpNode(
|
|
pIrp,
|
|
NULL,
|
|
pPinInstance->pFilterInstance,
|
|
pPinInstance));
|
|
|
|
default:
|
|
ASSERT(FALSE); // Can't happen because of above switch
|
|
}
|
|
exit:
|
|
::ReleaseMutex();
|
|
|
|
pIrp->IoStatus.Status = Status;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
CPinInstance::PinStateHandler
|
|
(
|
|
IN PIRP pIrp,
|
|
IN PKSPROPERTY pProperty,
|
|
IN OUT PKSSTATE pState
|
|
)
|
|
{
|
|
PSTART_NODE_INSTANCE pStartNodeInstance;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
#ifdef DEBUG
|
|
extern PSZ apszStates[];
|
|
#endif
|
|
Status = ::GetStartNodeInstance(pIrp, &pStartNodeInstance);
|
|
if(!NT_SUCCESS(Status)) {
|
|
Trap();
|
|
goto exit;
|
|
}
|
|
if(pProperty->Flags & KSPROPERTY_TYPE_GET) {
|
|
*pState = pStartNodeInstance->CurrentState;
|
|
pIrp->IoStatus.Information = sizeof(KSSTATE);
|
|
if(*pState == KSSTATE_PAUSE) {
|
|
if(pStartNodeInstance->pPinNodeInstance->
|
|
pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_OUT) {
|
|
Status = STATUS_NO_DATA_DETECTED;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ASSERT(pProperty->Flags & KSPROPERTY_TYPE_SET);
|
|
|
|
DPF3(90, "PinStateHandler from %s to %s - SNI: %08x",
|
|
apszStates[pStartNodeInstance->CurrentState],
|
|
apszStates[*pState],
|
|
pStartNodeInstance);
|
|
|
|
Status = pStartNodeInstance->SetState(*pState, 0);
|
|
if(!NT_SUCCESS(Status)) {
|
|
DPF1(90, "PinStateHandler FAILED: %08x", Status);
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
GetRelatedStartNodeInstance(
|
|
IN PIRP pIrp,
|
|
OUT PSTART_NODE_INSTANCE *ppStartNodeInstance
|
|
)
|
|
{
|
|
return(((PPIN_INSTANCE)IoGetCurrentIrpStackLocation(pIrp)->FileObject->
|
|
RelatedFileObject->FsContext)->GetStartNodeInstance(ppStartNodeInstance));
|
|
}
|
|
|
|
NTSTATUS
|
|
GetStartNodeInstance(
|
|
IN PIRP pIrp,
|
|
OUT PSTART_NODE_INSTANCE *ppStartNodeInstance
|
|
)
|
|
{
|
|
return(((PPIN_INSTANCE)IoGetCurrentIrpStackLocation(pIrp)->FileObject->
|
|
FsContext)->GetStartNodeInstance(ppStartNodeInstance));
|
|
}
|
|
|
|
NTSTATUS
|
|
CPinInstance::GetStartNodeInstance(
|
|
OUT PSTART_NODE_INSTANCE *ppStartNodeInstance
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if(this == NULL || pStartNodeInstance == NULL) {
|
|
DPF(60, "GetStartNodeInstance: pStartNodeInstance == NULL");
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
goto exit;
|
|
}
|
|
Assert(this);
|
|
*ppStartNodeInstance = pStartNodeInstance;
|
|
exit:
|
|
return(Status);
|
|
}
|
|
|
|
#pragma LOCKED_CODE
|
|
#pragma LOCKED_DATA
|
|
|
|
// NOTE: ForwardIrpNode releases gMutex
|
|
|
|
NTSTATUS
|
|
ForwardIrpNode(
|
|
IN PIRP pIrp,
|
|
IN OPTIONAL PKSPROPERTY pProperty, // already validated or NULL
|
|
IN PFILTER_INSTANCE pFilterInstance,
|
|
IN OPTIONAL PPIN_INSTANCE pPinInstance
|
|
)
|
|
{
|
|
PGRAPH_NODE_INSTANCE pGraphNodeInstance;
|
|
PFILE_OBJECT pFileObject = NULL;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PKSEVENTDATA pEventData;
|
|
ULONG OriginalNodeId;
|
|
NTSTATUS Status;
|
|
|
|
Assert(pFilterInstance);
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
Status = pFilterInstance->GetGraphNodeInstance(&pGraphNodeInstance);
|
|
if(!NT_SUCCESS(Status)) {
|
|
goto exit;
|
|
}
|
|
Assert(pGraphNodeInstance);
|
|
|
|
if(pPinInstance != NULL) {
|
|
pFileObject = pPinInstance->GetNextFileObject();
|
|
}
|
|
|
|
__try {
|
|
if(pIrpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(KSNODEPROPERTY) &&
|
|
pIrpStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_DISABLE_EVENT) {
|
|
|
|
if(pProperty == NULL) {
|
|
if(pIrp->AssociatedIrp.SystemBuffer == NULL) {
|
|
Trap();
|
|
pProperty = (PKSPROPERTY)
|
|
(pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer);
|
|
|
|
// Validate the pointers if the client is not trusted.
|
|
if(pIrp->RequestorMode != KernelMode) {
|
|
ProbeForWrite(
|
|
pProperty,
|
|
pIrpStack->Parameters.DeviceIoControl.InputBufferLength,
|
|
sizeof(BYTE));
|
|
}
|
|
}
|
|
else {
|
|
pProperty = (PKSPROPERTY)
|
|
((PUCHAR)pIrp->AssociatedIrp.SystemBuffer +
|
|
((pIrpStack->Parameters.DeviceIoControl.OutputBufferLength +
|
|
FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT));
|
|
}
|
|
}
|
|
|
|
ASSERT(!IsEqualGUID(&pProperty->Set, &KSPROPSETID_Sysaudio));
|
|
ASSERT(!IsEqualGUID(&pProperty->Set, &KSEVENTSETID_Sysaudio));
|
|
|
|
if(pProperty->Flags & KSPROPERTY_TYPE_TOPOLOGY) {
|
|
|
|
OriginalNodeId = ((PKSNODEPROPERTY)pProperty)->NodeId;
|
|
|
|
if(pPinInstance == NULL) {
|
|
Status = pGraphNodeInstance->
|
|
GetTopologyNodeFileObject(
|
|
&pFileObject,
|
|
OriginalNodeId);
|
|
}
|
|
else {
|
|
Status = pPinInstance->pStartNodeInstance->
|
|
GetTopologyNodeFileObject(
|
|
&pFileObject,
|
|
OriginalNodeId);
|
|
}
|
|
if(!NT_SUCCESS(Status)) {
|
|
DPF1(100,
|
|
"ForwardIrpNode: GetTopologyNodeFileObject FAILED %08x",
|
|
Status);
|
|
goto exit;
|
|
}
|
|
|
|
// Put real node number in input buffer
|
|
((PKSNODEPROPERTY)pProperty)->NodeId = pGraphNodeInstance->
|
|
papTopologyNode[OriginalNodeId]->ulRealNodeNumber;
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// If it is DisableEvent && if it is of type DPC. We look into the
|
|
// Reserved field of KSEVENTDATA to extract the original node on
|
|
// which the event was enabled (The high bit is set if we ever
|
|
// stashed a NodeId in there).
|
|
//
|
|
if(pIrpStack->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_KS_DISABLE_EVENT) {
|
|
|
|
if(pIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
|
|
sizeof(KSEVENTDATA)) {
|
|
pEventData = (PKSEVENTDATA)
|
|
pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
if(pIrp->RequestorMode != KernelMode) {
|
|
ProbeForWrite(
|
|
pEventData,
|
|
pIrpStack->Parameters.DeviceIoControl.InputBufferLength,
|
|
sizeof (BYTE));
|
|
}
|
|
|
|
OriginalNodeId = ULONG(pEventData->Dpc.Reserved);
|
|
|
|
if((pEventData->NotificationType == KSEVENTF_DPC) &&
|
|
(OriginalNodeId & 0x80000000)) {
|
|
|
|
OriginalNodeId = OriginalNodeId & 0x7fffffff;
|
|
|
|
if(pPinInstance == NULL) {
|
|
Status = pGraphNodeInstance->
|
|
GetTopologyNodeFileObject(
|
|
&pFileObject,
|
|
OriginalNodeId);
|
|
}
|
|
else {
|
|
Status = pPinInstance->pStartNodeInstance->
|
|
GetTopologyNodeFileObject(
|
|
&pFileObject,
|
|
OriginalNodeId);
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
DPF1(100,
|
|
"ForwardIrpNode: GetTopologyNodeFileObject FAILED %08x",
|
|
Status);
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Trap();
|
|
Status = GetExceptionCode();
|
|
DPF1(5, "ForwardIrpNode: Exception %08x", Status);
|
|
goto exit;
|
|
}
|
|
|
|
if(pFileObject == NULL) {
|
|
Status = STATUS_NOT_FOUND;
|
|
DPF1(100, "ForwardIrpNode: Property not forwarded: %08x", pProperty);
|
|
goto exit;
|
|
}
|
|
pIrpStack->FileObject = pFileObject;
|
|
|
|
//
|
|
// If it was EnableEvent we stash away pointer to KSEVENTDATA, so that we
|
|
// can stash the NodeID into it after we call the next driver on the stack
|
|
//
|
|
KPROCESSOR_MODE RequestorMode;
|
|
|
|
if((pProperty != NULL) &&
|
|
(pIrpStack->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_KS_ENABLE_EVENT) &&
|
|
!(pProperty->Flags & KSEVENT_TYPE_BASICSUPPORT) &&
|
|
(pProperty->Flags & KSPROPERTY_TYPE_TOPOLOGY) &&
|
|
(pProperty->Flags & KSEVENT_TYPE_ENABLE)) {
|
|
pEventData = (PKSEVENTDATA) pIrp->UserBuffer;
|
|
RequestorMode = pIrp->RequestorMode;
|
|
}
|
|
else {
|
|
pEventData = NULL;
|
|
}
|
|
|
|
IoSkipCurrentIrpStackLocation(pIrp);
|
|
AssertFileObject(pIrpStack->FileObject);
|
|
Status = IoCallDriver(IoGetRelatedDeviceObject(pFileObject), pIrp);
|
|
|
|
//
|
|
// Stash away the Node id in EventData
|
|
//
|
|
__try {
|
|
if (pEventData != NULL) {
|
|
if (RequestorMode == UserMode) {
|
|
ProbeForWrite(pEventData, sizeof(KSEVENTDATA), sizeof(BYTE));
|
|
}
|
|
|
|
if (pEventData->NotificationType == KSEVENTF_DPC) {
|
|
pEventData->Dpc.Reserved = OriginalNodeId | 0x80000000;
|
|
}
|
|
}
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Trap();
|
|
Status = GetExceptionCode();
|
|
DPF1(5, "ForwardIrpNode: Exception %08x", Status);
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
DPF1(100, "ForwardIrpNode: Status %08x", Status);
|
|
}
|
|
|
|
::ReleaseMutex();
|
|
return(Status);
|
|
|
|
exit:
|
|
::ReleaseMutex();
|
|
|
|
pIrp->IoStatus.Status = Status;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
return(Status);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
#ifdef DEBUG
|
|
|
|
extern PSZ apszStates[];
|
|
|
|
ENUMFUNC
|
|
CPinInstance::Dump(
|
|
)
|
|
{
|
|
Assert(this);
|
|
// .siv
|
|
if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
|
|
dprintf("PI: %08x FI %08x SNI %08x ulVNN %08x PinId %d\n",
|
|
this,
|
|
pFilterInstance,
|
|
pStartNodeInstance,
|
|
ulVolumeNodeNumber,
|
|
PinId);
|
|
CInstance::Dump();
|
|
ParentInstance.Dump();
|
|
}
|
|
else {
|
|
dprintf(" Fr: Sysaudio\n PinId: %d\n", PinId);
|
|
}
|
|
if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
|
|
if(pStartNodeInstance != NULL) {
|
|
pStartNodeInstance->Dump();
|
|
}
|
|
}
|
|
return(STATUS_CONTINUE);
|
|
}
|
|
|
|
ENUMFUNC
|
|
CPinInstance::DumpAddress(
|
|
)
|
|
{
|
|
if(this != NULL) {
|
|
Assert(this);
|
|
dprintf(" %08x", this);
|
|
}
|
|
return(STATUS_CONTINUE);
|
|
}
|
|
|
|
#endif
|
|
|
|
//---------------------------------------------------------------------------
|
|
// End of File: pins.c
|
|
//---------------------------------------------------------------------------
|