嵌入式开发环境的搭建实务_第1页
嵌入式开发环境的搭建实务_第2页
嵌入式开发环境的搭建实务_第3页
嵌入式开发环境的搭建实务_第4页
嵌入式开发环境的搭建实务_第5页
已阅读5页,还剩108页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

大连东软信息学院嵌入式系统导论课程组嵌入式系统导论2023/1/31第3章嵌入式开发环境的搭建3.1嵌入式开发环境概述13.2Flash程序烧写23.3BootLoader程序33.4内核的裁剪的编译43.5根文件系统的构建53.6驱动程序原理与开发62023/1/313.1嵌入式开发环境概述1.建立开发环境2.配置开发主机,配置MINICOM3.建立引导装载程序bootloader4.下载别人已经移植好的linux操作系统5.建立根文件系统6.建立应用程序的falsh分区7.开发应用程序8.烧写内核、根文件系统、应用程序9.发布产品2023/1/31第3章嵌入式开发环境的搭建3.1嵌入式开发环境概述13.2Flash程序烧写23.3BootLoader程序33.4内核的裁剪的编译43.5根文件系统的构建53.6驱动程序原理与开发62023/1/313.2Flash程序烧写烧写:即利用特殊工具向开发板中下载代码。实例:向ARM板(裸机)上烧写BootLoader、内核、根文件系统前提:存在目录。./img,其下有已经准备好的各个部分软件的映像文件(即用交叉编译器编译好的可执行文件),分别为:VIVI:针对S3C2410的BootLoader映像文件zImage:经裁剪的Linux内核映像文件root.cramfs:根文件系统映像文件sjf2410:完成烧写的程序2023/1/313.2Flash程序烧写具体烧写步骤1.安装JTAG驱动程序将整个giveoio目录(JTAG驱动所在目录)复制到c:\WINDOWS下,并将该目录下的giveio.sys文件复制到系统盘驱动目录下,如c:\WINDOWS\system32\drivers在控制面板中添加该驱动程序2.设置超级终端按照波特率115300,数据位8,无奇偶校验,停止位1,数据流控为无进行设置3.烧写引导程序使用sjf2410程序对vivi进行第一次烧写vivi启动后,使用bonpart命令对flash进行分区使用load命令对vivi进行第二次烧写4.烧写内核使用load命令对kernel进行烧写5.烧写根文件系统使用load命令对rootfs进行烧写2023/1/31第3章嵌入式开发环境的搭建3.1嵌入式开发环境概述13.2Flash程序烧写23.3BootLoader程序33.4内核的裁剪的编译43.5根文件系统的构建53.6驱动程序原理与开发62023/1/313.3.1BootLoader程序原理对于PC系统,引导加载程序BIOS(固件程序)和位于磁盘MBR(主引导记录)中系统引导程序(LILO和GRUB等)一起组成。BIOS完成硬件检测和资源分配后,将硬盘MBR中的引导程序读到系统的内存中,然后将控制权交给引导程序。引导程序的主要任务就是将内核映像从硬盘上读到内存中,然后跳转到内核的入口点去运行,即开始启动操作系统。在嵌入式系统中,主要使用flash作为系统的存储煤介,很少用磁盘,因此整个系统的加载启动任务就完全由引导程序(也称为Bootloader)来完成。2023/1/31就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。嵌入式系统中的bootloader概念2023/1/31Bootloader的功能1.硬件设备初始化(CPU的主频、SDRAM、中断、串口等)2.内核启动参数3.启动内核4.与主机进行交互,从串口、USB口或者网络口下载映象文件,并可以对FLASH等存储设备进行管理2023/1/31Bootloader特点1.依赖于硬件:每种不同的CPU体系结构都有不同的bootloader2.bootloader还依靠具体的嵌入式板级设备的配置2023/1/31BootLoader的安装媒介1.系统加电或复位后,所有的处理器通常都从某个预先安排的地址上取指令。比如,ARM在复位时从地址0x0取指。2.嵌入式系统中通常都有某种类型的固态存储设备(比如:ROM、EEPROM或FLASH等)被映射到这个预先安排的地址上。因此在系统加电后,处理器将首先执行BootLoader程序3.Bootloader是最先被系统执行的程序2023/1/31固态存储设备的典型空间分配结构2023/1/31Bootloader的烧写方式1.通过JTAG口2.通过以太网口3.通过串口4.其中前两种方式比后一种快得多2023/1/31BootLoader的控制方式1.主机和目标机之间一般通过串口建立连接,BootLoader软件在执行时通常会通过串口来进行通讯,比如:输出打印信息到串口,从串口读取用户控制字符2.也可以通过JTAG等其他接口通讯2023/1/31BootLoader的操作模式大多数BootLoader都包含两种不同的操作模式:1.启动加载模式2.下载模式从最终用户的角度看,BootLoader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别2023/1/31启动加载模式启动加载模式,称为“自主”(Autonomous)模式

