NAME msx55x ; File MSX55X.ASM ; Kermit system dependent module for Sanyo MBC-55x ; Sanyo mods by Robert W. Babcock and Joseph H. White ; For version which replaces the BIOS keycode translation table, ; use -dMODIFIED flag to MASM. ; Edit History ; Last edit 16 Oct. 1988, only call pcwtst on first serini call ; 1 Jan 1988 version 2.30 ; 24 Dec 1987 Revise selection of COM1 to use COM1 name but COM2 addresses ; if base address of 02f8 (COM2) is found in 40:00h and display notice. ; Restore state of IRQ interrupt line when finished with serial port. [jrd] ; 31 Oct 1987 Add terminal type Tek4010, with Tek submode Tekflg. [jrd] ; 24 Oct 1987 Enhance clrbuf to empty any intermediate (net) buffers. [jrd] ; 19 Oct 1987 Fix stray tab-set at column 32. [jrd] ; 2 Oct 1987 Add PCjr baud rate table, from Ted Medin. [jrd] ; 6 Sept 1987 Allow serial port serint to send xoff when buffer fills even ; though user may have sent xoff by hand. [jrd] ; 27 Aug 1987 Skip timeout test in OUTCHR if receive timeout is zero. [jrd] ; 23 August 1987 Add vtemu.vtflgop to hold runtime terminal settings so that ; a reset command restores them to the Setup values, vtemu.vtflgst. Show ; displays the vtemu.vtflgop operational values. [jrd] ; 17 August 1987 Make timing adjustments for Token Passing and single buffered ; network adapter boards. Byte netdbfr indicates presence of double buffering; ; it is set in chknet as a vendor option. To test your boards force dbl buf ; then look for missing 256 byte parts of long packets sent out; missing parts ; mean new material overwrote not-yet-sent old == single buffering. [jrd] ; 8 August 1987 Add interrupt chaining in serint. [jrd] ; 23 July 1987 Clear xofsnt and xofrcv xon/xoff flags in ihost(s/r). [jrd] ; 9 July 1987 Cure confusion about COM1/2 for IBM PCjr (address of regular ; COM2 in 40:0h slot for COM1) with info from John Neufeld. [jrd] ; 2 July 1987 Route NetBios cancels through separate scb for systems, such ; as Novell NetWare, which object to having active scbs touched. [jrd] ; 25 June 1987 Add trapping of Int 14H (Bios RS232 procedure) to allow ; CTTY command to function without too much inteference from DOS. [jrd] ; 17 June 1987 Enlarge tab setting to full 132 columns at all times. [jrd] ; 11 June 1987 Add Set Term Roll on/off to control auto roll back of screen ; when new characters are displayed; default is off (no unwinding). [jrd] ; 20 May 1987 Remove rejection of NULL and DEL chars, let callers do it. [jrd] ; 16 May 1987 Add distinction between user typed and receiver threshold ; controlled sending of XOFF. User level overrides buffer control.[jrd] ; Add COM3 and COM4 support: examine memory 40:00h->40:07h for selected ; port COM1..4, resp. If word is null then set flags.comflg to 0 to say ; undefined port. Otherwise, use that word in seg 40h as base of UART i/o ; ports. Assume IRQ4 for COM1 and COM3 (same except for port addresses) ; and IRQ4 for COM2 and COM4 (again, same except for port addresses). ; Serial port info sturcture (not values) assumed identical for all ports. ; 25 April 1987 Add Netbios compatible local area network support. [jrd] ; Set Port command expanded to syntax SET PORT NET nodename. Use nodename ; if acting as a client to named remote node, leave blank if running in ; Server mode. Byte 'ttyact' is controlled by msster.asm to indicate Connect ; mode is being used. Byte 'netdone' (stored in mssker.asm) holds offset of ; network hangup procedure 'netclose' to be done when leaving Kermit. Hangup ; command extended to to network hangup as well. Network uses IBM Netbios ; standard calls (Int 5Ch) and allows for extensions of AT&T STARLAN for ; longer node names via Int 2Bh (the later is tested before use). Virtual ; circuits are employed. The Redirector is not necessary. Kermit can operate ; as either a terminal (does a CALL at Connect mode startup), a file receiver ; (does a CALL at startup), or a Kermit server (does an anonomous LISTEN at ; startup, hence no nodename). Clients should Set Timer Off. ; 16 April 1987 Add measurement and correction of software timer pcwait. [jrd] ; 5 April 1987 Keep DTR & RTS low for 1/2 second in serhng, suggested by ; Jack Bryans. [jrd] ; 28 March 1987 Reference screen coord wrt low_rgt from msyibm, let number ; of tabs be full screen width. [jrd] ; 22 March 1987 Fix bug in pcwait code, from Stefan Vogel. [jrd] ; 6 March 1987 Make PCWAIT a global procedure, add SENDBL to send Long ; Break. [jrd] ; 21 Feb 1987 Merge operations for semi-clone machines (those identical to ; IBM PC's except the serial port must be accessed via the Bios rather than ; from the real UART hardware). Ports automatically checked for 8250. [jrd] ; 1 Oct 1986 Version 2.29a ; 30 Sept 1986 Reject DEL char at serial port reception level to avoid ; problems when DEL is used as a filler char (by Emacs). [jrd] ; 4 Sept 1986 Add Bob Goeke's change to move comms port table to a system ; dependent module (typ msx---) to allow 3+ ports and localized idents. [jrd] ; 26 August 1986 Use parity mask when testing for nulls & Xon/Xoff in serial ; port interrupt routine. [jrd] ; 16 August 1986 Use observed screen attributes for mode line. [jrd] ; 9 August 1986 Revise SERINT to insert control-G for overrun chars, give ; faster return of interrupts to system, remove use of BP in code. [jrd] ; 17 July 1986 Minor clean up of Terminal Status display routine. [jrd] ; 22 June 1986 Leave 8250 UART signal OUT1 low to avoid resetting Hayes ; 1200B modems (thanks to Neil Rickert). [jrd] ; Skip sending null byte in ihosts and ihostr (thanks to Skip Russell). [jrd] ; 22 May 1986 Rewrite serial port interrupt procedure and proc prtchr ; to avoid lockups with interrupts disabled, buffer corruption, and to ; minimize lost clock interrupts. Flow control not needed at 9600 baud, ; slow screen refresh, VT102 emulation, on a 4.77 MHz IBM PC clone. ; Added buffer low water mark to give more xon/xoff hysterisis. [jrd] ; [2.29] code frozen on 6 May 1986 [jrd] ; Note - ; When the Bios is used for serial port i/o the modem signals DSR and CTS ; must be asserted low before the Bios will access the hardware. Jumpers ; from pin 20 (DTR) to pin 6 (DSR) and from pin 4 (RTS) to pin 5 (CTS) ; will probably be necessary. ; From Glenn Everhart (who suggested using the Bios alternative) ; public serini, serrst, clrbuf, outchr, coms, vts, vtstat public dodel, ctlu, cmblnk, locate, prtchr, dobaud, clearl public dodisk, getbaud, beep, termtb, shomodem public count, xofsnt, puthlp, putmod, clrmod, poscur public sendbr, sendbl, machnam, setktab, setkhlp, lclini, showkey public ihosts, ihostr, dtrlow, serhng, comptab, pcwait public perrcnt ; for debugging -- [jhw] include mssdef.h off equ 0 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 MCONF EQU 11H ; Bios Machine configuration s/ware interrupt. KEYB EQU 16H ; Bios keyboard software interrupt VIDEO EQU 10H ; Bios Video display software interrupt RS232 EQU 14H ; Bios RS232 serial port s/ware interrupt ; constants used by serial port handler MDMINP equ 1 ; BIOS data ready mask flag ; 8251A serial communications device BUF8251 EQU 028h ; I/O address of 8251 in/out buffer CMD8251 EQU 02Ah ; I/O address of 8251A command buffer STS8251 EQU 02Ah ; I/O address of 8251A status buffer VEC8251 EQU 0FAh ; 8251A interrupt vector number INT8251 EQU 0FBh ; 8259A interrupt enable mask (int 2) ; 8251A Command instruction formats TxEN EQU 1 ; transmit enable DTR EQU 2 ; data terminal ready RxEN EQU 4 ; receiver enable SBRK EQU 8 ; send break ERRESET EQU 10h ; error reset RTS EQU 20h ; request to send INTRLRS EQU 40h ; internal reset ; 8251A Status read formats TxRDY EQU 1 ; transmitter ready RxRDY EQU 2 ; receiver ready TxEMPTY EQU 4 ; transmit buffer empty PARERR EQU 8 ; parity error OVRRUN EQU 10h ; overrun error FRAMERR EQU 20h ; framing error BRKDET EQU 40h ; break detect DSR EQU 80h ; data set ready ; 8253 timer device TIMER0DATA EQU 20h ; I/O address of counter #0 TIMER1DATA EQU 22h ; I/O address of counter #1 TIMER2DATA EQU 24h ; I/O address of counter #2 CMD8253 EQU 26h ; I/O address of counter control ; 8259A interrupt controller CMA8259 EQU 0 ; I/O address of command buff 1 CMB8259 EQU 2 ; I/O address of command buff 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 (only port1) [rwb] ; port1 - portinfo structures for the port [rwb] ; low_rgt - low byte = last column (typ 79), high byte = last text row ; (typ 23) in screen coordinates (start at 0), set by msyibm. ; 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. datas segment public 'datas' extrn drives:byte, flags:byte, trans:byte, ttyact:byte extrn portval:word, port1:byte, port2:byte, port3:byte, port4:byte extrn netdone:word, pcnet:byte extrn refresh:byte, scbattr:byte, low_rgt:word, vtemu:byte extrn vtroll:byte, tekflg:byte extrn crt_mode:byte ; [jhw] ; 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 0 ; superceded by msuibm code, return 0 here setkhlp db '$' ; and add empty help string savsci dd ? ; old serial port interrupt vector. sav232 dd ? ; Original Bios Int 14H address, in Code seg. savirq db ? ; Original Interrupt mask for IRQ hngmsg db cr,lf,' The phone should have hungup.' db cr,lf,'$' nohngmsg db cr,lf,' Command ineffective on this port.',cr,lf,'$' 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.',cr,lf db '$' erms40 db cr,lf,'?Warning: Unrecognized baud rate',cr,lf,'$' badbd db cr,lf,'Unimplemented baud rate$' prterr db '?Unrecognized value$' msmsg1 db cr,lf,' Modem is not ready: DSR is off$' msmsg2 db cr,lf,' Modem is ready: DSR is on$' machnam db 'Sanyo 55x' ifdef MODIFIED db ' (Modifies BIOS keycodes)' endif db '$' crlf db cr,lf,'$' delstr db BS,BS,' ',BS,BS,'$' ; Delete string clrlin db cr,'$' ; Clear line (just the cr part). onmsg db 'on$' offmsg db 'off$' portin db 0 ; Has comm port been initialized xofsnt db 0 ; Say if we sent an XOFF. xofrcv db 0 ; Say if we received an XOFF. parmsk db ? ; parity mask, 0ffh for no parity, 07fh with. flowoff db ? ; flow-off char, Xoff or null (if no flow) flowon db ? ; flow-on char, Xon or null overrun db ? ; holds status of receiver overrun pcwcnt dw 240 ; number of loops for 1 millisec in pcwait temp dw 0 tempsci dw 0 ; temp storage for serint tempdum dw 0 ; temp storage for serdum rdbuf db 80 dup (?) ; temporary storage ; begin Terminal emulator data set termtb db tttypes ; entries for Status, not Set mkeyw 'Heath-19',ttheath mkeyw 'none',ttgenrc mkeyw 'Tek4010',tttek mkeyw 'VT102',ttvt100 mkeyw 'VT52',ttvt52 vttbl db 15 ; number of 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 'Rollback',400h ; note 400H flag for decoding mkeyw 'Screen-background',scrval mkeyw 'Tabstops',tabval mkeyw 'Tek4010',tttek+100H mkeyw 'VT102',ttvt100+100H mkeyw 'VT52',ttvt52+100H 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, VT102, or Tek4010',cr,lf db ' Newline-mode Cursor-style Character-set (US UK)',cr,lf db ' Keyclick Margin-bell Screen-background' db ' (normal, reverse)',cr,lf db ' Tabstops Wrap (long lines) Color (fore & background)' db cr,lf,' Roll (undo screen roll back before writing new chars,' db ' default=off)$' 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,' 2 for monochrome mode' db cr,lf,' 3 for color mode' 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: $' vtbell 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 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 2 ; Two entries. mkeyw 'off',0 ; Should be alphabetized mkeyw 'on',1 comptab db 2 mkeyw '1',1 mkeyw 'COM1',1 mkeyw ' ',0 ; port is not present, for Status ; this table is indexed by the baud rate definitions given in ; pcdefs. Unsupported baud rates should contain FF. ; Baud rates above 4800 may be sufficiently inaccurate to cause problems. [rwb] ; The 8251 must be run in 16x mode for reliable reception, which leads [rwb] ; to small divisors and large errors. The baud rate divisor is [rwb] ; calculated by 1,789,773 / (16 * baud rate). [rwb] ; Odd baud rates have not been tested [rwb] bddat label word dw 2458 ; 45.5 baud dw 2337 ; 50 baud dw 1491 ; 75 baud dw 1017 ; 110 baud dw 832 ; 134.5 baud dw 746 ; 150 baud dw 373 ; 300 baud dw 186 ; 600 baud ; actual baud rates in parentheses dw 93 ; 1200 baud (1202.8) dw 62 ; 1800 baud (1804.2) dw 56 ; 2000 baud (1997.5) dw 47 ; 2400 baud (2380.0) dw 23 ; 4800 baud (4863.5) dw 12 ; 9600 baud (9321.7) dw 6 ; 19200 baud (18643.5) dw 0FFh ; 38400 baud -- not supported, exceeds ; chip spec of 19.2K max dw 0FFh ; 56800 baud -- not supported dw 0FFh ; 113600 baud -- not supported baudlen equ ($-bddat)/2 ; number of entries above ; variables for serial interrupt handler source db bufsiz+2 DUP(?) ; Buffer for data from port (+ 2 guard bytes). srcpnt dw source ; Pointer in buffer (DI). count dw 0 ; Number of chars in int buffer. perrcnt dw 0 ; count - missed interrupts dur. protocol xfer datas ends code segment public 'code' extrn comnd:near, dopar:near, defkey: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 extrn prompt:near extrn vtsound:near ; [rwb] ifdef MODIFIED extrn rbtabl:near ; [jhw] endif assume cs:code,ds:datas ; local initialization lclini proc near mov flags.comflg,1 ; assume COM1 for communications port mov ax,8 ; set default 1200 baud [rwb] mov bp,portval ; [rwb] mov ds:[bp].baud,ax ; [rwb] call dobaud ; programm default baud rate [rwb] call model ; get model of IBM machine 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. ; following lines commented out because Sanyo [rwb] ; VB BIOS reports no disk drives present [rwb] ;; 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). dodsk0: mov drives,al ; Remember how many. ret DODISK ENDP model proc near ; no model info, just return [rwb] 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. ; Returns normally. Obsolete, name here for external reference only. showkey proc near ret ; return showkey endp ; SHOW MODEM, displays current status of DSR (CD and CTS are not known) shomodem proc near mov ah,cmcfm ; get a confirm call comnd jmp r ; no confirm nop call serini ; activate port to get status call serrst ; turn off port again mov ah,prstr in al,STS8251 ; get status test al,DSR ; is DSR asserted? jz shomd1 ; z = no mov dx,offset msmsg2 ; say not asserted shomd1: int dos jmp rskp shomodem 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 srcpnt,offset source ; receive circular buffer mov count,0 ; receive circular buffer sti call prtchr ; empty any intermediate (net) buffers nop ; got a char, clear again nop nop cli mov srcpnt,offset source ; receive circular buffer mov count,0 ; receive circular buffer 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 video ; Get current cursor position into dx mov ax,dx ; Topview compatible clear line mov bh,ah ; same row mov bl,byte ptr low_rgt ; last column call atsclr ; clear from ax to bx, screen coord pop dx pop bx pop ax ret CLEARL ENDP ; 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,low_rgt ; to end of text screen (lower right corner) inc bh ; include status line 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 ; 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 video 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 BEEP PROC NEAR push bx ; [rwb] push di ; [rwb] mov bx,3 ; [rwb] mov di,8 ; [rwb] call vtsound ; in msz55x [rwb] pop di ; [rwb] pop bx ; [rwb] ret BEEP 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 push bx push cx push dx ; preserve message mov bl,scbattr ; screen attributes at Kermit init time and bl,77h ; get colors, omit bright and blink rol bl,1 ; interchange fore and background rol bl,1 rol bl,1 rol bl,1 mov bh,0 ; preset page 0 mov temp,bx ; temp = page 0, reverse video mov dx,low_rgt ; ending location is lower right corner inc dh ; of status line mov cx,dx ; start is status left side xor cl,cl ; left side mov ax,600h ; scroll to clear the line mov bh,byte ptr temp ; set inverse video attributes int video mov dx,low_rgt ; last text line inc dh ; status line xor dl,dl ; left side call poscur pop si ; get message back mov cx,1 ; only one char at a time xor bh,bh ; page 0 cld 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,temp ; page 0, inverse video int video pop si ; recover pointer jmp putmo1 putmo2: pop cx pop bx pop ax ret putmod endp ; clear the mode line written by putmod. Returns normally. clrmod proc near push ax ; save regs push bx push cx push dx mov ax,600h ; do a scroll up mov dx,low_rgt ; ending location is lower right corner inc dh ; of status line mov cx,dx ; start is status left side xor cl,cl ; left side mov bh,scbattr ; use screen attributes at Kermit init time int video pop dx 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 push cx push dx push si push ax ; preserve this cld mov bl,scbattr ; screen attributes at Kermit init time and bl,77h ; get colors, omit bright and blink rol bl,1 ; interchange fore and background rol bl,1 rol bl,1 rol bl,1 mov bh,0 ; preset page 0 mov temp,bx ; temp = page 0, reverse video 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 mov bh,bl ; inverse video int video call locate ; home cursor mov bx,0070h ; bh = page 0, bl = inverse video mov bx,temp mov cx,1 ; one char at a time cld ; scan direction is forward 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 cmp al,' ' ; printable? jb puth21 ; b = no mov ah,9 ; write char at current cursor position int video ; 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 video pop si ; restore pointer jmp puthl3 ; and keep going puthl4: mov dh,byte ptr low_rgt+1 ; go to last line inc dh xor dl,dl call poscur ; position cursor pop si pop dx pop cx pop bx ret puthlp 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 bh,1H ; marker for terminal type? je vsetu0a ; e = yes cmp bh,4h ; marker for roll back control? je vsetu3 ; e = yes cmp bh,2h ; marker for set term color? je vsetu2 ; e = yes jmp short vsetu1 ; else dispatch on bl vsetu0a: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 mov tekflg,0 ; clear Tek sub mode ret vsetu0: pop bx ret vsetu3: mov ah,cmkey ; Set Term Roll On/Off, auto roll back mov bx,0 ; Use on/off table as help mov dx,offset ontab ; Use on/off table call comnd jmp r ; bad keyword push bx mov ah,cmcfm ; get a confirm call comnd jmp vsetu0 ; did not get a confirm nop pop bx mov vtroll,bl ; set roll state (0=no auto rollback) jmp rskp ; return successfully 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 jne vse2cd ; cond. jmps modified to correct ; 'out-of-range' errors [jhw] jmp vsetu2j ; e = yes vse2cd: cmp ax,1 ; high intensity? jne vse2cc jmp vsetu2k ; e = yes vse2cc: cmp ax,2 ; set to mono mode (Sanyo) [jhw] jne vse2ca ; [jhw] jmp vsetu2m ; e = yes [jhw] vse2ca: cmp ax,3 ; set to color mode (Sanyo) [jhw] jne vse2cb ; [jhw] jmp vsetu2m ; e = yes [jhw] vse2cb: cmp ax,10 ; fast refresh? cmp ax,1 ; high intensity? je vsetu2k ; e = yes cmp ax,10 ; fast refresh? je vsetu2l ; e = yes cmp ax,30 ; check range jb clbad ; b = too small. complain [jhw] cmp ax,37 jna vsetu2b ; 30-37 is foreground color cmp ax,40 jb clbad ; [jhw] cmp ax,47 ; Compare as unsigned. jna vsetu2b ; 40-47 is background clbad: jmp colbad ; else error [jhw] 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 vsetu2m: ; Set screen mode (color/mono) [jhw] mov crt_mode,al ; remember the mode [jhw] int video ; AX contained 2 or 3 already [jhw] jmp vsetu2c ; [jhw] ; colbad: cmp byte ptr [si],0 ; at end of text? je colbad1 ; e = yes, not an error mov ah,prstr ; Not in range - complain and exit. mov dx,offset colerr int dos colbad1: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. or vtemu.vtflgop,al ; in runtime flags too jmp rskp ; Give good return. flgse1: not al ; Complement and vtemu.vtflgst,al ; Clear the indicated setup flag. and vtemu.vtflgop,al ; Clear the indicated runtime 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,132 ; 132 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,132 ; use 132 columns 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 jmp tabcpy ; no number available 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 bl,132-1 ; more than the right most column? jna tabse3 ; na = no, is ok 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 short tabse5 ; look for more tabcpy: mov cx,132 ; update all active 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 short 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,38 ; 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 short vtsta4 vtsta2: mov ax,cx mov cx,38 ; where we want to be next time 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,38 ; current column number vtsta4: add bx,size stent ; look at next entry jmp vtsta1 ; and do it vtstax: pop di pop bx 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 cl,byte ptr low_rgt ; loop screen width-1 times xor ch,ch ; clear high byte 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' cmp dl,'9' ; larger than 90? jbe tabsta2 ; be = no sub dl,10 ; roll over to 0, 1, etc 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,38 ; say line is used 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.vtflgop ; 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 ; Compute number of iterations needed in procedure pcwait inner loop ; to do one millisecond delay increments. Uses Intel 8253 timer chip ; (timer #2) to measure elapsed time assuming 1.78977 MHz clock. ; Called by serini below. For Sanyo 55x this is the baud rate generator, ; so call dobaud to reset the baud rate. ; Regs preserved. 16 April 87 [jrd] pcwtst proc near push ax push cx push dx ; 10 = timer 2, 11 = load low byte then high byte, 010 = mode 2, 0 = binary mov al,10110100B ; command byte out CMD8253,al ; timer command port xor al,al ; clear initial count for count-down out TIMER2DATA,al ; low order byte of count preset out TIMER2DATA,al ; high order byte, to the same place mov ax,8 ; wait 8 millisec call pcwait ; call the software timer ; 10 = timer 2, 00 = latching command, 0000 = don't cares mov al,10000000B ; command byte out CMD8253,al in al,timer2data ; read count down value xchg al,ah ; save low order byte in al,timer2data ; get high order byte xchg ah,al ; put in correct sequence neg ax ; subtract from zero to get elapsed tics add ax,1789-2 ; round up xor dx,dx ; clear high order divisor mov cx,1789 ; tics per millisec div cx ; count / 1193 yields millisecs, quo=ax push ax ; retain whole number of milliseconds mov ax,pcwcnt ; get current pcwait inner loop count mov cl,3 shl ax,cl ; current counter times 8 loops pop cx ; recover millisec for the 8 loop test xor dx,dx ; clear high order field for division div cx ; divide by observed milliseconds mov pcwcnt,ax ; store quotient as new inner loop counter call dobaud ; fix the baud rate we messed up pop dx pop cx pop ax ret pcwtst endp ;; Wait for the # of milliseconds in ax, for non-IBM compatibles. ;; Thanks to Bernie Eiben for this one. Modified to use adjustable ; inner loop counter (pcwcnt, adjusted by proc pcwtst) by [jrd]. pcwait proc near mov cx,pcwcnt ; inner loop counter for 1 ms (240 @ 4.77 MHz) 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 ; set the current port (only port 1 available on Sanyo) COMS PROC NEAR mov portval,offset port1 clc ; return success ret COMS ENDP ; Test presently selected serial port for having a real 8250 UART. ; Return carry clear and clone = 0 if 8250 present, ; else carry set and clone = 'B' for system Bios or ; carry set and clone = 'N' for network. ; Method is to check UART's Interrupt Identification Register for high ; five bits being zero; IBM does it this way. Assumes port structure ; has been initialized with addresses of UART. 21 Feb 1987 [jrd] ; 29 May 1987 Add double check by reading Line Status Register. [jrd] chkport proc near clc ; clear carry (say 8250) ret chkport 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 push bx push dx mov bx,portval ; pointer to port data structure mov temp,ax ; Don't overwrite previous rate mov ax,[bx].baud ; Check if new rate is valid shl ax,1 ; make a word index mov bx,offset bddat ; Start of table. dobd0a: add bx,ax mov ax,[bx] ; The data to output to port. cmp ax,0FFH ; Unimplemented baud rate. jne dobd2 mov ah,prstr mov dx,offset badbd ; Give an error message. int dos jmp dobd1 dobd2: mov temp,ax ; Remember value to output. [25] out TIMER2DATA,al ; [rwb] mov al,ah ; [rwb] out TIMER2DATA,al ; [rwb] dobd1: pop dx ; restore regs 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. Returns normally. ; This is used during initialization. ; This function is not possible with the Sanyo hardware, so just return. [rwb] GETBAUD PROC NEAR ret GETBAUD ENDP ; Get Char from serial port buffer. ; skip returns if no character available at port, ; otherwise returns with char in al, # of chars in buffer in dx. ; Revised 22 May 1986, and again slightly 2 August 1986 by [jrd] ; 21 Feb 1987 Add support for Bios calls (Clone) [jrd] ; 25 April 1987 Add Netbios support, remove test for NUL and DEL. [jrd] PRTCHR PROC NEAR call chkxon ; see if we need to xon ifdef DEBUG jmp prtc00 ; dummy jump to be changed by debug prtc00: endif in al,cmd8251 ; get port status test al,rxrdy ; is character in 8251? jz prtc01 ; no, go on cli ; yes, hold interrupts and int 0fah ; call the interrupt service routine sti ; re-enable interrupts inc perrcnt ; count the errors prtc01: cmp count,0 ; any characters available? jnz prtch1 ; nz = yes, get one prtch0: mov dx,0 ; return count of zero jmp rskp ; No data - check console. prtch1: push si ; save si cli ; interrupts off, to keep srcpnt & count consistent mov si,srcpnt ; address of next available slot in buffer sub si,count ; minus number of unread chars in buffer cmp si,offset source ; located before start of buf? jae prtch2 ; ae = no add si,bufsiz ; else do arithmetic modulo bufsiz prtch2: mov al,byte ptr [si] ; get a character into al dec count ; one less unread char now sti ; interrupts back on now. pop si mov dx,count ; return # of chars in buffer ret PRTCHR 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. ; 21 Feb 1987 Add support for Bios calls (Clone) [jrd] ; 25 April 1987 Add Netbios support [jrd] ; 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] 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 outch1b outch1: cmp ah,flowon ; user sending xon? jne outch1b ; ne = no mov xofsnt,off ; say an xon has been sent (cancels xoff) outch1b:cmp xofrcv,off ; Are we being held (xoff received)? je outch2 ; e = no - it's OK to go on. cmp flags.timflg,0 ; is timer off? je outch2 ; e = yes, no timeout period push cx ; save reg mov cl,trans.rtime ; receive timeout interval mov ch,0 jcxz outch1c ; z = no timeout wanted. outch1a:cmp xofrcv,off ; Are we being held (xoff received)? je outch1c ; e = no - it's OK to go on. mov al,1 ; else sleep for a second call sleep loop outch1a ; and try it again mov xofrcv,off ; timed out, force it off and fall thru outch1c:pop cx ; end of flow control section ; OUTCH2 is entry point for sending without flow control OUTCH2: mov al,ah ; Parity routine works on AL. call dopar ; Set parity appropriately. mov ah,al ; Don't overwrite character with status outch3a:push cx ; Save registers push dx sub cx,cx outch3b: in al,STS8251 ; get status [rwb] test al,TxEMPTY ; Transmitter ready? [rwb] jnz outch4 ; Yes jmp $+2 ; use time, prevent overdriving UART jmp $+2 loop outch3b jmp outch5 ; Timeout outch4: cli ; can't tolerate receiver ints here mov al,(TxEN+DTR+RxEN+ERRESET+RTS) ; enable transmit [rwb] out CMD8251,al ; [rwb] jmp $+2 ; waste some time [rwb] mov al,ah ; Now send it out [rwb] out BUF8251,al ; [rwb] jmp $+2 ; waste some time [rwb] mov al,(DTR+RxEN+ERRESET+RTS) ; back to receive-only mode [rwb] out CMD8251,al ; [rwb] sti pop dx ; exit success pop cx jmp rskp outch5: pop dx ; exit failure pop cx ret OUTCHR ENDP hexout proc near ; display byte in al as hex value push ax ; all regs preserved push cx push dx mov cx,2 ; two nibbles hexout1:push cx ; save counter mov cl,4 ; high nibble ror al,cl ; put in low order field mov dl,al xchg ch,al ; save al byte in ch and dl,0fh ; four bits cmp dl,9 ; too big? jbe hexout2 ; be = no add dl,'A'-'9'-1 ; bump up to A-F hexout2:add dl,'0' mov ah,conout int dos xchg ch,al ; recover data byte pop cx loop hexout1 ; do second nibble mov dl,'H' ; add a final hex ident int dos pop ax pop cx pop dx ret hexout endp ; local routine to see if we have to transmit an xon chkxon proc near cmp flowon,0 ; 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 (low water mark) trigger? jae chkxo1 ; no, forget it mov ah,flowon ; ah gets xon and xofsnt,off ; remember we've sent the xon. call outch2 ; send via non-flow controlled entry point nop nop nop ; in case it skips chkxo1: ret 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] ; 22 June 1986 Don't send null char if not using flow control. [jrd] 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,flowon ; put Go-ahead flow control char in ah or ah,ah ; check for null char jz ihosts1 ; z = null, don't send it. 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 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] ; 22 June 1986 Don't send null char if not using flow control. [jrd] IHOSTR PROC NEAR push ax ; save regs push cx mov xofrcv,off ; clear old xoff received flag mov xofsnt,off ; and old xoff sent flag mov ah,flowon ; 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) nop ; outchr can do skip return nop nop ihostr1:pop cx pop ax ret IHOSTR ENDP ; Send a break out the current serial port. Returns normally. ; Do both regular and long Break. 6 March 1987 [jrd] SENDBR PROC NEAR push cx ; Regular Break entry point mov cx,275 ; 275 milliseconds in regular Break call sendbw ; call worker routine to do it pop cx clc ; don't exit Connect mode ret SENDBL: push cx ; Long Break entry point mov cx,1800 ; 1.8 second long break call sendbw ; call worker routine to do it pop cx clc ; don't exit Connect mode ret ; worker - send Break for cx millisec sendbw: push ax mov al,(TxEN+DTR+RxEN+RTS) ; [rwb] out CMD8251,al ; [rwb] mov al,(TxEN+DTR+RxEN+SBRK+RTS) ; [rwb] out CMD8251,al ; [rwb] mov ax,cx ; # of ms to wait call pcwait ; hold break for desired interval mov al,(TxEN+DTR+RxEN+RTS) ; [rwb] out CMD8251,al ; [rwb] mov al,(DTR+RxEN+ERRESET+RTS) ; [rwb] out CMD8251,al ; [rwb] pop ax ret SENDBR 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. ; ; 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. ; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd] ; 21 Feb 1987 Add support for Bios calls (Clone) [jrd] ; 24 April 1987 Add PCnet support calls [jrd] ; 17 May 1987 Redo for COM3/4 support. [jrd] SERINI PROC NEAR cmp portin,0 ; Did we initialize port already? je serin0 ; e = no, not yet ret ; Yes, so just leave serin0: call pcwtst ; calibrate timer (only on first call) serin2a:push bx push es mov al,VEC8251 ; serial interrupt vector mov ah,35H ; Int 21H, function 35H = Get Vector. int dos ; get vector in es:bx mov word ptr savsci,bx ; save offset address of original vector mov word ptr savsci+2,es ; and its segment. mov al,VEC8251 ; serial interrupt vector mov dx,offset serint ; offset of our interrupt routine push ds ; save ds around next DOS call. mov bx,seg serint ; compose full address of our routine. mov ds,bx ; segment is the code segment. mov ah,25H ; set interrupt address from ds:dx int dos pop ds mov al,rs232 ; interrupt number for Bios serial port mov ah,35H ; get vector into es:bx int dos mov word ptr sav232,bx ; save offset mov word ptr sav232+2,es ; save segment mov dx,offset serdum ; offset of our interrupt routine push ds ; save ds around next DOS call. mov bx,seg serdum ; compose full address of our routine. mov ds,bx ; segment is the code segment. mov ah,25H ; set interrupt address from ds:dx int dos pop ds pop es pop bx mov portin,1 ; Remember port has been initialized. cli ; Disable interrupts cld ; Do increments in string operations mov al,INTRLRS ; 8251 reset command [rwb] out CMD8251,al ; [rwb] jmp $+2 ; waste some time [rwb] mov al,04Eh ; 8-bit, no parity, 1 stop, 16x clock [rwb] out CMD8251,al ; [rwb] jmp $+2 ; waste time again [rwb] mov al,(DTR+RxEN+ERRESET+RTS) ; enable receive [rwb] out CMD8251,al ; [rwb] in al,CMB8259 ; get interrupt mask [rwb] and al,INT8251 ; enable RS-232 interrupt [rwb] out CMB8259,al ; [rwb] sti ; Allow interrupts (AFTER next instr) serin4: push bx mov bx,portval ; get port mov parmsk,0ffh ; parity mask, assume parity is None. cmp [bx].parflg,parnon ; is it None? je serin1 ; e = yes mov parmsk,07fh ; no, pass lower 7 bits as data serin1: mov bx,[bx].flowc ; get flow control chars mov flowoff,bl ; xoff or null mov flowon,bh ; xon or null mov xofrcv,off ; clear xoff received flag pop bx mov portin,1 ; say initialized ret ; We're done 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. ; 22 June 1986 Leave OUT1 low to avoid resetting Hayes 1200B's. [jrd] ; 21 Feb 1987 Add support for Bios calls (Clone) [jrd] ; 17 May 1987 Redo for COM3/4 support [jrd] SERRST PROC NEAR cmp portin,0 ; Reset already? je srst1 ; Yes, just leave. cli ; Disable interrupts ; Leave receive and transmit enabled (that's how DOS sets them initially) [rwb] ; Also leave interrupt enabled, DOS will handle any interrupts mov al,(DTR+RxEN+TxEN+ERRESET+RTS) ; enable transmit and receive [rwb] out CMD8251,al ; [rwb] sti ; replace original IRQ interrupt vector push bx mov al,VEC8251 ; Restore the serial card int vector mov dx,word ptr savsci ; offset part push ds mov bx,word ptr savsci+2 ; segment part mov ds,bx ; ds:dx has interrupt vector mov ah,25H ; set interrupt vector int dos ; replaced. pop ds mov al,rs232 ; Bios serial port interrupt vector to restore mov dx,word ptr sav232 ; offset part push ds mov bx,word ptr sav232+2 ; segment part mov ds,bx mov ah,25h ; set interrupt vector int dos pop ds pop bx srst3: mov portin,0 ; Reset flag. srst1: ifdef MODIFIED call rbtabl ; make sure BIOS key translation table ptr is ; reset upon exit. Didn't know where else to ; put this in the machine dependent code [jhw] endif ret ; All done. SERRST ENDP ; Dummy Interrupt 14H to defeat DOS interference with serial port when CTTY ; and Kermit use the port simultaneously. If ports differ then chain DOS to ; original Int 14H Bios code. Else return dummy status=ok reports and ; Backspace for Read, ignore char for Write. ; Entered with AH = function request, AL = char to be sent, DX = com port num ; CS is our code segment, DS is DOS's, SS is ours or DOS's, interrupts off. ; 25 June 1987 [jrd] SERDUM PROC FAR push ds ; preserve all registers. push ax mov ax,seg datas ; get our data segment mov ds,ax pop ax ; recover request parameters pop ds cmp ah,0 ; initialization request? je serdu3 ; e = yes, return dummy status=ok rpt cmp ah,1 ; send char in al? jne serdu2 ; ne = no mov ah,60h ; yes, set line status=ok in ah iret serdu2: cmp ah,2 ; receive char (and wait for it)? jne serdu3 ; ne = no, return dummy report mov al,bs ; yes, return ascii BS to DOS mov ah,0 ; ah = errors (none here) iret serdu3: mov ax,60b0h ; dummy status report:xmtr empty, CD, iret ; DSR, and CTS are on. SERDUM ENDP ; serial port interrupt routine. This is not accessible outside this ; module, handles serial port receiver interrupts. ; Revised on 22 May 1986, again 2 August 1986 to run at 38.4kb on PC's. [jrd] ; Srcpnt holds offset, within buffer Source, where next rcv'd char goes. ; Count is number of chars now in buffer, and oldest char is srcpnt-count ; done modulo size of Source. All pointer management is handled here. ; Control-G char substituted for char(s) lost in overrun condition. [jrd] ; Upgraded to read cause of interrupt from interrupt ident reg (accepts only ; data ready), chain to old interrupt if source is not our device. [jrd] SERINT PROC FAR push ax ; save registers push dx ; push ds mov ax,seg datas mov ds,ax ; address data segment ; IBM version sends EOI command to 8259 interrupt controller at this [rwb] ; point, but Sanyo normally runs in auto EOI mode, so no EOI is needed [rwb] in al,STS8251 ; [rwb] test al,RxRDY ; Data available? [rwb] jnz srint0a ; nz = yes srint0: sti ; else turn on interrupts jmp retint ; and exit now (common jump point) srint0a:and al,OVRRUN ; select overrun bit [rwb] mov overrun,al ; save it for later in al,BUF8251 ; [rwb] cmp flowoff,0 ; flow control active? je srint2 ; e = no mov ah,al ; ah = working copy. Check null, flow cntl. and ah,parmsk ; strip parity temporarily, if any. jz srint2 ; if null skip flow control cmp ah,flowoff ; acting on Xoff? jne srint1 ; ne = Nope, go on. mov xofrcv,bufon ; Set the flag saying XOFF received. jmp srint0 ; and exit srint1: cmp ah,flowon ; acting on Xon? jne srint2 ; ne = no, go on. mov xofrcv,off ; Clear the XOFF received flag. jmp srint0 ; and exit srint2: push bx ; save register mov ah,overrun ; get overrun flag or ah,ah ; overrun? jz srint2a ; z = no mov ah,al ; yes, save present char mov al,(DTR+RxEN+ERRESET+RTS) ; [rwb] out CMD8251,al ; clear overrun status in 8251 [rwb] mov al,bell ; insert control-G for missing char srint2a:mov bx,srcpnt ; address of buffer storage slot mov byte ptr [bx],al ; store the new char in buffer "source" inc srcpnt ; point to next slot inc bx cmp bx,offset source + bufsiz ; beyond end of buffer? jb srint3 ; b = not past end mov srcpnt,offset source ; wrap buffer around srint3: cmp count,bufsiz ; filled already? jae srint4 ; ae = yes inc count ; no, add a char srint4: or ah,ah ; anything in overrun storage? jz srint4a ; z = no mov al,ah ; recover any recent char from overrun xor ah,ah ; clear overrun storage jmp srint2a ; yes, go store real second char srint4a:pop bx ; restore reg sti ; ok to allow interrupts now, not before cmp count,mntrgh ; past the high trigger point? jbe retint ; be = no, we're within our limit test xofsnt,bufon ; Has an XOFF been sent by buffer control? jnz retint ; nz = Yes. mov al,flowoff ; get the flow off char (Xoff or null) or al,al ; don't send nul chars jz retint ; z = null, nothing to send call dopar ; Set parity appropriately. mov ah,al ; Don't overwrite character with status push cx ; save reg xor cx,cx ; loop counter srint5: in al,STS8251 ; Get port status. [rwb] test al,TxEMPTY ; Transmitter ready? jnz srint6 ; nz = yes jmp $+2 ; use time, prevent overdriving UART loop srint5 ; else wait loop, cx times jmp srint7 ; Timeout srint6: cli mov al,(TxEN+DTR+RxEN+ERRESET+RTS) ; enable output command [rwb] out CMD8251,al ; [rwb] mov al,ah ; Now send out the flow control char out BUF8251,al push cx ; save reg [jrd] xor cx,cx ; loop counter [jrd] srint6a: in al,STS8251 ; Get port status. [rwb] test al,TxEMPTY ; Transmitter done? jnz srint6b ; nz = yes jmp $+2 ; use time, prevent overdriving UART loop srint6a ; else wait loop, cx times ; on timeout, kill transmitter srint6b: mov al,(DTR+RxEN+ERRESET+RTS) ; command to enable only receive [rwb] out CMD8251,al pop cx sti ; Enable interrupts after next instruct. [jrd] mov xofsnt,bufon ; Remember we sent an XOFF at buffer level srint7: pop cx ; restore reg retint: pop ds pop dx pop ax iret SERINT ENDP DTRLOW PROC NEAR ; Global proc to Hangup the Phone or Network ; by making DTR and RTS low (phone). [jrd] mov ah,cmtxt ; 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 jmp r call serhng ; drop DTR and RTS mov ah,prstr ; give a nice message mov dx,offset hngmsg int dos 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] ; 5 April 1987 Add 500 millisec wait with lines low before returning. [jrd] ; Calling this twice without intervening calls to serini should be harmless. ; If network then call nethangup procedure to hangup the session without ; losing local name information. ; Returns normally. serhng proc near ; clear modem's delta status bits and lower DTR & RTS shng1: cli ; Disable interrupts push ax mov al,(RxEN+ERRESET) ; DTR and RTS low [rwb] out CMD8251,al ; [rwb] shngx: sti ; Enable interrupts mov ax,500 ; 500 millisec, for pcwait call pcwait ; keep lines low for at least 500 millisec pop ax ret serhng 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 code ends end