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 ; (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 ; (ins 93.03.08) out dx,al ; (ins 93.03.08) NEWIODELAY 1 ; (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 ; (ins 93.03.08) jmp short api_master ; (ins 93.03.08) EOI_INT50: ; (ins 93.03.08) NEWIODELAY 1 ; (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 ; (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]| ; [QN]| ; none [QN]| ; [QN]| ; [QN]| ; [AL]= Line Status [QN]| ; [QN]| ; [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 ; ;(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? | jnz DataAvail140_Binary ; Yes | 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 ; (ins 93.10.27) jmp DataAvail00 @@: jmp InterruptLoop ;;;92.10.05 DataAvail140_Binary: ;Receive Binary | push cx ; | mov cx, [RECLoopCounter] ; [QN][BA](ins 93.03.30) RetryReadData2: ; | mov dx,StatusPort[si] ;Get ID reg I/O address | in al,dx ;Get Interrupt Id | test al,RX_RDY ;Is this RX_ready ? | jz @F ; No | pop cx ; | mov dx, DataPort[si] ; Store Read Data Port | in al, dx ;Receive Data | NEWIODELAY 14 ; (ins 93.10.27) jmp DataAvail00 ; | @@: ; | loop RetryReadData2 ; | pop cx ; | jmp InterruptLoop ; | 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]| ; [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]| ; ; [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 ; (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 ; (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 ; test al, 01h ; jz int_running_fifo_mode ; and al, 0feh out dx,al ; NEWIODELAY 3 ; @@: ; in al,dx ; NEWIODELAY 3 ; 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 ; 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 ; 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