BootLoader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是BootLoader的正常工作模式,因此在嵌入式产品发布的时侯,BootLoader显然必须工作在这种模式下。BootLoader的操作模式2023/1/31下载模式在下载模式下,目标机上的BootLoader将通过串口连接或网络连接等通信手段从主机下载文件,如:下载内核映像和根文件系统映像等从主机下载的文件通常首先被BootLoader保存到目标机的RAM中,然后再被BootLoader写到目标机上的FLASH类固态存储设备中。这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用BootLoader的这种工作模式。工作于这种模式下的BootLoader通常都会向它的终端用户提供一个简单的命令行接口。BootLoader的操作模式2023/1/31BL的典型结构框架大多数BootLoader都分为stage1和stage2两大部分。依赖于处理器体系结构和板级初始化的代码,通常都放在stage1中,用汇编语言实现而stage2则通常用C语言来实现,这样可以实现更复杂的功能,而且代码会具有更好的可读性和可移植性。

2023/1/31BootLoader的stage1通常包括以下步骤(以执行的先后顺序):硬件设备初始化。为加载BootLoader的stage2准备RAM空间。拷贝BootLoader的stage2到RAM空间中。设置好堆栈跳转到stage2的C入口点。

BL的典型结构框架2023/1/31BootLoader的stage2通常包括以下步骤(以执行的先后顺序):初始化本阶段要使用到的硬件设备。检测系统内存映射(memorymap)。将kernel映像和根文件系统映像从flash上读到RAM空间中。为内核设置启动参数。调用内核。stage2的代码通常用C语言来实现,以便于实现更复杂的功能和取得更好的代码可读性和可移植性。与普通C语言应用程序不同的是,在编译和链接bootloader这样的程序时,我们不能使用glibc库中的任何支持函数。BL的典型结构框架2023/1/313.3.2几种流行的LinuxBootLoader1.U-Boot2.BLOB3.RedBoot4.VIVI2023/1/313.3.3S3C2410平台上的VIVI分析vivi是由韩国Mizi公司开发的一种BootLoader,适合于ARM9处理器,支持S3C2410UP-NETARM2410平台的引导程序启动模式和下载模式结构简单支持Linux内核引导,可以传递内核参数支持分区(bon)命令行2023/1/31vivi的Stage1(文件head.S)<1>

关WATCHDOG:上电后,WATCHDOG默认是开着的<2>禁止所有中断<3>初始化系统时钟<4>初始化内存控制寄存器(一共13个)<5>检查是否从掉电模式唤醒,若是,则调用WakeupStart函数进行处理<6>点亮所有LED<7>

初始化UART0<8>将vivi所有代码(包括阶段1和阶段2)从nandflash复制到SDRAM中<9>

