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