home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 01e / msjall.zip / MSJV2-5.ZIP / MDM_DRV.ALL < prev    next >
Text File  |  1987-12-28  |  72KB  |  2,112 lines

  1. Microsoft Systems Journal
  2. Volume 2; Issue 5; November, 1987
  3.  
  4. Code Listings For:
  5.  
  6.     MDM_DRV
  7.     pp. 51-65
  8.  
  9. Author(s): Ross M. Greenberg
  10. Title:     A Strategy for Building And Debugging Your FIrst MS-DOS 
  11.            Device Driver
  12.  
  13.  
  14.  
  15. ;; Code listings for MDM-DRV.ASM and DEBUG.ASM
  16.  
  17.  
  18. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  19. ;;      MDM_DRV.ASM     An XMODEM Device Driver
  20. ;;
  21. ;;      Copyright       1987, Ross M. Greenberg
  22. ;;
  23. ;;      This program is a device driver which enables a simply DOS command
  24. ;;      such as:
  25. ;;
  26. ;;      C>COPY MDM FILENAME.EXT
  27. ;;
  28. ;;      to automatically use the popular XMODEM/Checksum protocol for
  29. ;;      transferring files through the serial port.
  30. ;;
  31. ;;      The current version of the code expects there to be a Hayes
  32. ;;       compatible modem atached to the serial port.
  33. ;;
  34. ;;      To compile and use this program, type the following commands (you
  35. ;;      must have MASM4.0):
  36. ;;
  37. ;;
  38. ;;      C> MASM MDM_DRV;
  39. ;;      C> LINK MDM_DRV;
  40. ;;      C> EXE2BIN MDM_DRV.EXE MDM_DRV.SYS
  41. ;;
  42. ;;      Remember that you must include a line of the form:
  43. ;;
  44. ;;      DEVICE=C:\devices\MDM_DRV.SYS
  45. ;;
  46. ;;      in your CONFIG.SYS file on the disk you usually boot from.
  47. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  48.  
  49. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  50. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  51.  
  52. ;DEBUG   equ     0                               ; remove the semi colon
  53.                                                 ; to get debug messages
  54. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  55. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  56.  
  57.  
  58. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  59. ;;
  60. ;;                      GLOBAL DEFINITIONS
  61. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  62.  
  63. MAX_CMD         equ     16      ; total number of commands in this driver
  64.  
  65. TIMER_ADD       equ     (01ch * 4h)
  66.  
  67. NULL    equ     0
  68. TRUE    equ     1
  69. FALSE   equ     0
  70.  
  71. FULLBLKSIZE     equ     (128 + 3 + 1)   ; Total size of an XMODEM/Checksum
  72.                                  ; block. SOH + BLK + ~BLK + DATA + CHK
  73. BLKSIZE         equ     (128)           ; Number of data bytes in an XMODEM Blk
  74. NAK_MAX         equ     5               ; Total number of NAKs before an abort
  75.  
  76. SOH     equ     01h             ; the first character of an XMODEM block
  77. EOT     equ     04h             ; End of transmission in XMODEM
  78. ACK     equ     06h             ; Last block received alright
  79. NAK     equ     015h            ; Last block was not received properly
  80. ABORT   equ     018h            ; Abort (CANcel) this transfer
  81.  
  82. CR      equ     0dh
  83. LF      equ     0ah
  84. ESCAPE  equ     01bh
  85.  
  86. LEFT_BRACKET    equ     '['             ; characters output by the STAT
  87. RIGHT_BRACKET   equ     ']'             ; macro.
  88. DOT             equ     '.'
  89. STAR            equ     '*'
  90. QUESTION        equ     '?'
  91. EXCLAIM         equ     '!'
  92. DUP_BLK          equ     'D'
  93.  
  94.  
  95. ONE_SECOND      equ     18
  96. TEN_SECONDS     equ     (ONE_SECOND * 10)
  97. ONE_MINUTE      equ     (ONE_SECOND * 60)
  98. FOREVER         equ     -1                      ; or close enough!
  99.  
  100. ERROR           equ     08000h                  ; general error bit
  101. BUSY            equ     0200h                   ; Device Busy Bit
  102. DONE            equ     0100h                   ; command finished
  103.  
  104. UNK_COMMAND     equ     03h
  105. WRITE_ERROR     equ     0ah
  106. READ_FAULT      equ     0bh
  107. GEN_FAILURE     equ     0ch
  108. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  109. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  110. ;;
  111. ;;                              MACRO DEFINITIONS
  112. ;;
  113. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  114. ;;      STAT    <arg>
  115. ;;
  116. ;;      This macro simply outputs the character represtned by <arg>.
  117. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  118. STAT            macro   arg
  119.         push    ax
  120.         mov     al, arg
  121.         call    o_char
  122.         pop     ax
  123.  
  124. endm
  125.         
  126.  
  127. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  128. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  129. ;;      PUSHALL
  130. ;;      POPALL
  131. ;;
  132. ;;       PUSHALL_AX
  133. ;;      POPALL_AX
  134. ;;
  135. ;;      Simple macros for saving all the registers, then another to pop them
  136. ;;      back.
  137. ;;
  138. ;;      The "_AX" macors do not save or restore the AX Register
  139. ;;
  140. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  141. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  142. PUSHALL         macro
  143.         pushf
  144.         push    ax
  145.         push    bx
  146.         push    cx
  147.         push    dx
  148.  
  149.         push    si
  150.         push    di
  151.  
  152.  push    bp
  153.  
  154.         push    ds
  155.         push    es
  156. endm
  157. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  158. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  159. POPALL          macro
  160.         pop     es
  161.         pop     ds
  162.  
  163.         pop     bp
  164.  
  165.         pop     di
  166.         pop     si
  167.  
  168.         pop     dx
  169.         pop     cx
  170.         pop     bx
  171.         pop     ax
  172.  popf
  173. endm
  174. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  175. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  176. PUSHALL_AX      macro
  177.         pushf
  178.         push    bx
  179.         push    cx
  180.         push    dx
  181.  
  182.         push    si
  183.         push    di
  184.  
  185.         push    bp
  186.  
  187.         push    ds
  188.         push    es
  189. endm
  190.  
  191. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  192. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  193. POPALL_AX       macro
  194.         pop     es
  195.         pop     ds
  196.  
  197.         pop     bp
  198.  
  199.         pop     di
  200.         pop     si
  201.  
  202.         pop     dx
  203.         pop     cx
  204.         pop     bx
  205.         popf
  206. endm
  207.  
  208. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  209. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  210. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  211.  
  212. code     segment public  'CODE'
  213.  
  214. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  215. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  216. ;;
  217. ;;      The driver itself is one large procedure, called 'driver'
  218. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  219. driver  proc    far
  220.  
  221.         assume  cs:code, ds:code, es:code       ; each segment should
  222.                                                 ; point to the code segment
  223.  
  224.         org     0                               ; drivers *must* start at
  225.                                                 ; ofset of zero
  226. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  227. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  228. ;;                      DEVICE DRIVER HEADER
  229. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  230. header1 dd      -1              ; This *must* be set to -1. Filled in by DOS
  231.         dw      0e800h          ; character device,
  232.                          ; IOCTL supported,
  233.                                 ; Output till busy,
  234.                                 ; open/close/rm supported
  235.  
  236.         dw      strat           ; point to the strategy routine
  237.         dw      ints            ; point to the interrupt routine
  238.         db      'MDM     '      ; The name of the device. Left justified,
  239.                                 ; space filled to eight characters
  240.  
  241.  
  242. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  243. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  244. ;;                      THE REQUEST HEADER
  245. ;;      The address of the Request Header is passed to the device driver
  246. ;;      when the strategy routine is called.  This address should be saved
  247. ;;      and then made available to the interrupt routine.
  248. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  249. request struc
  250. rlength db      0               ; 0  - length of pertinent data in header
  251. unit    db      0               ; 1  - unit number (not used in MDM_DRV)
  252. command  db      0               ; 2  - the actual command 
  253. status  dw      0               ; 3  - return status
  254. reserve db      8 dup (0)       ; 5  - Reserved for DOS
  255. media   db      0               ; 13 - Media desciptor. (Not used in MDM_DRV)
  256. address dd      0               ; 14 - Doubleword pointer for I/O
  257. count   dw      0               ; 18 - unsigned int count for character I/O
  258. sector  dw      0               ; 20 - starting sector. (Not used in MDM_DRV)
  259. request ends
  260. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  261. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  262.  
  263.  
  264. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  265. ;;      The dispatch table points to each of the routines the device
  266. ;;      driver needs.  This table is used by the interrupt routine,
  267. ;;      and the particular routine the Command Byte in the Request Header
  268. ;;      is used as index into the table.
  269. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  270. dispatch:
  271.         dw      init            ; 0x00 - init the driver. Called on install
  272.  dw      media_chk       ; 0x01 - media check (Not used in MDM_DRV)
  273.         dw      bld_bpb         ; 0x02 - Build the BPB (Not used by MDM_DRV)
  274.         dw      rd_ioctl        ; 0x03 - Read IOCTL
  275.         dw      read            ; 0x04 - Read 'count' characters
  276.         dw      nd_read         ; 0x05 - Non-destructive character read
  277.         dw      inp_stat        ; 0x06 - Input Status
  278.         dw      inp_flush       ; 0x07 - Input Flush
  279.         dw      write           ; 0x08 - Write 'count' characters to device
  280.         dw      write_vfy       ; 0x09 - Write Verify
  281.         dw      out_stat        ; 0x0A - Output Status
  282.         dw      out_flush       ; 0x0B - Fluch Output Buffers
  283.         dw      wrt_ioctl       ; 0x0C - Write IOCTL
  284.         dw      dev_open        ; 0x0D - Device Open (DOS 3.x only)
  285.         dw      dev_close       ; 0x0E - Device Close (DOS 3.x only)
  286.         dw      rem_media       ; 0x0F - Removable Media Routine (DOS 3.x only)
  287.         dw      out_busy        ; 0x10 - Output Until Busy (DOS 3.x only)
  288.                                         
  289. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  290. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  291. ;;                      STRATEGY ROUTINE
  292. ;;
  293. ;;      This rouinte merely stored the address of the Request header found
  294. ;;      on entry in the ES:BX register pair.
  295. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  296. strat   proc    far
  297.  
  298.         mov     word ptr cs:[rh_ptr], bx
  299.         mov     word ptr cs:[rh_ptr + 2], es
  300.         ret
  301.  
  302. strat   endp
  303. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  304. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  305.  
  306.  
  307. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  308. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  309. ;;                              GLOBAL VARIABLES
  310. ;;
  311. ;;      These variables are used for a variety of purposes.  Additionally
  312. ;;       the 'com_port' variable is the first value returned or written to
  313. ;;      for IOCTL READ and IOCTL WRITE calls, allowing application programs
  314. ;;      to change the communications port, baud rate and other information
  315. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  316.  
  317. com_port        dw      0               ; the comm port we are communicating
  318.                                         ; with. COM1 = 0, COM2 = 1, etc.
  319. init_data       db      10000011b       ; The initialization byte. See the
  320.                                         ; BIOS Technical Reference Manual for
  321.                                         ; details.
  322. block_num       dw      0               ; current block being transferred
  323. abort_xfer      dw      0               ; whether the current transfer is to
  324.                                         ; aborted. (TRUE = YES)
  325. nak_cnt         dw      0               ; How many Nak's have been sent or
  326.                                         ; received
  327.  
  328. inrequest       dw      0               ; the number of bytes not yet processed
  329. in_block        dw      0               ; has a block been received?
  330. was_dialed      dw      0               ; if set, stat was offline at start
  331. eof_flag        dw      0               ; set if eof seen in read
  332.  
  333. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  334. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  335.  
  336. new_stack       dw      128 dup (0)     ; 128 words for the new stack
  337. new_stack_end   dw      0
  338.  
  339. old_stack       dw      0               ; store old stack offset
  340.                 dw      0               ; store old stack segment
  341.  
  342. timer           dw      0               ; the timer count
  343. old_timer       dw      0               ; store old timer offset
  344.                 dw      0               ; store old timer segment
  345.  
  346. rh_ptr          dd      0               ; this is where the Request Header
  347.                                         ; address is stored
  348.  
  349. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  350. ;;      The I/O buffer, which looks like an XMODEM block
  351. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  352.  
  353. _soh            db      0               ; This will be an SOH
  354. _blk1           db      0               ; the block number
  355. _blk2           db      0               ;    and its complement
  356. _buf            db      128 dup (0)     ; the actual data
  357. _chksum         db      0               ; the sum of all data bytes
  358.  
  359. _outptr         dw      _buf            ; points to next character to be output
  360. _outcnt         dw      0               ; how many characters to be output
  361.  
  362. _inptr          dw      _soh            ; points to next input position
  363. _incnt          dw      0               ; the number of chars in the buffer
  364.  
  365. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  366. ;;      A variety of messages
  367. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  368.  
  369. offline db      CR, LF, 'You are currently off line. Enter number to dial (or <RET> t
  370. o answer): $'
  371. dialing db      CR, LF, 'Dialing...standby....$'
  372. no_con   db      CR, LF, 'Could not connect to remote.....', CR, LF, LF, '$'
  373. con     db      CR, LF, 'Connected to remote...<ESC> to continue', CR, LF, LF, '$'
  374. xfer    db      CR, LF, 'Starting Transfer Request...', CR, LF, LF, '$'
  375. await   db      CR, LF, 'Waiting for Carrier....', CR, LF, '$'
  376. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  377.  
  378. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  379. kb_len          dw      0                       ; number of chars in num_buf
  380. answerstring    db      'ATS0=1', CR, NULL      ; Output for Autoanswer
  381. dialstring      db      'ATDT', NULL            ; Output for AutoDial
  382. numbuf          db      20      dup (0)         ; and the number to dial
  383. return          db      CR, NULL
  384. pluses          db      '+++', NULL             ; used in hanging up
  385. hangup          db      'ATH', CR, NULL         ; the hang-up-the-modem string
  386. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  387.  
  388.  
  389. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  390. IFDEF   DEBUG                                   ; commented out above
  391. include         debug.asm                       ; debug procedures
  392. ELSE
  393.         DO_PRINT        macro   arg             ; else empty macros
  394.         endm
  395.         DO_ERR_PRINT    macro   arg
  396.         endm
  397. ENDIF
  398. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  399.  
  400.  
  401. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  402. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  403. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  404.  
  405.  
  406. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  407. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  408. ;;                              INTERRUPT ROUTINE
  409. ;;
  410. ;;      The main interrupt routine sets up a local stack, pushes all
  411. ;;      registers onto the new stack, gets the Request Header, determines
  412. ;;       if the Command Byte is a legitimate one and returns an error
  413. ;;      condition if it isn't.
  414. ;;
  415. ;;      Otherwise the Command Byte is used as an index into the dispatch
  416. ;;      table, and a near call is generated to the approriate routine.
  417. ;;      Since DOS doesn't casre about the Done Bit being set in the event
  418. ;;      of an error, this bit gets OR'ed in upon return of the new status
  419. ;;      in the AX register.  The status is then saved in the Request Header,
  420. ;;      all registers are popped, and the original stack is restored.
  421. ;;
  422. ;;      Finally, a far return to the caller (which should be DOS)
  423. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  424. ints    proc    far
  425.  
  426.         cli
  427.         mov     cs:[old_stack], sp
  428.         mov     cs:[old_stack + 2], ss
  429.         mov     sp, cs
  430.         mov     ss, sp
  431.         mov     sp, offset cs:new_stack_end
  432.  sti
  433.  
  434.         PUSHALL
  435.  
  436.         push    cs
  437.         pop     ds
  438.  
  439.         les     di, cs:[rh_ptr]
  440.         mov     bl, es:[di.command]
  441.         xor     bh, bh
  442.         cmp     bx, MAX_CMD
  443.         jle     ints1
  444.  
  445.         mov     ax, ERROR + UNK_COMMAND
  446.         jmp     ints2
  447.  
  448. ints1:
  449.         shl     bx, 1
  450.  
  451.         call    word ptr dispatch[bx]
  452.  
  453.         les     di, cs:[rh_ptr]                 ; reset just in case...
  454.  
  455. ints2:
  456.         or      ax, DONE                        ; Set the done flag
  457.         mov     es:[di.status], ax              ; Save status in the structure
  458.  
  459.  
  460.         POPALL
  461.  
  462.         cli
  463.         mov     ss, cs:[old_stack + 2]
  464.         mov     sp, cs:[old_stack]
  465.         sti
  466.  
  467.         ret
  468.  
  469. ints    endp
  470. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  471.  
  472. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  473. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  474. ;;              READ ROUTINE
  475. ;;
  476. ;;      This routine first saves the original charactrer count request, then
  477. ;;      zeros out the original call value, and loads up the "to" buffer
  478. ;;      address.
  479. ;;
  480. ;;      If it as already processing a block, meaning that the last read
  481. ;;      request did not exhaust the buffer totally, then it skips down
  482. ;;      and starts loading characters one at a time (a reps would work just
  483. ;;      as well!), until either the read request is exhausted or the buffer
  484. ;;      is exhausted.
  485. ;;
  486. ;;      When the block is exhausted, an ACK is sent to the remote which
  487. ;;      will then start to send another block.
  488. ;;
  489. ;;      The in_block variable is turned off, and a jump to the top of
  490. ;;      thr routine is made, where data is collected a character at a time
  491. ;;      until another full block is reached, verified and the entire routine
  492. ;;       starts again.
  493. ;;
  494. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  495. read            proc    near
  496.         DO_PRINT        msg_read
  497.         cmp     cs:[eof_flag], TRUE
  498.         jz      r_back
  499.  
  500.         mov     ax, es:[di.count]
  501.         mov     cs:[inrequest], ax              ; save the request count
  502.         mov     es:[di.count], FALSE            ; and zero the rh count
  503.         lds     bx, es:[di.address]             ; ds:bx points to data
  504.  
  505. top_read:
  506.         cmp     cs:[in_block], TRUE             ; are we in a block?
  507.         jnz     lp_it
  508.         jmp     read_loop                       ; yes
  509.  
  510. lp_it:
  511.         mov     cs:[_incnt], FALSE
  512.  mov     si, offset cs:[_soh]            ; set pointer to block begin
  513.         mov     cs:[timer], TEN_SECONDS         ; set up timer
  514.         mov     cs:[nak_cnt], FALSE             ; set to no NAKS
  515.         cmp     cs:[block_num], 1               ; first time?
  516.         jnz     rd_blk                          ; no
  517.         call    send_nak                        ; send the first NAK
  518.         STAT    LEFT_BRACKET                    ; show a '['
  519.  
  520. rd_blk:
  521.         call    get_char                        ; any characters?
  522.         jc      rd_blk2                         ; no
  523.  
  524.         cmp     cs:[_incnt], FALSE              ; first character?
  525.         jnz     nxt_char                        ; no
  526.  
  527.         cmp     al, SOH                         ; first character an SOH?
  528.         jz      nxt_char                        ; yes. store it
  529.  
  530.         cmp     al, ABORT                       ; Abort xfer?
  531.         jz      abort_it                        ; yep. Abort it!
  532.  
  533.         cmp     al, EOT                         ; are we done?
  534.         jnz     rd_blk                          ; nope, so throw char away
  535.  
  536.         call    send_ack                        ; process EOF
  537.         STAT    RIGHT_BRACKET                   ; show a ']'
  538.         STAT    CR                              ; and a clean line
  539.         STAT    LF
  540. r_back:
  541.         mov     es:[di.count], FALSE            ; and zero the rh count
  542.         mov     cs:[eof_flag], TRUE
  543.         xor     ax, ax
  544.         ret
  545.  
  546. nxt_char:
  547.         mov     cs:[si], al                     ; store it
  548.         inc     cs:[_incnt]                     ; bump the character count
  549.         inc     si                              ; and the pointer
  550.  
  551. rd_blk2:
  552.  cmp     cs:[_incnt], FULLBLKSIZE        ; enough bytes to check?
  553.         jz      chkblk
  554.  
  555.         cmp     cs:[timer], FALSE               ; out of time?
  556.         jnz     rd_blk                          ; nope. try again
  557.         STAT    DOT                             ; show a dot
  558.         jmp     bad_blk2
  559. bad_blk:
  560.         STAT    QUESTION                        ; show a question mark
  561. bad_blk2:
  562.         call    send_nak                        ; yep. send a NAK
  563.         cmp     word ptr cs:[abort], TRUE       ; abort?
  564.         jnz     rd_blk3                         ; no, so reset timer, try again
  565.  
  566. abort_it:
  567.         call    send_abort                      ; send an abort
  568.         call    send_abort                      ; twice
  569.         STAT    EXCLAIM                         ; finish with a bang!
  570.         mov     ax, 800ch                       ; mark an error
  571.         ret
  572.  
  573. rd_blk3:
  574.         mov     cs:[timer], TEN_SECONDS         ; reset the timer
  575.         jmp     rd_blk                          ; and try again
  576.  
  577. chkblk:
  578.         mov     ax, cs:[block_num]
  579.         push    ax
  580.  
  581.         dec     al                              ; temporary
  582.         cmp     al, cs:[_blk1]                  ; duplicate block?
  583.         jnz     real_blk                        ; no
  584.         STAT    DUP_BLK                         ; yes
  585.         mov     cs:[_incnt], FALSE
  586.         jmp     ack_blk
  587.  
  588. real_blk:
  589.         pop     ax                              ; back up to correct block
  590.  
  591.         cmp     cs:[_blk1], al                  ; is the block count alright?
  592.  jnz     bad_blk                         ; no
  593.         not     al
  594.         cmp     cs:[_blk2], al                  ; block complement?
  595.         jnz     bad_blk                         ; no
  596.  
  597.         mov     cx, BLKSIZE
  598.         mov     si, offset _buf
  599.         call    do_chksum
  600.         cmp     cs:[_chksum], al
  601.         jnz     bad_blk                         ; checksum bad
  602.  
  603.         mov     cs:[in_block], TRUE             ; looks good!
  604.         mov     cs:[_inptr], offset cs:_buf     ; set up pointer
  605.         sub     cs:[_incnt], FULLBLKSIZE - BLKSIZE
  606.  
  607. read_loop:
  608.         mov     si, cs:[_inptr]                 ; reset the pointer
  609. rd_loop:
  610.         mov     al, cs:[si]                     ; get the character
  611.         mov     ds:[bx], al                     ; and stuff it
  612.  inc     bx                              ; up each pointer
  613.         inc     si
  614.         inc     cs:[_inptr]
  615.  
  616.         inc     word ptr es:[di.count]          ; inc the counter
  617.         dec     cs:[_incnt]                     ; drop the characters left
  618.         jnz     stf_nxt_char                    ; still more!
  619.  
  620.         inc     cs:[block_num]
  621.         STAT    STAR                            ; send a '*'
  622. ack_blk:
  623.         call    send_ack                        ; send the ack
  624.         mov     cs:[in_block], FALSE            ; out of characters
  625.         dec     cs:[inrequest]
  626.         jz      read_back
  627.         jmp     top_read
  628.  
  629. stf_nxt_char:
  630.         dec     cs:[inrequest]                  ; anymore?
  631.         jnz     rd_loop
  632.  
  633. read_back:
  634.         xor     ax,ax                           ; no more request, no errors
  635.         ret
  636. read            endp
  637. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  638.  
  639. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  640. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  641. ;;                      WRITE ROUTINE
  642. ;;
  643. ;;      This routine starts loading characters one at a time (again a reps
  644. ;;      could be used) into a local buffer.  When the total number of
  645. ;;      characters collected (some of which may be left over from last
  646. ;;      time through) reaches 128, then the send_block routine is
  647. ;;      called.
  648. ;;
  649. ;;      The return from the send_block routine only happens if there
  650. ;;      was a successful ACK, or too many NAKs have been sent, which
  651. ;;      causes the abort flag to be set.
  652. ;;
  653. ;;      Stay in this loop until there are no more characters to store and
  654. ;;      send, as per the original character count from the Request Header
  655. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  656. write           proc    near
  657.         PUSHALL_AX
  658.  
  659.         DO_PRINT        msg_write
  660.  
  661.         mov     cx, es:[di.count]               ; how many bytes?
  662.         xor     dx, dx                          ; zero our character count
  663.         mov     es:[di.count], dx               ; zero out reciept area
  664.  
  665.         lds     bx, es:[di.address]             ; ds:bx points to data
  666.  
  667.         mov     si, cs:[_outptr]                ; where to stick each char
  668. wr_lp:
  669.         mov     al, ds:[bx]                     ; get the character
  670.         mov     cs:[si], al                     ; and save it in buffer
  671.         inc     bx                              ; move pointers
  672.  inc     cs:[_outcnt]                    ; total character count
  673.         inc     es:[di.count]                   ; and current character count
  674.  
  675.         cmp     cs:[_outcnt], BLKSIZE           ; time to send a block?
  676.         jnz     wr_ok                           ; not yet
  677.         call    send_block                      ; send the block
  678.         cmp     cs:[abort_xfer], FALSE          ; should we abort?
  679.         jz      blk_ok                          ; no, block sent okay
  680.  
  681.         call    send_abort                      ; yes,
  682.         call    send_abort                      ; send it twice!
  683.  
  684.         mov     es:[di.count], FALSE            ; mark no characters as sent
  685.         mov     ax, ERROR + WRITE_ERROR         ; mark as a write error
  686.         ret
  687.  
  688. blk_ok:
  689.         mov     cs:[_outptr], offset _buf       ; reset the pointer,
  690.         mov     si, offset _buf                 ; the register,
  691.         mov     cs:[_outcnt], FALSE             ; and the number of chars
  692.   
  693. wr_ok:
  694.         inc     si                              ; point to next char position
  695.         loop    wr_lp
  696.  
  697.         mov     cs:[_outptr], si                ; now save it
  698.         xor     ax, ax                          ; no errors
  699.         POPALL_AX
  700.         ret
  701. write           endp
  702. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  703.  
  704.  
  705.  
  706. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  707. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  708. ;;              WRITE WITH VERIFY ROUTINE
  709. ;;
  710. ;;      This routine simply jumps to the "regular" write routine.
  711. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  712. write_vfy        proc    near
  713.         DO_PRINT        msg_write_vfy
  714.         jmp     write
  715. write_vfy       endp
  716. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  717.  
  718.  
  719.  
  720. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  721. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  722. ;;                      DEVICE OPEN ROUTINE
  723. ;;
  724. ;;      After setting counts to their initial, startup condition, this
  725. ;;      routine steals the timer tick, then initializes the comm port
  726. ;;      to the parameters stored in the init_data variable, then gets
  727. ;;      the status of the comm port.
  728. ;;
  729. ;;      It eats all characters available on the comm port, then calls
  730. ;;      the dial_rout routine which will attempt to put the attached device
  731. ;;      on-line if it isn't already.
  732. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  733. dev_open        proc    near
  734.         PUSHALL_AX
  735.         DO_PRINT        msg_dev_open
  736.  
  737.         mov     cs:[_inptr], offset cs:_soh
  738.         mov     cs:[_incnt], FALSE
  739.  
  740.         mov     cs:[_outptr], offset cs:_buf
  741.         mov     cs:[_outcnt], FALSE
  742.  
  743.         mov     cs:[in_block], FALSE
  744.         mov     cs:[block_num], 1
  745.  
  746.         mov     dx, cs:[com_port]       ; init the comm port
  747.         mov     al, cs:[init_data] 
  748.         mov     ah, 0
  749.         int     14h
  750.  
  751. eat_loop:
  752.  mov     dx, ds:[com_port]
  753.         mov     ah, 3                   ; get status
  754.         int     14h
  755.  
  756.         test    ah, 1                   ; any data ready?
  757.         jz      continue                ; no
  758.         test    al, 20h                 ; DSR must be set, or next int14
  759.         jz      continue                ; will (basically) never return
  760.  
  761.         mov     ah, 2
  762.         int     14h                     ; eat the character and
  763.         jmp     eat_loop                ; try again
  764.  
  765. continue:
  766.         call    dial_rout               ; if not on line, make on line
  767.  
  768.         xor     ax, ax
  769.         POPALL_AX
  770.         ret
  771. dev_open        endp
  772.  
  773.  
  774. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  775.  
  776.  
  777. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  778. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  779. ;;              DEVICE CLOSE ROUTINE
  780. ;;
  781. ;;      A check is made to determine if there is a partial block to be
  782. ;;      sent (127/128 chance!), and if so, the block is sent, and an EOT
  783. ;;      is sent to indicate end of transmission.
  784. ;;
  785. ;;      If this was a "dialed" call (either Autoanswer or AutoDial), then
  786. ;;      the Hayes hangup sequence is generated (1 second pause, output three
  787. ;;      plus signs, 1 second pause, then a ATH followed by a <CR>).
  788. ;;
  789. ;;      In any case, the timer tick (originally set in the dev_open routine)
  790. ;;      is reset and then control is returned to the caller
  791. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  792. dev_close        proc    near
  793.         DO_PRINT        msg_dev_close
  794.  
  795.         mov     cs:[eof_flag], FALSE
  796.  
  797.         cmp     cs:[_outcnt], FALSE             ; any characters left?
  798.         jz      no_send                         ; no
  799.  
  800.         call    send_block                      ; yes. send the remainder
  801.         STAT    RIGHT_BRACKET
  802.         STAT    CR
  803.         STAT    LF
  804.         mov     cs:[_outptr], offset _buf       ; reset the pointer,
  805.         mov     si, offset _buf                 ; the register,
  806.         mov     cs:[_outcnt], FALSE             ; and the number of chars
  807.         inc     cs:[block_num]                  ; just in case....
  808.  
  809. no_send:
  810.         cmp     cs:[block_num], 1               ; was at least one block sent?
  811.         jz      no_hang                         ; no
  812.  
  813.         mov     al, EOT                         ; send the EOT
  814.         mov     ah, 1
  815.         mov     dx, cs:[com_port]
  816.         int     14h
  817.  
  818.         cmp     cs:[was_dialed], TRUE           ; were we the dialer?
  819.         jnz     no_hang
  820.  
  821.         call    do_hang                         ; send the +++ATH
  822.  
  823. no_hang:
  824.         mov     cs:[in_block], FALSE
  825.         mov     cs:[was_dialed], FALSE
  826.  
  827.         xor     ax, ax
  828.         ret
  829. dev_close       endp
  830. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  831.  
  832. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  833. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  834. ;;              NON-DESTRUCTIVE READ ROUTINE
  835. ;;
  836. ;;      This routine returns the next character in the input buffer if
  837. ;;      there is one.
  838. ;;
  839. ;;      In the event of an empty buffer, it returns a '?' and an
  840. ;;      error condition
  841. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  842. nd_read         proc    near
  843.         DO_PRINT        msg_nd_read
  844.         PUSHALL_AX
  845.  
  846.         mov     es:[di.count], 1                ; we always return some count
  847.         lds     bx, es:[di.address]             ; ds:bx points to data buffer
  848.         cmp     cs:[_incnt], FALSE              ; any characters?
  849.         jnz     get_nd_char                     ; yes!
  850.  
  851.         mov     ax, ERROR + READ_FAULT          ; mark an error condition
  852.  mov     byte ptr es:[bx], '?'
  853.         jmp     nd_return
  854.  
  855. get_nd_char:
  856.         xor     ax, ax                          ; no error
  857.         mov     si, cs:[_inptr]
  858.         mov     al, cs:[si]                     ; get the next character
  859.         mov     es:[bx], al
  860.  
  861. nd_return:
  862.         POPALL_AX
  863.         ret
  864. nd_read         endp
  865. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  866.  
  867. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  868. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  869. ;;                      INPUT STATUS ROUTINE
  870. ;;
  871. ;;      This routine simply examines the in_block variable to determine
  872. ;;       if there are any outstanding characters (from a good block) and
  873. ;;      returns the BUSY bit set if there are.
  874. ;;
  875. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  876. inp_stat        proc    near
  877.         DO_PRINT        msg_inp_stat
  878.         xor     ax,ax                   ; start off empty
  879.         cmp     cs:[in_block], FALSE    ; are we in a block
  880.         jz      no_chars                ; no
  881.  
  882.         or      ax, BUSY                ; yes. mark it
  883. no_chars:
  884.         ret
  885. inp_stat        endp
  886. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  887.  
  888. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  889. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  890. ;;              FLUSH INPUT BUFFER ROUTINE
  891. ;;
  892. ;;       This routine simply resets pointers and counts to indicate an
  893. ;;      empty input buffer
  894. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  895. inp_flush       proc    near
  896.         DO_PRINT        msg_inp_flush
  897.  
  898.         mov     cs:[_inptr], offset cs:_soh
  899.         mov     cs:[_incnt], FALSE
  900.  
  901.         xor     ax, ax
  902.         ret
  903. inp_flush       endp
  904. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  905.  
  906. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  907. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  908. ;;              OUTPUT STATUS ROUTINE
  909. ;;
  910. ;;      This is, basically, a do nothing routine, since the write routine
  911. ;;      never exits with a busy status.  If it did, then the status would
  912. ;;       be examined and the BUSY bit set if required.  Here, it is left
  913. ;;      unset.
  914. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  915. out_stat        proc    near
  916.         DO_PRINT        msg_out_stat
  917.  
  918.         xor     ax, ax
  919.         ret
  920. out_stat        endp
  921. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  922.  
  923. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  924. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  925. ;;              FLUSH OUTPUT BUFFERS ROUTINE
  926. ;;
  927. ;;      This routine would make things very difficult to sort out if
  928. ;;      it were to actually flush the output buffers.  As such, it is
  929. ;;      a "do-nothing" routine.
  930. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  931. out_flush       proc    near
  932.  DO_PRINT        msg_out_flush
  933.  
  934.         xor     ax, ax
  935.         ret
  936. out_flush       endp
  937.  
  938. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  939. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  940. ;;              READ I/O CONTROL ROUTINE
  941. ;;
  942. ;;      This routine simply copies 'count' bytes into the address specified
  943. ;;      as the transfer address, starting at the com_port variable.
  944. ;;
  945. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  946. rd_ioctl        proc    near
  947.         DO_PRINT        msg_rd_ioctl
  948.         ret
  949. rd_ioctl        endp
  950. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  951.  
  952. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  953. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  954. ;;              Write I/O CONTROL ROUTINE
  955. ;;
  956. ;;      This routine simply copies 'count' bytes from the address specified
  957. ;;      as the transfer address, starting at the com_port variable.
  958. ;;
  959. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  960. wrt_ioctl       proc    near
  961.         DO_PRINT        msg_wrt_ioctl
  962.         ret
  963. wrt_ioctl       endp
  964. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  965.  
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  974. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  975. ;;              These routines are not used by this driver
  976. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  977. media_chk       proc    near
  978.         DO_ERR_PRINT    msg_media_chk
  979.         xor     ax,ax
  980.         ret
  981. media_chk       endp
  982.  
  983. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  984.  
  985. bld_bpb         proc    near
  986.         DO_ERR_PRINT    msg_bld_bpb
  987.         xor     ax,ax
  988.         ret
  989. bld_bpb         endp
  990.  
  991. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  992.  
  993. rem_media       proc    near
  994.         DO_ERR_PRINT    msg_rem_media
  995.         xor     ax,ax
  996.         ret
  997. rem_media       endp
  998.  
  999. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1000.  
  1001. out_busy        proc    near
  1002.         DO_ERR_PRINT    msg_out_busy
  1003.         xor     ax,ax
  1004.         ret
  1005. out_busy        endp
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1013. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1014. ;;                              GENERALIZED ROUTINES
  1015. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1016.  
  1017.  
  1018. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1019. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1020. ;;      TIMER TICK:  this routine simply decrements a counter if the counter
  1021. ;;                      is non-zero
  1022. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1023. my_tick proc    far
  1024.         cmp     cs:[timer], 0                   ; and ticks to decrement?
  1025.         jz      no_dec                          ; no
  1026.         dec     cs:[timer]                      ; yes, so do it
  1027. no_dec:
  1028.         jmp     dword ptr cs:[old_timer]        ; call the original tick
  1029. my_tick endp
  1030.  
  1031. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1032. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1033. ;;      DIAL_ROUT
  1034. ;;
  1035. ;;      Called from the device open routine, this routine will simply return
  1036. ;;      if Carrier is detected.
  1037. ;;
  1038. ;;      Otherwise a message is displayed, and the user is allowed to
  1039. ;;      either input a number, or to only enter a return.  The modem then
  1040. ;;      is output a dial string or an answer string and the status is checked
  1041. ;;      until the modem is online (or until a timeout occurs).
  1042. ;;
  1043. ;;      Once on-line, any data on the comm port is displayed, and any data
  1044. ;;      at the keyboard is displayed and sent.  When an escape is discovered,
  1045. ;;      the routine returns back to the calling program.
  1046. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1047. dial_rout       proc    near
  1048.         test    al, 080h                ; DCD on?
  1049.         jz      off_line
  1050.         ret
  1051.  
  1052. off_line:
  1053.         mov     dx, offset cs:offline   ; output the message
  1054.         call    out_line
  1055.  
  1056.         mov     si, offset cs:numbuf
  1057.         mov     cx, 19                  ; maximum length
  1058.         call    get_num
  1059.  
  1060.         cmp     cs:[kb_len], 0          ; only a return?
  1061.         jnz     dial_it
  1062.  
  1063.         mov     dx, offset cs:await
  1064.         call    out_line
  1065.  
  1066.         mov     si, offset cs:answerstring
  1067.         call    out_string
  1068.         mov     cs:[timer], FOREVER
  1069.         jmp     offline_lp              ; now wait for carrier
  1070.  
  1071. dial_it:
  1072.  mov     dx, offset cs:dialing
  1073.         call    out_line
  1074.  
  1075.         mov     si, offset cs:dialstring
  1076.         call    out_string
  1077.  
  1078.         mov     si, offset cs:numbuf
  1079.         call    out_string
  1080.  
  1081.         mov     si, offset cs:return
  1082.         call    out_string
  1083.         mov     cs:[timer], ONE_MINUTE
  1084.  
  1085.         mov     cs:[was_dialed], TRUE   ; mark as a dialed call for ATH later
  1086.  
  1087. offline_lp:
  1088.         mov     ah, 3                   ; are we on-line?
  1089.         mov     dx, cs:[com_port]
  1090.         int     14h
  1091.  
  1092.  test    al, 080h                ; DCD on?
  1093.         jnz     made_con                ; yes
  1094.  
  1095.         cmp     cs:[timer], 0           ; out of time?
  1096.         jnz     offline_lp              ; nope
  1097.  
  1098. abort_call:
  1099.         mov     cs:[was_dialed], FALSE
  1100.         mov     dx, offset cs:no_con
  1101.         call    out_line
  1102.  
  1103. abort_out:
  1104.         xor     ax,ax
  1105.         mov     es:[di.count], ax       ; set count to zero
  1106.  
  1107.         mov     ax, ERROR + GEN_FAILURE ; mark as an error
  1108.         POPALL_AX
  1109.         ret
  1110.  
  1111. made_con:
  1112.  mov     dx, offset cs:con
  1113.         call    out_line
  1114.  
  1115. term_em_lp:
  1116.         call    get_char
  1117.         jc      get_term_char
  1118.  
  1119.         cmp     al, ESCAPE
  1120.         jz      term_exit               ; escape. Get out!
  1121.  
  1122.         call    o_char
  1123.  
  1124. get_term_char:
  1125.         mov     ah, 1h
  1126.         int     16h                     ; any characters?
  1127.         jz      term_em_lp              ; nope
  1128.         mov     ah, 0                   ; yep. get the character
  1129.         int     16h
  1130.  
  1131.         mov     ah, 1
  1132.  mov     dx, ds:[com_port]
  1133.         int     14h
  1134.  
  1135.         cmp     al, ESCAPE
  1136.         jz      term_exit               ; escape. Get out!
  1137.  
  1138.         call    o_char
  1139.  
  1140.         jmp     get_term_char
  1141.  
  1142. term_exit:
  1143.         mov     dx, offset cs:xfer      ; status message
  1144.         call    out_line
  1145.  
  1146. eat_c:
  1147.         call    get_char
  1148.         jnc     eat_c
  1149.  
  1150.         ret
  1151. dial_rout       endp
  1152. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1153. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1154.  
  1155. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1156. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1157. ;;              SEND_BLOCK ROUTINE
  1158. ;;
  1159. ;;      This is the generalized XMODEM Send-A-Block Routine.
  1160. ;;
  1161. ;;      If this is the first time since dev_open that this routine is
  1162. ;;      called, then the block count will be set to 1.  Wait for the
  1163. ;;      initial NAK from the remote before sending, or wait for a time
  1164. ;;      out.
  1165. ;;
  1166. ;;      Send the block, then wait for the ACK or NAK response.  If an ACK,
  1167. ;;      return immediately.  If a NAK, then try again, until the error
  1168. ;;      count gets too high.  If too high, set the abort flag and return.
  1169. ;;      
  1170. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1171. send_block      proc    near
  1172.  PUSHALL
  1173.         push    cs
  1174.         pop     ds
  1175.  
  1176.         cmp     cs:[block_num], 1               ; is this the first block?
  1177.         jnz     not_first                       ; no
  1178.         STAT    LEFT_BRACKET
  1179.  
  1180. first_nak:
  1181.         call    get_ack                         ; get the first ack
  1182.         cmp     al, NAK                         ; was it a NAK?
  1183.         jnz     first_nak                       ; nope
  1184.  
  1185. not_first:
  1186.         mov     word ptr ds:[_soh], SOH
  1187.         mov     ax, cs:[block_num]
  1188.         mov     ds:[_blk1], al
  1189.         not     al
  1190.         mov     ds:[_blk2], al
  1191.  
  1192.  mov     cx, BLKSIZE
  1193.         mov     si, offset _buf
  1194.         call    do_chksum
  1195.         mov     cs:[_chksum], al
  1196.  
  1197. send_top:
  1198.         mov     cx, FULLBLKSIZE
  1199.         mov     si, offset _soh
  1200.  
  1201. send_lp:
  1202.         mov     ah, 1
  1203.         mov     al, ds:[si]
  1204.         mov     dx, cs:[com_port]
  1205.         int     14h
  1206.  
  1207.         inc     si
  1208.         loop    send_lp
  1209.  
  1210.         call    get_ack
  1211.         jnc     send_ok
  1212.  
  1213.         STAT    QUESTION
  1214.         inc     cs:[nak_cnt]            ; error. inc the counter
  1215.         cmp     cs:[nak_cnt], NAK_MAX   ; too many blocks?
  1216.         jle     send_top                ; no. try again
  1217.         mov     cs:[abort_xfer], TRUE   ; mark for abort
  1218.         STAT    EXCLAIM
  1219.         jmp     send_back               ; return
  1220.  
  1221. send_ok:
  1222.         STAT    STAR
  1223.         inc     cs:[block_num]          ; block sent okay, inc the counter
  1224.         mov     cs:[nak_cnt], FALSE     ; reset the nak counter
  1225.  
  1226. send_back:
  1227.         POPALL
  1228.         ret
  1229. send_block      endp
  1230.  
  1231.  
  1232. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1233. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1234. ;;              GET_ACK ROUTINE
  1235. ;;
  1236. ;;      This routine will return with the carry flag set if an NAK was
  1237. ;;      received or if it times out.
  1238. ;;
  1239. ;;      Carry clear if the character received is an ACK
  1240. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1241. get_ack proc    near
  1242.  
  1243. not_ack:
  1244.         mov     cs:[timer], TEN_SECONDS
  1245.  
  1246. not_yet:
  1247.         mov     ah, 3
  1248.         mov     dx, cs:[com_port]
  1249.         int     14h
  1250.  
  1251.         test    ah, 1                   ; data ready?
  1252.  jnz     data_ready              ; yes
  1253.  
  1254.         cmp     cs:[timer], 0           ; out of time?
  1255.         jnz     not_yet                 ; no
  1256.         STAT    DOT
  1257.         jmp     set_c                   ; yes. set carry and return
  1258.  
  1259. data_ready:
  1260.         mov     ah, 2
  1261.         mov     dx, cs:[com_port]
  1262.         int     14h
  1263.  
  1264.         test    ah, 087h                ; any errors?
  1265.         jnz     ack_back                ; yes
  1266.  
  1267.         cmp     al, ACK                 ; is it an ACK?
  1268.         jz      ack_back                ; yes
  1269.         cmp     al, NAK                 ; a NAK?
  1270.         jz      set_c                   ; set the carry flag for return
  1271.         cmp     al, ABORT               ; a cancel?
  1272.  jnz     not_ack                 ; try again
  1273.         mov     cs:[abort_xfer], TRUE   ; set for an abort
  1274. set_c:
  1275.         stc
  1276.         ret     
  1277.  
  1278. ack_back:
  1279.         clc
  1280.         ret
  1281.  
  1282. get_ack endp
  1283.  
  1284. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1285. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1286. ;;      Simply send an abort out the serial port
  1287. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1288. send_abort      proc    near
  1289.  
  1290.         mov     ah, 1                           ; abort by sending an abort 
  1291.         mov     al, ABORT                       ; character
  1292.  int     14h                             ; yes, abort
  1293.  
  1294.         ret
  1295. send_abort      endp
  1296.  
  1297. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1298. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1299. ;;      DO_HANG
  1300. ;;
  1301. ;;      Hang up the modem with a second of silence, +++, a second of silence
  1302. ;;      then an ATH, followed by a return
  1303. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1304. do_hang proc    near
  1305.         mov     cs:[timer], ONE_SECOND          ; one second of silence
  1306.  
  1307. sil_lp1:
  1308.         cmp     cs:[timer], FALSE               ; expired?
  1309.         jnz     sil_lp1
  1310.  
  1311.         mov     si, offset cs:pluses            ; get the modems attention
  1312.  call    out_string
  1313.  
  1314.         mov     cs:[timer], ONE_SECOND          ; one second of silence
  1315.  
  1316. sil_lp2:
  1317.         cmp     cs:[timer], FALSE               ; expired?
  1318.         jnz     sil_lp2
  1319.  
  1320.         mov     si, offset cs:hangup            ; now hangup
  1321.         call    out_string
  1322. do_hang endp
  1323.  
  1324. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1325. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1326. ;;      DO_CHKSUM ROUTINE
  1327. ;;
  1328. ;;      Starting at CS:[SI], add the next CX characters into AX
  1329. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1330. do_chksum       proc    near
  1331.  
  1332.  mov     ax, FALSE                       ; zero out the count
  1333. chk_lp:
  1334.         add     al, cs:[si]                     ; add the individual byte
  1335.         inc     si
  1336.         loop    chk_lp                          ; for each byte
  1337.  
  1338.         ret
  1339.  
  1340. do_chksum       endp
  1341.  
  1342.  
  1343. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1344. ;;      Simply send the NAK, increment the count of NAKs, and set the
  1345. ;;      abort flag if required.
  1346. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1347. send_nak        proc    near
  1348.  
  1349.         push    ax
  1350.         push    dx
  1351.  
  1352.  mov     ah, 1                           ; send the NAK
  1353.         mov     al, NAK
  1354.         mov     dx, cs:[com_port]
  1355.         int     14h
  1356.  
  1357.         mov     cs:[_incnt], FALSE
  1358.         mov     si, offset cs:[_soh]            ; set pointer to block begin
  1359.         mov     cs:[timer], TEN_SECONDS         ; set up timer
  1360.  
  1361.         inc     cs:[nak_cnt]
  1362.         cmp     cs:[nak_cnt], NAK_MAX           ; too many NAKs?
  1363.         jnz     nak_ret                         ; no
  1364.         mov     word ptr cs:[abort], FALSE      ; yes, so abort
  1365. nak_ret:
  1366.         pop     dx
  1367.         pop     ax
  1368.         ret
  1369.  
  1370. send_nak        endp
  1371. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1372.  
  1373. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1374. ;;      Simply send the ACK
  1375. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1376. send_ack        proc    near
  1377.  
  1378.         push    ax
  1379.         push    dx
  1380.  
  1381.         mov     ah, 1                           ; send the ACK
  1382.         mov     al, ACK
  1383.         mov     dx, cs:[com_port]
  1384.         int     14h
  1385.  
  1386.         pop     dx
  1387.         pop     ax
  1388.         ret
  1389. send_ack        endp
  1390. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1391.  
  1392. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1393. ;;      If there is a character at the console, get the character into al,
  1394. ;;      and clear the carry bit.  Otherwise, set the carry bit.
  1395. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1396. get_char        proc    near
  1397.         mov     ah, 3                           ; is there a character?
  1398.         mov     dx, cs:[com_port]
  1399.         int     14h
  1400.         test    ah, 1                           ; data ready?
  1401.         jnz     get_ch2                         ; yes
  1402.         stc
  1403.         ret
  1404.  
  1405. get_ch2:
  1406.         mov     ah, 2                           ; get the character
  1407.         mov     dx, cs:[com_port]
  1408.         int     14h
  1409.         clc
  1410.         ret
  1411. get_char        endp
  1412. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1413.  
  1414.  
  1415. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1416. ;;      Set the character count to zero, get upto CX number of characters
  1417. ;;      and store them into a buffer, one at a time, starting at cs:[si].
  1418. ;;
  1419. ;;      Return when CX characters have been entered, or a <CR> is hit.
  1420. ;;      kb_len will contain how many characters were entered
  1421. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1422. get_num proc    near
  1423.         mov     cs:[kb_len], FALSE
  1424. get_kbc:
  1425.         mov     ah, 0                           ; get a character from kb
  1426.         int     16h
  1427.  
  1428.         call    o_char
  1429.         cmp     al, CR                          ; if CR, return
  1430.         jnz     store
  1431.         ret
  1432.  
  1433. store:
  1434.         mov     cs:[si], al                     ; store it
  1435.         inc     si                              ; bump pointer
  1436.         xor     ax, ax
  1437.         mov     cs:[si], al                     ; zero out from last time
  1438.         inc     cs:[kb_len]
  1439.         loop    get_kbc
  1440.         ret
  1441. get_num endp
  1442. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1443.  
  1444. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1445. ;;      Output the characters through the comm port, starting at cs:[si]
  1446. ;;      until a NULL is hit.
  1447. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1448. out_string      proc    near
  1449.  
  1450. out_lp:
  1451.         mov     al, cs:[si]                     ; load the character
  1452.  cmp     al, NULL                        ; at end?
  1453.         jnz     out_it                          ; no
  1454.         ret                                     ; yes
  1455.  
  1456. out_it:
  1457.         mov     dx, cs:[com_port]               ; output the character
  1458.         mov     ah, 1
  1459.         int     14h
  1460.         inc     si
  1461.         jmp     out_lp
  1462.  
  1463. out_string      endp
  1464.  
  1465. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1466. ;;      O_CHAR
  1467. ;;
  1468. ;;      Using the BIOS Teletype Calls, this routine merely dumps the character
  1469. ;;      in al onto page 0 at the current cursor position
  1470. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1471. o_char  proc    near
  1472.  push    bx
  1473.         xor     bx,bx
  1474.         mov     ah, 0eh
  1475.         int     10h
  1476.         pop     bx
  1477.         ret
  1478. o_char  endp
  1479.  
  1480. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1481. ;;      OUT_LINE
  1482. ;;
  1483. ;;      This routine will output (via the device driver safe BIOS calls)
  1484. ;;      the string pointed to by DS:DX, which is terminated with either
  1485. ;;      a '$' or a NULL byte.  It used the O_CHAR routine for each character.
  1486. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1487. out_line        proc    near
  1488.         push    ax
  1489.         push    si
  1490.         mov     si, dx
  1491. out_line_lp:
  1492.  mov     al, cs:[si]
  1493.         cmp     al, '$'
  1494.         jz      out_line_exit
  1495.         cmp     al, NULL
  1496.         jz      out_line_exit
  1497.         call    o_char
  1498.         inc     si
  1499.         jmp     out_line_lp
  1500. out_line_exit:
  1501.         pop     si
  1502.         pop     ax
  1503.         ret
  1504. out_line        endp
  1505.  
  1506.  
  1507. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1508.  
  1509.  
  1510. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1511. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1512. ;;       INITIALIZE DRIVER ROUTINE
  1513. ;;
  1514. ;;      This routine determines if the correct DOS version is running, exiting
  1515. ;;      with an error message if it is not.
  1516. ;;
  1517. ;;      The comm port is initialized, a greeting message is displayed and
  1518. ;;      the data following the equal sign in the CONFIG.SYS file is then
  1519. ;;      displayed.
  1520. ;;
  1521. ;;      Finally, the only real requirement of the initialization routine
  1522. ;;      is accomplished: it sets the "break address" bnack in the request
  1523. ;;      header
  1524. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1525. init            proc    near
  1526.         DO_PRINT        msg_init
  1527.  
  1528.         mov     ah, 030h                        ; get the DOS version
  1529.         int     21h
  1530.  
  1531.         cmp     ah, 3                           ; version 3.x?
  1532.  jge     okay_dos                        ; yes. At least.
  1533.  
  1534.         mov     dx, offset cs:wrong_dos         ; output the message
  1535.         call    out_line
  1536.  
  1537. endless_loop:
  1538.         cli
  1539.         jmp     endless_loop                    ; very ugly, but effective!
  1540.  
  1541. okay_dos:
  1542.  
  1543.         mov     dx, offset cs:greetings         ; output the message
  1544.         call    out_line
  1545.  
  1546.         call    set_timer
  1547.  
  1548.         push    ds
  1549.         mov     ds, es:[di.count + 2]   ; get the segment of CONFIG.SYS line
  1550.         mov     si, es:[di.count]       ; get the offset of CONFIG.SYS line
  1551.         call    output_chars
  1552.  pop     ds
  1553.  
  1554.         mov     dx, offset cs:end_greetings     ; output the message
  1555.         call    out_line
  1556.  
  1557.         mov     word ptr es:[di.address], offset cs:init
  1558.         mov     word ptr es:[di.address + 2], cs
  1559.         xor     ax,ax
  1560.         ret
  1561. init            endp
  1562.  
  1563. wrong_dos       db '????You must run this device driver under DOS 3.0 or higher',
  1564.                 db CR, LF, ' System Halted! $'
  1565. greetings       db CR, LF, LF, LF, 'MDM_DRV being installed...', CR, LF
  1566.                 db 'CONFIG.SYS Line is: $'
  1567. end_greetings   db CR, LF, LF, LF, '$'
  1568.  
  1569.  
  1570.  
  1571. output_chars    proc    near
  1572.  push    ax
  1573. output_loop:
  1574.         mov     al, ds:[si]             ; get the character
  1575.         cmp     al, LF                  ; is it NULL?
  1576.         jnz     outit                   ; no
  1577.         pop     ax
  1578.         ret
  1579.  
  1580. outit:
  1581.         call    o_char                  ; output character
  1582.         inc     si
  1583.         jmp     output_loop 
  1584. output_chars    endp
  1585.  
  1586. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1587. ;;      Save the current timer tick address at old_timer, and point the
  1588. ;;      tick to my_tick in this code seg.
  1589. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1590. set_timer       proc    near
  1591.         cli
  1592.  push    ax
  1593.         push    es
  1594.         xor     ax, ax
  1595.         mov     es, ax
  1596.  
  1597.         mov     ax, es:[TIMER_ADD]
  1598.         mov     cs:[old_timer], ax
  1599.         mov     ax, es:[TIMER_ADD + 2]
  1600.         mov     cs:[old_timer + 2], ax
  1601.  
  1602.         mov     ax, offset cs:my_tick
  1603.         mov     es:[TIMER_ADD], ax
  1604.         mov     ax, cs
  1605.         mov     es:[TIMER_ADD + 2], ax
  1606.  
  1607.         pop     es
  1608.         pop     ax
  1609.         sti
  1610.         ret
  1611. set_timer       endp
  1612. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1613.  
  1614. driver  endp
  1615. code    ends
  1616.         end
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.  
  1626. Subject: 3K source on debug.asm
  1627.  
  1628. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1629.         DO_PRINT        macro   arg
  1630.                 push    dx
  1631.                 push    ax
  1632.                 mov     dx, offset      cs:arg
  1633.                 call    out_line
  1634.                 call    out_rh
  1635.                 pop     ax
  1636.                 pop     dx
  1637.         endm
  1638. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1639.         DO_ERR_PRINT    macro   arg
  1640.                 DO_PRINT        arg
  1641.                 DO_PRINT        msg_char_err
  1642.  endm
  1643. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1644. form_num        proc    near
  1645.  
  1646.         push    ax
  1647.         push    bx
  1648.         push    cx
  1649.         push    dx
  1650.  
  1651.         mov     bx, dx
  1652.         mov     dx, cx
  1653. num_lp1:
  1654.         mov     cx, 4
  1655.         rol     ax,cl
  1656.         mov     cx, ax
  1657.         and     cx, 0fh
  1658.         add     cx, '0'
  1659.         cmp     cx, '9'
  1660.         jbe     is_decimal
  1661.         add     cx, 'A'-'9'-1
  1662. is_decimal:
  1663.         mov     [bx], cl
  1664.         inc     bx
  1665.         dec     dx
  1666.         jnz     num_lp1
  1667.  
  1668.         pop     dx
  1669.         pop     cx
  1670.         pop     bx
  1671.         pop     ax
  1672.         ret
  1673.  
  1674. form_num        endp
  1675.  
  1676. out_rh  proc    near
  1677.  
  1678.         push    ax
  1679.         push    cx
  1680.         push    dx
  1681.  
  1682.  mov     ax, es
  1683.         mov     dx, offset rh_0
  1684.         mov     cx, 4
  1685.         call    form_num
  1686.  
  1687.         mov     ax, di
  1688.         mov     dx, offset rh_00
  1689.         mov     cx, 4
  1690.         call    form_num
  1691.  
  1692.         mov     ah, es:[di.rlength]
  1693.         xor     al, al
  1694.         mov     dx, offset rh_1_val
  1695.         mov     cx, 2
  1696.         call    form_num
  1697.  
  1698.         mov     ah, es:[di.unit]
  1699.         xor     al, al
  1700.         mov     dx, offset rh_2_val
  1701.         mov     cx, 2
  1702.  call    form_num
  1703.  
  1704.         mov     ah, es:[di.command]
  1705.         xor     al, al
  1706.         mov     dx, offset rh_3_val
  1707.         mov     cx, 2
  1708.         call    form_num
  1709.  
  1710.         mov     ax, es:[di.status]
  1711.         mov     dx, offset rh_4_val
  1712.         mov     cx, 4
  1713.         call    form_num
  1714.  
  1715.         mov     ah, es:[di.media]
  1716.         xor     al, al
  1717.         mov     dx, offset rh_5_val
  1718.         mov     cx, 2
  1719.         call    form_num
  1720.  
  1721.         mov     ax, word ptr es:[di.address + 2]
  1722.  mov     dx, offset rh_6_val
  1723.         mov     cx, 4
  1724.         call    form_num
  1725.  
  1726.         mov     ax, word ptr es:[di.address]
  1727.         mov     dx, offset rh_7_val
  1728.         mov     cx, 4
  1729.         call    form_num
  1730.  
  1731.         mov     ax, es:[di.count]
  1732.         mov     dx, offset rh_8_val
  1733.         mov     cx, 4
  1734.         call    form_num
  1735.  
  1736.         mov     ax, es:[di.sector]
  1737.         mov     dx, offset rh_9_val
  1738.         mov     cx, 4
  1739.         call    form_num
  1740.  
  1741.         mov     dx, offset rh_1
  1742.  call    out_line
  1743.  
  1744.         pop     dx
  1745.         pop     cx
  1746.         pop     ax
  1747.  
  1748.         ret
  1749.  
  1750. out_rh  endp
  1751. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1752.  
  1753. rh_1            db      'RH:'
  1754. rh_0            db      'XXXX'
  1755.                 db      ':'
  1756. rh_00           db      'XXXX '
  1757.                 db      'RH_LEN:'
  1758. rh_1_val        db      'XX '
  1759.                 db      'UNIT:'
  1760. rh_2_val        db      'XX '
  1761.                 db      'Command:'
  1762. rh_3_val db      'XX '
  1763.                 db      'Status:'
  1764. rh_4_val        db      'XXXX ', CR, LF
  1765.                 db      'Media:'
  1766. rh_5_val        db      'XX '
  1767.                 db      'Address:'
  1768. rh_6_val        db      'XXXX'
  1769.                 db      ':'
  1770. rh_7_val        db      'XXXX '
  1771.                 db      'Count:'
  1772. rh_8_val        db      'XXXX '
  1773.                 db      'Sector:'
  1774. rh_9_val        db      'XXXX', CR, LF, '$'
  1775. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1776.  
  1777. adr_fmt db      'XXXX:XXXX', CR, LF, '$'
  1778.  
  1779. msg_init        db 'In init     ',CR,LF,'$'
  1780. msg_media_chk   db '??Media Check $'
  1781. msg_bld_bpb     db '??Bld_Bpb $'
  1782. msg_rd_ioctl    db 'In rd_ioctl ',CR,LF,'$'
  1783. msg_read        db 'In read     ',CR,LF,'$'
  1784. msg_nd_read     db 'In nd_read  ',CR,LF,'$'
  1785. msg_inp_stat    db 'In inp_stat ',CR,LF,'$'
  1786. msg_inp_flush   db 'In inp_flush',CR,LF,'$'
  1787. msg_write       db 'In write    ',CR,LF,'$'
  1788. msg_write_vfy   db 'In write_vfy',CR,LF,'$'
  1789. msg_out_stat    db 'In out_stat ',CR,LF,'$'
  1790. msg_out_flush   db 'In out_flush',CR,LF,'$'
  1791. msg_wrt_ioctl   db 'In wrt_ioctl',CR,LF,'$'
  1792. msg_dev_open    db 'In dev_open ',CR,LF,'$'
  1793. msg_dev_close   db 'In dev_close',CR,LF,'$'
  1794. msg_rem_media   db '??Rem_Media $'
  1795. msg_out_busy    db '??Out_Busy $'
  1796. msg_char_err    db ' called??', CR, LF, LF, '$'
  1797. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1798.  
  1799.  
  1800.  
  1801.  
  1802.  
  1803.  
  1804.  
  1805.  
  1806.  
  1807.  
  1808.  
  1809.  
  1810.  
  1811.  
  1812. Subject: 1.5K of source SET_MDM.ASM
  1813.  
  1814.  
  1815. code    segment
  1816. assume  cs:code
  1817. org     100h
  1818.  
  1819.  
  1820. start:
  1821.         jmp     install                 ; install out vectors and
  1822.  
  1823. old_dos dw      0
  1824.         dw      0
  1825.  
  1826.                                         ; then go TSR
  1827. my_int21        proc    far
  1828.         pushf
  1829.  cmp     ah, 03dh                ; handle open?
  1830.         jnz     normal_dos              ; no
  1831.         
  1832.         push    si
  1833.         mov     si, dx
  1834.         cmp     [si], 'DM'              ; cmp against "MDM",0
  1835.         jnz     not_me                  ; remembering that each pair of bytes
  1836.         cmp     word ptr [si + 2], 004dh; is reversed!
  1837.         jnz     not_me
  1838.         pop     si
  1839.  
  1840.                                         ; with the flags already on the stack,
  1841.         call    dword ptr cs:[old_dos]  ; do a long call to the old DOS
  1842.  
  1843.         jc      normal_ret              ; an error, so merely return
  1844.  
  1845.         pushf                           ; save DOS return status
  1846.         push    ax                      ; save the registers
  1847.         push    bx
  1848.         push    dx
  1849.  
  1850.         mov     bx, ax                  ; the handle just returned
  1851.         mov     ax, 4400h               ; get IOCTL
  1852.         int     21h
  1853.  
  1854.         xor     dh, dh                  ; zero out the top of the word
  1855.         or      dl, 20h                 ; set the raw bit
  1856.         mov     ax, 4401h               ; set IOCTL
  1857.         int     21h
  1858.  
  1859.         pop     dx
  1860.         pop     bx
  1861.         pop     ax
  1862.         popf
  1863.  
  1864. normal_ret:
  1865.         ret     2                       ; return with the flag word DOS left
  1866.  
  1867.  
  1868. not_me:
  1869.  pop     si
  1870. normal_dos:
  1871.         popf
  1872.         jmp     dword ptr cs:[old_dos]  ; and call the original DOS
  1873. my_int21        endp
  1874.  
  1875. my_size equ     (($-code)/16 + 1)       ; waste a 'graph!
  1876.  
  1877. install:
  1878.         mov     ax, 3521h               ; get the original DOS int vector
  1879.         int     21h
  1880.  
  1881.         mov     cs:[old_dos], bx
  1882.         mov     cs:[old_dos + 2], es
  1883.  
  1884.         push    cs
  1885.         pop     ds
  1886.         mov     dx, offset cs:my_int21
  1887.         mov     ax, 2521h
  1888.         int     21h
  1889.  
  1890.         mov     dx, my_size
  1891.         mov     ax, 3100h               ; go TSR
  1892.         int     21h
  1893.  
  1894.         int     20h                     ; belts *and* suspenders! :-)
  1895.  
  1896. code    ends
  1897.         end start
  1898.  
  1899.  
  1900.  
  1901. ======================[ End Listing for MDM-DRV.ASM ]====================
  1902.  
  1903.  
  1904.  
  1905. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1906. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1907. ;;
  1908. ;;            DEBUG AND MACRO DEFINITIONS
  1909. ;;
  1910. ;;    These macros and routines are included if DEBUG is defined in the
  1911. ;;    main body of the program.
  1912. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1913.  
  1914. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1915. ;;    DO_PRINT <arg>
  1916. ;;
  1917. ;;    Outputs the '$' terminated string <arg>, then prints the contents
  1918. ;;    of the Request Header, field by field
  1919. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1920.     DO_PRINT    macro    arg
  1921.         push    dx
  1922.         push    ax
  1923.         mov    dx, offset    cs:arg
  1924.         mov    ah, 09h
  1925.         int    21h
  1926.         call    out_rh
  1927.         pop    ax
  1928.         pop    dx
  1929.     endm
  1930. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1931.  
  1932. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1933. ;;    DO_ERR_PRINT    <arg>
  1934. ;;
  1935. ;;    Cause arg to be output, then output the common error suffix message
  1936. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1937.     DO_ERR_PRINT    macro    arg
  1938.         DO_PRINT    arg
  1939.         DO_PRINT    msg_char_err
  1940.     endm
  1941.  
  1942. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1943.  
  1944. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1945. ;;    OUTNUM ROUTINE
  1946. ;;
  1947. ;;    Output the number in AX (or AH) in hex into the buffer starting at
  1948. ;;    DX, and for CX characters.
  1949. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1950. outnum    proc    near
  1951.  
  1952.     push    ax
  1953.     push    bx
  1954.     push    cx
  1955.     push    dx
  1956.  
  1957.     mov    bx, dx
  1958.     mov    dx, cx
  1959. num_lp1:
  1960.     mov    cx, 4
  1961.     rol    ax,cl
  1962.     mov    cx, ax
  1963.     and    cx, 0fh
  1964.     add    cx, '0'
  1965.     cmp    cx, '9'
  1966.     jbe    is_decimal
  1967.     add    cx, 'A'-'9'-1
  1968. is_decimal:
  1969.     mov    [bx], cl
  1970.      inc    bx
  1971.     dec    dx
  1972.     jnz    num_lp1
  1973.  
  1974.     pop    dx
  1975.     pop    cx
  1976.     pop    bx
  1977.     pop    ax
  1978.     ret
  1979.  
  1980. outnum    endp
  1981. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1982.  
  1983. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1984. ;;    OUTPUT REQUEST HEADER ROUTINE
  1985. ;;
  1986. ;;    Output the Request Header, a field at a time.
  1987. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1988. out_rh    proc    near
  1989.  
  1990.     push    ax
  1991.     push    cx
  1992.     push    dx
  1993.  
  1994.     mov    ax, es
  1995.     mov    dx, offset rh_0
  1996.     mov    cx, 4
  1997.     call    outnum
  1998.  
  1999.     mov    ax, di
  2000.     mov    dx, offset rh_00
  2001.     mov    cx, 4
  2002.     call    outnum
  2003.  
  2004.     mov    ah, es:[di.rlength]
  2005.     xor    al, al
  2006.     mov    dx, offset rh_1_val
  2007.     mov    cx, 2
  2008.     call    outnum
  2009.  
  2010.     mov    ah, es:[di.unit]
  2011.     xor    al, al
  2012.     mov    dx, offset rh_2_val
  2013.     mov    cx, 2
  2014.     call    outnum
  2015.  
  2016.     mov    ah, es:[di.command]
  2017.     xor    al, al
  2018.     mov    dx, offset rh_3_val
  2019.     mov    cx, 2
  2020.     call    outnum
  2021.  
  2022.     mov    ax, es:[di.status]
  2023.     mov    dx, offset rh_4_val
  2024.     mov    cx, 4
  2025.     call    outnum
  2026.  
  2027.     mov    ah, es:[di.media]
  2028.     xor    al, al
  2029.     mov    dx, offset rh_5_val
  2030.     mov    cx, 2
  2031.     call    outnum
  2032.  
  2033.     mov    ax, word ptr es:[di.address + 2]
  2034.     mov    dx, offset rh_6_val
  2035.     mov    cx, 4
  2036.     call    outnum
  2037.  
  2038.     mov    ax, word ptr es:[di.address]
  2039.     mov    dx, offset rh_7_val
  2040.     mov    cx, 4
  2041.     call    outnum
  2042.  
  2043.     mov    ax, es:[di.count]
  2044.     mov    dx, offset rh_8_val
  2045.     mov    cx, 4
  2046.     call    outnum
  2047.  
  2048.     mov    ax, es:[di.sector]
  2049.     mov    dx, offset rh_9_val
  2050.     mov    cx, 4
  2051.     call    outnum
  2052.  
  2053.     mov    dx, offset rh_1
  2054.     mov    ah, 9
  2055.     int    21h
  2056.  
  2057.     pop    dx
  2058.     pop    cx
  2059.     pop    ax
  2060.  
  2061.     ret
  2062.  
  2063. out_rh    endp
  2064. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2065.  
  2066. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2067. ;;    The Layout of the Request Header output.
  2068. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2069. rh_1        db    'RH:',
  2070. rh_0        db    'XXXX'
  2071.         db    ':'
  2072. rh_00        db    'XXXX '
  2073.         db    'RH_LEN:'
  2074. rh_1_val    db    'XX '
  2075.         db    'UNIT:'
  2076. rh_2_val    db    'XX '
  2077.         db    'Command:'
  2078. rh_3_val    db    'XX '
  2079.         db    'Status:'
  2080. rh_4_val    db    'XXXX ', CR, LF
  2081.         db    'Media:'
  2082. rh_5_val    db    'XX '
  2083.         db    'Address:'
  2084. rh_6_val    db    'XXXX'
  2085.         db    ':'
  2086. rh_7_val    db    'XXXX '
  2087.         db    'Count:'
  2088. rh_8_val    db    'XXXX '
  2089.         db    'Sector:'
  2090. rh_9_val    db    'XXXX', CR, LF, '$'
  2091. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2092.  
  2093.  
  2094. msg_init    db 'In init     ',CR,LF,'$'
  2095. msg_media_chk   db '??Media Check $'
  2096. msg_bld_bpb     db '??Bld_Bpb $'
  2097. msg_rd_ioctl    db 'In rd_ioctl ',CR,LF,'$'
  2098. msg_read        db 'In read     ',CR,LF,'$'
  2099. msg_nd_read     db 'In nd_read  ',CR,LF,'$'
  2100. msg_inp_stat    db 'In inp_stat ',CR,LF,'$'
  2101. msg_inp_flush   db 'In inp_flush',CR,LF,'$'
  2102. msg_write       db 'In write    ',CR,LF,'$'
  2103. msg_write_vfy   db 'In write_vfy',CR,LF,'$'
  2104. msg_out_stat    db 'In out_stat ',CR,LF,'$'
  2105. msg_out_flush   db 'In out_flush',CR,LF,'$'
  2106. msg_wrt_ioctl   db 'In wrt_ioctl',CR,LF,'$'
  2107. msg_dev_open    db 'In dev_open ',CR,LF,'$'
  2108. msg_dev_close   db 'In dev_close',CR,LF,'$'
  2109. msg_rem_media   db '??Rem_Media $'
  2110. msg_out_busy    db '??Out_Busy $'
  2111. msg_char_err    db ' called??', CR, LF, LF, '$'
  2112.