ReactOS  0.4.15-dev-1184-g23e04ae
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 
34 NTAPI
37 {
39  PAGED_CODE();
40 
41  /* Allocate it */
43  if (!DeviceNode) return DeviceNode;
44 
45  /* Statistics */
47 
48  /* Set it up */
50  DeviceNode->InterfaceType = InterfaceTypeUndefined;
51  DeviceNode->BusNumber = -1;
52  DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
53  DeviceNode->ChildBusNumber = -1;
54  DeviceNode->ChildBusTypeIndex = -1;
55 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
56  InitializeListHead(&DeviceNode->DeviceArbiterList);
57  InitializeListHead(&DeviceNode->DeviceTranslatorList);
58  InitializeListHead(&DeviceNode->TargetDeviceNotify);
59  InitializeListHead(&DeviceNode->DockInfo.ListEntry);
60  InitializeListHead(&DeviceNode->PendedSetInterfaceState);
61 
62  /* Check if there is a PDO */
64  {
65  /* Link it and remove the init flag */
66  DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
67  ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
69  }
70 
71  /* Return the node */
72  return DeviceNode;
73 }
74 
90  _In_ PDEVICE_NODE ParentNode,
94 {
97  KIRQL OldIrql;
98  UNICODE_STRING FullServiceName;
99  UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
100  UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
101  UNICODE_STRING KeyName, ClassName;
102  PUNICODE_STRING ServiceName1;
103  ULONG LegacyValue;
105  HANDLE InstanceHandle;
106 
107  DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
108  ParentNode, PhysicalDeviceObject, ServiceName);
109 
111  if (!Node)
112  {
114  }
115 
116  RtlZeroMemory(Node, sizeof(DEVICE_NODE));
117 
118  if (!ServiceName)
119  ServiceName1 = &UnknownDeviceName;
120  else
121  ServiceName1 = ServiceName;
122 
124  {
125  FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length + sizeof(UNICODE_NULL);
126  FullServiceName.Length = 0;
127  FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
128  if (!FullServiceName.Buffer)
129  {
132  }
133 
134  RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
135  RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
136  RtlUpcaseUnicodeString(&FullServiceName, &FullServiceName, FALSE);
137 
138  Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath);
139  if (!NT_SUCCESS(Status))
140  {
141  DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
142  ExFreePool(FullServiceName.Buffer);
144  return Status;
145  }
146 
147  /* Create the device key for legacy drivers */
148  Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
149  if (!NT_SUCCESS(Status))
150  {
151  ExFreePool(FullServiceName.Buffer);
153  return Status;
154  }
155 
156  Node->ServiceName.MaximumLength = ServiceName1->Length + sizeof(UNICODE_NULL);
157  Node->ServiceName.Length = 0;
158  Node->ServiceName.Buffer = ExAllocatePool(PagedPool, Node->ServiceName.MaximumLength);
159  if (!Node->ServiceName.Buffer)
160  {
161  ZwClose(InstanceHandle);
162  ExFreePool(FullServiceName.Buffer);
164  return Status;
165  }
166 
167  RtlCopyUnicodeString(&Node->ServiceName, ServiceName1);
168 
169  if (ServiceName)
170  {
171  RtlInitUnicodeString(&KeyName, L"Service");
172  Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length + sizeof(UNICODE_NULL));
173  }
174 
175  if (NT_SUCCESS(Status))
176  {
177  RtlInitUnicodeString(&KeyName, L"Legacy");
178  LegacyValue = 1;
179  Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
180 
181  RtlInitUnicodeString(&KeyName, L"ConfigFlags");
182  LegacyValue = 0;
183  ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
184 
185  if (NT_SUCCESS(Status))
186  {
187  RtlInitUnicodeString(&KeyName, L"Class");
188  RtlInitUnicodeString(&ClassName, L"LegacyDriver");
189  Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length + sizeof(UNICODE_NULL));
190  if (NT_SUCCESS(Status))
191  {
192  RtlInitUnicodeString(&KeyName, L"ClassGUID");
193  RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
194  Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length + sizeof(UNICODE_NULL));
195  if (NT_SUCCESS(Status))
196  {
197  // FIXME: Retrieve the real "description" by looking at the "DisplayName" string
198  // of the corresponding CurrentControlSet\Services\xxx entry for this driver.
199  RtlInitUnicodeString(&KeyName, L"DeviceDesc");
200  Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName1->Buffer, ServiceName1->Length + sizeof(UNICODE_NULL));
201  }
202  }
203  }
204  }
205 
206  ZwClose(InstanceHandle);
207  ExFreePool(FullServiceName.Buffer);
208 
209  if (!NT_SUCCESS(Status))
210  {
211  ExFreePool(Node->ServiceName.Buffer);
213  return Status;
214  }
215 
220  }
221 
222  Node->PhysicalDeviceObject = PhysicalDeviceObject;
223 
224  ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
225 
226  if (ParentNode)
227  {
229  Node->Parent = ParentNode;
230  Node->Sibling = NULL;
231  if (ParentNode->LastChild == NULL)
232  {
233  ParentNode->Child = Node;
234  ParentNode->LastChild = Node;
235  }
236  else
237  {
238  ParentNode->LastChild->Sibling = Node;
239  ParentNode->LastChild = Node;
240  }
242  Node->Level = ParentNode->Level + 1;
243  }
244 
246 
247  *DeviceNode = Node;
248 
249  return STATUS_SUCCESS;
250 }
251 
252 NTSTATUS
255 {
256  KIRQL OldIrql;
257  PDEVICE_NODE PrevSibling = NULL;
258 
259  /* All children must be deleted before a parent is deleted */
260  ASSERT(!DeviceNode->Child);
261  ASSERT(DeviceNode->PhysicalDeviceObject);
262 
264 
265  /* Get previous sibling */
266  if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
267  {
268  PrevSibling = DeviceNode->Parent->Child;
269  while (PrevSibling->Sibling != DeviceNode)
270  PrevSibling = PrevSibling->Sibling;
271  }
272 
273  /* Unlink from parent if it exists */
274  if (DeviceNode->Parent)
275  {
276  if (DeviceNode->Parent->LastChild == DeviceNode)
277  {
278  DeviceNode->Parent->LastChild = PrevSibling;
279  if (PrevSibling)
280  PrevSibling->Sibling = NULL;
281  }
282  if (DeviceNode->Parent->Child == DeviceNode)
283  DeviceNode->Parent->Child = DeviceNode->Sibling;
284  }
285 
286  /* Unlink from sibling list */
287  if (PrevSibling)
288  PrevSibling->Sibling = DeviceNode->Sibling;
289 
291 
292  RtlFreeUnicodeString(&DeviceNode->InstancePath);
293 
294  RtlFreeUnicodeString(&DeviceNode->ServiceName);
295 
296  if (DeviceNode->ResourceList)
297  {
298  ExFreePool(DeviceNode->ResourceList);
299  }
300 
301  if (DeviceNode->ResourceListTranslated)
302  {
303  ExFreePool(DeviceNode->ResourceListTranslated);
304  }
305 
306  if (DeviceNode->ResourceRequirements)
307  {
308  ExFreePool(DeviceNode->ResourceRequirements);
309  }
310 
311  if (DeviceNode->BootResources)
312  {
313  ExFreePool(DeviceNode->BootResources);
314  }
315 
316  ((PEXTENDED_DEVOBJ_EXTENSION)DeviceNode->PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = NULL;
318 
319  return STATUS_SUCCESS;
320 }
321 
322 static
323 NTSTATUS
326 {
327  PDEVICE_NODE ParentDeviceNode;
328  PDEVICE_NODE ChildDeviceNode;
329  PDEVICE_NODE NextDeviceNode;
331 
332  /* Copy context data so we don't overwrite it in subsequent calls to this function */
333  ParentDeviceNode = Context->DeviceNode;
334 
335  /* HACK: Keep a reference to the PDO so we can keep traversing the tree
336  * if the device is deleted. In a perfect world, children would have to be
337  * deleted before their parents, and we'd restart the traversal after
338  * deleting a device node. */
339  ObReferenceObject(ParentDeviceNode->PhysicalDeviceObject);
340 
341  /* Call the action routine */
342  Status = (Context->Action)(ParentDeviceNode, Context->Context);
343  if (!NT_SUCCESS(Status))
344  {
345  ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
346  return Status;
347  }
348 
349  /* Traversal of all children nodes */
350  for (ChildDeviceNode = ParentDeviceNode->Child;
351  ChildDeviceNode != NULL;
352  ChildDeviceNode = NextDeviceNode)
353  {
354  /* HACK: We need this reference to ensure we can get Sibling below. */
355  ObReferenceObject(ChildDeviceNode->PhysicalDeviceObject);
356 
357  /* Pass the current device node to the action routine */
358  Context->DeviceNode = ChildDeviceNode;
359 
361  if (!NT_SUCCESS(Status))
362  {
363  ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject);
364  ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
365  return Status;
366  }
367 
368  NextDeviceNode = ChildDeviceNode->Sibling;
369  ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject);
370  }
371 
372  ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
373  return Status;
374 }
375 
376 NTSTATUS
379 {
381 
382  DPRINT("Context 0x%p\n", Context);
383 
384  DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
385  Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
386 
387  /* Start from the specified device node */
388  Context->DeviceNode = Context->FirstDeviceNode;
389 
390  /* Recursively traverse the device tree */
393  {
394  /* The action routine just wanted to terminate the traversal with status
395  code STATUS_SUCCESS */
397  }
398 
399  return Status;
400 }
#define DO_DEVICE_INITIALIZING
Definition: env_spec_w32.h:399
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
NTSTATUS IopCreateDeviceNode(_In_ PDEVICE_NODE ParentNode, _In_opt_ PDEVICE_OBJECT PhysicalDeviceObject, _In_opt_ PUNICODE_STRING ServiceName, _Out_ PDEVICE_NODE *DeviceNode)
Creates a device node.
Definition: devnode.c:89
PDEVICE_OBJECT PhysicalDeviceObject
Definition: iotypes.h:839
#define DNF_PROCESSED
Definition: iotypes.h:167
#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 TAG_IO_DEVNODE
Definition: tag.h:89
USHORT MaximumLength
Definition: env_spec_w32.h:370
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
KSPIN_LOCK IopDeviceTreeLock
Definition: devnode.c:19
static NTSTATUS IopTraverseDeviceTreeNode(_In_ PDEVICETREE_TRAVERSE_CONTEXT Context)
Definition: devnode.c:324
NTSTATUS NTAPI IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, IN ULONG CreateOptions, OUT PHANDLE Handle)
Definition: pnpmgr.c:666
LONG NTSTATUS
Definition: precomp.h:26
PDEVICE_NODE NTAPI PipAllocateDeviceNode(_In_opt_ PDEVICE_OBJECT PhysicalDeviceObject)
Definition: devnode.c:35
struct _EXTENDED_DEVOBJ_EXTENSION * PEXTENDED_DEVOBJ_EXTENSION
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
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
#define _In_opt_
Definition: no_sal2.h:213
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
UCHAR KIRQL
Definition: env_spec_w32.h:591
LONG IopNumberDeviceNodes
Definition: devnode.c:21
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
struct _DEVICE_NODE * Child
Definition: iotypes.h:824
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
long LONG
Definition: pedump.c:60
NTSTATUS IopFreeDeviceNode(_In_ PDEVICE_NODE DeviceNode)
Definition: devnode.c:253
union node Node
Definition: types.h:1255
#define IopDeviceNodeSetFlag(DeviceNode, Flag)
Definition: io.h:142
smooth NULL
Definition: ftsmooth.c:416
#define _Out_
Definition: no_sal2.h:323
void DPRINT(...)
Definition: polytest.cpp:61
static const WCHAR ClassGUID[]
Definition: devclass.c:30
#define DNF_STARTED
Definition: iotypes.h:168
LPTSTR ServiceName
Definition: ServiceMain.c:15
#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
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
Definition: Node.h:9
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
Status
Definition: gdiplustypes.h:24
static const WCHAR L[]
Definition: oid.c:1250
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:790
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
#define DNF_LEGACY_DRIVER
Definition: iotypes.h:181
NTSTATUS IopTraverseDeviceTree(_In_ PDEVICETREE_TRAVERSE_CONTEXT Context)
Definition: devnode.c:377
#define _In_
Definition: no_sal2.h:204
#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
_In_ PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:2464
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
struct _DEVICE_NODE * Sibling
Definition: iotypes.h:823
#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 REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:3014
#define DNF_ADDED
Definition: iotypes.h:179
#define REG_DWORD
Definition: sdbapi.c:596
#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