ChapLinux设备驱动程序实用教案

上传人:博****1 文档编号:575892599 上传时间:2024-08-19 格式:PPT 页数:111 大小:1.61MB
返回 下载 相关 举报
ChapLinux设备驱动程序实用教案_第1页
第1页 / 共111页
ChapLinux设备驱动程序实用教案_第2页
第2页 / 共111页
ChapLinux设备驱动程序实用教案_第3页
第3页 / 共111页
ChapLinux设备驱动程序实用教案_第4页
第4页 / 共111页
ChapLinux设备驱动程序实用教案_第5页
第5页 / 共111页
点击查看更多>>
资源描述

《ChapLinux设备驱动程序实用教案》由会员分享,可在线阅读,更多相关《ChapLinux设备驱动程序实用教案(111页珍藏版)》请在金锄头文库上搜索。

1、主要(zhyo)内容版级支持包 BSP嵌入式系统(xtng)初始化以及BSP的设计Linux系统(xtng)驱动程序开发第1页/共110页第一页,共111页。BSP的概念(ginin)BSP全称“板级支持包”(Board Support Packages),说的简单(jindn)一点,就是一段启动代码,和计算机主板的BIOS差不多,但提供的功能区别就相差很大在Windows CE中,BSP是驱动程序、OEM适应层(OEM Adaptation Layers,OAL)、硬件抽象层(HAL)以及启动设备和使外设正常工作所需BIOS文件的集合。 第2页/共110页第二页,共111页。BSP和BIOS

2、区别(qbi)BIOS主要是负责在电脑开启时检测、初始化系统设备(设置栈指针,中断分配,内存(ni cn)初始化.)、装入操作系统并调度操作系统向硬件发出的指令。 BSP是和操作系统绑在一起运行,尽管BSP的开始部分和BIOS所做的工作类似,但是 BSP还包含和系统有关的基本驱动 BIOS程序是用户不能更改,编译编程的,只能对参数进行修改设置,但是程序员还可以编程修改BSP,在BSP中任意添加一些和系统无关的驱动或程序,甚至可以把上层开发的统统放到BSP中 第3页/共110页第三页,共111页。不同(btn)系统中的BSP一个嵌入式操作系统针对不同的CPU,会有不同的BSP即使(jsh)同一种

3、CPU,由于外设的一点差别BSP相应的部分也不一样 第4页/共110页第四页,共111页。BSP的特点(tdin)与功能硬件相关性因为嵌入式实时系统(xtng)的硬件环境具有应用相关性,所以,作为高层软件与硬件之间的接口,BSP必须为操作系统(xtng)提供操作和控制具体硬件的方法。操作系统(xtng)相关性不同的操作系统(xtng)具有各自的软件层次结构,因此,不同的操作系统(xtng)具有特定的硬件接口形式第5页/共110页第五页,共111页。BSP的设计(shj)与实现为实现上述两部分为实现上述两部分(b fen)(b fen)功能,设计一个完整的功能,设计一个完整的BSPBSP需要完成

4、两部分需要完成两部分(b fen)(b fen)工作:工作:设计初始化过程,完成嵌入式系统的初始化;设计初始化过程,完成嵌入式系统的初始化;设计硬件相关的设备驱动,完成操作系统及应用程序对具体硬件的操作。设计硬件相关的设备驱动,完成操作系统及应用程序对具体硬件的操作。第6页/共110页第六页,共111页。嵌入式系统初始化以及(yj)BSP的功能嵌入式系统的初始化过程是一个同时包括硬嵌入式系统的初始化过程是一个同时包括硬件初始化和软件初始化的过程;而操作系统件初始化和软件初始化的过程;而操作系统启动以前的初始化操作是启动以前的初始化操作是BSPBSP的主要功能之一的主要功能之一 初始化过程总可以

5、抽象为三个主要环境,按初始化过程总可以抽象为三个主要环境,按照照(nzho)(nzho)自底向上、从硬件到软件的次自底向上、从硬件到软件的次序依次为:序依次为:片级初始化片级初始化板级初始化板级初始化系统级初始化系统级初始化第7页/共110页第七页,共111页。初始化过程(guchng)片级初始化:片级初始化:主要完成主要完成CPUCPU的初始化的初始化设置设置(shzh)CPU(shzh)CPU的核心寄存器和控制寄存器的核心寄存器和控制寄存器CPUCPU核心工作模式核心工作模式CPUCPU的局部总线模式等的局部总线模式等片级初始化把片级初始化把CPUCPU从上电时的缺省状态逐步设置从上电时的

6、缺省状态逐步设置(shzh)(shzh)成为系统所要求的工作成为系统所要求的工作状态状态这是一个纯硬件的初始化过程这是一个纯硬件的初始化过程第8页/共110页第八页,共111页。初始化过程(guchng)(续1)板级初始化:完成CPU以外(ywi)的其他硬件设备的初始化同时还要设置某些软件的数据结构和参数,为随后的系统级初始化和应用程序的运行建立硬件和软件环境这是一个同时包含软硬件两部分在内的初始化过程第9页/共110页第九页,共111页。初始化过程(guchng)(续2)系统级初始化:这是一个以软件初始化为主的过程,主要进行操作系统初始化BSP将控制转交给操作系统,由操作系统进行余下的初始化