跳到bootloader的阶段2运行2023/1/31vivi的Stage1(文件head.S)2023/1/31vivi的Stage2(文件main.c)1.打印vivi的信息,包括版本号等2.调用若干个初始化函数3.boot_or_vivi():判断是否有“r”,回车或空格键按下,若有,则进入vivishell;若没有,则执行boot命令,启动内核4.boot命令执行后,找到kernel分区,找它的偏移量和大小,执行boot_kernel()函数,拷贝内核映象5.设置linux启动参数,打印NowBootingLinux…6.调用call_linux()函数,启动内核2023/1/31第3章嵌入式开发环境的搭建3.1嵌入式开发环境概述13.2Flash程序烧写23.3BootLoader程序33.4内核的裁剪的编译43.5根文件系统的构建53.6驱动程序原理与开发62023/1/313.4.1内核的裁减ARM上的

linux内核移植准备工作1.下载linux2.6.0内核及其关于ARM平台的补丁,如:Patch-2.6.0-rmkl.gz2.给linux2.6.0打补丁3.准备交叉编译环境4.修改内核目录下的makefile文件2023/1/31Linux内核的编译菜单有好几个版本:1)makeconfig:进入命令行,可以一行一行的配置。2)makemenuconfig:开发人员比较熟悉的menuconfig菜单。3)makexconfig:在2.4.X以及以前版本中xconfig菜单是基于TCL/TK的图形库的。

3.4.1内核的裁减2023/1/312.4.X版本xconfig配置菜单:2023/1/312.4.X版本menuconfig配置菜单:2023/1/312.6.X版本xconfig配置菜单:2023/1/31内核模块处理方式要增加对某部分功能的支持,可以把相应部分编译到内核中,也可以把该部分编译成模块,动态调用。如果编译到内核中,在内核启动时就可以自动支持相应部分的功能,这样的优点是方便、速度快,机器一启动,你就可以使用这部分功能了;缺点是会使内核变得庞大起来,经常使用的部分直接编译到内核中,比如网卡。如果编译成模块,就会生成对应的.o文件,在使用的时候可以动态加载,优点是不会使内核过分庞大,缺点是你得自己来调用这些模块。2023/1/31在选择相应的配置时,有三种选择方式:Y-将该功能编译进内核N-不将该功能编译进内核M-将该功能编译成可以在需要时动态插入到内核中的模块2023/1/312023/1/31Linux内核的编译菜单有好几个版本:1)makeconfig:进入命令行,可以一行一行的配置。2)makemenuconfig:开发人员比较熟悉的menuconfig菜单。3)makexconfig:在2.4.X以及以前版本中xconfig菜单是基于TCL/TK的图形库的。

3.4.2内核的编译2023/1/31(1)makeclean:清楚当前环境(2)makedep:设置变量依赖关系(3)makezImage:编译内核,生成zImage编译命令2023/1/31编译完成的Linux内核在哪里?./vmlinux,elf格式未压缩内核arch/arm/boot/compressed/vmlinux,压缩以后的elf格式内核,此文件是从非压缩的内核映像产生的。arch/arm/boot/zImage,可自解压的压缩内核的映像文件2023/1/31第3章嵌入式开发环境的搭建3.1嵌入式开发环境概述13.2Flash程序烧写23.3BootLoader程序33.4内核的裁剪的编译43.5根文件系统的构建53.6驱动程序原理与开发62023/1/313.5根文件系统的构建Linux根文件系统目录结构使用busybox生成工具集构建根文件系统2023/1/31Linux根文件系统目录结构Linux根文件系统目录结构bin 必要的用户命令(二进制文件)*boot引导加载程序使用的静态文件dev设备文件及其他特殊文件etc系统配置文件*home用户主目录lib必要的链接库,例如:C链接库、内核模块mnt临时挂载的文件系统的挂载点注:“*”目录在嵌入式Linux上为可选的。2023/1/31Linux根文件系统目录结构*opt

