1. kobj、kset 分析:
http://www.wowotech.net/device_model/421.html
2. uevent 设备模型:
http://www.wowotech.net/device_model/uevent.html
3. 分析 linux3.4.xxx 内核中设备节点的创建过程:
在linux3.4.xxx中,linux创建设备节点的函数是 device_create,然后发生了什么呢?
device_create
--> device_create_vargs
--> device_create_groups_vargs
--> device_register
--> device_add
--> kobject_uevent(&dev->kobj, KOBJ_ADD);
--> kobject_uevent_env(kobj, action, NULL);
--> action_string = action_to_string(action); // action_string = "add";
--> add_uevent_var(env, "ACTION=%s", action_string);
add_uevent_var(env, "DEVPATH=%s", devpath);
...
--> argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
--> call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC); // 向用户空间发送消息
其中上边的 uevent_helper 是 由于busybox制作的根文件系统中的启动脚本的 echo /sbin/mdev > /proc/sys/kernel/hotplug 这句决定了这里的 uevent_helper = "/sbin/mdev"
当我们运行一个按键驱动,并用上边的函数自动创建设备节点,
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
/sbin/mdev 是 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)
至此,设备节点创建完成。
接上 U 盘,想自动挂载的方法是需要在 mdev.conf 文件中设定规则:
我们先来看一下 busybox/docs/mdev.txt
4. mdev.txt
基本的使用
=========
mdev 有两个主要的使用:初始化总体和动态更新。两个都要求内核配置上了支持 sysfs,并把它挂载到了 /sys。对于动态更新,你还需要内核 hotplugging 使能。
这是在初始化脚本中典型的代码片段:
[0] mount -t proc proc /proc
[1] mount -t sysfs sysfs /sys
[2] echo /bin/mdev > /proc/sys/kernel/hotplug
[3] mdev -s
没有上边的 procfs 的方式:
[1] mount -t sysfs sysfs /sys
[2] sysctl -w kernel.hotplug=/bin/mdev
[3] mdev -s
当然,一个完整的 setup 应该还需要执行下边的代码片段
[4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev
[5] mkdir /dev/pts
[6] mount -t devpts devpts /dev/pts
简单解释:[1] 需要 sysfs 挂载到 /sys。之后 [2] 通知内核当添加和删除设备节点时执行 /bin/mdev。之后 [3] 在系统启动时在 /dev 下产生出各个设备的节点。[4] 确保 /dev 是一个 tmpfs 文件系统。之后你想 [5] 创建 /dev/pts 设备节点,最后挂载 devpts文件系统到 /dev/pts 上。
MDEV 配置(/etc/mdev.conf)
=========
Mdev 有一个选项配置文件,用于控制节点间的关系和权限。默认情况下 root/root 660 的权限
格式:
<device regex> <uid>:<gid> <octal permissions>
例如:
hd[a-z][0-9]* 0:3 660
你能重命名/重新定位 设备节点 通过使用下一个可选域。
<device regex> <uid>:<gid> <octal permissions> [>path]
所以如果你想放置节点到字目录,确保你的路径最后有一个 /。如果你想重命名设备节点,把名字写上就行了。
hda 0:3 660 >drives/
上边的是将hda设备节点重定位到了 drivers/ 子目录下了。
hda 0:3 660 >cdrom
上边重命名 hda 到 cdrom
如果你想执行某个命令格式如下:
<device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]
特殊字符标识的意思:
@ 创建设备后运行
$ 移除设备之前运行
* 创建之后、移除之前都运行
FIRMWARE
=========
一些内核驱动在运行时为了正确的初始化需要请求固件。把固件集中放在 /lib/firmware/ 。在运行时,内核会传递固件名给mdev,并运行 mdev。
5. 正则表达式:
1)在电脑上查文件。*.c 中的*,是通配符,任意字符
2)正则表达式:
. 表示任意字符(换行符除外)
* 表示重复0次或者更多次
+ 表示重复一次或更多次
?表示重复0次或1次
[abc] 表示这些字符里边的某个
[abc]
[1-9]
6. 一些例子:
1)我们想把下边的内容囊括成一个规则:
leds 0:0 777
led1 0:0 777
led2 0:0 777
led3 0:0 777
-->
leds?[123]? 0:0 777 @ echo create /dev/$MDEV > /dev/console
s出现一次或0次,1、2、3出现一次或0次都执行将节点名字打印到终端上。添加后和删除前都执行
-->
leds?[123]? 0:0 777 * if [ $ACTION = "add" ]; then echo create /dev/$MDEV > /dev/console; else echo remove /dev/$MDEV > /dev/console; fi
具体将添加和删除分开
-->
把命令写入一个脚本:
leds?[123]? 0:0 777 * /bin/add_remove_led.sh
#!/bin/sh
if [ $ACTION = "add" ];
then
echo create /dev/$MDEV > /dev/console;
else
echo remove /dev/$MDEV > /dev/console;
fi
2)U 盘自动加载:
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