第九章 Linux网络设备驱动程序
设备驱动程序简介
设备驱动程序简介1.设备驱动程序的作⽤从⼀个⾓度看,设备驱动程序的作⽤在于提供机制,⽽不是策略。
在编写驱动程序时,程序猿应该特别注意以下这个基本概念:编写訪问硬件的内核代码时,不要给⽤户强加不论什么特定策略。
由于不同的⽤户有不同的需求,驱动程序应该处理如何使硬件可⽤的问题。
⽽将如何使⽤硬件的问题留给上层应⽤程序。
从还有⼀个⾓度来看驱动程序。
它还能够看作是应⽤程序和实际设备之间的⼀个软件层。
总的来说,驱动程序设计主要还是综合考虑以下三个⽅⾯的因素:提供给⽤户尽量多的选项、编写驱动程序要占⽤的时间以及尽量保持程序简单⽽不⾄于错误丛⽣。
2.内核功能划分Unix系统⽀持多进程并发执⾏。
每⼀个进程都请求系统资源。
内核负责处理全部这些请求,依据内核完毕任务的不同,可将内核功能分为例如以下⼏部分:1.进程管理:负责创建和销魂进程。
并处理它们和外部世界之间的连接。
内核进程管理活动就是在单个或多个CPU上实现了多个进程的抽象。
2.内存管理:内存是计算机的主要资源之中的⼀个,⽤来管理内存的策略是决定系统系能的⼀个关键因素。
3.⽂件系统:内核在没有结构的硬件上构造结构化的⽂件系统。
⽽⽂件抽象在整个系统中⼴泛使⽤。
4.设备控制:差点⼉每个系统操作终于都会映射到物理设备上。
5.⽹络功能:⽹络功能也必须由操作系统来管理,系统负责在应⽤程序和⽹络接⼝之间传递数据包,并依据⽹络活动控制程序的运⾏。
全部的路由和地址解析问题都由内核处理。
可装载模块:Linux有⼀个⾮常好的特性:内核提供的特性可在执⾏时进⾏扩展。
可在执⾏时加⼊到内核的代码被称为“模块”。
Linux内核⽀持⼏种模块类型。
包含但不限于设备驱动程序。
每⼀个模块由⽬标代码组成,能够使⽤insmod程序将模块连接到正在执⾏的内核,也能够使⽤rmmod程序移除连接。
3.设备和模块的分类Linux系统将设备分成三个基本类型:字符设备、块设备、⽹络接⼝。
1.字符设备:字符设备驱动程序通常⾄少要实现open、close、read和write系统调⽤。
LINUX设备驱动程序(4)
协议简介
对于网络的正式介绍一般都采用 OSI (Open Systems Interconnection)模型, 但是Linux 中网络栈的介绍一般分为四层的 Internet 模型。
协议栈层次对比
OSI七层网络模型 应用层 表示层 会话层 传输层 网络层
数据链路层 物理层
Linux TCP/IP 四层概念模型
网络协议
网络协议层用于实现各种具体的网络协议, 如: TCP、UDP 等。
设备无关接口
设备无关接口将协议与各种网络设备驱动连接在一起。 这一层提供一组通用函数供底层网络设备驱动程序使用,让 它们可以对高层协议栈进行操作。
首先,设备驱动程序可能会通过调用 register_netdevice 或 unregister_netdevice 在内核中 进行注册或注销。调用者首先填写 net_device 结构,然后 传递这个结构进行注册。内核调用它的 init 函数(如果定义 了这种函数),然后执行一组健全性检查,并将新设备添加 到设备列表中(内核中的活动设备链表)。
驱动程序
网络栈底部是负责 管理物理网络设备 的设备驱动程序。
第二节 网卡驱动程序设计
设备注册
设备描述:
每个网络接口都由一个 net_device结构来描述
注册: 网络接口驱动的注册方式与字符驱动不同之处在于 它没有主次设备号,并使用如下函数注册。
int register_netdev(struct net_device *dev)
Linux网络子系统架构
Linux协议架构
Linux 网络子系统的顶部是系统调用接口。它为用 户空间的应用程序提供了一种访问内核网络子系统 的方法。位于其下面的是一个协议无关层,它提供 了一种通用方法来使用传输层协议。然后是具体协 议的实现,在 Linux 中包括内嵌的协议 TCP、 UDP,当然还有 IP。然后是设备无关层,它提供了 协议与设备驱动通信的通用接口,最下面是设备驱 动程序。
Linux驱动程序
Linux系统下有关主设备号的分配原则,可参看 documentation/device.txt。
10
内核模块
Linux驱动程序可通过两种方式集成到内核中去:
直接编译到内核;
随时调用,但占内核空间, 修改驱动要重新编译内核。
编写成模块,需要时内核将其调入。在配置 Linux内核时,可以选择“Enable loadable module support”选项,来支持可加载内核模块。
网络设备:网络设备访问的 BSD socket接口, 如网卡等;
杂项设备:特殊驱动程序,如IIC、USB等。
8
Linux设备号
设备号是一个数字,是设备的标志,由主设备号 和次设备号组成,主设备号表明某一类设备,主设 备号相同的设备使用相同的驱动程序;次设备号用 来标识具体设备的实例。
例如,系统中块设备IDE 硬盘的主设备号是 3, 而多个 IDE 硬盘及其各个分区分别赋予次设备号1、 2、……
27
file结构
file结构,即文件结构,代表一个打开的文件描述符,它不 同于应用程序空间的FILE指针,FILE指针定义在C库中, struct file只出现在内核代码中,不出现在用户程序中。
28
file常用成员-1
struct dentry *f_dentry;
文件对应的目录项结构,除了使用flip->f_dentry->d_inode的 方法访问索引节点结构外,驱动开发人员一般无需关心。
16
驱动开发流程
内核模块一般都至少包含两个函数:初始化函数和卸载函 数,其它函数则跟设备相关。 宏module_init和module_exit用于注册初始化函数和卸载函 数。
17
Linux设备驱动程序原理及框架-内核模块入门篇
Linux设备驱动程序原理及框架-内核模块入门篇内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块内核模块介绍Linux采用的是整体式的内核结构,这种结构采用的是整体式的内核结构,采用的是整体式的内核结构的内核一般不能动态的增加新的功能。
为此,的内核一般不能动态的增加新的功能。
为此,Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制,可安装) 提供了一种全新的机制模块” )。
利用这个机制“模块”(module)。
利用这个机制,可以)。
利用这个机制,根据需要,根据需要,在不必对内核重新编译链接的条件将可安装模块动态的插入运行中的内核,下,将可安装模块动态的插入运行中的内核,成为内核的一个有机组成部分;成为内核的一个有机组成部分;或者从内核移走已经安装的模块。
正是这种机制,走已经安装的模块。
正是这种机制,使得内核的内存映像保持最小,的内存映像保持最小,但却具有很大的灵活性和可扩充性。
和可扩充性。
内核模块内核模块介绍可安装模块是可以在系统运行时动态地安装和卸载的内核软件。
严格来说,卸载的内核软件。
严格来说,这种软件的作用并不限于设备驱动,并不限于设备驱动,例如有些文件系统就是以可安装模块的形式实现的。
但是,另一方面,可安装模块的形式实现的。
但是,另一方面,它主要用来实现设备驱动程序或者与设备驱动密切相关的部分(如文件系统等)。
密切相关的部分(如文件系统等)。
课程内容内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块应用层加载模块操作过程内核引导的过程中,会识别出所有已经安装的硬件设备,内核引导的过程中,会识别出所有已经安装的硬件设备,并且创建好该系统中的硬件设备的列表树:文件系统。
且创建好该系统中的硬件设备的列表树:/sys 文件系统。
(udev 服务就是通过读取该文件系统内容来创建必要的设备文件的。
)。
linux网络基础知识
Linux网络基础知识TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
这4层分别为:应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。
传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。
网络接口层(网络接口层例如以太网设备驱动程序):对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。
网络接口层在发送端将上层的IP数据报封装成帧后发送到网络上;数据帧通过网络到达接收端时,该结点的网络接口层对数据帧拆封,并检查帧中包含的MAC地址。
如果该地址就是本机的MAC地址或者是广播地址,则上传到网络层,否则丢弃该帧。
网络接口层可细分为数据链路层和物理层,数据链路层实际上就是网卡的驱动程序,物理层实际上就是布线、光纤、网卡和其它用来把两台网络通信设备连接在一起的东西。
链路层,有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。
它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。
网卡驱动程序主要实现发送数据帧与接受数据帧的功能,发送数据帧采用内核函数hard_start_xmit();接收数据帧采用内核函数netif_rx();网卡驱动程序主要是分配设置及注册net_dev结构体;数据帧的载体采用sk-buff结构体。
用浏览网页为例:发送方:1.输入网址:,按了回车键,电脑使用应用层用IE浏览器将数据从80端口发出,给了下一层协议——传输层。
LINUX下安装无线网卡驱动程序
1.1下载驱动程序一、首先弄清楚当前使用的是什么版本的Linux,如:Redhat9.0、Freda core5等。
Linux用的是什么版本的内核,可以用uname –a得知内核版本号。
二、使用的是什么接口类型的无线网卡,常见的接口类型有PCI (台式机)、Cardbus/PCMCIA(笔记本)、USB(台式机、笔记本)等。
三、无线网卡使用的是哪一种类型的芯片,判断方法如下,到相关网站下载与其相对应的驱动程序。
常用的无线网卡驱动及其支持的芯片类型和接口类型如下表1所示。
PCMCIA卡:将无线网卡插入笔记本电脑中,用命令lspci可以看到芯片类型,如:Realtek Semiconductor Co.. Ltd, RTL8180L802.11b MAC (rev 20)其中RTL8180L即为网卡芯片类型,用参数v可以看到更详细的信息。
USB卡:用命令lsusb可以看到芯片类型(fc5没有此命令)。
通过其它方法查找。
驱动程序芯片类型接口类型官方网站下载页Linux-wlan-ng Prism2/2.5/3 Cardbus/PCI/USB /download.shtml Madwifi Atheros系列Cardbus/PCI /islsm ISL38XX USB/PCI http://jbnote.free.fr/prism54usb/index.html表1:网卡驱动程序有关信息1.2驱动程序的安装每款驱动的安装方法各不相同,阅读INSTALL文档,获得驱动程序的具体安装方法及系统内核要求。
阅读驱动程序附带的README文档,获得有关此驱动的详细信息,如驱动所支持的网络模式、接口类型、所包含的模块的功能及无线网卡的配置等。
下面是安装网卡驱动程序的一般步骤:编译网卡驱动程序#make安装驱动程序模块#make install加载模块#modprobe 主模块名安装好驱动后插入无线网卡,命令iwconfig可以查看驱动是否加载成功,如果出现新的设备名,则说明驱动已经装上并且能够识别出无线网卡。
Linux网络设备驱动_PCI网卡
⏹ Linux 网络设备驱动结构Linux的加载和卸载设备的注册初始化和注销设备的打开和释放据包的发送和接收络连接状况数设置和统计数据此驱动所支持的网卡系列初始化网络设备注销网络设备设备挂起函数设备恢复函数打开网络设备关闭网络设备读取包的网卡收发包的状态,统计数据用户的ioctl 命令系统调用硬件处理数据包发送ISR 数据包发送和接收⏹ struct pci_driver如果网络设备(包括wireless )是PCI 规范的,则先是向内核注册该PCI 设备(pci_register_driver),然后由pci_driver 数据结构中的probe 函数指针所指向的侦测函数来初始化该PCI 设备,并且同时注册和初始化该网络设备。
如果网络设备(包括wireless )是PCMCIA 规范的,则先是向内核注册该PCMCIA 设备(register_pccard_driver),然后driver_info_t 数据结构中的attach 函数指针所指向的侦测函数来初始化该PCMCIA 设备,并且同时注册和初始化该网络设备。
1. 申明为PCI 设备:static struct pci_driver tg3_driver = {.name = DRV_MODULE_NAME,//此驱动所支持的网卡系列,vendor_id, device_id.id_table = tg3_pci_tbl,//初始化网络设备的回调函数.probe = tg3_init_one,//注销网络设备的回调函数.remove = __devexit_p(tg3_remove_one),//设备挂起函数.suspend = tg3_suspend,//设备恢复函数.resume = tg3_resume};2. 驱动模块的加载和卸载static int __init tg3_init(void){//先注册成PCI设备,并初始化,如果是其他的ESIA,PCMCIA,用其他函数return pci_module_init(&tg3_driver);}static void __exit tg3_cleanup(void){pci_unregister_driver(&tg3_driver);//注销PCI设备}module_init(tg3_init); //驱动模块的加载module_exit(tg3_cleanup); //驱动模块的卸载3. PCI设备探测函数probe,初始化网络设备主要工作:申请并设置pci资源(内存),申请并设置net_device网络设备结构,IO映射,注册网络设备static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){//初始化设备,使I/O,memory可用,唤醒设备pci_enable_device(pdev);//申请内存空间,配置网卡的I/O,memory资源pci_request_regions(pdev, DRV_MODULE_NAME);pci_set_master(pdev);//设置DMA属性pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff);//网卡 I/O,memory资源的启始地址tg3reg_base = pci_resource_start(pdev, 0);//网卡I/O,memory资源的大小tg3reg_len = pci_resource_len(pdev, 0);//分配并设置网络设备dev = alloc_etherdev(sizeof(*tp));//申明为内核设备模块SET_MODULE_OWNER(dev);//初始化私有结构中的各成员值tp = dev->priv;tp->pdev = pdev;tp->dev = dev;……//锁的初始化spin_lock_init(&tp->lock);//映射I/O,memory地址到私有域中的寄存器结构tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);dev->irq = pdev->irq;//网络设备回调函数赋值dev->open = tg3_open;dev->stop = tg3_close;dev->get_stats = tg3_get_stats;dev->set_multicast_list = tg3_set_rx_mode;dev->set_mac_aDDRess = tg3_set_mac_addr;dev->do_ioctl = tg3_ioctl;dev->tx_timeout = tg3_tx_timeout;dev->hard_start_xmit= tg3_start_xmit;//网卡的MAC地址赋值dev->addrtg3_get_device_address(tp);//注册网络设备register_netdev(dev);//把网络设备指针地址放入PCI设备中的设备指针中pci_set_drvdata(pdev, dev);}4. 注销网络设备主要工作:注销并释放网络设备,取消地址映射,释放PCI资源static void __devexit tg3_remove_one(struct pci_dev *pdev){struct net_device *dev = pci_get_drvdata(pdev);//注销网络设备unregister_netdev(dev);//取消地址映射iounmap((void *) ((struct tg3 *)(dev->priv))->regs);//释放网络设备kfree(dev);//释放PCI资源pci_release_regions(pdev);//停用PCI设备pci_disable_device(pdev);//PCI设备中的设备指针赋空pci_set_drvdata(pdev, NULL);}5. 网络设备挂起主要工作:停用网卡的中断寄存器,停止网卡收发包,停用网卡某些硬件,设置电源状态static int tg3_suspend(struct pci_dev *pdev, u32 state){//停用网卡的中断寄存器tg3_disable_ints(tp);//停止网卡收发包netif_device_detach(dev);//停止网卡某些硬件,fireware的一些功能tg3_halt(tp);//设置网卡的电源状态tg3_set_power_state(tp, state);}6. 网络设备恢复主要工作:恢复网卡电源,允许收发包,初始化收发包的缓冲区,初始化网卡硬件,打开网卡中断寄存器static int tg3_resume(struct pci_dev *pdev){//恢复网卡电源tg3_set_power_state(tp, 0);//允许网卡收发包netif_device_attach(dev);//初始化收发包的缓冲区tg3_init_rings(tp);//初始化网卡硬件tg3_init_hw(tp);//打开网卡中断寄存器tg3_enable_ints(tp);}struct net_device1. 打开网络设备主要工作:分配中断及注册中断处理函数,初始化硬件及收发缓冲区,初始化定时器及注册超时函数,允许网卡开始传送包static int tg3_open(struct net_device *dev){//分配一个中断request_irq(dev->irq, tg3_interrupt, SA_SHIRQ, dev->name, dev);/* int request_irq(unsigned int irq,void (*handler)(int irq, void *dev_id, struct pt_regs *regs),unsigned long irqflags,const char * devname,void *dev_id);irq是要申请的硬件中断号。
Linux设备驱动程序课件(PPT 62页)
驱动程序中的内存分配
在Linux内核模式下,不能使用用户态的malloc() 和free()函数申请和释放内存。
内核编程最常用的内存申请和释放函数为 kmalloc()和kfree(),其原型为:
Linux设备驱动
广州嵌入式软件公共技术支持中心 梁老师
2007年07月
设备驱动概述
操作系统是通过各种驱动程序来驾驭硬件设备,它为 用户屏蔽了各种各样的设备,硬件设备的抽象。
设备驱动程序:处理和管理硬件控制器的软件。 设备驱动程序是操作系统内核和机器硬件之间的接口。
设备驱动概述
设备由两部分组成,一个是被称为控制器的电器部分, 另一个是机械部分。
设备驱动概述
Linux操作系统把设备纳入文件系统的范畴来管理。 文件操作是对设备操作的组织和抽象。设备操作则是
对文件操作的最终实现。 每个设备都对应一个文件名,在内核中也就对应一个
索引节点。 对文件操作的系统调用大都适用于设备文件。 从应用程序的角度看,设备文件逻辑上的空间是一个
一些重要的数据结构
文件操作结构体file_operations
结构体file_operations在头文件 linux/fs.h中定义, 用来存储驱动内核模块提供的对设备进行各种操作 的函数的指针。
结构体的每个域都对应着驱动模块用来处理某个被 请求的事务的函数的地址。
struct file_operations { struct module *owner; loff_t(*llseek) (struct file *, loff_t, int); ssize_t(*read) (struct file *, char __user *, size_t, loff_t *); ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *); 。。。
Linux ——Driver
第一章驱动程序基本框架星期二, 06/08/2010 - 00:21— william前言不管是Windows还是Linux,驱动程序都扮演着重要的角色。
应用程序只能通过驱动程序才能同硬件设备或系统内核通讯。
Linux内核对不同的系统定义了标准的接口(API),应用程序就是通过这些标准的接口来操作内核和硬件。
驱动可以被编译的内核中(build-in),也可以做为内核模块(Module)存在于内核的外面,需要的时候动态插入到内核中运行。
就像你学习操作系统概念时所了解的那样,Linux内核也分为几个大的部分:进程管理、内存管理、文件系统、设备控制、网络系统等,参考图1-1。
图1-1 Linux系统(来源:O‟Reilly Media, LDD3)这里就不对Linux系统内核的各个部分做过多的介绍了,在后面的学习中你就会逐渐地对这些概念有个更深入的了解。
其实Linux内核的精髓远不止这些,对于一个Linux内核的爱好者或开发者来说,最好详细的浏览内核源代码,订阅Linux内核相关的邮件列表,或是登陆Linux开发社区。
更多的信息,请登陆Linux内核官方网站:一个简单的驱动下面我们来编写第一个驱动程序,它很简单,在运行时会输出…Hello World‟消息。
// hello.c#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>static int __init hello_init(void){printk(KERN_ALERT "Hello World!\n");return 0;}static void __exit hello_exit(void){printk(KERN_ALERT "Goodbye World!\n");}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");这就是一个简单的驱动程序,它什么也没做,仅仅是输出一些信息,不过对于我们来说这已经足够了。
Linux系统网络配置教程
Linux系统网络配置教程一、引言在现代信息技术时代,网络已经成为我们生活和工作中不可或缺的一部分。
而对于使用Linux操作系统的用户来说,正确配置网络是十分重要的。
本章将介绍Linux系统网络配置的基本步骤和常见问题解决方法。
二、网络配置概述网络配置是指将计算机与网络相连,并配置正确的网络参数,以实现与其他计算机之间的通信。
Linux系统的网络配置可分为两个方面,即物理连接和逻辑配置。
2.1 物理连接物理连接是指将计算机与网络相连的操作。
首先要确保计算机已经正确连接到局域网或因特网。
如果是有线连接,需要插入以太网线到计算机的网卡插槽和路由器的网络接口;如果是无线连接,需要确保无线网卡已经连接到正确的无线网络。
2.2 逻辑配置逻辑配置是指在物理连接完成后,需要对计算机进行相应的软件设置,以使其能够正确地与其他网络设备进行通信。
逻辑配置的主要内容包括IP地址的配置、网关的配置、DNS的配置以及防火墙的配置等。
三、IP地址配置IP地址是互联网中用于标识和定位计算机的一种地址。
在Linux系统中,可以通过以下两种方式来配置IP地址:3.1 动态IP地址配置动态IP地址配置是指使用DHCP服务器为计算机分配IP地址的方式。
DHCP是一种网络协议,它可以自动为计算机分配IP地址和其他网络配置信息。
要使用动态IP地址配置,在终端中输入以下命令:```shellsudo dhclient eth0```其中,eth0是计算机的网卡接口名,根据实际情况进行相应更改。
3.2 静态IP地址配置静态IP地址配置是指手动为计算机分配一个固定的IP地址。
这种方式适用于需要长期使用特定IP地址的情况。
要进行静态IP 地址配置,需要编辑网络配置文件。
在终端中输入以下命令:```shellsudo nano /etc/network/interfaces```在文件中添加以下配置信息:```shellauto eth0iface eth0 inet staticaddress 192.168.0.100netmask 255.255.255.0gateway 192.168.0.1```其中,eth0是计算机的网卡接口名,address是计算机的IP地址,netmask是子网掩码,gateway是网关地址。
2-Linux驱动和内核模块编程
设备驱动的Hello World模块 设备驱动的 模块
模块卸载函数
static void __exit cleanup_function(void) { /* 释放资源 */ } module_exit(cleanup_function);
在模块被移除前注销接口并 释放所有所占用的系统资源
标识这个代码是只用于模块卸载( 标识这个代码是只用于模块卸载 通过使编译器把它放在 特殊的 ELF 段) 原型: 原型:#define __exit __attribute__ ((__section__(“.exit.text”)))
查看已加载模块
lsmod cat /proc/modules.
卸载驱动模块 卸载模块
从内核中卸载模块可以用rmmod工具.
注意,如果内核认为该模块任然在使用状态, 注意,如果内核认为该模块任然在使用状态,或 者内核被禁止移除该模块,则无法移除该模块。 者内核被禁止移除该模块,则无法移除该模块。
内核打印函数
隐藏硬件细节,提高应用软件的可移植性 提供安全性 开发模式 内核态驱动 用户态驱动
提供机制,而不是提供策略
机制:驱动程序能实现什么功能 策略:用户如何使用这些功能
设备的分类和特点Biblioteka 设备分类字符设备(char device) 字符设备 块设备(block device) 块设备 网络设备(network device) 网络设备
MODULE_LICENSE()---模块许可证声明 模块许可证声明
模块许可证(LICENSE)声明描述内核模块的许可权限 如果不声明LICENSE,模块被加载时,将收到内核被污染(kernel tainted)的警告
动手写一个内核模块
linux网络设备驱动
网络设备驱动
struct net_device 全局信息 结构 net_device 的第一部分是由下面成员组成: char name[IFNAMSIZ]; 设备名子. 如果名子由驱动设置, 包含一个 %d 格式串, register_netdev 用一个数替换它来形成一个唯一的名子; 分配的编 号从 0 开始. unsigned long state; 设备状态. 这个成员包括几个标志. 驱动正常情况下不直接操作这些 标志; 相反, 提供了一套实用函数. struct net_device *next; 全局列表中指向下一个设备的指针. 这个成员驱动不能动. int (*init)(struct net_device *dev); 一个初始化函数. 如果设置了这个指针, 这个函数被 register_netdev 调用来完成对 net_device 结构的初始化. 大部分现代的网络驱动不 再使用这个函数; 相反, 初始化在注册接口前进行.
网络设备驱动
struct net_device接口信息
unsigned char addr_len; unsigned char broadcast[MAX_ADDR_LEN]; unsigned char dev_addr[MAX_ADDR_LEN]; 硬件 (MAC) 地址长度和设备硬件地址. 以太网地址长度是 6 个字节( 我们指的是接口板的硬件 ID ), 广播地址由 6 个 0xff 字节组成; ether_setup 安排成正确的值. 设备地址, 另外, 必 须以特定于设备的方式从接口板读出, 驱动应当将它拷贝到 dev_addr. 硬件地址用来产生正确的以太网头
void *priv;
Байду номын сангаас
Linux设备驱动程序DF
Linux设备驱动程序
04/05/2006 应忍冬
内容
• • • • • • • • • 设备分类 设备驱动程序的框架 字符型设备 网络设备 文件系统
– User Spacuffer例子和使用 Debug原理和Debug方法 常用设备/fb/ram/loopback/zero
设备驱动程序内访问设备地址
• 设备驱动程序可以通过指针访问设备地址 • 设备驱动程序接触到的还是虚拟地址,但 对于外界设备有固定的设备地址映射(设 备的地址在移植Linux时候确定) 设备驱动程序
虚拟地址映射
设备地址映射
设备驱动程序
虚拟地址映射
设备地址映射
物理内存地址空间
设备地址空间
直接访问IO端口 vs 设备驱动程序
设备驱动程序的任务
• • • • 设备初始化 硬件操作和管理 外部硬件和内核空间的数据传递 内核空间和用户空间的数据传递
设备驱动程序的功能
用 户 空 间 内 核 空 间
用户程序
程序
用户态程序 vs 内核态程序
用户程序 • 权限受限 • 虚拟运行环境
–逻辑地址 –关键资源访问受监管
内核程序 • 最高权限 • 实际的运行环境
生成o文件
设备装载和设备文件建立
• chmod +x /tmp/LED.o • /sbin/insmod -f ./LED.o • cat /proc/devices得到装入内核的主 设备号 • mknod /dev/Lamp c Num1 Num2 Num1为主设备号 Num2为次设备号 强制安装,忽略版本检查
网络驱动程序
网络设备与媒介层
网络设备与媒介层直接对应于实际的硬件设备,我们可以定义一组宏和 一组访问设备内部寄存器的函数,具体的宏和函数与特定的硬件紧密相 关。
/*寄存器定义*/ #define DATA_REG 0x0004 #define CMD_REG 0x0008 /*寄存器读写函数*/ static u16 xxx_readword(u32 base_addr,int portno) {
• 设备驱动功能层各函数是网络设备接口层net_device数据结构的具体成员, 是驱使网络设备硬件完成相应动作的程序,它通过hard_start_xmit()函数启 动发送操作,并通过网络设备上的中断触发接收操作。
•网络设备与媒介层是完成数据包发送和接收的物理实体,包括网络适配器和 具体的传输媒介。
假设以太网适配器收到一个UDP数据包,Linux从底层到应用层处理 这一数据包的流程如下:
网卡收到一个UDP包后,驱动程序需要创建一个sk_buff结构体 和数据缓冲区,将收到的数据全部复制到data指向的空间,此 时,有效数据的开始位置是一个链路层的以太网头。
Linux网络驱动开发步骤
加载: int xxx_init_module(void) {
... /* 分配net_device结构体并对其成员赋值 */ xxx_dev = alloc_netdev(sizeof(struct xxx_priv), "sn%d",xxx_init);
if (xxx_dev == NULL) /* 分配net_device失败 */
二、设备驱动功能层
net_device 结构体的成员(属性和函数指针)需要被设备驱动功能层的具体数值 和函数赋予。对于具体的设备xxx,工程师应该编写设备驱动功能层的函数,这些函 数形如xxx_open()、xxx_stop()、xxx_start_xmit()、xxx_hard_header()、xxx_get_stats()、 xxx_tx_timeout()、xxx_poll()等。
设备驱动功能层的函数模板
void xxx_init(struct net_device *dev)
{ /*设备的私有信息结构体*/ struct xxx_priv *priv;
/* 检查设备是否存在和设备所使用的硬件资源 */ xxx_hw_init();
/* 初始化以太网设备的公用成员 */ ether_setup(dev);
unsigned short type;
//接口的硬件类型
unsigned mtu;
//最大传输单元(MTU)
unsigned char dev_addr[MAX_ADDR_LEN]; //存放设备的硬件地址
unsigned char broadcast[MAX_ADDR_LEN]; /*存放设备的广播地址, 以太网设备的广播
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
netif_start_queue()和netif_stop_queue()两个函数的原型
int skb_tailroom(struct sk_buff *skb);
返回缓冲区后部可用空间总量
int skb_headroom(struct sk_buff *skb);
返回缓冲区前面部分可用空间总量
void skb_reserve(struct sk_buff *skb, int len);
网络设备,又叫网络接口是Linux第三类标准设备 网络设备和块设备类似,在内核的特定数据结构中注册自 己 当发生网络数据交换时,网络设备驱动程序注册的方法将 被内核调用 网络设备不会在/dev下存在一个设备入口,它使用保留的 内部设备名
网络设备的特点
网络设备异步的接收外来的数据包,有别于其他设备
网络设备主动的“请求”将硬件获得的数据包压入内 核,而其他设备例如块设备被“请求”向内核发送缓 冲区 网络设备同时要执行大量的管理任务
int (*stop)(struct net_device *dev);
停止接口。在这个方法里面,我们完 成与open方法相反的,注销操作
该方法初始化数据包的传输。是网络设备驱动中非常重要的一个方法。我们将 完整的数据包放入一个套接字缓冲区sk_buff结构里 int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
描述设备的I/O基地址 描述设备中断号 描述多端口设备的活动端口 描述设备的DMA通道
9.1.2 网络设备接口层
接口信息
int (*open)(struct net_device *dev);
打开接口。当ifconfig激活网络设备 时,接口被打开。通常我们在open方 法里面完成资源的分配,包括I/O映射、 中断注册、DMA注册等。同时激活硬 件,并增加使用计数
9.2.1 网络设备的注册、注销 注册与注销函数
int register_netdev(struct net_device *dev); void unregister_netdev(struct net_device *dev);
创建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);
9.1.2 网络设备接口层
如果接口支持MAC地址改 变,则可以实现该函数 int (*set_mac_address)(struct net_device *dev, void *addr); 当接口的MTU改变时, 该方法将被调用,负责 做出相应的特定处理 int (*change_mtu)(struct net_device *dev, int new_mtu); 根据ARP查询的结果填充hh_cache结构 int (*header_cache) (struct neighbour *neigh, struct hh_cache *hh); 在发生变化时,该方法更新 hh_cache结构中的目的地址 int (*header_cache_update) (struct hh_cache *hh, struct net_device *dev, unsigned char *haddr); 从skb中包含的数据包中获得源地址,并 将其复制到位于haddr的缓冲区中 int (*hard_header_parse) (struct sk_buff *skb, unsigned char *haddr);
全局成员 硬件相关成员 接口相关成员 设备方法成员 公用成员
9.1.2 网络设备接口层
net_device 结构的主要成员
全局信息
char name[IFNAMESIZ] int (*init)(struct net_device *dev)
如果被设置了,在register_netdev奖 调用他初始化net_device结构,现代 驱动一般在注册接口中完成初始化。
释放net_device
void free_netdev(struct net_device *dev);
9.2.1 网络设备的注册、注销
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 }
unsigned char *head; unsigned char *data; unsigned char *tail; unsigned char *end; unsigned long len; unsigned char ip_summed; unsigned char pkt_type
指向数据包中各个层的数据包头。h指向传 输层包头,nh指向网络层包头,mac指向 链路层包头 用来寻址数据包中的数据指针。head指向 已分配空间开头,data指向有效的octet开 头,tail指向有效的octet结尾,而end指向 tail可以到达的最大地址 PACKET_HOST PACKET_BROADCAST PACKET_MULTICAST PACKET_OTHERHOST
dev_queue_xmit(struct sk_buff *skb);
上层对数据包的接收也通过向netif_rx()函数:
int netif_rx(struct sk_buff *skb);
9.1.1 网络协议接口层
套接字缓冲区(sk_buff)结构
套接字缓冲区(sk_buff)结构是Linux内核网络子系统的核心内 容,在<linux/skbuff.h>中被定义 sk_buff结构中的重要字段: struct net_device *rx_dev; 分别为接收和发送缓冲区的设备 struct net_device *dev; union { /* ... */ } h; union { /* . . . */ } nh; union { /*... */} mac;
9.3 网络设备的打开和释放
网络设备的打开函数完成如下工作:
使能设备使用的硬件资源,申请I/O区域、中断和DMA通道等。 调用Linux内核提供的netif_start_queue()函数,激活设备发送队列。
网络设备的关闭函数需要完成如下工作:
调用Linux内核提供的netif_stop_queue()函数,停止设备传输包。 释放设备所使用的I/O区域、中断和DMA资源。
9.1.1 网络协议接口层
struct sk_buff *alloc_skb(unsigned int len, int priority); struct sk_buff *dev_alloc_skb(unsigned int len); 分配套接字缓冲区
void kfree_skb(struct sk_buff *skb); void dev_kfree_skb(struct sk_buff *skb); 释放套接字缓冲区
设置地址 修改传输参数 维护流量和流量控制 错误统计和报告
网络设备的特点
网络子系统是完全与协议无关的,
网络驱动程序与内核其余部分之间的每次交互处理的 都是一个网络数据包
9.1 Linux网络设备驱动的结构
9.1.1 网络协议接口层
最主要的功能是给上层协议提供了透明的数据包发送 和接收接口。 上层ARP或IP协议需要发送数据包时,调用网络协议 接口层的dev_queue_xmit()函数
第9章
Linux网络设备驱动程序
本章目标
了解Linux网络驱动程序的数据交换过程 掌握移植和编写具体网卡驱动程序的方法
本章结构
Linux网络设备驱动的结构 网络设备的注册、注销和初始化 网络设备的打开和释放 Linux网络设备驱动程序 数据包发送 数据包接收 网络连接状态