struct ViaISAState {
PCIDevice dev;
qemu_irq cpu_intr;
- qemu_irq *isa_irqs;
+ qemu_irq *isa_irqs_in;
+ uint16_t irq_state[ISA_NUM_IRQS];
ViaSuperIOState via_sio;
- RTCState rtc;
+ MC146818RtcState rtc;
PCIIDEState ide;
UHCIState uhci[2];
ViaPMState pm;
- PCIDevice ac97;
+ ViaAC97State ac97;
PCIDevice mc97;
};
},
};
-void via_isa_set_irq(PCIDevice *d, int n, int level)
+static int via_isa_get_pci_irq(const ViaISAState *s, int pin)
+{
+ switch (pin) {
+ case 0:
+ return s->dev.config[0x55] >> 4;
+ case 1:
+ return s->dev.config[0x56] & 0xf;
+ case 2:
+ return s->dev.config[0x56] >> 4;
+ case 3:
+ return s->dev.config[0x57] >> 4;
+ }
+ return 0;
+}
+
+void via_isa_set_irq(PCIDevice *d, int pin, int level)
{
- ViaISAState *s = VIA_ISA(d);
- qemu_set_irq(s->isa_irqs[n], level);
+ ViaISAState *s = VIA_ISA(pci_get_function_0(d));
+ uint8_t irq = d->config[PCI_INTERRUPT_LINE], max_irq = 15;
+ int f = PCI_FUNC(d->devfn);
+ uint16_t mask = BIT(f);
+
+ switch (f) {
+ case 0: /* PIRQ/PINT inputs */
+ irq = via_isa_get_pci_irq(s, pin);
+ f = 8 + pin; /* Use function 8-11 for PCI interrupt inputs */
+ break;
+ case 2: /* USB ports 0-1 */
+ case 3: /* USB ports 2-3 */
+ case 5: /* AC97 audio */
+ max_irq = 14;
+ break;
+ }
+
+ /* Keep track of the state of all sources */
+ if (level) {
+ s->irq_state[0] |= mask;
+ } else {
+ s->irq_state[0] &= ~mask;
+ }
+ if (irq == 0 || irq == 0xff) {
+ return; /* disabled */
+ }
+ if (unlikely(irq > max_irq || irq == 2)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid ISA IRQ routing %d for %d",
+ irq, f);
+ return;
+ }
+ /* Record source state at mapped IRQ */
+ if (level) {
+ s->irq_state[irq] |= mask;
+ } else {
+ s->irq_state[irq] &= ~mask;
+ }
+ /* Make sure there are no stuck bits if mapping has changed */
+ s->irq_state[irq] &= s->irq_state[0];
+ /* ISA IRQ level is the OR of all sources routed to it */
+ qemu_set_irq(s->isa_irqs_in[irq], !!s->irq_state[irq]);
+}
+
+static void via_isa_pirq(void *opaque, int pin, int level)
+{
+ via_isa_set_irq(opaque, pin, level);
}
static void via_isa_request_i8259_irq(void *opaque, int irq, int level)
int i;
qdev_init_gpio_out(dev, &s->cpu_intr, 1);
+ qdev_init_gpio_in_named(dev, via_isa_pirq, "pirq", PCI_NUM_PINS);
isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1);
isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d),
errp);
return;
}
- s->isa_irqs = i8259_init(isa_bus, *isa_irq);
- isa_bus_irqs(isa_bus, s->isa_irqs);
+ s->isa_irqs_in = i8259_init(isa_bus, *isa_irq);
+ isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in);
i8254_pit_init(isa_bus, 0x40, 0, NULL);
i8257_dma_init(isa_bus, 0);
if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) {
return;
}
+ for (i = 0; i < 2; i++) {
+ qdev_connect_gpio_out_named(DEVICE(&s->ide), "isa-irq", i,
+ s->isa_irqs_in[14 + i]);
+ }
/* Functions 2-3: USB Ports */
for (i = 0; i < ARRAY_SIZE(s->uhci); i++) {
PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
+ pci_conf[0x4c] = 0x04; /* IDE interrupt Routing */
pci_conf[0x58] = 0x40; /* Miscellaneous Control 0 */
pci_conf[0x67] = 0x08; /* Fast IR Config */
pci_conf[0x6b] = 0x01; /* Fast IR I/O Base */