Unify IRQ handling.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2635 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/hw/acpi.c b/hw/acpi.c
index 78c4fea..e78e56d 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -92,7 +92,7 @@
     pmsts = get_pmsts(s);
     sci_level = (((pmsts & s->pmen) & 
                   (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
-    pci_set_irq(&s->dev, 0, sci_level);
+    qemu_set_irq(s->dev.irq[0], sci_level);
     /* schedule a timer interruption if needed */
     if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
         expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
diff --git a/hw/adlib.c b/hw/adlib.c
index b47bc3e..805365e 100644
--- a/hw/adlib.c
+++ b/hw/adlib.c
@@ -267,7 +267,7 @@
     AUD_remove_card (&s->card);
 }
 
-int Adlib_init (AudioState *audio)
+int Adlib_init (AudioState *audio, qemu_irq *pic)
 {
     AdlibState *s = &glob_adlib;
     audsettings_t as;
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index a5fe9b9..627fd9b 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -200,14 +200,14 @@
     return bus_offset + irq_num;
 }
 
-static void pci_apb_set_irq(void *pic, int irq_num, int level)
+static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level)
 {
     /* PCI IRQ map onto the first 32 INO.  */
-    pic_set_irq_new(pic, irq_num, level);
+    qemu_set_irq(pic[irq_num], level);
 }
 
 PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
-                     void *pic)
+                     qemu_irq *pic)
 {
     APBState *s;
     PCIDevice *d;
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 2901f34..eee5b7c 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -60,10 +60,8 @@
 
 typedef struct gic_state
 {
-    arm_pic_handler handler;
     uint32_t base;
-    void *parent;
-    int parent_irq;
+    qemu_irq parent_irq;
     int enabled;
     int cpu_enabled;
 
@@ -88,7 +86,7 @@
 
     s->current_pending = 1023;
     if (!s->enabled || !s->cpu_enabled) {
-        pic_set_irq_new(s->parent, s->parent_irq, 0);
+        qemu_irq_lower(s->parent_irq);
         return;
     }
     best_prio = 0x100;
@@ -102,12 +100,12 @@
         }
     }
     if (best_prio > s->priority_mask) {
-        pic_set_irq_new(s->parent, s->parent_irq, 0);
+        qemu_irq_lower(s->parent_irq);
     } else {
         s->current_pending = best_irq;
         if (best_prio < s->running_priority) {
             DPRINTF("Raised pending IRQ %d\n", best_irq);
-            pic_set_irq_new(s->parent, s->parent_irq, 1);
+            qemu_irq_raise(s->parent_irq);
         }
     }
 }
@@ -150,7 +148,7 @@
         DPRINTF("ACK no pending IRQ\n");
         return 1023;
     }
-    pic_set_irq_new(s->parent, s->parent_irq, 0);
+    qemu_irq_lower(s->parent_irq);
     s->last_active[new_irq] = s->running_irq;
     /* For level triggered interrupts we clear the pending bit while
        the interrupt is active.  */
@@ -520,16 +518,16 @@
     s->cpu_enabled = 0;
 }
 
-void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
+qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq)
 {
     gic_state *s;
+    qemu_irq *qi;
     int iomemtype;
 
     s = (gic_state *)qemu_mallocz(sizeof(gic_state));
     if (!s)
         return NULL;
-    s->handler = gic_set_irq;
-    s->parent = parent;
+    qi = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
     s->parent_irq = parent_irq;
     if (base != 0xffffffff) {
         iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
@@ -543,5 +541,5 @@
         s->base = 0;
     }
     gic_reset(s);
-    return s;
+    return qi;
 }
diff --git a/hw/arm_pic.c b/hw/arm_pic.c
index fbc2d67..dcc1198 100644
--- a/hw/arm_pic.c
+++ b/hw/arm_pic.c
@@ -11,11 +11,6 @@
 #include "arm_pic.h"
 
 /* Stub functions for hardware that doesn't exist.  */
-void pic_set_irq(int irq, int level)
-{
-    cpu_abort(cpu_single_env, "pic_set_irq");
-}
-
 void pic_info(void)
 {
 }
@@ -25,49 +20,29 @@
 }
 
 
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
-    arm_pic_handler *p = (arm_pic_handler *)opaque;
-    /* Call the real handler.  */
-    (*p)(opaque, irq, level);
-}
-
-/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller.
-   Input 0 is IRQ and input 1 is FIQ.  */
-typedef struct
-{
-    arm_pic_handler handler;
-    CPUState *cpu_env;
-} arm_pic_cpu_state;
-
+/* Input 0 is IRQ and input 1 is FIQ.  */
 static void arm_pic_cpu_handler(void *opaque, int irq, int level)
 {
-    arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque;
+    CPUState *env = (CPUState *)opaque;
     switch (irq) {
     case ARM_PIC_CPU_IRQ:
         if (level)
-            cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
         else
-            cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
         break;
     case ARM_PIC_CPU_FIQ:
         if (level)
-            cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
         else
-            cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
         break;
     default:
-        cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n",
-                  irq);
+        cpu_abort(env, "arm_pic_cpu_handler: Bad interrput line %d\n", irq);
     }
 }
 
-void *arm_pic_init_cpu(CPUState *env)
+qemu_irq *arm_pic_init_cpu(CPUState *env)
 {
-    arm_pic_cpu_state *s;
-    
-    s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state));
-    s->handler = arm_pic_cpu_handler;
-    s->cpu_env = env;
-    return s;
+    return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2);
 }
diff --git a/hw/arm_pic.h b/hw/arm_pic.h
index b299149..6c5ed17 100644
--- a/hw/arm_pic.h
+++ b/hw/arm_pic.h
@@ -14,14 +14,10 @@
 #ifndef ARM_INTERRUPT_H
 #define ARM_INTERRUPT_H 1
 
-/* The first element of an individual PIC state structures should
-   be a pointer to the handler routine.  */
-typedef void (*arm_pic_handler)(void *opaque, int irq, int level);
-
 /* The CPU is also modeled as an interrupt controller.  */
 #define ARM_PIC_CPU_IRQ 0
 #define ARM_PIC_CPU_FIQ 1
-void *arm_pic_init_cpu(CPUState *env);
+qemu_irq *arm_pic_init_cpu(CPUState *env);
 
 #endif /* !ARM_INTERRUPT_H */
 
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 068d0a0..3c6c0d2 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -32,8 +32,7 @@
     int raw_freq;
     int freq;
     int int_level;
-    void *pic;
-    int irq;
+    qemu_irq irq;
 } arm_timer_state;
 
 /* Calculate the new expiry time of the given timer.  */
@@ -85,9 +84,9 @@
     }
     /* Update interrupts.  */
     if (s->int_level && (s->control & TIMER_CTRL_IE)) {
-        pic_set_irq_new(s->pic, s->irq, 1);
+        qemu_irq_raise(s->irq);
     } else {
-        pic_set_irq_new(s->pic, s->irq, 0);
+        qemu_irq_lower(s->irq);
     }
 
     next = now;
@@ -215,12 +214,11 @@
     arm_timer_update((arm_timer_state *)opaque, now);
 }
 
-static void *arm_timer_init(uint32_t freq, void *pic, int irq)
+static void *arm_timer_init(uint32_t freq, qemu_irq irq)
 {
     arm_timer_state *s;
 
     s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
-    s->pic = pic;
     s->irq = irq;
     s->raw_freq = s->freq = 1000000;
     s->control = TIMER_CTRL_IE;
@@ -237,22 +235,19 @@
    Integrator/CP timer modules.  */
 
 typedef struct {
-    /* Include a pseudo-PIC device to merge the two interrupt sources.  */
-    arm_pic_handler handler;
     void *timer[2];
     int level[2];
     uint32_t base;
-    /* The output PIC device.  */
-    void *pic;
-    int irq;
+    qemu_irq irq;
 } sp804_state;
 
+/* Merge the IRQs from the two component devices.  */
 static void sp804_set_irq(void *opaque, int irq, int level)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     s->level[irq] = level;
-    pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]);
+    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 }
 
 static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
@@ -293,20 +288,20 @@
    sp804_write
 };
 
-void sp804_init(uint32_t base, void *pic, int irq)
+void sp804_init(uint32_t base, qemu_irq irq)
 {
     int iomemtype;
     sp804_state *s;
+    qemu_irq *qi;
 
     s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
-    s->handler = sp804_set_irq;
+    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     /* ??? The timers are actually configurable between 32kHz and 1MHz, but
        we don't implement that.  */
-    s->timer[0] = arm_timer_init(1000000, s, 0);
-    s->timer[1] = arm_timer_init(1000000, s, 1);
+    s->timer[0] = arm_timer_init(1000000, qi[0]);
+    s->timer[1] = arm_timer_init(1000000, qi[1]);
     iomemtype = cpu_register_io_memory(0, sp804_readfn,
                                        sp804_writefn, s);
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
@@ -362,7 +357,7 @@
    icp_pit_write
 };
 
-void icp_pit_init(uint32_t base, void *pic, int irq)
+void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
 {
     int iomemtype;
     icp_pit_state *s;
@@ -370,10 +365,10 @@
     s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
     s->base = base;
     /* Timer 0 runs at the system clock speed (40MHz).  */
-    s->timer[0] = arm_timer_init(40000000, pic, irq);
+    s->timer[0] = arm_timer_init(40000000, pic[irq]);
     /* The other two timers run at 1MHz.  */
-    s->timer[1] = arm_timer_init(1000000, pic, irq + 1);
-    s->timer[2] = arm_timer_init(1000000, pic, irq + 2);
+    s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
+    s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
 
     iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
                                        icp_pit_writefn, s);
diff --git a/hw/cs4231.c b/hw/cs4231.c
index a154685..6df881d 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -47,9 +47,6 @@
 #ifdef DEBUG_CS
 #define DPRINTF(fmt, args...)                           \
     do { printf("CS: " fmt , ##args); } while (0)
-#define pic_set_irq_new(intctl, irq, level)                             \
-    do { printf("CS: set_irq(%d): %d\n", (irq), (level));               \
-        pic_set_irq_new((intctl), (irq),(level));} while (0)
 #else
 #define DPRINTF(fmt, args...)
 #endif
diff --git a/hw/cuda.c b/hw/cuda.c
index f3c2b56..c290450 100644
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -124,9 +124,7 @@
     int data_in_index;
     int data_out_index;
 
-    SetIRQFunc *set_irq;
-    int irq;
-    void *irq_opaque;
+    qemu_irq irq;
     uint8_t autopoll;
     uint8_t data_in[128];
     uint8_t data_out[16];
@@ -145,9 +143,9 @@
 static void cuda_update_irq(CUDAState *s)
 {
     if (s->ifr & s->ier & (SR_INT | T1_INT)) {
-        s->set_irq(s->irq_opaque, s->irq, 1);
+        qemu_irq_raise(s->irq);
     } else {
-        s->set_irq(s->irq_opaque, s->irq, 0);
+        qemu_irq_lower(s->irq);
     }
 }
 
@@ -630,13 +628,11 @@
     &cuda_readl,
 };
 
-int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq)
+int cuda_init(qemu_irq irq)
 {
     CUDAState *s = &cuda_state;
     int cuda_mem_index;
 
-    s->set_irq = set_irq;
-    s->irq_opaque = irq_opaque;
     s->irq = irq;
 
     s->timers[0].index = 0;
diff --git a/hw/eepro100.c b/hw/eepro100.c
index ea18b89..bb57067 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -326,7 +326,7 @@
 {
     if (s->int_stat) {
         logout("interrupt disabled\n");
-        pci_set_irq(s->pci_dev, 0, 0);
+        qemu_irq_lower(s->pci_dev->irq[0]);
         s->int_stat = 0;
     }
 }
@@ -335,7 +335,7 @@
 {
     if (!s->int_stat) {
         logout("interrupt enabled\n");
-        pci_set_irq(s->pci_dev, 0, 1);
+        qemu_irq_raise(s->pci_dev->irq[0]);
         s->int_stat = 1;
     }
 }
diff --git a/hw/es1370.c b/hw/es1370.c
index 0d2d861..d607a94 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -324,7 +324,7 @@
     else {
         s->status = new_status & ~STAT_INTR;
     }
-    pci_set_irq (s->pci_dev, 0, !!level);
+    qemu_set_irq(s->pci_dev->irq[0], !!level);
 }
 
 static void es1370_reset (ES1370State *s)
@@ -350,7 +350,7 @@
             s->dac_voice[i] = NULL;
         }
     }
-    pci_set_irq (s->pci_dev, 0, 0);
+    qemu_irq_lower(s->pci_dev->irq[0]);
 }
 
 static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
diff --git a/hw/fdc.c b/hw/fdc.c
index 0012834..a12eb0a 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -368,7 +368,7 @@
     /* Controller's identification */
     uint8_t version;
     /* HW */
-    int irq_lvl;
+    qemu_irq irq;
     int dma_chann;
     uint32_t io_base;
     /* Controller state */
