• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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