|
|
1.06a MS-DOS
.xlist include mdef .ilist ;************************************************************************ ;* * ;* rciol: direct 8250 communications interface for C * ;* * ;* prototypes: int rioini(int,int); initialize com,irq * ;* int setbaud(int); set baud rate * ;* *n/a int rioctl(int); remote i/o control * ;* void dtr(char); set/reset dtr * ;* int outcom(int); send character * ;* int incom(void); receive character * ;* *n/a int rioifc(int); local i/o redirection * ;* * ;************************************************************************ ; this source file is lacking _rioctl and _rioifc biosda segment at 40h ;bios data area biosda ends setmod %mm ; 8259 interrupt controller register equates icr1 equ 20h ;interrupt command register (master) imr1 equ 21h ;interrupt mask register (master) ivb1 equ 8 ;vector base 0-7: cannot be read, assumed icr2 equ 0a0h ;interrupt command register (slave) imr2 equ 0a1h ;interrupt mask register (slave) ivb2 equ 70h ;vector base 8-f: cannot be read, assumed ; 8250 uart register equates iir equ 2 ;interrupt identification register ier equ 1 ;interrupt enable register ierd equ 0bh ;enable: rxd, thre, msr msr equ 6 ;modem status register mcr equ 4 ;modem control register mcrd equ 0bh ;irq enable, rts on, dtr on lsr equ 5 ;line status register lcr equ 3 ;line control register lcrd equ 3 ;N,8,1 mode ; buffer pointer structure dstruc bufp,0 dss 2,bcnt ;character count dss 2,bput ;next character to buffer dss 2,bget ;next character from buffer dss 1,ovfl ;overflow flag dss 1 dss 2,bofst ;buffer offset dss 2,bsize ;buffer size dstruc bufp .xlist .eopg .data public _plst align 2 brdd dd 115200 ;baud rate dividend iv16h dd 0 ;saved interrupt vector for int 16h iv29h dd 0 ;saved interrupt vector for int 29h ivsio dd 0 ;saved serial i/o vector buart dw 0 ;uart base address lsrad dw 0 ;line status register port address irqn db 0 ;interrupt request line ircr db 0 ;saved interrupt controller mask siovn db 0 ;serial i/o vector number ic29h equ 1 ;int 29h is being intercepted ic29d equ 3 ;int 29h is being diverted ic16h equ 10h ;int 16h is being intercepted intcp db 0 ;intercepted interrupt code opera db 0 ;operational (port defined, baud set) mode db 0 ;function enable (incl pause/abort cycles) state db 0 ;operational state (must follow mode) hold equ 2 ;stop transmission abort equ 4 ;aborting ctsck equ 10h ;check clear to send signal (mode only, fixed) txintp db 0 ;transmit interrupt pending status db 0 ;communications status rxlost equ 1 ;received characters lost align 2 txbmx equ 1024 ;receive buffer maximum size rxbmx equ 1024 ;transmit buffer maximum size _plst label word dv rxbp bufp,0 ;receive buffer pointers dv txbp bufp,0 ;transmit buffer pointers dv rxb rxbmx,0a8h ;receive buffer dv txb txbmx,0a8h ;transmit buffer tst db 0 .xlist .eopg .code public _rioini,_outcom,_incom,_dtr,_setbaud riods: dw -1 ;remote i/o routine data segment value ; initialize communications ; clear buffers, data, program uart, enable interrupts _rioini proc push bp mov bp,sp push si push di mov ax,pb[bp] ;com port or uart address or ax,ax mov ax,buart jnz @f ;initialize or ax,ax jz cierr ;error, not initialized jmp finis ;terminate @@: or ax,ax jz cinit ;continue, not yet initialized cierr: mov ax,-1 jmp ciex ;return error cinit: mov ax,ds mov cs:riods,ax ;save data segment call ibfls ;clear input buffer mov bofst[si],os rxb ;set receive buffer address call obfls ;clear output buffer mov bofst[si],os txb ;set transmit buffer address xor ax,ax mov mode,ax ;clear mode and state mov txintp,al ;clear int pending mov ax,seg biosda mov es,ax mov bx,pb[bp] ;com port or uart address mov dx,bx dec bx cmp bx,4 jnc scport ;com port address specified and bx,3 ;com 0-3 for 1-4 add bx,bx ;offset (x 2) mov dx,es:[bx] or dx,dx jnz scport ;port exists jmp ciabt ;no such com port scport: mov buart,dx ;uart base address add dx,lsr mov lsrad,dx ;line status register ; mov al,pb[bp+4] ;hardware flow control ; and al,1 ; jz girq ; or mode,ctsck ;check cts girq: mov al,pb[bp+2] ;irq line and al,7 jnz irqv ;valid and al,1 add al,3 ;assume 4 for 1, 3 for 2 irqv: mov irqn,al mov cl,al mov al,1 shl al,cl ;mask for current irq line ; mov irqm,al mov ah,al push ax ;save irq mask in al,imr1 mov ircr,al ;save prior enable mask or al,ah out imr1,al ;inhibit interrupts mov al,cl ;irq number add al,ivb1 ;add vector base mov siovn,al ;save sio vector call gvect ;get prior vector in dx:bx mov ivsio,bx mov ivsio+2,dx ;save prior vector push cs pop dx mov bx,os sioisr call svect ;set service routine vector in dx:bx mov dx,buart in ax,dx ;clear% add dx,mcr mov al,mcrd out dx,al ;modem control register dec dx mov al,lcrd out dx,al ;line control register dec dx dec dx mov al,ierd out dx,al ;interrupt enable register pop ax ;irq mask in al,imr1 not ah and al,ah out imr1,al ;enable interrupts ; mov mw cs:mv2,1234h ; xor ax,ax ; mov si,os inims ; call msout xor ax,ax ;return 0 jmp ciex ;exit ; terminate serial i/o operation finis: mov dx,buart add dx,mcr xor al,al out dx,al ;dtr off, release irq line mov al,siovn ;serial i/o vector mov bx,ivsio ;prior offset mov dx,ivsio+2 ;prior segment call svect ;replace original vector mov al,ircr out imr1,al ;replace prior interrupt controller mask xor bx,bx jmp cterm ;return 0 ciabt: mov bx,-1 cterm: xor ax,ax mov buart,ax ;not initialized mov opera,al ;not operational mov ax,bx ;return code ciex: pop di pop si pop bp ret _rioini endp ; get interrupt vector al in dx:bx gvect: push es mov ah,35h int 21h ;returns vector in es:bx push es pop dx ;segment pop es ret ; set interrupt vector al in dx:bx svect: push ds push dx mov ds,dx ;segment mov dx,bx ;offset mov ah,25h int 21h ;takes vector in ds:dx pop dx pop ds ret ; flush buffers ibfls: mov si,os rxbp ;address input buffer pointers mov bx,rxbmx ;set maximum size jmp s xbfls obfls: mov si,os txbp ;address output buffer pointers mov bx,txbmx ;set maximum size ; si -> bufp structure, bx = maximum size xbfls: mov cx,os bofst/2 ;pointer list length pushf cli push si xor ax,ax rep stosw ;clear pointers pop si mov bsize[si],bx popf ret ; get character from buffer, ds:si -> pointers, saves cx, dx bgetc: mov ax,bcnt[si] or ax,ax jz bgnc ;buffer empty pushf cli mov bx,bofst[si] ;buffer offset from segment mov di,bget[si] ;character offset from buffer mov al,mb [bx+di] ;get character inc di ;advance pointer cmp di,bsize[si] jc bggp ;pointer not past end of buffer xor di,di ;reset to start bggp: mov bget[si],di dec bcnt[si] ;character count popf ;re-enable interrupts if disabled or al,al ;character in al, clear carry ret bgnc: stc ret ; put character to buffer, ds:si -> pointers, al = char, saves ax, cx, dx bputc: mov bx,bcnt[si] bputco: cmp bx,bsize[si] jnc bgnc ;buffer full pushf cli mov bx,bofst[si] ;buffer offset from segment mov di,bput[si] ;character offset from buffer mov mb [bx+di],al ;put character inc di ;advance pointer cmp di,bsize[si] jc bpgp ;pointer not past end of buffer xor di,di ;reset to start bpgp: mov bput[si],di inc bcnt[si] ;character count popf ;re-enable interrupts if disabled clc ;character in al, clear carry ret ; sio input character _incom proc push si push di mov si,os rxbp ;address receive buffer pointers call bgetc ;get character from receive buffer mov ah,state jnc icgc ;received character in al or ah,1 ;no character available xor al,al icgc: pop di pop si ret _incom endp ; sio output character _outcom proc xor al,al mov ah,state test ah,abort jnz ocabt ;aborting push bp mov bp,sp push si push di mov al,pb[bp] mov si,os txbp ;address transmit buffer pointers ocrep: mov bx,bcnt[si] or bx,bx jnz ocbuf ;buffer not empty test ah,hold jnz ocbuf ;paused mov dx,lsrad ;address line status register mov cl,al in al,dx and al,20h ;transmit hold register empty mov al,cl jz ocbuf ;interrupt pending mov dx,buart ;uart base (r/w data port) out dx,al ;transmit character jmp s ocex ;exit ocbuf: call bputco ;put character to transmit buffer jnc ocex ;done ;check timer, exit if 2 min. jmp ocrep ;retry ocex: pop di pop si pop bp ocabt: ret ;state in ah _outcom endp ; sio interrupt service routine sioisr proc cli push ax push bx push cx push dx push si push di push ds mov ax,cs:riods mov ds,ax ;i/o data segment isrep: mov dx,lsrad ;line status register in ax,dx ;lsr in al, msr in ah mov mw cs:mv2,ax ;% mov cx,ax ;save line status sub dx,lsr ;address r/w data port test al,1 ;received data available jz txchk ;no character received test al,0ch ;overrun/parity/framing error in al,dx ;read data jnz txchk ;receive error, discard data mov bx,mode ;mode in bl, state in bh test bh,abort jnz intex ;aborting test bl,abort jz rcpau ;not checking for abort cmp al,3 ;^C jnz rcpau ;not abort character call ibfls ;flush input buffer call obfls ;flush output buffer mov state,abort ;aborting jmp intex rxccs: mov state,hold ;set pause flag jmp s txchk rxccq: and state,not hold ;clear pause flag jmp s txchk rcpau: test bl,hold jz rxpch ;not checking pause cmp al,13h ;^s jz rxccs ;pause cmp al,10h ;^q jz rxccq ;resume rxpch: mov si,os rxbp ;address receive buffer call bputc ;put character in buffer jnc txchk ;done or status,rxlost ;set receive characters lost flag txchk: test cl,20h ;transmit hold register empty jz intex ;not ready to transmit mov si,os txbp ;address transmit buffer call bgetc jc intex ;buffer empty mov bx,mode ;mode in bl, state in bh not ch and ch,bl ;mode and not msr test ch,ctsck ;cts checking and cts off jnz intex ;hardware flow off, interrupt will resume test bh,hold jnz intex ;paused out dx,al ;transmit character intex: mov dx,buart add dx,iir in al,dx ;reset int? in al,dx ; and al,1 ; jnz isrex ;more? ; jmp isrep inc mw cs:mv1 mov ax,rxbp.bcnt mov mw cs:mv3,ax mov ax,txbp.bcnt mov mw cs:mv4,ax mov ax,800 mov si,os intmsg call msout isrex: pop ds pop di pop si pop dx pop cx pop bx mov al,20h out icr1,al ;non-specific eoi pop ax iret intmsg: db 'Interrupt �5, msr/lsr �4, rxbc �4, txbc �4 ',0 sioisr endp ; set baud rate _setbaud proc mov dx,buart ;base port address or dx,dx jnz sbinit ;initialized xor ax,ax dec ax ;-1 ret ;return error sbinit: push bp mov bp,sp push si mov cx,dx ;% mov si,os brdd ;address baud rate dividend mov dx,2[si] mov ax,[si] ;dividend in dx:ax div mw pb[bp] ;divide by parameter 1 mov dx,cx ;% push ax ;actual rate divisor for uart mov si,dx add dx,lcr ;address line control register in al,dx or al,80h out dx,al ;address baud rate divisor xchg si,dx pop ax out dx,ax ;write baud rate divisor xchg si,dx in al,dx and al,7fh out dx,al ;address rx/tx registers, ier xchg si,dx in ax,dx ;clear% xor ax,ax ;no error pop si pop bp ret _setbaud endp .xlist .eopg ; drop dtr ; n=0 (off), n=1 (on), or n>1 (off, wait n seconds for dcd off) _dtr proc push bp mov bp,sp mov ax,seg biosda mov es,ax mov dx,buart ;uart base port or dx,dx jz dtrer ;not initialized add dx,4 ;address mcr in al,dx and al,0feh ;clear dtr bit mov ah,pb[bp] ;parameter and ah,0fh cmp ah,2 ;0 off, 1 on jnc wtdcd ;off, wait for dcd or al,ah out dx,al ;set as specified xor al,al jmp s dtrck wtdcd: out dx,al ;dtr off inc dx inc dx ;address msr twn: mov cx,18 ;55ms/s tws: mov bl,es:[6ch] ;55ms counter twt: in al,dx and al,80h ;dcd jz dtrck ;done cmp bl,es:[6ch] ;55ms counter jz twt ;wait 55ms loop tws ;wait 990ms dec ah jnz twn ;wait 2-x seconds dtrer: mov al,-1 ;timeout dtrck: mov ah,al cmp mb pb[bp],1 jz dtrex ;dtr was set push ax ;dtr was reset, clear state and buffers call ibfls call obfls xor al,al mov state,al mov status,al pop ax dtrex: pop bp ret _dtr endp include mviow end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.