@@ -485,7 +485,7 @@
     fdctrl_write_mem,
 };
 
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, 
+fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, 
                        uint32_t io_base,
                        BlockDriverState **fds)
 {
@@ -501,7 +501,7 @@
                                           fdctrl_result_timer, fdctrl);
 
     fdctrl->version = 0x90; /* Intel 82078 controller */
-    fdctrl->irq_lvl = irq_lvl;
+    fdctrl->irq = irq;
     fdctrl->dma_chann = dma_chann;
     fdctrl->io_base = io_base;
     fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
@@ -542,7 +542,7 @@
 static void fdctrl_reset_irq (fdctrl_t *fdctrl)
 {
     FLOPPY_DPRINTF("Reset interrupt\n");
-    pic_set_irq(fdctrl->irq_lvl, 0);
+    qemu_set_irq(fdctrl->irq, 0);
     fdctrl->state &= ~FD_CTRL_INTR;
 }
 
@@ -557,7 +557,7 @@
     }
 #endif
     if (~(fdctrl->state & FD_CTRL_INTR)) {
-        pic_set_irq(fdctrl->irq_lvl, 1);
+        qemu_set_irq(fdctrl->irq, 1);
         fdctrl->state |= FD_CTRL_INTR;
     }
     FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 4004f99..74d4efc 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -80,12 +80,12 @@
     return (irq_num + (pci_dev->devfn >> 3)) & 3;
 }
 
-static void pci_grackle_set_irq(void *pic, int irq_num, int level)
+static void pci_grackle_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    heathrow_pic_set_irq(pic, irq_num + 8, level);
+    qemu_set_irq(pic[irq_num + 8], level);
 }
 
-PCIBus *pci_grackle_init(uint32_t base, void *pic)
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
 {
     GrackleState *s;
     PCIDevice *d;
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 9d6bb44..3300d40 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -520,7 +520,7 @@
 extern PCIDevice *piix4_dev;
 static int pci_irq_levels[4];
 
-static void pci_gt64120_set_irq(void *pic, int irq_num, int level)
+static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level)
 {
     int i, pic_irq, pic_level;
 
@@ -537,7 +537,7 @@
             if (pic_irq == piix4_dev->config[0x60 + i])
                 pic_level |= pci_irq_levels[i];
         }
-        pic_set_irq(pic_irq, pic_level);
+        qemu_set_irq(pic[pic_irq], pic_level);
     }
 }
 
@@ -608,7 +608,7 @@
     gt64120_pci_mapping(s);
 }
 
-PCIBus *pci_gt64120_init(void *pic)
+PCIBus *pci_gt64120_init(qemu_irq *pic)
 {
     GT64120State *s;
     PCIDevice *d;
diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
index 4980cef..c0edaea 100644
--- a/hw/heathrow_pic.c
+++ b/hw/heathrow_pic.c
@@ -32,9 +32,9 @@
     uint32_t level_triggered;
 } HeathrowPIC;
 
-struct HeathrowPICS {
+typedef struct HeathrowPICS {
     HeathrowPIC pics[2];
-};
+} HeathrowPICS;
 
 static inline int check_irq(HeathrowPIC *pic)
 {
@@ -130,7 +130,7 @@
 };
 
 
-void heathrow_pic_set_irq(void *opaque, int num, int level)
+static void heathrow_pic_set_irq(void *opaque, int num, int level)
 {
     HeathrowPICS *s = opaque;
     HeathrowPIC *pic;
@@ -156,7 +156,7 @@
     heathrow_pic_update(s);
 }
 
-HeathrowPICS *heathrow_pic_init(int *pmem_index)
+qemu_irq *heathrow_pic_init(int *pmem_index)
 {
     HeathrowPICS *s;
     
@@ -164,5 +164,5 @@
     s->pics[0].level_triggered = 0;
     s->pics[1].level_triggered = 0x1ff00000;
     *pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
-    return s;
+    return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
 }
diff --git a/hw/i8254.c b/hw/i8254.c
index a409763..f0b41d7 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -47,7 +47,7 @@
     /* irq handling */
     int64_t next_transition_time;
     QEMUTimer *irq_timer;
-    int irq;
+    qemu_irq irq;
 } PITChannelState;
 
 struct PITState {
@@ -366,7 +366,7 @@
         return;
     expire_time = pit_get_next_transition_time(s, current_time);
     irq_level = pit_get_out1(s, current_time);
-    pic_set_irq(s->irq, irq_level);
+    qemu_set_irq(s->irq, irq_level);
 #ifdef DEBUG_PIT
     printf("irq_level=%d next_delay=%f\n",
            irq_level, 
@@ -460,7 +460,7 @@
     }
 }
 
-PITState *pit_init(int base, int irq)
+PITState *pit_init(int base, qemu_irq irq)
 {
     PITState *pit = &pit_state;
     PITChannelState *s;
diff --git a/hw/i8259.c b/hw/i8259.c
index 631e411..4b25df3 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -54,7 +54,7 @@
     /* 0 is master pic, 1 is slave pic */
     /* XXX: better separation between the two pics */
     PicState pics[2];
-    IRQRequestFunc *irq_request;
+    qemu_irq parent_irq;
     void *irq_request_opaque;
     /* IOAPIC callback support */
     SetIRQFunc *alt_irq_func;
@@ -160,13 +160,13 @@
         }
         printf("pic: cpu_interrupt\n");
 #endif
-        s->irq_request(s->irq_request_opaque, 1);
+        qemu_irq_raise(s->parent_irq);
     }
 
 /* all targets should do this rather than acking the IRQ in the cpu */
 #if defined(TARGET_MIPS)
     else {
-        s->irq_request(s->irq_request_opaque, 0);
+        qemu_irq_lower(s->parent_irq);
     }
 #endif
 }
@@ -175,14 +175,14 @@
 int64_t irq_time[16];
 #endif
 
-void pic_set_irq_new(void *opaque, int irq, int level)
+void i8259_set_irq(void *opaque, int irq, int level)
 {
     PicState2 *s = opaque;
 
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
     if (level != irq_level[irq]) {
 #if defined(DEBUG_PIC)
-        printf("pic_set_irq: irq=%d level=%d\n", irq, level);
+        printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
 #endif
         irq_level[irq] = level;
 #ifdef DEBUG_IRQ_COUNT
@@ -203,12 +203,6 @@
     pic_update_irq(s);
 }
 
-/* obsolete function */
-void pic_set_irq(int irq, int level)
-{
-    pic_set_irq_new(isa_pic, irq, level);
-}
-
 /* acknowledge interrupt 'irq' */
 static inline void pic_intack(PicState *s, int irq)
 {
@@ -297,7 +291,7 @@
             /* init */
             pic_reset(s);
             /* deassert a pending interrupt */
-            s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
+            qemu_irq_lower(s->pics_state->parent_irq);
             s->init_state = 1;
             s->init4 = val & 1;
             s->single_mode = val & 2;
@@ -546,9 +540,10 @@
 #endif
 }
 
-PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
+qemu_irq *i8259_init(qemu_irq parent_irq)
 {
     PicState2 *s;
+
     s = qemu_mallocz(sizeof(PicState2));
     if (!s)
         return NULL;
@@ -556,11 +551,11 @@
     pic_init1(0xa0, 0x4d1, &s->pics[1]);
     s->pics[0].elcr_mask = 0xf8;
     s->pics[1].elcr_mask = 0xde;
-    s->irq_request = irq_request;
-    s->irq_request_opaque = irq_request_opaque;
+    s->parent_irq = parent_irq;
     s->pics[0].pics_state = s;
     s->pics[1].pics_state = s;
-    return s;
+    isa_pic = s;
+    return qemu_allocate_irqs(i8259_set_irq, s, 16);
 }
 
 void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
diff --git a/hw/ide.c b/hw/ide.c
index e608cc5..ffee8dd 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -300,9 +300,7 @@
     int mult_sectors;
     int identify_set;
     uint16_t identify_data[256];
-    SetIRQFunc *set_irq;
-    void *irq_opaque;
-    int irq;
+    qemu_irq irq;
     PCIDevice *pci_dev;
     struct BMDMAState *bmdma;
     int drive_serial;
@@ -575,7 +573,7 @@
         if (bm) {
             bm->status |= BM_STATUS_INT;
         }
-        s->set_irq(s->irq_opaque, s->irq, 1);
+        qemu_irq_raise(s->irq);
     }
 }
 
@@ -1889,7 +1887,7 @@
             ret = 0;
         else
             ret = s->status;
-        s->set_irq(s->irq_opaque, s->irq, 0);
+        qemu_irq_lower(s->irq);
         break;
     }
 #ifdef DEBUG_IDE
@@ -2084,7 +2082,7 @@
 
 static void ide_init2(IDEState *ide_state,
                       BlockDriverState *hd0, BlockDriverState *hd1,
-                      SetIRQFunc *set_irq, void *irq_opaque, int irq)
+                      qemu_irq irq)
 {
     IDEState *s;
     static int drive_serial = 1;
@@ -2155,8 +2153,6 @@
             }
         }
         s->drive_serial = drive_serial++;
-        s->set_irq = set_irq;
-        s->irq_opaque = irq_opaque;
         s->irq = irq;
         s->sector_write_timer = qemu_new_timer(vm_clock, 
                                                ide_sector_write_timer_cb, s);
@@ -2183,7 +2179,7 @@
 /***********************************************************/
 /* ISA IDE definitions */
 
-void isa_ide_init(int iobase, int iobase2, int irq,
+void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
                   BlockDriverState *hd0, BlockDriverState *hd1)
 {
     IDEState *ide_state;
@@ -2192,7 +2188,7 @@
     if (!ide_state)
         return;
     
-    ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq);
+    ide_init2(ide_state, hd0, hd1, irq);
     ide_init_ioport(ide_state, iobase, iobase2);
 }
 
@@ -2399,7 +2395,7 @@
                  !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
         ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
          !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
-    pci_set_irq((PCIDevice *)d, 0, pci_level);
+    qemu_set_irq(d->dev.irq[0], pci_level);
 }
 
 /* the PCI irq level is the logical OR of the two channels */
@@ -2423,6 +2419,7 @@
     PCIIDEState *d;
     uint8_t *pci_conf;
     int i;
+    qemu_irq *irq;
 
     d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", 
                                            sizeof(PCIIDEState),
@@ -2462,10 +2459,10 @@
     
     for(i = 0; i < 4; i++)
         d->ide_if[i].pci_dev = (PCIDevice *)d;
-    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
-              cmd646_set_irq, d, 0);
-    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
-              cmd646_set_irq, d, 1);
+
+    irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], irq[1]);
 }
 
 static void pci_ide_save(QEMUFile* f, void *opaque)
@@ -2592,7 +2589,8 @@
 
 /* hd_table must contain 4 block drivers */
 /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic)
 {
     PCIIDEState *d;
     uint8_t *pci_conf;
@@ -2619,10 +2617,8 @@
     pci_register_io_region((PCIDevice *)d, 4, 0x10, 
                            PCI_ADDRESS_SPACE_IO, bmdma_map);
 
-    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
-              pic_set_irq_new, isa_pic, 14);
-    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
-              pic_set_irq_new, isa_pic, 15);
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
     ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
     ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
 
@@ -2741,15 +2737,13 @@
 /* hd_table must contain 4 block drivers */
 /* PowerMac uses memory mapped registers, not I/O. Return the memory
    I/O index to access the ide. */
-int pmac_ide_init (BlockDriverState **hd_table,
-                   SetIRQFunc *set_irq, void *irq_opaque, int irq)
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq)
 {
     IDEState *ide_if;
     int pmac_ide_memory;
 
     ide_if = qemu_mallocz(sizeof(IDEState) * 2);
-    ide_init2(&ide_if[0], hd_table[0], hd_table[1],
-              set_irq, irq_opaque, irq);
+    ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq);
     
     pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
                                              pmac_ide_write, &ide_if[0]);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 1d8b722..34c3b81 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -267,28 +267,22 @@
 
 typedef struct icp_pic_state
 {
-  arm_pic_handler handler;
   uint32_t base;
   uint32_t level;
   uint32_t irq_enabled;
   uint32_t fiq_enabled;
-  void *parent;
-  int parent_irq;
-  int parent_fiq;
+  qemu_irq parent_irq;
+  qemu_irq parent_fiq;
 } icp_pic_state;
 
 static void icp_pic_update(icp_pic_state *s)
 {
     uint32_t flags;
 
-    if (s->parent_irq != -1) {
-        flags = (s->level & s->irq_enabled);
-        pic_set_irq_new(s->parent, s->parent_irq, flags != 0);
-    }
-    if (s->parent_fiq != -1) {
-        flags = (s->level & s->fiq_enabled);
-        pic_set_irq_new(s->parent, s->parent_fiq, flags != 0);
-    }
+    flags = (s->level & s->irq_enabled);
+    qemu_set_irq(s->parent_irq, flags != 0);
+    flags = (s->level & s->fiq_enabled);
+    qemu_set_irq(s->parent_fiq, flags != 0);
 }
 
 static void icp_pic_set_irq(void *opaque, int irq, int level)
@@ -345,11 +339,11 @@
         break;
     case 4: /* INT_SOFTSET */
         if (value & 1)
