news 2026/6/22 11:09:36

[Linux外设驱动详解]第一部分:基础篇 —— 驱动开发入门

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[Linux外设驱动详解]第一部分:基础篇 —— 驱动开发入门

Linux 设备驱动开发入门指南

硬件平台: 瑞芯微 RK3588
源码路径:

  • U-Boot:./u-boot
  • Linux 内核:./kernel

目录

  1. 什么是 Linux 设备驱动
  2. Linux 内核模块机制
  3. 第一个字符设备驱动
  4. 源码分析实战
  5. 设备节点创建

1. 什么是 Linux 设备驱动

1.1 驱动程序的本质

设备驱动程序是连接 Linux 内核与硬件设备的桥梁,它为上层应用程序提供统一的访问接口,屏蔽底层硬件的具体实现细节。

┌─────────────────────────────────────────────────────────────┐ │ 用户空间 (User Space) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 应用程序 │ │ 应用程序 │ │ Shell │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ └─────────────────┼─────────────────┘ │ │ │ │ ├───────────────────────────┼───────────────────────────────────┤ │ 系统调用接口 │ (read, write, ioctl, etc.) │ ├───────────────────────────┼───────────────────────────────────┤ │ │ │ │ ┌────────────────────────▼─────────────────────────────┐ │ │ │ 内核空间 (Kernel Space) │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ │ │ VFS (虚拟文件系统) │ │ │ │ │ └────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ │ │ 设备驱动程序 (Driver) │ │ │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │ │ │ 字符设备│ │ 块设备 │ │ 网络设备│ │ │ │ │ │ │ └────────┘ └────────┘ └────────┘ │ │ │ │ │ └────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ │ │ 硬件抽象层 │ │ │ │ │ └────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ ├───────────────────────────┼───────────────────────────────────┤ │ 硬件设备 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ GPIO │ │ I2C │ │ SPI │ ... │ │ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────┘

关键点:

  • 用户空间程序通过系统调用访问设备
  • 驱动程序运行在内核空间,拥有最高权限
  • 设备文件(如/dev/gpio)是用户访问驱动的入口

1.2 设备驱动分类

Linux 系统将设备驱动分为三大类:

驱动类型特点访问方式典型设备源码位置
字符设备按字节流顺序访问,不支持随机访问read(),write(),ioctl()串口、GPIO、LED、键盘kernel/drivers/char/
块设备可随机访问,以数据块为单位文件系统接口硬盘、Flash、SD卡kernel/drivers/block/
网络设备处理网络数据包,不对应设备节点Socket 接口以太网、WiFi、蓝牙kernel/drivers/net/

字符设备 vs 块设备的核心区别:

// 字符设备:顺序访问,像水流一样/dev/tty → 只能顺序读写/dev/gpio → 按字节操作// 块设备:可随机访问任意位置/dev/sda → 可以跳到任意扇区/dev/mmcblk0 → 支持文件系统

2. Linux 内核模块机制

2.1 什么是内核模块

内核模块 (Kernel Module)是可以动态加载到内核中的代码,也称为 LKM (Loadable Kernel Module)。

优势:

  • 不需要重新编译整个内核
  • 按需加载,节省内存
  • 便于开发和调试

2.2 模块的生命周期

┌──────────────────────────────────────────────────────────────┐ │ 内核模块生命周期 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ insmod/modprobe │ │ │ │ │ ▼ │ │ ┌─────────┐ module_init() ┌─────────────┐ │ │ │ .ko 文件│ ─────────────────► │ 运行中 │ │ │ │(磁盘上) │ │ (内核内存) │ │ │ └─────────┘ └──────┬──────┘ │ │ │ │ │ │ 提供服务 │ │ ▼ │ │ ┌─────────┐ │ │ │ 设备操作 │ │ │ └─────────┘ │ │ │ │ │ rmmod │ │ │ │ │ │ │ ▼ │ │ │ module_exit() ◄───────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────┐ │ │ │ 卸载完成 │ │ │ └─────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘

2.3 模块编程基础

最简单的内核模块
#include<linux/init.h>// 宏定义#include<linux/module.h>// 模块核心头文件#include<linux/kernel.h>// 内核函数// 模块初始化函数 - 加载时执行staticint__inithello_init(void){printk(KERN_INFO"Hello: 模块已加载\n");return0;// 返回 0 表示成功}// 模块退出函数 - 卸载时执行staticvoid__exithello_exit(void){printk(KERN_INFO"Hello: 模块已卸载\n");}// 注册初始化和退出函数module_init(hello_init);module_exit(hello_exit);// 模块元信息MODULE_LICENSE("GPL");// 许可证声明 (必须)MODULE_AUTHOR("Your Name");// 作者MODULE_DESCRIPTION("简单模块");// 描述MODULE_VERSION("1.0");// 版本

宏说明:

  • __init: 函数在初始化后可被丢弃以节省内存
  • __exit: 函数仅在模块卸载时使用
  • module_init(): 指定模块加载入口
  • module_exit(): 指定模块卸载出口
