home *** CD-ROM | disk | FTP | other *** search
/ Between Heaven & Hell 2 / BetweenHeavenHell.cdr / 300 / 257 / msxapc.asm < prev    next >
Assembly Source File  |  1984-12-18  |  46KB  |  1,602 lines

  1. ; ************ START MSXAPC.ASM ***********************************
  2.  
  3. ; Kermit system dependent module for NEC Advanced Personal Computer (APC)
  4. ; Ron Blanford, University of Washington, August 1984
  5.  
  6. ; Modified to get key scan codes directly from fifo buffer in IO.SYS
  7. ; This version works with MS-DOS Versions 2.00 (000) and 2.11 (001); it 
  8. ; should work with future MS-DOS revisions so long as NECIS maintains
  9. ; the configuration table in IO.SYS -  the thing most apt to fail is the 
  10. ; key autorepeat because kbrepflg is furthest from a hook in config table.
  11. ; If this happens the equate for offset of kbrepflg will need adjusting. 
  12. ; Ian Gibbons, University of Hawaii, 10/26/84
  13.  
  14. ; Fixed incorrect timer command port assignment so that program will run
  15. ;   under MS-DOS 2.00 as well as 2.11.
  16. ; Added autodetermination of color/mono using crttype byte in IO.SYS; this
  17. ;   works only under DOS 2.11 (and future above ?)
  18. ; IG 10/28/84
  19. ; Added direct CRT I/O handling through BIOS in order to increase speed and
  20. ;  flexibility of help menus. It gives only an imitation window but it works
  21. ;  fairly well.
  22. ; IG 10/31/84
  23. ; Added simplified mode line data to the [Connecting to host...]" line which
  24. ;  has been moved here from MSTERM in order to have more system dependent 
  25. ;  control.
  26. ; IG 11/4/84
  27. ; Make unredefined break/stop key act as a scroll/noscroll key in telnet by
  28. ;  sending alternately a ^S and a ^Q.
  29. ; IG 11/5/84
  30. ; By now code for this MSXAPC module could well be divided into separate
  31. ;  transmission and terminal modules, but I don't want to spend more time
  32. ;  on it. It's not as readable as it might be, but so far as I know
  33. ;  everything works.IG 11/6/84
  34.  
  35.     public    serini, serrst, clrbuf, outchr, coms, vts, dodel,
  36.     public    ctlu, cmblnk, locate, lclini, lclrst, prtchr, dobaud,
  37.     public    discon, clearl, dodisk, getbaud, beep,
  38.     public    count, xofsnt, puthlp, putmod, clrmod, poscur
  39.     public    sendbr, term, machnam, setktab, setkhlp, showkey
  40.     include msdefs.h
  41.  
  42. false    equ    0
  43. true    equ    1
  44.  
  45. BIOS    EQU    0DCH        ; NEC-APC BIOS interrupt call
  46. fifoclr equ    6        ; clears keyboard fifo buffer
  47. crtcmd    equ    7        ; Direct CRT I/O command call
  48.  
  49. ; port assignments for 8251 serial controllers
  50.  
  51. ;        Standard interface
  52.  
  53. mndata    equ    30H        ; Data port (read/write)
  54. mnst1a    equ    32H        ; Status port (when read)
  55. mncmda    equ    32H        ; Command port (when written)
  56. mnst2a    equ    34H        ; Alternate status port (when read)
  57. mnmska    equ    34H        ; Mask port (when written)
  58. mntdca    equ    36H        ; Transmit disable port (write only)
  59.  
  60. ;        Optional (H14) interface
  61.  
  62. mndatb    equ    31H        ; Data port (read/write)
  63. mnst1b    equ    33H        ; Status port (when read)
  64. mncmdb    equ    33H        ; Command port (when written)
  65. mnst2b    equ    35H        ; Alternate status port (when read)
  66. mnmskb    equ    35H        ; Mask port (when written)
  67. mntdcb    equ    37H        ; Transmit disable port (write only)
  68.  
  69. ; Status bits from mnst1
  70.  
  71. txrdy    equ    01H        ; Bit for output ready.
  72. rxrdy    equ    02H        ; Bit for input ready.
  73.  
  74. ; Command values for mncmd
  75.  
  76. ccmd    equ    37H        ; RTS & DTR high, RX & TX enabled, reset ERR
  77. cbrk    equ    08H        ; break enabled
  78. cmode    equ    40H        ; enable mode reset
  79. mmode    equ    4EH        ; 16x rate, 8 data, no parity, 1 stop
  80.  
  81. ; Mask values for mnmsk
  82.  
  83. txmsk    equ    01H        ; disables transmit ready interrupt
  84. rxmsk    equ    02H        ; disables receive ready interrupt
  85. tbemsk    equ    04H        ; disables transmit buffer empty interrupt
  86.  
  87.  
  88. ; port assignments for 8253 timers
  89.  
  90. ;        Standard interface
  91.  
  92. tmdata    equ    2BH        ; data port
  93. tmcmda    equ    2FH        ; command port  (Was 27H Ian 10/27/84) 
  94.  
  95. ;        Optional (H14) interface
  96.  
  97. tmdatb    equ    61H        ; data port
  98. tmcmdb    equ    67H        ; command port
  99.  
  100. ; values for tmcmd which select timer channel and mode
  101.  
  102. tmsela    equ    76H        ; Channel 1, mode 3 (standard port)
  103. tmselb    equ    36H        ; Channel 0, mode 3 (optional port)
  104.  
  105. ; Timer information for current port selection
  106.  
  107. tmrinfo    struc
  108. tmdat    dw    0        ; data port
  109. tmcmd    dw    0        ; command port
  110. tmsel    db    0        ; byte which selects channel and mode
  111. tmrinfo    ends
  112.  
  113.  
  114. ; port assignments for 8259 interrupt controllers
  115.  
  116. ;        Standard interface
  117.  
  118. intcmda    equ    20H        ; Command port (master controller)
  119. intmska    equ    22H        ; Mask port
  120. ictmsk    equ    08H        ; Timer interrupt mask (to master)
  121. icsmska    equ    02H        ; Standard serial interrupt mask (to master)
  122. icsvcta equ    11H        ; Interrupt vector for standard interface
  123.  
  124. ;        Optional (H14) interface
  125.  
  126. ; The interrupt request vector for the optional (H14) serial interface is
  127. ; jumper-selectable to any of vectors IR2, IR5, IR8, or IR12.  NEC recommends
  128. ; that IR8 be used, so that has been selected as the default here.  To use
  129. ; any of the other vectors, set the following conditionals appropriately.
  130. ; Only one of the following should be true:
  131.  
  132. IR2    equ    false        ; interrupt vector 2
  133. IR5    equ    false        ; interrupt vector 5
  134. IR8    equ    true        ; interrupt vector 8
  135. IR12    equ    false        ; interrupt vector 12
  136.  
  137.     IF IR2
  138. intcmdb equ    20H        ; Command port (master controller)
  139. intmskb equ    22H        ; Mask port
  140. icsmskb equ    04H        ; Interrupt mask
  141. icsvctb equ    12H        ; Interrupt table index
  142.     ENDIF
  143.  
  144.     IF IR5
  145. intcmdb equ    20H        ; Command port (master controller)
  146. intmskb equ    22H        ; Mask port
  147. icsmskb equ    20H        ; Interrupt mask
  148. icsvctb equ    15H        ; Interrupt table index
  149.     ENDIF
  150.  
  151.     IF IR8
  152. intcmdb equ    28H        ; Command port (slave controller)
  153. intmskb equ    2AH        ; Mask port
  154. icsmskb equ    02H        ; Interrupt mask
  155. icsvctb equ    19H        ; Interrupt table index
  156.     ENDIF
  157.  
  158.     IF IR12
  159. intcmdb equ    28H        ; Command port (slave controller)
  160. intmskb equ    2AH        ; Mask port
  161. icsmskb equ    20H        ; Interrupt mask
  162. icsvctb equ    1DH        ; Interrupt table index
  163.     ENDIF
  164.  
  165. crtinfo struc        ; Structure for color/mono formatting info
  166. nrmseq    db    esc,'[0m$'    ; Default
  167. invseq    db    esc,'[7m$000'    ; Inverse (extra space for color)
  168. bldseq    db    esc,'[17m$'    ; Bold video
  169. nrmcrt    dw    8080H        ; Normal data for direct crt i/o
  170. bldcrt    dw    9090H        ; Inverse data for direct crt i/o    
  171.  
  172. crtinfo ends
  173.  
  174.  
  175. icEOI    equ    20H        ; generic end of interrupt for intcmd
  176. kbfifosiz equ    64        ; size of fifo buffer in IO.SYS
  177.  
  178.  
  179. ; miscellaneous constants
  180.  
  181. ctrlP    equ    10H        ; ^P.
  182. ctrl_q    equ    11H        ; ^Q
  183. ctrl_s    equ    13H        ; ^S
  184. printkey equ    00FFH        ; Scan code of unshifted PRINT key.
  185. brkstp    equ    0096H        ; Scan code of unshifted break/stop key.
  186. mntrgh    equ    bufsiz*3/4    ; High XON/XOFF trigger = 3/4 of buffer full.
  187.  
  188. ; external variables used:
  189. ; drives - # of disk drives on system
  190. ; flags - global flags as per flginfo structure defined in pcdefs
  191. ; trans - global transmission parameters, trinfo struct defined in pcdefs
  192. ; portval - pointer to current portinfo structure (currently either port1
  193. ;    or port2)
  194. ; port1, port2 - portinfo structures for the corresponding ports
  195.  
  196. ; global variables defined in this module:
  197. ; xofsnt, xofrcv - tell whether we saw or sent an xoff.
  198.  
  199. datas     segment    public 'datas'
  200.     extrn    drives:byte,flags:byte, trans:byte
  201.     extrn    portval:word, port1:byte, port2:byte
  202.  
  203. machnam    db    'NEC APC$'
  204. nyimsg    db    cr,lf,'Not implemented$'
  205. badbd    db    cr,lf,'Unimplemented baud rate$'
  206. bdkscn    db    cr,lf,'Unable to install key translate table'
  207.     db    cr,lf,'Possibly incompatible MS-DOS version',cr,lf
  208.     db    cr,lf,'(MS-KERMIT can be used without keyboard translation'
  209.     db    ' feature)',cr,lf,'$'
  210. nokbtr    db    cr,lf,'No key translation table is installed$'
  211. prtmsg    db    cr,lf,'You cannot redefine the PRINT key$'
  212. escmsg    db    cr,lf,'You cannot redefine the current CTRL-ESCAPE key$'
  213. hngcfm    db    cr,lf,'Please confirm DISCONNECT command. (Y/N)  $'
  214. dismsg    db    cr,lf,'Disconnecting for 3 seconds',cr,lf,'$'
  215. rcnmsg    db    cr,lf,'Reconnected',cr,lf,'$'
  216. cnmsg    db    cr,lf,'Connecting to host at '
  217. cnmsgb    db    '     '
  218.     db    ' baud on port '
  219. cnmsgp    db    ' ',cr,lf,'(Type $'
  220. cnmsg1    db    ' C  to return to PC)',cr,lf,lf,lf,'$'
  221. crlf    db    cr,lf,'$'
  222. delstr  db      BS,' ',BS,'$'    ; Delete string.
  223. clrlin  db      cr,'$'        ; Clear line (just the cr part).
  224. ceolseq    db    esc,'[K$'    ; Clear to end of line
  225. cpseq    db    esc,'=rc'    ; rc replaced by row and column before display
  226. clrseq    db    01EH,01AH,'$'    ; Home cursor and clear screen
  227. lstpos    dw    0        ; column position for printer echoing
  228.  
  229. ; Storage for color and mono formatting strings
  230.  
  231. nrmcol    db    esc,'[0m$'
  232. invcol    db    esc,'[3;21m$'    ; Yellow with green overline
  233. bldcol    db    esc,'[21m$'    ; Yellow
  234. ncrtcol    dw    8080H        ; Green
  235. bcrtcol dw    0A0A0H        ; Yellow  
  236.  
  237. ;nrmmon    db    esc,'[0m$'
  238. ;invmon    db    esc,'[7m$000'    ; Inverse video
  239. ;bldmon    db    esc,'[17m$'    ; Bold video
  240. ;ncrtmon    dw    8080H        ; Normal green
  241. ;bcrtmon dw    9090H        ; Inverse video    
  242.  
  243. formdat    crtinfo <>
  244. formdtl    db    $-formdat
  245.  
  246. nocur    db    esc,'[>5h$'    ; Disable cursor
  247. recur    db    esc,'[>5l$'    ; Reenable cursor
  248. storcur    db    esc,'[s$'    ; Store cursor position
  249. rstcur    db    esc,'[u$'    ; Restore cursor position
  250. upcur    db    esc,'[A$'    ; Move cursor up one line
  251. savcur    dw    0         ; storage for cursor position
  252. msglns    db    0        ; No of lines in help message
  253. rnoc    dw    0        ; Raw NOC for screen write
  254.  
  255. ; Data area for direct CRT I/O
  256.  
  257. EVEN                ; Force alignment to word boundary
  258. dispadr db    2000 dup (0)    ; Storage for string data
  259. attradr db    2000 dup (0)    ; Storage for attribute data 
  260.  
  261. ; Command block for direct CRT I/O
  262.  
  263. cmd    db    0        ; CRT command number
  264. la    db    0        ; Line address   (0-24 binary)
  265. ca    db    0        ; Column address (0-79 binary)
  266. noc    dw    0        ; Number of chars (0-2000 binary)
  267. dispptr dw    dispadr        ; Pointer to string data block
  268. dispseg    dw    datas        ;
  269. attrptr dw    attradr        ; Pointer to attribute data block
  270. attrseg dw    datas
  271.  
  272. ourarg    termarg    <>
  273. modem    mdminfo    <mndata,mnst1a,mncmda,0,0,0,0>
  274. timer    tmrinfo    <tmdata,tmcmda,tmsela>
  275.  
  276. ourflgs    db    0        ; Flags for telnet options
  277. fprint    equ    80H        ;   echo screen output to printer
  278. movcur    equ    40H        ;   cursor moved - needs resetting
  279. kbtrflg    equ    20H        ;   local flag showing if kb trans.is enabled
  280. autorepflg equ    10H        ;   is this an autorepeat cycle 
  281. inited    equ    8H        ;   are we initiating first call to term
  282. tlnxof    equ    4H        ;   have we sent a ^S in telnet with brk/stp
  283. savscn    dw    0        ; save last key-in for auto repeat if needed
  284. escscan dw    0        ; scan code for current ctrl-escape key
  285.  
  286. oldsera    dw    ?        ; old serial handler for standard port
  287. oldsega    dw    ?        ; segment of above
  288. oldmska    db    ?        ; old interrupt controller mask
  289. portina    db    0        ; Has comm port been initialized.
  290.  
  291. oldserb    dw    ?        ; old serial handler for optional port
  292. oldsegb    dw    ?        ; segment of same.
  293. oldmskb    db    ?        ; old interrupt controller mask
  294. portinb    db    0        ; Has comm port been initialized.
  295.  
  296. dosseg    dw    40H        ; Segment  to read IO.SYS
  297. zero    dw    0        ; Use to load segment regs for low core
  298.  
  299. ; Space for addresses in IO.SYS to be calculated at run time in 'lclini'
  300.  
  301. configptr equ    3H        ; Offset of pointer to base of config table
  302. configbas dw    0        ; base address of config table in IO.SYS
  303. fifobas dw    0        ; equ    0A62H for DOS 2.11
  304.  
  305. ; offsets from configbas
  306. statlnptr equ    0CH
  307. kbinptr   equ    2CH        ; kbin addr = base of fifodata area (fifobas)
  308. crtptr    equ    48H
  309.  
  310. ; offsets from fifobas
  311. kbin    equ    0            ; fifobas
  312. kbout    equ    1            ; fifobas + 1
  313. kbfifo    equ    2            ; fifobas + 2
  314. kbrepflg equ    0D9H            ; fifobas + 0D9H
  315.  
  316. xofsnt    db    0        ; Say if we sent an XOFF.
  317. xofrcv    db    0        ; Say if we received an XOFF.
  318.  
  319. ; variables for serial interrupt handler
  320. source    db    bufsiz DUP (?)    ; Buffer for data from port.
  321. srcpnt    dw    0        ; Pointer in buffer (DI).
  322. count    dw    0        ; Number of chars in int buffer.
  323. savesi    dw    0        ; Save SI register here.
  324.     dw    80 DUP (?)    ; local stack for interrupt processing
  325. mnstk    dw    ?
  326. mnsp    dw    ?        ; remote stack info
  327. mnsseg    dw    ?
  328.  
  329. shkbuf    db    300 dup (?)    ; room to display key definition
  330. shkmsg    db    '  Scan code: '
  331. shkmln    equ    $-shkmsg
  332. shkms1    db    cr,lf,'  Definition: '
  333. shkm1ln    equ    $-shkms1
  334.  
  335. setktab    db    24
  336.     mkeyw    'BACKSPACE',9CH
  337.     mkeyw    'F1',80H
  338.     mkeyw    'F2',81H
  339.     mkeyw    'F3',82H
  340.     mkeyw    'F4',83H
  341.     mkeyw    'F5',84H
  342.     mkeyw    'F6',85H
  343.     mkeyw    'F7',86H
  344.     mkeyw    'F8',87H
  345.     mkeyw    'F9',88H
  346.     mkeyw    'F10',89H
  347.     mkeyw    'F11',8AH
  348.     mkeyw    'F12',8BH
  349.     mkeyw    'F13',8CH
  350.     mkeyw    'F14',8DH
  351.     mkeyw    'F15',8EH
  352.     mkeyw    'F16',8FH
  353.     mkeyw    'F17',90H
  354.     mkeyw    'F18',91H
  355.     mkeyw    'F19',92H
  356.     mkeyw    'F20',93H
  357.     mkeyw    'F21',94H
  358.     mkeyw    'F22',95H
  359.     mkeyw    'SCAN',-1
  360.  
  361. setkhlp    db    cr,lf,'Either keyname:  Backspace, F1, ...,F22',cr,lf
  362.     db          '  or   "SCAN" followed by scan code'
  363.     db    ' (given by SHOW KEY)',cr,lf,'$'
  364.  
  365. comptab    db    7
  366.     mkeyw    '1',1
  367.     mkeyw    '2',0
  368.     mkeyw    'COM1',1
  369.     mkeyw    'COM2',0
  370.     mkeyw    'H14',0
  371.     mkeyw    'OPTIONAL',0
  372.     mkeyw    'STANDARD',1
  373.  
  374. bddat    label    word
  375.     dw    0D30H        ; 45.5 baud
  376.     dw    0C00H        ; 50 baud
  377.     dw    0800H        ; 75 baud
  378.     dw    0574H        ; 110 baud
  379.     dw    0476H        ; 134.5 baud
  380.     dw    0400H        ; 150 baud
  381.     dw    0200H        ; 300 baud
  382.     dw    0100H        ; 600 baud
  383.     dw    0080H        ; 1200 baud
  384.     dw    0055H        ; 1800 baud
  385.     dw    004DH        ; 2000 baud
  386.     dw    0040H        ; 2400 baud
  387.     dw    0020H        ; 4800 baud
  388.     dw    0010H        ; 9600 baud
  389.     dw    0008H        ; 19200 baud
  390.     dw    0004H        ; 38400 baud (not tested - may not work)
  391.  
  392. ; some static data for mode line
  393.  
  394. unkbaud    db    ' Unk '            ; must be 5 chars...
  395. baudn    db    ' 45.5'            ;        [g4 start]
  396.     db    '  50 '
  397.     db    '  75 '
  398.     db    ' 110 '
  399.     db    ' 135 '
  400.     db    ' 150 '
  401.     db    ' 300 '
  402.     db    ' 600 '
  403.     db    ' 1200'
  404.     db    ' 1800'
  405.     db    ' 2000'
  406.     db    ' 2400'
  407.     db    ' 4800'
  408.     db    ' 9600'
  409.     db    '19200'        ;        [g4 end]
  410. baudnsiz  equ    15        ; # of baud rates known (tbl size / 5)
  411.  
  412. datas    ends
  413.  
  414.  
  415. code    segment    public
  416.     extrn    comnd:near, dopar:near, escprt:near
  417.     assume    cs:code,ds:datas
  418.  
  419. ; local initialization routine, called by Kermit initialization.
  420.  
  421. LCLINI    PROC    NEAR
  422.     cld
  423.     mov flags.vtflg,0    ; turn off heath emulation
  424.     push es
  425.     mov es,dosseg
  426.     mov bx,configptr
  427.     mov bx,es:[bx]        ; Get offset of configuration table in IO.SYS
  428.     mov configbas,bx    ; store it
  429.     mov cl,fifoclr        ; Clear fifobuffer in case user has been 
  430.     int bios        ;  typing while program was loading
  431.     mov bx,es:[bx].kbinptr    ; Should be address of kbin
  432.     mov cl,es:[bx]        ; Confirm we're in right location    
  433.     cmp cl,byte ptr es:1[bx] ; by showing kbin = kbout
  434.     jne lclin1        ; Fails for DOS 2.00 (no kbinptr)
  435.     mov fifobas,bx        ; Kbin is base of fifo area
  436.     or ourflgs,kbtrflg    ; Show we have a key tranlate table
  437.     jmp short lclin2    ; Localization finished
  438. lclin1: mov bx,configbas    ; DOS 2.00 does have pointer to status line
  439.     mov bx,es:[bx].statlnptr ; Address of 'MS-DOS' in status line
  440.     sub bx,6BH            ; Work back to where kbin should be
  441.     mov cl,es:[bx]            ; Confirm we're in right location
  442.     cmp cl,byte ptr es:1[bx]     ;  by showing kbin = kbout
  443.     jnz lclin3        ; Nothing else to try - report failure
  444.     mov fifobas,bx        ; We've made it!
  445.     or  ourflgs,kbtrflg    ; Show we have a key tranlate table
  446.     xor ax,ax        ; Set zero flag for mono format default
  447.     jmp short lcli20
  448. lclin2:    mov bx,configbas
  449.     mov bx,es:[bx].crtptr        ; Get address of crttype byte
  450.     mov al,es:[bx]            ; get the crttype byte
  451.     test al,1            ; Is it a color crt?
  452. lcli20:    mov dx,ds            ; DOS 2.00 has no crt data and 
  453.     mov es,dx            ;   and defaults to mono
  454.     mov cl,formdtl            ; Length of crt format block
  455.     mov di,offset formdat        ; Where we want data
  456.     jnz lcli21            ; No, it's color
  457.     jmp short lclin4
  458. lcli21: mov si,offset nrmcol        ; Source of color data
  459.     rep movsb            ; Move data to working location
  460.     jmp short lclin4
  461. lclin3:    mov dx,offset bdkscn
  462.     call tmsg
  463.     and ourflgs,not kbtrflg        ; Show no translate table enabled
  464. lclin4:    mov dx,offset formdat.nrmseq    ; set to our normal background color
  465.     call tmsg
  466.     pop es
  467.     ret
  468. LCLINI    ENDP
  469.  
  470. ; Local reset routine, called upon exit from Kermit
  471.  
  472. LCLRST    PROC    NEAR
  473.     ret
  474. LCLRST    ENDP
  475.  
  476. ; this is called by Kermit initialization.  It checks the
  477. ; number of disks on the system, sets the drives variable
  478. ; appropriately.  The only problem is that a value of two
  479. ; is returned for single drive systems to be consistent
  480. ; with the idea of the system having logical drives A and
  481. ; B.  Returns normally.
  482.  
  483. DODISK    PROC    NEAR
  484.     mov ah,gcurdsk        ; current disk value to AL.
  485.     int dos
  486.     mov dl,al        ; put current disk in DL.
  487.     mov ah,seldsk        ; select current disk.
  488.     int dos            ; get number of drives in AL.
  489.     mov drives,al
  490.     ret
  491. DODISK    ENDP
  492.  
  493. ; show the definition of a key.  The terminal argument block (which contains
  494. ; the address and length of the definition tables) is passed in ax.
  495. ; Returns a string to print in AX, length of same in CX.
  496. ; Returns normally.
  497.  
  498. ; In this version, the complete untranslated key scan codes are obtained
  499. ; from the fifo buffer in IO.SYS. The fifo buffer pointers are then updated
  500. ; to show that the key has been read. Certain key scan codes which are
  501. ; intercepted in the kb interrupt routine give a blank or functional response
  502. ; to SHOW KEY  (eg FNC + CTRL + BREAK-STOP, PRINT, and CTRL + 0...9 )
  503. ; and these cannot be translated.
  504.  
  505. SHOWKEY    PROC    NEAR
  506.     push es
  507.     test ourflgs,kbtrflg
  508.     jnz showk0
  509.     push ax            ; Keep stack balanced
  510.     mov bx,ax
  511.     and [bx].flgs,not havtt ; reset flag
  512.     mov dx,offset nokbtr    ; Inform no table installed and return
  513.     jmp short shoerr
  514.  
  515. showk0:    push ax            ; save the terminal argument block
  516.     mov al,trans.escchr    ; calculate scan code for ctrl-escape key
  517.     add al,40H        ; uncontrolify escape char
  518.     mov ah,2        ; control byte
  519.     mov escscan,ax        ; save it
  520. showk1:    call inscan        ; get key-in scan code from IO.SYS
  521.      jmp short showk1    ; Nothing there yet - keep trying
  522.      nop
  523.     call inckbo        ; increment kbout pointer
  524.     cmp al,printkey        ; Is it the print key (any version) ?
  525.     jnz show11
  526.     mov dx,offset prtmsg    ; If so complain
  527.     jmp short shoerr
  528. show11: cmp al,byte ptr escscan    ; Is it current ctrl-escape key ?
  529.     jnz show12
  530.     test ah,02        ; With ctrl + anything
  531.     jz show12
  532.     mov dx,offset escmsg    ; Then complain
  533.     jmp short shoerr
  534. show12:    cld
  535.     mov cx,ds
  536.     mov es,cx
  537.     push ax            ; save scan code
  538.     mov di,offset shkbuf    ; move 'Scan code' message to buffer
  539.     mov si,offset shkmsg
  540.     mov cx,shkmln
  541.     rep movsb
  542.     call nout        ; add scan code to buffer
  543.     mov si,offset shkms1    ; move 'Definition' message to buffer
  544.     mov cx,shkm1ln
  545.     rep movsb
  546.     pop ax            ; retrieve scan code
  547.     pop bx            ; and terminal argument block
  548.     mov cx,[bx].klen    ; length of translation table
  549.     jcxz showk3        ; no table, key not defined
  550.     push di
  551.     mov di,[bx].ktab    ; get table address
  552.     repne scasw        ; look for scan code
  553.     mov si,di
  554.     pop di
  555.     jne showk3        ; not defined
  556.     sub si,[bx].ktab    ; compute entry offset in table
  557.     sub si,2
  558.     add si,[bx].krpl    ; index to replacement
  559.     mov si,[si]        ; get its address
  560.     mov cl,[si]        ; get its length
  561.     mov ch,0
  562.     inc si
  563.     rep movsb        ; transfer replacement to display buffer
  564. showk3:    mov ax,offset shkbuf    ; return address of buffer in ax
  565.     mov cx,di        ; and length in cx
  566.     sub cx,ax
  567.     pop es
  568.     ret
  569. shoerr: call tmsg
  570.     mov cx,0        ; 
  571.     pop ax            ; get rid of junk
  572.     pop es
  573.     ret
  574. SHOWKEY    ENDP
  575.  
  576. ; copy numeric value from AX to ASCII buffer indicated by DI.  DI is updated.
  577.  
  578. NOUT    PROC    NEAR
  579.     mov dx,0        ; zero high word
  580.     mov bx,10        ; divide
  581.     div bx
  582.     push dx            ; save remainder digit
  583.     or ax,ax        ; anything left?
  584.     jz nout1        ; no, start output phase
  585.     call nout
  586. nout1:    pop ax            ; retrieve a digit
  587.     add al,'0'        ; make it ASCII
  588.     stosb            ; put it in buffer
  589.     ret
  590. NOUT    ENDP
  591.  
  592. ; skip returns if no character available at port,
  593. ; otherwise returns with char in al, # of chars in buffer in dx.
  594.  
  595. PRTCHR  PROC    NEAR
  596.     call chkxon        ; see if we have to xon the host.
  597.     cmp count,0
  598.     jnz prtch2
  599.     jmp rskp        ; No data - check console.
  600. prtch2:    pushf            ; save current interrupt value
  601.     cli            ; disable interrupts while manipulating pointers
  602.     mov si,savesi
  603.     lodsb            ; get a byte
  604.     cmp si,offset source + bufsiz    ; bigger than buffer?
  605.     jb prtch1        ; no, keep going
  606.     mov si,offset source    ; yes, wrap around
  607. prtch1:    dec count
  608.     mov savesi,si
  609.     mov dx,count        ; return # of chars in buffer
  610.     popf            ; restore original interrupt flag
  611.     ret
  612. PRTCHR  ENDP
  613.  
  614. ; local routine to see if we have to transmit an xon
  615.  
  616. CHKXON    PROC    NEAR
  617.     push bx
  618.     mov bx,portval
  619.     cmp [bx].floflg,0    ; doing flow control?
  620.     je chkxo1        ; no, skip all this
  621.     cmp xofsnt,false    ; have we sent an xoff?
  622.     je chkxo1        ; no, forget it
  623.     cmp count,mntrgh    ; below trigger?
  624.     jae chkxo1        ; no, forget it
  625.     mov ax,[bx].flowc    ; ah gets xon
  626.     call outchr        ; send it
  627.      nop            ;  ignore failure
  628.      nop
  629.      nop
  630.     mov xofsnt,false    ; remember we've sent an xon.
  631. chkxo1:    pop bx            ; restore register
  632.     ret            ; and return
  633. CHKXON    ENDP
  634.  
  635. ; Put the char in AH to the serial port.  This assumes the
  636. ; port has been initialized.  Should honor xon/xoff.  Skip returns on
  637. ; success, returns normally if the character cannot be written.
  638.  
  639. OUTCHR    PROC    NEAR
  640.     mov bp,portval
  641.     cmp ds:[bp].floflg,0    ; Are we doing flow control.
  642.     je outch2        ; No, just continue.
  643.     sub cx,cx        ; clear counter
  644. outch1:    cmp xofrcv,true        ; Are we being held?
  645.     jne outch2        ; No - it's OK to go on.
  646.     loop outch1        ; held, try for a while
  647.     mov xofrcv,false    ; timed out, force it off and fall thru.
  648. outch2:    push dx            ; Save register.
  649.     sub cx,cx
  650.     mov al,ah        ; Parity routine works on AL.
  651.     call dopar        ; Set parity appropriately.
  652.     mov ah,al        ; Don't overwrite character with status.
  653.     mov dx,modem.mdstat    ; port status register
  654. outch3:    in al,dx
  655.     test al,txrdy        ; Transmitter ready?
  656.     jnz outch4        ; Yes
  657.     loop outch3
  658.      jmp outch5        ; Timeout
  659. outch4:    mov al,ah        ; Now send it out
  660.     mov dx,modem.mddat
  661.     out dx,al
  662.     pop dx
  663.     jmp rskp
  664. outch5:    pop dx
  665.     ret
  666. OUTCHR    ENDP
  667.  
  668. ; Send a break out the current serial port.  Returns normally.
  669.  
  670. SENDBR    PROC    NEAR
  671.     mov dx,modem.mdcom    ; send to command port
  672.     mov al,cbrk+ccmd    ; add break to normal command
  673.     out dx,al
  674.     sub cx,cx        ; wait a while
  675. sndbr1:    loop sndbr1
  676.     mov al,ccmd        ; restore normal command
  677.     out dx,al
  678.     ret            ; and return.
  679. SENDBR    ENDP
  680.  
  681. DISCON    PROC    NEAR
  682.     mov dx,offset hngcfm
  683.     call besure        ; Get confimation of command
  684.      jmp short discn1
  685.      nop
  686.     mov dx,offset dismsg    ; Say what we're doing
  687.     call tmsg
  688.     mov al,CCMD
  689.     xor al,2        ; Reset bit to drop DTR.
  690.     mov dx,modem.mdcom
  691.     out dx,al
  692.     mov bx,05H        ; Set outer counter  5 X --> 3sec.
  693. pause2:    xor cx,cx
  694. pause3:    push bx            ; Waste time for 600ms.
  695.     pop bx
  696.     loop pause3        ; Loop on inner loop.
  697.     dec bx
  698.     jnz pause2        ; Loop on outer loop.
  699.     or al,2            ; Set bit to enable DTR again.
  700.     out dx,al
  701.     mov dx,offset rcnmsg
  702.     call tmsg
  703. discn1:    ret
  704. DISCON    ENDP
  705.  
  706. BESURE    PROC    NEAR        ; Receives addr of prompt in DX.
  707.     call tmsg
  708.     mov ah,conin
  709.     int dos
  710.     and al,137Q        ; Convert to upper case if necessary. 
  711.     cmp al,'Y'
  712.     jz besur1        ; We must return rskp for a 'Y'/'y'
  713.     mov dx,offset crlf    ; For any other character input send a cr/lf.
  714.     call tmsg
  715.     ret            ; And return.
  716. besur1:    jmp rskp
  717. BESURE    ENDP
  718.  
  719.  
  720. ; Clear the input buffer. This throws away all the characters in the
  721. ; serial interrupt buffer.  This is particularly important when
  722. ; talking to servers, since NAKs can accumulate in the buffer.
  723. ; Returns normally.
  724.  
  725. CLRBUF    PROC    NEAR
  726.     pushf            ; save current interrupt value
  727.     cli            ; disable interrupts
  728.     mov ax,offset source    ; reset pointers to beginning of buffer
  729.     mov srcpnt,ax
  730.     mov savesi,ax
  731.     mov count,0
  732.     popf            ; restore original interrupt value
  733.     ret
  734. CLRBUF    ENDP
  735.  
  736. ; Set the baud rate for the current port, based on the value in the
  737. ; portinfo structure.  On entry, previous value of baud rate is saved in AX.
  738. ; Returns normally.
  739.  
  740. DOBAUD    PROC    NEAR
  741.     mov bp,portval
  742.     mov bx,ds:[bp].baud    ;make sure new value is valid
  743.     shl bx,1
  744.     add bx,offset bddat
  745.     cmp word ptr [bx],0FFH
  746.     jne dobd0
  747.     mov ds:[bp].baud,ax    ;replace bad rate with previous value
  748.     mov dx,offset badbd
  749.     jmp tmsg
  750. dobd0:    mov dx,timer.tmcmd    ;timer command port
  751.     mov al,timer.tmsel    ;select proper channel and mode
  752.     out dx,al
  753.     mov ax,[bx]        ;get timer initializer for this rate
  754.     mov dx,timer.tmdat    ;timer data port
  755.     out dx,al        ;output low byte
  756.     mov al,ah
  757.     out dx,al        ;output high byte
  758.     ret
  759. DOBAUD    ENDP
  760.  
  761. ; Get the current baud rate from the serial card and set it
  762. ; in the portinfo structure for the current port.  Returns normally.
  763. ; This is used during initialization.
  764.  
  765. GETBAUD    PROC    NEAR
  766.     mov bx,portval        ; no way to determine baud rate on APC
  767.     mov [bx].baud,B1200    ;  so set default baud rate to 1200
  768.     ret
  769. GETBAUD    ENDP
  770.  
  771. ; Set the mode for the current port.  This is part of the serial
  772. ; initialization routine.
  773.  
  774. DOMODE    PROC    NEAR
  775.     mov dx,modem.mdcom    ;send 3 zeros to command port to reset chip
  776.     mov al,0
  777.     out dx,al
  778.     mov al,0
  779.     out dx,al
  780.     mov al,0
  781.     out dx,al
  782.     mov al,cmode        ;enable mode setting
  783.     out dx,al
  784.     mov cx,100        ;allow chip time to reset
  785. mode1:    loop mode1
  786.     mov al,mmode        ;mode: 16x rate, 8 data, no parity, 1 stop
  787.     out dx,al
  788.     mov cx,100
  789. mode2:    loop mode2
  790.     mov al,ccmd        ;RTS & DTR high, RX & TX enabled, reset errors
  791.     out dx,al
  792.     ret
  793. DOMODE    ENDP
  794.  
  795. ; Reassure user about connection to the host.  Tell him what escape
  796. ; sequence to use to return and the communications port and baud
  797. ; rate being used.   [19b]
  798.  
  799. DOMSG    PROC    NEAR
  800.     mov    bx,offset ourarg    ; get argument block
  801.     mov    al,[bx].baudb        ; get baud bits
  802.     mov    si,offset unkbaud    ; Assume unknown baud.
  803.     cmp    al,baudnsiz        ; too big?
  804.     jnb    dmsg12            ; yes, use default
  805.     mov    cl,2            ; each is 5 bytes long
  806.     shl    al,cl            ; 4 X
  807.     add    al,[bx].baudb        ; make 4+1 = 5
  808.     mov    ah,0
  809.     add    ax,offset baudn
  810.     mov    si,ax
  811. dmsg12:    mov    cx,5            ; length of baud space
  812.     mov    di,offset cnmsgb
  813.     rep    movsb            ; copy in baud rate
  814.     mov    al,'1'
  815.     cmp    ourarg.prt,1        ; One means port 1
  816.     je    dmsg15            ; yes, keep going
  817.     mov    al,'2'            ; Zero means port 2
  818. dmsg15:    mov    cnmsgp,al        ; fill in port number
  819.     mov dx,offset cnmsg
  820.     call tmsg
  821.     call escprt            ; in MSSET
  822.     mov dx,offset cnmsg1
  823.     call tmsg
  824.     ret
  825. DOMSG    ENDP
  826.  
  827. ; set the current port.
  828.  
  829. COMS    PROC    NEAR
  830.     mov dx,offset comptab    ;get port selection
  831.     mov bx,0
  832.     mov ah,cmkey
  833.     call comnd
  834.      jmp r
  835.     push bx
  836.     mov ah,cmcfm        ;get a confirmation
  837.     call comnd
  838.      jmp comx
  839.      nop
  840.     pop bx
  841.     mov flags.comflg,bl    ;save port selection
  842.     cmp flags.comflg,1
  843.     jne coms2
  844.     mov ax,offset port1    ;set to run on port 1
  845.     mov portval,ax
  846.     call resetb        ;reset port 2, if in use
  847.     call inita        ;set up port 1
  848.     ret
  849. coms2:    mov ax,offset port2    ;set to run on port 2
  850.     mov portval,ax
  851.     call reseta        ;reset port 1, if in use
  852.     call initb        ;set up port 2
  853.     ret
  854. comx:    pop bx
  855.     ret
  856. COMS    ENDP
  857.  
  858. ; initialization for using serial port.  This routine performs
  859. ; any initialization necessary for using the serial port, including
  860. ; setting up interrupt routines, setting buffer pointers, etc.
  861. ; Doing this twice in a row should be harmless (this version checks
  862. ; a flag and returns if initialization has already been done).
  863. ; SERRST below should restore any interrupt vectors that this changes.
  864. ; Returns normally.
  865.  
  866. SERINI    PROC    NEAR
  867.     cmp flags.comflg,1
  868.     jne seri2
  869.     call resetb
  870.     call inita
  871.     ret
  872. seri2:    call reseta
  873.     call initb
  874.     ret
  875. SERINI    ENDP
  876.  
  877. ; Reset the serial port.  This is the opposite of serini.  Calling
  878. ; this twice without intervening calls to serini should be harmless.
  879. ; Returns normally.
  880.  
  881. SERRST    PROC    NEAR
  882.     call reseta        ;reset port 1
  883.     call resetb        ;reset port 2
  884.     mov dx,offset recur    ; Reenable cursor display
  885.     call tmsg
  886.     and ourflgs,not inited    ; Reset init flag for term usage
  887.     ret
  888. SERRST    ENDP
  889.  
  890. ; Local routine to initialize the standard serial port
  891.  
  892. INITA    PROC    NEAR
  893.     cmp portina,1        ; Did we initialize port already? [21c]
  894.     je inita0        ; Yes, so just leave. [21c]
  895.     push es
  896.     cli            ; Disable interrupts
  897.     mov ax,offset port1
  898.     mov portval,ax
  899.     xor ax,ax        ; Address low memory
  900.     mov es,ax
  901.     mov ax,es:[4*icsvcta]    ; save standard port interrupt vector
  902.     mov oldsera,ax
  903.     mov ax,es:[4*icsvcta+2]
  904.     mov oldsega,ax
  905.     mov ax,offset serint    ; point to our routine
  906.     mov es:[4*icsvcta],ax    ; point at our serial routine
  907.     mov es:[4*icsvcta+2],cs    ; our segment
  908.     mov dx,intmska        ; set up standard port...
  909.     in al,dx
  910.     mov oldmska,al        ; save old master controller mask
  911.  
  912. ;    NEC recommends that the timer interrupt be disabled during interrupt-
  913. ;    driven serial I/O, but this disables the clock display and keyboard
  914. ;    repeat.  I have not had any problems leaving it enabled, so I will
  915. ;    leave it alone here.  If problems develop, uncomment the following
  916. ;    line to disable timer interrupts. -- RonB
  917.  
  918. ;    or al,ictmsk        ; disable timer interrupt
  919.     and al,not icsmska    ; enable serial interrupt at master controller
  920.     out dx,al
  921.     mov dx,mnmska        ; enable serial interrupt at port
  922.     mov al,txmsk+tbemsk    ; disable tx and tbe interrupts (enable rx)
  923.     out dx,al
  924.     mov dx,mntdca        ; enable operation of serial port
  925.     mov al,0
  926.     out dx,al
  927.     mov modem.mddat,mndata
  928.     mov modem.mdstat,mnst1a
  929.     mov modem.mdcom,mncmda
  930.     mov timer.tmdat,tmdata
  931.     mov timer.tmcmd,tmcmda
  932.     mov timer.tmsel,tmsela
  933.     call domode
  934.     call dobaud
  935.     mov portina,1        ; Remember port has been initialized.
  936.     call clrbuf        ; Clear input buffer.
  937.     sti            ; Allow interrupts
  938.     pop es
  939. inita0:    ret
  940. INITA    ENDP
  941.  
  942. ; Local routine to initialize the optional (H14) serial port
  943.  
  944. INITB    PROC    NEAR
  945.     cmp portinb,1        ; Did we initialize port already? [21c]
  946.     je initb0        ; Yes, so just leave. [21c]
  947.     push es
  948.     cli            ; Disable interrupts
  949.     mov ax,offset port2
  950.     mov portval,ax
  951.     xor ax,ax        ; Address low memory
  952.     mov es,ax
  953.     mov ax,es:[4*icsvctb]    ; save optional port interrupt vector
  954.     mov oldserb,ax
  955.     mov ax,es:[4*icsvctb+2]
  956.     mov oldsegb,ax
  957.     mov ax,offset serint    ; point to our routine
  958.     mov es:[4*icsvctb],ax    ; point at our serial routine
  959.     mov es:[4*icsvctb+2],cs    ; our segment
  960.     mov dx,intmskb        ; set up optional port...
  961.     in al,dx
  962.     mov oldmskb,al        ; save old master or slave controller mask
  963.     and al,not icsmskb    ; enable serial interrupt at controller
  964.     out dx,al
  965.     mov dx,mnmskb        ; enable serial interrupt at port
  966.     mov al,txmsk+tbemsk    ; disable tx and tbe interrupts (enable rx)
  967.     out dx,al
  968.     mov dx,mntdcb        ; enable operation of serial port
  969.     mov al,0
  970.     out dx,al
  971.     mov modem.mdstat,mnst1b
  972.     mov modem.mddat,mndatb
  973.     mov modem.mdcom,mncmdb
  974.     mov timer.tmdat,tmdatb
  975.     mov timer.tmcmd,tmcmdb
  976.     mov timer.tmsel,tmselb
  977.     call domode
  978.     call dobaud
  979.     mov portinb,1        ; Remember port has been initialized.
  980.     call clrbuf        ; Clear input buffer.
  981.     sti            ; Allow interrupts
  982.     pop es
  983. initb0:    ret
  984. INITB    ENDP
  985.  
  986. ; Reset standard serial port
  987.  
  988. RESETA    PROC    NEAR
  989.     cmp portina,0        ; Did we reset port already?
  990.     je rsta0        ; Yes, so just leave.
  991.     push es
  992.     cli            ; Disable interrupts
  993.     xor ax,ax        ; Address low memory
  994.     mov es,ax
  995.     mov ax,oldsera        ; Restore interrupt vector
  996.     mov es:[4*icsvcta],ax
  997.     mov ax,oldsega
  998.     mov es:[4*icsvcta+2],ax
  999.     mov dx,intmska        ; restore old master controller mask
  1000.     mov al,oldmska
  1001.     out dx,al
  1002.     mov dx,mnmska        ; disable serial interrupts at port
  1003.     mov al,txmsk+rxmsk+tbemsk
  1004.     out dx,al
  1005.     mov portina,0        ; Remember port has been reset
  1006.     sti            ; Allow interrupts
  1007.     pop es
  1008. rsta0:    ret
  1009. RESETA    ENDP
  1010.  
  1011. ; Reset optional (H14) serial port
  1012.  
  1013. RESETB    PROC    NEAR
  1014.     cmp portinb,0        ; Did we reset port already?
  1015.     je rstb0        ; Yes, so just leave.
  1016.     push es
  1017.     cli            ; Disable interrupts
  1018.     xor ax,ax        ; Address low memory
  1019.     mov es,ax
  1020.     mov ax,oldserb        ; Restore interrupt vector
  1021.     mov es:[4*icsvctb],ax
  1022.     mov ax,oldsegb
  1023.     mov es:[4*icsvctb+2],ax
  1024.     mov dx,intmskb        ; restore old slave controller mask
  1025.     mov al,oldmskb
  1026.     out dx,al
  1027.     mov dx,mnmskb        ; disable serial interrupts at port
  1028.     mov al,txmsk+rxmsk+tbemsk
  1029.     out dx,al
  1030.     mov portinb,0        ; Remember port has been reset
  1031.     sti            ; Allow interrupts
  1032.     pop es
  1033. rstb0:    ret
  1034. RESETB    ENDP
  1035.  
  1036.  
  1037. ; serial port interrupt routine.  This is not accessible outside this
  1038. ; module, handles serial port receiver interrupts.
  1039.  
  1040. SERINT    PROC  NEAR
  1041.     push ds            ; save these on remote stack
  1042.     push ax
  1043.     mov ax,seg datas    ; get our own data segment
  1044.     mov ds,ax
  1045.     mov mnsp,sp        ; save remote stack information
  1046.     mov mnsseg,ss
  1047.     mov sp,offset mnstk    ; switch to local stack
  1048.     mov ss,ax
  1049.     push es            ; and save remaining registers
  1050.     push bp
  1051.     push di
  1052.     push si
  1053.     push dx
  1054.     push cx
  1055.     push bx
  1056.     mov es,ax
  1057.     call mnproc        ; process the interrupt
  1058.     mov al,icEOI
  1059.     cmp flags.comflg,1    ; If using standard port
  1060.     je intr1
  1061.     mov dx,intcmdb        ;    or H14 vectored to master
  1062.     cmp dx,intcmda
  1063.     je intr1        ;    only signal End of Interrupt to master,
  1064.     out dx,al        ; otherwise signal to both slave and master.
  1065. intr1:    mov dx,intcmda
  1066.     out dx,al
  1067.     pop bx            ; restore registers from stack
  1068.     pop cx
  1069.     pop dx
  1070.     pop si
  1071.     pop di
  1072.     pop bp
  1073.     pop es
  1074.     mov ax,mnsseg        ; switch back to remote stack
  1075.     mov ss,ax
  1076.     mov ax,mnsp
  1077.     mov sp,ax
  1078.     pop ax
  1079.     pop ds
  1080.     iret
  1081.  
  1082. ; handler for serial input
  1083.  
  1084. mnproc:    cld
  1085.     mov di,srcpnt        ; get buffer pointer
  1086.     mov dx,modem.mdstat    ; is data available?
  1087.     in al,dx
  1088.     test al,rxrdy
  1089.     jz mnpro7
  1090.     mov dx,modem.mddat    ; read data
  1091.     in al,dx
  1092.     or al,al
  1093.     jz mnpro7        ; Ignore nulls.
  1094.     cmp al,7FH        ; Ignore rubouts, too.
  1095.     jz mnpro7
  1096.     mov ah,al
  1097.     and ah,7fH        ; only consider low-order 7 bits for flow ctl.
  1098.     mov bp,portval
  1099.     cmp ds:[bp].floflg,0    ; Doing flow control?
  1100.     je mnpro4        ; Nope.
  1101.     mov bx,ds:[bp].flowc    ; Flow control char (BH = XON, BL = XOFF).
  1102.     cmp ah,bl        ; Is it an XOFF?
  1103.     jne mnpro3        ; Nope, go on.
  1104.     mov xofrcv,true        ; Set the flag.
  1105.     jmp short mnpro7
  1106. mnpro3:    cmp ah,bh        ; Get an XON?
  1107.     jne mnpro4        ; No, go on.
  1108.     mov xofrcv,false    ; Clear our flag.
  1109.     jmp mnpro7
  1110. mnpro4:    stosb
  1111.     cmp di,offset source + bufsiz
  1112.     jb mnpro5        ; not past end...
  1113.     mov di,offset source    ; wrap buffer around
  1114. mnpro5:    mov srcpnt,di        ; update ptr
  1115.     inc count
  1116.     cmp ds:[bp].floflg,0    ; Doing flow control?
  1117.     je mnpro7        ; No, just leave.
  1118.     cmp xofsnt,true        ; Have we sent an XOFF?
  1119.     je mnpro7        ; Yes.
  1120.     cmp count,mntrgh    ; Past the high trigger point?
  1121.     jbe mnpro7        ; No, we're within our limit.
  1122.     mov ah,bl        ; Get the XOFF.
  1123.     call outchr        ; Send it.
  1124.      nop            ;   ignore failure.
  1125.      nop
  1126.      nop
  1127.     mov xofsnt,true        ; Remember we sent it.
  1128. mnpro7:    ret
  1129.  
  1130. SERINT    ENDP
  1131.  
  1132. ; Dumb terminal emulator.  Anyone wishing to enhance it is encouraged
  1133. ; to do so.
  1134.  
  1135. TERM    PROC    NEAR
  1136.     push es
  1137.     test ourflgs,inited    ; Have we been here before
  1138.     jnz  term01        ; if so, skip this stuff
  1139.     or  ourflgs,inited    ; show we've been here
  1140.     test ourflgs,kbtrflg
  1141.     jnz term0
  1142.     mov bx,ax
  1143.     and [bx].flgs,not havtt ; If no table then reset flag
  1144. term0:    mov si,ax        ; save argument block locally
  1145.     mov di,offset ourarg
  1146.     mov ax,ds
  1147.     mov es,ax
  1148.     mov cx,size termarg
  1149.     rep movsb
  1150.     mov al,trans.escchr    ; Calculate scan code for cntrl-escape char
  1151.     add al,40H        ; Uncontollify escape char
  1152.     mov ah,02H        ; Control byte for escape scan code
  1153.     mov escscan,ax        ; save it
  1154.     call domsg        ; tell user how we're connecting.
  1155. term01: test ourflgs,movcur     ; Do we need to reset cursor position    
  1156.     jz term1
  1157.     mov dx,offset cmd
  1158.     mov cx,savcur
  1159.     mov word ptr la,cx
  1160.     mov noc,0
  1161.     mov cmd,1        ; Bios  move cursor call
  1162.     mov cl,crtcmd
  1163.     int bios
  1164.     and ourflgs, not movcur
  1165. term1:    call prtchr        ; Serial port input processor
  1166.      jmp short term2    ;  ...have a char
  1167.      nop
  1168.     jmp term4        ; no char, continue
  1169. term2:    and al,7FH        ; only use ASCII in terminal mode
  1170.     push ax
  1171.     mov dl,al
  1172.     mov ah,conout
  1173.     int dos            ; display char
  1174.     pop ax
  1175.     test ourarg.flgs,capt    ; are we capturing output?
  1176.     jz term3
  1177.     push ax
  1178.     call ourarg.captr
  1179.     pop ax
  1180. term3:    test ourflgs,fprint    ; are we echoing to printer?
  1181.     jz term4
  1182.     call lstchr
  1183.  
  1184. term4:    test ourflgs,kbtrflg
  1185.     jz term50
  1186.     call inscan
  1187.      jmp  short term1
  1188.      nop
  1189.     cmp al,printkey        ; All shifts of print key do special duty.
  1190.     jne term41
  1191.     cmp ah,0
  1192.     jne term40        ; but toggle printer only if unshifted print
  1193.     xor ourflgs,fprint    ; go toggle printer 
  1194. term40:    call inckbo        ; increment kbout pointer
  1195.     jmp term1
  1196. term41:    cmp al,byte ptr escscan ; Is it current escape key
  1197.     jne  term42
  1198.     test ah,02        ;  with ctrl + anything ?
  1199.     jz  term42
  1200.     call inckbo
  1201.     mov cx,100        ; Delay for memory stability
  1202. trm420:    loop trm420
  1203.     jmp short termx        ; it's ctrl-escape key so just return    
  1204. term42:    call trnout        ; Returns rskp if char not sent.
  1205.      jmp short term1    ; Translation found and already sent.
  1206.      nop            ; no translation so move char via DCONIO
  1207.     cmp ax,brkstp        ; is it unredefined/unshifted break/stop key
  1208.     jnz term50        ; if not, just continue
  1209.     mov ax,ctrl_s        ; get a ^S ready
  1210.     test ourflgs,tlnxof    ; have we already sent a ^S ?
  1211.     jz term43        ; no, we can just set flag and send the ^S
  1212.     mov ax,ctrl_q        ; yes, so now we need a ^Q
  1213. term43: xor ourflgs,tlnxof    ; change the flag in either case
  1214.     call sndhst        ; send our  ^S/ ^Q - IO.SYS 2.11 won't do it 
  1215.     mov ah,dconio        ; do a dummy read to clear IO.SYS flush flag
  1216.     mov dl,0FFH
  1217.     int dos
  1218.     jmp term1        ; and go back for more
  1219. term50:    mov ah,dconio        ; Keyboard input processor
  1220.     mov dl,0FFH
  1221.     int dos            ; check console
  1222.     jnz term51
  1223.     jmp term1        ; no char, continue .Too far for rel jmp.
  1224. term51:    cmp al,ourarg.escc    ; is it the escape char?
  1225.     je termx        ; allows use of unredef left arrow key to esc
  1226.     call sndhst        ; no translation, just send it out
  1227.     jmp term1        ; and go back for more
  1228. termx:    pop es
  1229.     ret
  1230.  
  1231.  
  1232. ; do appropriate translations on input key, and transmit
  1233. ; if translation entry found it sends char(s) to sndhst and returns normally 
  1234. ; if no translation entry is found, returns rskp with unsent scan code in ax
  1235. ;  so that CONIN in IO.SYS can do its translation if neessary.
  1236.  
  1237. trnout:    test ourflgs,kbtrflg    ; is there a translation table?
  1238.     jz trnou3
  1239.     mov cx,ourarg.klen    ; get table length and origin
  1240.     mov di,ourarg.ktab
  1241.     push es
  1242.     mov bx,ds
  1243.     mov es,bx
  1244.     jcxz trnou3        ; Needed for case of table zero length
  1245.     repne scasw        ; look for key
  1246.     jne trnou3        ; if not found, return rskp
  1247.     sub di,ourarg.ktab    ; reset to offset of replacement
  1248.     sub di,2
  1249.     add di,ourarg.krpl
  1250.     mov si,[di]
  1251.     mov cl,[si]        ; get length of replacement
  1252.     mov ch,0
  1253.     jcxz trnou3        ; if length is zero, send nothing
  1254.     inc si
  1255. trnou1:    lodsb            ; get replacement character
  1256.     push si
  1257.     push cx
  1258.     call sndhst        ; send it to port
  1259.     pop cx
  1260.     pop si
  1261.     loop trnou1        ; continue until translation complete
  1262. trnou2:    call inckbo        ; increment kbout pointer
  1263.     pop es
  1264.     ret            ; return after translating and sending
  1265. trnou3:    pop es
  1266.     jmp rskp        ; plain characters return rskp
  1267.  
  1268. ; get key-in scan code from fifo buffer in IO.SYS
  1269. ; if gets a key-in, skip returns with scan code in ax
  1270. ; returns normally if no key-in
  1271.  
  1272. inscan:    push es
  1273.     mov es,dosseg        ; Address IO.SYS segment with es
  1274.     and ourflgs,not autorepflg    ; Reset auto repeat flag
  1275.     mov bx,fifobas         ; Offset of fifobas in IO.SYS (from LCLINI)
  1276. insca1:    mov al,es:[bx].kbout    ; Get value of kbin pointer
  1277.     cmp al,es:[bx].kbin    ; Compare value of kbout pointer
  1278.     jz  insca2        ; If equal, no key-in yet so exit
  1279.     sub ah,ah
  1280.     add bx,ax        ; Calculate address pointed to (-2)
  1281.     mov ax,es:2[bx]        ; Get scan code pointed to by kbout.
  1282.     xchg ah,al        ; Get control byte -> ah, data byte -> al.
  1283.     mov savscn,ax        ; Save scan data in case key repeat needed.
  1284.     pop es
  1285.     jmp rskp
  1286. insca2: mov bx,fifobas
  1287.     cmp byte ptr es:[bx].kbrepflg,0     ; Is it time to repeat last key-in
  1288.     jz inscax             ; Nope so exit
  1289.     mov ax,savscn            ; Get last key-in
  1290.     or ourflgs,autorepflg        ; Show we are on auto repeat cycle
  1291.     pop es                ; And make it look like new
  1292.     jmp rskp
  1293. inscax:    pop es
  1294.     ret
  1295.  
  1296. ; increments kbout pointer (with reset to zero) and returns normally
  1297. ;   (on auto repeat cycles resets kbrepflg and returns )
  1298.  
  1299. inckbo:    push es
  1300.     mov es,dosseg
  1301.     mov bx,fifobas
  1302.     test ourflgs,autorepflg    ; new key-in or autorepeat
  1303.     jnz inckb2
  1304.     mov cl,0        ; Update kbout pointer to fifo 
  1305.     cli
  1306.     cmp byte ptr es:[bx].kbout,kbfifosiz-2        ; End of fifo buff ?
  1307.     je  inckb1        ; Yes, so start back at beginning
  1308.     mov cl,es:[bx].kbout    ; No, just update our place
  1309.     add cl,2
  1310. inckb1:    mov es:[bx].kbout,cl    ; Write back new pointer value
  1311.     sti
  1312.     jmp short inckbx
  1313. inckb2: mov byte ptr es:[bx].kbrepflg,0    ; Reset autorepeat flag in IO.SYS
  1314. inckbx:    pop es
  1315.     ret
  1316.  
  1317. ; send character in AL to port, with possible local echo
  1318.  
  1319. sndhst:    push ax
  1320.     mov ah,al
  1321.     call outchr        ; send char to port
  1322.      nop            ;  ...don't care if it fails
  1323.      nop
  1324.      nop
  1325.     pop ax
  1326.     test ourarg.flgs,lclecho ; doing local echo?
  1327.     jz sndhs2
  1328.     mov dl,al
  1329.     mov ah,conout
  1330.     int dos            ;  if so, display char
  1331. sndhs2:    ret
  1332.  
  1333. ; send character to printer.  The only special case is the tab, which must
  1334. ; be expanded to spaces because MS-DOS doesn't.
  1335.  
  1336. lstchr:    cmp al,tab
  1337.     jne lstch2
  1338.     mov ax,lstpos        ; current column position
  1339.     mov cx,8        ; # of spaces = 8 - (column % 8)
  1340.     div cl
  1341.     sub cl,ah
  1342.     add lstpos,cx        ; update the column position
  1343.     mov al,' '
  1344. lstch1:    call lstch4        ; print all the spaces
  1345.     loop lstch1
  1346.     ret
  1347. lstch2:    cmp al,cr        ; CR returns column count to zero
  1348.     jne lstch3
  1349.     mov lstpos,0
  1350. lstch3:    cmp al,' '        ; only printable characters are counted
  1351.     jb lstch4
  1352.     cmp al,del
  1353.     je lstch4
  1354.     inc lstpos
  1355. lstch4: mov dl,al        ; print the character in any case
  1356.     mov ah,lstout
  1357.     int dos
  1358.     ret
  1359.  
  1360. TERM    ENDP
  1361.  
  1362. ; Set heath emulation on/off.
  1363.  
  1364. VTS    PROC    NEAR
  1365.     mov dx,offset nyimsg
  1366.     jmp tmsg
  1367. VTS    ENDP
  1368.  
  1369. ; Position the cursor according to contents of DX:
  1370. ; DH contains row, DL contains column.  Returns normally.
  1371.  
  1372. POSCUR    PROC    NEAR
  1373.     push si
  1374.     cmp dh,25        ; out of range just assumes high value
  1375.     jb poscu1
  1376.     mov dh,24
  1377. poscu1:    cmp dl,80
  1378.     jb poscu2
  1379.     mov dl,79
  1380. poscu2:    add dx,2020H        ; add offset for ADM cursor addressing
  1381.     mov cpseq+2,dh
  1382.     mov cpseq+3,dl
  1383.     mov si,offset cpseq    ; print sequence (ESC=rc)
  1384.     mov cx,4
  1385. posc1:    lodsb
  1386.     mov dl,al
  1387.     mov ah,conout
  1388.     int dos
  1389.     loop posc1
  1390.     pop si
  1391.     ret
  1392. POSCUR    ENDP
  1393.  
  1394. ; Locate; homes cursor position and disables its display. Returns normally.
  1395.  
  1396. LOCATE  PROC    NEAR
  1397.     mov dx,offset nocur    ; Disable cursor
  1398.     call tmsg
  1399.     mov dx,0        ; Go to top left corner of screen.
  1400.     jmp poscur
  1401. LOCATE  ENDP
  1402.  
  1403. ; Delete a character from the terminal.  This works by printing
  1404. ; backspaces and spaces.  Returns normally.
  1405.  
  1406. DODEL    PROC    NEAR
  1407.     cmp al,del        ; Del character needs extra backspace
  1408.     jne dodel1
  1409.     mov dl,bs
  1410.     mov ah,conout
  1411.     int dos
  1412. dodel1:    mov dx,offset delstr    ; Erase weird character.
  1413.     jmp tmsg
  1414. DODEL    ENDP
  1415.  
  1416. ; Move the cursor to the left margin, then clear to end of line.
  1417. ; Returns normally.
  1418.  
  1419. CTLU    PROC    NEAR
  1420.     mov dx,offset clrlin    ; this just goes to left margin...
  1421.     call tmsg
  1422.     jmp clearl        ; now clear line
  1423. CTLU    ENDP
  1424.  
  1425. ; Clear to the end of the current line.  Returns normally.
  1426.  
  1427. CLEARL    PROC    NEAR
  1428.     mov dx,offset ceolseq    ; clear sequence
  1429.     jmp tmsg
  1430. CLEARL    ENDP
  1431.  
  1432. ; This routine blanks the screen and homes the cursor.  Returns normally.
  1433.  
  1434. CMBLNK    PROC    NEAR
  1435.     mov dx,offset clrseq    ; clear screen and home cursor sequence
  1436.     jmp tmsg
  1437. CMBLNK  ENDP
  1438.  
  1439. ; write a line in inverse video at the bottom of the screen...
  1440. ; the line is passed in dx, terminated by a $.  Returns normally.
  1441.  
  1442. PUTMOD    PROC    NEAR
  1443.     push dx            ; preserve message
  1444.     mov dx,24*100H        ; line 24
  1445.     call poscur
  1446.     mov dx,offset formdat.invseq    ; put into inverse video
  1447.     call tmsg
  1448.     pop dx            ; print the message
  1449.     call tmsg
  1450.     mov dx,offset formdat.nrmseq    ; normal video
  1451.     jmp tmsg        ; Jump to return
  1452. PUTMOD    ENDP
  1453.  
  1454. ; clear the mode line written by putmod.  Returns normally.
  1455.  
  1456. CLRMOD    PROC    NEAR
  1457.     mov dx,24*100H
  1458.     call poscur
  1459.     mov dx,offset ceolseq
  1460.     jmp tmsg
  1461. CLRMOD    ENDP
  1462.  
  1463. ; Put a help message in a box at the top of the screen. 
  1464. ; This one uses inverse video (or yellow if color)
  1465. ; Pass the message in ax, terminated by a null.  Returns normally.
  1466.  
  1467. PUTHLP    PROC    NEAR
  1468.     cld
  1469.     mov dx,ax        ; Prepare to pass message to 'getnoc'
  1470.     call getnoc        ; 
  1471.     mov rnoc,cx        ; This is unformatted NOC in message
  1472.     mov  cx,5        ; Calculate formatted area needed (in words)
  1473.     rol  bx,cl        ; BX is no of lf's.
  1474.     mov  NOC,bx
  1475.     mov cx,2
  1476.     ror bx,cl
  1477.     add NOC,bx        ; This is Lines X 40
  1478.     add NOC,80        ; Current line + one more
  1479.     mov cx,NOC
  1480.     mov si,dx        ; Source of message  given us
  1481.     mov di,attrptr        ; Pointer to screen attrib area
  1482.     mov ax,formdat.bldcrt    ; Need bold attribute
  1483.     rep stosw        ; Cover attribute area needed
  1484.     mov ax,formdat.nrmcrt    ; Rest of screen needs normal color
  1485.     mov cx,1000        ; Whole screen
  1486.     sub cx,NOC        ; Attribute area left to cover
  1487.     rep stosw        ; Do it
  1488.     mov cx,1000        ; Fill screen data area with null bytes
  1489.     mov di,dispptr        ; Pointer to screen data area
  1490.     xor ax,ax        ; This is source of null bytes
  1491.     rep stosw        ; Prepare clean screen data area
  1492.     mov cx,rnoc        ; No of unformatted data bytes 
  1493.     mov di,dispptr        ; Destination is screen data area
  1494. pthlp0:    push di            ; Save start of current line
  1495. pthlp1:    lodsb            ; Load data bytes 1-by-1
  1496.     cmp al,cr        ; Is this one an eol?
  1497.     jz pthlp2        ; Yep - handle cr/lf's ourselves
  1498.     stosb            ; No - move character
  1499.     loop  pthlp1        ; And go back for next
  1500.     jmp short pthlp3    ; Finished moving chars, so exit.
  1501. pthlp2: dec cx            ; Account for cr and lf
  1502.      dec cx
  1503.     inc si            ; Skip the lf
  1504.     pop di            ; Get start of current line.
  1505.     add di,80        ; Adjust pointer to next line
  1506.     jmp short pthlp0    ; And go back for more
  1507. pthlp3:    pop di
  1508.     mov noc,2000        ; We are going to write over whole screen
  1509.     test ourflgs,movcur    ; Save cursor only if not previously saved
  1510.     jnz pthlp4
  1511.     mov cmd,2        ; Get cursor position before writing
  1512.     mov dx,offset cmd
  1513.     mov cl,crtcmd
  1514.     int bios        ; Get cursor call
  1515.     mov cx,word ptr la
  1516.     mov savcur,cx        ; Store cursor position
  1517. pthlp4:    mov la,24        ; Prepare to roll down 24 lines
  1518.     mov ca,0
  1519.     mov cmd,3        ; Screen roll down command
  1520.     mov dx,offset cmd
  1521.     mov cl,crtcmd
  1522.     int bios        ; Do it!
  1523.     mov la,0        ; Begin our msg on top line of screen
  1524.     mov cmd,1        ; String write command
  1525.     int bios        ; Write it.
  1526.     mov cx,1000        ; Delay for video memory stability
  1527. pthlp5:    loop pthlp5
  1528.     mov dx,offset upcur
  1529.     call tmsg
  1530.     mov dx,offset upcur    ; Put cursor up onto clean screen
  1531.     call tmsg
  1532.     or  ourflgs,movcur    ; Tell that we've moved the cursor
  1533.     ret
  1534. PUTHLP    ENDP
  1535.  
  1536. ; Receives message pointer in DX, terminating character in CL
  1537. ; Returns with message ptr in DX, NOC in CX, and number of lf's in BX.
  1538.  
  1539. GETNOC    PROC    NEAR
  1540.     cld
  1541.     mov di,dx
  1542.     mov al,cl            ; Move terminator to AL
  1543.     mov cx,2000            ; Longest acceptible message.
  1544.     repnz scasb            ; Look for terminator
  1545.     jz gtnoc1
  1546.     xor cx,cx
  1547.     ret                ; Error return
  1548. gtnoc1: sub di,dx            ; Calculate NOC
  1549.     mov cx,di            ; Move it to counter
  1550.     dec cx                ; Discount terminator
  1551.     push cx                ; Save NOC
  1552.     mov di,dx
  1553.     mov al,lf
  1554.     xor bx,bx
  1555. gtnoc2:    repnz scasb            ; Now count lf's
  1556.     jcxz gtnoc3            ; If the counter ran out
  1557.     inc bx
  1558.     jmp short gtnoc2
  1559. gtnoc3:    pop cx                ; Recover NOC
  1560.     ret
  1561. GETNOC    ENDP
  1562.  
  1563.  
  1564.  
  1565. ; Produce a short beep.  Returns normally.
  1566.  
  1567. BEEP    PROC    NEAR
  1568.     mov dl,bell
  1569.     mov ah,conout
  1570.     int dos
  1571.     ret
  1572. BEEP    ENDP
  1573.  
  1574. ; Prints $-terminated message in dx, for local use only
  1575.  
  1576. TMSG    PROC    NEAR
  1577.     mov ah,prstr
  1578.     int dos
  1579.     ret
  1580. TMSG    ENDP
  1581.  
  1582. ; Jumping to this location is like retskp.  It assumes the instruction
  1583. ;   after the call is a jmp addr.
  1584.  
  1585. RSKP    PROC    NEAR
  1586.     pop bp
  1587.     add bp,3
  1588.     push bp
  1589.         ret
  1590. RSKP    ENDP
  1591.  
  1592. ; Jumping here is the same as a ret.
  1593.  
  1594. R       PROC    NEAR
  1595.         ret
  1596. R       ENDP
  1597.  
  1598. code    ends
  1599.     end
  1600.  
  1601. ; END OF MSXAPC.ASM
  1602.