Linux驱动开发简易流程

推荐视频:

正点原子【第四期】手把手教你学 Linux之驱动开发篇
小智-学长嵌入式Linux&Android底层开发入门教程

能力矩阵

基础能力矩阵

熟悉c/c++、熟悉数据结构
熟悉linux系统,Shell脚本,Makefile/cmake/mk
文件IO、多线程、竞争、并发、阻塞、同步、中断、网络
熟悉调试工具,gdb、gdbserver、tcpdump

行业能力矩阵

平台相关:海思/君正/安霸MTK/NXP/高通/全志/瑞芯微/展讯等平台
系统相关:bootloader、kernel、文件系统,定制、移植、开发与适配
Android相关:HAL、Services、Framework
驱动相关:驱动设备模型、GPIO、I2C、SPL、UART、WIFl、LCD、USB
物联网相关:TCP/IP、UDP、COAP、MQTT、HTTP
流媒体相关:RTMP、RTSP、Iive555
视频编码:H264、H265、MJPEG
音频编码:PCM、AAC、G711
流媒体框架:FFMEPG、GStreamer、WebRTC

开发流程

  1. 编译系统,跑起来(编译从原厂拿来的SDK,看看有没有报错,做好一些必要的ignore管理)
  2. 按照需求将项目外设逐个调通(遥控,WIFI,蓝牙,LED灯光等等)
  3. 封装Android接口,让应用能用上驱动(这个一般是移植的芯片厂家的驱动,适配好就行)
  4. 应用实现(根据客户的需求定制各种功能)

Linux驱动开发思维

1、Liuⅸ下驱动开发直接操作寄存器不现实。
2、根据Linuⅸ下的各种驱动框架进行开发。一定要满足框架,也就是Linux下各种驱动框架的掌握。
3、驱动最终表现就是/dev/xxx文件。打开、关闭、读写。
4、现在新的内核支持设备树,这个一个dts文件,此文件描述了板子的设备信息。

linux驱动开发分类

linux驱动分为三大类:
1、字符设备驱动,最多的。
2、块设备驱动,存储
3、网络设备驱动,
一个设备不说是一定只属于某一个类型。比如USB WIFI,SDIO WIFI,属于网络设备驱动,因为他又有USB和SDIO,因此也属于字符设备驱动。

应用程序和驱动交互原理

用户空间(用户态)和内核空间(内核态):
Linux操作系统内核和驱动程序运行在内核空间、应用程序运行在用户空间。
应用程序想要访问内核资源,怎么办,有三种方法:系统调用、异常(中断)和陷入。我们一般都是系统调用的方式。
Linux 驱动属于内核的一部分,因此驱动运行于内核空间。
[图片]

当我们在用户空间想要实现对内核的操作,比如使用 open 函数打开/dev/led 这个驱动,因为用户空间不能直接对内核进行操作,因此必须使用一个叫做“系统调用”的方法来实现从用户空间“陷入”到内核空间,这样才能实现对底层驱动的操作。
[图片]

驱动的加载与卸载

Linux 驱动有两种运行方式。

  1. 将驱动编译进 Linux 内核中,这样当 Linux 内核启动的时候就会自动运行驱动程序。
  2. 将驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用“insmod”命令加载驱动模块。
    驱动编译完成以后扩展名为.ko,有两种命令可以加载驱动模块:insmod和modprobe。insmod 命令不能解决模块的依赖关系,modprobe 会分析模块的依赖关系,然后会将所有的依赖模块都加载到内核中。驱动模块的卸载使用命令“rmmod”即可
    简单看懂驱动代码
 /* 驱动入口函数 */ 
 static int __init xxx_init(void) 
 { 
 
/* 入口函数具体内容 */ 
 
return 0; 
 } 
  
 /* 驱动出口函数 */ 
 static void __exit xxx_exit(void) 
 { 
 
/* 出口函数具体内容 */ 
 } 
 
 /* 将上面两个函数指定为驱动的入口和出口函数 */ 
 module_init(xxx_init); 
 module_exit(xxx_exit);

设备号的分配

  1. 静态分配设备号
    注册字符设备的时候需要给设备指定一个设备号,这个设备号可以是驱动开发者静态的指定一个设备号,比如选择 200 这个主设备号。有一些常用的设备号已经被 Linux 内核开发者给分配掉了,具体分配的内容可以查看文档 Documentation/devices.txt。
    使用“cat /proc/devices”命令即可查看当前系统中所有已经使用了的设备号。
  2. 动态分配设备号
    静态分配设备号需要我们检查当前系统中所有被使用了的设备号,然后挑选一个没有使用的。而且静态分配设备号很容易带来冲突问题,Linux 社区推荐使用动态分配设备号,在注册字符设备之前先申请一个设备号,系统会自动给你一个没有被使用的设备号,这样就避免了冲突。
    设备号的申请函数如下:
    int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
    注销字符设备之后要释放掉设备号,设备号释放函数如下:
    void unregister_chrdev_region(dev_t from, unsigned count)

