/*--------------------------------------------------------------------------*/
/*	File name:	ETHER.C							Revision date:	2000.11.08	*/
/*	Revised by:	Ulf Ronald Andersson			Revision start:	2000.11.08	*/
/*	Created by: Vassilis Papathanassiou			(RTL part)		1999.04.08	*/
/*		and:	Peter Rottengatter 				(HL driver)		1998.01.26	*/
/*--------------------------------------------------------------------------*/
/*	Project:	EtherNet Network Interface									*/
/*	Module:		Installation and activation of port driver					*/
/*--------------------------------------------------------------------------*/
#include <tos.h>
#include <stdio.h>
#include <string.h>
/*--------------------------------------------------------------------------*/
#include <sting\transprt.h>
#include <sting\port.h>
/*--------------------------------------------------------------------------*/
#include "rtl_8012.h"
/*--------------------------------------------------------------------------*/
#ifdef RTL_8012
	char	*RTL_TYPE = "RTL 8012";
#else
	char	*RTL_TYPE = "RTL 8002";
#endif
/*--------------------------------------------------------------------------*/
#define	M_NAME		"EtherNet"
#define	M_VERSION	"01.03"
#define	M_YEAR		2000
#define	M_MONTH		11
#define	M_DAY		8
#define	M_AUTHOR	"STinG Evolution Team"
/*--------------------------------------------------------------------------*/
int16          xmit_dgram (IP_DGRAM *dgram, BAB *txbab);
int16          fetch_dgram (IP_DGRAM **dgram);
void           recve_dgram (void);
void           deplete_queue (IP_DGRAM **queue);
void           arp_init (void);
/*--------------------------------------------------------------------------*/
long           check_hardware (void);
long           cache_on (void);
long           cache_off (void);
int            bus_error (void);
long           berr_off (void);
/*--------------------------------------------------------------------------*/
int            get_cookie (long which, long *value);
long           read_cookie (void);
void           install (void);
void    cdecl  my_send (PORT *port);
void    cdecl  my_receive (PORT *port);
int16   cdecl  my_set_state (PORT *port, int16 state);
long           create_rtl_structs (void);
long           check_start (void);
long           finish_start (void);
long			stop_Ether (void);
int16   cdecl	my_cntrl (PORT *port, uint32 argument, int16 code);
int				fetch_addresses (int type);
void			NIC_make_table(void);
short			chk_packet (void);
void 			Set_Ether_ID(void);
void			Stop_RTL(void);
/*--------------------------------------------------------------------------*/
DRV_LIST  *sting_drivers;
TPL       *tpl;
STX       *stx;
PORT      my_port   = {  M_NAME, L_SER_BUS, FALSE, 0L, 0xffffffffUL, 0xffffffffUL,
                         1500, 1500, 0L, NULL, 0L, NULL, 0, NULL, NULL  };
DRIVER	my_driver = {  my_set_state, my_cntrl, my_send, my_receive,
			M_NAME, M_VERSION, ((M_YEAR - 1980) << 9) | (M_MONTH << 5) | M_DAY,
			M_AUTHOR, NULL, NULL   };

