
/*
 Copyright 1999 by Digi International (www.digi.com)

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the 
 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 PURPOSE.  See the GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*******************************************************************
 ***  Common data and defines shared between host and card.
 ***  #(@) $Id: newchan.h,v 1.14 1999/09/03 15:27:23 dickl Exp $
 *******************************************************************/


#ifndef _newchan_h_included
#define _newchan_h_included

#define NEWCHAN_H_VERSION "$Revision: 1.14 $" /* Automatically updated */

/*******************************************************************
 ***  event interrupt flags.
 *******************************************************************/

#define EV_BREAK        0x01            /* Break interrupt */
#define EV_TLW          0x02            /* Transmit low water */
#define EV_TEM          0x04            /* Transmitter empty */
#define EV_DATA         0x08            /* Receive data */
#define EV_INTSPEC      0x10            /* int on special char */
#define EV_MODEM        0x20            /* Modem change */

/*******************************************************************
 ***  Commands that can be sent to the board.
 ***  The presence of these defines does not imply that they are
 ***  implemented or supported on any given FEP.
 *******************************************************************/

#define SET_RxLOWWATER  0xE0
#define SET_RxHIGHWATER 0xE1
#define CMD_TxFLUSH     0xE2
#define CMD_TxPAUSE     0xE3
#define CMD_TxRESUME    0xE4
#define SET_XONXOFF_CA  0xE6
#define CMD_BREAK       0xE8
#define SET_MODEM       0xE9
#define SET_IFLAG       0xEA
#define SET_XONXOFF_C   0xEB
#define SET_TxLOWWATER  0xEC
#define CMD_RxPAUSE     0xEE
#define CMD_RxRESUME    0xEF
#define SET_BUFFER      0xF2
#define SET_COOKED      0xF3
#define SET_HFLOW       0xF4
#define SET_CFLAG       0xF5
#define SET_VNEXT       0xF6


/* 
It seems to me there are four distinct classes of things stuck in the
channel structure.   Let's divvy them up into four categories.

	* Data movement (we'll consider modem signals to be a degenerate
		case of data)

		in and out, start and max, ilow, iempty, mint, mstat, etc.

	* Mirrors of things the host gave us.
		cflag, flow control characters, tlow value,  etc.
		It's my position that these should become internal 
		to the FEP, since the host knows what value it gave 
		us.   Of course, for debugging (KME, X-ray, etc.)
		the driver writer will still be able to "see" them,
		but is discouraged from actually using them in code.

	* Things internal to the FEP that the driver almost 
          certainly doesn't want to know about.
		Internal state machines, pointers to service 
		functions, etc.   These are subject to change at
		the whim of the FEP staff and are likely to be kept
		cached.


Now, if we also recognize that:
	* caches are real, and they bring burst and coherency issues.
	* the entire respectable segment of the computing universe has 
	  moved past 16 bit interfaces  
	* We live in a world of multiprocessing and have already
	  recognized that each member needs to be written by only
	  one processor.  
it becomes more obvious the first two need to be divided into 
things written by the host and things written by the card.   We'll
remove the fixed address of the channel structure in shared RAM and
instead give the host a pointer to it.    All pointers will be zero
relative to shared RAM.


If we accept that we're all highly trained professionals and can
write a header file that's useful to the firmware and all the host
OSes, this task becomes easier.   Of course, the structure should
essentially remain the same between firmware releases, clinging to
a current size when possible to avoid forcing a driver recompilation
but we should be able to minimize this need.

It's up to the native environment to offer typedefs for each type.  Only
you know what size your native types are, what methods you wish to define,
which operators you wish to overload, and so on.

Why nested structures?   Becuase this allows a really clever way to handle
these shared structures in systems with write-through caches or on systems
like Alpha.   It allows you to access the structures, then invalidate only
the subset of the shared structure that you just wrote and minimizes the
number of cache lines that have to be retired.   It also allows/enforces
a better concept of who "owns" each member.   The host can then better 
tinker with access methods such as volatility or caching style.
I've looked at compiler handling on this under OpenServer/Unixware cc,
mips64-elf gcc, and believe that this construct allows good code 
generation.

I've assumed you have familiarity with the current channel structure.
This saved me time thinking about comments.


Todo: 
   Total size, offsets, internal data, etc. will just magically fall into
       place as this takes form.   
    Can we do away with the "mirrors" stuff?  OK.  The driver gives the
	board a flow control character.   Does the driver really need to
        ask the board what flow control character is set?   I'd much
	rather this be kept in the internal area. 
    Reconsider typedefs, perhaps allowing some to be volatile and some
	not to be volatile.

*/

#define FEP_MAGIC       	('c' + ('h'<<8) + ('a'<<16) + ('n'<<24))
#define GLOBAL_MAGIC		('g' + ('l'<<8) + ('b'<<16) + ('l'<<24))

struct fep6channel_t 
{
#if defined (__cplusplus)
	inline uint32 tbuf_space() 
	{ 
		return (this->fep.tout - this->host.tin - 1) & fep_info.tmask ; 
	}