7、操作:包括加载和初始化与硬件无关的设备驱动程序建立系统内存区加载并初始化其他系统软件模块(m kui)(如网络系统、文件系统等)最后,操作系统创建应用程序环境并将控制转交给应用程序的入口第10页/共110页第十页,共111页。硬件(ynjin)相关的设备驱动程序BSPBSP另一个主要功能是硬件相关的设备驱动另一个主要功能是硬件相关的设备驱动与初始化过程相反,硬件相关的设备驱动程序的与初始化过程相反,硬件相关的设备驱动程序的初始化和使用通常是一个从高层到底层的过程初始化和使用通常是一个从高层到底层的过程尽管尽管BSPBSP中包含硬件相关的设备驱动程序,但是中包含硬件相关的设备驱动程序,但是这些设

8、备驱动程序通常不直接由这些设备驱动程序通常不直接由BSPBSP使用使用而是在系统初始化过程中由而是在系统初始化过程中由BSPBSP把它们与操作系把它们与操作系统中通用的设备驱动程序关联统中通用的设备驱动程序关联(gunlin)(gunlin)起起来,并在随后的应用中由通用的设备驱动程序来,并在随后的应用中由通用的设备驱动程序调用,实现对硬件设备的操作。调用,实现对硬件设备的操作。第11页/共110页第十一页,共111页。BSP开发的前提(qint)和步骤开发的前提 :熟悉硬件方面:使用CPU等熟悉工具方面:电表,示波器,逻辑分析仪,硬件仿真器,仿真调试环境等语言方面:汇编语言,C语言BSP开发

9、的一般步骤如下(rxi):硬件主板研制,测试操作系统的选定,BSP编程上层应用程序的开发第12页/共110页第十二页,共111页。编写(binxi)BSP函数BSP对板卡中每个芯片的操作都通过多个函数来完成(wn chng) 如果应用程序对板卡的操作都直接通过调用BSP中的函数来完成(wn chng),那将很不利于源程序的调试 ,并降低了程序的可移植性把能完成(wn chng)某个特定功能的函数封装在一个库文件中,并放在应用程序与BSP之间 对每个芯片来说,都应当有初始化函数和状态读取函数 第13页/共110页第十三页,共111页。设计实现BSP的一般(ybn)方法BSP的开发需要具备一定的硬

10、件知识 要求掌握操作系统所定义的BSP接口两种快捷方法 以经典BSP为参考 使用操作系统提供的BSP模板 设计(shj)实现BSP两部分功能时应采用以下两种不同方法 “自底向上”地实现BSP中的初始化操作 “自顶向下”地设计(shj)硬件相关的驱动程序 第14页/共110页第十四页,共111页。LinuxLinux设备设备(shbi)(shbi)驱动程序及驱动程序及开发开发第15页/共110页第十五页,共111页。Linux设备(shbi)驱动程序概述LinuxLinux设备驱动程序是处理或操作硬件控制器的软件,设备驱动程序是处理或操作硬件控制器的软件,被集成在内核中,是常驻内存的低级硬件处理

11、程序的被集成在内核中,是常驻内存的低级硬件处理程序的共享库,设备驱动程序是系统对设备的抽象管理与控共享库,设备驱动程序是系统对设备的抽象管理与控制。制。LinuxLinux允许允许(ynx)(ynx)设备驱动程序作为内核可加载模设备驱动程序作为内核可加载模块实现,即除了可以在系统启动时进行注册外,还可块实现,即除了可以在系统启动时进行注册外,还可以在启动后进行加载注册。以在启动后进行加载注册。第16页/共110页第十六页,共111页。Linux驱动程序开发(kif)建立嵌入式Linux平台,移植和编写驱动程序往往是最具挑战的工作驱动程序的开发周期一般较长,对产品的面世(min sh)时间有着重

12、要影响驱动程序质量的好坏,直接关系到系统工作效能和稳定性,对项目的成败起着关键作用第17页/共110页第十七页,共111页。设备(shbi)驱动程序主要功能设备驱动程序主要完成如下功能:设备驱动程序主要完成如下功能:检测设备和初始化设备检测设备和初始化设备使设备投入运行和退出服务使设备投入运行和退出服务(fw)从设备接收数据并提交给内核从设备接收数据并提交给内核从内核接收数据送到设备从内核接收数据送到设备检测和处理设备错误检测和处理设备错误第18页/共110页第十八页,共111页。Linux设备(shbi)驱动程序分类LinuxLinux中所有设备被抽象出来,都看成文件中所有设备被抽象出来,都

13、看成文件(wnjin) (wnjin) 设备的读写和普通文件设备的读写和普通文件(wnjin)(wnjin)一样一样 LinuxLinux系统的设备分为如下三类:系统的设备分为如下三类:字符设备字符设备(char device)(char device)块设备块设备(block device)(block device)网络设备网络设备(network device)(network device)字符设备是指存取时没有缓存的设备字符设备是指存取时没有缓存的设备块设备的读写都有缓存来支持,且块设备必须块设备的读写都有缓存来支持,且块设备必须能够随机存取能够随机存取(random access)

14、 (random access) 网络设备在网络设备在LinuxLinux里做专门的处理里做专门的处理 第19页/共110页第十九页,共111页。Linux设备(shbi)驱动程序分类网络设备在网络设备在LinuxLinux里做专门的处理里做专门的处理LinuxLinux的网络系统主要是基于的网络系统主要是基于BSD unixBSD unix的的socket socket 机制。在系统和驱动程序之间定义有专门的数据机制。在系统和驱动程序之间定义有专门的数据结构结构(sh j ji u)(sk_buff)(sh j ji u)(sk_buff)进行数据的传进行数据的传递递系统里支持对发送数据和接

