07-网络设备驱动的注册与注销
16.2 网络设备驱动的注册与注销
网络设备驱动的注册与注销使用成对出现的register_netdev()和unregister_netdev()函数完成,这两个函数的原型为:
int register_netdev(struct net_device *dev);
void unregister_netdev(struct net_device *dev);
这两个函数都接收一个net_device结构体指针为参数,可见net_device数据结构在网络设备驱动中的核心地位。
net_device的生成和成员的赋值并非一定要由工程师逐个亲自动手完成,可以利用下面的宏帮助我们填充:
define alloc_netdev(sizeof_priv, name, setup) \
alloc_netdev_mq(sizeof_priv, name, setup, 1)
define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
alloc_netdev宏引用的alloc_etherdev_mq()函数的原型为:
struct net_device alloc_netdev_mq(int sizeof_priv, const char name,
void (setup)(struct net_device ), unsigned int queue_count);
alloc_netdev_mq()函数生成一个net_device结构体,对其成员赋值并返回该结构体的指针。第一个参数为设备私有成员的大小,第二个参数为设备名,第三个参数为net_device的setup()函数指针,第四个参数为要分配的子队列的数量。setup()函数接收的参数也为struct net_device指针,用于预置 net_device成员的值。
alloc_etherdev()是alloc_netdev()针对以太网的“快捷”函数,这从alloc_etherdev()引用的alloc_etherdev_mq()函数的源代码可以看出,如代码清单16.3所示。
代码清单16.3 alloc_etherdev()函数
1 struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
2 {
3 / 以ether_setup为alloc_netdev_mq的setup参数 /
4 return alloc_netdev_mq(sizeof_priv, "eth%d", ether_setup, queue_count);
5 }
上述代码中的第4行传入alloc_netdev_mq()函数的第三个参数为ether_setup()函数地址,ether_setup()是由Linux内核提供的一个对以太网设备net_device结构体中公有成员快速赋值的函数。
完成与alloc_enetdev()和alloc_etherdev()函数相反功能,即释放net_device结构体的函数为:
void free_netdev(struct net_device *dev);
net_device结构体的分配和网络设备驱动注册需在网络设备驱动程序的模块加载函数中进行,而net_device结构体的释放和网络设备驱动的注销则需在模块卸载函数中完成,如代码清单16.4所示。
代码清单16.4 网络设备驱动程序的模块加载函数模板
1 int xxx_init_module(void)
2 {
3 ...
4 / 分配net_device结构体并对其成员赋值 /
5 xxx_dev = alloc_netdev(sizeof(struct xxx_priv), "sn%d", xxx_init);
6 if (xxx_dev == NULL)
7 ... / 分配net_device失败 /
8
9 / 注册net_device结构体 /
10 if ((result = register_netdev(xxx_dev)))
11 ...
12 }
13
14 void xxx_cleanup(void)
15 {
16 ...
17 / 注销net_device结构体 /
18 unregister_netdev(xxx_dev);
19 / 释放net_device结构体 /
20 free_netdev(xxx_dev);
21 }