windows-nt/Source/XPSP1/NT/base/mvdm/wow16/drivers/neccomm1/ibmint.asm
2020-09-26 16:20:57 +08:00

2899 lines
84 KiB
NASM

page,132
;---------------------------Module-Header-------------------------------
; Module Name: IBMINT.ASM
;
; Created: Fri 06-Feb-1987 10:45:12
; Author: Walt Moore [waltm]
;
; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved
;
; General Description:
; This file contains the interrupt time routines for the
; IBM Windows communications driver.
;
; The interrupt code is preloaded and fixed.
;
; History:
;
; **********************************************************************
; Tue Dec 19 1989 09:35:15 -by- Amit Chatterjee [amitc]
; ----------------------------------------------------------------------
; Added a far entry point 'FakeCOMIntFar' so that the routine 'FakeCOMInt'
; could be called from the 'InitAPort' routine in IBMCOM.ASM
;
; 26.Nov.90 richp
;
; Changed interrupt routines to use new VPICD services for bi-modal/multi-
; modal interrupt handling. They now work in straight real mode for real
; mode Windows, but can also handle interrupts in real mode or protected
; mode for standard mode Windows, and handle interrupts in RING 0 protected
; mode for enhanced mode Windows, even when the Windows VM is not currently
; executing.
;
; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
; FCLI/FSTI macros
;-----------------------------------------------------------------------;
subttl Communications Hardware Interrupt Service Routines
.xlist
include cmacros.inc
include comdev.inc
include ibmcom.inc
include ins8250.inc
include BIMODINT.INC
include vint.inc
.list
externFP GetSystemMsecCount
externW COMptrs
externW activeCOMs
externD lpPostMessage
ifdef NEC_98
externFP Comm1 ;(ins 92.09.25)
externFP Comm2 ;(ins 92.09.25)
externFP Comm3 ;(ins 92.09.25)
externFP SetFIFOmodeFar ;(ins 94.04.18)
externFP Set8251modeFar ;(ins 94.04.18)
externW Port_TBL ;(ins 92.08.24)
externW Port_EOI ;(ins 92.08.24)
externB Vect_TBL ;(ins 92.08.24)
externB Mask_TBL ;(ins 92.08.24)
externW RECLoopCounter ;(ins 93.03.31)
BIOS_FLAG5 equ 58h ; ins 93.03.24 (IOrecovery)
BIOS_FLAG7 equ 5bh ; ins 93.03.24 (IOrecovery)
endif ; NEC_98
sBegin Data
PUBLIC IRQhooks
IRQhooks label byte
DefineIRQhook MACRO num
IFDEF No_DOSX_Bimodal_Services
IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num,,,, \
IntCodeOFFSET DEF_RM_COM_INT_&num>
ELSE
IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num>
ENDIF
ENDM
??portnum = 1
REPT MAXCOM+1
DefineIRQhook %??portnum
??portnum = ??portnum+1
ENDM
PURGE DefineIRQhook
EXTRN VCD_int_callback:fword
ifdef NEC_98
TicCount dw 0 ;Timeout counter (ins 92.09.25)
endif ; NEC_98
sEnd data
createSeg _INTERRUPT,IntCode,word,public,CODE
sBegin IntCode
assumes cs,IntCode
page
IFDEF No_DOSX_Bimodal_Services
public RM_IntDataSeg
RM_IntDataSeg dw 0
; this variable is written into by a routine in inicom
; if the 286 DOS extender is present. This variable
; contains the SEGMENT value of the data selector "_DATA"
; so that the real mode interrupt handler may use the
; data segment, and not it's selector !
PUBLIC RM_CallBack
RM_CallBack dd 0
ENDIF
Control proc far
ret
Control endp
IFDEF No_DOSX_Bimodal_Services
DEF_RM_Handler proc far
push es
push di
push ax
mov es, cs:[RM_IntDataSeg]
mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
add di, SIZE ComDEB ; ES:DI -> BIS
mov es:[di.BIS_Mode], 4
push cs
call NEAR PTR COMHandler
mov es:[di.BIS_Mode], 0
pop ax
pop di ; ES:DI -> IRQ_Hook_Struc
jc short DEF_RM_chain
pop es
pop di
add sp, 4
iret
DEF_RM_chain:
call DOCLI
push bp
mov bp, sp ;stack frame:
; bp+8 -> OldInt CS
; bp+6 -> OldInt IP
; bp+4 -> di
; bp+2 -> es
; bp+0 -> bp
les di, es:[di.RM_OldIntVec]
mov [bp+6], di
mov [bp+8], es
pop bp
pop es
pop di
ret ; far ret to OldInt handler
DEF_RM_Handler endp
ENDIF ;No_DOSX_Bimodal_Services
Define_DEF_COM_INT MACRO num
IFDEF No_DOSX_Bimodal_Services
PUBLIC DEF_RM_COM_INT_&num
DEF_RM_COM_INT_&num proc far
sub sp, 4
push di
mov di, DataOFFSET IRQhook&num
jmp DEF_RM_Handler
DEF_RM_COM_INT_&num endp
ENDIF
PUBLIC DEF_COM_INT_&num
DEF_COM_INT_&num proc far
sub sp, 4
push di
mov di, DataOFFSET IRQhook&num
ifdef NEC_98
jmp DEF_COM_DUMMY
else ; NEC_98
jmp DEF_Handler
endif ; NEC_98
DEF_COM_INT_&num endp
ENDM
??portnum = 2
REPT MAXCOM
Define_DEF_COM_INT %??portnum
??portnum = ??portnum+1
ENDM
PURGE Define_DEF_COM_INT
ifdef NEC_98
DEF_COM_DUMMY:
jmp short DEF_Handler
endif ; NEC_98
IFDEF No_DOSX_Bimodal_Services
PUBLIC DEF_RM_COM_INT_1
DEF_RM_COM_INT_1 proc far
sub sp, 4
push di
mov di, DataOFFSET IRQhook1
jmp DEF_RM_Handler
DEF_RM_COM_INT_1 endp
ENDIF
PUBLIC DEF_COM_INT_1
DEF_COM_INT_1 proc far
sub sp, 4
push di
mov di, DataOFFSET IRQhook1
IF2
.errnz $ - OFFSET DEF_Handler
ENDIF
DEF_COM_INT_1 endp
DEF_Handler proc far
push es
push di
push ax
mov ax, _DATA
mov es, ax
mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
add di, SIZE ComDEB ; ES:DI -> BIS
push cs
call NEAR PTR COMHandler
pop ax
pop di ; ES:DI -> IRQ_Hook_Struc
jc short DEF_chain
pop es
pop di
add sp, 4
iret
DEF_chain:
call DOCLI
push bp
mov bp, sp ;stack frame:
; bp+8 -> OldInt CS
; bp+6 -> OldInt IP
; bp+4 -> di
; bp+2 -> es
; bp+0 -> bp
les di, es:[di.OldIntVec]
mov [bp+6], di
mov [bp+8], es
pop bp
pop es
pop di
ret ; far ret to OldInt handler
DEF_Handler endp
;------------------------------------------------------------------------------
;
; ENTER: ES:DI -> BIS
;
; EXIT: Carry set, if IRQ not handled by any com ports
;
COMHandler proc far
push ds
push si
push ax
push bx
mov si, es
mov ds, si
mov bh, -1
ch_chk_all:
lea si, [di-SIZE ComDEB] ;ds:si -> ComDEB
mov si, [si.IRQhook]
mov si, [si.First_DEB]
mov bl, -1
ch_next_com:
inc bl ; first time bl = 0
xor ax, ax
xchg ax, [di.BIS_Mode]
lea di, [si+SIZE ComDEB]
mov [di.BIS_Mode], ax
ifdef NEC_98
test [si.AOBA_flag],fFIFO_Mode ; (ins 94.04.16) |
jz @F ;Now, 8251 mode (ins 94.04.16) |
call AOBA_CommInt ; (ins 94.04.16) |
jmp short ch_AOBA_int ; (ins 94.05.17) |
@@: ; (ins 94.04.16) |
call CommInt
ch_AOBA_int: ; (ins 94.05.17)
else ; NEC_98
call CommInt
endif ; NEC_98
and al, 80h
or bl, al
mov si, [si.NextDEB]
or si, si
jnz ch_next_com
test bl, 7Fh ;Q: more than 1 com port?
jnz short ch_shared ; Y: check if handled
or bl, bl ;Q: int handled by port?
stc
jns ch_exit ; N:
ch_eoi:
xor ax, ax
.errnz BIH_API_EOI
xor bx, bx
xchg bx, es:[di.BIS_Mode]
call es:[bx][di.BIS_User_Mode_API]
lea si, [di-SIZE ComDEB] ; ds:si -> ComDEB
mov si, [si.IRQhook]
mov al, [si.OldMask]
shr al, 1 ; shift bit 0 into Carry (0, if unmasked
cmc ; -1, if originally masked)
ch_exit:
pop bx
pop ax
pop si
pop ds
ret
ch_shared:
inc bh ; count loop
or bl, bl ;Q: int handled by any port?
js ch_chk_all ; Y: check all ports again
or bh, bh ;Q: first time thru loop?
stc
jz ch_exit ; Y: int wasn't for a COM port, so
; chain to next IRQ handler
jmp ch_eoi
COMHandler endp
IFDEF No_DOSX_Bimodal_Services
PUBLIC Entry_From_RM
Entry_From_RM proc far
;
; Simulate the far ret
;
cld
lodsw
mov es:[di.RealMode_IP], ax
lodsw
mov es:[di.RealMode_CS], ax
add es:[di.RealMode_SP], 4
push es
push di
.286
;
; Push far addr of Ret_To_IRET to cleanup stack and return to DPMI host
;
push cs
push IntCodeOFFSET Ret_To_IRET
;
; Push far addr of proc to call, so we can do a far ret to it
;
push es:[di.RealMode_CX] ; segment of callback
push es:[di.RealMode_DX] ; offset of callback
mov di, es:[di.RealMode_DI]
ret ; far ret to cx:dx
; called proc will do a far ret
Ret_To_IRET: ; <- to here
pop di
pop es
iret
.8086
Entry_From_RM endp
PUBLIC RM_APIHandler
RM_APIHandler proc far
cmp ax, BIH_API_Call_Back
jne APIHandler
call cs:[RM_CallBack]
ret
RM_APIHandler endp
ENDIF
;------------------------------------------------------------------------------
;
; ENTER: ES:DI -> BIS
;
APIHandler proc far
or ax, ax
jnz short api_not_EOI
.errnz BIH_API_EOI
ifdef NEC_98
push dx ; (ins 93.03.20)
mov ax, es:[di.BIS_IRQ_Number] ; (ins 92.10.06)
cmp al,8 ;Q: slave IRQ? (ins 92.10.06)
mov al,EOI ; (ins 92.10.06)
jb short api_master ; N: (ins 92.10.06)
mov dx,08h ;Pic port address save (ins 93.03.11)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 93.03.08)
out dx,al ; (ins 93.03.08)
mov al,ISR_READ ;Isr read command byte (ins 93.03.08)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 93.03.08)
out dx,al ; (ins 93.03.08)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 93.03.08)
in al,SLAVE_ISR ; (ins 93.03.08)
test al,0ffh ; (ins 93.03.08)
jnz EOI_INT50 ; (ins 93.03.08)
mov al,EOI ; (ins 93.03.08)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 93.03.08)
jmp short api_master ; (ins 93.03.08)
EOI_INT50: ; (ins 93.03.08)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 93.03.08)
pop dx ; (ins 93.03.20)
ret ; (ins 93.03.08)
api_master: ; (ins 92.10.06)
out 00h,al ; EOI master (ins 92.10.06)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 93.03.08)
pop dx ; (ins 93.03.20)
ret ; (ins 92.10.06)
else ; NEC_98
mov ax, es:[di.BIS_IRQ_Number]
cmp al,8 ;Q: slave IRQ?
mov al,EOI
jb short api_master ; N:
out 0A0h,al ; Y: EOI slave
api_master:
out INTA0,al ; EOI master
ret
endif ; NEC_98
api_not_EOI:
cmp ax, BIH_API_Call_Back
jae short api_callme
push dx
push cx
ifdef NEC_98
mov dx, 0002h ; (ins 92.10.06)
else ; NEC_98
mov dx, INTA1
endif ; NEC_98
mov cx, es:[di.BIS_IRQ_Number]
cmp cl, 8 ;Q: 2nd PIC?
jb @f ; N:
ifdef NEC_98
mov dx, 000Ah ; (ins 92.10.06)
else ; NEC_98
mov dx, 0A1h ; Y: dx = mask port
endif ; NEC_98
sub cl, 8
@@:
cmp al, BIH_API_Get_Mask ;Q: get IRQ mask?
jae api_get_mask ; Y:
mov ah, al
mov ch, 1
shl ch, cl ; ch = mask byte
pushf
call DOCLI
in al, dx ; get current PIC mask state
cmp ah, BIH_API_Mask ;Q: mask IRQ?
jne @f ; N:
or al, ch ; Y: set IRQ's bit
jmp short api_mask_exit
@@:
not ch ; N: clear IRQ's bit to unmask
and al, ch
api_mask_exit:
out dx, al
pop ax
test ah, 2 ;Q: ints were enabled?
jz @f ; N:
call DOSTI
@@:
pop cx
pop dx
ret
api_get_mask:
in al, dx ; get current PIC mask state
inc cl
shr al, cl ; move IRQ's bit into carry
; Carry set, if IRQ masked
pop cx
pop dx
ret
api_callme:
push cx
push dx
ret ; far ret to call back, which will
; do a far ret to our caller
APIHandler endp
;--------------------------Fake a Hardware Interrupt----------------------;
; FakeCOMInt
;
; This routine fakes a hardware interrupt to IRQ3 or IRQ4
; to clear out characters pending in the buffer
;
; Entry:
; DS:SI --> DEB
; INTERRUPTS DISABLED!
; Returns:
; None
; Error Returns:
; None
; Registers Preserved:
;
; Registers Destroyed:
; AX,DX,FLAGS
; History: glenn steffler 5/17/89
;-----------------------------------------------------------------------;
FakeCOMInt proc near
; call DOCLI ;Done by caller
;
; WARNING: jumping into the middle of CommInt, so the stack must be set
; properly.
;
push dx
push bx
push cx
push di
push es
push EvtWord[si]
ifdef NEC_98
test [si.AOBA_flag],fFIFO_Mode ; (ins 94.04.16) |
jz @F ;Now, 8251 mode (ins 94.04.16) |
mov dx,Port[si] ;Get device I/O address (ins 94.04.16) |
add dl, ACE_IIDR ; (ins 94.04.16) |
push dx ; (ins 94.04.18) |
jmp AOBA_FakeXmitEmpty ; (ins 94.04.18) |
@@: ; (ins 94.04.16) |
else ; NEC_98
mov dx,Port[si] ;Get device I/O address
add dl, ACE_IIDR
endif ; NEC_98
push dx
jmp FakeXmitEmpty ;Process the fake interrupt, DS:SI is
; already pointing to proper DEB
;
; FakeXmitEmpty falls in XmitEmpty which jumps back into CommInt. When CommInt
; determines that no interrupt is pending, then it will near return back to
; FakeCOMIntFar which can far ret back to its caller.
;
FakeCOMInt endp
public FakeCOMIntFar
FakeCOMIntFar proc far
call FakeCOMInt
ret
FakeCOMIntFar endp
;--------------------------Interrupt Handler----------------------------
;
; CommInt - Interrupt handler for com ports
;
; Interrupt handlers for PC com ports. This is the communications
; interrupt service routine for RS232 communications. When an RS232
; event occurs the interrupt vectors here. This routine determines
; who the caller was and services the appropriate interrupt. The
; interrupts are prioritized in the following order:
;
; 1. line status interrupt
; 2. read data available interrupt
; 3. transmit buffer empty interrupt
; 4. modem service interrupt
;
; This routine continues to service until all interrupts have been
; satisfied.
;
; Entry:
; DS:SI --> DEB
; INTERRUPTS DISABLED!
; Returns:
; AL = 0, if not handled, -1, if handled
;
;-----------------------------------------------------------------------
assumes ds,Data
assumes es,nothing
; Dispatch table for interrupt types
ifndef NEC_98
SrvTab label word
dw OFFSET ModemStatus ;[0] Modem Status Interrupt
dw OFFSET XmitEmpty ;[2] Tx Holding Reg. Interrupt
dw OFFSET DataAvail ;[4] Rx Data Available Interrupt
; or [C] if 16550 & 16550A
dw OFFSET LineStat ;[6] Reciever Line Status Interrupt
endif ; NEC_98
public CommInt
CommInt proc near
xor al, al
cmp word ptr [VCD_int_callback+4], 0
je short @F ; jump if no callback (not 3.1 VCD)
test [si.VCDflags], fCOM_ignore_ints ;Q: we still own port?
ifdef NEC_98
jz IntLoop45 ; [QN] (ins 92.09.xx)
ret ; [QN] (ins 92.09.xx)
IntLoop45: ; [QN] (ins 92.09.xx)
else ; NEC_98
jnz IntLoop40 ; N: ignore the int
endif ; NEC_98
.386
push esi
mov esi, [si.VCD_data]
call [VCD_int_callback]
pop esi
.8086
@@:
push dx
ifdef NEC_98
mov dx,StatusPort[si] ; [QN] (ins 92.08.xx)
in al, dx ; Get Status [QN] (ins 92.08.xx)
test al,(TX_RDY+TX_EMP+RX_RDY); [QN] (ins 92.08.xx)
jnz IntLoop_qn ; Yes [QN] (ins 93.03.17)
or al, 1 ; No [QN] (ins 93.03.17)
jmp short IntLoop30 ; [QN] (ins 93.03.17)
IntLoop_qn: ; [QN] (ins 93.03.17)
xor al, al ; [QN] (ins 93.03.17)
else ; NEC_98
mov dx,Port[si] ;Get comm I/O port
add dl,ACE_IIDR ;--> Interrupt ID Register
in al, dx
test al, 1 ;Q: interrupt pending?
jnz short IntLoop30 ; N:
endif ; NEC_98
push bx
push cx
push di
push es
mov cx, EvtWord[si]
push cx
jmp short IntLoop10
InterruptLoop_ChkTx:
cmp QOutCount[si],0 ;Output queue empty?
je short InterruptLoop ; Y: don't chk tx
ifdef NEC_98
call KickTxINT ; (ins 92.09.xx)
else ; NEC_98
pop dx
push dx
dec dx ; to IER
.errnz ACE_IIDR - ACE_IER - 1
in al, dx
and al,NOT ACE_ETBEI ; disable it
iodelay
out dx, al
or al, ACE_ETBEI ; enable it again
iodelay
out dx, al
iodelay
out dx, al
endif ; NEC_98
InterruptLoop:
ifdef NEC_98
mov dx,StatusPort[si] ;Get ID reg I/O Address (ins 92.08.xx)
; (ins 92.08.xx)
IntLoop10: ; (ins 92.08.xx)
in al,dx ;Get Interrupt Id (ins 92.08.xx)
test al,RX_RDY ; (ins 92.08.xx)
jz Intloop15 ; (ins 92.08.xx)
jmp DataAvail ;Receive Data (ins 92.08.xx)
; (ins 92.08.xx)
IntLoop15: ; (ins 92.08.xx)
test al,(TX_RDY) ; (ins 92.08.xx)
jz IntLoop20 ; (ins 92.08.xx)
jmp XmitEmpty ;Send Data (ins 92.08.xx)
; (ins 92.08.xx)
;Check whether tx queue (ins 92.08.xx)
; has data (ins 92.08.xx)
IntLoop17: ; (ins 92.08.xx)
mov dx,StatusPort[si] ;Get ID reg I/O Address (ins 92.08.xx)
in al,dx ;Get Status (ins 92.08.xx)
test al,RX_RDY ; (ins 92.08.xx)
jz IntLoop20 ; (ins 92.08.xx)
jmp short DataAvail ;Receive Data (ins 92.08.xx)
else ; NEC_98
pop dx ;Get ID reg I/O address
in al,dx ;Get Interrupt Id
test al,1 ;Interrupt need servicing?
jnz IntLoop20 ;No, all done
IntLoop10:
and ax, 07h
mov di,ax
push dx ;Save Id register
jmp SrvTab[di] ;Service the Interrupt
endif ; NEC_98
IntLoop20:
mov ax,EvtMask[si] ;Mask the event word to only the
and ax, EvtWord[si] ; user specified bits
mov EvtWord[si], ax
pop bx
test [si.NotifyFlagsHI], CN_Notify
jz short ci_exit
not bx
and ax, bx ; bits set in ax are new events
jnz short ci_new_events
ci_exit:
pop es
assumes es,nothing
pop di
pop cx
pop bx
xor al, al
IntLoop30:
pop dx
and al, 1
dec al ; 0->-1, 1->0
IntLoop40:
ret
ci_new_events:
mov ax, CN_EVENT
call notify_owner
jmp ci_exit
CommInt endp
page
;----------------------------Private-Routine----------------------------;
;
; LineStat - Line Status Interrupt Handler
;
; Break detection is handled and set in the event word if
; enabled. Other errors (overrun, parity, framing) are
; saved for the data available interrupt.
;
; This routine used to fall into DataAvail for the bulk of its processing.
; This is no longer the case... A very popular internal modem seems to
; operate differently than a real 8250 when parity errors occur. Falling
; into the DataAvail handler on a parity error caused the same character
; to be received twice. Having this routine save the LSR status, and
; return to InterruptLoop fixes the problem, and still works on real COMM
; ports. The extra overhead isn't a big deal since this routine is only
; entered when there is an exception like a parity error.
;
; This routine is jumped to, and will perform a jump back into
; the dispatch loop.
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public LineStat ;Public for debugging
LineStat proc near
ifdef NEC_98
;=======================================================================[QN]|
; [QN]|
; Read Line Status [QN]|
; [QN]|
; <Entry> [QN]|
; none [QN]|
; [QN]|
; <Exit> [QN]|
; [AL]= Line Status [QN]|
; [QN]|
; <Modified> [QN]|
; AL Registor [QN]|
; [QN]|
; < Status Format > 8251 USART [QN]|
; Bit (7) (6) (5) (4) (3) (2) (1) (0) [QN]|
; none [bd] [fe] [oe] [pe] none none none ---------+ [QN]|
; I [QN]|
; < Status Format > 8250 USART MS-Windows format I [QN]|
; Bit (7) (6) (5) (4) (3) (2) (1) (0) I [QN]|
; none none none [bd] [fe] [pe] [oe] none <--------+ [QN]|
; [QN]|
;=======================================================================[QN]|
push dx ; [QN]|
push bx ; [QN]|
push ax ; [QN]|
mov dx,StatusPort[si] ; [QN]|
in al,dx ; [QN]|
and al,01111000b ; [QN]|
test al,00111000B ; Error ? [QN]|
jz LINE_SR_10 ; NO ! -> Reset Error [QN]|
push ax ; [QN]|
test al,01000000b ; [QN]|
jz LINE_SR_EV_Err ; [QN]|
or by EvtWord[si],EV_Break ;Show break [QN]|
LINE_SR_EV_Err: ; [QN]|
or by EvtWord[si],EV_Err ;Line Status Error [QN]|
; [QN]|
; AH AL BH [QN]|
mov al,CommandShadow[si] ;******** 0bfop000 ******** [QN]|
or al,ERR_RESET ;******** 0bf1p000 ******** [QN]|
out dx,al ; Reset ! [QN]|
pop ax ; [QN]|
LINE_SR_10: ;Adjust Bit Arrange to [QN]|
; MS-Windows Format (bit4-1) [QN]|
shr al,1 ;******** 00bf1p00 ******** [QN]|
shr al,1 ;******** 000bf1p0 ******** [QN]|
mov ah,al ;000bf1p0 000bf1p0 ******** [QN]|
mov bh,al ;000bf1p0 000bf1p0 000bf1p0 [QN]|
;Clear Bit 2,1 [QN]|
and al,11111001B ;000bf1p0 000bf1p0 000bf1p0 [QN]|
;Save (PE)Bit [QN]|
and ah,00000010B ;000000p0 000bf1p0 000bf1p0 [QN]|
;Save (OE)Bit [QN]|
and bh,00000100B ;000000p0 000bf1p0 00000100 [QN]|
shl ah,1 ;0000000p 000bf1p0 00000100 [QN]|
shr bh,1 ;0000000p 000bf1p0 00000010 [QN]|
;Reshuffle (PE) and (OE) bit [QN]|
or ah,bh ;0000001p 000bf1p0 00000010 [QN]|
;Save Bit 2,1 [QN]|
or al,ah ;0000001p 000bf11p 00000010 [QN]|
mov dl,al ; [QN]|
pop ax ; [QN]|
mov al,dl ; [QN]|
pop bx ; [QN]|
pop dx ; [QN]|
test al,ACE_PE+ACE_FE+ACE_OR ;Parity, Framing, Overrun error?
jz @f
mov LSRShadow[si],al ;yes, save status for DataAvail
@@:
ret ; qnes 92.10.06
else ; NEC_98
or by EvtWord[si],EV_Err ;Show line status error
add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
in al,dx
test al,ACE_PE+ACE_FE+ACE_OR ;Parity, Framing, Overrun error?
jz @f
mov LSRShadow[si],al ;yes, save status for DataAvail
@@:
test al,ACE_BI ;Break detect?
jz InterruptLoop_ChkTx ;Not break detect interrupt
or by EvtWord[si],EV_Break ;Show break
jmp short InterruptLoop_ChkTx
endif ; NEC_98
LineStat endp
page
;----------------------------Private-Routine----------------------------;
;
; DataAvail - Data Available Interrupt Handler
;
; The available character is read and stored in the input queue.
; If the queue has reached the point that a handshake is needed,
; one is issued (if enabled). EOF detection, Line Status errors,
; and lots of other stuff is checked.
;
; This routine is jumped to, and will perform a jump back into
; the dispatch loop.
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,BX,CX,DI,ES,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public DataAvail ;public for debugging
DataAvail proc near
ifdef NEC_98
;---------------------------------------------------------------;(ins 92.08.24)
; LineStat......Read Line Status ;(ins 92.08.24)
; return = AL (Line Status) ;(ins 92.08.24)
;---------------------------------------------------------------;(ins 92.08.24)
;(ins 92.08.24)
call LineStat ;Read 8251 Line Status ;(ins 92.08.24)
mov dx, DataPort[si] ;Store Read Data Port ;(ins 92.08.24)
in al, dx ;Receive Data ;(ins 92.08.24)
NEWIODELAY 14 ;<OUT 5F,AL> ;(ins 93.10.27)
else ; NEC_98
sub dl,ACE_IIDR-ACE_RBR ;--> receiver buffer register
in al,dx ;Read received character
endif ; NEC_98
and [si.NotifyFlagsHI], NOT CN_Idle ; flag as not idle
mov ah,LSRShadow[si] ;what did the last Line Status intrpt
mov bh,ah ; have to say?
or ah,ah
jz @f
and ah,ErrorMask[si] ;there was an error, record it
or by ComErr[si],ah
IFNDEF KKBUGFIX ; 1/05/93:TakuA:Fix #1666
mov LSRShadow[si],0
ENDIF
ifndef NEC_98
.errnz ACE_OR-CE_OVERRUN ;Must be the same bits
.errnz ACE_PE-CE_RXPARITY
.errnz ACE_FE-CE_FRAME
.errnz ACE_BI-CE_BREAK
endif ; NEC_98
@@:
; Regardless of the character received, flag the event in case
; the user wants to see it.
or by EvtWord[si],EV_RxChar ;Show a character received
.errnz HIGH EV_RxChar
; Check the input queue, and see if there is room for another
; character. If not, or if the end of file character has already
; been received, then go declare overflow.
DataAvail00:
IFDEF KKBUGFIX ; 1/05/93:TakuA:Fix #1666
mov bh,LSRShadow[si]
mov LSRShadow[si],0
ENDIF
mov cx,QInCount[si] ;Get queue count (used later too)
cmp cx,QInSize[si] ;Is queue full?
jge DataAvail20 ; Yes, comm overrun
test EFlags[si],fEOF ;Has end of file been received?
jnz DataAvail20 ; Yes - treat as overflow
; Test to see if there was a parity error, and replace
; the character with the parity character if so
test bh,ACE_PE ;Parity error
jz DataAvail25 ; No
test [si.DCB_Flags2],fPErrChar ;Parity error replacement character?
jz DataAvail25 ; No
mov al,[si.DCB_PEChar] ; Yes, get parity replacement char
; Skip all other processing except event checking and the queing
; of the parity error replacement character
jmp short DataAvail80 ;Skip all but event check, queing
DataAvail20:
or by ComErr[si],CE_RXOVER ;Show queue overrun
jmp short DataAvail50
; See if we need to strip null characters, and skip
; queueing if this is one. Also remove any parity bits.
DataAvail25:
and al,RxMask[si] ;Remove any parity bits
jnz DataAvail30 ;Not a Null character
test [si.DCB_Flags2],fNullStrip ;Are we stripping received nulls?
jnz DataAvail50 ; Yes, put char in the bit bucket
; Check to see if we need to check for EOF characters, and if so
; see if this character is it.
DataAvail30:
test [si.DCB_Flags],fBinary ;Is this binary stuff?
jnz DataAvail60 ; Yes, skip EOF check
cmp al,[si.DCB_EOFChar] ;Is this the EOF character?
jnz DataAvail60 ; No, see about queing the charcter
or EFlags[si],fEOF ;Set end of file flag
DataAvail50:
jmp DataAvail140 ;Skip the queing process
; If output XOn/XOff is enabled, see if the character just received
; is either an XOn or XOff character. If it is, then set or
; clear the XOffReceived flag as appropriate.
DataAvail60:
test [si.DCB_Flags2],fOutX ;Output handshaking?
jz DataAvail80 ; No
cmp al,[si.DCB_XoffChar] ;Is this an X-Off character?
jnz DataAvail70 ; No, see about XOn or Ack
or HSFlag[si],XOffReceived ;Show XOff received, ENQ or ETX [rkh]
test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
jz DataAvail50 ; No
cmp cx,[si.DCB_XonLim] ;See if at XOn limit
ja DataAvail50 ; No
and HSFlag[si],NOT XOffReceived ;Show ENQ or ETX not received
and HSFlag[si], NOT XOnPending+XOffSent
mov al, [si.DCB_XonChar]
call OutHandshakingChar
jmp DataAvail50 ;Done
DataAvail70:
cmp al,[si.DCB_XonChar] ;Is this an XOn character?
jnz DataAvail80 ; No, just a normal character
and HSFlag[si],NOT XOffReceived
test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
jz DataAvail75 ; No - jump to FakeXmitEmpty to get
; transmitting going again
and HSFlag[si],NOT EnqSent
DataAvail75:
jmp FakeXmitEmpty ;Restart transmit
; Now see if this is a character for which we need to set an event as
; having occured. If it is, then set the appropriate event flag
DataAvail80:
cmp al,[si.DCB_EVTChar] ;Is it the event generating character?
jne DataAvail90 ; No
or by EvtWord[si],EV_RxFlag ;Show received specific character
; Finally, a valid character that we want to keep, and we have
; room in the queue. Place the character in the queue.
; If the discard flag is set, then discard the character
DataAvail90:
test MiscFlags[si], Discard ;Discarding characters ?
jnz DataAvail50 ; Yes
lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
les di,QInAddr[si][bx] ;Get queue base pointer from either
assumes es,nothing ; QInAddr or AltQInAddr
mov bx,QInPut[si] ;Get index into queue
mov es:[bx][di],al ;Store the character
inc bx ;Update queue index
cmp bx,QInSize[si] ;See if time for wrap-around
jc DataAvail100 ;Not time to wrap
xor bx,bx ;Wrap-around is a new zero pointer
DataAvail100:
mov QInPut[si],bx ;Store updated pointer
inc cx ;And update queue population
mov QInCount[si],cx
; If flow control has been enabled, see if we are within the
; limit that requires us to halt the host's transmissions
cmp cx,XOffPoint[si] ;Time to see about XOff?
jc DataAvail120 ; Not yet
test HSFlag[si],HSSent ;Handshake already sent?
jnz DataAvail120 ; Yes, don't send it again
mov ah,HHSLines[si] ;Should hardware lines be dropped?
or ah,ah ; (i.e. do we have HW HS enabled?)
jz DataAvail110 ; No
ifdef NEC_98
mov al,CommandShadow[si] ;8251 Command get (ins 92.08.xx)
test ah,ACE_DTR ;DTR handshake Enable ? (ins 92.08.xx)
jz DataAvail101 ; No (ins 92.08.xx)
and al,not DTR ;Clear 8251's DTR Line ! (ins 92.08.xx)
DataAvail101: ; (ins 92.08.xx)
test ah,ACE_RTS ;RTS handshake Enable ? (ins 92.08.xx)
jz DataAvail102 ; No (ins 92.08.xx)
and al,not RTS ;Clear 8251's RTS Line ! (ins 92.08.xx)
DataAvail102: ; (ins 92.08.xx)
mov dx,CommandPort[si] ;GET Command port address (ins 92.08.xx)
out dx,al ; (ins 92.08.xx)
mov CommandShadow[si],al ;Get Back 8251 Command (ins 92.08.xx)
or HSFlag[si],HHSDropped ; and remember they were dropped(ins 92.08.xx)
else ; NEC_98
add dl,ACE_MCR ; Yes
in al,dx ;Clear the necessary bits
not ah
and al,ah
or HSFlag[si],HHSDropped ;Show lines have been dropped
out dx,al ; and drop the lines
sub dl,ACE_MCR
endif ; NEC_98
DataAvail110:
test [si.DCB_Flags2],fInX ;Input Xon/XOff handshaking
jz DataAvail120 ; No
or HSFlag[si], XOffSent
mov al, [si.DCB_XoffChar]
call OutHandshakingChar
DataAvail120:
cmp cx, [si.RecvTrigger] ;Q: time to call owner's callback?
jb short DataAvail130 ; N:
test [si.NotifyFlagsHI], CN_RECEIVE
jnz short DataAvail140 ; jump if notify already sent and
; data in buffer hasn't dropped
; below threshold
mov ax, IntCodeOFFSET DataAvail140
push ax
mov ax, CN_RECEIVE
%OUT probably should just set a flag and notify after EOI
jmp notify_owner
DataAvail130:
and [si.NotifyFlagsHI], NOT CN_RECEIVE
DataAvail140:
ifdef NEC_98
mov dx,StatusPort[si] ; [QN][BA] (ins 93.03.23)
in al,dx ; [QN][BA] (ins 93.03.23)
test al,01000000b ; [QN][BA] (ins 93.03.23)
jz @f ; [QN][BA] (ins 93.03.23)
or by EvtWord[si],EV_Break ; [QN][BA] (ins 93.03.23)
@@: ; [QN][BA] (ins 93.03.23)
test [si.DCB_Flags],fBinary ;Is this binary stuff? <add 92.10.13>|
jnz DataAvail140_Binary ; Yes <add 93.03.23>|
mov dx,StatusPort[si] ;Get ID reg I/O Address (ins 92.08.xx)
in al,dx ;Get Interrupt Id (ins 92.08.xx)
test al,RX_RDY ;Is this RX_ready ? (ins 92.08.xx)
jz @F ; No (ins 92.08.xx)
mov dx, DataPort[si] ;Store Read Data Port (ins 92.08.xx)
in al, dx ;Receive Data (ins 92.08.xx)
NEWIODELAY 14 ;<OUT 5F,AL> (ins 93.10.27)
jmp DataAvail00
@@:
jmp InterruptLoop ;;;92.10.05
DataAvail140_Binary: ;Receive Binary <add 92.10.13>|
push cx ; <add 92.10.13>|
mov cx, [RECLoopCounter] ; [QN][BA](ins 93.03.30)
RetryReadData2: ; <add 92.10.13>|
mov dx,StatusPort[si] ;Get ID reg I/O address <add 92.10.13>|
in al,dx ;Get Interrupt Id <add 92.10.13>|
test al,RX_RDY ;Is this RX_ready ? <add 92.10.13>|
jz @F ; No <add 92.10.13>|
pop cx ; <add 92.10.13>|
mov dx, DataPort[si] ; Store Read Data Port <add 92.10.13>|
in al, dx ;Receive Data <add 92.10.13>|
NEWIODELAY 14 ;<OUT 5F,AL> (ins 93.10.27)
jmp DataAvail00 ; <add 92.10.13>|
@@: ; <add 92.10.13>|
loop RetryReadData2 ; <add 92.10.13>|
pop cx ; <add 92.10.13>|
jmp InterruptLoop ; <add 92.10.13>|
else ; NEC_98
pop dx
push dx
add dl, ACE_LSR-ACE_IIDR
in al, dx
test al, ACE_DR ;Q: more data available?
jz @F ; N:
sub dl, ACE_LSR ; Y: go read it
in al, dx ;Read available character
jmp DataAvail00
@@:
jmp InterruptLoop_ChkTx
endif ; NEC_98
DataAvail endp
OutHandshakingChar proc near
ifdef NEC_98
mov dx,StatusPort[si] ;Get ID reg I/O Address (ins 92.08.xx)|
mov ah, al ; (ins 92.08.xx)|
@@: ; (ins 92.08.xx)|
in al, dx ; (ins 92.08.xx)|
test al,(TX_RDY+TX_EMP) ;Is this TX_empty ? (ins 92.08.xx)|
jz @B ; (ins 92.08.xx)|
mov dx,DataPort[si] ; (ins 92.09.24)|
else ; NEC_98
add dl, ACE_LSR
mov ah, al
@@:
in al, dx
test al, ACE_THRE
jz @B
sub dl, ACE_LSR
endif ; NEC_98
mov al, ah
out dx, al
ret
OutHandshakingChar endp
page
;----------------------------Private-Routine----------------------------;
;
; XmitEmpty - Transmitter Register Empty
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,BX,CX,DI,ES,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public FakeXmitEmpty
FakeXmitEmpty:
pop dx
push dx
; "Kick" the transmitter interrupt routine into operation.
ifdef NEC_98
call KickTxINT ; (ins 92.09.xx)
mov dx,StatusPort[si] ;Get Status Port (ins 92.08.xx)
mov ah, al ; (ins 92.08.xx)
in al, dx ; (ins 92.08.xx)
test al,(TX_RDY+TX_EMP) ;Is this TX_ready ? (ins 92.08.xx)
else ; NEC_98
dec dl
.errnz ACE_IIDR - ACE_IER-1
in al,dx ;Get current IER state
test al,ACE_ETBEI ;Interrupt already enabled?
jnz @F ; Yes, don't reenable it
or al,ACE_ETBEI ; No, enable it
out dx,al
iodelay ;8250, 8250-B bug requires
out dx,al ; writting register twice
@@:
add dl,ACE_LSR-ACE_IER ;--> Line Status Register
iodelay
in al,dx ;Is xmit really empty?
sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
test al,ACE_THRE
endif ; NEC_98
jnz short XmitEmpty5 ; Y: send next char
jmp InterruptLoop ; N: return to processing loop
public XmitEmpty
XmitEmpty proc near
ifdef NEC_98
call MSR_READ ; (ins 92.09.xx)
mov dx,StatusPort[si] ;Get ID reg I/O Address (ins 92.08.xx)
in al, dx ; (ins 92.08.xx)
test al,(TX_EMP+TX_RDY) ;Is this TX_empty ? (ins 92.08.xx)
else ; NEC_98
add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
in al,dx ;Is xmit really empty?
sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
test al,ACE_THRE
endif ; NEC_98
jz Xmit_jumpto90 ;Transmitter not empty, cannot send
; If the hardware handshake lines are down, then XOff/XOn cannot
; be sent. If they are up and XOff/XOn has been received, still
; allow us to transmit an XOff/XOn character. It will make
; a dead lock situation less possible (even though there are
; some which could happen that cannot be handled).
XmitEmpty5:
mov ah,HSFlag[si] ;Get handshaking flag
test ah,HHSDown+BreakSet ;Hardware lines down or break set?
jnz Xmit_jumpto100 ; Yes, cannot transmit
; Give priority to any handshake character waiting to be
; sent. If there are none, then check to see if there is
; an "immediate" character to be sent. If not, try the queue.
XmitEmpty10:
test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
jnz XmitEmpty40 ; Yes
XmitEmpty15:
test ah,HSPending ;XOff or XOn pending
jz XmitEmpty40 ; No
XmitEmpty20:
and ah,NOT XOnPending+XOffSent
mov al,[si.DCB_XonChar] ;Get XOn character
XmitEmpty30:
mov HSFlag[si],ah ;Save updated handshake flag
ifdef NEC_98
mov dx,DataPort[si] ;(ins 92.09.24)
endif ; NEC_98
jmp XmitEmpty110 ;Go output the character
Xmit_jumpto90:
jmp XmitEmpty90
; If any of the lines which were specified for a timeout are low, then
; don't send any characters. Note that by putting the check here,
; XOff and Xon can still be sent even though the lines might be low.
; Also test to see if a software handshake was received. If so,
; then transmission cannot continue. By delaying the software check
; to here, XOn/XOff can still be issued even though the host told
; us to stop transmission.
XmitEmpty40:
test ah,CannotXmit ;Anything preventing transmission?
jz XmitEmpty45 ; No
Xmit_jumpto100:
jmp XmitEmpty100 ; Yes, disarm and exit
; If a character has been placed in the single character "transmit
; immediately" buffer, clear that flag and pick up that character
; without affecting the transmitt queue.
XmitEmpty45:
test EFlags[si],fTxImmed ;Character to xmit immediately?
jz XmitEmpty515 ; No, try the queue
and EFlags[si],NOT fTxImmed ;Clear xmit immediate flag
mov al,ImmedChar[si] ;Get char to xmit
ifdef NEC_98
mov dx,DataPort[si] ;(ins 92.09.xx)
endif ; NEC_98
jmp XmitEmpty110 ;Transmit the character
XmitEmpty515:
mov cx,QOutCount[si] ;Output queue empty?
jcxz Xmit_jumpto90 ; Yes, go set an event
test [si.DCB_Flags],fEtxAck ;Etx Ack?
jz XmitEmpty55 ; No
mov cx,QOutMod[si] ;Get number bytes sent since last ETX
cmp cx,[si.DCB_XonLim] ;At Etx limit yet?
jne XmitEmpty51 ; No, inc counter
mov QOutMod[si],0 ; Yes, zero counter
or HSFlag[si],EtxSent ;Show ETX sent
jmp short XE_sendXOFF
XmitEmpty51:
inc cx ; Update counter
mov QOutMod[si],cx ; Save counter
jmp short XmitEmpty59 ; Send queue character
XmitEmpty55:
test [si.DCB_Flags],fEnqAck ;Enq Ack?
jz XmitEmpty59 ; No, send queue character
mov cx,QOutMod[si] ;Get number bytes sent since last ENQ
or cx,cx ;At the front again?
jnz XmitEmpty56 ; No, inc counter
mov QOutMod[si],1 ; Yes, send ENQ
or HSFlag[si],EnqSent ;Show ENQ sent
XE_sendXOFF:
mov al,[si.DCB_XoffChar]
ifdef NEC_98
mov dx,DataPort[si] ;(ins 92.09.24)
endif ; NEC_98
jmp short XmitEmpty110 ;Go output the character
XmitEmpty56:
inc cx ;Update counter
cmp cx,[si.DCB_XonLim] ;At end of our out buffer len?
jne XmitEmpty58 ; No
xor cx,cx ;Show at front again.
XmitEmpty58:
mov QOutMod[si],cx ;Save counter
XmitEmpty59:
lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
les di,QOutAddr[si][bx] ;Get queue base pointer from either
assumes es,nothing ; QOutAddr or AltQOutAddr
mov bx,QOutGet[si] ;Get pointer into queue
mov al,es:[bx][di] ;Get the character
inc bx ;Update queue pointer
cmp bx,QOutSize[si] ;See if time for wrap-around
jc XmitEmpty60 ;Not time for wrap
xor bx,bx ;Wrap by zeroing the index
XmitEmpty60:
mov QOutGet[si],bx ;Save queue index
mov cx,QOutCount[si] ;Output queue empty?
dec cx ;Dec # of bytes in queue
mov QOutCount[si],cx ; and save new population
ifdef NEC_98
mov dx,DataPort[si] ; (ins 92.08.xx)
endif ; NEC_98
out dx,al ;Send char
cmp cx, [si.SendTrigger] ;Q: time to call owner's callback?
jae short XmitEmpty70 ; N:
test [si.NotifyFlagsHI], CN_TRANSMIT
jnz short XmitEmpty80 ; jump if notify already sent and
; data in buffer hasn't raised
; above threshold
mov ax, IntCodeOFFSET XmitEmpty80
push ax
mov ax, CN_TRANSMIT
ifdef NEC_98
jmp notify_owner
else ; NEC_98
jmp short notify_owner
endif ; NEC_98
XmitEmpty70:
and [si.NotifyFlagsHI], NOT CN_TRANSMIT
XmitEmpty80:
%OUT check fNoFIFO in EFlags[si] to determine if we can queue more output
ifdef NEC_98
jmp IntLoop17 ;92.10.03
else ; NEC_98
jmp InterruptLoop
endif ; NEC_98
; No more characters to transmit. Flag this as an event.
XmitEmpty90:
or by EvtWord[si],EV_TxEmpty
; Cannot continue transmitting (for any of a number of reasons).
; Disable the transmit interrupt. When it's time resume, the
; transmit interrupt will be reenabled, which will generate an
; interrupt.
XmitEmpty100:
ifdef NEC_98
cmp [si.DCB_id],ID_Com1 ;Is This Com1 ID ? (ins 92.08.xx)|
jne XmitEmpty102 ;No, go to KickTx5 (ins 92.08.xx)|
mov dx,MaskFFPort[si] ;F/F Port Mask Bit (ins 92.08.xx)|
in al,dx ; (ins 92.08.xx)|
mov MaskFFShadow[si],al ;Save the Old Mask bit (ins 92.08.xx)|
; (ins 92.08.xx)|
XmitEmpty102: ; (ins 92.08.xx)|
mov al,MaskFFShadow[si] ;mask data(port C) save (ins 92.08.xx)|
test al,MSK_TXR ;Check a tx.RDY INT mask(ins 93.06.18)|
jz XmitEmpty105 ; disable (ins 92.08.xx)|
and al,NOT(MSK_TXE+MSK_TXR) ;= 11111001b (ins 92.08.xx)|
mov dx,MaskFFPort[si] ;Port address (Port C) (ins 92.08.xx)|
mov MaskFFShadow[si],al ;Masking data save (ins 92.08.xx)|
XmitEmpty110: ; (ins 92.08.xx)|
out dx,al ;Masking set (ins 92.08.xx)|
XmitEmpty105: ; (ins 92.08.xx)|
jmp IntLoop17 ; (ins 92.09.xx)|
else ; NEC_98
inc dx ;--> Interrupt Enable Register
.errnz ACE_IER-ACE_THR-1
in al,dx ;I don't know why it has to be read
and al,NOT ACE_ETBEI ; first, but it works this way
XmitEmpty110:
out dx,al
jmp InterruptLoop
endif ; NEC_98
XmitEmpty endp
page
;----------------------------Private-Routine----------------------------;
;
; ModemStatus - Modem Status Interrupt Handler
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,BX,CX,DI,ES,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public ModemStatus ;Public for debugging
ModemStatus proc near
; Get the modem status value and shadow it for MSRWait.
ifdef NEC_98
push ax ; [QN]|
push cx ; [QN]|
mov ch,al ;Save a local copy [QN]|
; [QN]|
; [Modem Status format (in AL and CH)] : [Assign of Event Word] [QN]|
; +------------- DRLSD : EV_RLSD = 0000|0000 0010|0000b |
; | +---------- TERI : EV_Ring = 0000|0001 0000|0000b |
; | | +------- DDSR : EV_DSR = 0000|0000 0001|0000b |
; | | | +---- DCTS : EV_CTS = 0000|0000 0000|1000b |
; (*)(*)(*)(*)|(R)(E)(D)(C) : [QN]|
; <ah> <al> <cl> [QN]|
mov ah,al ; ****|REDC ****|REDC ****|**** [QN]|
shr ax,1 ; 0***|*RED C***|*RED ****|**** [QN]|
shr ax,1 ; 00**|**RE DC**|**RE ****|**** [QN]|
ror al,1 ; 000*|**RE EDC*|***R ****|**** [QN]|
ror al,1 ; 000*|**RE REDC|**** ****|**** [QN]|
ror al,1 ; 000*|**RE *RED|C*** ****|**** [QN]|
mov cl,al ; *RED|C*** [QN]|
and ax, 0118h ; 0000|000E 000D|C000 [QN]|
and cl, 40h ; 0R00|0000 [QN]|
shr cl, 1 ; 00R0|0000 [QN]|
or al, cl ; 0000|000E 00RD|C000 [QN]|
; [QN]|
and ax,EV_CTS+EV_DSR+EV_RLSD+EV_Ring ; [QN]|
; 0000|000E 00RD|C000 [QN]|
or EvtWord[si],ax ; [QN]|
; [QN]|
; [Modem Status format (in CH)] : [Assign of Event Word] [QN]|
; +------------------------- RLSD : EV_RLSDS = 0001|0000 0000|0000b |
; | +---------------------- RI : EV_RingTe = 0010|0000 0000|0000b |
; | | +------------------- DSR : EV_DSRS = 0000|1000 0000|0000b |
; | | | +---------------- CTS : EV_CTSS = 0000|0100 0000|0000b |
; (R)(I)(D)(C)|(*)(*)(*)(*) [QN]|
; ; <ah> <al> <cl> [QN]|
mov ah,ch ; RIDC|**** ****|**** RIDC|**** [QN]|
shr ah,1 ; 0RID|C*** ****|**** RIDC|**** [QN]|
shr ah,1 ; 00RI|DC** ****|**** RIDC|**** [QN]|
and ax,EV_CTSS+EV_DSRS ; 0000|DC00 0000|0000 RIDC|**** [QN]|
or EvtWord[si],ax ; [QN]|
; [QN]|
mov ah,ch ; RIDC|**** ****|**** RIDC|**** [QN]|
mov cl,3 ; [QN]|
shr ah,cl ; 000R|IDC* ****|**** RIDC|**** [QN]|
and ax,EV_RLSDS ; 000R|0000 0000|0000 RIDC|**** [QN]|
or EvtWord[si],ax ; [QN]|
; [QN]|
mov ah,ch ; RIDC|**** ****|**** RIDC|**** [QN]|
shr ah, 1 ; 0RID|C*** ****|**** RIDC|**** [QN]|
and ax,EV_RingTe ; 00I0|0000 0000|0000 RIDC|**** [QN]|
or EvtWord[si],ax ; [QN]|
; [QN]|
ModemStatus10: ; [QN]|
mov al,OutHHSLines[si] ; [QN]|
or al,al ; [QN]|
jz ModemStatus30 ;No H/W handshake on output [QN]|
and ch,al ; [QN]|
cmp ch,al ;Lines set for Xmit? [QN]|
je ModemStatus20 ; Yes [QN]|
or HSFlag[si],HHSDown ;Show H/W lines have dropped [QN]|
jmp short ModemStatus30 ; [QN]|
; [QN]|
ModemStatus20: ; [QN]|
and HSFlag[si],NOT HHSDown ; [QN]|
call KickTxINT ; (ins 92.09.xx) [QN]|
; [QN]|
ModemStatus30: ; [QN]|
mov ax,EvtMask[si] ;Mask event signal [QN]|
and EvtWord[si],ax ; that user need [QN]|
; [QN]|
pop cx ; [QN]|
pop ax ; [QN]|
ret ; (ins 92.09.xx) [QN]|
else ; NEC_98
add dl,ACE_MSR-ACE_IIDR ;--> Modem Status Register
in al,dx
mov MSRShadow[si],al ;Save MSR data for others
mov ch,al ;Save a local copy
; Create the event mask for the delta signals
mov ah,al ;Just a lot of shifting
shr ax,1
shr ax,1
shr ah,1
mov cl,3
shr ax,cl
and ax,EV_CTS+EV_DSR+EV_RLSD+EV_Ring
or EvtWord[si],ax
mov ah,ch ;[rkh]...
shr ah,1
shr ah,1
and ax,EV_CTSS+EV_DSRS
or EvtWord[si],ax
mov ah,ch
mov cl,3
shr ah,cl
and ax,EV_RLSD
or EvtWord[si],ax
mov ah,ch
mov cl,3
shl ah,cl
and ax,EV_RingTe
or EvtWord[si],ax
.errnz EV_CTS-0000000000001000b
.errnz EV_DSR-0000000000010000b
.errnz EV_RLSD-0000000000100000b
.errnz EV_Ring-0000000100000000b
.errnz EV_CTSS-0000010000000000b ;[rkh]
.errnz EV_DSRS-0000100000000000b
.errnz EV_RLSDS-0001000000000000b
.errnz EV_RingTe-0010000000000000b
.errnz ACE_DCTS-00000001b
.errnz ACE_DDSR-00000010b
.errnz ACE_DRLSD-00001000b
.errnz ACE_RI-01000000b
.errnz ACE_TERI-00000100b ;[rkh]
.errnz ACE_CTS-00010000b
.errnz ACE_DSR-00100000b
.errnz ACE_RLSD-10000000b
ModemStatus10:
mov al,OutHHSLines[si] ;Get output hardware handshake lines
or al,al ;Any lines that must be set?
jz ModemStatus40 ;No hardware handshake on output
and ch,al ;Mask bits of interest
cmp ch,al ;Lines set for Xmit?
je ModemStatus20 ; Yes
or HSFlag[si],HHSDown ;Show hardware lines have dropped
ModemStatus30:
jmp InterruptLoop
ModemStatus40:
jmp InterruptLoop_ChkTx
; Lines are set for xmit. Kick an xmit interrupt if needed
ModemStatus20:
and HSFlag[si],NOT (HHSDown OR HHSAlwaysDown)
;Show hardware lines back up
mov cx,QOutCount[si] ;Output queue empty?
jcxz ModemStatus30 ; Yes, return to InterruptLoop
jmp FakeXmitEmpty ;Restart transmit
endif ; NEC_98
ModemStatus endp
page
;------------------------------------------------------------------------------
;
; ENTER: AX = message #
; DS:SI -> DEB
notify_owner proc near
or [si.NotifyFlags], ax
lea di, [si+SIZE ComDEB]
mov ax, ds
mov es, ax
mov ax, BIH_API_Call_Back ; call immediate, or in protected mode
mov bx, 1 ; force SYS VM, if enhanced mode
mov cx, _INTERRUPT
mov dx, IntCodeOFFSET callback_event
%OUT use equate
push ds
push si
mov si, 1 ; low priority boost
push bp
mov bp, es:[di.BIS_Mode]
call es:[bp][di.BIS_User_Mode_API]
pop bp
pop si
pop ds
ret
notify_owner endp
;------------------------------------------------------------------------------
;
; ENTER: ES:DI -> BIS
;
callback_event proc far
lea si, [di-SIZE ComDEB]
mov ax, es
mov ds, ax
ifdef NEC_98
mov al, [si.NotifyFlagsLO] ;ins 94.12.02 KBNES
and al, al ;ins 94.12.02 KBNES
jnz @f ;ins 94.12.02 KBNES
ret ;ins 94.12.02 KBNES
@@: ;ins 94.12.02 KBNES
endif ; NEC_98
mov ax, [si.NotifyHandle]
push ax ; push hWnd
mov ax, WM_COMMNOTIFY
push ax ; push wMsg
xor ax, ax
mov al, [si.DCB_Id]
push ax ; push wParam = ComID
xor al, al
push ax ; push high word of lParam
xchg al, [si.NotifyFlagsLO]
or [si.NotifyFlagsHI], al
push ax ; push low word of lParam = event flags
call [lpPostMessage]
ret
callback_event endp
PUBLIC TimerProc
TimerProc proc far
push ds
mov ax, _DATA
mov ds, ax
assumes ds,data
mov ax, [activeCOMs]
or ax, ax
jz short tp_nonactive
push si
mov si, DataOFFSET COMptrs
mov cx, MAXCOM+1
tp_lp:
push si
mov si, [si] ; si -> ComDEB
shr ax, 1
jnc tp_lpend
cmp [si.RecvTrigger], -1 ;Q: owner wants notification?
je short tp_lpend ; N: skip notify
cmp [si.QInCount], 0 ;Q: anything in input queue?
je short tp_lpend ; N: skip notify
test [si.NotifyFlagsHI], CN_RECEIVE ;Q: timeout notify already given?
jnz short tp_lpend ; N: skip notify
xor [si.NotifyFlagsHI], CN_Idle ;Q: first timer call?
js short tp_lpend ; Y: skip notify
push ax
push cx
mov ax, CN_RECEIVE ; N: notify owner
call notify_owner
pop cx
pop ax
tp_lpend:
pop si
inc si ; inc to ptr to next ComDEB
inc si
or ax, ax
loopnz tp_lp
pop si
tp_nonactive:
pop ds
assumes ds,nothing
ret
TimerProc endp
page
ifdef NEC_98
;===========================================================================
; System Timer Interrupt Routine
;
; if ( QOutCount[si] != 0x0000 )
; {
; KickTx ();
; }
;===========================================================================
public TickEntry1 ;(ins 92.09.25)
public TickEntry2 ;(ins 92.09.25)
public TickEntry3 ;(ins 92.09.25)
TickEntry1 proc far ;for COM1
push si ;
push ds ;
push ax ;
mov si,dataOFFSET Comm1 ;
mov ax, _DATA ;
mov ds, ax
jmp short TickWork ;
;
TickEntry2: ;for COM2
push si ;
push ds ;
push ax ;
mov si,dataOFFSET Comm2 ;
mov ax, _DATA ;
mov ds, ax
jmp short TickWork ;
;
TickEntry3: ;for COM3
push si ;
push ds ;
push ax ;
mov si,dataOFFSET Comm3 ;
mov ax, _DATA ;
mov ds, ax
;
public TickWork ;
TickWork: ;
cmp QOutCount[si],wo 00h ;Does queue empty ?
jz TickNoWork ; Yes : Goto Return
push dx ;
call KickTxINT ;
pop dx ;
TickNoWork: ;
pop ax ;
pop ds ;
pop si ;
ret ;
;(ins end 92.09.25)
TickEntry1 endp
page
;----------------------------Private-Routine----------------------------
; MSR Read
;-----------------------------------------------------------------------
public MSR_READ_Call ;(ins 92.08.xx)
MSR_READ_Call proc far ;(ins 92.08.xx)
call MSR_READ ;(ins 92.08.xx)
ret ;(ins 92.08.xx)
MSR_READ_Call endp ;(ins 92.08.xx)
MSR_READ PROC NEAR
push cx ;
push ax ;
mov dx,StatusPort[si] ; 8251 Status Port ( DSR )
in al,dx ; Read Status
mov ch,al ; save to CH
mov dx,ReadSigPort[si] ; MODEM Status Port (CS,CD,CI)
in al,dx ; Read Status
;---------------------------------
; CD='a' CI='b' DR='c' CS='d'
; a,b,c,d = ( 0 or 1 )
mov ah,al ; [AH] I [AL] I [CH]
xor al,al ; bda????? 00000000 c???????
and ch,10000000b ; bda????? 00000000 c0000000
and ah,11100000b ; bda00000 00000000 c0000000
rol ah,1 ; da00000b 00000000 c0000000
rol ah,1 ; a00000bd 00000000 c0000000
shr ax,1 ; 0a00000b d0000000 c0000000
shr al,1 ; 0a00000b 0d000000 c0000000
or al,ch ; 0a00000b cd000000 c0000000
shr ax,1 ; 00a00000 bcd00000 c0000000
rol ah,1 ; 0a000000 bcd00000 c0000000
rol ah,1 ; a0000000 bcd00000 c0000000
rol ah,1 ; 0000000a bcd00000 c0000000
shr ax,1 ; 00000000 abcd0000 c0000000
;
mov cl,al ; restore AL
pop ax ;
xor cl,11010000b ; Bit invert
mov ch,cl ; (CD,CS,CI is active Low )
and cl,0f0h ;
xor MSRShadow[si],cl ;
shr by MSRShadow[si],1 ;
shr by MSRShadow[si],1 ;
shr by MSRShadow[si],1 ;
shr by MSRShadow[si],1 ;
or MSRShadow[si],ch ;
mov al,MSRShadow[si] ;
pop cx ;
call ModemStatus ;Set Event Flag
ret
MSR_READ ENDP
;------------------------------------------------------------------------------
; AOBA-bug ins 94.11.19 KBNES
;------------------------------------------------------------------------------
public AOBA_MSR_READ_Call
AOBA_MSR_READ_Call proc far
call AOBA_MSR_READ
ret
AOBA_MSR_READ_Call endp
AOBA_MSR_READ PROC NEAR
push ax
push dx
mov dx,Port[si] ;Get comm I/O port
add dl,ACE_MSR ;
in al,dx
mov MSRShadow[si],al ;Save MSR data for others
call ModemStatus ;Set Event Flag
pop dx ;
pop ax ;
ret
AOBA_MSR_READ ENDP
;------------------------------------------------------------------------------
; AOBA-bug ins end 94.11.19 KBNES
;------------------------------------------------------------------------------
;----------------------------Private-Routine----------------------------;
;
; KickTxINT - 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:
;-----------------------------------------------------------------------;
assumes ds,Data
assumes es,nothing
public KickTxINT ;Public for debugging
KickTxINT proc near
cmp [si.DCB_id],ID_Com1 ;Is This Com1 ID ? (ins 92.08.xx)
jne KickTxINT5 ;No, go to KickTx5 (ins 92.08.xx)
mov dx,MaskFFPort[si] ;F/F Port Mask Bit (ins 92.08.xx)
in al,dx ; (ins 92.08.xx)
mov MaskFFShadow[si],al ;Save the Old Mask bit (ins 92.08.xx)
; (ins 92.08.xx)
KickTxINT5: ; (ins 92.08.xx)
mov al,MaskFFShadow[si] ;mask data(port C) save (ins 92.08.xx)
test al,MSK_TXR ;(ins 93.06.18)
jnz KickTxINT10 ; Enable (ins 92.08.xx)
KickTxINT9:
or al,MSK_TXR+MSK_RXR ; (ins 93.06.18)
mov dx,MaskFFPort[si] ;Port address (Port C) (ins 92.08.xx)
mov MaskFFShadow[si],al ;Masking data save (ins 92.08.xx)
out dx,al ;Masking set (ins 92.08.xx)
ret ; (ins 92.08.xx)
KickTxINT10: ; (ins 92.08.xx)|
and al,NOT(MSK_TXR+MSK_RXR) ; (ins 93.06.18)
mov dx,MaskFFPort[si] ;Port address (Port C) (ins 93.03.22)
out dx,al ;Masking set (ins 93.03.22)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 93.03.22)
jmp short KickTxINT9 ; (ins 93.03.22)
; (ins 93.03.22)
KickTxINT endp
;--------------------------Interrupt Handler----------------------------
;
; AOBA_CommInt - Interrupt handler for com ports
;
; Interrupt handlers for PC com ports. This is the communications
; interrupt service routine for RS232 communications. When an RS232
; event occurs the interrupt vectors here. This routine determines
; who the caller was and services the appropriate interrupt. The
; interrupts are prioritized in the following order:
;
; 1. line status interrupt
; 2. read data available interrupt
; 3. transmit buffer empty interrupt
; 4. modem service interrupt
;
; This routine continues to service until all interrupts have been
; satisfied.
;
; Entry:
; DS:SI --> DEB
; INTERRUPTS DISABLED!
; Returns:
; AL = 0, if not handled, -1, if handled
;
;-----------------------------------------------------------------------
assumes ds,Data
assumes es,nothing
; Dispatch table for interrupt types
SrvTab label word
dw OFFSET AOBA_ModemStatus ;[0] Modem Status Interrupt
dw OFFSET AOBA_XmitEmpty ;[2] Tx Holding Reg. Interrupt
dw OFFSET AOBA_DataAvail ;[4] Rx Data Available Interrupt
; or [C] if 16550 & 16550A
dw OFFSET AOBA_LineStat ;[6] Reciever Line Status Interrupt
public AOBA_CommInt
AOBA_CommInt proc near
xor al, al
cmp word ptr [VCD_int_callback+4], 0
je short @F ; jump if no callback (not 3.1 VCD)
test [si.VCDflags], fCOM_ignore_ints ;Q: we still own port?
jnz AOBA_IntLoop40 ; N: ignore the int
.386
push esi
mov esi, [si.VCD_data]
call [VCD_int_callback]
pop esi
.8086
@@:
push dx
mov dx,Port[si] ;Get comm I/O port
add dl,ACE_IIDR ;--> Interrupt ID Register
in al, dx
test al, 1 ;Q: interrupt pending?
jnz short AOBA_IntLoop30 ; N:
push bx
push cx
push di
push es
mov cx, EvtWord[si]
push cx
jmp short AOBA_IntLoop10
public AOBA_InterruptLoop_ChkTx
AOBA_InterruptLoop_ChkTx:
cmp QOutCount[si],0 ;Output queue empty?
je short AOBA_InterruptLoop ; Y: don't chk tx
call KickTxINT ; (ins 94.04.16)
public AOBA_InterruptLoop
AOBA_InterruptLoop:
pop dx ;Get ID reg I/O address
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_IIDR ;--> Interrupt ID Register (ins 94.04.16)
in al,dx ;Get Interrupt Id
test al,1 ;Interrupt need servicing?
jnz AOBA_IntLoop20 ;No, all done
public AOBA_IntLoop10
AOBA_IntLoop10:
and ax, 07h
mov di,ax
push dx ;Save Id register
jmp SrvTab[di] ;Service the Interrupt
public AOBA_IntLoop20
AOBA_IntLoop20:
mov ax,EvtMask[si] ;Mask the event word to only the
and ax, EvtWord[si] ; user specified bits
mov EvtWord[si], ax
pop bx
test [si.NotifyFlagsHI], CN_Notify
jz short AOBA_ci_exit
not bx
and ax, bx ; bits set in ax are new events
jnz short AOBA_ci_new_events
public AOBA_ci_exit
AOBA_ci_exit:
pop es
assumes es,nothing
pop di
pop cx
pop bx
xor al, al
public AOBA_IntLoop30
AOBA_IntLoop30:
pop dx
and al, 1
dec al ; 0->-1, 1->0
public AOBA_IntLoop40
AOBA_IntLoop40:
ret
public AOBA_ci_new_events
AOBA_ci_new_events:
mov ax, CN_EVENT
call notify_owner
jmp AOBA_ci_exit
public AOBA_CommInt
AOBA_CommInt endp
page
;----------------------------Private-Routine----------------------------;
;
; AOBA_LineStat - Line Status Interrupt Handler
;
; Break detection is handled and set in the event word if
; enabled. Other errors (overrun, parity, framing) are
; saved for the data available interrupt.
;
; This routine used to fall into DataAvail for the bulk of its processing.
; This is no longer the case... A very popular internal modem seems to
; operate differently than a real 8250 when parity errors occur. Falling
; into the DataAvail handler on a parity error caused the same character
; to be received twice. Having this routine save the LSR status, and
; return to InterruptLoop fixes the problem, and still works on real COMM
; ports. The extra overhead isn't a big deal since this routine is only
; entered when there is an exception like a parity error.
;
; This routine is jumped to, and will perform a jump back into
; the dispatch loop.
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public AOBA_LineStat ;Public for debugging
AOBA_LineStat proc near
or by EvtWord[si],EV_Err ;Show line status error
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_LSR ;--> Line Status Register (ins 94.04.16)
in al,dx
test al,ACE_PE+ACE_FE+ACE_OR ;Parity, Framing, Overrun error?
jz @f
mov LSRShadow[si],al ;yes, save status for DataAvail
@@:
test al,ACE_BI ;Break detect?
jz AOBA_InterruptLoop_ChkTx ;Not break detect interrupt
or by EvtWord[si],EV_Break ;Show break
jmp short AOBA_InterruptLoop_ChkTx
AOBA_LineStat endp
page
;----------------------------Private-Routine----------------------------;
;
; AOBA_DataAvail - Data Available Interrupt Handler
;
; The available character is read and stored in the input queue.
; If the queue has reached the point that a handshake is needed,
; one is issued (if enabled). EOF detection, Line Status errors,
; and lots of other stuff is checked.
;
; This routine is jumped to, and will perform a jump back into
; the dispatch loop.
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,BX,CX,DI,ES,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public AOBA_DataAvail ;public for debugging
AOBA_DataAvail proc near
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_RBR ;--> receiver buffer register (ins 94.04.16)
in al,dx ;Read received character
and [si.NotifyFlagsHI], NOT CN_Idle ; flag as not idle
mov ah,LSRShadow[si] ;what did the last Line Status intrpt
mov bh,ah ; have to say?
or ah,ah
jz @f
and ah,ErrorMask[si] ;there was an error, record it
or by ComErr[si],ah
IFNDEF KKBUGFIX ; 1/05/93:TakuA:Fix #1666
mov LSRShadow[si],0
ENDIF
@@:
; Regardless of the character received, flag the event in case
; the user wants to see it.
or by EvtWord[si],EV_RxChar ;Show a character received
.errnz HIGH EV_RxChar
; Check the input queue, and see if there is room for another
; character. If not, or if the end of file character has already
; been received, then go declare overflow.
public AOBA_DataAvail00
AOBA_DataAvail00:
IFDEF KKBUGFIX ; 1/05/93:TakuA:Fix #1666
mov bh,LSRShadow[si]
mov LSRShadow[si],0
ENDIF
mov cx,QInCount[si] ;Get queue count (used later too)
cmp cx,QInSize[si] ;Is queue full?
jge AOBA_DataAvail20 ; Yes, comm overrun
test EFlags[si],fEOF ;Has end of file been received?
jnz AOBA_DataAvail20 ; Yes - treat as overflow
; Test to see if there was a parity error, and replace
; the character with the parity character if so
test bh,ACE_PE ;Parity error
jz AOBA_DataAvail25 ; No
test [si.DCB_Flags2],fPErrChar ;Parity error replacement character?
jz AOBA_DataAvail25 ; No
mov al,[si.DCB_PEChar] ; Yes, get parity replacement char
; Skip all other processing except event checking and the queing
; of the parity error replacement character
jmp short AOBA_DataAvail80 ;Skip all but event check, queing
public AOBA_DataAvail20
AOBA_DataAvail20:
or by ComErr[si],CE_RXOVER ;Show queue overrun
jmp short AOBA_DataAvail50
; See if we need to strip null characters, and skip
; queueing if this is one. Also remove any parity bits.
public AOBA_DataAvail25
AOBA_DataAvail25:
and al,RxMask[si] ;Remove any parity bits
jnz AOBA_DataAvail30 ;Not a Null character
test [si.DCB_Flags2],fNullStrip ;Are we stripping received nulls?
jnz AOBA_DataAvail50 ; Yes, put char in the bit bucket
; Check to see if we need to check for EOF characters, and if so
; see if this character is it.
public AOBA_DataAvail30
AOBA_DataAvail30:
test [si.DCB_Flags],fBinary ;Is this binary stuff?
jnz AOBA_DataAvail60 ; Yes, skip EOF check
cmp al,[si.DCB_EOFChar] ;Is this the EOF character?
jnz AOBA_DataAvail60 ; No, see about queing the charcter
or EFlags[si],fEOF ;Set end of file flag
public AOBA_DataAvail50
AOBA_DataAvail50:
jmp AOBA_DataAvail140 ;Skip the queing process
; If output XOn/XOff is enabled, see if the character just received
; is either an XOn or XOff character. If it is, then set or
; clear the XOffReceived flag as appropriate.
public AOBA_DataAvail60
AOBA_DataAvail60:
test [si.DCB_Flags2],fOutX ;Output handshaking?
jz AOBA_DataAvail80 ; No
cmp al,[si.DCB_XoffChar] ;Is this an X-Off character?
jnz AOBA_DataAvail70 ; No, see about XOn or Ack
or HSFlag[si],XOffReceived ;Show XOff received, ENQ or ETX [rkh]
test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
jz AOBA_DataAvail50 ; No
cmp cx,[si.DCB_XonLim] ;See if at XOn limit
ja AOBA_DataAvail50 ; No
and HSFlag[si],NOT XOffReceived ;Show ENQ or ETX not received
and HSFlag[si], NOT XOnPending+XOffSent
mov al, [si.DCB_XonChar]
call AOBA_OutHandshakingChar
jmp AOBA_DataAvail50 ;Done
public AOBA_DataAvail70
AOBA_DataAvail70:
cmp al,[si.DCB_XonChar] ;Is this an XOn character?
jnz AOBA_DataAvail80 ; No, just a normal character
and HSFlag[si],NOT XOffReceived
test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
jz AOBA_DataAvail75 ; No - jump to FakeXmitEmpty to get
; transmitting going again
and HSFlag[si],NOT EnqSent
public AOBA_DataAvail75
AOBA_DataAvail75:
jmp AOBA_FakeXmitEmpty ;Restart transmit
; Now see if this is a character for which we need to set an event as
; having occured. If it is, then set the appropriate event flag
public AOBA_DataAvail80
AOBA_DataAvail80:
cmp al,[si.DCB_EVTChar] ;Is it the event generating character?
jne AOBA_DataAvail90 ; No
or by EvtWord[si],EV_RxFlag ;Show received specific character
; Finally, a valid character that we want to keep, and we have
; room in the queue. Place the character in the queue.
; If the discard flag is set, then discard the character
public AOBA_DataAvail90
AOBA_DataAvail90:
test MiscFlags[si], Discard ;Discarding characters ?
jnz AOBA_DataAvail50 ; Yes
lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
les di,QInAddr[si][bx] ;Get queue base pointer from either
assumes es,nothing ; QInAddr or AltQInAddr
mov bx,QInPut[si] ;Get index into queue
mov es:[bx][di],al ;Store the character
inc bx ;Update queue index
cmp bx,QInSize[si] ;See if time for wrap-around
jc AOBA_DataAvail100 ;Not time to wrap
xor bx,bx ;Wrap-around is a new zero pointer
public AOBA_DataAvail100
AOBA_DataAvail100:
mov QInPut[si],bx ;Store updated pointer
inc cx ;And update queue population
mov QInCount[si],cx
; If flow control has been enabled, see if we are within the
; limit that requires us to halt the host's transmissions
cmp cx,XOffPoint[si] ;Time to see about XOff?
jc AOBA_DataAvail120 ; Not yet
test HSFlag[si],HSSent ;Handshake already sent?
jnz AOBA_DataAvail120 ; Yes, don't send it again
mov ah,HHSLines[si] ;Should hardware lines be dropped?
or ah,ah ; (i.e. do we have HW HS enabled?)
jz AOBA_DataAvail110 ; No
;[QN]---------------------------------------------------------------------------+
mov al,CommandShadow[si] ;8251 Command get (ins 94.04.16) |
test ah,ACE_DTR ;DTR handshake Enable ? (ins 94.04.16) |
jz AOBA_DataAvail101 ; No (ins 94.04.16) |
and al,not DTR ;Clear 8251's DTR Line ! (ins 94.04.16) |
public AOBA_DataAvail101
AOBA_DataAvail101: ; (ins 94.04.16) |
test ah,ACE_RTS ;RTS handshake Enable ? (ins 94.04.16) |
jz AOBA_DataAvail102 ; No (ins 94.04.16) |
and al,not RTS ;Clear 8251's RTS Line ! (ins 94.04.16) |
public AOBA_DataAvail102
AOBA_DataAvail102: ; (ins 94.04.16) |
mov dx,CommandPort[si] ;GET Command port address (ins 94.04.16) |
call int_Set8251mode ;Change to 8251 mode (ins 94.04.16) |
out dx,al ; (ins 94.04.16) |
call int_SetFIFOmode ;Change to FIFO mode (ins 94.04.16) |
mov CommandShadow[si],al ;Get Back 8251 Command (ins 94.04.16) |
or HSFlag[si],HHSDropped ; (ins 94.04.16) |
;[QN]---------------------------------------------------------------------------+
public AOBA_DataAvail110
AOBA_DataAvail110:
test [si.DCB_Flags2],fInX ;Input Xon/XOff handshaking
jz AOBA_DataAvail120 ; No
or HSFlag[si], XOffSent
mov al, [si.DCB_XoffChar]
call AOBA_OutHandshakingChar
public AOBA_DataAvail120
AOBA_DataAvail120:
cmp cx, [si.RecvTrigger] ;Q: time to call owner's callback?
jb short AOBA_DataAvail130 ; N:
test [si.NotifyFlagsHI], CN_RECEIVE
jnz short AOBA_DataAvail140 ; jump if notify already sent and
; data in buffer hasn't dropped
; below threshold
mov ax, IntCodeOFFSET AOBA_DataAvail140
push ax
mov ax, CN_RECEIVE
%OUT probably should just set a flag and notify after EOI
jmp notify_owner
public AOBA_DataAvail130
AOBA_DataAvail130:
and [si.NotifyFlagsHI], NOT CN_RECEIVE
public AOBA_DataAvail140
AOBA_DataAvail140:
pop dx
push dx
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_LSR ; (ins 94.04.16)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
in al, dx
test al, ACE_DR ;Q: more data available?
jz @F ; N:
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_RBR ; (ins 94.04.16)
in al, dx ;Read available character
jmp AOBA_DataAvail00
@@:
jmp AOBA_InterruptLoop_ChkTx
AOBA_DataAvail endp
public AOBA_OutHandshakingChar
AOBA_OutHandshakingChar proc near
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_LSR ; (ins 94.04.16)
mov ah, al
@@:
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
in al, dx
test al,ACE_TSRE ; (ins 94.05.17)
jz @B
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_THR ; (ins 94.04.16)
mov al, ah
out dx, al
ret
AOBA_OutHandshakingChar endp
page
;----------------------------Private-Routine----------------------------;
;
; AOBA_XmitEmpty - Transmitter Register Empty
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,BX,CX,DI,ES,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public AOBA_FakeXmitEmpty
AOBA_FakeXmitEmpty:
pop dx
push dx
; "Kick" the transmitter interrupt routine into operation.
call KickTxINT ;Bug fixed PC-11419 AutoCAD (ins 94.09.07)
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_LSR ; (ins 94.04.16)
NEWIODELAY 1 ;<OUT 5F,AL> (ins 94.04.18)
in al,dx ;Is xmit really empty?
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_THR ;--> Transmitter Holding Register(ins 94.04.16)
test al,ACE_TSRE ; (ins 94.05.17)
jnz short AOBA_XmitEmpty5 ; Y: send next char
jmp AOBA_InterruptLoop ; N: return to processing loop
public AOBA_XmitEmpty
AOBA_XmitEmpty proc near
call AOBA_MSR_READ ;AOBA-bug del 94.11.19 KBNES
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_LSR ;--> Line Status Register (ins 94.04.16)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
out 5fh,al ; (ins 94.05.18)
in al,dx ;Is xmit really empty?
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_THR ;--> Transmitter Holding Register(ins 94.04.16)
test al,ACE_TSRE ; (ins 94.05.17)
jz AOBA_Xmit_jumpto90 ;Transmitter not empty, cannot send
; If the hardware handshake lines are down, then XOff/XOn cannot
; be sent. If they are up and XOff/XOn has been received, still
; allow us to transmit an XOff/XOn character. It will make
; a dead lock situation less possible (even though there are
; some which could happen that cannot be handled).
public AOBA_XmitEmpty5
AOBA_XmitEmpty5:
mov ah,HSFlag[si] ;Get handshaking flag
test ah,HHSDown+BreakSet ;Hardware lines down or break set?
jnz AOBA_Xmit_jumpto100 ; Yes, cannot transmit
; Give priority to any handshake character waiting to be
; sent. If there are none, then check to see if there is
; an "immediate" character to be sent. If not, try the queue.
public AOBA_XmitEmpty10
AOBA_XmitEmpty10:
test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
jnz AOBA_XmitEmpty40 ; Yes
public AOBA_XmitEmpty15
AOBA_XmitEmpty15:
test ah,HSPending ;XOff or XOn pending
jz AOBA_XmitEmpty40 ; No
public AOBA_XmitEmpty20
AOBA_XmitEmpty20:
and ah,NOT XOnPending+XOffSent
mov al,[si.DCB_XonChar] ;Get XOn character
public AOBA_XmitEmpty30
AOBA_XmitEmpty30:
mov HSFlag[si],ah ;Save updated handshake flag
jmp AOBA_XmitEmpty110 ;Go output the character
public AOBA_Xmit_jumpto90
AOBA_Xmit_jumpto90:
jmp AOBA_XmitEmpty90
; If any of the lines which were specified for a timeout are low, then
; don't send any characters. Note that by putting the check here,
; XOff and Xon can still be sent even though the lines might be low.
; Also test to see if a software handshake was received. If so,
; then transmission cannot continue. By delaying the software check
; to here, XOn/XOff can still be issued even though the host told
; us to stop transmission.
public AOBA_XmitEmpty40
AOBA_XmitEmpty40:
test ah,CannotXmit ;Anything preventing transmission?
jz AOBA_XmitEmpty45 ; No
public AOBA_Xmit_jumpto100
AOBA_Xmit_jumpto100:
jmp AOBA_XmitEmpty100 ; Yes, disarm and exit
; If a character has been placed in the single character "transmit
; immediately" buffer, clear that flag and pick up that character
; without affecting the transmitt queue.
public AOBA_XmitEmpty45
AOBA_XmitEmpty45:
test EFlags[si],fTxImmed ;Character to xmit immediately?
jz AOBA_XmitEmpty515 ; No, try the queue
and EFlags[si],NOT fTxImmed ;Clear xmit immediate flag
mov al,ImmedChar[si] ;Get char to xmit
jmp AOBA_XmitEmpty110 ;Transmit the character
public AOBA_XmitEmpty515
AOBA_XmitEmpty515:
mov cx,QOutCount[si] ;Output queue empty?
jcxz AOBA_Xmit_jumpto90 ; Yes, go set an event
test [si.DCB_Flags],fEtxAck ;Etx Ack?
jz AOBA_XmitEmpty55 ; No
mov cx,QOutMod[si] ;Get number bytes sent since last ETX
cmp cx,[si.DCB_XonLim] ;At Etx limit yet?
jne AOBA_XmitEmpty51 ; No, inc counter
mov QOutMod[si],0 ; Yes, zero counter
or HSFlag[si],EtxSent ;Show ETX sent
jmp short AOBA_XE_sendXOFF
public AOBA_XmitEmpty51
AOBA_XmitEmpty51:
inc cx ; Update counter
mov QOutMod[si],cx ; Save counter
jmp short AOBA_XmitEmpty59 ; Send queue character
public AOBA_XmitEmpty55
AOBA_XmitEmpty55:
test [si.DCB_Flags],fEnqAck ;Enq Ack?
jz AOBA_XmitEmpty59 ; No, send queue character
mov cx,QOutMod[si] ;Get number bytes sent since last ENQ
or cx,cx ;At the front again?
jnz AOBA_XmitEmpty56 ; No, inc counter
mov QOutMod[si],1 ; Yes, send ENQ
or HSFlag[si],EnqSent ;Show ENQ sent
public AOBA_XE_sendXOFF
AOBA_XE_sendXOFF:
mov al,[si.DCB_XoffChar]
jmp short AOBA_XmitEmpty110 ;Go output the character
public AOBA_XmitEmpty56
AOBA_XmitEmpty56:
inc cx ;Update counter
cmp cx,[si.DCB_XonLim] ;At end of our out buffer len?
jne AOBA_XmitEmpty58 ; No
xor cx,cx ;Show at front again.
public AOBA_XmitEmpty58
AOBA_XmitEmpty58:
mov QOutMod[si],cx ;Save counter
public AOBA_XmitEmpty59
AOBA_XmitEmpty59:
lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
les di,QOutAddr[si][bx] ;Get queue base pointer from either
assumes es,nothing ; QOutAddr or AltQOutAddr
mov bx,QOutGet[si] ;Get pointer into queue
mov al,es:[bx][di] ;Get the character
inc bx ;Update queue pointer
cmp bx,QOutSize[si] ;See if time for wrap-around
jc AOBA_XmitEmpty60 ;Not time for wrap
xor bx,bx ;Wrap by zeroing the index
public AOBA_XmitEmpty60
AOBA_XmitEmpty60:
mov QOutGet[si],bx ;Save queue index
mov cx,QOutCount[si] ;Output queue empty?
dec cx ;Dec # of bytes in queue
mov QOutCount[si],cx ; and save new population
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_THR ; (ins 94.04.16)
out dx,al ;Send char
cmp cx, [si.SendTrigger] ;Q: time to call owner's callback?
jae short AOBA_XmitEmpty70 ; N:
test [si.NotifyFlagsHI], CN_TRANSMIT
jnz short AOBA_XmitEmpty80 ; jump if notify already sent and
; data in buffer hasn't raised
; above threshold
mov ax, IntCodeOFFSET AOBA_XmitEmpty80
push ax
mov ax, CN_TRANSMIT
jmp notify_owner
public AOBA_XmitEmpty70
AOBA_XmitEmpty70:
and [si.NotifyFlagsHI], NOT CN_TRANSMIT
public AOBA_XmitEmpty80
AOBA_XmitEmpty80:
%OUT check fNoFIFO in EFlags[si] to determine if we can queue more output
jmp AOBA_InterruptLoop
; No more characters to transmit. Flag this as an event.
public AOBA_XmitEmpty90
AOBA_XmitEmpty90:
or by EvtWord[si],EV_TxEmpty
; Cannot continue transmitting (for any of a number of reasons).
; Disable the transmit interrupt. When it's time resume, the
; transmit interrupt will be reenabled, which will generate an
; interrupt.
public AOBA_XmitEmpty100
AOBA_XmitEmpty100:
;[QN]-------------------------------------------------------------------------+
cmp [si.DCB_id],ID_Com1 ;Is This Com1 ID ? (ins 94.05.19)|
jne AOBA_XmitEmpty102 ;No, go to KickTx5 (ins 94.05.19)|
mov dx,MaskFFPort[si] ;F/F Port Mask Bit (ins 94.05.19)|
in al,dx ; (ins 94.05.19)|
mov MaskFFShadow[si],al ;Save the Old Mask bit (ins 94.05.19)|
; (ins 94.05.19)|
AOBA_XmitEmpty102: ; (ins 94.05.19)|
mov al,MaskFFShadow[si] ;mask data(port C) save (ins 94.05.19)|
test al,MSK_TXR ;Check a tx.RDY INT mask(ins 94.05.19)|
jz AOBA_XmitEmpty110 ; disable (ins 94.05.19)|
and al,NOT(MSK_TXE+MSK_TXR) ;= 11111001b (ins 94.05.19)|
mov dx,MaskFFPort[si] ;Port address (Port C) (ins 94.05.19)|
mov MaskFFShadow[si],al ;Masking data save (ins 94.05.19)|
;-----------------------------------------------------------------------------+
public AOBA_XmitEmpty110
AOBA_XmitEmpty110:
out dx,al
jmp AOBA_InterruptLoop
AOBA_XmitEmpty endp
page
;----------------------------Private-Routine----------------------------;
;
; AOBA_ModemStatus - Modem Status Interrupt Handler
;
; Entry:
; DS:SI --> DEB
; DX = Port.IIDR
; Returns:
; None
; Error Returns:
; None
; Registers Destroyed:
; AX,BX,CX,DI,ES,FLAGS
; History:
;-----------------------------------------------------------------------;
; assumes ds,Data
assumes es,nothing
public AOBA_ModemStatus ;Public for debugging
AOBA_ModemStatus proc near
; Get the modem status value and shadow it for MSRWait.
mov dx,Port[si] ;Get comm I/O port (ins 94.04.16)
add dl,ACE_MSR ; (ins 94.04.16)
in al,dx
mov MSRShadow[si],al ;Save MSR data for others
mov ch,al ;Save a local copy
; Create the event mask for the delta signals
mov ah,al ;Just a lot of shifting
shr ax,1
shr ax,1
shr ah,1
mov cl,3
shr ax,cl
and ax,EV_CTS+EV_DSR+EV_RLSD+EV_Ring
or EvtWord[si],ax
mov ah,ch ;[rkh]...
shr ah,1
shr ah,1
and ax,EV_CTSS+EV_DSRS
or EvtWord[si],ax
mov ah,ch
mov cl,3
shr ah,cl
and ax,EV_RLSD
or EvtWord[si],ax
mov ah,ch
mov cl,3
shl ah,cl
and ax,EV_RingTe
or EvtWord[si],ax
public AOBA_ModemStatus10
AOBA_ModemStatus10:
mov al,OutHHSLines[si] ;Get output hardware handshake lines
or al,al ;Any lines that must be set?
jz AOBA_ModemStatus40 ;No hardware handshake on output
and ch,al ;Mask bits of interest
cmp ch,al ;Lines set for Xmit?
je AOBA_ModemStatus20 ; Yes
or HSFlag[si],HHSDown ;Show hardware lines have dropped
public AOBA_ModemStatus30
AOBA_ModemStatus30:
jmp AOBA_InterruptLoop
public AOBA_ModemStatus40
AOBA_ModemStatus40:
jmp AOBA_InterruptLoop_ChkTx
; Lines are set for xmit. Kick an xmit interrupt if needed
public AOBA_ModemStatus20
AOBA_ModemStatus20:
and HSFlag[si],NOT (HHSDown OR HHSAlwaysDown)
;Show hardware lines back up
mov cx,QOutCount[si] ;Output queue empty?
jcxz AOBA_ModemStatus30 ; Yes, return to InterruptLoop
jmp AOBA_FakeXmitEmpty ;Restart transmit
AOBA_ModemStatus endp
;-----------------------------Public-Routine----------------------------;
; int_Set8251mode - Change to 8251 mode
;
; Entry:
;
; Returns:
;
; Error Returns:
; NONE
; Registers Destroyed:
; NONE
; History: QNES T-MATUDA
;-----------------------------------------------------------------------;
int_Set8251mode proc near
push dx ;
push ax ;
mov dx,Port[si] ;
add dx,ACE_FCR ;
in al, dx ;
NEWIODELAY 3 ; <OUT 5F,AL>
test al, 01h ;
jz int_running_fifo_mode ;
and al, 0feh
out dx,al ;
NEWIODELAY 3 ; <OUT 5F,AL>
@@: ;
in al,dx ;
NEWIODELAY 3 ; <OUT 5F,AL>
test al,ACE_EFIFO ;
jnz @B ;
int_running_fifo_mode: ;
pop ax ;
pop dx ;
ret
int_Set8251mode endp
;-----------------------------Public-Routine----------------------------;
; int_SetFIFOmode - Change to FIFO mode
;
; Entry:
;
; Returns:
;
; Error Returns:
; NONE
; Registers Destroyed:
; NONE
; History: QNES T-MATUDA
;-----------------------------------------------------------------------;
int_SetFIFOmode proc near
push dx ;
push ax ;
mov dx,Port[si] ;
add dx,ACE_FCR ;
in al, dx ;
NEWIODELAY 3 ; <OUT 5F,AL>
test al, 01h ;
jnz int_running_8251_mode ;
;Set_FIFO == RLInt_Enable + ACE_TRIG14 + ACE_EFIFO
mov al,Set_FIFO ;set FIFO mode
out dx,al ;
NEWIODELAY 3 ; <OUT 5F,AL>
int_running_8251_mode: ;
pop ax ;
pop dx ;
ret
int_SetFIFOmode endp
TOMOE_PAT DB 16 DUP('PATCH !!') ;PATCH AREA (ins 92.11.11)
endif ; NEC_98
ifdef DEBUG
public Control, DEF_Handler, COMHandler, APIHandler
public InterruptLoop, IntLoop10, IntLoop20
public DataAvail25, DataAvail30, DataAvail50
public DataAvail60, DataAvail70, DataAvail80, DataAvail90
public DataAvail100, DataAvail110, DataAvail120
public DataAvail130, DataAvail140, OutHandshakingChar
public XmitEmpty10, XmitEmpty20, XmitEmpty30, XmitEmpty40
public XmitEmpty59, XmitEmpty60
public XmitEmpty90, XmitEmpty100, XmitEmpty110
public ModemStatus10, ModemStatus20, ModemStatus30
public notify_owner, callback_event
endif
DOSTI proc near
FSTI
ret
DOSTI endp
DOCLI proc near
FCLI
ret
DOCLI endp
sEnd IntCode
end