驱动开发实验指导书linux_第1页
驱动开发实验指导书linux_第2页
驱动开发实验指导书linux_第3页
驱动开发实验指导书linux_第4页
驱动开发实验指导书linux_第5页
已阅读5页,还剩200页未读 继续免费阅读

下载本文档

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

文档简介

目录驱动开发 71Linux驱动开发概述 基本概念 7设备驱动的作用 7设备驱动的分类 81.4Linux操作系统与驱动的关系 91.5目录驱动开发 71Linux驱动开发概述 基本概念 7设备驱动的作用 7设备驱动的分类 81.4Linux操作系统与驱动的关系 1.8用户态和内核态 10模块机制 10编写设备驱动程序需要了解的知识 11编写设备驱动程序的注意事项 111.8.1应用程序开发与驱动程序开发的差异 122Linux的内核模块(module) 2.42.5实验目的 12实验内容 12预备知识 12实验设备及工具 13基础知识 132.6实验原理 ..4内核模块概述 13模块机制的优缺点 13内核模块函数 14内核模块编译 142.7实验步骤 171、编写源程序代码 172、编译源码 183、执行程序 18字符设备驱动模型 1933.1 LED驱动开发(IO内存模型) 193.1.1实验目的 ...73.1.8实验内容 19预备知识 19实验设备及工具 20基础知识 20实验原理...73.1.8实验内容 19预备知识 19实验设备及工具 20基础知识 20实验原理 21实验步骤 26实验现象 283.2LED驱动开发(老方法) 28实验目的 28实验内容 28预备知识 28实验设备及工具 28基础知识 29实验原理 30实验步骤 31实验现象 323.3LED驱动开发(新方法) 38实验目的 32实验内容 33预备知识 33实验设备及工具 33基础知识 33实验原理 34实验步骤 35实验现象 363.4PWM驱动开发(misc设备模型) 3..43.4.5实验目的 37实验内容 37预备知识 37实验设备及工具 37基础知识 37实验步骤 44实验结果 44按键中断驱动开发(platform模型) 4...7实验目的 44实验内容 45预备知识实验步骤 44实验结果 44按键中断驱动开发(platform模型) 4...7实验目的 44实验内容 45预备知识 45实验设备及工具 45基础知识 45实验步骤 60实验结果 613.6IO内存管理驱动开发 61是MMU? 61MMU的作用 613.6.3MMU转换地址的61pagetable(页表) 61的linux内核中,页表是如何创建的? 623.7LCD触摸屏读写实验驱动开发(输模型) 6...63.7.8实验目的 65实验内容 65预备知识 65实验设备及工具 65基础知识 65实验步骤 67实验结果 703.8LCD显示实验驱动开发(framebuffer模型) 70...6实验目的 70实验内容 70预备知识 70实验设备及工具 70基础知识 70实验步骤 803.8.7实验结果 803.9设备树 87实验结果 803.9设备树 8...63.9.7实验目的 81实验内容 81预备知识 81实验设备及工具 81基础知识 81实验步骤 100实验现象 1134块设备 114块设备操作 1...64.1.7实验目的 114实验内容 114预备知识 114实验设备及工具 114基础知识 114实验步骤 134块设备驱动总结 1355网络设备 136网络设备驱动移植 1365.1wifi驱动开发 13...6实验目的 136实验内容 136预备知识 136实验设备及工具 136基础知识 137实验步骤 1406其他驱动 143串口读写驱动开发 143实验目的 143实验内容 预备知识 143实验设备及工具 143基础知识 1446.2USB设备加载驱动开发 1566.2.0USB驱动程序概述 15..46.1.5预备知识 143实验设备及工具 143基础知识 1446.2USB设备加载驱动开发 1566.2.0USB驱动程序概述 15...76.2.8实验目的 156实验内容 156预备知识 156实验设备及工具 156基础知识 156实验原理 159实验步骤 1626.3继电器驱动开发 16...66.3.7实验目的 164实验内容 164预备知识 164实验设备及工具 164基础知识 164实验原理 165实验步骤 1656.4温湿度驱动开发 16...6实验目的 166实验内容 166预备知识 166实验设备及工具 166基础知识 166实验步骤 1706.5直流电机驱动开发 实验目的 178实验内容 178预备知识 实验设备及工具 178基础知识 178实验步骤 1826.6步进电机驱动开发 18..56.6.6实验目的 实验设备及工具 178基础知识 178实验步骤 1826.6步进电机驱动开发 18..56.6.6实验目的 182实验内容 182预备知识 182实验设备及工具 183基础知识 1836.10.7实验原理 1836.6.8实验步骤 186气体传感器驱动开发 18..76.7.8实验目的 187实验内容 187预备知识 187实验设备及工具 187基础知识 187实验步骤 1916.8RFID驱动开发 实验目的 192实验内容 192预备知识 1926.10.4实验设备及工具 基础知识 192实验原理 200实验步骤 2056.9其它驱动见粤嵌提供的驱动文件夹 205驱动开发1Linux驱动开发概述设备驱动程序是计算机硬件与应用程序的接口,是软件系统与硬件系统沟通的桥梁。如果没有设备驱动程序,那么硬件设备就只是一对废铁,没有什么功能。1.1基本概念设备驱动程序(DeviceDriver),简称驱动程序(Driver)。它是一个计算机软件与硬件交互的程序。这种程序建立了一个硬件与硬件,会硬件与软件形成连接,这样的连接是的硬件设备之间的成为可能。依据不同的计算机架构与操作系统差异平台,驱动程序可以是8位、16位(驱动开发1Linux驱动开发概述设备驱动程序是计算机硬件与应用程序的接口,是软件系统与硬件系统沟通的桥梁。如果没有设备驱动程序,那么硬件设备就只是一对废铁,没有什么功能。1.1基本概念设备驱动程序(DeviceDriver),简称驱动程序(Driver)。它是一个计算机软件与硬件交互的程序。这种程序建立了一个硬件与硬件,会硬件与软件形成连接,这样的连接是的硬件设备之间的成为可能。依据不同的计算机架构与操作系统差异平台,驱动程序可以是8位、16位(16b)、32位(32b),64位(64b),这是为了windows32位64linuxwindows64位驱动。1.2设备驱动的作用设备驱动程序是一种可以使计算机与设备进行通信的特殊程序,可以说相硬件设备的工作。假如某设备的驱动程序未能正确安装,是不能正常工作。正因为这个,驱动程序在系统中的地位十分重要。一般操作系统安装完毕后,首要的便是安装硬件设备的驱动程序。、摄像头、Modem等就需要安装驱动程序,另外,不同版本的操作系统对IDE支持也是不同的。一般情况下,版本越高所支持的硬件设备也越多。设备驱动程序用来将硬件本身的功能高速操作系统,完成硬件设备电子信号与操作系统及软件的高级编程语言之间的相互翻译。当操作系统需要使用某个硬件时,例如让声卡音乐,它会先相应指令到声卡驱动程序。声卡驱动程序接收到后,马上将其翻译成声卡才能听懂的电子信号命令,从而让声卡音乐。所以简单地说,驱动程序是提供硬件到操作系统的一个接口,并且协调二者之间的关系。而因为驱动程序有如此重要的作用,所以人们都称“驱动程序是硬件的”、“硬件的主宰”,同时驱动程序也被形象地称为“硬件和系统之间的桥梁”。1.3设备驱动的分类计算机系统的主要硬件有CPU、器和外部设备组成,驱动程序的对象一般是器和外部设备。随着制造工艺的提高,为了节约成本,通常将嵌入到CPU内部。所以现在的驱动程序应该支持CPU中的嵌入 大类,分别是字符设备、块设备、网络设备。1、字符设备字符设备是指那些能一个字节一个字节数据的设备,如LED卡音乐。所以简单地说,驱动程序是提供硬件到操作系统的一个接口,并且协调二者之间的关系。而因为驱动程序有如此重要的作用,所以人们都称“驱动程序是硬件的”、“硬件的主宰”,同时驱动程序也被形象地称为“硬件和系统之间的桥梁”。1.3设备驱动的分类计算机系统的主要硬件有CPU、器和外部设备组成,驱动程序的对象一般是器和外部设备。随着制造工艺的提高,为了节约成本,通常将嵌入到CPU内部。所以现在的驱动程序应该支持CPU中的嵌入 大类,分别是字符设备、块设备、网络设备。1、字符设备字符设备是指那些能一个字节一个字节数据的设备,如LED灯,键盘、鼠标等。字符设备一般需要在驱动层实现open()、close()、read()、、ioctl()等函数。这些函数最终将被文件中的相关函数调用。内核为字符设备对应一个文件,如字符设备文件/dev/console。对字符设备的操作可以通过字符设备文件/dev/console来进行。这些字符设备文件与普通文件没有太大的差别,差别之处是字符设备一般不支持寻址,但特殊情况下,有很多字符设备也是支持寻址的。2、块设备Linux系统中,进行块设备读写时,每次只能传输一个或多个块。Linux可以让应用程序像字符设备一样块块设备能完成一个字节。所以块设备从本质上更像一个字符设备的扩展,的工作,例如传输一块数据。Linux内核中,与字符驱动相比,块设备驱动程序具API接口。3、网络设备计算机连接到互联网需要一个网络设备,网络设备主要负责主机之间的数Linux操作系统中是一种非常特殊的设备,其没有实read()、write()、ioctl()等函数。网络设备实现了一种套接字接口,任何网络数据传输都可以通过套接字来完成。1.4Linux操作系统与驱动的关系Linux操作系统与设备驱动之间的关系1.1所示。用户空间包括应用系统调用两层。应用程序一般依赖于库函数库,而函数库是调用来编写的,所以应用程序间接地一俩调用。系统调用层是内和空间和用户空间的接口层。通过这个系统调用层,应用程序不需要直接内核空间的程序,增加了内核的安。同时,应用程序也不能硬件设备,只能通过系统调用层来硬件设备。如果应用程序需要硬件设备,那么应用程序先系统调用层,调用层去性,也内核层的设备驱动程序。这样的设的安全。计,保证了各个模块的功能Linux内核中,包含很多实现具体功能的模块。这些模块包括文件系统、网络协议栈、设备驱动、内核调度、内存管理、进程,都属于系统内核空间。最底层是硬件层,这一层是实际硬件设备的抽象。设备驱动程序的功能就在没有操作系统的情况下。如果只需要实现一些建档的设备的操作,那么可以不适用操作系统。如果系统完成的功能比较复杂,则往往需要操作系统来帮忙。大多数操作系统都具有多任务的特性,所以对于设备驱动read()、write()、ioctl()等函数。网络设备实现了一种套接字接口,任何网络数据传输都可以通过套接字来完成。1.4Linux操作系统与驱动的关系Linux操作系统与设备驱动之间的关系1.1所示。用户空间包括应用系统调用两层。应用程序一般依赖于库函数库,而函数库是调用来编写的,所以应用程序间接地一俩调用。系统调用层是内和空间和用户空间的接口层。通过这个系统调用层,应用程序不需要直接内核空间的程序,增加了内核的安。同时,应用程序也不能硬件设备,只能通过系统调用层来硬件设备。如果应用程序需要硬件设备,那么应用程序先系统调用层,调用层去性,也内核层的设备驱动程序。这样的设的安全。计,保证了各个模块的功能Linux内核中,包含很多实现具体功能的模块。这些模块包括文件系统、网络协议栈、设备驱动、内核调度、内存管理、进程,都属于系统内核空间。最底层是硬件层,这一层是实际硬件设备的抽象。设备驱动程序的功能就在没有操作系统的情况下。如果只需要实现一些建档的设备的操作,那么可以不适用操作系统。如果系统完成的功能比较复杂,则往往需要操作系统来帮忙。大多数操作系统都具有多任务的特性,所以对于设备驱动说,应该充分考虑并发、阻塞等问题。1.1设备驱动程序与操作系统的关系1.5用户态和内核态Linux操作系统分为用户态和内核态。用户态处理器上层的软件工作。内交互,所以工作在内核态。Linux操作系统分为两个状态的主要是,为应用程序提供一个统一的计算机硬件抽象。工作在用户态的应用程序完全可以不考虑底层的硬件操作,这些操作有内核态完成。这些内核态程序大部分是设备驱动程序。一个好的操作系统的驱动程序对用户态应用程序应该是透明的,也就是说,应用程序可以在不了解硬件工作原理的情况下,很好地操作硬件设备,同时使硬状态。Linux操作系统很好的做到了这一点。工作在用户态的应用程序不能因为一些错误而破坏内核态的程序。现代处理已经充分考虑了这个问题。处理器提供了一些指令,分为指令和驱动指令。指令只有在内核态下才能使用;普通指令既可以在内核态使用,也可用户态和内核态是可以相互转换的。每当应用程序件中断挂起时,Linux1.1设备驱动程序与操作系统的关系1.5用户态和内核态Linux操作系统分为用户态和内核态。用户态处理器上层的软件工作。内交互,所以工作在内核态。Linux操作系统分为两个状态的主要是,为应用程序提供一个统一的计算机硬件抽象。工作在用户态的应用程序完全可以不考虑底层的硬件操作,这些操作有内核态完成。这些内核态程序大部分是设备驱动程序。一个好的操作系统的驱动程序对用户态应用程序应该是透明的,也就是说,应用程序可以在不了解硬件工作原理的情况下,很好地操作硬件设备,同时使硬状态。Linux操作系统很好的做到了这一点。工作在用户态的应用程序不能因为一些错误而破坏内核态的程序。现代处理已经充分考虑了这个问题。处理器提供了一些指令,分为指令和驱动指令。指令只有在内核态下才能使用;普通指令既可以在内核态使用,也可用户态和内核态是可以相互转换的。每当应用程序件中断挂起时,Linux操作系统都会从用户态切到内核态。调用或者被硬调用完成或1.6模块机制Linux一个很好的特性。这个特性使内核可以很容易地扩大或者缩小,一方面扩大内核可以增加内核的功能,另一方面缩小内核可以减小内核的大小。Linux内核支持很多种模块,驱动程序就是其中最重要的一种,甚至人间insmodrmmod命令将一个未使用的模块从内核中删除。试图删除一个正在使用的模块,见识不的。模块在内核启动时装载称为静态装载,在内核已经运行时装载称为动态装载。模块可以扩充内核所期望的任何功能,但通常用于实现设备驱动程序。一个模块的最基本框架代码如下:1.7编写设备驱动程序需要了解的知识Linux操作系统有三、四百万行代码,其中驱动程序代码就有四分之三左者需要掌握如下一些知识:1、驱动开发应该有良好的C语言基础,并能灵活地应用C语言的结LinuxCGNUCGNU1.7编写设备驱动程序需要了解的知识Linux操作系统有三、四百万行代码,其中驱动程序代码就有四分之三左者需要掌握如下一些知识:1、驱动开发应该有良好的C语言基础,并能灵活地应用C语言的结LinuxCGNUCGNUCC语言也应该所了解。2、驱动开发应该具有良好的硬件基础。虽然不要求驱动开发具有设计电路的原理,但也应该对手册上描述的接口设备有清楚的认识。常用、Flash、UART、IIC、USB等。3、驱动开发 如一些重要的数据结构和函数等。4、驱动开发应该有人文物程序设计的能力,同时驱动中也会使用大量的自旋锁、互斥锁、信号量等。1.8编写设备驱动程序的注意事项中。下面给出编写驱动程序的一些注意事项,希望引起读者注意。#include<linux/kernel.h>#include<linux/module.h>#include<linux/init.h>intinit {/*模块加载时的初始化工作*/return0;}voidexit _exit(void){/*模块卸载时的销毁工作*/}module_init( _init);/*指定模块的初始化函数的宏*/module_exit( _exit);/*指定模块的卸载函数的宏*/1.8.1应用程序开发与驱动程序开发的差异上的程序开发一般分为两种,一种是内核及驱动程序开发,另一Linux的两种状态,分别是内核态和层的软件工作。驱动程序与底层的硬件交互,所以工作在内核态。重要的差异包括以下几点:1、内核及驱动程序开发时不能CC库是使用内核中的系统调用来实现的,而且是在用户空间实现的。1.8.1应用程序开发与驱动程序开发的差异上的程序开发一般分为两种,一种是内核及驱动程序开发,另一Linux的两种状态,分别是内核态和层的软件工作。驱动程序与底层的硬件交互,所以工作在内核态。重要的差异包括以下几点:1、内核及驱动程序开发时不能CC库是使用内核中的系统调用来实现的,而且是在用户空间实现的。GNUCLinux操作系统从一开码做大量的修改。刻注意同步和并发。4、内核只有一个很小的定长堆栈。开发时必须时5、内核及驱动程序开发时缺乏像用户空间那样的内存保护机制。6、内核及驱动程序开发时浮点数很难使用,应该使用整型数。是不兼容的。2Linux的内核模块(module)2.1实验目的了解内核模块的概念。掌握基本的驱动程序设计。2.2实验内容文件。并调试驱动模块。2.3预备知识C语言基础知识。Linux下常用vim编辑器的使用。程序调试的基础知识和方法。ARM应用程序的基本框架结构2.4实验设备及工具硬件:GEC6818开发平台软件:PC操作系统Ubuntu14.04、、arm-linu2.5基础知识硬件原理:无。2.6实验原理2.6.1内核模块概述LinuxC语言基础知识。Linux下常用vim编辑器的使用。程序调试的基础知识和方法。ARM应用程序的基本框架结构2.4实验设备及工具硬件:GEC6818开发平台软件:PC操作系统Ubuntu14.04、、arm-linu2.5基础知识硬件原理:无。2.6实验原理2.6.1内核模块概述Linux内核是整体式结构,各个子系统紧密,作为一个大程序在内核空间运行。太多的设备驱动内核功能集成在内核中,内核过于庞大。如何解决?Linux内核引入内核模块制。通过动态加载内核模块,使得在运行过扩展内核的功能。不需要的时候。卸载该内核模块。什么是内核模块?内核模块式一种没有经过,不能运行的目标文件,是在内核空间中运行的程序。经过装载到内核里面成为内核的一部分,可以内核的公用符)内核模块可以让操作系统内核在需要是载入和执行,在不需要时由操作系统卸载。它们扩展了操作系统讷河的功能却不需要重新启动系的内核镜像来加入新的功能。还意味着一个臃肿的内核。内核模块是如何被调入内核工作的?当操作系统内核需要的扩展功能不存在时,内核模块管理守护进程kmod执行modprobe去加载内核模块。modprobe遍历文件/lib/modules/version/modules.dep来是否有其它内核模块需要在该模块加载前被加载。最后modprobe调用insmod先加载被依赖的模块,然后加载该被内核要求的模块。2.6.2模块机制的优缺点模块机制的优点:减小内核映像,增加系统灵活性;节省开发时间;修改内核,不必重新编译整个内核。模块的目标代码一旦被链入内核,作用和静态的内核目标代码完全等价。模块机制的缺点:对系统性能有一定损失;使用不当时会导致系统。2.6.3内核模块函数module_init(),在模块加载到内核时被调用。module_init()要么向内核某个内核函数。它可以处理的事物,要么用的代码替代module_exit()cleanup_module(),在内核模块被卸载时被调用,干一些收尾module_init()做的事,保证(linux/module.h)printk(函数:printk内核中定义并且对模块可用,为内核提供日志功能,内核信息或用来给出警告。与标准C模块机制的优点:减小内核映像,增加系统灵活性;节省开发时间;修改内核,不必重新编译整个内核。模块的目标代码一旦被链入内核,作用和静态的内核目标代码完全等价。模块机制的缺点:对系统性能有一定损失;使用不当时会导致系统。2.6.3内核模块函数module_init(),在模块加载到内核时被调用。module_init()要么向内核某个内核函数。它可以处理的事物,要么用的代码替代module_exit()cleanup_module(),在内核模块被卸载时被调用,干一些收尾module_init()做的事,保证(linux/module.h)printk(函数:printk内核中定义并且对模块可用,为内核提供日志功能,内核信息或用来给出警告。与标准C库函数printf的行为相似。每个printk()都会带一个优先级。内核总共定义了八个优先级的宏,DEFAULT_MESSAGE_LOGLEVEL/var/log/messages,可直接查看,或者用命令X-windowsinsmod一个模块,日志信息只会件中,而不在终端打印。dmesg查在日志文2.6.4内核模块编译顺利编译并且加载第一个“helloworld”模块有时就会比较Linux。强烈建议的版本经常给内核打一些非标准的补丁,这种情况会导致一些问题的发生。保证系统Documentation/Changes列出了需要的工具版本。用错误的工具版本建立一个内核(包括模块),可能导致一些奇怪复杂的问题。内核模块编译:为3.4.39版本内核构造模块,首先需要有配置并构建好的3.4.39内核源代码树。而且最好运行和模块对应的内核。3.4.39内核的模块要和内核源代码树中的目标文件连接。3.4.39kbuild,使得内核Hello.cMakefile文件:obj-m+=hello.ohello.ohello.ko。执行以下命令编译模块:建立,kbuild从该目标文件建立内改变目录到用-C选项提供的内核源码目录,在那里找到内核的顶层makefileHello.cMakefile文件:obj-m+=hello.ohello.ohello.ko。执行以下命令编译模块:建立,kbuild从该目标文件建立内改变目录到用-C选项提供的内核源码目录,在那里找到内核的顶层makefile。M= 选项使makefile在试图建立模块目标前,回到模块源码目录。3.4.39内核引入新的内核模块命名规范:内核模块使用.ko的文件后缀(代.o后缀),从而内核模块区别于普通的目标文件。多个文件的内核模块:Makefile会帮我们完成编译和连接的工作。start.cstop.c,则;Makefile这样写:obj-m+=startstop.ostartstop-objs:=start.ostop.o跟单个文件模块的编译方式一样,内核编译系统会将所有的目标文件连接内核模块是如何开始和结束的:main()module_init()指定的函数调用开始。这就是内核模块的函数。初始化函数的任务,为以后内核调用模块函数做准备。模块的展功能。函数则在模块别卸载之前调用,撤销“初始化函数”的扩模块可调用的函数:应用程序可以调用它没有定义的函数(函数库中的函数)。因为在连接阶。内核模块是连接到内核,它能够调用的函数和变量是内核公开的函数和变量,没有库来连接。可以在内核模块中使用的函数只能来自内核本身。make-C/usr/src/linux-`uname-r`M=$PWDmodules管理内核模块令lsmod列出已经挂载的内核模块smod是列出目前系统中已加载的模块的名称及大小等less/proc/modules查看模块一样。modinfo查看模块信息modinfo可以查看模块的信息,通过查看模块信息来判定这个模块的用途。modinfo模块名管理内核模块令modprobemodprobe同时挂载。modprobe管理内核模块令lsmod列出已经挂载的内核模块smod是列出目前系统中已加载的模块的名称及大小等less/proc/modules查看模块一样。modinfo查看模块信息modinfo可以查看模块的信息,通过查看模块信息来判定这个模块的用途。modinfo模块名管理内核模块令modprobemodprobe同时挂载。modprobe挂载新模块以及新模块相依赖的模块模块名,在挂载该内核模块的同时,这个模块所依赖的模块也被manmodprobe。例如:modprobel是列出内核中所有的模块,包括已挂载和未挂载的,的模块列表就位于/lib/modules/‘uname-r’目录中。rmmod移除已挂载模块用法:rmmod模块名(不带后缀)等同于:modprobe-r模块名insmod挂载模块insmod需要给出模块所在目录的绝对路径,以及要带有模块文件名后缀(.o或.ko)insmod **.ko功能上没有modprobe强。depmod创建模块依赖关系的列表Linux版所用的内核是2.6x版本,是自动解决依赖关系。depmod-a为所有列在/etc/modprobe.conf或/etc/modules.conf 所有模块创建依赖关系,并且写入到modules.dep文件depmod–e列出已挂载但不可用的模块。注意事项使用insmod./hello.ko命令加载该模块。/proc/modules被加载的内核模块。rmmodhello卸载模块module_init()返回值非零,重新编译再加载,观察结果发生了什么变化?非0返回值表示初始化内核模块失败,模块不能加载。Linux2.4之后,可以为模块的“初始化”和“卸载”函数起init_module()cleanup_module()的名字。rmmodhello卸载模块module_init()返回值非零,重新编译再加载,观察结果发生了什么变化?非0返回值表示初始化内核模块失败,模块不能加载。Linux2.4之后,可以为模块的“初始化”和“卸载”函数起init_module()cleanup_module()的名字。module_init()module_exit()linux/init.h中定义。module_init(hello_2_init);module_exit(hello_2_exit);函数必须在宏的使用前定义,否则编译会报错。initexit宏init的使用会在初始化如果该模块被编译进内核,宏exit将忽略“收尾”的函数。linux/init.h定义,用来内核占用的内存。例如启动时所占用空间时的打印信息。这些函数2.7实验步骤1、编写源程序代码#include<linux/kernel.h>#include<linux/module.h>staticintinitGEC6818_hello_module_init(void)//初始化{printk(“<0>”"Hello,GEC6818moduleisinstalled!\n");return0;}staticvoidexitGEC6818_hello_module_cleanup(void)//卸载{printk(“<0>”"Good-bye,GEC6818modulewasremoved!\n");}makefile文件2、编译源码hello.cmakefilemakefile文件2、编译源码hello.cmakefilemake命令,即可生成目标文件hello.ko。如:在ubuntu主机的终端输入:3、执行程序hello.ko6818板子的/tmp/下,6818arm板子的终端输入:mkdir/home/gec/hello_test/cd/home/gec/hello_test/makeINSTALLDIR=/home/zr/nfs/driver/dirverifneq($(KERNELRELEASE),)obj-m:=Hello.oelseKERNELDIR:=/home/zr/kernel/6818/kernel4.8/bin/arm-eabi-PWD:=$(shellpwd)default:$(MAKE)ARCH=arm PILE=$( PILE)-C$(KERNELDIR)M=$(PWD)modulesclean:rm-rf*.o*.order.*.cmd*.ko*.mod.c*.symversendifinstall:Hello.komkdir-p$(INSTALLDIR)cp--target-dir=$(INSTALLDIR)Hello.komodule_init(GEC6818_hello_module_init);module_exit(GEC6818_hello_module_cleanup);MODULE_LICENSE("GPL");注意事项:若在向内核加入模块时发现insmod:errorinserting'hello.ko':-1Invalidmoduleformat与当前系统的内核版本是否一致。3 字符设备驱动模型3.1 LED驱动开发(IO注意事项:若在向内核加入模块时发现insmod:errorinserting'hello.ko':-1Invalidmoduleformat与当前系统的内核版本是否一致。3 字符设备驱动模型3.1 LED驱动开发(IO内存模型)3.1.1实验目的1、掌握基本的字符设备的驱动程序设计。2、掌握基本的文件操作。3、掌握在操作系统下对普通IO端口的内存使用方法。3.1.2实验内容1S5P6818的2、编写LED应用程序。Makefile文件。,熟悉GPIO端口的原理。4、并调试LED跑马灯应用程序。3.1.3预备知识1、C语言基础知识。vim编辑器的使用。3、程序调试的基础知识和方法。insmodhello.ko显示:Hello,GEC6818moduleisinstalled!lsmod|grephello显示:hello 605 0rmmodhello显示:Good-bye,GEC6818modulewasremoved!4、ARM应用程序的基本架构。3.1.4实验设备及工具1、硬件:GEC6818开发平台。Ubuntu14.04、、arm-linu叉开发环境。3.1.5基础知识4、ARM应用程序的基本架构。3.1.4实验设备及工具1、硬件:GEC6818开发平台。Ubuntu14.04、、arm-linu叉开发环境。3.1.5基础知识1、硬件原理3-1所示:图3-1GEC6818LED灯的GPIOE13,GPIOC17,GPIOC7GPIO管脚,让管脚为输出端口,实现亮灭。LED灯的2、寄存器原理设置输出电平:设置为输出模式:3.1.6实验原理1、IOIO端口IO内存(统一编址)我们外设的地址和内存的地址是统一编址的,例如:arm平台我们设置为输出模式:3.1.6实验原理1、IOIO端口IO内存(统一编址)我们外设的地址和内存的地址是统一编址的,例如:arm平台我们SFR与内存是同样的方法。平台:如:ARM、powerpc、MIPS[root@GEC6818~]#cat/proc/iomem40000000-7fffffff:SystemRAM40008000-40a5418f:Kernelcode40a94000-40d0e407:Kerneldatac0000000-c0000fff:pl08xdmac.0c0000000-c0000fff:pl08xdmacc0001000-c0001fffc0001000-c0001fffc0019000-c00193ffc0019000-c00193ffc0030000-c00300ffc0040000-c0050fffc0040000-c0050fffc0001000-c0001fffc0001000-c0001fffc0019000-c00193ffc0019000-c00193ffc0030000-c00300ffc0040000-c0050fffc0040000-c0050fffc0053000-c00533ffc0053000-c00533ffc0060000-c0061fffc0060000-c0061fffc0062000-c0062fffc0068000-c0068fffc0069000-c0069fffc006d000-c006d040c0070000-c0070100c0071000-c0071200c0072000-c0072100c0073000-c0073100c0074000-c0074100c0075000-c0075100c0076000-c0076100c0077000-c0077100c0078000-c0079100c007a000-c007b100c007c000-c007d100c007e000-c007f100c00a0000-c00a0040c00a1000-c00a1040c00a2000-c00a2040c00a3000-c00a3040c00a5000-c00a5fffc00a5000-c00a5fffc00a6000-c00a6fffc00a6000-c00a6fff:::::::::::::::::::::::::::::::::::pl08xdmac.1pl08xdmacnxp-wdtnxp-wdtnxp-ehcidwc_otgdwc_otgnxp-adcnxp-adcstmmacethstmmacethdw_mmc.0dw_mmc.1dw_mmc.2nx Vr_GPVr_L2Vr_PMUVr_GP_MMUVr_PP0_MMUVr_PP1_MMUVr_PP2_MMUVr_PP3_MMUVr_PP0Vr_PP1Vr_PP2Vr_PP3nxnxnxnxrt.1rt.0rt.2rt.3s3c2440-i2c.1s3c2440-i2cs3c2440-i2c.2s3c2440-i2c[root@GEC6818~]#cat/proc/ioports00000000-00000020:00000000-00000020nxp-gpio.4:nxp-gpio.300000000-00000020:nxp-gpio.200000000-00000020:nxp-gpio.100000000-00000020:nxp-gpio.000000000-00000006:nxp-gpio.5[root@GEC6818~]#2、IO端口(IO编址)外设是没有地址,外设与内存并不在同一地址空间内,我们使用端外设。去3、在linux中,IO内存的使用思路:驱动安装>申请IO内存 物理地址的>得到虚拟地址>虚外设硬件解除地址3.1IO2、IO端口(IO编址)外设是没有地址,外设与内存并不在同一地址空间内,我们使用端外设。去3、在linux中,IO内存的使用思路:驱动安装>申请IO内存 物理地址的>得到虚拟地址>虚外设硬件解除地址3.1IO内存的>IO内存参数说明:resource_size_tstart:IO内存的开始地址,该地址是一个物理地址resource_size_tn:IO内存constchar*name:IO内存返回值:structresource*:的大小的名字3.2、IO内存3.3、IO内存(物理地址-->虚拟地址)voidiomem*ioremap(unsignedlongphys_addr,size_tsize)/*releaseapreviously resourceregion@start:resourcestartaddress@n:resourceregionsize*/voidrelease_mem_region(resource_size_tstart,resource_size_tn)/*createanewbusyresourceregion@start:resourcestartaddress@n:resourceregionsize@name:reservingcaller'sIDstring*/structresource*request_mem_region(resource_size_tstart,resource_size_tn,constchar*name)参数说明:unsignedlongphys_addr:准备的物理内存区开始地址size_tsize:准备3.4IO内存的物理内存区大小。注意:在linux系统中,是不能直接物理地址的,只能虚拟地址。如果要物理地址,需要通过IO内存得到该物理地址的虚拟地址,再虚拟地址。4、IO内存参数说明:unsignedlongphys_addr:准备的物理内存区开始地址size_tsize:准备3.4IO内存的物理内存区大小。注意:在linux系统中,是不能直接物理地址的,只能虚拟地址。如果要物理地址,需要通过IO内存得到该物理地址的虚拟地址,再虚拟地址。4、IO内存外设(GPIO)的方ED灯的驱动)4.1、IO内存的申请GPIOE13_LED=request_mem_region(GPIOEOUT_PA,8,"LED_IO");#include<linux/module.h>#include<linux/kernel.h>#include<linux/cdev.h>#include<linux/uaccess.h>#include<linux/fs.h>#include<linux/ioport.h>#include<linux/io.h>#include<linux/ioctl.h>#defineGPIOEOUT_PA 0xC001E000 外设的物理地址#defineBUF_SIZE 256structcdevchrdev_test;dev_tndev;intTestMajor=0; 备号intTestMinor=0; //此设备号chardrv_name[]="chrtest";charkbuf[BUF_SIZE];charwbuf[BUF_SIZE];unsignedint*GPIOEOUT_VA;//0xC001E000unsignedint*GPIOEOUTENB_VA;//0xC001E004structresource*GPIOE13_LED;iounmap(volatilevoidiomem*addr)4.2、IO内存的动态4.3、物理地址的虚拟地址4.4、虚拟地址。进而外设GPIOE13配置成输出2)014.5、IO内存的4.6、IO内存的解除4.74.2、IO内存的动态4.3、物理地址的虚拟地址4.4、虚拟地址。进而外设GPIOE13配置成输出2)014.5、IO内存的4.6、IO内存的解除4.7、应用程序设计#include<stdio.h>#include<stdlib.h>#include<unistd.h>iounmap(GPIOEOUT_PA);release_mem_region(GPIOEOUT_PA,8);staticlongtest_ioctl(structfile*file,unsignedintcmd,unsignedintargs){switch(cmd){case0:*GPIOEOUT_VA=(0<<13);printk("<0>""cmd=0,argsisnotquest\n");break;case1:*GPIOEOUT_VA=(1<<13);printk("<0>""cmd=1,argsisnotquest\n");break;default:printk("<0>""commandiserror!\n");break;}return0;}*GPIOEOUTENB_VA(113); //设置为输出模式GPIOEOUTENB_VA=GPIOEOUT_VA+1;GPIOEOUT_VA=(unsignedint*)ioremap(GPIOEOUT_PA,8);3.1.7实验步骤1PC机中,创建两个文件夹,分别为driver和3.1.7实验步骤1PC机中,创建两个文件夹,分别为driver和test2PCdriverled_drv.cMakefile两个文件#touchled_io.cMakefiel#mkdirdrivertest#include<sys/ioctl.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>intmain(void){intfd,ret;fd=open("/dev/gec_led",O_RDWR);if(fd<0){perror("open:");return-1;}while(1){ret=ioctl(fd,1,1);//LEDOFFif(ret<0){perror("ioctl:");return-1;}sleep(1);ret=ioctl(fd,0,1);//LEDOFFif(ret<0){perror("ioctl:");return-1;}sleep(1);}close(fd);return0;}3_1_led_iodriver中的文件编写Makefile文件。3PC机中的driver目录的终端中,编译文件生成led_io.ko文件4PC3_1_led_iodriver中的文件编写Makefile文件。3PC机中的driver目录的终端中,编译文件生成led_io.ko文件4PCtestled_test.cMakefile两个文件1-led_iotest中的文件编写Makefile文件。5PCtest目录的终端中,编译文件生成led_test文件6、在arm板子的终端中加载驱动加载驱动之前需要先卸载led预装的驱动。此时,我们可以在/proc/devices找到我们申请的主设备号和设备名命令如下:结果显示:7、在arm板子中创建设备文件的节点命令如下:mknod/dev/gec_ledc2430命令解释:mknod/dev/gec_led243chrtestcat/proc/deviceslsmod ledrmmodled ledinsmodled_io.ko //加载我们编译的驱动#maketouchled_iotest.cMakefile#make8、在arm板子中执行程序3.1.8实验现象开发板上的一个LED等在闪烁。3.2LED驱动开发(老方法)3.2.1实验目的1、掌握基本的字符设备的驱动程序设计(老方法)。2、掌握基本的文件操作。3、掌握在操作系统下对普通IO端口的设计。3.2.2实验内容18、在arm板子中执行程序3.1.8实验现象开发板上的一个LED等在闪烁。3.2LED驱动开发(老方法)3.2.1实验目的1、掌握基本的字符设备的驱动程序设计(老方法)。2、掌握基本的文件操作。3、掌握在操作系统下对普通IO端口的设计。3.2.2实验内容1S5P6818的2、编写LED应用程序。Makefile文件。,熟悉GPIO端口的原理。4、并调试LED跑马灯应用程序。3.2.3预备知识1、C语言基础知识。vim编辑器的使用。3、程序调试的基础知识和方法。4、ARM应用程序的基本架构。3.2.4实验设备及工具1、硬件:GEC6818开发平台Ubuntu14.04、、arm-linu叉开发环境。./led_iotestc //表示字符设备243 //刚刚我们查看到的主设备号0 2553.2.5基础知识1、硬件原理3-2所示:3-2GEC6818LED灯的GPIOE13,3.2.5基础知识1、硬件原理3-2所示:3-2GEC6818LED灯的GPIOE13,GPIOC17,GPIOC7GPIO管脚,让管脚为输出端口,实现亮灭。LED灯的2、寄存器原理设置输出电平:设置为输出模式:3.2.6实验原理1、 字符设备参数说明:intmajormajor=0,系统会自动分配一个主设备major!=0,静态constchar*name主设备号。设备名称conststructfile_operations设置为输出模式:3.2.6实验原理1、 字符设备参数说明:intmajormajor=0,系统会自动分配一个主设备major!=0,静态constchar*name主设备号。设备名称conststructfile_operations*fops文件操作集。返回值:0失败,返回一个负数的错误码将设备号申请、字符设备的初始化、字符设备的2、注销字符设备使用一个函数实现。register_chrdev族函数+创建设备类、文件的函数:这种方法是2.4版本流行的旧方法。优点是简单;缺点是无法4、register_chrdev族函数是形成驱动设备的设备号。。register_chrdev的作用是申请并一个设备号、构建一个字符设备体、向内核此字符设备。majormajor参数设(这种做法比较可靠、方便)。register_chrdevstaticinlinevoidunregister_chrdev(unsignedintmajor,constchar*name)staticinlineintregister_chrdev(unsignedintmajor,constchar*name,conststructfile_operations*fops)unregister_chrdev注销函数,注销函数需要主设备号来作为参数。unregister_chrdev函数,与这里的register_chrdev对应,只不过负责的是注销。udev(mdev)来创建一个位于/dev的设备文件。这一unregister_chrdev注销函数,注销函数需要主设备号来作为参数。unregister_chrdev函数,与这里的register_chrdev对应,只不过负责的是注销。udev(mdev)来创建一个位于/dev的设备文件。这一APPAPI操作设备文件file_operations内的函数)class_create先实例化新建device_create正式创建设备文件3.2.7实验步骤1PC机中,创建两个文件夹,分别为driver和test2PCdriverled_old.cMakefile两个文件3_2_led_olddriver中的文件编写Makefile文件。3PC机中的driver目录的终端中,编译文件生成led_old.ko文件4PCtestled_oldtest.cMakefile两个文件1-led_iotest中的文件编写Makefile文件。5PCtest目录的终端中,编译文件生成led_test文件6、在arm板子的终端中加载驱动加载驱动之前需要先卸载led预装的驱动。#maketouchled_oldtest.cMakefile#make#touchled_old.cMakefiel#mkdirdrivertest此时,我们可以在/proc/devices找到我们申请的主设备号和设备名命令如下:结果显示:7、在arm板子中创建设备文件的节点命令如下:8、在arm板子中执行程序3.2.8实验现象开发板上的一个LED此时,我们可以在/proc/devices找到我们申请的主设备号和设备名命令如下:结果显示:7、在arm板子中创建设备文件的节点命令如下:8、在arm板子中执行程序3.2.8实验现象开发板上的一个LED等在闪烁。3.3 LED驱动开发(新方法)3.3.1实验目的1、掌握基本的字符设备的驱动程序设计(新方法)。2、掌握基本的文件操作。3、掌握在操作系统下对普通IO端口的设计。./led_oldtestmknod/dev/gec_ledc2430命令解释:mknod/dev/gec_ledc //表示字符设备243 //刚刚我们查看到的主设备号0 255243chrtestcat/proc/deviceslsmod ledrmmodled ledinsmodled_old.ko //加载我们编译的驱动3.3.2实验内容1S5P6818的2、编写LED应用程序。Makefile文件。,熟悉GPIO端口的原理。4、并调试LED跑马灯应用程序。.2实验内容1S5P6818的2、编写LED应用程序。Makefile文件。,熟悉GPIO端口的原理。4、并调试LED跑马灯应用程序。3.3.3预备知识1、C语言基础知识。vim编辑器的使用。3、程序调试的基础知识和方法。4、ARM应用程序的基本架构。3.3.4实验设备及工具1、硬件:GEC6818开发平台。Ubuntu14.04、、arm-linu叉开发环境。3.3.5基础知识1、硬件原理3-3所示:图3-3原理图GEC6818LED灯的GPIOE13,GPIOC17,GPIOC7GPIO管脚,让管脚为输出端口,实现亮灭。LED灯的2GEC6818LED灯的GPIOE13,GPIOC17,GPIOC7GPIO管脚,让管脚为输出端口,实现亮灭。LED灯的2、寄存器原理设置输出电平:设置为输出模式:3.3.6实验原理1、register_chrdev_region族+cdev族+创建设备类、文件的函数:这种方法2.6版本推荐的新方法。优点是可以设置主次设备号;缺点是比较复杂。2、关于分配主次设备号,register_chrdev_region是用户自定义设备号的申(即次设备号)MKDEV这个宏获得,它可以通过主设备号和次设备号来计算设备号。其实更方便的做让内核给我们自动分配一个,这样就备号之间重复。导致设cdev_alloccdev分配内存。使用cdev_del时内核会为我们自动cdev占用的空间,而如果我们malloc的话就要了。file_operations填充进cdev_init()的,而是手动去填充,例如mydev_pcdevcdev_alloccdev分配内存。使用cdev_del时内核会为我们自动cdev占用的空间,而如果我们malloc的话就要了。file_operations填充进cdev_init()的,而是手动去填充,例如mydev_pcdevownerTHIS_MODULE;mydev_pcdevops&mydev_fops;说cdev_init()其实就相当于上面两句cdev_add将设备体与设备号绑定,并向内核一个字符设备6udev(mdev)来创建一个位于/dev的设备文件。这一步其APIAPPAPI操作设备文件(即调用内的函数)class_create先实例化新建一个device_create正式创建设备文件3.3.7实验步骤1PC机中,创建两个文件夹,分别为driver和test2PCdriverled_new.cMakefile两个文件3_3_led_newdriver中的文件编写Makefile文件。3PC机中的driver目录的终端中,编译文件生成led_new.ko文件led_newtest.cMakefile两个文件1-led_iotest中的文件编写Makefile文件。5PCtest目录的终端中,编译文件生成led_test文件#maketouchled_newtest.cMakefile#make#touchled_new.cMakefiel#mkdirdrivertest6、在arm板子的终端中加载驱动加载驱动之前需要先卸载led预装的驱动。此时,我们可以在/proc/devices找到我们申请的主设备号和设备名命令如下:结果显示:7、在arm板子中创建设备文件的节点命令如下:8、在6、在arm板子的终端中加载驱动加载驱动之前需要先卸载led预装的驱动。此时,我们可以在/proc/devices找到我们申请的主设备号和设备名命令如下:结果显示:7、在arm板子中创建设备文件的节点命令如下:8、在arm板子中执行程序3.3.8实验现象开发板上的一个LED等在闪烁。./led_newtestmknod/dev/gec_ledc2430命令解释:mknod/dev/gec_ledc //表示字符设备243 //刚刚我们查看到的主设备号0 255243chrtestcat/proc/deviceslsmod ledrmmodled ledinsmodled_new.ko //加载我们编译的驱动3.4 PWM驱动开发(misc设备模型)3.4.1实验目的1、掌握基本的字符设备的驱动程序设计。2、掌握基本的文件操作。3.4.2实验内容1S5P68182、编写应用程序。Makefile文件。,熟悉其工作原理。43.4 PWM驱动开发(misc设备模型)3.4.1实验目的1、掌握基本的字符设备的驱动程序设计。2、掌握基本的文件操作。3.4.2实验内容1S5P68182、编写应用程序。Makefile文件。,熟悉其工作原理。4、并调试输出的应用程序。3.4.3预备知识1、C语言基础知识。vim编辑器的使用。3、程序调试的基础知识和方法。4、ARM应用程序的基本架构。3.4.4实验设备及工具硬件:GEC6818开发平台。软件:PCUbuntu14.04、、arm-linu叉编译环。3.4.5基础知识1、硬件原理3-4所示:3-4PWM根据S5P6818GPIOC14。2、寄存器简介3-4PWM根据S5P6818GPIOC14。2、寄存器简介3、实验原理PWM输出脚,默认为低电平,PWMTCNTn的TCNTBnTCNTnTCMPBn的值时,PWM输PWM0时,输出又变为低电平,如此周而复始。ioctl函数来设置相关寄存器PWM波形的输出与驱动代码分析:(详细代码请查看附件)#include<linux/module.h>#include<linux/kernel.h>#include<linux/cdev.h>#include#include#include#include#include#include#include#include#include#include#include#include#include#include<linux/uaccess.h><linux/fs.h><linux/ioport.h><linux/miscdevice.h><linux/ioctl.h>#include#include#include#include#include#include#include#include#include#include#include#include#include#include<linux/uaccess.h><linux/fs.h><linux/ioport.h><linux/miscdevice.h><linux/ioctl.h><linux/delay.h><linux/gpio.h><cfg_type.h><linux/platform_device.h><linux/err.h><linux/io.h><linux/init.h><linux/pwm.h><linux/slab.h>#include#include#include<mach/platform.h><mach/devices.h><mach/soc.h>#defineDEVICE_NAME"pwm"#define#definePWM_IOCTL_SET_FREQ1PWM_IOCTL_STOP0#defineNS_IN_1HZ(1000000000UL)#define#defineBUZZER_PWM_ID 2BUZZER_PMW_GPIO(PAD_GPIO_C+14)staticstructpwm_device*pwm2buzzer;staticstructsemaphorelock;staticvoidpwm_set_freq(unsignedlongfreq){intperiod_ns=NS_IN_1HZ/freq;pwm_config(pwm2buzzer,period_ns/pwm_enable(pwm2buzzer);2,period_ns);}staticvoidpwm_stop(void){pwm_config(pwm2buzzer,0,NS_IN_1HZ/100);pwm_disable(pwm2buzzer);}staticintgec6818_pwm_open(structinode*inode,structfile*file){if(!down_trylock(&lock))returnelsereturn0;-EBUSY;}staticintgec6818_pwm_close(structinodepwm_disable(pwm2buzzer);}staticintgec6818_pwm_open(structinode*inode,structfile*file){if(!down_trylock(&lock))returnelsereturn0;-EBUSY;}staticintgec6818_pwm_close(structinode*inode,structfile*file){up(&lock);return0;}staticlonggec6818_pwm_ioctl(structunsignedlongarg){switch(cmd){casePWM_IOCTL_SET_FREQ:if(arg==0)return-EINVAL;pwm_set_freq(arg);break;file*filep,unsignedintcmd,casePWM_IOCTL_STOP:default:pwm_stop();break;}return0;}staticstruct.owner.open.releasefile_operationsgec6818_pwm_ops={==THIS_MODULE,gec6818_pwm_open,=gec6818_pwm_close,.unlocked_ioctl=gec6818_pwm_ioctl,};staticstructmiscdevicegec6818_misc_dev={.minor=MISC_DYNAMIC_MINOR,makefile请参面几章编写测试代码简析(详细代码请查看附件) intmain(intargcmakefile请参面几章编写测试代码简析(详细代码请查看附件) intmain(intargc,char**argv) .name=DEVICE_NAME,.fops=&gec6818_pwm_ops,};staticintinitgec6818_pwm_dev_init(void){intret;ret=gpio_request(BUZZER_PMW_GPIO,DEVICE_NAME);if(ret){printk("requestGPIO%dforpwmfailed\n",BUZZER_PMW_GPIO);returnret;}gpio_direction_output(BUZZER_PMW_GPIO,0);pwm2buzzer=pwm_request(BUZZER_PWM_ID,DEVICE_NAME);if(IS_ERR(pwm2buzzer)){printk("requestpwm%dfor%sfailed\n",BUZZER_PWM_ID,DEVICE_NAME);return-ENODEV;}pwm_stop();gpio_free(BUZZER_PMW_GPIO);same_init(&lock,1);ret=misc_register(&gec6818_misc_dev);printk(DEVICE_NAME"\tinitialized\n");returnret;}staticvoidexitgec6818_pwm_dev_exit(void){pwm_stop();misc_deregister(&gec6818_misc_dev);}module_init(gec6818_pwm_dev_init);module_exit(gec6818_pwm_dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("GECInc.");MODULE_DESCRIPTION("S5P6818PWMDriver");{intbuzzer_fd;unsignedlongfreq;char*endstr,*str;printf("Usage:%s{intbuzzer_fd;unsignedlongfreq;char*endstr,*str;printf("Usage:%s<on/off><freq>\n","./buzzer");if(argc==3){buzzer_fd=open("/dev/pwm",O_RDWR);if(buzzer_fd<0){perror("opendevice:");exit(1);}str=argv[2];errno=0;freq=strtol(str,&endstr,0);if((errno==ERANGE&&(freq==LONG_MAX||freq==LONG_MIN))||(errno==0)){perror("freq:");exit(EXIT_FAILURE);}if(endstr==str){fprintf(stderr,"Pleaseinputadigitsforfreq\n");exit(EXIT_FAILURE);}!=0&&freqif(!strncmp(argv[1],"on",2)){ioctl(buzzer_fd,BUZZER_IOCTL_SET_FREQ,freq);}elseif(!strncmp(argv[1],"off",3)){ioctl(buzzer_fd,BUZZER_IOCTL_STOP,freq);}else{close(buzzer_fd);exit(EXIT_FAILURE);}}elseif(argc==2){buzzer_fd=open("/dev/pwm",O_RDWR);if(buzzer_fd<0){perror("opendevice:");exit(1);}编写测试程序makefile文件(可参面几章makefile文件编写),以下编写一个较为通用的makefile编写测试程序makefile文件(可参面几章makefile文件编写),以下编写一个较为通用的makefile,在后面章节中读者只需将TARGET修改为相应的目标文件即可INSTALLDIR=/home/zr/nfs/driver/driverifneq($(KERNELRELEASE),)obj-m:=gec6818_beep.oelseKERNELDIR:=/home/zr/kernel/6818/kernel4.8/bin/arm-eabi-PWD:=$

温馨提示

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

评论

0/150

提交评论