• 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 "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)
QFIELD_INT32(int_status)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 
goldfish_battery_load(QEMUFile * f,void * opaque,int version_id)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 
goldfish_battery_read(void * opaque,target_phys_addr_t offset)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 
goldfish_battery_write(void * opaque,target_phys_addr_t offset,uint32_t val)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 
goldfish_battery_init()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 
goldfish_battery_set_prop(int ac,int property,int value)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 
goldfish_battery_display(void (* callback)(void * data,const char * string),void * data)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