/* $Id: hps_load.c,v 1.1 91/09/03 17:47:59 annette Exp $ */
/****************************************************************/
/* load.c:  HPS Loader											*/
/****************************************************************/
/*																*/
/*                 Confidential Information                     */
/*      Limited Distribution to Authorized Persons Only         */
/*     Created 1985 and Protected as an Unpublished Work        */
/*          Under the U.S. Copyright Act of 1976.               */
/*         Copyright (c) 1985,'88, Systech Corporation          */
/*                  All Rights Reserved                         */
/*																*/
/*	THIS SOFTWARE IS LICENSED BY AND IS THE	CONFIDENTIAL AND 	*/
/*	PROPRIETARY PROPERTY OF SYSTECH COMPUTER CORPORATION AND 	*/
/*	MAY NOT, WITHOUT THE PRIOR WRITTEN CONSENT OF SYSTECH 		*/
/*	COMPUTER CORPORATION, BE REPRODUCED, USED OR DISCLOSED 		*/
/*	EXCEPT IN ACCORDANCE WITH A SYSTECH COMPUTER CORPORATION 	*/
/*	SOFTWARE LICENSE AGREEMENT.									*/
/****************************************************************/
/*																*/
/*	This program loads executable code onto an HPS host-		*/
/*	adapter, and starts the downloaded code.  An options is		*/
/*	available to reconfigure the operating system after			*/
/*	downloading.												*/
/*																*/
/*	The "c" keyletter will reconfigure the on-board operating   */
/*	system after downloading.									*/
/*																*/
/*	This loader expects the downloaded file to be in			*/
/*	Systech's ".dnl" format.									*/
/*																*/
/****************************************************************/

/*
 * Generalized loader for HPS board.
 *
 *	1) Load the application code onto the board
 *	2) If the c keyletter is present, load the configuration information
 *	   into the on-board configuration table, and issue an INIT command.
 *	3) Issue a CREATE ioctl command for the downloaded code, to start the
 *	   boot task of the downloaded code.
 */

/*
#define DEBUG
#define DEBUG1
*/

#include "stdio.h"
#include "a.out.h"
#include "hps.types.h"
#include "hps.iocb.h"
#include "hps.ioctl.h"
#include "hps.conf.h"
#include "hps.swap.h"

#ifdef HPS_STREAMS
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#endif

#define V_SIZE		sizeof(v_tab)
#define T_SIZE		80

char  hps_intel		= 0;			/* host byte ordering	*/
bit16 sum;
int hpsfd;

extern int errno;

DNL_HDR dnl_header, sdnl_header;

