嵌入式linux之mdev机制分析

2019-07-12 16:41发布

一、mdev分析

1、作用

首先我们先说明它的作用是什么,然后分析为什么能产生这种作用。
在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所需的设备节点即/dev/xxx。同时可以设置一些脚本,并执行,脚本可以设置一下设备节点的读写权限,或者进行挂载等。mdev是udev的简化版本,它也是通过读取内核信息来创建设备文件

以前的按键驱动程序,入口函数,为什么创建类呢,为什么在类下创建设备节点呢?是为了让mdev根据这些信息来创建设备节点。
按键驱动程序中我们这么做:

sixthdrv_class = class_create(THIS_MODULE, "sixth_drv"); sixthdrv_class_dev = device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); 最后产生 /dev/buttons设备节点。

2、函数调用流程

device_create—>device_create_vargs—>device_register—>device_add—>kobject_uevent (&dev->kobj, KOBJ_ADD) —>kobject_uevent_env (kobj, action, NULL) —>
// action_string = "add"; const char *action_string = kobject_actions[action]; /* environment buffer */ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); /* 设置环境变量 */ retval = add_uevent_var(env, "ACTION=%s", action_string); retval = add_uevent_var(env, "DEVPATH=%s", devpath); retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
/* 调用应用程序: 比如mdev,启动脚本 echo /sbin/mdev > /proc/sys/kernel/hotplug 设置了uevent_helper为“/sbin/mdev“*/

argv [0] = uevent_helper; argv [1] = (char *)subsystem; argv [2] = NULL; retval = call_usermodehelper(argv[0], argv,env->envp, UMH_WAIT_EXEC);
调用了busybox文件系统中的 mdev.c  
修改内核,添加参数打印:


uevent_helper = /sbin/mdev envp[0] = HOME=/ envp[1] = PATH=/sbin:/bin:/usr/sbin:/usr/bin envp[2] = ACTION=add envp[3] = DEVPATH=/class/sixth_drv/buttons envp[4] = SUBSYSTEM=sixth_drv envp[5] = SEQNUM=720 envp[6] = MAJOR=252 envp[7] = MINOR=0

3、分析busybox mdev.c

