home *** CD-ROM | disk | FTP | other *** search
-
- title Prepare VHARD floppies
- subttl Prologue
- page 60,132
-
- comment {
-
- ******************************************************************************
-
- File VHPREP.ASM
-
- Author:
- Aaron L. Brenner
-
- BIX mail address albrenner
- GEnie address A.BRENNER
-
- This program is hereby released to the public domain.
-
- Purpose:
- Prepare floppy diskettes for use with VHARD.
-
- This consists of the following:
-
- 1) Format the floppies to 10 sectors per track, 40 tracks (resulting
- in a capacity of 800K per diskette).
- 2) Write the VHARD boot sector to each disk containing, along with
- boot code, a disk ID and number.
- 3) Write a DOS boot sector, 2 FATs, and root directory to the first
- disk.
-
- All disk operations are performed through VHARDCTL, the character
- device driver installed with VHARD.
-
- Errorlevel returned:
- 0 All is well
- 1 VHARD.SYS is not installed
-
- Revision history:
- 1.00 07/11/90 ALB Created.
-
- ******************************************************************************
-
- endcomment {
-
- subttl Included files
- page
-
- include dd_defs.inc
- include vhard.inc
-
- subttl Program data and stack
- page
-
- vhprep_data segment para
-
- ID_to_use db 8 dup(' ') ; ID to use for the diskettes
- disk_num db 0ffh ; Number for each diskette
- track_buf db 512 * 10 dup(0) ; Track buffer for reading and writing
- drive_num db 0 ; The drive assigned to VHARD
- vhard_vnum dw 0 ; Version of VHARD
- VHARD_BPB DOS_BPB <> ; BPB gotten from VHARD
-
- dw 81h ; Pointer to our command tail
- our_PSP dw 0 ; Our PSP segment
-
- ;
- ; This block is used to pass commands to VHPREP
- ;
- command_blk VH_CMD <>
-
- vhctl_name db 'VHARDCTL',0 ; Name of control driver for VHARD
- vhctl_handle dw 0 ; Handle for VHARDCTL
- not_installed db 13,10,'The VHARD driver is not installed.',13,10,'$'
- insert_disk db 13,10,'Put a blank diskette in drive A:, then press'
- db ' a key $'
- label_disk db 'Label this diskette $'
- disk_bad db 7,13,10,'This diskette is unusable!',13,10,'$'
- crlf_str db 13,10,'$'
-
- err_prefix db 7,'Error: $'
-
- err0 db 'spurious error message$'
- err1 db 'drive/adapter failed or no disk in drive$'
- err2 db 'seek operation failed$'
- err3 db 'disk adapter failed$'
- err4 db 'CRC error$'
- err5 db 'attempt to DMA across segment boundary$'
- err6 db 'DMA overrun$'
- err7 db 'sector not found$'
- err8 db 'diskette is write-protected$'
- err9 db 'address mark not found$'
- err10 db 'invalid BIOS command$'
- err11 db 'internal command error$'
- err0ff db 'unknown BIOS error code$'
-
- error_msgs dw err0, err1, err2, err3, err4, err5, err6, err7, err8
- dw err9, err10, err11, err0, err0, err0ff
-
- vhprep_data ends
-
-
- vhprep_stack segment word stack
-
- dw 256 dup(0)
-
- vhprep_stack ends
-
-
- ;*****************************************************************************
- ;
- ; This gets written to the actual boot sector of each diskette. As you can
- ; see, it just spits out a message, waits for a key, then tries to IPL again.
- ;
- ;*****************************************************************************
- boot_code_seg segment para
-
- assume cs:boot_code_seg, ds:boot_code_seg
-
- org 0
- boot_code proc near
-
- jmp short boot_msg_disp ; Jump to message display code
- db 17 dup(?) ; Place keeper for disk ID & number
- boot_msg_disp:
- cld ; Make sure of direction
- call do_display ; Do the display
- db 7,'This is NOT a bootable diskette!',13,10
- db 'Put a different disk in the drive, and press a key to'
- db ' try again',13,10,0
- do_display:
- pop si ; Point to the string to display
- ddsp_l1:
- lods byte ptr cs:[si] ; Get a byte
- or al,al ; End of string yet?
- jz ddsp_l2 ; Yep - just hang up now
- mov ah,14 ; BIOS "Write TTY" function
- int 10h ;
- jmp short ddsp_l1 ; Loop back for the rest
- ddsp_l2:
- sub ah,ah ; Get a key
- int 16h ;
- int 19h ; Try to IPL again
- jmp $ ; Hang up now
-
- boot_code_end label byte
-
- boot_code endp
-
- boot_code_seg ends
-
-
- subttl Start of program code
- page
-
- vhprep_code segment
-
- assume cs:vhprep_code, ds:vhprep_data, es:vhprep_data, ss:vhprep_stack
-
-
- start proc
-
- call initialize ; Set things up
- call do_prep ; Do the preparation
- call terminate ; Do program cleanup
- mov ax,4c00h ;
- int 21h ;
-
- start endp
-
-
- ;*****************************************************************************
- ;
- ; Program initialization.
- ;
- ; Make sure the VHARDCTL driver is present, and get driver info from it.
- ;
- ;*****************************************************************************
- initialize proc near
-
- mov ax,vhprep_data ; Get our data segment
- mov ds,ax ;
- mov our_PSP,es ; Save our PSP segment
- mov es,ax ;
- mov dx,offset vhctl_name ; Try to open VHARDCTL, read/write
- mov ax,3d02h ;
- int 21h ;
- jnc init_l1 ; If it opened, make sure it's a dev
- init_noway:
- mov dx,offset not_installed ; Complain that it isn't there
- mov ah,9 ;
- int 21h ;
- mov ax,4c01h ; Exit with errorlevel of 1
- int 21h ;
- init_l1:
- mov vhctl_handle,ax ; Save the handle for other ops
- mov bx,ax ; Get the handle for IOCTL call
- mov ax,4400h ; Get info on this guy
- int 21h ;
- test dl,80h ; Is this a device?
- jz init_noway ; Nope - no way we're doing anything
- mov command_blk.VC_cmd_code,CMD_GETDATA
- mov word ptr command_blk.VC_buffer[0],offset drive_num
- mov word ptr command_blk.VC_buffer[2],ds
- mov ax,4403h ; Get data from VHARDCTL
- mov dx,offset command_blk ;
- mov cx,size VH_CMD ;
- int 21h ;
- call get_cmdline_parms ; Get a parameters from the cmd line
- cmp byte ptr ID_to_use[0],' '; Did they supply an ID?
- jne init_exit ; Yep - don't change it
- mov ah,0 ; Get timer count from BIOS
- int 1ah ; Returns CX:DX
- mov ax,'HV' ; Set up disk ID
- mov word ptr ID_to_use[0],ax;
- mov ax,cx ; Use the time as part of the ID
- mov di,offset ID_to_use[2] ;
- call store2digits ;
- mov al,dh ;
- call store2digits ;
- mov al,dl ;
- call store2digits ;
- init_exit:
- ret ; Return to Main
-
- initialize endp
-
-
- ;*****************************************************************************
- ;
- ; Get any command line parameters
- ;
- ; The only parameters allowed are a disk ID and a disk number.
- ;
- ;*****************************************************************************
- get_cmdline_parms proc near
-
- push es ; Save it for this
- les si,dword ptr our_PSP[-2]; Point to the command tail
- call skip_spaces ; Skip any whitespace
- mov cx,8 ; Max to copy
- mov di,offset ID_to_use ;
- gcmp_l1:
- lods byte ptr es:[si] ; Get a byte
- cmp al,' ' ; Whitespace?
- je gcmp_l3 ; Yep - stop copying
- cmp al,9 ;
- je gcmp_l3 ;
- cmp al,0dh ; End of it?
- je gcmp_exit ; Yep - exit
- cmp al,'a' ; Lower case?
- jb gcmp_l2 ; No - never mind
- cmp al,'z' ;
- ja gcmp_l2 ;
- xor al,20h ; Make it upper case
- gcmp_l2:
- jcxz gcmp_l1 ; Don't store if ID is full
- mov [di],al ; Save the byte
- inc di ; Point to next spot
- dec cx ; Knock off the count
- jmp gcmp_l1 ; Loop back
- gcmp_l3:
- call skip_spaces ; Skip any other whitespace
- sub bl,bl ; Clear accumulator
- gcmp_l4:
- lods byte ptr es:[si] ; Pick up a byte
- cmp al,'0' ; Valid digit?
- jb gcmp_l5 ; Nope - stop now
- cmp al,'9' ;
- ja gcmp_l5 ;
- sub al,'0' ; Make digit binary
- mov bh,bl ; Multiply current value by 10
- shl bh,1 ; by (BL * 2) + (BL * 8)
- shl bl,1 ;
- shl bl,1 ;
- shl bl,1 ;
- add bl,al ; Add in new digit
- jmp short gcmp_l4 ; Loop back
- gcmp_l5:
- cmp bl,12 ; Make sure it's legal
- ja gcmp_exit ;
- mov disk_num,bl ; Save the number
- gcmp_exit:
- pop es ;
- ret ; Return to initialization
-
- get_cmdline_parms endp
-
-
- ;*****************************************************************************
- ;
- ; Skip whitespace characters at ES:SI
- ;
- ;*****************************************************************************
- skip_spaces proc near
-
- sksp_l1:
- mov al,es:[si] ; Get a byte
- cmp al,' ' ; Whitespace?
- je sksp_l2 ; Yep - skip it
- cmp al,9 ;
- jne sksp_exit ; No - exit now
- sksp_l2:
- inc si ; Skip this character
- jmp short sksp_l1 ; Loop back
- sksp_exit:
- ret ; Return to caller
-
- skip_spaces endp
-
-
- ;*****************************************************************************
- ;
- ; Convert AL to 2 hex digits, storing them at DI.
- ;
- ;*****************************************************************************
- store2digits proc near
-
- push ax ; Save it for a second
- mov cl,4 ; Move high nybble down
- shr al,cl ;
- call store_nybble ; Store it as ASCII
- pop ax ; Get low nybble back
- store_nybble:
- and al,0fh ; Just keep low nybble
- add al,90h ; Convert to ASCII hex
- daa ;
- adc al,40h ;
- daa ;
- stosb ; Store digit
- ret ; Return to caller
-
- store2digits endp
-
-
- ;*****************************************************************************
- ;
- ; Take care of any cleanup prior to returning to DOS.
- ; All we do is close the handle for VHARDCTL.
- ;
- ;*****************************************************************************
- terminate proc near
-
- mov bx,vhctl_handle ; Get the handle
- mov ah,3eh ; Close it
- int 21h ;
- ret ; Return to Main
-
- terminate endp
-
-
- ;*****************************************************************************
- ;
- ; Do the actual preparation
- ;
- ; Format disk 0, writing a DOS boot sector, 2 copies of the FAT, and an
- ; empty root directory (empty except for a volume label that is the disk ID).
- ;
- ; Once disk 0 is taken care of, just format the rest of the disks.
- ;
- ;*****************************************************************************
- do_prep proc near
-
- cmp disk_num,0ffh ; Did they specify a disk?
- je dopr_l2 ; No - do all disks
- cmp disk_num,0 ; Is it the first disk?
- jne dopr_l1 ; No - do a normal disk
- call do_first_disk ; Do just the first disk
- jmp short dopr_exit ; Exit
- dopr_l1:
- call do_one_disk ; Just do this disk
- jmp short dopr_exit ;
- dopr_l2:
- mov disk_num,0 ;
- call do_first_disk ; Set up the first disk
- mov cx,12 ; 12 more to do
- mov disk_num,1 ; Starting with disk 1
- dopr_l3:
- call do_one_disk ; Do this disk
- inc disk_num ; Set for next one
- loop dopr_l3 ; Loop for all 12 disks
- dopr_exit:
- ret ; Return to Main
-
- do_prep endp
-
-
- ;*****************************************************************************
- ;
- ; Prepare the first diskette. This requires special treatment because it also
- ; contains the DOS boot sector, 2 copies of a FAT, and a root directory.
- ;
- ;*****************************************************************************
- do_first_disk proc near
-
- dfdk_l1:
- call format_disk ; Format the first disk
- call copy_boot_sect ; Copy the boot sector to track buf
- mov di,offset track_buf[512].DBS_BPB
- mov si,offset VHARD_BPB
- mov cx,size DOS_BPB
- rep movsb
- mov word ptr track_buf[512 * 2],0fffch ; Set up 2 empty FATs
- mov track_buf[(512 * 2) + 2],0ffh ;
- mov word ptr track_buf[6 * 512],0fffch ;
- mov track_buf[(6 * 512) + 2],0ffh ;
- sub ax,ax ;
- call write_track ; Write it
- jc dfdk_err ; If unable, complain
- call clear_track_buf ; Wipe it clean
- mov di,offset track_buf ; Point to first root dir entry
- mov si,offset ID_to_use ; Use the disk ID as the vol label
- mov cx,4 ;
- rep movsw ;
- mov al,' ' ; Fill it out with spaces
- stosb ;
- stosb ;
- stosb ;
- mov al,8 ; Attribute byte for volume label
- stosb ;
- mov cx,5 ; Fill 10 reserved bytes w/0
- sub al,al ;
- rep stosw ;
- mov ah,2ch ; Get time from DOS
- int 21h ;
- mov ah,ch ; Get the hour
- shl ah,1 ; Put it in the high 5 bits
- shl ah,1 ;
- shl ah,1 ;
- mov ch,0 ; Make the minutes a word
- mov bx,cx ; Into a temp register
- mov cl,5 ; Move the minutes into middle 6 bits
- shl bx,cl ;
- or ax,bx ; Add to time
- shr dh,1 ; Make seconds 2-sec intervals
- or al,dh ; Finish with that
- stosw ; Put the timestamp into the dir entry
- mov ah,2ah ; Get the date from DOS
- int 21h ;
- sub cx,1980 ; Make the year the way DOS wants
- mov ax,cx ;
- mov cl,7 ; Move to high 7 bits
- ror ax,cl ;
- mov bl,dh ; Get the month
- sub bh,bh ; as a word
- mov cl,5 ; Put it in the middle
- shl bx,cl ;
- or ax,bx ; Add to date
- or al,dl ; Add the days
- stosw ; Put it in the dir entry
- mov ax,100h ; Write track 0, head 1
- call write_track ;
- jc dfdk_err
- call show_label ; Tell 'em how to label it
- dfdk_exit:
- ret ; Return to caller
- ;
- dfdk_err:
- call report_error ; Complain about the error
- mov dx,offset disk_bad ; Let 'em know the disk is bad
- mov ah,9 ;
- int 21h ;
- jmp dfdk_l1
-
- do_first_disk endp
-
-
- ;*****************************************************************************
- ;
- ; Prepare a disk other than the first one. Just format it and write a boot
- ; sector.
- ;
- ;*****************************************************************************
- do_one_disk proc near
-
- dodk_l1:
- call format_disk ; Format this disk
- call copy_boot_sect ; Copy the boot sector to track_buf
- mov al,0 ; Write this track
- call write_track ;
- jnc dodk_exit ;
- call report_error ; Complain about the error
- mov dx,offset disk_bad ; Let 'em know the disk is bad
- mov ah,9 ;
- int 21h ;
- jmp short dodk_l1
- dodk_exit:
- call show_label ; Tell 'em what the label is
- ret ; Return to caller
-
- do_one_disk endp
-
-
- ;*****************************************************************************
- ;
- ; Copy the boot sector into the first sector of the track buffer
- ;
- ;*****************************************************************************
- copy_boot_sect proc near
-
- save cx, si, di
- call clear_track_buf ; Wipe out our track buffer
- push ds ; Save Our Segment
- mov cx,boot_code_seg ; Point to our boot code
- mov ds,cx ;
-
- assume ds:boot_code_seg
-
- mov si,offset boot_code ; Point to the boot code
- mov cx,offset boot_code_end ; Number of bytes to copy
- mov di,offset track_buf ; Where to put it
- rep movsb ; Copy boot code to track buffer
- pop ds ; Get our segment back
-
- assume ds:vhprep_data
-
- mov si,offset ID_to_use ; Point to disk ID
- mov di,offset track_buf.BS_disk_id
- mov cx,4 ;
- rep movsw ; Copy disk ID to boot sector
- mov cl,disk_num ; Copy disk # to boot sector
- mov track_buf.BS_disk_num,cl;
- sub ax,ax ; Write track 0/head 0
- call write_track ;
- restore
- ret ; Return to caller
-
- copy_boot_sect endp
-
-
- ;*****************************************************************************
- ;
- ; Fill the track buffer with 0s.
- ;
- ;*****************************************************************************
- clear_track_buf proc near
-
- save ax, cx, di
- mov cx,512 * 5 ; Number of words to clear
- mov di,offset track_buf ; What to clear
- sub ax,ax ; Fill with 0
- cld ; Make sure of direction
- rep stosw ; Fill the buffer
- restore
- ret ; Return to caller
-
- clear_track_buf endp
-
-
- ;*****************************************************************************
- ;
- ; Prompt for a disk, then format all tracks.
- ;
- ;*****************************************************************************
- format_disk proc near
-
- save ax, cx, dx
- fmtd_l1:
- mov dx,offset insert_disk ; Display the prompt
- mov ah,9 ;
- int 21h ;
- mov ax,0c08h ; Get a key
- int 21h ;
- or al,al ; Fn key?
- jnz fmtd_l2 ; Nope - continue
- mov ah,8 ; Read the second character
- int 21h ;
- fmtd_l2:
- mov dx,offset crlf_str ; Newline
- mov ah,9 ;
- int 21h ;
- sub ax,ax ; Start with track 0
- ; inc ah ;
- mov cx,40 ; 40 tracks to do
- fmtd_l3:
- call format_track ; Format head 0 of the track
- jc fmtd_err ; Complain on error
- xor ah,1 ; Other head
- call format_track ;
- jc fmtd_err ; Complain on error
- xor ah,1 ; Head 0 again
- inc al ; Next cylinder
- loop fmtd_l3 ; Loop for the whole disk
- restore
- ret ; Return to caller
- fmtd_err:
- ;
- ; An error occurred during the format. Report the error, let them know the
- ; disk is unusable, then prompt for another.
- ;
- call report_error ; Report the error
- mov dx,offset disk_bad ; Let 'em know the disk is bad
- mov ah,9 ;
- int 21h ;
- jmp fmtd_l1 ; Try with another disk
-
- format_disk endp
-
-
- ;*****************************************************************************
- ;
- ; Issue a format command for the track in AL/head in AH
- ;
- ;*****************************************************************************
- format_track proc near
-
- save ax, bx, cx, dx, di
- ;
- ; Before we can do the format, we need to set up the track buffer with the
- ; array of format parameters. Each entry in the array is 4 bytes, structured:
- ; byte 0 track
- ; byte 1 head
- ; byte 2 sector
- ; byte 3 sector size (2 in this case)
- ;
- mov di,offset track_buf ; Point to the buffer
- mov cx,10 ; 10 entries
- mov bx,201h ; Starting with sector 1
- fmtt_l1:
- stosb ; Store the track
- mov [di],ah ; Store the head
- inc di ;
- mov [di],bl ; Now the sector number
- inc bl ;
- inc di ;
- mov byte ptr[di],2 ; Sector size
- inc di ;
- loop fmtt_l1 ; Loop for all entries
- mov command_blk.VC_cmd_code,CMD_FORMAT ; Command code
- ror ah,1 ; Put the head in the high bit
- or al,ah ; Add to track number
- mov command_blk.VC_track,al ; Pass it in the command block
- mov word ptr command_blk.VC_buffer[0],offset track_buf
- mov word ptr command_blk.VC_buffer[2],ds
- mov dx,offset command_blk ; Point to the block
- mov ax,4403h ; IOCTL Write to the VHARDCTL device
- mov bx,vhctl_handle
- mov cx,size VH_CMD
- int 21h
- cmp command_blk.VC_status,STS_OK + 1 ; Get the status
- cmc ; Set CF to 1 if error
- restore
- ret ; Return to caller
-
- format_track endp
-
-
- ;*****************************************************************************
- ;
- ; Write track_buf to the track in AL/head in AH
- ;
- ;*****************************************************************************
- write_track proc near
-
- save ax, bx, cx, dx
- mov command_blk.VC_cmd_code,CMD_WRITE
- ror ah,1
- or al,ah
- mov command_blk.VC_track,al
- mov word ptr command_blk.VC_buffer[0],offset track_buf
- mov word ptr command_blk.VC_buffer[2],ds
- mov dx,offset command_blk
- mov ax,4403h
- mov bx,vhctl_handle
- mov cx,size VH_CMD
- int 21h
- cmp command_blk.VC_status,STS_OK + 1
- cmc
- restore
- ret
-
- write_track endp
-
- ;*****************************************************************************
- ;
- ; Report an error based on the status byte in the command block.
- ;
- ;*****************************************************************************
- report_error proc near
-
- save ax, bx, dx
- mov dx,offset err_prefix ; Display the error message prefix
- mov ah,9 ;
- int 21h ;
- mov bl,command_blk.VC_status; Get returned status
- sub bh,bh ; Make it a word
- shl bx,1 ; Make it a word offset
- mov dx,error_msgs[bx] ; Get the appropriate error message
- mov ah,9 ;
- int 21h ;
- mov dx,offset crlf_str ; Newline
- mov ah,9 ;
- int 21h ;
- restore
- ret ; Return to caller
-
- report_error endp
-
-
- ;*****************************************************************************
- ;
- ; Tell the user what label to put on this diskette
- ;
- ;*****************************************************************************
- show_label proc near
-
- save ax, bx, cx, dx
- mov dx,offset label_disk ; Tell them to label the disk
- mov ah,9 ;
- int 21h ;
- mov dx,offset ID_to_use ; Tell them what to label it with
- mov cx,8 ;
- mov bx,1 ;
- mov ah,40h ; Use IOCTL Write to do it
- int 21h ;
- mov ah,2 ;
- mov dl,' ' ;
- int 21h ;
- mov ah,2 ;
- mov dl,'#' ;
- int 21h ;
- mov al,disk_num ; Display the disk number
- aam ;
- or ax,3030h ;
- push ax ;
- mov dl,ah ;
- mov ah,2 ;
- int 21h ;
- pop dx ;
- mov ah,2 ;
- int 21h ;
- mov dx,offset crlf_str ; Finish off with a newline
- mov ah,9 ;
- int 21h ;
- restore
- ret ; Return to caller
-
- show_label endp
-
-
- vhprep_code ends
-
-
- end start
-