NAME msxsee ; File MSXSEE.ASM ; ; This module is derived from MSXCLO.ASM, which was in turn derived from ; MSXIBM.ASM and is intended for the Seequa Chameleon, which differs from the ; IBM in its serial I/O, and uses the 8274 sio chip at 30. The idea is to use ; the VT100 emulation (which will work) but use special code for the Seequa's ; serial I/O. This module differs from MSXCLO.ASM in that it uses direct, ; interrupt-driven I/O to the Seequa's port (fast), rather than only BIOS ; calls (slow). ; ; Glenn Everhart ; ; Based on MS Kermit 2.29, June 1986 ; ; Kermit system dependent module for IBM-PC ; Edit History ; [2.29] code frozen on 6 May 1986 [jrd] ; Remove module VTS since mssset now selects terminal emulation type. ; Add Topview support for some screen handling functions and call smarter ; screen routines in module msyibm. ; Revise Putmod to not advance cursor to last column to avoid unwanted ; cursor wraparound on some machines (Compaq). ; Add DOS keyboard reading if running under IBM PC Netbios (pcnet != 0). ; Move all terminal Set and Status routines to this system dependent file. ; Add Global entry point vtstat to invoke local Status display. ; Remove Autowrap (H-19) as a separate item; a terminals now use Wrap. ; Add Set Term Color for terminal emulation; as a default the system uses ; colors in existence when Kermit is started. [jrd] ; Add extra code to SERINI & SERRST to assert 8250 Uart signals OUT1 and OUT2. ; Normally OUT2 is used to enable recoginition of IRQ3/4 and OUT1 is unused. ; Add code at end of SERRST to clear modem's delta line status bits and ; to reassert DTR, RTS, and OUT1/2. ; Add control of screen refresh as Set Term Color 0 for regular IBM CGA, ; waits for retrace before updating screen, and Set Color 10 for other systems ; not needing to wait. Default is to wait (no snow). ; Add global procedures IHOSTS and IHOSTR to handle host initialization ; when packets are to be sent or received by us,resp. 24 March 1986 ; Add global procedure DTRLOW (and worker serhng) to drop DTR and RTS and ; thus hangup the phone. 29 March 1986 [jrd] ; Revise Set Term Tab ... to use codes of set/clear/not-modified in tmptab ; buffer and hence set/clear individual tabs cleanly. 1 April 1986 ; In proc Outchr add override of xon from chkxon sending routine. ; This makes a hand typed Xoff supress the xon flow control character sent ; automatically as the receiver buffer empties. 20 April 1986 [jrd] ; Add save reg si in proc puthlp to help avoid lost cursor. ; Add test for IBM PC jr and if machine is a PC jr then set port 2 as the ; default. 23 April 1986 [jrd] ; Revise Puthlp procedure to use manual cursor movement while writing help ; text. Hope is to avoid screen problems on Compaq's. 1 May 1986 [jrd] ; Revise Poscur to not do Topview notification. Should cure video controller ; problems on early IBM/Compaq PC's. 5 May 1986 [jrd] ; ; [2.28 jrd/2] ; Modified procedure serini to flush input char before allowing interrupts, ; to stop interrupts from occurring during the procedure body, to stop ; interrupts from occurring due to TX holding buffer becoming empty, and to ; speed our exit from the procedure before an interrupt can occur. ; Modified procedure serrst to do quicker exit before interrupts occur. ; Modified procedure serint to remove unnecessary start-interrupts in proc ; body (it's an interrupt routine folks) and send 8259 end-of-interrupt ; code just before exiting procedure (less exposure time). [jrd] ; Joe R. Doupnik 22 Dec 1985. ; Make keywords mixed case for reading ease. 26 Dec 85 [jrd] ; ; Make break be 275 ms, DT 5:51pm Thursday, 6 December 1984 public serini, serrst, clrbuf, outchr, coms, vts, vtstat public dodel, ctlu, cmblnk, locate, prtchr, dobaud, clearl public dodisk, getbaud, beep public count, xofsnt, puthlp, putmod, clrmod, poscur public sendbr, machnam, setktab, setkhlp, lclini, showkey public ihosts, ihostr, dtrlow ; [jrd] PUBLIC SERIALIO include mssdef.h false equ 0 true equ 1 mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full. ; constants used by serial port handler ASYIO EQU 14H ; Interrupt for com1: device via bios. BRKBIT EQU 040H ; Send-break bit. TIMER EQU 40H ; Use to issue short beep. PORT_B EQU 61H ; Port B address. MCONF EQU 11H ; Machine configuration. KEYB EQU 16H BIOS EQU 10H MDMDAT1 EQU 03F8H ; Address of modem port (data). [19b] MDMSTS1 EQU 03FDH ; Address of modem port status. [19b] MDMCOM1 EQU 03FBH ; Address of modem port command. [19b] MDMDAT2 EQU 02F8H ; Port 2 address. [19b] MDMSTS2 EQU 02FDH ; Port 2 status. [19b] MDMCOM2 EQU 02FBH ; Port 2 command. [19b] MDMINP EQU 1 ; Input ready bit. MDMINTV EQU 0030H ; Address of modem port interrupt vector. MDINTV2 EQU 002CH ; Address for port 2. [19b] MDMINTO EQU 0EFH ; Mask to enable interrupt for modem port. MDINTO2 EQU 0F7H ; Enable interrupt level 3. [19b] MDMINTC EQU 010H ; Bit to set to disable interrupts for modem. MDINTC2 EQU 008H ; Disable IRQ3. [19b] INTCONT EQU 0021H ; Address of 8259 interrupt controller ICW2-3. INTCON1 EQU 0020H ; Address of 8259 ICW1. EOICOM EQU 0064H ; End of interrupt. EOICOM2 EQU 0063H ; End of interrupt for COM2. [19b] ; ; Serial I/O equates: EOI EQU 20H ; End of interrupt command FALSE EQU 0 ; Flag value LF EQU 0AH ; Line feed RX_AVIL EQU 100H SERIAL EQU 30H ; Asynchronous Communications $8274 TRUE EQU NOT FALSE;Flag value TX_EMTY EQU 2000H TIMEOUT EQU 8000H TIMER EQU 40H ; Timer addr WR0 EQU 3 NUL EQU 0 RESET_TX_ERR EQU 0C0H WR1 EQU 1 WR2 EQU 2 WR3 EQU 3 RX_ENAB EQU 1 RX_7_BIT EQU 40H AUTO_ENAB EQU 20H WR4 EQU 4 CLK_X_16 EQU 40H WR5 EQU 5 DTR EQU 80H TX_ENAB EQU 8 RTS EQU 2 ; ; 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 (currently either port1 ; or port2) ; port1, port2 - portinfo structures for the corresponding ports ; global variables defined in this module: ; xofsnt, xofrcv - tell whether we saw or sent an xoff. ; setktab - keyword table for redefining keys (should contain a 0 if ; not implemented) ; setkhlp - help for setktab. ; SEGMENT FOR SERIAL BUFFERS DABUF SEGMENT PUBLIC 'DABUF' BUFFERS DB 4096 DUP (?) ; SERIAL BUFFERS, PAGE ALIGNED DB 4 DUP (?) ; SAFETY DABUF ENDS datas segment public 'datas' extrn drives:byte,flags:byte, trans:byte extrn portval:word, port1:byte, port2:byte extrn pcnet:byte, refresh:byte extrn vtemu:byte ; [jrd] ; 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 setktab db 12 mkeyw 'BackSpace',0eh mkeyw 'F1',3bh mkeyw 'F2',3ch mkeyw 'F3',3dh mkeyw 'F4',3eh mkeyw 'F5',3fh mkeyw 'F6',40h mkeyw 'F7',41h mkeyw 'F8',42h mkeyw 'F9',43h mkeyw 'F10',44h mkeyw 'scan',-1 setkhlp db cr,lf,'Keyname: "BackSpace", F1, ... F10, or "scan" follwed by ' db 'decimal scan code$' brkval db 0 ; What to send for a break. brkadr dw 0 ; Where to send it. modem mdminfo 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,'$' ; [jrd] erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a] erms40 db cr,lf,'?Warning: Unrecognized baud rate$' badbd db cr,lf,'Unimplemented baud rate$' prterr db '?Unrecognized value$' ; [jrd] machnam db 'Seequa Chameleon$' crlf db cr,lf,'$' delstr db BS,BS,' ',BS,BS,'$' ; Delete string. [21d] clrlin db cr,'$' ; Clear line (just the cr part). onmsg db 'on$' ; [jrd] offmsg db 'off$' savsci dw ? ; Save for serial port interrupt vector. [14] savscs dw ? ; Ditto. [14] savbr1 dw ? ; "Break" interrupt vector. [25] savbr2 dw ? ; Ditto. [25] portin db 0 ; Has comm port been initialized. [21c] xofsnt db 0 ; Say if we sent an XOFF. xofrcv db 0 ; Say if we received an XOFF. tmp db ?,'$' temp dw 0 temp1 dw ? ; Temporary storage. temp2 dw ? ; Temporary storage. rdbuf db 80 dup (?) ; temporary storage. [jrd] ASYMD DW 0 ; STORE BAUD RATE SETTING ASYPR DB 0 ; ASYNCH PORT 0 OR 1 ; begin Terminal emulator data set termtb db tttypes ; entries for Status, not Set mkeyw 'Heath-19',ttheath mkeyw 'none',ttgenrc mkeyw 'VT102',ttvt100 mkeyw 'VT52',ttvt52 ; [jrd] vttbl db 13 ; fourteen entries. mkeyw 'Character-set',chaval mkeyw 'Color',200H ; screen fore/back colors; 200H=marker mkeyw 'Cursor-style',curval mkeyw 'Heath-19',ttheath+100H ; note 100H flag for decoding here mkeyw 'Keyclick',keyval mkeyw 'Margin-bell',marval mkeyw 'None',ttgenrc+100H mkeyw 'Newline',newval mkeyw 'Screen-background',scrval mkeyw 'Tabstops',tabval mkeyw 'VT102',ttvt100+100H mkeyw 'VT52',ttvt52+100H ; [jrd] mkeyw 'Wrap',wraval scrtab db 02H ; screen attributes mkeyw 'normal',00H mkeyw 'reverse',01H curtab db 02H ; cursor attributes mkeyw 'block',00H mkeyw 'underline',01H chatab db 02H ; character set (pound sign choice) mkeyw 'UK-ascii',01H mkeyw 'US-ascii',00H ; US ASCII is default (0). tabtab db 02H ; label says it all! mkeyw 'at',0FFH ; For setting tab stops. mkeyw 'Clear',00H ; For clearing tab stops. alltab db 02H ; more tab command decoding mkeyw 'all',00H mkeyw 'at',01H vtable dw ontab, curtab, chatab, ontab, ontab, ontab, scrtab, 0 vtsflg equ this byte ; define small digits xxxval newval equ $-vtsflg ; and mask for bit in byte db vsnewline curval equ $-vtsflg db vscursor chaval equ $-vtsflg db vsshift3 keyval equ $-vtsflg db vskeyclick wraval equ $-vtsflg db vswrap marval equ $-vtsflg db vsmarginbell scrval equ $-vtsflg db vsscreen numflgs equ $-vtsflg tabval equ $-vtsflg db 0 vtrtns dw numflgs dup (flgset), tabset ; dispatch table for vtsflg clrset db ? ; Temp for SET Term Tabstops xxx tmptabs db 80D dup (?) ; Temporary for unconfirmed tabs. vthlp db ' one of the following:',cr,lf db ' terminal types of: None, Heath-19, VT52, or VT102',cr,lf db ' Newline-mode Cursor-style Character-set (US UK)',cr,lf db ' Keyclick Margin-bell Screen-background',cr,lf db ' Tabstops Wrap (long lines) Color (fore & background)' db '$' wrpst db 'Autowrap (Heath-19): $' clrhlp db ' one of the following:' db cr,lf,' AT #s (to set tabs at column #s)' db cr,lf,' Clear AT #s or Clear ALL (to clear tabstops)' db cr,lf,' Ex: Set Term Tab at 10, 20, 34 sets tabs' db cr,lf,' Ex: Set Term Tab Clear at 9, 17, 65 clears tabs$' allhlp db ' one of the following:' db cr,lf,' AT #s (to clear at specific columns)' db cr,lf,' ALL (to clear all tabstops)$' tbshlp db ' column number of tab stop to set, 1-79$' tbchlp db ' column number of tab stop to clear, 1-79$' tbserr db cr,lf,'?Column number is not in range 1-79$' colhlp db cr,lf,' Set Term Color value, value, value, ...' db ' commas are optional.' db cr,lf,' 0 selects normal white on black and' db ' no-snow mode on an IBM CGA (default).' db cr,lf,' 1 for high intensity foreground.' db cr,lf,' 10 for fast screen updating.' db cr,lf,' Foreground color (30-37) = 30 + colors' db cr,lf,' Background color (40-47) = 40 + colors' db cr,lf,' where colors are 1 = red, 2 = green, 4 = blue.' db cr,lf,' Ex: 0, 1, 34, 47 IBM CGA(0), bright(1) blue(34)' db ' chars on a white(47) 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: $' ; 1st item has two spaces from STAT0 vtbell db 'Term margin-bell: $' ; this is also on same line as wrap. 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 foreground:3$' colst2 db ' background:4$' ; terminal emulator vtstbl stent ; VT100 line wrap stent ; VT100 margin bell stent ; VT100 cursor type stent ; VT100 newline stent ; VT100 screen stent ; VT100 character set stent ; VT100 keyclick stent ; VT100 colors stent ; VT100 tab status - needs one whole line dw 0 ; end of table ; end of Terminal data set ontab db 02H ; Two entries. db 03H,'off$' ; Should be alphabetized. [19a] dw 00H db 02H,'on$' dw 01H comptab db 04H db 01H,'1$' dw 01H db 01H,'2$' dw 00H db 04H,'COM1$' dw 01H db 04H,'COM2$' dw 00H ; this table is indexed by the baud rate definitions given in ; pcdefs. Unsupported baud rates should contain FF. bddat label word dw 0FFH ; 45.5 baud -- Not supported. dw 0FFH ; 50 baud dw 0FFH ; 75 baud dw 000H ; 110 baud dw 0FFH ; 134.5 baud dw 0FFH ; 150 baud dw 002H ; 300 baud dw 0FFH ; 600 baud dw 004H ; 1200 baud dw 0FFH ; 1800 baud dw 0FFH ; 2000 baud dw 005H ; 2400 baud dw 006H ; 4800 baud dw 007H ; 9600 baud dw 001H ; 19200 baud dw 003H ; 38400 baud ; NOTE THESE ARE JIGGERED FOR USE BY SET BAUD - NOT AS IN REAL IBM PC VERSION ASYBD DW 003H ; 110 BAUD REPORT DW 00EH ; 19200 DW 006H ; 300 DW 00FH ; 38400 DW 008H ; 1200 DW 00BH ; 2400 DW 00CH ; 4800 DW 00DH ; 9600 BAUD REPORT VALUE ; variables for serial interrupt handler source db bufsiz DUP(?) ; Buffer for data from port. srcpnt dw 0 ; Pointer in buffer (DI). count dw 0 ; Number of chars in int buffer. savesi dw 0 ; Save SI register here. telflg db 0 ; Are we acting as a terminal. mst dw 0 ; Modem status address. mdat dw 0 ; Modem data address. mdeoi db 0 ; End-of-Interrupt value. rbtrn db 7fH ; rubout shkbuf db 300 dup (?) ; room for definition shkmsg db ' Scan code: ' shkmln equ $-shkmsg shkms1 db cr,lf,' Definition: ' shkm1ln equ $-shkms1 ; ; Data declarations for serial I/O pieces PUBLIC TXBUFFSTRT,TXBUFFEND,RXBUFFSTRT,RXBUFFEND PUBLIC TXBUFFSEG,RXBUFFSEG,TXLENGTH,RXLENGTH PUBLIC SERSTAT,SERMASK,SRINIT TXBUFFSTRT DW ? ; Start of tx buff TXBUFFEND DW ? ; End of tx buff RXBUFFSTRT DW ? ; Start of RX buff RXBUFFEND DW ? ; End if RX buff RXBUFFSEG DW ? ; Segment of RX buff TXBUFFSEG DW ? ; Segment of TX buff TXLENGTH DW ? ; TX buffer length RXLENGTH DW ? ; RX buffer length SERSTAT DW ? ; Serial port status SRINIT DW ? ; serial port initialization word PORT DW ? ; port B (asynchronous) or port A (synchronous) SERMASK DB ? ; Mask char for serial port ; ------- Baud rate look up table SBAUD DW 710 ; 110 baud DW 4 ; 19200 (was 150 baud entry...) DW 260 ; 300 DW 2 ; 38400 (NOT 600) DW 65 ; 1200 DW 32 ; 2400 DW 16 ; 4800 DW 8 ; 9600 DW 4 ;19200 ; (not really used) DW 2 ;38400 ; (not really used) ; ------- Command dispatch SERJMP DW OFFSET SERINZ ; Serial initialization DW OFFSET SERPUT ; Transmit serially DW OFFSET SERGET ; Receive serially DW OFFSET SERSTS ; Get serial status DW OFFSET SEREND ; Close port communications ; ------- Interupt dispatch INTTBL DW OFFSET XMITT DW OFFSET STATCHG DW OFFSET RECEIVE DW OFFSET STATCHG datas ends code segment public 'code' extrn comnd:near, dopar:near, defkey:near, gss:near, lclyini:near extrn sleep:near, atsclr:near, scrseg:near,scrloc:near, scrsync:near extrn atoi:near, strlen:near, prtscr:near, scroff:near, scron:near assume cs:code,ds:datas ; ;********************************************************************; ;********************************************************************; ;********************************************************************; ; ; Serial port drivers for the 8274 chip at 30 ; Written by : Bob Depelteau ; Edit date : 9/21/83 , 2/21/84 ; ;********************************************************************; ;********************************************************************; ;********************************************************************; ;-----------------------------------------------; ; SERIALIO Asynchronous/Synchronous Communications ; (AH)=0 Initialize a communications port ; (SRINIT)= Parameters for initialization ; ; BITS: ; ; PORT ; 8 ; 0 - port B ; 1 - port A ; ; BAUD RATE PARITY STOPBIT WORDLENGTH ; 765 43 2 01 ; 000 - 110 00 - None 0 - 1 00 = 5 BIT ; 001 - 19.2K 01 - Odd 1 - 2 01 = 7 BIT ; 010 - 300 11 - Even 10 = 6 BIT ; 011 - 38.4K 11 = 8 BIT ; 100 - 1200 ; 101 - 2400 ; 110 - 4800 ; 111 - 9600 ; ; (BX)= Length of transmit buffer ; (CX)= Length of receive buffer ; ( Maxium size of any buffer is 64K or hex 0000 ) ; ( Length assumed to be on 16 byte boundry ) ; ( No check is made for out of memory ) ; (ES)= Starting Segment to use for buffers ; Public variables: ; RXBUFFSEG DW ? ; Segment of reciver buffer ; TXBUFFSEG DW ? ; Segment of transmitter buffer ; ; NOTE: ; Buffer are flushed and all information is lost upon initialization ; ; (AH)=1 Queue up a character in buffer to transmitt ; Updates tramsmitter buffer pointers ; PUBLIC VARIABLES ; TXBUFFSTRT DW ; Offset start of buffer ; TXBUFFEND DW ; Offset end of buffer ; TXLENGTH DW ; Length of buffer ; ; (AH)=2 Get a character from buffer into (AL) ; Updates Reciver buffer pointers ; PUBLIC VARIABLES ; RXBUFFSTRT DW ; Offset start of buffer ; RXBUFFEND DW ; Offset end of buffer ; RXLENGTH DW ; Length of buffer ; ; (AH)=3 Get port status into (AX) ; ; AH = 7 6 5 4 3 2 1 0 ; | | | | | | | | ; | | | | | | | --- RECIVER BUFFER NOT EMPTY ; | | | | | | ----- OVERRUN ERROR ; | | | | | ------- PARITY ERROR ; | | | | --------- FRAMING ERROR ; | | | ----------- BREAK DETECT ; | | ------------- TRANS BUFFER FULL ; | --------------- TRANS BUFFER EMPTY ; ----------------- BUFFER OVERFLOW OR TIMEOUT ; AL = 7 6 5 4 3 2 1 0 ; | | | | | | | | ; | | | | | | | --- ; | | | | | | ----- ; | | | | | ------- ; | | | | --------- DATA CARRIER DETECT ; | | | ----------- CLEAR TO SEND ; | | ------------- DATA SET READY ; | --------------- ; ----------------- ; ; (AH)=4 Close port communication ; (Must be done before exiting program) ; ; USED ON ALL ; ON EXIT ; (AH)= Status of port as returned by function 3 ; No other regs are affected ; ;-----------------------------------------------; SERIALIO PROC FAR STI PUSH BX ; PUSH CX ; PUSH DX ; PUSH DI ; PUSH SI ; PUSH DS ; PUSH ES ; CLD CMP AH,4 ; If illegal function JA SERROR ; then error PUSH AX ; Save MOV AX,SEG DATAS ; Set DS to DATA SEG MOV DS,AX ; ASSUME DS:DATAS POP AX ; PUSH AX ; MOV AL,AH ; Function SHL AL,1 ; Words 2 bytes CBW ; Word MOV SI,AX ; Index POP AX ; Restore CALL DS:WORD PTR SERJMP[SI]; Branch indirectly SERROR: SERETN: POP ES POP DS ; Restore POP SI ; POP DI ; POP DX ; POP CX ; POP BX ; RET SERIALIO ENDP ; local initialization lclini proc near mov ax,0eH ; scan code for arrow key mov si,offset rbtrn ; translate to rubout mov cx,1 ; one char translation call defkey call model ; get model of IBM machine. [jrd] MOV ASYPR,0 ; SET COM1 INITIALLY mov brkval,BRKBIT ; What to send for a break. mov ax,modem.mdcom ; Where to send it. mov brkadr,ax call lclyini ; let other modules initialize too... ret lclini 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 NEAR int mconf ; Get equipment configuration. mov ah,al ; Store AL value for a bit. and al,01H ; First, look at bit 0. jz dodsk0 ; No disk drives -- forget it. mov al,ah ; Get back original value. mov cl,6 ; Shift over bits 6 and 7. shr al,cl ; To positions 0 and 1. inc al ; Want 1 thru 4 (not 0 thru 3). mov drives,al ; Remember how many. ret dodsk0: mov ah,prstr ; Print a warning message. mov dx,offset erms20 ; I'm not sure if things will int dos ; work with only a cassette. mov drives,0 ; Say there aren't any drives. ret DODISK ENDP model proc near ; Get IBM model, set port 2 for PC jr. [jrd] push es push ax ; get IBM model code at F000:FFFE mov ax,0f000h ; address ROM mov es,ax mov al,byte ptr es:[0fffeh] ; get model id byte cmp al,0fdh ; PC jr? jne modelx ; ne = no mov flags.comflg,0 ; say not using port 1. call coms0 ; set port 2 for PC jr, in proc COMS modelx: pop ax pop es ret model endp ; show the definition of a key. The terminal argument block (which contains ; the address and length of the definition tables) is passed in ax. ; Returns a string to print in AX, length of same in CX. ; Revised to also run under IBM PC Netbios (lose some scan codes by doing ; DOS keyboard reads rather than Bios. Non-Network reads use Bios). [jrd] ; Returns normally. showkey proc near push es push ax ; save the ptr mov bx,ds mov es,bx ; address data segment cld showk1: cmp pcnet,0 ; running under Netbios? (0 = no) je showk3 ; e = no. xor bx,bx ; say shift state is none mov dl,0ffh ; Network. keyboard input, via DOS mov ah,conin ; get a char into al int dos xor ah,ah ; assume no scan code cmp al,0 ; special char? jne showk4 ; ne = no mov ah,conin ; get second byte, pseudo-scan-code int dos xor ah,ah ; clear effective shift state jmp showk4 ; and carry on regardless. showk3: xor ah,ah ; Non-Netbios. Bios keyboard input. int keyb ; read a char push ax ; save the character call gss ; get shift state pop bx mov ah,al ; shift state to ah mov al,bh ; scan code to al showk4: push ax ; remember scan code mov di,offset shkbuf mov si,offset shkmsg mov cx,shkmln rep movsb ; copy in initial message call nout ; write out scan code mov si,offset shkms1 mov cx,shkm1ln ; second message rep movsb pop ax ; get scan code back pop bx ; and terminal arg block mov cx,[bx].klen ; and length jcxz showk2 ; no table, not defined push di ; remember output ptr mov di,[bx].ktab ; get key table repne scasw ; search for a definition for this mov si,di ; remember result ptr pop di ; get output ptr back jne showk2 ; not defined, forget it sub si,[bx].ktab ; compute offset from beginning sub si,2 ; minus 2 for pre-increment add si,[bx].krpl ; get index into replacement table mov si,[si] ; pick up replacement mov cl,[si] ; get length mov ch,0 inc si rep movsb ; copy into buffer showk2: mov ax,offset shkbuf ; this is buffer mov cx,di sub cx,ax ; length pop es ret ; and return showkey 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 NEAR cli mov ax,offset source mov srcpnt,ax mov savesi,ax mov count,0 sti ret CLRBUF ENDP ; Clear to the end of the current line. Returns normally. ; Upgraded for Topview compatibility. [jrd] CLEARL PROC NEAR push ax push bx push dx mov ah,3 ; Clear to end of line. mov bh,0 int bios ; Get current cursor position into dx mov ax,dx ; Topview compatible clear line mov bh,ah ; same row mov bl,79 ; last column call atsclr ; clear from ax to bx, screen coord pop dx pop bx pop ax ret CLEARL 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: outch2: push dx ; Save register. PUSH AX sub cx,cx mov al,ah ; Parity routine works on AL. call dopar ; Set parity appropriately. MOV AH,1 ; FLAG WRITE A CHAR FROM AL ; MOV DX,ASYPR ;SET COM1 OR COM2 PORT PUSH ES PUSH BX ; PUSH CX ; MOV BX,SEG DABUF MOV ES,BX MOV BX,2048 MOV CX,BX CALL SERIALIO ; VIA INT SYSTEM ; AH GETS 1 BIT SET IF CHAR THERE POP CX POP BX POP ES ; INT ASYIO ; LET INT 14 DO IT FOR US ; AH RETURNS WITH STATUS BYTE. AND AH,80H CMP AH,80H ; DID WE GET IT SENT? JZ OUTCH5 ; IF EQUAL NO, FAILED, RETURN. ; CAN'T TIME OUT REALLY... BIOS BETTER KEEP UP. POP DX POP AX jmp rskp outch5: pop dx POP AX ret ; This routine blanks the screen. Returns normally. ; Upgraded to Topview compatiblity. [jrd] CMBLNK PROC NEAR push ax push bx xor ax,ax ; from screen loc 0,0 mov bx,184fH ; to 24,79 call atsclr ; do Topview compatible clear, in msyibm pop bx pop ax ret CMBLNK ENDP ; Locate: homes the cursor. Returns normally. LOCATE PROC NEAR mov dx,0 ; Go to top left corner of screen. jmp poscur LOCATE ENDP ; write a line in inverse video at the bottom of the screen... ; the line is passed in dx, terminated by a $. Returns normally. putmod proc near push ax ; save regs. [jrd] push bx push cx push dx ; preserve message mov cx,1800h mov dx,184fh mov ax,600h ; scroll to clear the line mov bh,70h ; inverse video int bios mov dx,1800h ; now address line 24 call poscur pop si ; get message back mov cx,1 ; only one char at a time xor bh,bh ; page 0 putmo1: lodsb ; get a byte cmp al,'$' ; end of string? je putmo2 push si ; save si push ax ; and the char call poscur inc dl ; increment for next write pop ax ; recover char mov ah,9 ; try this mov bx,0070h ; inverse video, page 0 int bios pop si ; recover pointer jmp putmo1 putmo2: pop cx ; [jrd] pop bx pop ax ret putmod endp ; clear the mode line written by putmod. Returns normally. clrmod proc near push ax ; save regs. [jrd] push bx push cx push dx mov cx,1800h mov dx,184fh mov ax,600h mov bh,7h int bios pop dx ; [jrd] pop cx pop bx pop ax ret clrmod endp ; put a help message on the screen. This one uses reverse video... ; pass the message in ax, terminated by a null. Returns normally. puthlp proc near push bx ; save regs. [jrd] push cx push dx push si push ax ; preserve this cld mov si,ax ; point to it mov dh,1 ; init counter puthl1: lodsb ; get a byte cmp al,lf ; linefeed? jne puthl2 ; no, keep going inc dh ; count it jmp puthl1 ; and keep looping puthl2: cmp al,0 ; end of string? jne puthl1 ; no, keep going mov ax,600h ; scroll to clear window xor cx,cx ; from top left mov dl,4fh ; to bottom right of needed piece mov bh,70h ; inverse video int bios call locate ; home cursor mov bx,0070h ; bh = page 0, bl = inverse video mov cx,1 ; one char at a time cld ; scan direction is forward [jrd] pop si ; point to string again puthl3: lodsb ; get a byte cmp al,0 ; end of string? je puthl4 ; yes, stop push si ; save around bios call [jrd] cmp al,' ' ; printable? jb puth21 ; b = no mov ah,9 ; write char at current cursor position [jrd] int bios ; do the Bios int 10h call inc dl ; point to next column jmp puth23 ; move cursor there puth21: cmp al,cr ; carriage return? jne puth22 ; ne = no xor dl,dl ; set to column zero jmp puth23 puth22: cmp al,lf ; line feed? jne puth23 inc dh ; go to next line puth23: mov ah,2 ; set cursor position to dx int bios pop si ; restore pointer [jrd] jmp puthl3 ; and keep going puthl4: mov dx,24 * 100H ; go to last line call poscur ; position cursor pop si ; [jrd] pop dx pop cx pop bx ret puthlp endp ; Set the baud rate for the current port, based on the value ; in the portinfo structure. Returns normally. DOBAUD PROC NEAR push ax ; save some regs. [jrd] push bx ; [jrd] push dx ; [jrd] push bp ; [jrd] mov bp,portval mov temp1,ax ; Don't overwrite previous rate. [25] mov ax,ds:[bp].baud ; Check if new rate is valid. [25] mov tmp,2 mul tmp ; 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,temp1 ; 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 jmp dobd1 ; [jrd] dobd0: mov temp1,ax ; Remember value to output. [25] ; WE JIGGER THE BAUD TBL FROM 0 TO 7 NOW... PUSH DX ; MOV DX,ASYPR ; SET PORT 0 OR 1 MOV ASYMD,AX ; SAVE BAUD RATE SETTING AS JUST 0-7 SHL AX,1 SHL AX,1 ; SHIFT INTO PLACE SHL AX,1 SHL AX,1 SHL AX,1 AND AX,0E0H ; MASK ANY EXTRA JUNK SO ONLY BAUD RATE REMAINS OR AX,3 ; SET 8 BIT CHARS NO PARITY ; MOV AH,0 ; ENSURE HI BYTE ZERO TO FLAG SETUP MOV AH,ASYPR ; SET PORT 0 OR 1 MOV SRINIT,AX ;STASH AWAY INITIALIZING PARAMS PUSH ES MOV BX,SEG DABUF MOV ES,BX ; SET ES TO BUFFER MOV AH,0 MOV BX,2048 ;TRANSMIT BUFFER PUSH CX MOV CX,BX ; RCV BUFF SIZE CALL SERIALIO ; INIT THE PORT ; INT ASYIO ; GET BIOS TO SET BAUD POP CX POP ES ; RESTORE BUFFER'S ES POP DX ; RESTORE DX REG NOW dobd1: pop bp ; restore regs [jrd] pop dx ; [jrd] pop bx ; [jrd] pop ax ; [jrd] ret DOBAUD ENDP ; Get the current baud rate from the serial card and set it ; in the portinfo structure for the current port. Returns normally. ; This is used during initialization. GETBAUD PROC NEAR PUSH BP push cx ; [jrd] ; SKIP THIS FOR NOW ; SINCE BIOS WON'T RETURN CURRENT BAUD RATE, JUST USE SAVED RATE WE SAVE ; WHENEVER WE SET IT AND HOPE (PRAY?) IT'S RIGHT. BAUD RATE REALLY ; OUGHT TO BE SET PRIOR TO ENTRY WITH MODE COMMAND. ; MOV CX,ASYMD ; GET LAST-SET BAUD RATE. mov cx,srinit shr cx,1 shr cx,1 ; shift baud rate down shr cx,1 shr cx,1 shr cx,1 and cx,07h ; mask off all but baud rate pat'n MOV BP,OFFSET ASYBD ; GET OUR BAUD RATE TABLE ; CX HAS JUST A VALUE 0-7 WHICH WAS USED IN OUR LAST SET RATE ; JUST GET DISPLAY VALUE NOW IN 0-15 RANGE. ; ASYBD IS CONVERSION FROM SET BAUD RATE TO DISPLAY VALUE ADD CX,CX ; DOUBLE CX FOR WORD OFFSET ADD BP,CX MOV CX,DS:[BP] ; NOW GET TABLE VALUE OUT OF THERE mov bp,portval mov ds:[bp].baud,cx ; Set baud rate. pop cx ; [jrd] POP BP ret GETBAUD ENDP ; skip returns if no character available at port, ; otherwise returns with char in al, # of chars in buffer in dx. PRTCHR PROC NEAR ; SINCE BIOS READ IS SYNCHRONOUS WE HAVE TO CALL IT TWICE, ONCE TO ; SEE IF ANYTHING'S THERE, AND AGAIN IF SO TO GET THE CHARACTER. ; PUSH BX MOV AH,3 ; EXAMINE STATUS FUNCTION PUSH DX ; MOV DX,ASYPR ; COM1 OR COM2 PUSH ES PUSH BX ; PUSH CX ; MOV BX,SEG DABUF MOV ES,BX MOV BX,2048 MOV CX,BX CALL SERIALIO ; VIA INT SYSTEM ; AH GETS 1 BIT SET IF CHAR THERE POP CX POP BX POP ES POP DX AND AH,1 ; LOOK AT DATA READY BIT CMP AH,1 ; IS IT ON? JZ PRTCH1 ; IF ZERO YES POP BX JMP RSKP ; NOTHING THERE ... SKIP RETURN PRTCH1: MOV AH,2 ; CHAR THERE ... READ IT (SYNCHRONOUSLY) PUSH DX ; MOV DX,ASYPR ; SET COM1 OR COM2 PUSH ES PUSH BX ; PUSH CX ; MOV BX,SEG DABUF MOV ES,BX MOV BX,2048 ; GET 1 CHAR MOV CX,BX CALL SERIALIO ; VIA INT SYSTEM ; AH GETS 1 BIT SET IF CHAR THERE POP CX POP BX POP ES POP DX POP BX RET PRTCHR ENDP ; local routine to see if we have to transmit an xon chkxon proc near ; push bx ; mov bx,portval ; cmp [bx].floflg,0 ; doing flow control? ; je chkxo1 ; no, skip all this ; cmp xofsnt,false ; have we sent an xoff? ; je chkxo1 ; no, forget it ; cmp count,mntrgh ; below trigger? ; jae chkxo1 ; no, forget it ; mov ax,[bx].flowc ; ah gets xon ; call outchr ; send it ; nop ; nop ; nop ; in case it skips ; mov xofsnt,false ; remember we've sent the xon. ;chkxo1: pop bx ; restore register ret ; and return chkxon endp ; IHOSTS - Initialize the host by sending XON, or equivalent, and enter the ; cycle of clear input buffer, wait 1 second, 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 NEAR 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 call outchr ; send it (release Host's output queue) nop ; outchr can do skip return nop nop ihosts1:call clrbuf ; clear out interrupt buffer mov ax,1 ; sleep for 1 second call sleep ; procedure sleep is in msscom.asm 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 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 call outchr ; send it (release Host's output queue) nop ; outchr can do skip return nop nop pop cx pop bx pop ax ret IHOSTR ENDP ; Send a break out the current serial port. Returns normally. SENDBR PROC NEAR ; ; CAN'T SEND BREAK VIA BIOS SO SKIP THIS ; ret ; And return. SENDBR ENDP ; Wait for the # of milliseconds in ax ; Thanks to Bernie Eiben for this one. pcwait proc near mov cx,240 ; inner loop counter for 1 millisecond pcwai1: sub cx,1 ; inner loop takes 20 clock cycles jnz pcwai1 dec ax ; outer loop counter jnz pcwait ; wait another millisecond ret pcwait endp ; Position the cursor according to contents of DX: ; DH contains row, DL contains column. Returns normally. POSCUR PROC NEAR push ax push bx mov ah,2 ; Position cursor. mov bh,0 ; page 0 int bios pop bx pop ax ret POSCUR ENDP ; Delete a character from the terminal. This works by printing ; backspaces and spaces. Returns normally. DODEL PROC NEAR mov ah,prstr mov dx,offset delstr ; Erase weird character. int dos ret DODEL ENDP ; Move the cursor to the left margin, then clear to end of line. ; Returns normally. CTLU PROC NEAR mov ah,prstr mov dx,offset clrlin int dos call clearl ret CTLU ENDP ; set the current port. COMS PROC NEAR mov dx,offset comptab mov bx,0 MOV ASYPR,0 mov ah,cmkey call comnd jmp r push bx mov ah,cmcfm call comnd ; Get a confirm. jmp comx ; Didn't get a confirm. nop pop bx mov flags.comflg,bl ; Set the comm port flag. cmp flags.comflg,1 ; Using Com 1? jne coms0 ; Nope. MOV ASYPR,0 ; SET PORT 1 mov ax,offset port1 mov portval,ax mov modem.mddat,MDMDAT1 ; Set COM1 defaults. mov modem.mdstat,MDMSTS1 mov modem.mdcom,MDMCOM1 mov modem.mddis,MDMINTC mov modem.mden,MDMINTO mov modem.mdmeoi,EOICOM mov modem.mdintv,MDMINTV mov brkadr,MDMCOM1 ret coms0: mov ax,offset port2 MOV ASYPR,1 ; SET PORT 2 mov portval,ax mov modem.mddat,MDMDAT2 ; Set COM2 defaults. mov modem.mdstat,MDMSTS2 mov modem.mdcom,MDMCOM2 mov modem.mddis,MDINTC2 mov modem.mden,MDINTO2 mov modem.mdmeoi,EOICOM2 mov modem.mdintv,MDINTV2 mov brkadr,MDMCOM2 ret comx: pop bx ret COMS ENDP ; begin Terminal set & status code ; 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. VTS proc near ; SET TERM whatever mov ah,cmkey ; Parse another keyword. mov bx,offset vthlp ; Use this help mov dx,offset vttbl ; Use this table call comnd jmp r ; Vsetup always returns +1. cmp bx,100H ; marker for terminal type? jb vsetu1 ; b = no. cmp bx,200h ; marker for set term color? je vsetu2 ; e = yes push bx ; yes mov ah,cmcfm call comnd ; Get a confirm. jmp vsetu0 ; Didn't get a confirm. nop pop bx mov flags.vtflg,bl ; Set the terminal emulation type ret ; in standard global byte. vsetu0: pop bx ret vsetu1: sal bx,1 ; Make bx a word index. call vtrtns[bx] ; Dispatch. jmp r ; Vsetup always returns +1. jmp r ; Vsetup always returns +1. ; Set Term Color foreground, background vsetu2: mov ah,cmtxt ; get number(s) after set term color mov dx,offset colhlp ; use this help mov bx,offset rdbuf ; temp buffer mov byte ptr [bx],0 ; clear the buffer call comnd jmp r cmp ah,0 ; anything given? jne vsetu2a ; ne = yes. jmp r ; else give not confirmed msg vsetu2a:mov ah,cmcfm ; Parse confirm mov bx,0 ; Use default help. call comnd jmp r ; not confirmed, complain. mov si,offset rdbuf ; si = place where atoi wants text vsetu2c:mov dx,si call strlen ; current length of text jcxz vsetu2x ; nothing left mov ah,cl ; put length where Atoi wants it call atoi ; convert text to numeric in ax jmp colbad ; no value available cmp ax,0 ; reset all? regular IBM CGA refresh je vsetu2j ; e = yes cmp ax,1 ; high intensity? je vsetu2k ; e = yes cmp ax,10 ; fast refresh? je vsetu2l ; e = yes cmp ax,30 ; check range jb colbad ; b = too small. complain cmp ax,37 jna vsetu2b ; 30-37 is foreground color cmp ax,40 jb colbad cmp ax,47 ; Compare as unsigned. jna vsetu2b ; 40-47 is background jmp colbad ; else error vsetu2x:jmp rskp ; and return normally. vsetu2b:push bx mov bx,vtemu.att_ptr ; Get address of attributes byte cmp al,40 ; background (40-47)? jnb vsetu2f ; nb = yes sub al,30 ; remove foreground bias and byte ptr [bx],not 07H ; clear foreground bits test al,1 ; ANSI red? jz vsetu2d ; z = no or byte ptr [bx],4 ; set IBM foreground red vsetu2d:test al,2 ; ANSI & IBM green? jz vsetu2e ; z = no or byte ptr [bx],2 ; set green foreground vsetu2e:test al,4 ; ANSI Blue? jz vsetu2i ; z = no or byte ptr [bx],1 ; set IBM blue jmp vsetu2i ; done with foreground settings vsetu2f:sub al,40 ; remove background bias and byte ptr [bx],not 70H ; clear background attributes test al,1 ; ANSI red? jz vsetu2g ; z = no or byte ptr [bx],40h ; set IBM background red vsetu2g:test al,2 ; ANSI & IBM green? jz vsetu2h ; z = no or byte ptr [bx],20h ; set green background vsetu2h:test al,4 ; ANSI Blue? jz vsetu2i ; z = no or byte ptr [bx],10h ; set IBM blue vsetu2i:pop bx jmp vsetu2c ; get any next value vsetu2j:mov refresh,0 ; Regular (slow) screen refresh mov bx,vtemu.att_ptr ; Get address of attributes byte mov byte ptr [bx],07h ; clear all, set white on black. jmp vsetu2c ; get next value vsetu2k:mov bx,vtemu.att_ptr ; Get address of attributes byte or byte ptr [bx],08h ; set high intensity jmp vsetu2c ; get next value vsetu2l:mov refresh,1 ; Fast screen refresh jmp vsetu2c colbad: mov ah,prstr ; Not in range - complain and exit. mov dx,offset colerr int dos jmp rskp ; SET Term flags. These are the (near) equivalent of VT100 Setup mode values. flgset: push bx ; Save bx for a second. mov ah,cmkey ; Another keyword. mov dx,vtable[bx] ; The table to use. mov bx,0 ; Use default help. call comnd jmp flgse3 push bx ; Save switch value. mov ah,cmcfm ; Confirm it. call comnd jmp flgse2 pop dx ; Restore switch value. pop bx ; And index. sar bx,1 ; Make it a byte index. mov al,vtsflg[bx] ; Get the flag. cmp dx,0 ; Set or clear? je flgse1 ; Go clear it. or vtemu.vtflgst,al ; Set the flag. jmp rskp ; Give good return. flgse1: not al ; Complement and vtemu.vtflgst,al ; Clear the indicated flag. jmp rskp ; Give good return. flgse2: pop bx ; error exits flgse3: pop bx ret ; SET Term Tabstops Clear ALL ; SET Term Tabstops Clear AT n1, n2, ..., nx ; SET Term Tabstops At n1, n2, ..., nx tabset: cld ; Make sure this is clear. mov di,offset tmptabs ; clear our temp work area here. mov cx,80 ; 80 columns mov al,0 ; set "not touched" indicator rep stosb ; in all tmptabs slots mov ah,cmkey ; Parse keyword. mov bx,offset clrhlp ; Use this help text. mov dx,offset tabtab ; This table. call comnd jmp r mov clrset,2 ; code for set a tab cmp bl,0 ; Was it set or clear? jne tabse1 ; SET - go parse column number(s). mov clrset,1 ; code for clear at/all tab(s) mov ah,cmkey ; CLEAR - parse ALL or AT mov bx,offset allhlp ; Use this help text. mov dx,offset alltab ; Parse ALL or AT. call comnd jmp r cmp bx,0 ; ALL? jne tabse1 ; ne = AT, clear at specific places. mov al,1 ; ALL, means clear all tab stops. mov cx,80D mov di,offset tmptabs rep stosb mov ah,cmcfm ; Confirm it. call comnd jmp r jmp tabcpy ; update active & coldstart tabs tabse1: mov dx,offset tbshlp ; Tell them we want a column number. cmp clrset,1 ; Clearing? jne tabse2 ; ne = Set. we guessed right on help. mov dx,offset tbchlp ; Yes - use this help instead. tabse2: mov ah,cmtxt ; get text w/o white space mov bx,offset rdbuf ; temp buffer call comnd jmp r cmp ah,0 ; anything given? jne tabse4 ; ne = yes. jmp r ; else give not confirmed msg tabse4: mov ah,cmcfm ; Parse confirm mov bx,0 ; Use default help. call comnd jmp r ; not confirmed, complain. mov si,offset rdbuf ; si = place where atoi wants text tabse5: mov dx,si call strlen ; current length of text mov ah,cl ; put length where Atoi wants it jcxz tabcpy ; nothing left call atoi ; convert text to numeric in ax nop nop nop mov bx,ax ; for subscripting in code below dec bx ; Put column in range 0-79 cmp bx,0 ; check range (1-80 --> 0-79) jl tbsbad ; l = too small. complain cmp bx,79 ; Compare as unsigned. jna tabse3 tbsbad: mov ah,prstr ; Not in range - complain and exit. mov dx,offset tbserr int dos jmp rskp tabse3: mov al,clrset ; Get value for setting or clearing. mov tmptabs[bx],al ; store in tabs temp work array jmp tabse5 ; look for more tabcpy: mov cx,80 ; update 80 tab stops mov si,vtemu.vttbst ; in terminal emulator's active buffer mov di,vtemu.vttbs ; and in the cold-start buffer. mov bx,0 ; subscript tabcpy1:mov al,byte ptr tmptabs [bx] ; get a table entry into al or al,al ; what is the code? jz tabcpy3 ; z = do not touch cmp al,2 ; set a tab? je tabcpy2 ; e = set the tab mov byte ptr [bx+si],0 ; clear the tab mov byte ptr [bx+di],0 ; clear the tab jmp tabcpy3 tabcpy2:mov byte ptr [bx+si],0ffh ; set the tab mov byte ptr [bx+di],0ffh ; set the tab tabcpy3:inc bx ; inc subscript loop tabcpy1 jmp rskp ; Give good return. VTS endp ; end of Set Term things. ; Terminal Status display, called within STAT0: in MSSSET.[jrd] VTSTAT proc near ;enter with di within sttbuf, save bx, di push bx push di mov bx,ds mov es,bx cld mov bx,offset vtstbl ; table of things to show xor cx,cx vtsta1: cmp word ptr [bx],0 ; end of table? je vtstax ; e = yes push bx call [bx].sttyp ; call appropriate routine pop bx ; cx incremented by output count cmp cx,37 ; place for second display jbe vtsta2 ; le = only half full mov dx,offset crlf ; over half full. send cr/lf mov ah,prstr int dos xor cx,cx ; say line is empty now jmp vtsta4 vtsta2: push cx mov cx,37 ; where we want to be next time pop ax sub cx,ax ; compute number of filler spaces jcxz vtsta4 ; nothing to do mov ah,conout mov dl,' ' vtsta3: int dos ; fill with spaces loop vtsta3 ; do cx times mov cx,37 ; current column number vtsta4:add bx,size stent ; look at next entry jmp vtsta1 ; and do it vtstax: pop di pop bx add di,40 ; say we used a lot of buffer space ret ; return to STAT0: in MSSSET. ; foreground/background color status colstat proc near mov dx,offset colst1 mov ah,prstr int dos ; print first part of msg xor ax,ax mov bx,vtemu.att_ptr ; pointer to attributes byte test byte ptr [bx],1 ; IBM blue foregound? jz colsta1 ; z = no or al,4 ; set blue bit colsta1:test byte ptr [bx],2 ; IBM green foreground? jz colsta2 or al,2 colsta2:test byte ptr [bx],4 ; IBM red foreground? jz colsta3 or al,1 colsta3:add al,'0' ; add ascii bias mov dl,al ; move to DOS place mov ah,conout int dos ; print the last digit mov dx,offset colst2 ; now do background mov ah,prstr int dos ; print second part of msg xor ax,ax test byte ptr [bx],10h ; IBM blue background? jz colsta4 ; z = no or al,4 ; set blue bit colsta4:test byte ptr [bx],20h ; IBM green background? jz colsta5 or al,2 ; set green bit colsta5:test byte ptr [bx],40h ; IBM red background? jz colsta6 or al,1 ; set red bit colsta6:add al,'0' ; add ascii bias mov dl,al ; move to DOS place mov ah,conout int dos add cx,45 ; about the # columns we used ret colstat endp ; Tabs Status display tabstat proc near ; display tabs ruler for Status push dx jcxz tabsta0 ; empty line, as it should be xor cx,cx ; used line, empty it mov dx,offset crlf ; cr, lf mov ah,prstr int dos tabsta0:mov si,vtemu.vttbst ; active tabs address, not shadow mov cx,79 ; loop 79 times dec si ; dec for inc below xor ax,ax ; tens counter tabsta1:mov dl,'.' ; default position symbol inc si ; start with position 1 inc al cmp al,10 ; time to roll over? jb tabsta2 ; b = not yet mov al,0 ; modulo 10 inc ah mov dl,ah ; display a tens-digit add dl,'0' tabsta2:cmp byte ptr [si],0 ; is tab set? je tabsta3 ; e = no mov dl,'T' ; yes, display a 'T' tabsta3:push ax mov ah,conout ; console output int dos pop ax loop tabsta1 ; loop til done (cx has count) pop dx mov cx,79 ; say line is full ret tabstat endp ; handler routines for status. All are called with bx/ stat ptr. onoff proc near call stmsg ; print the message mov si,[bx].basval ; get base value cmp si,0 ; any there? je onoff1 ; e = no mov si,[si] ; yes, use as base address onoff1: add si,[bx].tstcel ; add offset of test cell mov al,[si] mov dx,offset onmsg ; add cx,2 ; assume two byte on message or al,al ; test value jnz onoff2 ; nz = on mov dx,offset offmsg inc cx ; three byte message onoff2: mov ah,prstr ; display the message int dos ret onoff endp ; search a keyword table for a bit value, print that value. [jrd] srchkb proc near call stmsg ; first print message call stbval ; get bit set or reset mov ah,0 ; al has 0/1, high order is 0 mov bx,[bx].val2 ; this is table address jmp prttab ; and look in table. srchkb endp ; get address of test value in stent. Returns address in si. [jrd] stbval proc near mov si,[bx].basval ; get address of test value cmp si,0 ; any there? je stbva1 ; no, quit with no match mov al,byte ptr [si]; get byte value mov ah,0 test al,vtemu.vtflgst ; bit test value against emulator flags byte jz stbva1 ; z = they don't match mov al,1 ; match ret stbva1: mov al,0 ; no match ret ; and return it stbval endp ; get address of test value in stent. Returns address in si stval proc near mov si,[bx].basval ; get base value cmp si,0 ; any there? je stva1 ; no, keep going mov si,[si] ; yes, use as base address stva1: add si,[bx].tstcel ; add offset of test cell ret ; and return it stval endp ; copy the message to the screen stmsg proc near mov si,[bx].msg ; get message address stms1: lodsb ; get a byte cmp al,'$' ; end of message? je stms2 ; e = yes mov dl,al ; display the character mov ah,conout int dos inc cx ; count output chars jmp stms1 stms2: ret stmsg endp ; Print value from table. BX/address of table, AL/value of variable. prttab: push cx ; save column count mov cl,[bx] ; Number of entries in our table. inc bx ; Point to the data. prtt0: mov dl,[bx] ; Length of keyword. inc bx ; Point to keyword. mov dh,0 inc dx ; Account for "$" in table. mov si,dx ; Put to index register. cmp ax,[bx+si] ; Is this the one? je prtt1 add bx,dx ; Go to end of keyword. add bx,2 ; Point to next keyword. dec cl ; Any more keywords to check? jnz prtt0 ; Yes, go to it. mov bx,offset prterr prtt1: mov si,bx pop cx ; recover column count jmp stms1 ; copy in message ret ; and return VTSTAT endp ; end of Terminal set & status code ; 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. ; ; Revised slightly by Joe R. Doupnik 22 Dec 1985 to prevent interrupts ; being enabled until we're done, to stop interrupts from occurring when ; TX holding buffer becomes empty (a useless interrupt for us), and to ; shorten the time between enabling interrupts and our exit. [jrd] ; Returns normally. SERINI PROC NEAR cmp portin,0 ; Did we initialize port already? [21c] jne serin0 ; Yes, so just leave. [21c] ; INIT WITH 1200 BAUD, 8 BITS, NO PARITY PUSH DX MOV PORTIN,1 ; SET INIT'D ALREADY... PUSH ES PUSH AX PUSH BX PUSH CX ; SAVE REGS WE USE MOV AX,SEG DABUF ; BUFFER SEGMENT MOV ES,AX ; STORE IN ES ; mov ax,srinit ; get old baud rate if any MOV AH,ASYPR ; SET PORT UP MOV ASYMD,4 ; SET ASYNCH BAUD RATE SAVE cmp srinit,0 ; got a baud rate setup yet? jnz serin8 ; if nonzero assume yes, leave it there. MOV AL,083H ; INIT PATTERN FOR 1200 BAUD, 8 BITS, NO PARITY serin8: MOV BX,2048 MOV CX,BX ; BUFFERS 2048 LONG MOV SRINIT,AX ; SET SRINIT WORD FOR BAUD RATE MOV AH,0 ; SET INIT CALL SERIALIO ; DO THE WORK POP CX POP BX POP AX POP ES ; FIX STACK & REGS ; INT ASYIO POP DX ; BIOS INITS BAUD RATE ETC. serin0: ret ; We're done. [jrd] SERINI ENDP ; Reset the serial port. This is the opposite of serini. Calling ; this twice without intervening calls to serini should be harmless. ; Moved push/pop es code to do quicker exit before interrupts enabled. [jrd] ; Returns normally. SERRST PROC NEAR ; NOTHING REALLY TO DO HERE PUSH AX PUSH DX MOV AH,4 CALL SERIALIO ; CLOSE SERIAL I/O POP DX POP AX srst1: ret ; All done. SERRST ENDP DTRLOW PROC NEAR ; Global proc to Hangup the Phone by making ; CAN'T DO THIS... IGNORE jmp rskp DTRLOW ENDP ; Hang up the Phone. Similar to SERRST except it just forces DTR and RTS low ; to terminate the connection. 29 March 1986 [jrd] ; Calling this twice without intervening calls to serini should be harmless. ; Returns normally. serhng proc near ; clear modem's delta status bits and lower DTR & RTS ret serhng endp ; Produce a short beep. The PC DOS bell is long enough to cause a loss ; of data at the port. Returns normally. BEEP PROC NEAR mov al,10110110B ; Gen a short beep (long one losses data.) out timer+3,al ; Code snarfed from Technical Reference. mov ax,533H out timer+2,al mov al,ah out timer+2,al in al,port_b mov ah,al or al,03 out port_b,al sub cx,cx mov bl,1 beep0: loop beep0 dec bl jnz beep0 mov al,ah out port_b,al ret BEEP ENDP ; put the number in ax into the buffer pointed to by di. Di is updated nout proc near mov dx,0 ; high order is always 0. mov bx,10 div bx ; divide to get digit push dx ; save remainder digit or ax,ax ; test quotient jz nout1 ; zero, no more of number call nout ; else call for rest of number nout1: pop ax ; get digit back add al,'0' ; make printable stosb ; drop it off ret ; and return nout endp ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. RSKP PROC NEAR pop bp add bp,3 push bp ret RSKP ENDP ; Jumping here is the same as a ret. R PROC NEAR ret R ENDP PAGE ;-----------------------------------------------; ; Initialize the communication port using (DX) ; (srinit) bits: ; 8 Port ; 7-5 Baud rate ; 4-3 Parity ; 2 Stop bits ; 1-0 Data length ;-----------------------------------------------; SERINZ PROC NEAR ; ------- Set up buffer pointers ASSUME DS:DATAS MOV RXLENGTH,CX MOV TXLENGTH,BX MOV TXBUFFSEG,ES MOV RXBUFFSEG,ES MOV CL,4 SHR BX,CL ADD RXBUFFSEG,BX MOV RXBUFFSTRT,0 MOV RXBUFFEND,0 MOV TXBUFFSTRT,0 MOV TXBUFFEND,0 MOV PORT,1 ; default to port B MOV AX,SRINIT ; load parameters TEST AX,256 ; port B (0) or port A (1) JZ SER1 MOV PORT,0 SER1: ; ------- Set up serial port interrupt vector PUSH AX CLI ; XOR BX,BX ; MOV ES,BX ; MOV BX,0BH*4 ; MOV AX,OFFSET SERINT; MOV ES:[BX],AX ; MOV AX,CS ; ADD BX,2 ; MOV ES:[BX],AX ; ; ------- Enable interrupt controller IN AL,21H ; AND AL,0F7H ; Mask port bit OUT 21H,AL ; enabled STI ; ------- Do a chanel reset MOV DX,SERIAL+2 ; Point to command port ADD DX,PORT ; offset for PORT A or PORT B MOV AL,18H ; Command OUT DX,AL ; Send NOP ; Wait NOP ; Wait NOP ; Wait NOP ; Wait NOP ; Wait NOP ; Wait NOP ; Wait OUT DX,AL ; Send ; ------- Initiate baud timer POP AX PUSH AX ; Save MOV BL,40H ; Assume port 1 TEST PORT,1 JNZ SER3 SHL BL,1 ; adjust for A port timer SER3: OR BL,36H ; Add mode3 and read/load data MOV CL,4 ; Shift count SHR AL,CL ; Adjust baud AND AL,0EH ; Mask off unwanted bits MOV AH,0 ; Zero MOV SI,AX ; Index MOV CX,WORD PTR DS:SBAUD[SI]; Baud rate MOV AL,BL ; Get Timer parameters OUT TIMER+3,AL ; Timer command MOV AL,CL ; Baud rate MOV DX,TIMER+2 ; ----Port A SUB DX,PORT ; make adjustment for Port B OUT DX,AL ; Timer LSB MOV AL,CH ; then OUT DX,AL ; Timer MSB ; ------- Set WR2 CHAN A MOV AL,WR2 ; WR2 OUT SERIAL+2,AL ; Set MOV AL,14H ; System configuration OUT SERIAL+2,AL ; Sent ; ------- Set WR2 CHAN B MOV DX,SERIAL+3 ; Point to command port MOV AL,WR2 ; WR2 OUT DX,AL ; Set MOV AL,NUL ; WR2 OUT DX,AL ; Sent POP AX ; Retreive parameters ; ------- Set WR4 (parity, stop, clock) MOV DX,SERIAL+2 ADD DX,PORT ; point to command port MOV BX,AX ; Save parameters MOV AL,BL ; Parameters MOV CL,3 ; Count SHR AL,CL ; Shift bits AND AL,3 ; Mask out MOV AH,AL ; Parity MOV AL,BL ; Get parameters again SHL AL,1 ; AND AL,8 ; Mask OR AL,4 ; Assume 7 bits OR AH,AL ; Add to parity OR AH,CLK_X_16 ; Add in clock X 16 MOV AL,WR4 ; WR4 OUT DX,AL ; Set MOV AL,AH ; Value OUT DX,AL ; Sent ; ------- Set WR3 MOV AL,WR3 ; WR3 OUT DX,AL ; Set MOV AL,BL ; Parameters AND AL,3 ; Mask out ROR AL,1 ; Adjust ROR AL,1 ; OR AL,RX_ENAB ; Enable reciver OUT DX,AL ; Send WR3 ; ------- Set up mask for reciver MOV AH,0FFH ; MOV BH,BL ; AND BH,3 ; CMP BH,3 ; JE SERI08 ; CMP BH,2 ; JE SERI06 ; CMP BH,1 ; JE SERI07 ; SHR AH,1 ; SERI06: SHR AH,1 ; SERI07: SHR AH,1 ; SERI08: MOV SERMASK,AH ; Initalize mask char ; ------- Set WR5 SHR AL,1 ; Shift bit AND AL,60H ; Remove unwanted bits OR AL,DTR+TX_ENAB+RTS; Set TX enable, DTR and RTS MOV AH,AL ; Save MOV AL,WR5 ; WR5 OUT DX,AL ; Set MOV AL,AH ; Restore OUT DX,AL ; Send value ; ------- Reset WR0 error flags MOV AL,0 OUT DX,AL MOV AL,10H ; EXT Status OUT DX,AL ; ------- Set WR1 MOV AL,WR1 ; WR1 OUT DX,AL ; Set MOV AL,1FH ; EXT INT ENAB,STAT AFF VECT,ALL RX CHAR OUT DX,AL ; Sent ; ------- Reset WR0 error flags MOV AL,0 OUT DX,AL MOV AL,20H ; Enab RX INT OUT DX,AL MOV AL,28H ; TX INT Pend OUT DX,AL MOV AL,38H ; EOI OUT SERIAL+2,AL ; ------- Get the status of port CALL UPDATESTAT ; CALL STATCHG ; MOV AX,SERSTAT ; Get the status ; ------- End ; return them to the user RET SERINZ ENDP PAGE ;-----------------------------------------------; ; Buffer up the character in (AL) ;-----------------------------------------------; SERPUT PROC NEAR CLI ; Do not allow interrupts MOV DI,TXBUFFEND ; End of buffer PUSH DS ; Save ds MOV DS, TXBUFFSEG ; see of buffer MOV [DI],AL ; Store character POP DS ; INC DI ; Increment pointer CMP TXLENGTH,0 ; JE TXBUFFOK ; CMP DI,TXLENGTH ; See if at end of buffer JNE TXBUFFOK ; If not go XOR DI,DI ; Else zero buffer TXBUFFOK: MOV TXBUFFEND,DI ; PUSH AX STI ; Interrupts back on CALL STRTXMITT ; MOV AX,SERSTAT ; Get the status POP BX ; MOV AL,BL ; Retrieve old al RET SERPUT ENDP PAGE ;-----------------------------------------------; ; Transmit a character from Buffer ;-----------------------------------------------; STRTXMITT: MOV DX,SERIAL+2 ADD DX,PORT ; select port A or port B IN AL,DX TEST AL,4 ; See if transmitter empty JNZ XMITT ; JMP SHORT XMITRET ; XMITT PROC NEAR MOV SI,TXBUFFSTRT ; Start of buffer CMP TXBUFFEND,SI ; See if any thing to transmit JE XMITTRET ; If not then split PUSH DS ; Save SEG MOV DS,TXBUFFSEG ; Get buffer SEG MOV AL,[SI] ; Get a char POP DS ; retrieve INC SI ; Update pointer CMP TXLENGTH,0 ; JE NOXWRAP ; CMP SI,TXLENGTH ; Check for wrap JNE NOXWRAP ; XOR SI,SI ; NOXWRAP: MOV TXBUFFSTRT,SI ; Save new pointer MOV DX,SERIAL ADD DX,PORT OUT DX,AL ; Send character JMP SHORT XMITRET ; XMITTRET: MOV AL,28H MOV DX,SERIAL+2 ADD DX,PORT OUT DX,AL ; Reset TX int pending XMITRET: CALL UPDATESTAT ; Update the status of port RET XMITT ENDP PAGE ;-----------------------------------------------; ; Get a character from Buffer ;-----------------------------------------------; SERGET PROC NEAR CLI MOV SI,RXBUFFSTRT ; Start of buffer MOV AL,0 ; Assume null char CMP SI,RXBUFFEND ; Check for buffer empty JE GETRET ; If so split PUSH DS ; Save MOV DS,RXBUFFSEG ; Receiver buffer see MOV AL,[SI] ; Get a char POP DS ; Retrive INC SI ; Update buffer pointer CMP RXLENGTH,0 ; JE NORWRAP ; CMP SI,RXLENGTH ; Check for buffer wrap JNE NORWRAP ; XOR SI,SI ; NORWRAP: MOV RXBUFFSTRT,SI ; STI ; PUSH AX ; CALL UPDATESTAT ; Update the current statuses POP AX ; MOV BX,SERSTAT ; Get the status MOV AH,BH ; Put it where it goes and split GETRET: STI RET SERGET ENDP ;-----------------------------------------------; ; Receive a character into Buffer ;-----------------------------------------------; RECEIVE PROC NEAR MOV DX,SERIAL ADD DX,PORT ; offset for port A or port B IN AL,DX ; Get a char from port AND AL,SERMASK ; Mask off unwanted bits MOV DI,RXBUFFEND ; MOV ES,RXBUFFSEG ; MOV ES:[DI],AL ; Store char in buffer INC DI ; Update pointer CMP RXLENGTH,0 ; JE RXBUFFOK ; CMP DI,RXLENGTH ; JNE RXBUFFOK ; XOR DI,DI ; RXBUFFOK: MOV RXBUFFEND,DI ; Save pointer CALL UPDATESTAT ; RET RECEIVE ENDP PAGE ;-----------------------------------------------; ; Get Status Condition into (AX) ;-----------------------------------------------; SERSTS PROC NEAR MOV AX,SERSTAT AND SERSTAT,61FFH ; Clear errors and stuff RET SERSTS ENDP ;-----------------------------------------------; ; Close out the serial port ;-----------------------------------------------; SEREND PROC NEAR IN AL,21H OR AL,8 OUT 21H,AL MOV AL,18H MOV DX,SERIAL+2 ADD DX,PORT OUT DX,AL RET SEREND ENDP PAGE ;-----------------------------------------------; ; Update the current statuses of the buffer ;-----------------------------------------------; UPDATESTAT PROC NEAR PUSH AX PUSH BX MOV AX,SERSTAT ; Get the current status AND AX,9EFFH ; Mask out buffer stats saving errors MOV BX,RXBUFFEND ; Check receiver status CMP BX,RXBUFFSTRT ; JE UP105 ; If equal then buffer empty OR AH,1 ; Set flag if not empty INC BX ; Check for buffer overflow CMP RXLENGTH,0 ; JE UP100 ; CMP BX,RXLENGTH ; JNE UP100 ; XOR BX,BX ; ; ------- Check for over flow UP100: CMP BX,RXBUFFSTRT ; If equal Then next char will overflow JNE UP105 ; OR AH,80H ; So report error now ; ------- Do transmitter UP105: MOV BX,TXBUFFEND ; Check xmitter CMP BX,TXBUFFSTRT ; If equal then buffer empty JNE UP110 ; OR AH,40H ; Report buffer empty JMP SHORT UP130 ; And GO ; ------- Check for full UP110: INC BX ; Check for buffer full CMP TXLENGTH,0 ; JE UP120 ; CMP BX,TXLENGTH ; JNE UP120 ; XOR BX,BX ; UP120: CMP BX,TXBUFFSTRT ; JNE UP130 ; If not equal then not full OR AH,20H ; UP130: MOV SERSTAT,AX ; Put in the new status POP BX POP AX RET UPDATESTAT ENDP PAGE ;-----------------------------------------------; ; Report any change in port status ;-----------------------------------------------; STATCHG PROC NEAR MOV DX,SERIAL+2 ADD DX,PORT IN AL,DX MOV BX,SERSTAT ; AND BX,0FF00H ; Clear port status TEST AL,8 ; Data carrier detect JZ STAT100 ; OR BL,8 ; MOV AL,1 ; STAT100: TEST AL,20H ; Clear to send JZ STAT110 ; OR BL,10H ; STAT110: MOV AL,1 ; WR1 OUT dx,AL IN AL,dx TEST AL,10H ; Parity error JZ STAT120 ; OR BH,4 ; STAT120: TEST AL,20H ; Over run error JZ STAT130 ; OR BH,2 ; STAT130: TEST AL,40H ; Framing error JZ STAT140 ; OR BH,8 ; STAT140: MOV AL,0F0H OUT dx,AL ; Reset error pend MOV AL,10H ; Reset ext stats OUT dx,AL ; RET STATCHG ENDP PAGE ;-----------------------------------------------; ; Serial port interrupt handler ;-----------------------------------------------; SERINT PROC FAR STI PUSH AX ; PUSH BX ; PUSH CX ; PUSH DX ; PUSH DI ; PUSH SI ; PUSH DS ; PUSH ES ; MOV AX,SEG DATAS ; Set DS to DATA SEG MOV DS,AX ; ASSUME DS:DATAS MOV AL,2 ; OUT SERIAL+3,AL ; Set up to RR2 IN AL,SERIAL+3 ; AND AL,3 ; Mask off unwanted bits SHL AL,1 ; Justify for call CBW ; Convert to word MOV SI,AX ; CALL DS:WORD PTR INTTBL[SI]; Branch indirectly SERIAB: MOV AL,20H ; Send an EOI command OUT 20H,AL ; To interrupt controller ; ------- Send an EOI to port A because INTEL is strange MOV AL,38H ; EOI to serial port OUT SERIAL+2,AL ; POP ES ; POP DS ; Restore POP SI ; POP DI ; POP DX ; POP CX ; POP BX ; POP AX ; IRET SERINT ENDP CODE ENDS END