/*
 * i8255x.c
 *
 * Copyright 2004, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * Intel 82557,82558, 82559, 82550, or 82551 Fast Ethernet controllers.
 */


#include<types.h>
#include<pci.h>
#include<device.h>
#include<mm.h>
#include<lib.h>
#include<interrupt.h>
#include<errno.h>
#include<mp.h>
#include<lock.h>
#include<net/net.h>
#include<net/ether.h>


/*************************************************************************
 *
 * 共通
 *
 *************************************************************************/


enum{
	/* SCB Status Word Bits. */
	SCB_STAT_CX_TNO=   1<<15,
	SCB_STAT_FR=       1<<14,
	SCB_STAT_CNA=      1<<13,
	SCB_STAT_RNR=      1<<12,
	SCB_STAT_MDI=      1<<11,
	SCB_STAT_SWI=      1<<10,
	SCB_STAT_FCP=      1<<8,
	SCB_STAT_CUS_IDL=  0,
	SCB_STAT_CUS_SSP=  1<<6,
	SCB_STAT_CUS_LPQ=  2<<6,
	SCB_STAT_CUS_HQP=  3<<6,
	SCB_STAT_RUS_IDL=  0,
	SCB_STAT_RUS_SSP=  1<<2,
	SCB_STAT_RUS_NORSC=2<<2,
	SCB_STAT_RUS_RDY=  4<<2,

	/* SCB Command Word Bits. */
	SCB_CMD_CXMSK= 1<<15,
	SCB_CMD_FRMSK= 1<<14,
	SCB_CMD_CNAMSK=1<<13,
	SCB_CMD_RNRMSK=1<<12,
	SCB_CMD_ERMSK= 1<<11,
	SCB_CMD_FCPMSK=1<<10,
	SCB_CMD_SI=    1<<9,
	SCB_CMD_M=     1<<8,
	SCB_CMD_CU_NOP=       0,
	SCB_CMD_CU_START=     1<<4,
	SCB_CMD_CU_RESUME=    2<<4,
	SCB_CMD_CU_DUMPADDR=  4<<4,
	SCB_CMD_CU_DUMP=      5<<4,
	SCB_CMD_CU_LOADBASE=  6<<4,
	SCB_CMD_CU_DUMPRESET= 7<<4,
	SCB_CMD_CU_STRESUME= 10<<4,
	SCB_CMD_RU_NOP=      0,
	SCB_CMD_RU_START=    1,
	SCB_CMD_RU_RESUME=   2,
	SCB_CMD_RU_RECVDMA=  3,
	SCB_CMD_RU_ABORT=    4,
	SCB_CMD_RU_LOADHSIZE=5,
	SCB_CMD_RU_LOADBASE= 6,

	/* Port Selection Function. */
	SCB_PORT_RESET=    0,	/* CSRとPCIレジスタもクリアー、リセット後約10μS待つ必要がある。 */
	SCB_PORT_SELFTEST= 1,
	SCB_PORT_SLCTRESET=2,	/* リセット後約10μS待つ必要がある、参照マニュアル52P。 */
	SCB_PORT_DUMP=     3,

	/* MDI Control Register Bits,参照マニュアル58p。 */
	SCB_MDI_IE=1<<29,
	SCB_MDI_R=1<<28,
	SCB_MDI_OPW=1<<26,
	SCB_MDI_OPR=2<<26,
};


typedef struct{
	uint16_t scbSts;
	uint16_t scbCmd;
	uint32_t scbGnp;
	uint32_t port;
	uint16_t reserv1;
	uint16_t eepCtl;
	uint32_t mdiCtl;
	uint32_t rxBufSize;
	uint8_t  reserv2;
	uint16_t flwCtl __attribute__((packed));
	uint8_t  pmdr;
	uint8_t  gnlCtl;
	uint8_t  gnlSts;
	uint16_t reserv3;
	uint32_t reserv4[4];
	uint32_t fncEvn;
	uint32_t fncEvnMsk;
	uint32_t fncSts;
	uint32_t forcEvn;
}CSR_REG;

typedef struct{
	uint8_t trFrame;
	uint8_t trMaxcol;
	uint8_t trLatecol;
	uint8_t trUndrun;
	uint8_t trCrs;
	uint8_t trDefer;
	uint8_t trSngcol;
	uint8_t trMltcol;
	uint8_t trTtlcol;
	uint8_t rcFrame;
	uint8_t rcCrc;
	uint8_t rcAlign;
	uint8_t rcRsrc;
	uint8_t rcOvrun;
	uint8_t rcCdt;
	uint8_t rcShtfrm;
}STAT_COUNTER;


