从硬件操作到内核来谈网卡驱动

来源:互联网 发布:软件专业就业 编辑:程序博客网 时间:2024/05/01 12:21


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开始的,根据DM9000CS引脚接到CSN1即第二BANK区,故起始地址是0x18000000。在这个地址开始的就是DM9000的寄存器。


了解一下DM9000的寄存器功能:


用于复位:

NCR 00H):网络控制寄存器(Network Control Register 

NSR 01H):网络状态寄存器(Network Status Register 


用于发送接收设置:

TCR02H):发送控制寄存器(TX Control Register

RCR05H):接收控制寄存器(RX Control Register 

BPTR08H):背压门限寄存器(Back Pressure Threshold Register


模式设置:

SMCR2FH):特殊模式控制寄存器(Special Mode Control Register


中断设置:

IMRFFH):中断屏蔽寄存器(Interrupt Mask Register

ISRFEH):中断状态寄存器(Interrupt Status Register

PHY设置:

GPCR1FH):GPIO控制寄存器(General Purpose Control Register

GPR1FH):GPIO寄存器(General Purpose Register

读写寄存器:

MRCMDXF0H):存储器地址不变的读数据命令;  ----用于接下来的读取工作是否有效;


MRCMDF2H):存储器读地址自动增加的读数据命令---用于读取数据,从DM9000 RX SRAM读取


MWCMDF8H):存储器读地址自动增加的读数据命令---用于发送数据,直接先存放到DM9000 TX SRAM中;


TXPLLFCH):发送数据包长度寄存器低半字节(TX Packet Length Low Byte Register


TXPLHFDH):发送数据包长度寄存器高半字节(TX Packet Length High Byte Register


判断发送完成是否(在发送完之后判断是否无误发送完成):

TCR02H):发送控制寄存器(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


1iow(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输出来激活时能的。


2if (db->wake_supported)


ncr |= NCR_WAKEEN;


iow(db, DM9000_NCR, ncr);

设置DM9000支持睡眠功能,如果该芯片支持。


3iow(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,我也半懂。


4iow(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命令从DM9000RX 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)




原创粉丝点击