/*********************************************************************** 
* NOTICE
* All files contained on this disk are subject to the licensing conditions
* issued by MOTOROLA Inc.
*
* All files are copyright 1993 by MOTOROLA Inc. 
************************************************************************/


/********************************************************
 * File:	driver.c
 *
 * Description:
 *	This file contains the main loop of the driver module.
 *	The input queue of events is emptied each time.
 *
 * Routines:
 *	driver
 *	issue_cmd
 *
 * Author:
 *	Jonathan Masel
 ********************************************************/

#include "gct.h"
#include "modules.h"
#include "msg.h"
#include "quicc.h"
#include "status.h"
#include "bss.h"

#include "types.h"
#include "mng.h"
#include "mtypes.h"
#include "hdlc.h"




/********************************************************
 * routine:	driver
 *
 * description:
 *	This is the main loop of the QUICC driver module.
 *	Only one message is handled.
 *
 * arguments:
 *	h		points to the message header received
 *	drv		points to the child structure
 *	rom		the ROM address of the driver
 *
 * return code:
 *	0		do not re-enter (driver has been stopped)
 *	otherwise	call again after returning
 *
 * side effects:
 *
 ********************************************************/

driver()
{
	register HDR *h;
	register struct child *drv, *ch;
	GCT *gct;
	register BSS *bss;
	WORK_AREA *wa;

	GETGCT(gct);
	bss = gct->driver;
	drv = gct->driver->child;

	for(;;){
		if( !(h = (HDR *)(*gct->receive)(DRIVER, 0)) )
			continue;

		/*
		 * the subtype is the protocol event that
		 * has occured
		 * the id is the port for which the event
		 * has occurred.
		 * smac points to the sub-table of protocol
		 * according to the current state of the
		 * state machine.
		 */
		if( h->type & PRMTV ){
			if (h->id >= bss->max) {
				relm((HDR *)h);
				continue;
			}
			ch = drv + h->id;
			wa = (WORK_AREA *)(ch->work_area);
			if ( wa->more_flags & SCC_TTXRX ) {
				unsigned short	type;

				type = h->type;
				if( wa->more_flags & SCC_TTX ) {
					switch( type ) {
					case TX_REQ:
						tm_txreq(h, ch);
						continue;
					case TX_CONF:
						tm_conf(h, ch);
						continue;
					case TX_ERR:
						tm_txerr(h, ch);
						continue;
					case ABORT:
						tm_abort(h, ch);
						continue;
					}
				}
				if( wa->more_flags & SCC_TRX ) {
					switch( type ) {
					case RX_IND:
						tm_rxfr(h, ch);
						continue;
					case BUSY:
						tm_busy(h, ch);
						continue;
					}
				}
			}
			(*ch->smac[h->type & SUBTYPE])(h, ch);
		} else
			dr_req((MSG *)h);
	}
}


/********************************************************
 * routine:	issue_cmd
 *
 * description:
 *	Write the command to the QUICC's command register
 *
 * arguments:
 *	cmd		the required command
 *
 * return code:
 *	0		on success
 *	error code otherwise
 *
 * side effects:
 *
 ********************************************************/
issue_cmd(cmd, quicc)
unsigned short cmd;
volatile QUICC *quicc;
{
	register int i;
	register unsigned short *cr;

	cr = &quicc->cp_cr;
	/*
	 * wait for semaphore bit
	 */
	for(i = 0; i < CR_WAIT; i++)
		if( !((*cr) & CMD_FLAG) ){
			*cr = (cmd | CMD_FLAG);
			return(0);
		}
	return(SEMAPHORE_STUCK);
}


/********************************************************
 * routine:	driver_trace
 *
 * description:
 *	Send an event notification to the
 *	management module. This is used to
 *	trace the operations of the driver module.
 *
 * arguments:
 *	type		the action type taken by the driver
 *	id		the channel id
 *	par		a parameter (usually the address of
 *			a T_FRAME or R_FRAME).
 *
 * return code:
 *
 * side effects:
 *
 ********************************************************/

#define	DRIVER_MASK(ev)		(((unsigned short) 1) << \
				((ev) & SUBTYPE))
#define	min(i, j)		(i < j? i: j)

driver_trace(type, id, par)
{
	MSG *m;
	GCT *gct;
	EVENT_INFO *ev;
	GWA *gwa;
	T_FRAME *t;
	R_FRAME *r, *r1;
	QUICC_BD *b;
	int i, j, k;
	CHILD *child;
	extern MSG *getm();
	WORK_AREA *wa;

	GETGCT(gct);
	gwa = (GWA *)gct->driver->work_area;
	child = &gct->driver->child[id];
	wa = (WORK_AREA *)(child->work_area);
	if( !(gwa->trace_mask & DRIVER_MASK(type)) )
		return;
	m = getm(TRACE_EV, 0, 0, sizeof(EVENT_INFO)-EV_DATA_SIZE);
 	if (!m)
		return;

	ev = (EVENT_INFO *)m->param;
	ev->src = DRIVER;
	ev->dst = 0;
	ev->id = id;
	ev->type = type;
	ev->status = 0;
	ev->time = gct->time;
	ev->par = par;
	ev->data_length = 0;

	/*
	 * pass some data for R_FRAMEs and T_FRAMEs
	 */
	if( type == RX_IND ){
		r = (R_FRAME *)par;
		ev->dst = child->state >> 4;
		r1 = r->nextb;
		if( r->hdr.status == RECEIVE_ERROR )
			ev->status = (int)r->hdr.err_info & 0xffff;
		i = r->blen;
		if( r1 ) j = r1->blen;
		else j = 0;
		if( i > EV_DATA_SIZE )
			i = EV_DATA_SIZE;
		if( (i+j) > EV_DATA_SIZE )
			j -= ((i+j)-EV_DATA_SIZE);
		m->len += i + j;
		ev->data_length = i + j;
		for(k = 0; k < i; k++)
			ev->data[k] = r->buf[k+r->boff];
		if( r1 )
			for(k = 0; k < j; k++)
				ev->data[k+i] = r1->buf[k+r1->boff];
	} else if( type == TX_REQ ){
		t = (T_FRAME *)par;
		ev->dst = child->state >> 4;
		i = t->hsize - t->layer[0].hoff;
		j = t->bsize - t->layer[0].boff;
		if( i > EV_DATA_SIZE )
			i -= EV_DATA_SIZE;
		if( (i+j) > EV_DATA_SIZE )
			j -= ((i+j)-EV_DATA_SIZE);
		m->len += i + j;
		ev->data_length = i + j;
		for(k = 0; k < i; k++)
			ev->data[k] = t->hbuf[t->layer[0].hoff + k];
		for(k = 0; k < j; k++)
			ev->data[k+i] = t->buf[t->layer[0].boff + k];
	} else if( type == TX_ERR ){
		b = (QUICC_BD *)par;
		ev->status = b->status & wa->t_error;
		ev->dst = child->state >> 4;
	} else if( type == RX_ERROR ){
		b = (QUICC_BD *)par;
		ev->status = b->status & R_ERROR;
		ev->dst = child->state >> 4;
	}

	if( (*gct->send)(SYS_MNG, m) )
		relm((HDR *)m);
}

