从硬件层次驱动网卡

来源:互联网 发布:w网络资源管理系统 编辑:程序博客网 时间:2024/05/01 10:28

没有操作系统情况下如何驱动网卡:


1、对于网卡命令可以直接使用drivers/net/dm9000.h文件,里面包含了各个寄存器。

2、要确定板子和DM9000的接线,确定网卡寄存器的起始地址,我的是接在6410的静态存储区域的BANK2,端口起始地址为0x18000000,这样就可以度确定DM9000的地址端口是0x18000000,数据(地址)端口是0x18000004。对于DM9000寄存器操作就是基于这两个端口


引用网上:

DM9000对外来说只有两个端口——地址口和数据口,地址口用于输入内部寄存器的地址,而数据口则完成对某一寄存器的读写。DM9000CMD引脚用来区分这两个端口,当CMD引脚为0时,DM9000的数据线上传输的是寄存器地址,当CMD引脚为1时,传输的是读写数据。我们把DM9000AEN接到s3c2440nGCS4引脚上,则DM9000的端口基址为0x20000300,如果再把DM9000CMD引脚接到s3c2440ADDR2引脚上 



3、DM9000初始化:

首先如何往寄存器写内容?

引用内核的:

static u8  ior( int reg)
{


writeb(reg, 地址端口);  //对于读操作,要先往地址端口写待操作寄存器
return readb(数据端口);  //通过数据端口读取该操作寄存器的数据
}


/*
 *   Write a byte to I/O port
 */

static void  iow(int reg, int value)
{
writeb(reg, 地址端口);  //对于写操作,要先往地址端口写入待操作寄存器
writeb(value, 数据端口); //再通过数据端口往操作寄存器写入数据
}


现在就可以通过操作寄存器来初始化网卡了:

PHY使能:

iow(DM9000_GPCR, 0x01);//使DM9000的GPIO3为输出。
iow(DM9000_GPR,  0x00);//通过DM9000的GPIO3输出以激活内部PHY。
udelay(5000);

软件复位:
iow(DM9000_NCR,  0x03);//复位
udelay(3000);
iow(DM9000_NCR,  0x00);
iow(DM9000_NCR,  0x03);//第二次软件复位。
udelay(3000);
iow(DM9000_NCR,  0x00);    

清除标志位:

iow(DM9000_NSR,  0x2c);//清除网络状态标志位
iow(DM9000_ISR,  0xbf);//清除中断标志位

接收发送设置:

    iow(DM9000_RCR,  0x39);//接收控制:使能接收、忽略所有多点传送、丢弃CRC错误包、数据长度过大包也丢弃
    iow(DM9000_TCR,  0x00);//发送控制
    iow(DM9000_BPTR, 0x3f);  //设置拥挤状态
    iow(DM9000_FCTR, 0x38);//设置接收FIFO溢出门限,当FIFO达到该门限将暂停发送或者接收
    iow(DM9000_FCR,  0xff);  使能溢出控制模式
    iow(DM9000_SMCR, 0x00);

设置网卡物理地址:

 iow(DM9000_PAR + i, macaddr[i]);//物理地址40bit位,需要循环5次,每一次1byte

使能中断:

iow(DM9000_IMR, 0x81);


4、开发板连接到网卡的INT引脚的对应引脚将会产生中断,所以需要设置开发板该引脚为中断模式。


5、到这里网卡就运行起来了,紧接着就是收发函数实现了:

有数据到达,那么产生中断,在中断里获取收到的数据:

首先通过命令DM9000_MRCMDX读取一个数据判断接下来是否有数据读获取:

iow(DM9000_ISR, 0x01);  //清中断位

statue= ior(DM9000_MRCMDX); // 第一次读取,读到的数据要是0x00或者0x01
如果读取的不是0x00或者0x01,那么再读一次,如果还是不行,那么说明可能网卡没有正常工作,这样的话就重新初始化网卡。

如果再次读取还是不行,那么就直接返回,可能因为某些原因数据不存在了。

如果数据可以读取那么就:

地址端口 = DM9000_MRCMD;  //不适用读操作函数,因为我们要连续读取,如果使用ior会多次往地址端口写DM9000_MRCMD

len=数据端口;  //读取数据端口获取待读取数据长度,然后根据长度读取数据,如下:

data= 数据端口;  //通过for循环夺取len长度的数据

到这里就完成接收数据,在内核里封装为sk_buff包通过netif_rx函数交给上一层,我们这里可以直接把数据打印出来printf;


6、说完接收,现在说发送函数:

首先禁止中断

iow(DM9000_IMR,0x80);

发送待发送数据长度:

iow(DM9000_TXPLH, (len>>8) & 0x0ff);
iow(DM9000_TXPLL, len & 0x0ff);

通过DM9000_MWCMD吧待发送数据放到DM9000的TX SRAM缓存,交给DM9000发送:

地址端口= DM9000_MWCMD;

数据短裤 = datas[i] | (datas[i+1]<<8);  //通过for循环发送,由于我们DM9000使用16bit数据位,所以要以16bit为单位发送

iow(DM9000_TCR, 0x01);  //启动发送请求

最后通过判断状态位来判断是否发送完成即可:

通过 tior(DM9000_NSR)判断是否发送完成,入股发送完成的话通过ior(DM9000_TSR1)和ior(DM9000_TSR2)判断发送的包是否有出错,如果这些都OK说明发送正确无误完成!!

清除标志位和打开接收中断   

  ior(DM9000_NSR, 0x2c)

ior(DM9000_IMR, 0x81);


对于内核而言,待发送的包格式是上层来的sk_buff,我们要抽取有效数据发生,对于我们裸板来说就直接发送数据即可!


原创粉丝点击