home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / DOS / HILFEN / SYSTEM / RAMDISK4 / XPANDISK.ASM < prev    next >
Assembly Source File  |  1993-12-01  |  38KB  |  864 lines

  1. ;  XpanDisk is a virtual disk device driver for expanded memory.
  2. ;  The driver has the capability of releasing memory allocated to
  3. ;  its drive, making it available to other applications.  All data
  4. ;  is lost if the drive is resized.  XPANBOSS.COM is the control
  5. ;  program for the XPANDISK.SYS driver. PC Magazine 10-31-88
  6.  
  7. _TEXT          SEGMENT PUBLIC 'CODE'
  8.                ASSUME  CS:_TEXT,DS:_TEXT
  9.                ASSUME  ES:_TEXT,SS:_TEXT
  10.                ORG     0H
  11.  
  12. ;************* DEVICE_HEADER *************;
  13.  
  14. POINTER        DD      -1                    ;Minus one indicates one driver.
  15. ATTRIBUTE      DW      0100000000000000B     ;Block device with IOCTL support.
  16. DEVICE_STAG    DW      STRATEGY              ;Pointer to strategy procedure.
  17. DEVICE_INT     DW      INTERRUPT             ;Pointer to interrupt procedure.
  18. DEVICE_NAME    DB      1, 7 DUP (?)          ;One unit.
  19.  
  20. REQUEST_HEADER         STRUC
  21.  HEADER_LENGTH          DB      ?
  22.  UNIT_CODE              DB      ?
  23.  COMMAND_CODE           DB      ?
  24.  STATUS                 DW      ?
  25.  RESERVED               DQ      ?
  26. REQUEST_HEADER         ENDS
  27.  
  28. INIT_PACKET            STRUC
  29.  INIT_HEADER            DB      (TYPE REQUEST_HEADER) DUP(?)
  30.  UNITS                  DB      ?
  31.  ENDING_OFFSET          DW      ?
  32.  ENDING_SEGMENT         DW      ?
  33.  ARGUMENTS_OR_ARRAY_OFF DW      ?
  34.  ARGUMENTS_OR_ARRAY_SEG DW      ?
  35. INIT_PACKET    ENDS
  36.  
  37. MEDIA_CHECK_PACKET     STRUC
  38.  MEDIA_CHECK_HEADER     DB      (TYPE REQUEST_HEADER) DUP(?)
  39.  CHECK_MEDIA_DESCRIPTOR DB      ?
  40.  RETURN_BYTE            DB      ?
  41. MEDIA_CHECK_PACKET     ENDS
  42.  
  43. BUILD_BPB_PACKET       STRUC
  44.  BUILD_BPB_HEADER       DB      (TYPE REQUEST_HEADER) DUP(?)
  45.  BPB_MEDIA_DESCRIPTOR   DB      ?
  46.  BPB_TRANSFER_ADDRESS   DD      ?
  47.  BPB_OFFSET             DW      ?
  48.  BPB_SEGMENT            DW      ?
  49. BUILD_BPB_PACKET       ENDS
  50.  
  51. INPUT_OUTPUT_PACKET    STRUC
  52.  INPUT_OUTPUT_HEADER    DB      (TYPE REQUEST_HEADER) DUP(?)
  53.  IO_MEDIA_DESCRIPTOR    DB      ?
  54.  TRANSFER_OFFSET        DW      ?
  55.  TRANSFER_SEGMENT       DW      ?
  56.  BYTE_OR_SECTOR_COUNT   DW      ?
  57.  STARTING_SECTOR        DW      ?
  58. INPUT_OUTPUT_PACKET    ENDS
  59.  
  60. CR             EQU     13
  61. LF             EQU     10
  62. CTRL_Z         EQU     26
  63. SPACE          EQU     32
  64. BOX            EQU     254
  65.  
  66. DONE              EQU     0100H             ;STATUS CODES
  67. WRITE_PROTECT     EQU     8000H
  68. UNKNOWN_UNIT      EQU     8001H
  69. DEVICE_NOT_READY  EQU     8002H
  70. UNKNOWN_COMMAND   EQU     8003H
  71. SECTOR_NOT_FOUND  EQU     8008H
  72.  
  73. MAX_COMMAND    EQU     12
  74. EMM_FLAG       DB      1
  75. REQUEST_PACKET LABEL   DWORD
  76. REQUEST_OFFSET DW      ?
  77. REQUEST_SEG    DW      ?
  78.  
  79. ;-----------------------------------------------------------------------------;
  80. ; The only task of the strategy is to save the pointer to the request header. ;
  81. ;-----------------------------------------------------------------------------;
  82. STRATEGY       PROC    FAR
  83.  
  84.                MOV     CS:REQUEST_OFFSET,BX    ;Request header address is
  85.                MOV     CS:REQUEST_SEG,ES       ; passed in ES:BX.
  86.                RET
  87.  
  88. STRATEGY       ENDP
  89.  
  90. ;------------------------------------------------------------------------;
  91. ; The interrupt procedure will be called immediately after the strategy. ;
  92. ;------------------------------------------------------------------------;
  93. INTERRUPT      PROC    FAR
  94.  
  95.                PUSH    AX                      ;Responsible for all registers.
  96.                PUSH    BX
  97.                PUSH    CX
  98.                PUSH    DX
  99.                PUSH    DS
  100.                PUSH    ES
  101.                PUSH    SI
  102.                PUSH    DI
  103.                PUSH    BP
  104.                PUSHF
  105.  
  106.                CLD                             ;All string moves forward.
  107.                PUSH    CS                      ;Point to our data.
  108.                POP     DS
  109.  
  110.                CMP     EMM_FLAG,1              ;Was EMM found?
  111.                MOV     AX,UNKNOWN_UNIT         ;Assume no.
  112.                JNZ     EXIT                    ;If no expanded manager, exit.
  113.  
  114.                LES     DI,REQUEST_PACKET       ;Retrieve request header pointer.
  115.                MOV     BL,ES:COMMAND_CODE[DI]  ;Retrieve command.
  116.                CMP     BL,MAX_COMMAND          ;Do we support it?
  117.                MOV     AX,UNKNOWN_COMMAND      ;Assume no.
  118.                JA      EXIT                    ;If out of range, exit.
  119.  
  120.                XOR     BH,BH                   ;Zero in high half of command.
  121.                SHL     BX,1                    ;Convert to word pointer.
  122.                CALL    DISPATCH_TABLE[BX]      ;Go do our thing.
  123.  
  124. EXIT:          LDS     DI,REQUEST_PACKET       ;Retrieve request header pointer.
  125.                OR      AX,DONE
  126.                MOV     STATUS[DI],AX           ;Tell DOS we are done.
  127.  
  128.                POPF                            ;Restore rest of registers.
  129.                POP     BP                      ;Restore registers.
  130.                POP     DI
  131.                POP     SI
  132.                POP     ES
  133.                POP     DS
  134.                POP     DX
  135.                POP     CX
  136.                POP     BX
  137.                POP     AX
  138.                RET                             ;Far return back to DOS.
  139.  
  140. INTERRUPT      ENDP
  141.  
  142. EVEN
  143. MIN_RESIDENT   EQU     $
  144.  
  145. DISPATCH_TABLE LABEL   WORD
  146.  
  147. DW    INIT,          MEDIA_CHECK,   BUILD_BPB,    IOCTL_INPUT, INPUT
  148. DW    INPUT_NOWAIT,  INPUT_STATUS,  INPUT_FLUSH,  OUTPUT
  149. DW    OUTPUT_VERIFY, OUTPUT_STATUS, OUTPUT_FLUSH, IOCTL_OUTPUT
  150.  
  151. BOOT_RECORD            LABEL   BYTE
  152.  
  153.                        DB      3 DUP (0)
  154.                        DB      "XPANDISK"
  155.  
  156. BIOS_PARAMETER_BLOCK   LABEL   BYTE
  157.  
  158. BYTES_PER_SECTOR       DW      SECTOR_SIZE_DEFAULT
  159. SECTORS_PER_CLUSTER    DB      1
  160. RESERVED_SECTORS       DW      1
  161. NUMBER_OF_FATS         DB      1
  162. ROOT_DIRECTORY_ENTRIES DW      ROOT_ENTRIES_DEFAULT
  163. TOTAL_SECTORS          DW      1024 / SECTOR_SIZE_DEFAULT * DISK_SIZE_DEFAULT
  164. MEDIA_DESCRIPTOR_BYTE  DB      MEDIA_DESCRIPTOR
  165. SECTORS_PER_FAT        DW      1
  166. SECTORS_PER_TRACK      DW      8
  167. NUMBER_OF_HEADS        DW      1
  168. HIDDEN_SECTORS         DW      0
  169.  
  170. BOOT_RECORD_LENGTH     EQU     $ - BOOT_RECORD
  171.  
  172. MEDIA_DESCRIPTOR       EQU     0FEH
  173. DISK_SIZE_DEFAULT      EQU     64
  174. DISK_SIZE_MINIMUM      EQU     16
  175. DISK_SIZE_MAXIMUM      EQU     32 * 1024
  176. SECTOR_SIZE_DEFAULT    EQU     256
  177. SECTOR_SIZE_MINIMUM    EQU     128
  178. SECTOR_SIZE_MAXIMUM    EQU     512
  179. ROOT_ENTRIES_DEFAULT   EQU     64
  180. ROOT_ENTRIES_MINIMUM   EQU     4
  181. ROOT_ENTRIES_MAXIMUM   EQU     512
  182.  
  183. DISK_SIZE_TEMP         DW      DISK_SIZE_DEFAULT
  184. SECTOR_SIZE_TEMP       DW      SECTOR_SIZE_DEFAULT
  185. ROOT_ENTRIES_TEMP      DW      ROOT_ENTRIES_DEFAULT
  186. DISK_SIZE              DW      DISK_SIZE_DEFAULT
  187. PARA_FLAG              DB      ?
  188. READ_ONLY_FLAG         DB      0
  189. FORMAT_FLAG            DB      1
  190.  
  191. BPB_ARRAY      DW      BIOS_PARAMETER_BLOCK
  192.  
  193. VOLUME_LABEL   LABEL   BYTE
  194.                DB      "PCMAG",SPACE,BOX,SPACE,"MJM"
  195.                DB      28H
  196.                DT      0
  197.                DW      6000H                   ;Date  July 1, 1988
  198.                DW      10E1H                   ;Time  12:00pm
  199.                DB      6 DUP (0)
  200.  
  201. VOLUME_LENGTH  EQU     $ - VOLUME_LABEL
  202.  
  203. PASSWORD               DB      "PC Magazine Productivity"
  204. PASSWORD_LENGTH        EQU     $ - PASSWORD
  205.  
  206. DISK_SIZE_MSG          DB      CR,LF,"Disk Size         ",0
  207. SECTOR_SIZE_MSG        DB  "K",CR,LF,"Sector Size       ",0
  208. DIRECTORY_ENTRIES_MSG  DB      CR,LF,"Directory Entries ",0
  209.  
  210. MEDIA_NOT_CHANGED      EQU      1
  211. MEDIA_CHANGED          EQU     -1
  212. TWELVE_BIT_FAT         EQU     4087
  213. ONE_K                  EQU     1024
  214. SIXTEEN_K              EQU     16384
  215. THIRTY_TWO_K           EQU     32768
  216.  
  217. INPUT_COMMAND  EQU     4
  218. COMMAND        DB      ?
  219.  
  220. FRAME_SEGMENT  DW      ?
  221. HANDLE         DW      ?
  222. PAGES          DW      ?
  223.  
  224. ;--------------------------------------------------------------;
  225. ; Character device functions; ignore and return no error code. ;
  226. ;--------------------------------------------------------------;
  227. INPUT_NOWAIT:
  228. INPUT_STATUS:
  229. INPUT_FLUSH:
  230. OUTPUT_STATUS:
  231. OUTPUT_FLUSH:  XOR     AX,AX                   ;Successful.
  232.                RET
  233.  
  234. ;------------------------------------------------------;
  235. ; Tell DOS media has changed if disk has been resized. ;
  236. ;------------------------------------------------------;
  237. MEDIA_CHECK    PROC    NEAR
  238.  
  239.                MOV     ES:RETURN_BYTE[DI],MEDIA_NOT_CHANGED
  240.                CMP     FORMAT_FLAG,1
  241.                JNZ     MEDIA_END
  242.                MOV     ES:RETURN_BYTE[DI],MEDIA_CHANGED
  243. MEDIA_END:     XOR     AX,AX
  244.                RET
  245.  
  246. MEDIA_CHECK    ENDP
  247.  
  248. ;---------------------------------------------------------------;
  249. ; When DOS has retrieved BPB, indicate media no longer changed. ;
  250. ;---------------------------------------------------------------;
  251. BUILD_BPB      PROC    NEAR
  252.  
  253.                MOV     ES:BPB_OFFSET[DI],OFFSET BIOS_PARAMETER_BLOCK
  254.                MOV     ES:BPB_SEGMENT[DI],CS
  255.                MOV     FORMAT_FLAG,0
  256.                XOR     AX,AX
  257.                RET
  258.  
  259. BUILD_BPB      ENDP
  260.  
  261. ;---------------------------------------------------------------;
  262. ; Entry point for both DOS INPUT and OUTPUT.  The direction     ;
  263. ; the data is moved is determined by INPUT/OUTPUT command code. ;
  264. ;---------------------------------------------------------------;
  265. INPUT_OUTPUT   PROC    NEAR
  266.  
  267. INPUT:
  268. OUTPUT:
  269. OUTPUT_VERIFY: MOV     AL,ES:COMMAND_CODE[DI]
  270.                MOV     COMMAND,AL              ;Save the DOS request.
  271.  
  272. ;; If you add this code, an asterisk will be
  273. ;; displayed so you can observe every disk access.
  274. ;;  push ax
  275. ;;  mov  al,"*"
  276. ;;  call write_tty
  277. ;;  pop  ax
  278.                CMP     READ_ONLY_FLAG,1        ;Is this a write protect disk?
  279.                JNZ     CK_RANGE                ;If no, go check range.
  280.                CMP     AL,INPUT_COMMAND        ;Else, is this an write request?
  281.                MOV     AX,WRITE_PROTECT        ;Assume yes; write violation.
  282.                JNZ     IO_ERROR                ;If guessed right, exit.
  283.  
  284. CK_RANGE:      MOV     CX,ES:BYTE_OR_SECTOR_COUNT[DI]  ;Retrieve sector count.
  285.                MOV     BP,ES:STARTING_SECTOR[DI]       ;Retrieve starting sector
  286.                MOV     BX,BP                           ; and save in BX.
  287.                CMP     BP,TOTAL_SECTORS        ;If starting sector greater
  288.                MOV     AX,SECTOR_NOT_FOUND     ; or equal to total sectors        
  289.                JAE     IO_ERROR                ; then out of range.
  290.                ADD     BX,CX                   ;If starting + count > total
  291.                CMP     BX,TOTAL_SECTORS        ; then out of range.
  292.                JBE     SAVE_PAGE_MAP
  293.  
  294. IO_ERROR:      MOV     ES:BYTE_OR_SECTOR_COUNT[DI],0   ;No sectors moved.
  295.                RET
  296.  
  297. SAVE_PAGE_MAP: MOV     DX,HANDLE               ;Retrieve EMM handle.
  298.                MOV     AH,47H                  ;Preserve current expanded
  299.                INT     67H                     ; memory registers.
  300.                OR      AH,AH                   ;Was there an error?
  301.                MOV     AX,DEVICE_NOT_READY     ;If yes, return error.
  302.                JNZ     IO_ERROR
  303.  
  304.                PUSH    DS                          ;Preserve data segment.
  305.                MOV     DX,BYTES_PER_SECTOR         ;Retrieve bytes/sector.
  306.                MOV     AX,ES:TRANSFER_SEGMENT[DI]  ;Destination, transfer
  307.                MOV     SI,ES:TRANSFER_OFFSET[DI]   ; segment and offset.
  308.                MOV     BX,FRAME_SEGMENT            ;Source EMM segment.
  309.                CMP     COMMAND,INPUT_COMMAND       ;Is this a DOS read request?
  310.                JNZ     SET_SEGMENTS                ;If no, write; guessed right.
  311.                XCHG    AX,BX                       ;Else, read request; swap
  312.                MOV     DI,SI                       ; source and destination.
  313.  
  314. SET_SEGMENTS:  MOV     DS,AX                   ;Set segments.
  315.                MOV     ES,BX
  316.                MOV     BX,-1                   ;Initialize page out of range.
  317.  
  318. NEXT_SECTOR:   PUSH    CX                      ;Save sector count.
  319.                PUSH    DX                      ;Save bytes/sector.
  320.                MOV     AX,BP                   ;Requested sector times
  321.                MUL     DX                      ; bytes/sector = bytes offset.
  322.                MOV     CX,SIXTEEN_K            ;Divide by 16K; quotient = page
  323.                DIV     CX                      ; remainder = offset.
  324.                CMP     AX,BX                   ;Is request page currently in
  325.                JZ      MOVE_SECTOR             ; memory?  If yes, continue.
  326.  
  327.                MOV     BX,AX                       ;Make requested current page.
  328.                CMP     CS:COMMAND,INPUT_COMMAND    ;Is it a read request?
  329.                JNZ     OUTPUT_CODE                 ;If no, write request.
  330.                MOV     SI,DX                       ;If read, SI = destination.
  331.                JMP     SHORT MAP_PAGE
  332. OUTPUT_CODE:   MOV     DI,DX                   ;If write, DI = destination.
  333. MAP_PAGE:      XOR     AL,AL                   ;AL = physical page; BX = logical
  334.                MOV     DX,CS:HANDLE            ;DX = EMM handle.
  335.                MOV     AH,44H                  ;Map the page into memory.
  336.                INT     67H
  337.  
  338. MOVE_SECTOR:   POP     DX                      ;Retrieve bytes/sector.
  339.                MOV     CX,DX                   ;Save in counter.
  340.                SHR     CX,1                    ;Divide by two.
  341.                REP     MOVSW                   ;Move CX words.
  342.                INC     BP                      ;Next requested sector.
  343.                POP     CX                      ;Retrieve sector count.
  344.                LOOP    NEXT_SECTOR             ;Do all requested sectors.
  345.  
  346.                POP     DS                      ;Restore data segment.
  347.                MOV     DX,HANDLE               ;EMM handle.
  348.                MOV     AH,48H                  ;Restore Page Map.
  349.                INT     67H
  350.                XOR     AX,AX                   ;Return success code.
  351.                RET
  352.  
  353. INPUT_OUTPUT   ENDP
  354.  
  355. ;--------------------------------------------------;
  356. ; Return password and parsing results to XPANBOSS. ;
  357. ;--------------------------------------------------;
  358. IOCTL_INPUT    PROC    NEAR
  359.  
  360.                MOV     CX,PASSWORD_LENGTH               ;Is password length same
  361.                CMP     CX,ES:BYTE_OR_SECTOR_COUNT[DI]   ; as byte count request?
  362.                JZ      IOCTL_WRITE                      ;If yes, continue.
  363.                MOV     ES:BYTE_OR_SECTOR_COUNT[DI],0    ;Else, zero transferred.
  364.                MOV     AX,UNKNOWN_UNIT                  ;Unknown unit.
  365.                JMP     SHORT IO_INPUT_END
  366.  
  367. IOCTL_WRITE:   PUSH    DS                               ;Save segments and
  368.                PUSH    ES                               ; and counter.
  369.                PUSH    CX
  370.  
  371.                MOV     DS,ES:TRANSFER_SEGMENT[DI]       ;Point to XPANBOSS's
  372.                MOV     SI,81H                           ; PSP command line.
  373.                CALL    PARSE                            ;Parse the parameters.
  374.  
  375.                POP     CX                               ;Restore registers.
  376.                POP     ES
  377.                POP     DS
  378.  
  379.                MOV     SI,OFFSET PASSWORD               ;Point to password.
  380.                MOV     AX,ES:TRANSFER_OFFSET[DI]        ;Destination, XPANBOSS
  381.                MOV     ES,ES:TRANSFER_SEGMENT[DI]       ; communication pipe.
  382.                MOV     DI,AX
  383.                REP     MOVSB                            ;Transfer the password.
  384.  
  385.                MOV     AL,PARA_FLAG            ;Parameter found?
  386.                AND     AX,BP                   ;WITHOUT confirmation flag.
  387.                STOSB                           ;Return 1 if should prompt user.
  388.  
  389.                XOR     AX,AX                   ;Successful.
  390. IO_INPUT_END:  RET
  391.  
  392. IOCTL_INPUT    ENDP
  393.  
  394. ;--------------------------------------------------------------------------;
  395. ; If counter password confirms, then XPANBOSS OK'ed disk parameter changes.;
  396. ;--------------------------------------------------------------------------;
  397. IOCTL_OUTPUT   PROC    NEAR
  398.  
  399.                MOV     CX,PASSWORD_LENGTH               ;Is password length same
  400.                CMP     CX,ES:BYTE_OR_SECTOR_COUNT[DI]   ; as byte count request?
  401.                JNZ     IOCTL_ERROR                      ;If no, not XPANBOSS.
  402.  
  403.                PUSH    ES                               ;Save request header
  404.                PUSH    DI                               ; pointers.
  405.                MOV     SI,OFFSET PASSWORD               ;Check if counter
  406.                MOV     AX,ES:TRANSFER_OFFSET[DI]        ; password confirms.
  407.                MOV     ES,ES:TRANSFER_SEGMENT[DI]
  408.                MOV     DI,AX
  409.                REPZ    CMPSB
  410.                POP     DI                               ;Restore registers.
  411.                POP     ES
  412.                JNZ     IOCTL_ERROR                      ;If bad password, exit.
  413.  
  414.                CMP     PARA_FLAG,1                      ;Any parameters?
  415.                JNZ     IOCTL_DONE                       ;If no, our task done.
  416.  
  417.                MOV     DX,HANDLE                        ;Retrieve EMM handle.
  418.                MOV     AH,45H                           ;Deallocate Pages.
  419.                INT     67H
  420.                CALL    ALLOCATE                         ;Allocate new pages.
  421.                JC      IOCTL_ERROR                      ;Error exit if failed.
  422.  
  423. IOCTL_DONE:    CALL    STATISTICS                       ;Else, display stats.
  424.                XOR     AX,AX                            ;Return successful.
  425.                JMP     SHORT IO_OUTPUT_END
  426.  
  427. IOCTL_ERROR:   MOV     ES:BYTE_OR_SECTOR_COUNT[DI],0    ;Else, zero transferred.
  428.                MOV     AX,UNKNOWN_UNIT                  ;Unknown unit.
  429.  
  430. IO_OUTPUT_END: RET
  431.  
  432. IOCTL_OUTPUT   ENDP
  433.  
  434. ;-------------------------------;
  435. ; INPUT - DS:SI Points to parameters.
  436. ;-------------------------------;
  437. PARSE          PROC    NEAR
  438.  
  439.                PUSH    CS                      ;Point ES to local data.
  440.                POP     ES
  441.                MOV     ES:PARA_FLAG,0          ;Initialize variables.
  442.                MOV     ES:READ_ONLY_FLAG,0
  443.                MOV     ES:DISK_SIZE_TEMP,DISK_SIZE_DEFAULT
  444.                MOV     ES:SECTOR_SIZE_TEMP,SECTOR_SIZE_DEFAULT
  445.                MOV     ES:ROOT_ENTRIES_TEMP,ROOT_ENTRIES_DEFAULT
  446.  
  447.                MOV     BP,1                    ;WITHOUT asking flag; assume yes.
  448.  
  449. NEXT_PARSE:    LODSB                           ;Get a byte.
  450.                CMP     AL,CR                   ;If carriage return
  451.                JZ      PARSE_END               ; or linefeed, done.
  452.                CMP     AL,LF
  453.                JZ      PARSE_END
  454.                CMP     AL,"/"                  ;Switch character?
  455.                JNZ     NEXT_PARSE              ;If no, next byte.
  456.                LODSB                           ;Else, get switch.
  457.                CMP     AL,CR                   ;If CR or LF, done.
  458.                JZ      PARSE_END
  459.                CMP     AL,LF
  460.                JZ      PARSE_END
  461.                AND     AL,5FH                  ;Else, capitalize
  462.                CMP     AL,"M"                  ;Is it Minimum?
  463.                JNZ     CK_A
  464.                MOV     ES:DISK_SIZE_TEMP,DISK_SIZE_MINIMUM
  465.                JMP     SHORT PARA_CHANGED
  466.  
  467. PARSE_END:     RET
  468.  
  469. CK_A:          CMP     AL,"A"                  ;Is it Maximum?
  470.                JNZ     CK_R
  471.                MOV     ES:DISK_SIZE_TEMP,DISK_SIZE_MAXIMUM
  472.                JMP     SHORT PARA_CHANGED
  473.  
  474. CK_R:          CMP     AL,"R"                  ;Is it Read-only?
  475.                JNZ     CK_W
  476.                MOV     ES:READ_ONLY_FLAG,1
  477.  
  478. CK_W:          CMP     AL,"W"                  ;Is it WITHOUT asking?
  479.                JNZ     CK_PARA
  480.                XOR     BP,BP                   ;WITHOUT confirmation flag.
  481.  
  482. CK_PARA:       CALL    DECIMAL_INPUT           ;Get decimal number.
  483.  
  484.                CMP     AL,"D"                  ;Is switch character Disk Size?
  485.                JNZ     CK_S
  486.                CMP     BX,DISK_SIZE_MINIMUM    ;If yes, check boundaries.
  487.                JAE     CK_D_MAX
  488.                MOV     BX,DISK_SIZE_MINIMUM
  489. CK_D_MAX:      CMP     BX,DISK_SIZE_MAXIMUM
  490.                JBE     STORE_D_TEMP
  491.                MOV     BX,DISK_SIZE_MAXIMUM
  492. STORE_D_TEMP:  MOV     ES:DISK_SIZE_TEMP,BX
  493.                JMP     SHORT PARA_CHANGED
  494.  
  495. CK_S:          CMP     AL,"S"                  ;Is it Sector Size?
  496.                JNZ     CK_E
  497.                MOV     CX,SECTOR_SIZE_MINIMUM  ;If yes, check boundaries.
  498.                CMP     BX,CX
  499.                JBE     STORE_S_TEMP
  500.                MOV     CX,SECTOR_SIZE_MAXIMUM
  501.                CMP     BX,CX
  502.                JAE     STORE_S_TEMP
  503.                MOV     CX,SECTOR_SIZE_DEFAULT
  504. STORE_S_TEMP:  MOV     ES:SECTOR_SIZE_TEMP,CX
  505.                JMP     SHORT PARA_CHANGED
  506.  
  507. CK_E:          CMP     AL,"E"                  ;Is it Root Directory Entries?
  508.                JNZ     PARA_END
  509.                CMP     BX,ROOT_ENTRIES_MINIMUM ;If yes, check boundaries
  510.                JAE     CK_E_MAX
  511.                MOV     BX,ROOT_ENTRIES_MINIMUM
  512. CK_E_MAX:      CMP     BX,ROOT_ENTRIES_MAXIMUM
  513.                JBE     STORE_E_TEMP
  514.                MOV     BX,ROOT_ENTRIES_MAXIMUM
  515. STORE_E_TEMP:  MOV     ES:ROOT_ENTRIES_TEMP,BX
  516.  
  517. PARA_CHANGED:  OR      ES:PARA_FLAG,1          ;Flag that parameter found.
  518. PARA_END:      JMP     NEXT_PARSE              ;Parse all parameters.
  519.  
  520. PARSE          ENDP
  521.  
  522. ;---------------------------------;
  523. ; INPUT - SI points to parameter start.
  524. ; OUTPUT - SI points to parameter end. BX = number.
  525. ;---------------------------------;
  526. DECIMAL_INPUT  PROC    NEAR
  527.  
  528.                PUSH    AX                      ;Save switch character.
  529.                XOR     BX,BX                   ;Start with zero as number.
  530. NEXT_DECIMAL:  LODSB                           ;Get a character.
  531.                CMP     AL,CR                   ;Carriage return or linefeed?
  532.                JZ      ADJUST_DEC              ;If yes, done here.
  533.                CMP     AL,LF
  534.                JZ      ADJUST_DEC
  535.                CMP     AL,"/"                  ;Forward slash?
  536.                JZ      ADJUST_DEC              ;If yes, done here.
  537.                SUB     AL,"0"                  ;ASCII to binary.
  538.                JC      NEXT_DECIMAL            ;If not between 0 and 9, skip.
  539.                CMP     AL,9
  540.                JA      NEXT_DECIMAL
  541.                CBW                             ;Convert byte to word.
  542.                XCHG    AX,BX                   ;Swap old and new number.
  543.                MOV     CX,10                   ;Shift to left by multiplying
  544.                MUL     CX                      ; last entry by ten.
  545.                JC      DECIMAL_ERROR           ;If carry, too big.
  546.                ADD     BX,AX                   ;Add new number and store in BX.
  547.                JNC     NEXT_DECIMAL            ;If not carry, next number.
  548. DECIMAL_ERROR: MOV     BX,-1                   ;Else, too big; return -1.
  549.  
  550. ADJUST_DEC:    DEC     SI                      ;Adjust pointer.
  551.                POP     AX                      ;Restore switch character.
  552.                RET
  553.  
  554. DECIMAL_INPUT  ENDP
  555.  
  556. ;---------------------------;
  557. ;  OUTPUT - CY = 0 If successful. CY = 1 If unsuccessful.
  558. ;---------------------------;
  559. ALLOCATE       PROC    NEAR
  560.  
  561.                PUSH    ES                      ;Save request header pointers.
  562.                PUSH    DI
  563.  
  564.                MOV     BX,DISK_SIZE_TEMP       ;Retrieve disk size request.
  565.                ADD     BX,15 + 16              ;Round up and adjust for DEC.
  566.                MOV     CL,4                    ;Convert to number of 16K pages.
  567.                SHR     BX,CL
  568.  
  569. NEXT_ALLOCATE: DEC     BX                      ;Decrement page request until
  570.                JNZ     GET_MEMORY              ; filled with memory available.
  571.                STC                             ;Error if no memory available.
  572.                JMP     ALLOCATE_END
  573.  
  574. GET_MEMORY:    MOV     AH,43H                  ;Allocate Pages.
  575.                INT     67H
  576.                OR      AH,AH                   ;Successful?
  577.                JNZ     NEXT_ALLOCATE           ;If no, decrement by one page.
  578.  
  579.                MOV     PAGES,BX                ;Store pages.
  580.                MOV     HANDLE,DX               ;Store new EMM handle.
  581.  
  582.                SHL     BX,CL                   ;Convert back to K bytes.
  583.                MOV     DISK_SIZE,BX            ;Store size of disk for stats.
  584.  
  585.                MOV     BP,SECTOR_SIZE_TEMP     ;Retrieve sector size request.
  586. NEXT_SECTORS:  MOV     AX,ONE_K                ;Disk size * 1024 / sector size
  587.                MUL     BX                      ; = total sectors.  Total sectors
  588.                SUB     AX,BP                   ; cannot exceed 64K.  Adjust
  589.                SBB     DX,0                    ; sector size up until total
  590.                CMP     DX,BP                   ; sectors <= 64K.
  591.                JB      GOT_SECTORS             ; (Decrement by one sector to
  592.                SHL     BP,1                    ; make division by zero easy
  593.                JMP     SHORT NEXT_SECTORS      ; to detect and avoid.)
  594.  
  595. GOT_SECTORS:   DIV     BP                      ;Divide to get total sectors - 1.
  596.                INC     AX                      ;Increment to get total sectors.
  597.                OR      AX,AX                   ;Can't have 65536 (64K) sectors.
  598.                JNZ     SECTORS                 ;That is, sector total is not
  599.                DEC     AX                      ; a zero based number.
  600.                DEC     AX
  601. SECTORS:       MOV     TOTAL_SECTORS,AX        ;Store sector count.
  602.                PUSH    AX                      ;Save results.
  603.                MOV     BYTES_PER_SECTOR,BP     ;Store bytes/sector.
  604.  
  605.                MOV     DX,BP                   ;Retrieve sector size.
  606.                MOV     CL,5                    ;Divide by 32 = entries/sector.
  607.                SHR     DX,CL
  608.                MOV     AX,ROOT_ENTRIES_TEMP    ;Retrieve entries requested.
  609.                DIV     DL                      ;Divide by entries/sector.
  610.                ADD     AH,-1                   ;Round if remainder.
  611.                ADC     AL,0
  612.                XOR     AH,AH                   ;Zero in high half.
  613.                MOV     BX,AX                   ;Save directory sectors.
  614.                MUL     DL                         ;Times entries/sector
  615.                MOV     ROOT_DIRECTORY_ENTRIES,AX  ; = total directory entries.
  616.  
  617.                POP     AX                      ;Retrieve total sectors.
  618.                MOV     CL,1                    ;Assume 1 sector/cluster.
  619.                CMP     AX,THIRTY_TWO_K - 2     ;If total over half of maximum.
  620.                JB      STORE_RESULTS           ;If yes, assumed right.
  621.                INC     CL                      ;Else, use 2 sectors/cluster.
  622. STORE_RESULTS: MOV     SECTORS_PER_CLUSTER,CL  ;Store sectors/cluster.
  623.  
  624.                SUB     AX,BX                   ;Subtract directory sectors
  625.                DEC     AX                      ;Subtract boot sector
  626.                SHR     CL,1                    ;Divide cluster size by 2.
  627.                SHR     AX,CL                   ;Divide to get clusters.
  628.                MOV     CX,AX                   ;Save clusters in CX.
  629.                SHL     AX,1                    ;Clusters * 2 = 16 bit FAT bytes.
  630.                MOV     BL,0FFH                 ;0FFh as 3rd byte in 16 bit FAT.
  631.                CMP     CX,TWELVE_BIT_FAT
  632.                JA      GOT_FAT                 ;If clusters > 4087, 16 bit FAT.
  633.                ADD     AX,CX                   ;Else, 1.5 bytes per 12 bit FATs.
  634.                INC     AX                      ;Round up.
  635.                SHR     AX,1
  636.                XOR     BL,BL                   ;Use zero as 3rd byte in FAT.
  637.  
  638. GOT_FAT:       XOR     DX,DX                   ;Zero in high half.
  639.                DIV     BP                      ;Divide by bytes/sector.
  640.                ADD     DX,-1                   ;Round up.
  641.                ADC     AX,0
  642.                MOV     SECTORS_PER_FAT,AX      ;Store sectors/FAT.
  643.  
  644.                CALL    FORMAT                  ;Format the disk.
  645.                CLC                             ;CY = 0 for success.
  646.  
  647. ALLOCATE_END:  POP     DI                      ;Restore request header pointers.
  648.                POP     ES
  649.                RET
  650.  
  651. ALLOCATE       ENDP
  652.  
  653. ;-----------------------------; 
  654. ;  INPUT - BL = 00h for 12 bit fat. BL = FFh for 16 bit fat.
  655. ;-----------------------------;
  656. FORMAT         PROC    NEAR
  657.  
  658.                PUSH    BX                      ;Save BX.
  659.                MOV     DX,HANDLE               ;Retrieve EMM handle.
  660.                MOV     CX,PAGES                ;Retrieve pages.
  661.                CMP     CX,3                    ;Maximum for boot, FAT, and
  662.                JB      NEXT_MAP_PAGE           ; directory = 3 * 16K pages.
  663.                MOV     CX,3
  664. NEXT_MAP_PAGE: MOV     AX,CX                   ;Physical page.
  665.                DEC     AX                      ;Pages are zero based.
  666.                MOV     BX,AX                   ;Logical page the same.
  667.                MOV     AH,44H                  ;Map Handle Page.
  668.                INT     67H
  669.                LOOP    NEXT_MAP_PAGE           ;Map all necessary pages.
  670.  
  671.                MOV     AX,FRAME_SEGMENT        ;Retrieve frame segment.
  672.                MOV     ES,AX
  673.                XOR     DI,DI                   ;Offset of zero.
  674.                MOV     SI,OFFSET BOOT_RECORD        ;Store boot record
  675.                MOV     CX,BOOT_RECORD_LENGTH / 2    ; in sector zero.
  676.                REP     MOVSW
  677.  
  678.                MOV     DI,BYTES_PER_SECTOR     ;Retrieve bytes/sector; sector 1.
  679.                MOV     AX,SECTORS_PER_FAT      ;Retrieve sectors/FAT.
  680.                MUL     DI                      ;Multiply to get total bytes.
  681.                MOV     CX,AX
  682.                MOV     AL,MEDIA_DESCRIPTOR     ;Store media descriptor
  683.                STOSB                           ; as first FAT byte.
  684.  
  685.                MOV     AX,0FFFFH               ;0FFFFh next two bytes of FAT.
  686.                STOSW
  687.                POP     BX                      ;0 for 12 bit FAT; 0FFh for 16
  688.                MOV     AL,BL                   ; bit FAT next byte.
  689.                STOSB
  690.  
  691.                SUB     CX,4                    ;Adjust FAT bytes by 4 control
  692.                SHR     CX,1                    ; bytes; divide by two for words.
  693.                XOR     AX,AX                   ;Format FAT with zeros.
  694.                REP     STOSW
  695.  
  696.                MOV     SI,OFFSET VOLUME_LABEL  ;DI now points to directory.
  697.                MOV     CX,VOLUME_LENGTH / 2    ;Store volume label as first
  698.                REP     MOVSW                   ; entry in directory.
  699.  
  700.                MOV     BX,ROOT_DIRECTORY_ENTRIES   ;Retrieve directory entries.
  701.                DEC     BX                          ;Less one for volume entry.
  702.                MOV     CL,4                        ;Times 32 / 2 bytes per word.
  703.                SHL     BX,CL
  704.                MOV     CX,BX
  705.                REP     STOSW                   ;Zeros in directory.
  706.  
  707.                MOV     FORMAT_FLAG,1           ;Tell Media Check disk changed.
  708.                RET
  709.  
  710. FORMAT         ENDP
  711.  
  712. ;--------------------------------------------------------; 
  713. ; Display disk size, sector size, and directory entries. ;
  714. ;--------------------------------------------------------;
  715. STATISTICS:    MOV     SI,OFFSET DISK_SIZE_MSG
  716.                CALL    TTY_STRING
  717.                MOV     AX,DISK_SIZE
  718.                CALL    DECIMAL_OUTPUT
  719.                MOV     SI,OFFSET SECTOR_SIZE_MSG
  720.                CALL    TTY_STRING
  721.                MOV     AX,BYTES_PER_SECTOR
  722.                CALL    DECIMAL_OUTPUT
  723.                MOV     SI,OFFSET DIRECTORY_ENTRIES_MSG
  724.                CALL    TTY_STRING
  725.                MOV     AX,ROOT_DIRECTORY_ENTRIES
  726.                CALL    DECIMAL_OUTPUT
  727.                RET
  728. ;-------------------------;
  729. TTY:           CALL    WRITE_TTY
  730. TTY_STRING:    LODSB
  731.                OR      AL,AL
  732.                JNZ     TTY
  733.                RET
  734. ;-------------------------;
  735. WRITE_TTY:     MOV     AH,0EH
  736.                INT     10H
  737.                RET
  738. ;-------------------------;
  739. PRINT_STRING:  MOV     AH,9
  740.                INT     21H
  741.                RET
  742.  
  743. ;----------------------------------------;
  744. ; INPUT: AX = number.
  745. ;----------------------------------------;
  746. DECIMAL_OUTPUT PROC    NEAR
  747.  
  748.                MOV     BX,10                   ;Divisor of ten.
  749.                XOR     CX,CX                   ;Zero in counter.
  750. NEXT_COUNT:    XOR     DX,DX                   ;Zero in high half.
  751.                DIV     BX                      ;Divide by ten.
  752.                ADD     DL,"0"                  ;Convert to ASCII.
  753.                PUSH    DX                      ;Save results.
  754.                INC     CX                      ;Also increment count.
  755.                CMP     AX,0                    ;Are we done?
  756.                JNZ     NEXT_COUNT              ;Continue until zero.
  757.                MOV     BX,CX                   ;Save the number of characters.
  758.  
  759. NEXT_NUMBER:   POP     AX                      ;Retrieve numbers.
  760.                CALL    WRITE_TTY               ;And write them.
  761.                LOOP    NEXT_NUMBER
  762.                RET
  763.  
  764. DECIMAL_OUTPUT ENDP
  765.  
  766. EVEN
  767. MAX_RESIDENT   EQU     $
  768.  
  769. ;************* END OF RESIDENT PORTION *************;
  770.  
  771. HEADING        LABEL   BYTE
  772. COPYRIGHT      DB      CR,LF,"XPANDISK.SYS 1.0 (C) 1988 Ziff Communications Co."
  773. PROGRAMMER     DB      CR,LF,"PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
  774.  
  775. DB "Syntax: XPANDISK.SYS [/D disk size][/S sector size][/E entries][/M][/A]"
  776. DB CR,LF,LF
  777. DB "disk size   = (16 - 32768)K bytes; default = 64",CR,LF
  778. DB "sector size = (128,256,512) bytes; default = 256",CR,LF
  779. DB "entries     = (4 - 512)in root directory; default = 64",CR,LF
  780. DB "/M = Minimum disk size (16K)",CR,LF
  781. DB "/A = All of available expanded memory",CR,LF,LF
  782.  
  783. DB "Use XPANBOSS.COM to control installed XPANDISK",CR,LF,"$"
  784.  
  785. EMM            DB      "EMMXXXX0"
  786. EMM_LENGTH     EQU     $ - EMM
  787. EMM_NOT_FOUND  DB      CR,LF,"Expanded memory driver not found",CR,LF,LF,"$"
  788. INSTALLED      DB      CR,LF,LF,"XPANDISK installed",CR,LF,LF,"$"
  789.  
  790. ;------------------------------------------;
  791. ; INPUT - ES:DI points to request header.
  792. ; OUTPUT - AX = Error status
  793. ;------------------------------------------;
  794. INIT           PROC    NEAR
  795.  
  796.                MOV     DX,OFFSET HEADING       ;Display copyright.
  797.                CALL    PRINT_STRING
  798.  
  799.                PUSH    DS                      ;Save segment registers.
  800.                PUSH    ES
  801.                MOV     SI,ES:ARGUMENTS_OR_ARRAY_OFF[DI]   ;Point to CONFIG.SYS
  802.                MOV     DS,ES:ARGUMENTS_OR_ARRAY_SEG[DI]   ; XPANDISK parameters.
  803. PARSE_LEADING: LODSB                                      ;Parse of any leading
  804.                CMP     AL,SPACE                ; white space after DEVICE =.
  805.                JBE     PARSE_LEADING
  806. FIND_END:      LODSB                           ;Find end of "XPANDISK.SYS".
  807.                CMP     AL,SPACE
  808.                JA      FIND_END
  809.                DEC     SI
  810.                CALL    PARSE                   ;Parse parameters.
  811.                POP     ES                      ;Restore segment registers.
  812.                POP     DS
  813.  
  814.                MOV     ES:UNITS[DI],1          ;Set up header.
  815.                MOV     ES:ARGUMENTS_OR_ARRAY_OFF[DI],OFFSET BPB_ARRAY
  816.                MOV     ES:ARGUMENTS_OR_ARRAY_SEG[DI],CS
  817.  
  818.                PUSH    ES                      ;Save request header pointers.
  819.                PUSH    DI
  820.                MOV     AX,3567H                ;Retrieve EMM interrupt vector.
  821.                INT     21H
  822.                MOV     DI,0AH                  ;See if offset 10 of vector
  823.                MOV     SI,OFFSET EMM           ; points to EMMXXXX0.
  824.                MOV     CX,EMM_LENGTH
  825.                REPZ    CMPSB
  826.                POP     DI                      ;Restore segments.
  827.                POP     ES
  828.                JNZ     NO_EMM                  ;Exit if EMM not found.
  829.  
  830.                MOV     AH,40H                  ;Get Status of EMM.
  831.                INT     67H
  832.                OR      AH,AH
  833.                JNZ     NO_EMM                  ;Exit if not working.
  834.  
  835.                MOV     AH,41H                  ;Get Page Frame Address.
  836.                INT     67H
  837.                OR      AH,AH                   ;Exit if not available.
  838.                JNZ     NO_EMM
  839.                MOV     FRAME_SEGMENT,BX        ;Else, store.
  840.  
  841.                CALL    ALLOCATE                ;Allocate memory and format disk.
  842.                JNC     FOUND_EMM               ;Exit with error if failed.
  843.  
  844. NO_EMM:        MOV     ES:ENDING_OFFSET[DI],OFFSET MIN_RESIDENT
  845.                MOV     ES:ENDING_SEGMENT[DI],CS
  846.                MOV     ES:UNITS[DI],0             ;Install zero units.
  847.                MOV     EMM_FLAG,0                 ;Fail any other driver calls.
  848.                MOV     DX,OFFSET EMM_NOT_FOUND    ;Tell user not installed.
  849.                JMP     SHORT INIT_END
  850.  
  851. FOUND_EMM:     MOV     ES:ENDING_OFFSET[DI],OFFSET MAX_RESIDENT
  852.                MOV     ES:ENDING_SEGMENT[DI],CS
  853.                CALL    STATISTICS                 ;If successful installation
  854.                MOV     DX,OFFSET INSTALLED     ; display stats and "installed".
  855.  
  856. INIT_END:      CALL    PRINT_STRING
  857.                XOR     AX,AX
  858.                RET
  859.  
  860. INIT           ENDP
  861.  
  862. _TEXT          ENDS
  863.                END
  864.