理解字符设备、设备模型与子系统:以 i.MX8MP 平台为例

news2025/4/23 10:43:21

视频教程请关注 B 站:“嵌入式 Jerry”


Linux 内核驱动开发中,很多人在接触字符设备(char device)、设备模型(device model)和各种子系统(subsystem)时,往往会感到概念混杂,边界模糊。本文将从 Linux 驱动体系架构的演化入手,结合 NXP 的 i.MX 8M Plus EVK 平台(下文简称 i.MX8MP-EVK),深入讲解这三者的关系、用途与实际代码的融合方式,帮助你彻底理解这些核心概念。


在这里插入图片描述

一、历史与基础概念

1.1 字符设备(Character Device)

字符设备是 Linux 设备类型之一,另一种是块设备(Block Device)。字符设备以字节为单位进行读写,接口类似于普通文件,通过 read()write()ioctl() 等系统调用进行操作。

  • 常见字符设备:串口(serial)、GPIO、I2C、PWM、Watchdog 等。
  • 管理结构:主要由 struct file_operationsstruct cdev 控制,最终通过 register_chrdev_region()cdev_add() 注册到系统。

1.2 设备模型(Device Model)

Linux 为了实现设备与驱动的自动匹配、热插拔管理、sysfs 显示,设计了一套统一的设备模型架构,包括以下关键结构:

  • struct device
  • struct driver
  • struct bus_type
  • struct class

这套模型抽象了“设备是如何插到系统里的、驱动如何找到设备、如何在用户空间体现出设备结构”等问题。

设备模型的意义在于:“它是一种运行时的驱动与设备匹配与管理框架”。

1.3 子系统(Subsystem)

“子系统”是指内核中具有统一接口规范的功能模块,例如:

  • I2C 子系统
  • SPI 子系统
  • PWM 子系统
  • regulator 子系统
  • input 子系统
  • sound 子系统

每个子系统背后都有一个核心的框架代码,并暴露出标准接口(如 struct pwm_chipstruct i2c_driver 等),驱动开发者按照接口标准进行设备适配即可。

子系统的意义在于:“统一了设备驱动的行为规范和上层调用方式,是设备模型的具体实现与应用场景”。


二、三者关系的准确理解

我们通过一个类比来帮助你理解三者关系:

类别类比解释实际作用
字符设备老式收音机,直接接电可用最基本的驱动编程方式
设备模型家庭电网管理系统让每台收音机能统一开关、统一命名、自动识别
子系统不同的电台频道系统(如 FM/AM)为收音机统一音频标准接口、设置方法等

正确理解:

  • 设备模型并不是“设备驱动的替代品”,而是驱动与设备的匹配系统。
  • 字符设备可裸用,也可嵌入子系统内部。
  • 子系统是专用领域的模型扩展,基于设备模型构建的统一抽象。

三、实战解析:以 i.MX8MP 的 PWM 驱动为例

NXP 的 pwm-imx27 驱动是一个非常典型的子系统 + 设备模型驱动的代表。下面我们从设备树、驱动代码到字符接口逐步解析。

3.1 设备树定义(设备描述)

arch/arm64/boot/dts/freescale/imx8mp-evk.dts 中:

&pwm1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_pwm1>;
    status = "okay";
};

说明:pwm1 控制器启用,绑定了特定管脚。

3.2 驱动注册过程(platform_device + pwm_chip)

驱动源码文件:drivers/pwm/pwm-imx27.c

注册入口:

static struct platform_driver imx_pwm_driver = {
    .driver = {
        .name = "pwm-imx27",
        .of_match_table = pwm_imx27_dt_ids,
    },
    .probe = pwm_imx27_probe,
};
module_platform_driver(imx_pwm_driver);

核心结构:

struct pwm_imx27_chip {
    struct pwm_chip chip; // 属于PWM子系统的驱动注册入口
    ...
};

pwm_chip 是子系统定义的结构体,其 ops 字段中定义了 .apply.get_state 等操作接口。

然后调用:

return devm_pwmchip_add(&pdev->dev, &imx->chip);

此函数实际上完成了驱动注册到子系统 + 注册 sysfs 接口 + device model 挂载等多个功能。

3.3 sysfs 与字符设备的区别

尽管 pwm-imx27 没有 register_chrdevcdev_add,但它通过子系统自动创建了 sysfs 接口,例如:

/sys/class/pwm/pwmchip0/

这意味着控制 PWM 不再依赖传统字符设备节点 /dev/pwm0,而是通过标准 pwm 子系统提供的统一 sysfs 文件操作。


四、对比分析:没有子系统的字符设备

若驱动不走子系统,例如传统的 LED 控制驱动,则需要手动注册字符设备:

register_chrdev_region();
cdev_init();
cdev_add();

并创建 /dev/xxx 节点,再通过 open/read/write/ioctl 实现访问。

优缺点对比

特性传统字符设备子系统驱动(如 PWM)
注册方式register_chrdev + cdevpwmchip_add 等
用户访问方式/dev/xxxsysfs + standard API
是否自动匹配设备
是否统一接口
开发复杂度中等略高(但标准)

