mirror of
https://github.com/reactos/reactos.git
synced 2024-07-10 14:45:06 +00:00
ea8f6ef311
- 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
1816 lines
53 KiB
C
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;
|
|
}
|
|
}
|