mdev_main temp = /sys/class/sixth_drv/buttons make_device(temp, 0); /* 确定设备文件名,类型,主次设备号 */ device_name = bb_basename(path); = "buttons" 'c' == > 字符设备节点 根据"/sys/class/sixth_drv/buttons/dev"的内容确定主次设备号 mknod(device_name, mode | type, makedev(major, minor) 最后mdev调用了mknod创建设备节点,从而在/dev下产生/dev/buttons设备节点。到此知道了原来/dev下的设备节点是这么创建的!

如何在设备创建的时候执行一些脚本呢?比如修改设备节点权限,自动挂接U盘等。
需要添加/etc/mdev.conf配置文件。mdev.c会解析此配置文件,一旦匹配到设备,则可以执行一些脚本命令。 代码分析: int mdev_main(int argc UNUSED_PARAM, char **argv) { //mdev -s:mdev -s is to be run during boot to scan /sys and populate /dev. if (argv[1] && strcmp(argv[1], "-s") == 0){} snprintf(temp, PATH_MAX, "/sys%s", env_path); //static void make_device(char *path, int delete) make_device(temp, /*delete:*/ 0); { /* Determine device name, type, major and minor */ device_name = (char*) bb_basename(path); mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST } }

3.1 mdev.conf的格式:

: [<@|$|*> ]
device regex:正则表达式,表示哪一个设备
uid: owner
gid: 组ID
octal permissions:以八进制表示的属性
@:创建设备节点之后执行命令
$:删除设备节点之前执行命令
*: 创建设备节点之后 和 删除设备节点之前 执行命令
command:要执行的命令


3.2 写mdev.conf

1. leds 0:0 777 led1 0:0 777 led2 0:0 777 led3 0:0 777 2. leds?[123]? 0:0 777 3. leds?[123]? 0:0 777 @ echo create /dev/$MDEV > /dev/console 4. leds?[123]? 0:0 777 * if [ $ACTION = "add" ]; then echo create /dev/$MDEV > /dev/console; else echo remove /dev/$MDEV > /dev/console; fi 5. leds?[123]? 0:0 777 * /bin/add_remove_led.sh 把命令写入一个脚本: add_remove_led.sh #!/bin/sh if [ $ACTION = "add" ]; then echo create /dev/$MDEV > /dev/console; else echo remove /dev/$MDEV > /dev/console; fi 6. U盘自动加载 sda[1-9]+ 0:0 777 * if [ $ACTION = "add" ]; then mount /dev/$MDEV /mnt; else umount /mnt; fi 7. sda[1-9]+ 0:0 777 * /bin/add_remove_udisk.sh add_remove_udisk.sh #!/bin/sh if [ $ACTION = "add" ]; then mount /dev/$MDEV /mnt; else umount /mnt; fi

二、扩展etc配置分析

1、busybox文件目录中/doc/mdev.txt中写到

Here's a typical code snippet from the initscript: [0] mount -t proc proc /proc [1] mount -t sysfs sysfs /sys [2] echo /sbin/mdev >/proc/sys/kernel/hotplug [3] mdev -s Of course, a more "full" setup wouldentail executing this before the previous code snippet: [4] mount -t tmpfs -o size=64k,mode=0755 tmpfs/dev [5] mkdir /dev/pts [6] mount -t devpts devpts /dev/pts

所以在/etc/init.d/rcS配置如下

#!/bin/sh ifconfig eth0 192.168.1.17 mount -a mkdir /dev/pts #使用内存文件系统,减少对flash的读写 mount -t devpts devpts /devpts #/dev/pts用来支持外部网络链接(telnet:远程访问摄像头)的虚拟终端 echo /sbin/mdev > /proc/sys/kernel/hotplug #设置内核,当有设备插拔时调用/bin/mdev程序 mdev -s #在/dev目录下生成内核支持的所有设备的节点

2、在busybox文件目录中/doc/mdev.txt还有如下关键说明

The simple explanation here is that [1] youneed to have /sys mounted before executing mdev. [4]make sure /dev is a tmpfs filesystem (assuming you're running out of flash). Thenyou want to [5] create the /dev/pts mount point and finally [6] mount thedevpts filesystem on it  所以要修改/etc/fstab来自动挂载文件系统,修改etc/init.d/rcS加入要自动运行的命令。 #device mount-point type options dump fsck order proc /proc proc defaults 0 0 tmpfs/tmp tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 0 tmpfs/dev tmpfs defaults 0 0

3.linux虚拟文件系统

   1、linux有几种虚拟的文件系统类型(只存在于内核,在物理内存不存在,不过我们可以用挂载的方式将它在物理内存上进行映射,如mount-t proc proc /proc;将cpu,mem等信息挂载在硬盘中),比如proc,sysfs,tmpfs,root.
  2、proc是内核用的文件系统,用于显示内核信息及改变内核参数;
  3、sysfs文件系统用来管理和显示各种设备的运行参数及设备的层次结构。//能减少对flash的对写
  4、tmpfs:能解决临时的设备(/dev)或文件(/tmp)访问速度慢的缺点。

4./etc/fstab 的用途

/etc/fstab 是设定分割区分 mount目录相关的档案,开机时会依这个档案的內容 mount 档案系統,mount档案系統的命令为:
   linux# mount -av
会依 /etc/fstab的內容 mount 进"除了 root 以外的所有档案系統"。
root 是在开机时由核心所 mount 进來的。root 先由核心mount 成 read-only,然后由使用者手动remount 成 read-write。

5. /etc/inittab

init根据/etc/inittab配置文件来执行相应的脚本进行系统初始化,如设置键盘、字体,装载模块,设置网络;
 init 是在核心 mount 进 root 后,第一個执行的程式 (第一个 process)

开机后执行上述文件的过程: 开机==>mount -t root root /root (此句内核自动执行)==> /etc/fstab ==>/etc/inittab ==> 执行/etc/rc.d/目录下的脚本(包括/etc/init.d/rcS)