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.

1835 lines
52 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pnppower.c
  5. Abstract:
  6. SMBus Smart Battery Subsystem Miniport Driver
  7. (Selector, Battery, Charger) Plug and Play and
  8. Power Management IRP dispatch routines.
  9. Author:
  10. Scott Brenden
  11. Environment:
  12. Notes:
  13. Revision History:
  14. Chris Windle 1/27/98 Bug Fixes
  15. --*/
  16. #include "smbbattp.h"
  17. #include <devioctl.h>
  18. #include <acpiioct.h>
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text(PAGE,SmbBattPnpDispatch)
  21. #pragma alloc_text(PAGE,SmbBattPowerDispatch)
  22. #pragma alloc_text(PAGE,SmbBattRegisterForAlarm)
  23. #pragma alloc_text(PAGE,SmbBattUnregisterForAlarm)
  24. #pragma alloc_text(PAGE,SmbGetSBS)
  25. #pragma alloc_text(PAGE,SmbGetGLK)
  26. #pragma alloc_text(PAGE,SmbBattCreatePdos)
  27. #pragma alloc_text(PAGE,SmbBattBuildDeviceRelations)
  28. #pragma alloc_text(PAGE,SmbBattQueryDeviceRelations)
  29. #pragma alloc_text(PAGE,SmbBattRemoveDevice)
  30. #pragma alloc_text(PAGE,SmbBattQueryId)
  31. #pragma alloc_text(PAGE,SmbBattQueryCapabilities)
  32. #pragma alloc_text(PAGE,SmbBattBuildSelectorStruct)
  33. #endif
  34. NTSTATUS
  35. SmbBattPnpDispatch(
  36. IN PDEVICE_OBJECT DeviceObject,
  37. IN PIRP Irp
  38. )
  39. /*++
  40. Routine Description:
  41. This is a dispatch routine for the IRPs that come to the driver with the
  42. IRP_MJ_PNP major code (plug-and-play IRPs).
  43. Arguments:
  44. DeviceObject - Pointer to the device object for this device
  45. Irp - Pointer to the IRP for the current request
  46. Return Value:
  47. The function value is the final status of the call
  48. --*/
  49. {
  50. PSMB_BATT smbBatt;
  51. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  52. NTSTATUS status;
  53. BOOLEAN complete = TRUE;
  54. KEVENT syncEvent;
  55. //
  56. // This routine handles PnP IRPs for three different types of device objects:
  57. // the battery subsystem FDO, each battery PDO and each battery PDO. The
  58. // subsystem PDO creates children since each battery in the system must have
  59. // it's own device object, so this driver is essential two device drivers in
  60. // one: the smart battery selector bus driver (It is actually it's own bus
  61. // because the selector arbitrates between the two batteries.) and the
  62. // battery function driver. The two drivers are integrated because it would
  63. // not make sense to replace one and not the other, and having separate
  64. // drivers would require additional defined interfaces between them.
  65. //
  66. // The device extensions for the three device types are different structures.
  67. //
  68. PSMB_BATT_SUBSYSTEM subsystemExt =
  69. (PSMB_BATT_SUBSYSTEM) DeviceObject->DeviceExtension;
  70. PSMB_NP_BATT batteryExt =
  71. (PSMB_NP_BATT) DeviceObject->DeviceExtension;
  72. PDEVICE_OBJECT lowerDevice = NULL;
  73. PAGED_CODE();
  74. status = IoAcquireRemoveLock (&batteryExt->RemoveLock, Irp);
  75. if (NT_SUCCESS(status)) {
  76. status = STATUS_NOT_SUPPORTED;
  77. if (batteryExt->SmbBattFdoType == SmbTypeSubsystem) {
  78. lowerDevice = subsystemExt->LowerDevice;
  79. } else if (batteryExt->SmbBattFdoType == SmbTypeBattery) {
  80. lowerDevice = batteryExt->LowerDevice;
  81. } else {
  82. // Assuming (batteryExt->SmbBattFdoType == SmbTypePdo)
  83. ASSERT (batteryExt->SmbBattFdoType == SmbTypePdo);
  84. lowerDevice = NULL;
  85. }
  86. switch (irpStack->MinorFunction) {
  87. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  88. BattPrint(
  89. BAT_IRPS,
  90. ("SmbBattPnpDispatch: got IRP_MN_QUERY_DEVICE_RELATIONS, "
  91. "type = %x\n",
  92. irpStack->Parameters.QueryDeviceRelations.Type)
  93. );
  94. status = SmbBattQueryDeviceRelations (DeviceObject, Irp);
  95. break;
  96. }
  97. case IRP_MN_QUERY_CAPABILITIES: {
  98. BattPrint(
  99. BAT_IRPS,
  100. ("SmbBattPnpDispatch: got IRP_MN_QUERY_CAPABILITIES for device %x\n",
  101. DeviceObject)
  102. );
  103. status = SmbBattQueryCapabilities (DeviceObject, Irp);
  104. break;
  105. }
  106. case IRP_MN_START_DEVICE: {
  107. BattPrint(
  108. BAT_IRPS,
  109. ("SmbBattPnpDispatch: got IRP_MN_START_DEVICE for %x\n",
  110. DeviceObject)
  111. );
  112. if (subsystemExt->SmbBattFdoType == SmbTypeSubsystem) {
  113. //
  114. // Get the SMB host controller FDO
  115. //
  116. subsystemExt->SmbHcFdo = subsystemExt->LowerDevice;
  117. status = STATUS_SUCCESS;
  118. } else if (subsystemExt->SmbBattFdoType == SmbTypeBattery) {
  119. //
  120. // This is a battery. Just get the SMB host controller FDO.
  121. //
  122. smbBatt = batteryExt->Batt;
  123. smbBatt->SmbHcFdo =
  124. ((PSMB_BATT_SUBSYSTEM)(((PSMB_BATT_PDO)
  125. (smbBatt->PDO->DeviceExtension))->
  126. SubsystemFdo->DeviceExtension))->
  127. LowerDevice;
  128. status = STATUS_SUCCESS;
  129. } else if (subsystemExt->SmbBattFdoType == SmbTypePdo) {
  130. status = STATUS_SUCCESS;
  131. }
  132. break;
  133. }
  134. case IRP_MN_STOP_DEVICE: {
  135. status = STATUS_SUCCESS;
  136. BattPrint(BAT_IRPS, ("SmbBattPnpDispatch: got IRP_MN_STOP_DEVICE\n"));
  137. break;
  138. }
  139. case IRP_MN_QUERY_REMOVE_DEVICE: {
  140. status = STATUS_SUCCESS;
  141. BattPrint(BAT_IRPS, ("SmbBattPnpDispatch: got IRP_MN_QUERY_REMOVE_DEVICE\n"));
  142. break;
  143. }
  144. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  145. status = STATUS_SUCCESS;
  146. BattPrint(BAT_IRPS, ("SmbBattPnpDispatch: got IRP_MN_CANCEL_REMOVE_DEVICE\n"));
  147. break;
  148. }
  149. case IRP_MN_SURPRISE_REMOVAL: {
  150. status = STATUS_SUCCESS;
  151. BattPrint(BAT_IRPS, ("SmbBattPnpDispatch: got IRP_MN_SURPRISE_REMOVAL\n"));
  152. break;
  153. }
  154. case IRP_MN_REMOVE_DEVICE: {
  155. BattPrint(BAT_IRPS, ("SmbBattPnpDispatch: got IRP_MN_REMOVE_DEVICE\n"));
  156. status = SmbBattRemoveDevice (DeviceObject, Irp);
  157. return status;
  158. break;
  159. }
  160. case IRP_MN_QUERY_ID: {
  161. BattPrint(
  162. BAT_IRPS,
  163. ("SmbBattPnpDispatch: got IRP_MN_QUERY_ID for %x, query type is - %x\n",
  164. DeviceObject,
  165. irpStack->Parameters.QueryId.IdType)
  166. );
  167. if (batteryExt->SmbBattFdoType == SmbTypePdo) {
  168. status = SmbBattQueryId (DeviceObject, Irp);
  169. }
  170. break;
  171. }
  172. case IRP_MN_QUERY_PNP_DEVICE_STATE: {
  173. BattPrint(BAT_IRPS, ("SmbBattPnpDispatch: got IRP_MN_PNP_DEVICE_STATE\n"));
  174. if (subsystemExt->SmbBattFdoType == SmbTypeSubsystem) {
  175. IoCopyCurrentIrpStackLocationToNext (Irp);
  176. KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
  177. IoSetCompletionRoutine(Irp, SmbBattSynchronousRequest, &syncEvent, TRUE, TRUE, TRUE);
  178. status = IoCallDriver(lowerDevice, Irp);
  179. if (status == STATUS_PENDING) {
  180. KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
  181. status = Irp->IoStatus.Status;
  182. }
  183. Irp->IoStatus.Information &= ~PNP_DEVICE_NOT_DISABLEABLE;
  184. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  185. IoReleaseRemoveLock (&batteryExt->RemoveLock, Irp);
  186. return status;
  187. }
  188. break;
  189. }
  190. } // switch (irpStack->MinorFunction)
  191. IoReleaseRemoveLock (&batteryExt->RemoveLock, Irp);
  192. }
  193. //
  194. // Only set status if we have something to add
  195. //
  196. if (status != STATUS_NOT_SUPPORTED) {
  197. Irp->IoStatus.Status = status ;
  198. }
  199. //
  200. // Do we need to send it down?
  201. //
  202. if ((NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) && (lowerDevice != NULL)) {
  203. //
  204. // Forward request
  205. //
  206. IoSkipCurrentIrpStackLocation(Irp);
  207. status = IoCallDriver(lowerDevice,Irp);
  208. } else {
  209. //
  210. // Complete the request with the current status
  211. //
  212. status = Irp->IoStatus.Status;
  213. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  214. }
  215. return status;
  216. }
  217. NTSTATUS
  218. SmbBattPowerDispatch(
  219. IN PDEVICE_OBJECT Fdo,
  220. IN PIRP Irp
  221. )
  222. /*++
  223. Routine Description:
  224. This is a dispatch routine for the IRPs that come to the driver with the
  225. IRP_MJ_POWER major code (power IRPs).
  226. Arguments:
  227. DeviceObject - Pointer to the device object for this device
  228. Irp - Pointer to the IRP for the current request
  229. Return Value:
  230. The function value is the final status of the call
  231. --*/
  232. {
  233. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  234. NTSTATUS status = STATUS_NOT_SUPPORTED;
  235. PSMB_NP_BATT batteryExt = (PSMB_NP_BATT) Fdo->DeviceExtension;
  236. PSMB_BATT_SUBSYSTEM subsystemExt = (PSMB_BATT_SUBSYSTEM) Fdo->DeviceExtension;
  237. PDEVICE_OBJECT lowerDevice;
  238. PAGED_CODE();
  239. //
  240. // Not using Remove lock in this function because this function doesn't use
  241. // any resoureces that the remove lock protects.
  242. //
  243. if (batteryExt->SmbBattFdoType == SmbTypeSubsystem) {
  244. lowerDevice = subsystemExt->LowerDevice;
  245. } else if (batteryExt->SmbBattFdoType == SmbTypeBattery) {
  246. lowerDevice = batteryExt->LowerDevice;
  247. } else {
  248. // Assuming (batteryExt->SmbBattFdoType == SmbTypePdo)
  249. ASSERT (batteryExt->SmbBattFdoType == SmbTypePdo);
  250. lowerDevice = NULL;
  251. status = STATUS_SUCCESS;
  252. }
  253. switch (irpStack->MinorFunction) {
  254. case IRP_MN_WAIT_WAKE: {
  255. BattPrint(BAT_IRPS, ("SmbBattPowerDispatch: got IRP_MN_WAIT_WAKE\n"));
  256. //
  257. // Smart batteries can't wake the system.
  258. //
  259. status = STATUS_NOT_SUPPORTED;
  260. break;
  261. }
  262. case IRP_MN_POWER_SEQUENCE: {
  263. BattPrint(BAT_IRPS, ("SmbBattPowerDispatch: got IRP_MN_POWER_SEQUENCE\n"));
  264. break;
  265. }
  266. case IRP_MN_SET_POWER: {
  267. BattPrint(BAT_IRPS, ("SmbBattPowerDispatch: got IRP_MN_SET_POWER\n"));
  268. break;
  269. }
  270. case IRP_MN_QUERY_POWER: {
  271. BattPrint(BAT_IRPS, ("SmbBattPowerDispatch: got IRP_MN_QUERY_POWER\n"));
  272. break;
  273. }
  274. default: {
  275. status = STATUS_NOT_SUPPORTED;
  276. }
  277. } // switch (irpStack->MinorFunction)
  278. if (status != STATUS_NOT_SUPPORTED) {
  279. Irp->IoStatus.Status = status;
  280. }
  281. PoStartNextPowerIrp( Irp );
  282. if ((NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) && (lowerDevice != NULL)) {
  283. //
  284. // Forward the request along
  285. //
  286. IoSkipCurrentIrpStackLocation( Irp );
  287. status = PoCallDriver( lowerDevice, Irp );
  288. } else {
  289. //
  290. // Complete the request with the current status
  291. //
  292. status = Irp->IoStatus.Status;
  293. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  294. }
  295. return status;
  296. }
  297. NTSTATUS
  298. SmbBattRegisterForAlarm(
  299. IN PDEVICE_OBJECT Fdo
  300. )
  301. /*++
  302. Routine Description:
  303. This routine register with the SmbHc for alarm notifications. This
  304. is only done when smart battery subsystem FDO is started.
  305. Arguments:
  306. Fdo - Pointer to the Fdo for this device
  307. Irp - Pointer to the IRP for the current request
  308. Return Value:
  309. The function value is the final status of the call
  310. --*/
  311. {
  312. PIRP irp;
  313. PIO_STACK_LOCATION irpStack;
  314. SMB_REGISTER_ALARM registerAlarm;
  315. KEVENT event;
  316. NTSTATUS status;
  317. PSMB_BATT_SUBSYSTEM subsystemExtension =
  318. (PSMB_BATT_SUBSYSTEM) Fdo->DeviceExtension;
  319. PAGED_CODE();
  320. //
  321. // Register for alarm notifications
  322. //
  323. registerAlarm.MinAddress = SMB_CHARGER_ADDRESS;
  324. registerAlarm.MaxAddress = SMB_BATTERY_ADDRESS;
  325. registerAlarm.NotifyFunction = SmbBattAlarm;
  326. registerAlarm.NotifyContext = subsystemExtension;
  327. KeInitializeEvent (&event, NotificationEvent, FALSE);
  328. irp = IoAllocateIrp (subsystemExtension->SmbHcFdo->StackSize, FALSE);
  329. if (!irp) {
  330. BattPrint(BAT_ERROR, ("SmbBattRegisterForAlarm: couldn't allocate irp\n"));
  331. return STATUS_INSUFFICIENT_RESOURCES;
  332. }
  333. irpStack = IoGetNextIrpStackLocation(irp);
  334. irp->UserBuffer = &subsystemExtension->SmbAlarmHandle;
  335. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  336. irpStack->Parameters.DeviceIoControl.IoControlCode = SMB_REGISTER_ALARM_NOTIFY;
  337. irpStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(registerAlarm);
  338. irpStack->Parameters.DeviceIoControl.Type3InputBuffer = &registerAlarm;
  339. irpStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(subsystemExtension->SmbAlarmHandle);
  340. IoSetCompletionRoutine (irp, SmbBattSynchronousRequest, &event, TRUE, TRUE, TRUE);
  341. IoCallDriver (subsystemExtension->SmbHcFdo, irp);
  342. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  343. status = irp->IoStatus.Status;
  344. if (!NT_SUCCESS(status)) {
  345. BattPrint(BAT_ERROR, ("SmbBattRegisterForAlarm: couldn't register for alarms - %x\n", status));
  346. }
  347. IoFreeIrp (irp);
  348. return status;
  349. }
  350. NTSTATUS
  351. SmbBattUnregisterForAlarm(
  352. IN PDEVICE_OBJECT Fdo
  353. )
  354. /*++
  355. Routine Description:
  356. This routine unregisters with the SmbHc for alarm notifications. This
  357. is only done when smart battery subsystem FDO is stopped or unloaded.
  358. Arguments:
  359. Fdo - Pointer to the Fdo for this device
  360. Irp - Pointer to the IRP for the current request
  361. Return Value:
  362. The function value is the final status of the call
  363. --*/
  364. {
  365. PIRP irp;
  366. PIO_STACK_LOCATION irpStack;
  367. KEVENT event;
  368. NTSTATUS status;
  369. PSMB_BATT_SUBSYSTEM subsystemExtension = (PSMB_BATT_SUBSYSTEM) Fdo->DeviceExtension;
  370. PAGED_CODE();
  371. //
  372. // DeRegister for alarm notifications
  373. //
  374. KeInitializeEvent (&event, NotificationEvent, FALSE);
  375. irp = IoAllocateIrp (subsystemExtension->SmbHcFdo->StackSize, FALSE);
  376. if (!irp) {
  377. BattPrint(BAT_ERROR, ("SmbBattUnregisterForAlarm: couldn't allocate irp\n"));
  378. return STATUS_INSUFFICIENT_RESOURCES;
  379. }
  380. irpStack = IoGetNextIrpStackLocation(irp);
  381. irp->UserBuffer = NULL;
  382. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  383. irpStack->Parameters.DeviceIoControl.IoControlCode = SMB_DEREGISTER_ALARM_NOTIFY;
  384. irpStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(subsystemExtension->SmbAlarmHandle);
  385. irpStack->Parameters.DeviceIoControl.Type3InputBuffer = &subsystemExtension->SmbAlarmHandle;
  386. irpStack->Parameters.DeviceIoControl.OutputBufferLength = 0;
  387. IoSetCompletionRoutine (irp, SmbBattSynchronousRequest, &event, TRUE, TRUE, TRUE);
  388. IoCallDriver (subsystemExtension->SmbHcFdo, irp);
  389. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  390. status = irp->IoStatus.Status;
  391. if (!NT_SUCCESS(status)) {
  392. BattPrint(BAT_ERROR, ("SmbBattUnregisterForAlarm: couldn't unregister for alarms - %x\n", status));
  393. }
  394. IoFreeIrp (irp);
  395. return status;
  396. }
  397. NTSTATUS
  398. SmbGetSBS (
  399. IN PULONG NumberOfBatteries,
  400. IN PBOOLEAN SelectorPresent,
  401. IN PDEVICE_OBJECT LowerDevice
  402. )
  403. /*++
  404. Routine Description:
  405. This routine has the ACPI driver run the control method _SBS for the smart battery
  406. subsystem. This control method returns a value that tells the driver how many
  407. batteries are supported and whether or not the system contains a selector.
  408. Arguments:
  409. NumberOfBatteries - pointer to return the number of batteries
  410. SelectorPresent - Pointer to return whether a selector is present (TRUE)
  411. LowerDevice - device object to call
  412. Return Value:
  413. Status of the IOCTL to the ACPI driver.
  414. --*/
  415. {
  416. ACPI_EVAL_INPUT_BUFFER inputBuffer;
  417. ACPI_EVAL_OUTPUT_BUFFER outputBuffer;
  418. KEVENT event;
  419. IO_STATUS_BLOCK ioStatusBlock;
  420. NTSTATUS status;
  421. PACPI_METHOD_ARGUMENT argument;
  422. PIRP irp;
  423. PAGED_CODE();
  424. BattPrint (BAT_TRACE, ("SmbGetSBS: Entering\n"));
  425. //
  426. // Initialize the input structure
  427. //
  428. RtlZeroMemory( &inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER) );
  429. inputBuffer.MethodNameAsUlong = SMBATT_SBS_METHOD;
  430. inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
  431. //
  432. // Set the event object to the unsignaled state.
  433. // It will be used to signal request completion.
  434. //
  435. KeInitializeEvent(&event, NotificationEvent, FALSE);
  436. //
  437. // Build synchronous request with no transfer.
  438. //
  439. irp = IoBuildDeviceIoControlRequest(
  440. IOCTL_ACPI_ASYNC_EVAL_METHOD,
  441. LowerDevice,
  442. &inputBuffer,
  443. sizeof(ACPI_EVAL_INPUT_BUFFER),
  444. &outputBuffer,
  445. sizeof(ACPI_EVAL_OUTPUT_BUFFER),
  446. FALSE,
  447. &event,
  448. &ioStatusBlock
  449. );
  450. if (irp == NULL) {
  451. BattPrint (BAT_ERROR, ("SmbGetSBS: couldn't create Irp\n"));
  452. return STATUS_INSUFFICIENT_RESOURCES;
  453. }
  454. //
  455. // Pass request to port driver and wait for request to complete.
  456. //
  457. status = IoCallDriver (LowerDevice, irp);
  458. if (status == STATUS_PENDING) {
  459. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  460. status = ioStatusBlock.Status;
  461. }
  462. //
  463. // Sanity check the data
  464. //
  465. if (outputBuffer.Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE ||
  466. outputBuffer.Count == 0) {
  467. status = STATUS_ACPI_INVALID_DATA;
  468. }
  469. *SelectorPresent = FALSE;
  470. *NumberOfBatteries = 0;
  471. if (!NT_SUCCESS(status)) {
  472. BattPrint (BAT_BIOS_ERROR | BAT_ERROR, ("SmbGetSBS: Irp failed - %x\n", status));
  473. } else {
  474. argument = outputBuffer.Argument;
  475. if (argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  476. return STATUS_ACPI_INVALID_DATA;
  477. }
  478. switch (argument->Argument) {
  479. case 0:
  480. BattPrint(BAT_DATA, ("SmbGetSBS: Number of batteries = 1, no selector\n"));
  481. *NumberOfBatteries = 1;
  482. break;
  483. case 1:
  484. case 2:
  485. case 3:
  486. case 4:
  487. BattPrint(BAT_DATA, ("SmbGetSBS: Number of batteries found - %x\n", argument->Argument));
  488. *SelectorPresent = TRUE;
  489. *NumberOfBatteries = argument->Argument;
  490. break;
  491. default:
  492. BattPrint(BAT_ERROR, ("SmbGetSBS: Invalid number of batteries - %x\n", argument->Argument));
  493. return STATUS_NO_SUCH_DEVICE;
  494. }
  495. }
  496. return status;
  497. }
  498. NTSTATUS
  499. SmbGetGLK (
  500. IN PBOOLEAN GlobalLockRequired,
  501. IN PDEVICE_OBJECT LowerDevice
  502. )
  503. /*++
  504. Routine Description:
  505. This routine has the ACPI driver run the control method _SBS for the smart battery
  506. subsystem. This control method returns a value that tells the driver how many
  507. batteries are supported and whether or not the system contains a selector.
  508. Arguments:
  509. GlobalLockRequired - Pointer to return whether lock acquisition is needed
  510. LowerDevice - device object to call
  511. Return Value:
  512. Status of the IOCTL to the ACPI driver.
  513. --*/
  514. {
  515. ACPI_EVAL_INPUT_BUFFER inputBuffer;
  516. ACPI_EVAL_OUTPUT_BUFFER outputBuffer;
  517. KEVENT event;
  518. IO_STATUS_BLOCK ioStatusBlock;
  519. NTSTATUS status;
  520. PACPI_METHOD_ARGUMENT argument;
  521. PIRP irp;
  522. PAGED_CODE();
  523. BattPrint (BAT_TRACE, ("SmbGetGLK: Entering\n"));
  524. //
  525. // Initialize the input structure
  526. //
  527. RtlZeroMemory( &inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER) );
  528. inputBuffer.MethodNameAsUlong = SMBATT_GLK_METHOD;
  529. inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
  530. //
  531. // Set the event object to the unsignaled state.
  532. // It will be used to signal request completion.
  533. //
  534. KeInitializeEvent(&event, NotificationEvent, FALSE);
  535. //
  536. // Build synchronous request with no transfer.
  537. //
  538. irp = IoBuildDeviceIoControlRequest(
  539. IOCTL_ACPI_ASYNC_EVAL_METHOD,
  540. LowerDevice,
  541. &inputBuffer,
  542. sizeof(ACPI_EVAL_INPUT_BUFFER),
  543. &outputBuffer,
  544. sizeof(ACPI_EVAL_OUTPUT_BUFFER),
  545. FALSE,
  546. &event,
  547. &ioStatusBlock
  548. );
  549. if (irp == NULL) {
  550. BattPrint (BAT_ERROR, ("SmbGetGLK: couldn't create Irp\n"));
  551. return STATUS_INSUFFICIENT_RESOURCES;
  552. }
  553. //
  554. // Pass request to port driver and wait for request to complete.
  555. //
  556. status = IoCallDriver (LowerDevice, irp);
  557. if (status == STATUS_PENDING) {
  558. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  559. status = ioStatusBlock.Status;
  560. }
  561. if (!NT_SUCCESS(status)) {
  562. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  563. status = STATUS_SUCCESS;
  564. *GlobalLockRequired = FALSE;
  565. BattPrint (BAT_NOTE, ("SmbGetGLK: _GLK not found assuming lock is not needed.\n"));
  566. } else {
  567. BattPrint (BAT_ERROR, ("SmbGetGLK: Irp failed - %x\n", status));
  568. }
  569. } else {
  570. //
  571. // Sanity check the data
  572. //
  573. if (outputBuffer.Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE ||
  574. outputBuffer.Count == 0) {
  575. return STATUS_ACPI_INVALID_DATA;
  576. }
  577. argument = outputBuffer.Argument;
  578. if (argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  579. return STATUS_ACPI_INVALID_DATA;
  580. }
  581. if (argument->Argument == 0) {
  582. *GlobalLockRequired = FALSE;
  583. } else if (argument->Argument == 1) {
  584. *GlobalLockRequired = TRUE;
  585. } else {
  586. BattPrint(BAT_BIOS_ERROR, ("SmbGetGLK: Invalid value returned - %x\n", argument->Argument));
  587. status = STATUS_UNSUCCESSFUL;
  588. }
  589. }
  590. BattPrint (BAT_DATA, ("SmbGetGLK: Returning %x GLK = %d\n", status, SmbBattUseGlobalLock));
  591. return status;
  592. }
  593. NTSTATUS
  594. SmbBattCreatePdos(
  595. IN PDEVICE_OBJECT SubsystemFdo
  596. )
  597. /*++
  598. Routine Description:
  599. This routine creates a PDO for each battery supported by the system and puts
  600. it into a list kept with the FDO for the smart battery subsystem.
  601. Arguments:
  602. SubsystemFdo - Fdo for the smart battery subsystem
  603. Return Value:
  604. Status for creation of battery PDO.
  605. --*/
  606. {
  607. ULONG i;
  608. NTSTATUS status;
  609. PSMB_BATT_PDO batteryPdoExt;
  610. UNICODE_STRING numberString;
  611. WCHAR numberBuffer[10];
  612. PDEVICE_OBJECT pdo;
  613. PSMB_BATT_SUBSYSTEM subsystemExt = (PSMB_BATT_SUBSYSTEM) SubsystemFdo->DeviceExtension;
  614. BOOLEAN selectorPresent = FALSE;
  615. PAGED_CODE();
  616. //
  617. // Find out if there are multiple batteries and a selector on this machine.
  618. //
  619. status = SmbGetSBS (
  620. &subsystemExt->NumberOfBatteries,
  621. &subsystemExt->SelectorPresent,
  622. subsystemExt->LowerDevice
  623. );
  624. if (!NT_SUCCESS(status)) {
  625. BattPrint(BAT_ERROR, ("SmbBattCreatePdos: error reading SBS\n"));
  626. return status;
  627. }
  628. status = SmbGetGLK (
  629. &SmbBattUseGlobalLock,
  630. subsystemExt->LowerDevice
  631. );
  632. if (!NT_SUCCESS(status)) {
  633. BattPrint(BAT_ERROR, ("SmbBattCreatePdos: error reading GLK\n"));
  634. //
  635. // If this failed, ignore the failure and continue. This is not critical.
  636. //
  637. }
  638. //
  639. // Build the selector information structure
  640. //
  641. // Adjust Number of Batteries to Match SelectorInfo Supported Batteries
  642. // Just in case the ACPI information is incorrect
  643. status = SmbBattBuildSelectorStruct (SubsystemFdo);
  644. if (!NT_SUCCESS (status)) {
  645. BattPrint(BAT_ERROR, ("SmbBattCreatePdos: couldn't talk to the selector\n"));
  646. return status;
  647. }
  648. //
  649. // Build device object for each battery
  650. //
  651. for (i = 0; i < subsystemExt->NumberOfBatteries; i++) {
  652. //
  653. // Create the device object
  654. //
  655. status = IoCreateDevice(
  656. SubsystemFdo->DriverObject,
  657. sizeof (SMB_BATT_PDO),
  658. NULL,
  659. FILE_DEVICE_BATTERY,
  660. FILE_DEVICE_SECURE_OPEN|FILE_AUTOGENERATED_DEVICE_NAME,
  661. FALSE,
  662. &pdo
  663. );
  664. if (status != STATUS_SUCCESS) {
  665. BattPrint(BAT_ERROR, ("SmbBattCreatePdos: error creating battery pdo %x\n", status));
  666. //
  667. // Make sure we don't later try to use devices that weren't created.
  668. //
  669. subsystemExt->NumberOfBatteries = i;
  670. return(status);
  671. }
  672. //
  673. // Initialize the Pdo
  674. //
  675. pdo->Flags |= DO_BUFFERED_IO;
  676. pdo->Flags |= DO_POWER_PAGABLE;
  677. //
  678. // Save the PDO in the subsystem FDO PDO list
  679. //
  680. subsystemExt->BatteryPdoList[i] = pdo;
  681. //
  682. // Initialize the PDO extension
  683. //
  684. batteryPdoExt = (PSMB_BATT_PDO) pdo->DeviceExtension;
  685. batteryPdoExt->SmbBattFdoType = SmbTypePdo;
  686. batteryPdoExt->DeviceObject = pdo;
  687. batteryPdoExt->BatteryNumber = i;
  688. batteryPdoExt->SubsystemFdo = SubsystemFdo;
  689. IoInitializeRemoveLock (&batteryPdoExt->RemoveLock,
  690. SMB_BATTERY_TAG,
  691. REMOVE_LOCK_MAX_LOCKED_MINUTES,
  692. REMOVE_LOCK_HIGH_WATER_MARK);
  693. //
  694. // Device is ready for use
  695. //
  696. pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  697. } // for (i = 0; i < subsystemExt->NumberOfBatteries; i++)
  698. return STATUS_SUCCESS;
  699. }
  700. NTSTATUS
  701. SmbBattBuildDeviceRelations(
  702. IN PSMB_BATT_SUBSYSTEM SubsystemExt,
  703. IN PDEVICE_RELATIONS *DeviceRelations
  704. )
  705. /*++
  706. Routine Description:
  707. This routine is checks the device relations structure for existing device
  708. relations, calculates how big a new device relations structure has to be,
  709. allocates it, and fills it with the PDOs created for the batteries.
  710. Arguments:
  711. SubsystemExt - Device extension for the smart battery subsystem FDO
  712. DeviceRelations - The Current DeviceRelations for the device...
  713. Return Value:
  714. NTSTATUS
  715. --*/
  716. {
  717. PDEVICE_RELATIONS newDeviceRelations;
  718. ULONG i, j;
  719. ULONG newDeviceRelationsSize;
  720. NTSTATUS status;
  721. ULONG existingPdos = 0;
  722. ULONG deviceRelationsSize = 0;
  723. ULONG numberOfPdos = 0;
  724. PAGED_CODE();
  725. //
  726. // Calculate the size the new device relations structure has to be
  727. //
  728. if (*DeviceRelations != NULL && (*DeviceRelations)->Count > 0) {
  729. //
  730. // There are existing device relations to be copied
  731. //
  732. existingPdos = (*DeviceRelations)->Count;
  733. deviceRelationsSize = sizeof (ULONG) + (sizeof (PDEVICE_OBJECT) * existingPdos);
  734. }
  735. //
  736. // Calculate the size needed for the new device relations structure and allocate it
  737. //
  738. numberOfPdos = existingPdos + SubsystemExt->NumberOfBatteries;
  739. newDeviceRelationsSize = sizeof (ULONG) + (sizeof (PDEVICE_OBJECT) * numberOfPdos);
  740. newDeviceRelations = ExAllocatePoolWithTag (PagedPool, newDeviceRelationsSize, 'StaB');
  741. if (!newDeviceRelations) {
  742. BattPrint (BAT_ERROR, ("SmbBattBuildDeviceRelations: couldn't allocate device relations buffer\n"));
  743. return STATUS_INSUFFICIENT_RESOURCES;
  744. }
  745. //
  746. // If there are existing device relations copy them to the new device
  747. // relations structure and free the old one.
  748. //
  749. if (existingPdos) {
  750. RtlCopyMemory (newDeviceRelations, *DeviceRelations, deviceRelationsSize);
  751. }
  752. if (*DeviceRelations) { // Could be a zero length list, but still need freeing
  753. ExFreePool (*DeviceRelations);
  754. }
  755. //
  756. // Now add the battery PDOs to the end of the list and reference it
  757. //
  758. for (i = existingPdos, j = 0; i < numberOfPdos; i ++, j ++) {
  759. newDeviceRelations->Objects[i] = SubsystemExt->BatteryPdoList[j];
  760. status = ObReferenceObjectByPointer(
  761. SubsystemExt->BatteryPdoList[j],
  762. 0,
  763. NULL,
  764. KernelMode
  765. );
  766. if (!NT_SUCCESS(status) ) {
  767. //
  768. // This should theoretically never happen...
  769. //
  770. BattPrint(BAT_ERROR, ("SmbBattBuildDeviceRelations: error referencing battery pdo %x\n", status));
  771. return status;
  772. }
  773. }
  774. newDeviceRelations->Count = numberOfPdos;
  775. *DeviceRelations = newDeviceRelations;
  776. return STATUS_SUCCESS;
  777. }
  778. NTSTATUS
  779. SmbBattQueryDeviceRelations(
  780. IN PDEVICE_OBJECT DeviceObject,
  781. IN PIRP Irp
  782. )
  783. /*++
  784. Routine Description:
  785. This routine handles the IRP_MN_QUERY_DEVICE_RELATIONS.
  786. Arguments:
  787. Pdo - Battery PDO
  788. Irp - The query Irp
  789. Return Value:
  790. NTSTATUS
  791. --*/
  792. {
  793. PSMB_NP_BATT SmbNPBatt = (PSMB_NP_BATT) DeviceObject->DeviceExtension;
  794. PSMB_BATT_PDO PdoExt = (PSMB_BATT_PDO) DeviceObject->DeviceExtension;
  795. PSMB_BATT_SUBSYSTEM SubsystemExt = (PSMB_BATT_SUBSYSTEM) DeviceObject->DeviceExtension;
  796. PDEVICE_OBJECT pdo;
  797. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  798. NTSTATUS status = STATUS_NOT_SUPPORTED;
  799. ULONG i;
  800. PDEVICE_RELATIONS deviceRelations =
  801. (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  802. PAGED_CODE();
  803. BattPrint(BAT_TRACE, ("SmbBattQueryDeviceRelations: ENTERING\n"));
  804. switch (SmbNPBatt->SmbBattFdoType) {
  805. case SmbTypeSubsystem: {
  806. if (IrpSp->Parameters.QueryDeviceRelations.Type == BusRelations) {
  807. BattPrint(
  808. BAT_IRPS,
  809. ("SmbBattQueryDeviceRelations: Handling Bus relations request\n")
  810. );
  811. if (SubsystemExt->NumberOfBatteries != 0) {
  812. //
  813. // We've already found our batteries, so we don't need to
  814. // look again since smart batteries are static.
  815. // Just rebuild the return structure.
  816. //
  817. status = SmbBattBuildDeviceRelations (SubsystemExt, &deviceRelations);
  818. } else {
  819. status = SmbBattCreatePdos (DeviceObject);
  820. if (NT_SUCCESS (status)) {
  821. status = SmbBattBuildDeviceRelations (SubsystemExt, &deviceRelations);
  822. }
  823. if (NT_SUCCESS (status)) {
  824. //
  825. // Now register for alarms
  826. // (Used to register during START_DEVICE,
  827. // but don't need notifications until after the batteries
  828. // are here. This avoids some other problems too.)
  829. status = SmbBattRegisterForAlarm (DeviceObject);
  830. }
  831. }
  832. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  833. }
  834. break;
  835. }
  836. case SmbTypeBattery: {
  837. status = STATUS_NOT_SUPPORTED;
  838. break;
  839. }
  840. case SmbTypePdo: {
  841. if (IrpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation ) {
  842. BattPrint(
  843. BAT_IRPS,
  844. ("SmbBattQueryDeviceRelations: Handling TargetDeviceRelation request\n")
  845. );
  846. deviceRelations = ExAllocatePoolWithTag (PagedPool,
  847. sizeof(DEVICE_RELATIONS),
  848. SMB_BATTERY_TAG);
  849. if (!deviceRelations) {
  850. return STATUS_INSUFFICIENT_RESOURCES;
  851. }
  852. status = ObReferenceObjectByPointer(DeviceObject,
  853. 0,
  854. NULL,
  855. KernelMode);
  856. if (!NT_SUCCESS(status)) {
  857. ExFreePool(deviceRelations);
  858. return status;
  859. }
  860. deviceRelations->Count = 1;
  861. deviceRelations->Objects[0] = DeviceObject;
  862. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  863. } else {
  864. status = STATUS_NOT_SUPPORTED;
  865. }
  866. break;
  867. }
  868. default: {
  869. ASSERT (FALSE);
  870. }
  871. }
  872. return status;
  873. }
  874. NTSTATUS
  875. SmbBattRemoveDevice(
  876. IN PDEVICE_OBJECT DeviceObject,
  877. IN PIRP Irp
  878. )
  879. /*++
  880. Routine Description:
  881. This routine handles the IRP_MN_REMOVE_DEVICE.
  882. Arguments:
  883. Pdo - Battery PDO
  884. Irp - The query Irp
  885. Return Value:
  886. NTSTATUS
  887. --*/
  888. {
  889. PSMB_NP_BATT SmbNPBatt = (PSMB_NP_BATT) DeviceObject->DeviceExtension;
  890. PSMB_BATT_PDO PdoExt = (PSMB_BATT_PDO) DeviceObject->DeviceExtension;
  891. PSMB_BATT_SUBSYSTEM SubsystemExt = (PSMB_BATT_SUBSYSTEM) DeviceObject->DeviceExtension;
  892. PDEVICE_OBJECT pdo;
  893. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  894. NTSTATUS status = STATUS_NOT_SUPPORTED;
  895. ULONG i;
  896. PAGED_CODE();
  897. BattPrint(BAT_TRACE, ("SmbBattRemoveDevice: ENTERING\n"));
  898. switch (SmbNPBatt->SmbBattFdoType) {
  899. case SmbTypeSubsystem: {
  900. BattPrint(BAT_IRPS, ("SmbBattRemoveDevice: Removing Subsystem FDO.\n"));
  901. //
  902. // De-register for notifications
  903. //
  904. SmbBattUnregisterForAlarm (DeviceObject);
  905. IoFreeWorkItem (SubsystemExt->WorkerThread);
  906. //
  907. // Remove PDOs
  908. //
  909. for (i = 0; i < SubsystemExt->NumberOfBatteries; i++) {
  910. pdo = SubsystemExt->BatteryPdoList[i];
  911. if (pdo) {
  912. PdoExt = (PSMB_BATT_PDO) pdo->DeviceExtension;
  913. status = IoAcquireRemoveLock (&PdoExt->RemoveLock, Irp);
  914. IoReleaseRemoveLockAndWait (&PdoExt->RemoveLock, Irp);
  915. SubsystemExt->BatteryPdoList[i] = NULL;
  916. IoDeleteDevice (pdo);
  917. }
  918. }
  919. if ((SubsystemExt->SelectorPresent) && (SubsystemExt->Selector)) {
  920. ExFreePool (SubsystemExt->Selector);
  921. }
  922. IoSkipCurrentIrpStackLocation (Irp);
  923. Irp->IoStatus.Status = STATUS_SUCCESS;
  924. status = IoCallDriver (SubsystemExt->LowerDevice, Irp);
  925. IoDetachDevice (SubsystemExt->LowerDevice);
  926. IoDeleteDevice (DeviceObject);
  927. break;
  928. }
  929. case SmbTypeBattery: {
  930. BattPrint(BAT_IRPS, ("SmbBattRemoveDevice: Removing Battery FDO\n"));
  931. IoReleaseRemoveLockAndWait (&SmbNPBatt->RemoveLock, Irp);
  932. //
  933. // Unregister as a WMI Provider.
  934. //
  935. SmbBattWmiDeRegistration(SmbNPBatt);
  936. //
  937. // Tell the class driver we are going away
  938. //
  939. status = BatteryClassUnload (SmbNPBatt->Class);
  940. ASSERT (NT_SUCCESS(status));
  941. ExFreePool (SmbNPBatt->Batt);
  942. ((PSMB_BATT_PDO) SmbNPBatt->LowerDevice->DeviceExtension)->Fdo = NULL;
  943. IoSkipCurrentIrpStackLocation (Irp);
  944. Irp->IoStatus.Status = STATUS_SUCCESS;
  945. status = IoCallDriver (SmbNPBatt->LowerDevice, Irp);
  946. IoDetachDevice (SmbNPBatt->LowerDevice);
  947. IoDeleteDevice (DeviceObject);
  948. break;
  949. }
  950. case SmbTypePdo: {
  951. BattPrint(BAT_IRPS, ("SmbBattRemoveDevice: Remove for Battery PDO (doing nothing)\n"));
  952. //
  953. // Don't delete the device until it is physically removed.
  954. // Usually, the battery subsystem can't be physically removed...
  955. //
  956. //
  957. // Need to release Remove lock, since PnP dispatch won't...
  958. //
  959. IoReleaseRemoveLock (&PdoExt->RemoveLock, Irp);
  960. status = STATUS_SUCCESS;
  961. //
  962. // Complete the request with the current status
  963. //
  964. Irp->IoStatus.Status = status;
  965. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  966. break;
  967. }
  968. default: {
  969. ASSERT (FALSE);
  970. }
  971. }
  972. BattPrint(BAT_TRACE, ("SmbBattRemoveDevice: EXITING\n"));
  973. return status;
  974. }
  975. NTSTATUS
  976. SmbBattQueryId(
  977. IN PDEVICE_OBJECT Pdo,
  978. IN PIRP Irp
  979. )
  980. /*++
  981. Routine Description:
  982. This routine handles the IRP_MN_QUERY_ID for the newly created battery PDOs.
  983. Arguments:
  984. Pdo - Battery PDO
  985. Irp - The query Irp
  986. Return Value:
  987. NTSTATUS
  988. --*/
  989. {
  990. UNICODE_STRING unicodeString;
  991. WCHAR unicodeBuffer[MAX_DEVICE_NAME_LENGTH];
  992. UNICODE_STRING numberString;
  993. WCHAR numberBuffer[10];
  994. PSMB_BATT_PDO pdoExt = (PSMB_BATT_PDO) Pdo->DeviceExtension;
  995. NTSTATUS status = STATUS_SUCCESS;
  996. PWCHAR idString = NULL;
  997. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  998. PAGED_CODE();
  999. BattPrint(BAT_TRACE, ("SmbBattQueryId: ENTERING\n"));
  1000. RtlZeroMemory (unicodeBuffer, MAX_DEVICE_NAME_LENGTH);
  1001. unicodeString.MaximumLength = MAX_DEVICE_NAME_LENGTH;
  1002. unicodeString.Length = 0;
  1003. unicodeString.Buffer = unicodeBuffer;
  1004. switch (irpStack->Parameters.QueryId.IdType) {
  1005. case BusQueryDeviceID:
  1006. //
  1007. // This string has to have the form BUS\DEVICE.
  1008. //
  1009. // Use SMB as bus and SBS as device
  1010. //
  1011. RtlAppendUnicodeToString (&unicodeString, SubSystemIdentifier);
  1012. break;
  1013. case BusQueryInstanceID:
  1014. //
  1015. // Return the string "Batteryxx" where xx is the battery number
  1016. //
  1017. numberString.MaximumLength = 10;
  1018. numberString.Buffer = &numberBuffer[0];
  1019. RtlIntegerToUnicodeString (pdoExt->BatteryNumber, 10, &numberString);
  1020. RtlAppendUnicodeToString (&unicodeString, BatteryInstance);
  1021. RtlAppendUnicodeToString (&unicodeString, &numberString.Buffer[0]);
  1022. break;
  1023. case BusQueryHardwareIDs:
  1024. //
  1025. // This is the Pnp ID for the smart battery subsystem "ACPI0002".
  1026. // Make new hardware ID SMB\SBS, SmartBattery as a MULTIZ string
  1027. // so we have to add a NULL string to terminate.
  1028. //
  1029. RtlAppendUnicodeToString (&unicodeString, HidSmartBattery);
  1030. unicodeString.Length += sizeof (WCHAR);
  1031. break;
  1032. default:
  1033. //
  1034. // Unknown Query Type
  1035. //
  1036. status = STATUS_NOT_SUPPORTED;
  1037. }
  1038. if (status != STATUS_NOT_SUPPORTED) {
  1039. //
  1040. // If we created a string, allocate a buffer for it and copy it into the buffer.
  1041. // We need to make sure that we also copy the NULL terminator.
  1042. //
  1043. if (unicodeString.Length) {
  1044. idString = ExAllocatePoolWithTag (PagedPool, unicodeString.Length + sizeof (WCHAR), 'StaB');
  1045. if (!idString) {
  1046. BattPrint (BAT_ERROR, ("SmbBattQueryId: couldn't allocate id string buffer\n"));
  1047. return STATUS_INSUFFICIENT_RESOURCES;
  1048. }
  1049. RtlZeroMemory (idString, unicodeString.Length + sizeof (WCHAR));
  1050. RtlCopyMemory (idString, unicodeString.Buffer, unicodeString.Length);
  1051. }
  1052. Irp->IoStatus.Status = status;
  1053. Irp->IoStatus.Information = (ULONG_PTR) idString;
  1054. }
  1055. BattPrint(BAT_DATA, ("SmbBattQueryId: returning ID = %x\n", idString));
  1056. return status;
  1057. }
  1058. NTSTATUS
  1059. SmbBattQueryCapabilities(
  1060. IN PDEVICE_OBJECT Pdo,
  1061. IN PIRP Irp
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine handles the IRP_MN_QUERY_CAPABILITIES for the newly created
  1066. battery PDOs.
  1067. Arguments:
  1068. Pdo - Battery PDO
  1069. Irp - The query Irp
  1070. Return Value:
  1071. NTSTATUS
  1072. --*/
  1073. {
  1074. PDEVICE_CAPABILITIES deviceCaps;
  1075. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1076. PAGED_CODE();
  1077. deviceCaps = irpStack->Parameters.DeviceCapabilities.Capabilities;
  1078. if (deviceCaps->Version != 1) {
  1079. return STATUS_NOT_SUPPORTED;
  1080. }
  1081. //
  1082. // Now set up the bits for the capabilities.
  1083. //
  1084. //All bits are initialized to false. Only set bits that we support
  1085. deviceCaps->SilentInstall = TRUE;
  1086. //
  1087. // Now fill in the po manager information.
  1088. //
  1089. deviceCaps->SystemWake = PowerSystemUnspecified;
  1090. deviceCaps->DeviceWake = PowerDeviceUnspecified;
  1091. deviceCaps->D1Latency = 1;
  1092. deviceCaps->D2Latency = 1;
  1093. deviceCaps->D3Latency = 1;
  1094. return STATUS_SUCCESS;
  1095. }
  1096. SmbBattBuildSelectorStruct(
  1097. IN PDEVICE_OBJECT SubsystemFdo
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. This routine determines that address of the selector (whether it is a stand
  1102. alone selector of part of the charger) and builds a selector structure with
  1103. this information. It also reads the initial selector information and
  1104. caches this in the structure. This structure will be passed out to all of
  1105. the smart batteries in the system.
  1106. Arguments:
  1107. SubsystemFdo - Fdo for the smart battery subsystem
  1108. Return Value:
  1109. NTSTATUS
  1110. --*/
  1111. {
  1112. ULONG result;
  1113. UCHAR smbStatus;
  1114. PBATTERY_SELECTOR selector = NULL;
  1115. PSMB_BATT_SUBSYSTEM subsystemExt = (PSMB_BATT_SUBSYSTEM) SubsystemFdo->DeviceExtension;
  1116. ULONG numberOfBatteries;
  1117. PAGED_CODE();
  1118. if (subsystemExt->SelectorPresent) {
  1119. //
  1120. // Allocate the selector structure. This has to be from non-paged pool because
  1121. // it will be accessed as part of the alarm processing.
  1122. //
  1123. selector = ExAllocatePoolWithTag (NonPagedPool, sizeof (BATTERY_SELECTOR), 'StaB');
  1124. if (!selector) {
  1125. BattPrint (BAT_ERROR, ("SmbBattBuildSelectorStruct: Couldn't allocate selector structure\n"));
  1126. //
  1127. // Force Selector Not Present if allocation fails
  1128. //
  1129. subsystemExt->Selector = NULL;
  1130. subsystemExt->SelectorPresent = FALSE;
  1131. subsystemExt->NumberOfBatteries = 0;
  1132. return STATUS_INSUFFICIENT_RESOURCES;
  1133. }
  1134. //
  1135. // See if the selector is part of the charger. We do this by reading
  1136. // directly from the selector first. If this fails, then we verify
  1137. // the charger is implementing the selector.
  1138. //
  1139. smbStatus = SmbBattGenericRW (
  1140. subsystemExt->SmbHcFdo,
  1141. SMB_SELECTOR_ADDRESS,
  1142. SELECTOR_SELECTOR_STATE,
  1143. &result
  1144. );
  1145. if (smbStatus == SMB_STATUS_OK) {
  1146. //
  1147. // We have a stand alone selector
  1148. //
  1149. selector->SelectorAddress = SMB_SELECTOR_ADDRESS;
  1150. selector->SelectorStateCommand = SELECTOR_SELECTOR_STATE;
  1151. selector->SelectorPresetsCommand= SELECTOR_SELECTOR_PRESETS;
  1152. selector->SelectorInfoCommand = SELECTOR_SELECTOR_INFO;
  1153. BattPrint (BAT_NOTE, ("SmbBattBuildSelectorStruct: The selector is standalone\n"));
  1154. } else {
  1155. //
  1156. // Read the Charger Spec Info to check Selector Implemented Bit
  1157. // NOTE: We're doing this for verification and information purposes
  1158. //
  1159. smbStatus = SmbBattGenericRW (
  1160. subsystemExt->SmbHcFdo,
  1161. SMB_CHARGER_ADDRESS,
  1162. CHARGER_SPEC_INFO,
  1163. &result
  1164. );
  1165. if (smbStatus == SMB_STATUS_OK) {
  1166. if (result & CHARGER_SELECTOR_SUPPORT_BIT) {
  1167. // If Selector Support Bit is present, then Selector implemented in Charger
  1168. BattPrint (BAT_NOTE, ("SmbBattBuildSelectorStruct: ChargerSpecInfo indicates charger implementing selector\n"));
  1169. } else {
  1170. // If Charger says it doesn't implement Selector, let's double-check anyway
  1171. BattPrint (BAT_NOTE, ("SmbBattBuildSelectorStruct: ChargerSpecInfo indicates charger does not implement selector\n"));
  1172. }
  1173. } else {
  1174. // If it returns an error, let's double-check anyway
  1175. BattPrint (BAT_ERROR, ("SmbBattBuildSelectorStruct: Couldn't read ChargerSpecInfo - %x\n", smbStatus));
  1176. }
  1177. //
  1178. // Read SelectorState for Cache
  1179. //
  1180. smbStatus = SmbBattGenericRW (
  1181. subsystemExt->SmbHcFdo,
  1182. SMB_CHARGER_ADDRESS,
  1183. CHARGER_SELECTOR_STATE,
  1184. &result
  1185. );
  1186. if (smbStatus == SMB_STATUS_OK) {
  1187. BattPrint (BAT_DATA, ("SmbBattBuildSelectorStruct: Selector state %x\n", result));
  1188. } else {
  1189. BattPrint (BAT_ERROR, ("SmbBattBuildSelectorStruct: Couldn't read charger selector state - %x\n", smbStatus));
  1190. goto SelectorErrorExit;
  1191. }
  1192. //
  1193. // The charger is implementing the selector
  1194. //
  1195. selector->SelectorAddress = SMB_CHARGER_ADDRESS;
  1196. selector->SelectorStateCommand = CHARGER_SELECTOR_STATE;
  1197. selector->SelectorPresetsCommand= CHARGER_SELECTOR_PRESETS;
  1198. selector->SelectorInfoCommand = CHARGER_SELECTOR_INFO;
  1199. BattPrint (BAT_NOTE, ("SmbBattBuildSelectorStruct: Charger implements the selector\n"));
  1200. }
  1201. //
  1202. // Initialize the selector mutex
  1203. //
  1204. ExInitializeFastMutex (&selector->Mutex);
  1205. //
  1206. // Store SelectorState in Cache
  1207. //
  1208. selector->SelectorState = result;
  1209. //
  1210. // Read SelectorPresets for Cache
  1211. //
  1212. smbStatus = SmbBattGenericRW (
  1213. subsystemExt->SmbHcFdo,
  1214. selector->SelectorAddress,
  1215. selector->SelectorPresetsCommand,
  1216. &selector->SelectorPresets
  1217. );
  1218. if (smbStatus != SMB_STATUS_OK) {
  1219. BattPrint (BAT_ERROR, ("SmbBattBuildSelectorStruct: Couldn't read selector presets - %x\n", smbStatus));
  1220. //
  1221. // Should we really fail the whole thing, because of an error reading SelectorPresets?
  1222. // Let's Emulate the Information (Ok To Use All, Use Next A if available)
  1223. //
  1224. selector->SelectorPresets = (selector->SelectorState & SELECTOR_PRESETS_OKTOUSE_MASK);
  1225. if (selector->SelectorPresets & BATTERY_A_PRESENT) {
  1226. selector->SelectorPresets |= (BATTERY_A_PRESENT << SELECTOR_SHIFT_USENEXT);
  1227. }
  1228. BattPrint (BAT_ERROR, ("SmbBattBuildSelectorStruct: Emulating Selector Presets - %x\n", selector->SelectorPresets));
  1229. } else {
  1230. BattPrint (BAT_DATA, ("SmbBattBuildSelectorStruct: Selector presets %x\n", selector->SelectorPresets));
  1231. }
  1232. //
  1233. // Read Selector Info for Cache
  1234. //
  1235. smbStatus = SmbBattGenericRW (
  1236. subsystemExt->SmbHcFdo,
  1237. selector->SelectorAddress,
  1238. selector->SelectorInfoCommand,
  1239. &selector->SelectorInfo
  1240. );
  1241. if (smbStatus != SMB_STATUS_OK) {
  1242. BattPrint (BAT_ERROR, ("SmbBattBuildSelectorStruct: Couldn't read selector info - %x\n", smbStatus));
  1243. //
  1244. // Should we really fail the whole thing, because of an error reading SelectorInfo?
  1245. // Let's Emulate the Information (Specification 1.0, No Charge Indicator)
  1246. //
  1247. selector->SelectorInfo = 0x0010;
  1248. if (subsystemExt->NumberOfBatteries > 0) {
  1249. selector->SelectorInfo |= BATTERY_A_PRESENT;
  1250. }
  1251. if (subsystemExt->NumberOfBatteries > 1) {
  1252. selector->SelectorInfo |= BATTERY_B_PRESENT;
  1253. }
  1254. if (subsystemExt->NumberOfBatteries > 2) {
  1255. selector->SelectorInfo |= BATTERY_C_PRESENT;
  1256. }
  1257. if (subsystemExt->NumberOfBatteries > 3) {
  1258. selector->SelectorInfo |= BATTERY_D_PRESENT;
  1259. }
  1260. BattPrint (BAT_ERROR, ("SmbBattBuildSelectorStruct: Emulating Selector Info - %x\n", selector->SelectorInfo));
  1261. } else {
  1262. BattPrint (BAT_NOTE, ("SmbBattBuildSelectorStruct: Selector info %x\n", selector->SelectorInfo));
  1263. // Verify the Number of Batteries against the SelectorInfo
  1264. numberOfBatteries = 0;
  1265. result = (selector->SelectorInfo & SELECTOR_INFO_SUPPORT_MASK);
  1266. if (result & BATTERY_A_PRESENT) numberOfBatteries++;
  1267. if (result & BATTERY_B_PRESENT) numberOfBatteries++;
  1268. if (result & BATTERY_C_PRESENT) numberOfBatteries++;
  1269. if (result & BATTERY_D_PRESENT) numberOfBatteries++;
  1270. // Should we always override ACPI??
  1271. // Proposed Solution: if Selector supports less batteries than
  1272. // ACPI says, then Override ACPI with selector support. If
  1273. // Selector supports more than ACPI says, then don't override,
  1274. // unless ACPI was invalid and the # of batteries = 1
  1275. if (subsystemExt->NumberOfBatteries > numberOfBatteries) {
  1276. subsystemExt->NumberOfBatteries = numberOfBatteries;
  1277. } else if ((subsystemExt->NumberOfBatteries == 1) && (numberOfBatteries > 1)) {
  1278. subsystemExt->NumberOfBatteries = numberOfBatteries;
  1279. } else if (subsystemExt->NumberOfBatteries < numberOfBatteries) {
  1280. //subsystemExt->NumberOfBatteries = numberOfBatteries;
  1281. }
  1282. }
  1283. } // if (subsystemFdo->SelectorPresent)
  1284. //
  1285. // Everything was OK
  1286. //
  1287. subsystemExt->Selector = selector;
  1288. return STATUS_SUCCESS;
  1289. SelectorErrorExit:
  1290. //
  1291. // If a failure occurs, free the selector structure and don't creat any batery devices.
  1292. //
  1293. ExFreePool (selector);
  1294. subsystemExt->Selector = NULL;
  1295. subsystemExt->SelectorPresent = FALSE;
  1296. subsystemExt->NumberOfBatteries = 0;
  1297. return STATUS_UNSUCCESSFUL;
  1298. }