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.
 
 
 
 
 
 

1521 lines
48 KiB

/*****************************************************************************
* property.cpp - property support
*****************************************************************************
* Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
*/
#include "private.h"
/*****************************************************************************
* Functions
*/
#pragma code_seg("PAGE")
/*****************************************************************************
* PcHandlePropertyWithTable()
*****************************************************************************
* Uses a property table to handle a property request IOCTL.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcHandlePropertyWithTable
( IN PIRP pIrp
, IN ULONG ulPropertySetsCount
, IN const KSPROPERTY_SET* pKsPropertySet
, IN PPROPERTY_CONTEXT pPropertyContext
)
{
ASSERT(pIrp);
ASSERT(pPropertyContext);
pIrp->Tail.Overlay.DriverContext[3] = pPropertyContext;
NTSTATUS ntStatus =
KsPropertyHandler
(
pIrp,
ulPropertySetsCount,
pKsPropertySet
);
return ntStatus;
}
/*****************************************************************************
* PcDispatchProperty()
*****************************************************************************
* Dispatch a property via a PCPROPERTY_ITEM entry.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcDispatchProperty
(
IN PIRP pIrp OPTIONAL,
IN PPROPERTY_CONTEXT pPropertyContext,
IN const KSPROPERTY_SET * pKsPropertySet OPTIONAL,
IN ULONG ulIdentifierSize,
IN PKSIDENTIFIER pKsIdentifier,
IN OUT PULONG pulDataSize,
IN OUT PVOID pvData OPTIONAL
)
{
PAGED_CODE();
ASSERT(pPropertyContext);
ASSERT(pKsIdentifier);
ASSERT(pulDataSize);
PPCPROPERTY_REQUEST pPcPropertyRequest =
new(NonPagedPool,'rPcP') PCPROPERTY_REQUEST;
NTSTATUS ntStatus;
if (! pPcPropertyRequest)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
//
// Copy target information from the context structure.
//
pPcPropertyRequest->MajorTarget =
pPropertyContext->pUnknownMajorTarget;
pPcPropertyRequest->MinorTarget =
pPropertyContext->pUnknownMinorTarget;
pPcPropertyRequest->Node =
pPropertyContext->ulNodeId;
//
// Determine the value size.
//
pPcPropertyRequest->ValueSize = *pulDataSize;
//
// If the node number is in the instance data, extract it.
// TODO: Remove this when node objects rule.
//
if ( (pKsIdentifier->Flags & KSPROPERTY_TYPE_TOPOLOGY)
&& (pPcPropertyRequest->Node == ULONG(-1))
)
{
//
// Get the node id and remaining instance.
//
if (ulIdentifierSize < sizeof(KSP_NODE))
{
delete pPcPropertyRequest;
return STATUS_INVALID_BUFFER_SIZE;
}
PKSP_NODE pKsPNode = PKSP_NODE(pKsIdentifier);
pPcPropertyRequest->Node = pKsPNode->NodeId;
pPcPropertyRequest->InstanceSize =
ulIdentifierSize - sizeof(KSP_NODE);
pPcPropertyRequest->Instance =
( (pPcPropertyRequest->InstanceSize == 0)
? NULL
: PVOID(pKsPNode + 1)
);
}
else
{
//
// No node in the instance...get generic instance if any.
//
pPcPropertyRequest->InstanceSize =
ulIdentifierSize - sizeof(KSIDENTIFIER);
pPcPropertyRequest->Instance =
( (pPcPropertyRequest->InstanceSize == 0)
? NULL
: PVOID(pKsIdentifier + 1)
);
}
if (pKsPropertySet)
{
ASSERT(pKsPropertySet->PropertyItem);
//
// Find the property item in the KS-style list.
//
#if (DBG)
ULONG dbgCount = pKsPropertySet->PropertiesCount;
#endif
for
( const KSPROPERTY_ITEM *pKsPropertyItem =
pKsPropertySet->PropertyItem
; pKsPropertyItem->PropertyId != pKsIdentifier->Id
; pKsPropertyItem++
)
{
ASSERT(--dbgCount);
}
//
// The property item is stashed in the Relations field if this is not
// a node property. If it is, we have to find the node property in
// the original list.
//
pPcPropertyRequest->PropertyItem =
PPCPROPERTY_ITEM(pKsPropertyItem->Relations);
}
else
{
//
// No KS set was supplied. We need to look in the original list
// associated with the node.
//
pPcPropertyRequest->PropertyItem = NULL;
}
if (! pPcPropertyRequest->PropertyItem)
{
PPCFILTER_DESCRIPTOR pPcFilterDescriptor =
pPropertyContext->pPcFilterDescriptor;
if ( pPcFilterDescriptor
&& ( pPcPropertyRequest->Node
< pPcFilterDescriptor->NodeCount
)
&& pPcFilterDescriptor->
Nodes[pPcPropertyRequest->Node].AutomationTable
)
{
//
// Valid node...search the original property item list.
//
const PCAUTOMATION_TABLE *pPcAutomationTable =
pPcFilterDescriptor->
Nodes[pPcPropertyRequest->Node].AutomationTable;
const PCPROPERTY_ITEM *pPcPropertyItem =
pPcAutomationTable->Properties;
for (ULONG ul = pPcAutomationTable->PropertyCount; ul--; )
{
if ( IsEqualGUIDAligned
( *pPcPropertyItem->Set
, pKsIdentifier->Set
)
&& (pPcPropertyItem->Id == pKsIdentifier->Id)
)
{
pPcPropertyRequest->PropertyItem = pPcPropertyItem;
break;
}
pPcPropertyItem =
PPCPROPERTY_ITEM
( PBYTE(pPcPropertyItem)
+ pPcAutomationTable->PropertyItemSize
);
}
}
else
{
//
// The node ID was invalid.
//
ntStatus = STATUS_NOT_FOUND;
}
}
//
// Call the handler if we have a property item with a handler.
//
if ( pPcPropertyRequest->PropertyItem
&& pPcPropertyRequest->PropertyItem->Handler
)
{
pPcPropertyRequest->Verb = pKsIdentifier->Flags;
pPcPropertyRequest->Value = pvData;
pPcPropertyRequest->Irp = pIrp;
//
// Call the handler.
//
ntStatus =
pPcPropertyRequest->PropertyItem->Handler
(
pPcPropertyRequest
);
*pulDataSize = pPcPropertyRequest->ValueSize;
}
else
{
ntStatus = STATUS_NOT_FOUND;
}
//
// Delete the request structure unless we are pending.
//
if (ntStatus != STATUS_PENDING)
{
delete pPcPropertyRequest;
}
else
{
//
// Only requests with IRPs can be pending.
//
ASSERT(pIrp);
}
}
return ntStatus;
}
/*****************************************************************************
* PropertyItemPropertyHandler()
*****************************************************************************
* KS-sytle property handler that handles all properties using the
* PCPROPERTY_ITEM mechanism.
*/
NTSTATUS
PropertyItemPropertyHandler
(
IN PIRP pIrp,
IN PKSIDENTIFIER pKsIdentifier,
IN OUT PVOID pvData OPTIONAL
)
{
PAGED_CODE();
ASSERT(pIrp);
ASSERT(pKsIdentifier);
//
// Extract various things from the IRP and dispatch the property.
//
PIO_STACK_LOCATION irpSp =
IoGetCurrentIrpStackLocation(pIrp);
ULONG ulDataSize =
irpSp->Parameters.DeviceIoControl.OutputBufferLength;
NTSTATUS ntStatus =
PcDispatchProperty
( pIrp
, PPROPERTY_CONTEXT(pIrp->Tail.Overlay.DriverContext[3])
, KSPROPERTY_SET_IRP_STORAGE(pIrp)
, irpSp->Parameters.DeviceIoControl.InputBufferLength
, pKsIdentifier
, &ulDataSize
, pvData
);
//
// Inform the caller of the resulting status and size.
// Pending IRPs must be IoMarkIrpPending()ed before the dispatch routine
// returns.
//
if ((ntStatus != STATUS_PENDING) && !NT_ERROR(ntStatus))
{
pIrp->IoStatus.Information = ulDataSize;
}
return ntStatus;
}
/*****************************************************************************
* PcCompletePendingPropertyRequest()
*****************************************************************************
* Completes a pending property request.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcCompletePendingPropertyRequest
(
IN PPCPROPERTY_REQUEST PropertyRequest,
IN NTSTATUS NtStatus
)
{
ASSERT(PropertyRequest);
ASSERT(NtStatus != STATUS_PENDING);
//
// Validate Parameters.
//
if (NULL == PropertyRequest)
{
_DbgPrintF(DEBUGLVL_TERSE, ("PcCompletePendingPropertyRequest : Invalid Parameter."));
return STATUS_INVALID_PARAMETER;
}
if (!NT_ERROR(NtStatus))
{
PropertyRequest->Irp->IoStatus.Information =
PropertyRequest->ValueSize;
}
PropertyRequest->Irp->IoStatus.Status = NtStatus;
IoCompleteRequest(PropertyRequest->Irp,IO_NO_INCREMENT);
delete PropertyRequest;
return STATUS_SUCCESS;
}
/*****************************************************************************
* PcFreePropertyTable()
*****************************************************************************
* Frees allocated memory in a PROPERTY_TABLE structure.
*/
PORTCLASSAPI
void
NTAPI
PcFreePropertyTable
(
IN PPROPERTY_TABLE PropertyTable
)
{
_DbgPrintF(DEBUGLVL_VERBOSE,("PcFreePropertyTable"));
PAGED_CODE();
ASSERT(PropertyTable);
ASSERT((!PropertyTable->PropertySets) == (!PropertyTable->PropertySetCount));
// PropertySets and PropertySetCount must be non-NULL/non-zero, or NULL/zero
ASSERT(PropertyTable->StaticSets == (!PropertyTable->StaticItems));
// StaticSets and StaticItems must be TRUE/NULL, or FALSE/non-null
PBOOLEAN staticItem = PropertyTable->StaticItems;
if (staticItem)
{
PKSPROPERTY_SET propertySet = PropertyTable->PropertySets;
if (propertySet)
{
for( ULONG count = PropertyTable->PropertySetCount;
count--;
propertySet++, staticItem++)
{
if ((! *staticItem) && propertySet->PropertyItem)
{
ExFreePool(PVOID(propertySet->PropertyItem));
}
}
}
ExFreePool(PropertyTable->StaticItems);
PropertyTable->StaticItems = NULL;
}
if (PropertyTable->PropertySets && !PropertyTable->StaticSets)
{
PropertyTable->PropertySetCount = 0;
ExFreePool(PropertyTable->PropertySets);
PropertyTable->PropertySets = NULL;
}
PropertyTable->StaticSets = TRUE;
}
/*****************************************************************************
* PcAddToPropertyTable()
*****************************************************************************
* Adds a PROPERTY_ITEM property table to a PROPERTY_TABLE structure.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcAddToPropertyTable
(
IN OUT PPROPERTY_TABLE PropertyTable,
IN ULONG PropertyItemCount,
IN const PCPROPERTY_ITEM * PropertyItems,
IN ULONG PropertyItemSize,
IN BOOLEAN NodeTable
)
{
PAGED_CODE();
ASSERT(PropertyTable);
ASSERT(PropertyItems);
ASSERT(PropertyItemSize >= sizeof(PCPROPERTY_ITEM));
_DbgPrintF(DEBUGLVL_VERBOSE,("PcAddToEventTable"));
#define ADVANCE(item) (item = PPCPROPERTY_ITEM(PBYTE(item) + PropertyItemSize))
ASSERT((!PropertyTable->PropertySets) == (!PropertyTable->PropertySetCount));
// values must be non-NULL/non-zero, or NULL/zero.
//
// Determine how many sets we will end up with.
//
ULONG setCount = PropertyTable->PropertySetCount;
const PCPROPERTY_ITEM *item = PropertyItems;
for (ULONG count = PropertyItemCount; count--; ADVANCE(item))
{
BOOLEAN countThis = TRUE;
//
// See if it's already in the table.
//
PKSPROPERTY_SET propertySet = PropertyTable->PropertySets;
for
( ULONG count2 = PropertyTable->PropertySetCount;
count2--;
propertySet++
)
{
if (IsEqualGUIDAligned(*item->Set,*propertySet->Set))
{
countThis = FALSE;
break;
}
}
if (countThis)
{
//
// See if it's appeared in the list previously.
//
for
(
const PCPROPERTY_ITEM *prevItem = PropertyItems;
prevItem != item;
ADVANCE(prevItem)
)
{
if (IsEqualGUIDAligned(*item->Set,*prevItem->Set))
{
countThis = FALSE;
break;
}
}
}
if (countThis)
{
setCount++;
}
}
NTSTATUS ntStatus = STATUS_SUCCESS;
//
// Make a new set table
//
ASSERT(setCount);
ASSERT(setCount >= PropertyTable->PropertySetCount);
//
// Allocate memory required for the set table.
//
PKSPROPERTY_SET newTable =
PKSPROPERTY_SET
(
ExAllocatePoolWithTag
(
PagedPool,
sizeof(KSPROPERTY_SET) * setCount,
'tScP'
)
);
//
// Allocate memory for the static items flags.
//
PBOOLEAN newStaticItems = NULL;
if (newTable)
{
newStaticItems =
PBOOLEAN
(
ExAllocatePoolWithTag
(
PagedPool,
sizeof(BOOLEAN) * setCount,
'bScP'
)
);
if (! newStaticItems)
{
ExFreePool(newTable);
newTable = NULL;
}
}
if (newTable)
{
//
// Initialize the new set table.
//
RtlZeroMemory
(
PVOID(newTable),
sizeof(KSPROPERTY_SET) * setCount
);
if (PropertyTable->PropertySetCount != 0)
{
RtlCopyMemory
(
PVOID(newTable),
PVOID(PropertyTable->PropertySets),
sizeof(KSPROPERTY_SET) * PropertyTable->PropertySetCount
);
}
//
// Initialize the new static items flags.
//
RtlFillMemory
(
PVOID(newStaticItems),
sizeof(BOOLEAN) * setCount,
0xff
);
if (PropertyTable->StaticItems && PropertyTable->PropertySetCount)
{
//
// Flags existed before...copy them.
//
RtlCopyMemory
(
PVOID(newStaticItems),
PVOID(PropertyTable->StaticItems),
sizeof(BOOLEAN) * PropertyTable->PropertySetCount
);
}
//
// Assign set GUIDs to the new set entries.
//
PKSPROPERTY_SET addHere =
newTable + PropertyTable->PropertySetCount;
const PCPROPERTY_ITEM *item2 = PropertyItems;
for (ULONG count = PropertyItemCount; count--; ADVANCE(item2))
{
BOOLEAN addThis = TRUE;
//
// See if it's already in the table.
//
for( PKSPROPERTY_SET propertySet = newTable;
propertySet != addHere;
propertySet++)
{
if (IsEqualGUIDAligned(*item2->Set,*propertySet->Set))
{
addThis = FALSE;
break;
}
}
if (addThis)
{
addHere->Set = item2->Set;
addHere++;
}
}
ASSERT(addHere == newTable + setCount);
//
// Free old allocated tables.
//
if (PropertyTable->PropertySets && (!PropertyTable->StaticSets))
{
ExFreePool(PropertyTable->PropertySets);
}
if (PropertyTable->StaticItems)
{
ExFreePool(PropertyTable->StaticItems);
}
//
// Install the new tables.
//
PropertyTable->PropertySetCount = setCount;
PropertyTable->PropertySets = newTable;
PropertyTable->StaticSets = FALSE;
PropertyTable->StaticItems = newStaticItems;
}
else
{
// if allocations fail, return error and
// keep sets and items as they were.
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//
// Now we have a property set table that contains all the sets we need.
//
if (NT_SUCCESS(ntStatus))
{
//
// For each set...
//
PKSPROPERTY_SET propertySet = PropertyTable->PropertySets;
PBOOLEAN staticItem = PropertyTable->StaticItems;
for
( ULONG count = PropertyTable->PropertySetCount;
count--;
propertySet++, staticItem++
)
{
//
// Check to see how many new items we have.
//
ULONG itemCount = propertySet->PropertiesCount;
const PCPROPERTY_ITEM *item2 = PropertyItems;
for (ULONG count2 = PropertyItemCount; count2--; ADVANCE(item2))
{
if (IsEqualGUIDAligned(*item2->Set,*propertySet->Set))
{
itemCount++;
}
}
ASSERT(itemCount >= propertySet->PropertiesCount);
if (itemCount != propertySet->PropertiesCount)
{
//
// Allocate memory required for the items table.
//
PKSPROPERTY_ITEM newTable2 =
PKSPROPERTY_ITEM
(
ExAllocatePoolWithTag
(
PagedPool,
sizeof(KSPROPERTY_ITEM) * itemCount,
'iScP'
)
);
if (! newTable2)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// Initialize the table.
//
RtlZeroMemory
(
PVOID(newTable2),
sizeof(KSPROPERTY_ITEM) * itemCount
);
if (propertySet->PropertiesCount)
{
RtlCopyMemory
(
PVOID(newTable2),
PVOID(propertySet->PropertyItem),
sizeof(KSPROPERTY_ITEM) * propertySet->PropertiesCount
);
}
//
// Create the new items.
//
PKSPROPERTY_ITEM addHere =
newTable2 + propertySet->PropertiesCount;
item2 = PropertyItems;
for (count2 = PropertyItemCount; count2--; ADVANCE(item2))
{
if (IsEqualGUIDAligned(*item2->Set,*propertySet->Set))
{
addHere->PropertyId = item2->Id;
addHere->GetPropertyHandler =
( (item2->Flags & PCPROPERTY_ITEM_FLAG_GET)
? PropertyItemPropertyHandler
: NULL
);
addHere->MinProperty = sizeof(KSPROPERTY);
addHere->MinData = 0;
addHere->SetPropertyHandler =
( (item2->Flags & PCPROPERTY_ITEM_FLAG_SET)
? PropertyItemPropertyHandler
: NULL
);
addHere->Values = NULL;
addHere->RelationsCount = 0;
addHere->Relations =
( NodeTable
? NULL
: PKSPROPERTY(item2) // Secret hack!
);
addHere->SupportHandler =
( (item2->Flags & PCPROPERTY_ITEM_FLAG_BASICSUPPORT)
? PropertyItemPropertyHandler
: NULL
);
addHere->SerializedSize =
( (item2->Flags & PCPROPERTY_ITEM_FLAG_SERIALIZE)
? ULONG(-1)
: 0
);
addHere++;
}
}
ASSERT(addHere == newTable2 + itemCount);
//
// Free old allocated table.
//
if (propertySet->PropertyItem && ! *staticItem)
{
ExFreePool(PVOID(propertySet->PropertyItem));
}
//
// Install the new tables.
//
propertySet->PropertiesCount = itemCount;
propertySet->PropertyItem = newTable2;
*staticItem = FALSE;
}
}
}
return ntStatus;
}
/*****************************************************************************
* GenerateFormatFromRange()
*****************************************************************************
* Determine the particular format, based on the intersection of these
* two specific data ranges. First ask the miniport, then fall back to
* our own algorithm if the miniport doesn't handle it.
*/
NTSTATUS
GenerateFormatFromRange (
IN PIRP Irp,
IN ULONG PinId,
IN PKSDATARANGE MyDataRange,
IN PKSDATARANGE ClientDataRange,
IN ULONG OutputBufferLength,
OUT PVOID ResultantFormat OPTIONAL,
OUT PULONG ResultantFormatLength)
{
BOOLEAN bSpecifier;
NTSTATUS Status;
ULONG RequiredSize;
PPROPERTY_CONTEXT pPropertyContext = PPROPERTY_CONTEXT(Irp->Tail.Overlay.DriverContext[3]);
ASSERT(pPropertyContext);
PSUBDEVICE pSubdevice = pPropertyContext->pSubdevice;
ASSERT(pSubdevice);
//
// Give the miniport a chance to fill in the format structure
//
Status = pSubdevice->DataRangeIntersection (PinId,
ClientDataRange,
MyDataRange,
OutputBufferLength,
ResultantFormat,
ResultantFormatLength);
//
// return if the miniport filled out the structure.
//
if (Status != STATUS_NOT_IMPLEMENTED)
{
return Status;
}
//
// In case the miniport didn't implement the DataRangeIntersection,
// we provide a default handler here.
//
//
// Check if there is a wildcard somewhere.
//
if (IsEqualGUIDAligned (ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD) ||
IsEqualGUIDAligned (ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD) ||
IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD))
{
// If the miniport exposed a WILDCARD, then it must implement an
// intersection handler, because it must provide the specific
// ideal matching data range for that WILDCARD.
//
return STATUS_NO_MATCH;
}
if (!IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_NONE))
{
//
// The miniport did not resolve this format. Let's handle the specifiers
// that we know.
//
if (!IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND) &&
!IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
{
return STATUS_NO_MATCH;
}
bSpecifier = TRUE;
//
// The specifier here defines the format of ClientDataRange
// and the format expected to be returned in ResultantFormat.
//
if (IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
{
RequiredSize = sizeof (KSDATAFORMAT_DSOUND);
}
else
{
RequiredSize = sizeof (KSDATAFORMAT_WAVEFORMATEX);
}
}
else
{
bSpecifier = FALSE;
RequiredSize = sizeof (KSDATAFORMAT);
}
//
// Validate return buffer size, if the request is only for the
// size of the resultant structure, return it now.
//
if (!OutputBufferLength)
{
*ResultantFormatLength = RequiredSize;
return STATUS_BUFFER_OVERFLOW;
}
else if (OutputBufferLength < RequiredSize)
{
return STATUS_BUFFER_TOO_SMALL;
}
// There was a specifier ...
if (bSpecifier)
{
PKSDATARANGE_AUDIO myAudioRange,clientAudioRange;
PKSDATAFORMAT resultantFormat;
PWAVEFORMATEX resultantWaveFormatEx;
myAudioRange = (PKSDATARANGE_AUDIO) MyDataRange;
clientAudioRange = (PKSDATARANGE_AUDIO) ClientDataRange;
resultantFormat = (PKSDATAFORMAT)ResultantFormat;
//
// Fill out the dataformat and other general fields.
//
*resultantFormat = *ClientDataRange;
resultantFormat->FormatSize = RequiredSize;
*ResultantFormatLength = RequiredSize;
//
// Fill out the DSOUND specific structure
//
if (IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
{
PKSDATAFORMAT_DSOUND resultantDSoundFormat;
resultantDSoundFormat = (PKSDATAFORMAT_DSOUND)ResultantFormat;
_DbgPrintF (DEBUGLVL_VERBOSE, ("returning KSDATAFORMAT_DSOUND format intersection"));
//
// DSound format capabilities are not expressed
// this way in KS, so we express no capabilities.
//
resultantDSoundFormat->BufferDesc.Flags = 0 ;
resultantDSoundFormat->BufferDesc.Control = 0 ;
resultantWaveFormatEx = &resultantDSoundFormat->BufferDesc.WaveFormatEx;
}
else
{
_DbgPrintF (DEBUGLVL_VERBOSE, ("returning KSDATAFORMAT_WAVEFORMATEX format intersection"));
resultantWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT)ResultantFormat + 1);
}
//
// Return a format that intersects the given audio range,
// using our maximum support as the "best" format.
//
resultantWaveFormatEx->wFormatTag = WAVE_FORMAT_PCM;
resultantWaveFormatEx->nChannels = (USHORT) min (
myAudioRange->MaximumChannels,clientAudioRange->MaximumChannels);
resultantWaveFormatEx->nSamplesPerSec = min (
myAudioRange->MaximumSampleFrequency,clientAudioRange->MaximumSampleFrequency);
resultantWaveFormatEx->wBitsPerSample = (USHORT) min (
myAudioRange->MaximumBitsPerSample,clientAudioRange->MaximumBitsPerSample);
resultantWaveFormatEx->nBlockAlign = (resultantWaveFormatEx->wBitsPerSample * resultantWaveFormatEx->nChannels) / 8;
resultantWaveFormatEx->nAvgBytesPerSec = (resultantWaveFormatEx->nSamplesPerSec * resultantWaveFormatEx->nBlockAlign);
resultantWaveFormatEx->cbSize = 0;
((PKSDATAFORMAT) ResultantFormat)->SampleSize = resultantWaveFormatEx->nBlockAlign;
_DbgPrintF (DEBUGLVL_VERBOSE, ("Channels = %d", resultantWaveFormatEx->nChannels));
_DbgPrintF (DEBUGLVL_VERBOSE, ("Samples/sec = %d", resultantWaveFormatEx->nSamplesPerSec));
_DbgPrintF (DEBUGLVL_VERBOSE, ("Bits/sample = %d", resultantWaveFormatEx->wBitsPerSample));
}
else
{ // There was no specifier. Return only the KSDATAFORMAT structure.
//
// Copy the data format structure.
//
_DbgPrintF (DEBUGLVL_VERBOSE, ("returning default format intersection"));
RtlCopyMemory (ResultantFormat, ClientDataRange, sizeof (KSDATAFORMAT));
*ResultantFormatLength = sizeof (KSDATAFORMAT);
}
return STATUS_SUCCESS;
}
/*****************************************************************************
* ValidateTypeAndSpecifier()
*****************************************************************************
* Find the data range that best matches the client's data range, given our
* entire list of data ranges. This might include wildcard-based ranges.
*
*/
NTSTATUS
ValidateTypeAndSpecifier(
IN PIRP Irp,
IN ULONG PinId,
IN PKSDATARANGE ClientDataRange,
IN ULONG MyDataRangesCount,
IN const PKSDATARANGE * MyDataRanges,
IN ULONG OutputBufferLength,
OUT PVOID ResultantFormat,
OUT PULONG ResultantFormatLength
)
{
NTSTATUS ntStatus;
PKSDATARANGE aClientDataRange;
//
// Check the size of the structure.
//
if (ClientDataRange->FormatSize < sizeof (KSDATARANGE))
{
_DbgPrintF (DEBUGLVL_TERSE, ("Validating ClientDataRange: size < KSDATARANGE!"));
return STATUS_INVALID_PARAMETER;
}
//
// We default to no match.
//
ntStatus = STATUS_NO_MATCH;
//
// Go through all the dataranges in the validate list until we get a SUCCESS.
//
for (; MyDataRangesCount--; MyDataRanges++)
{
PKSDATARANGE myDataRange = *MyDataRanges;
//
// Verify that the correct major format, subformat and specifier (or wildcards)
// are in the intersection.
//
if ((!IsEqualGUIDAligned(ClientDataRange->MajorFormat,myDataRange->MajorFormat) &&
!IsEqualGUIDAligned(ClientDataRange->MajorFormat,KSDATAFORMAT_TYPE_WILDCARD)) ||
(!IsEqualGUIDAligned(ClientDataRange->SubFormat,myDataRange->SubFormat) &&
!IsEqualGUIDAligned(ClientDataRange->SubFormat,KSDATAFORMAT_SUBTYPE_WILDCARD)) ||
(!IsEqualGUIDAligned(ClientDataRange->Specifier,myDataRange->Specifier) &&
!IsEqualGUIDAligned(ClientDataRange->Specifier,KSDATAFORMAT_SPECIFIER_WILDCARD)))
{
continue; // no match and no WILDCARD, try the next one
}
//
// if not WILDCARD, then we ask the miniport to match this one exactly,
// else we manufacture a range and ask the miniport for a match from that.
//
aClientDataRange = ClientDataRange; // assume no WILDCARD for now, we ask the miniport to match this
//
// Handle the wildcards.
//
if (IsEqualGUIDAligned (ClientDataRange->MajorFormat,KSDATAFORMAT_TYPE_WILDCARD) ||
IsEqualGUIDAligned (ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD) ||
IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD))
{
//
// We pass a faked datarange for the specifiers we know or we pass to the
// miniport it's own datarange.
//
// We know the specifiers waveformatex and dsound.
//
if (IsEqualGUIDAligned (myDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
IsEqualGUIDAligned (myDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
{
KSDATARANGE_AUDIO dr;
//
// Take the complete datarange from the driver.
//
dr.DataRange = *myDataRange;
//
// Fill in a HUGE data range (it asked for WILDCARD, after all!)
//
dr.MaximumChannels = 0x1FFF0;
dr.MinimumBitsPerSample = 1;
dr.MaximumBitsPerSample = 0x1FFF0;
dr.MinimumSampleFrequency = 1;
dr.MaximumSampleFrequency = 0x1FFFFFF0;
aClientDataRange = (PKSDATARANGE)&dr;
}
else
{
//
// We don't know this non-wave format (in the list of formats we supposedly support).
// The miniport specified this format, so it is OK to pass it down.
//
aClientDataRange = myDataRange;
}
}
//
// Make sure KSDATARANGE_AUDIO is used, then see if there is a possible match.
//
if (IsEqualGUIDAligned (aClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
IsEqualGUIDAligned (aClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
{
if (aClientDataRange->FormatSize < sizeof (KSDATARANGE_AUDIO))
{
//
// The datarange structure passed has no KSDATARANGE_AUDIO.
//
_DbgPrintF (DEBUGLVL_TERSE, ("Validating PCM ValidDataRange: size < KSDATARANGE_AUDIO!"));
continue; // not large enough, try the next one
}
//
// Verify that we have an intersection with the specified format and
// our audio format dictated by our specific requirements.
//
_DbgPrintF (DEBUGLVL_VERBOSE, ("validating KSDATARANGE_AUDIO"));
if ((((PKSDATARANGE_AUDIO)aClientDataRange)->MinimumSampleFrequency >
((PKSDATARANGE_AUDIO)myDataRange)->MaximumSampleFrequency) ||
(((PKSDATARANGE_AUDIO)aClientDataRange)->MaximumSampleFrequency <
((PKSDATARANGE_AUDIO)myDataRange)->MinimumSampleFrequency) ||
(((PKSDATARANGE_AUDIO)aClientDataRange)->MinimumBitsPerSample >
((PKSDATARANGE_AUDIO)myDataRange)->MaximumBitsPerSample) ||
(((PKSDATARANGE_AUDIO)aClientDataRange)->MaximumBitsPerSample <
((PKSDATARANGE_AUDIO)myDataRange)->MinimumBitsPerSample))
{
continue;
}
}
ntStatus = GenerateFormatFromRange (Irp,
PinId,
myDataRange,
aClientDataRange,
OutputBufferLength,
ResultantFormat,
ResultantFormatLength);
if ( NT_SUCCESS(ntStatus)
|| (ntStatus == STATUS_BUFFER_OVERFLOW)
|| (ntStatus == STATUS_BUFFER_TOO_SMALL))
{
break; // We found a good one, or we failed.
// Either way we must leave.
}
}
return ntStatus;
}
/*****************************************************************************
* PinIntersectHandler()
*****************************************************************************
* This function is a data range callback for use with
* PropertyHandler_PinIntersection
*/
NTSTATUS
PinIntersectHandler
(
IN PIRP Irp,
IN PKSP_PIN Pin,
IN PKSDATARANGE DataRange,
OUT PVOID Data
)
{
NTSTATUS Status;
ULONG OutputBufferLength;
PAGED_CODE();
ASSERT(Irp);
ASSERT(Pin);
ASSERT(DataRange);
PPROPERTY_CONTEXT pPropertyContext =
PPROPERTY_CONTEXT(Irp->Tail.Overlay.DriverContext[3]);
ASSERT(pPropertyContext);
PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor =
pPropertyContext->pSubdeviceDescriptor;
ASSERT(pSubdeviceDescriptor);
ASSERT(pSubdeviceDescriptor->PinDescriptors);
ASSERT(Pin->PinId < pSubdeviceDescriptor->PinCount);
PKSPIN_DESCRIPTOR pinDescriptor =
&pSubdeviceDescriptor->PinDescriptors[Pin->PinId];
ASSERT(pinDescriptor);
_DbgPrintF(DEBUGLVL_VERBOSE,("[PinIntersectHandler]"));
OutputBufferLength =
IoGetCurrentIrpStackLocation( Irp )->
Parameters.DeviceIoControl.OutputBufferLength;
Status =
ValidateTypeAndSpecifier(
Irp,
Pin->PinId,
DataRange,
pinDescriptor->DataRangesCount,
pinDescriptor->DataRanges,
OutputBufferLength,
Data,
PULONG(&Irp->IoStatus.Information) );
if (!NT_SUCCESS( Status )) {
_DbgPrintF(
DEBUGLVL_VERBOSE,
("ValidateTypeAndSpecifier() returned %08x", Status) );
}
return Status;
}
/*****************************************************************************
* PinPhysicalConnection()
*****************************************************************************
* Handles physical connection property access for the pin.
*/
static
NTSTATUS
PinPhysicalConnection
(
IN PIRP Irp,
IN PKSP_PIN Pin,
OUT PVOID Data
)
{
PAGED_CODE();
ASSERT(Irp);
ASSERT(Pin);
PPROPERTY_CONTEXT pPropertyContext =
PPROPERTY_CONTEXT(Irp->Tail.Overlay.DriverContext[3]);
ASSERT(pPropertyContext);
PSUBDEVICE Subdevice =
pPropertyContext->pSubdevice;
ASSERT(Subdevice);
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(irpSp);
ASSERT(irpSp->DeviceObject);
PDEVICE_CONTEXT deviceContext =
PDEVICE_CONTEXT(irpSp->DeviceObject->DeviceExtension);
NTSTATUS ntStatus = STATUS_NOT_FOUND;
ULONG outPin;
PUNICODE_STRING outUnicodeString = NULL;
for
(
PLIST_ENTRY entry = deviceContext->PhysicalConnectionList.Flink;
entry != &deviceContext->PhysicalConnectionList;
entry = entry->Flink
)
{
PPHYSICALCONNECTION connection = PPHYSICALCONNECTION(entry);
if ( (connection->FromSubdevice == Subdevice)
&& (connection->FromPin == Pin->PinId)
)
{
outPin = connection->ToPin;
if (connection->ToString)
{
outUnicodeString = connection->ToString;
}
else
{
ULONG ulIndex =
SubdeviceIndex(irpSp->DeviceObject,connection->ToSubdevice);
if (ulIndex != ULONG(-1))
{
ntStatus = STATUS_SUCCESS;
outUnicodeString = &deviceContext->SymbolicLinkNames[ulIndex];
}
}
break;
}
else
if ( (connection->ToSubdevice == Subdevice)
&& (connection->ToPin == Pin->PinId)
)
{
outPin = connection->FromPin;
if (connection->FromString)
{
outUnicodeString = connection->FromString;
}
else
{
ULONG ulIndex =
SubdeviceIndex(irpSp->DeviceObject,connection->FromSubdevice);
if (ulIndex != ULONG(-1))
{
ntStatus = STATUS_SUCCESS;
outUnicodeString = &deviceContext->SymbolicLinkNames[ulIndex];
}
}
break;
}
}
if (!outUnicodeString)
{
ntStatus = STATUS_NOT_FOUND;
}
if (NT_SUCCESS(ntStatus))
{
ULONG outSize;
outSize = FIELD_OFFSET(KSPIN_PHYSICALCONNECTION,SymbolicLinkName[0]);
outSize += (outUnicodeString->Length + sizeof(UNICODE_NULL));
//
// Validate return buffer size.
//
ULONG outputBufferLength =
IoGetCurrentIrpStackLocation(Irp)->
Parameters.DeviceIoControl.OutputBufferLength;
if (!outputBufferLength)
{
Irp->IoStatus.Information = outSize;
ntStatus = STATUS_BUFFER_OVERFLOW;
}
else
if (outputBufferLength < outSize)
{
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
else
{
PKSPIN_PHYSICALCONNECTION out = PKSPIN_PHYSICALCONNECTION(Data);
out->Size = outSize;
out->Pin = outPin;
RtlCopyMemory
(
out->SymbolicLinkName,
outUnicodeString->Buffer,
outUnicodeString->Length
);
out->SymbolicLinkName[outUnicodeString->Length / sizeof(WCHAR)] = 0;
Irp->IoStatus.Information = outSize;
}
}
return ntStatus;
}
/*****************************************************************************
* PinCountHandler()
*****************************************************************************
* Handles pin count access for the pin.
*/
void PinCountHandler
( IN PPROPERTY_CONTEXT pPropertyContext,
IN ULONG pinId
)
{
PAGED_CODE();
ASSERT(pPropertyContext);
PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor = pPropertyContext->pSubdeviceDescriptor;
ASSERT(pSubdeviceDescriptor);
PSUBDEVICE Subdevice = pPropertyContext->pSubdevice;
ASSERT(Subdevice);
Subdevice->PinCount( pinId, &(pSubdeviceDescriptor->PinInstances[pinId].FilterNecessary),
&(pPropertyContext->pulPinInstanceCounts[pinId]),
&(pSubdeviceDescriptor->PinInstances[pinId].FilterPossible),
&(pSubdeviceDescriptor->PinInstances[pinId].GlobalCurrent),
&(pSubdeviceDescriptor->PinInstances[pinId].GlobalPossible) );
}
/*****************************************************************************
* PcPinPropertyHandler()
*****************************************************************************
* Property handler for pin properties on the filter.
*/
PORTCLASSAPI
NTSTATUS
NTAPI
PcPinPropertyHandler
( IN PIRP pIrp,
IN PKSP_PIN pKsPPin,
IN OUT PVOID pvData
)
{
PAGED_CODE();
ASSERT(pIrp);
ASSERT(pKsPPin);
PPROPERTY_CONTEXT pPropertyContext =
PPROPERTY_CONTEXT(pIrp->Tail.Overlay.DriverContext[3]);
ASSERT(pPropertyContext);
PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor =
pPropertyContext->pSubdeviceDescriptor;
ASSERT(pSubdeviceDescriptor);
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
if
( (pKsPPin->Property.Id != KSPROPERTY_PIN_CTYPES)
&& (pKsPPin->PinId >= pSubdeviceDescriptor->PinCount)
)
{
ntStatus = STATUS_INVALID_PARAMETER;
}
else
{
switch (pKsPPin->Property.Id)
{
case KSPROPERTY_PIN_CTYPES:
case KSPROPERTY_PIN_DATAFLOW:
case KSPROPERTY_PIN_DATARANGES:
case KSPROPERTY_PIN_INTERFACES:
case KSPROPERTY_PIN_MEDIUMS:
case KSPROPERTY_PIN_COMMUNICATION:
case KSPROPERTY_PIN_CATEGORY:
case KSPROPERTY_PIN_NAME:
ntStatus =
KsPinPropertyHandler
(
pIrp,
PKSPROPERTY(pKsPPin),
pvData,
pSubdeviceDescriptor->PinCount,
pSubdeviceDescriptor->PinDescriptors
);
break;
case KSPROPERTY_PIN_DATAINTERSECTION:
ntStatus =
KsPinDataIntersection
(
pIrp,
pKsPPin,
pvData,
pSubdeviceDescriptor->PinCount,
pSubdeviceDescriptor->PinDescriptors,
PinIntersectHandler
);
break;
case KSPROPERTY_PIN_CINSTANCES:
if (pPropertyContext->pulPinInstanceCounts)
{
PinCountHandler(pPropertyContext,pKsPPin->PinId);
PKSPIN_CINSTANCES(pvData)->PossibleCount =
pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].FilterPossible;
PKSPIN_CINSTANCES(pvData)->CurrentCount =
pPropertyContext->pulPinInstanceCounts[pKsPPin->PinId];
pIrp->IoStatus.Information = sizeof(KSPIN_CINSTANCES);
ntStatus = STATUS_SUCCESS;
}
break;
case KSPROPERTY_PIN_GLOBALCINSTANCES:
if (pPropertyContext->pulPinInstanceCounts)
{
PinCountHandler(pPropertyContext,pKsPPin->PinId);
}
PKSPIN_CINSTANCES(pvData)->PossibleCount =
pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].GlobalPossible;
PKSPIN_CINSTANCES(pvData)->CurrentCount =
pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].GlobalCurrent;
pIrp->IoStatus.Information = sizeof(KSPIN_CINSTANCES);
ntStatus = STATUS_SUCCESS;
break;
case KSPROPERTY_PIN_NECESSARYINSTANCES:
if (pPropertyContext->pulPinInstanceCounts)
{
PinCountHandler(pPropertyContext,pKsPPin->PinId);
*PULONG(pvData) = pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].FilterNecessary;
pIrp->IoStatus.Information = sizeof(ULONG);
ntStatus = STATUS_SUCCESS;
}
break;
case KSPROPERTY_PIN_PHYSICALCONNECTION:
ntStatus =
PinPhysicalConnection
(
pIrp,
pKsPPin,
pvData
);
break;
default:
ntStatus = STATUS_NOT_FOUND;
break;
}
}
return ntStatus;
}