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

Last change on this file since 420 was 416, checked in by pr, 11 years ago

ACPI power off changes from David.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
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/*
19 * Copyright (C) 2006-2014 Paul Ratcliffe.
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
42#include "helpers\apmh.h" // @@added V1.0.9 (2012-02-20) [slevine]
43#include "helpers\acpih.h"
44#include "helpers\standards.h"
45
46/* ******************************************************************
47 *
48 * Globals
49 *
50 ********************************************************************/
51
52HMODULE G_hmodACPI = NULLHANDLE;
53ULONG G_ulCount = 0;
54// @@added V1.0.9 (2012-02-20) [slevine]: additional ACPI support, code from David Azarewicz
55ACPI_HANDLE G_ahAC = 0;
56#define MAX_BATTERY_COUNT 4
57ACPI_HANDLE G_ahBat[MAX_BATTERY_COUNT];
58ULONG G_uiBatteryCount = 0;
59ULONG G_uiAlreadyWalked = 0;
60
61ACPISTARTAPI *pAcpiStartApi = NULL;
62ACPIENDAPI *pAcpiEndApi = NULL;
63ACPIGOTOSLEEP *pAcpiGoToSleep = NULL;
64
65ACPITKGETOBJECTINFOALLOC *pAcpiTkGetObjectInfoAlloc = NULL;
66ACPITKGETHANDLE *pAcpiTkGetHandle = NULL;
67ACPITKOSFREE *pAcpiTkOsFree = NULL;
68ACPITKWALKNAMESPACE *pAcpiTkWalkNamespace = NULL;
69ACPITKEVALUATEOBJECT *pAcpiTkEvaluateObject = NULL;
70// @@added V1.0.9 (2012-12-10) [slevine]: additional ACPI support
71ACPITKPREPARETOSLEEP *pAcpiTkPrepareToSleep = NULL;
72
73/*
74 *@@category: Helpers\Control program helpers\ACPI
75 * See acpih.c.
76 */
77
78/*
79 *@@ acpihOpen:
80 * resolves the ACPI entrypoints and loads the ACPI DLL.
81 *
82 *@@changed V1.0.10 (2014-08-30) [dazarewicz]: Call ACPI start API func.
83 */
84
85APIRET acpihOpen(ACPI_API_HANDLE *phACPI)
86{
87 APIRET arc = NO_ERROR;
88
89 if (!G_hmodACPI)
90 {
91 if (!(arc = DosLoadModule(NULL,
92 0,
93 "ACPI32",
94 &G_hmodACPI)))
95 {
96 arc = DosQueryProcAddr(G_hmodACPI,
97 ORD_ACPISTARTAPI,
98 NULL,
99 (PFN *) &pAcpiStartApi);
100 if (!arc)
101 arc = DosQueryProcAddr(G_hmodACPI,
102 ORD_ACPIENDAPI,
103 NULL,
104 (PFN *) &pAcpiEndApi);
105
106 if (!arc)
107 arc = DosQueryProcAddr(G_hmodACPI,
108 ORD_ACPIGOTOSLEEP,
109 NULL,
110 (PFN *) &pAcpiGoToSleep);
111 if (arc)
112 {
113 DosFreeModule(G_hmodACPI);
114 G_hmodACPI = NULLHANDLE;
115 pAcpiStartApi = NULL;
116 pAcpiEndApi = NULL;
117 pAcpiGoToSleep = NULL;
118 return(arc);
119 }
120
121 // @@added V1.0.9 (2012-02-20) [slevine]: additional ACPI support, code from David Azarewicz
122 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKGETOBJECTINFOALLOC,
123 NULL, (PFN *) &pAcpiTkGetObjectInfoAlloc);
124 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKGETHANDLE,
125 NULL, (PFN *) &pAcpiTkGetHandle);
126 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKOSFREE,
127 NULL, (PFN *) &pAcpiTkOsFree);
128 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKWALKNAMESPACE,
129 NULL, (PFN *) &pAcpiTkWalkNamespace);
130 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKEVALUATEOBJECT,
131 NULL, (PFN *) &pAcpiTkEvaluateObject);
132 // @@added V1.0.9 (2012-12-10) [slevine]: additional ACPI support
133 DosQueryProcAddr(G_hmodACPI, ORD_ACPITKPREPARETOSLEEP,
134 NULL, (PFN *) &pAcpiTkPrepareToSleep);
135 }
136 }
137
138 if (arc)
139 return(arc);
140 else
141 {
142 G_ulCount++;
143
144 return(pAcpiStartApi(phACPI));
145 }
146}
147
148/*
149 *@@ acpihPrepareToSleep:
150 * Prepares the system to sleep or power off
151 *
152 *@@added V1.0.10 (2014-08-30) [dazarewicz]
153 */
154
155VOID acpihPrepareToSleep(UCHAR ucState)
156{
157 // @@added V1.0.9 (2012-12-10) [slevine]: use AcpiTkPrepareToSleep rather than workaround
158 /* This function does not exist in older versions of acpi
159 * As a result the shutdown attempt will usually hang because
160 * the required code has not been committed into memory.
161 */
162 if (pAcpiTkPrepareToSleep)
163 pAcpiTkPrepareToSleep(ucState);
164}
165
166/*
167 *@@ acpihClose:
168 * unloads the ACPI DLL.
169 */
170
171VOID acpihClose(ACPI_API_HANDLE *phACPI)
172{
173 if (pAcpiEndApi)
174 {
175 pAcpiEndApi(phACPI);
176 G_ulCount--;
177 }
178
179 if (!G_ulCount)
180 {
181 DosFreeModule(G_hmodACPI);
182 G_hmodACPI = NULLHANDLE;
183 pAcpiStartApi = NULL;
184 pAcpiEndApi = NULL;
185 pAcpiGoToSleep = NULL;
186 // @@added V1.0.9 (2012-12-10) [slevine]: additional ACPI support
187 pAcpiTkPrepareToSleep = NULL;
188 }
189}
190
191/*
192 *@@ acpihGoToSleep:
193 * changes the Power State.
194 */
195
196APIRET acpihGoToSleep(ACPI_API_HANDLE *phACPI, UCHAR ucState)
197{
198 if (pAcpiGoToSleep)
199 return(pAcpiGoToSleep(phACPI, ucState));
200 else
201 return(ERROR_PROTECTION_VIOLATION);
202}
203
204
205/**
206 *@@ AcpiCallbackWidget:
207 * ACPI callback helper for battery and power status queries.
208 * Code provided by David Azarewicz
209 *@@added V1.0.9 (2012-02-20) [slevine]: code from David Azarewicz
210 *@@changed V1.0.10 (2014-08-30) [dazarewicz]: release resources correctly
211 */
212
213ACPI_STATUS APIENTRY AcpiCallbackWidget( ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context, void **ReturnValue )
214{
215 ACPI_DEVICE_INFO *pDevInfo = NULL;
216
217 if (pAcpiTkGetObjectInfoAlloc( ObjHandle, &pDevInfo ) != AE_OK)
218 return AE_OK;
219
220 do
221 {
222 if (pDevInfo->Type != ACPI_TYPE_DEVICE)
223 break;
224
225 if (!(pDevInfo->Valid & ACPI_VALID_HID))
226 break;
227
228 if (!pDevInfo->HardwareId.String)
229 break;
230
231 if (strncmp(pDevInfo->HardwareId.String, "ACPI0003", 8) == 0)
232 { /* AC Power */
233 if (pAcpiTkGetHandle(ObjHandle, "_PSR", &G_ahAC))
234 G_ahAC = 0;
235
236 break;
237 }
238
239 if (strncmp(pDevInfo->HardwareId.String, "PNP0C0A", 7) == 0)
240 { /* Smart battery */
241 if (G_uiBatteryCount < MAX_BATTERY_COUNT)
242 G_ahBat[G_uiBatteryCount++] = ObjHandle;
243
244 break;
245 }
246 } while (0);
247
248 if (pDevInfo)
249 pAcpiTkOsFree(pDevInfo);
250
251 return AE_OK;
252}
253
254/**
255 *@@ acpihGetPowerStatus:
256 * Returns power and battery status in caller provided buffers.
257 * Returns zero if success, non-zero if fail.
258 * Code provided by David Azarewicz
259 *@@added V1.0.9 (2012-02-20) [slevine]: code from David Azarewicz
260 *@@changed V1.0.10 (2014-08-30) [dazarewicz]: tidies
261 */
262
263APIRET acpihGetPowerStatus(PAPM pApm, PBOOL pfChanged)
264{
265 ACPI_STATUS Status;
266 ACPI_BUFFER Result;
267 ACPI_OBJECT *Obj, Object[20];
268 UINT32 uiI;
269 ULONG ulTmp, BRemaining, LastFull;
270 BOOL fChanged;
271
272 /* Make sure all the functions we need have valid pointers.
273 * @@added V1.0.9 (2012-02-25) [dazarewicz]: additional ACPI support
274 */
275 if ( (pAcpiTkWalkNamespace == NULL)
276 || (pAcpiTkGetObjectInfoAlloc == NULL)
277 || (pAcpiTkGetHandle == NULL)
278 || (pAcpiTkOsFree == NULL)
279 || (pAcpiTkEvaluateObject == NULL)
280 || (pApm == NULL)
281 )
282 return 1;
283
284 if (!G_uiAlreadyWalked)
285 {
286 Status = pAcpiTkWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
287 ACPI_UINT32_MAX, AcpiCallbackWidget,
288 pApm, NULL);
289 G_uiAlreadyWalked = 1;
290 }
291
292 fChanged = FALSE;
293
294 // VAC 3.08 long long compatibility support
295#ifdef INCL_LONGLONG // VAC 3.6.5 - compiler supports long long
296#define OBJECT_VALUE(index) (Object[index].Integer.Value)
297#define OBJ_VALUE(index) (Obj[index].Integer.Value)
298#else // VAC 3.08 - compiler does not support long long
299#define OBJECT_VALUE(index) (Object[index].Integer.Value.ulLo)
300#define OBJ_VALUE(index) (Obj[index].Integer.Value.ulLo)
301#endif
302
303 if (G_ahAC)
304 {
305 // Have _PSR
306 Result.Length = sizeof(Object);
307 Result.Pointer = Object;
308 Status = pAcpiTkEvaluateObject(G_ahAC, NULL, NULL, &Result);
309 if (Status != AE_OK)
310 ulTmp = 2; // assume on backup power
311 else if (Object[0].Type != ACPI_TYPE_INTEGER)
312 ulTmp = 2; // assume on backup power
313 else
314 ulTmp = (UINT32)OBJECT_VALUE(0);
315
316 if (pApm->fUsingAC != (BYTE) ulTmp)
317 {
318 pApm->fUsingAC = (BYTE) ulTmp;
319 fChanged = TRUE;
320 }
321 }
322
323 for (uiI=0; uiI < G_uiBatteryCount; uiI++)
324 {
325 if (G_ahBat[uiI] == 0)
326 continue;
327
328 Result.Length = sizeof(Object);
329 Result.Pointer = Object;
330 // Get battery info
331 Status = pAcpiTkEvaluateObject(G_ahBat[uiI], "_BIF", NULL, &Result);
332 if (Status != AE_OK)
333 {
334 G_ahBat[uiI] = 0;
335 continue;
336 }
337
338 Obj = Result.Pointer;
339 Obj = (ACPI_OBJECT *)Obj[0].Package.Elements; // Battery info package
340 LastFull = (UINT32)OBJ_VALUE(2);
341
342 Result.Length = sizeof(Object);
343 Result.Pointer = Object;
344 // Get battery status
345 Status = pAcpiTkEvaluateObject(G_ahBat[uiI], "_BST", NULL, &Result);
346 if (Status != AE_OK)
347 {
348 G_ahBat[uiI] = 0;
349 continue;
350 }
351
352 Obj = Result.Pointer;
353 Obj = (ACPI_OBJECT *)Obj[0].Package.Elements; // Battery status package
354 BRemaining = (UINT32)OBJ_VALUE(2);
355
356 // If battery units are mWh or mAh
357 // If not, it is a percentage
358 if ( (LastFull != 0xffffffff)
359 && (BRemaining != 0xffffffff)
360 )
361 {
362 if (BRemaining > (LastFull >> 1)) // > 50% is high. < 50% is low
363 ulTmp = 1; // High
364 else
365 ulTmp = 2; // Low
366
367 if (OBJ_VALUE(0) & 4)
368 ulTmp = 2; // Critical
369
370 // If battery charging - it can't be critical
371 if (OBJ_VALUE(0) & 2)
372 ulTmp = 3; // Charging
373
374 if (pApm->bBatteryStatus != ulTmp)
375 {
376 pApm->bBatteryStatus = (BYTE)ulTmp;
377 fChanged = TRUE;
378 }
379
380 ulTmp = (BRemaining*100) / LastFull;
381 if (ulTmp > 100)
382 ulTmp = 100;
383
384 if (pApm->bBatteryLife != ulTmp)
385 {
386 pApm->bBatteryLife = (BYTE) ulTmp;
387 fChanged = TRUE;
388 }
389 }
390 }
391
392 if (pfChanged)
393 *pfChanged = fChanged;
394
395 pApm->fAlreadyRead = FALSE;
396 return 0;
397
398#undef OBJECT_VALUE
399#undef OBJ_VALUE
400}
401
402/*
403 *@@ acpihHasBattery:
404 * quick'n'dirty helper which returns TRUE only
405 * if ACPI is supported on the system and the
406 * system actually has a battery (i.e. is a laptop).
407 * Code provided by David Azarewicz.
408 * @@added V1.0.9 (2012-02-20) [slevine]: code from David Azarewicz
409 */
410BOOL acpihHasBattery(VOID)
411{
412 BOOL brc = FALSE;
413 ACPI_API_HANDLE hACPI;
414 APM Apm;
415
416 if (!acpihOpen(&hACPI))
417 {
418 Apm.bBatteryStatus = 0xff;
419 if (!acpihGetPowerStatus(&Apm, NULL))
420 brc = (Apm.bBatteryStatus != 0xFF);
421
422 acpihClose(&hACPI);
423 }
424
425 return brc;
426}
427
Note: See TracBrowser for help on using the repository browser.