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

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

2156 lines
60 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel Streaming
* FILE: drivers/ksfilter/ks/swenum.c
* PURPOSE: KS Software BUS functions
* PROGRAMMER: Johannes Anderwald
*/
#include "priv.h"
LONG KsDeviceCount = 0;
typedef NTSTATUS (NTAPI *PKSP_BUS_ENUM_CALLBACK)(
IN PHANDLE hKey,
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PBUS_DEVICE_ENTRY DummyEntry,
IN LPWSTR RootName,
IN LPWSTR DirectoryName);
NTSTATUS
KspCreatePDO(
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PBUS_DEVICE_ENTRY DeviceEntry,
OUT PDEVICE_OBJECT * OutDeviceObject)
{
PDEVICE_OBJECT DeviceObject;
WCHAR Buffer[50];
ULONG CurDeviceId;
UNICODE_STRING DeviceName;
NTSTATUS Status;
PCOMMON_DEVICE_EXTENSION DeviceExtension;
/* increment device count */
CurDeviceId = InterlockedIncrement(&KsDeviceCount);
/* generate new device id */
swprintf(Buffer, L"\\Device\\KSENUM%08x", CurDeviceId);
/* initialize new device name */
RtlInitUnicodeString(&DeviceName, Buffer);
/* create new device object */
Status = IoCreateDevice(BusDeviceExtension->BusDeviceObject->DriverObject, sizeof(PVOID), &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject);
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed to create pdo */
return Status;
}
/* now allocate device extension */
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)AllocateItem(NonPagedPool, sizeof(COMMON_DEVICE_EXTENSION));
if (!DeviceExtension)
{
/* no memory */
IoDeleteDevice(DeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* store device extension */
*((PVOID*)DeviceObject->DeviceExtension) = DeviceExtension;
/* initialize device extension */
DeviceExtension->IsBus = FALSE;
DeviceExtension->DeviceObject = DeviceObject;
DeviceExtension->DeviceEntry = DeviceEntry;
DeviceExtension->BusDeviceExtension = BusDeviceExtension;
/* TODO: update last creation time in bus device extension */
/* setup flags */
DeviceObject->Flags |= DO_POWER_PAGABLE;
DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
/* TODO: fire time when expired */
*OutDeviceObject = DeviceObject;
return STATUS_SUCCESS;
}
NTSTATUS
KspRegisterDeviceAssociation(
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PBUS_DEVICE_ENTRY DeviceEntry,
IN OUT PBUS_INSTANCE_ENTRY BusInstanceEntry)
{
NTSTATUS Status;
UNICODE_STRING ReferenceString;
/* initialize reference string */
RtlInitUnicodeString(&ReferenceString, DeviceEntry->DeviceName);
/* register device interface */
Status = IoRegisterDeviceInterface(BusDeviceExtension->PhysicalDeviceObject, &BusInstanceEntry->InterfaceGuid, &ReferenceString, &BusInstanceEntry->SymbolicLink);
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed */
return Status;
}
/* now enable the interface */
Status = IoSetDeviceInterfaceState(&BusInstanceEntry->SymbolicLink, TRUE);
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed, free memory */
FreeItem(BusInstanceEntry->SymbolicLink.Buffer);
return Status;
}
DPRINT1("Registered DeviceInterface %wZ\n", &BusInstanceEntry->SymbolicLink);
/* done */
return Status;
}
VOID
KspRemoveDeviceAssociations(
IN PBUS_DEVICE_ENTRY DeviceEntry)
{
PLIST_ENTRY Entry;
PBUS_INSTANCE_ENTRY CurEntry;
/* remove all entries */
Entry = DeviceEntry->DeviceInterfaceList.Flink;
while(Entry != &DeviceEntry->DeviceInterfaceList)
{
/* get offset */
CurEntry = (PBUS_INSTANCE_ENTRY)CONTAINING_RECORD(Entry, BUS_INSTANCE_ENTRY, Entry);
/* sanity check */
ASSERT(CurEntry->SymbolicLink.Buffer);
/* de-register interface */
IoSetDeviceInterfaceState(&CurEntry->SymbolicLink, FALSE);
/* free symbolic link buffer */
FreeItem(CurEntry->SymbolicLink.Buffer);
/* remove entry from list */
RemoveEntryList(Entry);
/* move to next entry */
Entry = Entry->Flink;
/* free entry */
FreeItem(CurEntry);
}
}
NTSTATUS
KspEnumerateBusRegistryKeys(
IN HANDLE hKey,
IN LPWSTR ReferenceString,
IN PKSP_BUS_ENUM_CALLBACK Callback,
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PBUS_DEVICE_ENTRY DeviceEntry)
{
UNICODE_STRING String;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hNewKey;
NTSTATUS Status;
ULONG ResultLength, Index, KeyInfoLength;
KEY_FULL_INFORMATION KeyInformation;
PKEY_BASIC_INFORMATION KeyInfo;
/* initialize key name */
RtlInitUnicodeString(&String, ReferenceString);
/* initialize object attributes */
InitializeObjectAttributes(&ObjectAttributes, &String, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hKey, NULL);
/* open new key */
Status = ZwOpenKey(&hNewKey, GENERIC_READ, &ObjectAttributes);
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed to open key */
return Status;
}
/* query key stats */
Status = ZwQueryKey(hNewKey, KeyFullInformation, &KeyInformation, sizeof(KeyInformation), &ResultLength);
if (!NT_SUCCESS(Status))
{
/* close key */
ZwClose(hNewKey);
/* done */
return Status;
}
/* calculate key info length */
KeyInfoLength = KeyInformation.MaxNameLen + sizeof(KEY_BASIC_INFORMATION) + 1 * sizeof(WCHAR);
/* allocate buffer */
KeyInfo = (PKEY_BASIC_INFORMATION)AllocateItem(NonPagedPool, KeyInfoLength);
if (!KeyInfo)
{
/* no memory */
ZwClose(hNewKey);
/* done */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* enumerate all keys */
for(Index = 0; Index < KeyInformation.SubKeys; Index++)
{
/* query sub key */
Status = ZwEnumerateKey(hNewKey, Index, KeyBasicInformation, (PVOID)KeyInfo, KeyInfoLength, &ResultLength);
/* check for success */
if (NT_SUCCESS(Status))
{
/* perform callback */
Status = Callback(hNewKey, BusDeviceExtension, DeviceEntry, ReferenceString, KeyInfo->Name);
/* should enumeration stop */
if (!NT_SUCCESS(Status))
break;
}
}
/* free info buffer */
FreeItem(KeyInfo);
/* close key */
ZwClose(hNewKey);
/* done */
return Status;
}
NTSTATUS
NTAPI
KspCreateDeviceAssociation(
IN PHANDLE hKey,
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PBUS_DEVICE_ENTRY DeviceEntry,
IN LPWSTR ReferenceString,
IN LPWSTR InterfaceString)
{
GUID DeviceGuid;
NTSTATUS Status;
PLIST_ENTRY Entry;
PBUS_INSTANCE_ENTRY CurEntry;
UNICODE_STRING DeviceName;
/* initialize interface string */
RtlInitUnicodeString(&DeviceName, InterfaceString);
/* first convert device name to guid */
RtlGUIDFromString(&DeviceName, &DeviceGuid);
/* check if the device is already present */
Entry = DeviceEntry->DeviceInterfaceList.Flink;
while(Entry != &DeviceEntry->DeviceInterfaceList)
{
/* get offset */
CurEntry = (PBUS_INSTANCE_ENTRY)CONTAINING_RECORD(Entry, BUS_INSTANCE_ENTRY, Entry);
if (IsEqualGUIDAligned(&CurEntry->InterfaceGuid, &DeviceGuid))
{
/* entry already exists */
return STATUS_SUCCESS;
}
/* move to next entry */
Entry = Entry->Flink;
}
/* time to allocate new entry */
CurEntry = (PBUS_INSTANCE_ENTRY)AllocateItem(NonPagedPool, sizeof(BUS_INSTANCE_ENTRY));
if (!CurEntry)
{
/* no memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* store guid */
RtlMoveMemory(&CurEntry->InterfaceGuid, &DeviceGuid, sizeof(GUID));
/* now register the association */
Status = KspRegisterDeviceAssociation(BusDeviceExtension, DeviceEntry, CurEntry);
/* check for success */
if (NT_SUCCESS(Status))
{
/* store entry */
InsertTailList(&DeviceEntry->DeviceInterfaceList, &CurEntry->Entry);
}
else
{
/* failed to associated device */
FreeItem(CurEntry);
}
/* done */
return Status;
}
NTSTATUS
NTAPI
KspCreateDeviceReference(
IN PHANDLE hKey,
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PBUS_DEVICE_ENTRY DummyEntry,
IN LPWSTR DeviceCategory,
IN LPWSTR ReferenceString)
{
LPWSTR DeviceName;
ULONG Length;
PLIST_ENTRY Entry;
PBUS_DEVICE_ENTRY DeviceEntry = NULL; /* GCC warning */
BOOLEAN ItemExists = FALSE;
UNICODE_STRING String;
NTSTATUS Status;
KIRQL OldLevel;
/* first construct device name & reference guid */
Length = wcslen(DeviceCategory) + wcslen(ReferenceString);
/* append '&' and null byte */
Length += 2;
/* allocate device name */
DeviceName = AllocateItem(NonPagedPool, Length * sizeof(WCHAR));
if (!DeviceName)
{
/* not enough memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* construct device name */
swprintf(DeviceName, L"%s&%s", DeviceCategory, ReferenceString);
/* scan list and check if it is already present */
Entry = BusDeviceExtension->Common.Entry.Flink;
while(Entry != &BusDeviceExtension->Common.Entry)
{
/* get real offset */
DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
/* check if name matches */
if (!wcsicmp(DeviceEntry->DeviceName, DeviceName))
{
/* item already exists */
ItemExists = TRUE;
break;
}
/* move to next entry */
Entry = Entry->Flink;
}
if (!ItemExists)
{
/* allocate new device entry */
DeviceEntry = AllocateItem(NonPagedPool, sizeof(BUS_DEVICE_ENTRY));
if (!DeviceEntry)
{
/* no memory */
FreeItem(DeviceName);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* initialize device entry */
InitializeListHead(&DeviceEntry->DeviceInterfaceList);
InitializeListHead(&DeviceEntry->IrpPendingList);
/* copy device guid */
RtlInitUnicodeString(&String, ReferenceString);
RtlGUIDFromString(&String, &DeviceEntry->DeviceGuid);
/* copy device names */
DeviceEntry->DeviceName = DeviceName;
DeviceEntry->Instance = (DeviceName + wcslen(DeviceCategory) + 1);
/* copy name */
DeviceEntry->BusId = AllocateItem(NonPagedPool, (wcslen(DeviceCategory) + 1) * sizeof(WCHAR));
if (!DeviceEntry->BusId)
{
/* no memory */
FreeItem(DeviceName);
FreeItem(DeviceEntry);
return STATUS_INSUFFICIENT_RESOURCES;
}
wcscpy(DeviceEntry->BusId, DeviceCategory);
}
/* now enumerate the devices */
Status = KspEnumerateBusRegistryKeys(hKey, ReferenceString, KspCreateDeviceAssociation, BusDeviceExtension, DeviceEntry);
/* check if list is empty */
if (IsListEmpty(&DeviceEntry->DeviceInterfaceList))
{
/* invalid device settings */
FreeItem(DeviceEntry->BusId);
FreeItem(DeviceEntry->DeviceName);
FreeItem(DeviceEntry);
ASSERT(ItemExists == FALSE);
return STATUS_INVALID_DEVICE_STATE;
}
/* check if enumeration failed */
if (!NT_SUCCESS(Status))
{
/* failed */
KspRemoveDeviceAssociations(DeviceEntry);
FreeItem(DeviceEntry->BusId);
FreeItem(DeviceEntry->DeviceName);
FreeItem(DeviceEntry);
ASSERT(ItemExists == FALSE);
/* done */
return Status;
}
if (!ItemExists)
{
/* acquire lock */
KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
/* successfully initialized entry */
InsertTailList(&BusDeviceExtension->Common.Entry, &DeviceEntry->Entry);
/* release lock */
KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
}
/* done */
return Status;
}
NTSTATUS
NTAPI
KspCreateDeviceReferenceTrampoline(
IN PHANDLE hKey,
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PBUS_DEVICE_ENTRY DummyEntry,
IN LPWSTR DeviceCategory,
IN LPWSTR ReferenceString)
{
return KspEnumerateBusRegistryKeys(hKey, ReferenceString, KspCreateDeviceReference, BusDeviceExtension, DummyEntry);
}
NTSTATUS
KspOpenBusRegistryKey(
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
OUT PHANDLE hKey)
{
OBJECT_ATTRIBUTES ObjectAttributes;
/* initialize object attributes */
InitializeObjectAttributes(&ObjectAttributes, &BusDeviceExtension->ServicePath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
return ZwCreateKey(hKey, GENERIC_READ | GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
}
NTSTATUS
KspScanBus(
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension)
{
HANDLE hKey;
NTSTATUS Status;
/* first open key */
Status = KspOpenBusRegistryKey(BusDeviceExtension, &hKey);
/* check for success */
if (!NT_SUCCESS(Status))
{
/* no success */
return Status;
}
/* TODO clear reference marks */
/* construct device entries */
Status = KspEnumerateBusRegistryKeys(hKey, NULL, KspCreateDeviceReferenceTrampoline, BusDeviceExtension, NULL);
/* TODO: delete unreferenced devices */
/* close handle */
ZwClose(hKey);
/* done */
return Status;
}
NTSTATUS
NTAPI
KspBusQueryReferenceString(
IN PVOID Context,
IN OUT PWCHAR *String)
{
LPWSTR Name;
ULONG Length;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)Context;
/* sanity checks */
ASSERT(BusDeviceExtension);
ASSERT(BusDeviceExtension->BusIdentifier);
/* calculate length */
Length = wcslen(BusDeviceExtension->BusIdentifier) + 1;
/* allocate buffer */
Name = AllocateItem(PagedPool, Length * sizeof(WCHAR));
if (!Name)
{
/* failed to allocate buffer */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* copy buffer */
wcscpy(Name, BusDeviceExtension->BusIdentifier);
/* store result */
*String = Name;
/* done */
return STATUS_SUCCESS;
}
VOID
NTAPI
KspBusDeviceReference(
IN PVOID Context)
{
PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
/* reference count */
InterlockedIncrement((PLONG)&ChildDeviceExtension->DeviceReferenceCount);
}
VOID
NTAPI
KspBusDeviceDereference(
IN PVOID Context)
{
PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
/* reference count */
InterlockedDecrement((PLONG)&ChildDeviceExtension->DeviceReferenceCount);
}
VOID
NTAPI
KspBusReferenceDeviceObject(
IN PVOID Context)
{
PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
/* reference count */
InterlockedIncrement((PLONG)&ChildDeviceExtension->DeviceObjectReferenceCount);
}
VOID
NTAPI
KspBusDereferenceDeviceObject(
IN PVOID Context)
{
PCOMMON_DEVICE_EXTENSION ChildDeviceExtension = (PCOMMON_DEVICE_EXTENSION)Context;
/* reference count */
InterlockedDecrement((PLONG)&ChildDeviceExtension->DeviceObjectReferenceCount);
}
NTSTATUS
KspQueryBusDeviceInterface(
IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
IN PIRP Irp)
{
PBUS_INTERFACE_SWENUM Interface;
PIO_STACK_LOCATION IoStack;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* sanity checks */
ASSERT(IoStack->Parameters.QueryInterface.Size == sizeof(BUS_INTERFACE_SWENUM));
ASSERT(IoStack->Parameters.QueryInterface.Interface);
/* fill in interface */
Interface = (PBUS_INTERFACE_SWENUM)IoStack->Parameters.QueryInterface.Interface;
Interface->Interface.Size = sizeof(BUS_INTERFACE_SWENUM);
Interface->Interface.Version = BUS_INTERFACE_SWENUM_VERSION;
Interface->Interface.Context = ChildDeviceExtension;
Interface->Interface.InterfaceReference = KspBusDeviceReference;
Interface->Interface.InterfaceDereference = KspBusDeviceDereference;
Interface->ReferenceDeviceObject = KspBusReferenceDeviceObject;
Interface->DereferenceDeviceObject = KspBusDereferenceDeviceObject;
Interface->QueryReferenceString = KspBusQueryReferenceString;
return STATUS_SUCCESS;
}
NTSTATUS
KspEnableBusDeviceInterface(
PBUS_DEVICE_ENTRY DeviceEntry,
BOOLEAN bEnable)
{
PLIST_ENTRY Entry;
PBUS_INSTANCE_ENTRY InstanceEntry;
NTSTATUS Status = STATUS_SUCCESS;
/* enable now all interfaces */
Entry = DeviceEntry->DeviceInterfaceList.Flink;
while(Entry != &DeviceEntry->DeviceInterfaceList)
{
/* get bus instance entry */
InstanceEntry = (PBUS_INSTANCE_ENTRY)CONTAINING_RECORD(Entry, BUS_INSTANCE_ENTRY, Entry);
DPRINT1("Enabling %u %wZ Irql %u\n", bEnable, &InstanceEntry->SymbolicLink, KeGetCurrentIrql());
/* set interface state */
Status = IoSetDeviceInterfaceState(&InstanceEntry->SymbolicLink, bEnable);
if (!NT_SUCCESS(Status))
{
/* failed to set interface */
break;
}
/* move to next entry */
Entry = Entry->Flink;
}
/* done */
return Status;
}
NTSTATUS
KspDoReparseForIrp(
PIRP Irp,
PBUS_DEVICE_ENTRY DeviceEntry)
{
ULONG Length;
LPWSTR Buffer;
PIO_STACK_LOCATION IoStack;
/* get stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* sanity checks */
ASSERT(DeviceEntry->PDODeviceName);
ASSERT(DeviceEntry->Instance);
ASSERT(IoStack->FileObject);
ASSERT(IoStack->FileObject->FileName.Buffer);
/* calculate length */
Length = wcslen(DeviceEntry->PDODeviceName);
Length += wcslen(DeviceEntry->Instance);
/* zero byte and '\\' */
Length += 2;
/* allocate buffer */
Buffer = AllocateItem(NonPagedPool, Length * sizeof(WCHAR));
if (!Buffer)
{
/* no resources */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* construct buffer */
swprintf(Buffer, L"%s\\%s", DeviceEntry->PDODeviceName, DeviceEntry->Instance);
ExFreePool(IoStack->FileObject->FileName.Buffer);
/* store new file name */
RtlInitUnicodeString(&IoStack->FileObject->FileName, Buffer);
/* done */
return STATUS_REPARSE;
}
VOID
KspCompletePendingIrps(
IN PBUS_DEVICE_ENTRY DeviceEntry,
IN OUT NTSTATUS ResultCode)
{
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
/* go through list */
while(!IsListEmpty(&DeviceEntry->IrpPendingList))
{
/* get first entry */
Entry = RemoveHeadList(&DeviceEntry->IrpPendingList);
/* get irp */
Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
if (ResultCode == STATUS_REPARSE)
{
/* construct reparse information */
Status = KspDoReparseForIrp(Irp, DeviceEntry);
}
else
{
/* use default code */
Status = ResultCode;
}
/* store result code */
Irp->IoStatus.Status = Status;
DPRINT1("Completing IRP %p Status %x\n", Irp, Status);
/* complete the request */
CompleteRequest(Irp, IO_NO_INCREMENT);
}
}
NTSTATUS
KspStartBusDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
IN PIRP Irp)
{
WCHAR PDOName[256];
NTSTATUS Status;
ULONG ResultLength;
LPWSTR Name;
PBUS_DEVICE_ENTRY DeviceEntry;
/* FIXME handle pending remove */
/* get full device name */
Status = IoGetDeviceProperty(DeviceObject, DevicePropertyPhysicalDeviceObjectName, sizeof(PDOName), (PVOID)PDOName, &ResultLength);
if (!NT_SUCCESS(Status))
{
/* failed to get device name */
return Status;
}
/* allocate device name buffer */
Name = AllocateItem(NonPagedPool, (ResultLength + 1) * sizeof(WCHAR));
if (!Name)
{
/* no memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* copy name */
wcscpy(Name, PDOName);
/* TODO: time stamp creation time */
/* get device entry */
DeviceEntry = (PBUS_DEVICE_ENTRY)ChildDeviceExtension->DeviceEntry;
/* sanity check */
ASSERT(DeviceEntry);
/* store device name */
DeviceEntry->PDODeviceName = Name;
/* mark device as started */
DeviceEntry->DeviceState = Started;
/* reference start time */
KeQuerySystemTime(&DeviceEntry->TimeCreated);
DPRINT1("KspStartBusDevice Name %S DeviceName %S Instance %S Started\n", Name, DeviceEntry->DeviceName, DeviceEntry->Instance);
/* enable device classes */
//KspEnableBusDeviceInterface(DeviceEntry, TRUE);
/* done */
return STATUS_SUCCESS;
}
NTSTATUS
KspQueryBusDeviceCapabilities(
IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
IN PIRP Irp)
{
PDEVICE_CAPABILITIES Capabilities;
PIO_STACK_LOCATION IoStack;
/* get stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* get capabilities */
Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
/* setup capabilities */
Capabilities->UniqueID = TRUE;
Capabilities->SilentInstall = TRUE;
Capabilities->SurpriseRemovalOK = TRUE;
Capabilities->Address = 0;
Capabilities->UINumber = 0;
Capabilities->SystemWake = PowerSystemWorking; /* FIXME common device extension */
Capabilities->DeviceWake = PowerDeviceD0;
/* done */
return STATUS_SUCCESS;
}
NTSTATUS
KspQueryBusInformation(
IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
IN PIRP Irp)
{
PPNP_BUS_INFORMATION BusInformation;
/* allocate bus information */
BusInformation = (PPNP_BUS_INFORMATION)AllocateItem(PagedPool, sizeof(PNP_BUS_INFORMATION));
if (!BusInformation)
{
/* no memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* return info */
BusInformation->BusNumber = 0;
BusInformation->LegacyBusType = InterfaceTypeUndefined;
RtlMoveMemory(&BusInformation->BusTypeGuid, &KSMEDIUMSETID_Standard, sizeof(GUID));
/* store result */
Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
/* done */
return STATUS_SUCCESS;
}
NTSTATUS
KspQueryBusDevicePnpState(
IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
IN PIRP Irp)
{
/* set device flags */
Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI | PNP_DEVICE_NOT_DISABLEABLE;
/* done */
return STATUS_SUCCESS;
}
NTSTATUS
KspQueryId(
IN PCOMMON_DEVICE_EXTENSION ChildDeviceExtension,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PBUS_DEVICE_ENTRY DeviceEntry;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
LPWSTR Name;
ULONG Length;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
{
/* get device entry */
DeviceEntry = (PBUS_DEVICE_ENTRY) ChildDeviceExtension->DeviceEntry;
/* sanity check */
ASSERT(DeviceEntry);
ASSERT(DeviceEntry->Instance);
/* calculate length */
Length = wcslen(DeviceEntry->Instance) + 1;
/* allocate buffer */
Name = AllocateItem(PagedPool, Length * sizeof(WCHAR));
if (!Name)
{
/* failed to allocate buffer */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* copy buffer */
wcscpy(Name, DeviceEntry->Instance);
/* store result */
Irp->IoStatus.Information = (ULONG_PTR)Name;
/* done */
return STATUS_SUCCESS;
}
else if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID ||
IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
{
/* get device entry */
DeviceEntry = (PBUS_DEVICE_ENTRY) ChildDeviceExtension->DeviceEntry;
/* get bus device extension */
BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION) ChildDeviceExtension->BusDeviceExtension;
/* sanity check */
ASSERT(DeviceEntry);
ASSERT(DeviceEntry->BusId);
ASSERT(BusDeviceExtension);
ASSERT(BusDeviceExtension->BusIdentifier);
/* calculate length */
Length = wcslen(BusDeviceExtension->BusIdentifier);
Length += wcslen(DeviceEntry->BusId);
/* extra length for '\\' and zero byte */
Length += 2;
/* allocate buffer */
Name = ExAllocatePool(PagedPool, Length * sizeof(WCHAR));
if (!Name)
{
/* failed to allocate buffer */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* construct id */
swprintf(Name, L"%s\\%s", BusDeviceExtension->BusIdentifier, DeviceEntry->BusId);
/* store result */
Irp->IoStatus.Information = (ULONG_PTR)Name;
/* done */
return STATUS_SUCCESS;
}
else
{
/* other ids are not supported */
//DPRINT1("Not Supported ID Type %x\n", IoStack->Parameters.QueryId.IdType);
return Irp->IoStatus.Status;
}
}
NTSTATUS
KspInstallInterface(
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PSWENUM_INSTALL_INTERFACE InstallInterface)
{
ULONG Length, Index;
UNICODE_STRING DeviceString, InterfaceString, ReferenceString;
HANDLE hKey, hDeviceKey, hInterfaceKey, hReferenceKey;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
/* calculate length */
Length = wcslen(InstallInterface->ReferenceString);
/* check for invalid characters */
for(Index = 0; Index < Length; Index++)
{
if (InstallInterface->ReferenceString[Index] <= L' ' ||
InstallInterface->ReferenceString[Index] > L'~' ||
InstallInterface->ReferenceString[Index] == L',' ||
InstallInterface->ReferenceString[Index] == L'\\' ||
InstallInterface->ReferenceString[Index] == L'/')
{
/* invalid character */
return STATUS_INVALID_PARAMETER;
}
}
/* open bus key */
Status = KspOpenBusRegistryKey(BusDeviceExtension, &hKey);
if (NT_SUCCESS(Status))
{
/* convert device guid to string */
Status = RtlStringFromGUID(&InstallInterface->DeviceId, &DeviceString);
if (NT_SUCCESS(Status))
{
/* initialize object attributes */
InitializeObjectAttributes(&ObjectAttributes, &DeviceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hKey, NULL);
/* construct device key */
Status = ZwCreateKey(&hDeviceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
if (NT_SUCCESS(Status))
{
/* initialize reference string */
RtlInitUnicodeString(&ReferenceString, InstallInterface->ReferenceString);
/* initialize object attributes */
InitializeObjectAttributes(&ObjectAttributes, &ReferenceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceKey, NULL);
/* construct device key */
Status = ZwCreateKey(&hReferenceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
if (NT_SUCCESS(Status))
{
/* convert interface guid to string */
Status = RtlStringFromGUID(&InstallInterface->InterfaceId, &InterfaceString);
if (NT_SUCCESS(Status))
{
/* initialize object attributes */
InitializeObjectAttributes(&ObjectAttributes, &InterfaceString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hReferenceKey, NULL);
/* construct device key */
Status = ZwCreateKey(&hInterfaceKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
if (NT_SUCCESS(Status))
{
/* close key */
ZwClose(hInterfaceKey);
}
/* free interface string */
RtlFreeUnicodeString(&InterfaceString);
}
/* close reference key */
ZwClose(hReferenceKey);
}
/* close device key */
ZwClose(hDeviceKey);
}
/* free device string */
RtlFreeUnicodeString(&DeviceString);
}
/* close bus key */
ZwClose(hKey);
}
/* done */
return Status;
}
VOID
NTAPI
KspInstallBusEnumInterface(
IN PVOID Ctx)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
PLIST_ENTRY Entry;
PBUS_DEVICE_ENTRY DeviceEntry;
PSWENUM_INSTALL_INTERFACE InstallInterface;
PBUS_INSTALL_ENUM_CONTEXT Context = (PBUS_INSTALL_ENUM_CONTEXT)Ctx;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
/* get install request */
InstallInterface = (PSWENUM_INSTALL_INTERFACE)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SWENUM_INSTALL_INTERFACE))
{
/* buffer too small */
Context->Status = STATUS_INVALID_PARAMETER;
/* signal completion */
KeSetEvent(&Context->Event, 0, FALSE);
/* done */
return;
}
/* FIXME locks */
/* now install the interface */
Status = KspInstallInterface(Context->BusDeviceExtension, InstallInterface);
if (!NT_SUCCESS(Status))
{
/* failed to install interface */
Context->Status = Status;
/* signal completion */
KeSetEvent(&Context->Event, 0, FALSE);
/* done */
return;
}
/* now iterate all device entries */
Entry = Context->BusDeviceExtension->Common.Entry.Flink;
while(Entry != &Context->BusDeviceExtension->Common.Entry)
{
/* get device entry */
DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
if (IsEqualGUIDAligned(&DeviceEntry->DeviceGuid, &InstallInterface->DeviceId) &&
!wcsicmp(DeviceEntry->Instance, InstallInterface->ReferenceString))
{
if (!DeviceEntry->PDO)
{
/* create pdo */
Status = KspCreatePDO(Context->BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
/* done */
break;
}
}
}
/* signal that bus driver relations has changed */
IoInvalidateDeviceRelations(Context->BusDeviceExtension->PhysicalDeviceObject, BusRelations);
/* update status */
Context->Status = Status;
/* signal completion */
KeSetEvent(&Context->Event, 0, FALSE);
}
VOID
NTAPI
KspBusWorkerRoutine(
IN PVOID Parameter)
{
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
PBUS_DEVICE_ENTRY DeviceEntry;
PLIST_ENTRY Entry;
LARGE_INTEGER Time, Diff;
BOOLEAN DoInvalidate = FALSE;
KIRQL OldLevel;
/* acquire lock */
KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
/* get device extension */
BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)Parameter;
/* get current time */
KeQuerySystemTime(&Time);
/* enumerate all device entries */
Entry = BusDeviceExtension->Common.Entry.Flink;
while(Entry != &BusDeviceExtension->Common.Entry)
{
/* get offset to device entry */
DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
/* sanity check */
ASSERT(DeviceEntry);
//DPRINT1("DeviceEntry %p PDO %p State %x\n", DeviceEntry, DeviceEntry->PDO, DeviceEntry->DeviceState);
if (DeviceEntry->PDO)
{
if (DeviceEntry->DeviceState == NotStarted)
{
Diff.QuadPart = Time.QuadPart - DeviceEntry->TimeCreated.QuadPart;
if (Diff.QuadPart > Int32x32To64(15000, 10000))
{
DPRINT1("DeviceID %S Instance %S TimeCreated %I64u Now %I64u Diff %I64u hung\n", DeviceEntry->DeviceName, DeviceEntry->Instance, DeviceEntry->TimeCreated.QuadPart, Time.QuadPart, Diff.QuadPart);
/* release spin lock */
KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
/* deactivate interfaces */
//KspEnableBusDeviceInterface(DeviceEntry, FALSE);
/* re-acquire lock */
KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
/* pending remove device object */
DeviceEntry->DeviceState = StopPending;
/* perform invalidation */
DoInvalidate = TRUE;
}
}
else if (DeviceEntry->DeviceState == Started)
{
/* found pending irps */
KspCompletePendingIrps(DeviceEntry, STATUS_REPARSE);
}
}
/* move to next */
Entry = Entry->Flink;
}
/* release lock */
KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
if (DoInvalidate)
{
/* invalidate device relations */
IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
}
Time.QuadPart = Int32x32To64(5000, -10000);
KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
}
VOID
NTAPI
KspBusDpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext OPTIONAL,
IN PVOID SystemArgument1 OPTIONAL,
IN PVOID SystemArgument2 OPTIONAL)
{
/* get device extension */
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeferredContext;
/* queue the item */
ExQueueWorkItem(&BusDeviceExtension->WorkItem, DelayedWorkQueue);
}
VOID
NTAPI
KspRemoveBusInterface(
PVOID Ctx)
{
PBUS_INSTALL_ENUM_CONTEXT Context =(PBUS_INSTALL_ENUM_CONTEXT)Ctx;
/* TODO
* get SWENUM_INSTALL_INTERFACE struct
* open device key and delete the keys
*/
UNIMPLEMENTED
/* set status */
Context->Status = STATUS_NOT_IMPLEMENTED;
/* signal completion */
KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
}
NTSTATUS
KspQueryBusRelations(
IN PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension,
IN PIRP Irp)
{
PDEVICE_RELATIONS DeviceRelations;
PLIST_ENTRY Entry;
PBUS_DEVICE_ENTRY DeviceEntry;
ULONG Count = 0, Length;
KIRQL OldLevel;
/* acquire lock */
KeAcquireSpinLock(&BusDeviceExtension->Lock, &OldLevel);
/* first scan all device entries */
Entry = BusDeviceExtension->Common.Entry.Flink;
while(Entry != &BusDeviceExtension->Common.Entry)
{
/* get offset to device entry */
DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
/* is there a pdo yet */
if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
{
/* increment count */
Count++;
}
/* move to next entry */
Entry = Entry->Flink;
}
/* calculate length */
Length = sizeof(DEVICE_RELATIONS) + (Count > 1 ? sizeof(PDEVICE_OBJECT) * (Count-1) : 0);
/* allocate device relations */
DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(NonPagedPool, Length);
if (!DeviceRelations)
{
/* not enough memory */
KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* rescan device entries */
Entry = BusDeviceExtension->Common.Entry.Flink;
while(Entry != &BusDeviceExtension->Common.Entry)
{
/* get offset to device entry */
DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
/* is there a pdo yet */
if (DeviceEntry->PDO && (DeviceEntry->DeviceState == NotStarted || DeviceEntry->DeviceState == Started))
{
/* store pdo */
DeviceRelations->Objects[DeviceRelations->Count] = DeviceEntry->PDO;
/* reference device object */
ObReferenceObject(DeviceEntry->PDO);
/* increment pdo count */
DeviceRelations->Count++;
}
/* move to next entry */
Entry = Entry->Flink;
}
/* release lock */
KeReleaseSpinLock(&BusDeviceExtension->Lock, OldLevel);
/* FIXME handle existing device relations */
ASSERT(Irp->IoStatus.Information == 0);
/* store device relations */
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
/* done */
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------------------
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsGetBusEnumIdentifier(
IN PIRP Irp)
{
PDEV_EXTENSION DeviceExtension;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
PIO_STACK_LOCATION IoStack;
ULONG Length;
NTSTATUS Status;
LPWSTR Buffer;
DPRINT1("KsGetBusEnumIdentifier\n");
/* get stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* sanity checks */
ASSERT(IoStack->DeviceObject);
ASSERT(IoStack->DeviceObject->DeviceExtension);
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
/* get bus device extension */
BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext->BusDeviceExtension;
/* sanity checks */
ASSERT(BusDeviceExtension);
ASSERT(BusDeviceExtension->Common.IsBus);
if (!BusDeviceExtension)
{
/* invalid parameter */
return STATUS_INVALID_PARAMETER;
}
/* get length */
Length = (wcslen(BusDeviceExtension->BusIdentifier)+1) * sizeof(WCHAR);
/* is there an output buffer provided */
if (IoStack->Parameters.DeviceIoControl.InputBufferLength)
{
if (Length > IoStack->Parameters.DeviceIoControl.InputBufferLength)
{
/* buffer is too small */
return STATUS_BUFFER_TOO_SMALL;
}
/* now allocate buffer */
Buffer = AllocateItem(NonPagedPool, Length);
if (!Buffer)
{
/* no memory */
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
/* copy bus identifier */
wcscpy(Buffer, BusDeviceExtension->BusIdentifier);
/* store buffer */
Irp->AssociatedIrp.SystemBuffer = Buffer;
/* set flag that buffer gets copied back */
Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
/* done */
Status = STATUS_SUCCESS;
}
}
else
{
/* no buffer provided */
Status = STATUS_BUFFER_OVERFLOW;
}
/* done */
Irp->IoStatus.Status = Status;
return Status;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsGetBusEnumParentFDOFromChildPDO(
IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_OBJECT *FunctionalDeviceObject)
{
PDEV_EXTENSION DeviceExtension;
DPRINT1("KsGetBusEnumParentFDOFromChildPDO\n");
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
/* check if this is child pdo */
if (DeviceExtension->Ext->IsBus == FALSE)
{
/* return bus device object */
*FunctionalDeviceObject = DeviceExtension->Ext->BusDeviceExtension->BusDeviceObject;
/* done */
return STATUS_SUCCESS;
}
/* invalid parameter */
return STATUS_INVALID_PARAMETER;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsCreateBusEnumObject(
IN PWCHAR BusIdentifier,
IN PDEVICE_OBJECT BusDeviceObject,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PDEVICE_OBJECT PnpDeviceObject OPTIONAL,
IN REFGUID InterfaceGuid OPTIONAL,
IN PWCHAR ServiceRelativePath OPTIONAL)
{
ULONG Length;
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING ServiceKeyPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\");
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
PDEV_EXTENSION DeviceExtension;
DPRINT1("KsCreateBusEnumObject %S BusDeviceObject %p\n", ServiceRelativePath, BusDeviceObject);
/* calculate sizeof bus enum device extension */
Length = wcslen(BusIdentifier) * sizeof(WCHAR);
Length += sizeof(BUS_ENUM_DEVICE_EXTENSION);
BusDeviceExtension = AllocateItem(NonPagedPool, Length);
if (!BusDeviceExtension)
{
/* not enough memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)BusDeviceObject->DeviceExtension;
DPRINT1("DeviceExtension %p BusDeviceExtension %p\n", DeviceExtension, DeviceExtension->Ext);
/* store bus device extension */
DeviceExtension->Ext = (PCOMMON_DEVICE_EXTENSION)BusDeviceExtension;
DPRINT1("DeviceExtension %p BusDeviceExtension %p\n", DeviceExtension, DeviceExtension->Ext);
/* 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 = AllocateItem(NonPagedPool, Length);
if (!BusDeviceExtension->ServicePath.Buffer)
{
/* not enough memory */
FreeItem(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->DeviceInterfaceLink);
/* check for success */
if (!NT_SUCCESS(Status))
{
FreeItem(BusDeviceExtension->ServicePath.Buffer);
FreeItem(BusDeviceExtension);
return Status;
}
/* now enable device interface */
Status = IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, TRUE);
if (!NT_SUCCESS(Status))
{
FreeItem(BusDeviceExtension->ServicePath.Buffer);
FreeItem(BusDeviceExtension);
return Status;
}
}
/* initialize common device extension */
BusDeviceExtension->Common.BusDeviceExtension = NULL;
BusDeviceExtension->Common.DeviceObjectReferenceCount = 1;
BusDeviceExtension->Common.DeviceReferenceCount = 1;
BusDeviceExtension->Common.IsBus = TRUE;
InitializeListHead(&BusDeviceExtension->Common.Entry);
/* store device objects */
BusDeviceExtension->BusDeviceObject = BusDeviceObject;
BusDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
/* initialize lock */
KeInitializeSpinLock(&BusDeviceExtension->Lock);
/* initialize timer */
KeInitializeTimer(&BusDeviceExtension->Timer);
/* initialize dpc */
KeInitializeDpc(&BusDeviceExtension->Dpc, KspBusDpcRoutine, (PVOID)BusDeviceExtension);
/* initialize event */
KeInitializeEvent(&BusDeviceExtension->Event, SynchronizationEvent, FALSE);
/* initialize work item */
ExInitializeWorkItem(&BusDeviceExtension->WorkItem, KspBusWorkerRoutine, (PVOID)BusDeviceExtension);
if (!PnpDeviceObject)
{
/* attach device */
BusDeviceExtension->PnpDeviceObject = IoAttachDeviceToDeviceStack(BusDeviceObject, PhysicalDeviceObject);
if (!BusDeviceExtension->PnpDeviceObject)
{
/* failed to attach device */
if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
{
IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
}
/* free device extension */
FreeItem(BusDeviceExtension->ServicePath.Buffer);
FreeItem(BusDeviceExtension);
return STATUS_DEVICE_REMOVED;
}
/* mark device as attached */
BusDeviceExtension->DeviceAttached = TRUE;
}
else
{
/* directly attach */
BusDeviceExtension->PnpDeviceObject = PnpDeviceObject;
}
/* now scan the bus */
Status = KspScanBus(BusDeviceExtension);
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed to scan bus */
if (BusDeviceExtension->DeviceInterfaceLink.Buffer)
{
IoSetDeviceInterfaceState(&BusDeviceExtension->DeviceInterfaceLink, FALSE);
RtlFreeUnicodeString(&BusDeviceExtension->DeviceInterfaceLink);
}
if (BusDeviceExtension->DeviceAttached)
{
/* detach device */
IoDetachDevice(BusDeviceExtension->PnpDeviceObject);
}
/* free device extension */
FreeItem(BusDeviceExtension->ServicePath.Buffer);
FreeItem(BusDeviceExtension);
}
DPRINT("KsCreateBusEnumObject Status %x\n", Status);
/* done */
return Status;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsGetBusEnumPnpDeviceObject(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT *PnpDeviceObject)
{
PDEV_EXTENSION DeviceExtension;
PCOMMON_DEVICE_EXTENSION CommonDeviceExtension;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
DPRINT("KsGetBusEnumPnpDeviceObject\n");
if (!DeviceObject->DeviceExtension)
{
/* invalid parameter */
return STATUS_INVALID_PARAMETER;
}
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
/* get common device extension */
CommonDeviceExtension = DeviceExtension->Ext;
if (!CommonDeviceExtension)
{
/* invalid parameter */
return STATUS_INVALID_PARAMETER;
}
if (!CommonDeviceExtension->IsBus)
{
/* getting pnp device object is only supported for software bus device object */
return STATUS_INVALID_PARAMETER;
}
/* sanity checks */
ASSERT(CommonDeviceExtension);
ASSERT(CommonDeviceExtension->IsBus);
/* cast to bus device extension */
BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)CommonDeviceExtension;
/* store result */
*PnpDeviceObject = BusDeviceExtension->PnpDeviceObject;
/* done */
return STATUS_SUCCESS;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsInstallBusEnumInterface(
PIRP Irp)
{
BUS_INSTALL_ENUM_CONTEXT Context;
KPROCESSOR_MODE Mode;
LUID luid;
PIO_STACK_LOCATION IoStack;
PDEV_EXTENSION DeviceExtension;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
DPRINT1("KsGetBusEnumPnpDeviceObject\n");
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* 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;
}
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
/* get bus device extension */
BusDeviceExtension = DeviceExtension->Ext->BusDeviceExtension;
/* initialize context */
Context.Irp = Irp;
KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
Context.BusDeviceExtension = BusDeviceExtension;
ExInitializeWorkItem(&Context.WorkItem, KspInstallBusEnumInterface, (PVOID)&Context);
/* queue the work item */
ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
/* wait for completion */
KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
/* done */
return Context.Status;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsIsBusEnumChildDevice(
IN PDEVICE_OBJECT DeviceObject,
OUT PBOOLEAN ChildDevice)
{
PDEV_EXTENSION DeviceExtension;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
DPRINT("KsIsBusEnumChildDevice %p\n", DeviceObject);
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
/* get bus device extension */
BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
if (!BusDeviceExtension)
{
/* not a bus device */
return STATUS_INVALID_PARAMETER;
}
/* store result */
*ChildDevice = (BusDeviceExtension->Common.IsBus == FALSE);
return STATUS_SUCCESS;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsServiceBusEnumCreateRequest(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PLIST_ENTRY Entry;
PBUS_DEVICE_ENTRY DeviceEntry = NULL; /* fix gcc */
PIO_STACK_LOCATION IoStack;
BOOLEAN ItemExists = FALSE;
PDEV_EXTENSION DeviceExtension;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
//PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
NTSTATUS Status;
LARGE_INTEGER Time;
/* FIXME: locks */
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
/* get bus device extension */
BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* sanity checks */
ASSERT(IoStack->FileObject);
ASSERT(IoStack->FileObject->FileName.Buffer);
DPRINT1("KsServiceBusEnumCreateRequest IRP %p Name %wZ\n", Irp, &IoStack->FileObject->FileName);
/* scan list and check if it is already present */
Entry = BusDeviceExtension->Common.Entry.Flink;
while(Entry != &BusDeviceExtension->Common.Entry)
{
/* get real offset */
DeviceEntry = (PBUS_DEVICE_ENTRY)CONTAINING_RECORD(Entry, BUS_DEVICE_ENTRY, Entry);
/* check if name matches */
if (!wcsicmp(DeviceEntry->DeviceName, IoStack->FileObject->FileName.Buffer + 1))
{
/* item already exists */
ItemExists = TRUE;
break;
}
/* move to next entry */
Entry = Entry->Flink;
}
if (!ItemExists)
{
/* interface not registered */
DPRINT1("Interface %wZ not registered\n", &IoStack->FileObject->FileName);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
/* is there a pdo yet */
if (DeviceEntry->PDO)
{
if (DeviceEntry->DeviceState == Started)
{
/* issue reparse */
Status = KspDoReparseForIrp(Irp, DeviceEntry);
DPRINT("REPARSE Irp %p '%wZ'\n", Irp, &IoStack->FileObject->FileName);
Irp->IoStatus.Status = Status;
return Status;
}
/* delay processing until pnp is finished with enumeration */
IoMarkIrpPending(Irp);
/* insert into irp pending list */
InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
Time.QuadPart = Int32x32To64(1500, -10000);
DbgPrint("PENDING Irp %p %wZ\n", Irp, &IoStack->FileObject->FileName);
/* query current time */
KeQuerySystemTime(&DeviceEntry->TimeCreated);
/* set timer */
KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
/* done for now */
return STATUS_PENDING;
}
else
{
/* time to create PDO */
Status = KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
if (!NT_SUCCESS(Status))
{
/* failed to create PDO */
DPRINT1("KsServiceBusEnumCreateRequest failed to create PDO with %x\n", Status);
return Status;
}
DPRINT1("PENDING CREATE Irp %p %wZ\n", Irp, &IoStack->FileObject->FileName);
/* delay processing until pnp is finished with enumeration */
IoMarkIrpPending(Irp);
/* insert into irp pending list */
InsertTailList(&DeviceEntry->IrpPendingList, &Irp->Tail.Overlay.ListEntry);
/* get current time */
KeQuerySystemTime(&DeviceEntry->TimeCreated);
/* invalidate device relations */
IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
/* done for now */
return STATUS_PENDING;
}
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsServiceBusEnumPnpRequest(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PDEV_EXTENSION DeviceExtension;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
PCOMMON_DEVICE_EXTENSION ChildDeviceExtension;
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
LARGE_INTEGER Time;
PDEVICE_RELATIONS DeviceRelation;
PBUS_DEVICE_ENTRY DeviceEntry;
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)DeviceObject->DeviceExtension;
/* get bus device extension */
BusDeviceExtension = (PBUS_ENUM_DEVICE_EXTENSION)DeviceExtension->Ext;
/* get current irp stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
if (BusDeviceExtension->Common.IsBus)
{
if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
{
/* no op for bus driver */
Status = STATUS_SUCCESS;
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)
{
/* handle bus device relations */
ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == BusRelations);
Status = KspQueryBusRelations(BusDeviceExtension, Irp);
}
else
{
/* get default status */
Status = Irp->IoStatus.Status;
}
}
else
{
/* get child device extension */
ChildDeviceExtension = DeviceExtension->Ext;
/* get bus device extension */
BusDeviceExtension = ChildDeviceExtension->BusDeviceExtension;
if (IoStack->MinorFunction == IRP_MN_QUERY_ID)
{
/* query id */
Status = KspQueryId(ChildDeviceExtension, Irp);
}
else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
{
ASSERT(ChildDeviceExtension->DeviceEntry->DeviceState != Started || ChildDeviceExtension->DeviceEntry->DeviceState == NotStarted);
ASSERT(ChildDeviceExtension->DeviceEntry->PDO == DeviceObject);
/* backup device entry */
DeviceEntry = ChildDeviceExtension->DeviceEntry;
/* free device extension */
FreeItem(ChildDeviceExtension);
/* clear PDO reference */
DeviceEntry->PDO = NULL;
/* delete the device */
IoDeleteDevice(DeviceObject);
if (DeviceEntry->PDODeviceName)
{
/* delete pdo device name */
FreeItem(DeviceEntry->PDODeviceName);
/* set to null */
DeviceEntry->PDODeviceName = NULL;
}
/* set state no notstarted */
DeviceEntry->DeviceState = NotStarted;
/* time to create PDO */
KspCreatePDO(BusDeviceExtension, DeviceEntry, &DeviceEntry->PDO);
/* invalidate device relations */
IoInvalidateDeviceRelations(BusDeviceExtension->PhysicalDeviceObject, BusRelations);
/* done */
Status = STATUS_SUCCESS;
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_BUS_INFORMATION)
{
/* query bus information */
Status = KspQueryBusInformation(ChildDeviceExtension, Irp);
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCES)
{
/* no op */
Status = STATUS_SUCCESS;
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
{
/* no op */
Status = STATUS_SUCCESS;
}
else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
{
/* start bus */
Status = KspStartBusDevice(DeviceObject, ChildDeviceExtension, Irp);
/* set time out */
Time.QuadPart = Int32x32To64(1500, -10000);
/* sanity check */
ASSERT(BusDeviceExtension);
/* set timer */
KeSetTimer(&BusDeviceExtension->Timer, Time, &BusDeviceExtension->Dpc);
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_CAPABILITIES)
{
/* query capabilities */
Status = KspQueryBusDeviceCapabilities(ChildDeviceExtension, Irp);
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
{
/* query pnp state */
Status = KspQueryBusDevicePnpState(ChildDeviceExtension, Irp);
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_INTERFACE)
{
/* query interface */
Status = KspQueryBusDeviceInterface(ChildDeviceExtension, Irp);
}
else if (IoStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS && IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
{
/* handle target device relations */
ASSERT(IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation);
ASSERT(Irp->IoStatus.Information == 0);
/* allocate device relation */
DeviceRelation = AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
if (DeviceRelation)
{
DeviceRelation->Count = 1;
DeviceRelation->Objects[0] = DeviceObject;
/* reference self */
ObReferenceObject(DeviceObject);
/* store result */
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
/* done */
Status = STATUS_SUCCESS;
}
else
{
/* no memory */
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
/* get default status */
Status = Irp->IoStatus.Status;
}
}
DPRINT("KsServiceBusEnumPnpRequest %p Bus %u Function %x Status %x\n", DeviceObject, BusDeviceExtension->Common.IsBus, IoStack->MinorFunction, Status);
Irp->IoStatus.Status = Status;
return Status;
}
/*
@implemented
*/
KSDDKAPI
NTSTATUS
NTAPI
KsRemoveBusEnumInterface(
IN PIRP Irp)
{
KPROCESSOR_MODE Mode;
LUID luid;
BUS_INSTALL_ENUM_CONTEXT Ctx;
PDEV_EXTENSION DeviceExtension;
PBUS_ENUM_DEVICE_EXTENSION BusDeviceExtension;
PIO_STACK_LOCATION IoStack;
DPRINT1("KsRemoveBusEnumInterface\n");
/* get io stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* get device extension */
DeviceExtension = (PDEV_EXTENSION)IoStack->DeviceObject->DeviceExtension;
/* get bus device extension */
BusDeviceExtension = DeviceExtension->Ext->BusDeviceExtension;
/* 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 context */
KeInitializeEvent(&Ctx.Event, NotificationEvent, FALSE);
Ctx.Irp = Irp;
Ctx.BusDeviceExtension = BusDeviceExtension;
ExInitializeWorkItem(&Ctx.WorkItem, KspRemoveBusInterface, (PVOID)&Ctx);
/* now queue the work item */
ExQueueWorkItem(&Ctx.WorkItem, DelayedWorkQueue);
/* wait for completion */
KeWaitForSingleObject(&Ctx.Event, Executive, KernelMode, FALSE, NULL);
/* return result */
return Ctx.Status;
}