内核打印

在驱动中可以使用printk 来输出信息,而不用printf。因为在 Linux 内核中没有 printf 这个函数。printk 相当于printf 的孪生兄妹,printf运行在用户态,printk 运行在内核态。在内核中想要向控制台输出或显示一些内容,必须使用printk 这个函数。不同之处在于,printk 可以根据日志级别对消息进行分类,一共有 8 个消息级别,这 8 个消息级别定义在文件 include/linux/kern_levels.h 里面,定义如下:

#define KERN_SOH "\001" 
#define KERN_EMERG KERN_SOH "0" /* 紧急事件,一般是内核崩溃 */ 
#define KERN_ALERT KERN_SOH "1" /* 必须立即采取行动 */ 
#define KERN_CRIT KERN_SOH "2" /* 临界条件,比如严重的软件或硬件错误*/ 
#define KERN_ERR KERN_SOH "3" /* 错误状态,一般设备驱动程序中使用 KERN_ERR 报告硬件错误 */ 
#define KERN_WARNING KERN_SOH "4" /* 警告信息,不会对系统造成严重影响 */ 
#define KERN_NOTICE KERN_SOH "5" /* 有必要进行提示的一些信息 */ 
#define KERN_INFO KERN_SOH "6" /* 提示性的信息 */ 
#define KERN_DEBUG KERN_SOH "7" /* 调试信息 */

一共定义了 8 个级别,其中 0 的优先级最高,7 的优先级最低。如果要设置消息级别,参考如下示例:

printk(KERN_EMERG "gsmi: Log Shutdown Reason\n");

上述代码就是设置“gsmi: Log Shutdown Reason\n”这行消息的级别为 KERN_EMERG。在具体的消息前面加上 KERN_EMERG 就可以将这条消息的级别设置为 KERN_EMERG。
如果使用 printk 的 时 候 不 显 式 的 设 置 消 息 级 别 , 那 么 printk 将 会 采 用 默 认 级 别MESSAGE_LOGLEVEL_DEFAULT,MESSAGE_LOGLEVEL_DEFAULT 默认为 4
在控制台修改内核打印级别:

echo 7 > echo 7 > /proc/sys/kernel/printk

在uboot下改变内核打印级别:

env set loglevel7 
env save

编译驱动程序和测试 APP

编译驱动程序

当我们编写完一个驱动程序之后会生成.c文件,比如chrdevbase.c 这个文件。我们需要将其编译为.ko 模块.

  1. 创建Makefile 文件,然后在其中输入如下内容:
 KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek 
 CURRENT_PATH := $(shell pwd) 
 obj-m := chrdevbase.o 
  
 build: kernel_modules 
  
 kernel_modules: 
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules 
 clean:  
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean 

第 1 行,KERNELDIR 表示开发板所使用的 Linux 内核源码目录,使用绝对路径,大家根据自己的实际情况填写即可。
第 2 行,CURRENT_PATH 表示当前路径,直接通过运行“pwd”命令来获取当前所处路径。
第 3 行,obj-m 表示将 chrdevbase.c 这个文件编译为 chrdevbase.ko 模块。
第 8 行,具体的编译命令,后面的 modules 表示编译模块,-C 表示将当前的工作目录切换到指定目录中,也就是 KERNERLDIR 目录。M 表示模块源码目录,“make modules”命令中加入 M=dir 以后程序会自动到指定的 dir 目录中读取模块的源码并将其编译为.ko 文件。
2. Makefile 编写好以后输入“make”命令编译驱动模块,
3. 编译成功以后就会生成一个叫做 chrdevbaes.ko 的文件,此文件就是 chrdevbase 设备的驱动模块。至此,chrdevbase 设备的驱动就编译成功。

编译测试 APP

测试 APP 比较简单,只有一个文件,因此就不需要编写 Makefile 了,直接输入命令编译。
因为测试 APP 是要在 ARM 开发板上运行的,所以需要使用 arm-linux-gnueabihf-gcc 来编译,输入如下命令:

arm-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseApp

编译完成以后会生成一个叫做 chrdevbaseApp 的可执行程序,输入如下命令查看chrdevbaseAPP 这个程序的文件信息:

