xref: /reactos/drivers/bus/acpi/cmbatt/cmexec.c (revision 359e73d0)
1 /*
2  * PROJECT:         ReactOS ACPI-Compliant Control Method Battery
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            boot/drivers/bus/acpi/cmbatt/cmexec.c
5  * PURPOSE:         ACPI Method Execution/Evaluation Glue
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "cmbatt.h"
12 
13 #include <acpiioct.h>
14 #include <debug.h>
15 
16 typedef struct
17 {
18     LPSTR Name;
19     BOOLEAN IsString;
20     PVOID Data;
21 } ACPI_PACKAGE_FIELD, *PACPI_PACKAGE_FIELD;
22 
23 /* FUNCTIONS ******************************************************************/
24 
25 NTSTATUS
26 NTAPI
GetDwordElement(IN PACPI_METHOD_ARGUMENT Argument,OUT PULONG Value)27 GetDwordElement(IN PACPI_METHOD_ARGUMENT Argument,
28                 OUT PULONG Value)
29 {
30     NTSTATUS Status;
31 
32     /* Must have an integer */
33     if (Argument->Type != ACPI_METHOD_ARGUMENT_INTEGER)
34     {
35         /* Not an integer, fail */
36         Status = STATUS_ACPI_INVALID_DATA;
37         if (CmBattDebug & 0x4C)
38             DbgPrint("GetDwordElement: Object contained wrong data type - %d\n",
39                      Argument->Type);
40     }
41     else
42     {
43         /* Read the integer value */
44         *Value = Argument->Argument;
45         Status = STATUS_SUCCESS;
46     }
47 
48     /* Return status */
49     return Status;
50 }
51 
52 NTSTATUS
53 NTAPI
GetStringElement(IN PACPI_METHOD_ARGUMENT Argument,OUT PCHAR Value)54 GetStringElement(IN PACPI_METHOD_ARGUMENT Argument,
55                  OUT PCHAR Value)
56 {
57     NTSTATUS Status;
58 
59     /* Must have a string of buffer */
60     if ((Argument->Type == ACPI_METHOD_ARGUMENT_STRING) ||
61         (Argument->Type == ACPI_METHOD_ARGUMENT_BUFFER))
62     {
63         /* String must be less than 256 characters */
64         if (Argument->DataLength < 256)
65         {
66             /* Copy the buffer */
67             RtlCopyMemory(Value, Argument->Data, Argument->DataLength);
68             Status = STATUS_SUCCESS;
69         }
70         else
71         {
72             /* The buffer is too small (the string is too large) */
73             Status = STATUS_BUFFER_TOO_SMALL;
74             if (CmBattDebug & 0x4C)
75                 DbgPrint("GetStringElement: return buffer not big enough - %d\n", Argument->DataLength);
76         }
77     }
78     else
79     {
80         /* Not valid string data */
81         Status = STATUS_ACPI_INVALID_DATA;
82         if (CmBattDebug & 0x4C)
83             DbgPrint("GetStringElement: Object contained wrong data type - %d\n", Argument->Type);
84     }
85 
86     /* Return the status */
87     return Status;
88 }
89 
90 NTSTATUS
91 NTAPI
CmBattSendDownStreamIrp(IN PDEVICE_OBJECT DeviceObject,IN ULONG IoControlCode,IN PVOID InputBuffer,IN ULONG InputBufferLength,IN PACPI_EVAL_OUTPUT_BUFFER OutputBuffer,IN ULONG OutputBufferLength)92 CmBattSendDownStreamIrp(IN PDEVICE_OBJECT DeviceObject,
93                         IN ULONG IoControlCode,
94                         IN PVOID InputBuffer,
95                         IN ULONG InputBufferLength,
96                         IN PACPI_EVAL_OUTPUT_BUFFER OutputBuffer,
97                         IN ULONG OutputBufferLength)
98 {
99     PIRP Irp;
100     NTSTATUS Status;
101     KEVENT Event;
102     IO_STATUS_BLOCK IoStatusBlock;
103     PAGED_CODE();
104 
105     /* Initialize our wait event */
106     KeInitializeEvent(&Event, SynchronizationEvent, 0);
107 
108     /* Allocate the IRP */
109     Irp = IoBuildDeviceIoControlRequest(IoControlCode,
110                                         DeviceObject,
111                                         InputBuffer,
112                                         InputBufferLength,
113                                         OutputBuffer,
114                                         OutputBufferLength,
115                                         0,
116                                         &Event,
117                                         &IoStatusBlock);
118     if (!Irp)
119     {
120         /* No IRP, fail */
121         if (CmBattDebug & 0x4C)
122             DbgPrint("CmBattSendDownStreamIrp: Failed to allocate Irp\n");
123         return STATUS_INSUFFICIENT_RESOURCES;
124     }
125 
126     /* Call ACPI */
127     if (CmBattDebug & 0x40)
128         DbgPrint("CmBattSendDownStreamIrp: Irp %x [Tid] %x\n",
129                  Irp, KeGetCurrentThread());
130     Status = IoCallDriver(DeviceObject, Irp);
131     if (Status == STATUS_PENDING)
132     {
133         /* Wait for completion */
134         KeWaitForSingleObject(&Event,
135                               Executive,
136                               KernelMode,
137                               FALSE,
138                               NULL);
139         Status = Irp->IoStatus.Status;
140     }
141 
142     /* Check if caller wanted output */
143     if (OutputBuffer)
144     {
145         /* Make sure it's valid ACPI output buffer */
146         if ((OutputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) ||
147             !(OutputBuffer->Count))
148         {
149             /* It isn't, so set failure code */
150             Status = STATUS_ACPI_INVALID_DATA;
151         }
152     }
153 
154     /* Return status */
155     if (CmBattDebug & 0x40)
156         DbgPrint("CmBattSendDownStreamIrp: Irp %x completed %x! [Tid] %x\n",
157                  Irp, Status, KeGetCurrentThread());
158     return Status;
159 }
160 
161 static
162 NTSTATUS
CmBattCallAcpiPackage(_In_ LPCSTR FunctionName,_In_ PCMBATT_DEVICE_EXTENSION DeviceExtension,_In_ ULONG PackageName,_In_ ULONG OutputBufferSize,_In_ PACPI_PACKAGE_FIELD PackageFields,_In_ ULONG PackageFieldCount)163 CmBattCallAcpiPackage(
164     _In_ LPCSTR FunctionName,
165     _In_ PCMBATT_DEVICE_EXTENSION DeviceExtension,
166     _In_ ULONG PackageName,
167     _In_ ULONG OutputBufferSize,
168     _In_ PACPI_PACKAGE_FIELD PackageFields,
169     _In_ ULONG PackageFieldCount)
170 {
171     NTSTATUS Status;
172     PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
173     ACPI_EVAL_INPUT_BUFFER InputBuffer;
174     PACPI_METHOD_ARGUMENT Argument;
175     ULONG i;
176     PAGED_CODE();
177 
178     OutputBuffer = ExAllocatePoolWithTag(PagedPool,
179                                          OutputBufferSize,
180                                          'MtaB');
181     if (!OutputBuffer)
182     {
183         if (CmBattDebug & (CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))
184             DbgPrint("%s: Failed to allocate Buffer\n", FunctionName);
185         return STATUS_INSUFFICIENT_RESOURCES;
186     }
187 
188     /* Initialize to zero */
189     RtlZeroMemory(OutputBuffer, OutputBufferSize);
190 
191     /* Request the ACPI method */
192     *(PULONG)InputBuffer.MethodName = PackageName;
193     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
194 
195     /* Send it to ACPI */
196     Status = CmBattSendDownStreamIrp(DeviceExtension->AttachedDevice,
197                                      IOCTL_ACPI_EVAL_METHOD,
198                                      &InputBuffer,
199                                      sizeof(InputBuffer),
200                                      OutputBuffer,
201                                      OutputBufferSize);
202     if (!NT_SUCCESS(Status))
203     {
204         if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))
205             DbgPrint("%s: Failed 0x%08x method on device %x - Status (0x%x)\n",
206                      FunctionName, PackageName, DeviceExtension->DeviceId, Status);
207         ExFreePoolWithTag(OutputBuffer, 'MtaB');
208         return Status;
209     }
210 
211     /* Check if we got the right number of elements */
212     if (OutputBuffer->Count != PackageFieldCount)
213     {
214         if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))
215             DbgPrint("%s: 0x%08x method returned %d elements (requires %d)\n",
216                      FunctionName, PackageName, OutputBuffer->Count, PackageFieldCount);
217         ExFreePoolWithTag(OutputBuffer, 'MtaB');
218         return STATUS_ACPI_INVALID_DATA;
219     }
220 
221     Argument = OutputBuffer->Argument;
222     for (i = 0; i < PackageFieldCount && NT_SUCCESS(Status); i++)
223     {
224         if (PackageFields[i].IsString)
225             Status = GetStringElement(Argument, PackageFields[i].Data);
226         else
227             Status = GetDwordElement(Argument, PackageFields[i].Data);
228         if (!NT_SUCCESS(Status))
229         {
230             if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))
231                 DbgPrint("%s: Failed to get %s\n", FunctionName, PackageFields[i].Name);
232             break;
233         }
234         Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
235     }
236 
237     ExFreePoolWithTag(OutputBuffer, 'MtaB');
238     return Status;
239 }
240 
241 NTSTATUS
242 NTAPI
CmBattGetPsrData(IN PDEVICE_OBJECT DeviceObject,OUT PULONG PsrData)243 CmBattGetPsrData(IN PDEVICE_OBJECT DeviceObject,
244                  OUT PULONG PsrData)
245 {
246     NTSTATUS Status;
247     ACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
248     ACPI_EVAL_INPUT_BUFFER InputBuffer;
249     PAGED_CODE();
250     if (CmBattDebug & 0x40)
251         DbgPrint("CmBattGetPsrData: Entered with Pdo %x Tid %x\n",
252                  DeviceObject, KeGetCurrentThread());
253 
254     /* Initialize to zero */
255     ASSERT(PsrData != NULL);
256     *PsrData = 0;
257 
258     /* Request the _PSR method */
259     *(PULONG)InputBuffer.MethodName = 'RSP_';
260     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
261 
262     /* Send it to ACPI */
263     Status = CmBattSendDownStreamIrp(DeviceObject,
264                                      IOCTL_ACPI_EVAL_METHOD,
265                                      &InputBuffer,
266                                      sizeof(InputBuffer),
267                                      &OutputBuffer,
268                                      sizeof(OutputBuffer));
269     if (NT_SUCCESS(Status))
270     {
271         /* Read the result */
272         Status = GetDwordElement(OutputBuffer.Argument, PsrData);
273         if (CmBattDebug & 0x440)
274             DbgPrint("CmBattGetPsrData: _PSR method returned %x \n", *PsrData);
275     }
276     else if (CmBattDebug & 0x44C)
277     {
278         /* Failure */
279         DbgPrint("CmBattGetPsrData: Failed _PSR method - Status (0x%x)\n", Status);
280     }
281 
282     /* Return status */
283     return Status;
284 }
285 
286 NTSTATUS
287 NTAPI
CmBattGetStaData(IN PDEVICE_OBJECT DeviceObject,OUT PULONG StaData)288 CmBattGetStaData(IN PDEVICE_OBJECT DeviceObject,
289                  OUT PULONG StaData)
290 {
291     NTSTATUS Status;
292     ACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
293     ACPI_EVAL_INPUT_BUFFER InputBuffer;
294     PAGED_CODE();
295     if (CmBattDebug & 0x40)
296         DbgPrint("CmBattGetStaData: Entered with Pdo %x Tid %x\n",
297                  DeviceObject, KeGetCurrentThread());
298 
299     /* Initialize to zero */
300     ASSERT(StaData != NULL);
301     *StaData = 0;
302 
303     /* Request the _PSR method */
304     *(PULONG)InputBuffer.MethodName = 'ATS_';
305     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
306 
307     /* Send it to ACPI */
308     Status = CmBattSendDownStreamIrp(DeviceObject,
309                                      IOCTL_ACPI_EVAL_METHOD,
310                                      &InputBuffer,
311                                      sizeof(InputBuffer),
312                                      &OutputBuffer,
313                                      sizeof(OutputBuffer));
314     if (NT_SUCCESS(Status))
315     {
316         /* Read the result */
317         Status = GetDwordElement(OutputBuffer.Argument, StaData);
318         if (CmBattDebug & 0x440)
319             DbgPrint("CmBattGetStaData: _STA method returned %x \n", *StaData);
320     }
321     else if (CmBattDebug & 0x44C)
322     {
323         /* Failure */
324         DbgPrint("CmBattGetStaData: Failed _STA method - Status (0x%x)\n", Status);
325         Status = STATUS_NO_SUCH_DEVICE;
326     }
327 
328     /* Return status */
329     return Status;
330 }
331 
332 NTSTATUS
333 NTAPI
CmBattGetUniqueId(IN PDEVICE_OBJECT DeviceObject,OUT PULONG UniqueId)334 CmBattGetUniqueId(IN PDEVICE_OBJECT DeviceObject,
335                   OUT PULONG UniqueId)
336 {
337     NTSTATUS Status;
338     ACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
339     ACPI_EVAL_INPUT_BUFFER InputBuffer;
340     PAGED_CODE();
341     if (CmBattDebug & 0x40)
342         DbgPrint("CmBattGetUniqueId: Entered with Pdo %x Tid %x\n",
343                  DeviceObject, KeGetCurrentThread());
344 
345     /* Initialize to zero */
346     ASSERT(UniqueId != NULL);
347     *UniqueId = 0;
348 
349     /* Request the _PSR method */
350     *(PULONG)InputBuffer.MethodName = 'DIU_';
351     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
352 
353     /* Send it to ACPI */
354     Status = CmBattSendDownStreamIrp(DeviceObject,
355                                      IOCTL_ACPI_EVAL_METHOD,
356                                      &InputBuffer,
357                                      sizeof(InputBuffer),
358                                      &OutputBuffer,
359                                      sizeof(OutputBuffer));
360     if (NT_SUCCESS(Status))
361     {
362         /* Read the result */
363         Status = GetDwordElement(OutputBuffer.Argument, UniqueId);
364         if (CmBattDebug & 0x440)
365             DbgPrint("CmBattGetUniqueId: _UID method returned %x \n", *UniqueId);
366     }
367     else if (CmBattDebug & 0x44C)
368     {
369         /* Failure */
370         DbgPrint("CmBattGetUniqueId: Failed _UID method - Status (0x%x)\n", Status);
371         Status = STATUS_NO_SUCH_DEVICE;
372     }
373 
374     /* Return status */
375     return Status;
376 }
377 
378 NTSTATUS
379 NTAPI
CmBattSetTripPpoint(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,IN ULONG AlarmValue)380 CmBattSetTripPpoint(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
381                     IN ULONG AlarmValue)
382 {
383     NTSTATUS Status;
384     ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER InputBuffer;
385     PAGED_CODE();
386     if (CmBattDebug & 0x440)
387         DbgPrint("CmBattSetTripPpoint: _BTP Alarm Value %x Device %x Tid %x\n",
388                  AlarmValue, DeviceExtension->DeviceId, KeGetCurrentThread);
389 
390     /* Request the _BTP method */
391     *(PULONG)InputBuffer.MethodName = 'PTB_';
392     InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE;
393     InputBuffer.IntegerArgument = AlarmValue;
394 
395     /* Send it to ACPI */
396     Status = CmBattSendDownStreamIrp(DeviceExtension->AttachedDevice,
397                                      IOCTL_ACPI_EVAL_METHOD,
398                                      &InputBuffer,
399                                      sizeof(InputBuffer),
400                                      NULL,
401                                      0);
402     if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0x440))
403         DbgPrint("CmBattSetTripPpoint: Failed _BTP method on device %x - Status (0x%x)\n",
404                  DeviceExtension->DeviceId, Status);
405 
406     /* Return status */
407     return Status;
408 }
409 
410 NTSTATUS
411 NTAPI
CmBattGetBifData(PCMBATT_DEVICE_EXTENSION DeviceExtension,PACPI_BIF_DATA BifData)412 CmBattGetBifData(PCMBATT_DEVICE_EXTENSION DeviceExtension,
413                  PACPI_BIF_DATA BifData)
414 {
415     ACPI_PACKAGE_FIELD BifFields[] = {
416         { "PowerUnit", FALSE, &BifData->PowerUnit },
417         { "DesignCapacity", FALSE, &BifData->DesignCapacity },
418         { "LastFullCapacity", FALSE, &BifData->LastFullCapacity },
419         { "BatteryTechnology", FALSE, &BifData->BatteryTechnology },
420         { "DesignVoltage", FALSE, &BifData->DesignVoltage },
421         { "DesignCapacityWarning", FALSE, &BifData->DesignCapacityWarning },
422         { "DesignCapacityLow", FALSE, &BifData->DesignCapacityLow },
423         { "BatteryCapacityGranularity1", FALSE, &BifData->BatteryCapacityGranularity1 },
424         { "BatteryCapacityGranularity2", FALSE, &BifData->BatteryCapacityGranularity2 },
425         { "ModelNumber", TRUE, &BifData->ModelNumber },
426         { "SerialNumber", TRUE, &BifData->SerialNumber },
427         { "BatteryType", TRUE, &BifData->BatteryType },
428         { "OemInfo", TRUE, &BifData->OemInfo },
429     };
430     PAGED_CODE();
431 
432     if (CmBattDebug & CMBATT_ACPI_ENTRY_EXIT)
433         DbgPrint("CmBattGetBifData: Buffer (0x%x) Device %x Tid %x\n",
434                  BifData, DeviceExtension->DeviceId, KeGetCurrentThread());
435 
436     /* Request the _BIF method */
437     /* Note that _BIF method is deprecated since ACPI 4.0, and replaced by _BIX method.
438      * However, VirtualBox 7.0 only support _BIF method.
439      */
440     return CmBattCallAcpiPackage("CmBattGetBifData",
441                                  DeviceExtension,
442                                  'FIB_',
443                                  512,
444                                  BifFields,
445                                  RTL_NUMBER_OF(BifFields));
446 }
447 
448 NTSTATUS
449 NTAPI
CmBattGetBstData(PCMBATT_DEVICE_EXTENSION DeviceExtension,PACPI_BST_DATA BstData)450 CmBattGetBstData(PCMBATT_DEVICE_EXTENSION DeviceExtension,
451                  PACPI_BST_DATA BstData)
452 {
453     ACPI_PACKAGE_FIELD BstFields[] = {
454         { "State", FALSE, &BstData->State },
455         { "PresentRate", FALSE, &BstData->PresentRate },
456         { "RemainingCapacity", FALSE, &BstData->RemainingCapacity },
457         { "PresentVoltage", FALSE, &BstData->PresentVoltage },
458     };
459     PAGED_CODE();
460 
461     if (CmBattDebug & CMBATT_ACPI_ENTRY_EXIT)
462         DbgPrint("CmBattGetBstData: Buffer (0x%x) Device %x Tid %x\n",
463                  BstData, DeviceExtension->DeviceId, KeGetCurrentThread());
464 
465 
466     return CmBattCallAcpiPackage("CmBattGetBstData",
467                                  DeviceExtension,
468                                  'TSB_',
469                                  512,
470                                  BstFields,
471                                  RTL_NUMBER_OF(BstFields));
472 }
473 
474 /* EOF */
475