二十3、uevnet機制和U盤自動掛載

1、uevent機制

在分析以前,咱們首先要知道uevent做用是什麼。在此咱們先來看一個uevent機制的框架圖:html

該圖片來自:Linux設備模型(3)_Ueventlinux

經過圖片咱們能夠肯定uevent的做用:設備產生上報事件時會觸發uevent接口,uevent則經過netlink和kmod這兩種方式把事件上報到用戶空間。kmod會直接調用用戶空間的程序,netlink只是將事件上報到用戶空間。正則表達式

 

以前咱們分析的大部分設備驅動都會在/dev/目錄下建立節點給用戶使用。那麼在咱們調用device_create()後內核會作什麼呢?vim

如今咱們來分析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/mdevide

 

/sbin/mdev定義在busybox的mdev.c中:函數

咱們使用SI4建立busybox工程後,打開mdev.c,分析mdev_main()函數:post

 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

此函數最終調用make_device(temp, 0)建立設備,調用層次以下:ui

make_device(temp, 0);
  -> device_name = bb_basename(path);
  -> if (ENABLE_FEATURE_MDEV_CONF)                            /* 若是配置了支持mdev.conf選項 */
    -> fd = open("/etc/mdev.conf", O_RDONLY);                 /* 操做mdev.conf文件 */
  -> if (!delete)                                             /* 若是是建立設備節點 */
    -> mknod(device_name, mode | type, makedev(major, minor)  /* 建立節點 */

 

下面咱們來看看如何使用mdev.conf,參考工程中mdev.txt文件:

如設置初始化腳本/etc/init.d/rcS:

Here's a typical code snippet from the init script:
[1] mount -t sysfs sysfs /sys
[2] echo /bin/mdev > /proc/sys/kernel/hotplug
[3] mdev -s

Of course, a more "full" setup would entail executing this before the previous
code snippet:
[4] mount -t tmpfs mdev /dev
[5] mkdir /dev/pts
[6] mount -t devpts devpts /dev/pts

/etc/ndev.conf文件格式:

the format:
    <device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]
The special characters have the meaning:
    @ Run after creating the device.
    $ Run before removing the device.
    * Run both after creating and before removing the device.
the format:
    <device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]
The special characters have the meaning:
    @ Run after creating the device.
    $ Run before removing the device.
    * Run both after creating and before removing the device.

其中,

<device regex>:正則表達式,可參考:正則表達式 - 語法 | 菜鳥教程

<uid>:用戶ID

<gid>:組ID

<octal permissions>:/dev/dma_test的權限

<command>:命令

 

瞭解上面知識後,下一節開始編輯mdev.conf實現U盤自動掛載

 

 

2、編輯mdev.conf實現U盤自動掛載

在網絡文件系統根目錄中執行:

# vim etc/mdev.conf

添加一行:

sda[1-9]+ 0:0 660 * if [ $ACTION = "add" ]; then mount /dev/$MDEV /mnt; else umount /mnt; fi

其中,

sda[1-9]+表示重複匹配1-9的數字屢次

*表示建立設備節點以後和刪除設備節點以前執行命令

命令表示若是ACTION是add,則掛載,不然取消掛載

 

效果以下圖,亂碼是因爲開發板不支持中文:

 

 

下一章  二十4、V4L2框架主要結構體分析和虛擬攝像頭驅動編寫

相關文章
相關標籤/搜索