aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/i8259.c157
1 files changed, 100 insertions, 57 deletions
diff --git a/hw/i8259.c b/hw/i8259.c
index df23bb8c91..b4e1867de4 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -41,6 +41,7 @@
//#define DEBUG_IRQ_COUNT
struct PicState {
+ ISADevice dev;
uint8_t last_irr; /* edge detection */
uint8_t irr; /* interrupt request register */
uint8_t imr; /* interrupt mask register */
@@ -58,8 +59,10 @@ struct PicState {
uint8_t single_mode; /* true if slave pic is not initialized */
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
- qemu_irq int_out;
- bool master; /* reflects /SP input pin */
+ qemu_irq int_out[1];
+ uint32_t master; /* reflects /SP input pin */
+ uint32_t iobase;
+ uint32_t elcr_addr;
MemoryRegion base_io;
MemoryRegion elcr_io;
};
@@ -70,6 +73,9 @@ static int irq_level[16];
#ifdef DEBUG_IRQ_COUNT
static uint64_t irq_count[16];
#endif
+#ifdef DEBUG_IRQ_LATENCY
+static int64_t irq_time[16];
+#endif
PicState *isa_pic;
static PicState *slave_pic;
@@ -122,17 +128,39 @@ static void pic_update_irq(PicState *s)
if (irq >= 0) {
DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
- qemu_irq_raise(s->int_out);
+ qemu_irq_raise(s->int_out[0]);
} else {
- qemu_irq_lower(s->int_out);
+ qemu_irq_lower(s->int_out[0]);
}
}
/* set irq level. If an edge is detected, then the IRR is set to 1 */
-static void pic_set_irq1(PicState *s, int irq, int level)
+static void pic_set_irq(void *opaque, int irq, int level)
{
- int mask;
- mask = 1 << irq;
+ PicState *s = opaque;
+ int mask = 1 << irq;
+
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
+ defined(DEBUG_IRQ_LATENCY)
+ int irq_index = s->master ? irq : irq + 8;
+#endif
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
+ if (level != irq_level[irq_index]) {
+ DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
+ irq_level[irq_index] = level;
+#ifdef DEBUG_IRQ_COUNT
+ if (level == 1) {
+ irq_count[irq_index]++;
+ }
+#endif
+ }
+#endif
+#ifdef DEBUG_IRQ_LATENCY
+ if (level) {
+ irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
+ }
+#endif
+
if (s->elcr & mask) {
/* level triggered */
if (level) {
@@ -156,32 +184,6 @@ static void pic_set_irq1(PicState *s, int irq, int level)
pic_update_irq(s);
}
-#ifdef DEBUG_IRQ_LATENCY
-int64_t irq_time[16];
-#endif
-
-static void i8259_set_irq(void *opaque, int irq, int level)
-{
- PicState *s = irq <= 7 ? isa_pic : slave_pic;
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
- if (level != irq_level[irq]) {
- DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level);
- irq_level[irq] = level;
-#ifdef DEBUG_IRQ_COUNT
- if (level == 1)
- irq_count[irq]++;
-#endif
- }
-#endif
-#ifdef DEBUG_IRQ_LATENCY
- if (level) {
- irq_time[irq] = qemu_get_clock_ns(vm_clock);
- }
-#endif
- pic_set_irq1(s, irq & 7, level);
-}
-
/* acknowledge interrupt 'irq' */
static void pic_intack(PicState *s, int irq)
{
@@ -258,9 +260,9 @@ static void pic_init_reset(PicState *s)
pic_update_irq(s);
}
-static void pic_reset(void *opaque)
+static void pic_reset(DeviceState *dev)
{
- PicState *s = opaque;
+ PicState *s = container_of(dev, PicState, dev.qdev);
pic_init_reset(s);
s->elcr = 0;
@@ -447,23 +449,24 @@ static const MemoryRegionOps pic_elcr_ioport_ops = {
},
};
-/* XXX: add generic master/slave system */
-static void pic_init(int io_addr, int elcr_addr, PicState *s, qemu_irq int_out,
- bool master)
+static int pic_initfn(ISADevice *dev)
{
- s->int_out = int_out;
- s->master = master;
+ PicState *s = DO_UPCAST(PicState, dev, dev);
memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
- isa_register_ioport(NULL, &s->base_io, io_addr);
- if (elcr_addr >= 0) {
- isa_register_ioport(NULL, &s->elcr_io, elcr_addr);
+ isa_register_ioport(NULL, &s->base_io, s->iobase);
+ if (s->elcr_addr != -1) {
+ isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
}
- vmstate_register(NULL, io_addr, &vmstate_pic, s);
- qemu_register_reset(pic_reset, s);
+ qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
+ qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
+
+ qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
+
+ return 0;
}
void pic_info(Monitor *mon)
@@ -503,20 +506,60 @@ void irq_info(Monitor *mon)
qemu_irq *i8259_init(qemu_irq parent_irq)
{
- qemu_irq *irqs;
- PicState *s;
+ qemu_irq *irq_set;
+ ISADevice *dev;
+ int i;
- irqs = qemu_allocate_irqs(i8259_set_irq, NULL, 16);
+ irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
- s = g_malloc0(sizeof(PicState));
- pic_init(0x20, 0x4d0, s, parent_irq, true);
- s->elcr_mask = 0xf8;
- isa_pic = s;
+ dev = isa_create("isa-i8259");
+ qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
+ qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
+ qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
+ qdev_prop_set_bit(&dev->qdev, "master", true);
+ qdev_init_nofail(&dev->qdev);
- s = g_malloc0(sizeof(PicState));
- pic_init(0xa0, 0x4d1, s, irqs[2], false);
- s->elcr_mask = 0xde;
- slave_pic = s;
+ qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
+ for (i = 0 ; i < 8; i++) {
+ irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
+ }
+
+ isa_pic = DO_UPCAST(PicState, dev, dev);
+
+ dev = isa_create("isa-i8259");
+ qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
+ qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
+ qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
+ qdev_init_nofail(&dev->qdev);
+
+ qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
+ for (i = 0 ; i < 8; i++) {
+ irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
+ }
+
+ slave_pic = DO_UPCAST(PicState, dev, dev);
- return irqs;
+ return irq_set;
+}
+
+static ISADeviceInfo i8259_info = {
+ .qdev.name = "isa-i8259",
+ .qdev.size = sizeof(PicState),
+ .qdev.vmsd = &vmstate_pic,
+ .qdev.reset = pic_reset,
+ .qdev.no_user = 1,
+ .init = pic_initfn,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_HEX32("iobase", PicState, iobase, -1),
+ DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr, -1),
+ DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask, -1),
+ DEFINE_PROP_BIT("master", PicState, master, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static void pic_register(void)
+{
+ isa_qdev_register(&i8259_info);
}
+device_init(pic_register)