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.cadd.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,ulongcharp: 字符串指针bool: 布尔值,接受0/1,y/n,Y/Ninvbool: 布尔值,接受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…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