main(argc, argv)
int argc;
char **argv;
{
	char c, *key, *dlfile, *dldev, iobuf[512];
	short c_flag, error;
	int i, ii, result, temp, count, dlfd;
	long total_size;
	long sys_addrs[8];

	bit8 b_pri, b_id;
	bit16 v_us_size, t_count, v_is_size;
	bit32 v_ws, v_ws_size, t_ws;
	bit32 onb_addr;
	bit32 onb_vtab;
	bit32 onb_ttab;
	HPS_LONG base_adr;
	struct v_table v_tab;
	struct t_table t_tab;
	short tmp;
	bit32 ltmp;


	tmp = 0;
	hps_intel = *(char *)&tmp;

	c_flag = 0;
	error = 0;

	/* Scan the command line, if a keyword is present */
	i = argc;
	if (argc > 3)
	{
		key = argv[1];
		while ((c = *key++) != '\0')
		{
			switch (c) /* Possible values: cr */
			{
				case 'c':	/* Set the "configure" flag */
					c_flag = 1;
					i -= 1;
#					ifdef DEBUG
						fprintf(stderr, "%s: CONFIGURE\n", argv[0]);
#					endif
					break;
					
				default:
					fprintf(stderr,
						"%s: \"%c\" bad keyletter\n", argv[0], c);
					usage(argv[0]);
					error = 1;
					break;
			}
		}
	}
	if (error)
		exit(1);

	if (i != 3)
	{
		fprintf(stderr,
			"%s: Need download device and file name to download\n", argv[0]);
		usage(argv[0]);
		exit(1);
	}

	dldev = argv[argc-2];
	dlfile = argv[argc-1];

#ifdef DEBUG
	fprintf(stderr,"dldev name = %s\n",dldev);
	fprintf(stderr,"dlfile name = %s\n",dlfile);   
#endif

	/* Get the HPS host-adapter's on-board System address table */
	if ((result = gaddrs(sys_addrs, dldev, argv[0])) != 0)
	{
		fprintf(stderr,
			 "%s: Cannot get system address table\n", argv[0]);
		if (errno)
			perror(argv[0]);
		else
			errtab(result >> 16, argv[0]);
		exit(1);
	}
#	ifdef DEBUG
		fprintf(stderr, "%s: Onboard addresses:\n", argv[0]);
		for (ii=0; ii<8; ii++)
			fprintf(stderr, "0x%08X\n", sys_addrs[ii]);
#	endif

	/* Open download file (executable binary image in .dnl format) */
	if ((dlfd = open(dlfile, 0)) < 0)
	{
		fprintf(stderr, "%s: Cannot open file %s.\n", argv[0], dlfile);
		exit(1);
	}
#	ifdef DEBUG
		fprintf(stderr, "%s: Download file %s\n", argv[0], dlfile);
#	endif

	/* Open HPS raw driver */
	if ((hpsfd = open(dldev, 2)) < 0)
	{
		fprintf(stderr, "%s: Cannot open device %s\n", argv[0], dldev);
		if (errno)
			perror(argv[0]);
		exit(1);
	}

	/* Get download file's header */
	if (read(dlfd, hps_intel ? &sdnl_header : &dnl_header, sizeof(dnl_header))
		!= sizeof(dnl_header))
	{
		fprintf(stderr, "%s: Error reading %s's header\n", argv[0], dlfile);
		if (errno)
			perror(argv[0]);
		exit(1);
	}

	if (hps_intel)
	{
		SWAP_4BYTE(&dnl_header.start,      &sdnl_header.start);
		SWAP_4BYTE(&dnl_header.end,        &sdnl_header.end);
		SWAP_4BYTE(&dnl_header.vt_start,   &sdnl_header.vt_start);
		SWAP_4BYTE(&dnl_header.vt_len,     &sdnl_header.vt_len);
		SWAP_4BYTE(&dnl_header.tt_start,   &sdnl_header.tt_start);
		SWAP_4BYTE(&dnl_header.tt_len,     &sdnl_header.tt_len);
		SWAP_4BYTE(&dnl_header.boot_start, &sdnl_header.boot_start);
		SWAP_4BYTE(&dnl_header.v_ws,       &sdnl_header.v_ws);
		SWAP_4BYTE(&dnl_header.v_ws_size,  &sdnl_header.v_ws_size);
		SWAP_2BYTE(&dnl_header.v_us_size,  &sdnl_header.v_us_size);
		SWAP_2BYTE(&dnl_header.t_count,    &sdnl_header.t_count);
		SWAP_2BYTE(&dnl_header.b_pri,      &sdnl_header.b_pri);
		SWAP_2BYTE(&dnl_header.b_id,       &sdnl_header.b_id);
	}

	/* Setup for load */
	total_size = dnl_header.end - dnl_header.start;
	onb_addr = dnl_header.start;

#	ifdef DEBUG
		fprintf(stderr, "%s: Total size is %d\n", argv[0], total_size);
#	endif


	/* Download code */
#	ifdef DEBUG
		fprintf(stderr, "%s: Downloading to 0x%06x\n", argv[0], onb_addr);
#	endif

	/* Read information needed to configure board */
	if (c_flag)
	{
		/* Get initial on-board configuration tables */
		if (hps_read(&v_tab, sys_addrs[1], V_SIZE, argv[0]) != V_SIZE)
		{
			fprintf(stderr, "%s: VRTX table read() failed\n", argv[0]);
			exit(1);
		}
		if (hps_intel)
		{
			SWAP_4BYTE(&ltmp, &v_tab.tracer);
			v_tab.tracer = ltmp;
		}
		if (v_tab.tracer != 0)
		{
			if (hps_read(&t_tab, v_tab.tracer, T_SIZE, argv[0]) != T_SIZE)
			{
				fprintf(stderr, "%s: TRACER table read() failed\n", argv[0]);
				exit(1);
			}
		}

		/* Collect download configuration info from object file */
		onb_vtab = dnl_header.vt_start;
		onb_ttab = v_tab.tracer ? dnl_header.tt_start : 0;
		v_ws = dnl_header.v_ws;
		v_ws_size = dnl_header.v_ws_size;
		t_ws = v_ws + v_ws_size;
		v_us_size = dnl_header.v_us_size;
		t_count = dnl_header.t_count;
		if (v_tab.is_size < 0x200)
			v_is_size = 0x200;
		else
			v_is_size = v_tab.is_size;

		/* Plug new values into our copy of configuration tables */
		if (hps_intel)
		{
			SWAP_4BYTE(&v_tab.tracer, &onb_ttab);
			SWAP_4BYTE(&v_tab.workspace, &v_ws);
			SWAP_4BYTE(&v_tab.ws_size, &v_ws_size);
			SWAP_2BYTE(&v_tab.us_size, &v_us_size);
			SWAP_2BYTE(&v_tab.is_size, &v_is_size);
			SWAP_2BYTE(&v_tab.task_c, &t_count);
			SWAP_4BYTE(&ltmp, &t_ws);
			*(short *)((char *)&t_tab + 6) = (short)((ltmp >> 16) & 0xffff);
			*(short *)((char *)&t_tab + 8) = (short)(ltmp & 0xffff);
		}
		else
		{
			v_tab.tracer = onb_ttab;
			v_tab.workspace = v_ws;
			v_tab.ws_size = v_ws_size;
			v_tab.us_size = v_us_size;
			v_tab.is_size = v_is_size;
			v_tab.task_c = t_count;
			*(short *)((char *)&t_tab + 6) = (short)((t_ws >> 16) & 0xffff);
			*(short *)((char *)&t_tab + 8) = (short)(t_ws & 0xffff);
		}

/*		*(long *) ((char *)&t_tab+6) = t_ws;   store workspace pointer */

		/* make sure we're not going to overwrite the existing OS table ... */
		if (onb_vtab == sys_addrs[1])
		{
			fprintf(stderr, 
			"%s: ERROR--trying to overwrite configuration table\n", argv[0]);
			close(dlfd);
			close(hpsfd);
			exit(-1);
		}
	}
	

	/*
	 * This is the main loop of the loader.  Each time around, one block
	 * of code is written to the HPS host adpater.  The loop terminates
	 * after all the code and initialized data of the download file has
	 * been written to the host adapter.
	 */
	i=total_size;
	while (i)
	{
		/* Read a block from the download file */
		count = (i > sizeof(iobuf)) ? sizeof(iobuf) : i;
		if ((result = read(dlfd, iobuf, count)) != count)
		{
			fprintf(stderr, "%s: read(%s) == %d\n", argv[0], dlfile, result);
			fprintf(stderr, "%s: i == %d, count == %d, onb_addr == 0x%06x\n",
				argv[0], i, count, onb_addr);
			perror(argv[0]);
			exit(1);
		}

		/* Write the block to the host adapter */
		if (hps_write(iobuf, onb_addr, count) != count)
		{
			fprintf(stderr, "%s: Write error\n", argv[0]);
			exit(1);
		}
		onb_addr += count;
		i -= count;
	}

	/* This is where the configuration actually occurs */
	if (c_flag)
	{
		/* Send new configuration tables back to board */
#		ifdef DEBUG
			fprintf(stderr, "%s: New config    \n", argv[0]);
			fprintf(stderr, "%s: V table   == 0x%x\n", argv[0], onb_vtab);
			fprintf(stderr, "%s: T table   == 0x%x\n", argv[0], onb_ttab);
			fprintf(stderr, "%s: v_ws      == 0x%x\n", argv[0], v_ws);
			fprintf(stderr, "%s: v_ws_size == 0x%x\n", argv[0], v_ws_size);
			fprintf(stderr, "%s: v_us_size == 0x%x\n", argv[0], v_us_size);
			fprintf(stderr, "%s: t_count   == 0x%x\n", argv[0], t_count);
			fprintf(stderr, "%s: t_ws      == 0x%x\n", argv[0], t_ws);
#		endif
#		ifdef DEBUG
			printf("About to write VRTX config, type return");
			getchar();
#		endif

		if (hps_write(&v_tab, onb_vtab, V_SIZE) != V_SIZE)
		{
			fprintf(stderr, "%s: VRTX table write() failed\n", argv[0]);
			exit(1);
		}

		if (v_tab.tracer != 0)
		{
#			ifdef DEBUG
				printf("About to write TRACER config, type return");
				getchar();
#			endif

			if (hps_write(&t_tab, onb_ttab, T_SIZE) != T_SIZE)
			{
				fprintf(stderr, "%s: TRACER table write() failed\n", argv[0]);
				exit(1);
			}
		}

		/* Re-initialize VRTX */
#		ifdef DEBUG1
			printf("onb_vtab == 0x%06x\n", onb_vtab);
			printf("About to VINIT, type return");
			getchar();
#		endif
		/* TEMP */
		/*sleep(2);		/* to wait for write iocb to go out */
		if (hps_ioctl(INIT, onb_vtab + 4, 0, 0)) {
			close(dlfd);
			close(hpsfd);
			exit(1);
		}
#		ifdef DEBUG
			printf("VINIT complete\n");
#		endif
	}
	

	/* Issue a CREATE */
	if (dnl_header.boot_start)
	{
#		ifdef DEBUG1
		fprintf(stderr, "%s: addr == 0x%x\n", argv[0], dnl_header.boot_start);
		fprintf(stderr, "%s: b-pri   == 0x%x\n", argv[0], dnl_header.b_pri);
		fprintf(stderr, "%s: b_id    == 0x%x\n", argv[0], dnl_header.b_id);
		printf("About to CREATE, type return");
		getchar();
#		endif
		if (hps_ioctl(CREATE, dnl_header.boot_start, dnl_header.b_pri, 
					dnl_header.b_id)) {
			close(dlfd);
			close(hpsfd);
			exit(1);
		}
	}

	close(dlfd);
	close(hpsfd);

#	ifdef DEBUG
		fprintf(stderr, "%s: Done\n", argv[0]);
#	endif
	exit(0);
}




