PAGE 118,121
TITLE KYBD ----- 03/06/86  KEYBOARD BIOS
.XLIST
INCLUDE DSEG.INC
INCLUDE POSTEQU.INC
.LIST
CODE	SEGMENT BYTE PUBLIC

	PUBLIC	K16
	PUBLIC	KEYBOARD_IO_1
	PUBLIC	KB_INT_1
	PUBLIC	SND_DATA

	EXTRN	BEEP:NEAR
	EXTRN	DDS:NEAR
	EXTRN	START_1:NEAR
	EXTRN	K6:BYTE
	EXTRN	K6L:ABS
	EXTRN	K7:BYTE
	EXTRN	K8:BYTE
	EXTRN	K10:BYTE
	EXTRN	K11:BYTE
	EXTRN	K12:BYTE
	EXTRN	K14:BYTE
	EXTRN	K15:BYTE

;--- INT 16 H ------------------------------------------------------------------
; KEYBOARD I/O								       :
;	THESE ROUTINES PROVIDE READ KEYBOARD SUPPORT			       :
; INPUT 								       :
;	(AH)= 00H  READ THE NEXT ASCII CHARACTER ENTERED FROM THE KEYBOARD,    :
;		   RETURN THE RESULT IN (AL), SCAN CODE IN (AH).	       :
;		   THIS IS THE COMPATIBLE READ INTERFACE, EQUIVALENT TO THE    :
;		   STANDARD PC OR PCAT KEYBOARD 			       :
;------------------------------------------------------------------------------:
;	(AH)= 01H  SET THE ZERO FLAG TO INDICATE IF AN ASCII CHARACTER IS      :
;		   AVAILABLE TO BE READ FROM THE KEYBOARD BUFFER.	       :
;		   (ZF)= 1 -- NO CODE AVAILABLE 			       :
;		   (ZF)= 0 -- CODE IS AVAILABLE  (AX)= CHARACTER	       :
;		   IF (ZF)= 0, THE NEXT CHARACTER IN THE BUFFER TO BE READ IS  :
;		   IN (AX), AND THE ENTRY REMAINS IN THE BUFFER.	       :
;		   THIS WILL RETURN ONLY PC/PCAT KEYBOARD COMPATIBLE CODES     :
;------------------------------------------------------------------------------:
;	(AH)= 02H  RETURN THE CURRENT SHIFT STATUS IN (AL) REGISTER	       :
;		   THE BIT SETTINGS FOR THIS CODE ARE INDICATED IN THE	       :
;		   EQUATES FOR @KB_FLAG 				       :
;------------------------------------------------------------------------------:
;	(AH)= 03H  SET TYPAMATIC RATE AND DELAY 			       :
;	      (AL) = 05H						       :
;	      (BL) = TYPAMATIC RATE  (BITS 5 - 7 MUST BE RESET TO 0)	       :
;									       :
;		      REGISTER	   RATE      REGISTER	  RATE		       :
;		       VALUE	 SELECTED     VALUE	SELECTED	       :
;		      --------------------------------------------	       :
;			00H	   30.0        10H	   7.5		       :
;			01H	   26.7        11H	   6.7		       :
;			02H	   24.0        12H	   6.0		       :
;			03H	   21.8        13H	   5.5		       :
;			04H	   20.0        14H	   5.0		       :
;			05H	   18.5        15H	   4.6		       :
;			06H	   17.1        16H	   4.3		       :
;			07H	   16.0        17H	   4.0		       :
;			08H	   15.0        18H	   3.7		       :
;			09H	   13.3        19H	   3.3		       :
;			0AH	   12.0        1AH	   3.0		       :
;			0BH	   10.9        1BH	   2.7		       :
;			0CH	   10.0        1CH	   2.5		       :
;			0DH	    9.2        1DH	   2.3		       :
;			0EH	    8.6        1EH	   2.1		       :
;			0FH	    8.0        1FH	   2.0		       :
;									       :
;	      (BH) = TYPAMATIC DELAY (BITS 2 - 7 MUST BE RESET TO 0)	       :
;									       :
;		     REGISTER	 DELAY					       :
;		       VALUE	 VALUE					       :
;		     --------	 -----					       :
;			00H	 250ms					       :
;			01H	 500ms					       :
;			02H	 750ms					       :
;			03H	1000ms					       :
;------------------------------------------------------------------------------:
;	(AH)= 05H  PLACE ASCII CHARACTER/SCAN CODE COMBINATION IN KEYBOARD     :
;		   BUFFER AS IF STRUCK FROM KEYBOARD			       :
;		   ENTRY:  (CL) = ASCII CHARACTER			       :
;			   (CH) = SCAN CODE				       :
;		   EXIT:   (AL) = 00H = SUCCESSFUL OPERATION		       :
;			   (AH) = 01H = UNSUCCESSFUL - BUFFER FULL	       :
;		   FLAGS:  CARRY IF ERROR				       :
;------------------------------------------------------------------------------:
;	(AH)= 10H  EXTENDED READ INTERFACE FOR THE ENHANCED KEYBOARD,	       :
;		   OTHERWISE SAME AS FUNCTION AH=0			       :
;------------------------------------------------------------------------------:
;	(AH)= 11H  EXTENDED ASCII STATUS FOR THE ENHANCED KEYBOARD,	       :
;		   OTHERWISE SAME AS FUNCTION AH=1			       :
;------------------------------------------------------------------------------:
;	(AH)= 12H  RETURN THE EXTENDED SHIFT STATUS IN AX REGISTER	       :
;		   AL = BITS FROM KB_FLAG, AH = BITS FOR LEFT AND RIGHT        :
;		   CTL AND ALT KEYS FROM KB_FLAG_1 AND KB_FLAG_3	       :
;									       :
; OUTPUT								       :
;	AS NOTED ABOVE, ONLY (AX) AND FLAGS CHANGED			       :
;	ALL REGISTERS RETAINED						       :
;-------------------------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA

KEYBOARD_IO_1	PROC	FAR		;>>> ENTRY POINT FOR ORG 0E82EH
	STI				; INTERRUPTS BACK ON
	PUSH	DS			; SAVE CURRENT DS
	PUSH	BX			; SAVE BX TEMPORARILY
	PUSH	CX			; SAVE CX TEMPORARILY
	CALL	DDS			; ESTABLISH POINTER TO DATA REGION
	OR	AH,AH			; CHECK FOR (AH)= 00H
	JZ	K1			; ASCII_READ
	DEC	AH			; CHECK FOR (AH)= 01H
	JZ	K2			; ASCII_STATUS
	DEC	AH			; CHECK FOR (AH)= 02H
	JZ	K3			; SHIFT_STATUS
	DEC	AH			; CHECK FOR (AH)= 03H
	JZ	K300			; SET TYPAMATIC RATE/DELAY
	SUB	AH,2			; CHECK FOR (AH)= 05H
	JNZ	K101			;
	JMP	K500			; KEYBOARD WRITE
K101:	SUB	AH,11			; AH = 10
	JZ	K1E			; EXTENDED ASCII_READ
	DEC	AH			; CHECK FOR (AH)= 11H
	JZ	K2E			; EXTENDED ASCII_STATUS
	DEC	AH			; CHECK FOR (AH)= 12H
	JZ	K3E			; EXTENDED SHIFT_STATUS
K10_EXIT:
	POP	CX			; RECOVER REGISTER
	POP	BX			; RECOVER REGISTER
	POP	DS			; RECOVER SEGMENT
	IRET				; INVALID COMMAND

;------ ASCII CHARACTER

K1E:	CALL	K1S		; GET A CHARACTER FROM THE BUFFER (EXTENDED)
	CALL	K10_E_XLAT	; ROUTINE TO XLATE FOR EXTENDED CALLS
	JMP	K10_EXIT	; GIVE IT TO THE CALLER

K1:	CALL	K1S		; GET A CHARACTER FROM THE BUFFER
	CALL	K10_S_XLAT	; ROUTINE TO XLATE FOR STANDARD CALLS
	JC	K1		; CARRY SET MEANS THROW CODE AWAY
K1A:	JMP	K10_EXIT	; RETURN TO CALLER

;------ ASCII STATUS

K2E:	CALL	K2S		; TEST FOR CHARACTER IN BUFFER (EXTENDED)
	JZ	K2B		; RETURN IF BUFFER EMPTY
	PUSHF			; SAVE ZF FROM TEST
	CALL	K10_E_XLAT	; ROUTINE TO XLATE FOR EXTENDED CALLS
	JMP	SHORT K2A	; GIVE IT TO THE CALLER

