一文讲解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…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