	inline uint32 rbuf_space()
	{
		return (this->host.rout - this->fep.rin - 1) & this->fep_info.rmask ;
	}

	inline uint32 tbuf_bytes_queued()
	{
		return (this->host.tin - this->fep.tout ) & this->fep_info.tmask ;
	}

	inline uint32 rbuf_bytes_queued() 
	{ 
		return (this->fep.rin - this->host.rout ) & fep_info.rmask ; 
	}

#endif /* __cplusplus */
	struct fep_info {
	
	shared_uint32	magic; /* cookie so we knows it's a channel structure */
	shared_uint32 	port_capabilities ; /* enum or bitfield or something */
	shared_uint32	tbuf;	/* offset to start of tx buffer */
	shared_uint32	tmask;	/* power of two -1 */

	shared_uint32	rbuf;	/* offset to start of rx buf */
	shared_uint32	rmask;	/* power of two - 1 */
	shared_uint32	chnum;	/* channel number */
	shared_uint32	padding[1] ; 

	} fep_info ;
/* Alignment, padding */

	/* DATA Things written frequently, but only by the FEP */
	struct fep_t {
	shared_uint32	tout;	/* characters are removed from here */
	shared_uint32	tbusy;	/* non-zero means tx is pending */
	shared_uint32	rin;	/* characters are added to here */
	shared_uint32	mstat;	/* Current modem status */

	shared_uint32	padding[4] ; 
	} fep ;

/* Alignment, padding */
	/* DATA Things written frequently, but only by the host */
	struct host_t {
	shared_uint32	tin ;		/* tx data inserted in buf here */
	shared_uint32	rout ;		/* rx data removed from buf here */
	shared_uint32	mint ;		/* non-zero = int on modem changes */
	shared_uint32	iempty ; 	/* non-zero = Int on tx empty */

	shared_uint32	ilow ; 		/* non-zero = int on tx low */
	shared_uint32	idata ;		/* non-zero = int on rx present */
	shared_uint32	padding[2] ; 
	
	} host ;
	
/* Alignment, padding */
	/* Mirroring, internally cached stuff */
	
	struct private_t {
	uchar *		tbuf ; 
	uchar *		rbuf ; 
	uint		tmask ;		/* Cached, non-byteswapped version */
	uint		rmask ;		/* Cached, non-byteswapped version */

	uint		rlow ;		/* Rx low water mark */
	uint		rhigh ;		/* Rx high water mark */
	uint		tlow;		/* Tx low water mark */
	uint  		event_flags ; 	/* Queued events to send to PC */

	uchar		loopback_mode ;	/* From the liquor cabinet */
	uchar		_padding[3] ;	/* */
	uint32		lastin ;	/* Last rx in pointer in event loop */
	int 		edelay ; 	/* Number of Ms to queue rx events */
#if __cplusplus   /* FIXME: Kludge alert */
	TIME 		etime ; 	/* Last rx event time */
#else
	uint 		etime ; 	/* Last rx event time */
#endif
	uint		nbeers ; 	/* Current beer count */
	uint32		___padding[3] ; 

	} internal  ;
	
} ;

/* We can then go through a similar exercise making the commands and events
32-bit aware and do completely away with the whole extended channel 
structure kludge imposed by FEP5Plus. */


struct fep_event
{
	shared_uint8	chan ;
	shared_uint8	flags ;
	shared_uint8	mstat ;	
	shared_uint8	lstat ;
} ;

struct fep_command
{
	shared_uint8	cmd;
	shared_uint8	chan;
	union 
	{
		volatile uint16	hword;
		volatile uint8	byte[2];
	} data ;
} ;

struct q_desc
{
	shared_uint32	in;	/* Data goes into the q at this index */
	shared_uint32 	out;	/* Data pulled from the que at this index */	
	shared_uint32 	start;	/* Offset to where the queue starts */
	shared_uint32 	max;	/* If [in|out] == max, wrap to zero */
} ;

#if 0
#define GLOBAL_FEP_DATA_OFFSET 0x20

struct global_fep_data
{
	shared_uint32	magic ; /* Suitable for assertions, debuggers */
	shared_uint32	status ; /* running, initializing, failed, etc. */
	shared_uint32	chan ;  /* channel structures start here */
	shared_uint32	npayload_chans ;   /* Count of data chanels. */
	shared_uint32	ncontrol_chans ;   /* Count of additional channels */
	struct fep6_channel * command_chan ; /* Pointer to tcl command chan */
	shared_uint32	rw ;		/* Points to KME structure */
	shared_uint32	command_q ;     /* was "0xd10" */
	shared_uint32	event_q ;       /* was "0xd18" */
	shared_uint32	panic ;       	/* pointer to panic structure */
	shared_uint32	newchan_version ;     	/* pointer to panic structure */
} ; 
#endif

#define LOOP_NONE	0
#define LOOP_BEER	1
#define LOOP_LUSH	2
#define LOOP_VOMIT	3
#define LOOP_LOOSE_LUSH	4

#endif /* _newchan_h_included */
