[ACPI]
[reactos.git] / reactos / drivers / bus / acpi / main.c
1 #include <ntddk.h>
2
3 #include <acpi.h>
4 #include <acpisys.h>
5
6 #include <acpi_bus.h>
7 #include <acpi_drivers.h>
8
9 #include <acpiioct.h>
10 #include <poclass.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 NTSTATUS
16 NTAPI
17 DriverEntry (
18 PDRIVER_OBJECT DriverObject,
19 PUNICODE_STRING RegistryPath
20 );
21
22 #ifdef ALLOC_PRAGMA
23 #pragma alloc_text (INIT, DriverEntry)
24 #pragma alloc_text (PAGE, Bus_AddDevice)
25
26 #endif
27
28 extern struct acpi_device *sleep_button;
29 extern struct acpi_device *power_button;
30
31 UNICODE_STRING ProcessorHardwareIds = {0, 0, NULL};
32 LPWSTR ProcessorNameString = NULL;
33
34
35 NTSTATUS
36 NTAPI
37 Bus_AddDevice(
38 PDRIVER_OBJECT DriverObject,
39 PDEVICE_OBJECT PhysicalDeviceObject
40 )
41
42 {
43 NTSTATUS status;
44 PDEVICE_OBJECT deviceObject = NULL;
45 PFDO_DEVICE_DATA deviceData = NULL;
46 PWCHAR deviceName = NULL;
47 #ifndef NDEBUG
48 ULONG nameLength;
49 #endif
50
51 PAGED_CODE ();
52
53 DPRINT("Add Device: 0x%p\n", PhysicalDeviceObject);
54
55 DPRINT("#################### Bus_CreateClose Creating FDO Device ####################\n");
56 status = IoCreateDevice(DriverObject,
57 sizeof(FDO_DEVICE_DATA),
58 NULL,
59 FILE_DEVICE_ACPI,
60 FILE_DEVICE_SECURE_OPEN,
61 TRUE,
62 &deviceObject);
63 if (!NT_SUCCESS(status))
64 {
65 DPRINT1("IoCreateDevice() failed with status 0x%X\n", status);
66 goto End;
67 }
68
69 deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension;
70 RtlZeroMemory (deviceData, sizeof (FDO_DEVICE_DATA));
71
72 //
73 // Set the initial state of the FDO
74 //
75
76 INITIALIZE_PNP_STATE(deviceData->Common);
77
78 deviceData->Common.IsFDO = TRUE;
79
80 deviceData->Common.Self = deviceObject;
81
82 ExInitializeFastMutex (&deviceData->Mutex);
83
84 InitializeListHead (&deviceData->ListOfPDOs);
85
86 // Set the PDO for use with PlugPlay functions
87
88 deviceData->UnderlyingPDO = PhysicalDeviceObject;
89
90 //
91 // Set the initial powerstate of the FDO
92 //
93
94 deviceData->Common.DevicePowerState = PowerDeviceUnspecified;
95 deviceData->Common.SystemPowerState = PowerSystemWorking;
96
97 deviceObject->Flags |= DO_POWER_PAGABLE;
98
99 //
100 // Attach our FDO to the device stack.
101 // The return value of IoAttachDeviceToDeviceStack is the top of the
102 // attachment chain. This is where all the IRPs should be routed.
103 //
104
105 deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack (
106 deviceObject,
107 PhysicalDeviceObject);
108
109 if (NULL == deviceData->NextLowerDriver) {
110
111 status = STATUS_NO_SUCH_DEVICE;
112 goto End;
113 }
114
115
116 #ifndef NDEBUG
117 //
118 // We will demonstrate here the step to retrieve the name of the PDO
119 //
120
121 status = IoGetDeviceProperty (PhysicalDeviceObject,
122 DevicePropertyPhysicalDeviceObjectName,
123 0,
124 NULL,
125 &nameLength);
126
127 if (status != STATUS_BUFFER_TOO_SMALL)
128 {
129 DPRINT1("AddDevice:IoGDP failed (0x%x)\n", status);
130 goto End;
131 }
132
133 deviceName = ExAllocatePoolWithTag (NonPagedPool,
134 nameLength, 'IPCA');
135
136 if (NULL == deviceName) {
137 DPRINT1("AddDevice: no memory to alloc for deviceName(0x%x)\n", nameLength);
138 status = STATUS_INSUFFICIENT_RESOURCES;
139 goto End;
140 }
141
142 status = IoGetDeviceProperty (PhysicalDeviceObject,
143 DevicePropertyPhysicalDeviceObjectName,
144 nameLength,
145 deviceName,
146 &nameLength);
147
148 if (!NT_SUCCESS (status)) {
149
150 DPRINT1("AddDevice:IoGDP(2) failed (0x%x)", status);
151 goto End;
152 }
153
154 DPRINT("AddDevice: %p to %p->%p (%ws) \n",
155 deviceObject,
156 deviceData->NextLowerDriver,
157 PhysicalDeviceObject,
158 deviceName);
159
160 #endif
161
162 //
163 // We are done with initializing, so let's indicate that and return.
164 // This should be the final step in the AddDevice process.
165 //
166 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
167
168 End:
169 if (deviceName){
170 ExFreePoolWithTag(deviceName, 'IPCA');
171 }
172 if (!NT_SUCCESS(status) && deviceObject){
173 if (deviceData && deviceData->NextLowerDriver){
174 IoDetachDevice (deviceData->NextLowerDriver);
175 }
176 IoDeleteDevice (deviceObject);
177 }
178 return status;
179
180 }
181
182 NTSTATUS
183 NTAPI
184 ACPIDispatchCreateClose(
185 IN PDEVICE_OBJECT DeviceObject,
186 IN PIRP Irp)
187 {
188 Irp->IoStatus.Status = STATUS_SUCCESS;
189 Irp->IoStatus.Information = 0;
190
191 IoCompleteRequest(Irp, IO_NO_INCREMENT);
192
193 return STATUS_SUCCESS;
194 }
195
196 VOID
197 NTAPI
198 ButtonWaitThread(PVOID Context)
199 {
200 PIRP Irp = Context;
201 int result;
202 struct acpi_bus_event event;
203 ULONG ButtonEvent;
204
205 while (ACPI_SUCCESS(result = acpi_bus_receive_event(&event)) &&
206 event.type != ACPI_BUTTON_NOTIFY_STATUS);
207
208 if (!ACPI_SUCCESS(result))
209 {
210 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
211 }
212 else
213 {
214 if (strstr(event.bus_id, "PWRF"))
215 ButtonEvent = SYS_BUTTON_POWER;
216 else if (strstr(event.bus_id, "SLPF"))
217 ButtonEvent = SYS_BUTTON_SLEEP;
218 else
219 ButtonEvent = 0;
220
221 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &ButtonEvent, sizeof(ButtonEvent));
222 Irp->IoStatus.Status = STATUS_SUCCESS;
223 Irp->IoStatus.Information = sizeof(ULONG);
224 }
225
226 IoCompleteRequest(Irp, IO_NO_INCREMENT);
227 }
228
229
230 NTSTATUS
231 NTAPI
232 ACPIDispatchDeviceControl(
233 IN PDEVICE_OBJECT DeviceObject,
234 IN PIRP Irp)
235 {
236 PIO_STACK_LOCATION irpStack;
237 NTSTATUS status = STATUS_NOT_SUPPORTED;
238 PCOMMON_DEVICE_DATA commonData;
239 ULONG Caps = 0;
240 HANDLE ThreadHandle;
241
242 PAGED_CODE ();
243
244 irpStack = IoGetCurrentIrpStackLocation (Irp);
245 ASSERT (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction);
246
247 commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
248
249 Irp->IoStatus.Information = 0;
250
251 if (!commonData->IsFDO)
252 {
253 switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
254 {
255 case IOCTL_ACPI_EVAL_METHOD:
256 status = Bus_PDO_EvalMethod((PPDO_DEVICE_DATA)commonData,
257 Irp);
258 break;
259
260 case IOCTL_GET_SYS_BUTTON_CAPS:
261 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
262 {
263 status = STATUS_BUFFER_TOO_SMALL;
264 break;
265 }
266
267 if (wcsstr(((PPDO_DEVICE_DATA)commonData)->HardwareIDs, L"PNP0C0D"))
268 {
269 DPRINT1("Lid button reported to power manager\n");
270 Caps |= SYS_BUTTON_LID;
271 }
272 else if (((PPDO_DEVICE_DATA)commonData)->AcpiHandle == NULL)
273 {
274 /* We have to return both at the same time because since we
275 * have a NULL handle we are the fixed feature DO and we will
276 * only be called once (not once per device)
277 */
278 if (power_button)
279 {
280 DPRINT1("Fixed power button reported to power manager\n");
281 Caps |= SYS_BUTTON_POWER;
282 }
283 if (sleep_button)
284 {
285 DPRINT1("Fixed sleep button reported to power manager\n");
286 Caps |= SYS_BUTTON_SLEEP;
287 }
288 }
289 else if (wcsstr(((PPDO_DEVICE_DATA)commonData)->HardwareIDs, L"PNP0C0C"))
290 {
291 DPRINT1("Control method power button reported to power manager\n");
292 Caps |= SYS_BUTTON_POWER;
293 }
294 else if (wcsstr(((PPDO_DEVICE_DATA)commonData)->HardwareIDs, L"PNP0C0E"))
295 {
296 DPRINT1("Control method sleep reported to power manager\n");
297 Caps |= SYS_BUTTON_SLEEP;
298 }
299 else
300 {
301 DPRINT1("IOCTL_GET_SYS_BUTTON_CAPS sent to a non-button device\n");
302 status = STATUS_INVALID_PARAMETER;
303 }
304
305 if (Caps != 0)
306 {
307 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &Caps, sizeof(Caps));
308 Irp->IoStatus.Information = sizeof(Caps);
309 status = STATUS_SUCCESS;
310 }
311 break;
312
313 case IOCTL_GET_SYS_BUTTON_EVENT:
314 PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0, ButtonWaitThread, Irp);
315 ZwClose(ThreadHandle);
316
317 status = STATUS_PENDING;
318 break;
319
320 default:
321 DPRINT1("Unsupported IOCTL: %x\n", irpStack->Parameters.DeviceIoControl.IoControlCode);
322 break;
323 }
324 }
325 else
326 DPRINT1("IOCTL sent to the ACPI FDO! Kill the caller!\n");
327
328 if (status != STATUS_PENDING)
329 {
330 Irp->IoStatus.Status = status;
331 IoCompleteRequest(Irp, IO_NO_INCREMENT);
332 }
333 else
334 IoMarkIrpPending(Irp);
335
336 return status;
337 }
338
339 static
340 NTSTATUS
341 AcpiRegOpenKey(IN HANDLE ParentKeyHandle,
342 IN LPCWSTR KeyName,
343 IN ACCESS_MASK DesiredAccess,
344 OUT HANDLE KeyHandle)
345 {
346 OBJECT_ATTRIBUTES ObjectAttributes;
347 UNICODE_STRING Name;
348
349 RtlInitUnicodeString(&Name, KeyName);
350
351 InitializeObjectAttributes(&ObjectAttributes,
352 &Name,
353 OBJ_CASE_INSENSITIVE,
354 ParentKeyHandle,
355 NULL);
356
357 return ZwOpenKey(KeyHandle,
358 DesiredAccess,
359 &ObjectAttributes);
360 }
361
362 static
363 NTSTATUS
364 AcpiRegQueryValue(IN HANDLE KeyHandle,
365 IN LPWSTR ValueName,
366 OUT PULONG Type OPTIONAL,
367 OUT PVOID Data OPTIONAL,
368 IN OUT PULONG DataLength OPTIONAL)
369 {
370 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
371 UNICODE_STRING Name;
372 ULONG BufferLength = 0;
373 NTSTATUS Status;
374
375 RtlInitUnicodeString(&Name,
376 ValueName);
377
378 if (DataLength != NULL)
379 BufferLength = *DataLength;
380
381 BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
382
383 /* Allocate memory for the value */
384 ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferLength, 'IPCA');
385 if (ValueInfo == NULL)
386 return STATUS_NO_MEMORY;
387
388 /* Query the value */
389 Status = ZwQueryValueKey(KeyHandle,
390 &Name,
391 KeyValuePartialInformation,
392 ValueInfo,
393 BufferLength,
394 &BufferLength);
395 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW))
396 {
397 if (Type != NULL)
398 *Type = ValueInfo->Type;
399
400 if (DataLength != NULL)
401 *DataLength = ValueInfo->DataLength;
402 }
403
404 /* Check if the caller wanted data back, and we got it */
405 if ((NT_SUCCESS(Status)) && (Data != NULL))
406 {
407 /* Copy it */
408 RtlMoveMemory(Data,
409 ValueInfo->Data,
410 ValueInfo->DataLength);
411
412 /* if the type is REG_SZ and data is not 0-terminated
413 * and there is enough space in the buffer NT appends a \0 */
414 if (((ValueInfo->Type == REG_SZ) || (ValueInfo->Type == REG_EXPAND_SZ) || (ValueInfo->Type == REG_MULTI_SZ)) &&
415 (ValueInfo->DataLength <= *DataLength - sizeof(WCHAR)))
416 {
417 WCHAR *ptr = (WCHAR *)((ULONG_PTR)Data + ValueInfo->DataLength);
418 if ((ptr > (WCHAR *)Data) && ptr[-1])
419 *ptr = 0;
420 }
421 }
422
423 /* Free the memory and return status */
424 ExFreePoolWithTag(ValueInfo, 'IPCA');
425
426 if ((Data == NULL) && (Status == STATUS_BUFFER_OVERFLOW))
427 Status = STATUS_SUCCESS;
428
429 return Status;
430 }
431
432 static
433 NTSTATUS
434 GetProcessorInformation(VOID)
435 {
436 LPWSTR ProcessorIdentifier = NULL;
437 LPWSTR ProcessorVendorIdentifier = NULL;
438 LPWSTR HardwareIdsBuffer = NULL;
439 HANDLE ProcessorHandle = NULL;
440 ULONG Length, Level1Length = 0, Level2Length = 0, Level3Length = 0;
441 ULONG HardwareIdsLength = 0;
442 ULONG i;
443 PWCHAR Ptr;
444 NTSTATUS Status;
445
446 DPRINT1("GetProcessorInformation()\n");
447
448 Status = AcpiRegOpenKey(NULL,
449 L"\\Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor\\0",
450 KEY_READ,
451 &ProcessorHandle);
452 if (!NT_SUCCESS(Status))
453 goto done;
454
455 AcpiRegQueryValue(ProcessorHandle,
456 L"Identifier",
457 NULL,
458 NULL,
459 &Length);
460
461 if (Length != 0)
462 {
463 ProcessorIdentifier = ExAllocatePoolWithTag(PagedPool, Length, 'IPCA');
464 if (ProcessorIdentifier == NULL)
465 {
466 Status = STATUS_INSUFFICIENT_RESOURCES;
467 goto done;
468 }
469
470 Status = AcpiRegQueryValue(ProcessorHandle,
471 L"Identifier",
472 NULL,
473 ProcessorIdentifier,
474 &Length);
475 if (!NT_SUCCESS(Status))
476 goto done;
477
478 Length = 0;
479 }
480
481 AcpiRegQueryValue(ProcessorHandle,
482 L"ProcessorNameString",
483 NULL,
484 NULL,
485 &Length);
486
487 if (Length != 0)
488 {
489 ProcessorNameString = ExAllocatePoolWithTag(PagedPool, Length, 'IPCA');
490 if (ProcessorNameString == NULL)
491 {
492 Status = STATUS_INSUFFICIENT_RESOURCES;
493 goto done;
494 }
495
496 Status = AcpiRegQueryValue(ProcessorHandle,
497 L"ProcessorNameString",
498 NULL,
499 ProcessorNameString,
500 &Length);
501 if (!NT_SUCCESS(Status))
502 goto done;
503
504 Length = 0;
505 }
506
507 AcpiRegQueryValue(ProcessorHandle,
508 L"VendorIdentifier",
509 NULL,
510 NULL,
511 &Length);
512
513 if (Length != 0)
514 {
515 ProcessorVendorIdentifier = ExAllocatePoolWithTag(PagedPool, Length, 'IPCA');
516 if (ProcessorVendorIdentifier == NULL)
517 {
518 Status = STATUS_INSUFFICIENT_RESOURCES;
519 goto done;
520 }
521
522 Status = AcpiRegQueryValue(ProcessorHandle,
523 L"VendorIdentifier",
524 NULL,
525 ProcessorVendorIdentifier,
526 &Length);
527 if (!NT_SUCCESS(Status))
528 goto done;
529
530 Length = 0;
531 }
532
533 for (i = 0; i < wcslen(ProcessorIdentifier); i++)
534 {
535 if (ProcessorIdentifier[i] == L' ')
536 ProcessorIdentifier[i] = L'_';
537 }
538
539 Ptr = wcsstr(ProcessorIdentifier, L"Stepping");
540 if (Ptr != NULL)
541 {
542 Ptr--;
543 Level1Length = (ULONG)(Ptr - ProcessorIdentifier);
544 }
545
546 Ptr = wcsstr(ProcessorIdentifier, L"Model");
547 if (Ptr != NULL)
548 {
549 Ptr--;
550 Level2Length = (ULONG)(Ptr - ProcessorIdentifier);
551 }
552
553 Ptr = wcsstr(ProcessorIdentifier, L"Family");
554 if (Ptr != NULL)
555 {
556 Ptr--;
557 Level3Length = (ULONG)(Ptr - ProcessorIdentifier);
558 }
559
560 HardwareIdsLength = 5 + wcslen(ProcessorVendorIdentifier) + 3 + Level1Length + 1 +
561 1 + wcslen(ProcessorVendorIdentifier) + 3 + Level1Length + 1 +
562 5 + wcslen(ProcessorVendorIdentifier) + 3 + Level2Length + 1 +
563 1 + wcslen(ProcessorVendorIdentifier) + 3 + Level2Length + 1 +
564 5 + wcslen(ProcessorVendorIdentifier) + 3 + Level3Length + 1 +
565 1 + wcslen(ProcessorVendorIdentifier) + 3 + Level3Length + 1 +
566 2;
567
568 HardwareIdsBuffer = ExAllocatePoolWithTag(PagedPool, HardwareIdsLength * sizeof(WCHAR), 'IPCA');
569 if (HardwareIdsBuffer == NULL)
570 {
571 Status = STATUS_INSUFFICIENT_RESOURCES;
572 goto done;
573 }
574
575 Length = 0;
576 Length += swprintf(&HardwareIdsBuffer[Length], L"ACPI\\%s_-_%.*s", ProcessorVendorIdentifier, Level1Length, ProcessorIdentifier);
577 Length++;
578
579 Length += swprintf(&HardwareIdsBuffer[Length], L"*%s_-_%.*s", ProcessorVendorIdentifier, Level1Length, ProcessorIdentifier);
580 Length++;
581
582 Length += swprintf(&HardwareIdsBuffer[Length], L"ACPI\\%s_-_%.*s", ProcessorVendorIdentifier, Level2Length, ProcessorIdentifier);
583 Length++;
584
585 Length += swprintf(&HardwareIdsBuffer[Length], L"*%s_-_%.*s", ProcessorVendorIdentifier, Level2Length, ProcessorIdentifier);
586 Length++;
587
588 Length += swprintf(&HardwareIdsBuffer[Length], L"ACPI\\%s_-_%.*s", ProcessorVendorIdentifier, Level3Length, ProcessorIdentifier);
589 Length++;
590
591 Length += swprintf(&HardwareIdsBuffer[Length], L"*%s_-_%.*s", ProcessorVendorIdentifier, Level3Length, ProcessorIdentifier);
592 Length++;
593 HardwareIdsBuffer[Length] = UNICODE_NULL;
594
595 ProcessorHardwareIds.Length = HardwareIdsLength * sizeof(WCHAR);
596 ProcessorHardwareIds.MaximumLength = ProcessorHardwareIds.Length;
597 ProcessorHardwareIds.Buffer = HardwareIdsBuffer;
598
599 done:
600 if (ProcessorHandle != NULL)
601 ZwClose(ProcessorHandle);
602
603 if (ProcessorIdentifier != NULL)
604 ExFreePoolWithTag(ProcessorIdentifier, 'IPCA');
605
606 if (ProcessorVendorIdentifier != NULL)
607 ExFreePoolWithTag(ProcessorVendorIdentifier, 'IPCA');
608
609 if (!NT_SUCCESS(Status))
610 {
611 if (HardwareIdsBuffer != NULL)
612 ExFreePoolWithTag(HardwareIdsBuffer, 'IPCA');
613 }
614
615 return Status;
616 }
617
618 NTSTATUS
619 NTAPI
620 DriverEntry (
621 PDRIVER_OBJECT DriverObject,
622 PUNICODE_STRING RegistryPath
623 )
624 {
625 DPRINT("Driver Entry \n");
626
627 GetProcessorInformation();
628
629 //
630 // Set entry points into the driver
631 //
632 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ACPIDispatchDeviceControl;
633 DriverObject->MajorFunction [IRP_MJ_PNP] = Bus_PnP;
634 DriverObject->MajorFunction [IRP_MJ_POWER] = Bus_Power;
635 DriverObject->MajorFunction [IRP_MJ_CREATE] = ACPIDispatchCreateClose;
636 DriverObject->MajorFunction [IRP_MJ_CLOSE] = ACPIDispatchCreateClose;
637
638 DriverObject->DriverExtension->AddDevice = Bus_AddDevice;
639
640 return STATUS_SUCCESS;
641 }