Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencmbatt.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS ACPI-Compliant Control Method Battery 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: boot/drivers/bus/acpi/cmbatt/cmbatt.c 00005 * PURPOSE: Main Initialization Code and IRP Handling 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include "cmbatt.h" 00012 00013 /* GLOBALS ********************************************************************/ 00014 00015 ULONG CmBattDebug; 00016 PCALLBACK_OBJECT CmBattPowerCallBackObject; 00017 PVOID CmBattPowerCallBackRegistration; 00018 UNICODE_STRING GlobalRegistryPath; 00019 KTIMER CmBattWakeDpcTimerObject; 00020 KDPC CmBattWakeDpcObject; 00021 PDEVICE_OBJECT AcAdapterPdo; 00022 LARGE_INTEGER CmBattWakeDpcDelay; 00023 00024 /* FUNCTIONS ******************************************************************/ 00025 00026 VOID 00027 NTAPI 00028 CmBattPowerCallBack(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 00029 IN ULONG Action, 00030 IN ULONG Value) 00031 { 00032 BOOLEAN Cancelled; 00033 PDEVICE_OBJECT DeviceObject; 00034 if (CmBattDebug & 0x10) 00035 DbgPrint("CmBattPowerCallBack: action: %d, value: %d \n", Action, Value); 00036 00037 /* Check if a transition is going to happen */ 00038 if (Action == PO_CB_SYSTEM_STATE_LOCK) 00039 { 00040 /* We have just re-entered S0: call the wake DPC in 10 seconds */ 00041 if (Value == 1) 00042 { 00043 if (CmBattDebug & 0x10) 00044 DbgPrint("CmBattPowerCallBack: Calling CmBattWakeDpc after 10 seconds.\n"); 00045 Cancelled = KeSetTimer(&CmBattWakeDpcTimerObject, CmBattWakeDpcDelay, &CmBattWakeDpcObject); 00046 if (CmBattDebug & 0x10) 00047 DbgPrint("CmBattPowerCallBack: timerCanceled = %d.\n", Cancelled); 00048 } 00049 else if (Value == 0) 00050 { 00051 /* We are exiting the S0 state: loop all devices to set the delay flag */ 00052 if (CmBattDebug & 0x10) 00053 DbgPrint("CmBattPowerCallBack: Delaying Notifications\n"); 00054 for (DeviceObject = DeviceExtension->DeviceObject; 00055 DeviceObject; 00056 DeviceObject = DeviceObject->NextDevice) 00057 { 00058 /* Set the delay flag */ 00059 DeviceExtension = DeviceObject->DeviceExtension; 00060 DeviceExtension->DelayNotification = TRUE; 00061 } 00062 } 00063 else if (CmBattDebug & 0x10) 00064 { 00065 /* Unknown value */ 00066 DbgPrint("CmBattPowerCallBack: unknown argument2 = %08x\n"); 00067 } 00068 } 00069 } 00070 00071 VOID 00072 NTAPI 00073 CmBattWakeDpc(IN PKDPC Dpc, 00074 IN PCMBATT_DEVICE_EXTENSION FdoExtension, 00075 IN PVOID SystemArgument1, 00076 IN PVOID SystemArgument2) 00077 { 00078 PDEVICE_OBJECT CurrentObject; 00079 BOOLEAN AcNotify = FALSE; 00080 PCMBATT_DEVICE_EXTENSION DeviceExtension; 00081 ULONG ArFlag; 00082 if (CmBattDebug & 2) DbgPrint("CmBattWakeDpc: Entered.\n"); 00083 00084 /* Loop all device objects */ 00085 for (CurrentObject = FdoExtension->DeviceObject; 00086 CurrentObject; 00087 CurrentObject = CurrentObject->NextDevice) 00088 { 00089 /* Turn delay flag off, we're back in S0 */ 00090 DeviceExtension = CurrentObject->DeviceExtension; 00091 DeviceExtension->DelayNotification = 0; 00092 00093 /* Check if this is an AC adapter */ 00094 if (DeviceExtension->FdoType == CmBattAcAdapter) 00095 { 00096 /* Was there a pending notify? */ 00097 if (DeviceExtension->ArFlag & CMBATT_AR_NOTIFY) 00098 { 00099 /* We'll send a notify on the next pass */ 00100 AcNotify = TRUE; 00101 DeviceExtension->ArFlag = 0; 00102 if (CmBattDebug & 0x20) 00103 DbgPrint("CmBattWakeDpc: AC adapter notified\n"); 00104 } 00105 } 00106 } 00107 00108 /* Loop the device objects again */ 00109 for (CurrentObject = FdoExtension->DeviceObject; 00110 CurrentObject; 00111 CurrentObject = CurrentObject->NextDevice) 00112 { 00113 /* Check if this is a battery */ 00114 DeviceExtension = CurrentObject->DeviceExtension; 00115 if (DeviceExtension->FdoType == CmBattBattery) 00116 { 00117 /* Check what ARs are pending */ 00118 ArFlag = DeviceExtension->ArFlag; 00119 if (CmBattDebug & 0x20) 00120 DbgPrint("CmBattWakeDpc: Performing delayed ARs: %01x\n", ArFlag); 00121 00122 /* Insert notification, clear the lock value */ 00123 if (ArFlag & CMBATT_AR_INSERT) InterlockedExchange(&DeviceExtension->ArLockValue, 0); 00124 00125 /* Removal, clear the battery tag */ 00126 if (ArFlag & CMBATT_AR_REMOVE) DeviceExtension->Tag = 0; 00127 00128 /* Notification (or AC/DC adapter change from first pass above) */ 00129 if ((ArFlag & CMBATT_AR_NOTIFY) || (AcNotify)) 00130 { 00131 /* Notify the class driver */ 00132 BatteryClassStatusNotify(DeviceExtension->ClassData); 00133 } 00134 } 00135 } 00136 } 00137 00138 VOID 00139 NTAPI 00140 CmBattNotifyHandler(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 00141 IN ULONG NotifyValue) 00142 { 00143 ULONG ArFlag; 00144 PCMBATT_DEVICE_EXTENSION FdoExtension; 00145 PDEVICE_OBJECT DeviceObject; 00146 00147 if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_PNP_INFO)) 00148 DbgPrint("CmBattNotifyHandler: CmBatt 0x%08x Type %d Number %d Notify Value: %x\n", 00149 DeviceExtension, 00150 DeviceExtension->FdoType, 00151 DeviceExtension->DeviceId, 00152 NotifyValue); 00153 00154 /* Check what kind of notification was received */ 00155 switch (NotifyValue) 00156 { 00157 /* ACPI Specification says is sends a "Bus Check" when power source changes */ 00158 case ACPI_BUS_CHECK: 00159 00160 /* We treat it as possible physical change */ 00161 DeviceExtension->ArFlag |= (CMBATT_AR_NOTIFY | CMBATT_AR_INSERT); 00162 if ((DeviceExtension->Tag) && 00163 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 00164 DbgPrint("CmBattNotifyHandler: Received battery #%x insertion, but tag was not invalid.\n", 00165 DeviceExtension->DeviceId); 00166 break; 00167 00168 /* Status of the battery has changed */ 00169 case ACPI_BATT_NOTIFY_STATUS: 00170 00171 /* All we'll do is notify the class driver */ 00172 DeviceExtension->ArFlag |= CMBATT_AR_NOTIFY; 00173 break; 00174 00175 /* Information on the battery has changed, such as physical presence */ 00176 case ACPI_DEVICE_CHECK: 00177 case ACPI_BATT_NOTIFY_INFO: 00178 00179 /* Reset all state and let the class driver re-evaluate it all */ 00180 DeviceExtension->ArFlag |= (CMBATT_AR_NOTIFY | 00181 CMBATT_AR_INSERT | 00182 CMBATT_AR_REMOVE); 00183 break; 00184 00185 default: 00186 00187 if (CmBattDebug & CMBATT_PNP_INFO) 00188 DbgPrint("CmBattNotifyHandler: Unknown Notify Value: %x\n", NotifyValue); 00189 } 00190 00191 /* Check if we're supposed to delay the notification till later */ 00192 if (DeviceExtension->DelayNotification) 00193 { 00194 /* We'll handle this when we get a status query later on */ 00195 if (CmBattDebug & CMBATT_PNP_INFO) 00196 DbgPrint("CmBattNotifyHandler: Notification delayed: ARs = %01x\n", 00197 DeviceExtension->ArFlag); 00198 return; 00199 } 00200 00201 /* We're going to handle this now */ 00202 if (CmBattDebug & CMBATT_PNP_INFO) 00203 DbgPrint("CmBattNotifyHandler: Performing ARs: %01x\n", DeviceExtension->ArFlag); 00204 00205 /* Check if this is a battery or AC adapter notification */ 00206 if (DeviceExtension->FdoType == CmBattBattery) 00207 { 00208 /* Reset the current trip point */ 00209 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 00210 00211 /* Check what ARs have to be done */ 00212 ArFlag = DeviceExtension->ArFlag; 00213 00214 /* New battery inserted, reset lock value */ 00215 if (ArFlag & CMBATT_AR_INSERT) InterlockedExchange(&DeviceExtension->ArLockValue, 0); 00216 00217 /* Check if the battery may have been removed */ 00218 if (ArFlag & CMBATT_AR_REMOVE) DeviceExtension->Tag = 0; 00219 00220 /* Check if there's been any sort of change to the battery */ 00221 if (ArFlag & CMBATT_AR_NOTIFY) 00222 { 00223 /* We'll probably end up re-evaluating _BIF and _BST */ 00224 DeviceExtension->NotifySent = TRUE; 00225 BatteryClassStatusNotify(DeviceExtension->ClassData); 00226 } 00227 } 00228 else if (DeviceExtension->ArFlag & CMBATT_AR_NOTIFY) 00229 { 00230 /* The only known notification is AC/DC change. Loop device objects. */ 00231 for (DeviceObject = DeviceExtension->FdoDeviceObject->DriverObject->DeviceObject; 00232 DeviceObject; 00233 DeviceObject = DeviceObject->NextDevice) 00234 { 00235 /* Is this a battery? */ 00236 FdoExtension = DeviceObject->DeviceExtension; 00237 if (FdoExtension->FdoType == CmBattBattery) 00238 { 00239 /* Send a notification to the class driver */ 00240 FdoExtension->NotifySent = TRUE; 00241 BatteryClassStatusNotify(FdoExtension->ClassData); 00242 } 00243 } 00244 } 00245 00246 /* ARs have been processed */ 00247 DeviceExtension->ArFlag = 0; 00248 } 00249 00250 VOID 00251 NTAPI 00252 CmBattUnload(IN PDRIVER_OBJECT DriverObject) 00253 { 00254 if (CmBattDebug & CMBATT_GENERIC_INFO) DPRINT("CmBattUnload: \n"); 00255 00256 /* Check if we have a registered power callback */ 00257 if (CmBattPowerCallBackObject) 00258 { 00259 /* Get rid of it */ 00260 ExUnregisterCallback(CmBattPowerCallBackRegistration); 00261 ObDereferenceObject(CmBattPowerCallBackObject); 00262 } 00263 00264 /* Free the registry buffer if it exists */ 00265 if (GlobalRegistryPath.Buffer) ExFreePool(GlobalRegistryPath.Buffer); 00266 00267 /* Make sure we don't still have references to the DO */ 00268 if ((DriverObject->DeviceObject) && (CmBattDebug & CMBATT_GENERIC_WARNING)) 00269 { 00270 DbgPrint("Unload called before all devices removed.\n"); 00271 } 00272 } 00273 00274 NTSTATUS 00275 NTAPI 00276 CmBattVerifyStaticInfo(PCMBATT_DEVICE_EXTENSION DeviceExtension, 00277 ULONG BatteryTag) 00278 { 00279 UNIMPLEMENTED; 00280 return STATUS_NOT_IMPLEMENTED; 00281 } 00282 00283 NTSTATUS 00284 NTAPI 00285 CmBattOpenClose(IN PDEVICE_OBJECT DeviceObject, 00286 IN PIRP Irp) 00287 { 00288 NTSTATUS Status = STATUS_SUCCESS; 00289 PIO_STACK_LOCATION IoStackLocation; 00290 UCHAR Major; 00291 ULONG Count; 00292 PCMBATT_DEVICE_EXTENSION DeviceExtension; 00293 PAGED_CODE(); 00294 if (CmBattDebug & CMBATT_GENERIC_INFO) DPRINT("CmBattOpenClose\n"); 00295 00296 /* Grab the device extension and lock it */ 00297 DeviceExtension = DeviceObject->DeviceExtension; 00298 ExAcquireFastMutex(&DeviceExtension->FastMutex); 00299 00300 /* Check if someone is trying to open a device that doesn't exist yet */ 00301 Count = DeviceExtension->HandleCount; 00302 if (Count == 0xFFFFFFFF) 00303 { 00304 /* Fail the request */ 00305 Status = STATUS_NO_SUCH_DEVICE; 00306 if (CmBattDebug & CMBATT_PNP_INFO) 00307 { 00308 DbgPrint("CmBattOpenClose: Failed (UID = %x)(device being removed).\n", 00309 DeviceExtension->Tag); 00310 } 00311 goto Complete; 00312 } 00313 00314 /* Check if this is an open or close */ 00315 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 00316 Major = IoStackLocation->MajorFunction; 00317 if (Major == IRP_MJ_CREATE) 00318 { 00319 /* Increment the open count */ 00320 DeviceExtension->HandleCount = Count + 1; 00321 if (CmBattDebug & CMBATT_PNP_INFO) 00322 { 00323 DbgPrint("CmBattOpenClose: Open (DeviceNumber = %x)(count = %x).\n", 00324 DeviceExtension->DeviceId, Count + 1); 00325 } 00326 } 00327 else if (Major == IRP_MJ_CLOSE) 00328 { 00329 /* Decrement the open count */ 00330 DeviceExtension->HandleCount = Count - 1; 00331 if (CmBattDebug & CMBATT_PNP_INFO) 00332 { 00333 DbgPrint("CmBattOpenClose: Close (DeviceNumber = %x)(count = %x).\n", 00334 DeviceExtension->DeviceId, Count + 1); 00335 } 00336 } 00337 00338 Complete: 00339 /* Release lock and complete request */ 00340 ExReleaseFastMutex(&DeviceExtension->FastMutex); 00341 Irp->IoStatus.Status = Status; 00342 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00343 return Status; 00344 } 00345 00346 NTSTATUS 00347 NTAPI 00348 CmBattIoctl(IN PDEVICE_OBJECT DeviceObject, 00349 IN PIRP Irp) 00350 { 00351 PCMBATT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 00352 NTSTATUS Status; 00353 PIO_STACK_LOCATION IoStackLocation; 00354 ULONG IoControlCode, OutputBufferLength, InputBufferLength; 00355 PAGED_CODE(); 00356 if (CmBattDebug & 2) DbgPrint("CmBattIoctl\n"); 00357 00358 /* Acquire the remove lock */ 00359 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, 0); 00360 if (!NT_SUCCESS(Status)) 00361 { 00362 /* It's too late, fail */ 00363 Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; 00364 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00365 return STATUS_DEVICE_REMOVED; 00366 } 00367 00368 /* There's nothing to do for an AC adapter */ 00369 if (DeviceExtension->FdoType == CmBattAcAdapter) 00370 { 00371 /* Pass it down, and release the remove lock */ 00372 IoSkipCurrentIrpStackLocation(Irp); 00373 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 00374 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 00375 return Status; 00376 } 00377 00378 /* Send to class driver */ 00379 Status = BatteryClassIoctl(DeviceExtension->ClassData, Irp); 00380 if (Status == STATUS_NOT_SUPPORTED) 00381 { 00382 /* Read IOCTL information from IRP stack */ 00383 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 00384 IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode; 00385 OutputBufferLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength; 00386 InputBufferLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength; 00387 if (CmBattDebug & 4) 00388 DbgPrint("CmBattIoctl: Received Direct Access IOCTL %x\n", IoControlCode); 00389 00390 /* Handle internal IOCTLs */ 00391 switch (IoControlCode) 00392 { 00393 case IOCTL_BATTERY_QUERY_UNIQUE_ID: 00394 00395 /* Data is 4 bytes long */ 00396 if (OutputBufferLength == sizeof(ULONG)) 00397 { 00398 /* Query it */ 00399 Status = CmBattGetUniqueId(DeviceExtension->PdoDeviceObject, 00400 Irp->AssociatedIrp.SystemBuffer); 00401 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 00402 } 00403 else 00404 { 00405 /* Buffer size invalid */ 00406 Status = STATUS_INVALID_BUFFER_SIZE; 00407 } 00408 break; 00409 00410 case IOCTL_BATTERY_QUERY_STA: 00411 00412 /* Data is 4 bytes long */ 00413 if (OutputBufferLength == sizeof(ULONG)) 00414 { 00415 /* Query it */ 00416 Status = CmBattGetStaData(DeviceExtension->PdoDeviceObject, 00417 Irp->AssociatedIrp.SystemBuffer); 00418 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 00419 } 00420 else 00421 { 00422 /* Buffer size invalid */ 00423 Status = STATUS_INVALID_BUFFER_SIZE; 00424 } 00425 break; 00426 00427 case IOCTL_BATTERY_QUERY_PSR: 00428 00429 /* Data is 4 bytes long */ 00430 if (OutputBufferLength == sizeof(ULONG)) 00431 { 00432 /* Do we have an AC adapter? */ 00433 if (AcAdapterPdo) 00434 { 00435 /* Query it */ 00436 Status = CmBattGetPsrData(AcAdapterPdo, 00437 Irp->AssociatedIrp.SystemBuffer); 00438 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 00439 } 00440 else 00441 { 00442 /* No adapter, just a battery, so fail */ 00443 Status = STATUS_NO_SUCH_DEVICE; 00444 } 00445 } 00446 else 00447 { 00448 /* Buffer size invalid */ 00449 Status = STATUS_INVALID_BUFFER_SIZE; 00450 } 00451 break; 00452 00453 case IOCTL_BATTERY_SET_TRIP_POINT: 00454 00455 /* Data is 4 bytes long */ 00456 if (InputBufferLength == sizeof(ULONG)) 00457 { 00458 /* Query it */ 00459 Status = CmBattSetTripPpoint(DeviceExtension, 00460 *(PULONG)Irp->AssociatedIrp.SystemBuffer); 00461 Irp->IoStatus.Information = 0; 00462 } 00463 else 00464 { 00465 /* Buffer size invalid */ 00466 Status = STATUS_INVALID_BUFFER_SIZE; 00467 } 00468 break; 00469 00470 case IOCTL_BATTERY_QUERY_BIF: 00471 00472 /* Data is 1060 bytes long */ 00473 if (OutputBufferLength == sizeof(ACPI_BIF_DATA)) 00474 { 00475 /* Query it */ 00476 Status = CmBattGetBifData(DeviceExtension, 00477 Irp->AssociatedIrp.SystemBuffer); 00478 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BIF_DATA); 00479 } 00480 else 00481 { 00482 /* Buffer size invalid */ 00483 Status = STATUS_INVALID_BUFFER_SIZE; 00484 } 00485 break; 00486 00487 case IOCTL_BATTERY_QUERY_BST: 00488 00489 /* Data is 16 bytes long */ 00490 if (OutputBufferLength == sizeof(ACPI_BST_DATA)) 00491 { 00492 /* Query it */ 00493 Status = CmBattGetBstData(DeviceExtension, 00494 Irp->AssociatedIrp.SystemBuffer); 00495 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BST_DATA); 00496 } 00497 else 00498 { 00499 /* Buffer size invalid */ 00500 Status = STATUS_INVALID_BUFFER_SIZE; 00501 } 00502 break; 00503 00504 default: 00505 00506 /* Unknown, let us pass it on to ACPI */ 00507 if (CmBattDebug & 0xC) 00508 DbgPrint("CmBattIoctl: Unknown IOCTL %x\n", IoControlCode); 00509 break; 00510 } 00511 00512 /* Did someone pick it up? */ 00513 if (Status != STATUS_NOT_SUPPORTED) 00514 { 00515 /* Complete the request */ 00516 Irp->IoStatus.Status = Status; 00517 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00518 } 00519 else 00520 { 00521 /* Still unsupported, try ACPI */ 00522 IoSkipCurrentIrpStackLocation(Irp); 00523 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 00524 } 00525 } 00526 00527 /* Release the remove lock and return status */ 00528 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 00529 return Status; 00530 } 00531 00532 NTSTATUS 00533 NTAPI 00534 CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 00535 OUT PULONG Tag) 00536 { 00537 PDEVICE_OBJECT PdoDevice; 00538 ULONG StaData; 00539 ULONG NewTag; 00540 NTSTATUS Status; 00541 PAGED_CODE(); 00542 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 00543 DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n", 00544 *Tag, DeviceExtension, DeviceExtension->DeviceId); 00545 00546 /* Get PDO and clear notification flag */ 00547 PdoDevice = DeviceExtension->PdoDeviceObject; 00548 DeviceExtension->NotifySent = 0; 00549 00550 /* Get _STA from PDO (we need the machine status, not the battery status) */ 00551 Status = CmBattGetStaData(PdoDevice, &StaData); 00552 if (NT_SUCCESS(Status)) 00553 { 00554 /* Is a battery present? */ 00555 if (StaData & ACPI_STA_BATTERY_PRESENT) 00556 { 00557 /* Do we not have a tag yet? */ 00558 if (!DeviceExtension->Tag) 00559 { 00560 /* Set the new tag value, reset tags if we reached the maximum */ 00561 NewTag = DeviceExtension->TagData; 00562 if (DeviceExtension->TagData++ == 0xFFFFFFFF) NewTag = 1; 00563 DeviceExtension->Tag = NewTag; 00564 if (CmBattDebug & CMBATT_GENERIC_INFO) 00565 DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension->Tag); 00566 00567 /* Reset trip point data */ 00568 DeviceExtension->TripPointOld = 0; 00569 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 00570 00571 /* Clear AR lock and set new interrupt time */ 00572 InterlockedExchange(&DeviceExtension->ArLockValue, 0); 00573 DeviceExtension->InterruptTime = KeQueryInterruptTime(); 00574 } 00575 } 00576 else 00577 { 00578 /* No battery, so no tag */ 00579 DeviceExtension->Tag = 0; 00580 Status = STATUS_NO_SUCH_DEVICE; 00581 } 00582 } 00583 00584 /* Return the tag and status result */ 00585 *Tag = DeviceExtension->Tag; 00586 if (CmBattDebug & CMBATT_ACPI_WARNING) 00587 DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag, Status); 00588 return Status; 00589 } 00590 00591 NTSTATUS 00592 NTAPI 00593 CmBattDisableStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension) 00594 { 00595 NTSTATUS Status; 00596 PAGED_CODE(); 00597 if (CmBattDebug & 0xA) DbgPrint("CmBattDisableStatusNotify\n"); 00598 00599 /* Do we have a trip point */ 00600 if (DeviceExtension->TripPointSet) 00601 { 00602 /* Is there a current value set? */ 00603 if (DeviceExtension->TripPointValue) 00604 { 00605 /* Reset it back to 0 */ 00606 DeviceExtension->TripPointValue = 0; 00607 Status = CmBattSetTripPpoint(DeviceExtension, 0); 00608 if (!NT_SUCCESS(Status)) 00609 { 00610 /* If it failed, set unknown/invalid value */ 00611 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 00612 if (CmBattDebug & 8) 00613 DbgPrint("CmBattDisableStatusNotify: SetTripPoint failed - %x\n", Status); 00614 } 00615 } 00616 else 00617 { 00618 /* No trip point set, so this is a successful no-op */ 00619 Status = STATUS_SUCCESS; 00620 } 00621 } 00622 else 00623 { 00624 /* Nothing we can do */ 00625 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00626 } 00627 00628 /* Return status */ 00629 return Status; 00630 } 00631 00632 NTSTATUS 00633 NTAPI 00634 CmBattSetStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 00635 IN ULONG BatteryTag, 00636 IN PBATTERY_NOTIFY BatteryNotify) 00637 { 00638 NTSTATUS Status; 00639 ACPI_BST_DATA BstData; 00640 ULONG Capacity, NewTripPoint, TripPoint, DesignVoltage; 00641 BOOLEAN Charging; 00642 PAGED_CODE(); 00643 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 00644 DbgPrint("CmBattSetStatusNotify: Tag (%d) Target(0x%x)\n", 00645 BatteryTag, BatteryNotify->LowCapacity); 00646 00647 /* Update any ACPI evaluations */ 00648 Status = CmBattVerifyStaticInfo(DeviceExtension, BatteryTag); 00649 if (!NT_SUCCESS(Status)) return Status; 00650 00651 /* Trip point not supported, fail */ 00652 if (!DeviceExtension->TripPointSet) return STATUS_OBJECT_NAME_NOT_FOUND; 00653 00654 /* Are both capacities known? */ 00655 if ((BatteryNotify->HighCapacity == BATTERY_UNKNOWN_CAPACITY) || 00656 (BatteryNotify->LowCapacity == BATTERY_UNKNOWN_CAPACITY)) 00657 { 00658 /* We can't set trip points without these */ 00659 if (CmBattDebug & CMBATT_GENERIC_WARNING) 00660 DbgPrint("CmBattSetStatusNotify: Failing request because of BATTERY_UNKNOWN_CAPACITY.\n"); 00661 return STATUS_NOT_SUPPORTED; 00662 } 00663 00664 /* Is the battery charging? */ 00665 Charging = DeviceExtension->BstData.State & ACPI_BATT_STAT_CHARGING; 00666 if (Charging) 00667 { 00668 /* Then the trip point is when we hit the cap */ 00669 Capacity = BatteryNotify->HighCapacity; 00670 NewTripPoint = BatteryNotify->HighCapacity; 00671 } 00672 else 00673 { 00674 /* Otherwise it's when we discharge to the bottom */ 00675 Capacity = BatteryNotify->LowCapacity; 00676 NewTripPoint = BatteryNotify->LowCapacity; 00677 } 00678 00679 /* Do we have data in Amps or Watts? */ 00680 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_AMPS) 00681 { 00682 /* We need the voltage to do the conversion */ 00683 DesignVoltage = DeviceExtension->BifData.DesignVoltage; 00684 if ((DesignVoltage != BATTERY_UNKNOWN_VOLTAGE) && (DesignVoltage)) 00685 { 00686 /* Convert from mAh into Ah */ 00687 TripPoint = 1000 * NewTripPoint; 00688 if (Charging) 00689 { 00690 /* Scale the high trip point */ 00691 NewTripPoint = (TripPoint + 500) / DesignVoltage + ((TripPoint + 500) % DesignVoltage != 0); 00692 } 00693 else 00694 { 00695 /* Scale the low trip point */ 00696 NewTripPoint = (TripPoint - 500) / DesignVoltage - ((TripPoint - 500) % DesignVoltage == 0); 00697 } 00698 } 00699 else 00700 { 00701 /* Without knowing the voltage, Amps are not enough data on consumption */ 00702 Status = STATUS_NOT_SUPPORTED; 00703 if (CmBattDebug & CMBATT_ACPI_WARNING) 00704 DbgPrint("CmBattSetStatusNotify: Can't calculate BTP, DesignVoltage = 0x%08x\n", 00705 DesignVoltage); 00706 } 00707 } 00708 else if (Charging) 00709 { 00710 /* Make it trip just one past the charge cap */ 00711 ++NewTripPoint; 00712 } 00713 else if (NewTripPoint > 0) 00714 { 00715 /* Make it trip just one below the drain cap */ 00716 --NewTripPoint; 00717 } 00718 00719 /* Do we actually have a new trip point? */ 00720 if (NewTripPoint == DeviceExtension->TripPointValue) 00721 { 00722 /* No, so there is no work to be done */ 00723 if (CmBattDebug & CMBATT_GENERIC_STATUS) 00724 DbgPrint("CmBattSetStatusNotify: Keeping original setting: %X\n", DeviceExtension->TripPointValue); 00725 return STATUS_SUCCESS; 00726 } 00727 00728 /* Set the trip point with ACPI and check for success */ 00729 DeviceExtension->TripPointValue = NewTripPoint; 00730 Status = CmBattSetTripPpoint(DeviceExtension, NewTripPoint); 00731 if (!(NewTripPoint) && (Capacity)) Status = STATUS_NOT_SUPPORTED; 00732 if (!NT_SUCCESS(Status)) 00733 { 00734 /* We failed to set the trip point, or there wasn't one settable */ 00735 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 00736 if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING)) 00737 DbgPrint("CmBattSetStatusNotify: SetTripPoint failed - %x\n", Status); 00738 return Status; 00739 } 00740 00741 /* Read the new BST data to see the latest state */ 00742 Status = CmBattGetBstData(DeviceExtension, &BstData); 00743 if (!NT_SUCCESS(Status)) 00744 { 00745 /* We'll return failure to the caller */ 00746 if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING)) 00747 DbgPrint("CmBattSetStatusNotify: GetBstData - %x\n", Status); 00748 } 00749 else if ((Charging) && (BstData.RemainingCapacity >= NewTripPoint)) 00750 { 00751 /* We are charging and our capacity is past the trip point, so trip now */ 00752 if (CmBattDebug & CMBATT_GENERIC_WARNING) 00753 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n", 00754 NewTripPoint, BstData.RemainingCapacity); 00755 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 00756 } 00757 else if ((BstData.RemainingCapacity) && (Capacity)) 00758 { 00759 /* We are discharging, and our capacity is below the trip point, trip now */ 00760 if (CmBattDebug & CMBATT_GENERIC_WARNING) 00761 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n", 00762 NewTripPoint, BstData.RemainingCapacity); 00763 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 00764 } 00765 00766 /* All should've went well if we got here, unless BST failed... return! */ 00767 if (CmBattDebug & CMBATT_GENERIC_STATUS) 00768 DbgPrint("CmBattSetStatusNotify: Want %X CurrentCap %X\n", 00769 Capacity, DeviceExtension->RemainingCapacity); 00770 if (CmBattDebug & CMBATT_ACPI_WARNING) 00771 DbgPrint("CmBattSetStatusNotify: Set to: [%#08lx][%#08lx][%#08lx] Status %x\n", 00772 BatteryNotify->PowerState, 00773 BatteryNotify->LowCapacity, 00774 BatteryNotify->HighCapacity); 00775 return Status; 00776 } 00777 00778 NTSTATUS 00779 NTAPI 00780 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 00781 IN ULONG Tag) 00782 { 00783 ULONG PsrData = 0; 00784 NTSTATUS Status; 00785 ULONG BstState; 00786 ULONG DesignVoltage, PresentRate, RemainingCapacity; 00787 PAGED_CODE(); 00788 if (CmBattDebug & CMBATT_GENERIC_INFO) 00789 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension, Tag); 00790 00791 /* Validate ACPI data */ 00792 Status = CmBattVerifyStaticInfo(DeviceExtension, Tag); 00793 if (!NT_SUCCESS(Status)) return Status; 00794 00795 /* Check for delayed status notifications */ 00796 if (DeviceExtension->DelayNotification) 00797 { 00798 /* Process them now and don't do any other work */ 00799 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 00800 return Status; 00801 } 00802 00803 /* Get _BST from ACPI */ 00804 Status = CmBattGetBstData(DeviceExtension, &DeviceExtension->BstData); 00805 if (!NT_SUCCESS(Status)) 00806 { 00807 /* Fail */ 00808 InterlockedExchange(&DeviceExtension->ArLockValue, 0); 00809 return Status; 00810 } 00811 00812 /* Clear current BST information */ 00813 DeviceExtension->State = 0; 00814 DeviceExtension->RemainingCapacity = 0; 00815 DeviceExtension->PresentVoltage = 0; 00816 DeviceExtension->Rate = 0; 00817 00818 /* Get battery state */ 00819 BstState = DeviceExtension->BstData.State; 00820 00821 /* Is the battery both charging and discharging? */ 00822 if ((BstState & ACPI_BATT_STAT_DISCHARG) && (BstState & ACPI_BATT_STAT_CHARGING) && 00823 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 00824 DbgPrint("************************ ACPI BIOS BUG ********************\n* " 00825 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n" 00826 "* One battery cannot be charging and discharging at the same time.\n", 00827 BstState); 00828 00829 /* Is the battery discharging? */ 00830 if (BstState & ACPI_BATT_STAT_DISCHARG) 00831 { 00832 /* Set power state and check if it just started discharging now */ 00833 DeviceExtension->State |= BATTERY_DISCHARGING; 00834 if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG)) 00835 { 00836 /* Remember the time when the state changed */ 00837 DeviceExtension->InterruptTime = KeQueryInterruptTime(); 00838 } 00839 } 00840 else if (BstState & ACPI_BATT_STAT_CHARGING) 00841 { 00842 /* Battery is charging, update power state */ 00843 DeviceExtension->State |= (BATTERY_CHARGING | BATTERY_POWER_ON_LINE); 00844 } 00845 00846 /* Is the battery in a critical state? */ 00847 if (BstState & ACPI_BATT_STAT_CRITICAL) DeviceExtension->State |= BATTERY_CRITICAL; 00848 00849 /* Read the voltage data */ 00850 DeviceExtension->PresentVoltage = DeviceExtension->BstData.PresentVoltage; 00851 00852 /* Check if we have an A/C adapter */ 00853 if (AcAdapterPdo) 00854 { 00855 /* Query information on it */ 00856 CmBattGetPsrData(AcAdapterPdo, &PsrData); 00857 } 00858 else 00859 { 00860 /* Otherwise, check if the battery is charging */ 00861 if (BstState & ACPI_BATT_STAT_CHARGING) 00862 { 00863 /* Then we'll assume there's a charger */ 00864 PsrData = 1; 00865 } 00866 else 00867 { 00868 /* Assume no charger */ 00869 PsrData = 0; 00870 } 00871 } 00872 00873 /* Is there a charger? */ 00874 if (PsrData) 00875 { 00876 /* Set the power state flag to reflect this */ 00877 DeviceExtension->State |= BATTERY_POWER_ON_LINE; 00878 if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 00879 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n"); 00880 } 00881 else if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 00882 { 00883 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n"); 00884 } 00885 00886 /* Get some data we'll need */ 00887 DesignVoltage = DeviceExtension->BifData.DesignVoltage; 00888 PresentRate = DeviceExtension->BstData.PresentRate; 00889 RemainingCapacity = DeviceExtension->BstData.RemainingCapacity; 00890 00891 /* Check if we have battery data in Watts instead of Amps */ 00892 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_WATTS) 00893 { 00894 /* Get the data from the BST */ 00895 DeviceExtension->RemainingCapacity = RemainingCapacity; 00896 DeviceExtension->Rate = PresentRate; 00897 00898 /* Check if the rate is invalid */ 00899 if (PresentRate > CM_MAX_VALUE) 00900 { 00901 /* Set an unknown rate and don't touch the old value */ 00902 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 00903 if ((PresentRate != CM_UNKNOWN_VALUE) && (CmBattDebug & CMBATT_ACPI_WARNING)) 00904 { 00905 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n"); 00906 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate); 00907 } 00908 } 00909 } 00910 else if ((DesignVoltage != CM_UNKNOWN_VALUE) && (DesignVoltage)) 00911 { 00912 /* We have voltage data, what about capacity? */ 00913 if (RemainingCapacity == CM_UNKNOWN_VALUE) 00914 { 00915 /* Unable to calculate it */ 00916 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 00917 if (CmBattDebug & CMBATT_ACPI_WARNING) 00918 { 00919 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n"); 00920 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n"); 00921 } 00922 } 00923 else 00924 { 00925 /* Compute the capacity with the information we have */ 00926 DeviceExtension->RemainingCapacity = (DesignVoltage * RemainingCapacity + 500) / 1000; 00927 } 00928 00929 /* Check if we have a rate */ 00930 if (PresentRate != CM_UNKNOWN_VALUE) 00931 { 00932 /* Make sure the rate isn't too large */ 00933 if (PresentRate > (-500 / DesignVoltage)) 00934 { 00935 /* It is, so set unknown state */ 00936 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 00937 if (CmBattDebug & CMBATT_ACPI_WARNING) 00938 { 00939 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 00940 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate); 00941 } 00942 } 00943 00944 /* Compute the rate */ 00945 DeviceExtension->Rate = (PresentRate * DesignVoltage + 500) / 1000; 00946 } 00947 else 00948 { 00949 /* We don't have a rate, so set unknown value */ 00950 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 00951 if (CmBattDebug & CMBATT_ACPI_WARNING) 00952 { 00953 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 00954 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n"); 00955 } 00956 } 00957 } 00958 else 00959 { 00960 /* We have no rate, and no capacity, set unknown values */ 00961 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 00962 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 00963 if (CmBattDebug & CMBATT_ACPI_WARNING) 00964 { 00965 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n"); 00966 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage); 00967 } 00968 } 00969 00970 /* Check if we have an unknown rate */ 00971 if (DeviceExtension->Rate == BATTERY_UNKNOWN_RATE) 00972 { 00973 /* The battery is discharging but we don't know by how much... this is bad! */ 00974 if ((BstState & ACPI_BATT_STAT_DISCHARG) && 00975 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 00976 DbgPrint("CmBattGetBatteryStatus: battery rate is unkown when battery is not charging!\n"); 00977 } 00978 else if (DeviceExtension->State & BATTERY_DISCHARGING) 00979 { 00980 /* The battery is discharging, so treat the rate as a negative rate */ 00981 DeviceExtension->Rate = -DeviceExtension->Rate; 00982 } 00983 else if (!(DeviceExtension->State & BATTERY_CHARGING) && (DeviceExtension->Rate)) 00984 { 00985 /* We are not charging, not discharging, but have a rate? Ignore it! */ 00986 if (CmBattDebug & CMBATT_GENERIC_WARNING) 00987 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n", 00988 DeviceExtension->Rate); 00989 DeviceExtension->Rate = 0; 00990 } 00991 00992 /* Done */ 00993 return STATUS_SUCCESS; 00994 } 00995 00996 NTSTATUS 00997 NTAPI 00998 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension, 00999 IN ULONG Tag, 01000 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel, 01001 IN OPTIONAL LONG AtRate, 01002 IN PVOID Buffer, 01003 IN ULONG BufferLength, 01004 OUT PULONG ReturnedLength) 01005 { 01006 NTSTATUS Status; 01007 PVOID QueryData = NULL; 01008 ULONG QueryLength = 0; 01009 ULONG RemainingTime = 0; 01010 ANSI_STRING TempString; 01011 UNICODE_STRING TempString2; 01012 WCHAR InfoBuffer[256]; 01013 WCHAR TempBuffer[256]; 01014 UNICODE_STRING InfoString; 01015 ULONG RemainingCapacity; 01016 BATTERY_REPORTING_SCALE BatteryReportingScale[2]; 01017 LONG Rate; 01018 PAGED_CODE(); 01019 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 01020 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n", 01021 Tag, 01022 FdoExtension->DeviceId, 01023 InfoLevel); 01024 01025 /* Check ACPI Data */ 01026 Status = CmBattVerifyStaticInfo(FdoExtension, Tag); 01027 if (!NT_SUCCESS(Status)) return Status; 01028 01029 /* Check what caller wants */ 01030 switch (InfoLevel) 01031 { 01032 case BatteryInformation: 01033 /* Just return our static information */ 01034 QueryData = &FdoExtension->BatteryInformation; 01035 QueryLength = sizeof(BATTERY_INFORMATION); 01036 break; 01037 01038 case BatteryGranularityInformation: 01039 01040 /* Return our static information, we have two scales */ 01041 BatteryReportingScale[0].Granularity = FdoExtension->BatteryCapacityGranularity1; 01042 BatteryReportingScale[0].Capacity = FdoExtension->BatteryInformation.DefaultAlert1; 01043 BatteryReportingScale[1].Granularity = FdoExtension->BatteryCapacityGranularity2; 01044 BatteryReportingScale[1].Capacity = FdoExtension->BatteryInformation.DesignedCapacity; 01045 QueryData = BatteryReportingScale; 01046 QueryLength = sizeof(BATTERY_REPORTING_SCALE) * 2; 01047 break; 01048 01049 case BatteryEstimatedTime: 01050 01051 /* Check if it's been more than 2 1/2 minutes since the last change */ 01052 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime)) 01053 { 01054 /* Get new battery status */ 01055 CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag); 01056 01057 /* If the caller didn't specify a rate, use our static one */ 01058 Rate = AtRate; 01059 if (!Rate) Rate = FdoExtension->Rate; 01060 01061 /* If we don't have a valid negative rate, use unknown value */ 01062 if (Rate >= 0) Rate = BATTERY_UNKNOWN_RATE; 01063 01064 /* Grab the remaining capacity */ 01065 RemainingCapacity = FdoExtension->RemainingCapacity; 01066 01067 /* See if we don't know one or the other */ 01068 if ((Rate == BATTERY_UNKNOWN_RATE) || 01069 (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY)) 01070 { 01071 /* If the battery is discharging, we can't give out a time */ 01072 if ((FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG) && 01073 (CmBattDebug & CMBATT_GENERIC_WARNING)) 01074 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n"); 01075 01076 /* Check if we don't have a rate and capacity is going down */ 01077 if ((FdoExtension->Rate == BATTERY_UNKNOWN_RATE) && 01078 (FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG)) 01079 { 01080 /* We have to fail, since we lack data */ 01081 Status = STATUS_INVALID_DEVICE_REQUEST; 01082 if (CmBattDebug & CMBATT_GENERIC_WARNING) 01083 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n"); 01084 } 01085 01086 /* If we don't have capacity, the rate is useless */ 01087 if (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY) 01088 { 01089 /* We have to fail the request */ 01090 Status = STATUS_INVALID_DEVICE_REQUEST; 01091 if (CmBattDebug & CMBATT_GENERIC_WARNING) 01092 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n"); 01093 } 01094 } 01095 else 01096 { 01097 /* We have data, but is it valid? */ 01098 if (RemainingCapacity > 0x123456) 01099 { 01100 /* The capacity seems bogus, so don't use it */ 01101 if (CmBattDebug & CMBATT_ACPI_WARNING) 01102 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n"); 01103 } 01104 else 01105 { 01106 /* Compute the remaining time in seconds, based on rate */ 01107 RemainingTime = (RemainingCapacity * 3600) / -Rate; 01108 } 01109 } 01110 } 01111 01112 /* Return the remaining time */ 01113 QueryData = &RemainingTime; 01114 QueryLength = sizeof(ULONG); 01115 break; 01116 01117 case BatteryDeviceName: 01118 01119 /* Build the model number string */ 01120 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); 01121 01122 /* Convert it to Unicode */ 01123 InfoString.Buffer = InfoBuffer; 01124 InfoString.MaximumLength = sizeof(InfoBuffer); 01125 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 01126 01127 /* Return the unicode buffer */ 01128 QueryData = InfoString.Buffer; 01129 QueryLength = InfoString.Length; 01130 break; 01131 01132 case BatteryTemperature: 01133 case BatteryManufactureDate: 01134 01135 /* We don't support these */ 01136 Status = STATUS_INVALID_DEVICE_REQUEST; 01137 break; 01138 01139 case BatteryManufactureName: 01140 01141 /* Build the OEM info string */ 01142 RtlInitAnsiString(&TempString, FdoExtension->OemInfo); 01143 01144 /* Convert it to Unicode */ 01145 InfoString.Buffer = InfoBuffer; 01146 InfoString.MaximumLength = sizeof(InfoBuffer); 01147 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 01148 01149 /* Return the unicode buffer */ 01150 QueryData = InfoString.Buffer; 01151 QueryLength = InfoString.Length; 01152 break; 01153 01154 case BatteryUniqueID: 01155 01156 /* Build the serial number string */ 01157 RtlInitAnsiString(&TempString, FdoExtension->SerialNumber); 01158 01159 /* Convert it to Unicode */ 01160 InfoString.Buffer = InfoBuffer; 01161 InfoString.MaximumLength = sizeof(InfoBuffer); 01162 RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 01163 01164 /* Setup a temporary string for concatenation */ 01165 TempString2.Buffer = TempBuffer; 01166 TempString2.MaximumLength = sizeof(TempBuffer); 01167 01168 /* Check if there's an OEM string */ 01169 if (FdoExtension->OemInfo[0]) 01170 { 01171 /* Build the OEM info string */ 01172 RtlInitAnsiString(&TempString, FdoExtension->OemInfo); 01173 01174 /* Convert it to Unicode and append it */ 01175 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 01176 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 01177 } 01178 01179 /* Build the model number string */ 01180 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); 01181 01182 /* Convert it to Unicode and append it */ 01183 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 01184 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 01185 01186 /* Return the final appended string */ 01187 QueryData = InfoString.Buffer; 01188 QueryLength = InfoString.Length; 01189 break; 01190 01191 default: 01192 01193 /* Everything else is unknown */ 01194 Status = STATUS_INVALID_PARAMETER; 01195 break; 01196 } 01197 01198 /* Return the required length and check if the caller supplied enough */ 01199 *ReturnedLength = QueryLength; 01200 if (BufferLength < QueryLength) Status = STATUS_BUFFER_TOO_SMALL; 01201 01202 /* Copy the data if there's enough space and it exists */ 01203 if ((NT_SUCCESS(Status)) && (QueryData)) RtlCopyMemory(Buffer, QueryData, QueryLength); 01204 01205 /* Return function result */ 01206 return Status; 01207 } 01208 01209 NTSTATUS 01210 NTAPI 01211 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 01212 IN ULONG Tag, 01213 IN PBATTERY_STATUS BatteryStatus) 01214 { 01215 NTSTATUS Status; 01216 PAGED_CODE(); 01217 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 01218 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag, DeviceExtension->DeviceId); 01219 01220 /* Query ACPI information */ 01221 Status = CmBattGetBatteryStatus(DeviceExtension, Tag); 01222 if (NT_SUCCESS(Status)) 01223 { 01224 BatteryStatus->PowerState = DeviceExtension->State; 01225 BatteryStatus->Capacity = DeviceExtension->RemainingCapacity; 01226 BatteryStatus->Voltage = DeviceExtension->PresentVoltage; 01227 BatteryStatus->Rate = DeviceExtension->Rate; 01228 } 01229 01230 /* Return status */ 01231 if (CmBattDebug & (CMBATT_GENERIC_INFO)) 01232 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n", 01233 BatteryStatus->PowerState, 01234 BatteryStatus->Capacity, 01235 BatteryStatus->Voltage, 01236 BatteryStatus->Rate); 01237 return Status; 01238 } 01239 01240 NTSTATUS 01241 NTAPI 01242 DriverEntry(IN PDRIVER_OBJECT DriverObject, 01243 IN PUNICODE_STRING RegistryPath) 01244 { 01245 NTSTATUS Status; 01246 PDRIVER_EXTENSION DriverExtension; 01247 OBJECT_ATTRIBUTES ObjectAttributes; 01248 UNICODE_STRING CallbackName; 01249 01250 /* Allocate registry path */ 01251 GlobalRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); 01252 GlobalRegistryPath.Length = RegistryPath->Length; 01253 GlobalRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, 01254 GlobalRegistryPath.MaximumLength, 01255 'MtaB'); 01256 if (!GlobalRegistryPath.Buffer) 01257 { 01258 /* Fail if we're out of memory this early */ 01259 if (CmBattDebug & CMBATT_GENERIC_WARNING) 01260 DbgPrint("CmBatt: Couldn't allocate pool for registry path."); 01261 return STATUS_INSUFFICIENT_RESOURCES; 01262 } 01263 01264 /* Buffer allocated, copy the string */ 01265 RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath); 01266 if (CmBattDebug & CMBATT_GENERIC_INFO) 01267 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n", 01268 DriverObject, 01269 RegistryPath->Buffer); 01270 01271 /* Setup the major dispatchers */ 01272 DriverObject->MajorFunction[IRP_MJ_CREATE] = CmBattOpenClose; 01273 DriverObject->MajorFunction[IRP_MJ_CLOSE] = CmBattOpenClose; 01274 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CmBattIoctl; 01275 DriverObject->MajorFunction[IRP_MJ_POWER] = CmBattPowerDispatch; 01276 DriverObject->MajorFunction[IRP_MJ_PNP] = CmBattPnpDispatch; 01277 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = CmBattSystemControl; 01278 01279 /* And the unload routine */ 01280 DriverObject->DriverUnload = CmBattUnload; 01281 01282 /* And the add device routine */ 01283 DriverExtension = DriverObject->DriverExtension; 01284 DriverExtension->AddDevice = CmBattAddDevice; 01285 01286 /* Create a power callback */ 01287 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState"); 01288 InitializeObjectAttributes(&ObjectAttributes, 01289 &CallbackName, 01290 OBJ_KERNEL_HANDLE, 01291 NULL, 01292 NULL); 01293 Status = ExCreateCallback(&CmBattPowerCallBackObject, &ObjectAttributes, 0, TRUE); 01294 if (!NT_SUCCESS(Status)) 01295 { 01296 /* No callback, fail */ 01297 CmBattPowerCallBackObject = 0; 01298 if (CmBattDebug & CMBATT_GENERIC_WARNING) 01299 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status); 01300 } 01301 else 01302 { 01303 /* Register the power callback now */ 01304 CmBattPowerCallBackRegistration = ExRegisterCallback(CmBattPowerCallBackObject, 01305 (PVOID)CmBattPowerCallBack, 01306 DriverObject); 01307 if (CmBattPowerCallBackRegistration) 01308 { 01309 /* Last thing: setup our DPC and timer for battery wake */ 01310 KeInitializeDpc(&CmBattWakeDpcObject, (PVOID)CmBattWakeDpc, DriverObject); 01311 KeInitializeTimer(&CmBattWakeDpcTimerObject); 01312 } 01313 else 01314 { 01315 ObDereferenceObject(CmBattPowerCallBackObject); 01316 if (CmBattDebug & CMBATT_GENERIC_WARNING) 01317 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n"); 01318 } 01319 01320 /* All good */ 01321 Status = STATUS_SUCCESS; 01322 } 01323 01324 /* Return failure or success */ 01325 return Status; 01326 } 01327 01328 /* EOF */ Generated on Sun May 27 2012 04:27:25 for ReactOS by
1.7.6.1
|