一文讲解Linux 设备模型 kobject,kset
设备驱动模型
面试的时候,有面试官会问,什么是Linux 设备驱动模型?你要怎么回答?
这个问题,突然这么一问,可能你会愣住不知道怎么回答,因为Linux 设备驱动模型是一个比较整体的概念,Linux 内核一半的代码都是设备驱动,怎么管理设备驱动,怎么抽象,怎么简化驱动开发的工作,这就是设备驱动模型要干的事情
其实你不懂也没关系,你反问下面试官,你是如何理解设备驱动模型的,虽然面试失败了,但是你学到东西了啊,岗位那么多,下一家可能就是你人生的巅峰呢。
Linux 设备驱动模型,说到这个部分,就不得不提几个重要的东西,BUS(总线),Class(类),Device(设备),Driver(驱动)。
Bus(总线): Linux 把总线设计成一个道路,所有的设备都都必须挂载在总线上面,你可以理解为,所有的车子都必须开在高速路上,要不然就不遵守规则了。
Class(分类): 在Linux设备模型中,Class的概念非常类似面向对象程序设计中的Class(类),它主要是集合具有相似功能或属性的设备,这样就可以抽象出一套可以在多个设备之间共用的数据结构和接口函数。块设备,字符设备,网络设备这些可以理解为大类。
Device(设备): 抽象系统中所有的硬件设备,描述它的名字、属性、从属的Bus、从属的Class等信息,我们正常些驱动,还会写上这个设备的一些硬件资源,中断口,复位口,I2C地址等等。
Device Driver(驱动): Linux设备模型用Driver抽象硬件设备的驱动程序,它包含设备初始化、电源管理相关的接口实现。而Linux内核中的驱动开发,基本都围绕该抽象进行(实现所规定的接口函数),如果有3个一样的设备,可以使用同一个驱动。

资料直通车:Linux内核源码技术学习路线+视频教程内核源码
学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈
kobject 是什么?
kobject 就是一个结构体而已,别看只是一个结构体,这个结构体可以说是串联了设备驱动里面的所有东西,设备驱动模型都是靠这个来穿针引线的,嗯,我觉得用穿针引线这个词语非常好,非常妙。每个kobject对应/sys/目录下面的一个目录,name指定的就是这个目录的名字。
struct kobject {const char *name;struct list_head entry;struct kobject *parent;struct kset *kset;struct kobj_type *ktype;struct kernfs_node *sd; /* sysfs directory entry */struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASEstruct delayed_work release;
#endifunsigned int state_initialized:1;unsigned int state_in_sysfs:1;unsigned int state_add_uevent_sent:1;unsigned int state_remove_uevent_sent:1;unsigned int uevent_suppress:1;
};
既然kobject是对应/sys/下面的一个目录,那么kset是什么呢?好吧,kset也就只是一个结构体而已,这个结构体里面引用了kobject,这个应该是C语言的巧妙之处,使用这样的方式实现继承的关系,我包含里的类型,使用起来就是kobject是我的基类,通过这个基类我再创造出一个新的类,这个类的名字就是kset,类那个是C++的说法,在C里面就是一个结构体了。仅此而已。
struct kset {struct list_head list; struct kobject kobj; struct kset_uevent_ops *uevent_ops;spinlock_t list_lock;};
既然我们知道 kobject是一个目录,那么kset是kobject的高级体,那么kset也就是一个目录,这个目录的名字也就是kobject来指定的,而且kset 里面有一个链表,可以看出来,kset就是一个类别的kobject的集合,比如bus目录下面,就全部是bus相关的,i2c是一个Bus,platform也是一个bus,等等。



container_of宏
之前写过文章说明这个宏的作用,分析了实现的过程,实际上就是一个,如果我们知道一个结构体成员变量,可以通过这个结构体成员变量获取这个结构体的指针。
container_of宏解析
#ifndef container_of
#define container_of(ptr, type, member) ({ \const typeof(((type *)0)->member) * __mptr = (ptr); \(type *)((char *)__mptr - offsetof(type, member)); })
#endif

