news 2026/6/10 15:30:58

[Linux外设驱动详解]Linux 设备模型与 sysfs 机制深度分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[Linux外设驱动详解]Linux 设备模型与 sysfs 机制深度分析

Linux 设备模型与 sysfs 机制深度分析

前言

本文档基于 Linux 内核源码(RK3588 平台),系统梳理 Linux 设备模型的核心机制,重点讲解kobject、kset、ktype以及sysfs 文件系统的工作原理。内容面向初学者,结合源码示例和流程图,帮助理解内核如何通过/sys暴露设备属性。


目录

  1. 概述
  2. kobject 机制
  3. kset 机制
  4. kobj_type 机制
  5. sysfs 文件系统
  6. 设备属性暴露机制
  7. 完整示例

1. 概述

1.1 为什么需要设备模型?

Linux 设备模型是为了解决以下问题:

  • 统一管理:所有设备(CPU、内存、外设)用统一的数据结构表示
  • 层次组织:设备之间有父子关系(如 PCI 总线下的设备)
  • 用户空间可见:通过/sys暴露设备信息和配置接口
  • 热插拔支持:设备动态添加/删除时自动通知用户空间
  • 电源管理:统一的设备电源状态管理

1.2 核心组件关系图

┌─────────────────────────────────────────────────────────────┐ │ Linux 设备模型架构 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ kobject │────▶│ kset │────▶│ ktype │ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │ │ │ │ 内嵌 │ 包含 │ 描述 │ │ ▼ ▼ ▼ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ device │ │bus_type │ │sysfs_ops│ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │ │ │ └───────────────┴───────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ sysfs │ │ │ │ (/sys 文件) │ │ │ └─────────────────┘ │ └─────────────────────────────────────────────────────────────┘

关系说明

  • kobject是所有设备对象的基础结构
  • ksetkobject集合,提供统一的 uevent 处理
  • ktype定义kobject行为(如何释放、如何处理属性)
  • devicekobject扩展,代表实际设备
  • sysfskobject树暴露到用户空间

2. kobject 机制

2.1 kobject 结构定义

文件位置:kernel/include/linux/kobject.h:65-86

