VirtualBox

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

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

pdmifs.h: the penultimate batch of refactored interface ID code.

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