15、收数据的缓存,提供流系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持量控制机制,提供对多协议的支持 第20页/共110页第二十页,共111页。Linux设备(shbi)驱动程序分类典型的字符设备包括鼠标,键盘典型的字符设备包括鼠标,键盘(jinpn)(jinpn),串行口等,串行口等块设备主要包括硬盘、软盘设备、块设备主要包括硬盘、软盘设备、CD-ROMCD-ROM等等一个文件系统要安装进入操作系统必须在块设备上一个文件系统要安装进入操作系统必须在块设备上第21页/共110页第二十一页,共111页。Linux驱动程序介绍(jisho)嵌入式嵌入式LinuxLinux驱

16、动已经支持的设备门类齐全,驱动已经支持的设备门类齐全,已成为其相对其他嵌入式操作系统的一大优势已成为其相对其他嵌入式操作系统的一大优势工业控制常用工业控制常用(chn yn)(chn yn)的串口,并口的串口,并口人机输入设备如鼠标、键盘,触摸屏人机输入设备如鼠标、键盘,触摸屏彩色、黑白液晶显示输出彩色、黑白液晶显示输出网络的完善支持,包括网络的完善支持,包括tcp/iptcp/ip,udpudp,firewallfirewall,WLANWLAN,ip forwardingip forwarding,ipsecipsec,vpnvpnUsbUsb的全面支持,包括的全面支持,包括usbusb硬

17、盘、硬盘、u u盘,盘,usbusb摄像摄像头头支持丰富的文件系统,包括支持丰富的文件系统,包括FAT32FAT32,NTFSNTFS第22页/共110页第二十二页,共111页。嵌入式设备(shbi)框图第23页/共110页第二十三页,共111页。驱动程序的功用(gngyng)1 1、驱动程序直接操控硬件、驱动程序直接操控硬件收发通讯数据收发通讯数据读写存储介质,比如读写存储介质,比如flashflash或硬盘或硬盘操作操作(cozu)(cozu)输出设备和执行机构,例如打印,开关门禁等输出设备和执行机构,例如打印,开关门禁等第24页/共110页第二十四页,共111页。驱动程序的功用(gngy

18、ng)(续)2 2、驱动程序提供软件访问硬件的机制、驱动程序提供软件访问硬件的机制应用软件通过驱动程序安全高效的访问硬件应用软件通过驱动程序安全高效的访问硬件驱动程序文件可以方便的提供访问权限驱动程序文件可以方便的提供访问权限(qunxin)(qunxin)控制控制驱动程序作为一个隔离的中间层软件,将底驱动程序作为一个隔离的中间层软件,将底 层细节隐藏起来,提高了软件的可移植性层细节隐藏起来,提高了软件的可移植性第25页/共110页第二十五页,共111页。访问Linux设备驱动(qdn)的方法设备(shbi)提供dev文件系统节点和proc文 件系统节点应用程序通过dev文件节点访问驱动 程序

19、应用程序通过proc文件节点可以查 询设备(shbi)驱动的信息第26页/共110页第二十六页,共111页。驱动程序位置(wizhi)驱动程序位于驱动程序位于driversdrivers目录下目录下通常驱动程序占通常驱动程序占kernelkernel代码的代码的50%50%LinuxLinux设备驱动程序在设备驱动程序在LinuxLinux的内核源代码中占有很大的比例,的内核源代码中占有很大的比例,源代码的长度日益源代码的长度日益(ry)(ry)增加,主要是驱动程序的增加。增加,主要是驱动程序的增加。在在LinuxLinux内核的不断升级过程中,驱动程序的结构还是相对内核的不断升级过程中,驱动

20、程序的结构还是相对稳定。稳定。在到的变动里,驱动程序的编写做了一些改变,但是从的驱在到的变动里,驱动程序的编写做了一些改变,但是从的驱动到的移植只需做少量的工作。动到的移植只需做少量的工作。 第27页/共110页第二十七页,共111页。Linux驱动程序的加载方式(fngsh)驱动程序直接编译入内核驱动程序在内核启动时就已经在内存中可以保留专用存储(cn ch)器空间驱动程序以模块形式存储(cn ch)在文件系 统里,需要时动态载入内核驱动程序按需加载,不用时节省内存驱动程序相对独立于内核,升级灵活第28页/共110页第二十八页,共111页。Linux驱动程序模块(mkui)加载第29页/共1

21、10页第二十九页,共111页。Linux驱动程序开发(kif)的任务规划硬件资源的使用分离硬件相关和硬件无关的代码(dim)划分驱动程序的抽象层次移植驱动程序到新的平台第30页/共110页第三十页,共111页。Linux驱动程序开发(kif)的任务规划硬件资源的使用CPU时间片分配中断处理系统(xtng)存储器空间映射第31页/共110页第三十一页,共111页。设备(shbi)存储器的映射第32页/共110页第三十二页,共111页。Linux驱动程序开发(kif)的任务分离硬件相关(xinggun)和硬件无关的代码划分驱动程序的抽象层次第33页/共110页第三十三页,共111页。设备(shbi

22、)驱动程序的代码驱动程序的注册驱动程序的注册(zhc)(zhc)与注销与注销register_chrdev()register_chrdev()register_blkdev()register_blkdev()设备的打开与释放设备的打开与释放open()open()release()release()设备的读写操作设备的读写操作read()read()write()write()设备的控制操作设备的控制操作ioctl()ioctl()第34页/共110页第三十四页,共111页。设备(shbi)驱动的加载使用模块的方式动态加载驱动使用模块的方式动态加载驱动int func_init(void)

