home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / SHSUCD11.ZIP / SHSUCDN.ASM < prev    next >
Assembly Source File  |  1993-07-01  |  31KB  |  900 lines

  1. ;************************************************************************
  2. ;
  3. ;  CDN.ASM
  4. ;    An executable, driver for networking MSCDEX to a remote
  5. ;      CDNET drive using NETBIOS.  Execute before MSCDEX.
  6. ;    Requires CdServer be active on server before activating.
  7. ;
  8. ;    UsageMsg:
  9. ;      SHSUCDN [/?][/C:ClientName][/S:ServerName][/D:DriverName][/Q][/U]
  10. ;
  11. ;  Assemble using MASM 6.0 and link as an .exe file.
  12. ;  Requires:  NETBIOS.INC
  13. ;
  14. ;  CDN is a copyright-reserved, free use program.
  15. ;  (c)John H. McCoy, 1993, Sam Houston St. Univ., TX 77341-2206
  16. ;************************************************************************
  17.  
  18. .model tiny, os_dos
  19.  
  20. option nokeyword:<length name>
  21. option expr16
  22.  
  23. fptr  typedef  far ptr word
  24. nptr  typedef  near ptr word
  25.  
  26. rh    struc
  27.    Length      byte ?          ; header size in bytes
  28.    SubUnit     byte ?          ; cd drive number
  29.    Command     byte ?          ; device command code
  30.    Status      word ?          ; device command status
  31.    Reserved    byte 8 dup(?)
  32. rh    ends
  33.  
  34. rhINIT   struc
  35.                      byte size rh dup(?) ;rh common
  36.    NumberUnits       byte  ?
  37.                      dword ?
  38.                      dword ?
  39.                      byte  ?
  40. rhINIT   ends
  41.  
  42. rhIOCTL   struc
  43.                      byte size rh dup(?) ;rh common
  44.    MediaDesc         byte ?
  45.    CBPtr             fptr ?
  46.    BytesToTransfer   word ?
  47.    StartSector       word ?
  48.    VolIdPtr          fptr ?
  49. rhIOCTL   ends
  50.  
  51. IOCtl_RDHACommand       equ  0
  52.  
  53. IoCB_RDHA     struc                     ; Ioctl_0  command block structure
  54.    IoctlCommand           byte IOCtl_RDHACommand
  55.    DeviceHeaderAddress    fptr ?
  56. IoCB_RDHA ends
  57.  
  58. rhTransfer  struc
  59.                      byte size rh dup(?) ;rh common
  60.                      byte   ?
  61.    DtaPtr            fptr   ?
  62.    SectorCount       word   ?
  63.    StartSector       Dword  ?
  64.    ReadMode          byte   ?     ; we support cooked mode only
  65.                      byte   ?
  66.                      byte   ?
  67. rhTransfer ends
  68.  
  69.  
  70. LastDosDriverCommand      equ  14    ; varies with DOS version
  71. FirstCDExtendedCommand    equ  128
  72.  
  73. DeviceError            equ  8000h
  74. DeviceDone             equ  0100h
  75. DE_UnknownCommand      equ    03h    ; OR with DeviceError
  76. DE_ReadError           equ    0Bh
  77. DE_GeneralFailure      equ    0Ch
  78.  
  79. AsciiNul                equ     0
  80. cr                      equ     13
  81. lf                      equ     10
  82. QMark                   equ     '?'
  83.  
  84. Display   MACRO  msg
  85.          mov     dx,offset msg
  86.          mov     ah,9
  87.          int     21h
  88. ENDM
  89.  
  90. ; ** NetBIOS.INC prototypes
  91.  
  92.     NetAddName proto near syscall Name:nptr
  93.     NetCall    proto near syscall LocalName:nptr, RemoteName:nptr
  94.     NetDelName proto near syscall Name:nptr
  95.     NetReceive proto near syscall DTA:fptr, Length:word, Session:byte
  96.     NetHangup  proto near syscall Session:byte
  97.     NetSend    proto near syscall DTA:fptr, Length:word, Session:byte
  98.  
  99. .code
  100.  
  101.    assume cs:@code,  ds:@code
  102.  
  103. ;  dos device header with CDROM extension fields
  104.  
  105. DevHeader  label word
  106.   NextDriver     dword     -1
  107.   Attributes     word      0C800h
  108.                  nptr      Strategy
  109.                  nptr      Interrupt
  110.   DeviceName     byte      'SHSU-CDN'
  111.                  word      0                     ; CDROM reserved
  112.                  byte      0                     ; 1st CDROM drive letter
  113.   SubUnits       byte      1                     ; number of drives
  114.  
  115. LocalSession     byte      0
  116.  
  117. ;  strategy call saves req hdr addr here for use by interrupt call
  118.  
  119. rhAddr        label far ptr
  120.   rhOffset      word       ?
  121.   rhSegment     word       ?
  122.  
  123. rhBuf         byte size rhINIT, (size rhINIT -1) dup (0)
  124.  
  125. ;  work space for oversize readlong
  126.  
  127. DtaPtrSave          Dword      ?
  128. SectorCountSave     word       ?
  129. StartSectorSave     Dword      ?
  130. SectorsRead         word       ?
  131.  
  132. ;  CB size
  133.  
  134.  
  135. IoCB_InSize          byte  5,6,1,1,9,130,5,4,5,2,7,7,11,13,11,11
  136. IoCB_OutSize         byte  1,2,1,9,130,1
  137.  
  138. ClientNameFlag   byte       0
  139.  
  140. ClientName       byte       'CD-CLIENT       '
  141.                  byte       "$"
  142.  
  143. ServerName       byte       'SHSU-CD-SERVER  '
  144.                  byte       "$"
  145.  
  146. DriverName       byte       'SHSU-CDN'
  147.                  byte       "$"
  148.  
  149. Author           byte       "John H. McCoy"
  150.  
  151. ;************************************************************************
  152. ;  Driver Strategy routine
  153. ;************************************************************************
  154.  
  155. Strategy    proc     far
  156.  
  157.    ;  es:bx contains request header pointer.  save it.
  158.       mov    cs:rhOffset, bx
  159.       mov    cs:rhSegment, es
  160.       ret
  161.  
  162. Strategy    endp
  163.  
  164. ;************************************************************************
  165. ;  Driver Interrupt routine
  166. ;************************************************************************
  167.  
  168. Interrupt    proc  far uses ax bx cx dx si di ds es
  169.  
  170.    ;  setup ds addressing
  171.       push   cs
  172.       pop    ds
  173.    ;  process command
  174.       mov      al, es:[bx].rh.command
  175.       xor      ah, ah
  176.       .if      al >= FirstCDExtendedCommand
  177.           sub      al, 128
  178.           .if      al > 8          ; 128 thru 136 valid CDROM Commands
  179.               jmp   UnknownCommand
  180.           .endif
  181.           shl      ax, 1       ; convert to word offset for jmp table
  182.           mov      si, ax
  183.           jmp      CDExtendedCommandTable[si]
  184.  
  185.           CDExtendedCommandTable   label word
  186.                  nptr offset ReadLong
  187.                  nptr offset UnknownCommand
  188.                  nptr offset ReadPrefetch
  189.                  nptr offset Seek
  190.                  nptr offset UnknownCommand
  191.                  nptr offset UnknownCommand
  192.                  nptr offset UnknownCommand
  193.                  nptr offset UnknownCommand
  194.                  nptr offset UnknownCommand
  195.  
  196.       .elseif   al <= LastDosDriverCommand
  197.  
  198.           shl      ax, 1       ; convert to word offset for jmp table
  199.           mov      si, ax
  200.           jmp      DosDriverCommandTable[si]
  201.  
  202.           DosDriverCommandTable label word
  203.                  nptr offset UnknownCommand        ; we do init when loading
  204.                  nptr offset UnknownCommand
  205.                  nptr offset UnknownCommand
  206.                  nptr offset IoctlInput
  207.                  nptr offset UnknownCommand
  208.                  nptr offset UnknownCommand
  209.                  nptr offset UnknownCommand
  210.                  nptr offset UnknownCommand
  211.                  nptr offset UnknownCommand
  212.                  nptr offset UnknownCommand
  213.                  nptr offset UnknownCommand
  214.                  nptr offset UnknownCommand
  215.                  nptr offset IoctlOutput
  216.                  nptr offset DevOpen
  217.                  nptr offset DevClose
  218.                  nptr offset UnknownCommand
  219.  
  220.       .endif
  221.  
  222. IoctlInput:
  223.       les      bx, es:[bx].rhIOCTL.CBPtr
  224.       mov      al, byte ptr es:[bx]           ; 1st byte of dta is subcommand
  225.       .if  (al == 2) || (al > 15) || (LocalSession == 0)
  226.       ;  invalid sub-command or not conected to remote CD
  227.          mov   ax, (DeviceDone OR DeviceError OR DE_UnknownCommand)
  228.          jmp   ExitRestoreRH
  229.       .endif
  230.       .if      al == IOCtl_RDHACommand
  231.          lea   ax, DevHeader
  232.          mov   word ptr es:[bx].IoCB_RDHA.DeviceHeaderAddress, ax
  233.          mov   ax, ds
  234.          mov   word ptr es:[bx].IoCB_RDHA.DeviceHeaderAddress+2, ax
  235.          mov   ax, DeviceDone
  236.          jmp   ExitRestoreRH
  237.       .endif
  238.     ;  valid command and connected.  Lookup IoCB_InSize since some
  239.     ;    callers apparently don't tell us.  Do it here since we need
  240.     ;    it to bring back the CB.
  241.       lea      bx, IoCB_InSize
  242.       xlat
  243.       cbw
  244.       mov      dx, ax
  245.       les      bx, rhAddr
  246.       mov      es:[bx].rhIOCTL.BytesToTransfer, ax
  247.     ;  send rh and then control block to remote CD
  248.     ;  first the rh
  249.       INVOKE NetSend, es::bx, es:[bx].rh.length, LocalSession
  250.       .if      al != NB_Ok
  251.           jmp     IoctlError
  252.       .endif
  253.     ;  then the CB
  254.       les      bx, es:[bx].rhIOCTL.CBPtr
  255.       INVOKE NetSend, es::bx, dx, LocalSession
  256.       les      bx, rhAddr
  257.       .if      al != NB_Ok
  258.           jmp     IoctlError
  259.       .endif
  260.     ;  rh comes back first
  261.       INVOKE NetReceive, es::bx, es:[bx].rh.length, LocalSession
  262.       .if      al != NB_Ok
  263.           jmp     IoctlError
  264.       .endif
  265.     ;  then the CB if device done
  266.       .if      es:[bx].rh.Status == DeviceDone
  267.          les     bx, es:[bx].rhIOCTL.CBPtr
  268.          INVOKE NetReceive, es::bx, dx, LocalSession
  269.          les      bx, rhAddr
  270.          .if      al == NB_Ok
  271.             jmp     Exit0          ; returns device status to MSCDEX
  272.          .endif
  273.       .endif
  274.       jmp     IoctlError
  275.  
  276. IoctlOutput:
  277.       les      bx, es:[bx].rhIOCTL.CBPtr
  278.       mov      al, byte ptr es:[bx]           ; 1st byte of dta is subcommand
  279.       .if     (al > 5) || (LocalSession == 0)
  280.       ;  invalid sub-command or not conected to remote CD
  281.          mov      ax, (DeviceDone OR DeviceError OR DE_UnknownCommand)
  282.          jmp      ExitRestoreRH
  283.       .endif
  284.     ;  valid command and connected.  Lookup IoCB_OutSize since some
  285.     ;    callers don't tell us.
  286.       lea      bx, IoCB_OutSize
  287.       xlat
  288.       cbw
  289.       mov      dx, ax                ; keep size, we need it to send dta
  290.       les      bx, rhAddr
  291.       mov      es:[bx].rhIOCTL.BytesToTransfer, ax
  292.     ;  some programs also lie about the rhlength
  293.       mov       al, 26
  294.       mov       es:[bx].rh.length, al
  295.     ;  send rh and then control block to remote CD
  296.       INVOKE NetSend, es::bx, es:[bx].rh.length, LocalSession
  297.       .if      al != NB_Ok
  298.           jmp     IoctlError
  299.       .endif
  300.     ;  then the CB
  301.       les      bx, es:[bx].rhIOCTL.CBPtr
  302.       INVOKE NetSend, es::bx, dx, LocalSession
  303.       les      bx, rhAddr
  304.       .if      al != NB_Ok
  305.           jmp     IoctlError
  306.       .endif
  307.     ;  rh is only thing coming back
  308.       INVOKE NetReceive, es::bx, es:[bx].rh.length, LocalSession
  309.       .if      al == NB_Ok
  310.           jmp     Exit0          ; returns device status to MSCDEX
  311.       .endif
  312.  
  313. IoctlError:
  314.       mov      ax, (DeviceDone OR DeviceError OR DE_ReadError)
  315.       jmp      ExitWithStatus
  316.  
  317. DevOpen:
  318.    ;  When MSCDEX loads it has DOS do Open, use IOCTL input to get the
  319.    ;  device header address and then closes the device.  It then opens all
  320.    ;  subunits and gets a status from each.
  321.    ;  Subsequent calls are direct to strategy and/or interrupt address obtained
  322.    ;  from the device header.
  323.  
  324.       .if LocalSession == 0
  325.          INVOKE NetCall, offset ClientName,        ; call server
  326.                          offset ServerName
  327.          .if  al != NB_Ok
  328.             jmp  OpenError
  329.          .endif
  330.          mov   LocalSession, ah
  331.       .endif
  332.     ;  send the rh                        ; get # of CD's attached
  333.       mov   bx, offset rhBuf              ; init uses a local rh
  334.       INVOKE NetSend, ds::bx, ds:[bx].rh.length, LocalSession
  335.       .if   al == NB_Ok
  336.          INVOKE NetReceive, ds::bx, ds:[bx].rh.length, LocalSession
  337.          .if   al == NB_Ok
  338.              mov   al, ds:[bx].rhINIT.NumberUnits       ; save in header for
  339.              mov   SubUnits, al                        ; MSCDEX to use
  340.              mov   ax, DeviceDone
  341.              jmp   ExitRestoreRH
  342.          .endif
  343.       .endif
  344.       les      bx, rhAddr
  345.   OpenError:
  346.       .if ClientNameFlag != NB_DuplicateLocalName
  347.           INVOKE NetDelName, offset ClientName
  348.       .endif
  349.       mov      ax, (DeviceDone OR DeviceError OR DE_GeneralFailure)
  350.       jmp   ExitWithStatus
  351.  
  352. DevClose:                                     ; just acknowledge
  353.       mov      ax, DeviceDone
  354.       jmp      ExitWithStatus
  355.  
  356. ReadLong:
  357.     ;  save sector count
  358.        mov    cx, es:[bx].rhTransfer.SectorCount
  359.        mov    SectorCountSave, cx
  360.     ;  send the rh to remote CD
  361.        INVOKE NetSend, es::bx, es:[bx].rh.length, LocalSession
  362.     ;  and get it back
  363.       .if  al == NB_Ok
  364.         INVOKE NetReceive, es::bx, es:[bx].rh.length, LocalSession
  365.       .endif
  366.       .if  al != NB_Ok
  367.         jmp    NetworkErrorExit
  368.       .endif
  369.     ;  now get the dta
  370.        mov    cx, es:[bx].rhTransfer.SectorCount
  371.        .if (cx == 0) || (es:[bx].rh.Status != DeviceDone)
  372.          jmp    Exit0           ; rh.status tells all
  373.        .endif
  374.        mov    ax, cx
  375.        mov    cx, 11
  376.        shl    ax, cl           ;  bytes to xfer := sectors x 2048
  377.        mov    cx,ax
  378.        INVOKE NetReceive, es:[bx].rhTransfer.DtaPtr, cx, LocalSession
  379.        .if  al != NB_Ok
  380.          jmp    NetworkErrorExit
  381.        .endif
  382.        mov    cx, es:[bx].rhTransfer.SectorCount
  383.        .if cx == SectorCountSave
  384.          jmp    Exit0          ; usual requests will return here
  385.        .endif
  386.      ;  request to big, bring back the rest of the pieces
  387.      ;  first initialize work space and save rest of the rh info
  388.        mov    ax, word ptr es:[bx].rhTransfer.StartSector
  389.        mov    word ptr StartSectorSave, ax
  390.        mov    ax, word ptr es:[bx+2].rhTransfer.StartSector
  391.        mov    word ptr StartSectorSave+2, ax
  392.        mov    ax, word ptr es:[bx].rhTransfer.DtaPtr
  393.        mov    word ptr DtaPtrSave, ax
  394.        mov    ax, word ptr es:[bx+2].rhTransfer.DtaPtr
  395.        mov    word ptr DtaPtrSave+2, ax
  396.   ReadNextChunk:
  397.        mov    SectorsRead, cx
  398.        mov    ax, SectorCountSave
  399.        sub    ax, cx                               ; sectors left to read
  400.        mov    cx, es:[bx].rhTransfer.SectorCount   ; sectors in previous read
  401.        mov    es:[bx].rhTransfer.SectorCount, ax   ; count for next read
  402.        mov    ax, word ptr es:[bx].rhTransfer.StartSector
  403.        add    ax, cx                               ; start sector for next read
  404.        mov    word ptr es:[bx].rhTransfer.StartSector, ax
  405.        .if    carry?                ; then increment highorder byte
  406.          mov    ax, word ptr es:[bx+2].rhTransfer.StartSector
  407.          inc    ax
  408.          mov    word ptr es:[bx+2].rhTransfer.StartSector, ax
  409.        .endif
  410.  
  411.        mov    ax, cx                     ; sectors in previous read
  412.        mov    cl, 7
  413.        shl    ax, cl                     ; ParaRead := 128 * Sectors Read
  414.        add    ax, word ptr es:[bx+2].rhTransfer.DtaPtr
  415.        mov    word ptr es:[bx+2].rhTransfer.DtaPtr, ax
  416.  
  417.     ;  send the rh to remote CD
  418.        INVOKE NetSend, es::bx, es:[bx].rh.length, LocalSession
  419.     ;  and get it back
  420.       .if  al == NB_Ok
  421.         INVOKE NetReceive, es::bx, es:[bx].rh.length, LocalSession
  422.       .endif
  423.       .if  al != NB_Ok
  424.         jmp    OverSizeReadError
  425.       .endif
  426.        mov    cx, es:[bx].rhTransfer.SectorCount
  427.        .if (cx == 0) || (es:[bx].rh.Status != DeviceDone)
  428.          jmp    OverSizeReadExit           ; rh.status tells all
  429.        .endif
  430.     ;  now get the dta
  431.        mov    ax, cx
  432.        mov    cl, 11
  433.        shl    ax, cl           ;  bytes to xfer := sectors x 2048
  434.        mov    cx, ax
  435.        INVOKE NetReceive, es:[bx].rhTransfer.DtaPtr, cx, LocalSession
  436.        .if  al != NB_Ok
  437.          jmp    OverSizeReadError
  438.        .endif
  439.        mov    cx, es:[bx].rhTransfer.SectorCount
  440.        add    cx, SectorsRead
  441.        .if cx < SectorCountSave
  442.          jmp  ReadNextChunk
  443.        .endif
  444.        mov    SectorsRead, cx
  445.        jmp    OverSizeReadExit
  446.  
  447.   OverSizeReadError:
  448.    ;   call network error a device error before restoring rh info and exiting
  449.        mov    ax, (DeviceDone OR DeviceError OR DE_ReadError)
  450.        mov    es:[bx].rh.Status, ax
  451.  
  452.   OverSizeReadExit:
  453.      ;  restore rh info before exiting (this may be unneccessary)
  454.        mov    ax,word ptr DtaPtrSave
  455.        mov    word ptr es:[bx].rhTransfer.DtaPtr, ax
  456.        mov    ax, word ptr DtaPtrSave+2
  457.        mov    word ptr es:[bx+2].rhTransfer.DtaPtr, ax
  458.        mov    ax, word ptr StartSectorSave
  459.        mov    word ptr es:[bx].rhTransfer.StartSector, ax
  460.        mov    ax, word ptr StartSectorSave+2
  461.        mov    word ptr es:[bx+2].rhTransfer.StartSector, ax
  462.        mov    ax, SectorsRead
  463.        mov    word ptr es:[bx].rhTransfer.SectorCount, ax
  464.        jmp    Exit0
  465.  
  466.   NetworkErrorExit:
  467.    ;  network error occurred, call it a device error
  468.        mov    ax, (DeviceDone OR DeviceError OR DE_ReadError)
  469.        jmp    ExitWithStatus
  470.  
  471. ReadPrefetch:
  472.     ;  no data transfer, process like a seek
  473. Seek:
  474.     ;  send the rh to remote CD
  475.       INVOKE NetSend, es::bx, es:[bx].rh.length, LocalSession
  476.     ;  and get it back
  477.       .if      al == NB_Ok
  478.           INVOKE NetReceive, es::bx, es:[bx].rh.length, LocalSession
  479.       .endif
  480.       .if      al == NB_Ok
  481.           jmp     Exit0           ; status returned in rh.status
  482.       .else
  483.           mov     ax, (DeviceDone OR DeviceError OR DE_ReadError)
  484.           jmp     ExitWithStatus
  485.       .endif
  486.  
  487. UnknownCommand:
  488.       mov      ax, (DeviceDone OR DeviceError OR DE_UnknownCommand)
  489.       jmp      ExitRestoreRH
  490.  
  491.  
  492. ExitRestoreRH:
  493.  
  494.       les      bx, rhAddr                ; restore rh ptr
  495.  
  496. ExitWithStatus:
  497.  
  498.       mov   es:[bx].rh.Status, ax
  499.  
  500. Exit0:
  501.       ret
  502.  
  503. Interrupt   endp
  504.  
  505. include netbios.inc
  506.  
  507.      byte "End of CDNET"
  508.  
  509. LastByte               label byte
  510. ;============================================================================
  511. ;  everything below this line is discarded after installing the driver
  512.  
  513. ClientParm              equ     'C'     ; command line parms /C:, etc
  514. DriverParm              equ     'D'
  515. ServerParm              equ     'S'
  516. ArgumentNotFound        EQU     2       ; Unrecognized argument
  517. NoArgumentsFound        EQU     1       ; No argument in command line
  518. ArgumentFound           EQU     0       ; Ok argument in command line
  519.  
  520. UnInstall               equ     2
  521. DontInstall             equ     1
  522. Install                 equ     0
  523. QuietInstall            equ     2
  524.  
  525. InstallFlag             byte    0
  526. QuietFlag               word    0
  527.  
  528. _SS    word ?
  529. _SP    word ?
  530.  
  531.  
  532. Init  proc far
  533.                                  ; fix regs for Install/uninstall
  534.       push     ds                ; point to psp so we can access command line
  535.       pop      es                ; using es or for uninstall
  536.       push     cs                ; now set DS to CS
  537.       pop      ds
  538.  
  539.       call ParseCommandLine
  540.  
  541.       .if InstallFlag == Install
  542.            call VerifyClientName
  543.           .if InstallFlag == Install
  544.               call Link
  545.               .if (InstallFlag == Install && QuietFlag != QuietInstall)
  546.                   Display  InstallMsg
  547.                   Display  ClientMsg
  548.                   Display  ClientName
  549.                   Display  ServerMsg
  550.                   Display  ServerName
  551.                   Display  DriverMsg
  552.                   Display  DriverName
  553.                   Display  ActivateMsg
  554.               .endif
  555.               push   es                     ; reset ds to psp
  556.               pop    ds
  557.  
  558.               mov    ax, ds:[2Ch]           ; find environment and release it
  559.               mov    es, ax
  560.               mov    ah, 49h
  561.               int    21h
  562.               sub    ax, ax
  563.               mov    ds:[2Ch], ax           ; zero the evironment ptr
  564.  
  565.               if  (LastByte-DevHeader+1) mod 16
  566.                   roundup = 1
  567.               else
  568.                   roundup = 0
  569.               endif
  570.  
  571.               mov     dx,((LastByte-DevHeader)+1+100h)/16+roundup; para to keep
  572.               mov     ah,31h        ; stay resident and
  573.               int     21h             ; exit
  574.  
  575.           .endif
  576.       .elseif InstallFlag == UnInstall
  577.           call UnInstallDriver              ; es points to our psp
  578.  
  579.       .endif
  580.  
  581.       .exit
  582.  
  583. Init endp
  584.  
  585. Link   proc near uses es
  586.       mov      ax, 5200h               ; get list of list
  587.       int      21h                     ; we assume DOS 3.1 or later
  588.       add      bx, 22h                 ; es:bx[22] is NUL device header
  589.       mov      ax, es:[bx]               ; put NUL.next in our header
  590.       mov      word ptr NextDriver, ax
  591.       mov      ax, es:[bx+2]
  592.       mov      word ptr NextDriver+2, ax
  593.       mov      ax, 0                   ; then point NUL header at us
  594.       mov      es:[bx], ax
  595.       mov      es:[bx+2], cs
  596.       ret
  597. Link   endp
  598.  
  599. UnInstallDriver proc near
  600.  
  601.    local _bx,_es:word
  602.  
  603.       push     es                      ; save our psp address
  604.       mov      ax, 5200h               ; get list of list
  605.       int      21h                     ; we assume DOS 3.1 or later
  606.       add      bx, 22h                 ; es:bx[22] is NUL (1st) device header
  607.                                        ; es:bx now pointing at NUL header
  608.    TryNext:
  609.       mov      _bx, bx                 ; save current header addr
  610.       mov      _es, es
  611.       les      bx, es:[bx]             ; load next header addr into es:bx
  612.       mov      ax, es
  613.       cmp      ax, 0FFFFh              ; end of drivers?
  614.       je       DriverNotInstalled
  615.       mov      cx, 8
  616.       lea      di, DeviceName[bx]      ; es:di is chained device name
  617.       mov      si, offset DeviceName   ; dx:si is our device name
  618.       repe     cmpsb                   ; if equ its the one we are looking for
  619.       jne      TryNext
  620.       lea      di, LocalSession[bx]    ; get the session number of driver
  621.       mov      dl, byte ptr es:[di]    ; being uninstalled
  622.       push     ds
  623.       mov      ax, es                  ; es:bx is addr of driver being removed
  624.       mov      ds, ax                  ; put it into ds:si
  625.       mov      si, bx                  ;
  626.       mov      cx, 4                   ;
  627.       mov      es, _es                 ;
  628.       mov      di, _bx                 ; previous header now in es:di
  629.       rep      movsb                   ; move address ds:si -> es:di
  630.       mov      es, ax                  ; es now points at unlinked driver
  631.       pop      ds                      ; cs=ds=@code -- need this for net
  632.       .if   dl != 0
  633.           INVOKE NetHangup, dl
  634.       .endif
  635.       mov      ax, es                   ; locate the
  636.       sub      ax, 10h                  ; psp of installed driver
  637.       mov      es, ax                   ;
  638.       mov      bx, 16h                  ; installed drivers parent psp pointer
  639.       pop      ax                       ; our psp address(pushed es above)
  640.       mov      es:[bx],ax               ; make us parent of TSR
  641.       lea      ax, UnInstallExit        ; set TSRs
  642.       mov      bx, 0Ah                  ; terminate address
  643.       mov      es:[bx], ax              ; to come back to
  644.       mov      ax, cs
  645.       mov      es:[bx]+2, ax            ; us
  646.       mov      bx, es                   ; now make TSRs psp the
  647.       mov      ah, 50h                  ; current psp
  648.       int      21h
  649.  
  650.       push     bp
  651.       mov      _SS, ss                  ; save stack info
  652.       mov      _SP, sp
  653.       mov      ah, 4Ch                  ; terminate TSR and
  654.       int      21h                      ; come back to next
  655.  
  656.     UnInstallExit:
  657.       mov      ax, cs
  658.       mov      ds, ax                   ; reestablish addressing
  659.       mov      sp, _SP                  ; and stack info
  660.       mov      ss, _SS
  661.       pop      bp
  662.  
  663.       display DriverName                ; tell the world we did it
  664.       display UnInstallMsg
  665.       ret
  666.  
  667.   DriverNotInstalled:
  668.       display  DriverName
  669.       Display  DriverNotFoundMsg
  670.       ret
  671.  
  672. UnInstallDriver endp
  673.  
  674. VerifyClientName proc near
  675.  
  676.       INVOKE NetAddName, offset ClientName
  677.       .if      (al != NB_Ok && al != NB_DuplicateLocalName)
  678.           Display  ClientMsg
  679.           Display  ClientName
  680.           .if al == NB_NameAlreadyClaimed
  681.               Display   NotInstallMsg
  682.               Display   NameClaimedMsg
  683.           .else
  684.               Display   NotInstallMsg
  685.               Display   NetBIOSNotReadyMsg
  686.           .endif
  687.          mov   al,DontInstall
  688.          mov   InstallFlag, al
  689.       .elseif al == NB_DuplicateLocalName
  690.          mov   ClientNameFlag, al
  691.       .endif
  692.       ret
  693. VerifyClientName endp
  694.  
  695. ParseCommandLine       proc near  uses es
  696.  
  697.       ;* If driver is loaded from config.sys using device=drivername parms
  698.       ;* then rhINIT points to the first character following the drivername
  699.       ;* and a CR follows the last parm.  When loaded by executing, the
  700.       ;* command line is available in the PSP.(len +80h, 1st ch +81h, no CR)
  701.  
  702.       sub      ch, ch
  703.       mov      di, 80h            ; command line length @ +80h
  704.       mov      cl, es:[di]
  705.  
  706.       mov      al, '?'
  707.       call     GetParm
  708.       .if       ax == NoArgumentsFound
  709.          jmp   CopyDeviceName
  710.       .elseif   ax == ArgumentFound       ; /?  user needs help on usage
  711.          Display  UsageMsg
  712.          mov   al,DontInstall
  713.          mov   InstallFlag, al
  714.          jmp   exit
  715.       .endif
  716.  
  717.       sub      ch, ch
  718.       mov      di, 80h            ; command line length @ +80h
  719.       mov      cl, es:[di]
  720.       mov      al, 'Q'            ; /Q  quiet installation
  721.       call     GetParm
  722.       .if ax == ArgumentFound
  723.            mov      QuietFlag, QuietInstall
  724.       .endif
  725.  
  726.       sub      ch, ch
  727.       mov      di, 80h            ; command line length @ +80h
  728.       mov      cl, es:[di]
  729.       mov      al, 'U'            ; /U unInstall driver
  730.       call     GetParm
  731.       .if ax == ArgumentFound
  732.           mov      InstallFlag, UnInstall
  733.       .endif
  734.  
  735.       mov      al, ClientParm
  736.       call     FindParm
  737.       .if   ax == ArgumentFound
  738.          mov      dx, sizeof ClientName
  739.          lea      si, ClientName
  740.          call     MoveName
  741.       .endif
  742.  
  743.       mov      al, ServerParm
  744.       call     FindParm
  745.      .if   ax == ArgumentFound
  746.          mov      dx, sizeof ServerName
  747.          lea      si, ServerName
  748.          call     MoveName
  749.       .endif
  750.  
  751.       mov      al, DriverParm
  752.       call     FindParm
  753.      .if   ax == ArgumentFound
  754.          mov      dx, sizeof DeviceName
  755.          lea      si, DeviceName
  756.          call     MoveName
  757.       .endif
  758.  
  759.   CopyDeviceName:                               ; so we can display it
  760.  
  761.       mov   cx, 8
  762.       push  ds
  763.       pop   es
  764.       lea   si, DeviceName
  765.       lea   di, DriverName
  766.       cld
  767.       rep    movsb
  768.  
  769.  
  770. Exit: ret
  771.  
  772. ParseCommandLine       endp
  773.  
  774. UsageMsg    db cr, lf,"Usage:  CDNET"
  775.             db " [/?] [/C:ClientName] [/S:ServerName] [/D:DriverName]"
  776.             db " [/Q]"," [/U]",cr,lf,"$"
  777.  
  778. InstallMsg  db cr,lf,"Net Work CD Driver Installed.",cr,lf
  779.             db "Copyright 1993, John H. McCoy.","$"
  780. ClientMsg   db cr,lf,"Client Name:  ","$"
  781. ServerMsg   db cr,lf,"Server Name:  ","$"
  782. DriverMsg   db cr,lf,"Driver Name:  ","$"
  783. ActivateMsg db cr,lf,"Link to server will occur when MSCDEX is loaded.",cr,lf,"$"
  784. UnInstallMsg       db cr,lf,"Uninstalled and memory freed",cr,lf,"$"
  785. NotInstallMsg      db cr,lf,"Net Work Driver NOT installed.","$"
  786. NameClaimedMsg     db cr,lf,"Client name already in use on network.",cr,lf,"$"
  787. NetBIOSNotReadyMsg db cr,lf,"Net BIOS not ready.",cr,lf,"$"
  788. DriverNotFoundMsg  db " CD Network Driver not installed.",cr,lf,"$"
  789.  
  790. MoveName proc near
  791.       sub   bx, bx                                 ; es:di points to 1st char
  792.       .repeat                                      ; cx chars left on cmd line
  793.           mov al, es:[di]
  794.           .if (al == '/' || al == ' '|| cx <= 0)
  795.               mov    byte ptr [si+bx], ' '
  796.               inc    bx
  797.           .else
  798.              .if (al >= 'a' && al <= 'z')
  799.                  and    al, 11011111y           ; upper case it
  800.               .endif
  801.               mov    byte ptr [si+bx], al
  802.               inc    bx
  803.               inc    di
  804.               dec    cx
  805.           .endif
  806.       .until bx == dx
  807.  
  808. MoveName endp
  809.  
  810. FindParm proc near
  811.  
  812.    ; al has parm code we are to find       /X: or -X:
  813.  
  814.       mov      di, 80h                ; command line length @ +80h
  815.       sub      ch, ch
  816.       mov      cl, es:[di]
  817.  
  818.  GetNext:                             ; this code allows us to handle names
  819.       call     GetParm                ; like   -C:NET-CD
  820.       cmp      ax, ArgumentFound
  821.       jne      NotFound
  822.       inc      di                     ; found /X or -X, is next char a ':' ?
  823.       dec      cl
  824.       mov      al, es:[di]
  825.       cmp      al, ':'
  826.       je       FoundIt
  827.       loop     GetNext
  828.       mov      ax, ArgumentNotFound
  829.       ret
  830.  
  831.   FoundIt:
  832.       inc   di                           ; /X:name  make di point @ name
  833.       dec   cl
  834.       mov   ax, ArgumentFound
  835.   NotFound: ret
  836.  
  837. FindParm endp
  838.  
  839. ;* GetParm - Scans command line for argument of form /X or -X  where
  840. ;* X = specified ASCII character. Presumes that argument is preceded
  841. ;* by a '/' or a '-'. Comparisons are case insensitive.
  842. ;*
  843. ;* Params: ES:DI = Address of CommandLine -1
  844. ;*         AL    = Paramater character to scan for
  845. ;*         CX    = command line length
  846. ;*
  847. ;* Return: AX    = One of the following codes:
  848. ;*                 NoArgumentsFound  if empty command line
  849. ;*                 ArgumentFound  if argument found
  850. ;*                 ArgumentNotFound if argument not as specified
  851. ;*         ES:DI = Pointer to found argument
  852. ;*         CX    = chars left on command line including arg or 0
  853.  
  854. GetParm PROC NEAR
  855.  
  856.         mov     ah, NoArgumentsFound    ; assume no /X style arguments
  857.         jcxz    exit
  858.         .if (al >= 'a' && al <= 'z')
  859.             and    al, 11011111y           ; Make character upper case
  860.         .endif
  861.  
  862. ; Find start of argument
  863.  
  864. loop1:
  865.         inc     di                      ;
  866.         mov     dl, es:[di]             ; Get character from argument list
  867.         cmp     dl, '/'                 ; Find option prefix '/'
  868.         je      analyze
  869.         cmp     dl, '-'                 ;   or option prefix '-'
  870.         je      analyze
  871.  
  872.         loop    loop1
  873.  
  874.         jmp     exit
  875.  
  876. ; '/' or '-' prefix found. Compare command-line character
  877. ; with character specified in AL.
  878. analyze:
  879.         mov     ah, ArgumentFound         ; Assume argument is okay
  880.         inc     di
  881.         dec     cl
  882.         mov     dl, es:[di]
  883.         .if (dl >= 'a' && dl <= 'z')
  884.             and    dl, 11011111y           ; Make character upper case
  885.         .endif
  886.         cmp     dl, al
  887.         je      exit                    ; specified char
  888.         mov     ah, ArgumentNotFound    ; Else signal bad argument,
  889.         inc     bx
  890.         loop    loop1             ;   continue scan
  891.  
  892. exit:
  893.         mov     al, ah
  894.         cbw                             ; AX = return code
  895.         ret
  896.  
  897. GetParm ENDP
  898.  
  899.             end  Init
  900.