1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14#include "qemu/units.h"
15#include "hw/sysbus.h"
16#include "ui/console.h"
17#include "ui/pixel_ops.h"
18#include "hw/nubus/nubus.h"
19#include "hw/display/macfb.h"
20#include "qapi/error.h"
21#include "hw/qdev-properties.h"
22#include "migration/vmstate.h"
23#include "trace.h"
24
25#define VIDEO_BASE 0x0
26#define DAFB_BASE 0x00800000
27
28#define MACFB_PAGE_SIZE 4096
29#define MACFB_VRAM_SIZE (4 * MiB)
30
31#define DAFB_MODE_VADDR1 0x0
32#define DAFB_MODE_VADDR2 0x4
33#define DAFB_MODE_CTRL1 0x8
34#define DAFB_MODE_CTRL2 0xc
35#define DAFB_MODE_SENSE 0x1c
36#define DAFB_INTR_MASK 0x104
37#define DAFB_INTR_STAT 0x108
38#define DAFB_INTR_CLEAR 0x10c
39#define DAFB_RESET 0x200
40#define DAFB_LUT 0x213
41
42#define DAFB_INTR_VBL 0x4
43
44
45#define DAFB_INTR_VBL_PERIOD_NS 16625800
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79typedef struct MacFbSense {
80 uint8_t type;
81 uint8_t sense;
82 uint8_t ext_sense;
83} MacFbSense;
84
85static MacFbSense macfb_sense_table[] = {
86 { MACFB_DISPLAY_APPLE_21_COLOR, 0x0, 0 },
87 { MACFB_DISPLAY_APPLE_PORTRAIT, 0x1, 0 },
88 { MACFB_DISPLAY_APPLE_12_RGB, 0x2, 0 },
89 { MACFB_DISPLAY_APPLE_2PAGE_MONO, 0x3, 0 },
90 { MACFB_DISPLAY_NTSC_UNDERSCAN, 0x4, 0 },
91 { MACFB_DISPLAY_NTSC_OVERSCAN, 0x4, 0 },
92 { MACFB_DISPLAY_APPLE_12_MONO, 0x6, 0 },
93 { MACFB_DISPLAY_APPLE_13_RGB, 0x6, 0 },
94 { MACFB_DISPLAY_16_COLOR, 0x7, 0x3 },
95 { MACFB_DISPLAY_PAL1_UNDERSCAN, 0x7, 0x0 },
96 { MACFB_DISPLAY_PAL1_OVERSCAN, 0x7, 0x0 },
97 { MACFB_DISPLAY_PAL2_UNDERSCAN, 0x7, 0x6 },
98 { MACFB_DISPLAY_PAL2_OVERSCAN, 0x7, 0x6 },
99 { MACFB_DISPLAY_VGA, 0x7, 0x5 },
100 { MACFB_DISPLAY_SVGA, 0x7, 0x5 },
101};
102
103static MacFbMode macfb_mode_table[] = {
104 { MACFB_DISPLAY_VGA, 1, 0x100, 0x71e, 640, 480, 0x400, 0x1000 },
105 { MACFB_DISPLAY_VGA, 2, 0x100, 0x70e, 640, 480, 0x400, 0x1000 },
106 { MACFB_DISPLAY_VGA, 4, 0x100, 0x706, 640, 480, 0x400, 0x1000 },
107 { MACFB_DISPLAY_VGA, 8, 0x100, 0x702, 640, 480, 0x400, 0x1000 },
108 { MACFB_DISPLAY_VGA, 24, 0x100, 0x7ff, 640, 480, 0x1000, 0x1000 },
109 { MACFB_DISPLAY_VGA, 1, 0xd0 , 0x70e, 800, 600, 0x340, 0xe00 },
110 { MACFB_DISPLAY_VGA, 2, 0xd0 , 0x706, 800, 600, 0x340, 0xe00 },
111 { MACFB_DISPLAY_VGA, 4, 0xd0 , 0x702, 800, 600, 0x340, 0xe00 },
112 { MACFB_DISPLAY_VGA, 8, 0xd0, 0x700, 800, 600, 0x340, 0xe00 },
113 { MACFB_DISPLAY_VGA, 24, 0x340, 0x100, 800, 600, 0xd00, 0xe00 },
114 { MACFB_DISPLAY_APPLE_21_COLOR, 1, 0x90, 0x506, 1152, 870, 0x240, 0x80 },
115 { MACFB_DISPLAY_APPLE_21_COLOR, 2, 0x90, 0x502, 1152, 870, 0x240, 0x80 },
116 { MACFB_DISPLAY_APPLE_21_COLOR, 4, 0x90, 0x500, 1152, 870, 0x240, 0x80 },
117 { MACFB_DISPLAY_APPLE_21_COLOR, 8, 0x120, 0x5ff, 1152, 870, 0x480, 0x80 },
118};
119
120typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr,
121 int width);
122
123static inline uint8_t macfb_read_byte(MacfbState *s, uint32_t addr)
124{
125 return s->vram[addr & s->vram_bit_mask];
126}
127
128
129static void macfb_draw_line1(MacfbState *s, uint8_t *d, uint32_t addr,
130 int width)
131{
132 uint8_t r, g, b;
133 int x;
134
135 for (x = 0; x < width; x++) {
136 int bit = x & 7;
137 int idx = (macfb_read_byte(s, addr) >> (7 - bit)) & 1;
138 r = s->color_palette[idx * 3];
139 g = s->color_palette[idx * 3 + 1];
140 b = s->color_palette[idx * 3 + 2];
141 addr += (bit == 7);
142
143 *(uint32_t *)d = rgb_to_pixel32(r, g, b);
144 d += 4;
145 }
146}
147
148
149static void macfb_draw_line2(MacfbState *s, uint8_t *d, uint32_t addr,
150 int width)
151{
152 uint8_t r, g, b;
153 int x;
154
155 for (x = 0; x < width; x++) {
156 int bit = (x & 3);
157 int idx = (macfb_read_byte(s, addr) >> ((3 - bit) << 1)) & 3;
158 r = s->color_palette[idx * 3];
159 g = s->color_palette[idx * 3 + 1];
160 b = s->color_palette[idx * 3 + 2];
161 addr += (bit == 3);
162
163 *(uint32_t *)d = rgb_to_pixel32(r, g, b);
164 d += 4;
165 }
166}
167
168
169static void macfb_draw_line4(MacfbState *s, uint8_t *d, uint32_t addr,
170 int width)
171{
172 uint8_t r, g, b;
173 int x;
174
175 for (x = 0; x < width; x++) {
176 int bit = x & 1;
177 int idx = (macfb_read_byte(s, addr) >> ((1 - bit) << 2)) & 15;
178 r = s->color_palette[idx * 3];
179 g = s->color_palette[idx * 3 + 1];
180 b = s->color_palette[idx * 3 + 2];
181 addr += (bit == 1);
182
183 *(uint32_t *)d = rgb_to_pixel32(r, g, b);
184 d += 4;
185 }
186}
187
188
189static void macfb_draw_line8(MacfbState *s, uint8_t *d, uint32_t addr,
190 int width)
191{
192 uint8_t r, g, b;
193 int x;
194
195 for (x = 0; x < width; x++) {
196 r = s->color_palette[macfb_read_byte(s, addr) * 3];
197 g = s->color_palette[macfb_read_byte(s, addr) * 3 + 1];
198 b = s->color_palette[macfb_read_byte(s, addr) * 3 + 2];
199 addr++;
200
201 *(uint32_t *)d = rgb_to_pixel32(r, g, b);
202 d += 4;
203 }
204}
205
206
207static void macfb_draw_line16(MacfbState *s, uint8_t *d, uint32_t addr,
208 int width)
209{
210 uint8_t r, g, b;
211 int x;
212
213 for (x = 0; x < width; x++) {
214 uint16_t pixel;
215 pixel = (macfb_read_byte(s, addr) << 8) | macfb_read_byte(s, addr + 1);
216 r = ((pixel >> 10) & 0x1f) << 3;
217 g = ((pixel >> 5) & 0x1f) << 3;
218 b = (pixel & 0x1f) << 3;
219 addr += 2;
220
221 *(uint32_t *)d = rgb_to_pixel32(r, g, b);
222 d += 4;
223 }
224}
225
226
227static void macfb_draw_line24(MacfbState *s, uint8_t *d, uint32_t addr,
228 int width)
229{
230 uint8_t r, g, b;
231 int x;
232
233 for (x = 0; x < width; x++) {
234 r = macfb_read_byte(s, addr + 1);
235 g = macfb_read_byte(s, addr + 2);
236 b = macfb_read_byte(s, addr + 3);
237 addr += 4;
238
239 *(uint32_t *)d = rgb_to_pixel32(r, g, b);
240 d += 4;
241 }
242}
243
244
245enum {
246 MACFB_DRAW_LINE1,
247 MACFB_DRAW_LINE2,
248 MACFB_DRAW_LINE4,
249 MACFB_DRAW_LINE8,
250 MACFB_DRAW_LINE16,
251 MACFB_DRAW_LINE24,
252 MACFB_DRAW_LINE_NB,
253};
254
255static macfb_draw_line_func * const
256 macfb_draw_line_table[MACFB_DRAW_LINE_NB] = {
257 macfb_draw_line1,
258 macfb_draw_line2,
259 macfb_draw_line4,
260 macfb_draw_line8,
261 macfb_draw_line16,
262 macfb_draw_line24,
263};
264
265static int macfb_check_dirty(MacfbState *s, DirtyBitmapSnapshot *snap,
266 ram_addr_t addr, int len)
267{
268 return memory_region_snapshot_get_dirty(&s->mem_vram, snap, addr, len);
269}
270
271static void macfb_draw_graphic(MacfbState *s)
272{
273 DisplaySurface *surface = qemu_console_surface(s->con);
274 DirtyBitmapSnapshot *snap = NULL;
275 ram_addr_t page;
276 uint32_t v = 0;
277 int y, ymin;
278 int macfb_stride = s->mode->stride;
279 macfb_draw_line_func *macfb_draw_line;
280
281 switch (s->depth) {
282 case 1:
283 v = MACFB_DRAW_LINE1;
284 break;
285 case 2:
286 v = MACFB_DRAW_LINE2;
287 break;
288 case 4:
289 v = MACFB_DRAW_LINE4;
290 break;
291 case 8:
292 v = MACFB_DRAW_LINE8;
293 break;
294 case 16:
295 v = MACFB_DRAW_LINE16;
296 break;
297 case 24:
298 v = MACFB_DRAW_LINE24;
299 break;
300 }
301
302 macfb_draw_line = macfb_draw_line_table[v];
303 assert(macfb_draw_line != NULL);
304
305 snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0x0,
306 memory_region_size(&s->mem_vram),
307 DIRTY_MEMORY_VGA);
308
309 ymin = -1;
310 page = s->mode->offset;
311 for (y = 0; y < s->height; y++, page += macfb_stride) {
312 if (macfb_check_dirty(s, snap, page, macfb_stride)) {
313 uint8_t *data_display;
314
315 data_display = surface_data(surface) + y * surface_stride(surface);
316 macfb_draw_line(s, data_display, page, s->width);
317
318 if (ymin < 0) {
319 ymin = y;
320 }
321 } else {
322 if (ymin >= 0) {
323 dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
324 ymin = -1;
325 }
326 }
327 }
328
329 if (ymin >= 0) {
330 dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
331 }
332
333 g_free(snap);
334}
335
336static void macfb_invalidate_display(void *opaque)
337{
338 MacfbState *s = opaque;
339
340 memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE);
341}
342
343static uint32_t macfb_sense_read(MacfbState *s)
344{
345 MacFbSense *macfb_sense;
346 uint8_t sense;
347
348 assert(s->type < ARRAY_SIZE(macfb_sense_table));
349 macfb_sense = &macfb_sense_table[s->type];
350 if (macfb_sense->sense == 0x7) {
351
352 sense = 0;
353 if (!(macfb_sense->ext_sense & 1)) {
354
355 if (~s->regs[DAFB_MODE_SENSE >> 2] & 3) {
356 sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 3;
357 }
358 }
359 if (!(macfb_sense->ext_sense & 2)) {
360
361 if (~s->regs[DAFB_MODE_SENSE >> 2] & 6) {
362 sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 6;
363 }
364 }
365 if (!(macfb_sense->ext_sense & 4)) {
366
367 if (~s->regs[DAFB_MODE_SENSE >> 2] & 5) {
368 sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 5;
369 }
370 }
371 } else {
372
373 sense = (~macfb_sense->sense & 7) |
374 (~s->regs[DAFB_MODE_SENSE >> 2] & 7);
375 }
376
377 trace_macfb_sense_read(sense);
378 return sense;
379}
380
381static void macfb_sense_write(MacfbState *s, uint32_t val)
382{
383 s->regs[DAFB_MODE_SENSE >> 2] = val;
384
385 trace_macfb_sense_write(val);
386 return;
387}
388
389static void macfb_update_mode(MacfbState *s)
390{
391 s->width = s->mode->width;
392 s->height = s->mode->height;
393 s->depth = s->mode->depth;
394
395 trace_macfb_update_mode(s->width, s->height, s->depth);
396 macfb_invalidate_display(s);
397}
398
399static void macfb_mode_write(MacfbState *s)
400{
401 MacFbMode *macfb_mode;
402 int i;
403
404 for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
405 macfb_mode = &macfb_mode_table[i];
406
407 if (s->type != macfb_mode->type) {
408 continue;
409 }
410
411 if ((s->regs[DAFB_MODE_CTRL1 >> 2] & 0xff) ==
412 (macfb_mode->mode_ctrl1 & 0xff) &&
413 (s->regs[DAFB_MODE_CTRL2 >> 2] & 0xff) ==
414 (macfb_mode->mode_ctrl2 & 0xff)) {
415 s->mode = macfb_mode;
416 macfb_update_mode(s);
417 break;
418 }
419 }
420}
421
422static MacFbMode *macfb_find_mode(MacfbDisplayType display_type,
423 uint16_t width, uint16_t height,
424 uint8_t depth)
425{
426 MacFbMode *macfb_mode;
427 int i;
428
429 for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
430 macfb_mode = &macfb_mode_table[i];
431
432 if (display_type == macfb_mode->type && width == macfb_mode->width &&
433 height == macfb_mode->height && depth == macfb_mode->depth) {
434 return macfb_mode;
435 }
436 }
437
438 return NULL;
439}
440
441static gchar *macfb_mode_list(void)
442{
443 GString *list = g_string_new("");
444 MacFbMode *macfb_mode;
445 int i;
446
447 for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
448 macfb_mode = &macfb_mode_table[i];
449
450 g_string_append_printf(list, " %dx%dx%d\n", macfb_mode->width,
451 macfb_mode->height, macfb_mode->depth);
452 }
453
454 return g_string_free(list, FALSE);
455}
456
457
458static void macfb_update_display(void *opaque)
459{
460 MacfbState *s = opaque;
461 DisplaySurface *surface = qemu_console_surface(s->con);
462
463 qemu_flush_coalesced_mmio_buffer();
464
465 if (s->width == 0 || s->height == 0) {
466 return;
467 }
468
469 if (s->width != surface_width(surface) ||
470 s->height != surface_height(surface)) {
471 qemu_console_resize(s->con, s->width, s->height);
472 }
473
474 macfb_draw_graphic(s);
475}
476
477static void macfb_update_irq(MacfbState *s)
478{
479 uint32_t irq_state = s->regs[DAFB_INTR_STAT >> 2] &
480 s->regs[DAFB_INTR_MASK >> 2];
481
482 if (irq_state) {
483 qemu_irq_raise(s->irq);
484 } else {
485 qemu_irq_lower(s->irq);
486 }
487}
488
489static int64_t macfb_next_vbl(void)
490{
491 return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + DAFB_INTR_VBL_PERIOD_NS) /
492 DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS;
493}
494
495static void macfb_vbl_timer(void *opaque)
496{
497 MacfbState *s = opaque;
498 int64_t next_vbl;
499
500 s->regs[DAFB_INTR_STAT >> 2] |= DAFB_INTR_VBL;
501 macfb_update_irq(s);
502
503
504 next_vbl = macfb_next_vbl();
505 timer_mod(s->vbl_timer, next_vbl);
506}
507
508static void macfb_reset(MacfbState *s)
509{
510 int i;
511
512 s->palette_current = 0;
513 for (i = 0; i < 256; i++) {
514 s->color_palette[i * 3] = 255 - i;
515 s->color_palette[i * 3 + 1] = 255 - i;
516 s->color_palette[i * 3 + 2] = 255 - i;
517 }
518 memset(s->vram, 0, MACFB_VRAM_SIZE);
519 macfb_invalidate_display(s);
520}
521
522static uint64_t macfb_ctrl_read(void *opaque,
523 hwaddr addr,
524 unsigned int size)
525{
526 MacfbState *s = opaque;
527 uint64_t val = 0;
528
529 switch (addr) {
530 case DAFB_MODE_VADDR1:
531 case DAFB_MODE_VADDR2:
532 case DAFB_MODE_CTRL1:
533 case DAFB_MODE_CTRL2:
534 case DAFB_INTR_STAT:
535 val = s->regs[addr >> 2];
536 break;
537 case DAFB_MODE_SENSE:
538 val = macfb_sense_read(s);
539 break;
540 default:
541 if (addr < MACFB_CTRL_TOPADDR) {
542 val = s->regs[addr >> 2];
543 }
544 }
545
546 trace_macfb_ctrl_read(addr, val, size);
547 return val;
548}
549
550static void macfb_ctrl_write(void *opaque,
551 hwaddr addr,
552 uint64_t val,
553 unsigned int size)
554{
555 MacfbState *s = opaque;
556 int64_t next_vbl;
557
558 switch (addr) {
559 case DAFB_MODE_VADDR1:
560 case DAFB_MODE_VADDR2:
561 s->regs[addr >> 2] = val;
562 break;
563 case DAFB_MODE_CTRL1 ... DAFB_MODE_CTRL1 + 3:
564 case DAFB_MODE_CTRL2 ... DAFB_MODE_CTRL2 + 3:
565 s->regs[addr >> 2] = val;
566 if (val) {
567 macfb_mode_write(s);
568 }
569 break;
570 case DAFB_MODE_SENSE:
571 macfb_sense_write(s, val);
572 break;
573 case DAFB_INTR_MASK:
574 s->regs[addr >> 2] = val;
575 if (val & DAFB_INTR_VBL) {
576 next_vbl = macfb_next_vbl();
577 timer_mod(s->vbl_timer, next_vbl);
578 } else {
579 timer_del(s->vbl_timer);
580 }
581 break;
582 case DAFB_INTR_CLEAR:
583 s->regs[DAFB_INTR_STAT >> 2] &= ~DAFB_INTR_VBL;
584 macfb_update_irq(s);
585 break;
586 case DAFB_RESET:
587 s->palette_current = 0;
588 s->regs[DAFB_INTR_STAT >> 2] &= ~DAFB_INTR_VBL;
589 macfb_update_irq(s);
590 break;
591 case DAFB_LUT:
592 s->color_palette[s->palette_current] = val;
593 s->palette_current = (s->palette_current + 1) %
594 ARRAY_SIZE(s->color_palette);
595 if (s->palette_current % 3) {
596 macfb_invalidate_display(s);
597 }
598 break;
599 default:
600 if (addr < MACFB_CTRL_TOPADDR) {
601 s->regs[addr >> 2] = val;
602 }
603 }
604
605 trace_macfb_ctrl_write(addr, val, size);
606}
607
608static const MemoryRegionOps macfb_ctrl_ops = {
609 .read = macfb_ctrl_read,
610 .write = macfb_ctrl_write,
611 .endianness = DEVICE_BIG_ENDIAN,
612 .impl.min_access_size = 1,
613 .impl.max_access_size = 4,
614};
615
616static int macfb_post_load(void *opaque, int version_id)
617{
618 macfb_mode_write(opaque);
619 return 0;
620}
621
622static const VMStateDescription vmstate_macfb = {
623 .name = "macfb",
624 .version_id = 1,
625 .minimum_version_id = 1,
626 .post_load = macfb_post_load,
627 .fields = (VMStateField[]) {
628 VMSTATE_UINT8(type, MacfbState),
629 VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
630 VMSTATE_UINT32(palette_current, MacfbState),
631 VMSTATE_UINT32_ARRAY(regs, MacfbState, MACFB_NUM_REGS),
632 VMSTATE_TIMER_PTR(vbl_timer, MacfbState),
633 VMSTATE_END_OF_LIST()
634 }
635};
636
637static const GraphicHwOps macfb_ops = {
638 .invalidate = macfb_invalidate_display,
639 .gfx_update = macfb_update_display,
640};
641
642static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
643{
644 DisplaySurface *surface;
645
646 s->mode = macfb_find_mode(s->type, s->width, s->height, s->depth);
647 if (!s->mode) {
648 gchar *list;
649 error_setg(errp, "unknown display mode: width %d, height %d, depth %d",
650 s->width, s->height, s->depth);
651 list = macfb_mode_list();
652 error_append_hint(errp, "Available modes:\n%s", list);
653 g_free(list);
654
655 return false;
656 }
657
658
659
660
661
662
663 s->regs[DAFB_MODE_CTRL1 >> 2] = s->mode->mode_ctrl1;
664 s->regs[DAFB_MODE_CTRL2 >> 2] = s->mode->mode_ctrl2;
665
666 s->con = graphic_console_init(dev, 0, &macfb_ops, s);
667 surface = qemu_console_surface(s->con);
668
669 if (surface_bits_per_pixel(surface) != 32) {
670 error_setg(errp, "unknown host depth %d",
671 surface_bits_per_pixel(surface));
672 return false;
673 }
674
675 memory_region_init_io(&s->mem_ctrl, OBJECT(dev), &macfb_ctrl_ops, s,
676 "macfb-ctrl", 0x1000);
677
678 memory_region_init_ram(&s->mem_vram, OBJECT(dev), "macfb-vram",
679 MACFB_VRAM_SIZE, &error_abort);
680 memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA);
681 s->vram = memory_region_get_ram_ptr(&s->mem_vram);
682 s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
683
684 s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s);
685 macfb_update_mode(s);
686 return true;
687}
688
689static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
690{
691 MacfbSysBusState *s = MACFB(dev);
692 MacfbState *ms = &s->macfb;
693
694 if (!macfb_common_realize(dev, ms, errp)) {
695 return;
696 }
697
698 sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl);
699 sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
700
701 qdev_init_gpio_out(dev, &ms->irq, 1);
702}
703
704static void macfb_nubus_set_irq(void *opaque, int n, int level)
705{
706 MacfbNubusState *s = NUBUS_MACFB(opaque);
707 NubusDevice *nd = NUBUS_DEVICE(s);
708
709 nubus_set_irq(nd, level);
710}
711
712static void macfb_nubus_realize(DeviceState *dev, Error **errp)
713{
714 NubusDevice *nd = NUBUS_DEVICE(dev);
715 MacfbNubusState *s = NUBUS_MACFB(dev);
716 MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev);
717 MacfbState *ms = &s->macfb;
718
719 ndc->parent_realize(dev, errp);
720 if (*errp) {
721 return;
722 }
723
724 if (!macfb_common_realize(dev, ms, errp)) {
725 return;
726 }
727
728 memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
729 memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
730
731 ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0);
732}
733
734static void macfb_nubus_unrealize(DeviceState *dev)
735{
736 MacfbNubusState *s = NUBUS_MACFB(dev);
737 MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev);
738 MacfbState *ms = &s->macfb;
739
740 ndc->parent_unrealize(dev);
741
742 qemu_free_irq(ms->irq);
743}
744
745static void macfb_sysbus_reset(DeviceState *d)
746{
747 MacfbSysBusState *s = MACFB(d);
748 macfb_reset(&s->macfb);
749}
750
751static void macfb_nubus_reset(DeviceState *d)
752{
753 MacfbNubusState *s = NUBUS_MACFB(d);
754 macfb_reset(&s->macfb);
755}
756
757static Property macfb_sysbus_properties[] = {
758 DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640),
759 DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480),
760 DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8),
761 DEFINE_PROP_UINT8("display", MacfbSysBusState, macfb.type,
762 MACFB_DISPLAY_VGA),
763 DEFINE_PROP_END_OF_LIST(),
764};
765
766static const VMStateDescription vmstate_macfb_sysbus = {
767 .name = "macfb-sysbus",
768 .version_id = 1,
769 .minimum_version_id = 1,
770 .fields = (VMStateField[]) {
771 VMSTATE_STRUCT(macfb, MacfbSysBusState, 1, vmstate_macfb, MacfbState),
772 VMSTATE_END_OF_LIST()
773 }
774};
775
776static Property macfb_nubus_properties[] = {
777 DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640),
778 DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480),
779 DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8),
780 DEFINE_PROP_UINT8("display", MacfbNubusState, macfb.type,
781 MACFB_DISPLAY_VGA),
782 DEFINE_PROP_END_OF_LIST(),
783};
784
785static const VMStateDescription vmstate_macfb_nubus = {
786 .name = "macfb-nubus",
787 .version_id = 1,
788 .minimum_version_id = 1,
789 .fields = (VMStateField[]) {
790 VMSTATE_STRUCT(macfb, MacfbNubusState, 1, vmstate_macfb, MacfbState),
791 VMSTATE_END_OF_LIST()
792 }
793};
794
795static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
796{
797 DeviceClass *dc = DEVICE_CLASS(klass);
798
799 dc->realize = macfb_sysbus_realize;
800 dc->desc = "SysBus Macintosh framebuffer";
801 dc->reset = macfb_sysbus_reset;
802 dc->vmsd = &vmstate_macfb_sysbus;
803 device_class_set_props(dc, macfb_sysbus_properties);
804}
805
806static void macfb_nubus_class_init(ObjectClass *klass, void *data)
807{
808 DeviceClass *dc = DEVICE_CLASS(klass);
809 MacfbNubusDeviceClass *ndc = NUBUS_MACFB_CLASS(klass);
810
811 device_class_set_parent_realize(dc, macfb_nubus_realize,
812 &ndc->parent_realize);
813 device_class_set_parent_unrealize(dc, macfb_nubus_unrealize,
814 &ndc->parent_unrealize);
815 dc->desc = "Nubus Macintosh framebuffer";
816 dc->reset = macfb_nubus_reset;
817 dc->vmsd = &vmstate_macfb_nubus;
818 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
819 device_class_set_props(dc, macfb_nubus_properties);
820}
821
822static const TypeInfo macfb_sysbus_info = {
823 .name = TYPE_MACFB,
824 .parent = TYPE_SYS_BUS_DEVICE,
825 .instance_size = sizeof(MacfbSysBusState),
826 .class_init = macfb_sysbus_class_init,
827};
828
829static const TypeInfo macfb_nubus_info = {
830 .name = TYPE_NUBUS_MACFB,
831 .parent = TYPE_NUBUS_DEVICE,
832 .instance_size = sizeof(MacfbNubusState),
833 .class_init = macfb_nubus_class_init,
834 .class_size = sizeof(MacfbNubusDeviceClass),
835};
836
837static void macfb_register_types(void)
838{
839 type_register_static(&macfb_sysbus_info);
840 type_register_static(&macfb_nubus_info);
841}
842
843type_init(macfb_register_types)
844