title Manage the VHARD FAT cache subttl Prologue page 60,132 comment { ****************************************************************************** File VHCACHE.ASM Author: Aaron L. Brenner BIX mail address albrenner GEnie address A.BRENNER This program is hereby released to the public domain. Purpose: Provide a command-driven interface to the VHARD FAT/root dir cache. Command syntax: VHCACHE [? | ON | OFF | MANUAL | AUTO | FLUSH] Parameters: ? or INFO Display information about the cache. ON Enable the cache. OFF Disable and remove the cache. MANUAL Disable auto-flush. AUTO Enable auto-flush. FLUSH Write the cache to disk. If no parameters, a brief usage message is displayed. ERRORLEVEL returned: 0 The requested operation was performed successfully. 1 An error was reported by the driver. 2 Command syntax error. 3 VHARD.SYS not installed. 4 Invalid DOS version 5 Insufficient free memory Notes: All commands (including "?") require that VHARD.SYS be installed. Revision history: 1.00 07/20/90 ALB Created. ****************************************************************************** endcomment { subttl Included files page include dd_defs.inc include vhard.inc subttl Program stack and data page vhcache_stack segment stack dw 128 dup (0) vhcache_stack ends vhcache_data segment assume ds:vhcache_data ax_value dw 4c00h dx_value dw 0 vhctl_handle dw 0 vhctl_name db 'VHARDCTL',0 vhard_drive db 0ffh ; Drive assigned (FF = unavailable) vhard_ver dw 0 ; BCD version of driver vhard_BPB DOS_BPB <> ; BPB for the driver (we ignore it) cache_flags db 0 ; Flags for the cache if installed cache_addr dw 0, 0 ; Address of current cache cmd_block VH_CMD <> cmd_keyword db 8 dup (0) ; The keyword on the command line vhversion db 'VHARD version is $' vhdrive_is db 'VHARD is using drive letter $' cached_at db 'Currently installed cache is at $' needs_flushing db 'Cache needs to be FLUSHed', 13, 10, '$' auto_enabled db 'AUTOflush is enabled', 13, 10, '$' ; ; Error messages ; no_share db 'SHARE.EXE must be run before AUTOflush can be' db ' enabled.', 13, 10, '$' bad_dos_ver db 'Invalid DOS version for AUTOflush.', 13, 10, '$' no_memory db 'Not enough memory', 13, 10, '$' no_cache db 'The cache is not yet installed', 13, 10, '$' unk_err db 'unknown error$' em1 db 'drive not read$' em2 db 'seek error$' em3 db 'general failure$' em4 db 'CRC error$' em5 db 'DMA boundary error$' em6 db 'DMA overrun$' em7 db 'sector not found$' em8 db 'diskette is write-protected$' em9 db 'address mark not found$' em10 db 'unknown BIOS command$' em11 db 'unknown VHARD command$' em12 db 'cache already installed$' em13 db 'cache not installed$' em14 db 'cache must be flushed$' err_prefix db 'Error: $' crlf_str db 13, 10, '$' error_messages dw unk_err dw em1 dw em2 dw em3 dw em4 dw em5 dw em6 dw em7 dw em8 dw em9 dw em10 dw em11 dw em12 dw em13 dw em14 ; ; Keywords we recognize ; kw1 db 1,'?' kw11 db 4,'INFO' kw2 db 2,'ON' kw3 db 3,'OFF' kw4 db 6,'MANUAL' kw5 db 4,'AUTO' kw6 db 5,'FLUSH' keywords dw kw1, kw_info dw kw11, kw_info dw kw2, kw_on dw kw3, kw_off dw kw4, kw_manual dw kw5, kw_auto dw kw6, kw_flush dw 0 usage_msg db 'VHCACHE v1.00 - Public Domain Software', 13, 10 db 13, 10, 'Usage: VHPREP [? | ON | OFF | MANUAL | AUTO' db ' | FLUSH]', 13, 10 db 13, 10, '? or INFO Display information on the cache' db 13, 10, 'ON Enable the cache' db 13, 10, 'OFF Disable and remove the cache' db 13, 10, 'MANUAL Disable auto-flush' db 13, 10, 'AUTO Enable auto-flush' db 13, 10, 'FLUSH Write the cache to disk' db 13, 10, '$' bad_kw db 'Unknown keyword: "$' bad_kw2 db '".', 13, 10, '$' no_driver db 'VHARD.SYS must be installed', 13, 10, '$' vhcache_data ends subttl Start of program code page vhcache_code segment assume cs:vhcache_code, ds:nothing, es:nothing, ss:vhcache_stack start proc call initialize ; Do program initialization assume ds:vhcache_data call do_command ; Do the command they want mov ax,ax_value ; mov dx,dx_value ; int 21h ; start endp ;***************************************************************************** ; ; Perform once-only program initialization. ; ;***************************************************************************** initialize proc near mov ax,vhcache_data ; Get our data segment mov es,ax ; assume es:vhcache_data mov si,81h ; Point to the command tail cld ; Make sure of direction init_l1: lodsb ; Get a character cmp al,' ' ; Is it a blank? je init_l1 ; Yep - ignore it cmp al,9 ; Tab? je init_l1 ; Yes - ignore it cmp al,0dh ; End of the line? jne init_l2 ; No - copy the keyword push es ; Set DS aright pop ds ; assume ds:vhcache_data mov dx,offset usage_msg ; Display the usage message mov ah,9 ; int 21h ; mov ax,4c02h ; Pretend it's an error int 21h ; Exit to DOS init_l2: assume ds:nothing dec si ; Point back to where we stopped mov di,offset cmd_keyword[1]; Point to where we're copying to mov cx,6 ; Max we want to copy init_l3: lodsb ; Get the next byte cmp al,' ' ; Done with the command? je init_l5 ; Yes - stop copying cmp al,9 ; Done with it? je init_l5 ; Yes - stop copying cmp al,0dh ; End of the line? je init_l5 ; Yes - stop copying jcxz init_l3 ; If the name buffer's full, ignore cmp al,'a' ; Is it lower case? jb init_l4 ; No - use it cmp al,'z' ; Is it? ja init_l4 ; Nope - use it xor al,20h ; Make it upper case init_l4: stosb ; Put it in the name buffer inc cmd_keyword[0] ; Count this character dec cx ; Both ways jmp short init_l3 ; Loop back for more init_l5: sub al,al ; Terminate it, too stosb ; push es ; Swap segments so we can release our push ds ; environment pop es ; pop ds ; assume ds:vhcache_data, es:nothing mov es,es:[2ch] ; Get our environment segment mov ah,49h ; Fn to release memory int 21h ; push ds ; Lastly, set ES to our data seg pop es ; assume es:vhcache_data mov dx,offset vhctl_name ; Try to get to the VHARDCTL device mov ax,3c02h ; int 21h ; jnc init_l6 ; If we could, make sure it's a device init_err: mov dx,offset no_driver ; Complain that the driver's missing mov ah,9 ; int 21h ; mov ax,4c03h ; Exit with appropriate code int 21h ; init_l6: mov bx,ax ; Get the handle for it mov vhctl_handle,ax ; Save it for later use, too mov ax,4400h ; Get info on the handle int 21h ; test dl,80h ; Is this a device? jz init_err ; No - just a file, so complain mov cmd_block.VC_cmd_code,CMD_GETDATA; Get driver info mov word ptr cmd_block.VC_buffer[0],offset vhard_drive mov word ptr cmd_block.VC_buffer[2],ds mov dx,offset cmd_block ; Write it out to the driver mov cx,size VH_CMD ; mov ax,4403h ; int 21h ; ret ; Return to Main initialize endp ;***************************************************************************** ; ; Perform the command specified by cmd_keyword. ; ;***************************************************************************** do_command proc near sub bx,bx ; Start at the base of the table mov cx,bx ; docm_l1: mov di,keywords[bx] ; Pick up a keyword pointer or di,di ; Hit the end of the table? jnz docm_l2 ; No - see if they match mov dx,offset bad_kw ; Report an unknown keyword mov ah,9 ; int 21h ; mov dx,offset cmd_keyword[1]; Display the errant keyword mov cl,cmd_keyword[0] ; sub ch,ch ; mov bx,1 ; mov ah,40h ; int 21h ; mov dx,offset bad_kw2 ; Finish out the message mov ah,9 ; int 21h ; mov ax,4c02h ; Exit with error code int 21h ; docm_l2: mov si,offset cmd_keyword ; Point to the keyword they entered mov cl,[si] ; Get the length of it inc cl ; Allow for length byte rep cmpsb ; Is this the one they entered? je docm_l3 ; Yep - call the routine add bx,4 ; Point to next table entry jmp short docm_l1 ; Loop back docm_l3: call keywords[2][bx] ; Call the appropriate routine ret ; Return to Main do_command endp subttl Command keyword handlers page ;***************************************************************************** ; ; Command keyword handlers ; ;***************************************************************************** ;***************************************************************************** ; ; Handle the "?" or "INFO" keyword. ; Display information about the cache. ; ;***************************************************************************** kw_info proc near mov al,5 ; Get the cache info mov word ptr cmd_block.VC_buffer[0],offset cache_flags mov word ptr cmd_block.VC_buffer[2],ds call call_driver ; Get the info test cache_flags,CACHE_INSTALLED ; Is the cache installed? jnz kwin_l1 ; Yep - display its info mov dx,offset no_cache ; Tell 'em it ain't there mov ah,9 ; int 21h ; jmp kwin_exit ; Exit now kwin_l1: mov dx,offset vhversion ; Say what version of VHARD we have mov ah,9 ; int 21h ; mov ax,vhard_ver ; Get the version word push ax ; Save it mov al,ah ; Display major version call disp_byte ; mov dl,'.' ; mov ah,6 ; int 21h ; pop ax ; Display minor version call disp_byte ; mov dx,offset crlf_str ; End the line mov ah,9 ; int 21h ; inc vhard_drive ; Do we have the drive assigned jz kwin_l2 ; Nope - don't know what drive mov dx,offset vhdrive_is ; Tell 'em the drive letter mov ah,9 ; int 21h ; mov dl,vhard_drive ; add dl,'@' ; mov ah,6 ; int 21h ; mov dl,':' ; mov ah,6 ; int 21h ; mov dx,offset crlf_str ; End this line mov ah,9 ; int 21h ; kwin_l2: mov dx,offset cached_at ; Tell 'em where the cache is now mov ah,9 ; int 21h ; mov ax,cache_addr[2] ; call disp_word ; mov dl,':' ; mov ah,6 ; int 21h ; mov ax,cache_addr[0] ; call disp_word ; mov dx,offset crlf_str ; End the line mov ah,9 ; int 21h ; test cache_flags,CACHE_DIRTY ; Is the cache dirty? jz kwin_l3 ; No - just exit mov dx,offset needs_flushing; Tell 'em it needs to be flushed mov ah,9 ; int 21h ; kwin_l3: test cache_flags,CACHE_AUTO ; AUTOflush enabled? jz kwin_exit ; Nope - exit now mov dx,offset auto_enabled ; Tell 'em about it mov ah,9 ; int 21h ; kwin_exit: ret ; Return to caller kw_info endp ;***************************************************************************** ; ; Output the value in AX as 4 hex digits ; ;***************************************************************************** disp_word proc near push ax ; Save the value mov al,ah ; Do the high byte first call disp_byte ; pop ax ; Now, the low byte disp_byte: push ax ; Save the low nybble mov cl,4 ; Move the high nybble down shr al,cl ; call disp_nybble ; Display the nybble pop ax ; Get low nybble back disp_nybble: and al,0fh ; Keep the low nybble add al,90h ; Convert to ASCII hex digit daa ; adc al,40h ; daa ; mov dl,al ; Send it to the display mov ah,6 ; int 21h ; ret ; Return to caller disp_word endp ;***************************************************************************** ; ; Handle the "ON" keyword ; ;***************************************************************************** kw_on proc near mov ah,51h ; Get our PSP int 21h ; mov es,bx ; mov bx,768 ; Need 12K at least mov ah,4ah ; int 21h ; jnc kwon_l1 ; If we got it, install mov dx,offset no_memory ; Report insufficient memory mov ah,9 ; int 21h ; mov byte ptr ax_value[0],5 ; Exit code jmp short kwon_exit ; Exit now kwon_l1: mov word ptr cmd_block.VC_buffer[0],0 ; Set cache ptr mov word ptr cmd_block.VC_buffer[2],es ; to PSP:0 mov al,1 ; Enable the cache call call_driver ; jnc kwon_l2 ; If we did, continue call report_error ; Report the error jmp short kwon_exit ; Exit now kwon_l2: mov byte ptr ax_value[1],31h; Change exit fn to TSR exit mov dx_value,768 ; Set DX to # of paragraphs needed mov ah,30h ; Get our DOS version int 21h ; cmp al,3 ; At least 3.x? jb kwon_exit ; Nope - no auto-flush available mov ax,1000h ; See if SHARE is installed int 2fh ; or al,al ; Is it? jz kwon_exit ; Nope - no auto-flush mov al,4 ; Enable cache auto-flush call call_driver ; kwon_exit: ret ; Return to caller kw_on endp ;***************************************************************************** ; ; Handle the "OFF" keyword. ; ;***************************************************************************** kw_off proc near mov al,0 ; Disable the cache call call_driver ; jnc kwof_l1 ; If no error, release the memory call report_error ; Report the error jmp short kwof_exit ; Exit now kwof_l1: ; ; VHARDCTL set our VC_buffer to point to the existing cache ; mov es,word ptr cmd_block.VC_buffer[2] ; Get segment to free mov ah,49h ; Function to release memory int 21h ; Get rid of the memory kwof_exit: ret ; Return to caller kw_off endp ;***************************************************************************** ; ; Handle the "MANUAL" keyword ; ;***************************************************************************** kw_manual proc near mov al,3 ; Disable auto-flush call call_driver ; jnc kwmn_exit ; Exit if no error call report_error ; Report the error kwmn_exit: ret ; Return to caller kw_manual endp ;***************************************************************************** ; ; Handle the "AUTO" keyword ; ;***************************************************************************** kw_auto proc near mov ah,30h ; Get DOS version int 21h ; cmp al,3 ; Is it at least 3.x? jb kwau_err1 ; Nope - can't do autoflush mov ax,1000h ; See if SHARE is installed int 2fh ; cmp al,0 ; Is it? jz kwau_err2 ; Nope - report error mov al,4 ; Enable auto-flush call call_driver ; jnc kwau_exit ; Exit if it went call report_error ; Report an error kwau_exit: ret ; Return to caller ; kwau_err1: mov dx,offset bad_dos_ver ; jmp short kwau_err3 ; kwau_err2: mov dx,offset no_share ; kwau_err3: mov ah,9 ; Display the error message int 21h ; mov ax,4c04h ; Exit with appropriate error code int 21h ; kw_auto endp ;***************************************************************************** ; ; Handle the "FLUSH" keyword ; ;***************************************************************************** kw_flush proc near mov al,2 ; Send the "Flush Cache" command call call_driver ; jnc kwfl_exit ; Exit if it went mov byte ptr ax_value[0],1 ; Set exit code call report_error ; Report the error kwfl_exit: ret ; Return to caller kw_flush endp ;***************************************************************************** ; ; Call VHARDCTL. ; ; Call with command code in AL. ; ; Returns with CF = 1 if VC_status <> STS_OK ; ;***************************************************************************** call_driver proc near mov cmd_block.VC_cmd_code,CMD_CACHE ; It's a cache command mov cmd_block.VC_track,al ; Set the subcommand mov cmd_block.VC_status,STS_OK ; Init to "OK" status mov ax,4403h ; IOCTL write function mov dx,offset cmd_block ; Point to the data to write mov cx,size VH_CMD ; Number of bytes to write mov bx,vhctl_handle ; Handle to write to int 21h ; Do it cmp cmd_block.VC_status,STS_OK ; Did it fly? je clld_ok ; Yes - return CF=0 stc ; Return error flag jmp short clld_exit ; Exit now clld_ok: clc ; No error clld_exit: ret ; Return to caller call_driver endp ;***************************************************************************** ; ; Common error-reporting routine ; ;***************************************************************************** report_error proc near assume ds:vhcache_data mov bl,cmd_block.VC_status ; Get the return status cmp bl,STS_BAD_ERROR ; See if it was an unknown error jne rpte_l1 ; No - point to proper error message mov si,offset unk_err ; Point to "Unknown error" message jmp short rpte_l2 ; Continue rpte_l1: sub bh,bh ; Make the error code an offset shl bx,1 ; mov si,error_messages[bx] ; Point to the error message rpte_l2: mov dx,offset err_prefix ; mov ah,9 ; int 21h ; mov dx,si ; mov ah,9 ; int 21h ; mov dx,offset crlf_str ; mov ah,9 ; int 21h ; mov byte ptr ax_value[0],1 ; Set exit code ret ; Return to caller report_error endp vhcache_code ends end start