Linux驱动开发-02字符设备驱动开发初步

news2024/11/15 21:55:13

 一、驱动开发的前期准备

在进入驱动开发之前,需要烧写UBoot、内核、设备树,做一些前期的准备工作,确保我们开发板上的内核版本和Ubuntu上是一致的才能进行正式开发

 1.U-Boot

2.内核版本

 3.使用TFTP挂载的内核和设备树

二、Linux驱动开发与裸机开发的区别

Linux驱动开发和裸机开发的区别主要体现在以下几个方面:

  1. 开发环境
    • Linux驱动开发:在带有Linux操作系统的环境下进行,开发者利用Linux提供的各种驱动框架和API进行开发。这通常意味着开发者需要熟悉Linux内核的工作原理和相关的系统调用。
    • 裸机开发:在没有操作系统支持的环境中直接运行程序,开发者需要直接操作硬件的底层细节,包括寄存器、中断等。裸机开发常见于嵌入式系统、实时控制系统等对系统性能和资源使用有极高要求的场景。
  2. 开发技术
    • Linux驱动开发:主要使用C语言进行开发,并可能使用汇编语言进行某些特定的优化。开发者需要熟悉Linux内核编程和相关的驱动框架,如字符设备驱动、块设备驱动、网络设备驱动等。
    • 裸机开发:可能涉及汇编语言、C语言或更低级别的编程语言,因为需要直接操作硬件的底层细节。开发者需要深入了解硬件的工作原理和如何与之交互。
  3. 开发流程
    • Linux驱动开发:通常包括需求分析、设计、编码、测试等阶段。开发者需要编写符合Linux内核规范的代码,并通过系统调用或设备文件与应用程序进行交互。
    • 裸机开发:开发流程可能更为复杂,因为需要直接操作硬件。这通常包括编写启动代码、初始化硬件、配置中断、编写外设驱动程序等步骤。
  4. 关注点
    • Linux驱动开发:主要关注如何在Linux操作系统下实现对硬件设备的控制和管理,以及与操作系统的交互。
    • 裸机开发:主要关注如何直接操作硬件,实现底层的功能和性能优化。
  5. 可移植性和复用性
    • Linux驱动开发:由于是基于Linux操作系统的,因此驱动程序的可移植性和复用性通常较好。Linux支持多种硬件平台和架构,开发者可以编写通用的驱动程序以支持不同的硬件。
    • 裸机开发:由于直接操作硬件,因此可移植性和复用性通常较差。不同的硬件平台和架构可能需要完全不同的驱动程序。
  6. 调试和测试
    • Linux驱动开发:可以利用Linux提供的各种调试工具和技术进行调试和测试,如GDB、KDB等。此外,由于是在操作系统环境下进行开发,因此可以利用操作系统的功能进行辅助调试和测试。
    • 裸机开发:调试和测试通常更为复杂和困难,因为需要直接操作硬件。开发者可能需要使用专门的调试工具和技术,如JTAG调试器、逻辑分析仪等。

总结来说,Linux驱动开发和裸机开发在开发环境、技术、流程、关注点、可移植性和复用性、调试和测试等方面都存在显著的区别。选择哪种开发方式取决于具体的应用场景和需求

驱动最终表现就是/dev/xxx文件,对文件的读写、打开关闭;现在新的内核支持设备树,这个一个.dts文件,此文件描述了板子的设备信息

驱动加载成功以后会在“/dev”目录下生成一个相应的文件,应用程序通过对这个名为“/dev/xxx”(xxx 是具体的驱动文件名字)的文件进行相应的操作即可实现对硬件的操作

 2.1 驱动设备的分类

字符设备驱动:字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的

块设备驱动:所谓的块设备驱动就是存储器设备的驱动,比如 EMMC、 NAND、 SD卡和 U盘等存储设备,因为这些存储设备的特点是以存储块为基础,因此叫做块设备。网络设备驱动就更好理

网络设备驱动:就是网络驱动,不管是有线的还是无线的,都属于网络设备驱动的范畴。一个设备可以

一个设备可以属于多种设备驱动类型,比如 USB WIFI,其使用 USB接口,所以属于字符设备,但是其又能上网,所以也属于网络设备驱动。

三、Linux驱动开发的VScode的环境搭建

1.禁止鼠标中键复制与创建驱动文件夹

//禁止鼠标中键复制
alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ xmodmap -e "pointer = 1 25 3 4 5 6 7 2"
Warning: Only changing the first 8 of 16 buttons.
alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ pwd
/home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase
alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ ls
chrdevbase.c  chrdevbase.code-workspace
///home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase在该路径下,新建第一个驱动的文件夹,编写代码

 2.将创建的驱动文件夹,添加到Ubuntu的vscode中

 3.将我们的内核源码路径添加到c_cpp_properties.json和Makefile

 (1)c_cpp_properties.json文件

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/include", 
                "/home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/include", 
                "/home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/include/generated/"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "clang-x64"
        }
    ],
    "version": 4
}

  (2)Makefile文件

