home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / VDISK / VDISK.ASM < prev    next >
Assembly Source File  |  1995-04-14  |  80KB  |  2,168 lines

  1. ;*DDK*************************************************************************/
  2. ;
  3. ; COPYRIGHT (C) Microsoft Corporation, 1989
  4. ; COPYRIGHT    Copyright (C) 1995 IBM Corporation
  5. ;
  6. ;    The following IBM OS/2 WARP source code is provided to you solely for
  7. ;    the purpose of assisting you in your development of OS/2 WARP device
  8. ;    drivers. You may use this code in accordance with the IBM License
  9. ;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
  10. ;    Copyright statement may not be removed.;
  11. ;*****************************************************************************/
  12. title   Protected Mode VDisk for CP/DOS 2.0 (uses DWORD moves).
  13.  
  14. page    60,132
  15.  
  16. ;/*****************************************************************************
  17. ;*
  18. ;* SOURCE FILE NAME =  VDisk.asm
  19. ;*
  20. ;* DESCRIPTIVE NAME =  VDisk Device Driver
  21. ;*
  22. ;*
  23. ;* VERSION      V2.0
  24. ;*
  25. ;* DATE
  26. ;*
  27. ;* DESCRIPTION  Implements a virtual disk in RAM. Can be loaded via
  28. ;*              the following CONFIG.SYS command line:
  29. ;*
  30. ;*           device = ramdrive.sys [bbbb] [ssss] [dddd]
  31. ;*
  32. ;*           bbbb  First numeric argument, if present, is disk size
  33. ;*                   in K bytes. Default value is 64. Min is 16. Max
  34. ;*                   is 4096 (4 Meg).
  35. ;*
  36. ;*           ssss  Second numeric argument, if present, is sector size
  37. ;*                   in bytes. Default value is 512. Allowed values are  ;@mfa
  38. ;*                   128, 256, 512, 1024.
  39. ;*
  40. ;*           dddd  Third numeric argument, if present, is the number of
  41. ;*                   root directory entries. Default is 64. Min is 2
  42. ;*                   max is 1024. The value is rounded up to the nearest
  43. ;*                   sector size boundary.
  44. ;*                 NOTE: In the event that there is not enough memory
  45. ;*                   to create the VDisk volume, VDisk will try to make
  46. ;*                   a DOS volume with 16 directory entries. This may
  47. ;*                   result in a volume with a different number of
  48. ;*                   directory entries than the dddd parameter specifies.
  49. ;*
  50. ;* FUNCTIONS    VDisk_Strategy - Strategy entry point
  51. ;*
  52. ;*
  53. ;* NOTES        NONE
  54. ;*
  55. ;* STRUCTURES   NONE
  56. ;*
  57. ;* EXTERNAL REFERENCES
  58. ;*
  59. ;*              NONE
  60. ;*
  61. ;* EXTERNAL FUNCTIONS
  62. ;*
  63. ;*              NONE
  64. ;*
  65. ;* CHANGE ACTIVITY =
  66. ;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
  67. ;*   --------  ----------  -----  --------------------------------------
  68. ;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
  69. ;*   02/27/91             B718419 Special case of above ptrs
  70. ;*   07/18/91             B724590 Trap 6 in VDISK when running XGA demo
  71. ;*   08/31/92              D24793 VDISK > 4MB
  72. ;*   03/01/93              D62998 Device type & Attributes are wrong
  73. ;*   03/09/93              D63149 Sector size defaults to 512
  74. ;*   04/21/93              D64016 Allocate low, if fails then try high.
  75. ;*   08/04/93              D72412 Increase print space for disk size
  76. ;*
  77. ;*****************************************************************************/
  78.  
  79. .386p
  80.  
  81. .xlist
  82.         include mi.inc
  83.         include devhlp.inc
  84.         include basemaca.inc
  85.         include osmaca.inc
  86.         include devsym.inc
  87.         include struc.inc
  88.         include utilmid.inc
  89.         include error.inc
  90.         include strat2.inc
  91. .list
  92.  
  93.  
  94. extrn    DOSGETMESSAGE:FAR
  95. extrn    DOSPUTMESSAGE:FAR
  96. extrn    DOS32FLATDS:ABS
  97.  
  98.  
  99. TCYieldFlag     equ  8    ; Offset into DOSVARSEG for TCResched Flag
  100. CHUNKDWORDS     equ  8192 ; Max for S/G before a Yield check
  101. MAX_SG_ENTRIES  equ  16   ; Mem Mgmt can only handle SG <= 17 entries;          
  102. attr_volume_id  EQU  8    ; FAT Attribute for volume ID
  103.  
  104. VDiskData       segment  word public 'DATA'
  105. VDiskData       ends
  106.  
  107. VDiskCode       segment  word public 'CODE'
  108. VDiskCode       ends
  109.  
  110. .386p
  111.  
  112. BREAK   <VDiskData Data Segment>
  113.  
  114. ;/*
  115. ;**  VDiskData is the Data Segment for the VDisk driver. It contains the
  116. ;**  Device Header, Dummy Boot Record and BPB for the device, plus other
  117. ;**  global variables to the driver.
  118. ;*/
  119.  
  120. VDiskData segment
  121.  
  122. VDisk_Attrib    EQU     DEV_NON_IBM + DEVLEV_3
  123.  
  124. VDiskHDR        label   word
  125.                 dw      -1, -1          ; Pointer to next device header
  126.                 dw      VDisk_Attrib    ; Attributes of the device
  127.                 dw      VDisk_Strategy  ; Strategy entry point
  128.                 dw      0               ; Interrupt entry point
  129.                 db      1               ; 1 Unit
  130.                 db      7 dup (0)       ; Remaining Name Chars
  131.                 dw      0               ; Protect mode CS selctor of strategy
  132.                 dw      0               ; Protect-mode DS selector
  133.                 dw      0               ; Real-mode CS segment of strategy
  134.                 dw      0               ; Real-mode DS segment
  135.                 dd      1               ; Support physical address > 16M
  136.  
  137. ;/*
  138. ;**  This is the device driver command dispatch table.
  139. ;*/
  140.  
  141. TBLSize equ     29                      ; Command Dispatch Table Size
  142.  
  143. VDiskTBL  label   word
  144.         dw      Init                    ;  0 = Init
  145.         dw      Media_Check             ;  1 = Media Check
  146.         dw      Get_BPB                 ;  2 = Build BPB
  147.         dw      CmdErr                  ;  3 = Reserved
  148.         dw      Read                    ;  4 = Read
  149.         dw      CmdErr                  ;  5 = Non-Destruct Read NoWait
  150.         dw      CmdErr                  ;  6 = Input Status
  151.         dw      CmdErr                  ;  7 = Input Flush
  152.         dw      Write                   ;  8 = Write
  153.         dw      Write                   ;  9 = Write w/Verify
  154.         dw      CmdErr                  ;  A = Output Status
  155.         dw      CmdErr                  ;  B = Output Flush
  156.         dw      CmdErr                  ;  C = Reserved
  157.         dw      RetOK                   ;  D = Device Open (R/M)
  158.         dw      RetOK                   ;  E = Device Close (R/M)
  159.         dw      Rem_Media               ;  F = Removable Media (R/M)
  160.         dw      Ioctl                   ; 10 = Generic Ioctl
  161.         dw      RetOK                   ; 11 = Reset Media
  162.         dw      MapLogical              ; 12 = Get Logical Drive Map
  163.         dw      MapLogical              ; 13 = Set Logical Drive Map
  164.         dw      CmdErr                  ; 14 = DeInstall
  165.         dw      CmdErr                  ; 15 = Reserved
  166.         dw      CmdErr                  ; 16 = Get # Partitions
  167.         dw      CmdErr                  ; 17 = Get Unit map
  168.         dw      Read                    ; 18 = No caching read
  169.         dw      Write                   ; 19 = No caching write
  170.         dw      Write                   ; 1A = No caching write w/Verify
  171.         dw      CmdErr                  ; 1B = Initialize
  172.         dw      CmdErr                  ; 1C = Reserved
  173.         dw      Get_DCS_VCS             ; 1D = Get DCS/VCS
  174.  
  175.  
  176.  
  177. ;/*
  178. ;**  VDisk Bios Parameter Block and Bogus Boot Sector
  179. ;**
  180. ;**  This region is a valid CP/DOS "boot sector" which contains
  181. ;**  the BPB. This is used for storage of the relevant BPB parameters.
  182. ;**
  183. ;**  The BOOT_START code is a very simple stub which does nothing
  184. ;**  except go into an infinite loop. THIS "CODE" SHOULD NEVER
  185. ;**  BE EXECUTED BY ANYONE.
  186. ;*/
  187.  
  188. assume CS:VDiskData
  189. BOOT_SECTOR     LABEL   BYTE
  190.         JMP     BOOT_START
  191.         DB      "OS2VDISK"
  192.  
  193. VDISKBPB label word
  194. SSIZE   dw      512                     ; Physical sector size in bytes ;          
  195. CSIZE   db      0                       ; Sectors/allocation unit
  196. RESSEC  dw      1                       ; Reserved sectors for DOS
  197. FATNUM  db      1                       ; No. allocation tables
  198. DIRNUM  dw      64                      ; Number root directory entries
  199. SECLIM  dw      0                       ; Number sectors
  200.         db      0F8H                    ; Media descriptor
  201. FATSEC  dw      1                       ; Number of sectors per FAT (of FAT ?)
  202.         dw      1                       ; Number of sectors per track
  203.         dw      1                       ; Number of heads
  204.         dd      0                       ; Number of hidden sectors
  205. BIGSEC  dd      0                       ; Big Number of sectors      ;          
  206.  
  207.  
  208. SEC_SHIFT db     7                      ; Shifting number of        ;          
  209.                                         ;  sectors LEFT by this
  210.                                         ;  many bits yields #dwords
  211.                                         ;  in that many sectors.
  212.                                         ;  128   5
  213.                                         ;  256   6
  214.                                         ;  512   7
  215.                                         ;  1024  8
  216.  
  217. BOOT_START label near
  218.         JMP     BOOT_START
  219.  
  220. BOOT_SIG        LABEL BYTE
  221.         DB      (512 - (OFFSET BOOT_SIG - OFFSET BOOT_SECTOR)) DUP ("A") ;          
  222.  
  223. ;/*
  224. ;**  The following label is used to determine the size of the boot record
  225. ;**             OFFSET BOOT_END - OFFSET BOOT_SECTOR
  226. ;*/
  227.  
  228. BOOT_END LABEL BYTE
  229.  
  230. DevHelp         DD      0               ; DevHelp Function Router Address
  231. VDisk_Base      DD      0               ; Physical address of base of VDisk RAM
  232. TCReschedFlag   DD      0               ; Time Critical Thread Flag Address
  233. TotalSectors    DD      0               ; Total number of sectors    ;          
  234.  
  235. ;/*
  236. ;**  Device capabilities to be returned from command 1D.
  237. ;*/
  238.  
  239. VDisk_Caps LABEL BYTE
  240.         DW      0                       ; reserved, set to zero
  241.         DB      1                       ; major version of interface supported
  242.         DB      1                       ; minor version of interface supported
  243.         DD      GDC_DD_No_Block ; driver capabilties
  244.         DW      offset VDisk_Strat2, VDiskCode  ;  entry point for strategy-2
  245.         DD      0                       ; entry point for DD_EndOfInt
  246.         DD      0                       ; entry point for DD_ChgPriority
  247.         DD      0                       ; entry point for DD_SetRestPos
  248.         DD      0                       ; entry point for DD_GetBoundary
  249.  
  250. ;/*
  251. ;**  Volume characteristics to be returned for command 1D
  252. ;*/
  253.  
  254. NUMBER_CYLINDERS  EQU  1                                           ;           
  255. VDisk_VolChars LABEL BYTE
  256.         DW      VC_RAM_DISK             ; Volume descriptor
  257.         DW      0                       ; Avg. seek time, milliseconds
  258.         DW      0                       ; Avg latency, milliseconds
  259.         DW      0FFh                    ; # blocks on smallest track
  260.         DW      0FFh                    ; # blocks on largest track
  261.         DW      1                       ; # Heads / cylinder
  262.         DD      NUMBER_CYLINDERS        ; # cylinders on volume    ;           
  263.         DD      0                       ; block in center of volume (for seek)
  264.         DW      0FFh                    ; Max S/G list size.
  265.  
  266.  
  267. NORMAL_READ     EQU     0
  268. NORMAL_WRITE    EQU     1
  269. LINEAR_READ     EQU     2
  270. LINEAR_WRITE    EQU     4
  271.  
  272. .errnz (PB_READ_X - 01Eh)
  273. .errnz (PB_WRITE_X - 01Fh)
  274. .errnz (PB_WRITEV_X - 020h)
  275. .errnz (PB_PREFETCH_X - 021h)
  276. SG_VDisk_RW LABEL BYTE
  277.         DB      LINEAR_READ
  278.         DB      LINEAR_WRITE
  279.         DB      LINEAR_WRITE
  280.         DB      LINEAR_READ
  281.  
  282. DATA_END        label   word    ; End of Data Segment after Init
  283.  
  284. BREAK   <Disposable Init Data>
  285.  
  286. ;/*
  287. ;**  INIT data which need not be part of resident image
  288. ;*/
  289.  
  290. DEV_SIZE        DD      64      ; Size in K of this device
  291.  
  292. NUM_ARG         DB      1       ; Counter for order dependent numeric arguments
  293.                                 ; bbbb,ssss,dddd seperated by commas.
  294.  
  295. NUM_NUM         DB      0       ; Counter for order dependent numeric arguments
  296.                                 ; bbbb ssss dddd seperated by spaces.
  297.  
  298. DIRSEC          DW      ?       ; Number of directory sectors
  299.  
  300. ;/*
  301. ;**  Define and Statically Initialize Dummy_ReqPacket (WRITE)
  302. ;**  Used for fornatting the VDisk at Init time.
  303. ;*/
  304.  
  305. Dummy_ReqPacket label   word
  306.                 db      0               ; Unused packet size
  307.                 db      0               ; subunit number of block device
  308.                 db      CMDOUTPUT       ; command code
  309.                 dw      0               ; status word
  310.                 dd      0               ; reserved
  311.                 dd      0               ; device multiple-request link
  312.                 db      0               ; Unused
  313.                 dd      0               ; Filled at Init Time
  314.                 dw      1               ; 1 sector/write
  315.                 dw      0               ; start sector
  316.  
  317. ;/*
  318. ;**  Message texts and common data
  319. ;*/
  320.  
  321. MAXMSG  EQU     1024
  322. IvCount EQU     4
  323.  
  324. MsgFile db      "OSO001.MSG", 0
  325. MsgLen  dw      0
  326. MsgBuff db      MAXMSG DUP(" ")
  327.  
  328. IvTable dd      Var1
  329.         dd      Var2
  330.         dd      Var3
  331.         dd      Var4
  332.  
  333. Var1    db      "A", 0
  334. Var2    db      6 DUP(" "), 0    ;           increase from 4 DUP to 6 DUP
  335.                                  ;    so we can print "524288"
  336.                                  ;    (before, we only printed up to 4096)
  337. Var3    db      4 DUP(" "), 0
  338. Var4    db      4 DUP(" "), 0
  339.  
  340.  
  341. ;/*
  342. ;**  Volume Label and Sector Buffer for Formatting the VDisk at Init
  343. ;*/
  344.  
  345. VOLID   DB      'OS2VDISK   ',ATTR_VOLUME_ID
  346.         DB      10 DUP (0)
  347.         DW      1100000000000000B       ;12:00:00
  348.         DW      0000101011001001B       ;JUN 9, 1985
  349.         DW      0,0,0
  350.  
  351. SECTOR_BUFFER   DB      1024 DUP(0)
  352.  
  353. INIT_BPB        DD      offset VDISKBPB, VDiskData
  354.  
  355. VDiskData ends
  356.  
  357. BREAK   <VDiskCode Code Segment>
  358.  
  359. VDiskCode segment
  360.  
  361. ;/***************************************************************************
  362. ;*
  363. ;* FUNCTION NAME = VDisk_Strategy
  364. ;*
  365. ;* DESCRIPTION   = VDisk Strategy Entry Point
  366. ;*
  367. ;*                 Entry point called by File System to request service.
  368. ;*                 Validates request block and dispatches to the correct
  369. ;*                 service routine in VDiskCode.
  370. ;*
  371. ;*                 Called in protect mode only.
  372. ;*
  373. ;* INPUT         = ES: BX = ptr to request block
  374. ;*                 DS = VDiskData data segment
  375. ;*
  376. ;* OUTPUT        = ES: BX = ptr to request block
  377. ;*
  378. ;* RETURN-NORMAL = Status set to OK in request block
  379. ;*
  380. ;* RETURN-ERROR  = Status set in request block to indicate error
  381. ;*
  382. ;**************************************************************************/
  383.  
  384. Procedure VDisk_Strategy,FAR
  385. assume  CS:VDiskCode,DS:VDiskData,ES:NOTHING,SS:NOTHING
  386.  
  387.         mov     al, es:[bx].ReqFunc     ; Command code
  388.         mov     ah, TBLSize             ; Valid range
  389.         .if < al be ah >
  390.                 cbw                     ; Make command code a word
  391.                 mov     si, ax
  392.                 add     si, ax          ; (si) = command offset
  393.                 call    VDiskTBL[si]    ; go do request
  394.         .else
  395.                 call    CmdErr
  396.         .endif
  397.  
  398.         mov     es:[bx].ReqStat, ax     ; Set return status
  399.  
  400.         or      es:[bx].ReqStat, STDON  ; Set DONE bit at Init Time
  401.  
  402.         ret
  403.  
  404. EndProc VDisk_Strategy
  405.  
  406.  
  407. BREAK   <VDisk_Strat2>
  408. ;/***************************************************************************
  409. ;*
  410. ;* FUNCTION NAME = VDisk_Strat2
  411. ;*
  412. ;* DESCRIPTION   = VDisk Strategy2 Entry Point
  413. ;*
  414. ;*                 Entry point called by File System to request Strategy2
  415. ;*                 service.
  416. ;*
  417. ;*                 Called in protect mode only.
  418. ;*
  419. ;*                 This is only excepted to be called from FAT, and does not
  420. ;*                 support the full interface. If changes are made to the manner
  421. ;*                 in which Strat2 FAT calls are made, VDisk should be examined
  422. ;*                 for possible errors.
  423. ;*
  424. ;*
  425. ;* INPUT         = ES:BX = ptr to Strat2 request list header (RLH)
  426. ;* OUTPUT        = ES:BX = ptr to Strat2 request list header (RLH)
  427. ;*
  428. ;* RETURN-NORMAL =
  429. ;* RETURN-ERROR  =
  430. ;*
  431. ;**************************************************************************/
  432.  
  433. Procedure VDisk_Strat2, FAR
  434.  
  435. LocalVar vs2_RLH, DWORD                 ; Request List Header
  436.                                         ; Start req after last sector done
  437. LocalVar Running_PB_Start_Block,     DWORD                           ;          
  438.                                         ; Start after last SG entry processed
  439. LocalVar Running_PB_SG_Array_Offset, DWORD                           ;          
  440.  
  441.         EnterProc
  442.  
  443.         SaveReg <ds>
  444.  
  445.         mov     vs2_RLH.Segmt, es
  446.         mov     vs2_RLH.Offst, bx
  447.         mov     ax, VDiskData
  448.         mov     ds, ax
  449.  
  450. ;/*
  451. ;**  Set up status/error fields of RLH
  452. ;*/
  453.  
  454.         mov     es:[bx].RLH_Lst_Status, RLH_Seq_In_Process
  455.         mov     es:[bx].RLH_y_Done_Count, 0
  456.  
  457.  
  458.         mov     ecx,es:[bx].RLH_Count           ; ECX = # Requests
  459.         or      ecx,ecx                         ; Requests to process?
  460.         jz      Strat2_Done                     ;  No. Return
  461.  
  462.         add     bx, size Req_List_Header        ; ES:BX = Request Header (RH)
  463.  
  464. ;/*
  465. ;**  ECX   = # requests to process (> 0)
  466. ;**  ES:BX = Current request
  467. ;*/
  468.  
  469. request_loop:
  470.  
  471.         SaveReg <ecx>
  472.  
  473. ;/*
  474. ;**  Setup random fields
  475. ;*/
  476.         mov     es:[bx].RH_Status, RH_PROCESSING
  477.  
  478.         movzx   ecx, es:[bx].PB_SG_Desc_Count ; ECX = # S/G Descriptors
  479.  
  480.         xor     eax, eax                                             ;          
  481.         push    eax                           ; SG entries done so far          
  482.         mov     Running_PB_Start_Block, 0     ; Start at zero        ;          
  483.         mov     Running_PB_SG_Array_Offset, 0 ; Start at zero        ;          
  484. SG_loop:                                      ; More SG entries      ;          
  485.         RestoreReg <ecx>                      ; SG entries done so far          
  486.  
  487.         cmp     cx, es:[bx].PB_SG_Desc_Count  ; All SG entries done ?;          
  488.                                               ; Yes, try another List entry
  489.         jge     vst30                                                ;          
  490.         mov     ax, cx                        ; SG entries done so far          
  491.         add     ax, MAX_SG_ENTRIES            ; If we attempt MAX    ;          
  492.        .IF <ax gt es:[bx].PB_SG_Desc_Count>   ; Is that > SG list ?  ;          
  493.            mov  ax, cx                        ; Yes                  ;          
  494.                                               ; Do only as many as we need
  495.            sub  ax, es:[bx].PB_SG_Desc_Count                         ;          
  496.            neg  ax                            ; Make positive        ;          
  497.                                               ; Alrdy done + entries needed
  498.            add  cx, ax                                               ;          
  499.            xchg ecx, eax                      ; Do this many (ecx)   ;          
  500.        .ELSE                                  ; No, do MAX           ;          
  501.            mov  cx, MAX_SG_ENTRIES                                   ;          
  502.        .ENDIF                                                        ;          
  503.                                               ; Alrdy done + about to do
  504.         SaveReg  <eax>                                               ;          
  505.  
  506.         mov     esi, ecx
  507.         dec     esi
  508.         .errnz (8 - size SG_Descriptor)
  509.         shl     esi,3
  510.         movzx   ebx,bx
  511.                                                 ; ECX entries into SG lst
  512.         mov     eax, esi                                             ;          
  513.         add     eax, size SG_Descriptor         ; Next entry         ;          
  514.         add     esi,ebx
  515.         add     esi, PB_SG_Array_Offset         ; ES:SI = Last SG Descriptor
  516.                                                 ; Plus SG entries prvly done
  517.         add     esi, Running_PB_SG_Array_Offset                      ;          
  518.                                                 ; Update the ones done alrdy
  519.         add     Running_PB_SG_Array_Offset, eax                      ;          
  520.                                                 ; EAX = Total Byte count
  521.         xor     eax,eax                                              ;          
  522.  
  523. ;/*
  524. ;**  Calculate total size of request, for the PageListToLin call
  525. ;*/
  526.  
  527. vst1:   add     eax, es:[si].SG_BufferSize
  528.         sub     esi, size SG_Descriptor
  529.         loop    vst1
  530.  
  531. ;/*
  532. ;**  ECX = Total bytes in S/G request
  533. ;*/
  534.         mov     ecx, eax
  535.         add     esi, size SG_Descriptor         ; ES:ESI = S/G PageList
  536.  
  537. ;/*
  538. ;**  Get the linear address of the S/G page list
  539. ;*/
  540.  
  541.         mov     ax,es                           ; AX:ESI = (sel,offset)
  542.         mov     dl,DevHlp_VirtToLin
  543.         call    DevHelp                         ; EAX = (linear)
  544.  
  545. ;/*
  546. ;**  Convert the page list to a contiguous linear region
  547. ;*/
  548.  
  549.         mov     edi,eax                         ; EDI = Lin address of S/G
  550.                                                 ;       pagelist
  551.         mov     dl,DevHlp_PageListToLin
  552.         call    DevHelp                         ; EAX = Linear address of
  553.                                                 ;  Region mapping pages in
  554.                                                 ;  paglist.
  555.  
  556.         mov     edi, eax                        ; EDI = Linear address of
  557.                                                 ;       xfer region
  558.         mov     edx, ecx                        ; bytes count        ;          
  559.         shr     edx, 2                          ; bytes => DWORDS    ;          
  560.                                                 ; Shift factor DWORDS => sectors
  561.         mov     cl,  SEC_SHIFT                                       ;          
  562.                                                 ; Get number of sectors
  563.         shr     edx, cl                                              ;          
  564.         mov     ecx, edx
  565.  
  566. ;             mov     ecx, es:[bx].PB_Block_Count     ; ECX = # Sectors
  567.         mov     edx, Running_PB_Start_Block     ; Previous iterations           
  568.                                                 ; Previous iterations+# sectors
  569.         add     Running_PB_Start_Block, ecx     ;     to do now      ;          
  570.         add     edx, es:[bx].PB_Start_Block     ; EDX = First sector            
  571.  
  572.         movzx   esi, es:[bx].RH_Command_Code
  573.         sub     esi, PB_READ_X
  574.         movzx   esi, byte ptr [esi].SG_VDisk_RW ; ESI = Read/Write
  575.  
  576. ;/*
  577. ;** Call VDisk_IO to perform the actual I/O
  578. ;*/
  579.         SaveReg <bx>
  580.         call    VDisk_IO_Lin
  581.         RestoreReg <bx>
  582.         or      ah,ah                           ; Successful?
  583. ;                 je      short vst30
  584.         jnz      short error_found                                   ;          
  585.         jmp     sg_loop                     ; See if more SG entries ;          
  586. error_found:                                                         ;           
  587.         mov     es:[bx].RH_Status, RH_UNREC_ERROR
  588.         jmp     short Strat2_Done
  589.  
  590. vst30:  mov     es:[bx].RH_Status, RH_DONE
  591. ;                  cmp     es:[bx].RH_Length, RH_LAST_REQ ; Done w/all requests?
  592. ;                  je      short Strat2_Done              ;  Yes.
  593.         add     bx, es:[bx].RH_Length           ; ES:BX = Next Request Header
  594.         RestoreReg <ecx>                        ; ECX = RH Count
  595.  
  596.         dec     ecx
  597.         jnz     request_loop                    ; Do the next one
  598.  
  599. Strat2_Done:
  600.  
  601. ;/*
  602. ;**  Call notify_address, if appropriate
  603. ;*/
  604.  
  605.         les     bx, vs2_RLH                     ; ES:BX = RLH
  606.         mov     es:[bx].RLH_Lst_Status, RLH_All_Req_Done
  607.         neg     ecx
  608.         add     ecx, es:[bx].RLH_Count          ; ECX = # Completed requests
  609.         mov     es:[bx].RLH_y_Done_Count, ecx
  610.         test    es:[bx].RLH_Request_Control, RLH_Notify_Done
  611.         jz      short vst40
  612.         call    es:[bx].RLH_Notify_Address
  613.  
  614. vst40:  RestoreReg <ds>
  615.  
  616.         LeaveProc
  617.         ret
  618.  
  619. EndProc VDisk_Strat2
  620.  
  621. BREAK   <Media_Check>
  622. ;/***************************************************************************
  623. ;*
  624. ;* FUNCTION NAME = Media_Check
  625. ;*
  626. ;* DESCRIPTION   = VDisk Media Check Routine
  627. ;*                 Checks state of media for block devices
  628. ;*
  629. ;*                 Always returns Media Unchanged
  630. ;*
  631. ;* INPUT         = ES:BX = request packet address
  632. ;*                 DS = VDiskData
  633. ;*
  634. ;* OUTPUT        =
  635. ;*
  636. ;* RETURN-NORMAL = AX = status to return to DOS
  637. ;*                 Return Code set in Request Packet
  638. ;*
  639. ;* RETURN-ERROR  = None
  640. ;*
  641. ;**************************************************************************/
  642.  
  643. Procedure Media_Check,NEAR,LOCAL
  644. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING,DS:NOTHING
  645.  
  646.         mov     es:[bx.MedChkflag], 1   ; Always not changed
  647.         xor     ah, ah                  ; NOERROR
  648.         ret
  649.  
  650. EndProc Media_Check
  651.  
  652.  
  653. BREAK   <Get_BPB>
  654. ;/***************************************************************************
  655. ;*
  656. ;* FUNCTION NAME = Get_BPB
  657. ;*
  658. ;* DESCRIPTION   = VDisk Build BPB Routine
  659. ;*                 Returns pointer to BPB at VDISKBPB
  660. ;*
  661. ;* INPUT         = ES:BX = request packet address
  662. ;*                 DS = VDiskData
  663. ;*
  664. ;* OUTPUT        =
  665. ;*
  666. ;* RETURN-NORMAL = AX = status to return to DOS
  667. ;*                 BPB Address set in Request Packet
  668. ;*
  669. ;* RETURN-ERROR  = NONE
  670. ;*
  671. ;**************************************************************************/
  672.  
  673. Procedure Get_BPB,NEAR,LOCAL
  674. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  675.  
  676.         mov     word ptr es:[bx.BldBPBpBPB], offset VDISKBPB
  677.         mov     word ptr es:[bx.BldBPBpBPB+2], ds
  678.         xor     ah, ah
  679.         ret
  680.  
  681. EndProc Get_BPB
  682.  
  683.  
  684. BREAK   <Read>
  685. ;/***************************************************************************
  686. ;*
  687. ;* FUNCTION NAME = Read
  688. ;*
  689. ;* DESCRIPTION   = VDisk Read Routine
  690. ;*                 Performs Read Operation by calling VDisk_IO
  691. ;*
  692. ;* INPUT         = ES:BX = request packet address
  693. ;*                 DS = VDiskData
  694. ;*
  695. ;* OUTPUT        =
  696. ;*
  697. ;* RETURN-NORMAL = AX = status to return to DOS
  698. ;*
  699. ;* RETURN-ERROR  = NONE
  700. ;*
  701. ;**************************************************************************/
  702.  
  703. Procedure Read,NEAR,LOCAL
  704. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  705.  
  706.         mov     si, NORMAL_READ
  707.         call    VDisk_IO
  708.         ret
  709.  
  710. EndProc Read
  711.  
  712.  
  713. BREAK   <Write>
  714. ;/***************************************************************************
  715. ;*
  716. ;* FUNCTION NAME = Write
  717. ;*
  718. ;* DESCRIPTION   = VDisk Write Routine
  719. ;*                 Performs Write Operation by calling VDisk_IO
  720. ;*
  721. ;* INPUT         = ES:BX = request packet address
  722. ;*                 DS = VDiskData
  723. ;*
  724. ;* OUTPUT        =
  725. ;*
  726. ;* RETURN-NORMAL = AX = status to return to DOS
  727. ;*
  728. ;* RETURN-ERROR  = NONE
  729. ;*
  730. ;**************************************************************************/
  731.  
  732. Procedure Write,NEAR,LOCAL
  733. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  734.  
  735.         mov     si, NORMAL_WRITE
  736.         call    VDisk_IO
  737.         ret
  738.  
  739. EndProc Write
  740.  
  741.  
  742. BREAK   <Rem_Media>
  743. ;/***************************************************************************
  744. ;*
  745. ;* FUNCTION NAME = Rem_Media
  746. ;*
  747. ;* DESCRIPTION   = VDisk Removable Media Routine
  748. ;*                 Checks if Media is Removable
  749. ;*
  750. ;*                 Always returns media not removable
  751. ;*
  752. ;* INPUT         = ES:BX = request packet address
  753. ;*                 DS = VDiskData
  754. ;*
  755. ;* OUTPUT        =
  756. ;*
  757. ;* RETURN-NORMAL = AX = status to return to DOS
  758. ;*
  759. ;* RETURN-ERROR  = NONE
  760. ;*
  761. ;**************************************************************************/
  762.  
  763. Procedure Rem_Media,NEAR,LOCAL
  764. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  765.  
  766.         mov     ax, STBUI       ; Media NOT Removable (Busy = 1)
  767.         ret
  768.  
  769. EndProc Rem_Media
  770.  
  771.  
  772. BREAK   <MapLogical>
  773. ;/***************************************************************************
  774. ;*
  775. ;* FUNCTION NAME = MapLogical
  776. ;*
  777. ;* DESCRIPTION   = VDisk Get/Set Logical Drive Routine
  778. ;*                 Get/Set the logical drive specified
  779. ;*
  780. ;*                 Since we only have one drive, always returns zero (0)
  781. ;*                 in Logical Unit field
  782. ;*
  783. ;* INPUT         = ES:BX = request packet address
  784. ;*                 DS = VDiskData
  785. ;*
  786. ;* OUTPUT        =
  787. ;*
  788. ;* RETURN-NORMAL = AX = status to return to DOS
  789. ;*
  790. ;* RETURN-ERROR  = NONE
  791. ;*
  792. ;**************************************************************************/
  793.  
  794. Procedure MapLogical,NEAR,LOCAL
  795. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  796.  
  797.  
  798. ;       mov     es:[bx.Logical_Drive], 0
  799.         mov     es:[bx].PktUnit, 0
  800.         xor     ah, ah
  801.         ret
  802.  
  803. EndProc MapLogical
  804.  
  805. BREAK   <Get_DCS_VCS>
  806. ;/***************************************************************************
  807. ;*
  808. ;* FUNCTION NAME = Get_DCS_VCS
  809. ;*
  810. ;* DESCRIPTION   = VDisk Get Device/Volume characteristics
  811. ;*                 Returns pointers to DCS and VCS
  812. ;*
  813. ;* INPUT         = ES:BX = request packet address
  814. ;*                 DS = VDiskData
  815. ;*
  816. ;* OUTPUT        =
  817. ;*
  818. ;* RETURN-NORMAL = AX = status to return to DOS
  819. ;*                 DCS Address set in Request Packet
  820. ;*                 VCS Address set in Request Packet
  821. ;*
  822. ;* RETURN-ERROR  = NONE
  823. ;*
  824. ;**************************************************************************/
  825.  
  826. ASSUME DS:VDiskData, ES:NOTHING, FS:NOTHING
  827.  
  828. Procedure Get_DCS_VCS
  829.  
  830.         mov     es:[bx].Pkt_1d_DCS_Addr.Segmt,VDiskData
  831.         mov     es:[bx].Pkt_1d_DCS_Addr.Offst,offset VDisk_Caps
  832.         mov     es:[bx].Pkt_1d_VCS_Addr.Segmt,VDiskData
  833.         mov     es:[bx].Pkt_1d_VCS_Addr.Offst,offset VDisk_VolChars
  834.  
  835.         xor     ah,ah
  836.         ret
  837.  
  838. EndProc Get_DCS_VCS
  839.  
  840.  
  841.  
  842. BREAK   <RetOK>
  843. ;/***************************************************************************
  844. ;*
  845. ;* FUNCTION NAME = RetOK
  846. ;*
  847. ;* DESCRIPTION   = Returns OK status
  848. ;*                 Returns OK status for supported do-nothing entry points
  849. ;*
  850. ;*                 Called in place of Open, Close, Reset Media Routines
  851. ;*
  852. ;* INPUT         = ES:BX = request packet address
  853. ;*                 DS = VDiskData
  854. ;*
  855. ;* OUTPUT        =
  856. ;*
  857. ;* RETURN-NORMAL = AX = status to return to DOS
  858. ;*
  859. ;* RETURN-ERROR  = NONE
  860. ;*
  861. ;**************************************************************************/
  862.  
  863. Procedure RetOK,NEAR,LOCAL
  864. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  865.  
  866.         xor     ah, ah          ; NOERROR
  867.         ret
  868.  
  869. EndProc RetOK
  870.  
  871.  
  872. BREAK   <CmdErr>
  873. ;/***************************************************************************
  874. ;*
  875. ;* FUNCTION NAME = CmdErr
  876. ;*
  877. ;* DESCRIPTION   = Command Error
  878. ;*                 Returns error condition of Unknown Command
  879. ;*
  880. ;*                 Called when out of range request comes to VDisk_Strategy,
  881. ;*                 or when an unsupported function request is made.
  882. ;*
  883. ;* INPUT         = ES:BX = request packet address
  884. ;*                 DS = VDiskData
  885. ;*
  886. ;* OUTPUT        =
  887. ;*
  888. ;* RETURN-NORMAL = AX = Status to return to DOS (ERROR + UnKnown Command Error)
  889. ;*
  890. ;* RETURN-ERROR  = NONE
  891. ;*
  892. ;**************************************************************************/
  893.  
  894. Procedure CmdErr,NEAR,LOCAL
  895. assume  DS:VDiskData, ES:NOTHING, SS:NOTHING
  896.  
  897.         mov     ax, STERR + ERROR_I24_BAD_COMMAND
  898.         ret
  899.  
  900. EndProc CmdErr
  901.  
  902.  
  903. BREAK   <Ioctl>
  904. ;/***************************************************************************
  905. ;*
  906. ;* FUNCTION NAME = Ioctl
  907. ;*
  908. ;* DESCRIPTION   = Generic Ioctl Support Routine
  909. ;*                 Supports CHKDSK use of Function 63. Get Device Parameters
  910. ;*
  911. ;*                 Called when an application desires the BPB of the Device.
  912. ;*
  913. ;* INPUT         = ES:BX = request packet address
  914. ;*                 DS = VDiskData
  915. ;*
  916. ;* OUTPUT        =
  917. ;*
  918. ;* RETURN-NORMAL = AX = Status to return to DOS
  919. ;*
  920. ;* RETURN-ERROR  = AX = ERROR_I24_GEN_FAILURE
  921. ;*                 (when packet addresses not verified)
  922. ;*
  923. ;**************************************************************************/
  924.  
  925. Procedure Ioctl,NEAR
  926. assume  DS:VDiskData, ES:NOTHING, SS:NOTHING
  927.  
  928.         .if < es:[bx+GIOCategory] eq 8H > AND
  929.         .if < es:[bx+GIOFunction] eq 63H >
  930.  
  931.                 SaveReg <ds,es,bx,cx,si,di>
  932.  
  933.                 mov     di, word ptr es:[bx+GIODataPack]    ; (di) = offset
  934.                 mov     ax, word ptr es:[bx+GIODataPack+2]  ; (ax) = seg/sel
  935.                 mov     cx, 36                              ; length
  936.                 mov     dh, 1                               ; read/write
  937.                 mov     dl, DevHlp_VerifyAccess
  938.  
  939.                 call    DevHelp
  940.                 .if c                                       ; Access OK ?
  941.                     mov     ax, STERR+ERROR_I24_GEN_FAILURE
  942.                     jmp     eioctl
  943.                 .endif
  944.  
  945.                 les     di, es:[bx+GIODataPack] ; Target = User Buffer
  946.                 movzx   edi,di
  947.                 lea     esi, VDISKBPB           ; Source = VDiskData:VDISKBPB
  948.  
  949. ;                           mov     cx, 21
  950.                 mov     ecx, 25                                      ;          
  951.                 rep     movsb                   ; Move BPB
  952.  
  953. ;                           mov     ax, SECLIM      ; 1st word of Large Sectors
  954. ;                           stosw
  955.  
  956. ;                           mov     ecx, 5          ; Last word of Large Sectors
  957. ;                           xor     ax, ax          ; + 3 Reserved words
  958. ;                           rep     stosw           ; + 1 Word # Cylinders (0)
  959.  
  960.  
  961.                 mov     ecx, 3          ; Last word of Large Sectors ;          
  962.                 xor     ax, ax          ; + 3 Reserved words
  963.                 rep     stosw           ; + 1 Word # Cylinders (0)
  964.  
  965.                 mov     ecx, 1                  ;                               
  966.                 mov     ax,  NUMBER_CYLINDERS   ; # cylinders                   
  967.                 rep     stosw                   ;                               
  968.  
  969.                 mov     al, 7           ; Device Type = Other
  970.                 stosb
  971.  
  972.                 mov     ax, 1+4         ; Device Attributes =                   
  973.                                         ; NonRemovable+NoChangeStatus+>16MB
  974.                 stosw
  975.  
  976.                 xor     ax, ax          ; NOERROR
  977.  
  978. eioctl:
  979.                 RestoreReg      <di,si,cx,bx,es,ds>
  980.         .else
  981.                 call    CmdErr
  982.         .endif
  983.  
  984.         ret
  985.  
  986. EndProc Ioctl
  987.  
  988. BREAK   <VDisk_IO>
  989. ;/***************************************************************************
  990. ;*
  991. ;* FUNCTION NAME = VDisk_IO
  992. ;*
  993. ;* DESCRIPTION   = VDisk I/O Routine
  994. ;*
  995. ;*                 Performs I/O Operations to VDisk. Common worker routine for
  996. ;*                 Read, Write, Write w/Verify.
  997. ;*
  998. ;*           This routine first takes the count parameters out of the request
  999. ;*           packet. It then checks the I/O parameters for validity, then sets
  1000. ;*           up the parameters for the block move operation. It converts the
  1001. ;*           SectorCnt in CX to the # of words in that many sectors or 8000H,
  1002. ;*           which ever is less. It also converts the StartSector in DX into
  1003. ;*           a 32 bit byte offset (IO_Start) equal to that many sectors.
  1004. ;*
  1005. ;*           NOTE that we convert the number of sectors to transfer
  1006. ;*           to a number of words to transfer.
  1007. ;*                   Sector size is always a power of two, therefore a
  1008. ;*                   multiple of two so there are no "half word" problems.
  1009. ;*           DOS NEVER asks for a transfer larger than 64K bytes except
  1010. ;*                   in one case where we can ignore the extra anyway.
  1011. ;*                   or when an unsupported function request is made.
  1012. ;*
  1013. ;*           This routine also does all address translation for accessing
  1014. ;*           the VDisk, and the Time Critical considerations. Note the
  1015. ;*           main I/O loop is optimized for PRTECTED MODE, and we take care
  1016. ;*           of allowing Time Critical threads run.
  1017. ;*
  1018. ;* INPUT         = ES:BX = request packet address
  1019. ;*                 DS = VDiskData
  1020. ;*                 SI = Read/Write Flag ( 0 => READ)
  1021. ;*
  1022. ;* OUTPUT        =
  1023. ;*
  1024. ;* RETURN-NORMAL = AX = status to return to DOS
  1025. ;*                 Request packet has # of sectors transferred
  1026. ;*
  1027. ;* RETURN-ERROR  = None
  1028. ;*
  1029. ;**************************************************************************/
  1030.  
  1031. Procedure VDisk_IO,NEAR,LOCAL
  1032. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  1033.  
  1034.         movzx   ecx, es:[bx.IOcount]            ; ECX = SectorCnt    ;          
  1035.         movzx   edx, es:[bx.IOstart]            ; EDX = StartSector  ;          
  1036.  
  1037.         mov     eax, edx                        ; EAX = Tmp          ;          
  1038.         add     eax, ecx                        ; EAX = EndSector    ;          
  1039.  
  1040. ;                  .if < dx ae SECLIM > OR                 ; Validate Request
  1041. ;                  .if < ax a SECLIM >
  1042.         .if < edx ae TotalSectors > OR          ; Validate Request
  1043.         .if < eax a TotalSectors >
  1044.                 mov     ax, STERR + 8           ; ERROR + SECTOR NOT FOUND
  1045.         .else NEAR
  1046.  
  1047.                 mov es:[bx.IOcount], cx         ; Set Request.Sectors Moved
  1048.  
  1049. Entry VDisk_IO_Lin,NEAR                         ; S/G Entry Point
  1050.  
  1051.  
  1052.                 localvar        RWFlag, WORD
  1053.                 localvar        DWordLimit, DWORD
  1054.                 localvar        ChunkSize, DWORD
  1055.                 localvar        ChunkBytes, DWORD
  1056.                 localvar        t_es, WORD
  1057.                 localvar        t_ds, WORD
  1058.                 localvar        t_bx, WORD
  1059.                 localvar        t_DTA, DWORD
  1060.                 localvar        t_DH, DWORD
  1061.                 localvar        t_TCReschedFlag, DWORD
  1062.                 localvar        VDiskIO, DWORD
  1063.  
  1064.                 EnterProc
  1065. ;/*
  1066. ;**  Convert sector count to WordLimit : Bytes/Sector = SEC_SHIFT
  1067. ;*/
  1068.  
  1069.                 movzx   eax, cx         ; EAX = SectorCount
  1070.                 mov     cl, SEC_SHIFT
  1071.                 shl     eax, cl         ; EAX = DWordLimit
  1072.                 mov     DWordLimit, eax ; Save It
  1073. ;/*
  1074. ;**  Compute the start offset of I/O from sector 0 of the VDisk
  1075. ;*/
  1076.  
  1077.                 movzx   eax, dx         ; EAX = Starting Sector #
  1078.                 movzx   edx, SSIZE      ; EDX = Bytes/Sector
  1079.                 mul     edx             ; EDX:EAX is byte offset of start
  1080. ;/*
  1081. ;**  Compute the 32 bit address of start of I/O on the VDisk
  1082. ;*/
  1083.  
  1084.                 add     eax, VDisk_Base ; EAX = Starting linear address
  1085. ;/*
  1086. ;**  Save the DevHelp Function Router on the stack along with any
  1087. ;**  other variables needed from the data segment VDiskData. This is
  1088. ;**  because the loading of DS and ES for the transfer will destroy
  1089. ;**  addressibility to the VDiskData segment and the request packet.
  1090. ;**  Remember to restore the t_registers BEFORE removing the frame.
  1091. ;*/
  1092.  
  1093.  
  1094.                 mov     RWFlag, si
  1095.                 mov     VDiskIO, eax                    ; VDiskIO
  1096.                 mov     eax,DevHelp
  1097.                 mov     t_DH, eax
  1098.                 mov     eax, TCReschedFlag
  1099.                 mov     t_TCReschedFlag, eax
  1100.                 test    si, LINEAR_READ or LINEAR_WRITE
  1101.                 jnz     short vdi30
  1102.                 mov     edi, es:[bx.IOpData]
  1103. vdi30:          mov     ChunkSize, CHUNKDWORDS
  1104.                 mov     t_DTA, edi                      ; t_DTA = DTA
  1105.                 mov     t_es, es
  1106.                 mov     t_ds, ds                        ; Addressibility
  1107.                 mov     t_bx, bx
  1108.  
  1109.  
  1110. ;/*
  1111. ;**  Main Transfer Loop
  1112. ;*/
  1113.                 .while < DWordLimit a 0 > NEAR
  1114. ;/*
  1115. ;**  Adjust ChunkSize to handle case of left overs smaller
  1116. ;**  than a Chunk. Also set up cx to correct size of Segment
  1117. ;**  to be mapped for this transfer. This should only be true
  1118. ;**  on the LAST iteration of the Loop(s).
  1119. ;*/
  1120.  
  1121.                         mov     ecx, ChunkSize
  1122.                         .if < DWordLimit b ecx >
  1123.                                 mov     ecx, DWordLimit
  1124.                                 mov     ChunkSize, ecx
  1125.                         .endif
  1126.  
  1127.                         shl     ecx,2           ; DWords to Bytes
  1128.                         mov     ChunkBytes, ecx ; Save it
  1129. ;/*
  1130. ;**  Set up Virtual Target and Source addresses depending on function
  1131. ;**  Note here the physical address for IO on the VDisk is in the
  1132. ;**  variable VDisk_IO. The users DTA is in the local variable t_DTA as
  1133. ;**  a 32 bit physical address. Both addresses must be converted from
  1134. ;**  Physical to Virtual 32 bit addresses. The operation determines
  1135. ;**  which register the virtual addresses are left in. The source is
  1136. ;**  always left in DS:SI and the target in ES:DI. BE CAREFUL OF
  1137. ;**  REGISTERS BEING DESTROYED BY PHYSTOVIRT (CX?)
  1138. ;*/
  1139.  
  1140.                         mov     dl, DevHlp_PhysToVirt
  1141.  
  1142.                         .if < RWFlag eq NORMAL_READ >
  1143.                                 mov     ax, DOS32FLATDS
  1144.                                 mov     ds, ax
  1145.                                 mov     esi, VDiskIO
  1146.                                 mov     ecx, ChunkBytes
  1147.                                 mov     ax, t_DTAh      ; Map DTA
  1148.                                 mov     bx, t_DTAl
  1149.                                 mov     dh, 1           ; DTA Target
  1150.                                 call    t_DH            ; Call DevHelp
  1151.                                 movzx   edi,di
  1152.  
  1153.                         ;/*
  1154.                         ;**  DS:ESI = VirtSource = VDiskIO
  1155.                         ;**  ES:EDI = VirtTarget = DTA
  1156.                         ;*/
  1157.  
  1158.                         .elseif < RWFlag eq NORMAL_WRITE >
  1159.                                 mov     ax, DOS32FLATDS
  1160.                                 mov     es, ax
  1161.                                 mov     edi, VDiskIO
  1162.                                 mov     ecx, ChunkBytes
  1163.                                 mov     ax, t_DTAh      ; Map DTA
  1164.                                 mov     bx, t_DTAl
  1165.                                 xor     dh, dh          ; DTA Source
  1166.                                 call    t_DH            ; Call DevHelp
  1167.                                 movzx   esi,si
  1168.  
  1169.                         ;/*
  1170.                         ;**  DS:ESI = VirtSource = DTA
  1171.                         ;**  ES:EDI = VirtTarget = VDiskIO
  1172.                         ;*/
  1173.  
  1174.                         .else                           ; Linear R or W
  1175.                                 mov     ax, DOS32FLATDS
  1176.                                 mov     ds, ax
  1177.                                 mov     es, ax
  1178.                                 mov     esi, VDiskIO
  1179.                                 mov     edi, t_DTA
  1180.  
  1181.                                 .if <RWFlag eq LINEAR_WRITE>
  1182.                                         xchg    esi, edi
  1183.                                 .endif
  1184.  
  1185.                         .endif
  1186. ;/*
  1187. ;**  Addresses are mapped, so now we move a Chunk
  1188. ;*/
  1189.                         mov     ecx, ChunkSize
  1190.                         cld
  1191.                         rep     movs dword ptr [esi],dword ptr [edi]
  1192.                         db      MI_ADDRESSSIZE
  1193.                         nop
  1194. ;/*
  1195. ;**  Update Counters
  1196. ;*/
  1197.  
  1198.                         mov     eax, ChunkSize  ; EAX = ChunkSize
  1199.                         sub     DWordLimit, eax
  1200.                         shl     eax,2           ; EAX = ChunkSize in Bytes
  1201.                         add     t_DTA, eax      ; Move Addresses
  1202.                         add     VDiskIO, eax
  1203. ;/*
  1204. ;**  Test TCResched
  1205. ;*/
  1206.  
  1207.                         lds     bx, t_TCReschedFlag
  1208.                         .if < <byte ptr ds:[bx]> ne 0 >         ; VOLUNTARY
  1209.                                 mov     dl, DevHlp_TCYield      ; PREEMPTION
  1210.                                 call    t_DH                    ; Call DevHelp
  1211.                         .endif
  1212.  
  1213.                 .endwhile
  1214. ;/*
  1215. ;**  Set the Status to NOERROR
  1216. ;*/
  1217.  
  1218.                 xor     ah, ah          ; Status = NOERROR
  1219. ;/*
  1220. ;**  Set Registers back to before the frame
  1221. ;*/
  1222.  
  1223.                 mov     es, t_es
  1224.                 mov     ds, t_ds
  1225.                 mov     bx, t_bx
  1226.  
  1227.                 LeaveProc               ; Remove the local Var Frame
  1228.  
  1229.         .endif
  1230.  
  1231.         ret
  1232.  
  1233. EndProc VDisk_IO
  1234.  
  1235. BREAK   <End OF Resident Code>
  1236. ;/*
  1237. ;**
  1238. ;**  The following label defines the end of the VDisk resident code.
  1239. ;**
  1240. ;*/
  1241. DEVICE_END      LABEL   BYTE
  1242.  
  1243.  
  1244. BREAK   <Init>
  1245. ;/***************************************************************************
  1246. ;*
  1247. ;* FUNCTION NAME = Init
  1248. ;*
  1249. ;* DESCRIPTION   = VDisk Initialization Routine
  1250. ;*                 Initializes the VDisk Data Segment and VDisk itself.
  1251. ;*
  1252. ;*         VDisk Initialization routine. Its jobs are to:
  1253. ;*
  1254. ;*             1.  Initialize various global values
  1255. ;*             2.  Parse the command line and set values accordingly
  1256. ;*             3.  Allocate the memory for the VDisk
  1257. ;*             4.  Initialize the DOS volume in the VDIsk RAM
  1258. ;*             5.  Print out report of RAMDrive parameters
  1259. ;*             6.  Set the return INIT I/O packet values
  1260. ;*
  1261. ;*         At any time during the above steps an error may be detected. When
  1262. ;*         this happens one of the error messages is printed and VDisk
  1263. ;*         "de-installs" itself by returning a unit count of 0 in the INIT
  1264. ;*         device I/O packet. The DOS device installation code is responsible
  1265. ;*         for taking care of the details of re-claiming the memory used by
  1266. ;*         the device driver.
  1267. ;*
  1268. ;*         Step 1 initializes the DevHelp function router address.
  1269. ;*
  1270. ;*         Step 2 uses the "DEVICE = xxxxxxxxx" line pointer provided by
  1271. ;*         DOS to look for the various device parameters.
  1272. ;*         First we skips over the device name field
  1273. ;*         to get to the arguments. We then parse the arguments as they are
  1274. ;*         encountered. All parameter errors are detected here. NOTE THAT
  1275. ;*         THIS ROUTINE IS NOT RESPONSIBLE FOR SETTING DEFAULT VALUES OF
  1276. ;*         PARAMETER VARIABLES. This is accomplished by static initialization
  1277. ;*         of the parameter variables.
  1278. ;*
  1279. ;*         Step 3 alloactes RAM for the VDisk. It must set up the following
  1280. ;*         global variables:
  1281. ;*
  1282. ;*                         DEV_SIZE   set to TRUE size of device
  1283. ;*                         VDisk_Base set to TRUE start of device so VDisk_IO
  1284. ;*                                         can be called
  1285. ;*
  1286. ;*         Step 4 initializes the virtual disk. The BPB must be set, the
  1287. ;*         RESERVED (boot) sector, FAT sectors, and root directory sectors
  1288. ;*         must be initialized and written out to the VDisk. The first step
  1289. ;*         is to initialize all of the BPB values. The code is a typical piece
  1290. ;*         of PC-DOS code which given BYTES/SECTOR, TOTAL DISK SIZE
  1291. ;*         and NUMBER OF ROOT DIRECTORY ENTRIES inputs figures out reasonable
  1292. ;*         values for SEC/CLUSTER and SECTORS/FAT and TOTAL NUMBER OF CLUSTERS.
  1293. ;*         NOTE THAT THIS CODE IS TUNED AND SPECIFIC TO 12 BIT FATS. Don't
  1294. ;*         expect it to work AT ALL with a 16 bit FAT. The next step is to write
  1295. ;*         out the BOOT record containing the BPB to sector 0, write out
  1296. ;*         a FAT with all of the clusters free, and write out a root directory
  1297. ;*         with ONE entry (the Volume ID at VOLID).
  1298. ;*
  1299. ;*         Step 5 makes the status report display of DEVICE SIZE, SECTOR SIZE,
  1300. ;*         CLUSTER SIZE, and DIRECTORY SIZE by simply printing out the values
  1301. ;*         from the BPB.
  1302. ;*
  1303. ;*         Step 6 sets the INIT I/O packet return values for # of units,
  1304. ;*         Break address, and BPB array pointer and returns via DEVEXIT.
  1305. ;*
  1306. ;* INPUT         = ES:BX = request packet address
  1307. ;*                 DS = VDiskData
  1308. ;*
  1309. ;* OUTPUT        =
  1310. ;*
  1311. ;* RETURN-NORMAL = Request Packet Set
  1312. ;*                         Units Set
  1313. ;*                         BPB address set
  1314. ;*                         Terminating Code Address Set
  1315. ;*                         Terminating Data Address Set
  1316. ;*                 AX = status to return to DOS
  1317. ;*
  1318. ;* RETURN-ERROR  = NONE
  1319. ;*
  1320. ;**************************************************************************/
  1321.  
  1322. Procedure Init,NEAR,LOCAL
  1323. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  1324.  
  1325. ;/*
  1326. ;**  Save DvHelp Function Router Address in VDiskData
  1327. ;*/
  1328.  
  1329.         mov     eax, es:[bx.InitpEnd]
  1330.         mov     DevHelp, eax
  1331.  
  1332. ;/*
  1333. ;**  Parse Command Line and Set Values Accordingly
  1334. ;*/
  1335.  
  1336.         mov     al, es:[bx.Initdrv]     ; DOS drive letter
  1337.         add     Var1, al                ; Add into Global Var
  1338.  
  1339.  
  1340. ;/*
  1341. ;**  Create a local stack frame since we are going to use
  1342. ;**  DS for string operations. Create local variables for those
  1343. ;**  values in the VDiskData segment we need to Read/Write to.
  1344. ;**  These rules apply from here to end of Init.
  1345. ;*/
  1346.  
  1347.         localvar        t_ds, WORD
  1348.         localvar        t_es, WORD
  1349.         localvar        t_bx, WORD
  1350.  
  1351.         EnterProc
  1352.  
  1353.         mov     t_ds, ds
  1354.         mov     t_es, es
  1355.         mov     t_bx, bx
  1356.  
  1357. ;/*
  1358. ;**  Check For Out of Drives
  1359. ;*/
  1360.         .if <al a 25>
  1361.             mov     dx, msg_vdisk_no_drives
  1362.             call    print
  1363.             jmp     devabort
  1364.         .endif
  1365.  
  1366. ;/*
  1367. ;**  Get Address of TCResched Flag
  1368. ;*/
  1369.  
  1370.         mov     al, TCYieldFlag
  1371.         mov     dl, DevHlp_GetDOSVar    ; GetDOSVar
  1372.         call    DevHelp                 ; Call Device_Help
  1373.  
  1374.         mov     word ptr TCReschedFlag, bx
  1375.         mov     word ptr TCReschedFlag + 2, ax
  1376.  
  1377.         mov     bx, t_bx                ; Restore BX
  1378.  
  1379. ;/*
  1380. ;**  Since the LODSB instruction works with the DS register, we
  1381. ;**  save the values of both seg registers, and set up ES to point
  1382. ;**  to the VDiskData segment. The pointer to the request packet
  1383. ;**  is save in temp local variables.
  1384. ;*/
  1385.  
  1386.         lds     si, es:[bx.InitpBPB]    ; DS:SI points to config.sys
  1387.         mov     es, t_ds                ; ES points to VDiskData
  1388.  
  1389. assume  ds:NOTHING, es:VDiskData, ss:NOTHING
  1390.  
  1391. ;/*
  1392. ;**  Skip to start of name
  1393. ;*/
  1394.  
  1395.         .repeat
  1396.                 lodsb
  1397.         .until < al ne " " > AND
  1398.         .until < al ne 09h > AND
  1399.         .until < al ne "," >
  1400.  
  1401. ;/*
  1402. ;**  Skip over Device Name
  1403. ;*/
  1404.  
  1405.         .while < al ne 0 > AND
  1406.         .while < al ne " " > AND
  1407.         .while < al ne 09h > AND
  1408.         .while < al ne ",">
  1409.  
  1410.                 .if < al eq 0Dh > OR
  1411.                 .if < al eq 0Ah >
  1412.                         jmp     args_donej
  1413.                 .endif
  1414.  
  1415.                 lodsb
  1416.  
  1417.         .endwhile
  1418.  
  1419. ;/*
  1420. ;**  Process Arguments
  1421. ;*/
  1422.  
  1423.         .while < al ne 0 > NEAR AND
  1424.         .while < al ne 0Dh > NEAR AND
  1425.         .while < al ne 0Ah > NEAR
  1426.  
  1427.                 .if < al eq " " > OR
  1428.                 .if < al eq 09h >
  1429.                         lodsb
  1430.                 .else NEAR
  1431.  
  1432.                         .if < al eq "," >
  1433.                                 inc     es:NUM_ARG
  1434.                                 jmp     next_parm
  1435.                         .endif
  1436.  
  1437.                         .if < al b "0" > OR
  1438.                         .if < al a "9" >
  1439.                                 jmp     bad_parm
  1440.                         .endif
  1441. ;/*
  1442. ;**  P1795 START
  1443. ;*/
  1444.                         inc     es:NUM_NUM
  1445.                         push    ax
  1446.                         mov     al,es:NUM_ARG
  1447.                         .if <al gt es:NUM_NUM>
  1448.                             mov  es:NUM_NUM,al
  1449.                         .elseif <es:NUM_NUM gt al>
  1450.                             inc  es:NUM_ARG
  1451.                         .endif
  1452.                         pop     ax
  1453. ;/*
  1454. ;**  P1795 END
  1455. ;*/
  1456.                         dec     si
  1457.                         call    getnum
  1458.                         .if < es:NUM_ARG a 3>
  1459.                                 jmp     bad_parm
  1460.                         .endif
  1461.                         .if z                           ; Dir Parm
  1462.                                 .if < bx b 2> OR
  1463.                                 .if < bx a 1024>
  1464.                                         jmp     bad_parm
  1465.                                 .endif
  1466.  
  1467. ;/*
  1468. ;**  NOTE: Since DIRNUM is the 3rd numeric arg and SSIZE is the first,
  1469. ;**       we know the desired sector size has been given.
  1470. ;*/
  1471.  
  1472.                                 mov     di, es:SSIZE
  1473.                                 mov     cl, 5          ; 32 bytes per dir ent
  1474.                                                        ; DI is number of dirents
  1475.                                 shr     di, cl         ;    in a sector
  1476.                                 mov     ax, bx
  1477.                                 xor     dx, dx
  1478.                                 div     di             ; Rem in DX is partial
  1479.                                 or      dx, dx         ;    dir sector
  1480.                                 .if ne         ; User Specified OK number
  1481.                                                        ; Figure how much user
  1482.                                         sub     di, dx ;    goofed by
  1483.                                         add     bx, di ; Round UP by DI entries
  1484.                                 .endif
  1485.  
  1486.                                 mov     es:DIRNUM, bx
  1487.                         .endif
  1488.  
  1489.                         .if < es:NUM_ARG eq 2 >        ; Sector Parm
  1490.                                 mov     al, es:SEC_SHIFT
  1491.  
  1492.                                 .if < bx ne 128 > AND
  1493.                                 .if < bx ne 256 > AND
  1494.                                 .if < bx ne 512 > AND
  1495.                                 .if < bx ne 1024 >
  1496.                                         jmp     bad_parm
  1497.                                 .endif
  1498.  
  1499.                                 .if <bx eq 1024>
  1500.                                         mov     bx, 512
  1501.                                 .endif
  1502.  
  1503.                                 mov     es:SSIZE, bx
  1504.  
  1505.                                 ; 512 is the default & 1024 is not allowed
  1506.                                .if<bx eq 128>                       ;          
  1507.                                    mov   es:SEC_SHIFT, 5            ;          
  1508.                                .elseif<bx eq 256>                   ;          
  1509.                                    mov   es:SEC_SHIFT, 6            ;          
  1510.                                .endif                               ;          
  1511.  
  1512.                         .endif
  1513.  
  1514.                         .if < es:NUM_ARG eq 1 >
  1515.                                 .if < ebx b 16 > OR      ; 16KB      ;          
  1516.                                 .if < ebx a 524288 >     ; 512MB     ;          
  1517.                                         jmp     bad_parm
  1518.                                 .endif
  1519.  
  1520.                                 mov     es:DEV_SIZE, ebx             ;          
  1521.                         .endif
  1522.  
  1523. next_parm:              lodsb
  1524.                 .endif
  1525.         .endwhile
  1526.  
  1527. args_donej:
  1528.         jmp     args_done
  1529.  
  1530. bad_parm:
  1531.         mov     dx, msg_vdisk_inv_parm  ; Select Invalid Parameter Msg
  1532.         mov     ds, t_ds                ; ds = VDiskData
  1533.         call    print
  1534. devabort:                       ; here the correct message is printed already
  1535.         xor     ax, ax                  ;Indicate no devices
  1536.         jmp     setbpb                  ;and return
  1537.  
  1538. args_done:
  1539.  
  1540.         mov     ds, t_ds                ; DS = VDiskData
  1541.         assume ds:VDIskData, es:NOTHING, SS:NOTHING
  1542. ;/*
  1543. ;**       Allocate RAM for the virtual disk. If allocate FAILs print msg
  1544. ;**       and goto devabort. Otherwise es:VDisk_Base is set to base
  1545. ;**       address of VDisk RAM. Also DEV_SIZE must reflect the
  1546. ;**       size of the VDisk in K. (in case size was adjusted to 16K)
  1547. ;**       Can use most registers here. Optimize based on AllocPhys
  1548. ;**       Register Usage.
  1549. ;*/
  1550.  
  1551.         mov     eax, DEV_SIZE                   ; User's Size        ;          
  1552.         call    GetRAM
  1553.         .if c
  1554.                 mov     eax, 16                 ; Try 16K
  1555.                 mov     dh, 1                   ; Above 1M ; Does this work?
  1556.                 call    GetRAM
  1557.                 .if c                           ; Insufficient Memory ?
  1558.                         mov     dx, msg_vdisk_insuff_mem
  1559.                         call    print
  1560.                         jmp     devabort
  1561.                 .else
  1562.                         mov     DEV_SIZE, 16
  1563.                 .endif
  1564.         .endif
  1565.  
  1566.         mov     VDisk_Base, eax                 ; save VDisk_Base
  1567. ;/*
  1568. ;**  5.  Initialize the DOS volume in the VDisk memory
  1569. ;**
  1570. ;**
  1571. ;**  We must figure out what to do.
  1572. ;**  All values are set so we can call VDisk_IO to read and write disk
  1573. ;**  SSIZE is user sector size in bytes
  1574. ;**  DIRNUM is user directory entries
  1575. ;**  DEV_SIZE is size of device in K bytes
  1576. ;**
  1577. ;**
  1578. ;**  Figure out total number of sectors in logical image
  1579. ;*/
  1580.  
  1581.         mov     eax, DEV_SIZE                                        ;          
  1582.         mov     ecx, 1024                                            ;          
  1583.         mul     ecx             ; DX:AX is size in bytes of image    ;          
  1584.         movzx   ecx,SSIZE                                            ;          
  1585.         div     ecx             ; EAX is total sectors               ;          
  1586.                                 ; Any remainder in DX is ignored     ;          
  1587.         .if <eax b 10000h>                                           ;          
  1588.            mov     SECLIM, ax                                        ;          
  1589.            mov     TotalSectors, eax                                 ;          
  1590.         .else                                                        ;          
  1591.            mov     BIGSEC, eax                                       ;          
  1592.            mov     TotalSectors, eax                                 ;          
  1593.         .endif                                                       ;          
  1594. ;/*                                                                  ;          
  1595. ;**  Compute # of directory sectors
  1596. ;*/
  1597.  
  1598.         mov     ax, DIRNUM
  1599.         shl     ax, 5           ; Mult by 32 bytes per entry
  1600.                                 ; Don't need to worry about overflow, # ents
  1601.                                 ;     is at most 1024
  1602.         xor     dx, dx
  1603.         div     SSIZE
  1604.         .if < dx ne 0 >
  1605.                 inc     ax
  1606.         .endif
  1607.  
  1608.         mov     DIRSEC, ax      ; AX is # sectors for root dir
  1609.         add     ax, 2           ; One reserved, At least one FAT sector???
  1610.         cwde                    ; sign extend eax                    ;          
  1611.  
  1612.         .if < eax ae TotalSectors >                                  ;          
  1613.  
  1614.                 mov     DIRNUM, 16      ; Smallest reasonable number
  1615.                 xor     dx, dx
  1616.                 mov     ax, 512         ; 16*32 = 512 bytes for dir
  1617.                 div     SSIZE
  1618.                 .if < dx ne 0 >
  1619.                         inc     ax
  1620.                 .endif
  1621.  
  1622.                 mov     DIRSEC, ax      ; AX is # sectors for root dir
  1623.  
  1624.                 add     ax, 2           ; 0ne reserved, At least one FAT sector
  1625.  
  1626.                 .if < eax ae TotalSectors >                          ;          
  1627.                         mov     dx, msg_vdisk_insuff_mem
  1628.                         call    print
  1629.                         jmp     devabort
  1630.                 .endif
  1631.         .endif
  1632.  
  1633. ;/*
  1634. ;**  This is the rest of the code that sets up the BPB. It is
  1635. ;**  tuned for 12 bit FAT table format. DO NOT TOUCH
  1636. ;*/
  1637.  
  1638.  
  1639. CLUSHOME:
  1640.  
  1641. ;/*
  1642. ;**  Figure a reasonable cluster size
  1643. ;*/
  1644.  
  1645.         mov     eax, TotalSectors; AX is total sectors on disk       ;          
  1646.         movzx   ebx, RESSEC
  1647.         sub     eax, ebx      ; Sub off reserved sectors             ;          
  1648.         mov     cl, FATNUM      ; CX is number of FATs
  1649.         xor     ch, ch
  1650. FATSUB:
  1651.         movzx   ebx, FATSEC                                          ;          
  1652.         sub     eax, ebx        ; Sub off FAT sectors                ;          
  1653.         loop    FATSUB                                               ;          
  1654.         movzx   ebx, DIRSEC                                          ;          
  1655.                                ; Sub off directory sectors, AX is # data sectors
  1656.         sub     eax, ebx                                             ;          
  1657.         mov     ebx, 1           ; Start at 1 sec per alloc unit     ;          
  1658.         cmp     eax, 4096-10                                         ;          
  1659.         jb      cset            ; 1 sector per cluster is OK         ;          
  1660.         mov     ebx, 2                                               ;          
  1661.         cmp     eax, (4096-10) * 2                                   ;          
  1662.         jb      cset            ; 2 sector per cluster is OK         ;          
  1663.         mov     ebx, 4                                               ;          
  1664.         cmp     eax, (4096-10) * 4                                   ;          
  1665.         jb      cset            ; 4 sector per cluster is OK         ;          
  1666.         mov     ebx, 8                                               ;          
  1667.         cmp     eax, (4096-10) * 8                                   ;          
  1668.         jb      cset            ; 8 sector per cluster is OK         ;          
  1669.         mov     ebx, 16          ;                                   ;          
  1670.         cmp     eax, (4096-10) * 16                                  ;          
  1671.         jb      cset            ; 16 sector per cluster is OK        ;          
  1672.         mov     ebx, 32          ;                                   ;          
  1673.         cmp     eax, (4096-10) * 32                                  ;          
  1674.         jb      cset            ; 32 sector per cluster is OK        ;          
  1675.         mov     ebx, 64          ;                                   ;          
  1676.         cmp     eax, (4096-10) * 64                                  ;          
  1677.         jb      cset            ; 64 sector per cluster is OK        ;          
  1678.         mov     ebx, 128         ;                                   ;          
  1679.         cmp     eax, (4096-10) * 128                                 ;          
  1680.         jb      cset            ; 128 sector per cluster is OK       ;          
  1681.         mov     ebx, 256         ;                                   ;          
  1682.         cmp     eax, (4096-10) * 256                                 ;          
  1683.         jb      cset            ; 256 sector per cluster is OK       ;          
  1684.         mov     ebx, 512        ;                                    ;          
  1685.         cmp     eax, (4096-10) * 512                                 ;          
  1686.         jb      cset            ; 512 sector per cluster is OK       ;          
  1687.         mov     ebx, 1024       ;                                    ;          
  1688.         cmp     eax, (4096-10) * 1024                                ;          
  1689.         jb      cset            ; 1024 sector per cluster is OK      ;          
  1690.         mov     ebx, 2048       ; 2048 sector per cluster is OK      ;          
  1691. CSET:
  1692.  
  1693. ;/*
  1694. ;**  Figure FAT size. AX is reasonable approx to number of DATA sectors
  1695. ;**  BX is reasonable sec/cluster
  1696. ;*/
  1697.  
  1698.  
  1699.         xor     edx, edx                                             ;          
  1700.         div     ebx         ; AX is total clusters, ignore remainder ;          
  1701.                                 ;  can't have a "partial" cluster
  1702.         mov     ecx, eax                                             ;          
  1703.         shr     ecx, 1                                               ;          
  1704.         .if c                                                        ;          
  1705.                 inc     ecx                                          ;          
  1706.         .endif                                                       ;          
  1707.  
  1708.         add     eax, ecx   ; AX is Bytes for fat (1.5 * # of clusters)          
  1709.         add     eax, 3          ; Plus two reserved clusters         ;          
  1710.         xor     edx, edx                                             ;          
  1711.         movzx   ecx, SSIZE                                           ;          
  1712.         div     ecx             ; AX is # sectors for a FAT this size;          
  1713.         .if <edx ne 0>          ; if remainder                       ;          
  1714.                 inc     eax     ; Round UP                           ;          
  1715.         .endif                  ;                                    ;          
  1716.  
  1717.                                 ; AX is # sectors for FAT
  1718.         xchg    ax, FATSEC      ; Set newly computed value
  1719.         xchg    bl, CSIZE       ; Set newly computed value
  1720.         cmp     bl, CSIZE       ; Did we compute a different size?
  1721.         jnz     CLUSHOME        ; Keep performing FATSEC and CSIZE computation
  1722.                                 ;   until the values don't change.
  1723.         cmp     ax, FATSEC      ; Did we compute a different size?
  1724.         jb      CLUSHOME        ; Keep performing FATSEC and CSIZE computation
  1725.                                 ;   until the values don't change.   ;          
  1726.         mov     FATSEC, ax                                           ;          
  1727.  
  1728. ;/*
  1729. ;**  BPB is now all set !!!
  1730. ;**
  1731. ;**  FORMAT THE VDISK IN MEMORY !!!
  1732. ;**
  1733. ;**  Here DS = VDiskData and ES is unused.
  1734. ;**  In order to use VDisk_IO for formating the VDisk, we need
  1735. ;**  to set ES:BX to point to a dummy write request packet called
  1736. ;**  Dummy_ReqPacket in the VDiskData segment, and DS to VDiskData.
  1737. ;**  DTAs are set from either the DUMMY BOOT RECORD or SECTOR_BUFFER
  1738. ;**  in the VDiskData segment.
  1739. ;**  Dummy_ReqPacket is a write packet that is completely intialized
  1740. ;**  except for the DTA and StartSector.
  1741. ;*/
  1742.  
  1743.         mov     ds, t_ds                ; DS = VDiskData
  1744.         mov     es, t_ds                ; ES = VDiskData
  1745. assume ds:VDiskData, es:VDiskData, ss:NOTHING
  1746.  
  1747.         mov     bx, offset Dummy_ReqPacket
  1748.                                         ; ES:BX = Dummy_ReqPacket
  1749.  
  1750. ;/*
  1751. ;**  WRITE BOOT SECTOR
  1752. ;*/
  1753.  
  1754.         mov     [bx.IOstart], 0         ; Sector 0
  1755.         mov     esi,offset BOOT_SECTOR  ; DS:SI = DTA
  1756.         call    STUFF                   ; Do Request
  1757.  
  1758. ;/*
  1759. ;**  WRITE FIRST FAT SECTOR
  1760. ;*/
  1761.  
  1762.         mov     edi, offset SECTOR_BUFFER
  1763.         xor     eax, eax                ; Initialize Buffer for FAT
  1764.         mov     ecx, 256
  1765.         cld
  1766.         rep     stosd                   ; EMPTY FAT
  1767.  
  1768.         mov     edi, offset SECTOR_BUFFER
  1769.         mov     dword ptr [di], 0FFFFF8H   ; PLUS 2 Directories
  1770.  
  1771.         inc     word ptr [bx.IOstart]   ; Sector 1
  1772.         mov     si, offset SECTOR_BUFFER
  1773.         call    STUFF
  1774.  
  1775.         inc     [bx.IOstart]            ; Setup Next sector
  1776.         mov     di, offset SECTOR_BUFFER
  1777.         mov     dword ptr [di], 0       ; Fix Buffer to EMPTY FAT
  1778.  
  1779.         mov     cx, FATSEC
  1780.         dec     cx                      ; First FAT sector already written
  1781.         jcxz    FATDONE
  1782. FATZERO:
  1783.         SaveReg <cx>
  1784.         mov     si, NORMAL_WRITE
  1785.         call    iniVDisk_IO
  1786.         inc     [bx.IOstart]            ; Next Sector (still from SECTOR_BUFFER)
  1787.         RestoreReg      <cx>
  1788.         loop    FATZERO
  1789. FATDONE:
  1790.  
  1791.         mov     si, offset VOLID        ; Volume Label Dir Ent ???
  1792.         call    STUFF
  1793.  
  1794.         inc     [bx.IOstart]            ; Next Sector
  1795.         mov     cx, DIRSEC
  1796.         dec     cx                      ; First Sector Dir Already Written
  1797.         jcxz    drive_set
  1798. DIRZERO:
  1799.         SaveReg <cx>
  1800.         mov     si, offset SECTOR_BUFFER
  1801.         call    STUFF
  1802.         inc     [bx.IOstart]            ; Next Sector(still from VOLID)
  1803.         RestoreReg      <cx>
  1804.         loop    DIRZERO
  1805. DRIVE_SET:
  1806.  
  1807. ;/*
  1808. ;**  Print out Report of VDisk parameters
  1809. ;*/
  1810.  
  1811. assume ds:VDiskData, es:NOTHING, ss:NOTHING
  1812.  
  1813.         mov     eax, DEV_SIZE                                        ;          
  1814.         mov     bx, offset Var2
  1815.         call    itoa
  1816.         movzx   eax, SSIZE                                           ;          
  1817.         mov     bx, offset Var3
  1818.         call    itoa
  1819.         movzx   eax, DIRNUM                                          ;          
  1820.         mov     bx, offset Var4
  1821.         call    itoa
  1822.  
  1823.         mov     dx, msg_vdisk_report
  1824.         call    print
  1825.  
  1826.         mov     al, 1                   ; Number of ramdrives
  1827. ;/*
  1828. ;**  NOTE FALL THROUGH!!!!!!!
  1829. ;*/
  1830.  
  1831. ;/*
  1832. ;**  SETBPB - Set INIT packet I/O return values
  1833. ;**
  1834. ;**  This entry is used in ERROR situations to return
  1835. ;**  a unit count of 0 by jumping here with AL = 0.
  1836. ;**  The successful code path falls through to here
  1837. ;**  with AL = 1
  1838. ;**
  1839. ;**  ENTRY
  1840. ;**          AL = INIT packet unit count
  1841. ;**          DS = VDiskData
  1842. ;**  EXIT
  1843. ;**          AX = status to return to DOS
  1844. ;**          Request Packet Set up for return from Init
  1845. ;*/
  1846.  
  1847. SETBPB:
  1848. assume  ds:VDiskData, es:NOTHING, ss:NOTHING
  1849.  
  1850. ;/*
  1851. ;**  Restore ES:BX pointer to Original Init Request Packet and
  1852. ;**  remove local variable stack frame.
  1853. ;*/
  1854.  
  1855.         mov     ds, t_ds
  1856.         mov     bx, t_bx
  1857.         mov     es, t_es
  1858.  
  1859.         LeaveProc
  1860.  
  1861. ;/*
  1862. ;**  Set Units, End of CODE and DATA Segment, Address of BPB Array
  1863. ;**  in Request packet
  1864. ;*/
  1865.  
  1866.         mov     es:[bx.InitcUnit], al
  1867.  
  1868.         .if <al eq 0>
  1869.                 mov     es:[bx.InitpEnd], 0
  1870.         .else
  1871.                 mov     word ptr es:[bx.InitpEnd], offset DEVICE_END
  1872.                 mov     word ptr es:[bx.InitpEnd+2], offset DATA_END
  1873.                 mov     word ptr es:[bx.InitpBPB], offset INIT_BPB
  1874.                 mov     word ptr es:[bx.InitpBPB+2], ds
  1875.         .endif
  1876.  
  1877.         ret
  1878.  
  1879. EndProc Init
  1880.  
  1881.  
  1882. BREAK   <GetRAM>
  1883. ;/***************************************************************************
  1884. ;*
  1885. ;* FUNCTION NAME = GetRAM
  1886. ;*
  1887. ;* DESCRIPTION   = VDisk RAM Allocater
  1888. ;*                 Calls DevHelp(AllocPhys) to acquire RAM for VDisk
  1889. ;*
  1890. ;* INPUT         = AX = Size in K Desired
  1891. ;*
  1892. ;* OUTPUT        =
  1893. ;*
  1894. ;* RETURN-NORMAL = 'C' Clear
  1895. ;*                 EAX = Linear Base Address of RAM
  1896. ;*
  1897. ;* RETURN-ERROR  = NONE
  1898. ;*
  1899. ;**************************************************************************/
  1900.  
  1901. Procedure GetRAM,NEAR,LOCAL
  1902.  
  1903.         mov     ecx, 1024
  1904.         mul     ecx
  1905.         mov     ecx,eax                 ; ECX = Size of region in bytes
  1906.         push    ecx                                               ;          
  1907.                                         ; 0800h == Unpublished flag that will
  1908.                                         ;          allow VDISK to request more
  1909.                                         ;          than 4MB at init time.
  1910.         mov     eax,2                   ; EAX = Flags (VMDHA_FIXED)
  1911.         mov     dl, DevHlp_VMAlloc
  1912.         call    DevHelp
  1913.         pop     ecx                                               ;          
  1914.                                                                   ; Try high
  1915.        .IF c                                                      ;          
  1916.           mov     eax, 2+0800h                                    ;          
  1917.           mov     dl, DevHlp_VMAlloc                              ;          
  1918.           call    DevHelp                                         ;          
  1919.        .ENDIF                                                     ;          
  1920.  
  1921.         ret
  1922.  
  1923. EndProc GetRAM
  1924.  
  1925.  
  1926. BREAK   <iniVDisk_IO>
  1927. ;/***************************************************************************
  1928. ;*
  1929. ;* FUNCTION NAME = iniVDisk_IO
  1930. ;*
  1931. ;* DESCRIPTION   = VDisk VDisk_IO Caller for Init
  1932. ;*                 Saves Registers and calls VDisk_IO
  1933. ;*
  1934. ;*                 VDisk_IO is very register destructive, all this routine
  1935. ;*                 does is provide a less destructive way to call VDisk_IO.
  1936. ;*
  1937. ;* INPUT         = Same as VDisk_IO
  1938. ;*
  1939. ;* OUTPUT        =
  1940. ;*
  1941. ;* RETURN-NORMAL = Same as VDisk_IO
  1942. ;*
  1943. ;* RETURN-ERROR  = NONE
  1944. ;*
  1945. ;**************************************************************************/
  1946.  
  1947. Procedure iniVDisk_IO,NEAR,LOCAL
  1948. assume ds:VDiskData, es:NOTHING, ss:NOTHING
  1949.  
  1950.         SaveReg <es,ds>
  1951.         pushad
  1952.         call    VDisk_IO
  1953.         popad
  1954.         RestoreReg      <ds,es>
  1955.  
  1956.         ret
  1957.  
  1958. EndProc iniVDisk_IO
  1959.  
  1960.  
  1961. BREAK   <GetNum>
  1962. ;/***************************************************************************
  1963. ;*
  1964. ;* FUNCTION NAME = GetNum
  1965. ;*
  1966. ;* DESCRIPTION   = Get Number
  1967. ;*                 Read an unsigned integer
  1968. ;*
  1969. ;*            This routine looks at DS:SI for a decimal unsigned integer.
  1970. ;*            It is up to the caller to make sure DS:SI points to the start
  1971. ;*            of a number. If it is called without DS:SI pointing to a valid
  1972. ;*            decimal digit the routine will return 0. Any non decimal digit
  1973. ;*            defines the end of the number and SI is advanced over the
  1974. ;*            digits which composed the number. Leading "0"s are OK.
  1975. ;*
  1976. ;*            THIS ROUTINE DOES NOT CHECK FOR NUMBERS LARGER THAN WILL FIT
  1977. ;*            IN 16 BITS. If it is passed a pointer to a number larger than
  1978. ;*            16 bits it will return the low 16 bits of the number.
  1979. ;*
  1980. ;*            This routine uses the MUL instruction to multiply the running
  1981. ;*            number by 10 (initial value is 0) and add the numeric value
  1982. ;*            of the current digit. Any overflow on the MUL or ADD is ignored.
  1983. ;*
  1984. ;* INPUT         = DS:SI -> ASCII text of number
  1985. ;*
  1986. ;* OUTPUT        =
  1987. ;*
  1988. ;* RETURN-NORMAL = BX is binary for number
  1989. ;*                 SI advanced to point to char after number
  1990. ;*
  1991. ;* RETURN-ERROR  = NONE
  1992. ;*
  1993. ;**************************************************************************/
  1994.  
  1995. Procedure getnum,NEAR,LOCAL
  1996. assume  DS:NOTHING,ES:NOTHING,SS:NOTHING
  1997.  
  1998.         xor     ebx, ebx                                             ;          
  1999. getnum1:
  2000.         lodsb
  2001.         sub     al, "0"
  2002.         .if ae
  2003.                 .if < al be 9 >
  2004.                         cbw
  2005.                         cwde                                         ;          
  2006.                         xchg    eax, ebx                             ;          
  2007.                         mov     edx, 10                              ;          
  2008.                         mul     edx                                  ;          
  2009.                         add     ebx, eax                             ;          
  2010.                         jmp     getnum1
  2011.                 .endif
  2012.         .endif
  2013.  
  2014.         dec     si
  2015.         ret
  2016.  
  2017. EndProc getnum
  2018.  
  2019.  
  2020. BREAK   <Print>
  2021. ;/***************************************************************************
  2022. ;*
  2023. ;* FUNCTION NAME = Print
  2024. ;*
  2025. ;* DESCRIPTION   = Print a Message to StdOut
  2026. ;*                 Prints a message using the MSG Retriever API
  2027. ;*
  2028. ;*                 This routine gets a message from the system message file
  2029. ;*                 and prints it on StdOut.
  2030. ;*
  2031. ;* INPUT         = DS = VDiskData
  2032. ;*                 DX  = ID of message to be printed:
  2033. ;*                         msg_vdisk_inval_parm
  2034. ;*                         msg_vdisk_insuff_mem
  2035. ;*                         msg_vdisk_report
  2036. ;*
  2037. ;* OUTPUT        =
  2038. ;*
  2039. ;* RETURN-NORMAL = BX is binary for number
  2040. ;*                 SI advanced to point to char after number
  2041. ;*
  2042. ;* RETURN-ERROR  = NONE
  2043. ;*
  2044. ;**************************************************************************/
  2045.  
  2046. Procedure print,NEAR,LOCAL
  2047. assume  DS:VDiskData,ES:NOTHING,SS:NOTHING
  2048.  
  2049.  
  2050.         .if < dx eq msg_vdisk_report >
  2051.                 push    ds
  2052.                 push    offset IvTable  ; Table of Variables
  2053.                 push    IvCount         ; Number of Variables
  2054.         .else
  2055.                 push    0
  2056.                 push    0               ; No IvTable
  2057.                 push    0               ; Number of Variables
  2058.         .endif
  2059.  
  2060.         push    ds
  2061.         push    offset MsgBuff          ; Message Buffer
  2062.         push    MAXMSG                  ; Buffer Length
  2063.         push    dx                      ; Message ID
  2064.         push    ds
  2065.         push    offset MsgFile          ; Msg File Name
  2066.         push    ds
  2067.         push    offset MsgLen           ; Address of MsgLen
  2068.         call    DOSGETMESSAGE
  2069.  
  2070.         push    1                       ; StdOut
  2071.         push    MsgLen                  ; Msg Length
  2072.         push    ds
  2073.         push    offset MsgBuff          ; Address of Msg Buffer
  2074.         call    DOSPUTMESSAGE
  2075.  
  2076.         ret
  2077.  
  2078. EndProc print
  2079.  
  2080.  
  2081. BREAK   <Itoa>
  2082. ;/***************************************************************************
  2083. ;*
  2084. ;* FUNCTION NAME = Itoa
  2085. ;*
  2086. ;* DESCRIPTION   = Integer to ASCII Routine
  2087. ;*                 Convert an unsigned 16 bit value as a decimal integer
  2088. ;*                 with leading zero supression. Prints from 1 to 5 digits.
  2089. ;*                 Value 0 is "0".
  2090. ;*
  2091. ;*                 Routine uses divide instruction and a recursive call. Maximum
  2092. ;*                 recursion is four (five digit number) plus one word on stack
  2093. ;*                 for each level.
  2094. ;*
  2095. ;* INPUT         = AX = Binary Value to Convert
  2096. ;*                 DS:BX = Address for Destination
  2097. ;*
  2098. ;* OUTPUT        =
  2099. ;*
  2100. ;* RETURN-NORMAL = Destination Address filled in with string
  2101. ;*
  2102. ;* RETURN-ERROR  = NONE
  2103. ;*
  2104. ;**************************************************************************/
  2105.  
  2106. Procedure itoa,NEAR,LOCAL
  2107. assume  DS:NOTHING,ES:NOTHING,SS:NOTHING
  2108.  
  2109.         mov     cx, 10
  2110.         xor     dx, dx
  2111.         div     cx                      ; DX is low digit, AX is higher digits
  2112.         or      ax, ax
  2113.         .if nz
  2114.                 SaveReg <dx>            ; Save this digit
  2115.                 call    itoa            ; Print higher digits first
  2116.                 RestoreReg      <dx>    ; Recover this digit
  2117.         .endif
  2118.         add     dl, "0"                 ; Convert to ASCII
  2119.         mov     [bx], dl                ; Move Digit to Target
  2120.         inc     bx                      ; Advance Target Pointer
  2121.  
  2122.         ret
  2123.  
  2124. EndProc itoa
  2125.  
  2126.  
  2127. BREAK   <Stuff>
  2128. ;/***************************************************************************
  2129. ;*
  2130. ;* FUNCTION NAME = Stuff
  2131. ;*
  2132. ;* DESCRIPTION   = Converts DTA to physical address, stuffs
  2133. ;*                 it into the Request packet, and calls iniVDisk_IO
  2134. ;*
  2135. ;* INPUT         = DS:SI = Virtual DTA
  2136. ;*                 ES:BX = Virtual Request Packet
  2137. ;*                         w/All fields filled except DTA
  2138. ;*
  2139. ;* OUTPUT        = NONE
  2140. ;*
  2141. ;* RETURN-NORMAL =
  2142. ;* RETURN-ERROR  = NONE
  2143. ;*
  2144. ;**************************************************************************/
  2145.  
  2146. Procedure stuff,NEAR,LOCAL
  2147. assume  DS:VDiskData, ES:VDiskData, SS:NOTHING
  2148.  
  2149.         mov     di,bx                   ; save bx
  2150.         mov     dl,DevHlp_VirtToPhys
  2151.         call    DevHelp                 ; Convert to physical address
  2152.         xchg    di,bx                   ; Get Address of request packet
  2153.  
  2154.         mov     word ptr [bx.IOpData+2], ax ; Stuff Physical DTA
  2155.         mov     word ptr [bx.IOpData], di
  2156.         mov     si, NORMAL_WRITE        ; Write Flag to VDisk_IO
  2157.         call    iniVDisk_IO
  2158.  
  2159.         ret
  2160.  
  2161. EndProc stuff
  2162.  
  2163.  
  2164. VDisk_End       LABEL   BYTE
  2165.  
  2166. VDiskCode       ends
  2167.         end
  2168.