Category : Files from Magazines
Archive   : PCTJ8707.ZIP
Filename : ATKEY.ASM

 
Output of file : ATKEY.ASM contained in archive : PCTJ8707.ZIP
COMMENT| NOT EXECUTABLE! EXAMPLE ONLY

Module Specifications
Environment: IBM PC/AT, tested under DOS 3.20.

Segments, groups, and classes:
Group PGROUP:
Program segment CODE, byte-aligned, public, class 'prog'
Data segment DATA, byte-aligned, public, class 'data'

Original code by: Bob Smith, Qualitas, Inc., 8314 Thoreau Dr.,
March 1987 Bethesda, MD 20817-3164, 301-468-8848
|

@8255_A equ 60h ; Read-only in PC, Read/write in AT
@8042_ST equ 64h ; Status port
@CMD_CPAT equ 40h ; IBM PC Compatibility Mode switch
@OUTFULL equ 01b ; Output buffer full
@INPFULL equ 10b ; Input buffer full
@S2C_RCMD equ 020h ; Read controller's command byte
@S2C_WCMD equ 060h ; Write controller's command byte
@S2C_DIS equ 0ADh ; Keyboard disable
@S2C_ENA equ 0AEh ; Keyboard enable
@S2C_RINP equ 0C0h ; Read input port
@S2K_ECHO equ 0EEh ; Echo
@S2K_SCAN equ 0F0h ; Select alternate scan codes
@S2K_RID equ 0F2h ; Read ID (two bytes returned)
@K2S_ECHO equ 0EEh ; Echo response
@K2S_ACK equ 0FAh ; Last command acknowledged
@K2S_RESEND equ 0FEh ; Resend last command

REGSAVE macro LIST ; Register save macro
irp XX,
push XX
endm
endm ; REGSAVE

REGREST macro LIST ; Register restore macro
irp XX,
pop XX
endm
endm ; REGREST

POPFF macro
local L1,L2
jmp short L2
L1: iret
L2: push cs
call L1
endm ; POPFF

PGROUP group CODE,DATA

DATA segment byte public 'data' ; Start DATA segment

public RID_LO,RID_HI,RCMD,RINP,RSCAN
RID_LO db ? ; Low-order byte of Read ID byte
RID_HI db ? ; High-order ...
RCMD db ? ; Command byte
RINP db ? ; Input port
RSCAN db ? ; Read scan code set

public LCL_FLG
LCL_FLG dw 0 ; Local flags
@LCL_RID_LO equ 8000h ; Low-order Read ID byte
@LCL_RID_HI equ 4000h ; High-order Read ID byte
@LCL_RCMD equ 2000h ; Command byte
@LCL_RINP equ 0800h ; Input port
@LCL_RSCAN equ 0020h ; Read scan code set

DATA ends ; End DATA segment

CODE segment byte public 'prog' ; Start CODE segment
assume cs:PGROUP

GETRCMD proc near ; Get Command Byte
assume ds:PGROUP,es:PGROUP

; Read the command byte

REGSAVE ; Save register
cli ; Nobody move
call CLEAROBUF ; Wait for the output buffer to clear
mov al,@S2C_RCMD ; Read the controller's command byte
call SEND8042 ; Send to keyboard controller
jc ERR_RCMD ; Something went wrong
call WAITRESP ; Wait for a response, returned in AL
jc ERR_RCMD ; Something went wrong
mov RCMD,al ; Save response
or LCL_FLG,@LCL_RCMD ; Mark as present
ERR_RCMD:
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing
GETRCMD endp ; End GETRCMD procedure

GETRID proc near ; Read Keyboard ID
assume ds:PGROUP,es:PGROUP

; Read keyboard ID.
; This value is returned in scan code format. Thus to obtain the
; actual value we need to turn off the controller's scan code
;translation.

REGSAVE ; Save registers
cli ; Nobody move
call TRANSOFF ; Turn off scan code translation
jc ERR_RID2 ; Something went wrong
mov al,@S2K_RID ; Function code to read ID
call SEND6805 ; Send to keyboard, response in AL
jc ERR_RID1 ; Jump if controller not responding
cmp al,@K2S_ACK ; Izit an ACK?
jne ERR_RID1 ; Something went wrong
call WAITRESP ; Wait for a response, returned in AL
jc ERR_RID1 ; Something went wrong
mov RID_LO,al ; Save response
or LCL_FLG,@LCL_RID_LO ; Indicate we read it
call WAITRESP ; Wait for a response, returned in AL
jc ERR_RID1 ; Something went wrong
mov RID_HI,al ; Save response
or LCL_FLG,@LCL_RID_HI ; Mark as present
ERR_RID1:
call RESTCMD ; Restore original command byte
ERR_RID2:
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

