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 "arm_pic.h" 14 #include "goldfish_device.h" 15 #include "android/utils/debug.h" 16 #ifdef TARGET_I386 17 #include "kvm.h" 18 #endif 19 20 #define PDEV_BUS_OP_DONE (0x00) 21 #define PDEV_BUS_OP_REMOVE_DEV (0x04) 22 #define PDEV_BUS_OP_ADD_DEV (0x08) 23 24 #define PDEV_BUS_OP_INIT (0x00) 25 26 #define PDEV_BUS_OP (0x00) 27 #define PDEV_BUS_GET_NAME (0x04) 28 #define PDEV_BUS_NAME_LEN (0x08) 29 #define PDEV_BUS_ID (0x0c) 30 #define PDEV_BUS_IO_BASE (0x10) 31 #define PDEV_BUS_IO_SIZE (0x14) 32 #define PDEV_BUS_IRQ (0x18) 33 #define PDEV_BUS_IRQ_COUNT (0x1c) 34 35 struct bus_state { 36 struct goldfish_device dev; 37 struct goldfish_device *current; 38 }; 39 40 qemu_irq *goldfish_pic; 41 static struct goldfish_device *first_device; 42 static struct goldfish_device *last_device; 43 uint32_t goldfish_free_base; 44 uint32_t goldfish_free_irq; 45 46 void goldfish_device_set_irq(struct goldfish_device *dev, int irq, int level) 47 { 48 if(irq >= dev->irq_count) 49 cpu_abort (cpu_single_env, "goldfish_device_set_irq: Bad irq %d >= %d\n", irq, dev->irq_count); 50 else 51 qemu_set_irq(goldfish_pic[dev->irq + irq], level); 52 } 53 54 int goldfish_add_device_no_io(struct goldfish_device *dev) 55 { 56 if(dev->base == 0) { 57 dev->base = goldfish_free_base; 58 goldfish_free_base += dev->size; 59 } 60 if(dev->irq == 0 && dev->irq_count > 0) { 61 dev->irq = goldfish_free_irq; 62 goldfish_free_irq += dev->irq_count; 63 #ifdef TARGET_I386 64 /* Make sure that we pass by the reserved IRQs. */ 65 while (goldfish_free_irq == GFD_KBD_IRQ || 66 goldfish_free_irq == GFD_MOUSE_IRQ || 67 goldfish_free_irq == GFD_ERR_IRQ) { 68 goldfish_free_irq++; 69 } 70 #endif 71 if (goldfish_free_irq >= GFD_MAX_IRQ) { 72 derror("Goldfish device has exceeded available IRQ number."); 73 exit(1); 74 } 75 } 76 //printf("goldfish_add_device: %s, base %x %x, irq %d %d\n", 77 // dev->name, dev->base, dev->size, dev->irq, dev->irq_count); 78 dev->next = NULL; 79 if(last_device) { 80 last_device->next = dev; 81 } 82 else { 83 first_device = dev; 84 } 85 last_device = dev; 86 return 0; 87 } 88 89 int goldfish_device_add(struct goldfish_device *dev, 90 CPUReadMemoryFunc **mem_read, 91 CPUWriteMemoryFunc **mem_write, 92 void *opaque) 93 { 94 int iomemtype; 95 goldfish_add_device_no_io(dev); 96 iomemtype = cpu_register_io_memory(mem_read, mem_write, opaque); 97 cpu_register_physical_memory(dev->base, dev->size, iomemtype); 98 return 0; 99 } 100 101 static uint32_t goldfish_bus_read(void *opaque, target_phys_addr_t offset) 102 { 103 struct bus_state *s = (struct bus_state *)opaque; 104 105 switch (offset) { 106 case PDEV_BUS_OP: 107 if(s->current) { 108 s->current->reported_state = 1; 109 s->current = s->current->next; 110 } 111 else { 112 s->current = first_device; 113 } 114 while(s->current && s->current->reported_state == 1) 115 s->current = s->current->next; 116 if(s->current) 117 return PDEV_BUS_OP_ADD_DEV; 118 else { 119 goldfish_device_set_irq(&s->dev, 0, 0); 120 return PDEV_BUS_OP_DONE; 121 } 122 123 case PDEV_BUS_NAME_LEN: 124 return s->current ? strlen(s->current->name) : 0; 125 case PDEV_BUS_ID: 126 return s->current ? s->current->id : 0; 127 case PDEV_BUS_IO_BASE: 128 return s->current ? s->current->base : 0; 129 case PDEV_BUS_IO_SIZE: 130 return s->current ? s->current->size : 0; 131 case PDEV_BUS_IRQ: 132 return s->current ? s->current->irq : 0; 133 case PDEV_BUS_IRQ_COUNT: 134 return s->current ? s->current->irq_count : 0; 135 default: 136 cpu_abort (cpu_single_env, "goldfish_bus_read: Bad offset %x\n", offset); 137 return 0; 138 } 139 } 140 141 static void goldfish_bus_op_init(struct bus_state *s) 142 { 143 struct goldfish_device *dev = first_device; 144 while(dev) { 145 dev->reported_state = 0; 146 dev = dev->next; 147 } 148 s->current = NULL; 149 goldfish_device_set_irq(&s->dev, 0, first_device != NULL); 150 } 151 152 static void goldfish_bus_write(void *opaque, target_phys_addr_t offset, uint32_t value) 153 { 154 struct bus_state *s = (struct bus_state *)opaque; 155 156 switch(offset) { 157 case PDEV_BUS_OP: 158 switch(value) { 159 case PDEV_BUS_OP_INIT: 160 goldfish_bus_op_init(s); 161 break; 162 default: 163 cpu_abort (cpu_single_env, "goldfish_bus_write: Bad PDEV_BUS_OP value %x\n", value); 164 }; 165 break; 166 case PDEV_BUS_GET_NAME: 167 if(s->current) { 168 #ifdef TARGET_I386 169 if(kvm_enabled()) 170 cpu_synchronize_state(cpu_single_env, 0); 171 #endif 172 cpu_memory_rw_debug(cpu_single_env, value, (void*)s->current->name, strlen(s->current->name), 1); 173 } 174 break; 175 default: 176 cpu_abort (cpu_single_env, "goldfish_bus_write: Bad offset %x\n", offset); 177 } 178 } 179 180 static CPUReadMemoryFunc *goldfish_bus_readfn[] = { 181 goldfish_bus_read, 182 goldfish_bus_read, 183 goldfish_bus_read 184 }; 185 186 static CPUWriteMemoryFunc *goldfish_bus_writefn[] = { 187 goldfish_bus_write, 188 goldfish_bus_write, 189 goldfish_bus_write 190 }; 191 192 193 static struct bus_state bus_state = { 194 .dev = { 195 .name = "goldfish_device_bus", 196 .id = -1, 197 .base = 0x10001000, 198 .size = 0x1000, 199 .irq = 1, 200 .irq_count = 1, 201 } 202 }; 203 204 void goldfish_device_init(qemu_irq *pic, uint32_t base, uint32_t size, uint32_t irq, uint32_t irq_count) 205 { 206 goldfish_pic = pic; 207 goldfish_free_base = base; 208 goldfish_free_irq = irq; 209 } 210 211 int goldfish_device_bus_init(uint32_t base, uint32_t irq) 212 { 213 bus_state.dev.base = base; 214 bus_state.dev.irq = irq; 215 216 return goldfish_device_add(&bus_state.dev, goldfish_bus_readfn, goldfish_bus_writefn, &bus_state); 217 } 218 219