Basically put, unless you call the default handler after you've done your work, you'll have to tell the PIC (programmable interrupt controller) that you're done - the default handler will do this for you - sending the EOI (end of interrupt signal) to the PIC(s). The PIC wont fire the interrupt again until you tell it that you've done with the current one.
Code to do this in 32 bit protected mode looks something like this. Do note, that I use a generic handler for all IRQs, just handing off to the appropriately registered user callback function. I've included both.
First, the generic IRQ handler
irq_handler:
push ebp
mov ebp, esp
add ebp, 8
mov eax, [ebp +registers_t.int_no]
cmp eax, IRQ7 ; this just dumps spurious IRQ7 interrupts
je .irqHandlerDone
cmp eax, IRQ8 ; if it's IRQ0 - IRQ7, the first controller fired the int, otherwise the slave controller did
jb .slaveResetDone
.resetSlave:
mov al,20H ; send End-Of-Interrupt signal
out 0xA0,al ; to the 8259 _slave_ Programmable Interrupt Controller
.slaveResetDone:
.resetMaster:
mov al, 0x20 ; send End-Of-Interrupt signal
out 0x20, al ; to the 8259 master Programmable Interrupt Controller
mov eax, [ebp + registers_t.int_no]
shl eax, 2 ; x4
mov esi, interrupt_handlers
add esi, eax ; esi --> interrupt_handlers[int_no]
cmp dword [esi], 0
je .irqHandlerDone
call [esi]
.irqHandlerDone:
pop ebp
ret
Next, the IRQ1 (keyboard) handler. The registration function simply copies the offset of the function into a table (interrupt_handlers) of 32 bit addresses.
I'm in flat-memory mode (4GB addressable, ES already holds the segment selector for a writeable data segment. 0xB8000 + 79*2 simply points to the character on the top-right of a 80x25 mode3 text screen)
; keyboard IRQ handler
irq1Handler:
push ebp
mov ebp, esp
add ebp, 8+4
in al, 0x60
mov bl, al
mov byte [port60], al
in al, 0x61
mov ah, al
or al, 0x80
out 0x61, al
xchg ah, al
out 0x61, al
and bl, 0x80
jnz .done
pusha
;mov al, [port60]
;call outputChar
mov edi, 0xB8000 + 79*2
mov al, [port60]
mov [es:edi], al
popa
.done:
pop ebp
ret
port60 db 0
The code draws from James M's tutorial, here: http://www.jamesmolloy.co.uk/tutorial_html/5.-IRQs%20and%20the%20PIT.html
There is much that can be read about interfacing to hardware over at OSDev.org - http://wiki.osdev.org/Main_Page
UPDATE:
Here's a 16bit ISR that functions in DosBox.
;-----------------------------------------------------
; handles int 0x09
;-----------------------------------------------------
keyhandler:
cli
pusha
in al, 0x60 ; get key data
mov bl, al ; save it
mov byte [port60], al
in al, 0x61 ; keybrd control
mov ah, al
or al, 0x80 ; disable bit 7
out 0x61, al ; send it back
xchg ah, al ; get original
out 0x61, al ; send that back
mov al, 0x20 ; End of Interrupt
out 0x20, al ;
and bl, 0x80 ; key released
jnz done ; don't repeat
mov al, [port60]
;
; do something with the scan-code here
;
done:
popa
iret
port60 db 0 ; where we'll store the scan-code