home *** CD-ROM | disk | FTP | other *** search
- ;
- ; The Greenleaf Comm Library
- ;
- ; Copyright (C) 1984-90 Greenleaf Software Inc. All Rights Reserved.
- ;
- ;
- ; MODIFICATIONS
- ;
- ; "" 21-SEP-1988 10:05:48.64 version 2.21
- ; Near the end of psdigi interrupt routine si was not being popped
- ; before ds (in large data model only) (#126)
- ;
- ; "" Mon 05-Jun-1989 14:25:15
- ; Added support for 35 ports.
- ;
- include model.h
- include prologue.h
- include asiports.equ
-
- RESTARTTX macro
- local rstnmt,restartxexit
- test [si+chst_bits],TXEMPTY
- jnz restartxexit
- lea di,[si+tx_cell]
- cli
- call _remove
- jnz rstnmt
- or [si+chst_bits],TXEMPTY
- rstnmt: or [si+chst_bits],XCHRUN+TXIFLAG
- sti
- mov dx,[si+base_8250]
- out dx,al
- KILL_TIME
- restartxexit:
- endm
- TABLEPORT struc
- ptb dw ptrsize dup(?)
- as_shport dw ?
- as_shbits dw ?
- as_mask dw ?
- as_xorv dw ?
- TABLEPORT ends
-
-
- TABLESIZE equ size TABLEPORT
-
- dseg _commlib
-
- public ihdptr
- public inttbl
- public tblptr
- public serv0
- public pcdigi
- public psdigi
-
- ihdptr dw offset pcdigi
-
-
- ;==>-- This table contains the starting addresses of all interrupt
- ; service routines.
- ;
- inttbl dw offset serv0 ; offset of COM1: interrupt routine
- dw offset serv1 ; offset of COM2: interrupt routine
- dw offset serv2 ; offset of COM3: interrupt routine
- dw offset serv3 ; offset of COM4: interrupt routine
- dw offset serv4 ; offset of COM5: interrupt routine
- dw offset serv5 ; offset of COM6: interrupt routine
- dw offset serv6 ; offset of COM7: interrupt routine
- dw offset serv7 ; offset of COM8: interrupt routine
- dw offset serv8 ; offset of COM9: interrupt routine
- dw offset serv9 ; offset of COM10: interrupt routine
- dw offset serv10 ; offset of COM11: interrupt routine
- dw offset serv11 ; offset of COM12: interrupt routine
- dw offset serv12 ; offset of COM13: interrupt routine
- dw offset serv13 ; offset of COM14: interrupt routine
- dw offset serv14 ; offset of COM15: interrupt routine
- dw offset serv15 ; offset of COM16: interrupt routine
- dw offset serv16 ; offset of COM17: interrupt routine
- dw offset serv17 ; offset of COM18: interrupt routine
- dw offset serv18 ; offset of COM19: interrupt routine
- dw offset serv19 ; offset of COM20: interrupt routine
- dw offset serv20 ; offset of COM21: interrupt routine
- dw offset serv21 ; offset of COM22: interrupt routine
- dw offset serv22 ; offset of COM23: interrupt routine
- dw offset serv23 ; offset of COM24: interrupt routine
- dw offset serv24 ; offset of COM25: interrupt routine
- dw offset serv25 ; offset of COM26: interrupt routine
- dw offset serv26 ; offset of COM27: interrupt routine
- dw offset serv27 ; offset of COM28: interrupt routine
- dw offset serv28 ; offset of COM29: interrupt routine
- dw offset serv29 ; offset of COM30: interrupt routine
- dw offset serv30 ; offset of COM31: interrupt routine
- dw offset serv31 ; offset of COM32: interrupt routine
- dw offset serv32 ; offset of COM33: interrupt routine
- dw offset serv33 ; offset of COM34: interrupt routine
- dw offset serv34 ; offset of COM35: interrupt routine
-
- dev_cnt equ (($ - inttbl)/2) ; device count
-
- srcher db 0 ;set to 1 if interrupt routine has error
- icnt dw 0 ;These counters were added to work
- ecnt dw 0 ;with the C option in MULTLOOP.
- ;In order for them to do anything,
- ;define DEBUG_COUNTERS in ASIPORTS.EQU
-
- tblptr dd ? ;points to array of table pointers
-
- ;==>-- Table for interrupt service routines
- ;
- injmptl dw offset asicms ; case 0 modem status
- dw offset asictx ; case 2 transmit register empty
- dw offset asicrx ; case 4 receive character ready
- dw offset asicrs ; case 6 special condition
-
-
- endds
-
- pseg isr
- cproc GetInterruptCount,,geticnt
- mov ax,icnt
- cproce
-
- cproc GetInterruptErrorCount,,getecnt
- mov ax,ecnt
- cproce
-
- ;==>-- int _asigetc(p) remove character & wide track status
- ; from receive queue. Character is returned in AL, status
- ; (if enabled) is returned in AH.
- ;
- cproc _asigetc
- if _LDATA
- push ds
- lds si,parm1_
- else
- mov si,parm1_
- endif
- lea di,[si+rx_cell]
- cli
- and [si+chst_bits],not RXFULL
- call _remove ;remove character
- ;**2.10 sti
- jnz _asgne ;if non zero, not empty
- or [si+chst_bits],RXEMPTY ;say receive is empty
- _asgne: sti ;**2.10
- test [si+chmode_bits],IS_ASCII
- jz _asxxx
- and al,7FH
- _asxxx: test [si+chst_bits],XOFFSENT ;see if xon was sent
- jz asirck ;if not don't check low water
- push ax ;save character (&status)
- mov ax,[si+rx_count]
- cmp ax,[si+rx_lowater] ;see if down to low water yet
- jnb asixxt
- mov cx,[si+base_8250] ;cx=8250 base
- mov dx,LSREG
- add dx,cx
- asiglp: in al,dx
- KILL_TIME
- and al,THRE ;wait for transmit holding register
- jz asiglp
- mov dx,cx
- mov ax,[si+start_rem_xmt] ;get character to start it
- out dx,al
- KILL_TIME
- and [si+chst_bits], not XOFFSENT ;say it has been reversed
- test [si+chmode_bits],IS_TXINT ;are tx interrupts enabled
- jz asixxt ;if not get out
- or [si+chst_bits],XCHRUN ;else say xmit back on
- mov dx,LSREG ; now wait for tx holding to empty
- add dx,cx
- wloop1: in al,dx
- KILL_TIME
- and al,THRE ; is tx holding empty?
- jz wloop1
- RESTARTTX
- asixxt: pop ax ;get character back
- asirck: test [si+chmode_bits],IS_RTSCONTROL ;see if controlling RTS
- jz asiext ;if not exit _asigetc
- test [si+chst_bits],RTSACTIVE ;is RTS asserted?
- jnz asiext ;if so then nothing to do
- mov cx,[si+rts_lowater] ;see if down to low water yet
- cmp cx,[si+rx_count]
- jb asiext ;if not hop out
- push ax ;save character/status
- cli ;disable wolves while
- or [si+chst_bits],RTSACTIVE ;updating shared variable
- mov dx,[si+base_8250]
- add dx,MCREG ;dx=modem control register
- in al,dx
- KILL_TIME
- or al,RTS ;assert RTS
- out dx,al
- KILL_TIME
- sti ;wolves o.k. again
- pop ax ;restore character/status
- asiext:
- if _LDATA
- pop ds
- endif
- cproce
-
- ;==>-- int _asiputc(p,c) insert character in queue.
- ;
- cproc _asiputc
- if _LDATA
- push ds
- lds si,parm1_
- mov al,parm3_
- else
- mov si,parm1_
- mov al,parm2_
- endif
- test [si+chmode_bits],IS_ASCII
- jz _aspna
- and al,7fh
- _aspna: lea di,[si+tx_cell]
- cli
- call insert ;insert character
- jnz _aspnf ;if non zero not full
- or [si+chst_bits],TXFULL ;say transmit is full
- _aspnf: sti
- test [si+chst_bits],TXEMPTY ;is transmit empty?
- jz _asnmt ;if not skip out
- and [si+chst_bits],not TXEMPTY ;say it is now not empty
- test [si+chmode_bits],IS_TXINT ;should xmit be running?
- jz _asnmt ;if not don't re-start
- test [si+chst_bits],TXWXON+TXWCTS+TXWALERT+XCHRUN
- jnz _asnmt ;if waiting for something else?
- mov cx,[si+base_8250]
- mov dx,LSREG ; now wait for tx holding to empty
- add dx,cx
- wloop2: in al,dx
- KILL_TIME
- and al,THRE ; is tx holding empty?
- jz wloop2
- RESTARTTX
- _asnmt:
- if _LDATA
- pop ds
- endif
- xor ax,ax
- cproce
-
- ;==>-- Offsets for the insert & remove routines
- ;
- CELL equ 0
- BSIZE equ 2
- COUNT equ 4
- HEAD equ 6
- TAIL equ 8
- BUFFER equ 10
-
- ;==>-- int _asipekc(p) read character & wide track status
- ; from receive queue, do not adjust any pointers or flags.
- ; DO NOT call this routine unless there is a character to read.
- ; Character is returned in AL, status (if enabled) is returned in AH.
- ;
- cproc _asipekc
- if _LDATA
- push ds
- lds si,parm1_
- else
- mov si,parm1_
- endif
- lea di,[si+rx_cell]
- if _LDATA
- push es
- les si,[di+BUFFER] ;es:si=base of buffer
- else
- mov si,[di+BUFFER] ;ds:si=base of buffer
- endif
- mov bx,[di+HEAD] ;read the head
- cmp word ptr[di+CELL],2 ;see if word size buffer
- jz peword
- xor ah,ah
- if _LDATA
- mov al,es:[si+bx] ;remove character via ES:SI
- else
- mov al,[si+bx] ;remove character via DS:SI
- endif
- jmp short peend
- peword:
- if _LDATA
- mov ax,es:[si+bx] ;remove char/status via ES:SI
- else
- mov ax,[si+bx] ;remove char/status via DS:SI
- endif
- peend:
- if _LDATA
- pop es
- pop ds
- endif
- cproce
-
-
- ;==>-- insert character is to be called with ds:di pointing to the
- ; cell size variable, upon return the Zero flag being set indicates
- ; that the buffer is NOW FULL. When the buffer is full do not call
- ; this routine again, until there is space for another character.
- ; Call with character in AL, status in AH (if applicable). This
- ; routine does not test for a full buffer before inserting, only
- ; after inserting.
- ;
- insert PROC NEAR ;DS:DX points to beginning
- push si
- if _LDATA
- push es
- les si,[di+BUFFER] ;es:si points to base of array
- else
- mov si,[di+BUFFER] ;ds:si points to base of array
- endif
- inc word ptr [di+COUNT] ;bump counter
- mov bx,[di+TAIL] ;read the tail
- mov dx,bx
- add dx,[di+CELL] ;advance the tail for next
- mov cx,[di+BSIZE] ;get size of buffer to cx
- cmp word ptr[di+CELL],2 ;see if wide buffer
- jnz noiadj
- shl cx,1 ;buffer is * 2
- noiadj: cmp dx,cx ;check for wrap
- jb inwrap ;if no wrap take jump
- xor dx,dx ;reset subscript to 0
- inwrap: mov [di+TAIL],dx ;save updated tail
- cmp word ptr [di+CELL],2 ;see if word size buffer
- jz inword
- if _LDATA
- mov es:[si+bx],al ;save character via ES:SI
- else
- mov [si+bx],al ;save character via DS:SI
- endif
- jmp short inend
- inword:
- if _LDATA
- mov es:[si+bx],ax ;save char/status via ES:SI
- else
- mov [si+bx],ax ;save char/status via DS:SI
- endif
- inend: cmp dx,[di+HEAD] ;see if buffer full
- if _LDATA
- pop es
- endif
- pop si
- ret
- insert ENDP
-
- ;==>-- remove character is to be called with ds:di pointing to the
- ; cell size variable, upon return the Zero flag being set indicates
- ; that the buffer is NOW EMPTY. When the buffer is empty DO NOT call
- ; this routine again, until there is another character to remove.
- ; Returns with character in AL, status in AH (if applicable). This
- ; routine does not test for an empty buffer before removing, only
- ; after removing.
- ;
- _remove PROC NEAR
- push si
- if _LDATA
- push es
- les si,[di+BUFFER] ;es:si=base of buffer
- else
- mov si,[di+BUFFER] ;ds:si=base of buffer
- endif
- dec word ptr [di+COUNT] ;decrement counter
- mov bx,[di+HEAD] ;read the head
- mov dx,bx
- add dx,[di+CELL] ;advance the head
- mov cx,[di+BSIZE] ;get size of buffer to cx
- cmp word ptr[di+CELL],2 ;see if wide buffer
- jnz noradj
- shl cx,1 ;buffer is * 2
- noradj: cmp dx,cx ;check for wrap
- jb rewrap ;if no wrap take jump
- xor dx,dx ;reset subscript to 0
- rewrap: mov [di+HEAD],dx ;save updated head
- cmp word ptr[di+CELL],2 ;see if word size buffer
- jz reword
- xor ah,ah
- if _LDATA
- mov al,es:[si+bx] ;remove character via ES:SI
- else
- mov al,[si+bx] ;remove character via DS:SI
- endif
- jmp short reend
- reword:
- if _LDATA
- mov ax,es:[si+bx] ;remove char/status via ES:SI
- else
- mov ax,[si+bx] ;remove char/status via DS:SI
- endif
- reend: cmp dx,[di+TAIL] ;see if buffer empty
- if _LDATA
- pop es
- endif
- pop si
- ret
- _remove ENDP
-
- ;==>-- void _asiprime(p)
- ; struct PORT_TABLE *p;
- ;
- ; This function will re-start the 8250's transmit interrupt
- ; process (if transmit interrupts are enabled)
- ;
- cproc _asiprime,,_asiprim,,,<DS,OKEXIT>
- if _LDATA
- lds si,parm1_
- else
- mov si,parm1_
- endif
- test [si+chmode_bits],IS_TXINT ;see if app. has enabled
- jnz ok2p
-
- jmp short ok_exit
- ok2p: mov cx,[si+base_8250]
- mov dx,LSREG ; now wait for tx holding to empty
- add dx,cx
- wloop4: in al,dx
- KILL_TIME
- and al,THRE ; is tx holding empty?
- jz wloop4
- RESTARTTX
- ok_exit:
- xor ax,ax
- cproce
- ;==>-- The psdigi routine gets control when the PS/2 digiboard is installed.
- ; This code is enabled by calling asihsel(1)
- ;
- psdigi LABEL NEAR
- lds si,tblptr ;ds:si points to first entry in table
- add si,ax ;ax has offset into table
- mov dx,[si+as_shport] ;check shared port address
- or dx,dx ;if no shared port
- jnz psisshr
- ;
- ; This is a non-shared port interrupt. This means I now have to call the
- ; service routine for this port and every other port on the same IRQ.
- ; I sit in a loop calling the interrupt handler. CX is set to be the
- ; interrupt number for this port. The first time through the loop, CX
- ; is set to 0, which means we don't know the interrupt number yet.
- ;
- mov cx,0
- testloop:
-
- push si ;Save the pointer into the table
- if _LDATA
- push ds
- lds si,dword ptr[si]
- mov dx,ds
- else
- mov si,[si] ;test for NULL pointer
- mov dx,0
- endif
-
- or dx,si
- jz loopdone ;if so then take interrupt error exit
- mov dx,[si+base_8250]
- mov ax,[si+intrpt_num]
- or cx,cx
- jnz skip
- mov cx,ax
- skip: cmp ax,cx
- jnz loopdone
- push cx
- call psdintlop
- pop cx
- if _LDATA
- pop ds
- endif
- pop si
- add si,TABLESIZE
- jmp testloop
- loopdone:
- if _LDATA
- pop ds
- endif
- pop si
- mov dx,[si+port_8259]
- jmp short psdout2
-
- ;
- psisshr:
- mov bx,[si+as_mask] ;mask to bx
- or bh,bh ;check bits 8-15
- jz ps8bit
- in ax,dx ;read 16 bit shared port
- KILL_TIME
- and ax,bx ;mask unwanted bits
- xor ax,[si+as_xorv] ;invert bits if needed
- jnz psnxt1
- jmp servexit
-
- ps8bit: in al,dx ;read shared port to al (8 bit)
- KILL_TIME
- xor ah,ah ;clear ah
- and al,bl ;mask unwanted bits
- xor al,byte ptr [si+as_xorv] ;invert bits if needed
- jnz psnxt1
- jmp servexit
- psnxt1:
- if _LDATA
- push ds
- endif
- push si ;save pointer to start
- psdloop:
- shr ax,1 ;shift bit 0 to carry flag
- jnc psdnxt ;see if channel has int pending
- push si ;if so process it.
- if _LDATA
- push ds
- endif
- push ax
- call psdfound
- mov dx,[si+port_8259] ;dx = port of 8259 for serviced chnl.
- pop ax
- if _LDATA
- pop ds
- endif
- pop si
- psdnxt: add si,TABLESIZE ;ds:si points to next entry
- or ax,ax ;check, are we finished?
- jnz psdloop ;if not process next one.
-
- pop si ;get pointer to start back
- if _LDATA ; pop si before ds FIX
- pop ds
- endif
-
- mov cx,dx ;save dx away
- mov dx,[si+as_shport] ;check shared port address
- mov bx,[si+as_mask] ;mask to bx
- or bh,bh ;check bits 8-15
- jz ps8bit2
- in ax,dx ;read 16 bit shared port
- KILL_TIME
- and ax,bx ;mask unwanted bits
- xor ax,[si+as_xorv] ;invert bits if needed
- mov dx,cx
- jz psdout2
- jmp short psnxt2
- ps8bit2:
- in al,dx ;read shared port to al (8 bit)
- KILL_TIME
- xor ah,ah ;clear ah
- and al,bl ;mask unwanted bits
- xor al,byte ptr [si+as_xorv] ;invert bits if needed
- mov dx,cx
- jz psdout2
- psnxt2:
- if _LDATA
- push ds
- endif
- push si ;save pointer to start
- jmp psdloop
- psdout2:
- or dx,dx
- jnz dxvalid
- mov dx,20h
- dxvalid:
- cmp dx,20h ;See if the EOI is going to an
- je dx_skip ;8259 other than the system
- mov al,20h
- out dx,al
- KILL_TIME
- dx_skip:
- jmp servexit
-
- ;==>-- Now we have found the structure member that applies to this
- ; interrupt, ds:si points to the variable that contains the
- ; address of the ports data structure.
- ;
- psdfound:
- if _LDATA
- lds si,dword ptr[si]
- mov dx,ds
- or dx,si ;test for NULL pointer
- jz psdgobak ;if so then take interrupt error exit
- else
- mov si,[si] ;test for NULL pointer
- mov dx,si
- or si,si
- jz psdgobak ;if so then take interrupt error exit
- endif
- mov dx,[si+base_8250]
- psdintlop:
- mov cx,dx
- add dx,INTID ;point to interrupt ID register
- in al,dx ;read interrupt identification register
- KILL_TIME
- mov dx,cx ;leave pointing to base address
- test al,1 ;see if interrupt is pending
- jnz psdgobak ;if no interrupt pending get out
- xor bh,bh
- mov bl,al
- push dx ;save 8250 address for next pass
- ifdef DSNOTHING
- mov ax,__commlib_DATA
- assume es:__commlib_DATA
- else
- mov ax,DGROUP
- assume es:DGROUP
- endif
- mov es,ax
- call es:injmptl[bx] ;take required 8250 action.
- pop dx
- assume es:NOTHING
- jmp psdintlop
- psdgobak:
- ret
-
-
- ;==>-- The pcdigi routine gets control when either the PC digiboard
- ; or an ordinary COM1/COM2 is installed.
- ;
- pcdigi LABEL NEAR
- lds si,tblptr ;ds:si points to first entry in table
- add si,ax ;ax has offset into table
- mov dx,[si+as_shport] ;check shared port address
- or dx,dx ;if no shared port take jump
- jz pcdfound
- in al,dx ;read shared port
- KILL_TIME
- and al,byte ptr [si+as_mask]
- xor ah,ah
- mov dx,TABLESIZE ;incrementer
- pcdsrchl:
- cmp ax,[si+as_shbits] ;is this the one?
- jz pcdfound
- add si,dx
- loop pcdsrchl ;if cx!=0 do it again
- pcdinerex:
- jmp servexit
-
- ;==>-- Now we have found the structure member that applies to this
- ; interrupt, ds:si points to the variable that contains the
- ; address of the ports data structure.
- ;
- pcdfound:
- if _LDATA
- lds si,dword ptr[si]
- mov dx,ds
- or dx,si ;test for NULL pointer
- jnz pcd_continue
- jmp servexit ;if so then take interrupt error exit
- else
- mov si,[si] ;test for NULL pointer
- or si,si
- jnz pcd_continue
- jmp servexit ;if so then take interrupt error exit
- endif
- pcd_continue:
- mov dx,[si+base_8250]
- pcdintlop:
- mov cx,dx
- add dx,INTID ;point to interrupt ID register
- in al,dx ;read interrupt identification register
- KILL_TIME
- mov dx,cx ;leave pointing to base address
- test al,1 ;see if interrupt is pending
- jnz pcdgobak ;if no interrupt pending get out
- xor bh,bh
- mov bl,al
- push dx ;save 8250 address for next pass
- ifdef DSNOTHING
- mov ax,__commlib_DATA
- assume es:__commlib_DATA
- else
- mov ax,DGROUP
- assume es:DGROUP
- endif
- mov es,ax
- call es:injmptl[bx] ;take required 8250 action.
- pop dx
- jmp pcdintlop
- pcdgobak:
- pop bp
- pop di
- pop es
- pop bx
- mov dx,[si+port_8259] ;send generic 8259 eoi
- pop si
- pop ds
- mov al,20h
- out dx,al
- KILL_TIME
- cmp dx,20h ;see if system board
- jz pcdaround
- out 20h,al ;and to system board
- KILL_TIME
- pcdaround:
- pop dx
- pop cx
- pop ax
- iret
-
- ;
- ;==>-- Common Interrupt routines --<==;
- ;
-
- ;==>-- Modem status change interrupt handler
- ;
- asicms: mov cx,dx ;save 8250 base in cx for speed
- add dx,MSREG ;dx = Modem status register
- in al,dx ;read the reason we are here
- KILL_TIME
- mov dx,cx ;dx back to 8250 base
- mov ah,al
- not ah
- add dx,INTER ;dx=interrupt enable register
- or [si+modem_stat],ax ;update static status byte
- not ah
- mov bx,[si+wide_stat] ;save status bits for wide track
- and bl,0fh ;mask off bits 4-7
- and ah,0f0h
- or bl,ah
- mov ah,al ;refresh ah with 8250 status
- mov [si+wide_stat],bx
- or [si+chst_bits],MODCHG ;say we had a modem status change
- mov bp,[si+chmode_bits] ;let bp hold these for speed
- test bp,IS_IGMSTAT+IS_IGALERT+IS_CTSMODE ;**2.10 eliminate
- ;time-consuming test/jump sequences
- ;; jz mstout
- jnz mst001
- jmp mstout
- mst001: test bp,IS_IGMSTAT ;see if we are ignoring modem
- jz mstiga ;status changes?
- or [si+chst_bits],ALERT ;set alert bit if not
- mstiga: test bp,IS_IGALERT ;are we ignoring alert conditions?
- jz mstcts ;if so check for cts
- in al,dx ;come here to stop tx & rx interrupts
- KILL_TIME
- and [si+chst_bits],not TXIFLAG
- and al,not ENRX
- out dx,al
- KILL_TIME
- and [si+chst_bits],not XCHRUN+RCHRUN ;say interrupts both stopped
- or [si+chst_bits],TXWALERT ;and we are waiting for alert
- jmp short mstout
- mstcts: test bp,IS_CTSMODE ;see if CTS flow control enabled?
- jz mstout
- test bp,IS_TXINT ;see if transmit interrupts
- jz mstout ;are enabled?
- test ah,DCTS ;did CTS change?
- jz mstout ;if so disable or enable tx interrupts
- test ah,CTS ;did it just go true
- jz stoptx ;if not stop xmit ints
- mov dx,LSREG ; now wait for tx holding to empty
- add dx,cx
- wloop3: in al,dx
- KILL_TIME
- and al,THRE ; is tx holding empty?
- jz wloop3
- RESTARTTX
- and [si+chst_bits],not TXWCTS ;and not waiting for CTS
- jmp short mstout ;leave modem status change
- stoptx: in al,dx ;come here to stop tx-interrupts
- KILL_TIME
- and [si+chst_bits],not TXIFLAG
- and [si+chst_bits],not XCHRUN ;say tx interrupts stopped
- or [si+chst_bits],TXWCTS ;and we are waiting for CTS
- mstout: ret
-
- ;==>-- Transmit holding register empty interrupt handler
- ;
- asictx:
- if TXIFLAG
- test [si+chst_bits],TXIFLAG
- jz stopxm
- endif
- test [si+chst_bits],TXEMPTY ;see if TX buffer empty
- jnz stopxm ;if transmit is empty stop it
- test [si+chst_bits],TXWXON ;tx waiting for xon?
- jnz txout
- lea di,[si+tx_cell] ;else go get next character
- call _remove ;to al
- jnz txnomt ;if not empty take jump
- or [si+chst_bits],TXEMPTY ;say it is now empty
- txnomt: and [si+chst_bits],not TXFULL
- mov dx,[si+base_8250] ;dx=8250 base address
- out dx,al ;send character
- KILL_TIME
- jmp short txout
- stopxm:
- and [si+chst_bits],not XCHRUN+TXIFLAG ;say not running any more
- txout: ret
-
- ;==>-- Receive character ready interrupt handler
- ;
- asicrx: mov cx,dx ;save 8250 base in cx
- in al,dx ;clear condition
- KILL_TIME
- inc [si+rx_accum] ;increment accumulator
- test [si+chst_bits],RXFULL ;see if rx buffer is full
- jz rx0 ;if not full take jump
- or [si+chst_bits],RXOVFLOW ;else say overflow
- jmp rxrts
- rx0: mov bp,[si+chmode_bits] ;put in bp for speed
- test bp,IS_IGCD+IS_IGDSR+IS_IGALERT+IS_XOFFMODE+IS_RCHKING ;**2.10
- ;;; jz rx5 ;**2.10 skip numerous test
- jnz rx0a ;jump sequences if features
- jmp rx5 ;are not used
-
- rx0a: test bp,IS_IGCD ;are we ignoring CD
- jz rx1 ;if so take jump
- test [si+wide_stat],RLSD ;see if it is active
- jnz rx1
- jmp rxout
- ;;; jz rxout ;if not get out
- rx1: test bp,IS_IGDSR ;are we ignoring DSR?
- jz rx2 ;if so don't test it
- test [si+wide_stat],DSR ;is it active
- jnz rx2
- jmp rxout
- ;;; jz rxout ;if not get out
- rx2: test bp,IS_IGALERT ;are we ignoring alert?
- jz rx3 ;if so get out
- test [si+chst_bits],ALERT ;see if alert set
- jz rx3
- jmp rxout
- ;;; jnz rxout ;if so get out
- rx3: test bp,IS_XOFFMODE ;see if in xon/xoff mode
- jz rx4 ;if not skip around
- add dx,INTER ;dx=interrupt enable register
- cmp al,byte ptr[si+stop_xmt] ;is this the stop character
- jnz rx3a ;if not check for on character
- and [si+chst_bits],not TXIFLAG
- or [si+chst_bits],TXWXON ;set status bit
- and [si+chst_bits],not XCHRUN ;say transmit not running
- jmp rxout ;get out
- rx3a: cmp al,byte ptr[si+start_xmt] ;is this the start character
- jnz rx4 ;if not take jump
- test bp,IS_TXINT ;should tx interrupts be on
- jz rx4 ;if not don't re-enable them
- mov dx,LSREG ; now wait for tx holding to empty
- add dx,cx
- wloop5: in al,dx
- KILL_TIME
- and al,THRE ; is tx holding empty?
- jz wloop5
- RESTARTTX
- and [si+chst_bits],not TXWXON ;reset status bit
- jmp rxout ;get out
- rx4: test bp,IS_RCHKING ;are we rchking
- jz rx5 ;if not take quick way out
- lea di,[si+chkchr_1] ;start with #1
- mov cx,3 ;and check 3 characters
- rchlop: mov bx,[di] ;read value from structure
- test bx,RCHKENABLED ;is this position checking
- jz rchnom ;if not do next
- cmp al,bl ;do characters match
- jnz rchnom
- and bh,high RCHKVAL ;mask out all but mode
- jnz rx4a
- jmp rxout
- ;;; jz rxout ;if discarding just get out
- rx4a: or [di],RCHKFLAG ;1&2 both set flags so set now
- dec bh
- jnz rx5
- jmp rxout
- ;;; jz rxout ;if 1 discard
- ;;; jmp rx5
- rchnom: add di,2 ;check next character
- loop rchlop ;till all 3 checked
- rx5: lea di,[si+rx_cell] ;put character in queue
- and [si+chst_bits],not RXEMPTY ;say rx not empty
- mov ah,byte ptr[si+wide_stat]
- and byte ptr[si+wide_stat],0f0h ;**2.04
- call insert
- jnz rnfull ;if not full
- or [si+chst_bits],RXFULL ;else say full
- rnfull: test bp,IS_XOFFMODE+IS_RTSCONTROL ;**2.10 eliminate test/jumps
- ;;; jz rxout ;**2.10 and get out if
- jnz cxorts ;possible
- jmp short rxout
- cxorts: test bp,IS_XOFFMODE ;are we in xon/xoff mode?
- jz rxrts ;if not skip this
- test [si+chst_bits],XOFFSENT ;has it already been sent?
- jnz rxrts
- mov ax,[si+rx_count] ;get rx character count
- cmp ax,[si+rx_hiwater] ;see if below high water mark
- jnb rxsxof
- jmp short rxout ;if so don't send xoff
- rxsxof: mov cx,[si+base_8250]
- mov dx,LSREG
- add dx,cx
- or [si+chst_bits],XOFFSENT ;say XOFF sent
- xoflop: in al,dx ;wait till transmitter empty
- KILL_TIME
- and al,THRE
- jz xoflop
- mov dx,cx
- mov ax,[si+stop_rem_xmt] ;get character to send
- out dx,al ;and send it out
- KILL_TIME
- rxrts: test bp,IS_RTSCONTROL ;are we controlling RTS?
- jz rxout
- test [si+chst_bits],RTSACTIVE ;is RTS asserted?
- jz rxout ;if not then nothing to do
- mov cx,[si+rx_count] ;get rx character count
- cmp cx,[si+rts_hiwater]
- jb rxout ;if rx_count<rts_hiwater
- and [si+chst_bits],not RTSACTIVE ;say RTS de-asserted
- mov dx,[si+base_8250] ;and de-assert RTS
- add dx,MCREG
- in al,dx
- KILL_TIME
- and al,not RTS
- out dx,al
- KILL_TIME
- rxout: ret
-
- ;==>-- Special receive condition interrupt handler
- ;
- asicrs: mov cx,dx
- add dx,LSREG ;point to line status
- in al,dx ;read the reason we are here
- KILL_TIME
- mov ah,al
- not ah
- mov dx,INTER
- add dx,cx ;dx = interrupt enable register
- or [si+line_stat],ax ;update static status byte
- not ah
- mov bx,[si+wide_stat] ;save status bits for wide track
- and bl,0f0h ;set bits 0-3 to 0
- and ah,0eh ;strip unwanted bits in ah
- or bl,ah ;and merge into bl
- mov [si+wide_stat],bx ;and save it back
- or [si+chst_bits],LINERRG ;say we had a line status change
- mov bp,[si+chmode_bits] ;let bp hold these for speed
- test bp,IS_IGRCVER ;see if we are ignoring modem
- jz lstout ;status changes?
- or [si+chst_bits],ALERT ;set alert bit if not
- test bp,IS_IGALERT ;are we ignoring alert conditions?
- jz lstout ;if so get out
- in al,dx ;come here to stop tx & rx interrupts
- KILL_TIME
- and al,not ENRX
- out dx,al
- KILL_TIME
- and [si+chst_bits],not TXIFLAG
- out dx,al
- KILL_TIME
- and [si+chst_bits],not XCHRUN+RCHRUN ;say interrupts both stopped
- or [si+chst_bits],TXWALERT ;and we are waiting for alert
- lstout: ret
-
- ;==>-- Defined below is the entry point for 16 interrupt service
- ; routines.
- ;
- serv0: push ax ;COM1:
- push cx ;**2.04
- xor ax,ax
- mov cx,35 ;**2.04
- jmp servcommon
-
- serv1: push ax ;COM2:
- push cx ;**2.04
- mov ax,1 * TABLESIZE
- mov cx,34 ;**2.04
- jmp servcommon
-
- serv2: push ax ;COM3:
- push cx ;**2.04
- mov ax,2 * TABLESIZE
- mov cx,33 ;**2.04
- jmp servcommon
-
- serv3: push ax ;COM4:
- push cx ;**2.04
- mov ax,3 * TABLESIZE
- mov cx,32 ;**2.04
- jmp servcommon
-
- serv4: push ax ;COM5:
- push cx ;**2.04
- mov ax,4 * TABLESIZE
- mov cx,31 ;**2.04
- jmp servcommon
-
- serv5: push ax ;COM6:
- push cx ;**2.04
- mov ax,5 * TABLESIZE
- mov cx,30 ;**2.04
- jmp servcommon
-
- serv6: push ax ;COM7:
- push cx ;**2.04
- mov ax,6 * TABLESIZE
- mov cx,29 ;**2.04
- jmp servcommon
-
- serv7: push ax ;COM8:
- push cx ;**2.04
- mov ax,7 * TABLESIZE
- mov cx,28 ;**2.04
- jmp servcommon
-
- serv8: push ax ;COM9:
- push cx ;**2.04
- mov ax,8 * TABLESIZE
- mov cx,27 ;**2.04
- jmp servcommon
-
- serv9: push ax ;COM10:
- push cx ;**2.04
- mov ax,9 * TABLESIZE
- mov cx,26 ;**2.04
- jmp servcommon
-
- serv10: push ax ;COM11:
- push cx ;**2.04
- mov ax,10 * TABLESIZE
- mov cx,25 ;**2.04
- jmp servcommon
-
- serv11: push ax ;COM12:
- push cx ;**2.04
- mov ax,11 * TABLESIZE
- mov cx,24 ;**2.04
- jmp servcommon
-
- serv12: push ax ;COM13:
- push cx ;**2.04
- mov ax,12 * TABLESIZE
- mov cx,23 ;**2.04
- jmp servcommon
-
- serv13: push ax ;COM14:
- push cx ;**2.04
- mov ax,13 * TABLESIZE
- mov cx,22 ;**2.04
- jmp servcommon
-
- serv14: push ax ;COM15:
- push cx ;**2.04
- mov ax,14 * TABLESIZE
- mov cx,21 ;**2.04
- jmp servcommon
-
- serv15: push ax ;COM16:
- push cx ;**2.04
- mov ax,15 * TABLESIZE
- mov cx,20 ;**2.04
- jmp servcommon
-
- serv16: push ax ;COM17:
- push cx ;**2.04
- mov ax,16 * TABLESIZE
- mov cx,19 ;**2.04
- jmp servcommon
-
- serv17: push ax ;COM18:
- push cx ;**2.04
- mov ax,17 * TABLESIZE
- mov cx,18 ;**2.04
- jmp servcommon
-
- serv18: push ax ;COM19:
- push cx ;**2.04
- mov ax,18 * TABLESIZE
- mov cx,17 ;**2.04
- jmp servcommon
-
- serv19: push ax ;COM20:
- push cx ;**2.04
- mov ax,19 * TABLESIZE
- mov cx,16 ;**2.04
- jmp servcommon
-
- serv20: push ax ;COM21:
- push cx ;**2.04
- mov ax,20 * TABLESIZE
- mov cx,15 ;**2.04
- jmp servcommon
-
- serv21: push ax ;COM22:
- push cx ;**2.04
- mov ax,21 * TABLESIZE
- mov cx,14 ;**2.04
- jmp servcommon
-
- serv22: push ax ;COM23:
- push cx ;**2.04
- mov ax,22 * TABLESIZE
- mov cx,13 ;**2.04
- jmp short servcommon
-
- serv23: push ax ;COM24:
- push cx ;**2.04
- mov ax,23 * TABLESIZE
- mov cx,12 ;**2.04
- jmp short servcommon
-
-
- serv24: push ax ;COM25:
- push cx ;**2.04
- mov ax,24 * TABLESIZE
- mov cx,11 ;**2.04
- jmp short servcommon
-
- serv25: push ax ;COM26:
- push cx ;**2.04
- mov ax,25 * TABLESIZE
- mov cx,10 ;**2.04
- jmp short servcommon
-
- serv26: push ax ;COM27:
- push cx ;**2.04
- mov ax,26 * TABLESIZE
- mov cx,9 ;**2.04
- jmp short servcommon
-
- serv27: push ax ;COM28:
- push cx ;**2.04
- mov ax,27 * TABLESIZE
- mov cx,8 ;**2.04
- jmp short servcommon
-
- serv28: push ax ;COM29:
- push cx ;**2.04
- mov ax,28 * TABLESIZE
- mov cx,7 ;**2.04
- jmp short servcommon
-
- serv29: push ax ;COM30:
- push cx ;**2.04
- mov ax,29 * TABLESIZE
- mov cx,6 ;**2.04
- jmp short servcommon
-
- serv30: push ax ;COM31:
- push cx ;**2.04
- mov ax,30 * TABLESIZE
- mov cx,5 ;**2.04
- jmp short servcommon
-
- serv31: push ax ;COM32:
- push cx ;**2.04
- mov ax,31 * TABLESIZE
- mov cx,4 ;**2.04
- jmp short servcommon
-
- serv32: push ax ;COM33:
- push cx ;**2.04
- mov ax,32 * TABLESIZE
- mov cx,3 ;**2.04
- jmp short servcommon
-
- serv33: push ax ;COM34:
- push cx ;**2.04
- mov ax,33 * TABLESIZE
- mov cx,2 ;**2.04
- jmp short servcommon
-
- serv34: push ax ;COM35:
- push cx ;**2.04
- mov ax,34 * TABLESIZE
- mov cx,1 ;**2.04
- jmp short servcommon
-
- servcommon:
- sti
- push dx
- push ds
- push si
- push bx
- push es
- push di
- push bp
- ifdef DSNOTHING
- mov bx,__commlib_DATA
- else
- mov bx,DGROUP
- endif
- mov ds,bx
- ifdef DEBUG_COUNTERS
- inc icnt ;This is normally not compiled, only
- endif ;to save overhead
- jmp [ihdptr]
- ;
- ; After the interrupts have all been serviced, the ISR branches back
- ; here to return to the program that was interrupted.
- ;
- servexit:
- ifdef DSNOTHING
- mov bx,__commlib_DATA
- else
- mov bx,DGROUP
- endif
- mov ds,bx
- ifdef DEBUG_COUNTERS
- inc ecnt ;This is normally not compiled
- endif
- mov srcher,al ;if we get here, we could not
- ;identify the port so we set a
- ;variable and get out
- pop bp
- pop di
- pop es
- pop bx
- pop si
- pop ds
- pop dx
- pop cx
- mov al,20h
- out 20h,al
- KILL_TIME
- pop ax
- iret
-
-
-
-
- ;==>-- interror() - see if interrupt routines have had an error
- ; searching for match in shared hardware.
- ;
- cproc interror,,,,,<NOSI,NODI>
- xor ax,ax
- xchg al,srcher
- cproce
-
- endps
- end
-
-