structkobject{constchar*name;// 对象名称(对应 sysfs 目录名)structlist_headentry;// 链表节点(用于加入 kset)structkobject*parent;// 父对象(形成层次结构)structkset*kset;// 所属的 ksetstructkobj_type*ktype;// 对象类型(定义行为)structkernfs_node*sd;// sysfs 目录项指针structkrefkref;// 引用计数// 状态标志位unsignedintstate_initialized:1;// 是否已初始化unsignedintstate_in_sysfs:1;// 是否已在 sysfs 中unsignedintstate_add_uevent_sent:1;// 是否已发送 ADD 事件unsignedintstate_remove_uevent_sent:1;// 是否已发送 REMOVE 事件unsignedintuevent_suppress:1;// 是否抑制 uevent};

字段详解

字段作用类比
name对象名称文件名
parent父对象父目录
kset所属集合文件夹分组
ktype类型描述文件类型定义
sdsysfs 目录项实际的目录 inode
kref引用计数使用计数

2.2 kobject 生命周期

流程图

┌──────────────┐ │ 定义 kobject │ └──────┬───────┘ │ ▼ ┌──────────────┐ │kobject_init()│ ◀── 必须先初始化 │ 设置 ktype │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ kobject_add() │ ◀── 添加到层次结构 │ 创建 sysfs │ └──────┬───────┘ │ ┌──────┴───────┐ │ │ ▼ ▼ ┌───────────┐ ┌───────────┐ │正常使用期间 │ │ 引用计数 │ │ 通过 get/put│ │ 管理 │ └─────┬─────┘ └─────┬─────┘ │ │ └───────┬───────┘ │ ▼ ┌──────────────┐ │kobject_put() │ ◀── 引用计数归零 │ 调用 release │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 自动释放 │ │ (由 ktype │ │ 的 release) │ └──────────────┘

2.3 核心函数源码分析

2.3.1 kobject_init()

文件位置:kernel/lib/kobject.c:349-376

voidkobject_init(structkobject*kobj,structkobj_type*ktype){if(!kobj){pr_err("invalid kobject pointer!\n");return;}if(!ktype){pr_err("must have a ktype!\n");return;}if(kobj->state_initialized){pr_err("tried to init an initialized object!\n");dump_stack();}// 1. 初始化引用计数kobject_init_internal(kobj);// kref_init(&kobj->kref)// 2. 关联类型kobj->ktype=ktype;}

要点

  • 必须提供ktype,定义了对象的行为
  • 初始化引用计数为 1
  • 不能重复初始化
2.3.2 kobject_add()

文件位置:kernel/lib/kobject.c:426-447

intkobject_add(structkobject*kobj,structkobject*parent,constchar*fmt,...){if(!kobj->state_initialized){pr_err("tried to add an uninitialized object!\n");return-EINVAL;}// 设置名称(支持 printf 格式)va_start(args,fmt);retval=kobject_set_name_vargs(kobj,fmt,args);va_end(args);// 内部添加逻辑returnkobject_add_internal(kobj);}

内部添加流程(kobject_add_internal):

staticintkobject_add_internal(structkobject*kobj){structkobject*parent=kobj->parent;// 1. 如果有 kset,加入 kset 的链表if(kobj->kset){if(!parent)parent=&kobj->kset->kobj;// 用 kset 的 kobject 作为父对象kobj_kset_join(kobj);// 加入 kset->list}// 2. 创建 sysfs 目录error=create_dir(kobj);// sysfs_create_dir_ns()if(error)gotoerr_out;// 3. 标记已加入 sysfskobj->state_in_sysfs=1;return0;}
2.3.3 kobject_put()

文件位置:kernel/lib/kobject.c:746-756

voidkobject_put(structkobject*kobj){if(kobj){if(!kobj->state_initialized)WARN(1,"kobject is not initialized!\n");kref_put(&kobj->kref,kobject_release);// 减少引用计数}}

释放流程

staticvoidkobject_release(structkref*kref){structkobject*kobj=container_of(kref,structkobject,kref);// 1. 如果还在 sysfs 中,先删除if(kobj->state_in_sysfs)__kobject_del(kobj);// 删除 sysfs 目录// 2. 调用 ktype 的 release 函数if(kobj->ktype&&kobj->ktype->release)kobj->ktype->release(kobj);// 3. 释放名称字符串kfree_const(kobj->name);}

2.4 kobject 路径获取

函数kobject_get_path()→ 返回完整路径(如/devices/platform/serial8250

示例

char*path=kobject_get_path(my_kobj,GFP_KERNEL);printk("Path: %s\n",path);// 输出: /sys/devices/...kfree(path);

3. kset 机制

3.1 kset 结构定义

文件位置:kernel/include/linux/kobject.h:203-213

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 14:00:02

45分钟从零构建企业级智能管理平台:SmartAdmin实战部署全流程

45分钟从零构建企业级智能管理平台:SmartAdmin实战部署全流程 【免费下载链接】smart-admin SmartAdmin国内首个以「高质量代码」为核心,「简洁、高效、安全」中后台快速开发平台;基于SpringBoot2/3 Sa-Token Mybatis-Plus 和 Vue3 Vite5 …

作者头像 李华
网站建设 2026/6/9 14:00:00

纯粹直播终极指南:从零到精通的5分钟完全掌握手册

纯粹直播终极指南:从零到精通的5分钟完全掌握手册 【免费下载链接】pure_live 纯粹直播:哔哩哔哩/虎牙/斗鱼/快手/抖音/网易cc/M38自定义源应有尽有。 项目地址: https://gitcode.com/gh_mirrors/pur/pure_live 在当今多媒体时代,能够一站式观看全…

作者头像 李华
网站建设 2026/6/9 15:18:46

NAPS2:告别纸质文档困扰,开启高效数字化办公新时代

NAPS2:告别纸质文档困扰,开启高效数字化办公新时代 【免费下载链接】naps2 Scan documents to PDF and more, as simply as possible. 项目地址: https://gitcode.com/gh_mirrors/na/naps2 还在为办公桌上堆积如山的纸质文件而头疼吗?…

作者头像 李华
网站建设 2026/6/9 15:20:31

结合PyCharm开发环境调用Qwen3Guard-Gen-8B API接口示例

结合PyCharm开发环境调用Qwen3Guard-Gen-8B API接口示例 在当今生成式AI迅猛发展的背景下,大语言模型(LLM)正广泛应用于智能客服、内容创作、虚拟助手等场景。然而,随之而来的安全风险也日益突出:恶意诱导、不当言论、…

作者头像 李华
网站建设 2026/6/9 15:20:24

高效下载B站资源:B23Downloader实战精通指南

高效下载B站资源:B23Downloader实战精通指南 【免费下载链接】B23Downloader (已长久停更) 项目地址: https://gitcode.com/gh_mirrors/b2/B23Downloader 还在为无法离线观看B站视频而烦恼吗?B23Downloader作为一款专业的视…

作者头像 李华
网站建设 2026/6/9 15:22:28

JLink驱动安装无法识别?一文说清所有可能原因

JLink驱动安装无法识别?别急,一步步带你排完所有坑 你有没有遇到过这样的场景:刚插上J-Link调试器,满怀期待打开Keil或STM32CubeIDE,结果发现设备管理器里多了一个“未知设备”——连名字都叫不出来,更别说…

作者头像 李华