实例分析
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>MODULE_AUTHOR("peiqi");
MODULE_LICENSE("Dual BSD/GPL");/*对应于kobject的目录下的一个文件,Name成员就是文件名*/
struct attribute test_attr = { .name = "kobj_test_config", .mode = S_IRWXUGO,
};static struct attribute *def_attrs[] = { &test_attr, NULL,
};/*当读文件时执行的操作*/
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
{ printk("kobj_test_show\n"); printk("attrname:%s.\n", attr->name); sprintf(buf,">>>:%s\n",attr->name); return strlen(attr->name)+2;
}/*当写文件时执行的操作*/
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
{ printk("kobj_test_store\n"); printk("<<<write: %s\n",buf); return count;
}
//kobject对象的操作
struct sysfs_ops obj_test_sysops =
{ .show = kobj_test_show, .store = kobj_test_store,
};/*release方法释放该kobject对象*/
void obj_test_release(struct kobject *kobject)
{ printk("obj_test_release: release .\n");
}/*定义kobject对象的一些属性及对应的操作*/
struct kobj_type ktype =
{ .release = obj_test_release, .sysfs_ops=&obj_test_sysops, .default_attrs=def_attrs,
};struct kobject kobj;//声明对象static int kobj_test_init(void)
{ printk("kobj_test_init.\n"); kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test_1");//初始化kobject对象kobj,并将其注册到linux系统 return 0;
}static void kobj_test_exit(void)
{ printk("kobj_test_exit.\n"); kobject_del(&kobj);
}module_init(kobj_test_init);
module_exit(kobj_test_exit);
Makefile:
ifneq ($(KERNELRELEASE),)
$(warning ------------------------001)
obj-m := kobject.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
$(warning ------------------------002)
all:$(MAKE) -C $(KDIR) M=$(PWD) modules$(warning ------------------------003)
clean:rm -rf .*.cmd *.o *.*~ *.order *.symvers *.mod.c *.ko .tmp_versions
endif

设备驱动使用kobject
看下面这个图片,我们看到设备驱动使用kobject 的流程

/*** bus_add_driver - Add a driver to the bus.* @drv: driver.*/
int bus_add_driver(struct device_driver *drv)
{struct bus_type *bus;struct driver_private *priv;int error = 0;/* 通过driver指针获取bus指针 */bus = bus_get(drv->bus);if (!bus)return -EINVAL;pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);/* 申请内存 */priv = kzalloc(sizeof(*priv), GFP_KERNEL);if (!priv) {error = -ENOMEM;goto out_put_bus;}klist_init(&priv->klist_devices, NULL, NULL);priv->driver = drv;drv->p = priv;priv->kobj.kset = bus->p->drivers_kset;error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name);if (error)goto out_unregister;klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);if (drv->bus->p->drivers_autoprobe) {if (driver_allows_async_probing(drv)) {pr_debug("bus: '%s': probing driver %s asynchronously\n",drv->bus->name, drv->name);async_schedule(driver_attach_async, drv);} else {error = driver_attach(drv);if (error)goto out_unregister;}}module_add_driver(drv->owner, drv);error = driver_create_file(drv, &driver_attr_uevent);if (error) {printk(KERN_ERR "%s: uevent attr (%s) failed\n",__func__, drv->name);}error = driver_add_groups(drv, bus->drv_groups);if (error) {/* How the hell do we get out of this pickle? Give up */printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",__func__, drv->name);}if (!drv->suppress_bind_attrs) {error = add_bind_files(drv);if (error) {/* Ditto */printk(KERN_ERR "%s: add_bind_files(%s) failed\n",__func__, drv->name);}}return 0;out_unregister:kobject_put(&priv->kobj);kfree(drv->p);drv->p = NULL;
out_put_bus:bus_put(bus);return error;
}


相关文章:
一文讲解Linux 设备模型 kobject,kset
设备驱动模型 面试的时候,有面试官会问,什么是Linux 设备驱动模型?你要怎么回答? 这个问题,突然这么一问,可能你会愣住不知道怎么回答,因为Linux 设备驱动模型是一个比较整体的概念࿰…...
linux配置密码过期的安全策略(/etc/login.defs的解读)
长期不更换密码很容易导致密码被破解,而linux的密码过期安全策略主要在/etc/login.defs中配置。一、/etc/login.defs文件的参数解读1、/etc/login.defs文件的内容示例[rootlocalhost ~]# cat /etc/login.defs # # Please note that the parameters in this configur…...
c_character_string 字符串----我认真的弄明白了,也希望你们也是。
字符串 1. 字符串长度strlen 1.1strlen 函数介绍 size_t strlen ( const char * str );strlen ——string length strlen 的头文件是 #include <string.h> 参数指向的字符串必须要以 ‘\0’ 结束。 strlen 是求字符串长度的函数,统计的是字符串中\0之前出现…...
spring面试题 一
一、为了降低Java开发的复杂性,Spring采取了那4种关键策略 基于POJO的轻量级和最小侵入性编程; 通过依赖注入和面向接口实现松耦合; 基于切面和惯例进行声明式编程; 通过切面和模板减少样板式代码。 二、Spring框架的核心&am…...
C++中char *,char a[ ]的特殊应用
1.数组的本质 数组是多个元素的集合,在内存中分布在地址相连的单元中,所以可以通过其下标访问不同单元的元素。 2.指针 指针也是一种变量,只不过它的内存单元中保存的是一个标识其他位置的地址。 3.字符串常量的本质是它的第一个字符的地…...
【Windows10】电脑副屏无法调节屏幕亮度?解决方法
先说下情况,本人对显示器不太懂,属于小白 这个副屏无法调节的问题出现也已经很久了,但是之前亮度适合就无所谓,今天突然按了之后很亮,于是就找问题。 第一步,我直接百度,遇事不决,百…...
Paper简读 - ProGen2: Exploring the Boundaries of Protein Language Models
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/128976102 ProGen2: Exploring the Boundaries of Protein Language Models ProGen2:探索蛋白质语言模型的边界Cumulative density:累积密度 Ligand:在生…...
leaflet 加载WKT数据(示例代码050)
第050个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载WKT文件,将图形显示在地图上。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意如果OpenStreetMap无法加载,请加载其他来练习 文章目录 示例效果配置方式示例源代码(共67行…...
设计模式-组合模式和建筑者模式详解
一. 组合模式 1. 背景 在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。在软件开发中也是这样,例如&…...
Pcap文件的magic_number
1. 简述 pcap文件头中的magicNum是来标识pcap文件文件头和包头字节序和应用是否一致的。 在标准情况下为0xa1b2c3d4。如果相反则说明需要调换字节序。 一般格式 Global Header Packet Header Packet Data Packet Header Packet Data ....pcap文件头格式 typedef struct pca…...
MDS75-16-ASEMI三相整流模块MDS75-16
编辑-Z MDS75-16在MDS封装里采用的6个芯片,是一款工业焊机专用大功率整流模块。MDS75-16的浪涌电流Ifsm为920A,漏电流(Ir)为5mA,其工作时耐温度范围为-40~150摄氏度。MDS75-16采用GPP硅芯片材质,里面有6颗芯片组成。MDS75-16的电…...
基本TCP编程
1. 基本概念 TCP (即传输控制协议) 是一种面向连接的传输层协议,它能提供高可靠性通信 (即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。 2. 通信流程解析 TCP 通信的流程与打电话的过程相似,以下以一对情侣打电话的过程来展示TCP的通信流程: 其中服务端 …...
【沁恒WCH CH32V307V-R1开发板读取板载温度实验】
【沁恒WCH CH32V307V-R1开发板读取板载温度实验】1. 前言2. 软件配置2.1 安装MounRiver Studio3. ADC项目测试3.1 打开ADC工程3.2 编译项目4. 下载验证4.1 接线4.2 演示效果5. 小结1. 前言 ADC 模块包含 2 个 12 位的逐次逼近型的模拟数字转换器,最高 14MHz 的输入时…...
学习SpringCloudAlibaba(二)微服务的拆分与编写
目录 一、单体架构VS微服务架构 1.单体架构 (1).单体架构的优点 (2).单体架构的缺点 2.微服务架构 (1)微服务的特性 (2)微服务架构图 (3)微服务的优点 …...
通过对HashMap的源码分析解决部分关于HashMap的问题
HashMap第一次分配多大的空间我们查看resize()中的源码所以当我们没有传入默认容量的参数的时候,默认容量是16当传进一个20的初始参数时,数组的容量是多大所以当我们传入20的参数,这时创建的容量是32(2^5)对…...
【无标题】
Windeployqt 打包,缺少DLL 的原因分析,解决方法 很多同学使用工具windeployqt进行打包发布后,运行exe文件时,还是会出现下图所示的系统错误提示,这种情况就表示相关的DLL 库文件没有被正确打包。可是windeployqt明确显示运行正常啊,难道是QT自家的windeployqt这个工具有…...
渗透测试 -- 网站信息收集
数据来源 01 网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言(php、java、...)、数据库(Mysql、...)为什么要了解这些? 举个例子:发现了一…...
Windows 搭建ARM虚拟机 UOS系统
搭建环境安装虚拟机下载虚拟机QEMU,https://www.qemu.org/download/,目前最新版本是7.2.0。安装完成后,需要将qemu的安装路径设置到环境变量完成后运行cmd,测试环境变量配置完成。qemu-system-aarch64 --version如上截图所示&…...
day58每日温度_下一个更大元素1
力扣739.每日温度 题目链接:https://leetcode.cn/problems/daily-temperatures/ 思路 什么时候用单调栈呢? 通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了…...
超清遥感影像语义分割处理
分割出城市中的垃圾堆场,遂寻找到了 UrbanAtlas 2012 database 这个数据集和对应的 baseline baseline IoU for class 1: 0.5667 IoU for class 2: 0.3504 IoU for class 3: 0.0001 IoU for class 4: 0.0002 IoU for class 5: 0.4121 IoU for class 6: 0.0204 IoU for cla…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
