migrate substitution keywords to SVN
[reactos.git] / reactos / 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 FADT_DESCRIPTOR_REV2 acpi_fadt;
18
19 /*** PRIVATE *****************************************************************/
20
21
22 BOOLEAN
23 AcpiCreateUnicodeString(
24 PUNICODE_STRING Destination,
25 PWSTR Source,
26 POOL_TYPE PoolType)
27 {
28 ULONG Length;
29
30 if (!Source)
31 {
32 RtlInitUnicodeString(Destination, NULL);
33 return TRUE;
34 }
35
36 Length = (wcslen(Source) + 1) * sizeof(WCHAR);
37
38 Destination->Buffer = ExAllocatePool(PoolType, Length);
39 if (Destination->Buffer == NULL)
40 {
41 return FALSE;
42 }
43
44 RtlCopyMemory(Destination->Buffer, Source, Length);
45
46 Destination->MaximumLength = Length;
47
48 Destination->Length = Length - sizeof(WCHAR);
49
50 return TRUE;
51 }
52
53 BOOLEAN
54 AcpiCreateDeviceIDString(PUNICODE_STRING DeviceID,
55 BM_NODE *Node)
56 {
57 WCHAR Buffer[256];
58
59 swprintf(Buffer,
60 L"ACPI\\%S",
61 Node->device.id.hid);
62
63 if (!AcpiCreateUnicodeString(DeviceID, Buffer, PagedPool))
64 {
65 return FALSE;
66 }
67
68 return TRUE;
69 }
70
71
72 BOOLEAN
73 AcpiCreateHardwareIDsString(PUNICODE_STRING HardwareIDs,
74 BM_NODE *Node)
75 {
76 WCHAR Buffer[256];
77 ULONG Length;
78 ULONG Index;
79
80 Index = 0;
81 Index += swprintf(&Buffer[Index],
82 L"ACPI\\%S",
83 Node->device.id.hid);
84 Index++;
85
86 Index += swprintf(&Buffer[Index],
87 L"*%S",
88 Node->device.id.hid);
89 Index++;
90 Buffer[Index] = UNICODE_NULL;
91
92 Length = (Index + 1) * sizeof(WCHAR);
93 HardwareIDs->Buffer = ExAllocatePool(PagedPool, Length);
94 if (HardwareIDs->Buffer == NULL)
95 {
96 return FALSE;
97 }
98
99 HardwareIDs->Length = Length - sizeof(WCHAR);
100 HardwareIDs->MaximumLength = Length;
101 RtlCopyMemory(HardwareIDs->Buffer, Buffer, Length);
102
103 return TRUE;
104 }
105
106
107 BOOLEAN
108 AcpiCreateInstanceIDString(PUNICODE_STRING InstanceID,
109 BM_NODE *Node)
110 {
111 /* FIXME: Create unique instnce id. */
112 return AcpiCreateUnicodeString(InstanceID, L"0000", PagedPool);
113 }
114
115
116 static NTSTATUS
117 FdoQueryBusRelations(
118 IN PDEVICE_OBJECT DeviceObject,
119 IN PIRP Irp,
120 PIO_STACK_LOCATION IrpSp)
121 {
122 PPDO_DEVICE_EXTENSION PdoDeviceExtension;
123 PFDO_DEVICE_EXTENSION DeviceExtension;
124 PDEVICE_RELATIONS Relations;
125 PLIST_ENTRY CurrentEntry;
126 ANSI_STRING AnsiString;
127 ACPI_STATUS AcpiStatus;
128 PACPI_DEVICE Device;
129 NTSTATUS Status;
130 BM_NODE *Node;
131 ULONG Size;
132 ULONG i;
133
134 DPRINT("Called\n");
135
136 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
137
138 Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
139 (DeviceExtension->DeviceListCount - 1);
140 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
141 if (!Relations)
142 return STATUS_INSUFFICIENT_RESOURCES;
143
144 Relations->Count = DeviceExtension->DeviceListCount;
145
146 i = 0;
147 CurrentEntry = DeviceExtension->DeviceListHead.Flink;
148 while (CurrentEntry != &DeviceExtension->DeviceListHead)
149 {
150 Device = CONTAINING_RECORD(CurrentEntry, ACPI_DEVICE, DeviceListEntry);
151
152 /* FIXME: For ACPI namespace devices on the motherboard create filter DOs
153 and attach them just above the ACPI bus device object (PDO) */
154
155 /* FIXME: For other devices in ACPI namespace, but not on motherboard,
156 create PDOs */
157
158 if (!Device->Pdo)
159 {
160 /* Create a physical device object for the
161 device as it does not already have one */
162 Status = IoCreateDevice(DeviceObject->DriverObject,
163 sizeof(PDO_DEVICE_EXTENSION),
164 NULL,
165 FILE_DEVICE_CONTROLLER,
166 FILE_AUTOGENERATED_DEVICE_NAME,
167 FALSE,
168 &Device->Pdo);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
172 /* FIXME: Cleanup all new PDOs created in this call */
173 ExFreePool(Relations);
174 return Status;
175 }
176
177 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
178
179 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
180
181 Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
182
183 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
184
185 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
186
187 PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
188
189 PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
190
191 // PdoDeviceExtension->Common.Ldo = IoAttachDeviceToDeviceStack(DeviceObject,
192 // Device->Pdo);
193
194 RtlInitUnicodeString(&PdoDeviceExtension->DeviceID, NULL);
195 RtlInitUnicodeString(&PdoDeviceExtension->InstanceID, NULL);
196 RtlInitUnicodeString(&PdoDeviceExtension->HardwareIDs, NULL);
197
198 AcpiStatus = bm_get_node(Device->BmHandle, 0, &Node);
199 if (ACPI_SUCCESS(AcpiStatus))
200 {
201 /* Add Device ID string */
202 if (!AcpiCreateDeviceIDString(&PdoDeviceExtension->DeviceID,
203 Node))
204 {
205 ASSERT(FALSE);
206 // ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
207 // ErrorOccurred = TRUE;
208 // break;
209 }
210
211 if (!AcpiCreateInstanceIDString(&PdoDeviceExtension->InstanceID,
212 Node))
213 {
214 ASSERT(FALSE);
215 // ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
216 // ErrorOccurred = TRUE;
217 // break;
218 }
219
220 if (!AcpiCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs,
221 Node))
222 {
223 ASSERT(FALSE);
224 // ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
225 // ErrorOccurred = TRUE;
226 // break;
227 }
228 }
229 }
230
231 /* Reference the physical device object. The PnP manager
232 will dereference it again when it is no longer needed */
233 ObReferenceObject(Device->Pdo);
234
235 Relations->Objects[i] = Device->Pdo;
236
237 i++;
238
239 CurrentEntry = CurrentEntry->Flink;
240 }
241
242 Irp->IoStatus.Information = (ULONG)Relations;
243
244 return Status;
245 }
246
247
248 static VOID
249 ACPIPrintInfo(
250 PFDO_DEVICE_EXTENSION DeviceExtension)
251 {
252 DbgPrint("ACPI: System firmware supports:\n");
253
254 /*
255 * Print out basic system information
256 */
257 DbgPrint("+------------------------------------------------------------\n");
258 DbgPrint("| Sx states: %cS0 %cS1 %cS2 %cS3 %cS4 %cS5\n",
259 (DeviceExtension->SystemStates[0]?'+':'-'),
260 (DeviceExtension->SystemStates[1]?'+':'-'),
261 (DeviceExtension->SystemStates[2]?'+':'-'),
262 (DeviceExtension->SystemStates[3]?'+':'-'),
263 (DeviceExtension->SystemStates[4]?'+':'-'),
264 (DeviceExtension->SystemStates[5]?'+':'-'));
265 DbgPrint("+------------------------------------------------------------\n");
266 }
267
268
269 static NTSTATUS
270 ACPIInitializeInternalDriver(
271 PFDO_DEVICE_EXTENSION DeviceExtension,
272 ACPI_DRIVER_FUNCTION Initialize,
273 ACPI_DRIVER_FUNCTION Terminate)
274 {
275 ACPI_STATUS AcpiStatus;
276
277 AcpiStatus = Initialize();
278 if (!ACPI_SUCCESS(AcpiStatus)) {
279 DPRINT("BN init status 0x%X\n", AcpiStatus);
280 return STATUS_UNSUCCESSFUL;
281 }
282 #if 0
283 AcpiDevice = (PACPI_DEVICE)ExAllocatePool(
284 NonPagedPool, sizeof(ACPI_DEVICE));
285 if (!AcpiDevice) {
286 return STATUS_INSUFFICIENT_RESOURCES;
287 }
288
289 AcpiDevice->Initialize = Initialize;
290 AcpiDevice->Terminate = Terminate;
291
292 /* FIXME: Create PDO */
293
294 AcpiDevice->Pdo = NULL;
295 //AcpiDevice->BmHandle = HandleList.handles[i];
296
297 ExInterlockedInsertHeadList(&DeviceExtension->DeviceListHead,
298 &AcpiDevice->ListEntry, &DeviceExtension->DeviceListLock);
299 #endif
300 return STATUS_SUCCESS;
301 }
302
303
304 static NTSTATUS
305 ACPIInitializeInternalDrivers(
306 PFDO_DEVICE_EXTENSION DeviceExtension)
307 {
308 NTSTATUS Status;
309
310 Status = ACPIInitializeInternalDriver(DeviceExtension,
311 bn_initialize, bn_terminate);
312
313 return STATUS_SUCCESS;
314 }
315
316
317 static NTSTATUS
318 FdoStartDevice(
319 IN PDEVICE_OBJECT DeviceObject,
320 IN PIRP Irp)
321 {
322 PFDO_DEVICE_EXTENSION DeviceExtension;
323 ACPI_PHYSICAL_ADDRESS rsdp;
324 ACPI_SYSTEM_INFO SysInfo;
325 ACPI_STATUS AcpiStatus;
326 ACPI_BUFFER Buffer;
327 UCHAR TypeA, TypeB;
328 ULONG i;
329
330 DPRINT("Called\n");
331
332 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
333
334 ASSERT(DeviceExtension->State == dsStopped);
335
336 AcpiStatus = acpi_initialize_subsystem();
337 if (!ACPI_SUCCESS(AcpiStatus)) {
338 DPRINT("acpi_initialize_subsystem() failed with status 0x%X\n", AcpiStatus);
339 return STATUS_UNSUCCESSFUL;
340 }
341
342 AcpiStatus = acpi_find_root_pointer(&rsdp);
343 if (!ACPI_SUCCESS(AcpiStatus)) {
344 DPRINT("acpi_find_root_pointer() failed with status 0x%X\n", AcpiStatus);
345 return STATUS_UNSUCCESSFUL;
346 }
347
348 /* From this point on, on error we must call acpi_terminate() */
349
350 AcpiStatus = acpi_load_tables(rsdp);
351 if (!ACPI_SUCCESS(AcpiStatus)) {
352 DPRINT("acpi_load_tables() failed with status 0x%X\n", AcpiStatus);
353 acpi_terminate();
354 return STATUS_UNSUCCESSFUL;
355 }
356
357 Buffer.length = sizeof(SysInfo);
358 Buffer.pointer = &SysInfo;
359
360 AcpiStatus = acpi_get_system_info(&Buffer);
361 if (!ACPI_SUCCESS(AcpiStatus)) {
362 DPRINT("acpi_get_system_info() failed with status 0x%X\n", AcpiStatus);
363 acpi_terminate();
364 return STATUS_UNSUCCESSFUL;
365 }
366
367 DPRINT("ACPI CA Core Subsystem version 0x%X\n", SysInfo.acpi_ca_version);
368
369 ASSERT(SysInfo.num_table_types > ACPI_TABLE_FADT);
370
371 RtlMoveMemory(&acpi_fadt,
372 &SysInfo.table_info[ACPI_TABLE_FADT],
373 sizeof(FADT_DESCRIPTOR_REV2));
374
375 AcpiStatus = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
376 if (!ACPI_SUCCESS(AcpiStatus)) {
377 DPRINT("acpi_enable_subsystem() failed with status 0x%X\n", AcpiStatus);
378 acpi_terminate();
379 return STATUS_UNSUCCESSFUL;
380 }
381
382 DPRINT("ACPI CA Core Subsystem enabled\n");
383
384 /*
385 * Sx States:
386 * ----------
387 * Figure out which Sx states are supported
388 */
389 for (i=0; i<=ACPI_S_STATES_MAX; i++) {
390 AcpiStatus = acpi_hw_obtain_sleep_type_register_data(
391 i,
392 &TypeA,
393 &TypeB);
394 DPRINT("acpi_hw_obtain_sleep_type_register_data (%d) status 0x%X\n",
395 i, AcpiStatus);
396 if (ACPI_SUCCESS(AcpiStatus)) {
397 DeviceExtension->SystemStates[i] = TRUE;
398 }
399 }
400
401 ACPIPrintInfo(DeviceExtension);
402
403 /* Initialize ACPI bus manager */
404 AcpiStatus = bm_initialize();
405 if (!ACPI_SUCCESS(AcpiStatus)) {
406 DPRINT("bm_initialize() failed with status 0x%X\n", AcpiStatus);
407 acpi_terminate();
408 return STATUS_UNSUCCESSFUL;
409 }
410
411 InitializeListHead(&DeviceExtension->DeviceListHead);
412 KeInitializeSpinLock(&DeviceExtension->DeviceListLock);
413 DeviceExtension->DeviceListCount = 0;
414
415 ACPIEnumerateDevices(DeviceExtension);
416
417 ACPIInitializeInternalDrivers(DeviceExtension);
418
419 DeviceExtension->State = dsStarted;
420
421 return STATUS_SUCCESS;
422 }
423
424
425 static NTSTATUS
426 FdoSetPower(
427 IN PDEVICE_OBJECT DeviceObject,
428 IN PIRP Irp,
429 PIO_STACK_LOCATION IrpSp)
430 {
431 PFDO_DEVICE_EXTENSION DeviceExtension;
432 ACPI_STATUS AcpiStatus;
433 NTSTATUS Status;
434 ULONG AcpiState;
435
436 DPRINT("Called\n");
437
438 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
439
440 if (IrpSp->Parameters.Power.Type == SystemPowerState) {
441 Status = STATUS_SUCCESS;
442 switch (IrpSp->Parameters.Power.State.SystemState) {
443 case PowerSystemSleeping1:
444 AcpiState = ACPI_STATE_S1;
445 break;
446 case PowerSystemSleeping2:
447 AcpiState = ACPI_STATE_S2;
448 break;
449 case PowerSystemSleeping3:
450 AcpiState = ACPI_STATE_S3;
451 break;
452 case PowerSystemHibernate:
453 AcpiState = ACPI_STATE_S4;
454 break;
455 case PowerSystemShutdown:
456 AcpiState = ACPI_STATE_S5;
457 break;
458 default:
459 Status = STATUS_UNSUCCESSFUL;
460 }
461 if (!DeviceExtension->SystemStates[AcpiState]) {
462 DPRINT("System sleep state S%d is not supported by hardware\n", AcpiState);
463 Status = STATUS_UNSUCCESSFUL;
464 }
465
466 if (NT_SUCCESS(Status)) {
467 DPRINT("Trying to enter sleep state %d\n", AcpiState);
468
469 AcpiStatus = acpi_enter_sleep_state(AcpiState);
470 if (!ACPI_SUCCESS(AcpiStatus)) {
471 DPRINT("Failed to enter sleep state %d (Status 0x%X)\n",
472 AcpiState, AcpiStatus);
473 Status = STATUS_UNSUCCESSFUL;
474 }
475 }
476 } else {
477 Status = STATUS_UNSUCCESSFUL;
478 }
479
480 return Status;
481 }
482
483
484 /*** PUBLIC ******************************************************************/
485
486 NTSTATUS
487 STDCALL
488 FdoPnpControl(
489 PDEVICE_OBJECT DeviceObject,
490 PIRP Irp)
491 /*
492 * FUNCTION: Handle Plug and Play IRPs for the ACPI device
493 * ARGUMENTS:
494 * DeviceObject = Pointer to functional device object of the ACPI driver
495 * Irp = Pointer to IRP that should be handled
496 * RETURNS:
497 * Status
498 */
499 {
500 PIO_STACK_LOCATION IrpSp;
501 NTSTATUS Status;
502
503 DPRINT("Called\n");
504
505 IrpSp = IoGetCurrentIrpStackLocation(Irp);
506 switch (IrpSp->MinorFunction) {
507 case IRP_MN_CANCEL_REMOVE_DEVICE:
508 Status = STATUS_NOT_IMPLEMENTED;
509 break;
510
511 case IRP_MN_CANCEL_STOP_DEVICE:
512 Status = STATUS_NOT_IMPLEMENTED;
513 break;
514
515 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
516 Status = STATUS_NOT_IMPLEMENTED;
517 break;
518
519 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
520 Status = STATUS_NOT_IMPLEMENTED;
521 break;
522
523 case IRP_MN_QUERY_DEVICE_RELATIONS:
524 Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp);
525 break;
526
527 case IRP_MN_QUERY_PNP_DEVICE_STATE:
528 Status = STATUS_NOT_IMPLEMENTED;
529 break;
530
531 case IRP_MN_QUERY_REMOVE_DEVICE:
532 Status = STATUS_NOT_IMPLEMENTED;
533 break;
534
535 case IRP_MN_QUERY_STOP_DEVICE:
536 Status = STATUS_NOT_IMPLEMENTED;
537 break;
538
539 case IRP_MN_REMOVE_DEVICE:
540 Status = STATUS_NOT_IMPLEMENTED;
541 break;
542
543 case IRP_MN_START_DEVICE:
544 DPRINT("IRP_MN_START_DEVICE received\n");
545 Status = FdoStartDevice(DeviceObject, Irp);
546 break;
547
548 case IRP_MN_STOP_DEVICE:
549 /* Currently not supported */
550 //bm_terminate();
551 Status = STATUS_UNSUCCESSFUL;
552 break;
553
554 case IRP_MN_SURPRISE_REMOVAL:
555 Status = STATUS_NOT_IMPLEMENTED;
556 break;
557
558 default:
559 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
560 Status = STATUS_NOT_IMPLEMENTED;
561 break;
562 }
563
564 if (Status != STATUS_PENDING) {
565 Irp->IoStatus.Status = Status;
566 IoCompleteRequest(Irp, IO_NO_INCREMENT);
567 }
568
569 DPRINT("Leaving. Status 0x%X\n", Status);
570
571 return Status;
572 }
573
574
575 NTSTATUS
576 STDCALL
577 FdoPowerControl(
578 PDEVICE_OBJECT DeviceObject,
579 PIRP Irp)
580 /*
581 * FUNCTION: Handle power management IRPs for the ACPI device
582 * ARGUMENTS:
583 * DeviceObject = Pointer to functional device object of the ACPI driver
584 * Irp = Pointer to IRP that should be handled
585 * RETURNS:
586 * Status
587 */
588 {
589 PIO_STACK_LOCATION IrpSp;
590 NTSTATUS Status;
591
592 DPRINT("Called\n");
593
594 IrpSp = IoGetCurrentIrpStackLocation(Irp);
595
596 switch (IrpSp->MinorFunction) {
597 case IRP_MN_SET_POWER:
598 Status = FdoSetPower(DeviceObject, Irp, IrpSp);
599 break;
600
601 default:
602 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
603 Status = STATUS_NOT_IMPLEMENTED;
604 break;
605 }
606
607 if (Status != STATUS_PENDING) {
608 Irp->IoStatus.Status = Status;
609 IoCompleteRequest(Irp, IO_NO_INCREMENT);
610 }
611
612 DPRINT("Leaving. Status 0x%X\n", Status);
613
614 return Status;
615 }
616
617 /* EOF */