附加软件的安装目录proc提供内核和进程信息的proc文件系统*rootroot用户主目录sbin必要的系统管理员命令tmp临时文件目录usr大多数用户使用的应用程序和文件目录var监控程序和工具程序存放的可变数据Linux根文件系统目录结构2023/1/31/etc目录--系统配置文件fstab 挂载文件系统的配置文件passwd Password文件inetd.conf Inetd守护进程的配置文件group Group文件init.d/rcS 缺省的sysinit脚本Linux根文件系统目录结构2023/1/31使用Busybox生成工具集2023/1/31使用Busybox生成工具集2023/1/31使用Busybox生成工具集Busybox的配置和交叉编译(1)2023/1/31使用Busybox生成工具集1.如果在开发板上使用devfs,则需要设置GereralConfiguration选项[*]Supportfordevfs2.配置交叉编译器:BuildOptions[*]DoyouwanttobuildBusyBoxwithaCrossCompiler?(/usr/local/arm/3.4.1/bin/arm-linux-)CrossCompilerprefix需要在接下来的输入栏中输入宿主机中交叉编译器安装的路径,如“/opt/host/armv41/bin/armv41-unknown-linux-”Busybox的配置和交叉编译(2)2023/1/31使用Busybox生成工具集3.选择Busybox的编译方式:BuildOptions BuildBusyBoxasastaticbinary(nosharedlibs)

缺省配置为使用链接库Busybox的配置和交叉编译(2)2023/1/31使用Busybox生成工具集配置其他工具集:ArchivalUtilities工具:tar、zip、unzip

Coreutils常用命令:basenamecatchgrpchmoddatedddfechoenvlnlsmkdirmknodmvpwdrmrmdirsleepsortsyncwcwhoami等等ConsoleUtilitiesDebianUtilitieEditors编辑命令:viawksed等FindingUtilities查找命令:findgrepxargsBusybox的配置和交叉编译(3)2023/1/31配置其他工具集:InitUtilities[*]init[*]Supportreadinganinittabfile?[*]Supportrunninginitfromwithinaninitrd?Busybox的配置和交叉编译(3)使用Busybox生成工具集2023/1/31配置其他工具集:Login/PasswordManagementUtilitiesLogin:gettyloginpasswdMiscellaneousUtilitiesLinuxModuleUtilitiesNetworkingUtilities网络命令集:hostnameifconfiginetdnetstatpingrouteProcessUtilities进程命令:freepssysctltopShellsshell工具:ash等

SystemLoggingUtilities日志工具:syslogdklogdLinuxSystemUtilities系统工具:dmesgfdiskgetoptmoremountumount使用Busybox生成工具集Busybox的配置和交叉编译(3)2023/1/31编译Busybox:

(1)makedep

(2)make

(3)makeinstall使用Busybox生成工具集Busybox的配置和交叉编译(4)2023/1/31编译生成的目录结构(_install

):/bin/linuxrc/sbin/usr/usr/bin/usr/sbin使用Busybox生成工具集Busybox的配置和交叉编译(5)2023/1/31构建根文件系统在_install下创建其它的目录Dev:存放设备文件Proc:Lib:库文件所在目录Mnt:临时挂载点Tmp:临时目录Usr:用户目录Var:Etc:存放系统设置文件目录,在此目录下创建如下文件Inittab:指定运行级别文件Fstab:挂载文件系统的配置文件inetd.conf:Inetd守护进程配置文件profile:shell配置脚本Passwd:用户管理文件Hosts:静态域名解析文件2023/1/31利用cramfs工具创建根文件系统映象文件mkcramfs_installroot.cramfsroot.cramfs即是最后根文件系统的可执行映像文件构建根文件系统2023/1/31第3章嵌入式开发环境的搭建3.1嵌入式开发环境概述13.2Flash程序烧写23.3BootLoader程序33.4内核的裁剪的编译43.5根文件系统的构建53.6驱动程序原理与开发62023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31驱动开发简介驱动程序是应用程序与硬件之间的一个中间软件层;驱动程序应该为应用程序展现硬件的所有功能,不应该强加其他的约束,对于硬件使用的权限和限制应该由应用程序层控制。

