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 "qemu_file.h" 13 #include "goldfish_device.h" 14 #include "power_supply.h" 15 16 17 enum { 18 /* status register */ 19 BATTERY_INT_STATUS = 0x00, 20 /* set this to enable IRQ */ 21 BATTERY_INT_ENABLE = 0x04, 22 23 BATTERY_AC_ONLINE = 0x08, 24 BATTERY_STATUS = 0x0C, 25 BATTERY_HEALTH = 0x10, 26 BATTERY_PRESENT = 0x14, 27 BATTERY_CAPACITY = 0x18, 28 29 BATTERY_STATUS_CHANGED = 1U << 0, 30 AC_STATUS_CHANGED = 1U << 1, 31 BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED, 32 }; 33 34 35 struct goldfish_battery_state { 36 struct goldfish_device dev; 37 // IRQs 38 uint32_t int_status; 39 // irq enable mask for int_status 40 uint32_t int_enable; 41 42 int ac_online; 43 int status; 44 int health; 45 int present; 46 int capacity; 47 }; 48 49 /* update this each time you update the battery_state struct */ 50 #define BATTERY_STATE_SAVE_VERSION 1 51 52 #define QFIELD_STRUCT struct goldfish_battery_state 53 QFIELD_BEGIN(goldfish_battery_fields) 54 QFIELD_INT32(int_status), 55 QFIELD_INT32(int_enable), 56 QFIELD_INT32(ac_online), 57 QFIELD_INT32(status), 58 QFIELD_INT32(health), 59 QFIELD_INT32(present), 60 QFIELD_INT32(capacity), 61 QFIELD_END 62 63 static void goldfish_battery_save(QEMUFile* f, void* opaque) 64 { 65 struct goldfish_battery_state* s = opaque; 66 67 qemu_put_struct(f, goldfish_battery_fields, s); 68 } 69 70 static int goldfish_battery_load(QEMUFile* f, void* opaque, int version_id) 71 { 72 struct goldfish_battery_state* s = opaque; 73 74 if (version_id != BATTERY_STATE_SAVE_VERSION) 75 return -1; 76 77 return qemu_get_struct(f, goldfish_battery_fields, s); 78 } 79 80 static struct goldfish_battery_state *battery_state; 81 82 static uint32_t goldfish_battery_read(void *opaque, target_phys_addr_t offset) 83 { 84 uint32_t ret; 85 struct goldfish_battery_state *s = opaque; 86 87 switch(offset) { 88 case BATTERY_INT_STATUS: 89 // return current buffer status flags 90 ret = s->int_status & s->int_enable; 91 if (ret) { 92 goldfish_device_set_irq(&s->dev, 0, 0); 93 s->int_status = 0; 94 } 95 return ret; 96 97 case BATTERY_INT_ENABLE: 98 return s->int_enable; 99 case BATTERY_AC_ONLINE: 100 return s->ac_online; 101 case BATTERY_STATUS: 102 return s->status; 103 case BATTERY_HEALTH: 104 return s->health; 105 case BATTERY_PRESENT: 106 return s->present; 107 case BATTERY_CAPACITY: 108 return s->capacity; 109 110 default: 111 cpu_abort (cpu_single_env, "goldfish_battery_read: Bad offset %x\n", offset); 112 return 0; 113 } 114 } 115 116 static void goldfish_battery_write(void *opaque, target_phys_addr_t offset, uint32_t val) 117 { 118 struct goldfish_battery_state *s = opaque; 119 120 switch(offset) { 121 case BATTERY_INT_ENABLE: 122 /* enable interrupts */ 123 s->int_enable = val; 124 // s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY); 125 // goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); 126 break; 127 128 default: 129 cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset); 130 } 131 } 132 133 static CPUReadMemoryFunc *goldfish_battery_readfn[] = { 134 goldfish_battery_read, 135 goldfish_battery_read, 136 goldfish_battery_read 137 }; 138 139 140 static CPUWriteMemoryFunc *goldfish_battery_writefn[] = { 141 goldfish_battery_write, 142 goldfish_battery_write, 143 goldfish_battery_write 144 }; 145 146 void goldfish_battery_init() 147 { 148 struct goldfish_battery_state *s; 149 150 s = (struct goldfish_battery_state *)qemu_mallocz(sizeof(*s)); 151 s->dev.name = "goldfish-battery"; 152 s->dev.base = 0; // will be allocated dynamically 153 s->dev.size = 0x1000; 154 s->dev.irq_count = 1; 155 156 // default values for the battery 157 s->ac_online = 1; 158 s->status = POWER_SUPPLY_STATUS_CHARGING; 159 s->health = POWER_SUPPLY_HEALTH_GOOD; 160 s->present = 1; // battery is present 161 s->capacity = 50; // 50% charged 162 163 battery_state = s; 164 165 goldfish_device_add(&s->dev, goldfish_battery_readfn, goldfish_battery_writefn, s); 166 167 register_savevm( "battery_state", 0, BATTERY_STATE_SAVE_VERSION, 168 goldfish_battery_save, goldfish_battery_load, s); 169 } 170 171 void goldfish_battery_set_prop(int ac, int property, int value) 172 { 173 int new_status = (ac ? AC_STATUS_CHANGED : BATTERY_STATUS_CHANGED); 174 175 if (ac) { 176 switch (property) { 177 case POWER_SUPPLY_PROP_ONLINE: 178 battery_state->ac_online = value; 179 break; 180 } 181 } else { 182 switch (property) { 183 case POWER_SUPPLY_PROP_STATUS: 184 battery_state->status = value; 185 break; 186 case POWER_SUPPLY_PROP_HEALTH: 187 battery_state->health = value; 188 break; 189 case POWER_SUPPLY_PROP_PRESENT: 190 battery_state->present = value; 191 break; 192 case POWER_SUPPLY_PROP_CAPACITY: 193 battery_state->capacity = value; 194 break; 195 } 196 } 197 198 if (new_status != battery_state->int_status) { 199 battery_state->int_status |= new_status; 200 goldfish_device_set_irq(&battery_state->dev, 0, (battery_state->int_status & battery_state->int_enable)); 201 } 202 } 203 204 void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data) 205 { 206 char buffer[100]; 207 const char* value; 208 209 sprintf(buffer, "AC: %s\r\n", (battery_state->ac_online ? "online" : "offline")); 210 callback(data, buffer); 211 212 switch (battery_state->status) { 213 case POWER_SUPPLY_STATUS_CHARGING: 214 value = "Charging"; 215 break; 216 case POWER_SUPPLY_STATUS_DISCHARGING: 217 value = "Discharging"; 218 break; 219 case POWER_SUPPLY_STATUS_NOT_CHARGING: 220 value = "Not charging"; 221 break; 222 case POWER_SUPPLY_STATUS_FULL: 223 value = "Full"; 224 break; 225 default: 226 value = "Unknown"; 227 break; 228 } 229 sprintf(buffer, "status: %s\r\n", value); 230 callback(data, buffer); 231 232 switch (battery_state->health) { 233 case POWER_SUPPLY_HEALTH_GOOD: 234 value = "Good"; 235 break; 236 case POWER_SUPPLY_HEALTH_OVERHEAT: 237 value = "Overhead"; 238 break; 239 case POWER_SUPPLY_HEALTH_DEAD: 240 value = "Dead"; 241 break; 242 case POWER_SUPPLY_HEALTH_OVERVOLTAGE: 243 value = "Overvoltage"; 244 break; 245 case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: 246 value = "Unspecified failure"; 247 break; 248 default: 249 value = "Unknown"; 250 break; 251 } 252 sprintf(buffer, "health: %s\r\n", value); 253 callback(data, buffer); 254 255 sprintf(buffer, "present: %s\r\n", (battery_state->present ? "true" : "false")); 256 callback(data, buffer); 257 258 sprintf(buffer, "capacity: %d\r\n", battery_state->capacity); 259 callback(data, buffer); 260 } 261