/*
** $Header: SRC:CVSROOT/Vector/ParNet/task.c,v 1.1.1.1 1994/06/23 02:39:41 Barnard Exp $
*/

/*
** This code was originally written by Matthew Dillon and put into Public Domain
**
** All changes concerning the adaption of Matt's original code to the
** Vector Connection I/O board are © 1991-1994 by Henning Schmiedehausen
** All rights for this changes are reserved. The original code is Public Domain
**
** This code is distributed with the expressed written permission of Matthew
** Dillon (Thank you very much, Matt)
**
*/

/*
 *  TASK.C
 *
 *  -Accept packets to send to network
 *  -Receive data from network
 *
 *	    ParWrite(destaddr, buf, bytes)
 */

#include "defs.h"
#include "parnet_asm.h"

#include "task_protos.h"
#include "parnet_protos.h"

#include <proto/exec.h>

typedef struct {
    uword   Port;   /*	destination port    */
    uword   ChkSum; /*	data checksum	    */
    ulong   Bytes;  /*	# of bytes	    */
} Header;

char	DataBuf[MAXPKTSIZE];
Header	Hdr;
long	TLock[2] = { 0, 0 };
static	short Cnt = 0;

void
CParNetTask()
{
    long mask;
    Unit *unit;
    Packet *packet;
    long n;

    for (;;) {
        SetPIOInt();
	mask = Wait(SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
	LockAddr(TLock);
	if (mask & SIGBREAKF_CTRL_F) {      /*  packet pending  */
data:
	    if (ParDataReady() > 0) {
		n = ParReadV(&Hdr, sizeof(Hdr), DataBuf, MAXPKTSIZE, NULL, NULL);

		/*sprintf(StickyPort->DebugBuf, "%03d READ  %6ld", Cnt++, n);*/

		if (n >= sizeof(Hdr) && n >= sizeof(Hdr) + Hdr.Bytes) {
		    if (unit = FindUnitForPort(Hdr.Port)) {
			packet = AllocParPacket(NULL, unit, DataBuf, Hdr.Bytes, NULL, 0);
			LockAddr(unit->UnitLock);
			(*packet->io_Unit->DataFunc)('r', packet, n - sizeof(Hdr));
			UnlockAddr(unit->UnitLock);
		    }
		}
	    }
	}
	if (mask & SIGBREAKF_CTRL_E) {      /*  port            */
	    while (packet = (Packet *)GetMsg(&DevBase->Port)) {
		n = OutputPacket(packet);
		if (n == -2) {
		    Forbid();
		    AddHead(&DevBase->Port.mp_MsgList, (struct Node *)packet);
		    Permit();
		    goto data;
		}
	    }
	}
	UnlockAddr(TLock);
    }
}

OutputPacket(packet)
Packet *packet;
{
    long n;
    Unit *unit = packet->io_Unit;

    Hdr.Port  = packet->DestPort;
    Hdr.ChkSum= 0;
    Hdr.Bytes = packet->DLen1 + packet->DLen2;

    n = ParWriteV(packet->DestAddr, &Hdr, sizeof(Hdr), packet->Data1, packet->DLen1, packet->Data2, packet->DLen2, NULL, NULL);

    /* sprintf(StickyPort->DebugBuf, "%03d WRITE %6ld", Cnt++, n); */

    if (n == -2)                /*  can't write, pending rcv    */
	return(n);
    LockAddr(unit->UnitLock);
    if (n == sizeof(Hdr) + packet->DLen1 + packet->DLen2)
	(*unit->DataFunc)('w', packet, n - sizeof(Hdr));
    else
	(*unit->DataFunc)('W', packet, n - sizeof(Hdr));
    UnlockAddr(unit->UnitLock);
    return(n);
}


/*
 *  Queue packet for write.  If QUICKIO is requested and the packet can be
 *  sent manually it is, else it is queued to the task.
 */

void
QueuePacketForWrite(packet)
Packet *packet;
{
    Iob *iob = packet->iob;

    if ((iob->io_Flags & IOF_QUICK) && TryLockAddr(TLock) > 0) {
	if (OutputPacket(packet) != -2) {
	    UnlockAddr(TLock);
	    return;
	}
	/*
	 *  Can't write packet, rcv packet pending.
	 */
	UnlockAddr(TLock);
    }
    iob->io_Flags &= ~IOF_QUICK;
    iob->io_Flags |= IOF_QUEUED;
    PutMsg(&DevBase->Port, &packet->Msg);
}

