/********************************************************************
 ** PARALLEL PORT SUPPORT (PACKET DRIVER)
 **
 ** (c) Spak, Darrell Tam, c9107253@ee.newcastle.edu.au (1994)
 ** phone (Australia) 049-829-710
 **                    49-829-710
 ** (c) SST 1994
 **
 ** READ/RECV PACKET SUPPORT
 **
 ** TABS to 4
 ********************************************************************/

#include "packets.h"
#include "globs_protos.h"
#include "wingdings_protos.h"


/** INTERNAL CODES */
#define RECV_NOTHING	0
#define RECV_ORIGINAL	1
#define RECV_DMA		2


/********************************************************************/
void DoofusGotBody(struct PktMsgRecv *pmr)
/********************************************************************/
{
/** TAKE THE MESSAGE OUT OF THE MAJIC LIST & REPLY */
	MAJIC_REMOVE(pmr);
	PUT_STDMSG(&pmr->pm.smsg, pmr->internal.servport, TYPE_RECEIVED);
}


/********************************************************************/
void DoofusRecvOriginal(struct PktHead *ph, struct PktMsgRecv *pmr,
				long alloc_len, struct MsgPort *msgport)
/********************************************************************/
{
struct StdReq *sr = (void *)&pmr[1];
	INIT_MSG(&pmr->pm.smsg.msg, eatport, sizeof(struct PktMsgRecv));
	pmr->pm.smsg.alloclen = alloc_len;

	pmr->dmaport = comport;
	pmr->pm.stuff = NULL;

	pmr->pm.dest = ph->sender;
	pmr->pm.remote_majic = sr->majic_code;

	pmr->req_body = sr;
	pmr->req_len = ph->pktlen;
	if(pmr->pm.send_len = ph->totallength - pmr->req_len)
		pmr->pm.send_body = (void *)((long)pmr->req_body + pmr->req_len);
	else
		pmr->pm.send_body = NULL;
		
/** IS THERE MORE STUFF TO RECV?? IF SO SEND BACK A MAJIC CODE */
	if(pmr->pm.send_len) {
		pmr->internal.servport = msgport;
		pmr->internal.ourmajic = MAJIC_PLACE(pmr);

	/** SEND THE MAJIC_CODE TO THE ORIGINATOR MACHINE */
		INTERNAL_PREP_PKTMSG_DMA(&pmr->pm, EMEM_NOROUTINE, SERV_MAJIC,
				&pmr->internal.ourmajic, 4 );

	/** THEN WAIT FOR THE REST OF THE BODY TO COME BACK */
		INIT_EMEM(&pmr->pm.recv[SERV2INDEX(SERV_SEND)],
				pmr->pm.send_body, pmr->pm.send_len, DoofusGotBody);
		pmr->pm.recv[1].len = NULL;
		pmr->pm.recv[2].len = NULL;
	/** PUT THIS MESSAGE IN THE MAJIC LIST */
		PUT_STDMSG(&pmr->pm.smsg, comport, TYPE_INTERNAL_DOOFUSRECV);
	}

/** NO MORE TO RECEIVE, JUST SEND OFF THE MESSAGE */
	else
		PUT_STDMSG(&pmr->pm.smsg, msgport, TYPE_RECEIVED);
}





/********************************************************************/
	void ReceiveFromHWPort(void)
