- UID
- 872238
|
通过模块初始化网络接口是在编译内核时标记为编译为模块。系统在启动时并不知道该接口的存在,需要用户在/etc/rc.d/目录中定义的初始启动脚本中写入命令或手动将模块插入内核空间来激活网络接口。这也给我们在何时加载网络设备驱动程序提供了灵活性。
应用实例
我们以NE2000兼容网卡为例,来具体介绍基于模块的网络驱动程序的设计过程。可以参考文件linux/drivers/net/ne.c和linux/drivers/net/8390.c。
1.模块加载和卸载
NE2000网卡的模块加载功能由init_module()函数完成。具体过程及解释如下:
int init_module(void)
{
int this_dev, found = 0;
//循环检测ne2000类型的网络设备接口
for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++)
{
//获得网络接口对应的net-device结构指针
struct net_device *dev = &dev_ne[this_dev];
dev->irq = irq[this_dev]; //初始化该接口的中断请求号
dev->mem_end = bad[this_dev]; //初始化接收缓冲区的终点位置
dev->base_addr = io[this_dev]; //初始化网络接口的I/O基地址
dev->init = ne_probe; //初始化init为ne_probe,后面介绍此函数
//调用registre_netdevice()向系统登记网络接口,在这个函数中将分配给网络接口在系统中惟一
计算机教程设计Linux系统网络设备驱动程序来自www.itwen.comIT WEN计算机教程网
的名称。并且将该网络接口设备添加到系统管理的链表dev-base中进行管理。
if (register_netdev(dev) == 0) {
found++;
continue; }
… //省略
}
return 0;}
模块卸载功能由cleanup_module()函数来实现。如下所示:
void cleanup_module(void)
{
int this_dev;
//遍历整个dev-ne数组
for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
//获得net-device结构指针
struct net_device *dev = &dev_ne[this_dev];
if (dev->priv != NULL) {
void *priv = dev->priv;
struct pci_dev *idev = (struct pci_dev *)ei_status.priv;
//调用函数指针 idev->deactive将已经激活的网卡关闭使用
if (idev) idev->deactivate(idev);
free_irq(dev->irq, dev);
//调用函数release_region()释放该网卡占用的I/O地址空间
release_region(dev->base_addr, NE_IO_EXTENT);
//调用unregister_netdev()注销 这个net_device()结构
unregister_netdev(dev);
kfree(priv); //释放priv空间
}
}
}
2.网络接口初始化
实现此功能是由ne_probe()函数来完成的。前面已经提到过,在init_module()函数中用它来初始化init函数指针。它主要对网卡进行检测,并且初始化系统中网络设备信息,用于后面的网络数据的发送和接收。具体过程及解释如下:
int __init ne_probe(struct net_device *dev)
{
unsigned int base_addr = dev->base_addr;
//初始化dev-owner成员,因为使用模块类型驱动,会将dev-owner指向对象modules结构指针。
SET_MODULE_OWNER(dev);
//检测dev->base_addr是否合法,是则执行ne-probe1()函数检测过程。 |
|