KERNELDIR := /home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
//KERNELDIR表示开发板所使用的 Linux内核源码目录,使用绝对路径

CURRENT_PATH := $(shell pwd)
//CURRENT_PATH表示当前路径,直接通过运行“ pwd”命令来获取当前所处路
径。

obj-m := chrdevbase.o
//obj-m表示将 chrdevbase.c这个文件 编译为 chrdevbase.ko模块。

build: kernel_modules
//表示我们编译的是模块

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
//编译时,先把目录切换到源码中,因为使用了源码的一些函数;编译完成后再把目录切换到当前目录,需要把编译生成的文件放在当前目录下,Linux内核中我们已经指定好交叉编译器了
 clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

 3.先清理(make clean)再编译(make)

alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ make clean
make -C /home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek M=/home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase clean
make[1]: Entering directory '/home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek'
  CLEAN   /home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase/.tmp_versions
  CLEAN   /home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase/Module.symvers
make[1]: Leaving directory '/home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek'
alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ make
make -C /home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek M=/home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase modules
make[1]: Entering directory '/home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek'
  CC [M]  /home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase/chrdevbase.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase/chrdevbase.mod.o
  LD [M]  /home/alientek/linux/IMX6ULL/Linux_Drivers/1_chrdevbase/chrdevbase.ko
make[1]: Leaving directory '/home/alientek/alpha/alientek-zzk/kernel-chao/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek'
alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ ls
chrdevbase.c  chrdevbase.code-workspace  chrdevbase.ko  chrdevbase.mod.c  chrdevbase.mod.o  chrdevbase.o  Makefile  modules.order  Module.symvers
alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ 

 4.先清理(make clean)再编译(make)

 四、驱动模块加载与卸载

Linux驱动有两种运行方式,第一种就是将驱动编译进 Linux内核中,这样当 Linux内核启动的时候就会自动运行驱动程序。第二种就是将驱动编译成模块 (Linux下模块扩展名为 .ko),在Linux内核启动以后使用“ insmod”命令加载驱动模块。

 1.将我们在vscode中编译出来的文件拷贝到制作好的根文件目录下

alientek@ubuntu16:~/linux/IMX6ULL/Linux_Drivers/1_chrdevbase$ sudo cp chrdevbase.ko /home/alientek/linux/nfs/rootfs/lib/modules/4.1.15 -f

 2.modprobe来加载模块

insmod命令不能解决模块的依赖关系,modprobe会分析模块的依赖关系,然后会将所有的依赖模块都加载到内核中,我们使用modprobe来加载模块;

modprobe命令默认会去/lib/modules/<kernel-version>目录中查找模块,比如本书使用的 Linux kernel的版本号为 4.1.15因此 modprobe命令默认会到 /lib/modules/4.1.15这个目录中查找相应的驱动模块,一般自己制作的根文件系统中是不会有这个目录的,所以需要自己手 动创建。

 对于一个新的模块使用modprobe加载的时候需要先调用一下depmod命令;驱动模块加载成功以后可以使用lsmod查看一下;卸载模块使用rmmod命令

  2.lsmod查看当前驱动模块是否有我们刚刚加载的模块

  3.rmmod查看当前驱动模块

 

 

 4.执行命令

/lib/modules/4.1.15 # modprobe chrdevbase.ko
chrdevbase: module license 'unspecified' taints kernel.
Disabling lock debugging due to kernel taint
module_init!
/lib/modules/4.1.15 # lsmod
Module                  Size  Used by    Tainted: P
chrdevbase               664  0
/lib/modules/4.1.15 # rmmod chrdevbase.ko
module_exit!
/lib/modules/4.1.15 # lsmod
Module                  Size  Used by    Tainted: P
/lib/modules/4.1.15 # ls
8188eu.ko              ft5x06.ko              libcomposite.ko
8189fs.ko              g_audio.ko             modules.alias
8192cu.ko              g_mass_storage.ko      modules.dep
8821cu.ko              gpioled.ko             modules.symbols
adcApp                 ledAPP                 usb_f_mass_storage.ko
chrdevbase.ko          ledApp                 usb_f_uac1.ko
/lib/modules/4.1.15 # lsmod
Module                  Size  Used by    Tainted: P
/lib/modules/4.1.15 # modprobe chrdevbase.ko
module_init!
/lib/modules/4.1.15 # lsmod
Module                  Size  Used by    Tainted: P
chrdevbase               664  0
/lib/modules/4.1.15 # rmmod chrdevbase.ko
module_exit!
/lib/modules/4.1.15 # lsmod
Module                  Size  Used by    Tainted: P

