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) 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 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 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 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 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 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 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