/********************************************************************************
 * xxxx.c
 *
 * DESCRIPTION:
 *       MS API initialization routine
 *
 * DEPENDENCIES:   Platform
 *
 * FILE REVISION NUMBER:
 *
 *******************************************************************************/
#include "msSample.h"
#include <errno.h>
#include <fcntl.h>
#include "gtHwCntl.h"

//#define DEBUG

GT_SYS_CONFIG   cfg;
GT_QD_DEV       diagDev;
GT_QD_DEV       *dev=&diagDev;

static int fd;
static struct ifreq ifr;

GT_STATUS MiiInit(GT_QD_DEV* dev)
{
	struct mii_ioctl_data *mii;

	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_ifrn.ifrn_name, "eth0");
	mii = (struct mii_ioctl_data *)(&ifr.ifr_ifru.ifru_data);
	mii->phy_id = 0x115;  /* phy's ID */

	mii->reg_num = 3;
	mii->val_in = 0;
	mii->val_out = 0;

	fd = socket(AF_INET, SOCK_DGRAM, 0);

	if (fd < 0) {

		printf("DEBUG:Can't create socket for MII \n");
		return GT_FAIL;
	}

	return GT_OK;
}


GT_BOOL MiiRead (GT_QD_DEV* dev, unsigned int portNumber , unsigned int MIIReg,
		unsigned int* value)
{
	struct mii_ioctl_data *mii;

	mii = (struct mii_ioctl_data *)(&ifr.ifr_ifru.ifru_data);
	mii->phy_id = portNumber;
	mii->reg_num = MIIReg;

	if (ioctl(fd, SIOCGMIIREG, &ifr) < 0)
	{
		perror("ioctl[SIOCGMIIPHY]");
		return GT_FALSE;
	}

	*value = (unsigned int)(mii->val_out & 0xffff);

	return GT_TRUE;
}

GT_BOOL MiiWrite (GT_QD_DEV* dev, unsigned int portNumber , unsigned int MIIReg,
		unsigned int value)
{
	struct mii_ioctl_data *mii;
	mii = (struct mii_ioctl_data *)(&ifr.ifr_ifru.ifru_data);
	mii->phy_id = portNumber;
	mii->reg_num = MIIReg;
	mii->val_in = value & 0xffff;

	if (ioctl(fd, SIOCSMIIREG, &ifr) < 0)
	{
		perror("ioctl[SIOCSMIIPHY]");
		return GT_FALSE;
	}

	return GT_TRUE;
}

GT_STATUS qdVlanEnable(void)
{
	GT_STATUS status;
	IN GT_LPORT  memPort3[]={4,5};
	IN GT_U8     memPort3Len =2;

	IN GT_LPORT  memPort4[]={3};
	IN GT_U8     memPort4Len =1;

	IN GT_LPORT  memPort5[]={3};
	IN GT_U8     memPort5Len =1;

	/* Port based vlan configuration */
	if((status=gvlnSetPortVlanPorts(dev, 3,memPort3,memPort3Len))==GT_OK)
	{
		//printf("DEBUG:Vlan for Port3 Enabled\n");
	}

	if((status=gvlnSetPortVlanPorts(dev, 4,memPort4,memPort4Len))==GT_OK)
	{
		//printf("DEBUG:Vlan for Port4 Enabled\n");
	}

	if((status=gvlnSetPortVlanPorts(dev, 5,memPort5,memPort5Len))==GT_OK)
	{
		//printf("DEBUG:Vlan for Port5 Enabled\n");
	}

	return GT_TRUE;
}

GT_STATUS qdVlanDisable(void)
{
	GT_STATUS status;
	IN GT_LPORT  memPort3[]={4,5};
	IN GT_U8     memPort3Len =2;

	IN GT_LPORT  memPort4[]={3,5};
	IN GT_U8     memPort4Len =2;

	IN GT_LPORT  memPort5[]={3,4};
	IN GT_U8     memPort5Len =2;

	/* Port based vlan configuration */
	if((status=gvlnSetPortVlanPorts(dev, 3,memPort3,memPort3Len))==GT_OK)
	{
		//printf("DEBUG:Vlan for Port3 Disabled\n");
	}

	if((status=gvlnSetPortVlanPorts(dev, 4,memPort4,memPort4Len))==GT_OK)
	{
		//printf("DEBUG:Vlan for Port4 Disabled\n");
	}

	if((status=gvlnSetPortVlanPorts(dev, 5,memPort5,memPort5Len))==GT_OK)
	{
		//printf("DEBUG:Vlan for Port5 Disabled\n");
	}

	return GT_TRUE;
}


