reactos/drivers/ksfilter/ks/filter.c
Johannes Anderwald ea8f6ef311 [AUDIO-BRINGUP]
- Move irp completion to CompleteRequest function for debugging of multiple irp completion bugs
- Remove bugs asserts in IKsDevice_PnpStartDevice
- Set device to started when the device does not need pnp notification
- Don't complete the irp in IKsDevice_Create, the driver has already done this
- Comment out UNIMPLEMENTED macro in KsFilterAttemptProcessing
- Fix check in FindMatchingCreateItem
- Don't set DO_DIRECT_IO flags on PDO devices
- Set DO_DEVICE_INITIALIZING flag on PDO device 
- Construct device name with swprintf
- Add check if the device entry has already been constructed
- Zero device capabilities
- Implement bus watchdog routine. The routine checks if pdo has successfully been started, otherwise the pdo is marked invalid and the deleted and then constructed again. If the pdo has been started, all pending irp requests are completed with STATUS_REPARSE. (This is probably not supported by Ros kernel yet)
- Acquire device entry list lock when working with device entries
- Always store status code in irp for all Ks bus api routines
- Handle IRP_MN_REMOVE_DEVICE
- Start watchdog timer when IRP_MN_START_DEVICE is received
- Ros KS nos successfully initializes and all audio devices appear in VBOX+WinXP+SP3. Playback not yet working (Needs KsAttemptFilterProcessing for splitter and friends)
- TODO: enhance time out to make audio system initialize faster

svn path=/branches/audio-bringup/; revision=50079
2010-12-21 13:06:47 +00:00

