/*********************************************************************** 
* 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:	smc_uart_r.c
 *
 * Description:
 *	The driver routines for handling receive
 *	on an UART port.
 *
 * Routines:
 *	smc_uart_rxfr
 *	smc_uart_busy
 *	smc_uart_rxbuf
 *
 * Author:
 *	Ofrit Lesser
 ********************************************************/


#include "gct.h"
#include "types.h"
#include "mtypes.h"
#include "msg.h"
#include "smc_uart.h"
#include "bss.h"
#include "quicc.h"
#include "status.h"



extern driver_trace(int type, int id, volatile int par);

/********************************************************
 * routine:	smc_uart_rxfr
 *
 * description:
 *	This is reached after being sent a RX_IND message
 *	by the interrupt routine (interrupt on QUICC
 *	receiving a complete UART frame).
 *	This is assumed to have occured after a
 *	non-rejected control character is received
 *	(this generates a UART_CCR interrupt). Note that
 *	this is only of relevance in the message (frame)
 *	oriented mode of operation: when the driver module
 *	is functioning in a character oriented mode of
 *	operation, the smc_uart_rxbuf routine will be called
 *	for each buffer of data received.
 *	The receive buffer table is flushed of all UART
 *	frames received: these frames are sent to the
 *	port's upper layer.
 *	The RX_IND message sent is only a 32-bit code (not an
 *	allocated MSG structure) and therefore must
 *	not be relm-ed. Its structure corresponds to
 *	the first 32-bits of a normal HDR structure.
 *
 * arguments:
 *	h		the event message received
 *	child		points to the child structure
 *
 * return code:
 *
 * side effects:
 *	Advance quicc_rbd each time a
 *	received buffer is collected.
 *	The ccr interrupt must be re-enabled after
 *	all received messages have been collected.
 *
 ********************************************************/
smc_uart_rxfr(h, child)
HDR *h;
CHILD *child;
{
	GCT *gct;
	register WORK_AREA *wa;
	register unsigned short status;		/* status of BD */
	register R_FRAME *r1, *r2;
			/* r1 = first r_frame in frame */
			/* r2 temporary */
	struct quicc_bd *nextBD;	/* next BD in frame */
	int flen;		/* accumulative frame length */
	MSG *m;
	extern MSG *getm();
	struct smc_regs	*regs;

	GETGCT(gct);
	wa = (WORK_AREA *)child->work_area;
	regs = (struct smc_regs *)wa->regs;

	/*
	 * clear event bit
	 * this clears indications of old (masked) events
	 */
	regs->smc_smce = (SMC_UART_RX | SMC_UART_BUSY);

	/*
	 * if receive is disabled,
	 * return immediately
	 */
	if( child->flags & RX_DISABLE )
		if( child->flags & RX_ACTIVATE )
			child->flags &= ~RX_ACTIVATE;
		else
			return;

	if( !wa->rx_q->nextb ){
		regs->smc_smcm |= SMC_UART_RX;
		return;
	}

	/*
	 * rbd address next BD for receive
	 */
	nextBD = wa->quicc_rbd;
	status = nextBD->status;
	r1 = wa->rx_q;
	flen = 0;
	while( !(status & R_E) ){
		/*
		 * first check that r1 has been
		 * linked to the rx BD table
		 */
		if( !(r1->flags & LINKED_TO_TABLE) )
			break;

		/*
		 * update status and length
		 * in new received frame,
		 * zero accumulative length
		 * for next frame
		 */
		r1->blen = nextBD->length;
		r1->flen = flen;	/* frame total length */
		r2 = r1->nextb;	/* for next frame */
		r1->nextb = 0;	/* no more buffs in this frame */

		driver_trace(RX_IND, r1->hdr.id, (int)r1);
		/*
		 * pass r_frame to upper layer
		 * (subject to error mask).
		 * buffers are linked via nextb
		 */
		if( status & R_ERROR ){
			driver_trace(RX_ERROR, r1->hdr.id, (int)nextBD);
			r1->hdr.status = RECEIVE_ERROR;
			r1->hdr.err_info = status & R_ERROR;
			wa->rerr_cnt++;
			if( (status&R_ERROR) & ~wa->rxerr_mask )
				smc_return_to_pool(r1, child);
			else
				if( (*gct->send)(child->upper, r1) )
					smc_return_to_pool(r1, child);
		} else
			if( (*gct->send)(child->upper, r1) )
				smc_return_to_pool(r1, child);

		/*
		 * prepare for next R_FRAME
		 */
		r1 = r2;	/* next R_FRAME for rx */

		wa->rcount++;

		/*
		 * advance rbd (to next Rx BD in table)
		 */
		if( status & R_W )
			nextBD = SMC_RBD_ADDR(wa);
		else
			nextBD++;


		wa->rfree++;
		wa->quicc_rbd = nextBD;

		status = nextBD->status;	/* update status */
	}

	wa->rx_q = r1;

	/*
	 * replenish the rx BD table
	 */
	status = smc_replenish_rxbd(child);
	if( status ){
		driver_trace(BUSY_IND, h->id, status);
		m = getm(BUSY_IND, h->id, 0, 0);
		if( m ){
			m->hdr.status = status;
			if( (*gct->send)( child->upper, m) )
				relm((HDR *)m);
		}
	}

	/*
	 * re-enable interrupts
	 * setting the mask will result in an interrupt
	 * if any frames were received during the time
	 * the mask was zero. therefore, frames will not
	 * go unnoticed if received after exiting the while
	 * loop above and before the mask bit is set.
	 */
	regs->smc_smcm |= SMC_UART_RX;
	if( !(child->flags & LOCAL_BUSY) )
		regs->smc_smcm |= SMC_UART_BUSY;
}



