VirtualBox

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

Last change on this file since 6290 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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