xref: /openbmc/qemu/hw/display/macfb.c (revision 57eeaf44ce6964e6e86275318f5fc35610c1dc68)
1 /*
2  * QEMU Motorola 680x0 Macintosh Video Card Emulation
3  *                 Copyright (c) 2012-2018 Laurent Vivier
4  *
5  * some parts from QEMU G364 framebuffer Emulator.
6  *                 Copyright (c) 2007-2011 Herve Poussineau
7  *
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.
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_RESET          0x200
37 #define DAFB_LUT            0x213
38 
39 
40 /*
41  * Quadra sense codes taken from Apple Technical Note HW26:
42  * "Macintosh Quadra Built-In Video". The sense codes and
43  * extended sense codes have different meanings:
44  *
45  * Sense:
46  *    bit 2: SENSE2 (pin 10)
47  *    bit 1: SENSE1 (pin 7)
48  *    bit 0: SENSE0 (pin 4)
49  *
50  * 0 = pin tied to ground
51  * 1 = pin unconnected
52  *
53  * Extended Sense:
54  *    bit 2: pins 4-10
55  *    bit 1: pins 10-7
56  *    bit 0: pins 7-4
57  *
58  * 0 = pins tied together
59  * 1 = pins unconnected
60  *
61  * Reads from the sense register appear to be active low, i.e. a 1 indicates
62  * that the pin is tied to ground, a 0 indicates the pin is disconnected.
63  *
64  * Writes to the sense register appear to activate pulldowns i.e. a 1 enables
65  * a pulldown on a particular pin.
66  *
67  * The MacOS toolbox appears to use a series of reads and writes to first
68  * determine if extended sense is to be used, and then check which pins are
69  * tied together in order to determine the display type.
70  */
71 
72 typedef struct MacFbSense {
73     uint8_t type;
74     uint8_t sense;
75     uint8_t ext_sense;
76 } MacFbSense;
77 
78 static MacFbSense macfb_sense_table[] = {
79     { MACFB_DISPLAY_APPLE_21_COLOR, 0x0, 0 },
80     { MACFB_DISPLAY_APPLE_PORTRAIT, 0x1, 0 },
81     { MACFB_DISPLAY_APPLE_12_RGB, 0x2, 0 },
82     { MACFB_DISPLAY_APPLE_2PAGE_MONO, 0x3, 0 },
83     { MACFB_DISPLAY_NTSC_UNDERSCAN, 0x4, 0 },
84     { MACFB_DISPLAY_NTSC_OVERSCAN, 0x4, 0 },
85     { MACFB_DISPLAY_APPLE_12_MONO, 0x6, 0 },
86     { MACFB_DISPLAY_APPLE_13_RGB, 0x6, 0 },
87     { MACFB_DISPLAY_16_COLOR, 0x7, 0x3 },
88     { MACFB_DISPLAY_PAL1_UNDERSCAN, 0x7, 0x0 },
89     { MACFB_DISPLAY_PAL1_OVERSCAN, 0x7, 0x0 },
90     { MACFB_DISPLAY_PAL2_UNDERSCAN, 0x7, 0x6 },
91     { MACFB_DISPLAY_PAL2_OVERSCAN, 0x7, 0x6 },
92     { MACFB_DISPLAY_VGA, 0x7, 0x5 },
93     { MACFB_DISPLAY_SVGA, 0x7, 0x5 },
94 };
95 
96 static MacFbMode macfb_mode_table[] = {
97     { MACFB_DISPLAY_VGA, 1, 0x100, 0x71e, 640, 480, 0x400, 0x1000 },
98     { MACFB_DISPLAY_VGA, 2, 0x100, 0x70e, 640, 480, 0x400, 0x1000 },
99     { MACFB_DISPLAY_VGA, 4, 0x100, 0x706, 640, 480, 0x400, 0x1000 },
100     { MACFB_DISPLAY_VGA, 8, 0x100, 0x702, 640, 480, 0x400, 0x1000 },
101     { MACFB_DISPLAY_VGA, 24, 0x100, 0x7ff, 640, 480, 0x1000, 0x1000 },
102     { MACFB_DISPLAY_VGA, 1, 0xd0 , 0x70e, 800, 600, 0x340, 0xe00 },
103     { MACFB_DISPLAY_VGA, 2, 0xd0 , 0x706, 800, 600, 0x340, 0xe00 },
104     { MACFB_DISPLAY_VGA, 4, 0xd0 , 0x702, 800, 600, 0x340, 0xe00 },
105     { MACFB_DISPLAY_VGA, 8, 0xd0,  0x700, 800, 600, 0x340, 0xe00 },
106     { MACFB_DISPLAY_VGA, 24, 0x340, 0x100, 800, 600, 0xd00, 0xe00 },
107     { MACFB_DISPLAY_APPLE_21_COLOR, 1, 0x90, 0x506, 1152, 870, 0x240, 0x80 },
108     { MACFB_DISPLAY_APPLE_21_COLOR, 2, 0x90, 0x502, 1152, 870, 0x240, 0x80 },
109     { MACFB_DISPLAY_APPLE_21_COLOR, 4, 0x90, 0x500, 1152, 870, 0x240, 0x80 },
110     { MACFB_DISPLAY_APPLE_21_COLOR, 8, 0x120, 0x5ff, 1152, 870, 0x480, 0x80 },
111 };
112 
113 typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr,
114                                   int width);
115 
116 static inline uint8_t macfb_read_byte(MacfbState *s, uint32_t addr)
117 {
118     return s->vram[addr & s->vram_bit_mask];
119 }
120 
121 /* 1-bit color */
122 static void macfb_draw_line1(MacfbState *s, uint8_t *d, uint32_t addr,
123                              int width)
124 {
125     uint8_t r, g, b;
126     int x;
127 
128     for (x = 0; x < width; x++) {
129         int bit = x & 7;
130         int idx = (macfb_read_byte(s, addr) >> (7 - bit)) & 1;
131         r = s->color_palette[idx * 3];
132         g = s->color_palette[idx * 3 + 1];
133         b = s->color_palette[idx * 3 + 2];
134         addr += (bit == 7);
135 
136         *(uint32_t *)d = rgb_to_pixel32(r, g, b);
137         d += 4;
138     }
139 }
140 
141 /* 2-bit color */
142 static void macfb_draw_line2(MacfbState *s, uint8_t *d, uint32_t addr,
143                              int width)
144 {
145     uint8_t r, g, b;
146     int x;
147 
148     for (x = 0; x < width; x++) {
149         int bit = (x & 3);
150         int idx = (macfb_read_byte(s, addr) >> ((3 - bit) << 1)) & 3;
151         r = s->color_palette[idx * 3];
152         g = s->color_palette[idx * 3 + 1];
153         b = s->color_palette[idx * 3 + 2];
154         addr += (bit == 3);
155 
156         *(uint32_t *)d = rgb_to_pixel32(r, g, b);
157         d += 4;
158     }
159 }
160 
161 /* 4-bit color */
162 static void macfb_draw_line4(MacfbState *s, uint8_t *d, uint32_t addr,
163                              int width)
164 {
165     uint8_t r, g, b;
166     int x;
167 
168     for (x = 0; x < width; x++) {
169         int bit = x & 1;
170         int idx = (macfb_read_byte(s, addr) >> ((1 - bit) << 2)) & 15;
171         r = s->color_palette[idx * 3];
172         g = s->color_palette[idx * 3 + 1];
173         b = s->color_palette[idx * 3 + 2];
174         addr += (bit == 1);
175 
176         *(uint32_t *)d = rgb_to_pixel32(r, g, b);
177         d += 4;
178     }
179 }
180 
181 /* 8-bit color */
182 static void macfb_draw_line8(MacfbState *s, uint8_t *d, uint32_t addr,
183                              int width)
184 {
185     uint8_t r, g, b;
186     int x;
187 
188     for (x = 0; x < width; x++) {
189         r = s->color_palette[macfb_read_byte(s, addr) * 3];
190         g = s->color_palette[macfb_read_byte(s, addr) * 3 + 1];
191         b = s->color_palette[macfb_read_byte(s, addr) * 3 + 2];
192         addr++;
193 
194         *(uint32_t *)d = rgb_to_pixel32(r, g, b);
195         d += 4;
196     }
197 }
198 
199 /* 16-bit color */
200 static void macfb_draw_line16(MacfbState *s, uint8_t *d, uint32_t addr,
201                               int width)
202 {
203     uint8_t r, g, b;
204     int x;
205 
206     for (x = 0; x < width; x++) {
207         uint16_t pixel;
208         pixel = (macfb_read_byte(s, addr) << 8) | macfb_read_byte(s, addr + 1);
209         r = ((pixel >> 10) & 0x1f) << 3;
210         g = ((pixel >> 5) & 0x1f) << 3;
211         b = (pixel & 0x1f) << 3;
212         addr += 2;
213 
214         *(uint32_t *)d = rgb_to_pixel32(r, g, b);
215         d += 4;
216     }
217 }
218 
219 /* 24-bit color */
220 static void macfb_draw_line24(MacfbState *s, uint8_t *d, uint32_t addr,
221                               int width)
222 {
223     uint8_t r, g, b;
224     int x;
225 
226     for (x = 0; x < width; x++) {
227         r = macfb_read_byte(s, addr);
228         g = macfb_read_byte(s, addr + 1);
229         b = macfb_read_byte(s, addr + 2);
230         addr += 3;
231 
232         *(uint32_t *)d = rgb_to_pixel32(r, g, b);
233         d += 4;
234     }
235 }
236 
237 
238 enum {
239     MACFB_DRAW_LINE1,
240     MACFB_DRAW_LINE2,
241     MACFB_DRAW_LINE4,
242     MACFB_DRAW_LINE8,
243     MACFB_DRAW_LINE16,
244     MACFB_DRAW_LINE24,
245     MACFB_DRAW_LINE_NB,
246 };
247 
248 static macfb_draw_line_func * const
249                               macfb_draw_line_table[MACFB_DRAW_LINE_NB] = {
250     macfb_draw_line1,
251     macfb_draw_line2,
252     macfb_draw_line4,
253     macfb_draw_line8,
254     macfb_draw_line16,
255     macfb_draw_line24,
256 };
257 
258 static int macfb_check_dirty(MacfbState *s, DirtyBitmapSnapshot *snap,
259                              ram_addr_t addr, int len)
260 {
261     return memory_region_snapshot_get_dirty(&s->mem_vram, snap, addr, len);
262 }
263 
264 static void macfb_draw_graphic(MacfbState *s)
265 {
266     DisplaySurface *surface = qemu_console_surface(s->con);
267     DirtyBitmapSnapshot *snap = NULL;
268     ram_addr_t page;
269     uint32_t v = 0;
270     int y, ymin;
271     int macfb_stride = s->mode->stride;
272     macfb_draw_line_func *macfb_draw_line;
273 
274     switch (s->depth) {
275     case 1:
276         v = MACFB_DRAW_LINE1;
277         break;
278     case 2:
279         v = MACFB_DRAW_LINE2;
280         break;
281     case 4:
282         v = MACFB_DRAW_LINE4;
283         break;
284     case 8:
285         v = MACFB_DRAW_LINE8;
286         break;
287     case 16:
288         v = MACFB_DRAW_LINE16;
289         break;
290     case 24:
291         v = MACFB_DRAW_LINE24;
292         break;
293     }
294 
295     macfb_draw_line = macfb_draw_line_table[v];
296     assert(macfb_draw_line != NULL);
297 
298     snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0x0,
299                                              memory_region_size(&s->mem_vram),
300                                              DIRTY_MEMORY_VGA);
301 
302     ymin = -1;
303     page = s->mode->offset;
304     for (y = 0; y < s->height; y++, page += macfb_stride) {
305         if (macfb_check_dirty(s, snap, page, macfb_stride)) {
306             uint8_t *data_display;
307 
308             data_display = surface_data(surface) + y * surface_stride(surface);
309             macfb_draw_line(s, data_display, page, s->width);
310 
311             if (ymin < 0) {
312                 ymin = y;
313             }
314         } else {
315             if (ymin >= 0) {
316                 dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
317                 ymin = -1;
318             }
319         }
320     }
321 
322     if (ymin >= 0) {
323         dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
324     }
325 
326     g_free(snap);
327 }
328 
329 static void macfb_invalidate_display(void *opaque)
330 {
331     MacfbState *s = opaque;
332 
333     memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE);
334 }
335 
336 static uint32_t macfb_sense_read(MacfbState *s)
337 {
338     MacFbSense *macfb_sense;
339     uint8_t sense;
340 
341     assert(s->type < ARRAY_SIZE(macfb_sense_table));
342     macfb_sense = &macfb_sense_table[s->type];
343     if (macfb_sense->sense == 0x7) {
344         /* Extended sense */
345         sense = 0;
346         if (!(macfb_sense->ext_sense & 1)) {
347             /* Pins 7-4 together */
348             if (~s->regs[DAFB_MODE_SENSE >> 2] & 3) {
349                 sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 3;
350             }
351         }
352         if (!(macfb_sense->ext_sense & 2)) {
353             /* Pins 10-7 together */
354             if (~s->regs[DAFB_MODE_SENSE >> 2] & 6) {
355                 sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 6;
356             }
357         }
358         if (!(macfb_sense->ext_sense & 4)) {
359             /* Pins 4-10 together */
360             if (~s->regs[DAFB_MODE_SENSE >> 2] & 5) {
361                 sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 5;
362             }
363         }
364     } else {
365         /* Normal sense */
366         sense = (~macfb_sense->sense & 7) |
367                 (~s->regs[DAFB_MODE_SENSE >> 2] & 7);
368     }
369 
370     trace_macfb_sense_read(sense);
371     return sense;
372 }
373 
374 static void macfb_sense_write(MacfbState *s, uint32_t val)
375 {
376     s->regs[DAFB_MODE_SENSE >> 2] = val;
377 
378     trace_macfb_sense_write(val);
379     return;
380 }
381 
382 static void macfb_update_mode(MacfbState *s)
383 {
384     s->width = s->mode->width;
385     s->height = s->mode->height;
386     s->depth = s->mode->depth;
387 
388     trace_macfb_update_mode(s->width, s->height, s->depth);
389     macfb_invalidate_display(s);
390 }
391 
392 static void macfb_mode_write(MacfbState *s)
393 {
394     MacFbMode *macfb_mode;
395     int i;
396 
397     for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
398         macfb_mode = &macfb_mode_table[i];
399 
400         if (s->type != macfb_mode->type) {
401             continue;
402         }
403 
404         if ((s->regs[DAFB_MODE_CTRL1 >> 2] & 0xff) ==
405              (macfb_mode->mode_ctrl1 & 0xff) &&
406             (s->regs[DAFB_MODE_CTRL2 >> 2] & 0xff) ==
407              (macfb_mode->mode_ctrl2 & 0xff)) {
408             s->mode = macfb_mode;
409             macfb_update_mode(s);
410             break;
411         }
412     }
413 }
414 
415 static MacFbMode *macfb_find_mode(MacfbDisplayType display_type,
416                                   uint16_t width, uint16_t height,
417                                   uint8_t depth)
418 {
419     MacFbMode *macfb_mode;
420     int i;
421 
422     for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
423         macfb_mode = &macfb_mode_table[i];
424 
425         if (display_type == macfb_mode->type && width == macfb_mode->width &&
426                 height == macfb_mode->height && depth == macfb_mode->depth) {
427             return macfb_mode;
428         }
429     }
430 
431     return NULL;
432 }
433 
434 static gchar *macfb_mode_list(void)
435 {
436     gchar *list = NULL;
437     gchar *mode;
438     MacFbMode *macfb_mode;
439     int i;
440 
441     for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
442         macfb_mode = &macfb_mode_table[i];
443 
444         mode = g_strdup_printf("    %dx%dx%d\n", macfb_mode->width,
445                                macfb_mode->height, macfb_mode->depth);
446         list = g_strconcat(mode, list, NULL);
447         g_free(mode);
448     }
449 
450     return list;
451 }
452 
453 
454 static void macfb_update_display(void *opaque)
455 {
456     MacfbState *s = opaque;
457     DisplaySurface *surface = qemu_console_surface(s->con);
458 
459     qemu_flush_coalesced_mmio_buffer();
460 
461     if (s->width == 0 || s->height == 0) {
462         return;
463     }
464 
465     if (s->width != surface_width(surface) ||
466         s->height != surface_height(surface)) {
467         qemu_console_resize(s->con, s->width, s->height);
468     }
469 
470     macfb_draw_graphic(s);
471 }
472 
473 static void macfb_reset(MacfbState *s)
474 {
475     int i;
476 
477     s->palette_current = 0;
478     for (i = 0; i < 256; i++) {
479         s->color_palette[i * 3] = 255 - i;
480         s->color_palette[i * 3 + 1] = 255 - i;
481         s->color_palette[i * 3 + 2] = 255 - i;
482     }
483     memset(s->vram, 0, MACFB_VRAM_SIZE);
484     macfb_invalidate_display(s);
485 }
486 
487 static uint64_t macfb_ctrl_read(void *opaque,
488                                 hwaddr addr,
489                                 unsigned int size)
490 {
491     MacfbState *s = opaque;
492     uint64_t val = 0;
493 
494     switch (addr) {
495     case DAFB_MODE_VADDR1:
496     case DAFB_MODE_VADDR2:
497     case DAFB_MODE_CTRL1:
498     case DAFB_MODE_CTRL2:
499         val = s->regs[addr >> 2];
500         break;
501     case DAFB_MODE_SENSE:
502         val = macfb_sense_read(s);
503         break;
504     }
505 
506     trace_macfb_ctrl_read(addr, val, size);
507     return val;
508 }
509 
510 static void macfb_ctrl_write(void *opaque,
511                              hwaddr addr,
512                              uint64_t val,
513                              unsigned int size)
514 {
515     MacfbState *s = opaque;
516     switch (addr) {
517     case DAFB_MODE_VADDR1:
518     case DAFB_MODE_VADDR2:
519         s->regs[addr >> 2] = val;
520         break;
521     case DAFB_MODE_CTRL1 ... DAFB_MODE_CTRL1 + 3:
522     case DAFB_MODE_CTRL2 ... DAFB_MODE_CTRL2 + 3:
523         s->regs[addr >> 2] = val;
524         if (val) {
525             macfb_mode_write(s);
526         }
527         break;
528     case DAFB_MODE_SENSE:
529         macfb_sense_write(s, val);
530         break;
531     case DAFB_RESET:
532         s->palette_current = 0;
533         break;
534     case DAFB_LUT:
535         s->color_palette[s->palette_current] = val;
536         s->palette_current = (s->palette_current + 1) %
537                              ARRAY_SIZE(s->color_palette);
538         if (s->palette_current % 3) {
539             macfb_invalidate_display(s);
540         }
541         break;
542     }
543 
544     trace_macfb_ctrl_write(addr, val, size);
545 }
546 
547 static const MemoryRegionOps macfb_ctrl_ops = {
548     .read = macfb_ctrl_read,
549     .write = macfb_ctrl_write,
550     .endianness = DEVICE_BIG_ENDIAN,
551     .impl.min_access_size = 1,
552     .impl.max_access_size = 4,
553 };
554 
555 static int macfb_post_load(void *opaque, int version_id)
556 {
557     macfb_mode_write(opaque);
558     return 0;
559 }
560 
561 static const VMStateDescription vmstate_macfb = {
562     .name = "macfb",
563     .version_id = 1,
564     .minimum_version_id = 1,
565     .minimum_version_id_old = 1,
566     .post_load = macfb_post_load,
567     .fields = (VMStateField[]) {
568         VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
569         VMSTATE_UINT32(palette_current, MacfbState),
570         VMSTATE_UINT32_ARRAY(regs, MacfbState, MACFB_NUM_REGS),
571         VMSTATE_END_OF_LIST()
572     }
573 };
574 
575 static const GraphicHwOps macfb_ops = {
576     .invalidate = macfb_invalidate_display,
577     .gfx_update = macfb_update_display,
578 };
579 
580 static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
581 {
582     DisplaySurface *surface;
583 
584     s->mode = macfb_find_mode(s->type, s->width, s->height, s->depth);
585     if (!s->mode) {
586         gchar *list;
587         error_setg(errp, "unknown display mode: width %d, height %d, depth %d",
588                    s->width, s->height, s->depth);
589         list =  macfb_mode_list();
590         error_append_hint(errp, "Available modes:\n%s", list);
591         g_free(list);
592 
593         return false;
594     }
595 
596     s->con = graphic_console_init(dev, 0, &macfb_ops, s);
597     surface = qemu_console_surface(s->con);
598 
599     if (surface_bits_per_pixel(surface) != 32) {
600         error_setg(errp, "unknown host depth %d",
601                    surface_bits_per_pixel(surface));
602         return false;
603     }
604 
605     memory_region_init_io(&s->mem_ctrl, OBJECT(dev), &macfb_ctrl_ops, s,
606                           "macfb-ctrl", 0x1000);
607 
608     memory_region_init_ram(&s->mem_vram, OBJECT(dev), "macfb-vram",
609                            MACFB_VRAM_SIZE, &error_abort);
610     s->vram = memory_region_get_ram_ptr(&s->mem_vram);
611     s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
612     memory_region_set_coalescing(&s->mem_vram);
613 
614     macfb_update_mode(s);
615     return true;
616 }
617 
618 static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
619 {
620     MacfbSysBusState *s = MACFB(dev);
621     MacfbState *ms = &s->macfb;
622 
623     if (!macfb_common_realize(dev, ms, errp)) {
624         return;
625     }
626 
627     sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl);
628     sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
629 }
630 
631 static void macfb_nubus_realize(DeviceState *dev, Error **errp)
632 {
633     NubusDevice *nd = NUBUS_DEVICE(dev);
634     MacfbNubusState *s = NUBUS_MACFB(dev);
635     MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev);
636     MacfbState *ms = &s->macfb;
637 
638     ndc->parent_realize(dev, errp);
639     if (*errp) {
640         return;
641     }
642 
643     if (!macfb_common_realize(dev, ms, errp)) {
644         return;
645     }
646 
647     memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
648     memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
649 }
650 
651 static void macfb_sysbus_reset(DeviceState *d)
652 {
653     MacfbSysBusState *s = MACFB(d);
654     macfb_reset(&s->macfb);
655 }
656 
657 static void macfb_nubus_reset(DeviceState *d)
658 {
659     MacfbNubusState *s = NUBUS_MACFB(d);
660     macfb_reset(&s->macfb);
661 }
662 
663 static Property macfb_sysbus_properties[] = {
664     DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640),
665     DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480),
666     DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8),
667     DEFINE_PROP_UINT8("display", MacfbSysBusState, macfb.type,
668                       MACFB_DISPLAY_VGA),
669     DEFINE_PROP_END_OF_LIST(),
670 };
671 
672 static Property macfb_nubus_properties[] = {
673     DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640),
674     DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480),
675     DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8),
676     DEFINE_PROP_UINT8("display", MacfbNubusState, macfb.type,
677                       MACFB_DISPLAY_VGA),
678     DEFINE_PROP_END_OF_LIST(),
679 };
680 
681 static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
682 {
683     DeviceClass *dc = DEVICE_CLASS(klass);
684 
685     dc->realize = macfb_sysbus_realize;
686     dc->desc = "SysBus Macintosh framebuffer";
687     dc->reset = macfb_sysbus_reset;
688     dc->vmsd = &vmstate_macfb;
689     device_class_set_props(dc, macfb_sysbus_properties);
690 }
691 
692 static void macfb_nubus_class_init(ObjectClass *klass, void *data)
693 {
694     DeviceClass *dc = DEVICE_CLASS(klass);
695     MacfbNubusDeviceClass *ndc = NUBUS_MACFB_CLASS(klass);
696 
697     device_class_set_parent_realize(dc, macfb_nubus_realize,
698                                     &ndc->parent_realize);
699     dc->desc = "Nubus Macintosh framebuffer";
700     dc->reset = macfb_nubus_reset;
701     dc->vmsd = &vmstate_macfb;
702     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
703     device_class_set_props(dc, macfb_nubus_properties);
704 }
705 
706 static TypeInfo macfb_sysbus_info = {
707     .name          = TYPE_MACFB,
708     .parent        = TYPE_SYS_BUS_DEVICE,
709     .instance_size = sizeof(MacfbSysBusState),
710     .class_init    = macfb_sysbus_class_init,
711 };
712 
713 static TypeInfo macfb_nubus_info = {
714     .name          = TYPE_NUBUS_MACFB,
715     .parent        = TYPE_NUBUS_DEVICE,
716     .instance_size = sizeof(MacfbNubusState),
717     .class_init    = macfb_nubus_class_init,
718     .class_size    = sizeof(MacfbNubusDeviceClass),
719 };
720 
721 static void macfb_register_types(void)
722 {
723     type_register_static(&macfb_sysbus_info);
724     type_register_static(&macfb_nubus_info);
725 }
726 
727 type_init(macfb_register_types)
728