Linux网络设备驱动架構學習(二)
Linux网络设备驱动架構學習(二)
接下來會從以下幾個方面介紹網絡設備驅動的編寫流程:
1、網絡設備的註冊與註銷
2、網絡設備的初始化
3、網絡設備的打開與釋放
4、網絡數據發送流程
5、網絡數據接收流程
6、網絡連接狀態
7、網絡參數設置和統計數據
瞭解了這幾部份內容,網絡設備驅動的編寫方法也就基本明白了
網絡設備的註冊與註銷
网络设备驱动的注册与注销使用成对出现的register_netdev()和unregister_netdev()函数完成,这两个函数的原型为:
int register_netdev(struct net_device *dev);
void unregister_netdev(struct net_device *dev);
这两个函数都接收一个 net_device 结构体指针为参数,可见 net_device 数据结构在网络设备驱动中的核心地位。
net_device 的生成和成员的赋值并非一定要由工程师逐个亲自动手完成,可以利用下面的函数帮助我们填充:
struct net_device *alloc_netdev(int sizeof_priv, const char *name, void(*setup) (struct net_device*));
struct net_device *alloc_etherdev(int sizeof_priv);
alloc_netdev()函数生成一个 net_device 结构体,对其成员赋值并返回该结构体的指针。第一个参数为设备私有成员的大小,第二个参数为设备名,第三个参数为net_device 的 setup()函数指针。setup()函数接收的参数也为 struct net_device 指针,用
于预置 net_device 成员的值。
alloc_etherdev()是 alloc_netdev()针对以太网的“快捷”函数。
完成与 alloc_enetdev()和 alloc_etherdev()函数相反功能,即释放 net_device 结构体的函数为:
void free_netdev(struct net_device *dev);
net_device 结构体的分配和网络设备驱动注册需在网络设备驱动程序的模块加载函数中进行,而 net_device 结构体的释放和网络设备驱动的注销则需在模块卸载函数中完成,如代码清单所示。
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 }
網絡設備的初始化
网络设备的初始化主要需要完成如下几个方面的工作。
1、进行硬件上的准备工作,检查网络设备是否存在,如果存在,则检测设备所使用的硬件资源。
2、进行软件接口上的准备工作,分配 net_device 结构体并对其数据和函数指针成员赋值。
3、获得设备的私有信息指针并初始化其各成员的值。如果私有信息中包括自旋锁或信号量等并发或同步机制,则需对其进行初始化。
对 net_device 结构体成员及私有数据的赋值都可能需要与硬件初始化工作协同进行,即硬件检测出了相应的资源,需要根据检测结果填充 net_device 结构体成员和私有数据。 一个网络设备驱动初始化函数的模板如代码清单所示,具体的设备驱动初始化函数并不一定完全和本模板一样,但是其本质过程是一致的。
1 void xxx_init(struct net_device *dev)
2 {
3 /*设备的私有信息结构体*/
4 struct xxx_priv *priv;
5
6 /* 检查设备是否存在和设备所使用的硬件资源 */
7 xxx_hw_init();
8
9 /* 初始化以太网设备的公用成员 */
10 ether_setup(dev);
11
12 /*设置设备的成员函数指针*/
13 dev->open = xxx_open;
14 dev->stop = xxx_release;
15 dev->set_config = xxx_config;
16 dev->hard_start_xmit = xxx_tx;
17 dev->do_ioctl = xxx_ioctl;
18 dev->get_stats = xxx_stats;
19 dev->change_mtu = xxx_change_mtu;
20 dev->rebuild_header = xxx_rebuild_header;
21 dev->hard_header = xxx_header;
22 dev->tx_timeout = xxx_tx_timeout;
23 dev->watchdog_timeo = timeout;
24
25 /*如果使用 NAPI,设置 pool 函数*/
26 if (use_napi)
27 {
28 dev->poll = xxx_poll;
29 }
30
31 /* 取得私有信息,并初始化它*/
32 priv = netdev_priv(dev);
33 ... /* 初始化设备私有数据区 */
34 }
上述代码第 7 行的 xxx_hw_init()函数完成硬件相关的初始化操作,如下所示。
1、探测 xxx 网络设备是否存在。探测的方法类似于数学上的“反证法”,即先假设存在设备 xxx,访问该设备,如果设备的表现与预期的一致,就确定设备存在;否则,假设错误,设备 xxx 不存在。
2、探测设备的具体硬件配置。一些设备驱动编写得非常通用,对于同类的设备使用统一的驱动,我们需要在初始化时探测设备的具体型号。另外,即便是同一设备,在硬件上的配置也可能不一样,我们也可以探测设备所使用的硬件资源。
3、申请设备所需要的硬件资源,如用 request_region()函数进行 I/O 端口的申请等,但是这个过程可以放在设备的打开函数 xxx_open()中完成。
針對Mini2440 DM9000 驱动probe方法做一個分析就可以對上面兩個過程有一個更清晰的認識
網絡設備的打開與釋放
网络设备的打开函数需要完成如下工作。
1、使能设备使用的硬件资源,申请 I/O 区域、中断和 DMA 通道等。
2、调用 Linux 内核提供的 netif_start_queue()函数,激活设备发送队列。
网络设备的关闭函数需要完成如下工作。
1、调用 Linux 内核提供的 netif_stop_queue()函数,停止设备传输包。
2、释放设备所使用的 I/O 区域、中断和 DMA 资源。
Linux 内核提供的 netif_start_queue()和 netif_stop_queue()两个函数的原型为:
void netif_start_queue(struct net_device *dev);
void netif_stop_queue (struct net_device *dev);
根据以上分析,可得出如代码清单所示的网络设备打开和释放函数的模板。
1 int xxx_open(struct net_device *dev)
2 {
3 /* 申请端口、IRQ 等,类似于 fops->open */
4 ret = request_irq(dev->irq, &xxx_interrupt, 0, dev->name, dev);
5 ...
6 netif_start_queue(dev);
7 ...
8 }
9
10 int xxx_release(struct net_device *dev)
11 {
12 /* 释放端口、IRQ 等,类似于 fops->close */
13 free_irq(dev->irq, dev);
14 ...
15 netif_stop_queue(dev); /* can't transmit any more */
16 ...
17 }
針對Mini2440 DM9000 驱动open,stop方法做一個分析就可以對上面兩個過程有一個更清晰的認識
Linux网络设备驱动架構學習(二)的更多相关文章
- Linux网络设备驱动架構學習(三)
Linux网络设备驱动架構學習(三) 接下來會從以下幾個方面介紹網絡設備驅動的編寫流程: 1.網絡設備的註冊與註銷 2.網絡設備的初始化 3.網絡設備的打開與釋放 4.網絡數據發送流程 5.網絡數據接 ...
- linux设备驱动归纳总结(十二):简单的数码相框【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-116926.html linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxx ...
- linux网络设备驱动
Linux网络设备驱动 Linux网络驱动程序的体系结构可划分为4个层次.Linux内核源代码中提供了网络设备接口及以网络子系统的上层的代码,移植特定网络硬件的驱动程序的主要工作就是完成设备驱动功能层 ...
- 【Linux开发】linux设备驱动归纳总结(十二):简单的数码相框
linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- linux 网络设备驱动
linux 网络驱动 谨以此文纪念过往的岁月 一.前言在linux中网络驱动也是一个大头,如何去理解网络驱动是作为一个linux驱动工程师必备的技能.不过同样的设备,在不同人的手中会有不同的效果,其原 ...
- Linux网络设备驱动(一) _驱动模型
Linux素来以其强大的网络功能著名,同时, 网络设备也作为三大设备之一, 成为Linux驱动学习中必不可少的设备类型, 此外, 由于历史原因, Linux并没有强制对网络设备贯彻其"一切皆 ...
- Linux网络设备驱动架构
Linux网络设备驱动程序体系结构分为四层:网络协议接口层.网络设备接口层.提供实际功能的设备驱动层以及网络设备与媒介层. (1)网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议是AR ...
- Linux网络设备驱动 _驱动模型
Linux素来以其强大的网络功能著名,同时, 网络设备也作为三大设备之一, 成为Linux驱动学习中必不可少的设备类型, 此外, 由于历史原因, Linux并没有强制对网络设备贯彻其"一切皆 ...
- Linux 网络设备驱动开发(一) —— linux内核网络分层结构
Preface Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程,又 ...
随机推荐
- 线段树->面积并 Atlantis HDU - 1542
题目链接:https://cn.vjudge.net/problem/HDU-1542 题目大意:求面积并 具体思路:我们首先把矩形分割成一横条一横条的,然后对于每一个我们给定的矩形,我们将储存两个点 ...
- 让浏览器重新下载css文件,解决不刷新缓存的问题
网站页面源代码中的css文件和js文件后面带一个问号,后面跟着一连串数字或字符,问号起不到实际作用,仅能当作后缀,如果用问号加参数的方法,可以添加版本号等信息 它的作用有:1.作为版本号,让自己方便记 ...
- 解读Android LOG机制的实现【转】
转自:http://www.cnblogs.com/hoys/archive/2011/09/30/2196199.html http://armboard.taobao.com/ Android提供 ...
- Linux6.5 安装Python3.X(转载)
1.获取Python 3.6.3 通过官网https://www.python.org/downloads/下载Python 3.4.3源码: 源码获取命令如下:wget https://www.py ...
- 003_vim使用tip
vim 使用tip 编写python程序 自动插入头信息: #!/usr/bin/env python # coding=utf-8 输入.或按TAB键会触发代码补全功能 :w保存代码之后会自动检查代 ...
- [转]solver优化方法
原文地址:http://www.cnblogs.com/denny402/p/5074212.html 到目前为止,caffe总共提供了六种优化方法: Stochastic Gradient Desc ...
- 测试开发之前端——No2.HTML5中的标签
HTML5中的标签. 标签 描述 <!--...--> 定义注释. <!DOCTYPE> 定义文档类型. <a> 定义超链接. <abbr> 定义缩写 ...
- VirtualBox 安装 Gentoo 小记
因为需求,尝试了一下在 VirtualBox 安装 Gentoo.虽然多年前就折腾过多次 LFS,但 Gentoo 并没有太多尝试.这次确实也经历了种种波折,到最后总算成功了,大致跨度为3天.本来手上 ...
- 切换Intellij ieda 调试为Visual Studio风格
- SpringMVC的@RequestMapping和Controller方法返回值
本节内容: @RequestMapping Controller方法返回值 一.@RequestMapping 通过@RequestMapping注解可以定义不同的处理器映射规则. 1. URL路径映 ...