×
单片机 > 单片机程序设计 > 详情

S3C2440 热拔插驱动 hotplug_uevent机制 (三十三)

发布时间:2021-12-20 发布时间:
|

1、当我们每次插入U盘后,都会自动创建U盘的设备节点/dev/sda%d


这是因为里面调用了device_create()实现的,busybox的mdev机制就会根据主次设备号等信息,在/dev目录下创建设备节点,如下图所示:

而想使用上面的sda1设备节点,读写数据时,还需要使用mount /dev/sda1 /mnt来挂在U盘才行,会显得很麻烦,如下图所示:

2、其实,可以在/etc/mdev.conf文件里加入一行语句就能实现自动装载u盘,也可以在里面干其他与设备节点相关的事


2.1 而/etc/mdev.conf又是什么?


它是属于mdev的一个配置文件,而mdev之前就讲过了,它主要的功能是管理/dev目录底下的设备节点


当系统中有自动注册设备节点的时候,mdev就会/etc/mdev.conf一次,该文件可以实现与设备节点相关的事,比如自动装载usb,打印创建的设备节点信息等


3、我们首先来分析device_ceate(),是如何来调用到/etc/mdev.conf的,后面再讲如何使用mdev.conf(也可以直接跳过,直接看下面第4小节,如何使用)


(ps:之前创建字符设备节点用的class_device_create(),其实是和device_create功能差不多)


3.1 class_device_create()最终调用了:class_device_create()->class_device_register()->class_device_add():


device_create()->device_register()->device_add()函数如下所示:

int class_device_add(struct class_device *class_dev)

{

... ...

kobject_uevent(&class_dev->kobj, KOBJ_ADD); // KOBJ_ADD是一个枚举值

//调用了kobject_uevent_env(kobj, action, NULL); // action=KOBJ_ADD

}


3.2 class_device_create()->class_device_register()->class_device_add()->kobject_uevent_env()函数如下所示:


int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[])

{

char **envp;

char *buffer;

char *scratch;

int i = 0;

... ...

/* 通过KOBJ_ADD获取字符串"add",所以action_string="add" */

action_string = action_to_string(action); // action=KOBJ_ADD

/* environment index */

envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); //分配一个环境变量索引值

/* environment values */

buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); //分配一个环境变量缓冲值

/* event environemnt for helper process only */

/*设置环境变量*/

envp[i++] = "HOME=/";

envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";

scratch = buffer;

envp [i++] = scratch;

scratch += sprintf(scratch, "ACTION=%s", action_string) + 1; //"ACTION= add"

envp [i++] = scratch;

scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;

envp [i++] = scratch;

scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;

... ...

/*调用应用程序,比如mdev*/

if (uevent_helper[0]) {

char *argv [3];

argv [0] = uevent_helper; // uevent_helper[]= "/sbin/hotplug";

argv [1] = (char *)subsystem;

argv [2] = NULL;

call_usermodehelper (argv[0], argv, envp, 0); //调用应用程序,根据传入的环境变量参数来创建设备节点

}

}

从上面的代码和注释来看,最终通过*argv[],*envp[]两个字符串数组里面存的环境变量参数来创建设备节点的


3.2 接下来便在kobject_uevent_env()函数里添加打印信息,然后重新烧写uboot:


kobject_uevent_env() 函数 在 linux-2.6.22.6libkobject_uevent.c

3.3 然后我们以注册一个案件驱动为例:


加载以前的按键驱动,insmod buttons.ko打印以下语句:


class_device: argv[0]=/sbin/mdev //调用mdev

class_device: argv[1]=sixth_dev //类名

class_device: envp[0]=HOME=/

class_device: envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin

class_device: envp[2]=ACTION=add //add:表示添加设备节点,若=remove:表示卸载设备节点

class_device: envp[3]=DEVPATH=/class/sixth_dev/buttons //设备的路径

class_device: envp[4]=SUBSYSTEM=sixth_dev //类名

class_device: envp[5]=SEQNUM=745

class_device: envp[6]=MAJOR=252 //主设备号

class_device: envp[7]=MINOR=0

3.4 最终这些参数根据/sbin/mdev就进入了busybox的mdev.c的mdev_main()函数里:


int mdev_main(int argc, char **argv)

{

... ...

action = getenv("ACTION"); //获取传进来的执行参数,它等于“add”,则表示创建设备节点

env_path = getenv("DEVPATH"); //获取设备的路径“/class/sixth_dev/buttons”

sprintf(temp, "/sys%s", env_path); //指定temp (真正设备路径)为“/sys/class/sixth_dev/buttons”

if (!strcmp(action, "remove")) //卸载设备节点

make_device(temp, 1);

else if (!strcmp(action, "add")) { //创建设备节点

make_device(temp, 0);

... ...

}


3.5 最终调用mdev_main()->make_device()函数来创建/卸载设备节点,该函数如下所示:


static void make_device(char *path, int delete) //delete=0:创建, delete=1:卸载

{

/*判断创建的设备节点是否是有效的设备*/

if (!delete) {

strcat(path, "/dev");

len = open_read_close(path, temp + 1, 64);

*temp++ = 0;

if (len < 1) return;

}

device_name = bb_basename(path); //通过设备路径,来获取要创建/卸载的设备节点名称

//例: path =“/sys /class/sixth_dev/buttons”,那么device_name=“buttons”


type = path[5]=='c' ? S_IFCHR : S_IFBLK; //判断如果是在/sys/class/目录下,那么就是字符设备

//因为块设备,是存在/sys/block/目录下的

/* 如果配置了支持mdev.conf选项,那么就解析里边内容并执行 */

if (ENABLE_FEATURE_MDEV_CONF) {

/* mmap the config file */

fd = open("/etc/mdev.conf", O_RDONLY); //调用/etc/mdev.conf配置文件

... ... //开始操作 mdev.conf配置文件

}

if (!delete) { //如果是创建设备节点

if (sscanf(temp, "%d:%d", &major, &minor) != 2) return; //获取主次设备号

/*调用mknod ()创建字符设备节点*/

if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST)

bb_perror_msg_and_die("mknod %s", device_name);

if (major == root_major && minor == root_minor)

symlink(device_name, "root");

/*若配置了支持mdev.conf选项,则调用chown命令来改变属主,默认uid和gid=0 */

if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);

}

if (delete) unlink(device_name); //如果是卸载设备节点

}

从上面的代码和注释分析到,要使用mdev.conf配置文件,还需要配置busybox的menuconfig,使mdev支持mdev.conf选项才行


如下图,进入busybox目录,然后输入make menuconfig,发现我们已经配置过了该选项了

4、接下来,便来看看如何使用mdev.conf,参考:busybox-1.7.0docsmdev.txt文档


使用方法如下所示:


the format: : [ ]


The speci



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Keil(MDK-ARM)系列教程(七)_菜单