-            pic_set_irq_new(s, 0, 1);
+            icp_pic_set_irq(s, 0, 1);
         break;
     case 5: /* INT_SOFTCLR */
         if (value & 1)
-            pic_set_irq_new(s, 0, 0);
+            icp_pic_set_irq(s, 0, 0);
         break;
     case 10: /* FRQ_ENABLESET */
         s->fiq_enabled |= value;
@@ -380,25 +374,25 @@
    icp_pic_write
 };
 
-static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
-                                   int parent_irq, int parent_fiq)
+static qemu_irq *icp_pic_init(uint32_t base,
+                              qemu_irq parent_irq, qemu_irq parent_fiq)
 {
     icp_pic_state *s;
     int iomemtype;
+    qemu_irq *qi;
 
     s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
     if (!s)
         return NULL;
-    s->handler = icp_pic_set_irq;
+    qi = qemu_allocate_irqs(icp_pic_set_irq, s, 32);
     s->base = base;
-    s->parent = parent;
     s->parent_irq = parent_irq;
     s->parent_fiq = parent_fiq;
     iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
                                        icp_pic_writefn, s);
     cpu_register_physical_memory(base, 0x007fffff, iomemtype);
     /* ??? Save/restore.  */
-    return s;
+    return qi;
 }
 
 /* CP control registers.  */
@@ -475,8 +469,8 @@
 {
     CPUState *env;
     uint32_t bios_offset;
-    icp_pic_state *pic;
-    void *cpu_pic;
+    qemu_irq *pic;
+    qemu_irq *cpu_pic;
 
     env = cpu_init();
     if (!cpu_model)
@@ -492,25 +486,26 @@
 
     integratorcm_init(ram_size >> 20, bios_offset);
     cpu_pic = arm_pic_init_cpu(env);
-    pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
-    icp_pic_init(0xca000000, pic, 26, -1);
+    pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ],
+                       cpu_pic[ARM_PIC_CPU_FIQ]);
+    icp_pic_init(0xca000000, pic[26], NULL);
     icp_pit_init(0x13000000, pic, 5);
-    pl011_init(0x16000000, pic, 1, serial_hds[0]);
-    pl011_init(0x17000000, pic, 2, serial_hds[1]);
+    pl011_init(0x16000000, pic[1], serial_hds[0]);
+    pl011_init(0x17000000, pic[2], serial_hds[1]);
     icp_control_init(0xcb000000);
-    pl050_init(0x18000000, pic, 3, 0);
-    pl050_init(0x19000000, pic, 4, 1);
-    pl181_init(0x1c000000, sd_bdrv, pic, 23, 24);
+    pl050_init(0x18000000, pic[3], 0);
+    pl050_init(0x19000000, pic[4], 1);
+    pl181_init(0x1c000000, sd_bdrv, pic[23], pic[24]);
     if (nd_table[0].vlan) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "smc91c111") == 0) {
-            smc91c111_init(&nd_table[0], 0xc8000000, pic, 27);
+            smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
             exit (1);
         }
     }
-    pl110_init(ds, 0xc0000000, pic, 22, 0);
+    pl110_init(ds, 0xc0000000, pic[22], 0);
 
     arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
                     initrd_filename, 0x113);
diff --git a/hw/irq.c b/hw/irq.c
new file mode 100644
index 0000000..4bc8d80
--- /dev/null
+++ b/hw/irq.c
@@ -0,0 +1,57 @@
+/*
+ * QEMU IRQ/GPIO common code.
+ * 
+ * Copyright (c) 2007 CodeSourcery.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+struct IRQState {
+    qemu_irq_handler handler;
+    void *opaque;
+    int n;
+};
+
+void qemu_set_irq(qemu_irq irq, int level)
+{
+    if (!irq)
+        return;
+
+    irq->handler(irq->opaque, irq->n, level);
+}
+
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
+{
+    qemu_irq *s;
+    struct IRQState *p;
+    int i;
+
+    s = (qemu_irq *)qemu_mallocz(sizeof(qemu_irq) * n);
+    p = (struct IRQState *)qemu_mallocz(sizeof(struct IRQState) * n);
+    for (i = 0; i < n; i++) {
+        p->handler = handler;
+        p->opaque = opaque;
+        p->n = i;
+        s[i] = p;
+        p++;
+    }
+    return s;
+}
+
diff --git a/hw/irq.h b/hw/irq.h
new file mode 100644
index 0000000..652fd6a
--- /dev/null
+++ b/hw/irq.h
@@ -0,0 +1,21 @@
+/* Generic IRQ/GPIO pin infrastructure.  */
+
+typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
+
+typedef struct IRQState *qemu_irq;
+
+void qemu_set_irq(qemu_irq irq, int level);
+
+static inline void qemu_irq_raise(qemu_irq irq)
+{
+    qemu_set_irq(irq, 1);
+}
+
+static inline void qemu_irq_lower(qemu_irq irq)
+{
+    qemu_set_irq(irq, 0);
+}
+
+/* Returns an array of N IRQs.  */
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 193ff12..88806a6 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -374,7 +374,7 @@
                 level, s->dstat, s->sist1, s->sist0);
         last_level = level;
     }
-    pci_set_irq(&s->pci_dev, 0, level);
+    qemu_set_irq(s->pci_dev.irq[0], level);
 }
 
 /* Stop SCRIPTS execution and raise a SCSI interrupt.  */
diff --git a/hw/m48t59.c b/hw/m48t59.c
index daa1c52..1c61401 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -41,7 +41,7 @@
     /* Model parameters */
     int type; // 8 = m48t08, 59 = m48t59
     /* Hardware parameters */
-    int      IRQ;
+    qemu_irq IRQ;
     int mem_index;
     uint32_t mem_base;
     uint32_t io_base;
@@ -100,7 +100,7 @@
     uint64_t next_time;
     m48t59_t *NVRAM = opaque;
 
-    pic_set_irq(NVRAM->IRQ, 1);
+    qemu_set_irq(NVRAM->IRQ, 1);
     if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && 
 	(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
 	(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
@@ -137,7 +137,7 @@
 	next_time = 1 + mktime(&tm_now);
     }
     qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
-    pic_set_irq(NVRAM->IRQ, 0);
+    qemu_set_irq(NVRAM->IRQ, 0);
 }
 
 
@@ -173,8 +173,8 @@
         /* May it be a hw CPU Reset instead ? */
         qemu_system_reset_request();
     } else {
-	pic_set_irq(NVRAM->IRQ, 1);
-	pic_set_irq(NVRAM->IRQ, 0);
+	qemu_set_irq(NVRAM->IRQ, 1);
+	qemu_set_irq(NVRAM->IRQ, 0);
     }
 }
 
@@ -576,7 +576,7 @@
 };
 
 /* Initialisation routine */
-m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
+m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base,
                        uint32_t io_base, uint16_t size,
                        int type)
 {
diff --git a/hw/m48t59.h b/hw/m48t59.h
index af22dc1..df383e9 100644
--- a/hw/m48t59.h
+++ b/hw/m48t59.h
@@ -6,7 +6,7 @@
 void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val);
 uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr);
 void m48t59_toggle_lock (m48t59_t *NVRAM, int lock);
-m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
+m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base,
                        uint32_t io_base, uint16_t size,
                        int type);
 
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index bad4cbd..8b93574 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -54,7 +54,7 @@
     uint8_t cmos_data[128];
     uint8_t cmos_index;
     struct tm current_tm;
-    int irq;
+    qemu_irq irq;
     /* periodic timer */
     QEMUTimer *periodic_timer;
     int64_t next_periodic_time;
@@ -95,7 +95,7 @@
 
     rtc_timer_update(s, s->next_periodic_time);
     s->cmos_data[RTC_REG_C] |= 0xc0;
-    pic_set_irq(s->irq, 1);
+    qemu_irq_raise(s->irq);
 }
 
 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
@@ -314,14 +314,14 @@
              s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
 
             s->cmos_data[RTC_REG_C] |= 0xa0; 
-            pic_set_irq(s->irq, 1);
+            qemu_irq_raise(s->irq);
         }
     }
 
     /* update ended interrupt */
     if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
         s->cmos_data[RTC_REG_C] |= 0x90; 
-        pic_set_irq(s->irq, 1);
+        qemu_irq_raise(s->irq);
     }
 
     /* clear update in progress bit */
@@ -353,7 +353,7 @@
             break;
         case RTC_REG_C:
             ret = s->cmos_data[s->cmos_index];
-            pic_set_irq(s->irq, 0);
+            qemu_irq_lower(s->irq);
             s->cmos_data[RTC_REG_C] = 0x00; 
             break;
         default:
@@ -453,7 +453,7 @@
     return 0;
 }
 
-RTCState *rtc_init(int base, int irq)
+RTCState *rtc_init(int base, qemu_irq irq)
 {
     RTCState *s;
 
diff --git a/hw/mips_int.c b/hw/mips_int.c
index ed489f1..f4e22dc 100644
--- a/hw/mips_int.c
+++ b/hw/mips_int.c
@@ -17,7 +17,7 @@
         cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
 }
 
-void cpu_mips_irq_request(void *opaque, int irq, int level)
+static void cpu_mips_irq_request(void *opaque, int irq, int level)
 {
     CPUState *env = (CPUState *)opaque;
 
@@ -31,3 +31,14 @@
     }
     cpu_mips_update_irq(env);
 }
+
+void cpu_mips_irq_init_cpu(CPUState *env)
+{
+    qemu_irq *qi;
+    int i;
+
+    qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8);
+    for (i = 0; i < 8; i++) {
+        env->irq[i] = qi[i];
+    }
+}
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 97707c1..6102ecb 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -60,12 +60,6 @@
 
 static PITState *pit;
 
-/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
-static void pic_irq_request(void *opaque, int level)
-{
-    cpu_mips_irq_request(opaque, 2, level);
-}
-
 /* Malta FPGA */
 static void malta_fpga_update_display(void *opaque)
 {
@@ -451,8 +445,7 @@
 
     uart_chr = qemu_chr_open("vc");
     qemu_chr_printf(uart_chr, "CBUS UART\r\n");
-    s->uart = serial_mm_init(&cpu_mips_irq_request, env, base, 3, 2,
-                             uart_chr, 0);
+    s->uart = serial_mm_init(base, 3, env->irq[2], uart_chr, 0);
 
     malta_fpga_reset(s);
     qemu_register_reset(malta_fpga_reset, s);
@@ -676,6 +669,7 @@
     MaltaFPGAState *malta_fpga;
     int ret;
     mips_def_t *def;
+    qemu_irq *i8259;
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -729,6 +723,7 @@
     stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
 
     /* Init internal devices */
+    cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
     cpu_mips_irqctrl_init();
 
@@ -736,31 +731,32 @@
     malta_fpga = malta_fpga_init(0x1f000000LL, env);
 
     /* Interrupt controller */
-    isa_pic = pic_init(pic_irq_request, env);
+    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
+    i8259 = i8259_init(env->irq[2]);
 
     /* Northbridge */
-    pci_bus = pci_gt64120_init(isa_pic);
+    pci_bus = pci_gt64120_init(i8259);
 
     /* Southbridge */
     piix4_init(pci_bus, 80);
-    pci_piix3_ide_init(pci_bus, bs_table, 81);
+    pci_piix3_ide_init(pci_bus, bs_table, 81, i8259);
     usb_uhci_init(pci_bus, 82);
     piix4_pm_init(pci_bus, 83);
-    pit = pit_init(0x40, 0);
+    pit = pit_init(0x40, i8259[0]);
     DMA_init(0);
 
     /* Super I/O */
-    kbd_init();
-    rtc_state = rtc_init(0x70, 8);
+    i8042_init(i8259[1], i8259[12], 0x60);
+    rtc_state = rtc_init(0x70, i8259[8]);
     if (serial_hds[0])
-        serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
+        serial_init(0x3f8, i8259[4], serial_hds[0]);
     if (serial_hds[1])
-        serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 3, serial_hds[1]);
+        serial_init(0x2f8, i8259[3], serial_hds[1]);
     if (parallel_hds[0])
-        parallel_init(0x378, 7, parallel_hds[0]);
+        parallel_init(0x378, i8259[7], parallel_hds[0]);
     /* XXX: The floppy controller does not work correctly, something is
        probably wrong.
-    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
+    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */
 
     /* Sound card */
 #ifdef HAS_AUDIO
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 8fbddf3..f6af322 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -35,11 +35,6 @@
 static PITState *pit; /* PIT i8254 */
 
 /*i8254 PIT is attached to the IRQ0 at PIC i8259 */
-/*The PIC is attached to the MIPS CPU INT0 pin */
-static void pic_irq_request(void *opaque, int level)
-{
-    cpu_mips_irq_request(opaque, 2, level);
-}
 
 static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
 			      uint32_t val)
@@ -152,6 +147,7 @@
     RTCState *rtc_state;
     int i;
     mips_def_t *def;
+    qemu_irq *i8259;
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -203,22 +199,24 @@
     }
 
     /* Init CPU internal devices */
+    cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
     cpu_mips_irqctrl_init();
 
