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 *******************************************************************/
15 /* GLOBALS ********************************************************************/
18 PCALLBACK_OBJECT CmBattPowerCallBackObject
;
19 PVOID CmBattPowerCallBackRegistration
;
20 UNICODE_STRING GlobalRegistryPath
;
21 KTIMER CmBattWakeDpcTimerObject
;
22 KDPC CmBattWakeDpcObject
;
23 PDEVICE_OBJECT AcAdapterPdo
;
24 LARGE_INTEGER CmBattWakeDpcDelay
;
26 /* FUNCTIONS ******************************************************************/
30 CmBattPowerCallBack(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
35 PDEVICE_OBJECT DeviceObject
;
36 if (CmBattDebug
& 0x10)
37 DbgPrint("CmBattPowerCallBack: action: %d, value: %d \n", Action
, Value
);
39 /* Check if a transition is going to happen */
40 if (Action
== PO_CB_SYSTEM_STATE_LOCK
)
42 /* We have just re-entered S0: call the wake DPC in 10 seconds */
45 if (CmBattDebug
& 0x10)
46 DbgPrint("CmBattPowerCallBack: Calling CmBattWakeDpc after 10 seconds.\n");
47 Cancelled
= KeSetTimer(&CmBattWakeDpcTimerObject
, CmBattWakeDpcDelay
, &CmBattWakeDpcObject
);
48 if (CmBattDebug
& 0x10)
49 DbgPrint("CmBattPowerCallBack: timerCanceled = %d.\n", Cancelled
);
53 /* We are exiting the S0 state: loop all devices to set the delay flag */
54 if (CmBattDebug
& 0x10)
55 DbgPrint("CmBattPowerCallBack: Delaying Notifications\n");
56 for (DeviceObject
= DeviceExtension
->DeviceObject
;
58 DeviceObject
= DeviceObject
->NextDevice
)
60 /* Set the delay flag */
61 DeviceExtension
= DeviceObject
->DeviceExtension
;
62 DeviceExtension
->DelayNotification
= TRUE
;
65 else if (CmBattDebug
& 0x10)
68 DbgPrint("CmBattPowerCallBack: unknown argument2 = %08x\n");
75 CmBattWakeDpc(IN PKDPC Dpc
,
76 IN PCMBATT_DEVICE_EXTENSION FdoExtension
,
77 IN PVOID SystemArgument1
,
78 IN PVOID SystemArgument2
)
80 PDEVICE_OBJECT CurrentObject
;
81 BOOLEAN AcNotify
= FALSE
;
82 PCMBATT_DEVICE_EXTENSION DeviceExtension
;
84 if (CmBattDebug
& 2) DbgPrint("CmBattWakeDpc: Entered.\n");
86 /* Loop all device objects */
87 for (CurrentObject
= FdoExtension
->DeviceObject
;
89 CurrentObject
= CurrentObject
->NextDevice
)
91 /* Turn delay flag off, we're back in S0 */
92 DeviceExtension
= CurrentObject
->DeviceExtension
;
93 DeviceExtension
->DelayNotification
= 0;
95 /* Check if this is an AC adapter */
96 if (DeviceExtension
->FdoType
== CmBattAcAdapter
)
98 /* Was there a pending notify? */
99 if (DeviceExtension
->ArFlag
& CMBATT_AR_NOTIFY
)
101 /* We'll send a notify on the next pass */
103 DeviceExtension
->ArFlag
= 0;
104 if (CmBattDebug
& 0x20)
105 DbgPrint("CmBattWakeDpc: AC adapter notified\n");
110 /* Loop the device objects again */
111 for (CurrentObject
= FdoExtension
->DeviceObject
;
113 CurrentObject
= CurrentObject
->NextDevice
)
115 /* Check if this is a battery */
116 DeviceExtension
= CurrentObject
->DeviceExtension
;
117 if (DeviceExtension
->FdoType
== CmBattBattery
)
119 /* Check what ARs are pending */
120 ArFlag
= DeviceExtension
->ArFlag
;
121 if (CmBattDebug
& 0x20)
122 DbgPrint("CmBattWakeDpc: Performing delayed ARs: %01x\n", ArFlag
);
124 /* Insert notification, clear the lock value */
125 if (ArFlag
& CMBATT_AR_INSERT
) InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
127 /* Removal, clear the battery tag */
128 if (ArFlag
& CMBATT_AR_REMOVE
) DeviceExtension
->Tag
= 0;
130 /* Notification (or AC/DC adapter change from first pass above) */
131 if ((ArFlag
& CMBATT_AR_NOTIFY
) || (AcNotify
))
133 /* Notify the class driver */
134 BatteryClassStatusNotify(DeviceExtension
->ClassData
);
142 CmBattNotifyHandler(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
143 IN ULONG NotifyValue
)
146 PCMBATT_DEVICE_EXTENSION FdoExtension
;
147 PDEVICE_OBJECT DeviceObject
;
149 if (CmBattDebug
& (CMBATT_ACPI_ASSERT
| CMBATT_PNP_INFO
))
150 DbgPrint("CmBattNotifyHandler: CmBatt 0x%08x Type %d Number %d Notify Value: %x\n",
152 DeviceExtension
->FdoType
,
153 DeviceExtension
->DeviceId
,
156 /* Check what kind of notification was received */
159 /* ACPI Specification says is sends a "Bus Check" when power source changes */
162 /* We treat it as possible physical change */
163 DeviceExtension
->ArFlag
|= (CMBATT_AR_NOTIFY
| CMBATT_AR_INSERT
);
164 if ((DeviceExtension
->Tag
) &&
165 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
166 DbgPrint("CmBattNotifyHandler: Received battery #%x insertion, but tag was not invalid.\n",
167 DeviceExtension
->DeviceId
);
170 /* Status of the battery has changed */
171 case ACPI_BATT_NOTIFY_STATUS
:
173 /* All we'll do is notify the class driver */
174 DeviceExtension
->ArFlag
|= CMBATT_AR_NOTIFY
;
177 /* Information on the battery has changed, such as physical presence */
178 case ACPI_DEVICE_CHECK
:
179 case ACPI_BATT_NOTIFY_INFO
:
181 /* Reset all state and let the class driver re-evaluate it all */
182 DeviceExtension
->ArFlag
|= (CMBATT_AR_NOTIFY
|
189 if (CmBattDebug
& CMBATT_PNP_INFO
)
190 DbgPrint("CmBattNotifyHandler: Unknown Notify Value: %x\n", NotifyValue
);
193 /* Check if we're supposed to delay the notification till later */
194 if (DeviceExtension
->DelayNotification
)
196 /* We'll handle this when we get a status query later on */
197 if (CmBattDebug
& CMBATT_PNP_INFO
)
198 DbgPrint("CmBattNotifyHandler: Notification delayed: ARs = %01x\n",
199 DeviceExtension
->ArFlag
);
203 /* We're going to handle this now */
204 if (CmBattDebug
& CMBATT_PNP_INFO
)
205 DbgPrint("CmBattNotifyHandler: Performing ARs: %01x\n", DeviceExtension
->ArFlag
);
207 /* Check if this is a battery or AC adapter notification */
208 if (DeviceExtension
->FdoType
== CmBattBattery
)
210 /* Reset the current trip point */
211 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
213 /* Check what ARs have to be done */
214 ArFlag
= DeviceExtension
->ArFlag
;
216 /* New battery inserted, reset lock value */
217 if (ArFlag
& CMBATT_AR_INSERT
) InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
219 /* Check if the battery may have been removed */
220 if (ArFlag
& CMBATT_AR_REMOVE
) DeviceExtension
->Tag
= 0;
222 /* Check if there's been any sort of change to the battery */
223 if (ArFlag
& CMBATT_AR_NOTIFY
)
225 /* We'll probably end up re-evaluating _BIF and _BST */
226 DeviceExtension
->NotifySent
= TRUE
;
227 BatteryClassStatusNotify(DeviceExtension
->ClassData
);
230 else if (DeviceExtension
->ArFlag
& CMBATT_AR_NOTIFY
)
232 /* The only known notification is AC/DC change. Loop device objects. */
233 for (DeviceObject
= DeviceExtension
->FdoDeviceObject
->DriverObject
->DeviceObject
;
235 DeviceObject
= DeviceObject
->NextDevice
)
237 /* Is this a battery? */
238 FdoExtension
= DeviceObject
->DeviceExtension
;
239 if (FdoExtension
->FdoType
== CmBattBattery
)
241 /* Send a notification to the class driver */
242 FdoExtension
->NotifySent
= TRUE
;
243 BatteryClassStatusNotify(FdoExtension
->ClassData
);
248 /* ARs have been processed */
249 DeviceExtension
->ArFlag
= 0;
254 CmBattUnload(IN PDRIVER_OBJECT DriverObject
)
256 if (CmBattDebug
& CMBATT_GENERIC_INFO
) DPRINT("CmBattUnload: \n");
258 /* Check if we have a registered power callback */
259 if (CmBattPowerCallBackObject
)
262 ExUnregisterCallback(CmBattPowerCallBackRegistration
);
263 ObDereferenceObject(CmBattPowerCallBackObject
);
266 /* Free the registry buffer if it exists */
267 if (GlobalRegistryPath
.Buffer
) ExFreePool(GlobalRegistryPath
.Buffer
);
269 /* Make sure we don't still have references to the DO */
270 if ((DriverObject
->DeviceObject
) && (CmBattDebug
& CMBATT_GENERIC_WARNING
))
272 DbgPrint("Unload called before all devices removed.\n");
278 CmBattVerifyStaticInfo(PCMBATT_DEVICE_EXTENSION DeviceExtension
,
282 return STATUS_NOT_IMPLEMENTED
;
287 CmBattOpenClose(IN PDEVICE_OBJECT DeviceObject
,
290 NTSTATUS Status
= STATUS_SUCCESS
;
291 PIO_STACK_LOCATION IoStackLocation
;
294 PCMBATT_DEVICE_EXTENSION DeviceExtension
;
296 if (CmBattDebug
& CMBATT_GENERIC_INFO
) DPRINT("CmBattOpenClose\n");
298 /* Grab the device extension and lock it */
299 DeviceExtension
= DeviceObject
->DeviceExtension
;
300 ExAcquireFastMutex(&DeviceExtension
->FastMutex
);
302 /* Check if someone is trying to open a device that doesn't exist yet */
303 Count
= DeviceExtension
->HandleCount
;
304 if (Count
== 0xFFFFFFFF)
306 /* Fail the request */
307 Status
= STATUS_NO_SUCH_DEVICE
;
308 if (CmBattDebug
& CMBATT_PNP_INFO
)
310 DbgPrint("CmBattOpenClose: Failed (UID = %x)(device being removed).\n",
311 DeviceExtension
->Tag
);
316 /* Check if this is an open or close */
317 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
318 Major
= IoStackLocation
->MajorFunction
;
319 if (Major
== IRP_MJ_CREATE
)
321 /* Increment the open count */
322 DeviceExtension
->HandleCount
= Count
+ 1;
323 if (CmBattDebug
& CMBATT_PNP_INFO
)
325 DbgPrint("CmBattOpenClose: Open (DeviceNumber = %x)(count = %x).\n",
326 DeviceExtension
->DeviceId
, Count
+ 1);
329 else if (Major
== IRP_MJ_CLOSE
)
331 /* Decrement the open count */
332 DeviceExtension
->HandleCount
= Count
- 1;
333 if (CmBattDebug
& CMBATT_PNP_INFO
)
335 DbgPrint("CmBattOpenClose: Close (DeviceNumber = %x)(count = %x).\n",
336 DeviceExtension
->DeviceId
, Count
+ 1);
341 /* Release lock and complete request */
342 ExReleaseFastMutex(&DeviceExtension
->FastMutex
);
343 Irp
->IoStatus
.Status
= Status
;
344 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
350 CmBattIoctl(IN PDEVICE_OBJECT DeviceObject
,
353 PCMBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
355 PIO_STACK_LOCATION IoStackLocation
;
356 ULONG IoControlCode
, OutputBufferLength
, InputBufferLength
;
358 if (CmBattDebug
& 2) DbgPrint("CmBattIoctl\n");
360 /* Acquire the remove lock */
361 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, 0);
362 if (!NT_SUCCESS(Status
))
364 /* It's too late, fail */
365 Irp
->IoStatus
.Status
= STATUS_DEVICE_REMOVED
;
366 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
367 return STATUS_DEVICE_REMOVED
;
370 /* There's nothing to do for an AC adapter */
371 if (DeviceExtension
->FdoType
== CmBattAcAdapter
)
373 /* Pass it down, and release the remove lock */
374 IoSkipCurrentIrpStackLocation(Irp
);
375 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
376 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
380 /* Send to class driver */
381 Status
= BatteryClassIoctl(DeviceExtension
->ClassData
, Irp
);
382 if (Status
== STATUS_NOT_SUPPORTED
)
384 /* Read IOCTL information from IRP stack */
385 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
386 IoControlCode
= IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
;
387 OutputBufferLength
= IoStackLocation
->Parameters
.DeviceIoControl
.OutputBufferLength
;
388 InputBufferLength
= IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
;
390 DbgPrint("CmBattIoctl: Received Direct Access IOCTL %x\n", IoControlCode
);
392 /* Handle internal IOCTLs */
393 switch (IoControlCode
)
395 case IOCTL_BATTERY_QUERY_UNIQUE_ID
:
397 /* Data is 4 bytes long */
398 if (OutputBufferLength
== sizeof(ULONG
))
401 Status
= CmBattGetUniqueId(DeviceExtension
->PdoDeviceObject
,
402 Irp
->AssociatedIrp
.SystemBuffer
);
403 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ULONG
);
407 /* Buffer size invalid */
408 Status
= STATUS_INVALID_BUFFER_SIZE
;
412 case IOCTL_BATTERY_QUERY_STA
:
414 /* Data is 4 bytes long */
415 if (OutputBufferLength
== sizeof(ULONG
))
418 Status
= CmBattGetStaData(DeviceExtension
->PdoDeviceObject
,
419 Irp
->AssociatedIrp
.SystemBuffer
);
420 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ULONG
);
424 /* Buffer size invalid */
425 Status
= STATUS_INVALID_BUFFER_SIZE
;
429 case IOCTL_BATTERY_QUERY_PSR
:
431 /* Data is 4 bytes long */
432 if (OutputBufferLength
== sizeof(ULONG
))
434 /* Do we have an AC adapter? */
438 Status
= CmBattGetPsrData(AcAdapterPdo
,
439 Irp
->AssociatedIrp
.SystemBuffer
);
440 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ULONG
);
444 /* No adapter, just a battery, so fail */
445 Status
= STATUS_NO_SUCH_DEVICE
;
450 /* Buffer size invalid */
451 Status
= STATUS_INVALID_BUFFER_SIZE
;
455 case IOCTL_BATTERY_SET_TRIP_POINT
:
457 /* Data is 4 bytes long */
458 if (InputBufferLength
== sizeof(ULONG
))
461 Status
= CmBattSetTripPpoint(DeviceExtension
,
462 *(PULONG
)Irp
->AssociatedIrp
.SystemBuffer
);
463 Irp
->IoStatus
.Information
= 0;
467 /* Buffer size invalid */
468 Status
= STATUS_INVALID_BUFFER_SIZE
;
472 case IOCTL_BATTERY_QUERY_BIF
:
474 /* Data is 1060 bytes long */
475 if (OutputBufferLength
== sizeof(ACPI_BIF_DATA
))
478 Status
= CmBattGetBifData(DeviceExtension
,
479 Irp
->AssociatedIrp
.SystemBuffer
);
480 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ACPI_BIF_DATA
);
484 /* Buffer size invalid */
485 Status
= STATUS_INVALID_BUFFER_SIZE
;
489 case IOCTL_BATTERY_QUERY_BST
:
491 /* Data is 16 bytes long */
492 if (OutputBufferLength
== sizeof(ACPI_BST_DATA
))
495 Status
= CmBattGetBstData(DeviceExtension
,
496 Irp
->AssociatedIrp
.SystemBuffer
);
497 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ACPI_BST_DATA
);
501 /* Buffer size invalid */
502 Status
= STATUS_INVALID_BUFFER_SIZE
;
508 /* Unknown, let us pass it on to ACPI */
509 if (CmBattDebug
& 0xC)
510 DbgPrint("CmBattIoctl: Unknown IOCTL %x\n", IoControlCode
);
514 /* Did someone pick it up? */
515 if (Status
!= STATUS_NOT_SUPPORTED
)
517 /* Complete the request */
518 Irp
->IoStatus
.Status
= Status
;
519 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
523 /* Still unsupported, try ACPI */
524 IoSkipCurrentIrpStackLocation(Irp
);
525 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
529 /* Release the remove lock and return status */
530 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
536 CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
539 PDEVICE_OBJECT PdoDevice
;
544 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
545 DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n",
546 *Tag
, DeviceExtension
, DeviceExtension
->DeviceId
);
548 /* Get PDO and clear notification flag */
549 PdoDevice
= DeviceExtension
->PdoDeviceObject
;
550 DeviceExtension
->NotifySent
= 0;
552 /* Get _STA from PDO (we need the machine status, not the battery status) */
553 Status
= CmBattGetStaData(PdoDevice
, &StaData
);
554 if (NT_SUCCESS(Status
))
556 /* Is a battery present? */
557 if (StaData
& ACPI_STA_BATTERY_PRESENT
)
559 /* Do we not have a tag yet? */
560 if (!DeviceExtension
->Tag
)
562 /* Set the new tag value, reset tags if we reached the maximum */
563 NewTag
= DeviceExtension
->TagData
;
564 if (DeviceExtension
->TagData
++ == 0xFFFFFFFF) NewTag
= 1;
565 DeviceExtension
->Tag
= NewTag
;
566 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
567 DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension
->Tag
);
569 /* Reset trip point data */
570 DeviceExtension
->TripPointOld
= 0;
571 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
573 /* Clear AR lock and set new interrupt time */
574 InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
575 DeviceExtension
->InterruptTime
= KeQueryInterruptTime();
580 /* No battery, so no tag */
581 DeviceExtension
->Tag
= 0;
582 Status
= STATUS_NO_SUCH_DEVICE
;
586 /* Return the tag and status result */
587 *Tag
= DeviceExtension
->Tag
;
588 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
589 DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag
, Status
);
595 CmBattDisableStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
)
599 if (CmBattDebug
& 0xA) DbgPrint("CmBattDisableStatusNotify\n");
601 /* Do we have a trip point */
602 if (DeviceExtension
->TripPointSet
)
604 /* Is there a current value set? */
605 if (DeviceExtension
->TripPointValue
)
607 /* Reset it back to 0 */
608 DeviceExtension
->TripPointValue
= 0;
609 Status
= CmBattSetTripPpoint(DeviceExtension
, 0);
610 if (!NT_SUCCESS(Status
))
612 /* If it failed, set unknown/invalid value */
613 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
615 DbgPrint("CmBattDisableStatusNotify: SetTripPoint failed - %x\n", Status
);
620 /* No trip point set, so this is a successful no-op */
621 Status
= STATUS_SUCCESS
;
626 /* Nothing we can do */
627 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
636 CmBattSetStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
638 IN PBATTERY_NOTIFY BatteryNotify
)
641 ACPI_BST_DATA BstData
;
642 ULONG Capacity
, NewTripPoint
, TripPoint
, DesignVoltage
;
645 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
646 DbgPrint("CmBattSetStatusNotify: Tag (%d) Target(0x%x)\n",
647 BatteryTag
, BatteryNotify
->LowCapacity
);
649 /* Update any ACPI evaluations */
650 Status
= CmBattVerifyStaticInfo(DeviceExtension
, BatteryTag
);
651 if (!NT_SUCCESS(Status
)) return Status
;
653 /* Trip point not supported, fail */
654 if (!DeviceExtension
->TripPointSet
) return STATUS_OBJECT_NAME_NOT_FOUND
;
656 /* Are both capacities known? */
657 if ((BatteryNotify
->HighCapacity
== BATTERY_UNKNOWN_CAPACITY
) ||
658 (BatteryNotify
->LowCapacity
== BATTERY_UNKNOWN_CAPACITY
))
660 /* We can't set trip points without these */
661 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
662 DbgPrint("CmBattSetStatusNotify: Failing request because of BATTERY_UNKNOWN_CAPACITY.\n");
663 return STATUS_NOT_SUPPORTED
;
666 /* Is the battery charging? */
667 Charging
= DeviceExtension
->BstData
.State
& ACPI_BATT_STAT_CHARGING
;
670 /* Then the trip point is when we hit the cap */
671 Capacity
= BatteryNotify
->HighCapacity
;
672 NewTripPoint
= BatteryNotify
->HighCapacity
;
676 /* Otherwise it's when we discharge to the bottom */
677 Capacity
= BatteryNotify
->LowCapacity
;
678 NewTripPoint
= BatteryNotify
->LowCapacity
;
681 /* Do we have data in Amps or Watts? */
682 if (DeviceExtension
->BifData
.PowerUnit
== ACPI_BATT_POWER_UNIT_AMPS
)
684 /* We need the voltage to do the conversion */
685 DesignVoltage
= DeviceExtension
->BifData
.DesignVoltage
;
686 if ((DesignVoltage
!= BATTERY_UNKNOWN_VOLTAGE
) && (DesignVoltage
))
688 /* Convert from mAh into Ah */
689 TripPoint
= 1000 * NewTripPoint
;
692 /* Scale the high trip point */
693 NewTripPoint
= (TripPoint
+ 500) / DesignVoltage
+ ((TripPoint
+ 500) % DesignVoltage
!= 0);
697 /* Scale the low trip point */
698 NewTripPoint
= (TripPoint
- 500) / DesignVoltage
- ((TripPoint
- 500) % DesignVoltage
== 0);
703 /* Without knowing the voltage, Amps are not enough data on consumption */
704 Status
= STATUS_NOT_SUPPORTED
;
705 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
706 DbgPrint("CmBattSetStatusNotify: Can't calculate BTP, DesignVoltage = 0x%08x\n",
712 /* Make it trip just one past the charge cap */
715 else if (NewTripPoint
> 0)
717 /* Make it trip just one below the drain cap */
721 /* Do we actually have a new trip point? */
722 if (NewTripPoint
== DeviceExtension
->TripPointValue
)
724 /* No, so there is no work to be done */
725 if (CmBattDebug
& CMBATT_GENERIC_STATUS
)
726 DbgPrint("CmBattSetStatusNotify: Keeping original setting: %X\n", DeviceExtension
->TripPointValue
);
727 return STATUS_SUCCESS
;
730 /* Set the trip point with ACPI and check for success */
731 DeviceExtension
->TripPointValue
= NewTripPoint
;
732 Status
= CmBattSetTripPpoint(DeviceExtension
, NewTripPoint
);
733 if (!(NewTripPoint
) && (Capacity
)) Status
= STATUS_NOT_SUPPORTED
;
734 if (!NT_SUCCESS(Status
))
736 /* We failed to set the trip point, or there wasn't one settable */
737 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
738 if (CmBattDebug
& (CMBATT_GENERIC_WARNING
| CMBATT_ACPI_WARNING
))
739 DbgPrint("CmBattSetStatusNotify: SetTripPoint failed - %x\n", Status
);
743 /* Read the new BST data to see the latest state */
744 Status
= CmBattGetBstData(DeviceExtension
, &BstData
);
745 if (!NT_SUCCESS(Status
))
747 /* We'll return failure to the caller */
748 if (CmBattDebug
& (CMBATT_GENERIC_WARNING
| CMBATT_ACPI_WARNING
))
749 DbgPrint("CmBattSetStatusNotify: GetBstData - %x\n", Status
);
751 else if ((Charging
) && (BstData
.RemainingCapacity
>= NewTripPoint
))
753 /* We are charging and our capacity is past the trip point, so trip now */
754 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
755 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n",
756 NewTripPoint
, BstData
.RemainingCapacity
);
757 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
759 else if ((BstData
.RemainingCapacity
) && (Capacity
))
761 /* We are discharging, and our capacity is below the trip point, trip now */
762 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
763 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n",
764 NewTripPoint
, BstData
.RemainingCapacity
);
765 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
768 /* All should've went well if we got here, unless BST failed... return! */
769 if (CmBattDebug
& CMBATT_GENERIC_STATUS
)
770 DbgPrint("CmBattSetStatusNotify: Want %X CurrentCap %X\n",
771 Capacity
, DeviceExtension
->RemainingCapacity
);
772 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
773 DbgPrint("CmBattSetStatusNotify: Set to: [%#08lx][%#08lx][%#08lx] Status %x\n",
774 BatteryNotify
->PowerState
,
775 BatteryNotify
->LowCapacity
,
776 BatteryNotify
->HighCapacity
);
782 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
788 ULONG DesignVoltage
, PresentRate
, RemainingCapacity
;
790 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
791 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension
, Tag
);
793 /* Validate ACPI data */
794 Status
= CmBattVerifyStaticInfo(DeviceExtension
, Tag
);
795 if (!NT_SUCCESS(Status
)) return Status
;
797 /* Check for delayed status notifications */
798 if (DeviceExtension
->DelayNotification
)
800 /* Process them now and don't do any other work */
801 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
805 /* Get _BST from ACPI */
806 Status
= CmBattGetBstData(DeviceExtension
, &DeviceExtension
->BstData
);
807 if (!NT_SUCCESS(Status
))
810 InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
814 /* Clear current BST information */
815 DeviceExtension
->State
= 0;
816 DeviceExtension
->RemainingCapacity
= 0;
817 DeviceExtension
->PresentVoltage
= 0;
818 DeviceExtension
->Rate
= 0;
820 /* Get battery state */
821 BstState
= DeviceExtension
->BstData
.State
;
823 /* Is the battery both charging and discharging? */
824 if ((BstState
& ACPI_BATT_STAT_DISCHARG
) && (BstState
& ACPI_BATT_STAT_CHARGING
) &&
825 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
826 DbgPrint("************************ ACPI BIOS BUG ********************\n* "
827 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n"
828 "* One battery cannot be charging and discharging at the same time.\n",
831 /* Is the battery discharging? */
832 if (BstState
& ACPI_BATT_STAT_DISCHARG
)
834 /* Set power state and check if it just started discharging now */
835 DeviceExtension
->State
|= BATTERY_DISCHARGING
;
836 if (!(DeviceExtension
->State
& ACPI_BATT_STAT_DISCHARG
))
838 /* Remember the time when the state changed */
839 DeviceExtension
->InterruptTime
= KeQueryInterruptTime();
842 else if (BstState
& ACPI_BATT_STAT_CHARGING
)
844 /* Battery is charging, update power state */
845 DeviceExtension
->State
|= (BATTERY_CHARGING
| BATTERY_POWER_ON_LINE
);
848 /* Is the battery in a critical state? */
849 if (BstState
& ACPI_BATT_STAT_CRITICAL
) DeviceExtension
->State
|= BATTERY_CRITICAL
;
851 /* Read the voltage data */
852 DeviceExtension
->PresentVoltage
= DeviceExtension
->BstData
.PresentVoltage
;
854 /* Check if we have an A/C adapter */
857 /* Query information on it */
858 CmBattGetPsrData(AcAdapterPdo
, &PsrData
);
862 /* Otherwise, check if the battery is charging */
863 if (BstState
& ACPI_BATT_STAT_CHARGING
)
865 /* Then we'll assume there's a charger */
870 /* Assume no charger */
875 /* Is there a charger? */
878 /* Set the power state flag to reflect this */
879 DeviceExtension
->State
|= BATTERY_POWER_ON_LINE
;
880 if (CmBattDebug
& (CMBATT_GENERIC_INFO
| CMBATT_GENERIC_STATUS
))
881 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n");
883 else if (CmBattDebug
& (CMBATT_GENERIC_INFO
| CMBATT_GENERIC_STATUS
))
885 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n");
888 /* Get some data we'll need */
889 DesignVoltage
= DeviceExtension
->BifData
.DesignVoltage
;
890 PresentRate
= DeviceExtension
->BstData
.PresentRate
;
891 RemainingCapacity
= DeviceExtension
->BstData
.RemainingCapacity
;
893 /* Check if we have battery data in Watts instead of Amps */
894 if (DeviceExtension
->BifData
.PowerUnit
== ACPI_BATT_POWER_UNIT_WATTS
)
896 /* Get the data from the BST */
897 DeviceExtension
->RemainingCapacity
= RemainingCapacity
;
898 DeviceExtension
->Rate
= PresentRate
;
900 /* Check if the rate is invalid */
901 if (PresentRate
> CM_MAX_VALUE
)
903 /* Set an unknown rate and don't touch the old value */
904 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
905 if ((PresentRate
!= CM_UNKNOWN_VALUE
) && (CmBattDebug
& CMBATT_ACPI_WARNING
))
907 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n");
908 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate
);
912 else if ((DesignVoltage
!= CM_UNKNOWN_VALUE
) && (DesignVoltage
))
914 /* We have voltage data, what about capacity? */
915 if (RemainingCapacity
== CM_UNKNOWN_VALUE
)
917 /* Unable to calculate it */
918 DeviceExtension
->RemainingCapacity
= BATTERY_UNKNOWN_CAPACITY
;
919 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
921 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n");
922 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n");
927 /* Compute the capacity with the information we have */
928 DeviceExtension
->RemainingCapacity
= (DesignVoltage
* RemainingCapacity
+ 500) / 1000;
931 /* Check if we have a rate */
932 if (PresentRate
!= CM_UNKNOWN_VALUE
)
934 /* Make sure the rate isn't too large */
935 if (PresentRate
> (-500 / DesignVoltage
))
937 /* It is, so set unknown state */
938 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
939 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
941 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
942 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate
);
946 /* Compute the rate */
947 DeviceExtension
->Rate
= (PresentRate
* DesignVoltage
+ 500) / 1000;
951 /* We don't have a rate, so set unknown value */
952 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
953 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
955 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
956 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n");
962 /* We have no rate, and no capacity, set unknown values */
963 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
964 DeviceExtension
->RemainingCapacity
= BATTERY_UNKNOWN_CAPACITY
;
965 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
967 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n");
968 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage
);
972 /* Check if we have an unknown rate */
973 if (DeviceExtension
->Rate
== BATTERY_UNKNOWN_RATE
)
975 /* The battery is discharging but we don't know by how much... this is bad! */
976 if ((BstState
& ACPI_BATT_STAT_DISCHARG
) &&
977 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
978 DbgPrint("CmBattGetBatteryStatus: battery rate is unkown when battery is not charging!\n");
980 else if (DeviceExtension
->State
& BATTERY_DISCHARGING
)
982 /* The battery is discharging, so treat the rate as a negative rate */
983 DeviceExtension
->Rate
= -DeviceExtension
->Rate
;
985 else if (!(DeviceExtension
->State
& BATTERY_CHARGING
) && (DeviceExtension
->Rate
))
987 /* We are not charging, not discharging, but have a rate? Ignore it! */
988 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
989 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n",
990 DeviceExtension
->Rate
);
991 DeviceExtension
->Rate
= 0;
995 return STATUS_SUCCESS
;
1000 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension
,
1002 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel
,
1003 IN OPTIONAL LONG AtRate
,
1005 IN ULONG BufferLength
,
1006 OUT PULONG ReturnedLength
)
1009 PVOID QueryData
= NULL
;
1010 ULONG QueryLength
= 0;
1011 ULONG RemainingTime
= 0;
1012 ANSI_STRING TempString
;
1013 UNICODE_STRING TempString2
;
1014 WCHAR InfoBuffer
[256];
1015 WCHAR TempBuffer
[256];
1016 UNICODE_STRING InfoString
;
1017 ULONG RemainingCapacity
;
1018 BATTERY_REPORTING_SCALE BatteryReportingScale
[2];
1021 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
1022 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n",
1024 FdoExtension
->DeviceId
,
1027 /* Check ACPI Data */
1028 Status
= CmBattVerifyStaticInfo(FdoExtension
, Tag
);
1029 if (!NT_SUCCESS(Status
)) return Status
;
1031 /* Check what caller wants */
1034 case BatteryInformation
:
1035 /* Just return our static information */
1036 QueryData
= &FdoExtension
->BatteryInformation
;
1037 QueryLength
= sizeof(BATTERY_INFORMATION
);
1040 case BatteryGranularityInformation
:
1042 /* Return our static information, we have two scales */
1043 BatteryReportingScale
[0].Granularity
= FdoExtension
->BatteryCapacityGranularity1
;
1044 BatteryReportingScale
[0].Capacity
= FdoExtension
->BatteryInformation
.DefaultAlert1
;
1045 BatteryReportingScale
[1].Granularity
= FdoExtension
->BatteryCapacityGranularity2
;
1046 BatteryReportingScale
[1].Capacity
= FdoExtension
->BatteryInformation
.DesignedCapacity
;
1047 QueryData
= BatteryReportingScale
;
1048 QueryLength
= sizeof(BATTERY_REPORTING_SCALE
) * 2;
1051 case BatteryEstimatedTime
:
1053 /* Check if it's been more than 2 1/2 minutes since the last change */
1054 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension
->InterruptTime
))
1056 /* Get new battery status */
1057 CmBattGetBatteryStatus(FdoExtension
, FdoExtension
->Tag
);
1059 /* If the caller didn't specify a rate, use our static one */
1061 if (!Rate
) Rate
= FdoExtension
->Rate
;
1063 /* If we don't have a valid negative rate, use unknown value */
1064 if (Rate
>= 0) Rate
= BATTERY_UNKNOWN_RATE
;
1066 /* Grab the remaining capacity */
1067 RemainingCapacity
= FdoExtension
->RemainingCapacity
;
1069 /* See if we don't know one or the other */
1070 if ((Rate
== BATTERY_UNKNOWN_RATE
) ||
1071 (RemainingCapacity
== BATTERY_UNKNOWN_CAPACITY
))
1073 /* If the battery is discharging, we can't give out a time */
1074 if ((FdoExtension
->BstData
.State
& ACPI_BATT_STAT_DISCHARG
) &&
1075 (CmBattDebug
& CMBATT_GENERIC_WARNING
))
1076 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n");
1078 /* Check if we don't have a rate and capacity is going down */
1079 if ((FdoExtension
->Rate
== BATTERY_UNKNOWN_RATE
) &&
1080 (FdoExtension
->BstData
.State
& ACPI_BATT_STAT_DISCHARG
))
1082 /* We have to fail, since we lack data */
1083 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1084 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1085 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n");
1088 /* If we don't have capacity, the rate is useless */
1089 if (RemainingCapacity
== BATTERY_UNKNOWN_CAPACITY
)
1091 /* We have to fail the request */
1092 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1093 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1094 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n");
1099 /* We have data, but is it valid? */
1100 if (RemainingCapacity
> 0x123456)
1102 /* The capacity seems bogus, so don't use it */
1103 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
1104 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n");
1108 /* Compute the remaining time in seconds, based on rate */
1109 RemainingTime
= (RemainingCapacity
* 3600) / -Rate
;
1114 /* Return the remaining time */
1115 QueryData
= &RemainingTime
;
1116 QueryLength
= sizeof(ULONG
);
1119 case BatteryDeviceName
:
1121 /* Build the model number string */
1122 RtlInitAnsiString(&TempString
, FdoExtension
->ModelNumber
);
1124 /* Convert it to Unicode */
1125 InfoString
.Buffer
= InfoBuffer
;
1126 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
1127 Status
= RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
1129 /* Return the unicode buffer */
1130 QueryData
= InfoString
.Buffer
;
1131 QueryLength
= InfoString
.Length
;
1134 case BatteryTemperature
:
1135 case BatteryManufactureDate
:
1137 /* We don't support these */
1138 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1141 case BatteryManufactureName
:
1143 /* Build the OEM info string */
1144 RtlInitAnsiString(&TempString
, FdoExtension
->OemInfo
);
1146 /* Convert it to Unicode */
1147 InfoString
.Buffer
= InfoBuffer
;
1148 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
1149 Status
= RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
1151 /* Return the unicode buffer */
1152 QueryData
= InfoString
.Buffer
;
1153 QueryLength
= InfoString
.Length
;
1156 case BatteryUniqueID
:
1158 /* Build the serial number string */
1159 RtlInitAnsiString(&TempString
, FdoExtension
->SerialNumber
);
1161 /* Convert it to Unicode */
1162 InfoString
.Buffer
= InfoBuffer
;
1163 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
1164 RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
1166 /* Setup a temporary string for concatenation */
1167 TempString2
.Buffer
= TempBuffer
;
1168 TempString2
.MaximumLength
= sizeof(TempBuffer
);
1170 /* Check if there's an OEM string */
1171 if (FdoExtension
->OemInfo
[0])
1173 /* Build the OEM info string */
1174 RtlInitAnsiString(&TempString
, FdoExtension
->OemInfo
);
1176 /* Convert it to Unicode and append it */
1177 RtlAnsiStringToUnicodeString(&TempString2
, &TempString
, 0);
1178 RtlAppendUnicodeStringToString(&InfoString
, &TempString2
);
1181 /* Build the model number string */
1182 RtlInitAnsiString(&TempString
, FdoExtension
->ModelNumber
);
1184 /* Convert it to Unicode and append it */
1185 RtlAnsiStringToUnicodeString(&TempString2
, &TempString
, 0);
1186 RtlAppendUnicodeStringToString(&InfoString
, &TempString2
);
1188 /* Return the final appended string */
1189 QueryData
= InfoString
.Buffer
;
1190 QueryLength
= InfoString
.Length
;
1195 /* Everything else is unknown */
1196 Status
= STATUS_INVALID_PARAMETER
;
1200 /* Return the required length and check if the caller supplied enough */
1201 *ReturnedLength
= QueryLength
;
1202 if (BufferLength
< QueryLength
) Status
= STATUS_BUFFER_TOO_SMALL
;
1204 /* Copy the data if there's enough space and it exists */
1205 if ((NT_SUCCESS(Status
)) && (QueryData
)) RtlCopyMemory(Buffer
, QueryData
, QueryLength
);
1207 /* Return function result */
1213 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
1215 IN PBATTERY_STATUS BatteryStatus
)
1219 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
1220 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag
, DeviceExtension
->DeviceId
);
1222 /* Query ACPI information */
1223 Status
= CmBattGetBatteryStatus(DeviceExtension
, Tag
);
1224 if (NT_SUCCESS(Status
))
1226 BatteryStatus
->PowerState
= DeviceExtension
->State
;
1227 BatteryStatus
->Capacity
= DeviceExtension
->RemainingCapacity
;
1228 BatteryStatus
->Voltage
= DeviceExtension
->PresentVoltage
;
1229 BatteryStatus
->Rate
= DeviceExtension
->Rate
;
1233 if (CmBattDebug
& (CMBATT_GENERIC_INFO
))
1234 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n",
1235 BatteryStatus
->PowerState
,
1236 BatteryStatus
->Capacity
,
1237 BatteryStatus
->Voltage
,
1238 BatteryStatus
->Rate
);
1244 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1245 IN PUNICODE_STRING RegistryPath
)
1248 PDRIVER_EXTENSION DriverExtension
;
1249 OBJECT_ATTRIBUTES ObjectAttributes
;
1250 UNICODE_STRING CallbackName
;
1252 /* Allocate registry path */
1253 GlobalRegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(UNICODE_NULL
);
1254 GlobalRegistryPath
.Length
= RegistryPath
->Length
;
1255 GlobalRegistryPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1256 GlobalRegistryPath
.MaximumLength
,
1258 if (!GlobalRegistryPath
.Buffer
)
1260 /* Fail if we're out of memory this early */
1261 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1262 DbgPrint("CmBatt: Couldn't allocate pool for registry path.");
1263 return STATUS_INSUFFICIENT_RESOURCES
;
1266 /* Buffer allocated, copy the string */
1267 RtlCopyUnicodeString(&GlobalRegistryPath
, RegistryPath
);
1268 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
1269 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n",
1271 RegistryPath
->Buffer
);
1273 /* Setup the major dispatchers */
1274 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = CmBattOpenClose
;
1275 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = CmBattOpenClose
;
1276 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = CmBattIoctl
;
1277 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = CmBattPowerDispatch
;
1278 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = CmBattPnpDispatch
;
1279 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = CmBattSystemControl
;
1281 /* And the unload routine */
1282 DriverObject
->DriverUnload
= CmBattUnload
;
1284 /* And the add device routine */
1285 DriverExtension
= DriverObject
->DriverExtension
;
1286 DriverExtension
->AddDevice
= CmBattAddDevice
;
1288 /* Create a power callback */
1289 RtlInitUnicodeString(&CallbackName
, L
"\\Callback\\PowerState");
1290 InitializeObjectAttributes(&ObjectAttributes
,
1295 Status
= ExCreateCallback(&CmBattPowerCallBackObject
, &ObjectAttributes
, 0, TRUE
);
1296 if (!NT_SUCCESS(Status
))
1298 /* No callback, fail */
1299 CmBattPowerCallBackObject
= 0;
1300 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1301 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status
);
1305 /* Register the power callback now */
1306 CmBattPowerCallBackRegistration
= ExRegisterCallback(CmBattPowerCallBackObject
,
1307 (PVOID
)CmBattPowerCallBack
,
1309 if (CmBattPowerCallBackRegistration
)
1311 /* Last thing: setup our DPC and timer for battery wake */
1312 KeInitializeDpc(&CmBattWakeDpcObject
, (PVOID
)CmBattWakeDpc
, DriverObject
);
1313 KeInitializeTimer(&CmBattWakeDpcTimerObject
);
1317 ObDereferenceObject(CmBattPowerCallBackObject
);
1318 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1319 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n");
1323 Status
= STATUS_SUCCESS
;
1326 /* Return failure or success */