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

Last change on this file since 407 was 407, checked in by shl, 13 years ago

Ensure AcpiGoToSleep in memory when called to power off.

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