概述
创新互联建站制作网站网页找三站合一网站制作公司,专注于网页设计,网站设计、做网站,网站设计,企业网站搭建,网站开发,建网站业务,680元做网站,已为1000多家服务,创新互联建站网站建设将一如既往的为我们的客户提供最优质的网站建设、网络营销推广服务!
随着信息技术的高速发展,操作系统的功能越来越强大,越来越多的应用程序需要操作系统向它们发送事件通知。Linux操作系统为了快速响应外部设备的插拔事件,引入了Uevent事件机制。本文将从以下几个方面深入:Uevent定义、Uevent事件源、Uevent与udev、Uevent处理机制等。
Uevent定义
Uevent全称为Userspace Event,即用户空间事件。用户空间事件是Linux内核为用户空间提供给的一个机制,用于通知操作系统和相关程序发生了某些特定事件。这些事件通常管辖于管理UEVENT_HOTPLUG和UEVENT_COLDPLUG两个宏过程中来调度。
Uevent事件源
Uevent事件源指的是Uevent事件的来源。Linux中Uevent事件源主要来自两个方面:驱动程序和内核自身。
1. 驱动程序:当一个设备插入或者被拔出时,系统会自动将事件通知发给内核,内核通过驱动程序将事件通知送到用户空间(udev)。实际上,这个程序可以处理任何事件,不仅是设备插拔事件,同时也包括内核之间的消息事件等。
2. 内核自身:对于内核内部事件,如内存的初始分配、网络状态变化等Uevent可以及时通知用户空间的相关进程。
Uevent与udev
Uevent与udev是两个概念密不可分的东西,udev作为一个用户空间的设备管理程序,由驱动程序向内核捕获Uevent。当udev收到内核的Uevent事件时,它首先会侦听内核事件,然后在匹配设备节点和正则表达式方面执行是否需要更改udev规则,从而在设备节点中添加或删除属性。同时,udev会随时保持与内核同步,以确保设备变化的信息是实时的。
Uevent处理机制
Uevent的处理机制可以分为内核部分和用户空间部分两个环节。
1. 内核部分:内核创建uevent结构体,内部赋值、获取子系统、查询属性并赋值等操作。在完成所有的处理后,内核会调用uevent_netlink_send()函数将uevent结构体发送到用户空间。
2. 用户空间部分:当内核将uevent发送到用户空间之后,用户空间的udev进程会处理uevent事件通知,从而更新/dev目录下与该设备相关的信息等。同时,udev进程还发射事件通知给可以调用事件监听的用户空间应用程序。
本文介绍了Linux下的Uevent事件机制,包括Uevent定义、Uevent事件源、Uevent与udev、Uevent处理机制等相关内容。通过深入探究Uevent事件机制的原理和工作原理,我们可以更好地理解Linux操作系统的核心功能,进一步提升系统的应用性能。
成都网站建设公司-创新互联,建站经验丰富以策略为先导10多年以来专注数字化网站建设,提供企业网站建设,高端网站设计,响应式网站制作,设计师量身打造品牌风格,热线:028-86922220接触和学习Linux已模配一年有余了. 对 Linux 的设备模型(bus+device+driver+sysfs+uevent)理解尚困运未深刻.所以,写份简单的代码旦尺指强化理解. 我自己写的 bus, 和在 bus 上注册 device 和 driver. 并让 device 和 driver 成功的match. 还未实现 uevent 时间…
Linux下生成驱动设备节点文件的方法有3个:1、手动mknod;2、利用devfs;3、利用udev
在刚开始写Linux
设备驱动程序
的时候晌明帆,很多时候都是利用mknod命令手动创建设备宴雹节点,实际上
Linux内核
为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点。
在2.6.17以前,在/dev目录下生成设备文件很容易,
devfs_mk_bdev
devfs_mk_cdev
devfs_mk_symlink
devfs_mk_dir
devfs_remove
这几个是纯devfs的api,2.6.17以前可用,但后来devfs被sysfs+udev的形式取代,同时期sysfs
文件系统
可以用的api:
class_device_create_file,在2.6.26以后也不行了,现在,使用的是device_create ,从2.6.18开始可用
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, const char *fmt, …)
从2.6.26起又多了一个参数drvdata: the data to be added to the device for callbacks
不会用可以给此参数赋NULL
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, …)
下面着重讲解第三种方法udev
在驱动用加入对udev的支持主要做的就是:在驱动初始化的代码里调用class_create(…)为该设备创建一个class,再为每个设备调用device_create(…)( 在2.6较早的内核中用class_device_create)创建对应的设备。
内核中定义的struct class
结构体
,顾名思义,一个struct class结构体
类
型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应 device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
struct class和class_create(…) 以及device_create(…)都包含在在/include/linux/device.h中,使用的时候一定要包含这个
头槐唯文件
,否则
编译器
会报错。
struct class定义在头文件include/linux/device.h中
class_create(…)在/drivers/base/class.c中实现
device_create(…)函数在/drivers/base/core.c中实现
class_destroy(…),device_destroy(…)也在/drivers/base/core.c中实现调用过程类似如下:
static struct class *spidev_class;
/*—*/
static int __devinit spidev_probe(struct spi_device *spi)
{
….
dev =device_create(spidev_class, &spi->dev, spidev->devt,
spidev, “spidev%d.%d”,
spi->master->bus_num, spi->chip_select);
…
}
static int __devexit spidev_remove(struct spi_device *spi)
{
……
device_destroy(spidev_class, spidev->devt);
…..
return 0;
}
static struct spi_driver spidev_spi = {
.driver = {
.name =”spidev”,
.owner = THIS_MODULE,
},
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),
};
/*—*/
static int __init spidev_init(void)
{
….
spidev_class =class_create(THIS_MODULE, “spidev”);
if (IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
return PTR_ERR(spidev_class);
}
….
}
module_init(spidev_init);
static void __exit spidev_exit(void)
{
……
class_destroy(spidev_class);
……
}
module_exit(spidev_exit);
MODULE_DESCRIPTION(“User mode SPI device interface”);
MODULE_LICENSE(“GPL”);
下面以一个简单字符设备驱动来展示如何使用这几个函数
#include
#include
#include
#include
#include
#include
int HELLO_MAJOR = 0;
int HELLO_MINOR = 0;
int NUMBER_OF_DEVICES = 2;
struct class *my_class;
//struct cdev cdev;
//dev_t devno;
struct hello_dev {
struct device *dev;
dev_t chrdev;
struct cdev cdev;
};
static struct hello_dev *my_hello_dev = NULL;
struct file_operations hello_fops = {
.owner = THIS_MODULE
};
static int __init hello_init (void)
{
int err = 0;
struct device *dev;
my_hello_dev = kzalloc(sizeof(struct hello_dev), GFP_KERNEL);
if (NULL == my_hello_dev) {
printk(“%s kzalloc failed!\n”,__func__);
return -ENOMEM;
}
devno = MKDEV(HELLO_MAJOR, HELLO_MINOR);
if (HELLO_MAJOR)
err= register_chrdev_region(my_hello_dev->chrdev, 2, “memdev”);
else
{
err = alloc_chrdev_region(&my_hello_dev->chrdev, 0, 2, “memdev”);
HELLO_MAJOR = MAJOR(devno);
}
if (err) {
printk(“%s alloc_chrdev_region failed!\n”,__func__);
goto alloc_chrdev_err;
}
printk(“MAJOR IS %d\n”,HELLO_MAJOR);
cdev_init(&(my_hello_dev->cdev), &hello_fops);
my_hello_dev->cdev.owner = THIS_MODULE;
err = cdev_add(&(my_hello_dev->cdev), my_hello_dev->chrdev, 1);
if (err) {
printk(“%s cdev_add failed!\n”,__func__);
goto cdev_add_err;
}
printk (KERN_INFO “Character driver Registered\n”);
my_class =class_create(THIS_MODULE,”hello_char_class”); //类名为hello_char_class
if(IS_ERR(my_class))
{
err = PTR_ERR(my_class);
printk(“%s class_create failed!\n”,__func__);
goto class_err;
}
dev = device_create(my_class,NULL,my_hello_dev->chrdev,NULL,”memdev%d”,0); //设备名为memdev
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
gyro_err(“%s device_create failed!\n”,__func__);
goto device_err;
}
printk(“hello module initialization\n”);
return 0;
device_err:
device_destroy(my_class, my_hello_dev->chrdev);
class_err:
cdev_del(my_hello_dev->chrdev);
cdev_add_err:
unregister_chrdev_region(my_hello_dev->chrdev, 1);
alloc_chrdev_err:
kfree(my_hello_dev);
return err;
}
static void __exit hello_exit (void)
{
cdev_del (&(my_hello_dev->cdev));
unregister_chrdev_region (my_hello_dev->chrdev,1);
device_destroy(my_class, devno);//delete device node under /dev//必须先删除设备,再删除class类
class_destroy(my_class); //delete class created by us
printk (KERN_INFO “char driver cleaned up\n”);
}
module_init (hello_init);
module_exit (hello_exit);
MODULE_LICENSE (“GPL”);
这样,模块加载后,就能在/dev目录下找到memdev这个设备节点了。
例2:内核中的drivers/i2c/i2c-dev.c
在i2cdev_attach_adapter中调用device_create(i2c_dev_class, &adap->dev,
MKDEV(I2C_MAJOR, adap->nr), NULL,
“i2c-%d”, adap->nr);
这样在dev目录就产生i2c-0 或i2c-1节点
接下来就是udev应用,udev是
应用层
的东西,udev需要内核sysfs和tmpfs的支持,sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件提供存放空间
udev的源码可以在去相关网站下载,然后就是对其在运行环境下的移植,指定交叉编译环境,修改Makefile下的CROSS_COMPILE,如为mipsel-linux-,DESTDIR=xxx,或直接make CROSS_COMPILE=mipsel-linux-,DESTDIR=xxx 并install
把主要生成的udevd、udevstart拷贝rootfs下的/in/目录内,udev的
配置文件
udev.conf和rules.d下的rules文件拷贝到rootfs下的/etc/目录内
并在rootfs/etc/init.d/rcS中添加以下几行:
echo “Starting udevd…”
/in/udevd –daemon
/in/udevstart
(原rcS内容如下:
# mount filesystems
/bin/mount -t proc /proc /proc
/bin/mount -t sysfs sysfs /sys
/bin/mount -t tmpfs tmpfs /dev
# create necessary devices
/bin/mknod /dev/null c 1 3
/bin/mkdir /dev/pts
/bin/mount -t devpts devpts /dev/pts
/bin/mknod /dev/audio c 14 4
/bin/mknod /dev/ts c 10 16
)
这样当系统启动后,udevd和udevstart就会解析配置文件,并自动在/dev下创建设备节点文件
这个恩一般我记得连接Android的操作系统你得给u添加一个驱动到/etc/udev/下面绝孝毁哦。ubuntu现在是基于uevent驱动的热插拔机制。
基于uevent驱动加载机制,需并备要再/etc/udev/rules.d/51-android.rules文件,内容如下SUBSYSTEM==”u”, SYSFS{idVendor}==”18d1″, MODE=”0666″同时慎毕chmod修改777权限。供u驱动使用
linux uevent事件的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux uevent事件,探究Linux下的Uevent事件机制,在linux下用什么IO模型好些,如何手动创建一个设备节点,写出主要命令及参数,如何在linux ubuntu中使用android手机程序的信息别忘了在本站进行查找喔。
创新互联【028-86922220】值得信赖的成都网站建设公司。多年持续为众多企业提供成都网站建设,成都品牌建站设计,成都高端网站制作开发,SEO优化排名推广服务,全网营销让企业网站产生价值。
网站栏目:探究Linux下的Uevent事件机制(linuxuevent事件)
本文网址:http://www.36103.cn/qtweb/news22/9072.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联