/********************************************************
 * routine:	smc_uart_rxbuf
 *
 * description:
 *	This routine is called upon reception of
 *	a RX_IND message. The message is sent from
 *	the UART interrupt routine when a receive buffer
 *	has been filled with data in the
 *	character oriented mode of operation.
 *	Note that the event message received is only
 *	a 32-bit value (not a pointer to a MSG structure
 *	which can be released).
 *	In order to handle each of the characters received,
 *	the rxchar routine is called (via the GCT).
 *
 * arguments:
 *	h		the event message received
 *	child		points to the child structure
 *
 * return code:
 *
 * side effects:
 *
 ********************************************************/
smc_uart_rxbuf(h, child)
register HDR *h;
CHILD *child;
{
	GCT *gct;
	register int i;
	register unsigned char *s;
	register WORK_AREA *wa;
	register struct quicc_bd *nextBD;		/* next BD */
	struct quicc_bd *bd;			/* temp */
	struct smc_regs	*regs;

	GETGCT(gct);
	wa = (WORK_AREA *)child->work_area;
	regs = (struct smc_regs *)wa->regs;

	/*
	 * clear event bit
	 * this clears indications of old (masked) events
	 */
	regs->smc_smce = (SMC_UART_RX | SMC_UART_BUSY);

	/*
	 * if receive is disabled,
	 * return immediately
	 */
	if( child->flags & RX_DISABLE )
		if( child->flags & RX_ACTIVATE )
			child->flags &= ~RX_ACTIVATE;
		else
			return;

	/*
	 * rbd address next BD for receive
	 */
	nextBD = wa->quicc_rbd;
	while( !(nextBD->status & R_E) ){
		if( !(nextBD->status & R_ERROR) ){
			/*
			 * handle all characters in this buffer
			 */
			i = nextBD->length;
			s = nextBD->buf;
			if( gct->rxchar )
				while( i-- )
					(*gct->rxchar)(*s++);
		}
		else
			driver_trace(RX_ERROR, child->key, (int)nextBD);

		/*
		 * advance rbd (to next Rx BD in table)
		 */
		bd = nextBD;
		if( nextBD->status & R_W )
			nextBD = SMC_RBD_ADDR(wa);
		else
			nextBD++;
		wa->quicc_rbd = nextBD;

		/*
		 * mark used BD as empty
		 * (available for use by QUICC)
		 * without destroying the wrap
		 * or external bits.
		 */
		bd->status &= R_W;
		bd->status |= (R_I | R_E);
	}

	/*
	 * re-enable interrupts
	 * setting the mask will result in an interrupt
	 * if any frames were received during the time
	 * the mask was zero. therefore, events will not
	 * go unnoticed if they occur after exiting the while
	 * loop above and before the mask bit is set.
	 */
	regs->smc_smcm |= SMC_UART_RX;
	if( !(child->flags & LOCAL_BUSY) )
		regs->smc_smcm |= SMC_UART_BUSY;
}

smc_uart_busy()
{
}
