VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DrvACPI.cpp@ 10700

Last change on this file since 10700 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.3 KB
Line 
1/** $Id: DrvACPI.cpp 8155 2008-04-18 15:16:47Z vboxsync $ */
2/** @file
3 * ACPI Host Driver.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DRV_ACPI
26
27#ifdef RT_OS_WINDOWS
28# include <windows.h>
29#endif
30
31#include <VBox/pdmdrv.h>
32#include <VBox/log.h>
33#include <iprt/assert.h>
34#include <iprt/string.h>
35
36#ifdef RT_OS_LINUX
37# include <iprt/string.h>
38# include <sys/types.h>
39# include <dirent.h>
40# include <stdio.h>
41#endif
42
43#include "Builtins.h"
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * ACPI driver instance data.
51 */
52typedef struct DRVACPI
53{
54 /** The ACPI interface. */
55 PDMIACPICONNECTOR IACPIConnector;
56 /** The ACPI port interface. */
57 PPDMIACPIPORT pPort;
58 /** Pointer to the driver instance. */
59 PPDMDRVINS pDrvIns;
60} DRVACPI, *PDRVACPI;
61
62
63/**
64 * Queries an interface to the driver.
65 *
66 * @returns Pointer to interface.
67 * @returns NULL if the interface was not supported by the driver.
68 * @param pInterface Pointer to this interface structure.
69 * @param enmInterface The requested interface identification.
70 * @thread Any thread.
71 */
72static DECLCALLBACK(void *) drvACPIQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
73{
74 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
75 PDRVACPI pData = PDMINS2DATA(pDrvIns, PDRVACPI);
76 switch (enmInterface)
77 {
78 case PDMINTERFACE_BASE:
79 return &pDrvIns->IBase;
80 case PDMINTERFACE_ACPI_CONNECTOR:
81 return &pData->IACPIConnector;
82 default:
83 return NULL;
84 }
85}
86
87/**
88 * Get the current power source of the host system.
89 *
90 * @returns status code
91 * @param pInterface Pointer to the interface structure containing the called function pointer.
92 * @param pPowerSource Pointer to the power source result variable.
93 */
94static DECLCALLBACK(int) drvACPIQueryPowerSource(PPDMIACPICONNECTOR pInterface,
95 PDMACPIPOWERSOURCE *pPowerSource)
96{
97#if defined(RT_OS_WINDOWS)
98 SYSTEM_POWER_STATUS powerStatus;
99 if (GetSystemPowerStatus(&powerStatus))
100 {
101 /* running on battery? */
102 if ( (powerStatus.ACLineStatus == 0)
103 || (powerStatus.ACLineStatus == 255)
104 && (powerStatus.BatteryFlag & 15))
105 {
106 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
107 }
108 /* running on AC link? */
109 else if (powerStatus.ACLineStatus == 1)
110 {
111 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
112 }
113 else
114 /* what the hell we're running on? */
115 {
116 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
117 }
118 }
119 else
120 {
121 AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
122 GetLastError()));
123 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
124 }
125#elif defined (RT_OS_LINUX) /* !RT_OS_WINDOWS */
126 DIR *dfd;
127 struct dirent *dp;
128 FILE *statusFile = NULL;
129 char buff[NAME_MAX+50];
130
131 /* start with no result */
132 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
133
134 dfd = opendir("/proc/acpi/ac_adapter/");
135 if (dfd)
136 {
137 for (;;)
138 {
139 dp = readdir(dfd);
140 if (dp == 0)
141 break;
142 if (strcmp(dp->d_name, ".") == 0 ||
143 strcmp(dp->d_name, "..") == 0)
144 continue;
145 strcpy(buff, "/proc/acpi/ac_adapter/");
146 strcat(buff, dp->d_name);
147 strcat(buff, "/status");
148 statusFile = fopen(buff, "r");
149 /* there's another possible name for this file */
150 if (!statusFile)
151 {
152 strcpy(buff, "/proc/acpi/ac_adapter/");
153 strcat(buff, dp->d_name);
154 strcat(buff, "/state");
155 statusFile = fopen(buff, "r");
156 }
157 if (statusFile)
158 break;
159 }
160 closedir(dfd);
161 }
162
163 if (statusFile)
164 {
165 for (;;)
166 {
167 char buff2[1024];
168 if (fgets(buff2, sizeof(buff), statusFile) == NULL)
169 break;
170 if (strstr(buff2, "Status:") != NULL ||
171 strstr(buff2, "state:") != NULL)
172 {
173 if (strstr(buff2, "on-line") != NULL)
174 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
175 else
176 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
177 }
178 }
179 fclose(statusFile);
180 }
181#else /* !RT_OS_LINUX either - what could this be? */
182 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
183#endif /* !RT_OS_WINDOWS */
184 return VINF_SUCCESS;
185}
186
187/**
188 * @copydoc PDMIACPICONNECTOR::pfnQueryBatteryStatus
189 */
190static DECLCALLBACK(int) drvACPIQueryBatteryStatus(PPDMIACPICONNECTOR pInterface, bool *pfPresent,
191 PPDMACPIBATCAPACITY penmRemainingCapacity,
192 PPDMACPIBATSTATE penmBatteryState,
193 uint32_t *pu32PresentRate)
194{
195 /* default return values for all architectures */
196 *pfPresent = false; /* no battery present */
197 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
198 *penmRemainingCapacity = PDM_ACPI_BAT_CAPACITY_UNKNOWN;
199 *pu32PresentRate = ~0; /* present rate is unknown */
200
201#if defined(RT_OS_WINDOWS)
202 SYSTEM_POWER_STATUS powerStatus;
203 if (GetSystemPowerStatus(&powerStatus))
204 {
205 /* 128 means no battery present */
206 *pfPresent = !(powerStatus.BatteryFlag & 128);
207 /* just forward the value directly */
208 *penmRemainingCapacity = (PDMACPIBATCAPACITY)powerStatus.BatteryLifePercent;
209 /* we assume that we are discharging the battery if we are not on-line and
210 * not charge the battery */
211 uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
212 if (powerStatus.BatteryFlag & 8)
213 uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
214 else if (powerStatus.ACLineStatus == 0 || powerStatus.ACLineStatus == 255)
215 uBs = PDM_ACPI_BAT_STATE_CHARGING;
216 if (powerStatus.BatteryFlag & 4)
217 uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
218 *penmBatteryState = (PDMACPIBATSTATE)uBs;
219 /* on Windows it is difficult to request the present charging/discharging rate */
220 }
221 else
222 {
223 AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
224 GetLastError()));
225 }
226#elif defined(RT_OS_LINUX)
227 DIR *dfd;
228 struct dirent *dp;
229 FILE *statusFile = NULL;
230 FILE *infoFile = NULL;
231 char buff[NAME_MAX+50];
232 /* the summed up maximum capacity */
233 int maxCapacityTotal = ~0;
234 /* the summed up total capacity */
235 int currentCapacityTotal = ~0;
236 int presentRate = 0;
237 int presentRateTotal = 0;
238 bool fBatteryPresent = false, fCharging=false, fDischarging=false, fCritical=false;
239
240 dfd = opendir("/proc/acpi/battery/");
241 if (dfd)
242 {
243 for (;;)
244 {
245 dp = readdir(dfd);
246 if (dp == 0)
247 break;
248 if (strcmp(dp->d_name, ".") == 0 ||
249 strcmp(dp->d_name, "..") == 0)
250 continue;
251 strcpy(buff, "/proc/acpi/battery/");
252 strcat(buff, dp->d_name);
253 strcat(buff, "/status");
254 statusFile = fopen(buff, "r");
255 /* there is a 2nd variant of that file */
256 if (!statusFile)
257 {
258 strcpy(buff, "/proc/acpi/battery/");
259 strcat(buff, dp->d_name);
260 strcat(buff, "/state");
261 statusFile = fopen(buff, "r");
262 }
263 strcpy(buff, "/proc/acpi/battery/");
264 strcat(buff, dp->d_name);
265 strcat(buff, "/info");
266 infoFile = fopen(buff, "r");
267 /* we need both files */
268 if (!statusFile || !infoFile)
269 {
270 if (statusFile)
271 fclose(statusFile);
272 if (infoFile)
273 fclose(infoFile);
274 break;
275 }
276
277 /* get 'present' status from the info file */
278 for (;;)
279 {
280 char buff2[1024];
281 if (fgets(buff2, sizeof(buff), infoFile) == NULL)
282 break;
283
284 if (strstr(buff2, "present:") != NULL)
285 {
286 if (strstr(buff2, "yes") != NULL)
287 fBatteryPresent = true;
288 }
289 }
290
291 /* move file pointer back to start of file */
292 fseek(infoFile, 0, SEEK_SET);
293
294 if (fBatteryPresent)
295 {
296 /* get the maximum capacity from the info file */
297 for (;;)
298 {
299 char buff2[1024];
300 int maxCapacity = ~0;
301 if (fgets(buff2, sizeof(buff), infoFile) == NULL)
302 break;
303 if (strstr(buff2, "last full capacity:") != NULL)
304 {
305 if (sscanf(buff2 + 19, "%d", &maxCapacity) <= 0)
306 maxCapacity = ~0;
307
308 /* did we get a valid capacity and it's the first value we got? */
309 if (maxCapacityTotal < 0 && maxCapacity > 0)
310 {
311 /* take this as the maximum capacity */
312 maxCapacityTotal = maxCapacity;
313 }
314 else
315 {
316 /* sum up the maximum capacity */
317 if (maxCapacityTotal > 0 && maxCapacity > 0)
318 maxCapacityTotal += maxCapacity;
319 }
320 /* we got all we need */
321 break;
322 }
323 }
324
325 /* get the current capacity/state from the status file */
326 bool gotRemainingCapacity=false, gotBatteryState=false,
327 gotCapacityState=false, gotPresentRate=false;
328 while (!gotRemainingCapacity || !gotBatteryState ||
329 !gotCapacityState || !gotPresentRate)
330 {
331 char buff2[1024];
332 int currentCapacity = ~0;
333 if (fgets(buff2, sizeof(buff), statusFile) == NULL)
334 break;
335 if (strstr(buff2, "remaining capacity:") != NULL)
336 {
337 if (sscanf(buff2 + 19, "%d", &currentCapacity) <= 0)
338 currentCapacity = ~0;
339
340 /* is this the first valid value we see? If so, take it! */
341 if (currentCapacityTotal < 0 && currentCapacity >= 0)
342 {
343 currentCapacityTotal = currentCapacity;
344 }
345 else
346 {
347 /* just sum up the current value */
348 if (currentCapacityTotal > 0 && currentCapacity > 0)
349 currentCapacityTotal += currentCapacity;
350 }
351 gotRemainingCapacity = true;
352 }
353 if (strstr(buff2, "charging state:") != NULL)
354 {
355 if (strstr(buff2 + 15, "discharging") != NULL)
356 fDischarging = true;
357 else if (strstr(buff2 + 15, "charging") != NULL)
358 fCharging = true;
359 gotBatteryState = true;
360 }
361 if (strstr(buff2, "capacity state:") != NULL)
362 {
363 if (strstr(buff2 + 15, "critical") != NULL)
364 fCritical = true;
365 gotCapacityState = true;
366 }
367 if (strstr(buff2, "present rate:") != NULL)
368 {
369 if (sscanf(buff2 + 13, "%d", &presentRate) <= 0)
370 presentRate = 0;
371 gotPresentRate = true;
372 }
373 }
374 }
375
376 if (presentRate)
377 {
378 if (fDischarging)
379 presentRateTotal -= presentRate;
380 else
381 presentRateTotal += presentRate;
382 }
383
384 if (statusFile)
385 fclose(statusFile);
386 if (infoFile)
387 fclose(infoFile);
388
389 }
390 closedir(dfd);
391 }
392
393 *pfPresent = fBatteryPresent;
394
395 /* charging/discharging bits are mutual exclusive */
396 uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
397 if (fDischarging)
398 uBs = PDM_ACPI_BAT_STATE_CHARGING;
399 else if (fCharging)
400 uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
401 if (fCritical)
402 uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
403 *penmBatteryState = (PDMACPIBATSTATE)uBs;
404
405 if (presentRateTotal < 0)
406 presentRateTotal = -presentRateTotal;
407
408 if (maxCapacityTotal > 0 && currentCapacityTotal > 0)
409 {
410 /* calculate the percentage */
411 *penmRemainingCapacity = (PDMACPIBATCAPACITY)(((float)currentCapacityTotal / (float)maxCapacityTotal)
412 * PDM_ACPI_BAT_CAPACITY_MAX);
413 *pu32PresentRate = (uint32_t)(((float)presentRateTotal / (float)maxCapacityTotal) * 1000);
414 }
415#endif /* RT_OS_LINUX */
416 return VINF_SUCCESS;
417}
418
419/**
420 * Destruct a driver instance.
421 *
422 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
423 * resources can be freed correctly.
424 *
425 * @param pDrvIns The driver instance data.
426 */
427static DECLCALLBACK(void) drvACPIDestruct(PPDMDRVINS pDrvIns)
428{
429 LogFlow(("drvACPIDestruct\n"));
430}
431
432/**
433 * Construct an ACPI driver instance.
434 *
435 * @returns VBox status.
436 * @param pDrvIns The driver instance data.
437 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
438 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
439 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
440 * iInstance it's expected to be used a bit in this function.
441 */
442static DECLCALLBACK(int) drvACPIConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
443{
444 PDRVACPI pData = PDMINS2DATA(pDrvIns, PDRVACPI);
445
446 /*
447 * Init the static parts.
448 */
449 pData->pDrvIns = pDrvIns;
450 /* IBase */
451 pDrvIns->IBase.pfnQueryInterface = drvACPIQueryInterface;
452 /* IACPIConnector */
453 pData->IACPIConnector.pfnQueryPowerSource = drvACPIQueryPowerSource;
454 pData->IACPIConnector.pfnQueryBatteryStatus = drvACPIQueryBatteryStatus;
455
456 /*
457 * Validate the config.
458 */
459 if (!CFGMR3AreValuesValid(pCfgHandle, "\0"))
460 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
461
462 /*
463 * Check that no-one is attached to us.
464 */
465 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
466 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
467 {
468 AssertMsgFailed(("Configuration error: Cannot attach drivers to the ACPI driver!\n"));
469 return VERR_PDM_DRVINS_NO_ATTACH;
470 }
471
472 /*
473 * Query the ACPI port interface.
474 */
475 pData->pPort = (PPDMIACPIPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase,
476 PDMINTERFACE_ACPI_PORT);
477 if (!pData->pPort)
478 {
479 AssertMsgFailed(("Configuration error: "
480 "the above device/driver didn't export the ACPI port interface!\n"));
481 return VERR_PDM_MISSING_INTERFACE_ABOVE;
482 }
483
484 return VINF_SUCCESS;
485}
486
487
488/**
489 * ACPI driver registration record.
490 */
491const PDMDRVREG g_DrvACPI =
492{
493 /* u32Version */
494 PDM_DRVREG_VERSION,
495 /* szDriverName */
496 "ACPIHost",
497 /* pszDescription */
498 "ACPI Host Driver",
499 /* fFlags */
500 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
501 /* fClass. */
502 PDM_DRVREG_CLASS_ACPI,
503 /* cMaxInstances */
504 ~0,
505 /* cbInstance */
506 sizeof(DRVACPI),
507 /* pfnConstruct */
508 drvACPIConstruct,
509 /* pfnDestruct */
510 drvACPIDestruct,
511 /* pfnIOCtl */
512 NULL,
513 /* pfnPowerOn */
514 NULL,
515 /* pfnReset */
516 NULL,
517 /* pfnSuspend */
518 NULL,
519 /* pfnResume */
520 NULL,
521 /* pfnDetach */
522 NULL,
523 /* pfnPowerOff */
524 NULL
525};
526
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette