一、驱动概念

        驱动与底层硬件直接打交道,充当了硬件与应用软件中间的桥梁。

1、具体任务

        (1)读写设备寄存器(实现控制的方式)

        (2)完成设备的轮询、中断处理、DMA通信(CPU与外设通信的方式)

        (3)进行物理内存向虚拟内存的映射(在开启硬件MMU的情况下)

2、驱动的定位

        Linux系统主要部分:内核、shell、文件系统、应用程序。

        内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。分层设计的思想让程序间松耦合,有助于适配各种平台。驱动的上面是系统调用下面是硬件。

3、驱动的分类

        Linux驱动分为三个基础大类:字符设备驱动,块设备驱动,网络设备驱动

(1)字符设备
字符(char)设备是个能够像字节流(类似文件)一样被访问的设备。
对字符设备发出读/写请求时,实际的硬件I/O操作一般紧接着发生。
字符设备驱动程序通常至少要实现open、close、read和write系统调用。
比如我们常见的lcd、触摸屏、键盘、led、串口等等,他们一般对应具体的硬件都是进行出具的采集、处理、传输。
(2)块设备
一个块设备驱动程序主要通过传输固定大小的数据(一般为512或1k)来访问设备。
块设备通过buffer cache(内存缓冲区)访问,可以随机存取,即:任何块都可以读写,不必考虑它在设备的什么地方。
块设备可以通过它们的设备特殊文件访问,但是更常见的是通过文件系统进行访问。
只有一个块设备可以支持一个安装的文件系统。
比如我们常见的电脑硬盘、SD卡、U盘、光盘等。
(3)网络设备
任何网络事务都经过一个网络接口形成,即一个能够和其他主机交换数据的设备。
访问网络接口的方法仍然是给它们分配一个唯一的名字(比如eth0),但这个名字在文件系统中不存在对应的节点。
内核和网络设备驱动程序间的通信,完全不同于内核和字符以及块驱动程序之间的通信,内核调用一套和数据包传输相关的函(socket函数)而不是read、write等。
比如我们常见的网卡设备、蓝牙设备。

4、驱动的功能

        (1)对设备初始化和释放

        (2)把数据从内核传送到硬件和从硬件读取数据

        (3)读取应用程序传送给设备文件的数据和回送应用程序请求的数据

        (4)检测和处理设备出现的错误

二、环境搭建——以树莓派开发板为例

        树莓派是ARM架构的开发板。在烧录好系统之后(树莓派的系统烧录是将系统烧录进sd卡),配置无线网络(用于和开发的计算机进行通信)。

        下一步,通信成功之后,就要在自己的计算机(以下简称PC)上进行开发。大致的流程如下:

1、安装交叉编译工具链

        先去软件源刷新一下最新的软件清单:

sudo apt-get update

        然后安装交叉编译器以及相应的一些依赖工具:

sudo apt-get install gcc-arm-linux-gnueabihf build-essential bc bison flex libssl-dev

(1)交叉编译器 gcc-arm-linux-gnueabihf

(2)build-essential

(3)其他工具

(4)交叉编译器的选择

①选择标准

②交叉编译器命名规则

2、下载对应内核源码

        对应的,开发板上烧录的是什么系统,就需要下载对应的内核源码,这里是为了后续驱动开发做准备。

git clone --depth=1 --single-branch -b rpi-5.10.y https://github.com/raspberrypi/linux.git

3、获取开发板内核配置文件

        每个开发板对应的系统有差异,所以配置文件所在的地方也有差异。这里采用的是安装内核头文件从而获取内核配置文件的方式。

sudo apt-get install raspberrypi-kernel-headers

        安装完成之后,会得到一个目录:

/usr/src/linux-headers-$(uname -r)/

        这里uname-r作为参数,表示的是正在运行的 Linux 操作系统的内核版本。

        接下来讲整个目录打包,通过网络传到云服务器上

cd /usr/src
tar czf linux-headers.tar.gz linux-headers-$(uname -r)
scp linux-headers.tar.gz <云服务器用户>@<云服务器IP>:~/

        在云服务器上解压:(这里以放到~/目录下为例,实际可以放到一个更干净的目录下)

