/*
* Copyright 2007 The Android Open Source Project
*
* Magic entries in /sys/class/power_supply/.
*/
#include "Common.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/ioctl.h>
/*
* Map filename to device index.
*
* [ not using DeviceIndex -- would be useful if we need to return something
* other than a static string ]
*/
static const struct {
const char* name;
//DeviceIndex idx;
const char* data;
} gDeviceMap[] = {
{ "ac/online",
"0\n" },
{ "battery/batt_temp",
"281\n", },
{ "battery/batt_vol",
"4170\n" },
{ "battery/capacity",
"100\n" },
{ "battery/health",
"Good\n" },
{ "battery/present",
"0\n" },
{ "battery/status",
"Full" },
{ "battery/technology",
"Li-ion\n" },
{ "usb/online",
"1\n" },
};
/*
* Power driver state.
*
* Right now we just ignore everything written.
*/
typedef struct PowerState {
int which;
} PowerState;
/*
* Figure out who we are, based on "pathName".
*/
static void configureInitialState(const char* pathName, PowerState* powerState)
{
const char* cp = pathName + strlen("/sys/class/power_supply/");
int i;
powerState->which = -1;
for (i = 0; i < (int) (sizeof(gDeviceMap) / sizeof(gDeviceMap[0])); i++) {
if (strcmp(cp, gDeviceMap[i].name) == 0) {
powerState->which = i;
break;
}
}
if (powerState->which == -1) {
wsLog("Warning: access to unknown power device '%s'\n", pathName);
return;
}
}
/*
* Free up the state structure.
*/
static void freeState(PowerState* powerState)
{
free(powerState);
}
/*
* Read data from the device.
*
* We don't try to keep track of how much was read -- existing clients just
* try to read into a large buffer.
*/
static ssize_t readPower(FakeDev* dev, int fd, void* buf, size_t count)
{
PowerState* state = (PowerState*) dev->state;
int dataLen;
wsLog("%s: read %d\n", dev->debugName, count);
if (state->which < 0 ||
state->which >= (int) (sizeof(gDeviceMap)/sizeof(gDeviceMap[0])))
{
return 0;
}
const char* data = gDeviceMap[state->which].data;
size_t strLen = strlen(data);
while(strLen == 0)
sleep(10); // block forever
ssize_t copyCount = (strLen < count) ? strLen : count;
memcpy(buf, data, copyCount);
return copyCount;
}
/*
* Ignore the request.
*/
static ssize_t writePower(FakeDev* dev, int fd, const void* buf, size_t count)
{
wsLog("%s: write %d bytes\n", dev->debugName, count);
return count;
}
/*
* Our Java classes want to be able to do ioctl(FIONREAD) on files. The
* battery power manager is blowing up if we get an error other than
* ENOTTY (meaning a device that doesn't understand buffering).
*/
static int ioctlPower(FakeDev* dev, int fd, int request, void* argp)
{
if (request == FIONREAD) {
wsLog("%s: ioctl(FIONREAD, %p)\n", dev->debugName, argp);
errno = ENOTTY;
return -1;
} else {
wsLog("%s: ioctl(0x%08x, %p) ??\n", dev->debugName, request, argp);
errno = EINVAL;
return -1;
}
}
/*
* Free up our state before closing down the fake descriptor.
*/
static int closePower(FakeDev* dev, int fd)
{
freeState((PowerState*)dev->state);
dev->state = NULL;
return 0;
}
/*
* Open a power device.
*/
FakeDev* wsOpenDevPower(const char* pathName, int flags)
{
FakeDev* newDev = wsCreateFakeDev(pathName);
if (newDev != NULL) {
newDev->read = readPower;
newDev->write = writePower;
newDev->ioctl = ioctlPower;
newDev->close = closePower;
PowerState* powerState = calloc(1, sizeof(PowerState));
configureInitialState(pathName, powerState);
newDev->state = powerState;
}
return newDev;
}