|  | /* | 
|  | * 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; | 
|  | } | 
|  |  |