qemu/hw/display/macfb.c
<<
>>
Prefs
   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_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/* Vertical Blank period (60.15Hz) */
  45#define DAFB_INTR_VBL_PERIOD_NS 16625800
  46
  47/*
  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:
  51 *
  52 * Sense:
  53 *    bit 2: SENSE2 (pin 10)
  54 *    bit 1: SENSE1 (pin 7)
  55 *    bit 0: SENSE0 (pin 4)
  56 *
  57 * 0 = pin tied to ground
  58 * 1 = pin unconnected
  59 *
  60 * Extended Sense:
  61 *    bit 2: pins 4-10
  62 *    bit 1: pins 10-7
  63 *    bit 0: pins 7-4
  64 *
  65 * 0 = pins tied together
  66 * 1 = pins unconnected
  67 *
  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.
  70 *
  71 * Writes to the sense register appear to activate pulldowns i.e. a 1 enables
  72 * a pulldown on a particular pin.
  73 *
  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.
  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/* 1-bit color */
 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/* 2-bit color */
 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/* 4-bit color */
 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/* 8-bit color */
 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/* 16-bit color */
 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/* 24-bit color */
 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        /* Extended sense */
 352        sense = 0;
 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;
 357            }
 358        }
 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;
 363            }
 364        }
 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;
 369            }
 370        }
 371    } else {
 372        /* Normal sense */
 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    /* 60 Hz irq */
 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     * Set mode control registers to match the mode found above so that
 660     * macfb_mode_write() does the right thing if no MacOS toolbox ROM
 661     * is present to initialise them
 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