#TITLE "NEC-APC Keyboard Interface Module" #PAGE 132,66 ; ; KBDAPC.A ; ; NOTE: This version handles APC keyboard input and calls ; the screen driver at entry point "SCREEN#" for output. ; ; Version: 07/12/84 ; MODULE "KBDAPC" ; module ID ; #INCLUDE "DREQUATE" ; common driver equivalences #INCLUDE "APCEQU" ; common NEC-APC equivalences ; KBDIREQ == 4 ; keyboard IREQ level DLYCNT == 40 ; delay in ticks before key repeat RATECNT == 3 ; rate count in ticks for key repeat ; ; LOC Data# ; locate in data segment ; CIBSIZ::WORD 64 ; console input buffer size CIBADR: WORD 0 ; console input buffer address CIIPTR: WORD 0 ; console input buffer input pointer CIOPTR: WORD 0 ; console input buffer output pointer ; CISPH: ; console input semaphore WORD 0 ; semaphore count WORD . ; semaphore list head WORD .-2 ; KBDFL: BYTE 0 ; keyboard locked flag DELAY: BYTE DLYCNT ; key repeat delay counter RATE: BYTE 0 ; key repeat rate counter ; ; Key translation table for keyboard data 5E-FF hex. ; A byte of FF in the table means key is ignored. ; KEYTBL: BYTE 0X18 ; 5E - Control-X BYTE "-" ; 5F ; #REPEAT 0X6A-0X60 ; 60 to 69 - undefined codes BYTE 0XFF #ENDREP ; BYTE "*" ; 6A BYTE "+" ; 6B BYTE 0XFF ; 6C - undefined code BYTE "-" ; 6D BYTE "." ; 6E BYTE "/" ; 6F BYTE "0" ; 70 BYTE "1" ; 71 BYTE "2" ; 72 BYTE "3" ; 73 BYTE "4" ; 74 BYTE "5" ; 75 BYTE "6" ; 76 BYTE "7" ; 77 BYTE "8" ; 78 BYTE "9" ; 79 ; #REPEAT 0X80-0X7A ; 7A to 7F - undefined codes BYTE 0XFF #ENDREP ; #REPEAT 0X96-0X80 ; 80 to 95 - function keys BYTE 0XFF #ENDREP ; BYTE 0X00 ; 96 - break stop BYTE 0X0D ; 97 - return BYTE 0X09 ; 98 - tab/back tab BYTE 0XFF ; 99 - undefined code BYTE 0X1E ; 9A - home/clear BYTE 0XFF ; 9B - undefined code BYTE 0X08 ; 9C - back space ; #REPEAT 0XF7-0X9D ; 9D to F6 - undefined codes BYTE 0XFF #ENDREP ; BYTE 0X0B ; F7 - up arrow BYTE 0X0A ; F8 - down arrow BYTE 0X0C ; F9 - right arrow BYTE 0X08 ; FA - left arrow ; BYTE 0XFF ; FB - ins BYTE 0X7F ; FC - del BYTE 0X0D ; FD - enter BYTE 0XFF ; FE - undefined code BYTE 0XFF ; FF - print ; ; Special table for screwed-up keys. Scan codes are converted. ; SPECTBL: BYTE 0X2D,0X3D BYTE 0X40,0X60 BYTE 0X3A,0X3B BYTE 0X3B,0X27 SPECTLN == (.-SPECTBL)/2 ; length of table ; ; Shift case table ; CASETBL: BYTE "1!" BYTE "2@" BYTE "3#" BYTE "4$" BYTE "5%" BYTE "6",0XD0 BYTE "7&" BYTE "8*" BYTE "9(" BYTE "0)" BYTE "-_" BYTE "=+" BYTE "`~" BYTE "[{" BYTE "]}" BYTE "\\|" BYTE ",<" BYTE ".>" BYTE "/?" BYTE ";:" BYTE 0X27,0X22 BYTE 0X18,"^" CASETLN == (.-CASETBL)/2 ; ; BOOTOF: WORD 0X1FED WORD 0XFE00 FKEYPTR: WORD 0 FUNCS: #REPEAT 0X10 ; Allocate empty func key BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #ENDREP BYTE 0X1B,"OO",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OP",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OQ",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OR",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OS",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OT",0,0,0,0,0,0,0,0,0,0,0,0,0 #REPEAT 0X10 BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #ENDREP BYTE 0X1B,"OU",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OV",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OW",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OX",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OY",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0X1B,"OZ",0,0,0,0,0,0,0,0,0,0,0,0,0 BYTE 0 ; ; ; Local console initialization routine. ; LOC Code# ; locate in code segment ; CONNIT:: IN AL,KBD_DATA ; clear intrps once IN AL,KBD_DATA ; and again ; MOV DX,&KBDISR ; get ISR entry point MOV AL,=KBDIREQ ; get keyboard IREQ level CALL INTENA# ; enable interrupts from device ; MOV BX,CIBSIZ ; get console input buffer size CALL ALLOC# ; allocate console input buffer MOV CIBADR,BX ; save console input buffer addr ADD BX,CIBSIZ ; calculate zero position MOV CIIPTR,BX ; set console input pointer MOV CIOPTR,BX ; set console output pointer ; RET ; and exit ; ; ; Local driver entry point. ; CONDR_:: MOV AL,DL ; get function number CMP AL,=10 ; function number = 10? JZ __CO0 ; if so, do char output OR AL,AL ; function = 0? JZ CONST ; if so, do char status DEC AL ; function = 1? JZ CONIN ; if so, do char input DEC AL ; function = 2? JZ __CO ; if so, do char output SUB AL,=8-2 ; function = 8? JZ CONSI ; if so, do error shift in DEC AL ; function = 9? JZ CONSO ; if so, do error shift out XOR AL,AL ; clear return status RET ; and exit ; __CO0: CMP WORD SMXSPH#,=0000 ; Is the screen busy ? JNE __CO XOR AL,AL ; Yes, return bad status RET __CO: JMP SCREEN# ; CONSO: CONSI: CALL DMS# ; position to next line BYTE ACR,ALF,0 RET ; done ; CONST: CALL CHKCIB ; check input buffer RET ; exit ; CONIN: CALL CHKCIB ; check console input buffer JNZ __CI2 ; if char waiting, continue CALL CSRENA# ; enable cursor for console input __CI1: MOV BX,&CISPH ; get console input semaphore CALL WAIT# ; wait for console input CALL CHKCIB ; check input buffer JZ __CI1 ; if false alarm, continue __CI2: MOV CIOPTR,BX ; update buffer out pointer MOV FKEYPTR,DX ; Update function key pointer MOV AL,CL ; get char in reg RET ; and exit ; ; Check the contents of the input buffer. ; CHKCIB: MOV BX,FKEYPTR ; Get ^current func key buffer MOV DX,BX ; Initialize pointer return val OR BX,BX ; Is there an active key ? MOV CL,[BX] ; Get the char just in case MOV BX,CIOPTR ; Get the normal buffer pointer JZ __0 ; Is there a key active ? OR CL,CL ; Yes, is there valid data ? JZ __F2 OR AL,0XFF ; Yes, return with it INC DX ; Update key buffer pointer __X: RET __F2: XOR DX,DX ; No, cancel function key __0: XOR AL,AL ; clear reg CMP BX,CIIPTR ; compare to input pointer JZ __X ; if equal, continue MOV AX,CIBADR ; get buffer base ADD AX,CIBSIZ ; calc end of buffer CMP AX,BX ; buffer wrap? JNZ __1 ; if not, continue MOV BX,CIBADR ; reset buffer out pointer __1: MOV AL,[BX] ; load the char INC BX ; Index to shift status MOV CH,[BX] ; Load shift status INC BX PUSH BX ; Save buffer pointer CMP AL,=0X80 ; function key ? JB __C6 CMP AL,=0X95 JA __C6 XOR AH,AH ; Yes, calculate address of key SHR CH,=1 ; Is the FUNC shift down ? JNC __F1 ADD AL,=0X16 ; Yes, shift up to upper set __F1: SHL AL,=1 ; Multiply key number by 16 SHL AX,=1 SHL AX,=1 SHL AX,=1 ADD AX,&FUNCS ; Offset into key table MOV BX,AX ; Setup function key pointer MOV CL,[BX] ; Get first character OR CL,CL ; Is there really a character ? JZ __F3 MOV DX,BX ; Yes, increment to next char INC DX JMP __C4 __F3: POP BX ; No, get next character JMP __0 __C6: CMP AL,=0X5E ; special soft keys? JB __XL1 ; if not, continue MOV BX,&KEYTBL-0X5E ; get key translate table addr XLAT ; load the real key value CMP AL,=0XFF ; undefined code? JNZ __C2 ; if not, continue POP BX ; Recover buffer pointer JMP __0 ; Yes, try reading next char ; __XL1: MOV BX,&SPECTBL ; get special sub table addr MOV CL,=SPECTLN ; and length __XL2: CMP AL,0[BX] ; match? JZ __XL3 ; if so, continue ADD BX,=2 ; select next entry DEC CL ; any left? JNZ __XL2 ; if so, continue loop JMPS __C2 ; else, continue __XL3: MOV AL,1[BX] ; get substitute scan code ; __C2: MOV CL,AL ; move key data to reg CALL CASES ; do caps and shift cases TEST CH,=1<<1 ; Is the control key down ? JZ __C4 ; if not, continue MOV AL,CL ; get char value CALL UPCASE ; fold to upper case CMP AL,=0X40 ; is key below control range? JB __C4 ; if so, continue CMP AL,=0X5F ; is key above control range? JA __C4 ; if so, continue AND AL,=0X1F ; mask to control values MOV CL,AL ; Return character in CL __C4: POP BX ; Recover buffer pointer OR AL,=0XFF ; Return status FF and Z = 0 RET ; ; KBDISR: PUSH AX PUSH BX PUSH CX PUSH DX PUSH DS ; save regs CALL GETSDS# ; get system data seg CALL KBDIN ; do keyboard request stuff MOV AL,=KBDIREQ ; get keyboard IREQ level CALL SIGEOI# ; signal EOI condition POP DS POP DX POP CX POP BX POP AX ; restore regs JMP ISRXIT# ; and exit interrupt ; ; ; Keyboard repeat routines. NOTE: Public entry called from "RTCAPC" module. ; KBDREP:: MOV AX,CIIPTR ; get char buffer in pointer CMP CIOPTR,AX ; compare out pointer, chars present? JNZ __X ; if so, skip repeat stuff IN AL,KBD_SIG ; read signal switches TEST AL,=1<<4 ; test repeat bit, reqeat on? JZ __X ; if so, skip repeat stuff CMP DELAY,=0 ; initial delay completed? JZ __C1 ; if so, continue DEC DELAY ; else, decrement delay count __X: RET ; and exit ; __C1: CMP RATE,=0 ; keyboard rate completed? JZ __C2 ; if so, continue DEC RATE ; else, decrement repeat rate count RET ; and exit ; __C2: MOV RATE,=RATECNT ; pre-set next rate count JMPS KBDIN1 ; and simulate keyboard interrupt ; ; KBDIN: IN AL,KBD_STAT ; read status AND AL,=0X01 ; key ready JZ __C1 ; if so, continue IN AL,KBD_DATA ; dummy read, reset interrupt RET ; and exit ; __C1: MOV DELAY,=DLYCNT ; pre-set repeat delay timer ; ; Entry point called for keyboard repeat function. ; KBDIN1: IN AL,KBD_SIG ; read switch signal port AND AL,=0X2F ; mask off unused bits MOV DL,AL ; move to reg IN AL,KBD_SH ; read shift switches TEST AL,=1<<0 ; shift key held? JZ __SH1 ; if not, continue OR DL,=1<<6 ; set additional siganls __SH1: TEST AL,=1<<2 ; caps locked? JZ __SH2 ; if not, continue OR DL,=1<<7 ; set additional signals __SH2: IN AL,KBD_DATA ; read key data MOV CL,AL ; Move into comparison reg MOV BX,CIIPTR ; Get buffer pointer CMP CL,=0X96 ; Was the Break/Stop hit ? JNE __QCH MOV AH,DL ; Is both the CTRL and FUNC ? AND AH,=03 JZ __ATTN JPO __ATTN ; ; Reboot the system ; CLI ; Yes, shut down and jump XOR AX,AX ; ... into boot ROM MOV SS,AX MOV ES,AX MOV SP,=0XFF00 JMPFI BOOTOF ; ; ; Store contents of the CL and DL register in console input buffer ; __ATTN: MOV CIOPTR,BX ; Flush out keyboard buffer __QCH: MOV AX,CIBADR ; get buffer base address ADD AX,CIBSIZ ; calc end of buffer CMP AX,BX ; compare to pointer, wrap buffer? JNZ __2 ; if not, continue MOV BX,CIBADR ; point buffer back to start __2: INC BX ; Move buffer to next chars INC BX CMP BX,CIOPTR ; buffer full? JZ __X ; if so, exit MOV -2[BX],CL ; place char in buffer MOV -1[BX],DL ; Save shift key state MOV CIIPTR,BX ; update buffer in pointer MOV BX,&CISPH ; get console input semaphore PUSH DX ; save reg CALL SIGNAL# ; signal process as ready POP DX ; restore reg __X: RET ; and exit ; ; CASES: MOV AL,=0XC0 ; get mask for shift and caps AND AL,CH ; mask to these bits JZ __LC ; if neither, fold to lower case CMP AL,=1<<7 ; caps only? JZ __X ; if so, done MOV BX,&CASETBL ; get case table addr MOV AL,=CASETLN ; get table length __1: CMP CL,0[BX] ; case match? JZ __2 ; if so, continue ADD BX,=2 ; advance to next case DEC AL ; check count JNZ __1 ; and loop RET ; else exit ; __2: MOV CL,1[BX] ; get case substitute RET ; and exit ; __LC: CMP CL,='A' ; is key below letter range? JB __X ; if so, continue CMP CL,='Z' ; is key above letter range? JA __X ; if so, continue ADD CL,=0X20 ; fold to lower case __X: RET ; ; UPCASE: CMP AL,='a' ; below lower case? JB __X ; if so, exit CMP AL,='z' ; above lower case? JA __X ; if so, exit SUB AL,=0X20 ; fold to upper case __X: RET ; exit ; ; ; These routines are called from the screen driver to ; perform the following functions. ; ; Lock the keyboard. ESCAPE # ; KBDLOK:: MOV KBDFL,=0XFF ; set keyboard lock flag RET ; all done ; ; Unlock the keyboard. ESCAPE " ; KBDULK:: MOV KBDFL,=0 ; unlock the keyboard RET ; all done ; END