/* コントローラごとの固有情報。 */



/*************************************************************************
 *
 * 送信
 *
 *************************************************************************/


/*
 * PUBLIC
 * Init transfer buffer.
 * parameters : LOCAL_INFO address
 * return : 0 or error number
 */
static int initTransBuf(LOCAL_INFO *linf)
{

	return 0;
}


/*
 * PUBLIC
 * Reset transfer registers.
 * parameters : register
 * return : 0 or error number
 */
static int resetTransfer(LOCAL_INFO *linf)
{

	return 0;
}


/*
 * PUBLIC
 * Transfer end handle.
 * parameters : LOCAL_INFO address
 */
static void endTransfer(LOCAL_INFO *linf)
{
}

static void errorTransfer(LOCAL_INFO *linf)
{

}


/*
 * PUBLIC
 * Transfer ethernet frame.
 * parameters : LOCAL_INFO address,TRANS_BUF_INFO address,destination mac address
 */
static inline void transFrame(LOCAL_INFO *linf,TRANS_BUF_INFO *tbi,char *dstmac)
{

}


/*************************************************************************
 *
 * 受信
 *
 *************************************************************************/


typedef struct{
	ushort state;		/* Receive state. */
	ushort size;		/* Frame size */
	ETHER_FRAME ether;
}RECEIVE_FRAME;


/*
 * PUBLIC
 * Read receive buffer.
 * parameters : device number,LOCAL_INFO address
 * return : task switch on=1,off=0
 */
static int readReceiveBuf(int num,LOCAL_INFO *linf)
{

}


/*
 * PUBLIC
 * Init receive buffer.
 * parameters : LOCAL_INFO address
 * return : 0 or error number
 */
static int initReceiveBuf(LOCAL_INFO *linf)
{
}


/*
 * PUBLIC
 * Init receive registers.
 * parameters : register
 */
static void resetReceive(RT_REG *reg)
{

}


/*************************************************************************
 *
 * リセット
 *
 *************************************************************************/


/*
 * PUBLIC
 * Reset rt8139.
 */


/*
 * PUBLIC
 * Init rt8139.
 * parameters : RT_REG address
 * return : 0 or error number
 */
static int initRt(LOCAL_INFO *linf)
{

	return 0;
}


/**************************************************************************
 *
 * 割り込み
 * ・割込み開放はSCB Status Word の8-15bitに書き込む。
 *
 **************************************************************************/


/* PRIVATE */
static LOCAL_INFO *local[2];


/*
 * PRIVATE
 * Interrupt handler.
 * parameters : device number,LOCAL_INFO address
 * return : task switch on=1,off=0
 */
static inline int intrHandler(int num,LOCAL_INFO *linf)
{

}


/*
 * PRIVATE
 * Interrupt handler head.
 * return : task switch on=1,off=0
 */
static int intr0()
{
	return intrHandler(0,local[0]);
}

static int intr1()
{
	return intrHandler(1,local[1]);
}


/* PUBLIC */
int (*intr[])()={intr0,intr1};


/*************************************************************************
 *
 * サービスルーチン
 *
 *************************************************************************/


static int open()
{
	return 0;
}


static int close()
{
	return 0;
}


static int write(void *linf,size_t tbi,size_t dstmac)
{
	transFrame((LOCAL_INFO*)linf,(TRANS_BUF_INFO*)tbi,(char*)dstmac);

	return 0;
}


static int ioctl(int prm_num,int cmd,...)
{
	return 0;
}


/**************************************************************************
 *
 * 初期化
 *
 **************************************************************************/


enum{
	/* Vender ID,Device ID. */
	VID_INTEL=					0x8086,
		DID_INTEL_8255X=		0x1229,
		DID_INTEL_82559E=		0x1209,

	/* Revision ID. */
	RID_82557A=1,
	RID_82557B,
	RID_82557C,
	RID_82558A,
	RID_82558B,
	RID_82558C,
	RID_82559A,
	RID_82559B,
	RID_82559C,
	RID_82559E,
	RID_82550A=0xc,
	RID_82550B,
	RID_82550C,
	RID_82551A,
	RID_82551B,

	/* PCI Configuration Space Registers. */
	PCI_MEMAR=0x10,
};


/*
 * PRIVATE
 * Init interrupt.
 * parameters : device number,PCI_INFO address,LOCAL_INFO address
 * return : 0 or error number
 */
