home *** CD-ROM | disk | FTP | other *** search
- 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 16 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 ;Address for ROM routine
- ROM_KEYBOARD_IO DD
- BUFFER_HEAD DW OFFSET KEYBOARD_BUFFER
- BUFFER_TAIL DW OFFSET KEYBOARD_BUFFER
- KEYBOARD_BUFFER DW 160 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 and
- ; speaker
- ERROR_BEEP PROC NEAR
- PUSH AX
- PUSH BX
- PUSH CX
- PUSHF ;Save the old interrupt enable flag
- CLI ;Turn off beep during interrupt
- MOV BX,30 ;Number of cycles for 1/8 sec beep
- IN AL,KB_CONTROL ;Get control info from speaker port
- PUSH AX ;Save the control information
- START_OF_ONE_CYCLE:
- AND AL,0FCH ;Turn off the speaker
- OUT KB_CONTROL,AL
- MOV CX,60 ;Delay for one half cycle
- OFF_LOOP: LOOP OFF_LOOP
- OR AL,2 ;Turn on the speaker
- OUT KB_CONTROL,AL
- MOV CX,60 ;Delay for second half of 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 interrupt 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 of interrupts during check
- MOV BX,ROM_BUFFER_HEAD ;Check to see if buffer cleared
- CMP BX,ROM_BUFFER_TAIL ;Is the buffer empty?
- JNE BUFFER_OK ;No, then everything is OK
- ; Yes, then clear 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 ;Interrupts 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 the internal buffer
- ;
- ASSUME DS:ROM_BIOS_DATA
- MOV BX,ROM_BIOS_DATA
- MOV DS,BX
- MOV SI,BUFFER_TAIL
- MOV BX,ROM_BUFFER_HEAD ;Check if real character in buffer
- ADD BX,2 ;Skip over dummy character
- CMP BX,OFFSET KB_BUFFER_END
- JB DONT_WRAP ;No need to wrap pointer
- MOV BX,OFFSET KB_BUFFER
- DONT_WRAP:
- CMP BX,ROM_BUFFER_TAIL ;Is there a real character?
- JE NO_NEW_CHARACTERS ;No, then return to caller
- MOV AX,[BX] ;Yes, move char to internal buffer
- MOV CS:[SI],AX
- ADD SI,2 ;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
- ;
- ; See if [Ctrl] + [Alt] pushed and clear buffer if so
- ;
- NO_NEW_CHARACTERS:
- MOV AL,KBD_FLAG ;Get status of shift keys into AL
- AND AL,0CH ;Isolate Ctrl and Alt shift flags
- CMP AL,0CH ;Both Ctrl and Alt keys pressed?
- JNE DONT_CLEAR_BUFFER ;No, so don't clear buffer
- MOV AX,BUFFER_TAIL ;Yes, so clear 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
- DEC AH ;AH = 1?
- JZ READ_STATUS ;Yes, return the status
- DEC AH ;AH = 2?
- JZ READ_SHIFT_STATUS ;Yes, return the shift status
- POP BX ;Ignore other function numbers
- POP DS
- IRET
- ;
- ; Read the character
- ;
- READ_CHARACTER: ;ASCII Read
- STI ;Interrupts back on
- 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 appears
- 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 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 then nothing there
- MOV AX,[BX]
- STI ;Interrupts back on
- POP BX ;Recover registers
- POP DS
- RET 2 ;Throw away flags
- ;
- ; Shift status
- ;
- READ_SHIFT_STATUS:
- JMP ROM_KEYBOARD_IO ;Let ROM routine do this
- 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 Data Segment for vectors
- MOV DS,AX
- CLI ;Dont allow interrupts
- MOV AX,KEYBOARD_INT_VECTOR ;Save addresses of BIOS
- MOV ROM_KEYBOARD_INT,AX ;routines and set up new
- MOV AX,KEYBOARD_INT_VECTOR[2] ;KEYBOARD_INT vector
- MOV ROM_KEYBOARD_INT[2],AX ;
- MOV KEYBOARD_INT_VECTOR,OFFSET INTERCEPT_KEYBOARD_INT
- MOV KEYBOARD_INT_VECTOR[2],CS
- STI ;allow interrupts again
- MOV AX,KEYBOARD_IO_VECTOR ;Set up 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
- ASSUME DS:ROM_BIOS_DATA ;Now set up the keyboard buffer,
- MOV AX,ROM_BIOS_DATA ;etc.
- MOV DS,AX
- CLI ;Dont allow interrupts
- 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 portion
- INT 27H ;Terminate but stay resident
- INIT_VECTORS ENDP
- ;
- CODE_SEG ENDS
- END BEGIN