📄 dm9000.c
字号:
/*Spenser---------------------------------------------------------*/
/*Initial DM9000*/
init_dm9000();
/*Set the Mac address*/
err=ETHER_MacLoad(netp);
/* set Multicast table */
ETHER_setMulticast(netp);
/*added by anlow for multicast, 06-01-09*/
//netp->set_multicalist = &dm9000_hash_table;
netp->set_multicalist =dm9000_hash_table;
#ifdef AUTO_RELEASE
/* automatically release successfully transmitted packets */
#endif
#ifdef LOOP_BACK
iow(iobase, 0, 0x02); /*MAC internal loop back. */
#endif
/* Activate DM9000 */
iow(iobase, 0x5, (RXCTL_DEFAULT | 1)); /* RX enable */
/*install the interupt handler */
/* enables IRQs */
/* By Anky */
iow(iobase, 0xFF, IMR_DEFAULT); /* Enable TX/RX interrupt mask */
return(err);
}
/*-----------------------------------------------------------------------------
Name : init_dm9000
Description : Initialize MAC & PHY
Author : Spenser
------------------------------------------------------------------------------*/
ErrorCode_t init_dm9000(void)
{
iow(iobase, 0x1F, 0); /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */
task_delay(200);
iow(iobase, 0, 3);
task_delay(200); /* wait 20us at least for software reset ok */
iow(iobase, 0, 3); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on. Added by SPenser */
task_delay(200); /* wait 20us at least for software reset ok */
/* change I/O mode to byte mode
iow(iobase, 0xfe, U8 RegData)*/
/* I/O mode */
dm9000_iomode = ior(iobase, 0xfe) >> 6; /* ISR bit7:6 keeps I/O mode */
/* Configure the PHY */
set_PHY_mode();
/* Program operating register */
iow(iobase, 0x00, 0);
iow(iobase, 0x02, 0); /* TX Polling clear */
iow(iobase, 0x2f, 0); /* Special Mode */
iow(iobase, 0x01, 0x2c); /* clear TX status */
/* iow(iobase, 0xfe, 0x0f); Clear interrupt status */
iow(iobase, 0x08, BACK_PRESSURE_THRESHOLD);
iow(iobase, 0x09, FLOWCONTROL_THRESHOLD); /* Flow control: High/Low water */
iow(iobase, 0x0a, TX_RX_FLOWCONTROL); /* flow control */
/* Initial Global variable */
tx_pkt_cnt = 0;
}
/*---------------------------------------------------------------------------
Name : set_PHY_mode
Description : PHY setting
Author : Spenser
-----------------------------------------------------------------------------*/
ErrorCode_t set_PHY_mode(void)
{
/*U16 phy_reg0 = 0x1200; Auto-negotiation & non-duplux mode*/
U16 phy_reg0 = 0x1000;
U16 phy_reg4 = 0x01e1; /* Default non flow control */
phy_write(0, phy_reg0);
phy_write(4, phy_reg4);
}
/*--------------------------------------------------------------
Name : phy_write
Description : Write PHY's register.
Author : Spenser
---------------------------------------------------------------*/
void phy_write(U8 reg, U16 value)
{
/* Fill the phyxcer register into REG_0C */
iow(iobase, 0xc, DM9000_PHY | reg);
/* Fill the written data into REG_0D & REG_0E */
iow(iobase, 0xd, (value & 0xff));
iow(iobase, 0xe, ( (value >> 8) & 0xff));
iow(iobase, 0xb, 0xa); /* Issue phyxcer write command */
task_delay(500); /* Wait write complete */
iow(iobase, 0xb, 0x0); /* Clear phyxcer write command */
}
/*-------------------------------------------------------------------
Name : phy_read
Description : Read a word from phyxcer
Author : Spenser
---------------------------------------------------------------------*/
static U16 phy_read(int reg)
{
/* Fill the phyxcer register into REG_0C */
iow(iobase, 0xc, DM9000_PHY | reg);
iow(iobase, 0xb, 0xc); /* Issue phyxcer read command */
task_delay(100); /* Wait read complete */
iow(iobase, 0xb, 0x0); /* Clear phyxcer read command */
/* The read data keeps on REG_0D & REG_0E */
return ( ior(iobase, 0xe) << 8 ) | ior(iobase, 0xd);
}
/*-------------------------------------------------------------------
Name : read_srom_word
Description : Read a word data from SROM
Parameters : offset = Word offset of eeprom.
Author : Spenser
--------------------------------------------------------------------*/
U16 read_srom_word(int offset)
{
EEPROM_PHY_ADR_REG = offset; /*Word address */
EEPROM_PHY_CTL_REG = EEPROM_READ_COMMAND; /*read command */
task_delay(200);
EEPROM_PHY_CTL_REG = 0; /*Clear read command */
return (EE_PHY_L_REG + (EE_PHY_H_REG << 8));
}
/*----------------------------------------------------------------------------
Name : dm9000_hash_table
Description : Set DM9000 MAC address & multicase address filter
Author : Spenser
-----------------------------------------------------------------------------*/
void dm9000_hash_table(struct netif *dev)
{
//board_info_t *db = (board_info_t *)dev->priv;
struct dev_mc_list *mcptr = dev->mc_list;
int mc_cnt = dev->mc_count;
U32 hash_val;
U16 i, oft, hash_table[4];
/* Set Node address */
PAB0_REG = mac_addr[0];
PAB1_REG = mac_addr[1];
PAB2_REG = mac_addr[2];
PAB3_REG = mac_addr[3];
PAB4_REG = mac_addr[4];
PAB5_REG = mac_addr[5];
/* Clear Hash Table */
for (i = 0; i < 4; i++)
hash_table[i] = 0x0;
/* broadcast address */
hash_table[3] = 0x8000;
/* the multicast address in Hash Table : 64 bits */
for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
hash_val = cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 0x3f;
hash_table[hash_val / 16] |= (U16) 1 << (hash_val % 16);
}
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++) {
iow(IO_base, oft++, hash_table[i] & 0xff);
iow(IO_base, oft++, (hash_table[i] >> 8) & 0xff);
}
}
/*----------------------------------------------------------------------------
Name : cal_CRC
Description : Calculate the CRC valude of the Rx packet
Parameter : flag = 1 : return the reverse CRC (for the received packet CRC)
0 : return the normal CRC (for Hash Table index)
Author : Spenser
--------------------------------------------------------------------------------*/
static unsigned long cal_CRC(unsigned char * Data, unsigned int Len, U8 flag)
{
unsigned long Crc = 0xffffffff;
while (Len--) {
Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
}
if (flag)
return ~Crc;
else
return Crc;
}
/*-----------------------------------------------------------------------------
Name : dmfe_start_xmit
Description : Hardware start transmission. Send a packet to media from the upper layer.
--------------------------------------------------------------------------------*/
int dmfe_start_xmit(struct netif *netp, struct pbuf *p)
{
char * data_ptr;
int i, tmplen;
int sent_pkt_len;
struct pbuf *q;
if (tx_pkt_cnt > 1)
return 1;
/* netif_stop_queue(dev); */
#ifdef MUTEX_RD
semaphore_wait(mutex_wr_dm9k);
#endif
/* Disable all interrupt */
iow(iobase, 0xff, IMR_DIS_ALL);
/* Move data to DM9000 TX RAM */
outb(0xf8,iobase);
sent_pkt_len = p->tot_len;
if (dm9000_iomode == DM9000_BYTE_MODE) {
for(q = p; q != NULL; q = q->next)
{
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
data_ptr = (char *)q->payload;
for (i = 0; i < q->len; i++)
outb((data_ptr[i] & 0xff), iodata);
}
}else{
/* Word mode */
for(q = p; q != NULL; q = q->next)
{
tmplen = (q->len + 1) / 2;
data_ptr = (char *)q->payload;
for (i = 0; i < tmplen; i++)
{
outw(((U16 *)data_ptr)[i], iodata);
}
}
tx_counter++; /*for test*/
}
/* TX control: First packet immediately send, second packet queue */
if (tx_pkt_cnt == 0)
{
/* First Packet */
tx_pkt_cnt++;
/* Set TX length to DM9000 */
#if 0
iow(iobase, 0xfc, sent_pkt_len & 0xff);
iow(iobase, 0xfd, (sent_pkt_len >> 8) & 0xff);
#else
iow(iobase, 0xfc, sent_pkt_len & 0xff);
iow(iobase, 0xfd, (sent_pkt_len >> 8) & 0xff);
#endif
/* Issue TX polling command */
iow(iobase, 0x2, 0x1); /* Cleared after TX complete */
/*save data length to use it in stat*/
pktsize=sent_pkt_len;
//netp->if_opackets++;
//netp->if_obytes += pktsize;
}
else {
/* Second packet */
tx_pkt_cnt++;
queue_pkt_len = sent_pkt_len;
}
/* Re-enable interrupt*/
iow(iobase,0xff, IMR_DEFAULT);
#ifdef MUTEX_RD
semaphore_signal(mutex_wr_dm9k);
#endif
return 0;
}
#ifdef TASK_MODE
/*============================================================================
Name :
Description : Copy Data from chip to NexGen buffer.
============================================================================*/
static void ETHER_CopyData(struct netif *netp)
{
while(task_run)
{
semaphore_wait(CopyGo);
dmfe_packet_receive(netp);
}
}
#endif
static int ETHER_Close(struct netif *netp)
{
/*U16 cfg_reg;
static NGbuf * bufp; */
/*interface must be already running*/
if(!(netp->flags)&NG_IFF_RUNNING)
{
return(1);
}
/* clear flags*/
/*(netp->flags)&=~(NG_IFF_RUNNING|NG_IFF_UP); */
(netp->flags)&=~NG_IFF_RUNNING;
/* RESET devie */
/* phy_write(db, 0x00, 0x8000); PHY RESET */
iow(iobase, 0xff, 0x80); /* Disable all interrupt */
iow(iobase, 0x05, 0x00); /* Disable RX */
iow(iobase, 0x1f, 0x01); /* Power-Down PHY */
/*uninstall the irq*/
#ifdef TASK_MODE
task_run=FALSE;
task_delete(Task);
semaphore_delete(CopyGo);
#endif
#if 0
/* Remove pending buffers */
while (1)
{
ngBufDequeue(netp, bufp);
if (bufp == NULL)
{
break;
}
ngBufOutputFree(bufp);
}
#endif
return(0);
}
/*-------------------------------------------------------------------------
Name : ETHER_InterruptHandler
Description : handler of the interruptions.
Author :
--------------------------------------------------------------------------*/
static void InterruptHandler(struct netif *netp)
{
/* A real interrupt coming */
/* Save previous register address */
reg_save = inb(iobase);
/* Disable all interrupt */
iow(iobase, 0xff, IMR_DIS_ALL);
/* Got DM9000 interrupt status */
int_status = ior(iobase, 0xfe); /* Got ISR */
iow(iobase, 0xfe, 0x3f); /*Clear ISR status */
/* Trnasmit Interrupt check */
if (int_status & DM9000_TX_INTR)
{
tx_status = ior(iobase, 0x01); /* Got TX status */
if (tx_status & 0xc)
{
/* One packet sent complete */
tx_pkt_cnt--;
/* Queue packet check & send */
if (tx_pkt_cnt > 0)
{
/* Set TX length to DM9000 */
iow(iobase, 0xfc, queue_pkt_len & 0xff);
iow(iobase, 0xfd, (queue_pkt_len >> 8) & 0xff);
/* Issue TX polling command */
iow(iobase, 0x2, 0x1); /* Cleared after TX complete */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -