[REACTOS]
[reactos.git] / reactos / drivers / bus / acpi / pnp.c
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 = (PDEVICE_RELATIONS) ExAllocatePoolWithTag (PagedPool,
192 length, 'IPCA');
193
194 if (NULL == relations) {
195 //
196 // Fail the IRP
197 //
198 ExReleaseFastMutex (&DeviceData->Mutex);
199 Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES;
200 IoCompleteRequest (Irp, IO_NO_INCREMENT);
201 return status;
202
203 }
204
205 //
206 // Copy in the device objects so far
207 //
208 if (prevcount) {
209 RtlCopyMemory (relations->Objects, oldRelations->Objects,
210 prevcount * sizeof (PDEVICE_OBJECT));
211 }
212
213 relations->Count = prevcount + numPdosPresent;
214
215 //
216 // For each PDO present on this bus add a pointer to the device relations
217 // buffer, being sure to take out a reference to that object.
218 // The Plug & Play system will dereference the object when it is done
219 // with it and free the device relations buffer.
220 //
221
222 for (entry = DeviceData->ListOfPDOs.Flink;
223 entry != &DeviceData->ListOfPDOs;
224 entry = entry->Flink) {
225
226 pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
227 relations->Objects[prevcount] = pdoData->Common.Self;
228 ObReferenceObject (pdoData->Common.Self);
229 prevcount++;
230 }
231
232 DPRINT("\t#PDOs present = %d\n\t#PDOs reported = %d\n",
233 DeviceData->NumPDOs, relations->Count);
234
235 //
236 // Replace the relations structure in the IRP with the new
237 // one.
238 //
239 if (oldRelations) {
240 ExFreePool (oldRelations);
241 }
242 Irp->IoStatus.Information = (ULONG_PTR) relations;
243
244 ExReleaseFastMutex (&DeviceData->Mutex);
245
246 //
247 // Set up and pass the IRP further down the stack
248 //
249 Irp->IoStatus.Status = STATUS_SUCCESS;
250 break;
251
252 default:
253
254 //
255 // In the default case we merely call the next driver.
256 // We must not modify Irp->IoStatus.Status or complete the IRP.
257 //
258
259 break;
260 }
261
262 IoSkipCurrentIrpStackLocation (Irp);
263 status = IoCallDriver (DeviceData->NextLowerDriver, Irp);
264 return STATUS_SUCCESS;
265 }
266
267 NTSTATUS
268 Bus_StartFdo (
269 PFDO_DEVICE_DATA FdoData,
270 PIRP Irp )
271 {
272 NTSTATUS status = STATUS_SUCCESS;
273 POWER_STATE powerState;
274 ACPI_STATUS AcpiStatus;
275
276 PAGED_CODE ();
277
278 FdoData->Common.DevicePowerState = PowerDeviceD0;
279 powerState.DeviceState = PowerDeviceD0;
280 PoSetPowerState ( FdoData->Common.Self, DevicePowerState, powerState );
281
282 SET_NEW_PNP_STATE(FdoData->Common, Started);
283
284 AcpiStatus = AcpiInitializeSubsystem();
285 if(ACPI_FAILURE(AcpiStatus)){
286 DPRINT1("Unable to AcpiInitializeSubsystem\n");
287 return STATUS_UNSUCCESSFUL;
288 }
289
290
291 AcpiStatus = AcpiInitializeTables(NULL, 16, 0);
292 if (ACPI_FAILURE(status)){
293 DPRINT1("Unable to AcpiInitializeSubsystem\n");
294 return STATUS_UNSUCCESSFUL;
295 }
296
297 AcpiStatus = AcpiLoadTables();
298 if(ACPI_FAILURE(AcpiStatus)){
299 DPRINT1("Unable to AcpiLoadTables\n");
300 AcpiTerminate();
301 return STATUS_UNSUCCESSFUL;
302 }
303
304 DPRINT("Acpi subsystem init\n");
305 /* Initialize ACPI bus manager */
306 AcpiStatus = acpi_init();
307 if (!ACPI_SUCCESS(AcpiStatus)) {
308 DPRINT1("acpi_init() failed with status 0x%X\n", AcpiStatus);
309 AcpiTerminate();
310 return STATUS_UNSUCCESSFUL;
311 }
312 status = ACPIEnumerateDevices(FdoData);
313
314 return status;
315 }
316
317 NTSTATUS
318 Bus_SendIrpSynchronously (
319 PDEVICE_OBJECT DeviceObject,
320 PIRP Irp
321 )
322 {
323 KEVENT event;
324 NTSTATUS status;
325
326 PAGED_CODE();
327
328 KeInitializeEvent(&event, NotificationEvent, FALSE);
329
330 IoCopyCurrentIrpStackLocationToNext(Irp);
331
332 IoSetCompletionRoutine(Irp,
333 Bus_CompletionRoutine,
334 &event,
335 TRUE,
336 TRUE,
337 TRUE
338 );
339
340 status = IoCallDriver(DeviceObject, Irp);
341
342 //
343 // Wait for lower drivers to be done with the Irp.
344 // Important thing to note here is when you allocate
345 // the memory for an event in the stack you must do a
346 // KernelMode wait instead of UserMode to prevent
347 // the stack from getting paged out.
348 //
349
350 if (status == STATUS_PENDING) {
351 KeWaitForSingleObject(&event,
352 Executive,
353 KernelMode,
354 FALSE,
355 NULL
356 );
357 status = Irp->IoStatus.Status;
358 }
359
360 return status;
361 }
362
363 NTSTATUS
364 NTAPI
365 Bus_CompletionRoutine(
366 PDEVICE_OBJECT DeviceObject,
367 PIRP Irp,
368 PVOID Context
369 )
370 {
371 UNREFERENCED_PARAMETER (DeviceObject);
372
373 //
374 // If the lower driver didn't return STATUS_PENDING, we don't need to
375 // set the event because we won't be waiting on it.
376 // This optimization avoids grabbing the dispatcher lock and improves perf.
377 //
378 if (Irp->PendingReturned == TRUE) {
379
380 KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
381 }
382 return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
383 }
384
385 NTSTATUS
386 Bus_DestroyPdo (
387 PDEVICE_OBJECT Device,
388 PPDO_DEVICE_DATA PdoData
389 )
390 {
391 PAGED_CODE ();
392
393 //
394 // BusEnum does not queue any irps at this time so we have nothing to do.
395 //
396
397 //
398 // Free any resources.
399 //
400
401 if (PdoData->HardwareIDs) {
402 ExFreePoolWithTag (PdoData->HardwareIDs, 'IPCA');
403 PdoData->HardwareIDs = NULL;
404 }
405
406 DPRINT("\tDeleting PDO: 0x%p\n", Device);
407 IoDeleteDevice (Device);
408 return STATUS_SUCCESS;
409 }
410
411
412 VOID
413 Bus_InitializePdo (
414 PDEVICE_OBJECT Pdo,
415 PFDO_DEVICE_DATA FdoData
416 )
417 {
418 PPDO_DEVICE_DATA pdoData;
419 int acpistate;
420 DEVICE_POWER_STATE ntState;
421
422 PAGED_CODE ();
423
424 pdoData = (PPDO_DEVICE_DATA) Pdo->DeviceExtension;
425
426 DPRINT("pdo 0x%p, extension 0x%p\n", Pdo, pdoData);
427
428 if (pdoData->AcpiHandle)
429 acpi_bus_get_power(pdoData->AcpiHandle, &acpistate);
430 else
431 acpistate = ACPI_STATE_D0;
432
433 switch(acpistate)
434 {
435 case ACPI_STATE_D0:
436 ntState = PowerDeviceD0;
437 break;
438 case ACPI_STATE_D1:
439 ntState = PowerDeviceD1;
440 break;
441 case ACPI_STATE_D2:
442 ntState = PowerDeviceD2;
443 break;
444 case ACPI_STATE_D3:
445 ntState = PowerDeviceD3;
446 break;
447 default:
448 DPRINT1("Unknown power state (%d) returned by acpi\n",acpistate);
449 ntState = PowerDeviceUnspecified;
450 break;
451 }
452
453 //
454 // Initialize the rest
455 //
456 pdoData->Common.IsFDO = FALSE;
457 pdoData->Common.Self = Pdo;
458
459 pdoData->ParentFdo = FdoData->Common.Self;
460
461
462 INITIALIZE_PNP_STATE(pdoData->Common);
463
464 pdoData->Common.DevicePowerState = ntState;
465 pdoData->Common.SystemPowerState = FdoData->Common.SystemPowerState;
466
467 Pdo->Flags |= DO_POWER_PAGABLE;
468
469 ExAcquireFastMutex (&FdoData->Mutex);
470 InsertTailList(&FdoData->ListOfPDOs, &pdoData->Link);
471 FdoData->NumPDOs++;
472 ExReleaseFastMutex (&FdoData->Mutex);
473
474 // This should be the last step in initialization.
475 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
476
477 }
478
479 #if DBG
480
481 PCHAR
482 PnPMinorFunctionString (
483 UCHAR MinorFunction
484 )
485 {
486 switch (MinorFunction)
487 {
488 case IRP_MN_START_DEVICE:
489 return "IRP_MN_START_DEVICE";
490 case IRP_MN_QUERY_REMOVE_DEVICE:
491 return "IRP_MN_QUERY_REMOVE_DEVICE";
492 case IRP_MN_REMOVE_DEVICE:
493 return "IRP_MN_REMOVE_DEVICE";
494 case IRP_MN_CANCEL_REMOVE_DEVICE:
495 return "IRP_MN_CANCEL_REMOVE_DEVICE";
496 case IRP_MN_STOP_DEVICE:
497 return "IRP_MN_STOP_DEVICE";
498 case IRP_MN_QUERY_STOP_DEVICE:
499 return "IRP_MN_QUERY_STOP_DEVICE";
500 case IRP_MN_CANCEL_STOP_DEVICE:
501 return "IRP_MN_CANCEL_STOP_DEVICE";
502 case IRP_MN_QUERY_DEVICE_RELATIONS:
503 return "IRP_MN_QUERY_DEVICE_RELATIONS";
504 case IRP_MN_QUERY_INTERFACE:
505 return "IRP_MN_QUERY_INTERFACE";
506 case IRP_MN_QUERY_CAPABILITIES:
507 return "IRP_MN_QUERY_CAPABILITIES";
508 case IRP_MN_QUERY_RESOURCES:
509 return "IRP_MN_QUERY_RESOURCES";
510 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
511 return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
512 case IRP_MN_QUERY_DEVICE_TEXT:
513 return "IRP_MN_QUERY_DEVICE_TEXT";
514 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
515 return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
516 case IRP_MN_READ_CONFIG:
517 return "IRP_MN_READ_CONFIG";
518 case IRP_MN_WRITE_CONFIG:
519 return "IRP_MN_WRITE_CONFIG";
520 case IRP_MN_EJECT:
521 return "IRP_MN_EJECT";
522 case IRP_MN_SET_LOCK:
523 return "IRP_MN_SET_LOCK";
524 case IRP_MN_QUERY_ID:
525 return "IRP_MN_QUERY_ID";
526 case IRP_MN_QUERY_PNP_DEVICE_STATE:
527 return "IRP_MN_QUERY_PNP_DEVICE_STATE";
528 case IRP_MN_QUERY_BUS_INFORMATION:
529 return "IRP_MN_QUERY_BUS_INFORMATION";
530 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
531 return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
532 case IRP_MN_SURPRISE_REMOVAL:
533 return "IRP_MN_SURPRISE_REMOVAL";
534 case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
535 return "IRP_MN_QUERY_LEGACY_BUS_INFORMATION";
536 default:
537 return "unknown_pnp_irp";
538 }
539 }
540
541 PCHAR
542 DbgDeviceRelationString(
543 DEVICE_RELATION_TYPE Type
544 )
545 {
546 switch (Type)
547 {
548 case BusRelations:
549 return "BusRelations";
550 case EjectionRelations:
551 return "EjectionRelations";
552 case RemovalRelations:
553 return "RemovalRelations";
554 case TargetDeviceRelation:
555 return "TargetDeviceRelation";
556 default:
557 return "UnKnown Relation";
558 }
559 }
560
561 PCHAR
562 DbgDeviceIDString(
563 BUS_QUERY_ID_TYPE Type
564 )
565 {
566 switch (Type)
567 {
568 case BusQueryDeviceID:
569 return "BusQueryDeviceID";
570 case BusQueryHardwareIDs:
571 return "BusQueryHardwareIDs";
572 case BusQueryCompatibleIDs:
573 return "BusQueryCompatibleIDs";
574 case BusQueryInstanceID:
575 return "BusQueryInstanceID";
576 case BusQueryDeviceSerialNumber:
577 return "BusQueryDeviceSerialNumber";
578 default:
579 return "UnKnown ID";
580 }
581 }
582
583 #endif
584
585