模块加载与卸载命令
# 加载模块insmod hello.ko# 简单加载modprobe hello.ko# 智能加载(处理依赖)# 查看模块lsmod|grephello# 列出已加载模块modinfo hello.ko# 查看模块信息# 卸载模块rmmod hello# 移除模块# 查看内核日志dmesg|tail# 查看最近的内核消息dmesg|grepHello# 查看特定消息

2.4 printk 与内核日志

printk 是内核空间的 printf,用于输出调试信息。

日志级别
#defineKERN_EMERG"0"// 紧急情况:系统崩溃#defineKERN_ALERT"1"// 需要立即处理#defineKERN_CRIT"2"// 严重情况#defineKERN_ERR"3"// 错误#defineKERN_WARNING"4"// 警告#defineKERN_NOTICE"5"// 注意#defineKERN_INFO"6"// 信息#defineKERN_DEBUG"7"// 调试

使用示例:

printk(KERN_INFO"设备号: %d\n",major);// 信息级别printk(KERN_ERR"设备初始化失败: %d\n",ret);// 错误级别printk(KERN_DEBUG"调试信息: count=%u\n",count);// 调试级别// 简写形式(需要包含 <linux/printk.h>)pr_info("设备号: %d\n",major);pr_err("初始化失败: %d\n",ret);pr_debug("count=%u\n",count);
查看内核日志
# 实时查看内核日志dmesg-w# 持续监控dmesg-w|grepmy_driver# 过滤特定驱动# 控制台日志级别cat/proc/sys/kernel/printk# 查看当前级别echo8>/proc/sys/kernel/printk# 设置为调试级别

3. 第一个字符设备驱动

3.1 字符设备架构概览

┌───────────────────────────────────────────────────────────────┐ │ 字符设备驱动架构 │ ├───────────────────────────────────────────────────────────────┤ │ │ │ 用户空间 │ │ ┌─────────────┐ open("/dev/mydev") ┌──────────────┐ │ │ │ 应用程序 │ ─────────────────────► │ VFS 层 │ │ │ │ │ │ │ │ │ │ fd = open()│ read(fd, buf, len) │ 文件系统 │ │ │ │ read(fd) │ ─────────────────────► │ │ │ │ │ write(fd) │ └─
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 17:36:59

Vue3电商后台管理系统实战:从零到上线

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个电商后台管理系统&#xff0c;功能包括&#xff1a;1. 基于Vue3和Element Plus的UI框架&#xff1b;2. 多角色权限控制&#xff08;管理员、运营、客服&#xff09;&#…

作者头像 李华
网站建设 2026/6/22 8:48:11

GLM-4.6V-Flash-WEB在智能家居控制中的潜在用途

GLM-4.6V-Flash-WEB在智能家居控制中的潜在用途 在如今的智能家庭环境中&#xff0c;用户早已不满足于“喊一声开灯、再喊一声关空调”这种机械式的交互。我们真正期待的是一个能“看懂我家”的系统——它知道孩子放学后独自进了厨房&#xff0c;会主动提醒“检测到儿童接近灶…

作者头像 李华
网站建设 2026/6/22 8:46:00

GLM-4.6V-Flash-WEB能否识别赝品文物的细节破绽?

GLM-4.6V-Flash-WEB能否识别赝品文物的细节破绽&#xff1f; 在博物馆数字化浪潮席卷全球的今天&#xff0c;一件高仿青铜器悄然混入线上展览——表面绿锈斑驳、铭文古意盎然&#xff0c;连资深鉴定师初看也难辨真伪。然而&#xff0c;当这张图片被上传至一个基于AI的视觉分析系…

作者头像 李华
网站建设 2026/6/13 13:18:45

HBase与Hive集成:实现SQL查询HBase数据

HBase与Hive集成:实现SQL查询HBase数据 关键词:HBase、Hive、数据集成、外部表、SQL查询、列族映射、MapReduce 摘要:HBase是大数据领域的"高速抽屉"——擅长实时读写但查询功能薄弱;Hive是"数据菜谱"——能用SQL搞定复杂分析但不擅长实时存储。本文用…

作者头像 李华
网站建设 2026/6/20 17:30:33

GLM-4.6V-Flash-WEB助力在线教育平台实现智能批改

GLM-4.6V-Flash-WEB助力在线教育平台实现智能批改 在今天的在线教育平台上&#xff0c;一个看似简单的场景正变得越来越复杂&#xff1a;学生上传一张手写作业的照片——可能是数学题配几何图、物理实验的数据表格&#xff0c;也可能是语文阅读理解的圈画批注。教师需要逐一批阅…

作者头像 李华
网站建设 2026/6/19 21:42:36

arm64和x64参数传递方式详解:手把手教程

arm64 和 x64 参数传递机制详解&#xff1a;从底层看函数调用的差异与优化你有没有遇到过这样的情况——同一段 C 代码&#xff0c;在手机上跑得飞快&#xff0c;到了 PC 上却慢了一截&#xff1f;或者调试崩溃日志时&#xff0c;发现寄存器里的值“对不上号”&#xff1f;问题…

作者头像 李华