in q40/q40ints.c [209:300]
static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
{
unsigned mir, mer;
int i;
//repeat:
mir = master_inb(IIRQ_REG);
#ifdef CONFIG_BLK_DEV_FD
if ((mir & Q40_IRQ_EXT_MASK) &&
(master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) {
floppy_hardint();
return;
}
#endif
switch (irq) {
case 4:
case 6:
do_IRQ(Q40_IRQ_SAMPLE, fp);
return;
}
if (mir & Q40_IRQ_FRAME_MASK) {
do_IRQ(Q40_IRQ_FRAME, fp);
master_outb(-1, FRAME_CLEAR_REG);
}
if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
mer = master_inb(EIRQ_REG);
for (i = 0; eirqs[i].mask; i++) {
if (mer & eirqs[i].mask) {
irq = eirqs[i].irq;
/*
* There is a little mess wrt which IRQ really caused this irq request. The
* main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
* are read - which is long after the request came in. In theory IRQs should
* not just go away but they occasionally do
*/
if (irq > 4 && irq <= 15 && mext_disabled) {
/*aliased_irq++;*/
goto iirq;
}
if (q40_state[irq] & IRQ_INPROGRESS) {
/* some handlers do local_irq_enable() for irq latency reasons, */
/* however reentering an active irq handler is not permitted */
#ifdef IP_USE_DISABLE
/* in theory this is the better way to do it because it still */
/* lets through eg the serial irqs, unfortunately it crashes */
disable_irq(irq);
disabled = 1;
#else
/*pr_warn("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",
irq, disabled ? "already" : "not yet"); */
fp->sr = (((fp->sr) & (~0x700))+0x200);
disabled = 1;
#endif
goto iirq;
}
q40_state[irq] |= IRQ_INPROGRESS;
do_IRQ(irq, fp);
q40_state[irq] &= ~IRQ_INPROGRESS;
/* naively enable everything, if that fails than */
/* this function will be reentered immediately thus */
/* getting another chance to disable the IRQ */
if (disabled) {
#ifdef IP_USE_DISABLE
if (irq > 4) {
disabled = 0;
enable_irq(irq);
}
#else
disabled = 0;
/*pr_info("reenabling irq %d\n", irq); */
#endif
}
// used to do 'goto repeat;' here, this delayed bh processing too long
return;
}
}
if (mer && ccleirq > 0 && !aliased_irq) {
pr_warn("ISA interrupt from unknown source? EIRQ_REG = %x\n",
mer);
ccleirq--;
}
}
iirq:
mir = master_inb(IIRQ_REG);
/* should test whether keyboard irq is really enabled, doing it in defhand */
if (mir & Q40_IRQ_KEYB_MASK)
do_IRQ(Q40_IRQ_KEYBOARD, fp);
return;
}