VirtualBox

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

Last change on this file since 239 was 1, checked in by vboxsync, 55 years ago

import

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