--- /dev/null
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+/*
+ * 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;
++ IKsProcessingObjectVtbl * lpVtblKsProcessingObject;
+ LONG ref;
+
+ PKSIOBJECT_HEADER ObjectHeader;
+ KSTOPOLOGY Topology;
+ PKSFILTERFACTORY Factory;
+ PFILE_OBJECT FileObject;
+ KMUTEX ControlMutex;
+ KMUTEX ProcessingMutex;
+
++ PKSWORKER Worker;
++ WORK_QUEUE_ITEM WorkItem;
++ KSGATE Gate;
+
+ 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
++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(
+ 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 */
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ 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 */
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ 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 */
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ 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;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ 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;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ 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;
- if (!Factory || !Factory->FilterDescriptor || !Factory->FilterDescriptor->Dispatch || !Factory->FilterDescriptor->Dispatch->Create)
++ 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);
+}
+
++VOID
++NTAPI
++IKsFilter_FilterCentricWorker(
++ IN PVOID Ctx)
++{
++ IKsProcessingObject * Object = (IKsProcessingObject*)Ctx;
++
++ /* sanity check */
++ ASSERT(Object);
++
++ /* perform work */
++ Object->lpVtbl->ProcessingObjectWork(Object);
++}
++
+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);
+
- DPRINT("KspCreateFilter OutOfMemory\n");
++ 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;
+ }
+
+ /* initialize object bag */
+ This->Filter.Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
+ if (!This->Filter.Bag)
+ {
+ /* no memory */
+ FreeItem(This);
- DPRINT("KspCreateFilter OutOfMemory\n");
++ DPRINT1("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 Flags %lx\n", Factory->FilterDescriptor->Flags);
-
++ DPRINT1("KspCreateFilter OutOfMemory\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
- DPRINT("IKsFilter_CreateDescriptors failed with %lx\n", Status);
+ /* 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->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);
+ This->Header.Type = KsObjectTypeFilter;
+ This->Header.ControlMutex = &This->ControlMutex;
+ KeInitializeMutex(This->Header.ControlMutex, 0);
+ 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("KspCreateFilter done %lx KsDevice %p\n", Status, This->Header.KsDevice);
+ 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 */
++ KsUnregisterWorker(This->Worker);
+ 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 */
- @unimplemented
++ DPRINT1("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
++ @implemented
+*/
+KSDDKAPI
+VOID
+NTAPI
+KsFilterAttemptProcessing(
+ IN PKSFILTER Filter,
+ IN BOOLEAN Asynchronous)
+{
- UNIMPLEMENTED
- return NULL;
++ 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);
+}
+
+/*
+ @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)
+{
++ IKsFilterImpl * This = (IKsFilterImpl*)CONTAINING_RECORD(Filter, IKsFilterImpl, Filter);
++
++ /* return and-gate */
++ return &This->Gate;
+}
+
+/*
+ @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;
+ }
+}
--- /dev/null
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel Streaming
+ * FILE: drivers/ksfilter/ks/factory.c
+ * PURPOSE: KS Allocator functions
+ * PROGRAMMER: Johannes Anderwald
+ */
+
+
+#include "priv.h"
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsDispatchQuerySecurity(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PKSOBJECT_CREATE_ITEM CreateItem;
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+ ULONG Length;
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* get create item */
+ CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
+
+ if (!CreateItem || !CreateItem->SecurityDescriptor)
+ {
+ /* no create item */
+ Irp->IoStatus.Status = STATUS_NO_SECURITY_ON_OBJECT;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NO_SECURITY_ON_OBJECT;
+ }
+
+
+ /* get input length */
+ Length = IoStack->Parameters.QuerySecurity.Length;
+
+ /* clone the security descriptor */
+ Status = SeQuerySecurityDescriptorInfo(&IoStack->Parameters.QuerySecurity.SecurityInformation, (PSECURITY_DESCRIPTOR)Irp->UserBuffer, &Length, &CreateItem->SecurityDescriptor);
+
+ DPRINT("SeQuerySecurityDescriptorInfo Status %x\n", Status);
+ /* store result */
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Length;
+
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsDispatchSetSecurity(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PKSOBJECT_CREATE_ITEM CreateItem;
+ PIO_STACK_LOCATION IoStack;
+ PGENERIC_MAPPING Mapping;
+ PSECURITY_DESCRIPTOR Descriptor;
+ NTSTATUS Status;
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* get create item */
+ CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
+
+ if (!CreateItem || !CreateItem->SecurityDescriptor)
+ {
+ /* no create item */
+ Irp->IoStatus.Status = STATUS_NO_SECURITY_ON_OBJECT;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NO_SECURITY_ON_OBJECT;
+ }
+
+ /* backup old descriptor */
+ Descriptor = CreateItem->SecurityDescriptor;
+
+ /* get generic mapping */
+ Mapping = IoGetFileObjectGenericMapping();
+
+ /* change security descriptor */
+ Status = SeSetSecurityDescriptorInfo(NULL, /*FIXME */
+ &IoStack->Parameters.SetSecurity.SecurityInformation,
+ IoStack->Parameters.SetSecurity.SecurityDescriptor,
+ &CreateItem->SecurityDescriptor,
+ NonPagedPool,
+ Mapping);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* free old descriptor */
+ FreeItem(Descriptor);
+
+ /* mark create item as changed */
+ CreateItem->Flags |= KSCREATE_ITEM_SECURITYCHANGED;
+ }
+
+ /* store result */
+ Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+/*
+ @unimplemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsDispatchSpecificMethod(
+ IN PIRP Irp,
+ IN PFNKSHANDLER Handler)
+{
+ UNIMPLEMENTED;
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsReadFile(
+ IN PFILE_OBJECT FileObject,
+ IN PKEVENT Event OPTIONAL,
+ IN PVOID PortContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ IN ULONG Key OPTIONAL,
+ IN KPROCESSOR_MODE RequestorMode)
+{
+ PDEVICE_OBJECT DeviceObject;
+ PIRP Irp;
+ NTSTATUS Status;
+ BOOLEAN Result;
+ KEVENT LocalEvent;
+
+ if (Event)
+ {
+ /* make sure event is reset */
+ KeClearEvent(Event);
+ }
+
+ if (RequestorMode == UserMode)
+ {
+ /* probe the user buffer */
+ _SEH2_TRY
+ {
+ ProbeForWrite(Buffer, Length, sizeof(UCHAR));
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Invalid user buffer provided\n");
+ return Status;
+ }
+ }
+
+ /* get corresponding device object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+ /* fast-io read is only available for kernel mode clients */
+ if (RequestorMode == KernelMode && ExGetPreviousMode() == KernelMode &&
+ DeviceObject->DriverObject->FastIoDispatch->FastIoRead)
+ {
+ /* call fast io write */
+ Result = DeviceObject->DriverObject->FastIoDispatch->FastIoRead(FileObject, &FileObject->CurrentByteOffset, Length, TRUE, Key, Buffer, IoStatusBlock, DeviceObject);
+
+ if (Result && NT_SUCCESS(IoStatusBlock->Status))
+ {
+ /* request was handeled and succeeded */
+ return STATUS_SUCCESS;
+ }
+ }
+
+ /* do the slow way */
+ if (!Event)
+ {
+ /* initialize temp event */
+ KeInitializeEvent(&LocalEvent, NotificationEvent, FALSE);
+ Event = &LocalEvent;
+ }
+
+ /* build the irp packet */
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, Buffer, Length, &FileObject->CurrentByteOffset, Event, IoStatusBlock);
+ if (!Irp)
+ {
+ /* not enough resources */
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* send the packet */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ /* operation is pending, is sync file object */
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ {
+ /* it is so wait */
+ KeWaitForSingleObject(Event, Executive, RequestorMode, FALSE, NULL);
+ Status = IoStatusBlock->Status;
+ }
+ }
+ /* return result */
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsWriteFile(
+ IN PFILE_OBJECT FileObject,
+ IN PKEVENT Event OPTIONAL,
+ IN PVOID PortContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ IN ULONG Key OPTIONAL,
+ IN KPROCESSOR_MODE RequestorMode)
+{
+ PDEVICE_OBJECT DeviceObject;
+ PIRP Irp;
+ NTSTATUS Status;
+ BOOLEAN Result;
+ KEVENT LocalEvent;
+
+ if (Event)
+ {
+ /* make sure event is reset */
+ KeClearEvent(Event);
+ }
+
+ if (RequestorMode == UserMode)
+ {
+ /* probe the user buffer */
+ _SEH2_TRY
+ {
+ ProbeForRead(Buffer, Length, sizeof(UCHAR));
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Invalid user buffer provided\n");
+ return Status;
+ }
+ }
+
+ /* get corresponding device object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+ /* fast-io write is only available for kernel mode clients */
+ if (RequestorMode == KernelMode && ExGetPreviousMode() == KernelMode &&
+ DeviceObject->DriverObject->FastIoDispatch->FastIoWrite)
+ {
+ /* call fast io write */
+ Result = DeviceObject->DriverObject->FastIoDispatch->FastIoWrite(FileObject, &FileObject->CurrentByteOffset, Length, TRUE, Key, Buffer, IoStatusBlock, DeviceObject);
+
+ if (Result && NT_SUCCESS(IoStatusBlock->Status))
+ {
+ /* request was handeled and succeeded */
+ return STATUS_SUCCESS;
+ }
+ }
+
+ /* do the slow way */
+ if (!Event)
+ {
+ /* initialize temp event */
+ KeInitializeEvent(&LocalEvent, NotificationEvent, FALSE);
+ Event = &LocalEvent;
+ }
+
+ /* build the irp packet */
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, Buffer, Length, &FileObject->CurrentByteOffset, Event, IoStatusBlock);
+ if (!Irp)
+ {
+ /* not enough resources */
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* send the packet */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ /* operation is pending, is sync file object */
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ {
+ /* it is so wait */
+ KeWaitForSingleObject(Event, Executive, RequestorMode, FALSE, NULL);
+ Status = IoStatusBlock->Status;
+ }
+ }
+ /* return result */
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsQueryInformationFile(
+ IN PFILE_OBJECT FileObject,
+ OUT PVOID FileInformation,
+ IN ULONG Length,
+ IN FILE_INFORMATION_CLASS FileInformationClass)
+{
+ PDEVICE_OBJECT DeviceObject;
+ PFAST_IO_DISPATCH FastIoDispatch;
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ IO_STATUS_BLOCK IoStatus;
+ KEVENT Event;
+ LARGE_INTEGER Offset;
+ IO_STATUS_BLOCK StatusBlock;
+ NTSTATUS Status;
+
+ /* get related file object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+ /* get fast i/o table */
+ FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+ /* is there a fast table */
+ if (FastIoDispatch)
+ {
+ /* check the class */
+ if (FileInformationClass == FileBasicInformation)
+ {
+ /* use FastIoQueryBasicInfo routine */
+ if (FastIoDispatch->FastIoQueryBasicInfo)
+ {
+ return FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE, (PFILE_BASIC_INFORMATION)FileInformation, &IoStatus, DeviceObject);
+ }
+ }
+ else if (FileInformationClass == FileStandardInformation)
+ {
+ /* use FastIoQueryBasicInfo routine */
+ if (FastIoDispatch->FastIoQueryBasicInfo)
+ {
+ return FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE, (PFILE_STANDARD_INFORMATION)FileInformation, &IoStatus, DeviceObject);
+ }
+ }
+ }
+ /* clear event */
+ KeClearEvent(&FileObject->Event);
+
+ /* initialize event */
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ /* set offset to zero */
+ Offset.QuadPart = 0L;
+
+ /* build the request */
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_QUERY_INFORMATION, IoGetRelatedDeviceObject(FileObject), NULL, 0, &Offset, &Event, &StatusBlock);
+
+ if (!Irp)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* get next stack location */
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ /* setup parameters */
+ IoStack->Parameters.QueryFile.FileInformationClass = FileInformationClass;
+ IoStack->Parameters.QueryFile.Length = Length;
+ Irp->AssociatedIrp.SystemBuffer = FileInformation;
+
+
+ /* call the driver */
+ Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ /* wait for the operation to complete */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+ /* is object sync */
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ Status = FileObject->FinalStatus;
+ else
+ Status = StatusBlock.Status;
+ }
+
+ /* done */
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsSetInformationFile(
+ IN PFILE_OBJECT FileObject,
+ IN PVOID FileInformation,
+ IN ULONG Length,
+ IN FILE_INFORMATION_CLASS FileInformationClass)
+{
+ PIO_STACK_LOCATION IoStack;
+ PDEVICE_OBJECT DeviceObject;
+ PIRP Irp;
+ PVOID Buffer;
+ KEVENT Event;
+ LARGE_INTEGER Offset;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+
+ /* get related device object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+ /* copy file information */
+ Buffer = AllocateItem(NonPagedPool, Length);
+ if (!Buffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(Buffer, Length, sizeof(UCHAR));
+ RtlMoveMemory(Buffer, FileInformation, Length);
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* invalid user buffer */
+ FreeItem(Buffer);
+ return Status;
+ }
+
+ /* initialize the event */
+ KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+
+ /* zero offset */
+ Offset.QuadPart = 0LL;
+
+ /* build the irp */
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SET_INFORMATION, DeviceObject, NULL, 0, &Offset, &Event, &IoStatus);
+
+ if (!Irp)
+ {
+ /* failed to allocate irp */
+ FreeItem(Buffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* get next stack location */
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ /* set irp parameters */
+ IoStack->Parameters.SetFile.FileInformationClass = FileInformationClass;
+ IoStack->Parameters.SetFile.Length = Length;
+ IoStack->Parameters.SetFile.FileObject = FileObject;
+ Irp->AssociatedIrp.SystemBuffer = Buffer;
+ Irp->UserBuffer = FileInformation;
+
+ /* dispatch the irp */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING)
+ {
+ /* wait untill the operation has completed */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ /* is a sync file object */
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ Status = FileObject->FinalStatus;
+ else
+ Status = IoStatus.Status;
+ }
+ /* done */
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsStreamIo(
+ IN PFILE_OBJECT FileObject,
+ IN PKEVENT Event OPTIONAL,
+ IN PVOID PortContext OPTIONAL,
+ IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
+ IN PVOID CompletionContext OPTIONAL,
+ IN KSCOMPLETION_INVOCATION CompletionInvocationFlags OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN OUT PVOID StreamHeaders,
+ IN ULONG Length,
+ IN ULONG Flags,
+ IN KPROCESSOR_MODE RequestorMode)
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStack;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ LARGE_INTEGER Offset;
+ PKSIOBJECT_HEADER ObjectHeader;
+ BOOLEAN Ret;
+
+ /* get related device object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+ /* sanity check */
+ ASSERT(DeviceObject != NULL);
+
+ /* is there a event provided */
+ if (Event)
+ {
+ /* reset event */
+ KeClearEvent(Event);
+ }
+
+ if (RequestorMode || ExGetPreviousMode() == KernelMode)
+ {
+ /* requestor is from kernel land */
+ ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext2;
+
+ if (ObjectHeader)
+ {
+ /* there is a object header */
+ if (Flags == KSSTREAM_READ)
+ {
+ /* is fast read supported */
+ if (ObjectHeader->DispatchTable.FastRead)
+ {
+ /* call fast read dispatch routine */
+ Ret = ObjectHeader->DispatchTable.FastRead(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject);
+
+ if (Ret)
+ {
+ /* the request was handeled */
+ return IoStatusBlock->Status;
+ }
+ }
+ }
+ else if (Flags == KSSTREAM_WRITE)
+ {
+ /* is fast write supported */
+ if (ObjectHeader->DispatchTable.FastWrite)
+ {
+ /* call fast write dispatch routine */
+ Ret = ObjectHeader->DispatchTable.FastWrite(FileObject, NULL, Length, FALSE, 0, StreamHeaders, IoStatusBlock, DeviceObject);
+
+ if (Ret)
+ {
+ /* the request was handeled */
+ return IoStatusBlock->Status;
+ }
+ }
+ }
+ }
+ }
+
+ /* clear file object event */
+ KeClearEvent(&FileObject->Event);
+
+ /* set the offset to zero */
+ Offset.QuadPart = 0LL;
+
+ /* now build the irp */
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_DEVICE_CONTROL,
+ DeviceObject, (PVOID)StreamHeaders, Length, &Offset, Event, IoStatusBlock);
+ if (!Irp)
+ {
+ /* not enough memory */
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* setup irp parameters */
+ Irp->RequestorMode = RequestorMode;
+ Irp->Overlay.AsynchronousParameters.UserApcContext = PortContext;
+ Irp->Tail.Overlay.OriginalFileObject = FileObject;
+ Irp->UserBuffer = StreamHeaders;
+
+ /* get next irp stack location */
+ IoStack = IoGetNextIrpStackLocation(Irp);
+ /* setup stack parameters */
+ IoStack->FileObject = FileObject;
+ IoStack->Parameters.DeviceIoControl.InputBufferLength = Length;
+ IoStack->Parameters.DeviceIoControl.Type3InputBuffer = StreamHeaders;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = (Flags == KSSTREAM_READ ? IOCTL_KS_READ_STREAM : IOCTL_KS_WRITE_STREAM);
+
+ if (CompletionRoutine)
+ {
+ /* setup completion routine for async processing */
+ IoSetCompletionRoutine(Irp, CompletionRoutine, CompletionContext, (CompletionInvocationFlags & KsInvokeOnSuccess), (CompletionInvocationFlags & KsInvokeOnError), (CompletionInvocationFlags & KsInvokeOnCancel));
+ }
+
+ /* now call the driver */
+ Status = IoCallDriver(DeviceObject, Irp);
+ /* done */
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsProbeStreamIrp(
+ IN PIRP Irp,
+ IN ULONG ProbeFlags,
+ IN ULONG HeaderSize)
+{
+ PMDL Mdl;
+ PVOID Buffer;
+ LOCK_OPERATION Operation;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PKSSTREAM_HEADER StreamHeader;
+ PIO_STACK_LOCATION IoStack;
+ ULONG Length;
+ BOOLEAN AllocateMdl = FALSE;
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (Irp->RequestorMode == KernelMode || Irp->AssociatedIrp.SystemBuffer)
+ {
+ if (Irp->RequestorMode == KernelMode)
+ {
+ /* no need to allocate stream header */
+ Irp->AssociatedIrp.SystemBuffer = Irp->UserBuffer;
+ }
+AllocMdl:
+ /* check if alloc mdl flag is passed */
+ if (!(ProbeFlags & KSPROBE_ALLOCATEMDL))
+ {
+ /* nothing more to do */
+ return STATUS_SUCCESS;
+ }
+ if (Irp->MdlAddress)
+ {
+ProbeMdl:
+ if (ProbeFlags & KSPROBE_PROBEANDLOCK)
+ {
+ if (Irp->MdlAddress->MdlFlags & (MDL_PAGES_LOCKED | MDL_SOURCE_IS_NONPAGED_POOL))
+ {
+ if (ProbeFlags & KSPROBE_SYSTEMADDRESS)
+ {
+ _SEH2_TRY
+ {
+ /* loop through all mdls and probe them */
+ Mdl = Irp->MdlAddress;
+ do
+ {
+ /* the mapping can fail */
+ Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
+
+ if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
+ {
+ /* no need to probe these pages */
+ Buffer = Mdl->MappedSystemVa;
+ }
+ else
+ {
+ /* probe that mdl */
+ Buffer = MmMapLockedPages(Mdl, KernelMode);
+ }
+
+ /* check if the mapping succeeded */
+ if (!Buffer)
+ {
+ /* raise exception we'll catch */
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ /* iterate to next mdl */
+ Mdl = Mdl->Next;
+
+ }while(Mdl);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ } _SEH2_END;
+ }
+ }
+ else
+ {
+ _SEH2_TRY
+ {
+ /* loop through all mdls and probe them */
+ Mdl = Irp->MdlAddress;
+
+ /* determine operation */
+ if (!(ProbeFlags & KSPROBE_STREAMWRITE) || (ProbeFlags & KSPROBE_MODIFY))
+ {
+ /* operation is read / modify stream, need write access */
+ Operation = IoWriteAccess;
+ }
+ else
+ {
+ /* operation is write to device, so we need read access */
+ Operation = IoReadAccess;
+ }
+
+ do
+ {
+ /* probe the pages */
+ MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
+
+ if (ProbeFlags & KSPROBE_SYSTEMADDRESS)
+ {
+ /* the mapping can fail */
+ Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
+
+ if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
+ {
+ /* no need to probe these pages */
+ Buffer = Mdl->MappedSystemVa;
+ }
+ else
+ {
+ /* probe that mdl */
+ Buffer = MmMapLockedPages(Mdl, KernelMode);
+ }
+
+ /* check if the mapping succeeded */
+ if (!Buffer)
+ {
+ /* raise exception we'll catch */
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ }
+
+ /* iterate to next mdl */
+ Mdl = Mdl->Next;
+
+ }while(Mdl);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ } _SEH2_END;
+ }
+ }
+ return Status;
+ }
+
+ /* check all stream headers */
+ StreamHeader = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
+ ASSERT(StreamHeader);
+ _SEH2_TRY
+ {
+ do
+ {
+ if (HeaderSize)
+ {
+ /* does the supplied header size match stream header size and no type changed */
+ if (StreamHeader->Size != HeaderSize && !(StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED))
+ {
+ /* invalid stream header */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+ }
+ else
+ {
+ /* stream must be at least of size KSSTREAM_HEADER and size must be 8-byte block aligned */
+ if (StreamHeader->Size < sizeof(KSSTREAM_HEADER) || (StreamHeader->Size & 7))
+ {
+ /* invalid stream header */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+ }
+
+ if (Length < StreamHeader->Size)
+ {
+ /* length is too short */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ if (ProbeFlags & KSPROBE_STREAMWRITE)
+ {
+ if (StreamHeader->DataUsed > StreamHeader->FrameExtent)
+ {
+ /* frame extend can never be smaller */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ /* is this stream change packet */
+ if (StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)
+ {
+ if (Length != sizeof(KSSTREAM_HEADER) || (PVOID)StreamHeader != Irp->AssociatedIrp.SystemBuffer)
+ {
+ /* stream changed - must be send in a single packet */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ if (!(ProbeFlags & KSPROBE_ALLOWFORMATCHANGE))
+ {
+ /* caller does not permit format changes */
+ ExRaiseStatus(STATUS_INVALID_PARAMETER);
+ }
+
+ if (StreamHeader->FrameExtent)
+ {
+ /* allocate an mdl */
+ Mdl = IoAllocateMdl(StreamHeader->Data, StreamHeader->FrameExtent, FALSE, TRUE, Irp);
+
+ if (!Mdl)
+ {
+ /* not enough memory */
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ /* break-out to probe for the irp */
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (StreamHeader->DataUsed)
+ {
+ /* DataUsed must be zero for stream read operation */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ if (StreamHeader->OptionsFlags)
+ {
+ /* no flags supported for reading */
+ ExRaiseStatus(STATUS_INVALID_PARAMETER);
+ }
+ }
+
+ if (StreamHeader->FrameExtent)
+ {
+ /* allocate an mdl */
+ ASSERT(Irp->MdlAddress == NULL);
+ Mdl = IoAllocateMdl(StreamHeader->Data, StreamHeader->FrameExtent, FALSE, TRUE, Irp);
+ if (!Mdl)
+ {
+ /* not enough memory */
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ }
+
+ /* move to next stream header */
+ Length -= StreamHeader->Size;
+ StreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamHeader + StreamHeader->Size);
+ }while(Length);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }_SEH2_END;
+
+ /* now probe the allocated mdl's */
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Status %x\n", Status);
+ return Status;
+ }
+ else
+ goto ProbeMdl;
+ }
+
+ /* probe user mode buffers */
+ if (Length && ( (!HeaderSize) || (Length % HeaderSize == 0) || ((ProbeFlags & KSPROBE_ALLOWFORMATCHANGE) && (Length == sizeof(KSSTREAM_HEADER))) ) )
+ {
+ /* allocate stream header buffer */
+ Irp->AssociatedIrp.SystemBuffer = AllocateItem(NonPagedPool, Length);
+
+ if (!Irp->AssociatedIrp.SystemBuffer)
+ {
+ /* no memory */
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* mark irp as buffered so that changes the stream headers are propagated back */
+ Irp->Flags = IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO;
+
+ _SEH2_TRY
+ {
+ if (ProbeFlags & KSPROBE_STREAMWRITE)
+ {
+ if (ProbeFlags & KSPROBE_MODIFY)
+ ProbeForWrite(Irp->UserBuffer, Length, sizeof(UCHAR));
+ else
+ ProbeForRead(Irp->UserBuffer, Length, sizeof(UCHAR));
+ }
+ else
+ {
+ /* stream reads means writing */
+ ProbeForWrite(Irp->UserBuffer, Length, sizeof(UCHAR));
+
+ /* set input operation flags */
+ Irp->Flags |= IRP_INPUT_OPERATION;
+ }
+
+ /* copy stream buffer */
+ RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, Irp->UserBuffer, Length);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }_SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* failed */
+ return Status;
+ }
+
+ if (ProbeFlags & KSPROBE_ALLOCATEMDL)
+ {
+ /* alloc mdls */
+ goto AllocMdl;
+ }
+
+ /* check all stream headers */
+ StreamHeader = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
+
+ _SEH2_TRY
+ {
+ do
+ {
+ if (HeaderSize)
+ {
+ /* does the supplied header size match stream header size and no type changed */
+ if (StreamHeader->Size != HeaderSize && !(StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED))
+ {
+ /* invalid stream header */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+ }
+ else
+ {
+ /* stream must be at least of size KSSTREAM_HEADER and size must be 8-byte block aligned */
+ if (StreamHeader->Size < sizeof(KSSTREAM_HEADER) || (StreamHeader->Size & 7))
+ {
+ /* invalid stream header */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+ }
+
+ if (Length < StreamHeader->Size)
+ {
+ /* length is too short */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ if (ProbeFlags & KSPROBE_STREAMWRITE)
+ {
+ if (StreamHeader->DataUsed > StreamHeader->FrameExtent)
+ {
+ /* frame extend can never be smaller */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ /* is this stream change packet */
+ if (StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TYPECHANGED)
+ {
+ if (Length != sizeof(KSSTREAM_HEADER) || (PVOID)StreamHeader != Irp->AssociatedIrp.SystemBuffer)
+ {
+ /* stream changed - must be send in a single packet */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ if (!(ProbeFlags & KSPROBE_ALLOWFORMATCHANGE))
+ {
+ /* caller does not permit format changes */
+ ExRaiseStatus(STATUS_INVALID_PARAMETER);
+ }
+
+ if (StreamHeader->FrameExtent)
+ {
+ /* allocate an mdl */
+ Mdl = IoAllocateMdl(StreamHeader->Data, StreamHeader->FrameExtent, FALSE, TRUE, Irp);
+
+ if (!Mdl)
+ {
+ /* not enough memory */
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ /* break out to probe for the irp */
+ AllocateMdl = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (StreamHeader->DataUsed)
+ {
+ /* DataUsed must be zero for stream read operation */
+ ExRaiseStatus(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ if (StreamHeader->OptionsFlags)
+ {
+ /* no flags supported for reading */
+ ExRaiseStatus(STATUS_INVALID_PARAMETER);
+ }
+ }
+
+ /* move to next stream header */
+ Length -= StreamHeader->Size;
+ StreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)StreamHeader + StreamHeader->Size);
+ }while(Length);
+
+ }_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }_SEH2_END;
+
+ /* now probe the allocated mdl's */
+ if (NT_SUCCESS(Status))
+ goto AllocMdl;
+ else
+ return Status;
+ }
+
+ return STATUS_INVALID_BUFFER_SIZE;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsAllocateExtraData(
+ IN PIRP Irp,
+ IN ULONG ExtraSize,
+ OUT PVOID* ExtraBuffer)
+{
+ PIO_STACK_LOCATION IoStack;
+ ULONG Count, Index;
+ PUCHAR Buffer, BufferOrg;
+ PKSSTREAM_HEADER Header;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* sanity check */
+ ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(KSSTREAM_HEADER));
+
+ /* get total length */
+ Count = IoStack->Parameters.DeviceIoControl.InputBufferLength / sizeof(KSSTREAM_HEADER);
+
+ /* allocate buffer */
+ Buffer = BufferOrg = AllocateItem(NonPagedPool, Count * (sizeof(KSSTREAM_HEADER) + ExtraSize));
+ if (!Buffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ _SEH2_TRY
+ {
+ /* get input buffer */
+ Header = (PKSSTREAM_HEADER)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+ for(Index = 0; Index < Count; Index++)
+ {
+ /* copy stream header */
+ RtlMoveMemory(Buffer, Header, sizeof(KSSTREAM_HEADER));
+
+ /* move to next header */
+ Header++;
+ /* increment output buffer offset */
+ Buffer += sizeof(KSSTREAM_HEADER) + ExtraSize;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* free buffer on exception */
+ FreeItem(Buffer);
+ return Status;
+ }
+
+ /* store result */
+ *ExtraBuffer = BufferOrg;
+
+ /* done */
+ return STATUS_SUCCESS;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+VOID
+NTAPI
+KsNullDriverUnload(
+ IN PDRIVER_OBJECT DriverObject)
+{
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsDispatchInvalidDeviceRequest(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsDefaultDeviceIoCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ if (IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_PROPERTY &&
+ IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_METHOD &&
+ IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_PROPERTY)
+ {
+ if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_RESET_STATE)
+ {
+ /* fake success */
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ /* request unsupported */
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+ else
+ {
+ /* property / method / event not found */
+ Status = STATUS_PROPSET_NOT_FOUND;
+ }
+
+ /* complete request */
+ Irp->IoStatus.Status = Status;
- DPRINT("KsAddIrpToCancelableQueue QueueHead %p SpinLock %p Irp %p ListLocation %x DriverCancel %p\n", QueueHead, SpinLock, Irp, ListLocation, DriverCancel);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+
+
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+BOOLEAN
+NTAPI
+KsDispatchFastIoDeviceControlFailure(
+ IN PFILE_OBJECT FileObject,
+ IN BOOLEAN Wait,
+ IN PVOID InputBuffer OPTIONAL,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer OPTIONAL,
+ IN ULONG OutputBufferLength,
+ IN ULONG IoControlCode,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ return FALSE;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+BOOLEAN
+NTAPI
+KsDispatchFastReadFailure(
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN ULONG LockKey,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ return FALSE;
+}
+
+
+/*
+ @implemented
+*/
+KSDDKAPI
+VOID
+NTAPI
+KsCancelIo(
+ IN OUT PLIST_ENTRY QueueHead,
+ IN PKSPIN_LOCK SpinLock)
+{
+ PDRIVER_CANCEL OldDriverCancel;
+ PIO_STACK_LOCATION IoStack;
+ PLIST_ENTRY Entry;
+ PLIST_ENTRY NextEntry;
+ PIRP Irp;
+ KIRQL OldLevel;
+
+ /* acquire spinlock */
+ KeAcquireSpinLock(SpinLock, &OldLevel);
+ /* point to first entry */
+ Entry = QueueHead->Flink;
+ /* loop all items */
+ while(Entry != QueueHead)
+ {
+ /* get irp offset */
+ Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
+
+ /* get next entry */
+ NextEntry = Entry->Flink;
+
+ /* set cancelled bit */
+ Irp->Cancel = TRUE;
+
+ /* now set the cancel routine */
+ OldDriverCancel = IoSetCancelRoutine(Irp, NULL);
+ if (OldDriverCancel)
+ {
+ /* this irp hasnt been yet used, so free to cancel */
+ KeReleaseSpinLock(SpinLock, OldLevel);
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* acquire cancel spinlock */
+ IoAcquireCancelSpinLock(&Irp->CancelIrql);
+
+ /* call provided cancel routine */
+ OldDriverCancel(IoStack->DeviceObject, Irp);
+
+ /* re-acquire spinlock */
+ KeAcquireSpinLock(SpinLock, &OldLevel);
+ }
+
+ /* move on to next entry */
+ Entry = NextEntry;
+ }
+
+ /* the irp has already been canceled */
+ KeReleaseSpinLock(SpinLock, OldLevel);
+
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+VOID
+NTAPI
+KsReleaseIrpOnCancelableQueue(
+ IN PIRP Irp,
+ IN PDRIVER_CANCEL DriverCancel OPTIONAL)
+{
+ PKSPIN_LOCK SpinLock;
+ PDRIVER_CANCEL OldDriverCancel;
+ PIO_STACK_LOCATION IoStack;
+ KIRQL OldLevel;
+
+ /* check for required parameters */
+ if (!Irp)
+ return;
+
+ if (!DriverCancel)
+ {
+ /* default to KsCancelRoutine */
+ DriverCancel = KsCancelRoutine;
+ }
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* get internal queue lock */
+ SpinLock = KSQUEUE_SPINLOCK_IRP_STORAGE(Irp);
+
+ /* acquire spinlock */
+ KeAcquireSpinLock(SpinLock, &OldLevel);
+
+ /* now set the cancel routine */
+ OldDriverCancel = IoSetCancelRoutine(Irp, DriverCancel);
+
+ if (Irp->Cancel && OldDriverCancel == NULL)
+ {
+ /* the irp has already been canceled */
+ KeReleaseSpinLock(SpinLock, OldLevel);
+
+ /* cancel routine requires that cancel spinlock is held */
+ IoAcquireCancelSpinLock(&Irp->CancelIrql);
+
+ /* cancel irp */
+ DriverCancel(IoStack->DeviceObject, Irp);
+ }
+ else
+ {
+ /* done */
+ KeReleaseSpinLock(SpinLock, OldLevel);
+ }
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+PIRP
+NTAPI
+KsRemoveIrpFromCancelableQueue(
+ IN OUT PLIST_ENTRY QueueHead,
+ IN PKSPIN_LOCK SpinLock,
+ IN KSLIST_ENTRY_LOCATION ListLocation,
+ IN KSIRP_REMOVAL_OPERATION RemovalOperation)
+{
+ PIRP Irp;
+ PLIST_ENTRY CurEntry;
+ KIRQL OldIrql;
+
+ DPRINT("KsRemoveIrpFromCancelableQueue ListHead %p SpinLock %p ListLocation %x RemovalOperation %x\n", QueueHead, SpinLock, ListLocation, RemovalOperation);
+
+ /* check parameters */
+ if (!QueueHead || !SpinLock)
+ return NULL;
+
+ /* check if parameter ListLocation is valid */
+ if (ListLocation != KsListEntryTail && ListLocation != KsListEntryHead)
+ return NULL;
+
+ /* acquire list lock */
+ KeAcquireSpinLock(SpinLock, &OldIrql);
+
+ /* point to queue head */
+ CurEntry = QueueHead;
+
+ do
+ {
+ /* reset irp to null */
+ Irp = NULL;
+
+ /* iterate to next entry */
+ if (ListLocation == KsListEntryHead)
+ CurEntry = CurEntry->Flink;
+ else
+ CurEntry = CurEntry->Blink;
+
+ /* is the end of list reached */
+ if (CurEntry == QueueHead)
+ {
+ /* reached end of list */
+ break;
+ }
+
+ /* get irp offset */
+ Irp = (PIRP)CONTAINING_RECORD(CurEntry, IRP, Tail.Overlay.ListEntry);
+
+ if (Irp->Cancel)
+ {
+ /* irp has been canceled */
+ break;
+ }
+
+ if (Irp->CancelRoutine)
+ {
+ /* remove cancel routine */
+ Irp->CancelRoutine = NULL;
+
+ if (RemovalOperation == KsAcquireAndRemove || RemovalOperation == KsAcquireAndRemoveOnlySingleItem)
+ {
+ /* remove irp from list */
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+ }
+
+ if (RemovalOperation == KsAcquireAndRemoveOnlySingleItem || RemovalOperation == KsAcquireOnlySingleItem)
+ break;
+ }
+
+ }while(TRUE);
+
+ /* release lock */
+ KeReleaseSpinLock(SpinLock, OldIrql);
+
+ if (!Irp || Irp->CancelRoutine == NULL)
+ {
+ /* either an irp has been acquired or nothing found */
+ return Irp;
+ }
+
+ /* time to remove the canceled irp */
+ IoAcquireCancelSpinLock(&OldIrql);
+ /* acquire list lock */
+ KeAcquireSpinLockAtDpcLevel(SpinLock);
+
+ if (RemovalOperation == KsAcquireAndRemove || RemovalOperation == KsAcquireAndRemoveOnlySingleItem)
+ {
+ /* remove it */
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+ }
+
+ /* release list lock */
+ KeReleaseSpinLockFromDpcLevel(SpinLock);
+
+ /* release cancel spinlock */
+ IoReleaseCancelSpinLock(OldIrql);
+ /* no non canceled irp has been found */
+ return NULL;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsMoveIrpsOnCancelableQueue(
+ IN OUT PLIST_ENTRY SourceList,
+ IN PKSPIN_LOCK SourceLock,
+ IN OUT PLIST_ENTRY DestinationList,
+ IN PKSPIN_LOCK DestinationLock OPTIONAL,
+ IN KSLIST_ENTRY_LOCATION ListLocation,
+ IN PFNKSIRPLISTCALLBACK ListCallback,
+ IN PVOID Context)
+{
+ KIRQL OldLevel;
+ PLIST_ENTRY SrcEntry;
+ PIRP Irp;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!DestinationLock)
+ {
+ /* no destination lock just acquire the source lock */
+ KeAcquireSpinLock(SourceLock, &OldLevel);
+ }
+ else
+ {
+ /* acquire cancel spinlock */
+ IoAcquireCancelSpinLock(&OldLevel);
+
+ /* now acquire source lock */
+ KeAcquireSpinLockAtDpcLevel(SourceLock);
+
+ /* now acquire destination lock */
+ KeAcquireSpinLockAtDpcLevel(DestinationLock);
+ }
+
+ /* point to list head */
+ SrcEntry = SourceList;
+
+ /* now move all irps */
+ while(TRUE)
+ {
+ if (ListLocation == KsListEntryTail)
+ {
+ /* move queue downwards */
+ SrcEntry = SrcEntry->Flink;
+ }
+ else
+ {
+ /* move queue upwards */
+ SrcEntry = SrcEntry->Blink;
+ }
+
+ if (SrcEntry == SourceList)
+ {
+ /* eof list reached */
+ break;
+ }
+
+ /* get irp offset */
+ Irp = (PIRP)CONTAINING_RECORD(SrcEntry, IRP, Tail.Overlay.ListEntry);
+
+ /* now check if irp can be moved */
+ Status = ListCallback(Irp, Context);
+
+ /* check if irp can be moved */
+ if (Status == STATUS_SUCCESS)
+ {
+ /* remove irp from src list */
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
+ if (ListLocation == KsListEntryTail)
+ {
+ /* insert irp end of list */
+ InsertTailList(DestinationList, &Irp->Tail.Overlay.ListEntry);
+ }
+ else
+ {
+ /* insert irp head of list */
+ InsertHeadList(DestinationList, &Irp->Tail.Overlay.ListEntry);
+ }
+
+ /* do we need to update the irp lock */
+ if (DestinationLock)
+ {
+ /* update irp lock */
+ KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) = DestinationLock;
+ }
+ }
+ else
+ {
+ if (Status != STATUS_NO_MATCH)
+ {
+ /* callback decided to stop enumeration */
+ break;
+ }
+
+ /* reset return value */
+ Status = STATUS_SUCCESS;
+ }
+ }
+
+ if (!DestinationLock)
+ {
+ /* release source lock */
+ KeReleaseSpinLock(SourceLock, OldLevel);
+ }
+ else
+ {
+ /* now release destination lock */
+ KeReleaseSpinLockFromDpcLevel(DestinationLock);
+
+ /* now release source lock */
+ KeReleaseSpinLockFromDpcLevel(SourceLock);
+
+
+ /* now release cancel spinlock */
+ IoReleaseCancelSpinLock(OldLevel);
+ }
+
+ /* done */
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+VOID
+NTAPI
+KsRemoveSpecificIrpFromCancelableQueue(
+ IN PIRP Irp)
+{
+ PKSPIN_LOCK SpinLock;
+ KIRQL OldLevel;
+
+ DPRINT("KsRemoveSpecificIrpFromCancelableQueue %p\n", Irp);
+
+ /* get internal queue lock */
+ SpinLock = KSQUEUE_SPINLOCK_IRP_STORAGE(Irp);
+
+ /* acquire spinlock */
+ KeAcquireSpinLock(SpinLock, &OldLevel);
+
+ /* remove the irp from the list */
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
+ /* release spinlock */
+ KeReleaseSpinLock(SpinLock, OldLevel);
+}
+
+
+/*
+ @implemented
+*/
+KSDDKAPI
+VOID
+NTAPI
+KsAddIrpToCancelableQueue(
+ IN OUT PLIST_ENTRY QueueHead,
+ IN PKSPIN_LOCK SpinLock,
+ IN PIRP Irp,
+ IN KSLIST_ENTRY_LOCATION ListLocation,
+ IN PDRIVER_CANCEL DriverCancel OPTIONAL)
+{
+ PDRIVER_CANCEL OldDriverCancel;
+ PIO_STACK_LOCATION IoStack;
+ KIRQL OldLevel;
+
+ /* check for required parameters */
+ if (!QueueHead || !SpinLock || !Irp)
+ return;
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ DPRINT1("KsAddIrpToCancelableQueue QueueHead %p SpinLock %p Irp %p ListLocation %x DriverCancel %p\n", QueueHead, SpinLock, Irp, ListLocation, DriverCancel);
+
+ // HACK for ms portcls
+ if (IoStack->MajorFunction == IRP_MJ_CREATE)
+ {
+ // complete the request
++ DPRINT1("MS HACK\n");
+ Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return;
+ }
+
+
+ if (!DriverCancel)
+ {
+ /* default to KsCancelRoutine */
+ DriverCancel = KsCancelRoutine;
+ }
+
+
+ /* acquire spinlock */
+ KeAcquireSpinLock(SpinLock, &OldLevel);
+
+ if (ListLocation == KsListEntryTail)
+ {
+ /* insert irp to tail of list */
+ InsertTailList(QueueHead, &Irp->Tail.Overlay.ListEntry);
+ }
+ else
+ {
+ /* insert irp to head of list */
+ InsertHeadList(QueueHead, &Irp->Tail.Overlay.ListEntry);
+ }
+
+ /* store internal queue lock */
+ KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) = SpinLock;
+
+ /* now set the cancel routine */
+ OldDriverCancel = IoSetCancelRoutine(Irp, DriverCancel);
+
+ if (Irp->Cancel && OldDriverCancel == NULL)
+ {
+ /* the irp has already been canceled */
+ KeReleaseSpinLock(SpinLock, OldLevel);
+
+ /* cancel routine requires that cancel spinlock is held */
+ IoAcquireCancelSpinLock(&Irp->CancelIrql);
+
+ /* cancel irp */
+ DriverCancel(IoStack->DeviceObject, Irp);
+ }
+ else
+ {
+ /* done */
+ KeReleaseSpinLock(SpinLock, OldLevel);
+ }
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+VOID
+NTAPI
+KsCancelRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PKSPIN_LOCK SpinLock;
+
+ /* get internal queue lock */
+ SpinLock = KSQUEUE_SPINLOCK_IRP_STORAGE(Irp);
+
+ /* acquire spinlock */
+ KeAcquireSpinLockAtDpcLevel(SpinLock);
+
+ /* sanity check */
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ /* release cancel spinlock */
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ /* remove the irp from the list */
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
+ /* release spinlock */
+ KeReleaseSpinLock(SpinLock, Irp->CancelIrql);
+
+ /* has the irp already been canceled */
+ if (Irp->IoStatus.Status != STATUS_CANCELLED)
+ {
+ /* let's complete it */
+ Irp->IoStatus.Status = STATUS_CANCELLED;
- ASSERT(CreateItemEntry->CreateItem->ObjectClass.Buffer);
-
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+}
+
+NTSTATUS
+FindMatchingCreateItem(
+ PLIST_ENTRY ListHead,
+ ULONG BufferSize,
+ LPWSTR Buffer,
+ OUT PCREATE_ITEM_ENTRY *OutCreateItem)
+{
+ PLIST_ENTRY Entry;
+ PCREATE_ITEM_ENTRY CreateItemEntry;
+ UNICODE_STRING RefString;
+ LPWSTR pStr;
+
+ /* get terminator */
+ pStr = wcschr(Buffer, L'\\');
+
+ /* sanity check */
+ ASSERT(pStr != NULL);
+
+ if (pStr == Buffer)
+ {
+ // skip slash
+ RtlInitUnicodeString(&RefString, ++pStr);
+ }
+ else
+ {
+ // request is for pin / node / allocator
+ RefString.Buffer = Buffer;
+ RefString.Length = BufferSize = RefString.MaximumLength = ((ULONG_PTR)pStr - (ULONG_PTR)Buffer);
+ }
+
+ /* point to first entry */
+ Entry = ListHead->Flink;
+
+ /* loop all device items */
+ while(Entry != ListHead)
+ {
+ /* get create item entry */
+ CreateItemEntry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(Entry, CREATE_ITEM_ENTRY, Entry);
+
+ ASSERT(CreateItemEntry->CreateItem);
+
+ if(CreateItemEntry->CreateItem->Flags & KSCREATE_ITEM_WILDCARD)
+ {
+ /* create item is default */
+ *OutCreateItem = CreateItemEntry;
+ return STATUS_SUCCESS;
+ }
+
+ if (!CreateItemEntry->CreateItem->Create)
+ {
+ /* skip free create item */
+ Entry = Entry->Flink;
+ continue;
+ }
+
- BufferSize);
+ DPRINT("CreateItem %S Length %u Request %wZ %u\n", CreateItemEntry->CreateItem->ObjectClass.Buffer,
+ CreateItemEntry->CreateItem->ObjectClass.Length,
+ &RefString,
- if (CreateItemEntry->CreateItem->ObjectClass.Length > BufferSize)
++ RefString.Length);
+
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ if (CreateItemEntry->CreateItem->ObjectClass.Length > RefString.Length)
+ {
+ /* create item doesnt match in length */
+ Entry = Entry->Flink;
+ continue;
+ }
+
+ /* now check if the object class is the same */
+ if (!RtlCompareUnicodeString(&CreateItemEntry->CreateItem->ObjectClass, &RefString, TRUE))
+ {
+ /* found matching create item */
+ *OutCreateItem = CreateItemEntry;
+ return STATUS_SUCCESS;
+ }
+ /* iterate to next */
+ Entry = Entry->Flink;
+ }
+
+ return STATUS_NOT_FOUND;
+}
+
+NTSTATUS
+NTAPI
+KspCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PCREATE_ITEM_ENTRY CreateItemEntry;
+ PIO_STACK_LOCATION IoStack;
+ PDEVICE_EXTENSION DeviceExtension;
+ PKSIDEVICE_HEADER DeviceHeader;
+ PKSIOBJECT_HEADER ObjectHeader;
+ NTSTATUS Status;
+
+ DPRINT("KS / CREATE\n");
+
+ /* get current stack location */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ /* get device extension */
+ DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ /* get device header */
+ DeviceHeader = DeviceExtension->DeviceHeader;
+
+
+ if (IoStack->FileObject->FileName.Buffer == NULL)
+ {
+ /* FIXME Pnp-Issue */
+ DPRINT("Using reference string hack\n");
+ Irp->IoStatus.Information = 0;
+ /* set return status */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+
+ if (IoStack->FileObject->RelatedFileObject != NULL)
+ {
+ /* request is to instantiate a pin / node / clock / allocator */
+ ObjectHeader = (PKSIOBJECT_HEADER)IoStack->FileObject->RelatedFileObject->FsContext2;
+
+ /* sanity check */
+ ASSERT(ObjectHeader);
+
+ /* find a matching a create item */
+ Status = FindMatchingCreateItem(&ObjectHeader->ItemList, IoStack->FileObject->FileName.Length, IoStack->FileObject->FileName.Buffer, &CreateItemEntry);
+ }
+ else
+ {
+ /* request to create a filter */
+ Status = FindMatchingCreateItem(&DeviceHeader->ItemList, IoStack->FileObject->FileName.Length, IoStack->FileObject->FileName.Buffer, &CreateItemEntry);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ /* set object create item */
+ KSCREATE_ITEM_IRP_STORAGE(Irp) = CreateItemEntry->CreateItem;
+
+ /* call create function */
+ Status = CreateItemEntry->CreateItem->Create(DeviceObject, Irp);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* increment create item reference count */
+ InterlockedIncrement(&CreateItemEntry->ReferenceCount);
+ }
+ return Status;
+ }
+
+ Irp->IoStatus.Information = 0;
+ /* set return status */
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+NTAPI
+KspDispatchIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
+ PDEVICE_EXTENSION DeviceExtension;
+ PKSIOBJECT_HEADER ObjectHeader;
+ PKSIDEVICE_HEADER DeviceHeader;
+ PDRIVER_DISPATCH Dispatch;
+ NTSTATUS Status;
+
+ /* get current stack location */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* get device extension */
+ DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ /* get device header */
+ DeviceHeader = DeviceExtension->DeviceHeader;
+
+ ASSERT(IoStack->FileObject);
+
+ /* get object header */
+ ObjectHeader = (PKSIOBJECT_HEADER) IoStack->FileObject->FsContext2;
+
+ if (!ObjectHeader)
+ {
+ /* FIXME Pnp-Issue*/
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ /* complete and forget */
++ CompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+
+ /* sanity check */
+ ASSERT(ObjectHeader);
+ /* store create item */
+ //KSCREATE_ITEM_IRP_STORAGE(Irp) = (PKSOBJECT_CREATE_ITEM)0x12345678; //ObjectHeader->CreateItem;
+
+ /* retrieve matching dispatch function */
+ switch(IoStack->MajorFunction)
+ {
+ case IRP_MJ_CLOSE:
+ Dispatch = ObjectHeader->DispatchTable.Close;
+ break;
+ case IRP_MJ_DEVICE_CONTROL:
+ Dispatch = ObjectHeader->DispatchTable.DeviceIoControl;
+ break;
+ case IRP_MJ_READ:
+ Dispatch = ObjectHeader->DispatchTable.Read;
+ break;
+ case IRP_MJ_WRITE:
+ Dispatch = ObjectHeader->DispatchTable.Write;
+ break;
+ case IRP_MJ_FLUSH_BUFFERS :
+ Dispatch = ObjectHeader->DispatchTable.Flush;
+ break;
+ case IRP_MJ_QUERY_SECURITY:
+ Dispatch = ObjectHeader->DispatchTable.QuerySecurity;
+ break;
+ case IRP_MJ_SET_SECURITY:
+ Dispatch = ObjectHeader->DispatchTable.SetSecurity;
+ break;
+ case IRP_MJ_PNP:
+ Dispatch = KsDefaultDispatchPnp;
+ default:
+ Dispatch = NULL;
+ }
+
+ /* is the request supported */
+ if (Dispatch)
+ {
+ /* now call the dispatch function */
+ Status = Dispatch(DeviceObject, Irp);
+ }
+ else
+ {
+ /* not supported request */
+ Status = KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+ }
+
+ /* done */
+ return Status;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsSetMajorFunctionHandler(
+ IN PDRIVER_OBJECT DriverObject,
+ IN ULONG MajorFunction)
+{
+ DPRINT("KsSetMajorFunctionHandler Function %x\n", MajorFunction);
+
+ switch ( MajorFunction )
+ {
+ case IRP_MJ_CREATE:
+ DriverObject->MajorFunction[MajorFunction] = KspCreate;
+ break;
+ case IRP_MJ_DEVICE_CONTROL:
+ case IRP_MJ_CLOSE:
+ case IRP_MJ_READ:
+ case IRP_MJ_WRITE:
+ case IRP_MJ_FLUSH_BUFFERS :
+ case IRP_MJ_QUERY_SECURITY:
+ case IRP_MJ_SET_SECURITY:
+ DriverObject->MajorFunction[MajorFunction] = KspDispatchIrp;
+ break;
+ default:
+ DPRINT1("NotSupported %x\n", MajorFunction);
+ return STATUS_INVALID_PARAMETER;
+ };
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ @implemented
+*/
+KSDDKAPI
+NTSTATUS
+NTAPI
+KsDispatchIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
+ PKSIDEVICE_HEADER DeviceHeader;
+ PDEVICE_EXTENSION DeviceExtension;
+
+ DPRINT("KsDispatchIrp DeviceObject %p Irp %p\n", DeviceObject, Irp);
+
+ /* get device extension */
+ DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
++
+ /* get device header */
+ DeviceHeader = DeviceExtension->DeviceHeader;
+
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ if (IoStack->MajorFunction <= IRP_MJ_DEVICE_CONTROL)
+ {
+ if (IoStack->MajorFunction == IRP_MJ_CREATE)
+ {
+ /* check internal type */
+ if (DeviceHeader->BasicHeader.OuterUnknown) /* FIXME improve check */
+ {
+ /* AVStream client */
+ return IKsDevice_Create(DeviceObject, Irp);
+ }
+ else
+ {
+ /* external client (portcls) */
+ return KspCreate(DeviceObject, Irp);
+ }
+ }
+
+ switch (IoStack->MajorFunction)
+ {
+ case IRP_MJ_CLOSE:
+ case IRP_MJ_READ:
+ case IRP_MJ_WRITE:
+ case IRP_MJ_FLUSH_BUFFERS:
+ case IRP_MJ_QUERY_SECURITY:
+ case IRP_MJ_SET_SECURITY:
+ case IRP_MJ_PNP:
+ case IRP_MJ_DEVICE_CONTROL:
+ return KspDispatchIrp(DeviceObject, Irp);
+ default:
+ return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+ }
+ }
+
+ /* dispatch power */
+ if (IoStack->MajorFunction == IRP_MJ_POWER)
+ {
+ /* check internal type */
+ if (DeviceHeader->BasicHeader.OuterUnknown) /* FIXME improve check */
+ {
+ /* AVStream client */
+ return IKsDevice_Power(DeviceObject, Irp);
+ }
+ else
+ {
+ /* external client (portcls) */
+ return KsDefaultDispatchPower(DeviceObject, Irp);
+ }
+ }
+ else if (IoStack->MajorFunction == IRP_MJ_PNP) /* dispatch pnp */
+ {
+ /* check internal type */
+ if (DeviceHeader->BasicHeader.OuterUnknown) /* FIXME improve check */
+ {
+ /* AVStream client */
+ return IKsDevice_Pnp(DeviceObject, Irp);
+ }
+ else
+ {
+ /* external client (portcls) */
+ return KsDefaultDispatchPnp(DeviceObject, Irp);
+ }
+ }
+ else if (IoStack->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
+ {
+ /* forward irp */
+ return KsDefaultForwardIrp(DeviceObject, Irp);
+ }
+ else
+ {
+ /* not supported */
+ return KsDispatchInvalidDeviceRequest(DeviceObject, Irp);
+ }
+}
+
+/*
+ @unimplemented
+*/
+KSDDKAPI
+ULONG
+NTAPI
+KsGetNodeIdFromIrp(
+ IN PIRP Irp)
+{
+ UNIMPLEMENTED
+ return KSFILTER_NODE;
+}
+
--- /dev/null
- UNIMPLEMENTED;
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel Streaming
+ * FILE: drivers/ksfilter/swenum/swenum.c
+ * PURPOSE: KS Allocator functions
+ * PROGRAMMER: Johannes Anderwald
+ */
+
+
+#include "precomp.h"
+
+const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
+
+
+NTSTATUS
+NTAPI
+SwDispatchPower(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
++ NTSTATUS Status, PnpStatus;
++ BOOLEAN ChildDevice;
++ PIO_STACK_LOCATION IoStack;
++ PDEVICE_OBJECT PnpDeviceObject = NULL;
++
++ /* get current stack location */
++ IoStack = IoGetCurrentIrpStackLocation(Irp);
++
++ /* check if the device object is a child device */
++ Status = KsIsBusEnumChildDevice(DeviceObject, &ChildDevice);
++
++ /* get bus enum pnp object */
++ PnpStatus = KsGetBusEnumPnpDeviceObject(DeviceObject, &PnpDeviceObject);
++
++ /* check for success */
++ if (!NT_SUCCESS(Status) || !NT_SUCCESS(PnpStatus))
++ {
++ /* start next power irp */
++ PoStartNextPowerIrp(Irp);
++
++ /* just complete the irp */
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++
++ /* complete the irp */
++ IoCompleteRequest(Irp, IO_NO_INCREMENT);
++
++ /* done */
++ return STATUS_SUCCESS;
++ }
++
++ if (IoStack->MinorFunction == IRP_MN_SET_POWER || IoStack->MinorFunction == IRP_MN_QUERY_POWER)
++ {
++ /* fake success */
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++ }
+
-
++ if (!ChildDevice)
++ {
++ /* forward to pnp device object */
++ PoStartNextPowerIrp(Irp);
++
++ /* skip current location */
++ IoSkipCurrentIrpStackLocation(Irp);
++
++ /* done */
++ return PoCallDriver(PnpDeviceObject, Irp);
++ }
++
++ /* start next power irp */
++ PoStartNextPowerIrp(Irp);
+
+ /* just complete the irp */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ /* complete the irp */
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ /* done */
+ return STATUS_SUCCESS;
- if (!NT_SUCCESS(Status))
+}
+
+NTSTATUS
+NTAPI
+SwDispatchPnp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ NTSTATUS Status;
+ BOOLEAN ChildDevice;
+ PIO_STACK_LOCATION IoStack;
+ PDEVICE_OBJECT PnpDeviceObject = NULL;
+
++ /* get current stack location */
++ IoStack = IoGetCurrentIrpStackLocation(Irp);
++
+ /* check if the device object is a child device */
+ Status = KsIsBusEnumChildDevice(DeviceObject, &ChildDevice);
+
+ /* check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* failed */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+
++ DPRINT("SwDispatchPnp ChildDevice %u Request %x\n", ChildDevice, IoStack->MinorFunction);
++
+ /* let ks handle it */
+ Status = KsServiceBusEnumPnpRequest(DeviceObject, Irp);
+
- /* skip current location */
- IoSkipCurrentIrpStackLocation(Irp);
- /* call the pnp device object */
- return IoCallDriver(PnpDeviceObject, Irp);
++ /* check if the request was for a pdo */
++ if (!ChildDevice)
++ {
++ if (Status != STATUS_NOT_SUPPORTED)
++ {
++ /* store result */
++ Irp->IoStatus.Status = Status;
++ }
++
++ /* complete request */
++ IoCompleteRequest(Irp, IO_NO_INCREMENT);
++
++ /* done */
++ return Status;
++ }
++
++ DPRINT("SwDispatchPnp KsServiceBusEnumPnpRequest Status %x\n", Status);
++
++ if (NT_SUCCESS(Status))
+ {
+ /* invalid request or not supported */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+
+ /* get bus enum pnp object */
+ Status = KsGetBusEnumPnpDeviceObject(DeviceObject, &PnpDeviceObject);
+
++ DPRINT("SwDispatchPnp KsGetBusEnumPnpDeviceObject Status %x\n", Status);
++
+ /* check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* failed to get pnp object */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+
+ /* sanity check */
+ ASSERT(PnpDeviceObject);
+
+ /* get current stack location */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
+ {
+ /* delete the device */
+ IoDeleteDevice(DeviceObject);
+ }
++ else
++ {
++ if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCES || IoStack->MinorFunction == IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
++ {
++ /* no resources required */
++ Irp->IoStatus.Information = 0;
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++
++ /* skip current location */
++ IoSkipCurrentIrpStackLocation(Irp);
++
++ /* call the pnp device object */
++ return IoCallDriver(PnpDeviceObject, Irp);
++ }
++
++ if (IoStack->MajorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
++ {
++ /* device cannot be disabled */
++ Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++
++ /* skip current location */
++ IoSkipCurrentIrpStackLocation(Irp);
++
++ /* call the pnp device object */
++ return IoCallDriver(PnpDeviceObject, Irp);
++ }
+
- NTSTATUS Status = STATUS_SUCCESS;
++ if (Status == STATUS_NOT_SUPPORTED)
++ {
++ /* skip current location */
++ IoSkipCurrentIrpStackLocation(Irp);
++
++ /* call the pnp device object */
++ return IoCallDriver(PnpDeviceObject, Irp);
++ }
++ }
++
++ /* complete the request */
++ Irp->IoStatus.Status = Status;
++ IoCompleteRequest(Irp, IO_NO_INCREMENT);
++
++ return Status;
+}
+
+NTSTATUS
+NTAPI
+SwDispatchSystemControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ NTSTATUS Status;
+ BOOLEAN ChildDevice;
+ PDEVICE_OBJECT PnpDeviceObject;
+
+ /* check if the device object is a child device */
+ Status = KsIsBusEnumChildDevice(DeviceObject, &ChildDevice);
+
+ /* check for success */
+ if (NT_SUCCESS(Status))
+ {
+ if (!ChildDevice)
+ {
+ /* bus devices dont support internal requests */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+
+ /* get bus enum pnp object */
+ Status = KsGetBusEnumPnpDeviceObject(DeviceObject, &PnpDeviceObject);
+
+ /* check for success */
+ if (NT_SUCCESS(Status))
+ {
+ /* skip current location */
+ IoSkipCurrentIrpStackLocation(Irp);
+ /* call the pnp device object */
+ return IoCallDriver(PnpDeviceObject, Irp);
+ }
+
+ }
+
+ /* complete the request */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+
+}
+
+NTSTATUS
+NTAPI
+SwDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
- return KsGetBusEnumIdentifier(Irp);
++ NTSTATUS Status;
+
+ /* get current stack location */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SWENUM_INSTALL_INTERFACE)
+ {
+ /* install interface */
+ Status = KsInstallBusEnumInterface(Irp);
++ DPRINT("SwDispatchDeviceControl IOCTL_SWENUM_INSTALL_INTERFACE %x\n", Status);
+ }
+ else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SWENUM_REMOVE_INTERFACE)
+ {
+ /* remove interface */
+ Status = KsRemoveBusEnumInterface(Irp);
++ DPRINT("SwDispatchDeviceControl IOCTL_SWENUM_REMOVE_INTERFACE %x\n", Status);
++
+ }
+ else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SWENUM_GET_BUS_ID)
+ {
+ /* get bus id */
-
++ Status = KsGetBusEnumIdentifier(Irp);
++ DPRINT("SwDispatchDeviceControl IOCTL_SWENUM_GET_BUS_ID %x\n", Status);
++ }
++ else
++ {
++ DPRINT("SwDispatchDeviceControl Unknown IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
++ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ /* store result */
+ Irp->IoStatus.Status = Status;
+
+ /* complete irp */
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ /* done */
+ return Status;
+}
+
+
+NTSTATUS
+NTAPI
+SwDispatchCreate(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ NTSTATUS Status;
+ BOOLEAN ChildDevice;
+
+ /* check if the device object is a child device */
+ Status = KsIsBusEnumChildDevice(DeviceObject, &ChildDevice);
+
++ DPRINT("SwDispatchCreate %x\n", Status);
++
+ /* check for success */
+ if (NT_SUCCESS(Status))
+ {
+ if (ChildDevice)
+ {
+ /* child devices cant create devices */
+ Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ /* perform the create request */
+ Status = KsServiceBusEnumCreateRequest(DeviceObject, Irp);
++ DPRINT("SwDispatchCreate %x\n", Status);
+ }
+
+ /* check the irp is pending */
+ if (Status != STATUS_PENDING)
+ {
+ /* irp is ok to complete */
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+NTAPI
+SwDispatchClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ /* just complete the irp */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ /* complete the irp */
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ /* done */
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS
+NTAPI
+SwAddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT PhysicalDeviceObject)
+{
+ NTSTATUS Status;
+ PDEVICE_OBJECT FunctionalDeviceObject;
+
++ DPRINT("SWENUM AddDevice\n");
+ /* create the device */
+ Status = IoCreateDevice(DriverObject, sizeof(KSDEVICE_HEADER), NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &FunctionalDeviceObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* failed */
+ return Status;
+ }
+
+ /* create the bus enum object */
+ Status = KsCreateBusEnumObject(L"SW", FunctionalDeviceObject, PhysicalDeviceObject, NULL, &KSMEDIUMSETID_Standard, L"Devices");
+
+ /* check for success */
+ if (NT_SUCCESS(Status))
+ {
+ /* set device flags */
+ FunctionalDeviceObject->Flags |= DO_POWER_PAGABLE;
+ FunctionalDeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
+ }
+ else
+ {
+ /* failed to create bus enum object */
+ IoDeleteDevice(FunctionalDeviceObject);
+ }
+
+ /* done */
+ return Status;
+}
+
+VOID
+NTAPI
+SwUnload(
+ IN PDRIVER_OBJECT DriverObject)
+{
+ /* nop */
+}
+
+NTSTATUS
+NTAPI
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPathName)
+{
+
+ /* setup add device routine */
+ DriverObject->DriverExtension->AddDevice = SwAddDevice;
+
+ /* setup unload routine */
+ DriverObject->DriverUnload = SwUnload;
+
+ /* misc irp handling routines */
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = SwDispatchCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = SwDispatchClose;
+ DriverObject->MajorFunction[IRP_MJ_PNP] = SwDispatchPnp;
+ DriverObject->MajorFunction[IRP_MJ_POWER] = SwDispatchPower;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SwDispatchDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = SwDispatchSystemControl;
+
++ DPRINT("SWENUM loaded\n");
+ return STATUS_SUCCESS;
+}
+