VirtualBox

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

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

PDM,*: Redid the PDM structure versions. Check the instance and helper versions in every device and driver constructor.

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