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