NtPlugPlayControl: Implement PLUGPLAY_GET_RELATED_DEVICE and
PLUGPLAY_DEVICE_STATUS.
Modified: trunk/reactos/include/ntos/ntpnp.h
Modified: trunk/reactos/ntoskrnl/io/plugplay.c
_____
Modified: trunk/reactos/include/ntos/ntpnp.h
--- trunk/reactos/include/ntos/ntpnp.h 2005-06-06 20:27:49 UTC (rev
15821)
+++ trunk/reactos/include/ntos/ntpnp.h 2005-06-06 20:31:56 UTC (rev
15822)
@@ -38,9 +38,10 @@
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 @@
* 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,8 +246,53 @@
* ...
*/
-#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(
ULONG ControlCode,
_____
Modified: trunk/reactos/ntoskrnl/io/plugplay.c
--- trunk/reactos/ntoskrnl/io/plugplay.c 2005-06-06 20:27:49 UTC
(rev 15821)
+++ trunk/reactos/ntoskrnl/io/plugplay.c 2005-06-06 20:31:56 UTC
(rev 15822)
@@ -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 @@
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 @@
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 @@
* 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 @@
0,
FALSE);
}
+
+ return STATUS_SUCCESS;
}
@@ -168,6 +168,256 @@
}
+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 @@
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 */