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 "goldfish_vmem.h" 15 16 enum { 17 SW_NAME_LEN = 0x00, 18 SW_NAME_PTR = 0x04, 19 SW_FLAGS = 0x08, 20 SW_STATE = 0x0c, 21 SW_INT_STATUS = 0x10, 22 SW_INT_ENABLE = 0x14, 23 24 SW_FLAGS_OUTPUT = 1U << 0 25 }; 26 27 28 struct switch_state { 29 struct goldfish_device dev; 30 char *name; 31 uint32_t state; 32 uint32_t state_changed : 1; 33 uint32_t int_enable : 1; 34 uint32_t (*writefn)(void *opaque, uint32_t state); 35 void *writeopaque; 36 }; 37 38 #define GOLDFISH_SWITCH_SAVE_VERSION 1 39 40 static void goldfish_switch_save(QEMUFile* f, void* opaque) 41 { 42 struct switch_state* s = opaque; 43 44 qemu_put_be32(f, s->state); 45 qemu_put_byte(f, s->state_changed); 46 qemu_put_byte(f, s->int_enable); 47 } 48 49 static int goldfish_switch_load(QEMUFile* f, void* opaque, int version_id) 50 { 51 struct switch_state* s = opaque; 52 53 if (version_id != GOLDFISH_SWITCH_SAVE_VERSION) 54 return -1; 55 56 s->state = qemu_get_be32(f); 57 s->state_changed = qemu_get_byte(f); 58 s->int_enable = qemu_get_byte(f); 59 60 return 0; 61 } 62 63 static uint32_t goldfish_switch_read(void *opaque, target_phys_addr_t offset) 64 { 65 struct switch_state *s = (struct switch_state *)opaque; 66 67 //printf("goldfish_switch_read %x %x\n", offset, size); 68 69 switch (offset) { 70 case SW_NAME_LEN: 71 return strlen(s->name); 72 case SW_FLAGS: 73 return s->writefn ? SW_FLAGS_OUTPUT : 0; 74 case SW_STATE: 75 return s->state; 76 case SW_INT_STATUS: 77 if(s->state_changed && s->int_enable) { 78 s->state_changed = 0; 79 goldfish_device_set_irq(&s->dev, 0, 0); 80 return 1; 81 } 82 return 0; 83 default: 84 cpu_abort (cpu_single_env, "goldfish_switch_read: Bad offset %x\n", offset); 85 return 0; 86 } 87 } 88 89 static void goldfish_switch_write(void *opaque, target_phys_addr_t offset, uint32_t value) 90 { 91 struct switch_state *s = (struct switch_state *)opaque; 92 93 //printf("goldfish_switch_read %x %x %x\n", offset, value, size); 94 95 switch(offset) { 96 case SW_NAME_PTR: 97 safe_memory_rw_debug(cpu_single_env, value, (void*)s->name, strlen(s->name), 1); 98 break; 99 100 case SW_STATE: 101 if(s->writefn) { 102 uint32_t new_state; 103 new_state = s->writefn(s->writeopaque, value); 104 if(new_state != s->state) { 105 goldfish_switch_set_state(s, new_state); 106 } 107 } 108 else 109 cpu_abort (cpu_single_env, "goldfish_switch_write: write to SW_STATE on input\n"); 110 break; 111 112 case SW_INT_ENABLE: 113 value &= 1; 114 if(s->state_changed && s->int_enable != value) 115 goldfish_device_set_irq(&s->dev, 0, value); 116 s->int_enable = value; 117 break; 118 119 default: 120 cpu_abort (cpu_single_env, "goldfish_switch_write: Bad offset %x\n", offset); 121 } 122 } 123 124 static CPUReadMemoryFunc *goldfish_switch_readfn[] = { 125 goldfish_switch_read, 126 goldfish_switch_read, 127 goldfish_switch_read 128 }; 129 130 static CPUWriteMemoryFunc *goldfish_switch_writefn[] = { 131 goldfish_switch_write, 132 goldfish_switch_write, 133 goldfish_switch_write 134 }; 135 136 void goldfish_switch_set_state(void *opaque, uint32_t state) 137 { 138 struct switch_state *s = opaque; 139 s->state_changed = 1; 140 s->state = state; 141 if(s->int_enable) 142 goldfish_device_set_irq(&s->dev, 0, 1); 143 } 144 145 void *goldfish_switch_add(char *name, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id) 146 { 147 int ret; 148 struct switch_state *s; 149 150 s = qemu_mallocz(sizeof(*s)); 151 s->dev.name = "goldfish-switch"; 152 s->dev.id = id; 153 s->dev.size = 0x1000; 154 s->dev.irq_count = 1; 155 s->name = name; 156 s->writefn = writefn; 157 s->writeopaque = writeopaque; 158 159 160 ret = goldfish_device_add(&s->dev, goldfish_switch_readfn, goldfish_switch_writefn, s); 161 if(ret) { 162 qemu_free(s); 163 return NULL; 164 } 165 166 register_savevm( "goldfish_switch", 0, GOLDFISH_SWITCH_SAVE_VERSION, 167 goldfish_switch_save, goldfish_switch_load, s); 168 169 return s; 170 } 171 172