[CMAKE]
[reactos.git] / drivers / bus / pcix / fdo.c
1 /*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/fdo.c
5 * PURPOSE: FDO Device Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 SINGLE_LIST_ENTRY PciFdoExtensionListHead;
18 BOOLEAN PciBreakOnDefault;
19
20 PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable[] =
21 {
22 {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoWaitWake},
23 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
24 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoSetPowerState},
25 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryPower},
26 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
27 };
28
29 PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable[] =
30 {
31 {IRP_UPWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpStartDevice},
32 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryRemoveDevice},
33 {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpRemoveDevice},
34 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelRemoveDevice},
35 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpStopDevice},
36 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryStopDevice},
37 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelStopDevice},
38 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryDeviceRelations},
39 {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryInterface},
40 {IRP_UPWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryCapabilities},
41 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
42 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
43 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
44 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
45 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
46 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
47 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
48 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
49 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
50 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
51 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
52 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
53 {IRP_UPWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpDeviceUsageNotification},
54 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpSurpriseRemoval},
55 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryLegacyBusInformation},
56 {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
57 };
58
59 PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable =
60 {
61 IRP_MN_QUERY_LEGACY_BUS_INFORMATION,
62 PciFdoDispatchPnpTable,
63 IRP_MN_QUERY_POWER,
64 PciFdoDispatchPowerTable,
65 IRP_DOWNWARD,
66 (PCI_DISPATCH_FUNCTION)PciIrpNotSupported,
67 IRP_DOWNWARD,
68 (PCI_DISPATCH_FUNCTION)PciIrpNotSupported
69 };
70
71 /* FUNCTIONS ******************************************************************/
72
73 NTSTATUS
74 NTAPI
75 PciFdoIrpStartDevice(IN PIRP Irp,
76 IN PIO_STACK_LOCATION IoStackLocation,
77 IN PPCI_FDO_EXTENSION DeviceExtension)
78 {
79 NTSTATUS Status;
80 PCM_RESOURCE_LIST Resources;
81 PAGED_CODE();
82
83 /* The device stack must be starting the FDO in a success path */
84 if (!NT_SUCCESS(Irp->IoStatus.Status)) return STATUS_NOT_SUPPORTED;
85
86 /* Attempt to switch the state machine to the started state */
87 Status = PciBeginStateTransition(DeviceExtension, PciStarted);
88 if (!NT_SUCCESS(Status)) return Status;
89
90 /* Check for any boot-provided resources */
91 Resources = IoStackLocation->Parameters.StartDevice.AllocatedResources;
92 DPRINT1("Resources: %p\n", Resources);
93 if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
94 {
95 /* These resources would only be for non-root FDOs, unhandled for now */
96 ASSERT(Resources->Count == 1);
97 UNIMPLEMENTED;
98 while (TRUE);
99 }
100
101 /* Initialize the arbiter for this FDO */
102 Status = PciInitializeArbiterRanges(DeviceExtension, Resources);
103 if (!NT_SUCCESS(Status))
104 {
105 /* Cancel the transition if this failed */
106 PciCancelStateTransition(DeviceExtension, PciStarted);
107 return Status;
108 }
109
110 /* Again, check for boot-provided resources for non-root FDO */
111 if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
112 {
113 /* Unhandled for now */
114 ASSERT(Resources->Count == 1);
115 UNIMPLEMENTED;
116 while (TRUE);
117 }
118
119 /* Commit the transition to the started state */
120 PciCommitStateTransition(DeviceExtension, PciStarted);
121 return STATUS_SUCCESS;
122 }
123
124 NTSTATUS
125 NTAPI
126 PciFdoIrpQueryRemoveDevice(IN PIRP Irp,
127 IN PIO_STACK_LOCATION IoStackLocation,
128 IN PPCI_FDO_EXTENSION DeviceExtension)
129 {
130 UNIMPLEMENTED;
131 while (TRUE);
132 return STATUS_NOT_SUPPORTED;
133 }
134
135 NTSTATUS
136 NTAPI
137 PciFdoIrpRemoveDevice(IN PIRP Irp,
138 IN PIO_STACK_LOCATION IoStackLocation,
139 IN PPCI_FDO_EXTENSION DeviceExtension)
140 {
141 UNIMPLEMENTED;
142 while (TRUE);
143 return STATUS_NOT_SUPPORTED;
144 }
145
146 NTSTATUS
147 NTAPI
148 PciFdoIrpCancelRemoveDevice(IN PIRP Irp,
149 IN PIO_STACK_LOCATION IoStackLocation,
150 IN PPCI_FDO_EXTENSION DeviceExtension)
151 {
152 UNIMPLEMENTED;
153 while (TRUE);
154 return STATUS_NOT_SUPPORTED;
155 }
156
157 NTSTATUS
158 NTAPI
159 PciFdoIrpStopDevice(IN PIRP Irp,
160 IN PIO_STACK_LOCATION IoStackLocation,
161 IN PPCI_FDO_EXTENSION DeviceExtension)
162 {
163 UNIMPLEMENTED;
164 while (TRUE);
165 return STATUS_NOT_SUPPORTED;
166 }
167
168 NTSTATUS
169 NTAPI
170 PciFdoIrpQueryStopDevice(IN PIRP Irp,
171 IN PIO_STACK_LOCATION IoStackLocation,
172 IN PPCI_FDO_EXTENSION DeviceExtension)
173 {
174 UNIMPLEMENTED;
175 while (TRUE);
176 return STATUS_NOT_SUPPORTED;
177 }
178
179 NTSTATUS
180 NTAPI
181 PciFdoIrpCancelStopDevice(IN PIRP Irp,
182 IN PIO_STACK_LOCATION IoStackLocation,
183 IN PPCI_FDO_EXTENSION DeviceExtension)
184 {
185 UNIMPLEMENTED;
186 while (TRUE);
187 return STATUS_NOT_SUPPORTED;
188 }
189
190 NTSTATUS
191 NTAPI
192 PciFdoIrpQueryDeviceRelations(IN PIRP Irp,
193 IN PIO_STACK_LOCATION IoStackLocation,
194 IN PPCI_FDO_EXTENSION DeviceExtension)
195 {
196 NTSTATUS Status;
197 PAGED_CODE();
198
199 /* Are bus relations being queried? */
200 if (IoStackLocation->Parameters.QueryDeviceRelations.Type != BusRelations)
201 {
202 /* The FDO is a bus, so only bus relations can be obtained */
203 Status = STATUS_NOT_SUPPORTED;
204 }
205 else
206 {
207 /* Scan the PCI bus and build the device relations for the caller */
208 Status = PciQueryDeviceRelations(DeviceExtension,
209 (PDEVICE_RELATIONS*)
210 &Irp->IoStatus.Information);
211 }
212
213 /* Return the enumeration status back */
214 return Status;
215 }
216
217 NTSTATUS
218 NTAPI
219 PciFdoIrpQueryInterface(IN PIRP Irp,
220 IN PIO_STACK_LOCATION IoStackLocation,
221 IN PPCI_FDO_EXTENSION DeviceExtension)
222 {
223 NTSTATUS Status;
224 PAGED_CODE();
225 ASSERT(DeviceExtension->ExtensionType == PciFdoExtensionType);
226
227 /* Deleted extensions don't respond to IRPs */
228 if (DeviceExtension->DeviceState == PciDeleted)
229 {
230 /* Hand it bacO try to deal with it */
231 return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
232 }
233
234 /* Query our driver for this interface */
235 Status = PciQueryInterface(DeviceExtension,
236 IoStackLocation->Parameters.QueryInterface.
237 InterfaceType,
238 IoStackLocation->Parameters.QueryInterface.
239 Size,
240 IoStackLocation->Parameters.QueryInterface.
241 Version,
242 IoStackLocation->Parameters.QueryInterface.
243 InterfaceSpecificData,
244 IoStackLocation->Parameters.QueryInterface.
245 Interface,
246 FALSE);
247 if (NT_SUCCESS(Status))
248 {
249 /* We found it, let the PDO handle it */
250 Irp->IoStatus.Status = Status;
251 return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
252 }
253 else if (Status == STATUS_NOT_SUPPORTED)
254 {
255 /* Otherwise, we can't handle it, let someone else down the stack try */
256 Status = PciCallDownIrpStack(DeviceExtension, Irp);
257 if (Status == STATUS_NOT_SUPPORTED)
258 {
259 /* They can't either, try a last-resort interface lookup */
260 Status = PciQueryInterface(DeviceExtension,
261 IoStackLocation->Parameters.QueryInterface.
262 InterfaceType,
263 IoStackLocation->Parameters.QueryInterface.
264 Size,
265 IoStackLocation->Parameters.QueryInterface.
266 Version,
267 IoStackLocation->Parameters.QueryInterface.
268 InterfaceSpecificData,
269 IoStackLocation->Parameters.QueryInterface.
270 Interface,
271 TRUE);
272 }
273 }
274
275 /* Has anyone claimed this interface yet? */
276 if (Status == STATUS_NOT_SUPPORTED)
277 {
278 /* No, return the original IRP status */
279 Status = Irp->IoStatus.Status;
280 }
281 else
282 {
283 /* Yes, set the new IRP status */
284 Irp->IoStatus.Status = Status;
285 }
286
287 /* Complete this IRP */
288 IoCompleteRequest(Irp, IO_NO_INCREMENT);
289 return Status;
290 }
291
292 NTSTATUS
293 NTAPI
294 PciFdoIrpQueryCapabilities(IN PIRP Irp,
295 IN PIO_STACK_LOCATION IoStackLocation,
296 IN PPCI_FDO_EXTENSION DeviceExtension)
297 {
298 PDEVICE_CAPABILITIES Capabilities;
299 PAGED_CODE();
300 ASSERT_FDO(DeviceExtension);
301
302 /* Get the capabilities */
303 Capabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
304
305 /* Inherit wake levels and power mappings from the higher-up capabilities */
306 DeviceExtension->PowerState.SystemWakeLevel = Capabilities->SystemWake;
307 DeviceExtension->PowerState.DeviceWakeLevel = Capabilities->DeviceWake;
308 RtlCopyMemory(DeviceExtension->PowerState.SystemStateMapping,
309 Capabilities->DeviceState,
310 sizeof(DeviceExtension->PowerState.SystemStateMapping));
311
312 /* Dump the capabilities and return success */
313 PciDebugDumpQueryCapabilities(Capabilities);
314 return STATUS_SUCCESS;
315 }
316
317 NTSTATUS
318 NTAPI
319 PciFdoIrpDeviceUsageNotification(IN PIRP Irp,
320 IN PIO_STACK_LOCATION IoStackLocation,
321 IN PPCI_FDO_EXTENSION DeviceExtension)
322 {
323 UNIMPLEMENTED;
324 while (TRUE);
325 return STATUS_NOT_SUPPORTED;
326 }
327
328 NTSTATUS
329 NTAPI
330 PciFdoIrpSurpriseRemoval(IN PIRP Irp,
331 IN PIO_STACK_LOCATION IoStackLocation,
332 IN PPCI_FDO_EXTENSION DeviceExtension)
333 {
334 UNIMPLEMENTED;
335 while (TRUE);
336 return STATUS_NOT_SUPPORTED;
337 }
338
339 NTSTATUS
340 NTAPI
341 PciFdoIrpQueryLegacyBusInformation(IN PIRP Irp,
342 IN PIO_STACK_LOCATION IoStackLocation,
343 IN PPCI_FDO_EXTENSION DeviceExtension)
344 {
345 UNIMPLEMENTED;
346 while (TRUE);
347 return STATUS_NOT_SUPPORTED;
348 }
349
350 VOID
351 NTAPI
352 PciGetHotPlugParameters(IN PPCI_FDO_EXTENSION FdoExtension)
353 {
354 ACPI_EVAL_INPUT_BUFFER InputBuffer;
355 PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
356 ULONG Length;
357 NTSTATUS Status;
358 PAGED_CODE();
359
360 /* We should receive 4 parameters, per the HPP specification */
361 Length = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 4 * sizeof(ACPI_METHOD_ARGUMENT);
362
363 /* Allocate the buffer to hold the parameters */
364 OutputBuffer = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
365 if (!OutputBuffer) return;
366
367 /* Initialize the output and input buffers. The method is _HPP */
368 RtlZeroMemory(OutputBuffer, Length);
369 *(PULONG)InputBuffer.MethodName = 'PPH_';
370 InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
371 do
372 {
373 /* Send the IOCTL to the ACPI driver */
374 Status = PciSendIoctl(FdoExtension->PhysicalDeviceObject,
375 IOCTL_ACPI_EVAL_METHOD,
376 &InputBuffer,
377 sizeof(InputBuffer),
378 OutputBuffer,
379 Length);
380 if (!NT_SUCCESS(Status))
381 {
382 /* The method failed, check if we can salvage data from parent */
383 if (!PCI_IS_ROOT_FDO(FdoExtension))
384 {
385 /* Copy the root bus' hot plug parameters */
386 FdoExtension->HotPlugParameters = FdoExtension->ParentFdoExtension->HotPlugParameters;
387 }
388
389 /* Nothing more to do on this path */
390 break;
391 }
392
393 /* ACPI sent back some data. 4 parameters are expected in the output */
394 if (OutputBuffer->Count != 4) break;
395
396 /* HotPlug PCI Support not yet implemented */
397 UNIMPLEMENTED;
398 while (TRUE);
399 } while (FALSE);
400
401 /* Free the buffer and return */
402 ExFreePoolWithTag(OutputBuffer, 0);
403 }
404
405 VOID
406 NTAPI
407 PciInitializeFdoExtensionCommonFields(PPCI_FDO_EXTENSION FdoExtension,
408 IN PDEVICE_OBJECT DeviceObject,
409 IN PDEVICE_OBJECT PhysicalDeviceObject)
410 {
411 /* Initialize the extension */
412 RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
413
414 /* Setup the common fields */
415 FdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
416 FdoExtension->FunctionalDeviceObject = DeviceObject;
417 FdoExtension->ExtensionType = PciFdoExtensionType;
418 FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
419 FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
420 FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
421
422 /* Initialize the extension locks */
423 KeInitializeEvent(&FdoExtension->SecondaryExtLock, SynchronizationEvent, TRUE);
424 KeInitializeEvent(&FdoExtension->ChildListLock, SynchronizationEvent, TRUE);
425
426 /* Initialize the default state */
427 PciInitializeState(FdoExtension);
428 }
429
430 NTSTATUS
431 NTAPI
432 PciAddDevice(IN PDRIVER_OBJECT DriverObject,
433 IN PDEVICE_OBJECT PhysicalDeviceObject)
434 {
435 PCM_RESOURCE_LIST Descriptor;
436 PDEVICE_OBJECT AttachedTo;
437 PPCI_FDO_EXTENSION FdoExtension;
438 PPCI_FDO_EXTENSION ParentExtension;
439 PDEVICE_OBJECT DeviceObject;
440 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
441 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
442 NTSTATUS Status;
443 HANDLE KeyHandle;
444 UNICODE_STRING ValueName;
445 ULONG ResultLength;
446 PAGED_CODE();
447 DPRINT1("PCI - AddDevice (a new bus). PDO: %p (Driver: %wZ)\n",
448 PhysicalDeviceObject, &PhysicalDeviceObject->DriverObject->DriverName);
449
450 /* Zero out variables so failure path knows what to do */
451 AttachedTo = NULL;
452 do
453 {
454 /* Check if there's already a device extension for this bus */
455 ParentExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject,
456 &PciGlobalLock);
457 if (ParentExtension)
458 {
459 /* More than one PCI bus, this is not expected yet */
460 UNIMPLEMENTED;
461 while (TRUE);
462 }
463
464 /* Create the FDO for the bus */
465 Status = IoCreateDevice(DriverObject,
466 sizeof(PCI_FDO_EXTENSION),
467 NULL,
468 FILE_DEVICE_BUS_EXTENDER,
469 0,
470 0,
471 &DeviceObject);
472 if (!NT_SUCCESS(Status)) break;
473
474 /* Initialize the extension for the FDO */
475 FdoExtension = DeviceObject->DeviceExtension;
476 PciInitializeFdoExtensionCommonFields(DeviceObject->DeviceExtension,
477 DeviceObject,
478 PhysicalDeviceObject);
479
480 /* Attach to the root PDO */
481 Status = STATUS_NO_SUCH_DEVICE;
482 AttachedTo = IoAttachDeviceToDeviceStack(DeviceObject,
483 PhysicalDeviceObject);
484 ASSERT(AttachedTo != NULL);
485 if (!AttachedTo) break;
486 FdoExtension->AttachedDeviceObject = AttachedTo;
487 if (ParentExtension)
488 {
489 /* More than one PCI bus, this is not expected yet */
490 UNIMPLEMENTED;
491 while (TRUE);
492 }
493 else
494 {
495 /* Query the boot configuration */
496 Status = PciGetDeviceProperty(PhysicalDeviceObject,
497 DevicePropertyBootConfiguration,
498 (PVOID*)&Descriptor);
499 if (!NT_SUCCESS(Status))
500 {
501 /* No configuration has been set */
502 Descriptor = NULL;
503 }
504 else
505 {
506 /* Root PDO in ReactOS does not assign boot resources */
507 UNIMPLEMENTED;
508 while (TRUE);
509 }
510
511 if (Descriptor)
512 {
513 /* Root PDO in ReactOS does not assign boot resources */
514 UNIMPLEMENTED;
515 while (TRUE);
516 }
517 else
518 {
519 /* Default configuration isn't the normal path on Windows */
520 if (PciBreakOnDefault)
521 {
522 /* If a second bus is found and there's still no data, crash */
523 #if 0 // ros bug?
524 KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
525 0xDEAD0010u,
526 (ULONG_PTR)DeviceObject,
527 0,
528 0);
529 #else
530 DPRINT1("Windows would crash!\n");
531 #endif
532 }
533
534 /* Warn that a default configuration will be used, and set bus 0 */
535 DPRINT1("PCI Will use default configuration.\n");
536 PciBreakOnDefault = TRUE;
537 FdoExtension->BaseBus = 0;
538 }
539
540 /* This is the root bus */
541 FdoExtension->BusRootFdoExtension = FdoExtension;
542 }
543
544 /* Get the HAL or ACPI Bus Handler Callbacks for Configuration Access */
545 Status = PciGetConfigHandlers(FdoExtension);
546 if (!NT_SUCCESS(Status)) break;
547
548 /* Initialize all the supported PCI arbiters */
549 Status = PciInitializeArbiters(FdoExtension);
550 if (!NT_SUCCESS(Status)) break;
551
552 /* This is a real FDO, insert it into the list */
553 FdoExtension->Fake = FALSE;
554 PciInsertEntryAtTail(&PciFdoExtensionListHead,
555 FdoExtension,
556 &PciGlobalLock);
557
558 /* Open the device registry key so that we can query the errata flags */
559 IoOpenDeviceRegistryKey(DeviceObject,
560 PLUGPLAY_REGKEY_DEVICE,
561 KEY_ALL_ACCESS,
562 &KeyHandle),
563
564 /* Open the value that contains errata flags for this bus instance */
565 RtlInitUnicodeString(&ValueName, L"HackFlags");
566 Status = ZwQueryValueKey(KeyHandle,
567 &ValueName,
568 KeyValuePartialInformation,
569 ValueInfo,
570 sizeof(Buffer),
571 &ResultLength);
572 ZwClose(KeyHandle);
573 if (NT_SUCCESS(Status))
574 {
575 /* Make sure the data is of expected type and size */
576 if ((ValueInfo->Type == REG_DWORD) &&
577 (ValueInfo->DataLength == sizeof(ULONG)))
578 {
579 /* Read the flags for this bus */
580 FdoExtension->BusHackFlags = *(PULONG)&ValueInfo->Data;
581 }
582 }
583
584 /* Query ACPI for PCI HotPlug Support */
585 PciGetHotPlugParameters(FdoExtension);
586
587 /* The Bus FDO is now initialized */
588 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
589 DPRINT1("PCI Root FDO Added: %p %p\n", DeviceObject, FdoExtension);
590 return STATUS_SUCCESS;
591 } while (FALSE);
592
593 /* This is the failure path */
594 ASSERT(!NT_SUCCESS(Status));
595 if (AttachedTo) IoDetachDevice(AttachedTo);
596 if (DeviceObject) IoDeleteDevice(DeviceObject);
597 return Status;
598 }
599
600 /* EOF */