/* $Id: rhps_lib.c,v 2.5 91/10/02 10:28:01 leynette Exp $ */
/****************************************************************/
/* rhps_lib.c:  HPS raw I/O library                    			*/
/****************************************************************/
/*																*/
/*                 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.									*/
/****************************************************************/
/*																*/
/*	These routines provide a convenient interface to the		*/
/*	raw HPS device driver.										*/
/*																*/
/****************************************************************/

/* This library defines five entry points:
 *
 *	hps_open()
 *	hps_close()
 *	hps_read()
 *	hps_write()
 *	hps_ioctl()
 *
 * These calls give a UNIX application program access to applicaitons
 * executing on-board the HPS controller.  The UNIX application must
 * open() the HPS raw device (/dev/rhps), and use the resulting file
 * descriptor in all calls to these library routines.
 */

#include <stdio.h>
#include "hps.types.h"
#include "hps.iocb.h"
#include "hps.ioctl.h"
#include "hps.onb.h"
#include "hps.net.h"
#include "hps.diag.h"
#include "hps.swap.h"

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

/* #define DEBUG */

#ifdef BSD
#define S_DO_IOCB (DO_IOCB | (0xC0000000|(sizeof(DIAG_IOCB)<<16)))
#endif

extern char hps_intel;

#ifndef NULL
#define NULL 0
#endif

