diff --git a/reactos/include/ntos/ntpnp.h b/reactos/include/ntos/ntpnp.h index 7e51fe7a3d9..426ff76d576 100644 --- a/reactos/include/ntos/ntpnp.h +++ b/reactos/include/ntos/ntpnp.h @@ -38,9 +38,10 @@ DEFINE_GUID(GUID_DEVICE_REMOVAL_VETOED, 0x60DBD5FA, 0xDDD2, 0x11D2, 0x97, 0xB8, DEFINE_GUID(GUID_DEVICE_HIBERNATE_VETOED, 0x61173AD9, 0x194F, 0x11D3, 0x97, 0xDC, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); DEFINE_GUID(GUID_DEVICE_BATTERY, 0x72631E54, 0x78A4, 0x11D0, 0xBC, 0xF7, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A); DEFINE_GUID(GUID_DEVICE_SAFE_REMOVAL, 0x8FBEF967, 0xD6C5, 0x11D2, 0x97, 0xB5, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); -/* These GUIDs are documented, and they are defined in wdmguid.h */ -/* DEFINE_GUID(GUID_DEVICE_INTERFACE_ARRIVAL, 0xCB3A4004, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); */ -/* DEFINE_GUID(GUID_DEVICE_INTERFACE_REMOVAL, 0xCB3A4005, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); */ +#ifndef __USE_W32API +DEFINE_GUID(GUID_DEVICE_INTERFACE_ARRIVAL, 0xCB3A4004, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_INTERFACE_REMOVAL, 0xCB3A4005, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +#endif DEFINE_GUID(GUID_DEVICE_ARRIVAL, 0xCB3A4009, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); DEFINE_GUID(GUID_DEVICE_ENUMERATED, 0xCB3A400A, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); DEFINE_GUID(GUID_DEVICE_ENUMERATE_REQUEST, 0xCB3A400B, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); @@ -220,7 +221,7 @@ NtGetPlugPlayEvent( * 0x0B Device class association (Registration) * 0x0C Get related device * 0x0D Get device interface alias - * 0x0E Get/set device status + * 0x0E Get/set/clear device status * 0x0F Get device depth * 0x10 Query device relations * 0x11 Query target device relation @@ -245,7 +246,52 @@ NtGetPlugPlayEvent( * ... */ -#define PLUGPLAY_USER_RESPONSE 0x07 +#define PLUGPLAY_USER_RESPONSE 0x07 +#define PLUGPLAY_GET_PROPERTY 0x0A +#define PLUGPLAY_GET_RELATED_DEVICE 0x0C +#define PLUGPLAY_DEVICE_STATUS 0x0E + + +typedef struct _PLUGPLAY_PROPERTY_DATA +{ + UNICODE_STRING DeviceInstance; + ULONG Property; + PVOID Buffer; + ULONG BufferSize; +} PLUGPLAY_PROPERTY_DATA, *PPLUGPLAY_PROPERTY_DATA; + + +/* PLUGPLAY_GET_RELATED_DEVICE (Code 0x0C) */ + +/* Relation values */ +#define PNP_GET_PARENT_DEVICE 1 +#define PNP_GET_CHILD_DEVICE 2 +#define PNP_GET_SIBLING_DEVICE 3 + +typedef struct _PLUGPLAY_RELATED_DEVICE_DATA +{ + UNICODE_STRING DeviceInstance; + UNICODE_STRING RelatedDeviceInstance; + ULONG Relation; /* 1: Parent 2: Child 3: Sibling */ +} PLUGPLAY_RELATED_DEVICE_DATA, *PPLUGPLAY_RELATED_DEVICE_DATA; + + +/* PLUGPLAY_DEVICE_STATUS (Code 0x0E) */ + +/* Action values */ +#define PNP_GET_DEVICE_STATUS 0 +#define PNP_SET_DEVICE_STATUS 1 +#define PNP_CLEAR_DEVICE_STATUS 2 + + +typedef struct _PLUGPLAY_DEVICE_STATUS_DATA +{ + UNICODE_STRING DeviceInstance; + ULONG Action; /* 0: Get 1: Set 2: Clear */ + ULONG Problem; /* CM_PROB_ see cfg.h */ + ULONG Flags; /* DN_ see cfg.h */ +} PLUGPLAY_DEVICE_STATUS_DATA, *PPLUGPLAY_DEVICE_STATUS_DATA; + NTSTATUS STDCALL NtPlugPlayControl( diff --git a/reactos/ntoskrnl/io/plugplay.c b/reactos/ntoskrnl/io/plugplay.c index 2f09eaca53e..603f043359c 100644 --- a/reactos/ntoskrnl/io/plugplay.c +++ b/reactos/ntoskrnl/io/plugplay.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/io/plugplay.c @@ -33,14 +32,13 @@ static KEVENT IopPnpNotifyEvent; NTSTATUS INIT_FUNCTION IopInitPlugPlayEvents(VOID) { + InitializeListHead(&IopPnpEventQueueHead); - InitializeListHead(&IopPnpEventQueueHead); + KeInitializeEvent(&IopPnpNotifyEvent, + SynchronizationEvent, + FALSE); - KeInitializeEvent(&IopPnpNotifyEvent, - SynchronizationEvent, - FALSE); - - return STATUS_SUCCESS; + return STATUS_SUCCESS; } @@ -48,35 +46,35 @@ NTSTATUS IopQueueTargetDeviceEvent(const GUID *Guid, PUNICODE_STRING DeviceIds) { - PPNP_EVENT_ENTRY EventEntry; - DWORD TotalSize; + PPNP_EVENT_ENTRY EventEntry; + DWORD TotalSize; - TotalSize = - FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) + - DeviceIds->MaximumLength; + TotalSize = + FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) + + DeviceIds->MaximumLength; - EventEntry = ExAllocatePool(NonPagedPool, - TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); - if (EventEntry == NULL) - return STATUS_INSUFFICIENT_RESOURCES; + EventEntry = ExAllocatePool(NonPagedPool, + TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event)); + if (EventEntry == NULL) + return STATUS_INSUFFICIENT_RESOURCES; - memcpy(&EventEntry->Event.EventGuid, - Guid, - sizeof(GUID)); - EventEntry->Event.EventCategory = TargetDeviceChangeEvent; - EventEntry->Event.TotalSize = TotalSize; + memcpy(&EventEntry->Event.EventGuid, + Guid, + sizeof(GUID)); + EventEntry->Event.EventCategory = TargetDeviceChangeEvent; + EventEntry->Event.TotalSize = TotalSize; - memcpy(&EventEntry->Event.TargetDevice.DeviceIds, - DeviceIds->Buffer, - DeviceIds->MaximumLength); + memcpy(&EventEntry->Event.TargetDevice.DeviceIds, + DeviceIds->Buffer, + DeviceIds->MaximumLength); - InsertHeadList(&IopPnpEventQueueHead, - &EventEntry->ListEntry); - KeSetEvent(&IopPnpNotifyEvent, - 0, - FALSE); + InsertHeadList(&IopPnpEventQueueHead, + &EventEntry->ListEntry); + KeSetEvent(&IopPnpNotifyEvent, + 0, + FALSE); - return STATUS_SUCCESS; + return STATUS_SUCCESS; } @@ -84,7 +82,7 @@ IopQueueTargetDeviceEvent(const GUID *Guid, * 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 VOID +static NTSTATUS IopRemovePlugPlayEvent(VOID) { /* Remove a pnp event entry from the tail of the queue */ @@ -100,6 +98,8 @@ IopRemovePlugPlayEvent(VOID) 0, FALSE); } + + return STATUS_SUCCESS; } @@ -168,6 +168,256 @@ NtGetPlugPlayEvent(IN ULONG Reserved1, } +static PDEVICE_OBJECT +IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName, ValueName; + LPWSTR KeyNameBuffer; + HANDLE InstanceKeyHandle; + HANDLE ControlKeyHandle; + NTSTATUS Status; + PKEY_VALUE_PARTIAL_INFORMATION ValueInformation; + ULONG ValueInformationLength; + PDEVICE_OBJECT DeviceObject = NULL; + + DPRINT("IopGetDeviceObjectFromDeviceInstance(%wZ) called\n", DeviceInstance); + + KeyNameBuffer = ExAllocatePool(PagedPool, + (49 * sizeof(WCHAR)) + DeviceInstance->Length); + if (KeyNameBuffer == NULL) + { + DPRINT1("Failed to allocate key name buffer!\n"); + return NULL; + } + + wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\"); + wcscat(KeyNameBuffer, DeviceInstance->Buffer); + + RtlInitUnicodeString(&KeyName, + KeyNameBuffer); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = ZwOpenKey(&InstanceKeyHandle, + KEY_READ, + &ObjectAttributes); + ExFreePool(KeyNameBuffer); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to open the instance key (Status %lx)\n", Status); + return NULL; + } + + /* Open the 'Control' subkey */ + RtlInitUnicodeString(&KeyName, + L"Control"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + InstanceKeyHandle, + NULL); + + Status = ZwOpenKey(&ControlKeyHandle, + KEY_READ, + &ObjectAttributes); + ZwClose(InstanceKeyHandle); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to open the 'Control' key (Status %lx)\n", Status); + return NULL; + } + + /* Query the 'DeviceReference' value */ + RtlInitUnicodeString(&ValueName, + L"DeviceReference"); + ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, + Data[0]) + sizeof(ULONG); + ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength); + if (ValueInformation == NULL) + { + DPRINT1("Failed to allocate the name information buffer!\n"); + ZwClose(ControlKeyHandle); + return NULL; + } + + Status = ZwQueryValueKey(ControlKeyHandle, + &ValueName, + KeyValuePartialInformation, + ValueInformation, + ValueInformationLength, + &ValueInformationLength); + ZwClose(ControlKeyHandle); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to open the 'Control' key (Status %lx)\n", Status); + return NULL; + } + + /* Check the device object */ + RtlCopyMemory(&DeviceObject, + ValueInformation->Data, + sizeof(PDEVICE_OBJECT)); + + DPRINT("DeviceObject: %p\n", DeviceObject); + + if (DeviceObject->Type != IO_TYPE_DEVICE || + DeviceObject->DeviceObjectExtension == NULL || + DeviceObject->DeviceObjectExtension->DeviceNode == NULL || + !RtlEqualUnicodeString(&DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath, + DeviceInstance, TRUE)) + { + DPRINT1("Invalid object type!\n"); + return NULL; + } + + DPRINT("Instance path: %wZ\n", &DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath); + + ObReferenceObject(DeviceObject); + + DPRINT("IopGetDeviceObjectFromDeviceInstance() done\n"); + + return DeviceObject; +} + + +static NTSTATUS +IopGetRelatedDevice(PPLUGPLAY_RELATED_DEVICE_DATA RelatedDeviceData) +{ + UNICODE_STRING RootDeviceName; + PDEVICE_OBJECT DeviceObject = NULL; + PDEVICE_NODE DeviceNode = NULL; + PDEVICE_NODE RelatedDeviceNode; + + DPRINT("IopGetRelatedDevice() called\n"); + + DPRINT("Device name: %wZ\n", &RelatedDeviceData->DeviceInstance); + + RtlInitUnicodeString(&RootDeviceName, + L"HTREE\\ROOT\\0"); + if (RtlEqualUnicodeString(&RelatedDeviceData->DeviceInstance, + &RootDeviceName, + TRUE)) + { + DeviceNode = IopRootDeviceNode; + } + else + { + /* Get the device object */ + DeviceObject = IopGetDeviceObjectFromDeviceInstance(&RelatedDeviceData->DeviceInstance); + if (DeviceObject == NULL) + return STATUS_NO_SUCH_DEVICE; + + DeviceNode = DeviceObject->DeviceObjectExtension->DeviceNode; + } + + switch (RelatedDeviceData->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->NextSibling; + 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 > + RelatedDeviceData->RelatedDeviceInstance.MaximumLength) + { + if (DeviceObject) + { + ObDereferenceObject(DeviceObject); + } + + return STATUS_BUFFER_TOO_SMALL; + } + + /* Copy related device instance name */ + RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance.Buffer, + RelatedDeviceNode->InstancePath.Buffer, + RelatedDeviceNode->InstancePath.Length); + RelatedDeviceData->RelatedDeviceInstance.Length = + RelatedDeviceNode->InstancePath.Length; + + if (DeviceObject != NULL) + { + ObDereferenceObject(DeviceObject); + } + + DPRINT("IopGetRelatedDevice() done\n"); + + return STATUS_SUCCESS; +} + + +static NTSTATUS +IopDeviceStatus(PPLUGPLAY_DEVICE_STATUS_DATA DeviceStatusData) +{ + PDEVICE_OBJECT DeviceObject; + PDEVICE_NODE DeviceNode; + + DPRINT("IopDeviceStatus() called\n"); + + DPRINT("Device name: %wZ\n", &DeviceStatusData->DeviceInstance); + + /* Get the device object */ + DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceStatusData->DeviceInstance); + if (DeviceObject == NULL) + return STATUS_NO_SUCH_DEVICE; + + DeviceNode = DeviceObject->DeviceObjectExtension->DeviceNode; + + switch (DeviceStatusData->Action) + { + case PNP_GET_DEVICE_STATUS: + DPRINT("Get status data\n"); + DeviceStatusData->Problem = DeviceNode->Problem; + DeviceStatusData->Flags = DeviceNode->Flags; + break; + + case PNP_SET_DEVICE_STATUS: + DPRINT("Set status data\n"); + DeviceNode->Problem = DeviceStatusData->Problem; + DeviceNode->Flags = DeviceStatusData->Flags; + break; + + case PNP_CLEAR_DEVICE_STATUS: + DPRINT1("FIXME: Clear status data!\n"); + break; + } + + ObDereferenceObject(DeviceObject); + + return STATUS_SUCCESS; +} + + /* * @unimplemented */ @@ -176,17 +426,63 @@ NtPlugPlayControl(IN ULONG ControlCode, IN OUT PVOID Buffer, IN ULONG BufferLength) { - DPRINT("NtPlugPlayControl(%lu %p %lu) called\n", - ControlCode, Buffer, BufferLength); + NTSTATUS Status = STATUS_SUCCESS; - switch (ControlCode) - { - case PLUGPLAY_USER_RESPONSE: - IopRemovePlugPlayEvent(); - return STATUS_SUCCESS; - } + DPRINT("NtPlugPlayControl(%lu %p %lu) called\n", + ControlCode, Buffer, BufferLength); - return STATUS_NOT_IMPLEMENTED; + /* Function can only be called from user-mode */ + if (KeGetPreviousMode() != UserMode) + { + 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 */ + _SEH_TRY + { + ProbeForWrite(Buffer, + BufferLength, + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + switch (ControlCode) + { + case PLUGPLAY_USER_RESPONSE: + if (Buffer || BufferLength != 0) + return STATUS_INVALID_PARAMETER; + return IopRemovePlugPlayEvent(); + + case PLUGPLAY_GET_RELATED_DEVICE: + if (!Buffer || BufferLength < sizeof(PLUGPLAY_RELATED_DEVICE_DATA)) + return STATUS_INVALID_PARAMETER; + return IopGetRelatedDevice((PPLUGPLAY_RELATED_DEVICE_DATA)Buffer); + + case PLUGPLAY_DEVICE_STATUS: + if (!Buffer || BufferLength < sizeof(PLUGPLAY_DEVICE_STATUS_DATA)) + return STATUS_INVALID_PARAMETER; + return IopDeviceStatus((PPLUGPLAY_DEVICE_STATUS_DATA)Buffer); + } + + return STATUS_NOT_IMPLEMENTED; } /* EOF */