$COMPACT(ramdrv -CONST IN CODE- HAS
$        ramdrv,
$		 xram;
$        EXPORTS
$		 ram$init$io,
$		 ram$finish$io,
$		 ram$queue$io,
$		 ram$cancel$io)

ramdrv:
DO;

$include(/rmx386/inc/rmxplm.ext)
$include(/rmx386/inc/error.lit)
$include(/rmx386/inc/common.lit)
$include(/rmx386/inc/io.lit)
$include(lddinfo.lit)

ram$init$io: PROCEDURE(duib$p,ddata$t$p,status$p) EXTERNAL;
	DECLARE
		duib$p				POINTER,
		ddata$t$p			POINTER,
		status$p			POINTER;
END ram$init$io;

ram$finish$io: PROCEDURE(duib$p, ddata$t) EXTERNAL;
	DECLARE
		duib$p	 			POINTER,
		ddata$t				TOKEN;
END ram$finish$io;

ram$cancel$io: PROCEDURE(conn$t, duib$p, ddata$t) EXTERNAL;
	DECLARE
		conn$t				TOKEN,
		duib$p	 			POINTER,
		ddata$t				TOKEN;
END ram$cancel$io;

ram$queue$io: PROCEDURE(iors$t, duib$p, ddata$t) EXTERNAL;
	DECLARE
		iors$t				TOKEN,
		duib$p				POINTER,
		ddata$t				TOKEN;
END ram$queue$io;

DECLARE
	duib					DUIB$STRUCT,
	dinfo					LOADABLE$CUSTOM$DINFO,
	uinfo					STRUCTURE(
		device$address		DWORD,
		write$protect		BYTE);


DECLARE
		co$conn$t			TOKEN,
		file$conn$t			TOKEN,
		root$t				TOKEN,
		HI$job$$t			TOKEN,
		parent$job$t		TOKEN,
		input$buff(128)		BYTE,
		status				WORD,
		bytes$read			WORD,
		del					BYTE, /* Delimeter returned by get$argument */
		disk$size			DWORD,
		file$info	STRUCTURE(
			owner(15)		BYTE,
			length			DWORD,
			type			BYTE,
			owner$access	BYTE,
			world$access	BYTE,
			create$time		DWORD,
			last$mod$time	DWORD,
			reserved(20)	BYTE),
		ram$p				POINTER,
		exception$info		STRUCTURE(
			entry$point			POINTER,
			mode				BYTE),
		MIN$DISK$SIZE		LITERALLY	'64',
		NO$BUFFERS			LITERALLY	'0',
		RT_PREN				LITERALLY	'29H',
		ROOT_JOB			LITERALLY	'3',
		PARENT_JOB			LITERALLY	'1',
		NO$EXCEPTIONS		LITERALLY	'00',
		RAM0(*)				BYTE DATA(52H,41H,4DH,30H,20H,20H,20H,
									  20H,20H,20H,20H,20H,20H,20H),
		sign$on$msg(*)		BYTE	DATA(CR,LF,
		'                iRMX III Loadable RAM Disk Front End',CR,LF,LF),
		illegal$file$msg(*)	BYTE DATA(CR,LF,
			'File Size Does Not Match specified RAM Disk Size',CR,LF),
		badparm$msg(*)		BYTE DATA(CR,LF,
			'Invalid Command Tail',CR,LF), /* Unknown parameter msg */
		illegal$size$msg(*)		BYTE DATA(CR,LF,
			'Invalid RAM Disk Size Specification',CR,LF),
		missing$parm$msg(*)		BYTE DATA(CR,LF,
			'Missing input parameter',CR,LF), /* missing input parm msg */
		usage$msg(*)		BYTE DATA(CR,LF,
	'USAGE: ramdrv( (RAM Disk Size in KBytes(Decimal > 63)),',CR,LF,
	'              <initial contents file pathname>)',CR,LF);

$subtitle('CONVERT')
convert: PROCEDURE(char$p) DWORD REENTRANT;

	DECLARE
		char$p						POINTER,
		char	BASED	char$p	(1)	BYTE,
		value						DWORD,
		i							BYTE;

	value = 0;
	DO i = 1 to char(0);
		IF (char(i) < 30H) OR (char(i) > 39H) THEN
			RETURN 0;
		value = (value * 10) + (char(i) - 30H);
	END;
	RETURN value;

END convert;

