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