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.

929 lines
29 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. //
  152. // 1 additional lock is held for the worker thread which only releases it
  153. // at removal time. Rather than aquiring and releasing each time, it just
  154. // checks WantToRemove to determine if it should release the lock.
  155. // This means that the worker thread must be queued at least once after
  156. // WantToRemove is set to TRUE.
  157. //
  158. BattNPInfo->InUseCount = 2;
  159. KeInitializeEvent(&BattNPInfo->ReadyToRemove, SynchronizationEvent, FALSE);
  160. #if DEBUG // Set device Number for debug prints.
  161. BattNPInfo->DeviceNum = NextDeviceNum;
  162. NextDeviceNum++;
  163. #endif
  164. *ClassData = BattNPInfo;
  165. //
  166. // Check to see if this is a battery other than the composite
  167. //
  168. if (MiniportInfo->Pdo) {
  169. // Blank UNICODE_STRING so IoRegisterDeviceInterface will allocate space.
  170. RtlInitUnicodeString (&BattInfo->SymbolicLinkName, NULL);
  171. //
  172. // Create the symbolic link
  173. //
  174. status = IoRegisterDeviceInterface(
  175. MiniportInfo->Pdo,
  176. (LPGUID)&GUID_DEVICE_BATTERY,
  177. NULL,
  178. &BattInfo->SymbolicLinkName);
  179. if (NT_SUCCESS(status)) {
  180. //
  181. // Now set the symbolic link for the association and store it..
  182. //
  183. BattPrint ((BATT_NOTE), ("BattC (%d): Making SetDeviceInterfaceState call.\n", BattNPInfo->DeviceNum));
  184. status = IoSetDeviceInterfaceState(&BattInfo->SymbolicLinkName, TRUE);
  185. if (status == STATUS_OBJECT_NAME_EXISTS) {
  186. // The device interface was already enabled. Continue anyway.
  187. BattPrint ((BATT_WARN), ("BattC (%d): Got STATUS_OBJECT_NAME_EXISTS for SetDeviceInterfaceState\n", BattNPInfo->DeviceNum));
  188. status = STATUS_SUCCESS;
  189. }
  190. }
  191. }
  192. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassInitializeDevice (status = 0x%08lx).\n", BattNPInfo->DeviceNum, status));
  193. return status;
  194. } // BatteryClassInitializeDevice
  195. NTSTATUS
  196. BATTERYCLASSAPI
  197. BatteryClassUnload (
  198. IN PVOID ClassData
  199. )
  200. /*++
  201. Routine Description:
  202. Called by the miniport when it has received a remove request.
  203. The miniclass driver must syncronize itself so that this API is
  204. not called while any of the others are not yet completed.
  205. Arguments:
  206. ClassData - Handle to class driver
  207. Return Value:
  208. This routine must not fail. It returns STATUS_SUCCESS
  209. --*/
  210. {
  211. NTSTATUS status;
  212. PBATT_INFO BattInfo;
  213. PBATT_NP_INFO BattNPInfo;
  214. PAGED_CODE();
  215. BattNPInfo = (PBATT_NP_INFO) ClassData;
  216. BattInfo = BattNPInfo->BattInfo;
  217. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassUnload called.\n", BattNPInfo->DeviceNum));
  218. //
  219. // Disable the symbolic link
  220. //
  221. ASSERT(BattInfo->SymbolicLinkName.Buffer);
  222. status = IoSetDeviceInterfaceState(&BattInfo->SymbolicLinkName, FALSE);
  223. if (!NT_SUCCESS(status)) {
  224. BattPrint (BATT_ERROR, ("BattC (%d) Unload: IoSetDeviceInterface returned 0x%08lx\n", BattNPInfo->DeviceNum, status));
  225. }
  226. //
  227. // Syncronization with the worker thread.
  228. // We can't return because the worker may be in the middle of something.
  229. // By returning, the battery class driver gives up the right to call miniport routines.
  230. //
  231. // This needs to be done before canceling the timers so that the worker
  232. // thread doesn't reset them.
  233. //
  234. BattNPInfo->WantToRemove = TRUE;
  235. //
  236. // Cancel timers
  237. // If a timer had been waiting,we need to release the remove lock that was
  238. // aquired before the timer was set since it will not be released in the DPC.
  239. //
  240. if (KeCancelTimer (&BattNPInfo->WorkerTimer)) {
  241. // Release Removal Lock
  242. // "InUseCount can never be 0 after this operation.
  243. InterlockedDecrement(&BattNPInfo->InUseCount);
  244. BattPrint ((BATT_LOCK), ("BatteryClassUnload: Released WorkerTimer remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  245. }
  246. if (KeCancelTimer (&BattNPInfo->TagTimer)) {
  247. // Release Removal Lock
  248. // "InUseCount can never be 0 after this operation.
  249. InterlockedDecrement(&BattNPInfo->InUseCount);
  250. BattPrint ((BATT_LOCK), ("BatteryClassUnload: Released TagTimer remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  251. }
  252. //
  253. // Queue the worker thread once more to make sure that the remove lock for
  254. // the worker thread is released.
  255. //
  256. BattCQueueWorker (BattNPInfo, FALSE);
  257. // Finish syncronization
  258. if (InterlockedDecrement (&BattNPInfo->InUseCount) > 0) {
  259. KeWaitForSingleObject (&BattNPInfo->ReadyToRemove,
  260. Executive,
  261. KernelMode,
  262. FALSE,
  263. NULL
  264. );
  265. }
  266. BattPrint ((BATT_LOCK), ("BatteryClassUnload: Done waiting for remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  267. //
  268. // Free Structures
  269. //
  270. ExFreePool (BattInfo->SymbolicLinkName.Buffer);
  271. ExFreePool (BattInfo);
  272. ExFreePool (BattNPInfo);
  273. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassUnload returning.\n", BattNPInfo->DeviceNum));
  274. return STATUS_SUCCESS;
  275. }
  276. NTSTATUS
  277. BATTERYCLASSAPI
  278. BatteryClassIoctl (
  279. IN PVOID ClassData,
  280. IN PIRP Irp
  281. )
  282. /*++
  283. Routine Description:
  284. Called by the miniport to handle battery ioctl requests. If handled,
  285. the battery class driver owns the IRP. If not handled, it belongs to
  286. the caller.
  287. Arguments:
  288. ClassData - Handle to class driver
  289. Irp - ICOTL irp to check
  290. Return Value:
  291. If handled, the battery class driver owns the IRP and will complete it
  292. once its handled; otherwise, the error STATUS_NOT_SUPPORTED is returned.
  293. --*/
  294. {
  295. NTSTATUS status;
  296. PBATT_INFO BattInfo;
  297. PBATT_NP_INFO BattNPInfo;
  298. PIO_STACK_LOCATION IrpSp;
  299. PAGED_CODE();
  300. BattNPInfo = (PBATT_NP_INFO) ClassData;
  301. BattInfo = BattNPInfo->BattInfo;
  302. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassIoctl called.\n", BattNPInfo->DeviceNum));
  303. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  304. //
  305. // Assume it's not our IRP
  306. //
  307. status = STATUS_NOT_SUPPORTED;
  308. //
  309. // Check IOCTL code to see if it's our IRP
  310. //
  311. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  312. case IOCTL_BATTERY_QUERY_TAG:
  313. case IOCTL_BATTERY_QUERY_INFORMATION:
  314. case IOCTL_BATTERY_SET_INFORMATION:
  315. case IOCTL_BATTERY_QUERY_STATUS:
  316. //
  317. // Acquire remove lock.
  318. // We don't want to queue anything more if we're being removed.
  319. //
  320. InterlockedIncrement (&BattNPInfo->InUseCount);
  321. BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  322. if (BattNPInfo->WantToRemove == TRUE) {
  323. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  324. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  325. }
  326. BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  327. status = STATUS_DEVICE_REMOVED;
  328. } else {
  329. //
  330. // Irp to handle. Put it in the queue worker threads list
  331. //
  332. status = STATUS_PENDING;
  333. Irp->IoStatus.Status = STATUS_PENDING;
  334. IoMarkIrpPending (Irp);
  335. ExAcquireFastMutex (&BattNPInfo->Mutex);
  336. InsertTailList (&BattInfo->IoQueue, &Irp->Tail.Overlay.ListEntry);
  337. ExReleaseFastMutex (&BattNPInfo->Mutex);
  338. BattCQueueWorker (BattNPInfo, FALSE);
  339. //
  340. // Release Remove Lock.
  341. //
  342. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  343. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  344. }
  345. BattPrint ((BATT_LOCK), ("BatteryClassIoctl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  346. }
  347. break;
  348. default:
  349. BattPrint ((BATT_ERROR|BATT_IOCTL),
  350. ("BattC (%d): unknown battery ioctl - %x\n",
  351. BattNPInfo->DeviceNum,
  352. IrpSp->Parameters.DeviceIoControl.IoControlCode));
  353. break;
  354. }
  355. if ((status != STATUS_PENDING) && (status != STATUS_NOT_SUPPORTED)) {
  356. Irp->IoStatus.Status = status;
  357. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  358. }
  359. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassIoctl returning (status = 0x%08lx).\n", BattNPInfo->DeviceNum, status));
  360. return status;
  361. }
  362. NTSTATUS
  363. BATTERYCLASSAPI
  364. BatteryClassStatusNotify (
  365. IN PVOID ClassData
  366. )
  367. /*++
  368. Routine Description:
  369. Called by the miniport to signify that something interesting concerning
  370. the battery status has occured. Calling this function will cause the
  371. battery class driver to obtain the battery status if there are any pending
  372. status requests pending.
  373. If the miniport supports SetNotify from the class driver, then the miniport
  374. only needs to call this function once when the notification crtierea is
  375. met.
  376. If the miniport does not support SetNotify from the class driver, then
  377. the class driver will poll (at a slow rate) but the miniport should still
  378. call this function at least when the batteries power status changes such
  379. that timely updates of at least the power status will occur in the UI.
  380. Arguments:
  381. ClassData - Handle to class driver
  382. Return Value:
  383. Status
  384. --*/
  385. {
  386. PBATT_NP_INFO BattNPInfo;
  387. BattNPInfo = (PBATT_NP_INFO) ClassData;
  388. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassStatusNotify called\n", BattNPInfo->DeviceNum));
  389. InterlockedExchange (&BattNPInfo->StatusNotified, 1);
  390. InterlockedExchange (&BattNPInfo->TagNotified, 1);
  391. BattCQueueWorker (BattNPInfo, TRUE);
  392. return STATUS_SUCCESS;
  393. }
  394. NTSTATUS
  395. BATTERYCLASSAPI
  396. BatteryClassSystemControl (
  397. IN PVOID ClassData,
  398. IN PWMILIB_CONTEXT WmiLibContext,
  399. IN PDEVICE_OBJECT DeviceObject,
  400. IN PIRP Irp,
  401. OUT PSYSCTL_IRP_DISPOSITION Disposition
  402. )
  403. /*++
  404. Routine Description:
  405. The miniport driver calls this instead of WmiSystemControl.
  406. Arguments:
  407. ClassData - Handle to class driver
  408. The other parameters are the parameters for WmiSystemControl.
  409. Return Value:
  410. STATUS_SUCCESS or one of the following error codes:
  411. STATUS_INVALID_DEVICE_REQUEST
  412. STATUS_WMI_GUID_NOT_FOUND
  413. STATUS_WMI_INSTANCE_NOT_FOUND
  414. --*/
  415. {
  416. NTSTATUS status = STATUS_NOT_SUPPORTED;
  417. PBATT_INFO BattInfo;
  418. PBATT_NP_INFO BattNPInfo;
  419. PIO_STACK_LOCATION IrpSp;
  420. PAGED_CODE();
  421. BattNPInfo = (PBATT_NP_INFO) ClassData;
  422. BattInfo = BattNPInfo->BattInfo;
  423. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  424. BattPrint ((BATT_TRACE), ("BattC (%d): BatteryClassSystemControl called.\n", BattNPInfo->DeviceNum));
  425. //
  426. // Initialize the WmiLibContext structure if this is the first time.
  427. //
  428. if (BattInfo->WmiLibContext.GuidCount == 0) {
  429. RtlCopyMemory(&BattInfo->WmiLibContext, // Copy all callback routines set by minidriver
  430. WmiLibContext,
  431. sizeof(*WmiLibContext));
  432. BattInfo->WmiLibContext.GuidCount = WmiLibContext->GuidCount + BattWmiTotalGuids;
  433. BattInfo->WmiGuidIndex = WmiLibContext->GuidCount;
  434. BattInfo->WmiLibContext.GuidList = ExAllocatePoolWithTag(PagedPool, BattInfo->WmiLibContext.GuidCount * sizeof(WMIGUIDREGINFO), 'ttaB');
  435. if (!BattInfo->WmiLibContext.GuidList) {
  436. //
  437. // Fail. If the miniclass tries again, this might work the next time.
  438. //
  439. BattInfo->WmiLibContext.GuidCount = 0;
  440. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  441. *Disposition = IrpNotCompleted;
  442. return STATUS_INSUFFICIENT_RESOURCES;
  443. }
  444. RtlCopyMemory(BattInfo->WmiLibContext.GuidList,
  445. WmiLibContext->GuidList,
  446. WmiLibContext->GuidCount * sizeof(WMIGUIDREGINFO));
  447. RtlCopyMemory(&BattInfo->WmiLibContext.GuidList [WmiLibContext->GuidCount],
  448. BattWmiGuidList, BattWmiTotalGuids * sizeof(WMIGUIDREGINFO));
  449. }
  450. //
  451. // Acquire remove lock.
  452. // We don't want to queue anything more if we're being removed.
  453. //
  454. InterlockedIncrement (&BattNPInfo->InUseCount);
  455. BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Aqcuired remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  456. if (BattNPInfo->WantToRemove == TRUE) {
  457. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  458. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  459. }
  460. BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  461. status = STATUS_DEVICE_REMOVED;
  462. } else {
  463. status = WmiSystemControl(&BattInfo->WmiLibContext,
  464. DeviceObject,
  465. Irp,
  466. Disposition);
  467. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Returned from WmiSystemControl (status = 0x%08x).\n", BattNPInfo->DeviceNum, status));
  468. //
  469. // For IRP_MN_REGINFO BattC needs to add additional data to the IRP
  470. // about the battery class MOF resource.
  471. //
  472. if ((*Disposition == IrpNotCompleted) &&
  473. ((IrpSp->MinorFunction == IRP_MN_REGINFO) ||
  474. (IrpSp->MinorFunction == IRP_MN_REGINFO_EX)) &&
  475. (IrpSp->Parameters.WMI.DataPath == WMIREGISTER)) {
  476. //
  477. // Original structure
  478. //
  479. PWMIREGINFO regInfoPtr = IrpSp->Parameters.WMI.Buffer;
  480. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Adding Resource.\n", BattNPInfo->DeviceNum));
  481. //
  482. // If WmiSystemControl returned STATUS_BUFFER_TOO_SMALL or entered
  483. // the correct size as a ULONG in IoStatus.Information.
  484. // Increase the required size to accomodate battery class data
  485. // before returning
  486. //
  487. if (Irp->IoStatus.Information == sizeof(ULONG) ||
  488. Irp->IoStatus.Status == STATUS_BUFFER_TOO_SMALL) {
  489. //
  490. // Aditional battery class data includes one WMIREGINFO structure
  491. // Followed strings for the regstry path and resource name.
  492. // (Plus two WCHARS because these need to be counted strings.)
  493. // Round this up to the nearest 8 bytes.
  494. //
  495. regInfoPtr->BufferSize =
  496. (regInfoPtr->BufferSize +
  497. sizeof(WMIREGINFO) +
  498. sizeof(MOFREGISTRYPATH) +
  499. sizeof(MOFRESOURCENAME) + 2 * sizeof(WCHAR) + 7) & 0xFFFFFFF8;
  500. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Buffer Too Small:\n"
  501. " Information = %08x\n"
  502. " BufferSize = %08x\n"
  503. " NewSize = %08x\n",
  504. BattNPInfo->DeviceNum,
  505. Irp->IoStatus.Information,
  506. IrpSp->Parameters.WMI.BufferSize,
  507. regInfoPtr->BufferSize));
  508. //
  509. // Make sure IRP is set up to fail correctly.
  510. //
  511. Irp->IoStatus.Information = sizeof(ULONG);
  512. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  513. status = STATUS_BUFFER_TOO_SMALL;
  514. } else {
  515. ULONG size;
  516. PWCHAR tempString;
  517. //
  518. // Assume that there is only one WmiRegInfo Structure so far.
  519. //
  520. ASSERT (regInfoPtr->NextWmiRegInfo == 0);
  521. regInfoPtr->NextWmiRegInfo = (regInfoPtr->BufferSize + 7) & 0xFFFFFFF8;
  522. size = regInfoPtr->NextWmiRegInfo + sizeof(WMIREGINFO) +
  523. sizeof(MOFRESOURCENAME) + sizeof(MOFREGISTRYPATH) + 2 * sizeof(WCHAR);
  524. //
  525. // Set BufferSize Whether we succeed or not.
  526. //
  527. ((PWMIREGINFO)IrpSp->Parameters.WMI.Buffer)->BufferSize = size;
  528. if (size > IrpSp->Parameters.WMI.BufferSize) {
  529. //
  530. // If WmiSystemControl was successful, but there isnt room
  531. // for the extra data, this request needs to fail
  532. //
  533. Irp->IoStatus.Information = sizeof(ULONG);
  534. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  535. status = STATUS_BUFFER_TOO_SMALL;
  536. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Buffer Too Small.\n"
  537. " BufferSize = %08x\n"
  538. " Size = %08x\n",
  539. BattNPInfo->DeviceNum,
  540. IrpSp->Parameters.WMI.BufferSize,
  541. size));
  542. } else {
  543. Irp->IoStatus.Information = size;
  544. BattPrint ((BATT_DEBUG), ("BattC (%d): BatteryClassSystemControl Munging Structures:\n"
  545. " Buffer = %08x\n"
  546. " temp = %08x\n",
  547. BattNPInfo->DeviceNum,
  548. (ULONG_PTR) IrpSp->Parameters.WMI.Buffer,
  549. (ULONG_PTR) regInfoPtr));
  550. //
  551. // Intialize new structure
  552. //
  553. // Set teporary pointer to point at data structure we are adding.
  554. (ULONG_PTR)regInfoPtr += (ULONG_PTR)regInfoPtr->NextWmiRegInfo;
  555. regInfoPtr->BufferSize = sizeof(WMIREGINFO) +
  556. sizeof(MOFRESOURCENAME) +
  557. sizeof(MOFREGISTRYPATH) + 2 * sizeof(WCHAR);
  558. regInfoPtr->NextWmiRegInfo = 0;
  559. // Initialize RegistryPath counted string.
  560. regInfoPtr->RegistryPath = sizeof(WMIREGINFO);
  561. tempString = (PWCHAR)((ULONG_PTR)regInfoPtr + sizeof(WMIREGINFO));
  562. *tempString++ = sizeof(MOFREGISTRYPATH);
  563. RtlCopyMemory(tempString, MOFREGISTRYPATH, sizeof(MOFREGISTRYPATH));
  564. // Initialize MofResourceName counted string.
  565. regInfoPtr->MofResourceName = sizeof(WMIREGINFO) + sizeof(MOFREGISTRYPATH) + sizeof(WCHAR);
  566. tempString = (PWCHAR)((ULONG_PTR)regInfoPtr + regInfoPtr->MofResourceName);
  567. *tempString++ = sizeof(MOFRESOURCENAME);
  568. RtlCopyMemory(tempString, MOFRESOURCENAME, sizeof(MOFRESOURCENAME));
  569. regInfoPtr->GuidCount = 0;
  570. }
  571. }
  572. }
  573. //
  574. // Release Remove Lock.
  575. //
  576. if (0 == InterlockedDecrement(&BattNPInfo->InUseCount)) {
  577. KeSetEvent (&BattNPInfo->ReadyToRemove, IO_NO_INCREMENT, FALSE);
  578. }
  579. BattPrint ((BATT_LOCK), ("BatteryClassSystemControl: Released remove lock %d (count = %d)\n", BattNPInfo->DeviceNum, BattNPInfo->InUseCount));
  580. }
  581. return status;
  582. }
  583. NTSTATUS
  584. BATTERYCLASSAPI
  585. BatteryClassQueryWmiDataBlock(
  586. IN PVOID ClassData,
  587. IN PDEVICE_OBJECT DeviceObject,
  588. IN PIRP Irp,
  589. IN ULONG GuidIndex,
  590. IN OUT PULONG InstanceLengthArray,
  591. IN ULONG OutBufferSize,
  592. OUT PUCHAR Buffer
  593. )
  594. /*++
  595. Routine Description:
  596. This routine is a callback into the driver to query for the contents of
  597. a data block. When the driver has finished filling the data block it
  598. must call WmiCompleteRequest to complete the irp. The driver can
  599. return STATUS_PENDING if the irp cannot be completed immediately.
  600. Arguments:
  601. DeviceObject is the device whose data block is being queried
  602. Irp is the Irp that makes this request
  603. GuidIndex is the index into the list of guids provided when the
  604. device registered
  605. InstanceLengthArray is a pointer to an array of ULONG that returns the
  606. lengths of each instance of the data block. If this is NULL then
  607. there was not enough space in the output buffer to fulfill the request
  608. so the irp should be completed with the buffer needed.
  609. BufferAvail on has the maximum size available to write the data
  610. block.
  611. Buffer on return is filled with the returned data block
  612. Return Value:
  613. status
  614. --*/
  615. {
  616. PBATT_NP_INFO BattNPInfo = (PBATT_NP_INFO) ClassData;
  617. PBATT_INFO BattInfo = BattNPInfo->BattInfo;
  618. PBATT_WMI_REQUEST WmiRequest;
  619. NTSTATUS status = STATUS_SUCCESS;
  620. ULONG size = 0;
  621. PAGED_CODE();
  622. BattPrint ((BATT_TRACE|BATT_WMI), ("Entered BatteryClassQueryWmiDataBlock\n"));
  623. //
  624. // Don't need to acquire remove lock. It is already held by SystemControl.
  625. //
  626. switch (GuidIndex - BattInfo->WmiGuidIndex) {
  627. case BattWmiStatusId:
  628. size = sizeof (BATTERY_WMI_STATUS);
  629. break;
  630. case BattWmiRuntimeId:
  631. size = sizeof (BATTERY_WMI_RUNTIME);
  632. break;
  633. case BattWmiTemperatureId:
  634. size = sizeof (BATTERY_WMI_TEMPERATURE);
  635. break;
  636. case BattWmiFullChargedCapacityId:
  637. size = sizeof (BATTERY_WMI_FULL_CHARGED_CAPACITY);
  638. break;
  639. case BattWmiCycleCountId:
  640. size = sizeof (BATTERY_WMI_CYCLE_COUNT);
  641. break;
  642. case BattWmiStaticDataId:
  643. size = sizeof(BATTERY_WMI_STATIC_DATA)+4*MAX_BATTERY_STRING_SIZE*sizeof(WCHAR);
  644. // data plus 4 strings
  645. break;
  646. default:
  647. status = STATUS_WMI_GUID_NOT_FOUND;
  648. }
  649. if (status != STATUS_WMI_GUID_NOT_FOUND) {
  650. if (OutBufferSize < size ) {
  651. status = STATUS_BUFFER_TOO_SMALL;
  652. *InstanceLengthArray = size;
  653. status = WmiCompleteRequest( DeviceObject,
  654. Irp,
  655. status,
  656. size,
  657. IO_NO_INCREMENT);
  658. return status;
  659. }
  660. WmiRequest = ExAllocatePoolWithTag (PagedPool, sizeof(BATT_WMI_REQUEST), 'ttaB');
  661. if (!WmiRequest) {
  662. BattPrint((BATT_ERROR), ("Failed to allocate memory for WMI request\n"));
  663. status = STATUS_INSUFFICIENT_RESOURCES;
  664. status = WmiCompleteRequest( DeviceObject,
  665. Irp,
  666. status,
  667. size,
  668. IO_NO_INCREMENT);
  669. return status;
  670. }
  671. WmiRequest->DeviceObject = DeviceObject;
  672. WmiRequest->Irp = Irp;
  673. WmiRequest->GuidIndex = GuidIndex - BattInfo->WmiGuidIndex;
  674. WmiRequest->InstanceLengthArray = InstanceLengthArray;
  675. WmiRequest->OutBufferSize = OutBufferSize;
  676. WmiRequest->Buffer = Buffer;
  677. ExAcquireFastMutex (&BattNPInfo->Mutex);
  678. InsertTailList (&BattInfo->WmiQueue, &WmiRequest->ListEntry);
  679. ExReleaseFastMutex (&BattNPInfo->Mutex);
  680. BattCQueueWorker (BattNPInfo, FALSE);
  681. status = STATUS_PENDING;
  682. }
  683. return status;
  684. }