$subtitle('append$string')
append$string: PROCEDURE(str1$p, str2$p) REENTRANT;

	DECLARE
		str1$p						POINTER,
		str2$p						POINTER,
		str1	BASED	str1$p(1)	BYTE,
		str2	BASED	str2$p(1)	BYTE,
		i							BYTE,
		j							BYTE;

	j = str1(0);
	DO i = 1 to str2(0);
		str1(j+i) = str2(i);
	END;
	str1(0) = str1(0) + str2(0);

END append$string;

$subtitle('Check Exception')
check$exception: PROCEDURE(exception, info$p) REENTRANT;

	DECLARE
			exception				WORD,
			info$p					POINTER,
			info	BASED	info$p	STRUCTURE(
				count				BYTE,
				char(1)				BYTE),
			exc$buf					STRUCTURE(
				count				BYTE,
				char(80)			BYTE),
			dummy					WORD;

	IF exception <> E$OK THEN
	DO;
		CALL dq$decode$exception(exception, @exc$buf, @dummy);
		CALL dq$write(co$conn$t, @(CR,LF), 2, @dummy);
		CALL dq$write(co$conn$t, @exc$buf.char, exc$buf.count, @dummy);
		CALL dq$write(co$conn$t, @(': '), 2, @dummy);
		IF info$p <> NIL THEN
			CALL dq$write(co$conn$t, @info.char, info.count, @dummy);
		CALL dq$write(co$conn$t, @(CR,LF), 2, @dummy);

		CALL rq$delete$job (SELECTOR$OF(NIL), @status);

		CALL rq$suspend$task(SELECTOR$OF(NIL),@status);	/* if all else fails */
	END;

END check$exception;


/*
 *		MAIN PROGRAM
 */

	file$conn$t = SELECTOR$OF(NIL);

	/*
	 *	Turn off exceptions
	 */

	exception$info.mode = NO$EXCEPTIONS;
	CALL rq$set$exception$handler( @exception$info, @status);

	/*
	 * Get the first argument.  The first one should be the name
	 * of this program.
	 */

	del = dq$get$argument(@input$buff, @status );

	/*
	 * Create a log file for the program 
	 */

	IF status = E$OK THEN
	DO;
		/* log file name = <prog name>.log */

		CALL append$string (@input$buff, @(4,'.log')); 
	END;
	ELSE
	DO;
		input$buff(0) = 0;
		CALL append$string (@input$buff, @(16,'/work/ramdrv.log')); 
	END;

	/*
	 * Create a connection to log and open it for writing only.
	 */

	co$conn$t = dq$create(@input$buff, @status );

	CALL dq$open( co$conn$t, WRITE$ONLY, NO$BUFFERS, @status );

	CALL dq$write(co$conn$t,@sign$on$msg,LENGTH(sign$on$msg),@status);
	CALL check$exception(status,NIL);

	/*
	 * Get the arguments.  The first one should be the name
	 * of this program and has already been received.
	 */

	/*
	 * If the delimeter is a CR or LF then there are no parameters.
	 * This is an error so print out the usage message.
	 */

	IF (del = CR) OR (del = LF) THEN
	DO;
		CALL dq$write(co$conn$t,@usage$msg,LENGTH(usage$msg),@status);
		GOTO exit;
	END;
	ELSE
	DO; /* Get RAM Disk Size argument */
		del = dq$get$argument(@input$buff,@status);
		CALL check$exception(status,NIL);
		IF (del = CR) OR (del = LF) OR (input$buff(0) = 0) THEN
		DO;
            CALL dq$write(co$conn$t,@missing$parm$msg,
							LENGTH(missing$parm$msg),@status);
			CALL dq$write(co$conn$t,@usage$msg,LENGTH(usage$msg),@status);
			GOTO exit;
		END;
		ELSE
		DO;	/* Convert ASCII input number to HEX */
			disk$size = convert(@input$buff);
			IF disk$size < MIN$DISK$SIZE THEN
			DO;
	            CALL dq$write(co$conn$t,@illegal$size$msg,
								LENGTH(illegal$size$msg),@status);
				CALL dq$write(co$conn$t,@usage$msg,LENGTH(usage$msg),@status);
				GOTO exit;
			END;
			IF del = RT_PREN THEN
				GOTO load$driver;

			/* Get pathname file name argument */
			del = dq$get$argument(@input$buff(0),@status);
			CALL check$exception(status,NIL);

			IF (del = RT_PREN) AND (input$buff(0) <> 0) THEN
			DO;
				/*
				 * Initial Contents File Specified - 
				 * Make sure file is valid before any further processing
				 */

				/*
				 *	Attach and open the configuration file
				 */

				file$conn$t = dq$attach( @input$buff, @status );
				CALL check$exception(status,@input$buff);

				CALL dq$open( file$conn$t, READ$ONLY, NO$BUFFERS, @status );
				CALL check$exception(status,@input$buff);

				/*
				 *	Get the attributes of the configuration file
				 */

				CALL dq$file$info(file$conn$t,NO$BUFFERS,@file$info,@status);
				CALL check$exception(status,@input$buff);

				IF (disk$size * 1024) <> file$info.length THEN
				DO;
	        	    CALL dq$write(co$conn$t,@illegal$file$msg,
									LENGTH(illegal$file$msg),@status);
					CALL dq$write(co$conn$t,@usage$msg,LENGTH(usage$msg),
									@status);
					GOTO exit;
				END;
			END;
			ELSE
			DO;
        	    CALL dq$write(co$conn$t,@badparm$msg,
								LENGTH(badparm$msg),@status);
				CALL dq$write(co$conn$t,@usage$msg,LENGTH(usage$msg),
								@status);
				GOTO exit;
			END;
		END;
	END;

