:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / ospm / fdo.c
1 /* $Id$
2  *
3  * PROJECT:         ReactOS ACPI bus driver
4  * FILE:            acpi/ospm/fdo.c
5  * PURPOSE:         ACPI device object dispatch routines
6  * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * UPDATE HISTORY:
8  *      08-08-2001  CSH  Created
9  */
10 #include <acpisys.h>
11 #include <bm.h>
12 #include <bn.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /*** PRIVATE *****************************************************************/
18
19 FADT_DESCRIPTOR_REV2    acpi_fadt;
20
21 NTSTATUS
22 FdoQueryBusRelations(
23   IN PDEVICE_OBJECT DeviceObject,
24   IN PIRP Irp,
25   PIO_STACK_LOCATION IrpSp)
26 {
27   PPDO_DEVICE_EXTENSION PdoDeviceExtension;
28   PFDO_DEVICE_EXTENSION DeviceExtension;
29   PDEVICE_RELATIONS Relations;
30   PLIST_ENTRY CurrentEntry;
31   ANSI_STRING AnsiString;
32   ACPI_STATUS AcpiStatus;
33   PACPI_DEVICE Device;
34   NTSTATUS Status;
35   BM_NODE *Node;
36   ULONG Size;
37   ULONG i;
38
39   DPRINT("Called\n");
40
41   DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
42
43   Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
44     (DeviceExtension->DeviceListCount - 1);
45   Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
46   if (!Relations)
47     return STATUS_INSUFFICIENT_RESOURCES;
48
49   Relations->Count = DeviceExtension->DeviceListCount;
50
51   i = 0;
52   CurrentEntry = DeviceExtension->DeviceListHead.Flink;
53   while (CurrentEntry != &DeviceExtension->DeviceListHead) {
54     Device = CONTAINING_RECORD(CurrentEntry, ACPI_DEVICE, DeviceListEntry);
55
56     /* FIXME: For ACPI namespace devices on the motherboard create filter DOs
57        and attach them just above the ACPI bus device object (PDO) */
58
59     /* FIXME: For other devices in ACPI namespace, but not on motherboard,
60        create PDOs */
61
62     if (!Device->Pdo) {
63       /* Create a physical device object for the
64          device as it does not already have one */
65       Status = IoCreateDevice(DeviceObject->DriverObject, 0,
66         NULL, FILE_DEVICE_CONTROLLER, 0, FALSE, &Device->Pdo);
67       if (!NT_SUCCESS(Status)) {
68         DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
69         /* FIXME: Cleanup all new PDOs created in this call */
70         ExFreePool(Relations);
71         return Status;
72       }
73
74       PdoDeviceExtension = ExAllocatePool(
75         NonPagedPool,
76         sizeof(PDO_DEVICE_EXTENSION));
77       if (!PdoDeviceExtension) {
78         /* FIXME: Cleanup all new PDOs created in this call */
79         ExFreePool(Relations);
80       }
81
82       RtlZeroMemory(
83         PdoDeviceExtension,
84         sizeof(PDO_DEVICE_EXTENSION));
85
86       Device->Pdo->DeviceExtension = PdoDeviceExtension;
87
88       Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
89
90       PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
91
92       PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
93
94       PdoDeviceExtension->Common.Ldo = IoAttachDeviceToDeviceStack(
95         DeviceObject,
96         Device->Pdo);
97
98       RtlInitUnicodeString(&PdoDeviceExtension->HardwareIDs, NULL);
99       RtlInitUnicodeString(&PdoDeviceExtension->CompatibleIDs, NULL);
100
101       AcpiStatus = bm_get_node(Device->BmHandle, 0, &Node);
102       if (ACPI_SUCCESS(AcpiStatus)) {
103         if (Node->device.flags & BM_FLAGS_HAS_A_HID) {
104           RtlInitAnsiString(&AnsiString, Node->device.id.hid);
105           Status = RtlAnsiStringToUnicodeString(
106             &PdoDeviceExtension->HardwareIDs,
107             &AnsiString,
108             TRUE);
109           assert(NT_SUCCESS(Status));
110         }
111
112         if (Node->device.flags & BM_FLAGS_HAS_A_CID) {
113           RtlInitAnsiString(&AnsiString, Node->device.id.cid);
114           Status = RtlAnsiStringToUnicodeString(
115             &PdoDeviceExtension->CompatibleIDs,
116             &AnsiString,
117             TRUE);
118           assert(NT_SUCCESS(Status));
119         }
120       }
121     }
122
123     /* Reference the physical device object. The PnP manager
124        will dereference it again when it is no longer needed */
125     ObReferenceObject(Device->Pdo);
126
127     Relations->Objects[i] = Device->Pdo;
128
129     i++;
130
131     CurrentEntry = CurrentEntry->Flink;
132   }
133
134   Irp->IoStatus.Information = (ULONG)Relations;
135
136   return Status;
137 }
138
139
140 VOID ACPIPrintInfo(
141         PFDO_DEVICE_EXTENSION DeviceExtension)
142 {
143   DbgPrint("ACPI: System firmware supports:\n");
144
145         /*
146          * Print out basic system information
147          */
148         DbgPrint("+------------------------------------------------------------\n");
149         DbgPrint("| Sx states: %cS0 %cS1 %cS2 %cS3 %cS4 %cS5\n",
150     (DeviceExtension->SystemStates[0]?'+':'-'),
151     (DeviceExtension->SystemStates[1]?'+':'-'),
152     (DeviceExtension->SystemStates[2]?'+':'-'),
153     (DeviceExtension->SystemStates[3]?'+':'-'),
154     (DeviceExtension->SystemStates[4]?'+':'-'),
155     (DeviceExtension->SystemStates[5]?'+':'-'));
156         DbgPrint("+------------------------------------------------------------\n");
157 }
158
159 NTSTATUS
160 ACPIInitializeInternalDriver(
161   PFDO_DEVICE_EXTENSION DeviceExtension,
162   ACPI_DRIVER_FUNCTION Initialize,
163   ACPI_DRIVER_FUNCTION Terminate)
164 {
165   ACPI_STATUS AcpiStatus;
166   PACPI_DEVICE AcpiDevice;
167
168   AcpiStatus = Initialize();
169   if (!ACPI_SUCCESS(AcpiStatus)) {
170     DPRINT("BN init status 0x%X\n", AcpiStatus);
171     return STATUS_UNSUCCESSFUL;
172   }
173 #if 0
174   AcpiDevice = (PACPI_DEVICE)ExAllocatePool(
175     NonPagedPool, sizeof(ACPI_DEVICE));
176   if (!AcpiDevice) {
177     return STATUS_INSUFFICIENT_RESOURCES;
178   }
179
180   AcpiDevice->Initialize = Initialize;
181   AcpiDevice->Terminate = Terminate;
182
183   /* FIXME: Create PDO */
184
185   AcpiDevice->Pdo = NULL;
186   //AcpiDevice->BmHandle = HandleList.handles[i];
187
188   ExInterlockedInsertHeadList(&DeviceExtension->DeviceListHead,
189     &AcpiDevice->ListEntry, &DeviceExtension->DeviceListLock);
190 #endif
191   return STATUS_SUCCESS;
192 }
193
194
195 NTSTATUS
196 ACPIInitializeInternalDrivers(
197   PFDO_DEVICE_EXTENSION DeviceExtension)
198 {
199   NTSTATUS Status;
200
201   ULONG j;
202
203   Status = ACPIInitializeInternalDriver(DeviceExtension,
204     bn_initialize, bn_terminate);
205
206   return STATUS_SUCCESS;
207 }
208
209
210 NTSTATUS
211 FdoStartDevice(
212   IN PDEVICE_OBJECT DeviceObject,
213   IN PIRP Irp)
214 {
215   PFDO_DEVICE_EXTENSION DeviceExtension;
216         ACPI_PHYSICAL_ADDRESS rsdp;
217         ACPI_SYSTEM_INFO SysInfo;
218   ACPI_STATUS AcpiStatus;
219   ACPI_BUFFER   Buffer;
220         UCHAR TypeA, TypeB;
221   ULONG i;
222
223   DPRINT("Called\n");
224
225   DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
226
227   assert(DeviceExtension->State == dsStopped);
228
229   AcpiStatus = acpi_initialize_subsystem();
230   if (!ACPI_SUCCESS(AcpiStatus)) {
231     DPRINT("acpi_initialize_subsystem() failed with status 0x%X\n", AcpiStatus);
232     return STATUS_UNSUCCESSFUL;
233   }
234
235   AcpiStatus = acpi_find_root_pointer(&rsdp);
236   if (!ACPI_SUCCESS(AcpiStatus)) {
237     DPRINT("acpi_find_root_pointer() failed with status 0x%X\n", AcpiStatus);
238     return STATUS_UNSUCCESSFUL;
239         }
240
241   /* From this point on, on error we must call acpi_terminate() */
242
243   AcpiStatus = acpi_load_tables(rsdp);
244         if (!ACPI_SUCCESS(AcpiStatus)) {
245                 DPRINT("acpi_load_tables() failed with status 0x%X\n", AcpiStatus);
246                 acpi_terminate();
247                 return STATUS_UNSUCCESSFUL;
248         }
249
250         Buffer.length  = sizeof(SysInfo);
251         Buffer.pointer = &SysInfo;
252
253   AcpiStatus = acpi_get_system_info(&Buffer);
254         if (!ACPI_SUCCESS(AcpiStatus)) {
255                 DPRINT("acpi_get_system_info() failed with status 0x%X\n", AcpiStatus);
256                 acpi_terminate();
257                 return STATUS_UNSUCCESSFUL;
258         }
259
260         DPRINT("ACPI CA Core Subsystem version 0x%X\n", SysInfo.acpi_ca_version);
261
262   assert(SysInfo.num_table_types > ACPI_TABLE_FADT);
263
264   RtlMoveMemory(&acpi_fadt,
265     &SysInfo.table_info[ACPI_TABLE_FADT],
266     sizeof(FADT_DESCRIPTOR_REV2));
267
268   AcpiStatus = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
269   if (!ACPI_SUCCESS(AcpiStatus)) {
270     DPRINT("acpi_enable_subsystem() failed with status 0x%X\n", AcpiStatus);
271     acpi_terminate();
272     return STATUS_UNSUCCESSFUL;
273   }
274
275   DPRINT("ACPI CA Core Subsystem enabled\n");
276
277   /*
278          * Sx States:
279          * ----------
280          * Figure out which Sx states are supported
281          */
282         for (i=0; i<=ACPI_S_STATES_MAX; i++) {
283                 AcpiStatus = acpi_hw_obtain_sleep_type_register_data(
284                         i,
285                         &TypeA,
286                         &TypeB);
287     DPRINT("acpi_hw_obtain_sleep_type_register_data (%d) status 0x%X\n",
288       i, AcpiStatus);
289     if (ACPI_SUCCESS(AcpiStatus)) {
290                         DeviceExtension->SystemStates[i] = TRUE;
291                 }
292         }
293
294   ACPIPrintInfo(DeviceExtension);
295
296   /* Initialize ACPI bus manager */
297   AcpiStatus = bm_initialize();
298   if (!ACPI_SUCCESS(AcpiStatus)) {
299     DPRINT("bm_initialize() failed with status 0x%X\n", AcpiStatus);
300     acpi_terminate();
301     return STATUS_UNSUCCESSFUL;
302   }
303
304   InitializeListHead(&DeviceExtension->DeviceListHead);
305   KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
306   DeviceExtension->DeviceListCount = 0;
307
308   ACPIEnumerateNamespace(DeviceExtension);
309
310   //ACPIEnumerateRootBusses(DeviceExtension);
311
312   ACPIInitializeInternalDrivers(DeviceExtension);
313
314   DeviceExtension->State = dsStarted;
315
316         return STATUS_SUCCESS;
317 }
318
319
320 NTSTATUS
321 FdoSetPower(
322   IN PDEVICE_OBJECT DeviceObject,
323   IN PIRP Irp,
324   PIO_STACK_LOCATION IrpSp)
325 {
326   PFDO_DEVICE_EXTENSION DeviceExtension;
327   ACPI_STATUS AcpiStatus;
328   NTSTATUS Status;
329   ULONG AcpiState;
330
331   DPRINT("Called\n");
332
333   DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
334
335   if (IrpSp->Parameters.Power.Type == SystemPowerState) {
336     Status = STATUS_SUCCESS;
337     switch (IrpSp->Parameters.Power.State.SystemState) {
338     case PowerSystemSleeping1:
339       AcpiState = ACPI_STATE_S1;
340       break;
341     case PowerSystemSleeping2:
342       AcpiState = ACPI_STATE_S2;
343       break;
344     case PowerSystemSleeping3:
345       AcpiState = ACPI_STATE_S3;
346       break;
347     case PowerSystemHibernate:
348       AcpiState = ACPI_STATE_S4;
349       break;
350     case PowerSystemShutdown:
351       AcpiState = ACPI_STATE_S5;
352       break;
353     default:
354       Status = STATUS_UNSUCCESSFUL;
355     }
356     if (!DeviceExtension->SystemStates[AcpiState]) {
357       DPRINT("System sleep state S%d is not supported by hardware\n", AcpiState);
358       Status = STATUS_UNSUCCESSFUL;
359     }
360
361     if (NT_SUCCESS(Status)) {
362       DPRINT("Trying to enter sleep state %d\n", AcpiState);
363
364       AcpiStatus = acpi_enter_sleep_state(AcpiState);
365       if (!ACPI_SUCCESS(AcpiStatus)) {
366         DPRINT("Failed to enter sleep state %d (Status 0x%X)\n",
367           AcpiState, AcpiStatus);
368         Status = STATUS_UNSUCCESSFUL;
369       }
370     }
371   } else {
372     Status = STATUS_UNSUCCESSFUL;
373   }
374
375   return Status;
376 }
377
378
379 /*** PUBLIC ******************************************************************/
380
381 NTSTATUS
382 STDCALL
383 FdoPnpControl(
384   PDEVICE_OBJECT DeviceObject,
385   PIRP Irp)
386 /*
387  * FUNCTION: Handle Plug and Play IRPs for the ACPI device
388  * ARGUMENTS:
389  *     DeviceObject = Pointer to functional device object of the ACPI driver
390  *     Irp          = Pointer to IRP that should be handled
391  * RETURNS:
392  *     Status
393  */
394 {
395   PIO_STACK_LOCATION IrpSp;
396   NTSTATUS Status;
397
398   DPRINT("Called\n");
399
400   IrpSp = IoGetCurrentIrpStackLocation(Irp);
401   switch (IrpSp->MinorFunction) {
402   case IRP_MN_CANCEL_REMOVE_DEVICE:
403     Status = STATUS_NOT_IMPLEMENTED;
404     break;
405
406   case IRP_MN_CANCEL_STOP_DEVICE:
407     Status = STATUS_NOT_IMPLEMENTED;
408     break;
409
410   case IRP_MN_DEVICE_USAGE_NOTIFICATION:
411     Status = STATUS_NOT_IMPLEMENTED;
412     break;
413
414   case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
415     Status = STATUS_NOT_IMPLEMENTED;
416     break;
417
418   case IRP_MN_QUERY_DEVICE_RELATIONS:
419     Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);
420     break;
421
422   case IRP_MN_QUERY_PNP_DEVICE_STATE:
423     Status = STATUS_NOT_IMPLEMENTED;
424     break;
425
426   case IRP_MN_QUERY_REMOVE_DEVICE:
427     Status = STATUS_NOT_IMPLEMENTED;
428     break;
429
430   case IRP_MN_QUERY_STOP_DEVICE:
431     Status = STATUS_NOT_IMPLEMENTED;
432     break;
433
434   case IRP_MN_REMOVE_DEVICE:
435     Status = STATUS_NOT_IMPLEMENTED;
436     break;
437
438   case IRP_MN_START_DEVICE:
439     DPRINT("IRP_MN_START_DEVICE received\n");
440     Status = FdoStartDevice(DeviceObject, Irp);
441     break;
442
443   case IRP_MN_STOP_DEVICE:
444     /* Currently not supported */
445     //bm_terminate();
446     Status = STATUS_UNSUCCESSFUL;
447     break;
448
449   case IRP_MN_SURPRISE_REMOVAL:
450     Status = STATUS_NOT_IMPLEMENTED;
451     break;
452
453   default:
454     DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
455     Status = STATUS_NOT_IMPLEMENTED;
456     break;
457   }
458
459   if (Status != STATUS_PENDING) {
460     Irp->IoStatus.Status = Status;
461     IoCompleteRequest(Irp, IO_NO_INCREMENT);
462   }
463
464   DPRINT("Leaving. Status 0x%X\n", Status);
465
466   return Status;
467 }
468
469
470 NTSTATUS
471 STDCALL
472 FdoPowerControl(
473   PDEVICE_OBJECT DeviceObject,
474   PIRP Irp)
475 /*
476  * FUNCTION: Handle power management IRPs for the ACPI device
477  * ARGUMENTS:
478  *     DeviceObject = Pointer to functional device object of the ACPI driver
479  *     Irp          = Pointer to IRP that should be handled
480  * RETURNS:
481  *     Status
482  */
483 {
484   PIO_STACK_LOCATION IrpSp;
485   NTSTATUS Status;
486
487   DPRINT("Called\n");
488
489   IrpSp = IoGetCurrentIrpStackLocation(Irp);
490
491   switch (IrpSp->MinorFunction) {
492   case IRP_MN_SET_POWER:
493     Status = FdoSetPower(DeviceObject, Irp, IrpSp);
494     break;
495
496   default:
497     DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
498     Status = STATUS_NOT_IMPLEMENTED;
499     break;
500   }
501
502   if (Status != STATUS_PENDING) {
503     Irp->IoStatus.Status = Status;
504     IoCompleteRequest(Irp, IO_NO_INCREMENT);
505   }
506
507   DPRINT("Leaving. Status 0x%X\n", Status);
508
509   return Status;
510 }
511
512 /* EOF */