ARM 裸机与 Linux 驱动对比及 Linux 内核入门
目录
ARM裸机代码和驱动的区别
Linux系统组成
内核五大功能
设备驱动分类
内核类型
驱动模块
驱动模块示例
Makefile配置
命令
编码辅助工具
内核中的打印函数
printk 函数
修改打印级别
编辑
打印级别含义
驱动多文件编译
示例
模块传递参数
命令行传递参数
支持的数据类型
module_param 函数
MODULE_PARM_DESC 函数
示例
module_param_array 函数
字符设备驱动
Linux系统中一切皆文件
字符设备驱动步骤
字符设备驱动的注册
编辑
字符设备驱动的注销
以下是本人学习时的一些笔记,对初入门的驱动可能会有一些帮助,希望可以帮到大家~
ARM裸机代码和驱动的区别
共同点:
- 都能够操作硬件。
不同点:
- 裸机编程是直接用C语言给寄存器写值。
- 驱动编程遵循一定的框架和规范,通过往寄存器写值来控制硬件。
- 裸机代码独立编译和执行,而驱动依赖于内核进行编译和执行。
- 裸机程序一次只能执行一个任务,而驱动可以支持并发执行多个任务。
- 裸机程序只需一个
main
函数即可,而驱动需要遵循内核的框架和流程。
Linux系统组成
- 用户空间(0-3G):每个进程独占0-3G的虚拟地址空间。
- 内核空间(3-4G):所有进程共享3-4G的虚拟地址空间。
- 系统调用:应用程序通过系统调用(软中断SWI)与内核交互。
内核五大功能
- 进程管理:负责进程的创建、销毁和调度。
- 文件管理:通过文件系统(如ext2/ext3/ext4/YAFFS/JFFS等)来管理文件。
- 网络管理:通过网络协议栈(如OSI/TCP/IP)处理数据包的封装和拆解。
- 内存管理:负责用户空间和内核空间内存的分配和回收。
- 设备管理:管理设备驱动,如字符设备、块设备和网络设备。
设备驱动分类
- 字符设备驱动:如LED、鼠标、键盘、LCD、触摸屏等。
- 按照字节为单位访问,支持顺序访问。
- 创建设备文件,通过
open
,read
,write
,close
等操作访问。
- 块设备驱动:如摄像头、U盘、eMMC等。
- 按照块(通常是512字节)访问,支持顺序和随机访问。
- 创建设备文件,通过
open
,read
,write
,close
等操作访问。
- 网络设备驱动:如网卡。
- 按照网络数据包进行收发。
内核类型
- 宏内核:将主要功能集成在一个内核中。
- 优点:运行效率高。
- 缺点:任何一个部分出错都可能导致整个内核崩溃。
- 示例:Ubuntu, Android
- 微内核:只包含最基本的功能,其他功能通过服务的形式在用户空间实现。
- 优点:更高的稳定性和安全性。
- 缺点:相对较低的运行效率。
- 示例:HarmonyOS, QNX
驱动模块
- 三要素:入口、出口、许可证。
- 入口:资源的申请。
- 出口:资源的释放。
- 许可证:通常使用GPL许可。
(__init可以不指定,及可以不写,但是正常是写的)
驱动模块示例
#include <linux/init.h>
#include <linux/module.h>//__init将hello_init放到.init.text段中
static int __init hello_init(void) {// 初始化函数return 0;
}//__exit将hello_exit放到.exit.text段中
static void __exit hello_exit(void) {// 清理函数
}//告诉内核驱动的入口地址(函数名为函数首地址)
module_init(hello_init);//告诉内核驱动的出口地址
module_exit(hello_exit);//许可证
MODULE_LICENSE("GPL");
Makefile配置
KERNELDIR := /lib/modules/$(shell uname -r)/build/
PWD := $(shell pwd)all:make -C $(KERNELDIR) M=$(PWD) modulesclean:make -C $(KERNELDIR) M=$(PWD) cleanobj-m += hello.o
命令
- 安装驱动模块:
sudo insmod hello.ko
- 卸载驱动模块:
sudo rmmod hello
- 查看已加载的模块:
lsmod
- 查看内核消息:
dmesg
- 清空内核消息:
sudo dmesg -C
或sudo dmesg -c
- 持续查看内核消息:
sudo dmesg -w
编码辅助工具
- 创建索引文件:
ctags -R
- 在vi中跳转至标签:
ctrl + ]
和ctrl + t
Ubuntu内核所对应的内核路径
内核中的打印函数
printk 函数
-
函数原型:
printk(打印级别 "内容")
-
示例:
printk(KERN_ERR "Fail%d", a); printk(KERN_ERR "%s:%s:%d\n", __FILE__, __func__, __LINE__); printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
-
查看内核打印级别:
vi -t KERN_ERR
-
内核打印级别定义:
#define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ #define KERN_ERR "<3>" /* error conditions */ #define KERN_WARNING "<4>" /* warning conditions */ #define KERN_NOTICE "<5>" /* normal but significant condition */ #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */
-
打印级别范围:
- 从
<0>
到<7>
,<0>
为最高级别,<7>
为最低级别。
- 从
修改打印级别
-
查看当前打印级别:
cat /proc/sys/kernel/printk
-
打印级别的含义:
- 第一个数字:终端的级别。
- 第二个数字:消息的默认级别。
- 第三个数字:终端的最大级别。
- 第四个数字:终端的最小级别。
-
修改系统默认的级别:
su root echo 4 3 1 7 > /proc/sys/kernel/printk
-
添加修改级别命令:
echo 4 3 1 7 > /proc/sys/kernel/printk
打印级别含义
- 终端的级别:只有当消息的级别大于或等于终端级别时,消息才会在终端上显示。
- 消息的默认级别:如果没有特别指定,消息将采用此级别。
- 终端的最大级别:终端可以显示的最高级别。
安装驱动和卸载驱动时,消息会打印。
驱动多文件编译
示例
-
文件列表:
hello.c
add.c
-
Makefile:
obj-m := demo.o demo-y += hello.o add.o
-
说明:
-y
作用:将hello.o
和add.o
文件合并到demo.o
中。- 最终生成:
demo.ko
文件。
模块传递参数
命令行传递参数
- 命令示例:
sudo insmod demo.ko hello world
支持的数据类型
- 标准类型:
byte
,short
,ushort
,int
,uint
,long
,ulong
charp
: 字符串指针bool
: 布尔值,接受0/1
,y/n
,Y/N
invbool
: 布尔值,接受0/1
,y/n
,Y/N
,但意义相反(N
表示真)
module_param 函数
- 函数原型:
module_param(name, type, perm);
- 参数:
name
: 变量的名字。type
: 变量的类型。perm
: 权限,如0664
,0775
。
MODULE_PARM_DESC 函数
- 函数原型:
MODULE_PARM_DESC(_parm, desc);
- 参数:
_parm
: 变量。desc
: 描述字段。
示例
-
命令行参数:
sudo insmod hello.ko a=20 b=30 c=65 p="hello_world"
-
注意事项:
- 传递字符时使用 ASCII 码值。
- 传递字符串时不能包含空格。
module_param_array 函数
- 函数原型:
module_param_array(name, type, nump, perm);
- 参数:
name
: 数组名。type
: 数组的类型。nump
: 参数的个数,变量的地址。perm
: 权限。
练习:
1.byte类型如何使用 (传递参数用ascii)
2.如何给一个指针传递一个字符串
- 命令行参数:
sudo insmod hello.ko a=121 b=10 c=65 p="hello" ww=1,2,3,4,5
传参成功~
字符设备驱动
Linux系统中一切皆文件
-
应用层:
fd = open("led驱动的文件", O_RDWR); read(fd); write(fd); close(fd);
-
内核层:
- 驱动文件:
led_driver.c
- 驱动函数:
driver_open(); driver_read(); driver_write(); driver_close();
- 驱动文件:
-
结构体定义:
struct file_operations {int (*open)(struct inode *, struct file *);ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);int (*release)(struct inode *, struct file *); ;
-
设备号:
- 32位无符号数字:
- 高12位:主设备号,用于区分设备类别。
- 低20位:次设备号,用于区分同一类别中的不同设备。
- 32位无符号数字:
-
硬件层:
- LED、UART、ADC、PWM 等设备。
字符设备驱动步骤
- 注册字符设备驱动 - 得到一个字符设备驱动的框架,并获得设备号。
- 确定操作的硬件设备 - 如 LED 灯(初始化灯)。
- 初始化灯 - 建立灯实际物理地址和虚拟地址之间的映射。
- 用户空间与内核空间数据交互 - 当用户使用时,驱动会被真正运行,涉及数据交互。
- 在应用层创建设备文件(设备节点)。
字符设备驱动的注册
-
函数原型:
int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);
-
参数:
major
:主设备号。- 如果填写的值大于0,它认为这个就是主设备号。
- 如果填写的值为0,操作系统会分配一个主设备号。
name
:设备名称。fops
:操作方法结构体。
-
返回值:
major > 0
:成功返回0,失败返回错误码(负数)。major = 0
:成功返回分配的主设备号,失败返回错误码(负数)。
-
查看设备信息:
cat /proc/devices
字符设备驱动的注销
-
函数原型:
void unregister_chrdev(unsigned int major, const char *name);
-
参数:
major
:主设备号。name
:设备名称。
-
返回值:无。
就分享到这,希望可以帮到你吧~
相关文章:

ARM 裸机与 Linux 驱动对比及 Linux 内核入门
目录 ARM裸机代码和驱动的区别 Linux系统组成 内核五大功能 设备驱动分类 内核类型 驱动模块 驱动模块示例 Makefile配置 命令 编码辅助工具 内核中的打印函数 printk 函数 修改打印级别 编辑 打印级别含义 驱动多文件编译 示例 模块传递参数 命令行传递参数…...
0101DNS TCP fallback on UDP query timeout disabled-redission-中间件
文章目录 1.问题描述2.临时解决方案 结语 1.问题描述 Springcloud 项目,微服务模块使用redission,启动报错 DNS TCP fallback on UDP query timeout disabled. Upgrade Netty to 4.1.105 or higher.相关软件版本如下 软件版本描述springboot2.7.18spr…...
位运算
x1010 原码:000...1010 (一共32位) 反码:111...0101 (~x) 补码:111...0110 (反码1)(-x) 1、n 的二进制表示中第 k 位是几 #include<iost…...

MemFire Cloud是否真的可以取代后端
近年来,随着前端技术的迅速发展,前端工程师们越来越多地开始思考一个问题:“我还能不能不依赖后端?” 这种想法并非空穴来风,尤其是随着像MemFire Cloud这样的工具出现,它不仅能让开发者在没有后端的情况下…...

数据结构(邓俊辉)学习笔记】优先级队列 06——完全二叉堆:批量建堆
文章目录 1. 自上而下的上滤:算法2. 自上而下的上滤:效率3. 自下而上的下滤:算法4. 自下而上的下滤:实例5. 自下而上的下滤:效率 1. 自上而下的上滤:算法 在介绍过完全二叉堆标准的静态和动态操作接口之后…...

Java | Leetcode Java题解之第344题反转字符串
题目: 题解: class Solution {public void reverseString(char[] s) {int n s.length;for (int left 0, right n - 1; left < right; left, --right) {char tmp s[left];s[left] s[right];s[right] tmp;}} }...

定制开发AI智能名片O2O商城小程序:基于限量策略与个性化追求的营销创新
摘要:随着科技的飞速发展和消费者需求的日益多元化,传统商业模式正经历着前所未有的变革。在数字化转型的大潮中,定制开发AI智能名片O2O商城小程序作为一种新兴的商业模式,凭借其独特的个性化定制能力、高效的线上线下融合(O2O&am…...

Spring MVC Controller返回json日期格式配置失效的解决办法
如题,Spring MVC 4.3.0版本,配置jackson读写json。Controller层方法返回值对象包含java.util.Date类型的属性,并且在applicationContext.xml中配置了jackson的日期格式: <mvc:annotation-driven><mvc:message-converters…...

3.Default Constructor的构造操作
目录 1. 问题引入 2. 4种implicitly声明的default constructor 1. 问题引入 “default constructors......在需要的时候被编译产生出来”。关键词是“在需要的时候”,被谁需要,做什么事情?看看下面的代码,然后梳理下思路。 cl…...
CSS的:current伪类:精准定位当前活动元素
CSS(层叠样式表)是控制网页样式的核心语言。随着CSS4的提出,一系列新的选择器被引入,其中:current伪类便是这些新特性之一。:current伪类允许开发者选择当前处于活动状态的元素,这在创建动态和交互性网页时非常有用。本…...
搭建个人网站
一 个人搭建网站需要进行的操作 详细步骤: 1 网站目标:搭建在线查看法拍房拍卖价格的预测模型,输出预测结果 2 实际功能:在线爬取 阿里法拍网站的信息 3 根据实时模型建模预测法拍价格和成交概率 要搭建一个能够在线查看法拍房拍卖…...

机器学习课程学习周报八
机器学习课程学习周报八 文章目录 机器学习课程学习周报八摘要Abstract一、机器学习部分1.1 self-attention的计算量1.2 人类理解代替自注意力计算1.2.1 Local Attention/Truncated Attention1.2.2 Stride Attention1.2.3 Global Attention1.2.4 聚类Query和Key 1.3 自动选择自…...

福泰轴承股份有限公司进销存系统pf
TOC springboot413福泰轴承股份有限公司进销存系统pf 绪论 1.1 研究背景 现在大家正处于互联网加的时代,这个时代它就是一个信息内容无比丰富,信息处理与管理变得越加高效的网络化的时代,这个时代让大家的生活不仅变得更加地便利化&#…...

【k8s从节点报错】error: You must be logged in to the server (Unauthorized)
k8s主节点可以获取nodes节点信息,但是从节点无法获取,且报错“error: You must be logged in to the server (Unauthorized)” 排查思路: 当时证书过期了,只处理的主节点的证书过期,没有处理从节点的 kubeadm alpha …...

风清扬/基于Java语言的光伏监控系统+光伏发电预测+光伏项目+光伏运维+光伏储能项目
基于Java语言的光伏监控系统光伏发电预测光伏项目光伏运维光伏储能项目 介绍 基于Java语言的光伏监控系统光伏发电系统光伏软件系统光伏监控系统源码光伏发电系统源码 基于Java语言的光伏监控系统光伏发电预测光伏项目光伏运维光伏储能项目 安装教程 参与贡献 Fork 本仓库新…...

Datawhale X 魔搭 AI夏令营第四期 魔搭-AIGC方向全过程笔记
task1: 传送门 task2: 传送门 task3: 传送门 目录 Task1 赛题内容 可图Kolors-LoRA风格故事挑战赛 baseline要点讲解(请配合Datawhale速通教程食用) Step1 设置算例及比赛账号的报名和授权 Step2 进行赛事报名并创建PAI实例 Step3 执行baseline Step4…...

数组---怎么样定义和引用数组
一怎么定义数组 例 int a[10]; //定义了一个一维数组,数组名为a,此数组包含10个整型元素 所以我们了解到数组的基本定义为 类型符 数组名 [常量表达式] 定义数组可以包括常量和符号常量如 int [ 35 ];但是不能利用变量定义如 int n; …...
Nginx—Rewrite
目录 一、Nginx—Rewrite概述 1、常用的Nginx正则表达式 2、Rewrite功能 3、Rewrite跳转实现 4、Rewrite执行顺序和语法格式 二、location概述 1、location分类 2、location 常用的匹配规则 3、location 优先级 案例一: 案例二: 案例三&…...

《深入浅出WPF》读书笔记.5控件与布局(上)
《深入浅出WPF》读书笔记.5控件与布局(上) 背景 深入浅出WPF书籍学习笔记附代码。WPF中数据是核心是主动的,UI是数据的表达是被动的。 程序的本质是数据算法;控件的本质是数据行为; 5.控件与布局 一、6类控件派生关系 1.布局控件:可以容纳多个控件…...

二叉树的判断
二叉树的判断 判断一颗二叉树是不是搜索二叉树 (左边的比根小,右边的比根大) 中序遍历一下,如果是的话就一定是升序的 如何判断一颗二叉树是否是完全二叉树 1.遍历任意的节点时候,如果返回右孩子没有左孩子&#x…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...

mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...