收藏 分销(赏)

嵌入式系统软件开发技术BSP和驱动.ppt

上传人:xrp****65 文档编号:13087236 上传时间:2026-01-14 格式:PPT 页数:179 大小:1.17MB 下载积分:10 金币
下载 相关 举报
嵌入式系统软件开发技术BSP和驱动.ppt_第1页
第1页 / 共179页
嵌入式系统软件开发技术BSP和驱动.ppt_第2页
第2页 / 共179页


点击查看更多>>
资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,嵌入式系统软件开发技术,嵌入式系统,主要内容,版级支持包,BSP,嵌入式系统初始化以及,BSP,的设计,Linux,系统驱动程序开发,嵌入式联网,BSP,的概念,BSP,全称,“,板级支持包,”,(,Board Support Packages,),说的简单一点,就是一段启动代码,和计算机主板的,BIOS,差不多,但提供的功能区别就相差很大,在,Windows CE,中,,BSP,是驱动程序、,OEM,适应层(,OEM Adaptation Layers,,,OAL,)、硬件抽象层(,HAL,)以及启动设备和使外设正常工作所需,BIOS,文件的集合。,BSP,和,BIOS,区别,BIOS,主要是负责在电脑开启时检测、初始化系统设备(设置栈指针,中断分配,内存初始化,.,)、装入操作系统并调度操作系统向硬件发出的指令。,BSP,是和操作系统绑在一起运行,尽管,BSP,的开始部分和,BIOS,所做的工作类似,但是,BSP,还包含和系统有关的基本驱动,BIOS,程序是用户不能更改,编译编程的,只能对参数进行修改设置,但是程序员还可以编程修改,BSP,,在,BSP,中任意添加一些和系统无关的驱动或程序,甚至可以把上层开发的统统放到,BSP,中,不同系统中的,BSP,一个嵌入式操作系统针对不同的,CPU,,会有不同的,BSP,即使同一种,CPU,,由于外设的一点差别,BSP,相应的部分也不一样,BSP,的特点与功能,硬件相关性,因为嵌入式实时系统的硬件环境具有应用相关性,所以,作为高层软件与硬件之间的接口,,BSP,必须为操作系统提供操作和控制具体硬件的方法。,操作系统相关性,不同的操作系统具有各自的软件层次结构,,因此,不同的操作系统具有特定的硬件接口形式,BSP,的设计与实现,为实现上述两部分功能,设计一个完整的,BSP,需要完成两部分工作:,设计初始化过程,完成嵌入式系统的初始化;,设计硬件相关的设备驱动,完成操作系统及应用程序对具体硬件的操作。,嵌入式系统初始化以及,BSP,的功能,嵌入式系统的初始化过程是一个同时包括硬件初始化和软件初始化的过程;而操作系统启动以前的初始化操作是,BSP,的主要功能之一,初始化过程总可以抽象为三个主要环境,按照自底向上、从硬件到软件的次序依次为:,片级初始化,板级初始化,系统级初始化,初始化过程,片级初始化:,主要完成,CPU,的初始化,设置,CPU,的核心寄存器和控制寄存器,CPU,核心工作模式,CPU,的局部总线模式等,片级初始化把,CPU,从上电时的缺省状态逐步设置成为系统所要求的工作状态,这是一个纯硬件的初始化过程,初始化过程(续,1,),板级初始化:,完成,CPU,以外的其他硬件设备的初始化,同时还要设置某些软件的数据结构和参数,为随后的系统级初始化和应用程序的运行建立硬件和软件环境,这是一个同时包含软硬件两部分在内的初始化过程,初始化过程(续,2,),系统级初始化:,这是一个以软件初始化为主的过程,主要进行操作系统初始化,BSP,将控制转交给操作系统,由操作系统进行余下的初始化操作,:,包括加载和初始化与硬件无关的设备驱动程序,建立系统内存区,加载并初始化其他系统软件模块(如网络系统、文件系统等),最后,操作系统创建应用程序环境并将控制转交给应用程序的入口,硬件相关的设备驱动程序,BSP,另一个主要功能是硬件相关的设备驱动,与初始化过程相反,硬件相关的设备驱动程序的初始化和使用通常是一个从高层到底层的过程,尽管,BSP,中包含硬件相关的设备驱动程序,但是这些设备驱动程序通常不直接由,BSP,使用,而是在系统初始化过程中由,BSP,把它们与操作系统中通用的设备驱动程序关联起来,并在随后的应用中由通用的设备驱动程序调用,实现对硬件设备的操作。,BSP,开发的前提和步骤,开发的前提:,熟悉硬件方面:使用,CPU,等,熟悉工具方面:电表,示波器,逻辑分析仪,硬件仿真器,仿真调试环境等,语言方面:汇编语言,,C,语言,BSP,开发的一般步骤如下:,硬件主板研制,测试,操作系统的选定,,BSP,编程,上层应用程序的开发,编写,BSP,函数,BSP,对板卡中每个芯片的操作都通过多个函数来完成,如果应用程序对板卡的操作都直接通过调用,BSP,中的函数来完成,那将很不利于源程序的调试,并降低了程序的可移植性,把能完成某个特定功能的函数封装在一个库文件中,并放在应用程序与,BSP,之间,对每个芯片来说,都应当有初始化函数和状态读取函数,设计实现,BSP,的一般方法,BSP,的开发需要具备一定的硬件知识,要求掌握操作系统所定义的,BSP,接口,两种快捷方法,以经典,BSP,为参考,使用操作系统提供的,BSP,模板,设计实现,BSP,两部分功能时应采用以下两种不同方法,“,自底向上,”,地实现,BSP,中的初始化操作,“,自顶向下,”,地设计硬件相关的驱动程序,BSP,设计方法的不足与改进,目前,BSP,的设计与实现主要是针对某些特定的文件进行修改,直接修改相关文件容易造成代码的不一致性,增加软件设计上的隐形错误,从而增加系统调试和代码维护的难度,解决这个问题的一个可行办法是:设计实现一种具有图形界面的,BSP,开发设计向导,由该向导指导设计者逐步完成,BSP,的设计和开发,并最终由向导生成相应的,BSP,文件,而不再由设计人员直接对源文件进行修改,。,Linux,设备驱动程序及开发,Linux,设备驱动程序概述,Linux,设备驱动程序是处理或操作硬件控制器的软件,被集成在内核中,是常驻内存的低级硬件处理程序的共享库,设备驱动程序是系统对设备的抽象管理与控制。,Linux,允许设备驱动程序作为内核可加载模块实现,即除了可以在系统启动时进行注册外,还可以在启动后进行加载注册。,Linux,驱动程序开发,建立嵌入式,Linux,平台,移植和编写驱动程序往往是最具挑战的工作,驱动程序的开发周期一般较长,对产品的面世时间有着重要影响,驱动程序质量的好坏,直接关系到系统工作效能和稳定性,对项目的成败起着关键作用,设备驱动程序主要功能,设备驱动程序主要完成如下功能:,检测设备和初始化设备,使设备投入运行和退出服务,从设备接收数据并提交给内核,从内核接收数据送到设备,检测和处理设备错误,Linux,设备驱动程序分类,Linux,中所有设备被抽象出来,都看成文件,设备的读写和普通文件一样,Linux,系统的设备分为如下三类:,字符设备,(char device),块设备,(block device),网络设备,(network device),字符设备是指存取时没有缓存的设备,块设备的读写都有缓存来支持,且块设备必须能够随机存取,(random access),网络设备在,Linux,里做专门的处理,Linux,设备驱动程序分类,网络设备在,Linux,里做专门的处理,Linux,的网络系统主要是基于,BSD,unix,的,socket,机制。在系统和驱动程序之间定义有专门的数据结构,(,sk_buff,),进行数据的传递,系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持,Linux,设备驱动程序分类,典型的字符设备包括鼠标,键盘,串行口等,块设备主要包括硬盘、软盘设备、,CD-ROM,等,一个文件系统要安装进入操作系统必须在块设备上,Linux,驱动程序介绍,嵌入式,Linux,驱动已经支持的设备门类齐全,已成为其相对其他嵌入式操作系统的一大优势,工业控制常用的串口,并口,人机输入设备如鼠标、键盘,触摸屏,彩色、黑白液晶显示输出,网络的完善支持,包括,tcp/ip,,,udp,,,firewall,,,WLAN,,,ip,forwarding,,,ipsec,,,vpn,Usb,的全面支持,包括,usb,硬盘、,u,盘,,usb,摄像头,支持丰富的文件系统,包括,FAT32,,,NTFS,嵌入式设备框图,驱动程序的功用,1,、驱动程序直接操控硬件,收发通讯数据,读写存储介质,比如,flash,或硬盘,操作输出设备和执行机构,例如打印,开关门禁等,驱动程序的功用(续),2,、驱动程序提供软件访问硬件的机制,应用软件通过驱动程序安全高效的访问硬件,驱动程序文件可以方便的提供访问权限控制,驱动程序作为一个隔离的中间层软件,将底,层细节隐藏起来,提高了软件的可移植性,访问,Linux,设备驱动的方法,设备提供,dev,文件系统节点和,proc,文,件系统节点,应用程序通过,dev,文件节点访问驱动,程序,应用程序通过,proc,文件节点可以查,询设备驱动的信息,驱动程序位置,驱动程序位于,drivers,目录下,通常驱动程序占,kernel,代码的,50%,Linux,设备驱动程序在,Linux,的内核源代码中占有很大的比例,源代码的长度日益增加,主要是驱动程序的增加。,在,Linux,内核的不断升级过程中,驱动程序的结构还是相对稳定。,在,2.0.xx,到,2.2.xx,的变动里,驱动程序的编写做了一些改变,但是从,2.0.xx,的驱动到,2.2.xx,的移植只需做少量的工作。,Linux,驱动程序的特点,嵌入式,Linux,驱动程序需求多样,嵌入式设备硬件各异,嵌入式计算平台往往资源有限,比如处理速度、存储器容量、总线带宽、电池容量等,通常要求短的开发周期、压力大,开发驱动程序需要丰富的专业知识,包括,硬件和软件知识,嵌入式,Linux,驱动程序特点,嵌入式系统硬件更新速度加快,国际上大的嵌入式芯片提供商如,Intel,、,Samsung,、,Freescale,、,TI,、,ST,每年都有大量新品推出,新的芯片功能总是需要相应的驱动程序支持,Linux,驱动开发流程,熟悉设备的特性,确定设备驱动程序类别,编写测试用例,搜集可重用的代码,编写自己的驱动程序代码,编码、调试、测试,Linux,驱动程序的开发环境,本机编译调试,开发环境配置简单,无需网络环境,适用于配置较高的,x86,机器,主机,+,目标机,主机可以自由选择,Linux,或,Windows+Cygwin,主机和目标机通过网络共享文件系统,内核崩溃不会影响主机,Linux,驱动程序的开发环境(续),主机,+,目标机环境包括,主机运行的工具链,cross,gcc,+,glibc,+,gdb,,,如果是,windows,主机还要有,cygwin,仿真环境,主机运行远程服务,常用的有,tftp,用来传送内,核映像、,initrd,,,NFS,用来共享文件系统,目标机运行,ssh,或,telnet,等远程登陆服务,用来,调试驱动程序,Linux,驱动程序的加载方式,驱动程序直接编译入内核,驱动程序在内核启动时就已经在内存中,可以保留专用存储器空间,驱动程序以模块形式存储在文件系,统里,需要时动态载入内核,驱动程序按需加载,不用时节省内存,驱动程序相对独立于内核,升级灵活,Linux,驱动程序模块加载,Linux,驱动程序开发的任务,规划硬件资源的使用,分离硬件相关和硬件无关的代码,划分驱动程序的抽象层次,移植驱动程序到新的平台,Linux,驱动程序开发的任务,规划硬件资源的使用,CPU,时间片分配,中断处理,系统存储器空间映射,设备存储器的映射,Linux,驱动程序开发的任务,分离硬件相关和硬件无关的代码,划分驱动程序的抽象层次,Linux,驱动程序开发的任务,移植驱动程序到新的平台,GPL,对驱动程序开发的影响,实现非,GPL,授权的方法,模块形,式动态加载,驱动程序可以以私有产权形式进行,商业授权,设备驱动程序的代码,驱动程序的注册与注销,register_chrdev,(),register_blkdev,(),设备的打开与释放,open(),release(),设备的读写操作,read(),write(),设备的控制操作,ioctl,(),设备驱动的加载,使用模块的方式动态加载驱动,int,func_init(void,),Makefile,:,insmod,xx.o,lsmod,rmmod,xx.o,将驱动静态编译到内核里面,int,_init,func_init(void,),Makefile,:,启动时自动加载,Linux,驱动程序模块加载,编写驱动程序的一些基本概念,无论是什么操作系统的驱动程序,都有一些通用的概念,操作系统提供给驱动程序的支持也大致相同,以下简单介绍网络设备驱动程序的一些基本要求,编写网络驱动程序,发送和接收,这是一个网络设备最基本的功能,如一块网卡所做的无非就是收发工作。所以驱动程序里要告诉系统发送函数在哪里,系统在有数据要发送时就会调用发送程序。,驱动程序由于是直接操纵硬件的,所以网络硬件有数据收到,最先能得到这个数据的也就是驱动程序,它负责把这些原始数据进行必要的处理,然后送给系统。,这里,操作系统必须要提供两个机制:,找到驱动程序的发送函数,驱动程序把收到的数据送给系统,编写驱动程序,读写,几乎所有设备都有输入和输出。每个驱动程序要负责本设备的读写操作。,操作系统不需要知道对设备的具体读写操作怎样进行,这些都由驱动程序屏蔽掉了,操作系统定义好一些读写接口,由驱动程序完成具体的功能,在驱动程序初始化时,需要把具有这种接口的读写函数注册进操作系统,编写驱动程序,中断,中断在现代计算机结构中有重要的地位,操作系统必须提供驱动程序响应中断的能力,一般是把一个中断处理程序注册到系统中去,操作系统在硬件中断发生后调用驱动程序的处理程序,Linux,支持中断的共享,即多个设备共享一个中断,编写驱动程序,时钟,在实现驱动程序时,很多地方会用到时钟。如某些协议里的超时处理,没有中断机制的硬件的轮询等。,操作系统应为驱动程序提供定时机制,一般是在预定的时间过了以后回调注册的时钟函数,内核模块,模块是内核的一部分,但是并没有被编译到内核里去。它们被分别编译和连接成目标文件。,用命令,insmod,插入一个模块到内核中,用命令,rmmod,卸载一个模块,在,Linux,内核中,以下内容一般编译成模块:,大多数的驱动程序,。包括,SCSI,设备,,CD-ROM,,网络设备,不常用的字符设备,如打印机,,watchdog,等。,大多数文件系统,理论上除了根文件系统不能是模块,其他文件系统都可以是模块。,一些内核支持的不常用的可执行文件格式,如,binfmt_misc,。,kmod,和高级模块化,Linux,提供了对模块自动加载和卸载的支持,要利用这一特性,在编译内核前进行的配置中,必须打开对,kmod,的支持选项。,一旦内核试图访问某种资源并发现该资源不可用时,它会对,kmod,子系统进行一次特殊的调用而不仅仅是返回一个错误,按需加载的例子:,ALSA,(,Advanced Linux Sound Architecture,)声卡驱动程序组的实现,常用的系统支持,内存申请和释放,中断,时钟,I/O,中断打开关闭,输出信息,注册驱动程序,内存申请和释放,include/,linux/kernel.h,里声明了,kmalloc,(),和,kfree,(),。用于在内核模式下申请和释放内存。,与用户模式下的,malloc,(),不同,,kmalloc,(),申请空间有大小限制。长度是,2,的整次方。可以申请的最大长度也有限制。另外,kmalloc,(),有,priority,参数,Kfree,(),释放的内存必须是,kmalloc,(),申请的,申请中断和释放中断,request_irq,(),、,free_irq,(),是驱动程序申请中断和释放中断的调用。,在,include/,linux/sched.h,里声明,时钟,时钟的处理类似中断,也是登记一个时间处理函数,在预定的时间过后,系统会调用这个函数。,在,include/,linux/,timer.h,里声明,使用时钟,先声明一个,timer_list,结构,调用,init_timer,对它进行初始化。,Time_list,结构里,expires,是标明这个时钟的周期,单位采用,jiffies,的单位。,I/O,I/O,端口的存取使用:,inline unsigned,int,inb(unsigned,short port);,inline unsigned,int,inb_p(unsigned,short port);,inline void,outb(char,value,unsigned short port);,inline void,outb_p(char,value,unsigned short port);,在,include/,adm/io.h,里定义,中断打开关闭,系统提供给驱动程序开放和关闭响应中断的能力,是在,include/,asm/,system.h,#define,cli,()_,asm,_ _volatile_(,cli,:),#define,sti,()_,asm,_ _volatile_(,sti,:),输出信息,驱动程序要输出信息使用,printk,(),include/,linux/,kernel.h,里声明,注册驱动程序,如果使用模块,(module),方式加载驱动程序,需要在模块初始化时把设备注册到系统设备表里去,不再使用时,把设备从系统中卸除,定义在,drivers/net/,net_init.h,里的两个函数完成这个工作,Int,register_netdev(struct,device*dev);,void,unregister_netdev(struct,device*dev);,网络驱动程序的结构,所有的,Linux,网络驱动程序遵循通用的接口,设计时采用的是面向对象的方法,一个设备就是一个对象,(device,结构,),,它内部有自己的数据和方法,每一个设备的方法被调用时的第一个参数都是这个设备对象本身。这样这个方法就可以存取自身的数据,(,类似面向对象程序设计时的,this,引用,),一个网络设备最基本的方法有初始化、发送和接收,网络驱动程序的结构(续),初始化程序完成硬件的初始化、,device,中变量的初始化和系统资源的申请,发送程序是在驱动程序的上层协议层有数据要发送时自动调用的。一般驱动程序中不对发送数据进行缓存,而是直接使用硬件的发送功能把数据发送出去,接收数据一般是通过硬件中断来通知的。在中断处理程序里,把硬件帧信息填入一个,skbuff,结构中,然后调用,netif_rx,(),传递给上层处理,网络驱动程序的基本方法,初始化,(initialize),打开,(open),关闭,(stop,),发送,(,hard_start_xmit,),接收,(reception),硬件帧头,(,hard_header,),地址解析,(,xarp,),参数设置和统计数据,网络驱动程序的基本方法,-,初始化,驱动程序必须有一个初始化方法,在把驱动程序载入系统的时候会调用这个初始化程序。它做以下几方面的工作:,检测设备,:在初始化程序里你可以根据硬件的特征检查硬件是否存在,然后决定是否启动这个驱动程序。,配置和初始化硬件,:在初始化程序里可以完成对硬件资源的配置,比如即插即用的硬件就可以在这个时候进行配置,(Linux,内核对,PnP,功能没有很好的支持,可以在驱动程序里完成这个功能,),。,配置或协商好硬件占用的资源以后,就可以向系统申请这些资源。有些资源是可以和别的设备共享的,如中断。有些是不能共享的,如,IO,、,DMA,。,初始化,device,结构中的变量,让硬件正式开始工作,网络驱动程序的基本方法,打开,打开,(open),open,这个方法在网络设备驱动程序里是在网络设备被激活的时候被调用,(,即设备状态由,down-up),实际上很多在,initialize,中的工作可以放到这里来做。比如资源的申请、硬件的激活。,如果,dev-open,返回非,0(error),,则硬件的状态还是,down,open,方法另一个作用是如果驱动程序做为一个模块被装入,则要防止模块卸载时设备处于打开状态。,在,open,方法里要调用,MOD_INC_USE_COUNT,宏,网络驱动程序的基本方法,关闭,关闭,(stop),close,方法做和,open,相反的工作。可以释放某些资源以减少系统负担。,close,是在设备状态由,up,转为,down,时被调用的,如果是做为模块装入的驱动程序,,close,里 应该调用,MOD_DEC_USE_COUNT,,减少设备被引用的次数,以使驱动程序可以被卸载。,close,方法必须返回成功,(0=success),网络驱动程序的基本方法,发送,发送,(,hard_start_xmit,),所有的网络设备驱动程序都必须有这个发送方法。,在系统调用驱动程序的,xmit,时,发送的数据放在一个,sk_buff,结构中。,一般的驱动程序把数据传给硬件发出去。也有一些特殊的设备比如,loopback,把数据组成一个接收数据再回送给系统,或者,dummy,设备直接丢弃数据。,如果发送成功,,hard_start_xmit,方法里释放,sk_buff,,返回,0(,发送成功,),如果设备暂时无法处理,比如硬件忙,则返回,1,。这时如果,dev-,tbusy,置为非,0,,则系统认为硬件忙,要等到,dev-,tbusy,置,0,以后才会再次发送。,tbusy,的置,0,任务一般由中断完成。,网络驱动程序的基本方法,发送(续),硬件在发送结束后产生中断,这时可以把,tbusy,置,0,,然后用,mark_bh,(),调用通知系统可以再次发送。,在发送不成功的情况下,也可以不置,dev-,tbusy,为非,0,,这样系统会不断尝试重发。,如果,hard_start_xmit,发送不成功,则不要释放,sk_buff,。,传送下来的,sk_buff,中的数据已经包含硬件需要的帧头。所以在发送方法里不需要再填充硬件帧头,数据可以直接提交给硬件发送。,sk_buff,是被锁住的,(locked),,确保其他程序不会存取它。,网络驱动程序的基本方法,接收,接收,(reception),驱动程序并不存在一个接收方法。有数据收到应该是驱动程序来通知系统的。,一般设备收到数据后都会产生一个中断,在中断处理程序中驱动程序申请一块,sk_buff(skb,),,从硬件读出数据放置到申请好的缓冲区里。接下来填充,sk_buff,中的一些信息。,skb,-dev=,dev,,判断收到帧的协议类型,填入,skb,-protocol(,多协 议的支持,),。,把指针,skb,-,mac.raw,指向硬件数据然后丢弃硬件帧头,(,skb_pull,),。,网络驱动程序的基本方法,接收(续),还要 设置,skb,-,pkt_type,,标明第二层,(,链路层,),数据类型。可以是以下类型:,PACKET_BROADCAST:,链路层广播,PACKET_MULTICAST:,链路层组播,PACKET_SELF:,发给自己的帧,PACKET_OTHERHOST:,发给别人的帧,(,监听模式时会有这种帧,),最后调用,netif_rx,(),把数据传送给协议层。,netif_rx,(),里数据放入处理队列然后返回,真正的处理是在中断返回以后,这样可以减少中断时间。,调用,netif_rx,(),以后,驱动程序就不能再存取数据缓冲区,skb,。,网络驱动程序的基本方法,硬件帧头,硬件一般都会在上层数据发送之前加上自己的硬件帧头,比如以太网,(Ethernet),就有,14,字节的帧头。这个帧头是加在上层,ip,、,ipx,等数据包的前面的。,驱动程序提供一个,hard_header,方法,协议层,(,ip,、,ipx,、,arp,等,),在发送数据之前会调用这段程序。,硬件帧头的长度必须填在,dev-,hard_header_len,,这样协议层回在数据之前保留好硬件帧头的空间。这样,hard_header,程序只要调用,skb_push,然后正确填入硬件帧头就可以了。,网络驱动程序的基本方法,硬件帧头(续,1,),在协议层调用,hard_header,时,传送的参数包括,(2.0.xx),:,数据的,sk_buff,device,指针,Protocol,目的地址,(,daddr,),源地址,(,saddr,),数据长度,(,len,),数据长度不要使用,sk_buff,中的参数,因为调用,hard_header,时数据可能还没完全组织好,saddr,是,NULL,的话是使用缺省地址,(default),daddr,是,NULL,表明协议层不知道硬件目的地址,如果,hard_header,完全填好了硬件帧头,则返回添加的字节数。,网络驱动程序的基本方法,硬件帧头(续,2,),如果硬件帧头中的信息还不完全,(,比如,daddr,为,NULL,,但是帧头中需要目的硬件地址。典型的情况是以太网需要地址解析,(,arp,),,则返回负字节数。,hard_header,返回负数的情况下,协议层会做进一步的,build header,的工作。,目前,Linux,系统里就是做,arp,(,如果,hard_header,返回正,,dev-,arp,=1,,表明不需要做,arp,,返回负,,dev-,arp,=0,,做,arp,),。对,hard_header,的调用在每个协议层的处理程序里。如,ip_output,。,网络驱动程序的基本方法,地址解析,地址解析,(,xarp,),有些网络有硬件地址,(,比如,Ethernet),,并且在发送硬件帧时需要知道目的硬件地址。这样就需要上层协议地址,(,ip,、,ipx,),和硬件地址的对应。这个对应是通过地址 解析完成的。,需要做,arp,的的设备在发送之前会调用驱动程序的,rebuild_header,方法。调用的主要参数包括:,指向硬件帧头的指针,协议层地址,如果驱动程序能够解析硬件地址,就返回,1,,如果不能,返回,0,。,对,rebuild_header,的调用在,net/core/,dev.c,的,do_dev_queue_xmit,(),里。,网络驱动程序的基本方法,参数设置和统计数据,参数设置和统计数据,在驱动程序里还提供一些方法供系统对设备的参数进行设置和读取信息。,一般只有超级用户,(root),权限才能对设备参数进行设置。,设置方法有:,dev-,set_mac_address,(),当用户调用,ioctl,类型为,SIOCSIFHWADDR,时是要设置这个设备的,mac,地址。一般对,mac,地址的设置没有太大意义的。,网络驱动程序的基本方法,参数设置和统计数据(续),dev-,set_config,(),当用户调用,ioctl,时类型为,SIOCSIFMAP,时,系统会调用驱动程序的,set_config,方法。用户会传递一个,ifmap,结构包含需要的,I/O,、中断等参数。,dev-,do_ioctl,(),如果用户调用,ioctl,时类型在,SIOCDEVPRIVATE,和,SIOCDEVPRIVATE+15,之间,系统会调用驱动程序的这个方法。一般是设置设备的专用数据。读取信息也是通过,ioctl,调用进行。,除次之外驱动程序还可以提供一个,dev-,get_stats,方法,返回一个,enet_statistics,结构,包含发送接收的统计信息。,ioctl,的处理在,net/core/,dev.c,的,dev_ioctl,(),和,dev_ifsioc,(),里,网络驱动程序中用到的数据结构,最重要的是网络设备的数据结构。它定义在,include/,linux/,netdevice.h,sk_buff,Linux,网络各层之间的数据传送都是通过,sk_buff,编写,Linux,网络驱动程序中需要注意的问题,中断共享,硬件发送忙时的处理,流量控制,(flow control),调试,中断共享,Linux,系统运行几个设备共享同一个中断。需要共享的话,在申请的时候指明共享方式。,系统提供的,request_irq,(),调用的定义:,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,);,如果共享中断,,irqflags,设置,SA_SHIRQ,属性,这样就允许别的设备申请同一个中断。需要注意所有用到这个中断的设备在调用,request_irq,(),都必须设置这个属性。系统在回调每个中断处理程序时,可以用,dev_id,这个参数找到相应的设备。一 般,dev_id,就设为,device,结构本身。系统处理共享中断是用各自的,dev_id,参数依次调用每一个中断处理程序。,硬件发送忙时的处理,主,CPU,的处理能力一般比网络发送要快,所以经常会遇到系统有数据要发,但上一包数据网络设备还没发送完。因为在,Linux,里网络设备驱动程序一般不做数据缓存,不能发送的数据都是通知系统发送不成功,所以必须要有一个机制在硬件不忙时及时通知系统接着发送下面的数据。,一般对发送忙的处理在前面设备的发送方法,(,hard_start_xmit,),里已经描述过,即如果发送忙,置,tbusy,为,1,。处理完发送数据后,在发送结束中断里清,tbusy,,同时用,mark_bh,(),调用通知系统继续发送。但在具体实现驱动程序时发现,这样的处理系统好象并不能及时地知道硬件已经空闲了,即在,mark_bh,(),以后,系统要等一段时间才会接着发送。造成发送效率很低。,实现时不把,tbusy,置,1,,让系统始终认为硬件空闲,但是报告发送不成功。系统会一直尝试重发。这样处理就运行正常了。,流量控制,网络数据的发送和接收都需要流量控制。这些控制是在系统里实现的,不需要驱动程序做工作。,每个设备数据结构里都有一个参数,dev-,tx_queue_len,,这个参数 标明发送时最多缓存的数据包。在,Linux,系统里以太网设备,(10/100Mbps),tx_queue_len,一般设置为,100,,串行线路,(,异步串口,),为,10,。,实际上,设置了,dev-,tx_queue_len,并不是为缓存这些数据申请了空间。这个参数只是在收到协议层的数据包时判断发送队列里的数据是不是到了,tx_queue_len,的限度,以决定这一包数据加不加进发送队列。发送时另一个方面的流控是更高层协议的发送窗口,(TCP,协议里就有发送窗口,),。,达到了窗口大小,高层协议就不会再发送数据。,接收流控也分两个层次。,netif_rx,(),缓存的数据包有限制。另外高层协议也会有一个最大的等待处理的数据量。,发送和接收流控处理在,net/core/,dev.c,的,do_dev_queue_xmit,(),和,netif_rx,(),中。,调试,很多,Linux,的驱动程序都是编译进内核的,形成一个大的内核文件。但对调试来说,这是相当麻烦的。调试驱动程序可以用,module,方式加载。,支持模块方式的驱动程序必须提供两个函数:,int,init_module(void,),和,void,cleanup_module(void,),。,init_module,(),在加载此模块时调用,在这个函数里可以,register_netdev,(),注册设备。,init_module,(),返回,0,表示成功,返回负表示失败。,cleanup_module,(),在驱动程序被卸载时调用,清除占用的资源,调用,unregister_netdev,(),。,模块可以动态地加载、卸载。在,2.0.xx,版本里,还有,kerneld,自动加载模块,但是,2.2.xx,中已经取消了,kerneld,。手工加载使用,insmod,命令,卸载用,rmmod,命令,看内核中的模块用,lsmod,命令。,编译驱动程序用,gcc,,主要命令行参数,-DKERNEL-DMODULE,。并且作为模块加载的驱动程序,只编译成,obj,形式,(,加,-c,参数,),。编译好的目标文件放在,/lib/modules/2.x.xx/misc,下,在启动文件里用,insmod,加载,Linux,驱动程序可利用资源,互联网上有很多驱动程序资源:,www.kernel.org,www.linuxdevice.org,驱动源代码,驱动源代码,驱动源代码,驱动源代码,驱动源代码,编译驱动程序,应用程序,编译应用程序,背景知识:,Linux,设备管理,主要内容,概述,驱动程序基础,中断处理,辅助函数,设备驱动程序,模块编程基础,字符设备,块设备,网络设备,概述,输入输出子系统:,下层:设备驱动程序,上层:设备无关部分,VFS in Linux,?,Unix,和,Linux,的设备管理方法:,VFS,设备管理总体结构示意,用户程序,系统调用接口,文件系统,高速缓存,字符设备,块设备,驱动程序,硬件设备,输入输出系统层次结构,用户进程,设备无关软件,设备驱动程序,设备服务子程序,中断处理程序,硬件,I/O,请求,I/O,应答,进行,I/O,调用;格式化,I/O,命名、保护、阻塞、缓冲、分配,建立设备寄存器、检测状态,I/O,结束时,唤醒设备服务子程序,执行,I/O,操作,驱动程序基础,I/O,空间,Linux,中的三种地址空间:,CPU,Untranslated,Address,CPU Translated Address,Bus Address,:,一般,PC,机中是一组寄存器,命令,more/proc/,ioports,常见总线,ISAVESAEISAPCI,驱动程序基础,命名空间,并行设备:,lp,软盘:,fd,SCSI,盘:,sd,IDE,硬盘:,hda1,hda2,hdb,等网络设备:,ethn,slipn,pppn,等,在写驱动程序的时候,需要给函数名加上选择的前缀来避免任何混淆。如:,foo_read(),,,foo_write,(),等。,驱动程序基础,内存分配,函数,kmalloc,(),内存以,2,的幂大小的块分配,有一个优先级参数,宏,kfree,(),和函数,kfree_s,(),kfree,(),调用,kfree_s,(),,,和,free(),一样工作可以直接调用,kfree_s,(),,,但是需要知道释放内存块的大小,驱动程序基础,设备分类,字符设备:不使用缓冲区,顺序读写,foo_read,()&,foo_write,(),块设备:需要使用缓冲区,随机读写,策略规程,网络设备采用了特殊的处理方法。,Struct,device,驱动程序基础,设备号,主设备号,&,次设备号,主设备号相同的设备使用相同的驱动程序次设备号区分具体设备的实例,命令:,ls,l/dev/had*,驱动程序基础,中断,vs,轮询,工作机制的区别,编程上的区别:,UNIX,的系统调用:执行模式的改变,内核模式下的进程访问进程原来所在的用户空间的存储:,get_fs,_*(),和,memcpy_fromfs,(),读用户空间,,put_fs,_*(),和,memcpy_tofs,(),写入用户空间内存,。,在进程运行时调用,不需要考虑地址的问题。,在中断发生时,这些宏不能使用,。,因为它们可能覆盖其他运行着的进程的随机空间。,必须提供临时空间存放信息。对于块设备,由,cache,缓冲机制自动提供;字符设备需要驱动程序分配。,驱动程序基础,DMA,方式,用于传送大规模的数据,PC,机上的,ISA DMA,控制器,8,条,DMA,通道。每条通道联系着一个,16,位地址寄存器和,16,位计数器,DMA,直接访问物理内存,DMA,通道不能被共享。一些设备拥有固定的,DMA,通道
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服