file chrdevbaseApp

运行测试

  1. 拷贝文件
    [图片]

  2. 加载 chrdevbase.ko 驱动文件

insmod chrdevbase.ko 

或者

modprobe chrdevbase.ko

如果使用 modprobe 加载驱动的话,可能会出现如下的提示:
[图片]

modprobe 提示无法打开“modules.dep”这个文件,因此驱动挂载失败了。我们不用手动创建 modules.dep 这个文件,直接输入 depmod 命令即可自动生成modules.dep,有些根文件系统可能没有 depmod 这个命令,如果没有这个命令就只能重新配置busybox,使能此命令,然后重新编译 busybox。输入“depmod”命令以后会自动生成 modules.alias、modules.symbols 和 modules.dep 这三个文件,
[图片]

然后重新使用modprobe 加载 chrdevbase.ko
输入如下命令查看当前系统中有没有 chrdevbase 这个设备:

cat /proc/devices

[图片]

创建设备节点文件

驱动加载成功需要在/dev 目录下创建一个与之对应的设备节点文件,应用程序就是通过操作这个设备节点文件来完成对具体设备的操作。输入如下命令创建/dev/chrdevbase 这个设备节点文件:

mknod /dev/chrdevbase c 200 0

其中“mknod”是创建节点命令,“/dev/chrdevbase”是要创建的节点文件,“c”表示这是个字符设备,“200”是设备的主设备号,“0”是设备的次设备号。创建完成以后就会存在/dev/chrdevbase 这个文件,可以使用“ls /dev/chrdevbase -l”命令查看,
如果 chrdevbaseAPP 想要读写 chrdevbase 设备,直接对/dev/chrdevbase 进行读写操作即可。

设备操作测试

./chrdevbaseApp /dev/chrdevbase 1

[图片]

./chrdevbaseApp /dev/chrdevbase 2

[图片]

卸载驱动模块

如果不再使用某个设备的话可以将其驱动卸载掉,比如输入如下命令卸载掉 chrdevbase 这个设备

rmmod chrdevbase.ko

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

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

相关文章

基于Python的B站排行榜大数据分析与可视化系统

温馨提示:文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 本文介绍了一项基于Python的B站排行榜大数据分析与可视化系统的研究。通过网络爬虫技术,系统能够自动分析B站网址,提取大量相关文本信息并存储在系统中。通过对这些信息进行…

nginx+keepalived实现七层负载

目录 一、部署nginx01、nginx02 二、keepalived配置(抢占模式、master- backup模式) 三、测试 四、非抢占模式(backup-backup模式) nginx01 11.0.1.31nginx0211.0.1.32虚拟IP(VIP)11.0.1.30 一、部署ngin…

Android实验:contentprovider 实验+SQLite 数据库的实现

目录 SQLite实验目的实验内容实验要求项目结构代码实现结果展示 SQLite SQLite 是一个开源的嵌入式关系数据库,实现了自给自足的、无服务器的、配置无需的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库系统不同,…

虚拟化技术和云计算的关系

