Implement qemu_reserve_isa_irq() and fix the code to call it whenever
an ISA IRQ is claimed.

The old QEMU code simply claimed ISA IRQs without keeping track of it
in any way. This patch tries to catch the culprits and make them call
qemu_reserve_isa_irq() where appropriate.

This allows us to keep track of which IRQs are available for PCI and
later pass that on to the BIOS.

Note that on non PC architectures, this should have zero effect.

Signed-off-by: Jes Sorensen <jes@sgi.com>

---
 hw/cs4231a.c |    3 +++
 hw/gus.c     |    3 +++
 hw/ide.c     |   24 ++++++++++++++++--------
 hw/irq.c     |   12 ++++++++++++
 hw/irq.h     |    2 ++
 hw/pc.c      |   38 ++++++++++++++++++++++++++++++--------
 hw/sb16.c    |    3 +++
 7 files changed, 69 insertions(+), 16 deletions(-)

Index: qemu/hw/cs4231a.c
===================================================================
--- qemu.orig/hw/cs4231a.c
+++ qemu/hw/cs4231a.c
@@ -641,6 +641,9 @@ int cs4231a_init (qemu_irq *pic)
     int i;
     CSState *s;
 
+    if (qemu_reserve_isa_irq(conf.irq))
+        return -1;
+
     s = qemu_mallocz (sizeof (*s));
 
     s->pic = pic;
Index: qemu/hw/gus.c
===================================================================
--- qemu.orig/hw/gus.c
+++ qemu/hw/gus.c
@@ -255,6 +255,9 @@ int GUS_init (qemu_irq *pic)
     GUSState *s;
     struct audsettings as;
 
+    if (qemu_reserve_isa_irq(conf.irq))
+        return -1;
+
     s = qemu_mallocz (sizeof (*s));
 
     AUD_register_card ("gus", &s->card);
Index: qemu/hw/ide.c
===================================================================
--- qemu.orig/hw/ide.c
+++ qemu/hw/ide.c
@@ -3405,10 +3405,14 @@ void pci_piix3_ide_init(PCIBus *bus, Blo
     pci_register_bar((PCIDevice *)d, 4, 0x10,
                            PCI_ADDRESS_SPACE_IO, bmdma_map);
 
-    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);
+    if (!qemu_reserve_isa_irq(14)) {
+        ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+        ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
+    }
+    if (!qemu_reserve_isa_irq(15)) {
+        ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
+        ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
+    }
 
     for (i = 0; i < 4; i++)
         if (hd_table[i])
@@ -3445,10 +3449,14 @@ void pci_piix4_ide_init(PCIBus *bus, Blo
     pci_register_bar((PCIDevice *)d, 4, 0x10,
                            PCI_ADDRESS_SPACE_IO, bmdma_map);
 
-    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);
+    if (!qemu_reserve_isa_irq(14)) {
+        ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+        ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
+    }
+    if (!qemu_reserve_isa_irq(15)) {
+        ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
+        ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
+    }
 
     register_savevm("ide", 0, 2, pci_ide_save, pci_ide_load, d);
 }
Index: qemu/hw/irq.c
===================================================================
--- qemu.orig/hw/irq.c
+++ qemu/hw/irq.c
@@ -30,6 +30,18 @@ struct IRQState {
     int n;
 };
 
