DM9000任务:
1、把上层传下来的数据sk_buff,抽取有效数据通过DM9000转为二进制发送出去;
2、接收来自其他设备的二进制数据,通过DM9000得到这些数据,然后封装为sk_buff格式,然后提交给上一层。
我们需要对网卡驱动做的主要任务:
1、网卡初始化,然网卡运行起来;
2、注册接收中断函数,中断处理函数负责接收来自其他设备数据,以及当发送完成也会产生中断等。
3、上一层调用我们网卡的一个函数指针:ndev->netdev_ops->ndo_start_xmit来完成包交付给网卡。
首先第一件事网卡初始化要做什么事情?
1、让网卡能运行起来;
对于网卡主要初始化工作是在打开函数。
dm9000_open
dm9000_reset(db);
dm9000_init_dm9000(dev);
在看着两个函数之前,先了解一下DM9000底层操作:
对于硬件操作,由于DM9000内部存在很多寄存器,我们是通过处理器引出的地址线来操作这款芯片,相当于存储芯片一样。所以我们呢可以相当把那些寄存器当做芯片内存,起始地址根据地址引脚得出:
我们6410的静态存储区域是从0x10000000开始的,根据DM9000的CS引脚接到CSN1即第二BANK区,故起始地址是0x18000000。在这个地址开始的就是DM9000的寄存器。
了解一下DM9000的寄存器功能:
用于复位:
NCR (00H):网络控制寄存器(Network Control Register )
NSR (01H):网络状态寄存器(Network Status Register )
用于发送接收设置:
TCR(02H):发送控制寄存器(TX Control Register)
RCR(05H):接收控制寄存器(RX Control Register )
BPTR(08H):背压门限寄存器(Back Pressure Threshold Register)
模式设置:
SMCR(2FH):特殊模式控制寄存器(Special Mode Control Register
中断设置:
IMR(FFH):中断屏蔽寄存器(Interrupt Mask Register)
ISR(FEH):中断状态寄存器(Interrupt Status Register)
PHY设置:
GPCR(1FH):GPIO控制寄存器(General Purpose Control Register)
GPR(1FH):GPIO寄存器(General Purpose Register)
读写寄存器:
MRCMDX(F0H):存储器地址不变的读数据命令; ----用于接下来的读取工作是否有效;
MRCMD(F2H):存储器读地址自动增加的读数据命令---用于读取数据,从DM9000 RX SRAM读取
;
MWCMD(F8H):存储器读地址自动增加的读数据命令---用于发送数据,直接先存放到DM9000 TX SRAM中;
TXPLL(FCH):发送数据包长度寄存器低半字节(TX Packet Length Low Byte Register)
TXPLH(FDH):发送数据包长度寄存器高半字节(TX Packet Length High Byte Register)
判断发送完成是否(在发送完之后判断是否无误发送完成):
TCR(02H):发送控制寄存器(TX Control Register)
TSR_I(03H):数据包指针1的发送状态寄存器1(TX Status Register I)
TSR_II(04H):数据包指针2的发送状态寄存器2(TX Status Register II)
首先看内核如何初始化DM9000:
dm9000_reset:
软件复位:
writeb(DM9000_NCR, db->io_addr); //时能PHY
udelay(200);
writeb(NCR_RST, db->io_data); //复位
udelay(200);
dm9000_init_dm9000:
1、iow(db, DM9000_GPR, 0);/* REG_1F bit0 activate phyxcer */
iow(db, DM9000_GPCR, GPCR_GEP_CNTL);/* Let GPIO0 output */
iow(db, DM9000_GPR, 0);/* Enable PHY */
上面说的很明白,第一句激活PHY,第二句让GPIO0输出,第三句时能PHY。所以PHY要通过芯片GP输出来激活时能的。
2、if (db->wake_supported)
ncr |= NCR_WAKEEN;
iow(db, DM9000_NCR, ncr);
设置DM9000支持睡眠功能,如果该芯片支持。
3、iow(db, DM9000_TCR, 0); /* TX Polling clear */
iow(db, DM9000_BPTR, 0x3f);/* Less 3Kb, 200us */
iow(db, DM9000_FCR, 0xff);/* Flow Control */
iow(db, DM9000_SMCR, 0); /* Special Mode */
设置发送接收寄存器,寄存器相关功能看http://hi.baidu.com/firstm25/item/ae2332588b40e93a33e0a9b0,我也半懂。
4、iow(db, DM9000_IMR, imr);时能接收发送中断位;
到这里DM9000就可以工作了。
总结一下:
软件复位-->使能PHY---->设置发送接收寄存器----->时能发送接收中断。
另外可以参考:http://hi.baidu.com/firstm25/item/a232d8acce42bc9a1510738d
往寄存器读写东西:
static u8 ior(board_info_t * db, int reg)
{
writeb(reg, db->io_addr);
return readb(db->io_data);
}
static void iow(board_info_t * db, int reg, int value)
{
writeb(reg, db->io_addr);
writeb(value, db->io_data);
}
最后来看看内核如何实现读写操作的:
1、发送操作:
首先得到上层数据,然后通过DM9000操作发送出去。
上层调用dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)函数:
1、读取DM9000_MWCMD寄存器的内容,通过db->outblk发送出去(dm9000_outblk_16bit)[通过
DM9000_MWCMD命令写到TX SRAM那里],如果是第一个包,那么就直接发送发送包的长度。如果是第二个包的
话,说明还有一个包在发送中,那么就需要把报的长度和ip_summed就暂停发送netif_stop_queue,直到第一个包发
完产生中断调用dm9000_interrupt函数的时候,再调用dm9000_tx_done函数把刚才没法送的发送出去,最后释放
dev_kfree_skb(skb);
如果接收的话,首先产生中断dm9000_interrupt,读取中断状态知道是接收数据,调用dm9000_rx函数,然后通过DM9000_MRCMDX从读取第一个字节(验证字节),由于DM9000读取的这个第一个字节必须是0x00,0x01,不是的话表示出错。读完之后就可以开始读取数据,通过DM9000_MRCMD命令从DM9000的RX SRAM缓存读取数据了,使用读取函数(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));,然后就是检验数据大小和数据准确性,紧接着就是封装为sk_buff格式了:dev_alloc_skb分配sk_buff,(db->inblk)(db->io_data, rdptr, RxLen)读取数据长度,最后提交给上一层skb->protocol = eth_type_trans(skb, dev)。