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

922 lines
28 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. battc.c
  5. Abstract:
  6. Battery Class Driver
  7. Author:
  8. Ken Reneris
  9. Environment:
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "battcp.h"
  14. #include <initguid.h>
  15. #include <batclass.h>
  16. WMIGUIDREGINFO BattWmiGuidList[BattWmiTotalGuids] =
  17. {
  18. {
  19. &BATTERY_STATUS_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  20. },
  21. {
  22. &BATTERY_RUNTIME_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  23. },
  24. {
  25. &BATTERY_TEMPERATURE_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  26. },
  27. {
  28. &BATTERY_FULL_CHARGED_CAPACITY_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  29. },
  30. {
  31. &BATTERY_CYCLE_COUNT_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  32. },
  33. {
  34. &BATTERY_STATIC_DATA_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  35. },
  36. {
  37. &BATTERY_STATUS_CHANGE_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  38. },
  39. {
  40. &BATTERY_TAG_CHANGE_WMI_GUID, 1, WMIREG_FLAG_INSTANCE_PDO
  41. }
  42. };
  43. //
  44. // Prototypes
  45. //
  46. NTSTATUS
  47. DriverEntry (
  48. IN PDRIVER_OBJECT DriverObject,
  49. IN PUNICODE_STRING RegistryPath
  50. );
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text(PAGE,DriverEntry)
  53. #pragma alloc_text(PAGE,BatteryClassInitializeDevice)
  54. #pragma alloc_text(PAGE,BatteryClassUnload)
  55. #pragma alloc_text(PAGE,BatteryClassIoctl)
  56. #endif
  57. #if DEBUG
  58. #if DBG
  59. ULONG BattDebug = BATT_ERROR|BATT_WARN;
  60. #else
  61. ULONG BattDebug = 0x0;
  62. #endif
  63. ULONG NextDeviceNum = 0; // Used to assign a unique number to each device for debugging.
  64. #endif
  65. NTSTATUS
  66. DriverEntry (
  67. IN PDRIVER_OBJECT DriverObject,
  68. IN PUNICODE_STRING RegistryPath
  69. )
  70. {
  71. return STATUS_SUCCESS;
  72. }
  73. NTSTATUS
  74. BATTERYCLASSAPI
  75. BatteryClassInitializeDevice (
  76. IN PBATTERY_MINIPORT_INFO MiniportInfo,
  77. IN PVOID *ClassData
  78. )
  79. /*++
  80. Routine Description:
  81. Initializes a new battery class device.
  82. N.B. The caller needs to reserve 1 IRP stack location for the
  83. battery class driver
  84. Arguments:
  85. MiniportInfo - Pointer to registration structure for driver
  86. registering as a battery miniport
  87. ClassData - Returned battery class handle for use by the
  88. miniport when invoking furture battery class functions
  89. Return Value:
  90. On sucess the battery has been registered.
  91. --*/
  92. {
  93. PBATT_NP_INFO BattNPInfo;
  94. PBATT_INFO BattInfo;
  95. NTSTATUS status = STATUS_SUCCESS;
  96. PAGED_CODE();
  97. #if DEBUG
  98. if (MiniportInfo->DeviceName && MiniportInfo->DeviceName->Buffer) {
  99. BattPrint ((BATT_TRACE), ("BattC (%d): InitializeDevice (Pdo = 0x%08lx) (DeviceName = %ws)\n", NextDeviceNum, MiniportInfo->Pdo, MiniportInfo->DeviceName->Buffer));
  100. } else {
  101. BattPrint ((BATT_TRACE), ("BattC (%d): InitializeDevice (Pdo = 0x%08lx)\n", NextDeviceNum, MiniportInfo->Pdo));
  102. }
  103. #endif
  104. if (MiniportInfo->MajorVersion != BATTERY_CLASS_MAJOR_VERSION) {
  105. return STATUS_REVISION_MISMATCH;
  106. }
  107. //
  108. // Allocate space for the class info to be kept with this device instance
  109. //
  110. BattNPInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(BATT_NP_INFO), 'ttaB');
  111. if (!BattNPInfo) {
  112. return STATUS_INSUFFICIENT_RESOURCES;
  113. }
  114. BattInfo = ExAllocatePoolWithTag(PagedPool, sizeof(BATT_INFO), 'ttaB');
  115. if (!BattInfo) {
  116. ExFreePool (BattNPInfo);
  117. return STATUS_INSUFFICIENT_RESOURCES;
  118. }
  119. RtlZeroMemory (BattNPInfo, sizeof(*BattNPInfo));
  120. RtlZeroMemory (BattInfo, sizeof(*BattInfo));
  121. //
  122. // Capture Miniport info
  123. //
  124. RtlCopyMemory (&BattInfo->Mp, MiniportInfo, sizeof(*MiniportInfo));
  125. //
  126. // Initilize class driver values
  127. //
  128. KeInitializeTimer (&BattNPInfo->WorkerTimer);
  129. KeInitializeTimer (&BattNPInfo->TagTimer);
  130. KeInitializeDpc (&BattNPInfo->WorkerDpc, BattCWorkerDpc, BattNPInfo);
  131. KeInitializeDpc (&BattNPInfo->TagDpc, BattCTagDpc, BattNPInfo);
  132. ExInitializeWorkItem (&BattNPInfo->WorkerThread, BattCWorkerThread, BattNPInfo);
  133. ExInitializeFastMutex (&BattNPInfo->Mutex);
  134. BattNPInfo->TagNotified = TRUE;
  135. BattNPInfo->StatusNotified = TRUE;
  136. BattNPInfo->BattInfo = BattInfo;
  137. #if DEBUG
  138. BattInfo->BattNPInfo = BattNPInfo;
  139. #endif
  140. BattInfo->Tag = BATTERY_TAG_INVALID;
  141. InitializeListHead (&BattInfo->IoQueue);
  142. InitializeListHead (&BattInfo->StatusQueue);
  143. InitializeListHead (&BattInfo->TagQueue);
  144. InitializeListHead (&BattInfo->WmiQueue);
  145. //
  146. // Removal lock initialization
  147. //
  148. BattNPInfo->WantToRemove = FALSE;
  149. //
  150. // InUseCount is set to 2. 1 lock is always held until the removal time.
  151. // 1 additional lock is held for the worker thread which only releases it
  152. // at removal time. Rather than aquiring and releasing each time, it just
  153. // checks WantToRemove to determine if it should release the lock.
  154. //
  155. BattNPInfo->InUseCount = 2;
  156. KeInitializeEvent(&BattNPInfo->ReadyToRemove, SynchronizationEvent, FALSE);
  157. #if DEBUG // Set device Number for debug prints.
  158. BattNPInfo->DeviceNum = NextDeviceNum;
  159. NextDeviceNum++;
  160. #endif
  161. *ClassData = BattNPInfo;
  162. //
  163. // Check to see if this is a battery other than the composite
  164. //
  165. if (MiniportInfo->Pdo) {
  166. // Blank UNICODE_STRING so IoRegisterDeviceInterface will allocate space.
  167. RtlInitUnicodeString (&BattInfo->SymbolicLinkName, NULL);
  168. //
  169. // Create the symbolic link
  170. //
  171. status = IoRegisterDeviceInterface(
  172. MiniportInfo->Pdo,
  173. (LPGUID)&GUID_DEVICE_BATTERY,
  174. NULL,
  175. &BattInfo->SymbolicLinkName);
  176. if (NT_SUCCESS(status)) {
  177. //
  178. // Now set the symbolic link for the association and store it..
  179. //
  180. BattPrint ((BATT_NOTE), ("BattC (%d): Making SetDeviceInterfaceState call.\n", BattNPInfo->DeviceNum));
  181. status = IoSetDeviceInterfaceState(&BattInfo->SymbolicLinkName, TRUE);
  182. if (status == STATUS_OBJECT_NAME_EXISTS) {
  183. // The device interface was already enabled. Continue anyway.
  184. BattPrint ((BATT_WARN), ("BattC (%d): Got STATUS_OBJECT_NAME_EXISTS for SetDeviceInterfaceState\n", BattNPInfo->DeviceNum));
  185. status = STATUS_SUCCESS;
  186. }
  187. }
  188. }
  189. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassInitializeDevice (status = 0x%08lx).\n", BattNPInfo->DeviceNum, status));
  190. return status;
  191. } // BatteryClassInitializeDevice
  192. NTSTATUS
  193. BATTERYCLASSAPI
  194. BatteryClassUnload (
  195. IN PVOID ClassData
  196. )
  197. /*++
  198. Routine Description:
  199. Called by the miniport when it has received a remove request.
  200. The miniclass driver must syncronize itself so that this API is
  201. not called while any of the others are not yet completed.
  202. Arguments:
  203. ClassData - Handle to class driver
  204. Return Value:
  205. This routine must not fail. It returns STATUS_SUCCESS
  206. --*/
  207. {
  208. NTSTATUS status;
  209. PBATT_INFO BattInfo;
  210. PBATT_NP_INFO BattNPInfo;
  211. PAGED_CODE();
  212. BattNPInfo = (PBATT_NP_INFO) ClassData;
  213. BattInfo = BattNPInfo->BattInfo;
  214. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassUnload called.\n", BattNPInfo->DeviceNum));
  215. //
  216. // Disable the symbolic link
  217. //
  218. ASSERT(BattInfo->SymbolicLinkName.Buffer);
  219. status = IoSetDeviceInterfaceState(&BattInfo->SymbolicLinkName, FALSE);
  220. if (!NT_SUCCESS(status)) {
  221. BattPrint (BATT_ERROR, ("BattC (%d) Unload: IoSetDeviceInterface returned 0x%08lx\n", BattNPInfo->DeviceNum, status));
  222. }
  223. //
  224. // Syncronization with the worker thread.
  225. // We can't return because the worker may be in the middle of something.
  226. // By returning, the battery class driver gives up the right to call miniport routines.
  227. //
  228. // This needs to be done before canceling the timers so that the worker
  229. // thread doesn't reset them.
  230. //
  231. BattNPInfo->WantToRemove = TRUE;
  232. //
  233. // Cancel timers
  234. // If a timer had been waiting,we need to release the remove lock that was
  235. // aquired before the timer was set since it will not be released in the DPC.
  236. //
  237. if (KeCancelTimer (&BattNPInfo->WorkerTimer)) {
  238. // Release Removal Lock
  239. // "InUseCount can never be 0 after this operation.
  240. InterlockedDecrement(&BattNPInfo->InUseCount);
  241. BattPrint ((BATT_LOCK), ("BatteryClassUnload: Released WorkerTimer remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  242. }
  243. if (KeCancelTimer (&BattNPInfo->TagTimer)) {
  244. // Release Removal Lock
  245. // "InUseCount can never be 0 after this operation.
  246. InterlockedDecrement(&BattNPInfo->InUseCount);
  247. BattPrint ((BATT_LOCK), ("BatteryClassUnload: Released TagTimer remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  248. }
  249. //
  250. // Queue the worker thread once more to make sure that the remove lock for
  251. // the worker thread is released.
  252. //
  253. BattCQueueWorker (BattNPInfo, FALSE);
  254. // Finish syncronization
  255. if (InterlockedDecrement (&BattNPInfo->InUseCount) > 0) {
  256. KeWaitForSingleObject (&BattNPInfo->ReadyToRemove,
  257. Executive,
  258. KernelMode,
  259. FALSE,
  260. NULL
  261. );
  262. }
  263. BattPrint ((BATT_LOCK), ("BatteryClassUnload: Done waiting for remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  264. //
  265. // Free Structures
  266. //
  267. ExFreePool (BattInfo->SymbolicLinkName.Buffer);
  268. ExFreePool (BattInfo);
  269. ExFreePool (BattNPInfo);
  270. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassUnload returning.\n", BattNPInfo->DeviceNum));
  271. return STATUS_SUCCESS;
  272. }
  273. NTSTATUS
  274. BATTERYCLASSAPI
  275. BatteryClassIoctl (
  276. IN PVOID ClassData,
  277. IN PIRP Irp
  278. )
  279. /*++
  280. Routine Description:
  281. Called by the miniport to handle battery ioctl requests. If handled,
  282. the battery class driver owns the IRP. If not handled, it belongs to
  283. the caller.
  284. Arguments:
  285. ClassData - Handle to class driver
  286. Irp - ICOTL irp to check
  287. Return Value:
  288. If handled, the battery class driver owns the IRP and will complete it
  289. once its handled; otherwise, the error STATUS_NOT_SUPPORTED is returned.
  290. --*/
  291. {
  292. NTSTATUS status;
  293. PBATT_INFO BattInfo;
  294. PBATT_NP_INFO BattNPInfo;
  295. PIO_STACK_LOCATION IrpSp;
  296. PAGED_CODE();
  297. BattNPInfo = (PBATT_NP_INFO) ClassData;
  298. BattInfo = BattNPInfo->BattInfo;
  299. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassIoctl called.\n", BattNPInfo->DeviceNum));
  300. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  301. //
  302. // Assume it's not our IRP
  303. //
  304. status = STATUS_NOT_SUPPORTED;
  305. //
  306. // Check IOCTL code to see if it's our IRP
  307. //
  308. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  309. case IOCTL_BATTERY_QUERY_TAG:
  310. case IOCTL_BATTERY_QUERY_INFORMATION:
  311. case IOCTL_BATTERY_SET_INFORMATION:
  312. case IOCTL_BATTERY_QUERY_STATUS:
  313. //
  314. // Acquire remove lock.
  315. // We don't want to queue anything more if we're being removed.
  316. //
  317. InterlockedIncrement (&BattNPInfo->InUseCount);
  318. BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  319. if (BattNPInfo->WantToRemove == TRUE) {
  320. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  321. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  322. }
  323. BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  324. status = STATUS_DEVICE_REMOVED;
  325. } else {
  326. //
  327. // Irp to handle. Put it in the queue worker threads list
  328. //
  329. status = STATUS_PENDING;
  330. Irp->IoStatus.Status = STATUS_PENDING;
  331. IoMarkIrpPending (Irp);
  332. ExAcquireFastMutex (&BattNPInfo->Mutex);
  333. InsertTailList (&BattInfo->IoQueue, &Irp->Tail.Overlay.ListEntry);
  334. ExReleaseFastMutex (&BattNPInfo->Mutex);
  335. BattCQueueWorker (BattNPInfo, FALSE);
  336. //
  337. // Release Remove Lock.
  338. //
  339. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  340. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  341. }
  342. BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  343. }
  344. break;
  345. default:
  346. BattPrint ((BATT_ERROR|BATT_IOCTL),
  347. ("BattC (%d): unknown battery ioctl - %x\n",
  348. BattNPInfo->DeviceNum,
  349. IrpSp->Parameters.DeviceIoControl.IoControlCode));
  350. break;
  351. }
  352. if ((status != STATUS_PENDING) && (status != STATUS_NOT_SUPPORTED)) {
  353. Irp->IoStatus.Status = status;
  354. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  355. }
  356. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassIoctl returning (status = 0x%08lx).\n", BattNPInfo->DeviceNum, status));
  357. return status;
  358. }
  359. NTSTATUS
  360. BATTERYCLASSAPI
  361. BatteryClassStatusNotify (
  362. IN PVOID ClassData
  363. )
  364. /*++
  365. Routine Description:
  366. Called by the miniport to signify that something interesting concerning
  367. the battery status has occured. Calling this function will cause the
  368. battery class driver to obtain the battery status if there are any pending
  369. status requests pending.
  370. If the miniport supports SetNotify from the class driver, then the miniport
  371. only needs to call this function once when the notification crtierea is
  372. met.
  373. If the miniport does not support SetNotify from the class driver, then
  374. the class driver will poll (at a slow rate) but the miniport should still
  375. call this function at least when the batteries power status changes such
  376. that timely updates of at least the power status will occur in the UI.
  377. Arguments:
  378. ClassData - Handle to class driver
  379. Return Value:
  380. Status
  381. --*/
  382. {
  383. PBATT_NP_INFO BattNPInfo;
  384. BattNPInfo = (PBATT_NP_INFO) ClassData;
  385. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassStatusNotify called\n", BattNPInfo->DeviceNum));
  386. InterlockedExchange (&BattNPInfo->StatusNotified, 1);
  387. InterlockedExchange (&BattNPInfo->TagNotified, 1);
  388. BattCQueueWorker (BattNPInfo, TRUE);
  389. return STATUS_SUCCESS;
  390. }
  391. NTSTATUS
  392. BATTERYCLASSAPI
  393. BatteryClassSystemControl (
  394. IN PVOID ClassData,
  395. IN PWMILIB_CONTEXT WmiLibContext,
  396. IN PDEVICE_OBJECT DeviceObject,
  397. IN PIRP Irp,
  398. OUT PSYSCTL_IRP_DISPOSITION Disposition
  399. )
  400. /*++
  401. Routine Description:
  402. The miniport driver calls this instead of WmiSystemControl.
  403. Arguments:
  404. ClassData - Handle to class driver
  405. The other parameters are the parameters for WmiSystemControl.
  406. Return Value:
  407. STATUS_SUCCESS or one of the following error codes:
  408. STATUS_INVALID_DEVICE_REQUEST
  409. STATUS_WMI_GUID_NOT_FOUND
  410. STATUS_WMI_INSTANCE_NOT_FOUND
  411. --*/
  412. {
  413. NTSTATUS status = STATUS_NOT_SUPPORTED;
  414. PBATT_INFO BattInfo;
  415. PBATT_NP_INFO BattNPInfo;
  416. PIO_STACK_LOCATION IrpSp;
  417. PAGED_CODE();
  418. BattNPInfo = (PBATT_NP_INFO) ClassData;
  419. BattInfo = BattNPInfo->BattInfo;
  420. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  421. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassSystemControl called.\n", BattNPInfo->DeviceNum));
  422. //
  423. // Initialize the WmiLibContext structure if this is the first time.
  424. //
  425. if (BattInfo->WmiLibContext.GuidCount == 0) {
  426. RtlCopyMemory(&BattInfo->WmiLibContext,
  427. WmiLibContext,
  428. sizeof(*WmiLibContext));
  429. BattInfo->WmiLibContext.GuidCount = WmiLibContext->GuidCount + BattWmiTotalGuids;
  430. BattInfo->WmiGuidIndex = WmiLibContext->GuidCount;
  431. BattInfo->WmiLibContext.GuidList = ExAllocatePoolWithTag(PagedPool, BattInfo->WmiLibContext.GuidCount * sizeof(WMIGUIDREGINFO), 'ttaB');
  432. if (!BattInfo->WmiLibContext.GuidList) {
  433. //
  434. // Figure out how to fail gracefully.
  435. //
  436. }
  437. RtlCopyMemory(BattInfo->WmiLibContext.GuidList,
  438. WmiLibContext->GuidList,
  439. WmiLibContext->GuidCount * sizeof(WMIGUIDREGINFO));
  440. RtlCopyMemory(&BattInfo->WmiLibContext.GuidList [WmiLibContext->GuidCount],
  441. BattWmiGuidList, BattWmiTotalGuids * sizeof(WMIGUIDREGINFO));
  442. }
  443. //
  444. // Acquire remove lock.
  445. // We don't want to queue anything more if we're being removed.
  446. //
  447. InterlockedIncrement (&BattNPInfo->InUseCount);
  448. BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  449. if (BattNPInfo->WantToRemove == TRUE) {
  450. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  451. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  452. }
  453. BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  454. status = STATUS_DEVICE_REMOVED;
  455. } else {
  456. status = WmiSystemControl(&BattInfo->WmiLibContext,
  457. DeviceObject,
  458. Irp,
  459. Disposition);
  460. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Returned from WmiSystemControl (status = 0x%08x).\n", BattNPInfo->DeviceNum, status));
  461. //
  462. // For IRP_MN_REGINFO BattC needs to add additional data to the IRP
  463. // about the battery class MOF resource.
  464. //
  465. if ((*Disposition == IrpNotCompleted) &&
  466. ((IrpSp->MinorFunction == IRP_MN_REGINFO) ||
  467. (IrpSp->MinorFunction == IRP_MN_REGINFO_EX)) &&
  468. (IrpSp->Parameters.WMI.DataPath == WMIREGISTER)) {
  469. //
  470. // Original structure
  471. //
  472. PWMIREGINFO regInfoPtr = IrpSp->Parameters.WMI.Buffer;
  473. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Adding Resource.\n", BattNPInfo->DeviceNum));
  474. //
  475. // If WmiSystemControl returned STATUS_BUFFER_TOO_SMALL or entered
  476. // the correct size as a ULONG in IoStatus.Information.
  477. // Increase the required size to accomodate battery class data
  478. // before returning
  479. //
  480. if (Irp->IoStatus.Information == sizeof(ULONG) ||
  481. Irp->IoStatus.Status == STATUS_BUFFER_TOO_SMALL) {
  482. //
  483. // Aditional battery class data includes one WMIREGINFO structure
  484. // Followed strings for the regstry path and resource name.
  485. // (Plus two WCHARS because these need to be counted strings.)
  486. // Round this up to the nearest 8 bytes.
  487. //
  488. regInfoPtr->BufferSize =
  489. (regInfoPtr->BufferSize +
  490. sizeof(WMIREGINFO) +
  491. sizeof(MOFREGISTRYPATH) +
  492. sizeof(MOFRESOURCENAME) + 2 * sizeof(WCHAR) + 7) & 0xFFFFFFF8;
  493. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Buffer Too Small:\n"
  494. " Information = %08x\n"
  495. " BufferSize = %08x\n"
  496. " NewSize = %08x\n",
  497. BattNPInfo->DeviceNum,
  498. Irp->IoStatus.Information,
  499. IrpSp->Parameters.WMI.BufferSize,
  500. regInfoPtr->BufferSize));
  501. //
  502. // Make sure IRP is set up to fail correctly.
  503. //
  504. Irp->IoStatus.Information = sizeof(ULONG);
  505. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  506. status = STATUS_BUFFER_TOO_SMALL;
  507. } else {
  508. ULONG size;
  509. PWCHAR tempString;
  510. //
  511. // Assume that there is only one WmiRegInfo Structure so far.
  512. //
  513. ASSERT (regInfoPtr->NextWmiRegInfo == 0);
  514. regInfoPtr->NextWmiRegInfo = (regInfoPtr->BufferSize + 7) & 0xFFFFFFF8;
  515. size = regInfoPtr->NextWmiRegInfo + sizeof(WMIREGINFO) +
  516. sizeof(MOFRESOURCENAME) + sizeof(MOFREGISTRYPATH) + 2 * sizeof(WCHAR);
  517. //
  518. // Set BufferSize Whether we succeed or not.
  519. //
  520. ((PWMIREGINFO)IrpSp->Parameters.WMI.Buffer)->BufferSize = size;
  521. if (size > IrpSp->Parameters.WMI.BufferSize) {
  522. //
  523. // If WmiSystemControl was successful, but there isnt room
  524. // for the extra data, this request needs to fail
  525. //
  526. Irp->IoStatus.Information = sizeof(ULONG);
  527. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  528. status = STATUS_BUFFER_TOO_SMALL;
  529. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Buffer Too Small.\n"
  530. " BufferSize = %08x\n"
  531. " Size = %08x\n",
  532. BattNPInfo->DeviceNum,
  533. IrpSp->Parameters.WMI.BufferSize,
  534. size));
  535. } else {
  536. Irp->IoStatus.Information = size;
  537. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Munging Structures:\n"
  538. " Buffer = %08x\n"
  539. " temp = %08x\n",
  540. BattNPInfo->DeviceNum,
  541. (ULONG_PTR) IrpSp->Parameters.WMI.Buffer,
  542. (ULONG_PTR) regInfoPtr));
  543. //
  544. // Intialize new structure
  545. //
  546. // Set teporary pointer to point at data structure we are adding.
  547. (ULONG_PTR)regInfoPtr += (ULONG_PTR)regInfoPtr->NextWmiRegInfo;
  548. regInfoPtr->BufferSize = sizeof(WMIREGINFO) +
  549. sizeof(MOFRESOURCENAME) +
  550. sizeof(MOFREGISTRYPATH) + 2 * sizeof(WCHAR);
  551. regInfoPtr->NextWmiRegInfo = 0;
  552. // Initialize RegistryPath counted string.
  553. regInfoPtr->RegistryPath = sizeof(WMIREGINFO);
  554. tempString = (PWCHAR)((ULONG_PTR)regInfoPtr + sizeof(WMIREGINFO));
  555. *tempString++ = sizeof(MOFREGISTRYPATH);
  556. RtlCopyMemory(tempString, MOFREGISTRYPATH, sizeof(MOFREGISTRYPATH));
  557. // Initialize MofResourceName counted string.
  558. regInfoPtr->MofResourceName = sizeof(WMIREGINFO) + sizeof(MOFREGISTRYPATH) + sizeof(WCHAR);
  559. tempString = (PWCHAR)((ULONG_PTR)regInfoPtr + regInfoPtr->MofResourceName);
  560. *tempString++ = sizeof(MOFRESOURCENAME);
  561. RtlCopyMemory(tempString, MOFRESOURCENAME, sizeof(MOFRESOURCENAME));
  562. regInfoPtr->GuidCount = 0;
  563. }
  564. }
  565. }
  566. //
  567. // Release Remove Lock.
  568. //
  569. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  570. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  571. }
  572. BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  573. }
  574. return status;
  575. }
  576. NTSTATUS
  577. BATTERYCLASSAPI
  578. BatteryClassQueryWmiDataBlock(
  579. IN PVOID ClassData,
  580. IN PDEVICE_OBJECT DeviceObject,
  581. IN PIRP Irp,
  582. IN ULONG GuidIndex,
  583. IN OUT PULONG InstanceLengthArray,
  584. IN ULONG OutBufferSize,
  585. OUT PUCHAR Buffer
  586. )
  587. /*++
  588. Routine Description:
  589. This routine is a callback into the driver to query for the contents of
  590. a data block. When the driver has finished filling the data block it
  591. must call WmiCompleteRequest to complete the irp. The driver can
  592. return STATUS_PENDING if the irp cannot be completed immediately.
  593. Arguments:
  594. DeviceObject is the device whose data block is being queried
  595. Irp is the Irp that makes this request
  596. GuidIndex is the index into the list of guids provided when the
  597. device registered
  598. InstanceLengthArray is a pointer to an array of ULONG that returns the
  599. lengths of each instance of the data block. If this is NULL then
  600. there was not enough space in the output buffer to fulfill the request
  601. so the irp should be completed with the buffer needed.
  602. BufferAvail on has the maximum size available to write the data
  603. block.
  604. Buffer on return is filled with the returned data block
  605. Return Value:
  606. status
  607. --*/
  608. {
  609. PBATT_NP_INFO BattNPInfo = (PBATT_NP_INFO) ClassData;
  610. PBATT_INFO BattInfo = BattNPInfo->BattInfo;
  611. PBATT_WMI_REQUEST WmiRequest;
  612. NTSTATUS status = STATUS_SUCCESS;
  613. ULONG size = 0;
  614. PAGED_CODE();
  615. BattPrint ((BATT_TRACE|BATT_WMI), ("Entered BatteryClassQueryWmiDataBlock\n"));
  616. //
  617. // Don't need to acquire remove lock. It is already head by SystemControl.
  618. //
  619. switch (GuidIndex - BattInfo->WmiGuidIndex) {
  620. case BattWmiStatusId:
  621. size = sizeof (BATTERY_WMI_STATUS);
  622. break;
  623. case BattWmiRuntimeId:
  624. size = sizeof (BATTERY_WMI_RUNTIME);
  625. break;
  626. case BattWmiTemperatureId:
  627. size = sizeof (BATTERY_WMI_TEMPERATURE);
  628. break;
  629. case BattWmiFullChargedCapacityId:
  630. size = sizeof (BATTERY_WMI_FULL_CHARGED_CAPACITY);
  631. break;
  632. case BattWmiCycleCountId:
  633. size = sizeof (BATTERY_WMI_CYCLE_COUNT);
  634. break;
  635. case BattWmiStaticDataId:
  636. size = sizeof(BATTERY_WMI_STATIC_DATA)+4*MAX_BATTERY_STRING_SIZE*sizeof(WCHAR);
  637. // data plus 4 strings
  638. break;
  639. default:
  640. status = STATUS_WMI_GUID_NOT_FOUND;
  641. }
  642. if (status != STATUS_WMI_GUID_NOT_FOUND) {
  643. if (OutBufferSize < size ) {
  644. status = STATUS_BUFFER_TOO_SMALL;
  645. *InstanceLengthArray = size;
  646. status = WmiCompleteRequest( DeviceObject,
  647. Irp,
  648. status,
  649. size,
  650. IO_NO_INCREMENT);
  651. return status;
  652. }
  653. WmiRequest = ExAllocatePoolWithTag (PagedPool, sizeof(BATT_WMI_REQUEST), 'ttaB');
  654. if (!WmiRequest) {
  655. BattPrint((BATT_ERROR), ("Failed to allocate memory for WMI request\n"));
  656. status = STATUS_INSUFFICIENT_RESOURCES;
  657. status = WmiCompleteRequest( DeviceObject,
  658. Irp,
  659. status,
  660. size,
  661. IO_NO_INCREMENT);
  662. return status;
  663. }
  664. WmiRequest->DeviceObject = DeviceObject;
  665. WmiRequest->Irp = Irp;
  666. WmiRequest->GuidIndex = GuidIndex - BattInfo->WmiGuidIndex;
  667. WmiRequest->InstanceLengthArray = InstanceLengthArray;
  668. WmiRequest->OutBufferSize = OutBufferSize;
  669. WmiRequest->Buffer = Buffer;
  670. ExAcquireFastMutex (&BattNPInfo->Mutex);
  671. InsertTailList (&BattInfo->WmiQueue, &WmiRequest->ListEntry);
  672. ExReleaseFastMutex (&BattNPInfo->Mutex);
  673. BattCQueueWorker (BattNPInfo, FALSE);
  674. status = STATUS_PENDING;
  675. }
  676. return status;
  677. }