五、设备模型:驱动背后的系统机制

Linux 驱动之所以能做到自动识别设备、按需加载驱动,靠的就是设备模型架构。

5.1 总线(bus_type)

  • platform 总线:用于板载设备(PWM、I2C、SPI)
  • usb 总线:用于外设热插拔设备
  • pci 总线:用于 PC 设备识别与枚举

所有子系统最终都依赖某种 bus 类型与设备模型框架。

5.2 匹配过程(match)

设备模型按照:

  • .of_match_table(设备树匹配)
  • .id_table(非设备树匹配)

来完成 devicedriver 的自动匹配与调用 probe。


六、结语与建议

6.1 学习建议

  • 新手建议从字符设备入手,理解基础接口。
  • 进阶阶段要深入了解设备模型与 sysfs 接口。
  • 若目标是嵌入式设备驱动,应熟练掌握子系统开发接口(如 I2C/SPI/PWM 等子系统结构)。

6.2 总结结构图

           +------------------------+
           |     用户空间接口       |
           +------------------------+
                     ↑
          +-------------------------+
          |     sysfs / /dev 节点    |
          +-------------------------+
                     ↑
        +----------------------------+
        |  子系统接口(如 PWM/SPI)   |
        +----------------------------+
                     ↑
         +---------------------------+
         |  设备模型(device model) |
         +---------------------------+
                     ↑
         +--------------------------+
         |   platform/PCI/... bus   |
         +--------------------------+

附录:i.MX8MP 平台相关驱动推荐阅读

  • drivers/pwm/pwm-imx27.c:PWM 控制器驱动
  • drivers/regulator/pca9450-regulator.c:PMIC 驱动
  • drivers/i2c/busses/i2c-imx.c:I2C 控制器驱动

视频教程请关注 B 站:“嵌入式 Jerry”

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

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

相关文章

鸿蒙Flutter仓库停止更新?

停止更新 熟悉 Flutter 鸿蒙开发的小伙伴应该知道&#xff0c;Flutter 3.7.12 鸿蒙化 SDK 已经在开源鸿蒙社区发布快一年了&#xff0c; Flutter 3.22.x 的鸿蒙化适配一直由鸿蒙突击队仓库提供&#xff0c;最近有小伙伴反馈已经 2 个多月没有停止更新了&#xff0c;不少人以为停…

网络基础概念(下)

网络基础概念&#xff08;上&#xff09;https://blog.csdn.net/Small_entreprene/article/details/147261091?sharetypeblogdetail&sharerId147261091&sharereferPC&sharesourceSmall_entreprene&sharefrommp_from_link 网络传输的基本流程 局域网网络传输流…

一个关于相对速度的假想的故事-4

回到公式&#xff0c; 正写速度叠加和倒写速度叠加的倒写相等&#xff0c;这就是这个表达式所要表达的意思。但倒写叠加用的是减法&#xff0c;而正写叠加用的是加法。当然是这样&#xff0c;因为正写叠加要的是单位时间上完成更远的距离&#xff0c;而倒写叠加说的是单位距离需…

Idea创建项目的搭建方式

目录 一、普通Java项目 二、普通JavaWeb项目 三、maven的JavaWeb项目 四、maven的Java项目 一、普通Java项目 1. 点击 Create New Project 2. 选择Java项目&#xff0c;选择JDK&#xff0c;点击Next 3. 输入项目名称&#xff08;驼峰式命名法&#xff09;&#xff0c;可选…

【DeepSeek 学习推理】Llumnix: Dynamic Scheduling for Large Language Model Serving实验部分

6.1 实验设置 测试平台。我们使用阿里云上的16-GPU集群&#xff08;包含4个GPU虚拟机&#xff0c;类型为ecs.gn7i-c32g1.32xlarge&#xff09;。每台虚拟机配备4个NVIDIA A10&#xff08;24 GB&#xff09;GPU&#xff08;通过PCI-e 4.0连接&#xff09;、128个vCPU、752 GB内…

Kubernetes相关的名词解释kubeadm(19)

kubeadm是什么&#xff1f; kubeadm 是 Kubernetes 官方提供的一个用于快速部署和管理 Kubernetes 集群的命令行工具。它简化了集群的初始化、节点加入和升级过程&#xff0c;特别适合在生产环境或学习环境中快速搭建符合最佳实践的 Kubernetes 集群。 kubeadm 的定位 不是完整…

什么是负载均衡?NGINX是如何实现负载均衡的?

大家好&#xff0c;我是锋哥。今天分享关于【什么是负载均衡&#xff1f;NGINX是如何实现负载均衡的&#xff1f;】面试题。希望对大家有帮助&#xff1b; 什么是负载均衡&#xff1f;NGINX是如何实现负载均衡的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源…

基于Python(Django)+SQLite实现(Web)校园助手

校园助手 本校园助手采用 B/S 架构。并已将其部署到服务器上。在网址上输入 db.uplei.com 即可访问。 使用说明 可使用如下账号体验&#xff1a; 学生界面: 账号1&#xff1a;123 密码1&#xff1a;123 账户2&#xff1a;201805301348 密码2&#xff1a;1 # --------------…

