在mini2440上编写linux应用程序、字符设备驱动程序的编写与编译

在mini2440上编写linux应用程序

结合前两篇的学习,一个linux操作系统已经在mini2440上运行起来了,结合交叉编译环境和nfs等工具,我们可以在mini2440上编写任何我们在linux系统编程中学到的应用程序。一个简要的多文件Makefile文件如下:
在这里插入图片描述

linux驱动程序

linux系统驱动程序分为三大类,字符设备驱动,块设备驱动和网络设备驱动。其中字符设备驱动是使用最多的一种,从点灯到IIC,SPI,音频设备等的驱动都是字符设备驱动。块设备和网络设备驱动要比字符设备驱动复杂,就是因为其复杂所以半导体厂商一般都给我们编写好了,大多数情况下都是直接可以使用的。所谓的块设备驱动就是存储器设备的驱动,比如 EMMC、NAND、SD 卡和U 盘等存储设备,因为这些存储设备的特点是以存储块为基础,因此叫做块设备。网络设备驱动就更好理解了,就是网络驱动,不管是有线的还是无线的,都属于网络设备驱动的范畴。一个设备可以属于多种设备驱动类型,比如USB WIFI,由于其使用USB 接口,所以属于字符设备,但是其又能上网,所以也属于网络设备驱动。
我们主要讨论如何编写字符设备驱动。

字符设备驱动程序简介

字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。比如我们最常见的点灯、按键、IIC、SPI、LCD 等等都是字符设备,这些设备的驱动就叫做字符设备驱动。
在详细的学习字符设备驱动架构之前,我们先来简单的了解一下 Linux 下的应用程序是如何调用驱动程序的:
在这里插入图片描述
linux系统中万物皆文件,驱动程序加载后会在/dev目录下生成一个对应的文件,如/dev/led。应用程序就是先用open打开该文件,用write控制led的亮灭,用read读取led的亮灭,用完之后用close关闭该文件。
这里需要注意的是,应用程序运行在用户空间,驱动程序运行在内核空间。应用程序必须使用一个叫做**“系统调用”**的方法来实现从用户空间“陷入”到内核空间,这样才能实现对底层驱动的操作。一个open函数执行的过程如下:
在这里插入图片描述

字符设备驱动程序的编写

linux源码中字符设备驱动程序存放在driver/char目录下,我们也可以将我们自己的驱动程序保存在该目录下
在driver/char下创建源文件first_driver.c并在文件中填入如下代码:
在这里插入图片描述
linux驱动程序对代码有着特定的要求,首先就是驱动程序加载和卸载时的函数调用,48和53行分别就是当驱动程序加载和卸载时调用的函数57和58行分别用两个带参宏指出驱动程序初始化入口点和退出入口点。59表示该驱动程序遵守的协议。这样就完成了驱动程序最基础的框架。
目前我们编写的是一个字符设备驱动程序,字符设备驱动程序将来被linux加载的时候需要注册这个驱动程序。其实无论哪种驱动程序,按照linux的做法在加载时都需要注册。字符设备驱动程序注册函数为:

int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)

int register_chrdev函数

1.unsigned int major主设备号,这里就不得不提一下linux中的设备号了。一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称为设备号主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的设备。简单来说,linux需要一个数来管理某个驱动程序和使用这个驱动程序的设备。很明显,这个设备号具有唯一性。我们可以使用cat /proc/devices命令即可查看当前系统中所有已经使用了的设备号。在接下来的程序中,我们可以设置一个静态的主设备号,比如200。设置时一定要注意不能使用已经用了的主设备号。
2. const char name:为你的驱动程序起一个名字
3. struct file_operations fops:这是一个指向
file_operations结构体变量的指针**,这个结构体里面的成员绝大多数都是函数的指针。这些函数的指针指向一个我们编写的函数,每个函数都有着各自的作用。这里列举常用的几个:
① open 函数用于打开设备文件
② release 函数用于释放(关闭)设备文件,与应用程序中的 close 函数对应
③ read 函数用于读取设备文件
④ write 函数用于向设备文件写入(发送)数据
⑤ poll 是个轮询函数,用于查询设备是否可以进行非阻塞的读写
⑥ owner 拥有该结构体的模块的指针,一般设置为THIS_MODULE
现在我们的方向已经非常明确了,为了调用注册字符设备驱动函数,不得不先准备一个file_operations结构体变量,而这个结构体变量中必要的成员,必须提前准备几个函数。
在这里插入图片描述

第12和13行:为了将来能看出这个函数调用了,输出一些信息,由于我们的程序现在运行在内核空间,所以不能用printf而是要用printk,用法和printf一样;
第19行:使用copy_to_user函数把内核空间的数据拷贝到用户空间
然后定义一个file_operations结构体变量,并将函数入口地址赋字符设备驱动值给各自的成员:
在这里插入图片描述
下面就可以调用register_chrdev函数注册字符设备驱动了。
在这里插入图片描述

#define DEVICE_MAJOR 200
#define DEVICE_NAME "first_device"

注册主设备号为200,名字为first_device的字符设备驱动。

程序写好了,如何编译呢?这里介绍两种方法

