news 2026/1/17 15:57: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/1/15 10:23:12

RR 25.9.7:黑群晖引导技术全面解析与实战部署指南

RR 25.9.7:黑群晖引导技术全面解析与实战部署指南 【免费下载链接】rr Redpill Recovery (arpl-i18n) 项目地址: https://gitcode.com/gh_mirrors/rr2/rr 在NAS系统构建领域,黑群晖引导工具的技术演进正在重新定义DIY用户的系统部署体验。RR 25.9…

作者头像 李华
网站建设 2026/1/15 8:58:04

星火应用商店终极指南:让Linux软件安装变得简单快捷

星火应用商店终极指南:让Linux软件安装变得简单快捷 【免费下载链接】星火应用商店Spark-Store 星火应用商店是国内知名的linux应用分发平台,为中国linux桌面生态贡献力量 项目地址: https://gitcode.com/spark-store-project/spark-store 星火应…

作者头像 李华
网站建设 2026/1/11 3:39:15

星火应用商店:终结Linux软件安装困境的智能解决方案

星火应用商店:终结Linux软件安装困境的智能解决方案 【免费下载链接】星火应用商店Spark-Store 星火应用商店是国内知名的linux应用分发平台,为中国linux桌面生态贡献力量 项目地址: https://gitcode.com/spark-store-project/spark-store 还在为…

作者头像 李华
网站建设 2026/1/14 5:12:51

FreeGLUT完全指南:掌握跨平台OpenGL开发的核心利器

FreeGLUT完全指南:掌握跨平台OpenGL开发的核心利器 【免费下载链接】freeglut 项目地址: https://gitcode.com/gh_mirrors/free/freeglut 想要在Windows、Linux、macOS等不同操作系统上构建统一的OpenGL应用程序吗?FreeGLUT作为开源的OpenGL工具…

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

通过ms-swift实现多GPU资源调度的Kubernetes部署实践

通过ms-swift实现多GPU资源调度的Kubernetes部署实践 在大模型落地进入深水区的今天,企业面临的不再是“能不能训出来”的问题,而是“如何高效、稳定、低成本地把模型从实验环境推到生产线上”。尤其是在多GPU集群中运行Qwen3、Llama4这类百亿参数级模型…

作者头像 李华
网站建设 2026/1/10 14:26:45

告别繁琐PPT制作:Marp Next让你用Markdown轻松搞定专业演示

告别繁琐PPT制作:Marp Next让你用Markdown轻松搞定专业演示 【免费下载链接】marp The site of classic Markdown presentation writer app 项目地址: https://gitcode.com/gh_mirrors/ma/marp 还在为制作幻灯片而烦恼吗?传统演示软件复杂的操作界…

作者头像 李华