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