/*
 *  Initialize the QuarterDeck. This should be done in BSP driver init routine.
 *    Since BSP is not combined with QuarterDeck driver, we are doing here.
 */
#define LAN_LINK	"/sys/devices/platform/enet.0/lanLink"
#define PC_LINK		"/sys/devices/platform/enet.0/pcLink"

static void sysfs_write(const char *path, const char *s)
{
	int len;
	int fd = open(path, O_WRONLY);

	if (fd < 0) {
		printf("Error opening %s: %s\n", path, strerror(errno));
		return;
	}

	len = write(fd, s, strlen(s));
	if (len < 0) {
		printf("Error writing to %s: %s\n", path, strerror(errno));
	}

	close(fd);
}

GT_STATUS qdStart(int cpuPort, int useQdSim, int devId) /* devId is used for simulator only */
{
	GT_STATUS status;
	OUT GT_U16 data_reg;
#ifdef DEBUG
	OUT GT_U16 j,k;
	OUT GT_U16 phyreg[0x20];
	OUT GT_U16 phyreg1[0x20], globalreg[0x20],globalreg2[0x20],globalreg3[0x20];
	OUT GT_U32 switchreg[0x20];
	OUT GT_U32 switchreg1[0x20];
	OUT GT_U32 switchreg2[0x20];
#endif
	OUT GT_BOOL	link3status = GT_FALSE,link4status = GT_FALSE;
	OUT GT_BOOL	oldlink3status = GT_FALSE, oldlink4status = GT_FALSE;
	/*
	 *  Register all the required functions to QuarterDeck Driver.
	 */
	memset((char*)&cfg,0,sizeof(GT_SYS_CONFIG));
	memset((char*)&diagDev,0,sizeof(GT_QD_DEV));

	cfg.BSPFunctions.readMii   = MiiRead;
	cfg.BSPFunctions.writeMii  = MiiWrite;
	cfg.BSPFunctions.semCreate = NULL;
	cfg.BSPFunctions.semDelete = NULL;
	cfg.BSPFunctions.semTake   = NULL;
	cfg.BSPFunctions.semGive   = NULL;
	MiiInit(dev);

	cfg.initPorts = GT_TRUE;    /* Set switch ports to Forwarding mode. If GT_FALSE, use Default Setting. */
	cfg.cpuPortNum = cpuPort;
#ifdef MANUAL_MODE    /* not defined. this is only for sample */
	/* user may want to use this mode when there are two QD switchs on the same MII bus. */
	cfg.mode.scanMode = SMI_MANUAL_MODE;    /* Use QD located at manually defined base addr */
	cfg.mode.baseAddr = 0x10;    /* valid value in this case is either 0 or 0x10 */
	printf("DEBUG:qdStart start MANUAL_MODE\n");
#else
#ifdef MULTI_ADDR_MODE
	cfg.mode.scanMode = SMI_MULTI_ADDR_MODE;    /* find a QD in indirect access mode */
	cfg.mode.baseAddr = 1;        /* this is the phyAddr used by QD family device.
					 Valid value are 1 ~ 31.*/
	printf("DEBUG:qdStart start MULTI_ADDR_MODE\n");
#else
	cfg.mode.scanMode = SMI_AUTO_SCAN_MODE;    /* Scan 0 or 0x10 base address to find the QD */
	cfg.mode.baseAddr = 0;
#endif
#endif

	if((status=qdLoadDriver(&cfg, dev)) != GT_OK)
	{
		printf("DEBUG:qdLoadDriver return Failed\n");
		return status;
	}

	gprtSetGlobal2Reg(dev, 0x0, 0x1f);
	gprtSetGlobal2Reg(dev, 0x1, 0x1f);
	gprtSetGlobal2Reg(dev, 0x1C, 0x1f);

	/*
	 *  start the QuarterDeck
	 */

	if((status=sysEnable(dev)) != GT_OK)
	{
		printf("DEBUG:sysConfig return Failed\n");
		return status;
	}

	/* Configure TX/RX clock delay */
	if((status=gpcsSetRGMIITimingDelay(dev, 5, GT_TRUE,GT_FALSE))!=GT_OK)
	{
		printf("DEBUG: Error - gprt gpcsSetRGMIITimingDelay Port 5 \n");
	}

	if((status=gprtGetGlobalReg(dev, 0x1A ,&data_reg))==GT_OK)
	{
		data_reg &= 0xff5F;
		gprtSetGlobalReg(dev, 0x1A ,data_reg);
		gprtGetGlobalReg(dev, 0x1A ,&data_reg);
	}

	if((status=gprtPortPowerDown(dev, 3, GT_FALSE))!=GT_OK)
	{
		printf("DEBUG:Error - gprt PowerUp Port 3 \n");
	}

	if((status=gprtPortPowerDown(dev, 4, GT_FALSE))!=GT_OK)
	{
		printf("DEBUG:Error - gprt PowerUp Port 4 \n");
	}

	if((status=gprtSetLinkTimeWorkaround(dev, 4))!=GT_OK)
	{
		printf("DEBUG:Error - gprtSetLinkTimeWorkaround set \n");
	}

#ifdef DEBUG
	printf("-----------PHY Reg Dump----------------------\n");
	printf("|Address\t |Port3\t |Port4\t |\n");
	printf("---------------------------------------------\n");
	for(j=0; j <=0x1F; j++ )
	{
		if((status=gprtGetPhyReg(dev, 3, j, &phyreg[j] ))==GT_OK)
		{
			if((status=gprtGetPhyReg(dev, 4, j, &phyreg1[j] ))==GT_OK)
			{
				printf("[%x]\t\t %x\t %x\t \n",j, phyreg[j], phyreg1[j]);
			}
		}

	}
	printf("---------------------------------------------\n\n\n");

	printf("------------Switch Port Reg Dump--------------\n");
	printf("|Address\t |Port3\t |Port4\t |Port5\t |\n");
	printf("----------------------------------------------\n");
	for(k=0; k<=0x1F; k++ )
	{
		gsysReadMiiReg(dev, 0x13, k,&switchreg[k]);
		gsysReadMiiReg(dev, 0x14, k,&switchreg1[k]);
		gsysReadMiiReg(dev, 0x15, k,&switchreg2[k]);
		printf("[%x]\t\t %lx\t %lx\t %lx\t \n",k,switchreg[k], switchreg1[k], switchreg2[k]);
	}
	printf("-----------------------------------------------\n");

	printf("------------Global Reg Dump--------------------\n");
	printf("|Address\t |Global\t |Global2\t |Global3\t |\n");
	printf("----------------------------------------------\n");
	for(k=0; k<=0x1F; k++ )
	{
		gprtGetGlobalReg(dev, k,&globalreg[k]);
		gprtGetGlobal2Reg(dev, k,&globalreg2[k]);
		gprtGetGlobal3Reg(dev, k,&globalreg3[k]);
		printf("[%x]\t\t %x\t %x\t %x\t \n",k,globalreg[k], globalreg2[k], globalreg3[k]);
	}
	printf("----------------------------------------------\n");
#endif
	while(1)
	{
		sleep(1);
		gprtGetPhyLinkStatus(dev, 3, &link3status );
		gprtGetPhyLinkStatus(dev, 4, &link4status );

		if(link3status != oldlink3status)
		{
			if(link3status){
				if(link4status){
					sysfs_write(PC_LINK, "0");
					oldlink4status = link4status;
					gprtPortPowerDown(dev, 4, GT_TRUE);
					sleep(1);
					gprtPortPowerDown(dev, 4, GT_FALSE);
				}
				sysfs_write(LAN_LINK, "1");
				qdVlanEnable();
			}
			else{
				sysfs_write(LAN_LINK, "0");
				qdVlanDisable();
				if(link4status){
					oldlink4status = 0;
					link4status = 0;
					gprtPortPowerDown(dev, 4, GT_TRUE);
					sleep(1);
					gprtPortPowerDown(dev, 4, GT_FALSE);
					sleep(1);
					//sysfs_write(PC_LINK, "1");
				}
			}
			oldlink3status = link3status;
		}
		if ((link4status != oldlink4status) && (link3status == 0))
		{
			if(link4status){
				sysfs_write(PC_LINK, "1");
			}
			else {

				sysfs_write(PC_LINK, "0");
			}
			oldlink4status = link4status;
		}

	}
	return GT_OK;
}


int main ()
{
	int cpuPort = 5;
	int devId   = 0;
	int useQdSim = 0;
	GT_STATUS status;
#ifdef DEBUG
	freopen("/data/log/dsdt.log", "a", stdout);
	freopen("/data/log/dsdt.log", "a", stderr);
	setbuf(stdout, NULL);
	setbuf(stderr, NULL);
#endif
	if ((status=qdStart(cpuPort, useQdSim, devId)) !=GT_OK)
	{
		printf("DEBUG:QuarterDeck has been Failed.\n");
		return status;
	}
	return 0;
}
