1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12 #include "cpu.h"
13 #include "migration/qemu-file.h"
14 #include "hw/android/goldfish/device.h"
15 #include "hw/hw.h"
16 #include "hw/power_supply.h"
17
18
19 enum {
20 /* status register */
21 BATTERY_INT_STATUS = 0x00,
22 /* set this to enable IRQ */
23 BATTERY_INT_ENABLE = 0x04,
24
25 BATTERY_AC_ONLINE = 0x08,
26 BATTERY_STATUS = 0x0C,
27 BATTERY_HEALTH = 0x10,
28 BATTERY_PRESENT = 0x14,
29 BATTERY_CAPACITY = 0x18,
30
31 BATTERY_STATUS_CHANGED = 1U << 0,
32 AC_STATUS_CHANGED = 1U << 1,
33 BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
34 };
35
36
37 struct goldfish_battery_state {
38 struct goldfish_device dev;
39 // IRQs
40 uint32_t int_status;
41 // irq enable mask for int_status
42 uint32_t int_enable;
43
44 int ac_online;
45 int status;
46 int health;
47 int present;
48 int capacity;
49
50 // the fields below are part of the device configuration
51 // and don't need to be saved to / restored from snapshots.
52 int hw_has_battery;
53 };
54
55 /* update this each time you update the battery_state struct */
56 #define BATTERY_STATE_SAVE_VERSION 1
57
58 #define QFIELD_STRUCT struct goldfish_battery_state
59 QFIELD_BEGIN(goldfish_battery_fields)
QFIELD_INT32(int_status)60 QFIELD_INT32(int_status),
61 QFIELD_INT32(int_enable),
62 QFIELD_INT32(ac_online),
63 QFIELD_INT32(status),
64 QFIELD_INT32(health),
65 QFIELD_INT32(present),
66 QFIELD_INT32(capacity),
67 QFIELD_END
68
69 static void goldfish_battery_save(QEMUFile* f, void* opaque)
70 {
71 struct goldfish_battery_state* s = opaque;
72
73 qemu_put_struct(f, goldfish_battery_fields, s);
74 }
75
goldfish_battery_load(QEMUFile * f,void * opaque,int version_id)76 static int goldfish_battery_load(QEMUFile* f, void* opaque, int version_id)
77 {
78 struct goldfish_battery_state* s = opaque;
79
80 if (version_id != BATTERY_STATE_SAVE_VERSION)
81 return -1;
82
83 return qemu_get_struct(f, goldfish_battery_fields, s);
84 }
85
86 static struct goldfish_battery_state *battery_state;
87
goldfish_battery_read(void * opaque,hwaddr offset)88 static uint32_t goldfish_battery_read(void *opaque, hwaddr offset)
89 {
90 uint32_t ret;
91 struct goldfish_battery_state *s = opaque;
92
93 switch(offset) {
94 case BATTERY_INT_STATUS:
95 // return current buffer status flags
96 ret = s->int_status & s->int_enable;
97 if (ret) {
98 goldfish_device_set_irq(&s->dev, 0, 0);
99 s->int_status = 0;
100 }
101 return ret;
102
103 case BATTERY_INT_ENABLE:
104 return s->int_enable;
105 case BATTERY_AC_ONLINE:
106 return s->ac_online;
107 case BATTERY_STATUS:
108 return s->status;
109 case BATTERY_HEALTH:
110 return s->health;
111 case BATTERY_PRESENT:
112 return s->present;
113 case BATTERY_CAPACITY:
114 return s->capacity;
115
116 default:
117 cpu_abort (cpu_single_env, "goldfish_battery_read: Bad offset %x\n", offset);
118 return 0;
119 }
120 }
121
goldfish_battery_write(void * opaque,hwaddr offset,uint32_t val)122 static void goldfish_battery_write(void *opaque, hwaddr offset, uint32_t val)
123 {
124 struct goldfish_battery_state *s = opaque;
125
126 switch(offset) {
127 case BATTERY_INT_ENABLE:
128 /* enable interrupts */
129 s->int_enable = val;
130 // s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY);
131 // goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
132 break;
133
134 default:
135 cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset);
136 }
137 }
138
139 static CPUReadMemoryFunc *goldfish_battery_readfn[] = {
140 goldfish_battery_read,
141 goldfish_battery_read,
142 goldfish_battery_read
143 };
144
145
146 static CPUWriteMemoryFunc *goldfish_battery_writefn[] = {
147 goldfish_battery_write,
148 goldfish_battery_write,
149 goldfish_battery_write
150 };
151
goldfish_battery_init(int has_battery)152 void goldfish_battery_init(int has_battery)
153 {
154 struct goldfish_battery_state *s;
155
156 s = (struct goldfish_battery_state *)g_malloc0(sizeof(*s));
157 s->dev.name = "goldfish-battery";
158 s->dev.base = 0; // will be allocated dynamically
159 s->dev.size = 0x1000;
160 s->dev.irq_count = 1;
161
162 // default values for the battery
163 s->ac_online = 1;
164 s->hw_has_battery = has_battery;
165 if (has_battery) {
166 s->status = POWER_SUPPLY_STATUS_CHARGING;
167 s->health = POWER_SUPPLY_HEALTH_GOOD;
168 s->present = 1; // battery is present
169 s->capacity = 50; // 50% charged
170 } else {
171 s->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
172 s->health = POWER_SUPPLY_HEALTH_DEAD;
173 s->present = 0;
174 s->capacity = 0;
175 }
176
177 battery_state = s;
178
179 goldfish_device_add(&s->dev, goldfish_battery_readfn, goldfish_battery_writefn, s);
180
181 register_savevm(NULL,
182 "battery_state",
183 0,
184 BATTERY_STATE_SAVE_VERSION,
185 goldfish_battery_save,
186 goldfish_battery_load,
187 s);
188 }
189
goldfish_battery_set_prop(int ac,int property,int value)190 void goldfish_battery_set_prop(int ac, int property, int value)
191 {
192 int new_status = (ac ? AC_STATUS_CHANGED : BATTERY_STATUS_CHANGED);
193
194 if (!battery_state || !battery_state->hw_has_battery)
195 return;
196
197 if (ac) {
198 switch (property) {
199 case POWER_SUPPLY_PROP_ONLINE:
200 battery_state->ac_online = value;
201 break;
202 }
203 } else {
204 switch (property) {
205 case POWER_SUPPLY_PROP_STATUS:
206 battery_state->status = value;
207 break;
208 case POWER_SUPPLY_PROP_HEALTH:
209 battery_state->health = value;
210 break;
211 case POWER_SUPPLY_PROP_PRESENT:
212 battery_state->present = value;
213 break;
214 case POWER_SUPPLY_PROP_CAPACITY:
215 battery_state->capacity = value;
216 break;
217 }
218 }
219
220 if (new_status != battery_state->int_status) {
221 battery_state->int_status |= new_status;
222 goldfish_device_set_irq(&battery_state->dev, 0, (battery_state->int_status & battery_state->int_enable));
223 }
224 }
225
goldfish_battery_display(void (* callback)(void * data,const char * string),void * data)226 void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data)
227 {
228 char buffer[100];
229 const char* value;
230
231 // Note: obviously, if there is no battery, the AC must always be on.
232 snprintf(buffer, sizeof buffer, "AC: %s\r\n",
233 (battery_state->ac_online) ? "online" : "offline");
234 callback(data, buffer);
235
236 switch (battery_state->status) {
237 case POWER_SUPPLY_STATUS_CHARGING:
238 value = "Charging";
239 break;
240 case POWER_SUPPLY_STATUS_DISCHARGING:
241 value = "Discharging";
242 break;
243 case POWER_SUPPLY_STATUS_NOT_CHARGING:
244 value = "Not charging";
245 break;
246 case POWER_SUPPLY_STATUS_FULL:
247 value = "Full";
248 break;
249 default:
250 value = "Unknown";
251 }
252 snprintf(buffer, sizeof buffer, "status: %s\r\n", value);
253 callback(data, buffer);
254
255 switch (battery_state->health) {
256 case POWER_SUPPLY_HEALTH_GOOD:
257 value = "Good";
258 break;
259 case POWER_SUPPLY_HEALTH_OVERHEAT:
260 value = "Overhead";
261 break;
262 case POWER_SUPPLY_HEALTH_DEAD:
263 value = "Dead";
264 break;
265 case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
266 value = "Overvoltage";
267 break;
268 case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
269 value = "Unspecified failure";
270 break;
271 default:
272 value = "Unknown";
273 }
274 snprintf(buffer, sizeof buffer, "health: %s\r\n", value);
275 callback(data, buffer);
276
277 snprintf(buffer, sizeof buffer, "present: %s\r\n",
278 (battery_state->present) ? "true" : "false");
279 callback(data, buffer);
280
281 snprintf(buffer, sizeof buffer, "capacity: %d\r\n", battery_state->capacity);
282 callback(data, buffer);
283 }
284