tar xzf linux-headers.tar.gz -C ~/

4、写驱动的makefile

        对于解压后的内核的头文件,需要做的就是在写驱动的makefile的时候放到KDIR里面。

obj-m += mydriver.oKDIR := /home/xxx/linux-headers-5.10.63-v7l+   # 解压的内核头文件目录
PWD  := $(shell pwd)all:$(MAKE) -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules

        这样就能正常编译驱动文件了。

三、驱动编译的两种方式

1、编译进内核

        将驱动编译进 Linux 内核中,当 Linux 内核启动的时就会自动运行驱动程序。

2、编译成模块

        将驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用相应命令加载驱动模块。

        内核模块是Linux内核向外部提供的一个插口;内核模块是具有独立功能的程序,他可以被单独编译,但不能单独运行。他在运行时被链接到内核作为内核的一部分在内核空间运行;内核模块便于驱动、文件系统等的二次开发。

四、驱动框架

1、模块加载函数

module_init(xxx_init);

        module_init 函数用来向 Linux 内核注册一个模块加载函数,参数 xxx_init 就是需要注册的具体函数(理解是模块的构造函数),当加载驱动的时, xxx_init 这个函数就会被调用。

2、模块卸载函数

module_exit(xxx_exit);

        module_exit函数用来向 Linux 内核注册一个模块卸载函数,参数 xxx_exit 就是需要注册的具体函数(理解是模块的析构函数),当使用“rmmod”命令卸载具体驱动的时候 xxx_exit 函数就会被调用

3、模块许可证明

MODULE_LICENSE("GPL") //添加模块 LICENSE 信息 ,LICENSE 采用 GPL 协议

4、模块参数(可选)

        模块参数是一种内核空间与用户空间的交互方式,只不过是用户空间 --> 内核空间单向的,他对应模块内部的全局变量

5、模块信息(可选)

MODULE_AUTHOR("songwei") //添加模块作者信息

6、模块打印printk

        printk在内核中用来记录日志信息的函数,只能在内核源码范围内使用。和printf非常相似。
printk函数主要做两件事情:①将信息记录到log中 ②调用控制台驱动来将信息输出

printk打印等级

        printk 可以根据日志级别对消息进行分类,一共有 8 个日志级别:

#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"  /* 调试信息 */

        以下代码就是设置“gsmi: Log Shutdown Reason\n”这行消息的级别为 KERN_EMERG。

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

        如果使用 printk 的时候不显式的设置消息级别,那 么printk 将会采用默认级别MESSAGE_LOGLEVEL_DEFAULT,默认为 4

        对于控制台打印出的日志,如果代码中的打印等级低于默认控制台打印等级,则不会打印到控制台中。在 include/linux/printk.h 中有个宏 CONSOLE_LOGLEVEL_DEFAULT,定义如下:

#define CONSOLE_LOGLEVEL_DEFAULT 7

        CONSOLE_LOGLEVEL_DEFAULT 控制着哪些级别的消息可以显示在控制台上,此宏默认为 7,意味着只有优先级高于 7 的消息才能显示在控制台上。

        这个就是 printk 和 printf 的最大区别,可以通过消息级别来决定哪些消息可以显示在控制台上。默认消息级别为 4,4 的级别比 7 高,所示直接使用 printk 输出的信息是可以显示在控制台上的。

        但是,所有打印的信息,不管优先级多少,都可以通过dmesg显示,必要时可以通过管道筛选:dmesg | grep hello

7、模块操作命令

(1)加载模块

①insmod XXX.ko
为模块分配内核内存、将模块代码和数据装入内存、通过内核符号表解析模块中的内核引用、调用模块初始化函数(module_init)
insmod要加载的模块有依赖模块,且其依赖的模块尚未加载,那么该insmod操作将失败
②modprobe XXX.ko
加载模块时会同时加载该模块所依赖的其他模块,提供了模块的依赖性分析、错误检查、错误报告
modprobe 提示无法打开“modules.dep”这个文件 ,输入 depmod 命令即可自动生成 modules.dep

(2)卸载模块

        rmmod XXX.ko

