windows-nt/Source/XPSP1/NT/base/mvdm/wow16/drivers/comm/ibmcom1.asm

1557 lines
41 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
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