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
;
22 LARGE_INTEGER CmBattWakeDpcDelay
;
24 /* FUNCTIONS ******************************************************************/
28 CmBattPowerCallBack(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
33 PDEVICE_OBJECT DeviceObject
;
34 if (CmBattDebug
& 0x10)
35 DbgPrint("CmBattPowerCallBack: action: %d, value: %d \n", Action
, Value
);
37 /* Check if a transition is going to happen */
38 if (Action
== PO_CB_SYSTEM_STATE_LOCK
)
40 /* We have just re-entered S0: call the wake DPC in 10 seconds */
43 if (CmBattDebug
& 0x10)
44 DbgPrint("CmBattPowerCallBack: Calling CmBattWakeDpc after 10 seconds.\n");
45 Cancelled
= KeSetTimer(&CmBattWakeDpcTimerObject
, CmBattWakeDpcDelay
, &CmBattWakeDpcObject
);
46 if (CmBattDebug
& 0x10)
47 DbgPrint("CmBattPowerCallBack: timerCanceled = %d.\n", Cancelled
);
51 /* We are exiting the S0 state: loop all devices to set the delay flag */
52 if (CmBattDebug
& 0x10)
53 DbgPrint("CmBattPowerCallBack: Delaying Notifications\n");
54 for (DeviceObject
= DeviceExtension
->DeviceObject
;
56 DeviceObject
= DeviceObject
->NextDevice
)
58 /* Set the delay flag */
59 DeviceExtension
= DeviceObject
->DeviceExtension
;
60 DeviceExtension
->DelayNotification
= TRUE
;
63 else if (CmBattDebug
& 0x10)
66 DbgPrint("CmBattPowerCallBack: unknown argument2 = %08x\n");
73 CmBattWakeDpc(IN PKDPC Dpc
,
74 IN PCMBATT_DEVICE_EXTENSION FdoExtension
,
75 IN PVOID SystemArgument1
,
76 IN PVOID SystemArgument2
)
78 PDEVICE_OBJECT CurrentObject
;
79 BOOLEAN AcNotify
= FALSE
;
80 PCMBATT_DEVICE_EXTENSION DeviceExtension
;
82 if (CmBattDebug
& 2) DbgPrint("CmBattWakeDpc: Entered.\n");
84 /* Loop all device objects */
85 for (CurrentObject
= FdoExtension
->DeviceObject
;
87 CurrentObject
= CurrentObject
->NextDevice
)
89 /* Turn delay flag off, we're back in S0 */
90 DeviceExtension
= CurrentObject
->DeviceExtension
;
91 DeviceExtension
->DelayNotification
= 0;
93 /* Check if this is an AC adapter */
94 if (DeviceExtension
->FdoType
== CmBattAcAdapter
)
96 /* Was there a pending notify? */
97 if (DeviceExtension
->ArFlag
& CMBATT_AR_NOTIFY
)
99 /* We'll send a notify on the next pass */
101 DeviceExtension
->ArFlag
= 0;
102 if (CmBattDebug
& 0x20)
103 DbgPrint("CmBattWakeDpc: AC adapter notified\n");
108 /* Loop the device objects again */
109 for (CurrentObject
= FdoExtension
->DeviceObject
;
111 CurrentObject
= CurrentObject
->NextDevice
)
113 /* Check if this is a battery */
114 DeviceExtension
= CurrentObject
->DeviceExtension
;
115 if (DeviceExtension
->FdoType
== CmBattBattery
)
117 /* Check what ARs are pending */
118 ArFlag
= DeviceExtension
->ArFlag
;
119 if (CmBattDebug
& 0x20)
120 DbgPrint("CmBattWakeDpc: Performing delayed ARs: %01x\n", ArFlag
);
122 /* Insert notification, clear the lock value */
123 if (ArFlag
& CMBATT_AR_INSERT
) InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
125 /* Removal, clear the battery tag */
126 if (ArFlag
& CMBATT_AR_REMOVE
) DeviceExtension
->Tag
= 0;
128 /* Notification (or AC/DC adapter change from first pass above) */
129 if ((ArFlag
& CMBATT_AR_NOTIFY
) || (AcNotify
))
131 /* Notify the class driver */
132 BatteryClassStatusNotify(DeviceExtension
->ClassData
);
140 CmBattNotifyHandler(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
141 IN ULONG NotifyValue
)
144 PCMBATT_DEVICE_EXTENSION FdoExtension
;
145 PDEVICE_OBJECT DeviceObject
;
147 if (CmBattDebug
& (CMBATT_ACPI_ASSERT
| CMBATT_PNP_INFO
))
148 DbgPrint("CmBattNotifyHandler: CmBatt 0x%08x Type %d Number %d Notify Value: %x\n",
150 DeviceExtension
->FdoType
,
151 DeviceExtension
->DeviceId
,
154 /* Check what kind of notification was received */
157 /* ACPI Specification says is sends a "Bus Check" when power source changes */
160 /* We treat it as possible physical change */
161 DeviceExtension
->ArFlag
|= (CMBATT_AR_NOTIFY
| CMBATT_AR_INSERT
);
162 if ((DeviceExtension
->Tag
) &&
163 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
164 DbgPrint("CmBattNotifyHandler: Received battery #%x insertion, but tag was not invalid.\n",
165 DeviceExtension
->DeviceId
);
168 /* Status of the battery has changed */
169 case ACPI_BATT_NOTIFY_STATUS
:
171 /* All we'll do is notify the class driver */
172 DeviceExtension
->ArFlag
|= CMBATT_AR_NOTIFY
;
175 /* Information on the battery has changed, such as physical presence */
176 case ACPI_DEVICE_CHECK
:
177 case ACPI_BATT_NOTIFY_INFO
:
179 /* Reset all state and let the class driver re-evaluate it all */
180 DeviceExtension
->ArFlag
|= (CMBATT_AR_NOTIFY
|
187 if (CmBattDebug
& CMBATT_PNP_INFO
)
188 DbgPrint("CmBattNotifyHandler: Unknown Notify Value: %x\n", NotifyValue
);
191 /* Check if we're supposed to delay the notification till later */
192 if (DeviceExtension
->DelayNotification
)
194 /* We'll handle this when we get a status query later on */
195 if (CmBattDebug
& CMBATT_PNP_INFO
)
196 DbgPrint("CmBattNotifyHandler: Notification delayed: ARs = %01x\n",
197 DeviceExtension
->ArFlag
);
201 /* We're going to handle this now */
202 if (CmBattDebug
& CMBATT_PNP_INFO
)
203 DbgPrint("CmBattNotifyHandler: Performing ARs: %01x\n", DeviceExtension
->ArFlag
);
205 /* Check if this is a battery or AC adapter notification */
206 if (DeviceExtension
->FdoType
== CmBattBattery
)
208 /* Reset the current trip point */
209 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
211 /* Check what ARs have to be done */
212 ArFlag
= DeviceExtension
->ArFlag
;
214 /* New battery inserted, reset lock value */
215 if (ArFlag
& CMBATT_AR_INSERT
) InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
217 /* Check if the battery may have been removed */
218 if (ArFlag
& CMBATT_AR_REMOVE
) DeviceExtension
->Tag
= 0;
220 /* Check if there's been any sort of change to the battery */
221 if (ArFlag
& CMBATT_AR_NOTIFY
)
223 /* We'll probably end up re-evaluating _BIF and _BST */
224 DeviceExtension
->NotifySent
= TRUE
;
225 BatteryClassStatusNotify(DeviceExtension
->ClassData
);
228 else if (DeviceExtension
->ArFlag
& CMBATT_AR_NOTIFY
)
230 /* The only known notification is AC/DC change. Loop device objects. */
231 for (DeviceObject
= DeviceExtension
->FdoDeviceObject
->DriverObject
->DeviceObject
;
233 DeviceObject
= DeviceObject
->NextDevice
)
235 /* Is this a battery? */
236 FdoExtension
= DeviceObject
->DeviceExtension
;
237 if (FdoExtension
->FdoType
== CmBattBattery
)
239 /* Send a notification to the class driver */
240 FdoExtension
->NotifySent
= TRUE
;
241 BatteryClassStatusNotify(FdoExtension
->ClassData
);
246 /* ARs have been processed */
247 DeviceExtension
->ArFlag
= 0;
252 CmBattUnload(IN PDRIVER_OBJECT DriverObject
)
254 if (CmBattDebug
& CMBATT_GENERIC_INFO
) DPRINT("CmBattUnload: \n");
256 /* Check if we have a registered power callback */
257 if (CmBattPowerCallBackObject
)
260 ExUnregisterCallback(CmBattPowerCallBackRegistration
);
261 ObfDereferenceObject(CmBattPowerCallBackObject
);
264 /* Free the registry buffer if it exists */
265 if (GlobalRegistryPath
.Buffer
) ExFreePool(GlobalRegistryPath
.Buffer
);
267 /* Make sure we don't still have references to the DO */
268 if ((DriverObject
->DeviceObject
) && (CmBattDebug
& CMBATT_GENERIC_WARNING
))
270 DbgPrint("Unload called before all devices removed.\n");
276 CmBattVerifyStaticInfo(PCMBATT_DEVICE_EXTENSION DeviceExtension
,
280 return STATUS_NOT_IMPLEMENTED
;
285 CmBattOpenClose(IN PDEVICE_OBJECT DeviceObject
,
288 NTSTATUS Status
= STATUS_SUCCESS
;
289 PIO_STACK_LOCATION IoStackLocation
;
292 PCMBATT_DEVICE_EXTENSION DeviceExtension
;
294 if (CmBattDebug
& CMBATT_GENERIC_INFO
) DPRINT("CmBattOpenClose\n");
296 /* Grab the device extension and lock it */
297 DeviceExtension
= DeviceObject
->DeviceExtension
;
298 ExAcquireFastMutex(&DeviceExtension
->FastMutex
);
300 /* Check if someone is trying to open a device that doesn't exist yet */
301 Count
= DeviceExtension
->HandleCount
;
302 if (Count
== 0xFFFFFFFF)
304 /* Fail the request */
305 Status
= STATUS_NO_SUCH_DEVICE
;
306 if (CmBattDebug
& CMBATT_PNP_INFO
)
308 DbgPrint("CmBattOpenClose: Failed (UID = %x)(device being removed).\n",
309 DeviceExtension
->Tag
);
314 /* Check if this is an open or close */
315 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
316 Major
= IoStackLocation
->MajorFunction
;
317 if (Major
== IRP_MJ_CREATE
)
319 /* Increment the open count */
320 DeviceExtension
->HandleCount
= Count
+ 1;
321 if (CmBattDebug
& CMBATT_PNP_INFO
)
323 DbgPrint("CmBattOpenClose: Open (DeviceNumber = %x)(count = %x).\n",
324 DeviceExtension
->DeviceId
, Count
+ 1);
327 else if (Major
== IRP_MJ_CLOSE
)
329 /* Decrement the open count */
330 DeviceExtension
->HandleCount
= Count
- 1;
331 if (CmBattDebug
& CMBATT_PNP_INFO
)
333 DbgPrint("CmBattOpenClose: Close (DeviceNumber = %x)(count = %x).\n",
334 DeviceExtension
->DeviceId
, Count
+ 1);
339 /* Release lock and complete request */
340 ExReleaseFastMutex(&DeviceExtension
->FastMutex
);
341 Irp
->IoStatus
.Status
= Status
;
342 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
348 CmBattIoctl(IN PDEVICE_OBJECT DeviceObject
,
351 PCMBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
353 PIO_STACK_LOCATION IoStackLocation
;
354 ULONG IoControlCode
, OutputBufferLength
, InputBufferLength
;
356 if (CmBattDebug
& 2) DbgPrint("CmBattIoctl\n");
358 /* Acquire the remove lock */
359 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, 0);
360 if (!NT_SUCCESS(Status
))
362 /* It's too late, fail */
363 Irp
->IoStatus
.Status
= STATUS_DEVICE_REMOVED
;
364 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
365 return STATUS_DEVICE_REMOVED
;
368 /* There's nothing to do for an AC adapter */
369 if (DeviceExtension
->FdoType
== CmBattAcAdapter
)
371 /* Pass it down, and release the remove lock */
372 IoSkipCurrentIrpStackLocation(Irp
);
373 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
374 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
378 /* Send to class driver */
379 Status
= BatteryClassIoctl(DeviceExtension
->ClassData
, Irp
);
380 if (Status
== STATUS_NOT_SUPPORTED
)
382 /* Read IOCTL information from IRP stack */
383 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
384 IoControlCode
= IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
;
385 OutputBufferLength
= IoStackLocation
->Parameters
.DeviceIoControl
.OutputBufferLength
;
386 InputBufferLength
= IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
;
388 DbgPrint("CmBattIoctl: Received Direct Access IOCTL %x\n", IoControlCode
);
390 /* Handle internal IOCTLs */
391 switch (IoControlCode
)
393 case IOCTL_BATTERY_QUERY_UNIQUE_ID
:
395 /* Data is 4 bytes long */
396 if (OutputBufferLength
== sizeof(ULONG
))
399 Status
= CmBattGetUniqueId(DeviceExtension
->PdoDeviceObject
,
400 Irp
->AssociatedIrp
.SystemBuffer
);
401 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ULONG
);
405 /* Buffer size invalid */
406 Status
= STATUS_INVALID_BUFFER_SIZE
;
410 case IOCTL_BATTERY_QUERY_STA
:
412 /* Data is 4 bytes long */
413 if (OutputBufferLength
== sizeof(ULONG
))
416 Status
= CmBattGetStaData(DeviceExtension
->PdoDeviceObject
,
417 Irp
->AssociatedIrp
.SystemBuffer
);
418 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ULONG
);
422 /* Buffer size invalid */
423 Status
= STATUS_INVALID_BUFFER_SIZE
;
427 case IOCTL_BATTERY_QUERY_PSR
:
429 /* Data is 4 bytes long */
430 if (OutputBufferLength
== sizeof(ULONG
))
432 /* Do we have an AC adapter? */
436 Status
= CmBattGetPsrData(AcAdapterPdo
,
437 Irp
->AssociatedIrp
.SystemBuffer
);
438 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ULONG
);
442 /* No adapter, just a battery, so fail */
443 Status
= STATUS_NO_SUCH_DEVICE
;
448 /* Buffer size invalid */
449 Status
= STATUS_INVALID_BUFFER_SIZE
;
453 case IOCTL_BATTERY_SET_TRIP_POINT
:
455 /* Data is 4 bytes long */
456 if (InputBufferLength
== sizeof(ULONG
))
459 Status
= CmBattSetTripPpoint(DeviceExtension
,
460 *(PULONG
)Irp
->AssociatedIrp
.SystemBuffer
);
461 Irp
->IoStatus
.Information
= 0;
465 /* Buffer size invalid */
466 Status
= STATUS_INVALID_BUFFER_SIZE
;
470 case IOCTL_BATTERY_QUERY_BIF
:
472 /* Data is 1060 bytes long */
473 if (OutputBufferLength
== sizeof(ACPI_BIF_DATA
))
476 Status
= CmBattGetBifData(DeviceExtension
,
477 Irp
->AssociatedIrp
.SystemBuffer
);
478 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ACPI_BIF_DATA
);
482 /* Buffer size invalid */
483 Status
= STATUS_INVALID_BUFFER_SIZE
;
487 case IOCTL_BATTERY_QUERY_BST
:
489 /* Data is 16 bytes long */
490 if (OutputBufferLength
== sizeof(ACPI_BST_DATA
))
493 Status
= CmBattGetBstData(DeviceExtension
,
494 Irp
->AssociatedIrp
.SystemBuffer
);
495 if (NT_SUCCESS(Status
)) Irp
->IoStatus
.Information
= sizeof(ACPI_BST_DATA
);
499 /* Buffer size invalid */
500 Status
= STATUS_INVALID_BUFFER_SIZE
;
506 /* Unknown, let us pass it on to ACPI */
507 if (CmBattDebug
& 0xC)
508 DbgPrint("CmBattIoctl: Unknown IOCTL %x\n", IoControlCode
);
512 /* Did someone pick it up? */
513 if (Status
!= STATUS_NOT_SUPPORTED
)
515 /* Complete the request */
516 Irp
->IoStatus
.Status
= Status
;
517 IofCompleteRequest(Irp
, IO_NO_INCREMENT
);
521 /* Still unsupported, try ACPI */
522 IoSkipCurrentIrpStackLocation(Irp
);
523 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
527 /* Release the remove lock and return status */
528 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
534 CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
537 PDEVICE_OBJECT PdoDevice
;
542 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
543 DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n",
544 *Tag
, DeviceExtension
, DeviceExtension
->DeviceId
);
546 /* Get PDO and clear notification flag */
547 PdoDevice
= DeviceExtension
->PdoDeviceObject
;
548 DeviceExtension
->NotifySent
= 0;
550 /* Get _STA from PDO (we need the machine status, not the battery status) */
551 Status
= CmBattGetStaData(PdoDevice
, &StaData
);
552 if (NT_SUCCESS(Status
))
554 /* Is a battery present? */
555 if (StaData
& ACPI_STA_BATTERY_PRESENT
)
557 /* Do we not have a tag yet? */
558 if (!DeviceExtension
->Tag
)
560 /* Set the new tag value, reset tags if we reached the maximum */
561 NewTag
= DeviceExtension
->TagData
;
562 if (DeviceExtension
->TagData
++ == 0xFFFFFFFF) NewTag
= 1;
563 DeviceExtension
->Tag
= NewTag
;
564 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
565 DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension
->Tag
);
567 /* Reset trip point data */
568 DeviceExtension
->TripPointOld
= 0;
569 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
571 /* Clear AR lock and set new interrupt time */
572 InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
573 DeviceExtension
->InterruptTime
= KeQueryInterruptTime();
578 /* No battery, so no tag */
579 DeviceExtension
->Tag
= 0;
580 Status
= STATUS_NO_SUCH_DEVICE
;
584 /* Return the tag and status result */
585 *Tag
= DeviceExtension
->Tag
;
586 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
587 DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag
, Status
);
593 CmBattDisableStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
)
597 if (CmBattDebug
& 0xA) DbgPrint("CmBattDisableStatusNotify\n");
599 /* Do we have a trip point */
600 if (DeviceExtension
->TripPointSet
)
602 /* Is there a current value set? */
603 if (DeviceExtension
->TripPointValue
)
605 /* Reset it back to 0 */
606 DeviceExtension
->TripPointValue
= 0;
607 Status
= CmBattSetTripPpoint(DeviceExtension
, 0);
608 if (!NT_SUCCESS(Status
))
610 /* If it failed, set unknown/invalid value */
611 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
613 DbgPrint("CmBattDisableStatusNotify: SetTripPoint failed - %x\n", Status
);
618 /* No trip point set, so this is a successful no-op */
619 Status
= STATUS_SUCCESS
;
624 /* Nothing we can do */
625 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
634 CmBattSetStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
636 IN PBATTERY_NOTIFY BatteryNotify
)
639 ACPI_BST_DATA BstData
;
640 ULONG Capacity
, NewTripPoint
, TripPoint
, DesignVoltage
;
643 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
644 DbgPrint("CmBattSetStatusNotify: Tag (%d) Target(0x%x)\n",
645 BatteryTag
, BatteryNotify
->LowCapacity
);
647 /* Update any ACPI evaluations */
648 Status
= CmBattVerifyStaticInfo(DeviceExtension
, BatteryTag
);
649 if (!NT_SUCCESS(Status
)) return Status
;
651 /* Trip point not supported, fail */
652 if (!DeviceExtension
->TripPointSet
) return STATUS_OBJECT_NAME_NOT_FOUND
;
654 /* Are both capacities known? */
655 if ((BatteryNotify
->HighCapacity
== BATTERY_UNKNOWN_CAPACITY
) ||
656 (BatteryNotify
->LowCapacity
== BATTERY_UNKNOWN_CAPACITY
))
658 /* We can't set trip points without these */
659 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
660 DbgPrint("CmBattSetStatusNotify: Failing request because of BATTERY_UNKNOWN_CAPACITY.\n");
661 return STATUS_NOT_SUPPORTED
;
664 /* Is the battery charging? */
665 Charging
= DeviceExtension
->BstData
.State
& ACPI_BATT_STAT_CHARGING
;
668 /* Then the trip point is when we hit the cap */
669 Capacity
= BatteryNotify
->HighCapacity
;
670 NewTripPoint
= BatteryNotify
->HighCapacity
;
674 /* Otherwise it's when we discharge to the bottom */
675 Capacity
= BatteryNotify
->LowCapacity
;
676 NewTripPoint
= BatteryNotify
->LowCapacity
;
679 /* Do we have data in Amps or Watts? */
680 if (DeviceExtension
->BifData
.PowerUnit
== ACPI_BATT_POWER_UNIT_AMPS
)
682 /* We need the voltage to do the conversion */
683 DesignVoltage
= DeviceExtension
->BifData
.DesignVoltage
;
684 if ((DesignVoltage
!= BATTERY_UNKNOWN_VOLTAGE
) && (DesignVoltage
))
686 /* Convert from mAh into Ah */
687 TripPoint
= 1000 * NewTripPoint
;
690 /* Scale the high trip point */
691 NewTripPoint
= (TripPoint
+ 500) / DesignVoltage
+ ((TripPoint
+ 500) % DesignVoltage
!= 0);
695 /* Scale the low trip point */
696 NewTripPoint
= (TripPoint
- 500) / DesignVoltage
- ((TripPoint
- 500) % DesignVoltage
== 0);
701 /* Without knowing the voltage, Amps are not enough data on consumption */
702 Status
= STATUS_NOT_SUPPORTED
;
703 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
704 DbgPrint("CmBattSetStatusNotify: Can't calculate BTP, DesignVoltage = 0x%08x\n",
710 /* Make it trip just one past the charge cap */
713 else if (NewTripPoint
> 0)
715 /* Make it trip just one below the drain cap */
719 /* Do we actually have a new trip point? */
720 if (NewTripPoint
== DeviceExtension
->TripPointValue
)
722 /* No, so there is no work to be done */
723 if (CmBattDebug
& CMBATT_GENERIC_STATUS
)
724 DbgPrint("CmBattSetStatusNotify: Keeping original setting: %X\n", DeviceExtension
->TripPointValue
);
725 return STATUS_SUCCESS
;
728 /* Set the trip point with ACPI and check for success */
729 DeviceExtension
->TripPointValue
= NewTripPoint
;
730 Status
= CmBattSetTripPpoint(DeviceExtension
, NewTripPoint
);
731 if (!(NewTripPoint
) && (Capacity
)) Status
= STATUS_NOT_SUPPORTED
;
732 if (!NT_SUCCESS(Status
))
734 /* We failed to set the trip point, or there wasn't one settable */
735 DeviceExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
736 if (CmBattDebug
& (CMBATT_GENERIC_WARNING
| CMBATT_ACPI_WARNING
))
737 DbgPrint("CmBattSetStatusNotify: SetTripPoint failed - %x\n", Status
);
741 /* Read the new BST data to see the latest state */
742 Status
= CmBattGetBstData(DeviceExtension
, &BstData
);
743 if (!NT_SUCCESS(Status
))
745 /* We'll return failure to the caller */
746 if (CmBattDebug
& (CMBATT_GENERIC_WARNING
| CMBATT_ACPI_WARNING
))
747 DbgPrint("CmBattSetStatusNotify: GetBstData - %x\n", Status
);
749 else if ((Charging
) && (BstData
.RemainingCapacity
>= NewTripPoint
))
751 /* We are charging and our capacity is past the trip point, so trip now */
752 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
753 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n",
754 NewTripPoint
, BstData
.RemainingCapacity
);
755 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
757 else if ((BstData
.RemainingCapacity
) && (Capacity
))
759 /* We are discharging, and our capacity is below the trip point, trip now */
760 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
761 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n",
762 NewTripPoint
, BstData
.RemainingCapacity
);
763 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
766 /* All should've went well if we got here, unless BST failed... return! */
767 if (CmBattDebug
& CMBATT_GENERIC_STATUS
)
768 DbgPrint("CmBattSetStatusNotify: Want %X CurrentCap %X\n",
769 Capacity
, DeviceExtension
->RemainingCapacity
);
770 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
771 DbgPrint("CmBattSetStatusNotify: Set to: [%#08lx][%#08lx][%#08lx] Status %x\n",
772 BatteryNotify
->PowerState
,
773 BatteryNotify
->LowCapacity
,
774 BatteryNotify
->HighCapacity
);
780 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
786 ULONG DesignVoltage
, PresentRate
, RemainingCapacity
;
788 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
789 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension
, Tag
);
791 /* Validate ACPI data */
792 Status
= CmBattVerifyStaticInfo(DeviceExtension
, Tag
);
793 if (!NT_SUCCESS(Status
)) return Status
;
795 /* Check for delayed status notifications */
796 if (DeviceExtension
->DelayNotification
)
798 /* Process them now and don't do any other work */
799 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
803 /* Get _BST from ACPI */
804 Status
= CmBattGetBstData(DeviceExtension
, &DeviceExtension
->BstData
);
805 if (!NT_SUCCESS(Status
))
808 InterlockedExchange(&DeviceExtension
->ArLockValue
, 0);
812 /* Clear current BST information */
813 DeviceExtension
->State
= 0;
814 DeviceExtension
->RemainingCapacity
= 0;
815 DeviceExtension
->PresentVoltage
= 0;
816 DeviceExtension
->Rate
= 0;
818 /* Get battery state */
819 BstState
= DeviceExtension
->BstData
.State
;
821 /* Is the battery both charging and discharging? */
822 if ((BstState
& ACPI_BATT_STAT_DISCHARG
) && (BstState
& ACPI_BATT_STAT_CHARGING
) &&
823 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
824 DbgPrint("************************ ACPI BIOS BUG ********************\n* "
825 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n"
826 "* One battery cannot be charging and discharging at the same time.\n",
829 /* Is the battery discharging? */
830 if (BstState
& ACPI_BATT_STAT_DISCHARG
)
832 /* Set power state and check if it just started discharging now */
833 DeviceExtension
->State
|= BATTERY_DISCHARGING
;
834 if (!(DeviceExtension
->State
& ACPI_BATT_STAT_DISCHARG
))
836 /* Remember the time when the state changed */
837 DeviceExtension
->InterruptTime
= KeQueryInterruptTime();
840 else if (BstState
& ACPI_BATT_STAT_CHARGING
)
842 /* Battery is charging, update power state */
843 DeviceExtension
->State
|= (BATTERY_CHARGING
| BATTERY_POWER_ON_LINE
);
846 /* Is the battery in a critical state? */
847 if (BstState
& ACPI_BATT_STAT_CRITICAL
) DeviceExtension
->State
|= BATTERY_CRITICAL
;
849 /* Read the voltage data */
850 DeviceExtension
->PresentVoltage
= DeviceExtension
->BstData
.PresentVoltage
;
852 /* Check if we have an A/C adapter */
855 /* Query information on it */
856 CmBattGetPsrData(AcAdapterPdo
, &PsrData
);
860 /* Otherwise, check if the battery is charging */
861 if (BstState
& ACPI_BATT_STAT_CHARGING
)
863 /* Then we'll assume there's a charger */
868 /* Assume no charger */
873 /* Is there a charger? */
876 /* Set the power state flag to reflect this */
877 DeviceExtension
->State
|= BATTERY_POWER_ON_LINE
;
878 if (CmBattDebug
& (CMBATT_GENERIC_INFO
| CMBATT_GENERIC_STATUS
))
879 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n");
881 else if (CmBattDebug
& (CMBATT_GENERIC_INFO
| CMBATT_GENERIC_STATUS
))
883 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n");
886 /* Get some data we'll need */
887 DesignVoltage
= DeviceExtension
->BifData
.DesignVoltage
;
888 PresentRate
= DeviceExtension
->BstData
.PresentRate
;
889 RemainingCapacity
= DeviceExtension
->BstData
.RemainingCapacity
;
891 /* Check if we have battery data in Watts instead of Amps */
892 if (DeviceExtension
->BifData
.PowerUnit
== ACPI_BATT_POWER_UNIT_WATTS
)
894 /* Get the data from the BST */
895 DeviceExtension
->RemainingCapacity
= RemainingCapacity
;
896 DeviceExtension
->Rate
= PresentRate
;
898 /* Check if the rate is invalid */
899 if (PresentRate
> CM_MAX_VALUE
)
901 /* Set an unknown rate and don't touch the old value */
902 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
903 if ((PresentRate
!= CM_UNKNOWN_VALUE
) && (CmBattDebug
& CMBATT_ACPI_WARNING
))
905 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n");
906 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate
);
910 else if ((DesignVoltage
!= CM_UNKNOWN_VALUE
) && (DesignVoltage
))
912 /* We have voltage data, what about capacity? */
913 if (RemainingCapacity
== CM_UNKNOWN_VALUE
)
915 /* Unable to calculate it */
916 DeviceExtension
->RemainingCapacity
= BATTERY_UNKNOWN_CAPACITY
;
917 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
919 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n");
920 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n");
925 /* Compute the capacity with the information we have */
926 DeviceExtension
->RemainingCapacity
= (DesignVoltage
* RemainingCapacity
+ 500) / 1000;
929 /* Check if we have a rate */
930 if (PresentRate
!= CM_UNKNOWN_VALUE
)
932 /* Make sure the rate isn't too large */
933 if (PresentRate
> (-500 / DesignVoltage
))
935 /* It is, so set unknown state */
936 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
937 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
939 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
940 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate
);
944 /* Compute the rate */
945 DeviceExtension
->Rate
= (PresentRate
* DesignVoltage
+ 500) / 1000;
949 /* We don't have a rate, so set unknown value */
950 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
951 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
953 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
954 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n");
960 /* We have no rate, and no capacity, set unknown values */
961 DeviceExtension
->Rate
= BATTERY_UNKNOWN_RATE
;
962 DeviceExtension
->RemainingCapacity
= BATTERY_UNKNOWN_CAPACITY
;
963 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
965 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n");
966 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage
);
970 /* Check if we have an unknown rate */
971 if (DeviceExtension
->Rate
== BATTERY_UNKNOWN_RATE
)
973 /* The battery is discharging but we don't know by how much... this is bad! */
974 if ((BstState
& ACPI_BATT_STAT_DISCHARG
) &&
975 (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_WARNING
)))
976 DbgPrint("CmBattGetBatteryStatus: battery rate is unkown when battery is not charging!\n");
978 else if (DeviceExtension
->State
& BATTERY_DISCHARGING
)
980 /* The battery is discharging, so treat the rate as a negative rate */
981 DeviceExtension
->Rate
= -DeviceExtension
->Rate
;
983 else if (!(DeviceExtension
->State
& BATTERY_CHARGING
) && (DeviceExtension
->Rate
))
985 /* We are not charging, not discharging, but have a rate? Ignore it! */
986 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
987 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n",
988 DeviceExtension
->Rate
);
989 DeviceExtension
->Rate
= 0;
993 return STATUS_SUCCESS
;
998 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension
,
1000 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel
,
1001 IN OPTIONAL LONG AtRate
,
1003 IN ULONG BufferLength
,
1004 OUT PULONG ReturnedLength
)
1007 PVOID QueryData
= NULL
;
1008 ULONG QueryLength
= 0;
1009 ULONG RemainingTime
= 0;
1010 ANSI_STRING TempString
;
1011 UNICODE_STRING TempString2
;
1012 WCHAR InfoBuffer
[256];
1013 WCHAR TempBuffer
[256];
1014 UNICODE_STRING InfoString
;
1015 ULONG RemainingCapacity
;
1016 BATTERY_REPORTING_SCALE BatteryReportingScale
[2];
1019 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
1020 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n",
1022 FdoExtension
->DeviceId
,
1025 /* Check ACPI Data */
1026 Status
= CmBattVerifyStaticInfo(FdoExtension
, Tag
);
1027 if (!NT_SUCCESS(Status
)) return Status
;
1029 /* Check what caller wants */
1032 case BatteryInformation
:
1033 /* Just return our static information */
1034 QueryData
= &FdoExtension
->BatteryInformation
;
1035 QueryLength
= sizeof(BATTERY_INFORMATION
);
1038 case BatteryGranularityInformation
:
1040 /* Return our static information, we have two scales */
1041 BatteryReportingScale
[0].Granularity
= FdoExtension
->BatteryCapacityGranularity1
;
1042 BatteryReportingScale
[0].Capacity
= FdoExtension
->BatteryInformation
.DefaultAlert1
;
1043 BatteryReportingScale
[1].Granularity
= FdoExtension
->BatteryCapacityGranularity2
;
1044 BatteryReportingScale
[1].Capacity
= FdoExtension
->BatteryInformation
.DesignedCapacity
;
1045 QueryData
= BatteryReportingScale
;
1046 QueryLength
= sizeof(BATTERY_REPORTING_SCALE
) * 2;
1049 case BatteryEstimatedTime
:
1051 /* Check if it's been more than 2 1/2 minutes since the last change */
1052 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension
->InterruptTime
))
1054 /* Get new battery status */
1055 CmBattGetBatteryStatus(FdoExtension
, FdoExtension
->Tag
);
1057 /* If the caller didn't specify a rate, use our static one */
1059 if (!Rate
) Rate
= FdoExtension
->Rate
;
1061 /* If we don't have a valid negative rate, use unknown value */
1062 if (Rate
>= 0) Rate
= BATTERY_UNKNOWN_RATE
;
1064 /* Grab the remaining capacity */
1065 RemainingCapacity
= FdoExtension
->RemainingCapacity
;
1067 /* See if we don't know one or the other */
1068 if ((Rate
== BATTERY_UNKNOWN_RATE
) ||
1069 (RemainingCapacity
== BATTERY_UNKNOWN_CAPACITY
))
1071 /* If the battery is discharging, we can't give out a time */
1072 if ((FdoExtension
->BstData
.State
& ACPI_BATT_STAT_DISCHARG
) &&
1073 (CmBattDebug
& CMBATT_GENERIC_WARNING
))
1074 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n");
1076 /* Check if we don't have a rate and capacity is going down */
1077 if ((FdoExtension
->Rate
== BATTERY_UNKNOWN_RATE
) &&
1078 (FdoExtension
->BstData
.State
& ACPI_BATT_STAT_DISCHARG
))
1080 /* We have to fail, since we lack data */
1081 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1082 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1083 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n");
1086 /* If we don't have capacity, the rate is useless */
1087 if (RemainingCapacity
== BATTERY_UNKNOWN_CAPACITY
)
1089 /* We have to fail the request */
1090 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1091 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1092 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n");
1097 /* We have data, but is it valid? */
1098 if (RemainingCapacity
> 0x123456)
1100 /* The capacity seems bogus, so don't use it */
1101 if (CmBattDebug
& CMBATT_ACPI_WARNING
)
1102 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n");
1106 /* Compute the remaining time in seconds, based on rate */
1107 RemainingTime
= (RemainingCapacity
* 3600) / -Rate
;
1112 /* Return the remaining time */
1113 QueryData
= &RemainingTime
;
1114 QueryLength
= sizeof(ULONG
);
1117 case BatteryDeviceName
:
1119 /* Build the model number string */
1120 RtlInitAnsiString(&TempString
, FdoExtension
->ModelNumber
);
1122 /* Convert it to Unicode */
1123 InfoString
.Buffer
= InfoBuffer
;
1124 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
1125 Status
= RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
1127 /* Return the unicode buffer */
1128 QueryData
= InfoString
.Buffer
;
1129 QueryLength
= InfoString
.Length
;
1132 case BatteryTemperature
:
1133 case BatteryManufactureDate
:
1135 /* We don't support these */
1136 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1139 case BatteryManufactureName
:
1141 /* Build the OEM info string */
1142 RtlInitAnsiString(&TempString
, FdoExtension
->OemInfo
);
1144 /* Convert it to Unicode */
1145 InfoString
.Buffer
= InfoBuffer
;
1146 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
1147 Status
= RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
1149 /* Return the unicode buffer */
1150 QueryData
= InfoString
.Buffer
;
1151 QueryLength
= InfoString
.Length
;
1154 case BatteryUniqueID
:
1156 /* Build the serial number string */
1157 RtlInitAnsiString(&TempString
, FdoExtension
->SerialNumber
);
1159 /* Convert it to Unicode */
1160 InfoString
.Buffer
= InfoBuffer
;
1161 InfoString
.MaximumLength
= sizeof(InfoBuffer
);
1162 RtlAnsiStringToUnicodeString(&InfoString
, &TempString
, 0);
1164 /* Setup a temporary string for concatenation */
1165 TempString2
.Buffer
= TempBuffer
;
1166 TempString2
.MaximumLength
= sizeof(TempBuffer
);
1168 /* Check if there's an OEM string */
1169 if (FdoExtension
->OemInfo
[0])
1171 /* Build the OEM info string */
1172 RtlInitAnsiString(&TempString
, FdoExtension
->OemInfo
);
1174 /* Convert it to Unicode and append it */
1175 RtlAnsiStringToUnicodeString(&TempString2
, &TempString
, 0);
1176 RtlAppendUnicodeStringToString(&InfoString
, &TempString2
);
1179 /* Build the model number string */
1180 RtlInitAnsiString(&TempString
, FdoExtension
->ModelNumber
);
1182 /* Convert it to Unicode and append it */
1183 RtlAnsiStringToUnicodeString(&TempString2
, &TempString
, 0);
1184 RtlAppendUnicodeStringToString(&InfoString
, &TempString2
);
1186 /* Return the final appended string */
1187 QueryData
= InfoString
.Buffer
;
1188 QueryLength
= InfoString
.Length
;
1193 /* Everything else is unknown */
1194 Status
= STATUS_INVALID_PARAMETER
;
1198 /* Return the required length and check if the caller supplied enough */
1199 *ReturnedLength
= QueryLength
;
1200 if (BufferLength
< QueryLength
) Status
= STATUS_BUFFER_TOO_SMALL
;
1202 /* Copy the data if there's enough space and it exists */
1203 if ((NT_SUCCESS(Status
)) && (QueryData
)) RtlCopyMemory(Buffer
, QueryData
, QueryLength
);
1205 /* Return function result */
1211 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension
,
1213 IN PBATTERY_STATUS BatteryStatus
)
1217 if (CmBattDebug
& (CMBATT_ACPI_WARNING
| CMBATT_GENERIC_INFO
))
1218 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag
, DeviceExtension
->DeviceId
);
1220 /* Query ACPI information */
1221 Status
= CmBattGetBatteryStatus(DeviceExtension
, Tag
);
1222 if (NT_SUCCESS(Status
))
1224 BatteryStatus
->PowerState
= DeviceExtension
->State
;
1225 BatteryStatus
->Capacity
= DeviceExtension
->RemainingCapacity
;
1226 BatteryStatus
->Voltage
= DeviceExtension
->PresentVoltage
;
1227 BatteryStatus
->Rate
= DeviceExtension
->Rate
;
1231 if (CmBattDebug
& (CMBATT_GENERIC_INFO
))
1232 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n",
1233 BatteryStatus
->PowerState
,
1234 BatteryStatus
->Capacity
,
1235 BatteryStatus
->Voltage
,
1236 BatteryStatus
->Rate
);
1242 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1243 IN PUNICODE_STRING RegistryPath
)
1246 PDRIVER_EXTENSION DriverExtension
;
1247 OBJECT_ATTRIBUTES ObjectAttributes
;
1248 UNICODE_STRING CallbackName
;
1250 /* Allocate registry path */
1251 GlobalRegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(UNICODE_NULL
);
1252 GlobalRegistryPath
.Length
= RegistryPath
->Length
;
1253 GlobalRegistryPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1254 GlobalRegistryPath
.MaximumLength
,
1256 if (!GlobalRegistryPath
.Buffer
)
1258 /* Fail if we're out of memory this early */
1259 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1260 DbgPrint("CmBatt: Couldn't allocate pool for registry path.");
1261 return STATUS_INSUFFICIENT_RESOURCES
;
1264 /* Buffer allocated, copy the string */
1265 RtlCopyUnicodeString(&GlobalRegistryPath
, RegistryPath
);
1266 if (CmBattDebug
& CMBATT_GENERIC_INFO
)
1267 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n",
1269 RegistryPath
->Buffer
);
1271 /* Setup the major dispatchers */
1272 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = CmBattOpenClose
;
1273 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = CmBattOpenClose
;
1274 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = CmBattIoctl
;
1275 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = CmBattPowerDispatch
;
1276 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = CmBattPnpDispatch
;
1277 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = CmBattSystemControl
;
1279 /* And the unload routine */
1280 DriverObject
->DriverUnload
= CmBattUnload
;
1282 /* And the add device routine */
1283 DriverExtension
= DriverObject
->DriverExtension
;
1284 DriverExtension
->AddDevice
= CmBattAddDevice
;
1286 /* Create a power callback */
1287 RtlInitUnicodeString(&CallbackName
, L
"\\Callback\\PowerState");
1288 InitializeObjectAttributes(&ObjectAttributes
,
1293 Status
= ExCreateCallback(&CmBattPowerCallBackObject
, &ObjectAttributes
, 0, TRUE
);
1294 if (!NT_SUCCESS(Status
))
1296 /* No callback, fail */
1297 CmBattPowerCallBackObject
= 0;
1298 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1299 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status
);
1303 /* Register the power callback now */
1304 CmBattPowerCallBackRegistration
= ExRegisterCallback(CmBattPowerCallBackObject
,
1305 (PVOID
)CmBattPowerCallBack
,
1307 if (CmBattPowerCallBackRegistration
)
1309 /* Last thing: setup our DPC and timer for battery wake */
1310 KeInitializeDpc(&CmBattWakeDpcObject
, (PVOID
)CmBattWakeDpc
, DriverObject
);
1311 KeInitializeTimer(&CmBattWakeDpcTimerObject
);
1315 ObfDereferenceObject(CmBattPowerCallBackObject
);
1316 if (CmBattDebug
& CMBATT_GENERIC_WARNING
)
1317 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n");
1321 Status
= STATUS_SUCCESS
;
1324 /* Return failure or success */