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

Last change on this file since 409 was 409, checked in by rlw, 13 years ago

fix ACPI crash, improve ACPI code - from Steve Levine

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