23、int func_init(void) Makefile: Makefile:insmod insmod lsmodlsmodrmmod rmmod 将驱动静态编译将驱动静态编译(biny)(biny)到内核里面到内核里面 int _init func_init(void) int _init func_init(void) Makefile: Makefile:启动时自动加载启动时自动加载第35页/共110页第三十五页,共111页。内核模块模块是内核的一部分,但是并没有被编译到内核里去。它们被分别编译和连接成目标文件。 用命令insmod插入一个模块到内核中,用命令rmmod卸载一个模块 在

24、Linux内核中,以下内容一般编译成模块:大多数的驱动程序。包括SCSI设备,CD-ROM,网络设备,不常用(chn yn)的字符设备,如打印机,watchdog等。大多数文件系统,理论上除了根文件系统不能是模块,其他文件系统都可以是模块。一些内核支持的不常用(chn yn)的可执行文件格式,如binfmt_misc。第36页/共110页第三十六页,共111页。kmod和高级(goj)模块化Linux 提供了对模块自动加载和卸载的支持 要利用(lyng)这一特性,在编译内核前进行的配置中,必须打开对 kmod 的支持选项。 一旦内核试图访问某种资源并发现该资源不可用时,它会对 kmod 子系统

25、进行一次特殊的调用而不仅仅是返回一个错误 按需加载的例子 :ALSA(Advanced Linux Sound Architecture)声卡驱动程序组的实现 第37页/共110页第三十七页,共111页。常用的系统(xtng)支持内存申请和释放 中断时钟 I/O 中断打开关闭 输出(shch)信息注册驱动程序 第38页/共110页第三十八页,共111页。内存申请(shnqng)和释放include/里声明了kmalloc()和kfree()。用于在内核模式下申请和释放内存。与用户模式下的malloc()不同(b tn),kmalloc()申请空间有大小限制。长度是2的整次方。可以申请的最大长度

26、也有限制。另外kmalloc()有priority参数 Kfree()释放的内存必须是kmalloc()申请的 第39页/共110页第三十九页,共111页。申请(shnqng)中断和释放中断request_irq()、free_irq() 是驱动程序申请中断(zhngdun)和释放中断(zhngdun)的调用。在include/里声明 第40页/共110页第四十页,共111页。时钟(shzhng)时钟的处理类似中断,也是登记(dngj)一个时间处理函数,在预定的时间过后,系统会调用这个函数。在include/linux/里声明使用时钟,先声明一个timer_list结构,调用init_time

27、r对它进行初始化。Time_list结构里expires是标明这个时钟的周期,单位采用jiffies的单位。 第41页/共110页第四十一页,共111页。I/OI/O端口的存取使用(shyng):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

28、/里定义 第42页/共110页第四十二页,共111页。中断(zhngdun)打开关闭系统提供给驱动程序开放和关闭(gunb)响应中断的能力 是在include/asm/ #define cli() _asm_ _volatile_ (cli:)#define sti() _asm_ _volatile_ (sti:) 第43页/共110页第四十三页,共111页。输出(shch)信息驱动程序要输出(shch)信息使用printk() include/linux/里声明 第44页/共110页第四十四页,共111页。注册(zhc)驱动程序如果使用模块(module)方式加载驱动程序,需要在模块初始化

29、时把设备(shbi)注册到系统设备(shbi)表里去不再使用时,把设备(shbi)从系统中卸除 定义在drivers/net/里的两个函数完成这个工作Int register_netdev(struct device *dev);void unregister_netdev(struct device *dev); 第45页/共110页第四十五页,共111页。调试调试(dio sh)(dio sh)很多Linux的驱动程序都是编译进内核的,形成一个大的内核文件。但对调试来说,这是相当(xingdng)麻烦的。调试驱动程序可以用module方式加载。支持模块方式的驱动程序必须提供两个函数:int

30、 init_module(void)和void cleanup_module(void)。 init_module()在加载此模块时调用,在这个函数里可以register_netdev()注册设备。init_module()返回0表示成功,返回负表示失败。cleanup_module()在驱动程序被卸载时调用,清除占用的资源,调用unregister_netdev()。 第46页/共110页第四十六页,共111页。模块可以动态地加载、卸载(xi zi)。在版本里,还有kerneld自动加载模块,但是中已经取消了kerneld。手工加载使用insmod命令,卸载(xi zi)用rmmod命令,看

31、内核中的模块用lsmod命令。 编译驱动程序用gcc,主要命令行参数-DKERNEL -DMODULE。并且作为模块加载的驱动程序,只编译成obj形式(加-c参数)。编译好的目标文件放在下,在启动文件里用insmod加载 第47页/共110页第四十七页,共111页。编译(biny)驱动程序第48页/共110页第四十八页,共111页。应用程序第49页/共110页第四十九页,共111页。编译(biny)应用程序第50页/共110页第五十页,共111页。背景知识:背景知识: Linux设备设备(shbi)管理管理第51页/共110页第五十一页,共111页。主要(zhyo)内容概述驱动程序基础中断处理