1、云计算底层就是虚拟化技术。 (1)常见的虚拟化技术:VMware(闭源的,需要收费)、XEN、KVM (2)大部分公司用的虚拟化方案:XEN、KVM 2、虚拟化的历史 (1&am…

鸿蒙 Window 环境的搭建

鸿蒙操作系统是国内自研的新一代的智能终端操作系统,支持多种终端设备部署,能够适配不同类别的硬件资源和功能需求。是一款面向万物互联的全场景分布式操作系统。 下载、安装与配置 DevEco Studio支持Windows系统和macOS系统 Windows系统配置华为官方推…

LSTM中文新闻分类源码详解

LSTM中文新闻分类 一、导包二、读取数据三、数据预处理1.分词、去掉停用词和数字、字母转换成小写等2.新闻文本标签数值化 三、创建词汇表/词典1.data.Field()2.空格切分等3.构建词汇表/词典使用训练集构建单词表,vectorsNone:没有使用预训练好的词向量,而是使用的是…

AI人工智能大模型讲师叶梓《基于人工智能的内容生成(AIGC)理论与实践》培训提纲

【课程简介】 本课程介绍了chatGPT相关模型的具体案例实践,通过实操更好的掌握chatGPT的概念与应用场景,可以作为chatGPT领域学习者的入门到进阶级课程。 【课程时长】 1天(6小时/天) 【课程对象】 理工科本科及以上&#xff0…

亚信安慧AntDB数据库引领数字时代通信创新

在数字经济与实体经济深度融合的时代,通信行业正迎来前所未有的新机遇。特别是在中国信通院的预测中,2027年5G专网市场规模预计将达到802亿元,呈现出显著的增长态势,年复合增长率高达42%。 亚信安慧AntDB数据库一直致力于紧跟科技…

【JVM】一篇通关JMM内存模型

JMM内存模型 1. 原子性1-1. 问题分析1-2. 问题解决 2. 可见性2-1. 问题分析2-2. 问题解决 3. 有序性3-1. 问题分析3-2. 问题解决 4. CAS与原子性5. synchronized 优化 1. 原子性 很多人将【java 内存结构】与【java 内存模型】傻傻分不清,【java 内存模型】是 Java…

【模拟电路】常见电学定律 戴维宁定理、诺顿定理、基尔霍夫定律

一、戴维宁定理 二、诺顿定理 三、基尔霍夫定律 一、戴维宁定理 任何复杂电路可以等效为一个电压源和一个电阻器组成 德维宁定理(Thevenin’s Theorem)是电路理论中的一个基本定理,它提供了一种简化复杂线性电路的方法。德维宁定理的主要思…

【网络安全】网络隔离设备

一、网络和终端隔离产品 网络和终端隔离产品分为终端隔离产品和网络隔离产品两大类。终端隔离产品一般指隔离卡或者隔离计算机。网络隔离产品根据产品形态和功能上的不同,该类产品可以分为协议转换产品、网闸和网络单向导入产品三种。 图1为终端隔离产品的一个典型…

机器学习系列13:通过随机森林获取特征重要性

我们已经知道通过 L1 正则化和 SBS 算法可以用来做特征选择。 我们还可以通过随机森林从数据集中选择相关的特征。随机森林里面包含了多棵决策树,我们可以通过计算特征在每棵决策树决策过程中所产生的的信息增益平均值来衡量该特征的重要性。 你可能需要参考&…

用IDEA创建/同步到gitee(码云)远程仓库(保姆级详细)

前言: 笔者最近在学习java,最开始在用很笨的方法:先克隆远程仓库到本地,再把自己练习的代码从本地仓库上传到远程仓库,很是繁琐。后发现可以IDEA只需要做些操作可以直接把代码上传到远程仓库,也在网上搜了些…

2023年03月22日_腾讯2022年财报解读

文章目录 1 - 腾讯营收增长停滞2 - 腾讯游戏业务低迷3 - 小程序和视频号拉动广告增长4 - 腾讯云和金融科技表现不佳5 - 营销费用减半6 - 裁员但福利上涨 2023年03月22日 今天晚上呢 腾讯披露了2022年第四季度和全年的财报 看过之后呢不禁要说 腾讯在2022年真的是过得不容易啊…

简单vlan划分和dhcp中继(Cisco Packet Tracer模拟)

文章目录 1. 前言2. 功能实现2.1. dhcp服务器接入2.2. 学校web服务器2.3. 设置学校dns服务器2.4. 设置线路冗余2.5. 配置ac。 1. 前言 在这里我们的计网作业是使用思科的Cisco Packet Tracer进行对校园网的简单规划,这里我对校园网进行了简单的规划,功能…

IDEA JAVA Spring Boot运行Hello World(1.8)

参考资料: Spring Boot运行Hello World - 知乎https://blog.csdn.net/weixin_44005516/article/details/108293228(解决bug)SpringBoot入门第一章:Hello World-java教程-PHP中文网 (仅参考如何运行程序)java 8安装教程 java 8安装教程_java8安装-CSDN博…

数据结构(五)——初识线性表

🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉 在csdn获奖荣誉: 🏆csdn城市之星2名 ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ …

C#语言发展历程(1-7)

一、类型发展 C#1中是没有泛型的 在C#2中在逐渐推出泛型。C#2还引入了可空类型。 示例:C#泛型(详解)-CSDN博客 1 C#3:引入了匿名类型、和隐式的局部变量(var) 匿名类型:我们主要是使用在LIN…

宠物救助上门喂养系统宠物领养宠物寄养寻宠小程序宠物社区系统宠物托运宠物殡葬源码

后端php 前端uniapp mysql数据库 主要功能介绍: 1.根据当前位置 支持多城市切换 2.支持首页公告实时显示 3.支持 宠物救助,上门喂养,宠物领养,宠物寄养,寻宠,宠物社区,宠物托运&#xff…

SpringAMQP的使用方式

MQ介绍 MQ,中文是消息队列(MessageQueue),字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。 比较常见的MQ实现: ActiveMQ RabbitMQ RocketMQ Kafka 几种常见MQ的对比: RabbitMQActiveM…
最新文章