1、课程设计目 录1嵌入式的概述11.1 嵌入式技术的现状11.2 嵌入式系统概述11.2.1嵌入式系统的定义11.2.2嵌入式系统分类21.2.3嵌入式系统的组成21.3 B超技术的发展32 B型超声仪前端模拟电路设计42.1 发射电路52.2 低通滤波器的设计52.3 前置放大器设计62.4 A/D转换电路设计73 ARM体系结构和BootLoader的实现83.1 ARM体系结构83.1.1 ARM处理器的工作状态83.1.2 ARM处理器模式83.1.3 ARM920T系统结构分析93.1.4 S3C2410A处理器介绍93.2 ARM的BootLoader概念113.3 BootLoad
2、er的移植实现113.4 Linux内核移植123.4.1 内核的配置、编译与移植124 Linux设备驱动程序134.1 设备驱动程序的分类与特征134.2 设备驱动结构144.2.1设备驱动关键数据结构144.2.2 设备驱动的基本函数154.2.3 键盘驱动的实现175 嵌入式数字B超图像处理系统的实现195.1 系统实现的方法195.2 系统实现的原理195.2.1 前处理及帧存控制205.2.2 DMA传输205.2.3 后处理及其显示206 嵌入式Linux的B超图像打印的实现216.1 嵌入式Linux的小型B超仪的打印方案217 总结与心得23参考文献2411嵌入式的概述1.1
3、 嵌入式技术的现状 后PC时代,嵌入式系统将拥有最大的市场。目前在世界范围内嵌入式系统带来的工业年产值已经超过了1万亿美兀。尽管还没有从事该领域开发的公司占到了大多数,但我国国内的嵌入式软件市场已经处十整体启动阶段。国内嵌入式软件市场未来的发展重点在十对应用范围的拓展,而且手持设备、信息家电和工业控制则是近期市场的二大热点。展望未来,明天的嵌入式系统将比今天的更方便、更小巧、更可靠、更高效而且更智能化。美国著名的未来学家尼葛洛庞帝在1999年访华时曾预言,4至5年后嵌入式系统将是继PC和Internet之后最伟大的发明。如今那么多年过去了,现实的发展也验证了这个预言的正确性。现在,嵌入式系统正
4、处十高速发展阶段,未来几年,这种发展和竞争将愈演愈烈。经过几十年的发展,嵌入式系统已经在很大程度上改变了人们的生活、工作和娱乐方式,而且这些改变还在加速。嵌入式系统具有无数的种类,每类都具有自己独特的个性。例如,MP3、数码相机与打印机就有很大的不同。汽车中更是具有多个嵌入式系统,使汽车更轻快、更安全和更容易驾驶。即使不可见,嵌入式系统也无处不在。嵌入式系统在很多产业中得到了广泛的应用并逐步改变着这些产业,包括工业自动化、国防、运输和航天领域。例如神州飞船和长征火箭中有很多嵌入式系统,导弹的制导系统是嵌入式系统,高档汽车中也有多达几十个嵌入式系统。在口常生活中,几乎所有的带有一点“智能”的家电
5、(如全自动洗衣机、电脑电饭煲等)都是嵌入式系统。1.2 嵌入式系统概述1.2.1嵌入式系统的定义嵌入式系统实际上是嵌入式计算机系统的简称。通常计算机连同一些常规的外设是作为独立的系统而存在的,并非为某一方面的专门应用而存在。例如一台PC就是一个计算机系统,整个系统存在的目的就是为人们提供一台可以编程、会计算、能处理数据的机器。它可以作为科学计算工具,也可以作为企业管理的工具,一般把这样的计算机系统成为通用计算机系统。但是有些系统却不是这样。例如医用CT也是一个系统,这里面也有计算机,但是这种计算机是作为某个专用系统中的一个部件而存在的。像这样嵌入到更大的、专用的系统中的计算机系统就是嵌入式系统
6、。IEEE(国际电气和电子工程师协会)对嵌入式系统的定义为:嵌入式系统是“用十控制、监视或者辅助操作机器和设备的装置”。国内普遍认同的嵌入式系统定义为:以应用为中心,以计算机技术为基础,软硬件可裁减,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计算机系统。1.2.2嵌入式系统分类嵌入式系统可以大致分为如下类型。这种分类是依据系统是否必须作为独立单兀工作或必须具有网络功能,是否必须执行实时操作等标准来划分的。(1)单机嵌入式系统单机嵌入式系统以单机方式工作,获取输入并产生输出。输入可以是来自传感器的电信号,或者是来自人的命令,比如按下按钮。输出可以是驱动另一个系统的电信号,或者是
7、为用户显示信息的LED或者LCD显示。在制造厂和汽车厂里很多用十过程控制的嵌入式系统可以被划入此类。在过程控制系统中,输入来自传感器,传感器将温度等物理信号转换为电信号,电信号成为能够控制阀门等设备的输出。在一些单机系统中,执行某项特定任务的时间限制并不十分严格,早几毫秒和晚几毫秒没有太大的关系,换句话说,响应时间不是至关重要的。(2)实时嵌入式系统有些嵌入式系统被要求在指定的时间内完成特定的任务。这样的系统被称为实时嵌入式系统。例如,例如当潮度超过特定闽值的时候,必须在30毫秒内打开阀门的系统。如果该任务未能在30毫秒内完成则可能产生严重的后果。这种必须严格符合实时约束条件的系统被称作“硬实
8、时嵌入式系统”。当必须执行对时间要求很严格的任务时,在过程控制中也大量使用“硬实时嵌入式系统”。还有很多系统有实时要求,但是对实时的要求不强,例如语音通信系统,语音包的延迟只会造成短暂的静默,不会有什么严重的后果,类似的这种系统被成为“软实时嵌入式系统”。1.2.3嵌入式系统的组成嵌入式系统是专用计算机应用系统,它具有一般计算机组成的共性,也是由硬件和软件组成的。嵌入式系统的硬件是嵌入式系统软件环境运行的基础,它提供嵌入式系统软件运行的物理平台和通信接口;嵌入式操作系统和嵌入式应用软件则是整个系统的控制核心,控制整个系统的运行,提供人机交互的信息等。虽然嵌入式系统一般没有系统软件和应用软件的明
9、显区分,但是一般都把嵌入式系统的软件分为嵌入式操作系统和嵌入式应用软件两大部分。 (1)嵌入式系统硬件嵌入式系统的硬件组成部分是以嵌入式处理器为中心,由存储器、I/O设备、通信模块以及电源等必要的辅助接口组成。嵌入式系统是量身定做的专用计算机应用系统,它不同十PC机的组成,在实际应用中的嵌入式系统硬件配置非常精简,除了微控制器和基本的外围电路以外,其余的电路都可根据需要和成本进行裁减、定制。嵌入式系统硬件核心是嵌入式微处理器,有时为了提高系统的信息处理能力,常常外接 DSP(或者选用内部集成了DSP模块的微处理器),以完成高性能信号处理。(2)嵌入式系统软件对十使用操作系统的嵌入式系统来说,嵌
10、入式系统软件结构一般包含4个层面:设备驱动层、实时操作系统、应用程序接口API层、实际应用程序层。对十功能简单,仅仅包括应用程序的嵌入式系统,一般不使用操作系统,仅有应用程序和设备驱动程序。驱动程序是嵌入式系统中不可或缺的重要部分,使用任何外部设备都需要有相应的驱动程序的支持,它为上层软件提供了设备的操作接口。上层软件不用考虑设备的具体内部操作,只需要调用驱动层程序提供的接口即可。驱动程序不仅要实现设备的基本功能函数,如初始化、中断响应、发送、接收等,使设备的基本功能能够实现,而且因为设备在使用过程中还会出现各种各样的差错,所以好的驱动程序还有完备的错误处理函数。1.3 B超技术的发展B超现今
11、已成为超声诊断的最基本技术,由十其具有无创伤、操作简便、成本低廉的特点,广泛用十临床诊断。30年来经历了模拟、模拟/数字混合和全数字技术二个阶段。90年代,由十超高密度(192, 256阵元)、超宽频(5MHz)探头的发展,采用现代计算机技术和图像处理技术,已能形成高质量的声束(分辨率极高)获取超宽频信号和细微变化的信息。高质量的图像(信息丰富而且真实)不仅提供了高的空间分辨率和对比分辨率,而且提高了十分重要的组织鉴别力,有力地增强了超声临床诊断效果。B超的发展,一直围绕着如何获得更充分更真实的信息而努力。不断地提高仪器的空间分辨力,对比分辨力,近年特别注意解决组织的鉴别力。主要特点有:不断发
12、展探头的超宽频、高信噪比、高匹配能力以及电子探头的超高密度阵兀,以提供获取高质量声束的基础;采用全数字声束形成技术和超宽频技术,以得到丰富而且真实的信息,取得高质量的图像,为解决对组织的鉴别力提供了可能的条件;采用现代的图像处理技术,减少斑点、噪音。提高信噪比,可以获取更微弱的组织信号,增强对组织的鉴别力,有利十逐步解决B超特异性不强的缺点。小型化是现今B超发展的一个趋势。微电子技术的进步和集成化的提高,使得芯片的功能更强、体积更小、功耗更低。以往体积做得很大的硬件模块而今也许只需一个芯片即可替代。同时,嵌入式技术的成熟也为B超的进步做出了巨大贡献。多家公司已经成功推出了他们的笔记本式B超仪,
13、极大地方便了医生的出诊。2 B型超声仪前端模拟电路设计B型超声诊断仪采用B型(Brightness)调制方式来显示回波信号的强弱。B型显示时,探头中的换能器所发射和接收的超声波按一定规则扫查过一个平面,所以显示的B型黑白图像是一幅二维的截面声像图。因此,也常把这类仪器称为超声断层显像仪,国外则常称它为B型超声扫查仪(Ultrasound B-mode Scanner)。因为脉冲回波法可获得回波信号幅度和回波反射源深度信息,调亮后的光点亮度(通常称为灰阶)与回波幅度间存在一定的函数关系(由显示管的调制特性决定)。在B超仪的接收放大通道中使用对数放大器,因此调亮所用的回波幅度信号已经过对数压缩处理
14、,于是显示出来的二维黑白图像具有很大的动态范围,其灰阶代表着反射(或散射)系数的变化。声阻抗大的组织和结石等物质(质量密度大的组织和物质,其声阻抗通常也大),其反射系数也大,所以B超图像上的光点亮度也高。B超图像所能显示的组织界面及组织内部不均匀的反射系数的变化范围很大,加之二维截面声图像的解剖学特性,使得B型图像具有极大的诊断价值。完整的B型超声仪的工作原理图可用图2-1所示的方框图来说明。接受隔离与放大检波信号处理与视放换能器显示器发射电路时序电路图2-1 超声仪原理框图2.1 发射电路由单片机发出的触发脉冲使发射电路产生一个窄脉冲,其脉冲宽带通常是换能器工作频率之倒数的一半左右,即: (
15、2-2)式(2-2)中:为发射脉冲的宽度,为换能器的工作频率。若采用的换能器工作频率为3.5MHz,可得出发射脉冲宽度约为150ns。采用SN74LS221器件得到150ns宽度的发射脉冲,SN74LS221是一款性能非常优良的单稳态多频振荡器,使用方便,可靠性高。只需外接不同阻值和电容值的电阻电容即可实现不同宽度的脉冲输出。具体电路如图2-2所示。图2-2 发射脉冲产生电路2.2 低通滤波器的设计超声波在人体内传播的过程中,遇到不同的界面时,就会发生部分反射和部分透射。当两个反射的分界面的性质相同时,反射和透射的百分率是相同的。因此,相同性质的分界面处于相同深度时,反射回来的超声能量是相等的
16、。但是相同性质的分界面处于不同的深度时,超声强度随探测深度的增加而逐渐衰减。超声波在人体组织内的衰减是一个很复杂的物理过程,它是由于超声在人体组织内传播时,被人体组织吸收、反射、绕射、折射和散射等原因造成。其中,吸收是主要的。超声波在人体内的传播过程中,能量被人体组织吸收,随着探测深度的增加超声波能量逐渐衰减。对于均匀的生物体软组织,声衰减系数在区域内基本上是相同的。经过前置放大器处理后的超声回波信号中混有较多的高频噪声,为方便后级电路对有用信号的处理,需要对噪声进行消除,因此引入低通滤波器。采用TL082构成四阶巴特沃斯低通滤波器,TL082是一款高带宽,双通道运算放大器,其带宽可达到4MH
17、z,输入阻抗为10,截止频率为:通带增益为:1002.3 前置放大器设计超声回波信号频率高,强度弱,噪声大,需要先对其进行放大处理。在放大的时候应特别小心,如果处理不好将会给后级电路造成极大的麻烦。因此,前置放大电路是整个超声信号接收电路的一个重点,同时也是一个瓶颈。采用三级管MRF904和MM4049实现高输入阻抗的前置放大器,这两种三级管是一组对管,性能很接近,其转换频率在,时可达到3.5GHz,很适合用于对高频信号的处理。此前置放大器能够很好地避免信号的衰减并对噪声有一定的抑制作用。具体电路如图2-3所示。图2-3 前置电路原理图2.4 A/D转换电路设计超声回波信号在经过一系列模拟电路
18、处理后,还需要对其进行数字化,以供后端的更高级处理。前端模拟处理加后端数字处理的方法是现在电路系统中普遍采用的方式,虽然数字化技术在当今已占主导地位,但是模拟技术绝对不会被取代,因为现实世界本就是一个模拟的世界。因此,我们要进行数字化处理A/D转换很重要。选用AD公司的AD9220实现A/D转换。AD9220是一款通用的高性能12位A/D转换器,采样率最高可达10MSPS。我们采用3.5MHz的探头,根据采样定理,这款A/D转换器能够达到要求。用74HC541对转换输出的数字信号进行缓存,从而更好地实现对后级电路的支持。A/D转换电路如图2-4所示。图2-4 A/D转换电路图253 ARM体系
19、结构和BootLoader的实现3.1 ARM体系结构ARM(Advanced RISC Machines),既可以认为是一个公司的名字,也可以认为是对一类微处理器的通称,还可以认为是一种技术的名字。1991年ARM公司成立于英国剑桥,主要出售芯片设计技术的授权。在32位RISC中CPU开发领域不断取得突破,其结构已经从V3发展到V6。由于ARM公司自成立以来,一直以IP提供者的身份向各大半导体制造商出售知识产权,而自己不介入芯片的生产销售,加上其设计的芯核具有功耗低、成本低等显著优点,因此获得众多的半导体厂家和整机厂商的大力支持,在32位嵌入式应用领域获得了巨大的成功,目前已经占有75%以上
20、的32位RISC嵌入式产品市场。在低功耗、低成本的嵌入式应用领域确立了市场领导地位。目前非常流行的ARM核有ARM7TDMI,StrongARM,ARM720T,ARM920TDMI,ARM922T,ARM940T,ARM946T,ARM966T,ARMI0TDM1等。自V5以后,ARM公司提供Piccolo DSP的芯核给芯片设计者,用于设计ARM+DSP的SOC(System On Chip)结构的芯片。此外,ARM芯片还获得了许多实时操作系统(RealTime Operating System)供应商的支持,比较知名的有:Linux,Win CE,pSOS,VxWorks,Mucleus
21、,EPOC,uCOS,BeOS等。3.1.1 ARM处理器的工作状态从编程的角度看,ARM920T处理器的工作状态一般有两种(1)ARM状态,此时处理器执行32位的、字对齐的ARM指令;(2)Thumb状态,此时处理器执行16位的、半字对齐的Thumb指令。ARM指令集和Thumb指令集均有切换处理器状态的指令,在程序的执行过程中,处理器可以随时在两种工作状态之间切换。并且,处理器工作状态的转变并不影响处理器的工作模式和相应寄存器中的内容。但ARM处理器在开始执行代码时,应该处于ARM状态。3.1.2 ARM处理器模式ARM920T支持7种运行模式,分别为:(1)用户模式(usr),ARM处理
22、器正常的程序执行状态;(2)快速中断模式(fiq),用于高速数据传输或通道处理;(3)外部中断模式(irq),用于通用的中断处理;(4)管理模式(svc),操作系统使用的保护模式;(5)数据访问终止模式(abt),当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护;(6)系统模式(sys),运行具有特权的操作系统任务;(7)未定义指令终止模式(und),当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。ARM处理器的运行模式可以通过软件改变,也可以通过外部中断或异常处理改变。大多数的应用程序运行在用户模式下,当处理器运行在用户模式下时,某些被保护的系统资源是不能被访问的
23、。3.1.3 ARM920T系统结构分析ARM920T采用5级流水线,具有分开的指令和数据存储器,5级流水线具体如下:(1)取指:从存储器中去取指令,并将其放入指令流水线。(2)译码:对指令进行译码。(3)执行:把一个操作数移位,产生ALU的结果。(4)缓冲/数据:如果需要,则访问数据存储器;否则ALU的结果只是简单地缓冲1个时钟周期,以便所有的指令具有同样的流水线流程。(5)回写:将指令产生的结果回写到寄存器,包括任何从存储器中读取的数据。ARM920T处理器的一个显著特点就是采用指令和数据分离访问的方式,即采用了指令缓存(I-Cache)和数据缓存(D-Cache)。这样可以把指令访问和数
24、据访问单独安排1级流水线。3.1.4 S3C2410A处理器介绍S3C2410A在包含ARM920T核的同时,增加了丰富的外围资源。其中片内外围模块主要包括:(1)一个LCD控制器,支持STN和TFT液晶显示屏;(2)外部存储管理(SDRAM控制器和芯片选择逻辑);(3)3个通道的UART;(4)4个通道的DMA,支持存储器和I/O口之间的传输,以提高传输速率;(5)4个具有PWM功能的16位定时/计数器和1个16位内部定时器,支持外部时钟源;(6)8通道的10位ADC,最高速率可达到500kB/s,10位分辨率;(7)触摸屏接口;(8)IIS总线接口;(9)2个USB主机接口,1个USB设备
25、接口;(10)2个SPI接口;(11)SD卡接口和MMC卡接口;(12)16位看门狗定时器;(13)117位通用I/O口和24位外部中断源;(14)8通道10位AD控制器;(15)电源管理。S3C2410A同时集成了一个具有日历功能RTC和具有PLL(MPLL和UPLL)的芯片时钟发生器。MPLL产生主时钟,能够支持处理器工作频率最高达到203MHz。UPLL产生实现主从USB功能的时钟。利用S3C2410A资源和强大的管理功能,可以轻松地进行各种嵌入式系统的设计开发。S3C2410A结构框图如图3-1所示。图3-1 S3C2410A结构框图3.2 ARM的BootLoader概念对于移植操作
26、系统到开发板的人来说,编写移植BootLoader是一个不可避免的过程,同时也是一个很有挑战性的工作。我们知道PC机Linux的体系结构,PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的OS BootLoader(比如GRUB等)一起组成。BIOS在完成硬件检测和资源分配后,将硬盘MBR中的BootLoader读到系统RAM中,然后将控制权交给BootLoader。BootLoader的主要运行任务就是将内核映像从硬盘上读到RAM中,然后跳转到内核的入口点去运行,即开始启动操作系统。而在嵌入式系统中,通常并没有像BIOS那样的固件程序,因此整个系统的加载启动任务就
27、完全由BootLoader来完成。简单地说,BootLoader就是在操作系统内核运行之前运行的一段小程序,通过这段小程序,可以初始化硬件设备、建立内存空间的映射,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境,将内核映像从Flash上读到RAM中,然后跳转到内核的入口点去运行,即开始启动操作系统。(1)Boot Loader的stage l通常包括以下步骤(以执行的先后顺序): 硬件设备初始化; 为加载BootLoader的stage2准备RAM空间; 拷贝BootLoader的stage2到RAM空间中; 设置好堆栈; 跳转到stage2的C入口。(2
28、)Boot Loader的stage2通常包括以下步骤(以执行的先后顺序): 初始化本阶段要使用到的硬件设备; 检测系统内存映射(memory map); 将kernel映像和根文件系统映像从flash上读到RAM空间中; 为内核设置启动参数; 调用内核; 3.3 BootLoader的移植实现在嵌入操作系统的ARM平台上,平台启动后执行的第一段代码就是BootLoader。BootLoader的任务是初始化硬件条件,将系统带入一个合适的工作环境并引导操作系统。成功引导操作系统之后,BootLoader将控制权交给操作系统。可以看出,BootLoader在ARM平台上所起的作用非常关键。3.4
29、 Linux内核移植Linux内核主要由5个子系统组成:进程管理,内存管理,虚拟文件系统,网络接口,设备管理。它们之间有着复杂的调用关系,但幸运的是,在移植中不会触及到太多,因为Linux内核良好的分层结构将硬件相关的代码独立出来。在做系统移植的时候,需要改动的就是进程管理、内存管理和设备管理中被独立出来的那部分与硬件相关的代码。虚拟文件系统和网络则几乎与平台无关,它们由设备管理中的驱动程序提供底层支持。3.4.1 内核的配置、编译与移植从Linux 2.6.11开始,Samsung S3C2410已经成为Linux的一个标准支持平台,无需任何patch就可以在S3C2410的目标板上运行得很
30、好了,不用打补丁并不意味着我们一个字符都不用修改。我们选择的Linux版本是Linux2.6.14。(1)直接将ARCH?=$(SUBARCH)这行注释掉,并加入一行ARCH?=arm。上面两种修改方法都是可以的,不管怎么做目的就是要使编译出来的目标文件(可执行文件)面向的是arm平台。还要注释掉CROSS_OMPILE?=这行,加一行CROSS_COMPILE=arm-linux-。修改这一行是为了在编译过程中使用我们的交叉编译器。(2)使用make manuconfig(也可以使用make config,make xconfig)来配置内核。(3)使用以下命令对内核进行编译:make de
31、p/make zImage(4)将生成的zImage文件通过VIVI下载功能经网络传输到开发板,整个的操作系统移植工作就完成了。具体的实现过程如下:在VIVI Shell下输入命令load flash kernelt.然后在WINDOWS的命令行模式下,进入到盘符C:,输入命令mytftpi 202.115.26.45 put zImage.4 Linux设备驱动程序4.1 设备驱动程序的分类与特征在Linux中,对每一个设备的描述都通过主设备号和从设备号。其中主设备号描述控制这一类设备的驱动程序,从设备号用来区分同一个驱动程序控制的不同设备。Linux为三大类设备提供了接口,分别是:(1)字
32、符设备(Char Device)字符设备支持面向字符I/O操作,它不经过系统的快速缓存,所以它们负责管理自己的缓冲区结构。字符设备只支持顺序存取的功能,不支持随机存取。(2)块设备(Block Device)块设备接口仅支持面向块的I/O操作,所有I/O操作都通过在内核地址空间中的I/O缓冲区进行,它可以提供随机存取的功能。典型的块设备主要包括硬盘、软盘、CD-ROM等。(3)网络设备(Network Device)网络设备在Linux里作专门的处理。Linux的网络系统主要是基于BSD Unix的socket机制。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统
33、里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。Linux系统中虽然存在着许多不同的设备驱动程序,但它们具有一些共同的特征: 驱动程序属于内核代码设备驱动程序是内核的一部分,它像内核中其它代码一样运行在内核模式,驱动程序如果出错将会使操作系统受到严重破坏,甚至能使系统崩溃并导致文件系统的破坏和数据丢失。 为内核提供统一的接口设备驱动程序必须为Linux内核或其它子系统提供一个标准的接口。例如终端驱动程序为Linux内核提供了一个设备文件I/O接口。 驱动程序的执行是属于内核机制并且使用内核服务设备驱动可以使用标准的内核服务如内存分配、中断发送和等待队列等。 动态可加载多
34、数Linux设备驱动程序可以在内核模块发出加载请求时加载,而在不使用时将其卸载,这样内核能有效地利用系统资源。可配置Linux设备驱动程序可以连接到内核中。当内核被编译时,被连入内核的设备驱动程序是可以配置的。4.2 设备驱动结构4.2.1设备驱动关键数据结构设备驱动程序提供的入口点分别是file_operation数据结构、inode数据结构和file数据结构,它们是驱动开发的基础。(1)file_operation数据结构file_operations结构是定义在include/linux/fs.h中的函数指针表,内核内部通过它提供文件系统的入口点函数。驱动程序很大一部分工作就是要“填写”
35、结构体中定义的函数(根据需要,实现部分函数或全部):struct file_operationsstruct_module*owner;loff_t(*llseek)(struct file*,loff_t,int);ssize_t(*read)(struct file*,char*,size_t,loff_t*);ssize_t(*write)(struct file*,const char*,size_t,loff_t*);int(*readdir)(struct file*,void*,filldir_t);unsigned int(*poll)(struct file*,struct
36、poll_table_struct*);int(*ioctl)(struct inode*,struct file*,unsigned int,unsigned long);int(*mmap)(struct file*,struct vm_area_struct*);int(*open)(struct inode*,struct file*);int(*flush)(struct file*);int(*release)(struct inode*,struct file*);int(*fsync)(struct file*,struct dentry*,int datasync);int(
37、*fasync)(int,struct file*,int);int(*lock)(struct file*,int,struct file_lock*);ssize_t(*readv)(struct file*,const struct iovec*,unsigned long,loff_t*);ssize_t(*writev)(struct file*,const struct iovec*,unsigned long,loff_t*);这个结构的每一个成员的名字都对应着一个系统调用。在用户进程利用系统调用对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应
38、的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给函数,这就是Linux的设备驱动程序工作的基本原理。(2)inode数据结构文件系统处理的文件所需要的信息在inode(索引结点)数据结构中,inode数据结构提供了关于特别设备文件/dev/driver(假设此设备名为driver)的信息。(3)file数据结构file数据结构主要用于与文件系统对应的设备驱动程序使用。当然其他设备驱动程序也可以使用,它提供有关被打开文件的信息。在结构file_operations里,指出了设备驱动程序所提供的入口点位置,分别是:lseek,移动文件指针的位置,显然只能用于可以随机存取的设备。
39、read,进行读操作,参数buf为存放读取结果的缓冲区,count为所要读取的数据长度。返回值为负表示读取操作发生错误,否则返回实际读取的字节数。对于字符型,要求读取的字节和返回实际读取字节数都必须是inodei_blksize的倍数。write,进行写操作,与read类似。readdir,取得下一个目录入口点,只有与文件系统相关的设备驱动程序才使用。select,进行选择操作,如果驱动程序没有提供select入口,select操作将会认为设备已经准备好进行任何的I/O操作。ioctl,进行读/写以外的其它操作,参数cmd为自定义的命令。mmap,用于把设备的内容映射到地址空间,一般只有块设备
40、驱动程序使用。open,打开设备准备进行I/O操作。返回0表示打开成功,返回负数表示失败。如果驱动程序没有提供open入口,则只要/dev/driver文件存在就认为打开成功。release,即colse操作。4.2.2 设备驱动的基本函数(1)内存操作作为系统核心的一部分,设备驱动程序在申请和释放内存时不是调用malloc和free,而代之以调用kmalloc和kfree,它们定义为:#includevoid*kmalloc(unsigned int len,int priority);void kfree(void*obj);参数len为希望申请的字节数;obj为要释放的内存指针;prio
41、rity为分配内存操作的优先级,即在没有足够空闲内存时如何操作,一般用GEP_KERNEL。(2)中断在Linux系统里,对中断的处理是属于系统核心的一部分,因此如果设备与系统之间以中断方式进行数据交换的话,就必须把该设备的驱动程序作为系统核心的一部分,设备驱动程序通过调用request_irq函数来申请中断,通过free_irq释放中断。它们的定义为:#includeint request_irq(unsigned int irqvoid(*handler)(int ira,void dev_id,struct pt_regs*rdgs);unsigned long flags;const
42、char*device;void*dev_id);void free_irq(unsigned int irq,void*dev_id);参数irq表示所要申请的硬件中断号;handler为向系统登记的中断处理子程序,中断产生时由系统来调用,调用时所带参数irq为中断号;device为设备名,将会出现在/proc/interrupts文件里;dev_id为申请时告诉系统的设备标识;regs为中断发生时寄存器内容。flag是申请时的选项,它决定中断处理程序的一些特性。其中最重要的中断处理程序是快速处理程序(flag里设置了SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT
43、)。快速处理程序运行时,所有中断都被屏蔽,而慢速处理程序运行时,除了正在处理的中断外,其它中断都没有被屏蔽。(3)时钟在设备驱动程序里,一般都需要用到计时机制。在Linux系统中,时钟由系统接管,设备驱动程序可以向系统申请时钟。与时钟有关的系统调用有:#include#includevoid add timer(struct timer_list*timer);int del_timer(struct timer_list*timer);int del_timer(struct timer_list*timer);inline void init_timer(struct timer_list
44、*timer);struct timer_list的定义为:struct timer_liststruct timer_list*next;struct timer_list*prev;unsigned long expires;unsigned long data;void(*function)(unsigned long d);其中expires是要执行function的时间。系统核心有一个全局变量jiffies表示当前时间,一般在调用add_timer时jiffies=JIFFIES+num,表示在num个系统最小时间间隔后执行function函数。系统最小时间间隔与所用的硬件平台有关,
45、在核心里定义了常数HZ表示一秒内最小时间间隔的数目,则num*HZ表示num秒。系统计时到预定时间就调用function,并把此子程序从定时队列里删除,因此如果想要每隔一定时间间隔执行一次的话,就必须在function里再一次调用add_timer.。function的参数d即为timer里面的data项。4.2.3 键盘驱动的实现在Linux中,键盘驱动被化分成两层来实现。其中,上层是一个通用的键盘抽象层,完成键盘驱动中不依赖于底层具体硬件的一些功能,并且负责为底层提供服务;下层则是硬件处理层,与具体硬件密切相关,主要负责对硬件进行直接操作,下面对键盘驱动的初始化程序进行分析。keyboar
46、d_init()函数是键盘代码执行的入口点。它在对键盘的工作模式及其他参数进行配置后,调用keyboard_init hw()函数。对于上层来说,此函数是一个个统一的接口,对于不同体系结构,它们的keyboard_init hw()实现代码是不同的(通过CONFIG_ARCH的值来确定),它就是进行键盘的硬件初始化功能。keyboard_init()函数的源代码及其分析如下:int_init keyboard_init(void)int i;struct keyboard_struct keyboard0;extern struct tty_driver console_dirver;keyb
47、oard0.ledflagstate=keyboard0.default_ledflagstate=KBD_DEFLEDS;/缺省灯不亮keyboard0.ledmode=LED_SHOW_FLAGS;keyboard0.lockstate=KBD_DEFLOCK;/表示用key_map的第一个表,没有lock键keyboard0.slockstate=0;keyboard0.modeflags=KBD_DEFMODE;keyboard0.kbdmode=VC_XLATE;for(i=0;iMAX_NR_CONSOLES;i+)/为每个控制台分配一个KBD结构keyboard_tablei=keyboard0;ttytab=console_driver.table;keyboard_init_hw();tasklet_enable(&keyboard_tasklet);/把keyboard_tasklet挂到CPU的运行队列中