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

Last change on this file since 415 was 414, checked in by pr, 12 years ago

ACPI sleep mods. from Steven.

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