Linux设备模型浅析之uevent篇
Linuxexpect详解
Linuxexpect详解场景现在有两台Linux主机A和B,如何从A主机ssh到B主机,然后在B主机上执⾏命令,如何使这个过程实现全程⾃动化?你可能会使⽤这种⽅法:ssh admin@10.220.20.15 "ls"但是这种⽅式⽐较笨拙,每次都要输⼊密码,同时并不能执⾏⼀些复杂的逻辑或命令。
那么如何实现全程⾃动化呢?这就要⽤到今天这篇⽂章总结的expect了。
expect是什么?expect是⼀个免费的编程⼯具,⽤来实现⾃动的交互式任务,⽽⽆需⼈为⼲预。
说⽩了,expect就是⼀套⽤来实现⾃动交互功能的软件。
在实际⼯作中,我们运⾏命令、脚本或程序时,这些命令、脚本或程序都需要从终端输⼊某些继续运⾏的指令,⽽这些输⼊都需要⼈为的⼿⼯进⾏。
⽽利⽤expect,则可以根据程序的提⽰,模拟标准输⼊提供给程序,从⽽实现⾃动化交互执⾏。
这就是expectexpect基础在使⽤expect时,基本上都是和以下四个命令打交道:命令作⽤send ⽤于向进程发送字符串expect 从进程接收字符串spawn 启动新的进程interact 允许⽤户交互send命令接收⼀个字符串参数,并将该参数发送到进程。
expect命令和send命令相反,expect通常⽤来等待⼀个进程的反馈,我们根据进程的反馈,再发送对应的交互命令。
spawn命令⽤来启动新的进程,spawn后的send和expect命令都是和使⽤spawn打开的进程进⾏交互。
interact命令⽤的其实不是很多,⼀般情况下使⽤spawn、send和expect命令就可以很好的完成我们的任务;但在⼀些特殊场合下还是需要使⽤interact命令的,interact命令主要⽤于退出⾃动化,进⼊⼈⼯交互。
⽐如我们使⽤spawn、send和expect命令完成了ftp登陆主机,执⾏下载⽂件任务,但是我们希望在⽂件下载结束以后,仍然可以停留在ftp命令⾏状态,以便⼿动的执⾏后续命令,此时使⽤interact命令就可以很好的完成这个任务。
linux设备模型_uevent
Linux设备模型(3)_Uevent作者:蜗蜗发布于:2014-3-10 20:391. Uevent的功能Uevent是Kobject的一部分,用于在Kobject状态发生改变时,例如增加、移除等,通知用户空间程序。
用户空间程序收到这样的事件后,会做相应的处理。
该机制通常是用来支持热拔插设备的,例如U盘插入后,USB 相关的驱动软件会动态创建用于表示该U盘的device结构(相应的也包括其中的kobject),并告知用户空间程序,为该U盘动态的创建/dev/目录下的设备节点,更进一步,可以通知其它的应用程序,将该U盘设备mount到系统中,从而动态的支持该设备。
2. Uevent在kernel中的位置下面图片描述了Uevent模块在内核中的位置:由此可知,Uevent的机制是比较简单的,设备模型中任何设备有事件需要上报时,会触发Uevent提供的接口。
Uevent模块准备好上报事件的格式后,可以通过两个途径把事件上报到用户空间:一种是通过kmod模块,直接调用用户空间的可执行文件;另一种是通过netlink通信机制,将事件从内核空间传递给用户空间。
注1:有关kmod和netlink,会在其它文章中描述,因此本文就不再详细说明了。
3. Uevent的内部逻辑解析3.1 Source Code位置Uevent的代码比较简单,主要涉及kobject.h和kobject_uevent.c两个文件,如下:include/linux/kobject.hlib/kobject_uevent.c3.2 数据结构描述kobject.h定义了uevent相关的常量和数据结构,如下:kobject_action 1: /* include/linux/kobject.h, line 50 */2: enum kobject_action {3: KOBJ_ADD,4: KOBJ_REMOVE,5: KOBJ_CHANGE,6: KOBJ_MOVE,7: KOBJ_ONLINE,8: KOBJ_OFFLINE,9: KOBJ_MAX10: };kobject_action定义了event的类型,包括:ADD/REMOVE,Kobject(或上层数据结构)的添加/移除事件。
Linux设备模型 热插拔、mdev 与 firmware
Linux设备驱动程序学习(15)-Linux设备模型(热插拔、mdev 与firmware)热插拔有2 个不同角度来看待热插拔:从内核角度看,热插拔是在硬件、内核和内核驱动之间的交互。
从用户角度看,热插拔是内核和用户空间之间,通过调用用户空间程序(如hotplug、udev 和mdev)的交互。
当需要通知用户内核发生了某种热插拔事件时,内核才调用这个用户空间程序。
现在的计算机系统,要求Linux 内核能够在硬件从系统中增删时,可靠稳定地运行。
这就对设备驱动作者增加了压力,因为在他们必须处理一个毫无征兆地突然出现或消失的设备。
热插拔工具当用户向系统添加或删除设备时,内核会产生一个热插拔事件,并在/proc/sys/kernel/hotplug文件里查找处理设备连接的用户空间程序。
这个用户空间程序主要有hotplug:这个程序是一个典型的bash 脚本,只传递执行权给一系列位于/etc/hot-plug.d/ 目录树的程序。
hotplug 脚本搜索所有的有 .hotplug 后缀的可能对这个事件进行处理的程序并调用它们, 并传递给它们许多不同的已经被内核设置的环境变量。
(基本已被淘汰,具体内容请参阅《LDD3》)udev :用于linux2.6.13或更高版本的内核上,为用户空间提供使用固定设备名的动态/dev目录的解决方案。
它通过在sysfs 的/class/ 和/block/ 目录树中查找一个称为dev 的文件,以确定所创建的设备节点文件的主次设备号。
所以要使用udev,驱动必须为设备在sysfs中创建类接口及其dev属性文件,方法和sculld模块中创建dev属性相同。
udev的资料网上十分丰富,我就不在这废话了,给出以下链接有兴趣的自己研究:mdev:一个简化版的udev,是busybox所带的程序,十分适合嵌入式系统。
因为hotplug现在也在被慢慢地淘汰,udev不再依赖hotplug了,所以这里不再介绍;udev较mdev复杂,不太适合嵌入式使用。
底层节点uevent机制
底层节点uevent机制
底层节点uevent机制是指在Linux系统下,底层节点对于设备的事件通知机制。
底层节点是指设备文件系统中的最底层节点,也就是设备文件的具体实现部分,而uevent则是指用户空间与内核空间之间的事件通知机制。
在Linux系统中,底层节点uevent机制主要用于设备的热插拔、设备状态变化以及驱动程序的加载卸载等操作。
当一个设备被插入或者拔出时,底层节点会向内核发送一个uevent事件,内核会通过uevent机制将这个事件通知到用户空间,用户空间可以根据这个事件来进行相应的操作。
底层节点uevent机制的实现依赖于sysfs文件系统,每个设备在sysfs中都有一个对应的目录,该目录下包含了该设备的属性信息和uevent文件。
当设备发生变化时,底层节点会在uevent文件中写入相应的事件信息,内核会通过sysfs文件系统将这个事件通知到用户空间。
总的来说,底层节点uevent机制是Linux系统下设备管理的重要机制之一,它可以实现设备的热插拔和状态变化的实时通知,为系统的设备管理提供了强大的支持。
- 1 -。
Linux设备模型 热插拔mdev 与 firmware
Linux设备模型热插拔、mdev 与 firmwareLinux设备驱动程序学习(15)-Linux设备模型(热插拔、mdev 与 firmware)热插拔有 2 个不同角度来看待热插拔:从内核角度看,热插拔是在硬件、内核和内核驱动之间的交互。
从用户角度看,热插拔是内核和用户空间之间,通过调用用户空间程序(如hotplug、udev 和 mdev)的交互。
当需要通知用户内核发生了某种热插拔事件时,内核才调用这个用户空间程序。
现在的计算机系统,要求 Linux 内核能够在硬件从系统中增删时,可靠稳定地运行。
这就对设备驱动作者增加了压力,因为在他们必须处理一个毫无征兆地突然出现或消失的设备。
热插拔工具当用户向系统添加或删除设备时,内核会产生一个热插拔事件,并在/proc/sys/kernel/hotplug 文件里查找处理设备连接的用户空间程序。
这个用户空间程序主要有hotplug:这个程序是一个典型的 bash 脚本,只传递执行权给一系列位于 /etc/hot-plug.d/ 目录树的程序。
hotplug 脚本搜索所有的有 .hotplug 后缀的可能对这个事件进行处理的程序并调用它们, 并传递给它们许多不同的已经被内核设置的环境变量。
(基本已被淘汰,具体内容请参阅《LDD3》)udev :用于linux2.6.13或更高版本的内核上,为用户空间提供使用固定设备名的动态/dev目录的解决方案。
它通过在 sysfs 的 /class/ 和/block/ 目录树中查找一个称为 dev 的文件,以确定所创建的设备节点文件的主次设备号。
所以要使用udev,驱动必须为设备在sysfs中创建类接口及其dev属性文件,方法和sculld模块中创建dev属性相同。
udev的资料网上十分丰富,我就不在这废话了,给出以下链接有兴趣的自己研究:《UDEV Primer》(英文),地址:/decibelshelp/LinuxHelp_UDEVPrimer.html 《udev规则编写》(luofuchong翻译),地址:/luofuchong/archive/2021/12/18/37831.html 《什么是udev》地址:/steganography/archive/2021/04/10/657620.aspx《udev-FAQ 中文翻译》地址:/3225765.html 《udev轻松上路》地址:/user1/3313/archives/2021/1635169.shtml 《Udev (简体中文)》地址:/index.php/Udev_(????????-???) Udev官方主页:/pub/linux/utils/kernel/hotplug/udev.html 下载地址:/pub/linux/utils/kernel/hotplug/ 在《LFS》中也有介绍udev的使用,很值得参考!下载地址:/lfs/downloads/stable/mdev:一个简化版的udev,是busybox所带的程序,十分适合嵌入式系统。
电源管理方式的变更,driver.pm.suspend
电源管理⽅式的变更,driver.pm.suspend 与 i2c_driver.suspend 新版linux系统设备架构中关于电源管理⽅式的变更based on linux-2.6.32⼀、设备模型各数据结构中电源管理的部分linux的设备模型通过诸多结构体来联合描述,如struct device,struct device_type,struct class,struct device_driver,struct bus_type等。
@kernel/include/linux/devices.h中有这⼏中结构体的定义,这⾥只列出和PM有关的项,其余查看源码:struct device{...struct dev_pm_info power;...}struct device_type {...int (*uevent)(struct device *dev, struct kobj_uevent_env *env);char *(*devnode)(struct device *dev, mode_t *mode);void (*release)(struct device *dev);const struct dev_pm_ops *pm;};struct class {...void (*class_release)(struct class *class);void (*dev_release)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;...};struct device_driver {...int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct dev_pm_ops *pm;...};struct bus_type {...int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;...};以上可以看出和电源管理相关的两个结构体是struct dev_pm_info和struct dev_pm_ops,他们定义于⽂件@kernel/include/linux/pm.hstruct dev_pm_info {pm_message_t power_state;unsigned int can_wakeup:1;unsigned int should_wakeup:1;enum dpm_state status;#ifdef CONFIG_PM_SLEEPstruct list_head entry;#endif#ifdef CONFIG_PM_RUNTIME // undefstruct timer_list suspend_timer;unsigned long timer_expires;struct work_struct work;wait_queue_head_t wait_queue;spinlock_t lock;atomic_t usage_count;atomic_t child_count;unsigned int disable_depth:3;unsigned int ignore_children:1;unsigned int idle_notification:1;unsigned int request_pending:1;unsigned int deferred_resume:1;enum rpm_request request;enum rpm_status runtime_status;int runtime_error;#endif};struct dev_pm_ops {int (*prepare)(struct device *dev);void (*complete)(struct device *dev);int (*suspend)(struct device *dev);int (*resume)(struct device *dev);int (*freeze)(struct device *dev);int (*thaw)(struct device *dev);int (*poweroff)(struct device *dev);int (*restore)(struct device *dev);int (*suspend_noirq)(struct device *dev);int (*resume_noirq)(struct device *dev);int (*freeze_noirq)(struct device *dev);int (*thaw_noirq)(struct device *dev);int (*poweroff_noirq)(struct device *dev);int (*restore_noirq)(struct device *dev);int (*runtime_suspend)(struct device *dev);int (*runtime_resume)(struct device *dev);int (*runtime_idle)(struct device *dev);};⼆、device中的dev_pm_info结构体device结构体中的power项⽤来将该设备纳⼊电源管理的范围,记录电源管理的⼀些信息。
SELinux概述
SELinux使用了分级的强制访问控制,是Linux核的重要安全措施。
SELinux的安全策略工具可从oss.tresys./projects下载。
本章分析了SELinux的安全机制,介绍了安全策略配置语言、核策略库的结构,简述了SELinux核模块的实现,还分析了用户空间的客体管理器。
3.1 SELinux概述SELinux是安全增强了的Linux,是Security-enhanced Linux的简写,SELinux改进了对核对象和服务的访问控制,改进了对进程初始化、继承和程序执行的访问控制,改进了对文件系统、目录、文件和打开文件描述的访问控制,还改进了对端口、信息和网络接口的访问控制。
早期的Linux核只提供了经典的UNIX自主访问控制(root用户,用户ID,模式位安全机制),以及部分地支持了POSIX.1e标准草案中的capabilities安全机制,这对于Linux系统的安全性是不够的,NSA(the National Security Agency)和SCC(Secure Computing Corporation)共同开发了强大的基于类型加强(Type Enforcement)的强制访问控制(mandatory access control,简称MAC)机制,提供了动态的安全策略机制。
Linux核增加了一个通用的安全访问控制框架,它通过hook函数来控制程序的执行,这个框架就是Linux安全模块(LSM),在LSM上可使用各种安全控制机制(如:Flask机制)来实现对程序的控制。
SELinux应用了类型加强(Type Enforcement,TE)和基于角色访问控制(role-based access control,RBAC)技术。
TE给每个主体(进程)和系统中的客体定义了一个类型,这些类型定义在SELinux的安全策略文件中,以安全标签形式存放在文件本身的扩展属性(extended attributes,简称xattrs)里。
Linux设备模型浅析之设备篇
Linux设备模型浅析之设备篇本文属本人原创,欢转载,转载请注明出处。
由于个人的见识和能力有限,不可能面面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是yzq.seen@,博客是。
Linux设备模型,仅仅看理论介绍,比如LDD3的第十四章,会感觉太抽象不易理解,而通过阅读内核代码就更具体更易理解,所以结合理论介绍和内核代码阅读能够更快速的理解掌握linux设备模型。
这一序列的文章的目的就是在于此,看这些文章之前最好能够仔细阅读LDD3的第十四章。
大部分device和driver都被包含在一个特定bus中,platform_device和platform_driver就是如此,包含在platform_bus_type中。
这里就以对platform_bus_type的调用为主线,浅析platform_device的注册过程,从而理解linux设备模型。
platform_bus_type用于关联SOC的platform device和platform driver,比如在内核linux-2.6.29中所有S3C2410中的platform device都保存在devs.c中。
这里就以S3C2410 RTC为例。
在文章的最后贴有一张针对本例的device model图片,可在阅读本文章的时候作为参照。
一、S3C2410 RTC的platform device定义在arch/arm/plat-s3c24xx/devs.c中,如下:static struct resource s3c_rtc_resource[] = {[0] = {.start = S3C24XX_PA_RTC,.end = S3C24XX_PA_RTC + 0xff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_RTC,.end = IRQ_RTC,.flags = IORESOURCE_IRQ,},[2] = {.start = IRQ_TICK,.end = IRQ_TICK,.flags = IORESOURCE_IRQ}};struct platform_device s3c_device_rtc = {.name = "s3c2410-rtc",.id = -1,.num_resources = ARRAY_SIZE(s3c_rtc_resource),.resource = s3c_rtc_resource,};把它们添加在arch/arm/mach-s3c2440/ mach- smdk2440.c中,如下:static struct platform_device *smdk2440_devices[] __initdata = {&s3c_device_usb,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_iis,& s3c_device_rtc};系统初始化的时候会调用drivers/base/platform.c里的platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices))将其注册到platform_bus_type,最终被添加到device hierarchy 。
input(evdev)
Linux输入子系统框架2012-10-13 17:58:13Linux输入子系统包括三个层次:事件处理层(Event Handler)、核心层(Input Core)和驱动层(Input Driver)。
1.事件层负责与用户程序打交道,将核心层传来的事件报告给用户程序。
2.核心层是链接其他两个层之间的纽带与桥梁,向下提供驱动层的接口,向上提供事件处理层的接口。
3.驱动层负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,键盘、鼠标、触摸屏等字符设备驱动功能的实现工作主要在这层。
在Linux输入子系统中,有几个重要的结构体,掌握这些结构体对理解整个输入子系统有很大的帮助:input_dev结构体用来描述一个input设备,位于设备驱动层,一个设备能产生哪类以及该类事件中的哪些事件都是在该结构体中声明的。
struct input_dev{const char *name;struct input_id id;unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; // 表示能产生哪类事件unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; // 表示能产生哪些按键unsigned long relbit[BITS_TO_LONGS(REL_CNT)];unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];unsigned long key[BITS_TO_LONGS(KEY_CNT)];int (*open)(struct input_dev *dev);void (*close)(struct input_dev *dev);struct input_handle *grab;struct device dev;struct list_head h_list;struct list_head node;......};input_handler结构体用来描述一个事件处理器,结构体中的input_device_id*id_table;成员用来和input_dev设备匹配,看是否支持该输入设备。
linux vtune 用法
linux vtune 用法VTune是Intel提供的一款性能分析工具,可以用于对Linux系统的应用程序进行性能分析和优化。
使用VTune进行Linux性能分析的一般步骤如下:1.安装VTune:首先需要从Intel官网下载并安装VTune软件包。
2.收集性能数据:使用VTune运行目标程序,并根据需求配置所需的分析类型、采样频率和持续时间等参数。
VTune可以对CPU利用率、内存访问、I/O操作等进行分析。
收集的性能数据可以保存到一个文件中。
3.分析性能数据:通过命令行界面或者图形界面打开VTune的分析器,然后将收集到的性能数据加载到分析器中。
VTune会根据加载的性能数据生成相应的分析报告,包括热点函数、线程活动、内存分配等多个方面的信息。
4.优化性能:根据分析报告中的信息,定位性能瓶颈,并提出相应的优化建议。
可以通过调整代码、算法、并行化结构等方式来改进程序的性能。
此外,VTune还提供了许多功能和选项,可以帮助用户更深入地分析和优化程序,例如:-支持多种分析器和事件:VTune提供了多个分析器,可以针对不同的性能指标进行分析,例如CPU利用率、内存带宽、磁盘I/O等。
用户可以选择适合自己需求的分析器,并指定需要监视的性能指标。
-支持命令行和图形界面:VTune可以通过命令行界面或者图形界面来操作,用户可以根据自己的习惯选择使用方式。
-支持远程分析:VTune还支持通过网络对远程Linux系统进行性能分析,用户可以在本地机器上运行VTune并分析远程系统的性能。
-支持多种编程语言和平台:VTune可以用于分析多种编程语言和平台的程序,包括C、C++、Fortran等,并支持Intel和非Intel的处理器架构。
总结而言,VTune是一款强大的Linux性能分析工具,通过收集、分析和优化性能数据,可以帮助开发人员提高程序的性能和效率。
设备驱动模型
简介作者:hjlin内核版本:2.6.29设备驱动模型框架是linux驱动编程的基础。
它通过kobject,kset,ktype等底层数据结构将bus_type, device, device_driver 等高层数据结构组织起来,形成一个层次、分类清晰的驱动模型。
优点如下:1.代码重用。
将对象抽象为总线、驱动、设备三种,各司其职。
同一总线的多个驱动使用相同的总线对象。
同一驱动可以关联驱动多个设备。
2.通过sysfs文件系统,清晰了展示内核驱动模型中的层次关系。
同时sysfs文件系统还提供了方便的同用户控件交互的接口。
框架数据结构KobjectKobject是代表驱动模型中的一个对象。
总线、驱动、设备都继承了它。
(在结构体中包含kobject)。
每个kobject在sysfs中表现为一个目录。
每个kobject都有一个parent kobject和所属的kset。
Kset就是kobject所属的kset,通过kset 的链表可以找到所有属于它的kobject。
这些kobject进行uevent操作时,都会调用所属的kset 的uevent_ops方法。
父kobj,用于表示kobject之间或者kobject和kset,kset之间的在sysfs 中的目录结构关系。
如果父kobj不存在,并且所属的kset存在的话,则父kobj就是设置为所属的kset的内嵌kobj。
因此,注册设备、驱动或者总线的时候如果不指定parent kobj的话,父kobj则会设置为所属的kset的kobj。
(todo:最好画图表示关系)Kest通过kset可以将kobject组织成一颗层次树。
kobj_typebus_type代表一个总线。
对应/sys/bus下的一个目录。
管理相应总线下的所有驱动和设备。
struct bus_type {const char *name; //总线名称struct bus_attribute *bus_attrs; //该总线目录下的属性文件以及相应的访问方法struct device_attribute *dev_attrs; //该总线设备子目录下的属性文件以及相应的访问方法struct driver_attribute *drv_attrs; //该总线驱动子目录下的属性文件以及相应的访问方法int (*match)(struct device *dev, struct device_driver *drv); //驱动模型进行驱动和设备的匹配时调用int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //uevent方法int (*probe)(struct device *dev); //match成功之后会调用。
《Linux设备节点创建》内核kobject上报uevent过滤规则
《Linux设备节点创建》内核kobject上报uevent过滤规则/tankai19880619/article/details/11776589说明:本文基于Android2.3和Linux2.6,其余版本仅供参考。
Android2.3及Linux2.6.29内核模拟器版本编译与调试阅读本文前请阅读:Linux总线、设备、驱动与设备节点创建、用户测试程序一、netlink监听程序testnet.c[cpp]view plain copy1.#include <stdio.h>2.#include <stdlib.h>3.#include <string.h>4.#include <errno.h>5.#include <sys/types.h>6.#include <asm/types.h>7.//该头文件需要放在netlink.h前面防止编译出现__kernel_sa_family未定义8.#include <sys/socket.h>9.#include <linux/netlink.h>10.11.void MonitorNetlinkUevent()12.{13.int sockfd;14.struct sockaddr_nl sa;15.int len;16.char buf[4096];17.struct iovec iov;18.struct msghdr msg;19.int i;20.21. memset(&sa,0,sizeof(sa));22. sa.nl_family=AF_NETLINK;23. sa.nl_groups=NETLINK_KOBJECT_UEVENT;24. sa.nl_pid = 0;//getpid(); both is ok25. memset(&msg,0,sizeof(msg));26. iov.iov_base=(void *)buf;27. iov.iov_len=sizeof(buf);28. msg.msg_name=(void *)&sa;29. msg.msg_namelen=sizeof(sa);30. msg.msg_iov=&iov;31. msg.msg_iovlen=1;32.33. sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);34.if(sockfd==-1)35. printf("socket creating failed:%s\n",strerror(errno));36.if(bind(sockfd,(struct sockaddr *)&sa,sizeof(sa))==-1)37. printf("bind error:%s\n",strerror(errno));38.while(1){39. memset(buf,0,sizeof(buf));40. len=recvmsg(sockfd,&msg,0);41.if(len<0){}42.//printf("receive error\n");43.else if(len<32||len>sizeof(buf))44. printf("invalid message");45.for(i=0;i<len;i++)46.if(*(buf+i)=='\0')47. buf[i]='\n';48. printf("received %d bytes\n%s\n",len,buf);49. }50.}51.52.int main(int argc,char **argv)53.{54. MonitorNetlinkUevent();55.return 0;56.}Android.mk[plain]view plain copy1.LOCAL_PATH:= $(call my-dir)2.include $(CLEAR_VARS)3.4.LOCAL_SRC_FILES:= \5. testnet.c6.7.LOCAL_SHARED_LIBRARIES := \8. libutils9.10.LOCAL_MODULE:= testnet11.12.LOCAL_MODULE_TAGS := optional13.14.include $(BUILD_EXECUTABLE)二、如下是添加打印后的信息(Android用户空间udev为ueventd,属于init的一个软连接)1.总线驱动root@android:/data/tank # insmod testbus.ko[plain]view plain copy1.//内核模块加载成功,会上报netlink------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env3.kobject: 'testbus' (bf02d1c8): kobject_uevent_env------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast5.//总线注册上报netlink---testlddbus.c----->>>>ldd_bus_init--------->>>>>>bus.c>>>>>>bus_register,,,bus->name is ldd-------_>>>>kobject.c>>>>>>>kset_register-------_>>>>kobject.c>>>>>>>kset_register>>>kobject_uevent------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env11.kobject: 'ldd' (cfcdb1c8): kobject_uevent_env------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast13.//设备注册由于没有分配主设备号,不上报netlink-------_>>>>>>>>core.c>>>>>device_register-------_>>>>>>>>core.c>>>>>device_add-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0x0-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->class is 0x022.kobject: 'ldd0' (bf02d074): kobject_uevent_env23.kobject: 'ldd0' (bf02d074): kobject_uevent_env: filter function caused the event to drop!24.//用户空间ueventd的处理,2个uevent事件25.init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 426.init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd27.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -128.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->majorand minor < 029.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -130.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->majorand minor < 031.received 83 bytes32.add@/module/testbus33.ACTION=add34.DEVPATH=/module/testbus35.SUBSYSTEM=module36.SEQNUM=64937.38.received 66 bytes39.add@/bus/ldd40.ACTION=add41.DEVPATH=/bus/ldd42.SUBSYSTEM=bus43.SEQNUM=650说明:drivers/base/bus.c[plain]view plain copy1.int bus_register(struct bus_type *bus){2. retval = kset_register(&priv->subsys);3. /*4. lib/kobject.c5. int kset_register(struct kset *k){6. kobject_uevent(&k->kobj, KOBJ_ADD);7. }8. */9. retval = bus_create_file(bus, &bus_attr_uevent);10. priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj);11. priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);12.}2.插入设备root@android:/data/tank # insmod testdev.ko[plain]view plain copy1.//内核模块加载会上报netlink------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env3.kobject: 'testdev' (bf0334e0): kobject_uevent_env------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast5.//没有主设备号,不会上报netlink---testdev.c----->>>>mini_init-------_>>>>>>>>core.c>>>>>device_register-------_>>>>>>>>core.c>>>>>device_add-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env11.kobject: 'mini' (bf0333dc): kobject_uevent_env-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0xbf001130---testlddbus.c----->>>>ldd_uevent-------_>>>>>>drivers/base/core.c>>dev_uevent>>retval is -1217.kobject: 'mini' (bf0333dc): kobject_uevent_env: uevent() returned -1218.//用户空间ueventd的处理,1个uevent事件19.init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 420.init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd21.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -122.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->majorand minor < 023.received 83 bytes24.add@/module/testdev25.ACTION=add26.DEVPATH=/module/testdev27.SUBSYSTEM=module28.SEQNUM=6513.设备驱动root@android:/data/tank # insmod testdriver.ko[plain]view plain copy1.//内核模块成功加载,会上报netlink------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env3.kobject: 'testdriver' (bf039c34): kobject_uevent_env------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast5.//类注册会上报netlink(class_creat)---testdriver.c----->>>>driver_init--------->>>>>driver.c>>>>>>driver_register---------_>>>>>bus.c>>>>>>>bus_add_driver---testbus.c----->>>>ldd_match---testbus.c----->>>>ldd_match---testlddbus.c----->>>>ldd_drv_probe----testdriver.c------>>>>driver_probe mini-------_>>>>kobject.c>>>>>>>kset_register-------_>>>>kobject.c>>>>>>>kset_register>>>kobject_uevent------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env16.kobject: 'mymodule' (cfee5b68): kobject_uevent_env------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast18.//有主设备号时设备注册上报netlink-------->>>>>core.c>>>>device_create-------_>>>>>>>>core.c>>>>>device_register-------_>>>>>>>>core.c>>>>>device_add-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env24.kobject: 'mymod0' (caa4e724): kobject_uevent_env-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0x0-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->class is 0xcaade760-------_>>>>>>drivers/base/core.c>>dev_uevent>>retval is 0------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast31.//驱动注册都会上报netlink---------_>>>>>bus.c>>>>>>>bus_add_driver>>>>kobject_uevent------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env34.kobject: 'mini' (c8aa48c0): kobject_uevent_env------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast36.//用户空间ueventd的处理,4个uevent事件37.init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 438.init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd39.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -140.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->majorand minor < 041.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -142.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->majorand minor < 043.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is 248,uevent->minor is 044.init: TK------_>>>>>>>>>make_devices45.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -146.init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->majorand minor < 047.received 89 bytes48.add@/module/testdriver49.ACTION=add50.DEVPATH=/module/testdriver51.SUBSYSTEM=module52.SEQNUM=65253.54.received 82 bytes55.add@/class/mymodule56.ACTION=add57.DEVPATH=/class/mymodule58.SUBSYSTEM=class59.SEQNUM=65360.61.received 137 bytes62.add@/devices/virtual/mymodule/mymod063.ACTION=add64.DEVPATH=/devices/virtual/mymodule/mymod065.SUBSYSTEM=mymodule66.MAJOR=24867.MINOR=068.SEQNUM=65469.70.received 96 bytes71.add@/bus/ldd/drivers/mini72.ACTION=add73.DEVPATH=/bus/ldd/drivers/mini74.SUBSYSTEM=drivers75.SEQNUM=655说明:drivers/base/driver.c[cpp]view plain copy1.int driver_register(struct device_driver *drv){2. ret = bus_add_driver(drv);3./*4. drivers/base/bus.c5. int bus_add_driver(struct device_driver *drv){6. kobject_uevent(&priv->kobj, KOBJ_ADD);7. }8. */9.}include/linux/device.h[cpp]view plain copy1.#define class_create(owner, name) \2.({ \3.static struct lock_class_key __key; \4. __class_create(owner, name, &__key); \5./*6. drivers/base/class.c7. retval = __class_register(cls, key);8. int __class_register(struct class *cls, struct lock_class_key *key){9. error = kset_register(&cp->subsys);10. }11. lib/kobject.c12. int kset_register(struct kset *k){13. kobject_uevent(&k->kobj, KOBJ_ADD);14. }15. */16.})drivers/base/core.c[cpp]view plain copy1.struct device *device_create(struct class *class, struct device *parent,2. dev_t devt, void *drvdata, const char *fmt, ...){3. dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);4./*5. struct device *device_create_vargs(struct class *class, struct device *parent,6. dev_t devt, void *drvdata, const char *fmt,7. va_list args){8. retval = device_register(dev);9. }10. int device_register(struct device *dev){11. return device_add(dev);12. }13. int device_add(struct device *dev){14. error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev));15. if (MAJOR(dev->devt)) { //有设备号才会上报uevent事件!!16. error = device_create_file(dev, &devt_attr);17. if (error) goto ueventattrError;18. error = device_create_sys_dev_entry(dev);19. if (error) goto devtattrError;20. }21. kobject_uevent(&dev->kobj, KOBJ_ADD);22. }23. */24.}总结:bus_register,driver_register,class_create,device_create以及内核模块加载有uevent 通过netlink上报,device_register的uevent会根据是否有设备号来决定是否上报事件。
字符设备驱动模型浅析
对于写过 linux-2.6 内核(本文采用 linux-2.6.18 内核)字符驱动的程序员来说,对下面这段程序的形 式肯定不陌生。 int result; /*
* Register the driver in the kernel * Dynmically get the major number for the driver using * alloc_chrdev_region function */ result = alloc_chrdev_region(&dev, 0, 1, “testchar”);
通常这段程序会放在一个模块初始化加载函数里,形式是这样的, int __init testchar_init(void) { } module_init(testchar_init);
既然有注册的函数,那必然有注销的函数,这叫有进必有出,有公必有母…,总而言之,这是大自然 的神奇被人类所利用。废话少说,形式是这样的,
字符设备驱动模型浅析
本文属本人原创,欢迎转载,转载请注明出处。由于个人的见识和能力有限,不可能面 面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是yzq.seen@,博客是 。
在 linux 系统中,很多驱动是字符型驱动,有些是直接编译集成在内核中,另一些是单独编译成“.ko” 动态加载的。其实字符驱动只是个外壳,用于内核与应用程序间通信,无非是调用 open,release,read, write 和 ioctl 等例程。所以根据应用不同,字符驱动能会调用其他驱动模块,如 i2c、spi 和 v4l2 等,于是 字符驱动还可分 WDT 驱动、RTC 驱动和 MTD 驱动等。所以在分析其他驱动模块之前有必要好好分析下字 符设备驱动模型。本篇文章要讲的就是字符设备驱动模型,也就是字符设备驱动是怎么注册和注销的, 怎么生成设备节点的,怎么和应用程序关联的,例程调用具体如何实现的等等。
spi_driver
linux spi驱动分析整理1、SPI总线:SPI(同步外设接口)是由摩托罗拉公司开发的全双工同步串行总线,其接口由MISO(串行数据输入),MOSI(串行数据输出),SCK(串行移位时钟),SS/CS(从使能信号)四种信号构成(当然了,现在芯片技术日新月异,SPI 模块的结构也在变化中,象OMAP 系列中的SPI 模块还支持 5 线的一种模式),SS /CS决定了唯一的与主设备通信的从设备,主设备通过产生移位时钟来发起通讯。
通讯时,数据由MOSI 输出,MISO 输入,数据在时钟的上升或下降沿由MOSI 输出,在紧接着的下降或上升沿由MISO 读入,这样经过8/16 次时钟的改变,完成8/16 位数据的传输。
SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性(CPOL)和相位(CPHA)可以进行配置。
如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。
如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。
2、LINUX驱动的分层与分离:在面向对象的程序设计中,可以为某一类相似的事物定义一个基类,而具体的事物可以继承这个基类中的函数。
Linux 内核中频繁使用到面向对象的设计思想。
在设备驱动方面,往往为同类的设备设计了一个框架,而框架中的核心层则实现了该设备通用的一些功能。
而且具体的设备不想使用核心层的函数,它可以重载之。
这就是我们所说的在驱动设计中的分层思想。
此外,在驱动的设计中,我们还会使用分离的思想。
如果一个设备的驱动和host 的驱动休戚相关,那么,这就意味着这个普通的设备如果用在不同的host 上,会采用n 个版本的驱动。
如果产品单一,也许感觉不到不使用分离思想来设计驱动的危害,但是我们想一下,这个世上被人们称道的多是什么?精品,艺术品!精品如何打造?注重细节,不只考虑单一需求!大家开发个东西不容易,怎么能随随便便就让它茫然众码矣呢,所以,何时何地,我们都要以打造精品的思想来要求自己,让自己的劳动力不浪费。
Linuxuevent分析、用户接收uevent以及mdev分析
};
1.2 uevent初始化
()创建类型为NETLINK_KOBJECT_UEVENT的socket,并将其放入uevent_sock_list链表上。()则将其从uevent_socket_list中摘除,并且释放 socket相关资源。
static int uevent_net_init(struct net *net) {
};
call_usermodehelper()首先创建struct subprocess_info,然后执行用户空间程序。
底层节点uevent机制
底层节点uevent机制
底层节点uevent机制(uevent是"User Space Event"的缩写)是Linux内核提供的一种机制,用于将硬件设备的事件通知传递到用户空间,以方便用户空间程序进行相关的处理。它是一种异步通知机制,当底层节点(比如硬件设备)发生了状态变化或者其他重要事件时,内核会生成一个uevent,并将该事件发送给用户空间的udev守护进程。udev守护进程接收到uevent之后,就可以根据事件信息进行相关的设备管理操作。
此外,在底层节点uevent机制中,还支持自定义uevent事件,用户空间程序可以向内核发送自定义事件,并在接收到uevent后进行相关的处理。例如,用户空间程序可以通过发送一个uevent事件来通知内核进行特定的操作,比如重新加载பைடு நூலகம்动程序或者重新启动系统。
总之,底层节点uevent机制是Linux内核提供的一种方便用户空间程序管理设备的机制,通过该机制,用户空间程序可以接收到底层节点的状态变化或者其他重要事件,并根据事件信息进行相关的设备管理操作。
uevent机制
博客园 用户登录 代码改变世界 密码登录 短信登录 忘记登录用户名 忘记密码 记住我 登录 第三方登录/注册 没有账户, 立即注册
uevent机 制
1:概要 uevent机制就是设备驱动模型中任意设备可以把uevent字符串上报给用户空间。主要用于热插拔设备或设备状态变化时。 无论是usermodehelper还是netlink的方式,uevent对系统性能是有影响的。特别是netlink的方式,上报的event会通知到所有的用户进程, 所以还是少用为妙。 2:uevent模块提供的api接口
这两个接口用于上报uevent事件。 3:struct kset_uevent_ops 这个结构体是专门为kset实例定义的uevent 操作。
kobject_uevent_env ->ket-->uevent // 由所属的kset统一添加环境变量(即键值字符串) // 添加 由 char *envp[]参数保存的扩展或自定义环境变量 4:设备的uevent属性文件c
uevent的使用 -回复
uevent的使用-回复什么是uevent?uevent(User Event)是Linux内核提供的一种机制,用于向用户空间发送设备事件通知。
在Linux系统中,所有的设备都被视为文件,当设备状态发生变化时,内核会通过uevent将相应的事件信息发送给用户空间,供应用程序或用户进行处理。
为什么使用uevent?使用uevent机制的优势主要可以归结为两方面。
首先,uevent机制具有较好的可扩展性。
当系统中新增设备或设备状态发生变化时,内核只需要通过uevent通知用户空间,而不需要用户空间轮询设备状态,这样大大降低了系统的资源消耗。
其次,uevent机制提供了一种灵活的方式,使用户空间能够根据设备事件做出相应的处理和决策。
如何使用uevent?使用uevent的关键在于注册和监听相应的事件。
下面将介绍uevent 的使用步骤。
1. 创建uevent的监听文件首先,我们需要创建一个uevent文件,用于接收设备事件通知。
可以使用`socket`函数创建一个UNIX域socket,将uevent文件和这个socket绑定起来,以便接收内核发送的事件通知。
cint sock = socket(AF_NETLINK, SOCK_RAW,NETLINK_KOBJECT_UEVENT);struct sockaddr_nl addr;memset(&addr, 0, sizeof(addr));addr.nl_family = AF_NETLINK;addr.nl_groups = NETLINK_KOBJECT_UEVENT;bind(sock, (struct sockaddr *)&addr, sizeof(addr));2. 接收和处理uevent事件接下来,我们需要使用`recv`函数从uevent文件中接收事件信息,并进行处理。
在接收数据之前,我们需要定义一个缓冲区来存储接收到的数据,并设置一个循环来不断接收和处理事件。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/* 在本例中是 devices_kset 容器,详细介绍可参照《Linux 设备模型浅析之设备篇》,后 面将列出 devices_kset 的定义 */ kset = top_kobj->kset; uevent_ops = kset->uevent_ops; // 本例中 uevent_ops = &device_uevent_ops
struct sk_buff *skb; size_t len;
/* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; skb = alloc_skb(len + env->buflen, GFP_KERNEL); if (skb) {
return 0; }
// 获得用于存放环境变量的 buffer /* environment buffer */ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); if (!env)
return -ENOMEM;
/* 获取该 kobj 在 sysfs 的路径,通过遍历其父 kobj 来获得,本例是/sys/devices/platform/ s3c2410-rtc/rtc/rtc0 */ /* complete object path */
goto exit;
/* 如果配置了网络,那么就会通过 netlink socket 向用户空间发送环境标量,而用户空间 则通过 netlink socket 接收,然后采取一些列的动作。这种机制目前用在 udev 中,也就是 pc 机系统中,后面会分析*/ #if defined(CONFIG_NET) /* send netlink message */ /* 如果配置了 net,则会在 kobject_uevent_init()例程中将全局比昂俩 uevent_sock 初试化 为 NETLINK_KOBJECT_UEVENT 类型的 socket。*/ if (uevent_sock) {
一、在《Linux 设备模型浅析之设备篇》中介绍过 device_add()例程,其用于将一个 device 注册到 device model,其中调用了 kobject_uevent(&dev->kobj, KOBJ_ADD)例程向用户空间发出 KOBJ_ADD 事件并输出环境变量,以表明一个 device 被添加了。在《Linux 设备模型浅析之设 备篇》中介绍过 rtc_device_register()例程 ,其最终调用 device_add()例程添加了一个 rtc0 的 device,我们就以它为例子来完成 uevent 的分析。让我们看看 kobject_uevent()这个例程的代 码,如下: int kobject_uevent(struct kobject *kobj, enum kobject_action action) {
retval = uevent_ops->uevent(kset, kobj, env); if (retval) {
pr_debug("kobject: '%s' (%p): %s: uevent() returned " "%d\n", kobject_name(kobj), kobj, __func__, retval);
pr_debug("kobject: '%s' (%p): %s\n", kobject_name(kobj), kobj, __func__);
/* search the kset we belong to */ top_kobj = kobj; /* 找到其所属的 kset 容器,如果没找到就从其父 kobj 找,一直持续下去,直到父 kobj 不 存在 */ while (!top_kobj->kset && top_kobj->parent)
Linux 设备模型浅析之 uevent 篇
本文属本人原创,欢迎转载,转载请注明出处。由于个人的见识和能力有限,不可能面 面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是 yzq.seen@,博客是 。
Linux 设备模型,仅仅看理论介绍,比如 LDD3 的第十四章,会感觉太抽象不易理解,而 通过阅读内核代码就更具体更易理解,所以结合理论介绍和内核代码阅读能够更快速的理解掌 握 linux 设备模型。这一序列的文章的目的就是在于此,看这些文章之前最好能够仔细阅读 LDD3 的第十四章。uevent,即 user space event,就是内核向用户空间发出的一个事件通知,使 得应用程序能有机会对该 event 作出反应,udev 及 mdev(busybox)就是这种应用程序。阅读这篇 文章之前,最好先阅读文章《Linux 设备模型浅析之设备篇》和《Linux 设备模型浅析之驱动 篇》。
goto exit;
/* keys passed in from the caller */
if (envp_ext) {
// 为 NULL,不执行
for (i = 0; envp_ext[i]; i++) {
retval = add_uevent_var(env, "%s", envp_ext[i]);
}
/* 回调 uevent_ops-> name (),本例中是 dev_uevent_name()例程,获取 bus 或 class 的名 字,本例中 rtc0 不存在 bus,所以是 class 的名字“rtc”,后面分析 */ /* originating subsystem */ if (uevent_ops && uevent_ops->name)
char *envp_ext[]) {
struct kobj_uevent_env *env; const char *action_string = kobject_actions[action]; // 本例是“add”命令 const char *devpath = NULL; const char *subsystem; struct kobject *top_kobj; struct kset *kset; struct kset_uevent_ops *uevent_ops; u64 seq; int i = 0; int retval = 0;
kobj->state_add_uevent_sent = 1; else if (action == KOBJ_REMOVE)
kobj->state_remove_uevent_sent = 1;
/* 增加 event 序列号的值,并输出到环境变量的 buffer。该系列号可以从/sys/kernel/ uevent_seqnum 属性文件读取,至于 ue录是怎样产 生的,后面会分析 */ /* we will send an event, so request a new sequence number */ spin_lock(&sequence_lock); seq = ++uevent_seqnum; spin_unlock(&sequence_lock); retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq); if (retval)
if (retval)
goto exit;
}
}
// 回调 uevent_ops->uevent(),本例中是 dev_uevent()例程,输出一些环境变量,后面分析
/* let the kset specific function add its stuff */ if (uevent_ops && uevent_ops->uevent) {
subsystem = uevent_ops->name(kset, kobj); else
subsystem = kobject_name(&kset->kobj); if (!subsystem) {
pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the " "event to drop!\n", kobject_name(kobj), kobj, __func__);
if (!uevent_ops->filter(kset, kobj)) { // 如果不成功,即 uevent suppress,则直接返回 pr_debug("kobject: '%s' (%p): %s: filter function " "caused the event to drop!\n", kobject_name(kobj), kobj, __func__); return 0;
top_kobj = top_kobj->parent;
if (!top_kobj->kset) { pr_debug("kobject: '%s' (%p): %s: attempted to send uevent " "without kset!\n", kobject_name(kobj), kobj, __func__); return -EINVAL;
/* 回调 uevent_ops->filter ()例程,本例中是 dev_uevent_filter()例程,主要是检查是否 uevent suppress,后面分析 */ /* skip the event, if the filter returns zero. */ if (uevent_ops && uevent_ops->filter)