#ident "$Id: sloop_str.c,v 1.6 1997/10/21 20:48:32 gary Exp $"
/*****************************************************************************
 * Copyright (c) 1988-95 Digi International Inc., All Rights Reserved
 * 
 * This  software  contains  proprietary  and  confidential   information   of
 * Digi International  Inc.   By  accepting  transfer  of this copy, Recipient
 * agrees to retain this software in  confidence,  to  prevent  disclosure  to
 * others,  and  to make no  use of this software other than that for which it
 * was delivered.  This is an unpublished copyright work  Digi   International
 * Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is
 * strictly prohibited.
 * 
 * Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc.
 * Confidential  when   combined   with   the   aggregated  modules  for  this
 * product) OBJECT CODE ONLY SOURCE MATERIALS
 * 
 * (C) COPYRIGHT Digi International Inc. 1995
 * 
 * All Rights Reserved
 * 
 * US   Government   Users   Restricted   Rights   -   Use,   duplication   or
 * disclosure  restricted by GSA ADP Schedule Contract with Digi International
 * Inc.
 * 
 *****************************************************************************/


/******************************************************************
 *
 *  Embedded STREAMS Package
 *
 *  Copyright 1991  Spider Systems Limited
 *
 *  SLOOP_STR.C
 *
 *  Streams Loopback Driver
 *
 ******************************************************************/

/*
 *	 /redknee5/projects/tcp/PBRAIN/SCCS/pbrainE/dev/embed/sloop/0/s.sloop_str.c
 *	@(#)sloop_str.c	1.3
 *
 *	Last delta created	14:33:45 12/9/91
 *	This file extracted	15:46:45 4/27/92
 *
 *	Modifications:
 *
 *	GSA	19 Sep 91	New file created
 *
 */


#ifndef NULL
#define NULL 0
#endif

#include "types.h"
#include "stream.h"
#include "sloop.h"

#define NAME	"sloop"	/* the stream name */
#define HIWAT	0x400	/* Hi water mark */
#define LOWAT	0x100	/* Lo water mark */
#define SLOOP_STID  222	/* Stream driver id */

extern struct user u;

static struct module_info minfo = {
	SLOOP_STID, NAME, 0, INFPSZ, HIWAT, LOWAT
};

int sloopopen(), sloopclose(), sloopuwput(), sloopuwsrv();

static struct qinit rinit = {
	NULL, NULL, sloopopen, sloopclose, NULL, &minfo, NULL
};

static struct qinit winit = {
	sloopuwput, sloopuwsrv, NULL, NULL, NULL, &minfo, NULL
};


struct streamtab sloopinfo = { &rinit, &winit, NULL, NULL };

/*
 * variables set in the space.c file 
 */

extern int sloop_maxdevs;
extern mblk_t *getq();

/*
 * SLOOPINIT - no-op?
 */
/******************************************************************/
void sloopinit()
/******************************************************************/
{
}

/* 
 * SLOOPOPEN - SLOOP device open routine
 */
/******************************************************************/
/* ARGSUSED */
int sloopopen(q, dev, fl, sfl)
/******************************************************************/
queue_t *q;
int dev;
int fl, sfl;
{
	/*
	 * Sloop works on pairs of devices. Pairs have the same minor
	 * device number except for the low bit.
	 * Either may open first;  data transfers are not permitted
	 * until both sides are in place
	 */

	struct sloopdev *od;

#ifdef DEBUG
printf("Sloop open %x %x %x %x\n", q, dev, fl, sfl);
#endif /* DEBUG */

	if ((sfl == MODOPEN) || (sfl == CLONEOPEN))
		return(OPENFAIL);

	dev = minor(dev);
	if (dev >= sloop_maxdevs)
		return (OPENFAIL);
	
#ifdef DEBUG
printf("dev %d: q %x\n", dev, q);
#endif /* DEBUG */

	/* Hook up q_back and q_can to the stream head to allow 
	 * shget() to back enable us.
	 */
	q->q_next->q_back = WR(q);
	q->q_next->q_can = q->q_next;
	return(dev);
}

/* 
 * SLOOPCLOSE - SLOOP device close routine
 */
/******************************************************************/
/* ARGSUSED */
int sloopclose(q,fl)
/******************************************************************/
queue_t *q;
int fl;
{
	q->q_next->q_back = (queue_t *)0;
	q->q_next->q_can = (queue_t *)0;
	return 1;
}


/*
 * SLOOPUWPUT - SLOOP Upper Write Put Procedure
 *
 * Called from Network Module Write Service Procedure or 
 * from the Daemon stream head.
 */
/******************************************************************/
int sloopuwput(q, mp)
/******************************************************************/
queue_t *q;
mblk_t *mp;
{

#ifdef DEBUG
printf("Sloopuwput(%x %x[%x: %x])\n", q, mp, 
	mp->b_datap->db_type, mp->b_wptr - mp->b_rptr);
#endif /* DEBUG */
	
	switch(mp->b_datap->db_type) {
		
	case M_FLUSH:

		if(*mp->b_rptr & FLUSHW)
			flushq(q, FLUSHDATA);

		if(*mp->b_rptr & FLUSHR)
		{
			flushq(RD(q), FLUSHDATA);
			*mp->b_rptr &= ~FLUSHW;
			qreply(q, mp);
		} else
			freemsg(mp);
		break;


	case M_DATA:
	case M_PROTO:
	case M_PCPROTO:
		{
			/* check if queue in use (q_first != 0), and if so
			 * use queue to avoid re-ordering output data */

			if ((canput(RD(q)->q_next) == 0) || (q->q_first != 0)) 
			{
#ifdef DEBUG
printf("putq in sloopuwput 0x%x\n", q);
#endif /* DEBUG */
				putq(q, mp);
			} 
			else
			{
#ifdef DEBUG
printf("qreply in sloopuwput 0x%x\n", q);
#endif /* DEBUG */
				qreply(q, mp);
			}
			break;
		}

	case M_IOCTL:
	   {
		struct iocblk FAR *iocp = (struct iocblk FAR *)(mp->b_rptr);
	
		switch((int)iocp->ioc_cmd)
		{
		case I_LINK:
			printf("LINK ioctl\n");

			printf("Ioctl OK\n");
			mp->b_datap->db_type = M_IOCACK;
			qreply(q, mp);
			break;

		default:
			printf("ioctl %x - unknown\n", iocp->ioc_cmd);
			mp->b_datap->db_type = M_IOCNAK;
			qreply(q, mp);
			break;
		}
	    }
	    break;


	default:
	    {
#ifdef DEBUG
printf("Unknown Message in sloopuwput\n");
#endif /* DEBUG */
		freemsg(mp);
		return 1;
		break;
	    }
	}

	return 1 ;
}

/*
 * SLOOPUWSRV - SLOOP Upper Write Service Procedure
 */
/******************************************************************/
int sloopuwsrv(q)
/******************************************************************/
queue_t *q;
{
	mblk_t *mp;

#ifdef DEBUG
printf("sloopuwsrv q=0x%x\n", q);
#endif /* DEBUG */
	while (mp = getq(q))
	{
		if (canput(RD(q)->q_next))
		{
#ifdef DEBUG
printf("uwsrv: qreply\n"); 
#endif /* DEBUG */
			qreply(q, mp);
		}
		else
		{
#ifdef DEBUG
printf("uwsrv: putbq\n"); 
#endif /* DEBUG */
			putbq(q, mp);
			return 1;
		}
	}
	return 1 ;
}
