DrvACPI.cpp revision 1e1273b11e17928ec3c3a8fff45121aa7a169413
/* $Id$ */
/** @file
* DrvACPI - ACPI Host Driver.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_ACPI
#ifdef RT_OS_WINDOWS
# include <windows.h>
#endif
#ifdef RT_OS_LINUX
# include <iprt/critsect.h>
# include <iprt/semaphore.h>
#endif
#ifdef RT_OS_DARWIN
#endif
#ifdef RT_OS_FREEBSD
# include <stdio.h>
# include <errno.h>
# include <fcntl.h>
# include <unistd.h>
#endif
#include "VBoxDD.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* ACPI driver instance data.
*
* @implements PDMIACPICONNECTOR
*/
typedef struct DRVACPI
{
/** The ACPI interface. */
/** The ACPI port interface. */
/** Pointer to the driver instance. */
#ifdef RT_OS_LINUX
/** The current power source. */
/** true = one or more batteries preset, false = no battery present. */
bool fBatteryPresent;
/** No need to RTThreadPoke the poller when set. */
bool volatile fDontPokePoller;
/** Remaining battery capacity. */
/** Battery state. */
/** Preset battery charging/discharging rate. */
/** The poller thread. */
/** Synchronize access to the above fields.
* XXX A spinlock is probably cheaper ... */
/** Event semaphore the poller thread is sleeping on. */
#endif
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
return NULL;
}
/**
* Get the current power source of the host system.
*
* @returns status code
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param pPowerSource Pointer to the power source result variable.
*/
{
#if defined(RT_OS_WINDOWS)
if (GetSystemPowerStatus(&powerStatus))
{
/* running on battery? */
) /** @todo why is 'charging' included in the flag test? Add parenthesis around the right bits so the code is clearer. */
{
}
/* running on AC link? */
{
}
else
/* what the hell we're running on? */
{
}
}
else
{
AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
GetLastError()));
}
#elif defined (RT_OS_LINUX)
#elif defined (RT_OS_DARWIN)
const void *psValue;
bool fResult;
if (CFArrayGetCount(pSources) > 0)
{
for (int i = 0; i < CFArrayGetCount(pSources); ++i)
{
/* If the source is empty skip over to the next one. */
if(!pSource)
continue;
/* Skip all power sources which are currently not present like a
* second battery. */
continue;
/* Only internal power types are of interest. */
if ( fResult
{
/* Check which power source we are connect on. */
if ( fResult
else if ( fResult
}
}
}
#elif defined(RT_OS_FREEBSD)
int fAcLine = 0;
if (!rc)
{
if (fAcLine == 1)
else if (fAcLine == 0)
else
}
else
{
}
#else /* !RT_OS_FREEBSD either - what could this be? */
#endif /* !RT_OS_FREEBSD */
return VINF_SUCCESS;
}
/**
* @copydoc PDMIACPICONNECTOR::pfnQueryBatteryStatus
*/
{
/* default return values for all architectures */
*pfPresent = false; /* no battery present */
*pu32PresentRate = ~0; /* present rate is unknown */
#if defined(RT_OS_WINDOWS)
if (GetSystemPowerStatus(&powerStatus))
{
/* 128 means no battery present */
/* just forward the value directly */
/* we assume that we are discharging the battery if we are not on-line and
* not charge the battery */
/* on Windows it is difficult to request the present charging/discharging rate */
}
else
{
AssertMsgFailed(("Could not determine system power status, error: 0x%x\n",
GetLastError()));
}
#elif defined(RT_OS_LINUX)
#elif defined(RT_OS_DARWIN)
const void *psValue;
bool fResult;
if (CFArrayGetCount(pSources) > 0)
{
for (int i = 0; i < CFArrayGetCount(pSources); ++i)
{
/* If the source is empty skip over to the next one. */
if(!pSource)
continue;
/* Skip all power sources which are currently not present like a
* second battery. */
continue;
/* Only internal power types are of interest. */
if ( fResult
{
/* First check which power source we are connect on. */
if ( fResult
else if ( fResult
/* At this point the power source is present. */
*pfPresent = true;
int curCapacity = 0;
int maxCapacity = 1;
float remCapacity = 0.0f;
/* Fetch the current capacity value of the power source */
if (fResult)
/* Fetch the maximum capacity value of the power source */
if (fResult)
/* Calculate the remaining capacity in percent */
{
/* If we are on battery power we are discharging in every
* case */
int timeToEmpty = -1;
/* Get the time till the battery source will be empty */
if (fResult)
if (timeToEmpty != -1)
/* 0...1000 */
}
{
/* We are running on an AC power source, but we also have a
* battery power source present. */
{
/* This means charging. */
int timeToFull = -1;
/* Get the time till the battery source will be charged */
if (fResult)
if (timeToFull != -1)
/* 0...1000 */
}
}
/* Check for critical */
int criticalValue = 20;
if (fResult)
if (remCapacity < criticalValue)
}
}
}
#elif defined(RT_OS_FREEBSD)
bool fSuccess = true;
int FileAcpi = 0;
int rc = 0;
if (FileAcpi != -1)
{
bool fMilliWatt;
union acpi_battery_ioctl_arg BatteryIo;
/* Determine the power units first. */
fSuccess = false;
else
{
fMilliWatt = true;
else
fMilliWatt = false; /* mA */
fSuccess = false;
else
{
*pfPresent = false;
else
{
*pfPresent = true;
else
}
{
/* The rate can be either mW or mA but the ACPI device wants mW. */
{
if (fMilliWatt)
{
/*
* The rate is in mA so we have to convert it.
* The current power rate can be calculated with P = U * I
*/
* 1000.0);
}
}
}
}
}
}
else
fSuccess = false;
if (!fSuccess)
{
int fBatteryState = 0;
if (!rc)
{
*pfPresent = false;
else
{
*pfPresent = true;
else if (fBatteryState & ACPI_BATT_STAT_CHARGING)
else
/* Get battery level. */
int curCapacity = 0;
cbParameter = sizeof(curCapacity);
if (!rc && curCapacity >= 0)
/* The rate can't be determined with sysctls. */
}
}
}
#endif /* RT_OS_FREEBSD */
return VINF_SUCCESS;
}
#ifdef RT_OS_LINUX
/**
*
* 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.
*/
{
return VINF_SUCCESS;
{
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 */
if (RT_SUCCESS(rc))
{
/*
* The new /sys interface introduced with Linux 2.6.25.
*/
{
if (RT_FAILURE(rc))
break;
continue;
if (RT_FAILURE(rc))
continue;
if (RT_SUCCESS(rc))
{
{
/* AC adapter */
if (RT_SUCCESS(rc))
{
if ( RT_SUCCESS(rc)
else
}
}
{
/* Battery */
if (RT_SUCCESS(rc))
{
if ( RT_SUCCESS(rc)
{
fBatteryPresent = true;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
fDischarging = true;
fCharging = true;
}
}
if (RT_SUCCESS(rc))
{
if ( RT_SUCCESS(rc)
fCritical = true;
}
if (RT_FAILURE(rc))
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
int32_t maxCapacity = 0;
if ( RT_SUCCESS(rc)
&& maxCapacity > 0)
}
}
if (RT_FAILURE(rc))
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
int32_t currentCapacity = 0;
if ( RT_SUCCESS(rc)
&& currentCapacity > 0)
}
}
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
int32_t presentRate = 0;
if ( RT_SUCCESS(rc)
&& presentRate > 0)
{
if (fDischarging)
else
}
}
}
}
}
}
}
}
}
else /* !/sys */
{
/*
*/
/*
* Read the status of the powerline-adapter.
*/
if (RT_SUCCESS(rc))
{
{
if (RT_FAILURE(rc))
break;
continue;
if (RT_FAILURE(rc))
if (RT_SUCCESS(rc))
{
{
if (RT_FAILURE(rc))
break;
{
else
break;
}
}
break;
}
}
}
/*
* Read the status of all batteries and collect it into one.
*/
if (RT_SUCCESS(rc))
{
bool fThisBatteryPresent = false;
bool fThisDischarging = false;
{
if (RT_FAILURE(rc))
break;
continue;
/* there is a 2nd variant of that file */
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
continue;
if (RT_FAILURE(rc))
{
continue;
}
/* get 'present' status from the info file */
{
if (RT_FAILURE(rc))
break;
{
{
fThisBatteryPresent = true;
break;
}
}
}
if (fThisBatteryPresent)
{
fBatteryPresent = true;
/* get the maximum capacity from the info file */
{
if (RT_FAILURE(rc))
break;
{
char *psz;
int32_t maxCapacity = 0;
if (RT_FAILURE(rc))
maxCapacity = 0;
break;
}
}
int32_t presentRate = 0;
bool fGotRemainingCapacity = false;
bool fGotBatteryState = false;
bool fGotCapacityState = false;
bool fGotPresentRate = false;
while ( ( !fGotRemainingCapacity
|| !fGotBatteryState
|| !fGotPresentRate)
{
if (RT_FAILURE(rc))
break;
{
char *psz;
int32_t currentCapacity = 0;
if ( RT_SUCCESS(rc)
&& currentCapacity > 0)
fGotRemainingCapacity = true;
}
{
{
fDischarging = true;
fThisDischarging = true;
}
fCharging = true;
fGotBatteryState = true;
}
{
fCritical = true;
fGotCapacityState = true;
}
{
char *psz;
if (RT_FAILURE(rc))
presentRate = 0;
fGotPresentRate = true;
}
}
if (fThisDischarging)
else
}
}
}
/* atomic update of the state */
/* charging/discharging bits are mutual exclusive */
if (fDischarging)
else if (fCharging)
if (fCritical)
if (maxCapacityTotal > 0 && currentCapacityTotal > 0)
{
if (presentRateTotal < 0)
/* calculate the percentage */
(PDMACPIBATCAPACITY)( ( (float)currentCapacityTotal
/ (float)maxCapacityTotal)
(uint32_t)(( (float)presentRateTotal
/ (float)maxCapacityTotal) * 1000);
}
else
{
/* unknown capacity / state */
pThis->u32BatteryPresentRate = ~0;
}
}
return VINF_SUCCESS;
}
{
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.
*/
{
LogFlow(("drvACPIDestruct\n"));
#ifdef RT_OS_LINUX
{
}
#endif
}
/**
* Construct an ACPI driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
{
int rc = VINF_SUCCESS;
/*
* Init the static parts.
*/
#ifdef RT_OS_LINUX
#endif
/* IBase */
/* IACPIConnector */
/*
* Validate the config.
*/
/*
* Check that no-one is attached to us.
*/
("Configuration error: Not possible to attach anything to this driver!\n"),
/*
* Query the ACPI port interface.
*/
{
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.
*/
if (RT_FAILURE(rc))
return rc;
if (RT_FAILURE(rc))
return rc;
#endif
return rc;
}
/**
* ACPI driver registration record.
*/
{
/* u32Version */
/* szName */
"ACPIHost",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"ACPI Host Driver",
/* fFlags */
/* fClass. */
/* cMaxInstances */
~0U,
/* cbInstance */
sizeof(DRVACPI),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
};