驱动程序有时会被多个进程同时使用,这时我们要考虑如何处理并发的问题,就需要调用一些内核的函数使用互斥量和锁等机制。概念:2023/1/31驱动开发简介Linux输入/输出系统层次结构和功能:用户应用程序(设备)文件系统设备驱动程序物理设备控制器输入/输出请求输入/输出响应物理设备物理设备控制器2023/1/31驱动开发简介Linux驱动程序与外界的接口:设备驱动程序接口具体设备驱动程序与设备间接口系统初始化接口操作系统内核数据结构file_operations各设备初始化交互进行实现2023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31设备驱动分类目前Linux支持的设备驱动大体可分为三种:字符设备(characterdevice);块设备(blockdeivce);网络接口设备(networkinterface)。设备类型:2023/1/31设备驱动分类所有能够像字节流一样访问的设备比如文件等在Linux中都通过字符设备驱动程序来实现。在Linux中它们也被映射为文件系统的一个节点,常在/dev目录下。应用程序对于字符设备的每一个I/O操作,都会直接传递给系统内核对应的驱动程序;字符设备驱动程序一般要包含open,close,read,write等几个系统调用。Eg:如串口、触摸屏、并口、虚拟控制台、AD等。

字符设备:2023/1/31设备驱动分类Linux的块设备通常是指可以容纳文件系统的存储设备。与字符设备类似,块设备也是通过文件系统来进行访问,它们之间的区别仅仅在于内核内部管理数据的方式不同。Linux中的块设备包含整数个块,每个块包含2的几次幂的字节。应用程序对于块设备的操作,要经过系统的缓冲区管理,间接传递给驱动程序处理。Eg:诸如磁盘,内存,Flash等。块设备:2023/1/31设备驱动分类

网络接口设备比较复杂,通常它们指的是硬件设备,但有时也可是一个软件设备(如回环接口loopback)。由内核中网络子系统驱动,负责发送和接收数据包,而且它并不需要了解每一项事务是如何映射到实际传送的数据包的。在Linux中采用给网络接口设备分配一个唯一名字的方法来访问该设备。Eg:eth0等。网络接口设备:2023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31Linux下字符型设备管理设备文件的概念来统一对设备的访问接口,在引入设备文件系统(devfs)之前Linux将设备文件放在/dev目录下。设备的命名一般为设备文件名+数字或字母表示的子类,例如/dev/hda1、/dev/hda2、/dev/ttyS0等。在LINUX-2.4/2.6内核中引入了设备文件系统(devfs),所有的设备文件作为一个可以挂装的文件系统,这样就可以被文件系统进行统一管理,从而设备文件就可以挂装到任何需要的地方。命名规则也发生了变化,一般将主设备建立一个目录,再将具体的子设备文件建立在此目录下。Eg:串口1设备为:/dev/tts/0。

设备文件及设备文件系统概念:2023/1/31Linux下字符型设备管理传统方式中的设备管理中,除了设备类型外,内核还需要一对称作主次设备号的参数,才能唯一标识一个设备。主设备号相同的设备使用相同的驱动程序,次设备号用于区分具体设备的实例。

设备操作宏MAJOR()和MINOR()可分别用于获取主次设备号,宏MKDEV()用于将主设备号和次设备号合并为设备号,这些宏定义在include/linux/kdev_t.h

中。主设备号和对应的驱动程序系统会将其记录在/proc/devices里主设备号和次设备号(1/2):2023/1/31Linux下字符型设备管理系统增加一个驱动程序就要赋予它一个主设备号。这一赋值过程在驱动程序的初始化过程中进行:对于字符设备:intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);主设备号和次设备号(2/2):2023/1/31Linux下字符型设备管理[/mnt/yaffs]ls /dev-lcrw------- 1rootroot 5,

