Metropoli BBS
VIEWER: park.c MODE: TEXT (ASCII)
/*
 * A configurable disk parking utility.
 *
 * Copyright 1991-1995 Dave Dunfield
 * All rights reserved.
 *
 * Permission granted for personal (non-commercial) use only.
 *
 * Compile command: cc park -fop
 */
#include <stdio.h>

	int parms[12] = 2;		/* Default, 2 drives park via BIOS */

	extern char PSP[];		/* To determine address of COM start */

/*
 * Main program - parse arguments, park drives
 */
main(argc, argv)
	int argc;
	int *argv[];
{
	int drive, cyl, flag;
	FILE *fp;

	flag = cyl = 0;
	for(drive = 1; drive < argc; ++drive) switch(*argv[drive]) {
		case '?-' :		/* Help request */
		case '?'  :
			abort("\nUse: park [-s cyl1 cyl2 ...]\n\nCopyright 1991 Dave Dunfield\nAll rights reserved.\n");
		case 's-' :		/* Setup command */
		case 'S-' :
			flag = -1;
			break;
		default:
			if(!isdigit(*(char*)argv[drive]))
				abort("Invalid operand.");
			parms[parms[0] = ++cyl] = atoi(argv[drive]); }

	if(flag) {				/* Setup mode */
		putc('\n', stdout);
		for(drive=1; drive <= *parms; ++drive) {
			printf("Park drive %u ", drive);
			if(flag = parms[drive])
				printf("at cylinder %u\n", flag);
			else
				printf("via BIOS\n"); }
		if(cyl) {			/* Set options */
			fp = fopen("PARK.COM", "bwvq");
			fput(0x100, PSP-0x102, fp);
			fclose(fp);
			printf("\nPARK.COM written!\n"); }
		return; }

	printf("System shutdown in progress...\n\n");

	asm " MOV AH,0Dh";	/* Disk reset command */
	asm " INT 21h";		/* Ask DOS */

	for(drive = 1; drive <= *parms; ++drive) {
		if(!test_disk(drive)) {
			printf("Drive %u ", drive);
			if(!(cyl = parms[drive]))
				cyl = max_cyl(drive);
			flag = seek_disk(drive, cyl);
			printf("parked at cylinder %u", cyl);
			if(flag)
				printf(" - *flag %02x*", flag);
			putc('\n', stdout); } }

	printf("\nTurn system power OFF now!!! ");

	while(getc(stdin) != '\n');
}

/*
 * Recalibrate the fixed disk (also determine its existance)
 */
test_disk(drive) asm
{
		MOV		DL,4[BP]	; Get drive id
		ADD		DL,7fh		; Offset to drive
		MOV		AH,11h		; Recalibrate
		INT		13h			; Ask BIOS
		MOV		AL,AH		; Set low value
		XOR		AH,AH		; Zero high
}

/*
 * Get the maximum cylinder number for drive
 */
max_cyl(drive) asm
{
		MOV		DL,4[BP]	; Get drive id
		ADD		DL,7fh		; Convert ID
		MOV		AH,08h		; Get parms function
		INT		13h			; Ask BIOS
		MOV		AL,CH		; Get LOW byte of result
		MOV		AH,CL		; Get HIGH two bits
		MOV		CL,6		; Shift 6 bits
		SHR		AH,CL		; Do the shift
}

/*
 * Seek to specified cylinder on fixed disk
 */
seek_disk(drive, cyl) asm
{
		MOV		DL,6[BP]	; Get drive id
		ADD		DL,7fh		; Convert to BIOS id
		MOV		AL,5[BP]	; Get high cylinder
		MOV		CL,6		; Shift 6 bits
		SHL		AL,CL		; Perform shift
		INC		AL			; Sector 1
		MOV		CL,AL		; Set high bits
		MOV		CH,4[BP]	; Get LOW cylinder
		XOR		DH,DH		; Head zero
		MOV		AH,0Ch		; Function 13 SEEK
		INT		13h			; Ask BIOS
		MOV		AL,AH		; Put RC in lower byte
		XOR		AH,AH		; Zero upper byte
}
[ RETURN TO DIRECTORY ]