-    rtc_state = rtc_init(0x70, 8);
+    /* The PIC is attached to the MIPS CPU INT0 pin */
+    i8259 = i8259_init(env->irq[2]);
+
+    rtc_state = rtc_init(0x70, i8259[8]);
 
     /* Register 64 KB of ISA IO space at 0x14000000 */
     isa_mmio_init(0x14000000, 0x00010000);
     isa_mem_base = 0x10000000;
 
-    isa_pic = pic_init(pic_irq_request, env);
-    pit = pit_init(0x40, 0);
+    pit = pit_init(0x40, i8259[0]);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(&pic_set_irq_new, isa_pic,
-                        serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
         }
     }
 
@@ -228,7 +226,7 @@
     if (nd_table[0].vlan) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
-            isa_ne2000_init(0x300, 9, &nd_table[0]);
+            isa_ne2000_init(0x300, i8259[9], &nd_table[0]);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
             exit (1);
@@ -236,10 +234,10 @@
     }
 
     for(i = 0; i < 2; i++)
-        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
                      bs_table[2 * i], bs_table[2 * i + 1]);
 
-    kbd_init();
+    i8042_init(i8259[1], i8259[12], 0x60);
     ds1225y_init(0x9000, "nvram");
 }
 
diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index 9128cbf..bd89e5d 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -63,7 +63,7 @@
     cpu_mips_update_count(env, cpu_mips_get_count(env));
     if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
         env->CP0_Cause &= ~(1 << CP0Ca_TI);
-    cpu_mips_irq_request(env, 7, 0);
+    qemu_irq_lower(env->irq[7]);
 }
 
 static void mips_timer_cb (void *opaque)
@@ -79,7 +79,7 @@
     cpu_mips_update_count(env, cpu_mips_get_count(env));
     if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
         env->CP0_Cause |= 1 << CP0Ca_TI;
-    cpu_mips_irq_request(env, 7, 1);
+    qemu_irq_raise(env->irq[7]);
 }
 
 void cpu_mips_clock_init (CPUState *env)
diff --git a/hw/ne2000.c b/hw/ne2000.c
index df3f3b5..1830ab5 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -136,7 +136,7 @@
     uint8_t phys[6]; /* mac address */
     uint8_t curpag;
     uint8_t mult[8]; /* multicast mask array */
-    int irq;
+    qemu_irq irq;
     PCIDevice *pci_dev;
     VLANClientState *vc;
     uint8_t macaddr[6];
@@ -164,16 +164,10 @@
     int isr;
     isr = (s->isr & s->imr) & 0x7f;
 #if defined(DEBUG_NE2000)
-    printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
-	   s->irq, isr ? 1 : 0, s->isr, s->imr);
+    printf("NE2000: Set IRQ to %d (%02x %02x)\n",
+	   isr ? 1 : 0, s->isr, s->imr);
 #endif
-    if (s->irq == 16) {
-        /* PCI irq */
-        pci_set_irq(s->pci_dev, 0, (isr != 0));
-    } else {
-        /* ISA irq */
-        pic_set_irq(s->irq, (isr != 0));
-    }
+    qemu_set_irq(s->irq, (isr != 0));
 }
 
 #define POLYNOMIAL 0x04c11db6
@@ -647,6 +641,7 @@
 static void ne2000_save(QEMUFile* f,void* opaque)
 {
 	NE2000State* s=(NE2000State*)opaque;
+        int tmp;
 
         if (s->pci_dev)
             pci_device_save(s->pci_dev, f);
@@ -669,7 +664,8 @@
 	qemu_put_buffer(f, s->phys, 6);
 	qemu_put_8s(f, &s->curpag);
 	qemu_put_buffer(f, s->mult, 8);
-	qemu_put_be32s(f, &s->irq);
+        tmp = 0;
+	qemu_put_be32s(f, &tmp); /* ignored, was irq */
 	qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
 }
 
@@ -677,6 +673,7 @@
 {
 	NE2000State* s=(NE2000State*)opaque;
         int ret;
+        int tmp;
 
         if (version_id > 3)
             return -EINVAL;
@@ -709,13 +706,13 @@
 	qemu_get_buffer(f, s->phys, 6);
 	qemu_get_8s(f, &s->curpag);
 	qemu_get_buffer(f, s->mult, 8);
-	qemu_get_be32s(f, &s->irq);
+	qemu_get_be32s(f, &tmp); /* ignored */
 	qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
 
 	return 0;
 }
 
-void isa_ne2000_init(int base, int irq, NICInfo *nd)
+void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd)
 {
     NE2000State *s;
     
@@ -804,7 +801,7 @@
     pci_register_io_region(&d->dev, 0, 0x100, 
                            PCI_ADDRESS_SPACE_IO, ne2000_map);
     s = &d->ne2000;
-    s->irq = 16; // PCI interrupt
+    s->irq = d->dev.irq[0];
     s->pci_dev = (PCIDevice *)d;
     memcpy(s->macaddr, nd->macaddr, 6);
     ne2000_reset(s);
diff --git a/hw/openpic.c b/hw/openpic.c
index 1d91665..3481f2d 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -162,7 +162,7 @@
     CPUState *env;
 } IRQ_dst_t;
 
-struct openpic_t {
+typedef struct openpic_t {
     PCIDevice pci_dev;
     SetIRQFunc *set_irq;
     int mem_index;
@@ -196,7 +196,7 @@
 	uint32_t mbr;    /* Mailbox register */
     } mailboxes[MAX_MAILBOXES];
 #endif
-};
+} openpic_t;
 
 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
 {
@@ -321,7 +321,7 @@
     }
 }
 
-void openpic_set_irq(void *opaque, int n_IRQ, int level)
+static void openpic_set_irq(void *opaque, int n_IRQ, int level)
 {
     openpic_t *opp = opaque;
     IRQ_src_t *src;
@@ -964,7 +964,7 @@
 #endif
 }
 
-openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
+qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
                          int *pmem_index, int nb_cpus, CPUState **envp)
 {
     openpic_t *opp;
@@ -1024,5 +1024,5 @@
     openpic_reset(opp);
     if (pmem_index)
         *pmem_index = opp->mem_index;
-    return opp;
+    return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
 }
diff --git a/hw/parallel.c b/hw/parallel.c
index d751d7a..c927ddd 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -65,7 +65,7 @@
     uint8_t datar;
     uint8_t status;
     uint8_t control;
-    int irq;
+    qemu_irq irq;
     int irq_pending;
     CharDriverState *chr;
     int hw_driver;
@@ -76,9 +76,9 @@
 static void parallel_update_irq(ParallelState *s)
 {
     if (s->irq_pending)
-        pic_set_irq(s->irq, 1);
+        qemu_irq_raise(s->irq);
     else
-        pic_set_irq(s->irq, 0);
+        qemu_irq_lower(s->irq);
 }
 
 static void
@@ -401,7 +401,7 @@
 }
 
 /* If fd is zero, it means that the parallel device uses the console */
-ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
+ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr)
 {
     ParallelState *s;
     uint8_t dummy;
diff --git a/hw/pc.c b/hw/pc.c
index 332bb1c..e8dca4d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -49,15 +49,16 @@
 }
 
 /* MSDOS compatibility mode FPU exception support */
+static qemu_irq ferr_irq;
 /* XXX: add IGNNE support */
 void cpu_set_ferr(CPUX86State *s)
 {
-    pic_set_irq(13, 1);
+    qemu_irq_raise(ferr_irq);
 }
 
 static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
 {
-    pic_set_irq(13, 0);
+    qemu_irq_lower(ferr_irq);
 }
 
 /* TSC handling */
@@ -101,7 +102,7 @@
     return intno;
 }
 
-static void pic_irq_request(void *opaque, int level)
+static void pic_irq_request(void *opaque, int irq, int level)
 {
     CPUState *env = opaque;
     if (level)
@@ -403,7 +404,7 @@
 static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
 
 #ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus)
+static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
 {
     struct soundhw *c;
     int audio_enabled = 0;
@@ -420,7 +421,7 @@
             for (c = soundhw; c->name; ++c) {
                 if (c->enabled) {
                     if (c->isa) {
-                        c->init.init_isa (s);
+                        c->init.init_isa (s, pic);
                     }
                     else {
                         if (pci_bus) {
@@ -434,13 +435,13 @@
 }
 #endif
 
-static void pc_init_ne2k_isa(NICInfo *nd)
+static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
 {
     static int nb_ne2k = 0;
 
     if (nb_ne2k == NE2000_NB_MAX)
         return;
-    isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd);
+    isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
     nb_ne2k++;
 }
 
@@ -460,6 +461,8 @@
     int piix3_devfn = -1;
     CPUState *env;
     NICInfo *nd;
+    qemu_irq *cpu_irq;
+    qemu_irq *i8259;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -643,8 +646,12 @@
         stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
     }
 
+    cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
+    i8259 = i8259_init(cpu_irq[0]);
+    ferr_irq = i8259[13];
+
     if (pci_enabled) {
-        pci_bus = i440fx_init(&i440fx_state);
+        pci_bus = i440fx_init(&i440fx_state, i8259);
         piix3_devfn = piix3_init(pci_bus, -1);
     } else {
         pci_bus = NULL;
@@ -680,7 +687,7 @@
         }
     }
 
-    rtc_state = rtc_init(0x70, 8);
+    rtc_state = rtc_init(0x70, i8259[8]);
 
     register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
     register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
@@ -688,8 +695,7 @@
     if (pci_enabled) {
         ioapic = ioapic_init();
     }
-    isa_pic = pic_init(pic_irq_request, first_cpu);
-    pit = pit_init(0x40, 0);
+    pit = pit_init(0x40, i8259[0]);
     pcspk_init(pit);
     if (pci_enabled) {
         pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
@@ -697,14 +703,14 @@
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(&pic_set_irq_new, isa_pic,
-                        serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
         }
     }
 
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         if (parallel_hds[i]) {
-            parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
+            parallel_init(parallel_io[i], i8259[parallel_irq[i]],
+                          parallel_hds[i]);
         }
     }
 
@@ -718,7 +724,7 @@
             }
         }
         if (strcmp(nd->model, "ne2k_isa") == 0) {
-            pc_init_ne2k_isa(nd);
+            pc_init_ne2k_isa(nd, i8259);
         } else if (pci_enabled) {
             pci_nic_init(pci_bus, nd, -1);
         } else {
@@ -728,21 +734,21 @@
     }
 
     if (pci_enabled) {
-        pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
+        pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259);
     } else {
         for(i = 0; i < 2; i++) {
-            isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+            isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
                          bs_table[2 * i], bs_table[2 * i + 1]);
         }
     }
 
-    kbd_init();
+    i8042_init(i8259[1], i8259[12], 0x60);
     DMA_init(0);
 #ifdef HAS_AUDIO
-    audio_init(pci_enabled ? pci_bus : NULL);
+    audio_init(pci_enabled ? pci_bus : NULL, i8259);
 #endif
 
-    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
+    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
 
     cmos_init(ram_size, boot_device, bs_table);
 
diff --git a/hw/pci.c b/hw/pci.c
index 4d9eb03..b5dcbda 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -33,7 +33,7 @@
     uint32_t config_reg; /* XXX: suppress */
     /* low level pic */
     SetIRQFunc *low_set_irq;
-    void *irq_opaque;
+    qemu_irq *irq_opaque;
     PCIDevice *devices[256];
     PCIDevice *parent_dev;
     PCIBus *next;
@@ -43,13 +43,14 @@
 };
 
 static void pci_update_mappings(PCIDevice *d);
+static void pci_set_irq(void *opaque, int irq_num, int level);
 
 target_phys_addr_t pci_mem_base;
 static int pci_irq_index;
 static PCIBus *first_bus;
 
 PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                         void *pic, int devfn_min, int nirq)
+                         qemu_irq *pic, int devfn_min, int nirq)
 {
     PCIBus *bus;
     bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
@@ -129,6 +130,7 @@
     pci_dev->config_write = config_write;
     pci_dev->irq_index = pci_irq_index++;
     bus->devices[devfn] = pci_dev;
+    pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4);
     return pci_dev;
 }
 
@@ -433,8 +435,9 @@
 /* generic PCI irq support */
 
 /* 0 <= irq_num <= 3. level must be 0 or 1 */
-void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
+static void pci_set_irq(void *opaque, int irq_num, int level)
 {
+    PCIDevice *pci_dev = (PCIDevice *)opaque;
     PCIBus *bus;
     int change;
     
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 0ace3c0..a6f9d09 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -122,8 +122,8 @@
     void *kbd;
     void *mouse;
 
-    int irq_kbd;
-    int irq_mouse;
+    qemu_irq irq_kbd;
+    qemu_irq irq_mouse;
 } KBDState;
 
 KBDState kbd_state;
@@ -151,8 +151,8 @@
                 irq_kbd_level = 1;
         }
     }
-    pic_set_irq(s->irq_kbd, irq_kbd_level);
-    pic_set_irq(s->irq_mouse, irq_mouse_level);
+    qemu_set_irq(s->irq_kbd, irq_kbd_level);
+    qemu_set_irq(s->irq_mouse, irq_mouse_level);
 }
 
 static void kbd_update_kbd_irq(void *opaque, int level)
