;--------------------------------------------------; ; file keyboard.asm ; ; copyright (C) Ra.M. Software ; ; intercetta la IRQ1 - INT 09h keyboard controller ; ;--------------------------------------------------; ; nasm -f obj keyboard.asm ; ; tlink /t keyboard.obj + comlib.obj ; ; (oppure link /tiny keyboard.obj + comlib.obj) ; ;--------------------------------------------------; ;########### direttive per l'assembler ############ CPU 386 ; set di istruzioni a 32 bit %include "comlib.inc" ; inclusione libreria di I/O ;######### dichiarazione tipi e costanti ########## %assign INT09h 09h ; INT 09h - keyboard ISR %assign KBD_BUFF 60h ; porta buffer dati tastiera %assign KBD_COMM 64h ; porta comandi tastiera %assign MPICP0 20h ; porta P0 PIC Master %assign MPICP1 21h ; porta P1 PIC Master %assign IRQ1_MASK 00000010b ; mask-on per la IRQ1 %assign IRQ1_UNMASK 11111101b ; mask-off per la IRQ1 ;################ segmento unico ################## SEGMENT COMSEGM ALIGN=16 PUBLIC USE16 CLASS=CODE resb 0100h ; libera 256 byte per il PSP ..start: ; entry point ;------- inizio blocco principale istruzioni ------ call hideCursor ; nasconde il cursore call clearScreen ; pulisce lo schermo ; visualizza il titolo del programma mov di, title_str ; DS:DI punta a title_str mov dx, 000Ah ; riga, colonna di output call writeString ; visualizza la stringa ; installazione nuova ISR per la INT 09h in al, MPICP1 ; AL = IMR PIC Master or al, IRQ1_MASK ; pone a 1 il bit 1 (mask) out MPICP1, al ; scrive OCW1 nel PIC Master xor ax, ax ; AX = 0 mov es, ax ; ES = paragrafo 0000h mov eax, [es:(INT09h * 4)] ; legge il vecchio vettore 09h mov [old_int09h], eax ; e lo salva in old_int09h mov ax, cs ; AX = Seg(new_int09h) shl eax, 16 ; sposta nella WORD alta di EAX mov ax, new_int09h ; AX = Offset(new_int09h) mov [es:(INT09h * 4)], eax ; installa il nuovo vettore 09h in al, MPICP1 ; AL = IMR PIC Master and al, IRQ1_UNMASK ; pone a 0 il bit 1 (unmask) out MPICP1, al ; scrive OCW1 nel PIC Master mov dx, 0400h ; inizializza riga, colonna ; loop principale del programma keyboard_loop: mov al, [key_buffer] ; nuovo scan code letto dalla ISR cmp al, 01h ; tasto [Esc] premuto? jne keyboard_loop ; controllo loop ; ripristino vecchia ISR per la INT 09h in al, MPICP1 ; AL = IMR PIC Master or al, IRQ1_MASK ; pone a 1 il bit 1 (mask) out MPICP1, al ; scrive OCW1 nel PIC Master xor ax, ax ; AX = 0 mov es, ax ; ES = paragrafo 0000h mov eax, [old_int09h] ; EAX = indirizzo vecchio vettore 09h mov [es:(INT09h * 4)], eax ; ripristina il vecchio vettore 09h in al, MPICP1 ; AL = IMR PIC Master and al, IRQ1_UNMASK ; pone a 0 il bit 1 (unmask) out MPICP1, al ; scrive OCW1 nel PIC Master call showCursor ; ripristina il cursore ;-------- fine blocco principale istruzioni ------- mov ah, 4ch ; servizio Terminate Program mov al, 00h ; exit code = 0 int 21h ; chiama i servizi DOS ;----- inizio definizione variabili statiche ------ align 4, db 0 ; allinea alla DWORD old_int09h dd 0 ; indirizzo vecchia ISR key_buffer db 0 ; scan code tasto premuto irq_counter db 0 ; contatore IRQ title_str db "CODICI DI SCANSIONE DELLA TASTIERA" db " (premere [Esc] per uscire)", 0 clear_str db " ", 0 ;------- fine definizione variabili statiche ------ ;---------- inizio definizione procedure ---------- ; new_int09h: nuova ISR per la INT 09h ; una ISR deve sempre preservare tutti i registri che utilizza! new_int09h: push ax ; preserva AX push bx ; preserva BX push cx ; preserva CX push di ; preserva DI cmp byte [irq_counter], 0 ; fine scan code ? ja next_scancode ; se "no" salta a next_scancode mov di, clear_str ; DS:DI punta a clear_str mov dx, 0400h ; riga 4, colonna 0 call writeString ; visualizza la stringa xor cx, cx ; CX = 0 wait1: in al, KBD_COMM ; legge lo Status Byte test al, 00000010b ; buffer pronto per la lettura ? loopnz wait1 ; controllo loop in al, KBD_BUFF ; legge il prossimo codice mov [key_buffer], al ; e lo salva in key_buffer call writeHex8 ; visualizza il codice mov byte [irq_counter], 0 ; assume "normal key" (1 codice) test_for_E0h: cmp al, 0E0h ; codice == E0h ? jne test_for_E1h ; se "no" salta a test_for_E1h mov byte [irq_counter], 1 ; "extended key" da 2 codici add dl, 4 ; incremento colonna jmp short send_eoi ; salta a send_eoi test_for_E1h: cmp al, 0E1h ; codice == E1h ? jne send_eoi ; se "no" salta a send_eoi mov byte [irq_counter], 5 ; "extended key" da 6 codici add dl, 4 ; incremento colonna jmp short send_eoi ; salta a send_eoi next_scancode: xor cx, cx ; CX = 0 wait2: in al, KBD_COMM ; legge lo Status Byte test al, 00000010b ; buffer pronto per la lettura ? loopnz wait2 ; controllo loop in al, KBD_BUFF ; legge il prossimo codice mov [key_buffer], al ; e lo salva in key_buffer call writeHex8 ; visualizza il codice add dl, 4 ; incremento colonna dec byte [irq_counter] ; decremento contatore send_eoi: mov al, 20h ; OCW3 = specific EOI out MPICP0, al ; scrive OCW3 nel PIC Master pop di ; ripristina DI pop cx ; ripristina CX pop bx ; ripristina BX pop ax ; ripristina AX iret ; return from interrupt ;----------- fine definizione procedure ----------- ;##################################################