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/cmbatt.c
5 * PURPOSE: Main Initialization Code and IRP Handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 /* GLOBALS ********************************************************************/
16 PCALLBACK_OBJECT CmBattPowerCallBackObject
;
17 PVOID CmBattPowerCallBackRegistration
;
18 UNICODE_STRING GlobalRegistryPath
;
19 KTIMER CmBattWakeDpcTimerObject
;
20 KDPC CmBattWakeDpcObject
;
21 PDEVICE_OBJECT AcAdapterPdo
;
23 /* FUNCTIONS ******************************************************************/
27 CmBattPowerCallBack(PCMBATT_DEVICE_EXTENSION DeviceExtension
,
36 CmBattWakeDpc(PKDPC Dpc
,
37 PCMBATT_DEVICE_EXTENSION FdoExtension
,
38 PVOID SystemArgument1
,
39 PVOID SystemArgument2
)
46 CmBattNotifyHandler(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
50 PCMBATT_DEVICE_EXTENSION FdoExtension
;
51 PDEVICE_OBJECT DeviceObject
;
53 if (CmBattDebug
& (CMBATT_ACPI_ASSERT
| CMBATT_PNP_INFO
))
54 DbgPrint("CmBattNotifyHandler: CmBatt 0x%08x Type %d Number %d Notify Value: %x\n",
56 DeviceExtension
->FdoType
,
57 DeviceExtension
->DeviceId
,
60 /* Check what kind of notification was received */
63 /* ACPI Specification says is sends a "Bus Check" when power source changes */
66 /* We treat it as possible physical change */
67 DeviceExtension
->ArFlag
|= (CMBATT_AR_NOTIFY
| CMBATT_AR_INSERT
);
68 if ((DeviceExtension
->Tag
) &&
69 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
70 DbgPrint("CmBattNotifyHandler: Received battery #%x insertion, but tag was not invalid.\n",
71 DeviceExtension
->DeviceId
);
74 /* Status of the battery has changed */
75 case ACPI_BATT_NOTIFY_STATUS
:
77 /* All we'll do is notify the class driver */
78 DeviceExtension
->ArFlag
|= CMBATT_AR_NOTIFY
;
81 /* Information on the battery has changed, such as physical presence */
82 case ACPI_DEVICE_CHECK
:
83 case ACPI_BATT_NOTIFY_INFO
:
85 /* Reset all state and let the class driver re-evaluate it all */
86 DeviceExtension
->ArFlag
|= (CMBATT_AR_NOTIFY
|
93 if (CmBattDebug
& CMBATT_PNP_INFO
)
94 DbgPrint("CmBattNotifyHandler: Unknown Notify Value: %x\n", NotifyValue
);
97 /* Check if we're supposed to delay the notification till later */
98 if (DeviceExtension
->DelayNotification
)
100 /* We'll handle this when we get a status query later on */
101 if (CmBattDebug
& CMBATT_PNP_INFO
)
102 DbgPrint("CmBattNotifyHandler: Notification delayed: ARs = %01x\n",
103 DeviceExtension
->ArFlag
);
107 /* We're going to handle this now */
108 if (CmBattDebug
& CMBATT_PNP_INFO
)
109 DbgPrint("CmBattNotifyHandler: Performing ARs: %01x\n", DeviceExtension
->ArFlag
);
111 /* Check if this is a battery or AC adapter notification */
112 if (DeviceExtension
->FdoType
== CmBattBattery
)
114 /* Reset the current trip point */
115 DeviceExtension
->TripPointValue
= 0xFFFFFFFF;
117 /* Check what ARs have to be done */
118 ArFlag
= DeviceExtension
->ArFlag
;
120 /* New battery inserted, reset lock value */
121 if (ArFlag
& CMBATT_AR_INSERT
) InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
123 /* Check if the battery may have been removed */
124 if (ArFlag
& CMBATT_AR_REMOVE
) DeviceExtension
->Tag
= 0;
126 /* Check if there's been any sort of change to the battery */
127 if (ArFlag
& CMBATT_AR_NOTIFY
)
129 /* We'll probably end up re-evaluating _BIF and _BST */
130 DeviceExtension
->NotifySent
= TRUE
;
131 BatteryClassStatusNotify(DeviceExtension
->ClassData
);
136 /* The only known notification is AC/DC change */
137 if (DeviceExtension
->ArFlag
& CMBATT_AR_NOTIFY
)
139 for (DeviceObject
= DeviceExtension
->FdoDeviceObject
->DriverObject
->DeviceObject
;
141 DeviceObject
= DeviceObject
->NextDevice
)
143 /* Is this a battery? */
144 FdoExtension
= DeviceObject
->DeviceExtension
;
145 if (FdoExtension
->FdoType
== CmBattBattery
)
147 /* Send a notification to the class driver */
148 FdoExtension
->NotifySent
= TRUE
;
149 BatteryClassStatusNotify(FdoExtension
->ClassData
);
155 /* ARs have been processed */
156 DeviceExtension
->ArFlag
= 0;
161 CmBattUnload(IN PDRIVER_OBJECT DriverObject
)
163 if (CmBattDebug
& CMBATT_GENERIC_INFO
) DPRINT("CmBattUnload: \n");
165 /* Check if we have a registered power callback */
166 if (CmBattPowerCallBackObject
)
169 ExUnregisterCallback(CmBattPowerCallBackRegistration
);
170 ObfDereferenceObject(CmBattPowerCallBackObject
);
173 /* Free the registry buffer if it exists */
174 if (GlobalRegistryPath
.Buffer
) ExFreePool(GlobalRegistryPath
.Buffer
);
176 /* Make sure we don't still have references to the DO */
177 if ((DriverObject
->DeviceObject
) && (CmBattDebug
& CMBATT_GENERIC_WARNING
))
179 DbgPrint("Unload called before all devices removed.\n");
185 CmBattVerifyStaticInfo(PCMBATT_DEVICE_EXTENSION DeviceExtension
,
189 return STATUS_NOT_IMPLEMENTED
;
194 CmBattOpenClose(IN PDEVICE_OBJECT DeviceObject
,
197 NTSTATUS Status
= STATUS_SUCCESS
;
198 PIO_STACK_LOCATION IoStackLocation
;
201 PCMBATT_DEVICE_EXTENSION DeviceExtension
;
203 if (CmBattDebug
& CMBATT_GENERIC_INFO
) DPRINT("CmBattOpenClose\n");
205 /* Grab the device extension and lock it */
206 DeviceExtension
= DeviceObject
->DeviceExtension
;
207 ExAcquireFastMutex(&DeviceExtension
->FastMutex
);
209 /* Check if someone is trying to open a device that doesn't exist yet */
210 Count
= DeviceExtension
->HandleCount
;
211 if (Count
== 0xFFFFFFFF)
213 /* Fail the request */
214 Status
= STATUS_NO_SUCH_DEVICE
;
215 if (CmBattDebug
& CMBATT_PNP_INFO
)
217 DbgPrint("CmBattOpenClose: Failed (UID = %x)(device being removed).\n",
218 DeviceExtension
->Tag
);
223 /* Check if this is an open or close */
224 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
225 Major
= IoStackLocation
->MajorFunction
;
226 if (Major
== IRP_MJ_CREATE
)
228 /* Increment the open count */
229 DeviceExtension
->HandleCount
= Count
+ 1;
230 if (CmBattDebug
& CMBATT_PNP_INFO
)
232 DbgPrint("CmBattOpenClose: Open (DeviceNumber = %x)(count = %x).\n",
233 DeviceExtension
->DeviceId
, Count
+ 1);
236 else if (Major
== IRP_MJ_CLOSE
)
238 /* Decrement the open count */
239 DeviceExtension
->HandleCount
= Count
- 1;
240 if (CmBattDebug
& CMBATT_PNP_INFO
)
242 DbgPrint("CmBattOpenClose: Close (DeviceNumber = %x)(count = %x).\n",
243 DeviceExtension
->DeviceId
, Count
+ 1);
248 /* Release lock and complete request */
249 ExReleaseFastMutex(&DeviceExtension
->FastMutex
);
250 Irp
->IoStatus
.Status
= Status
;
251 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
257 CmBattIoctl(PDEVICE_OBJECT DeviceObject
,
261 return STATUS_NOT_IMPLEMENTED
;
266 CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
269 PDEVICE_OBJECT PdoDevice
;
274 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
275 DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n",
276 *Tag
, DeviceExtension
, DeviceExtension
->DeviceId
);
278 /* Get PDO and clear notification flag */
279 PdoDevice
= DeviceExtension
->PdoDeviceObject
;
280 DeviceExtension
->NotifySent
= 0;
282 /* Get _STA from PDO (we need the machine status, not the battery status) */
283 Status
= CmBattGetStaData(PdoDevice
, &StaData
);
284 if (NT_SUCCESS(Status
))
286 /* Is a battery present? */
287 if (StaData
& ACPI_STA_BATTERY_PRESENT
)
289 /* Do we not have a tag yet? */
290 if (!DeviceExtension
->Tag
)
292 /* Set the new tag value, reset tags if we reached the maximum */
293 NewTag
= DeviceExtension
->TagData
;
294 if (DeviceExtension
->TagData
++ == 0xFFFFFFFF) NewTag
= 1;
295 DeviceExtension
->Tag
= NewTag
;
296 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
297 DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension
->Tag
);
299 /* Reset trip point data */
300 DeviceExtension
->TripPointOld
= 0;
301 DeviceExtension
->TripPointValue
= 0xFFFFFFFF;
303 /* Clear AR lock and set new interrupt time */
304 InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
305 DeviceExtension
->InterruptTime
= KeQueryInterruptTime();
310 /* No battery, so no tag */
311 DeviceExtension
->Tag
= 0;
312 Status
= STATUS_NO_SUCH_DEVICE
;
316 /* Return the tag and status result */
317 *Tag
= DeviceExtension
->Tag
;
318 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
319 DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag
, Status
);
325 CmBattDisableStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension
)
328 return STATUS_NOT_IMPLEMENTED
;
333 CmBattSetStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension
,
335 PBATTERY_NOTIFY BatteryNotify
)
338 return STATUS_NOT_IMPLEMENTED
;
343 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
349 ULONG DesignVoltage
, PresentRate
, RemainingCapacity
;
351 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
352 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension
, Tag
);
354 /* Validate ACPI data */
355 Status
= CmBattVerifyStaticInfo(DeviceExtension
, Tag
);
356 if (!NT_SUCCESS(Status
)) return Status
;
358 /* Check for delayed status notifications */
359 if (DeviceExtension
->DelayNotification
)
361 /* Process them now and don't do any other work */
362 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
366 /* Get _BST from ACPI */
367 Status
= CmBattGetBstData(DeviceExtension
, &DeviceExtension
->BstData
);
368 if (!NT_SUCCESS(Status
))
371 InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
375 /* Clear current BST information */
376 DeviceExtension
->State
= 0;
377 DeviceExtension
->RemainingCapacity
= 0;
378 DeviceExtension
->PresentVoltage
= 0;
379 DeviceExtension
->Rate
= 0;
381 /* Get battery state */
382 BstState
= DeviceExtension
->BstData
.State
;
384 /* Is the battery both charging and discharging? */
385 if ((BstState
& ACPI_BATT_STAT_DISCHARG
) && (BstState
& ACPI_BATT_STAT_CHARGING
) &&
386 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
387 DbgPrint("************************ ACPI BIOS BUG ********************\n* "
388 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n"
389 "* One battery cannot be charging and discharging at the same time.\n",
392 /* Is the battery discharging? */
393 if (BstState
& ACPI_BATT_STAT_DISCHARG
)
395 /* Set power state and check if it just started discharging now */
396 DeviceExtension
->State
|= BATTERY_DISCHARGING
;
397 if (!(DeviceExtension
->State
& ACPI_BATT_STAT_DISCHARG
))
399 /* Remember the time when the state changed */
400 DeviceExtension
->InterruptTime
= KeQueryInterruptTime();
403 else if (BstState
& ACPI_BATT_STAT_CHARGING
)
405 /* Battery is charging, update power state */
406 DeviceExtension
->State
|= (BATTERY_CHARGING
| BATTERY_POWER_ON_LINE
);
409 /* Is the battery in a critical state? */
410 if (BstState
& ACPI_BATT_STAT_CRITICAL
) DeviceExtension
->State
|= BATTERY_CRITICAL
;
412 /* Read the voltage data */
413 DeviceExtension
->PresentVoltage
= DeviceExtension
->BstData
.PresentVoltage
;
415 /* Check if we have an A/C adapter */
418 /* Query information on it */
419 CmBattGetPsrData(AcAdapterPdo
, &PsrData
);
423 /* Otherwise, check if the battery is charging */
424 if (BstState
& ACPI_BATT_STAT_CHARGING
)
426 /* Then we'll assume there's a charger */
431 /* Assume no charger */
436 /* Is there a charger? */
439 /* Set the power state flag to reflect this */
440 DeviceExtension
->State
|= BATTERY_POWER_ON_LINE
;
441 if (CmBattDebug
& (CMBATT_GENERIC_INFO
| CMBATT_GENERIC_STATUS
))
442 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n");
444 else if (CmBattDebug
& (CMBATT_GENERIC_INFO
| CMBATT_GENERIC_STATUS
))
446 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n");
449 /* Get some data we'll need */
450 DesignVoltage
= DeviceExtension
->BifData
.DesignVoltage
;
451 PresentRate
= DeviceExtension
->BstData
.PresentRate
;
452 RemainingCapacity
= DeviceExtension
->BstData
.RemainingCapacity
;
454 /* Check if we have battery data in Watts instead of Amps */
455 if (DeviceExtension
->BifData
.PowerUnit
== ACPI_BATT_POWER_UNIT_WATTS
)
457 /* Get the data from the BST */
458 DeviceExtension
->RemainingCapacity
= RemainingCapacity
;
459 DeviceExtension
->Rate
= PresentRate
;
461 /* Check if the rate is invalid */
462 if (PresentRate
> CM_MAX_VALUE
)
464 /* Set an unknown rate and don't touch the old value */
465 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
466 if ((PresentRate
!= CM_UNKNOWN_VALUE
) && (CmBattDebug
& CMBATT_ACPI_WARNING
))
468 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n");
469 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate
);
473 else if ((DesignVoltage
!= CM_UNKNOWN_VALUE
) && (DesignVoltage
))
475 /* We have voltage data, what about capacity? */
476 if (RemainingCapacity
== CM_UNKNOWN_VALUE
)
478 /* Unable to calculate it */
479 DeviceExtension
->RemainingCapacity
= BATTERY_UNKNOWN_CAPACITY
;
480 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
482 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n");
483 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n");
488 /* Compute the capacity with the information we have */
489 DeviceExtension
->RemainingCapacity
= (DesignVoltage
* RemainingCapacity
+ 500) / 1000;
492 /* Check if we have a rate */
493 if (PresentRate
!= CM_UNKNOWN_VALUE
)
495 /* Make sure the rate isn't too large */
496 if (PresentRate
> (-500 / DesignVoltage
))
498 /* It is, so set unknown state */
499 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
500 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
502 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
503 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate
);
507 /* Compute the rate */
508 DeviceExtension
->Rate
= (PresentRate
* DesignVoltage
+ 500) / 1000;
512 /* We don't have a rate, so set unknown value */
513 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
514 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
516 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
517 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n");
523 /* We have no rate, and no capacity, set unknown values */
524 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
525 DeviceExtension
->RemainingCapacity
= BATTERY_UNKNOWN_CAPACITY
;
526 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
528 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n");
529 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage
);
533 /* Check if we have an unknown rate */
534 if (DeviceExtension
->Rate
== BATTERY_UNKNOWN_RATE
)
536 /* The battery is discharging but we don't know by how much... this is bad! */
537 if ((BstState
& ACPI_BATT_STAT_DISCHARG
) &&
538 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
539 DbgPrint("CmBattGetBatteryStatus: battery rate is unkown when battery is not charging!\n");
541 else if (DeviceExtension
->State
& BATTERY_DISCHARGING
)
543 /* The battery is discharging, so treat the rate as a negative rate */
544 DeviceExtension
->Rate
= -DeviceExtension
->Rate
;
546 else if (!(DeviceExtension
->State
& BATTERY_CHARGING
) && (DeviceExtension
->Rate
))
548 /* We are not charging, not discharging, but have a rate? Ignore it! */
549 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
550 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n",
551 DeviceExtension
->Rate
);
552 DeviceExtension
->Rate
= 0;
556 return STATUS_SUCCESS
;
561 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension
,
563 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel
,
564 IN OPTIONAL LONG AtRate
,
566 IN ULONG BufferLength
,
567 OUT PULONG ReturnedLength
)
570 PVOID QueryData
= NULL
;
571 ULONG QueryLength
= 0;
572 ULONG RemainingTime
= 0;
573 ANSI_STRING TempString
;
574 UNICODE_STRING TempString2
;
575 WCHAR InfoBuffer
[256];
576 WCHAR TempBuffer
[256];
577 UNICODE_STRING InfoString
;
578 ULONG RemainingCapacity
;
579 BATTERY_REPORTING_SCALE BatteryReportingScale
[2];
582 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
583 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n",
585 FdoExtension
->DeviceId
,
588 /* Check ACPI Data */
589 Status
= CmBattVerifyStaticInfo(FdoExtension
, Tag
);
590 if (!NT_SUCCESS(Status
)) return Status
;
592 /* Check what caller wants */
595 case BatteryInformation
:
596 /* Just return our static information */
597 QueryData
= &FdoExtension
->BatteryInformation
;
598 QueryLength
= sizeof(BATTERY_INFORMATION
);
601 case BatteryGranularityInformation
:
603 /* Return our static information, we have two scales */
604 BatteryReportingScale
[0].Granularity
= FdoExtension
->BatteryCapacityGranularity1
;
605 BatteryReportingScale
[0].Capacity
= FdoExtension
->BatteryInformation
.DefaultAlert1
;
606 BatteryReportingScale
[1].Granularity
= FdoExtension
->BatteryCapacityGranularity2
;
607 BatteryReportingScale
[1].Capacity
= FdoExtension
->BatteryInformation
.DesignedCapacity
;
608 QueryData
= BatteryReportingScale
;
609 QueryLength
= sizeof(BATTERY_REPORTING_SCALE
) * 2;
612 case BatteryEstimatedTime
:
614 /* Check if it's been more than 2 1/2 minutes since the last change */
615 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension
->InterruptTime
))
617 /* Get new battery status */
618 CmBattGetBatteryStatus(FdoExtension
, FdoExtension
->Tag
);
620 /* If the caller didn't specify a rate, use our static one */
622 if (!Rate
) Rate
= FdoExtension
->Rate
;
624 /* If we don't have a valid negative rate, use unknown value */
625 if (Rate
>= 0) Rate
= BATTERY_UNKNOWN_RATE
;
627 /* Grab the remaining capacity */
628 RemainingCapacity
= FdoExtension
->RemainingCapacity
;
630 /* See if we don't know one or the other */
631 if ((Rate
== BATTERY_UNKNOWN_RATE
) ||
632 (RemainingCapacity
== BATTERY_UNKNOWN_CAPACITY
))
634 /* If the battery is discharging, we can't give out a time */
635 if ((FdoExtension
->BstData
.State
& ACPI_BATT_STAT_DISCHARG
) &&
636 (CmBattDebug
& CMBATT_GENERIC_WARNING
))
637 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n");
639 /* Check if we don't have a rate and capacity is going down */
640 if ((FdoExtension
->Rate
== BATTERY_UNKNOWN_RATE
) &&
641 (FdoExtension
->BstData
.State
& ACPI_BATT_STAT_DISCHARG
))
643 /* We have to fail, since we lack data */
644 Status
= STATUS_INVALID_DEVICE_REQUEST
;
645 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
646 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n");
649 /* If we don't have capacity, the rate is useless */
650 if (RemainingCapacity
== BATTERY_UNKNOWN_CAPACITY
)
652 /* We have to fail the request */
653 Status
= STATUS_INVALID_DEVICE_REQUEST
;
654 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
655 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n");
660 /* We have data, but is it valid? */
661 if (RemainingCapacity
> 0x123456)
663 /* The capacity seems bogus, so don't use it */
664 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
665 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n");
669 /* Compute the remaining time in seconds, based on rate */
670 RemainingTime
= (RemainingCapacity
* 3600) / -Rate
;
675 /* Return the remaining time */
676 QueryData
= &RemainingTime
;
677 QueryLength
= sizeof(ULONG
);
680 case BatteryDeviceName
:
682 /* Build the model number string */
683 RtlInitAnsiString(&TempString
, FdoExtension
->ModelNumber
);
685 /* Convert it to Unicode */
686 InfoString
.Buffer
= InfoBuffer
;
687 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
688 Status
= RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
690 /* Return the unicode buffer */
691 QueryData
= InfoString
.Buffer
;
692 QueryLength
= InfoString
.Length
;
695 case BatteryTemperature
:
696 case BatteryManufactureDate
:
698 /* We don't support these */
699 Status
= STATUS_INVALID_DEVICE_REQUEST
;
702 case BatteryManufactureName
:
704 /* Build the OEM info string */
705 RtlInitAnsiString(&TempString
, FdoExtension
->OemInfo
);
707 /* Convert it to Unicode */
708 InfoString
.Buffer
= InfoBuffer
;
709 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
710 Status
= RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
712 /* Return the unicode buffer */
713 QueryData
= InfoString
.Buffer
;
714 QueryLength
= InfoString
.Length
;
717 case BatteryUniqueID
:
719 /* Build the serial number string */
720 RtlInitAnsiString(&TempString
, FdoExtension
->SerialNumber
);
722 /* Convert it to Unicode */
723 InfoString
.Buffer
= InfoBuffer
;
724 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
725 RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
727 /* Setup a temporary string for concatenation */
728 TempString2
.Buffer
= TempBuffer
;
729 TempString2
.MaximumLength
= sizeof(TempBuffer
);
731 /* Check if there's an OEM string */
732 if (FdoExtension
->OemInfo
[0])
734 /* Build the OEM info string */
735 RtlInitAnsiString(&TempString
, FdoExtension
->OemInfo
);
737 /* Convert it to Unicode and append it */
738 RtlAnsiStringToUnicodeString(&TempString2
, &TempString
, 0);
739 RtlAppendUnicodeStringToString(&InfoString
, &TempString2
);
742 /* Build the model number string */
743 RtlInitAnsiString(&TempString
, FdoExtension
->ModelNumber
);
745 /* Convert it to Unicode and append it */
746 RtlAnsiStringToUnicodeString(&TempString2
, &TempString
, 0);
747 RtlAppendUnicodeStringToString(&InfoString
, &TempString2
);
749 /* Return the final appended string */
750 QueryData
= InfoString
.Buffer
;
751 QueryLength
= InfoString
.Length
;
756 /* Everything else is unknown */
757 Status
= STATUS_INVALID_PARAMETER
;
761 /* Return the required length and check if the caller supplied enough */
762 *ReturnedLength
= QueryLength
;
763 if (BufferLength
< QueryLength
) Status
= STATUS_BUFFER_TOO_SMALL
;
765 /* Copy the data if there's enough space and it exists */
766 if ((NT_SUCCESS(Status
)) && (QueryData
)) RtlCopyMemory(Buffer
, QueryData
, QueryLength
);
768 /* Return function result */
774 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
776 IN PBATTERY_STATUS BatteryStatus
)
780 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
781 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag
, DeviceExtension
->DeviceId
);
783 /* Query ACPI information */
784 Status
= CmBattGetBatteryStatus(DeviceExtension
, Tag
);
785 if (NT_SUCCESS(Status
))
787 BatteryStatus
->PowerState
= DeviceExtension
->State
;
788 BatteryStatus
->Capacity
= DeviceExtension
->RemainingCapacity
;
789 BatteryStatus
->Voltage
= DeviceExtension
->PresentVoltage
;
790 BatteryStatus
->Rate
= DeviceExtension
->Rate
;
794 if (CmBattDebug
& (CMBATT_GENERIC_INFO
))
795 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n",
796 BatteryStatus
->PowerState
,
797 BatteryStatus
->Capacity
,
798 BatteryStatus
->Voltage
,
799 BatteryStatus
->Rate
);
805 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
806 IN PUNICODE_STRING RegistryPath
)
809 PDRIVER_EXTENSION DriverExtension
;
810 OBJECT_ATTRIBUTES ObjectAttributes
;
811 UNICODE_STRING CallbackName
;
813 /* Allocate registry path */
814 GlobalRegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(UNICODE_NULL
);
815 GlobalRegistryPath
.Length
= RegistryPath
->Length
;
816 GlobalRegistryPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
817 GlobalRegistryPath
.MaximumLength
,
819 if (!GlobalRegistryPath
.Buffer
)
821 /* Fail if we're out of memory this early */
822 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
823 DbgPrint("CmBatt: Couldn't allocate pool for registry path.");
824 return STATUS_INSUFFICIENT_RESOURCES
;
827 /* Buffer allocated, copy the string */
828 RtlCopyUnicodeString(&GlobalRegistryPath
, RegistryPath
);
829 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
830 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n",
832 RegistryPath
->Buffer
);
834 /* Setup the major dispatchers */
835 DriverObject
->MajorFunction
[0] = CmBattOpenClose
;
836 DriverObject
->MajorFunction
[2] = CmBattOpenClose
;
837 DriverObject
->MajorFunction
[14] = CmBattIoctl
;
838 DriverObject
->MajorFunction
[22] = CmBattPowerDispatch
;
839 DriverObject
->MajorFunction
[27] = CmBattPnpDispatch
;
840 DriverObject
->MajorFunction
[23] = CmBattSystemControl
;
842 /* And the unload routine */
843 DriverObject
->DriverUnload
= CmBattUnload
;
845 /* And the add device routine */
846 DriverExtension
= DriverObject
->DriverExtension
;
847 DriverExtension
->AddDevice
= CmBattAddDevice
;
849 /* Create a power callback */
850 RtlInitUnicodeString(&CallbackName
, L
"\\Callback\\PowerState");
851 InitializeObjectAttributes(&ObjectAttributes
,
856 Status
= ExCreateCallback(&CmBattPowerCallBackObject
, &ObjectAttributes
, 0, TRUE
);
857 if (!NT_SUCCESS(Status
))
859 /* No callback, fail */
860 CmBattPowerCallBackObject
= 0;
861 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
862 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status
);
866 /* Register the power callback now */
867 CmBattPowerCallBackRegistration
= ExRegisterCallback(CmBattPowerCallBackObject
,
868 (PVOID
)CmBattPowerCallBack
,
870 if (CmBattPowerCallBackRegistration
)
872 /* Last thing: setup our DPC and timer for battery wake */
873 KeInitializeDpc(&CmBattWakeDpcObject
, (PVOID
)CmBattWakeDpc
, DriverObject
);
874 KeInitializeTimer(&CmBattWakeDpcTimerObject
);
878 ObfDereferenceObject(CmBattPowerCallBackObject
);
879 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
880 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n");
884 Status
= STATUS_SUCCESS
;
887 /* Return failure or success */