K2:	CALL	K2S		; TEST FOR CHARACTER IN BUFFER
	JZ	K2B		; RETURN IF BUFFER EMPTY
	PUSHF			; SAVE ZF FROM TEST
	CALL	K10_S_XLAT	; ROUTINE TO XLATE FOR STANDARD CALLS
	JNC	K2A		; CARRY CLEAR MEANS PASS VALID CODE
	POPF			;  INVALID CODE FOR THIS TYPE OF CALL
	CALL	K1S		;  THROW THE CHARACTER AWAY
	JMP	K2		; GO LOOK FOR NEXT CHAR, IF ANY

K2A:	POPF			; RESTORE ZF FROM TEST
K2B:	POP	CX		; RECOVER REGISTER
	POP	BX		; RECOVER REGISTER
	POP	DS		; RECOVER SEGMENT
	RET	2		; THROW AWAY FLAGS

;------ SHIFT STATUS

K3E:				; GET THE EXTENDED SHIFT STATUS FLAGS
	MOV	AH,@KB_FLAG_1	; GET SYSTEM SHIFT KEY STATUS
	AND	AH,SYS_SHIFT	; MASK ALL BUT SYS KEY BIT
	MOV	CL,5		; SHIFT THE SYSTEM KEY BIT OVER TO
	SHL	AH,CL		;  BIT 7 POSITION
	MOV	AL,@KB_FLAG_1	; GET SHIFT STATES BACK
	AND	AL,01110011B	; ELIMINATE SYS_SHIFT, HOLD_STATE, AND INS_SHIFT
	OR	AH,AL		; MERGE THE REMAINING BITS INTO AH
	MOV	AL,@KB_FLAG_3	; GET RIGHT CTL AND ALT
	AND	AL,00001100B	; ELIMINATE LC_E0 AND LC_E1
	OR	AH,AL		; OR THE SHIFT FLAGS TOGETHER
K3:	MOV	AL,@KB_FLAG	; GET THE SHIFT STATUS FLAGS
	JMP	K10_EXIT	; RETURN TO CALLER

;------ SET TYPAMATIC RATE AND DELAY

K300:	CMP	AL,5		; CORRECT FUNCTION CALL?
	JNE	K10_EXIT	;  NO, RETURN
	TEST	BL,0E0h 	; TEST FOR OUT-OF-RANGE RATE
	JNZ	K10_EXIT	; RETURN IF SO
	TEST	BH,0FCh 	; TEST FOR OUT-OF-RANGE DELAY
	JNZ	K10_EXIT	; RETURN IF SO
	MOV	AL,KB_TYPA_RD	; COMMAND FOR TYPAMATIC RATE/DELAY
	CALL	SND_DATA	; SEND TO KEYBOARD
	MOV	CX,5		; SHIFT COUNT
	SHL	BH,CL		; SHIFT DELAY OVER
	MOV	AL,BL		; PUT IN RATE
	OR	AL,BH		; AND DELAY
	CALL	SND_DATA	; SEND TO KEYBOARD
	JMP	K10_EXIT	; RETURN TO CALLER

;------ WRITE TO KEYBOARD BUFFER

K500:	PUSH	SI		; SAVE SI
	CLI
	MOV	BX,@BUFFER_TAIL ; GET THE "IN TO" POINTER TO THE BUFFER
	MOV	SI,BX		; SAVE A COPY IN CASE BUFFER NOT FULL
	CALL	K4		; BUMP THE POINTER TO SEE IF BUFFER IS FULL
	CMP	BX,@BUFFER_HEAD ; WILL THE BUFFER OVERRUN IF WE STORE THIS?
	JE	K502		;  YES - INFORM CALLER OF ERROR
	MOV	[SI],CX 	;  NO  - PUT THE ASCII/SCAN CODE INTO BUFFER
	MOV	@BUFFER_TAIL,BX ; ADJUST "IN TO" POINTER TO REFLECT CHANGE
	SUB	AL,AL		; TELL CALLER THAT OPERATION WAS SUCCESSFUL
	JMP	K504		; SUB INSTRUCTION ALSO RESETS CARRY FLAG
K502:
	MOV	AL,01H		; BUFFER FULL INDICATION
K504:
	STI
	POP	SI		; RECOVER SI
	JMP	K10_EXIT	; RETURN TO CALLER

KEYBOARD_IO_1	ENDP
PAGE
;------ READ THE KEY TO FIGURE OUT WHAT TO DO ------------------------

K1S	PROC	NEAR
	MOV	BX,@BUFFER_HEAD ; GET POINTER TO HEAD OF BUFFER
	CMP	BX,@BUFFER_TAIL ; TEST END OF BUFFER
	JNE	K1U		; IF ANYTHING IN BUFFER DONT DO INTERRUPT

	MOV	AX,09002H	; MOVE IN WAIT CODE & TYPE
	INT	15H		; PERFORM OTHER FUNCTION
K1T:				; ASCII READ
	STI			; INTERRUPTS BACK ON DURING LOOP
	NOP			; ALLOW AN INTERRUPT TO OCCUR
K1U:	CLI			; INTERRUPTS BACK OFF
	MOV	BX,@BUFFER_HEAD ; GET POINTER TO HEAD OF BUFFER
	CMP	BX,@BUFFER_TAIL ; TEST END OF BUFFER
	PUSH	BX		; SAVE ADDRESS
	PUSHF			; SAVE FLAG
	CALL	MAKE_LED	; GO GET MODE INDICATOR DATA BYTE
	MOV	BL,@KB_FLAG_2	; GET PREVIOUS BITS
	XOR	BL,AL		; SEE IF ANY DIFFERENT
	AND	BL,07H		; ISOLATE INDICATOR BITS
	JZ	K1V		; IF NO CHANGE BYPASS UPDATE

	CALL	SND_LED1	; GO TURN ON MODE INDICATORS
	CLI			; DISABLE INTERRUPTS
K1V:	POPF			; RESTORE FLAGS
	POP	BX		; RESTORE ADDRESS
	JZ	K1T		; LOOP UNTIL SOMETHING IN BUFFER

	MOV	AX,[BX] 	; GET SCAN CODE AND ASCII CODE
	CALL	K4		; MOVE POINTER TO NEXT POSITION
	MOV	@BUFFER_HEAD,BX ; STORE VALUE IN VARIABLE
	RET			; RETURN
K1S	ENDP


;------ READ THE KEY TO SEE IF ONE IS PRESENT ------------------------

K2S	PROC	NEAR
	CLI			; INTERRUPTS OFF
	MOV	BX,@BUFFER_HEAD ; GET HEAD POINTER
	CMP	BX,@BUFFER_TAIL ; IF EQUAL (Z=1) THEN NOTHING THERE
	MOV	AX,[BX]
	PUSHF			; SAVE FLAGS

	PUSH	AX		; SAVE CODE
	CALL	MAKE_LED	; GO GET MODE INDICATOR DATA BYTE
	MOV	BL,@KB_FLAG_2	; GET PREVIOUS BITS
	XOR	BL,AL		; SEE IF ANY DIFFERENT
	AND	BL,KB_LEDS	; ISOLATE INDICATOR BITS
	JZ	K2T		; IF NO CHANGE BYPASS UPDATE

	CALL	SND_LED 	; GO TURN ON MODE INDICATORS
K2T:	POP	AX		; RESTORE CODE
	POPF			; RESTORE FLAGS
	STI			; INTERRUPTS BACK ON
	RET			; RETURN
K2S	ENDP


;------ ROUTINE TO TRANSLATE SCAN CODE PAIRS FOR EXTENDED CALLS

K10_E_XLAT:
	CMP	AL,0F0h 	; IS IT ONE OF THE FILL-INs?
	JNE	K10_E_RET	;  NO, PASS IT ON
	OR	AH,AH		; AH = 0 IS SPECIAL CASE
	JZ	K10_E_RET	;  PASS THIS ON UNCHANGED
	XOR	AL,AL		;  OTHERWISE SET AL = 0
K10_E_RET:
	RET			; GO BACK


;------ ROUTINE TO TRANSLATE SCAN CODE PAIRS FOR STANDARD CALLS