第一种方法是告诉linux的Makefile我们添加了一个新的驱动程序,这种方法需要我们的驱动源码就放在driver/char目录中,恰好我们就是这么做的。步骤如下:

第一种方法

  1. 打开 drivers/char/Kconfig 文件并添加如下内容:
    在这里插入图片描述
    Kconfig文件被称之为内核配置文件,这里我们添加了一个名为FIRST_DRIVER的配置选项,该配置选项为三态的,所谓三态是指将来的编译结果可以是模块,可以直接编译进内核还可以不编译default m是指默认编译成模块。最后那段是帮助文本
    之后我们运行make menuconfig,依次进入Device Driver-Character devices就可以看到My first driver了
    在这里插入图片描述
    选择该项按空格分别在编译成模块,编译进内核和不编译之间切换。我们选择’M’,编译成模块,以方便之后的调试。
  2. 通过上一步,我们虽然可以在配置内核的时候进行选择,但实际上此时执行编译内核还是不能把first_dirver.c 编译进去的,还需要在 Makefile 中把内核配置选项和真正的源代码联系起来。打开 drivers/char/Makefile并添加下面内容:
    在这里插入图片描述
    注意:CONFIG_之后的文字必须和Kconfig文件中配置选项名称一致,之后的文件名也必须和驱动源码文件名一致。
  3. 之后在源码顶层目录下执行make modules就可以完成编译了
    编译完成之后在driver/char目录下可以找到一个名为first_driver.ko文件,这个就是我们需要的驱动程序
    first_driver.ko通过nfs复制到开发板上
    使用insmod xxx.ko命令加载驱动程序
    使用lsmod查看已经加载的驱动
    使用rmmod xxx卸载驱动程序,注意不用加.ko
    加载好驱动程序以后,查看一下/dev目录,这里并没有出现我们所说的设备文件,这是因为目前我们的驱动程序还不能自动创建设备文件,之后我们会讲解如何自动创建设备文件。这里我们先用手动的方法创建设备文件,命令为mknod [OPTIONS] NAME TYPE MAJOR MINOR
    该命令中**[OPTIONS]选项可不填**;NAME就是/dev下的设备文件名;TYPE是设备型号,这里是字符设备用c表示;MAJOR主设备号;MINOR子设备号。
    如:mknod /dev/first c 200 0那么以后应用程序就是以文件/dev/first作为入口点调用驱动程序的。

第二种方法

将我们写好的驱动源码放在任意一个文件夹内,如linux源码目录下的mydriver目录,并在该目录下创建一个Makefile文件,内容如下:
在这里插入图片描述
第1行:获得linux源码顶层目录,根据实际情况填写
第2行:获得驱动源码所在目录
第3行:定义目标文件并指定目标文件为模块形式
第8行:具体的编译命令,后面的 modules 表示编译模块,-C 表示将当前的工作
目录切换到指定目录中,也就是 KERNERLDIR 目录。M 表示模块源码目录,”make modules”命令中加入 M=dir 以后程序会自动到指定的 dir 目录中读取模块的源码并将其编译为.ko 文件
之后使用make命令编译同样得到xxx.ko文件,加载什么的操作就和之前一样了。

正如之前所提到的,驱动程序的调用是通过应用程序的文件IO实现的。所以调用驱动程序就是编写一个简单的文件IO程序。
在这里插入图片描述
第11行:打开设备文件
第22行:调用read函数,此时就会调到我们在驱动中写的first_driver_read函数
可以看到的结果演示如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/557629.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计模式——2_9 模版方法(Template Method)

人们往往把任性也叫做自由,但是任性只是非理性的自由,人性的选择和自决都不是出于意志的理性,而是出于偶然的动机以及这种动机对感性外在世界的依赖 ——黑格尔 文章目录 定义图纸一个例子:从文件中获取信息分几步?Rea…

基于Spingboot+vue协同过滤音乐推荐管理系统

项目演示视频效果: 基于Spingbootvue协同过滤音乐推荐管理系统 基于Spingbootvue协同过滤音乐推荐管理系统 1、项目介绍 基于Springboot的音乐播放管理系统总共两个角色,用户和管理员。用户使用前端前台界面,管理员使用前端后台界面。 有推荐…

Golang内存、指针逃逸、垃圾回收机制概览

最近看到了一篇文章是关于go的内存、指针逃逸和垃圾回收机制的,发现自己并未很细致的了解过这方面的内容,于是在翻阅各种文章的情况下,写出了这篇总结,参考文章放在文末,可自取 内存 Go 语言使用一个自带的垃圾收集器…

【S32K3 入门系列】- ADC 模块简介(上)

