source: branches/branch-1-0/src/helpers/acpih.c

Last change on this file was 443, checked in by rlwalsh, 6 years ago

acpih: add CPU temperature support; update battery support
patch from David Azarewicz

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 15.0 KB
RevLine 
[323]1
2/*
3 *@@sourcefile apcih.c:
4 * contains helpers for accessing ACPI.
5 *
6 * Usage: All OS/2 programs.
7 *
8 * Function prefixes:
9 * -- acpih* ACPI helper functions
10 *
11 * Note: Version numbering in this file relates to XWorkplace version
12 * numbering.
13 *
14 *@@header "helpers\acpih.h"
15 *@@added V1.0.5 (2006-06-26) [pr]
16 */
17
18/*
[416]19 * Copyright (C) 2006-2014 Paul Ratcliffe.
[323]20 * This file is part of the "XWorkplace helpers" source package.
21 * This is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published
23 * by the Free Software Foundation, in version 2 as it comes in the
24 * "COPYING" file of the XWorkplace main distribution.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 */
30
31#define OS2EMX_PLAIN_CHAR
32 // this is needed for "os2emx.h"; if this is defined,
33 // emx will define PSZ as _signed_ char, otherwise
34 // as unsigned char
35
36#define INCL_DOSMODULEMGR
37#define INCL_DOSERRORS
38#include <os2.h>
39
40#include "setup.h" // code generation and debugging options
41
[406]42#include "helpers\apmh.h" // @@added V1.0.9 (2012-02-20) [slevine]
[323]43#include "helpers\acpih.h"
44#include "helpers\standards.h"
45
46/* ******************************************************************
47 *
48 * Globals
49 *
50 ********************************************************************/
51
[380]52HMODULE G_hmodACPI = NULLHANDLE;
53ULONG G_ulCount = 0;
[406]54// @@added V1.0.9 (2012-02-20) [slevine]: additional ACPI support, code from David Azarewicz
55ACPI_HANDLE G_ahAC = 0;
[443]56ACPI_HANDLE G_ahTemp = 0;
57ULONG G_uiTempWalked = 0;
[406]58#define MAX_BATTERY_COUNT 4
[443]59struct _gahbat_ {
60 ACPI_HANDLE ahBat;
61 ULONG ulLastFull;
62} G_Bat[MAX_BATTERY_COUNT];
[406]63ULONG G_uiBatteryCount = 0;
64ULONG G_uiAlreadyWalked = 0;
[323]65
[429]66ACPITKSTARTAPI *pAcpiStartApi = NULL;
67ACPITKENDAPI *pAcpiEndApi = NULL;
68ACPITKGOTOSLEEP *pAcpiGoToSleep = NULL;
[323]69
[406]70ACPITKGETOBJECTINFOALLOC *pAcpiTkGetObjectInfoAlloc = NULL;
71ACPITKGETHANDLE *pAcpiTkGetHandle = NULL;
72ACPITKOSFREE *pAcpiTkOsFree = NULL;
73ACPITKWALKNAMESPACE *pAcpiTkWalkNamespace = NULL;
74ACPITKEVALUATEOBJECT *pAcpiTkEvaluateObject = NULL;
[414]75// @@added V1.0.9 (2012-12-10) [slevine]: additional ACPI support
76ACPITKPREPARETOSLEEP *pAcpiTkPrepareToSleep = NULL;
[406]77
[323]78/*
79 *@@category: Helpers\Control program helpers\ACPI
80 * See acpih.c.
81 */
82
83/*
84 *@@ acpihOpen:
85 * resolves the ACPI entrypoints and loads the ACPI DLL.
[416]86 *
87 *@@changed V1.0.10 (2014-08-30) [dazarewicz]: Call ACPI start API func.
[323]88 */
89
90APIRET acpihOpen(ACPI_API_HANDLE *phACPI)
91{
92 APIRET arc = NO_ERROR;
93
[380]94 if (!G_hmodACPI)
[406]95 {
[323]96 if (!(arc = DosLoadModule(NULL,
97 0,
98 "ACPI32",
[380]99 &G_hmodACPI)))
[323]100 {
[380]101 arc = DosQueryProcAddr(G_hmodACPI,
[429]102 ORD_ACPITKSTARTAPI,
[323]103 NULL,
104 (PFN *) &pAcpiStartApi);
105 if (!arc)
[380]106 arc = DosQueryProcAddr(G_hmodACPI,
[429]107 ORD_ACPITKENDAPI,
[410]108 NULL,
109 (PFN *) &pAcpiEndApi);
[323]110
111 if (!arc)
[380]112 arc = DosQueryProcAddr(G_hmodACPI,
[429]113 ORD_ACPITKGOTOSLEEP,
[410]114 NULL,
115 (PFN *) &pAcpiGoToSleep);
[323]116 if (arc)
117 {
[380]118 DosFreeModule(G_hmodACPI);
119 G_hmodACPI = NULLHANDLE;
[327]120 pAcpiStartApi = NULL;
121 pAcpiEndApi = NULL;
122 pAcpiGoToSleep = NULL;
[323]123 return(arc);
124 }
[406]125
126 // @@added V1.0.9 (2012-02-20) [slevine]: additional ACPI support, code from David Azarewicz
[429]127 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKGETOBJECTINFOALLOC3,
[410]128 NULL, (PFN *) &pAcpiTkGetObjectInfoAlloc);
129 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKGETHANDLE,
130 NULL, (PFN *) &pAcpiTkGetHandle);
131 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKOSFREE,
132 NULL, (PFN *) &pAcpiTkOsFree);
133 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKWALKNAMESPACE,
134 NULL, (PFN *) &pAcpiTkWalkNamespace);
135 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKEVALUATEOBJECT,
136 NULL, (PFN *) &pAcpiTkEvaluateObject);
[414]137 // @@added V1.0.9 (2012-12-10) [slevine]: additional ACPI support
138 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKPREPARETOSLEEP,
139 NULL, (PFN *) &pAcpiTkPrepareToSleep);
[323]140 }
[406]141 }
[323]142
143 if (arc)
144 return(arc);
145 else
[380]146 {
[414]147 G_ulCount++;
[409]148
[323]149 return(pAcpiStartApi(phACPI));
[380]150 }
[323]151}
152
153/*
[416]154 *@@ acpihPrepareToSleep:
155 * Prepares the system to sleep or power off
156 *
157 *@@added V1.0.10 (2014-08-30) [dazarewicz]
158 */
159
160VOID acpihPrepareToSleep(UCHAR ucState)
161{
162 // @@added V1.0.9 (2012-12-10) [slevine]: use AcpiTkPrepareToSleep rather than workaround
163 /* This function does not exist in older versions of acpi
164 * As a result the shutdown attempt will usually hang because
165 * the required code has not been committed into memory.
166 */
167 if (pAcpiTkPrepareToSleep)
168 pAcpiTkPrepareToSleep(ucState);
169}
170
171/*
[323]172 *@@ acpihClose:
173 * unloads the ACPI DLL.
174 */
175
176VOID acpihClose(ACPI_API_HANDLE *phACPI)
177{
178 if (pAcpiEndApi)
[380]179 {
[323]180 pAcpiEndApi(phACPI);
[380]181 G_ulCount--;
182 }
183
184 if (!G_ulCount)
185 {
186 DosFreeModule(G_hmodACPI);
187 G_hmodACPI = NULLHANDLE;
188 pAcpiStartApi = NULL;
189 pAcpiEndApi = NULL;
190 pAcpiGoToSleep = NULL;
[414]191 // @@added V1.0.9 (2012-12-10) [slevine]: additional ACPI support
192 pAcpiTkPrepareToSleep = NULL;
[380]193 }
[323]194}
195
196/*
197 *@@ acpihGoToSleep:
198 * changes the Power State.
199 */
200
201APIRET acpihGoToSleep(ACPI_API_HANDLE *phACPI, UCHAR ucState)
202{
203 if (pAcpiGoToSleep)
204 return(pAcpiGoToSleep(phACPI, ucState));
205 else
206 return(ERROR_PROTECTION_VIOLATION);
207}
208
[443]209 // VAC 3.08 long long compatibility support
210#ifdef INCL_LONGLONG // VAC 3.6.5 - compiler supports long long
211#define OBJECT_VALUE(index) (Object[index].Integer.Value)
212#define OBJ_VALUE(index) (pObj[index].Integer.Value)
213#else // VAC 3.08 - compiler does not support long long
214#define OBJECT_VALUE(index) (Object[index].Integer.Value.ulLo)
215#define OBJ_VALUE(index) (pObj[index].Integer.Value.ulLo)
216#endif
[406]217
218/**
219 *@@ AcpiCallbackWidget:
220 * ACPI callback helper for battery and power status queries.
221 * Code provided by David Azarewicz
222 *@@added V1.0.9 (2012-02-20) [slevine]: code from David Azarewicz
[416]223 *@@changed V1.0.10 (2014-08-30) [dazarewicz]: release resources correctly
[406]224 */
225
[416]226ACPI_STATUS APIENTRY AcpiCallbackWidget( ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context, void **ReturnValue )
[406]227{
[410]228 ACPI_DEVICE_INFO *pDevInfo = NULL;
[443]229 ACPI_BUFFER Buffer;
230 ACPI_OBJECT *pObj, Object[25];
[406]231
[416]232 if (pAcpiTkGetObjectInfoAlloc( ObjHandle, &pDevInfo ) != AE_OK)
233 return AE_OK;
234
235 do
[406]236 {
[410]237 if (pDevInfo->Type != ACPI_TYPE_DEVICE)
[416]238 break;
[406]239
[410]240 if (!(pDevInfo->Valid & ACPI_VALID_HID))
[416]241 break;
[410]242
243 if (!pDevInfo->HardwareId.String)
[416]244 break;
[410]245
246 if (strncmp(pDevInfo->HardwareId.String, "ACPI0003", 8) == 0)
[406]247 { /* AC Power */
[416]248 if (pAcpiTkGetHandle(ObjHandle, "_PSR", &G_ahAC))
[410]249 G_ahAC = 0;
250
[416]251 break;
[406]252 }
253
[410]254 if (strncmp(pDevInfo->HardwareId.String, "PNP0C0A", 7) == 0)
[406]255 { /* Smart battery */
[410]256 if (G_uiBatteryCount < MAX_BATTERY_COUNT)
[443]257 {
258 G_Bat[G_uiBatteryCount].ahBat = ObjHandle;
259 G_Bat[G_uiBatteryCount].ulLastFull = 0xffffffff;
[410]260
[443]261 /* Get static battery inFormation */
262 Buffer.Length = sizeof(Object);
263 Buffer.Pointer = Object;
264 if (pAcpiTkEvaluateObject(ObjHandle, "_BIX", NULL, &Buffer) == AE_OK)
265 {
266 pObj = Buffer.Pointer;
267 pObj = (ACPI_OBJECT *)pObj[0].Package.Elements;
268 G_Bat[G_uiBatteryCount].ulLastFull = (UINT32)OBJ_VALUE(3);
269 }
270 else
271 {
272 Buffer.Length = sizeof(Object);
273 Buffer.Pointer = Object;
274 if (pAcpiTkEvaluateObject(ObjHandle, "_BIF", NULL, &Buffer) == AE_OK)
275 {
276 pObj = Buffer.Pointer;
277 pObj = (ACPI_OBJECT *)pObj[0].Package.Elements;
278 G_Bat[G_uiBatteryCount].ulLastFull = (UINT32)OBJ_VALUE(2);
279 }
280 }
281
282 G_uiBatteryCount++;
283 }
284
[416]285 break;
[406]286 }
[416]287 } while (0);
[406]288
[410]289 if (pDevInfo)
290 pAcpiTkOsFree(pDevInfo);
[406]291
292 return AE_OK;
293}
294
295/**
296 *@@ acpihGetPowerStatus:
297 * Returns power and battery status in caller provided buffers.
298 * Returns zero if success, non-zero if fail.
299 * Code provided by David Azarewicz
300 *@@added V1.0.9 (2012-02-20) [slevine]: code from David Azarewicz
[416]301 *@@changed V1.0.10 (2014-08-30) [dazarewicz]: tidies
[406]302 */
[414]303
[406]304APIRET acpihGetPowerStatus(PAPM pApm, PBOOL pfChanged)
305{
306 ACPI_STATUS Status;
307 ACPI_BUFFER Result;
[443]308 ACPI_OBJECT *pObj, Object[20];
[406]309 UINT32 uiI;
[443]310 ULONG ulTmp, BRemaining;
[406]311 BOOL fChanged;
312
[414]313 /* Make sure all the functions we need have valid pointers.
314 * @@added V1.0.9 (2012-02-25) [dazarewicz]: additional ACPI support
315 */
316 if ( (pAcpiTkWalkNamespace == NULL)
317 || (pAcpiTkGetObjectInfoAlloc == NULL)
318 || (pAcpiTkGetHandle == NULL)
319 || (pAcpiTkOsFree == NULL)
320 || (pAcpiTkEvaluateObject == NULL)
321 || (pApm == NULL)
322 )
[410]323 return 1;
[406]324
325 if (!G_uiAlreadyWalked)
326 {
[410]327 Status = pAcpiTkWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
328 ACPI_UINT32_MAX, AcpiCallbackWidget,
329 pApm, NULL);
[406]330 G_uiAlreadyWalked = 1;
331 }
332
333 fChanged = FALSE;
334
335 if (G_ahAC)
336 {
[409]337 // Have _PSR
[406]338 Result.Length = sizeof(Object);
339 Result.Pointer = Object;
340 Status = pAcpiTkEvaluateObject(G_ahAC, NULL, NULL, &Result);
[409]341 if (Status != AE_OK)
[414]342 ulTmp = 2; // assume on backup power
343 else if (Object[0].Type != ACPI_TYPE_INTEGER)
344 ulTmp = 2; // assume on backup power
[410]345 else
346 ulTmp = (UINT32)OBJECT_VALUE(0);
347
348 if (pApm->fUsingAC != (BYTE) ulTmp)
[406]349 {
[410]350 pApm->fUsingAC = (BYTE) ulTmp;
[406]351 fChanged = TRUE;
352 }
353 }
354
[410]355 for (uiI=0; uiI < G_uiBatteryCount; uiI++)
[406]356 {
[443]357 if (G_Bat[uiI].ahBat == 0)
[410]358 continue;
[443]359 if (G_Bat[uiI].ulLastFull == 0xffffffff)
[406]360 continue;
361
362 Result.Length = sizeof(Object);
363 Result.Pointer = Object;
[414]364 // Get battery status
[443]365 Status = pAcpiTkEvaluateObject(G_Bat[uiI].ahBat, "_BST", NULL, &Result);
[406]366 if (Status != AE_OK)
367 {
[443]368 G_Bat[uiI].ahBat = 0;
[406]369 continue;
370 }
371
[443]372 pObj = Result.Pointer;
373 pObj = (ACPI_OBJECT *)pObj[0].Package.Elements; // Battery status package
[416]374 BRemaining = (UINT32)OBJ_VALUE(2);
[406]375
[409]376 // If battery units are mWh or mAh
[414]377 // If not, it is a percentage
[443]378 if (BRemaining == 0xffffffff)
379 continue;
[406]380
[443]381 if (BRemaining > (G_Bat[uiI].ulLastFull >> 1)) // > 50% is high. < 50% is low
382 ulTmp = 1; // High
383 else
384 ulTmp = 2; // Low
[409]385
[443]386 if (OBJ_VALUE(0) & 4)
387 ulTmp = 2; // Critical
[409]388
[443]389 // If battery charging - it can't be critical
390 if (OBJ_VALUE(0) & 2)
391 ulTmp = 3; // Charging
[406]392
[443]393 if (pApm->bBatteryStatus != ulTmp)
394 {
395 pApm->bBatteryStatus = (BYTE)ulTmp;
396 fChanged = TRUE;
397 }
[410]398
[443]399 ulTmp = 0;
400 if (G_Bat[uiI].ulLastFull)
401 ulTmp = (BRemaining*100) / G_Bat[uiI].ulLastFull;
402 if (ulTmp > 100)
403 ulTmp = 100;
404
405 if (pApm->bBatteryLife != ulTmp)
406 {
407 pApm->bBatteryLife = (BYTE) ulTmp;
408 fChanged = TRUE;
[406]409 }
410 }
411
[410]412 if (pfChanged)
413 *pfChanged = fChanged;
414
[406]415 pApm->fAlreadyRead = FALSE;
416 return 0;
[443]417}
[406]418
[410]419#undef OBJECT_VALUE
420#undef OBJ_VALUE
[406]421
422/*
423 *@@ acpihHasBattery:
424 * quick'n'dirty helper which returns TRUE only
425 * if ACPI is supported on the system and the
426 * system actually has a battery (i.e. is a laptop).
427 * Code provided by David Azarewicz.
428 * @@added V1.0.9 (2012-02-20) [slevine]: code from David Azarewicz
429 */
430BOOL acpihHasBattery(VOID)
431{
432 BOOL brc = FALSE;
433 ACPI_API_HANDLE hACPI;
434 APM Apm;
435
436 if (!acpihOpen(&hACPI))
437 {
438 Apm.bBatteryStatus = 0xff;
[410]439 if (!acpihGetPowerStatus(&Apm, NULL))
440 brc = (Apm.bBatteryStatus != 0xFF);
441
[406]442 acpihClose(&hACPI);
443 }
444
445 return brc;
446}
[410]447
[443]448/**
449 *@@ AcpiCallbackTemperature:
450 * ACPI callback helper for CPU Temperature
451 * Code provided by David Azarewicz
452 */
453
454ACPI_STATUS APIENTRY AcpiCallbackTemperature( ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context, void **ReturnValue )
455{
456 if (G_ahTemp)
457 return AE_OK;
458
459 if (pAcpiTkGetHandle(ObjHandle, "_TMP", &G_ahTemp))
460 G_ahTemp = 0;
461
462 return AE_OK;
463}
464
465/*
466 *@@ acpihGetCpuTemp:
467 * Code provided by David Azarewicz.
468 */
469ULONG acpihGetCpuTemp(ACPI_API_HANDLE *phACPI)
470{
471 ACPI_STATUS Status;
472 ACPI_BUFFER Result;
473 ACPI_OBJECT Object;
474 ULONG ulTemp = 0;
475
476 /* Make sure all the functions we need have valid pointers. */
477 if ( (pAcpiTkWalkNamespace == NULL)
478 || (pAcpiTkGetHandle == NULL)
479 || (pAcpiTkEvaluateObject == NULL)
480 )
481 return 1;
482
483 if (!G_uiTempWalked)
484 {
485 Status = pAcpiTkWalkNamespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
486 ACPI_UINT32_MAX, AcpiCallbackTemperature,
487 NULL, NULL);
488 G_uiTempWalked = 1;
489 }
490
491 if (G_ahTemp)
492 {
493 Result.Length = sizeof(Object);
494 Result.Pointer = &Object;
495 Status = pAcpiTkEvaluateObject(G_ahTemp, NULL, NULL, &Result);
496 if (Status == AE_OK)
497 ulTemp = (Object.Integer.Value - 2732) / 10;
498 }
499
500 return ulTemp;
501}
502
Note: See TracBrowser for help on using the repository browser.