K10_S_XLAT:
	CMP	AH,0E0h 	; IS IT KEYPAD ENTER OR / ?
	JNE	K10_S2		;  NO, CONTINUE
	CMP	AL,0Dh		; KEYPAD ENTER CODE?
	JE	K10_S1		;  YES, MASSAGE A BIT
	CMP	AL,0Ah		; CTRL KEYPAD ENTER CODE?
	JE	K10_S1		;  YES, MASSAGE THE SAME
	MOV	AH,35h		;  NO, MUST BE KEYPAD /
	JMP	K10_USE 	; GIVE TO CALLER
K10_S1: MOV	AH,1Ch		; CONVERT TO COMPATIBLE OUTPUT
	JMP	K10_USE 	; GIVE TO CALLER

K10_S2: CMP	AH,84h		; IS IT ONE OF THE EXTENDED ONES?
	JA	K10_DIS 	;  YES, THROW AWAY AND GET ANOTHER CHAR

	CMP	AL,0F0h 	; IS IT ONE OF THE FILL-INs?
	JNE	K10_S3		;  NO, TRY LAST TEST
	OR	AH,AH		; AH = 0 IS SPECIAL CASE
	JZ	K10_USE 	;  PASS THIS ON UNCHANGED
	JMP	K10_DIS 	;  THROW AWAY THE REST

K10_S3: CMP	AL,0E0h 	; IS IT AN EXTENSION OF A PREVIOUS ONE?
	JNE	K10_USE 	;  NO, MUST BE A STANDARD CODE
	OR	AH,AH		; AH = 0 IS SPECIAL CASE
	JZ	K10_USE 	; JUMP IF AH = 0
	XOR	AL,AL		; CONVERT TO COMPATIBLE OUTPUT
	JMP	K10_USE 	; PASS IT ON TO CALLER

K10_USE:
	CLC			; CLEAR CARRY FLAG TO INDICATE GOOD CODE
	RET			; RETURN
K10_DIS:
	STC			; SET CARRY FLAG TO INDICATE DISCARD CODE
	RET			; RETURN
PAGE
;----------------------------------------------------------------------
;	INCREMENT BUFFER POINTER ROUTINE			      -
;----------------------------------------------------------------------

K4	PROC	NEAR
	INC	BX			; MOVE TO NEXT WORD IN LIST
	INC	BX

	CMP	BX,@BUFFER_END		; AT END OF BUFFER?
	JNE	K5			; NO, CONTINUE
	MOV	BX,@BUFFER_START	; YES, RESET TO BUFFER BEGINNING
K5:	RET
K4	ENDP

;--- HARDWARE INT  09 H -- ( IRQ LEVEL 1 ) -------------------------------------
;									       :
;	KEYBOARD INTERRUPT ROUTINE					       :
;									       :
;-------------------------------------------------------------------------------

KB_INT_1 PROC	FAR
	STI				; ENABLE INTERRUPTS
	PUSH	BP
	PUSH	AX
	PUSH	BX
	PUSH	CX
	PUSH	DX
	PUSH	SI
	PUSH	DI
	PUSH	DS
	PUSH	ES
	CLD				; FORWARD DIRECTION
	CALL	DDS			; SET UP ADDRESSING

;-----	WAIT FOR KEYBOARD DISABLE COMMAND TO BE ACCEPTED

	MOV	AL,DIS_KBD		; DISABLE THE KEYBOARD COMMAND
	CALL	SHIP_IT 		; EXECUTE DISABLE
	CLI				; DISABLE INTERRUPTS
	SUB	CX,CX			; SET MAXIMUM TIMEOUT
KB_INT_01:
	IN	AL,STATUS_PORT		; READ ADAPTER STATUS
	TEST	AL,INPT_BUF_FULL	; CHECK INPUT BUFFER FULL STATUS BIT
	LOOPNZ	KB_INT_01		; WAIT FOR COMMAND TO BE ACCEPTED

;-----	READ CHARACTER FROM KEYBOARD INTERFACE

	IN	AL,PORT_A		; READ IN THE CHARACTER

;-----	SYSTEM HOOK  INT 15H - FUNCTION 4FH  (ON HARDWARE INTERRUPT LEVEL 9H)

	MOV	AH,04FH 		; SYSTEM INTERCEPT - KEY CODE FUNCTION
	STC				; SET CY= 1 (IN CASE OF IRET)
	INT	15H			; CASSETTE CALL   (AL)= KEY SCAN CODE
					;  RETURNS CY= 1 FOR INVALID FUNCTION
	JC	KB_INT_02		; CONTINUE IF CARRY FLAG SET ((AL)=CODE)
	JMP	K26			; EXIT IF SYSTEM HANDLED SCAN CODE
					;  EXIT HANDLES HARDWARE EOI AND ENABLE

;-----	CHECK FOR A RESEND COMMAND TO KEYBOARD

KB_INT_02:				;	(AL)= SCAN CODE
	STI				; ENABLE INTERRUPTS AGAIN
	CMP	AL,KB_RESEND		; IS THE INPUT A RESEND
	JE	KB_INT_4		; GO IF RESEND

;-----	CHECK FOR RESPONSE TO A COMMAND TO KEYBOARD

	CMP	AL,KB_ACK		; IS THE INPUT AN ACKNOWLEDGE
	JNZ	KB_INT_2		; GO IF NOT

;-----	A COMMAND TO THE KEYBOARD WAS ISSUED

	CLI				; DISABLE INTERRUPTS
	OR	@KB_FLAG_2,KB_FA	; INDICATE ACK RECEIVED
	JMP	K26			; RETURN IF NOT (ACK RETURNED FOR DATA)

;-----	RESEND THE LAST BYTE

KB_INT_4:
	CLI				; DISABLE INTERRUPTS
	OR	@KB_FLAG_2,KB_FE	; INDICATE RESEND RECEIVED
	JMP	K26			; RETURN IF NOT (ACK RETURNED FOR DATA)


;-----	UPDATE MODE INDICATORS IF CHANGE IN STATE

KB_INT_2:
	PUSH	AX			; SAVE DATA IN
	CALL	MAKE_LED		; GO GET MODE INDICATOR DATA BYTE
	MOV	BL,@KB_FLAG_2		; GET PREVIOUS BITS
	XOR	BL,AL			; SEE IF ANY DIFFERENT
	AND	BL,KB_LEDS		; ISOLATE INDICATOR BITS
	JZ	UP0			; IF NO CHANGE BYPASS UPDATE
	CALL	SND_LED 		; GO TURN ON MODE INDICATORS
UP0:	POP	AX			; RESTORE DATA IN
PAGE
;----------------------------------------------------------------------
;	      START OF KEY PROCESSING				      -
;----------------------------------------------------------------------

	MOV	AH,AL			; SAVE SCAN CODE IN AH ALSO

;------ TEST FOR OVERRUN SCAN CODE FROM KEYBOARD

	CMP	AL,KB_OVER_RUN		; IS THIS AN OVERRUN CHAR
	JNZ	K16			; NO, TEST FOR SHIFT KEY
	JMP	K62			; BUFFER_FULL_BEEP

K16:	PUSH	CS
	POP	ES			; ESTABLISH ADDRESS OF TABLES
	MOV	BH,@KB_FLAG_3		; LOAD FLAGS FOR TESTING

;------ TEST TO SEE IF A READ_ID IS IN PROGRESS

	TEST	BH,RD_ID+LC_AB		; ARE WE DOING A READ ID?
	JZ	NOT_ID			; CONTINUE IF NOT
	JNS	TST_ID_2		; IS THE RD_ID FLAG ON?
	CMP	AL,ID_1 		; IS THIS THE 1ST ID CHARACTER?
	JNE	RST_RD_ID
	OR	@KB_FLAG_3,LC_AB	; INDICATE 1ST ID WAS OK
RST_RD_ID:
	AND	@KB_FLAG_3,NOT RD_ID	; RESET THE READ ID FLAG
	JMP	SHORT ID_EX		; AND EXIT

TST_ID_2:
	AND	@KB_FLAG_3,NOT LC_AB	; RESET FLAG
	CMP	AL,ID_2A		; IS THIS THE 2ND ID CHARACTER?
	JE	KX_BIT			;  JUMP IF SO
	CMP	AL,ID_2 		; IS THIS THE 2ND ID CHARACTER?
	JNE	ID_EX			; LEAVE IF NOT

;-----	A READ ID SAID THAT IT WAS ENHANCED KEYBOARD

	TEST	BH,SET_NUM_LK		; SHOULD WE SET NUM LOCK?
	JZ	KX_BIT			; EXIT IF NOT
	OR	@KB_FLAG,NUM_STATE	; FORCE NUM LOCK ON
	CALL	SND_LED 		; GO SET THE NUM LOCK INDICATOR