5.在Ubuntu上的根文件系统中同步可以看到文件

alientek@ubuntu16:~/linux/nfs/rootfs/lib/modules/4.1.15$ pwd
/home/alientek/linux/nfs/rootfs/lib/modules/4.1.15
alientek@ubuntu16:~/linux/nfs/rootfs/lib/modules/4.1.15$ ls
8188eu.ko  chrdevbase.ko      ledApp           modules.symbols
8189fs.ko  ft5x06.ko          ledAPP           usb_f_mass_storage.ko
8192cu.ko  g_audio.ko         libcomposite.ko  usb_f_uac1.ko
8821cu.ko  g_mass_storage.ko  modules.alias
adcApp     gpioled.ko         modules.dep
alientek@ubuntu16:~/linux/nfs/rootfs/lib/modules/4.1.15$ ls
8188eu.ko  chrdevbase.ko      ledApp           modules.symbols
8189fs.ko  ft5x06.ko          ledAPP           usb_f_mass_storage.ko
8192cu.ko  g_audio.ko         libcomposite.ko  usb_f_uac1.ko
8821cu.ko  g_mass_storage.ko  modules.alias
adcApp     gpioled.ko         modules.dep

 我们的第一个驱动模块加载与卸载编译完成

 五、代码

chrdevbase.c

#include <linux/module.h>
#include <linux/init.h>//printk函数头文件
static int __init chrdevbase_init(void)
{
    printk("module_init!\r\n");
	return 0;
}

static void __exit chrdevbase_exit(void)
{
	//没有返回值
    printk("module_exit!\r\n");
}
/*
模块的入口与出口
*/
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
/*
模块的一些许可证信息
*/

MODULE_AUTHOR("Chao");//作者是谁
MODULE_LICENSE("GPL");//开源协议

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

acme.sh泛证书申请

说明: 1、想每个项目都接入域名+端口访问,所以通过acme.sh申请泛域名证书 2、阿里云域名解析,并且指定公网ip地址对应的公共Nginx服务 3、acme.sh证书只有3个月,所以要用shell自动续签证书 4、阿里云域名已解析,所以二级域名、三级域名能正常解析,如下图所示, 一、阿里云…

大厂面试官问我:Redis内存淘汰,LRU维护整个队列吗?【后端八股文四:Redis内存淘汰策略八股文合集】

往期内容&#xff1a; 大厂面试官问我&#xff1a;Redis处理点赞&#xff0c;如果瞬时涌入大量用户点赞&#xff08;千万级&#xff09;&#xff0c;应当如何进行处理&#xff1f;【后端八股文一&#xff1a;Redis点赞八股文合集】-CSDN博客 大厂面试官问我&#xff1a;布隆过滤…

SpringBoot集成Druid数据库连接池并配置可视化界面和监控慢SQL

pom.xml <!-- Druid 数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.23</version></dependency>application.yml spring:jackson:date-…

【Qt之·类QTableWidget】

系列文章目录 文章目录 前言一、常用属性二、成员函数2.1 左上角空白区域 三、实例演示总结 前言 一、常用属性 二、成员函数 方法描述selectRow选中行removeRow移除行insertRow插入行rowCount总行数 2.1 左上角空白区域 QTableCornerButton即不属于列表头&#xff0c;也不…

病理性不对称引导的渐进学习用于急性缺血性脑卒中梗死分割| 文献速递-先进深度学习疾病诊断

Title 题目 Pathological Asymmetry-Guided Progressive Learning for Acute Ischemic Stroke Infarct Segmentation 病理性不对称引导的渐进学习用于急性缺血性脑卒中梗死分割 01 文献速递介绍 中风已经成为第二大致命疾病&#xff0c;大约70%的中风是缺血性的。众所周知…

Java家教系统小程序APP公众号h5源码

让学习更高效&#xff0c;更便捷 &#x1f31f; 引言&#xff1a;家教新选择&#xff0c;小程序来助力 在快节奏的现代生活中&#xff0c;家长们越来越注重孩子的教育问题。然而&#xff0c;如何为孩子找到一位合适的家教老师&#xff0c;成为了许多家长头疼的问题。现在&…

【马拉车 中心扩展】1745. 分割回文串 IV

本文涉及知识点 回文&#xff1a; 马拉车 中心扩展 划分性dp: 动态规划汇总 LeetCocde 1745. 分割回文串 IV 给你一个字符串 s &#xff0c;如果可以将它分割成三个 非空 回文子字符串&#xff0c;那么返回 true &#xff0c;否则返回 false 。 当一个字符串正着读和反着读是…

Spark算法之ALS模型(附Scala代码)

