`
字符串
  • 浏览: 37921 次
文章分类
社区版块
存档分类
最新评论

Linux设备驱动模型中的热插拔机制及mdev

 
阅读更多

热插拔(hotplug,打这个词的时候我常常想到热干面)不一定非要指类似U盘那样的插入拔出,此处的热插拔广义上讲,
是指一个设备加入系统,内核如何通知用户空间。举个简单的例子,如果你的电脑中有块PCI网卡,针对该网卡的驱动程序
以内核模块的形式被编译(obj-m),那么Linux系统在启动过程中是如何自动加载该网卡的驱动模块呢?
大家都知道现在udev负责干这事,其实除了udev,还可以有其他的手法,你自己就可以这样做。
我们先讨论udev,udev最关键的东西是当系统发现一个设备时,它要能够被通知该事件,一旦它知道了这件事,那么余下的事情就都好说了,
无非是个如何查找模块并加载的过程。所以我们看到,这里的关键是热插拔事件的通知机制。Linux的设备模型为此提供了非常完美的支持,
其原理其实发源于kset这一层,对此在《深入Linux设备驱动程序内核机制》一书中有详细的描述,虽然这部分看起来蛮复杂,貌似挺能吓唬住一些新手,
其实说白了,要点就是通过sysfs建立关系,沟通内核与用户空间,然后就是uevent,也就是下面要说的热插拔事件。
当然设备驱动程序一般不会和这些太底层的kobject/kset家伙打交道,因为更高层次的device,bus和driver把kobject/kset那一层
的细节实现都给封装了起来。所以设备热插拔的uevent事件最终的源头来自于device_add,本帖这里肯定不会讨论device与driver如何
绑定那一摊子事情。下面看看device_add的源码,是如何实现uevent机制的:
int device_add(struct device *dev)
{
   ...
   kobject_uevent(&dev->kobj, KOBJ_ADD);
   ...
}

热插拔的核心实现就那一个函数调用,这里device_add对应的是KOBJ_ADD,那么移除设备自然对应KOBJ_REMOVE了。
kobject_uevent函数最终调用的是kobject_uevent_env,后者才是真正干事的伙计。
下面给出kobject_uevent_env函数的核心框架:
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                    char *envp_ext[])
{
     ...
#if defined(CONFIG_NET)
     /* send netlink message */
     ...
#endif
     /* call uevent_helper, usually only enabled during early boot */
     if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
             char *argv [3];
             argv [0] = uevent_helper;
             argv [1] = (char *)subsystem;
             argv [2] = NULL;
             retval = add_uevent_var(env, "HOME=/");
             if (retval)
                     goto exit;
             retval = add_uevent_var(env,
                                     "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
             if (retval)
                     goto exit;
             retval = call_usermodehelper(argv[0], argv,
                                          env->envp, UMH_WAIT_EXEC);
     }
     ...
}

怎么样,够简洁吧,其实看实际的代码比这要郁闷地多,不过骨架清晰就行了。代码中的netlink message就不用多说了吧,
给udev发通知用(有时间的话可以分析分析udev的代码)。本帖重点讨论后半段的if (uevent_helper[0] && !kobj_usermode_filter(kobj))代码,这
里的核心调用是call_usermodehelper,这个函数最有意思的地方就在于在内核空间调用用户空间的程序,它的详细实现机制在书中已经讲得很多,
这里就不再赘述了。call_usermodehelper在kobject_uevent_env函数中要调用的用户空间程序由uevent_helper[0]来指定,
所以如果我们能控制这个uevent_helper[0],就能接收到设备加入系统移出系统等事件。那个if中的kobj_usermode_filter条件一般都会
满足(除非这是个特别注意个人隐私的设备,那就不好说了,人家偷偷加入系统就是不想让你知道你也没有办法,但是udev还是能知道的)。
下面看看uevent_helper[0]来自何处:
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;

貌似要通过内核配置来指定,我看了一下我系统中Linux目录下的.config文件,找到了下面这行:
#
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH=""

丫的,居然没指定,那么uevent_helper[0]="",这样的话我们在kobject_uevent_env函数中的那个if语句就没法满足了,
看来要重新配置再编译内核了。不过想想sysfs这么强大,内核开发的那帮人好歹给留个用户空间的接口出来吧,一查看还真有:
static ssize_t uevent_helper_store(struct kobject *kobj,
                                struct kobj_attribute *attr,
                                const char *buf, size_t count)
{
     if (count+1 > UEVENT_HELPER_PATH_LEN)
             return -ENOENT;
     memcpy(uevent_helper, buf, count);
     uevent_helper[count] = '\0';
     if (count && uevent_helper[count-1] == '\n')
             uevent_helper[count-1] = '\0';
     return count;
}

尼玛,爽得简直是一塌糊涂,虽然俺那台马力强劲的机器编个全新的内核不过几分钟的事情,但是哪里有上面这个方法爽啊。
马上进入到/sys/kernel目录下ls一把,截屏如下(点击放大):
uevent1.png
有个uevent_helper文件不是?那么我们现在可以把我们用户空间的程序给打进去了,我打算做个最简单的脚本/sbin/myhotplug,
这个脚本只干一件事,在/home/dennis目录下生成一个hotplug文件:
#!/bin/sh
cd /home/dennis
touch hotplug

然后把这个脚本程序的文件名给打入到内核空间的uevent_helper[0]上:
root@build-server:/sys/kernel# echo "/sbin/myhotplug" > uevent_helper
root@build-server:/sys/kernel# cat uevent_helper
/sbin/myhotplug

好了,现在检查一下你的/home/dennis目录下面有没有hotplug这个文件,有的话就删掉,否则怎么知道是新生成的呢。现在,
找个U盘插到你的电脑里,然后再看一下/home/dennis目录,有个hotplug文件对吧?如果你现在删除这个文件,再把U盘给拔了,
你会再次发现这个文件。这意味着什么,意味着你可以轻而易举地捕捉到设备加入/移出系统等事件,如果你的脚本足够智能,
那么你就会想到很多很有创意的玩法对吧?
执行mdev -s
:以‘-s’为参数调用位于
/sbin目录写的mdev(其实是个链接,作用是传递参数给/bin目录下的busybox程序并调用它),mdev扫描 /sys/class 和
/sys/block
中所有的类设备目录,如果在目录中含有名为“dev”的文件,且文件中包含的是设备号,则mdev就利用这些信息为这个设备在/dev
下创建设备节点文件。一般只在启动时才执行一次 “mdev -s”。

分享到:
评论

相关推荐

    Linux设备驱动程序学习(15)-Linux设备模型(热插拔、mdev 与 firmware) - Linux设备驱动程序

    本节我们将深入探讨Linux设备模型中的关键概念:热插拔、mdev(迷你设备)以及firmware(固件)在设备驱动程序中的应用。 热插拔(Hotplug)是指在系统运行时,可以动态添加或移除硬件设备的能力。在Linux中,热插...

    Linux热插拔及mdev机制

    就是由内核来启动一个用户进程,通过filter判断kset中的内核对象状态改变是否需要通知到用户层

    使用mdev来实现arm linux自动识别挂载sd卡,支持热插拔

    "使用mdev实现arm linux自动识别挂载sd卡,支持热插拔" mdev是一个Device Manager for Linux,它可以自动识别和挂载设备,包括SD卡和U盘。下面是使用mdev实现arm linux自动识别和挂载sd卡的详细步骤: 首先,在...

    基于Linux的USB摄像头热插拔状态检测

    本文将深入探讨如何在Linux环境下,利用udev工具来实现USB摄像头的热插拔状态检测,并在终端中实时显示设备的“add”(添加)和“remove”(移除)状态。 首先,udev是Linux内核设备管理系统的一部分,它负责在系统...

    Linux设备驱动程序学习

    Linux设备驱动程序学习(1)-字符设备驱动程序 ·Linux设备驱动程序学习(0)-Hello, world!模块 ·Linux设备驱动程序学习(2)-...·Linux设备驱动程序学习(15)-Linux设备模型(热插拔、mdev 与 firmware) 等等

    linux设备驱动模型--uevent篇

    在深入探讨Linux设备驱动模型的uevent机制前,我们首先简要回顾一下设备模型的基本概念。Linux设备模型是Linux内核中的一个核心组件,它提供了统一的接口来管理和操作硬件设备。设备模型的核心概念包括设备(device)...

    Linux-2[1].6-device-model.rar_linux 设备模型

    在Linux操作系统中,设备模型是系统管理硬件设备的关键机制,特别是在Linux 2.6内核及后续版本中,这一模型得到了显著的改进和扩展。这个压缩包文件"Linux-2[1].6-device-model.rar"包含了一份名为"Linux 2[1].6 ...

    Linux设备驱动程序学习(1)-字符设备驱动程序.pdf

    在Linux中,设备编号存储在`dev_t`类型中,12位用于主设备号,20位用于次设备号。编程时,可以使用`MAJOR()`和`MINOR()`宏将`dev_t`转换为主设备号和次设备号,反之,使用`MKDEV()`创建`dev_t`。注册字符设备时,...

    Linux设备驱动程序第三版

    《Linux设备驱动程序》第三版是一本深入探讨Linux内核设备驱动编程的权威书籍,针对的是Linux系统中的硬件交互和设备管理。这本书详尽地介绍了如何编写和理解Linux下的设备驱动程序,帮助开发者掌握与硬件通信的核心...

    busybox 中的mdev.txt中文版.pdf

    动态更新则需要在内核中启用热插拔支持,并在 /proc/sys/kernel/hotplug 文件中指定 mdev 的执行路径。 mdev 的优点是它可以灵活地创建和管理设备文件,使得系统管理员可以更方便地管理设备文件。 mdev 也可以用于...

    linux下的mdev用法

    mdev 是一种用于在 Linux 内核中动态创建设备节点的方法,主要用于嵌入式系统。它通常与 udev 或 BusyBox 结合使用,在启动过程中自动创建所需的设备节点。mdev 依赖于 sysfs 和 procfs 文件系统来获取硬件信息,并...

    linux启动优化:mdev -s.docx

    mdev 通过环境变量中的 ACTION 和 DEVPATH,来确定此次热插拔事件的动作以及影响了 `/sys` 中的那个目录。接着会看看这个目录中是否有“dev”的属性文件,如果有就利用这些信息为这个设备在 `/dev` 下创建设备节点...

    Linux设备驱动程序学习(1)-字符设备驱动程序[参考].pdf

    本篇主要关注字符设备驱动程序,字符设备是Linux中的基本设备类型之一,适用于一次处理一个数据单元的设备,如串口、键盘、鼠标等。 首先,我们了解设备驱动中的关键概念——主设备号和次设备号。主设备号标识了...

    jz2440学习笔记-设备驱动

    本文主要讲述了s3c2440 Linux设备驱动开发过程中的重要细节,包括字符设备驱动程序的设计、实现和测试。下面是相关知识点的总结: 1. 设备驱动程序的基本结构: 在Linux设备驱动程序中,需要定义一个结构体file_...

    Linux设备驱动程序学习(1)-字符设备驱动程序[参照].pdf

    在Linux中,设备编号存储在`dev_t`类型中,它是一个32位的数值,其中12位用于主设备号,剩下的20位用于次设备号。`MAJOR()`和`MINOR()`宏用于分别提取主设备号和次设备号,而`MKDEV()`宏用于组合主设备号和次设备号...

    busybox 中的mdev的使用说明中文版

    ### Busybox 中的mdev使用说明中文版 ...通过这种方式,可以根据具体的项目需求灵活地调整设备节点的所有权和权限,使得mdev不仅能够在嵌入式Linux环境中高效地管理设备节点,还能满足各种安全性和使用场景的需求。

    linux2.6驱动开发系列教程借鉴.pdf

    在Linux驱动开发中,基础部分涵盖了对操作系统内核的理解、设备驱动的基本概念、模块编程、内核配置以及各种设备驱动模型。以下是这些知识点的详细阐述: 1. **Linux设备驱动概述**:设备驱动是操作系统内核与硬件...

    Linux GPIO 驱动模块

    在嵌入式开发和物联网(IoT)应用中,Linux GPIO驱动常用于控制外围设备,如LED灯、传感器、电机等。例如,一个简单的应用可能就是用GPIO驱动来控制LED,通过设置GPIO的输出状态实现LED的亮灭。 此外,GPIO驱动还支持...

Global site tag (gtag.js) - Google Analytics