VirtualBox

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

Last change on this file since 21205 was 19967, checked in by vboxsync, 15 years ago

ACPI: Add support for FreeBSD

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.6 KB
Line 
1/* $Id: DrvACPI.cpp 19967 2009-05-24 12:05:02Z vboxsync $ */
2/** @file
3 * DrvACPI - 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#ifdef RT_OS_DARWIN
44# include <Carbon/Carbon.h>
45# include <IOKit/ps/IOPowerSources.h>
46# include <IOKit/ps/IOPSKeys.h>
47#endif
48
49#ifdef RT_OS_FREEBSD
50# include <sys/ioctl.h>
51# include <dev/acpica/acpiio.h>
52# include <sys/types.h>
53# include <sys/sysctl.h>
54# include <stdio.h>
55# include <errno.h>
56# include <fcntl.h>
57# include <unistd.h>
58#endif
59
60#include "Builtins.h"
61
62
63/*******************************************************************************
64* Structures and Typedefs *
65*******************************************************************************/
66/**
67 * ACPI driver instance data.
68 */
69typedef struct DRVACPI
70{
71 /** The ACPI interface. */
72 PDMIACPICONNECTOR IACPIConnector;
73 /** The ACPI port interface. */
74 PPDMIACPIPORT pPort;
75 /** Pointer to the driver instance. */
76 PPDMDRVINS pDrvIns;
77} DRVACPI, *PDRVACPI;
78
79
80/**
81 * Queries an interface to the driver.
82 *
83 * @returns Pointer to interface.
84 * @returns NULL if the interface was not supported by the driver.
85 * @param pInterface Pointer to this interface structure.
86 * @param enmInterface The requested interface identification.
87 * @thread Any thread.
88 */
89static DECLCALLBACK(void *) drvACPIQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
90{
91 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
92 PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
93 switch (enmInterface)
94 {
95 case PDMINTERFACE_BASE:
96 return &pDrvIns->IBase;
97 case PDMINTERFACE_ACPI_CONNECTOR:
98 return &pThis->IACPIConnector;
99 default:
100 return NULL;
101 }
102}
103
104/**
105 * Get the current power source of the host system.
106 *
107 * @returns status code
108 * @param pInterface Pointer to the interface structure containing the called function pointer.
109 * @param pPowerSource Pointer to the power source result variable.
110 */
111static DECLCALLBACK(int) drvACPIQueryPowerSource(PPDMIACPICONNECTOR pInterface,
112 PDMACPIPOWERSOURCE *pPowerSource)
113{
114#if defined(RT_OS_WINDOWS)
115 SYSTEM_POWER_STATUS powerStatus;
116 if (GetSystemPowerStatus(&powerStatus))
117 {
118 /* running on battery? */
119 if ( (powerStatus.ACLineStatus == 0)
120 || (powerStatus.ACLineStatus == 255)
121 && (powerStatus.BatteryFlag & 15))
122 {
123 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
124 }
125 /* running on AC link? */
126 else if (powerStatus.ACLineStatus == 1)
127 {
128 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
129 }
130 else
131 /* what the hell we're running on? */
132 {
133 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
134 }
135 }
136 else
137 {
138 AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
139 GetLastError()));
140 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
141 }
142#elif defined (RT_OS_LINUX) /* !RT_OS_WINDOWS */
143 DIR *dfd;
144 struct dirent *dp;
145 FILE *statusFile = NULL;
146 char buff[NAME_MAX+50];
147
148 /* start with no result */
149 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
150
151 dfd = opendir("/proc/acpi/ac_adapter/");
152 if (dfd)
153 {
154 for (;;)
155 {
156 dp = readdir(dfd);
157 if (dp == 0)
158 break;
159 if (strcmp(dp->d_name, ".") == 0 ||
160 strcmp(dp->d_name, "..") == 0)
161 continue;
162 strcpy(buff, "/proc/acpi/ac_adapter/");
163 strcat(buff, dp->d_name);
164 strcat(buff, "/status");
165 statusFile = fopen(buff, "r");
166 /* there's another possible name for this file */
167 if (!statusFile)
168 {
169 strcpy(buff, "/proc/acpi/ac_adapter/");
170 strcat(buff, dp->d_name);
171 strcat(buff, "/state");
172 statusFile = fopen(buff, "r");
173 }
174 if (statusFile)
175 break;
176 }
177 closedir(dfd);
178 }
179
180 if (statusFile)
181 {
182 for (;;)
183 {
184 char buff2[1024];
185 if (fgets(buff2, sizeof(buff), statusFile) == NULL)
186 break;
187 if (strstr(buff2, "Status:") != NULL ||
188 strstr(buff2, "state:") != NULL)
189 {
190 if (strstr(buff2, "on-line") != NULL)
191 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
192 else
193 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
194 }
195 }
196 fclose(statusFile);
197 }
198#elif defined (RT_OS_DARWIN) /* !RT_OS_LINUX */
199 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
200
201 CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
202 CFArrayRef pSources = IOPSCopyPowerSourcesList(pBlob);
203
204 CFDictionaryRef pSource = NULL;
205 const void *psValue;
206 bool result;
207
208 if (CFArrayGetCount(pSources) > 0)
209 {
210 for(int i = 0; i < CFArrayGetCount(pSources); ++i)
211 {
212 pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i));
213 /* If the source is empty skip over to the next one. */
214 if(!pSource)
215 continue;
216 /* Skip all power sources which are currently not present like a
217 * second battery. */
218 if (CFDictionaryGetValue(pSource, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse)
219 continue;
220 /* Only internal power types are of interest. */
221 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
222 if (result &&
223 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
224 {
225 /* Check which power source we are connect on. */
226 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
227 if (result &&
228 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
229 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
230 else if (result &&
231 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
232 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
233 }
234 }
235 }
236 CFRelease(pBlob);
237 CFRelease(pSources);
238#elif defined(RT_OS_FREEBSD) /* !RT_OS_DARWIN */
239 int fAcLine = 0;
240 size_t cbParameter = sizeof(fAcLine);
241
242 int rc = sysctlbyname("hw.acpi.acline", &fAcLine, &cbParameter, NULL, NULL);
243
244 if (!rc)
245 {
246 if (fAcLine == 1)
247 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
248 else if (fAcLine == 0)
249 *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
250 else
251 *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
252 }
253 else
254 {
255 AssertMsg(errno == ENOENT, ("rc=%d (%s)\n", rc, strerror(errno)));
256 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
257 }
258#else /* !RT_OS_FREEBSD either - what could this be? */
259 *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
260#endif /* !RT_OS_WINDOWS */
261 return VINF_SUCCESS;
262}
263
264/**
265 * @copydoc PDMIACPICONNECTOR::pfnQueryBatteryStatus
266 */
267static DECLCALLBACK(int) drvACPIQueryBatteryStatus(PPDMIACPICONNECTOR pInterface, bool *pfPresent,
268 PPDMACPIBATCAPACITY penmRemainingCapacity,
269 PPDMACPIBATSTATE penmBatteryState,
270 uint32_t *pu32PresentRate)
271{
272 /* default return values for all architectures */
273 *pfPresent = false; /* no battery present */
274 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
275 *penmRemainingCapacity = PDM_ACPI_BAT_CAPACITY_UNKNOWN;
276 *pu32PresentRate = ~0; /* present rate is unknown */
277
278#if defined(RT_OS_WINDOWS)
279 SYSTEM_POWER_STATUS powerStatus;
280 if (GetSystemPowerStatus(&powerStatus))
281 {
282 /* 128 means no battery present */
283 *pfPresent = !(powerStatus.BatteryFlag & 128);
284 /* just forward the value directly */
285 *penmRemainingCapacity = (PDMACPIBATCAPACITY)powerStatus.BatteryLifePercent;
286 /* we assume that we are discharging the battery if we are not on-line and
287 * not charge the battery */
288 uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
289 if (powerStatus.BatteryFlag & 8)
290 uBs = PDM_ACPI_BAT_STATE_CHARGING;
291 else if (powerStatus.ACLineStatus == 0 || powerStatus.ACLineStatus == 255)
292 uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
293 if (powerStatus.BatteryFlag & 4)
294 uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
295 *penmBatteryState = (PDMACPIBATSTATE)uBs;
296 /* on Windows it is difficult to request the present charging/discharging rate */
297 }
298 else
299 {
300 AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
301 GetLastError()));
302 }
303#elif defined(RT_OS_LINUX)
304 DIR *dfd;
305 struct dirent *dp;
306 FILE *statusFile = NULL;
307 FILE *infoFile = NULL;
308 char buff[NAME_MAX+50];
309 /* the summed up maximum capacity */
310 int maxCapacityTotal = ~0;
311 /* the summed up total capacity */
312 int currentCapacityTotal = ~0;
313 int presentRate = 0;
314 int presentRateTotal = 0;
315 bool fBatteryPresent = false, fCharging=false, fDischarging=false, fCritical=false;
316
317 dfd = opendir("/proc/acpi/battery/");
318 if (dfd)
319 {
320 for (;;)
321 {
322 dp = readdir(dfd);
323 if (dp == 0)
324 break;
325 if (strcmp(dp->d_name, ".") == 0 ||
326 strcmp(dp->d_name, "..") == 0)
327 continue;
328 strcpy(buff, "/proc/acpi/battery/");
329 strcat(buff, dp->d_name);
330 strcat(buff, "/status");
331 statusFile = fopen(buff, "r");
332 /* there is a 2nd variant of that file */
333 if (!statusFile)
334 {
335 strcpy(buff, "/proc/acpi/battery/");
336 strcat(buff, dp->d_name);
337 strcat(buff, "/state");
338 statusFile = fopen(buff, "r");
339 }
340 strcpy(buff, "/proc/acpi/battery/");
341 strcat(buff, dp->d_name);
342 strcat(buff, "/info");
343 infoFile = fopen(buff, "r");
344 /* we need both files */
345 if (!statusFile || !infoFile)
346 {
347 if (statusFile)
348 fclose(statusFile);
349 if (infoFile)
350 fclose(infoFile);
351 break;
352 }
353
354 /* get 'present' status from the info file */
355 for (;;)
356 {
357 char buff2[1024];
358 if (fgets(buff2, sizeof(buff), infoFile) == NULL)
359 break;
360
361 if (strstr(buff2, "present:") != NULL)
362 {
363 if (strstr(buff2, "yes") != NULL)
364 fBatteryPresent = true;
365 }
366 }
367
368 /* move file pointer back to start of file */
369 fseek(infoFile, 0, SEEK_SET);
370
371 if (fBatteryPresent)
372 {
373 /* get the maximum capacity from the info file */
374 for (;;)
375 {
376 char buff2[1024];
377 int maxCapacity = ~0;
378 if (fgets(buff2, sizeof(buff), infoFile) == NULL)
379 break;
380 if (strstr(buff2, "last full capacity:") != NULL)
381 {
382 if (sscanf(buff2 + 19, "%d", &maxCapacity) <= 0)
383 maxCapacity = ~0;
384
385 /* did we get a valid capacity and it's the first value we got? */
386 if (maxCapacityTotal < 0 && maxCapacity > 0)
387 {
388 /* take this as the maximum capacity */
389 maxCapacityTotal = maxCapacity;
390 }
391 else
392 {
393 /* sum up the maximum capacity */
394 if (maxCapacityTotal > 0 && maxCapacity > 0)
395 maxCapacityTotal += maxCapacity;
396 }
397 /* we got all we need */
398 break;
399 }
400 }
401
402 /* get the current capacity/state from the status file */
403 bool gotRemainingCapacity=false, gotBatteryState=false,
404 gotCapacityState=false, gotPresentRate=false;
405 while (!gotRemainingCapacity || !gotBatteryState ||
406 !gotCapacityState || !gotPresentRate)
407 {
408 char buff2[1024];
409 int currentCapacity = ~0;
410 if (fgets(buff2, sizeof(buff), statusFile) == NULL)
411 break;
412 if (strstr(buff2, "remaining capacity:") != NULL)
413 {
414 if (sscanf(buff2 + 19, "%d", &currentCapacity) <= 0)
415 currentCapacity = ~0;
416
417 /* is this the first valid value we see? If so, take it! */
418 if (currentCapacityTotal < 0 && currentCapacity >= 0)
419 {
420 currentCapacityTotal = currentCapacity;
421 }
422 else
423 {
424 /* just sum up the current value */
425 if (currentCapacityTotal > 0 && currentCapacity > 0)
426 currentCapacityTotal += currentCapacity;
427 }
428 gotRemainingCapacity = true;
429 }
430 if (strstr(buff2, "charging state:") != NULL)
431 {
432 if (strstr(buff2 + 15, "discharging") != NULL)
433 fDischarging = true;
434 else if (strstr(buff2 + 15, "charging") != NULL)
435 fCharging = true;
436 gotBatteryState = true;
437 }
438 if (strstr(buff2, "capacity state:") != NULL)
439 {
440 if (strstr(buff2 + 15, "critical") != NULL)
441 fCritical = true;
442 gotCapacityState = true;
443 }
444 if (strstr(buff2, "present rate:") != NULL)
445 {
446 if (sscanf(buff2 + 13, "%d", &presentRate) <= 0)
447 presentRate = 0;
448 gotPresentRate = true;
449 }
450 }
451 }
452
453 if (presentRate)
454 {
455 if (fDischarging)
456 presentRateTotal -= presentRate;
457 else
458 presentRateTotal += presentRate;
459 }
460
461 if (statusFile)
462 fclose(statusFile);
463 if (infoFile)
464 fclose(infoFile);
465
466 }
467 closedir(dfd);
468 }
469
470 *pfPresent = fBatteryPresent;
471
472 /* charging/discharging bits are mutual exclusive */
473 uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
474 if (fDischarging)
475 uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
476 else if (fCharging)
477 uBs = PDM_ACPI_BAT_STATE_CHARGING;
478 if (fCritical)
479 uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
480 *penmBatteryState = (PDMACPIBATSTATE)uBs;
481
482 if (presentRateTotal < 0)
483 presentRateTotal = -presentRateTotal;
484
485 if (maxCapacityTotal > 0 && currentCapacityTotal > 0)
486 {
487 /* calculate the percentage */
488 *penmRemainingCapacity = (PDMACPIBATCAPACITY)(((float)currentCapacityTotal / (float)maxCapacityTotal)
489 * PDM_ACPI_BAT_CAPACITY_MAX);
490 *pu32PresentRate = (uint32_t)(((float)presentRateTotal / (float)maxCapacityTotal) * 1000);
491 }
492#elif defined(RT_OS_DARWIN)
493 CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
494 CFArrayRef pSources = IOPSCopyPowerSourcesList(pBlob);
495
496 CFDictionaryRef pSource = NULL;
497 const void *psValue;
498 bool result;
499
500 if (CFArrayGetCount(pSources) > 0)
501 {
502 for(int i = 0; i < CFArrayGetCount(pSources); ++i)
503 {
504 pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i));
505 /* If the source is empty skip over to the next one. */
506 if(!pSource)
507 continue;
508 /* Skip all power sources which are currently not present like a
509 * second battery. */
510 if (CFDictionaryGetValue(pSource, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse)
511 continue;
512 /* Only internal power types are of interest. */
513 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
514 if (result &&
515 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
516 {
517 PDMACPIPOWERSOURCE powerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
518 /* First check which power source we are connect on. */
519 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
520 if (result &&
521 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
522 powerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
523 else if (result &&
524 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
525 powerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
526
527 /* At this point the power source is present. */
528 *pfPresent = true;
529 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
530
531 int curCapacity = 0;
532 int maxCapacity = 1;
533 float remCapacity = 0.0f;
534
535 /* Fetch the current capacity value of the power source */
536 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue);
537 if (result)
538 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
539 /* Fetch the maximum capacity value of the power source */
540 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue);
541 if (result)
542 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
543
544 /* Calculate the remaining capacity in percent */
545 remCapacity = ((float)curCapacity/(float)maxCapacity * PDM_ACPI_BAT_CAPACITY_MAX);
546 *penmRemainingCapacity = (PDMACPIBATCAPACITY)remCapacity;
547
548 if (powerSource == PDM_ACPI_POWER_SOURCE_BATTERY)
549 {
550 /* If we are on battery power we are discharging in every
551 * case */
552 *penmBatteryState = PDM_ACPI_BAT_STATE_DISCHARGING;
553 int timeToEmpty = -1;
554 /* Get the time till the battery source will be empty */
555 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToEmptyKey), &psValue);
556 if (result)
557 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToEmpty);
558 if (timeToEmpty != -1)
559 /* 0...1000 */
560 *pu32PresentRate = (uint32_t)roundf((remCapacity / ((float)timeToEmpty/60.0)) * 10.0);
561 }
562
563 if (powerSource == PDM_ACPI_POWER_SOURCE_OUTLET &&
564 CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsChargingKey), &psValue))
565 {
566 /* We are running on an AC power source, but we also have a
567 * battery power source present. */
568 if (CFBooleanGetValue((CFBooleanRef)psValue) > 0)
569 {
570 /* This means charging. */
571 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGING;
572 int timeToFull = -1;
573 /* Get the time till the battery source will be charged */
574 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToFullChargeKey), &psValue);
575 if (result)
576 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToFull);
577 if (timeToFull != -1)
578 /* 0...1000 */
579 *pu32PresentRate = (uint32_t)roundf((100.0-(float)remCapacity) / ((float)timeToFull/60.0)) * 10.0;
580 }
581 }
582
583 /* Check for critical */
584 int criticalValue = 20;
585 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue);
586 if (result)
587 CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue);
588 if (remCapacity < criticalValue)
589 *penmBatteryState = (PDMACPIBATSTATE)(*penmBatteryState | PDM_ACPI_BAT_STATE_CRITICAL);
590 }
591 }
592 }
593 CFRelease(pBlob);
594 CFRelease(pSources);
595#elif defined(RT_OS_FREEBSD)
596 /* We try to use /dev/acpi first and if that fails use the sysctls. */
597 bool fSuccess = true;
598 int FileAcpi = 0;
599 int rc = 0;
600
601 FileAcpi = open("/dev/acpi", O_RDONLY);
602 if (FileAcpi != -1)
603 {
604 bool fMilliWatt;
605 union acpi_battery_ioctl_arg BatteryIo;
606
607 memset(&BatteryIo, 0, sizeof(BatteryIo));
608 BatteryIo.unit = 0; /* Always use the first battery. */
609
610 /* Determine the power units first. */
611 if (ioctl(FileAcpi, ACPIIO_BATT_GET_BIF, &BatteryIo) == -1)
612 fSuccess = false;
613 else
614 {
615 if (BatteryIo.bif.units == ACPI_BIF_UNITS_MW)
616 fMilliWatt = true;
617 else
618 fMilliWatt = false; /* mA */
619
620 BatteryIo.unit = 0;
621 if (ioctl(FileAcpi, ACPIIO_BATT_GET_BATTINFO, &BatteryIo) == -1)
622 fSuccess = false;
623 else
624 {
625 if ((BatteryIo.battinfo.state & ACPI_BATT_STAT_NOT_PRESENT) == ACPI_BATT_STAT_NOT_PRESENT)
626 *pfPresent = false;
627 else
628 {
629 *pfPresent = true;
630
631 if (BatteryIo.battinfo.state & ACPI_BATT_STAT_DISCHARG)
632 *penmBatteryState = PDM_ACPI_BAT_STATE_DISCHARGING;
633 else if (BatteryIo.battinfo.state & ACPI_BATT_STAT_CHARGING)
634 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGING;
635 else
636 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
637
638 if (BatteryIo.battinfo.state & ACPI_BATT_STAT_CRITICAL)
639 *penmBatteryState = (PDMACPIBATSTATE)(*penmBatteryState | PDM_ACPI_BAT_STATE_CRITICAL);
640 }
641
642 if (BatteryIo.battinfo.cap != -1)
643 *penmRemainingCapacity = (PDMACPIBATCAPACITY)BatteryIo.battinfo.cap;
644
645 BatteryIo.unit = 0;
646 if (ioctl(FileAcpi, ACPIIO_BATT_GET_BST, &BatteryIo) == 0)
647 {
648 /* The rate can be either mW or mA but the ACPI device wants mW. */
649 if (BatteryIo.bst.rate != 0xffffffff)
650 {
651 if (fMilliWatt)
652 *pu32PresentRate = BatteryIo.bst.rate;
653 else if (BatteryIo.bst.volt != 0xffffffff)
654 {
655 /*
656 * The rate is in mA so we have to convert it.
657 * The current power rate can be calculated with P = U * I
658 */
659 *pu32PresentRate = (uint32_t)((((float)BatteryIo.bst.volt/1000.0) * ((float)BatteryIo.bst.rate/1000.0)) * 1000.0);
660 }
661 }
662 }
663 }
664 }
665
666 close(FileAcpi);
667 }
668 else
669 fSuccess = false;
670
671 if (!fSuccess)
672 {
673 int fBatteryState = 0;
674 size_t cbParameter = sizeof(fBatteryState);
675
676 rc = sysctlbyname("hw.acpi.battery.state", &fBatteryState, &cbParameter, NULL, NULL);
677 if (!rc)
678 {
679 if ((fBatteryState & ACPI_BATT_STAT_NOT_PRESENT) == ACPI_BATT_STAT_NOT_PRESENT)
680 *pfPresent = false;
681 else
682 {
683 *pfPresent = true;
684
685 if (fBatteryState & ACPI_BATT_STAT_DISCHARG)
686 *penmBatteryState = PDM_ACPI_BAT_STATE_DISCHARGING;
687 else if (fBatteryState & ACPI_BATT_STAT_CHARGING)
688 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGING;
689 else
690 *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
691
692 if (fBatteryState & ACPI_BATT_STAT_CRITICAL)
693 *penmBatteryState = (PDMACPIBATSTATE)(*penmBatteryState | PDM_ACPI_BAT_STATE_CRITICAL);
694
695 /* Get battery level. */
696 int curCapacity = 0;
697 cbParameter = sizeof(curCapacity);
698 rc = sysctlbyname("hw.acpi.battery.life", &curCapacity, &cbParameter, NULL, NULL);
699 if ((!rc) && (curCapacity >= 0))
700 *penmRemainingCapacity = (PDMACPIBATCAPACITY)curCapacity;
701
702 /* The rate can't be determined with sysctls. */
703 }
704 }
705 }
706#endif /* RT_OS_FREEBSD */
707 return VINF_SUCCESS;
708}
709
710/**
711 * Destruct a driver instance.
712 *
713 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
714 * resources can be freed correctly.
715 *
716 * @param pDrvIns The driver instance data.
717 */
718static DECLCALLBACK(void) drvACPIDestruct(PPDMDRVINS pDrvIns)
719{
720 LogFlow(("drvACPIDestruct\n"));
721}
722
723/**
724 * Construct an ACPI driver instance.
725 *
726 * @returns VBox status.
727 * @param pDrvIns The driver instance data.
728 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
729 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
730 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
731 * iInstance it's expected to be used a bit in this function.
732 */
733static DECLCALLBACK(int) drvACPIConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
734{
735 PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
736
737 /*
738 * Init the static parts.
739 */
740 pThis->pDrvIns = pDrvIns;
741 /* IBase */
742 pDrvIns->IBase.pfnQueryInterface = drvACPIQueryInterface;
743 /* IACPIConnector */
744 pThis->IACPIConnector.pfnQueryPowerSource = drvACPIQueryPowerSource;
745 pThis->IACPIConnector.pfnQueryBatteryStatus = drvACPIQueryBatteryStatus;
746
747 /*
748 * Validate the config.
749 */
750 if (!CFGMR3AreValuesValid(pCfgHandle, "\0"))
751 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
752
753 /*
754 * Check that no-one is attached to us.
755 */
756 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
757 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
758 {
759 AssertMsgFailed(("Configuration error: Cannot attach drivers to the ACPI driver!\n"));
760 return VERR_PDM_DRVINS_NO_ATTACH;
761 }
762
763 /*
764 * Query the ACPI port interface.
765 */
766 pThis->pPort = (PPDMIACPIPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase,
767 PDMINTERFACE_ACPI_PORT);
768 if (!pThis->pPort)
769 {
770 AssertMsgFailed(("Configuration error: "
771 "the above device/driver didn't export the ACPI port interface!\n"));
772 return VERR_PDM_MISSING_INTERFACE_ABOVE;
773 }
774
775 return VINF_SUCCESS;
776}
777
778
779/**
780 * ACPI driver registration record.
781 */
782const PDMDRVREG g_DrvACPI =
783{
784 /* u32Version */
785 PDM_DRVREG_VERSION,
786 /* szDriverName */
787 "ACPIHost",
788 /* pszDescription */
789 "ACPI Host Driver",
790 /* fFlags */
791 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
792 /* fClass. */
793 PDM_DRVREG_CLASS_ACPI,
794 /* cMaxInstances */
795 ~0,
796 /* cbInstance */
797 sizeof(DRVACPI),
798 /* pfnConstruct */
799 drvACPIConstruct,
800 /* pfnDestruct */
801 drvACPIDestruct,
802 /* pfnIOCtl */
803 NULL,
804 /* pfnPowerOn */
805 NULL,
806 /* pfnReset */
807 NULL,
808 /* pfnSuspend */
809 NULL,
810 /* pfnResume */
811 NULL,
812 /* pfnDetach */
813 NULL,
814 /* pfnPowerOff */
815 NULL
816};
817
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use