1816 lines
53 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel Streaming
* FILE: drivers/ksfilter/ks/filter.c
* PURPOSE: KS IKsFilter interface functions
* PROGRAMMER: Johannes Anderwald
*/
#include "priv.h"
typedef struct
{
KSBASIC_HEADER Header;
KSFILTER Filter;
IKsControlVtbl *lpVtblKsControl;
IKsFilterFactory * FilterFactory;
LONG ref;
PKSIOBJECT_HEADER ObjectHeader;
KSTOPOLOGY Topology;
PKSFILTERFACTORY Factory;
PFILE_OBJECT FileObject;
KMUTEX ControlMutex;
KMUTEX ProcessingMutex;
PFNKSFILTERPOWER Sleep;
PFNKSFILTERPOWER Wake;
ULONG *PinInstanceCount;
PKSPIN * FirstPin;
PKSPROCESSPIN_INDEXENTRY ProcessPinIndex;
}IKsFilterImpl;
const GUID IID_IKsControl = {0x28F54685L, 0x06FD, 0x11D2, {0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
const GUID IID_IKsFilter = {0x3ef6ee44L, 0x0D41, 0x11d2, {0xbe, 0xDA, 0x00, 0xc0, 0x4f, 0x8e, 0xF4, 0x57}};
const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
VOID
IKsFilter_RemoveFilterFromFilterFactory(
IKsFilterImpl * This,
PKSFILTERFACTORY FilterFactory);
NTSTATUS NTAPI FilterTopologyPropertyHandler(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
NTSTATUS NTAPI FilterPinPropertyHandler(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
DEFINE_KSPROPERTY_TOPOLOGYSET(IKsFilterTopologySet, FilterTopologyPropertyHandler);
DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(IKsFilterPinSet, FilterPinPropertyHandler, FilterPinPropertyHandler, FilterPinPropertyHandler);
KSPROPERTY_SET FilterPropertySet[] =
{
{
&KSPROPSETID_Topology,
sizeof(IKsFilterTopologySet) / sizeof(KSPROPERTY_ITEM),
(const KSPROPERTY_ITEM*)&IKsFilterTopologySet,
0,
NULL
},
{
&KSPROPSETID_Pin,
sizeof(IKsFilterPinSet) / sizeof(KSPROPERTY_ITEM),
(const KSPROPERTY_ITEM*)&IKsFilterPinSet,
0,
NULL
}
};
NTSTATUS
NTAPI
IKsControl_fnQueryInterface(
IKsControl * iface,
IN REFIID refiid,
OUT PVOID* Output)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsControl);
if (IsEqualGUIDAligned(refiid, &IID_IUnknown))
{
*Output = &This->Header.OuterUnknown;
_InterlockedIncrement(&This->ref);
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
ULONG
NTAPI
IKsControl_fnAddRef(
IKsControl * iface)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsControl);
return InterlockedIncrement(&This->ref);
}
ULONG
NTAPI
IKsControl_fnRelease(
IKsControl * iface)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsControl);
InterlockedDecrement(&This->ref);
/* Return new reference count */
return This->ref;
}
NTSTATUS
NTAPI
IKsControl_fnKsProperty(
IKsControl * iface,
IN PKSPROPERTY Property,
IN ULONG PropertyLength,
IN OUT PVOID PropertyData,
IN ULONG DataLength,
OUT ULONG* BytesReturned)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsControl);
return KsSynchronousIoControlDevice(This->FileObject, KernelMode, IOCTL_KS_PROPERTY, Property, PropertyLength, PropertyData, DataLength, BytesReturned);
}
NTSTATUS
NTAPI
IKsControl_fnKsMethod(
IKsControl * iface,
IN PKSMETHOD Method,
IN ULONG MethodLength,
IN OUT PVOID MethodData,
IN ULONG DataLength,
OUT ULONG* BytesReturned)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsControl);
return KsSynchronousIoControlDevice(This->FileObject, KernelMode, IOCTL_KS_METHOD, Method, MethodLength, MethodData, DataLength, BytesReturned);
}
NTSTATUS
NTAPI
IKsControl_fnKsEvent(
IKsControl * iface,
IN PKSEVENT Event OPTIONAL,
IN ULONG EventLength,
IN OUT PVOID EventData,
IN ULONG DataLength,
OUT ULONG* BytesReturned)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsControl);
if (Event)
{
return KsSynchronousIoControlDevice(This->FileObject, KernelMode, IOCTL_KS_ENABLE_EVENT, Event, EventLength, EventData, DataLength, BytesReturned);
}
else
{
return KsSynchronousIoControlDevice(This->FileObject, KernelMode, IOCTL_KS_DISABLE_EVENT, EventData, DataLength, NULL, 0, BytesReturned);
}
}
static IKsControlVtbl vt_IKsControl =
{
IKsControl_fnQueryInterface,
IKsControl_fnAddRef,
IKsControl_fnRelease,
IKsControl_fnKsProperty,
IKsControl_fnKsMethod,
IKsControl_fnKsEvent
};
NTSTATUS
NTAPI
IKsFilter_fnQueryInterface(
IKsFilter * iface,
IN REFIID refiid,
OUT PVOID* Output)
{
NTSTATUS Status;
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, Header.OuterUnknown);
if (IsEqualGUIDAligned(refiid, &IID_IUnknown) ||
IsEqualGUIDAligned(refiid, &IID_IKsFilter))
{
*Output = &This->Header.OuterUnknown;
_InterlockedIncrement(&This->ref);
return STATUS_SUCCESS;
}
else if (IsEqualGUIDAligned(refiid, &IID_IKsControl))
{
*Output = &This->lpVtblKsControl;
_InterlockedIncrement(&This->ref);
return STATUS_SUCCESS;
}
if (This->Header.ClientAggregate)
{
/* using client aggregate */
Status = This->Header.ClientAggregate->lpVtbl->QueryInterface(This->Header.ClientAggregate, refiid, Output);
if (NT_SUCCESS(Status))
{
/* client aggregate supports interface */
return Status;
}
}
DPRINT("IKsFilter_fnQueryInterface no interface\n");
return STATUS_NOT_SUPPORTED;
}
ULONG
NTAPI
IKsFilter_fnAddRef(
IKsFilter * iface)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, Header.OuterUnknown);
return InterlockedIncrement(&This->ref);
}
ULONG
NTAPI
IKsFilter_fnRelease(
IKsFilter * iface)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, Header.OuterUnknown);
InterlockedDecrement(&This->ref);
if (This->ref == 0)
{
FreeItem(This);
return 0;
}
/* Return new reference count */
return This->ref;
}
PKSFILTER
NTAPI
IKsFilter_fnGetStruct(
IKsFilter * iface)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, Header.OuterUnknown);
return &This->Filter;
}
BOOL
NTAPI
IKsFilter_fnDoAllNecessaryPinsExist(
IKsFilter * iface)
{
UNIMPLEMENTED
return FALSE;
}
NTSTATUS
NTAPI
IKsFilter_fnCreateNode(
IKsFilter * iface,
IN PIRP Irp,
IN IKsPin * Pin,
IN PLIST_ENTRY ListEntry)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
IKsFilter_fnBindProcessPinsToPipeSection(
IKsFilter * iface,
IN struct KSPROCESSPIPESECTION *Section,
IN PVOID Create,
IN PKSPIN KsPin,
OUT IKsPin **Pin,
OUT PKSGATE *OutGate)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
IKsFilter_fnUnbindProcessPinsFromPipeSection(
IKsFilter * iface,
IN struct KSPROCESSPIPESECTION *Section)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
IKsFilter_fnAddProcessPin(
IKsFilter * iface,
IN PKSPROCESSPIN ProcessPin)
{
NTSTATUS Status;
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, Header.OuterUnknown);
/* first acquire processing mutex */
KeWaitForSingleObject(&This->ProcessingMutex, Executive, KernelMode, FALSE, NULL);
/* sanity check */
ASSERT(This->Filter.Descriptor->PinDescriptorsCount > ProcessPin->Pin->Id);
/* allocate new process pin array */
Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->ProcessPinIndex[ProcessPin->Pin->Id].Pins,
(This->Filter.Descriptor->PinDescriptorsCount + 1) * sizeof(PKSPROCESSPIN),
This->Filter.Descriptor->PinDescriptorsCount * sizeof(PKSPROCESSPIN),
0);
if (NT_SUCCESS(Status))
{
/* store process pin */
This->ProcessPinIndex[ProcessPin->Pin->Id].Pins[This->ProcessPinIndex[ProcessPin->Pin->Id].Count] = ProcessPin;
This->ProcessPinIndex[ProcessPin->Pin->Id].Count++;
}
/* release process mutex */
KeReleaseMutex(&This->ProcessingMutex, FALSE);
return Status;
}
NTSTATUS
NTAPI
IKsFilter_fnRemoveProcessPin(
IKsFilter * iface,
IN PKSPROCESSPIN ProcessPin)
{
ULONG Index;
ULONG Count;
PKSPROCESSPIN * Pins;
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, Header.OuterUnknown);
/* first acquire processing mutex */
KeWaitForSingleObject(&This->ProcessingMutex, Executive, KernelMode, FALSE, NULL);
/* sanity check */
ASSERT(ProcessPin->Pin);
ASSERT(ProcessPin->Pin->Id);
Count = This->ProcessPinIndex[ProcessPin->Pin->Id].Count;
Pins = This->ProcessPinIndex[ProcessPin->Pin->Id].Pins;
/* search for current process pin */
for(Index = 0; Index < Count; Index++)
{
if (Pins[Index] == ProcessPin)
{
RtlMoveMemory(&Pins[Index], &Pins[Index + 1], (Count - (Index + 1)) * sizeof(PKSPROCESSPIN));
break;
}
}
/* decrement pin count */
This->ProcessPinIndex[ProcessPin->Pin->Id].Count--;
if (!This->ProcessPinIndex[ProcessPin->Pin->Id].Count)
{
/* clear entry object bag will delete it */
This->ProcessPinIndex[ProcessPin->Pin->Id].Pins = NULL;
}
/* release process mutex */
KeReleaseMutex(&This->ProcessingMutex, FALSE);
/* done */
return STATUS_SUCCESS;
}
BOOL
NTAPI
IKsFilter_fnReprepareProcessPipeSection(
IKsFilter * iface,
IN struct KSPROCESSPIPESECTION *PipeSection,
IN PULONG Data)
{
UNIMPLEMENTED
return FALSE;
}
VOID
NTAPI
IKsFilter_fnDeliverResetState(
IKsFilter * iface,
IN struct KSPROCESSPIPESECTION *PipeSection,
IN KSRESET ResetState)
{
UNIMPLEMENTED
}
BOOL
NTAPI
IKsFilter_fnIsFrameHolding(
IKsFilter * iface)
{
UNIMPLEMENTED
return FALSE;
}
VOID
NTAPI
IKsFilter_fnRegisterForCopyCallbacks(
IKsFilter * iface,
IKsQueue *Queue,
BOOL Register)
{
UNIMPLEMENTED
}
PKSPROCESSPIN_INDEXENTRY
NTAPI
IKsFilter_fnGetProcessDispatch(
IKsFilter * iface)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, Header.OuterUnknown);
return This->ProcessPinIndex;
}
static IKsFilterVtbl vt_IKsFilter =
{
IKsFilter_fnQueryInterface,
IKsFilter_fnAddRef,
IKsFilter_fnRelease,
IKsFilter_fnGetStruct,
IKsFilter_fnDoAllNecessaryPinsExist,
IKsFilter_fnCreateNode,
IKsFilter_fnBindProcessPinsToPipeSection,
IKsFilter_fnUnbindProcessPinsFromPipeSection,
IKsFilter_fnAddProcessPin,
IKsFilter_fnRemoveProcessPin,
IKsFilter_fnReprepareProcessPipeSection,
IKsFilter_fnDeliverResetState,
IKsFilter_fnIsFrameHolding,
IKsFilter_fnRegisterForCopyCallbacks,
IKsFilter_fnGetProcessDispatch
};
NTSTATUS
IKsFilter_GetFilterFromIrp(
IN PIRP Irp,
OUT IKsFilter **Filter)
{
PIO_STACK_LOCATION IoStack;
PKSIOBJECT_HEADER ObjectHeader;
NTSTATUS Status;
/* get current irp stack */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* santiy check */
ASSERT(IoStack->FileObject != NULL);
ObjectHeader = (PKSIOBJECT_HEADER)IoStack->FileObject->FsContext2;
/* sanity is important */
ASSERT(ObjectHeader != NULL);
ASSERT(ObjectHeader->Type == KsObjectTypeFilter);
ASSERT(ObjectHeader->Unknown != NULL);
/* get our private interface */
Status = ObjectHeader->Unknown->lpVtbl->QueryInterface(ObjectHeader->Unknown, &IID_IKsFilter, (PVOID*)Filter);
if (!NT_SUCCESS(Status))
{
/* something is wrong here */
DPRINT1("KS: Misbehaving filter %p\n", ObjectHeader->Unknown);
Irp->IoStatus.Status = Status;
/* complete and forget irp */
CompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
return Status;
}
NTSTATUS
NTAPI
IKsFilter_DispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
IKsFilter * Filter;
IKsFilterImpl * This;
NTSTATUS Status;
/* obtain filter from object header */
Status = IKsFilter_GetFilterFromIrp(Irp, &Filter);
if (!NT_SUCCESS(Status))
return Status;
/* get our real implementation */
This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Header.OuterUnknown);
/* does the driver support notifications */
if (This->Filter.Descriptor && This->Filter.Descriptor->Dispatch && This->Filter.Descriptor->Dispatch->Close)
{
/* call driver's filter close function */
Status = This->Filter.Descriptor->Dispatch->Close(&This->Filter, Irp);
}
if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
{
/* save the result */
Irp->IoStatus.Status = Status;
/* complete irp */
CompleteRequest(Irp, IO_NO_INCREMENT);
/* remove our instance from the filter factory */
IKsFilter_RemoveFilterFromFilterFactory(This, This->Factory);
/* free object header */
KsFreeObjectHeader(This->ObjectHeader);
}
else
{
/* complete and forget */
Irp->IoStatus.Status = Status;
/* complete irp */
CompleteRequest(Irp, IO_NO_INCREMENT);
}
/* done */
return Status;
}
NTSTATUS
KspHandlePropertyInstances(
IN PIO_STATUS_BLOCK IoStatus,
IN PKSIDENTIFIER Request,
IN OUT PVOID Data,
IN IKsFilterImpl * This,
IN BOOL Global)
{
KSPIN_CINSTANCES * Instances;
KSP_PIN * Pin = (KSP_PIN*)Request;
if (!This->Filter.Descriptor || !This->Filter.Descriptor->PinDescriptorsCount)
{
/* no filter / pin descriptor */
IoStatus->Status = STATUS_NOT_IMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* ignore custom structs for now */
ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
ASSERT(This->Filter.Descriptor->PinDescriptorsCount > Pin->PinId);
Instances = (KSPIN_CINSTANCES*)Data;
/* max instance count */
Instances->PossibleCount = This->Filter.Descriptor->PinDescriptors[Pin->PinId].InstancesPossible;
/* current instance count */
Instances->CurrentCount = This->PinInstanceCount[Pin->PinId];
IoStatus->Information = sizeof(KSPIN_CINSTANCES);
IoStatus->Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
NTSTATUS
KspHandleNecessaryPropertyInstances(
IN PIO_STATUS_BLOCK IoStatus,
IN PKSIDENTIFIER Request,
IN OUT PVOID Data,
IN IKsFilterImpl * This)
{
PULONG Result;
KSP_PIN * Pin = (KSP_PIN*)Request;
if (!This->Filter.Descriptor || !This->Filter.Descriptor->PinDescriptorsCount)
{
/* no filter / pin descriptor */
IoStatus->Status = STATUS_NOT_IMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* ignore custom structs for now */
ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
ASSERT(This->Filter.Descriptor->PinDescriptorsCount > Pin->PinId);
Result = (PULONG)Data;
*Result = This->Filter.Descriptor->PinDescriptors[Pin->PinId].InstancesNecessary;
IoStatus->Information = sizeof(ULONG);
IoStatus->Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
NTSTATUS
KspHandleDataIntersection(
IN PIRP Irp,
IN PIO_STATUS_BLOCK IoStatus,
IN PKSIDENTIFIER Request,
IN OUT PVOID Data,
IN ULONG DataLength,
IN IKsFilterImpl * This)
{
PKSMULTIPLE_ITEM MultipleItem;
PKSDATARANGE DataRange;
NTSTATUS Status = STATUS_NO_MATCH;
ULONG Index, Length;
PIO_STACK_LOCATION IoStack;
KSP_PIN * Pin = (KSP_PIN*)Request;
/* get stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* sanity check */
ASSERT(DataLength == IoStack->Parameters.DeviceIoControl.OutputBufferLength);
/* Access parameters */
MultipleItem = (PKSMULTIPLE_ITEM)(Pin + 1);
DataRange = (PKSDATARANGE)(MultipleItem + 1);
/* FIXME make sure its 64 bit aligned */
ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
if (!This->Filter.Descriptor || !This->Filter.Descriptor->PinDescriptorsCount)
{
/* no filter / pin descriptor */
IoStatus->Status = STATUS_NOT_IMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* ignore custom structs for now */
ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
ASSERT(This->Filter.Descriptor->PinDescriptorsCount > Pin->PinId);
if (This->Filter.Descriptor->PinDescriptors[Pin->PinId].IntersectHandler == NULL ||
This->Filter.Descriptor->PinDescriptors[Pin->PinId].PinDescriptor.DataRanges == NULL ||
This->Filter.Descriptor->PinDescriptors[Pin->PinId].PinDescriptor.DataRangesCount == 0)
{
/* no driver supported intersect handler / no provided data ranges */
IoStatus->Status = STATUS_NOT_IMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
for(Index = 0; Index < MultipleItem->Count; Index++)
{
UNICODE_STRING MajorFormat, SubFormat, Specifier;
/* convert the guid to string */
RtlStringFromGUID(&DataRange->MajorFormat, &MajorFormat);
RtlStringFromGUID(&DataRange->SubFormat, &SubFormat);
RtlStringFromGUID(&DataRange->Specifier, &Specifier);
DPRINT("KspHandleDataIntersection Index %lu PinId %lu MajorFormat %S SubFormat %S Specifier %S FormatSize %lu SampleSize %lu Align %lu Flags %lx Reserved %lx DataLength %lu\n", Index, Pin->PinId, MajorFormat.Buffer, SubFormat.Buffer, Specifier.Buffer,
DataRange->FormatSize, DataRange->SampleSize, DataRange->Alignment, DataRange->Flags, DataRange->Reserved, DataLength);
/* FIXME implement KsPinDataIntersectionEx */
/* Call miniport's properitary handler */
Status = This->Filter.Descriptor->PinDescriptors[Pin->PinId].IntersectHandler(&This->Filter,
Irp,
Pin,
DataRange,
This->Filter.Descriptor->PinDescriptors[Pin->PinId].PinDescriptor.DataRanges[0], /* HACK */
DataLength,
Data,
&Length);
DPRINT("KspHandleDataIntersection Status %lx\n", Status);
if (Status == STATUS_SUCCESS || Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
{
ASSERT(Length);
IoStatus->Information = Length;
break;
}
DataRange = UlongToPtr(PtrToUlong(DataRange) + DataRange->FormatSize);
/* FIXME make sure its 64 bit aligned */
ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
}
IoStatus->Status = Status;
return Status;
}
NTSTATUS
NTAPI
FilterTopologyPropertyHandler(
IN PIRP Irp,
IN PKSIDENTIFIER Request,
IN OUT PVOID Data)
{
IKsFilterImpl * This;
/* get filter implementation */
This = (IKsFilterImpl*)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
/* sanity check */
ASSERT(This);
return KsTopologyPropertyHandler(Irp, Request, Data, &This->Topology);
}
NTSTATUS
NTAPI
FilterPinPropertyHandler(
IN PIRP Irp,
IN PKSIDENTIFIER Request,
IN OUT PVOID Data)
{
PIO_STACK_LOCATION IoStack;
IKsFilterImpl * This;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
/* get filter implementation */
This = (IKsFilterImpl*)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
/* sanity check */
ASSERT(This);
/* get current stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
switch(Request->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:
case KSPROPERTY_PIN_CONSTRAINEDDATARANGES:
Status = KspPinPropertyHandler(Irp, Request, Data, This->Filter.Descriptor->PinDescriptorsCount, (const KSPIN_DESCRIPTOR*)This->Filter.Descriptor->PinDescriptors, This->Filter.Descriptor->PinDescriptorSize);
break;
case KSPROPERTY_PIN_GLOBALCINSTANCES:
Status = KspHandlePropertyInstances(&Irp->IoStatus, Request, Data, This, TRUE);
break;
case KSPROPERTY_PIN_CINSTANCES:
Status = KspHandlePropertyInstances(&Irp->IoStatus, Request, Data, This, FALSE);
break;
case KSPROPERTY_PIN_NECESSARYINSTANCES:
Status = KspHandleNecessaryPropertyInstances(&Irp->IoStatus, Request, Data, This);
break;
case KSPROPERTY_PIN_DATAINTERSECTION:
Status = KspHandleDataIntersection(Irp, &Irp->IoStatus, Request, Data, IoStack->Parameters.DeviceIoControl.OutputBufferLength, This);
break;
default:
UNIMPLEMENTED
Status = STATUS_NOT_FOUND;
}
//DPRINT("KspPinPropertyHandler Pins %lu Request->Id %lu Status %lx\n", This->PinDescriptorCount, Request->Id, Status);
return Status;
}
NTSTATUS
NTAPI
IKsFilter_DispatchDeviceIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
IKsFilter * Filter;
IKsFilterImpl * This;
NTSTATUS Status;
PKSFILTER FilterInstance;
UNICODE_STRING GuidString;
PKSPROPERTY Property;
ULONG SetCount = 0;
/* obtain filter from object header */
Status = IKsFilter_GetFilterFromIrp(Irp, &Filter);
if (!NT_SUCCESS(Status))
return Status;
/* get our real implementation */
This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Header.OuterUnknown);
/* current irp stack */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* get property from input buffer */
Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
/* get filter instance */
FilterInstance = Filter->lpVtbl->GetStruct(Filter);
/* sanity check */
ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(KSIDENTIFIER));
ASSERT(FilterInstance);
ASSERT(FilterInstance->Descriptor);
ASSERT(FilterInstance->Descriptor->AutomationTable);
/* acquire control mutex */
KeWaitForSingleObject(This->Header.ControlMutex, Executive, KernelMode, FALSE, NULL);
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_METHOD)
{
const KSMETHOD_SET *MethodSet = NULL;
ULONG MethodItemSize = 0;
/* check if the driver supports method sets */
if (FilterInstance->Descriptor->AutomationTable->MethodSetsCount)
{
SetCount = FilterInstance->Descriptor->AutomationTable->MethodSetsCount;
MethodSet = FilterInstance->Descriptor->AutomationTable->MethodSets;
MethodItemSize = FilterInstance->Descriptor->AutomationTable->MethodItemSize;
}
/* call method set handler */
Status = KspMethodHandlerWithAllocator(Irp, SetCount, MethodSet, NULL, MethodItemSize);
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
{
const KSPROPERTY_SET *PropertySet = NULL;
ULONG PropertyItemSize = 0;
/* check if the driver supports method sets */
if (FilterInstance->Descriptor->AutomationTable->PropertySetsCount)
{
SetCount = FilterInstance->Descriptor->AutomationTable->PropertySetsCount;
PropertySet = FilterInstance->Descriptor->AutomationTable->PropertySets;
PropertyItemSize = FilterInstance->Descriptor->AutomationTable->PropertyItemSize;
}
/* needed for our property handlers */
KSPROPERTY_ITEM_IRP_STORAGE(Irp) = (KSPROPERTY_ITEM*)This;
/* call property handler */
Status = KspPropertyHandler(Irp, SetCount, PropertySet, NULL, PropertyItemSize);
}
else
{
/* sanity check */
ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT ||
IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_DISABLE_EVENT);
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_ENABLE_EVENT)
{
/* call enable event handlers */
Status = KspEnableEvent(Irp,
FilterInstance->Descriptor->AutomationTable->EventSetsCount,
(PKSEVENT_SET)FilterInstance->Descriptor->AutomationTable->EventSets,
&This->Header.EventList,
KSEVENTS_SPINLOCK,
(PVOID)&This->Header.EventListLock,
NULL,
FilterInstance->Descriptor->AutomationTable->EventItemSize);
}
else
{
/* disable event handler */
Status = KsDisableEvent(Irp, &This->Header.EventList, KSEVENTS_SPINLOCK, &This->Header.EventListLock);
}
}
RtlStringFromGUID(&Property->Set, &GuidString);
DPRINT("IKsFilter_DispatchDeviceIoControl property Set |%S| Id %u Flags %x Status %lx ResultLength %lu\n", GuidString.Buffer, Property->Id, Property->Flags, Status, Irp->IoStatus.Information);
RtlFreeUnicodeString(&GuidString);
/* release filter */
Filter->lpVtbl->Release(Filter);
/* release control mutex */
KeReleaseMutex(This->Header.ControlMutex, FALSE);
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
CompleteRequest(Irp, IO_NO_INCREMENT);
}
/* done */
return Status;
}
static KSDISPATCH_TABLE DispatchTable =
{
IKsFilter_DispatchDeviceIoControl,
KsDispatchInvalidDeviceRequest,
KsDispatchInvalidDeviceRequest,
KsDispatchInvalidDeviceRequest,
IKsFilter_DispatchClose,
KsDispatchQuerySecurity,
KsDispatchSetSecurity,
KsDispatchFastIoDeviceControlFailure,
KsDispatchFastReadFailure,
KsDispatchFastReadFailure,
};
NTSTATUS
IKsFilter_CreateDescriptors(
IKsFilterImpl * This,
KSFILTER_DESCRIPTOR* FilterDescriptor)
{
ULONG Index = 0;
NTSTATUS Status;
/* initialize pin descriptors */
This->FirstPin = NULL;
This->PinInstanceCount = NULL;
This->ProcessPinIndex = NULL;
/* initialize topology descriptor */
This->Topology.CategoriesCount = FilterDescriptor->CategoriesCount;
This->Topology.Categories = FilterDescriptor->Categories;
This->Topology.TopologyNodesCount = FilterDescriptor->NodeDescriptorsCount;
This->Topology.TopologyConnectionsCount = FilterDescriptor->ConnectionsCount;
This->Topology.TopologyConnections = FilterDescriptor->Connections;
/* are there any templates */
if (FilterDescriptor->PinDescriptorsCount)
{
/* sanity check */
ASSERT(FilterDescriptor->PinDescriptors);
/* FIXME handle variable sized pin descriptors */
ASSERT(FilterDescriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
/* store pin descriptors ex */
Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->Filter.Descriptor->PinDescriptors, FilterDescriptor->PinDescriptorSize * FilterDescriptor->PinDescriptorsCount,
FilterDescriptor->PinDescriptorSize * FilterDescriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
DPRINT("IKsFilter_CreateDescriptors _KsEdit failed %lx\n", Status);
return Status;
}
/* store pin instance count */
Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->PinInstanceCount, sizeof(ULONG) * FilterDescriptor->PinDescriptorsCount,
sizeof(ULONG) * FilterDescriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
DPRINT("IKsFilter_CreateDescriptors _KsEdit failed %lx\n", Status);
return Status;
}
/* store instantiated pin arrays */
Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->FirstPin, sizeof(PKSPIN) * FilterDescriptor->PinDescriptorsCount,
sizeof(PKSPIN) * FilterDescriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
DPRINT("IKsFilter_CreateDescriptors _KsEdit failed %lx\n", Status);
return Status;
}
/* add new pin factory */
RtlMoveMemory((PVOID)This->Filter.Descriptor->PinDescriptors, FilterDescriptor->PinDescriptors, FilterDescriptor->PinDescriptorSize * FilterDescriptor->PinDescriptorsCount);
/* allocate process pin index */
Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->ProcessPinIndex, sizeof(KSPROCESSPIN_INDEXENTRY) * FilterDescriptor->PinDescriptorsCount,
sizeof(KSPROCESSPIN_INDEXENTRY) * FilterDescriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
DPRINT("IKsFilter_CreateDescriptors _KsEdit failed %lx\n", Status);
return Status;
}
}
if (FilterDescriptor->ConnectionsCount)
{
/* modify connections array */
Status = _KsEdit(This->Filter.Bag,
(PVOID*)&This->Filter.Descriptor->Connections,
FilterDescriptor->ConnectionsCount * sizeof(KSTOPOLOGY_CONNECTION),
FilterDescriptor->ConnectionsCount * sizeof(KSTOPOLOGY_CONNECTION),
0);
This->Topology.TopologyConnections = This->Filter.Descriptor->Connections;
This->Topology.TopologyConnectionsCount = ((PKSFILTER_DESCRIPTOR)This->Filter.Descriptor)->ConnectionsCount = FilterDescriptor->ConnectionsCount;
}
if (FilterDescriptor->NodeDescriptorsCount)
{
/* sanity check */
ASSERT(FilterDescriptor->NodeDescriptors);
/* FIXME handle variable sized node descriptors */
ASSERT(FilterDescriptor->NodeDescriptorSize == sizeof(KSNODE_DESCRIPTOR));
This->Topology.TopologyNodes = AllocateItem(NonPagedPool, sizeof(GUID) * FilterDescriptor->NodeDescriptorsCount);
/* allocate topology node types array */
if (!This->Topology.TopologyNodes)
{
DPRINT("IKsFilter_CreateDescriptors OutOfMemory TopologyNodesCount %lu\n", FilterDescriptor->NodeDescriptorsCount);
return STATUS_INSUFFICIENT_RESOURCES;
}
This->Topology.TopologyNodesNames = AllocateItem(NonPagedPool, sizeof(GUID) * FilterDescriptor->NodeDescriptorsCount);
/* allocate topology names array */
if (!This->Topology.TopologyNodesNames)
{
FreeItem((PVOID)This->Topology.TopologyNodes);
DPRINT("IKsFilter_CreateDescriptors OutOfMemory TopologyNodesCount %lu\n", FilterDescriptor->NodeDescriptorsCount);
return STATUS_INSUFFICIENT_RESOURCES;
}
DPRINT("NodeDescriptorCount %lu\n", FilterDescriptor->NodeDescriptorsCount);
for(Index = 0; Index < FilterDescriptor->NodeDescriptorsCount; Index++)
{
DPRINT("Index %lu Type %p Name %p\n", Index, FilterDescriptor->NodeDescriptors[Index].Type, FilterDescriptor->NodeDescriptors[Index].Name);
/* copy topology type */
if (FilterDescriptor->NodeDescriptors[Index].Type)
RtlMoveMemory((PVOID)&This->Topology.TopologyNodes[Index], FilterDescriptor->NodeDescriptors[Index].Type, sizeof(GUID));
/* copy topology name */
if (FilterDescriptor->NodeDescriptors[Index].Name)
RtlMoveMemory((PVOID)&This->Topology.TopologyNodesNames[Index], FilterDescriptor->NodeDescriptors[Index].Name, sizeof(GUID));
}
}
/* done! */
return STATUS_SUCCESS;
}
NTSTATUS
IKsFilter_CopyFilterDescriptor(
IKsFilterImpl * This,
const KSFILTER_DESCRIPTOR* FilterDescriptor)
{
NTSTATUS Status;
KSAUTOMATION_TABLE AutomationTable;
This->Filter.Descriptor = AllocateItem(NonPagedPool, sizeof(KSFILTER_DESCRIPTOR));
if (!This->Filter.Descriptor)
return STATUS_INSUFFICIENT_RESOURCES;
Status = KsAddItemToObjectBag(This->Filter.Bag, (PVOID)This->Filter.Descriptor, NULL);
if (!NT_SUCCESS(Status))
{
FreeItem((PVOID)This->Filter.Descriptor);
This->Filter.Descriptor = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
/* copy filter descriptor fields */
RtlMoveMemory((PVOID)This->Filter.Descriptor, FilterDescriptor, sizeof(KSFILTER_DESCRIPTOR));
/* zero automation table */
RtlZeroMemory(&AutomationTable, sizeof(KSAUTOMATION_TABLE));
/* setup filter property sets */
AutomationTable.PropertyItemSize = sizeof(KSPROPERTY_ITEM);
AutomationTable.PropertySetsCount = 2;
AutomationTable.PropertySets = FilterPropertySet;
/* merge filter automation table */
Status = KsMergeAutomationTables((PKSAUTOMATION_TABLE*)&This->Filter.Descriptor->AutomationTable, (PKSAUTOMATION_TABLE)FilterDescriptor->AutomationTable, &AutomationTable, This->Filter.Bag);
return Status;
}
VOID
IKsFilter_AddPin(
PKSFILTER Filter,
PKSPIN Pin)
{
PKSPIN NextPin, CurPin;
PKSBASIC_HEADER BasicHeader;
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
/* sanity check */
ASSERT(Pin->Id < This->Filter.Descriptor->PinDescriptorsCount);
if (This->FirstPin[Pin->Id] == NULL)
{
/* welcome first pin */
This->FirstPin[Pin->Id] = Pin;
This->PinInstanceCount[Pin->Id]++;
return;
}
/* get first pin */
CurPin = This->FirstPin[Pin->Id];
do
{
/* get next instantiated pin */
NextPin = KsPinGetNextSiblingPin(CurPin);
if (!NextPin)
break;
NextPin = CurPin;
}while(NextPin != NULL);
/* get basic header */
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)CurPin - sizeof(KSBASIC_HEADER));
/* store pin */
BasicHeader->Next.Pin = Pin;
}
VOID
IKsFilter_RemovePin(
PKSFILTER Filter,
PKSPIN Pin)
{
PKSPIN NextPin, CurPin, LastPin;
PKSBASIC_HEADER BasicHeader;
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
/* sanity check */
ASSERT(Pin->Id < This->Filter.Descriptor->PinDescriptorsCount);
/* get first pin */
CurPin = This->FirstPin[Pin->Id];
LastPin = NULL;
do
{
/* get next instantiated pin */
NextPin = KsPinGetNextSiblingPin(CurPin);
if (CurPin == Pin)
{
if (LastPin)
{
/* get basic header of last pin */
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)LastPin - sizeof(KSBASIC_HEADER));
BasicHeader->Next.Pin = NextPin;
}
else
{
/* erase last pin */
This->FirstPin[Pin->Id] = NextPin;
}
/* decrement pin instance count */
This->PinInstanceCount[Pin->Id]--;
return;
}
if (!NextPin)
break;
LastPin = CurPin;
NextPin = CurPin;
}while(NextPin != NULL);
/* pin not found */
ASSERT(0);
}
NTSTATUS
NTAPI
IKsFilter_DispatchCreatePin(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
IKsFilterImpl * This;
PKSOBJECT_CREATE_ITEM CreateItem;
PKSPIN_CONNECT Connect;
NTSTATUS Status;
DPRINT("IKsFilter_DispatchCreatePin\n");
/* get the create item */
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
/* get the filter object */
This = (IKsFilterImpl*)CreateItem->Context;
/* sanity check */
ASSERT(This->Header.Type == KsObjectTypeFilter);
/* acquire control mutex */
KeWaitForSingleObject(This->Header.ControlMutex, Executive, KernelMode, FALSE, NULL);
/* now validate the connect request */
Status = KspValidateConnectRequest(Irp, This->Filter.Descriptor->PinDescriptorsCount, (PVOID)This->Filter.Descriptor->PinDescriptors, This->Filter.Descriptor->PinDescriptorSize, &Connect);
DPRINT("IKsFilter_DispatchCreatePin KsValidateConnectRequest %lx\n", Status);
if (NT_SUCCESS(Status))
{
/* sanity check */
ASSERT(Connect->PinId < This->Filter.Descriptor->PinDescriptorsCount);
DPRINT("IKsFilter_DispatchCreatePin KsValidateConnectRequest PinId %lu CurrentInstanceCount %lu MaxPossible %lu\n", Connect->PinId,
This->PinInstanceCount[Connect->PinId],
This->Filter.Descriptor->PinDescriptors[Connect->PinId].InstancesPossible);
if (This->PinInstanceCount[Connect->PinId] < This->Filter.Descriptor->PinDescriptors[Connect->PinId].InstancesPossible)
{
/* create the pin */
Status = KspCreatePin(DeviceObject, Irp, This->Header.KsDevice, This->FilterFactory, (IKsFilter*)&This->Header.OuterUnknown, Connect, (KSPIN_DESCRIPTOR_EX*)&This->Filter.Descriptor->PinDescriptors[Connect->PinId]);
DPRINT("IKsFilter_DispatchCreatePin KspCreatePin %lx\n", Status);
}
else
{
/* maximum instance count reached, bye-bye */
Status = STATUS_UNSUCCESSFUL;
DPRINT("IKsFilter_DispatchCreatePin MaxInstance %lu CurInstance %lu %lx\n", This->Filter.Descriptor->PinDescriptors[Connect->PinId].InstancesPossible, This->PinInstanceCount[Connect->PinId]);
}
}
/* release control mutex */
KeReleaseMutex(This->Header.ControlMutex, FALSE);
if (Status != STATUS_PENDING)
{
/* complete request */
Irp->IoStatus.Status = Status;
CompleteRequest(Irp, IO_NO_INCREMENT);
}
/* done */
DPRINT("IKsFilter_DispatchCreatePin Result %lx\n", Status);
return Status;
}
NTSTATUS
NTAPI
IKsFilter_DispatchCreateNode(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
UNIMPLEMENTED
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
CompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
VOID
IKsFilter_AttachFilterToFilterFactory(
IKsFilterImpl * This,
PKSFILTERFACTORY FilterFactory)
{
PKSBASIC_HEADER BasicHeader;
PKSFILTER Filter;
/* get filter factory basic header */
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)FilterFactory - sizeof(KSBASIC_HEADER));
/* sanity check */
ASSERT(BasicHeader->Type == KsObjectTypeFilterFactory);
if (BasicHeader->FirstChild.FilterFactory == NULL)
{
/* welcome first instantiated filter */
BasicHeader->FirstChild.Filter = &This->Filter;
return;
}
/* set to first entry */
Filter = BasicHeader->FirstChild.Filter;
do
{
/* get basic header */
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Filter - sizeof(KSBASIC_HEADER));
/* sanity check */
ASSERT(BasicHeader->Type == KsObjectTypeFilter);
if (BasicHeader->Next.Filter)
{
/* iterate to next filter factory */
Filter = BasicHeader->Next.Filter;
}
else
{
/* found last entry */
break;
}
}while(TRUE);
/* attach filter factory */
BasicHeader->Next.Filter = &This->Filter;
}
VOID
IKsFilter_RemoveFilterFromFilterFactory(
IKsFilterImpl * This,
PKSFILTERFACTORY FilterFactory)
{
PKSBASIC_HEADER BasicHeader;
PKSFILTER Filter, LastFilter;
/* get filter factory basic header */
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)FilterFactory - sizeof(KSBASIC_HEADER));
/* sanity check */
ASSERT(BasicHeader->Type == KsObjectTypeFilterFactory);
ASSERT(BasicHeader->FirstChild.Filter != NULL);
/* set to first entry */
Filter = BasicHeader->FirstChild.Filter;
LastFilter = NULL;
do
{
if (Filter == &This->Filter)
{
if (LastFilter)
{
/* get basic header */
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)LastFilter - sizeof(KSBASIC_HEADER));
/* remove filter instance */
BasicHeader->Next.Filter = This->Header.Next.Filter;
break;
}
else
{
/* remove filter instance */
BasicHeader->FirstChild.Filter = This->Header.Next.Filter;
break;
}
}
/* get basic header */
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Filter - sizeof(KSBASIC_HEADER));
/* sanity check */
ASSERT(BasicHeader->Type == KsObjectTypeFilter);
LastFilter = Filter;
if (BasicHeader->Next.Filter)
{
/* iterate to next filter factory */
Filter = BasicHeader->Next.Filter;
}
else
{
/* filter is not in list */
ASSERT(0);
break;
}
}while(TRUE);
}
NTSTATUS
NTAPI
KspCreateFilter(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN IKsFilterFactory *iface)
{
IKsFilterImpl * This;
IKsDevice *KsDevice;
PKSFILTERFACTORY Factory;
PIO_STACK_LOCATION IoStack;
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
PKSOBJECT_CREATE_ITEM CreateItem;
/* get device extension */
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* get the filter factory */
Factory = iface->lpVtbl->GetStruct(iface);
if (!Factory || !Factory->FilterDescriptor || !Factory->FilterDescriptor->Dispatch || !Factory->FilterDescriptor->Dispatch->Create)
{
/* Sorry it just will not work */
return STATUS_UNSUCCESSFUL;
}
/* allocate filter instance */
This = AllocateItem(NonPagedPool, sizeof(IKsFilterImpl));
if (!This)
{
DPRINT("KspCreateFilter OutOfMemory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
/* initialize object bag */
This->Filter.Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
if (!This->Filter.Bag)
{
/* no memory */
FreeItem(This);
DPRINT("KspCreateFilter OutOfMemory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
KsDevice = (IKsDevice*)&DeviceExtension->DeviceHeader->BasicHeader.OuterUnknown;
KsDevice->lpVtbl->InitializeObjectBag(KsDevice, (PKSIOBJECT_BAG)This->Filter.Bag, NULL);
/* copy filter descriptor */
Status = IKsFilter_CopyFilterDescriptor(This, Factory->FilterDescriptor);
if (!NT_SUCCESS(Status))
{
/* not enough memory */
FreeItem(This->Filter.Bag);
FreeItem(This);
DPRINT("KspCreateFilter IKsFilter_CopyFilterDescriptor failed %lx\n", Status);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* get current irp stack */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* allocate create items */
CreateItem = AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM) * 2);
if (!CreateItem)
{
/* no memory */
FreeItem(This->Filter.Bag);
FreeItem(This);
DPRINT("KspCreateFilter OutOfMemory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
DPRINT("KspCreateFilter Flags %lx\n", Factory->FilterDescriptor->Flags);
/* initialize pin create item */
CreateItem[0].Create = IKsFilter_DispatchCreatePin;
CreateItem[0].Context = (PVOID)This;
CreateItem[0].Flags = KSCREATE_ITEM_FREEONSTOP;
RtlInitUnicodeString(&CreateItem[0].ObjectClass, KSSTRING_Pin);
/* initialize node create item */
CreateItem[1].Create = IKsFilter_DispatchCreateNode;
CreateItem[1].Context = (PVOID)This;
CreateItem[1].Flags = KSCREATE_ITEM_FREEONSTOP;
RtlInitUnicodeString(&CreateItem[1].ObjectClass, KSSTRING_TopologyNode);
/* initialize filter instance */
This->ref = 1;
This->Header.OuterUnknown = (PUNKNOWN)&vt_IKsFilter;
This->lpVtblKsControl = &vt_IKsControl;
This->Factory = Factory;
This->FilterFactory = iface;
This->FileObject = IoStack->FileObject;
KeInitializeMutex(&This->ProcessingMutex, 0);
/* initialize basic header */
This->Header.KsDevice = &DeviceExtension->DeviceHeader->KsDevice;
This->Header.Parent.KsFilterFactory = iface->lpVtbl->GetStruct(iface);
This->Header.Type = KsObjectTypeFilter;
This->Header.ControlMutex = &This->ControlMutex;
KeInitializeMutex(This->Header.ControlMutex, 0);
InitializeListHead(&This->Header.EventList);
KeInitializeSpinLock(&This->Header.EventListLock);
/* allocate the stream descriptors */
Status = IKsFilter_CreateDescriptors(This, (PKSFILTER_DESCRIPTOR)Factory->FilterDescriptor);
if (!NT_SUCCESS(Status))
{
/* what can go wrong, goes wrong */
FreeItem(This);
FreeItem(CreateItem);
DPRINT("IKsFilter_CreateDescriptors failed with %lx\n", Status);
return Status;
}
/* does the filter have a filter dispatch */
if (Factory->FilterDescriptor->Dispatch)
{
/* does it have a create routine */
if (Factory->FilterDescriptor->Dispatch->Create)
{
/* now let driver initialize the filter instance */
ASSERT(This->Header.KsDevice);
ASSERT(This->Header.KsDevice->Started);
Status = Factory->FilterDescriptor->Dispatch->Create(&This->Filter, Irp);
if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
{
/* driver failed to initialize */
DPRINT1("Driver: Status %x\n", Status);
/* free filter instance */
FreeItem(This);
FreeItem(CreateItem);
return Status;
}
}
}
/* now allocate the object header */
Status = KsAllocateObjectHeader((PVOID*)&This->ObjectHeader, 2, CreateItem, Irp, &DispatchTable);
if (!NT_SUCCESS(Status))
{
/* failed to allocate object header */
DPRINT1("Failed to allocate object header %x\n", Status);
return Status;
}
/* initialize object header extra fields */
This->ObjectHeader->Type = KsObjectTypeFilter;
This->ObjectHeader->Unknown = (PUNKNOWN)&This->Header.OuterUnknown;
This->ObjectHeader->ObjectType = (PVOID)&This->Filter;
/* attach filter to filter factory */
IKsFilter_AttachFilterToFilterFactory(This, This->Header.Parent.KsFilterFactory);
/* completed initialization */
DPRINT("KspCreateFilter done %lx KsDevice %p\n", Status, This->Header.KsDevice);
return Status;
}
/*
@implemented
*/
KSDDKAPI
VOID
NTAPI
KsFilterAcquireProcessingMutex(
IN PKSFILTER Filter)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
KeWaitForSingleObject(&This->ProcessingMutex, Executive, KernelMode, FALSE, NULL);
}
/*
@implemented
*/
KSDDKAPI
VOID
NTAPI
KsFilterReleaseProcessingMutex(
IN PKSFILTER Filter)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
KeReleaseMutex(&This->ProcessingMutex, FALSE);
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsFilterAddTopologyConnections (
IN PKSFILTER Filter,
IN ULONG NewConnectionsCount,
IN const KSTOPOLOGY_CONNECTION *const NewTopologyConnections)
{
ULONG Count;
NTSTATUS Status;
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
DPRINT("KsFilterAddTopologyConnections\n");
ASSERT(This->Filter.Descriptor);
Count = This->Filter.Descriptor->ConnectionsCount + NewConnectionsCount;
/* modify connections array */
Status = _KsEdit(This->Filter.Bag,
(PVOID*)&This->Filter.Descriptor->Connections,
Count * sizeof(KSTOPOLOGY_CONNECTION),
This->Filter.Descriptor->ConnectionsCount * sizeof(KSTOPOLOGY_CONNECTION),
0);
if (!NT_SUCCESS(Status))
{
/* failed */
DPRINT("KsFilterAddTopologyConnections KsEdit failed with %lx\n", Status);
return Status;
}
/* FIXME verify connections */
/* copy new connections */
RtlMoveMemory((PVOID)&This->Filter.Descriptor->Connections[This->Filter.Descriptor->ConnectionsCount],
NewTopologyConnections,
NewConnectionsCount * sizeof(KSTOPOLOGY_CONNECTION));
/* update topology */
This->Topology.TopologyConnectionsCount += NewConnectionsCount;
((PKSFILTER_DESCRIPTOR)This->Filter.Descriptor)->ConnectionsCount += NewConnectionsCount;
This->Topology.TopologyConnections = This->Filter.Descriptor->Connections;
return Status;
}
/*
@unimplemented
*/
KSDDKAPI
VOID
NTAPI
KsFilterAttemptProcessing(
IN PKSFILTER Filter,
IN BOOLEAN Asynchronous)
{
//UNIMPLEMENTED
}
/*
@unimplemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsFilterCreateNode (
IN PKSFILTER Filter,
IN const KSNODE_DESCRIPTOR *const NodeDescriptor,
OUT PULONG NodeID)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsFilterCreatePinFactory (
IN PKSFILTER Filter,
IN const KSPIN_DESCRIPTOR_EX *const InPinDescriptor,
OUT PULONG PinID)
{
ULONG Count;
NTSTATUS Status;
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
DPRINT("KsFilterCreatePinFactory\n");
/* calculate new count */
Count = This->Filter.Descriptor->PinDescriptorsCount + 1;
/* sanity check */
ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
/* modify pin descriptors ex array */
Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->Filter.Descriptor->PinDescriptors, Count * This->Filter.Descriptor->PinDescriptorSize, This->Filter.Descriptor->PinDescriptorsCount * This->Filter.Descriptor->PinDescriptorSize, 0);
if (!NT_SUCCESS(Status))
{
/* failed */
DPRINT("KsFilterCreatePinFactory _KsEdit failed with %lx\n", Status);
return Status;
}
/* modify pin instance count array */
Status = _KsEdit(This->Filter.Bag,(PVOID*)&This->PinInstanceCount, sizeof(ULONG) * Count, sizeof(ULONG) * This->Filter.Descriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
/* failed */
DPRINT("KsFilterCreatePinFactory _KsEdit failed with %lx\n", Status);
return Status;
}
/* modify first pin array */
Status = _KsEdit(This->Filter.Bag,(PVOID*)&This->FirstPin, sizeof(PKSPIN) * Count, sizeof(PKSPIN) * This->Filter.Descriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
/* failed */
DPRINT("KsFilterCreatePinFactory _KsEdit failed with %lx\n", Status);
return Status;
}
/* add new pin factory */
RtlMoveMemory((PVOID)&This->Filter.Descriptor->PinDescriptors[This->Filter.Descriptor->PinDescriptorsCount], InPinDescriptor, sizeof(KSPIN_DESCRIPTOR_EX));
/* allocate process pin index */
Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->ProcessPinIndex, sizeof(KSPROCESSPIN_INDEXENTRY) * Count,
sizeof(KSPROCESSPIN_INDEXENTRY) * This->Filter.Descriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
DPRINT("KsFilterCreatePinFactory _KsEdit failed %lx\n", Status);
return Status;
}
/* store new pin id */
*PinID = This->Filter.Descriptor->PinDescriptorsCount;
/* increment pin descriptor count */
((PKSFILTER_DESCRIPTOR)This->Filter.Descriptor)->PinDescriptorsCount++;
DPRINT("KsFilterCreatePinFactory done\n");
return STATUS_SUCCESS;
}
/*
@unimplemented
*/
KSDDKAPI
PKSGATE
NTAPI
KsFilterGetAndGate(
IN PKSFILTER Filter)
{
UNIMPLEMENTED
return NULL;
}
/*
@implemented
*/
KSDDKAPI
ULONG
NTAPI
KsFilterGetChildPinCount(
IN PKSFILTER Filter,
IN ULONG PinId)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
if (PinId >= This->Filter.Descriptor->PinDescriptorsCount)
{
/* index is out of bounds */
return 0;
}
/* return pin instance count */
return This->PinInstanceCount[PinId];
}
/*
@implemented
*/
KSDDKAPI
PKSPIN
NTAPI
KsFilterGetFirstChildPin(
IN PKSFILTER Filter,
IN ULONG PinId)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
if (PinId >= This->Filter.Descriptor->PinDescriptorsCount)
{
/* index is out of bounds */
return NULL;
}
/* return first pin index */
return This->FirstPin[PinId];
}
/*
@implemented
*/
KSDDKAPI
VOID
NTAPI
KsFilterRegisterPowerCallbacks(
IN PKSFILTER Filter,
IN PFNKSFILTERPOWER Sleep OPTIONAL,
IN PFNKSFILTERPOWER Wake OPTIONAL)
{
IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
This->Sleep = Sleep;
This->Wake = Wake;
}
/*
@implemented
*/
KSDDKAPI
PKSFILTER
NTAPI
KsGetFilterFromIrp(
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PKSIOBJECT_HEADER ObjectHeader;
DPRINT("KsGetFilterFromIrp\n");
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* sanity check */
ASSERT(IoStack->FileObject);
/* get object header */
ObjectHeader = (PKSIOBJECT_HEADER)IoStack->FileObject->FsContext2;
if (ObjectHeader->Type == KsObjectTypeFilter)
{
/* irp is targeted at the filter */
return (PKSFILTER)ObjectHeader->ObjectType;
}
else if (ObjectHeader->Type == KsObjectTypePin)
{
/* irp is for a pin */
return KsPinGetParentFilter((PKSPIN)ObjectHeader->ObjectType);
}
else
{
/* irp is unappropiate to retrieve a filter */
return NULL;
}
}