GETRID endp ; End GETRID procedure

GETRINP proc near ; Read Input Port
assume ds:PGROUP,es:PGROUP

;Read controller's input port.

REGSAVE ; Save registers
cli ; Nobody move
call CLEAROBUF ; Wait for the output buffer to clear
mov al,@S2C_RINP ; Read controller's input port
call SEND8042 ; Send to keyboard controller
jc ERR_RINP ; Something went wrong
call WAITRESP ; Wait for a response, returned in AL
jc ERR_RINP ; Something went wrong
mov RINP,al ; Save response
or LCL_FLG,@LCL_RINP ; Mark as present
ERR_RINP:
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

GETRINP endp ; End GETRINP procedure

GETRSCAN proc near ; Read Current Scan Code Set
assume ds:PGROUP,es:PGROUP

; Read current scan code set.
; This value is returned in scan code format. Thus to obtain the
; actual value we need to turn off the controller's scan code
; translation.

REGSAVE ; Save registers
cli ; Nobody move
call TRANSOFF ; Turn off scan code translation
jc ERR_RSCAN2 ; Something went wrong
mov al,@S2K_SCAN ; Select scan code set
call SEND6805 ; Send to keyboard, response in AL
jc ERR_RSCAN1 ; Jump if controller not responding
cmp al,@K2S_ACK ; Izit an ACK?
jne ERR_RSCAN1 ; Something went wrong
mov al,0 ; Send it a request for current set
call SEND6805 ; Send to keyboard, response in AL
jc ERR_RSCAN1 ; Jump if controller not responding
cmp al,@K2S_ACK ; Izit an ACK?
jne ERR_RSCAN1 ; Something went wrong
call WAITRESP ; Wait for a response, returned in AL
jc ERR_RSCAN1 ; Something went wrong
mov RSCAN,al ; Save response
or LCL_FLG,@LCL_RSCAN ; Indicate we read it
ERR_RSCAN1:
call RESTCMD ; Restore original command byte
ERR_RSCAN2:
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

GETRSCAN endp ; End GETRSCAN procedure

TRANSOFF proc near ; Turn Off Scan Code Translation
assume ds:PGROUP,es:PGROUP
COMMENT|
Turn off scan code translation.
On exit:
CF = 0 if all went well
= 1 otherwise
|
REGSAVE ; Save register
test LCL_FLG,@LCL_RCMD ; Is RCMD valid?
stc ; Assume not
jz TRANSOFF_EXIT ; No
mov al,@S2C_WCMD ; Write command byte
call SEND8042 ; Send to keyboard controller
jc TRANSOFF_EXIT ; Something went wrong
call CLEARIBUF ; Wait for input buffer to clear
jc TRANSOFF_EXIT ; Error, controller not reading data

; Turn off scan code translation

mov al,RCMD ; Get the original command byte
and al,not @CMD_CPAT ; Turn off compatibility mode
out @8255_A,al ; Issue the command
TRANSOFF_EXIT:
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

TRANSOFF endp ; End TRANSOFF procedure

RESTCMD proc near ; Restore Command Byte
assume ds:PGROUP,es:PGROUP
COMMENT|
Restore command byte from RCMD.
On exit:
CF = 0 if all went well
= 1 otherwise
|
REGSAVE ; Save registers
mov al,@S2C_WCMD ; Write command byte
call SEND8042 ; Send to keyboard controller
jc RESTCMD_EXIT ; Something went wrong
call CLEARIBUF ; Wait for input buffer to clear
jc RESTCMD_EXIT ; Error, controller not reading data
mov al,RCMD ; Get the original command byte
out @8255_A,al ; Issue the command
RESTCMD_EXIT:
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

RESTCMD endp ; End RESTCMD procedure

WAITRESP proc near ; Wait For A Response
assume ds:PGROUP,es:PGROUP
COMMENT|
Wait a response from the keyboard or its controller.
On exit:
CF = 1 if no response
= 0 otherwise
AL = response if CF=0
AH = clobbered
|
REGSAVE ; Save registers
clc ; Assume all goes well
lahf ; Load AH with flags
pushf ; Save flags
cli ; Nobody move

; Wait for a response