static int initIntr(int devnum,PCI_INFO *pci,LOCAL_INFO *linf)
{
	int rest;
	int irq;


	/* 割り込みの設定。 */
	irq=read_pci_config(pci,PCI_CONF_INTRLIN)&0xff;
	local[devnum]=linf;
	irq_entry[irq]=intr[devnum];

	/* MPシステムの場合。 */
	if(MFPS_addres)
	{
		if((rest=SetPciIrqInIoapic(pci,irq))<0)return rest;
		releasePciIrqIoapicMask(pci);
	}
	else release_irq_mask(irq);

	return 0;
}


/*
 * PRIVATE
 * PCI機能の設定。
 * parameters : PCI_INFO,LOCAL_INFO pointer address
 * return : 0 or error number
 */
static int initPCI(PCI_INFO *pci,LOCAL_INFO *linf)
{
	int com;
	uint membase;


	/* ポート・メモリーベース、バスマスターON。 */
	com=read_pci_config(pci,PCI_CONF_COMMAND);
	com|=PCI_COMMAND_IOACS|PCI_COMMAND_MEMACS|PCI_COMMAND_BSMST;
	writew_pci_config(pci,com,PCI_CONF_COMMAND);

	/* レジスタメモリアクセスベースアドレスの設定 4Kbyte。 */
	membase=getPciMemAddress(0x1000);
	writedw_pci_config(pci,PCI_MEMAR,membase);
	if(read_pci_config(pci,PCI_MEMAR)!=membase)return -EDERRE;
	linf->reg=(RT_REG*)membase;

	return 0;
}


/*
 * GLOBAL
 * parameters : device number
 * return : next device number or error number
 */
int initI8255x(int devnum)
{
	char *nic_name;
	char *dev_name;
	int rest;
	int vendID,devID;
	PCI_INFO pci={0,0,0,0};
	DEV_INFO *devinf;


	/* NicをPCIから検索。 */
	while(search_pci_class(PCI_CLASS_ETHER,&pci)==0)
	{
		/* VenderID と DeviceID の確認。 */
		nic_name=NULL;
		vendID=pci.vidDid&0xffff;
		devID=pci.vidDid>>16;
		switch(vendID)
		{
			case VID_INTEL:
				switch(devID)
				{
					case DID_INTEL_8255X:
						rest=read_pci_config(&pci,PCI_CONF_REVIVION);
						switch(rest&0xff)
						{
							case RID_82557A:
							case RID_82557B:
							case RID_82557C:
								nic_name="Intel 82557 PCI EtherExpressPro";
								break;
							case RID_82558A:
							case RID_82558B:
							case RID_82558C:
								nic_name="Intel 82558 PCI EtherExpressPro";
								break;
							case RID_82559A:
							case RID_82559B:
							case RID_82559C:
							case RID_82559E:
								nic_name="Intel 82559 PCI EtherExpressPro";
								break;
							case RID_82550A:
							case RID_82550B:
							case RID_82550C:
								nic_name="Intel 82550 PCI EtherExpressPro";
								break;
							case RID_82551A:
							case RID_82551B:
								nic_name="Intel 82551 PCI EtherExpressPro";
								break;
						}
						break;
					case DID_INTEL_82559E:
						nic_name="Intel 82559ER PCI EtherExpressPro";
						break;
				}
		}

		if(nic_name!=NULL)
		{
			/* Init device information. */
			if((devinf=kmalloc(sizeof(DEV_INFO)))==NULL)return -ENOMEM;
			devinf->sector_size=0;
			devinf->begin_blk=0;
			devinf->last_blk=0;
			devinf->open=open;
			devinf->lose=close;
			devinf->write=write;
			devinf->ioctl=ioctl;
			if((dev_name=kmalloc(6))==NULL)return -ENOMEM;
			sprintk(dev_name,"eth%d",devnum);
			devinf->name=dev_name;

			if((devinf->linf=kmalloc(sizeof(LOCAL_INFO)))==NULL)return -ENOMEM;

			/* Init PCI. */
			if((rest=initPCI(&pci,devinf->linf))<0)return rest;

			/* Get MAC address. */
			memcpy(((LOCAL_INFO*)devinf->linf)->mac,((LOCAL_INFO*)devinf->linf)->reg->idr,6);

			/* Init receive buffer. */
			initReceiveBuf(devinf->linf);

			/* Init transfer buffer. */
			if((rest=initTransBuf(devinf->linf))<0)return rest;

			/* Init chip. */
			initRt(devinf->linf);

			/* Init interrrupt. */
			if(initIntr(devnum,&pci,devinf->linf)<0)return devnum;

			regist_device(devinf);

			/* Set device structure. */
			setEtherDevice(devnum,devinf,((LOCAL_INFO*)devinf->linf)->mac);

			printk("%s : %s\n",devinf->name,nic_name);

			++devnum;
		}

		++pci.dev;
		pci.func=0;
	}

	return devnum;
}