1Jan 100:00consolecrw-r----- 1rootroot 1, 4Jan100:00portcrw------- 1rootroot 108, 0Jan100:00pppcrw-rw-rw-1rootroot5, 0Jan100:00ttycrw------- 1rootroot 4, 64Jan100:11ttyS0crw------- 1rootroot 4, 65Jan100:00ttyS1crw-rw-rw-1rootroot1, 5Jan100:00zero…………

查看/dev目录下的设备的主次设备号:2023/1/31Linux下字符型设备管理为该模块建立一个设备节点。命令:mknod/dev/tsc2540其中/dev/ts表示我们的设备名是ts,“c”说明它是字符设备,“254”是主设备号,“0”是次设备号。一旦通过mknod创建了设备文件,它就一直保留下来,除非我们手工删除它。手工设备管理:2023/1/31Linux下字符型设备管理动态分配:初始化时动态分配设备号;在Documentation/devices.txt文件中可以找到已经静态分配给大部分设备的列表由于许多数字已经分配了,为新设备选择一个唯一的号码是很困难的如果调用register_chrdev时的major为零,函数就会选择一个空闲号码并做为返回值返回动态管理(1/2):2023/1/31Linux下字符型设备管理动态分配的主设备号不能保证总是一样的,无法事先创建设备节点可以从/proc/devices读取

cat/proc/devices利用脚本动态创建设备文件节点动态管理(2/2):2023/1/31Linux下字符型设备管理使用设备文件系统--devfs

:2023/1/31Linux下字符型设备管理udev完全在用户态(userspace)工作,利用设备加入或移除时内核所发送的hotplug事件(event)来工作。关于设备的详细信息是由内核输出(export)到位于/sys的sysfs文件系统的。所有的设备命名策略、权限控制和事件处理都是在用户态下完成的。与此相反,devfs是作为内核的一部分工作的。使用设备文件系统--udev

:2023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31Linux驱动编译和加载方式一种是直接编译到内核,当内核启动之后,新的驱动程序随之运行;二是编译为模块,动态加载运行对模块操作需要使用module-utiles:insmod将编译的模块直接插入内核rmmod从内核中卸载模块lsmod显示已安装的模块gcc编译参数:-D__KERNEL__-DMODULE

–I$(KERNELDIR_INCLUDE)在调试的过程中一般使用模块动态加载的方式,它的调试效率较高。当驱动调试完成后,在发行的过程就集成进内核。但编译进内核是某些驱动运行的唯一方法。例如:console驱动,flash驱动和对至少一种文件系统的支持等等。Eg:DA实验:insmodda.o;CAN实验:insmodcan.oLinux驱动编译和加载方式:2023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31Linux内核模块结构介绍#include<linux/module.h>//所有模块都需要的头文件#include<linux/init.h>//init&exit相关宏staticint__inithello_init(void){

printk("Hellomoduleinit\n");

return0;}内核模块的基本框架(1/2):2023/1/31Linux内核模块结构介绍staticvoid__exithello_exit(void)

{

printk("Hellomoduleexit\n");

}

module_init(hello_init);

module_exit(hello_exit);

内核模块的基本框架(2/2):2023/1/31Linux内核模块结构介绍gcc-D__KERNEL__-DMODULE-DLINUX-I/usr/src/linux2.4/include-c-ohello.ohello.cinsmod./hello.o…………rmmodhello

内核模块的编译和加载:2023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31简单Linux字符型设备驱动程序驱动程序在Linux内核中往往是以模块形式出现的。与应用程序的执行过程不同,模块通常只是预先向内核注册自己,当内核需要时响应请求。内核模块的编译和加载:2023/1/31简单Linux字符型设备驱动程序设备驱动程序流程图:insmodrmmodinit_module()clean_module()模块内核设备功能设备注册设备卸载用户调用2023/1/31简单Linux字符型设备驱动程序重要的数据结构—file_operations(1/3):说明:设备驱动程序接口:file_operations数据结构通常所说的设备驱动程序接口是指结构file_operations结构,它定义在include/linux/fs.h中。file_operations结构是整个Linux内核的重要数据结构2023/1/31简单Linux字符型设备驱动程序重要的数据结构—file_operations(2/3):structfile_operations{structmodule*owner;ssize_t(*read)(structfile*,char*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar*,size_t,loff_t*);int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);int(*open)(structinode*,structfile*);int(*release)(structinode*,structfile*);//………………};

