macfb.c (22514B)
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 gchar *list = NULL; 444 gchar *mode; 445 MacFbMode *macfb_mode; 446 int i; 447 448 for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) { 449 macfb_mode = &macfb_mode_table[i]; 450 451 mode = g_strdup_printf(" %dx%dx%d\n", macfb_mode->width, 452 macfb_mode->height, macfb_mode->depth); 453 list = g_strconcat(mode, list, NULL); 454 g_free(mode); 455 } 456 457 return list; 458} 459 460 461static void macfb_update_display(void *opaque) 462{ 463 MacfbState *s = opaque; 464 DisplaySurface *surface = qemu_console_surface(s->con); 465 466 qemu_flush_coalesced_mmio_buffer(); 467 468 if (s->width == 0 || s->height == 0) { 469 return; 470 } 471 472 if (s->width != surface_width(surface) || 473 s->height != surface_height(surface)) { 474 qemu_console_resize(s->con, s->width, s->height); 475 } 476 477 macfb_draw_graphic(s); 478} 479 480static void macfb_update_irq(MacfbState *s) 481{ 482 uint32_t irq_state = s->irq_state & s->irq_mask; 483 484 if (irq_state) { 485 qemu_irq_raise(s->irq); 486 } else { 487 qemu_irq_lower(s->irq); 488 } 489} 490 491static int64_t macfb_next_vbl(void) 492{ 493 return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + DAFB_INTR_VBL_PERIOD_NS) / 494 DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS; 495} 496 497static void macfb_vbl_timer(void *opaque) 498{ 499 MacfbState *s = opaque; 500 int64_t next_vbl; 501 502 s->irq_state |= DAFB_INTR_VBL; 503 macfb_update_irq(s); 504 505 /* 60 Hz irq */ 506 next_vbl = macfb_next_vbl(); 507 timer_mod(s->vbl_timer, next_vbl); 508} 509 510static void macfb_reset(MacfbState *s) 511{ 512 int i; 513 514 s->palette_current = 0; 515 for (i = 0; i < 256; i++) { 516 s->color_palette[i * 3] = 255 - i; 517 s->color_palette[i * 3 + 1] = 255 - i; 518 s->color_palette[i * 3 + 2] = 255 - i; 519 } 520 memset(s->vram, 0, MACFB_VRAM_SIZE); 521 macfb_invalidate_display(s); 522} 523 524static uint64_t macfb_ctrl_read(void *opaque, 525 hwaddr addr, 526 unsigned int size) 527{ 528 MacfbState *s = opaque; 529 uint64_t val = 0; 530 531 switch (addr) { 532 case DAFB_MODE_VADDR1: 533 case DAFB_MODE_VADDR2: 534 case DAFB_MODE_CTRL1: 535 case DAFB_MODE_CTRL2: 536 val = s->regs[addr >> 2]; 537 break; 538 case DAFB_INTR_STAT: 539 val = s->irq_state; 540 break; 541 case DAFB_MODE_SENSE: 542 val = macfb_sense_read(s); 543 break; 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->irq_mask = 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->irq_state &= ~DAFB_INTR_VBL; 584 macfb_update_irq(s); 585 break; 586 case DAFB_RESET: 587 s->palette_current = 0; 588 s->irq_state &= ~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 } 600 601 trace_macfb_ctrl_write(addr, val, size); 602} 603 604static const MemoryRegionOps macfb_ctrl_ops = { 605 .read = macfb_ctrl_read, 606 .write = macfb_ctrl_write, 607 .endianness = DEVICE_BIG_ENDIAN, 608 .impl.min_access_size = 1, 609 .impl.max_access_size = 4, 610}; 611 612static int macfb_post_load(void *opaque, int version_id) 613{ 614 macfb_mode_write(opaque); 615 return 0; 616} 617 618static const VMStateDescription vmstate_macfb = { 619 .name = "macfb", 620 .version_id = 1, 621 .minimum_version_id = 1, 622 .minimum_version_id_old = 1, 623 .post_load = macfb_post_load, 624 .fields = (VMStateField[]) { 625 VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3), 626 VMSTATE_UINT32(palette_current, MacfbState), 627 VMSTATE_UINT32_ARRAY(regs, MacfbState, MACFB_NUM_REGS), 628 VMSTATE_END_OF_LIST() 629 } 630}; 631 632static const GraphicHwOps macfb_ops = { 633 .invalidate = macfb_invalidate_display, 634 .gfx_update = macfb_update_display, 635}; 636 637static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp) 638{ 639 DisplaySurface *surface; 640 641 s->mode = macfb_find_mode(s->type, s->width, s->height, s->depth); 642 if (!s->mode) { 643 gchar *list; 644 error_setg(errp, "unknown display mode: width %d, height %d, depth %d", 645 s->width, s->height, s->depth); 646 list = macfb_mode_list(); 647 error_append_hint(errp, "Available modes:\n%s", list); 648 g_free(list); 649 650 return false; 651 } 652 653 s->con = graphic_console_init(dev, 0, &macfb_ops, s); 654 surface = qemu_console_surface(s->con); 655 656 if (surface_bits_per_pixel(surface) != 32) { 657 error_setg(errp, "unknown host depth %d", 658 surface_bits_per_pixel(surface)); 659 return false; 660 } 661 662 memory_region_init_io(&s->mem_ctrl, OBJECT(dev), &macfb_ctrl_ops, s, 663 "macfb-ctrl", 0x1000); 664 665 memory_region_init_ram(&s->mem_vram, OBJECT(dev), "macfb-vram", 666 MACFB_VRAM_SIZE, &error_abort); 667 s->vram = memory_region_get_ram_ptr(&s->mem_vram); 668 s->vram_bit_mask = MACFB_VRAM_SIZE - 1; 669 memory_region_set_coalescing(&s->mem_vram); 670 671 s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s); 672 macfb_update_mode(s); 673 return true; 674} 675 676static void macfb_sysbus_realize(DeviceState *dev, Error **errp) 677{ 678 MacfbSysBusState *s = MACFB(dev); 679 MacfbState *ms = &s->macfb; 680 681 if (!macfb_common_realize(dev, ms, errp)) { 682 return; 683 } 684 685 sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl); 686 sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram); 687 688 qdev_init_gpio_out(dev, &ms->irq, 1); 689} 690 691static void macfb_nubus_set_irq(void *opaque, int n, int level) 692{ 693 MacfbNubusState *s = NUBUS_MACFB(opaque); 694 NubusDevice *nd = NUBUS_DEVICE(s); 695 696 nubus_set_irq(nd, level); 697} 698 699static void macfb_nubus_realize(DeviceState *dev, Error **errp) 700{ 701 NubusDevice *nd = NUBUS_DEVICE(dev); 702 MacfbNubusState *s = NUBUS_MACFB(dev); 703 MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev); 704 MacfbState *ms = &s->macfb; 705 706 ndc->parent_realize(dev, errp); 707 if (*errp) { 708 return; 709 } 710 711 if (!macfb_common_realize(dev, ms, errp)) { 712 return; 713 } 714 715 memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl); 716 memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram); 717 718 ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0); 719} 720 721static void macfb_nubus_unrealize(DeviceState *dev) 722{ 723 MacfbNubusState *s = NUBUS_MACFB(dev); 724 MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev); 725 MacfbState *ms = &s->macfb; 726 727 ndc->parent_unrealize(dev); 728 729 qemu_free_irq(ms->irq); 730} 731 732static void macfb_sysbus_reset(DeviceState *d) 733{ 734 MacfbSysBusState *s = MACFB(d); 735 macfb_reset(&s->macfb); 736} 737 738static void macfb_nubus_reset(DeviceState *d) 739{ 740 MacfbNubusState *s = NUBUS_MACFB(d); 741 macfb_reset(&s->macfb); 742} 743 744static Property macfb_sysbus_properties[] = { 745 DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640), 746 DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480), 747 DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8), 748 DEFINE_PROP_UINT8("display", MacfbSysBusState, macfb.type, 749 MACFB_DISPLAY_VGA), 750 DEFINE_PROP_END_OF_LIST(), 751}; 752 753static Property macfb_nubus_properties[] = { 754 DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640), 755 DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480), 756 DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8), 757 DEFINE_PROP_UINT8("display", MacfbNubusState, macfb.type, 758 MACFB_DISPLAY_VGA), 759 DEFINE_PROP_END_OF_LIST(), 760}; 761 762static void macfb_sysbus_class_init(ObjectClass *klass, void *data) 763{ 764 DeviceClass *dc = DEVICE_CLASS(klass); 765 766 dc->realize = macfb_sysbus_realize; 767 dc->desc = "SysBus Macintosh framebuffer"; 768 dc->reset = macfb_sysbus_reset; 769 dc->vmsd = &vmstate_macfb; 770 device_class_set_props(dc, macfb_sysbus_properties); 771} 772 773static void macfb_nubus_class_init(ObjectClass *klass, void *data) 774{ 775 DeviceClass *dc = DEVICE_CLASS(klass); 776 MacfbNubusDeviceClass *ndc = NUBUS_MACFB_CLASS(klass); 777 778 device_class_set_parent_realize(dc, macfb_nubus_realize, 779 &ndc->parent_realize); 780 device_class_set_parent_unrealize(dc, macfb_nubus_unrealize, 781 &ndc->parent_unrealize); 782 dc->desc = "Nubus Macintosh framebuffer"; 783 dc->reset = macfb_nubus_reset; 784 dc->vmsd = &vmstate_macfb; 785 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 786 device_class_set_props(dc, macfb_nubus_properties); 787} 788 789static TypeInfo macfb_sysbus_info = { 790 .name = TYPE_MACFB, 791 .parent = TYPE_SYS_BUS_DEVICE, 792 .instance_size = sizeof(MacfbSysBusState), 793 .class_init = macfb_sysbus_class_init, 794}; 795 796static TypeInfo macfb_nubus_info = { 797 .name = TYPE_NUBUS_MACFB, 798 .parent = TYPE_NUBUS_DEVICE, 799 .instance_size = sizeof(MacfbNubusState), 800 .class_init = macfb_nubus_class_init, 801 .class_size = sizeof(MacfbNubusDeviceClass), 802}; 803 804static void macfb_register_types(void) 805{ 806 type_register_static(&macfb_sysbus_info); 807 type_register_static(&macfb_nubus_info); 808} 809 810type_init(macfb_register_types)