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

Last change on this file since 411 was 410, checked in by pr, 13 years ago

Fix formatting.

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