一、 前言 对于 S32K3 系列的初学者来说,S32K3 系列的参考手册阅读难度是让人望而却步的,本系列将对 S32K3 系列的外设进行逐一介绍,对参考手册一些要点进行解析。本文旨在介绍 S32K3 系列的 ADC 模块, ADC(Analog to…

node端导出excel-用请求排队来限流

需求 有一个会执行luckySheet脚本并且导出excel的node接口,会在每天凌晨执行,但是文件过大时会内存溢出 之前有用worker来实现多线程(主要是避免变量污染),但这样只能保证主线程不卡死,几个子线程合起来占用…

MDC搭配ttl使用!!!

一、简介 MDC 介绍​ MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能。MDC 可以看成是一个与当前线程绑定的Map,可以往其中添加键值对。MDC 中包含的内容可以被…

使用yolov8 进行实例分割训练

1、基于windows 的ISAM标注 直接下载安装包,解压后即可使用 链接:https://pan.baidu.com/s/1u_6jk-7sj4CUK1DC0fDEXQ 提取码:c780 2、标注结果转yolo格式 通过ISAM标注后的json文件路径 原始json格式如下: ISAM.json 转 yolo.…

牛客2024 【牛客赛文X】春招冲刺 ONT34 加油站【中等 贪心 C++、Java、Go、PHP】

题目 题目链接: https://www.nowcoder.com/practice/a013a0691a0343aeb262ca1450d2fe4e 思路 贪心: 如果总的gas小于走完全程的cost,直接返回-1不需要再找了 如果确保了可以走完一圈之后,那么从index 0开始找, 当g…

【cygwin】工具安装apt-cyg

目录 下载安装查看是否安装成功安装软件 下载 git clone https://github.com/transcode-open/apt-cyg.git安装 cd apt-cyg mv apt-cyg /usr/local/bin/ 查看是否安装成功 apt-cyg --help安装软件 apt-cyg install nano

视频号小店怎么做?新手开店必备运营攻略,看这一篇就够了

大家好,我是电商笨笨熊 作为腾讯推出的电商项目,视频号小店在推出到现在一直都备受关注,同时也吸引了不少玩家入驻; 毕竟作为一个新平台、新市场,一个适合跑马圈地的红利平台,谁都想在这里分的一杯羹。 …

Linux debian gdb dump

1.开发背景 记录 debian 下应用程序崩溃调试方法 2.开发需求 程序越界可以定位到越界的位置附近 3.开发环境 debian 操作系统,如果不支持需要查看是否存在对应的可执行文件 4.实现步骤 4.1 设置 dump 输出大小 ulimit -c unlimited # 设置输出大小 生成core 文…

一个文生视频MoneyPrinterTurbo项目解析

最近抖音剪映发布了图文生成视频功能,同时百家号也有这个功能,这个可以看做是一个开源的实现,一起看看它的原理吧~ 一句话提示词 大模型生成文案 百家号生成视频效果 MoneyPrinterTurbo生成视频效果 天空为什么是蓝色的? 天空…

上位机图像处理和嵌入式模块部署(智能硬件的介绍)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 目前,用上位机软件虽然可以部署项目,但是它本身有自己的缺点,那就是稳定性差、价格贵。稳定性这部分&#xff0…

深度剖析扫雷游戏的各个知识点(2)

小伙伴们,大家好。这次继续上次的剖析扫雷游戏的知识点。 那么本次咱们主要是讲扫雷中的宏定义,也就是#define这些 首先#define是用来定义一个宏,后面就是类似于和变量一样的常量名,以及最后的数字就是它的值。 定义规则 #def…

数据结构——树和二叉树

目录 前言 一、树概念及结构 1.1树的概念 1.2 树的相关概念 ​编辑 1.3 树的表示 1.4 树的应用 2.二叉树概念及结构 2.1 二叉树概念 2.2 现实中的二叉树 2.3 特殊的二叉树 2.4 二叉树的性质 2.5 二叉树的存储结构 总结 前言 之前我们学习到的数据结构都是线性的…

Linux Makefile

1.开发背景 linux 下编译程序需要用到对应的 Makefile,用于编译应用程序。 2.开发需求 编写 Makefile 编译应用程序 1)支持多个源文件 2)支持多个头文件 3)支持只编译修改的文件,包括源文件和头文件 4)支持…

【Android Studio报错】:* What went wrong:Out of memory. Java heap space

项目场景: 今天,刚打开自己的安卓项目发现报错: 报错: * What went wrong: Out of memory. Java heap space Possible solution: - Check the JVM memory arguments defined for the gradle process in: gradle.properties in…

STM32G030F6P6TR ST意法

STM32G030F6P6TR是ST(意法半导体)一款基于高性能ArmCortex-M032位RISC内核,工作频率高达64MHz的32位MCU微控制器。代理销售ST(意法半导体)全系列IC电子元器件-中芯巨能为您提供STM32G030F6P6TR(ST 32位MCU)引脚图及中文参数介绍等内容。 STM32G030F6P6TR的中文参数 …

Python多态

1.多态 多态定义:多态(polymorphism)是指同一个方法调用由于对象不同可能会产生不同的行为 注意以下2点: 1.多态是方法的多态,属性没有多态。 2.多态的存在有2个必要条件:继承、方法重写 class Animal:de…

RabbitMQ入门实战

文章目录 RabbitMQ入门实战基本概念安装快速入门单向发送多消费者 RabbitMQ入门实战 官方:https://www.rabbitmq.com 基本概念 AMQP协议:https://www.rabbitmq.com/tutorials/amqp-concepts.html 定义:高级信息队列协议(Advanc…