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