2023/1/31简单Linux字符型设备驱动程序重要的数据结构—file_operations(3/3):应用:“标记化”方法为该结构进行初始化:staticstructfile_operationss3c44b0_fops={owner:THIS_MODULE,open:s3c44b0_ts_open,read:s3c44b0_ts_read,release:s3c44b0_ts_release,};2023/1/31简单Linux字符型设备驱动程序重要的数据结构—file:说明:file结构定义在头文件linux/fs.h中。它代表一个打开的文件,由内核在调用open时创建。并传递给在该文件上进行操作的所有函数,直到最后的close函数被调用。在文件的所有实例都关闭时,内核释放这个数据结构。注:与inode的区别,inode表示磁盘文件,而file表示一个打开的文件2023/1/31简单Linux字符型设备驱动程序设备注册:驱动程序模块通过函数register_chrdev来完成向内核注册的。intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);其中unsignedintmajor为主设备号,constchar*name为设备名,structfile_operations*fops为文件操作结构指针。2023/1/31简单Linux字符型设备驱动程序设备卸载:驱动程序模块通过函数unregister_chrdev来完成向内核卸载的。intunregister_chrdev(unsignedintmajor,constchar*name);其中unsignedintmajor为主设备号,constchar*name为设备名。2023/1/31简单Linux字符型设备驱动程序打开设备:驱动程序模块通过函数open来完成打开设备的。提供给驱动程序初始化设备的能力,为后续的操作做准备此外一般会递增使用计数,防止文件关闭前模块被卸载通常情况下,open完成如下工作:递增使用计数检查特定设备错误如果设备是首次打开,则对其进行初始化识别次设备号,如有必要,则修改f_op指针分配并填写filp->private_data中的数据2023/1/31简单Linux字符型设备驱动程序释放设备:驱动程序模块通过函数release来完成释放设备的。与open正好相反释放由open分配的filp->private_data中的数据在最后一次关闭操作时关闭设备使用计数减一2023/1/31简单Linux字符型设备驱动程序读写设备(1/3):read函数将数据从内核拷贝到应用程序空间,write函数则将数据从应用程序空间拷贝到内核。ssize_tread(structfile*filp,char__user*buff,size_tcount,loff_t*offp);ssize_twrite(structfile*filp,char__user*buff,size_tcount,loff_t*offp);其中,filp是文件指针,count是请求传输的数据长度。参数buff是指向用户空间的缓存区,这个缓存区或者保存要写入的数据,或者是一个存放新读入数据的空缓冲区,最后的offp是一个指向“longoffsettype(长偏移量类型)”对象的指针,这个对象指明用户在文件中进行存取操作的位置2023/1/31简单Linux字符型设备驱动程序读写设备(2/3):注:buff为用户空间的地址指针,内核代码不能直接引用其中的内容原因:用户空间的指针可能是无效的,该地址可能根本就无法映射到内核空间用户空间的内存可以被换出,因此可能会出现页面失效的问题从安全角度考虑解决办法:使用内核函数进行数据拷贝2023/1/31简单Linux字符型设备驱动程序解决函数:unsigned

longcopy_to_user(void*to,const

void*from,unsigned

longcount);unsigned

longcopy_from_user(void*to,const

void*from,unsigned

longcount);其中:to表示数据目的缓冲区

from表示数据源缓冲区

count表示数据长度返回值:成功,返回数据长度