KX_BIT: OR	@KB_FLAG_3,KBX		; INDICATE ENHANCED KEYBOARD WAS FOUND
ID_EX:	JMP	K26			; EXIT


NOT_ID:
	CMP	AL,MC_E0		; IS THIS THE GENERAL MARKER CODE?
	JNE	TEST_E1 		;
	OR	@KB_FLAG_3,LC_E0+KBX	; SET FLAG BIT, SET KBX, AND
	JMP	SHORT EXIT		; THROW AWAY THIS CODE

TEST_E1:
	CMP	AL,MC_E1		; IS THIS THE PAUSE KEY?
	JNE	NOT_HC			;
	OR	@KB_FLAG_3,LC_E1+KBX	; SET FLAG, PAUSE KEY MARKER CODE
EXIT:	JMP	K26A			; THROW AWAY THIS CODE

NOT_HC:
	AND	AL,07FH 		; TURN OFF THE BREAK BIT
	TEST	BH,LC_E0		; LAST CODE THE E0 MARKER CODE?
	JZ	NOT_LC_E0		; JUMP IF NOT

	MOV	CX,2			; LENGTH OF SEARCH
	MOV	DI,OFFSET K6+6		; IS THIS A SHIFT KEY?
	REPNE	SCASB			; CHECK IT
	JNE	K16A			; NO, CONTINUE KEY PROCESSING
	JMP	SHORT K16B		; YES, THROW AWAY & RESET FLAG

NOT_LC_E0:
	TEST	BH,LC_E1		; LAST CODE THE E1 MARKER CODE?
	JZ	T_SYS_KEY		; JUMP IF NOT

	MOV	CX,4			; LENGTH OF SEARCH
	MOV	DI,OFFSET K6+4		; IS THIS AN ALT, CTL, OR SHIFT?
	REPNE	SCASB			; CHECK IT
	JE	EXIT			; THROW AWAY IF SO

	CMP	AL,NUM_KEY		; IS IT THE PAUSE KEY?
	JNE	K16B			; NO, THROW AWAY & RESET FLAG
	TEST	AH,80H			; YES, IS IT THE BREAK OF THE KEY?
	JNZ	K16B			;  YES, THROW THIS AWAY TOO
	TEST	@KB_FLAG_1,HOLD_STATE	;  NO, ARE WE PAUSED ALREADY?
	JNZ	K16B			;  YES, THROW AWAY
	JMP	K39P

;------ TEST FOR SYSTEM KEY

T_SYS_KEY:
	CMP	AL,SYS_KEY		; IS IT THE SYSTEM KEY?
	JNZ	K16A			; CONTINUE IF NOT

	TEST	AH,080H 		; CHECK IF THIS A BREAK CODE
	JNZ	K16C			; DO NOT TOUCH SYSTEM INDICATOR IF TRUE

	TEST	@KB_FLAG_1,SYS_SHIFT	; SEE IF IN SYSTEM KEY HELD DOWN
	JNZ	K16B			; IF YES, DON'T PROCESS SYSTEM INDICATOR

	OR	@KB_FLAG_1,SYS_SHIFT	; INDICATE SYSTEM KEY DEPRESSED
	MOV	AL,EOI			; END OF INTERRUPT COMMAND
	OUT	020H,AL 		; SEND COMMAND TO INTERRUPT CONTROL PORT
					; INTERRUPT-RETURN-NO-EOI
	MOV	AL,ENA_KBD		; INSURE KEYBOARD IS ENABLED
	CALL	SHIP_IT 		; EXECUTE ENABLE
	MOV	AX,08500H		; FUNCTION VALUE FOR MAKE OF SYSTEM KEY
	STI				; MAKE SURE INTERRUPTS ENABLED
	INT	15H			; USER INTERRUPT
	JMP	K27A			; END PROCESSING

K16B:	JMP	K26			; IGNORE SYSTEM KEY

K16C:	AND	@KB_FLAG_1,NOT SYS_SHIFT ;TURN OFF SHIFT KEY HELD DOWN
	MOV	AL,EOI			; END OF INTERRUPT COMMAND
	OUT	020H,AL 		; SEND COMMAND TO INTERRUPT CONTROL PORT
					; INTERRUPT-RETURN-NO-EOI
	MOV	AL,ENA_KBD		; INSURE KEYBOARD IS ENABLED
	CALL	SHIP_IT 		; EXECUTE ENABLE
	MOV	AX,08501H		; FUNCTION VALUE FOR BREAK OF SYSTEM KEY
	STI				; MAKE SURE INTERRUPTS ENABLED
	INT	15H			; USER INTERRUPT
	JMP	K27A			; IGNORE SYSTEM KEY

;------ TEST FOR SHIFT KEYS

K16A:	MOV	BL,@KB_FLAG		; PUT STATE FLAGS IN BL
	MOV	DI,OFFSET K6		; SHIFT KEY TABLE
	MOV	CX,OFFSET K6L		; LENGTH
	REPNE	SCASB			; LOOK THROUGH THE TABLE FOR A MATCH
	MOV	AL,AH			; RECOVER SCAN CODE
	JE	K17			; JUMP IF MATCH FOUND
	JMP	K25			; IF NO MATCH, THEN SHIFT NOT FOUND

;------ SHIFT KEY FOUND

K17:	SUB	DI,OFFSET K6+1		; ADJUST PTR TO SCAN CODE MTCH
	MOV	AH,CS:K7[DI]		; GET MASK INTO AH
	MOV	CL,2			; SET UP COUNT FOR FLAG SHIFTS
	TEST	AL,80H			; TEST FOR BREAK KEY
	JZ	K17C
	JMP	K23			; JUMP IF BREAK

;------ DETERMINE SET OR TOGGLE

K17C:	CMP	AH,SCROLL_SHIFT
	JAE	K18			; IF SCROLL SHIFT OR ABOVE, TOGGLE KEY

;------ PLAIN SHIFT KEY, SET SHIFT ON

	OR	@KB_FLAG,AH		; TURN ON SHIFT BIT
	TEST	AH,CTL_SHIFT+ALT_SHIFT	; IS IT ALT OR CTRL ?
	JNZ	K17D			;  YES, MORE FLAGS TO SET
	JMP	K26			;  NO, INTERRUPT_RETURN
K17D:	TEST	BH,LC_E0		; IS THIS ONE OF THE NEW KEYS?
	JZ	K17E			;  NO, JUMP
	OR	@KB_FLAG_3,AH		; SET BITS FOR RIGHT CTRL, ALT
	JMP	K26			; INTERRUPT_RETURN
K17E:	SHR	AH,CL			; MOVE FLAG BITS TWO POSITIONS
	OR	@KB_FLAG_1,AH		; SET BITS FOR LEFT CTRL, ALT
	JMP	K26			; INTERRUPT_RETURN

;------ TOGGLED SHIFT KEY, TEST FOR 1ST MAKE OR NOT

K18:					; SHIFT-TOGGLE
	TEST	BL, CTL_SHIFT		; CHECK CTL SHIFT STATE
	JZ	K18A			; JUMP IF NOT CTL STATE
	JMP	K25			; JUMP IF CTL STATE
K18A:	CMP	AL,INS_KEY		; CHECK FOR INSERT KEY
	JNE	K22			; JUMP IF NOT INSERT KEY
	TEST	BL,ALT_SHIFT		; CHECK FOR ALTERNATE SHIFT
	JZ	K18B			; JUMP IF NOT ALTERNATE SHIFT
	JMP	K25			; JUMP IF ALTERNATE SHIFT
K18B:	TEST	BH,LC_E0		; IS THIS THE NEW INSERT KEY?
	JNZ	K22			; YES, THIS ONE'S NEVER A "0"
K19:	TEST	BL,NUM_STATE		; CHECK FOR BASE STATE
	JNZ	K21			; JUMP IF NUM LOCK IS ON
	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT  ; TEST FOR SHIFT STATE
	JZ	K22			   ; JUMP IF BASE STATE
K20:	MOV	AH,AL			; PUT SCAN CODE BACK IN AH
	JMP	K25			; NUMERAL "0", STNDRD. PROCESSING

K21:	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT  ; MIGHT BE NUMERIC
	JZ	K20			   ; IS NUMERIC, STD. PROC.

