home *** CD-ROM | disk | FTP | other *** search
- ;**************************************************************************
- ;* AQUEDUCT vers 1.20, DOS *
- ;* Connects COM1 and COM2 in software. *
- ;* 6/1/90 *
- ;* by James W. Birdsall *
- ;* *
- ;* assembles under Turbo Assembler 1.0, 2.0 *
- ;* *
- ;* requires DOS 2.0 or higher *
- ;* *
- ;* This program is a small TSR that connects COM1 and COM2 in software. *
- ;* It is run from the command line with no arguments. After *
- ;* installation, setup and activation is performed with the program *
- ;* VALVE. *
- ;* *
- ;* This program can share an interrupt vector. It can be set to chain *
- ;* to the previous interrupt handler if examination of the serial port *
- ;* shows that no interrupt is pending. *
- ;* *
- ;**************************************************************************
-
- LOCALS
- .MODEL tiny
-
-
- ENVOFFSET EQU 2Ch
-
- INTERFACEINT EQU 0F1h
-
- BUFFERLENGTH EQU 8
- BUFFERLENMASK EQU 08h
- BUSY1READ EQU 01h
- BUSY1SEND EQU 02h
- BUSY2READ EQU 04h
- BUSY2SEND EQU 08h
-
-
- ; TO CHANGE FROM COM1 OR COM2, CHANGE THE FOLLOWING INTERRUPT AND PORT
- ; VALUES.
- COM1INT EQU 0Ch
- COM2INT EQU 0Bh
-
- COM1BASE EQU 3F8h
- COM1IER EQU 3F9h
- COM1IIR EQU 3FAh
- COM1LSR EQU 3FDh
-
- COM2BASE EQU 2F8h
- COM2IER EQU 2F9h
- COM2IIR EQU 2FAh
- COM2LSR EQU 2FDh
- ; END OF INTERRUPT AND PORT VALUES
-
-
- EOI EQU 20h
- EOIPORT EQU 20h
-
- RDAINT EQU 04h
- THREINT EQU 02h
- RDAENABLE EQU 01h
- BOTHENABLE EQU 03h
- OVERRUNMASK EQU 02h
- INTPENDMASK EQU 01h
-
-
- .CODE
- ORG 100h
- start:
- jmp Install ; jump to installation code
-
- ; DATA AREA
-
- errors dw 0
- int_B dd 0
- old_int_B dd 0
- int_C dd 0
- old_int_C dd 0
- PSPseg dw 0
- old_interface dd 0
- enabled db 0
- chain db 0
- one_in_head dw 0
- one_in_tail dw 0
- two_in_head dw 0
- two_in_tail dw 0
- busyflag db 0
- one_in db BUFFERLENGTH dup (?)
- two_in db BUFFERLENGTH dup (?)
-
-
- ; HANDLER FOR COM1 INTERRUPTS
-
- Com1handler:
- sti ; enable interrupts
- push ax ; preserve
- push bx
- push dx
-
- mov dx, COM1LSR ; check for overruns
- in al, dx
- test al, OVERRUNMASK
- jz @@NoOverrun ; if zero, OK
- inc cs:errors ; else increment ERRORS
- @@NoOverrun:
- mov dx, COM1IIR ; read interrupt id
- in al, dx
- test al, INTPENDMASK ; is our interrupt?
- jz @@Ours ; if zero, ours
- jmp @@NotOurs ; else not
- @@Ours:
- cmp al, RDAINT ; is received char?
- je @@Received
- cmp al, THREINT ; is send?
- je @@Transmit
- jmp @@SendEOI ; if unknown, send EOI
-
- @@Received:
- mov dx, COM1BASE ; read character
- in al, dx
- test cs:busyflag, BUSY2SEND ; is port 2 sending?
- jz @@OkToRead ; if zero, go ahead
- inc cs:errors ; else increment errors
- jmp @@SendEOI ; and send EOI
- @@OkToRead:
- or cs:busyflag, BUSY1READ ; set flag
- mov bx, cs:one_in_head ; get index
- mov cs:one_in + bx, al ; put char in buffer
- inc cs:one_in_head ; increment index
- test cs:one_in_head, BUFFERLENMASK ; check for index overflow
- jz @@ReadDone ; if no overflow, jump
- mov cs:one_in_head, 0 ; else zero index
- @@ReadDone:
- mov dx, COM2IER ; read interrupt enable
- in al, dx
- cmp al, BOTHENABLE ; THRE already on?
- je @@ReadDone2 ; do nothing
- mov al, BOTHENABLE ; else enable it
- xor cs:busyflag, BUSY1READ ; reset flag just before enabling int
- out dx, al
- jmp @@SendEOI ; and jump
- @@ReadDone2:
- xor cs:busyflag, BUSY1READ ; reset flag
- jmp @@SendEOI
-
- @@Transmit:
- test cs:busyflag, BUSY2READ ; is port 2 reading?
- jz @@OkToSend ; if zero, go ahead
- or cs:busyflag, BUSY1SEND
- jmp @@NoTrans ; otherwise shut down sending
- @@OkToSend:
- or cs:busyflag, BUSY1SEND ; set flag
- mov bx, cs:two_in_tail ; set index
- cmp bx, cs:two_in_head ; are chars to send?
- je @@NoTrans ; if not, shut down sending
- mov al, cs:two_in + bx ; else move char to AL
- mov dx, COM1BASE
- out dx, al
- inc cs:two_in_tail ; increment index
- test cs:two_in_tail, BUFFERLENMASK ; check for overflow
- jz @@SentOK ; if no overflow, jump
- mov cs:two_in_tail, 0 ; else zero index
- @@SentOK:
- xor cs:busyflag, BUSY1SEND ; reset flag
- jmp @@SendEOI
- @@NoTrans:
- mov dx, COM1IER ; read interrupt enable
- in al, dx
- cmp al, RDAENABLE ; RDA only already?
- je @@NoTrans2 ; if so, do nothing
- mov al, RDAENABLE ; else enable RDA only
- out dx, al
- jmp @@NoTrans2 ; and jump
- @@NoTrans2:
- xor cs:busyflag, BUSY1SEND ; reset flag
- jmp @@SendEOI ; and jump
-
- @@NotOurs:
- test cs:chain, 0FFh ; is chain zero?
- jz @@SendEOI ; if so, return normally
- pushf ; preserve flags
- call cs:old_int_C ; call old handler
- jmp @@Final ; and return
-
- @@SendEOI:
- mov al, EOI ; send EOI
- out EOIPORT, al
-
- @@Final:
- pop dx ; restore
- pop bx
- pop ax
- iret ; return
-
-
- ; HANDLER FOR COM2 INTERRUPTS
-
- Com2handler:
- sti ; enable interrupts
- push ax ; preserve
- push bx
- push dx
-
- mov dx, COM2LSR ; check for overruns
- in al, dx
- test al, OVERRUNMASK
- jz @@NoOverrun ; if zero, OK
- inc cs:errors ; else increment ERRORS
- @@NoOverrun:
- mov dx, COM2IIR ; read interrupt id
- in al, dx
- test al, INTPENDMASK ; is our interrupt?
- jz @@Ours ; if zero, ours
- jmp @@NotOurs ; else not
- @@Ours:
- cmp al, RDAINT ; is received char?
- je @@Received
- cmp al, THREINT ; is send?
- je @@Transmit
- jmp @@SendEOI ; if unknown, send EOI
-
- @@Received:
- mov dx, COM2BASE ; read character
- in al, dx
- test cs:busyflag, BUSY1SEND ; is port 1 sending?
- jz @@OkToRead ; if zero, go ahead
- inc cs:errors ; else increment errors
- jmp @@SendEOI ; and send EOI
- @@OkToRead:
- or cs:busyflag, BUSY2READ ; set flag
- mov bx, cs:two_in_head ; get index
- mov cs:two_in + bx, al ; put char in buffer
- inc cs:two_in_head ; increment index
- test cs:two_in_head, BUFFERLENMASK ; check for index overflow
- jz @@ReadDone ; if no overflow, jump
- mov cs:two_in_head, 0 ; else zero index
- @@ReadDone:
- mov dx, COM1IER ; read interrupt enable
- in al, dx
- cmp al, BOTHENABLE ; THRE already on?
- je @@ReadDone2 ; do nothing
- mov al, BOTHENABLE ; else enable it
- out dx, al
- jmp @@ReadDone2 ; and jump
- @@ReadDone2:
- xor cs:busyflag, BUSY2READ ; reset flag
- jmp @@SendEOI ; and jump
-
- @@Transmit:
- test cs:busyflag, BUSY1READ ; is port 1 reading?
- jz @@OkToSend ; if zero, go ahead
- or cs:busyflag, BUSY2SEND ; set flag
- jmp @@NoTrans ; otherwise shut down sending
- @@OkToSend:
- or cs:busyflag, BUSY2SEND ; set flag
- mov bx, cs:one_in_tail ; set index
- cmp bx, cs:one_in_head ; are chars to send?
- je @@NoTrans ; if not, shut down sending
- mov al, cs:one_in + bx ; else move char to AL
- mov dx, COM2BASE
- out dx, al
- inc cs:one_in_tail ; increment index
- test cs:one_in_tail, BUFFERLENMASK ; check for overflow
- jz @@SentOK ; if no overflow, jump
- mov cs:one_in_tail, 0 ; else zero index
- jmp @@SentOK ; and jump
- @@SentOK:
- xor cs:busyflag, BUSY2SEND ; reset flag
- jmp @@SendEOI
- @@NoTrans:
- mov dx, COM2IER ; read interrupt enable
- in al, dx
- cmp al, RDAENABLE ; RDA only already?
- je @@NoTrans2 ; if so, do nothing
- mov al, RDAENABLE ; else enable RDA only
- out dx, al
- jmp @@NoTrans2 ; and jump
- @@NoTrans2:
- xor cs:busyflag, BUSY2SEND ; reset flag
- jmp @@SendEOI ; and jump
-
- @@NotOurs:
- test cs:chain, 0FFh ; is chain zero?
- jz @@SendEOI ; if so, return normally
- pushf ; preserve flags
- call cs:old_int_B ; call old handler
- jmp @@Final ; and return
-
- @@SendEOI:
- mov al, EOI ; send EOI
- out EOIPORT, al
-
- @@Final:
- pop dx ; restore
- pop bx
- pop ax
- iret ; return
-
-
- ; SIGNATURE USED FOR INSTALLATION CHECK
-
- signature db 'JWBA12'
-
-
- ; INTERFACE INTERRUPT HANDLER -- RETURNS POINTER TO DATA AREA
-
- Interface:
- mov ax, cs ; put segment in AX
- mov bx, offset errors ; put offset in BX
- iret ; and return
-
-
- ; INSTALLATION CODE -- IS DISCARDED AFTER INSTALLATION
-
- Last_byte:
-
- OKmessage db 'AQUEDUCT installed OK.',0Dh,0Ah,'$'
- FAILmessage db 'AQUEDUCT installation error.',0Dh,0Ah,'$'
- COPYRIGHT db 'Copyright (c) 1990 James W. Birdsall.'
- COPYRIGHT2 db 'All Rights Reserved.'
-
- Install:
- mov bx, es ; copy PSP segment from ES to BX
- mov PSPseg, bx ; put into storage
- mov si, ENVOFFSET
- mov ax, es:si ; move environment segment into AX
- or ax, ax ; check it
- jz Continue ; if zero, no environment
- mov es, ax ; put env seg in ES
- mov ah, 49h ; free block
- int 21h
- jc Fail ; if carry set, error
- Continue:
- ; put far ptrs to handlers in storage
- mov WORD PTR [int_B], offset Com2handler
- mov WORD PTR [int_C], offset Com1handler
- mov ax, cs
- mov WORD PTR [int_B+2], ax
- mov WORD PTR [int_C+2], ax
-
- mov ah, 35h ; get old int 0Bh vector
- mov al, 0Bh
- int 21h
- mov WORD PTR [old_int_B], bx ; and put in old_int_B
- mov bx, es
- mov WORD PTR [old_int_B+2], bx
-
- mov ah, 35h ; get old int 0Ch vector
- mov al, 0Ch
- int 21h
- mov WORD PTR [old_int_C], bx ; and put in old_int_C
- mov bx, es
- mov WORD PTR [old_int_C+2], bx
-
- mov ah, 35h ; get old interface vector
- mov al, INTERFACEINT
- int 21h
- mov WORD PTR [old_interface], bx ; and put in old_interface
- mov bx, es
- mov WORD PTR [old_interface+2], bx
- mov ah, 25h ; set up interface
- mov al, INTERFACEINT
- mov dx, offset Interface
- int 21h
-
- mov ah, 09h ; print OK message
- mov dx, offset OKmessage
- int 21h
-
- mov dx, offset Last_byte ; go resident with code 0
- add dx, 15
- mov cl, 4
- shr dx, cl
- mov ah, 31h
- xor al, al
- int 21h
- Fail:
- mov ah, 09h ; print FAIL message
- mov dx, offset FAILmessage
- int 21h
-
- mov ah, 4Ch ; exit with code 3
- mov al, 3
- int 21h
- END start
- END