+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * COPYRIGHT: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/io/pnpmgr/plugplay.c
- * PURPOSE: Plug-and-play interface routines
- * PROGRAMMERS: Eric Kohl <eric.kohl@t-online.de>
- */
-
-/* INCLUDES *****************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <debug.h>
-
-#if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, IopInitPlugPlayEvents)
-#endif
-
-typedef struct _PNP_EVENT_ENTRY
-{
- LIST_ENTRY ListEntry;
- PLUGPLAY_EVENT_BLOCK Event;
-} PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY;
-
-
-/* GLOBALS *******************************************************************/
-
-static LIST_ENTRY IopPnpEventQueueHead;
-static KEVENT IopPnpNotifyEvent;
-
-/* FUNCTIONS *****************************************************************/
-
-NTSTATUS INIT_FUNCTION
-IopInitPlugPlayEvents(VOID)
-{
- InitializeListHead(&IopPnpEventQueueHead);
-
- KeInitializeEvent(&IopPnpNotifyEvent,
- SynchronizationEvent,
- FALSE);
-
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-IopQueueTargetDeviceEvent(const GUID *Guid,
- PUNICODE_STRING DeviceIds)
-{
- PPNP_EVENT_ENTRY EventEntry;
- UNICODE_STRING Copy;
- ULONG TotalSize;
- NTSTATUS Status;
-
- ASSERT(DeviceIds);
-
- /* Allocate a big enough buffer */
- Copy.Length = 0;
- Copy.MaximumLength = DeviceIds->Length + sizeof(UNICODE_NULL);
- TotalSize =
- FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) +
- Copy.MaximumLength;
-
- EventEntry = ExAllocatePool(NonPagedPool,
- TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
- if (!EventEntry)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Fill the buffer with the event GUID */
- RtlCopyMemory(&EventEntry->Event.EventGuid,
- Guid,
- sizeof(GUID));
- EventEntry->Event.EventCategory = TargetDeviceChangeEvent;
- EventEntry->Event.TotalSize = TotalSize;
-
- /* Fill the device id */
- Copy.Buffer = EventEntry->Event.TargetDevice.DeviceIds;
- Status = RtlAppendUnicodeStringToString(&Copy, DeviceIds);
- if (!NT_SUCCESS(Status))
- {
- ExFreePool(EventEntry);
- return Status;
- }
-
- InsertHeadList(&IopPnpEventQueueHead,
- &EventEntry->ListEntry);
- KeSetEvent(&IopPnpNotifyEvent,
- 0,
- FALSE);
-
- return STATUS_SUCCESS;
-}
-
-
-/*
- * Remove the current PnP event from the tail of the event queue
- * and signal IopPnpNotifyEvent if there is yet another event in the queue.
- */
-static NTSTATUS
-IopRemovePlugPlayEvent(VOID)
-{
- /* Remove a pnp event entry from the tail of the queue */
- if (!IsListEmpty(&IopPnpEventQueueHead))
- {
- ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead), PNP_EVENT_ENTRY, ListEntry));
- }
-
- /* Signal the next pnp event in the queue */
- if (!IsListEmpty(&IopPnpEventQueueHead))
- {
- KeSetEvent(&IopPnpNotifyEvent,
- 0,
- FALSE);
- }
-
- return STATUS_SUCCESS;
-}
-
-static PDEVICE_OBJECT
-IopTraverseDeviceNode(PDEVICE_NODE Node, PUNICODE_STRING DeviceInstance)
-{
- PDEVICE_OBJECT DeviceObject;
- PDEVICE_NODE ChildNode;
-
- if (RtlEqualUnicodeString(&Node->InstancePath,
- DeviceInstance, TRUE))
- {
- ObReferenceObject(Node->PhysicalDeviceObject);
- return Node->PhysicalDeviceObject;
- }
-
- /* Traversal of all children nodes */
- for (ChildNode = Node->Child;
- ChildNode != NULL;
- ChildNode = ChildNode->Sibling)
- {
- DeviceObject = IopTraverseDeviceNode(ChildNode, DeviceInstance);
- if (DeviceObject != NULL)
- {
- return DeviceObject;
- }
- }
-
- return NULL;
-}
-
-
-PDEVICE_OBJECT
-IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
-{
- if (IopRootDeviceNode == NULL)
- return NULL;
-
- if (DeviceInstance == NULL ||
- DeviceInstance->Length == 0)
- {
- if (IopRootDeviceNode->PhysicalDeviceObject)
- {
- ObReferenceObject(IopRootDeviceNode->PhysicalDeviceObject);
- return IopRootDeviceNode->PhysicalDeviceObject;
- }
- else
- return NULL;
- }
-
- return IopTraverseDeviceNode(IopRootDeviceNode, DeviceInstance);
-}
-
-static NTSTATUS
-IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- volatile UNICODE_STRING Name;
-
- Name.Buffer = NULL;
- _SEH2_TRY
- {
- Name.Length = SrcName->Length;
- Name.MaximumLength = SrcName->MaximumLength;
- if (Name.Length > Name.MaximumLength)
- {
- Status = STATUS_INVALID_PARAMETER;
- _SEH2_LEAVE;
- }
-
- if (Name.MaximumLength)
- {
- ProbeForRead(SrcName->Buffer,
- Name.MaximumLength,
- sizeof(WCHAR));
- Name.Buffer = ExAllocatePool(NonPagedPool, Name.MaximumLength);
- if (Name.Buffer == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- _SEH2_LEAVE;
- }
-
- memcpy(Name.Buffer, SrcName->Buffer, Name.MaximumLength);
- }
-
- *DstName = Name;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- if (Name.Buffer)
- {
- ExFreePool(Name.Buffer);
- }
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
-
- return Status;
-}
-
-static NTSTATUS
-IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList)
-{
- NTSTATUS Status;
- PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList;
- UNICODE_STRING DeviceInstance;
- PDEVICE_OBJECT DeviceObject = NULL;
- GUID FilterGuid;
- PZZWSTR SymbolicLinkList = NULL, LinkList;
- SIZE_T TotalLength;
-
- _SEH2_TRY
- {
- RtlCopyMemory(&StackList, DeviceList, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
-
- ProbeForRead(StackList.FilterGuid, sizeof(GUID), sizeof(UCHAR));
- RtlCopyMemory(&FilterGuid, StackList.FilterGuid, sizeof(GUID));
-
- if (StackList.Buffer != NULL && StackList.BufferSize != 0)
- {
- ProbeForWrite(StackList.Buffer, StackList.BufferSize, sizeof(UCHAR));
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- Status = IopCaptureUnicodeString(&DeviceInstance, &StackList.DeviceInstance);
- if (NT_SUCCESS(Status))
- {
- /* Get the device object */
- DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
- if (DeviceInstance.Buffer != NULL)
- {
- ExFreePool(DeviceInstance.Buffer);
- }
- }
-
- Status = IoGetDeviceInterfaces(&FilterGuid, DeviceObject, StackList.Flags, &SymbolicLinkList);
- ObDereferenceObject(DeviceObject);
-
- if (!NT_SUCCESS(Status))
- {
- /* failed */
- return Status;
- }
-
- LinkList = SymbolicLinkList;
- while (*SymbolicLinkList != UNICODE_NULL)
- {
- SymbolicLinkList += wcslen(SymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
- }
- TotalLength = ((SymbolicLinkList - LinkList + 1) * sizeof(WCHAR));
-
- _SEH2_TRY
- {
- if (StackList.Buffer != NULL &&
- StackList.BufferSize >= TotalLength)
- {
- // We've already probed the buffer for writing above.
- RtlCopyMemory(StackList.Buffer, LinkList, TotalLength);
- }
-
- DeviceList->BufferSize = TotalLength;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- ExFreePool(LinkList);
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- ExFreePool(LinkList);
- return STATUS_SUCCESS;
-}
-
-static NTSTATUS
-IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
-{
- PDEVICE_OBJECT DeviceObject = NULL;
- NTSTATUS Status;
- UNICODE_STRING DeviceInstance;
- ULONG BufferSize;
- ULONG Property = 0;
- PVOID Buffer;
-
- DPRINT("IopGetDeviceProperty() called\n");
- DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance);
-
- Status = IopCaptureUnicodeString(&DeviceInstance, &PropertyData->DeviceInstance);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- _SEH2_TRY
- {
- Property = PropertyData->Property;
- BufferSize = PropertyData->BufferSize;
- ProbeForWrite(PropertyData->Buffer,
- BufferSize,
- sizeof(UCHAR));
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- if (DeviceInstance.Buffer != NULL)
- {
- ExFreePool(DeviceInstance.Buffer);
- }
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- /* Get the device object */
- DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
- if (DeviceInstance.Buffer != NULL)
- {
- ExFreePool(DeviceInstance.Buffer);
- }
- if (DeviceObject == NULL)
- {
- return STATUS_NO_SUCH_DEVICE;
- }
-
- Buffer = ExAllocatePool(NonPagedPool, BufferSize);
- if (Buffer == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- Status = IoGetDeviceProperty(DeviceObject,
- Property,
- BufferSize,
- Buffer,
- &BufferSize);
-
- ObDereferenceObject(DeviceObject);
-
- if (NT_SUCCESS(Status))
- {
- _SEH2_TRY
- {
- RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize);
- PropertyData->BufferSize = BufferSize;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
- }
-
- ExFreePool(Buffer);
- return Status;
-}
-
-
-static NTSTATUS
-IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData)
-{
- UNICODE_STRING RootDeviceName;
- PDEVICE_OBJECT DeviceObject = NULL;
- PDEVICE_NODE DeviceNode = NULL;
- PDEVICE_NODE RelatedDeviceNode;
- UNICODE_STRING TargetDeviceInstance;
- NTSTATUS Status = STATUS_SUCCESS;
- ULONG Relation = 0;
- ULONG MaximumLength = 0;
-
- DPRINT("IopGetRelatedDevice() called\n");
- DPRINT("Device name: %wZ\n", &RelatedDeviceData->TargetDeviceInstance);
-
- Status = IopCaptureUnicodeString(&TargetDeviceInstance, &RelatedDeviceData->TargetDeviceInstance);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- _SEH2_TRY
- {
- Relation = RelatedDeviceData->Relation;
- MaximumLength = RelatedDeviceData->RelatedDeviceInstanceLength;
- ProbeForWrite(RelatedDeviceData->RelatedDeviceInstance,
- MaximumLength,
- sizeof(WCHAR));
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- if (TargetDeviceInstance.Buffer != NULL)
- {
- ExFreePool(TargetDeviceInstance.Buffer);
- }
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- RtlInitUnicodeString(&RootDeviceName,
- L"HTREE\\ROOT\\0");
- if (RtlEqualUnicodeString(&TargetDeviceInstance,
- &RootDeviceName,
- TRUE))
- {
- DeviceNode = IopRootDeviceNode;
- if (TargetDeviceInstance.Buffer != NULL)
- {
- ExFreePool(TargetDeviceInstance.Buffer);
- }
- }
- else
- {
- /* Get the device object */
- DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance);
- if (TargetDeviceInstance.Buffer != NULL)
- {
- ExFreePool(TargetDeviceInstance.Buffer);
- }
- if (DeviceObject == NULL)
- return STATUS_NO_SUCH_DEVICE;
-
- DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
- }
-
- switch (Relation)
- {
- case PNP_GET_PARENT_DEVICE:
- RelatedDeviceNode = DeviceNode->Parent;
- break;
-
- case PNP_GET_CHILD_DEVICE:
- RelatedDeviceNode = DeviceNode->Child;
- break;
-
- case PNP_GET_SIBLING_DEVICE:
- RelatedDeviceNode = DeviceNode->Sibling;
- break;
-
- default:
- if (DeviceObject != NULL)
- {
- ObDereferenceObject(DeviceObject);
- }
-
- return STATUS_INVALID_PARAMETER;
- }
-
- if (RelatedDeviceNode == NULL)
- {
- if (DeviceObject)
- {
- ObDereferenceObject(DeviceObject);
- }
-
- return STATUS_NO_SUCH_DEVICE;
- }
-
- if (RelatedDeviceNode->InstancePath.Length > MaximumLength)
- {
- if (DeviceObject)
- {
- ObDereferenceObject(DeviceObject);
- }
-
- return STATUS_BUFFER_TOO_SMALL;
- }
-
- /* Copy related device instance name */
- _SEH2_TRY
- {
- RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance,
- RelatedDeviceNode->InstancePath.Buffer,
- RelatedDeviceNode->InstancePath.Length);
- RelatedDeviceData->RelatedDeviceInstanceLength = RelatedDeviceNode->InstancePath.Length;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
-
- if (DeviceObject != NULL)
- {
- ObDereferenceObject(DeviceObject);
- }
-
- DPRINT("IopGetRelatedDevice() done\n");
-
- return Status;
-}
-
-static ULONG
-IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode)
-{
- ULONG Output = 0;
-
- if (DeviceNode->Parent == IopRootDeviceNode)
- Output |= DN_ROOT_ENUMERATED;
-
- if (DeviceNode->Flags & DNF_ADDED)
- Output |= DN_DRIVER_LOADED;
-
- /* FIXME: DN_ENUM_LOADED */
-
- if (DeviceNode->Flags & DNF_STARTED)
- Output |= DN_STARTED;
-
- /* FIXME: Manual */
-
- if (!(DeviceNode->Flags & DNF_PROCESSED))
- Output |= DN_NEED_TO_ENUM;
-
- /* DN_NOT_FIRST_TIME is 9x only */
-
- /* FIXME: DN_HARDWARE_ENUM */
-
- /* DN_LIAR and DN_HAS_MARK are 9x only */
-
- if (DeviceNode->Problem != 0)
- Output |= DN_HAS_PROBLEM;
-
- /* FIXME: DN_FILTERED */
-
- if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
- Output |= DN_LEGACY_DRIVER;
-
- if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI)
- Output |= DN_NO_SHOW_IN_DM;
-
- if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE))
- Output |= DN_DISABLEABLE;
-
- /* FIXME: Implement the rest */
-
- Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER;
-
- return Output;
-}
-
-static NTSTATUS
-IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
-{
- PDEVICE_OBJECT DeviceObject;
- PDEVICE_NODE DeviceNode;
- ULONG Operation = 0;
- ULONG DeviceStatus = 0;
- ULONG DeviceProblem = 0;
- UNICODE_STRING DeviceInstance;
- NTSTATUS Status;
-
- DPRINT("IopDeviceStatus() called\n");
-
- Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- DPRINT("Device name: '%wZ'\n", &DeviceInstance);
-
- _SEH2_TRY
- {
- Operation = StatusData->Operation;
- if (Operation == PNP_SET_DEVICE_STATUS)
- {
- DeviceStatus = StatusData->DeviceStatus;
- DeviceProblem = StatusData->DeviceProblem;
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- if (DeviceInstance.Buffer != NULL)
- {
- ExFreePool(DeviceInstance.Buffer);
- }
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- /* Get the device object */
- DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
- if (DeviceInstance.Buffer != NULL)
- {
- ExFreePool(DeviceInstance.Buffer);
- }
- if (DeviceObject == NULL)
- {
- return STATUS_NO_SUCH_DEVICE;
- }
-
- DeviceNode = IopGetDeviceNode(DeviceObject);
-
- switch (Operation)
- {
- case PNP_GET_DEVICE_STATUS:
- DPRINT("Get status data\n");
- DeviceStatus = IopGetDeviceNodeStatus(DeviceNode);
- DeviceProblem = DeviceNode->Problem;
- break;
-
- case PNP_SET_DEVICE_STATUS:
- DPRINT1("Set status data is NOT SUPPORTED\n");
- break;
-
- case PNP_CLEAR_DEVICE_STATUS:
- DPRINT1("FIXME: Clear status data!\n");
- break;
- }
-
- ObDereferenceObject(DeviceObject);
-
- if (Operation == PNP_GET_DEVICE_STATUS)
- {
- _SEH2_TRY
- {
- StatusData->DeviceStatus = DeviceStatus;
- StatusData->DeviceProblem = DeviceProblem;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
- }
-
- return Status;
-}
-
-static
-NTSTATUS
-IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData)
-{
- UNICODE_STRING DeviceInstance;
- PDEVICE_OBJECT DeviceObject = NULL;
- IO_STACK_LOCATION Stack;
- IO_STATUS_BLOCK IoStatusBlock;
- PDEVICE_RELATIONS DeviceRelations = NULL;
- PDEVICE_OBJECT ChildDeviceObject;
- PDEVICE_NODE ChildDeviceNode;
- ULONG i;
- ULONG Relations;
- ULONG BufferSize, RequiredSize;
- ULONG BufferLeft;
- PWCHAR Buffer, Ptr;
- NTSTATUS Status = STATUS_SUCCESS;
-
- DPRINT("IopGetDeviceRelations() called\n");
- DPRINT("Device name: %wZ\n", &RelationsData->DeviceInstance);
- DPRINT("Relations: %lu\n", RelationsData->Relations);
- DPRINT("BufferSize: %lu\n", RelationsData->BufferSize);
- DPRINT("Buffer: %p\n", RelationsData->Buffer);
-
- _SEH2_TRY
- {
- Relations = RelationsData->Relations;
- BufferSize = RelationsData->BufferSize;
- Buffer = RelationsData->Buffer;
-
- ProbeForWrite(Buffer, BufferSize, sizeof(CHAR));
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- Status = IopCaptureUnicodeString(&DeviceInstance, &RelationsData->DeviceInstance);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status);
- return Status;
- }
-
- /* Get the device object */
- DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
- if (DeviceObject == NULL)
- {
- DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
- Status = STATUS_NO_SUCH_DEVICE;
- goto done;
- }
-
- switch (Relations)
- {
- case 0: /* EjectRelations */
- Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
- break;
-
- case 1: /* RemovalRelations */
- Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
- break;
-
- case 2: /* PowerRelations */
- Stack.Parameters.QueryDeviceRelations.Type = PowerRelations;
- break;
-
- case 3: /* BusRelations */
- Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
- break;
-
- default:
- Status = STATUS_INVALID_PARAMETER;
- goto done;
- }
-
- Status = IopInitiatePnpIrp(DeviceObject,
- &IoStatusBlock,
- IRP_MN_QUERY_DEVICE_RELATIONS,
- &Stack);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
- goto done;
- }
-
- DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
-
- DPRINT("Found %d device relations\n", DeviceRelations->Count);
-
- _SEH2_TRY
- {
- RequiredSize = 0;
- BufferLeft = BufferSize;
- Ptr = Buffer;
-
- for (i = 0; i < DeviceRelations->Count; i++)
- {
- ChildDeviceObject = DeviceRelations->Objects[i];
-
- ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
- if (ChildDeviceNode)
- {
- DPRINT("Device instance: %wZ\n", &ChildDeviceNode->InstancePath);
- DPRINT("RequiredSize: %hu\n", ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
-
- if (Ptr != NULL)
- {
- if (BufferLeft < ChildDeviceNode->InstancePath.Length + 2 * sizeof(WCHAR))
- {
- Status = STATUS_BUFFER_TOO_SMALL;
- break;
- }
-
- RtlCopyMemory(Ptr,
- ChildDeviceNode->InstancePath.Buffer,
- ChildDeviceNode->InstancePath.Length);
- Ptr = (PWCHAR)((ULONG_PTR)Ptr + ChildDeviceNode->InstancePath.Length);
- *Ptr = UNICODE_NULL;
- Ptr = (PWCHAR)((ULONG_PTR)Ptr + sizeof(WCHAR));
-
- BufferLeft -= (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
- }
-
- RequiredSize += (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
- }
- }
-
- if (Ptr != NULL && BufferLeft >= sizeof(WCHAR))
- *Ptr = UNICODE_NULL;
-
- if (RequiredSize > 0)
- RequiredSize += sizeof(WCHAR);
-
- DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData->BufferSize, RequiredSize);
-
- RelationsData->BufferSize = RequiredSize;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
-
-done:
- if (DeviceRelations != NULL)
- ExFreePool(DeviceRelations);
-
- if (DeviceObject != NULL)
- ObDereferenceObject(DeviceObject);
-
- if (DeviceInstance.Buffer != NULL)
- ExFreePool(DeviceInstance.Buffer);
-
- return Status;
-}
-
-static NTSTATUS
-IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData)
-{
- PDEVICE_OBJECT DeviceObject;
- PDEVICE_NODE DeviceNode;
- UNICODE_STRING DeviceInstance;
- NTSTATUS Status = STATUS_SUCCESS;
-
- DPRINT("IopGetDeviceDepth() called\n");
- DPRINT("Device name: %wZ\n", &DepthData->DeviceInstance);
-
- Status = IopCaptureUnicodeString(&DeviceInstance, &DepthData->DeviceInstance);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- /* Get the device object */
- DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
- if (DeviceInstance.Buffer != NULL)
- {
- ExFreePool(DeviceInstance.Buffer);
- }
- if (DeviceObject == NULL)
- {
- return STATUS_NO_SUCH_DEVICE;
- }
-
- DeviceNode = IopGetDeviceNode(DeviceObject);
-
- _SEH2_TRY
- {
- DepthData->Depth = DeviceNode->Level;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
-
- ObDereferenceObject(DeviceObject);
-
- return Status;
-}
-
-
-static NTSTATUS
-IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData)
-{
- PDEVICE_OBJECT DeviceObject;
- PDEVICE_NODE DeviceNode;
- NTSTATUS Status = STATUS_SUCCESS;
- UNICODE_STRING DeviceInstance;
-
- Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance);
-
- /* Get the device object */
- DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
- if (DeviceInstance.Buffer != NULL)
- {
- ExFreePool(DeviceInstance.Buffer);
- }
- if (DeviceObject == NULL)
- {
- return STATUS_NO_SUCH_DEVICE;
- }
-
- /* Get the device node */
- DeviceNode = IopGetDeviceNode(DeviceObject);
-
- ASSERT(DeviceNode->Flags & DNF_ENUMERATED);
- ASSERT(DeviceNode->Flags & DNF_PROCESSED);
-
- /* Check if there's already a driver loaded for this device */
- if (DeviceNode->Flags & DNF_ADDED)
- {
-#if 0
- /* Remove the device node */
- Status = IopRemoveDevice(DeviceNode);
- if (NT_SUCCESS(Status))
- {
- /* Invalidate device relations for the parent to reenumerate the device */
- DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode->InstancePath);
- Status = IoSynchronousInvalidateDeviceRelations(DeviceNode->Parent->PhysicalDeviceObject, BusRelations);
- }
- else
-#endif
- {
- /* A driver has already been loaded for this device */
- DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode->InstancePath);
- DeviceNode->Problem = CM_PROB_NEED_RESTART;
- }
- }
- else
- {
- /* FIXME: What if the device really is disabled? */
- DeviceNode->Flags &= ~DNF_DISABLED;
- DeviceNode->Problem = 0;
-
- /* Load service data from the registry */
- Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
-
- if (NT_SUCCESS(Status))
- {
- /* Start the service and begin PnP initialization of the device again */
- DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode->InstancePath);
- Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent);
- }
- }
-
- ObDereferenceObject(DeviceObject);
-
- return Status;
-}
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * Plug and Play event structure used by NtGetPlugPlayEvent.
- *
- * EventGuid
- * Can be one of the following values:
- * GUID_HWPROFILE_QUERY_CHANGE
- * GUID_HWPROFILE_CHANGE_CANCELLED
- * GUID_HWPROFILE_CHANGE_COMPLETE
- * GUID_TARGET_DEVICE_QUERY_REMOVE
- * GUID_TARGET_DEVICE_REMOVE_CANCELLED
- * GUID_TARGET_DEVICE_REMOVE_COMPLETE
- * GUID_PNP_CUSTOM_NOTIFICATION
- * GUID_PNP_POWER_NOTIFICATION
- * GUID_DEVICE_* (see above)
- *
- * EventCategory
- * Type of the event that happened.
- *
- * Result
- * ?
- *
- * Flags
- * ?
- *
- * TotalSize
- * Size of the event block including the device IDs and other
- * per category specific fields.
- */
-
-/*
- * NtGetPlugPlayEvent
- *
- * Returns one Plug & Play event from a global queue.
- *
- * Parameters
- * Reserved1
- * Reserved2
- * Always set to zero.
- *
- * Buffer
- * The buffer that will be filled with the event information on
- * successful return from the function.
- *
- * BufferSize
- * Size of the buffer pointed by the Buffer parameter. If the
- * buffer size is not large enough to hold the whole event
- * information, error STATUS_BUFFER_TOO_SMALL is returned and
- * the buffer remains untouched.
- *
- * Return Values
- * STATUS_PRIVILEGE_NOT_HELD
- * STATUS_BUFFER_TOO_SMALL
- * STATUS_SUCCESS
- *
- * Remarks
- * This function isn't multi-thread safe!
- *
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtGetPlugPlayEvent(IN ULONG Reserved1,
- IN ULONG Reserved2,
- OUT PPLUGPLAY_EVENT_BLOCK Buffer,
- IN ULONG BufferSize)
-{
- PPNP_EVENT_ENTRY Entry;
- NTSTATUS Status;
-
- DPRINT("NtGetPlugPlayEvent() called\n");
-
- /* Function can only be called from user-mode */
- if (KeGetPreviousMode() == KernelMode)
- {
- DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
- return STATUS_ACCESS_DENIED;
- }
-
- /* Check for Tcb privilege */
- if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
- UserMode))
- {
- DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
- return STATUS_PRIVILEGE_NOT_HELD;
- }
-
- /* Wait for a PnP event */
- DPRINT("Waiting for pnp notification event\n");
- Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
- UserRequest,
- UserMode,
- FALSE,
- NULL);
- if (!NT_SUCCESS(Status) || Status == STATUS_USER_APC)
- {
- DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status);
- ASSERT(Status == STATUS_USER_APC);
- return Status;
- }
-
- /* Get entry from the tail of the queue */
- Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink,
- PNP_EVENT_ENTRY,
- ListEntry);
-
- /* Check the buffer size */
- if (BufferSize < Entry->Event.TotalSize)
- {
- DPRINT1("Buffer is too small for the pnp-event\n");
- return STATUS_BUFFER_TOO_SMALL;
- }
-
- /* Copy event data to the user buffer */
- _SEH2_TRY
- {
- ProbeForWrite(Buffer,
- Entry->Event.TotalSize,
- sizeof(UCHAR));
- RtlCopyMemory(Buffer,
- &Entry->Event,
- Entry->Event.TotalSize);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- DPRINT("NtGetPlugPlayEvent() done\n");
-
- return STATUS_SUCCESS;
-}
-
-/*
- * NtPlugPlayControl
- *
- * A function for doing various Plug & Play operations from user mode.
- *
- * Parameters
- * PlugPlayControlClass
- * 0x00 Reenumerate device tree
- *
- * Buffer points to UNICODE_STRING decribing the instance
- * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
- * more information about instance paths see !devnode command
- * in kernel debugger or look at "Inside Windows 2000" book,
- * chapter "Driver Loading, Initialization, and Installation".
- *
- * 0x01 Register new device
- * 0x02 Deregister device
- * 0x03 Initialize device
- * 0x04 Start device
- * 0x06 Query and remove device
- * 0x07 User response
- *
- * Called after processing the message from NtGetPlugPlayEvent.
- *
- * 0x08 Generate legacy device
- * 0x09 Get interface device list
- * 0x0A Get property data
- * 0x0B Device class association (Registration)
- * 0x0C Get related device
- * 0x0D Get device interface alias
- * 0x0E Get/set/clear device status
- * 0x0F Get device depth
- * 0x10 Query device relations
- * 0x11 Query target device relation
- * 0x12 Query conflict list
- * 0x13 Retrieve dock data
- * 0x14 Reset device
- * 0x15 Halt device
- * 0x16 Get blocked driver data
- *
- * Buffer
- * The buffer contains information that is specific to each control
- * code. The buffer is read-only.
- *
- * BufferSize
- * Size of the buffer pointed by the Buffer parameter. If the
- * buffer size specifies incorrect value for specified control
- * code, error ??? is returned.
- *
- * Return Values
- * STATUS_PRIVILEGE_NOT_HELD
- * STATUS_SUCCESS
- * ...
- *
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
- IN OUT PVOID Buffer,
- IN ULONG BufferLength)
-{
- DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
- PlugPlayControlClass, Buffer, BufferLength);
-
- /* Function can only be called from user-mode */
- if (KeGetPreviousMode() == KernelMode)
- {
- DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
- return STATUS_ACCESS_DENIED;
- }
-
- /* Check for Tcb privilege */
- if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
- UserMode))
- {
- DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
- return STATUS_PRIVILEGE_NOT_HELD;
- }
-
- /* Probe the buffer */
- _SEH2_TRY
- {
- ProbeForWrite(Buffer,
- BufferLength,
- sizeof(ULONG));
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- switch (PlugPlayControlClass)
- {
-// case PlugPlayControlEnumerateDevice:
-// case PlugPlayControlRegisterNewDevice:
-// case PlugPlayControlDeregisterDevice:
-// case PlugPlayControlInitializeDevice:
-// case PlugPlayControlStartDevice:
-// case PlugPlayControlUnlockDevice:
-// case PlugPlayControlQueryAndRemoveDevice:
-
- case PlugPlayControlUserResponse:
- if (Buffer || BufferLength != 0)
- return STATUS_INVALID_PARAMETER;
- return IopRemovePlugPlayEvent();
-
-// case PlugPlayControlGenerateLegacyDevice:
-
- case PlugPlayControlGetInterfaceDeviceList:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA))
- return STATUS_INVALID_PARAMETER;
- return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)Buffer);
-
- case PlugPlayControlProperty:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA))
- return STATUS_INVALID_PARAMETER;
- return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer);
-
-// case PlugPlayControlDeviceClassAssociation:
-
- case PlugPlayControlGetRelatedDevice:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA))
- return STATUS_INVALID_PARAMETER;
- return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer);
-
-// case PlugPlayControlGetInterfaceDeviceAlias:
-
- case PlugPlayControlDeviceStatus:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA))
- return STATUS_INVALID_PARAMETER;
- return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA)Buffer);
-
- case PlugPlayControlGetDeviceDepth:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEPTH_DATA))
- return STATUS_INVALID_PARAMETER;
- return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer);
-
- case PlugPlayControlQueryDeviceRelations:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA))
- return STATUS_INVALID_PARAMETER;
- return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer);
-
-// case PlugPlayControlTargetDeviceRelation:
-// case PlugPlayControlQueryConflictList:
-// case PlugPlayControlRetrieveDock:
-
- case PlugPlayControlResetDevice:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA))
- return STATUS_INVALID_PARAMETER;
- return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer);
-
-// case PlugPlayControlHaltDevice:
-// case PlugPlayControlGetBlockedDriverList:
-
- default:
- return STATUS_NOT_IMPLEMENTED;
- }
-
- return STATUS_NOT_IMPLEMENTED;
-}