eboot下使用的DM9000驱动源代码

#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().

本文出自 “Embedded_System_Development” 博客,请务必保留此出处http://buaadallas.blog.51cto.com/399160/80917

posted on 2010-07-12 10:49  xilentz  阅读(982)  评论(0编辑  收藏  举报