apj@cernvax.UUCP (apj) (03/08/85)
vectors segment at 0h org 9h*4 keyboard_int_vector label dword org 16h*4 keyboard_io_vector label dword vectors ends ;============================================================================== rom_bios_data segment at 40h org 17h kbd_flag db ? org 1ah rom_buffer_head dw ? rom_buffer_tail dw ? kb_buffer dw 16d dup (?) kb_buffer_end label word rom_bios_data ends ;============================================================================== code_seg segment assume cs:code_seg org 100h begin: jmp init_vectors ;initialize vectors and attach to dos rom_keyboard_int dd rom_keyboard_io dd buffer_head dw offset keyboard_buffer buffer_tail dw offset keyboard_buffer keyboard_buffer dw 160d dup(0) ;159 character input buffer keyboard_buffer_end label word ;--------------------------------------------------------; ; this procedure sends a short beep when the buffer fills ;--------------------------------------------------------; kb_control equ 61h ;control bits for keyboard & speaker error_beep proc near push ax push bx push cx pushf ;save old interupt enable flag cli ;turn off beep during interupt mov bx,30d ;number of cycles for 1/8 second tone in al,kb_control ;get information from speaker port push ax ;save control information start_of_one_cycle: and al,0fch ;turn off speaker out kb_control,al mov cx,60d ;delay for one half cycle off_loop: loop off_loop or al,2 ;turn off speaker out kb_control,al mov cx,60d ;delay for second half cycle on_loop: loop on_loop dec bx ;200 cycles yet? jnz start_of_one_cycle pop ax ;recover old keyboard information out kb_control,al popf ;restore interupt flag pop cx pop bx pop ax ret error_beep endp ;------------------------------------------------------------------------------ ;this procedure checks the rom keyboard buffer to see if some program ;tried to clear this buffer. we know it's been cleared when the rom ;tail and header overlap. normally, the new procedures below keep the ;dummy character, word 0,in the buffer. ; ;uses: bx,ds ;writes: buffer_head,buffer_tail,rom_buffer_head, ; rom_buffer_tail ;reads: keyboard_buffer,kb_buffer check_clear_buffer proc near assume ds:rom_bios_data mov bx,rom_bios_data ;establish pointer to bios data mov ds,bx cli ;turn off interupts during this check mov bx,rom_buffer_head ;check tn see if buffer cleared cmp bx,rom_buffer_tail ;is the buffer empty? jne buffer_ok ;no, then everything is alright ;yes, then clear the internal buffer mov bx,offset kb_buffer ;reset buffer with word 0 in buffer mov rom_buffer_head,bx add bx,2 mov rom_buffer_tail,bx assume ds:code_seg mov bx,cs mov ds,bx mov bx,offset keyboard_buffer ;reset internal buffer mov buffer_head,bx mov buffer_tail,bx buffer_ok: assume ds:code_seg sti ;interupts back on ret check_clear_buffer endp ;------------------------------------------------------------------------------ ;this procedure intercepts the keyboard interrupt and moves any new ;characters to the internal, 80 character buffer. intercept_keyboard_int proc near assume ds:nothing push ds push si push bx push ax call check_clear_buffer ;check for buffer cleared pushf call rom_keyboard_int ;read scan code with bios routines ;----- transfer any characters to internal buffer assume ds:rom_bios_data mov bx,rom_bios_data ;establish pointer to bios data mov ds,bx mov si,buffer_tail mov bx,rom_buffer_head ;check if real characters in buffer inc bx ;skip over dummy character inc bx cmp bx,offset kb_buffer_end jb dont_wrap ;no need to wrap the pointer mov bx,offset kb_buffer ;wrap the pointer dont_wrap: cmp bx,rom_buffer_tail ;is there a real character? je no_new_characers ;no then return to caller mov ax,[bx] ;yes,move character to internal buffer mov cs:[si],ax inc si inc si ;move to next position cmp si,offset keyboard_buffer_end jb not_at_end mov si,offset keyboard_buffer not_at_end: cmp si,buffer_head ;buffer overrun? jne write_to_buffer ;yes beep and throw out character call error_beep jmp short not_at_kb_end write_to_buffer: mov buffer_tail,si not_at_kb_end: mov rom_buffer_head,bx no_new_characters: ;---- see if ctrl + alt pushed, and clear buffer if so mov al,kbd_flag ;get status of shift keys into al and al,0ch ;isolate alt and crtl shift flags cmp al,0ch ;are both the alt and crtl keys down? jne dont_clear_buffer ;no, then dont clear the buffer mov ax,buffer_tail ;yes, then clear the buffer mov buffer_head,ax dont_clear_buffer: pop ax pop bx pop si pop ds iret intercept_keyboard_int endp ;-----------------------------------------------------------------------; ;this procedure replaces the rom bios routines for reading a character ; ;-----------------------------------------------------------------------; assume ds:code_seg ;------------------------------------------------------------------------------ intercept_keyboard_io proc far sti ;interrupts back on push ds ;save current ds push bx ;save bx temporarily call check_clear_buffer ;check for buffer cleared mov bx,cs ;establish pointer to data area mov ds,bx or ah,ah ;ah=0? jz read_character ;yes, read a character cmp ah,1 ;ah=1? jz read_status ;yes, return the status pop bx ;let rom bios handle other functhons pop ds assume ds:nothing jmp rom_keyboard_io ;call rom bios for other functions assume ds:code_seg ;ascii read ;--=- read the key read_character: ;ascii read sti ;interrupts back on during loop nop ;allow an interrupt to occur cli ;interrupts back off mov bx,buffer_head ;get pointer to head of buffer cmp bx,buffer_tail ;test end of buffer je read_character ;loop until something in buffer mov ax,[bx] ;get scan code and ascii code add bx,2 ;move to next word in buffer cmp bx,offset keyboard_buffer_end ;at end of buffer? jne save_pointer ;no, continue mov bx,offset keyboard_buffer ;yes, reset to buffer start save_pointer: mov buffer_head,bx ;store value in variable pop bx pop ds iret ;return to caller ;---- ascii status read_status: cli ;interrupts off mov bx,buffer_head ;get head pointer cmp bx,buffer_tail ;if equal (zf=1) then nothing there mov ax,[bx] sti ;interrupts back on pop bx ;recover registers pop ds ret 2 ;throw away flags intercept_keyboard_io endp ;-----------------------------------------------------------------; ;this procedure initializes the interrupt vectors. ; ;-----------------------------------------------------------------; ;------------------------------------------------------------------------------ init_vectors proc near assume ds:vectors push ds ;save old data segment mov ax,vectors ;set up the data segment for vectors mov ds,ax cli ;dont allow interrupts mov ax,keyboard_int_vector ;save addresses of bios routines mov rom_keyboard_int,ax mov ax,keyboard_int_vector[2] mov rom_keyboard_int[2],ax ;set up new keyboard_int vector mov keyboard_int_vector,offset intercept_keyboard_int mov keyboard_int_vector[2],cs sti ;allow interrupts again ;set up keyboard_io vector mov ax,keyboard_io_vector mov rom_keyboard_io,ax mov ax,keyboard_io_vector[2] mov rom_keyboard_io[2],ax mov keyboard_io_vector,offset intercept_keyboard_io mov keyboard_io_vector[2],cs ;now set up the the kbd buffer, etc. assume ds:rom_bios_data mov ax,rom_bios_data mov ds,ax cli ;dont allow interrupts now mov bx,offset kb_buffer mov rom_buffer_head,bx mov word ptr [bx],0 add bx,2 mov rom_buffer_tail,bx sti ;allow interrupts again mov dx,offset init_vectors ;end of resident portions int 27h ;terminate but stay resident init_vectors endp ;------------------------------------------------------------------------------ code_seg ends ;============================================================================== end begin