为了加深印象,所以写一写,,linux内核太复杂了,要搞懂好像我是肯定搞不懂,,不过我感觉把它当做一个工具来用换是不算很难,,,
linux网络设备驱动程序体系结构分为4层,,
(1),网络协议接口层,向网络协议提供统一的发送数据、接收数据函数,dev_queue_xmit(),发送,netif_rx()函数接收数据,,,
因为这一层使得上层协议完全独立于硬件,这一层的内容linux中已经做好了,不需要我们改动。
(2)网络设备接口层,,向上一层协议接口层提供了用于描述具体网络设备属性和操作的net_device,,这个结构图组织了设备驱动中的各信息、各函数,从宏观上规划了具体操作硬件的设备驱动功能层的结构。
(3)设备驱动功能层,实现了net_device数据结构的具体成员,,这些成员可驱使硬件完成动作
(4)网络设备与媒介层,,,即数据发送接收的物理实体。。
对网卡进行移植,主要是对设备驱动层进行操作,,,就是所谓的驱动程序,,但是内核中已经有了这个程序的模板,所以移植的过程只需要改很少的部分就可以。
在网卡驱动移植时,有一个关键知识就是平台设备驱动的问题,,platform,这是一种虚拟总线,,它的优点,我现在想是,实现了设备与驱动的分离,就是硬件描述和驱动程序的分离,,要移植它的驱动,,只需要在硬件描述的文件中添加这个设备的硬件信息,然后找到这个硬件的驱动程序,,,
platform机制中有几个关键的数据结构,,
1,platform_device结构体
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
struct platform_device_id *id_entry;
};
这个结构体描述了设备的硬件信息,,移植时,可在mach-smdk2410.c中定义这个结构体类型的设备,并且赋值,
2,platform_driver结构体
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct device_driver driver;
struct platform_device_id *id_table;
};
这个结构体组织了驱动程序的实现结构,,在驱动程序中定义设备的这个类型的结构体,以及成员函数的实现,,
模块加载时执行platform_driver_register(&dm9000_driver);
这个函数的作用是注册平台设备驱动,,,它里面的功能主要是把定义的平台驱动的信息赋值到struct device_driver driver;结构中,这是一个更加通用的描述驱动程序结构的结构体,,赋值完之后driver_register(&drv_driver),,,,,据说加载平台驱动程序时会执行int (*probe)(struct platform_device *);函数,但是我还没找到哪执行的这个,,,
以后再研究了。。
移植网卡驱动主要有两步,
1.在BSP板文件中加入平台设备结构,,在/arch/arm/mach-s3c2440/mach-smdk2440.c中添加
/* DM9000 */
static struct resource s3c_dm9k_resource[] = {
[0] = {
.start = S3C2410_CS4,
.end = S3C2410_CS4 + 3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = S3C2410_CS4 + 4,
.end = S3C2410_CS4 + 4 + 3,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
}
};
这个结构定义了DM9000所用的资源,,两个内存空间,一个中断资源
添加
static struct dm9000_plat_data s3c_dm9k_platdata = {
.flags = DM9000_PLATF_16BITONLY,
};
该结构指定访问DM9000时,数据宽度为16位
添加
struct platform_device s3c_device_dm9000 = {
.name = "dm9000",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_dm9k_resource),
.resource = s3c_dm9k_resource,
.dev = {
.platform_data = &s3c_dm9k_platdata,
}
};
定义设备结构
在static struct platform_device *smdk2440_devices[] __initdata = {}中添加 &s3c_device_dm9000,系统启动时就会把这个数组中的设备注册到内核中,
然后记得在文件开头加入#include <linux/dm9000.h>,,
2,修改drivers/net/dm9000.c
在文件开头加入
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
然后修改dm9000_probe(struct platform_device *pdev)函数中的一些内容,,比如设置工作模式的寄存器值,,保存默认的寄存器值,比如设置MAC地址的值,这些我觉得没什么意思