IKsControlVtbl *lpVtblKsControl;
IKsFilterFactory * FilterFactory;
+ IKsProcessingObjectVtbl * lpVtblKsProcessingObject;
LONG ref;
PKSIOBJECT_HEADER ObjectHeader;
KMUTEX ControlMutex;
KMUTEX ProcessingMutex;
+ PKSWORKER Worker;
+ WORK_QUEUE_ITEM WorkItem;
+ KSGATE Gate;
PFNKSFILTERPOWER Sleep;
PFNKSFILTERPOWER Wake;
}
};
+NTSTATUS
+NTAPI
+IKsProcessingObject_fnQueryInterface(
+ IKsProcessingObject * iface,
+ IN REFIID refiid,
+ OUT PVOID* Output)
+{
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsProcessingObject);
+
+ if (IsEqualGUIDAligned(refiid, &IID_IUnknown))
+ {
+ *Output = &This->Header.OuterUnknown;
+ _InterlockedIncrement(&This->ref);
+ return STATUS_SUCCESS;
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+ULONG
+NTAPI
+IKsProcessingObject_fnAddRef(
+ IKsProcessingObject * iface)
+{
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsProcessingObject);
+
+ return InterlockedIncrement(&This->ref);
+}
+
+ULONG
+NTAPI
+IKsProcessingObject_fnRelease(
+ IKsProcessingObject * iface)
+{
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsProcessingObject);
+
+ InterlockedDecrement(&This->ref);
+
+ /* Return new reference count */
+ return This->ref;
+}
+
+VOID
+NTAPI
+IKsProcessingObject_fnProcessingObjectWork(
+ IKsProcessingObject * iface)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER TimeOut;
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsProcessingObject);
+
+ DPRINT1("processing object\n");
+ /* first check if running at passive level */
+ if (KeGetCurrentIrql() == PASSIVE_LEVEL)
+ {
+ /* acquire processing mutex */
+ KeWaitForSingleObject(&This->ControlMutex, Executive, KernelMode, FALSE, NULL);
+ }
+ else
+ {
+ /* dispatch level processing */
+ if (KeReadStateMutex(&This->ControlMutex) == 0)
+ {
+ /* some thread was faster */
+ DPRINT1("processing object too slow\n");
+ return;
+ }
+
+ /* acquire processing mutex */
+ TimeOut.QuadPart = 0LL;
+ Status = KeWaitForSingleObject(&This->ControlMutex, Executive, KernelMode, FALSE, &TimeOut);
+
+ if (Status == STATUS_TIMEOUT)
+ {
+ /* some thread was faster */
+ DPRINT1("processing object too slow\n");
+ return;
+ }
+ }
+
+ do
+ {
+
+ /* check if the and-gate has been enabled again */
+ if (&This->Gate.Count != 0)
+ {
+ /* gate is open */
+ DPRINT1("processing object gate open\n");
+ break;
+ }
+
+ DPRINT1("IKsProcessingObject_fnProcessingObjectWork not implemented\n");
+ ASSERT(0);
+
+ }while(TRUE);
+
+ /* release process mutex */
+ KeReleaseMutex(&This->ProcessingMutex, FALSE);
+}
+
+PKSGATE
+NTAPI
+IKsProcessingObject_fnGetAndGate(
+ IKsProcessingObject * iface)
+{
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsProcessingObject);
+
+ /* return and gate */
+ return &This->Gate;
+}
+
+VOID
+NTAPI
+IKsProcessingObject_fnProcess(
+ IKsProcessingObject * iface,
+ IN BOOLEAN Asynchronous)
+{
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsProcessingObject);
+
+ /* should the action be asynchronous */
+ if (Asynchronous)
+ {
+ /* queue work item */
+ KsQueueWorkItem(This->Worker, &This->WorkItem);
+DPRINT1("queueing\n");
+ /* done */
+ return;
+ }
+
+ /* does the filter require explicit deferred processing */
+ if ((This->Filter.Descriptor->Flags & (KSFILTER_FLAG_DISPATCH_LEVEL_PROCESSING | KSFILTER_FLAG_CRITICAL_PROCESSING | KSFILTER_FLAG_HYPERCRITICAL_PROCESSING)) &&
+ KeGetCurrentIrql() > PASSIVE_LEVEL)
+ {
+ /* queue work item */
+ KsQueueWorkItem(This->Worker, &This->WorkItem);
+DPRINT1("queueing\n");
+ /* done */
+ return;
+ }
+DPRINT1("invoke\n");
+ /* call worker routine directly */
+ iface->lpVtbl->ProcessingObjectWork(iface);
+}
+
+VOID
+NTAPI
+IKsProcessingObject_fnReset(
+ IKsProcessingObject * iface)
+{
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(iface, IKsFilterImpl, lpVtblKsProcessingObject);
+
+ /* acquire processing mutex */
+ KeWaitForSingleObject(&This->ProcessingMutex, Executive, KernelMode, FALSE, NULL);
+
+ /* check if the filter supports dispatch routines */
+ if (This->Filter.Descriptor->Dispatch)
+ {
+ /* has the filter a reset routine */
+ if (This->Filter.Descriptor->Dispatch->Reset)
+ {
+ /* reset filter */
+ This->Filter.Descriptor->Dispatch->Reset(&This->Filter);
+ }
+ }
+
+ /* release process mutex */
+ KeReleaseMutex(&This->ProcessingMutex, FALSE);
+}
+
+VOID
+NTAPI
+IKsProcessingObject_fnTriggerNotification(
+ IKsProcessingObject * iface)
+{
+
+}
+
+static IKsProcessingObjectVtbl vt_IKsProcessingObject =
+{
+ IKsProcessingObject_fnQueryInterface,
+ IKsProcessingObject_fnAddRef,
+ IKsProcessingObject_fnRelease,
+ IKsProcessingObject_fnProcessingObjectWork,
+ IKsProcessingObject_fnGetAndGate,
+ IKsProcessingObject_fnProcess,
+ IKsProcessingObject_fnReset,
+ IKsProcessingObject_fnTriggerNotification
+};
+
+
+//---------------------------------------------------------------------------------------------------------
NTSTATUS
NTAPI
IKsControl_fnQueryInterface(
/* 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),
+ (This->Filter.Descriptor->PinDescriptorsCount + 1) * sizeof(PVOID),
+ This->Filter.Descriptor->PinDescriptorsCount * sizeof(PVOID),
0);
if (NT_SUCCESS(Status))
{
if (Pins[Index] == ProcessPin)
{
- RtlMoveMemory(&Pins[Index], &Pins[Index + 1], (Count - (Index + 1)) * sizeof(PKSPROCESSPIN));
+ RtlMoveMemory(&Pins[Index], &Pins[Index + 1], (Count - (Index + 1)) * sizeof(PVOID));
break;
}
Irp->IoStatus.Status = Status;
/* complete and forget irp */
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ CompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
return Status;
/* save the result */
Irp->IoStatus.Status = Status;
/* complete irp */
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ CompleteRequest(Irp, IO_NO_INCREMENT);
/* remove our instance from the filter factory */
IKsFilter_RemoveFilterFromFilterFactory(This, This->Factory);
/* complete and forget */
Irp->IoStatus.Status = Status;
/* complete irp */
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ CompleteRequest(Irp, IO_NO_INCREMENT);
}
/* done */
}
/* ignore custom structs for now */
- ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
+ ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
ASSERT(This->Filter.Descriptor->PinDescriptorsCount > Pin->PinId);
Instances = (KSPIN_CINSTANCES*)Data;
}
/* ignore custom structs for now */
- ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
+ ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
ASSERT(This->Filter.Descriptor->PinDescriptorsCount > Pin->PinId);
Result = (PULONG)Data;
}
/* ignore custom structs for now */
- ASSERT(This->Filter.Descriptor->PinDescriptorSize == sizeof(KSPIN_DESCRIPTOR_EX));
+ 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 ||
break;
}
- DataRange = UlongToPtr(PtrToUlong(DataRange) + DataRange->FormatSize);
+ DataRange = (PKSDATARANGE)((PUCHAR)DataRange + DataRange->FormatSize);
/* FIXME make sure its 64 bit aligned */
ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
}
UNIMPLEMENTED
Status = STATUS_NOT_FOUND;
}
- //DPRINT("KspPinPropertyHandler Pins %lu Request->Id %lu Status %lx\n", This->PinDescriptorCount, Request->Id, Status);
+ DPRINT("KspPinPropertyHandler Pins %lu Request->Id %lu Status %lx\n", This->Filter.Descriptor->PinDescriptorsCount, Request->Id, Status);
return Status;
SetCount = FilterInstance->Descriptor->AutomationTable->PropertySetsCount;
PropertySet = FilterInstance->Descriptor->AutomationTable->PropertySets;
PropertyItemSize = FilterInstance->Descriptor->AutomationTable->PropertyItemSize;
+ // FIXME: handle variable sized property items
+ ASSERT(PropertyItemSize == sizeof(KSPROPERTY_ITEM));
+ PropertyItemSize = 0;
}
/* needed for our property handlers */
}
RtlStringFromGUID(&Property->Set, &GuidString);
+ DPRINT("IKsFilter_DispatchDeviceIoControl property PinCount %x\n", FilterInstance->Descriptor->PinDescriptorsCount);
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);
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ CompleteRequest(Irp, IO_NO_INCREMENT);
}
/* done */
{
ULONG Index = 0;
NTSTATUS Status;
+ PKSNODE_DESCRIPTOR NodeDescriptor;
/* initialize pin descriptors */
This->FirstPin = NULL;
}
/* store instantiated pin arrays */
- Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->FirstPin, sizeof(PKSPIN) * FilterDescriptor->PinDescriptorsCount,
- sizeof(PKSPIN) * FilterDescriptor->PinDescriptorsCount, 0);
+ Status = _KsEdit(This->Filter.Bag, (PVOID*)&This->FirstPin, sizeof(PVOID) * FilterDescriptor->PinDescriptorsCount,
+ sizeof(PVOID) * FilterDescriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
/* sanity check */
ASSERT(FilterDescriptor->NodeDescriptors);
- /* FIXME handle variable sized node descriptors */
- ASSERT(FilterDescriptor->NodeDescriptorSize == sizeof(KSNODE_DESCRIPTOR));
+ /* sanity check */
+ ASSERT(FilterDescriptor->NodeDescriptorSize >= sizeof(KSNODE_DESCRIPTOR));
This->Topology.TopologyNodes = AllocateItem(NonPagedPool, sizeof(GUID) * FilterDescriptor->NodeDescriptorsCount);
/* allocate topology node types array */
}
DPRINT("NodeDescriptorCount %lu\n", FilterDescriptor->NodeDescriptorsCount);
+ NodeDescriptor = (PKSNODE_DESCRIPTOR)FilterDescriptor->NodeDescriptors;
for(Index = 0; Index < FilterDescriptor->NodeDescriptorsCount; Index++)
{
- DPRINT("Index %lu Type %p Name %p\n", Index, FilterDescriptor->NodeDescriptors[Index].Type, FilterDescriptor->NodeDescriptors[Index].Name);
+ DPRINT("Index %lu Type %p Name %p\n", Index, NodeDescriptor->Type, NodeDescriptor->Name);
/* copy topology type */
- if (FilterDescriptor->NodeDescriptors[Index].Type)
- RtlMoveMemory((PVOID)&This->Topology.TopologyNodes[Index], FilterDescriptor->NodeDescriptors[Index].Type, sizeof(GUID));
+ if (NodeDescriptor->Type)
+ RtlMoveMemory((PVOID)&This->Topology.TopologyNodes[Index], NodeDescriptor->Type, sizeof(GUID));
/* copy topology name */
- if (FilterDescriptor->NodeDescriptors[Index].Name)
- RtlMoveMemory((PVOID)&This->Topology.TopologyNodesNames[Index], FilterDescriptor->NodeDescriptors[Index].Name, sizeof(GUID));
+ if (NodeDescriptor->Name)
+ RtlMoveMemory((PVOID)&This->Topology.TopologyNodesNames[Index], NodeDescriptor->Name, sizeof(GUID));
+
+ // next node descriptor
+ NodeDescriptor = (PKSNODE_DESCRIPTOR)((ULONG_PTR)NodeDescriptor + FilterDescriptor->NodeDescriptorSize);
}
}
/* done! */
/* sanity check */
ASSERT(Connect->PinId < This->Filter.Descriptor->PinDescriptorsCount);
- DPRINT("IKsFilter_DispatchCreatePin KsValidateConnectRequest PinId %lu CurrentInstanceCount %lu MaxPossible %lu\n", Connect->PinId,
+ DPRINT("IKsFilter_DispatchCreatePin KsValidateConnectRequest PinId %lu CurrentInstanceCount %lu MaxPossible %lu\n", Connect->PinId,
This->PinInstanceCount[Connect->PinId],
This->Filter.Descriptor->PinDescriptors[Connect->PinId].InstancesPossible);
{
/* complete request */
Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ CompleteRequest(Irp, IO_NO_INCREMENT);
}
/* done */
{
UNIMPLEMENTED
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ CompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
}while(TRUE);
}
+VOID
+NTAPI
+IKsFilter_FilterCentricWorker(
+ IN PVOID Ctx)
+{
+ IKsProcessingObject * Object = (IKsProcessingObject*)Ctx;
+
+ /* sanity check */
+ ASSERT(Object);
+
+ /* perform work */
+ Object->lpVtbl->ProcessingObjectWork(Object);
+}
+
NTSTATUS
NTAPI
KspCreateFilter(
/* get the filter factory */
Factory = iface->lpVtbl->GetStruct(iface);
- if (!Factory || !Factory->FilterDescriptor || !Factory->FilterDescriptor->Dispatch || !Factory->FilterDescriptor->Dispatch->Create)
+ if (!Factory || !Factory->FilterDescriptor)
{
/* Sorry it just will not work */
return STATUS_UNSUCCESSFUL;
}
+ if (Factory->FilterDescriptor->Flags & KSFILTER_FLAG_DENY_USERMODE_ACCESS)
+ {
+ if (Irp->RequestorMode == UserMode)
+ {
+ /* filter not accessible from user mode */
+ DPRINT1("Access denied\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
/* allocate filter instance */
This = AllocateItem(NonPagedPool, sizeof(IKsFilterImpl));
if (!This)
{
- DPRINT("KspCreateFilter OutOfMemory\n");
+ DPRINT1("KspCreateFilter OutOfMemory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
{
/* no memory */
FreeItem(This);
- DPRINT("KspCreateFilter OutOfMemory\n");
+ DPRINT1("KspCreateFilter OutOfMemory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
KsDevice = (IKsDevice*)&DeviceExtension->DeviceHeader->BasicHeader.OuterUnknown;
/* no memory */
FreeItem(This->Filter.Bag);
FreeItem(This);
- DPRINT("KspCreateFilter OutOfMemory\n");
+ DPRINT1("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;
This->ref = 1;
This->Header.OuterUnknown = (PUNKNOWN)&vt_IKsFilter;
This->lpVtblKsControl = &vt_IKsControl;
+ This->lpVtblKsProcessingObject = &vt_IKsProcessingObject;
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);
InitializeListHead(&This->Header.EventList);
KeInitializeSpinLock(&This->Header.EventListLock);
+ /* initialize and gate */
+ KsGateInitializeAnd(&This->Gate, NULL);
+
+ /* FIXME initialize and gate based on pin flags */
+
+ /* initialize work item */
+ ExInitializeWorkItem(&This->WorkItem, IKsFilter_FilterCentricWorker, (PVOID)This->lpVtblKsProcessingObject);
+
+ /* allocate counted work item */
+ Status = KsRegisterCountedWorker(HyperCriticalWorkQueue, &This->WorkItem, &This->Worker);
+ if (!NT_SUCCESS(Status))
+ {
+ /* what can go wrong, goes wrong */
+ DPRINT1("KsRegisterCountedWorker failed with %lx\n", Status);
+ FreeItem(This);
+ FreeItem(CreateItem);
+ return Status;
+ }
+
/* allocate the stream descriptors */
Status = IKsFilter_CreateDescriptors(This, (PKSFILTER_DESCRIPTOR)Factory->FilterDescriptor);
if (!NT_SUCCESS(Status))
{
/* what can go wrong, goes wrong */
+ DPRINT1("IKsFilter_CreateDescriptors failed with %lx\n", Status);
+ KsUnregisterWorker(This->Worker);
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)
{
DPRINT1("Driver: Status %x\n", Status);
/* free filter instance */
+ KsUnregisterWorker(This->Worker);
FreeItem(This);
FreeItem(CreateItem);
return Status;
IKsFilter_AttachFilterToFilterFactory(This, This->Header.Parent.KsFilterFactory);
/* completed initialization */
- DPRINT("KspCreateFilter done %lx KsDevice %p\n", Status, This->Header.KsDevice);
+ DPRINT1("KspCreateFilter done %lx KsDevice %p\n", Status, This->Header.KsDevice);
return Status;
}
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
VOID
IN PKSFILTER Filter,
IN BOOLEAN Asynchronous)
{
- UNIMPLEMENTED
+ PKSGATE Gate;
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
+
+ /* get gate */
+ Gate = This->lpVtblKsProcessingObject->GetAndGate((IKsProcessingObject*)This->lpVtblKsProcessingObject);
+
+ if (!KsGateCaptureThreshold(Gate))
+ {
+ /* filter control gate is closed */
+ return;
+ }
+DPRINT1("processing\n");
+ /* try initiate processing */
+ This->lpVtblKsProcessingObject->Process((IKsProcessingObject*)This->lpVtblKsProcessingObject, Asynchronous);
}
/*
}
/* modify first pin array */
- Status = _KsEdit(This->Filter.Bag,(PVOID*)&This->FirstPin, sizeof(PKSPIN) * Count, sizeof(PKSPIN) * This->Filter.Descriptor->PinDescriptorsCount, 0);
+ Status = _KsEdit(This->Filter.Bag,(PVOID*)&This->FirstPin, sizeof(PVOID) * Count, sizeof(PVOID) * This->Filter.Descriptor->PinDescriptorsCount, 0);
if (!NT_SUCCESS(Status))
{
/* failed */
KsFilterGetAndGate(
IN PKSFILTER Filter)
{
- UNIMPLEMENTED
- return NULL;
+ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
+
+ /* return and-gate */
+ return &This->Gate;
}
/*