Leaked source code of windows server 2003
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.

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