2 * QEMU Motorola 680x0 Macintosh Video Card Emulation
3 * Copyright (c) 2012-2018 Laurent Vivier
5 * some parts from QEMU G364 framebuffer Emulator.
6 * Copyright (c) 2007-2011 Herve Poussineau
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
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"
25 #define VIDEO_BASE 0x0
26 #define DAFB_BASE 0x00800000
28 #define MACFB_PAGE_SIZE 4096
29 #define MACFB_VRAM_SIZE (4 * MiB)
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
42 #define DAFB_INTR_VBL 0x4
44 /* Vertical Blank period (60.15Hz) */
45 #define DAFB_INTR_VBL_PERIOD_NS 16625800
48 * Quadra sense codes taken from Apple Technical Note HW26:
49 * "Macintosh Quadra Built-In Video". The sense codes and
50 * extended sense codes have different meanings:
53 * bit 2: SENSE2 (pin 10)
54 * bit 1: SENSE1 (pin 7)
55 * bit 0: SENSE0 (pin 4)
57 * 0 = pin tied to ground
65 * 0 = pins tied together
66 * 1 = pins unconnected
68 * Reads from the sense register appear to be active low, i.e. a 1 indicates
69 * that the pin is tied to ground, a 0 indicates the pin is disconnected.
71 * Writes to the sense register appear to activate pulldowns i.e. a 1 enables
72 * a pulldown on a particular pin.
74 * The MacOS toolbox appears to use a series of reads and writes to first
75 * determine if extended sense is to be used, and then check which pins are
76 * tied together in order to determine the display type.
79 typedef struct MacFbSense
{
85 static 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 },
103 static 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 },
120 typedef void macfb_draw_line_func(MacfbState
*s
, uint8_t *d
, uint32_t addr
,
123 static inline uint8_t macfb_read_byte(MacfbState
*s
, uint32_t addr
)
125 return s
->vram
[addr
& s
->vram_bit_mask
];
129 static void macfb_draw_line1(MacfbState
*s
, uint8_t *d
, uint32_t addr
,
135 for (x
= 0; x
< width
; x
++) {
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];
143 *(uint32_t *)d
= rgb_to_pixel32(r
, g
, b
);
149 static void macfb_draw_line2(MacfbState
*s
, uint8_t *d
, uint32_t addr
,
155 for (x
= 0; x
< width
; x
++) {
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];
163 *(uint32_t *)d
= rgb_to_pixel32(r
, g
, b
);
169 static void macfb_draw_line4(MacfbState
*s
, uint8_t *d
, uint32_t addr
,
175 for (x
= 0; x
< width
; x
++) {
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];
183 *(uint32_t *)d
= rgb_to_pixel32(r
, g
, b
);
189 static void macfb_draw_line8(MacfbState
*s
, uint8_t *d
, uint32_t addr
,
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];
201 *(uint32_t *)d
= rgb_to_pixel32(r
, g
, b
);
207 static void macfb_draw_line16(MacfbState
*s
, uint8_t *d
, uint32_t addr
,
213 for (x
= 0; x
< width
; x
++) {
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;
221 *(uint32_t *)d
= rgb_to_pixel32(r
, g
, b
);
227 static void macfb_draw_line24(MacfbState
*s
, uint8_t *d
, uint32_t addr
,
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);
239 *(uint32_t *)d
= rgb_to_pixel32(r
, g
, b
);
255 static macfb_draw_line_func
* const
256 macfb_draw_line_table
[MACFB_DRAW_LINE_NB
] = {
265 static int macfb_check_dirty(MacfbState
*s
, DirtyBitmapSnapshot
*snap
,
266 ram_addr_t addr
, int len
)
268 return memory_region_snapshot_get_dirty(&s
->mem_vram
, snap
, addr
, len
);
271 static void macfb_draw_graphic(MacfbState
*s
)
273 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
274 DirtyBitmapSnapshot
*snap
= NULL
;
278 int macfb_stride
= s
->mode
->stride
;
279 macfb_draw_line_func
*macfb_draw_line
;
283 v
= MACFB_DRAW_LINE1
;
286 v
= MACFB_DRAW_LINE2
;
289 v
= MACFB_DRAW_LINE4
;
292 v
= MACFB_DRAW_LINE8
;
295 v
= MACFB_DRAW_LINE16
;
298 v
= MACFB_DRAW_LINE24
;
302 macfb_draw_line
= macfb_draw_line_table
[v
];
303 assert(macfb_draw_line
!= NULL
);
305 snap
= memory_region_snapshot_and_clear_dirty(&s
->mem_vram
, 0x0,
306 memory_region_size(&s
->mem_vram
),
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
;
315 data_display
= surface_data(surface
) + y
* surface_stride(surface
);
316 macfb_draw_line(s
, data_display
, page
, s
->width
);
323 dpy_gfx_update(s
->con
, 0, ymin
, s
->width
, y
- ymin
);
330 dpy_gfx_update(s
->con
, 0, ymin
, s
->width
, y
- ymin
);
336 static void macfb_invalidate_display(void *opaque
)
338 MacfbState
*s
= opaque
;
340 memory_region_set_dirty(&s
->mem_vram
, 0, MACFB_VRAM_SIZE
);
343 static uint32_t macfb_sense_read(MacfbState
*s
)
345 MacFbSense
*macfb_sense
;
348 assert(s
->type
< ARRAY_SIZE(macfb_sense_table
));
349 macfb_sense
= &macfb_sense_table
[s
->type
];
350 if (macfb_sense
->sense
== 0x7) {
353 if (!(macfb_sense
->ext_sense
& 1)) {
354 /* Pins 7-4 together */
355 if (~s
->regs
[DAFB_MODE_SENSE
>> 2] & 3) {
356 sense
= (~s
->regs
[DAFB_MODE_SENSE
>> 2] & 7) | 3;
359 if (!(macfb_sense
->ext_sense
& 2)) {
360 /* Pins 10-7 together */
361 if (~s
->regs
[DAFB_MODE_SENSE
>> 2] & 6) {
362 sense
= (~s
->regs
[DAFB_MODE_SENSE
>> 2] & 7) | 6;
365 if (!(macfb_sense
->ext_sense
& 4)) {
366 /* Pins 4-10 together */
367 if (~s
->regs
[DAFB_MODE_SENSE
>> 2] & 5) {
368 sense
= (~s
->regs
[DAFB_MODE_SENSE
>> 2] & 7) | 5;
373 sense
= (~macfb_sense
->sense
& 7) |
374 (~s
->regs
[DAFB_MODE_SENSE
>> 2] & 7);
377 trace_macfb_sense_read(sense
);
381 static void macfb_sense_write(MacfbState
*s
, uint32_t val
)
383 s
->regs
[DAFB_MODE_SENSE
>> 2] = val
;
385 trace_macfb_sense_write(val
);
389 static void macfb_update_mode(MacfbState
*s
)
391 s
->width
= s
->mode
->width
;
392 s
->height
= s
->mode
->height
;
393 s
->depth
= s
->mode
->depth
;
395 trace_macfb_update_mode(s
->width
, s
->height
, s
->depth
);
396 macfb_invalidate_display(s
);
399 static void macfb_mode_write(MacfbState
*s
)
401 MacFbMode
*macfb_mode
;
404 for (i
= 0; i
< ARRAY_SIZE(macfb_mode_table
); i
++) {
405 macfb_mode
= &macfb_mode_table
[i
];
407 if (s
->type
!= macfb_mode
->type
) {
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
);
422 static MacFbMode
*macfb_find_mode(MacfbDisplayType display_type
,
423 uint16_t width
, uint16_t height
,
426 MacFbMode
*macfb_mode
;
429 for (i
= 0; i
< ARRAY_SIZE(macfb_mode_table
); i
++) {
430 macfb_mode
= &macfb_mode_table
[i
];
432 if (display_type
== macfb_mode
->type
&& width
== macfb_mode
->width
&&
433 height
== macfb_mode
->height
&& depth
== macfb_mode
->depth
) {
441 static gchar
*macfb_mode_list(void)
443 GString
*list
= g_string_new("");
444 MacFbMode
*macfb_mode
;
447 for (i
= 0; i
< ARRAY_SIZE(macfb_mode_table
); i
++) {
448 macfb_mode
= &macfb_mode_table
[i
];
450 g_string_append_printf(list
, " %dx%dx%d\n", macfb_mode
->width
,
451 macfb_mode
->height
, macfb_mode
->depth
);
454 return g_string_free(list
, FALSE
);
458 static void macfb_update_display(void *opaque
)
460 MacfbState
*s
= opaque
;
461 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
463 qemu_flush_coalesced_mmio_buffer();
465 if (s
->width
== 0 || s
->height
== 0) {
469 if (s
->width
!= surface_width(surface
) ||
470 s
->height
!= surface_height(surface
)) {
471 qemu_console_resize(s
->con
, s
->width
, s
->height
);
474 macfb_draw_graphic(s
);
477 static void macfb_update_irq(MacfbState
*s
)
479 uint32_t irq_state
= s
->irq_state
& s
->irq_mask
;
482 qemu_irq_raise(s
->irq
);
484 qemu_irq_lower(s
->irq
);
488 static int64_t macfb_next_vbl(void)
490 return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) + DAFB_INTR_VBL_PERIOD_NS
) /
491 DAFB_INTR_VBL_PERIOD_NS
* DAFB_INTR_VBL_PERIOD_NS
;
494 static void macfb_vbl_timer(void *opaque
)
496 MacfbState
*s
= opaque
;
499 s
->irq_state
|= DAFB_INTR_VBL
;
503 next_vbl
= macfb_next_vbl();
504 timer_mod(s
->vbl_timer
, next_vbl
);
507 static void macfb_reset(MacfbState
*s
)
511 s
->palette_current
= 0;
512 for (i
= 0; i
< 256; i
++) {
513 s
->color_palette
[i
* 3] = 255 - i
;
514 s
->color_palette
[i
* 3 + 1] = 255 - i
;
515 s
->color_palette
[i
* 3 + 2] = 255 - i
;
517 memset(s
->vram
, 0, MACFB_VRAM_SIZE
);
518 macfb_invalidate_display(s
);
521 static uint64_t macfb_ctrl_read(void *opaque
,
525 MacfbState
*s
= opaque
;
529 case DAFB_MODE_VADDR1
:
530 case DAFB_MODE_VADDR2
:
531 case DAFB_MODE_CTRL1
:
532 case DAFB_MODE_CTRL2
:
533 val
= s
->regs
[addr
>> 2];
538 case DAFB_MODE_SENSE
:
539 val
= macfb_sense_read(s
);
543 trace_macfb_ctrl_read(addr
, val
, size
);
547 static void macfb_ctrl_write(void *opaque
,
552 MacfbState
*s
= opaque
;
556 case DAFB_MODE_VADDR1
:
557 case DAFB_MODE_VADDR2
:
558 s
->regs
[addr
>> 2] = val
;
560 case DAFB_MODE_CTRL1
... DAFB_MODE_CTRL1
+ 3:
561 case DAFB_MODE_CTRL2
... DAFB_MODE_CTRL2
+ 3:
562 s
->regs
[addr
>> 2] = val
;
567 case DAFB_MODE_SENSE
:
568 macfb_sense_write(s
, val
);
572 if (val
& DAFB_INTR_VBL
) {
573 next_vbl
= macfb_next_vbl();
574 timer_mod(s
->vbl_timer
, next_vbl
);
576 timer_del(s
->vbl_timer
);
579 case DAFB_INTR_CLEAR
:
580 s
->irq_state
&= ~DAFB_INTR_VBL
;
584 s
->palette_current
= 0;
585 s
->irq_state
&= ~DAFB_INTR_VBL
;
589 s
->color_palette
[s
->palette_current
] = val
;
590 s
->palette_current
= (s
->palette_current
+ 1) %
591 ARRAY_SIZE(s
->color_palette
);
592 if (s
->palette_current
% 3) {
593 macfb_invalidate_display(s
);
598 trace_macfb_ctrl_write(addr
, val
, size
);
601 static const MemoryRegionOps macfb_ctrl_ops
= {
602 .read
= macfb_ctrl_read
,
603 .write
= macfb_ctrl_write
,
604 .endianness
= DEVICE_BIG_ENDIAN
,
605 .impl
.min_access_size
= 1,
606 .impl
.max_access_size
= 4,
609 static int macfb_post_load(void *opaque
, int version_id
)
611 macfb_mode_write(opaque
);
615 static const VMStateDescription vmstate_macfb
= {
618 .minimum_version_id
= 1,
619 .minimum_version_id_old
= 1,
620 .post_load
= macfb_post_load
,
621 .fields
= (VMStateField
[]) {
622 VMSTATE_UINT8_ARRAY(color_palette
, MacfbState
, 256 * 3),
623 VMSTATE_UINT32(palette_current
, MacfbState
),
624 VMSTATE_UINT32_ARRAY(regs
, MacfbState
, MACFB_NUM_REGS
),
625 VMSTATE_END_OF_LIST()
629 static const GraphicHwOps macfb_ops
= {
630 .invalidate
= macfb_invalidate_display
,
631 .gfx_update
= macfb_update_display
,
634 static bool macfb_common_realize(DeviceState
*dev
, MacfbState
*s
, Error
**errp
)
636 DisplaySurface
*surface
;
638 s
->mode
= macfb_find_mode(s
->type
, s
->width
, s
->height
, s
->depth
);
641 error_setg(errp
, "unknown display mode: width %d, height %d, depth %d",
642 s
->width
, s
->height
, s
->depth
);
643 list
= macfb_mode_list();
644 error_append_hint(errp
, "Available modes:\n%s", list
);
650 s
->con
= graphic_console_init(dev
, 0, &macfb_ops
, s
);
651 surface
= qemu_console_surface(s
->con
);
653 if (surface_bits_per_pixel(surface
) != 32) {
654 error_setg(errp
, "unknown host depth %d",
655 surface_bits_per_pixel(surface
));
659 memory_region_init_io(&s
->mem_ctrl
, OBJECT(dev
), &macfb_ctrl_ops
, s
,
660 "macfb-ctrl", 0x1000);
662 memory_region_init_ram(&s
->mem_vram
, OBJECT(dev
), "macfb-vram",
663 MACFB_VRAM_SIZE
, &error_abort
);
664 s
->vram
= memory_region_get_ram_ptr(&s
->mem_vram
);
665 s
->vram_bit_mask
= MACFB_VRAM_SIZE
- 1;
666 memory_region_set_coalescing(&s
->mem_vram
);
668 s
->vbl_timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, macfb_vbl_timer
, s
);
669 macfb_update_mode(s
);
673 static void macfb_sysbus_realize(DeviceState
*dev
, Error
**errp
)
675 MacfbSysBusState
*s
= MACFB(dev
);
676 MacfbState
*ms
= &s
->macfb
;
678 if (!macfb_common_realize(dev
, ms
, errp
)) {
682 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &ms
->mem_ctrl
);
683 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &ms
->mem_vram
);
685 qdev_init_gpio_out(dev
, &ms
->irq
, 1);
688 static void macfb_nubus_set_irq(void *opaque
, int n
, int level
)
690 MacfbNubusState
*s
= NUBUS_MACFB(opaque
);
691 NubusDevice
*nd
= NUBUS_DEVICE(s
);
693 nubus_set_irq(nd
, level
);
696 static void macfb_nubus_realize(DeviceState
*dev
, Error
**errp
)
698 NubusDevice
*nd
= NUBUS_DEVICE(dev
);
699 MacfbNubusState
*s
= NUBUS_MACFB(dev
);
700 MacfbNubusDeviceClass
*ndc
= NUBUS_MACFB_GET_CLASS(dev
);
701 MacfbState
*ms
= &s
->macfb
;
703 ndc
->parent_realize(dev
, errp
);
708 if (!macfb_common_realize(dev
, ms
, errp
)) {
712 memory_region_add_subregion(&nd
->slot_mem
, DAFB_BASE
, &ms
->mem_ctrl
);
713 memory_region_add_subregion(&nd
->slot_mem
, VIDEO_BASE
, &ms
->mem_vram
);
715 ms
->irq
= qemu_allocate_irq(macfb_nubus_set_irq
, s
, 0);
718 static void macfb_nubus_unrealize(DeviceState
*dev
)
720 MacfbNubusState
*s
= NUBUS_MACFB(dev
);
721 MacfbNubusDeviceClass
*ndc
= NUBUS_MACFB_GET_CLASS(dev
);
722 MacfbState
*ms
= &s
->macfb
;
724 ndc
->parent_unrealize(dev
);
726 qemu_free_irq(ms
->irq
);
729 static void macfb_sysbus_reset(DeviceState
*d
)
731 MacfbSysBusState
*s
= MACFB(d
);
732 macfb_reset(&s
->macfb
);
735 static void macfb_nubus_reset(DeviceState
*d
)
737 MacfbNubusState
*s
= NUBUS_MACFB(d
);
738 macfb_reset(&s
->macfb
);
741 static Property macfb_sysbus_properties
[] = {
742 DEFINE_PROP_UINT32("width", MacfbSysBusState
, macfb
.width
, 640),
743 DEFINE_PROP_UINT32("height", MacfbSysBusState
, macfb
.height
, 480),
744 DEFINE_PROP_UINT8("depth", MacfbSysBusState
, macfb
.depth
, 8),
745 DEFINE_PROP_UINT8("display", MacfbSysBusState
, macfb
.type
,
747 DEFINE_PROP_END_OF_LIST(),
750 static Property macfb_nubus_properties
[] = {
751 DEFINE_PROP_UINT32("width", MacfbNubusState
, macfb
.width
, 640),
752 DEFINE_PROP_UINT32("height", MacfbNubusState
, macfb
.height
, 480),
753 DEFINE_PROP_UINT8("depth", MacfbNubusState
, macfb
.depth
, 8),
754 DEFINE_PROP_UINT8("display", MacfbNubusState
, macfb
.type
,
756 DEFINE_PROP_END_OF_LIST(),
759 static void macfb_sysbus_class_init(ObjectClass
*klass
, void *data
)
761 DeviceClass
*dc
= DEVICE_CLASS(klass
);
763 dc
->realize
= macfb_sysbus_realize
;
764 dc
->desc
= "SysBus Macintosh framebuffer";
765 dc
->reset
= macfb_sysbus_reset
;
766 dc
->vmsd
= &vmstate_macfb
;
767 device_class_set_props(dc
, macfb_sysbus_properties
);
770 static void macfb_nubus_class_init(ObjectClass
*klass
, void *data
)
772 DeviceClass
*dc
= DEVICE_CLASS(klass
);
773 MacfbNubusDeviceClass
*ndc
= NUBUS_MACFB_CLASS(klass
);
775 device_class_set_parent_realize(dc
, macfb_nubus_realize
,
776 &ndc
->parent_realize
);
777 device_class_set_parent_unrealize(dc
, macfb_nubus_unrealize
,
778 &ndc
->parent_unrealize
);
779 dc
->desc
= "Nubus Macintosh framebuffer";
780 dc
->reset
= macfb_nubus_reset
;
781 dc
->vmsd
= &vmstate_macfb
;
782 set_bit(DEVICE_CATEGORY_DISPLAY
, dc
->categories
);
783 device_class_set_props(dc
, macfb_nubus_properties
);
786 static TypeInfo macfb_sysbus_info
= {
788 .parent
= TYPE_SYS_BUS_DEVICE
,
789 .instance_size
= sizeof(MacfbSysBusState
),
790 .class_init
= macfb_sysbus_class_init
,
793 static TypeInfo macfb_nubus_info
= {
794 .name
= TYPE_NUBUS_MACFB
,
795 .parent
= TYPE_NUBUS_DEVICE
,
796 .instance_size
= sizeof(MacfbNubusState
),
797 .class_init
= macfb_nubus_class_init
,
798 .class_size
= sizeof(MacfbNubusDeviceClass
),
801 static void macfb_register_types(void)
803 type_register_static(&macfb_sysbus_info
);
804 type_register_static(&macfb_nubus_info
);
807 type_init(macfb_register_types
)