1375 lines
32 KiB
NASM
1375 lines
32 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
|
|
|
|
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
|
|
|
|
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
|
|
jmp DEF_Handler
|
|
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 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
|
|
call CommInt
|
|
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
|
|
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
|
|
|
|
api_not_EOI:
|
|
cmp ax, BIH_API_Call_Back
|
|
jae short api_callme
|
|
push dx
|
|
push cx
|
|
mov dx, INTA1
|
|
mov cx, es:[di.BIS_IRQ_Number]
|
|
cmp cl, 8 ;Q: 2nd PIC?
|
|
jb @f ; N:
|
|
mov dx, 0A1h ; Y: dx = mask port
|
|
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]
|
|
mov dx,Port[si] ;Get device I/O address
|
|
add dl, ACE_IIDR
|
|
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
|
|
|
|
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
|
|
|
|
|
|
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?
|
|
jnz 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 IntLoop30 ; N:
|
|
|
|
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
|
|
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
|
|
|
|
InterruptLoop:
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
sub dl,ACE_IIDR-ACE_RBR ;--> receiver buffer register
|
|
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
|
|
mov LSRShadow[si],0
|
|
.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
|
|
@@:
|
|
|
|
; 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:
|
|
|
|
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
|
|
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
|
|
|
|
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:
|
|
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
|
|
|
|
DataAvail endp
|
|
|
|
|
|
OutHandshakingChar proc near
|
|
|
|
add dl, ACE_LSR
|
|
mov ah, al
|
|
@@:
|
|
in al, dx
|
|
test al, ACE_THRE
|
|
jz @B
|
|
sub dl, ACE_LSR
|
|
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.
|
|
|
|
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
|
|
jnz short XmitEmpty5 ; Y: send next char
|
|
jmp InterruptLoop ; N: return to processing loop
|
|
|
|
public XmitEmpty
|
|
XmitEmpty proc near
|
|
|
|
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
|
|
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
|
|
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
|
|
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]
|
|
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
|
|
|
|
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
|
|
jmp short notify_owner
|
|
|
|
XmitEmpty70:
|
|
and [si.NotifyFlagsHI], NOT CN_TRANSMIT
|
|
|
|
XmitEmpty80:
|
|
%OUT check fNoFIFO in EFlags[si] to determine if we can queue more output
|
|
jmp InterruptLoop
|
|
|
|
|
|
; 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:
|
|
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
|
|
|
|
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.
|
|
|
|
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
|
|
|
|
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
|
|
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 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
|