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.

1394 lines
37 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. cmbpnp.c
  5. Abstract:
  6. Control Method Battery Plug and Play support
  7. Author:
  8. Ron Mosgrove
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "CmBattp.h"
  14. #include <wdmguid.h>
  15. #include <string.h>
  16. //
  17. // Power Source Type registry key
  18. //
  19. PCWSTR PowerSourceType = L"PowerSourceType";
  20. #define POWER_SOURCE_TYPE_BATTERY 0
  21. #define POWER_SOURCE_TYPE_AC_ADAPTER 1
  22. //
  23. // WaitWake registry key
  24. //
  25. PCWSTR WaitWakeEnableKey = L"WaitWakeEnabled";
  26. //
  27. // Globals
  28. //
  29. PDEVICE_OBJECT AcAdapterPdo = NULL;
  30. //
  31. // Prototypes
  32. //
  33. NTSTATUS
  34. CmBattAddDevice(
  35. IN PDRIVER_OBJECT DriverObject,
  36. IN PDEVICE_OBJECT Pdo
  37. );
  38. NTSTATUS
  39. CmBattRemoveDevice(
  40. IN PDEVICE_OBJECT DeviceObject,
  41. IN PIRP Irp
  42. );
  43. NTSTATUS
  44. CmBattGetAcpiInterfaces(
  45. IN PDEVICE_OBJECT LowerDevice,
  46. OUT PACPI_INTERFACE_STANDARD AcpiInterfaces
  47. );
  48. NTSTATUS
  49. CmBattAddBattery(
  50. IN PDRIVER_OBJECT DriverObject,
  51. IN PDEVICE_OBJECT Pdo
  52. );
  53. NTSTATUS
  54. CmBattAddAcAdapter(
  55. IN PDRIVER_OBJECT DriverObject,
  56. IN PDEVICE_OBJECT Pdo
  57. );
  58. NTSTATUS
  59. CmBattCreateFdo(
  60. IN PDRIVER_OBJECT DriverObject,
  61. IN PDEVICE_OBJECT Pdo,
  62. IN ULONG ExtensionSize,
  63. OUT PDEVICE_OBJECT *NewFdo
  64. );
  65. VOID
  66. CmBattDestroyFdo(
  67. IN PDEVICE_OBJECT Fdo
  68. );
  69. NTSTATUS
  70. CmBattIoCompletion(
  71. IN PDEVICE_OBJECT DeviceObject,
  72. IN PIRP Irp,
  73. IN PKEVENT pdoIoCompletedEvent
  74. )
  75. /*++
  76. Routine Description:
  77. This routine catches completion notifications.
  78. Arguments:
  79. DeviceObject - Pointer to class device object.
  80. Irp - Pointer to the request packet.
  81. pdoIoCompletedEvent - the just completed event
  82. Return Value:
  83. Status is returned.
  84. --*/
  85. {
  86. CmBattPrint (CMBATT_TRACE, ("CmBattIoCompletion: Event (%x)\n", pdoIoCompletedEvent));
  87. KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
  88. return STATUS_MORE_PROCESSING_REQUIRED;
  89. }
  90. NTSTATUS
  91. CmBattAddDevice(
  92. IN PDRIVER_OBJECT DriverObject,
  93. IN PDEVICE_OBJECT Pdo
  94. )
  95. /*++
  96. Routine Description:
  97. This routine creates functional device objects for each CmBatt controller in the
  98. system and attaches them to the physical device objects for the controllers
  99. Arguments:
  100. DriverObject - a pointer to the object for this driver
  101. PhysicalDeviceObject - a pointer to the physical object we need to attach to
  102. Return Value:
  103. Status from device creation and initialization
  104. --*/
  105. {
  106. NTSTATUS Status;
  107. HANDLE handle;
  108. UNICODE_STRING unicodeString;
  109. CHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)];
  110. ULONG unused;
  111. PAGED_CODE();
  112. CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattAddDevice: Entered with pdo %x\n", Pdo));
  113. if (Pdo == NULL) {
  114. //
  115. // Have we been asked to do detection on our own?
  116. // if so just return no more devices
  117. //
  118. CmBattPrint((CMBATT_WARN | CMBATT_PNP), ("CmBattAddDevice: Asked to do detection\n"));
  119. return STATUS_NO_MORE_ENTRIES;
  120. }
  121. //
  122. // Get the software branch.
  123. //
  124. Status = IoOpenDeviceRegistryKey (Pdo,
  125. PLUGPLAY_REGKEY_DRIVER,
  126. STANDARD_RIGHTS_READ,
  127. &handle);
  128. if (!NT_SUCCESS(Status)) {
  129. CmBattPrint(CMBATT_ERROR, ("CmBattAddDevice: Could not get the software branch: %x\n", Status));
  130. return Status;
  131. }
  132. //
  133. // Check if this is for an AC adapter or a battery.
  134. //
  135. RtlInitUnicodeString (&unicodeString, PowerSourceType);
  136. Status = ZwQueryValueKey(
  137. handle,
  138. &unicodeString,
  139. KeyValuePartialInformation,
  140. buffer,
  141. sizeof(buffer),
  142. &unused
  143. );
  144. ZwClose( handle );
  145. if (!NT_SUCCESS(Status)) {
  146. CmBattPrint(CMBATT_ERROR, ("CmBattAddDevice: Could not read the power type identifier: %x\n", Status));
  147. } else {
  148. switch (*(PULONG)&((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data) {
  149. case POWER_SOURCE_TYPE_BATTERY:
  150. Status = CmBattAddBattery (DriverObject, Pdo);
  151. break;
  152. case POWER_SOURCE_TYPE_AC_ADAPTER:
  153. Status = CmBattAddAcAdapter (DriverObject, Pdo);
  154. break;
  155. default:
  156. CmBattPrint(CMBATT_ERROR, ("CmBattAddDevice: Invalid POWER_SOURCE_TYPE == %d \n", *(PULONG)&((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data));
  157. Status = STATUS_UNSUCCESSFUL;
  158. break;
  159. }
  160. }
  161. //
  162. // Return the status.
  163. //
  164. return Status;
  165. }
  166. NTSTATUS
  167. CmBattAddBattery(
  168. IN PDRIVER_OBJECT DriverObject,
  169. IN PDEVICE_OBJECT Pdo
  170. )
  171. /*++
  172. Routine Description:
  173. This routine creates a functional device object for a CM battery, and attache it
  174. to the physical device object for the battery.
  175. Arguments:
  176. DriverObject - a pointer to the object for this driver
  177. PhysicalDeviceObject - a pointer to the physical object we need to attach to
  178. Return Value:
  179. Status from device creation and initialization
  180. --*/
  181. {
  182. PDEVICE_OBJECT Fdo = NULL;
  183. PCM_BATT CmBatt;
  184. NTSTATUS Status;
  185. BATTERY_MINIPORT_INFO BattInit;
  186. PAGED_CODE();
  187. CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattAddBattery: pdo %x\n", Pdo));
  188. //
  189. // Create and initialize the new functional device object
  190. //
  191. Status = CmBattCreateFdo(DriverObject, Pdo, sizeof(CM_BATT), &Fdo);
  192. if (!NT_SUCCESS(Status)) {
  193. CmBattPrint(CMBATT_ERROR, ("CmBattAddBattery: error (0x%x) creating Fdo\n", Status));
  194. return Status;
  195. }
  196. //
  197. // Initialize Fdo device extension data
  198. //
  199. CmBatt = (PCM_BATT) Fdo->DeviceExtension;
  200. CmBatt->Type = CM_BATTERY_TYPE;
  201. CmBatt->IsStarted = FALSE;
  202. CmBatt->ReCheckSta = TRUE;
  203. InterlockedExchange (&CmBatt->CacheState, 0);
  204. CmBatt->Info.Tag = BATTERY_TAG_INVALID;
  205. CmBatt->Alarm.Setting = CM_ALARM_INVALID;
  206. CmBatt->DischargeTime = KeQueryInterruptTime();
  207. if (CmBattSetTripPpoint (CmBatt, 0) == STATUS_OBJECT_NAME_NOT_FOUND) {
  208. CmBatt->Info.BtpExists = FALSE;
  209. } else {
  210. CmBatt->Info.BtpExists = TRUE;
  211. }
  212. //
  213. // Attach to the Class Driver
  214. //
  215. RtlZeroMemory (&BattInit, sizeof(BattInit));
  216. BattInit.MajorVersion = BATTERY_CLASS_MAJOR_VERSION;
  217. BattInit.MinorVersion = BATTERY_CLASS_MINOR_VERSION;
  218. BattInit.Context = CmBatt;
  219. BattInit.QueryTag = CmBattQueryTag;
  220. BattInit.QueryInformation = CmBattQueryInformation;
  221. BattInit.SetInformation = NULL; // tbd
  222. BattInit.QueryStatus = CmBattQueryStatus;
  223. BattInit.SetStatusNotify = CmBattSetStatusNotify;
  224. BattInit.DisableStatusNotify = CmBattDisableStatusNotify;
  225. BattInit.Pdo = Pdo;
  226. BattInit.DeviceName = CmBatt->DeviceName;
  227. Status = BatteryClassInitializeDevice (&BattInit, &CmBatt->Class);
  228. if (!NT_SUCCESS(Status)) {
  229. //
  230. // if we can't attach to class driver we're toast
  231. //
  232. CmBattPrint(CMBATT_ERROR, ("CmBattAddBattery: error (0x%x) registering with class\n", Status));
  233. IoDetachDevice (CmBatt->LowerDeviceObject);
  234. CmBattDestroyFdo (CmBatt->Fdo);
  235. return Status;
  236. }
  237. //
  238. // Register WMI support.
  239. //
  240. Status = CmBattWmiRegistration(CmBatt);
  241. if (!NT_SUCCESS(Status)) {
  242. //
  243. // WMI support is not critical to operation. Just log an error.
  244. //
  245. CmBattPrint(CMBATT_ERROR,
  246. ("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status));
  247. }
  248. //
  249. // Register the battery notify handler for this battery with ACPI
  250. // This registration is performed after registering with the battery
  251. // class because CmBattNotifyHandler must not be run until the battery
  252. // class is ready.
  253. //
  254. Status = CmBatt->AcpiInterfaces.RegisterForDeviceNotifications (
  255. CmBatt->AcpiInterfaces.Context,
  256. CmBattNotifyHandler,
  257. CmBatt);
  258. if (!NT_SUCCESS(Status)) {
  259. CmBattPrint(CMBATT_ERROR,
  260. ("CmBattAddBattery: Could not register for battery notify, status = %Lx\n", Status));
  261. CmBattWmiDeRegistration(CmBatt);
  262. BatteryClassUnload (CmBatt->Class);
  263. IoDetachDevice (CmBatt->LowerDeviceObject);
  264. CmBattDestroyFdo (CmBatt->Fdo);
  265. return Status;
  266. }
  267. return STATUS_SUCCESS;
  268. }
  269. NTSTATUS
  270. CmBattAddAcAdapter(
  271. IN PDRIVER_OBJECT DriverObject,
  272. IN PDEVICE_OBJECT Pdo
  273. )
  274. /*++
  275. Routine Description:
  276. This routine registers a notify handler for the AC Adapter. And saves the PDO so we can run
  277. the _STA method against it to get the AC status.
  278. Arguments:
  279. DriverObject - a pointer to the object for this driver
  280. Pdo - a pointer to the Pdo
  281. Return Value:
  282. Status from device creation and initialization
  283. --*/
  284. {
  285. PDEVICE_OBJECT Fdo;
  286. NTSTATUS Status;
  287. PAC_ADAPTER acExtension;
  288. PAGED_CODE();
  289. CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattAddAcAdapter: pdo %x\n", Pdo));
  290. //
  291. // Save PDO so we can run _STA method on it later
  292. //
  293. if (AcAdapterPdo != NULL) {
  294. CmBattPrint(CMBATT_ERROR, ("CmBatt: Second AC adapter found. Current version of driver only supports 1 aadapter.\n"));
  295. } else {
  296. AcAdapterPdo = Pdo;
  297. }
  298. Status = CmBattCreateFdo(DriverObject, Pdo, sizeof(AC_ADAPTER), &Fdo);
  299. if (!NT_SUCCESS(Status)) {
  300. CmBattPrint(CMBATT_ERROR, ("CmBattAddAcAdapter: error (0x%x) creating Fdo\n", Status));
  301. return Status;
  302. }
  303. //
  304. // Initialize Fdo device extension data
  305. //
  306. acExtension = (PAC_ADAPTER) Fdo->DeviceExtension;
  307. acExtension->Type = AC_ADAPTER_TYPE;
  308. //
  309. // Register WMI support.
  310. //
  311. Status = CmBattWmiRegistration((PCM_BATT)acExtension);
  312. if (!NT_SUCCESS(Status)) {
  313. //
  314. // WMI support is not critical to operation. Just log an error.
  315. //
  316. CmBattPrint(CMBATT_ERROR,
  317. ("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status));
  318. }
  319. //
  320. // Register the AC adapter notify handler with ACPI
  321. //
  322. Status = acExtension->AcpiInterfaces.RegisterForDeviceNotifications (
  323. acExtension->AcpiInterfaces.Context,
  324. CmBattNotifyHandler,
  325. acExtension);
  326. //
  327. // We will ignore errors, since this is not a critical operation
  328. //
  329. if (!NT_SUCCESS(Status)) {
  330. CmBattPrint(CMBATT_ERROR,
  331. ("CmBattAddAcAdapter: Could not register for power notify, status = %Lx\n", Status));
  332. }
  333. //
  334. // Give one notification, to make sure all batteries get updated.
  335. //
  336. CmBattNotifyHandler (acExtension, BATTERY_STATUS_CHANGE);
  337. return STATUS_SUCCESS;
  338. }
  339. NTSTATUS
  340. CmBattGetAcpiInterfaces(
  341. IN PDEVICE_OBJECT LowerDevice,
  342. OUT PACPI_INTERFACE_STANDARD AcpiInterfaces
  343. )
  344. /*++
  345. Routine Description:
  346. Call ACPI driver to get the direct-call interfaces. It does
  347. this the first time it is called, no more.
  348. Arguments:
  349. None.
  350. Return Value:
  351. Status
  352. --*/
  353. {
  354. NTSTATUS Status = STATUS_SUCCESS;
  355. PIRP Irp;
  356. PIO_STACK_LOCATION IrpSp;
  357. KEVENT syncEvent;
  358. //
  359. // Allocate an IRP for below
  360. //
  361. Irp = IoAllocateIrp (LowerDevice->StackSize, FALSE); // Get stack size from PDO
  362. if (!Irp) {
  363. CmBattPrint((CMBATT_ERROR),
  364. ("CmBattGetAcpiInterfaces: Failed to allocate Irp\n"));
  365. return STATUS_INSUFFICIENT_RESOURCES;
  366. }
  367. IrpSp = IoGetNextIrpStackLocation(Irp);
  368. //
  369. // Use QUERY_INTERFACE to get the address of the direct-call ACPI interfaces.
  370. //
  371. IrpSp->MajorFunction = IRP_MJ_PNP;
  372. IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
  373. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  374. IrpSp->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_ACPI_INTERFACE_STANDARD;
  375. IrpSp->Parameters.QueryInterface.Version = 1;
  376. IrpSp->Parameters.QueryInterface.Size = sizeof (*AcpiInterfaces);
  377. IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE) AcpiInterfaces;
  378. IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  379. //
  380. // Initialize an event so this will be a syncronous call.
  381. //
  382. KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
  383. IoSetCompletionRoutine (Irp, CmBattIoCompletion, &syncEvent, TRUE, TRUE, TRUE);
  384. //
  385. // Call ACPI
  386. //
  387. Status = IoCallDriver (LowerDevice, Irp);
  388. //
  389. // Wait if necessary, then clean up.
  390. //
  391. if (Status == STATUS_PENDING) {
  392. KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
  393. Status = Irp->IoStatus.Status;
  394. }
  395. IoFreeIrp (Irp);
  396. if (!NT_SUCCESS(Status)) {
  397. CmBattPrint(CMBATT_ERROR,
  398. ("CmBattGetAcpiInterfaces: Could not get ACPI driver interfaces, status = %x\n", Status));
  399. }
  400. return Status;
  401. }
  402. NTSTATUS
  403. CmBattCreateFdo(
  404. IN PDRIVER_OBJECT DriverObject,
  405. IN PDEVICE_OBJECT Pdo,
  406. IN ULONG ExtensionSize,
  407. OUT PDEVICE_OBJECT *NewFdo
  408. )
  409. /*++
  410. Routine Description:
  411. This routine will create and initialize a functional device object to
  412. be attached to a Control Method Battery PDO.
  413. Arguments:
  414. DriverObject - a pointer to the driver object this is created under
  415. ExtensionSize - device extension size: sizeof (CM_BATT) or sizeof (AC_ADAPTER)
  416. NewFdo - a location to store the pointer to the new device object
  417. Return Value:
  418. STATUS_SUCCESS if everything was successful
  419. reason for failure otherwise
  420. --*/
  421. {
  422. PDEVICE_OBJECT fdo;
  423. NTSTATUS status;
  424. PCM_BATT cmBatt;
  425. ULONG uniqueId;
  426. USHORT strLength = 0;
  427. HANDLE devInstRegKey;
  428. UNICODE_STRING valueName;
  429. CHAR buffer [sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)];
  430. ULONG returnSize;
  431. PAGED_CODE();
  432. CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattCreateFdo: Entered\n"));
  433. //
  434. // Get the unique ID of this device by running the _UID method.
  435. // If this fails, assume one device.
  436. //
  437. status = CmBattGetUniqueId (Pdo, &uniqueId);
  438. if (!NT_SUCCESS(status)) {
  439. CmBattPrint(CMBATT_NOTE, ("CmBattCreateFdo: Error %x from _UID, assuming unit #0\n", status));
  440. uniqueId = 0;
  441. }
  442. //
  443. // Create the FDO
  444. //
  445. status = IoCreateDevice(
  446. DriverObject,
  447. ExtensionSize,
  448. NULL,
  449. FILE_DEVICE_BATTERY,
  450. FILE_DEVICE_SECURE_OPEN,
  451. FALSE,
  452. &fdo
  453. );
  454. if (status != STATUS_SUCCESS) {
  455. CmBattPrint(CMBATT_ERROR, ("CmBattCreateFdo: error (0x%x) creating device object\n", status));
  456. return(status);
  457. }
  458. fdo->Flags |= DO_BUFFERED_IO;
  459. fdo->Flags |= DO_POWER_PAGABLE; // Don't want power Irps at irql 2
  460. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  461. //
  462. // Initialize Fdo device extension data
  463. //
  464. cmBatt = (PCM_BATT) fdo->DeviceExtension;
  465. //
  466. // Note: This is note necessarily a battery. It could be an AC adapter, so only fields
  467. // common to both should be initialized here.
  468. //
  469. RtlZeroMemory(cmBatt, ExtensionSize);
  470. //CmBatt->Type must be initialized after this call.
  471. cmBatt->DeviceObject = fdo;
  472. cmBatt->Fdo = fdo;
  473. cmBatt->Pdo = Pdo;
  474. //
  475. // Connect to lower device
  476. //
  477. cmBatt->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, Pdo);
  478. if (!cmBatt->LowerDeviceObject) {
  479. CmBattPrint(CMBATT_ERROR, ("CmBattCreateFdo: IoAttachDeviceToDeviceStack failed.\n"));
  480. CmBattDestroyFdo (cmBatt->Fdo);
  481. return STATUS_UNSUCCESSFUL;
  482. }
  483. //
  484. // Get the direct-call ACPI interfaces
  485. //
  486. status = CmBattGetAcpiInterfaces (cmBatt->LowerDeviceObject, &cmBatt->AcpiInterfaces);
  487. if (!NT_SUCCESS(status)) {
  488. CmBattPrint(CMBATT_ERROR, ("CmBattCreateFdor: Could not get ACPI interfaces: %x\n", status));
  489. IoDetachDevice (cmBatt->LowerDeviceObject);
  490. CmBattDestroyFdo (cmBatt->Fdo);
  491. return status;
  492. }
  493. //
  494. // Initializes File handle tracking.
  495. //
  496. ExInitializeFastMutex (&cmBatt->OpenCloseMutex);
  497. cmBatt->OpenCount = 0;
  498. //
  499. // Removal lock initialization
  500. //
  501. cmBatt->WantToRemove = FALSE;
  502. cmBatt->InUseCount = 1;
  503. KeInitializeEvent(&cmBatt->ReadyToRemove, SynchronizationEvent, FALSE);
  504. cmBatt->DeviceNumber = uniqueId;
  505. cmBatt->DeviceName = NULL;
  506. cmBatt->Sleeping = FALSE;
  507. cmBatt->ActionRequired = CMBATT_AR_NO_ACTION;
  508. //
  509. // Determine if wake on Battery should be enabled
  510. //
  511. cmBatt->WakeEnabled = FALSE;
  512. status = IoOpenDeviceRegistryKey (Pdo,
  513. PLUGPLAY_REGKEY_DEVICE,
  514. STANDARD_RIGHTS_ALL,
  515. &devInstRegKey);
  516. if (NT_SUCCESS (status)) {
  517. RtlInitUnicodeString (&valueName, WaitWakeEnableKey);
  518. status = ZwQueryValueKey(
  519. devInstRegKey,
  520. &valueName,
  521. KeyValuePartialInformation,
  522. buffer,
  523. sizeof(buffer),
  524. &returnSize
  525. );
  526. if (NT_SUCCESS (status)) {
  527. cmBatt->WakeEnabled = (*(PULONG)((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data ? TRUE : FALSE);
  528. }
  529. ZwClose(devInstRegKey);
  530. }
  531. *NewFdo = fdo;
  532. CmBattPrint((CMBATT_TRACE | CMBATT_PNP), ("CmBattCreateFdo: Created FDO %x\n", fdo));
  533. return STATUS_SUCCESS;
  534. }
  535. VOID
  536. CmBattDestroyFdo(
  537. IN PDEVICE_OBJECT Fdo
  538. )
  539. /*++
  540. Routine Description:
  541. This routine will deallocate a functional device object.
  542. This includes calling IoDeleteDevice.
  543. Arguments:
  544. Fdo - a pointer to the FDO to destroy.
  545. Return Value:
  546. STATUS_SUCCESS if everything was successful
  547. reason for failure otherwise
  548. --*/
  549. {
  550. PAGED_CODE();
  551. CmBattPrint ((CMBATT_TRACE | CMBATT_PNP), ("CmBattDestroyFdo, Battery.\n"));
  552. IoDeleteDevice (Fdo);
  553. CmBattPrint((CMBATT_TRACE | CMBATT_PNP), ("CmBattDestroyFdo: done.\n"));
  554. }
  555. NTSTATUS
  556. CmBattPnpDispatch(
  557. IN PDEVICE_OBJECT DeviceObject,
  558. IN PIRP Irp
  559. )
  560. /*++
  561. Routine Description:
  562. This routine is the dispatch routine for plug and play requests.
  563. Arguments:
  564. DeviceObject - Pointer to class device object.
  565. Irp - Pointer to the request packet.
  566. Return Value:
  567. Status is returned.
  568. --*/
  569. {
  570. PIO_STACK_LOCATION irpStack;
  571. PCM_BATT CmBatt;
  572. NTSTATUS status;
  573. KEVENT syncEvent;
  574. PAGED_CODE();
  575. status = STATUS_NOT_SUPPORTED;
  576. //
  577. // Get a pointer to the current parameters for this request. The
  578. // information is contained in the current stack location.
  579. //
  580. irpStack = IoGetCurrentIrpStackLocation(Irp);
  581. CmBatt = DeviceObject->DeviceExtension;
  582. //
  583. // Aquire remove lock
  584. //
  585. InterlockedIncrement (&CmBatt->InUseCount);
  586. if (CmBatt->WantToRemove == TRUE) {
  587. //
  588. // Failed to acquire remove lock.
  589. //
  590. status = STATUS_DEVICE_REMOVED;
  591. } else {
  592. //
  593. // Remove lock acquired.
  594. //
  595. //
  596. // Dispatch minor function
  597. //
  598. switch (irpStack->MinorFunction) {
  599. case IRP_MN_START_DEVICE: {
  600. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_START_DEVICE\n"));
  601. if (CmBatt->Type == CM_BATTERY_TYPE) {
  602. //
  603. // We only want to handle batteries, not AC adapters.
  604. //
  605. CmBatt->IsStarted = TRUE;
  606. }
  607. status = STATUS_SUCCESS;
  608. break;
  609. } // IRP_MN_START_DEVICE
  610. case IRP_MN_STOP_DEVICE: {
  611. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_STOP_DEVICE\n"));
  612. if (CmBatt->Type == CM_BATTERY_TYPE) {
  613. CmBatt->IsStarted = FALSE;
  614. }
  615. status = STATUS_SUCCESS;
  616. break;
  617. } // IRP_MN_STOP_DEVICE
  618. case IRP_MN_REMOVE_DEVICE: {
  619. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_REMOVE_DEVICE\n"));
  620. status = CmBattRemoveDevice(DeviceObject, Irp);
  621. break;
  622. } // IRP_MN_REMOVE_DEVICE
  623. case IRP_MN_SURPRISE_REMOVAL: {
  624. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_SURPRISE_REMOVAL\n"));
  625. ExAcquireFastMutex (&CmBatt->OpenCloseMutex);
  626. status = STATUS_SUCCESS;
  627. CmBatt->OpenCount = (ULONG) -1;
  628. ExReleaseFastMutex (&CmBatt->OpenCloseMutex);
  629. break;
  630. } // IRP_MN_QUERY_REMOVE_DEVICE
  631. case IRP_MN_QUERY_REMOVE_DEVICE: {
  632. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_REMOVE_DEVICE\n"));
  633. ExAcquireFastMutex (&CmBatt->OpenCloseMutex);
  634. status = STATUS_SUCCESS;
  635. if (CmBatt->OpenCount == 0) {
  636. CmBatt->OpenCount = (ULONG) -1;
  637. } else if (CmBatt->OpenCount == (ULONG) -1) {
  638. CmBattPrint (CMBATT_WARN, ("CmBattPnpDispatch: Recieved two consecutive QUERY_REMOVE requests.\n"));
  639. } else {
  640. status = STATUS_UNSUCCESSFUL;
  641. }
  642. ExReleaseFastMutex (&CmBatt->OpenCloseMutex);
  643. break;
  644. } // IRP_MN_QUERY_REMOVE_DEVICE
  645. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  646. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
  647. ExAcquireFastMutex (&CmBatt->OpenCloseMutex);
  648. if (CmBatt->OpenCount == (ULONG) -1) {
  649. CmBatt->OpenCount = 0;
  650. } else {
  651. CmBattPrint (CMBATT_NOTE, ("CmBattPnpDispatch: Received CANCEL_REMOVE when OpenCount == %x\n",
  652. CmBatt->OpenCount));
  653. }
  654. status = STATUS_SUCCESS;
  655. ExReleaseFastMutex (&CmBatt->OpenCloseMutex);
  656. break;
  657. } // IRP_MN_CANCEL_REMOVE_DEVICE
  658. case IRP_MN_QUERY_STOP_DEVICE: {
  659. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_STOP_DEVICE\n"));
  660. status = STATUS_NOT_IMPLEMENTED;
  661. break;
  662. } // IRP_MN_QUERY_STOP_DEVICE
  663. case IRP_MN_CANCEL_STOP_DEVICE: {
  664. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_CANCEL_STOP_DEVICE\n"));
  665. status = STATUS_NOT_IMPLEMENTED;
  666. break;
  667. } // IRP_MN_CANCEL_STOP_DEVICE
  668. case IRP_MN_QUERY_PNP_DEVICE_STATE: {
  669. IoCopyCurrentIrpStackLocationToNext (Irp);
  670. KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
  671. IoSetCompletionRoutine(Irp, CmBattIoCompletion, &syncEvent, TRUE, TRUE, TRUE);
  672. status = IoCallDriver(CmBatt->LowerDeviceObject, Irp);
  673. if (status == STATUS_PENDING) {
  674. KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
  675. status = Irp->IoStatus.Status;
  676. }
  677. Irp->IoStatus.Information &= ~PNP_DEVICE_NOT_DISABLEABLE;
  678. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  679. if (0 == InterlockedDecrement(&CmBatt->InUseCount)) {
  680. KeSetEvent (&CmBatt->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  681. }
  682. return status;
  683. }
  684. case IRP_MN_QUERY_CAPABILITIES: {
  685. IoCopyCurrentIrpStackLocationToNext (Irp);
  686. KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
  687. IoSetCompletionRoutine(Irp, CmBattIoCompletion, &syncEvent, TRUE, TRUE, TRUE);
  688. status = IoCallDriver(CmBatt->LowerDeviceObject, Irp);
  689. if (status == STATUS_PENDING) {
  690. KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
  691. status = Irp->IoStatus.Status;
  692. }
  693. CmBatt->WakeSupportedState.SystemState = irpStack->Parameters.DeviceCapabilities.Capabilities->SystemWake;
  694. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES %d Capabilities->SystemWake = %x\n", CmBatt->Type, CmBatt->WakeSupportedState.SystemState));
  695. if (CmBatt->WakeSupportedState.SystemState != PowerSystemUnspecified) {
  696. if (CmBatt->WaitWakeIrp == NULL && CmBatt->WakeEnabled) {
  697. PoRequestPowerIrp(
  698. CmBatt->DeviceObject,
  699. IRP_MN_WAIT_WAKE,
  700. CmBatt->WakeSupportedState,
  701. CmBattWaitWakeLoop,
  702. NULL,
  703. &(CmBatt->WaitWakeIrp)
  704. );
  705. //
  706. // Ignore return value. Capbilities IRP should still succeed.
  707. //
  708. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES wait/Wake irp sent.\n"));
  709. }
  710. } else {
  711. CmBatt->WakeEnabled=FALSE;
  712. CmBattPrint (CMBATT_PNP, ("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES Wake not supported.\n"));
  713. }
  714. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  715. if (0 == InterlockedDecrement(&CmBatt->InUseCount)) {
  716. KeSetEvent (&CmBatt->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  717. }
  718. return status;
  719. }
  720. default: {
  721. //
  722. // Unimplemented minor, Pass this down
  723. //
  724. CmBattPrint (CMBATT_PNP,
  725. ("CmBattPnpDispatch: Unimplemented minor %0x\n", \
  726. irpStack->MinorFunction));
  727. } // default
  728. // Fall through...
  729. case IRP_MN_QUERY_RESOURCES:
  730. case IRP_MN_READ_CONFIG:
  731. case IRP_MN_WRITE_CONFIG:
  732. case IRP_MN_EJECT:
  733. case IRP_MN_SET_LOCK:
  734. case IRP_MN_QUERY_ID:
  735. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  736. break ;
  737. }
  738. }
  739. }
  740. //
  741. // Release remove lock
  742. //
  743. if (0 == InterlockedDecrement(&CmBatt->InUseCount)) {
  744. KeSetEvent (&CmBatt->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  745. }
  746. //
  747. // Only set status if we have something to add
  748. //
  749. if (status != STATUS_NOT_SUPPORTED) {
  750. Irp->IoStatus.Status = status;
  751. }
  752. //
  753. // Do we need to send it down?
  754. //
  755. if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
  756. CmBattCallLowerDriver(status, CmBatt->LowerDeviceObject, Irp);
  757. return status;
  758. }
  759. //
  760. // At this point, it must have been passed down and needs recompletion,
  761. // or the status is unsuccessful.
  762. //
  763. ASSERT(!NT_SUCCESS(status) && (status != STATUS_NOT_SUPPORTED));
  764. status = Irp->IoStatus.Status ;
  765. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  766. return status;
  767. }
  768. NTSTATUS
  769. CmBattRemoveDevice(
  770. IN PDEVICE_OBJECT DeviceObject,
  771. IN PIRP Irp
  772. )
  773. /*++
  774. Routine Description:
  775. This routine processes a IRP_MN_REMOVE_DEVICE
  776. Arguments:
  777. DeviceObject - Pointer to class device object.
  778. Irp - Pointer to the request packet.
  779. Return Value:
  780. Returns STATUS_SUCCESS. (This function must not fail.)
  781. --*/
  782. {
  783. PCM_BATT cmBatt;
  784. NTSTATUS status;
  785. cmBatt = (PCM_BATT) DeviceObject->DeviceExtension;
  786. CmBattPrint (CMBATT_TRACE, ("CmBattRemoveDevice: CmBatt (%x), Type %d, _UID %d\n",
  787. cmBatt, cmBatt->Type, cmBatt->DeviceNumber));
  788. //
  789. // Remove device syncronization
  790. //
  791. //
  792. // Prevent more locks from being acquired.
  793. //
  794. cmBatt->WantToRemove = TRUE;
  795. //
  796. // Release lock acquired at start of CmBattPnpDispatch
  797. //
  798. if (InterlockedDecrement (&cmBatt->InUseCount) <= 0) {
  799. CmBattPrint (CMBATT_ERROR, ("CmBattRemoveDevice: Remove lock error.\n"));
  800. ASSERT(FALSE);
  801. }
  802. //
  803. // Final release and wait.
  804. //
  805. // Note: there will be one more relase at the end of CmBattPnpDispatch
  806. // but it will decrement the InUseCount to -1 so it won't set the event.
  807. //
  808. if (InterlockedDecrement (&cmBatt->InUseCount) > 0) {
  809. KeWaitForSingleObject (&cmBatt->ReadyToRemove,
  810. Executive,
  811. KernelMode,
  812. FALSE,
  813. NULL
  814. );
  815. }
  816. //
  817. // Cancel the Wait/wake IRP;
  818. //
  819. if (cmBatt->WaitWakeIrp != NULL) {
  820. IoCancelIrp (cmBatt->WaitWakeIrp);
  821. cmBatt->WaitWakeIrp = NULL;
  822. }
  823. if (cmBatt->Type == CM_BATTERY_TYPE) {
  824. //
  825. // This is a control method battery FDO
  826. //
  827. //
  828. // Disconnect from receiving device (battery) notifications
  829. //
  830. cmBatt->AcpiInterfaces.UnregisterForDeviceNotifications (
  831. cmBatt->AcpiInterfaces.Context,
  832. CmBattNotifyHandler);
  833. //
  834. // Unregister as a WMI Provider.
  835. //
  836. CmBattWmiDeRegistration(cmBatt);
  837. //
  838. // Tell the class driver we are going away
  839. //
  840. status = BatteryClassUnload (cmBatt->Class);
  841. ASSERT (NT_SUCCESS(status));
  842. } else {
  843. //
  844. // This is an AC adapter FDO
  845. //
  846. //
  847. // Disconnect from receiving device (battery) notifications
  848. //
  849. cmBatt->AcpiInterfaces.UnregisterForDeviceNotifications (
  850. cmBatt->AcpiInterfaces.Context,
  851. CmBattNotifyHandler);
  852. //
  853. // Unregister as a WMI Provider.
  854. //
  855. CmBattWmiDeRegistration(cmBatt);
  856. AcAdapterPdo = NULL;
  857. }
  858. //
  859. // Clean up, delete the Fdo we created at AddDevice time
  860. //
  861. IoDetachDevice (cmBatt->LowerDeviceObject);
  862. IoDeleteDevice (cmBatt->DeviceObject);
  863. return STATUS_SUCCESS;
  864. }
  865. NTSTATUS
  866. CmBattPowerDispatch(
  867. IN PDEVICE_OBJECT DeviceObject,
  868. IN PIRP Irp
  869. )
  870. /*++
  871. Routine Description:
  872. This routine is the dispatch routine for power requests.
  873. Arguments:
  874. DeviceObject - Pointer to class device object.
  875. Irp - Pointer to the request packet.
  876. Return Value:
  877. Status is returned.
  878. --*/
  879. {
  880. PIO_STACK_LOCATION irpStack;
  881. PCM_BATT CmBatt;
  882. NTSTATUS Status;
  883. //
  884. // A remove lock is not needed in this dispatch function because
  885. // all data accessed is in the device extension. If any other functionality
  886. // was added to this routine, a remove lock might be neccesary.
  887. //
  888. CmBattPrint ((CMBATT_TRACE | CMBATT_POWER), ("CmBattPowerDispatch\n"));
  889. //
  890. // Get a pointer to the current parameters for this request. The
  891. // information is contained in the current stack location.
  892. //
  893. irpStack = IoGetCurrentIrpStackLocation(Irp);
  894. CmBatt = DeviceObject->DeviceExtension;
  895. //
  896. // Dispatch minor function
  897. //
  898. switch (irpStack->MinorFunction) {
  899. case IRP_MN_WAIT_WAKE: {
  900. CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_WAIT_WAKE\n"));
  901. break;
  902. }
  903. case IRP_MN_POWER_SEQUENCE: {
  904. CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n"));
  905. break;
  906. }
  907. case IRP_MN_SET_POWER: {
  908. CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_SET_POWER type: %d, State: %d \n",
  909. irpStack->Parameters.Power.Type,
  910. irpStack->Parameters.Power.State));
  911. break;
  912. }
  913. case IRP_MN_QUERY_POWER: {
  914. CmBattPrint (CMBATT_POWER, ("CmBattPowerDispatch: IRP_MN_QUERY_POWER\n"));
  915. break;
  916. }
  917. default: {
  918. CmBattPrint(CMBATT_LOW, ("CmBattPowerDispatch: minor %d\n",
  919. irpStack->MinorFunction));
  920. break;
  921. }
  922. }
  923. //
  924. // What do we do with the irp?
  925. //
  926. PoStartNextPowerIrp( Irp );
  927. if (CmBatt->LowerDeviceObject != NULL) {
  928. //
  929. // Forward the request along
  930. //
  931. IoSkipCurrentIrpStackLocation( Irp );
  932. Status = PoCallDriver( CmBatt->LowerDeviceObject, Irp );
  933. } else {
  934. //
  935. // Complete the request with the current status
  936. //
  937. Status = Irp->IoStatus.Status;
  938. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  939. }
  940. return Status;
  941. }
  942. NTSTATUS
  943. CmBattForwardRequest(
  944. IN PDEVICE_OBJECT DeviceObject,
  945. IN PIRP Irp
  946. )
  947. /*++
  948. Routine Description:
  949. This routine passes the request down the stack
  950. Arguments:
  951. DeviceObject - The target
  952. Irp - The request
  953. Return Value:
  954. NTSTATUS
  955. --*/
  956. {
  957. NTSTATUS status;
  958. PCM_BATT cmBatt = DeviceObject->DeviceExtension;
  959. //
  960. // A remove lock is not needed in this dispatch function because
  961. // all data accessed is in the device extension. If any other functionality was
  962. // added to this routine, a remove lock might be neccesary.
  963. //
  964. if (cmBatt->LowerDeviceObject != NULL) {
  965. IoSkipCurrentIrpStackLocation( Irp );
  966. status = IoCallDriver( cmBatt->LowerDeviceObject, Irp );
  967. } else {
  968. Irp->IoStatus.Status = status = STATUS_NOT_SUPPORTED;
  969. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  970. }
  971. return status;
  972. }
  973. NTSTATUS
  974. CmBattWaitWakeLoop(
  975. IN PDEVICE_OBJECT DeviceObject,
  976. IN UCHAR MinorFunction,
  977. IN POWER_STATE PowerState,
  978. IN PVOID Context,
  979. IN PIO_STATUS_BLOCK IoStatus
  980. )
  981. /*++
  982. Routine Description:
  983. This routine is called after the WAIT_WAKE has been completed
  984. Arguments:
  985. DeviceObject - The PDO
  986. MinorFunction - IRP_MN_WAIT_WAKE
  987. PowerState - The Sleep state that it could wake from
  988. Context - NOT USED
  989. IoStatus - The status of the request
  990. Return Value:
  991. NTSTATUS
  992. --*/
  993. {
  994. NTSTATUS status;
  995. PCM_BATT cmBatt = (PCM_BATT) DeviceObject->DeviceExtension;
  996. CmBattPrint (CMBATT_PNP, ("CmBattWaitWakeLoop: Entered.\n"));
  997. if (!NT_SUCCESS(IoStatus->Status) || !cmBatt->WakeEnabled) {
  998. CmBattPrint (CMBATT_ERROR, ("CmBattWaitWakeLoop: failed: status = 0x%08x.\n", IoStatus->Status));
  999. cmBatt->WaitWakeIrp = NULL;
  1000. return IoStatus->Status;
  1001. } else {
  1002. CmBattPrint (CMBATT_NOTE, ("CmBattWaitWakeLoop: completed successfully\n"));
  1003. }
  1004. //
  1005. // In this case, we just cause the same thing to happen again
  1006. //
  1007. status = PoRequestPowerIrp(
  1008. DeviceObject,
  1009. MinorFunction,
  1010. PowerState,
  1011. CmBattWaitWakeLoop,
  1012. Context,
  1013. &(cmBatt->WaitWakeIrp)
  1014. );
  1015. CmBattPrint (CMBATT_NOTE, ("CmBattWaitWakeLoop: PoRequestPowerIrp: status = 0x%08x.\n", status));
  1016. //
  1017. // Done
  1018. //
  1019. return STATUS_SUCCESS;
  1020. }