Spark算法之ALS模型&#xff08;附Scala代码&#xff09; 在大数据时代&#xff0c;个性化推荐系统已成为连接用户与信息的桥梁&#xff0c;而算法则是构建这一桥梁的基石。Apache Spark&#xff0c;作为一款强大的分布式计算系统&#xff0c;提供了丰富的机器学习库&#xff…

Linux安装frp实现内网穿透

Linux运维工具-ywtool 目录 一. 简介二.代理类型三.frp支持的Linux的架构四.安装1.准备工作2.配置frp服务器端(a)下载安装包(b)解压安装包(c)修改配置文件(d)启动服务端 3.配置frp客户端(a)下载安装包并修改配置文件(b)启动客户端 4.测试连接 五.其他1.多端口穿透(a)服务端(b)客…

营销能力大提升:6步策略助你成为市场精英

作为一名拥有9年经验的营销老兵&#xff0c;道叔有一些心得想要分享给每一位在营销领域奋斗的朋友。 在这个快速变化的行业里&#xff0c;除了掌握营销的专业知识&#xff0c;还有一些技能和视角是我们必须掌握的。 1. 培养业务视角 你有没有注意到&#xff0c;现在企业在投…

2024年国内外最好用的六款项目管理平台盘点!

项目管理是指在一定的时间、成本、范围和质量约束下&#xff0c;通过对资源、风险、沟通、变更等方面的规划、执行、监控和控制&#xff0c;实现项目目标的过程&#xff0c;确保团队能够在有限资源下&#xff0c;保质保量的完成目标 。 今天将为大家推荐六款国内外好用的的项目…

autoware.universe源码略读(3.3)--perception:tensorrt_yolo

autoware.universe源码略读3.3--perception&#xff1a;tensorrt_yolo 模块组成cuda_utils&#xff08;CUDA接口&#xff09;calibrator&#xff08;校准器&#xff09;ImageStreamInt8EntropyCalibrator mish&#xff08;mish激活函数&#xff0c;基于CUDA&#xff09;mish_p…

旅游收入增速超469%!2.13亿小镇中老年为银发旅游增长提供新动能

下沉市场疯狂“上分”&#xff0c;银发旅游增长迎来新动能 作者&#xff5c;吕娆炜 排版&#xff5c;张思琪 干货抢先看 1. 今年第一季度&#xff0c;我国旅游人数和旅游收入增长率最高的均为三线及以下城市。 2. 独具特色的县域城市成为备受银发族青睐的新兴目的地&#xf…

vue-cli 搭建项目,ElementUI的搭建和使用

vue-cli 官方提供的一个脚手架&#xff0c;用于快速生成一个vue的项目模板&#xff1b;预先定义 好的目录结构及基础代码&#xff0c;就好比咱们在创建Maven项目时可以选择创建一个 骨架项目&#xff0c;这个骨架项目就是脚手架&#xff0c;我们的开发更加的快速&#xff1b; …

第11周 多线程接口并行对数据字典的查询优化

第11周 多线程接口并行对数据字典的查询优化 本章概述1. 多线程的初始化方式1.1 简单实现多线程的启动方式(3种)1. 继承Thread实现2. 实现Runnable接口3. 实现callable接口(返回值)1.2 基于线程池实现多线程的启动方式❤❤❤*************************************************…

「51媒体」浙江地区媒体邀约

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 浙江地区的媒体邀约资源丰富多样&#xff0c;涵盖了电视台…

进程线程协程

进程、线程和协程 进程 进程是一个正在运行的可执行文件&#xff08;exe&#xff09;&#xff0c;它是系统分配资源的最小单位。好像wx、xhs和wb都是不同的进程。它们各自独立&#xff0c;有自己的资源 线程 一个进程里可以有多个线程&#xff0c;线程是系统进行运行调度的最…

微服务和kafka

一、微服务简介 1.单体架构 分布式--微服务--云原生 传统架构&#xff08;单机系统&#xff09;&#xff0c;一个项目一个工程&#xff1a;比如商品、订单、支付、库存、登录、注册等等&#xff0c;统一部署&#xff0c;一个进程 all in one的架构方式&#xff0c;把所有的…

MyBatis案例

目录 一、配置文件1.数据与环境准备1.1 创建tb_brand表1.2 在Pojo中创建实体类Brand.java1.3 在test文件夹下的java中创建测试类1.4 安装MyBatisX插件 二、增删改查1. 查询 一、配置文件 1.数据与环境准备 1.1 创建tb_brand表 -- 删除tb_brand表 drop table if exists tb_bra…

Nginx 通过代理服务器访问目标接口

需求&#xff1a;某Nginx需要通过一个http代理服务来访问目标URL。 如果下图所示&#xff1a; 服务器B仅提供一个代理出来&#xff0c;不允许在该服务器上安装和进行任何其他配置操作。 在这种需求场景下&#xff0c;网络请求过程和域名解析的工作流程大致如下&#xff1a; 1…