+uint16_t isa_reserved_irqs = 0;
+
+int qemu_reserve_isa_irq(int irq)
+{
+    if (isa_reserved_irqs & (1 << irq)) {
+        fprintf(stderr, "qemu: failed to reserve isa irq %i\n", irq);
+        return -1;
+    }
+    isa_reserved_irqs |= (1 << irq);
+    return 0;
+}
+
 void qemu_set_irq(qemu_irq irq, int level)
 {
     if (!irq)
Index: qemu/hw/irq.h
===================================================================
--- qemu.orig/hw/irq.h
+++ qemu/hw/irq.h
@@ -7,6 +7,8 @@
 typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
 typedef void SetIRQFunc(void *opaque, int irq_num, int level);
 
+extern uint16_t isa_reserved_irqs;
+int qemu_reserve_isa_irq(int irq);
 void qemu_set_irq(qemu_irq irq, int level);
 
 static inline void qemu_irq_raise(qemu_irq irq)
Index: qemu/hw/pc.c
===================================================================
--- qemu.orig/hw/pc.c
+++ qemu/hw/pc.c
@@ -1047,10 +1047,14 @@ static void audio_init (PCIBus *pci_bus,
 static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
 {
     static int nb_ne2k = 0;
+    int irq = ne2000_irq[nb_ne2k];
 
     if (nb_ne2k == NE2000_NB_MAX)
         return;
-    isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
+    if (qemu_reserve_isa_irq(irq)) {
+        return;
+    }
+    isa_ne2000_init(ne2000_io[nb_ne2k], pic[irq], nd);
     nb_ne2k++;
 }
 
@@ -1271,6 +1275,9 @@ static void pc_init1(ram_addr_t ram_size
 
     cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
     i8259 = i8259_init(cpu_irq[0]);
+    if (qemu_reserve_isa_irq(13)) {
+        exit(1);
+    }
     ferr_irq = i8259[13];
 
     if (pci_enabled) {
@@ -1304,6 +1311,9 @@ static void pc_init1(ram_addr_t ram_size
         }
     }
 
+    if (qemu_reserve_isa_irq(8)) {
+        exit(1);
+    }
     rtc_state = rtc_init(0x70, i8259[8], 2000);
 
     qemu_register_boot_set(pc_boot_set, rtc_state);
@@ -1314,6 +1324,9 @@ static void pc_init1(ram_addr_t ram_size
     if (pci_enabled) {
         ioapic = ioapic_init();
     }
+    if (qemu_reserve_isa_irq(0)) {
+        exit(1);
+    }
     pit = pit_init(0x40, i8259[0]);
     pcspk_init(pit);
     if (!no_hpet) {
@@ -1325,15 +1338,19 @@ static void pc_init1(ram_addr_t ram_size
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(serial_io[i], i8259[serial_irq[i]], 115200,
-                        serial_hds[i]);
+            int irq = serial_irq[i];
+            if (qemu_reserve_isa_irq(irq))
+                break;
+            serial_init(serial_io[i], i8259[irq], 115200, serial_hds[i]);
         }
     }
 
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         if (parallel_hds[i]) {
-            parallel_init(parallel_io[i], i8259[parallel_irq[i]],
-                          parallel_hds[i]);
+            int irq = parallel_irq[i];
+            if (qemu_reserve_isa_irq(irq))
+                break;
+            parallel_init(parallel_io[i], i8259[irq], parallel_hds[i]);
         }
     }
 
@@ -1364,11 +1381,15 @@ static void pc_init1(ram_addr_t ram_size
         pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259);
     } else {
         for(i = 0; i < MAX_IDE_BUS; i++) {
-            isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
-	                 hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
+            int irq = ide_irq[i];
+            if (!qemu_reserve_isa_irq(irq))
+                isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[irq],
+                             hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
         }
     }
 
+    if (qemu_reserve_isa_irq(1) || qemu_reserve_isa_irq(12))
+        exit(1);
     i8042_init(i8259[1], i8259[12], 0x60);
     DMA_init(0);
 #ifdef HAS_AUDIO
@@ -1379,7 +1400,8 @@ static void pc_init1(ram_addr_t ram_size
         dinfo = drive_get(IF_FLOPPY, 0, i);
         fd[i] = dinfo ? dinfo->bdrv : NULL;
     }
-    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
+    if (!qemu_reserve_isa_irq(6))
+        floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
 
     cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd);
 
Index: qemu/hw/sb16.c
===================================================================
--- qemu.orig/hw/sb16.c
+++ qemu/hw/sb16.c
@@ -1405,6 +1405,9 @@ int SB16_init (qemu_irq *pic)
     static const uint8_t dsp_write_ports[] = {0x6, 0xc};
     static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
 
+    if (qemu_reserve_isa_irq(conf.irq))
+        return -1;
+
     s = qemu_mallocz (sizeof (*s));
 
     s->cmd = -1;