(3)查看模块信息

  • lsmod
    • 查看系统中加载的所有模块及模块间的依赖关系
  • modinfo (模块路径)
    • 查看详细信息,内核模块描述信息,编译系统信息

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机视觉(十):ROI

什么是感兴趣区域&#xff08;ROI&#xff09;&#xff1f; 在计算机视觉中&#xff0c;**感兴趣区域&#xff08;ROI&#xff09;**指的是图像中包含我们想要分析、处理或识别的目标或特征的特定子集。就像我们在阅读一本书时会聚焦于某个重要的段落&#xff0c;计算机视觉系统…

Jenkins 构建 Node 项目报错解析与解决——pnpm lockfile 问题实战

在使用 Jenkins 自动化构建 Node.js 项目时&#xff0c;经常会遇到类似报错&#xff1a; ERR_PNPM_OUTDATED_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with package.json Error: Cannot find module node_module…

Kafka在多环境中安全管理敏感

1. 配置提供者是什么&#xff1f; 配置提供者&#xff08;ConfigProvider&#xff09;是一类按需“拉取配置”的组件&#xff1a;应用读取配置时&#xff0c;按约定的占位符语法去外部来源&#xff08;目录、环境变量、单一 properties 文件、你自定义的来源……&#xff09;取…

编程工具的演进逻辑:从Python IDLE到Arduino IDE的深度剖析

引言:工具进化的本质 在编程学习与开发的道路上,我们总会与各种各样的工具相遇。一个有趣的现象是,无论是初学者的第一款工具Python IDLE,还是硬件爱好者常用的Thonny和Arduino IDE,它们都自称“集成开发环境”(IDE)。这背后隐藏着怎样的逻辑? 本文将带你深入分析这三…

p10k configure执行报错: ~/powerlevel10k/config/p10k-lean.zsh is not readable

[ERROR] p10k configure: ~/powerlevel10k/config/p10k-lean.zsh is not readable 背景 我移动了Powerlevel10k文件夹的位置&#xff0c;导致p10k configure命令找不到powerlevel10k文件夹的位置。 原来Powerlevel10k的位置&#xff1a;~/powerlevel10k 移动后Powerlevel10k的位…

Java 学习笔记(进阶篇3)

1. 美化界面关键逻辑 1&#xff1a;// 相对路径&#xff1a;直接从项目的 src 目录开始写&#xff0c;不包含 D:\ 和个人名字 ImageIcon bg new ImageIcon("src/image/background.png"); JLabel background new JLabel(bg);这两行代码是 Swing 中加载并显示图片的经…

BFD 概述

BFD简介1.BFD:Bidirectional Forwarding Detection,双向转发检查概述&#xff1a;毫秒级链路故障检查&#xff0c;通常结合三层协议&#xff08;如静态路由、vrrp、 ospf、 BGP等&#xff09;实现链路故障快速切换。作用&#xff1a;① 检测二层非直连故障② 加快三层协议收敛底…

【嵌入式DIY实例-ESP32篇】-Flappy Bird游戏

Flappy Bird游戏 文章目录 Flappy Bird游戏 1、游戏介绍 2、硬件准备与接线 3、代码实现 《Flappy Bird》游戏以其引人入胜的玩法和简约的设计风靡全球。本文将探讨如何使用 OLED SSD1306 显示屏和 ESP32 微控制器重现这款经典游戏。这个 DIY 项目不仅充满乐趣,也是学习编程和…

[数据结构——lesson2.顺序表]

目录 学习目标 引言 1.什么是线性表&#xff1f; 2.什么是顺序表&#xff1f; 2.1概念及结构 2.2 接口实现 2.2.1顺序表的功能 1.顺序表的初始化 2.打印数据 3.尾插数据 (1)检查空间 (2)插入数据 4.尾删数据 5.头插数据 6.头删数据 7.数据查找 8.指定位置数据…

ChatGPT大模型训练指南:如何借助动态代理IP提高训练效率

随着人工智能技术的飞速发展&#xff0c;ChatGPT等大型语言模型&#xff08;LLM&#xff09;已成为科技界和产业界关注的焦点。模型的训练过程耗时、耗资源且对网络环境要求极高。尤其是在需要模拟真实用户行为、进行大规模数据爬取或分布式训练的场景下&#xff0c;单一IP地址…

