1、为什么有hotplug_uevent机制
(1)查看驱动程序,以前是构造file_operation结构体。
(2)在入口函数来注册它。
(3)为什么还要创建类,为什么还要在类下创建设备,这样做是为了让mdev根据这些信息来创建设备节点
(4)分析为什么class_device_create这个函数能让mdev创建设备节点
class_device_create
class_device_register
class_device_add
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
kobject_uevent_env(kobj, action, NULL);
/ / action_string = "add";
action_string = action_to_string(action);
/* 分配保存环境变量的内存 */
/* environment values */
buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
/* 设置环境变量 */
envp [i++] = scratch;
scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
envp [i++] = scratch;
scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
envp [i++] = scratch;
scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
/* 调用应用程序: 比如mdev */
/* 启动脚本 echo /sbin/mdev > /proc/sys/kernel/hotplug
* 设置了uevent_helper为“/sbin/mdev“
*/
argv [0] = uevent_helper; // 假设argv [0] = "/sbin/mdev"
argv [1] = (char *)subsystem;
argv [2] = NULL;
call_usermodehelper (argv[0], argv, envp, 0);//创建一个进程argv[0](调用应用 程序),应用程序根据环境变envp量来创建设备节点
(4)打印应用程序的名字argv[0]和环境变量envp
这里在循环打印环境变量中,其环境变量的循环次数界限值用envp[i],主要是想数组元素不存在时退出。
应用程序根据环境变量来创建设备节点。
2、实验
(1)修改内核程序
(2)编译内核make uImage并把编译好的内核拷贝到网络文件系统那里去
(3)reboot命令重启开发板用新内核启动
(4)启动内核
(5)把编译好的驱动模块拷贝到网络文件系统
(6)装载模块
可以看出uevent_helper函数是/sbin/mdev,打印出来的环境变量存在问题
3、环境变量打印存在问题,缺少一个变量
(1)重新执行之前操作出现各种环境变量
(3)装载驱动
驱动程序里面会调用class_device_create函数,最终调用call_usermodehelper (argv[0], argv, envp, 0);//创建一个进程argv[0](调用应用程序/sbin/mdev),应用程序根据环境变envp量来创建设备节点
4、应用程序根据环境变envp量来创建设备节点分析
(1)分析busybox的mdev.c里面的main 函数
如果不是mdev -s,是指一开始启动的时候
(2)在etc/init.d/rcS中有mdev -s
(3)看mdev的意思
带-s参数是在系统启动时扫描/sys and populate这个目录,根据里面的信息创建各种设备节点,产生/dev目录
(4)mdev_main函数分析
上面打印环境变量时已经知道action等于add,也就是执行make_device(temp, 0)函数。
- 在make_device(temp, 0)函数中//创建设备节点
- 因为temp = /sys/class/sixth_drv/buttons,因为temp等于envpath,而envpath等于DEVPATH,查看打印出来的环境变量可知DEVPATH=/class/sixth_drv/buttons
- bb_basename(path)这里的path和上面的temp等价
下面分析bb_basename()函数,strrchr函数是找到name里面倒数第一个反斜杠,返回这个斜杠后面的字符串,也就是找到buttons,设备节点的名字就定下来了啦
类型根据path数组的第5个元素是否为'c'来判断,'c' == > 字符设备节点。根据上面分析path等于temp ,看temp = /sys/class/sixth_drv/buttons中第5个值,应该是c,应该是字符设备,也就是class目录下都是字符设备
- 看make_device函数
extern char *strcat(char *dest, const char *src);
- 看主次设备号
创建设备节点,这里的设备文件名device_name = bb_basename(path); = "buttons"。
5、知识点回顾
(1)mdev_main函数根据传进来的环境变量,根据action是add就创建设备节点。根据devpath这个参数在前面加一个/sys创建设备节点
(2)创建设备节点(知道设备名字,设备类型(字符设备,块设备,网络设备),主次设备号)
(3)根据/sys/class/sixth_drv/buttons目录下的dev下的内容确定主次设备号
根据/sys/class/sixth_drv/buttons目录中第5个字符是否为C来判断是否为字符类型的设备
(4)我们的驱动程序在类下面创建设备节点(通过class_device_create这个函数),最终会导致调用call_usermodehelper这个函数会调用应用程序(一般设置为/sbin/mdev),这个应用程序会根据环境变量来创建设备节点。
(5)uevent_helper为什么是“/sbin/mdev“,在启动脚本里/etc/init.d/rcS里有
echo /sbin/mdev >/proc/sys/kernel/hotplug
因而设置字符串uevent_helper为“/sbin/mdev“
(6)在出口函数里面有class_device_unregister函数
这个函数类似于class_device_create这个函数
卸载驱动,可以看到action等于remove