/* Access I/O port for CC/NET */

#include    <stdio.h>
#include    <sys/io.h>
/*#include     <asm/io.h>*/ 
#include	<string.h>
#include	"ErrCode.h"

//-----Test result place----
#define LOGDIR	"/tmp/"
#define LOGEXT	".log"

//-----I/O Address-----
#define BASE_ADDR	0xe800

#define ADDR_TX_LDT	0x00	//lower 32bitData
#define ADDR_TX_UDT	0x04	//upper 32bitData
#define ADDR_TX_CTL	0x08	//Control
#define ADDR_TX_STA 0x0C	//Status
#define ADDR_TX_MAR	0x10	//Master mode Address
#define ADDR_TX_FPR	0x14	//Frame preset
#define ADDR_TX_FCR	0x18	//Frame count register
#define ADDR_TX_CNT	0x1C	//FIFO count

#define ADDR_RX_LDT	0x20	//lower 32bitData
#define ADDR_RX_UDT	0x24	//upper 32bitData
#define ADDR_RX_CTL	0x28	//Control
#define ADDR_RX_STA 0x2C	//Status
#define ADDR_RX_MAR	0x30	//Master mode Address
#define ADDR_RX_FPR	0x34	//Frame preset
#define ADDR_RX_FCR	0x38	//Frame count register
#define ADDR_RX_CNT	0x3C	//FIFO count

#define ADDR_SYSTEM	0x40	//system

//-----for Interruption handling----
#define ADDR_IR_LDT	0x60	//lower 32bitData
#define ADDR_IR_UDT	0x64	//upper 32bitData
#define ADDR_IR_CTL	0x68	//Control
#define ADDR_IR_STA 0x6C	//Status

#define ADDR_IR_CNT	0x7C	//FIFO count



//-----64bit frame-----
struct FRAME
{
	unsigned long code, data;
};


//-----Dataway status-----
struct DATAWAYSTAT
{
	unsigned char N;
	unsigned char A;
	unsigned char F;
	unsigned char Q;
	unsigned char X;
	unsigned char Z;
	unsigned char C;
	unsigned char I;
	unsigned char B;
};


//-----Dataway status-----
struct PCIREG
{
	unsigned short txldt_u, txldt_l;
	unsigned short txudt_u, txudt_l;
	unsigned short txctl_u, txctl_l;
	unsigned short txsta_u, txsta_l;
	unsigned short txmar_u, txmar_l;
	unsigned short txfpr_u, txfpr_l;
	unsigned short txfcr_u, txfcr_l;
	unsigned short txcnt_u, txcnt_l;
	
	unsigned short rxldt_u, rxldt_l;
	unsigned short rxudt_u, rxudt_l;
	unsigned short rxctl_u, rxctl_l;
	unsigned short rxsta_u, rxsta_l;
	unsigned short rxmar_u, rxmar_l;
	unsigned short rxfpr_u, rxfpr_l;
	unsigned short rxfcr_u, rxfcr_l;
	unsigned short rxcnt_u, rxcnt_l;
	
	unsigned short system_u, system_l;

	unsigned short irldt_u, irldt_l;
	unsigned short irudt_u, irudt_l;
	unsigned short irctl_u, irctl_l;
	unsigned short irsta_u, irsta_l;
	unsigned short ircnt_u, ircnt_l;
};




/* Error log file creation */
int create_logfile(char* pszFName, char* pszMsg)
{
	char szPathNameExt[0xFF];
	memset(szPathNameExt, 0x00, sizeof(szPathNameExt) );
	
	if ( strlen(LOGDIR)+strlen(pszFName)+strlen(LOGEXT)+1 > 0xFF ) return ERR_FNAME;
	strcpy( szPathNameExt, LOGDIR );
	strcat( szPathNameExt, pszFName );
	strcat( szPathNameExt, LOGEXT );
	
	FILE* fp;
	fp = fopen(szPathNameExt, "a");
	fprintf( fp, pszMsg );
	fclose(fp);
	
	return NO_ERR;
}


