static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) serio_interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0, regs); master_outb(-1, KEYBOARD_UNLOCK_REG); return IRQ_HANDLED; }
static void q40kbd_flush(void) { int maxread = 100; unsigned long flags; spin_lock_irqsave(&q40kbd_lock, flags); while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) master_inb(KEYCODE_REG); spin_unlock_irqrestore(&q40kbd_lock, flags); }
static int __init kbd_read_input(void) { int retval = KBD_NO_DATA; unsigned char status; status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); if (status) { unsigned char data = master_inb(KEYCODE_REG); retval = data; master_outb(-1,KEYBOARD_UNLOCK_REG); } return retval; }
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; spin_lock_irqsave(&q40kbd_lock, flags); if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs); master_outb(-1, KEYBOARD_UNLOCK_REG); spin_unlock_irqrestore(&q40kbd_lock, flags); return IRQ_HANDLED; }
static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned char status; spin_lock(&kbd_controller_lock); kbd_pt_regs = regs; status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); if (status ) { unsigned char scancode,qcode; qcode = master_inb(KEYCODE_REG); if (qcode != 0xf0) { if (qcode == 0xe0) { qprev=0xe0; handle_scancode(qprev , 1); goto exit; } scancode=qprev ? q40ecl[qcode] : q40cl[qcode]; #if 0 /* next line is last resort to hanlde some oddities */ if (qprev && !scancode) scancode=q40cl[qcode]; #endif qprev=0; if (!scancode) { printk("unknown scancode %x\n",qcode); goto exit; } if (scancode==0xff) /* SySrq */ scancode=SYSRQ_KEY; handle_scancode(scancode, ! keyup ); keyup=0; tasklet_schedule(&keyboard_tasklet); } else keyup=1; } exit: spin_unlock(&kbd_controller_lock); master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */ }
static int __init q40kbd_init(void) { int maxread = 100; if (!MACH_IS_Q40) return -EIO; /* allocate the IRQ */ request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL); /* flush any pending input */ while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) master_inb(KEYCODE_REG); /* off we go */ master_outb(-1,KEYBOARD_UNLOCK_REG); master_outb(1,KEY_IRQ_ENABLE_REG); serio_register_port(&q40kbd_port); printk(KERN_INFO "serio: Q40 kbd registered\n"); return 0; }
/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp) { unsigned mir, mer; int irq,i; mir=master_inb(IIRQ_REG); if (mir&Q40_IRQ_FRAME_MASK) { irq_tab[Q40_IRQ_FRAME].count++; irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,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 occassionally do */ if (irq>4 && irq<=15 && mext_disabled) { /*aliased_irq++;*/ goto iirq; } if (irq_tab[irq].handler == q40_defhand ) { printk("handler for IRQ %d not defined\n",irq); continue; /* ignore uninited INTs :-( */ } if ( irq_tab[irq].state & IRQ_INPROGRESS ) { /* some handlers do sti() 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 /*printk("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; } irq_tab[irq].count++; irq_tab[irq].state |= IRQ_INPROGRESS; irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp); irq_tab[irq].state &= ~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; /*printk("reenabling irq %d\n",irq); */ #endif } return; } } if (mer && ccleirq>0 && !aliased_irq) printk("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) { irq_tab[Q40_IRQ_KEYBOARD].count++; irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp); } }
void q40_process_int (int level, struct pt_regs *fp) { printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n", level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2); printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG)); }