@@ -356,12 +356,12 @@
     return 0;
 }
 
-void i8042_init(int kbd_irq_lvl, int mouse_irq_lvl, uint32_t io_base)
+void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base)
 {
     KBDState *s = &kbd_state;
 
-    s->irq_kbd = kbd_irq_lvl;
-    s->irq_mouse = mouse_irq_lvl;
+    s->irq_kbd = kbd_irq;
+    s->irq_mouse = mouse_irq;
     
     kbd_reset(s);
     register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
@@ -377,8 +377,3 @@
 #endif
     qemu_register_reset(kbd_reset, s);
 }
-
-void kbd_init(void)
-{
-    return i8042_init(1, 12, 0x60);
-}
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 71b8cf2..f2130d7 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -69,7 +69,7 @@
     int xmit_pos, recv_pos;
     uint8_t buffer[4096];
     int tx_busy;
-    void (*set_irq_cb)(void *s, int isr);
+    qemu_irq irq;
     void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
                          uint8_t *buf, int len, int do_bswap);
     void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr,
@@ -823,7 +823,7 @@
         printf("pcnet: INTA=%d\n", isr);
 #endif
     }
-    s->set_irq_cb(s, isr);
+    qemu_set_irq(s->irq, isr);
     s->isr = isr;
 }
 
@@ -1940,13 +1940,6 @@
     cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index);
 }
 
-static void pcnet_pci_set_irq_cb(void *opaque, int isr)
-{
-    PCNetState *s = opaque;
-
-    pci_set_irq(&s->dev, 0, isr);
-}
-
 static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
                                       uint8_t *buf, int len, int do_bswap)
 {
@@ -2001,7 +1994,7 @@
     pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, 
                            PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
                            
-    d->set_irq_cb = pcnet_pci_set_irq_cb;
+    d->irq = d->dev.irq[0];
     d->phys_mem_read = pci_physical_memory_read;
     d->phys_mem_write = pci_physical_memory_write;
     d->pci_dev = &d->dev;
@@ -2025,14 +2018,7 @@
     (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
 };
 
-static void pcnet_sparc_set_irq_cb(void *opaque, int isr)
-{
-    PCNetState *s = opaque;
-
-    ledma_set_irq(s->dma_opaque, isr);
-}
-
-void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque)
+void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq)
 {
     PCNetState *d;
     int lance_io_memory;
@@ -2047,7 +2033,7 @@
     d->dma_opaque = dma_opaque;
     cpu_register_physical_memory(leaddr, 4, lance_io_memory);
 
-    d->set_irq_cb = pcnet_sparc_set_irq_cb;
+    d->irq = irq;
     d->phys_mem_read = ledma_memory_read;
     d->phys_mem_write = ledma_memory_write;
 
diff --git a/hw/pcspk.c b/hw/pcspk.c
index 0d52b31..2cbeff3 100644
--- a/hw/pcspk.c
+++ b/hw/pcspk.c
@@ -92,7 +92,7 @@
     }
 }
 
-int pcspk_audio_init(AudioState *audio)
+int pcspk_audio_init(AudioState *audio, qemu_irq *pic)
 {
     PCSpkState *s = &pcspk_state;
     audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 1b16652..095698c 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -40,7 +40,7 @@
     return s->config_reg;
 }
 
-static void piix3_set_irq(void *pic, int irq_num, int level);
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level);
 
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
@@ -155,14 +155,14 @@
     return 0;
 }
 
-PCIBus *i440fx_init(PCIDevice **pi440fx_state)
+PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
 {
     PCIBus *b;
     PCIDevice *d;
     I440FXState *s;
 
     s = qemu_mallocz(sizeof(I440FXState));
-    b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4);
+    b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
     s->bus = b;
 
     register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
@@ -204,7 +204,7 @@
 
 static int pci_irq_levels[4];
 
-static void piix3_set_irq(void *pic, int irq_num, int level)
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level)
 {
     int i, pic_irq, pic_level;
 
@@ -221,7 +221,7 @@
             if (pic_irq == piix3_dev->config[0x60 + i])
                 pic_level |= pci_irq_levels[i];
         }
-        pic_set_irq(pic_irq, pic_level);
+        qemu_set_irq(pic[pic_irq], pic_level);
     }
 }
 
diff --git a/hw/pl011.c b/hw/pl011.c
index fb7ab7b..29e551a 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -27,8 +27,7 @@
     int read_count;
     int read_trigger;
     CharDriverState *chr;
-    void *pic;
-    int irq;
+    qemu_irq irq;
 } pl011_state;
 
 #define PL011_INT_TX 0x20
@@ -47,7 +46,7 @@
     uint32_t flags;
     
     flags = s->int_level & s->int_enabled;
-    pic_set_irq_new(s->pic, s->irq, flags != 0);
+    qemu_set_irq(s->irq, flags != 0);
 }
 
 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
@@ -224,7 +223,7 @@
    pl011_write
 };
 
-void pl011_init(uint32_t base, void *pic, int irq,
+void pl011_init(uint32_t base, qemu_irq irq,
                 CharDriverState *chr)
 {
     int iomemtype;
@@ -235,7 +234,6 @@
                                        pl011_writefn, s);
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     s->chr = chr;
     s->read_trigger = 1;
diff --git a/hw/pl050.c b/hw/pl050.c
index 20451e5..eed7294 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -15,9 +15,8 @@
     uint32_t cr;
     uint32_t clk;
     uint32_t last;
-    void *pic;
     int pending;
-    int irq;
+    qemu_irq irq;
     int is_mouse;
 } pl050_state;
 
@@ -32,7 +31,7 @@
     s->pending = level;
     raise = (s->pending && (s->cr & 0x10) != 0)
             || (s->cr & 0x08) != 0;
-    pic_set_irq_new(s->pic, s->irq, raise);
+    qemu_set_irq(s->irq, raise);
 }
 
 static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
@@ -105,7 +104,7 @@
    pl050_write
 };
 
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse)
+void pl050_init(uint32_t base, qemu_irq irq, int is_mouse)
 {
     int iomemtype;
     pl050_state *s;
@@ -115,7 +114,6 @@
                                        pl050_writefn, s);
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     s->is_mouse = is_mouse;
     if (is_mouse)
diff --git a/hw/pl080.c b/hw/pl080.c
index 549b3bf..aab1cac 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -49,8 +49,7 @@
     int nchannels;
     /* Flag to avoid recursive DMA invocations.  */
     int running;
-    void *pic;
-    int irq;
+    qemu_irq irq;
 } pl080_state;
 
 static const unsigned char pl080_id[] =
@@ -63,9 +62,9 @@
 {
     if ((s->tc_int & s->tc_mask)
             || (s->err_int & s->err_mask))
-        pic_set_irq_new(s->pic, s->irq, 1);
+        qemu_irq_raise(s->irq);
     else
-        pic_set_irq_new(s->pic, s->irq, 1);
+        qemu_irq_lower(s->irq);
 }
 
 static void pl080_run(pl080_state *s)
@@ -325,7 +324,7 @@
 
 /* The PL080 and PL081 are the same except for the number of channels
    they implement (8 and 2 respectively).  */
-void *pl080_init(uint32_t base, void *pic, int irq, int nchannels)
+void *pl080_init(uint32_t base, qemu_irq irq, int nchannels)
 {
     int iomemtype;
     pl080_state *s;
@@ -335,7 +334,6 @@
                                        pl080_writefn, s);
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     s->nchannels = nchannels;
     /* ??? Save/restore.  */
diff --git a/hw/pl110.c b/hw/pl110.c
index 16de16c..92a7e0b 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -29,7 +29,6 @@
     DisplayState *ds;
     /* The Versatile/PB uses a slightly modified PL110 controller.  */
     int versatile;
-    void *pic;
     uint32_t timing[4];
     uint32_t cr;
     uint32_t upbase;
@@ -42,7 +41,7 @@
     int invalidate;
     uint32_t pallette[256];
     uint32_t raw_pallette[128];
-    int irq;
+    qemu_irq irq;
 } pl110_state;
 
 static const unsigned char pl110_id[] =
@@ -399,7 +398,7 @@
    pl110_write
 };
 
-void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq,
+void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq,
                  int versatile)
 {
     pl110_state *s;
@@ -412,7 +411,6 @@
     s->base = base;
     s->ds = ds;
     s->versatile = versatile;
-    s->pic = pic;
     s->irq = irq;
     graphic_console_init(ds, pl110_update_display, pl110_invalidate_display,
                          NULL, s);
diff --git a/hw/pl181.c b/hw/pl181.c
index 7c3b5de..cf731cc 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -40,8 +40,7 @@
     int fifo_pos;
     int fifo_len;
     uint32_t fifo[PL181_FIFO_LEN];
-    void *pic;
-    int irq[2];
+    qemu_irq irq[2];
 } pl181_state;
 
 #define PL181_CMD_INDEX     0x3f
@@ -96,7 +95,7 @@
 {
     int i;
     for (i = 0; i < 2; i++) {
-        pic_set_irq_new(s->pic, s->irq[i], (s->status & s->mask[i]) != 0);
+        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
     }
 }
 
@@ -425,7 +424,7 @@
 }
 
 void pl181_init(uint32_t base, BlockDriverState *bd,
-                void *pic, int irq0, int irq1)
+                qemu_irq irq0, qemu_irq irq1)
 {
     int iomemtype;
     pl181_state *s;
@@ -436,7 +435,6 @@
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
     s->base = base;
     s->card = sd_init(bd);
-    s->pic = pic;
     s->irq[0] = irq0;
     s->irq[1] = irq1;
     qemu_register_reset(pl181_reset, s);
diff --git a/hw/pl190.c b/hw/pl190.c
index 55c7180..12d935f 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -17,7 +17,6 @@
 #define PL190_NUM_PRIO 17
 
 typedef struct {
-    arm_pic_handler handler;
     uint32_t base;
     DisplayState *ds;
     uint32_t level;
@@ -33,9 +32,8 @@
     /* Current priority level.  */
     int priority;
     int prev_prio[PL190_NUM_PRIO];
-    void *parent;
-    int irq;
-    int fiq;
+    qemu_irq irq;
+    qemu_irq fiq;
 } pl190_state;
 
 static const unsigned char pl190_id[] =
@@ -53,9 +51,9 @@
     int set;
 
     set = (level & s->prio_mask[s->priority]) != 0;
-    pic_set_irq_new(s->parent, s->irq, set);
+    qemu_set_irq(s->irq, set);
     set = ((s->level | s->soft_level) & s->fiq_select) != 0;
-    pic_set_irq_new(s->parent, s->fiq, set);
+    qemu_set_irq(s->fiq, set);
 }
 
 static void pl190_set_irq(void *opaque, int irq, int level)
@@ -232,21 +230,21 @@
   pl190_update_vectors(s);
 }
 
-void *pl190_init(uint32_t base, void *parent, int irq, int fiq)
+qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq)
 {
     pl190_state *s;
+    qemu_irq *qi;
     int iomemtype;
 
     s = (pl190_state *)qemu_mallocz(sizeof(pl190_state));
     iomemtype = cpu_register_io_memory(0, pl190_readfn,
                                        pl190_writefn, s);
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
-    s->handler = pl190_set_irq;
+    qi = qemu_allocate_irqs(pl190_set_irq, s, 16);
     s->base = base;
-    s->parent = parent;
     s->irq = irq;
     s->fiq = fiq;
     pl190_reset(s);
     /* ??? Save/restore.  */
-    return s;
+    return qi;
 }
diff --git a/hw/ppc.c b/hw/ppc.c
index 273c75f..44555bd 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -31,8 +31,7 @@
 /* PowerPC internal fake IRQ controller
  * used to manage multiple sources hardware events
  */
-/* XXX: should be protected */
-void ppc_set_irq (void *opaque, int n_IRQ, int level)
+static void ppc_set_irq (void *opaque, int n_IRQ, int level)
 {
     CPUState *env;
 
@@ -51,6 +50,17 @@
 #endif
 }
 
+void cpu_ppc_irq_init_cpu(CPUState *env)
+{
+    qemu_irq *qi;
+    int i;
+
+    qi = qemu_allocate_irqs(ppc_set_irq, env, 32);
+    for (i = 0; i < 32; i++) {
+        env->irq[i] = qi[i];
+    }
+}
+
 /* External IRQ callback from OpenPIC IRQ controller */
 void ppc_openpic_irq (void *opaque, int n_IRQ, int level)
 {
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index 55ca6ac..18a1aab 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -264,11 +264,6 @@
     return 1; /* osi_call handled */
 }
 
