ReactOS  0.4.15-dev-2996-gf777e6b
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;
71  }
72 
73  DPRINT("Allocated devnode 0x%p\n", DeviceNode);
74 
75  /* Return the node */
76  return DeviceNode;
77 }
78 
79 VOID
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 
131 VOID
134  _In_ UINT32 Problem)
135 {
136  DeviceNode->Flags |= DNF_HAS_PROBLEM;
137  DeviceNode->Problem = Problem;
138 }
139 
140 VOID
143 {
144  DeviceNode->Flags &= ~DNF_HAS_PROBLEM;
145  DeviceNode->Problem = 0;
146 }
147 
160 #if 0
161 NTSTATUS
162 IopCreateDeviceNode(
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 
188  RtlZeroMemory(Node, sizeof(DEVICE_NODE));
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  {
260  RtlInitUnicodeString(&KeyName, L"Class");
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 
319 
320  *DeviceNode = Node;
321 
322  return STATUS_SUCCESS;
323 }
324 #endif
325 
326 NTSTATUS
329 {
330  KIRQL OldIrql;
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 
400 static
401 NTSTATUS
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 
434 NTSTATUS
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 DO_DEVICE_INITIALIZING
Definition: env_spec_w32.h:399
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
#define DNF_HAS_PROBLEM
Definition: iotypes.h:183
#define _In_opt_
Definition: ms_sal.h:309
#define TAG_IO_DEVNODE
Definition: tag.h:89
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define _Out_
Definition: ms_sal.h:345
VOID PiInsertDevNode(_In_ PDEVICE_NODE DeviceNode, _In_ PDEVICE_NODE ParentNode)
Definition: devnode.c:80
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
KSPIN_LOCK IopDeviceTreeLock
Definition: devnode.c:19
NTSTATUS NTAPI IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, IN ULONG CreateOptions, OUT PHANDLE Handle)
Definition: pnpmgr.c:522
LONG NTSTATUS
Definition: precomp.h:26
struct _EXTENDED_DEVOBJ_EXTENSION * PEXTENDED_DEVOBJ_EXTENSION
VOID PiSetDevNodeProblem(_In_ PDEVICE_NODE DeviceNode, _In_ UINT32 Problem)
Definition: devnode.c:132
PDEVICE_OBJECT PhysicalDeviceObject
Definition: btrfs_drv.h:1155
PDEVICE_NODE FASTCALL IopGetDeviceNode(_In_ PDEVICE_OBJECT DeviceObject)
Definition: devnode.c:27
#define FASTCALL
Definition: nt_native.h:50
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
UCHAR KIRQL
Definition: env_spec_w32.h:591
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
LONG IopNumberDeviceNodes
Definition: devnode.c:21
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
unsigned int UINT32
VOID PiClearDevNodeProblem(_In_ PDEVICE_NODE DeviceNode)
Definition: devnode.c:141
long LONG
Definition: pedump.c:60
NTSTATUS IopFreeDeviceNode(_In_ PDEVICE_NODE DeviceNode)
Creates a device node.
Definition: devnode.c:327
union node Node
Definition: types.h:1255
#define IopDeviceNodeSetFlag(DeviceNode, Flag)
Definition: io.h:146
enum _PNP_DEVNODE_STATE PNP_DEVNODE_STATE
#define _In_
Definition: ms_sal.h:308
static NTSTATUS IopFindNextDeviceNodeForTraversal(_In_ PDEVICETREE_TRAVERSE_CONTEXT Context)
Definition: devnode.c:402
static const WCHAR ClassGUID[]
Definition: devclass.c:30
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2697
KIRQL OldIrql
Definition: mm.h:1502
Status
Definition: gdiplustypes.h:24
LPTSTR ServiceName
Definition: ServiceMain.c:15
#define ASSERT(a)
Definition: mode.c:44
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PDEVICE_NODE IopRootDeviceNode
Definition: devnode.c:18
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define ObDereferenceObject
Definition: obfuncs.h:203
PDEVICE_NODE PipAllocateDeviceNode(_In_opt_ PDEVICE_OBJECT PhysicalDeviceObject)
Definition: devnode.c:34
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
Definition: Node.h:9
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static const WCHAR L[]
Definition: oid.c:1250
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
#define DNF_LEGACY_DRIVER
Definition: iotypes.h:182
NTSTATUS IopTraverseDeviceTree(_In_ PDEVICETREE_TRAVERSE_CONTEXT Context)
Definition: devnode.c:435
#define DEVNODE_HISTORY_SIZE
Definition: iotypes.h:827
#define InterlockedIncrement
Definition: armddk.h:53
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
#define NULL
Definition: types.h:112
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
struct _DEVICE_NODE * Sibling
Definition: iotypes.h:834
#define DPRINT1
Definition: precomp.h:8
#define ObReferenceObject
Definition: obfuncs.h:204
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define STATUS_SUCCESS
Definition: shellext.h:65
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define DPRINT
Definition: sndvol32.h:71
#define REG_DWORD
Definition: sdbapi.c:596
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
PNP_DEVNODE_STATE PiSetDevNodeState(_In_ PDEVICE_NODE DeviceNode, _In_ PNP_DEVNODE_STATE NewState)
Definition: devnode.c:108
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
NTSTATUS PnpRootCreateDevice(IN PUNICODE_STRING ServiceName, IN OPTIONAL PDRIVER_OBJECT DriverObject, OUT PDEVICE_OBJECT *PhysicalDeviceObject, OUT OPTIONAL PUNICODE_STRING FullInstancePath)
Definition: pnproot.c:185
Definition: dlist.c:348
#define PAGED_CODE()
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
#define REG_SZ
Definition: layer.c:22