32、辅助函数设备(shbi)驱动程序模块编程基础字符设备(shbi)块设备(shbi)网络设备(shbi)第52页/共110页第五十二页,共111页。概述(ish)输入输出子系统: 下层:设备驱动程序 上层:设备无关部分VFS in Linux?Unix和Linux的设备管理(gunl)方法: VFS第53页/共110页第五十三页,共111页。设备(shbi)管理总体结构示意用户程序系统调用(dioyng)接口文件系统高速缓存字符(z f)设备块设备驱动程序硬件设备第54页/共110页第五十四页,共111页。输入输出系统(xtng)层次结构用户进程设备无关软件设备驱动程序设备服务子程序中断处理程序

33、硬件I/O请求I/O应答进行I/O调用;格式化I/O命名、保护、阻塞、缓冲、分配建立设备寄存器、检测状态I/O结束时,唤醒设备服务子程序执行I/O操作第55页/共110页第五十五页,共111页。驱动程序基础(jch)I/O空间Linux中的三种地址空间:CPUUntranslatedAddressCPUTranslatedAddressBusAddress:一般PC机中是一组寄存器命令(mnglng)more/proc/ioports常见总线ISAVESAEISAPCI第56页/共110页第五十六页,共111页。驱动程序基础(jch)命名空间并行设备:lp软盘:fdSCSI盘:sdIDE硬盘:

34、hda1, hda2, hdb等网络设备:ethn, slipn, pppn等在写驱动程序的时候,需要给函数(hnsh)名加上选择的前缀来避免任何混淆。如:foo_read(),foo_write()等。 第57页/共110页第五十七页,共111页。驱动程序基础(jch)内存分配函数kmalloc()内存以2的幂大小的块分配有一个优先级参数(cnsh)宏kfree()和函数kfree_s()kfree()调用kfree_s(),和free()一样工作可以直接调用kfree_s(),但是需要知道释放内存块的大小第58页/共110页第五十八页,共111页。驱动程序基础(jch)设备分类字符设备:不

35、使用缓冲区,顺序读写foo_read()&foo_write()块设备:需要使用缓冲区,随机读写策略规程(guchng)网络设备采用了特殊的处理方法。Structdevice第59页/共110页第五十九页,共111页。驱动程序基础(jch)设备号主设备号&次设备号主设备号相同的设备使用相同的驱动程序次设备号区分具体设备的实例(shl)命令:lsl/dev/had*第60页/共110页第六十页,共111页。驱动程序基础(jch)中断vs轮询工作机制的区别编程上的区别:UNIX的系统调用:执行模式的改变内核模式下的进程访问进程原来所在的用户空间的存储:get_fs_*()和memcpy_fromf

36、s()读用户空间,put_fs_*()和memcpy_tofs()写入用户空间内存。在进程运行时调用,不需要考虑地址的问题(wnt)。在中断发生时,这些宏不能使用。因为它们可能覆盖其他运行着的进程的随机空间。必须提供临时空间存放信息。对于块设备,由cache缓冲机制自动提供;字符设备需要驱动程序分配。第61页/共110页第六十一页,共111页。驱动程序基础(jch)DMA方式用于传送大规模的数据PC机上的ISADMA控制器8条DMA通道。每条通道联系着一个16位地址寄存器和16位计数器DMA直接访问物理内存DMA通道不能被共享。一些设备(shbi)拥有固定的DMA通道。Structdma_ch

37、an结构:每个通道拥有一个此结构两个域:指向该通道拥有者的字符串指针指示该通道是否已分配的标志第62页/共110页第六十二页,共111页。驱动程序基础(jch)睡眠唤醒机制TASK_INTERRUPTIBLETASK_UNITERUPTIBLE ,决定于睡眠是否能够被系统调用(dioyng)一类的事情打断。一般来说,如果设备比较慢、可以被无限阻塞,包括终端、网络设备或伪设备,睡眠应该是可中断的_sleep_on()Structwait_queuestructtask_struct*task;structwait_queue*next;第63页/共110页第六十三页,共111页。驱动程序基础设备

38、(shbi)文件设备管理(gunl)的“上半部分”Structfile结构include/增加一个设备时需要用mknod命令为该设备创建一个inode第64页/共110页第六十四页,共111页。驱动程序基础(jch)file_operationslseek():转到所需的偏移。structinode*inode指向此设备inode结构的指针。Structfile*file指向此设备的文件结构的指针。Off_toffset要转移到的相对origin指示的基准的偏移地址。Intorigin0=采用相对于绝对地址0(开始(kish))的偏移量。1=采用相对于当前位置的偏移量。2=采用相对于末尾的偏移

39、量。Lseek()在出错是返回出错码errno,否则返回lseek操作以后的绝对地址(=0)。第65页/共110页第六十五页,共111页。read()和write()structinode*inode:指向代表要访问的设备的特殊文件的指针。sturctfile*file:指向该设备的文件结构( jigu)的指针。Char*buf:一个读写的字符缓冲区。位于用户空间内存中,可以用get_fs*(),put_fs*()和memcpy*fs()访问。Intcount:缓冲区中读或写的字符的计数。它是buf的大小,也是知道怎样到达buf的末尾的手段,因为buf是没有保证以NULL结尾的。第66页/共1

40、10页第六十六页,共111页。Select()structinode*inode:指向该设备的inode结构的指针(zhzhn)。Structfile*file:指向设备的文件结构的指针(zhzhn)。Intsel_type:可以执行的选择类型SEL_INreadSEL_OUTwriteSEL_EXexceptionSelect_table*wait如果设备没有准备好,调用select_wait(),并且返回0。如果设备准备好,返回1。第67页/共110页第六十七页,共111页。ioctl()函数:处理ioctl调用。结构:首先差错检查,然后用一个大的switch语句(yj)来处理所有可能的i