Docker 学习笔记(六):多容器管理与集群部署实践

Docker Docker-compose 单个 Dockerfile 可定义单容器应用&#xff0c;但日常工作中&#xff0c;Web 项目等常需 Web 服务、数据库、负载均衡等多容器配合&#xff0c;手动按序启停容器会导致维护量大、效率低。 Docker Compose 是高效的多容器管理工具&#xff0c;通过单个 do…

C++类和对象初识

面向过程 1.1 面向过程特点 1.2 通俗解释&#xff1a;煮方便面 1.3 面向过程实现代码 1.4 特点总结面向对象 2.1 面向对象特点 2.2 通俗解释&#xff1a;对象协作思维 2.3 面向对象实现代码 2.4 特点总结面向对象和面向过程总结C 面向对象介绍 4.1 面向对象三大基本特征封装&am…

C++ Int128 —— 128位有符号整数类实现剖析

&#x1f9e0; C Int128 —— 128位有符号整数类实现剖析 引用&#xff1a;openppp2/ppp/Int128.h &#x1f3d7;️ 1. 存储结构设计 #mermaid-svg-2JDFsdz6MTbX253D {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-sv…

【C 语言生成指定范围随机数(整数 + 小数):原理、实现与避坑指南】

概述 在 C 语言开发中&#xff0c;生成指定范围的随机数是高频需求&#xff08;如游戏随机道具、数据模拟、测试用例生成等&#xff09;。但很多新手会卡在 “范围控制”“随机数重复”“小数生成” 等问题上。本文结合实战场景&#xff0c;从原理到代码详细讲解如何生成 1100、…

一个简单的langgraph agent系统

本文基于langgraph的预制件 Agent Chat UI和《搭建一个本地langgraph服务》中的本地服务构建一个简单的agent系统。 说明&#xff1a;Agent Chat UI需要nodejs版本18及以上&#xff0c;而nodejs18需要的glibc版本为2.28&#xff0c;本人使用操作系统为ubuntu18.04&#xff0c;g…

通过SSH来推送本地文件夹到Github

配置SSH git使用SSH配置&#xff0c; 初始需要以下三个步骤 使用秘钥生成工具生成rsa秘钥和公钥 将rsa公钥添加到代码托管平台 将rsa秘钥添加到ssh-agent中&#xff0c;为ssh client指定使用的秘钥文件 具体操作如下&#xff1a; 第一步&#xff1a;检查本地主机是否已经存在…

视频转webp批量处理工具哪个好?这里有答案

你是不是也遇到过这样的困扰&#xff1a;手机里存满了精彩的短视频&#xff0c;想做成动图分享到社交媒体&#xff0c;却发现转换后的GIF文件巨大无比&#xff0c;画质还惨不忍睹&#xff1f;要怎么把手机视频转webp&#xff0c;才能既保持高清画质&#xff0c;又能大幅减小文件…

【Fastjson】Fastjson2 在不同 Modules 模块包下,@JSONField name映射无法反序列化的 BUG 及解决

问题&#xff1a;在使用 alibaba fastjson2 做 JSONField 字段名映射时&#xff0c;在同模块包下 Flink Jar 任务正常映射&#xff0c;本地测试正常映射&#xff0c;但是将两个模块包上传至 Flink Cluster 之后&#xff0c;出现反序列化异常&#xff0c;子模块无法反序列化父模…

Go语言基础---数据类型间的故事

Go语言基础—数据类型间的故事 目录 前言基本数据类型 整形字节特殊整形unsafe.Sizeof数字字面量语法浮点型布尔值字符串byte和rune类型 运算符 算术运算符关系运算符逻辑运算符位运算符赋值运算符 前言 Go语言是Google开发的一种静态强类型、编译型语言。Go语言语法与C相近…

dedecms软件等级★号改成图片图标显示的办法

我们在用到dedecms织梦的软件模型&#xff0c;在调用软件星级的时候&#xff0c;要把默认的星号改为图片&#xff0c;这个要怎么操作呢&#xff1f;1、软件模型管理里面-字段管理-字段配置softrankislink一行改为&#xff1a;<field:softrank itemname软件等级 typeint isnu…