ReactOS 0.4.15-dev-7961-gdcf9eb0
devnode.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: PnP manager device tree functions
5 * COPYRIGHT: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * 2007 Hervé Poussineau (hpoussin@reactos.org)
7 * 2010-2012 Cameron Gutman (cameron.gutman@reactos.org)
8 */
9
10/* INCLUDES ******************************************************************/
11
12#include <ntoskrnl.h>
13#define NDEBUG
14#include <debug.h>
15
16/* GLOBALS *******************************************************************/
17
20
22
23/* FUNCTIONS *****************************************************************/
24
29{
30 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
31}
32
36{
38 PAGED_CODE();
39
40 /* Allocate it */
41 DeviceNode = ExAllocatePoolZero(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE);
42 if (!DeviceNode)
43 {
44 return NULL;
45 }
46
47 /* Statistics */
49
50 /* Set it up */
51 DeviceNode->InterfaceType = InterfaceTypeUndefined;
52 DeviceNode->BusNumber = -1;
53 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
54 DeviceNode->ChildBusNumber = -1;
55 DeviceNode->ChildBusTypeIndex = -1;
57// KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
58 InitializeListHead(&DeviceNode->DeviceArbiterList);
59 InitializeListHead(&DeviceNode->DeviceTranslatorList);
60 InitializeListHead(&DeviceNode->TargetDeviceNotify);
61 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
62 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
63
64 /* Check if there is a PDO */
66 {
67 /* Link it and remove the init flag */
68 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
69 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
70 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
71 }
72
73 DPRINT("Allocated devnode 0x%p\n", DeviceNode);
74
75 /* Return the node */
76 return DeviceNode;
77}
78
79VOID
82 _In_ PDEVICE_NODE ParentNode)
83{
84 KIRQL oldIrql;
85
86 ASSERT(DeviceNode->Parent == NULL);
87
89 DeviceNode->Parent = ParentNode;
90 DeviceNode->Sibling = NULL;
91 if (ParentNode->LastChild == NULL)
92 {
93 ParentNode->Child = DeviceNode;
94 ParentNode->LastChild = DeviceNode;
95 }
96 else
97 {
98 ParentNode->LastChild->Sibling = DeviceNode;
99 ParentNode->LastChild = DeviceNode;
100 }
102 DeviceNode->Level = ParentNode->Level + 1;
103
104 DPRINT("Inserted devnode 0x%p to parent 0x%p\n", DeviceNode, ParentNode);
105}
106
110 _In_ PNP_DEVNODE_STATE NewState)
111{
112 KIRQL oldIrql;
113
115
116 PNP_DEVNODE_STATE prevState = DeviceNode->State;
117 if (prevState != NewState)
118 {
119 DeviceNode->State = NewState;
120 DeviceNode->PreviousState = prevState;
121 DeviceNode->StateHistory[DeviceNode->StateHistoryEntry++] = prevState;
122 DeviceNode->StateHistoryEntry %= DEVNODE_HISTORY_SIZE;
123 }
124
126
127 DPRINT("%wZ Changed state 0x%x => 0x%x\n", &DeviceNode->InstancePath, prevState, NewState);
128 return prevState;
129}
130
131VOID
134 _In_ UINT32 Problem)
135{
136 DeviceNode->Flags |= DNF_HAS_PROBLEM;
137 DeviceNode->Problem = Problem;
138}
139
140VOID
143{
144 DeviceNode->Flags &= ~DNF_HAS_PROBLEM;
145 DeviceNode->Problem = 0;
146}
147
160#if 0
162IopCreateDeviceNode(
163 _In_ PDEVICE_NODE ParentNode,
167{
170 UNICODE_STRING FullServiceName;
171 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
172 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
173 UNICODE_STRING KeyName, ClassName;
174 PUNICODE_STRING ServiceName1;
175 ULONG LegacyValue;
177 HANDLE InstanceHandle;
178
179 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
180 ParentNode, PhysicalDeviceObject, ServiceName);
181
183 if (!Node)
184 {
186 }
187
189 InitializeListHead(&Node->TargetDeviceNotify);
190
191 if (!ServiceName)
192 ServiceName1 = &UnknownDeviceName;
193 else
194 ServiceName1 = ServiceName;
195
197 {
198 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length + sizeof(UNICODE_NULL);
199 FullServiceName.Length = 0;
200 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
201 if (!FullServiceName.Buffer)
202 {
205 }
206
207 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
208 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
209 RtlUpcaseUnicodeString(&FullServiceName, &FullServiceName, FALSE);
210
211 Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath);
212 if (!NT_SUCCESS(Status))
213 {
214 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
215 ExFreePool(FullServiceName.Buffer);
217 return Status;
218 }
219
220 /* Create the device key for legacy drivers */
221 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
222 if (!NT_SUCCESS(Status))
223 {
224 ExFreePool(FullServiceName.Buffer);
226 return Status;
227 }
228
229 Node->ServiceName.MaximumLength = ServiceName1->Length + sizeof(UNICODE_NULL);
230 Node->ServiceName.Length = 0;
231 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, Node->ServiceName.MaximumLength);
232 if (!Node->ServiceName.Buffer)
233 {
234 ZwClose(InstanceHandle);
235 ExFreePool(FullServiceName.Buffer);
237 return Status;
238 }
239
240 RtlCopyUnicodeString(&Node->ServiceName, ServiceName1);
241
242 if (ServiceName)
243 {
244 RtlInitUnicodeString(&KeyName, L"Service");
245 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length + sizeof(UNICODE_NULL));
246 }
247
248 if (NT_SUCCESS(Status))
249 {
250 RtlInitUnicodeString(&KeyName, L"Legacy");
251 LegacyValue = 1;
252 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
253
254 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
255 LegacyValue = 0;
256 ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
257
258 if (NT_SUCCESS(Status))
259 {
261 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
262 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length + sizeof(UNICODE_NULL));
263 if (NT_SUCCESS(Status))
264 {
265 RtlInitUnicodeString(&KeyName, L"ClassGUID");
266 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
267 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length + sizeof(UNICODE_NULL));
268 if (NT_SUCCESS(Status))
269 {
270 // FIXME: Retrieve the real "description" by looking at the "DisplayName" string
271 // of the corresponding CurrentControlSet\Services\xxx entry for this driver.
272 RtlInitUnicodeString(&KeyName, L"DeviceDesc");
273 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName1->Buffer, ServiceName1->Length + sizeof(UNICODE_NULL));
274 }
275 }
276 }
277 }
278
279 ZwClose(InstanceHandle);
280 ExFreePool(FullServiceName.Buffer);
281
282 if (!NT_SUCCESS(Status))
283 {
284 ExFreePool(Node->ServiceName.Buffer);
286 return Status;
287 }
288
290 IopDeviceNodeSetFlag(Node, DNF_PROCESSED);
291 IopDeviceNodeSetFlag(Node, DNF_ADDED);
292 IopDeviceNodeSetFlag(Node, DNF_STARTED);
293 }
294
295 Node->PhysicalDeviceObject = PhysicalDeviceObject;
296
297 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
298
299 if (ParentNode)
300 {
302 Node->Parent = ParentNode;
303 Node->Sibling = NULL;
304 if (ParentNode->LastChild == NULL)
305 {
306 ParentNode->Child = Node;
307 ParentNode->LastChild = Node;
308 }
309 else
310 {
311 ParentNode->LastChild->Sibling = Node;
312 ParentNode->LastChild = Node;
313 }
315 Node->Level = ParentNode->Level + 1;
316 }
317
318 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
319
320 *DeviceNode = Node;
321
322 return STATUS_SUCCESS;
323}
324#endif
325
329{
331 PDEVICE_NODE PrevSibling = NULL;
332
333 ASSERT(DeviceNode->PhysicalDeviceObject);
334 /* All children must be deleted before a parent is deleted */
335 ASSERT(DeviceNode->Child == NULL);
336 /* This is the only state where we are allowed to remove the node */
338 /* No notifications should be registered for this device */
339 ASSERT(IsListEmpty(&DeviceNode->TargetDeviceNotify));
340
342
343 /* Get previous sibling */
344 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
345 {
346 PrevSibling = DeviceNode->Parent->Child;
347 while (PrevSibling->Sibling != DeviceNode)
348 PrevSibling = PrevSibling->Sibling;
349 }
350
351 /* Unlink from parent if it exists */
352 if (DeviceNode->Parent)
353 {
354 if (DeviceNode->Parent->LastChild == DeviceNode)
355 {
356 DeviceNode->Parent->LastChild = PrevSibling;
357 if (PrevSibling)
358 PrevSibling->Sibling = NULL;
359 }
360 if (DeviceNode->Parent->Child == DeviceNode)
361 DeviceNode->Parent->Child = DeviceNode->Sibling;
362 }
363
364 /* Unlink from sibling list */
365 if (PrevSibling)
366 PrevSibling->Sibling = DeviceNode->Sibling;
367
369
370 RtlFreeUnicodeString(&DeviceNode->InstancePath);
371
372 RtlFreeUnicodeString(&DeviceNode->ServiceName);
373
374 if (DeviceNode->ResourceList)
375 {
376 ExFreePool(DeviceNode->ResourceList);
377 }
378
379 if (DeviceNode->ResourceListTranslated)
380 {
381 ExFreePool(DeviceNode->ResourceListTranslated);
382 }
383
384 if (DeviceNode->ResourceRequirements)
385 {
386 ExFreePool(DeviceNode->ResourceRequirements);
387 }
388
389 if (DeviceNode->BootResources)
390 {
391 ExFreePool(DeviceNode->BootResources);
392 }
393
394 ((PEXTENDED_DEVOBJ_EXTENSION)DeviceNode->PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = NULL;
396
397 return STATUS_SUCCESS;
398}
399
400static
404{
405 /* If we have a child, simply go down the tree */
406 if (Context->DeviceNode->Child != NULL)
407 {
408 ASSERT(Context->DeviceNode->Child->Parent == Context->DeviceNode);
409 Context->DeviceNode = Context->DeviceNode->Child;
410 return STATUS_SUCCESS;
411 }
412
413 while (Context->DeviceNode != Context->FirstDeviceNode)
414 {
415 /* All children processed -- go sideways */
416 if (Context->DeviceNode->Sibling != NULL)
417 {
418 ASSERT(Context->DeviceNode->Sibling->Parent == Context->DeviceNode->Parent);
419 Context->DeviceNode = Context->DeviceNode->Sibling;
420 return STATUS_SUCCESS;
421 }
422
423 /* We're the last sibling -- go back up */
424 ASSERT(Context->DeviceNode->Parent->LastChild == Context->DeviceNode);
425 Context->DeviceNode = Context->DeviceNode->Parent;
426
427 /* We already visited the parent and all its children, so keep looking */
428 }
429
430 /* Done with all children of the start node -- stop enumeration */
431 return STATUS_UNSUCCESSFUL;
432}
433
437{
440
441 DPRINT("Context 0x%p\n", Context);
442
443 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
444 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
445
446 /* Start from the specified device node */
447 Context->DeviceNode = Context->FirstDeviceNode;
448
449 /* Traverse the device tree */
450 do
451 {
452 DeviceNode = Context->DeviceNode;
453
454 /* HACK: Keep a reference to the PDO so we can keep traversing the tree
455 * if the device is deleted. In a perfect world, children would have to be
456 * deleted before their parents, and we'd restart the traversal after
457 * deleting a device node. */
458 ObReferenceObject(DeviceNode->PhysicalDeviceObject);
459
460 /* Call the action routine */
461 Status = (Context->Action)(DeviceNode, Context->Context);
462 if (NT_SUCCESS(Status))
463 {
464 /* Find next device node */
465 ASSERT(Context->DeviceNode == DeviceNode);
467 }
468
469 /* We need to either abort or make progress */
470 ASSERT(!NT_SUCCESS(Status) || Context->DeviceNode != DeviceNode);
471
472 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
473 } while (NT_SUCCESS(Status));
474
476 {
477 /* The action routine just wanted to terminate the traversal with status
478 code STATUS_SUCCESS */
480 }
481
482 return Status;
483}
#define PAGED_CODE()
@ DeviceNode
Definition: Node.h:9
unsigned int UINT32
#define InterlockedIncrement
Definition: armddk.h:53
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
static WCHAR ServiceName[]
Definition: browser.c:19
PDEVICE_OBJECT PhysicalDeviceObject
Definition: btrfs_drv.h:1157
VOID PiInsertDevNode(_In_ PDEVICE_NODE DeviceNode, _In_ PDEVICE_NODE ParentNode)
Definition: devnode.c:80
static NTSTATUS IopFindNextDeviceNodeForTraversal(_In_ PDEVICETREE_TRAVERSE_CONTEXT Context)
Definition: devnode.c:402
VOID PiClearDevNodeProblem(_In_ PDEVICE_NODE DeviceNode)
Definition: devnode.c:141
PDEVICE_NODE PipAllocateDeviceNode(_In_opt_ PDEVICE_OBJECT PhysicalDeviceObject)
Definition: devnode.c:34
KSPIN_LOCK IopDeviceTreeLock
Definition: devnode.c:19
PDEVICE_NODE FASTCALL IopGetDeviceNode(_In_ PDEVICE_OBJECT DeviceObject)
Definition: devnode.c:27
VOID PiSetDevNodeProblem(_In_ PDEVICE_NODE DeviceNode, _In_ UINT32 Problem)
Definition: devnode.c:132
PNP_DEVNODE_STATE PiSetDevNodeState(_In_ PDEVICE_NODE DeviceNode, _In_ PNP_DEVNODE_STATE NewState)
Definition: devnode.c:108
NTSTATUS IopFreeDeviceNode(_In_ PDEVICE_NODE DeviceNode)
Creates a device node.
Definition: devnode.c:327
PDEVICE_NODE IopRootDeviceNode
Definition: devnode.c:18
LONG IopNumberDeviceNodes
Definition: devnode.c:21
NTSTATUS IopTraverseDeviceTree(_In_ PDEVICETREE_TRAVERSE_CONTEXT Context)
Definition: devnode.c:435
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
union node Node
Definition: types.h:1255
static const WCHAR ClassGUID[]
Definition: devclass.c:30
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define NonPagedPool
Definition: env_spec_w32.h:307
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define PagedPool
Definition: env_spec_w32.h:308
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
Status
Definition: gdiplustypes.h:25
@ InterfaceTypeUndefined
Definition: hwresource.cpp:136
#define REG_SZ
Definition: layer.c:22
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
enum _PNP_DEVNODE_STATE PNP_DEVNODE_STATE
#define DNF_LEGACY_DRIVER
Definition: iotypes.h:182
@ DeviceNodeRemoved
Definition: iotypes.h:439
@ DeviceNodeUninitialized
Definition: iotypes.h:422
struct _EXTENDED_DEVOBJ_EXTENSION * PEXTENDED_DEVOBJ_EXTENSION
#define DNF_HAS_PROBLEM
Definition: iotypes.h:183
#define DEVNODE_HISTORY_SIZE
Definition: iotypes.h:869
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define FASTCALL
Definition: nt_native.h:50
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define UNICODE_NULL
NTSTATUS NTAPI IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, IN ULONG CreateOptions, OUT PHANDLE Handle)
Definition: pnpmgr.c:522
NTSTATUS PnpRootCreateDevice(IN PUNICODE_STRING ServiceName, OUT PDEVICE_OBJECT *PhysicalDeviceObject, OUT PUNICODE_STRING FullInstancePath)
Definition: pnproot.c:184
#define IopDeviceNodeSetFlag(DeviceNode, Flag)
Definition: io.h:146
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
#define REG_DWORD
Definition: sdbapi.c:596
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
struct _DEVICE_NODE * Sibling
Definition: iotypes.h:876
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define TAG_IO_DEVNODE
Definition: tag.h:90
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
Definition: dlist.c:348
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2699
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
#define ObDereferenceObject
Definition: obfuncs.h:203
#define ObReferenceObject
Definition: obfuncs.h:204