失败,返回-EFAULT这两个函数不仅要拷贝数据,还要检查指针有效性读写设备(3/3):2023/1/31简单Linux字符型设备驱动程序ioctl函数:int(*ioctl)(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg);其中,inode和filp对应于应用程序传过来的文件描述符fd,cmd是用户空间传递给驱动程序的命令,arg为附加的命令参数读写以外的I/O操作:2023/1/31简单Linux字符型设备驱动程序printk函数:intprintk(constchar*fmt,…);其中,fmt为日志级别返回值:成功,返回1,失败,返回-1。如:printk(KERN_DEBUG,”HereIam:%s:%i\n”,__FILE__,__LINE__);打印信息:2023/1/31简单Linux字符型设备驱动程序驱动程序的编译、加载及卸载:驱动程序的编译以demo.c为例Makefile的形式命令行的形式[root@RedHatAS~]$gcc-c-D__KERNEL__-DMODULE-I/usr/src/linux-2.4/includedemo.c-odemo.o加载驱动[root@RedHatAS~]$insmoddemo.o卸载驱动[root@RedHatAS~]$rmmoddemo.o2023/1/31简单Linux字符型设备驱动程序驱动程序的编译、加载及卸载说明:依赖关系问题当模块与内核链接时,insmod

会检查模块和当前内核版本是否匹配;每个内核版本都需要特定版本的编译器的支持,高版本的编译器并不适合低版本的内核;2023/1/31简单Linux字符型设备驱动程序驱动程序的测试://test.c#include<stdio.h>#include<fcntl.h>#include<stdlib.h>intmain() { intfd; fd=open("/dev/demo",O_RDWR); if(fd<0) { exit(fd); } //yourcodehere read(fd,buffer,size); write(fd,buffer,size); ...... close(fd);

return0;}2023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31驱动程序与应用程序的区别应用程序一般有一个main函数,从头到尾执行一个任务;驱动程序却不同,它没有main函数,通过使用宏module_init(初始化函数名),将初始化函数加入内核全局初始化函数列表中。通过宏module_exit(退出处理函数名)注册退出处理函数。驱动程序与应用程序的区别(1/2):2023/1/31驱动程序与应用程序的区别应用程序可以和GLIBC库连接,因此可以包含标准的头文件,比如<stdio.h>、<stdlib.h>等,;在驱动程序中是不能使用标准C库的,因此不能调用所有的C库函数,只能调用内核的函数,eg:比如输出打印函数只能使用内核的printk函数,包含的头文件只能是内核的头文件,比如<linux/module.h>。驱动程序与应用程序的区别(2/2):2023/1/31驱动开发简介设备驱动分类Linux下字符型设备管理Linux驱动编译和加载方式Linux内核模块结构介绍简单Linux字符型设备驱动程序驱动程序与应用程序的区别字符型设备驱动demo分析3.6驱动程序原理与开发2023/1/31字符型设备驱动demo分析#include<linux/config.h>#include<linux/module.h>#include<linux/init.h>#include<linux/kernel.h>/*printk()*/#include<linux/fs.h>/*everything...*/#include<linux/errno.h>/*errorcodes*/#include<linux/types.h>/*size_t*/#include<linux/proc_fs.h>#include<linux/fcntl.h>/*O_ACCMODE*/#include<linux/poll.h>/*COPY_TO_USER*/#include<asm/system.h>/*cli(),*_flags*/#defineDEVICE_NAME "demo"#definedemo_MAJOR249#definedemo_MINOR0#defineMAX_BUF_LEN20staticchardrv_buf[20];头文件及变量等定义:2023/1/31字符型设备驱动demo分析static

int__initdemo_init(void) {intresult;SET_MODULE_OWNER(&demo_fops);result=register_chrdev(demo_MAJOR,"demo",&demo_fops);

if(result<0)returnresult; printk(DEVICE_NAME"initialized\n");

return0;}static

void__exitdemo_exit(void) {unregister_chrdev(demo_MAJOR,"demo"); printk(DEVICE_NAME"unloaded\n");}module_init(demo_init);module_exit(demo_

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论