-/* XXX: suppress that */
-static void pic_irq_request(void *opaque, int level)
-{
-}
-
 static uint8_t nvram_chksum(const uint8_t *buf, int n)
 {
     int sum, i;
@@ -303,8 +298,7 @@
 {
     CPUState *env;
     char buf[1024];
-    SetIRQFunc *set_irq;
-    void *pic;
+    qemu_irq *pic;
     m48t59_t *nvram;
     int unin_memory;
     int linux_boot, i;
@@ -314,6 +308,7 @@
     PCIBus *pci_bus;
     const char *arch_name;
     int vga_bios_size, bios_size;
+    qemu_irq *dummy_irq;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -335,6 +330,7 @@
         cpu_abort(env, "Unable to find PowerPC CPU definition\n");
     }
     cpu_ppc_register(env, def);
+    cpu_ppc_irq_init_cpu(env);
 
     /* Set time-base frequency to 100 Mhz */
     cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
@@ -416,17 +412,16 @@
 
         /* init basic PC hardware */
         pic = heathrow_pic_init(&heathrow_pic_mem_index);
-        set_irq = heathrow_pic_set_irq;
         pci_bus = pci_grackle_init(0xfec00000, pic);
         pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, 
                      ram_size, vga_ram_size,
                      vga_bios_offset, vga_bios_size);
 
         /* XXX: suppress that */
-        isa_pic = pic_init(pic_irq_request, NULL);
+        dummy_irq = i8259_init(NULL);
         
         /* XXX: use Mac Serial port */
-        serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
+        serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
         
         for(i = 0; i < nb_nics; i++) {
             if (!nd_table[i].model)
@@ -437,7 +432,7 @@
         pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
 
         /* cuda also initialize ADB */
-        cuda_mem_index = cuda_init(set_irq, pic, 0x12);
+        cuda_mem_index = cuda_init(pic[0x12]);
         
         adb_kbd_init(&adb_bus);
         adb_mouse_init(&adb_bus);
@@ -450,7 +445,7 @@
 
         macio_init(pci_bus, 0x0017);
 
-        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
+        nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
 
         arch_name = "HEATHROW";
     } else {
@@ -464,7 +459,6 @@
         cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
 
         pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env);
-        set_irq = openpic_set_irq;
         pci_bus = pci_pmac_init(pic);
         /* init basic PC hardware */
         pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
@@ -472,30 +466,30 @@
                      vga_bios_offset, vga_bios_size);
 
         /* XXX: suppress that */
-        isa_pic = pic_init(pic_irq_request, NULL);
+        dummy_irq = i8259_init(NULL);
 
         /* XXX: use Mac Serial port */
-        serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
+        serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
         for(i = 0; i < nb_nics; i++) {
             if (!nd_table[i].model)
                 nd_table[i].model = "ne2k_pci";
             pci_nic_init(pci_bus, &nd_table[i], -1);
         }
 #if 1
-        ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
-        ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
+        ide0_mem_index = pmac_ide_init(&bs_table[0], pic[0x13]);
+        ide1_mem_index = pmac_ide_init(&bs_table[2], pic[0x14]);
 #else
         pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
 #endif
         /* cuda also initialize ADB */
-        cuda_mem_index = cuda_init(set_irq, pic, 0x19);
+        cuda_mem_index = cuda_init(pic[0x19]);
         
         adb_kbd_init(&adb_bus);
         adb_mouse_init(&adb_bus);
         
         macio_init(pci_bus, 0x0022);
         
-        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
+        nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
         
         arch_name = "MAC99";
     }
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index d504b1c..225b531 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -96,11 +96,6 @@
     return 0;
 }
 
-static void pic_irq_request (void *opaque, int level)
-{
-    ppc_set_irq(opaque, PPC_INTERRUPT_EXT, level);
-}
-
 /* PCI intack register */
 /* Read-only register (?) */
 static void _PPC_intack_write (void *opaque,
@@ -532,6 +527,7 @@
     uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
     ppc_def_t *def;
     PCIBus *pci_bus;
+    qemu_irq *i8259;
 
     sysctrl = qemu_mallocz(sizeof(sysctrl_t));
     if (sysctrl == NULL)
@@ -552,6 +548,7 @@
         cpu_abort(env, "Unable to find PowerPC CPU definition\n");
     }
     cpu_ppc_register(env, def);
+    cpu_ppc_irq_init_cpu(env);
     /* Set time-base frequency to 100 Mhz */
     cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
 
@@ -602,7 +599,8 @@
     }
 
     isa_mem_base = 0xc0000000;
-    pci_bus = pci_prep_init();
+    i8259 = i8259_init(first_cpu->irq[PPC_INTERRUPT_EXT]);
+    pci_bus = pci_prep_init(i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
     PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read,
@@ -612,19 +610,18 @@
     /* init basic PC hardware */
     pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, 
                  vga_ram_size, 0, 0);
-    rtc_init(0x70, 8);
     //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
-    isa_pic = pic_init(pic_irq_request, first_cpu);
-    //    pit = pit_init(0x40, 0);
+    //    pit = pit_init(0x40, i8259[0]);
+    rtc_init(0x70, i8259[8]);
 
-    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
+    serial_init(0x3f8, i8259[4], serial_hds[0]);
     nb_nics1 = nb_nics;
     if (nb_nics1 > NE2000_NB_MAX)
         nb_nics1 = NE2000_NB_MAX;
     for(i = 0; i < nb_nics1; i++) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
-            isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
+            isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
             exit (1);
@@ -632,15 +629,15 @@
     }
 
     for(i = 0; i < 2; i++) {
-        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
                      bs_table[2 * i], bs_table[2 * i + 1]);
     }
-    kbd_init();
+    i8042_init(i8259[1], i8259[12], 0x60);
     DMA_init(1);
     //    AUD_init();
     //    SB16_init();
 
-    fdctrl_init(6, 2, 0, 0x3f0, fd_table);
+    fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
 
     /* Register speaker port */
     register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
@@ -667,7 +664,7 @@
         usb_ohci_init_pci(pci_bus, 3, -1);
     }
 
-    nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
+    nvram = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
     if (nvram == NULL)
         return;
     sysctrl->nvram = nvram;
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 3d93c06..be62b89 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -123,19 +123,19 @@
     return (irq_num + (pci_dev->devfn >> 3)) & 1;
 }
 
-static void prep_set_irq(void *pic, int irq_num, int level)
+static void prep_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    pic_set_irq(irq_num ? 11 : 9, level);
+    qemu_set_irq(pic[irq_num ? 11 : 9], level);
 }
 
-PCIBus *pci_prep_init(void)
+PCIBus *pci_prep_init(qemu_irq *pic)
 {
     PREPPCIState *s;
     PCIDevice *d;
     int PPC_io_memory;
 
     s = qemu_mallocz(sizeof(PREPPCIState));
-    s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0, 2);
+    s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 2);
 
     register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
     register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
diff --git a/hw/realview.c b/hw/realview.c
index 1d351bf..c15c231 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -18,7 +18,7 @@
                      const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
-    void *pic;
+    qemu_irq *pic;
     void *scsi_hba;
     PCIBus *pci_bus;
     NICInfo *nd;
@@ -38,24 +38,24 @@
     /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
        is nIRQ (there are inconsistencies).  However Linux 2.6.17 expects
        GIC1 to be nIRQ and ignores all the others, so do that for now.  */
-    pic = arm_gic_init(0x10040000, pic, ARM_PIC_CPU_IRQ);
-    pl050_init(0x10006000, pic, 20, 0);
-    pl050_init(0x10007000, pic, 21, 1);
+    pic = arm_gic_init(0x10040000, pic[ARM_PIC_CPU_IRQ]);
+    pl050_init(0x10006000, pic[20], 0);
+    pl050_init(0x10007000, pic[21], 1);
 
-    pl011_init(0x10009000, pic, 12, serial_hds[0]);
-    pl011_init(0x1000a000, pic, 13, serial_hds[1]);
-    pl011_init(0x1000b000, pic, 14, serial_hds[2]);
-    pl011_init(0x1000c000, pic, 15, serial_hds[3]);
+    pl011_init(0x10009000, pic[12], serial_hds[0]);
+    pl011_init(0x1000a000, pic[13], serial_hds[1]);
+    pl011_init(0x1000b000, pic[14], serial_hds[2]);
+    pl011_init(0x1000c000, pic[15], serial_hds[3]);
 
     /* DMA controller is optional, apparently.  */
-    pl080_init(0x10030000, pic, 24, 2);
+    pl080_init(0x10030000, pic[24], 2);
 
-    sp804_init(0x10011000, pic, 4);
-    sp804_init(0x10012000, pic, 5);
+    sp804_init(0x10011000, pic[4]);
+    sp804_init(0x10012000, pic[5]);
 
-    pl110_init(ds, 0x10020000, pic, 23, 1);
+    pl110_init(ds, 0x10020000, pic[23], 1);
 
-    pl181_init(0x10005000, sd_bdrv, pic, 17, 18);
+    pl181_init(0x10005000, sd_bdrv, pic[17], pic[18]);
 
     pci_bus = pci_vpb_init(pic, 48, 1);
     if (usb_enabled) {
@@ -72,7 +72,7 @@
         if (!nd->model)
             nd->model = done_smc ? "rtl8139" : "smc91c111";
         if (strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x4e000000, pic, 28);
+            smc91c111_init(nd, 0x4e000000, pic[28]);
         } else {
             pci_nic_init(pci_bus, nd, -1);
         }
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index ee5b9f5..d1e60e8 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -687,7 +687,7 @@
     DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n",
        isr ? 1 : 0, s->IntrStatus, s->IntrMask));
 
-    pci_set_irq(s->pci_dev, 0, (isr != 0));
+    qemu_set_irq(s->pci_dev->irq[0], (isr != 0));
 }
 
 #define POLYNOMIAL 0x04c11db6
