xref: /reactos/drivers/bus/acpi/pnp.c (revision 1734f297)
1 #include "precomp.h"
2 
3 #define NDEBUG
4 #include <debug.h>
5 
6 NTSTATUS
7 Bus_PlugInDevice (
8     struct acpi_device *Device,
9     PFDO_DEVICE_DATA            FdoData
10     );
11 
12 #ifdef ALLOC_PRAGMA
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)
20 #endif
21 
22 
23 NTSTATUS
24 NTAPI
25 Bus_PnP (
26     PDEVICE_OBJECT   DeviceObject,
27     PIRP             Irp
28     )
29 {
30     PIO_STACK_LOCATION      irpStack;
31     NTSTATUS                status;
32     PCOMMON_DEVICE_DATA     commonData;
33 
34     PAGED_CODE ();
35 
36     irpStack = IoGetCurrentIrpStackLocation (Irp);
37     ASSERT (IRP_MJ_PNP == irpStack->MajorFunction);
38 
39     commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
40 
41 
42     if (commonData->IsFDO) {
43         DPRINT("FDO %s IRP:0x%p\n",
44                       PnPMinorFunctionString(irpStack->MinorFunction),
45                       Irp);
46         //
47         // Request is for the bus FDO
48         //
49         status = Bus_FDO_PnP (
50                     DeviceObject,
51                     Irp,
52                     irpStack,
53                     (PFDO_DEVICE_DATA) commonData);
54     } else {
55         DPRINT("PDO %s IRP: 0x%p\n",
56                       PnPMinorFunctionString(irpStack->MinorFunction),
57                       Irp);
58         //
59         // Request is for the child PDO.
60         //
61         status = Bus_PDO_PnP (
62                     DeviceObject,
63                     Irp,
64                     irpStack,
65                     (PPDO_DEVICE_DATA) commonData);
66     }
67 
68     return status;
69 }
70 
71 NTSTATUS
72 Bus_FDO_PnP (
73     PDEVICE_OBJECT       DeviceObject,
74     PIRP                 Irp,
75     PIO_STACK_LOCATION   IrpStack,
76     PFDO_DEVICE_DATA     DeviceData
77     )
78 {
79     NTSTATUS            status;
80     ULONG               length, prevcount, numPdosPresent;
81     PLIST_ENTRY         entry;
82     PPDO_DEVICE_DATA    pdoData;
83     PDEVICE_RELATIONS   relations, oldRelations;
84 
85     PAGED_CODE ();
86 
87     switch (IrpStack->MinorFunction) {
88 
89     case IRP_MN_START_DEVICE:
90 
91         status = Bus_StartFdo (DeviceData, Irp);
92 
93 
94         //
95         // We must now complete the IRP, since we stopped it in the
96         // completion routine with MORE_PROCESSING_REQUIRED.
97         //
98 
99         Irp->IoStatus.Status = status;
100         IoCompleteRequest (Irp, IO_NO_INCREMENT);
101 
102         return status;
103 
104     case IRP_MN_QUERY_STOP_DEVICE:
105 
106         //
107         // The PnP manager is trying to stop the device
108         // for resource rebalancing.
109         //
110         SET_NEW_PNP_STATE(DeviceData->Common, StopPending);
111         Irp->IoStatus.Status = STATUS_SUCCESS;
112         break;
113 
114     case IRP_MN_CANCEL_STOP_DEVICE:
115 
116         //
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.
121         //
122         //
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
126         // cancel-stop.
127         //
128 
129         if (StopPending == DeviceData->Common.DevicePnPState)
130         {
131             //
132             // We did receive a query-stop, so restore.
133             //
134             RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common);
135             ASSERT(DeviceData->Common.DevicePnPState == Started);
136         }
137         Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP.
138         break;
139 
140     case IRP_MN_QUERY_DEVICE_RELATIONS:
141 
142         DPRINT("\tQueryDeviceRelation Type: %s\n",
143                     DbgDeviceRelationString(\
144                     IrpStack->Parameters.QueryDeviceRelations.Type));
145 
146         if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) {
147             //
148             // We don't support any other Device Relations
149             //
150             break;
151         }
152 
153 
154         ExAcquireFastMutex (&DeviceData->Mutex);
155 
156         oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
157         if (oldRelations) {
158             prevcount = oldRelations->Count;
159             if (!DeviceData->NumPDOs) {
160                 //
161                 // There is a device relations struct already present and we have
162                 // nothing to add to it, so just call IoSkip and IoCall
163                 //
164                 ExReleaseFastMutex (&DeviceData->Mutex);
165                 break;
166             }
167         }
168         else  {
169             prevcount = 0;
170         }
171 
172         //
173         // Calculate the number of PDOs actually present on the bus
174         //
175         numPdosPresent = 0;
176         for (entry = DeviceData->ListOfPDOs.Flink;
177              entry != &DeviceData->ListOfPDOs;
178              entry = entry->Flink) {
179             pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
180             numPdosPresent++;
181         }
182 
183         //
184         // Need to allocate a new relations structure and add our
185         // PDOs to it.
186         //
187 
188         length = sizeof(DEVICE_RELATIONS) +
189                 (((numPdosPresent + prevcount) - 1) * sizeof (PDEVICE_OBJECT));
190 
191         relations = ExAllocatePoolWithTag(PagedPool, length, 'IpcA');
192 
193         if (NULL == relations) {
194             //
195             // Fail the IRP
196             //
197             ExReleaseFastMutex (&DeviceData->Mutex);
198             Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES;
199             IoCompleteRequest (Irp, IO_NO_INCREMENT);
200             return status;
201 
202         }
203 
204         //
205         // Copy in the device objects so far
206         //
207         if (prevcount) {
208             RtlCopyMemory (relations->Objects, oldRelations->Objects,
209                                       prevcount * sizeof (PDEVICE_OBJECT));
210         }
211 
212         relations->Count = prevcount + numPdosPresent;
213 
214         //
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.
219         //
220 
221         for (entry = DeviceData->ListOfPDOs.Flink;
222              entry != &DeviceData->ListOfPDOs;
223              entry = entry->Flink) {
224 
225             pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
226             relations->Objects[prevcount] = pdoData->Common.Self;
227             ObReferenceObject (pdoData->Common.Self);
228             prevcount++;
229         }
230 
231         DPRINT("\t#PDOs present = %d\n\t#PDOs reported = %d\n",
232                              DeviceData->NumPDOs, relations->Count);
233 
234         //
235         // Replace the relations structure in the IRP with the new
236         // one.
237         //
238         if (oldRelations) {
239             ExFreePoolWithTag(oldRelations, 0);
240         }
241         Irp->IoStatus.Information = (ULONG_PTR) relations;
242 
243         ExReleaseFastMutex (&DeviceData->Mutex);
244 
245         //
246         // Set up and pass the IRP further down the stack
247         //
248         Irp->IoStatus.Status = STATUS_SUCCESS;
249         break;
250 
251     default:
252 
253         //
254         // In the default case we merely call the next driver.
255         // We must not modify Irp->IoStatus.Status or complete the IRP.
256         //
257 
258         break;
259     }
260 
261     IoSkipCurrentIrpStackLocation (Irp);
262     status = IoCallDriver (DeviceData->NextLowerDriver, Irp);
263     return STATUS_SUCCESS;
264 }
265 
266 NTSTATUS
267 Bus_StartFdo (
268     PFDO_DEVICE_DATA            FdoData,
269     PIRP   Irp )
270 {
271     NTSTATUS status;
272     POWER_STATE powerState;
273     ACPI_STATUS AcpiStatus;
274 
275     PAGED_CODE ();
276 
277     FdoData->Common.DevicePowerState = PowerDeviceD0;
278     powerState.DeviceState = PowerDeviceD0;
279     PoSetPowerState ( FdoData->Common.Self, DevicePowerState, powerState );
280 
281     SET_NEW_PNP_STATE(FdoData->Common, Started);
282 
283     AcpiStatus = AcpiInitializeSubsystem();
284     if(ACPI_FAILURE(AcpiStatus)){
285         DPRINT1("Unable to AcpiInitializeSubsystem\n");
286         return STATUS_UNSUCCESSFUL;
287     }
288 
289     AcpiStatus = AcpiInitializeTables(NULL, 16, 0);
290     if (ACPI_FAILURE(AcpiStatus)){
291         DPRINT1("Unable to AcpiInitializeTables\n");
292 		return STATUS_UNSUCCESSFUL;
293     }
294 
295     AcpiStatus = AcpiLoadTables();
296     if(ACPI_FAILURE(AcpiStatus)){
297         DPRINT1("Unable to AcpiLoadTables\n");
298         AcpiTerminate();
299         return STATUS_UNSUCCESSFUL;
300     }
301 
302     status = acpi_create_volatile_registry_tables();
303     if (!NT_SUCCESS(status))
304     {
305         DPRINT1("Unable to create ACPI tables in registry\n");
306     }
307 
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);
313         AcpiTerminate();
314         return STATUS_UNSUCCESSFUL;
315     }
316 	status = ACPIEnumerateDevices(FdoData);
317 
318     return status;
319 }
320 
321 NTSTATUS
322 Bus_SendIrpSynchronously (
323     PDEVICE_OBJECT DeviceObject,
324     PIRP Irp
325     )
326 {
327     KEVENT   event;
328     NTSTATUS status;
329 
330     PAGED_CODE();
331 
332     KeInitializeEvent(&event, NotificationEvent, FALSE);
333 
334     IoCopyCurrentIrpStackLocationToNext(Irp);
335 
336     IoSetCompletionRoutine(Irp,
337                            Bus_CompletionRoutine,
338                            &event,
339                            TRUE,
340                            TRUE,
341                            TRUE
342                            );
343 
344     status = IoCallDriver(DeviceObject, Irp);
345 
346     //
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.
352     //
353 
354     if (status == STATUS_PENDING) {
355        KeWaitForSingleObject(&event,
356                              Executive,
357                              KernelMode,
358                              FALSE,
359                              NULL
360                              );
361        status = Irp->IoStatus.Status;
362     }
363 
364     return status;
365 }
366 
367 NTSTATUS
368 NTAPI
369 Bus_CompletionRoutine(
370     PDEVICE_OBJECT   DeviceObject,
371     PIRP             Irp,
372     PVOID            Context
373     )
374 {
375     UNREFERENCED_PARAMETER (DeviceObject);
376 
377     //
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.
381     //
382     if (Irp->PendingReturned != FALSE) {
383 
384         KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
385     }
386     return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
387 }
388 
389 NTSTATUS
390 Bus_DestroyPdo (
391     PDEVICE_OBJECT      Device,
392     PPDO_DEVICE_DATA    PdoData
393     )
394 {
395     PAGED_CODE ();
396 
397     //
398     // BusEnum does not queue any irps at this time so we have nothing to do.
399     //
400 
401     //
402     // Free any resources.
403     //
404 
405     if (PdoData->HardwareIDs) {
406         ExFreePoolWithTag(PdoData->HardwareIDs, 'DpcA');
407         PdoData->HardwareIDs = NULL;
408     }
409 
410     DPRINT("\tDeleting PDO: 0x%p\n", Device);
411     IoDeleteDevice (Device);
412     return STATUS_SUCCESS;
413 }
414 
415 
416 VOID
417 Bus_InitializePdo (
418     PDEVICE_OBJECT      Pdo,
419     PFDO_DEVICE_DATA    FdoData
420     )
421 {
422     PPDO_DEVICE_DATA pdoData;
423     int acpistate;
424     DEVICE_POWER_STATE ntState;
425 
426     PAGED_CODE ();
427 
428     pdoData = (PPDO_DEVICE_DATA)  Pdo->DeviceExtension;
429 
430     DPRINT("pdo 0x%p, extension 0x%p\n", Pdo, pdoData);
431 
432     if (pdoData->AcpiHandle)
433         acpi_bus_get_power(pdoData->AcpiHandle, &acpistate);
434     else
435         acpistate = ACPI_STATE_D0;
436 
437     switch(acpistate)
438     {
439         case ACPI_STATE_D0:
440             ntState = PowerDeviceD0;
441             break;
442         case ACPI_STATE_D1:
443             ntState = PowerDeviceD1;
444             break;
445         case ACPI_STATE_D2:
446             ntState = PowerDeviceD2;
447             break;
448         case ACPI_STATE_D3:
449             ntState = PowerDeviceD3;
450             break;
451         default:
452             DPRINT1("Unknown power state (%d) returned by acpi\n",acpistate);
453             ntState = PowerDeviceUnspecified;
454             break;
455     }
456 
457     //
458     // Initialize the rest
459     //
460     pdoData->Common.IsFDO = FALSE;
461     pdoData->Common.Self =  Pdo;
462 
463     pdoData->ParentFdo = FdoData->Common.Self;
464 
465 
466     INITIALIZE_PNP_STATE(pdoData->Common);
467 
468     pdoData->Common.DevicePowerState = ntState;
469     pdoData->Common.SystemPowerState = FdoData->Common.SystemPowerState;
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 
588