#include <windows.h>
#include <halether.h>
#define DM9000_ID 0x90000A46
// Hash creation constants.
//
#define CRC_PRIME 0xFFFFFFFF;
#define CRC_POLYNOMIAL 0x04C11DB6;
#define IOREAD(o) ((UCHAR)*((volatile UCHAR *)(o)))
#define IOWRITE(o, d) *((volatile UCHAR *)(o)) = (UCHAR)(d)
#define IOREAD16(o) ((USHORT)*((volatile USHORT *)(o)))
#define IOWRITE16(o, d) *((volatile USHORT *)(o)) = (USHORT)(d)
#define IOREAD32(o) ((ULONG)*((volatile ULONG *)(o)))
#define IOWRITE32(o, d) *((volatile ULONG *)(o)) = (ULONG)(d)
#define MEMREAD(o) ((USHORT)*((volatile USHORT *)(dwEthernetMemBase + (o))))
#define MEMWRITE(o, d) *((volatile USHORT *)(dwEthernetMemBase + (o))) = (USHORT)(d)
static DWORD dwEthernetIOBase;
static DWORD dwEthernetDataPort;
static UCHAR DM9000_iomode;
static USHORT hash_table[4];
static DWORD dwEthernetMemBase;
//V1.02
static UCHAR DM9000_rev;
#define DM9000_DWORD_MODE 1
#define DM9000_BYTE_MODE 2
#define DM9000_WORD_MODE 0
//#define DM9000_MEM_MODE
#ifdef DM9000_MEM_MODE
#define READ_REG1 ReadReg
#define READ_REG2 MEMREAD
#define WRITE_REG1 WriteReg
#define WRITE_REG2 MEMWRITE
#else
#define READ_REG1 ReadReg
#define READ_REG2 ReadReg
#define WRITE_REG1 WriteReg
#define WRITE_REG2 WriteReg
#endif
static BOOL bIsPacket;
static UCHAR
ReadReg(USHORT offset)
{
IOWRITE(dwEthernetIOBase, offset);
return IOREAD(dwEthernetDataPort);
}
static void
WriteReg(USHORT offset, UCHAR data)
{
IOWRITE(dwEthernetIOBase, offset);
IOWRITE(dwEthernetDataPort, data);
}
/*
@func BYTE | CalculateHashIndex | Computes the logical addres filter hash index value. This used when there are multiple
destination addresses to be filtered.
@rdesc Hash index value.
@comm
@xref
*/
BYTE CalculateHashIndex( BYTE *pMulticastAddr )
{
DWORD CRC;
BYTE HashIndex;
BYTE AddrByte;
DWORD HighBit;
int Byte;
int Bit;
// Prime the CRC.
CRC = CRC_PRIME;
// For each of the six bytes of the multicast address.
for ( Byte=0; Byte<6; Byte++ )
{
AddrByte = *pMulticastAddr++;
// For each bit of the byte.
for ( Bit=8; Bit>0; Bit-- )
{
HighBit = CRC >> 31;
CRC <<= 1;
if ( HighBit ^ (AddrByte & 1) )
{
CRC ^= CRC_POLYNOMIAL;
CRC |= 1;
}
AddrByte >>= 1;
}
}
// Take the least significant six bits of the CRC and copy them
// to the HashIndex in reverse order.
for( Bit=0,HashIndex=0; Bit<6; Bit++ )
{
HashIndex <<= 1;
HashIndex |= (BYTE)(CRC & 1);
CRC >>= 1;
}
return(HashIndex);
}
void DM9000_Delay(DWORD dwCounter)
{
// Simply loop...
while (dwCounter--);
}
void dm9000_hash_table(USHORT *mac)
{
USHORT i, oft;
/* Set Node address */
WRITE_REG1(0x10, (UINT8)(mac[0] & 0xFF));
WRITE_REG1(0x11, (UINT8)(mac[0] >> 8));
WRITE_REG1(0x12, (UINT8)(mac[1] & 0xFF));
WRITE_REG1(0x13, (UINT8)(mac[1] >> 8));
WRITE_REG1(0x14, (UINT8)(mac[2] & 0xFF));
WRITE_REG1(0x15, (UINT8)(mac[2] >> 8));
/* Clear Hash Table */
for (i = 0; i < 4; i++)
hash_table[i] = 0x0;
/* broadcast address */
hash_table[3] = 0x8000;
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++)
{
WRITE_REG1(oft++, (UINT8)(hash_table[i] & 0xff));
WRITE_REG1(oft++, (UINT8)((hash_table[i] >> 8) & 0xff));
}
}
/*
* This function is used to detect DM9000 chip
* input : void
* return : TRUE, detect DM9000
* FALSE, Not find DM9000
*/
static BOOL Probe(void)
{
BOOL r = FALSE;
DWORD id_val;
id_val = READ_REG1(0x28);
id_val |= READ_REG1(0x29) << 8;
id_val |= READ_REG1(0x2a) << 16;
id_val |= READ_REG1(0x2b) << 24;
if (id_val == DM9000_ID) {
RETAILMSG(1, (TEXT("INFO: Probe: DM9000 is detected.\r\n")));
DM9000_rev = READ_REG1(0x2c);
r = TRUE;
}
else {
RETAILMSG(1, (TEXT("ERROR: Probe: Can not find DM9000.\r\n")));
}
return r;
}
/*
* This function enables TX/RX interrupt mask
* input : void
* return : viod
*/
void DM9000DBG_EnableInts(void)
{
/*only enable RX interrupt*/
WRITE_REG1(0xff, 0x81);
}
/*
* This function disables TX/RX interrupt mask
* input : void
* return void
*/
void DM9000DBG_DisableInts(void)
{
WRITE_REG1(0xff, 0x80);
}
/* Send a data block via Ethernet. */
static USHORT dm9000_send (BYTE *pbData, USHORT length)
{
int i;
int tmplen;
IOWRITE(dwEthernetIOBase, 0xf8); /* data copy ready set */
/* copy data to FIFO */
switch (DM9000_iomode)
{
case DM9000_BYTE_MODE:
tmplen = length ;
for (i = 0; i < tmplen; i++)
IOWRITE(dwEthernetDataPort, ((UCHAR *)pbData)[i]);
break;
case DM9000_WORD_MODE:
tmplen = (length+1)/2;
for (i = 0; i < tmplen; i++)
IOWRITE16(dwEthernetDataPort, ((USHORT *)pbData)[i]);
break;
case DM9000_DWORD_MODE:
tmplen = (length+3)/4;
for (i = 0; i < tmplen; i++)
IOWRITE32(dwEthernetDataPort, ((ULONG *)pbData)[i]);
default:
EdbgOutputDebugString("[DM9000][TX]Move data error!!!");
break;
}
/*set packet leng */
WRITE_REG1(0xfd, (length >> 8) & 0xff);
WRITE_REG1(0xfc, length & 0xff);
/* start transmit */
WRITE_REG1(0x02, 1);
/*wait TX complete*/
while(1)
{
if (READ_REG1(0xfe) & 2) { //TX completed
WRITE_REG1(0xfe, 2);
break;
}
DM9000_Delay(1000);
}
return 0;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
BOOL DM9000DBG_Init(BYTE *iobase, ULONG membase, USHORT MacAddr[3])
{
BOOL r = FALSE;
bIsPacket = FALSE;
dwEthernetIOBase = (DWORD)iobase;
dwEthernetDataPort = dwEthernetIOBase + 4;
dwEthernetMemBase = membase;
r = Probe(); /*Detect DM9000 */
EdbgOutputDebugString("DM9000: MAC Address: %x:%x:%x:%x:%x:%x\r\n",
MacAddr[0] & 0x00FF, MacAddr[0] >> 8,
MacAddr[1] & 0x00FF, MacAddr[1] >> 8,
MacAddr[2] & 0x00FF, MacAddr[2] >> 8);
/* set the internal PHY power-on, GPIOs normal */
WRITE_REG1(0x1f, 0); /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
DM9000_Delay(200000000);
/* do a software reset */
WRITE_REG1(0x0, 3); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on */
DM9000_Delay(200000000);
WRITE_REG1(0x0, 3); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on */
DM9000_Delay(200000000);
/* I/O mode */
DM9000_iomode = READ_REG1(0xfe) >> 6; /* ISR bit7:6 keeps I/O mode */
/* Program operating register */
WRITE_REG1(0x0, 0);
WRITE_REG1(0x02, 0); /* TX Polling clear */
WRITE_REG1(0x2f, 0); /* Special Mode */
WRITE_REG1(0x01, 0x2c); /* clear TX status */
WRITE_REG1(0xfe, 0x0f); /* Clear interrupt status */
/* Set address filter table */
dm9000_hash_table(MacAddr);
/* Activate DM9000A/DM9010 */
WRITE_REG1(0x05, 0x30 | 1); /* Discard long packet and CRC error packets*//* RX enable */
WRITE_REG1(0xff, 0x80); /* Enable SRAM automatically return */
/* wait link ok */
while(1)
{
if(READ_REG1(0x01)&0x40)
break;
}
return r;
}
//----------------------------------------------------------------------
DWORD
DM9000DBG_GetPendingInts(void)
{
UCHAR intr_state;
intr_state = READ_REG1(0xfe);
WRITE_REG1(0xfe, intr_state); /*clean ISR*/
return(1);
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
UINT16 DM9000DBG_GetFrame(BYTE *pbData, UINT16 *pwLength)
{
int i;
unsigned long tmp32;
unsigned short rxlen, tmplen;
unsigned short status;
UCHAR RxRead;
READ_REG1(0x3); READ_REG1(0x4); /*Try & work run*/
/* read the first byte*/
RxRead = READ_REG1(0xf0);
RxRead = IOREAD(dwEthernetDataPort);
RxRead = IOREAD(dwEthernetDataPort);
/* the fist byte is ready or not */
if ((RxRead & 3) != 1) /* no data */
return 0;
IOWRITE(dwEthernetIOBase, 0xf2); /* set read ptr ++ */
switch (DM9000_iomode)
{
case DM9000_BYTE_MODE:
status = IOREAD(dwEthernetDataPort)+(IOREAD(dwEthernetDataPort)<<8);
rxlen = IOREAD(dwEthernetDataPort) + (IOREAD(dwEthernetDataPort)<<8);
break;
case DM9000_WORD_MODE:
status = IOREAD16(dwEthernetDataPort);
rxlen = IOREAD16(dwEthernetDataPort);
break;
case DM9000_DWORD_MODE:
tmp32 = IOREAD32(dwEthernetDataPort);
status = (unsigned short)(tmp32&0xffff);
rxlen = (unsigned short)((tmp32>>16)&0xffff);
default:
EdbgOutputDebugString("[DM9000]Get status and rxlen error!!!");
break;
}
if (status & 0xbf00)
EdbgOutputDebugString("[DM9000]RX status error!!!=[%x]",(status>>8) );
/* move data from FIFO to memory */
switch (DM9000_iomode)
{
case DM9000_BYTE_MODE:
tmplen = rxlen ;
for (i = 0; i < tmplen; i++)
((UCHAR *)pbData)[i] = IOREAD(dwEthernetDataPort);
break;
case DM9000_WORD_MODE:
tmplen = (rxlen+1)/2;
for (i = 0; i < tmplen; i++)
((USHORT *)pbData)[i] = IOREAD16(dwEthernetDataPort);
break;
case DM9000_DWORD_MODE:
tmplen = (rxlen+3)/4;
for (i = 0; i < tmplen; i++)
((ULONG *)pbData)[i] = IOREAD32(dwEthernetDataPort);
default:
EdbgOutputDebugString("[DM9000][RX]Move data error!!!");
break;
}
*pwLength = rxlen;
/* clean ISR */
WRITE_REG1(0xfe,READ_REG1(0xfe));
return rxlen;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
UINT16 DM9000DBG_SendFrame( BYTE *pbData, DWORD dwLength )
{
// EdbgOutputDebugString("[DM9000A]: DM9000DBG_SendFrame()..........\r\n");
return dm9000_send(pbData, (UINT16)dwLength);
}
/*
@func void | DM9000DBG_CurrentPacketFilter | Sets a receive packet h/w filter.
@rdesc N/A.
@comm
@xref
*/
void DM9000DBG_CurrentPacketFilter(DWORD dwFilter)
{
UCHAR uTemp;
USHORT i, oft;
EdbgOutputDebugString("[DM9000A]: DM9000DBG_CurrentPacketFilter()..........\r\n");
// What kind of filtering do we want to apply?
//
// NOTE: the filter provided might be 0, but since this EDBG driver is used for KITL, we don't want
// to stifle the KITL connection, so broadcast and directed packets should always be accepted.
//
if (dwFilter & PACKET_TYPE_ALL_MULTICAST)
{ // Accept *all* multicast packets.
uTemp = READ_REG1(0x05);
WRITE_REG1(0x05, uTemp | 0x08); //Enable pass all multicast
}
#if 0 //Always can receive multicast address according to hash table.
if (dwFilter & PACKET_TYPE_MULTICAST)
{ // Accept multicast packets.
}
#endif
if (dwFilter & PACKET_TYPE_BROADCAST)
{
/* broadcast address */
hash_table[3] = 0x8000;
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++) {
WRITE_REG1(oft++, hash_table[i] & 0xff);
WRITE_REG1(oft++, (hash_table[i] >> 8) & 0xff);
}
}
// Promiscuous mode is causing random hangs - it's not strictly needed.
if (dwFilter & PACKET_TYPE_PROMISCUOUS)
{ // Accept anything.
uTemp = READ_REG1(0x05);
WRITE_REG1(0x05, uTemp | 0x02); //Enable pass all multicast
}
EdbgOutputDebugString("DM9000: Set receive packet filter [Filter=0x%x].\r\n", dwFilter);
} // DM9000DBG_CurrentPacketFilter().
/*
@func BOOL | DM9000DBG_MulticastList | Sets a multicast address filter list.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
*/
BOOL DM9000DBG_MulticastList(PUCHAR pucMulticastAddresses, DWORD dwNumAddresses)
{
BYTE nCount;
BYTE nIndex;
BYTE i, oft;
BYTE Reg5;
//Stop RX
Reg5 = READ_REG1(0x05);
WRITE_REG1(0x05, Reg5 & 0xfe);
// Compute the logical address filter value.
//
for (nCount = 0 ; nCount < dwNumAddresses ; nCount++)
{
EdbgOutputDebugString("DM9000: Multicast[%d of %d] = %x-%x-%x-%x-%x-%x\r\n",
(nCount + 1),
dwNumAddresses,
pucMulticastAddresses[6*nCount + 0],
pucMulticastAddresses[6*nCount + 1],
pucMulticastAddresses[6*nCount + 2],
pucMulticastAddresses[6*nCount + 3],
pucMulticastAddresses[6*nCount + 4],
pucMulticastAddresses[6*nCount + 5]);
nIndex = CalculateHashIndex(&pucMulticastAddresses[6*nCount]);
hash_table[nIndex/16] |= 1 << (nIndex%16);
}
EdbgOutputDebugString("DM9000: Logical Address Filter = %x.%x.%x.%x.\r\n", hash_table[3], hash_table[2], hash_table[1], hash_table[0]);
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++) {
WRITE_REG1(oft++, hash_table[i] & 0xff);
WRITE_REG1(oft++, (hash_table[i] >> 8) & 0xff);
}
//Start RX
WRITE_REG1(0x05, Reg5);
return(TRUE);
} // DM9000DBG_MulticastList().