+}
+
static void macfb_reset(MacfbState *s)
{
int i;
@@ -477,6 +510,9 @@ static uint64_t macfb_ctrl_read(void *opaque,
case DAFB_MODE_CTRL2:
val = s->regs[addr >> 2];
break;
+ case DAFB_INTR_STAT:
+ val = s->irq_state;
+ break;
case DAFB_MODE_SENSE:
val = macfb_sense_read(s);
break;
@@ -492,6 +528,8 @@ static void macfb_ctrl_write(void *opaque,
unsigned int size)
{
MacfbState *s = opaque;
+ int64_t next_vbl;
+
switch (addr) {
case DAFB_MODE_VADDR1:
case DAFB_MODE_VADDR2:
@@ -507,8 +545,25 @@ static void macfb_ctrl_write(void *opaque,
case DAFB_MODE_SENSE:
macfb_sense_write(s, val);
break;
+ case DAFB_INTR_MASK:
+ s->irq_mask = val;
+ if (val & DAFB_INTR_VBL) {
+ next_vbl = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ DAFB_INTR_VBL_PERIOD_NS) /
+ DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS;
+ timer_mod(s->vbl_timer, next_vbl);
+ } else {
+ timer_del(s->vbl_timer);
+ }
+ break;
+ case DAFB_INTR_CLEAR:
+ s->irq_state &= ~DAFB_INTR_VBL;
+ macfb_update_irq(s);
+ break;
case DAFB_RESET:
s->palette_current = 0;
+ s->irq_state &= ~DAFB_INTR_VBL;
+ macfb_update_irq(s);
break;
case DAFB_LUT:
s->color_palette[s->palette_current++] = val;
@@ -586,6 +641,7 @@ static void macfb_common_realize(DeviceState *dev,
MacfbState *s, Error **errp)
s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
memory_region_set_coalescing(&s->mem_vram);
+ s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s);
macfb_update_mode(s);
}
@@ -601,6 +657,16 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
+
+ qdev_init_gpio_out(dev, &ms->irq, 1);
+}
+
+static void macfb_nubus_set_irq(void *opaque, int n, int level)
+{
+ MacfbNubusState *s = NUBUS_MACFB(opaque);
+ NubusDevice *nd = NUBUS_DEVICE(s);
+
+ nubus_set_irq(nd, level);
}
static void macfb_nubus_realize(DeviceState *dev, Error **errp)
@@ -622,6 +688,19 @@ static void macfb_nubus_realize(DeviceState *dev, Error
**errp)
memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
+
+ ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0);
+}
+
+static void macfb_nubus_unrealize(DeviceState *dev)
+{
+ MacfbNubusState *s = NUBUS_MACFB(dev);
+ MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev);
+ MacfbState *ms = &s->macfb;
+
+ ndc->parent_unrealize(dev);
+
+ qemu_free_irq(ms->irq);
}
static void macfb_sysbus_reset(DeviceState *d)
@@ -672,6 +751,8 @@ static void macfb_nubus_class_init(ObjectClass *klass, void
*data)
device_class_set_parent_realize(dc, macfb_nubus_realize,
&ndc->parent_realize);
+ device_class_set_parent_unrealize(dc, macfb_nubus_unrealize,
+ &ndc->parent_unrealize);
dc->desc = "Nubus Macintosh framebuffer";
dc->reset = macfb_nubus_reset;
dc->vmsd = &vmstate_macfb;
diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h
index 0aff0d84d2..e52775aa21 100644
--- a/include/hw/display/macfb.h
+++ b/include/hw/display/macfb.h
@@ -14,7 +14,9 @@
#define MACFB_H
#include "exec/memory.h"
+#include "hw/irq.h"
#include "ui/console.h"
+#include "qemu/timer.h"
#include "qom/object.h"
typedef enum {
@@ -63,6 +65,11 @@ typedef struct MacfbState {
uint32_t regs[MACFB_NUM_REGS];
MacFbMode *mode;
+
+ uint32_t irq_state;
+ uint32_t irq_mask;
+ QEMUTimer *vbl_timer;
+ qemu_irq irq;
} MacfbState;
#define TYPE_MACFB "sysbus-macfb"
@@ -81,6 +88,7 @@ struct MacfbNubusDeviceClass {
DeviceClass parent_class;
DeviceRealize parent_realize;
+ DeviceUnrealize parent_unrealize;
};