4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/* $Id$ */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/** @file
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * DrvACPI - ACPI Host Driver.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/*
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Copyright (C) 2006-2012 Oracle Corporation
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * available from http://www.virtualbox.org. This file is free software;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * you can redistribute it and/or modify it under the terms of the GNU
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * General Public License (GPL) as published by the Free Software
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/*******************************************************************************
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Header Files *
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync*******************************************************************************/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define LOG_GROUP LOG_GROUP_DRV_ACPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#ifdef RT_OS_WINDOWS
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <windows.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#endif
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <VBox/vmm/pdmdrv.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <VBox/log.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <iprt/asm.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <iprt/assert.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <iprt/string.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include <iprt/uuid.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#ifdef RT_OS_LINUX
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <iprt/critsect.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <iprt/dir.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <iprt/semaphore.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <iprt/stream.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#endif
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#ifdef RT_OS_DARWIN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <Carbon/Carbon.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <IOKit/ps/IOPowerSources.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <IOKit/ps/IOPSKeys.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#endif
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#ifdef RT_OS_FREEBSD
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <sys/ioctl.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <dev/acpica/acpiio.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <sys/types.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <sys/sysctl.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <stdio.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <errno.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <fcntl.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync# include <unistd.h>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#endif
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#include "VBoxDD.h"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/*******************************************************************************
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Structures and Typedefs *
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync*******************************************************************************/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * ACPI driver instance data.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * @implements PDMIACPICONNECTOR
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynctypedef struct DRVACPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** The ACPI interface. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMIACPICONNECTOR IACPIConnector;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** The ACPI port interface. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PPDMIACPIPORT pPort;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** Pointer to the driver instance. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PPDMDRVINS pDrvIns;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#ifdef RT_OS_LINUX
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** The current power source. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMACPIPOWERSOURCE enmPowerSource;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** true = one or more batteries preset, false = no battery present. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool fBatteryPresent;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** No need to RTThreadPoke the poller when set. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool volatile fDontPokePoller;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** Remaining battery capacity. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMACPIBATCAPACITY enmBatteryRemainingCapacity;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** Battery state. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMACPIBATSTATE enmBatteryState;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** Preset battery charging/discharging rate. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync uint32_t u32BatteryPresentRate;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** The poller thread. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PPDMTHREAD pPollerThread;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** Synchronize access to the above fields.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * XXX A spinlock is probably cheaper ... */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync RTCRITSECT CritSect;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /** Event semaphore the poller thread is sleeping on. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync RTSEMEVENT hPollerSleepEvent;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#endif
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync} DRVACPI, *PDRVACPI;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstatic DECLCALLBACK(void *) drvACPIQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPICONNECTOR, &pThis->IACPIConnector);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * Get the current power source of the host system.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * @returns status code
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * @param pPowerSource Pointer to the power source result variable.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstatic DECLCALLBACK(int) drvACPIQueryPowerSource(PPDMIACPICONNECTOR pInterface,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMACPIPOWERSOURCE *pPowerSource)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#if defined(RT_OS_WINDOWS)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SYSTEM_POWER_STATUS powerStatus;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (GetSystemPowerStatus(&powerStatus))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* running on battery? */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ( powerStatus.ACLineStatus == 0 /* Offline */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync || powerStatus.ACLineStatus == 255 /* Unknown */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && (powerStatus.BatteryFlag & 15) /* high | low | critical | charging */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ) /** @todo why is 'charging' included in the flag test? Add parenthesis around the right bits so the code is clearer. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* running on AC link? */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (powerStatus.ACLineStatus == 1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* what the hell we're running on? */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync GetLastError()));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#elif defined (RT_OS_LINUX)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDRVACPI pThis = RT_FROM_MEMBER(pInterface, DRVACPI, IACPIConnector);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync RTCritSectEnter(&pThis->CritSect);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = pThis->enmPowerSource;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync RTCritSectLeave(&pThis->CritSect);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#elif defined (RT_OS_DARWIN)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFArrayRef pSources = IOPSCopyPowerSourcesList(pBlob);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFDictionaryRef pSource = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const void *psValue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool fResult;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (CFArrayGetCount(pSources) > 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (int i = 0; i < CFArrayGetCount(pSources); ++i)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* If the source is empty skip over to the next one. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if(!pSource)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync continue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Skip all power sources which are currently not present like a
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * second battery. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (CFDictionaryGetValue(pSource, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync continue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Only internal power types are of interest. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ( fResult
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Check which power source we are connect on. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ( fResult
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if ( fResult
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFRelease(pBlob);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFRelease(pSources);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#elif defined(RT_OS_FREEBSD)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int fAcLine = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync size_t cbParameter = sizeof(fAcLine);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int rc = sysctlbyname("hw.acpi.acline", &fAcLine, &cbParameter, NULL, 0);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!rc)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (fAcLine == 1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (fAcLine == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync AssertMsg(errno == ENOENT, ("rc=%d (%s)\n", rc, strerror(errno)));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#else /* !RT_OS_FREEBSD either - what could this be? */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#endif /* !RT_OS_FREEBSD */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync return VINF_SUCCESS;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync}
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync/**
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * @copydoc PDMIACPICONNECTOR::pfnQueryBatteryStatus
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncstatic DECLCALLBACK(int) drvACPIQueryBatteryStatus(PPDMIACPICONNECTOR pInterface, bool *pfPresent,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PPDMACPIBATCAPACITY penmRemainingCapacity,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PPDMACPIBATSTATE penmBatteryState,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync uint32_t *pu32PresentRate)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync{
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* default return values for all architectures */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = false; /* no battery present */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmRemainingCapacity = PDM_ACPI_BAT_CAPACITY_UNKNOWN;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pu32PresentRate = ~0; /* present rate is unknown */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#if defined(RT_OS_WINDOWS)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync SYSTEM_POWER_STATUS powerStatus;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (GetSystemPowerStatus(&powerStatus))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* 128 means no battery present */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = !(powerStatus.BatteryFlag & 128);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* just forward the value directly */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmRemainingCapacity = (PDMACPIBATCAPACITY)powerStatus.BatteryLifePercent;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* we assume that we are discharging the battery if we are not on-line and
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * not charge the battery */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (powerStatus.BatteryFlag & 8)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync uBs = PDM_ACPI_BAT_STATE_CHARGING;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (powerStatus.ACLineStatus == 0 || powerStatus.ACLineStatus == 255)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (powerStatus.BatteryFlag & 4)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = (PDMACPIBATSTATE)uBs;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* on Windows it is difficult to request the present charging/discharging rate */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync GetLastError()));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#elif defined(RT_OS_LINUX)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDRVACPI pThis = RT_FROM_MEMBER(pInterface, DRVACPI, IACPIConnector);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync RTCritSectEnter(&pThis->CritSect);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = pThis->fBatteryPresent;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmRemainingCapacity = pThis->enmBatteryRemainingCapacity;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = pThis->enmBatteryState;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pu32PresentRate = pThis->u32BatteryPresentRate;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync RTCritSectLeave(&pThis->CritSect);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#elif defined(RT_OS_DARWIN)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFArrayRef pSources = IOPSCopyPowerSourcesList(pBlob);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFDictionaryRef pSource = NULL;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync const void *psValue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool fResult;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (CFArrayGetCount(pSources) > 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync for (int i = 0; i < CFArrayGetCount(pSources); ++i)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* If the source is empty skip over to the next one. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if(!pSource)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync continue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Skip all power sources which are currently not present like a
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * second battery. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (CFDictionaryGetValue(pSource, CFSTR(kIOPSIsPresentKey)) == kCFBooleanFalse)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync continue;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Only internal power types are of interest. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ( fResult
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync PDMACPIPOWERSOURCE powerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* First check which power source we are connect on. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ( fResult
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync powerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if ( fResult
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync powerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* At this point the power source is present. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = true;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int curCapacity = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int maxCapacity = 1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync float remCapacity = 0.0f;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Fetch the current capacity value of the power source */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (fResult)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Fetch the maximum capacity value of the power source */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (fResult)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Calculate the remaining capacity in percent */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync remCapacity = ((float)curCapacity/(float)maxCapacity * PDM_ACPI_BAT_CAPACITY_MAX);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmRemainingCapacity = (PDMACPIBATCAPACITY)remCapacity;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (powerSource == PDM_ACPI_POWER_SOURCE_BATTERY)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* If we are on battery power we are discharging in every
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * case */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = PDM_ACPI_BAT_STATE_DISCHARGING;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int timeToEmpty = -1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Get the time till the battery source will be empty */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToEmptyKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (fResult)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToEmpty);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (timeToEmpty != -1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* 0...1000 */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pu32PresentRate = (uint32_t)roundf((remCapacity / ((float)timeToEmpty/60.0)) * 10.0);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ( powerSource == PDM_ACPI_POWER_SOURCE_OUTLET
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync && CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsChargingKey), &psValue))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* We are running on an AC power source, but we also have a
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * battery power source present. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (CFBooleanGetValue((CFBooleanRef)psValue) > 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* This means charging. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGING;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int timeToFull = -1;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Get the time till the battery source will be charged */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToFullChargeKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (fResult)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToFull);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (timeToFull != -1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* 0...1000 */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pu32PresentRate = (uint32_t)roundf((100.0-(float)remCapacity) / ((float)timeToFull/60.0)) * 10.0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Check for critical */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int criticalValue = 20;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (fResult)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (remCapacity < criticalValue)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = (PDMACPIBATSTATE)(*penmBatteryState | PDM_ACPI_BAT_STATE_CRITICAL);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFRelease(pBlob);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync CFRelease(pSources);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#elif defined(RT_OS_FREEBSD)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* We try to use /dev/acpi first and if that fails use the sysctls. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool fSuccess = true;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int FileAcpi = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int rc = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync FileAcpi = open("/dev/acpi", O_RDONLY);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (FileAcpi != -1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync bool fMilliWatt;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync union acpi_battery_ioctl_arg BatteryIo;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync memset(&BatteryIo, 0, sizeof(BatteryIo));
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BatteryIo.unit = 0; /* Always use the first battery. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* Determine the power units first. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (ioctl(FileAcpi, ACPIIO_BATT_GET_BIF, &BatteryIo) == -1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fSuccess = false;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (BatteryIo.bif.units == ACPI_BIF_UNITS_MW)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fMilliWatt = true;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fMilliWatt = false; /* mA */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BatteryIo.unit = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (ioctl(FileAcpi, ACPIIO_BATT_GET_BATTINFO, &BatteryIo) == -1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fSuccess = false;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((BatteryIo.battinfo.state & ACPI_BATT_STAT_NOT_PRESENT) == ACPI_BATT_STAT_NOT_PRESENT)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = false;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = true;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (BatteryIo.battinfo.state & ACPI_BATT_STAT_DISCHARG)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = PDM_ACPI_BAT_STATE_DISCHARGING;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (BatteryIo.battinfo.state & ACPI_BATT_STAT_CHARGING)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGING;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (BatteryIo.battinfo.state & ACPI_BATT_STAT_CRITICAL)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmBatteryState = (PDMACPIBATSTATE)(*penmBatteryState | PDM_ACPI_BAT_STATE_CRITICAL);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (BatteryIo.battinfo.cap != -1)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *penmRemainingCapacity = (PDMACPIBATCAPACITY)BatteryIo.battinfo.cap;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync BatteryIo.unit = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (ioctl(FileAcpi, ACPIIO_BATT_GET_BST, &BatteryIo) == 0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /* The rate can be either mW or mA but the ACPI device wants mW. */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (BatteryIo.bst.rate != 0xffffffff)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (fMilliWatt)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pu32PresentRate = BatteryIo.bst.rate;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else if (BatteryIo.bst.volt != 0xffffffff)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync /*
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * The rate is in mA so we have to convert it.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * The current power rate can be calculated with P = U * I
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync */
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pu32PresentRate = (uint32_t)( ( ((float)BatteryIo.bst.volt/1000.0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * ((float)BatteryIo.bst.rate/1000.0))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync * 1000.0);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync close(FileAcpi);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync }
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync fSuccess = false;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!fSuccess)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync int fBatteryState = 0;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync size_t cbParameter = sizeof(fBatteryState);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync rc = sysctlbyname("hw.acpi.battery.state", &fBatteryState, &cbParameter, NULL, 0);
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if (!rc)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync if ((fBatteryState & ACPI_BATT_STAT_NOT_PRESENT) == ACPI_BATT_STAT_NOT_PRESENT)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = false;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync else
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync {
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync *pfPresent = true;
if (fBatteryState & ACPI_BATT_STAT_DISCHARG)
*penmBatteryState = PDM_ACPI_BAT_STATE_DISCHARGING;
else if (fBatteryState & ACPI_BATT_STAT_CHARGING)
*penmBatteryState = PDM_ACPI_BAT_STATE_CHARGING;
else
*penmBatteryState = PDM_ACPI_BAT_STATE_CHARGED;
if (fBatteryState & ACPI_BATT_STAT_CRITICAL)
*penmBatteryState = (PDMACPIBATSTATE)(*penmBatteryState | PDM_ACPI_BAT_STATE_CRITICAL);
/* Get battery level. */
int curCapacity = 0;
cbParameter = sizeof(curCapacity);
rc = sysctlbyname("hw.acpi.battery.life", &curCapacity, &cbParameter, NULL, 0);
if (!rc && curCapacity >= 0)
*penmRemainingCapacity = (PDMACPIBATCAPACITY)curCapacity;
/* The rate can't be determined with sysctls. */
}
}
}
#endif /* RT_OS_FREEBSD */
return VINF_SUCCESS;
}
#ifdef RT_OS_LINUX
/**
* Poller thread for /proc/acpi status files.
*
* Reading these files takes ages (several seconds) on some hosts, therefore
* start this thread. The termination of this thread may take some seconds
* on such a hosts!
*
* @param pDrvIns The driver instance data.
* @param pThread The thread.
*/
static DECLCALLBACK(int) drvACPIPoller(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
return VINF_SUCCESS;
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
ASMAtomicWriteBool(&pThis->fDontPokePoller, false);
PDMACPIPOWERSOURCE enmPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
PRTSTREAM pStrmStatus;
PRTSTREAM pStrmType;
PRTDIR pDir = NULL;
RTDIRENTRY DirEntry;
char szLine[1024];
bool fBatteryPresent = false; /* one or more batteries present */
bool fCharging = false; /* one or more batteries charging */
bool fDischarging = false; /* one or more batteries discharging */
bool fCritical = false; /* one or more batteries in critical state */
int32_t maxCapacityTotal = 0; /* total capacity of all batteries */
int32_t currentCapacityTotal = 0; /* total current capacity of all batteries */
int32_t presentRateTotal = 0; /* total present (dis)charging rate of all batts */
int rc = RTDirOpen(&pDir, "/sys/class/power_supply/");
if (RT_SUCCESS(rc))
{
/*
* The new /sys interface introduced with Linux 2.6.25.
*/
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
rc = RTDirRead(pDir, &DirEntry, NULL);
if (RT_FAILURE(rc))
break;
if ( strcmp(DirEntry.szName, ".") == 0
|| strcmp(DirEntry.szName, "..") == 0)
continue;
#define POWER_OPEN(s, n) RTStrmOpenF("r", s, "/sys/class/power_supply/%s/" n, DirEntry.szName)
rc = POWER_OPEN(&pStrmType, "type");
if (RT_FAILURE(rc))
continue;
rc = RTStrmGetLine(pStrmType, szLine, sizeof(szLine));
if (RT_SUCCESS(rc))
{
if (strcmp(szLine, "Mains") == 0)
{
/* AC adapter */
rc = POWER_OPEN(&pStrmStatus, "online");
if (RT_SUCCESS(rc))
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if ( RT_SUCCESS(rc)
&& strcmp(szLine, "1") == 0)
enmPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
else
enmPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
RTStrmClose(pStrmStatus);
}
}
else if (strcmp(szLine, "Battery") == 0)
{
/* Battery */
rc = POWER_OPEN(&pStrmStatus, "present");
if (RT_SUCCESS(rc))
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
RTStrmClose(pStrmStatus);
if ( RT_SUCCESS(rc)
&& strcmp(szLine, "1") == 0)
{
fBatteryPresent = true;
rc = RTStrmOpenF("r", &pStrmStatus,
"/sys/class/power_supply/%s/status", DirEntry.szName);
if (RT_SUCCESS(rc))
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if (RT_SUCCESS(rc))
{
if (strcmp(szLine, "Discharging") == 0)
fDischarging = true;
else if (strcmp(szLine, "Charging") == 0)
fCharging = true;
}
RTStrmClose(pStrmStatus);
}
rc = POWER_OPEN(&pStrmStatus, "capacity_level");
if (RT_SUCCESS(rc))
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if ( RT_SUCCESS(rc)
&& strcmp(szLine, "Critical") == 0)
fCritical = true;
RTStrmClose(pStrmStatus);
}
rc = POWER_OPEN(&pStrmStatus, "energy_full");
if (RT_FAILURE(rc))
rc = POWER_OPEN(&pStrmStatus, "charge_full");
if (RT_SUCCESS(rc))
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if (RT_SUCCESS(rc))
{
int32_t maxCapacity = 0;
rc = RTStrToInt32Full(szLine, 0, &maxCapacity);
if ( RT_SUCCESS(rc)
&& maxCapacity > 0)
maxCapacityTotal += maxCapacity;
}
RTStrmClose(pStrmStatus);
}
rc = POWER_OPEN(&pStrmStatus, "energy_now");
if (RT_FAILURE(rc))
rc = POWER_OPEN(&pStrmStatus, "charge_now");
if (RT_SUCCESS(rc))
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if (RT_SUCCESS(rc))
{
int32_t currentCapacity = 0;
rc = RTStrToInt32Full(szLine, 0, &currentCapacity);
if ( RT_SUCCESS(rc)
&& currentCapacity > 0)
currentCapacityTotal += currentCapacity;
}
RTStrmClose(pStrmStatus);
}
rc = POWER_OPEN(&pStrmStatus, "current_now");
if (RT_SUCCESS(rc))
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if (RT_SUCCESS(rc))
{
int32_t presentRate = 0;
rc = RTStrToInt32Full(szLine, 0, &presentRate);
if ( RT_SUCCESS(rc)
&& presentRate > 0)
{
if (fDischarging)
presentRateTotal -= presentRate;
else
presentRateTotal += presentRate;
}
}
RTStrmClose(pStrmStatus);
}
}
}
}
}
RTStrmClose(pStrmType);
#undef POWER_OPEN
}
RTDirClose(pDir);
}
else /* !/sys */
{
/*
* The old /proc/acpi interface
*/
/*
* Read the status of the powerline-adapter.
*/
rc = RTDirOpen(&pDir, "/proc/acpi/ac_adapter/");
if (RT_SUCCESS(rc))
{
#define POWER_OPEN(s, n) RTStrmOpenF("r", s, "/proc/acpi/ac_adapter/%s/" n, DirEntry.szName)
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
rc = RTDirRead(pDir, &DirEntry, NULL);
if (RT_FAILURE(rc))
break;
if ( strcmp(DirEntry.szName, ".") == 0
|| strcmp(DirEntry.szName, "..") == 0)
continue;
rc = POWER_OPEN(&pStrmStatus, "status");
if (RT_FAILURE(rc))
rc = POWER_OPEN(&pStrmStatus, "state");
if (RT_SUCCESS(rc))
{
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if (RT_FAILURE(rc))
break;
if ( strstr(szLine, "Status:") != NULL
|| strstr(szLine, "state:") != NULL)
{
if (strstr(szLine, "on-line") != NULL)
enmPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
else
enmPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
break;
}
}
RTStrmClose(pStrmStatus);
break;
}
}
RTDirClose(pDir);
#undef POWER_OPEN
}
/*
* Read the status of all batteries and collect it into one.
*/
rc = RTDirOpen(&pDir, "/proc/acpi/battery/");
if (RT_SUCCESS(rc))
{
#define POWER_OPEN(s, n) RTStrmOpenF("r", s, "/proc/acpi/battery/%s/" n, DirEntry.szName)
bool fThisBatteryPresent = false;
bool fThisDischarging = false;
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
rc = RTDirRead(pDir, &DirEntry, NULL);
if (RT_FAILURE(rc))
break;
if ( strcmp(DirEntry.szName, ".") == 0
|| strcmp(DirEntry.szName, "..") == 0)
continue;
rc = POWER_OPEN(&pStrmStatus, "status");
/* there is a 2nd variant of that file */
if (RT_FAILURE(rc))
rc = POWER_OPEN(&pStrmStatus, "state");
if (RT_FAILURE(rc))
continue;
PRTSTREAM pStrmInfo;
rc = POWER_OPEN(&pStrmInfo, "info");
if (RT_FAILURE(rc))
{
RTStrmClose(pStrmStatus);
continue;
}
/* get 'present' status from the info file */
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
rc = RTStrmGetLine(pStrmInfo, szLine, sizeof(szLine));
if (RT_FAILURE(rc))
break;
if (strstr(szLine, "present:") != NULL)
{
if (strstr(szLine, "yes") != NULL)
{
fThisBatteryPresent = true;
break;
}
}
}
if (fThisBatteryPresent)
{
fBatteryPresent = true;
RTStrmRewind(pStrmInfo);
/* get the maximum capacity from the info file */
while (pThread->enmState == PDMTHREADSTATE_RUNNING)
{
rc = RTStrmGetLine(pStrmInfo, szLine, sizeof(szLine));
if (RT_FAILURE(rc))
break;
if (strstr(szLine, "last full capacity:") != NULL)
{
char *psz;
int32_t maxCapacity = 0;
rc = RTStrToInt32Ex(RTStrStripL(&szLine[19]), &psz, 0, &maxCapacity);
if (RT_FAILURE(rc))
maxCapacity = 0;
maxCapacityTotal += maxCapacity;
break;
}
}
/* get the current capacity/state from the status file */
int32_t presentRate = 0;
bool fGotRemainingCapacity = false;
bool fGotBatteryState = false;
bool fGotCapacityState = false;
bool fGotPresentRate = false;
while ( ( !fGotRemainingCapacity
|| !fGotBatteryState
|| !fGotCapacityState
|| !fGotPresentRate)
&& pThread->enmState == PDMTHREADSTATE_RUNNING)
{
rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
if (RT_FAILURE(rc))
break;
if (strstr(szLine, "remaining capacity:") != NULL)
{
char *psz;
int32_t currentCapacity = 0;
rc = RTStrToInt32Ex(RTStrStripL(&szLine[19]), &psz, 0, &currentCapacity);
if ( RT_SUCCESS(rc)
&& currentCapacity > 0)
currentCapacityTotal += currentCapacity;
fGotRemainingCapacity = true;
}
else if (strstr(szLine, "charging state:") != NULL)
{
if (strstr(szLine + 15, "discharging") != NULL)
{
fDischarging = true;
fThisDischarging = true;
}
else if (strstr(szLine + 15, "charging") != NULL)
fCharging = true;
fGotBatteryState = true;
}
else if (strstr(szLine, "capacity state:") != NULL)
{
if (strstr(szLine + 15, "critical") != NULL)
fCritical = true;
fGotCapacityState = true;
}
if (strstr(szLine, "present rate:") != NULL)
{
char *psz;
rc = RTStrToInt32Ex(RTStrStripL(&szLine[13]), &psz, 0, &presentRate);
if (RT_FAILURE(rc))
presentRate = 0;
fGotPresentRate = true;
}
}
if (fThisDischarging)
presentRateTotal -= presentRate;
else
presentRateTotal += presentRate;
}
RTStrmClose(pStrmStatus);
RTStrmClose(pStrmInfo);
}
RTDirClose(pDir);
#undef POWER_OPEN
}
} /* /proc/acpi */
/* atomic update of the state */
RTCritSectEnter(&pThis->CritSect);
pThis->enmPowerSource = enmPowerSource;
pThis->fBatteryPresent = fBatteryPresent;
/* charging/discharging bits are mutual exclusive */
uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
if (fDischarging)
uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
else if (fCharging)
uBs = PDM_ACPI_BAT_STATE_CHARGING;
if (fCritical)
uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
pThis->enmBatteryState = (PDMACPIBATSTATE)uBs;
if (maxCapacityTotal > 0 && currentCapacityTotal > 0)
{
if (presentRateTotal < 0)
presentRateTotal = -presentRateTotal;
/* calculate the percentage */
pThis->enmBatteryRemainingCapacity =
(PDMACPIBATCAPACITY)( ( (float)currentCapacityTotal
/ (float)maxCapacityTotal)
* PDM_ACPI_BAT_CAPACITY_MAX);
pThis->u32BatteryPresentRate =
(uint32_t)(( (float)presentRateTotal
/ (float)maxCapacityTotal) * 1000);
}
else
{
/* unknown capacity / state */
pThis->enmBatteryRemainingCapacity = PDM_ACPI_BAT_CAPACITY_UNKNOWN;
pThis->u32BatteryPresentRate = ~0;
}
RTCritSectLeave(&pThis->CritSect);
/* wait a bit (e.g. Ubuntu/GNOME polls every 30 seconds) */
ASMAtomicWriteBool(&pThis->fDontPokePoller, true);
rc = RTSemEventWait(pThis->hPollerSleepEvent, 20000);
}
return VINF_SUCCESS;
}
static DECLCALLBACK(int) drvACPIPollerWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
RTSemEventSignal(pThis->hPollerSleepEvent);
if (!ASMAtomicReadBool(&pThis->fDontPokePoller))
RTThreadPoke(pThread->Thread);
return VINF_SUCCESS;
}
#endif /* RT_OS_LINUX */
/**
* Destruct a driver instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) drvACPIDestruct(PPDMDRVINS pDrvIns)
{
PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
LogFlow(("drvACPIDestruct\n"));
PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
#ifdef RT_OS_LINUX
if (pThis->hPollerSleepEvent != NIL_RTSEMEVENT)
{
RTSemEventDestroy(pThis->hPollerSleepEvent);
pThis->hPollerSleepEvent = NIL_RTSEMEVENT;
}
RTCritSectDelete(&pThis->CritSect);
#endif
}
/**
* Construct an ACPI driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
static DECLCALLBACK(int) drvACPIConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
int rc = VINF_SUCCESS;
/*
* Init the static parts.
*/
pThis->pDrvIns = pDrvIns;
#ifdef RT_OS_LINUX
pThis->hPollerSleepEvent = NIL_RTSEMEVENT;
#endif
/* IBase */
pDrvIns->IBase.pfnQueryInterface = drvACPIQueryInterface;
/* IACPIConnector */
pThis->IACPIConnector.pfnQueryPowerSource = drvACPIQueryPowerSource;
pThis->IACPIConnector.pfnQueryBatteryStatus = drvACPIQueryBatteryStatus;
/*
* Validate the config.
*/
if (!CFGMR3AreValuesValid(pCfg, "\0"))
return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
/*
* Check that no-one is attached to us.
*/
AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
("Configuration error: Not possible to attach anything to this driver!\n"),
VERR_PDM_DRVINS_NO_ATTACH);
/*
* Query the ACPI port interface.
*/
pThis->pPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIACPIPORT);
if (!pThis->pPort)
{
AssertMsgFailed(("Configuration error: the above device/driver didn't export the ACPI port interface!\n"));
return VERR_PDM_MISSING_INTERFACE_ABOVE;
}
#ifdef RT_OS_LINUX
/*
* Start the poller thread.
*/
rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pPollerThread, pThis, drvACPIPoller,
drvACPIPollerWakeup, 0, RTTHREADTYPE_INFREQUENT_POLLER, "ACPI Poller");
if (RT_FAILURE(rc))
return rc;
rc = RTCritSectInit(&pThis->CritSect);
if (RT_FAILURE(rc))
return rc;
rc = RTSemEventCreate(&pThis->hPollerSleepEvent);
#endif
return rc;
}
/**
* ACPI driver registration record.
*/
const PDMDRVREG g_DrvACPI =
{
/* u32Version */
PDM_DRVREG_VERSION,
/* szName */
"ACPIHost",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"ACPI Host Driver",
/* fFlags */
PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
/* fClass. */
PDM_DRVREG_CLASS_ACPI,
/* cMaxInstances */
~0U,
/* cbInstance */
sizeof(DRVACPI),
/* pfnConstruct */
drvACPIConstruct,
/* pfnDestruct */
drvACPIDestruct,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
PDM_DRVREG_VERSION
};