K22:					; SHIFT TOGGLE KEY HIT; PROCESS IT
	TEST	AH,@KB_FLAG_1		; IS KEY ALREADY DEPRESSED
	JZ	K22A
	JMP	K26			; JUMP IF KEY ALREADY DEPRESSED
K22A:	OR	@KB_FLAG_1,AH		; INDICATE THAT THE KEY IS DEPRESSED
	XOR	@KB_FLAG,AH		; TOGGLE THE SHIFT STATE

;------ TOGGLE LED IF CAPS, NUM, OR SCROLL KEY DEPRESSED

	TEST	AH,CAPS_SHIFT+NUM_SHIFT+SCROLL_SHIFT ; SHIFT TOGGLE?
	JZ	K22B			; GO IF NOT
	PUSH	AX			; SAVE SCAN CODE AND SHIFT MASK
	CALL	SND_LED 		; GO TURN MODE INDICATORS ON
	POP	AX			; RESTORE SCAN CODE

K22B:	CMP	AL,INS_KEY		; TEST FOR 1ST MAKE OF INSERT KEY
	JNE	K26			; JUMP IF NOT INSERT KEY
	MOV	AH,AL			; SCAN CODE IN BOTH HALVES OF AX
	JMP	K28			; FLAGS UPDATED, PROC. FOR BUFFER

;------ BREAK SHIFT FOUND

K23:					; BREAK-SHIFT-FOUND
	CMP	AH,SCROLL_SHIFT 	; IS THIS A TOGGLE KEY
	NOT	AH			; INVERT MASK
	JAE	K24			; YES, HANDLE BREAK TOGGLE
	AND	@KB_FLAG,AH		; TURN OFF SHIFT BIT
	CMP	AH,NOT CTL_SHIFT	; IS THIS ALT OR CTL?
	JA	K23D			;  NO, ALL DONE

	TEST	BH,LC_E0		; 2ND ALT OR CTL?
	JZ	K23A			; NO, HANDLE NORMALLY
	AND	@KB_FLAG_3,AH		; RESET BIT FOR RIGHT ALT OR CTL
	JMP	SHORT K23B		; CONTINUE
K23A:	SAR	AH,CL			; MOVE THE MASK BIT TWO POSITIONS
	AND	@KB_FLAG_1,AH		; RESET BIT FOR LEFT ALT OR CTL
K23B:	MOV	AH,AL			; SAVE SCAN CODE
	MOV	AL,@KB_FLAG_3		; GET RIGHT ALT & CTRL FLAGS
	SHR	AL,CL			; MOVE TO BITS 1 & 0
	OR	AL,@KB_FLAG_1		; PUT IN LEFT ALT & CTL FLAGS
	SHL	AL,CL			; MOVE BACK TO BITS 3 & 2
	AND	AL,ALT_SHIFT+CTL_SHIFT	; FILTER OUT OTHER GARBAGE
	OR	@KB_FLAG,AL		; PUT RESULT IN THE REAL FLAGS
	MOV	AL,AH			; RECOVER SAVED SCAN CODE

K23D:	CMP	AL,ALT_KEY+80H		; IS THIS ALTERNATE SHIFT RELEASE
	JNE	K26			; INTERRUPT_RETURN

;------ ALTERNATE SHIFT KEY RELEASED, GET THE VALUE INTO BUFFER

	MOV	AL,@ALT_INPUT
	MOV	AH,0			; SCAN CODE OF 0
	MOV	@ALT_INPUT,AH		; ZERO OUT THE FIELD
	CMP	AL,0			; WAS THE INPUT=0
	JE	K26			; INTERRUPT_RETURN
	JMP	K61			; IT WASN'T, SO PUT IN BUFFER

K24:					; BREAK-TOGGLE
	AND	@KB_FLAG_1,AH		; INDICATE NO LONGER DEPRESSED
	JMP	SHORT K26		; INTERRUPT_RETURN

;------ TEST FOR HOLD STATE
					; AL, AH = SCAN CODE
K25:					; NO-SHIFT-FOUND
	CMP	AL,80H			; TEST FOR BREAK KEY
	JAE	K26			; NOTHING FOR BREAK CHARS FROM HERE ON
	TEST	@KB_FLAG_1,HOLD_STATE	; ARE WE IN HOLD STATE
	JZ	K28			; BRANCH AROUND TEST IF NOT
	CMP	AL,NUM_KEY
	JE	K26			; CAN'T END HOLD ON NUM_LOCK
	AND	@KB_FLAG_1,NOT HOLD_STATE  ; TURN OFF THE HOLD STATE BIT

K26:
	AND	@KB_FLAG_3,NOT LC_E0+LC_E1 ; RESET LAST CHAR H.C. FLAG

K26A:					; INTERRUPT-RETURN
	CLI				; TURN OFF INTERRUPTS
	MOV	AL,EOI			; END OF INTERRUPT COMMAND
	OUT	020H,AL 		; SEND COMMAND TO INTERRUPT CONTROL PORT

K27:					; INTERRUPT-RETURN-NO-EOI
	MOV	AL,ENA_KBD		; INSURE KEYBOARD IS ENABLED
	CALL	SHIP_IT 		; EXECUTE ENABLE

K27A:	CLI				; DISABLE INTERRUPTS
	POP	ES			; RESTORE REGISTERS
	POP	DS
	POP	DI
	POP	SI
	POP	DX
	POP	CX
	POP	BX
	POP	AX
	POP	BP
	IRET				; RETURN
PAGE
;------ NOT IN HOLD STATE
					; AL, AH = SCAN CODE (ALL MAKES)
K28:					; NO-HOLD-STATE
	CMP	AL,88			; TEST FOR OUT-OF-RANGE SCAN CODES
	JA	K26			; IGNORE IF OUT-OF-RANGE

	TEST	BL,ALT_SHIFT		; ARE WE IN ALTERNATE SHIFT?
	JZ	K28A			; JUMP IF NOT ALTERNATE

	TEST	BH,KBX			; IS THIS THE ENHANCED KEYBOARD?
	JZ	K29			; NO, ALT STATE IS REAL

	TEST	@KB_FLAG_1,SYS_SHIFT	; YES, IS SYSREQ KEY DOWN?
	JZ	K29			;  NO, ALT STATE IS REAL
K28A:	JMP	K38			;  YES, THIS IS PHONY ALT STATE
					;	DUE TO PRESSING SYSREQ

;------ TEST FOR RESET KEY SEQUENCE (CTL ALT DEL)

K29:					; TEST-RESET
	TEST	BL,CTL_SHIFT		; ARE WE IN CONTROL SHIFT ALSO?
	JZ	K31			; NO_RESET
	CMP	AL,DEL_KEY		; SHIFT STATE IS THERE, TEST KEY
	JNE	K31			; NO_RESET

;------ CTL-ALT-DEL HAS BEEN FOUND, DO I/O CLEANUP

	MOV	@RESET_FLAG,1234H	; SET FLAG FOR RESET FUNCTION
	JMP	START_1 		; JUMP TO POWER ON DIAGNOSTICS

;----------------------  TABLES FOR ALT CASE  ------------------------
;------ ALT-INPUT-TABLE
K30	LABEL	BYTE
	DB	82,79,80,81,75
	DB	76,77,71,72,73		; 10 NUMBERS ON KEYPAD
;------ SUPER-SHIFT-TABLE
	DB	16,17,18,19,20,21	; A-Z TYPEWRITER CHARS
	DB	22,23,24,25,30,31
	DB	32,33,34,35,36,37
	DB	38,44,45,46,47,48
	DB	49,50

;------ IN ALTERNATE SHIFT, RESET NOT FOUND

K31:					; NO-RESET
	CMP	AL,57			; TEST FOR SPACE KEY
	JNE	K311			; NOT THERE
	MOV	AL,' '                  ; SET SPACE CHAR
	JMP	K57			; BUFFER_FILL
K311:
	CMP	AL,15			; TEST FOR TAB KEY
	JNE	K312			; NOT THERE
	MOV	AX,0A500h		; SET SPECIAL CODE FOR ALT-TAB
	JMP	K57			; BUFFER_FILL
K312:
	CMP	AL,74			; TEST FOR KEYPAD -
	JE	K37B			; GO PROCESS
	CMP	AL,78			; TEST FOR KEYPAD +
	JE	K37B			; GO PROCESS

;------ LOOK FOR KEY PAD ENTRY

