Davicom公司DM9000A和DM9010 ISA NIC 以太网驱动分析
et timer again */
db->timer.expires = DMFE_TIMER_WUT;
add_timer(db->timer);
return;
}
#if !defined(CHECKSUM)
#define check_rx_ready(a) ((a) == 0x01)
#else
inline u8 check_rx_ready(u8 rxbyte)
{
if (!(rxbyte 0x01))
return 0;
return ((rxbyte >> 4) | 0x01);
}
#endif
/*
Received a packet and pass to upper layer
*/
static void dmfe_packet_receive(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
struct sk_buff *skb;
u8 rxbyte, val;
u16 i, GoodPacket, tmplen = 0, MDRAH, MDRAL;
u32 tmpdata;
rx_t rx;
u16 * ptr = (u16*)rx;
u8* rdptr;
DMFE_DBUG(0, dmfe_packet_receive(), 0);
do {
/*store the value of Memory Data Read address register*/
MDRAH=ior(db, DM9KS_MDRAH);
MDRAL=ior(db, DM9KS_MDRAL);
ior(db, DM9KS_MRCMDX); /* Dummy read */
rxbyte = inb(db->io_data); /* Got most updated data */
/* packet ready to receive check */
if(!(val = check_rx_ready(rxbyte))) break;
/* A packet ready now Get status/length */
GoodPacket = TRUE;
outb(DM9KS_MRCMD, db->io_addr);
/* Read packet status length */
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
*ptr = inb(db->io_data) +
(inb(db->io_data) 8);
*(ptr+1) = inb(db->io_data) +
(inb(db->io_data) 8);
break;
case DM9KS_WORD_MODE:
*ptr = inw(db->io_data);
*(ptr+1) = inw(db->io_data);
break;
case DM9KS_DWORD_MODE:
tmpdata = inl(db->io_data);
*ptr = tmpdata;
*(ptr+1) = tmpdata >> 16;
break;
default:
break;
}
/* Packet status check */
if (rx.desc.status 0xbf)
{
GoodPacket = FALSE;
if (rx.desc.status 0x01)
{
db->stats.rx_fifo_errors++;
printk(
}
if (rx.desc.status 0x02)
{
db->stats.rx_crc_errors++;
printk(
}
if (rx.desc.status 0x80)
{
db->stats.rx_length_errors++;
printk(
}
if (rx.desc.status 0x08)
printk(
}
if (!GoodPacket)
{
// drop this packet!!!
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
for (i=0; i
inb(db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (rx.desc.length + 1) / 2;
for (i = 0; i tmplen; i++)
inw(db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (rx.desc.length + 3) / 4;
for (i = 0; i tmplen; i++)
inl(db->io_data);
break;
}
continue;/*next the packet*/
}
skb = dev_alloc_skb(rx.desc.length+4);
if (skb == NULL )
{
printk(KERN_INFO %s: Memory squeeze.n, dev->name);
/*re-load the value into Memory data read address register*/
iow(db,DM9KS_MDRAH,MDRAH);
iow(db,DM9KS_MDRAL,MDRAL);
return;
}
else
{
/* Move data from DM9000 */
skb->dev = dev;
skb_reserve(skb, 2);
rdptr = (u8*)skb_put(skb, rx.desc.length - 4);
/* Read received packet from RX SARM */
switch (db->io_mode)
{
case DM9KS_BYTE_MODE:
for (i=0; i
rdptr[i]=inb(db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (rx.desc.length + 1) / 2;
for (i = 0; i tmplen; i++)
((u16 *)rdptr)[i] = inw(db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (rx.desc.length + 3) / 4;
for (i = 0; i tmplen; i++)
((u32 *)rdptr)[i] = inl(db->io_data);
break;
}
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb,dev);
#if defined(CHECKSUM)
if (val == 0x01)
skb->ip_summed = CHECKSUM_UNNECESSARY;
#endif
netif_rx(skb);
dev->last_rx=jiffies;
db->stats.rx_packets++;
db->stats.rx_bytes += rx.desc.length;
db->cont_rx_pkt_cnt++;
if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT)
{
dmfe_tx_done(0);
break;
}
}
}while((rxbyte 0x01) == DM9KS_PKT_RDY);
DMFE_DBUG(0, [END]dmfe_packet_receive(), 0);
}
/*
Read a word data from SROM
*/
static u16 read_srom_word(board_info_t *db, int offset)
{
iow(db, DM9KS_EPAR, offset);
iow(db, DM9KS_EPCR, 0x4);
udelay(200);
iow(db, DM9KS_EPCR, 0x0);
return (ior(db, DM9KS_EPDRL) + (ior(db, DM9KS_EPDRH) 8) );
}
/*
Set DM9000A/DM9010 multicast address
*/
static void dm9000_hash_table(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
struct dev_mc_l
以太网 驱动 分析 NIC ISA 公司 DM9000A DM9010 Davicom 相关文章:
- 基于S3C44B0X+μcLinux的嵌入式以太网设计(07-08)
- TM1300 DSP系统以太网接口的设计(03-07)
- 工业级特性在嵌入式处理中至关重要(05-08)
- 基于VxWorks的双端口网卡智能双冗余驱动(07-01)
- 基于μC/OS-II和TCP/IP协议的多串口服务器(08-23)
- 基于DSP/FPGA的以太网控制器的运动控制器设计(02-06)