/* for TestModule... (special function) */
int DecTM(struct DATAWAYSTAT* dataway, unsigned long data)
{
	dataway->N = (data & 0x0000001F) +1;
	dataway->F = (data & 0x000003E0)>>5;
	dataway->A = (data & 0x00003C00)>>10;
	dataway->Q = (data & 0x00010000)>>16;
	dataway->X = (data & 0x00020000)>>17;
	dataway->Z = (data & 0x00040000)>>18;
	dataway->C = (data & 0x00080000)>>19;
	dataway->I = (data & 0x00100000)>>20;
	dataway->B = (data & 0x00200000)>>21;
	
	return 0;
}


//-------I/O address directly access--------
/* dump */
int dump_reg(struct PCIREG* reg)
{
	if ( iopl(3) )	return ERR_PRIV;

	unsigned long tmp;
/*
	tmp = inl(BASE_ADDR+ADDR_TX_LDT);
	reg->txldt_u = (tmp>>16)&0x0000FFFF;
	reg->txldt_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_TX_UDT);
	reg->txudt_u = (tmp>>16)&0x0000FFFF;
	reg->txudt_l = tmp & 0x0000FFFF;
*/	
	tmp = inl(BASE_ADDR+ADDR_TX_CTL);
	reg->txctl_u = (tmp>>16)&0x0000FFFF;
	reg->txctl_l = tmp & 0x0000FFFF;

	tmp = inl(BASE_ADDR+ADDR_TX_STA);
	reg->txsta_u = (tmp>>16)&0x0000FFFF;
	reg->txsta_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_TX_MAR);
	reg->txmar_u = (tmp>>16)&0x0000FFFF;
	reg->txmar_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_TX_FPR);
	reg->txfpr_u = (tmp>>16)&0x0000FFFF;
	reg->txfpr_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_TX_FCR);
	reg->txfcr_u = (tmp>>16)&0x0000FFFF;
	reg->txfcr_l = tmp & 0x0000FFFF;

	tmp = inl(BASE_ADDR+ADDR_TX_CNT);
	reg->txcnt_u = (tmp>>16)&0x0000FFFF;
	reg->txcnt_l = tmp & 0x0000FFFF;
	


/*
	tmp = inl(BASE_ADDR+ADDR_RX_LDT);
	reg->rxldt_u = (tmp>>16)&0x0000FFFF;
	reg->rxldt_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_RX_UDT);
	reg->rxudt_u = (tmp>>16)&0x0000FFFF;
	reg->rxudt_l = tmp & 0x0000FFFF;
*/	
	tmp = inl(BASE_ADDR+ADDR_RX_CTL);
	reg->rxctl_u = (tmp>>16)&0x0000FFFF;
	reg->rxctl_l = tmp & 0x0000FFFF;

	tmp = inl(BASE_ADDR+ADDR_RX_STA);
	reg->rxsta_u = (tmp>>16)&0x0000FFFF;
	reg->rxsta_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_RX_MAR);
	reg->rxmar_u = (tmp>>16)&0x0000FFFF;
	reg->rxmar_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_RX_FPR);
	reg->rxfpr_u = (tmp>>16)&0x0000FFFF;
	reg->rxfpr_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_RX_FCR);
	reg->rxfcr_u = (tmp>>16)&0x0000FFFF;
	reg->rxfcr_l = tmp & 0x0000FFFF;

	tmp = inl(BASE_ADDR+ADDR_RX_CNT);
	reg->rxcnt_u = (tmp>>16)&0x0000FFFF;
	reg->rxcnt_l = tmp & 0x0000FFFF;
	



	tmp = inl(BASE_ADDR+ADDR_SYSTEM);
	reg->system_u = (tmp>>16)&0x0000FFFF;
	reg->system_l = tmp & 0x0000FFFF;



/*
	tmp = inl(BASE_ADDR+ADDR_IR_LDT);
	reg->irldt_u = (tmp>>16)&0x0000FFFF;
	reg->irldt_l = tmp & 0x0000FFFF;
	
	tmp = inl(BASE_ADDR+ADDR_IR_UDT);
	reg->irudt_u = (tmp>>16)&0x0000FFFF;
	reg->irudt_l = tmp & 0x0000FFFF;
*/	
	tmp = inl(BASE_ADDR+ADDR_IR_CTL);
	reg->irctl_u = (tmp>>16)&0x0000FFFF;
	reg->irctl_l = tmp & 0x0000FFFF;

	tmp = inl(BASE_ADDR+ADDR_IR_STA);
	reg->irsta_u = (tmp>>16)&0x0000FFFF;
	reg->irsta_l = tmp & 0x0000FFFF;
	

	tmp = inl(BASE_ADDR+ADDR_IR_CNT);
	reg->ircnt_u = (tmp>>16)&0x0000FFFF;
	reg->ircnt_l = tmp & 0x0000FFFF;
	

	return NO_ERR;
}


/* FIFO clear */
int clr_fifo()
{
	if ( iopl(3) )	return ERR_PRIV;

	outl( 0x00070002, BASE_ADDR + ADDR_TX_CTL );
	outl( 0x003F0002, BASE_ADDR + ADDR_RX_CTL );
	outl( 0x00010002, BASE_ADDR + ADDR_IR_CTL );

	outl( 0x00000000, BASE_ADDR + ADDR_TX_CTL );
	outl( 0x00000000, BASE_ADDR + ADDR_RX_CTL );
	outl( 0x00000000, BASE_ADDR + ADDR_IR_CTL );

	return NO_ERR;
}


/*Tx a frame */
int put_frame(struct FRAME cmd)
{
	if ( iopl(3) )	return ERR_PRIV;
	

	outl( cmd.data, BASE_ADDR+ADDR_TX_LDT );
	outl( cmd.code, BASE_ADDR+ADDR_TX_UDT );

	unsigned char wcnt=0;
	while (++wcnt)
	{
		if (inl(BASE_ADDR+ADDR_TX_STA)&0x00000001 )	return NO_ERR;
		if (inl(BASE_ADDR+ADDR_TX_STA)&0x00000002 ) break;
	}

	return ERR_TXTOUT;
}


/* Rx a frame */
int get_frame(struct FRAME* rpl)
{
	if ( iopl(3) )	return ERR_PRIV;

	if ( (inl(BASE_ADDR+ADDR_RX_CNT)&0xffffff) < 2 ) return ERR_EMP;

	rpl->data = inl( BASE_ADDR+ADDR_RX_LDT );
	rpl->code = inl( BASE_ADDR+ADDR_RX_UDT );
	
//	if ( (inl(BASE_ADDR+ADDR_RX_STA)&0x00000001)==0 ) return ERR_EMP;
	

	return NO_ERR;
}


/* Fetch an interruption frame */
int get_intfrm(struct FRAME* rpl)
{

	if ( iopl(3) )	return ERR_PRIV;

	if ( (inl(BASE_ADDR+ADDR_IR_CNT)&0xffffff) < 2 ) return ERR_EMP;

	rpl->data = inl( BASE_ADDR+ADDR_IR_LDT );
	rpl->code = inl( BASE_ADDR+ADDR_IR_UDT );
	
//	if ( (inl(BASE_ADDR+ADDR_IR_STA)&0x00000001)==0 ) return ERR_EMP;
	

	return NO_ERR;
}


/* current Rx FIFO count */
int get_rxcnt()
{
	if ( iopl(3) )	return ERR_PRIV;

	return inl(BASE_ADDR+ADDR_RX_CNT)&0xffffff;
}

/* current Int FIFO count */
int get_ircnt()
{
	if ( iopl(3) )	return ERR_PRIV;

	return inl(BASE_ADDR+ADDR_IR_CNT)&0xffffff;
}

