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