《Linux设备驱动开发详解》——第16章 Linux网络设备驱动二
来源:互联网 发布:境外网络电视直播.apk 编辑:程序博客网 时间:2024/05/18 04:55
16.4 网络设备的打开与释放
网络设备打开:
使能设备使用的硬件资源,申请I/O区域,中断和DMA通道等。
调用Linux内核提供的netif_start_queue()函数,激活设备发送队列。
网络设备关闭:
调用Linux内核提供的netif_stop_queue()函数,停止设备传输包。
释放设备所使用的I/O区域,中断和DMA资源。
<pre name="code" class="cpp">
/* 网络设备打开和释放函数模板 */int xxx_open(struct net_device *dev){ /* 申请端口,IRQ等,类似于fops->open */ ret = request_irq(dev->irq, &xxx_interrupt, 0, dev->name, dev); ... netif_start_queue(dev); ...}
<pre name="code" class="plain">
int xxx_release(struct net_device *dev){ /* 释放端口,IRQ等,类似于 fops->close */ free_irq(dev->irq, dev); ... netif_stop_queue(dev); /* can't transmit any more */ ...}
16.5 数据发送流程
Linux网络子系统在发送数据包时,会调用驱动程序提供的hard_start_transmit()函数,该函数用于启动数据包的发送。
网络设备驱动完成数据包发送的流程如下:
(1)网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区。
(2)对于以太网,如果有效数据的长度小于以太网冲突检测所要求数据帧的最小长度ETH_ZLEN,则临时缓冲区的末尾填充0.
(3)设置硬件的寄存器,驱动网络设备进行数据发送操作。
/* 网络设备驱动程序的数据包发送函数模板 */int xxx_tx(struct sk_buff *skb, struct net_device *dev){ int len;
char *data , shortpkt[ETH_ZLEN];
if( xxx_send_available(...) ){ /* 发送队列未满,可以发送 */
/* 获得有效数据指针和长度 */
data = skb->data;
len = skb->len;
if( len < ETH_ZLEN ){
/* 如果帧长小于以太网最小长度,补0 */
memset(shortpkt, 0, ETH_ZLEN);
len = ETH_ZLEN;
data = shortpkt;
}
dev->trans_start = jiffies; /* 记录发送实践戳 */
/* 设置硬件寄存器让硬件把数据包发送出去 */
xxx_hw_tx(data, len, dev);
...
}else{
netif_stop_queue(dev); //当发送队列为满或因其他原因来不及发送当前上层传下来的包,则调用次函数阻止上层继续向网络设备驱动传输数据包
... //当忙于发送的数据包被发送完成后,TX结束的中断处理中,应该调用netif_wake_queue()唤醒被阻塞的上层,以启动它继续向网络设备驱动传输数据包
}}当数据传输超时时,意味着当前的发送操作失败或硬件已陷入未知状态,此时,数据包发送超时处理函数xxx_tx_timeout()将被调用,这个函数也需要调用Linux内核提供的netif_wake_queue()函数重启设备发送队列。
/* 网络设备驱动程序的数据包发送超时函数 */ void xxx_tx_timeout(struct net_device *dev) { ... netif_wake_queue(dev); //重启设备发送队列 }从上文可知,netif_wake_queue() 和 netif_stop_queue() 是数据发送流程中要调用的两个非常重要的函数,分别用于唤醒和阻止上层向下传送数据包,它们的原型定义在 include/linux/netdevice.h,如下:
static inline void netif_wake_queue(struct net_device *dev):
static inline void netif_stop_queue(struct net_device *dev):
16.6 数据接收流程
网络设备接收数据的主要方式是由中断引发设备的中断处理函数。中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buff数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()将sk_buff传递给上层协议。
/* 网络设备驱动的中断处理函数 */static void xxx_interrupt(int irq, void *dev_id){ ... switch(status & ISQ_EVENT_MASK){
case ISQ_RECEIVER_EVENT:
/* 获取数据包 */
xxx_rx(dev);
break;
/* 其他类型的中断 */ }}
<pre name="code" class="cpp">
static void xxx_rx(struct xxx_device *dev){ ... length = get_rev_len(...); /* 分配新的套接字缓冲区 */ skb = dev_alloc_skb(length + 2); skb_reserve(skb, 2); //对齐 skb->dev = dev; /* 读取硬件上接收到的数据 */、 insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1); if( length & 1 ) skb->data[length - 1] = inw(ioaddr + RX_FRAME_PORT); /* 获取上层协议类型 */ skb->protocol = eth_type_trans(skb, dev); /* 把数据包递交给上层 */ netif_rx(skb); /* 记录接收实践戳 */ dev->last_rx = jiffies; ...}如果是NAPI兼容的设备驱动,则可以通过poll方式接收数据包,这种情况下,我们需要为设备驱动提供作为netif_napi_add()参数的xxx_poll()函数
- 《Linux设备驱动开发详解》——第16章 Linux网络设备驱动二
- 《Linux设备驱动开发详解》——第16章 Linux网络设备驱动一
- Linux设备驱动开发详解-第6章字符设备驱动(二)-支持2个globalmem
- 《Linux4.0设备驱动开发详解》笔记--第十四章:Linux网络设备驱动
- 第16章 Linux网络设备驱动
- Linux设备驱动之网络设备驱动
- 《Linux设备驱动开发详解》第2版第6章 - 字符设备驱动
- 《Linux设备驱动开发详解》第2版第6章 - 字符设备驱动
- 《Linux设备驱动开发详解》第2版第6章 - 字符设备驱动
- linux网络设备驱动(二)
- Linux设备驱动开发详解-第4章(二)-模块参数
- Linux 网络设备驱动开发(三) —— 网络设备驱动基本原理和框架
- Linux 网络设备驱动开发(三) —— 网络设备驱动基本原理和框架
- Linux 网络设备驱动开发(二) —— Linux 网络栈剖析
- Linux 网络设备驱动开发(二) —— Linux 网络栈剖析
- Linux设备驱动开发详解-第6章字符设备驱动(一)-globalmem
- linux中秒字符设备驱动(宋宝华设备驱动开发详解第10章)
- Linux驱动开发-15、网络设备驱动
- LoadRunner关联详解
- jquery $(document).ready() 与window.onload的区别
- android解决无法设定listview的item高度
- python抓取网页的html
- innerHTML、innerText和outerHTML、outerText的区别
- 《Linux设备驱动开发详解》——第16章 Linux网络设备驱动二
- zigbee zstack的关系
- 【快速幂取模】HDU 1061---Rightmost Digit
- 学习 easyui 之四:禁用 linkbutton 问题
- linux下tar.gz、tar、bz2、zip等解压缩、压缩命令小结
- POJ 2947 Widget Factory
- hdu1233还是畅通工程(并查集加Kruskal算法)
- 数据库如何降级?
- 取数组/序列之和k最小