BAB		xmit_bab[2], *this_xmit, recve_bab[2], *this_recve;
long	cookie, _cpu;
uint8	address[6];
uint16	ck_flag, gtype;
void	*memory = NULL;
char	*hardware[6];
char	fault[] = "ETHER_PA.STX : STinG extension module. Only to be started by STinG !\r\n";
char	testmem[ sizeof (VIRT_INIT) ];
char	my_buf[ 4096 ];		/* 2 * maximum RTL send packet */
/*--------------------------------------------------------------------------*/
void  main (int	argc, char  *argv[])
{
	if (argc != 2)
	{
		Cconws (fault);   return;
	}
	if (strcmp (argv[1], "STinG_Load") != 0)
	{
		Cconws (fault);   return;
	}

	if (! get_cookie ('STiK', (long *) & sting_drivers))
		return;

	if (sting_drivers == 0L)
		return;
	if (strcmp (sting_drivers->magic, MAGIC) != 0)
		return;

	tpl = (TPL *) (*sting_drivers->get_dftab) (TRANSPORT_DRIVER);
	stx = (STX *) (*sting_drivers->get_dftab) (MODULE_DRIVER);

	NIC_make_table();

	if (tpl != (TPL *) NULL && stx != (STX *) NULL)
	{
		install();
		Ptermres (_PgmSize, 0);
	}
}
/*--------------------------------------------------------------------------*/
int  get_cookie (long  which, long  *value)
{
	cookie = which;
	*value = Supexec (read_cookie);

	return (ck_flag);
}
/*--------------------------------------------------------------------------*/
long  read_cookie (void)
{
	long  *work;

	ck_flag = FALSE;

	if (* (long **) 0x5a0L == NULL)
		return (0L);

	for (work = * (long **) 0x5a0L; *work != 0L; work += 2)
		if (*work == cookie)
		{
			ck_flag = TRUE;
			return (*++work);
		}

	return (-1L);
}
/*--------------------------------------------------------------------------*/
void  install (void)
{
	PORT	*ports;
	DRIVER	*driver;

	if (! get_cookie ('_CPU', & _cpu))
		_cpu = 0;
	_cpu = (_cpu >= 20) ? 1 : 0;

	query_chains ((void **) & ports, (void **) & driver, NULL);

	(my_port.driver = & my_driver)->basepage = _BasPag;

	while (ports->next)
		ports = ports->next;

	ports->next = & my_port;

	while (driver->next)
		driver = driver->next;

	driver->next = & my_driver;

	hardware[0] = "No selection";	hardware[1] = RTL_TYPE;	hardware[2] = NULL;
}
/*--------------------------------------------------------------------------*/
void  cdecl  my_send (PORT  *port)
{
	IP_DGRAM  *dgram;

	if (port != & my_port || my_port.active == 0)
		return;

	while (1)
	{
		if (fetch_dgram (& dgram) == FALSE)
			return;
		if (! xmit_dgram (dgram, this_xmit))
			continue;
	/*	this_xmit = this_xmit->next_bab;	*//* Only for retransmiting */
	}
}
/*--------------------------------------------------------------------------*/
void  cdecl  my_receive (PORT  *port)
{
	if (port != & my_port || my_port.active == 0)
		return;

	while ( chk_packet() )
		recve_dgram ();
}
/*--------------------------------------------------------------------------*/
int16  cdecl  my_set_state (PORT   *port, int16  state)
{
	int32  now;

	if (port != & my_port)   return (FALSE);

	if (state)
	{
		if (Supexec (check_hardware) == FALSE)
			return (FALSE);
		Supexec (cache_off);
		Supexec (create_rtl_structs);
		now = TIMER_now();
		while (TIMER_elapsed (now) < 500 && Supexec (check_start) == 0);
		now = Supexec (finish_start);
		Supexec (cache_on);
		if (now == FALSE)
			return (FALSE);
		arp_init();
	}
	else
	{
		Supexec (stop_Ether);
		deplete_queue (& my_port.send);
		deplete_queue (& my_port.receive);
	}

	return (TRUE);
}
/*--------------------------------------------------------------------------*/
long  create_rtl_structs (void)
{
	VIRT_INIT	*init;
	uint8		*buffer = my_buf;
	int16		count, length = 2048;

	init = (VIRT_INIT *) memory;
	for (count = 0; count < 2; count++)
	{
		xmit_bab[count].data = (ETH_HDR *) buffer;
		xmit_bab[count].next_bab = & xmit_bab[(count < 1) ? count + 1 : 0];
		buffer += length;
    }

	this_xmit = & xmit_bab[0];
	this_recve = & recve_bab[0];	/* dummy */

	init->mode = 0;
	memcpy (address, &init->addr[0], 6 );
	Set_Ether_ID();
	init->ladrf[0] = 0;   init->ladrf[1] = 0;		/* No multicast filter */

	return (0L);
}
/*--------------------------------------------------------------------------*/
long  check_start()
{
	return	(0x0100);
}
/*--------------------------------------------------------------------------*/
long  finish_start()
{
	this_recve = & recve_bab[0];
	this_xmit = & xmit_bab[0];

	return (TRUE);
}
/*--------------------------------------------------------------------------*/
long  stop_Ether(void)
{
	this_recve = & recve_bab[0];
	this_xmit = & xmit_bab[0];
	Stop_RTL();
	return (0L);
}
/*--------------------------------------------------------------------------*/
int16  cdecl  my_cntrl (PORT *port, uint32 argument, int16  code)
{
	int16  *arr, result = E_NORMAL;
	static int16  type = -1;

	if (port != & my_port)
		return (E_PARAMETER);

	if (bus_error())
	{
		berr_off();
		return (E_UNREACHABLE);
	}

	switch (code)
	{
	case CTL_ETHER_SET_MAC :
		if (memory)
			memcpy (& ((VIRT_INIT *) memory)->addr[0], (uint8 *) argument, 6);
		break;
	case CTL_ETHER_GET_MAC :
		if (memory)
			memcpy ((uint8 *) argument, & ((VIRT_INIT *) memory)->addr[0], 6);
		break;
	case CTL_ETHER_INQ_SUPPTYPE :
		*((char ***) argument) = & hardware[0];
		break;
	case CTL_ETHER_SET_TYPE :
		if (fetch_addresses (type = (argument & 7)) == FALSE)
			result = E_PARAMETER;
		break;
	case CTL_ETHER_GET_TYPE :
		*((int16 *) argument) = type;
		break;
	default :
		result = E_FNAVAIL;
	}

	berr_off();

	return (result);
}
/*--------------------------------------------------------------------------*/
int  fetch_addresses (int type)
{
	int   result = TRUE;
	long  machine;

	switch (type)
	{
	case 0 :
		memory = testmem;
		break;
	case 1 :
		memory = testmem;
		break;
	default :
		result = FALSE;
	}

	gtype = type;

	return (result);
}
/*--------------------------------------------------------------------------*/
/*	End of file:	ETHER.C													*/
/*--------------------------------------------------------------------------*/