diff --git a/hw/sb16.c b/hw/sb16.c
index 04325ac..1610b32 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -54,6 +54,7 @@
 
 typedef struct SB16State {
     QEMUSoundCard card;
+    qemu_irq *pic;
     int irq;
     int dma;
     int hdma;
@@ -187,7 +188,7 @@
 {
     SB16State *s = opaque;
     s->can_write = 1;
-    pic_set_irq (s->irq, 1);
+    qemu_irq_raise (s->pic[s->irq]);
 }
 
 #define DMA8_AUTO 1
@@ -595,7 +596,7 @@
         case 0xf3:
             dsp_out_data (s, 0xaa);
             s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
-            pic_set_irq (s->irq, 1);
+            qemu_irq_raise (s->pic[s->irq]);
             break;
 
         case 0xf9:
@@ -763,7 +764,7 @@
                 bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
                 ticks = (bytes * ticks_per_sec) / freq;
                 if (ticks < ticks_per_sec / 1024) {
-                    pic_set_irq (s->irq, 1);
+                    qemu_irq_raise (s->pic[s->irq]);
                 }
                 else {
                     if (s->aux_ts) {
@@ -855,10 +856,10 @@
 
 static void reset (SB16State *s)
 {
-    pic_set_irq (s->irq, 0);
+    qemu_irq_lower (s->pic[s->irq]);
     if (s->dma_auto) {
-        pic_set_irq (s->irq, 1);
-        pic_set_irq (s->irq, 0);
+        qemu_irq_raise (s->pic[s->irq]);
+        qemu_irq_lower (s->pic[s->irq]);
     }
 
     s->mixer_regs[0x82] = 0;
@@ -894,7 +895,7 @@
             if (s->v2x6 == 1) {
                 if (0 && s->highspeed) {
                     s->highspeed = 0;
-                    pic_set_irq (s->irq, 0);
+                    qemu_irq_lower (s->pic[s->irq]);
                     control (s, 0);
                 }
                 else {
@@ -1005,7 +1006,7 @@
         if (s->mixer_regs[0x82] & 1) {
             ack = 1;
             s->mixer_regs[0x82] &= 1;
-            pic_set_irq (s->irq, 0);
+            qemu_irq_lower (s->pic[s->irq]);
         }
         break;
 
@@ -1014,7 +1015,7 @@
         if (s->mixer_regs[0x82] & 2) {
             ack = 1;
             s->mixer_regs[0x82] &= 2;
-            pic_set_irq (s->irq, 0);
+            qemu_irq_lower (s->pic[s->irq]);
         }
         break;
 
@@ -1222,7 +1223,7 @@
 
     if (s->left_till_irq <= 0) {
         s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
-        pic_set_irq (s->irq, 1);
+        qemu_irq_raise (s->pic[s->irq]);
         if (0 == s->dma_auto) {
             control (s, 0);
             speaker (s, 0);
@@ -1389,7 +1390,7 @@
     return 0;
 }
 
-int SB16_init (AudioState *audio)
+int SB16_init (AudioState *audio, qemu_irq *pic)
 {
     SB16State *s;
     int i;
@@ -1409,6 +1410,7 @@
     }
 
     s->cmd = -1;
+    s->pic = pic;
     s->irq = conf.irq;
     s->dma = conf.dma;
     s->hdma = conf.hdma;
diff --git a/hw/serial.c b/hw/serial.c
index ed2a857..e0ff3a7 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -83,9 +83,7 @@
     /* NOTE: this hidden state is necessary for tx irq generation as
        it can be reset while reading iir */
     int thr_ipending;
-    SetIRQFunc *set_irq;
-    void *irq_opaque;
-    int irq;
+    qemu_irq irq;
     CharDriverState *chr;
     int last_break_enable;
     target_ulong base;
@@ -102,9 +100,9 @@
         s->iir = UART_IIR_NO_INT;
     }
     if (s->iir != UART_IIR_NO_INT) {
-        s->set_irq(s->irq_opaque, s->irq, 1);
+        qemu_irq_raise(s->irq);
     } else {
-        s->set_irq(s->irq_opaque, s->irq, 0);
+        qemu_irq_lower(s->irq);
     }
 }
 
@@ -345,16 +343,13 @@
 }
 
 /* If fd is zero, it means that the serial device uses the console */
-SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
-                         int base, int irq, CharDriverState *chr)
+SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr)
 {
     SerialState *s;
 
     s = qemu_mallocz(sizeof(SerialState));
     if (!s)
         return NULL;
-    s->set_irq = set_irq;
-    s->irq_opaque = opaque;
     s->irq = irq;
     s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
     s->iir = UART_IIR_NO_INT;
@@ -428,9 +423,8 @@
     &serial_mm_writel,
 };
 
-SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
-                             target_ulong base, int it_shift,
-                             int irq, CharDriverState *chr,
+SerialState *serial_mm_init (target_ulong base, int it_shift,
+                             qemu_irq irq, CharDriverState *chr,
                              int ioregister)
 {
     SerialState *s;
@@ -439,8 +433,6 @@
     s = qemu_mallocz(sizeof(SerialState));
     if (!s)
         return NULL;
-    s->set_irq = set_irq;
-    s->irq_opaque = opaque;
     s->irq = irq;
     s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
     s->iir = UART_IIR_NO_INT;
diff --git a/hw/shix.c b/hw/shix.c
index 5857d0e..000fd6a 100644
--- a/hw/shix.c
+++ b/hw/shix.c
@@ -42,11 +42,6 @@
     /* XXXXX */
 }
 
-void pic_set_irq(int irq, int level)
-{
-    /* XXXXX */
-}
-
 void pic_info()
 {
     /* XXXXX */
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index ed145a3..0c1eb58 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -277,7 +277,7 @@
  * "irq" here is the bit number in the system interrupt register to
  * separate serial and keyboard interrupts sharing a level.
  */
-void pic_set_irq_new(void *opaque, int irq, int level)
+void slavio_set_irq(void *opaque, int irq, int level)
 {
     SLAVIO_INTCTLState *s = opaque;
 
@@ -305,7 +305,7 @@
 
     DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
     if (cpu == (unsigned int)-1) {
-        pic_set_irq_new(opaque, irq, level);
+        slavio_set_irq(opaque, irq, level);
         return;
     }
     if (irq < 32) {
@@ -372,7 +372,8 @@
 }
 
 void *slavio_intctl_init(uint32_t addr, uint32_t addrg,
-                         const uint32_t *intbit_to_level)
+                         const uint32_t *intbit_to_level,
+                         qemu_irq **irq)
 {
     int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
     SLAVIO_INTCTLState *s;
@@ -392,6 +393,7 @@
 
     register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
     qemu_register_reset(slavio_intctl_reset, s);
+    *irq = qemu_allocate_irqs(slavio_set_irq, s, 32);
     slavio_intctl_reset(s);
     return s;
 }
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 1f4128e..9e7629e 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -36,19 +36,15 @@
 #ifdef DEBUG_MISC
 #define MISC_DPRINTF(fmt, args...) \
 do { printf("MISC: " fmt , ##args); } while (0)
-#define pic_set_irq_new(intctl, irq, level)                             \
-    do { printf("MISC: set_irq(%d): %d\n", (irq), (level));             \
-        pic_set_irq_new((intctl), (irq),(level));} while (0)
 #else
 #define MISC_DPRINTF(fmt, args...)
 #endif
 
 typedef struct MiscState {
-    int irq;
+    qemu_irq irq;
     uint8_t config;
     uint8_t aux1, aux2;
     uint8_t diag, mctrl, sysctrl;
-    void *intctl;
 } MiscState;
 
 #define MISC_MAXADDR 1
@@ -58,9 +54,11 @@
     MiscState *s = opaque;
 
     if ((s->aux2 & 0x4) && (s->config & 0x8)) {
-        pic_set_irq_new(s->intctl, s->irq, 1);
+        MISC_DPRINTF("Raise IRQ\n");
+        qemu_irq_raise(s->irq);
     } else {
-        pic_set_irq_new(s->intctl, s->irq, 0);
+        MISC_DPRINTF("Lower IRQ\n");
+        qemu_irq_lower(s->irq);
     }
 }
 
@@ -184,8 +182,10 @@
 static void slavio_misc_save(QEMUFile *f, void *opaque)
 {
     MiscState *s = opaque;
+    int tmp;
 
-    qemu_put_be32s(f, &s->irq);
+    tmp = 0;
+    qemu_put_be32s(f, &tmp); /* ignored, was IRQ.  */
     qemu_put_8s(f, &s->config);
     qemu_put_8s(f, &s->aux1);
     qemu_put_8s(f, &s->aux2);
@@ -197,11 +197,12 @@
 static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
 {
     MiscState *s = opaque;
+    int tmp;
 
     if (version_id != 1)
         return -EINVAL;
 
-    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &tmp);
     qemu_get_8s(f, &s->config);
     qemu_get_8s(f, &s->aux1);
     qemu_get_8s(f, &s->aux2);
@@ -211,7 +212,7 @@
     return 0;
 }
 
-void *slavio_misc_init(uint32_t base, int irq, void *intctl)
+void *slavio_misc_init(uint32_t base, qemu_irq irq)
 {
     int slavio_misc_io_memory;
     MiscState *s;
@@ -237,7 +238,6 @@
     cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
 
     s->irq = irq;
-    s->intctl = intctl;
 
     register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
     qemu_register_reset(slavio_misc_reset, s);
diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c
index 847710e..2ca3eed 100644
--- a/hw/slavio_serial.c
+++ b/hw/slavio_serial.c
@@ -52,9 +52,6 @@
 #ifdef DEBUG_SERIAL
 #define SER_DPRINTF(fmt, args...) \
 do { printf("SER: " fmt , ##args); } while (0)
-#define pic_set_irq_new(intctl, irq, level)                             \
-    do { printf("SER: set_irq(%d): %d\n", (irq), (level));              \
-        pic_set_irq_new((intctl), (irq),(level));} while (0)
 #else
 #define SER_DPRINTF(fmt, args...)
 #endif
@@ -89,7 +86,7 @@
 } SERIOQueue;
 
 typedef struct ChannelState {
-    int irq;
+    qemu_irq irq;
     int reg;
     int rxint, txint, rxint_under_svc, txint_under_svc;
     chn_id_t chn; // this channel, A (base+4) or B (base+0)
@@ -98,7 +95,6 @@
     uint8_t rx, tx, wregs[16], rregs[16];
     SERIOQueue queue;
     CharDriverState *chr;
-    void *intctl;
 } ChannelState;
 
 struct SerialState {
@@ -166,7 +162,8 @@
     irq = slavio_serial_update_irq_chn(s);
     irq |= slavio_serial_update_irq_chn(s->otherchn);
 
-    pic_set_irq_new(s->intctl, s->irq, irq);
+    SER_DPRINTF("IRQ = %d\n", irq);
+    qemu_set_irq(s->irq, irq);
 }
 
 static void slavio_serial_reset_chn(ChannelState *s)
@@ -494,7 +491,9 @@
 
 static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
 {
-    qemu_put_be32s(f, &s->irq);
+    int tmp;
+    tmp = 0;
+    qemu_put_be32s(f, &tmp); /* unused, was IRQ.  */
     qemu_put_be32s(f, &s->reg);
     qemu_put_be32s(f, &s->rxint);
     qemu_put_be32s(f, &s->txint);
@@ -516,10 +515,12 @@
 
 static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
 {
+    int tmp;
+
     if (version_id > 2)
         return -EINVAL;
 
-    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &tmp); /* unused */
     qemu_get_be32s(f, &s->reg);
     qemu_get_be32s(f, &s->rxint);
     qemu_get_be32s(f, &s->txint);
@@ -547,8 +548,8 @@
 
 }
 
-SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1,
-                                CharDriverState *chr2, void *intctl)
+SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1,
+                                CharDriverState *chr2)
 {
     int slavio_serial_io_memory, i;
     SerialState *s;
@@ -567,7 +568,6 @@
 	s->chn[i].irq = irq;
 	s->chn[i].chn = 1 - i;
 	s->chn[i].type = ser;
-        s->chn[i].intctl = intctl;
 	if (s->chn[i].chr) {
 	    qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
                                   serial_receive1, serial_event, &s->chn[i]);
@@ -665,7 +665,7 @@
     put_queue(s, 0);
 }
 
-void slavio_serial_ms_kbd_init(int base, int irq, void *intctl)
+void slavio_serial_ms_kbd_init(int base, qemu_irq irq)
 {
     int slavio_serial_io_memory, i;
     SerialState *s;
@@ -677,7 +677,6 @@
 	s->chn[i].irq = irq;
 	s->chn[i].chn = 1 - i;
 	s->chn[i].chr = NULL;
-        s->chn[i].intctl = intctl;
     }
     s->chn[0].otherchn = &s->chn[1];
     s->chn[1].otherchn = &s->chn[0];
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 59fe683..8898afc 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -28,9 +28,6 @@
 #ifdef DEBUG_TIMER
 #define DPRINTF(fmt, args...) \
 do { printf("TIMER: " fmt , ##args); } while (0)
-#define pic_set_irq_new(intctl, irq, level)                             \
-    do { printf("TIMER: set_irq(%d): %d\n", (irq), (level));            \
-        pic_set_irq_new((intctl), (irq),(level));} while (0)
 #else
 #define DPRINTF(fmt, args...)
 #endif
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 855a9b1..d90ab32 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -24,8 +24,7 @@
     uint16_t gpr;
     uint16_t ptr;
     uint16_t ercv;
-    void *pic;
-    int irq;
+    qemu_irq irq;
     int bank;
     int packet_num;
     int tx_alloc;
@@ -86,7 +85,7 @@
     if (s->tx_fifo_done_len != 0)
         s->int_level |= INT_TX;
     level = (s->int_level & s->int_mask) != 0;
-    pic_set_irq_new(s->pic, s->irq, level);
+    qemu_set_irq(s->irq, level);
 }
 
 /* Try to allocate a packet.  Returns 0x80 on failure.  */
@@ -693,7 +692,7 @@
     smc91c111_writel
 };
 
-void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
+void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
 {
     smc91c111_state *s;
     int iomemtype;
@@ -703,7 +702,6 @@
                                        smc91c111_writefn, s);
     cpu_register_physical_memory(base, 16, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     memcpy(s->macaddr, nd->macaddr, 6);
 
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index b17a12b..8480c8d 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -37,9 +37,6 @@
 #ifdef DEBUG_DMA
 #define DPRINTF(fmt, args...) \
 do { printf("DMA: " fmt , ##args); } while (0)
-#define pic_set_irq_new(ctl, irq, level)                                \
-    do { printf("DMA: set_irq(%d): %d\n", (irq), (level));              \
-        pic_set_irq_new((ctl), (irq),(level));} while (0)
 #else
 #define DPRINTF(fmt, args...)
 #endif
@@ -58,17 +55,11 @@
 
 struct DMAState {
     uint32_t dmaregs[DMA_REGS];
-    int espirq, leirq;
-    void *iommu, *esp_opaque, *lance_opaque, *intctl;
+    qemu_irq espirq, leirq;
+    void *iommu, *esp_opaque, *lance_opaque;
+    qemu_irq *pic;
 };
 
-void ledma_set_irq(void *opaque, int isr)
-{
-    DMAState *s = opaque;
-
-    pic_set_irq_new(s->intctl, s->leirq, isr);
-}
-
 /* Note: on sparc, the lance 16 bit bus is swapped */
 void ledma_memory_read(void *opaque, target_phys_addr_t addr, 
                        uint8_t *buf, int len, int do_bswap)
@@ -125,8 +116,9 @@
 {
     DMAState *s = opaque;
 
+    DPRINTF("Raise ESP IRQ\n");
     s->dmaregs[0] |= DMA_INTR;
-    pic_set_irq_new(s->intctl, s->espirq, 1);
+    qemu_irq_raise(s->espirq);
 }
 
 void espdma_clear_irq(void *opaque)
@@ -134,7 +126,8 @@
     DMAState *s = opaque;
 
     s->dmaregs[0] &= ~DMA_INTR;
-    pic_set_irq_new(s->intctl, s->espirq, 0);
+    DPRINTF("Lower ESP IRQ\n");
+    qemu_irq_lower(s->espirq);
 }
 
 void espdma_memory_read(void *opaque, uint8_t *buf, int len)
@@ -179,8 +172,10 @@
     DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->dmaregs[saddr], val);
     switch (saddr) {
     case 0:
-        if (!(val & DMA_INTREN))
-            pic_set_irq_new(s->intctl, s->espirq, 0);
+        if (!(val & DMA_INTREN)) {
+            DPRINTF("Lower ESP IRQ\n");
+            qemu_irq_lower(s->espirq);
+        }
         if (val & DMA_RESET) {
             esp_reset(s->esp_opaque);
         } else if (val & 0x40) {
@@ -194,8 +189,12 @@
         s->dmaregs[0] |= DMA_LOADED;
         break;
     case 4:
-        if (!(val & DMA_INTREN))
-            pic_set_irq_new(s->intctl, s->leirq, 0);
+        /* ??? Should this mask out the lance IRQ?  The NIC may re-assert
+           this IRQ unexpectedly.  */
+        if (!(val & DMA_INTREN)) {
+            DPRINTF("Lower Lance IRQ\n");
+            qemu_irq_lower(s->leirq);
+        }
         if (val & DMA_RESET)
             pcnet_h_reset(s->lance_opaque);
         val &= 0x0fffffff;
@@ -250,7 +249,8 @@
     return 0;
 }
 
-void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void *intctl)
+void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq,
+                       void *iommu)
 {
     DMAState *s;
     int dma_io_memory;
@@ -262,7 +262,6 @@
     s->espirq = espirq;
     s->leirq = leirq;
     s->iommu = iommu;
-    s->intctl = intctl;
 
     dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s);
     cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory);
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 49e9c22..b41dd25 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -182,11 +182,6 @@
     slavio_irq_info(slavio_intctl);
 }
 
-void pic_set_irq(int irq, int level)
-{
-    pic_set_irq_new(slavio_intctl, irq, level);
-}
-
 static void *slavio_misc;
 
 void qemu_system_powerdown(void)
@@ -208,6 +203,7 @@
     unsigned int i;
     void *iommu, *dma, *main_esp, *main_lance = NULL;
     const sparc_def_t *def;
+    qemu_irq *slavio_irq;
 
     /* init CPUs */
     sparc_find_by_name(cpu_model, &def);
@@ -230,38 +226,40 @@
     iommu = iommu_init(hwdef->iommu_base);
     slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
                                        hwdef->intctl_base + 0x10000,
-                                       &hwdef->intbit_to_level[0]);
+                                       &hwdef->intbit_to_level[0],
+                                       &slavio_irq);
     for(i = 0; i < smp_cpus; i++) {
         slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
     }