41、oct。参数:Structinode*inodeStructfile*fileUnsignedintcmd:ioctl命令。一般用于做case语句(yj)的switch参数。Unsignedintarg这是此命令的参数,由用户定义。返回:出错返回-error。其他情况下返回由用户定义。第68页/共110页第六十八页,共111页。mmap()函数函数Struct inode *inode Struct file *file Unsigned long addr 需需要要映映射射进进入入的的主主存存开开始始地址。地址。Size_t len 需要映射的存需要映射的存储储空空间长间长度。度。Int p

42、rot 下面中的一个:下面中的一个: PROT_READ 可以可以读读的区域。的区域。 PROT_WRITE 可写的区域可写的区域 PROT_EXEC 可可执执行的区域行的区域 PROT_NONE 不可不可(bk)访问访问的区域的区域 Unsigned long off 需需要要映映射射的的文文件件偏偏移移地地址。址。这这个地址将被映射到个地址将被映射到addr。 第69页/共110页第六十九页,共111页。 open()和和release()函数函数 Struct inode *inode 指向此指向此设备设备的的inode结结构的指构的指针针。 Struct file *file 指向此指

43、向此设备设备的文件的文件结结构的指构的指针针。 Open()在在设设备备特特殊殊文文件件打打开开时时调调用用。是是用用来来保保证证一一致致性性的的策策略略机机制制。 Release()只只在在进进程程关关闭闭它它打打开开的的最最后后一一个个文文件件描描述述(mio sh)子子的的时时候候调调用?用? 第70页/共110页第七十页,共111页。init()函数内核第一次启动时调用:在正确的位置(wizhi)调用init():字符设备drivers/char/中的chr_dev_init()把file_operation注册到VFS中:对于字符设备register_chrdev()打印关于设备的信

44、息,并且报告找到的硬件printk()第71页/共110页第七十一页,共111页。中断(zhngdun)处理文件(wnjin)/proc/interrupts函数request_irq()函数free_irq()睡眠与唤醒中断共享ISR的上部和下部(bottomhalf)第72页/共110页第七十二页,共111页。辅助函数请求(qngqi)调度Staticvoidadd_request(structblk_dev_struct*dev,structrequest*req)Staticvoidend_request(structblk_dev_struct*dev,structrequest*r

45、eq)staticvoidmake_request(intmajor,intrw,structbuffer_head*bh)voidll_rw_block(intrw,intnr,structbuffer_head*bh)make_request()调用add_request()ll_rw_block()对请求队列排序,只能(zhnn)通过buffercache调用。电梯算法:读在写前低次设备号请求在高次设备号前低块号在高块号前drivers/block/第73页/共110页第七十三页,共111页。辅助函数(hnsh)定时器管理voidadd_timer(structtimer_list*ti

46、mer)voiddel_timer(structtimer_list*timer)voidinit_timer(structtimer_list*timer)structtimer_list第74页/共110页第七十四页,共111页。辅助函数(hnsh)中断管理externintrequest_irq(unsignedintirq,void(*handler)(int,void*,structpt_regs*),unsignedlongflags,constchar*device,void*dev_id);voidfree_irq(unsignedintirq)cli()sti()第75页/共

47、110页第七十五页,共111页。辅助(fzh)函数端口读写voidout*()unsignedcharbyte,unsignedportunsignedin*()参数:unsignedport*:b,w,l用in*()来清空(qnkn)某些状态值?第76页/共110页第七十六页,共111页。辅助(fzh)函数内存管理&设备号kmalloc()kfree()kfree_s()设备(shbi)号由主、次设备(shbi)号拼接而成。#defineMAJOR(dev)(dev)8)#defineMINOR(dev)(dev)&0xff)第77页/共110页第七十七页,共111页。辅助函数(hnsh)设

48、备的注册和注销intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops)intregister_blkdev(unsignedintmajor,constchar*name,structfile_operations*fops)intunregister_chrdev(unsignedintmajor,constchar*name)intunregister_blkdev(unsignedintmajor,constchar*name)#include#include第78页/共110页第七十八页

49、,共111页。辅助(fzh)函数内存空间转换inlinevoidmemcpy_tofs(void*to,constvoid*from,unsignedlongn)inlinevoidmemcpy_fromfs(void*to,constvoid*from,unsignedlongn)#include#defineget_user(ptr)(_typeof_(*(ptr)_get_user(ptr),sizeof(*(ptr)#defineput_user(x,ptr)_put_user(unsignedlong)(x),(ptr),sizeof(*(ptr)#include在用户空间和内核空间

50、拷贝内存属于隐含的I/O操作,不要再临界代码中使用(shyng),因为它可能冲破cli()和sti()的保护第79页/共110页第七十九页,共111页。辅助(fzh)函数缓冲区管理structbuffer_head*getblk(kdev_tdev,intblock,intsize);voidbrelse(structbuffer_head*buf);voidll_rw_block(intrw,intnr,structbuffer_head*bh);第80页/共110页第八十页,共111页。辅助(fzh)函数其他intprintk(constchar*fmt,.)#include在内核(nih

51、)中打印信息,是printf的内核(nih)版本可能导致隐含的I/O操作。不要在cli()保护的代码段中使用,因为它可能导致开中断。一些与进程相关的系统调用第81页/共110页第八十一页,共111页。模块(mkui)编程基础模块的基本概念:可以动态的加载到内核中成为kernel的一部分;加载后可以访问内核的数据结构;用户空间(kngjin)的程序或进程可以通过某个模块和内核交互。module在需要的时可通过符号表(symboltable)使用核心资源。而且module一般需要调用核心的资源,所以必须注意module的版本和核心的版本的相配问题。一般在module的装入过程中检查module的版

