irq: turn a PS/2 line over when its device waits and nothing comes

An ASUS TUF A15 booted with its internal keyboard dead and a USB one
fine. These AMD laptops' firmware describes IRQ 1's polarity wrongly --
Linux keeps a quirk list -- and an edge line programmed the wrong way
up never fires: the controller holds its byte, and only the interrupt
that never comes would read it.

irq_watch() lets a driver say how to ask its device whether something
is waiting. The poller asks every tick; 50 ms of waiting with nothing
delivered turns the line's polarity over and drains the device, which
re-arms the edge, and if it still says nothing the line is polled.
Both are announced. The keyboard and the PS/2 mouse are watched.

ISA lines now also take their mode from the MADT's override entries,
which were parsed and never read.

Tested in QEMU, which ignores polarity on edge lines, with the keyboard
line masked: the first key turns it over and typing works; masked again
after the flip, it is polled and typing still works.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-24 11:10:29 +02:00
commit 8c426b2077
4 changed files with 123 additions and 0 deletions

View file

@ -48,6 +48,15 @@ mouse_read(void)
return inb(KBD_S_DATA);
}
// A byte from the auxiliary port, which IRQ 12 should have announced; see
// kbd_waiting() in console.c.
static int
mouse_waiting(void)
{
uchar st = inb(KBD_S_STAT);
return st != 0xFF && (st & 0x21) == 0x21;
}
static void
mouse_irq(void *arg)
{
@ -262,4 +271,5 @@ mouseinit(void)
mouse_read();
irq_register(IRQ_MOUSE, mouse_irq, 0, "ps2-mouse", 0);
irq_watch(IRQ_MOUSE, mouse_waiting);
}