1557 lines
41 KiB
NASM
1557 lines
41 KiB
NASM
|
page
|
||
|
|
||
|
;---------------------------Module-Header-------------------------------;
|
||
|
; Module Name: IBMCOM1.ASM
|
||
|
;
|
||
|
; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
|
||
|
;
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; DoLPT - Do Function To LPT port
|
||
|
;
|
||
|
; The given function (output or reset) is performed to the
|
||
|
; passed LPT port.
|
||
|
;
|
||
|
; Before a character is sent, a check is made to see if the device
|
||
|
; will be able to accept the character. If it can, then the character
|
||
|
; will be sent. If not, then an error will be returned. If the
|
||
|
; printer is selected and busy and no error, then the code returned
|
||
|
; will be CE_TXFULL and the handshake bits will be set in HSFlag
|
||
|
; to simulate that a handshake was received.
|
||
|
;
|
||
|
; If the BIOS ROM code is examined, you will note that they wait for
|
||
|
; the busy character from the last charcater to be cleared before
|
||
|
; they strobe in the current character. This can take a long time
|
||
|
; on the standard EPSON class printer (1 mSec to greater than
|
||
|
; 300 mSec if the last character actually caused printing).
|
||
|
;
|
||
|
; Because of this, several status read retrys will be made before
|
||
|
; declaring that the device is actually busy. If only one status
|
||
|
; read is performed, the spooler will yeild, take a while to get
|
||
|
; back here, and things will be really slow. What difference does
|
||
|
; it really make if we or the BIOS does the delay, at least we can
|
||
|
; break out of it at some point when it seems hopeless.
|
||
|
;
|
||
|
; The OKIHACK: Okidata reports a 50 ns. 2.2 volt pulse on the paper
|
||
|
; out signal on the trailing edge of the Busy signal. If we see this
|
||
|
; glitch then we report paper out. So we try to get the status twice...
|
||
|
; if it changes between the two tries we keep getting the status.
|
||
|
;
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = cid
|
||
|
; AL = character to output
|
||
|
; CH = Function request. 0 = Output, 1 = Initialize, 2 = Status
|
||
|
; DS:SI -> DEB for the port
|
||
|
; Returns:
|
||
|
; AX = 0 if no errors occured
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; SI,DI
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
|
||
|
; FCLI/FSTI macros
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
include vint.inc
|
||
|
|
||
|
externFP OutputDebugString
|
||
|
|
||
|
dbmsg macro msg
|
||
|
.286
|
||
|
push cs
|
||
|
push offset $ + 3 + 5 + 2 ; push + far call + short jump
|
||
|
call OutputDebugString
|
||
|
jmp short @F
|
||
|
db msg,13,10,0
|
||
|
@@:
|
||
|
endm
|
||
|
|
||
|
iodelay macro
|
||
|
jmp $+2
|
||
|
jmp $+2
|
||
|
endm
|
||
|
|
||
|
public DoLPT ;Publics for debugging
|
||
|
public LPT_Reset
|
||
|
public LPT_Outchar
|
||
|
public LPT_Strobe
|
||
|
public LPT_GetStatus
|
||
|
public DoLPT40
|
||
|
|
||
|
; status bit defines
|
||
|
|
||
|
L_BITS equ 0F8h ; the status bits we want
|
||
|
L_BITS_INVERT equ 048h ; must invert to match BIOS
|
||
|
L_DEVBUSY equ 080h ; device busy bit
|
||
|
L_TIMEOUT equ 001h ; timeout bit
|
||
|
|
||
|
; control bit defines
|
||
|
|
||
|
L_NORMAL equ 00Ch ; normal state: selected, no reset
|
||
|
L_RESET equ 008h ; reset state
|
||
|
L_STROBE equ 00Dh ; tell printer we have char
|
||
|
|
||
|
DoLPT proc near
|
||
|
|
||
|
mov dx,Port[si] ;Get port address
|
||
|
|
||
|
; DX = port address
|
||
|
; CH = operation: 0 = write, 1 = init, 2 = status
|
||
|
; AL = character
|
||
|
|
||
|
or ch, ch
|
||
|
jz LPT_OutChar
|
||
|
cmp ch, 1
|
||
|
jz LPT_Reset
|
||
|
jmp LPT_GetStatus
|
||
|
ret
|
||
|
|
||
|
LPT_Reset:
|
||
|
|
||
|
inc dx
|
||
|
inc dx
|
||
|
mov al, L_RESET
|
||
|
iodelay
|
||
|
out dx, al
|
||
|
|
||
|
push dx
|
||
|
|
||
|
cCall GetSystemMsecCount
|
||
|
mov bx, ax
|
||
|
|
||
|
LPT_ResetDelay:
|
||
|
push bx
|
||
|
cCall GetSystemMsecCount
|
||
|
pop bx
|
||
|
sub ax, bx
|
||
|
cmp ax, 300 ; 1/3 sec as good as any
|
||
|
jbe LPT_ResetDelay
|
||
|
|
||
|
pop dx
|
||
|
|
||
|
mov al, L_NORMAL
|
||
|
iodelay
|
||
|
iodelay
|
||
|
out dx, al
|
||
|
dec dx
|
||
|
dec dx
|
||
|
jmp LPT_GetStatus
|
||
|
|
||
|
LPT_OutChar:
|
||
|
push ax ; save character to be written
|
||
|
|
||
|
; first check to see if printer is ready for us
|
||
|
push di
|
||
|
|
||
|
push dx
|
||
|
call GetSystemMSecCount
|
||
|
mov di, ax
|
||
|
pop dx
|
||
|
|
||
|
LPT_WaitReady:
|
||
|
|
||
|
inc dx ; point to status port
|
||
|
iodelay
|
||
|
in al, dx ; get status bits
|
||
|
and al, L_BITS ; mask unused ones
|
||
|
xor al, L_BITS_INVERT ; flip a couple
|
||
|
xchg al, ah
|
||
|
|
||
|
ifndef NOOKIHACK
|
||
|
iodelay
|
||
|
in al, dx
|
||
|
|
||
|
dec dx
|
||
|
|
||
|
and al, L_BITS
|
||
|
xor al, L_BITS_INVERT
|
||
|
cmp al, ah ; did any bits change?
|
||
|
jnz LPT_WaitReady
|
||
|
else
|
||
|
dec dx
|
||
|
endif
|
||
|
|
||
|
|
||
|
test ah, PS_PaperOut or PS_IOError
|
||
|
jnz LPT_PrinterNotReady
|
||
|
test ah, PS_Select
|
||
|
jz LPT_PrinterNotReady
|
||
|
test ah, PS_NotBusy
|
||
|
jnz LPT_PrinterReady
|
||
|
|
||
|
push ax
|
||
|
push dx
|
||
|
call GetSystemMSecCount
|
||
|
pop dx
|
||
|
pop bx
|
||
|
sub ax, di
|
||
|
cmp ax, 300 ; 1/3 sec timeout
|
||
|
|
||
|
jbe LPT_WaitReady
|
||
|
|
||
|
; The device seems to be selected and powered up, but is just
|
||
|
; busy (some printers seem to show selected but busy when they
|
||
|
; are taken offline). Show that the transmit queue is full and
|
||
|
; that the hold handshakes are set. This is so the windows
|
||
|
; spooler will retry (and do yields so that other apps may run).
|
||
|
|
||
|
|
||
|
or ComErr[si],CE_TXFULL ;Show queue full
|
||
|
mov ah,bh
|
||
|
or ah, L_TIMEOUT
|
||
|
|
||
|
LPT_PrinterNotReady:
|
||
|
|
||
|
pop di
|
||
|
pop cx ; throw away character
|
||
|
jmp LPT_ReturnStatus
|
||
|
|
||
|
LPT_PrinterReady:
|
||
|
pop di ; get di back
|
||
|
pop ax ; get character back
|
||
|
|
||
|
iodelay
|
||
|
out dx, al ; write character to port
|
||
|
|
||
|
inc dx ; access status port
|
||
|
|
||
|
LPT_Strobe:
|
||
|
inc dx ; control port
|
||
|
mov al, L_STROBE ; set strobe high
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
out dx, al ; ...
|
||
|
|
||
|
mov al, L_NORMAL ;
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
iodelay
|
||
|
out dx, al ; set strobe low
|
||
|
|
||
|
sub dx, 2 ; point back to port base
|
||
|
|
||
|
; FALL THRU
|
||
|
|
||
|
LPT_GetStatus:
|
||
|
inc dx ; point to status port
|
||
|
LPT_GS1:
|
||
|
iodelay
|
||
|
iodelay
|
||
|
in al, dx ; get status bits
|
||
|
and al, L_BITS ; mask unused ones
|
||
|
xor al, L_BITS_INVERT ; flip a couple
|
||
|
mov ah, al
|
||
|
|
||
|
ifndef NOOKIHACK
|
||
|
in al, dx
|
||
|
and al, L_BITS
|
||
|
xor al, L_BITS_INVERT
|
||
|
cmp al, ah
|
||
|
jnz LPT_GS1 ; if they changed try again...
|
||
|
endif
|
||
|
|
||
|
LPT_ReturnStatus:
|
||
|
|
||
|
assumes ds,Data
|
||
|
and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)*256
|
||
|
shr ah,1
|
||
|
adc ah,al ;Get back Timeout bit
|
||
|
xor ah,HIGH CE_DNS ;Invert selected bit
|
||
|
.errnz LOW CE_DNS
|
||
|
or by ComErr+1[si],ah ;Save comm error
|
||
|
ret
|
||
|
|
||
|
.errnz CE_PTO-0200h
|
||
|
.errnz CE_IOE-0400h
|
||
|
.errnz CE_DNS-0800h
|
||
|
.errnz CE_OOP-1000h
|
||
|
|
||
|
DoLPT40:
|
||
|
assumes ds,Data
|
||
|
or ComErr[si],CE_TXFULL ;Show queue full
|
||
|
ret
|
||
|
|
||
|
DoLPT endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; TXI - Transmit A Character Immediately
|
||
|
;
|
||
|
; Set up a character to be transmitted "immediately".
|
||
|
; by placing the character in a location that guarantees
|
||
|
; it to be the next character transmitted.
|
||
|
;
|
||
|
; The check to see if the immediate character can be placed has
|
||
|
; already been made prior to entry.
|
||
|
;
|
||
|
; Interrupts must be disabled before entering this code
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Character
|
||
|
; DS:SI --> DEB
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; BX,CX,SI,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; AL,DX,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public TXI ;Public for debugging
|
||
|
TXI proc near
|
||
|
|
||
|
; FCLI ;Must be done by caller!
|
||
|
or EFlags[si],fTxImmed ;Show char to xmit
|
||
|
mov ImmedChar[si],ah ;Set character to transmit next
|
||
|
; jmp short KickTx ;Kick Xmit just in case
|
||
|
errn$ KickTx
|
||
|
|
||
|
TXI endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; KickTx - Kick Transmitter
|
||
|
;
|
||
|
; "Kick" the transmitter interrupt routine into operation.
|
||
|
; If the Transmitter Holding Register isn't empty, then
|
||
|
; nothing needs to be done. If it is empty, then the xmit
|
||
|
; interrupt needs to enabled in the IER.
|
||
|
;
|
||
|
; Entry:
|
||
|
; DS:SI --> DEB
|
||
|
; INTERRUPTS DISABLED!
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; BX,CX,SI,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; AX,DX,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public KickTx ;Public for debugging
|
||
|
KickTx proc near
|
||
|
|
||
|
; FCLI ;Done by caller
|
||
|
mov dx,Port[si] ;Get device I/O address
|
||
|
add dl,ACE_LSR ;Point at the line status reg
|
||
|
pin al,dx ;And get it
|
||
|
and al,ACE_THRE ;Check transmitter holding reg status
|
||
|
jz KickTx10 ;Busy, interrupt will hit soon enough
|
||
|
|
||
|
sub dl,ACE_LSR-ACE_IER ;--> Interrupt enable register
|
||
|
pin al,dx ;Get current IER state
|
||
|
test al,ACE_THREI ;Interrupt already enabled?
|
||
|
jnz KickTx10 ; Yes, don't reenable it
|
||
|
or al,ACE_THREI ; No, enable it
|
||
|
pout dx,al
|
||
|
pause ;8250, 8250-B bug requires
|
||
|
pout dx,al ; writting register twice
|
||
|
|
||
|
KickTx10:
|
||
|
; FSTI ;Done by caller
|
||
|
ret
|
||
|
|
||
|
KickTx endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; GetDEB - Get Pointer To Device's DEB
|
||
|
;
|
||
|
; Returns a pointer to appropriate DEB, based on device number.
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = cid
|
||
|
; Returns:
|
||
|
; 'C' clear
|
||
|
; 'S' set if LPT device
|
||
|
; DS:SI --> DEB is valid cid
|
||
|
; AH = cid
|
||
|
; Error Returns:
|
||
|
; 'C' set if error (cid is invalid)
|
||
|
; AX = 8000h
|
||
|
; Registers Preserved:
|
||
|
; BX,CX,DX,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; AX,SI,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public GetDEB ;Public for debugging
|
||
|
GetDEB proc near
|
||
|
|
||
|
cmp ah,LPTx+MAXLPT ;Within range?
|
||
|
ja GetDEB30 ;No, return invalid ID
|
||
|
mov si,DataOFFSET LPT3 ;Assume LPT3
|
||
|
je GetDEB10 ;It's LPT3
|
||
|
cmp ah,MAXCOM ;Is cid within range for a com port?
|
||
|
ja GetDEB20 ; No, check for a LPT port 1 and 2
|
||
|
mov si,DataOFFSET Comm4 ;Assume COM4 [rkh] ...
|
||
|
je GetDEB10 ;It was COM4
|
||
|
mov si,DataOFFSET Comm3 ;Assume COM3
|
||
|
cmp ah,MAXCOM-1 ;Is cid within range for a com port?
|
||
|
je GetDEB10 ;It was COM3
|
||
|
mov si,DataOFFSET Comm2 ;Assume COM2
|
||
|
cmp ah,MAXCOM-2 ;Is cid within range for a com port?
|
||
|
je GetDEB10 ;It was COM2
|
||
|
mov si,DataOFFSET Comm1 ;It was COM1
|
||
|
|
||
|
GetDEB10:
|
||
|
or ah,ah ;Set 'S' if LPT, clear 'C'
|
||
|
ret
|
||
|
.errnz LPTx-10000000b
|
||
|
|
||
|
GetDEB20:
|
||
|
mov si,DataOFFSET LPT1 ;Assume LPT1
|
||
|
cmp ah,LPTx
|
||
|
je GetDEB10 ;Its LPT1
|
||
|
mov si,DataOFFSET LPT2 ;Assume LPT2
|
||
|
ja GetDEB10 ;Its LPT2
|
||
|
|
||
|
GetDEB30:
|
||
|
mov ax,8000h ;Set error code
|
||
|
stc ;Set 'C' to show error
|
||
|
ret
|
||
|
|
||
|
GetDEB endp
|
||
|
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $SETQUE - Set up Queue Pointers
|
||
|
;
|
||
|
; Sets pointers to Receive and Transmit Queues, as provided by the
|
||
|
; caller, and initializes those queues to be empty.
|
||
|
;
|
||
|
; Queues must be set before $INICOM is called!
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; ES:BX --> Queue Definition Block
|
||
|
; Returns:
|
||
|
; AX = 0 if no errors occured
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; BX,DX,SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,CX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $SETQUE
|
||
|
$SETQUE proc near
|
||
|
|
||
|
push si ;These will be used
|
||
|
push di
|
||
|
call GetDEB ;Get DEB
|
||
|
jc SetQue10 ;Invalid, ignore the call
|
||
|
js SetQue10 ;Ignore call for LPT ports
|
||
|
push ds ;Set ds:si --> QDB
|
||
|
push es ;Set es:di --> to ComDCB.QInAddr
|
||
|
pop ds
|
||
|
assumes ds,nothing
|
||
|
pop es
|
||
|
assumes es,Data
|
||
|
lea di,QInAddr[si]
|
||
|
mov si,bx
|
||
|
mov cx,(SIZE QDB)/2
|
||
|
.errnz (SIZE QDB) AND 1
|
||
|
xor ax,ax ;Will do some zero filling
|
||
|
cld
|
||
|
FCLI ;No one else can play with queues
|
||
|
rep movsw
|
||
|
mov cl,(EFlags-QInCount)/2
|
||
|
.errnz (EFlags-QInCount) AND 0FE01h
|
||
|
rep stosw
|
||
|
FSTI
|
||
|
push es ;Restore the data segment
|
||
|
pop ds
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
SetQue10:
|
||
|
pop di ;Restore saved registers
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
; The above code made a few assumptions about how memory
|
||
|
; was allocated within the structures:
|
||
|
|
||
|
.errnz (QueueRxSize-QueueRxAddr)-(QInSize-QInAddr)
|
||
|
.errnz (QueueTxAddr-QueueRxSize)-(QOutAddr-QInSize)
|
||
|
.errnz (QueueTxSize-QueueTxAddr)-(QOutSize-QOutAddr)
|
||
|
|
||
|
.errnz QueueRxSize-QueueRxAddr-4
|
||
|
.errnz QueueTxAddr-QueueRxSize-2
|
||
|
.errnz QueueTxSize-QueueTxAddr-4
|
||
|
|
||
|
.errnz QInSize-QInAddr-4
|
||
|
.errnz QOutAddr-QInSize-2
|
||
|
.errnz QOutSize-QOutAddr-4
|
||
|
|
||
|
.errnz QInCount-QOutSize-2
|
||
|
.errnz QInGet-QInCount-2
|
||
|
.errnz QInPut-QInGet-2
|
||
|
.errnz QOutCount-QInPut-2
|
||
|
.errnz QOutGet-QOutCount-2
|
||
|
.errnz QOutPut-QOutGet-2
|
||
|
.errnz EFlags-QOutPut-2 ;First non-queue item
|
||
|
|
||
|
$SETQUE endp
|
||
|
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $EVT - Set Event Mask
|
||
|
;
|
||
|
; Set up event word and mask. Returns a pointer to a word in which
|
||
|
; certain bits, as enabled by the mask, will be set when certain
|
||
|
; events occur.
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; BX = Event enable mask
|
||
|
; Returns:
|
||
|
; DX:AX --> event word.
|
||
|
; Error Returns:
|
||
|
; AX = 0 if error
|
||
|
; Registers Preserved:
|
||
|
; BX,CX,SI,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; AX,DX,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $EVT
|
||
|
$EVT proc near
|
||
|
|
||
|
push si
|
||
|
xor dx,dx ;In case of error
|
||
|
call GetDEB ;Get pointer to DEB
|
||
|
mov ax,dx ;Finish setting error return value
|
||
|
jc Evt10 ;Illegal id, return error
|
||
|
js Evt10 ;LPTx, return error
|
||
|
mov EvtMask[si],bx ;Save the new event mask
|
||
|
lea ax,EvtWord[si] ;Get address of event word
|
||
|
mov dx,ds ; into dx:ax
|
||
|
|
||
|
Evt10:
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
$EVT endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $EVTGET - Get Event Word
|
||
|
;
|
||
|
; Return and clear fields in the event word. This routine MUST be used
|
||
|
; by applications to read the event word, as it is the ONLY way they
|
||
|
; can be assured that an event is not lost between reading the flags
|
||
|
; and resetting some.
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; BX = Event clear mask
|
||
|
; Returns:
|
||
|
; AX = event word
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; AX,CX,SI,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; BX,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $EVTGET
|
||
|
$EVTGET proc near
|
||
|
|
||
|
push si
|
||
|
call GetDEB
|
||
|
mov ah,0 ;In case of error (AL already 0)
|
||
|
jc EvtGet10 ;Illegal ID
|
||
|
js EvtGet10 ;Illegal ID
|
||
|
FCLI ;No interrupts allowed
|
||
|
mov ax,EvtWord[si] ;Get the current event word
|
||
|
not bx ;Convert mask for our purposes
|
||
|
and bx,ax ;Clear events that user wants us to
|
||
|
mov EvtWord[si],bx ;And save those results
|
||
|
FSTI ;Magic over
|
||
|
|
||
|
EvtGet10:
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
$EVTGET endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $STACOM - Return Status Information
|
||
|
;
|
||
|
; Returns the number of bytes in both queues.
|
||
|
;
|
||
|
; LPT ports will show both queues empty.
|
||
|
; and resetting some.
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; ES:BX = Pointer to status structure to be updated.
|
||
|
; = Null if not to update
|
||
|
; Returns:
|
||
|
; AX = comm error word
|
||
|
; Status Structure Updated.
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $STACOM
|
||
|
$STACOM proc near
|
||
|
|
||
|
push si
|
||
|
call GetDEB ;Get DEB pointer in SI
|
||
|
jc StaCom30 ;Invalid ID
|
||
|
mov cx,es ;Is the pointer NULL?
|
||
|
or cx,bx
|
||
|
jz StaCom25 ; Yes, just return error code
|
||
|
xor cx,cx
|
||
|
xor dx,dx
|
||
|
or ah,ah ;Set 'S' if LPT port
|
||
|
mov ax,cx ;For LPTs, everything is zero
|
||
|
js StaCom20 ;LPT port
|
||
|
|
||
|
; Need to get the status for a com port. Since not all the
|
||
|
; status is contained within EFlags, it has to be assembled.
|
||
|
; Also note that currently there is no way to specify RLSD
|
||
|
; as a handshaking line, so fRLSDHold is always returned false.
|
||
|
|
||
|
mov al,MSRShadow[si] ;Get state of hardware lines
|
||
|
and al,OutHHSLines[si] ;Mask off required bits
|
||
|
xor al,OutHHSLines[si] ;1 = line low
|
||
|
mov cl,4 ;Align bits
|
||
|
shr al,cl ;al = fCTSHold + fDSRHold
|
||
|
.errnz ACE_CTS-00010000b
|
||
|
.errnz ACE_DSR-00100000b
|
||
|
.errnz fCTSHold-00000001b
|
||
|
.errnz fDSRHold-00000010b
|
||
|
|
||
|
mov ah,HSFlag[si] ;Get fXOffHold+fXOffSent
|
||
|
and ah,XOffReceived+XOffSent
|
||
|
or al,ah
|
||
|
|
||
|
.errnz XOffReceived-fXOFFHold
|
||
|
.errnz XOffSent-fXOFFSent
|
||
|
|
||
|
mov ah,EFlags[si] ;Get fEOF+fTxImmed
|
||
|
and ah,fEOF+fTxImmed
|
||
|
or al,ah
|
||
|
|
||
|
mov cx,QInCount[si] ;Get input queue count
|
||
|
mov dx,QOutCount[si] ;Get tx queue count
|
||
|
|
||
|
StaCom20:
|
||
|
mov es:StatFlags[bx],al
|
||
|
mov es:StatRxCount[bx],cx
|
||
|
mov es:StatTxCount[bx],dx
|
||
|
|
||
|
StaCom25:
|
||
|
xor ax,ax ;Return old com error
|
||
|
xchg ax,ComErr[si] ; and clear it out
|
||
|
|
||
|
StaCom30:
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
$STACOM endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $SetBrk - Set Break
|
||
|
;
|
||
|
; Clamp the Tx data line low. Does not wait for the
|
||
|
; transmitter holding register and shift registers to empty.
|
||
|
;
|
||
|
; LPT ports will just return the comm error word
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; Returns:
|
||
|
; AX = comm error word
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $SETBRK
|
||
|
$SETBRK proc near
|
||
|
|
||
|
mov cx,0FF00h+ACE_SB ;Will be setting break
|
||
|
jmp short ClrBrk10
|
||
|
.errnz BreakSet-ACE_SB ;Must be same bits
|
||
|
|
||
|
$SETBRK endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $CLRBRK - Clear Break
|
||
|
;
|
||
|
; Release any BREAK clamp on the Tx data line.
|
||
|
;
|
||
|
; LPT ports will just return the comm error word
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; Returns:
|
||
|
; AX = comm error word
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS,ES
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $CLRBRK
|
||
|
$CLRBRK proc near
|
||
|
|
||
|
mov cx,(NOT ACE_SB) SHL 8
|
||
|
.errnz BreakSet-ACE_SB ;Must be same bits
|
||
|
|
||
|
ClrBrk10:
|
||
|
push si
|
||
|
call GetDEB ;Get DEB address
|
||
|
jc ClrBrk30 ;Invalid ID
|
||
|
js ClrBrk20 ;Ignored for LPT ports
|
||
|
FCLI
|
||
|
and HSFlag[si],ch ;Set or clear the BreakSet bit
|
||
|
or HSFlag[si],cl
|
||
|
|
||
|
; ch = mask to remove bits in the Line Control Register
|
||
|
; cl = mask to turn bits on in the Line Control Register
|
||
|
|
||
|
mov dx,Port[si] ;Get comm device base I/O port
|
||
|
add dl,ACE_LCR ;Point at the Line Control Regieter
|
||
|
pin al,dx ;Get old line control value
|
||
|
and al,ch ;Turn off desired bits
|
||
|
or al,cl ;Turn on desired bits
|
||
|
pause
|
||
|
pout dx,al ;Output New LCR.
|
||
|
FSTI
|
||
|
|
||
|
ClrBrk20:
|
||
|
mov ax,ComErr[si] ;Return Status Word
|
||
|
|
||
|
ClrBrk30:
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
$CLRBRK endp
|
||
|
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $EXTCOM - Extended Comm Functions
|
||
|
;
|
||
|
; A number of extended functions are routed through this entry point.
|
||
|
;
|
||
|
; Functions currently implemented:
|
||
|
;
|
||
|
; 0: Ignored
|
||
|
; 1: SETXOFF - Exactly as if X-OFF character has been received.
|
||
|
; 2: SETXON - Exactly as if X-ON character has been received.
|
||
|
; 3: SETRTS - Set the RTS signal
|
||
|
; 4: CLRRTS - Clear the RTS signal
|
||
|
; 5: SETDTR - Set the DTR signal
|
||
|
; 6: CLRDTR - Clear the DTR signal
|
||
|
; 7: RESET - Yank on reset line if available (LPT devices)
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; BL = Function Code
|
||
|
; (0-127 are MS-defined, 128-255 are OEM defined)
|
||
|
; Returns:
|
||
|
; AX = comm error word
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
|
||
|
; Dispatch table for the extended functions
|
||
|
|
||
|
ExtTab dw ExtComDummy ;Function 0: Never Mind
|
||
|
dw ExtCom_FN1 ;1: Set X-Off
|
||
|
dw ExtCom_FN2 ;2: Clear X-Off
|
||
|
dw ExtCom_FN3 ;3: Set RTS
|
||
|
dw ExtCom_FN4 ;4: Clear RTS
|
||
|
dw ExtCom_FN5 ;5: Set DSR
|
||
|
dw ExtCom_FN6 ;6: Clear DSR
|
||
|
dw ExtCom_FN7 ;7: Reset printer
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $EXTCOM
|
||
|
$EXTCOM proc near
|
||
|
|
||
|
push si
|
||
|
call GetDEB ;Get DEB pointer
|
||
|
jc ExtCom40 ;Invalid ID, return error
|
||
|
mov dx,Port[si] ; get port address
|
||
|
jns ExtCom10 ;Its a COM port
|
||
|
cmp bl,7 ;RESET extended function?
|
||
|
jne ExtCom30 ; No, return error word
|
||
|
jmp short ExtCom20 ; Yes, invoke the function
|
||
|
|
||
|
ExtCom10:
|
||
|
cmp bl,7 ;Last fcn supported +1
|
||
|
jnc ExtCom30 ;Not an implemented function.
|
||
|
|
||
|
ExtCom20:
|
||
|
xor bh,bh
|
||
|
add bx,bx ;Shift for the call
|
||
|
FCLI ;Consider as critical sections
|
||
|
call ExtTab[bx] ; and perform the function
|
||
|
FSTI
|
||
|
|
||
|
ExtCom30:
|
||
|
mov ax,ComErr[si] ;Return standard error word
|
||
|
|
||
|
ExtCom40:
|
||
|
pop si
|
||
|
|
||
|
ExtComDummy:
|
||
|
ret
|
||
|
|
||
|
$EXTCOM endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; ExtCom_FN1 - Extended Function Set X-Off
|
||
|
;
|
||
|
; Analagous to receiving an X-OFF character. Bufferred transmision of
|
||
|
; characters is halted until an X-ON character is received, or until
|
||
|
; we fake that with a Clear X-Off call.
|
||
|
;
|
||
|
; Entry:
|
||
|
; interrupts disabled
|
||
|
; dx = port base address
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public ExtCom_FN1
|
||
|
ExtCom_FN1 proc near
|
||
|
|
||
|
or HSFlag[si],XOffReceived
|
||
|
ret
|
||
|
|
||
|
ExtCom_FN1 endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; ExtCom_FN2 - Extended Function Clear X-Off
|
||
|
;
|
||
|
; Analagous to receiving an X-ON character. Buffered
|
||
|
; transmission of characters is restarted.
|
||
|
;
|
||
|
; Entry:
|
||
|
; interrupts disabled
|
||
|
; dx = port base address
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public ExtCom_FN2
|
||
|
ExtCom_FN2 proc near
|
||
|
|
||
|
and HSFlag[si],NOT XOffReceived
|
||
|
jmp KickTx ;Kick transmitter interrupts on
|
||
|
|
||
|
ExtCom_FN2 endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; ExtCom_FN3 - Extended Function Set RTS
|
||
|
;
|
||
|
; Set the RTS signal active.
|
||
|
;
|
||
|
; Entry:
|
||
|
; interrupts disabled
|
||
|
; dx = port base address
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public ExtCom_FN3
|
||
|
ExtCom_FN3 proc near
|
||
|
|
||
|
add dl,ACE_MCR ;Point at Modem Control Register
|
||
|
pin al,dx ;Get current settings
|
||
|
or al,ACE_RTS ;Set RTS
|
||
|
pause
|
||
|
pout dx,al ;And update
|
||
|
ret
|
||
|
|
||
|
ExtCom_FN3 endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; ExtCom_FN4 - Extended Function Clear RTS
|
||
|
;
|
||
|
; Set the RTS signal inactive.
|
||
|
;
|
||
|
; Entry:
|
||
|
; interrupts disabled
|
||
|
; dx = port base address
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public ExtCom_FN4
|
||
|
ExtCom_FN4 proc near
|
||
|
|
||
|
add dl,ACE_MCR ;Point at Modem Control Register
|
||
|
pin al,dx ;Get current settings
|
||
|
and al,NOT ACE_RTS ;Clear RTS
|
||
|
pause
|
||
|
pout dx,al ;And update
|
||
|
ret
|
||
|
|
||
|
ExtCom_FN4 endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; ExtCom_FN5 - Extended Function Set DTR
|
||
|
;
|
||
|
; Set the DTR signal active.
|
||
|
;
|
||
|
; Entry:
|
||
|
; interrupts disabled
|
||
|
; dx = port base address
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public ExtCom_FN5
|
||
|
ExtCom_FN5 proc near
|
||
|
|
||
|
add dl,ACE_MCR ;Point at Modem Control Register
|
||
|
pin al,dx ;Get current settings
|
||
|
or al,ACE_DTR ;Set DTR
|
||
|
pause
|
||
|
pout dx,al ;And update
|
||
|
ret
|
||
|
|
||
|
ExtCom_FN5 endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; ExtCom_FN6 - Extended Function Clear DTR
|
||
|
;
|
||
|
; Set the DTR signal inactive.
|
||
|
;
|
||
|
; Entry:
|
||
|
; interrupts disabled
|
||
|
; dx = port base address
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public ExtCom_FN6
|
||
|
ExtCom_FN6 proc near
|
||
|
|
||
|
add dl,ACE_MCR ;Point at Modem Control Register
|
||
|
pin al,dx ;Get current settings
|
||
|
and al,NOT ACE_DTR ;Clear DTR
|
||
|
pause
|
||
|
pout dx,al ;And update
|
||
|
ret
|
||
|
|
||
|
ExtCom_FN6 endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Private-Routine----------------------------;
|
||
|
;
|
||
|
; ExtCom_FN7 - Extended Function Reset Printer
|
||
|
;
|
||
|
; Assert the RESET line on an LPT port
|
||
|
;
|
||
|
; Entry:
|
||
|
; interrupts disabled
|
||
|
; dx = port base address
|
||
|
; Returns:
|
||
|
; None
|
||
|
; Error Returns:
|
||
|
; None
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public ExtCom_FN7
|
||
|
ExtCom_FN7 proc near
|
||
|
|
||
|
FSTI ;Not called at interrupt time
|
||
|
mov ch,1 ;ROM BIOS Reset Port
|
||
|
call DoLPT ;Perform the function
|
||
|
ret
|
||
|
|
||
|
ExtCom_FN7 endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $DCBPtr - Return Pointer To DCB
|
||
|
;
|
||
|
; Returns a long pointer to the DCB for the requested device.
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; Returns:
|
||
|
; DX:AX = pointer to DCB.
|
||
|
; Error Returns:
|
||
|
; DX:AX = 0
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; BX,CX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $DCBPTR
|
||
|
$DCBPTR proc near
|
||
|
|
||
|
push si
|
||
|
xor dx,dx
|
||
|
call GetDEB ;Get pointer to DEB
|
||
|
mov ax,dx
|
||
|
jc DCBPtr10 ;Jump if invalid device
|
||
|
mov ax,si ;else return value here
|
||
|
mov dx,ds
|
||
|
|
||
|
DCBPtr10:
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
$DCBPTR endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $RECCOM - Receive Characters From Device
|
||
|
;
|
||
|
; Read Byte From RS232 Input Queue If Data Is Ready
|
||
|
;
|
||
|
; LPT ports will return with an indication that no characters are
|
||
|
; available.
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; Returns:
|
||
|
; 'Z' clear if data available
|
||
|
; AL = byte
|
||
|
; Error Returns:
|
||
|
; 'Z' Set if error or no data
|
||
|
; AX = error code
|
||
|
; AX = 0 if no data
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $RECCOM
|
||
|
$RECCOM proc near
|
||
|
|
||
|
push si ;Once again, save some registers
|
||
|
push di
|
||
|
call GetDEB ;Get DEB pointer in SI
|
||
|
jc RecCom10 ;Invalid Port [rkh] ...
|
||
|
js RecCom20 ;LPT port, return no characters
|
||
|
jmp short RecCom30
|
||
|
|
||
|
RecCom10:
|
||
|
jmp RecCom100 ; Invalid Port
|
||
|
|
||
|
RecCom20:
|
||
|
jmp RecCom95 ;LPT port, return no characters
|
||
|
|
||
|
; Before removing any charcters from the input queue, check to see
|
||
|
; if XON needs to be issued. If it needs to be issued, set the
|
||
|
; flag that will force it and arm transmit interrupts.
|
||
|
|
||
|
RecCom30:
|
||
|
test Flags[si],fEnqAck+fEtxAck ;Enq or Etx Ack?
|
||
|
jz RecCom32 ; No
|
||
|
test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped?
|
||
|
jz RecCom60 ; No Enq recvd & no lines dropped
|
||
|
jmp short RecCom34
|
||
|
|
||
|
RecCom32:
|
||
|
test HSFlag[si],HSSent ;Handshake sent?
|
||
|
jz RecCom60 ; No XOFF sent & no lines dropped
|
||
|
|
||
|
RecCom34:
|
||
|
mov ax,QInCount[si] ;Get current count of input chars
|
||
|
cmp ax,XONLim[si] ;See if at XOn limit
|
||
|
ja RecCom60 ;Not at XOn limit yet
|
||
|
|
||
|
; If any hardware lines are down, then raise them. Then see
|
||
|
; about sending XON.
|
||
|
|
||
|
mov dx,Port[si] ;Get the port
|
||
|
mov ah,HHSLines[si] ;Get hardware lines mask
|
||
|
FCLI ;Handle this as a critical section
|
||
|
mov cl,HSFlag[si] ;Get handshaking flags
|
||
|
or ah,ah ;Any hardware lines to play with?
|
||
|
jz RecCom40 ; No
|
||
|
add dl,ACE_MCR ;--> Modem control register
|
||
|
pin al,dx
|
||
|
or al,ah ;Turn on the hardware bits
|
||
|
pause
|
||
|
pout dx,al
|
||
|
and cl,NOT HHSDropped ;Show hardware lines back up
|
||
|
|
||
|
RecCom40:
|
||
|
test Flags[si],fEnqAck+fEtxAck ;Enq or Etx Ack?
|
||
|
jz RecCom47 ; No
|
||
|
test cl,EnqReceived ;Did we receive Enq?
|
||
|
jz RecCom55 ; No
|
||
|
and cl,NOT EnqReceived
|
||
|
jmp short RecCom50
|
||
|
|
||
|
RecCom47:
|
||
|
test cl,XOffSent ;Did we send XOFF?
|
||
|
jz RecCom55 ; No
|
||
|
and cl,NOT XOffSent ;Remove XOFF sent flag
|
||
|
|
||
|
RecCom50:
|
||
|
or cl,XOnPending ;Show XON or ACK must be sent
|
||
|
call KickTx ;Kick xmit if needed
|
||
|
|
||
|
RecCom55:
|
||
|
mov HSFlag[si],cl ;Store handshake flag
|
||
|
FSTI ;Can allow interrupts now
|
||
|
|
||
|
; Now we can get down to the business at hand, and remove a character
|
||
|
; from the receive queue. If a communications error exists, we return
|
||
|
; that, and nothing else.
|
||
|
|
||
|
RecCom60:
|
||
|
xor ax,ax
|
||
|
or ax,ComErr[si] ;Any Errors?
|
||
|
jnz RecCom100 ; Yes, return the error code
|
||
|
or ax,QInCount[si] ;Get current input char count
|
||
|
jz RecCom90 ;No characters in the queue
|
||
|
les di,QInAddr[si] ;Get queue pointer
|
||
|
assumes es,nothing
|
||
|
|
||
|
mov bx,QInGet[si] ;Also get the index to head
|
||
|
mov al,es:[bx][di] ;Finally, get byte from queue
|
||
|
inc bx ;Update queue index
|
||
|
cmp bx,QInSize[si] ;See if time for wrap-around
|
||
|
jc RecCom70 ;Jump if no wrap
|
||
|
xor bx,bx ;wrap by zeroing the index
|
||
|
|
||
|
RecCom70:
|
||
|
mov QInGet[si],bx ;Save new head pointer
|
||
|
dec QInCount[si] ;Dec # of bytes in queue
|
||
|
|
||
|
RecCom80:
|
||
|
or sp,sp ;Reset PSW.Z
|
||
|
pop di
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
; No characters in the input queue. Check to see if EOF
|
||
|
; was received, and return it if it was. Otherwise show
|
||
|
; no characters.
|
||
|
|
||
|
RecCom90:
|
||
|
test Flags[si],fBinary ;Are we doing binary stuff?
|
||
|
jnz RecCom95 ; Yes, show no characters
|
||
|
mov al,EOFChar[si] ;Assume EOF
|
||
|
test EFlags[si],fEOF ;Has end of file char been received?
|
||
|
jnz RecCom80 ; Yes, show end of file
|
||
|
|
||
|
RecCom95:
|
||
|
xor ax,ax ;Show no more characters
|
||
|
|
||
|
; Return with 'Z' to show error or no characters
|
||
|
|
||
|
RecCom100:
|
||
|
xor cx,cx ;Set PSW.Z
|
||
|
pop di
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
$RECCOM endp
|
||
|
page
|
||
|
|
||
|
;----------------------------Public Routine-----------------------------;
|
||
|
;
|
||
|
; $FLUSH - Flush The Input and Output Queues
|
||
|
;
|
||
|
; This is a hard initialization of the transmit and receive queue's,
|
||
|
; which immediately empties the given queue.
|
||
|
;
|
||
|
; LPT ports will just return the device error word
|
||
|
;
|
||
|
; Entry:
|
||
|
; AH = Device ID
|
||
|
; BH = Queue # to clear (0=Tx, 1=Rx)
|
||
|
; Returns:
|
||
|
; AX = Device Error Word. (Not reset)
|
||
|
; Error Returns:
|
||
|
; AX = error code
|
||
|
; Registers Preserved:
|
||
|
; SI,DI,DS
|
||
|
; Registers Destroyed:
|
||
|
; AX,BX,CX,DX,ES,FLAGS
|
||
|
; History:
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
;------------------------------Pseudo-Code------------------------------;
|
||
|
; {
|
||
|
; }
|
||
|
;-----------------------------------------------------------------------;
|
||
|
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public $FLUSH
|
||
|
$FLUSH proc near
|
||
|
|
||
|
push si
|
||
|
push di
|
||
|
call GetDEB ;si --> DEB
|
||
|
jc Flush40 ;Invalid ID
|
||
|
js Flush30 ;LPT port, return any error
|
||
|
|
||
|
mov cx,QOutCount-QInCount ;# of bytes to zero
|
||
|
lea di,QInCount[si] ;--> receive queue data
|
||
|
or bh,bh ;Transmit queue?
|
||
|
jnz Flush10 ; No, input queue
|
||
|
add di,cx ; Yes, --> xmit queue data
|
||
|
|
||
|
Flush10:
|
||
|
cld
|
||
|
push ds
|
||
|
pop es
|
||
|
assumes es,nothing
|
||
|
|
||
|
xor al,al
|
||
|
FCLI ;Time to worry about critical sections
|
||
|
rep stosb
|
||
|
FSTI
|
||
|
.errnz QInGet-QInCount-2
|
||
|
.errnz QInPut-QInGet-2
|
||
|
.errnz QOutCount-QInPut-2
|
||
|
.errnz QOutGet-QOutCount-2
|
||
|
.errnz QOutPut-QOutGet-2
|
||
|
|
||
|
or bh,bh ;Rx queue?
|
||
|
jz Flush30 ; No, xmit queue
|
||
|
|
||
|
|
||
|
; If the queue to be cleared is the receive queue, any
|
||
|
; hardware handshake must be cleared to prevent a possible
|
||
|
; deadlock situation. Since we just zeroed the queue count,
|
||
|
; a quick call to $RecCom should do wonders to clear any
|
||
|
; receive handshake (i.e. send XON if needed).
|
||
|
|
||
|
Flush20:
|
||
|
call $RECCOM ;Take care of handshakes here
|
||
|
|
||
|
Flush30:
|
||
|
mov ax,ComErr[si] ;And return the error word.
|
||
|
|
||
|
Flush40:
|
||
|
pop di
|
||
|
pop si
|
||
|
ret
|
||
|
|
||
|
$FLUSH endp
|
||
|
|
||
|
ifdef DEBUG
|
||
|
public KickTx10
|
||
|
public GetDEB10
|
||
|
public GetDEB20
|
||
|
public GetDEB30
|
||
|
public SetQue10
|
||
|
public Evt10
|
||
|
public EvtGet10
|
||
|
public StaCom20
|
||
|
public StaCom25
|
||
|
public StaCom30
|
||
|
public ClrBrk10
|
||
|
public ClrBrk20
|
||
|
public ClrBrk30
|
||
|
public ExtCom10
|
||
|
public ExtCom20
|
||
|
public ExtCom30
|
||
|
public ExtCom40
|
||
|
public ExtComDummy
|
||
|
public DCBPtr10
|
||
|
public RecCom30
|
||
|
public RecCom40
|
||
|
public RecCom50
|
||
|
public RecCom60
|
||
|
public RecCom70
|
||
|
public RecCom80
|
||
|
public RecCom90
|
||
|
public RecCom95
|
||
|
public RecCom100
|
||
|
public Flush10
|
||
|
public Flush20
|
||
|
public Flush30
|
||
|
public Flush40
|
||
|
endif
|