52、本信息。第82页/共110页第八十二页,共111页。模块之间的函数调用 内核可以使用其它模块或内核的函数,也可以export一些函数供其他模块或内核使用。 模块栈:如果模块A使用了模块B的函数,那么B必须在A之前加载,否则加载A的命令不成功。模块可以使用的函数: 自身(zshn)定义; 其他module提供; 内核提供命令ksyms a:列出已经加载的模块的函数或变量。Symbol table:记录module导出的函数或变量。所有声明为global的函数或变量都意味着被导出,可以被其他模块使用。第83页/共110页第八十三页,共111页。模块(mkui)编程基础常用命令lsmod 把现在ke

53、rnel中已经(yjing)安装的modules列出来insmod把某个module安装到kernel中。rmmod把某个没在用的module从kerne中卸载。depmod制造moduledependencyfile,以告诉将来的insmod 要去哪儿找modules 来安装。这个 dependencyfile放在/lib/modules/当前kernel版本/。第84页/共110页第八十四页,共111页。模块(mkui)基础装入Insmod命令内核kerneld守护进程(daemon)自动装入。守护进程:在超级用户下运行的一个用户进程,与核心建立一个IPC通道。Kerneld调用insmo

54、d和rmmond来装入和移出模块(mkui)。kerneld装入的module,一般放在/lib/modules/kernel-version目录下。insmod命令调用sys_get_kernel_sys()系统调用收集核心中所有符号来解决module中资源引用问题。第85页/共110页第八十五页,共111页。模块(mkui)基础装入符号表的记录有两个域:符号的名字(symbol name)和符号的值(一般是符号的地址)。核心提供的符号表在module 链表最尾module中。 insmod调用(dioyng)sys_create_module(),为新module分配一个module数据结

55、构,挂在module_list头上,置新module 状态为UNINITIALIZED。 当初始化module时,insmod调用(dioyng)sys_init_module()系统调用(dioyng),将module的初始化和清除函数作为参数传递。修改核心的符号表,同时系统需要修改新module依赖的所有module中的相关指针。 第86页/共110页第八十六页,共111页。模块基础(jch)卸载Rmmod命令Kerneld进程自动卸载自动卸载的机制为:每隔一定的时间,kerneld调用sys_delete_module()系统调用,将它装入的且不在被使用的module从系统中卸载。它遍历

56、module_list,检查被它装入(AUTOCLEAN)并且不用(VISITED标志(biozh))的模块。第87页/共110页第八十七页,共111页。内核模块必须有两个函数: int init_module():为内核中的某些东西注册一个句柄,或者把内核中的程序提换成它自己的代码(通常是进行一些工作以后再调用原来工作的代码)。 void clean_module():模块要求撤销init_module进行的所有修改(xigi),使得模块可以被安全的卸载。 在insmod和rmmod命令中使用这两个函数。Use count:记录使用本模块的进程数或模块数。 MOD_INC_USE_COUNT

57、:增加use count MOD_DEC_USE_COUNT:减少use count MOD_IN_USE:检查use count是否是0第88页/共110页第八十八页,共111页。模块(mkui)基础数据结构structmodulestructmodule*next;structmodule_ref*ref;/*所有引用该模块的模块,也用链表连接*/structsymbol_table*symtab;/*符号表*/constchar*name;/*模块的名字,存放在module结构后面(humian)的64个字节里*/intsize;/*sizeofmoduleinpages*/void*a

58、ddr;/*addressofmodule*/intstate;/*三种状态:未初始化,运行,删除*/void(*cleanup)(void);/*cleanuproutine*/;第89页/共110页第八十九页,共111页。struct symbol_table int size; /* 包括string table的总长度 */int n_symbols; int n_refs;struct internal_symbol symbol0; struct module_ref ref0; ; 后面定义的是两个(lin )零大小的数组声明,便于动态分配空间。 symbol包含一组字符串指针,

59、指向真正的符号字符串表第90页/共110页第九十页,共111页。struct internal_symbol /*符号信息(xnx)*/void *addr;const char *name; /*指向string table*/;struct module_ref /*引用信息(xnx)*/struct module *module;struct module_ref *next;string table的内容是该模块导出的函数名和变量名第91页/共110页第九十一页,共111页。第92页/共110页第九十二页,共111页。模块基础(jch)系统调用Sys_create_module为模块(

60、mkui)分配空间,将模块(mkui)链入系统的模块(mkui)链中Sys_init_module初始化模块(mkui),修正指针使模块(mkui)正常工作Sys_delete_module从系统模块(mkui)链中删除模块(mkui),释放内存空间Sys_get_kernel_syms将系统的所有符号表全部取出到用户空间第93页/共110页第九十三页,共111页。第94页/共110页第九十四页,共111页。insmod先调用系统调用sys_get_kernel_syms,将当前(dngqin)加到系统中的模块和核心的符号表全部输出到kernel_sym结构中,为后面使用。这个结构的内容在in

