ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cmbatt.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.