Hi,
Masterkiller wrote:Everything works perfectly fine, except that mouse interrupt handler is called only once. I test the stack and no stack failure. No registers and system flags are affected by my interrupt handler and stack is OK. Where am I wrong?
Mostly, the entire thing is dodgy...
First, you don't need to save and restore registers that aren't used. You don't use most of the general registers and don't use DS or ES (as far as I can tell), so don't bother saving and restoring them. Alternatively you could set DS and use it instead of having heaps of CS segment override prefixes.
Next, the keyboard controller won't generate an IRQ 12 unless there's data ready from the mouse, and it also won't generate and IRQ 1 unless there's data ready from the keyboard. This means that the following lines should be deleted:
Code: Select all
IN al, 0x64
.checkData:
TEST al, 0x1 ;1 <data available?>
JZ .iexit
TEST al, 0x20 ;Test bit 5 <mouse data?>
JNZ .mouseDataAvailable
IN al, 0x60 ;Removing unexpected keyboard data
JMP short .checkData
Next, the keyboard controller generates an IRQ for each byte, so you should get one byte per IRQ. You're trying to get 3 bytes per IRQ and probably causing a huge amount of IRQ latency while you wait for the second and third bytes to go from the mouse to the keyboard controller over a slow serial connection. Basically this code needs to be ripped out:
Code: Select all
.mouseDataAvailable: ;Get the 3 byte packet
IN al, 0x60
MOV byte[CS:mouseDataStatus], al
CALL waitForRead
IN al, 0x60
MOV byte[CS:mouseDataX], al
CALL waitForRead
IN al, 0x60
MOV byte[CS:mouseDataY], al
It could be replaced by something like this:
Code: Select all
section .bss
mouseBuffer:
resb 3
section .data
mouseBufferPointer:
dd mouseBuffer
section .text
in al,0x60
mov edx,[mouseBufferPointer]
mov [edx],al
inc edx
cmp edx,mouseBuffer + 3
jb .done
mov edx,mouseBuffer
; *** More stuff here ***
.done:
mov [mouseBufferPointer],edx
Note: This code is simplistic example code for demonstration purposes only. IIRC there's a bit set in the first byte that can be used for synchronization, so that you know that the first byte really is the first byte, and so that if a byte is lost somewhere you don't continually think that the second byte is the first byte and the third byte is the second byte, etc.
Next, why have you got part of a GUI wedged into your IRQ handler? The only thing the mouse IRQ handler should do is send a "mouse packet arrived" event to something. It shouldn't do anything involving mouse cursors or video - that's the GUI's job. An even better idea might be to put the raw bytes onto a FIFO, where something else can get the bytes out the other end of the FIFO and work out how to interpret the received bytes (and where even less work needs to be done in the IRQ handler). That way you could have several different pieces of code (one for each different mouse protocol) that all rely on the same "keyboard controller chip" driver.
Lastly, at the end of an IRQ handler you need to send an EOI to let the interrupt controller know you've finished handling the interrupt. In this case you need to send one EOI to the slave PIC and one EOI to the master PIC. If you don't do this then the PIC chips won't send any more IRQs for that device or for any other devices that use a lower priority IRQ. Don't add code to send the EOI to the end of the IRQ handler - use some abstraction and call a "sendEOI()" kernel function at the end of the IRQ handler instead and let the kernel can deal with the PIC chips (or the I/O APIC, if present).
After all of that, you'd end up with something like:
Code: Select all
irq12:
push eax
push ebx
in al,0x60
; ** send the byte to whoever is listening here **
mov eax,KAPI_SENDEOI ;Function number for the "send the EOI" function
mov ebx,12 ;ebx = IRQ number
CALL_KERNEL_API ;Call the kernel API
pop ebx
pop eax
iret
Cheers,
Brendan