Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3014 lines
88 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbbatt.c
  5. Abstract:
  6. SMBus Smart Battery Subsystem Miniport Driver
  7. (Selector, Battery, Charger)
  8. Author:
  9. Ken Reneris
  10. Environment:
  11. Notes:
  12. Revision History:
  13. Chris Windle 1/27/98 Bug Fixes
  14. --*/
  15. #include "smbbattp.h"
  16. #include <initguid.h>
  17. #include <batclass.h>
  18. #if DEBUG
  19. ULONG SMBBattDebug = BAT_WARN | BAT_ERROR | BAT_BIOS_ERROR;
  20. #endif
  21. // Global
  22. BOOLEAN SmbBattUseGlobalLock = TRUE;
  23. UNICODE_STRING GlobalRegistryPath;
  24. //
  25. // Prototypes
  26. //
  27. NTSTATUS
  28. DriverEntry(
  29. IN PDRIVER_OBJECT DriverObject,
  30. IN PUNICODE_STRING RegistryPath
  31. );
  32. NTSTATUS
  33. SmbBattNewDevice (
  34. IN PDRIVER_OBJECT DriverObject,
  35. IN PDEVICE_OBJECT PDO
  36. );
  37. NTSTATUS
  38. SmbBattQueryTag (
  39. IN PVOID Context,
  40. OUT PULONG BatteryTag
  41. );
  42. NTSTATUS
  43. SmbBattQueryInformation (
  44. IN PVOID Context,
  45. IN ULONG BatteryTag,
  46. IN BATTERY_QUERY_INFORMATION_LEVEL Level,
  47. IN LONG AtRate OPTIONAL,
  48. OUT PVOID Buffer,
  49. IN ULONG BufferLength,
  50. OUT PULONG ReturnedLength
  51. );
  52. NTSTATUS
  53. SmbBattSetStatusNotify (
  54. IN PVOID Context,
  55. IN ULONG BatteryTag,
  56. IN PBATTERY_NOTIFY BatteryNotify
  57. );
  58. NTSTATUS
  59. SmbBattDisableStatusNotify (
  60. IN PVOID Context
  61. );
  62. NTSTATUS
  63. SmbBattQueryStatus (
  64. IN PVOID Context,
  65. IN ULONG BatteryTag,
  66. OUT PBATTERY_STATUS BatteryStatus
  67. );
  68. NTSTATUS
  69. SmbBattCreate(
  70. IN PDEVICE_OBJECT DeviceObject,
  71. IN PIRP Irp
  72. );
  73. NTSTATUS
  74. SmbBattClose(
  75. IN PDEVICE_OBJECT DeviceObject,
  76. IN PIRP Irp
  77. );
  78. NTSTATUS
  79. SmbBattIoctl(
  80. IN PDEVICE_OBJECT DeviceObject,
  81. IN PIRP Irp
  82. );
  83. VOID
  84. SmbBattUnload(
  85. IN PDRIVER_OBJECT DriverObject
  86. );
  87. VOID
  88. SmbBattProcessSelectorAlarm (
  89. IN PSMB_BATT_SUBSYSTEM SubsystemExt,
  90. IN ULONG OldSelectorState,
  91. IN ULONG NewSelectorState
  92. );
  93. NTSTATUS
  94. SmbBattGetPowerState (
  95. IN PSMB_BATT SmbBatt,
  96. OUT PULONG PowerState,
  97. OUT PLONG Current
  98. );
  99. #ifdef ALLOC_PRAGMA
  100. #pragma alloc_text(INIT,DriverEntry)
  101. #pragma alloc_text(PAGE,SmbBattNewDevice)
  102. #pragma alloc_text(PAGE,SmbBattUnload)
  103. #pragma alloc_text(PAGE,SmbBattCreate)
  104. #pragma alloc_text(PAGE,SmbBattClose)
  105. #pragma alloc_text(PAGE,SmbBattIoctl)
  106. #pragma alloc_text(PAGE,SmbBattQueryTag)
  107. #pragma alloc_text(PAGE,SmbBattQueryInformation)
  108. #pragma alloc_text(PAGE,SmbBattSetInformation)
  109. #pragma alloc_text(PAGE,SmbBattGetPowerState)
  110. #pragma alloc_text(PAGE,SmbBattQueryStatus)
  111. #pragma alloc_text(PAGE,SmbBattSetStatusNotify)
  112. #pragma alloc_text(PAGE,SmbBattDisableStatusNotify)
  113. #endif
  114. NTSTATUS
  115. DriverEntry(
  116. IN PDRIVER_OBJECT DriverObject,
  117. IN PUNICODE_STRING RegistryPath
  118. )
  119. /*++
  120. Routine Description:
  121. This routine initializes the Smart Battery Driver
  122. Arguments:
  123. DriverObject - Pointer to driver object created by system.
  124. RegistryPath - Pointer to the Unicode name of the registry path
  125. for this driver.
  126. Return Value:
  127. The function value is the final status from the initialization operation.
  128. --*/
  129. {
  130. OBJECT_ATTRIBUTES objAttributes;
  131. BattPrint(BAT_TRACE, ("SmbBatt: DriverEntry\n"));
  132. //
  133. // Save the RegistryPath.
  134. //
  135. GlobalRegistryPath.MaximumLength = RegistryPath->Length +
  136. sizeof(UNICODE_NULL);
  137. GlobalRegistryPath.Length = RegistryPath->Length;
  138. GlobalRegistryPath.Buffer = ExAllocatePoolWithTag (
  139. PagedPool,
  140. GlobalRegistryPath.MaximumLength,
  141. 'StaB');
  142. if (!GlobalRegistryPath.Buffer) {
  143. BattPrint ((BAT_ERROR),("SmbBatt: Couldn't allocate pool for registry path."));
  144. return STATUS_INSUFFICIENT_RESOURCES;
  145. }
  146. RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath);
  147. BattPrint (BAT_TRACE, ("SmbBatt DriverEntry - Obj (%08x) Path \"%ws\"\n",
  148. DriverObject, RegistryPath->Buffer));
  149. DriverObject->DriverUnload = SmbBattUnload;
  150. DriverObject->DriverExtension->AddDevice = SmbBattNewDevice;
  151. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SmbBattIoctl;
  152. DriverObject->MajorFunction[IRP_MJ_CREATE] = SmbBattCreate;
  153. DriverObject->MajorFunction[IRP_MJ_CLOSE] = SmbBattClose;
  154. DriverObject->MajorFunction[IRP_MJ_PNP] = SmbBattPnpDispatch;
  155. DriverObject->MajorFunction[IRP_MJ_POWER] = SmbBattPowerDispatch;
  156. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = SmbBattSystemControl;
  157. return STATUS_SUCCESS;
  158. }
  159. NTSTATUS
  160. SmbBattNewDevice (
  161. IN PDRIVER_OBJECT DriverObject,
  162. IN PDEVICE_OBJECT PDO
  163. )
  164. /*++
  165. Routine Description:
  166. This creates a smb smart battery functional device objects. The first
  167. object created will be the one for the "smart battery subsystem" which will
  168. have a PDO from ACPI. This will receive a START Irp, then a
  169. QUERY_DEVICE_RELATIONS Irp. In the QUERY it will create PDOs for the
  170. batteries that are supported by the system and eventually they will end
  171. up here for FDOs to be created and attached to them.
  172. Arguments:
  173. DriverObject - Pointer to driver object created by system.
  174. PDO - PDO for the new device(s)
  175. Return Value:
  176. Status
  177. --*/
  178. {
  179. PDEVICE_OBJECT fdo;
  180. PSMB_BATT_SUBSYSTEM subsystemExt;
  181. PSMB_BATT_PDO pdoExt;
  182. PSMB_NP_BATT SmbNPBatt;
  183. PSMB_BATT SmbBatt;
  184. BATTERY_MINIPORT_INFO BattInit;
  185. NTSTATUS status = STATUS_UNSUCCESSFUL;
  186. BOOLEAN selectorPresent = FALSE;
  187. PAGED_CODE();
  188. BattPrint(BAT_IRPS, ("SmbBattNewDevice: AddDevice for device %x\n", PDO));
  189. //
  190. // Check to see if we are being asked to enumerate ourself
  191. //
  192. if (PDO == NULL) {
  193. BattPrint(BAT_ERROR, ("SmbBattNewDevice: Being asked to enumerate\n"));
  194. return STATUS_NOT_IMPLEMENTED;
  195. }
  196. //
  197. // Check to see if the PDO is the battery subsystem PDO or a battery PDO. This will be
  198. // determined by the PDO's DeviceType.
  199. //
  200. // FILE_DEVICE_ACPI This PDO is from ACPI and belongs to battery subsystem
  201. // FILE_DEVICE_BATTERY This PDO is a battery PDO
  202. //
  203. if (PDO->DeviceType == FILE_DEVICE_ACPI) {
  204. //
  205. // Create the device object
  206. //
  207. status = IoCreateDevice(
  208. DriverObject,
  209. sizeof (SMB_BATT_SUBSYSTEM),
  210. NULL,
  211. FILE_DEVICE_BATTERY,
  212. 0,
  213. FALSE,
  214. &fdo
  215. );
  216. if (status != STATUS_SUCCESS) {
  217. BattPrint(BAT_ERROR, ("SmbBattNewDevice: error creating Fdo for battery subsystem %x\n", status));
  218. return(status);
  219. }
  220. //
  221. // Initialize the Fdo
  222. //
  223. fdo->Flags |= DO_BUFFERED_IO;
  224. fdo->Flags |= DO_POWER_PAGABLE;
  225. //
  226. // Initialize the extension
  227. //
  228. subsystemExt = (PSMB_BATT_SUBSYSTEM)fdo->DeviceExtension;
  229. RtlZeroMemory (subsystemExt, sizeof (PSMB_BATT_SUBSYSTEM));
  230. subsystemExt->DeviceObject = fdo;
  231. subsystemExt->SmbBattFdoType = SmbTypeSubsystem;
  232. IoInitializeRemoveLock (&subsystemExt->RemoveLock,
  233. SMB_BATTERY_TAG,
  234. REMOVE_LOCK_MAX_LOCKED_MINUTES,
  235. REMOVE_LOCK_HIGH_WATER_MARK);
  236. //
  237. // These fields are implicitly initialize by zeroing the extension
  238. //
  239. // subsystemExt->NumberOfBatteries = 0;
  240. // subsystemExt->SelectorPresent = FALSE;
  241. // subsystemExt->Selector = NULL;
  242. // subsystemExt->WorkerActive = 0;
  243. KeInitializeSpinLock (&subsystemExt->AlarmListLock);
  244. InitializeListHead (&subsystemExt->AlarmList);
  245. subsystemExt->WorkerThread = IoAllocateWorkItem (fdo);
  246. //
  247. // Layer our FDO on top of the ACPI PDO.
  248. //
  249. subsystemExt->LowerDevice = IoAttachDeviceToDeviceStack (fdo,PDO);
  250. if (!subsystemExt->LowerDevice) {
  251. BattPrint(BAT_ERROR, ("SmbBattNewDevice: Error attaching subsystem to device stack.\n"));
  252. IoDeleteDevice (fdo);
  253. return(status);
  254. }
  255. //
  256. // Zero out the battery PDO list
  257. // This is already zeroed by the RtlZeroMemory above.
  258. //
  259. // RtlZeroMemory(
  260. // &subsystemExt->BatteryPdoList[0],
  261. // sizeof(PDEVICE_OBJECT) * MAX_SMART_BATTERIES_SUPPORTED
  262. // );
  263. //
  264. // Device is ready for use
  265. //
  266. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  267. } else {
  268. //
  269. // This is a battery PDO. Create the FDO to layer on top of it.
  270. //
  271. pdoExt = (PSMB_BATT_PDO) PDO->DeviceExtension;
  272. subsystemExt = (PSMB_BATT_SUBSYSTEM) pdoExt->SubsystemFdo->DeviceExtension;
  273. //
  274. // Allocate space for the paged portion of the device extension
  275. //
  276. SmbBatt = ExAllocatePoolWithTag (PagedPool, sizeof(SMB_BATT), SMB_BATTERY_TAG);
  277. if (!SmbBatt) {
  278. BattPrint(BAT_ERROR, ("SmbBattNewDevice: Can't allocate Smart Battery data\n"));
  279. return STATUS_INSUFFICIENT_RESOURCES;
  280. }
  281. RtlZeroMemory (SmbBatt, sizeof(SMB_BATT));
  282. //
  283. // Create the device object
  284. //
  285. status = IoCreateDevice(
  286. DriverObject,
  287. sizeof (SMB_NP_BATT),
  288. NULL,
  289. FILE_DEVICE_BATTERY,
  290. 0,
  291. FALSE,
  292. &fdo
  293. );
  294. if (status != STATUS_SUCCESS) {
  295. BattPrint(BAT_ERROR, ("SmbBattNewDevice: error creating Fdo: %x\n", status));
  296. ExFreePool (SmbBatt);
  297. return(status);
  298. }
  299. //
  300. // Initialize the Fdo
  301. //
  302. fdo->Flags |= DO_BUFFERED_IO;
  303. fdo->Flags |= DO_POWER_PAGABLE;
  304. //
  305. // Layer our FDO on top of the PDO.
  306. //
  307. SmbNPBatt = (PSMB_NP_BATT) fdo->DeviceExtension;
  308. SmbNPBatt->LowerDevice = IoAttachDeviceToDeviceStack (fdo,PDO);
  309. if (!SmbNPBatt->LowerDevice) {
  310. BattPrint(BAT_ERROR, ("SmbBattNewDevice: error attaching to device stack\n"));
  311. ExFreePool (SmbBatt);
  312. IoDeleteDevice (fdo);
  313. return(status);
  314. }
  315. //
  316. // Fill in privates
  317. //
  318. SmbNPBatt->Batt = SmbBatt;
  319. SmbNPBatt->SmbBattFdoType = SmbTypeBattery;
  320. IoInitializeRemoveLock (&SmbNPBatt->RemoveLock,
  321. SMB_BATTERY_TAG,
  322. REMOVE_LOCK_MAX_LOCKED_MINUTES,
  323. REMOVE_LOCK_HIGH_WATER_MARK);
  324. ExInitializeFastMutex (&SmbNPBatt->Mutex);
  325. SmbBatt->NP = SmbNPBatt;
  326. SmbBatt->PDO = PDO;
  327. SmbBatt->DeviceObject = fdo;
  328. SmbBatt->SelectorPresent = subsystemExt->SelectorPresent;
  329. SmbBatt->Selector = subsystemExt->Selector;
  330. pdoExt->Fdo = fdo;
  331. //
  332. // Precalculate this batteries SMB_x bit position in the selector status register.
  333. //
  334. // Just move it into the lower nibble and any function that needs
  335. // the bit can shift it left 4 = charger, 8 = power, 12 = smb
  336. //
  337. SmbBatt->SelectorBitPosition = 1;
  338. if (pdoExt->BatteryNumber > 0) {
  339. SmbBatt->SelectorBitPosition <<= pdoExt->BatteryNumber;
  340. }
  341. //
  342. // Have class driver allocate a new SMB miniport device
  343. //
  344. RtlZeroMemory (&BattInit, sizeof(BattInit));
  345. BattInit.MajorVersion = SMB_BATTERY_MAJOR_VERSION;
  346. BattInit.MinorVersion = SMB_BATTERY_MINOR_VERSION;
  347. BattInit.Context = SmbBatt;
  348. BattInit.QueryTag = SmbBattQueryTag;
  349. BattInit.QueryInformation = SmbBattQueryInformation;
  350. BattInit.SetInformation = SmbBattSetInformation;
  351. BattInit.QueryStatus = SmbBattQueryStatus;
  352. BattInit.SetStatusNotify = SmbBattSetStatusNotify;
  353. BattInit.DisableStatusNotify = SmbBattDisableStatusNotify;
  354. BattInit.Pdo = PDO;
  355. BattInit.DeviceName = NULL;
  356. status = BatteryClassInitializeDevice (
  357. &BattInit,
  358. &SmbNPBatt->Class
  359. );
  360. if (status != STATUS_SUCCESS) {
  361. BattPrint(BAT_ERROR, ("SmbBattNewDevice: error initializing battery: %x\n", status));
  362. ExFreePool (SmbBatt);
  363. IoDetachDevice (SmbNPBatt->LowerDevice);
  364. IoDeleteDevice (fdo);
  365. return(status);
  366. }
  367. //
  368. // Register WMI support.
  369. //
  370. status = SmbBattWmiRegistration(SmbNPBatt);
  371. if (!NT_SUCCESS(status)) {
  372. //
  373. // WMI support is not critical to operation. Just log an error.
  374. //
  375. BattPrint(BAT_ERROR,
  376. ("SmbBattNewDevice: Could not register as a WMI provider, status = %Lx\n", status));
  377. }
  378. //
  379. // Device is ready for use
  380. //
  381. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  382. } // else (we have a battery PDO)
  383. return status;
  384. }
  385. VOID
  386. SmbBattUnload(
  387. IN PDRIVER_OBJECT DriverObject
  388. )
  389. /*++
  390. Routine Description:
  391. Cleanup all devices and unload the driver
  392. Arguments:
  393. DriverObject - Driver object for unload
  394. Return Value:
  395. Status
  396. --*/
  397. {
  398. PAGED_CODE();
  399. BattPrint(BAT_TRACE, ("SmbBattUnload: ENTERING\n"));
  400. //
  401. // Should check here to make sure all DO's are gone.
  402. //
  403. ExFreePool (GlobalRegistryPath.Buffer);
  404. // This is listed as an error so I'll always see when it is unloaded...
  405. BattPrint(BAT_ERROR, ("SmbBattUnload: Smbbatt.sys unloaded successfully.\n"));
  406. }
  407. NTSTATUS
  408. SmbBattCreate(
  409. IN PDEVICE_OBJECT DeviceObject,
  410. IN PIRP Irp
  411. )
  412. {
  413. PSMB_NP_BATT SmbNPBatt = (PSMB_NP_BATT) DeviceObject->DeviceExtension;
  414. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  415. NTSTATUS status;
  416. PAGED_CODE();
  417. BattPrint(BAT_TRACE, ("SmbBattCreate: ENTERING\n"));
  418. status = IoAcquireRemoveLock (&SmbNPBatt->RemoveLock, IrpSp->FileObject);
  419. //
  420. // Complete the request and return status.
  421. //
  422. Irp->IoStatus.Status = status;
  423. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  424. BattPrint(BAT_TRACE, ("SmbBattCreate: EXITING (status = 0x%08x\n", status));
  425. return(status);
  426. }
  427. NTSTATUS
  428. SmbBattClose(
  429. IN PDEVICE_OBJECT DeviceObject,
  430. IN PIRP Irp
  431. )
  432. {
  433. PSMB_NP_BATT SmbNPBatt = (PSMB_NP_BATT) DeviceObject->DeviceExtension;
  434. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  435. PAGED_CODE();
  436. BattPrint(BAT_TRACE, ("SmbBattClose: ENTERING\n"));
  437. IoReleaseRemoveLock (&SmbNPBatt->RemoveLock, IrpSp->FileObject);
  438. //
  439. // Complete the request and return status.
  440. //
  441. Irp->IoStatus.Status = STATUS_SUCCESS;
  442. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  443. BattPrint(BAT_TRACE, ("SmbBattClose: EXITING\n"));
  444. return(STATUS_SUCCESS);
  445. }
  446. NTSTATUS
  447. SmbBattIoctl(
  448. IN PDEVICE_OBJECT DeviceObject,
  449. IN PIRP Irp
  450. )
  451. /*++
  452. Routine Description:
  453. IOCTL handler. As this is an exclusive battery device, send the
  454. Irp to the battery class driver to handle battery IOCTLs.
  455. Arguments:
  456. DeviceObject - Battery for request
  457. Irp - IO request
  458. Return Value:
  459. Status of request
  460. --*/
  461. {
  462. PSMB_NP_BATT SmbNPBatt;
  463. PSMB_BATT SmbBatt;
  464. ULONG InputLen, OutputLen;
  465. PVOID IOBuffer;
  466. PIO_STACK_LOCATION IrpSp;
  467. BOOLEAN complete = TRUE;
  468. NTSTATUS status = STATUS_NOT_SUPPORTED;
  469. PAGED_CODE();
  470. BattPrint(BAT_TRACE, ("SmbBattIoctl: ENTERING\n"));
  471. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  472. SmbNPBatt = (PSMB_NP_BATT) DeviceObject->DeviceExtension;
  473. status = IoAcquireRemoveLock (&SmbNPBatt->RemoveLock, Irp);
  474. if (NT_SUCCESS(status)) {
  475. if (SmbNPBatt->SmbBattFdoType == SmbTypePdo) {
  476. status = STATUS_NOT_SUPPORTED;
  477. } else if (SmbNPBatt->SmbBattFdoType == SmbTypeSubsystem) {
  478. if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SMBBATT_DATA) {
  479. //
  480. // Direct Access Irp
  481. //
  482. IOBuffer = Irp->AssociatedIrp.SystemBuffer;
  483. InputLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  484. OutputLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  485. status = SmbBattDirectDataAccess (
  486. (PSMB_NP_BATT) DeviceObject->DeviceExtension,
  487. (PSMBBATT_DATA_STRUCT) IOBuffer,
  488. InputLen,
  489. OutputLen
  490. );
  491. if (NT_SUCCESS(status)) {
  492. Irp->IoStatus.Information = OutputLen;
  493. } else {
  494. Irp->IoStatus.Information = 0;
  495. }
  496. } else {
  497. status = STATUS_NOT_SUPPORTED;
  498. }
  499. } else {
  500. ASSERT (SmbNPBatt->SmbBattFdoType == SmbTypeBattery);
  501. //
  502. // Check to see if this is one of the private Ioctls we handle
  503. //
  504. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  505. case IOCTL_SMBBATT_DATA:
  506. IOBuffer = Irp->AssociatedIrp.SystemBuffer;
  507. InputLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  508. OutputLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  509. //
  510. // This one is only handled by the battery subsystem
  511. //
  512. status = SmbBattDirectDataAccess (
  513. (PSMB_NP_BATT) DeviceObject->DeviceExtension,
  514. (PSMBBATT_DATA_STRUCT) IOBuffer,
  515. InputLen,
  516. OutputLen
  517. );
  518. if (NT_SUCCESS(status)) {
  519. Irp->IoStatus.Information = OutputLen;
  520. } else {
  521. Irp->IoStatus.Information = 0;
  522. }
  523. break;
  524. default:
  525. //
  526. // Not IOCTL for us, see if it's for the battery
  527. //
  528. SmbBatt = SmbNPBatt->Batt;
  529. status = BatteryClassIoctl (SmbNPBatt->Class, Irp);
  530. if (NT_SUCCESS(status)) {
  531. //
  532. // The Irp was completed by the batery class. Don't
  533. // touch the Irp. Simply release the lock and return.
  534. //
  535. IoReleaseRemoveLock (&SmbNPBatt->RemoveLock, Irp);
  536. BattPrint(BAT_TRACE, ("SmbBattIoctl: EXITING (was battery IOCTL)\n", status));
  537. return status;
  538. }
  539. break;
  540. } // switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
  541. }
  542. IoReleaseRemoveLock (&SmbNPBatt->RemoveLock, Irp);
  543. }
  544. Irp->IoStatus.Status = status;
  545. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  546. BattPrint(BAT_TRACE, ("SmbBattIoctl: EXITING (status = 0x%08x)\n", status));
  547. return status;
  548. }
  549. NTSTATUS
  550. SmbBattQueryTag (
  551. IN PVOID Context,
  552. OUT PULONG BatteryTag
  553. )
  554. /*++
  555. Routine Description:
  556. Called by the class driver to retrieve the batteries current tag value
  557. Arguments:
  558. Context - Miniport context value for battery
  559. BatteryTag - Pointer to return current tag
  560. Return Value:
  561. Success if there is a battery currently installed, else no such device.
  562. --*/
  563. {
  564. //PSMB_BATT_SUBSYSTEM subsystemExt;
  565. NTSTATUS status;
  566. PSMB_BATT SmbBatt;
  567. ULONG oldSelectorState;
  568. PAGED_CODE();
  569. BattPrint(BAT_TRACE, ("SmbBattQueryTag: ENTERING\n"));
  570. //
  571. // Get device lock and make sure the selector is set up to talk to us.
  572. // Since multiple people may be doing this, always lock the selector
  573. // first followed by the battery.
  574. //
  575. SmbBatt = (PSMB_BATT) Context;
  576. SmbBattLockSelector (SmbBatt->Selector);
  577. SmbBattLockDevice (SmbBatt);
  578. status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
  579. if (!NT_SUCCESS (status)) {
  580. BattPrint(BAT_ERROR, ("SmbBattQueryTag: can't set selector communications path\n"));
  581. } else {
  582. //
  583. // If the tag is not valid, check for one
  584. //
  585. if (SmbBatt->Info.Tag == BATTERY_TAG_INVALID) {
  586. SmbBatt->Info.Valid = 0;
  587. }
  588. //
  589. // Insure the static information regarding the battery up to date
  590. //
  591. SmbBattVerifyStaticInfo (SmbBatt, 0);
  592. //
  593. // If theres a battery return it's tag
  594. //
  595. if (SmbBatt->Info.Tag != BATTERY_TAG_INVALID) {
  596. *BatteryTag = SmbBatt->Info.Tag;
  597. status = STATUS_SUCCESS;
  598. } else {
  599. status = STATUS_NO_SUCH_DEVICE;
  600. }
  601. }
  602. //
  603. // Done, unlock the device and reset the selector state
  604. //
  605. if (NT_SUCCESS (status)) {
  606. status = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  607. if (!NT_SUCCESS (status)) {
  608. BattPrint(BAT_ERROR, ("SmbBattQueryTag: can't reset selector communications path\n"));
  609. }
  610. } else {
  611. //
  612. // Ignore the return value from ResetSelectorComm because we already
  613. // have an error here.
  614. //
  615. SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  616. }
  617. SmbBattUnlockDevice (SmbBatt);
  618. SmbBattUnlockSelector (SmbBatt->Selector);
  619. BattPrint(BAT_TRACE, ("SmbBattQueryTag: EXITING\n"));
  620. return status;
  621. }
  622. NTSTATUS
  623. SmbBattQueryInformation (
  624. IN PVOID Context,
  625. IN ULONG BatteryTag,
  626. IN BATTERY_QUERY_INFORMATION_LEVEL Level,
  627. IN LONG AtRate OPTIONAL,
  628. OUT PVOID Buffer,
  629. IN ULONG BufferLength,
  630. OUT PULONG ReturnedLength
  631. )
  632. {
  633. PSMB_BATT SmbBatt;
  634. ULONG ResultData;
  635. BOOLEAN IoCheck;
  636. NTSTATUS status, st;
  637. PVOID ReturnBuffer;
  638. ULONG ReturnBufferLength;
  639. WCHAR scratchBuffer[SMB_MAX_DATA_SIZE+1]; // +1 for UNICODE_NULL
  640. UNICODE_STRING unicodeString;
  641. UNICODE_STRING tmpUnicodeString;
  642. ANSI_STRING ansiString;
  643. ULONG oldSelectorState;
  644. BATTERY_REPORTING_SCALE granularity;
  645. PAGED_CODE();
  646. BattPrint(BAT_TRACE, ("SmbBattQueryInformation: ENTERING\n"));
  647. if (BatteryTag == BATTERY_TAG_INVALID) {
  648. return STATUS_NO_SUCH_DEVICE;
  649. }
  650. //
  651. // Get device lock and make sure the selector is set up to talk to us.
  652. // Since multiple people may be doing this, always lock the selector
  653. // first followed by the battery.
  654. //
  655. SmbBatt = (PSMB_BATT) Context;
  656. SmbBattLockSelector (SmbBatt->Selector);
  657. SmbBattLockDevice (SmbBatt);
  658. status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
  659. if (!NT_SUCCESS (status)) {
  660. BattPrint(BAT_ERROR, ("SmbBattQueryInformation: can't set selector communications path\n"));
  661. } else {
  662. do {
  663. ResultData = 0;
  664. ReturnBuffer = NULL;
  665. ReturnBufferLength = 0;
  666. status = STATUS_SUCCESS;
  667. //
  668. // If no device, or caller has the wrong ID give an error
  669. //
  670. if (BatteryTag != SmbBatt->Info.Tag) {
  671. status = STATUS_NO_SUCH_DEVICE;
  672. break;
  673. }
  674. //
  675. // Get the info requested
  676. //
  677. switch (Level) {
  678. case BatteryInformation:
  679. ReturnBuffer = &SmbBatt->Info.Info;
  680. ReturnBufferLength = sizeof (SmbBatt->Info.Info);
  681. break;
  682. case BatteryGranularityInformation:
  683. SmbBattRW(SmbBatt, BAT_FULL_CHARGE_CAPACITY, &granularity.Capacity);
  684. granularity.Capacity *= SmbBatt->Info.PowerScale;
  685. granularity.Granularity = SmbBatt->Info.PowerScale;
  686. ReturnBuffer = &granularity;
  687. ReturnBufferLength = sizeof (granularity);
  688. break;
  689. case BatteryTemperature:
  690. SmbBattRW(SmbBatt, BAT_TEMPERATURE, &ResultData);
  691. ReturnBuffer = &ResultData;
  692. ReturnBufferLength = sizeof(ULONG);
  693. break;
  694. case BatteryEstimatedTime:
  695. //
  696. // If an AtRate has been specified, then we will use the AtRate
  697. // functions to get this information (AtRateTimeToEmpty()).
  698. // Otherwise, we will return the AVERAGE_TIME_TO_EMPTY.
  699. //
  700. BattPrint(BAT_DATA, ("SmbBattQueryInformation: EstimatedTime: AtRate: %08x\n", AtRate));
  701. if (AtRate != 0) {
  702. //
  703. // Currently we only support the time to empty functions.
  704. //
  705. ASSERT (AtRate < 0);
  706. //
  707. // The smart battery input value for AtRate is in 10mW increments
  708. //
  709. AtRate /= (LONG)SmbBatt->Info.PowerScale;
  710. BattPrint(BAT_DATA, ("SmbBattQueryInformation: EstimatedTime: AtRate scaled to: %08x\n", AtRate));
  711. SmbBattWW(SmbBatt, BAT_AT_RATE, AtRate);
  712. SmbBattRW(SmbBatt, BAT_RATE_TIME_TO_EMPTY, &ResultData);
  713. BattPrint(BAT_DATA, ("SmbBattQueryInformation: EstimatedTime: AT_RATE_TIME_TO_EMPTY: %08x\n", ResultData));
  714. } else {
  715. SmbBattRW(SmbBatt, BAT_AVERAGE_TIME_TO_EMPTY, &ResultData);
  716. BattPrint(BAT_DATA, ("SmbBattQueryInformation: EstimatedTime: AVERAGE_TIME_TO_EMPTY: %08x\n", ResultData));
  717. }
  718. if (ResultData == 0xffff) {
  719. ResultData = BATTERY_UNKNOWN_TIME;
  720. } else {
  721. ResultData *= 60;
  722. }
  723. BattPrint(BAT_DATA, ("SmbBattQueryInformation: (%01x) EstimatedTime: %08x seconds\n", SmbBatt->SelectorBitPosition, ResultData));
  724. ReturnBuffer = &ResultData;
  725. ReturnBufferLength = sizeof(ULONG);
  726. break;
  727. case BatteryDeviceName:
  728. //
  729. // This has to be returned as a WCHAR string but is kept internally
  730. // as a character string. Have to convert it.
  731. //
  732. unicodeString.Buffer = Buffer;
  733. unicodeString.MaximumLength = BufferLength > (USHORT)-1 ? (USHORT) -1 : (USHORT)BufferLength;
  734. ansiString.Length = SmbBatt->Info.DeviceNameLength;
  735. ansiString.MaximumLength = sizeof(SmbBatt->Info.DeviceName);
  736. ansiString.Buffer = SmbBatt->Info.DeviceName;
  737. status = RtlAnsiStringToUnicodeString (&unicodeString, &ansiString, FALSE);
  738. if (NT_SUCCESS(status)) {
  739. ReturnBuffer = Buffer;
  740. ReturnBufferLength = unicodeString.Length;
  741. }
  742. break;
  743. case BatteryManufactureDate:
  744. ReturnBuffer = &SmbBatt->Info.ManufacturerDate;
  745. ReturnBufferLength = sizeof (SmbBatt->Info.ManufacturerDate);
  746. break;
  747. case BatteryManufactureName:
  748. //
  749. // This has to be returned as a WCHAR string but is kept internally
  750. // as a character string. Have to convert it.
  751. //
  752. unicodeString.Buffer = Buffer;
  753. unicodeString.MaximumLength = BufferLength > (USHORT)-1 ? (USHORT) -1 : (USHORT)BufferLength;
  754. ansiString.Length = SmbBatt->Info.ManufacturerNameLength;
  755. ansiString.MaximumLength = sizeof(SmbBatt->Info.ManufacturerName);
  756. ansiString.Buffer = SmbBatt->Info.ManufacturerName;
  757. status = RtlAnsiStringToUnicodeString (&unicodeString, &ansiString, FALSE);
  758. if (NT_SUCCESS(status)) {
  759. ReturnBuffer = Buffer;
  760. ReturnBufferLength = unicodeString.Length;
  761. }
  762. break;
  763. case BatteryUniqueID:
  764. //
  765. // The unique ID is a character string consisting of the serial
  766. // number, the manufacturer name, and the device name.
  767. //
  768. unicodeString.Buffer = Buffer;
  769. unicodeString.MaximumLength = BufferLength > (USHORT)-1 ? (USHORT) -1 : (USHORT)BufferLength;
  770. tmpUnicodeString.Buffer = scratchBuffer;
  771. tmpUnicodeString.MaximumLength = sizeof (scratchBuffer);
  772. RtlIntegerToUnicodeString(SmbBatt->Info.SerialNumber, 10, &unicodeString);
  773. ansiString.Length = SmbBatt->Info.ManufacturerNameLength;
  774. ansiString.MaximumLength = sizeof(SmbBatt->Info.ManufacturerName);
  775. ansiString.Buffer = SmbBatt->Info.ManufacturerName;
  776. status = RtlAnsiStringToUnicodeString (&tmpUnicodeString, &ansiString, FALSE);
  777. if (!NT_SUCCESS(status)) break;
  778. status = RtlAppendUnicodeStringToString (&unicodeString, &tmpUnicodeString);
  779. if (!NT_SUCCESS(status)) break;
  780. ansiString.Length = SmbBatt->Info.DeviceNameLength;
  781. ansiString.MaximumLength = sizeof(SmbBatt->Info.DeviceName);
  782. ansiString.Buffer = SmbBatt->Info.DeviceName;
  783. status = RtlAnsiStringToUnicodeString (&tmpUnicodeString, &ansiString, FALSE);
  784. if (!NT_SUCCESS(status)) break;
  785. status = RtlAppendUnicodeStringToString (&unicodeString, &tmpUnicodeString);
  786. if (!NT_SUCCESS(status)) break;
  787. ReturnBuffer = Buffer;
  788. ReturnBufferLength = unicodeString.Length;
  789. break;
  790. }
  791. //
  792. // Re-verify static info in case there's been an IO error
  793. //
  794. //IoCheck = SmbBattVerifyStaticInfo (SmbBatt, BatteryTag);
  795. IoCheck = FALSE;
  796. } while (IoCheck);
  797. }
  798. if (NT_SUCCESS (status)) {
  799. //
  800. // Done, return buffer if needed
  801. //
  802. *ReturnedLength = ReturnBufferLength;
  803. if (ReturnBuffer != Buffer) {
  804. // ReturnBuffer == Buffer indicates that data is already copied.
  805. //
  806. if (BufferLength < ReturnBufferLength) {
  807. status = STATUS_BUFFER_TOO_SMALL;
  808. }
  809. if (NT_SUCCESS(status) && ReturnBuffer) {
  810. memcpy (Buffer, ReturnBuffer, ReturnBufferLength);
  811. }
  812. }
  813. //
  814. // Unlock the device and reset the selector state
  815. //
  816. st = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  817. if (!NT_SUCCESS (st)) {
  818. BattPrint(BAT_ERROR, ("SmbBattQueryInformation: can't reset selector communications path\n"));
  819. status = st;
  820. }
  821. } else {
  822. *ReturnedLength = 0;
  823. //
  824. // Ignore the return value from ResetSelectorComm because we already
  825. // have an error here.
  826. //
  827. SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  828. }
  829. SmbBattUnlockDevice (SmbBatt);
  830. SmbBattUnlockSelector (SmbBatt->Selector);
  831. BattPrint(BAT_TRACE, ("SmbBattQueryInformation: EXITING\n"));
  832. return status;
  833. }
  834. NTSTATUS
  835. SmbBattSetInformation (
  836. IN PVOID Context,
  837. IN ULONG BatteryTag,
  838. IN BATTERY_SET_INFORMATION_LEVEL Level,
  839. IN PVOID Buffer OPTIONAL
  840. )
  841. /*++
  842. Routine Description:
  843. Called by the class driver to set the battery's charge/discharge state.
  844. The smart battery does not support the critical bias function of this
  845. call.
  846. Arguments:
  847. Context - Miniport context value for battery
  848. BatteryTag - Tag of current battery
  849. Level - Action being asked for
  850. Return Value:
  851. NTSTATUS
  852. --*/
  853. {
  854. PSMB_BATT SmbBatt;
  855. ULONG newSelectorState;
  856. ULONG selectorState;
  857. UCHAR smbStatus;
  858. ULONG tmp;
  859. NTSTATUS status = STATUS_NOT_SUPPORTED;
  860. PAGED_CODE();
  861. BattPrint(BAT_TRACE, ("SmbBattSetInformation: ENTERING\n"));
  862. SmbBatt = (PSMB_BATT) Context;
  863. //
  864. // See if this is for our battery
  865. //
  866. if ((BatteryTag == BATTERY_TAG_INVALID) || (BatteryTag != SmbBatt->Info.Tag)) {
  867. return STATUS_NO_SUCH_DEVICE;
  868. }
  869. //
  870. // We can only do this if there is a selector in the system
  871. //
  872. if ((SmbBatt->SelectorPresent) && (SmbBatt->Selector)) {
  873. //
  874. // Get a lock on the selector
  875. //
  876. SmbBattLockSelector (SmbBatt->Selector);
  877. switch (Level) {
  878. case BatteryCharge:
  879. BattPrint(BAT_IRPS, ("SmbBattSetInformation: Got SetInformation for BatteryCharge\n"));
  880. //
  881. // Set the appropriate bit in the selector state charge nibble
  882. //
  883. newSelectorState = SELECTOR_SET_CHARGE_MASK;
  884. newSelectorState |= (SmbBatt->SelectorBitPosition << SELECTOR_SHIFT_CHARGE);
  885. //
  886. // Write the new selector state, then read it back. The system
  887. // may or may not let us do this.
  888. //
  889. smbStatus = SmbBattGenericWW (
  890. SmbBatt->SmbHcFdo,
  891. SmbBatt->Selector->SelectorAddress,
  892. SmbBatt->Selector->SelectorStateCommand,
  893. newSelectorState
  894. );
  895. if (smbStatus != SMB_STATUS_OK) {
  896. BattPrint(BAT_ERROR,
  897. ("SmbBattSetInformation: couldn't write selector state - %x\n",
  898. smbStatus)
  899. );
  900. status = STATUS_UNSUCCESSFUL;
  901. break;
  902. }
  903. smbStatus = SmbBattGenericRW (
  904. SmbBatt->SmbHcFdo,
  905. SmbBatt->Selector->SelectorAddress,
  906. SmbBatt->Selector->SelectorStateCommand,
  907. &selectorState
  908. );
  909. if ((smbStatus != SMB_STATUS_OK)) {
  910. BattPrint(BAT_ERROR,
  911. ("SmbBattSetInformation: couldn't read selector state - %x\n",
  912. smbStatus)
  913. );
  914. status = STATUS_UNSUCCESSFUL;
  915. break;
  916. }
  917. //
  918. // Check the status that was read versus what we wrote
  919. // to see if the operation was successful
  920. //
  921. // To support simultaneous charging of more than one battery,
  922. // we can't check the charge nibble to see if it is equal to
  923. // what we wrote, but we can check to see if the battery
  924. // we specified to charge is now set to charge.
  925. tmp = (selectorState & SELECTOR_STATE_CHARGE_MASK) >> SELECTOR_SHIFT_CHARGE;
  926. if (SmbBattReverseLogic(SmbBatt->Selector, tmp)) {
  927. tmp ^= SELECTOR_STATE_PRESENT_MASK;
  928. }
  929. if (tmp & SmbBatt->SelectorBitPosition) {
  930. BattPrint(BAT_IRPS, ("SmbBattSetInformation: successfully set charging battery\n"));
  931. //
  932. // Success! Save the new selector state in the cache
  933. //
  934. SmbBatt->Selector->SelectorState = selectorState;
  935. status = STATUS_SUCCESS;
  936. } else {
  937. BattPrint(BAT_ERROR, ("SmbBattSetInformation: couldn't set charging battery\n"));
  938. status = STATUS_UNSUCCESSFUL;
  939. }
  940. break;
  941. case BatteryDischarge:
  942. BattPrint(BAT_IRPS, ("SmbBattSetInformation: Got SetInformation for BatteryDischarge\n"));
  943. //
  944. // Set the appropriate bit in the selector state power by nibble
  945. //
  946. newSelectorState = SELECTOR_SET_POWER_BY_MASK;
  947. newSelectorState |= (SmbBatt->SelectorBitPosition << SELECTOR_SHIFT_POWER);
  948. //
  949. // Write the new selector state, then read it back. The system
  950. // may or may not let us do this.
  951. //
  952. smbStatus = SmbBattGenericWW (
  953. SmbBatt->SmbHcFdo,
  954. SmbBatt->Selector->SelectorAddress,
  955. SmbBatt->Selector->SelectorStateCommand,
  956. newSelectorState
  957. );
  958. if (smbStatus != SMB_STATUS_OK) {
  959. BattPrint(BAT_ERROR,
  960. ("SmbBattSetInformation: couldn't write selector state - %x\n",
  961. smbStatus)
  962. );
  963. status = STATUS_UNSUCCESSFUL;
  964. break;
  965. }
  966. smbStatus = SmbBattGenericRW (
  967. SmbBatt->SmbHcFdo,
  968. SmbBatt->Selector->SelectorAddress,
  969. SmbBatt->Selector->SelectorStateCommand,
  970. &selectorState
  971. );
  972. if ((smbStatus != SMB_STATUS_OK)) {
  973. BattPrint(BAT_ERROR,
  974. ("SmbBattSetInformation: couldn't read selector state - %x\n",
  975. smbStatus)
  976. );
  977. status = STATUS_UNSUCCESSFUL;
  978. break;
  979. }
  980. //
  981. // Check the status that was read versus what we wrote
  982. // to see if the operation was successful
  983. //
  984. // To support simultaneous powering of more than one battery,
  985. // we can't check the power nibble to see if it is equal to
  986. // what we wrote, but we can check to see if the battery
  987. // we specified to power by is now set to power the system.
  988. tmp = (selectorState & SELECTOR_STATE_POWER_BY_MASK) >> SELECTOR_SHIFT_POWER;
  989. if (SmbBattReverseLogic(SmbBatt->Selector, tmp)) {
  990. tmp ^= SELECTOR_STATE_PRESENT_MASK;
  991. }
  992. if (tmp & SmbBatt->SelectorBitPosition) {
  993. BattPrint(BAT_IRPS, ("SmbBattSetInformation: successfully set powering battery\n"));
  994. //
  995. // Success! Save the new selector state in the cache
  996. //
  997. SmbBatt->Selector->SelectorState = selectorState;
  998. status = STATUS_SUCCESS;
  999. } else {
  1000. BattPrint(BAT_ERROR, ("SmbBattSetInformation: couldn't set powering battery\n"));
  1001. status = STATUS_UNSUCCESSFUL;
  1002. }
  1003. break;
  1004. } // switch (Level)
  1005. //
  1006. // Release the lock on the selector
  1007. //
  1008. SmbBattUnlockSelector (SmbBatt->Selector);
  1009. } // if (SmbBatt->Selector->SelectorPresent)
  1010. BattPrint(BAT_TRACE, ("SmbBattSetInformation: EXITING\n"));
  1011. return status;
  1012. }
  1013. NTSTATUS
  1014. SmbBattGetPowerState (
  1015. IN PSMB_BATT SmbBatt,
  1016. OUT PULONG PowerState,
  1017. OUT PLONG Current
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. Returns the current state of AC power. There are several cases which
  1022. make this far more complex than it really ought to be.
  1023. NOTE: the selector must be locked before entering this routine.
  1024. Arguments:
  1025. SmbBatt - Miniport context value for battery
  1026. AcConnected - Pointer to a boolean where the AC status is returned
  1027. Return Value:
  1028. NTSTATUS
  1029. --*/
  1030. {
  1031. ULONG tmp;
  1032. ULONG chargeBattery;
  1033. ULONG powerBattery;
  1034. NTSTATUS status;
  1035. UCHAR smbStatus;
  1036. PAGED_CODE();
  1037. status = STATUS_SUCCESS;
  1038. *PowerState = 0;
  1039. //
  1040. // Is there a selector in the system? if not, go read directly from the charger
  1041. //
  1042. if ((SmbBatt->SelectorPresent) && (SmbBatt->Selector)) {
  1043. //
  1044. // There is a selector, we will examine the CHARGE nibble of the state register
  1045. //
  1046. SmbBattGenericRW(
  1047. SmbBatt->SmbHcFdo,
  1048. SMB_SELECTOR_ADDRESS,
  1049. SELECTOR_SELECTOR_STATE,
  1050. &SmbBatt->Selector->SelectorState);
  1051. chargeBattery = (SmbBatt->Selector->SelectorState & SELECTOR_STATE_CHARGE_MASK) >> SELECTOR_SHIFT_CHARGE;
  1052. powerBattery = (SmbBatt->Selector->SelectorState & SELECTOR_STATE_POWER_BY_MASK) >> SELECTOR_SHIFT_POWER;
  1053. //
  1054. // If the bits in the CHARGE_X nibble of the selector state register are in the
  1055. // reverse logic state, then AC is connected, otherwise AC is not connected.
  1056. //
  1057. // NOTE: This code depends on every selector implementing this. If it turns out
  1058. // that this is optional, we can no longer depend on this, and must enable the
  1059. // code below it.
  1060. //
  1061. if (SmbBattReverseLogic(SmbBatt->Selector, chargeBattery)) {
  1062. *PowerState |= BATTERY_POWER_ON_LINE;
  1063. }
  1064. //
  1065. // Look at Charge Indicator if it is supported
  1066. //
  1067. if (*PowerState & BATTERY_POWER_ON_LINE) {
  1068. if (SmbBatt->Selector->SelectorInfo & SELECTOR_INFO_CHARGING_INDICATOR_BIT) {
  1069. if (SmbBattReverseLogic(SmbBatt->Selector, powerBattery)) {
  1070. *PowerState |= BATTERY_CHARGING;
  1071. }
  1072. }
  1073. if (*Current > 0) {
  1074. *PowerState |= BATTERY_CHARGING;
  1075. }
  1076. } else {
  1077. if (*Current <= 0) {
  1078. //
  1079. // There is some small leakage on some systems, even when AC
  1080. // is present. So, if AC is present, and the draw
  1081. // is below this "noise" level we will not report as discharging
  1082. // and zero this out.
  1083. //
  1084. if (*Current < -25) {
  1085. *PowerState |= BATTERY_DISCHARGING;
  1086. } else {
  1087. *Current = 0;
  1088. }
  1089. }
  1090. //else {
  1091. // *PowerState |= BATTERY_CHARGING;
  1092. //
  1093. //}
  1094. // If we don't report as discharging, then the AC adapter removal
  1095. // might cause a PowerState of 0 to return, which PowerMeter assumes
  1096. // means, don't change anything
  1097. *PowerState |= BATTERY_DISCHARGING;
  1098. }
  1099. } else {
  1100. //
  1101. // There is no selector, so we'll try to read from the charger.
  1102. //
  1103. smbStatus = SmbBattGenericRW (
  1104. SmbBatt->SmbHcFdo,
  1105. SMB_CHARGER_ADDRESS,
  1106. CHARGER_STATUS,
  1107. &tmp
  1108. );
  1109. if (smbStatus != SMB_STATUS_OK) {
  1110. BattPrint (
  1111. BAT_ERROR,
  1112. ("SmbBattGetPowerState: Trying to get charging info, couldn't read from charger at %x, status %x\n",
  1113. SMB_CHARGER_ADDRESS,
  1114. smbStatus)
  1115. );
  1116. *PowerState = 0;
  1117. status = STATUS_UNSUCCESSFUL;
  1118. }
  1119. // Read Charger Successful
  1120. else {
  1121. if (tmp & CHARGER_STATUS_AC_PRESENT_BIT) {
  1122. *PowerState = BATTERY_POWER_ON_LINE;
  1123. if (*Current > 0) {
  1124. *PowerState |= BATTERY_CHARGING;
  1125. }
  1126. } else {
  1127. if (*Current <= 0) {
  1128. //
  1129. // There is some small leakage on some systems, even when AC
  1130. // is present. So, if AC is present, and the draw
  1131. // is below this "noise" level we will not report as discharging
  1132. // and zero this out.
  1133. //
  1134. if (*Current < -25) {
  1135. *PowerState |= BATTERY_DISCHARGING;
  1136. } else {
  1137. *Current = 0;
  1138. }
  1139. }
  1140. // If we don't report as discharging, then the AC adapter removal
  1141. // might cause a PowerState of 0 to return, which PowerMeter assumes
  1142. // means, don't change anything
  1143. *PowerState |= BATTERY_DISCHARGING;
  1144. }
  1145. }
  1146. }
  1147. return status;
  1148. }
  1149. NTSTATUS
  1150. SmbBattQueryStatus (
  1151. IN PVOID Context,
  1152. IN ULONG BatteryTag,
  1153. OUT PBATTERY_STATUS BatteryStatus
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Called by the class driver to retrieve the batteries current status
  1158. N.B. the battery class driver will serialize all requests it issues to
  1159. the miniport for a given battery. However, this miniport implements
  1160. a lock on the battery device as it needs to serialize to the smb
  1161. battery selector device as well.
  1162. Arguments:
  1163. Context - Miniport context value for battery
  1164. BatteryTag - Tag of current battery
  1165. BatteryStatus - Pointer to structure to return the current battery status
  1166. Return Value:
  1167. Success if there is a battery currently installed, else no such device.
  1168. --*/
  1169. {
  1170. PSMB_BATT SmbBatt;
  1171. NTSTATUS status;
  1172. BOOLEAN IoCheck;
  1173. LONG Current;
  1174. ULONG oldSelectorState;
  1175. PAGED_CODE();
  1176. BattPrint(BAT_TRACE, ("SmbBattQueryStatus: ENTERING\n"));
  1177. if (BatteryTag == BATTERY_TAG_INVALID) {
  1178. return STATUS_NO_SUCH_DEVICE;
  1179. }
  1180. status = STATUS_SUCCESS;
  1181. //
  1182. // Get device lock and make sure the selector is set up to talk to us.
  1183. // Since multiple people may be doing this, always lock the selector
  1184. // first followed by the battery.
  1185. //
  1186. SmbBatt = (PSMB_BATT) Context;
  1187. SmbBattLockSelector (SmbBatt->Selector);
  1188. SmbBattLockDevice (SmbBatt);
  1189. status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
  1190. if (!NT_SUCCESS (status)) {
  1191. BattPrint(BAT_ERROR, ("SmbBattQueryStatus: can't set selector communications path\n"));
  1192. } else {
  1193. do {
  1194. if (BatteryTag != SmbBatt->Info.Tag) {
  1195. status = STATUS_NO_SUCH_DEVICE;
  1196. break;
  1197. }
  1198. SmbBattRW(SmbBatt, BAT_VOLTAGE, &BatteryStatus->Voltage);
  1199. BatteryStatus->Voltage *= SmbBatt->Info.VoltageScale;
  1200. SmbBattRW(SmbBatt, BAT_REMAINING_CAPACITY, &BatteryStatus->Capacity);
  1201. BatteryStatus->Capacity *= SmbBatt->Info.PowerScale;
  1202. SmbBattRSW(SmbBatt, BAT_CURRENT, &Current);
  1203. Current *= SmbBatt->Info.CurrentScale;
  1204. BattPrint(BAT_DATA,
  1205. ("SmbBattQueryStatus: (%01x)\n"
  1206. "------- Remaining Capacity - %x\n"
  1207. "------- Voltage - %x\n"
  1208. "------- Current - %x\n",
  1209. SmbBatt->SelectorBitPosition,
  1210. BatteryStatus->Capacity,
  1211. BatteryStatus->Voltage,
  1212. Current)
  1213. );
  1214. BatteryStatus->Rate = (Current * ((LONG)BatteryStatus->Voltage))/1000;
  1215. //
  1216. // Check to see if we are currently connected to AC.
  1217. //
  1218. status = SmbBattGetPowerState (SmbBatt, &BatteryStatus->PowerState, &Current);
  1219. if (!NT_SUCCESS (status)) {
  1220. BatteryStatus->PowerState = 0;
  1221. }
  1222. //
  1223. // Re-verify static info in case there's been an IO error
  1224. //
  1225. IoCheck = SmbBattVerifyStaticInfo (SmbBatt, BatteryTag);
  1226. } while (IoCheck);
  1227. }
  1228. if (NT_SUCCESS (status)) {
  1229. //
  1230. // Set batteries current power state & capacity
  1231. //
  1232. SmbBatt->Info.PowerState = BatteryStatus->PowerState;
  1233. SmbBatt->Info.Capacity = BatteryStatus->Capacity;
  1234. //
  1235. // Done, unlock the device and reset the selector state
  1236. //
  1237. status = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  1238. if (!NT_SUCCESS (status)) {
  1239. BattPrint(BAT_ERROR, ("SmbBattQueryStatus: can't reset selector communications path\n"));
  1240. }
  1241. } else {
  1242. //
  1243. // Ignore the return value from ResetSelectorComm because we already
  1244. // have an error here.
  1245. //
  1246. SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  1247. }
  1248. SmbBattUnlockDevice (SmbBatt);
  1249. SmbBattUnlockSelector (SmbBatt->Selector);
  1250. BattPrint(BAT_TRACE, ("SmbBattQueryStatus: EXITING\n"));
  1251. return status;
  1252. }
  1253. NTSTATUS
  1254. SmbBattSetStatusNotify (
  1255. IN PVOID Context,
  1256. IN ULONG BatteryTag,
  1257. IN PBATTERY_NOTIFY Notify
  1258. )
  1259. /*++
  1260. Routine Description:
  1261. Called by the class driver to set the batteries current notification
  1262. setting. When the battery trips the notification, one call to
  1263. BatteryClassStatusNotify is issued. If an error is returned, the
  1264. class driver will poll the battery status - primarily for capacity
  1265. changes. Which is to say the miniport should still issue BatteryClass-
  1266. StatusNotify whenever the power state changes.
  1267. The class driver will always set the notification level it needs
  1268. after each call to BatteryClassStatusNotify.
  1269. Arguments:
  1270. Context - Miniport context value for battery
  1271. BatteryTag - Tag of current battery
  1272. BatteryNotify - The notification setting
  1273. Return Value:
  1274. Status
  1275. --*/
  1276. {
  1277. PSMB_BATT SmbBatt;
  1278. NTSTATUS status;
  1279. BOOLEAN UpdateAlarm;
  1280. ULONG Target, NewAlarm;
  1281. LONG DeltaAdjustment, Attempt, i;
  1282. ULONG oldSelectorState;
  1283. PAGED_CODE();
  1284. BattPrint(BAT_TRACE, ("SmbBattSetStatusNotify: ENTERING\n"));
  1285. if (BatteryTag == BATTERY_TAG_INVALID) {
  1286. return STATUS_NO_SUCH_DEVICE;
  1287. }
  1288. if ((Notify->HighCapacity == BATTERY_UNKNOWN_CAPACITY) ||
  1289. (Notify->LowCapacity == BATTERY_UNKNOWN_CAPACITY)) {
  1290. BattPrint(BAT_WARN, ("SmbBattSetStatusNotify: Failing because of BATTERY_UNKNOWN_CAPACITY.\n"));
  1291. return STATUS_NOT_SUPPORTED;
  1292. }
  1293. status = STATUS_SUCCESS;
  1294. //
  1295. // Get device lock and make sure the selector is set up to talk to us.
  1296. // Since multiple people may be doing this, always lock the selector
  1297. // first followed by the battery.
  1298. //
  1299. SmbBatt = (PSMB_BATT) Context;
  1300. BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x): Called with LowCapacity = %08x\n",
  1301. SmbBatt->SelectorBitPosition, Notify->LowCapacity));
  1302. SmbBattLockSelector (SmbBatt->Selector);
  1303. SmbBattLockDevice (SmbBatt);
  1304. status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
  1305. if (!NT_SUCCESS (status)) {
  1306. BattPrint(BAT_ERROR, ("SmbBattSetStatusNotify: can't set selector communications path\n"));
  1307. } else {
  1308. // Target (10*PS*mWh) = Lowcapacity (mWh) / 10*PS (1/(10*PS))
  1309. Target = Notify->LowCapacity / SmbBatt->Info.PowerScale;
  1310. DeltaAdjustment = 0;
  1311. BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x): Last set to: %08x\n",
  1312. SmbBatt->SelectorBitPosition, SmbBatt->AlarmLow.Setting));
  1313. //
  1314. // Some batteries are messed up and won't just take an alarm setting. Fortunately,
  1315. // the error is off in some linear fashion, so this code attempts to hone in on the
  1316. // adjustment needed to get the proper setting, along with an "allowable fudge value",
  1317. // since sometimes the desired setting can never be obtained.
  1318. //
  1319. for (; ;) {
  1320. if (BatteryTag != SmbBatt->Info.Tag) {
  1321. status = STATUS_NO_SUCH_DEVICE;
  1322. break;
  1323. }
  1324. //
  1325. // If the status is charging we can't detect. Let the OS poll
  1326. //
  1327. if (SmbBatt->Info.PowerState & (BATTERY_CHARGING | BATTERY_POWER_ON_LINE)) {
  1328. status = STATUS_NOT_SUPPORTED;
  1329. break;
  1330. }
  1331. //
  1332. // If the current capacity is below the target, fire an alarm and we're done
  1333. //
  1334. if (SmbBatt->Info.Capacity < Target) {
  1335. BatteryClassStatusNotify (SmbBatt->NP->Class);
  1336. break;
  1337. }
  1338. //
  1339. // If the target setting is the Skip value then there was an error attempting
  1340. // this value last time.
  1341. //
  1342. if (Target == SmbBatt->AlarmLow.Skip) {
  1343. status = STATUS_NOT_SUPPORTED;
  1344. break;
  1345. }
  1346. //
  1347. // If the current setting is above the current capacity then we need to
  1348. // program the alarm
  1349. //
  1350. UpdateAlarm = FALSE;
  1351. if (Target < SmbBatt->AlarmLow.Setting) {
  1352. UpdateAlarm = TRUE;
  1353. }
  1354. //
  1355. // If the target alarm is above the current setting, and the current setting
  1356. // is off by more then AllowedFudge then it needs updated
  1357. //
  1358. if (Target > SmbBatt->AlarmLow.Setting &&
  1359. Target - SmbBatt->AlarmLow.Setting > (ULONG) SmbBatt->AlarmLow.AllowedFudge) {
  1360. UpdateAlarm = TRUE;
  1361. }
  1362. //
  1363. // If alarm doesn't need updated, done
  1364. //
  1365. if (!UpdateAlarm) {
  1366. BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x) NOT Updating Alarm.\n", SmbBatt->SelectorBitPosition));
  1367. break;
  1368. }
  1369. BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x) Updating Alarm.\n", SmbBatt->SelectorBitPosition));
  1370. //
  1371. // If this is not the first time, then delta is not good enough. Let's start
  1372. // adjusting it
  1373. //
  1374. if (DeltaAdjustment) {
  1375. //
  1376. // If delta is positive subtract off 1/2 of fudge
  1377. //
  1378. if (DeltaAdjustment > 0) {
  1379. DeltaAdjustment -= SmbBatt->AlarmLow.AllowedFudge / 2 + (SmbBatt->AlarmLow.AllowedFudge & 1);
  1380. // too much - don't handle it
  1381. if (DeltaAdjustment > 50) {
  1382. status = STATUS_NOT_SUPPORTED;
  1383. break;
  1384. }
  1385. } else {
  1386. // too much - don't handle it
  1387. if (DeltaAdjustment < -50) {
  1388. status = STATUS_NOT_SUPPORTED;
  1389. break;
  1390. }
  1391. }
  1392. SmbBatt->AlarmLow.Delta += DeltaAdjustment;
  1393. }
  1394. //
  1395. // If attempt is less then 1, then we can't set it
  1396. //
  1397. Attempt = Target + SmbBatt->AlarmLow.Delta;
  1398. if (Attempt < 1) {
  1399. // battery class driver needs to poll for it
  1400. status = STATUS_NOT_SUPPORTED;
  1401. break;
  1402. }
  1403. //
  1404. // Perform IOs to update & read back the alarm. Use VerifyStaticInfo after
  1405. // IOs in case there's an IO error and the state is lost.
  1406. //
  1407. SmbBattWW(SmbBatt, BAT_REMAINING_CAPACITY_ALARM, Attempt);
  1408. // verify in case there was an IO error
  1409. //if (SmbBattVerifyStaticInfo (SmbBatt, BatteryTag)) {
  1410. // DeltaAdjustment = 0;
  1411. // continue;
  1412. //}
  1413. SmbBattRW(SmbBatt, BAT_REMAINING_CAPACITY_ALARM, &NewAlarm);
  1414. // verify in case there was an IO error
  1415. //if (SmbBattVerifyStaticInfo (SmbBatt, BatteryTag)) {
  1416. // DeltaAdjustment = 0;
  1417. // continue;
  1418. //}
  1419. BattPrint(BAT_DATA,
  1420. ("SmbBattSetStatusNotify: (%01x) Want %X, Had %X, Got %X, CurrentCap %X, Delta %d, Fudge %d\n",
  1421. SmbBatt->SelectorBitPosition,
  1422. Target,
  1423. SmbBatt->AlarmLow.Setting,
  1424. NewAlarm,
  1425. SmbBatt->Info.Capacity / SmbBatt->Info.PowerScale,
  1426. SmbBatt->AlarmLow.Delta,
  1427. SmbBatt->AlarmLow.AllowedFudge
  1428. ));
  1429. //
  1430. // If DeltaAdjustment was applied to Delta but the setting
  1431. // moved by more then DeltaAdjustment, then increase the
  1432. // allowed fudge.
  1433. //
  1434. if (DeltaAdjustment) {
  1435. i = NewAlarm - SmbBatt->AlarmLow.Setting - DeltaAdjustment;
  1436. if (DeltaAdjustment < 0) {
  1437. DeltaAdjustment = -DeltaAdjustment;
  1438. i = -i;
  1439. }
  1440. if (i > SmbBatt->AlarmLow.AllowedFudge) {
  1441. SmbBatt->AlarmLow.AllowedFudge = i;
  1442. BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: Fudge increased to %x\n", SmbBatt->AlarmLow.AllowedFudge));
  1443. }
  1444. }
  1445. //
  1446. // Current setting
  1447. //
  1448. SmbBatt->AlarmLow.Setting = NewAlarm;
  1449. //
  1450. // Compute next delta adjustment
  1451. //
  1452. DeltaAdjustment = Target - SmbBatt->AlarmLow.Setting;
  1453. }
  1454. //
  1455. // If there was an attempt to set the alarm but it failed, set the
  1456. // skip value so we don't keep trying to set an alarm for this value
  1457. // which isn't working
  1458. //
  1459. if (!NT_SUCCESS(status) && DeltaAdjustment) {
  1460. SmbBatt->AlarmLow.Skip = Target;
  1461. }
  1462. }
  1463. //
  1464. // Done, unlock the device and reset the selector state
  1465. //
  1466. if (NT_SUCCESS (status)) {
  1467. status = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  1468. if (!NT_SUCCESS (status)) {
  1469. BattPrint(BAT_ERROR, ("SmbBattSetStatusNotify: can't reset selector communications path\n"));
  1470. }
  1471. } else {
  1472. //
  1473. // Ignore the return value from ResetSelectorComm because we already
  1474. // have an error here.
  1475. //
  1476. SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  1477. }
  1478. SmbBattUnlockDevice (SmbBatt);
  1479. SmbBattUnlockSelector (SmbBatt->Selector);
  1480. BattPrint(BAT_TRACE, ("SmbBattSetStatusNotify: EXITING\n"));
  1481. return status;
  1482. }
  1483. NTSTATUS
  1484. SmbBattDisableStatusNotify (
  1485. IN PVOID Context
  1486. )
  1487. /*++
  1488. Routine Description:
  1489. Called by the class driver to disable the notification setting
  1490. for the battery supplied by Context. Note, to disable a setting
  1491. does not require the battery tag. Any notification is to be
  1492. masked off until a subsequent call to SmbBattSetStatusNotify.
  1493. Arguments:
  1494. Context - Miniport context value for battery
  1495. Return Value:
  1496. Status
  1497. --*/
  1498. {
  1499. NTSTATUS status;
  1500. PSMB_BATT SmbBatt;
  1501. ULONG oldSelectorState;
  1502. PAGED_CODE();
  1503. BattPrint(BAT_TRACE, ("SmbBattDisableStatusNotify: ENTERING\n"));
  1504. SmbBatt = (PSMB_BATT) Context;
  1505. SmbBattLockSelector (SmbBatt->Selector);
  1506. SmbBattLockDevice (SmbBatt);
  1507. status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
  1508. if (!NT_SUCCESS (status)) {
  1509. BattPrint(BAT_ERROR, ("SmbBattDisableStatusNotify: can't set selector communications path\n"));
  1510. } else {
  1511. SmbBatt->AlarmLow.Setting = 0;
  1512. SmbBattWW(SmbBatt, BAT_REMAINING_CAPACITY_ALARM, 0);
  1513. //
  1514. // Done, reset the selector state.
  1515. //
  1516. status = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  1517. if (!NT_SUCCESS (status)) {
  1518. BattPrint(BAT_ERROR, ("SmbBattDisableStatusNotify: can't reset selector communications path\n"));
  1519. }
  1520. }
  1521. //
  1522. // Done, unlock the device
  1523. //
  1524. SmbBattUnlockDevice (SmbBatt);
  1525. SmbBattUnlockSelector (SmbBatt->Selector);
  1526. BattPrint(BAT_TRACE, ("SmbBattDisableStatusNotify: EXITING\n"));
  1527. return STATUS_SUCCESS;
  1528. }
  1529. BOOLEAN
  1530. SmbBattVerifyStaticInfo (
  1531. IN PSMB_BATT SmbBatt,
  1532. IN ULONG BatteryTag
  1533. )
  1534. /*++
  1535. Routine Description:
  1536. Reads any non-valid cached battery info and set Info.Valid accordingly.
  1537. Performs a serial number check after reading in battery info in order
  1538. to detect verify the data is from the same battery. If the value does
  1539. not match what is expect, the cached info is reset and the function
  1540. iterates until a consistent snapshot is obtained.
  1541. Arguments:
  1542. SmbBatt - Battery to read
  1543. BatteryTag - Tag of battery as expected by the caller
  1544. Return Value:
  1545. Returns a boolean to indicate to the caller that IO was performed.
  1546. This allows the caller to iterate on changes it may be making until
  1547. the battery state is correct.
  1548. --*/
  1549. {
  1550. ULONG BatteryMode;
  1551. ULONG ManufacturerDate;
  1552. UCHAR Buffer[SMB_MAX_DATA_SIZE];
  1553. UCHAR BufferLength;
  1554. BOOLEAN IoCheck;
  1555. STATIC_BAT_INFO NewInfo;
  1556. ULONG tmp;
  1557. BattPrint(BAT_TRACE, ("SmbBattVerifyStaticInfo: ENTERING\n"));
  1558. IoCheck = FALSE;
  1559. //
  1560. // Loop until state doesn't change
  1561. //
  1562. do {
  1563. //
  1564. // If device name and serial # not known, get them.
  1565. //
  1566. if (!(SmbBatt->Info.Valid & VALID_TAG_DATA)) {
  1567. IoCheck = TRUE;
  1568. SmbBatt->Info.Valid |= VALID_TAG_DATA;
  1569. RtlZeroMemory (&NewInfo, sizeof(NewInfo));
  1570. SmbBattRW(SmbBatt, BAT_SERIAL_NUMBER, &NewInfo.SerialNumber);
  1571. BattPrint(BAT_DATA,
  1572. ("SmbBattVerifyStaticInfo: serial number = %x\n",
  1573. NewInfo.SerialNumber)
  1574. );
  1575. //
  1576. // If SerialNumber was read without a problem, read the rest
  1577. //
  1578. if (SmbBatt->Info.Valid & VALID_TAG_DATA) {
  1579. BattPrint(BAT_IRPS, ("SmbBattVerifyStaticInfo: reading manufacturer name\n"));
  1580. SmbBattRB (
  1581. SmbBatt,
  1582. BAT_MANUFACTURER_NAME,
  1583. NewInfo.ManufacturerName,
  1584. &NewInfo.ManufacturerNameLength
  1585. );
  1586. BattPrint(BAT_IRPS, ("SmbBattVerifyStaticInfo: reading device name\n"));
  1587. SmbBattRB (
  1588. SmbBatt,
  1589. BAT_DEVICE_NAME,
  1590. NewInfo.DeviceName,
  1591. &NewInfo.DeviceNameLength
  1592. );
  1593. //
  1594. // See if battery ID has changed
  1595. //
  1596. if (SmbBatt->Info.SerialNumber != NewInfo.SerialNumber ||
  1597. SmbBatt->Info.ManufacturerNameLength != NewInfo.ManufacturerNameLength ||
  1598. memcmp (SmbBatt->Info.ManufacturerName, NewInfo.ManufacturerName, NewInfo.ManufacturerNameLength) ||
  1599. SmbBatt->Info.DeviceNameLength != NewInfo.DeviceNameLength ||
  1600. memcmp (SmbBatt->Info.DeviceName, NewInfo.DeviceName, NewInfo.DeviceNameLength)) {
  1601. //
  1602. // This is a new battery, reread all information
  1603. //
  1604. SmbBatt->Info.Valid = VALID_TAG_DATA;
  1605. //
  1606. // Pickup ID info
  1607. //
  1608. SmbBatt->Info.SerialNumber = NewInfo.SerialNumber;
  1609. SmbBatt->Info.ManufacturerNameLength = NewInfo.ManufacturerNameLength;
  1610. memcpy (SmbBatt->Info.ManufacturerName, NewInfo.ManufacturerName, NewInfo.ManufacturerNameLength);
  1611. SmbBatt->Info.DeviceNameLength = NewInfo.DeviceNameLength;
  1612. memcpy (SmbBatt->Info.DeviceName, NewInfo.DeviceName, NewInfo.DeviceNameLength);
  1613. }
  1614. } else {
  1615. //
  1616. // No battery, set cached info for no battery
  1617. //
  1618. SmbBatt->Info.Valid = VALID_TAG | VALID_TAG_DATA;
  1619. SmbBatt->Info.Tag = BATTERY_TAG_INVALID;
  1620. }
  1621. }
  1622. //
  1623. // If the battery tag is valid, and it's NO_BATTERY there is no other
  1624. // cached info to read
  1625. //
  1626. if (SmbBatt->Info.Valid & VALID_TAG && SmbBatt->Info.Tag == BATTERY_TAG_INVALID) {
  1627. break;
  1628. }
  1629. //
  1630. // If the mode has not been verified, do it now
  1631. //
  1632. if (!(SmbBatt->Info.Valid & VALID_MODE)) {
  1633. SmbBatt->Info.Valid |= VALID_MODE;
  1634. SmbBattRW(SmbBatt, BAT_BATTERY_MODE, &BatteryMode);
  1635. BattPrint(BAT_DATA, ("SmbBattVerifyStaticInfo:(%01x) Was set to report in %s (BatteryMode = %04x)\n",
  1636. SmbBatt->SelectorBitPosition,
  1637. (BatteryMode & CAPACITY_WATTS_MODE)? "10mWH" : "mAH", BatteryMode));
  1638. if (!(BatteryMode & CAPACITY_WATTS_MODE)) {
  1639. //
  1640. // Battery not in watts mode, clear valid_mode bit and
  1641. // set the battery into watts mode now
  1642. //
  1643. BattPrint(BAT_DATA, ("SmbBattVerifyStaticInfo:(%01x) Setting battery to report in 10mWh\n",
  1644. SmbBatt->SelectorBitPosition));
  1645. SmbBatt->Info.Valid &= ~VALID_MODE;
  1646. BatteryMode |= CAPACITY_WATTS_MODE;
  1647. SmbBattWW(SmbBatt, BAT_BATTERY_MODE, BatteryMode);
  1648. continue; // re-read mode
  1649. }
  1650. }
  1651. //
  1652. // If other static manufacturer info not known, get it
  1653. //
  1654. if (!(SmbBatt->Info.Valid & VALID_OTHER)) {
  1655. IoCheck = TRUE;
  1656. SmbBatt->Info.Valid |= VALID_OTHER;
  1657. SmbBatt->Info.Info.Capabilities = (BATTERY_SYSTEM_BATTERY |
  1658. BATTERY_SET_CHARGE_SUPPORTED |
  1659. BATTERY_SET_DISCHARGE_SUPPORTED);
  1660. SmbBatt->Info.Info.Technology = 1; // secondary cell type
  1661. // Read chemistry
  1662. SmbBattRB (SmbBatt, BAT_CHEMISTRY, Buffer, &BufferLength);
  1663. if (BufferLength > MAX_CHEMISTRY_LENGTH) {
  1664. ASSERT (BufferLength > MAX_CHEMISTRY_LENGTH);
  1665. BufferLength = MAX_CHEMISTRY_LENGTH;
  1666. }
  1667. RtlZeroMemory (SmbBatt->Info.Info.Chemistry, MAX_CHEMISTRY_LENGTH);
  1668. memcpy (SmbBatt->Info.Info.Chemistry, Buffer, BufferLength);
  1669. //
  1670. // Voltage and Current scaling information
  1671. //
  1672. SmbBattRW (SmbBatt, BAT_SPECITICATION_INFO, &tmp);
  1673. BattPrint(BAT_DATA, ("SmbBattVerifyStaticInfo: (%04x) specification info = %x\n",
  1674. SmbBatt->SelectorBitPosition, tmp));
  1675. switch ((tmp & BATTERY_VSCALE_MASK) >> BATTERY_VSCALE_SHIFT) {
  1676. case 1:
  1677. SmbBatt->Info.VoltageScale = BSCALE_FACTOR_1;
  1678. break;
  1679. case 2:
  1680. SmbBatt->Info.VoltageScale = BSCALE_FACTOR_2;
  1681. break;
  1682. case 3:
  1683. SmbBatt->Info.VoltageScale = BSCALE_FACTOR_3;
  1684. break;
  1685. case 0:
  1686. default:
  1687. SmbBatt->Info.VoltageScale = BSCALE_FACTOR_0;
  1688. break;
  1689. }
  1690. switch ((tmp & BATTERY_IPSCALE_MASK) >> BATTERY_IPSCALE_SHIFT) {
  1691. case 1:
  1692. SmbBatt->Info.CurrentScale = BSCALE_FACTOR_1;
  1693. break;
  1694. case 2:
  1695. SmbBatt->Info.CurrentScale = BSCALE_FACTOR_2;
  1696. break;
  1697. case 3:
  1698. SmbBatt->Info.CurrentScale = BSCALE_FACTOR_3;
  1699. break;
  1700. case 0:
  1701. default:
  1702. SmbBatt->Info.CurrentScale = BSCALE_FACTOR_0;
  1703. break;
  1704. }
  1705. SmbBatt->Info.PowerScale = SmbBatt->Info.CurrentScale * SmbBatt->Info.VoltageScale * 10;
  1706. //
  1707. // Read DesignCapacity & FullChargeCapacity and multiply them by the
  1708. // scaling factor
  1709. //
  1710. SmbBattRW(SmbBatt, BAT_DESIGN_CAPACITY, &SmbBatt->Info.Info.DesignedCapacity);
  1711. BattPrint(BAT_DATA, ("SmbBattVerifyStaticInfo: (%01x) DesignCapacity = %04x ... PowerScale = %08x\n",
  1712. SmbBatt->SelectorBitPosition, SmbBatt->Info.Info.DesignedCapacity, SmbBatt->Info.PowerScale));
  1713. SmbBatt->Info.Info.DesignedCapacity *= SmbBatt->Info.PowerScale;
  1714. SmbBattRW(SmbBatt, BAT_FULL_CHARGE_CAPACITY, &SmbBatt->Info.Info.FullChargedCapacity);
  1715. BattPrint(BAT_DATA, ("SmbBattVerifyStaticInfo: (%01x) FullChargedCapacity = %04x ... PowerScale = %08x\n",
  1716. SmbBatt->SelectorBitPosition, SmbBatt->Info.Info.FullChargedCapacity, SmbBatt->Info.PowerScale));
  1717. SmbBatt->Info.Info.FullChargedCapacity *= SmbBatt->Info.PowerScale;
  1718. //
  1719. // Smart batteries have no Use the RemainingCapacityAlarm from the smart battery for the alert values
  1720. //
  1721. SmbBatt->Info.Info.DefaultAlert1 = 0;
  1722. SmbBatt->Info.Info.DefaultAlert2 = 0;
  1723. // Critical bias is 0 for smart batteries.
  1724. SmbBatt->Info.Info.CriticalBias = 0;
  1725. // Manufacturer date
  1726. SmbBattRW (SmbBatt, BAT_MANUFACTURER_DATE, &ManufacturerDate);
  1727. SmbBatt->Info.ManufacturerDate.Day = (UCHAR) ManufacturerDate & 0x1f; // day
  1728. SmbBatt->Info.ManufacturerDate.Month = (UCHAR) (ManufacturerDate >> 5) & 0xf; // month
  1729. SmbBatt->Info.ManufacturerDate.Year = (USHORT) (ManufacturerDate >> 9) + 1980;
  1730. }
  1731. //
  1732. // If cycle count is not known, read it
  1733. //
  1734. if (!(SmbBatt->Info.Valid & VALID_CYCLE_COUNT)) {
  1735. IoCheck = TRUE;
  1736. SmbBatt->Info.Valid |= VALID_CYCLE_COUNT;
  1737. SmbBattRW(SmbBatt, BAT_CYCLE_COUNT, &SmbBatt->Info.Info.CycleCount);
  1738. }
  1739. //
  1740. // If redundant serial # read hasn't been done, do it now
  1741. //
  1742. if (!(SmbBatt->Info.Valid & VALID_SANITY_CHECK)) {
  1743. SmbBatt->Info.Valid |= VALID_SANITY_CHECK;
  1744. SmbBattRW(SmbBatt, BAT_SERIAL_NUMBER, &NewInfo.SerialNumber);
  1745. if (SmbBatt->Info.SerialNumber != NewInfo.SerialNumber) {
  1746. SmbBatt->Info.Valid &= ~VALID_TAG_DATA;
  1747. }
  1748. }
  1749. //
  1750. // If cached info isn't complete, loop
  1751. //
  1752. } while ((SmbBatt->Info.Valid & VALID_ALL) != VALID_ALL) ;
  1753. //
  1754. // If the tag isn't assigned, assign it
  1755. //
  1756. if (!(SmbBatt->Info.Valid & VALID_TAG)) {
  1757. SmbBatt->TagCount += 1;
  1758. SmbBatt->Info.Tag = SmbBatt->TagCount;
  1759. SmbBatt->Info.Valid |= VALID_TAG;
  1760. SmbBatt->AlarmLow.Setting = 0; // assume not set
  1761. SmbBatt->AlarmLow.Skip = 0;
  1762. SmbBatt->AlarmLow.Delta = 0;
  1763. SmbBatt->AlarmLow.AllowedFudge = 0;
  1764. }
  1765. //
  1766. // If callers BatteryTag does not match current tag, let caller know
  1767. //
  1768. if (SmbBatt->Info.Tag != BatteryTag) {
  1769. IoCheck = TRUE;
  1770. }
  1771. //
  1772. // Let caller know if there's been an IoCheck
  1773. //
  1774. BattPrint(BAT_TRACE, ("SmbBattVerifyStaticInfo: EXITING\n"));
  1775. return IoCheck;
  1776. }
  1777. VOID
  1778. SmbBattInvalidateTag (
  1779. PSMB_BATT_SUBSYSTEM SubsystemExt,
  1780. ULONG BatteryIndex,
  1781. BOOLEAN NotifyClient
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. This routine processes battery insertion/removal by invalidating the
  1786. tag information and then notifies the client of the change.
  1787. Arguments:
  1788. SubsystemExt - Device extension for the smart battery subsystem
  1789. BatteryIndex - Index of Battery to Process Changes for
  1790. - Power and Charge
  1791. NotifyClient - Whether or not to Notify Client
  1792. Return Value:
  1793. None
  1794. --*/
  1795. {
  1796. PDEVICE_OBJECT batteryPdo;
  1797. PSMB_BATT_PDO batteryPdoExt;
  1798. PDEVICE_OBJECT batteryFdo;
  1799. PSMB_NP_BATT smbNpBatt;
  1800. PSMB_BATT smbBatt;
  1801. BattPrint(BAT_TRACE, ("SmbBattInvalidateTag: ENTERING for battery %x\n", BatteryIndex));
  1802. batteryPdo = SubsystemExt->BatteryPdoList[BatteryIndex];
  1803. if (batteryPdo) {
  1804. batteryPdoExt = (PSMB_BATT_PDO) batteryPdo->DeviceExtension;
  1805. batteryFdo = batteryPdoExt->Fdo;
  1806. if (batteryFdo) {
  1807. //
  1808. // Invalidate this battery's tag data
  1809. //
  1810. BattPrint (
  1811. BAT_ALARM,
  1812. ("SmbBattInvalidateTag: Battery present status change, invalidating battery %x\n",
  1813. BatteryIndex)
  1814. );
  1815. smbNpBatt = (PSMB_NP_BATT) batteryFdo->DeviceExtension;
  1816. smbBatt = smbNpBatt->Batt;
  1817. SmbBattLockDevice (smbBatt);
  1818. smbBatt->Info.Valid = 0;
  1819. smbBatt->Info.Tag = BATTERY_TAG_INVALID;
  1820. SmbBattUnlockDevice (smbBatt);
  1821. //
  1822. // Notify the class driver
  1823. //
  1824. if (NotifyClient) {
  1825. BattPrint(BAT_ALARM, ("SmbBattInvalidateTag: Status Change notification for battery %x\n", BatteryIndex));
  1826. SmbBattNotifyClassDriver (SubsystemExt, BatteryIndex);
  1827. }
  1828. }
  1829. }
  1830. BattPrint(BAT_TRACE, ("SmbBattInvalidateTag: EXITING\n"));
  1831. }
  1832. VOID
  1833. SmbBattAlarm (
  1834. IN PVOID Context,
  1835. IN UCHAR Address,
  1836. IN USHORT Data
  1837. )
  1838. {
  1839. PSMB_ALARM_ENTRY newAlarmEntry;
  1840. ULONG compState;
  1841. PSMB_BATT_SUBSYSTEM subsystemExt = (PSMB_BATT_SUBSYSTEM) Context;
  1842. BattPrint(BAT_TRACE, ("SmbBattAlarm: ENTERING\n"));
  1843. BattPrint(BAT_DATA, ("SmbBattAlarm: Alarm - Address %x, Data %x\n", Address, Data));
  1844. // If we have a selector and the message is from the address that
  1845. // implements the selector, then handle it. If there is no selector
  1846. // and the message is from the charger, then process it. Or, if the
  1847. // message is from the battery, then process it. Or, in other words,
  1848. // if the message is from the charger and we have a stand-alone selector,
  1849. // then ignore the message.
  1850. if (Address != SMB_BATTERY_ADDRESS) {
  1851. if ((subsystemExt->SelectorPresent) && (subsystemExt->Selector)) {
  1852. // If a Selector is implemented and the Alarm Message came from
  1853. // something besides the Selector or a Battery, then ignore it.
  1854. if (Address != subsystemExt->Selector->SelectorAddress) {
  1855. return;
  1856. }
  1857. }
  1858. }
  1859. //
  1860. // Allocate a new alarm list structure. This has to be from non-paged pool
  1861. // because we are being called at Dispatch level.
  1862. //
  1863. newAlarmEntry = ExAllocatePoolWithTag (NonPagedPool, sizeof (SMB_ALARM_ENTRY), 'StaB');
  1864. if (!newAlarmEntry) {
  1865. BattPrint (BAT_ERROR, ("SmbBattAlarm: couldn't allocate alarm structure\n"));
  1866. return;
  1867. }
  1868. newAlarmEntry->Data = Data;
  1869. newAlarmEntry->Address = Address;
  1870. //
  1871. // Add this alarm to the alarm queue
  1872. //
  1873. ExInterlockedInsertTailList(
  1874. &subsystemExt->AlarmList,
  1875. &newAlarmEntry->Alarms,
  1876. &subsystemExt->AlarmListLock
  1877. );
  1878. //
  1879. // Add 1 to the WorkerActive value, if this is the first count
  1880. // queue a worker thread
  1881. //
  1882. if (InterlockedIncrement(&subsystemExt->WorkerActive) == 1) {
  1883. IoQueueWorkItem (subsystemExt->WorkerThread, SmbBattWorkerThread, DelayedWorkQueue, subsystemExt);
  1884. }
  1885. BattPrint(BAT_TRACE, ("SmbBattAlarm: EXITING\n"));
  1886. }
  1887. VOID
  1888. SmbBattWorkerThread (
  1889. IN PDEVICE_OBJECT Fdo,
  1890. IN PVOID Context
  1891. )
  1892. /*++
  1893. Routine Description:
  1894. This routine handles the alarms for the batteries.
  1895. Arguments:
  1896. Context - Non-paged extension for the battery subsystem FDO
  1897. Return Value:
  1898. None
  1899. --*/
  1900. {
  1901. PSMB_ALARM_ENTRY alarmEntry;
  1902. PLIST_ENTRY nextEntry;
  1903. ULONG selectorState;
  1904. ULONG batteryIndex;
  1905. BOOLEAN charging = FALSE;
  1906. BOOLEAN acOn = FALSE;
  1907. PSMB_BATT_SUBSYSTEM subsystemExt = (PSMB_BATT_SUBSYSTEM) Context;
  1908. BattPrint(BAT_TRACE, ("SmbBattWorkerThread: ENTERING\n"));
  1909. do {
  1910. //
  1911. // Check to see if we have more alarms to process. If so retrieve
  1912. // the next one and decrement the worker active count.
  1913. //
  1914. nextEntry = ExInterlockedRemoveHeadList(
  1915. &subsystemExt->AlarmList,
  1916. &subsystemExt->AlarmListLock
  1917. );
  1918. //
  1919. //It should only get here if there is an entry in the list
  1920. //
  1921. ASSERT (nextEntry != NULL);
  1922. alarmEntry = CONTAINING_RECORD (nextEntry, SMB_ALARM_ENTRY, Alarms);
  1923. BattPrint(
  1924. BAT_ALARM,
  1925. ("SmbBattWorkerThread: processing alarm, address = %x, data = %x\n",
  1926. alarmEntry->Address,
  1927. alarmEntry->Data)
  1928. );
  1929. //
  1930. // Get last Selector State Cached Value (update cache with new value)
  1931. //
  1932. if (subsystemExt->SelectorPresent) {
  1933. if (subsystemExt->Selector) {
  1934. selectorState = subsystemExt->Selector->SelectorState;
  1935. } else {
  1936. // We're not initialized enough to handle a message
  1937. break;
  1938. }
  1939. }
  1940. // Determine Source of Alarm Message and then Process it
  1941. switch (alarmEntry->Address) {
  1942. case SMB_CHARGER_ADDRESS:
  1943. //
  1944. // Handle Charger Message - If Charger/Selector Combo, then
  1945. // fall through and handle it as a Selector. If no Selector,
  1946. // then attempt processing as a Charger. Ignore Charger messages
  1947. // if Selector is present.
  1948. //
  1949. if (!subsystemExt->SelectorPresent) {
  1950. SmbBattProcessChargerAlarm (subsystemExt, alarmEntry->Data);
  1951. break;
  1952. } else {
  1953. // If SelectorPresent, but no Selector Structure, Ignore message
  1954. if (!subsystemExt->Selector) {
  1955. break;
  1956. } else {
  1957. if (subsystemExt->Selector->SelectorAddress != SMB_CHARGER_ADDRESS) {
  1958. break;
  1959. }
  1960. }
  1961. }
  1962. //
  1963. // Fall through to Selector Procesing for integrated Charger/Selector
  1964. //
  1965. case SMB_SELECTOR_ADDRESS:
  1966. if (!subsystemExt->SelectorPresent) {
  1967. BattPrint (
  1968. BAT_BIOS_ERROR,
  1969. ("SmbBattProcessSelectorAlarm: Received alarm from selector address, but BIOS reports no selector is present.\n")
  1970. );
  1971. break;
  1972. }
  1973. //
  1974. // This is a selector alarm indicating a change in the selector state.
  1975. // There are four different areas that could change: SMB, POWER_BY,
  1976. // CHARGE, PRESENT. First try to determine which ones changed.
  1977. //
  1978. SmbBattLockSelector (subsystemExt->Selector);
  1979. BattPrint (
  1980. BAT_DATA,
  1981. ("SmbBattProcessSelectorAlarm: New SelectorState being written as - %x\n",
  1982. alarmEntry->Data)
  1983. );
  1984. subsystemExt->Selector->SelectorState = alarmEntry->Data;
  1985. SmbBattUnlockSelector (subsystemExt->Selector);
  1986. SmbBattProcessSelectorAlarm (subsystemExt, selectorState, alarmEntry->Data);
  1987. break;
  1988. case SMB_BATTERY_ADDRESS:
  1989. //
  1990. // Send notifications to all batteries.
  1991. // It seems we get notifications even for batteries not currently selected.
  1992. //
  1993. for (batteryIndex = 0; batteryIndex < subsystemExt->NumberOfBatteries; batteryIndex++) {
  1994. BattPrint(BAT_ALARM, ("SmbBattWorkerThread: Notification to battery %x\n", batteryIndex));
  1995. SmbBattNotifyClassDriver (subsystemExt, batteryIndex);
  1996. }
  1997. break;
  1998. } // switch (alarmEntry->Address)
  1999. //
  2000. // Free the alarm structure
  2001. //
  2002. ExFreePool (alarmEntry);
  2003. } while (InterlockedDecrement (&subsystemExt->WorkerActive) != 0);
  2004. BattPrint(BAT_TRACE, ("SmbBattWorkerThread: EXITING\n"));
  2005. }
  2006. VOID
  2007. SmbBattProcessSelectorAlarm (
  2008. IN PSMB_BATT_SUBSYSTEM SubsystemExt,
  2009. IN ULONG OldSelectorState,
  2010. IN ULONG NewSelectorState
  2011. )
  2012. /*++
  2013. Routine Description:
  2014. This routine process alarms generated by the selector. We will only get
  2015. here is there is a change in the SelectorState for one or more of the
  2016. following state changes:
  2017. - PowerBy nibble change caused by the power source changing to a different
  2018. battery or to AC adapter.
  2019. - PowerBy nbble change caused by optional Charge Indicator state change
  2020. when the charger starts or stops charging a battery.
  2021. - ChargeWhich nibble change caused by a change in the current battery
  2022. connected to the Charger.
  2023. - ChargeWhich nibble change caused by AC adapter insertion/removal.
  2024. - BatteryPresent nibble change caused by insertion/removal of 1 or more batteries.
  2025. Arguments:
  2026. SubsystemExt - Device extension for the smart battery subsystem
  2027. NewSelectorState - Data value sent by the selector alarm, which is
  2028. New SelectorState.
  2029. Return Value:
  2030. None
  2031. --*/
  2032. {
  2033. ULONG tmp;
  2034. ULONG BatteryMask;
  2035. ULONG NotifyMask;
  2036. ULONG ChangeSelector;
  2037. ULONG index;
  2038. BattPrint(BAT_TRACE, ("SmbBattProcessSelectorAlarm: ENTERING\n"));
  2039. //
  2040. // Determine SelectorState changes and combine them together
  2041. //
  2042. ChangeSelector = NewSelectorState ^ OldSelectorState;
  2043. if (!(ChangeSelector & ~SELECTOR_STATE_SMB_MASK)) {
  2044. //
  2045. // If the only change is in SMB nibble, no nothing.
  2046. //
  2047. return;
  2048. }
  2049. //
  2050. // Check for change to Batteries Present nibble. Invalidate and Notify
  2051. // each battery that changes state.
  2052. //
  2053. BatteryMask = ChangeSelector & SELECTOR_STATE_PRESENT_MASK;
  2054. NotifyMask = BatteryMask;
  2055. //
  2056. // Check for change to Charge Which nibble. If all bits set, then the nibble
  2057. // just inverted state indicating an AC adapter Insertion/Removal. Notify
  2058. // all batteries of change. If only one or two bits changed, notify just
  2059. // the batteries that changed status.
  2060. //
  2061. tmp = (ChangeSelector >> SELECTOR_SHIFT_CHARGE) & SELECTOR_STATE_PRESENT_MASK;
  2062. if (tmp) {
  2063. // If nibble inverted state, then the AC Adapter changed state
  2064. if (tmp == SELECTOR_STATE_PRESENT_MASK) {
  2065. BattPrint(BAT_DATA, ("SmbBattProcessSelectorAlarm: AC Adapter was inserted/removed\n"));
  2066. NotifyMask |= tmp;
  2067. // Battery Charge Which changed
  2068. } else {
  2069. //if (SmbBattReverseLogic(SubsystemExt->Selector, tmp)) {
  2070. // tmp ^= SELECTOR_STATE_PRESENT_MASK;
  2071. //}
  2072. // Let's just notify all batteries to be safe
  2073. tmp = SELECTOR_STATE_PRESENT_MASK;
  2074. BattPrint(BAT_DATA, ("SmbBattProcessSelectorAlarm: Charger Nibble changed status\n"));
  2075. NotifyMask |= tmp;
  2076. }
  2077. }
  2078. //
  2079. // Check for change in Power By nibble. Notify all batteries of any change.
  2080. //
  2081. tmp = (ChangeSelector >> SELECTOR_SHIFT_POWER) & SELECTOR_STATE_PRESENT_MASK;
  2082. if (tmp) {
  2083. // If nibble inverted state, then the check for Charge Indicator change
  2084. // and notify the battery that started/stopped charging
  2085. if (tmp == SELECTOR_STATE_PRESENT_MASK) {
  2086. if (SubsystemExt->Selector->SelectorInfo & SELECTOR_INFO_CHARGING_INDICATOR_BIT) {
  2087. tmp = (NewSelectorState >> SELECTOR_SHIFT_CHARGE) & SELECTOR_STATE_PRESENT_MASK;
  2088. if (SmbBattReverseLogic(SubsystemExt->Selector, tmp)) {
  2089. tmp ^= SELECTOR_STATE_PRESENT_MASK;
  2090. }
  2091. BattPrint(BAT_DATA, ("SmbBattProcessSelectorAlarm: Charging Indicator changed status\n"));
  2092. NotifyMask |= tmp;
  2093. } else {
  2094. // If not Charging Indicator, then all battery power by nibbles inverted
  2095. BattPrint(BAT_DATA, ("SmbBattProcessSelectorAlarm: Power By inverted state, without supporting Charge Indication\n"));
  2096. NotifyMask |= SELECTOR_STATE_PRESENT_MASK;
  2097. }
  2098. } else {
  2099. // Let's notify all batteries if the Power By nibble changes
  2100. BattPrint(BAT_DATA, ("SmbBattProcessSelectorAlarm: Power By Nibble changed status\n"));
  2101. NotifyMask |= SELECTOR_STATE_PRESENT_MASK;
  2102. }
  2103. }
  2104. //
  2105. // Notify all batteries of change in Present Status
  2106. //
  2107. tmp = BATTERY_A_PRESENT;
  2108. for (index = 0; index < SubsystemExt->NumberOfBatteries; index++) {
  2109. if (BatteryMask & tmp) {
  2110. if (!(NewSelectorState & tmp)) {
  2111. BattPrint(BAT_DATA, ("SmbBattProcessSelectorAlarm: Invalidating battery %x\n", index));
  2112. SmbBattInvalidateTag (SubsystemExt, index, FALSE);
  2113. }
  2114. }
  2115. tmp <<= 1;
  2116. }
  2117. // Don't notify batteries already notified
  2118. //NotifyMask &= ~BatteryMask;
  2119. //
  2120. // Process Notifications Now for changes to SelectorState for Power, Charge, etc.
  2121. //
  2122. tmp = BATTERY_A_PRESENT;
  2123. for (index = 0; index < SubsystemExt->NumberOfBatteries; index++) {
  2124. if (NotifyMask & tmp) {
  2125. BattPrint(BAT_DATA, ("SmbBattProcessSelectorAlarm: Status Change notification for battery %x\n", index));
  2126. SmbBattNotifyClassDriver (SubsystemExt, index);
  2127. }
  2128. tmp <<= 1;
  2129. }
  2130. BattPrint(BAT_TRACE, ("SmbBattProcessSelectorAlarm: EXITING\n"));
  2131. }
  2132. VOID
  2133. SmbBattProcessChargerAlarm (
  2134. IN PSMB_BATT_SUBSYSTEM SubsystemExt,
  2135. IN ULONG ChargerStatus
  2136. )
  2137. /*++
  2138. Routine Description:
  2139. This routine process alarms generated by the charger. We will only get
  2140. here is there is no selector in the system and the alarm is the one to
  2141. tell us when AC and batteries come and go.
  2142. Arguments:
  2143. SubsystemExt - Device extension for the smart battery subsystem
  2144. ChargerStatus - Data value sent by the charger alarm, which is
  2145. charger status register
  2146. Return Value:
  2147. None
  2148. --*/
  2149. {
  2150. BattPrint(BAT_TRACE, ("SmbBattProcessChargeAlarm: ENTERING\n"));
  2151. //
  2152. // There should only be two reasons we get called: a change in AC, or
  2153. // a change in the battery present. We are really only interested in
  2154. // whether or not there is a battery in the system. If there isn't, we
  2155. // will invalidate battery 0. If it was already gone this re-invalidation
  2156. // won't matter.
  2157. //
  2158. if (!(ChargerStatus & CHARGER_STATUS_BATTERY_PRESENT_BIT)) {
  2159. SmbBattInvalidateTag (SubsystemExt, BATTERY_A, TRUE);
  2160. }
  2161. // Notify Change
  2162. SmbBattNotifyClassDriver (SubsystemExt, 0);
  2163. BattPrint(BAT_TRACE, ("SmbBattProcessChargerAlarm: EXITING\n"));
  2164. }
  2165. VOID
  2166. SmbBattNotifyClassDriver (
  2167. IN PSMB_BATT_SUBSYSTEM SubsystemExt,
  2168. IN ULONG BatteryIndex
  2169. )
  2170. /*++
  2171. Routine Description:
  2172. This routine gets the FDO for the battery indicated by index from the
  2173. smart battery subsystem and notifies the class driver there has been
  2174. a status change.
  2175. Arguments:
  2176. SubsystemExt - Device extension for the smart battery subsystem
  2177. BatteryIndex - Index for the battery in the subsystem battery
  2178. list
  2179. Return Value:
  2180. None
  2181. --*/
  2182. {
  2183. PDEVICE_OBJECT batteryPdo;
  2184. PSMB_BATT_PDO batteryPdoExt;
  2185. PDEVICE_OBJECT batteryFdo;
  2186. PSMB_NP_BATT smbNpBatt;
  2187. BattPrint(BAT_TRACE, ("SmbBattNotifyClassDriver: ENTERING\n"));
  2188. batteryPdo = SubsystemExt->BatteryPdoList[BatteryIndex];
  2189. if (batteryPdo) {
  2190. batteryPdoExt = (PSMB_BATT_PDO) batteryPdo->DeviceExtension;
  2191. batteryFdo = batteryPdoExt->Fdo;
  2192. if (batteryFdo) {
  2193. BattPrint (
  2194. BAT_IRPS,
  2195. ("SmbBattNotifyClassDriver: Calling BatteryClassNotify for battery - %x\n",
  2196. batteryFdo)
  2197. );
  2198. smbNpBatt = (PSMB_NP_BATT) batteryFdo->DeviceExtension;
  2199. BatteryClassStatusNotify (smbNpBatt->Class);
  2200. }
  2201. } else {
  2202. BattPrint (
  2203. BAT_ERROR,
  2204. ("SmbBattNotifyClassDriver: No PDO for device.\n")
  2205. );
  2206. }
  2207. BattPrint(BAT_TRACE, ("SmbBattNotifyClassDriver: EXITING\n"));
  2208. }