Revision 4af39611
b/Makefile.target | ||
---|---|---|
655 | 655 |
OBJS+= mst_fpga.o mainstone.o |
656 | 656 |
OBJS+= musicpal.o pflash_cfi02.o |
657 | 657 |
OBJS+= framebuffer.o |
658 |
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o |
|
659 |
OBJS+= syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o |
|
658 | 660 |
CPPFLAGS += -DHAS_AUDIO |
659 | 661 |
endif |
660 | 662 |
ifeq ($(TARGET_BASE_ARCH), sh4) |
b/hw/boards.h | ||
---|---|---|
128 | 128 |
/* tosa.c */ |
129 | 129 |
extern QEMUMachine tosapda_machine; |
130 | 130 |
|
131 |
/* syborg.c */ |
|
132 |
extern QEMUMachine syborg_machine; |
|
133 |
|
|
131 | 134 |
#endif |
b/hw/syborg.c | ||
---|---|---|
1 |
/* |
|
2 |
* Syborg (Symbian Virtual Platform) reference board |
|
3 |
* |
|
4 |
* Copyright (c) 2009 CodeSourcery |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
#include "sysbus.h" |
|
26 |
#include "boards.h" |
|
27 |
#include "arm-misc.h" |
|
28 |
#include "sysemu.h" |
|
29 |
|
|
30 |
static struct arm_boot_info syborg_binfo; |
|
31 |
|
|
32 |
static void syborg_init(ram_addr_t ram_size, |
|
33 |
const char *boot_device, |
|
34 |
const char *kernel_filename, const char *kernel_cmdline, |
|
35 |
const char *initrd_filename, const char *cpu_model) |
|
36 |
{ |
|
37 |
CPUState *env; |
|
38 |
qemu_irq *cpu_pic; |
|
39 |
qemu_irq pic[64]; |
|
40 |
ram_addr_t ram_addr; |
|
41 |
DeviceState *dev; |
|
42 |
int i; |
|
43 |
|
|
44 |
if (!cpu_model) |
|
45 |
cpu_model = "cortex-a8"; |
|
46 |
env = cpu_init(cpu_model); |
|
47 |
if (!env) { |
|
48 |
fprintf(stderr, "Unable to find CPU definition\n"); |
|
49 |
exit(1); |
|
50 |
} |
|
51 |
|
|
52 |
/* RAM at address zero. */ |
|
53 |
ram_addr = qemu_ram_alloc(ram_size); |
|
54 |
cpu_register_physical_memory(0, ram_size, ram_addr | IO_MEM_RAM); |
|
55 |
|
|
56 |
cpu_pic = arm_pic_init_cpu(env); |
|
57 |
dev = sysbus_create_simple("syborg,interrupt", 0xC0000000, |
|
58 |
cpu_pic[ARM_PIC_CPU_IRQ]); |
|
59 |
for (i = 0; i < 64; i++) { |
|
60 |
pic[i] = qdev_get_irq_sink(dev, i); |
|
61 |
} |
|
62 |
|
|
63 |
sysbus_create_simple("syborg,rtc", 0xC0001000, NULL); |
|
64 |
|
|
65 |
dev = qdev_create(NULL, "syborg,timer"); |
|
66 |
qdev_set_prop_int(dev, "frequency", 1000000); |
|
67 |
qdev_init(dev); |
|
68 |
sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xC0002000); |
|
69 |
sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[1]); |
|
70 |
|
|
71 |
sysbus_create_simple("syborg,keyboard", 0xC0003000, pic[2]); |
|
72 |
sysbus_create_simple("syborg,pointer", 0xC0004000, pic[3]); |
|
73 |
sysbus_create_simple("syborg,framebuffer", 0xC0005000, pic[4]); |
|
74 |
sysbus_create_simple("syborg,serial", 0xC0006000, pic[5]); |
|
75 |
sysbus_create_simple("syborg,serial", 0xC0007000, pic[6]); |
|
76 |
sysbus_create_simple("syborg,serial", 0xC0008000, pic[7]); |
|
77 |
sysbus_create_simple("syborg,serial", 0xC0009000, pic[8]); |
|
78 |
|
|
79 |
syborg_binfo.ram_size = ram_size; |
|
80 |
syborg_binfo.kernel_filename = kernel_filename; |
|
81 |
syborg_binfo.kernel_cmdline = kernel_cmdline; |
|
82 |
syborg_binfo.initrd_filename = initrd_filename; |
|
83 |
syborg_binfo.board_id = 0; |
|
84 |
arm_load_kernel(env, &syborg_binfo); |
|
85 |
} |
|
86 |
|
|
87 |
QEMUMachine syborg_machine = { |
|
88 |
.name = "syborg", |
|
89 |
.desc = "Syborg (Symbian Virtual Platform)", |
|
90 |
.init = syborg_init, |
|
91 |
}; |
b/hw/syborg.h | ||
---|---|---|
1 |
#ifndef _SYBORG_H |
|
2 |
#define _SYBORG_H |
|
3 |
|
|
4 |
#define SYBORG_ID_PLATFORM 0xc51d1000 |
|
5 |
#define SYBORG_ID_INT 0xc51d0000 |
|
6 |
#define SYBORG_ID_SERIAL 0xc51d0001 |
|
7 |
#define SYBORG_ID_KEYBOARD 0xc51d0002 |
|
8 |
#define SYBORG_ID_TIMER 0xc51d0003 |
|
9 |
#define SYBORG_ID_RTC 0xc51d0004 |
|
10 |
#define SYBORG_ID_MOUSE 0xc51d0005 |
|
11 |
#define SYBORG_ID_TOUCHSCREEN 0xc51d0006 |
|
12 |
#define SYBORG_ID_FRAMEBUFFER 0xc51d0007 |
|
13 |
#define SYBORG_ID_HOSTFS 0xc51d0008 |
|
14 |
#define SYBORG_ID_SNAPSHOT 0xc51d0009 |
|
15 |
#define SYBORG_ID_VIRTIO 0xc51d000a |
|
16 |
#define SYBORG_ID_NAND 0xc51d000b |
|
17 |
|
|
18 |
#endif |
b/hw/syborg_fb.c | ||
---|---|---|
1 |
/* |
|
2 |
* Syborg Framebuffer |
|
3 |
* |
|
4 |
* Copyright (c) 2009 CodeSourcery |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
#include "sysbus.h" |
|
26 |
#include "console.h" |
|
27 |
#include "syborg.h" |
|
28 |
#include "framebuffer.h" |
|
29 |
|
|
30 |
//#define DEBUG_SYBORG_FB |
|
31 |
|
|
32 |
#ifdef DEBUG_SYBORG_FB |
|
33 |
#define DPRINTF(fmt, ...) \ |
|
34 |
do { printf("syborg_fb: " fmt , ## __VA_ARGS__); } while (0) |
|
35 |
#define BADF(fmt, ...) \ |
|
36 |
do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__); \ |
|
37 |
exit(1);} while (0) |
|
38 |
#else |
|
39 |
#define DPRINTF(fmt, ...) do {} while(0) |
|
40 |
#define BADF(fmt, ...) \ |
|
41 |
do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__);} while (0) |
|
42 |
#endif |
|
43 |
|
|
44 |
enum { |
|
45 |
FB_ID = 0, |
|
46 |
FB_BASE = 1, |
|
47 |
FB_HEIGHT = 2, |
|
48 |
FB_WIDTH = 3, |
|
49 |
FB_ORIENTATION = 4, |
|
50 |
FB_BLANK = 5, |
|
51 |
FB_INT_MASK = 6, |
|
52 |
FB_INTERRUPT_CAUSE = 7, |
|
53 |
FB_BPP = 8, |
|
54 |
FB_COLOR_ORDER = 9, |
|
55 |
FB_BYTE_ORDER = 10, |
|
56 |
FB_PIXEL_ORDER = 11, |
|
57 |
FB_ROW_PITCH = 12, |
|
58 |
FB_ENABLED = 13, |
|
59 |
FB_PALETTE_START = 0x400 >> 2, |
|
60 |
FB_PALETTE_END = FB_PALETTE_START+256-1, |
|
61 |
}; |
|
62 |
|
|
63 |
#define FB_INT_VSYNC (1U << 0) |
|
64 |
#define FB_INT_BASE_UPDATE_DONE (1U << 1) |
|
65 |
|
|
66 |
typedef struct { |
|
67 |
SysBusDevice busdev; |
|
68 |
DisplayState *ds; |
|
69 |
/*QEMUConsole *console;*/ |
|
70 |
uint32_t need_update : 1; |
|
71 |
uint32_t need_int : 1; |
|
72 |
uint32_t enabled : 1; |
|
73 |
uint32_t int_status; |
|
74 |
uint32_t int_enable; |
|
75 |
qemu_irq irq; |
|
76 |
|
|
77 |
uint32_t base; |
|
78 |
uint32_t pitch; |
|
79 |
int rows; |
|
80 |
int cols; |
|
81 |
int blank; |
|
82 |
int bpp; |
|
83 |
int rgb; /* 0 = BGR, 1 = RGB */ |
|
84 |
int endian; /* 0 = Little, 1 = Big */ |
|
85 |
uint32_t raw_palette[256]; |
|
86 |
uint32_t palette[256]; |
|
87 |
} SyborgFBState; |
|
88 |
|
|
89 |
enum { |
|
90 |
BPP_SRC_1, |
|
91 |
BPP_SRC_2, |
|
92 |
BPP_SRC_4, |
|
93 |
BPP_SRC_8, |
|
94 |
BPP_SRC_16, |
|
95 |
BPP_SRC_32, |
|
96 |
/* TODO: Implement these. */ |
|
97 |
BPP_SRC_15 = -1, |
|
98 |
BPP_SRC_24 = -2 |
|
99 |
}; |
|
100 |
|
|
101 |
#include "pixel_ops.h" |
|
102 |
|
|
103 |
#define BITS 8 |
|
104 |
#include "pl110_template.h" |
|
105 |
#define BITS 15 |
|
106 |
#include "pl110_template.h" |
|
107 |
#define BITS 16 |
|
108 |
#include "pl110_template.h" |
|
109 |
#define BITS 24 |
|
110 |
#include "pl110_template.h" |
|
111 |
#define BITS 32 |
|
112 |
#include "pl110_template.h" |
|
113 |
|
|
114 |
/* Update interrupts. */ |
|
115 |
static void syborg_fb_update(SyborgFBState *s) |
|
116 |
{ |
|
117 |
if ((s->int_status & s->int_enable) != 0) { |
|
118 |
DPRINTF("Raise IRQ\n"); |
|
119 |
qemu_irq_raise(s->irq); |
|
120 |
} else { |
|
121 |
DPRINTF("Lower IRQ\n"); |
|
122 |
qemu_irq_lower(s->irq); |
|
123 |
} |
|
124 |
} |
|
125 |
|
|
126 |
static int syborg_fb_enabled(const SyborgFBState *s) |
|
127 |
{ |
|
128 |
return s->enabled; |
|
129 |
} |
|
130 |
|
|
131 |
static void syborg_fb_update_palette(SyborgFBState *s) |
|
132 |
{ |
|
133 |
int n, i; |
|
134 |
uint32_t raw; |
|
135 |
unsigned int r, g, b; |
|
136 |
|
|
137 |
switch (s->bpp) { |
|
138 |
case BPP_SRC_1: n = 2; break; |
|
139 |
case BPP_SRC_2: n = 4; break; |
|
140 |
case BPP_SRC_4: n = 16; break; |
|
141 |
case BPP_SRC_8: n = 256; break; |
|
142 |
default: return; |
|
143 |
} |
|
144 |
|
|
145 |
for (i = 0; i < n; i++) { |
|
146 |
raw = s->raw_palette[i]; |
|
147 |
r = (raw >> 16) & 0xff; |
|
148 |
g = (raw >> 8) & 0xff; |
|
149 |
b = raw & 0xff; |
|
150 |
switch (ds_get_bits_per_pixel(s->ds)) { |
|
151 |
case 8: |
|
152 |
s->palette[i] = rgb_to_pixel8(r, g, b); |
|
153 |
break; |
|
154 |
case 15: |
|
155 |
s->palette[i] = rgb_to_pixel15(r, g, b); |
|
156 |
break; |
|
157 |
case 16: |
|
158 |
s->palette[i] = rgb_to_pixel16(r, g, b); |
|
159 |
break; |
|
160 |
case 24: |
|
161 |
case 32: |
|
162 |
s->palette[i] = rgb_to_pixel32(r, g, b); |
|
163 |
break; |
|
164 |
default: |
|
165 |
abort(); |
|
166 |
} |
|
167 |
} |
|
168 |
|
|
169 |
} |
|
170 |
|
|
171 |
static void syborg_fb_update_display(void *opaque) |
|
172 |
{ |
|
173 |
SyborgFBState *s = (SyborgFBState *)opaque; |
|
174 |
drawfn* fntable; |
|
175 |
drawfn fn; |
|
176 |
int dest_width; |
|
177 |
int src_width; |
|
178 |
int bpp_offset; |
|
179 |
int first; |
|
180 |
int last; |
|
181 |
|
|
182 |
if (!syborg_fb_enabled(s)) |
|
183 |
return; |
|
184 |
|
|
185 |
switch (ds_get_bits_per_pixel(s->ds)) { |
|
186 |
case 0: |
|
187 |
return; |
|
188 |
case 8: |
|
189 |
fntable = pl110_draw_fn_8; |
|
190 |
dest_width = 1; |
|
191 |
break; |
|
192 |
case 15: |
|
193 |
fntable = pl110_draw_fn_15; |
|
194 |
dest_width = 2; |
|
195 |
break; |
|
196 |
case 16: |
|
197 |
fntable = pl110_draw_fn_16; |
|
198 |
dest_width = 2; |
|
199 |
break; |
|
200 |
case 24: |
|
201 |
fntable = pl110_draw_fn_24; |
|
202 |
dest_width = 3; |
|
203 |
break; |
|
204 |
case 32: |
|
205 |
fntable = pl110_draw_fn_32; |
|
206 |
dest_width = 4; |
|
207 |
break; |
|
208 |
default: |
|
209 |
fprintf(stderr, "syborg_fb: Bad color depth\n"); |
|
210 |
exit(1); |
|
211 |
} |
|
212 |
|
|
213 |
if (s->need_int) { |
|
214 |
s->int_status |= FB_INT_BASE_UPDATE_DONE; |
|
215 |
syborg_fb_update(s); |
|
216 |
s->need_int = 0; |
|
217 |
} |
|
218 |
|
|
219 |
if (s->rgb) { |
|
220 |
bpp_offset = 18; |
|
221 |
} else { |
|
222 |
bpp_offset = 0; |
|
223 |
} |
|
224 |
if (s->endian) { |
|
225 |
bpp_offset += 6; |
|
226 |
} |
|
227 |
|
|
228 |
fn = fntable[s->bpp + bpp_offset]; |
|
229 |
|
|
230 |
if (s->pitch) { |
|
231 |
src_width = s->pitch; |
|
232 |
} else { |
|
233 |
src_width = s->cols; |
|
234 |
switch (s->bpp) { |
|
235 |
case BPP_SRC_1: |
|
236 |
src_width >>= 3; |
|
237 |
break; |
|
238 |
case BPP_SRC_2: |
|
239 |
src_width >>= 2; |
|
240 |
break; |
|
241 |
case BPP_SRC_4: |
|
242 |
src_width >>= 1; |
|
243 |
break; |
|
244 |
case BPP_SRC_8: |
|
245 |
break; |
|
246 |
case BPP_SRC_15: |
|
247 |
case BPP_SRC_16: |
|
248 |
src_width <<= 1; |
|
249 |
break; |
|
250 |
case BPP_SRC_24: |
|
251 |
src_width *= 3; |
|
252 |
break; |
|
253 |
case BPP_SRC_32: |
|
254 |
src_width <<= 2; |
|
255 |
break; |
|
256 |
} |
|
257 |
} |
|
258 |
dest_width *= s->cols; |
|
259 |
first = 0; |
|
260 |
/* TODO: Implement blanking. */ |
|
261 |
if (!s->blank) { |
|
262 |
if (s->need_update && s->bpp <= BPP_SRC_8) { |
|
263 |
syborg_fb_update_palette(s); |
|
264 |
} |
|
265 |
framebuffer_update_display(s->ds, |
|
266 |
s->base, s->cols, s->rows, |
|
267 |
src_width, dest_width, 0, |
|
268 |
s->need_update, |
|
269 |
fn, s->palette, |
|
270 |
&first, &last); |
|
271 |
if (first >= 0) { |
|
272 |
dpy_update(s->ds, 0, first, s->cols, last - first + 1); |
|
273 |
} |
|
274 |
|
|
275 |
s->int_status |= FB_INT_VSYNC; |
|
276 |
syborg_fb_update(s); |
|
277 |
} |
|
278 |
|
|
279 |
s->need_update = 0; |
|
280 |
} |
|
281 |
|
|
282 |
static void syborg_fb_invalidate_display(void * opaque) |
|
283 |
{ |
|
284 |
SyborgFBState *s = (SyborgFBState *)opaque; |
|
285 |
s->need_update = 1; |
|
286 |
} |
|
287 |
|
|
288 |
static uint32_t syborg_fb_read(void *opaque, target_phys_addr_t offset) |
|
289 |
{ |
|
290 |
SyborgFBState *s = opaque; |
|
291 |
|
|
292 |
DPRINTF("read reg %d\n", (int)offset); |
|
293 |
offset &= 0xfff; |
|
294 |
switch (offset >> 2) { |
|
295 |
case FB_ID: |
|
296 |
return SYBORG_ID_FRAMEBUFFER; |
|
297 |
|
|
298 |
case FB_BASE: |
|
299 |
return s->base; |
|
300 |
|
|
301 |
case FB_HEIGHT: |
|
302 |
return s->rows; |
|
303 |
|
|
304 |
case FB_WIDTH: |
|
305 |
return s->cols; |
|
306 |
|
|
307 |
case FB_ORIENTATION: |
|
308 |
return 0; |
|
309 |
|
|
310 |
case FB_BLANK: |
|
311 |
return s->blank; |
|
312 |
|
|
313 |
case FB_INT_MASK: |
|
314 |
return s->int_enable; |
|
315 |
|
|
316 |
case FB_INTERRUPT_CAUSE: |
|
317 |
return s->int_status; |
|
318 |
|
|
319 |
case FB_BPP: |
|
320 |
switch (s->bpp) { |
|
321 |
case BPP_SRC_1: return 1; |
|
322 |
case BPP_SRC_2: return 2; |
|
323 |
case BPP_SRC_4: return 4; |
|
324 |
case BPP_SRC_8: return 8; |
|
325 |
case BPP_SRC_15: return 15; |
|
326 |
case BPP_SRC_16: return 16; |
|
327 |
case BPP_SRC_24: return 24; |
|
328 |
case BPP_SRC_32: return 32; |
|
329 |
default: return 0; |
|
330 |
} |
|
331 |
|
|
332 |
case FB_COLOR_ORDER: |
|
333 |
return s->rgb; |
|
334 |
|
|
335 |
case FB_BYTE_ORDER: |
|
336 |
return s->endian; |
|
337 |
|
|
338 |
case FB_PIXEL_ORDER: |
|
339 |
return 0; |
|
340 |
|
|
341 |
case FB_ROW_PITCH: |
|
342 |
return s->pitch; |
|
343 |
|
|
344 |
case FB_ENABLED: |
|
345 |
return s->enabled; |
|
346 |
|
|
347 |
default: |
|
348 |
if ((offset >> 2) >= FB_PALETTE_START |
|
349 |
&& (offset >> 2) <= FB_PALETTE_END) { |
|
350 |
return s->raw_palette[(offset >> 2) - FB_PALETTE_START]; |
|
351 |
} else { |
|
352 |
cpu_abort (cpu_single_env, "syborg_fb_read: Bad offset %x\n", |
|
353 |
(int)offset); |
|
354 |
} |
|
355 |
return 0; |
|
356 |
} |
|
357 |
} |
|
358 |
|
|
359 |
static void syborg_fb_write(void *opaque, target_phys_addr_t offset, |
|
360 |
uint32_t val) |
|
361 |
{ |
|
362 |
SyborgFBState *s = opaque; |
|
363 |
|
|
364 |
DPRINTF("write reg %d = %d\n", (int)offset, val); |
|
365 |
s->need_update = 1; |
|
366 |
offset &= 0xfff; |
|
367 |
switch (offset >> 2) { |
|
368 |
case FB_BASE: |
|
369 |
s->base = val; |
|
370 |
s->need_int = 1; |
|
371 |
s->need_update = 1; |
|
372 |
syborg_fb_update(s); |
|
373 |
break; |
|
374 |
|
|
375 |
case FB_HEIGHT: |
|
376 |
s->rows = val; |
|
377 |
break; |
|
378 |
|
|
379 |
case FB_WIDTH: |
|
380 |
s->cols = val; |
|
381 |
break; |
|
382 |
|
|
383 |
case FB_ORIENTATION: |
|
384 |
/* TODO: Implement rotation. */ |
|
385 |
break; |
|
386 |
|
|
387 |
case FB_BLANK: |
|
388 |
s->blank = val & 1; |
|
389 |
break; |
|
390 |
|
|
391 |
case FB_INT_MASK: |
|
392 |
s->int_enable = val; |
|
393 |
syborg_fb_update(s); |
|
394 |
break; |
|
395 |
|
|
396 |
case FB_INTERRUPT_CAUSE: |
|
397 |
s->int_status &= ~val; |
|
398 |
syborg_fb_update(s); |
|
399 |
break; |
|
400 |
|
|
401 |
case FB_BPP: |
|
402 |
switch (val) { |
|
403 |
case 1: val = BPP_SRC_1; break; |
|
404 |
case 2: val = BPP_SRC_2; break; |
|
405 |
case 4: val = BPP_SRC_4; break; |
|
406 |
case 8: val = BPP_SRC_8; break; |
|
407 |
/* case 15: val = BPP_SRC_15; break; */ |
|
408 |
case 16: val = BPP_SRC_16; break; |
|
409 |
/* case 24: val = BPP_SRC_24; break; */ |
|
410 |
case 32: val = BPP_SRC_32; break; |
|
411 |
default: val = s->bpp; break; |
|
412 |
} |
|
413 |
s->bpp = val; |
|
414 |
break; |
|
415 |
|
|
416 |
case FB_COLOR_ORDER: |
|
417 |
s->rgb = (val != 0); |
|
418 |
break; |
|
419 |
|
|
420 |
case FB_BYTE_ORDER: |
|
421 |
s->endian = (val != 0); |
|
422 |
break; |
|
423 |
|
|
424 |
case FB_PIXEL_ORDER: |
|
425 |
/* TODO: Implement this. */ |
|
426 |
break; |
|
427 |
|
|
428 |
case FB_ROW_PITCH: |
|
429 |
s->pitch = val; |
|
430 |
break; |
|
431 |
|
|
432 |
case FB_ENABLED: |
|
433 |
s->enabled = val; |
|
434 |
break; |
|
435 |
|
|
436 |
default: |
|
437 |
if ((offset >> 2) >= FB_PALETTE_START |
|
438 |
&& (offset >> 2) <= FB_PALETTE_END) { |
|
439 |
s->raw_palette[(offset >> 2) - FB_PALETTE_START] = val; |
|
440 |
} else { |
|
441 |
cpu_abort (cpu_single_env, "syborg_fb_write: Bad offset %x\n", |
|
442 |
(int)offset); |
|
443 |
} |
|
444 |
break; |
|
445 |
} |
|
446 |
} |
|
447 |
|
|
448 |
static CPUReadMemoryFunc *syborg_fb_readfn[] = { |
|
449 |
syborg_fb_read, |
|
450 |
syborg_fb_read, |
|
451 |
syborg_fb_read |
|
452 |
}; |
|
453 |
|
|
454 |
static CPUWriteMemoryFunc *syborg_fb_writefn[] = { |
|
455 |
syborg_fb_write, |
|
456 |
syborg_fb_write, |
|
457 |
syborg_fb_write |
|
458 |
}; |
|
459 |
|
|
460 |
static void syborg_fb_save(QEMUFile *f, void *opaque) |
|
461 |
{ |
|
462 |
SyborgFBState *s = opaque; |
|
463 |
int i; |
|
464 |
|
|
465 |
qemu_put_be32(f, s->need_int); |
|
466 |
qemu_put_be32(f, s->int_status); |
|
467 |
qemu_put_be32(f, s->int_enable); |
|
468 |
qemu_put_be32(f, s->enabled); |
|
469 |
qemu_put_be32(f, s->base); |
|
470 |
qemu_put_be32(f, s->pitch); |
|
471 |
qemu_put_be32(f, s->rows); |
|
472 |
qemu_put_be32(f, s->cols); |
|
473 |
qemu_put_be32(f, s->bpp); |
|
474 |
qemu_put_be32(f, s->rgb); |
|
475 |
for (i = 0; i < 256; i++) { |
|
476 |
qemu_put_be32(f, s->raw_palette[i]); |
|
477 |
} |
|
478 |
} |
|
479 |
|
|
480 |
static int syborg_fb_load(QEMUFile *f, void *opaque, int version_id) |
|
481 |
{ |
|
482 |
SyborgFBState *s = opaque; |
|
483 |
int i; |
|
484 |
|
|
485 |
if (version_id != 1) |
|
486 |
return -EINVAL; |
|
487 |
|
|
488 |
s->need_int = qemu_get_be32(f); |
|
489 |
s->int_status = qemu_get_be32(f); |
|
490 |
s->int_enable = qemu_get_be32(f); |
|
491 |
s->enabled = qemu_get_be32(f); |
|
492 |
s->base = qemu_get_be32(f); |
|
493 |
s->pitch = qemu_get_be32(f); |
|
494 |
s->rows = qemu_get_be32(f); |
|
495 |
s->cols = qemu_get_be32(f); |
|
496 |
s->bpp = qemu_get_be32(f); |
|
497 |
s->rgb = qemu_get_be32(f); |
|
498 |
for (i = 0; i < 256; i++) { |
|
499 |
s->raw_palette[i] = qemu_get_be32(f); |
|
500 |
} |
|
501 |
s->need_update = 1; |
|
502 |
|
|
503 |
return 0; |
|
504 |
} |
|
505 |
|
|
506 |
static void syborg_fb_init(SysBusDevice *dev) |
|
507 |
{ |
|
508 |
SyborgFBState *s = FROM_SYSBUS(SyborgFBState, dev); |
|
509 |
int iomemtype; |
|
510 |
int width; |
|
511 |
int height; |
|
512 |
|
|
513 |
sysbus_init_irq(dev, &s->irq); |
|
514 |
iomemtype = cpu_register_io_memory(0, syborg_fb_readfn, |
|
515 |
syborg_fb_writefn, s); |
|
516 |
sysbus_init_mmio(dev, 0x1000, iomemtype); |
|
517 |
|
|
518 |
width = qdev_get_prop_int(&dev->qdev, "width", 0); |
|
519 |
height = qdev_get_prop_int(&dev->qdev, "height", 0); |
|
520 |
|
|
521 |
s->ds = graphic_console_init(syborg_fb_update_display, |
|
522 |
syborg_fb_invalidate_display, |
|
523 |
NULL, NULL, s); |
|
524 |
|
|
525 |
if (width != 0 && height != 0) { |
|
526 |
qemu_console_resize(s->ds, width, height); |
|
527 |
} |
|
528 |
|
|
529 |
if (!width) |
|
530 |
width = ds_get_width(s->ds); |
|
531 |
if (!height) |
|
532 |
height = ds_get_height(s->ds); |
|
533 |
|
|
534 |
s->cols = width; |
|
535 |
s->rows = height; |
|
536 |
|
|
537 |
register_savevm("syborg_framebuffer", -1, 1, |
|
538 |
syborg_fb_save, syborg_fb_load, s); |
|
539 |
} |
|
540 |
|
|
541 |
static void syborg_fb_register_devices(void) |
|
542 |
{ |
|
543 |
sysbus_register_dev("syborg,framebuffer", sizeof(SyborgFBState), |
|
544 |
syborg_fb_init); |
|
545 |
} |
|
546 |
|
|
547 |
device_init(syborg_fb_register_devices) |
b/hw/syborg_interrupt.c | ||
---|---|---|
1 |
/* |
|
2 |
* Syborg interrupt controller. |
|
3 |
* |
|
4 |
* Copyright (c) 2008 CodeSourcery |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
#include "sysbus.h" |
|
26 |
#include "syborg.h" |
|
27 |
|
|
28 |
//#define DEBUG_SYBORG_INT |
|
29 |
|
|
30 |
#ifdef DEBUG_SYBORG_INT |
|
31 |
#define DPRINTF(fmt, ...) \ |
|
32 |
do { printf("syborg_int: " fmt , ## __VA_ARGS__); } while (0) |
|
33 |
#define BADF(fmt, ...) \ |
|
34 |
do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__); \ |
|
35 |
exit(1);} while (0) |
|
36 |
#else |
|
37 |
#define DPRINTF(fmt, ...) do {} while(0) |
|
38 |
#define BADF(fmt, ...) \ |
|
39 |
do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__);} while (0) |
|
40 |
#endif |
|
41 |
enum { |
|
42 |
INT_ID = 0, |
|
43 |
INT_STATUS = 1, /* number of pending interrupts */ |
|
44 |
INT_CURRENT = 2, /* next interrupt to be serviced */ |
|
45 |
INT_DISABLE_ALL = 3, |
|
46 |
INT_DISABLE = 4, |
|
47 |
INT_ENABLE = 5, |
|
48 |
INT_TOTAL = 6 |
|
49 |
}; |
|
50 |
|
|
51 |
typedef struct { |
|
52 |
unsigned level:1; |
|
53 |
unsigned enabled:1; |
|
54 |
} syborg_int_flags; |
|
55 |
|
|
56 |
typedef struct { |
|
57 |
SysBusDevice busdev; |
|
58 |
int pending_count; |
|
59 |
int num_irqs; |
|
60 |
syborg_int_flags *flags; |
|
61 |
qemu_irq parent_irq; |
|
62 |
} SyborgIntState; |
|
63 |
|
|
64 |
static void syborg_int_update(SyborgIntState *s) |
|
65 |
{ |
|
66 |
DPRINTF("pending %d\n", s->pending_count); |
|
67 |
qemu_set_irq(s->parent_irq, s->pending_count > 0); |
|
68 |
} |
|
69 |
|
|
70 |
static void syborg_int_set_irq(void *opaque, int irq, int level) |
|
71 |
{ |
|
72 |
SyborgIntState *s = (SyborgIntState *)opaque; |
|
73 |
|
|
74 |
if (s->flags[irq].level == level) |
|
75 |
return; |
|
76 |
|
|
77 |
s->flags[irq].level = level; |
|
78 |
if (s->flags[irq].enabled) { |
|
79 |
if (level) |
|
80 |
s->pending_count++; |
|
81 |
else |
|
82 |
s->pending_count--; |
|
83 |
syborg_int_update(s); |
|
84 |
} |
|
85 |
} |
|
86 |
|
|
87 |
static uint32_t syborg_int_read(void *opaque, target_phys_addr_t offset) |
|
88 |
{ |
|
89 |
SyborgIntState *s = (SyborgIntState *)opaque; |
|
90 |
int i; |
|
91 |
|
|
92 |
offset &= 0xfff; |
|
93 |
switch (offset >> 2) { |
|
94 |
case INT_ID: |
|
95 |
return SYBORG_ID_INT; |
|
96 |
case INT_STATUS: |
|
97 |
DPRINTF("read status=%d\n", s->pending_count); |
|
98 |
return s->pending_count; |
|
99 |
|
|
100 |
case INT_CURRENT: |
|
101 |
for (i = 0; i < s->num_irqs; i++) { |
|
102 |
if (s->flags[i].level & s->flags[i].enabled) { |
|
103 |
DPRINTF("read current=%d\n", i); |
|
104 |
return i; |
|
105 |
} |
|
106 |
} |
|
107 |
DPRINTF("read current=none\n"); |
|
108 |
return 0xffffffffu; |
|
109 |
|
|
110 |
default: |
|
111 |
cpu_abort(cpu_single_env, "syborg_int_read: Bad offset %x\n", |
|
112 |
(int)offset); |
|
113 |
return 0; |
|
114 |
} |
|
115 |
} |
|
116 |
|
|
117 |
static void syborg_int_write(void *opaque, target_phys_addr_t offset, uint32_t value) |
|
118 |
{ |
|
119 |
SyborgIntState *s = (SyborgIntState *)opaque; |
|
120 |
int i; |
|
121 |
offset &= 0xfff; |
|
122 |
|
|
123 |
DPRINTF("syborg_int_write offset=%d val=%d\n", (int)offset, (int)value); |
|
124 |
switch (offset >> 2) { |
|
125 |
case INT_DISABLE_ALL: |
|
126 |
s->pending_count = 0; |
|
127 |
for (i = 0; i < s->num_irqs; i++) |
|
128 |
s->flags[i].enabled = 0; |
|
129 |
break; |
|
130 |
|
|
131 |
case INT_DISABLE: |
|
132 |
if (value >= s->num_irqs) |
|
133 |
break; |
|
134 |
if (s->flags[value].enabled) { |
|
135 |
if (s->flags[value].enabled) |
|
136 |
s->pending_count--; |
|
137 |
s->flags[value].enabled = 0; |
|
138 |
} |
|
139 |
break; |
|
140 |
|
|
141 |
case INT_ENABLE: |
|
142 |
if (value >= s->num_irqs) |
|
143 |
break; |
|
144 |
if (!(s->flags[value].enabled)) { |
|
145 |
if(s->flags[value].level) |
|
146 |
s->pending_count++; |
|
147 |
s->flags[value].enabled = 1; |
|
148 |
} |
|
149 |
break; |
|
150 |
|
|
151 |
default: |
|
152 |
cpu_abort(cpu_single_env, "syborg_int_write: Bad offset %x\n", |
|
153 |
(int)offset); |
|
154 |
return; |
|
155 |
} |
|
156 |
syborg_int_update(s); |
|
157 |
} |
|
158 |
|
|
159 |
static CPUReadMemoryFunc *syborg_int_readfn[] = { |
|
160 |
syborg_int_read, |
|
161 |
syborg_int_read, |
|
162 |
syborg_int_read |
|
163 |
}; |
|
164 |
|
|
165 |
static CPUWriteMemoryFunc *syborg_int_writefn[] = { |
|
166 |
syborg_int_write, |
|
167 |
syborg_int_write, |
|
168 |
syborg_int_write |
|
169 |
}; |
|
170 |
|
|
171 |
static void syborg_int_save(QEMUFile *f, void *opaque) |
|
172 |
{ |
|
173 |
SyborgIntState *s = (SyborgIntState *)opaque; |
|
174 |
int i; |
|
175 |
|
|
176 |
qemu_put_be32(f, s->num_irqs); |
|
177 |
qemu_put_be32(f, s->pending_count); |
|
178 |
for (i = 0; i < s->num_irqs; i++) { |
|
179 |
qemu_put_be32(f, s->flags[i].enabled |
|
180 |
| ((unsigned)s->flags[i].level << 1)); |
|
181 |
} |
|
182 |
} |
|
183 |
|
|
184 |
static int syborg_int_load(QEMUFile *f, void *opaque, int version_id) |
|
185 |
{ |
|
186 |
SyborgIntState *s = (SyborgIntState *)opaque; |
|
187 |
uint32_t val; |
|
188 |
int i; |
|
189 |
|
|
190 |
if (version_id != 1) |
|
191 |
return -EINVAL; |
|
192 |
|
|
193 |
val = qemu_get_be32(f); |
|
194 |
if (val != s->num_irqs) |
|
195 |
return -EINVAL; |
|
196 |
s->pending_count = qemu_get_be32(f); |
|
197 |
for (i = 0; i < s->num_irqs; i++) { |
|
198 |
val = qemu_get_be32(f); |
|
199 |
s->flags[i].enabled = val & 1; |
|
200 |
s->flags[i].level = (val >> 1) & 1; |
|
201 |
} |
|
202 |
return 0; |
|
203 |
} |
|
204 |
|
|
205 |
static void syborg_int_init(SysBusDevice *dev) |
|
206 |
{ |
|
207 |
SyborgIntState *s = FROM_SYSBUS(SyborgIntState, dev); |
|
208 |
int iomemtype; |
|
209 |
|
|
210 |
sysbus_init_irq(dev, &s->parent_irq); |
|
211 |
s->num_irqs = qdev_get_prop_int(&dev->qdev, "num-interrupts", 64); |
|
212 |
qdev_init_irq_sink(&dev->qdev, syborg_int_set_irq, s->num_irqs); |
|
213 |
iomemtype = cpu_register_io_memory(0, syborg_int_readfn, |
|
214 |
syborg_int_writefn, s); |
|
215 |
sysbus_init_mmio(dev, 0x1000, iomemtype); |
|
216 |
s->flags = qemu_mallocz(s->num_irqs * sizeof(syborg_int_flags)); |
|
217 |
|
|
218 |
register_savevm("syborg_int", -1, 1, syborg_int_save, syborg_int_load, s); |
|
219 |
} |
|
220 |
|
|
221 |
static void syborg_interrupt_register_devices(void) |
|
222 |
{ |
|
223 |
sysbus_register_dev("syborg,interrupt", sizeof(SyborgIntState), |
|
224 |
syborg_int_init); |
|
225 |
} |
|
226 |
|
|
227 |
device_init(syborg_interrupt_register_devices) |
b/hw/syborg_keyboard.c | ||
---|---|---|
1 |
/* |
|
2 |
* Syborg keyboard controller. |
|
3 |
* |
|
4 |
* Copyright (c) 2008 CodeSourcery |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
#include "sysbus.h" |
|
26 |
#include "console.h" |
|
27 |
#include "syborg.h" |
|
28 |
|
|
29 |
//#define DEBUG_SYBORG_KEYBOARD |
|
30 |
|
|
31 |
#ifdef DEBUG_SYBORG_KEYBOARD |
|
32 |
#define DPRINTF(fmt, ...) \ |
|
33 |
do { printf("syborg_keyboard: " fmt , ##args); } while (0) |
|
34 |
#define BADF(fmt, ...) \ |
|
35 |
do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \ |
|
36 |
exit(1);} while (0) |
|
37 |
#else |
|
38 |
#define DPRINTF(fmt, ...) do {} while(0) |
|
39 |
#define BADF(fmt, ...) \ |
|
40 |
do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \ |
|
41 |
} while (0) |
|
42 |
#endif |
|
43 |
|
|
44 |
enum { |
|
45 |
KBD_ID = 0, |
|
46 |
KBD_DATA = 1, |
|
47 |
KBD_FIFO_COUNT = 2, |
|
48 |
KBD_INT_ENABLE = 3, |
|
49 |
KBD_FIFO_SIZE = 4 |
|
50 |
}; |
|
51 |
|
|
52 |
typedef struct { |
|
53 |
SysBusDevice busdev; |
|
54 |
int int_enabled; |
|
55 |
int extension_bit; |
|
56 |
int fifo_size; |
|
57 |
uint32_t *key_fifo; |
|
58 |
int read_pos, read_count; |
|
59 |
qemu_irq irq; |
|
60 |
} SyborgKeyboardState; |
|
61 |
|
|
62 |
static void syborg_keyboard_update(SyborgKeyboardState *s) |
|
63 |
{ |
|
64 |
int level = s->read_count && s->int_enabled; |
|
65 |
DPRINTF("Update IRQ %d\n", level); |
|
66 |
qemu_set_irq(s->irq, level); |
|
67 |
} |
|
68 |
|
|
69 |
static uint32_t syborg_keyboard_read(void *opaque, target_phys_addr_t offset) |
|
70 |
{ |
|
71 |
SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; |
|
72 |
int c; |
|
73 |
|
|
74 |
DPRINTF("reg read %d\n", (int)offset); |
|
75 |
offset &= 0xfff; |
|
76 |
switch (offset >> 2) { |
|
77 |
case KBD_ID: |
|
78 |
return SYBORG_ID_KEYBOARD; |
|
79 |
case KBD_FIFO_COUNT: |
|
80 |
return s->read_count; |
|
81 |
case KBD_DATA: |
|
82 |
if (s->read_count == 0) { |
|
83 |
c = -1; |
|
84 |
DPRINTF("FIFO underflow\n"); |
|
85 |
} else { |
|
86 |
c = s->key_fifo[s->read_pos]; |
|
87 |
DPRINTF("FIFO read 0x%x\n", c); |
|
88 |
s->read_count--; |
|
89 |
s->read_pos++; |
|
90 |
if (s->read_pos == s->fifo_size) |
|
91 |
s->read_pos = 0; |
|
92 |
} |
|
93 |
syborg_keyboard_update(s); |
|
94 |
return c; |
|
95 |
case KBD_INT_ENABLE: |
|
96 |
return s->int_enabled; |
|
97 |
case KBD_FIFO_SIZE: |
|
98 |
return s->fifo_size; |
|
99 |
default: |
|
100 |
cpu_abort(cpu_single_env, "syborg_keyboard_read: Bad offset %x\n", |
|
101 |
(int)offset); |
|
102 |
return 0; |
|
103 |
} |
|
104 |
} |
|
105 |
|
|
106 |
static void syborg_keyboard_write(void *opaque, target_phys_addr_t offset, |
|
107 |
uint32_t value) |
|
108 |
{ |
|
109 |
SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; |
|
110 |
|
|
111 |
DPRINTF("reg write %d\n", (int)offset); |
|
112 |
offset &= 0xfff; |
|
113 |
switch (offset >> 2) { |
|
114 |
case KBD_INT_ENABLE: |
|
115 |
s->int_enabled = value; |
|
116 |
syborg_keyboard_update(s); |
|
117 |
break; |
|
118 |
default: |
|
119 |
cpu_abort(cpu_single_env, "syborg_keyboard_write: Bad offset %x\n", |
|
120 |
(int)offset); |
|
121 |
} |
|
122 |
} |
|
123 |
|
|
124 |
static CPUReadMemoryFunc *syborg_keyboard_readfn[] = { |
|
125 |
syborg_keyboard_read, |
|
126 |
syborg_keyboard_read, |
|
127 |
syborg_keyboard_read |
|
128 |
}; |
|
129 |
|
|
130 |
static CPUWriteMemoryFunc *syborg_keyboard_writefn[] = { |
|
131 |
syborg_keyboard_write, |
|
132 |
syborg_keyboard_write, |
|
133 |
syborg_keyboard_write |
|
134 |
}; |
|
135 |
|
|
136 |
static void syborg_keyboard_event(void *opaque, int keycode) |
|
137 |
{ |
|
138 |
SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; |
|
139 |
int slot; |
|
140 |
uint32_t val; |
|
141 |
|
|
142 |
/* Strip off 0xe0 prefixes and reconstruct the full scancode. */ |
|
143 |
if (keycode == 0xe0 && !s->extension_bit) { |
|
144 |
DPRINTF("Extension bit\n"); |
|
145 |
s->extension_bit = 0x80; |
|
146 |
return; |
|
147 |
} |
|
148 |
val = (keycode & 0x7f) | s->extension_bit; |
|
149 |
if (keycode & 0x80) |
|
150 |
val |= 0x80000000u; |
|
151 |
s->extension_bit = 0; |
|
152 |
|
|
153 |
DPRINTF("FIFO push 0x%x\n", val); |
|
154 |
slot = s->read_pos + s->read_count; |
|
155 |
if (slot >= s->fifo_size) |
|
156 |
slot -= s->fifo_size; |
|
157 |
|
|
158 |
if (s->read_count < s->fifo_size) { |
|
159 |
s->read_count++; |
|
160 |
s->key_fifo[slot] = val; |
|
161 |
} else { |
|
162 |
fprintf(stderr, "syborg_keyboard error! FIFO overflow\n"); |
|
163 |
} |
|
164 |
|
|
165 |
syborg_keyboard_update(s); |
|
166 |
} |
|
167 |
|
|
168 |
static void syborg_keyboard_save(QEMUFile *f, void *opaque) |
|
169 |
{ |
|
170 |
SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; |
|
171 |
int i; |
|
172 |
|
|
173 |
qemu_put_be32(f, s->fifo_size); |
|
174 |
qemu_put_be32(f, s->int_enabled); |
|
175 |
qemu_put_be32(f, s->extension_bit); |
|
176 |
qemu_put_be32(f, s->read_pos); |
|
177 |
qemu_put_be32(f, s->read_count); |
|
178 |
for (i = 0; i < s->fifo_size; i++) { |
|
179 |
qemu_put_be32(f, s->key_fifo[i]); |
|
180 |
} |
|
181 |
} |
|
182 |
|
|
183 |
static int syborg_keyboard_load(QEMUFile *f, void *opaque, int version_id) |
|
184 |
{ |
|
185 |
SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; |
|
186 |
uint32_t val; |
|
187 |
int i; |
|
188 |
|
|
189 |
if (version_id != 1) |
|
190 |
return -EINVAL; |
|
191 |
|
|
192 |
val = qemu_get_be32(f); |
|
193 |
if (val != s->fifo_size) |
|
194 |
return -EINVAL; |
|
195 |
|
|
196 |
s->int_enabled = qemu_get_be32(f); |
|
197 |
s->extension_bit = qemu_get_be32(f); |
|
198 |
s->read_pos = qemu_get_be32(f); |
|
199 |
s->read_count = qemu_get_be32(f); |
|
200 |
for (i = 0; i < s->fifo_size; i++) { |
|
201 |
s->key_fifo[i] = qemu_get_be32(f); |
|
202 |
} |
|
203 |
return 0; |
|
204 |
} |
|
205 |
|
|
206 |
static void syborg_keyboard_init(SysBusDevice *dev) |
|
207 |
{ |
|
208 |
SyborgKeyboardState *s = FROM_SYSBUS(SyborgKeyboardState, dev); |
|
209 |
int iomemtype; |
|
210 |
|
|
211 |
sysbus_init_irq(dev, &s->irq); |
|
212 |
iomemtype = cpu_register_io_memory(0, syborg_keyboard_readfn, |
|
213 |
syborg_keyboard_writefn, s); |
|
214 |
sysbus_init_mmio(dev, 0x1000, iomemtype); |
|
215 |
s->fifo_size = qdev_get_prop_int(&dev->qdev, "fifo-size", 16); |
|
216 |
if (s->fifo_size <= 0) { |
|
217 |
fprintf(stderr, "syborg_keyboard: fifo too small\n"); |
|
218 |
s->fifo_size = 16; |
|
219 |
} |
|
220 |
s->key_fifo = qemu_mallocz(s->fifo_size * sizeof(s->key_fifo[0])); |
|
221 |
|
|
222 |
qemu_add_kbd_event_handler(syborg_keyboard_event, s); |
|
223 |
|
|
224 |
register_savevm("syborg_keyboard", -1, 1, |
|
225 |
syborg_keyboard_save, syborg_keyboard_load, s); |
|
226 |
} |
|
227 |
|
|
228 |
static void syborg_keyboard_register_devices(void) |
|
229 |
{ |
|
230 |
sysbus_register_dev("syborg,keyboard", sizeof(SyborgKeyboardState), |
|
231 |
syborg_keyboard_init); |
|
232 |
} |
|
233 |
|
|
234 |
device_init(syborg_keyboard_register_devices) |
b/hw/syborg_pointer.c | ||
---|---|---|
1 |
/* |
|
2 |
* Syborg pointing device (mouse/touchscreen) |
|
3 |
* |
|
4 |
* Copyright (c) 2008 CodeSourcery |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
#include "sysbus.h" |
|
26 |
#include "console.h" |
|
27 |
#include "syborg.h" |
|
28 |
|
|
29 |
enum { |
|
30 |
POINTER_ID = 0, |
|
31 |
POINTER_LATCH = 1, |
|
32 |
POINTER_FIFO_COUNT = 2, |
|
33 |
POINTER_X = 3, |
|
34 |
POINTER_Y = 4, |
|
35 |
POINTER_Z = 5, |
|
36 |
POINTER_BUTTONS = 6, |
|
37 |
POINTER_INT_ENABLE = 7, |
|
38 |
POINTER_FIFO_SIZE = 8 |
|
39 |
}; |
|
40 |
|
|
41 |
typedef struct { |
|
42 |
int x, y, z, pointer_buttons; |
|
43 |
} event_data; |
|
44 |
|
|
45 |
typedef struct { |
|
46 |
SysBusDevice busdev; |
|
47 |
int int_enabled; |
|
48 |
int fifo_size; |
|
49 |
event_data *event_fifo; |
|
50 |
int read_pos, read_count; |
|
51 |
qemu_irq irq; |
|
52 |
int absolute; |
|
53 |
} SyborgPointerState; |
|
54 |
|
|
55 |
static void syborg_pointer_update(SyborgPointerState *s) |
|
56 |
{ |
|
57 |
qemu_set_irq(s->irq, s->read_count && s->int_enabled); |
|
58 |
} |
|
59 |
|
|
60 |
static uint32_t syborg_pointer_read(void *opaque, target_phys_addr_t offset) |
|
61 |
{ |
|
62 |
SyborgPointerState *s = (SyborgPointerState *)opaque; |
|
63 |
|
|
64 |
offset &= 0xfff; |
|
65 |
switch (offset >> 2) { |
|
66 |
case POINTER_ID: |
|
67 |
return s->absolute ? SYBORG_ID_TOUCHSCREEN : SYBORG_ID_MOUSE; |
|
68 |
case POINTER_FIFO_COUNT: |
|
69 |
return s->read_count; |
|
70 |
case POINTER_X: |
|
71 |
return s->event_fifo[s->read_pos].x; |
|
72 |
case POINTER_Y: |
|
73 |
return s->event_fifo[s->read_pos].y; |
|
74 |
case POINTER_Z: |
|
75 |
return s->event_fifo[s->read_pos].z; |
|
76 |
case POINTER_BUTTONS: |
|
77 |
return s->event_fifo[s->read_pos].pointer_buttons; |
|
78 |
case POINTER_INT_ENABLE: |
|
79 |
return s->int_enabled; |
|
80 |
case POINTER_FIFO_SIZE: |
|
81 |
return s->fifo_size; |
|
82 |
default: |
|
83 |
cpu_abort(cpu_single_env, "syborg_pointer_read: Bad offset %x\n", |
|
84 |
(int)offset); |
|
85 |
return 0; |
|
86 |
} |
|
87 |
} |
|
88 |
|
|
89 |
static void syborg_pointer_write(void *opaque, target_phys_addr_t offset, |
|
90 |
uint32_t value) |
|
91 |
{ |
|
92 |
SyborgPointerState *s = (SyborgPointerState *)opaque; |
|
93 |
|
|
94 |
offset &= 0xfff; |
|
95 |
switch (offset >> 2) { |
|
96 |
case POINTER_LATCH: |
|
97 |
if (s->read_count > 0) { |
|
98 |
s->read_count--; |
|
99 |
if (++s->read_pos == s->fifo_size) |
|
100 |
s->read_pos = 0; |
|
101 |
} |
|
102 |
break; |
|
103 |
case POINTER_INT_ENABLE: |
|
104 |
s->int_enabled = value; |
|
105 |
break; |
|
106 |
default: |
|
107 |
cpu_abort(cpu_single_env, "syborg_pointer_write: Bad offset %x\n", |
|
108 |
(int)offset); |
|
109 |
} |
|
110 |
syborg_pointer_update(s); |
|
111 |
} |
|
112 |
|
|
113 |
static CPUReadMemoryFunc *syborg_pointer_readfn[] = { |
|
114 |
syborg_pointer_read, |
|
115 |
syborg_pointer_read, |
|
116 |
syborg_pointer_read |
|
117 |
}; |
|
118 |
|
|
119 |
static CPUWriteMemoryFunc *syborg_pointer_writefn[] = { |
|
120 |
syborg_pointer_write, |
|
121 |
syborg_pointer_write, |
|
122 |
syborg_pointer_write |
|
123 |
}; |
|
124 |
|
|
125 |
static void syborg_pointer_event(void *opaque, int dx, int dy, int dz, |
|
126 |
int buttons_state) |
|
127 |
{ |
|
128 |
SyborgPointerState *s = (SyborgPointerState *)opaque; |
|
129 |
int slot = s->read_pos + s->read_count; |
|
130 |
|
|
131 |
/* This first FIFO entry is used to store current register state. */ |
|
132 |
if (s->read_count < s->fifo_size - 1) { |
|
133 |
s->read_count++; |
|
134 |
slot++; |
|
135 |
} |
|
136 |
|
|
137 |
if (slot >= s->fifo_size) |
|
138 |
slot -= s->fifo_size; |
|
139 |
|
|
140 |
if (s->read_count == s->fifo_size && !s->absolute) { |
|
141 |
/* Merge existing entries. */ |
|
142 |
s->event_fifo[slot].x += dx; |
|
143 |
s->event_fifo[slot].y += dy; |
|
144 |
s->event_fifo[slot].z += dz; |
|
145 |
} else { |
|
146 |
s->event_fifo[slot].x = dx; |
|
147 |
s->event_fifo[slot].y = dy; |
|
148 |
s->event_fifo[slot].z = dz; |
|
149 |
} |
|
150 |
s->event_fifo[slot].pointer_buttons = buttons_state; |
|
151 |
|
|
152 |
syborg_pointer_update(s); |
|
153 |
} |
|
154 |
|
|
155 |
static void syborg_pointer_save(QEMUFile *f, void *opaque) |
|
156 |
{ |
|
157 |
SyborgPointerState *s = (SyborgPointerState *)opaque; |
|
158 |
int i; |
|
159 |
|
|
160 |
qemu_put_be32(f, s->fifo_size); |
|
161 |
qemu_put_be32(f, s->absolute); |
|
162 |
qemu_put_be32(f, s->int_enabled); |
|
163 |
qemu_put_be32(f, s->read_pos); |
|
164 |
qemu_put_be32(f, s->read_count); |
|
165 |
for (i = 0; i < s->fifo_size; i++) { |
|
166 |
qemu_put_be32(f, s->event_fifo[i].x); |
|
167 |
qemu_put_be32(f, s->event_fifo[i].y); |
|
168 |
qemu_put_be32(f, s->event_fifo[i].z); |
|
169 |
qemu_put_be32(f, s->event_fifo[i].pointer_buttons); |
|
170 |
} |
|
171 |
} |
|
172 |
|
|
173 |
static int syborg_pointer_load(QEMUFile *f, void *opaque, int version_id) |
|
174 |
{ |
|
175 |
SyborgPointerState *s = (SyborgPointerState *)opaque; |
|
176 |
uint32_t val; |
|
177 |
int i; |
|
178 |
|
|
179 |
if (version_id != 1) |
|
180 |
return -EINVAL; |
|
181 |
|
|
182 |
val = qemu_get_be32(f); |
|
183 |
if (val != s->fifo_size) |
|
184 |
return -EINVAL; |
|
185 |
|
|
186 |
val = qemu_get_be32(f); |
|
187 |
if (val != s->absolute) |
|
188 |
return -EINVAL; |
|
189 |
|
|
190 |
s->int_enabled = qemu_get_be32(f); |
|
191 |
s->read_pos = qemu_get_be32(f); |
|
192 |
s->read_count = qemu_get_be32(f); |
|
193 |
for (i = 0; i < s->fifo_size; i++) { |
|
194 |
s->event_fifo[i].x = qemu_get_be32(f); |
|
195 |
s->event_fifo[i].y = qemu_get_be32(f); |
|
196 |
s->event_fifo[i].z = qemu_get_be32(f); |
|
197 |
s->event_fifo[i].pointer_buttons = qemu_get_be32(f); |
|
198 |
} |
|
199 |
return 0; |
|
200 |
} |
|
201 |
|
|
202 |
static void syborg_pointer_init(SysBusDevice *dev) |
|
203 |
{ |
|
204 |
SyborgPointerState *s = FROM_SYSBUS(SyborgPointerState, dev); |
|
205 |
int iomemtype; |
|
206 |
|
|
207 |
sysbus_init_irq(dev, &s->irq); |
|
208 |
iomemtype = cpu_register_io_memory(0, syborg_pointer_readfn, |
|
209 |
syborg_pointer_writefn, s); |
|
210 |
sysbus_init_mmio(dev, 0x1000, iomemtype); |
|
211 |
|
|
212 |
s->absolute = qdev_get_prop_int(&dev->qdev, "absolute", 1); |
|
213 |
s->fifo_size = qdev_get_prop_int(&dev->qdev, "fifo-size", 16); |
|
214 |
if (s->fifo_size <= 0) { |
|
215 |
fprintf(stderr, "syborg_pointer: fifo too small\n"); |
|
216 |
s->fifo_size = 16; |
|
217 |
} |
|
218 |
s->event_fifo = qemu_mallocz(s->fifo_size * sizeof(s->event_fifo[0])); |
|
219 |
|
|
220 |
qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute, |
|
221 |
"Syborg Pointer"); |
|
222 |
|
|
223 |
register_savevm("syborg_pointer", -1, 1, |
|
224 |
syborg_pointer_save, syborg_pointer_load, s); |
|
225 |
} |
|
226 |
|
|
227 |
static void syborg_pointer_register_devices(void) |
|
228 |
{ |
|
229 |
sysbus_register_dev("syborg,pointer", sizeof(SyborgPointerState), |
|
230 |
syborg_pointer_init); |
|
231 |
} |
|
232 |
|
|
233 |
device_init(syborg_pointer_register_devices) |
b/hw/syborg_rtc.c | ||
---|---|---|
1 |
/* |
|
2 |
* Syborg RTC |
|
3 |
* |
|
4 |
* Copyright (c) 2008 CodeSourcery |
|
5 |
* |
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 |
* of this software and associated documentation files (the "Software"), to deal |
|
8 |
* in the Software without restriction, including without limitation the rights |
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 |
* copies of the Software, and to permit persons to whom the Software is |
|
11 |
* furnished to do so, subject to the following conditions: |
|
12 |
* |
|
13 |
* The above copyright notice and this permission notice shall be included in |
|
14 |
* all copies or substantial portions of the Software. |
|
15 |
* |
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 |
* THE SOFTWARE. |
|
23 |
*/ |
|
24 |
|
|
25 |
#include "sysbus.h" |
|
26 |
#include "qemu-timer.h" |
|
27 |
#include "syborg.h" |
|
28 |
|
|
29 |
enum { |
|
30 |
RTC_ID = 0, |
|
31 |
RTC_LATCH = 1, |
|
32 |
RTC_DATA_LOW = 2, |
|
33 |
RTC_DATA_HIGH = 3 |
|
34 |
}; |
|
35 |
|
|
36 |
typedef struct { |
|
37 |
SysBusDevice busdev; |
|
38 |
int64_t offset; |
|
39 |
int64_t data; |
|
40 |
qemu_irq irq; |
|
41 |
} SyborgRTCState; |
|
42 |
|
|
43 |
static uint32_t syborg_rtc_read(void *opaque, target_phys_addr_t offset) |
|
44 |
{ |
|
45 |
SyborgRTCState *s = (SyborgRTCState *)opaque; |
|
46 |
offset &= 0xfff; |
|
47 |
switch (offset >> 2) { |
|
48 |
case RTC_ID: |
|
49 |
return SYBORG_ID_RTC; |
|
50 |
case RTC_DATA_LOW: |
|
51 |
return (uint32_t)s->data; |
|
52 |
case RTC_DATA_HIGH: |
|
53 |
return (uint32_t)(s->data >> 32); |
|
54 |
default: |
|
55 |
cpu_abort(cpu_single_env, "syborg_rtc_read: Bad offset %x\n", |
|
56 |
(int)offset); |
|
57 |
return 0; |
|
58 |
} |
|
59 |
} |
|
60 |
|
|
61 |
static void syborg_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value) |
|
62 |
{ |
|
63 |
SyborgRTCState *s = (SyborgRTCState *)opaque; |
|
64 |
uint64_t now; |
|
65 |
|
|
66 |
offset &= 0xfff; |
|
67 |
switch (offset >> 2) { |
|
68 |
case RTC_LATCH: |
|
69 |
now = qemu_get_clock(vm_clock); |
|
70 |
if (value >= 4) { |
|
71 |
s->offset = s->data - now; |
|
72 |
} else { |
|
73 |
s->data = now + s->offset; |
|
74 |
while (value) { |
Also available in: Unified diff