//==========================================================================; // // 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 #include #include #include #include #include #include #include #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; }