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 */
configureInitialState(const char * pathName,PowerState * powerState)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 */
freeState(PowerState * powerState)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 */
readPower(FakeDev * dev,int fd,void * buf,size_t count)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 */
writePower(FakeDev * dev,int fd,const void * buf,size_t count)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 */
ioctlPower(FakeDev * dev,int fd,int request,void * argp)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 */
closePower(FakeDev * dev,int fd)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 */
wsOpenDevPower(const char * pathName,int flags)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