Sync to trunk head (r47736)
[reactos.git] / drivers / bus / acpi / pnp.c
1 #include <ntddk.h>
2
3 #include <acpi.h>
4
5 #include <acpisys.h>
6 #include <acpi_bus.h>
7 #include <acpi_drivers.h>
8
9 #include <wdmguid.h>
10 #define NDEBUG
11 #include <debug.h>
12
13 #ifdef ALLOC_PRAGMA
14 #pragma alloc_text (PAGE, Bus_PnP)
15 #pragma alloc_text (PAGE, Bus_PlugInDevice)
16 #pragma alloc_text (PAGE, Bus_InitializePdo)
17 #pragma alloc_text (PAGE, Bus_UnPlugDevice)
18 #pragma alloc_text (PAGE, Bus_DestroyPdo)
19 #pragma alloc_text (PAGE, Bus_FDO_PnP)
20 #pragma alloc_text (PAGE, Bus_StartFdo)
21 #pragma alloc_text (PAGE, Bus_SendIrpSynchronously)
22 #endif
23
24
25 NTSTATUS
26 NTAPI
27 Bus_PnP (
28 PDEVICE_OBJECT DeviceObject,
29 PIRP Irp
30 )
31 {
32 PIO_STACK_LOCATION irpStack;
33 NTSTATUS status;
34 PCOMMON_DEVICE_DATA commonData;
35
36 PAGED_CODE ();
37
38 irpStack = IoGetCurrentIrpStackLocation (Irp);
39 ASSERT (IRP_MJ_PNP == irpStack->MajorFunction);
40
41 commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
42
43
44 if (commonData->IsFDO) {
45 DPRINT("FDO %s IRP:0x%p\n",
46 PnPMinorFunctionString(irpStack->MinorFunction),
47 Irp);
48 //
49 // Request is for the bus FDO
50 //
51 status = Bus_FDO_PnP (
52 DeviceObject,
53 Irp,
54 irpStack,
55 (PFDO_DEVICE_DATA) commonData);
56 } else {
57 DPRINT("PDO %s IRP: 0x%p\n",
58 PnPMinorFunctionString(irpStack->MinorFunction),
59 Irp);
60 //
61 // Request is for the child PDO.
62 //
63 status = Bus_PDO_PnP (
64 DeviceObject,
65 Irp,
66 irpStack,
67 (PPDO_DEVICE_DATA) commonData);
68 }
69
70 return status;
71 }
72
73 NTSTATUS
74 Bus_FDO_PnP (
75 PDEVICE_OBJECT DeviceObject,
76 PIRP Irp,
77 PIO_STACK_LOCATION IrpStack,
78 PFDO_DEVICE_DATA DeviceData
79 )
80 {
81 NTSTATUS status;
82 ULONG length, prevcount, numPdosPresent;
83 PLIST_ENTRY entry;
84 PPDO_DEVICE_DATA pdoData;
85 PDEVICE_RELATIONS relations, oldRelations;
86
87 PAGED_CODE ();
88
89 switch (IrpStack->MinorFunction) {
90
91 case IRP_MN_START_DEVICE:
92
93 status = Bus_StartFdo (DeviceData, Irp);
94
95
96 //
97 // We must now complete the IRP, since we stopped it in the
98 // completion routine with MORE_PROCESSING_REQUIRED.
99 //
100
101 Irp->IoStatus.Status = status;
102 IoCompleteRequest (Irp, IO_NO_INCREMENT);
103
104 return status;
105
106 case IRP_MN_QUERY_STOP_DEVICE:
107
108 //
109 // The PnP manager is trying to stop the device
110 // for resource rebalancing.
111 //
112 SET_NEW_PNP_STATE(DeviceData->Common, StopPending);
113 Irp->IoStatus.Status = STATUS_SUCCESS;
114 break;
115
116 case IRP_MN_CANCEL_STOP_DEVICE:
117
118 //
119 // The PnP Manager sends this IRP, at some point after an
120 // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a
121 // device that the device will not be stopped for
122 // resource reconfiguration.
123 //
124 //
125 // First check to see whether you have received cancel-stop
126 // without first receiving a query-stop. This could happen if
127 // someone above us fails a query-stop and passes down the subsequent
128 // cancel-stop.
129 //
130
131 if (StopPending == DeviceData->Common.DevicePnPState)
132 {
133 //
134 // We did receive a query-stop, so restore.
135 //
136 RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common);
137 ASSERT(DeviceData->Common.DevicePnPState == Started);
138 }
139 Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP.
140 break;
141
142 case IRP_MN_QUERY_DEVICE_RELATIONS:
143
144 DPRINT("\tQueryDeviceRelation Type: %s\n",
145 DbgDeviceRelationString(\
146 IrpStack->Parameters.QueryDeviceRelations.Type));
147
148 if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) {
149 //
150 // We don't support any other Device Relations
151 //
152 break;
153 }
154
155
156 ExAcquireFastMutex (&DeviceData->Mutex);
157
158 oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
159 if (oldRelations) {
160 prevcount = oldRelations->Count;
161 if (!DeviceData->NumPDOs) {
162 //
163 // There is a device relations struct already present and we have
164 // nothing to add to it, so just call IoSkip and IoCall
165 //
166 ExReleaseFastMutex (&DeviceData->Mutex);
167 break;
168 }
169 }
170 else {
171 prevcount = 0;
172 }
173
174 //
175 // Calculate the number of PDOs actually present on the bus
176 //
177 numPdosPresent = 0;
178 for (entry = DeviceData->ListOfPDOs.Flink;
179 entry != &DeviceData->ListOfPDOs;
180 entry = entry->Flink) {
181 pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
182 numPdosPresent++;
183 }
184
185 //
186 // Need to allocate a new relations structure and add our
187 // PDOs to it.
188 //
189
190 length = sizeof(DEVICE_RELATIONS) +
191 ((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) -1;
192
193 relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag (PagedPool,
194 length, 'IPCA');
195
196 if (NULL == relations) {
197 //
198 // Fail the IRP
199 //
200 ExReleaseFastMutex (&DeviceData->Mutex);
201 Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES;
202 IoCompleteRequest (Irp, IO_NO_INCREMENT);
203 return status;
204
205 }
206
207 //
208 // Copy in the device objects so far
209 //
210 if (prevcount) {
211 RtlCopyMemory (relations->Objects, oldRelations->Objects,
212 prevcount * sizeof (PDEVICE_OBJECT));
213 }
214
215 relations->Count = prevcount + numPdosPresent;
216
217 //
218 // For each PDO present on this bus add a pointer to the device relations
219 // buffer, being sure to take out a reference to that object.
220 // The Plug & Play system will dereference the object when it is done
221 // with it and free the device relations buffer.
222 //
223
224 for (entry = DeviceData->ListOfPDOs.Flink;
225 entry != &DeviceData->ListOfPDOs;
226 entry = entry->Flink) {
227
228 pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
229 relations->Objects[prevcount] = pdoData->Common.Self;
230 ObReferenceObject (pdoData->Common.Self);
231 prevcount++;
232 }
233
234 DPRINT("\t#PDOs present = %d\n\t#PDOs reported = %d\n",
235 DeviceData->NumPDOs, relations->Count);
236
237 //
238 // Replace the relations structure in the IRP with the new
239 // one.
240 //
241 if (oldRelations) {
242 ExFreePool (oldRelations);
243 }
244 Irp->IoStatus.Information = (ULONG_PTR) relations;
245
246 ExReleaseFastMutex (&DeviceData->Mutex);
247
248 //
249 // Set up and pass the IRP further down the stack
250 //
251 Irp->IoStatus.Status = STATUS_SUCCESS;
252 break;
253
254 default:
255
256 //
257 // In the default case we merely call the next driver.
258 // We must not modify Irp->IoStatus.Status or complete the IRP.
259 //
260
261 break;
262 }
263
264 IoSkipCurrentIrpStackLocation (Irp);
265 status = IoCallDriver (DeviceData->NextLowerDriver, Irp);
266 return STATUS_SUCCESS;
267 }
268
269 NTSTATUS
270 Bus_StartFdo (
271 PFDO_DEVICE_DATA FdoData,
272 PIRP Irp )
273 {
274 NTSTATUS status = STATUS_SUCCESS;
275 POWER_STATE powerState;
276 ACPI_STATUS AcpiStatus;
277
278 PAGED_CODE ();
279
280 FdoData->Common.DevicePowerState = PowerDeviceD0;
281 powerState.DeviceState = PowerDeviceD0;
282 PoSetPowerState ( FdoData->Common.Self, DevicePowerState, powerState );
283
284 SET_NEW_PNP_STATE(FdoData->Common, Started);
285
286 AcpiStatus = AcpiInitializeSubsystem();
287 if(ACPI_FAILURE(AcpiStatus)){
288 DPRINT1("Unable to AcpiInitializeSubsystem\n");
289 return STATUS_UNSUCCESSFUL;
290 }
291
292
293 AcpiStatus = AcpiInitializeTables(NULL, 16, 0);
294 if (ACPI_FAILURE(status)){
295 DPRINT1("Unable to AcpiInitializeSubsystem\n");
296 return STATUS_UNSUCCESSFUL;
297 }
298
299 AcpiStatus = AcpiLoadTables();
300 if(ACPI_FAILURE(AcpiStatus)){
301 DPRINT1("Unable to AcpiLoadTables\n");
302 AcpiTerminate();
303 return STATUS_UNSUCCESSFUL;
304 }
305
306 DPRINT("Acpi subsystem init\n");
307 /* Initialize ACPI bus manager */
308 AcpiStatus = acpi_init();
309 if (!ACPI_SUCCESS(AcpiStatus)) {
310 DPRINT("acpi_init() failed with status 0x%X\n", AcpiStatus);
311 AcpiTerminate();
312 return STATUS_UNSUCCESSFUL;
313 }
314 status = ACPIEnumerateDevices(FdoData);
315
316 return status;
317 }
318
319 NTSTATUS
320 Bus_SendIrpSynchronously (
321 PDEVICE_OBJECT DeviceObject,
322 PIRP Irp
323 )
324 {
325 KEVENT event;
326 NTSTATUS status;
327
328 PAGED_CODE();
329
330 KeInitializeEvent(&event, NotificationEvent, FALSE);
331
332 IoCopyCurrentIrpStackLocationToNext(Irp);
333
334 IoSetCompletionRoutine(Irp,
335 Bus_CompletionRoutine,
336 &event,
337 TRUE,
338 TRUE,
339 TRUE
340 );
341
342 status = IoCallDriver(DeviceObject, Irp);
343
344 //
345 // Wait for lower drivers to be done with the Irp.
346 // Important thing to note here is when you allocate
347 // the memory for an event in the stack you must do a
348 // KernelMode wait instead of UserMode to prevent
349 // the stack from getting paged out.
350 //
351
352 if (status == STATUS_PENDING) {
353 KeWaitForSingleObject(&event,
354 Executive,
355 KernelMode,
356 FALSE,
357 NULL
358 );
359 status = Irp->IoStatus.Status;
360 }
361
362 return status;
363 }
364
365 NTSTATUS
366 NTAPI
367 Bus_CompletionRoutine(
368 PDEVICE_OBJECT DeviceObject,
369 PIRP Irp,
370 PVOID Context
371 )
372 {
373 UNREFERENCED_PARAMETER (DeviceObject);
374
375 //
376 // If the lower driver didn't return STATUS_PENDING, we don't need to
377 // set the event because we won't be waiting on it.
378 // This optimization avoids grabbing the dispatcher lock and improves perf.
379 //
380 if (Irp->PendingReturned == TRUE) {
381
382 KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
383 }
384 return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
385 }
386
387 NTSTATUS
388 Bus_DestroyPdo (
389 PDEVICE_OBJECT Device,
390 PPDO_DEVICE_DATA PdoData
391 )
392 {
393 PAGED_CODE ();
394
395 //
396 // BusEnum does not queue any irps at this time so we have nothing to do.
397 //
398
399 //
400 // Free any resources.
401 //
402
403 if (PdoData->HardwareIDs) {
404 ExFreePool (PdoData->HardwareIDs);
405 PdoData->HardwareIDs = NULL;
406 }
407
408 DPRINT("\tDeleting PDO: 0x%p\n", Device);
409 IoDeleteDevice (Device);
410 return STATUS_SUCCESS;
411 }
412
413
414 VOID
415 Bus_InitializePdo (
416 PDEVICE_OBJECT Pdo,
417 PFDO_DEVICE_DATA FdoData
418 )
419 {
420 PPDO_DEVICE_DATA pdoData;
421 int acpistate;
422 DEVICE_POWER_STATE ntState;
423
424 PAGED_CODE ();
425
426 pdoData = (PPDO_DEVICE_DATA) Pdo->DeviceExtension;
427
428 DPRINT("pdo 0x%p, extension 0x%p\n", Pdo, pdoData);
429
430 if (pdoData->AcpiHandle)
431 acpi_bus_get_power(pdoData->AcpiHandle, &acpistate);
432 else
433 acpistate = ACPI_STATE_D0;
434
435 switch(acpistate)
436 {
437 case ACPI_STATE_D0:
438 ntState = PowerDeviceD0;
439 break;
440 case ACPI_STATE_D1:
441 ntState = PowerDeviceD1;
442 break;
443 case ACPI_STATE_D2:
444 ntState = PowerDeviceD2;
445 break;
446 case ACPI_STATE_D3:
447 ntState = PowerDeviceD3;
448 break;
449 default:
450 DPRINT1("Unknown power state (%d) returned by acpi\n",acpistate);
451 ntState = PowerDeviceUnspecified;
452 break;
453 }
454
455 //
456 // Initialize the rest
457 //
458 pdoData->Common.IsFDO = FALSE;
459 pdoData->Common.Self = Pdo;
460
461 pdoData->ParentFdo = FdoData->Common.Self;
462
463
464 INITIALIZE_PNP_STATE(pdoData->Common);
465
466 pdoData->Common.DevicePowerState = ntState;
467 pdoData->Common.SystemPowerState = FdoData->Common.SystemPowerState;
468
469 Pdo->Flags |= DO_POWER_PAGABLE;
470
471 ExAcquireFastMutex (&FdoData->Mutex);
472 InsertTailList(&FdoData->ListOfPDOs, &pdoData->Link);
473 FdoData->NumPDOs++;
474 ExReleaseFastMutex (&FdoData->Mutex);
475
476 // This should be the last step in initialization.
477 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
478
479 }
480
481 #if DBG
482
483 PCHAR
484 PnPMinorFunctionString (
485 UCHAR MinorFunction
486 )
487 {
488 switch (MinorFunction)
489 {
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";
522 case IRP_MN_EJECT:
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";
538 default:
539 return "unknown_pnp_irp";
540 }
541 }
542
543 PCHAR
544 DbgDeviceRelationString(
545 DEVICE_RELATION_TYPE Type
546 )
547 {
548 switch (Type)
549 {
550 case BusRelations:
551 return "BusRelations";
552 case EjectionRelations:
553 return "EjectionRelations";
554 case RemovalRelations:
555 return "RemovalRelations";
556 case TargetDeviceRelation:
557 return "TargetDeviceRelation";
558 default:
559 return "UnKnown Relation";
560 }
561 }
562
563 PCHAR
564 DbgDeviceIDString(
565 BUS_QUERY_ID_TYPE Type
566 )
567 {
568 switch (Type)
569 {
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";
580 default:
581 return "UnKnown ID";
582 }
583 }
584
585 #endif
586
587