Le 02/10/2021 à 13:00, Mark Cave-Ayland a écrit : > The MacOS driver expects a 60.15Hz vertical blank interrupt to be generated by > the framebuffer which in turn schedules the mouse driver via the Vertical > Retrace > Manager. > > Signed-off-by: Mark Cave-Ayland <mark.cave-ayl...@ilande.co.uk> > --- > hw/display/macfb.c | 81 ++++++++++++++++++++++++++++++++++++++ > include/hw/display/macfb.h | 8 ++++ > 2 files changed, 89 insertions(+) > > diff --git a/hw/display/macfb.c b/hw/display/macfb.c > index 29f6ad8eba..60a203e67b 100644 > --- a/hw/display/macfb.c > +++ b/hw/display/macfb.c > @@ -33,9 +33,16 @@ > #define DAFB_MODE_CTRL1 0x8 > #define DAFB_MODE_CTRL2 0xc > #define DAFB_MODE_SENSE 0x1c > +#define DAFB_INTR_MASK 0x104 > +#define DAFB_INTR_STAT 0x108 > +#define DAFB_INTR_CLEAR 0x10c > #define DAFB_RESET 0x200 > #define DAFB_LUT 0x213 > > +#define DAFB_INTR_VBL 0x4 > + > +/* Vertical Blank period (60.15Hz) */ > +#define DAFB_INTR_VBL_PERIOD_NS 16625800 > > /* > * Quadra sense codes taken from Apple Technical Note HW26: > @@ -449,6 +456,32 @@ static void macfb_update_display(void *opaque) > macfb_draw_graphic(s); > } > > +static void macfb_update_irq(MacfbState *s) > +{ > + uint32_t irq_state = s->irq_state & s->irq_mask; > + > + if (irq_state) { > + qemu_irq_raise(s->irq); > + } else { > + qemu_irq_lower(s->irq); > + } > +} > + > +static void macfb_vbl_timer(void *opaque) > +{ > + MacfbState *s = opaque; > + int64_t next_vbl; > + > + s->irq_state |= DAFB_INTR_VBL; > + macfb_update_irq(s); > + > + /* 60 Hz irq */ > + 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);
perhaps you can move this to a function and call it here and below? > +} > + > 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; > }; > > > Reviewed-by: Laurent Vivier <laur...@vivier.eu>