实现与局域网传输介质之间物理连接和电信号匹配,还涉及帧的发送和接收,真的封装与拆封,介质访问控制,数据的编码与解码及数据缓存的功能
9.2 网络设备驱动程序体系结构
9.2.1 嵌入式linux网络驱动介绍
9.2.2 Linux网络设备驱动的体系结构
9.2.3 网络设备驱动程序编写方法
1.初始化
2.数据包的发送和接收
3.实现模式
4.
9.2.4 网络设备驱动程序应用实例
1.模块加载和卸载
2.网络接口初始化
9.3 net_device 数据结构
9.3.1 全局信息
9.3.1 硬件信息
9.3.3 接口信息
9.3.4 设备方法
9.3.5 公用成员
9.4 DM9000网卡概述
9.4.1 总述
9.4.2 特点
9.4.3 内部寄存器
1.网络控制寄存器(NCR)
2.网络状态寄存器(NSR)
3.发送控制寄存器(TCR)
4.数据包指针1的发送状态寄存器1(TSR_I)
5.数据包指针2的发送状态寄存器2(TSR_II)
6.接收控制寄存器(RCR)
7.接收状态寄存器(RSR)
8.接收/发送溢出控制寄存器(RTFCR)
9.发送数据长度寄存器
10.中断状态寄存器
11.中断掩码寄存器(IMR)
9.4.4 功能描述
1.总线
2.存储器直接访问控制
3.包的发送
9.5 DM9000网卡驱动移植 driver/net/ethernet/davicom/dm9000.c
9.5.1 网卡连接
********************DM9000网卡与芯片连接图*************
1.GCS4作为片选信号,所以访问DM9000基址为0x20000000,这是物理地址
2.CMD:高电平,数据总路线传输数据信号,反之传递地址信号。每次访问需要先将CMD置为低电平发送地址信号,然后置高读写数据
3.总路线宽为16位,用你WAIT信号
4.用EINT7外部中断作为中断引脚。
9.5.2 驱动分析---硬件数据结构
/* Structure/enum declaration ------------------------------- */
struct board_info {
void __iomem *io_addr; //地址基址,这两个地址是内核虚拟地址不是物理地址/* Register I/O base address */
void __iomem *io_data; //数据基址/* Data I/O address */
u16 irq; /* IRQ 中断号*/
u16 tx_pkt_cnt; //发包计数
u16 queue_pkt_len; //队列长度
u16 queue_start_addr;//队列开始地址
u16 queue_ip_summed;
u16 dbug_cnt;
u8 io_mode; /* 0:word, 2:byte */
u8 phy_addr;
u8 imr_all;
unsigned int flags;
unsigned int in_timeout:1;
unsigned int in_suspend:1;
unsigned int wake_supported:1;
//
enum dm9000_type type;
void (*inblk)(void __iomem *port, void *data, int length); //输入方法
void (*outblk)(void __iomem *port, void *data, int length); //输出方法
void (*dumpblk)(void __iomem *port, int length);
struct device *dev; /* parent device */
struct resource *addr_res; /* resources found *///找到在devs.c中定义的资源
struct resource *data_res;
struct resource *addr_req; /* resources requested *///根据addr_res申请到的资源,上面两个只是知道了网卡所使用的所有资源,但在内核中,物力资源的使用时要经过申请的
struct resource *data_req;
int irq_wake;
struct mutex addr_lock; /* phy and eeprom access lock */
struct delayed_work phy_poll;
struct net_device *ndev;
spinlock_t lock; //自旋锁
struct mii_if_info mii;//mii信息
u32 msg_enable; //使能标志
u32 wake_state;
int ip_summed;
};
以上用于保存设备属性和相关操作,是设备的物理抽象,最后被挂载到net_device的priv成员也
9.5.3 驱动分析---数据读写函数
DM9000地址和数据线复用,故读写方法特别。
当从网卡某个寄存器读值时,要先在地址基址中写入要读取的寄存器地址,然后再从数据基址读取数据。
/*
* Read a byte from I/O port
*/
static u8
ior(struct board_info *db, int reg)
{
writeb(reg, db->io_addr);
return readb(db->io_data);
}
当从网卡某寄存器写入值时,要现在地址基址中写入目标寄存器地址,然后再从数据机制中写入要写进去的数据
/*
* Write a byte to I/O port
*/
static void
iow(struct board_info *db, int reg, int value)
{
writeb(reg, db->io_addr);
writeb(value, db->io_data);
}
9.5.4 驱动分析---重置网卡
启动网卡前要重置,全部网络控制寄存器写入1
static void
dm9000_reset(struct board_info *db)
{
dev_dbg(db->dev, "resetting device\n");//调试信息
/* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29
* The essential point is that we have to do a double reset, and the
* instruction is to set LBK into MAC internal loopback mode.
*/
iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK);//写入要操作的寄存器地址这里是NCR
udelay(100); /* Application note says at least 20 us *///延时200
if (ior(db, DM9000_NCR) & 1)
dev_err(db->dev, "dm9000 did not respond to first reset\n");
iow(db, DM9000_NCR, 0);
iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK);
udelay(100);
if (ior(db, DM9000_NCR) & 1)//写入置位值,这里是1
dev_err(db->dev, "dm9000 did not respond to second reset\n");
}
9.5.5 驱动分析---初始化网卡
由dm9000_probe完成,
1.主要是获取和申请硬件资源,
2.申请中断号
3.初始化net_device结构体
4.最后注册网络设备
9.5.6 驱动分析---打开和关闭网卡
打开即**网络接口,使能接收网络数据,并能传送到网络协议栈,也可将数据发送到网络上,二网卡的关闭就是是网络接口停止工作。
static int dm9000_open()
9.5.7 驱动分析---数据包的发送和接收
驱动层次,数据包的收发都是通过底层对硬件读写完成,网络来数据将触发硬件中断,根据注册的中断向量表确定处理函数,进入中断向量处理函数,将数据送到上层协议进行处理或转发。
当协议层已封装好上层协议数据的skb_buffer后,将调用dm9000_start_xmit(struct sk_buff* skb,structnet_device *dev)把数据发送出去
********************8dm9000_start_xmit**************
网络数据包到达,DM9000自动接收并存放在DM9000内部RAM中,产生中断。在中断处理中识别中断原因,并调用接收处理函数。
接收函数如下
static void dm9000_rx()
9.5.8 DM9000网卡驱动移植
1.定义网卡设备
硬件的使用需要知道硬件所用道德资源,如IO端口和中断号,在arch/arm/plat-s3c24xx中的devs.c添加DM9000用到的地址端口,数据端口,和中断号。
要依据硬件连接图
1.static struct resource s3c_dm9000_resource[]={}
2.添加DM9000平台数据,该数据用于内核传递给驱动程序,
arch/arm/mach-s3c2410/devs.c 定义platform_device挂载到structplatform_device结构体成员的dev.platform_data中。
DM9000平台数据结构定义在include/linux/dm9000.h,定义如下
struct dm9000_plat_data{
unsigned int flags;
void (*inblk)
void (*outblk)
void(*dumpblk)
}
arch/arm/plat-s3c24xx中的devs.c,只需添加以下
static struct dm9000_plat_data s3c_device_dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY
};
struct platform_device s3c_device_dm9000 ={
.name = "dm9000",
.id =-1,
.num
.resource
.dev = {
.platform_data = &s3c_device_dm9000_platdata,
}
};
EXPORT_SYMBOL(s3c_device_dm9000); //声明为全局变量,
2.添加变量声明
在arch/arm/plat-S3c24xx/include/plat/devs.h声明如下
extern struct platform_device s3c_device_dm9000;
3.添加平台设备列表
添加网络设备到系统启动设备初始化列表中
static struct platform_device *smdk2440_devices[] __initdata ={
}
4.修改dm9000.c
0.前面已经完成设备注册到驱动核心
1.设置芯片MAC地址
2.使能DM9000中断
修改如下
1.设置GPGCON使GPG1功能设置为EINT7,使用s3c2410_gpio_cfgpin(S3C2410_GPG1,S3C2410_GPF3_EINT7);
2.外部中断EXTINT1的[6:4]位置100上升沿触发中,因用到GPIO寄存器地址,必须在文件开头吧相关mach/regs-gpio.h文件包含仅dm9000.c;
#include<mach/regs-gpio.h>
static void *extin1; //中断寄存器地址
static void *intmsk; //中断屏蔽寄存器地址
#define EINTMASK (0x560000a4)//外部中断屏蔽
#define EXTINT1 (0x5600008c) //外部中断方式
#define INTMSK (0x4A000008) //中断屏蔽
3.在dm9000.c中初始化函数xxx_probe的register_netdev添加如下
memcpy(ndev->dev_addr,"\0andy1",6);
extin1 = ioremap_nocache(EXTINT1,4);
intmsk = ioremap_nocache(INTMSK,4);
s3c2410_gpio_cfgpin(S3C2410_GPF7,S3C2410_GPF7_EINT7);
write1(readl(extin1)|0x40,extin1);
write1(read1(intmsk)&0xfff1,intmsk);
iounmap(intmsk);
iounmap(extint1);
5.编译内核
device drivers -> Network device support ->Ethernet(10 or 100Mbit)->DM9000support
9.6 小结--分析硬件,内核自带驱动,讲述移植--了解网络驱动体系结构
9.2解释基础,特别是网络数据结构的主要成员含义