hps_open(fd, min, sta, userbox)
int fd, min, sta;
long *userbox;
{
	int result;
	DIAG_IOCB	iocb;
	bit16 tmp;
#ifdef HPS_STREAMS
	struct strbuf	ctlbuf;
	struct strbuf	datbuf;
	long			ctlcmd;
	int				gflags;
#endif

#	ifdef DEBUG
		fprintf(stderr, "hps_open: Enter\n");
#	endif
	iocb.hdr.len = sizeof(DIAG_IOCB);
	iocb.hdr.maj_dev = DIAG_DEV;
	iocb.hdr.min_dev = min;
	iocb.hdr.int_enab = ENABLED;
	iocb.hdr.data_len = 0; 
	iocb.hdr.data_dir = 0;
	iocb.hdr.data.hps_addr = 0;

	if (hps_intel)
	{
		iocb.command = (OPEN<<8)|(OPEN>>8);
		tmp = sta;
		SWAP_2BYTE(&iocb.station, &tmp);
	}
	else
	{
		iocb.command = OPEN;
		iocb.station = sta;
	}
	iocb.cmd_modifier = 0;
	iocb.connection = 0;

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

	if (putmsg(fd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_open: putmsg failed\n");
		return(-1);
	}

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

	if ((result = getmsg(fd,&ctlbuf,&datbuf,&gflags)) != 0)
#elif BSD
	if ((result = ioctl(fd, S_DO_IOCB, &iocb)) != 0)
#else
	if ((result = ioctl(fd, DO_IOCB, &iocb)) != 0)
#endif
	{
#		ifdef DEBUG
			fprintf(stderr, "hps_open: ioctl() == 0x%04x\n",
				result & 0xFFFF);
#		endif
		if (userbox) 
			*userbox = iocb.hdr.mail.hps_addr;
		return(-1);
	}

	if (iocb.hdr.mail.hps_addr >> 16)
	{
#		ifdef DEBUG
			fprintf(stderr, "hps_open == 0x%08x\n", iocb.hdr.mail.hps_addr);
#		endif
		if (userbox) 
			*userbox = iocb.hdr.mail.hps_addr;
		return(-1);
	}

#	ifdef DEBUG
		fprintf(stderr, "hps_open: Done, mail == 0x%08x\n", 
			iocb.hdr.mail.hps_addr);
#	endif

	return(iocb.hdr.mail.hps_addr);
}

hps_close(fd, min, cd, sta, userbox)
int fd, min, cd, sta;
long *userbox;
{
	int result;
	DIAG_IOCB	iocb;
	bit16 tmp;
#ifdef HPS_STREAMS
	struct strbuf	ctlbuf;
	struct strbuf	datbuf;
	long			ctlcmd;
	int				gflags;
#endif

	iocb.hdr.len = sizeof(DIAG_IOCB);
	iocb.hdr.maj_dev = DIAG_DEV;
	iocb.hdr.min_dev = min;
	iocb.hdr.int_enab = ENABLED;
	iocb.hdr.data_len = 0; 
	iocb.hdr.data_dir = 0;
	iocb.hdr.data.hps_addr = 0;

	if (hps_intel)
	{
		iocb.command = (CLOSE<<8)|(CLOSE>>8);
		tmp = sta;
		SWAP_2BYTE(&iocb.station, &tmp);
		tmp = cd;
		SWAP_2BYTE(&iocb.connection, &tmp);
	}
	else
	{
		iocb.command = CLOSE;
		iocb.station = sta;
		iocb.connection = cd;
	}
	iocb.cmd_modifier = 0;

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

	if (putmsg(fd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_close: putmsg failed\n");
		return(-1);
	}

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

	if ((result = getmsg(fd,&ctlbuf,&datbuf,&gflags)) != 0)
#elif BSD
	if ((result = ioctl(fd, S_DO_IOCB, &iocb)) != 0)
#else
	if ((result = ioctl(fd, DO_IOCB, &iocb)) != 0)
#endif
		return(result);

	if (iocb.hdr.mail.hps_addr >> 16)
	{
#		ifdef DEBUG
			fprintf(stderr, "hps_close == 0x%08x\n", iocb.hdr.mail.hps_addr);
#		endif
		if (userbox) 
			*userbox = iocb.hdr.mail.hps_addr;
		return(-1);
	}

#	ifdef DEBUG
		fprintf(stderr, "hps_close: Done, mail == 0x%08x\n", 
			iocb.hdr.mail.hps_addr);
#	endif
	return(0);
}

hps_read(fd, min, cd, sta, buffer, nbytes, userbox)
int fd, min, cd, sta, nbytes;
long *userbox;
char *buffer;
{
	bit16 tmp;

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

#if (BSD || HPS_STREAMS)
	int i;
	struct
	{
		DIAG_IOCB	xiocb;
		char 		buffer[512];
	} x;
#define iocb x.xiocb
#else
	DIAG_IOCB	iocb;
#endif

	iocb.hdr.len = sizeof(DIAG_IOCB);
	iocb.hdr.maj_dev = DIAG_DEV;
	iocb.hdr.min_dev = min;
	iocb.hdr.data_len = (bit16) nbytes;

#if (HPS_STREAMS || BSD)
	iocb.hdr.data.hps_addr = (bit32) x.buffer;
#else
	iocb.hdr.data.hps_addr = (bit32) buffer;
#endif

	iocb.hdr.data_dir = 0;
	iocb.hdr.int_enab = ENABLED;

	if (hps_intel)
	{
		iocb.command = (READ<<8)|(READ>>8);
		tmp = sta;
		SWAP_2BYTE(&iocb.station, &tmp);
		tmp = cd;
		SWAP_2BYTE(&iocb.connection, &tmp);
	}
	else
	{
		iocb.command = READ;
		iocb.station = sta;
		iocb.connection = cd;
	}
	iocb.cmd_modifier = 0;

#ifdef DEBUG
	printf("rhps_lib: reading from HPS\n");
#endif

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

	if (putmsg(fd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_read: putmsg failed\n");
		return(-1);
	}

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

	if (getmsg(fd,&ctlbuf,&datbuf,&gflags) != 0)
#elif BSD
	i = nbytes + sizeof(DIAG_IOCB);
	if (read(fd, &x, i) != i)
#else
	if (ioctl(fd, DO_IOCB, &iocb) != 0)
#endif
	{
		if (userbox)
			*userbox = iocb.hdr.mail.hps_addr;
		return(-1);
	}

	if (userbox) 
		*userbox = iocb.hdr.mail.hps_addr;

	if (iocb.hdr.mail.hps_addr >> 16)
	{
#		ifdef DEBUG
			fprintf(stderr, "hps_read == 0x%08x\n", iocb.hdr.mail.hps_addr);
#		endif
		return(0);
	}

#if (BSD || HPS_STREAMS)
	for (i = 0; i < nbytes; i++)
	  buffer[i] = x.buffer[i];
#endif

#	ifdef DEBUG
		fprintf(stderr, "hps_read: Done, mail == 0x%08x\n", 
			iocb.hdr.mail.hps_addr);
#	endif
	return(nbytes);
#undef iocb 
}

hps_write(fd, min, cd, sta, buffer, nbytes, userbox)
int fd, min, cd, sta, nbytes;
long *userbox;
char *buffer;
{
	bit16 tmp;

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

#if (BSD || HPS_STREAMS)
	int i;
	int result;
	struct
	{
		DIAG_IOCB	xiocb;
		char 		buffer[512];
	} x;
#define iocb x.xiocb
	for (i=0; i<nbytes; ++i)
		x.buffer[i] = buffer[i];
#else
	DIAG_IOCB	iocb;
#endif

	iocb.hdr.len = sizeof(DIAG_IOCB);
	iocb.hdr.maj_dev = DIAG_DEV;
	iocb.hdr.min_dev = min;
	iocb.hdr.data_len = (bit16) nbytes;

#if (BSD || HPS_STREAMS)
	iocb.hdr.data.hps_addr = (bit32) x.buffer;
#else
	iocb.hdr.data.hps_addr = (bit32) buffer;
#endif
	
	iocb.hdr.data_dir = 1;
	iocb.hdr.int_enab = ENABLED;

	if (hps_intel)
	{
		iocb.command = (WRITE<<8)|(WRITE>>8);
		tmp = sta;
		SWAP_2BYTE(&iocb.station, &tmp);
		tmp = cd;
		SWAP_2BYTE(&iocb.connection, &tmp);
	}
	else
	{
		iocb.command = WRITE;
		iocb.station = sta;
		iocb.connection = cd;
	}
	iocb.cmd_modifier = 0;

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

	if (putmsg(fd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_write: putmsg failed\n");
		return(-1);
	}

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

	if (getmsg(fd,&ctlbuf,&datbuf,&gflags) != 0)
#elif BSD
	for (i=0; i < nbytes; i++)
		x.buffer[i] = buffer[i];
	i = nbytes + sizeof(DIAG_IOCB);
	if ((result = write(fd, &x, i)) != i)
#else
	if (ioctl(fd, DO_IOCB, &iocb) != 0)
#endif
	{
		if (userbox)
			*userbox = iocb.hdr.mail.hps_addr;
		return(-1);
	}

	if (userbox) 
		*userbox = iocb.hdr.mail.hps_addr;

	if (iocb.hdr.mail.hps_addr >> 16)
	{
#		ifdef DEBUG
			fprintf(stderr, "hps_write == 0x%08x\n", iocb.hdr.mail.hps_addr);
#		endif
		return(-1);
	}

#	ifdef DEBUG
		fprintf(stderr, "hps_write: Done, mail == 0x%08x\n", 
			iocb.hdr.mail.hps_addr);
#	endif

	return(nbytes);

#undef iocb 
}

hps_ioctl(fd, min, cd, sta, buffer, nbytes, request, userbox)
int fd, min, cd, sta, nbytes, request;
long *userbox;
char *buffer;
{

	int result;
	DIAG_IOCB	iocb;
	bit16 tmp;
#ifdef HPS_STREAMS
	struct strbuf	ctlbuf;
	struct strbuf	datbuf;
	long			ctlcmd;
	int				gflags;
#endif 

	iocb.hdr.len = sizeof(DIAG_IOCB);
	iocb.hdr.maj_dev = DIAG_DEV;
	iocb.hdr.min_dev = min;
	iocb.hdr.int_enab = ENABLED;

	if (hps_intel)
	{
		iocb.command = (IOCTL<<8)|(IOCTL>>8);
		tmp = request;
		SWAP_2BYTE(&iocb.cmd_modifier, &tmp);
		tmp = sta;
		SWAP_2BYTE(&iocb.station, &tmp);
		tmp = cd;
		SWAP_2BYTE(&iocb.connection, &tmp);
	}
	else
	{
		iocb.command = IOCTL;
		iocb.cmd_modifier = request;
		iocb.station = sta;
		iocb.connection = cd;
	}

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

	if (putmsg(fd,&ctlbuf,&datbuf,0) < 0)
	{
		printf("hps_ioctl: putmsg failed\n");
		return(-1);
	}

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

	if ((result = getmsg(fd,&ctlbuf,&datbuf,&gflags)) != 0)
#elif BSD
	if ((result = ioctl(fd, S_DO_IOCB, &iocb)) != 0)
#else
	if ((result = ioctl(fd, DO_IOCB, &iocb)) != 0)
#endif
	{
		if (userbox)
			*userbox = iocb.hdr.mail.hps_addr;
		return(result);
	}

	if (userbox) 
		*userbox = iocb.hdr.mail.hps_addr;

	if (iocb.hdr.mail.hps_addr >> 16)
	{
#		ifdef DEBUG
			fprintf(stderr, "hps_ioctl == 0x%08x\n", iocb.hdr.mail.hps_addr);
#		endif
		return(-1);
	}

#	ifdef DEBUG
		fprintf(stderr, "hps_ioctl: Done, mail == 0x%08x\n", 
			iocb.hdr.mail.hps_addr);
#	endif
	return(0);
}

/*
 * MODIFICATION HISTORY:
 *
 * $Log:	rhps_lib.c,v $
 * Revision 1.1.2.1  92/06/24  13:54:01  marker
 * Branch RISCOS_5_01_2_FIXES off of trunk.
 * 
 * Revision 2.5  91/10/02  10:28:01  leynette
 * Changed declaration of userbox from char * to long * in hps_{open,close};
 * changed return() at end of hps_open to return iocb.hdr.mail.hps_addr
 * instead of 0 (which would cause util's like hps_*loop to hang).
 * ENHANCEMENT
 * 
 * Revision 2.4  91/09/03  17:41:13  annette
 * Changed error message handling.
 * INTERNAL
 * 
 * Revision 2.3  91/01/10  17:24:34  dave
 * Modify header; add footer.
 * COSMETIC
 * 
 */
