home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-01-25 | 32.9 KB | 1,360 lines |
- 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.
- ;
- ;-----------------------------------------------------------------------;
-
- subttl Communications Hardware Interrupt Service Routines
-
- .xlist
- include cmacros.inc
- include comdev.inc
- include ibmcom.inc
- include ins8250.inc
- include BIMODINT.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:
- cli
- 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 short 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 short 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 short 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:
- cli
- 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
- cli
- 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:
- sti
- @@:
- 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
-
- ; cli ;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
-
- sEnd IntCode
- end
-