Home | History | Annotate | Download | only in goldfish
      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