Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1878 lines
59 KiB

/*****************************************************************************
* porthelp.cpp - WDM Streaming port class driver port helper functions
*****************************************************************************
* Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
*/
#include "private.h"
/*****************************************************************************
* Functions.
*/
#pragma code_seg("PAGE")
static
KSPIN_MEDIUM PinMediums[] =
{
{
STATICGUIDOF(KSMEDIUMSETID_Standard),
KSMEDIUM_STANDARD_DEVIO,
0
}
};
#define UPTOQUAD(x) (((x)+7)&~7)
/*****************************************************************************
* PrivateHeap
*****************************************************************************
* Class for managing a private heap.
*/
class PrivateHeap
{
private:
PBYTE m_pbTop;
PBYTE m_pbCurrent;
ULONG m_ulSize;
public:
PrivateHeap(void) : m_pbTop(NULL),
m_pbCurrent(NULL),
m_ulSize(NULL)
{
}
//
// Increase the number of bytes that will be allocated for the heap.
//
ULONG Reserve(ULONG ulBytes)
{
ASSERT(! m_pbTop);
ASSERT(! m_pbCurrent);
m_ulSize += UPTOQUAD(ulBytes);
return m_ulSize;
}
//
// Allocate memory for the private heap from a pool.
//
NTSTATUS AllocateFromPool(POOL_TYPE poolType,ULONG ulTag)
{
ASSERT(! m_pbTop);
ASSERT(! m_pbCurrent);
ASSERT(m_ulSize);
m_pbTop = new(poolType,ulTag) BYTE[m_ulSize];
if (! m_pbTop)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
m_pbCurrent = m_pbTop;
return STATUS_SUCCESS;
}
//
// Allocate memory from the heap.
//
PVOID Alloc(ULONG ulSize)
{
ASSERT(ulSize);
ASSERT(m_pbTop);
ASSERT(m_pbCurrent);
ASSERT(m_pbCurrent + UPTOQUAD(ulSize) <= m_pbTop + m_ulSize);
PVOID pvResult = PVOID(m_pbCurrent);
m_pbCurrent += UPTOQUAD(ulSize);
return pvResult;
}
//
// Determine the amount of space remaining in the heap.
//
ULONG BytesRemaining(void)
{
ASSERT(m_pbTop);
ASSERT(m_pbCurrent);
ASSERT(m_pbCurrent <= m_pbTop + m_ulSize);
return ULONG((m_pbTop + m_ulSize) - m_pbCurrent);
}
};
/*****************************************************************************
* ::new()
*****************************************************************************
* New function for creating objects with private heap.
*/
inline PVOID operator new
(
size_t iSize,
PrivateHeap& privateHeap
)
{
return privateHeap.Alloc(ULONG(iSize));
}
/*****************************************************************************
* MeasureDataRanges()
*****************************************************************************
* Determine how much a set of data ranges will expand as a result
* of cloning WAVEFORMATEX ranges into identical DSOUND ranges.
*
* As of WinME, we also clone non-PCM ranges.
*/
static
ULONG
MeasureDataRanges
(
IN PrivateHeap * pPrivateHeap OPTIONAL,
IN ULONG ulDataRangeCountIn,
IN KSDATARANGE *const * ppKsDataRangeIn
)
{
ULONG ulNewDataRangeCount = ulDataRangeCountIn;
for (ULONG ul = ulDataRangeCountIn; ul--; )
{
ASSERT(ppKsDataRangeIn);
if ( ( (*ppKsDataRangeIn)->FormatSize
>= sizeof(KSDATAFORMAT_WAVEFORMATEX)
)
&& IsEqualGUIDAligned
( (*ppKsDataRangeIn)->MajorFormat,
KSDATAFORMAT_TYPE_AUDIO
)
&& IsEqualGUIDAligned
( (*ppKsDataRangeIn)->Specifier,
KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
)
)
{
ulNewDataRangeCount++;
if (pPrivateHeap)
{
pPrivateHeap->Reserve((*ppKsDataRangeIn)->FormatSize);
}
}
ppKsDataRangeIn++;
}
if (pPrivateHeap && (ulNewDataRangeCount != ulDataRangeCountIn))
{
pPrivateHeap->Reserve(ulNewDataRangeCount * sizeof(PKSDATARANGE));
}
return ulNewDataRangeCount;
}
/*****************************************************************************
* CloneDataRanges()
*****************************************************************************
* Expand data ranges to include DSound formats.
*/
static
const PKSDATARANGE *
CloneDataRanges
(
IN PrivateHeap& privateHeap,
OUT PULONG pulDataRangeCountOut,
IN ULONG ulDataRangeCountIn,
IN KSDATARANGE *const * ppKsDataRangeIn
)
{
ASSERT(pulDataRangeCountOut);
//
// Determine how many data ranges there will be and how much space will be
// required for the new ones.
//
ULONG ulDataRangeCountOut =
MeasureDataRanges(NULL,ulDataRangeCountIn,ppKsDataRangeIn);
const PKSDATARANGE *ppKsDataRangeOut;
if (ulDataRangeCountOut == ulDataRangeCountIn)
{
//
// No new data ranges. Use the array we were given.
//
ppKsDataRangeOut = ppKsDataRangeIn;
}
else
{
//
// Allocate some space for the new array.
//
ppKsDataRangeOut = new(privateHeap) PKSDATARANGE[ulDataRangeCountOut];
//
// Build the new array.
//
PKSDATARANGE *ppKsDataRange = (PKSDATARANGE *) ppKsDataRangeOut;
while (ulDataRangeCountIn--)
{
ASSERT(ppKsDataRangeIn);
//
// All the data ranges get copied.
//
*ppKsDataRange++ = *ppKsDataRangeIn;
//
// Check for WaveFormatEx datarange
// This includes non-PCM subformats....
//
if ( ( (*ppKsDataRangeIn)->FormatSize
>= sizeof(KSDATAFORMAT_WAVEFORMATEX)
)
&& IsEqualGUIDAligned
( (*ppKsDataRangeIn)->MajorFormat,
KSDATAFORMAT_TYPE_AUDIO
)
&& IsEqualGUIDAligned
( (*ppKsDataRangeIn)->Specifier,
KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
)
)
{
//
// WaveFormatEx datarange will require DSound clone.
// Allocate memory for it and copy.
//
*ppKsDataRange =
PKSDATARANGE
(
new(privateHeap) BYTE[(*ppKsDataRangeIn)->FormatSize]
);
RtlCopyMemory
(
*ppKsDataRange,
*ppKsDataRangeIn,
(*ppKsDataRangeIn)->FormatSize
);
//
// Update the specifier.
//
(*ppKsDataRange++)->Specifier =
KSDATAFORMAT_SPECIFIER_DSOUND;
}
//
// Increment input position
//
ppKsDataRangeIn++;
}
}
*pulDataRangeCountOut = ulDataRangeCountOut;
return ppKsDataRangeOut;
}
/*****************************************************************************
* PcCreateSubdeviceDescriptor()
*****************************************************************************
* Creates a subdevice descriptor.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcCreateSubdeviceDescriptor
(
IN PPCFILTER_DESCRIPTOR pPcFilterDescriptor,
IN ULONG CategoriesCount,
IN GUID * Categories,
IN ULONG StreamInterfacesCount,
IN PKSPIN_INTERFACE StreamInterfaces,
IN ULONG FilterPropertySetCount,
IN PKSPROPERTY_SET FilterPropertySets,
IN ULONG FilterEventSetCount,
IN PKSEVENT_SET FilterEventSets,
IN ULONG PinPropertySetCount,
IN PKSPROPERTY_SET PinPropertySets,
IN ULONG PinEventSetCount,
IN PKSEVENT_SET PinEventSets,
OUT PSUBDEVICE_DESCRIPTOR * OutDescriptor
)
{
PAGED_CODE();
ASSERT(pPcFilterDescriptor);
ASSERT(OutDescriptor);
NTSTATUS ntStatus = STATUS_SUCCESS;
//
// Calculate how much memory we will need.
//
PrivateHeap privateHeap;
privateHeap.Reserve(sizeof(SUBDEVICE_DESCRIPTOR));
privateHeap.Reserve(sizeof(KSTOPOLOGY));
privateHeap.Reserve(sizeof(KSPIN_DESCRIPTOR) * pPcFilterDescriptor->PinCount);
privateHeap.Reserve(sizeof(PIN_CINSTANCES) * pPcFilterDescriptor->PinCount);
privateHeap.Reserve(sizeof(PROPERTY_TABLE) * pPcFilterDescriptor->PinCount);
privateHeap.Reserve(sizeof(EVENT_TABLE) * pPcFilterDescriptor->PinCount);
if (pPcFilterDescriptor->NodeCount)
{
privateHeap.Reserve(sizeof(GUID) * pPcFilterDescriptor->NodeCount);
privateHeap.Reserve(sizeof(GUID) * pPcFilterDescriptor->NodeCount);
}
const PCPIN_DESCRIPTOR *pPcPinDescriptor = pPcFilterDescriptor->Pins;
for (ULONG ul = pPcFilterDescriptor->PinCount; ul--; )
{
if (pPcPinDescriptor->KsPinDescriptor.DataRanges)
{
MeasureDataRanges( &privateHeap,
pPcPinDescriptor->KsPinDescriptor.DataRangesCount,
pPcPinDescriptor->KsPinDescriptor.DataRanges );
pPcPinDescriptor = PPCPIN_DESCRIPTOR( PBYTE(pPcPinDescriptor) + pPcFilterDescriptor->PinSize );
}
else
{
ntStatus = STATUS_RANGE_NOT_FOUND; // DataRanges field is NULL
break; // Don't even bother, just exit
}
}
if (NT_SUCCESS(ntStatus)) // if fail above, fall through the rest
{
//
// Allocate the required memory.
//
ntStatus = privateHeap.AllocateFromPool(PagedPool,'pFcP');
}
if (NT_SUCCESS(ntStatus))
{
PSUBDEVICE_DESCRIPTOR descr = new(privateHeap) SUBDEVICE_DESCRIPTOR;
//
// Set up pointers into one big chunk of memory.
//
descr->PinCount = pPcFilterDescriptor->PinCount;
descr->Topology = new(privateHeap) KSTOPOLOGY;
descr->PinDescriptors = new(privateHeap) KSPIN_DESCRIPTOR[descr->PinCount];
descr->PinInstances = new(privateHeap) PIN_CINSTANCES[descr->PinCount];
descr->PinPropertyTables = new(privateHeap) PROPERTY_TABLE[descr->PinCount];
descr->PinEventTables = new(privateHeap) EVENT_TABLE[descr->PinCount];
if (pPcFilterDescriptor->NodeCount)
{
descr->Topology->TopologyNodes =
new(privateHeap) GUID[pPcFilterDescriptor->NodeCount];
descr->Topology->TopologyNodesNames =
new(privateHeap) GUID[pPcFilterDescriptor->NodeCount];
}
else
{
descr->Topology->TopologyNodes = NULL;
descr->Topology->TopologyNodesNames = NULL;
}
//
// Prefer the categories from the filter descriptor.
//
if (pPcFilterDescriptor->CategoryCount != 0)
{
descr->Topology->CategoriesCount = pPcFilterDescriptor->CategoryCount;
descr->Topology->Categories = pPcFilterDescriptor->Categories;
}
else
{
descr->Topology->CategoriesCount = CategoriesCount;
descr->Topology->Categories = Categories;
}
descr->Topology->TopologyNodesCount = pPcFilterDescriptor->NodeCount;
descr->Topology->TopologyConnectionsCount = pPcFilterDescriptor->ConnectionCount;
descr->Topology->TopologyConnections = pPcFilterDescriptor->Connections;
//
// Initialize filter properties.
//
descr->FilterPropertyTable.PropertySetCount = FilterPropertySetCount;
descr->FilterPropertyTable.PropertySets = FilterPropertySets;
descr->FilterPropertyTable.StaticSets = TRUE;
//
// Initialize filter events.
//
descr->FilterEventTable.EventSetCount = FilterEventSetCount;
descr->FilterEventTable.EventSets = FilterEventSets;
descr->FilterEventTable.StaticSets = TRUE;
//
// Copy node type and name and merge node properties and events.
//
const PCNODE_DESCRIPTOR *pPcNodeDescriptor = pPcFilterDescriptor->Nodes;
GUID *pGuidType = (GUID *) descr->Topology->TopologyNodes;
GUID *pGuidName = (GUID *) descr->Topology->TopologyNodesNames;
for (ULONG node = pPcFilterDescriptor->NodeCount; node--; )
{
*pGuidType++ = *pPcNodeDescriptor->Type;
if (pPcNodeDescriptor->Name)
{
*pGuidName++ = *pPcNodeDescriptor->Name;
}
else
{
*pGuidName++ = *pPcNodeDescriptor->Type;
}
if ( (pPcNodeDescriptor->AutomationTable)
&& (pPcNodeDescriptor->AutomationTable->PropertyCount)
)
{
PcAddToPropertyTable
(
&descr->FilterPropertyTable,
pPcNodeDescriptor->AutomationTable->PropertyCount,
pPcNodeDescriptor->AutomationTable->Properties,
pPcNodeDescriptor->AutomationTable->PropertyItemSize,
TRUE
);
}
if ( (pPcNodeDescriptor->AutomationTable)
&& (pPcNodeDescriptor->AutomationTable->EventCount)
)
{
PcAddToEventTable
(
&descr->FilterEventTable,
pPcNodeDescriptor->AutomationTable->EventCount,
pPcNodeDescriptor->AutomationTable->Events,
pPcNodeDescriptor->AutomationTable->EventItemSize,
TRUE
);
}
pPcNodeDescriptor =
PPCNODE_DESCRIPTOR
( PBYTE(pPcNodeDescriptor) + pPcFilterDescriptor->NodeSize
);
}
//
// Merge filter properties.
//
if ( (pPcFilterDescriptor->AutomationTable)
&& (pPcFilterDescriptor->AutomationTable->PropertyCount)
)
{
PcAddToPropertyTable
(
&descr->FilterPropertyTable,
pPcFilterDescriptor->AutomationTable->PropertyCount,
pPcFilterDescriptor->AutomationTable->Properties,
pPcFilterDescriptor->AutomationTable->PropertyItemSize,
FALSE
);
}
//
// Merge filter events.
//
if ( (pPcFilterDescriptor->AutomationTable)
&& (pPcFilterDescriptor->AutomationTable->EventCount)
)
{
PcAddToEventTable
(
&descr->FilterEventTable,
pPcFilterDescriptor->AutomationTable->EventCount,
pPcFilterDescriptor->AutomationTable->Events,
pPcFilterDescriptor->AutomationTable->EventItemSize,
FALSE
);
}
//
// Do per-pin stuff.
//
PPROPERTY_TABLE pt = descr->PinPropertyTables;
PEVENT_TABLE et = descr->PinEventTables;
PKSPIN_DESCRIPTOR p = descr->PinDescriptors;
PPIN_CINSTANCES i = descr->PinInstances;
pPcPinDescriptor = PPCPIN_DESCRIPTOR(pPcFilterDescriptor->Pins);
for
(
ULONG pin = 0;
pin < pPcFilterDescriptor->PinCount;
pin++
)
{
//
// Find a pin that has the same property set.
//
PPROPERTY_TABLE twinPt = descr->PinPropertyTables;
PPCPIN_DESCRIPTOR pPcPinDescriptorTwin =
PPCPIN_DESCRIPTOR(pPcFilterDescriptor->Pins);
for
(
ULONG twinPin = 0;
twinPin < pin;
twinPin++, twinPt++
)
{
if ( ( pPcPinDescriptor->AutomationTable
== pPcPinDescriptorTwin->AutomationTable
)
|| ( pPcPinDescriptor->AutomationTable
&& pPcPinDescriptorTwin->AutomationTable
&& ( pPcPinDescriptor->AutomationTable->PropertyCount
== pPcPinDescriptorTwin->AutomationTable->PropertyCount
)
&& ( pPcPinDescriptor->AutomationTable->Properties
== pPcPinDescriptorTwin->AutomationTable->Properties
)
&& ( pPcPinDescriptor->AutomationTable->PropertyItemSize
== pPcPinDescriptorTwin->AutomationTable->PropertyItemSize
)
)
)
{
*pt = *twinPt;
break;
}
pPcPinDescriptorTwin =
PPCPIN_DESCRIPTOR
( PBYTE(pPcPinDescriptorTwin) + pPcFilterDescriptor->PinSize
);
}
//
// Create a new table if we have to.
//
if (twinPin == pin)
{
pt->PropertySetCount = PinPropertySetCount;
pt->PropertySets = PinPropertySets;
pt->StaticSets = TRUE;
if ( (pPcPinDescriptor->AutomationTable)
&& (pPcPinDescriptor->AutomationTable->PropertyCount)
)
{
PcAddToPropertyTable
(
pt,
pPcPinDescriptor->AutomationTable->PropertyCount,
pPcPinDescriptor->AutomationTable->Properties,
pPcPinDescriptor->AutomationTable->PropertyItemSize,
FALSE
);
}
const PCNODE_DESCRIPTOR *pPcNodeDescriptor2 = pPcFilterDescriptor->Nodes;
for (ULONG node = pPcFilterDescriptor->NodeCount; node--; )
{
if ( (pPcNodeDescriptor2->AutomationTable)
&& (pPcNodeDescriptor2->AutomationTable->PropertyCount)
)
{
PcAddToPropertyTable
(
pt,
pPcNodeDescriptor2->AutomationTable->PropertyCount,
pPcNodeDescriptor2->AutomationTable->Properties,
pPcNodeDescriptor2->AutomationTable->PropertyItemSize,
TRUE
);
}
pPcNodeDescriptor2 =
PPCNODE_DESCRIPTOR
( PBYTE(pPcNodeDescriptor2) + pPcFilterDescriptor->NodeSize
);
}
}
pt++;
//
// Find a pin that has the same event set.
//
PEVENT_TABLE twinEt = descr->PinEventTables;
pPcPinDescriptorTwin = PPCPIN_DESCRIPTOR(pPcFilterDescriptor->Pins);
for
(
ULONG twinEPin = 0;
twinEPin < pin;
twinEPin++, twinEt++
)
{
if ( ( pPcPinDescriptor->AutomationTable
== pPcPinDescriptorTwin->AutomationTable
)
|| ( pPcPinDescriptor->AutomationTable
&& pPcPinDescriptorTwin->AutomationTable
&& ( pPcPinDescriptor->AutomationTable->EventCount
== pPcPinDescriptorTwin->AutomationTable->EventCount
)
&& ( pPcPinDescriptor->AutomationTable->Events
== pPcPinDescriptorTwin->AutomationTable->Events
)
&& ( pPcPinDescriptor->AutomationTable->EventItemSize
== pPcPinDescriptorTwin->AutomationTable->EventItemSize
)
)
)
{
*et = *twinEt;
break;
}
pPcPinDescriptorTwin =
PPCPIN_DESCRIPTOR
( PBYTE(pPcPinDescriptorTwin) + pPcFilterDescriptor->PinSize
);
}
//
// Create a new table if we have to.
//
if (twinEPin == pin)
{
et->EventSetCount = PinEventSetCount;
et->EventSets = PinEventSets;
et->StaticSets = TRUE;
if ( (pPcPinDescriptor->AutomationTable)
&& (pPcPinDescriptor->AutomationTable->EventCount)
)
{
PcAddToEventTable
(
et,
pPcPinDescriptor->AutomationTable->EventCount,
pPcPinDescriptor->AutomationTable->Events,
pPcPinDescriptor->AutomationTable->EventItemSize,
FALSE
);
}
const PCNODE_DESCRIPTOR *pPcNodeDescriptor2 = pPcFilterDescriptor->Nodes;
for( ULONG node = pPcFilterDescriptor->NodeCount; node--; )
{
if ( (pPcNodeDescriptor2->AutomationTable)
&& (pPcNodeDescriptor2->AutomationTable->EventCount)
)
{
PcAddToEventTable
(
et,
pPcNodeDescriptor2->AutomationTable->EventCount,
pPcNodeDescriptor2->AutomationTable->Events,
pPcNodeDescriptor2->AutomationTable->EventItemSize,
TRUE
);
}
pPcNodeDescriptor2 = PPCNODE_DESCRIPTOR( PBYTE(pPcNodeDescriptor2) + pPcFilterDescriptor->NodeSize );
}
}
et++;
//
// Copy the KS descriptor.
//
*p = pPcPinDescriptor->KsPinDescriptor;
//
// Provide default mediums if necessary.
//
if (p->Mediums == NULL)
{
p->MediumsCount = SIZEOF_ARRAY(PinMediums);
p->Mediums = PinMediums;
}
//
// Massage the data ranges.
//
p->DataRanges =
CloneDataRanges
(
privateHeap,
&p->DataRangesCount,
pPcPinDescriptor->KsPinDescriptor.DataRangesCount,
pPcPinDescriptor->KsPinDescriptor.DataRanges
);
//
// Provide default interfaces if necessary.
//
if ( (p->Communication & KSPIN_COMMUNICATION_BOTH)
&& (p->Interfaces == NULL)
)
{
p->InterfacesCount = StreamInterfacesCount;
p->Interfaces = StreamInterfaces;
}
p++;
i->FilterPossible = pPcPinDescriptor->MaxFilterInstanceCount;
i->FilterNecessary = pPcPinDescriptor->MinFilterInstanceCount;
i->GlobalPossible = pPcPinDescriptor->MaxGlobalInstanceCount;
i->GlobalCurrent = 0;
i++;
pPcPinDescriptor =
PPCPIN_DESCRIPTOR
( PBYTE(pPcPinDescriptor) + pPcFilterDescriptor->PinSize
);
}
*OutDescriptor = descr;
ASSERT(privateHeap.BytesRemaining() == 0);
}
return ntStatus;
}
/*****************************************************************************
* PcDeleteSubdeviceDescriptor()
*****************************************************************************
* Deletes a subdevice descriptor.
*/
PORTCLASSAPI
void
NTAPI
PcDeleteSubdeviceDescriptor
(
IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
)
{
//
// Free allocated memory for filter property and event tables.
//
PcFreePropertyTable(&pSubdeviceDescriptor->FilterPropertyTable);
PcFreeEventTable(&pSubdeviceDescriptor->FilterEventTable);
//
// Free allocated memory for pin property tables.
//
PPROPERTY_TABLE pPropertyTable = pSubdeviceDescriptor->PinPropertyTables;
for (ULONG ul = pSubdeviceDescriptor->PinCount; ul--; pPropertyTable++)
{
//
// Find and clear any references to the same property set.
//
for
( PPROPERTY_TABLE pPropertyTableTwin =
( pSubdeviceDescriptor->PinPropertyTables
+ ( pSubdeviceDescriptor->PinCount
- 1
)
)
; pPropertyTableTwin != pPropertyTable
; pPropertyTableTwin--
)
{
if
( pPropertyTableTwin->PropertySets
== pPropertyTable->PropertySets
)
{
pPropertyTableTwin->PropertySetCount = 0;
pPropertyTableTwin->PropertySets = NULL;
pPropertyTableTwin->StaticSets = TRUE;
pPropertyTableTwin->StaticItems = NULL;
}
}
PcFreePropertyTable(pPropertyTable);
}
//
// Free allocated memory for pin event tables.
//
PEVENT_TABLE pEventTable = pSubdeviceDescriptor->PinEventTables;
for (ul = pSubdeviceDescriptor->PinCount; ul--; pEventTable++)
{
//
// Find and clear any references to the same event set.
//
for
( PEVENT_TABLE pEventTableTwin =
( pSubdeviceDescriptor->PinEventTables
+ ( pSubdeviceDescriptor->PinCount
- 1
)
)
; pEventTableTwin != pEventTable
; pEventTableTwin--
)
{
if
( pEventTableTwin->EventSets
== pEventTable->EventSets
)
{
pEventTableTwin->EventSetCount = 0;
pEventTableTwin->EventSets = NULL;
pEventTableTwin->StaticSets = TRUE;
pEventTableTwin->StaticItems = NULL;
}
}
PcFreeEventTable(pEventTable);
}
//
// The rest is one big chunk.
//
delete [] PBYTE(pSubdeviceDescriptor);
}
/*****************************************************************************
* PcValidateConnectRequest()
*****************************************************************************
* Validate attempt to create a pin.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcValidateConnectRequest
( IN PIRP pIrp
, IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
, OUT PKSPIN_CONNECT * ppKsPinConnect
)
{
PAGED_CODE();
ASSERT(pIrp);
ASSERT(pSubdeviceDescriptor);
ASSERT(ppKsPinConnect);
NTSTATUS ntStatus =
KsValidateConnectRequest
( pIrp
, pSubdeviceDescriptor->PinCount
, pSubdeviceDescriptor->PinDescriptors
, ppKsPinConnect
);
return ntStatus;
}
/*****************************************************************************
* PcValidatePinCount()
*****************************************************************************
* Validate pin count.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcValidatePinCount
( IN ULONG ulPinId
, IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
, IN PULONG pulPinInstanceCounts
)
{
PAGED_CODE();
ASSERT(pSubdeviceDescriptor);
ASSERT(pulPinInstanceCounts);
NTSTATUS ntStatus = STATUS_SUCCESS;
if
( ( pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent
< pSubdeviceDescriptor->PinInstances[ulPinId].GlobalPossible
)
|| ( pulPinInstanceCounts[ulPinId]
< pSubdeviceDescriptor->PinInstances[ulPinId].FilterPossible
)
)
{
pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent++;
pulPinInstanceCounts[ulPinId]++;
_DbgPrintF( DEBUGLVL_VERBOSE,
( "Create pin %d: global=%d local=%d"
, ulPinId
, pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent
, pulPinInstanceCounts[ulPinId]
));
}
else
{
// TODO: What code?
ntStatus = STATUS_UNSUCCESSFUL;
}
return ntStatus;
}
/*****************************************************************************
* PcValidateDeviceContext()
*****************************************************************************
* Probes DeviceContext for writing.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcValidateDeviceContext
( IN PDEVICE_CONTEXT pDeviceContext,
IN PIRP pIrp
)
{
PAGED_CODE();
NTSTATUS ntStatus = STATUS_SUCCESS;
if (NULL == pDeviceContext)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcValidateDeviceContext : pDeviceContext = NULL"));
return STATUS_INVALID_PARAMETER;
}
// validate the pointers if we don't trust the client
//
/*
// ISSUE ALPERS 2000/12/20 - The Probe call is disabled because it always generates an exception.
// Therefore it is disabled.
if (KernelMode != pIrp->RequestorMode)
{
__try
{
ProbeForRead( pDeviceContext,
sizeof(*pDeviceContext),
sizeof(BYTE));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
ntStatus = GetExceptionCode();
_DbgPrintF(DEBUGLVL_TERSE, ("PcValidateDeviceContext : ProbeForWrite failed %X", ntStatus));
}
}
*/
if (NT_SUCCESS(ntStatus))
{
if (PORTCLS_DEVICE_EXTENSION_SIGNATURE != pDeviceContext->Signature )
{
ntStatus = STATUS_INVALID_PARAMETER;
_DbgPrintF(DEBUGLVL_TERSE, ("PcValidateDeviceContext : Invalid Extension Signature"));
}
}
return ntStatus;
} // PcValidateDeviceContext
/*****************************************************************************
* PcTerminateConnection()
*****************************************************************************
* Decrement instance counts associated with a pin.
*/
PORTCLASSAPI
void
NTAPI
PcTerminateConnection
( IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
, IN PULONG pulPinInstanceCounts
, IN ULONG ulPinId
)
{
PAGED_CODE();
ASSERT(pSubdeviceDescriptor);
ASSERT(pulPinInstanceCounts);
ASSERT(ulPinId <= pSubdeviceDescriptor->PinCount);
pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent--;
pulPinInstanceCounts[ulPinId]--;
_DbgPrintF( DEBUGLVL_VERBOSE,
( "Delete pin %d: global=%d local=%d"
, ulPinId
, pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent
, pulPinInstanceCounts[ulPinId]
));
}
/*****************************************************************************
* PcVerifyFilterIsReady()
*****************************************************************************
* Verify necessary pins are connected.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcVerifyFilterIsReady
( IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
, IN PULONG pulPinInstanceCounts
)
{
PAGED_CODE();
ASSERT(pSubdeviceDescriptor);
ASSERT(pulPinInstanceCounts);
NTSTATUS ntStatus = STATUS_SUCCESS;
for
( ULONG ulPinId = 0
; ulPinId < pSubdeviceDescriptor->PinCount
; ulPinId++
)
{
if
( pulPinInstanceCounts[ulPinId]
< pSubdeviceDescriptor->PinInstances[ulPinId].FilterNecessary
)
{
// TODO: What code?
ntStatus = STATUS_UNSUCCESSFUL;
break;
}
}
return ntStatus;
}
#define END_NONE 0
#define END_FROM 1
#define END_TO 2
#define END_BOTH 3
/*****************************************************************************
* FindConnectionToPin()
*****************************************************************************
* Find a connection that connects to a given node or filter pin.
*
* ulNode - node number of KSFILTER_NODE
* ulConnection - in: connection to start with
* out: found connection or ULONG(-1) if not found
*
* return - 0 for no connection found
* END_FROM for outgoing connection
* END_TO for incoming connection
*/
ULONG
FindConnectionToPin
(
IN ULONG ulNode,
IN ULONG ulPin,
IN PKSTOPOLOGY pKsTopology,
IN OUT PULONG ulConnection,
OUT PKSTOPOLOGY_CONNECTION * ppKsTopologyConnection OPTIONAL
)
{
ASSERT(pKsTopology);
ASSERT(ulConnection);
ASSERT(*ulConnection < pKsTopology->TopologyConnectionsCount);
ULONG ulEnd;
PKSTOPOLOGY_CONNECTION pKsTopologyConnection =
PKSTOPOLOGY_CONNECTION
(
&pKsTopology->TopologyConnections[*ulConnection]
);
while (1)
{
ASSERT(*ulConnection <= pKsTopology->TopologyConnectionsCount);
if (*ulConnection == pKsTopology->TopologyConnectionsCount)
{
ulEnd = END_NONE;
*ulConnection = ULONG(-1);
pKsTopologyConnection = NULL;
break;
}
else
if ( (pKsTopologyConnection->FromNode == ulNode)
&& (pKsTopologyConnection->FromNodePin == ulPin)
)
{
ulEnd = END_FROM;
break;
}
else
if ( (pKsTopologyConnection->ToNode == ulNode)
&& (pKsTopologyConnection->ToNodePin == ulPin)
)
{
ulEnd = END_TO;
break;
}
(*ulConnection)++;
pKsTopologyConnection++;
}
if (ppKsTopologyConnection)
{
*ppKsTopologyConnection = pKsTopologyConnection;
}
return ulEnd;
}
/*****************************************************************************
* FindConnectionToNode()
*****************************************************************************
* Find a connection that connects to a given node or to the filter.
*
* ulNode - node number of KSFILTER_NODE
* ulEnd - 0 for any direction
* END_FROM for outgoing connection
* END_TO for incoming connection
* ulConnection - in: connection to start with
* out: found connection or ULONG(-1) if not found
*
* return - 0 for no connection found
* END_FROM for outgoing connection
* END_TO for incoming connection
*/
ULONG
FindConnectionToNode
(
IN ULONG ulNode,
IN ULONG ulEnd,
IN PKSTOPOLOGY pKsTopology,
IN OUT PULONG ulConnection,
OUT PKSTOPOLOGY_CONNECTION * ppKsTopologyConnection OPTIONAL
)
{
ASSERT(pKsTopology);
ASSERT
( (ulNode == KSFILTER_NODE)
|| (ulNode < pKsTopology->TopologyNodesCount)
);
ASSERT(ulConnection);
ASSERT(*ulConnection < pKsTopology->TopologyConnectionsCount);
PKSTOPOLOGY_CONNECTION pKsTopologyConnection =
PKSTOPOLOGY_CONNECTION
(
&pKsTopology->TopologyConnections[*ulConnection]
);
while (1)
{
ASSERT(*ulConnection <= pKsTopology->TopologyConnectionsCount);
if (*ulConnection == pKsTopology->TopologyConnectionsCount)
{
ulEnd = END_NONE;
*ulConnection = ULONG(-1);
pKsTopologyConnection = NULL;
break;
}
else
if ( (pKsTopologyConnection->FromNode == ulNode)
&& (ulEnd != END_TO)
)
{
ulEnd = END_FROM;
break;
}
else
if ( (pKsTopologyConnection->ToNode == ulNode)
&& (ulEnd != END_FROM)
)
{
ulEnd = END_TO;
break;
}
(*ulConnection)++;
pKsTopologyConnection++;
}
if (ppKsTopologyConnection)
{
*ppKsTopologyConnection = pKsTopologyConnection;
}
return ulEnd;
}
/*****************************************************************************
* NodeIsTransform()
*****************************************************************************
* Determines if a node is a transform. KSFILTER_NODE is handled (FALSE).
*/
BOOLEAN
NodeIsTransform
(
IN ULONG ulNode,
IN PKSTOPOLOGY pKsTopology
)
{
ASSERT(pKsTopology);
ASSERT
( (ulNode == KSFILTER_NODE)
|| (ulNode < pKsTopology->TopologyNodesCount)
);
ULONG ulEnd = END_NONE;
if (ulNode != KSFILTER_NODE)
{
PKSTOPOLOGY_CONNECTION pKsTopologyConnection =
PKSTOPOLOGY_CONNECTION(pKsTopology->TopologyConnections);
for
(
ULONG ul = pKsTopology->TopologyConnectionsCount;
ul--;
pKsTopologyConnection++
)
{
if (pKsTopologyConnection->FromNode == ulNode)
{
ulEnd += END_FROM;
if ( (ulEnd != END_FROM)
&& (ulEnd != END_BOTH)
)
{
break;
}
}
if (pKsTopologyConnection->ToNode == ulNode)
{
ulEnd += END_TO;
if ( (ulEnd != END_TO)
&& (ulEnd != END_BOTH)
)
{
break;
}
}
}
}
return ulEnd == END_BOTH;
}
/*****************************************************************************
* NodeAtThisEnd()
*****************************************************************************
* Node at indicated end of the connection.
*/
inline
ULONG
NodeAtThisEnd
(
IN ULONG ulEnd,
IN PKSTOPOLOGY_CONNECTION pKsTopologyConnection
)
{
return
( (ulEnd == END_FROM)
? pKsTopologyConnection->FromNode
: pKsTopologyConnection->ToNode
);
}
/*****************************************************************************
* NodeAtOtherEnd()
*****************************************************************************
* Node at opposite end of the connection.
*/
inline
ULONG
NodeAtOtherEnd
(
IN ULONG ulEnd,
IN PKSTOPOLOGY_CONNECTION pKsTopologyConnection
)
{
return
( (ulEnd == END_FROM)
? pKsTopologyConnection->ToNode
: pKsTopologyConnection->FromNode
);
}
/*****************************************************************************
* PcCaptureFormat()
*****************************************************************************
* Capture a data format in an allocated buffer, possibly changing offensive
* formats.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcCaptureFormat
(
OUT PKSDATAFORMAT * ppKsDataFormatOut,
IN PKSDATAFORMAT pKsDataFormatIn,
IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor,
IN ULONG ulPinId
)
{
ASSERT(ppKsDataFormatOut);
ASSERT(pKsDataFormatIn);
ASSERT(pSubdeviceDescriptor);
ASSERT(ulPinId < pSubdeviceDescriptor->PinCount);
NTSTATUS ntStatus = STATUS_SUCCESS;
if( (pKsDataFormatIn->FormatSize >= sizeof(KSDATAFORMAT_DSOUND)) &&
IsEqualGUIDAligned( pKsDataFormatIn->MajorFormat, KSDATAFORMAT_TYPE_AUDIO ) &&
IsEqualGUIDAligned( pKsDataFormatIn->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND ) )
{
//
// This is the dread DSound format. Check to see if we have the
// required topology and convert to WaveFormatEx if we do.
//
// Note: DSound format does not have to be PCM....
//
PKSDATAFORMAT_DSOUND pKsDataFormatDSound =
PKSDATAFORMAT_DSOUND(pKsDataFormatIn);
//
// Fail if the client has asked for a software buffer.
//
if ( pKsDataFormatDSound->BufferDesc.Flags
& KSDSOUND_BUFFER_LOCSOFTWARE
)
{
_DbgPrintF(DEBUGLVL_TERSE,("PcCaptureFormat Failed because client requested software buffer."));
return STATUS_INVALID_PARAMETER;
}
//
// Find a connection involving the filter pin.
//
ULONG ulConnection = 0;
PKSTOPOLOGY_CONNECTION pKsTopologyConnection;
ULONG ulEnd =
FindConnectionToPin
(
KSFILTER_NODE,
ulPinId,
pSubdeviceDescriptor->Topology,
&ulConnection,
&pKsTopologyConnection
);
//
// Trace the topology until we find a non-transform or all the
// required nodes have been found. Position notification is
// always supported.
//
ULONG ulMissing =
( pKsDataFormatDSound->BufferDesc.Control
& ~KSDSOUND_BUFFER_CTRL_POSITIONNOTIFY
);
while (ulMissing && ulEnd)
{
//
// Found a connection. Follow the topology.
//
ULONG ulNode = NodeAtOtherEnd(ulEnd,pKsTopologyConnection);
if (! NodeIsTransform(ulNode,pSubdeviceDescriptor->Topology))
{
//
// The new node is not a simple transform (1 in, 1 out).
//
break;
}
//
// Drop 'missing' bits as appropriate based on the node GUID.
//
ASSERT(ulNode < pSubdeviceDescriptor->Topology->TopologyNodesCount);
const GUID *pGuid = &pSubdeviceDescriptor->Topology->TopologyNodes[ulNode];
if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_3D_EFFECTS))
{
ulMissing &=~ KSDSOUND_BUFFER_CTRL_3D;
}
else
if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_SRC))
{
ulMissing &=~ KSDSOUND_BUFFER_CTRL_FREQUENCY;
}
else
if ( IsEqualGUIDAligned(*pGuid,KSNODETYPE_SUPERMIX)
|| IsEqualGUIDAligned(*pGuid,KSNODETYPE_VOLUME)
)
{
ulMissing &=~ KSDSOUND_BUFFER_CTRL_PAN;
ulMissing &=~ KSDSOUND_BUFFER_CTRL_VOLUME;
}
//
// Find the next connection in line.
//
ulConnection = 0;
ulEnd =
FindConnectionToNode
(
ulNode,
ulEnd,
pSubdeviceDescriptor->Topology,
&ulConnection,
&pKsTopologyConnection
);
}
//
// Make sure no nodes were missing.
//
if (! ulMissing)
{
//
// We have the capabilities required. Build the new format.
//
ULONG ulSize =
( sizeof(KSDATAFORMAT_WAVEFORMATEX)
+ ( pKsDataFormatIn->FormatSize
- sizeof(KSDATAFORMAT_DSOUND)
)
);
*ppKsDataFormatOut =
PKSDATAFORMAT
(
ExAllocatePoolWithTag
(
PagedPool,
ulSize,
'fDcP'
)
);
if (*ppKsDataFormatOut)
{
//
// Copy KSDATAFORMAT part.
//
RtlCopyMemory
(
*ppKsDataFormatOut,
pKsDataFormatIn,
sizeof(KSDATAFORMAT)
);
//
// Copy WAVEFORMATEX part including appended stuff.
//
RtlCopyMemory
(
*ppKsDataFormatOut + 1,
&pKsDataFormatDSound->BufferDesc.WaveFormatEx,
ulSize - sizeof(KSDATAFORMAT)
);
//
// Adjust size and specifier.
//
(*ppKsDataFormatOut)->FormatSize = ulSize;
(*ppKsDataFormatOut)->Specifier =
KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PcCaptureFormat Failed to allocate memory for format."));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PcCaptureFormat Failed due to lack of feature support (0x%08x).",ulMissing));
//
// Don't have the required nodes...fail.
//
ntStatus = STATUS_INVALID_PARAMETER;
}
}
else
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PcCaptureFormat Format captured as-is."));
//
// Some other format. Just capture it.
//
*ppKsDataFormatOut = PKSDATAFORMAT(ExAllocatePoolWithTag(PagedPool,
pKsDataFormatIn->FormatSize,
'fDcP'));
if (*ppKsDataFormatOut)
{
RtlCopyMemory
(
*ppKsDataFormatOut,
pKsDataFormatIn,
pKsDataFormatIn->FormatSize
);
}
else
{
_DbgPrintF(DEBUGLVL_TERSE,("PcCaptureFormat Failed to allocate memory for format."));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
// check to verify SampleSize is set properly on waveformatex formats
if( NT_SUCCESS(ntStatus) &&
(pKsDataFormatIn->FormatSize >= sizeof(KSDATAFORMAT_WAVEFORMATEX)) &&
IsEqualGUIDAligned((*ppKsDataFormatOut)->MajorFormat,KSDATAFORMAT_TYPE_AUDIO) &&
IsEqualGUIDAligned((*ppKsDataFormatOut)->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
{
PKSDATAFORMAT_WAVEFORMATEX pWaveFormat = PKSDATAFORMAT_WAVEFORMATEX(*ppKsDataFormatOut);
if( 0 == pWaveFormat->DataFormat.SampleSize )
{
pWaveFormat->DataFormat.SampleSize = pWaveFormat->WaveFormatEx.nBlockAlign;
}
}
return ntStatus;
}
/*****************************************************************************
* PcAcquireFormatResources()
*****************************************************************************
* Acquire resources specified in a format.
*/
PORTCLASSAPI
void
NTAPI
PcAcquireFormatResources
(
IN PKSDATAFORMAT pKsDataFormatIn,
IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor,
IN ULONG ulPinId,
IN PPROPERTY_CONTEXT pPropertyContext
)
{
ASSERT(pKsDataFormatIn);
ASSERT(pSubdeviceDescriptor);
ASSERT(ulPinId < pSubdeviceDescriptor->PinCount);
ASSERT(pPropertyContext);
KSP_NODE ksPNode;
ksPNode.Property.Set = KSPROPSETID_TopologyNode;
ksPNode.Property.Id = KSPROPERTY_TOPOLOGYNODE_ENABLE;
ksPNode.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
ksPNode.NodeId = 0; // Fill in later
ksPNode.Reserved = 0;
if ( (pKsDataFormatIn->FormatSize >= sizeof(KSDATAFORMAT_DSOUND))
&& IsEqualGUIDAligned
( pKsDataFormatIn->MajorFormat,
KSDATAFORMAT_TYPE_AUDIO
)
&& IsEqualGUIDAligned
( pKsDataFormatIn->Specifier,
KSDATAFORMAT_SPECIFIER_DSOUND
)
)
{
//
// This is the dreaded DSound format. Turn on all the nodes
// that are specified in the caps bits.
//
PKSDATAFORMAT_DSOUND pKsDataFormatDSound =
PKSDATAFORMAT_DSOUND(pKsDataFormatIn);
//
// Find a connection involving the filter pin.
//
ULONG ulConnection = 0;
PKSTOPOLOGY_CONNECTION pKsTopologyConnection;
ULONG ulEnd =
FindConnectionToPin
(
KSFILTER_NODE,
ulPinId,
pSubdeviceDescriptor->Topology,
&ulConnection,
&pKsTopologyConnection
);
//
// Trace the topology until we find a non-transform or all the
// required nodes have been found. Position notification is
// always supported.
//
ULONG ulMissing =
( pKsDataFormatDSound->BufferDesc.Control
& ( KSDSOUND_BUFFER_CTRL_3D
| KSDSOUND_BUFFER_CTRL_FREQUENCY
)
);
while (ulMissing && ulEnd)
{
//
// Found a connection. Follow the topology.
//
ULONG ulNode = NodeAtOtherEnd(ulEnd,pKsTopologyConnection);
if (! NodeIsTransform(ulNode,pSubdeviceDescriptor->Topology))
{
//
// The new node is not a simple transform (1 in, 1 out).
//
break;
}
//
// Turn on nodes as appropriate based on the node GUID.
//
ASSERT(ulNode < pSubdeviceDescriptor->Topology->TopologyNodesCount);
const GUID *pGuid = &pSubdeviceDescriptor->Topology->TopologyNodes[ulNode];
if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_3D_EFFECTS))
{
if (ulMissing & KSDSOUND_BUFFER_CTRL_3D)
{
//
// Turn on the 3D node.
//
ULONG ulPropertyValue = TRUE;
ULONG ulPropertyValueSize = sizeof(ULONG);
ksPNode.NodeId = ulNode;
PcDispatchProperty
( NULL // pIrp
, pPropertyContext
, NULL // pKsPropertySet
, sizeof(KSP_NODE)
, &ksPNode.Property
, &ulPropertyValueSize
, &ulPropertyValue
);
ulMissing &=~ KSDSOUND_BUFFER_CTRL_3D;
}
}
else
if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_SRC))
{
if (ulMissing & KSDSOUND_BUFFER_CTRL_FREQUENCY)
{
//
// Turn on the SRC node.
//
ULONG ulPropertyValue = TRUE;
ULONG ulPropertyValueSize = sizeof(ULONG);
ksPNode.NodeId = ulNode;
PcDispatchProperty
( NULL // pIrp
, pPropertyContext
, NULL // pKsPropertySet
, sizeof(KSP_NODE)
, &ksPNode.Property
, &ulPropertyValueSize
, &ulPropertyValue
);
ulMissing &=~ KSDSOUND_BUFFER_CTRL_FREQUENCY;
}
}
//
// Find the next connection in line.
//
ulConnection = 0;
ulEnd =
FindConnectionToNode
(
ulNode,
ulEnd,
pSubdeviceDescriptor->Topology,
&ulConnection,
&pKsTopologyConnection
);
}
}
}
#pragma code_seg()
/*****************************************************************************
* PcRegisterIoTimeout()
*****************************************************************************
* Registers an IoTimeout callback.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcRegisterIoTimeout
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIO_TIMER_ROUTINE pTimerRoutine,
IN PVOID pContext
)
{
KIRQL OldIrql;
PTIMEOUTCALLBACK TimeoutCallback;
NTSTATUS ntStatus = STATUS_SUCCESS;
ASSERT(pDeviceObject);
ASSERT(pTimerRoutine);
ASSERT( PASSIVE_LEVEL == KeGetCurrentIrql() );
//
// Validate Parameters.
//
if (NULL == pDeviceObject ||
NULL == pTimerRoutine ||
NULL == pDeviceObject->DeviceExtension)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterIoTimeout : Invalid Parameter"));
return STATUS_INVALID_PARAMETER;
}
// get the device context
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
// allocate a timeout callback structure -- 'PcTc'
TimeoutCallback = PTIMEOUTCALLBACK(ExAllocatePoolWithTag( NonPagedPool, sizeof(TIMEOUTCALLBACK),'cTcP' ));
if( TimeoutCallback )
{
// initialize the entry
TimeoutCallback->TimerRoutine = pTimerRoutine;
TimeoutCallback->Context = pContext;
// grab the list spin lock
KeAcquireSpinLock( &(pDeviceContext->TimeoutLock), &OldIrql );
// walk the list to see if the entry is already registered
if( !IsListEmpty( &(pDeviceContext->TimeoutList) ) )
{
PLIST_ENTRY ListEntry;
PTIMEOUTCALLBACK pCallback;
for( ListEntry = pDeviceContext->TimeoutList.Flink;
ListEntry != &(pDeviceContext->TimeoutList);
ListEntry = ListEntry->Flink )
{
pCallback = (PTIMEOUTCALLBACK) CONTAINING_RECORD( ListEntry,
TIMEOUTCALLBACK,
ListEntry );
if( (pCallback->TimerRoutine == pTimerRoutine) &&
(pCallback->Context == pContext) )
{
// entry already exists in the list, so fail this request
ntStatus = STATUS_UNSUCCESSFUL;
}
}
}
if( NT_SUCCESS(ntStatus) )
{
// add the entry to the list
InsertTailList( &(pDeviceContext->TimeoutList), &(TimeoutCallback->ListEntry) );
}
else
{
// free the entry
ExFreePool( TimeoutCallback );
}
// release the spin lock
KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
return ntStatus;
}
/*****************************************************************************
* PcUnregisterIoTimeout()
*****************************************************************************
* Unregisters an IoTimeout callback.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcUnregisterIoTimeout
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIO_TIMER_ROUTINE pTimerRoutine,
IN PVOID pContext
)
{
KIRQL OldIrql;
ASSERT(pDeviceObject);
ASSERT(pTimerRoutine);
ASSERT( PASSIVE_LEVEL == KeGetCurrentIrql() );
//
// Validate Parameters.
//
if (NULL == pDeviceObject ||
NULL == pTimerRoutine ||
NULL == pDeviceObject->DeviceExtension)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcUnregisterIoTimeout : Invalid Parameter"));
return STATUS_INVALID_PARAMETER;
}
// get the device context
PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
// grab the spin lock
KeAcquireSpinLock( &(pDeviceContext->TimeoutLock), &OldIrql );
// walk the list
if( !IsListEmpty( &(pDeviceContext->TimeoutList) ) )
{
PLIST_ENTRY ListEntry;
PTIMEOUTCALLBACK pCallback;
for( ListEntry = pDeviceContext->TimeoutList.Flink;
ListEntry != &(pDeviceContext->TimeoutList);
ListEntry = ListEntry->Flink )
{
pCallback = (PTIMEOUTCALLBACK) CONTAINING_RECORD( ListEntry,
TIMEOUTCALLBACK,
ListEntry );
if( (pCallback->TimerRoutine == pTimerRoutine) &&
(pCallback->Context == pContext) )
{
RemoveEntryList(ListEntry);
KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
ExFreePool(pCallback);
return STATUS_SUCCESS;
}
}
}
// release the spinlock
KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
return STATUS_NOT_FOUND;
}