load$driver:

	ram$p = dq$mallocate((disk$size * 1024),@status);
	CALL check$exception(status,@input$buff);

	IF file$conn$t <> SELECTOR$OF(NIL) THEN
	DO;
		/*
		 *	Read the initial contents file into the RAM Disk segment.
		 */

		bytes$read = dq$read(file$conn$t,ram$p,file$info.length,@status);
		CALL check$exception(status,NIL);

		CALL dq$detach(file$conn$t,@status);
		CALL check$exception(status,NIL);

	END;

	uinfo.write$protect = 0;

	uinfo.device$address = rqe$get$address(ram$p,@status);
	CALL check$exception(status,@input$buff);

	dinfo.far$init$io = @ram$init$io;
	dinfo.far$finish$io = @ram$finish$io;
	dinfo.far$queue$io = @ram$queue$io;
	dinfo.far$cancel$io = @ram$cancel$io;

	CALL MOVB(@RAM0,@duib.name,14);
	duib.file$driver = 9;	/* Physical, Named */
	duib.functs = 0FFH;
	duib.flags = 0;
	duib.dev$gran = 64;
	duib.dev$size = disk$size * 1024;
	duib.device = 0;
	duib.unit = 0;
	duib.dev$unit = 0;
	duib.init$io = CUSTOM$TYPE;
	duib.finish$io = CUSTOM$TYPE;
	duib.queue$io = CUSTOM$TYPE;
	duib.cancel$io = CUSTOM$TYPE;
	duib.dinfo$p = @dinfo;
	duib.uinfo$p = @uinfo;
	duib.update$timeout = 100;
	duib.num$buffers = 2;
	duib.priority = 128;
	duib.fixed$update = 1;
	duib.max$buffers = 0FFH;

	CALL rq$install$duibs(1,
						  @duib,
						  NIL,
						  @status);
	CALL check$exception(status,NIL);

	root$t = rq$get$task$tokens(ROOT_JOB,@status);
	CALL check$exception(status,NIL);

	HI$job$t = rq$lookup$object(root$t,@(8,'R?HI$JOB'),0,@status);
	CALL check$exception(status,NIL);

	parent$job$t = rq$get$task$tokens(PARENT_JOB,@status);
	CALL check$exception(status,NIL);

	CALL rq$catalog$object(HI$job$t,parent$job$t,
							@(10,'RAMDRV_JOB'),@status);
	IF status = E$CONTEXT THEN
	DO;
		CALL rq$uncatalog$object(HI$job$t,
									@(10,'RAMDRV_JOB'),@status);
		CALL rq$catalog$object(HI$job$t,parent$job$t,
									@(10,'RAMDRV_JOB'),@status);
	END;

	CALL dq$detach(co$conn$t,@status);	/* detach the log file */

	CALL rq$suspend$task(SELECTOR$OF(NIL),@status);

exit:

	/*
	 * Clean up.  Detach :CO:.
	 */

	CALL dq$detach(co$conn$t,@status);

	CALL rq$delete$job (SELECTOR$OF(NIL), @status);

	CALL rq$suspend$task(SELECTOR$OF(NIL),@status);	/* if all else fails */

END ramdrv;