-    dma = sparc32_dma_init(hwdef->dma_base, hwdef->esp_irq,
-                           hwdef->le_irq, iommu, slavio_intctl);
+    dma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
+                           slavio_irq[hwdef->le_irq], iommu);
 
     tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size,
              hwdef->vram_size, graphic_width, graphic_height);
     if (nd_table[0].vlan) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "lance") == 0) {
-            main_lance = lance_init(&nd_table[0], hwdef->le_base, dma);
+            main_lance = lance_init(&nd_table[0], hwdef->le_base, dma,
+                                    slavio_irq[hwdef->le_irq]);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
             exit (1);
         }
     }
-    nvram = m48t59_init(0, hwdef->nvram_base, 0, hwdef->nvram_size, 8);
+    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
+                        hwdef->nvram_size, 8);
     for (i = 0; i < MAX_CPUS; i++) {
         slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE,
                           hwdef->clock_irq, 0, i, slavio_intctl);
     }
     slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2,
                       (unsigned int)-1, slavio_intctl);
-    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, hwdef->ms_kb_irq,
-                              slavio_intctl);
+    slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]);
     // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
     // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
-    slavio_serial_init(hwdef->serial_base, hwdef->ser_irq,
-                       serial_hds[1], serial_hds[0], slavio_intctl);
-    fdctrl_init(hwdef->fd_irq, 0, 1, hwdef->fd_base, fd_table);
+    slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq],
+                       serial_hds[1], serial_hds[0]);
+    fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table);
     main_esp = esp_init(bs_table, hwdef->esp_base, dma);
 
     for (i = 0; i < MAX_DISKS; i++) {
@@ -270,8 +268,8 @@
         }
     }
 
-    slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->me_irq,
-                                   slavio_intctl);
+    slavio_misc = slavio_misc_init(hwdef->slavio_base, 
+                                   slavio_irq[hwdef->me_irq]);
     if (hwdef->cs_base != (target_ulong)-1)
         cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
     sparc32_dma_set_reset_data(dma, main_esp, main_lance);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index e536c48..b10722f 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -223,14 +223,6 @@
 {
 }
 
-void pic_set_irq(int irq, int level)
-{
-}
-
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
-}
-
 void qemu_system_powerdown(void)
 {
 }
@@ -340,14 +332,13 @@
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(&pic_set_irq_new, NULL,
-                        serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(serial_io[i], NULL/*serial_irq[i]*/, serial_hds[i]);
         }
     }
 
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         if (parallel_hds[i]) {
-            parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
+            parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/, parallel_hds[i]);
         }
     }
 
@@ -358,9 +349,10 @@
     }
 
     pci_cmd646_ide_init(pci_bus, bs_table, 1);
-    kbd_init();
-    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
-    nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
+    /* FIXME: wire up interrupts.  */
+    i8042_init(NULL/*1*/, NULL/*12*/, 0x60);
+    floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table);
+    nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59);
     sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device,
                          KERNEL_LOAD_ADDR, kernel_size,
                          kernel_cmdline,
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 6448a6f..f32d195 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -146,12 +146,12 @@
     return (irq_num + (pci_dev->devfn >> 3)) & 3;
 }
 
-static void pci_unin_set_irq(void *pic, int irq_num, int level)
+static void pci_unin_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    openpic_set_irq(pic, irq_num + 8, level);
+    qemu_set_irq(pic[irq_num + 8], level);
 }
 
-PCIBus *pci_pmac_init(void *pic)
+PCIBus *pci_pmac_init(qemu_irq *pic)
 {
     UNINState *s;
     PCIDevice *d;
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index a4f8aa6..6808579 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -59,8 +59,7 @@
 };
 
 typedef struct {
-    void *pic;
-    int irq;
+    qemu_irq irq;
     enum ohci_type type;
     target_phys_addr_t mem_base;
     int mem;
@@ -282,10 +281,7 @@
         (ohci->intr_status & ohci->intr))
         level = 1;
 
-    if (ohci->type == OHCI_TYPE_PCI)
-      pci_set_irq((PCIDevice *)ohci->pic, ohci->irq, level);
-    else
-      pic_set_irq_new(ohci->pic, ohci->irq, level);
+    qemu_set_irq(ohci->irq, level);
 }
 
 /* Set an interrupt */
@@ -1263,7 +1259,7 @@
 };
 
 static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
-            void *pic, int irq, enum ohci_type type, const char *name)
+            qemu_irq irq, enum ohci_type type, const char *name)
 {
     int i;
 
@@ -1286,7 +1282,6 @@
     ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
     ohci->name = name;
 
-    ohci->pic = pic;
     ohci->irq = irq;
     ohci->type = type;
 
@@ -1334,19 +1329,19 @@
     ohci->pci_dev.config[0x0b] = 0xc;
     ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
 
-    usb_ohci_init(&ohci->state, num_ports, devfn, &ohci->pci_dev,
-                  0, OHCI_TYPE_PCI, ohci->pci_dev.name);
+    usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
+                  OHCI_TYPE_PCI, ohci->pci_dev.name);
 
     pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
                            PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
 }
 
 void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
-            void *pic, int irq)
+                       qemu_irq irq)
 {
     OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
 
-    usb_ohci_init(ohci, num_ports, devfn, pic, irq,
+    usb_ohci_init(ohci, num_ports, devfn, irq,
                   OHCI_TYPE_PXA, "OHCI USB");
     ohci->mem_base = base;
 
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 509c54f..638b199 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -119,7 +119,7 @@
     } else {
         level = 0;
     }
-    pci_set_irq(&s->dev, 3, level);
+    qemu_set_irq(s->dev.irq[3], level);
 }
 
 static void uhci_reset(UHCIState *s)
diff --git a/hw/usb.h b/hw/usb.h
index bd77eea..02a7355 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -208,7 +208,7 @@
 /* usb-ohci.c */
 void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn);
 void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
-                       void *pic, int irq);
+                       qemu_irq irq);
 
 /* usb-linux.c */
 USBDevice *usb_host_device_open(const char *devname);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 32854c2..98a2f4f 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -84,12 +84,12 @@
     return irq_num;
 }
 
-static void pci_vpb_set_irq(void *pic, int irq_num, int level)
+static void pci_vpb_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    pic_set_irq_new(pic, pci_vpb_irq + irq_num, level);
+    qemu_set_irq(pic[pci_vpb_irq + irq_num], level);
 }
 
-PCIBus *pci_vpb_init(void *pic, int irq, int realview)
+PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview)
 {
     PCIBus *s;
     PCIDevice *d;
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index a91d7ef..c090816 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -14,12 +14,11 @@
 
 typedef struct vpb_sic_state
 {
-  arm_pic_handler handler;
   uint32_t base;
   uint32_t level;
   uint32_t mask;
   uint32_t pic_enable;
-  void *parent;
+  qemu_irq *parent;
   int irq;
 } vpb_sic_state;
 
@@ -28,7 +27,7 @@
     uint32_t flags;
 
     flags = s->level & s->mask;
-    pic_set_irq_new(s->parent, s->irq, flags != 0);
+    qemu_set_irq(s->parent[s->irq], flags != 0);
 }
 
 static void vpb_sic_update_pic(vpb_sic_state *s)
@@ -40,7 +39,7 @@
         mask = 1u << i;
         if (!(s->pic_enable & mask))
             continue;
-        pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
+        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
     }
 }
 
@@ -52,7 +51,7 @@
     else
         s->level &= ~(1u << irq);
     if (s->pic_enable & (1u << irq))
-        pic_set_irq_new(s->parent, irq, level);
+        qemu_set_irq(s->parent[irq], level);
     vpb_sic_update(s);
 }
 
@@ -126,15 +125,16 @@
    vpb_sic_write
 };
 
-static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
+static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq)
 {
     vpb_sic_state *s;
+    qemu_irq *qi;
     int iomemtype;
 
     s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
     if (!s)
         return NULL;
-    s->handler = vpb_sic_set_irq;
+    qi = qemu_allocate_irqs(vpb_sic_set_irq, s, 32);
     s->base = base;
     s->parent = parent;
     s->irq = irq;
@@ -142,7 +142,7 @@
                                        vpb_sic_writefn, s);
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
     /* ??? Save/restore.  */
-    return s;
+    return qi;
 }
 
 /* Board init.  */
@@ -158,8 +158,8 @@
                      int board_id)
 {
     CPUState *env;
-    void *pic;
-    void *sic;
+    qemu_irq *pic;
+    qemu_irq *sic;
     void *scsi_hba;
     PCIBus *pci_bus;
     NICInfo *nd;
@@ -176,10 +176,10 @@
 
     arm_sysctl_init(0x10000000, 0x41007004);
     pic = arm_pic_init_cpu(env);
-    pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
+    pic = pl190_init(0x10140000, pic[0], pic[1]);
     sic = vpb_sic_init(0x10003000, pic, 31);
-    pl050_init(0x10006000, sic, 3, 0);
-    pl050_init(0x10007000, sic, 4, 1);
+    pl050_init(0x10006000, sic[3], 0);
+    pl050_init(0x10007000, sic[4], 1);
 
     pci_bus = pci_vpb_init(sic, 27, 0);
     /* The Versatile PCI bridge does not provide access to PCI IO space,
@@ -189,7 +189,7 @@
         if (!nd->model)
             nd->model = done_smc ? "rtl8139" : "smc91c111";
         if (strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x10010000, sic, 25);
+            smc91c111_init(nd, 0x10010000, sic[25]);
         } else {
             pci_nic_init(pci_bus, nd, -1);
         }
@@ -204,20 +204,20 @@
         }
     }
 
-    pl011_init(0x101f1000, pic, 12, serial_hds[0]);
-    pl011_init(0x101f2000, pic, 13, serial_hds[1]);
-    pl011_init(0x101f3000, pic, 14, serial_hds[2]);
-    pl011_init(0x10009000, sic, 6, serial_hds[3]);
+    pl011_init(0x101f1000, pic[12], serial_hds[0]);
+    pl011_init(0x101f2000, pic[13], serial_hds[1]);
+    pl011_init(0x101f3000, pic[14], serial_hds[2]);
+    pl011_init(0x10009000, sic[6], serial_hds[3]);
 
-    pl080_init(0x10130000, pic, 17, 8);
-    sp804_init(0x101e2000, pic, 4);
-    sp804_init(0x101e3000, pic, 5);
+    pl080_init(0x10130000, pic[17], 8);
+    sp804_init(0x101e2000, pic[4]);
+    sp804_init(0x101e3000, pic[5]);
 
     /* The versatile/PB actually has a modified Color LCD controller
        that includes hardware cursor support from the PL111.  */
-    pl110_init(ds, 0x10120000, pic, 16, 1);
+    pl110_init(ds, 0x10120000, pic[16], 1);
 
-    pl181_init(0x10005000, sd_bdrv, sic, 22, 1);
+    pl181_init(0x10005000, sd_bdrv, sic[22], sic[1]);
 #if 0
     /* Disabled because there's no way of specifying a block device.  */
     pl181_init(0x1000b000, NULL, sic, 23, 2);