home *** CD-ROM | disk | FTP | other *** search
- page 55,132
- title COMM - Device drivers for COM1 and COM2.
- subttl Parameter definitions:
- ;
- ; COMM.ASM - Installable device drivers for COM1 and COM2.
- ;
- ; All of this code originated at my dainty fingertips, and I won't be mad
- ; at anybody who wants to help himself to it. - Peter Pearson.
- ;
- ; Version of 20 June 1985.
- ;
- ; Revision history:
- ; 852005 - Send ^S when input buffer approaches fullness, ^Q when it
- ; is nearly empty again.
- ;
- cseg segment para public 'code'
- org 0
- ;
- ; Equates:
- ;
- CTRLS equ 19
- CTRLQ equ 17
-
- primary equ 3f8h ;Base address for primary asynch.
- secondary equ 2f8h ;Base address for secondary asynch.
- prim_int equ 0ch ;Hardware interrupt vector number.
- sec_int equ 0bh ;Hardware interrupt vector number.
- ;
- ;
- ; Description of the Serial Port:
- ;
- ; I/O I/O
- ; addr addr
- ; ---- ----
- ; 3F8 2F8 TX data, RX data, Div Latch LSB.
- ; 3F9 2F9 Interrupt Enable, Div Latch MSB.
- ; 7 6 5 4 3 2 1 0
- ; | | | | | | | \_ Data Available.
- ; | | | | | | \___ Xmit Holding Reg Empty.
- ; | | | | | \_____ Receiver Line Status.
- ; | | | | \_______ Modem Status.
- ; | | | \_________ = 0.
- ; | | \___________ = 0.
- ; | \_____________ = 0.
- ; \_______________ = 0.
- ;
- ; 3FA 2FA Interrupt Identification.
- ; 7 6 5 4 3 2 1 0
- ; | | | | | \_\_\___________ 001 = no interrupt.
- ; | | | | | 110 = rcvr status.
- ; | | | | | 100 = rcvd data.
- ; | | | | | 010 = THR empty.
- ; | | | | | 000 = Modem status.
- ; | | | | \_______ = 0.
- ; | | | \_________ = 0.
- ; | | \___________ = 0.
- ; | \_____________ = 0.
- ; \_______________ = 0.
- ;
- ; 3FB 2FB Line Control.
- ; 7 6 5 4 3 2 1 0
- ; | | | | | | | \_ Word Length Select Bit 0.
- ; | | | | | | \___ Word Length Select Bit 1.
- ; | | | | | \_____ Number Stop Bits.
- ; | | | | \_______ Parity Enable.
- ; | | | \_________ Even Parity Select.
- ; | | \___________ Stick Parity.
- ; | \_____________ Set Break.
- ; \_______________ Divisor Latch Access Bit.
- ;
- ; 3FC 2FC Modem Control.
- ; 7 6 5 4 3 2 1 0
- ; | | | | | | | \_ Data Terminal Ready.
- ; | | | | | | \___ Request to Send.
- ; | | | | | \_____ Out 1.
- ; | | | | \_______ Out 2. (= 1 to enable ints.)
- ; | | | \_________ Loop.
- ; | | \___________ = 0.
- ; | \_____________ = 0.
- ; \_______________ = 0.
- ;
- ; 3FD 2FD Line Status.
- ; 7 6 5 4 3 2 1 0
- ; | | | | | | | \_ Data Ready.
- ; | | | | | | \___ Overrun Error.
- ; | | | | | \_____ Parity Error.
- ; | | | | \_______ Framing Error.
- ; | | | \_________ Break interrupt.
- ; | | \___________ Transmitter Holding Reg Empty.
- ; | \_____________ Transmitter Shift Reg Empty.
- ; \_______________ = 0.
- ;
- ; 3FE 2FE Modem Status.
- ; 7 6 5 4 3 2 1 0
- ; | | | | | | | \_ Delta Clear to Send.
- ; | | | | | | \___ Delta Data Set Ready.
- ; | | | | | \_____ Trailing Edge Ring Indicator.
- ; | | | | \_______ Delta Rx Line Signal Detect.
- ; | | | \_________ Clear to Send.
- ; | | \___________ Data Set Ready.
- ; | \_____________ Ring Indicator.
- ; \_______________ Receive Line Signal Detect.
- ;
- ;
- R_tx equ 0 ;UART data-to-transmit register.
- R_rx equ 0 ;UART received-data register.
- R_ie equ 1 ;UART interrupt-enable register.
- R_ii equ 2 ;UART interrupt-identification register.
- R_lc equ 3 ;UART Line-Control register.
- R_mc equ 4 ;UART Modem-Control register.
- R_ls equ 5 ;UART line-status register.
- LC_dlab equ 80h ;UART LC reg. DLAB bit.
- MC_dtr equ 1 ;UART MC reg. DTR bit.
- MC_rts equ 2 ;UART MC reg. RTS bit.
- MC_out2 equ 8 ;UART MC reg. "OUT2" bit.
- LS_dr equ 1 ;UART LS reg. "data ready" bit.
- LS_or equ 2 ;UART LS reg. "overrun error" bit.
- LS_pe equ 4 ;UART LS reg. "parity error" bit.
- LS_fe equ 8 ;UART LS reg. "framing error" bit.
- LS_bi equ 10h ;UART LS reg. "Break Interrupt" bit.
- LS_thre equ 20h ;UART LS reg. "Xmit Hold Reg empty" bit.
- LS_tsre equ 40h ;UART LS reg. "Xmit Shift Reg Empty" bit.
- IE_da equ 1 ;UART IE reg. "Data Available" bit.
- IE_thre equ 2 ;UART IE reg. "Xmit Hold Reg Empty" bit.
- IE_rls equ 4 ;UART IE reg. "Receive Line Status" bit.
- IE_ms equ 8 ;UART IE reg. "Modem Status" bit.
- II_never equ 0f8h ;UART II reg: these bits never on.
-
- ; Definitions for the Interrupt Controller Chip:
-
- ICC_msk equ 21h ;I/O address of ICC's "mask" register.
- ICC_ctl equ 20h ;I/O address of ICC's "control" reg.
- ICC_eoi equ 20h ;Non-specific end-of-interrupt.
- MSK_d1 equ 10h ;Bit in MSK: disable IRQ4 (COM1).
- MSK_d2 equ 08h ;Bit in MSK: disable IRQ3 (COM2).
-
- org 0 ;Define layout of Request Header:
- RH_rhlen db ? ;Length of Request Header (bytes).
- RH_unit db ? ;Unit code. (No meaning for char dev.)
- RH_command db ? ;Command code.
- RH_status dw ? ;Status.
- RH_reserved db 8 dup(?) ;Reserved for DOS.
- RH_char db ? ;Character of data.
- RH_end_addr label word ;Ending address for INIT call.
- RH_buf_addr dd ? ;Buffer address for INPUT or OUTPUT.
- RH_count dw ? ;Byte count for INPUT or OUTPUT.
- org 0
-
- STAT_err equ 8000h ;Req Hdr, status reg., "error" bit.
- STAT_busy equ 200h ;Req Hdr, status reg., "busy" bit.
- STAT_done equ 100h ;Req Hdr, status reg., "done" bit.
- S_E_unkunit equ 01h ;Req Hdr, status reg., "unknown unit" error code.
- S_E_not_rdy equ 02h ;Req Hdr, status reg., "not ready" error code.
- S_E_unkcom equ 03h ;Req Hdr, status reg., "unknown command" error code.
- S_E_write equ 0ah ;Req Hdr, status reg., "write fault" error code.
- S_E_read equ 0bh ;Req Hdr, status reg., "read fault" error code.
- S_E_general equ 0ch ;Req Hdr, status reg., "general failure" error code.
- page
- ;
- ; Equates relating to data structures:
- ;
- ; Buffers:
- ; --------
- ;
- ; When we talk about a "buffer" in this program, we're talking not
- ; just about the area of data storage, but about the pointers to that
- ; data area as well. Four pointers are expected to precede the first
- ; byte of data storage:
- ; BEGINNING - Offset of the first byte of data storage.
- ; END - Offset of the first byte AFTER data storage.
- ; IN - Offset at which next byte is to be put into buffer.
- ; OUT - Offset from which next byte is to be taken out
- ; of buffer.
- ; IN and OUT may range from BEGINNING to END-1. If IN = OUT, the
- ; buffer is empty.
- ; These definitions must be coordinated with the storage-allocation
- ; statements for the buffers near the end of this program (just before
- ; the INIT handler.)
- ;
- B_beg equ 0
- B_end equ 2
- B_in equ 4
- B_out equ 6
- B_data equ 8
- ;
- in_buf_len equ 2000 ;Length of input buffers.
- out_buf_len equ 100 ;Length of output buffers.
- near_full equ 1200 ;Input buffer is nearly full when it
- ; has more than this number of data
- ; bytes.
- near_empty equ 200 ;Input buffer is nearly empty when it
- ; has fewer than this number of data
- ; bytes.
- ;
- ;
- ; Unit Control Blocks:
- ; --------------------
- ;
- ; (I just made up that name. Any conflict with any other usage is
- ; unfortunate.)
- ; A UCB is assigned to each asynchronous communications device
- ; (COM) we handle. (E.g., one for COM1, another for COM2.) The
- ; UCB contains
- ; BASE - The base I/O address for the hardware device.
- ; HOLD - XON/XOFF flag.
- ; HOLD & 1 nonzero means we have received a CTRLS.
- ; HOLD & 2 nonzero means we have sent a CTRLS.
- ; INBUF - An input buffer (as described above).
- ; OUTBUF - An output buffer (as described above).
- ;
- ; Take care to keep these definitions compatible with the actual
- ; allocation of these data areas near the end of this program (just
- ; before label "init:").
- ;
- U_base equ 0
- U_stat equ 2 ;Status bits, defined below.
- U_inbuf equ 4
- U_outbuf equ U_inbuf+B_data+in_buf_len
- U_totlen equ U_outbuf+B_data+out_buf_len
- ;
- ; Bits in U_stat:
- ;
- US_outhold equ 1 ;Host has sent us a "hold it".
- US_inhold equ 2 ;We have sent the host a "hold it".
- US_saywait equ 4 ;We need to send a "hold it".
- US_saygo equ 8 ;We need to send an "OK to send" (un-holdit).
- subttl Device Headers:
- page
- ;
- ; Here are the Device Headers:
- ;
- coms proc far
- assume cs:cseg,ds:cseg
- begin:
-
- next_dev1 dw DevHdr2 ;Pointer to next device.
- dw -1
- attribute1 dw 0c000h ;Attributes.
- strategy1 dw Com1Strat ;Pointer to "device strategy" entry.
- interrupt1 dw Com1Int ;Pointer to software "interrupt" entry.
- dev_name1 db 'COM1 '
-
- DevHdr2:
- next_dev2 dw -1 ;Pointer to next device.
- dw -1
- attribute2 dw 0c000h ;Attributes.
- strategy2 dw Com2Strat ;Pointer to "device strategy" entry.
- interrupt2 dw Com2Int ;Pointer to software "interrupt" entry.
- dev_name2 db 'COM2 '
- subttl Dispatch Table:
- page
- ;
- ; Here is the dispatch table:
- ;
- dispatch label byte
- dw init ;Initialization.
- dw MediaCheck ;Media check (block devices only).
- dw BuildBPB ;Build BPB (block devices only).
- dw IoctlIn ;IOCTL input.
- dw input ;input (read).
- dw NDInput ;Non-destructive input, no wait.
- dw InStat ;Status for input.
- dw InFlush ;Input flush.
- dw output ;Output (write).
- dw OutVerify ;Output with verify.
- dw OutStat ;Status for output.
- dw OutFlush ;Output flush.
- dw IoctlOut ;IOCTL output.
- subttl Entry points:
- page
- ;
- ; Device "Strategy" entry points:
- ;
- Com1Strat:
- Com2Strat:
- mov cs:ReqHdrSeg,es ;Segment of Request Header Pointer.
- mov cs:ReqHdrOff,bx ;Offset of Request Header Pointer.
- ret
- ;
- ; Device "Interrupt" entry points:
- ;
- Com1Int: push ax
- push bx
- xor al,al ;Unit # for COM1 is 0.
- mov bx,offset UCB1
- jmp JointInt
-
- Com2Int: push ax
- push bx
- mov al,1 ;Unit # for COM2 is 1.
- mov bx,offset UCB2
-
- JointInt:
- push cx
- push dx
- push di
- push si
- push ds
- push es
-
- push cs
- pop ds ;DS = CS.
-
- mov unit,al ;Save unit number.
- mov dx,[bx] ;DX = base address for appropriate card.
- les bx,ReqHdr ;Load ES and BX pointers to Request Hdr.
- ;
- ; Dispatch through the Dispatch Table:
- ;
- mov al,es:[bx]+RH_command ;Get function byte.
- rol al,1
- lea di,dispatch
- xor ah,ah
- add di,ax ;Jump through dispatch table +
- jmp word ptr[di] ; 2 * function code.
- subttl Return paths:
- page
- ;
- ; Return "Unknown Unit" error code.
- ;
- BadUnit: mov ax,STAT_err+STAT_done+S_E_unkunit
- jmp SetStat
- ;
- ; Return "done" status.
- ;
- NormalDone: mov ax,STAT_done
- ;
- ; Store AX in the STATUS word of the Request Header, then restore registers
- ; and return.
- ;
- SetStat: lds bx,cs:ReqHdr
- mov [bx]+RH_status,ax
- ;
- ; Restore the original registers and return.
- ;
- RestRegsRet:
- pop es
- pop ds
- pop si
- pop di
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- subttl Command processors:
- page
- ;
- ; IOCTL input.
- ; Do the requested function.
- ; Set the actual number of bytes transferred.
- ; Set the status word in the Request header.
- ;
- IoctlIn:
- call CheckUnit
- jc BadUnit
- jmp NormalDone
- page
- ;
- ; Input.
- ; Do the requested function.
- ; Set the actual number of bytes transferred.
- ; Set the status word in the Request header.
- ;
- input:
- mov cx,es:[bx]+RH_count ;CX = # bytes to transfer.
- jcxz NormalDone
- les di,es:[bx]+RH_buf_addr ;ES:DI points to destination.
- call GetBase
- jc BadUnit
- call EnabInt
- add bx,U_inbuf ;BX -> appropriate input buffer.
- cld
- input1: call TakeByte ;Get byte in AL.
- jnc input6 ;Jump if no more chars avail.
- stosb ;Store in es:[di++].
- loop input1 ;Continue.
- input6:
- mov ax,[bx]+U_stat-U_inbuf
- test ax,US_inhold
- jz input8 ;If the "I've sent CTRLS" flag
- call UsedBuff ; is set and there are fewer
- cmp ax,near_empty ; than near_empty data bytes
- jns input8 ; in the buffer, make a note
- ; to send a CTRLQ.
- or word ptr [bx]+U_stat-U_inbuf,US_saygo
- input8:
- or cx,cx ;If we didn't transfer the
- jz NormalD2 ; requested number of chars,
- les bx,ReqHdr ; calculate the number of
- mov ax,es:[bx]+RH_count ; characters moved and store
- sub ax,cx ; it in the Request Header.
- mov es:[bx]+RH_count,ax ;
- mov ax,STAT_done+STAT_busy ;Return BUSY.
- jmp SetStat
- page
- ;
- ; Non-Destructive Input, No Wait.
- ; Return a byte from the device.
- ; Set the status word in the Request Header.
- ;
- NDInput:
- call GetBase
- jc BadUnit
- call EnabInt
- add bx,U_inbuf ;BX -> appropriate input buff.
- mov ax,[bx]+B_in ;Examine buffer's pointers.
- cmp ax,[bx]+B_out
- jz ndin1 ;Jump if buffer empty.
- mov si,ax
- mov al,[si] ;Fetch a character.
- mov cx,STAT_done
- jmp ndin2
-
- ndin1: xor al,al ;No character available.
- mov cx,STAT_done+STAT_busy
-
- ndin2: les bx,ReqHdr
- mov es:[bx]+RH_char,al
- mov ax,cx
- jmp SetStat
- page
- ;
- ; Status for Input.
- ; Perform the operation.
- ; Set the status word in the Request Header.
- ;
- InStat:
- call GetBase
- jc BadUnit2
- add bx,U_inbuf ;BX -> appropriate input buff.
- mov ax,STAT_done
- mov cx,[bx]+B_in ;Examine buffer's pointers.
- cmp cx,[bx]+B_out
- jnz inst1 ;Jump if buffer not empty.
- or ax,STAT_busy ;If empty, say "busy".
- inst1: jmp SetStat
- ;
- ; Input Flush.
- ; Perform the operation.
- ; Set the status word in the Request Header.
- ;
- InFlush:
- call GetBase ;BX -> appropriate input buff.
- jc BadUnit2
- add bx,U_inbuf
- mov ax,[bx]+B_in ;Set the "out" pointer equal to
- mov [bx]+B_out,ax ; the "in" pointer.
- NormalD2: jmp NormalDone
- page
- ;
- ; Output (write) and Output with Verify.
- ; Do the requested function.
- ; Set the actual number of bytes transferred.
- ; Set the status word in the Request header.
- ;
- output:
- OutVerify:
- mov cx,es:[bx]+RH_count ;CX = # bytes to transfer.
- jcxz NormalD2
- les si,es:[bx]+RH_buf_addr ;ES:SI points to source.
- call GetBase
- jc BadUnit2
- add bx,U_outbuf ;BX -> appropriate output buf.
- cld
- output1: lods es:byte ptr [si] ;Get 1 char in AL.
- call PutByte ;Put character in output buff.
- jnc output8 ;Jump if no room in output buffer.
- loop output1
- output8: sub bx,U_outbuf ;BX -> appropriate UCB.
- call EnabInt ;Enable interrupts, if approp.
- or cx,cx ;If we didn't transfer the
- jz NormalD2 ; requested number of chars,
- les bx,ReqHdr ; calculate the number of
- mov ax,es:[bx]+RH_count ; characters moved and store
- sub ax,cx ; it in the Request Header.
- mov es:[bx]+RH_count,ax ;
- mov ax,STAT_done+STAT_busy ;Return BUSY.
- jmp SetStat
- BadUnit2: jmp BadUnit
- page
- ;
- ; Status for Output.
- ; Perform the operation.
- ; Set the status word in the Request Header.
- ;
- OutStat:
- call GetBase
- jc BadUnit2
- add bx,U_outbuf ;BX -> appropriate output buf.
- call IsRoom ;Is there room in the buffer?
- mov ax,STAT_done
- jc outst1 ;Jump if buffer not full.
- or ax,STAT_busy ;If full, say "busy".
- outst1: jmp SetStat
- ;
- ; Output Flush.
- ; Perform the operation.
- ; Set the status word in the Request Header.
- ;
- OutFlush:
- call CheckUnit
- jc BadUnit2
- jmp NormalDone
- ;
- ; IOCTL output.
- ; Do the requested function.
- ; Set the actual number of bytes transferred.
- ; Set the status word in the Request header.
- ;
- IoctlOut:
- call CheckUnit
- jc BadUnit2
- jmp NormalDone
- page
- ;
- ; Entry points for functions not implemented:
- ;
- NotImplemented:
- MediaCheck:
- BuildBPB:
- mov ax,STAT_err+STAT_done+S_E_unkcom
- jmp SetStat
- subttl Interrupt handlers:
- page
- ;
- ; Hardware interrupt handlers.
- ; We run with two interrupts enabled:
- ; Data Available
- ; Transmit Holding Register Empty.
- ;
- ; If Data Available is set
- ; If there's room in the IN buffer, put the byte there.
- ; If there are data in the OUT buffer,
- ; If the Transmit Holding Register is empty, output a byte.
- ;
- Hdw1Int:
- push ax
- mov ax,offset UCB1
- jmp HdwInt
-
- Hdw2Int:
- push ax
- mov ax,offset UCB2
-
- HdwInt:
- push bx
- push ds
- push cx
- push dx
- push di
- push si
- push es
-
- push cs
- pop ds
-
- mov bx,ax
- mov di,[bx] ;DI = base I/O address.
- lea dx,R_lc[di]
- in al,dx ; the Line Control Register.
- and al,255-LC_dlab
- out dx,al
- lea dx,R_ls[di]
- in al,dx ;Read the Line Status Reg.
- test al,LS_dr ;"Data Ready" set?
- jz HdwI2
- push ax
- call ReadByte ;Process the incoming byte.
- pop ax
- HdwI2: test al,LS_thre ;"Xmit Holding Reg Empty" set?
- jz HdwI3
- ;If we want to send a CTRLS or
- ; CTRLQ to the host, this is our
- ; chance to do it.
- ;Note that, if both are set, the
- ; CTRLS is not sent.
- ;
- test word ptr [bx]+U_stat,US_saywait+US_saygo
- jz HdwI5
- test word ptr [bx]+U_stat,US_saygo
- jz HdwI6
- mov al,CTRLQ
- and word ptr [bx]+U_stat,0ffffh-(US_saywait+US_saygo+US_inhold)
- jmp HdwI7
- HdwI6: ;else
- mov al,CTRLS
- and word ptr [bx]+U_stat,0ffffh-(US_saywait+US_saygo)
- or word ptr [bx]+U_stat,US_inhold
- HdwI7: mov dx,di
- out dx,al
-
- jmp HdwI3
- ; If we get here, we didn't want to
- ; send a CTRLS or CTLRQ.
- HdwI5:
- test word ptr [bx]+U_stat,US_outhold
- jnz HdwI3 ;Jump if output held by CTRL-S.
- add bx,U_outbuf
- call TakeByte
- jnc HdwI4 ;Jump if nothing to output.
- mov dx,di
- out dx,al ;Output another character.
- HdwI4: sub bx,U_outbuf
- HdwI3: ;;;
- pop es
- pop si
- pop di
- pop dx
- pop cx
- cli
- mov al,ICC_eoi ;Issue "end-of-interrupt" command
- out ICC_ctl,al ; to the interrupt-controller chip.
- call EnabInt ;Re-enable interrupts at the UART.
- pop ds
- pop bx
- pop ax
- iret
- page
- ;
- ; Process an incoming character.
- ; Pick up the character in the device.
- ; If it's a CTRLS or CTRLQ,
- ; set or clear the "he said hold" flag for this device;
- ; otherwise
- ; put it into the buffer.
- ;
- ; Enter with:
- ; BX pointing to the UCB.
- ; DI containing the base address for the device.
- ;
- ; Clobbers: AX, DX.
- ;
- ; Side effects:
- ; May set or clear the low-order bit of the "hold" word
- ; for this device.
- ;
- ReadByte proc near
- lea dx,R_rx[di]
- in al,dx ;Read the data byte.
- cmp al,CTRLS ;Watch for XOFF and XON (CTRLS and
- jnz ReadB1 ; CTRLQ).
- mov ax,US_outhold
- or word ptr [bx]+U_stat,ax
- ret
-
- ReadB1: cmp al,CTRLQ
- jnz ReadB3
- and word ptr [bx]+U_stat,0ffffh-US_outhold
- ret
-
- ReadB3: add bx,U_inbuf
- call PutByte ;Put it into the buffer.
- call UsedBuff
- cmp ax,near_full ;If the buffer is getting full,
- js ReadB4 ; and we haven't already asked the
- ; host to wait, do that.
- test word ptr [bx]+U_stat-U_inbuf,US_inhold
- jnz ReadB4
- or word ptr [bx]+U_stat-U_inbuf,US_saywait
- ReadB4:
- sub bx,U_inbuf
- ret
- ReadByte endp
- subttl General-Purpose Subroutines:
- page
- ;
- ; General-purpose subroutines.
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Return a pointer to the "base" of the data block for this unit.
- ;
- ; Enter with: unit number (0 or 1) in the variable "unit".
- ; DS = CS.
- ;
- ; Returns: BX containing the offset of either UCB1 or UCB2.
- ;
- GetBase proc near
- call CheckUnit
- jnc gb0
- ret
- gb0: test al,0ffh
- jz gb1
- mov bx,offset UCB2
- ret
- gb1: mov bx,offset UCB1
- ret
- GetBase endp
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Check the unit number to make sure it's valid.
-
- ; Enter with:
- ; the variable "unit" set to the unit number to be checked;
- ; the variable "maxunit" set to the maximum unit number allowed.
- ;
- ; Returns with:
- ; "carry" condition set if "unit" < 0 or "unit" > "maxunit".
- ; AL = contents of the variable "unit".
- ;
- CheckUnit proc near
- mov al,unit
- or al,al
- js RetCarry
- test maxunit,080h
- jnz RetCarry
- cmp al,maxunit
- jg RetCarry
- clc
- ret
- RetCarry: stc
- ret
- CheckUnit endp
- page
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Take a byte out of a buffer and return it in AL.
- ;
- ; Enter with:
- ; BX pointing to the buffer from which a byte is to be taken.
- ;
- ; Returns:
- ; Carry condition and a byte in AL if the buffer was not empty,
- ; NoCarry condition if the buffer was empty.
- ;
- ; Side effect: The "output" pointer for the buffer is advanced to reflect
- ; the used-upness of the character taken.
- ;
- ; Note:
- ; Since this subroutine may be interrupted, it is important that
- ; the character be taken out of the buffer before the OUT pointer
- ; is advanced to reflect its absence.
- ;
- TakeByte proc near
- mov ax,[bx]+B_out ;Output pointer.
- cmp ax,[bx]+B_in ; = input pointer?
- jz tb9 ;If equal, buffer is empty.
- push si
- push cx
- mov si,ax
- mov cl,[si] ;Fetch the character.
- call advance ;Advance the "out" pointer.
- mov [bx]+B_out,ax ;Store updated ptr.
- mov al,cl
- pop cx
- pop si
- stc ;Set carry flag.
- tb9: ret
- TakeByte endp
- page
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Put a character into a buffer.
- ;
- ; Enter with:
- ; BX pointing to the beginning of a buffer,
- ; AL holding the character to be put into the buffer.
- ;
- ; Returns:
- ; NoCarry condition if the buffer is full (character couldn't be put).
- ; Carry condition if the character is successfully put into the buffer.
- ;
- ; Note:
- ; Since this subroutine may be interrupted, it is important that
- ; the character be put into the buffer before the IN pointer is
- ; adjusted to reflect its availablility.
- ;
- PutByte proc near
- push cx
- push di
- mov cl,al ;CL = the character.
- mov ax,[bx]+B_in
- mov di,ax ;DI = original IN pointer.
- call advance ;AX = updated IN pointer.
- cmp ax,[bx]+B_out
- jz pb9 ;Jump if buffer is full.
- mov [di],cl ;Store the character.
- mov [bx]+B_in,ax ;Update the pointer.
- stc
- pb9: pop di
- pop cx
- ret
- PutByte endp
- page
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Is there room in this buffer?
- ;
- ; Enter with BX pointing to the beginning of a buffer.
- ;
- ; Returns:
- ; NoCarry condition if the buffer is full,
- ; Carry condition if there is room in the buffer.
- ;
- IsRoom proc near
- mov ax,[bx]+B_in
- call advance
- cmp ax,[bx]+B_out
- jz ir9
- stc
- ir9: ret
- IsRoom endp
- ;
- ; ----------------------------------------------------------------------
- ;
- ; How many data bytes are in this buffer?
- ;
- ; Enter with BX pointing to the beginning of a buffer.
- ;
- ; Returns:
- ; AX containing the number of bytes used in the buffer.
- ; Z flag set if AX contains 0.
- ;
- UsedBuff proc near
- mov ax,[bx]+B_in
- sub ax,[bx]+B_out
- jns ub9
- add ax,[bx]+B_end
- sub ax,[bx]+B_beg
- ub9: ret
- UsedBuff endp
- page
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Advance a buffer pointer.
- ;
- ; Enter with
- ; BX pointing to the beginning of the buffer.
- ; AX containing a pointer into the buffer.
- ;
- ; Returns with
- ; AX incremented by one, wrapped to the beginning of the buffer
- ; if necessary.
- ;
- advance proc near
- inc ax
- cmp ax,[bx]+B_end
- jnz adv9
- mov ax,[bx]
- adv9: ret
- advance endp
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Reset the input-buffer pointers for one unit.
- ;
- ; Enter with BX pointing to the Unit Control Block for the unit whose input-
- ; buffer pointers are to be cleared.
- ;
- ResInbuf proc near
- mov ax,[bx]+U_inbuf+B_beg
- mov [bx]+U_inbuf+B_in,ax
- mov [bx]+U_inbuf+B_out,ax
- ret
- ResInbuf endp
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Reset the output-buffer pointers for one unit.
- ;
- ; Enter with BX pointing to the Unit Control Block for the unit whose output-
- ; buffer pointers are to be cleared.
- ;
- ResOutbuf proc near
- mov ax,[bx]+U_outbuf+B_beg
- mov [bx]+U_outbuf+B_in,ax
- mov [bx]+U_outbuf+B_out,ax
- ret
- ResOutbuf endp
- page
- ;
- ; ----------------------------------------------------------------------
- ;
- ; Enable appropriate interrupts.
- ;
- ; Enter with:
- ; BX pointing to the Unit Control Block controlling the device
- ; whose interrupts are to be enabled.
- ;
- EnabInt proc near
- push cx
- push dx
- push di
- xor cx,cx
- add bx,U_inbuf
- call IsRoom
- jnc ei1 ;If there's room in the input buffer,
- or cl,IE_da ; enable "data available" interrupt.
- ei1: sub bx,U_inbuf
-
- ;Enable the "transmit holding register
- ; empty" interrupt if:
- ; - there's something in the output
- ; buffer, and output is not being
- ; "held"; or
- ; - we want to send a CTRLS or CTRLQ.
-
- mov ax,[bx]+U_outbuf+B_in
- cmp ax,[bx]+U_outbuf+B_out
- mov ax,[bx]+U_stat
- jz ei2
- test ax,US_outhold
- jz ei4
- ei2: ;;;
- test ax,US_saygo+US_saywait
- jz ei3
- ei4: or cl,IE_thre
- ei3:
- mov di,[bx]
- lea dx,R_lc[di]
- in al,dx ;Turn off DLAB (just in case).
- and al,255-LC_dlab
- out dx,al
- lea dx,R_ie[di]
- mov al,0
- out dx,al ;Interrupt Enable = 0 (to ensure a
- mov al,cl ; transition).
- out dx,al ;Set final Interrupt Enable.
-
- lea dx,R_mc[di] ;Turn the enabling "out2" bit
- mov al,MC_out2+MC_rts+MC_dtr ; on.
- out dx,al
-
- pop di
- pop dx
- pop cx
- ret
- EnabInt endp
- subttl Storage:
- page
- ;
- ; Storage for both COM1 and COM2.
- ;
- ReqHdr dd ? ;The Request Header:
- ReqHdrOff equ word ptr ReqHdr
- ReqHdrSeg equ ReqHdrOff+2
- ;
- ;
- unit db ? ;0 for COM1, 1 for COM2.
- ;(Set according to which "interrupt"
- ; entry point is used.)
- maxunit db -1 ;Maximum unit number allowed.
- ;(Set during INIT.)
- end0: ;Ending address if no asynch cards found.
- ;
- ; Unit Control Block for COM1:
- ; Keep this space allocation consistent with the definitions of U_inbuf,
- ; B_end, etc.
- ;
- UCB1:
- base_1: dw ? ;Base address for COM1.
- ;(Set during INIT.)
- hold_1: dw ?
- inb1_beg: dw offset inb1
- inb1_end: dw offset inb1+in_buf_len
- inb1_in: dw ?
- inb1_out: dw ?
- inb1: db in_buf_len dup(?)
-
- outb1_beg: dw offset outb1
- outb1_end dw offset outb1+out_buf_len
- outb1_in: dw ?
- outb1_out: dw ?
- outb1: db out_buf_len dup(?)
- end1: ;Ending address if only 1 asynch card found.
- ;
- ; Unit Control Block for COM2.
- ; Keep this space allocation consistent with the definitions of U_inbuf,
- ; B_end, etc.
- ;
- UCB2:
- base_2: dw ? ;Base address for COM2.
- ;(Set during INIT.)
- hold_2: dw ?
- inb2_beg: dw offset inb2
- inb2_end: dw offset inb2+in_buf_len
- inb2_in: dw ?
- inb2_out: dw ?
- inb2: db in_buf_len dup(?)
-
- outb2_beg: dw offset outb2
- outb2_end dw offset outb2+out_buf_len
- outb2_in: dw ?
- outb2_out: dw ?
- outb2: db out_buf_len dup(?)
- ;
- end2: ;Ending address if 2 asynch cards found.
- subttl Initialization:
- page
- ;
- ; Initialization:
- ; Perform any initialization code.
- ; If COM2, skip this part.
- ; Fill base_1 and base_2, as appropriate.
- ; Initialize pointers to input & output buffers.
- ; Install our hardware interrupt vectors.
- ; Set up the ending address for resident code.
- ; Set the status word in the Request Header.
- ;
- init:
- mov ax,endaddr ;Have we been called before?
- or ax,ax
- jnz initend ;Skip this part if so.
- mov dx,primary
- mov bx,offset base_1
- call InitUCB
- call HaveUnit ;Is "primary" card there?
- jnz init2
- push dx ;Assign our interrupt handler
- mov dx,NextHandler ; to its interrupt.
- mov al,prim_int
- mov ah,25h
- int 21h
- mov ax,offset Hdw2Int ;Use other interrupt handler
- mov NextHandler,ax ; next time.
- pop dx
- mov [bx],dx ;Use the first UCB
- call EnabInt ; for it.
- mov bx,offset base_2
- call InitUCB
- inc maxunit
- init2: mov dx,secondary
- call HaveUnit ;Is "secondary" card there?
- jnz init3
- push dx ;Assign our interrupt handler
- mov dx,NextHandler ; to its interrupt.
- mov al,sec_int
- mov ah,25h
- int 21h
- pop dx
- mov [bx],dx ;Use for it whichever
- call EnabInt ; UCB is indicated by
- inc maxunit ; BX.
- init3: mov bl,maxunit
- inc bl
- xor bh,bh
- rol bl,1
- mov ax,[bx]+endtable
- mov endaddr,ax
- initend: mov ax,endaddr ;Store the ending address.
- lds bx,cs:ReqHdr
- mov [bx]+RH_end_addr,ax
- mov [bx]+RH_end_addr+2,cs
-
- in al,ICC_msk ;Tell the interrupt controller chip
- and al,255-(MSK_d1+MSK_d2) ; to allow these interrupts.
- out ICC_msk,al
-
- jmp NormalDone
- ;
- ; Is there an asynch card answering at this address?
- ;
- ; Enter with:
- ; DX holding the base I/O address to be interrogated.
- ;
- ; Returns:
- ; Z condition if there is a card there,
- ; NZ condition if there is NO card there.
- ;
- HaveUnit proc near
- add dx,R_ii
- in al,dx ;Read the Interrupt Identification
- sub dx,R_ii ; register.
- and al,II_never ;If there's a device there, these bits
- ret ; will be zero.
- HaveUnit endp
- ;
- ; Initialize a Unit Control Block (UCB).
- ;
- ; Enter with
- ; BX pointing to the data block for the channel whose input
- ; and output buffer pointers are to be reset.
- ;
- InitUCB proc near
- mov word ptr [bx]+U_stat,0
- call ResInbuf
- call ResOutbuf
- ret
- InitUCB endp
- ;
- endaddr: dw 0 ;END address returned on INIT call.
- endtable: dw offset end0 ;END address if 0 asynch cards found.
- dw offset end1 ;END address if 1 asynch cards found.
- dw offset end2 ;END address if 2 asynch cards found.
- NextHandler: dw offset Hdw1Int ;Successive interrupt-handler addresses.
- coms endp
- cseg ends
- end begin
-