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