VirtualBox

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

Last change on this file since 3429 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

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