mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
NtPlugPlayControl: Implement PLUGPLAY_GET_RELATED_DEVICE and PLUGPLAY_DEVICE_STATUS.
svn path=/trunk/; revision=15822
This commit is contained in:
parent
700e2c8098
commit
a344dd8f15
2 changed files with 388 additions and 46 deletions
|
@ -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(
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue