NAME msxz10 ; File MSXZ10.ASM include mssdef.h ; Copyright (C) 1982,1991, Trustees of Columbia University in the ; City of New York. Permission is granted to any individual or ; institution to use, copy, or redistribute this software as long as ; it is not sold for profit and this copyright notice is retained. ; Kermit system dependent module for Heath/Zenith Z100 ; Edit history ; 2 March 1991 version 3.10 ; Last change: 3 November 1990. ; ; OUTCH2 defined as far label. ; Replay code in PRTCHR modified per ibm pc version and call serrst added at ; label coms0. These two last changes are for version 3.02. ; New code for VTS and VTSTAT added and under revision but not active. These ; two routines and corresponding data really belong in msy but the routines ; and some of their data are kept here to make msy small enough to assemble ; with MASM 4. DUMPSCR moved to msyz10.asm. ; A number of calls to SPRTCH added in order to allow windowing for the non ; interupt driven S-100 modem ports COM3/COM4. Some very limited success at ; 1200 baud would indicate that it might work at 300 (untested). ; SERISR optimized and performance improved for COM1/COM2. However, there are ; still some problems from 19200 baud and up, in particular with windowing. ; OUTCHR significantly rewritten. Modified CHKXON (COM1/2) and CHKXOF (COM3/4) ; to call OUTCH5 and OUTCH2 respectively rather than OUTCHAR. ; SERISR significantly modified to improve flow control for COM1/2 and SPRTCH ; fixed to ignore flow control for COM3/4 if not called for. ; Minor correction to WAIT01. CLEARL and CTLU merged. ; PUTHLP display routine improved and replay command implemented. ; Increased size of buffilen and buffolen. Added register save to BEEP. ; Added routines ENA_WRP and DIS_WRP and several calls to these to make serial ; display behave. Help message for 'set port' improved. ; Various cosmetic changes. ; ; First version of this file for MS-Kermit 3.0: 8 May 1990. ; Bo Gedda ; ; Support for 2 US Robotics S-100 modems at ports 20H (com3) and 2EH (com4). ; com1 (1 in status list) means serial port B. ; com2 (2 in status list) means serial port A. ; com3 (3 in status list) means S-100 port 1 (20H). ; com4 (4 in status list) means S-100 port 2 (2EH). ; public getbaud, serini, serrst, clrbuf, outchr, coms, vts, vtstat public ctlu, cmblnk, locate, prtchr, baudst, clearl, bdtab, dodel public beep, sprtch, klen, ktab, krpl, getivec, setivec, dupflg public count, xofsnt, puthlp, putmod, clrmod, poscur, pcwait public sendbr, sendbl, machnam, lclini, outch2, dis_scan public ihosts, ihostr, dtrlow, mdmhand, shomodem, getmodem public portval, port1, port2, port3, port4, serhng, ena_scan public flowon, flowoff, sescur, sesdisp, setnbios, peekcom, parmsk off equ 0 false equ 0 true equ 1 bufon equ 1 ; buffer level xon/xoff on-state control flag usron equ 2 ; user level xon/xoff on-state control flag mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full mntrgl equ bufsiz/4 ; Low point = 1/4 buffer full xoftime equ 15 ; 15 seconds time out for xoff, see timer ; constants used by serial port handler ; Z-100 standard serial ports A (J1) and B (J2), called COM2 and COM1 here. ; Note that A=J1=COM2=2 and B=J2=COM1=1. Port B is the standard modem port ; similar to an IBM PC port. Thats why. ; serial port information TSRE EQU 004H THBE EQU 001H DTR EQU 002H DTROFF EQU 0fdH RTS EQU 020H RTSOFF EQU 0dfH DCD EQU 040H DSR EQU 080H RDA EQU 002H J1_ADDR EQU 0e8H J2_ADDR EQU 0ecH PDATA EQU 0 PSTATUS EQU 1 PMODE EQU 2 PCOMM EQU 3 TXON EQU 001H TXOFF EQU 0feH RXON EQU 004H RXOFF EQU 0fbH MODE1 EQU 04dH MODE2 EQU 030H ; must be ORed with appropriate baud rate Z8259 EQU 0f2H EOI EQU 020H J1INT EQU 68 J2INT EQU 69 BUFILEN EQU bufsiz BUFOLEN EQU bufsiz/2 BRKBIT EQU 048H ; Send-break bit. mdmdat1 equ J2_ADDR ; Address of serial port B (J2) mdmcom1 equ J2_ADDR + PCOMM ; Address of serial port B command mdmdat2 equ J1_ADDR ; Address of serial port A (J1) mdmcom2 equ J1_ADDR + PCOMM ; Address of serial port A command ;US Robotics S-100 modem using 8251A USART data mdmdat3 equ 020h ; Address of USR S-100 port 1 mdmcom3 equ mdmdat3 + 1 ; Address of USR S-100 command port mdmdat4 equ 02eh ; Address of USR S-100 port 2 mdmcom4 equ mdmdat4 + 1 ; Address of USR S-100 command port modsndb equ 1h ; Bit to test for send S-100 modem modrcvb equ 2h ; Bit to test for receive S-100 modem modperb equ 8h ; Parity error detect bit S-100 modem modorub equ 10h ; Overrun error detect bit moddcdb equ 80h ; Carrier detect bit S-100 modem COLUMNS EQU 80 ; Characters per screen line. ROWS EQU 24 ; Text lines per screen VID_CMD EQU 0d8h ; Video-memory control port. PAR_GRN EQU 0e000h ; Green video plane segment address. ; external variables used: ; 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 (currently either port1, ; port2, port3 or port4 ) ; port1, port2, port3, port4 - portinfo structures for the corresponding ports ; monmode - color/monochrome mode of monitor ; dmpname - file name for screen dump file ; global variables defined in this module: ; xofsnt, xofrcv - tell whether we saw or sent an xoff. BIOS_SEG SEGMENT AT 40H ; Define segment where BIOS really is ORG 1*3 BIOS_STATUS LABEL FAR ; Console input status ORG 2*3 BIOS_CONIN LABEL FAR ; Console input ORG 3*3 BIOS_CONOUT LABEL FAR ; Console output ORG 4*3 BIOS_PRINT LABEL FAR ; Printer output ORG 6*3 BIOS_AUXOUT LABEL FAR ; AUX output routine ORG 25*3 BIOS_PRNFUNC LABEL FAR ; PRN: FUNCTION ORG 26*3 BIOS_AUXFUNC LABEL FAR ; AUX: function ORG 27*3 BIOS_CONFUNC LABEL FAR ; CON: function BIOS_SEG ENDS ; Define functions of BIOS_CONFUNC, BIOS_PRNFUNC, and BIOS_AUXFUNC CHR_WRITE EQU 0 ; Write function CHR_READ EQU CHR_WRITE+1 ; Read function CHR_STATUS EQU CHR_READ+1 ; Status function CHR_SFGS EQU 0 ; Get status subfunction CHRS_WA EQU 00000001B ; sent, waiting for CHRS_WD EQU 00000010B ; seen, waiting for CHRS_SN EQU 00000100B ; Sending nulls CHRS_TXR EQU 10000000B ; Transmitter ready to send data CHRS_RXR EQU 01000000B ; Receiver has data CHRS_RXOF EQU 00100000B ; Receiver queue overflow CHRS_RXE EQU 00010000B ; Other type of reciver error CHRS_TXE EQU 00001000B ; Transmitter error CHR_SFGC EQU CHR_SFGS+1 ; Get configuration info subfunction CHR_CONTROL EQU CHR_STATUS+1 ; Control function CHR_CFSU EQU 0 ; Setup new configuration parms subfunction CHR_CFCI EQU CHR_CFSU+1 ; Clear input subfunction CHR_CFCO EQU CHR_CFCI+1 ; Clear output subfunction CHR_LOOK EQU CHR_CONTROL+1; Nondestructive read function CHR_FMAX EQU CHR_LOOK ; Maximum function number ; storage for port configuration cfginfo struc cfclass db 0 cfattr db 0 cfport dw 0 cfbaud db 0 cfhshk db 0 cfbctl db 0 cfecnt db 0 cfncnt db 0 cfnchr db 0 cfres db 6 dup(?) cfsize db 0 cfginfo ends ; structure for status information table sttab. stent struc sttyp dw ? ; type (actually routine to call) msg dw ? ; message to print val2 dw ? ; needed value: another message, or tbl addr tstcel dw ? ; address of cell to test, in data segment basval dw 0 ; base value, if non-zero stent ends data segment extrn flags:byte, trans:byte, taklev:byte, verident:byte extrn comptab:byte, termtb:byte, ontab:byte, scrtab:byte extrn cntltab:byte, beltab:byte, curtab:byte, chatab:byte extrn kpamtab:byte, dirtab:byte, doscol:byte extrn lclsusp:word, lclrest:word, lclexit:word, dosflg:byte extrn dosflg1:byte, repflg:byte, diskio:byte, kstatus:byte extrn holdscr:byte, vtemu:word, lincur:word extrn belltype:byte, vtroll:byte oldoff dw 0 oldseg dw 0 sescur dw 0 dupflg db 0 ; full (0) or half (1) duplex on port brkval db 0 ; What to send for a break. brkdur dw 0 ; Length of break in centiseconds badbd db cr,lf,'Unimplemented baud rate$' noimp db cr,lf,'Not implemented$' coms0msg db cr,lf,'No US Robotics S-100 modem detected at this port!' db cr,lf,'$' comsmsg db ' One of the following:' db cr,lf,' 1 2 3 4 COM1 COM2 COM3 COM4 A B J1 J2' db cr,lf,lf,'Where' db cr,lf,' 1 = COM1 = Serial Port B = J2' db cr,lf,' 2 = COM2 = Serial Port A = J1' db cr,lf,' 3 = COM3 = US Robotics S-100 modem at port 20H' db cr,lf,' 4 = COM4 = US Robotics S-100 modem at port 2EH$' vtsmsg db cr,lf,'The Z-100 terminal has inherent HEATH-19 support.' db cr,lf,' Set terminal none activates native Heath-19 ' db 'properties.',cr,lf db ' This deactivates key mapping and scan codes.$' msmsg0 db cr,lf,' Modem may be ready: DSR is unknown$' msmsg1 db cr,lf,' Modem is not ready: DSR is off$' msmsg2 db cr,lf,' Modem is ready: DSR is on$' msmsg3 db cr,lf,' no Carrier Detect: CD is off$' msmsg4 db cr,lf,' Carrier Detect: CD is on$' msmsg5 db cr,lf,' no Clear To Send: CTS is off$' msmsg6 db cr,lf,' Clear To Send: CTS is on$' msmsg7 db cr,lf,' Modem is not used by the Network$' not_z db 'Sorry, wrong software!',cr,lf db 'This Kermit will only run on the Z-100 -- a non ' db 'IBM PC compatible',cr,lf,lf machnam db 'Heath-Zenith_Z-100$' com3ms db 'Carrier detected at S-100 Port 20H, COM3',cr,lf,'$' com4ms db 'Carrier detected at S-100 Port 2EH, COM4',cr,lf,'$' com3ms1 db 'Modem detected at S-100 Port 20H, COM3',cr,lf,'$' com4ms1 db 'Modem detected at S-100 Port 2EH, COM4' crlf db cr,lf,'$' infmsg db 'S-100 MODEM INITIALIZATION FAILURE',cr,lf,'$' wmsg db cr,lf,' CARRIER detected -- disconnecting',cr,lf,'$' dscmsg db cr,lf,' DISCONNECTED',cr,lf,'$' ndscmsg db cr,lf,' !!! WARNING >>> NOT DISCONNECTED !!!',cr,lf,'$' hngstr db '+++$' hngmsg db cr,lf,' The phone should have hungup.',cr,lf,'$' ; [jrd] hnghlp db cr,lf,' The modem control lines DTR and RTS for the current' db ' port are forced low (off)' db cr,lf,' to hangup the phone. Normally, Kermit leaves them' db ' high (on) when it exits.' db cr,lf,lf,' The USR S-100 modem is hung up using "+++".' db cr,lf,'$' rdbuf db 80 dup (?) ; temp buf [jrd] delstr db BS,BS,' ',BS,BS,'$' ; Delete string clrlin db BS,BS,' ',cr,'$' ; Clear line (just the cr part) home db ESCAPE,'H$' ; Home cursor clrstr db ESCAPE,'E$' ; Home cursor and erase entire display eeolstr db ESCAPE,'K$' ; Erase to end of line enamod db ESCAPE,'x1$' ; Enable 25th line dismod db ESCAPE,'y1$' ; Disable 25th line enascan db ESCAPE,'y?$' ; Enable scan codes, disable key expansion disscan db ESCAPE,'x?$' ; Disable scan codes, enable key expansion begrev db ESCAPE,'p$' ; Enter reverse video endrev db ESCAPE,'q$' ; Exit reverse video lin25 db ESCAPE,'Y8 $' ; Column 1 row 25 savcur db ESCAPE,'j$' ; Save current cursor position precur db ESCAPE,'k$' ; Restore cursor to previous position monstr db ESCAPE,'i0$' ; Return montior information portin db -1 ; Has comm port been initialized? ; -1=has not used, 1=is used, 0=has been used xofsnt db 0 ; Say if we sent an XOFF xofrcv db 0 ; Say if we received an XOFF parmsk db 0ffh ; parity mask, 0ffh for no parity, 07fh with flowoff db 0 ; flow-off char, Xoff or null (if no flow) flowon db 0 ; flow-on char, Xon or null tmp db 0,'$' temp dw 0 ; Temporary storage. mddat0 dw 0 ; Storage for modem data port mdstat0 dw 0 ; Storage for modem status port savedi dw offset source ; Temporary storage for di srcpnt dw offset source ; where to read next serial port byte source db bufsiz dup(0) ; S-100 port input buffer timer db 0 timer0 db 0 ; begin Terminal emulator data set portmax equ 4 ; number of predefined ports port1 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0> port2 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0> port3 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0> port4 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0> rept portmax-4 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon,0> endm portval dw port1 ; Default is to use port 1 bdtab db 16 ; 16 entries mkeyw '45.5',0 mkeyw '50 ',1 mkeyw '75 ',2 mkeyw '110 ',3 mkeyw '134.5',4 mkeyw '150',5 mkeyw '300',6 mkeyw '600',7 mkeyw '1200',8 mkeyw '1800',9 mkeyw '2000',10 mkeyw '2400',11 mkeyw '4800',12 mkeyw '9600',13 mkeyw '19200',14 mkeyw '38400',15 bdtab12 db 16 ; 16 (yes 16) entries for com1 and com2 mkeyw '45.5',0 mkeyw '50 ',1 mkeyw '75 ',2 mkeyw '110 ',3 lbdtab12 equ $-bdtab12 ; length of table bdtab34 db 4 ; 4 entries for com3 and com4, s-100 modem mkeyw '150 ',0 mkeyw '300',1 mkeyw '600',2 mkeyw '1200',3 ; this table is indexed by the baud rate definitions given in ; bdtab. Unsupported baud rates should contain 0FFH. bddat label word dw 0 ; 45.5 baud dw 1 ; 50 baud dw 2 ; 75 baud dw 3 ; 110 baud dw 4 ; 134.5 baud dw 5 ; 150 baud dw 6 ; 300 baud dw 7 ; 600 baud dw 8 ; 1200 baud dw 9 ; 1800 baud dw 10 ; 2000 baud dw 11 ; 2400 baud dw 12 ; 4800 baud dw 13 ; 9600 baud dw 14 ; 19200 baud dw 15 ; 38400 baud lbddat equ $-bddat ; length of table bddat12 label word ; for com1 and com2 dw 0 ; 45.5 baud dw 1 ; 50 baud dw 2 ; 75 baud dw 3 ; 110 baud dw 4 ; 134.5 baud dw 5 ; 150 baud dw 6 ; 300 baud dw 7 ; 600 baud dw 8 ; 1200 baud dw 9 ; 1800 baud dw 10 ; 2000 baud dw 11 ; 2400 baud dw 12 ; 4800 baud dw 13 ; 9600 baud dw 14 ; 19200 baud dw 15 ; 38400 baud bddat34 label word ; for com3 and com4, s-100 modem dw 0 ; 150 baud dw 1 ; 300 baud dw 2 ; 600 baud dw 3 ; 1200 baud dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh dw 0ffh ; baud rate data for S-100 modem bd150 db 4fh ; Low speed mode byte (150/300) db 17h ; Low speed command byte (150/600) bd300 db 4fh ; Low speed mode byte (150/300) db 37h ; High speed command byte(300/1200) bd600 db 4eh ; High speed mode byte (600/1200) db 17h ; Low speed command byte (150/600) bd1200 db 4eh ; High speed mode byte (300/1200) db 37h ; High speed command byte(300/1200) ; S-100 COM3/COM4 default baud rate: 0=150, 1=300, 2=600, 3=1200 baud bds100 equ 3 ; Set to 0, 1, 2, or 3 ; S-100 modem set up string ; echo commands, use extended result codes, do not answer call set_str db 'ATE1X1S0=0',cr,'$' auxconf cfginfo <> ; variables for serial interrupt handler count dw 0 ; Number of chars in int buffer. buffin db BUFILEN+2 dup(?) ; input buffer bufibeg dw 0 bufiend dw 0 buffout db BUFOLEN+2 dup(?) ; output buffer bufobeg dw 0 bufoend dw 0 portadr dw 0 intin db 0 ; port int installed flag mdmhand db 0 ; Modem status ourarg termarg <> klen dw ? ; length of key redefinition table ktab dw ? ; address of key redefinition table krpl dw ? ; address of key replacement table colortb db 0,4,2,6,1,5,3,7 ; color reversed-bit setting bytes clrset db ? ; Temp for SET Term Tabstops xxx ; This is data for the extended set terminal parameters. It was put here ; in order to keep the size of msyz10.asm within limits for assembly by ; MASM 4. The corresponding code is conatained in VTS and VTSTAT below. erms41 db cr,lf,'?More parameters are needed$' vthlp db ' one of the following:',cr,lf db ' terminal types of: None, Heath-19, VT52, VT102, VT320,' db ' or Tek4010',cr,lf db ' Newline-mode Cursor-style Character-set' db cr,lf db ' Keyclick Margin-bell Screen-background' db ' (normal, reverse)',cr,lf db ' Tabstops Wrap (long lines) Color (fore & background)' db cr,lf,' Bell audible or visual' db cr,lf,' Clear-screen (clears old startup screen)' db cr,lf,' Controls 7-bit or 8-bit (permits VT320 to use' db ' 8-bit control sequences (C1))' db cr,lf,' Direction Left-to-right or Right-to-left' db ' (screen writing direction)' db cr,lf,' Graphics (type of display adapter when in Tek4010' db ' mode)' db cr,lf,' Keypad numeric (normal) or application mode' db cr,lf,' Replay filespec (display a file through the emulator)' db cr,lf,' Rollback (undo screen roll back before writing new' db ' chars, default=off)$' clrhlp db ' one of the following:' db cr,lf,' AT #s (to set tabs at column #s) or' db ' AT start-column:spacing' db cr,lf,' Clear AT #s (clears individual tabs) or' db ' AT start-column:spacing' db cr,lf,' Clear ALL (to clear all tabstops)' db cr,lf,' Ex: Set term tab at 10, 20, 34 sets tabs' db cr,lf,' Ex: Set term tab at 1:8 sets tabs at 1, 9,' db cr,lf,' Ex: Set term tab clear at 9, 17, 65 clears tabs' db cr,lf,' Ex: Set term tab clear at 1:8 clears tabs at 1, 9,' db ' 17,...$' tbserr db cr,lf,'?Column number is not in range 1 to screen width-1$' colhlp db cr,lf,' Set Term Color value, value, value, ...' db cr,lf,' 0 no-snow mode on an IBM CGA and white on black' db cr,lf,' 1 for high intensity foreground' db cr,lf,' 10 for fast CGA screen updating (may cause snow)' db cr,lf,' Foreground color (30-37) = 30 + sum of colors' db cr,lf,' Background color (40-47) = 40 + sum of colors' db cr,lf,' where colors are 1 = red, 2 = green, 4 = blue' db cr,lf,' Ex: 0, 1, 37, 44 IBM CGA(0), bright(1) white(37)' db ' chars on a blue(44) field' db cr,lf,' Attributes are applied in order of appearance.$' colerr db cr,lf,'?Value not in range of 0, 1, 10, 30-37, or 40-47$' vtwrap db 'Term wrap-lines: $' vtbellm db 'Term margin-bell: $' vtnewln db 'Term newline: $' vtcur db 'Term cursor-style: $' vtcset db 'Term character-set: $' vtclik db 'Term key-click: $' vtscrn db 'Term screen-background: $' colst1 db 'Term color foregnd:3$' colst2 db ' backgnd:4$' vtrolst db 'Term rollback: $' vtdir db 'Term direction: $' vtcntst db 'Term controls: $' vtkpst db 'Term keypad: $' vtbset db 'Term bell: $' vtgchst db 'Term graph char: $' ; terminal emulator vtstbl stent ; char set stent ; keyclick stent ; line wrap stent ; controls stent ;margin bell stent ; cursor type stent ; bell stent ; write direct stent ; newline stent ; rollback stent ; keypad stent ; screen dw 0 ; end of table ; end of Terminal data set vttbl db 19 ; number of entries mkeyw 'Bell',8800h ; note 8800 flag for decoding mkeyw 'Character-set',chaval+8300h mkeyw 'Clear-screen',8500h ; 8500h = marker here mkeyw 'Color',8200H ; screen fore/back colors; 200H=marker mkeyw 'Controls',cntlval mkeyw 'Cursor-style',curval mkeyw 'Direction',dirval mkeyw 'Graphics',8600h ; Tek graphics board, 800h=marker mkeyw 'Heath-19',ttheath+8100H; note 8100H flag for decoding here mkeyw 'Keyclick',keyval mkeyw 'Keypad',kpamval mkeyw 'Margin-bell',marval mkeyw 'None',ttgenrc+8100H mkeyw 'Newline',newval mkeyw 'Replay',8700h ; note 8700H flag for file replaying mkeyw 'Rollback',8400h ; note 8400H flag for decoding mkeyw 'Screen-background',scrval mkeyw 'Tabstops',tabval mkeyw 'Wrap',wraval vtsflg equ this word ; define small digits xxxval newval equ $-vtsflg ; 0 and mask for bit in byte dw vsnewline ; 1 wraval equ $-vtsflg ; 2 dw vswrap ; 2 chaval equ $-vtsflg ; 4 dw vsnrcm ; 4 dirval equ $-vtsflg ; 6 dw vswdir ; 8 keyval equ $-vtsflg ; 8 dw vskeyclick ; 10h marval equ $-vtsflg ; 10 dw vsmarginbell ; 20h curval equ $-vtsflg ; 12 dw vscursor ; 40h scrval equ $-vtsflg ; 14 dw vsscreen ; 80h cntlval equ $-vtsflg ; 16 dw vscntl ; 100h kpamval equ $-vtsflg ; 18 dw deckpam ; 400h numflgs equ ($-vtsflg)/2 ; 10 tabval equ $-vtsflg ; 20 dw 0 ;vtrtns dw numflgs dup (flgset), tabmod ; dispatch table for vtsflg data ends code segment public extrn comnd:near, dopar:near, defkey:near, getpos:near, atsclr:near extrn lclyini:near, setcol:near, srchkb:near, srchkw:near extrn csrtype:near assume cs:code, ds:data, es:nothing ; local initialization LCLINI proc near jmp lclini1 ; Bypass the exit code not_z10:mov ah,prstr mov dx,offset not_z ; This is not a Z-100, IBM PC maybe? int dos ; This program is for mov dx,offset verident ; display version header int dos mov ah,4ch ; terminate process int dos ; Find out if this is a Z-100 ; We are doing that by looking for 0E9H at locations 0040:0000H ; and 0040:0003H which are in the Z-100 bios jump table. lclini1:mov bx,BIOS_SEG ; The segment at 40h mov ax,es ; Save es mov es,bx ; Set up the extra segment cmp byte ptr es:0,0e9h ; Z-100? jnz not_z10 ; No, it's probably IBM compatible cmp byte ptr es:3,0e9h ;Z-100? jnz not_z10 ; No, it's probably IBM compatible mov es,ax ; Restore es ; mov flags.vtflg,ttheath ; Set Heath-19 emulation mode, allows macs mov brkval,BRKBIT ; What to send for a break in al,mdmcom4 ; Check this port and al,modperb ; Is it there? jnz lclini3 ; No, skip mov dx,offset com4ms1 mov ah,prstr ; Tell user it is there int dos in al,mdmcom4 ; Check again and al,moddcdb ; Carrier? jz lclini3 ; No, skip mov flags.comflg,4 ; Indicate s-100 port 2 for now mov portval,offset port4 mov mddat0,mdmdat4 mov mdstat0,mdmcom4 mov ah,prstr ; Tell user mov dx,offset com4ms int dos lclini3:in al,mdmcom3 ; Check this port and al,modperb ; Is it there? jnz lclini4 ; No, skip mov dx,offset com3ms1 mov ah,prstr ; Tell user it is there int dos in al,mdmcom3 ; Check again and al,moddcdb ; Carrier? jz lclini4 ; No, skip mov flags.comflg,3 ; Indicate s-100 port 1 mov portval,offset port3 mov mddat0,mdmdat3 mov mdstat0,mdmcom3 mov ah,prstr ; Tell user mov dx,offset com3ms int dos lclini4: call getbaud ; Which port of COM1/COM2 is default? ; Get baud rate from UARTs for this call baudref ; Set up baud rate references bdtab, bddat mov port3.baud,bds100 ; and put in default baud rate mov port4.baud,bds100 ; and put in default baud rate mov lclsusp,offset suspend ; call this when suspending to DOS mov lclrest,offset restore ; call this when returning from DOS mov lclexit,offset finexit ; call this when exiting Kermit call ena_wrp ; Make terminal wrap to next line at line end call lclyini ; let other modules initialize too... ret ; We are all done with lclini ; baudref:push di ; Rearrange bdtab and bddat push si push es mov ax,ds ; Set up mov es,ax ; pointers mov di,offset bddat ; to move baud mov si,offset bddat12 ; rate selection mov cx,lbddat ; length of table cmp flags.comflg,2 ; Ports 1/2 jle lclini5 ; or ports 3/4? mov si,offset bddat34 ;Port 4! lclini5:cld rep movsb ; Move array mov di,offset bdtab ; This too mov si,offset bdtab12 mov cx,lbdtab12 ; Length of table cmp flags.comflg,2 ; Ports 1/2 jle lclini6 ; or ports 3/4? mov si,offset bdtab34 ;Port 4! lclini6:rep movsb ; Move array pop es ; Restore registers pop si pop di ret ; We're done LCLINI endp ; Call these routines when suspending Kermit to go to DOS suspend proc near call ihosts ; suspend the host call serrst call dis_scan ; disable scan code generation call dis_wrp ; disable sreen line wrap around ret suspend endp ; Call these routines when returning to Kermit from DOS restore proc near call serini ; reinit serial port call ihostr ; resume the host call ena_wrp ; enable screen line wrap around ret restore endp ; Call these routines when doing final exit of Kermit finexit proc near call serrst ; reset serial port call dis_scan ; disable scan code generation call dis_wrp ; disable sreen line wrap around ret finexit endp ; This routine, ena_scan, enables Z-100 scan code generation. It also ; disables extended key code generation. Modifies ax. ENA_SCAN PROC NEAR push dx mov ah,prstr mov dx,offset enascan int dos or dosflg1,1 ; say scan codes enabled pop dx ret ENA_SCAN ENDP ; This routine, dis_scan, disables Z-100 scan code generation. It also ; enables extended key code generatin. Modifies ax. DIS_SCAN PROC NEAR push dx mov ah,prstr mov dx,offset disscan int dos and dosflg1,0feh ; say scan codes disabled pop dx ret DIS_SCAN ENDP ; This routine, ena_wrp, enables wrap around at end of line. ; Modifies ax. ENA_WRP PROC NEAR push dx mov ah,conout mov dl,ESCAPE int dos mov dl,'v' int dos pop dx ret ENA_WRP ENDP ; This routine, dis_wrp, disables wrap around at end of line. ; Modifies ax. DIS_WRP PROC NEAR push dx mov ah,conout mov dl,ESCAPE int dos mov dl,'w' int dos pop dx ret DIS_WRP ENDP ; SHOW MODEM, displays current status of lines DSR, CD, and CTS. ; Uses byte mdmhand, the modem line status register. [jrd] shomodem proc near mov ah,cmeol ; get a confirm call comnd jc shomd5 ; c = failure mov dx,offset msmsg7 ; no modem status for network call getmodem ; get modem status mov ah,prstr cmp flags.comflg,2 ; port 1 or 2 jle shomd0 ; yes, jump mov dx,offset msmsg0 ; not supported function jmp shomd1 shomd0: mov dx,offset msmsg1 ; modem not ready msg test mdmhand,20h ; is DSR asserted? jz shomd1 ; z = not ready mov dx,offset msmsg2 ; modem ready msg shomd1: int dos mov dx,offset msmsg3 ; CD not asserted msg test mdmhand,80h ; CD asserted? jz shomd2 ; z = not asserted mov dx,offset msmsg4 ; CD asserted msg shomd2: int dos clc shomd5: ret shomodem endp ; Get modem status and set global byte mdmhand. Preserve all registers but dx. ; Returns with byte mdmhand in al, ah=0. getmodem proc near ; gets modem status upon request cmp flags.comflg,2 ; COM1 or COM2? jna getmodem2 ; na = yes, jump to handle these mov dx,mdstat0 ; Port address in al,dx ; Get status and al,moddcdb ; Carrier? mov mdmhand,0 ; Everything off jz getmodem1 ; z = yes, no carrier, done mov mdmhand,80h ; No, carrier detected getmodem1:jmp getmodem4 ; Done with COM3/COM4 getmodem2:mov dx,portadr add dx,PSTATUS in al,dx mov mdmhand,0 ; Everything off test al,DSR ; DSR indicated? jz getmodem3 ; z = no, go on mov mdmhand,20h ; Indicate DSR getmodem3:test al,DCD ; CD indicated? jz getmodem4 ; z = no, go on or mdmhand,80h ; Indicate CD, don't touch DSR getmodem4:mov al,mdmhand ; Promised it here xor ah,ah ; A promise too clc ; Success ret getmodem 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. CLRBUF PROC NEAR cmp flags.comflg,2 ; Ports 1/2? jg clrbuf1 ; g = no, do S-100 stuff cli push bx xor bx,bx mov bufoend,bx mov bufobeg,bx mov bufiend,bx mov bufibeg,bx pop bx mov count,0 sti ret clrbuf1:push ax ; First empty port push dx mov dx,mddat0 ; Get possible in al,dx ; character pop dx pop ax ; then do it mov count,0 ; Nothing in buffer mov srcpnt,offset source ; Reset buffer mov savedi,offset source ; pointers ret CLRBUF ENDP ; Put the char in AH to the serial port, assumimg the port is active. ; Returns carry clear if success, else carry set. ; 16 May 1987 Add entry point OUTCH2 for non-flow controlled sending to ; prevent confusion of flow control logic at top of outchr; used by receiver ; buffer high/low water mark flow control code. [jrd] ; 14 September 1990 add entry point OUTCH5 for priority sending of xon; ; used by CHKXON and SERISR. OUTCHR PROC NEAR cmp flowoff,0 ; Are we doing flow control je outch2 ; No, just continue cmp ah,flowoff ; sending xoff? jne outch1 ; ne = no mov xofsnt,usron ; indicate user level xoff being sent jmp outch12 outch1:and xofsnt,not usron ; cancel user level xoff cmp ah,flowon ; user sending xon? jne outch12 ; ne = no mov xofsnt,off ; say an xon has been sent (cancels xoff) outch12:mov timer,xoftime+1 ; Set delay to xoftime minimum, maximum+1 sec outch14:cmp xofrcv,true ; Are we being held (xoff received)? jnz outch2 ; no - it's OK to go on cmp flags.comflg,2 ; Check if S-100 ports push ax ; Save regs push bx push cx push dx jle outch16 ; No, make it simple push es mov cx,1 ; No delay for sprtch call sprtch ; Get possible char at port com3/4 pop es outch16:mov ah,gettim ; Get time function int dos cmp dl,timer0 ; Normally 0 pop dx pop cx pop bx pop ax jnz outch14 ; No, go loop xor timer0,50 ; Yes, move target 1/2 second cmp timer0,0 ; This is only true every second jnz outch14 ; No, continue looping dec timer ; Yes, one second has passed (unless 1st time) jnz outch14 ; No, have more seconds left, try again mov xofrcv,off ; Timed out, force it off and fall thru. OUTCH2 LABEL NEAR ; outch2 entry point without flow control mov al,ah ; Routine works on AL. call dopar ; Set parity appropriately. cmp repflg,0 ; Doing REPLAY from a file? je outch24 ; e = no and al,7fh ; Strip parity cmp al,'C'-40h ; Control-C? (to exit playback mode) je outch22 ; e = yes, return failure clc ; Return success, send nothing ret outch22:stc ; Return failure to exit playback mode ret ; outch24:push bx push dx cmp flags.comflg,2 ; Ports J1/J2 jle outch4 ; Yes, go handle J1/J2 mov bl,al ; No, do S-100, save byte to send push cx xor cx,cx ; Set loop counter outch26:push bx ; Check on input push cx push es mov cx,1 ; No delay call sprtch ; Get char from port if any pop es pop cx pop bx mov dx,mdstat0 in al,dx ; Check this port and al,modsndb ; for ready jnz outch28 ; Ready, continue loop outch26 ; Not ready, loop until ready or timeout jmp short outch44 ; Timed out, return with carry set outch28:pop cx mov al,bl ; Get back byte to send mov dx,mddat0 out dx,al ; Send it out jmp outch8 ; All done S-100 modem ; outch4: push cx xor cx,cx ; Set loop counter outch40:mov bx,bufobeg ; get pointer to beginning of que sub bx,bufoend ; where are we? jnl outch42 ; we did not wrap add bx,BUFOLEN ; we have wrapped outch42:cmp bx,BUFOLEN-2 ; we have bx char in buffer; is it full? jnae outch53 ; no, go on loop outch40 ; yes, loop until there is space or timeout outch44:pop cx ; timed out pop dx pop bx stc ret ; outch5: push bx ; OUTCH5 entry for SERISR and CHKXON push dx ; ah will contain xon or xoff only push cx xor cx,cx ; Set loop counter outch50:mov bx,bufobeg ; get pointer to beginning of que sub bx,bufoend ; where are we? jnl outch51 ; we did not wrap add bx,BUFOLEN ; we have wrapped outch51:cmp bx,BUFOLEN ; we have bx char in buffer; is it full? jne outch52 ; no, go on loop outch50 ; yes, loop until there is space or timeout jmp short outch44 ; timed out, no space outch52:mov al,ah ; Routine works on AL. call dopar ; Set parity appropriately. pop cx jmp short outch54 ; outch53:pop cx ; restore stack cmp bx,0 ; buffer empty? jz outch58 ; yes, skip cmp flowoff,0 ; Are we doing flow control je outch58 ; No, skip cmp al,flowoff ; Is it xoff? je outch54 ; Yes, this is priority, expedite cmp al,flowon ; Is it xon? jne outch58 ; No, skip ; outch54:cli mov bx,bufobeg ; beginning of que dec bx ; we want space in between, bx still >= 0 jae outch56 ; yes, go on mov bx,BUFOLEN ; wrap outch56:mov bufobeg,bx ; new beginning mov byte ptr buffout[bx],al ; put char in it sti jmp short outch6 outch58:mov bx,bufoend mov byte ptr buffout[bx],al ; put char in it inc bx ; point to next spot in que cmp bx,BUFOLEN ; looking at end of que ? jne outch6 ; no, OK xor bx,bx ; yes, reset pointer outch6: mov bufoend,bx ; store new value mov dx,portadr add dx,PCOMM cli in al,dx test al,TXON ; TX already on ? jnz outch7 ; yes, OK or al,TXON ; no, turn it on out dx,al ; it's on outch7: sti ; done with 2661 outch8: pop dx pop bx clc ; success, return with carry cleared ret OUTCHR ENDP ; Move the cursor to the left margin, then clear to end of line. CTLU PROC NEAR mov ah,prstr mov dx,offset clrlin int dos ; Clear to the end of the current line CLEARL PROC NEAR push ax push dx mov ah,prstr mov dx,offset eeolstr ; Erase to end of line int dos pop dx pop ax ret CLEARL ENDP CTLU ENDP ; This routine blanks the screen and homes the cursor. Uses ax and dx. CMBLNK PROC NEAR mov ah,prstr mov dx,offset clrstr ; Home cursor, blank screen int dos ret CMBLNK ENDP ; Locate: homes the cursor. Uses ax and dx. LOCATE PROC NEAR mov ah,prstr mov dx,offset home ; Go to top left corner of screen. int dos LOCATE ENDP ; write a line in inverse video at the bottom of the screen... ; the line is passed in dx, terminated by a $. PUTMOD PROC NEAR push ax ; save regs push dx ; preserve message mov ah,prstr mov dx,offset savcur int dos mov dx,offset enamod int dos mov dx,offset lin25 int dos mov dx,offset begrev int dos pop dx ; get message back int dos ; write it out mov dx,offset endrev int dos mov dx,offset precur int dos pop ax ret ; and return PUTMOD ENDP ; clear the mode line written by putmod. CLRMOD PROC NEAR mov ah,prstr mov dx,offset dismod int dos ret CLRMOD ENDP BEEP PROC NEAR push ax ; save regs push dx ; preserve message mov ah,conout mov dl,BELL ; ASCII BEL int dos ; Ring it pop dx pop ax clc ret BEEP ENDP ; Put a help message on the screen. This one uses reverse video... ; pass the message in ax, terminated by a null. Messes up ax, bx, cx, dx. PUTHLP PROC NEAR push si push ax ; preserve this mov dx,offset crlf int dos pop si ; point to string again jmp short puthl3 ; assume message begins with cr and lf puthl2: call getpos ; get cursor pos into dx mov ax,dx ; from row ah, col al mov bx,dx mov bl,COLUMNS ; to row bh, col bl mov dx,word ptr doscol ; dos color reversed call setcol ; set this color call atsclr ; and clear the line puthl3: mov cx,COLUMNS - 1 ; characters on a line less one (starts at 0) puthl4: lodsb ; get a byte mov ah,conout ; print char cmp al,0 ; end of string? je puthl5 ; yes, stop cmp al,lf ; lf ? je puthl7 ; end of line, do new one cmp cx,0 ; last column je puthl6 ; no more space on line, get new one mov dl,al ; else, print char int dos jmp short puthl3 ; get next char puthl5: pop si ret puthl6: mov dl,cr int dos puthl7: mov dl,lf int dos jmp short puthl2 PUTHLP ENDP ; Set the baud rate for the current port, based on the value ; in the portinfo structure. Returns carry clear. BAUDST PROC NEAR mov dx,offset bdtab ; baud rate table, ascii xor bx,bx ; help is the table itself mov ah,cmkey ; get keyword call comnd jc baudst1 ; c = failure push bx ; save result mov ah,cmeol ; get confirmation call comnd pop bx jc baudst1 ; c = failure push si mov si,portval mov ax,[si].baud ; remember original value mov [si].baud,bx ; set the baud rate pop si call dobaud ; use common code clc baudst1:ret BAUDST ENDP DOBAUD PROC NEAR push ax ; save some regs push bx push cx push dx mov bp,portval ; Pointer to port data structure mov temp,ax ; Don't overwrite previous rate mov ax,ds:[bp].baud ; Check if new rate is valid shl ax,1 ; Get index into baud table mov bx,offset bddat ; Start of table. add bx,ax mov ax,[bx] ; The data to output to port. cmp ax,0FFH ; Unimplemented baud rate. jne dobd0 mov ax,temp ; Get back orginal value. mov ds:[bp].baud,ax ; Leave baud rate as is. mov ah,prstr mov dx,offset badbd ; Give an error message. int dos stc ; Failure jmp dobd2 dobd0: mov ds:[bp].baud,ax ; Put in new baud rate cmp flags.comflg,2 ; is it J1/J2? jle dobd1 ; yes, go do J1/J2 stuff call serini ; go set rate in S-100 modem jmp dobd2 dobd1: mov dx,portadr ; get addr to send it add dx,PMODE push ax ; save baud mov al,MODE1 cli ; none while setting 2661 out dx,al ; mode reg 1/2 pop ax ; get baud back and al,0fH ; make sure it's clean or al,MODE2 ; make complete mode 2/2 command out dx,al ; set mode reg 2/2 sti ; done with 2661 clc ; Success dobd2: pop dx ; restore regs pop cx pop bx pop ax ret DOBAUD ENDP ; Get the current baud rate from the serial card and set it ; in the portinfo structure for the current port. ; Also finds out which serial port, A (COM2) or B (COM1), is defined ; as default by Zenith Configur. ; This is used during initialization. GETBAUD PROC NEAR cmp flags.comflg,2 ; J1/J2? jg getbau3 ; No, all done push ax push bx push dx push di cmp portadr,0 ; Just started Kermit? jnz getbau2 ; No, skip this mov bx,ds ; Set up pointer to config info mov es,bx mov bx,offset auxconf mov ah,chr_status mov al,chr_sfgc ; Get current config info call bios_auxfunc cmp auxconf.cfport,mdmdat1 ; Is it B? jne getbau1 ; ne = no mov flags.comflg,1 ; Set flag to indicate port B mov portval,offset port1 mov mddat0,mdmdat1 mov portadr,mdmdat1 mov mdstat0,mdmcom1 jmp getbau2 getbau1:mov flags.comflg,2 ; Set flag to indicate port A mov portval,offset port2 mov mddat0,mdmdat2 mov portadr,mdmdat2 mov mdstat0,mdmcom2 getbau2:mov dx,portadr ; Get addr to retrieve mode from add dx,PMODE in al,dx ; Read and discard mode 1/2 in al,dx ; mode 2/2 has baud rate and ax,000fH ; Clean it up mov bp,portval mov ds:[bp].baud,ax ; Put it in portinfo struct pop di pop dx pop bx pop ax getbau3:ret GETBAUD ENDP ; Get Char from serial port buffer. ; returns carry set if no character available at port, otherwise prtchr ; returns carry clear with char in al, # of chars in buffer in dx and count. PRTCHR PROC NEAR cmp flags.comflg,2 ; check if S-100 ports jg prtch4 ; Yes, go do S-100 stuff call chkxon ; see if we need to xon cmp repflg,0 ; REPLAY? je prtch0 ; e = no jmp prtch30 ; yes, do replay file reading prtch0: cli ; dont let intterrupts touch buffers mov dx,bufiend ; compute number of chars in sub dx,bufibeg ; input que jge prtch1 ; is it wrapped around add dx,BUFILEN ; yes, make it + prtch1: cmp dx,0 ; anything in there ? jne prtch2 ; ne = yes. [jrd] mov count,dx sti stc ; no ret prtch2: mov bx,bufibeg ; yes, get the char, get the position mov al,byte ptr buffin[bx] ; get the char inc bx ; bump the position ptr cmp bx,BUFILEN ; wrap it ? jne prtch3 xor bx,bx ; yes, reset pointer prtch3: mov bufibeg,bx ; store new value dec dx ; we took one char out mov count,dx ; save sti clc ; yes, got it ret prtch4: push ax ; First check port for possible input push bx push cx push es mov cx,1 ; Parameter for sprtch, cx=1 means don't loop call sprtch ; Read port pop es pop cx pop bx pop ax cmp repflg,0 ; REPLAY? je prtch41 ; e = no jmp prtch30 ; yes, do replay file reading prtch41:cmp count,0 ; Buffer empty? jne prtch5 ; ne = no, get char mov dx,0 ; Nothing there Is this needed? stc ; Got nothing ret prtch5: push si ; Don't mess up, used by spack mov si,srcpnt ; Point to next character in que cld lodsb ; Get the next one cmp si,offset source + bufsiz ; Bigger than buffer? jb prtch6 ; No, keep going mov si,offset source ; Yes, wrap around prtch6: dec count mov dx,count mov srcpnt,si pop si ; Left in good shape clc ; Yes, got it ret prtch30:cmp repflg,2 ; at EOF already? jne prtch31 ; ne = no stc ; yes, return with no char ret prtch31:push bx ; REPLAY, read char from a file push cx xor dx,dx test xofsnt,usron ; user level xoff sent? jz prtch32 ; z = no pop cx ; suppress reading here pop bx stc ; return with no char ret prtch32:mov ax,100 mov bx,1 jmp $+2 ; flush lookahead buffer div bx ; burn some cpu cycles div bx ; because a 1 ms wait is too long div bx div bx mov ah,readf2 mov bx,diskio.handle ; file handle mov cx,1 ; read one char mov dx,offset rdbuf ; to this buffer int dos jc prtch34 ; c = read failure cmp ax,cx ; read the byte? jne prtch34 ; ne = no pop cx pop bx mov al,rdbuf ; get the char into al mov dx,1 ; external char count clc ret ; return it prtch34:call beep mov ax,40 ; wait 40 millisec call pcwait call beep mov repflg,2 ; say at EOF pop cx pop bx stc ; say no char ret PRTCHR ENDP ; Examine incoming communications stream for a packet SOP character. ; Return CX= count of bytes starting at the SOP character (includes SOP) ; and carry clear. Return CX = 0 and carry set if SOP is not present. ; Destroys AL. peekcom proc far mov cx,count ; qty in circular buffer cmp cx,6 ; basic NAK jb peekc4 ; b = two few chars, get more push bx cli ; interrupts off, to keep srcpnt & count consistent mov bx,srcpnt ; address of next available slot in buffer sub bx,cx ; minus number of unread chars in buffer cmp bx,offset source ; located before start of buf? jae peekc1 ; ae = no add bx,bufsiz ; else do arithmetic modulo bufsiz peekc1: mov al,[bx] cmp al,trans.rsoh ; packet receive SOP? je peekc3 ; e = yes inc bx cmp bx,offset source+bufsiz ; beyond end of buffer? jb peekc2 ; b = no mov bx,offset source ; wrap around peekc2: loop peekc1 ; keep looking sti pop bx stc ; set carry for no SOP ret peekc3: sti ; interrupts back on now pop bx inc cx ; include SOP in count clc ; say SOP found ret ; CX has count remaining peekc4: xor cx,cx ; return count of zero stc ; say no data ret peekcom endp ; local routine to see if we have to transmit an xon when com1/2 chkxon proc near cmp xofsnt,false ; have we sent an xoff? je chkxo1 ; no, forget it cmp flowoff,0 ; Are wo doing flow control? je chkxo1 ; no, skip all this test xofsnt,usron ; did user send an xoff? jnz chkxo1 ; nz = yes, don't contradict it here test xofsnt,bufon ; have we sent a buffer level xoff? jz chkxo1 ; z = no, forget it cmp count,mntrgl ; below trigger? jae chkxo1 ; no, forget it mov ah,flowon ; xon call outch5 ; send it jc chkxo1 ; failure and xofsnt,false ; remember we've sent the xon. chkxo1: ret ; and return chkxon endp ; Local routine to see if we have to transmit an xoff or xon when com3/4 ; this is probably overdoing it ; called by sprtch chkxof proc near cmp flowoff,0 ; Are wo doing flow control? je chkxof1 ; no, skip all this test xofsnt,usron ; did user send an xoff? jnz chkxof1 ; nz = yes, don't contradict it here test xofsnt,bufon ; have we sent a buffer level xoff? jz chkxof1 ; z = no, forget it cmp count,mntrgh ; Buffer filling up? jb chkxof3 ; no, go check that xon sent cmp xofsnt,true ; yes, have we sent an xoff? je chkxof1 ; yes, all done mov ah,flowoff ; xoff mov xofsnt,true ; remember we've sent the xoff. jmp short chkxof2 ; go send xoff chkxof3:cmp count,mntrgl ; below trigger jae chkxof1 ; no, forget it cmp xofsnt,false ; xon sent? je chkxof1 ; all done mov ah,flowon ; xon chkxof2:call outch2 ; send it chkxof1:ret ; and return chkxof endp ; Read the serial port for the S-100 modem and put input in buffer. ; Call with delay loop count in cx, c = 1 means no delay. ; Input stream is monitored for xon/xoff. ; Called by outchr, prtchr and outtty. ; Destroys ax, bx, cx, dx, es SPRTCH PROC NEAR mov bx,ds ; Point to data segment mov es,bx mov dx,mdstat0 ; Check in al,dx ; status and al,modrcvb ; Character at port? jnz sprtch2 ; Yes, go get it call chkxof loop sprtch0 ; Keep checking port if cx not=1 ret ; No data sprtch0:push cx xor cx,cx ; This is a delay loop to expand the delay for mov cl,trans.rtime ; screen escape sequencies and capture. or cx,cx ; avoid 0, it will loop for ever jnz sprtch1 inc cx sprtch1:loop sprtch1 ; The delay time is controlled through the pop cx ; receive timeout setting. jmp sprtch sprtch2:mov dx,mddat0 ; Get in al,dx ; character mov ah,al ; Make working copy and ah,parmsk ; Strip parity mov bx,portval cmp [bx].floflg,0 ; Are we doing flow control. jz sprtch4 ; No, skip mov dx,[bx].flowc cmp ah,dh ; xon? jne sprtch3 ; No, check xoff mov xofrcv,off ; Set flag to indicate xoff not received (xon) jmp short sprtch6 ; Get the next char sprtch3:cmp ah,dl ; xoff? jne sprtch4 ; No, go do normal buffer handling mov xofrcv,true ; Set flag to indicatae xoff received jmp short sprtch6 ; Get the next char sprtch4:push di mov di,savedi ; Point to last received char cld stosb ; Save the next one cmp di,offset source + bufsiz ; Bigger than buffer? jb sprtch5 ; No, keep going mov di,offset source ; Yes, wrap around sprtch5:inc count mov savedi,di pop di sprtch6:call chkxof loop sprtch0 ; Keep checking port if cx not=0 ret SPRTCH ENDP ; IHOSTS - Initialize the host by sending XOFF, or equivalent. ; Requires that the port be initialized before hand. ; Do not send flow control if doing half duplex. IHOSTS PROC NEAR push ax ; save the registers push cx push dx mov xofrcv,off ; clear old xoff received flag mov xofsnt,off ; and old xoff sent flag mov ah,flowoff ; put wait flow control char in ah or ah,ah ; check for null char jz ihosts1 ; z = null, don't send it cmp dupflg,0 ; full duplex? jne ihosts1 ; ne = no, half call outchr ; send it ihosts1:call clrbuf ; clear out interrupt buffer pop dx ; empty buffer. we are done here pop cx 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 NEAR 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 or ah,ah ; check for null char jz ihostr1 ; z = null, don't send it call outchr ; send it (release Host's output queue) ihostr1:pop cx pop bx pop ax ret IHOSTR ENDP ; Global proc to Hangup the Phone or Network by making DTR and ; RTS low (phone). DTRLOW PROC NEAR mov ah,cmline ; allow text, to be able to display help mov bx,offset rdbuf ; dummy buffer mov dx,offset hnghlp ; help message call comnd ; get a confirm jc dtrlow3 ; c = failure cmp flags.comflg,'0' ; Bios? jb dtrlow1 ; b = no, UART cmp flags.comflg,'4' ; Bios? jbe dtrlow2 ; be = yes, can't access modem lines dtrlow1:call serhng ; drop DTR and RTS cmp taklev,0 ; in a Take file or macro? jne dtrlow2 ; ne = yes, no message mov ah,prstr ; give a nice message mov dx,offset hngmsg int dos dtrlow2:clc ; success dtrlow3:ret DTRLOW ENDP ; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low ; to terminate the connection. (com1 and com2) ; The USR S-100 modem will not respond to dropping of DTR. Instead the +++ ; sequence must be sent. ; Calling this twice without intervening calls to serini should be harmless. SERHNG PROC NEAR cmp flags.comflg,2 ; Which port? jg serhng1 cli call porton ; Insure that DTR and RTS are high sti mov dx,portadr add dx,PCOMM in al,dx xor al,DTR ; Drop DTR xor al,RTS ; Drop RTS out dx,al mov ax,500 ; 500 millisec, for pcwait call pcwait ; keep lines low for at least 500 millisec clc ret serhng1:mov dx,mdstat0 ; Port address. [19b] in al,dx ; Get status and al,moddcdb ; Carrier? jz serhng4 ; No, tell user mov ah,prstr ; Yes, tell user to wait mov dx,offset wmsg int dos mov ax,1100 ; 1100 milliseconds call pcwait ; Wait before sending '+++' push si mov si,offset hngstr ; Point to '+++' cld lodsb ; Get the first byte of string serhng2:push ax ; We need the loaded byte later mov dx,mdstat0 ; The status port serhng3:in al,dx ; Get status and al,modsndb ; Mask for ready jz serhng3 ; No, go on pop ax ; Get byte back mov dx,mddat0 ; The data port out dx,al ; Send it out lodsb ; Load next byte cmp al,'$' ; Finished? jnz serhng2 ; No, process next pop si mov ax,1100 ; 1100 milliseconds call pcwait ; Wait after sending '+++' mov dx,mdstat0 ; Port address. [19b] in al,dx ; Get status and al,moddcdb ; Carrier? serhng4:mov ah,prstr mov dx,offset dscmsg ; Point to message clc jz serhng5 ; Yes, no carrier, go tell user inc cl ; No, carrier detected cmp cl,3 ; Try three times jnz serhng1 ; No, go try again mov dx,offset ndscmsg ; Warn user serhng5:int dos ; all done ret SERHNG ENDP ; Send a break out the current serial port. SENDBR PROC NEAR mov brkdur,28 ; Normal break 280ms jmp sendbr1 sendbl: mov brkdur,180 ; Long break 1800ms jmp sendbr1 sendbr1:push cx push dx push ax mov dx,mdstat0 ; Port address cmp flags.comflg,2 ; Which port? jg sendbr3 in al,dx ; Get current setting or al,brkval ; Set send-break bit(s) out dx,al ; Start the break mov bx,brkdur ; wait this long call wait01 ; hold break for desired interval xor al,brkval ; Clear send-break bit(s) out dx,al ; Stop the break sendbr2:pop ax pop dx pop cx ret sendbr3:call pickspd ; Point to speed mov al,[bx+1] ; Command byte sub al,8h ; Break byte 8h lower (1fh and 3fh) cmp al,1fh je sendbr4 mov al,3fh sendbr4:out dx,al mov bx,brkdur ; wait this long call wait01 call initmod jmp sendbr2 SENDBR ENDP ; Position the cursor according to contents of DX: ; DH contains row, DL contains column. POSCUR PROC NEAR push ax push dx cmp flags.comflg,2 ; Ports 1/2 jna poscur1 ; Yes, skip this push bx ; No, check input port push cx push es mov cx,1 ; No delay call sprtch ; Get char from port if any pop es pop cx pop bx poscur1:mov ah,conout mov dl,ESCAPE int dos mov dl,'Y' int dos pop dx push dx mov dl,dh add dl,' ' int dos pop dx add dl,' ' int dos pop ax ret POSCUR ENDP ; Delete a character from the terminal. This works by printing ; backspaces and spaces. DODEL PROC NEAR mov ah,prstr mov dx,offset delstr ; Erase weird character. int dos ret DODEL ENDP ; select port to be current. Returns with carry clear if success. COMS PROC NEAR ; mov kstatus,0 ; global status, success mov dx,offset comptab ; table of legal comms ports mov bx,offset comsmsg ; point to comsmsg mov ah,cmkey ; parse key word call comnd jnc coms0 ; nc = success ret ; failure coms0: call serrst ; uninstall interrupt call comstrt jnc coms1 mov ah,prstr mov dx,offset coms0msg ; Point to no S-100 modem msg int dos coms1: clc ret comstrt:mov al,flags.comflg mov tmp,al ; Save the old one in case mov flags.comflg,bl ; Set the comm port flag. cmp bl,1 ; COM1 (port B)? je coms2 ; Yes cmp bl,2 ; COM2 (port A)? je coms3 ; Yes cmp bl,3 ; COM3 (S-100 modem port 1) je coms4 ; Yes in al,mdmcom4 ; Check this port and al,modperb ; Is it there? jnz coms6 ; No, skip mov portval,offset port4 ; Must be COM4 mov mddat0,mdmdat4 mov mdstat0,mdmcom4 jmp coms5 coms4: in al,mdmcom3 ; Check this port and al,modperb ; Is it there? jnz coms6 ; No, skip mov portval,offset port3 mov mddat0,mdmdat3 mov mdstat0,mdmcom3 jmp coms5 coms2: mov mdstat0,mdmcom1 ; Set break address for B mov portadr,mdmdat1 ; Set address for B mov portval,offset port1 ; Point to portinfo for B jmp coms5 coms3: mov mdstat0,mdmcom2 ; Set break address for A mov portadr,mdmdat2 ; Set address for A mov portval,offset port2 ; Point to portinfo for A coms5: call baudref ; Set up bdtab and bddat call getbaud ; See what is in the port now set clc ; Success ret coms6: mov al,tmp mov flags.comflg,al ; Get the old one back stc ; Failure ret COMS ENDP ; Set heath emulation on/off. ; SET Term parameters, especially for use with VT100 emulator. [jrd] ; Taken from work done originally by James Harvey IUPUI. ; VTS is called only by mssset to set terminal type and characteristics. ; Enter via direct jmp. Exit ret with carry set for failure, else carry ; cleared. VTS proc near ; SET TERM whatever mov dx,offset termtb ; terminal table, ascii xor bx,bx ; help is the table itself mov ah,cmkey ; get keyword call comnd jnc vset1 ; nc = success ret ; failure vset1: mov flags.vtflg,bx ; Set the Heath emulation flag and bx,bx ; emulating? mov dosflg,0ffh ; set the flag, disable scan codes mov flags.xltkbd,0 ; key translation disabled jz vset2 ; nz=yes mov dosflg,0 ; clear the flag, enable scan codes mov flags.xltkbd,1 ; key translation enabled vset2: mov dx,offset vtsmsg mov ah,prstr int dos clc ; success ret VTS ENDP VTSTAT PROC NEAR ; For Status display [jrd] ret ; no emulator status to display VTSTAT ENDP ; simple routine to insure that the port has RXON and DTR high ; assumes int are off porton proc near push dx push ax mov dx,portadr add dx,PCOMM in al,dx or al,RXON or al,DTR or al,RTS out dx,al pop ax pop dx ret porton endp ; routine to retrieve current int vector ; inputs: al = int number ; outputs: cx = seg for current isr ; dx = offset for current isr getivec proc near push es ; save registers push bx mov ah,35H ; Int 21H, function 35H = Get Vector. int dos ; get vector in es:bx mov cx,es ; addr of org vector (seg) mov dx,bx ; and offset pop bx pop es ret getivec endp ; routine to set int vector ; inputs: al = int number ; cx = seg for isr ; dx = offset for isr setivec proc near push ds ; save ds around next DOS call. mov ds,cx mov ah,25H ; set interrupt address from ds:dx int dos pop ds ret setivec endp ; initialization for using serial port. This routine performs ; any initialization necessary for using the serial port, including ; setting up interrupt routines, setting buffer pointers, etc. ; Doing this twice in a row should be harmless (this version checks ; a flag and returns if initialization has already been done). ; SERRST below should restore any interrupt vectors that this changes. SERINI PROC NEAR cmp portin,0 ; did we initialize port already? je serin1 ; e = yes jl serin0 ; l = no, not yet jmp serin2 serin0: mov bl,flags.comflg ; pass current port ident call comstrt ; do SET PORT now jnc serin1 ; nc = success ret ; failed, exit now serin1: cmp flags.comflg,2 ; COM1 or COM2? jle serini1 ; Go do COM1/COM2 stuff serin2: cmp flags.comflg,2 ; COM1 or COM2? jg serini2 ; Go do COM3/COM4 stuff jmp serini3 ; Update flow and leave initmod: ; The S-100 modem set up routine serini2:call pickspd ; Select baud and speed info xor al,al ; Use this to reset modem mov dx,mdstat0 ; Status port out dx,al ; Send to port jmp $+2 ; Wait a little out dx,al jmp $+2 ; Wait a little out dx,al jmp $+2 ; Wait a little mov al,40h out dx,al jmp $+2 ; Wait a little mov al,[bx] out dx,al jmp $+2 ; Wait a little mov al,[bx+1] out dx,al jmp $+2 in al,dx ; Check port and al,moddcdb ; for carrier jnz serini0 ; Yes, don't do AT stuff mov bx,10 ; Wait 10/100 seconds call wait01 ; Call wait routine push si mov si,offset set_str;ATE1X1S0=0 sets up modem: echo commands, use cld ; extended response codes, don't answer lodsb ; Get the first byte of string serini5:push ax ; We need the loaded byte later serini6:xor cx,cx ; Reset loop counter. Loop to avoid hanging mov dx,mdstat0 ; The status port serini7:in al,dx ; Get status and al,modsndb ; Mask for ready jnz serini8 ; Yes, go on inc cx ; No or cx,cx ; Run out? jnz serini7 ; No, try again mov ah,prstr ; Yes, tell user failure in initialization mov dx,offset infmsg; Tell user init failed int dos pop ax ; Restore stack pop si stc ; Failure ret serini8:pop ax ; Get byte back mov dx,mddat0 ; The data port out dx,al ; Send it out lodsb ; Load next byte cmp al,'$' ; Finished? jnz serini5 ; No, process next pop si ; Left in good order mov bx,25 ; Wait 25/100 seconds call wait01 ; Call wait routine call prtchr ; Purge modem jmp serini3 ; Success serini1:mov ax,portval cmp ax,offset port2 je seri2 ; setup for J1 cmp intin,2 jne seri0 serini0:clc ; Success ret ; J2 (com3, com4) already set up seri0: cmp intin,1 jne seri1 ; J1 currently installed call serrst ; de-install current int seri1: mov al,J2INT call getivec mov oldseg,cx mov oldoff,dx mov cx,cs mov dx,offset serisr mov al,J2INT call setivec mov portadr,J2_ADDR call clrbuf call porton mov intin,2 ; show J2 installed jmp serini3 ; Success seri2: cmp intin,1 jne seri3 clc ; Success ret ; J1 already set up seri3: cmp intin,2 jne seri4 ; J2 currently installed call serrst ; de-install current int seri4: mov al,J1INT call getivec mov oldseg,cx mov oldoff,dx mov cx,cs mov dx,offset serisr mov al,J1INT call setivec mov portadr,J1_ADDR call clrbuf call porton mov intin,1 ; show J1 installed serini3:push bx mov bx,portval ; get port data structure mov [bx].portrdy,1 ; say the comms port is ready mov parmsk,0ffh ; parity mask, assume parity is None cmp [bx].parflg,parnon ; is it None? je serini3a ; e = yes mov parmsk,07fh ; no, pass lower 7 bits as data serini3a:xor ax,ax cmp [bx].floflg,0 ; flow control is off? je serini3b ; e = yes mov ax,[bx].flowc ; get flow control chars serini3b:mov flowoff,al ; xoff or null mov flowon,ah ; xon or null mov xofrcv,off ; clear xoff received flag pop bx mov portin,1 ; say initialized clc ; carry clear for success ret ; We're done pickspd:mov bp,portval ; Get speed for S-100 modem 'from' portval cmp ds:[bp].baud,0 ; 150 baud? mov bx,offset bd150 jz serini4 cmp ds:[bp].baud,1 ; 300 baud? mov bx,offset bd300 jz serini4 cmp ds:[bp].baud,2 ; 600 baud? mov bx,offset bd600 jz serini4 mov bx,offset bd1200; Default to 1200 baud serini4:ret SERINI ENDP ; Reset the serial port. This is the opposite of serini. Calling ; this twice without intervening calls to serini should be harmless. SERRST PROC NEAR cmp portin,0 ; Reset already? jg serr0 ; g = no clc ret ; e = yes, l=not used yet, just leave serr0: push dx cmp intin,0 ; is any isr installed je serr2 ; no, all done push cx push ax mov ax,J2INT ; guess it's J2 cmp intin,2 ; yes, je serr1 ; reset it mov ax,J1INT ; no, must be J1 serr1: mov cx,oldseg ; original isr mov dx,oldoff ; address call setivec ; do it mov intin,0 ; show nothing installed call porton ; Insure that DTR and RTS are high pop ax pop cx serr2: pop dx mov portin,0 ; reset flag push bx mov bx,portval ; port data structure mov [bx].portrdy,0 ; say port is not ready pop bx clc ret SERRST ENDP ; the serial port interrupt service routine ; this routine does int driven input and output ; once installed, it displaces the Z-100 serial isr serisr: push ax ; Save regs push bx push cx push dx push ds ; Save data seg mov ax,seg data ; Set our mov ds,ax ; data seg ; mov dx,portadr ; Get the port address mov cx,dx ; and save a copy add dx,PSTATUS in al,dx ; Get port status mov ah,al ; Save it test ah,RDA ; Check for data available jz isr5 ; No, nothing to receive, go send ; mov dx,cx ; Port address in al,dx ; Get the data cmp flowoff,0 ; Are wo doing flow control? jz isr2 ; No, skip ; mov ch,al ; Make working copy of data and ch,parmsk ; Strip parity, if any cmp ch,flowon ; xon? jne isr1 ; No, check xoff mov xofrcv,false ; Indicate xoff not received (xon) ; Done with receiver jmp short isr5 ; there should be time for send isr1: cmp ch,flowoff ; xoff? mov ch,0 ; We need this later in cx jnz isr2 ; No, put regular char in buffer cmp xofsnt,true ; Did we send an outstanding xoff? jz isr5 ; Yes, ignore (possible echo), go send mov xofrcv,true ; Set flag to indicatae xoff received ; Done with receiver jmp short isr5 ; there should still be time for send isr2: mov bx,bufiend ; Get where to put it cmp count,BUFILEN ; Buffer full? jne isr3 ; No, jump dec bx ; Don't overwrite que mov byte ptr buffin[bx],bell; Put Ctrl-G in the que as marker jmp short isr5 ; We missed it anyway isr3: mov byte ptr buffin[bx],al ; Stick it in the que inc bx ; Bump que pointer inc count ; One more in que cmp bx,BUFILEN ; Pointing to end of que? jne isr4 ; No, go on xor bx,bx ; Reset pointer isr4: mov bufiend,bx ; Store new pointer ; jmp short isr12 ; Pick ; We won't take time to send now jmp short isr5 ; one ; There should still be time for send ; isr5: test ah,TSRE+THBE ; Ready to send? jz isr12 ; No, almost done mov bx,bufobeg ; Pointer to beginning of output buffer cmp count,mntrgh ; Past the high trigger point? jnae isr6 ; no, make it simple cmp flowoff,0 ; Are we doing flow control? jz isr6 ; no, make it simple cmp xofsnt,true ; Did we send an xoff already? jz isr6 ; yes, make it simple mov al,flowoff ; xoff or al,al ; Null? jz isr6 ; Don't send null call dopar mov dx,cx ; Port address out dx,al ; Send the xoff out mov xofsnt,true ; Remember cmp bx,bufoend ; Buffer empty? jz isr11 ; Yes, turn transmitter off jmp short isr12 ; We have used transmitter already, ; so we need to go isr6: cmp bx,bufoend ; Buffer empty? jz isr11 ; Yes, turn transmitter off mov al,byte ptr buffout[bx] ; Get char to send cmp flowoff,0 ; Are we doing flow control? jz isr7 ; No, just go on mov ah,al ; Working copy and ah,parmsk ; Strip parity cmp ah,flowoff ; xoff? jz isr7 ; Just send it cmp ah,flowon ; xon? jz isr7 ; Just send it cmp xofrcv,true ; Being held? jz isr12 ; Yes, don't send isr7: mov dx,cx ; Port address out dx,al ; Send it inc bx ; Point to next char to send cmp bx,BUFOLEN ; Pointing to end of que? jne isr10 xor bx,bx ; Reset pointer isr10: mov bufobeg,bx ; Save it jmp short isr12 ; Almost done ; isr11: mov dx,cx ; Port address add dx,PCOMM in al,dx ; Get current mode and al,TXOFF ; Turn xmitter off out dx,al ; Do it. ; isr12: mov al,EOI ; Tell interrupt controller out Z8259,al ; that interrupt serviced ; pop ds ; Restore regs pop dx pop cx pop bx pop ax iret ;; Wait for the # of milliseconds in ax, for non-IBM compatibles. pcwait proc near cmp ax,0 jz pcwait2 ; no wait push bx push cx push dx xor dx,dx mov cx,10 ; we can not make it finer than 10ms div cx cmp ax,0 jnz pcwait1 inc ax ; make it 10ms for 1 to 9 pcwait1:mov bx,ax ; and 10ms for 10 to 19, 20ms for 20 to 29 call wait01 ; 10ms => 10 to 20ms by wait01 pop dx ; 20ms => 20 to 30ms by wait01 pop cx pop bx pcwait2:ret pcwait endp ; Wait for the # of hundredths seconds in bx. Range 1 to 0ffffh. ; Accuracy within 10ms due to use of system clock. ; This uses dos calls and is compatible with all msdos systems. ; Preserves all registers. wait01 proc near push ax push cx push dx push di mov ah,gettim ; Get time function int dos wait011:mov di,dx ; Preset/reset di wait012:int dos cmp dx,di ; Changed? je wait012 ; Yes, continue dec bx ; 1/100 second passed jnz wait011 ; Did not time out, keep waiting pop di ; Timed out pop dx pop cx pop ax ret wait01 endp ; Service SET NETBIOS-NAME name command at Kermit prompt level setnbios proc near ret setnbios endp sesdisp proc near ret sesdisp endp code ends end