61、smod用户进程空间。将Mymodule目标文件读进insmod用户进程空间,成为一个映像。根据第一步得到的信息,将Mymodule映像中的地址没有确定的函数和变量一一修正过来。调用系统调用sys_create_module、sys_init_module,将Mymodule链入到系统中去。 第95页/共110页第九十五页,共111页。内核模块的编译需要用-c选项进行编译。所有的内核模块都必须包含特定的标志(biozh):_KERNEL_:这个标志(biozh)告诉头文件此代码将在内核模块中运行,而不是作为用户进程。MODULE:这个标志(biozh)告诉头文件要给出适当的内核模块的定义。LI

62、NUX:从技术上讲,这个标志(biozh)不是必要的。用于比较正规的内核模块,在多个操作系统上编译,这个标志(biozh)将会使你感到方便。它可以允许你在独立于操作系统的部分进行常规的编译。例:gcc-Wall-DMODULE-D_KERNEL_-DLINUX-D表示加入标志(biozh)第96页/共110页第九十六页,共111页。用户空间(kngjin)设备驱动程序有时不需要真正的驱动程序:没有两个(lin)以上的应用程序使用设备并且不需要响应中断没有多个进程访问不管理资源例:vgalib库早期的鼠标转换第97页/共110页第九十七页,共111页。设备(shbi)驱动程序框架接口Linux设

63、备驱动程序与外界的接口1.设备驱动程序与操作系统内核(nih)的接口,通过)完成。2.驱动程序与系统引导的接口,初始化设备。3.驱动程序与设备的接口。与具体设备相关。第98页/共110页第九十八页,共111页。驱动程序框架(kunji)功能驱动程序的注册与注销设备的打开与释放设备的读写操作设备的控制操作设备的中断(zhngdun)和轮询处理第99页/共110页第九十九页,共111页。初始化函数(hnsh)的调用关系系 统 转 入 核 心 , 调 用 函 数 start_kernel()。 它 调 用kernel_thread (init,NULL,0),创建init进程进行(jnxng)系统配

64、置(其中包括所有设备的初始化工作)。sys_setup()device_setup()chr_dev_init()/blk_dev_init()Kernel_thread()init()setup()第100页/共110页第一百页,共111页。注册(zhc)与注销注册和注销函数(hnsh):register_*dev()unregister_*dev()/include/所谓注册就是在内核的chrdevs或blkdevs中添加一项。structdevice_structconstchar*name;structfile_operations*fops;相同主设备号的fops元素内容相同。第10

65、1页/共110页第一百零一页,共111页。打开(dki)与释放打开设备:open()检查与设备有关的错误,如未准备好。如果是首次打开,则初始化设备。确定(qudng)次设备号,根据需要可更新设备的f_op。如果需要,分配且设置文件中的private_data。递增设备使用的计数器。如果只允许一个进程使用设备,则需要设忙标志。第102页/共110页第一百零二页,共111页。 释放设备:release() 递减设备使用的计数器 释放设备文件中的私有数据所占空间 如果是独占(dzhn)设备,则要清除忙标志,使其他进程可以使用 如果是最后一个释放,则关闭设备第103页/共110页第一百零三页,共111

66、页。设备(shbi)的读写操作字符设备:foo_read()和foo_write()块设备block_read和block_write()策略规程,不需要在驱动程序中实现。通过缓冲区读写,只在数据不在缓冲区时才真正(zhnzhng)执行数据传输,通过request_fn()完成。structblk_dev_structstructrequest第104页/共110页第一百零四页,共111页。设备(shbi)的控制ioctl()一般做法(zuf)是:首先差错检查,然后用一个大的switch语句(可能是内嵌的)来处理所有可能的ioctl命令。返回:出错返回-erro其他情况由用户定义第105页/共

67、110页第一百零五页,共111页。字符(zf)设备驱动程序数据结构注册(zhc)与注销轮询和中断对应驱动程序的“三个接口”。第106页/共110页第一百零六页,共111页。添加一个简单(jindn)的字符设备确定主设备号编写file_operations中的函数以及中断处理函数。编写初始化函数foo_init()在chr_dev_init()中添加(tin ji)调用和返回初始化函数的代码。修改drivers/char/Makefile;假设我们把所以必要的函数写中,则在“L_OBJS := ”行把“”加到其中。第107页/共110页第一百零七页,共111页。将该设备(shbi)私有的*.c,

68、*.h复制到目录drivers/char下。用命令:make clean;make dep;make zImage重新编译内核。用mknod命令在目录/dev下建立相应主设备(shbi)号的用于读写的特殊文件 mknod命令:建立设备(shbi)特殊文件 格式: mknod 文件名 类型 主设备(shbi)号 次设备(shbi)号 类型:c或b,代表字符设备(shbi)或块设备(shbi)第108页/共110页第一百零八页,共111页。块设备(shbi)驱动程序数据结构注册与注销读写请求及其处理增加一个块设备的方法和字符设备差不多。块设备不需要编写file_operations结构里的read

69、和write函数,但是(dnsh)也需要read和write在request中调用。需要有请求处理函数,以及中断处理函数。第109页/共110页第一百零九页,共111页。感谢您的观看(gunkn)!第110页/共110页第一百一十页,共111页。内容(nirng)总结主要内容。为实现上述两部分功能,设计一个完整的BSP需要完成两部分工作:。设置CPU的核心寄存器和控制寄存器。每条通道联系(linx)着一个16位地址寄存器和16位计数器。ioctl()函数:处理ioctl调用。symbol包含一组字符串指针,指向真正的符号字符串表。相同主设备号的fops元素内容相同。需要有请求处理函数,以及中断处理函数。感谢您的观看第一百一十一页,共111页。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号