#include "priv.h"
+const GUID GUID_NULL = {0x00000000L, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
+
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
NTSTATUS
IN PIRP Irp,
OUT KSRESET* ResetValue)
{
- UNIMPLEMENTED;
- return STATUS_UNSUCCESSFUL;
+ PIO_STACK_LOCATION IoStack;
+ KSRESET* Value;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ /* get current irp stack */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* check if there is reset value provided */
+ if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSRESET))
+ return STATUS_INVALID_PARAMETER;
+
+ if (Irp->RequestorMode == UserMode)
+ {
+ /* need to probe the buffer */
+ _SEH2_TRY
+ {
+ ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSRESET), sizeof(UCHAR));
+ Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+ *ResetValue = *Value;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Exception, get the error code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
+ *ResetValue = *Value;
+ }
+
+ return Status;
}
/*
{
PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
+ DPRINT("KsReleaseDevice\n");
+
ExReleaseResourceLite(&Header->SecurityLock);
KeLeaveCriticalRegion();
}
Entry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(RemoveHeadList(ListHead), CREATE_ITEM_ENTRY, Entry);
/* caller shouldnt have any references */
- ASSERT(Entry->ReferenceCount == 0);
- ASSERT(IsListEmpty(&Entry->ObjectItemList));
+ //ASSERT(Entry->ReferenceCount == 0);
+ //ASSERT(IsListEmpty(&Entry->ObjectItemList));
/* does the creator wish notification */
if (Entry->ItemFreeCallback)
InitializeListHead(&Header->TargetDeviceList);
/* initialize power dispatch list */
InitializeListHead(&Header->PowerDispatchList);
+ /* initialize object bag lists */
+ InitializeListHead(&Header->ObjectBags);
/* initialize create item list */
InitializeListHead(&Header->ItemList);
}
}
/* store the object in the file object */
- ASSERT(IoStack->FileObject->FsContext == NULL);
- IoStack->FileObject->FsContext = ObjectHeader;
+ IoStack->FileObject->FsContext2 = ObjectHeader;
/* store parent device */
ObjectHeader->ParentDeviceObject = IoGetRelatedDeviceObject(IoStack->FileObject);
{
PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER) Header;
+ DPRINT("KsFreeObjectHeader Header %p Class %wZ\n", Header, &ObjectHeader->ObjectClass);
+
if (ObjectHeader->ObjectClass.Buffer)
{
/* release object class buffer */
Header = (PKSIDEVICE_HEADER)DevHeader;
- DPRINT1("KsAddObjectCreateItemToDeviceHeader entered\n");
+ DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
/* check if a device header has been provided */
if (!DevHeader)
/* increment create item count */
InterlockedIncrement(&Header->ItemListCount);
}
-
+ DPRINT("KsAddObjectCreateItemToDeviceHeader Status %x\n", Status);
return Status;
}
Header = (PKSIOBJECT_HEADER)ObjectHeader;
- DPRINT1("KsAddObjectCreateItemToDeviceHeader entered\n");
+ DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
/* check if a device header has been provided */
if (!Header)
return STATUS_INVALID_PARAMETER_2;
/* first allocate a create entry */
- CreateEntry = AllocateItem(NonPagedPool, sizeof(PCREATE_ITEM_ENTRY));
+ CreateEntry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
/* check for allocation success */
if (!CreateEntry)
/* get object header */
- ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext;
+ ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext2;
/* check if there is fast device io function */
if (ObjectHeader && ObjectHeader->DispatchTable.FastDeviceIoControl)
IoStatusBlock.Status = STATUS_UNSUCCESSFUL;
IoStatusBlock.Information = 0;
- /* it is send the request */
+ /* send the request */
Status = ObjectHeader->DispatchTable.FastDeviceIoControl(FileObject, TRUE, InBuffer, InSize, OutBuffer, OutSize, IoControl, &IoStatusBlock, DeviceObject);
/* check if the request was handled */
//DPRINT("Handled %u Status %x Length %u\n", Status, IoStatusBlock.Status, IoStatusBlock.Information);
/* create the irp */
Irp = IoBuildDeviceIoControlRequest(IoControl, DeviceObject, InBuffer, InSize, OutBuffer, OutSize, FALSE, &Event, &IoStatusBlock);
- /* HACK */
+ if (!Irp)
+ {
+ /* no memory to allocate the irp */
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ /* Store Fileobject */
IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->FileObject = FileObject;
+ if (IoControl == IOCTL_KS_WRITE_STREAM)
+ {
+ Irp->AssociatedIrp.SystemBuffer = OutBuffer;
+ }
+ else if (IoControl == IOCTL_KS_READ_STREAM)
+ {
+ Irp->AssociatedIrp.SystemBuffer = InBuffer;
+ }
+
IoSetCompletionRoutine(Irp, KspSynchronousIoControlDeviceCompletion, (PVOID)&IoStatusBlock, TRUE, TRUE, TRUE);
Status = IoCallDriver(DeviceObject, Irp);
}
/*
- @implemented
+ @unimplemented
*/
KSDDKAPI
NTSTATUS
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
NTSTATUS
IN PKSPIN_MEDIUM Medium,
IN ULONG PinDirection)
{
- UNIMPLEMENTED;
- return STATUS_UNSUCCESSFUL;
+ HANDLE hKey;
+ UNICODE_STRING Path;
+ UNICODE_STRING BasePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediumCache\\");
+ UNICODE_STRING GuidString;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ BOOLEAN PathAdjusted = FALSE;
+ ULONG Value = 0;
+
+ /* first check if the medium is standard */
+ if (IsEqualGUIDAligned(&KSMEDIUMSETID_Standard, &Medium->Set) ||
+ IsEqualGUIDAligned(&GUID_NULL, &Medium->Set))
+ {
+ /* no need to cache that */
+ return STATUS_SUCCESS;
+ }
+
+ /* convert guid to string */
+ Status = RtlStringFromGUID(&Medium->Set, &GuidString);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ /* allocate path buffer */
+ Path.Length = 0;
+ Path.MaximumLength = BasePath.MaximumLength + GuidString.MaximumLength + 10 * sizeof(WCHAR);
+ Path.Buffer = AllocateItem(PagedPool, Path.MaximumLength);
+ if (!Path.Buffer)
+ {
+ /* not enough resources */
+ RtlFreeUnicodeString(&GuidString);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeStringToString(&Path, &BasePath);
+ RtlAppendUnicodeStringToString(&Path, &GuidString);
+ RtlAppendUnicodeToString(&Path, L"-");
+ /* FIXME append real instance id */
+ RtlAppendUnicodeToString(&Path, L"0");
+ RtlAppendUnicodeToString(&Path, L"-");
+ /* FIXME append real instance id */
+ RtlAppendUnicodeToString(&Path, L"0");
+
+ /* free guid string */
+ RtlFreeUnicodeString(&GuidString);
+
+ /* initialize object attributes */
+ InitializeObjectAttributes(&ObjectAttributes, &Path, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+ /* create the key */
+ Status = ZwCreateKey(&hKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
+
+ /* free path buffer */
+ FreeItem(Path.Buffer);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* store symbolic link */
+ if (SymbolicLink->Buffer[1] == L'?' && SymbolicLink->Buffer[2] == L'?')
+ {
+ /* replace kernel path with user mode path */
+ SymbolicLink->Buffer[1] = L'\\';
+ PathAdjusted = TRUE;
+ }
+
+ /* store the key */
+ Status = ZwSetValueKey(hKey, SymbolicLink, 0, REG_DWORD, &Value, sizeof(ULONG));
+
+ if (PathAdjusted)
+ {
+ /* restore kernel path */
+ SymbolicLink->Buffer[1] = L'?';
+ }
+
+ ZwClose(hKey);
+ }
+
+ /* done */
+ return Status;
}
/*
DriverObjectExtension = (PKO_DRIVER_EXTENSION)IoGetDriverObjectExtension(DeviceObject->DriverObject, (PVOID)KoDriverInitialize);
if (!DriverObjectExtension)
{
- DPRINT1("FileObject not attached!\n");
+ DPRINT1("No DriverObjectExtension!\n");
Status = STATUS_UNSUCCESSFUL;
goto cleanup;
}
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
VOID
KsAcquireControl(
IN PVOID Object)
{
- UNIMPLEMENTED
+ PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
+
+ /* sanity check */
+ ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
+
+ KeWaitForSingleObject(BasicHeader->ControlMutex, Executive, KernelMode, FALSE, NULL);
+
+}
+
+/*
+ @implemented
+*/
+VOID
+NTAPI
+KsReleaseControl(
+ IN PVOID Object)
+{
+ PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
+
+ /* sanity check */
+ ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
+
+ KeReleaseMutex(BasicHeader->ControlMutex, FALSE);
}
+
+
/*
@implemented
*/
IN PKSDEVICE Device)
{
IKsDevice *KsDevice;
- PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
+ PKSIDEVICE_HEADER DeviceHeader;
+
+ DPRINT("KsAcquireDevice\n");
+ DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
/* get device interface*/
- KsDevice = (IKsDevice*)&DeviceHeader->lpVtblIKsDevice;
+ KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
/* acquire device mutex */
KsDevice->lpVtbl->AcquireDevice(KsDevice);
PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
/* get device interface*/
- KsDevice = (IKsDevice*)&DeviceHeader->lpVtblIKsDevice;
+ KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
/* release device mutex */
KsDevice->lpVtbl->ReleaseDevice(KsDevice);
DeviceHeader = DeviceExtension->DeviceHeader;
/* get device interface*/
- KsDevice = (IKsDevice*)&DeviceHeader->lpVtblIKsDevice;
+ KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
/* now free device header */
KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
}
}
-
-
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
VOID
KsCompletePendingRequest(
IN PIRP Irp)
{
+ PIO_STACK_LOCATION IoStack;
+
+ /* get current irp stack location */
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ /* sanity check */
+ ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
+
+ if (IoStack->MajorFunction != IRP_MJ_CLOSE)
+ {
+ /* can be completed immediately */
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return;
+ }
+
+ /* did close operation fail */
+ if (!NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ /* closing failed, complete irp */
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return;
+ }
+
+ /* FIXME
+ * delete object / device header
+ * remove dead pin / filter instance
+ */
UNIMPLEMENTED
+
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
NTSTATUS
IN REFGUID InterfaceGuid OPTIONAL,
IN PWCHAR ServiceRelativePath OPTIONAL)
{
- UNIMPLEMENTED
- return STATUS_UNSUCCESSFUL;
+ ULONG Length;
+ NTSTATUS Status = STATUS_SUCCESS;
+ UNICODE_STRING ServiceKeyPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\");
+ PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
+ PDEVICE_EXTENSION DeviceExtension;
+
+ /* calculate sizeof bus enum device extension */
+ Length = wcslen(BusIdentifier) * sizeof(WCHAR);
+ Length += sizeof(BUS_ENUM_DEVICE_EXTENSION);
+
+ BusDeviceExtension = ExAllocatePool(NonPagedPool, Length);
+ if (!BusDeviceExtension)
+ {
+ /* not enough memory */
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* zero device extension */
+ RtlZeroMemory(BusDeviceExtension, sizeof(BUS_ENUM_DEVICE_EXTENSION));
+
+ /* initialize bus device extension */
+ wcscpy(BusDeviceExtension->BusIdentifier, BusIdentifier);
+
+ /* allocate service path string */
+ Length = ServiceKeyPath.MaximumLength;
+ Length += BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName.MaximumLength;
+
+ if (ServiceRelativePath)
+ {
+ /* relative path for devices */
+ Length += wcslen(ServiceRelativePath) + 2 * sizeof(WCHAR);
+ }
+
+ BusDeviceExtension->ServicePath.Length = 0;
+ BusDeviceExtension->ServicePath.MaximumLength = Length;
+ BusDeviceExtension->ServicePath.Buffer = ExAllocatePool(NonPagedPool, Length);
+
+ if (!BusDeviceExtension->ServicePath.Buffer)
+ {
+ /* not enough memory */
+ ExFreePool(BusDeviceExtension);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &ServiceKeyPath);
+ RtlAppendUnicodeStringToString(&BusDeviceExtension->ServicePath, &BusDeviceObject->DriverObject->DriverExtension->ServiceKeyName);
+
+ if (ServiceRelativePath)
+ {
+ RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, L"\\");
+ RtlAppendUnicodeToString(&BusDeviceExtension->ServicePath, ServiceRelativePath);
+ }
+
+ if (InterfaceGuid)
+ {
+ /* register an device interface */
+ Status = IoRegisterDeviceInterface(PhysicalDeviceObject, InterfaceGuid, NULL, &BusDeviceExtension->SymbolicLinkName);
+
+ /* check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(BusDeviceExtension->ServicePath.Buffer);
+ ExFreePool(BusDeviceExtension);
+ return Status;
+ }
+
+ /* now enable device interface */
+ Status = IoSetDeviceInterfaceState(&BusDeviceExtension->SymbolicLinkName, TRUE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(BusDeviceExtension->ServicePath.Buffer);
+ ExFreePool(BusDeviceExtension);
+ return Status;
+ }
+
+ /* set state enabled */
+ BusDeviceExtension->Enabled = TRUE;
+ }
+
+ /* store device objects */
+ BusDeviceExtension->BusDeviceObject = BusDeviceObject;
+ BusDeviceExtension->PnpDeviceObject = PnpDeviceObject;
+ BusDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
+
+ if (!PnpDeviceObject)
+ {
+ BusDeviceExtension->PnpDeviceObject = IoAttachDeviceToDeviceStack(BusDeviceObject, PhysicalDeviceObject);
+
+ if (!BusDeviceExtension->PnpDeviceObject)
+ {
+ /* failed to attach device */
+ if (BusDeviceExtension->Enabled)
+ {
+ IoSetDeviceInterfaceState(&BusDeviceExtension->SymbolicLinkName, FALSE);
+ RtlFreeUnicodeString(&BusDeviceExtension->SymbolicLinkName);
+ }
+
+ /* free device extension */
+ ExFreePool(BusDeviceExtension->ServicePath.Buffer);
+ ExFreePool(BusDeviceExtension);
+
+ return STATUS_DEVICE_REMOVED;
+ }
+ }
+
+ /* attach device extension */
+ DeviceExtension = (PDEVICE_EXTENSION)BusDeviceObject->DeviceExtension;
+ DeviceExtension->DeviceHeader = (PKSIDEVICE_HEADER)BusDeviceExtension;
+
+ /* FIXME scan bus and invalidate device relations */
+ return Status;
+}
+
+ NTSTATUS
+NTAPI
+KspSetGetBusDataCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ /* signal completion */
+ KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
+
+ /* more work needs be done, so dont free the irp */
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+}
+
+NTSTATUS
+KspDeviceSetGetBusData(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ULONG DataType,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOL bGet)
+{
+ PIO_STACK_LOCATION IoStack;
+ PIRP Irp;
+ NTSTATUS Status;
+ KEVENT Event;
+
+ /* allocate the irp */
+ Irp = IoAllocateIrp(1, /*FIXME */
+ FALSE);
+
+ if (!Irp)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* initialize the event */
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ /* get next stack location */
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ /* setup a completion routine */
+ IoSetCompletionRoutine(Irp, KspSetGetBusDataCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+
+ /* setup parameters */
+ IoStack->Parameters.ReadWriteConfig.Buffer = Buffer;
+ IoStack->Parameters.ReadWriteConfig.Length = Length;
+ IoStack->Parameters.ReadWriteConfig.Offset = Offset;
+ IoStack->Parameters.ReadWriteConfig.WhichSpace = DataType;
+ /* setup function code */
+ IoStack->MajorFunction = IRP_MJ_PNP;
+ IoStack->MinorFunction = (bGet ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG);
+
+ /* lets call the driver */
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ /* is the request still pending */
+ if (Status == STATUS_PENDING)
+ {
+ /* have a nap */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ /* update status */
+ Status = Irp->IoStatus.Status;
+ }
+
+ /* free the irp */
+ IoFreeIrp(Irp);
+ /* done */
+ return Status;
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
ULONG
IN ULONG Offset,
IN ULONG Length)
{
- UNIMPLEMENTED
- return 0;
+ return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
+ DataType, Buffer, Offset, Length, FALSE);
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
ULONG
IN ULONG Offset,
IN ULONG Length)
{
- UNIMPLEMENTED
- return 0;
+ return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
+ DataType, Buffer, Offset, Length, TRUE);
+
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
void
IN ULONG MaxMappingsByteCount,
IN ULONG MappingTableStride)
{
- UNIMPLEMENTED
-}
+ PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
+
+ DeviceHeader->AdapterObject = AdapterObject;
+ DeviceHeader->MaxMappingsByteCount = MaxMappingsByteCount;
+ DeviceHeader->MappingTableStride = MappingTableStride;
-/*
- @unimplemented
-*/
-KSDDKAPI
-NTSTATUS
-NTAPI
-_KsEdit(
- IN KSOBJECT_BAG ObjectBag,
- IN OUT PVOID* PointerToPointerToItem,
- IN ULONG NewSize,
- IN ULONG OldSize,
- IN ULONG Tag)
-{
- UNIMPLEMENTED
- return STATUS_UNSUCCESSFUL;
}
/*
IN PIRP Irp)
{
UNIMPLEMENTED
+
return STATUS_UNSUCCESSFUL;
}
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
PVOID
KsGetFirstChild(
IN PVOID Object)
{
- UNIMPLEMENTED
- return NULL;
+ PKSBASIC_HEADER BasicHeader;
+
+ /* get the basic header */
+ BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
+
+ /* type has to be either a device or a filter factory */
+ ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory);
+
+ return (PVOID)BasicHeader->FirstChild.Filter;
}
/*
- @unimplemented
+ @implemented
*/
KSDDKAPI
PVOID
KsGetNextSibling(
IN PVOID Object)
{
- UNIMPLEMENTED
- return NULL;
+ PKSBASIC_HEADER BasicHeader;
+
+ /* get the basic header */
+ BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
+
+ ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
+ BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
+
+ return (PVOID)BasicHeader->Next.Pin;
}
/*
return STATUS_UNSUCCESSFUL;
}
-/*
- @unimplemented
-*/
-NTSTATUS
-NTAPI
-KsMergeAutomationTables(
- OUT PKSAUTOMATION_TABLE *AutomationTableAB,
+ULONG
+KspCountMethodSets(
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
- IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL,
+ IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
+{
+ ULONG Index, SubIndex, Count;
+ BOOL bFound;
+
+ if (!AutomationTableA)
+ return AutomationTableB->MethodSetsCount;
+
+ if (!AutomationTableB)
+ return AutomationTableA->MethodSetsCount;
+
+
+ DPRINT("AutomationTableA MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableA->MethodItemSize, AutomationTableA->MethodSetsCount);
+ DPRINT("AutomationTableB MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableB->MethodItemSize, AutomationTableB->MethodSetsCount);
+
+ if (AutomationTableA->MethodItemSize && AutomationTableB->MethodItemSize)
+ {
+ /* sanity check */
+ ASSERT(AutomationTableA->MethodItemSize == AutomationTableB->MethodItemSize);
+ }
+
+ /* now iterate all property sets and compare their guids */
+ Count = AutomationTableA->MethodSetsCount;
+
+ for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
+ {
+ /* set found to false */
+ bFound = FALSE;
+
+ for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
+ {
+ if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
+ {
+ /* same property set found */
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ Count++;
+ }
+
+ return Count;
+}
+
+ULONG
+KspCountEventSets(
+ IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
+ IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
+{
+ ULONG Index, SubIndex, Count;
+ BOOL bFound;
+
+ if (!AutomationTableA)
+ return AutomationTableB->EventSetsCount;
+
+ if (!AutomationTableB)
+ return AutomationTableA->EventSetsCount;
+
+ DPRINT("AutomationTableA EventItemSize %lu EventSetsCount %lu\n", AutomationTableA->EventItemSize, AutomationTableA->EventSetsCount);
+ DPRINT("AutomationTableB EventItemSize %lu EventSetsCount %lu\n", AutomationTableB->EventItemSize, AutomationTableB->EventSetsCount);
+
+ if (AutomationTableA->EventItemSize && AutomationTableB->EventItemSize)
+ {
+ /* sanity check */
+ ASSERT(AutomationTableA->EventItemSize == AutomationTableB->EventItemSize);
+ }
+
+ /* now iterate all Event sets and compare their guids */
+ Count = AutomationTableA->EventSetsCount;
+
+ for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
+ {
+ /* set found to false */
+ bFound = FALSE;
+
+ for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
+ {
+ if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
+ {
+ /* same Event set found */
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ Count++;
+ }
+
+ return Count;
+}
+
+
+ULONG
+KspCountPropertySets(
+ IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
+ IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
+{
+ ULONG Index, SubIndex, Count;
+ BOOL bFound;
+
+ if (!AutomationTableA)
+ return AutomationTableB->PropertySetsCount;
+
+ if (!AutomationTableB)
+ return AutomationTableA->PropertySetsCount;
+
+ /* sanity check */
+ DPRINT("AutomationTableA PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableA->PropertyItemSize, AutomationTableA->PropertySetsCount);
+ DPRINT("AutomationTableB PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableB->PropertyItemSize, AutomationTableB->PropertySetsCount);
+ ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
+
+ /* now iterate all property sets and compare their guids */
+ Count = AutomationTableA->PropertySetsCount;
+
+ for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
+ {
+ /* set found to false */
+ bFound = FALSE;
+
+ for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
+ {
+ if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
+ {
+ /* same property set found */
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ Count++;
+ }
+
+ return Count;
+}
+
+NTSTATUS
+KspCopyMethodSets(
+ OUT PKSAUTOMATION_TABLE Table,
+ IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
+ IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
+{
+ ULONG Index, SubIndex, Count;
+ BOOL bFound;
+
+ if (!AutomationTableA)
+ {
+ /* copy of property set */
+ RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableB->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableB->MethodSetsCount);
+ return STATUS_SUCCESS;
+ }
+ else if (!AutomationTableB)
+ {
+ /* copy of property set */
+ RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
+ return STATUS_SUCCESS;
+ }
+
+ /* first copy all property items from dominant table */
+ RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
+ /* set counter */
+ Count = AutomationTableA->MethodSetsCount;
+
+ /* now copy entries which arent available in the dominant table */
+ for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
+ {
+ /* set found to false */
+ bFound = FALSE;
+
+ for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
+ {
+ if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
+ {
+ /* same property set found */
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ /* copy new property item set */
+ RtlMoveMemory((PVOID)&Table->MethodSets[Count], &AutomationTableB->MethodSets[Index], sizeof(KSMETHOD_SET));
+ Count++;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+KspCopyPropertySets(
+ OUT PKSAUTOMATION_TABLE Table,
+ IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
+ IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
+{
+ ULONG Index, SubIndex, Count;
+ BOOL bFound;
+
+ if (!AutomationTableA)
+ {
+ /* copy of property set */
+ RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableB->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableB->PropertySetsCount);
+ return STATUS_SUCCESS;
+ }
+ else if (!AutomationTableB)
+ {
+ /* copy of property set */
+ RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
+ return STATUS_SUCCESS;
+ }
+
+ /* first copy all property items from dominant table */
+ RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
+ /* set counter */
+ Count = AutomationTableA->PropertySetsCount;
+
+ /* now copy entries which arent available in the dominant table */
+ for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
+ {
+ /* set found to false */
+ bFound = FALSE;
+
+ for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
+ {
+ if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
+ {
+ /* same property set found */
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ /* copy new property item set */
+ RtlMoveMemory((PVOID)&Table->PropertySets[Count], &AutomationTableB->PropertySets[Index], sizeof(KSPROPERTY_SET));
+ Count++;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+KspCopyEventSets(
+ OUT PKSAUTOMATION_TABLE Table,
+ IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
+ IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
+{
+ ULONG Index, SubIndex, Count;
+ BOOL bFound;
+
+ if (!AutomationTableA)
+ {
+ /* copy of Event set */
+ RtlMoveMemory((PVOID)Table->EventSets, AutomationTableB->EventSets, sizeof(KSEVENT_SET) * AutomationTableB->EventSetsCount);
+ return STATUS_SUCCESS;
+ }
+ else if (!AutomationTableB)
+ {
+ /* copy of Event set */
+ RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
+ return STATUS_SUCCESS;
+ }
+
+ /* first copy all Event items from dominant table */
+ RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
+ /* set counter */
+ Count = AutomationTableA->EventSetsCount;
+
+ /* now copy entries which arent available in the dominant table */
+ for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
+ {
+ /* set found to false */
+ bFound = FALSE;
+
+ for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
+ {
+ if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
+ {
+ /* same Event set found */
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ /* copy new Event item set */
+ RtlMoveMemory((PVOID)&Table->EventSets[Count], &AutomationTableB->EventSets[Index], sizeof(KSEVENT_SET));
+ Count++;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+/*
+ @implemented
+*/
+NTSTATUS
+NTAPI
+KsMergeAutomationTables(
+ OUT PKSAUTOMATION_TABLE *AutomationTableAB,
+ IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
+ IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL,
IN KSOBJECT_BAG Bag OPTIONAL)
{
- UNIMPLEMENTED
- return STATUS_UNSUCCESSFUL;
+ PKSAUTOMATION_TABLE Table;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!AutomationTableA && !AutomationTableB)
+ {
+ /* nothing to merge */
+ return STATUS_SUCCESS;
+ }
+
+ /* allocate an automation table */
+ Table = AllocateItem(NonPagedPool, sizeof(KSAUTOMATION_TABLE));
+ if (!Table)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ if (Bag)
+ {
+ /* add table to object bag */
+ Status = KsAddItemToObjectBag(Bag, Table, NULL);
+ /* check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* free table */
+ FreeItem(Table);
+ return Status;
+ }
+ }
+
+ /* count property sets */
+ Table->PropertySetsCount = KspCountPropertySets(AutomationTableA, AutomationTableB);
+
+ if (Table->PropertySetsCount)
+ {
+ if (AutomationTableA)
+ {
+ /* use item size from dominant automation table */
+ Table->PropertyItemSize = AutomationTableA->PropertyItemSize;
+ }
+ else
+ {
+ /* use item size from 2nd automation table */
+ Table->PropertyItemSize = AutomationTableB->PropertyItemSize;
+ }
+
+ /* now allocate the property sets */
+ Table->PropertySets = AllocateItem(NonPagedPool, sizeof(KSPROPERTY_SET) * Table->PropertySetsCount);
+
+ if (!Table->PropertySets)
+ {
+ /* not enough memory */
+ goto cleanup;
+ }
+
+ if (Bag)
+ {
+ /* add set to property bag */
+ Status = KsAddItemToObjectBag(Bag, (PVOID)Table->PropertySets, NULL);
+ /* check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* cleanup table */
+ goto cleanup;
+ }
+ }
+ /* now copy the property sets */
+ Status = KspCopyPropertySets(Table, AutomationTableA, AutomationTableB);
+ if(!NT_SUCCESS(Status))
+ goto cleanup;
+
+ }
+
+ /* now count the method sets */
+ Table->MethodSetsCount = KspCountMethodSets(AutomationTableA, AutomationTableB);
+
+ if (Table->MethodSetsCount)
+ {
+ if (AutomationTableA)
+ {
+ /* use item size from dominant automation table */
+ Table->MethodItemSize = AutomationTableA->MethodItemSize;
+ }
+ else
+ {
+ /* use item size from 2nd automation table */
+ Table->MethodItemSize = AutomationTableB->MethodItemSize;
+ }
+
+ /* now allocate the property sets */
+ Table->MethodSets = AllocateItem(NonPagedPool, sizeof(KSMETHOD_SET) * Table->MethodSetsCount);
+
+ if (!Table->MethodSets)
+ {
+ /* not enough memory */
+ goto cleanup;
+ }
+
+ if (Bag)
+ {
+ /* add set to property bag */
+ Status = KsAddItemToObjectBag(Bag, (PVOID)Table->MethodSets, NULL);
+ /* check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* cleanup table */
+ goto cleanup;
+ }
+ }
+ /* now copy the property sets */
+ Status = KspCopyMethodSets(Table, AutomationTableA, AutomationTableB);
+ if(!NT_SUCCESS(Status))
+ goto cleanup;
+ }
+
+
+ /* now count the event sets */
+ Table->EventSetsCount = KspCountEventSets(AutomationTableA, AutomationTableB);
+
+ if (Table->EventSetsCount)
+ {
+ if (AutomationTableA)
+ {
+ /* use item size from dominant automation table */
+ Table->EventItemSize = AutomationTableA->EventItemSize;
+ }
+ else
+ {
+ /* use item size from 2nd automation table */
+ Table->EventItemSize = AutomationTableB->EventItemSize;
+ }
+
+ /* now allocate the property sets */
+ Table->EventSets = AllocateItem(NonPagedPool, sizeof(KSEVENT_SET) * Table->EventSetsCount);
+
+ if (!Table->EventSets)
+ {
+ /* not enough memory */
+ goto cleanup;
+ }
+
+ if (Bag)
+ {
+ /* add set to property bag */
+ Status = KsAddItemToObjectBag(Bag, (PVOID)Table->EventSets, NULL);
+ /* check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* cleanup table */
+ goto cleanup;
+ }
+ }
+ /* now copy the property sets */
+ Status = KspCopyEventSets(Table, AutomationTableA, AutomationTableB);
+ if(!NT_SUCCESS(Status))
+ goto cleanup;
+ }
+
+ /* store result */
+ *AutomationTableAB = Table;
+
+ return Status;
+
+
+cleanup:
+
+ if (Table)
+ {
+ if (Table->PropertySets)
+ {
+ /* clean property sets */
+ if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->PropertySets, TRUE)))
+ FreeItem((PVOID)Table->PropertySets);
+ }
+
+ if (Table->MethodSets)
+ {
+ /* clean property sets */
+ if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->MethodSets, TRUE)))
+ FreeItem((PVOID)Table->MethodSets);
+ }
+
+ if (Table->EventSets)
+ {
+ /* clean property sets */
+ if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->EventSets, TRUE)))
+ FreeItem((PVOID)Table->EventSets);
+ }
+
+ if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, Table, TRUE)))
+ FreeItem(Table);
+ }
+
+ return STATUS_INSUFFICIENT_RESOURCES;
}
/*
return STATUS_UNSUCCESSFUL;
}
+VOID
+NTAPI
+KspRemoveBusInterface(
+ PVOID Ctx)
+{
+ PKSREMOVE_BUS_INTERFACE_CTX Context =(PKSREMOVE_BUS_INTERFACE_CTX)Ctx;
+
+ /* TODO
+ * get SWENUM_INSTALL_INTERFACE struct
+ * open device key and delete the keys
+ */
+
+ UNIMPLEMENTED
+
+ /* set status */
+ Context->Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+
+
+ /* signal completion */
+ KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
+}
+
/*
@unimplemented
*/
KsRemoveBusEnumInterface(
IN PIRP Irp)
{
- UNIMPLEMENTED
- return STATUS_UNSUCCESSFUL;
-}
+ KPROCESSOR_MODE Mode;
+ LUID luid;
+ KSREMOVE_BUS_INTERFACE_CTX Ctx;
+ WORK_QUEUE_ITEM WorkItem;
+
+ /* get previous mode */
+ Mode = ExGetPreviousMode();
+
+ /* convert to luid */
+ luid = RtlConvertUlongToLuid(SE_LOAD_DRIVER_PRIVILEGE);
+ /* perform access check */
+ if (!SeSinglePrivilegeCheck(luid, Mode))
+ {
+ /* insufficient privileges */
+ return STATUS_PRIVILEGE_NOT_HELD;
+ }
+ /* initialize event */
+ KeInitializeEvent(&Ctx.Event, NotificationEvent, FALSE);
+
+ /* store irp in ctx */
+ Ctx.Irp = Irp;
+
+ /* initialize work item */
+ ExInitializeWorkItem(&WorkItem, KspRemoveBusInterface, (PVOID)&Ctx);
+
+ /* now queue the work item */
+ ExQueueWorkItem(&WorkItem, DelayedWorkQueue);
+
+ /* wait for completion */
+ KeWaitForSingleObject(&Ctx.Event, Executive, KernelMode, FALSE, NULL);
+
+ /* return result */
+ return Ctx.Irp->IoStatus.Status;
+
+}
/*
IN PVOID Object,
IN PUNKNOWN ClientUnknown)
{
- UNIMPLEMENTED
- return NULL;
-}
+ PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
-/*
- @unimplemented
-*/
-VOID
-NTAPI
-KsReleaseControl(
- IN PVOID Object)
-{
- UNIMPLEMENTED
+ /* sanity check */
+ ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
+ BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
+
+ if (BasicHeader->ClientAggregate)
+ {
+ /* release existing aggregate */
+ BasicHeader->ClientAggregate->lpVtbl->Release(BasicHeader->ClientAggregate);
+ }
+
+ /* increment reference count */
+ ClientUnknown->lpVtbl->AddRef(ClientUnknown);
+
+ /* store client aggregate */
+ BasicHeader->ClientAggregate = ClientUnknown;
+
+ /* return objects outer unknown */
+ return BasicHeader->OuterUnknown;
}
/*
IN KSPIN_MEDIUM* MediumList,
IN GUID* CategoryList OPTIONAL)
{
+ ULONG Size, Index;
+ NTSTATUS Status;
+ PWSTR SymbolicLinkList;
+ //PUCHAR Buffer;
+ HANDLE hKey;
+ UNICODE_STRING InterfaceString;
+ //UNICODE_STRING FilterData = RTL_CONSTANT_STRING(L"FilterData");
+
+ if (!InterfaceClassGUID || !PinCount || !PinDirection || !MediumList)
+ {
+ /* all these parameters are required */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* calculate filter data value size */
+ Size = PinCount * sizeof(KSPIN_MEDIUM);
+ if (CategoryList)
+ {
+ /* add category list */
+ Size += PinCount * sizeof(GUID);
+ }
+
+ /* FIXME generate filter data blob */
UNIMPLEMENTED
- return STATUS_UNSUCCESSFUL;
+
+ /* get symbolic link list */
+ Status = IoGetDeviceInterfaces(InterfaceClassGUID, DeviceObject, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &SymbolicLinkList);
+ if (NT_SUCCESS(Status))
+ {
+ /* initialize first symbolic link */
+ RtlInitUnicodeString(&InterfaceString, SymbolicLinkList);
+
+ /* open first device interface registry key */
+ Status = IoOpenDeviceInterfaceRegistryKey(&InterfaceString, GENERIC_WRITE, &hKey);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* write filter data */
+ //Status = ZwSetValueKey(hKey, &FilterData, 0, REG_BINARY, Buffer, Size);
+
+ /* close the key */
+ ZwClose(hKey);
+ }
+
+ if (PinCount)
+ {
+ /* update medium cache */
+ for(Index = 0; Index < PinCount; Index++)
+ {
+ KsCacheMedium(&InterfaceString, &MediumList[Index], PinDirection[Index]);
+ }
+ }
+
+ /* free the symbolic link list */
+ ExFreePool(SymbolicLinkList);
+ }
+
+ return Status;
}