从零开始搭建Django博客②--Django的服务器内容搭建

本文主要在Ubuntu环境上搭建&#xff0c;为便于研究理解&#xff0c;采用SSH连接在虚拟机里的ubuntu-24.04.2-desktop系统搭建&#xff0c;当涉及一些文件操作部分便于通过桌面化进行理解&#xff0c;通过Nginx代理绑定域名&#xff0c;对外发布。 此为从零开始搭建Django博客…

【读论文】HM-RAG:分层多智能体多模态检索增强生成

如何在多模态信息检索和生成中&#xff0c;通过协作式多智能体系统来处理复杂的多模态查询。传统的单代理RAG系统在处理需要跨异构数据生态系统进行协调推理的复杂查询时存在根本性限制:处理多种查询类型、数据格式异质性和检索任务目标的多样性&#xff1b;在视觉内容和文本内…

文件操作和IO(上)

绝对路径和相对路径 文件按照层级结构进行组织&#xff08;类似于数据结构中的树型结构&#xff09;&#xff0c;将专门用来存放管理信息的特殊文件称为文件夹或目录。对于文件系统中文件的定位有两种方式&#xff0c;一种是绝对路径&#xff0c;另一种是相对路径。 绝对路径…

JavaFX深度实践:从零构建高级打地鼠游戏(含多物品与反馈机制)

大家好&#xff01;经典的“打地鼠”游戏是许多人童年的回忆&#xff0c;也是学习 GUI 编程一个非常好的切入点。但仅仅是“地鼠出来就打”未免有些单调。今天&#xff0c;我们来点不一样的——用 JavaFX 打造一个高级版的打地鼠游戏&#xff01;在这个版本中&#xff0c;洞里钻…

Python 简介与入门

目录 一、Python 初识 1、Python 的优势 2、Python 的特性 3、Python 的应用领域 二、Linux 环境中安装 Python 1、下载 Python3.11.6 2、安装依赖包 3、解压 Python 压缩包 4、安装 Python 5、编译及安装 6、建立软链接 7、测试 Python3 运行 8、设置国内 pip 更…

理解RAG第六部分:有效的检索优化

在RAG系统中&#xff0c;识别相关上下文的检索器组件的性能与语言模型在生成有效响应方面的性能同样重要&#xff0c;甚至更为重要。因此&#xff0c;一些改进RAG系统的努力将重点放在优化检索过程上。 从检索方面提高RAG系统性能的一些常见方法。通过实施高级检索技术&#x…

实训Day-2 流量分析与安全杂项

目录 实训Day-2-1流量分析实战 实训目的 实训任务1 SYN半链接攻击流量分析 实训任务2 SQL注入攻击流量分析一 实训任务3 SQL注入攻击流量分析二 实训任务4 Web入侵溯源一 实训任务5 Web入侵溯源二 ​编辑 实训Day-2-1安全杂项实战 实训目的 实训任务1 流量分析 FTP…

几种电气绝缘类型

1. 基本绝缘 1.1 绝缘等级 1.2 I类设备 2. 附加绝缘 3. 双重绝缘 4. 加强绝缘 5. 功能性绝缘 1. 基本绝缘 用于防止触及带电部件的初级保护,该防护是由绝缘材料完成的 基本绝缘的目的在于为防电击提供一个基本的保护,以避免触电的危险,不过此类绝缘只能保证正常状态下…

char32_t、char16_t、wchar_t 用于 c++ 语言里存储 unicode 编码的字符,给出它们的具体定义

&#xff08;1&#xff09; #include <iostream> #include <string>int main() { std::u16string s u"C11 引入 char16_t"; // 定义 UTF-16 字符串for (char16_t c : s) // 遍历输出每个 char16_t 的值std::cout << std::hex << (…

Java Set/List 知识点 Java面试 基础面试题

Java Set/List 知识点 Set与List区别 List 有序、值可重复,内部数据结构 Obejct[ ] 数组Set 无序、值不重复,内部数据结构 HashMap keyobject value固定new Object() ArrayList 有序存储元素允许元素重复&#xff0c;允许存储 null 值支持动态扩容非线程安全 HashSet、LinkedHa…

Oracle Database Resident Connection Pooling (DRCP) 白皮书阅读笔记

本文为“Extreme Oracle Database Connection Scalability with Database Resident Connection Pooling (DRCP)”的中文翻译加阅读笔记。觉得是重点的就用粗体表示了。 白皮书版本为March 2025, Version 3.3&#xff0c;副标题为&#xff1a;Optimizing Oracle Database resou…

FastAPI WebSocket 聊天应用详细教程

项目简介 这是一个基于 FastAPI 和 WebSocket 实现的实时聊天应用&#xff0c;支持一对一聊天、离线消息存储等功能。 技术栈 后端&#xff1a;FastAPI (Python)前端&#xff1a;HTML、JavaScript、CSS通信&#xff1a;WebSocket认证&#xff1a;简单的 token 认证 项目结构…