/*
 * Raw driver IOCB and data 
 */
struct whole_thing
{
	LOADER_IOCB 	raw_iocb;
	char 		raw_buffer[512];
} iocb_buf;


/*
 * This routine sends a block of code to the host adapter.  Routine
 * "check" is called to compare our computed checksum with that returned
 * by the HPS loader.
 */
hps_write(source, dest, count, pname)
char *source;
bit32 dest;
int count;
char *pname;
{
	int i;
	bit32 ltmp;

#ifdef HPS_STREAMS
	struct strbuf	ctlbuf;
	struct strbuf	datbuf;
	long			ctlcmd;
	int				gflags;
#endif

#	ifdef DEBUG
		fprintf(stderr, "%s: 0x%06x --> 0x%06x, %d bytes\n",
			argv[0], source, dest, count);
#	endif

	for (i = 0; i < count; i++)
		iocb_buf.raw_buffer[i] = source[i];

  	iocb_buf.raw_iocb.header.len = sizeof(LOADER_IOCB);
  	iocb_buf.raw_iocb.header.maj_dev = 1;
  	iocb_buf.raw_iocb.header.min_dev = 0;
  	iocb_buf.raw_iocb.header.int_enab = 1;
	iocb_buf.raw_iocb.header.data.hps_addr = (bit32)iocb_buf.raw_buffer;
  	iocb_buf.raw_iocb.header.data_len = count;
  	iocb_buf.raw_iocb.header.data_dir = TO_HPS;

	if (hps_intel)
	{
  		iocb_buf.raw_iocb.command = (WRITE<<8)|(WRITE>>8);
  		iocb_buf.raw_iocb.cmd_modifier = 0;
  		SWAP_4BYTE(&ltmp,&dest);
  		iocb_buf.raw_iocb.hpsadr.hps_addr = ltmp;
  		iocb_buf.raw_iocb.priority = 0;
  		iocb_buf.raw_iocb.tid = 0;
  		iocb_buf.raw_iocb.mode = 0x0100;
	}
	else
	{
  		iocb_buf.raw_iocb.command = WRITE;
  		iocb_buf.raw_iocb.cmd_modifier = 0;
  		iocb_buf.raw_iocb.hpsadr.hps_addr = dest;
  		iocb_buf.raw_iocb.priority = 0;
  		iocb_buf.raw_iocb.tid = 0;
  		iocb_buf.raw_iocb.mode = 1;
	}

	/*
	 * At this point, the IOCB is passed to the HPS driver, which coordinates
	 * the actual interface to the board through the DPRAM parameter block.
	 */

#ifdef HPS_STREAMS
	ctlbuf.maxlen = 0;
	ctlbuf.len    = sizeof(long);
	ctlbuf.buf    = (char *)&ctlcmd;
	ctlcmd        = 1;
	datbuf.maxlen = 0;
	datbuf.len    = sizeof(iocb_buf);
	datbuf.buf    = (char *)&iocb_buf;

	if (putmsg(hpsfd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_write: putmsg failed, errno = %d\n",errno);
		return(-1);
	}

	ctlbuf.len    = 0;
	ctlbuf.maxlen = sizeof(long);
	ctlbuf.buf    = (char *)&ctlcmd;
	datbuf.len    = 0;
	datbuf.maxlen = sizeof(iocb_buf);
	datbuf.buf    = (char *)&iocb_buf;
	gflags        = 0;
	ctlcmd        = 0;
	bzero((char *)&iocb_buf,sizeof(iocb_buf));

	if (getmsg(hpsfd,&ctlbuf,&datbuf,&gflags) != 0)
		printf("hps_write: getmsg failed, errno = %d\n",errno);

#elif BSD
  	if (write(hpsfd, &iocb_buf, sizeof(iocb_buf)) < 0)
          	printf("Write failed: %d\n", errno);
#else
	if (ioctl(hpsfd, DO_IOCB, &iocb_buf) < 0)
	{
		fprintf(stderr, "%s: Write failed: %d\n", pname);
		if (errno)
			perror(pname);
	}
#endif

	if (check(source, count, iocb_buf.raw_iocb.header.mail.hps_addr & 0xFFFF))
	{
		fprintf(stderr, 
			"%s: Checksum error: HPS == 0x%x; appl == 0x%x\n",
			pname, iocb_buf.raw_iocb.header.mail.hps_addr & 0xFFFF, sum);
		return(-1);
	}
	return(count);
}



/*
 * This routine reads a block from the HPS host adapter.  The loader
 * uses this routine to read VRTX/TRACER configuration tables from the
 * board, before reconfiguring the HPS operating system.
 */
hps_read(dest, source, count, pname)
char *dest;
bit32 source;
int count;
char *pname;
{
	int i;
	bit32 ltmp;

#ifdef HPS_STREAMS
	struct strbuf	ctlbuf;
	struct strbuf	datbuf;
	long			ctlcmd;
	int				gflags;
#endif

#	ifdef DEBUG
		fprintf(stderr, "%s: 0x%06x <-- 0x%06x, %d bytes\n",
			argv[0], dest, source, count);
#	endif

  	iocb_buf.raw_iocb.header.len = sizeof(LOADER_IOCB);
  	iocb_buf.raw_iocb.header.maj_dev = 1;
  	iocb_buf.raw_iocb.header.min_dev = 0;
  	iocb_buf.raw_iocb.header.int_enab = 1;
	iocb_buf.raw_iocb.header.data.hps_addr = (bit32)iocb_buf.raw_buffer;
  	iocb_buf.raw_iocb.header.data_len = count;
  	iocb_buf.raw_iocb.header.data_dir = FROM_HPS;

	if (hps_intel)
	{
  		iocb_buf.raw_iocb.command = (READ<<8)|(READ>>8);
  		iocb_buf.raw_iocb.cmd_modifier = 0;
		SWAP_4BYTE(&ltmp, &source);
  		iocb_buf.raw_iocb.hpsadr.hps_addr = ltmp;
  		iocb_buf.raw_iocb.priority = 0;
  		iocb_buf.raw_iocb.tid = 0;
  		iocb_buf.raw_iocb.mode = 0x0100;
	}
	else
	{
  		iocb_buf.raw_iocb.command = READ;
  		iocb_buf.raw_iocb.cmd_modifier = 0;
  		iocb_buf.raw_iocb.hpsadr.hps_addr = source;
  		iocb_buf.raw_iocb.priority = 0;
  		iocb_buf.raw_iocb.tid = 0;
  		iocb_buf.raw_iocb.mode = 1;
	}

	/*
	 * At this point, the IOCB is passed to the HPS driver, which coordinates
	 * the actual interface to the board through the DPRAM parameter block.
	 */

#ifdef HPS_STREAMS
	ctlbuf.maxlen = 0;
	ctlbuf.len    = sizeof(long);
	ctlbuf.buf    = (char *)&ctlcmd;
	ctlcmd        = 1;
	datbuf.maxlen = 0;
	datbuf.len    = sizeof(iocb_buf);
	datbuf.buf    = (char *)&iocb_buf;

	if (putmsg(hpsfd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_read: putmsg failed, errno = %d\n",errno);
		return(-1);
	}

	ctlbuf.len    = 0;
	ctlbuf.maxlen = sizeof(long);
	ctlbuf.buf    = (char *)&ctlcmd;
	datbuf.len    = 0;
	datbuf.maxlen = sizeof(iocb_buf);
	datbuf.buf    = (char *)&iocb_buf;
	gflags        = 0;
	ctlcmd        = 0;
	bzero((char *)&iocb_buf,sizeof(iocb_buf));

	if (getmsg(hpsfd,&ctlbuf,&datbuf,&gflags) != 0)
		printf("hps_read: getmsg failed, errno = %d\n",errno);
#elif BSD
  	if (read(hpsfd, &iocb_buf, sizeof(iocb_buf)) < 0)
	 	printf("Read failed: %d\n",errno);
#else
	if (ioctl(hpsfd, DO_IOCB, &iocb_buf) < 0)
	{
		fprintf(stderr, "%s: Read failed.\n", pname);
		if (errno)
			perror(pname);
		return(-1);
	}
#endif

	for (i = 0; i < count; i++)
	  dest[i] = iocb_buf.raw_buffer[i];
	return(count);
}


/*
 * This routine issues IOCTL commands to the HPS host adapter.  These
 * include the INIT and CREATE commands to reconfigure the HPS operating
 * system, and create the downloaded task.
 */
hps_ioctl(cmd_mod, hps_addr, pri, tid)
int cmd_mod, pri, tid;
char *hps_addr; 
{
bit16 tmp;
bit32 ltmp;

#ifdef HPS_STREAMS
	struct strbuf	ctlbuf;
	struct strbuf	datbuf;
	long			ctlcmd;
	int				gflags;
#endif

	iocb_buf.raw_iocb.header.len = sizeof(LOADER_IOCB);
	iocb_buf.raw_iocb.header.maj_dev = 1;
	iocb_buf.raw_iocb.header.min_dev = 0;
	if (cmd_mod == INIT)
		iocb_buf.raw_iocb.header.int_enab = 0;
	else
		iocb_buf.raw_iocb.header.int_enab = 1;
	iocb_buf.raw_iocb.header.data_len = 0;
	iocb_buf.raw_iocb.header.data_dir = TO_HPS;

	if (hps_intel)
	{
		iocb_buf.raw_iocb.command = (IOCTL<<8)|(IOCTL>>8);
		tmp = cmd_mod;
		SWAP_2BYTE(&iocb_buf.raw_iocb.cmd_modifier, &tmp);
		ltmp = (bit32)hps_addr;
		SWAP_4BYTE(&iocb_buf.raw_iocb.hpsadr.hps_addr, &ltmp);
		tmp = pri;
		SWAP_2BYTE(&iocb_buf.raw_iocb.priority, &tmp);
		tmp = tid;
		SWAP_2BYTE(&iocb_buf.raw_iocb.tid, &tmp);
		iocb_buf.raw_iocb.mode = 0x0100;
	}
	else
	{
		iocb_buf.raw_iocb.command = IOCTL;
		iocb_buf.raw_iocb.cmd_modifier = cmd_mod;
		iocb_buf.raw_iocb.hpsadr.hps_addr = (bit32)hps_addr;
		iocb_buf.raw_iocb.priority = pri;
		iocb_buf.raw_iocb.tid = tid;
		iocb_buf.raw_iocb.mode = 1;
	}

	/*
	 * At this point, the IOCB is passed to the HPS driver, which coordinates
	 * the actual interface to the board through the DPRAM parameter block.
	 */

/* try  to use write instead to see if it works with the custom driver */

#ifdef HPS_STREAMS
	ctlbuf.maxlen = 0;
	ctlbuf.len    = sizeof(long);
	ctlbuf.buf    = (char *)&ctlcmd;
	ctlcmd        = 1;
	datbuf.maxlen = 0;
	datbuf.len    = sizeof(iocb_buf);
	datbuf.buf    = (char *)&iocb_buf;

	if (putmsg(hpsfd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_ioctl: putmsg failed, errno = %d\n",errno);
		return(-1);
	}

	ctlbuf.len    = 0;
	ctlbuf.maxlen = sizeof(long);
	ctlbuf.buf    = (char *)&ctlcmd;
	datbuf.len    = 0;
	datbuf.maxlen = sizeof(iocb_buf);
	datbuf.buf    = (char *)&iocb_buf;
	gflags        = 0;
	ctlcmd        = 0;
	bzero((char *)&iocb_buf,sizeof(iocb_buf));

	getmsg(hpsfd,&ctlbuf,&datbuf,&gflags);
#elif BSD
		ioctl(hpsfd, 
			DO_IOCB | (0xC0000000 | (sizeof(LOADER_IOCB)<<16)), &iocb_buf);
#else
		ioctl(hpsfd, DO_IOCB, &iocb_buf);
#endif

}

/*
 * This routine computes an HPS checksum on a block, and compares
 * it with a given checksum.
 */
check(buffer, count, checksum)
bit8 *buffer;
bit16 checksum;
{
	sum = 0;
	while (count--)
		sum += *buffer++ & 0xff;
	return sum != checksum;
}

usage(name)
char *name;
{
	fprintf (stderr, "%s: usage: %s [c] <raw_device> <dnl_filename>\n", 
			name, name);
}

/*
 * MODIFICATION HISTORY:
 *
 * $Log:	hps_load.c,v $
 * Revision 1.1.2.1  92/06/24  13:53:31  marker
 * Branch RISCOS_5_01_2_FIXES off of trunk.
 * 
 * Revision 1.1  91/09/03  17:47:59  annette
 * Initial revision
 * 
 * Revision 2.4  91/07/18  11:04:08  annette
 * Added check for interrupt stack size.  If < 0x200 will now make it
 * 0x200 for new network manager.
 * 
 * Revision 2.3  91/01/10  17:23:57  dave
 * Modify header; add footer.
 * COSMETIC
 * 
 */
