@@ -34,4 +34,6 @@ struct ViaAC97State {
uint32_t ac97_cmd;
};
+void via_isa_set_irq(PCIDevice *d, int n, int level);
+
#endif
@@ -549,6 +549,7 @@ struct ViaISAState {
PCIDevice dev;
qemu_irq cpu_intr;
qemu_irq *isa_irqs_in;
+ uint16_t irq_state[ISA_NUM_IRQS];
ViaSuperIOState via_sio;
MC146818RtcState rtc;
PCIIDEState ide;
@@ -592,6 +593,46 @@ static const TypeInfo via_isa_info = {
},
};
+void via_isa_set_irq(PCIDevice *d, int pin, int 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 2: /* USB ports 0-1 */
+ case 3: /* USB ports 2-3 */
+ 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_request_i8259_irq(void *opaque, int irq, int level)
{
ViaISAState *s = opaque;