- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / io / plugplay.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/plugplay.c
5 * PURPOSE: Plug-and-play interface routines
6 *
7 * PROGRAMMERS: Eric Kohl <eric.kohl@t-online.de>
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, IopInitPlugPlayEvents)
19 #endif
20
21 typedef struct _PNP_EVENT_ENTRY
22 {
23 LIST_ENTRY ListEntry;
24 PLUGPLAY_EVENT_BLOCK Event;
25 } PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY;
26
27
28 /* GLOBALS *******************************************************************/
29
30 static LIST_ENTRY IopPnpEventQueueHead;
31 static KEVENT IopPnpNotifyEvent;
32
33 /* FUNCTIONS *****************************************************************/
34
35 NTSTATUS INIT_FUNCTION
36 IopInitPlugPlayEvents(VOID)
37 {
38 InitializeListHead(&IopPnpEventQueueHead);
39
40 KeInitializeEvent(&IopPnpNotifyEvent,
41 SynchronizationEvent,
42 FALSE);
43
44 return STATUS_SUCCESS;
45 }
46
47
48 NTSTATUS
49 IopQueueTargetDeviceEvent(const GUID *Guid,
50 PUNICODE_STRING DeviceIds)
51 {
52 PPNP_EVENT_ENTRY EventEntry;
53 DWORD TotalSize;
54
55 TotalSize =
56 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) +
57 DeviceIds->MaximumLength;
58
59 EventEntry = ExAllocatePool(NonPagedPool,
60 TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
61 if (EventEntry == NULL)
62 return STATUS_INSUFFICIENT_RESOURCES;
63
64 memcpy(&EventEntry->Event.EventGuid,
65 Guid,
66 sizeof(GUID));
67 EventEntry->Event.EventCategory = TargetDeviceChangeEvent;
68 EventEntry->Event.TotalSize = TotalSize;
69
70 memcpy(&EventEntry->Event.TargetDevice.DeviceIds,
71 DeviceIds->Buffer,
72 DeviceIds->MaximumLength);
73
74 InsertHeadList(&IopPnpEventQueueHead,
75 &EventEntry->ListEntry);
76 KeSetEvent(&IopPnpNotifyEvent,
77 0,
78 FALSE);
79
80 return STATUS_SUCCESS;
81 }
82
83
84 /*
85 * Remove the current PnP event from the tail of the event queue
86 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
87 */
88 static NTSTATUS
89 IopRemovePlugPlayEvent(VOID)
90 {
91 /* Remove a pnp event entry from the tail of the queue */
92 if (!IsListEmpty(&IopPnpEventQueueHead))
93 {
94 ExFreePool(RemoveTailList(&IopPnpEventQueueHead));
95 }
96
97 /* Signal the next pnp event in the queue */
98 if (!IsListEmpty(&IopPnpEventQueueHead))
99 {
100 KeSetEvent(&IopPnpNotifyEvent,
101 0,
102 FALSE);
103 }
104
105 return STATUS_SUCCESS;
106 }
107
108
109 /*
110 * Plug and Play event structure used by NtGetPlugPlayEvent.
111 *
112 * EventGuid
113 * Can be one of the following values:
114 * GUID_HWPROFILE_QUERY_CHANGE
115 * GUID_HWPROFILE_CHANGE_CANCELLED
116 * GUID_HWPROFILE_CHANGE_COMPLETE
117 * GUID_TARGET_DEVICE_QUERY_REMOVE
118 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
119 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
120 * GUID_PNP_CUSTOM_NOTIFICATION
121 * GUID_PNP_POWER_NOTIFICATION
122 * GUID_DEVICE_* (see above)
123 *
124 * EventCategory
125 * Type of the event that happened.
126 *
127 * Result
128 * ?
129 *
130 * Flags
131 * ?
132 *
133 * TotalSize
134 * Size of the event block including the device IDs and other
135 * per category specific fields.
136 */
137 /*
138 * NtGetPlugPlayEvent
139 *
140 * Returns one Plug & Play event from a global queue.
141 *
142 * Parameters
143 * Reserved1
144 * Reserved2
145 * Always set to zero.
146 *
147 * Buffer
148 * The buffer that will be filled with the event information on
149 * successful return from the function.
150 *
151 * BufferSize
152 * Size of the buffer pointed by the Buffer parameter. If the
153 * buffer size is not large enough to hold the whole event
154 * information, error STATUS_BUFFER_TOO_SMALL is returned and
155 * the buffer remains untouched.
156 *
157 * Return Values
158 * STATUS_PRIVILEGE_NOT_HELD
159 * STATUS_BUFFER_TOO_SMALL
160 * STATUS_SUCCESS
161 *
162 * Remarks
163 * This function isn't multi-thread safe!
164 *
165 * @implemented
166 */
167 NTSTATUS STDCALL
168 NtGetPlugPlayEvent(IN ULONG Reserved1,
169 IN ULONG Reserved2,
170 OUT PPLUGPLAY_EVENT_BLOCK Buffer,
171 IN ULONG BufferSize)
172 {
173 PPNP_EVENT_ENTRY Entry;
174 NTSTATUS Status;
175
176 DPRINT("NtGetPlugPlayEvent() called\n");
177
178 /* Function can only be called from user-mode */
179 if (KeGetPreviousMode() == KernelMode)
180 {
181 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
182 return STATUS_ACCESS_DENIED;
183 }
184
185 /* Check for Tcb privilege */
186 if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
187 UserMode))
188 {
189 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
190 return STATUS_PRIVILEGE_NOT_HELD;
191 }
192
193 /* Wait for a PnP event */
194 DPRINT("Waiting for pnp notification event\n");
195 Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
196 UserRequest,
197 KernelMode,
198 FALSE,
199 NULL);
200 if (!NT_SUCCESS(Status))
201 {
202 DPRINT1("KeWaitForSingleObject() failed (Status %lx)\n", Status);
203 return Status;
204 }
205
206 /* Get entry from the tail of the queue */
207 Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink,
208 PNP_EVENT_ENTRY,
209 ListEntry);
210
211 /* Check the buffer size */
212 if (BufferSize < Entry->Event.TotalSize)
213 {
214 DPRINT1("Buffer is too small for the pnp-event\n");
215 return STATUS_BUFFER_TOO_SMALL;
216 }
217
218 /* Copy event data to the user buffer */
219 memcpy(Buffer,
220 &Entry->Event,
221 Entry->Event.TotalSize);
222
223 DPRINT("NtGetPlugPlayEvent() done\n");
224
225 return STATUS_SUCCESS;
226 }
227
228
229 static PDEVICE_OBJECT
230 IopTraverseDeviceNode(PDEVICE_NODE Node, PUNICODE_STRING DeviceInstance)
231 {
232 PDEVICE_OBJECT DeviceObject;
233 PDEVICE_NODE ChildNode;
234
235 if (RtlEqualUnicodeString(&Node->InstancePath,
236 DeviceInstance, TRUE))
237 {
238 ObReferenceObject(Node->PhysicalDeviceObject);
239 return Node->PhysicalDeviceObject;
240 }
241
242 /* Traversal of all children nodes */
243 for (ChildNode = Node->Child;
244 ChildNode != NULL;
245 ChildNode = ChildNode->NextSibling)
246 {
247 DeviceObject = IopTraverseDeviceNode(ChildNode, DeviceInstance);
248 if (DeviceObject != NULL)
249 {
250 return DeviceObject;
251 }
252 }
253
254 return NULL;
255 }
256
257
258 static PDEVICE_OBJECT
259 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
260 {
261 #if 0
262 OBJECT_ATTRIBUTES ObjectAttributes;
263 UNICODE_STRING KeyName, ValueName;
264 LPWSTR KeyNameBuffer;
265 HANDLE InstanceKeyHandle;
266 HANDLE ControlKeyHandle;
267 NTSTATUS Status;
268 PKEY_VALUE_PARTIAL_INFORMATION ValueInformation;
269 ULONG ValueInformationLength;
270 PDEVICE_OBJECT DeviceObject = NULL;
271
272 DPRINT("IopGetDeviceObjectFromDeviceInstance(%wZ) called\n", DeviceInstance);
273
274 KeyNameBuffer = ExAllocatePool(PagedPool,
275 (49 * sizeof(WCHAR)) + DeviceInstance->Length);
276 if (KeyNameBuffer == NULL)
277 {
278 DPRINT1("Failed to allocate key name buffer!\n");
279 return NULL;
280 }
281
282 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
283 wcscat(KeyNameBuffer, DeviceInstance->Buffer);
284
285 RtlInitUnicodeString(&KeyName,
286 KeyNameBuffer);
287 InitializeObjectAttributes(&ObjectAttributes,
288 &KeyName,
289 OBJ_CASE_INSENSITIVE,
290 NULL,
291 NULL);
292
293 Status = ZwOpenKey(&InstanceKeyHandle,
294 KEY_READ,
295 &ObjectAttributes);
296 ExFreePool(KeyNameBuffer);
297 if (!NT_SUCCESS(Status))
298 {
299 DPRINT1("Failed to open the instance key (Status %lx)\n", Status);
300 return NULL;
301 }
302
303 /* Open the 'Control' subkey */
304 RtlInitUnicodeString(&KeyName,
305 L"Control");
306 InitializeObjectAttributes(&ObjectAttributes,
307 &KeyName,
308 OBJ_CASE_INSENSITIVE,
309 InstanceKeyHandle,
310 NULL);
311
312 Status = ZwOpenKey(&ControlKeyHandle,
313 KEY_READ,
314 &ObjectAttributes);
315 ZwClose(InstanceKeyHandle);
316 if (!NT_SUCCESS(Status))
317 {
318 DPRINT1("Failed to open the 'Control' key (Status %lx)\n", Status);
319 return NULL;
320 }
321
322 /* Query the 'DeviceReference' value */
323 RtlInitUnicodeString(&ValueName,
324 L"DeviceReference");
325 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
326 Data[0]) + sizeof(ULONG);
327 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
328 if (ValueInformation == NULL)
329 {
330 DPRINT1("Failed to allocate the name information buffer!\n");
331 ZwClose(ControlKeyHandle);
332 return NULL;
333 }
334
335 Status = ZwQueryValueKey(ControlKeyHandle,
336 &ValueName,
337 KeyValuePartialInformation,
338 ValueInformation,
339 ValueInformationLength,
340 &ValueInformationLength);
341 ZwClose(ControlKeyHandle);
342 if (!NT_SUCCESS(Status))
343 {
344 DPRINT1("Failed to query the 'DeviceReference' value (Status %lx)\n", Status);
345 return NULL;
346 }
347
348 /* Check the device object */
349 RtlCopyMemory(&DeviceObject,
350 ValueInformation->Data,
351 sizeof(PDEVICE_OBJECT));
352
353 DPRINT("DeviceObject: %p\n", DeviceObject);
354
355 if (DeviceObject->Type != IO_TYPE_DEVICE ||
356 DeviceObject->DeviceObjectExtension == NULL ||
357 DeviceObject->DeviceObjectExtension->DeviceNode == NULL ||
358 !RtlEqualUnicodeString(&DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath,
359 DeviceInstance, TRUE))
360 {
361 DPRINT1("Invalid object type!\n");
362 return NULL;
363 }
364
365 DPRINT("Instance path: %wZ\n", &DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath);
366
367 ObReferenceObject(DeviceObject);
368
369 DPRINT("IopGetDeviceObjectFromDeviceInstance() done\n");
370
371 return DeviceObject;
372 #endif
373
374 if (IopRootDeviceNode == NULL)
375 return NULL;
376
377 if (DeviceInstance == NULL ||
378 DeviceInstance->Length == 0
379 )
380 {
381 if (IopRootDeviceNode->PhysicalDeviceObject)
382 {
383 ObReferenceObject(IopRootDeviceNode->PhysicalDeviceObject);
384 return IopRootDeviceNode->PhysicalDeviceObject;
385 }
386 else
387 return NULL;
388 }
389
390 return IopTraverseDeviceNode(IopRootDeviceNode, DeviceInstance);
391
392 }
393
394 static NTSTATUS
395 IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
396 {
397 NTSTATUS Status = STATUS_SUCCESS;
398 UNICODE_STRING Name;
399
400 Name.Buffer = NULL;
401 _SEH_TRY
402 {
403 Name.Length = SrcName->Length;
404 Name.MaximumLength = SrcName->MaximumLength;
405 if (Name.Length > Name.MaximumLength)
406 {
407 Status = STATUS_INVALID_PARAMETER;
408 _SEH_LEAVE;
409 }
410 if (Name.MaximumLength)
411 {
412 ProbeForRead(SrcName->Buffer,
413 Name.MaximumLength,
414 sizeof(WCHAR));
415 Name.Buffer = ExAllocatePool(NonPagedPool, Name.MaximumLength);
416 if (Name.Buffer == NULL)
417 {
418 Status = STATUS_INSUFFICIENT_RESOURCES;
419 _SEH_LEAVE;
420 }
421 memcpy(Name.Buffer, SrcName->Buffer, Name.MaximumLength);
422 }
423 *DstName = Name;
424 }
425 _SEH_HANDLE
426 {
427 Status = _SEH_GetExceptionCode();
428 }
429 _SEH_END;
430
431 if (!NT_SUCCESS(Status) && Name.Buffer)
432 {
433 ExFreePool(Name.Buffer);
434 }
435 return Status;
436 }
437
438 static NTSTATUS
439 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
440 {
441 PDEVICE_OBJECT DeviceObject = NULL;
442 NTSTATUS Status = STATUS_SUCCESS;
443 UNICODE_STRING DeviceInstance;
444 ULONG BufferSize;
445 ULONG Property = 0;
446 PVOID Buffer;
447
448 DPRINT("IopGetDeviceProperty() called\n");
449 DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance);
450
451 Status = IopCaptureUnicodeString(&DeviceInstance, &PropertyData->DeviceInstance);
452 if (!NT_SUCCESS(Status))
453 {
454 return Status;
455 }
456
457 _SEH_TRY
458 {
459 Property = PropertyData->Property;
460 BufferSize = PropertyData->BufferSize;
461 ProbeForWrite(PropertyData->Buffer,
462 BufferSize,
463 sizeof(UCHAR));
464 }
465 _SEH_HANDLE
466 {
467 Status = _SEH_GetExceptionCode();
468 }
469 _SEH_END;
470
471 if (!NT_SUCCESS(Status))
472 {
473 ExFreePool(DeviceInstance.Buffer);
474 return Status;
475 }
476
477 /* Get the device object */
478 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&PropertyData->DeviceInstance);
479 ExFreePool(DeviceInstance.Buffer);
480 if (DeviceObject == NULL)
481 {
482 return STATUS_NO_SUCH_DEVICE;
483 }
484
485 Buffer = ExAllocatePool(NonPagedPool, BufferSize);
486 if (Buffer == NULL)
487 {
488 return STATUS_INSUFFICIENT_RESOURCES;
489 }
490
491
492 Status = IoGetDeviceProperty(DeviceObject,
493 Property,
494 BufferSize,
495 Buffer,
496 &BufferSize);
497
498 ObDereferenceObject(DeviceObject);
499
500 if (NT_SUCCESS(Status))
501 {
502 _SEH_TRY
503 {
504 memcpy(Buffer, PropertyData->Buffer, BufferSize);
505 PropertyData->BufferSize = BufferSize;
506 }
507 _SEH_HANDLE
508 {
509 Status = _SEH_GetExceptionCode();
510 }
511 _SEH_END;
512 }
513 ExFreePool(Buffer);
514 return Status;
515 }
516
517
518 static NTSTATUS
519 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData)
520 {
521 UNICODE_STRING RootDeviceName;
522 PDEVICE_OBJECT DeviceObject = NULL;
523 PDEVICE_NODE DeviceNode = NULL;
524 PDEVICE_NODE RelatedDeviceNode;
525 UNICODE_STRING TargetDeviceInstance;
526 NTSTATUS Status = STATUS_SUCCESS;
527 ULONG Relation = 0;
528 ULONG MaximumLength = 0;
529
530 DPRINT("IopGetRelatedDevice() called\n");
531 DPRINT("Device name: %wZ\n", &RelatedDeviceData->TargetDeviceInstance);
532
533 Status = IopCaptureUnicodeString(&TargetDeviceInstance, &RelatedDeviceData->TargetDeviceInstance);
534 if (!NT_SUCCESS(Status))
535 {
536 return Status;
537 }
538
539 _SEH_TRY
540 {
541 Relation = RelatedDeviceData->Relation;
542 MaximumLength = RelatedDeviceData->RelatedDeviceInstanceLength;
543 ProbeForWrite(RelatedDeviceData->RelatedDeviceInstance,
544 MaximumLength,
545 sizeof(WCHAR));
546 }
547 _SEH_HANDLE
548 {
549 Status = _SEH_GetExceptionCode();
550 }
551 _SEH_END;
552
553 if (!NT_SUCCESS(Status))
554 {
555 ExFreePool(TargetDeviceInstance.Buffer);
556 return Status;
557 }
558
559 RtlInitUnicodeString(&RootDeviceName,
560 L"HTREE\\ROOT\\0");
561 if (RtlEqualUnicodeString(&TargetDeviceInstance,
562 &RootDeviceName,
563 TRUE))
564 {
565 DeviceNode = IopRootDeviceNode;
566 ExFreePool(TargetDeviceInstance.Buffer);
567 }
568 else
569 {
570 /* Get the device object */
571 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance);
572 ExFreePool(TargetDeviceInstance.Buffer);
573 if (DeviceObject == NULL)
574 return STATUS_NO_SUCH_DEVICE;
575
576 DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
577 }
578
579 switch (Relation)
580 {
581 case PNP_GET_PARENT_DEVICE:
582 RelatedDeviceNode = DeviceNode->Parent;
583 break;
584
585 case PNP_GET_CHILD_DEVICE:
586 RelatedDeviceNode = DeviceNode->Child;
587 break;
588
589 case PNP_GET_SIBLING_DEVICE:
590 RelatedDeviceNode = DeviceNode->NextSibling;
591 break;
592
593 default:
594 if (DeviceObject != NULL)
595 {
596 ObDereferenceObject(DeviceObject);
597 }
598
599 return STATUS_INVALID_PARAMETER;
600 }
601
602 if (RelatedDeviceNode == NULL)
603 {
604 if (DeviceObject)
605 {
606 ObDereferenceObject(DeviceObject);
607 }
608
609 return STATUS_NO_SUCH_DEVICE;
610 }
611
612 if (RelatedDeviceNode->InstancePath.Length > MaximumLength)
613 {
614 if (DeviceObject)
615 {
616 ObDereferenceObject(DeviceObject);
617 }
618
619 return STATUS_BUFFER_TOO_SMALL;
620 }
621
622 /* Copy related device instance name */
623 _SEH_TRY
624 {
625 RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance,
626 RelatedDeviceNode->InstancePath.Buffer,
627 RelatedDeviceNode->InstancePath.Length);
628 RelatedDeviceData->RelatedDeviceInstanceLength = RelatedDeviceNode->InstancePath.Length;
629 }
630 _SEH_HANDLE
631 {
632 Status = _SEH_GetExceptionCode();
633 }
634 _SEH_END;
635
636 if (DeviceObject != NULL)
637 {
638 ObDereferenceObject(DeviceObject);
639 }
640
641 DPRINT("IopGetRelatedDevice() done\n");
642
643 return Status;
644 }
645
646
647 static NTSTATUS
648 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
649 {
650 PDEVICE_OBJECT DeviceObject;
651 PDEVICE_NODE DeviceNode;
652 ULONG Operation = 0;
653 ULONG DeviceStatus = 0;
654 ULONG DeviceProblem = 0;
655 UNICODE_STRING DeviceInstance;
656 NTSTATUS Status = STATUS_SUCCESS;
657
658 DPRINT("IopDeviceStatus() called\n");
659 DPRINT("Device name: %wZ\n", &StatusData->DeviceInstance);
660
661 Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance);
662 if (!NT_SUCCESS(Status))
663 {
664 return Status;
665 }
666
667 _SEH_TRY
668 {
669 Operation = StatusData->Operation;
670 if (Operation == PNP_SET_DEVICE_STATUS)
671 {
672 DeviceStatus = StatusData->DeviceStatus;
673 DeviceProblem = StatusData->DeviceProblem;
674 }
675 }
676 _SEH_HANDLE
677 {
678 Status = _SEH_GetExceptionCode();
679 }
680 _SEH_END;
681
682 if (!NT_SUCCESS(Status))
683 {
684 if (DeviceInstance.Buffer)
685 {
686 ExFreePool(DeviceInstance.Buffer);
687 }
688 return Status;
689 }
690
691 /* Get the device object */
692 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&StatusData->DeviceInstance);
693 ExFreePool(DeviceInstance.Buffer);
694 if (DeviceObject == NULL)
695 return STATUS_NO_SUCH_DEVICE;
696
697 DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
698
699 switch (Operation)
700 {
701 case PNP_GET_DEVICE_STATUS:
702 DPRINT("Get status data\n");
703 DeviceStatus = DeviceNode->Flags;
704 DeviceProblem = DeviceNode->Problem;
705 break;
706
707 case PNP_SET_DEVICE_STATUS:
708 DPRINT("Set status data\n");
709 DeviceNode->Flags = DeviceStatus;
710 DeviceNode->Problem = DeviceProblem;
711 break;
712
713 case PNP_CLEAR_DEVICE_STATUS:
714 DPRINT1("FIXME: Clear status data!\n");
715 break;
716 }
717
718 ObDereferenceObject(DeviceObject);
719
720 if (Operation == PNP_GET_DEVICE_STATUS)
721 {
722 _SEH_TRY
723 {
724 StatusData->DeviceStatus = DeviceStatus;
725 StatusData->DeviceProblem = DeviceProblem;
726 }
727 _SEH_HANDLE
728 {
729 Status = _SEH_GetExceptionCode();
730 }
731 _SEH_END;
732 }
733
734 return Status;
735 }
736
737
738 static NTSTATUS
739 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData)
740 {
741 PDEVICE_OBJECT DeviceObject;
742 PDEVICE_NODE DeviceNode;
743 UNICODE_STRING DeviceInstance;
744 NTSTATUS Status = STATUS_SUCCESS;
745
746 DPRINT("IopGetDeviceDepth() called\n");
747 DPRINT("Device name: %wZ\n", &DepthData->DeviceInstance);
748
749 Status = IopCaptureUnicodeString(&DeviceInstance, &DepthData->DeviceInstance);
750 if (!NT_SUCCESS(Status))
751 {
752 return Status;
753 }
754
755 /* Get the device object */
756 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DepthData->DeviceInstance);
757 ExFreePool(DeviceInstance.Buffer);
758 if (DeviceObject == NULL)
759 return STATUS_NO_SUCH_DEVICE;
760
761 DeviceNode = IopGetDeviceNode(DeviceObject);
762
763 DepthData->Depth = DeviceNode->Level;
764
765 ObDereferenceObject(DeviceObject);
766
767 _SEH_TRY
768 {
769 DepthData->Depth = DeviceNode->Level;
770 }
771 _SEH_HANDLE
772 {
773 Status = _SEH_GetExceptionCode();
774 }
775 _SEH_END;
776
777 return Status;
778 }
779
780
781 static NTSTATUS
782 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData)
783 {
784 PDEVICE_OBJECT DeviceObject;
785 PDEVICE_NODE DeviceNode;
786 NTSTATUS Status = STATUS_SUCCESS;
787 UNICODE_STRING DeviceInstance;
788
789 DPRINT("IopResetDevice() called\n");
790 DPRINT("Device name: %wZ\n", &ResetDeviceData->DeviceInstance);
791
792 Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance);
793 if (!NT_SUCCESS(Status))
794 {
795 return Status;
796 }
797
798 /* Get the device object */
799 DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
800 ExFreePool(DeviceInstance.Buffer);
801 if (DeviceObject == NULL)
802 return STATUS_NO_SUCH_DEVICE;
803
804 DeviceNode = IopGetDeviceNode(DeviceObject);
805
806 /* FIXME: we should stop the device, before starting it again */
807
808 /* Start the device */
809 IopDeviceNodeClearFlag(DeviceNode, DNF_DISABLED);
810 Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
811
812 if (NT_SUCCESS(Status))
813 Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent, FALSE);
814
815 ObDereferenceObject(DeviceObject);
816
817 return Status;
818 }
819
820
821 /*
822 * NtPlugPlayControl
823 *
824 * A function for doing various Plug & Play operations from user mode.
825 *
826 * Parameters
827 * PlugPlayControlClass
828 * 0x00 Reenumerate device tree
829 *
830 * Buffer points to UNICODE_STRING decribing the instance
831 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
832 * more information about instance paths see !devnode command
833 * in kernel debugger or look at "Inside Windows 2000" book,
834 * chapter "Driver Loading, Initialization, and Installation".
835 *
836 * 0x01 Register new device
837 * 0x02 Deregister device
838 * 0x03 Initialize device
839 * 0x04 Start device
840 * 0x06 Query and remove device
841 * 0x07 User response
842 *
843 * Called after processing the message from NtGetPlugPlayEvent.
844 *
845 * 0x08 Generate legacy device
846 * 0x09 Get interface device list
847 * 0x0A Get property data
848 * 0x0B Device class association (Registration)
849 * 0x0C Get related device
850 * 0x0D Get device interface alias
851 * 0x0E Get/set/clear device status
852 * 0x0F Get device depth
853 * 0x10 Query device relations
854 * 0x11 Query target device relation
855 * 0x12 Query conflict list
856 * 0x13 Retrieve dock data
857 * 0x14 Reset device
858 * 0x15 Halt device
859 * 0x16 Get blocked driver data
860 *
861 * Buffer
862 * The buffer contains information that is specific to each control
863 * code. The buffer is read-only.
864 *
865 * BufferSize
866 * Size of the buffer pointed by the Buffer parameter. If the
867 * buffer size specifies incorrect value for specified control
868 * code, error ??? is returned.
869 *
870 * Return Values
871 * STATUS_PRIVILEGE_NOT_HELD
872 * STATUS_SUCCESS
873 * ...
874 *
875 * @unimplemented
876 */
877 NTSTATUS STDCALL
878 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
879 IN OUT PVOID Buffer,
880 IN ULONG BufferLength)
881 {
882 NTSTATUS Status = STATUS_SUCCESS;
883
884 DPRINT("NtPlugPlayControl(%lu %p %lu) called\n",
885 PlugPlayControlClass, Buffer, BufferLength);
886
887 /* Function can only be called from user-mode */
888 if (KeGetPreviousMode() == KernelMode)
889 {
890 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
891 return STATUS_ACCESS_DENIED;
892 }
893
894 /* Check for Tcb privilege */
895 if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
896 UserMode))
897 {
898 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
899 return STATUS_PRIVILEGE_NOT_HELD;
900 }
901
902 /* Probe the buffer */
903 _SEH_TRY
904 {
905 ProbeForWrite(Buffer,
906 BufferLength,
907 sizeof(ULONG));
908 }
909 _SEH_HANDLE
910 {
911 Status = _SEH_GetExceptionCode();
912 }
913 _SEH_END;
914
915 if (!NT_SUCCESS(Status))
916 {
917 return Status;
918 }
919
920 switch (PlugPlayControlClass)
921 {
922 case PlugPlayControlUserResponse:
923 if (Buffer || BufferLength != 0)
924 return STATUS_INVALID_PARAMETER;
925 return IopRemovePlugPlayEvent();
926
927 case PlugPlayControlProperty:
928 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA))
929 return STATUS_INVALID_PARAMETER;
930 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer);
931
932 case PlugPlayControlGetRelatedDevice:
933 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA))
934 return STATUS_INVALID_PARAMETER;
935 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer);
936
937 case PlugPlayControlDeviceStatus:
938 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA))
939 return STATUS_INVALID_PARAMETER;
940 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA)Buffer);
941
942 case PlugPlayControlGetDeviceDepth:
943 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEPTH_DATA))
944 return STATUS_INVALID_PARAMETER;
945 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer);
946
947 case PlugPlayControlResetDevice:
948 if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA))
949 return STATUS_INVALID_PARAMETER;
950 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer);
951
952 default:
953 return STATUS_NOT_IMPLEMENTED;
954 }
955
956 return STATUS_NOT_IMPLEMENTED;
957 }
958
959 /* EOF */