K32:					; ALT-KEY-PAD
	MOV	DI,OFFSET K30		; ALT-INPUT-TABLE
	MOV	CX,10			; LOOK FOR ENTRY USING KEYPAD
	REPNE	SCASB			; LOOK FOR MATCH
	JNE	K33			; NO_ALT_KEYPAD
	TEST	BH,LC_E0		; IS THIS ONE OF THE NEW KEYS?
	JNZ	K37C			;  YES, JUMP, NOT NUMPAD KEY
	SUB	DI,OFFSET K30+1 	; DI NOW HAS ENTRY VALUE
	MOV	AL,@ALT_INPUT		; GET THE CURRENT BYTE
	MOV	AH,10			; MULTIPLY BY 10
	MUL	AH
	ADD	AX,DI			; ADD IN THE LATEST ENTRY
	MOV	@ALT_INPUT,AL		; STORE IT AWAY
K32A:	JMP	K26			; THROW AWAY THAT KEYSTROKE

;------ LOOK FOR SUPERSHIFT ENTRY

K33:					; NO-ALT-KEYPAD
	MOV	@ALT_INPUT,0		; ZERO ANY PREVIOUS ENTRY INTO INPUT
	MOV	CX,26			; (DI),(ES) ALREADY POINTING
	REPNE	SCASB			; LOOK FOR MATCH IN ALPHABET
	JE	K37A			; MATCH FOUND, GO FILL THE BUFFER

;------ LOOK FOR TOP ROW OF ALTERNATE SHIFT

K34:					; ALT-TOP-ROW
	CMP	AL,2			; KEY WITH '1' ON IT
	JB	K37B			; MUST BE ESCAPE
	CMP	AL,13			; IS IT IN THE REGION
	JA	K35			;  NO, ALT-SOMETHING ELSE
	ADD	AH,118			; CONVERT PSEUDO SCAN CODE TO RANGE
	JMP	SHORT K37A		; GO FILL THE BUFFER

;------ TRANSLATE ALTERNATE SHIFT PSEUDO SCAN CODES

K35:					; ALT-FUNCTION
	CMP	AL,F11_M		; IS IT F11?
	JB	K35A			;  NO, BRANCH
	CMP	AL,F12_M		; IS IT F12?
	JA	K35A			;  NO, BRANCH
	ADD	AH,52			; CONVERT TO PSEUDO SCAN CODE
	JMP	SHORT K37A		; GO FILL THE BUFFER

K35A:	TEST	BH,LC_E0		; DO WE HAVE ONE OF THE NEW KEYS?
	JZ	K37			;  NO, JUMP
	CMP	AL,28			; TEST FOR KEYPAD ENTER
	JNZ	K35B			; NOT THERE
	MOV	AX,0A600h		; SPECIAL CODE
	JMP	K57			; BUFFER FILL
K35B:	CMP	AL,83			; TEST FOR DELETE KEY
	JE	K37C			; HANDLE WITH OTHER EDIT KEYS
	CMP	AL,53			; TEST FOR KEYPAD /
	JNE	K32A			; HANDLE WITH OTHER EDIT KEYS
	MOV	AX,0A400h		; SPECIAL CODE
	JMP	K57			; BUFFER FILL

K37:	CMP	AL,59			; TEST FOR FUNCTION KEYS (F1)
	JB	K37B			;  NO FN, HANDLE W/OTHER EXTENDED
	CMP	AL,68			; IN KEYPAD REGION?
					; OR NUMLOCK, SCROLLOCK?
	JA	K32A			; IF SO, IGNORE
	ADD	AH,45			; CONVERT TO PSEUDO SCAN CODE

K37A:	MOV	AL,0			; ASCII CODE OF ZERO
	JMP	K57			; PUT IT IN THE BUFFER

K37B:	MOV	AL,0F0h 		; USE SPECIAL ASCII CODE
	JMP	K57			; PUT IT IN THE BUFFER

K37C:	ADD	AL,80			; CONVERT SCAN CODE (EDIT KEYS)
	MOV	AH,AL			; (SCAN CODE NOT IN AH FOR INSERT)
	JMP	K37A			; PUT IT IN THE BUFFER

;------ NOT IN ALTERNATE SHIFT

K38:					; NOT-ALT-SHIFT
					; BL STILL HAS SHIFT FLAGS
	TEST	BL,CTL_SHIFT		; ARE WE IN CONTROL SHIFT?
	JNZ	K38A			;  YES, START PROCESSING
	JMP	K44			; NOT-CTL-SHIFT

;------ CONTROL SHIFT, TEST SPECIAL CHARACTERS

;------ TEST FOR BREAK

K38A:	CMP	AL,SCROLL_KEY		; TEST FOR BREAK
	JNE	K39			; NO-BREAK
	TEST	BH,KBX			; IS THIS THE ENHANCED KEYBOARD?
	JZ	K38B			;  NO, BREAK IS VALID
	TEST	BH,LC_E0		;  YES, WAS LAST CODE AN E0?
	JZ	K39			;  NO-BREAK, TEST FOR PAUSE

K38B:	MOV	BX,@BUFFER_HEAD 	; RESET BUFFER TO EMPTY
	MOV	@BUFFER_TAIL,BX
	MOV	@BIOS_BREAK,80H 	; TURN ON @BIOS_BREAK BIT

;-------- ENABLE KEYBOARD

	MOV	AL,ENA_KBD		; ENABLE KEYBOARD
	CALL	SHIP_IT 		; EXECUTE ENABLE
	INT	1BH			; BREAK INTERRUPT VECTOR
	SUB	AX,AX			; PUT OUT DUMMY CHARACTER
	JMP	K57			; BUFFER_FILL

;-------- TEST FOR PAUSE

K39:					; NO_BREAK
	TEST	BH,KBX			; IS THIS THE ENHANCED KEYBOARD?
	JNZ	K41			; YES, THEN THIS CAN'T BE PAUSE
	CMP	AL,NUM_KEY		; LOOK FOR PAUSE KEY
	JNE	K41			; NO-PAUSE
K39P:	OR	@KB_FLAG_1,HOLD_STATE	; TURN ON THE HOLD FLAG

;-------- ENABLE KEYBOARD

	MOV	AL,ENA_KBD		; ENABLE KEYBOARD
	CALL	SHIP_IT 		; EXECUTE ENABLE
K39A:	MOV	AL,EOI			; END OF INTERRUPT TO CONTROL PORT
	OUT	020H,AL 		; ALLOW FURTHER KEYSTROKE INTS

;------ DURING PAUSE INTERVAL, TURN CRT BACK ON

	CMP	@CRT_MODE,7		; IS THIS BLACK AND WHITE CARD
	JE	K40			; YES, NOTHING TO DO
	MOV	DX,03D8H		; PORT FOR COLOR CARD
	MOV	AL,@CRT_MODE_SET	; GET THE VALUE OF THE CURRENT MODE
	OUT	DX,AL			; SET THE CRT MODE, SO THAT CRT IS ON
K40:					; PAUSE-LOOP
	TEST	@KB_FLAG_1,HOLD_STATE
	JNZ	K40			; LOOP UNTIL FLAG TURNED OFF
	JMP	K27			; INTERRUPT_RETURN_NO_EOI

;------ TEST SPECIAL CASE KEY 55

K41:					; NO-PAUSE
	CMP	AL,55			; TEST FOR */PRTSC KEY
	JNE	K42			; NOT-KEY-55
	TEST	BH,KBX			; IS THIS THE ENHANCED KEYBOARD?
	JZ	K41A			;  NO, CTL-PRTSC IS VALID
	TEST	BH,LC_E0		;  YES, WAS LAST CODE AN E0?
	JZ	K42B			;  NO, TRANSLATE TO A FUNCTION
K41A:	MOV	AX,114*256		; START/STOP PRINTING SWITCH
	JMP	K57			; BUFFER_FILL

;------ SET UP TO TRANSLATE CONTROL SHIFT

K42:					; NOT-KEY-55
	CMP	AL,15			; IS IT THE TAB KEY?
	JE	K42B			;  YES, XLATE TO FUNCTION CODE
	CMP	AL,53			; IS IT THE / KEY?
	JNE	K42A			;  NO, NO MORE SPECIAL CASES
	TEST	BH,LC_E0		;  YES, IS IT FROM THE KEYPAD?
	JZ	K42A			;   NO, JUST TRANSLATE
	MOV	AX,09500h		;   YES, SPECIAL CODE FOR THIS ONE
	JMP	K57			;   BUFFER FILL

K42A:	MOV	BX,OFFSET K8		; SET UP TO TRANSLATE CTL
	CMP	AL,59			; IS IT IN CHARACTER TABLE?
	JB	K45F			;  YES, GO TRANSLATE CHAR
