blob: e98161a519189b714764885549cc59c26347b1cd [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* 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"
Jun Nakajima1321c762011-03-04 17:17:45 -080015#ifdef TARGET_I386
16#include "kvm.h"
17#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080018
19#define PDEV_BUS_OP_DONE (0x00)
20#define PDEV_BUS_OP_REMOVE_DEV (0x04)
21#define PDEV_BUS_OP_ADD_DEV (0x08)
22
23#define PDEV_BUS_OP_INIT (0x00)
24
25#define PDEV_BUS_OP (0x00)
26#define PDEV_BUS_GET_NAME (0x04)
27#define PDEV_BUS_NAME_LEN (0x08)
28#define PDEV_BUS_ID (0x0c)
29#define PDEV_BUS_IO_BASE (0x10)
30#define PDEV_BUS_IO_SIZE (0x14)
31#define PDEV_BUS_IRQ (0x18)
32#define PDEV_BUS_IRQ_COUNT (0x1c)
33
34struct bus_state {
35 struct goldfish_device dev;
36 struct goldfish_device *current;
37};
38
39qemu_irq *goldfish_pic;
40static struct goldfish_device *first_device;
41static struct goldfish_device *last_device;
42uint32_t goldfish_free_base;
43uint32_t goldfish_free_irq;
44
45void goldfish_device_set_irq(struct goldfish_device *dev, int irq, int level)
46{
47 if(irq >= dev->irq_count)
48 cpu_abort (cpu_single_env, "goldfish_device_set_irq: Bad irq %d >= %d\n", irq, dev->irq_count);
49 else
50 qemu_set_irq(goldfish_pic[dev->irq + irq], level);
51}
52
53int goldfish_add_device_no_io(struct goldfish_device *dev)
54{
55 if(dev->base == 0) {
56 dev->base = goldfish_free_base;
57 goldfish_free_base += dev->size;
58 }
59 if(dev->irq == 0 && dev->irq_count > 0) {
60 dev->irq = goldfish_free_irq;
61 goldfish_free_irq += dev->irq_count;
62 }
63 //printf("goldfish_add_device: %s, base %x %x, irq %d %d\n",
64 // dev->name, dev->base, dev->size, dev->irq, dev->irq_count);
65 dev->next = NULL;
66 if(last_device) {
67 last_device->next = dev;
68 }
69 else {
70 first_device = dev;
71 }
72 last_device = dev;
73 return 0;
74}
75
76int goldfish_device_add(struct goldfish_device *dev,
77 CPUReadMemoryFunc **mem_read,
78 CPUWriteMemoryFunc **mem_write,
79 void *opaque)
80{
81 int iomemtype;
82 goldfish_add_device_no_io(dev);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070083 iomemtype = cpu_register_io_memory(mem_read, mem_write, opaque);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080084 cpu_register_physical_memory(dev->base, dev->size, iomemtype);
85 return 0;
86}
87
88static uint32_t goldfish_bus_read(void *opaque, target_phys_addr_t offset)
89{
90 struct bus_state *s = (struct bus_state *)opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080091
92 switch (offset) {
93 case PDEV_BUS_OP:
94 if(s->current) {
95 s->current->reported_state = 1;
96 s->current = s->current->next;
97 }
98 else {
99 s->current = first_device;
100 }
101 while(s->current && s->current->reported_state == 1)
102 s->current = s->current->next;
103 if(s->current)
104 return PDEV_BUS_OP_ADD_DEV;
105 else {
106 goldfish_device_set_irq(&s->dev, 0, 0);
107 return PDEV_BUS_OP_DONE;
108 }
109
110 case PDEV_BUS_NAME_LEN:
111 return s->current ? strlen(s->current->name) : 0;
112 case PDEV_BUS_ID:
113 return s->current ? s->current->id : 0;
114 case PDEV_BUS_IO_BASE:
115 return s->current ? s->current->base : 0;
116 case PDEV_BUS_IO_SIZE:
117 return s->current ? s->current->size : 0;
118 case PDEV_BUS_IRQ:
119 return s->current ? s->current->irq : 0;
120 case PDEV_BUS_IRQ_COUNT:
121 return s->current ? s->current->irq_count : 0;
122 default:
123 cpu_abort (cpu_single_env, "goldfish_bus_read: Bad offset %x\n", offset);
124 return 0;
125 }
126}
127
128static void goldfish_bus_op_init(struct bus_state *s)
129{
130 struct goldfish_device *dev = first_device;
131 while(dev) {
132 dev->reported_state = 0;
133 dev = dev->next;
134 }
135 s->current = NULL;
136 goldfish_device_set_irq(&s->dev, 0, first_device != NULL);
137}
138
139static void goldfish_bus_write(void *opaque, target_phys_addr_t offset, uint32_t value)
140{
141 struct bus_state *s = (struct bus_state *)opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800142
143 switch(offset) {
144 case PDEV_BUS_OP:
145 switch(value) {
146 case PDEV_BUS_OP_INIT:
147 goldfish_bus_op_init(s);
148 break;
149 default:
150 cpu_abort (cpu_single_env, "goldfish_bus_write: Bad PDEV_BUS_OP value %x\n", value);
151 };
152 break;
153 case PDEV_BUS_GET_NAME:
Jun Nakajima1321c762011-03-04 17:17:45 -0800154 if(s->current) {
155#ifdef TARGET_I386
156 if(kvm_enabled())
157 cpu_synchronize_state(cpu_single_env, 0);
158#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700159 cpu_memory_rw_debug(cpu_single_env, value, (void*)s->current->name, strlen(s->current->name), 1);
Jun Nakajima1321c762011-03-04 17:17:45 -0800160 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800161 break;
162 default:
163 cpu_abort (cpu_single_env, "goldfish_bus_write: Bad offset %x\n", offset);
164 }
165}
166
167static CPUReadMemoryFunc *goldfish_bus_readfn[] = {
168 goldfish_bus_read,
169 goldfish_bus_read,
170 goldfish_bus_read
171};
172
173static CPUWriteMemoryFunc *goldfish_bus_writefn[] = {
174 goldfish_bus_write,
175 goldfish_bus_write,
176 goldfish_bus_write
177};
178
179
180static struct bus_state bus_state = {
181 .dev = {
182 .name = "goldfish_device_bus",
183 .id = -1,
184 .base = 0x10001000,
185 .size = 0x1000,
186 .irq = 1,
187 .irq_count = 1,
188 }
189};
190
191void goldfish_device_init(qemu_irq *pic, uint32_t base, uint32_t size, uint32_t irq, uint32_t irq_count)
192{
193 goldfish_pic = pic;
194 goldfish_free_base = base;
195 goldfish_free_irq = irq;
196}
197
198int goldfish_device_bus_init(uint32_t base, uint32_t irq)
199{
200 bus_state.dev.base = base;
201 bus_state.dev.irq = irq;
202
203 return goldfish_device_add(&bus_state.dev, goldfish_bus_readfn, goldfish_bus_writefn, &bus_state);
204}
205