8 struct acpi_device
*Device
,
9 PFDO_DEVICE_DATA FdoData
13 #pragma alloc_text (PAGE, Bus_PnP)
14 #pragma alloc_text (PAGE, Bus_PlugInDevice)
15 #pragma alloc_text (PAGE, Bus_InitializePdo)
16 #pragma alloc_text (PAGE, Bus_DestroyPdo)
17 #pragma alloc_text (PAGE, Bus_FDO_PnP)
18 #pragma alloc_text (PAGE, Bus_StartFdo)
19 #pragma alloc_text (PAGE, Bus_SendIrpSynchronously)
26 PDEVICE_OBJECT DeviceObject
,
30 PIO_STACK_LOCATION irpStack
;
32 PCOMMON_DEVICE_DATA commonData
;
36 irpStack
= IoGetCurrentIrpStackLocation (Irp
);
37 ASSERT (IRP_MJ_PNP
== irpStack
->MajorFunction
);
39 commonData
= (PCOMMON_DEVICE_DATA
) DeviceObject
->DeviceExtension
;
42 if (commonData
->IsFDO
) {
43 DPRINT("FDO %s IRP:0x%p\n",
44 PnPMinorFunctionString(irpStack
->MinorFunction
),
47 // Request is for the bus FDO
49 status
= Bus_FDO_PnP (
53 (PFDO_DEVICE_DATA
) commonData
);
55 DPRINT("PDO %s IRP: 0x%p\n",
56 PnPMinorFunctionString(irpStack
->MinorFunction
),
59 // Request is for the child PDO.
61 status
= Bus_PDO_PnP (
65 (PPDO_DEVICE_DATA
) commonData
);
73 PDEVICE_OBJECT DeviceObject
,
75 PIO_STACK_LOCATION IrpStack
,
76 PFDO_DEVICE_DATA DeviceData
80 ULONG length
, prevcount
, numPdosPresent
;
82 PPDO_DEVICE_DATA pdoData
;
83 PDEVICE_RELATIONS relations
, oldRelations
;
87 switch (IrpStack
->MinorFunction
) {
89 case IRP_MN_START_DEVICE
:
91 status
= Bus_StartFdo (DeviceData
, Irp
);
95 // We must now complete the IRP, since we stopped it in the
96 // completion routine with MORE_PROCESSING_REQUIRED.
99 Irp
->IoStatus
.Status
= status
;
100 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
104 case IRP_MN_QUERY_STOP_DEVICE
:
107 // The PnP manager is trying to stop the device
108 // for resource rebalancing.
110 SET_NEW_PNP_STATE(DeviceData
->Common
, StopPending
);
111 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
114 case IRP_MN_CANCEL_STOP_DEVICE
:
117 // The PnP Manager sends this IRP, at some point after an
118 // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a
119 // device that the device will not be stopped for
120 // resource reconfiguration.
123 // First check to see whether you have received cancel-stop
124 // without first receiving a query-stop. This could happen if
125 // someone above us fails a query-stop and passes down the subsequent
129 if (StopPending
== DeviceData
->Common
.DevicePnPState
)
132 // We did receive a query-stop, so restore.
134 RESTORE_PREVIOUS_PNP_STATE(DeviceData
->Common
);
135 ASSERT(DeviceData
->Common
.DevicePnPState
== Started
);
137 Irp
->IoStatus
.Status
= STATUS_SUCCESS
; // We must not fail the IRP.
140 case IRP_MN_QUERY_DEVICE_RELATIONS
:
142 DPRINT("\tQueryDeviceRelation Type: %s\n",
143 DbgDeviceRelationString(\
144 IrpStack
->Parameters
.QueryDeviceRelations
.Type
));
146 if (BusRelations
!= IrpStack
->Parameters
.QueryDeviceRelations
.Type
) {
148 // We don't support any other Device Relations
154 ExAcquireFastMutex (&DeviceData
->Mutex
);
156 oldRelations
= (PDEVICE_RELATIONS
) Irp
->IoStatus
.Information
;
158 prevcount
= oldRelations
->Count
;
159 if (!DeviceData
->NumPDOs
) {
161 // There is a device relations struct already present and we have
162 // nothing to add to it, so just call IoSkip and IoCall
164 ExReleaseFastMutex (&DeviceData
->Mutex
);
173 // Calculate the number of PDOs actually present on the bus
176 for (entry
= DeviceData
->ListOfPDOs
.Flink
;
177 entry
!= &DeviceData
->ListOfPDOs
;
178 entry
= entry
->Flink
) {
179 pdoData
= CONTAINING_RECORD (entry
, PDO_DEVICE_DATA
, Link
);
184 // Need to allocate a new relations structure and add our
188 length
= sizeof(DEVICE_RELATIONS
) +
189 (((numPdosPresent
+ prevcount
) - 1) * sizeof (PDEVICE_OBJECT
));
191 relations
= ExAllocatePoolWithTag(PagedPool
, length
, 'IpcA');
193 if (NULL
== relations
) {
197 ExReleaseFastMutex (&DeviceData
->Mutex
);
198 Irp
->IoStatus
.Status
= status
= STATUS_INSUFFICIENT_RESOURCES
;
199 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
205 // Copy in the device objects so far
208 RtlCopyMemory (relations
->Objects
, oldRelations
->Objects
,
209 prevcount
* sizeof (PDEVICE_OBJECT
));
212 relations
->Count
= prevcount
+ numPdosPresent
;
215 // For each PDO present on this bus add a pointer to the device relations
216 // buffer, being sure to take out a reference to that object.
217 // The Plug & Play system will dereference the object when it is done
218 // with it and free the device relations buffer.
221 for (entry
= DeviceData
->ListOfPDOs
.Flink
;
222 entry
!= &DeviceData
->ListOfPDOs
;
223 entry
= entry
->Flink
) {
225 pdoData
= CONTAINING_RECORD (entry
, PDO_DEVICE_DATA
, Link
);
226 relations
->Objects
[prevcount
] = pdoData
->Common
.Self
;
227 ObReferenceObject (pdoData
->Common
.Self
);
231 DPRINT("\t#PDOs present = %d\n\t#PDOs reported = %d\n",
232 DeviceData
->NumPDOs
, relations
->Count
);
235 // Replace the relations structure in the IRP with the new
239 ExFreePoolWithTag(oldRelations
, 0);
241 Irp
->IoStatus
.Information
= (ULONG_PTR
) relations
;
243 ExReleaseFastMutex (&DeviceData
->Mutex
);
246 // Set up and pass the IRP further down the stack
248 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
254 // In the default case we merely call the next driver.
255 // We must not modify Irp->IoStatus.Status or complete the IRP.
261 IoSkipCurrentIrpStackLocation (Irp
);
262 status
= IoCallDriver (DeviceData
->NextLowerDriver
, Irp
);
263 return STATUS_SUCCESS
;
268 PFDO_DEVICE_DATA FdoData
,
272 POWER_STATE powerState
;
273 ACPI_STATUS AcpiStatus
;
277 FdoData
->Common
.DevicePowerState
= PowerDeviceD0
;
278 powerState
.DeviceState
= PowerDeviceD0
;
279 PoSetPowerState ( FdoData
->Common
.Self
, DevicePowerState
, powerState
);
281 SET_NEW_PNP_STATE(FdoData
->Common
, Started
);
283 AcpiStatus
= AcpiInitializeSubsystem();
284 if(ACPI_FAILURE(AcpiStatus
)){
285 DPRINT1("Unable to AcpiInitializeSubsystem\n");
286 return STATUS_UNSUCCESSFUL
;
289 AcpiStatus
= AcpiInitializeTables(NULL
, 16, 0);
290 if (ACPI_FAILURE(AcpiStatus
)){
291 DPRINT1("Unable to AcpiInitializeTables\n");
292 return STATUS_UNSUCCESSFUL
;
295 AcpiStatus
= AcpiLoadTables();
296 if(ACPI_FAILURE(AcpiStatus
)){
297 DPRINT1("Unable to AcpiLoadTables\n");
299 return STATUS_UNSUCCESSFUL
;
302 status
= acpi_create_volatile_registry_tables();
303 if (!NT_SUCCESS(status
))
305 DPRINT1("Unable to create ACPI tables in registry\n");
308 DPRINT("Acpi subsystem init\n");
309 /* Initialize ACPI bus manager */
310 AcpiStatus
= acpi_init();
311 if (!ACPI_SUCCESS(AcpiStatus
)) {
312 DPRINT1("acpi_init() failed with status 0x%X\n", AcpiStatus
);
314 return STATUS_UNSUCCESSFUL
;
316 status
= ACPIEnumerateDevices(FdoData
);
322 Bus_SendIrpSynchronously (
323 PDEVICE_OBJECT DeviceObject
,
332 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
334 IoCopyCurrentIrpStackLocationToNext(Irp
);
336 IoSetCompletionRoutine(Irp
,
337 Bus_CompletionRoutine
,
344 status
= IoCallDriver(DeviceObject
, Irp
);
347 // Wait for lower drivers to be done with the Irp.
348 // Important thing to note here is when you allocate
349 // the memory for an event in the stack you must do a
350 // KernelMode wait instead of UserMode to prevent
351 // the stack from getting paged out.
354 if (status
== STATUS_PENDING
) {
355 KeWaitForSingleObject(&event
,
361 status
= Irp
->IoStatus
.Status
;
369 Bus_CompletionRoutine(
370 PDEVICE_OBJECT DeviceObject
,
375 UNREFERENCED_PARAMETER (DeviceObject
);
378 // If the lower driver didn't return STATUS_PENDING, we don't need to
379 // set the event because we won't be waiting on it.
380 // This optimization avoids grabbing the dispatcher lock and improves perf.
382 if (Irp
->PendingReturned
!= FALSE
) {
384 KeSetEvent ((PKEVENT
) Context
, IO_NO_INCREMENT
, FALSE
);
386 return STATUS_MORE_PROCESSING_REQUIRED
; // Keep this IRP
391 PDEVICE_OBJECT Device
,
392 PPDO_DEVICE_DATA PdoData
398 // BusEnum does not queue any irps at this time so we have nothing to do.
402 // Free any resources.
405 if (PdoData
->HardwareIDs
) {
406 ExFreePoolWithTag(PdoData
->HardwareIDs
, 'DpcA');
407 PdoData
->HardwareIDs
= NULL
;
410 DPRINT("\tDeleting PDO: 0x%p\n", Device
);
411 IoDeleteDevice (Device
);
412 return STATUS_SUCCESS
;
419 PFDO_DEVICE_DATA FdoData
422 PPDO_DEVICE_DATA pdoData
;
424 DEVICE_POWER_STATE ntState
;
428 pdoData
= (PPDO_DEVICE_DATA
) Pdo
->DeviceExtension
;
430 DPRINT("pdo 0x%p, extension 0x%p\n", Pdo
, pdoData
);
432 if (pdoData
->AcpiHandle
)
433 acpi_bus_get_power(pdoData
->AcpiHandle
, &acpistate
);
435 acpistate
= ACPI_STATE_D0
;
440 ntState
= PowerDeviceD0
;
443 ntState
= PowerDeviceD1
;
446 ntState
= PowerDeviceD2
;
449 ntState
= PowerDeviceD3
;
452 DPRINT1("Unknown power state (%d) returned by acpi\n",acpistate
);
453 ntState
= PowerDeviceUnspecified
;
458 // Initialize the rest
460 pdoData
->Common
.IsFDO
= FALSE
;
461 pdoData
->Common
.Self
= Pdo
;
463 pdoData
->ParentFdo
= FdoData
->Common
.Self
;
466 INITIALIZE_PNP_STATE(pdoData
->Common
);
468 pdoData
->Common
.DevicePowerState
= ntState
;
469 pdoData
->Common
.SystemPowerState
= FdoData
->Common
.SystemPowerState
;
471 ExAcquireFastMutex (&FdoData
->Mutex
);
472 InsertTailList(&FdoData
->ListOfPDOs
, &pdoData
->Link
);
474 ExReleaseFastMutex (&FdoData
->Mutex
);
476 // This should be the last step in initialization.
477 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
484 PnPMinorFunctionString (
488 switch (MinorFunction
)
490 case IRP_MN_START_DEVICE
:
491 return "IRP_MN_START_DEVICE";
492 case IRP_MN_QUERY_REMOVE_DEVICE
:
493 return "IRP_MN_QUERY_REMOVE_DEVICE";
494 case IRP_MN_REMOVE_DEVICE
:
495 return "IRP_MN_REMOVE_DEVICE";
496 case IRP_MN_CANCEL_REMOVE_DEVICE
:
497 return "IRP_MN_CANCEL_REMOVE_DEVICE";
498 case IRP_MN_STOP_DEVICE
:
499 return "IRP_MN_STOP_DEVICE";
500 case IRP_MN_QUERY_STOP_DEVICE
:
501 return "IRP_MN_QUERY_STOP_DEVICE";
502 case IRP_MN_CANCEL_STOP_DEVICE
:
503 return "IRP_MN_CANCEL_STOP_DEVICE";
504 case IRP_MN_QUERY_DEVICE_RELATIONS
:
505 return "IRP_MN_QUERY_DEVICE_RELATIONS";
506 case IRP_MN_QUERY_INTERFACE
:
507 return "IRP_MN_QUERY_INTERFACE";
508 case IRP_MN_QUERY_CAPABILITIES
:
509 return "IRP_MN_QUERY_CAPABILITIES";
510 case IRP_MN_QUERY_RESOURCES
:
511 return "IRP_MN_QUERY_RESOURCES";
512 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
:
513 return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
514 case IRP_MN_QUERY_DEVICE_TEXT
:
515 return "IRP_MN_QUERY_DEVICE_TEXT";
516 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
517 return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
518 case IRP_MN_READ_CONFIG
:
519 return "IRP_MN_READ_CONFIG";
520 case IRP_MN_WRITE_CONFIG
:
521 return "IRP_MN_WRITE_CONFIG";
523 return "IRP_MN_EJECT";
524 case IRP_MN_SET_LOCK
:
525 return "IRP_MN_SET_LOCK";
526 case IRP_MN_QUERY_ID
:
527 return "IRP_MN_QUERY_ID";
528 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
529 return "IRP_MN_QUERY_PNP_DEVICE_STATE";
530 case IRP_MN_QUERY_BUS_INFORMATION
:
531 return "IRP_MN_QUERY_BUS_INFORMATION";
532 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
533 return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
534 case IRP_MN_SURPRISE_REMOVAL
:
535 return "IRP_MN_SURPRISE_REMOVAL";
536 case IRP_MN_QUERY_LEGACY_BUS_INFORMATION
:
537 return "IRP_MN_QUERY_LEGACY_BUS_INFORMATION";
539 return "unknown_pnp_irp";
544 DbgDeviceRelationString(
545 DEVICE_RELATION_TYPE Type
551 return "BusRelations";
552 case EjectionRelations
:
553 return "EjectionRelations";
554 case RemovalRelations
:
555 return "RemovalRelations";
556 case TargetDeviceRelation
:
557 return "TargetDeviceRelation";
559 return "UnKnown Relation";
565 BUS_QUERY_ID_TYPE Type
570 case BusQueryDeviceID
:
571 return "BusQueryDeviceID";
572 case BusQueryHardwareIDs
:
573 return "BusQueryHardwareIDs";
574 case BusQueryCompatibleIDs
:
575 return "BusQueryCompatibleIDs";
576 case BusQueryInstanceID
:
577 return "BusQueryInstanceID";
578 case BusQueryDeviceSerialNumber
:
579 return "BusQueryDeviceSerialNumber";