/********************************************************************
 ** 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
 **
 ** ALL KINDS OF ROUTINES
 **
 **
 ** TABS to 4
 ********************************************************************/

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


/** THE FOLLOWING ROUTINES SHOULD BE GENERIC HOWEVER I HAVE NOT
    BOTHERED TO MAKE THEM SO (SO THEY ARE WRITTEN FOR PktMsg only) */

/********************************************************************/
void ReplyAllHashNodes(struct PktMsg *table[], short length)
/********************************************************************/
{
short i;
struct PktMsg *chain, *next;
	length <<= 1;
	for(i = 0; i < length; i+=2) {
		chain = table[i+HASH_FIRST];
		while(chain) {
			next = chain->next;
			if(chain->smsg.type == TYPE_INTERNAL_DOOFUSRECV)
				FREE_PKTMSGRECV((struct PktMsgRecv *)chain);
			else {
				chain->smsg.result = PAR_ERROR_QUIT;
				REPLY_STDMSG(&chain->smsg);
			}
			chain = next;
		}
		table[i+HASH_FIRST] = NULL;
		table[i+HASH_LAST] = NULL;
	}
}


/********************************************************************/
long PlaceHashNode(struct PktMsg *table[], struct PktMsg *node)
/********************************************************************
  Insert the node at the end of the list in a particular hash slot
      return the "majic number" to identify this node
 ********************************************************************/
{
short thing = HASH_FUNC(node)<<1;
	node->stuff = &table[thing];
	node->next = NULL;
	if(table[thing+HASH_LAST]) table[thing+HASH_LAST]->next = node;
	else table[thing+HASH_FIRST] = node;
	table[thing+HASH_LAST] = node;
	return((long)node);
}



/********************************************************************/
struct PktMsg
	*FindHashNode(struct PktMsg *table[], long majic)
/********************************************************************/
{
short thing = HASH_FUNC(majic)<<1;
struct PktMsg *search;

	for(search = table[thing+HASH_FIRST]; search; search = search->next)
			if((long)search == majic) return(search);

	return(NULL);
}

/********************************************************************/
	void RemoveHashNode(struct PktMsg *node)
/********************************************************************/
{
struct PktMsg **hash = node->stuff, *prev, *search;
	if(!hash) return;
	for(prev = NULL, search = hash[HASH_FIRST]; search;
					prev = search, search = search->next)
		if(search == node) {
			if(prev) prev->next = search->next;
			else hash[HASH_FIRST] = search->next;
			if(!search->next) hash[HASH_LAST] = prev;
		}

	node->stuff = NULL;
}


/********************************************************************/


/********************************************************************/
void abort_code(void *dummy, struct MsgInterrupt *mi)
/* Assume a0=dummy, a1=mi <-- I HOPE THIS IS OK FOR EVERYONE !!! */
/********************************************************************/
{
/* no globals used here... */
	GetMsg(mi->msgport);
	*(char *)(mi->stuff) = 1;
}

/********************************************************************/
				void CloseTimers(void)
/********************************************************************/
{
	TimerBase = (void *)-1;
	if(timerintio->tr_node.io_Device) CloseDevice(timerintio);
	FreeMsgInterrupt(timermi);
	if(timersysio->tr_node.io_Device) CloseDevice(timersysio);
	if(timersysport) DeletePort(timersysport);
	if(timersysio) DeleteExtIO(timersysio);
	if(timedelayio) DeleteExtIO(timedelayio);
}

/********************************************************************/
				short OpenTimers(void)
/********************************************************************/
{
/** GET THE PORTS FOR THE TIMERS */
	if( !(timersysport = CreatePort(0,0)) ) {
		fpf(out, "No port\n");
		return(0);
	}
/** SET UP THE ABORT TIMER SUCH THAT IT WILL CAUSE A SOFTINT */
	if(!(timermi = InitMsgInterrupt(NULL, abort_code, &cir.abort)) ||
	   !ALLOCSTRUCT(&timermi->mem, timerintio, MEMF_PUBLIC | MEMF_CLEAR) )  {
		fpf(out, "No mem\n");
		return(0);
	}
	INIT_MSG(&timerintio->tr_node.io_Message, timermi->msgport, sizeof(*timerintio));

/** GET THE REQUEST STRUCTS FOR THE TIMERS */
	if( !(timersysio = (struct timerequest *)
					CreateExtIO(timersysport, sizeof(*timersysio))) ||
		!(timedelayio = (struct timerequest *)
					CreateExtIO(timersysport, sizeof(*timersysio)))) {
		fpf(out, "No mem\n");
		return(0);
	}
/** OPEN THE TIMERS & FILL IN THE TimerBase VARIABLE */
	if(OpenDevice("timer.device", UNIT_VBLANK, timerintio, 0) != NULL ||
	   OpenDevice("timer.device", UNIT_MICROHZ, timersysio, 0) != NULL ) {
		fpf(out, "No timer\n");
		return(0);
	}
	TimerBase = (struct Library *) timersysio->tr_node.io_Device;
	timedelayio->tr_node.io_Device = timerintio->tr_node.io_Device;
	timedelayio->tr_node.io_Unit = timerintio->tr_node.io_Unit;
	return(-1);
}


/********************************************************************/


/********************************************************************/
				void CloseCIA(void)
/********************************************************************/
{
	if(!oldciaint) RemICRVector(cir.ciares, CIAINTB, ciaint);
	if(ciasignal != -1) FreeSignal(ciasignal);
	/* don't seem to free cia.resource */
}

/********************************************************************/
				short OpenCIA(void)
/********************************************************************/
{
/** GET A SIGNAL (WHICH IS USED IN THE INTERRUPT) */
	if((ciasignal = AllocSignal(-1)) == -1) {
		fpf(out, "No free signals\n");
		return(0);
	}
	cir.sigmask = 1<<ciasignal;
	cir.sigtask = FindTask(NULL);
	fpf(out, "signal=%ld (%lx)\n", ciasignal, cir.sigmask);

/** OPEN THE CIA RESOURCE SO WE CAN HAVE INTERRUPTS */
	if(!(cir.ciares = (struct Library *)OpenResource("ciaa.resource")) ) {
		fpf(out, "Can't open CIA-A\n");
		return(0);
	}

/** SET UP AN INTERRUPT */
	if(!ALLOCSTRUCT(&mem, ciaint, MEMF_PUBLIC | MEMF_CLEAR) ) {
		fpf(out, "No mem\n");
		return(0);
	}
	SetICR(cir.ciares, 1<<CIAINTB);				/* clear out the interrupt */
	ciaint->is_Node.ln_Type = NT_INTERRUPT;
	ciaint->is_Node.ln_Pri = 10;
	ciaint->is_Node.ln_Name = "nETtHING";
	ciaint->is_Code = (void (*)())CIAIntRoutine;
	ciaint->is_Data = &cir;
	if(oldciaint = AddICRVector(cir.ciares, CIAINTB, ciaint)) {
		fpf(out, "Can't use the hardware because of '%s'\n",
			oldciaint->is_Node.ln_Name);
		return(0);
	}

	RelinquishPort();
	return(-1);
}