K42B:	MOV	BX,OFFSET K8		; SET UP TO TRANSLATE CTL
	JMP	K64			;  NO, GO TRANSLATE_SCAN

;------ NOT IN CONTROL SHIFT

K44:	CMP	AL,55			; PRINT SCREEN KEY
	JNE	K45			; NOT-PRINT-SCREEN
	TEST	BH,KBX			; IS THIS ENHANCED KEYBOARD?
	JZ	K44A			;  NO, TEST FOR SHIFT STATE
	TEST	BH,LC_E0		;  YES, LAST CODE A MARKER?
	JNZ	K44B			;   YES, IS PRINT SCREEN
	JMP	SHORT K45C		;   NO, XLATE TO "*" CHARACTER
K44A:	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT   ;NOT 101 KBD, SHIFT KEY DOWN?
	JZ	K45C			;   ; NO, XLATE TO "*" CHARACTER

;------ ISSUE INTERRUPT TO INDICATE PRINT SCREEN FUNCTION
K44B:	MOV	AL,ENA_KBD		; INSURE KEYBOARD IS ENABLED
	CALL	SHIP_IT 		; EXECUTE ENABLE
	MOV	AL,EOI			; END OF CURRENT INTERRUPT
	OUT	020H,AL 		;  SO FURTHER THINGS CAN HAPPEN
	PUSH	BP			; SAVE POINTER
	INT	05H			; ISSUE PRINT SCREEN INTERRUPT
	POP	BP			; RESTORE POINTER
	AND	@KB_FLAG_3,NOT LC_E0+LC_E1 ;ZERO OUT THESE FLAGS
	JMP	K27			; GO BACK WITHOUT EOI OCCURRING


;------ HANDLE THE IN-CORE KEYS
K45:					; NOT-PRINT-SCREEN
	CMP	AL,58			; TEST FOR IN-CORE AREA
	JA	K46			; JUMP IF NOT

	CMP	AL,53			; IS THIS THE "/" KEY?
	JNE	K45A			;  NO, JUMP
	TEST	BH,LC_E0		; WAS LAST CODE THE MARKER?
	JNZ	K45C			;  YES, TRANSLATE TO CHARACTER

K45A:	MOV	CX,26			; LENGTH OF SEARCH
	MOV	DI,OFFSET K30+10	; POINT TO TABLE OF A-Z CHARS
	REPNE	SCASB			; IS THIS A LETTER KEY?
	JNE	K45B			;  NO, SYMBOL KEY

	TEST	BL,CAPS_STATE		; ARE WE IN CAPS LOCK?
	JNZ	K45D			; TEST FOR SURE
K45B:	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT ; ARE WE IN SHIFT STATE?
	JNZ	K45E			  ; YES, UPPERCASE
					  ; NO, LOWERCASE
K45C:	MOV	BX,OFFSET K10		; TRANSLATE TO LOWERCASE LETTERS
	JMP	SHORT K56
K45D:					; ALMOST-CAPS-STATE
	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT ; CL ON. IS SHIFT ON, TOO?
	JNZ	K45C			; SHIFTED TEMP OUT OF CAPS STATE
K45E:	MOV	BX,OFFSET K11		; TRANSLATE TO UPPERCASE LETTERS
K45F:	JMP	SHORT K56


;------ TEST FOR KEYS F1 - F10
K46:					; NOT IN-CORE AREA
	CMP	AL,68			; TEST FOR F1 - F10
	JA	K47			; JUMP IF NOT
	JMP	SHORT K53		; YES, GO DO FN KEY PROCESS


;------ HANDLE THE NUMERIC PAD KEYS
K47:					; NOT F1 - F10
	CMP	AL,83			; TEST FOR NUMERIC PAD KEYS
	JA	K52			; JUMP IF NOT

;------ KEYPAD KEYS, MUST TEST NUM LOCK FOR DETERMINATION
K48:	CMP	AL,74			; SPECIAL CASE FOR MINUS
	JE	K45E			; GO TRANSLATE
	CMP	AL,78			; SPECIAL CASE FOR PLUS
	JE	K45E			; GO TRANSLATE
	TEST	BH,LC_E0		; IS THIS ONE OF THE NEW KEYS?
	JNZ	K49			;  YES, TRANSLATE TO BASE STATE

	TEST	BL,NUM_STATE		; ARE WE IN NUM LOCK?
	JNZ	K50			; TEST FOR SURE
	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT ; ARE WE IN SHIFT STATE
	JNZ	K51			  ; IF SHIFTED, REALLY NUM STATE

;------ BASE CASE FOR KEYPAD
K49:	CMP	AL,76			; SPECIAL CASE FOR BASE STATE 5
	JNE	K49A			; CONTINUE IF NOT KEYPAD 5
	MOV	AL,0F0h 		; SPECIAL ASCII CODE
	JMP	K57			; BUFFER FILL
K49A:	MOV	BX,OFFSET K10		; BASE CASE TABLE
	JMP	SHORT K64		; CONVERT TO PSEUDO SCAN

;------ MIGHT BE NUM LOCK, TEST SHIFT STATUS
K50:	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT	; ALMOST-NUM-STATE
	JNZ	K49			; SHIFTED TEMP OUT OF NUM STATE
K51:	JMP	SHORT K45E		; REALLY_NUM_STATE


;------ TEST FOR THE NEW KEY ON WT KEYBOARDS

K52:					; NOT A NUMPAD KEY
	CMP	AL,86			; IS IT THE NEW WT KEY?
	JNE	K53			; JUMP IF NOT
	JMP	SHORT K45B		; HANDLE WITH REST OF LETTER KEYS


;------ MUST BE F11 OR F12
					; F1 - F10 COME HERE, TOO
K53:	TEST	BL,LEFT_SHIFT+RIGHT_SHIFT  ; TEST SHIFT STATE
	JZ	K49			   ; JUMP, LOWERCASE PSEUDO SC'S

	MOV	BX,OFFSET K11		; UPPERCASE PSEUDO SCAN CODES
	JMP	SHORT K64		; TRANSLATE_SCAN

;------ TRANSLATE THE CHARACTER

K56:					; TRANSLATE-CHAR
	DEC	AL			; CONVERT ORIGIN
	XLAT	CS:K11			; CONVERT THE SCAN CODE TO ASCII
	TEST	@KB_FLAG_3,LC_E0	; IS THIS A NEW KEY?
	JZ	K57			;  NO, GO FILL BUFFER
	MOV	AH,MC_E0		;  YES, PUT SPECIAL MARKER IN AH
	JMP	SHORT K57		; PUT IT INTO THE BUFFER

;-----	TRANSLATE SCAN FOR PSEUDO SCAN CODES

K64:					; TRANSLATE-SCAN-ORGD
	DEC	AL			; CONVERT ORIGIN
	XLAT	CS:K8			; CTL TABLE SCAN
	MOV	AH,AL			; PUT VALUE INTO AH
	MOV	AL,0			; ZERO ASCII CODE
	TEST	@KB_FLAG_3,LC_E0	; IS THIS A NEW KEY?
	JZ	K57			;  NO, GO FILL BUFFER
	MOV	AL,MC_E0		;  YES, PUT SPECIAL MARKER IN AL

;------ PUT CHARACTER INTO BUFFER

K57:					; BUFFER_FILL
	CMP	AL,-1			; IS THIS AN IGNORE CHAR
	JE	K59			; YES, DO NOTHING WITH IT
	CMP	AH,-1			; LOOK FOR -1 PSEUDO SCAN
	JNE	K61			; NEAR_INTERRUPT_RETURN

K59:					; NEAR-INTERRUPT-RETURN
	JMP	K26			; INTERRUPT_RETURN

K61:
	MOV	BX,@BUFFER_TAIL 	; GET THE END POINTER TO THE BUFFER
	MOV	SI,BX			; SAVE THE VALUE
	CALL	K4			; ADVANCE THE TAIL
	CMP	BX,@BUFFER_HEAD 	; HAS THE BUFFER WRAPPED AROUND
	JE	K62			; BUFFER_FULL_BEEP
	MOV	[SI],AX 		; STORE THE VALUE
	MOV	@BUFFER_TAIL,BX 	; MOVE THE POINTER UP
	CLI				; TURN OFF INTERRUPTS
	MOV	AL,EOI			; END OF INTERRUPT COMMAND
	OUT	INTA00,AL		; SEND COMMAND TO INTERRUPT CONTROL PORT
	MOV	AL,ENA_KBD		; INSURE KEYBOARD IS ENABLED
	CALL	SHIP_IT 		; EXECUTE ENABLE
	MOV	AX,09102H		; MOVE IN POST CODE & TYPE
	INT	15H			; PERFORM OTHER FUNCTION
	AND	@KB_FLAG_3,NOT LC_E0+LC_E1 ; RESET LAST CHAR H.C. FLAG
	JMP	K27A			; INTERRUPT_RETURN

