在分析之前,我们首先要知道uevent作用是什么。在此我们先来看一个uevent机制的框架图:

23、uevnet机制和U盘自动挂载

该图片来自:Linux设备模型(3)_Uevent

通过图片我们可以确定uevent的作用:设备产生上报事件时会触发uevent接口,uevent则通过netlink和kmod这两种方式把事件上报到用户空间。kmod会直接调用用户空间的程序,netlink只是将事件上报到用户空间。

 

之前我们分析的大部分设备驱动都会在/dev/目录下创建节点给用户使用。那么在我们调用device_create()后内核会做什么呢?

现在我们来分析device_create()的详细调用关系:

device_create()
  -> va_start(vargs, fmt);              /* 初始化va_list可变参数变量 */
  -> dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
    -> dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    -> dev->devt = devt;                /* 设置device成员 */
    -> retval = device_register(dev);
      -> device_initialize(dev);        /* 初始化device链表头 */
      -> device_add(dev);               /* 添加device */
        -> kobject_uevent(&dev->kobj, KOBJ_ADD);
          -> kobject_uevent_env(kobj, action, NULL);
            -> env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);      /* 分配环境变量 */
            -> if (uevent_helper[0] && !kobj_usermode_filter(kobj))
              -> argv [0] = uevent_helper;    /* 下面调用的就是uevent_helper程序 */
              -> call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC); /* 调用应用程序argv[0] */
  -> va_end(vargs);

为了确定调用程序,我们可以在代码中添加打印语句,如8-14行:

 1 if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
 2     char *argv [3];
 3 
 4     argv [0] = uevent_helper;
 5     argv [1] = (char *)subsystem;
 6     argv [2] = NULL;
 7 
 8     int i;
 9     for (i = 0; i < 2; ++i) {    /* 参数 */
10         printk("device: argv[%d] = %s\n", i, argv[i]);
11     }
12     for (i = 0; env[i]; ++i) {   /* 环境变量 */
13         printk("device: envp[%d] = %s", i, env[i]);
14     }
15 
16     retval = add_uevent_var(env, "HOME=/");
17     if (retval)
18         goto exit;
19     retval = add_uevent_var(env,
20                 "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
21     if (retval)
22         goto exit;
23 
24     retval = call_usermodehelper(argv[0], argv,
25                      env->envp, UMH_WAIT_EXEC);
26 }

重新编译烧写内核后,insmod某个模块后可以确定uevent_helper为/sbin/mdev

23、uevnet机制和U盘自动挂载

 

/sbin/mdev定义在busybox的mdev.c中:

23、uevnet机制和U盘自动挂载

我们使用SI4创建busybox工程后,打开mdev.c,分析mdev_main()函数:

23、uevnet机制和U盘自动挂载
 1 int mdev_main(int argc, char **argv)
 2 {
 3     char *action;
 4     char *env_path;
 5     RESERVE_CONFIG_BUFFER(temp,PATH_MAX);
 6 
 7     xchdir("/dev");
 8 
 9     if (argc == 2 && !strcmp(argv[1],"-s")) {        /* 判断参数个数,如果不是mdev -s进入if */
10         struct stat st;
11 
12         xstat("/", &st);
13         root_major = major(st.st_dev);
14         root_minor = minor(st.st_dev);
15 
16         recursive_action("/sys/block",
17             ACTION_RECURSE | ACTION_FOLLOWLINKS,
18             fileAction, dirAction, temp, 0);
19 
20         recursive_action("/sys/class",
21             ACTION_RECURSE | ACTION_FOLLOWLINKS,
22             fileAction, dirAction, temp, 0);
23 
24     } else {                                        /* 热拔插mdev -s */
25         action = getenv("ACTION");                    /* 设备驱动中ACTION = add */
26         env_path = getenv("DEVPATH");                /* DEVPATH = /class/dma_test */
27         if (!action || !env_path)
28             bb_show_usage();
29 
30         sprintf(temp, "/sys%s", env_path);            /* temp = /sys/class/dma_test */
31         if (!strcmp(action, "remove"))
32             make_device(temp, 1);
33         else if (!strcmp(action, "add")) {
34             make_device(temp, 0);
35 
36             if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE)
37                 load_firmware(getenv("FIRMWARE"), temp);
38         }
39     }
40 
41     if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp);
42     return 0;
43 }
View Code

相关文章:

  • 2021-11-28
  • 2022-01-12
  • 2021-08-15
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-07-30
  • 2022-03-04
猜你喜欢
  • 2021-11-03
  • 2022-12-23
  • 2021-09-12
  • 2021-12-05
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案