windows-nt/Source/XPSP1/NT/drivers/wdm/bda/bdasup/bdatopgy.c
2020-09-26 16:20:57 +08:00

4218 lines
104 KiB
C

//==========================================================================;
//
// 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) 1992 - 1998 Microsoft Corporation. All Rights Reserved.
//
//==========================================================================;
#include <wdm.h>
#include <limits.h>
#include <unknown.h>
#include <ks.h>
#include <ksmedia.h>
#include <bdatypes.h>
#include <bdamedia.h>
#include <bdasup.h>
#include "bdasupi.h"
/*
- DriverEntry
-
* This the the required DriverEntry for the BDA Support Driver.
* Though required, it is never actually called.
*
*/
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pszuRegistryPath
)
//////////////////////////////////////////////////////////////////////////////////////
{
//$BUGBUG This entry point is required but never called.
return STATUS_SUCCESS;
}
STDMETHODIMP_(NTSTATUS)
BdaFindContextEntry(
PBDA_CONTEXT_LIST pContextList,
PVOID pvReference,
PVOID * ppvContext
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uliEntry;
KIRQL oldIrql;
ASSERT( pContextList);
ASSERT( ppvContext);
if (!pContextList->fInitialized)
{
status = STATUS_NOT_FOUND;
goto errExit;
}
// NULL pvReference is not valid.
//
if (!pvReference)
{
status = STATUS_INVALID_PARAMETER;
*ppvContext = NULL;
goto errExit;
}
// Lock down the list while we search it.
//
KeAcquireSpinLock( &(pContextList->lock), &oldIrql);
// Find a list entry with a matching pvReference
//
for (uliEntry = 0; uliEntry < pContextList->ulcListEntries; uliEntry++)
{
if (pContextList->pListEntries[uliEntry].pvReference == pvReference)
{
break;
}
}
if (uliEntry >= pContextList->ulcListEntries)
{
// No matching entry was found so return error.
//
status = STATUS_NOT_FOUND;
*ppvContext = NULL;
}
else
{
// Return the pvContext corresponding to the matching pvReference.
//
*ppvContext = pContextList->pListEntries[uliEntry].pvContext;
}
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
errExit:
return status;
}
STDMETHODIMP_(NTSTATUS)
BdaCreateContextEntry(
PBDA_CONTEXT_LIST pContextList,
PVOID pvReference,
ULONG ulcbContext,
PVOID * ppvContext
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uliEntry;
KIRQL oldIrql;
ASSERT( pContextList);
ASSERT( ppvContext);
if (!pContextList->fInitialized)
{
KeInitializeSpinLock ( &(pContextList->lock));
pContextList->fInitialized = TRUE;
}
// See if a list entry has already been created.
//
status = BdaFindContextEntry( pContextList, pvReference, ppvContext);
if (status != STATUS_NOT_FOUND)
{
goto errExit;
}
status = STATUS_SUCCESS;
KeAcquireSpinLock( &(pContextList->lock), &oldIrql);
// If the current block of context entries is full, allocate
// a bigger block to put the new entry into.
//
if (pContextList->ulcListEntries >= pContextList->ulcMaxListEntries)
{
ULONG ulcEntriesToAllocate;
PBDA_CONTEXT_ENTRY pNewList;
ulcEntriesToAllocate = pContextList->ulcMaxListEntries
+ pContextList->ulcListEntriesPerBlock;
pNewList = (PBDA_CONTEXT_ENTRY) ExAllocatePool(
NonPagedPool,
ulcEntriesToAllocate * sizeof( BDA_CONTEXT_ENTRY)
);
if (!pNewList)
{
status = STATUS_NO_MEMORY;
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
goto errExit;
}
RtlZeroMemory( pNewList,
ulcEntriesToAllocate * sizeof( BDA_CONTEXT_ENTRY)
);
if (pContextList->pListEntries)
{
RtlMoveMemory( pNewList,
pContextList->pListEntries,
pContextList->ulcMaxListEntries
* sizeof( BDA_CONTEXT_ENTRY)
);
ExFreePool( pContextList->pListEntries);
}
pContextList->pListEntries = pNewList;
pContextList->ulcMaxListEntries = ulcEntriesToAllocate;
}
#ifdef SORTED_CONTEXT_ENTRIES
// Find the proper place to insert the new entry into the list.
//
for (uliEntry = 0; uliEntry < pContextList->ulcListEntries; uliEntry++)
{
if (pContextList->pListEntries[uliEntry].pvReference > pvReference)
{
break;
}
}
#else
uliEntry = pContextList->ulcListEntries;
#endif // SORTED_CONTEXT_ENTRIES
// Allocate a new context entry
//
*ppvContext = ExAllocatePool( NonPagedPool, ulcbContext);
if (!*ppvContext)
{
status = STATUS_NO_MEMORY;
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
goto errExit;
}
#ifdef SORTED_CONTEXT_ENTRIES
// If the new entry is in the middle of the list, then create
// a whole for it by moving the end of the list down.
//
if (uliEntry < pContextList->ulcListEntries)
{
// NOTE! RtlMoveMemory handles overlapped source and destination.
//
RtlMoveMemory( &(pContextList->pListEntries[uliEntry + 1]),
&(pContextList->pListEntries[uliEntry]),
(pContextList->ulcListEntries - uliEntry)
* sizeof( BDA_CONTEXT_ENTRY)
);
}
#endif // SORTED_CONTEXT_ENTRIES
RtlZeroMemory( *ppvContext, ulcbContext);
pContextList->pListEntries[uliEntry].pvContext = *ppvContext;
pContextList->pListEntries[uliEntry].ulcbContext = ulcbContext;
pContextList->pListEntries[uliEntry].pvReference = pvReference;
pContextList->ulcListEntries++;
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
errExit:
return status;
}
STDMETHODIMP_(NTSTATUS)
BdaDeleteContextEntry(
PBDA_CONTEXT_LIST pContextList,
PVOID pvReference
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uliEntry;
KIRQL oldIrql;
PVOID pvContext;
ULONG ulcbContext;
ASSERT( pContextList);
ASSERT( pvReference);
ASSERT( pContextList->fInitialized);
if (!pContextList->fInitialized)
{
goto errExit;
}
KeAcquireSpinLock( &(pContextList->lock), &oldIrql);
// Find the Context Entry in the list
//
for (uliEntry = 0; uliEntry < pContextList->ulcListEntries; uliEntry++)
{
if (pContextList->pListEntries[uliEntry].pvReference == pvReference)
{
break;
}
}
if (uliEntry >= pContextList->ulcListEntries)
{
status = STATUS_NOT_FOUND;
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
goto errExit;
}
pvContext = pContextList->pListEntries[uliEntry].pvContext;
ulcbContext = pContextList->pListEntries[uliEntry].ulcbContext;
pContextList->pListEntries[uliEntry].pvContext = NULL;
pContextList->pListEntries[uliEntry].pvReference = NULL;
RtlZeroMemory( pvContext, ulcbContext);
ExFreePool( pvContext);
pContextList->ulcListEntries -= 1;
if (uliEntry < pContextList->ulcListEntries)
{
// NOTE! RtlMoveMemory handles overlapped source and destination.
//
RtlMoveMemory( &(pContextList->pListEntries[uliEntry]),
&(pContextList->pListEntries[uliEntry + 1]),
(pContextList->ulcListEntries - uliEntry)
* sizeof( BDA_CONTEXT_ENTRY)
);
}
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
errExit:
return status;
}
STDMETHODIMP_(NTSTATUS)
BdaDeleteContextEntryByValue(
PBDA_CONTEXT_LIST pContextList,
PVOID pvContext
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uliEntry;
KIRQL oldIrql;
ULONG ulcbContext;
ASSERT( pContextList);
ASSERT( pvContext);
ASSERT( pContextList->fInitialized);
if (!pContextList->fInitialized)
{
goto errExit;
}
KeAcquireSpinLock( &(pContextList->lock), &oldIrql);
// Find the Context Entry in the list
//
for (uliEntry = 0; uliEntry < pContextList->ulcListEntries; uliEntry++)
{
if (pContextList->pListEntries[uliEntry].pvContext == pvContext)
{
break;
}
}
if (uliEntry >= pContextList->ulcListEntries)
{
status = STATUS_NOT_FOUND;
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
goto errExit;
}
ulcbContext = pContextList->pListEntries[uliEntry].ulcbContext;
pContextList->pListEntries[uliEntry].pvContext = NULL;
pContextList->pListEntries[uliEntry].pvReference = NULL;
RtlZeroMemory( pvContext, ulcbContext);
ExFreePool( pvContext);
pContextList->ulcListEntries -= 1;
if (uliEntry < pContextList->ulcListEntries)
{
// NOTE! RtlMoveMemory handles overlapped source and destination.
//
RtlMoveMemory( &(pContextList->pListEntries[uliEntry]),
&(pContextList->pListEntries[uliEntry + 1]),
(pContextList->ulcListEntries - uliEntry)
* sizeof( BDA_CONTEXT_ENTRY)
);
}
KeReleaseSpinLock( &(pContextList->lock), oldIrql);
errExit:
return status;
}
/*
** BdaDeleteFilterFactoryContextByValue()
**
** Finds the given BDA Filter Factory Context in the FilterFactory
** context list and removes it.
**
** This function is provided as a callback when the Filter Facotry Context
** is added to the KSFilterFactory's Object Bag. This allows KS to clean
** up the context when the filter factory is unexpectedly closed.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
BDA_CONTEXT_LIST FilterFactoryContextList = { 0, 0, 4, NULL, 0, FALSE};
STDMETHODIMP_(VOID)
BdaDeleteFilterFactoryContextByValue(
PVOID pFilterFactoryCtx
)
{
BdaDeleteContextEntryByValue( &FilterFactoryContextList,
pFilterFactoryCtx
);
}
/*
** BdaCreateFilterFactoryContext()
**
** Finds or creates a BDA Filter Factory Context that corresponds
** to the given KS Filter Factory.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreateFilterFactoryContext(
PKSFILTERFACTORY pKSFilterFactory,
PBDA_FILTER_FACTORY_CONTEXT * ppFilterFactoryCtx
)
{
NTSTATUS status = STATUS_SUCCESS;
status = BdaCreateContextEntry( &FilterFactoryContextList,
pKSFilterFactory,
sizeof( BDA_FILTER_FACTORY_CONTEXT),
(PVOID *) ppFilterFactoryCtx
);
if (!NT_SUCCESS( status))
{
goto errExit;
}
status = KsAddItemToObjectBag( pKSFilterFactory->Bag,
*ppFilterFactoryCtx,
BdaDeleteFilterFactoryContextByValue
);
errExit:
return status;
}
/*
** BdaDestructFilterContext()
**
** Finds the given BDA Filter Context in the Filter
** context list and removes it.
**
** This function is provided as a callback when the Filter Context is
** added to the KSFilter's Object Bag. This allows KS to clean up the
** context when the filter is unexpectedly closed.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(VOID)
BdaDestructFilterContext(
PBDA_FILTER_CONTEXT pFilterCtx
)
{
ULONG uliPath;
ASSERT( pFilterCtx);
if (!pFilterCtx || !pFilterCtx->argpPathInfo)
{
goto exit;
}
// Delete the path information.
//
for ( uliPath = 0; uliPath < pFilterCtx->ulcPathInfo; uliPath++)
{
if (pFilterCtx->argpPathInfo[uliPath])
{
ExFreePool( pFilterCtx->argpPathInfo[uliPath]);
pFilterCtx->argpPathInfo[uliPath] = NULL;
}
}
ExFreePool( pFilterCtx->argpPathInfo);
pFilterCtx->argpPathInfo = NULL;
pFilterCtx->ulcPathInfo = 0;
exit:
return;
}
/*
** BdaDeleteFilterContextByValue()
**
** Finds the given BDA Filter Context in the Filter
** context list and removes it.
**
** This function is provided as a callback when the Filter Context is
** added to the KSFilter's Object Bag. This allows KS to clean up the
** context when the filter is unexpectedly closed.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
BDA_CONTEXT_LIST FilterContextList = { 0, 0, 4, NULL, 0, FALSE};
STDMETHODIMP_(VOID)
BdaDeleteFilterContextByValue(
PVOID pFilterCtx
)
{
BdaDestructFilterContext( (PBDA_FILTER_CONTEXT) pFilterCtx);
BdaDeleteContextEntryByValue( &FilterContextList,
pFilterCtx
);
}
/*
** BdaCreateFilterContext()
**
** Finds or creates a BDA Filter Context that corresponds
** to the given KS Filter.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreateFilterContext(
PKSFILTER pKSFilter,
PBDA_FILTER_CONTEXT * ppFilterCtx
)
{
NTSTATUS status = STATUS_SUCCESS;
status = BdaCreateContextEntry( &FilterContextList,
pKSFilter,
sizeof( BDA_FILTER_CONTEXT),
(PVOID *) ppFilterCtx
);
if (!NT_SUCCESS( status))
{
goto errExit;
}
status = KsAddItemToObjectBag( pKSFilter->Bag,
*ppFilterCtx,
BdaDeleteFilterContextByValue
);
(*ppFilterCtx)->pKSFilter = pKSFilter;
errExit:
return status;
}
/*
** BdaGetFilterContext()
**
** Finds a BDA Filter Context that corresponds
** to the given KS Filter Instance.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaGetFilterContext(
PKSFILTER pKSFilter,
PBDA_FILTER_CONTEXT * ppFilterCtx
)
{
NTSTATUS status = STATUS_SUCCESS;
status = BdaFindContextEntry( &FilterContextList,
pKSFilter,
(PVOID *) ppFilterCtx
);
return status;
}
/*
** BdaDeleteFilterContext()
**
** Deletes a BDA Filter Context.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaDeleteFilterContext(
PVOID pvReference
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uliPath;
PBDA_FILTER_CONTEXT pFilterCtx;
status = BdaGetFilterContext( (PKSFILTER) pvReference, &pFilterCtx);
if (status == STATUS_SUCCESS)
{
BdaDestructFilterContext( pFilterCtx);
}
status = BdaDeleteContextEntry( &FilterContextList,
pvReference
);
return status;
}
/*
** BdaGetControllingPinType()
**
**
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaGetControllingPinType(
ULONG ulNodeType,
ULONG ulInputPinType,
ULONG ulOutputPinType,
PBDA_FILTER_CONTEXT pFilterCtx,
PULONG pulControllingPinType
)
{
NTSTATUS status = STATUS_NOT_FOUND;
ULONG ulControllingPinType;
ULONG uliPath;
const KSFILTER_DESCRIPTOR * pKSFilterDescriptor;
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pBdaFilterTemplate);
ASSERT( pFilterCtx->pBdaFilterTemplate->pFilterDescriptor);
if ( !pFilterCtx
|| !pFilterCtx->pBdaFilterTemplate
|| !pFilterCtx->pBdaFilterTemplate->pFilterDescriptor
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
if ( !pFilterCtx->ulcPathInfo
|| !pFilterCtx->argpPathInfo
|| !pFilterCtx->pBdaFilterTemplate->pFilterDescriptor->Connections
)
{
goto errExit;
}
pKSFilterDescriptor = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
for (uliPath = 0; uliPath < pFilterCtx->ulcPathInfo; uliPath++)
{
PBDA_PATH_INFO pPathInfo;
ULONG uliPathEntry;
pPathInfo = pFilterCtx->argpPathInfo[uliPath];
if ( !pPathInfo
|| (pPathInfo->ulInputPin != ulInputPinType)
|| (pPathInfo->ulOutputPin != ulOutputPinType)
)
{
// This is not the path for this pin pair.
//
continue;
}
// Search the Path for the given node type.
//
ulControllingPinType = ulInputPinType;
for ( uliPathEntry = 0
; uliPathEntry < pPathInfo->ulcPathEntries
; uliPathEntry++
)
{
ULONG uliConnection;
// If we encounter topology joint then switch the controlling
// pin to be the output pin.
//
if (pPathInfo->rgPathEntries[uliPathEntry].fJoint)
{
ulControllingPinType = ulOutputPinType;
}
uliConnection = pPathInfo->rgPathEntries[uliPathEntry].uliConnection;
if (pKSFilterDescriptor->Connections[uliConnection].ToNode == ulNodeType)
{
// We found the controlling pin type for the node type.
// Indicate success and set the output parameter.
//
status = STATUS_SUCCESS;
*pulControllingPinType = ulControllingPinType;
break;
}
}
if (uliPathEntry < pPathInfo->ulcPathEntries)
{
// We found the controlling pin type for the node type.
//
break;
}
}
errExit:
return status;
}
/*
** BdaFilterInitTopologyData()
**
** Initializes the common BDA filter context's topology info.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaFilterInitTopologyData(
PBDA_FILTER_CONTEXT pFilterCtx
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG ulcTemplateNodes;
PBDA_NODE_CONTROL_INFO pNodeControlInfo = NULL;
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pKSFilter);
ASSERT( pFilterCtx->pBdaFilterTemplate);
ASSERT( pFilterCtx->pBdaFilterTemplate->pFilterDescriptor);
if ( !pFilterCtx
|| !pFilterCtx->pBdaFilterTemplate
|| !pFilterCtx->pBdaFilterTemplate->pFilterDescriptor
|| !pFilterCtx->pKSFilter
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
#ifdef REMOVE
ulcTemplateNodes
= pFilterCtx->pBdaFilterTemplate->pFilterDescriptor->NodeDescriptorsCount;
if (ulcTemplateNodes)
{
PKSNODE_DESCRIPTOR pCurNode;
ULONG uliNode;
ASSERT( pFilterCtx->pBdaFilterTemplate->pFilterDescriptor->NodeDescriptors);
ASSERT( pFilterCtx->pBdaFilterTemplate->pFilterDescriptor->NodeDescriptorSize);
// Allocate an array of node control info structures
//
pNodeControlInfo = ExAllocatePool(
NonPagedPool,
ulcTemplateNodes * sizeof( BDA_NODE_CONTROL_INFO)
);
if (!pNodeControlInfo)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
RtlZeroMemory( pNodeControlInfo,
ulcTemplateNodes * sizeof( BDA_NODE_CONTROL_INFO)
);
// Add the allocation to the KS Filter's object bag so that it
// will be freed on filter destruction.
//
status = KsAddItemToObjectBag( pFilterCtx->pKSFilter->Bag,
pNodeControlInfo,
NULL
);
// Point the BDA Filter Context at the node control info.
//
pFilterCtx->argNodeControlInfo = pNodeControlInfo;
// Determine the contolling pin type for each node type and fill
// it in to the node control array
//
for ( uliNode = 0
; uliNode < ulcTemplateNodes
; uliNode++, pNodeControlInfo++
)
{
// BdaSup.sys always uses the index of the node descriptor as
// the node type.
//
pNodeControlInfo->ulNodeType = uliNode;
// Determine which template pin type controls this node type.
//
status = BdaGetControllingPinType(
uliNode,
pFilterCtx->pBdaFilterTemplate,
&pNodeControlInfo->ulControllingPinType
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Add the node control info as we determine it.
//
pFilterCtx->ulcNodeControlInfo++;
}
}
#endif // REMOVE
errExit:
return status;
}
/*
** BdaAddPinFactoryContext()
**
** Adds pin factory information to the array of pin factory context
** structures for this filter instance. It will enlarge the array
** if necessary.
** NOTE! Since the array is an array of structure NOT pointers to
** structures, AND since the array can be moved, one should NOT keep
** pointers to the pin factory context entries.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreatePinFactoryContext(
PKSFILTER pKSFilter,
PBDA_FILTER_CONTEXT pFilterCtx,
ULONG uliPinId,
ULONG ulPinType
)
{
NTSTATUS status = STATUS_SUCCESS;
// Add the Pin Factory info to the filter context.
//
if (uliPinId >= pFilterCtx->ulcPinFactoriesMax)
{
// If there isn't enough room then add more.
//
PBDA_PIN_FACTORY_CONTEXT argNewPinCtx = NULL;
PVOID pvTemp;
ULONG ulcPinFactoriesMax;
ulcPinFactoriesMax = uliPinId + BDA_PIN_STORAGE_INCREMENT;
argNewPinCtx = ExAllocatePool(
NonPagedPool,
ulcPinFactoriesMax * sizeof(BDA_PIN_FACTORY_CONTEXT)
);
if (!argNewPinCtx)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
if (pFilterCtx->argPinFactoryCtx)
{
RtlMoveMemory( argNewPinCtx,
pFilterCtx->argPinFactoryCtx,
pFilterCtx->ulcPinFactoriesMax * sizeof(BDA_PIN_FACTORY_CONTEXT)
);
}
KsAddItemToObjectBag( pKSFilter->Bag,
argNewPinCtx,
NULL
);
pvTemp = pFilterCtx->argPinFactoryCtx;
pFilterCtx->argPinFactoryCtx = argNewPinCtx;
pFilterCtx->ulcPinFactoriesMax = ulcPinFactoriesMax;
KsRemoveItemFromObjectBag( pKSFilter->Bag,
pvTemp,
TRUE
);
}
// Fill in the pin factory context information.
//
pFilterCtx->argPinFactoryCtx[uliPinId].ulPinType = ulPinType;
pFilterCtx->argPinFactoryCtx[uliPinId].ulPinFactoryId = uliPinId;
if (uliPinId >= pFilterCtx->ulcPinFactories)
{
pFilterCtx->ulcPinFactories = uliPinId + 1;
}
errExit:
return status;
}
/*
** BdaInitFilter()
**
** Creates a BDA filter context for use by BdaCreatePinFactory etc.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaInitFilter(
PKSFILTER pKSFilter,
const BDA_FILTER_TEMPLATE * pBdaFilterTemplate
)
{
NTSTATUS status = STATUS_SUCCESS;
PBDA_FILTER_FACTORY_CONTEXT pFilterFactoryCtx = NULL;
PBDA_FILTER_CONTEXT pFilterCtx = NULL;
PKSFILTERFACTORY pKSFilterFactory = NULL;
ULONG ulcPinFactoriesMax;
const KSFILTER_DESCRIPTOR * pInitialFilterDescriptor = NULL;
status = BdaFindContextEntry( &FilterContextList,
pKSFilter,
(PVOID *) &pFilterCtx
);
if (NT_SUCCESS( status))
{
status = STATUS_SHARING_VIOLATION;
goto errExit;
}
if (status != STATUS_NOT_FOUND)
{
goto errExit;
}
// Get the filter factory context so that we can determine
// the initial pin list.
//
pKSFilterFactory = KsFilterGetParentFilterFactory( pKSFilter);
ASSERT( pKSFilterFactory);
if (!pKSFilterFactory)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
status = BdaFindContextEntry( &FilterFactoryContextList,
pKSFilterFactory,
(PVOID *) &pFilterFactoryCtx
);
if (!NT_SUCCESS( status))
{
goto errExit;
}
if (!pFilterFactoryCtx)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
pInitialFilterDescriptor = pFilterFactoryCtx->pInitialFilterDescriptor;
// Create a BDA filter context and put it in the list so we can
// find it when BDA calls are made relative to the filter.
//
status = BdaCreateFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Point the BDA filter context at the template topology for the
// filter.
//
if (pBdaFilterTemplate)
{
pFilterCtx->pBdaFilterTemplate = pBdaFilterTemplate;
}
else
{
pFilterCtx->pBdaFilterTemplate
= pFilterFactoryCtx->pBdaFilterTemplate;
}
// Expand the template topology information into a list
// of paths keyed by the input-output pin type pair.
//
status = BdaCreateTemplatePaths( pFilterCtx->pBdaFilterTemplate,
&pFilterCtx->ulcPathInfo,
&pFilterCtx->argpPathInfo
);
if (!NT_SUCCESS( status))
{
goto errExit;
}
//$REVIEW - Should we allow filters with no input-output paths?
//
ASSERT( pFilterCtx->ulcPathInfo);
ASSERT( pFilterCtx->argpPathInfo);
// Allocate space for the Pin Factory context information
//
ulcPinFactoriesMax = pBdaFilterTemplate->pFilterDescriptor->PinDescriptorsCount;
ulcPinFactoriesMax += BDA_PIN_STORAGE_INCREMENT;
pFilterCtx->argPinFactoryCtx
= ExAllocatePool( NonPagedPool,
ulcPinFactoriesMax * sizeof( BDA_PIN_FACTORY_CONTEXT)
);
if (!pFilterCtx->argPinFactoryCtx)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
pFilterCtx->ulcPinFactories = 0;
pFilterCtx->ulcPinFactoriesMax = ulcPinFactoriesMax;
// Loop through each initial pin descriptor and fill in the pin
// context info.
//
if (pInitialFilterDescriptor && pInitialFilterDescriptor->PinDescriptors)
{
ULONG ulcbPinDescriptor;
ULONG uliPinType;
if (pInitialFilterDescriptor->PinDescriptorsCount > pFilterCtx->ulcPinFactoriesMax)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
ulcbPinDescriptor = pInitialFilterDescriptor->PinDescriptorSize;
for ( uliPinType = 0
; uliPinType < pInitialFilterDescriptor->PinDescriptorsCount
; uliPinType++
)
{
ULONG ulPinId;
// It is a BDA requirement that the index of all pins listed in the initial
// filter descriptor correspond to the index of its pin type
// in the BDA Template Descriptor.
//
status = BdaCreatePin( pKSFilter,
uliPinType,
&ulPinId
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
//
// We do not "CreateTopology" on the initial pins. The
// initial pins are usually only input pins. The Network
// Provider will create output pins and "CreateTopology".
//
}
}
errExit:
return status;
}
/*
** BdaUninitFilter()
**
** Deletes the BDA filter context for use by BdaCreatePinFactory etc.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaUninitFilter(
PKSFILTER pKSFilter
)
{
NTSTATUS status = STATUS_SUCCESS;
#ifdef NO_KS_OBJECT_BAG
status = BdaDeleteContextEntry( &FilterContextList,
pKSFilter
);
if (!NT_SUCCESS( status))
{
goto errExit;
}
errExit:
#endif // def NO_KS_OBJECT_BAG
return status;
}
/*
** BdaCreateFilterFactoryEx()
**
** Initializes the common BDA filter context.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreateFilterFactoryEx(
PKSDEVICE pKSDevice,
const KSFILTER_DESCRIPTOR * pInitialFilterDescriptor,
const BDA_FILTER_TEMPLATE * pBdaFilterTemplate,
PKSFILTERFACTORY * ppKSFilterFactory
)
{
NTSTATUS status = STATUS_SUCCESS;
PBDA_FILTER_FACTORY_CONTEXT pFilterFactoryCtx = NULL;
PKSFILTERFACTORY pKSFilterFactory = NULL;
PKSFILTER_DESCRIPTOR pFilterDescriptor = NULL;
PKSAUTOMATION_TABLE pNewAutomationTable = NULL;
ASSERT( pKSDevice);
if (!pKSDevice)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( pInitialFilterDescriptor);
if (!pInitialFilterDescriptor)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( pBdaFilterTemplate);
if (!pBdaFilterTemplate)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Create a copy of the filter factory descriptor information and
// remove any pins and connections. These will be added when
// the filter is initialized by BDAInitFilter.
//
pFilterDescriptor = ExAllocatePool( NonPagedPool,
sizeof( KSFILTER_DESCRIPTOR)
);
if (!pFilterDescriptor)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
*pFilterDescriptor = *pInitialFilterDescriptor;
pFilterDescriptor->PinDescriptorsCount = 0;
pFilterDescriptor->PinDescriptors = NULL;
pFilterDescriptor->NodeDescriptorsCount = 0;
pFilterDescriptor->NodeDescriptors = NULL;
pFilterDescriptor->ConnectionsCount = 0;
pFilterDescriptor->Connections = NULL;
status = KsMergeAutomationTables(
&pNewAutomationTable,
(PKSAUTOMATION_TABLE) (pFilterDescriptor->AutomationTable),
(PKSAUTOMATION_TABLE) &BdaDefaultFilterAutomation,
NULL
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
if (!pNewAutomationTable)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
pFilterDescriptor->AutomationTable = pNewAutomationTable;
//$BUG - Check Filter Factory Dispatch for Filter Close. If none
//$BUG - we must add BdaDeleteFilterFactory to clean up.
// Create the KSFilterFactory
//
status = KsCreateFilterFactory(
pKSDevice->FunctionalDeviceObject,
pFilterDescriptor,
NULL, // RefString
NULL, // SecurityDescriptor
0, // CreateItemFlags
NULL, // SleepCallback
NULL, // WakeCallback
&pKSFilterFactory
);
if ((status != STATUS_SUCCESS) || !pKSFilterFactory)
{
goto errExit;
}
// Add our copy of the Filter Factory's new automation table to the
// KSFilterFactory's object bag. This insures the memory will
// be freed when the filter factory is destroyed.
//
if ( pNewAutomationTable
&& (pNewAutomationTable != &BdaDefaultFilterAutomation)
)
{
KsAddItemToObjectBag( pKSFilterFactory->Bag,
pNewAutomationTable,
NULL
);
}
pNewAutomationTable = NULL;
// Add our copy of the Filter Factory's descriptor to the
// KSFilterFactory's object bag. This insures the memory will
// be freed when the filter factory is destroyed.
//
KsAddItemToObjectBag( pKSFilterFactory->Bag,
pFilterDescriptor,
NULL
);
pFilterDescriptor = NULL;
// Merge our default filter automation table onto the filter
// factory descriptor
//
status = KsEdit( pKSFilterFactory,
&(pKSFilterFactory->FilterDescriptor->AutomationTable),
'SadB'
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Create a filter factory context for BdaSup to use.
//
status = BdaCreateFilterFactoryContext( pKSFilterFactory,
&pFilterFactoryCtx
);
if ((status != STATUS_SUCCESS) || !pFilterFactoryCtx)
{
KsDeleteFilterFactory( pKSFilterFactory);
goto errExit;
}
// Allow for the filter factory to use a default filter template
// topology when it creates a filter
//
//$REVIEW
pFilterFactoryCtx->pInitialFilterDescriptor = pInitialFilterDescriptor;
pFilterFactoryCtx->pBdaFilterTemplate = pBdaFilterTemplate;
pFilterFactoryCtx->pKSFilterFactory = pKSFilterFactory;
if (ppKSFilterFactory)
{
*ppKSFilterFactory = pKSFilterFactory;
}
errExit:
if (pFilterDescriptor)
{
ExFreePool( pFilterDescriptor);
pFilterDescriptor = NULL;
}
if ( pNewAutomationTable
&& (pNewAutomationTable != &BdaDefaultFilterAutomation)
)
{
ExFreePool( pNewAutomationTable);
pNewAutomationTable = NULL;
}
return status;
}
/*
** BdaCreateFilterFactory()
**
** Initializes the common BDA filter context.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreateFilterFactory(
PKSDEVICE pKSDevice,
const KSFILTER_DESCRIPTOR * pInitialFilterDescriptor,
const BDA_FILTER_TEMPLATE * pBdaFilterTemplate
)
{
NTSTATUS Status = STATUS_SUCCESS;
Status = BdaCreateFilterFactoryEx( pKSDevice,
pInitialFilterDescriptor,
pBdaFilterTemplate,
NULL
);
return Status;
}
/*
** BdaFilterFactoryUpdateCacheData()
**
** Updates the pin data cache for the given filter factory.
** The function will update the cached information for all pin factories
** exposed by the given filter factory.
**
** If the option filter descriptor is given, the function will update
** the pin data cache for all pins listed in the given filter descriptor
** instead of those in the filter factory.
**
** Drivers will call this to update the pin data cache for all
** pins that may be exposed by the filter factory. The driver will
** provide a filter descriptor listing pins that are not initially exposed
** by the filter factory (this is usually the same as the template filter
** descriptor).
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaFilterFactoryUpdateCacheData(
IN PKSFILTERFACTORY pFilterFactory,
IN const KSFILTER_DESCRIPTOR * pFilterDescriptor OPTIONAL
)
{
NTSTATUS Status = STATUS_SUCCESS;
Status = KsFilterFactoryUpdateCacheData( pFilterFactory,
pFilterDescriptor
);
return Status;
}
/*
** BdaSyncTopology()
**
** This routine updates the existing topology to complete all
** Pending topology changes.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaSyncTopology(
PKSFILTER pKSFilter
)
{
NTSTATUS Status = STATUS_SUCCESS;
//$BUG Implement topology sync.
return STATUS_NOT_IMPLEMENTED;
}
// -------------------------------------------------------------------
// BDA Filter Global Property Set functions
// -------------------------------------------------------------------
/*
** BdaPropertyNodeTypes ()
**
** Returns a list of ULONGS.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyNodeTypes(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT ULONG * pulProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
const KSFILTER_DESCRIPTOR * pTemplateDesc;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSFilter = KsGetFilterFromIrp( Irp);
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pBdaFilterTemplate);
pTemplateDesc = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
ASSERT( pTemplateDesc);
ASSERT( pTemplateDesc->NodeDescriptorSize == sizeof( KSNODE_DESCRIPTOR));
if (pulProperty)
{
ULONG uliNodeDesc;
for ( uliNodeDesc = 0
; uliNodeDesc < pTemplateDesc->NodeDescriptorsCount
; uliNodeDesc++, pulProperty++
)
{
// For this implementation, the NodeType is just the
// index into the NodeDescriptor table.
//
*pulProperty = uliNodeDesc;
}
Irp->IoStatus.Information = uliNodeDesc * sizeof( ULONG);
}
else
{
status = STATUS_MORE_ENTRIES;
// If there is no place to put the property then just
// return the data size.
//
Irp->IoStatus.Information
= pTemplateDesc->NodeDescriptorsCount * sizeof( ULONG);
}
errExit:
return status;
}
/*
** BdaPropertyNodeDescriptors ()
**
** Returns a list of GUIDS. The index of the GUID in the list
** corresponds to the Node type.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyNodeDescriptors(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT BDANODE_DESCRIPTOR * pNodeDescripterProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
const KSFILTER_DESCRIPTOR * pTemplateDesc;
ULONG ulcPropertyEntries;
ULONG ulcNodes;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Determine how many entries the input buffer can hold.
//
ulcPropertyEntries = OutputBufferLenFromIrp( Irp);
ulcPropertyEntries = ulcPropertyEntries / sizeof( BDANODE_DESCRIPTOR);
pKSFilter = KsGetFilterFromIrp( Irp);
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
if ( !pFilterCtx
|| !pFilterCtx->pBdaFilterTemplate
)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
pTemplateDesc = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
ASSERT( pTemplateDesc);
if (!pTemplateDesc)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
ASSERT( pTemplateDesc->NodeDescriptorSize == sizeof( KSNODE_DESCRIPTOR));
// Handle the case of a NULL NodeDesriptor array as 0 nodes.
//
if (!pTemplateDesc->NodeDescriptors)
{
ulcNodes = 0;
}
else
{
ulcNodes = pTemplateDesc->NodeDescriptorsCount;
}
if (!pNodeDescripterProperty || (ulcPropertyEntries < ulcNodes))
{
status = STATUS_MORE_ENTRIES;
// If there is no place to put the property then just
// return the data size.
//
}
else
{
const KSNODE_DESCRIPTOR * pNodeDesc;
ULONG uliNodeDesc;
pNodeDesc = pTemplateDesc->NodeDescriptors;
if (pNodeDesc)
{
for ( uliNodeDesc = 0
; uliNodeDesc < ulcNodes
; uliNodeDesc++, pNodeDescripterProperty++
)
{
// For this implementation, the NodeType is just the
// index into the NodeDescriptor table.
//
pNodeDescripterProperty->ulBdaNodeType = uliNodeDesc;
// Fill in the function GUID for the node type.
//
if (pNodeDesc->Type)
{
pNodeDescripterProperty->guidFunction = *pNodeDesc->Type;
}
else
{
pNodeDescripterProperty->guidFunction = GUID_NULL;
}
// Fill in the GUID that represents a displayable name
// for the node type.
if (pNodeDesc->Name)
{
pNodeDescripterProperty->guidName = *pNodeDesc->Name;
}
else
{
pNodeDescripterProperty->guidName = GUID_NULL;
}
// Point at the next node descriptor
//
pNodeDesc = (const KSNODE_DESCRIPTOR *)
((BYTE *) pNodeDesc + pTemplateDesc->NodeDescriptorSize);
}
}
}
Irp->IoStatus.Information = ulcNodes * sizeof( BDANODE_DESCRIPTOR);
errExit:
return status;
}
/*
** BdaPropertyNodeProperties ()
**
** Returns a list of GUIDS. The guid for each property set
** supported by the specified node is included in the list.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyNodeProperties(
IN PIRP Irp,
IN PKSP_NODE Property,
OUT GUID * pguidProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
const KSFILTER_DESCRIPTOR * pTemplateDesc;
const KSNODE_DESCRIPTOR * pNodeDesc;
const KSAUTOMATION_TABLE* pAutomationTable;
ULONG uliNodeDesc;
ULONG ulcInterfaces;
ULONG ulcPropertyEntries;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Determine how many entries the input buffer can hold.
//
ulcPropertyEntries = OutputBufferLenFromIrp( Irp);
ulcPropertyEntries = ulcPropertyEntries / sizeof( GUID);
pKSFilter = KsGetFilterFromIrp( Irp);
if (!pKSFilter)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pBdaFilterTemplate);
if (!pFilterCtx->pBdaFilterTemplate)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
pTemplateDesc = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
ASSERT( pTemplateDesc);
if (!pTemplateDesc)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
ASSERT( pTemplateDesc->NodeDescriptorSize == sizeof( KSNODE_DESCRIPTOR));
uliNodeDesc = Property->NodeId;
if (uliNodeDesc >= pTemplateDesc->NodeDescriptorsCount)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pNodeDesc = pTemplateDesc->NodeDescriptors;
ASSERT( pNodeDesc);
if (!pNodeDesc)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
ASSERT( pTemplateDesc->NodeDescriptorSize);
pNodeDesc = (const KSNODE_DESCRIPTOR *)
((BYTE *) pNodeDesc + uliNodeDesc * pTemplateDesc->NodeDescriptorSize);
if ( !pNodeDesc->AutomationTable
|| !pNodeDesc->AutomationTable->PropertySets
)
{
ulcInterfaces = 0;
}
else
{
ulcInterfaces = pNodeDesc->AutomationTable->PropertySetsCount;
}
if (!pguidProperty || (ulcPropertyEntries < ulcInterfaces))
{
status = STATUS_MORE_ENTRIES;
// If there is no place to put the property then just
// return the data size.
//
}
else
{
ULONG uliSet;
const KSPROPERTY_SET * pPropertySet;
GUID * pguidOut;
pguidOut = pguidProperty;
pPropertySet = pNodeDesc->AutomationTable->PropertySets;
if (pPropertySet)
{
for ( uliSet = 0
; uliSet < ulcInterfaces
; uliSet++
)
{
RtlMoveMemory( pguidOut,
pPropertySet->Set,
sizeof( GUID)
);
pguidOut += 1;
pPropertySet += 1;
}
}
}
Irp->IoStatus.Information = ulcInterfaces * sizeof( GUID);
errExit:
return status;
}
/*
** BdaPropertyNodeMethods ()
**
** Returns a list of GUIDS. The guid for each property set
** supported by the specified node is included in the list.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyNodeMethods(
IN PIRP Irp,
IN PKSP_NODE Property,
OUT GUID * pguidProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
const KSFILTER_DESCRIPTOR * pTemplateDesc;
const KSNODE_DESCRIPTOR * pNodeDesc;
const KSAUTOMATION_TABLE* pAutomationTable;
ULONG uliNodeDesc;
ULONG ulcInterfaces;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSFilter = KsGetFilterFromIrp( Irp);
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pBdaFilterTemplate);
pTemplateDesc = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
ASSERT( pTemplateDesc);
ASSERT( pTemplateDesc->NodeDescriptorSize == sizeof( KSNODE_DESCRIPTOR));
uliNodeDesc = Property->NodeId;
if (uliNodeDesc >= pTemplateDesc->NodeDescriptorsCount)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pNodeDesc = pTemplateDesc->NodeDescriptors;
ASSERT( pTemplateDesc->NodeDescriptorSize);
pNodeDesc = (const KSNODE_DESCRIPTOR *)
((BYTE *) pNodeDesc + uliNodeDesc * pTemplateDesc->NodeDescriptorSize);
ulcInterfaces = pNodeDesc->AutomationTable->PropertySetsCount;
if (pguidProperty)
{
ULONG uliSet;
const KSMETHOD_SET * pMethodSet;
GUID * pguidOut;
pguidOut = pguidProperty;
ulcInterfaces = 0;
pMethodSet = pNodeDesc->AutomationTable->MethodSets;
if (pMethodSet)
{
for ( uliSet = 0
; uliSet < pNodeDesc->AutomationTable->MethodSetsCount
; uliSet++
)
{
RtlMoveMemory( pguidOut,
pMethodSet->Set,
sizeof( GUID)
);
pguidOut += 1;
pMethodSet += 1;
ulcInterfaces += 1;
}
}
Irp->IoStatus.Information = ulcInterfaces * sizeof( GUID);
}
else
{
status = STATUS_MORE_ENTRIES;
// If there is no place to put the property then just
// return the data size.
//
Irp->IoStatus.Information = ulcInterfaces * sizeof( GUID);
}
errExit:
return status;
}
/*
** BdaPropertyNodeEvents ()
**
** Returns a list of GUIDS. The guid for each event set
** supported by the specified node is included in the list.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyNodeEvents(
IN PIRP Irp,
IN PKSP_NODE Property,
OUT GUID * pguidProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
const KSFILTER_DESCRIPTOR * pTemplateDesc;
const KSNODE_DESCRIPTOR * pNodeDesc;
const KSAUTOMATION_TABLE* pAutomationTable;
ULONG uliNodeDesc;
ULONG ulcInterfaces;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSFilter = KsGetFilterFromIrp( Irp);
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pBdaFilterTemplate);
pTemplateDesc = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
ASSERT( pTemplateDesc);
ASSERT( pTemplateDesc->NodeDescriptorSize == sizeof( KSNODE_DESCRIPTOR));
uliNodeDesc = Property->NodeId;
if (uliNodeDesc >= pTemplateDesc->NodeDescriptorsCount)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pNodeDesc = pTemplateDesc->NodeDescriptors;
ASSERT( pTemplateDesc->NodeDescriptorSize);
pNodeDesc = (const KSNODE_DESCRIPTOR *)
((BYTE *) pNodeDesc + uliNodeDesc * pTemplateDesc->NodeDescriptorSize);
ulcInterfaces = pNodeDesc->AutomationTable->PropertySetsCount;
if (pguidProperty)
{
ULONG uliSet;
const KSEVENT_SET * pEventSet;
GUID * pguidOut;
pguidOut = pguidProperty;
ulcInterfaces = 0;
pEventSet = pNodeDesc->AutomationTable->EventSets;
if (pEventSet)
{
for ( uliSet = 0
; uliSet < pNodeDesc->AutomationTable->EventSetsCount
; uliSet++
)
{
RtlMoveMemory( pguidOut,
pEventSet->Set,
sizeof( GUID)
);
pguidOut += 1;
pEventSet += 1;
ulcInterfaces += 1;
}
}
Irp->IoStatus.Information = ulcInterfaces * sizeof( GUID);
}
else
{
status = STATUS_MORE_ENTRIES;
// If there is no place to put the property then just
// return the data size.
//
Irp->IoStatus.Information = ulcInterfaces * sizeof( GUID);
}
errExit:
return status;
}
/*
** BdaPropertyPinTypes ()
**
** Returns a list of GUIDS. The index of the GUID in the list
** corresponds to the Node type.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyPinTypes(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT ULONG * pulProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
const KSFILTER_DESCRIPTOR * pTemplateDesc;
const KSPIN_DESCRIPTOR_EX * pPinDesc;
ULONG uliPinDesc;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSFilter = KsGetFilterFromIrp( Irp);
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pBdaFilterTemplate);
pTemplateDesc = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
ASSERT( pTemplateDesc);
ASSERT( pTemplateDesc->PinDescriptorSize == sizeof( KSPIN_DESCRIPTOR_EX));
if (pulProperty)
{
for ( uliPinDesc = 0
; uliPinDesc < pTemplateDesc->PinDescriptorsCount
; uliPinDesc++, pulProperty++
)
{
// For this implementation, the PinType is just the
// index into the PinDescriptor table.
//
*pulProperty = uliPinDesc;
}
Irp->IoStatus.Information = uliPinDesc * sizeof( ULONG);
}
else
{
status = STATUS_BUFFER_OVERFLOW;
// If there is no place to put the property then just
// return the data size.
//
Irp->IoStatus.Information
= pTemplateDesc->PinDescriptorsCount * sizeof( ULONG);
}
errExit:
return status;
}
/*
** BdaPropertyTemplateConnections ()
**
** Returns a list of KSTOPOLOGY_CONNECTIONS. The list of connections
** describs how pin types and node types are connected in the template
** topology
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyTemplateConnections(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT PKSTOPOLOGY_CONNECTION pConnectionProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
const KSFILTER_DESCRIPTOR * pTemplateDesc;
const KSTOPOLOGY_CONNECTION * pConnection;
ULONG uliConnection;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSFilter = KsGetFilterFromIrp( Irp);
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
ASSERT( pFilterCtx->pBdaFilterTemplate);
pTemplateDesc = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
ASSERT( pTemplateDesc);
if (pConnectionProperty)
{
for ( uliConnection = 0, pConnection = pTemplateDesc->Connections
; uliConnection < pTemplateDesc->ConnectionsCount
; uliConnection++, pConnection++, pConnectionProperty++
)
{
*pConnectionProperty = *pConnection;
}
Irp->IoStatus.Information
= uliConnection * sizeof( KSTOPOLOGY_CONNECTION);
}
else
{
status = STATUS_BUFFER_OVERFLOW;
// If there is no place to put the property then just
// return the data size.
//
Irp->IoStatus.Information
= pTemplateDesc->ConnectionsCount * sizeof( KSTOPOLOGY_CONNECTION);
}
errExit:
return status;
}
/*
** BdaPinTypeFromPinId()
**
** Gets the ID of the pin on which to submit node properties, methods
** and events.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPinTypeFromPinId(
PBDA_FILTER_CONTEXT pFilterCtx,
ULONG ulPinId,
PULONG pulPinType
)
{
NTSTATUS status = STATUS_SUCCESS;
if ( !pFilterCtx
|| !pFilterCtx->argPinFactoryCtx
|| (ulPinId >= pFilterCtx->ulcPinFactories)
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
if (pFilterCtx->argPinFactoryCtx[ulPinId].ulPinFactoryId != ulPinId)
{
status = STATUS_NOT_FOUND;
goto errExit;
}
*pulPinType = pFilterCtx->argPinFactoryCtx[ulPinId].ulPinType;
errExit:
return status;
}
/*
** BdaGetControllingPinId ()
**
** Gets the ID of the pin on which to submit node properties, methods
** and events.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaGetControllingPinId(
PBDA_FILTER_CONTEXT pFilterCtx,
ULONG ulInputPinId,
ULONG ulOutputPinId,
ULONG ulNodeType,
PULONG pulControllingPinId
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG ulInputPinType = 0;
ULONG ulOutputPinType = -1;
ULONG ulControllingPinType = -1;
// Get the input pin type.
//
status = BdaPinTypeFromPinId( pFilterCtx,
ulInputPinId,
&ulInputPinType
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Get the output pin type.
//
status = BdaPinTypeFromPinId( pFilterCtx,
ulOutputPinId,
&ulOutputPinType
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Determine the cotnrolling pin type.
//
status = BdaGetControllingPinType( ulNodeType,
ulInputPinType,
ulOutputPinType,
pFilterCtx,
&ulControllingPinType
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Map the controlling pin type to the controlling pin ID.
//
if (ulControllingPinType == ulInputPinType)
{
*pulControllingPinId = ulInputPinId;
}
else if (ulControllingPinType == ulOutputPinType)
{
*pulControllingPinId = ulOutputPinId;
}
else
{
status = STATUS_NOT_FOUND;
}
errExit:
return status;
}
/*
** BdaPropertyGetControllingPinId ()
**
** Gets the ID of the pin on which to submit node properties, methods
** and events.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyGetControllingPinId(
IN PIRP Irp,
IN PKSP_BDA_NODE_PIN Property,
OUT PULONG pulControllingPinId
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSFilter = KsGetFilterFromIrp( Irp);
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
if (!pFilterCtx)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
if (pulControllingPinId)
{
status = BdaGetControllingPinId(
pFilterCtx,
Property->ulInputPinId,
Property->ulOutputPinId,
Property->ulNodeType,
pulControllingPinId
);
if (status == STATUS_NOT_FOUND)
{
// See if the pins were part of a static filter configuration.
//
//$BUG - Pins that are configured without template type information
// should always be controlled by the output pin.
//
if (Property->ulNodeType == 0)
{
*pulControllingPinId = Property->ulInputPinId;
}
else
{
*pulControllingPinId = Property->ulOutputPinId;
}
status = STATUS_SUCCESS;
}
Irp->IoStatus.Information = sizeof( ULONG);
}
else
{
status = STATUS_BUFFER_OVERFLOW;
// If there is no place to put the property then just
// return the data size.
//
Irp->IoStatus.Information = sizeof( ULONG);
}
errExit:
return status;
}
/*
** BdaStartChanges ()
**
** Puts the filter into change state. All changes to BDA topology
** and properties changed after this will be in effect only after
** CommitChanges.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaStartChanges(
IN PIRP pIrp
)
{
ASSERT( pIrp);
if (!pIrp)
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
/*
** BdaCheckChanges ()
**
** Checks the changes to BDA interfaces that have occured since the
** last StartChanges. Returns the result that would have occurred if
** CommitChanges had been called.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCheckChanges(
IN PIRP pIrp
)
{
ASSERT( pIrp);
if (!pIrp)
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
/*
** BdaCommitChanges ()
**
** Checks the changes to BDA interfaces that have occured since the
** last StartChanges.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCommitChanges(
IN PIRP pIrp
)
{
ASSERT( pIrp);
if (!pIrp)
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
/*
** BdaGetChangeState ()
**
** Checks the changes to BDA interfaces that have occured since the
** last StartChanges.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaGetChangeState(
IN PIRP pIrp,
PBDA_CHANGE_STATE pChangeState
)
{
ASSERT( pIrp);
if (!pIrp)
{
return STATUS_INVALID_PARAMETER;
}
ASSERT( pChangeState);
if (!pChangeState)
{
return STATUS_INVALID_PARAMETER;
}
*pChangeState = BDA_CHANGES_COMPLETE;
return STATUS_SUCCESS;
}
/*
** BdaMethodCreatePin ()
**
** Creates a new pin factory for the given pin type.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaMethodCreatePin(
IN PIRP pIrp,
IN PKSMETHOD pKSMethod,
OUT PULONG pulPinFactoryID
)
{
NTSTATUS status = STATUS_SUCCESS;
ASSERT(pIrp);
if (pIrp)
{
PKSFILTER pKSFilter;
PKSM_BDA_PIN pKSPinMethod;
ULONG ulPinId;
pKSPinMethod = (PKSM_BDA_PIN) pKSMethod;
pKSFilter = KsGetFilterFromIrp( pIrp);
if (pKSFilter && pKSPinMethod)
{
status = BdaCreatePin( pKSFilter,
pKSPinMethod->PinType,
pulPinFactoryID
);
}
}
else
{
status = STATUS_INVALID_PARAMETER;
}
return status;
}
/*
** BdaMethodDeletePin ()
**
** Deletes the given pin factory
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaMethodDeletePin(
IN PIRP Irp,
IN PKSMETHOD Method,
OPTIONAL PVOID pvIgnored
)
{
ASSERT( Irp);
if (!Irp)
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
/*
** BdaPropertyGetPinControl ()
**
** Returns a the BDA ID or BDA Template Type of the Pin.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPropertyGetPinControl(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT ULONG * pulProperty
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSPIN pKSPin;
BDA_PIN_FACTORY_CONTEXT pinCtx;
ASSERT( Irp);
if (!Irp)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
ASSERT( Property);
if (!Property)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSPin = KsGetPinFromIrp( Irp);
status = BdaGetPinFactoryContext( pKSPin, &pinCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
if (pulProperty)
{
Irp->IoStatus.Information = sizeof( ULONG);
switch (Property->Id)
{
case KSPROPERTY_BDA_PIN_ID:
// Return the BDA ID of this pin
//
*pulProperty = pinCtx.ulPinFactoryId;
break;
case KSPROPERTY_BDA_PIN_TYPE:
// Return the BDA Type of this pin
//
*pulProperty = pinCtx.ulPinType;
break;
default:
Irp->IoStatus.Information = 0;
status = STATUS_INVALID_PARAMETER;
ASSERT( FALSE);
}
}
else
{
status = STATUS_MORE_ENTRIES;
// If there is no place to put the property then just
// return the data size.
//
Irp->IoStatus.Information = sizeof( ULONG);
}
errExit:
return status;
}
/*
** BdaValidateNodeProperty ()
**
** Validates that the IRP is for a Pin and that
** the property belongs to a node associated with that
** Pin.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaValidateNodeProperty(
IN PIRP pIrp,
IN PKSMETHOD pKSProperty
)
{
ASSERT( pIrp);
if (!pIrp)
{
return STATUS_INVALID_PARAMETER;
}
ASSERT( pKSProperty);
if (!pKSProperty)
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
/*
** BdaMethodCreateTopology ()
**
** Creates the topology between the two given pin factories.
**
** Arguments:
**
**
** Returns:
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaMethodCreateTopology(
IN PIRP pIrp,
IN PKSMETHOD pKSMethod,
OPTIONAL PVOID pvIgnored
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PKSM_BDA_PIN_PAIR pKSPinPairMethod;
ULONG ulPinId;
if (pIrp)
{
pKSPinPairMethod = (PKSM_BDA_PIN_PAIR) pKSMethod;
pKSFilter = KsGetFilterFromIrp( pIrp);
if (pKSFilter && pKSPinPairMethod)
{
// Obtain the KS Filter Mutex
//
//$BUG - Obtain the KS Filter Mutex
status = BdaCreateTopology( pKSFilter,
pKSPinPairMethod->InputPinId,
pKSPinPairMethod->OutputPinId
);
// Release the KS Filter Mutex
//
//$BUG - Obtain the KS Filter Mutex
}
else
{
status = STATUS_INVALID_PARAMETER;
}
}
else
{
status = STATUS_INVALID_PARAMETER;
}
return status;
}
/*
** BdaFindPinPair()
**
** Returns a pointer to the BDA_PIN_PAIRING that corresponds
** to the given input and output pins.
**
** Arguments:
**
** pTopology Pointer to the BDA topology that contains the
** pin pairing.
**
** InputPinId Id of the input Pin to match
**
** OutputPinId Id of the output Pin to match
**
** Returns:
**
** pPinPairing Pointer to a valid BDA Pin Pairing structure
**
** NULL If no valid pin pairing exists with the
** given input and output pins.
**
** Side Effects: none
*/
PBDA_PIN_PAIRING
BdaFindPinPair(
PBDA_FILTER_TEMPLATE pFilterTemplate,
ULONG InputPinId,
ULONG OutputPinId
)
{
return NULL;
}
/*
** BdaGetPinFactoryContext()
**
** Finds a BDA PinFactory Context that corresponds
** to the given KS Pin Instance.
**
** Arguments:
**
**
** Returns:
**
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaGetPinFactoryContext(
PKSPIN pKSPin,
PBDA_PIN_FACTORY_CONTEXT pPinFactoryCtx
)
{
NTSTATUS status = STATUS_SUCCESS;
PKSFILTER pKSFilter;
PBDA_FILTER_CONTEXT pFilterCtx = NULL;
if (!pKSPin || !pPinFactoryCtx)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pKSFilter = KsPinGetParentFilter( pKSPin);
if (!pKSFilter)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Find our Filter Context so that we can look up the pin type
// in the Template Topology.
//
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
if (pKSPin->Id >= pFilterCtx->ulcPinFactories)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
*pPinFactoryCtx = pFilterCtx->argPinFactoryCtx[pKSPin->Id];
errExit:
return status;
}
/*
** BdaCreatePin()
**
** Utility function creates a new pin in the given filter instance.
**
**
** Arguments:
**
**
**
** PinType Pin type to create.
**
** pPinId Id of the Pin that was created.
**
** Returns:
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreatePin(
PKSFILTER pKSFilter,
ULONG ulPinType,
PULONG pulPinId
)
{
NTSTATUS status = STATUS_SUCCESS;
PBDA_FILTER_CONTEXT pFilterCtx;
PBDA_PIN_FACTORY_CONTEXT pPinFactoryCtx;
KSPIN_DESCRIPTOR_EX myKSPinDescriptorEx;
KSAUTOMATION_TABLE * pNewAutomationTable = NULL;
const KSPIN_DESCRIPTOR_EX * pKSPinDescriptorEx;
const BDA_FILTER_TEMPLATE * pBdaFilterTemplate;
const KSFILTER_DESCRIPTOR * pFilterDescriptor;
ASSERT( pulPinId);
if (!pulPinId)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Find our Filter Context so that we can look up the pin type
// in the Template Topology.
//
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
// Locate this filter's Template Topology
//
if ( !pFilterCtx
|| !pFilterCtx->pBdaFilterTemplate
|| !pFilterCtx->pBdaFilterTemplate->pFilterDescriptor
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
pFilterDescriptor = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
// Locate the Pin Type in this filter's Template Topology
//
if (pFilterDescriptor->PinDescriptorsCount <= ulPinType)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Get the KSPIN_DESCRIPTOR_EX for this pin type
//
pKSPinDescriptorEx = pFilterDescriptor->PinDescriptors;
ASSERT( pKSPinDescriptorEx);
ASSERT( pFilterDescriptor->PinDescriptorSize);
pKSPinDescriptorEx = (const KSPIN_DESCRIPTOR_EX *)
( (BYTE *) pKSPinDescriptorEx
+ ulPinType * pFilterDescriptor->PinDescriptorSize
);
// Create a new copy of the pin descriptor so that it is easier to
// modify
//
myKSPinDescriptorEx = *pKSPinDescriptorEx;
myKSPinDescriptorEx.AutomationTable = NULL;
status = BdaAddNodeAutomationToPin( pFilterCtx,
ulPinType,
pKSFilter->Bag,
pKSPinDescriptorEx->AutomationTable,
&pNewAutomationTable
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Merge required properties for which BdaSup.sys provides a default
// implementation.
//
status = KsMergeAutomationTables(
&((PKSAUTOMATION_TABLE)(myKSPinDescriptorEx.AutomationTable)),
pNewAutomationTable,
(PKSAUTOMATION_TABLE) &BdaDefaultPinAutomation,
pKSFilter->Bag
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
status = KsFilterCreatePinFactory ( pKSFilter,
&myKSPinDescriptorEx,
pulPinId
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
status = BdaCreatePinFactoryContext( pKSFilter,
pFilterCtx,
*pulPinId,
ulPinType
);
errExit:
return status;
}
/*
** BdaAddNodeAutomationToPin()
**
** Merges the automation tables for each node type that is controlled
** by the pin type being created into the automation table for the
** the pin factory. This is how the automation tables for BDA
** control nodes get linked to the controlling pin. Otherwise the
** nodes would not be accesable.
**
**
** Arguments:
**
**
** pFilterCtx The BDA filter context to which the pin factory
** belongs. Must have this to get at the template
** topology.
**
** ulPinType BDA Pin Type of the pin being created. Need this
** to figure out which nodes are controlled by the
** pin.
**
** Returns:
** Always returns a resulting automation table, even on error.
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaAddNodeAutomationToPin(
PBDA_FILTER_CONTEXT pFilterCtx,
ULONG ulControllingPinType,
KSOBJECT_BAG ObjectBag,
const KSAUTOMATION_TABLE * pOriginalAutomationTable,
PKSAUTOMATION_TABLE * ppNewAutomationTable
)
{
NTSTATUS status = STATUS_SUCCESS;
const KSFILTER_DESCRIPTOR * pFilterDescriptor;
KSAUTOMATION_TABLE * pNewAutomationTable = NULL;
ULONG uliPath;
ULONG ulcNodes;
ULONG ulcbNodeDescriptor;
// Check for required parameters
//
if (!pFilterCtx || !ObjectBag)
{
status = STATUS_INVALID_PARAMETER;
goto exit;
}
if ( !pFilterCtx->ulcPathInfo
|| !pFilterCtx->pBdaFilterTemplate
|| !pFilterCtx->pBdaFilterTemplate->pFilterDescriptor
|| !pFilterCtx->pBdaFilterTemplate->pFilterDescriptor->NodeDescriptorsCount
|| !pFilterCtx->pBdaFilterTemplate->pFilterDescriptor->NodeDescriptors
)
{
goto exit;
}
pFilterDescriptor = pFilterCtx->pBdaFilterTemplate->pFilterDescriptor;
// If ulcNodeControlInfo is not zero the that array of control info
// structures must exist
//
ASSERT( pFilterCtx->argpPathInfo);
if (!pFilterCtx->argpPathInfo)
{
status = STATUS_INVALID_DEVICE_STATE;
goto exit;
}
// Initial variables used to step through the list of node descriptors
// for the filter to which this pin type belongs.
//
ulcNodes = pFilterDescriptor->NodeDescriptorsCount;
ulcbNodeDescriptor = pFilterDescriptor->NodeDescriptorSize;
// Step through each template node descriptor and, if it is controlled,
// by the given pin type, add its automation table to resulting table.
//
for ( uliPath = 0
; uliPath < pFilterCtx->ulcPathInfo
; uliPath++
)
{
PBDA_PATH_INFO pPathInfo;
ULONG uliPathEntry;
BOOLEAN fMergeNode = FALSE;
pPathInfo = pFilterCtx->argpPathInfo[uliPath];
// Skip paths that don't include this pin type.
//
if (pPathInfo->ulInputPin == ulControllingPinType)
{
// If the controlling pin is an input pin then we
// will start merging nodes right away and quit when
// we find a topology joint.
//
fMergeNode = TRUE;
}
else if (pPathInfo->ulOutputPin == ulControllingPinType)
{
// If the controlling pin is an output pin then we
// will not merge nodes until we find a topology
// joint.
//
fMergeNode = FALSE;
}
else
{
// The pin we're interested in isn't part of this path.
continue;
}
// Loop through each connection in the path to see if it points
// to a node whose automation table needs to be merged to the
// pin.
//
for ( uliPathEntry = 0
; uliPathEntry < pPathInfo->ulcPathEntries
; uliPathEntry++
)
{
const KSTOPOLOGY_CONNECTION * pConnection;
ULONG uliConnection;
const KSNODE_DESCRIPTOR * pNodeDescriptor;
ULONG uliNode;
if (pPathInfo->rgPathEntries[uliPathEntry].fJoint)
{
// Switch the merge state on a topology joint.
//
fMergeNode = !fMergeNode;
if (!fMergeNode)
{
// If we were merging input side nodes then we're done
//
break;
}
}
if (!fMergeNode)
{
continue;
}
// Get the "ToNode" from this connection and, if it is not
// an output pin, merge its automation table.
//
uliConnection = pPathInfo->rgPathEntries[uliPathEntry].uliConnection;
pConnection = &(pFilterDescriptor->Connections[uliConnection]);
uliNode = pConnection->ToNode;
if ( (uliNode == -1)
|| (uliNode >= pFilterDescriptor->NodeDescriptorsCount)
)
{
// This connection's "ToNode" is an output pin so
// skip it.
//
continue;
}
// Find the Node Descriptor for the node type
//
pNodeDescriptor = pFilterDescriptor->NodeDescriptors;
pNodeDescriptor = (const KSNODE_DESCRIPTOR *)
( (const BYTE *) (pNodeDescriptor)
+ (ulcbNodeDescriptor * uliNode)
);
// Merge the nodes automation table into the resulting automation
// table.
//
//$BUGBUG - KsMergeAutomationTables should take const xxx *
//
if (!pOriginalAutomationTable)
{
pOriginalAutomationTable
= (PKSAUTOMATION_TABLE) (pNodeDescriptor->AutomationTable);
}
else
{
status = KsMergeAutomationTables(
&pNewAutomationTable,
(PKSAUTOMATION_TABLE) pOriginalAutomationTable,
(PKSAUTOMATION_TABLE) (pNodeDescriptor->AutomationTable),
ObjectBag
);
if (status != STATUS_SUCCESS)
{
goto exit;
}
ASSERT( pNewAutomationTable);
pOriginalAutomationTable = pNewAutomationTable;
pNewAutomationTable = NULL;
}
}
}
exit:
*ppNewAutomationTable = (PKSAUTOMATION_TABLE) pOriginalAutomationTable;
return status;
}
/*
** BdaDeletePin()
**
** Utility function deletes a pin from the given filter instance.
**
**
** Arguments:
**
**
** PinType Pin type to create.
**
** pPinId Id of the Pin that was created.
**
** Returns:
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaDeletePin(
PKSFILTER pKSFilter,
PULONG pulPinId
)
{
NTSTATUS status = STATUS_SUCCESS;
PBDA_FILTER_CONTEXT pFilterCtx;
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
errExit:
return status;
}
/*
** BdaPathExists()
**
** Utility function checks if there is a path between the input and
** the output.
**
**
** Arguments:
**
** InputPinId
**
** OutPutPinId
**
** Returns:
**
** TRUE If a path exists.
** FALSE If no path exists.
**
** Side Effects: none
*/
STDMETHODIMP_(BOOLEAN)
BdaPathExists(
const KSFILTER_DESCRIPTOR * pFilterDescriptor,
ULONG ulInputPinId,
ULONG ulOutputPinId
)
{
const KSTOPOLOGY_CONNECTION * pConnection;
ULONG ulcConnections;
ULONG uliConnection;
if ( !pFilterDescriptor
|| !pFilterDescriptor->ConnectionsCount
|| !pFilterDescriptor->Connections
)
{
return FALSE;
}
//$REVIEW - Assume only DShow style internal connections.
//$REVIEW (ie connections between pins with no intervening nodes)
//
ulcConnections = pFilterDescriptor->ConnectionsCount;
pConnection = pFilterDescriptor->Connections;
for (uliConnection = 0; uliConnection < ulcConnections; uliConnection++)
{
if ( (pConnection[uliConnection].FromNode == -1)
&& (pConnection[uliConnection].FromNodePin == ulInputPinId)
&& (pConnection[uliConnection].ToNode == -1)
&& (pConnection[uliConnection].ToNodePin == ulOutputPinId)
)
{
break;
}
}
return (uliConnection < ulcConnections);
}
/*
** BdaCreateTopology()
**
** Utility function creates the topology between two pins.
**
**
** Arguments:
**
**
** InputPinId
**
** OutPutPinId
**
** Returns:
**
** NULL If no valid pin pairing exists with the
** given input and output pins.
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreateTopology(
PKSFILTER pKSFilter,
ULONG ulInputPinId,
ULONG ulOutputPinId
)
{
NTSTATUS status = STATUS_SUCCESS;
PBDA_FILTER_CONTEXT pFilterCtx = NULL;
const KSFILTER_DESCRIPTOR * pFilterDesc;
ULONG uliPinPair;
ULONG ulcPinPairs;
const BDA_PIN_PAIRING * pPinPairs;
ULONG ulInputPinType;
ULONG ulOutputPinType;
if (!pKSFilter)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
status = BdaGetFilterContext( pKSFilter, &pFilterCtx);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
ASSERT( pFilterCtx);
if (!pFilterCtx)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
ASSERT( pFilterCtx->pBdaFilterTemplate);
if (!pFilterCtx->pBdaFilterTemplate)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
pPinPairs = pFilterCtx->pBdaFilterTemplate->pPinPairs;
ulcPinPairs = pFilterCtx->pBdaFilterTemplate->ulcPinPairs;
pFilterDesc = pKSFilter->Descriptor;
if ( !pFilterDesc
|| (ulInputPinId >= pFilterDesc->PinDescriptorsCount)
|| (ulOutputPinId >= pFilterDesc->PinDescriptorsCount)
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
if (BdaPathExists( pFilterDesc, ulInputPinId, ulOutputPinId))
{
goto errExit;
}
// Get the input pin type.
//
status = BdaPinTypeFromPinId( pFilterCtx,
ulInputPinId,
&ulInputPinType
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// Get the output pin type.
//
status = BdaPinTypeFromPinId( pFilterCtx,
ulOutputPinId,
&ulOutputPinType
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
// See if there is a pin pairing to match the requested topology.
//
for (uliPinPair = 0; uliPinPair < ulcPinPairs; uliPinPair++)
{
if ( (pPinPairs[uliPinPair].ulInputPin == ulInputPinType)
&& (pPinPairs[uliPinPair].ulOutputPin == ulOutputPinType)
)
{
break;
}
}
if (uliPinPair >= ulcPinPairs)
{
status = STATUS_INVALID_DEVICE_REQUEST;
goto errExit;
}
{
KSTOPOLOGY_CONNECTION ksConnection;
// Add a path between the pins to the filter descriptor
//
ksConnection.FromNode = -1;
ksConnection.FromNodePin = ulInputPinId;
ksConnection.ToNode = -1;
ksConnection.ToNodePin = ulOutputPinId;
status = KsFilterAddTopologyConnections ( pKSFilter,
1,
&ksConnection
);
}
errExit:
return status;
}
/*
** BdaInitFilterFactoryContext()
**
** Initializes a BDA Filter Factory Context based on the filter's
** template descriptor.
**
**
** Arguments:
**
**
** pFilterFactoryCtx
**
** Returns:
**
** NULL If no valid pin pairing exists with the
** given input and output pins.
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaInitFilterFactoryContext(
PBDA_FILTER_FACTORY_CONTEXT pFilterFactoryCtx
)
{
NTSTATUS status = STATUS_SUCCESS;
ASSERT( pFilterFactoryCtx);
if (!pFilterFactoryCtx)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
if (!pFilterFactoryCtx->pBdaFilterTemplate)
{
goto errExit;
}
errExit:
return status;
}
/*
** BdaPushNextPathHop()
**
** Recursively pushes connections onto the connection stack until
** (starting with the input pin of the pin pair) until either the
** output pin is found or there are no connections that can be pushed.
**
**
** Arguments:
**
**
** pFilterFactoryCtx
**
** Returns:
**
** NULL If no valid pin pairing exists with the
** given input and output pins.
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPushNextPathHop(
PULONG puliPathStack,
PBDA_PATH_STACK_ENTRY pPathStack,
ULONG ulcConnections,
const KSTOPOLOGY_CONNECTION * pConnections,
const BDA_PIN_PAIRING * pPinPair
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG ulHop;
ULONG ulFromNode;
ULONG ulFromNodePin;
ULONG uliConnection;
// Determine which node we are currently finding connection to.
//
if (!*puliPathStack)
{
// We are pushing the first hop.
//
ulHop = 0;
// Hop 0 is always the input pin
//
ulFromNode = -1;
ulFromNodePin = pPinPair->ulInputPin;
}
else
{
// We are pushing the next hop.
//
ulHop = pPathStack[*puliPathStack - 1].ulHop + 1;
// We will be looking for connections from the "ToNode" of the
// connection at the top of the stack.
//
uliConnection = pPathStack[*puliPathStack - 1].uliConnection;
ulFromNode = pConnections[uliConnection].ToNode;
ulFromNodePin = pConnections[uliConnection].ToNodePin;
}
// GO through each connection in the filter factories connection
// and push any connection to ulFromNode onto the connections stack.
// If a connection from ulFromNode to the output pin of the given
// pin pair is found then we have found a complete path for the
// pin pair.
//
for ( uliConnection = 0
; uliConnection < ulcConnections
; uliConnection++
)
{
ULONG uliJoints;
const ULONG * pJoints;
if (pConnections[uliConnection].FromNode != ulFromNode)
{
// Connection is not from the node at the top of the stack.
//
continue;
}
if ( (pConnections[uliConnection].FromNode == -1)
&& (pConnections[uliConnection].FromNodePin != ulFromNodePin)
)
{
// The input pin is at the top of the stack and this connection
// is not from the input pin of the pin pair.
//
continue;
}
//
// This connection is from the node that was on top of the stack
// when this function was called. Push it onto the stack.
//
if (*puliPathStack >= ulcConnections)
{
// Stack overflow
// Can only occur when the BDA topology contains
// cirular references.
//
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Write the connection info to the next stack entry.
//
pPathStack[*puliPathStack].ulHop = ulHop;
pPathStack[*puliPathStack].uliConnection = uliConnection;
pPathStack[*puliPathStack].fJoint = FALSE;
// See if this connection is also a topology joint.
//
for ( uliJoints = 0, pJoints = pPinPair->pTopologyJoints
; (uliJoints < pPinPair->ulcTopologyJoints) && pJoints
; uliJoints++
)
{
if (pJoints[uliJoints] == uliConnection)
{
pPathStack[*puliPathStack].fJoint = TRUE;
break;
}
}
// Increment the stack pointer
//
*puliPathStack += 1;
// Now that the connection has been pushed on the stack. See if it
// completes a path between the input and output pin pair.
//
if ( (pConnections[uliConnection].ToNode == -1)
&& (pConnections[uliConnection].ToNodePin == pPinPair->ulOutputPin)
)
{
// If this connection completes the path, then complete
// now so that the caller will find the end of the path
// at the top of the stack.
//
break;
}
}
errExit:
return status;
}
/*
** BdaPopPathSegment()
**
** Pops the stack back to the next path segment to try.
**
**
** Arguments:
**
**
** Returns:
**
**
** Side Effects: none
*/
BdaPopPathSegment(
PULONG puliPathStack,
PBDA_PATH_STACK_ENTRY pPathStack
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG ulCurHop;
ULONG ulNewHop;
ulCurHop = pPathStack[*puliPathStack].ulHop;
while (*puliPathStack)
{
*puliPathStack -= 1;
if (!*puliPathStack)
{
// Empty Stack
//
break;
}
if (pPathStack[(*puliPathStack) - 1].ulHop == ulCurHop)
{
// Stop here if there is another entry on the stack at
// the current hop count.
//
break;
}
// We've popped back to a new hop count, so set the current
// hop count and pop off another entry.
//
ulCurHop = pPathStack[(*puliPathStack) - 1].ulHop;
}
return status;
}
/*
** BdaPathInfoFromPathStack()
**
** Builds a connection path between the input and output pins of
** a pin pair.
**
**
** Arguments:
**
**
** Returns:
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaPathInfoFromPathStack(
ULONG uliPathStack,
PBDA_PATH_STACK_ENTRY pPathStack,
ULONG ulcConnections,
const KSTOPOLOGY_CONNECTION * pConnections,
const BDA_PIN_PAIRING * pPinPair,
PBDA_PATH_INFO * ppPathInfo
)
{
NTSTATUS status = STATUS_SUCCESS;
PBDA_PATH_INFO pPathInfo = NULL;
ULONG uliConnection;
ULONG ulHop;
ASSERT( uliPathStack);
ASSERT( pPathStack);
ASSERT( uliPathStack <= ulcConnections);
ASSERT( ulcConnections);
ASSERT( pConnections);
ASSERT( ppPathInfo);
ASSERT( pPinPair);
if ( !ppPathInfo
|| !pConnections
|| !pPathStack
|| !pPinPair
|| !uliPathStack
|| !ulcConnections
|| (uliPathStack > ulcConnections)
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Make sure the connection at the top of the path stack points
// to the output pin of the pin pair.
//
uliConnection = pPathStack[uliPathStack - 1].uliConnection;
if ( (pConnections[uliConnection].ToNode != -1)
|| (pConnections[uliConnection].ToNodePin != pPinPair->ulOutputPin)
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Start filling in from the node at the last hop. If the last
// hop == 0 then there was only one connection between the input
// and output pins with no intervening nodes.
//
ulHop = pPathStack[uliPathStack - 1].ulHop;
// Allocate enough space for the node path structure and all
// nodes in the path.
//
pPathInfo = ExAllocatePool(
NonPagedPool,
sizeof( BDA_PATH_INFO)
+ (ulHop + 1) * sizeof( BDA_PATH_STACK_ENTRY)
);
if (!pPathInfo)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
pPathInfo->ulInputPin = pPinPair->ulInputPin;
pPathInfo->ulOutputPin = pPinPair->ulOutputPin;
pPathInfo->ulcPathEntries = ulHop + 1;
while (uliPathStack)
{
// Enter the Connection info into the path connection list
//
//
pPathInfo->rgPathEntries[ulHop] = pPathStack[uliPathStack - 1];
// Pop the path stack up to the top entry of the next lower hop.
// If exhaust the path stack then we are either done or the path
// stack didn't reflect a complete path from input pin to
// output pin.
//
ulHop -= 1;
while ( uliPathStack
&& (pPathStack[uliPathStack - 1].ulHop != ulHop)
)
{
uliPathStack -= 1;
}
}
// We should alway end up pointing to a connection between the input
// pin and the first node of the path to the output pin.
//
ASSERT( ulHop == -1);
if (ulHop != -1)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
// Make sure the last connection points back to the input pin.
//
uliConnection = pPathInfo->rgPathEntries[0].uliConnection;
if ( (pConnections[uliConnection].FromNode != -1)
|| (pConnections[uliConnection].FromNodePin != pPinPair->ulInputPin)
)
{
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
exit:
*ppPathInfo = pPathInfo;
pPathInfo = NULL;
return status;
errExit:
if (pPathInfo)
{
ExFreePool( pPathInfo);
pPathInfo = NULL;
}
goto exit;
}
/*
** BdaBuildPath()
**
** Builds a connection path between the input and output pins of
** a pin pair.
**
**
** Arguments:
**
**
** Returns:
**
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaBuildPath(
ULONG ulcConnections,
const KSTOPOLOGY_CONNECTION * pConnections,
const BDA_PIN_PAIRING * pPinPair,
PBDA_PATH_INFO * ppPathInfo
)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uliStackPointer;
PBDA_PATH_STACK_ENTRY pPathStack = NULL;
ULONG ulcAttempts;
ULONG uliConnection;
// Allocate a stack on which to put unfollowed connections to a path.
//
pPathStack = ExAllocatePool(
NonPagedPool,
ulcConnections * sizeof( BDA_PATH_STACK_ENTRY)
);
if (!pPathStack)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
// Initialize the unfollowed connection stack
//
uliStackPointer = 0;
// Build a path stack by pushing each connection that connects from
// the previous hop.
//
// It isn't possible to attempt to push the next hop more times than
// there are connections. If this happens then there is an illegal
// circular path in the connection list.
//
for (ulcAttempts = 0; ulcAttempts < ulcConnections; ulcAttempts++)
{
ULONG uliPrevStackPointer;
uliPrevStackPointer = uliStackPointer;
status = BdaPushNextPathHop( &uliStackPointer,
pPathStack,
ulcConnections,
pConnections,
pPinPair
);
if (!uliStackPointer)
{
// If the stack is empty at this point then there is
// no path from the input pin to the output pin.
//
break;
}
// See if the connection at the top of the stack connects to
// the output pin of the pin pair.
//
uliConnection = pPathStack[uliStackPointer - 1].uliConnection;
if ( (pConnections[uliConnection].ToNode == -1)
&& (pConnections[uliConnection].ToNodePin == pPinPair->ulOutputPin)
)
{
// A path from the input pin to the output pin has been
// located.
//
break;
}
// If no hop could be pushed onto the connnection at the top of
// the stack then it is a dead end.
//
if (uliStackPointer <= uliPrevStackPointer)
{
// Pop connections from the stack until we reach a viable
// (new) candidate to attempt a path from.
//
BdaPopPathSegment( &uliStackPointer, pPathStack);
if (!uliStackPointer)
{
// If the stack is empty at this point then there is
// no path from the input pin to the output pin.
//
break;
}
}
}
if (!uliStackPointer || (ulcAttempts >= ulcConnections))
{
// Either there is no path from the input pin to the output pin
// or there is an illegal circular path in the connection list
//
status = STATUS_INVALID_PARAMETER;
goto errExit;
}
// Create a BDA node path structure from the Path Stack
//
//$REVIEW - Should we allow more than one path per pin pair
//
status = BdaPathInfoFromPathStack( uliStackPointer,
pPathStack,
ulcConnections,
pConnections,
pPinPair,
ppPathInfo
);
errExit:
if (pPathStack)
{
ExFreePool( pPathStack);
pPathStack = NULL;
}
return status;
}
/*
** BdaCreateTemplatePaths()
**
** Creates a list of all possible paths through the template filter.
** Determines the controlling pin type for each node type in the
** template filter.
**
**
** Arguments:
**
**
** pFilterFactoryCtx
**
** Returns:
**
** NULL If no valid pin pairing exists with the
** given input and output pins.
**
** Side Effects: none
*/
STDMETHODIMP_(NTSTATUS)
BdaCreateTemplatePaths(
const BDA_FILTER_TEMPLATE * pBdaFilterTemplate,
PULONG pulcPathInfo,
PBDA_PATH_INFO ** pargpPathInfo
)
{
NTSTATUS status = STATUS_SUCCESS;
const BDA_FILTER_TEMPLATE * pFilterTemplate;
ULONG uliPinPair;
ULONG ulcPinPairs;
const BDA_PIN_PAIRING * pPinPairs;
ULONG ulcConnections;
const KSTOPOLOGY_CONNECTION * pConnections;
PBDA_PATH_INFO * argpPathInfo = NULL;
ASSERT( pBdaFilterTemplate);
ASSERT( pBdaFilterTemplate->pFilterDescriptor);
ASSERT( pBdaFilterTemplate->ulcPinPairs);
if ( !pBdaFilterTemplate
|| !pBdaFilterTemplate->pFilterDescriptor
|| !pBdaFilterTemplate->ulcPinPairs
)
{
goto errExit;
}
if ( !pBdaFilterTemplate->pFilterDescriptor->ConnectionsCount
|| !pBdaFilterTemplate->pFilterDescriptor->Connections
|| !pBdaFilterTemplate->pPinPairs
)
{
status = STATUS_INVALID_DEVICE_STATE;
goto errExit;
}
ulcPinPairs = pBdaFilterTemplate->ulcPinPairs;
pPinPairs = pBdaFilterTemplate->pPinPairs;
ulcConnections = pBdaFilterTemplate->pFilterDescriptor->ConnectionsCount;
pConnections = pBdaFilterTemplate->pFilterDescriptor->Connections;
// Allocate the node path list (one entry for each pin pairing).
//
//$REVIEW - Should we allow more than one path per pin pair
//
argpPathInfo = ExAllocatePool(
NonPagedPool,
ulcPinPairs * sizeof( PBDA_PATH_INFO)
);
if (!argpPathInfo)
{
status = STATUS_NO_MEMORY;
goto errExit;
}
for (uliPinPair = 0; uliPinPair < ulcPinPairs; uliPinPair++)
{
status = BdaBuildPath(
ulcConnections,
pConnections,
&(pPinPairs[uliPinPair]),
&(argpPathInfo[uliPinPair])
);
if (status != STATUS_SUCCESS)
{
goto errExit;
}
}
*pulcPathInfo = ulcPinPairs;
*pargpPathInfo = argpPathInfo;
argpPathInfo = NULL;
errExit:
if (argpPathInfo)
{
ExFreePool( argpPathInfo);
argpPathInfo = NULL;
}
return status;
}