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.

1811 lines
46 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. thermal.c
  5. Abstract:
  6. Thermal Zone support
  7. A small discourse on the use and function of the THRM_WAIT_FOR_NOTIFY
  8. flag. This flag was added to ensure that at least one Notify() operation
  9. occured between each query of the temperature. In other words, we didn't
  10. want to loop forever asking and receiving the same temperature information.
  11. One of the side effects of this flag is that if we get a QUERY, then
  12. a SET (instead of another QUERY), then the set must clear the flag.
  13. Failure to do so will prevent the ThermalLoop() code from ever completing
  14. the IRP. And that means that the temperature mechanisms will stop working.
  15. Author:
  16. Stephane Plante (splante)
  17. Environment:
  18. NT Kernel Model Driver only
  19. Revision History:
  20. July 7, 1997 - Complete Rewrite
  21. --*/
  22. #include "pch.h"
  23. WMIGUIDREGINFO ACPIThermalGuidList =
  24. {
  25. &THERMAL_ZONE_GUID,
  26. 1,
  27. 0
  28. };
  29. //
  30. // Spinlock to protect the thermal list
  31. //
  32. KSPIN_LOCK AcpiThermalLock;
  33. //
  34. // List entry to store the thermal requests on
  35. //
  36. LIST_ENTRY AcpiThermalList;
  37. #ifdef ALLOC_PRAGMA
  38. #pragma alloc_text(PAGE, ACPIThermalStartDevice)
  39. #pragma alloc_text(PAGE, ACPIThermalWorker)
  40. #pragma alloc_text(PAGE, ACPIThermalQueryWmiRegInfo)
  41. #pragma alloc_text(PAGE, ACPIThermalQueryWmiDataBlock)
  42. #pragma alloc_text(PAGE, ACPIThermalWmi)
  43. #endif
  44. VOID
  45. ACPIThermalCalculateProcessorMask(
  46. IN PNSOBJ ProcessorObject,
  47. IN PTHRM_INFO Thrm
  48. )
  49. /*++
  50. Routine Description:
  51. This routine, which is only called from ACPIThermalWorker, has been
  52. created so that we don't have to worry about locking down the
  53. ACPIThermalWorker, takes a processor object from the namespace and
  54. sets the proper affinity bit in the thermal info
  55. Arguments:
  56. ProcessorObject - Pointer to Namespace Processor Object
  57. Thrm - Thermal Information Structure
  58. Return Value:
  59. None
  60. --*/
  61. {
  62. KIRQL OldIrql;
  63. PDEVICE_EXTENSION ProcessorExtension;
  64. //
  65. // Sanity check
  66. //
  67. if (ProcessorObject == NULL) {
  68. return;
  69. }
  70. //
  71. // We need the spinlock to deref the processor extension
  72. //
  73. KeAcquireSpinLock( &AcpiDeviceTreeLock, &OldIrql );
  74. //
  75. // The context pointer is the device extension
  76. //
  77. ProcessorExtension = (PDEVICE_EXTENSION) ProcessorObject->Context;
  78. if (ProcessorExtension) {
  79. //
  80. // We know what index it is within the processor list.
  81. // This should be a good enough guess for now
  82. //
  83. Thrm->Info.Processors |= ( (ULONG_PTR) 1 << ProcessorExtension->Processor.ProcessorIndex);
  84. }
  85. //
  86. // Done with the spinlock
  87. //
  88. KeReleaseSpinLock( &AcpiDeviceTreeLock, OldIrql );
  89. }
  90. VOID
  91. ACPIThermalCancelRequest (
  92. IN PDEVICE_OBJECT DeviceObject,
  93. IN PIRP Irp
  94. )
  95. /*++
  96. Routine Description:
  97. This routine cancels an outstanding thermal request
  98. Arguments
  99. DeviceObject - The device which has a request being cancelled
  100. Irp - The cancelling irp
  101. Return Value:
  102. None
  103. --*/
  104. {
  105. KIRQL oldIrql;
  106. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  107. #if DBG
  108. ULONGLONG currentTime = KeQueryInterruptTime();
  109. ACPIThermalPrint( (
  110. ACPI_PRINT_THERMAL,
  111. deviceExtension,
  112. currentTime,
  113. "ACPIThermalCancelRequest: Irp %08lx\n",
  114. Irp
  115. ) );
  116. #endif
  117. //
  118. // We no longer need the cancel lock
  119. //
  120. IoReleaseCancelSpinLock (Irp->CancelIrql);
  121. //
  122. // We do however need the thermal queue lock
  123. //
  124. KeAcquireSpinLock( &AcpiThermalLock, &oldIrql );
  125. //
  126. // Remove the irp from the list that it is on
  127. //
  128. RemoveEntryList( &(Irp->Tail.Overlay.ListEntry) );
  129. //
  130. // Done with the thermal lock now
  131. //
  132. KeReleaseSpinLock( &AcpiThermalLock, oldIrql );
  133. //
  134. // Complete the irp now
  135. //
  136. Irp->IoStatus.Status = STATUS_CANCELLED;
  137. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  138. }
  139. VOID
  140. EXPORT
  141. ACPIThermalComplete (
  142. IN PNSOBJ AcpiObject,
  143. IN NTSTATUS Status,
  144. IN POBJDATA Result OPTIONAL,
  145. IN PVOID DeviceExtension
  146. )
  147. /*++
  148. Routine Description:
  149. This routine is called when the interpreter has completed a request
  150. Arguments:
  151. AcpiObject - The request that was completed
  152. Status - The status of the request
  153. Result - What the result of the request was
  154. DevExt - The context of the request
  155. Return Value:
  156. NONE
  157. --*/
  158. {
  159. ACPIThermalLoop (DeviceExtension, THRM_BUSY);
  160. }
  161. BOOLEAN
  162. ACPIThermalCompletePendingIrps(
  163. IN PDEVICE_EXTENSION DeviceExtension,
  164. IN PTHRM_INFO Thermal
  165. )
  166. /*++
  167. Routine Description:
  168. This routine is called, with no spinlock being held. This routine
  169. completes any IOCTLs associated with the device object
  170. This routine will return TRUE if it completed any requests, false
  171. otherwise
  172. Arguments:
  173. DeviceExtension - The device extension whose requests we want to complete
  174. Thermal - Pointer to the thermal information for the extension
  175. Return Value:
  176. BOOLEAN
  177. --*/
  178. {
  179. BOOLEAN handledRequest = FALSE;
  180. KIRQL oldIrql;
  181. LIST_ENTRY doneList;
  182. PDEVICE_EXTENSION irpExtension;
  183. PDEVICE_OBJECT deviceObject;
  184. PIO_STACK_LOCATION irpSp;
  185. PIRP irp;
  186. PLIST_ENTRY listEntry;
  187. PTHERMAL_INFORMATION thermalInfo;
  188. //
  189. // Initialize the list that will hold the requets that we need to complete
  190. //
  191. InitializeListHead( &doneList );
  192. //
  193. // Acquire the thermal lock so that we can pend these requests
  194. //
  195. KeAcquireSpinLock( &AcpiThermalLock, &oldIrql );
  196. //
  197. // Walk the list of pending irps to see which ones match this extensions
  198. //
  199. listEntry = AcpiThermalList.Flink;
  200. while (listEntry != &AcpiThermalList) {
  201. //
  202. // Grab the irp from the list entry and update the next list entry
  203. // that we will look at
  204. //
  205. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  206. listEntry = listEntry->Flink;
  207. //
  208. // We need the current irp stack location
  209. //
  210. irpSp = IoGetCurrentIrpStackLocation( irp );
  211. //
  212. // Grab the device object from the irp stack and turn that into a
  213. // device extension
  214. //
  215. irpExtension = ACPIInternalGetDeviceExtension( irpSp->DeviceObject );
  216. //
  217. // Is this an irp that we care about? IE: does the target match the
  218. // one specified in this function
  219. //
  220. if (irpExtension != DeviceExtension) {
  221. continue;
  222. }
  223. //
  224. // If this is a query information irp then, we must be able to set the
  225. // cancel routine to NULL to make sure that it cannot be cancelled on
  226. // us
  227. //
  228. if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_THERMAL_QUERY_INFORMATION) {
  229. if (IoSetCancelRoutine(irp, NULL) == NULL) {
  230. //
  231. // Cancel routine is active, stop processing this irp and move on
  232. //
  233. continue;
  234. }
  235. //
  236. // Copy the data that we got back to the irp
  237. //
  238. DeviceExtension->Thermal.Flags |= THRM_WAIT_FOR_NOTIFY;
  239. thermalInfo = (PTHERMAL_INFORMATION) irp->AssociatedIrp.SystemBuffer;
  240. memcpy (thermalInfo, Thermal, sizeof (THERMAL_INFORMATION));
  241. //
  242. // Set the parameters that we will return
  243. //
  244. irp->IoStatus.Information = sizeof(THERMAL_INFORMATION);
  245. } else {
  246. //
  247. // Set the parameters that we will return
  248. //
  249. irp->IoStatus.Information = 0;
  250. }
  251. //
  252. // Always succeed these irps
  253. //
  254. irp->IoStatus.Status = STATUS_SUCCESS;
  255. //
  256. // Remove the entry from the list
  257. //
  258. RemoveEntryList( &(irp->Tail.Overlay.ListEntry) );
  259. //
  260. // Insert the list into the next queue so that we know to complete it
  261. // later on
  262. //
  263. InsertTailList( &doneList, &(irp->Tail.Overlay.ListEntry) );
  264. }
  265. //
  266. // At this point, drop our thermal lock
  267. //
  268. KeReleaseSpinLock( &AcpiThermalLock, oldIrql );
  269. //
  270. // Walk the list of irpts to be completed
  271. //
  272. listEntry = doneList.Flink;
  273. while (listEntry != &doneList) {
  274. //
  275. // Grab the irp from the list entry and update the next list entry
  276. // that we will look at
  277. //
  278. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  279. listEntry = listEntry->Flink;
  280. RemoveEntryList( &(irp->Tail.Overlay.ListEntry) );
  281. ACPIThermalPrint( (
  282. ACPI_PRINT_THERMAL,
  283. DeviceExtension,
  284. KeQueryInterruptTime(),
  285. "Completing Irp 0x%x\n",
  286. irp
  287. ) );
  288. //
  289. // Now complete the irp
  290. //
  291. IoCompleteRequest( irp, IO_NO_INCREMENT );
  292. //
  293. // Remember that we handled a request
  294. //
  295. handledRequest = TRUE;
  296. }
  297. //
  298. // Return wether or not we handled a request
  299. return handledRequest;
  300. }
  301. NTSTATUS
  302. ACPIThermalDeviceControl (
  303. IN PDEVICE_OBJECT DeviceObject,
  304. IN PIRP Irp
  305. )
  306. /*++
  307. Routine Description:
  308. Fixed button device IOCTL handler
  309. Arguments:
  310. DeviceObject - fixed feature button device object
  311. Irp - the ioctl request
  312. Return Value:
  313. NTSTATUS
  314. --*/
  315. {
  316. KIRQL oldIrql;
  317. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  318. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  319. PTHERMAL_INFORMATION thermalInfo;
  320. PULONG Mode;
  321. PTHRM_INFO Thrm = deviceExtension->Thermal.Info;
  322. NTSTATUS Status = STATUS_PENDING;
  323. ULONG ThermalWork = 0;
  324. ULONGLONG currentTime;
  325. //
  326. // Do not allow user mode IRPs in this routine
  327. //
  328. if (Irp->RequestorMode != KernelMode) {
  329. return ACPIDispatchIrpInvalid( DeviceObject, Irp );
  330. }
  331. #if DBG
  332. currentTime = KeQueryInterruptTime();
  333. #endif
  334. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  335. case IOCTL_THERMAL_QUERY_INFORMATION:
  336. //
  337. // If this irp's stamp does not match the known last stamp, then we
  338. // need a new temp now
  339. //
  340. thermalInfo = (PTHERMAL_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  341. if (thermalInfo->ThermalStamp != Thrm->Info.ThermalStamp) {
  342. ThermalWork = THRM_TEMP | THRM_WAIT_FOR_NOTIFY;
  343. }
  344. #if DBG
  345. ACPIThermalPrint( (
  346. ACPI_PRINT_THERMAL,
  347. deviceExtension,
  348. currentTime,
  349. "%08x - THERMAL_QUERY_INFORMATION: %x - %x\n",
  350. Irp,
  351. thermalInfo->ThermalStamp,
  352. Thrm->Info.ThermalStamp
  353. ) );
  354. #endif
  355. break;
  356. case IOCTL_THERMAL_SET_COOLING_POLICY:
  357. //
  358. // Set the thermal zone's policy mode
  359. //
  360. Thrm->Mode = *((PUCHAR) Irp->AssociatedIrp.SystemBuffer);
  361. ThermalWork = THRM_MODE | THRM_TRIP_POINTS | THRM_WAIT_FOR_NOTIFY;
  362. #if DBG
  363. ACPIThermalPrint( (
  364. ACPI_PRINT_THERMAL,
  365. deviceExtension,
  366. currentTime,
  367. "%08x - SET_COOLING_POLICY: %x\n",
  368. Irp,
  369. Thrm->Mode
  370. ) );
  371. #endif
  372. break;
  373. case IOCTL_RUN_ACTIVE_COOLING_METHOD:
  374. Thrm->CoolingLevel = *((PUCHAR) Irp->AssociatedIrp.SystemBuffer);
  375. ThermalWork = THRM_COOLING_LEVEL | THRM_WAIT_FOR_NOTIFY;
  376. #if DBG
  377. ACPIThermalPrint( (
  378. ACPI_PRINT_THERMAL,
  379. deviceExtension,
  380. currentTime,
  381. "%08x - ACTIVE_COOLING_LEVEL: %x\n",
  382. Irp,
  383. Thrm->CoolingLevel
  384. ) );
  385. #endif
  386. break;
  387. default:
  388. Irp->IoStatus.Information = 0;
  389. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  390. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  391. return STATUS_NOT_SUPPORTED;
  392. }
  393. //
  394. // Grab the thermal lock, queue the request to the proper place, and make
  395. // sure to set a cancel routine --- no that we will only allow a cancel
  396. // routine if this is a query irp
  397. //
  398. KeAcquireSpinLock( &AcpiThermalLock, &oldIrql );
  399. //
  400. // There is one fly in the ointment: What to do if the device is no longer
  401. // there. The only way to really handle that is to just fail the request.
  402. // Its important to note that this check is done while the ThermalLock
  403. // is being held because the code that builds a SurpriseRemoved extension
  404. // will attempt to call AcpiThermalCompletePendingIrps which also
  405. // acquires this lock.
  406. //
  407. if (deviceExtension->Flags & DEV_TYPE_SURPRISE_REMOVED) {
  408. KeReleaseSpinLock( &AcpiThermalLock, oldIrql );
  409. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  410. Irp->IoStatus.Information = 0;
  411. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  412. return STATUS_NO_SUCH_DEVICE;
  413. }
  414. if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_THERMAL_QUERY_INFORMATION) {
  415. IoSetCancelRoutine (Irp, ACPIThermalCancelRequest);
  416. if (Irp->Cancel && IoSetCancelRoutine( Irp, NULL ) ) {
  417. //
  418. // If we got here, that means that the irp has been cancelled and we
  419. // beat the IO manager to the ThermalLock. So release the irp, and
  420. // mark the irp as being cancelled
  421. //
  422. KeReleaseSpinLock( &AcpiThermalLock, oldIrql );
  423. Irp->IoStatus.Information = 0;
  424. Irp->IoStatus.Status = STATUS_CANCELLED;
  425. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  426. return STATUS_CANCELLED;
  427. }
  428. }
  429. //
  430. // If we got to this point, we are going to queue the request and do some
  431. // work on it. The ACPIThermalLoop routine may process this request right
  432. // away or do it later depending on wether it is busy doing some work when
  433. // it is called. Therefore we should mark this IRP pending. There is no harm
  434. // in marking it pending and returning STATUS_PENDING even if the work
  435. // gets completed by ACPIThermalLoop syncronously.
  436. //
  437. IoMarkIrpPending( Irp );
  438. //
  439. // If we got here, we know we can queue the irp in the outstanding
  440. // work list entry
  441. //
  442. InsertTailList( &AcpiThermalList, &(Irp->Tail.Overlay.ListEntry) );
  443. //
  444. // Done with the lock at this point
  445. //
  446. KeReleaseSpinLock( &AcpiThermalLock, oldIrql );
  447. //
  448. // Fire off the workter thread
  449. //
  450. ACPIThermalLoop (deviceExtension, ThermalWork);
  451. return Status;
  452. }
  453. VOID
  454. ACPIThermalEvent (
  455. IN PDEVICE_OBJECT DeviceObject,
  456. IN ULONG EventData
  457. )
  458. /*++
  459. Routine Description:
  460. This routine handles thermal events
  461. Arguments:
  462. DeviceObject - The device that received the event
  463. EventData - The event that just happened
  464. Return Value:
  465. NONE
  466. --*/
  467. {
  468. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  469. ULONG clear;
  470. ACPIThermalPrint( (
  471. ACPI_PRINT_THERMAL,
  472. deviceExtension,
  473. KeQueryInterruptTime(),
  474. "ACPIThermalEvent - Notify(%x)\n",
  475. EventData
  476. ) );
  477. //
  478. // Handle event type
  479. //
  480. clear = 0;
  481. switch (EventData) {
  482. case 0x80:
  483. //
  484. // Tempature changed notification
  485. //
  486. clear = THRM_WAIT_FOR_NOTIFY | THRM_TEMP;
  487. break;
  488. case 0x81:
  489. //
  490. // Trips points changed notification
  491. //
  492. clear = THRM_WAIT_FOR_NOTIFY | THRM_TEMP | THRM_TRIP_POINTS;
  493. break;
  494. default:
  495. break;
  496. }
  497. ACPIThermalLoop (deviceExtension, clear);
  498. }
  499. NTSTATUS
  500. ACPIThermalFanStartDevice(
  501. IN PDEVICE_OBJECT DeviceObject,
  502. IN PIRP Irp
  503. )
  504. /*++
  505. Routine Description:
  506. This is the routine that processes the start device for the fans
  507. Arguments:
  508. DeviceObject - The fan device
  509. Irp - The start request
  510. Return Value:
  511. NTSTATUS
  512. --*/
  513. {
  514. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  515. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
  516. UCHAR minorFunction = irpStack->MinorFunction;
  517. //
  518. // There is nothing to do when starting a fan --- it is really being
  519. // controlled by the thermal zones
  520. //
  521. deviceExtension->DeviceState = Started;
  522. //
  523. // Complete the request
  524. //
  525. Irp->IoStatus.Status = STATUS_SUCCESS;
  526. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  527. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  528. //
  529. // Let the world know
  530. //
  531. ACPIDevPrint( (
  532. ACPI_PRINT_THERMAL,
  533. deviceExtension,
  534. "(0x%08lx): %s = 0x%08lx\n",
  535. Irp,
  536. ACPIDebugGetIrpText(IRP_MJ_PNP, minorFunction),
  537. STATUS_SUCCESS
  538. ) );
  539. //
  540. // Done
  541. //
  542. return STATUS_SUCCESS;
  543. }
  544. VOID
  545. ACPIThermalLoop (
  546. IN PDEVICE_EXTENSION DeviceExtension,
  547. IN ULONG Clear
  548. )
  549. /*++
  550. Routine Description:
  551. This is the routine that processes all thermal events
  552. Arguments:
  553. DevExt - The device extension of the thermal zone
  554. Clear - Bits to clear
  555. Return Value:
  556. NTSTATUS
  557. --*/
  558. {
  559. BOOLEAN doneRequests;
  560. BOOLEAN lockHeld;
  561. KIRQL oldIrql;
  562. PTHRM_INFO thermal;
  563. NTSTATUS status;
  564. thermal = DeviceExtension->Thermal.Info;
  565. KeAcquireSpinLock (&DeviceExtension->Thermal.SpinLock, &oldIrql);
  566. lockHeld = TRUE;
  567. DeviceExtension->Thermal.Flags &= ~Clear;
  568. //
  569. // If we're not in the service loop, enter it now
  570. //
  571. if (!(DeviceExtension->Thermal.Flags & THRM_IN_SERVICE_LOOP)) {
  572. DeviceExtension->Thermal.Flags |= THRM_IN_SERVICE_LOOP;
  573. //
  574. // Loop while there's work to be done
  575. //
  576. for (; ;) {
  577. //
  578. // Synchronize the thermal zone
  579. //
  580. if (!lockHeld) {
  581. KeAcquireSpinLock(&DeviceExtension->Thermal.SpinLock, &oldIrql);
  582. lockHeld = TRUE;
  583. }
  584. //
  585. // If some work is pending, wait for it to complete
  586. //
  587. if (DeviceExtension->Thermal.Flags & THRM_BUSY) {
  588. break;
  589. }
  590. //
  591. // Make sure that the thermal zone is initialized. This must
  592. // be the first thing that we do in the loop!!!
  593. //
  594. if (!(DeviceExtension->Thermal.Flags & THRM_INITIALIZE) ) {
  595. DeviceExtension->Thermal.Flags |= THRM_BUSY | THRM_INITIALIZE;
  596. ACPISetDeviceWorker(
  597. DeviceExtension,
  598. THRM_COOLING_LEVEL | THRM_INITIALIZE
  599. );
  600. continue;
  601. }
  602. //
  603. // If the thermal zone mode needs updated, do it now
  604. //
  605. if (!(DeviceExtension->Thermal.Flags & THRM_MODE)) {
  606. DeviceExtension->Thermal.Flags |= THRM_BUSY | THRM_MODE;
  607. KeReleaseSpinLock (&DeviceExtension->Thermal.SpinLock, oldIrql);
  608. lockHeld = FALSE;
  609. status = ACPIGetNothingEvalIntegerAsync(
  610. DeviceExtension,
  611. PACKED_SCP,
  612. thermal->Mode,
  613. ACPIThermalComplete,
  614. DeviceExtension
  615. );
  616. if (status != STATUS_PENDING) {
  617. ACPIThermalComplete(
  618. NULL,
  619. status,
  620. NULL,
  621. DeviceExtension
  622. );
  623. }
  624. continue;
  625. }
  626. //
  627. // If the trip point infomation needs updated, get it. Note that
  628. // updating the trip points means that we also need to redo the
  629. // cooling level
  630. //
  631. if (!(DeviceExtension->Thermal.Flags & THRM_TRIP_POINTS)) {
  632. DeviceExtension->Thermal.Flags |= THRM_BUSY | THRM_TRIP_POINTS;
  633. ACPISetDeviceWorker( DeviceExtension, THRM_TRIP_POINTS );
  634. continue;
  635. }
  636. //
  637. // If the cooling level has changed,
  638. //
  639. if (!(DeviceExtension->Thermal.Flags & THRM_COOLING_LEVEL)) {
  640. DeviceExtension->Thermal.Flags |= THRM_BUSY | THRM_COOLING_LEVEL;
  641. ACPISetDeviceWorker (DeviceExtension, THRM_COOLING_LEVEL);
  642. continue;
  643. }
  644. //
  645. // Prevent the recursion that occurs when we complete an irp and
  646. // the completion routine is able to queue the IRP before we resume
  647. // the loop
  648. //
  649. if ( (DeviceExtension->Thermal.Flags & THRM_WAIT_FOR_NOTIFY) &&
  650. (DeviceExtension->Thermal.Flags & THRM_TEMP) ) {
  651. break;
  652. }
  653. //
  654. // If we don't have a temp, get it
  655. //
  656. if (!(DeviceExtension->Thermal.Flags & THRM_TEMP)) {
  657. //
  658. // Is the temp object not present?
  659. //
  660. #if DBG
  661. if (thermal->TempMethod == NULL) {
  662. ACPIInternalError( ACPI_THERMAL );
  663. }
  664. #endif
  665. thermal->Info.ThermalStamp += 1;
  666. DeviceExtension->Thermal.Flags |= THRM_BUSY | THRM_TEMP;
  667. KeReleaseSpinLock (&DeviceExtension->Thermal.SpinLock, oldIrql);
  668. lockHeld = FALSE;
  669. RtlZeroMemory (&thermal->Temp, sizeof(OBJDATA));
  670. thermal->Temp.dwDataType = OBJTYPE_UNKNOWN;
  671. status = AMLIAsyncEvalObject(
  672. thermal->TempMethod,
  673. &thermal->Temp,
  674. 0,
  675. NULL,
  676. ACPIThermalTempatureRead,
  677. DeviceExtension
  678. );
  679. if (status != STATUS_PENDING) {
  680. ACPIThermalTempatureRead(
  681. thermal->TempMethod,
  682. status,
  683. &thermal->Temp,
  684. DeviceExtension
  685. );
  686. }
  687. continue;
  688. }
  689. //
  690. // Everything is up to date. Check for a pending irp to see if
  691. // we can complete it.
  692. //
  693. //
  694. // Call into a child function to determine if we have completed
  695. // any requests
  696. //
  697. doneRequests = ACPIThermalCompletePendingIrps(
  698. DeviceExtension,
  699. thermal
  700. );
  701. if (doneRequests) {
  702. continue;
  703. }
  704. break;
  705. }
  706. //
  707. // No longer in the serivce loop
  708. //
  709. DeviceExtension->Thermal.Flags &= ~THRM_IN_SERVICE_LOOP;
  710. }
  711. KeReleaseSpinLock (&DeviceExtension->Thermal.SpinLock, oldIrql);
  712. return ;
  713. }
  714. VOID
  715. ACPIThermalPowerCallback (
  716. IN PDEVICE_EXTENSION DeviceExtension,
  717. IN PVOID Context,
  718. IN NTSTATUS Status
  719. )
  720. /*++
  721. Routine Description:
  722. This is the routine that is called after we have sent an internal
  723. power request to the device
  724. Arguments:
  725. DeviceExtension - the device that was set
  726. Context - Not used
  727. Status - Result
  728. Return Value:
  729. None
  730. --*/
  731. {
  732. if (!NT_SUCCESS(Status)) {
  733. ACPIDevPrint( (
  734. ACPI_PRINT_CRITICAL,
  735. DeviceExtension,
  736. "ACPIThermalPowerCallBack: failed power setting %x\n",
  737. Status
  738. ) );
  739. }
  740. }
  741. NTSTATUS
  742. ACPIThermalQueryWmiDataBlock(
  743. IN PDEVICE_OBJECT DeviceObject,
  744. IN PIRP Irp,
  745. IN ULONG GuidIndex,
  746. IN ULONG InstanceIndex,
  747. IN ULONG InstanceCount,
  748. IN OUT PULONG InstanceLengthArray,
  749. IN ULONG BufferAvail,
  750. OUT PUCHAR Buffer
  751. )
  752. /*++
  753. Routine Description:
  754. This routine is a callback into the driver to query for the contents of
  755. all instances of a data block. When the driver has finished filling the
  756. data block it must call WmiCompleteRequest to complete the irp. The
  757. driver can return STATUS_PENDING if the irp cannot be completed
  758. immediately.
  759. Arguments:
  760. DeviceObject is the device whose data block is being queried
  761. Irp is the Irp that makes this request
  762. GuidIndex is the index into the list of guids provided when the
  763. device registered
  764. InstanceCount is the number of instnaces expected to be returned for
  765. the data block.
  766. InstanceLengthArray is a pointer to an array of ULONG that returns the
  767. lengths of each instance of the data block. If this is NULL then
  768. there was not enough space in the output buffer to fufill the request
  769. so the irp should be completed with the buffer needed.
  770. BufferAvail on entry has the maximum size available to write the data
  771. blocks.
  772. Buffer on return is filled with the returned data blocks. Note that each
  773. instance of the data block must be aligned on a 8 byte boundry.
  774. Return Value:
  775. status
  776. --*/
  777. {
  778. NTSTATUS status;
  779. PDEVICE_EXTENSION deviceExtension;
  780. ULONG sizeNeeded;
  781. PTHRM_INFO info;
  782. PTHERMAL_INFORMATION thermalInfo;
  783. PTHERMAL_INFORMATION wmiThermalInfo;
  784. PAGED_CODE();
  785. deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  786. if (GuidIndex == 0) {
  787. //
  788. // ThermalZone temperature query
  789. //
  790. info = (PTHRM_INFO) deviceExtension->Thermal.Info;
  791. thermalInfo = &info->Info;
  792. wmiThermalInfo = (PTHERMAL_INFORMATION)Buffer;
  793. sizeNeeded = sizeof(THERMAL_INFORMATION);
  794. if (BufferAvail >= sizeNeeded) {
  795. // NOTE - Synchronize with thread getting this data
  796. *InstanceLengthArray = sizeNeeded;
  797. RtlCopyMemory(wmiThermalInfo, thermalInfo, sizeNeeded);
  798. status = STATUS_SUCCESS;
  799. } else {
  800. status = STATUS_BUFFER_TOO_SMALL;
  801. }
  802. } else {
  803. status = STATUS_WMI_GUID_NOT_FOUND;
  804. sizeNeeded = 0;
  805. }
  806. status = WmiCompleteRequest(
  807. DeviceObject,
  808. Irp,
  809. status,
  810. sizeNeeded,
  811. IO_NO_INCREMENT
  812. );
  813. return status;
  814. }
  815. NTSTATUS
  816. ACPIThermalQueryWmiRegInfo(
  817. IN PDEVICE_OBJECT DeviceObject,
  818. OUT ULONG *RegFlags,
  819. OUT PUNICODE_STRING InstanceName,
  820. OUT PUNICODE_STRING *RegistryPath,
  821. OUT PUNICODE_STRING MofResourceName,
  822. OUT PDEVICE_OBJECT *Pdo
  823. )
  824. /*++
  825. Routine Description:
  826. This routine is a callback into the driver to retrieve information about
  827. the guids being registered.
  828. Implementations of this routine may be in paged memory
  829. Arguments:
  830. DeviceObject is the device whose registration information is needed
  831. *RegFlags returns with a set of flags that describe all of the guids being
  832. registered for this device. If the device wants enable and disable
  833. collection callbacks before receiving queries for the registered
  834. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  835. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  836. the instance name is determined from the PDO associated with the
  837. device object. Note that the PDO must have an associated devnode. If
  838. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  839. name for the device. These flags are ORed into the flags specified
  840. by the GUIDREGINFO for each guid.
  841. InstanceName returns with the instance name for the guids if
  842. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  843. caller will call ExFreePool with the buffer returned.
  844. *RegistryPath returns with the registry path of the driver. This is
  845. required
  846. MofResourceName returns with the name of the MOF resource attached to
  847. the binary file. If the driver does not have a mof resource attached
  848. then this can be returned unmodified. If a value is returned then
  849. it is NOT freed.
  850. *Pdo returns with the device object for the PDO associated with this
  851. device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in
  852. *RegFlags.
  853. Return Value:
  854. status
  855. --*/
  856. {
  857. PAGED_CODE();
  858. if (AcpiRegistryPath.Buffer != NULL) {
  859. *RegistryPath = &AcpiRegistryPath;
  860. } else {
  861. *RegistryPath = NULL;
  862. }
  863. *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
  864. *Pdo = DeviceObject;
  865. return STATUS_SUCCESS;
  866. }
  867. NTSTATUS
  868. ACPIThermalStartDevice (
  869. IN PDEVICE_OBJECT DeviceObject,
  870. IN PIRP Irp
  871. )
  872. /*++
  873. Routine Description:
  874. This routine is called to start the thermal zone
  875. Arguments:
  876. DeviceObject - The device that is starting up
  877. Irp - The request
  878. Return Value:
  879. NTSTATUS
  880. --*/
  881. {
  882. NTSTATUS status;
  883. PDEVICE_EXTENSION deviceExtension;
  884. PWMILIB_CONTEXT wmilibContext;
  885. deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  886. ACPIDevPrint( (
  887. ACPI_PRINT_IRP,
  888. deviceExtension,
  889. "(0x%08lx): IRP_MN_START_DEVICE\n",
  890. Irp
  891. ) );
  892. status = ACPIInternalSetDeviceInterface (
  893. DeviceObject,
  894. (LPGUID) &GUID_DEVICE_THERMAL_ZONE
  895. );
  896. if (!NT_SUCCESS(status)) {
  897. ACPIDevPrint( (
  898. ACPI_PRINT_FAILURE,
  899. deviceExtension,
  900. "ACPIThermalStartDevice -> SetDeviceInterface = 0x%08lx\n",
  901. status
  902. ) );
  903. goto ACPIThermalStartDeviceExit;
  904. }
  905. ACPIRegisterForDeviceNotifications(
  906. DeviceObject,
  907. (PDEVICE_NOTIFY_CALLBACK) ACPIThermalEvent,
  908. (PVOID) DeviceObject
  909. );
  910. //
  911. // Initialize device object for WMILIB
  912. //
  913. wmilibContext = ExAllocatePoolWithTag(
  914. PagedPool,
  915. sizeof(WMILIB_CONTEXT),
  916. ACPI_THERMAL_POOLTAG
  917. );
  918. if (wmilibContext == NULL) {
  919. status = STATUS_INSUFFICIENT_RESOURCES;
  920. goto ACPIThermalStartDeviceExit;
  921. }
  922. RtlZeroMemory(wmilibContext, sizeof(WMILIB_CONTEXT));
  923. wmilibContext->GuidCount = ACPIThermalGuidCount;
  924. wmilibContext->GuidList = &ACPIThermalGuidList;
  925. wmilibContext->QueryWmiRegInfo = ACPIThermalQueryWmiRegInfo;
  926. wmilibContext->QueryWmiDataBlock = ACPIThermalQueryWmiDataBlock;
  927. deviceExtension->Thermal.WmilibContext = wmilibContext;
  928. //
  929. // Register for WMI events
  930. //
  931. status = IoWMIRegistrationControl(
  932. DeviceObject,
  933. WMIREG_ACTION_REGISTER
  934. );
  935. if (!NT_SUCCESS(status)) {
  936. deviceExtension->Thermal.WmilibContext = NULL;
  937. ExFreePool(wmilibContext);
  938. goto ACPIThermalStartDeviceExit;
  939. }
  940. //
  941. // Mark the device as started
  942. //
  943. deviceExtension->DeviceState = Started;
  944. //
  945. // Request that the device go to the D0 state
  946. // Note: that we don't block on this call, since we assume that
  947. // we can process thermal events asynchronously from being in
  948. // the D0 state. However, there may be a future occasion where
  949. // this is not true, so this makes the code more ready to handle
  950. // that case
  951. //
  952. status = ACPIDeviceInternalDeviceRequest(
  953. deviceExtension,
  954. PowerDeviceD0,
  955. NULL,
  956. NULL,
  957. 0
  958. );
  959. if (status == STATUS_PENDING) {
  960. status = STATUS_SUCCESS;
  961. }
  962. //
  963. // Start the thermal engine
  964. //
  965. ACPIThermalLoop( deviceExtension, THRM_TRIP_POINTS | THRM_MODE);
  966. ACPIThermalStartDeviceExit:
  967. Irp->IoStatus.Status = status;
  968. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  969. return status;
  970. }
  971. VOID
  972. EXPORT
  973. ACPIThermalTempatureRead (
  974. IN PNSOBJ AcpiObject,
  975. IN NTSTATUS Status,
  976. IN POBJDATA Result OPTIONAL,
  977. IN PVOID Context
  978. )
  979. /*++
  980. Routine Description:
  981. This routine is called to read the temperature. It is used a callback to
  982. an interpreter call
  983. Arguments:
  984. AcpiObject - The object that was executed
  985. Status - The status of the execution
  986. Result - The result of the execution
  987. Context - The device extension
  988. Return Value:
  989. NTSTATUS
  990. --*/
  991. {
  992. PTHRM_INFO Thrm;
  993. PDEVICE_EXTENSION deviceExtension;
  994. deviceExtension = Context;
  995. if (NT_SUCCESS(Status)) {
  996. ASSERT (Result->dwDataType == OBJTYPE_INTDATA);
  997. Thrm = deviceExtension->Thermal.Info;
  998. Thrm->Info.CurrentTemperature = (ULONG)Result->uipDataValue;
  999. AMLIFreeDataBuffs (Result, 1);
  1000. ACPIThermalPrint( (
  1001. ACPI_PRINT_THERMAL,
  1002. deviceExtension,
  1003. KeQueryInterruptTime(),
  1004. "Current Temperature is %d.%dK\n",
  1005. (Thrm->Info.CurrentTemperature / 10 ),
  1006. (Thrm->Info.CurrentTemperature % 10 )
  1007. ) );
  1008. }
  1009. ACPIThermalLoop (deviceExtension, THRM_BUSY);
  1010. }
  1011. VOID
  1012. ACPIThermalWorker (
  1013. IN PDEVICE_EXTENSION DeviceExtension,
  1014. IN ULONG Events
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. Worker thread for thermal regions
  1019. Arguments:
  1020. DeviceExtension - The device extension that we are manipulating
  1021. Events - What just happened
  1022. Return Value:
  1023. None
  1024. --*/
  1025. {
  1026. BOOLEAN TurnOn;
  1027. PTHRM_INFO Thrm;
  1028. NTSTATUS Status;
  1029. PNSOBJ ThrmObj;
  1030. PNSOBJ ALobj;
  1031. OBJDATA ALPackage;
  1032. OBJDATA ALElement;
  1033. PNSOBJ ACDevObj;
  1034. ULONG Index;
  1035. ULONG Level;
  1036. ULONG PackageSize;
  1037. ULONGLONG currentTime;
  1038. PAGED_CODE();
  1039. #if DBG
  1040. currentTime = KeQueryInterruptTime();
  1041. #endif
  1042. Thrm = DeviceExtension->Thermal.Info;
  1043. ThrmObj = DeviceExtension->AcpiObject;
  1044. //
  1045. // Initialization code
  1046. //
  1047. if (Events & THRM_INITIALIZE) {
  1048. ULONG names[10] = {
  1049. PACKED_AL0,
  1050. PACKED_AL1,
  1051. PACKED_AL2,
  1052. PACKED_AL3,
  1053. PACKED_AL4,
  1054. PACKED_AL5,
  1055. PACKED_AL6,
  1056. PACKED_AL7,
  1057. PACKED_AL8,
  1058. PACKED_AL9,
  1059. };
  1060. //
  1061. // Start the system in PASSIVE mode
  1062. //
  1063. Thrm->Mode = 1;
  1064. //
  1065. // Fetch all of the objects associated with each cooling level
  1066. //
  1067. for (Level = 0; Level < 10; Level++) {
  1068. //
  1069. // Find this level's active list
  1070. //
  1071. ALobj = ACPIAmliGetNamedChild(
  1072. ThrmObj,
  1073. names[Level]
  1074. );
  1075. if (ALobj == NULL) {
  1076. break;
  1077. }
  1078. //
  1079. // Remember that we have this object
  1080. //
  1081. Thrm->ActiveList[Level] = ALobj;
  1082. }
  1083. }
  1084. //
  1085. // Do this before we update the trips points
  1086. //
  1087. if ( (Events & THRM_COOLING_LEVEL) ) {
  1088. RtlZeroMemory (&ALPackage, sizeof(OBJDATA));
  1089. RtlZeroMemory (&ALElement, sizeof(OBJDATA));
  1090. for (Level=0; Level < 10; Level++) {
  1091. //
  1092. // Is there a cooling object?
  1093. //
  1094. ALobj = Thrm->ActiveList[Level];
  1095. if (ALobj == NULL) {
  1096. break;
  1097. }
  1098. //
  1099. // Evalute the list to its package
  1100. //
  1101. Status = AMLIEvalNameSpaceObject(
  1102. ALobj,
  1103. &ALPackage,
  1104. 0,
  1105. NULL
  1106. );
  1107. if (!NT_SUCCESS(Status)) {
  1108. break;
  1109. }
  1110. //
  1111. // Remember how large the package is
  1112. //
  1113. PackageSize = ((PPACKAGEOBJ) ALPackage.pbDataBuff)->dwcElements;
  1114. //
  1115. // Walk the names in the package
  1116. //
  1117. for (Index = 0; Index < PackageSize; Index += 1) {
  1118. //
  1119. // Grab the object name
  1120. Status = AMLIEvalPkgDataElement(
  1121. &ALPackage,
  1122. Index,
  1123. &ALElement
  1124. );
  1125. if (!NT_SUCCESS(Status)) {
  1126. break;
  1127. }
  1128. //
  1129. // Determine if we are going to the device on or off
  1130. //
  1131. TurnOn = (Level >= Thrm->CoolingLevel);
  1132. //
  1133. // Tell the world
  1134. //
  1135. #if DBG
  1136. ACPIThermalPrint( (
  1137. ACPI_PRINT_THERMAL,
  1138. DeviceExtension,
  1139. currentTime,
  1140. "ACPIThermalWorker: Turn %s %s\n",
  1141. TurnOn ? "on " : "off",
  1142. ALElement.pbDataBuff
  1143. ) );
  1144. #endif
  1145. //
  1146. // Find this device of this name
  1147. //
  1148. Status = AMLIGetNameSpaceObject(
  1149. ALElement.pbDataBuff,
  1150. ThrmObj,
  1151. &ACDevObj,
  1152. 0
  1153. );
  1154. AMLIFreeDataBuffs (&ALElement, 1);
  1155. if (!NT_SUCCESS(Status) || !ACDevObj->Context) {
  1156. break;
  1157. }
  1158. //
  1159. // Turn it on/off
  1160. //
  1161. ACPIDeviceInternalDeviceRequest (
  1162. (PDEVICE_EXTENSION) ACDevObj->Context,
  1163. TurnOn ? PowerDeviceD0 : PowerDeviceD3,
  1164. ACPIThermalPowerCallback,
  1165. NULL,
  1166. 0
  1167. );
  1168. }
  1169. AMLIFreeDataBuffs (&ALPackage, 1);
  1170. }
  1171. }
  1172. //
  1173. // If the trip points need to be re-freshed, go read them
  1174. //
  1175. if (Events & THRM_TRIP_POINTS) {
  1176. ULONG names[10] = {
  1177. PACKED_AC0,
  1178. PACKED_AC1,
  1179. PACKED_AC2,
  1180. PACKED_AC3,
  1181. PACKED_AC4,
  1182. PACKED_AC5,
  1183. PACKED_AC6,
  1184. PACKED_AC7,
  1185. PACKED_AC8,
  1186. PACKED_AC9,
  1187. };
  1188. //
  1189. // Get the thermal constants, passive & critical values
  1190. //
  1191. ACPIGetIntegerSync(
  1192. DeviceExtension,
  1193. PACKED_TC1,
  1194. &Thrm->Info.ThermalConstant1,
  1195. NULL
  1196. );
  1197. #if DBG
  1198. ACPIThermalPrint( (
  1199. ACPI_PRINT_THERMAL,
  1200. DeviceExtension,
  1201. currentTime,
  1202. "ACPIThermalWorker - ThermalConstant1 = %x\n",
  1203. Thrm->Info.ThermalConstant1
  1204. ) );
  1205. #endif
  1206. ACPIGetIntegerSync(
  1207. DeviceExtension,
  1208. PACKED_TC2,
  1209. &Thrm->Info.ThermalConstant2,
  1210. NULL
  1211. );
  1212. #if DBG
  1213. ACPIThermalPrint( (
  1214. ACPI_PRINT_THERMAL,
  1215. DeviceExtension,
  1216. currentTime,
  1217. "ACPIThermalWorker - ThermalConstant2 = %x\n",
  1218. Thrm->Info.ThermalConstant2
  1219. ) );
  1220. #endif
  1221. ACPIGetIntegerSync(
  1222. DeviceExtension,
  1223. PACKED_PSV,
  1224. &Thrm->Info.PassiveTripPoint,
  1225. NULL
  1226. );
  1227. #if DBG
  1228. ACPIThermalPrint( (
  1229. ACPI_PRINT_THERMAL,
  1230. DeviceExtension,
  1231. currentTime,
  1232. "ACPIThermalWorker - PassiveTripPoint = %d.%dK\n",
  1233. (Thrm->Info.PassiveTripPoint / 10),
  1234. (Thrm->Info.PassiveTripPoint % 10)
  1235. ) );
  1236. #endif
  1237. ACPIGetIntegerSync(
  1238. DeviceExtension,
  1239. PACKED_CRT,
  1240. &Thrm->Info.CriticalTripPoint,
  1241. NULL
  1242. );
  1243. #if DBG
  1244. ACPIThermalPrint( (
  1245. ACPI_PRINT_THERMAL,
  1246. DeviceExtension,
  1247. currentTime,
  1248. "ACPIThermalWorker - CriticalTripPoint = %d.%dK\n",
  1249. (Thrm->Info.CriticalTripPoint / 10),
  1250. (Thrm->Info.CriticalTripPoint % 10)
  1251. ) );
  1252. #endif
  1253. ACPIGetIntegerSync(
  1254. DeviceExtension,
  1255. PACKED_TSP,
  1256. &Thrm->Info.SamplingPeriod,
  1257. NULL
  1258. );
  1259. #if DBG
  1260. ACPIThermalPrint( (
  1261. ACPI_PRINT_THERMAL,
  1262. DeviceExtension,
  1263. currentTime,
  1264. "ACPIThermalWorker - SamplingPeriod = %x\n",
  1265. Thrm->Info.SamplingPeriod
  1266. ) );
  1267. #endif
  1268. //
  1269. // Get the active cooling limits
  1270. //
  1271. for (Level=0; Level < 10; Level++) {
  1272. Status = ACPIGetIntegerSync(
  1273. DeviceExtension,
  1274. names[Level],
  1275. &Thrm->Info.ActiveTripPoint[Level],
  1276. NULL
  1277. );
  1278. if (!NT_SUCCESS(Status)) {
  1279. break;
  1280. }
  1281. #if DBG
  1282. ACPIThermalPrint( (
  1283. ACPI_PRINT_THERMAL,
  1284. DeviceExtension,
  1285. currentTime,
  1286. "ACPIThermalWorker - Active Cooling Level %x = %d.%dK\n",
  1287. Level,
  1288. (Thrm->Info.ActiveTripPoint[Level] / 10),
  1289. (Thrm->Info.ActiveTripPoint[Level] % 10)
  1290. ) );
  1291. #endif
  1292. }
  1293. Thrm->Info.ActiveTripPointCount = (UCHAR) Level;
  1294. //
  1295. // Clean these variables for reuse
  1296. //
  1297. RtlZeroMemory (&ALPackage, sizeof(OBJDATA));
  1298. RtlZeroMemory (&ALElement, sizeof(OBJDATA));
  1299. //
  1300. // Assume an affinity of 0
  1301. //
  1302. Thrm->Info.Processors = 0;
  1303. //
  1304. // Get the passive cooling affinity object
  1305. //
  1306. ALobj = ACPIAmliGetNamedChild(
  1307. ThrmObj,
  1308. PACKED_PSL
  1309. );
  1310. if (ALobj != NULL) {
  1311. //
  1312. // Evaluate the processor affinity object
  1313. //
  1314. Status = AMLIEvalNameSpaceObject(
  1315. ALobj,
  1316. &ALPackage,
  1317. 0,
  1318. NULL
  1319. );
  1320. if (!NT_SUCCESS(Status)) {
  1321. goto ACPIThermalWorkerExit;
  1322. }
  1323. //
  1324. // Remember how large the package is
  1325. //
  1326. PackageSize = ((PPACKAGEOBJ) ALPackage.pbDataBuff)->dwcElements;
  1327. //
  1328. // Walk the elements in the package
  1329. //
  1330. for (Index = 0; Index < PackageSize ;Index++) {
  1331. Status = AMLIEvalPkgDataElement(
  1332. &ALPackage,
  1333. Index,
  1334. &ALElement
  1335. );
  1336. if (!NT_SUCCESS(Status)) {
  1337. break;
  1338. }
  1339. //
  1340. // Find this device of this name
  1341. //
  1342. Status = AMLIGetNameSpaceObject(
  1343. ALElement.pbDataBuff,
  1344. NULL,
  1345. &ACDevObj,
  1346. 0
  1347. );
  1348. //
  1349. // No longer need this information
  1350. //
  1351. AMLIFreeDataBuffs (&ALElement, 1);
  1352. //
  1353. // Did we find what we wanted?
  1354. //
  1355. if (!NT_SUCCESS(Status) ) {
  1356. break;
  1357. }
  1358. //
  1359. // Get the correct affinity mask. We call another
  1360. // function since that one requires a spinlock which
  1361. // don't want to take in this worker function
  1362. //
  1363. ACPIThermalCalculateProcessorMask( ACDevObj, Thrm );
  1364. }
  1365. //
  1366. // We are done with the package
  1367. //
  1368. AMLIFreeDataBuffs (&ALPackage, 1);
  1369. }
  1370. }
  1371. ACPIThermalWorkerExit:
  1372. //
  1373. // done, check for next work
  1374. //
  1375. ACPIThermalLoop (DeviceExtension, THRM_TEMP | THRM_BUSY);
  1376. }
  1377. NTSTATUS
  1378. ACPIThermalWmi(
  1379. IN PDEVICE_OBJECT DeviceObject,
  1380. IN PIRP Irp
  1381. )
  1382. {
  1383. NTSTATUS status;
  1384. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1385. PIO_STACK_LOCATION irpSp;
  1386. PWMILIB_CONTEXT wmilibContext;
  1387. SYSCTL_IRP_DISPOSITION disposition;
  1388. wmilibContext = deviceExtension->Thermal.WmilibContext;
  1389. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1390. status = WmiSystemControl(
  1391. wmilibContext,
  1392. DeviceObject,
  1393. Irp,
  1394. &disposition
  1395. );
  1396. switch (disposition) {
  1397. case IrpProcessed:
  1398. break;
  1399. case IrpNotCompleted:
  1400. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1401. break;
  1402. case IrpNotWmi:
  1403. case IrpForward:
  1404. default:
  1405. status = ACPIDispatchForwardIrp(DeviceObject, Irp);
  1406. break;
  1407. }
  1408. return status;
  1409. }