NAME MSXRMX ; RMX System dependent module derived from Generic MS DOS Kermit module $INCLUDE(mssdef.h86) public serini, serrst, clrbuf, outchr, coms, vts, dodel, termtb, bddat public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl, pcwait public dodisk, getbaud, beep, srcptr, sendbl, dtrtime, shomodem public xofsnt, puthlp, putmod, clrmod, poscur, savsi, portatt, sintok public sendbr, term, setktab, setkhlp, showkey, dtrlow, serhng public vtstat, ihosts, ihostr, dumpscr, comptab, costrt, coptr, spkout public chrout, chang, klogof, klogon, snull, cquit, cstatus, cquery false equ 0 true equ 1 ; external variables used: ; drives - # of disk drives on system ; flags - global flags as per flginfo structure defined in pcdefs ; trans - global transmission parameters, trinfo struct defined in pcdefs ; portval - pointer to current portinfo structure ; port1, port2 - portinfo structures for the corresponding ports ; global variables defined in this module: ; xofsnt, xofrcv - tell whether we saw or sent an xoff. datas segment PURGE prstr, dconio extrn drives:byte, flags:byte, trans:byte, citok:word, cotok:word extrn portval:word, prtbase:byte, oneport:byte, trmstr:byte extrn mbox:word, tmbox:word, sigpair:word, sematok:word, spkcnt:word extrn data:byte, pack:byte, combx:word, cimbx:word, termatt:word extrn trok:byte, rxtable:byte, kbdflg:byte, subpksz:word, source:byte extrn bufill:word, temp:word erms40 db cr,lf,'?Warning: Unrecognized baud rate',cr,lf,'$' erms60 db cr,lf,'Port doesn''t exist, use RUN ATTACH . . .' db cr,lf,'& try again$' wrn1prt db & bell,cr,lf,'Warning: No ports found, port 0 being used',cr,lf,bell,'$' badbd db cr,lf,'Unimplemented baud rate$' noimp db cr,lf,'Command not implemented.$' setktab db 0 setkhlp db 0 crlf db cr,lf,'$' delstr db BS,BS,' ',BS,'$' ; Delete string. clrlin db cr ; Clear line (just the cr part). clreol db ESCAPE,'[0K' ; Clear line. clscr db ESCAPE,'[2J' ; clear screen cursor db ESCAPE,'[' ; position cursor row dw ? ; part db ';' ; of col dw ? ; above db 'H' ; last of above mode db ESCAPE,'[24;1H',ESCAPE,'[0K' ; put cursor on mode line & clea model db 80 dup(?) ; mode line contents huosc db ESCAPE,']M:H',ESCAPE,'\' ; hangup OSC xofsnt db 0 ; Say if we sent an XOFF. xofrcv db 0 ; Say if we received an XOFF. parmsk db ? ; 8/7 bit parity mask, for reception savrflg db ? ; save previous remflg comstr db 6,':COM_:' tstr db 4,':T_:' devname db 14 dup(?) ; :TERM:'s physical device name ; Entries for choosing communications port. [19b] comptab db 10 %mkeyw (%('0 (TERM)'),0) %mkeyw (%('1 (COM1 or T1)'),1) %mkeyw (%('2 (COM2 or T2)'),2) %mkeyw (%('3 (COM3 or T3)'),3) %mkeyw (%('4 (COM4 or T4)'),4) %mkeyw (%('5 (COM5 or T5)'),5) %mkeyw (%('6 (COM6 or T6)'),6) %mkeyw (%('7 (COM7 or T7)'),7) %mkeyw (%('8 (COM8 or T8)'),8) %mkeyw (%('9 (COM9 or T9)'),9) ourarg termarg <> termtb db 1 %mkeyw (%('none'),ttgenrc) even ten dw 10 dtrtime dw 500 status dw ? sostrt dw ? soend dw ? sofin dw ? savsi dw source ; points to next char in buffer srcptr dw source ; points to next quadrant of buffer sintok dw 0 soutok dw 0 portptr dw ? costrt dw ? coptr dw ? argadr dw ? portatt dw 4,4,0ffh,119h ; serial I/O port attributes for rqaspecial inbaud dw 0,1 ; part of above getptat dw 3,3,2 dup(?) ; structure to read baud rate getinbd dw ? ; part of above dest db 2 dup (?) ; outchr's buffer ; This table is indexed by portinfo.baud. Unsupported baud rates contain 0. bddat label word dw 0 ; 45.5 baud N/A dw 50 ; 50 baud dw 75 ; 75 baud dw 110 ; 110 baud dw 0 ; 134.5 baud N/A dw 150 ; 150 baud dw 300 ; 300 baud dw 600 ; 600 baud dw 1200 ; 1200 baud dw 1800 ; 1800 baud dw 2000 ; 2000 baud dw 2400 ; 2400 baud dw 4800 ; 4800 baud dw 9600 ; 9600 baud dw 19200 ; 19200 baud dw 38400 ; 38400 baud dw 56800 ; 56800 baud dw 0 ; 113600 baud N/A datas ends code segment extrn comnd:near, dopar:near, prserr:near, keybd:near, msuinit:near extrn delcon:near, crfile:near, opfile:near, writer:near extrn aspcl:near, prstr:near, awrite:near, rqsleep:near, flushci:near extrn waitio:near, sendms:near, aopen:near, aclose:near, special:near extrn rcvmsg:near, delseg:near, dconio:near, gfilsta:near ; This is the HANGUP command. It drops DTR momentarily, if the serial board ; and its driver support modem control. dtrlow PROC serhng: call serrst ; reset & reinitialize port call serini mov ax,soutok ; enable OSC's on output mov bx,offset portatt and word ptr[bx+4],0bfh mov cx,5 call aspcl mov ax,soutok ; send hangup OSC mov bx,offset huosc mov byte ptr[bx+4],'H' mov cx,size huosc mov dx,tmbox call awrite mov ax,soutok ; wait for it mov bx,tmbox call waitio mov ax,dtrtime ; kill time call pcwait mov ax,soutok mov bx,offset huosc mov byte ptr[bx+4],'A' mov cx,size huosc ; send answer OSC mov dx,tmbox call awrite mov ax,soutok ; wait for it mov bx,tmbox call waitio mov ax,soutok ; disable OSC's on output mov bx,offset portatt or word ptr[bx+4],40h mov cx,5 call aspcl call serrst ; reset port jmp RSKP dtrlow ENDP pcwait PROC ; sleep for ax milliseconds (rounded up to nearest 10) push ax ; too lazy to find out how much of this is necessary push bx push cx push dx push si push di push es sub dx,dx add ax,9 div ten push ax push ds mov ax,offset status push ax call rqsleep pop es pop di pop si pop dx pop cx pop bx pop ax ret pcwait ENDP ; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the ; cycle of clear input buffer, test if buffer empty then exit, else repeat ; cycle. Requires that the port be initialized before hand. ; Ihosts is used by the local send-file routine just after initializing ; the serial port. ; 22 March 1986 [jrd] IHOSTS PROC push ax ; save the registers push bx push cx push dx mov bx,portval ; port indicator mov ax,[bx].flowc ; put Go-ahead flow control char in ah test ah,ah ; don't send null if flow=null jz ihosts1 ; z=null call outchr ; send it (release Host's output queue) nop ; outchr can do skip return nop nop ihosts1:call clrbuf ; clear out interrupt buffer call prtchr ; check for char at port jmp ihosts1 ; have a char in al, repeat wait/read cycle nop ; prtchr does skip return on empty buffer pop dx ; empty buffer. we are done here. pop cx pop bx pop ax ret IHOSTS ENDP ; IHOSTR - initialize the remote host for our reception of a file by ; sending the flow-on character (XON typically) to release any held ; data. Called by receive-file code just after initializing the serial ; port. 22 March 1986 [jrd] IHOSTR PROC push ax ; save regs push bx push cx mov bx,portval ; port indicator mov ax,[bx].flowc ; put Go-ahead flow control char in ah test ah,ah ; don't send null if flow=null jz ihostr1 ; z=null call outchr ; send it (release Host's output queue) nop ; outchr can do skip return nop nop ihostr1:pop cx pop bx pop ax ret IHOSTR ENDP ; this is called by Kermit initialization. It checks the ; number of disks on the system, sets the drives variable ; appropriately. Returns normally. DODISK PROC mov drives,1 ; 1 "disk". It's $, which can be reattachfiled ret DODISK ENDP ; Clear the input buffer. This throws away all the characters in the ; serial interrupt buffer. This is particularly important when ; talking to servers, since NAKs can accumulate in the buffer. ; Returns normally. CLRBUF PROC push es mov ax,ds mov es,ax cld cli mov di,savsi ; scan from current ptr mov cx,offset source+bufsiz sub cx,di ; to end of buffer for fill char mov al,byte ptr bufill repne scasb je CLRB1 ; jump if found mov di,offset source ; scan from the beginning, if not mov cx,bufsiz repne scasb CLRB1: dec di mov savsi,di ; current ptr points to fill char sti pop es ret CLRBUF ENDP ; Put the char in AH to the serial port. This assumes the ; port has been initialized. Should honor xon/xoff. Skip returns on ; success, returns normally if the character cannot be written. outchr PROC push bx push cx push dx push es mov al,ah call dopar ; set parity, as req'd mov dest,al mov ax,soutok mov bx,offset dest ; write it mov cx,1 sub dx,dx call awrite pop es pop dx pop cx pop bx cmp status,0 jne OUTCH1 jmp RSKP ; OK return OUTCH1: ret ; NG return outchr ENDP ; Set the baud rate for the current port, based on the value in the portinfo ; structure. Returns normally. Entered w/current baud rate in ax. DOBAUD PROC push bx mov bx,portval ; see if new baud rate is OK mov si,[bx].baud shl si,1 mov cx,bddat[si] jcxz DOBD1 ; nope call serrst ; yeah, force serini to set it pop bx ret DOBD1: mov [bx].baud,ax ; restore previous baud rate mov dx,offset badbd ; send bad baud msg call prstr pop bx ret DOBAUD ENDP ; Get the current baud rate from the serial card and set it ; in the potinfo structure for the current port. Returns normally. ; This is used during initialization. GETBAUD PROC ret ; It's all taken care of, so what's to do? GETBAUD ENDP ; Use for DOS 2.0 and above. Check the port status. If no data, skip return. ; Else, read in a char and return. DX returns # chars (0 or 1 for us). PRTCHR PROC push si cmp xofsnt,true ; if XOF has been sent, je PRTCH4 ; see if there's room in buffer for XON PRTCH1: sub dx,dx ; # of chars mov si,savsi ; current serial input buffer ptr cld lodsb cmp al,byte ptr bufill ; got one? jne PRTCH2 pop si ; nope jmp RSKP PRTCH2: cmp si,offset source+bufsiz ; edge of the universe? jb PRTCH3 ; no mov si,offset source ; yeah, point to beginning PRTCH3: mov savsi,si ; update current ptr inc dx ; # chars=1 pop si ret ; got one return PRTCH4: mov ax,srcptr ; if next quadrant & current ptr are sub ax,savsi ; 2 quadrants apart jns PRTCH5 ; there's room to XON add ax,bufsiz PRTCH5: cmp ax,bufsiz/2 jg PRTCH1 ; they aren't push bx ; send XON mov bx,portval mov ax,[bx].flowc call outchr nop nop nop mov xofsnt,false ; reset pop bx jmp PRTCH1 PRTCHR ENDP ; Send a break out the current serial port. Returns normally. SENDBR PROC sendbl: mov dx,offset noimp ; send intel's appologies call prstr ; for not having OS support ret ; for their hardware's capabilities SENDBR ENDP ; Show modem command. Not implemented. SHOMODEM PROC mov ah,cmcfm ; get a confirm call comnd ret ; no confirm nop nop call SENDBR ; send not imp. msg jmp RSKP SHOMODEM ENDP ; Clear to the end of the current line. Returns normally. CLEARL PROC push bx mov bx,offset clreol ; send ESC[0K SCRO1: mov cx,4 ; to clear to end of line SCRO2: push ax SCRO3: mov ax,cotok push es push dx push si call writer pop si pop dx pop es pop ax pop bx ret CLEARL ENDP ; This routine blanks the screen. Returns normally. CMBLNK PROC push bx mov bx,offset clscr ; send ESC[2J for clear screen jmp SCRO1 CMBLNK ENDP ; Position the cursor according to contents of DX: ; DH contains row, DL contains column. Returns normally. POSCUR PROC push bx push ax add dx,101h ; KERMIT starts w/0, RMX w/1 mov al,dh ; convert row to decimal sub ah,ah mov cl,10 div cl add ax,'00' ; covert to ASCII mov row,ax ; stash in row portion of escape sequence mov al,dl ; convert column to decimal sub ah,ah div cl add ax,'00' ; convert to ASCII mov col,ax ; to column portion of escape sequence mov bx,offset cursor mov cx,8 ; send ESC[row;colH to position cursor jmp SCRO3 POSCUR ENDP ; Move the cursor to the left margin, then clear to end of line. ; Returns normally. CTLU PROC push bx mov bx,offset clrlin ; send CR,ESC[0K to clear entire line mov cx,5 jmp SCRO2 CTLU ENDP ; Homes the cursor. Returns normally. LOCATE PROC mov dx,0 ; Go to top left corner of screen. jmp poscur LOCATE ENDP ; Write a line at the bottom of the screen... ; the line is passed in dx, terminated by a $. Returns normally. putmod PROC push bx push ax mov bx,es ; save es mov ax,ds mov es,ax mov di,dx mov cx,0ffffh ; compute # bytes in line mov al,'$' repne scasb neg cx add cx,0fffeh mov si,dx mov di,offset model mov dx,cx ; save # bytes rep movsb ; move line after mode line escape sequence mov cx,size mode ; mode line escape sequence length add cx,dx ; plus line length mov es,bx ; restore es mov bx,offset mode ; write line prefixed w/escape sequence jmp SCRO3 putmod ENDP ; clear the mode line written by putmod. Returns normally. clrmod PROC push bx mov bx,offset mode ; mode line escape sequence mov cx,size mode ; ESC[24;1HESC[0K jmp SCRO2 ; clears mode line clrmod ENDP ; Put a help message on the screen. ; Pass the message in ax, terminated by a null. Returns normally. puthlp PROC push dx push si push ax ; preserve this mov dx,offset crlf call prstr pop si ; point to string again puthl3: cld lodsb ; get a byte cmp al,0 ; end of string? je puthl4 ; yes, stop mov dl,al call dconio ; else write to screen jmp puthl3 ; and keep going puthl4: mov dx,offset crlf call prstr pop si pop dx ret puthlp ENDP ; Delete a character from the terminal. This works by printing ; backspaces and spaces. Returns normally. DODEL PROC mov dx,offset delstr call prstr ; Erase weird character. ret DODEL ENDP ; Set the current port. COMS PROC call serrst ; reset the old port mov dx,offset comptab sub bx,bx mov ah,cmkey call comnd ; parse for the new one ret nop nop push bx ; save port # mov ah,cmcfm call comnd ; Get a confirm. jmp short COMX ; Didn't get a confirm. nop pop cx ; get port # mov ax,size prtinfo ; compute address of prtinfo structure mul cl add ax,offset prtbase mov temp,ax ; save it jcxz COMS1 ; jmp if port 0 (:TERM:) call COMSR ; crfile :COMn: or :Tn: jz COMS2 ; jmp if successful mov dx,offset erms60 call prstr ; no luck, bitch ret COMX: pop bx ret COMS1: mov di,offset trmstr mov temp+2,di ; port name string pointer call crfile COMS2: mov bx,temp mov portval,bx ; set prtinfo ptr COMS3: mov flags.comflg,cl ; remember port # mov sintok,ax ; open port mov bx,1 call aopen call rdbaud ; read it's baud rate mov bx,portval mov [bx].baud,cx ; memorize it call serrst ; reset port mov di,temp+2 ; port name string pointer mov portptr,di call gfilsta ; puts physical device name @temp+10 mov ax,ds mov es,ax mov si,offset devname mov di,offset temp+10 mov cx,size devname repe cmpsb ; is it the same as :TERM:? je COMS5 ; eq = yes cmp oneport,true ; was it oneport? jne COMS4 ; ne = no, exit mov al,savrflg ; yes, restore remflg to what it was before mov flags.remflg,al mov oneport,cl ; clear oneport COMS4: ret COMS5: mov al,dquiet ; get current remflg & set to quiet mode xchg al,flags.remflg cmp oneport,true ; if not previously one port je COMS4 ; save previous remflg & set oneport mov savrflg,al mov oneport,true ; set oneport ret COMSR proc push cx ; save port # add cl,'0' ; charify mov di,offset comstr mov temp+2,di ; temp+2 is port name string pointer mov [di+5],cl ; setup :COMn: & :Tn: strings mov tstr+3,cl call crfile ; try COMn jcxz CSR1 ; OK mov di,offset tstr ; try Tn mov temp+2,di call crfile CSR1: test cx,cx ; return zero flag, if successful pop cx ; restore port # ret COMSR endp COMS ENDP ; Reads serial port's baud rate. Returns baud rate index in cx if recognizable ; by KERMIT, if not, cx=0ffffh. rdbaud PROC push es mov ax,sintok ; use aspecial function 4 to read baud rate mov bx,offset getptat mov cx,4 call aspcl mov ax,ds mov es,ax mov ax,getinbd ; search bddat table for it mov cx,baudsiz mov di,offset bddat+2*(baudsiz-1) std repne scasw cld je RDB1 ; found it, cx=index mov dx,offset erms40 call prstr ; not found, say so mov cx,0ffffh ; return unrecognizable RDB1: pop es ret rdbaud ENDP ; Set heath emulation on/off. VTS PROC mov dx,offset noimp call prstr jmp prserr VTS ENDP ; Initialize variables & find port lclini: mov flags.vtflg,0 ; Don't do terminal emulation. call msuinit mov di,offset trmstr ; get :TERM:'s physical devive name call gfilsta mov ax,ds mov es,ax mov si,offset temp+10 ; move it to devname mov di,offset devname mov cx,size devname rep movsb mov ax,offset prtbase ; base value of prtinfo struc ptr mov ax,portval mov temp,ax ; save in case it ends up port 0 LCL1: add portval,size prtinfo ; loop thru looking for 1st of 1 to max inc cx ; 0 1st time thru call COMSR ; try crfile COMn or Tn jz LCL2 ; z = success cmp cl,portmax-1 ; done? jl LCL1 ; l = no call COMS1 ; yes, go use :TERM: mov dx,offset wrn1prt ; and give one port warning call prstr ret LCL2: jmp COMS3 ; join common code ret showkey:ret ; obsolete, for ext def only ; Initialization for using serial port. Returns normally. SERINI PROC cmp sintok,0 ; is this trip necessary? jne SIN3 ; no push bx push es cmp oneport,true ; is it oneport? jne SIN1 ; ne = no mov ax,citok ; yes, shut down citsk sub cx,cx call aclose mov ax,citok ; reopen mov bx,3 call aopen call flushci ; necessary for 386 SIN1: mov di,portptr ; get port ptr push di ; save for 2nd crfile call crfile ; create it mov sintok,ax ; set serial input token mov bx,1 ; open for reading call aopen pop di ; port ptr call crfile ; create it mov soutok,ax ; set serial output token mov bx,2 ; open for writing call aopen mov bx,portval ; prtinfo struc ptr mov parmsk,0ffh ; set parmsk according to this port cmp [bx].parflg,parnon je SIN2 mov parmsk,7fh SIN2: mov bx,[bx].baud ; set baud rate according to this prot shl bx,1 mov ax,bddat[bx] mov inbaud,ax mov ax,soutok ; set baud rate & attributes mov bx,offset portatt mov cx,5 call aspcl mov ax,mbox ; when the message sent to mbox mov bx,ax ; is the mbox token itself call sendms ; it tells the serial input task pop es ; to initialize & start input pop bx SIN3: ret SERINI ENDP ; Reset the serial port. This is the opposite of serini. Calling ; this twice without intervening calls to serini should be harmless. ; Returns normally. SERRST PROC push bx mov bx,sintok ; serial input token test bx,bx jz SERST1 ; unecessary mov sintok,0 ; MUST be done 1st, cuz siotsk is gonna get ints call delcon ; before we get back from delete connection SERST1: mov ax,soutok ; serial output token test ax,ax jz SERST2 ; don't bother push ax ; save for delcon mov cx,tmbox push cx ; save for rcvmsg call aclose ; let I/O complete before delcon pop ax mov bx,0ffffh call rcvmsg call delseg pop bx ; soutok mov soutok,0 ; see above call delcon ; ditto cmp oneport,true jne SERST2 call flushci ; necessary for 386 mov ax,citok mov bx,offset termatt mov cx,5 call aspcl mov ax,cimbx ; restart citsk mov bx,ax call sendms SERST2: pop bx ret SERRST ENDP ; Bell ringer BEEP PROC mov dl,bell call dconio ret BEEP ENDP VTSTAT PROC ; For Status display [jrd] ret ; no emulator status to display VTSTAT ENDP ; Save the screen to a buffer and then append buffer to a disk file. [jrd] ; Default filename is Kermit.scn; actual file can be a device too. Filename ; is determined by mssset and is passed as pointer dmpname. DUMPSCR PROC ; Dumps screen contents to a file. Just Beeps here jmp beep ; [jrd] DUMPSCR ENDP ; Dumb terminal emulator. TERM PROC cmp oneport,true ; if oneport jne TERM1 mov kbdflg,'C' ; force exit connect mode jmp BEEP TERM1: mov si,ax ; this is source mov di,offset ourarg ; place to store arguments mov ax,ds mov es,ax ; address destination segment mov cx,size termarg cld rep movsb ; copy into our arg blk mov parmsk,0ffh cmp ourarg.parity,parnon je TERM2 mov parmsk,7fh TERM2: mov ax,citok ; shut down citsk & reopen citok call aclose mov ax,citok mov bx,3 call aopen sub ax,ax ; turn off control C trap mov sigpair,ax mov ax,citok mov bx,offset sigpair mov cx,6 call aspcl push termatt+6 ; save cmp trok,true je TERM3 and termatt+6,0fdffh ; turn off translation TERM3: push termatt+4 ; save or termatt+4,0e0h ; disable OSC's & output ctrl chars mov ax,cotok ; make it transparent as all get out mov bx,offset termatt ; during terminal emulation mov cx,5 call special mov ax,citok mov bx,offset termatt mov cx,5 call aspcl mov ax,cimbx ; start citsk & cotsk mov bx,ax call sendms mov ax,combx mov bx,ax call sendms mov ax,ds mov es,ax TERM4: call PORTCHR ; get char from port call OUTTTY ; if char, output it call KEYBD ; check keyboard jnc TERM4 ; carry=exit Connect mode pop termatt+4 ; restore pop termatt+6 ; restore mov ax,combx ; shut down cotsk mov bx,ax call sendms mov ax,citok ; shut down citsk & reopen citok call aclose mov ax,citok mov bx,3 call aopen mov ax,sematok ; restore control C trap mov sigpair,ax mov ax,citok mov bx,offset sigpair mov cx,6 call aspcl mov ax,cotok ; reopen cotok mov bx,3 mov cx,bx call opfile mov ax,citok ; restore terminal attributes mov bx,offset termatt mov cx,5 call aspcl mov ax,cotok mov bx,offset termatt mov cx,5 call special mov ax,cimbx ; restart citsk mov bx,ax call sendms ret TERM ENDP ;; keyboard translator action routines, system dependent, called from msurmx. ; These are invoked by a jump instruction. Return carry clear for normal ; processing, return carry set exit Connect mode (kbdflg has transfer char). klogon proc ; resume logging (if any) test flags.capflg,logses ; session logging enabled? jz klogn ; z = no, forget it or argadr.flgs,capt ; turn on capture flag or ourarg.flgs,capt ; turn on local capture flag as well klogn: clc ret klogon endp klogof proc ; suspend logging (if any) and argadr.flgs,not capt ; stop capturing and ourarg.flgs,not capt ; rest local as well clc ret klogof endp snull: mov ah,0 ; send a null call outchr ; send without echo or logging nop nop nop clc ret cmdcom: mov kbdflg,al ; pass char to msster.asm via kbdflg stc ; say exit Connect mode ret cstatus:mov al,'S' ; these commands exit Connect mode jmp cmdcom cquit: mov al,'C' jmp cmdcom cquery: mov al,'?' jmp cmdcom chang: mov al,'H' jmp cmdcom ;; end of action routines OUTTTY PROC cmp rxtable+256,0 ; translation turned off? je OTY1 ; e = yes, no translation push bx mov bx,offset rxtable ; address of translate table [jrd] xlatb ; new char is in al pop bx OTY1: test ourarg.flgs,capt ; capturing output? jz OTY2 ; no, forget it push ax call ourarg.captr ; else call the routine pop ax OTY2: test ourarg.flgs,trnctl ; debugging? nz=yes jnz OTY3 ; bypass translation & do debug display test flags.remflg,d8bit ; keep 8 bits for displays? jnz OUTONE ; nz = yes, 8 bits if possible and al,7fh ; remove high bit OUTONE PROC mov di,coptr ; CO buffer pointer sub di,costrt ; is buffer full? cmp di,cobufl je OUTONE ; eq=yes, wait for room cli ; disable ints during mov di,coptr ; these 3 stosb ; critical mov coptr,di ; instructions sti ret OUTONE ENDP OTY3: test al,al ; is high bit on? jns OTY4 ; ns=no mov ah,al ; save it mov al,'~' ; output tilde call OUTONE mov al,ah ; restore it & turn off high bit and al,7fh OTY4: cmp al,7fh ; is it rubout? jne OTY5 ; ne=no and al,3fh ; convert to ? jmp short OTY6 ; to display ^? for rubout OTY5: cmp al,' ' ; is it a control character? jae OUTONE ; ae=no, just output it add al,'@' ; make printable OTY6: mov ah,al ; save mov al,'^' ; output ^ call OUTONE mov al,ah ; restore & output jmp OUTONE OUTTTY ENDP CHROUT PROC test ourarg.flgs,lclecho ; echoing? jz CHRO1 ; no, don't bother push ax call OUTTTY pop ax CHRO1: mov ah,al call outchr ; output the character nop nop nop ret CHROUT ENDP SPKOUT PROC inc spkcnt ; bump ctr cmp ah,trans.ssoh je SPK4 ; eq = start of packet cmp bx,soend je SPK1 ; eq = enough to write clc ret SPK1: push cx push bx push ax push dx mov cx,bx ; bx is last byte+1 xchg bx,sostrt ; bx = current 1st byte, sostrt = next 1st byte sub cx,bx ; cx = # bytes mov ax,soutok ; call rqawrite(soutok,ds:bx,cx,0,@status) sub dx,dx call awrite pop dx pop ax mov bx,sostrt mov cx,sofin SPK2: add bx,subpksz ; next time to write (soend) = cmp bx,cx ; min{sofin,(sostrt + subpksz)} jb SPK3 mov bx,cx SPK3: mov soend,bx pop bx pop cx clc ret SPK4: push cx push bx ; start of packet dec bx ; point to soh mov sostrt,bx ; set sub-packet start ptr sub cx,cx mov cl,trans.chklen add cx,offset data add cx,pack.argbk1 inc cx mov sofin,cx ; sofin = end of packet ptr jmp SPK2 SPKOUT ENDP PORTCHR PROC call prtchr ; get char from port jmp short PORCH1 ; got one nop jmp short RSKP ; don't got PORCH1: and al,parmsk ; apply 8/7 bit parity mask jz RSKP ; filter nulls cmp al,del ; filter rubouts je RSKP ret PORTCHR ENDP ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. RSKP PROC pop bp add bp,3 jmp bp RSKP ENDP code ends end