2 * PROJECT: ReactOS Composite Battery Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/drivers/bus/acpi/compbatt/compbatt.c
5 * PURPOSE: Main Initialization Code and IRP Handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 /* GLOBALS ********************************************************************/
17 /* FUNCTIONS ******************************************************************/
21 CompBattOpenClose(IN PDEVICE_OBJECT DeviceObject
,
25 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: ENTERING OpenClose\n");
27 /* Complete the IRP with success */
28 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
29 Irp
->IoStatus
.Information
= 0;
30 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
33 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: Exiting OpenClose\n");
34 return STATUS_SUCCESS
;
39 CompBattSystemControl(IN PDEVICE_OBJECT DeviceObject
,
42 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
45 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING System Control\n");
47 /* Are we attached yet? */
48 if (DeviceExtension
->AttachedDevice
)
50 /* Send it up the stack */
51 IoSkipCurrentIrpStackLocation(Irp
);
52 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
56 /* We don't support WMI */
57 Status
= STATUS_NOT_SUPPORTED
;
58 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
59 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
68 CompBattMonitorIrpComplete(IN PDEVICE_OBJECT DeviceObject
,
73 return STATUS_NOT_IMPLEMENTED
;
78 CompBattMonitorIrpCompleteWorker(IN PCOMPBATT_BATTERY_DATA BatteryData
)
81 return STATUS_NOT_IMPLEMENTED
;
86 CompBattRecalculateTag(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
88 PCOMPBATT_BATTERY_DATA BatteryData
;
90 PLIST_ENTRY ListHead
, NextEntry
;
91 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: ENTERING CompBattRecalculateTag\n");
93 /* Loop the battery list */
94 ExAcquireFastMutex(&DeviceExtension
->Lock
);
95 ListHead
= &DeviceExtension
->BatteryList
;
96 NextEntry
= ListHead
->Flink
;
97 while (NextEntry
!= ListHead
)
99 /* Get the battery information and check if it has a tag */
100 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
101 if (BatteryData
->Flags
& COMPBATT_TAG_ASSIGNED
)
103 /* Generate the next tag and exit */
104 Tag
= DeviceExtension
->NextTag
;
105 DeviceExtension
->Flags
|= COMPBATT_TAG_ASSIGNED
;
106 DeviceExtension
->Tag
= Tag
;
107 DeviceExtension
->NextTag
= Tag
+ 1;
111 /* No tag for this device extension, clear it */
112 DeviceExtension
->Tag
= 0;
113 NextEntry
= NextEntry
->Flink
;
117 ExReleaseFastMutex(&DeviceExtension
->Lock
);
118 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: EXITING CompBattRecalculateTag\n");
123 CompBattIoctl(IN PDEVICE_OBJECT DeviceObject
,
126 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
128 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING Ioctl\n");
130 /* Let the class driver handle it */
131 Status
= BatteryClassIoctl(DeviceExtension
->ClassData
, Irp
);
132 if (Status
== STATUS_NOT_SUPPORTED
)
134 /* It failed, try the next driver up the stack */
135 Irp
->IoStatus
.Status
= Status
;
136 IoSkipCurrentIrpStackLocation(Irp
);
137 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
141 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING Ioctl\n");
147 CompBattQueryTag(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
,
152 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: ENTERING QueryTag\n");
154 /* Was a tag assigned? */
155 if (!(DeviceExtension
->Flags
& COMPBATT_TAG_ASSIGNED
))
158 CompBattRecalculateTag(DeviceExtension
);
161 /* Do we have a tag now? */
162 if ((DeviceExtension
->Flags
& COMPBATT_TAG_ASSIGNED
) && (DeviceExtension
->Tag
))
165 *Tag
= DeviceExtension
->Tag
;
166 Status
= STATUS_SUCCESS
;
172 Status
= STATUS_NO_SUCH_DEVICE
;
176 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: EXITING QueryTag\n");
182 CompBattDisableStatusNotify(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
184 PCOMPBATT_BATTERY_DATA BatteryData
;
185 PLIST_ENTRY ListHead
, NextEntry
;
186 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: ENTERING DisableStatusNotify\n");
188 /* Loop the battery list */
189 ExAcquireFastMutex(&DeviceExtension
->Lock
);
190 ListHead
= &DeviceExtension
->BatteryList
;
191 NextEntry
= ListHead
->Flink
;
192 while (NextEntry
!= ListHead
)
194 /* Get the battery information and clear capacity data */
195 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
196 BatteryData
->WaitStatus
.LowCapacity
= 0;
197 BatteryData
->WaitStatus
.HighCapacity
= 0x7FFFFFFF;
198 NextEntry
= NextEntry
->Flink
;
202 ExReleaseFastMutex(&DeviceExtension
->Lock
);
203 if (CompBattDebug
& 0x100) DbgPrint("CompBatt: EXITING DisableStatusNotify\n");
204 return STATUS_SUCCESS
;
209 CompBattSetStatusNotify(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
,
211 IN PBATTERY_NOTIFY BatteryNotify
)
214 return STATUS_NOT_IMPLEMENTED
;
219 CompBattQueryStatus(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
,
221 IN PBATTERY_STATUS BatteryStatus
)
224 return STATUS_NOT_IMPLEMENTED
;
229 CompBattGetBatteryInformation(OUT PBATTERY_INFORMATION BatteryInfo
,
230 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
232 NTSTATUS Status
= STATUS_SUCCESS
;
233 BATTERY_QUERY_INFORMATION InputBuffer
;
234 PCOMPBATT_BATTERY_DATA BatteryData
;
235 PLIST_ENTRY ListHead
, NextEntry
;
236 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING GetBatteryInformation\n");
239 BatteryInfo
->DefaultAlert1
= 0;
240 BatteryInfo
->DefaultAlert2
= 0;
241 BatteryInfo
->CriticalBias
= 0;
243 /* Loop the battery list */
244 ExAcquireFastMutex(&DeviceExtension
->Lock
);
245 ListHead
= &DeviceExtension
->BatteryList
;
246 NextEntry
= ListHead
->Flink
;
247 while (NextEntry
!= ListHead
)
249 /* Try to acquire the remove lock */
250 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
251 if (NT_SUCCESS(IoAcquireRemoveLock(&BatteryData
->RemoveLock
, 0)))
253 /* Now release the device lock since the battery can't go away */
254 ExReleaseFastMutex(&DeviceExtension
->Lock
);
256 /* Build the query */
257 InputBuffer
.BatteryTag
= BatteryData
->Tag
;
258 InputBuffer
.InformationLevel
= BatteryInformation
;
259 InputBuffer
.AtRate
= 0;
261 /* Make sure the battery has a tag */
262 if (BatteryData
->Tag
)
264 /* Do we already have the data? */
265 if (!(BatteryData
->Flags
& COMPBATT_BATTERY_INFORMATION_PRESENT
))
267 /* Send the IOCTL to query the information */
268 RtlZeroMemory(&BatteryData
->BatteryInformation
,
269 sizeof(BatteryData
->BatteryInformation
));
270 Status
= BatteryIoctl(IOCTL_BATTERY_QUERY_INFORMATION
,
271 BatteryData
->DeviceObject
,
274 &BatteryData
->BatteryInformation
,
275 sizeof(BatteryData
->BatteryInformation
),
277 if (!NT_SUCCESS(Status
))
279 /* Fail if the query had a problem */
280 if (Status
== STATUS_DEVICE_REMOVED
) Status
= STATUS_NO_SUCH_DEVICE
;
281 ExAcquireFastMutex(&DeviceExtension
->Lock
);
282 IoReleaseRemoveLock(&BatteryData
->RemoveLock
, 0);
286 /* Next time we can use the static copy */
287 BatteryData
->Flags
|= COMPBATT_BATTERY_INFORMATION_PRESENT
;
288 if (CompBattDebug
& 2)
289 DbgPrint("CompBattGetBatteryInformation: Read individual BATTERY_INFORMATION\n"
290 "-------- Capabilities = %x\n-------- Technology = %x\n"
291 "-------- Chemistry[4] = %x\n-------- DesignedCapacity = %x\n"
292 "-------- FullChargedCapacity = %x\n-------- DefaultAlert1 = %x\n"
293 "-------- DefaultAlert2 = %x\n-------- CriticalBias = %x\n"
294 "-------- CycleCount = %x\n",
295 BatteryData
->BatteryInformation
.Capabilities
,
296 BatteryData
->BatteryInformation
.Technology
,
297 BatteryData
->BatteryInformation
.Chemistry
,
298 BatteryData
->BatteryInformation
.DesignedCapacity
,
299 BatteryData
->BatteryInformation
.FullChargedCapacity
,
300 BatteryData
->BatteryInformation
.DefaultAlert1
,
301 BatteryData
->BatteryInformation
.DefaultAlert2
,
302 BatteryData
->BatteryInformation
.CriticalBias
,
303 BatteryData
->BatteryInformation
.CycleCount
);
306 /* Combine capabilities */
307 BatteryInfo
->Capabilities
|= BatteryData
->BatteryInformation
.Capabilities
;
309 /* Add-on capacity */
310 if (BatteryData
->BatteryInformation
.DesignedCapacity
!= BATTERY_UNKNOWN_CAPACITY
)
312 BatteryInfo
->DesignedCapacity
+= BatteryData
->BatteryInformation
.DesignedCapacity
;
315 /* Add on fully charged capacity */
316 if (BatteryData
->BatteryInformation
.FullChargedCapacity
!= BATTERY_UNKNOWN_CAPACITY
)
318 BatteryInfo
->FullChargedCapacity
+= BatteryData
->BatteryInformation
.FullChargedCapacity
;
321 /* Choose the highest alert */
322 BatteryInfo
->DefaultAlert1
= max(BatteryInfo
->DefaultAlert1
,
323 BatteryData
->BatteryInformation
.DefaultAlert1
);
325 /* Choose the highest alert */
326 BatteryInfo
->DefaultAlert2
= max(BatteryInfo
->DefaultAlert2
,
327 BatteryData
->BatteryInformation
.DefaultAlert2
);
329 /* Choose the highest critical bias */
330 BatteryInfo
->CriticalBias
= max(BatteryInfo
->CriticalBias
,
331 BatteryData
->BatteryInformation
.CriticalBias
);
334 /* Re-acquire the device extension lock and release the remove lock */
335 ExAcquireFastMutex(&DeviceExtension
->Lock
);
336 IoReleaseRemoveLock(&BatteryData
->RemoveLock
, 0);
340 NextEntry
= NextEntry
->Flink
;
343 /* We are done with the list, check if the information was queried okay */
344 ExReleaseFastMutex(&DeviceExtension
->Lock
);
345 if (NT_SUCCESS(Status
))
347 /* If there's no fully charged capacity, use the design capacity */
348 if (!BatteryInfo
->FullChargedCapacity
)
350 BatteryInfo
->FullChargedCapacity
= BatteryInfo
->DesignedCapacity
;
353 /* Print out final combined data */
354 if (CompBattDebug
& 2)
355 DbgPrint("CompBattGetBatteryInformation: Returning BATTERY_INFORMATION\n"
356 "-------- Capabilities = %x\n-------- Technology = %x\n"
357 "-------- Chemistry[4] = %x\n-------- DesignedCapacity = %x\n"
358 "-------- FullChargedCapacity = %x\n-------- DefaultAlert1 = %x\n"
359 "-------- DefaultAlert2 = %x\n-------- CriticalBias = %x\n"
360 "-------- CycleCount = %x\n",
361 BatteryInfo
->Capabilities
,
362 BatteryInfo
->Technology
,
363 BatteryInfo
->Chemistry
,
364 BatteryInfo
->DesignedCapacity
,
365 BatteryInfo
->FullChargedCapacity
,
366 BatteryInfo
->DefaultAlert1
,
367 BatteryInfo
->DefaultAlert2
,
368 BatteryInfo
->CriticalBias
,
369 BatteryInfo
->CycleCount
);
371 /* Copy the data into the device extension */
372 RtlCopyMemory(&DeviceExtension
->BatteryInformation
,
374 sizeof(DeviceExtension
->BatteryInformation
));
375 DeviceExtension
->Flags
|= COMPBATT_BATTERY_INFORMATION_PRESENT
;
379 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING GetBatteryInformation\n");
385 CompBattGetBatteryGranularity(OUT PBATTERY_REPORTING_SCALE ReportingScale
,
386 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
388 NTSTATUS Status
= STATUS_SUCCESS
;
389 BATTERY_QUERY_INFORMATION InputBuffer
;
390 PCOMPBATT_BATTERY_DATA BatteryData
;
391 BATTERY_REPORTING_SCALE BatteryScale
[4];
392 PLIST_ENTRY ListHead
, NextEntry
;
394 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING GetBatteryGranularity\n");
397 ReportingScale
[0].Granularity
= -1;
398 ReportingScale
[1].Granularity
= -1;
399 ReportingScale
[2].Granularity
= -1;
400 ReportingScale
[3].Granularity
= -1;
402 /* Loop the battery list */
403 ExAcquireFastMutex(&DeviceExtension
->Lock
);
404 ListHead
= &DeviceExtension
->BatteryList
;
405 NextEntry
= ListHead
->Flink
;
406 while (NextEntry
!= ListHead
)
408 /* Try to acquire the remove lock */
409 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
410 if (NT_SUCCESS(IoAcquireRemoveLock(&BatteryData
->RemoveLock
, 0)))
412 /* Now release the device lock since the battery can't go away */
413 ExReleaseFastMutex(&DeviceExtension
->Lock
);
415 /* Build the query */
416 InputBuffer
.BatteryTag
= BatteryData
->Tag
;
417 InputBuffer
.InformationLevel
= BatteryGranularityInformation
;
419 /* Make sure the battery has a tag */
420 if (BatteryData
->Tag
)
422 /* Send the IOCTL to query the information */
423 RtlZeroMemory(&BatteryData
->BatteryInformation
,
424 sizeof(BatteryData
->BatteryInformation
));
425 Status
= BatteryIoctl(IOCTL_BATTERY_QUERY_INFORMATION
,
426 BatteryData
->DeviceObject
,
430 sizeof(BatteryScale
),
432 if (!NT_SUCCESS(Status
))
434 /* Fail if the query had a problem */
435 ExAcquireFastMutex(&DeviceExtension
->Lock
);
436 IoReleaseRemoveLock(&BatteryData
->RemoveLock
, 0);
440 /* Loop all 4 scales */
441 for (i
= 0; i
< 4; i
++)
443 /* Check for valid granularity */
444 if (BatteryScale
[i
].Granularity
)
446 /* If it's smaller, use it instead */
447 ReportingScale
[i
].Granularity
= min(BatteryScale
[i
].Granularity
,
448 ReportingScale
[i
].Granularity
);
454 /* Re-acquire the device extension lock and release the remove lock */
455 ExAcquireFastMutex(&DeviceExtension
->Lock
);
456 IoReleaseRemoveLock(&BatteryData
->RemoveLock
, 0);
460 NextEntry
= NextEntry
->Flink
;
464 ExReleaseFastMutex(&DeviceExtension
->Lock
);
465 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING GetBatteryGranularity\n");
466 return STATUS_SUCCESS
;
471 CompBattGetEstimatedTime(OUT PULONG Time
,
472 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
475 return STATUS_NOT_IMPLEMENTED
;
480 CompBattQueryInformation(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
,
482 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel
,
483 IN OPTIONAL LONG AtRate
,
485 IN ULONG BufferLength
,
486 OUT PULONG ReturnedLength
)
488 BATTERY_INFORMATION BatteryInfo
;
489 BATTERY_REPORTING_SCALE BatteryGranularity
[4];
490 PWCHAR BatteryName
= L
"Composite Battery";
491 //BATTERY_MANUFACTURE_DATE Date;
493 PVOID QueryData
= NULL
;
494 ULONG QueryLength
= 0;
495 NTSTATUS Status
= STATUS_SUCCESS
;
497 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING QueryInformation\n");
499 /* Check for valid/correct tag */
500 if ((Tag
!= DeviceExtension
->Tag
) ||
501 (!(DeviceExtension
->Flags
& COMPBATT_TAG_ASSIGNED
)))
503 /* Not right, so fail */
504 return STATUS_NO_SUCH_DEVICE
;
507 /* Check what caller wants */
510 case BatteryInformation
:
512 /* Query combined battery information */
513 RtlZeroMemory(&BatteryInfo
, sizeof(BatteryInfo
));
514 Status
= CompBattGetBatteryInformation(&BatteryInfo
, DeviceExtension
);
515 if (NT_SUCCESS(Status
))
517 /* Return the data if successful */
518 QueryData
= &BatteryInfo
;
519 QueryLength
= sizeof(BatteryInfo
);
523 case BatteryGranularityInformation
:
525 /* Query combined granularity information */
526 RtlZeroMemory(&BatteryGranularity
, sizeof(BatteryGranularity
));
527 Status
= CompBattGetBatteryGranularity(BatteryGranularity
, DeviceExtension
);
528 if (NT_SUCCESS(Status
))
530 /* Return the data if successful */
531 QueryLength
= sizeof(BatteryGranularity
);
532 QueryData
= &BatteryGranularity
;
536 case BatteryEstimatedTime
:
538 /* Query combined time estimate information */
539 RtlZeroMemory(&Time
, sizeof(Time
));
540 Status
= CompBattGetEstimatedTime(&Time
, DeviceExtension
);
541 if (NT_SUCCESS(Status
))
543 /* Return the data if successful */
544 QueryLength
= sizeof(Time
);
549 case BatteryManufactureName
:
550 case BatteryDeviceName
:
552 /* Return the static buffer */
553 QueryData
= BatteryName
;
554 QueryLength
= sizeof(L
"Composite Battery");
557 case BatteryManufactureDate
:
565 case BatteryTemperature
:
566 case BatteryUniqueID
:
571 QueryLength
= sizeof(Dummy
);
575 /* Everything else is unknown */
576 Status
= STATUS_INVALID_PARAMETER
;
580 /* Return the required length and check if the caller supplied enough */
581 *ReturnedLength
= QueryLength
;
582 if (BufferLength
< QueryLength
) Status
= STATUS_BUFFER_TOO_SMALL
;
584 /* Copy the data if there's enough space and it exists */
585 if ((NT_SUCCESS(Status
)) && (QueryData
)) RtlCopyMemory(Buffer
, QueryData
, QueryLength
);
587 /* Return function result */
588 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING QueryInformation\n");
594 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
595 IN PUNICODE_STRING RegistryPath
)
597 /* Register add device routine */
598 DriverObject
->DriverExtension
->AddDevice
= CompBattAddDevice
;
600 /* Register other handlers */
601 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = CompBattOpenClose
;
602 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = CompBattOpenClose
;
603 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = CompBattIoctl
;
604 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = CompBattPowerDispatch
;
605 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = CompBattSystemControl
;
606 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = CompBattPnpDispatch
;
607 return STATUS_SUCCESS
;