/********************************************************************
  Everything is handled correctly should a valid-message
   come from the hardware port
 ********************************************************************/
{

struct	PktMsgRecv *pmr = NULL;			/* for original */
struct	MsgPort *dest_msgport;			/* "" */
long	alloc_len;						/* "" */

struct	PktMsg *pm;						/* if it was DMA */
struct	EMem   *emem;					/* "" */

long	majicreturn = MAJIC_ACCEPT;
void	*dest_mem;

struct	PktHead ph;

char	*aborty = &cir.abort;
short	error = PAR_OK,
		chksum;

char	recvtype = RECV_NOTHING;

	cir.abort = 0;

	START_TIMER(timerintio, timeoutsecs, timeoutmicros);

/** START RECEIVING */
	if(SetupReceive(aborty) != PAR_OK) {
		fpf(out, "Sender never waited!\n");
		error = PAR_ERROR_TIMEOUT;
		goto readnomore;
	}

/** GET THE HEADER OF THE PACKET */
	if(ReceiveData(&ph, sizeof(struct PktHead), aborty, &chksum)) {
		fpf(out, "header timeout\n");
		error = PAR_ERROR_TIMEOUT;
		goto readnomore;
	}

/** TEST THE CHKSUM */
	if(chksum != ph.phchk + ((unsigned char *)&ph.phchk)[0] +
							((unsigned char *)&ph.phchk)[1]) {
		fpf(out, "header chksum bad\n");
		majicreturn = MAJIC_CHKSUMERR;
		error = PAR_ERROR_CHKSUM;
	}
/** CHECK SUM OK - CHECK TO SEE IF ITS A DMA/INTERNAL PACKET */
	else if(ph.server < 0 && ph.server >= -3 ) {
	short  serv = SERV2INDEX(ph.server);
		if(	(pm = FIND_MAJIC(ph.majic_code)) &&					/* valid?? */
			(emem = &pm->recv[serv], dest_mem = emem->mem) &&	/* memory?? */
			(ph.pktlen <= emem->len) )							/* length?? */
				recvtype = RECV_DMA;
		else {
			majicreturn = MAJIC_REJECT;
			error = PAR_ERROR_REJECT;
		}
	}
/** OTHERWISE IF WE HAVE THE SERVICE, GET SOME MEMORY FOR A REQUEST */
	else if(SERVICE_VALID(ph.server) && (dest_msgport = SERVICE_PORT(ph.server))) {
		if(pmr = (struct PktMsgRecv *)
			AllocMem(alloc_len = ph.totallength + sizeof(struct PktMsgRecv),
																MEMF_PUBLIC)) {
			dest_mem = &pmr[1];
			recvtype = RECV_ORIGINAL;
		}
		else {
			majicreturn = MAJIC_NOMEM;
			error = PAR_ERROR_NOMEM;
		}
	}
/** IT WAS DESTINED FOR A SERVICE WE DON'T HAVE */
	else {
		fpf(out, "Un-registered service %ld\n", ph.server);
		majicreturn = MAJIC_REJECT;
		error = PAR_ERROR_REJECT;
	}

/** SEND THE MAJIC- ACCEPT/REJECT PART */
	if(BackSendData(&majicreturn, 4, aborty)) {
		fpf(out, "accept timeout\n");
		error = PAR_ERROR_TIMEOUT;
	}
	if(!ph.pktlen || error) goto readnomore;

/** RECEIVE THE BODY */
	if(ReceiveData(dest_mem, ph.pktlen, aborty, &chksum)) {
		fpf(out,"body timeout\n");
		error = PAR_ERROR_TIMEOUT;
		goto readnomore;
	}

/** CHECK THE CHEK SUM */
	if(chksum != ph.bodychk) {
		fpf(out, "body chksum error\n");
		majicreturn = MAJIC_CHKSUMERR;
		error = PAR_ERROR_CHKSUM;
	}

/** SEND BACK THE RESULT */
	if(BackSendData(&majicreturn, 4, aborty)) {
		fpf(out,"result timeout\n");
		error = PAR_ERROR_TIMEOUT;
	}

readnomore:
	RelinquishPort();
	AbortIO(timerintio);


/** WAS THE PACKET RECV'D OK? */
	if(!error) {

/*		fpf(out, "RECV: pchk=%lx, bchk=%lx, maji=%lx, plen=%ld, serv=%ld\n"
				 "      send=%lc, res =%ld\n",
			ph.phchk,
			ph.bodychk,
			ph.majic_code,
			ph.pktlen,
			ph.server,
			ph.sender,
			error);
*/
		if(recvtype == RECV_ORIGINAL)
			DoofusRecvOriginal(&ph, pmr, alloc_len, dest_msgport);

	/** HAS ENOUGH BEEN READ FOR THE DMA?? */
		else if(recvtype == RECV_DMA) {
			*(long *)&emem->mem += ph.pktlen;
			if((emem->len -= ph.pktlen) <= 0)
				switch((long)emem->routine) {
					case (long)EMEM_NOROUTINE: break;
					case (long)EMEM_RETURNMSG: REPLY_STDMSG(&pm->smsg); break;
					default: emem->routine(pm);
				}
		}
		return;
	}

/** NOPE, FREE MEMORY THEN */
	else if(pmr)
		FreeMem(pmr, alloc_len);
}