mov bl,12 ; Outer loop counter
xor cx,cx ; Inner loop counter
RESP1:
in al,@8042_ST ; Get status from keyboard
and al,@OUTFULL ; Check Output Buffer Full flag
loopz RESP1 ; Jump if no response as yet
jz RESP2 ; Still no response
jmp $+2 ; Take into account I/O delay
in al,@8255_A ; Read in the code
jmp short RESP_EXIT ; Join common exit code
RESP2:
dec bl ; Try again
jnz RESP1 ; Jump if more tries available
inc ah ; Set CF in AH
RESP_EXIT:
POPFF ; Restore flags with caller's IF
sahf ; Store AH into flags
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

WAITRESP endp ; End WAITRESP procedure

SEND8042 proc near ; Send Command To Keyboard Controller
assume ds:PGROUP,es:PGROUP
COMMENT|
Send the command in AL to the keyboard controller port 64h.
There is no acknowledgement of this command.
On exit:
CF = 1 if keyboard controller not responding
= 0 otherwise
|
REGSAVE ; Save for a moment
clc ; Assume all goes well
lahf ; Load AH with flags
pushf ; Save flags
cli ; Nobody move
call CLEARIBUF ; Wait for input buffer to clear
jc CTRL_EXIT ; Jump if controller not responding
out @8042_ST,al ; Send the command
CTRL_EXIT:
adc ah,0 ; Set CF in AH as necessary
POPFF ; Restore flags with caller's IF
sahf ; Store AH into flags
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

SEND8042 endp ; End SEND8042 procedure

SEND6805 proc near ; Send Data in AL to Keyboard
assume ds:PGROUP,es:PGROUP
COMMENT|
Send AL to keyboard.
On exit:
CF = 1 if timeout
= 0 otherwise
AL = keyboard response if CF=0
AH is clobbered.
|
REGSAVE ; Save for a moment
mov cx,6 ; # retries of resend
clc ; Assume all goes well
lahf ; Load AH with flags
pushf ; Save flags
cli ; Nobody move
SEND0:
REGSAVE ; Save for a moment
call CLEARIBUF ; Wait for input buffer to clear
jc SEND1 ; Error, controller not reading data
out @8255_A,al ; Issue the command
call WAITRESP ; Wait for a response, returned in AL
jc SEND1 ; Something went wrong
cmp al,@K2S_RESEND ; Izit a resend?
clc ; In case it isn't
jne SEND1 ; No
REGREST ; Restore
loop SEND0 ; Jump if more retries
stc ; Indicate something went wrong
push ax ; Save for a moment
SEND1:
inc sp ; Restore stack pointer
inc sp ; ...without changing CF
adc ah,0 ; Set CF in AH as necessary
POPFF ; Restore flags with caller's IF
sahf ; Store AH into flags
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

SEND6805 endp ; End SEND6805 procedure

CLEARIBUF proc near ; Wait For The Input Buffer To Clear
assume ds:PGROUP,es:PGROUP
COMMENT|
Wait for the one-byte input buffer to clear.
On exit:
CF = 0 if buffer empty
= 1 otherwise
|
REGSAVE ; Save registers
clc ; Assume all goes well
lahf ; Load AH with flags
pushf ; Save flags
cli ; Nobody move
xor cx,cx ; Loop counter
CLEARIBUF1:
in al,@8042_ST ; Get status from keyboard
and al,@INPFULL ; Check Input Buffer Full flag
loopnz CLEARIBUF1 ; Last char not read as yet
jz CLEARIBUF_EXIT ; Jump if buffer clear before then
stc ; Mark as in error
CLEARIBUF_EXIT:
adc ah,0 ; Set CF in AH as necessary
POPFF ; Restore flags with caller's IF
sahf ; Store AH into flags
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

CLEARIBUF endp ; End CLEARIBUF procedure

CLEAROBUF proc near ; Wait For The Output Buffer To Clear
assume ds:PGROUP,es:PGROUP

; Wait for the one-byte input buffer to clear.
REGSAVE ; Save register
cli ; Nobody move
CLEAROBUF1:
in al,@8042_ST ; Get status from keyboard
and al,@OUTFULL ; Check Output Buffer Full flag
jz CLEAROBUF_EXIT ; Jump if buffer clear before
jmp $+2 ; I/O delay
in al,@8255_A ; Purge the character
jmp CLEAROBUF1 ; Continue on
CLEAROBUF_EXIT:
REGREST ; Restore
ret ; Return to caller
assume ds:nothing,es:nothing

CLEAROBUF endp ; End CLEAROBUF procedure
CODE ends ; End CODE segment
end ; End LIST1 module


  3 Responses to “Category : Files from Magazines
Archive   : PCTJ8707.ZIP
Filename : ATKEY.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/