Home | History | Annotate | Download | only in wrapsim
      1 /*
      2  * Copyright 2007 The Android Open Source Project
      3  *
      4  * Magic entries in /sys/class/power_supply/.
      5  */
      6 #include "Common.h"
      7 
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <ctype.h>
     11 
     12 #include <fcntl.h>
     13 #include <sys/ioctl.h>
     14 
     15 /*
     16  * Map filename to device index.
     17  *
     18  * [ not using DeviceIndex -- would be useful if we need to return something
     19  * other than a static string ]
     20  */
     21 static const struct {
     22     const char*     name;
     23     //DeviceIndex     idx;
     24     const char*     data;
     25 } gDeviceMap[] = {
     26     { "ac/online",
     27         "0\n" },
     28 
     29     { "battery/batt_temp",
     30         "281\n", },
     31     { "battery/batt_vol",
     32         "4170\n" },
     33     { "battery/capacity",
     34         "100\n" },
     35     { "battery/health",
     36         "Good\n" },
     37     { "battery/present",
     38         "0\n" },
     39     { "battery/status",
     40         "Full" },
     41     { "battery/technology",
     42         "Li-ion\n" },
     43 
     44     { "usb/online",
     45         "1\n" },
     46 };
     47 
     48 /*
     49  * Power driver state.
     50  *
     51  * Right now we just ignore everything written.
     52  */
     53 typedef struct PowerState {
     54     int         which;
     55 } PowerState;
     56 
     57 
     58 /*
     59  * Figure out who we are, based on "pathName".
     60  */
     61 static void configureInitialState(const char* pathName, PowerState* powerState)
     62 {
     63     const char* cp = pathName + strlen("/sys/class/power_supply/");
     64     int i;
     65 
     66     powerState->which = -1;
     67     for (i = 0; i < (int) (sizeof(gDeviceMap) / sizeof(gDeviceMap[0])); i++) {
     68         if (strcmp(cp, gDeviceMap[i].name) == 0) {
     69             powerState->which = i;
     70             break;
     71         }
     72     }
     73 
     74     if (powerState->which == -1) {
     75         wsLog("Warning: access to unknown power device '%s'\n", pathName);
     76         return;
     77     }
     78 }
     79 
     80 /*
     81  * Free up the state structure.
     82  */
     83 static void freeState(PowerState* powerState)
     84 {
     85     free(powerState);
     86 }
     87 
     88 /*
     89  * Read data from the device.
     90  *
     91  * We don't try to keep track of how much was read -- existing clients just
     92  * try to read into a large buffer.
     93  */
     94 static ssize_t readPower(FakeDev* dev, int fd, void* buf, size_t count)
     95 {
     96     PowerState* state = (PowerState*) dev->state;
     97     int dataLen;
     98 
     99     wsLog("%s: read %d\n", dev->debugName, count);
    100 
    101     if (state->which < 0 ||
    102         state->which >= (int) (sizeof(gDeviceMap)/sizeof(gDeviceMap[0])))
    103     {
    104         return 0;
    105     }
    106 
    107     const char* data = gDeviceMap[state->which].data;
    108     size_t strLen = strlen(data);
    109 
    110     while(strLen == 0)
    111         sleep(10); // block forever
    112 
    113     ssize_t copyCount = (strLen < count) ? strLen : count;
    114     memcpy(buf, data, copyCount);
    115     return copyCount;
    116 }
    117 
    118 /*
    119  * Ignore the request.
    120  */
    121 static ssize_t writePower(FakeDev* dev, int fd, const void* buf, size_t count)
    122 {
    123     wsLog("%s: write %d bytes\n", dev->debugName, count);
    124     return count;
    125 }
    126 
    127 /*
    128  * Our Java classes want to be able to do ioctl(FIONREAD) on files.  The
    129  * battery power manager is blowing up if we get an error other than
    130  * ENOTTY (meaning a device that doesn't understand buffering).
    131  */
    132 static int ioctlPower(FakeDev* dev, int fd, int request, void* argp)
    133 {
    134     if (request == FIONREAD) {
    135         wsLog("%s: ioctl(FIONREAD, %p)\n", dev->debugName, argp);
    136         errno = ENOTTY;
    137         return -1;
    138     } else {
    139         wsLog("%s: ioctl(0x%08x, %p) ??\n", dev->debugName, request, argp);
    140         errno = EINVAL;
    141         return -1;
    142     }
    143 }
    144 
    145 /*
    146  * Free up our state before closing down the fake descriptor.
    147  */
    148 static int closePower(FakeDev* dev, int fd)
    149 {
    150     freeState((PowerState*)dev->state);
    151     dev->state = NULL;
    152     return 0;
    153 }
    154 
    155 /*
    156  * Open a power device.
    157  */
    158 FakeDev* wsOpenDevPower(const char* pathName, int flags)
    159 {
    160     FakeDev* newDev = wsCreateFakeDev(pathName);
    161     if (newDev != NULL) {
    162         newDev->read = readPower;
    163         newDev->write = writePower;
    164         newDev->ioctl = ioctlPower;
    165         newDev->close = closePower;
    166 
    167         PowerState* powerState = calloc(1, sizeof(PowerState));
    168 
    169         configureInitialState(pathName, powerState);
    170         newDev->state = powerState;
    171     }
    172 
    173     return newDev;
    174 }
    175 
    176