;------ BUFFER IS FULL SOUND THE BEEPER

K62:
	MOV	AL,EOI			; ENABLE INTERRUPT CONTROLLER CHIP
	OUT	INTA00,AL		;
	MOV	CX,678			; DIVISOR FOR 1760 HZ
	MOV	BL,4			; SHORT BEEP COUNT (1/16 + 1/64 DELAY)
	CALL	BEEP			; GO TO COMMON BEEP HANDLER
	JMP	K27			; EXIT

KB_INT_1	ENDP
PAGE
;---------------------------------------------------------------------
;								     -
;	SHIP_IT 						     -
;								     -
;	THIS ROUTINE HANDLES TRANSMISSION OF COMMAND AND DATA BYTES  -
;	TO THE KEYBOARD CONTROLLER.				     -
;								     -
;---------------------------------------------------------------------
SHIP_IT PROC	NEAR
	PUSH	AX			; SAVE DATA TO SEND

;------- WAIT FOR COMMAND TO BE ACCEPTED
CLI				; DISABLE INTERRUPTS TILL DATA SENT
	SUB	CX,CX			; CLEAR TIMEOUT COUNTER
S10:
	IN	AL,STATUS_PORT		; READ KEYBOARD CONTROLLER STATUS
	TEST	AL,INPT_BUF_FULL	; CHECK FOR ITS INPUT BUFFER BUSY
	LOOPNZ	S10			; WAIT FOR COMMAND TO BE ACCEPTED

	POP	AX			; GET DATA TO SEND
	OUT	STATUS_PORT,AL		; SEND TO KEYBOARD CONTROLLER
	STI				; ENABLE INTERRUPTS AGAIN
	RET				; RETURN TO CALLER
SHIP_IT ENDP

;---------------------------------------------------------------------
;								     -
;	SND_DATA						     -
;								     -
;	THIS ROUTINE HANDLES TRANSMISSION OF COMMAND AND DATA BYTES  -
;	TO THE KEYBOARD AND RECEIPT OF ACKNOWLEDGEMENTS.  IT ALSO    -
;	HANDLES ANY RETRIES IF REQUIRED 			     -
;								     -
;---------------------------------------------------------------------

SND_DATA PROC	NEAR
	PUSH	AX			; SAVE REGISTERS
	PUSH	BX
	PUSH	CX
	MOV	BH,AL			; SAVE TRANSMITTED BYTE FOR RETRIES
	MOV	BL,3			; LOAD RETRY COUNT
SD0:	CLI				; DISABLE INTERRUPTS
	AND	@KB_FLAG_2,NOT (KB_FE+KB_FA) ; CLEAR ACK AND RESEND FLAGS

;-----	WAIT FOR COMMAND TO BE ACCEPTED

	SUB	CX,CX
SD5:	IN	AL,STATUS_PORT
	TEST	AL,INPT_BUF_FULL
	LOOPNZ	SD5			; WAIT FOR COMMAND TO BE ACCEPTED

	MOV	AL,BH			; REESTABLISH BYTE TO TRANSMIT
	OUT	PORT_A,AL		; SEND BYTE
	STI				; ENABLE INTERRUPTS
	MOV	CX,01A00H		; LOAD COUNT FOR 10ms+
SD1:	TEST	@KB_FLAG_2,KB_FE+KB_FA	; SEE IF EITHER BIT SET
	JNZ	SD3			; IF SET, SOMETHING RECEIVED GO PROCESS
	LOOP	SD1			; OTHERWISE WAIT

SD2:	DEC	BL			; DECREMENT RETRY COUNT
	JNZ	SD0			; RETRY TRANSMISSION
	OR	@KB_FLAG_2,KB_ERR	; TURN ON TRANSMIT ERROR FLAG
	JMP	SHORT SD4		; RETRIES EXHAUSTED FORGET TRANSMISSION

SD3:	TEST	@KB_FLAG_2,KB_FA	; SEE IF THIS IS AN ACKNOWLEDGE
	JZ	SD2			; IF NOT, GO RESEND

SD4:	POP	CX			; RESTORE REGISTERS
	POP	BX			;
	POP	AX			;
	RET				; RETURN, GOOD TRANSMISSION
SND_DATA ENDP
PAGE
;---------------------------------------------------------------------
;								     -
;	SND_LED 						     -
;								     -
;	THIS ROUTINES TURNS ON THE MODE INDICATORS.		     -
;								     -
;---------------------------------------------------------------------
SND_LED PROC	NEAR
	CLI				; TURN OFF INTERRUPTS
	TEST	@KB_FLAG_2,KB_PR_LED	; CHECK FOR MODE INDICATOR UPDATE
	JNZ	SL1			; DONT UPDATE AGAIN IF UPDATE UNDERWAY
;
	OR	@KB_FLAG_2,KB_PR_LED	; TURN ON UPDATE IN PROCESS
	MOV	AL,EOI			; END OF INTERRUPT COMMAND
	OUT	020H,AL 		; SEND COMMAND TO INTERRUPT CONTROL PORT
	JMP	SHORT SL0		; GO SEND MODE INDICATOR COMMAND
;
SND_LED1:
	CLI				; TURN OFF INTERRUPTS
	TEST	@KB_FLAG_2,KB_PR_LED	; CHECK FOR MODE INDICATOR UPDATE
	JNZ	SL1			; DONT UPDATE AGAIN IF UPDATE UNDERWAY
;
	OR	@KB_FLAG_2,KB_PR_LED	; TURN ON UPDATE IN PROCESS
SL0:	MOV	AL,LED_CMD		; LED CMD BYTE
	CALL	SND_DATA		; SEND DATA TO KEYBOARD
	CLI				;
	CALL	MAKE_LED		; GO FORM INDICATOR DATA BYTE
	AND	@KB_FLAG_2,0F8H 	; CLEAR MODE INDICATOR BITS
	OR	@KB_FLAG_2,AL		; SAVE PRESENT INDICATORS FOR NEXT TIME
	TEST	@KB_FLAG_2,KB_ERR	; TRANSMIT ERROR DETECTED
	JNZ	SL2			;  YES, BYPASS SECOND BYTE TRANSMISSION
;
	CALL	SND_DATA		; SEND DATA TO KEYBOARD
	CLI				; TURN OFF INTERRUPTS
	TEST	@KB_FLAG_2,KB_ERR	; TRANSMIT ERROR DETECTED
	JZ	SL3			; IF NOT, DON'T SEND AN ENABLE COMMAND
;
SL2:	MOV	AL,KB_ENABLE		; GET KEYBOARD CSA ENABLE COMMAND
	CALL	SND_DATA		; SEND DATA TO KEYBOARD
	CLI				; TURN OFF INTERRUPTS
SL3:	AND	@KB_FLAG_2,NOT(KB_PR_LED+KB_ERR) ; TURN OFF MODE INDICATOR
					; UPDATE AND TRANSMIT ERROR FLAG
SL1:	STI				; ENABLE INTERRUPTS
	RET				; RETURN TO CALLER
SND_LED ENDP

;---------------------------------------------------------------------
; MAKE_LED							     -
;								     -
;	THIS ROUTINES FORMS THE DATA BYTE NECESSARY TO TURN ON/OFF   -
;	THE MODE INDICATORS.					     -
;								     -
;---------------------------------------------------------------------
MAKE_LED PROC	NEAR
	PUSH	CX			; SAVE CX
	MOV	AL,@KB_FLAG		; GET CAPS & NUM LOCK INDICATORS
	AND	AL,CAPS_STATE+NUM_STATE+SCROLL_STATE ; ISOLATE INDICATORS
	MOV	CL,4			; SHIFT COUNT
	ROL	AL,CL			; SHIFT BITS OVER TO TURN ON INDICATORS
	AND	AL,07H			; MAKE SURE ONLY MODE BITS ON
	POP	CX
	RET				; RETURN TO CALLER
MAKE_LED ENDP

CODE	ENDS
	END
