title: hotplug/mdev机制

date: 2019/1/9 19:35:14

toc: true

hotplug/mdev机制

框架

我们以前创建设备的时候,使用class_create来自动创建设备,是利用了mdev根据我们的提供的信息来创建设备节点

kobject_uevent_env

我们使用drv_class_dev来创建设备,具体的实例如下

drv_class = class_create(THIS_MODULE, "drv");
drv_class_dev = class_device_create(drv_class, NULL, MKDEV(major, 0), NULL, "xyz%d", minor);

继续分析class_device_create,可以看到最后调用kobject_uevent_env来调用我们自己设置的辅助函数uevent_helper,可以在内核加入打印函数打印这个变量

drv_class = class_create(THIS_MODULE, "drv");
drv_class_dev = class_device_create(drv_class, NULL, MKDEV(major, 0), NULL, "xyz%d", minor);
class_device_register(class_dev);
class_device_initialize(class_dev);
class_device_add(class_dev);
//KOBJ_ADD = (__force kobject_action_t) 0x01, /* exclusive to core */
sysfs_create_link(&class_dev->kobj,&class_dev->dev->kobj, "device");
kobject_uevent(&class_dev->kobj, KOBJ_ADD); // 设置环境变量后调用辅助函数
kobject_uevent_env(kobj, action, NULL)
{
action_string = action_to_string(action); //return "add";
/* environment index */
envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
/* environment values */
buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
/* complete object path */
devpath = kobject_get_path(kobj, GFP_KERNEL); /* event environemnt for helper process only */
envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
// 先将指针scratch指向分配到的buffer
// 再赋值到envp 环境变量中
/* default keys */
scratch = buffer;
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;
for (j = 0; envp_ext && envp_ext[j]; j++)
envp[i++] = envp_ext[j];
... //我们自己在这里加入打印函数,查看下环境变量和uevent_helper
printk("userhelp=%s\n",uevent_helper);
for (i=0;envp[i];i++) {
printk("envp[%d]=%s\n",i,envp[i]);
}
printk("argv[1]=%s\n",subsystem); // 辅助函数,也就是我们自动创建设备的mdev
/* call uevent_helper, usually only enabled during early boot */
if (uevent_helper[0]) {
char *argv [3]; argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
call_usermodehelper (argv[0], argv, envp, 0);
}
}

启动后加载一个驱动,打印如下,起始启动内核的时候也有许多的打印,userhelp=/sbin/hotplug

// filename =dri_src.c
major=register_chrdev(0, "drv_register", &drv_fops); // 注册, 告诉内核
drv_class = class_create(THIS_MODULE, "drv_class");
drv_class_dev = class_device_create(drv_class, NULL, MKDEV(major, 0), NULL, "xyz%d", minor);

可以看到个信息包含了主次设备号,文件路径,模块的名字等,这里注意一下,当你修改了一个模块 a.ko 为 b.ko ,加载b.ko 后使用lsmod显示的依然是 a 模块,这里的信息也是 a 模块的

这里的argv[1]其实就是envp[4]也就是类名

# insmod dri_src.ko

userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/module/dri_src #模块名,一般就是文件名,但这个文件名指的是当时编译好的名字,也就是C文件的名字,生成ko后修改名字无效
envp[4]=SUBSYSTEM=module
envp[5]=SEQNUM=754
argv[1]=module
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/class/drv_class/xyz0 #设备文件的描述,最终会生成文件 /dev/xyz0
#输入子系统这里是 envp[3]=DEVPATH=/class/input/input1/event1
envp[4]=SUBSYSTEM=drv_class #类的名字 class_create创建,如果是输入子系统这里是
# envp[4]=SUBSYSTEM=input
envp[5]=SEQNUM=755
envp[6]=MAJOR=252
envp[7]=MINOR=0
argv[1]=drv_class #就是类名 # rmmod dri_src #卸载模块的时候使用ACTION=remove
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=remove
envp[3]=DEVPATH=/class/drv_class/xyz0
envp[4]=SUBSYSTEM=drv_class
envp[5]=SEQNUM=756
envp[6]=MAJOR=252
envp[7]=MINOR=0
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=remove
envp[3]=DEVPATH=/class/drv_class
envp[4]=SUBSYSTEM=class
envp[5]=SEQNUM=757
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=remove
envp[3]=DEVPATH=/module/dri_src
envp[4]=SUBSYSTEM=module
envp[5]=SEQNUM=758

mdev_main

接下来就去执行函数/sbin/mdev,也就是busybox的应用程序,定义在busybox-1.7.0\util-linux\mdev.c

匹配后执行make_device(temp, 0);,getenv是个库函数,我们之前在kobject_uevent_env设置了参数

mdev_main(int argc, char **argv)
//扫描模式,一般是上电用的
scan
//我们自己实际用的
action = getenv("ACTION");
env_path = getenv("DEVPATH"); sprintf(temp, "/sys%s", env_path);
if (!strcmp(action, "remove"))
make_device(temp, 1);
else if (!strcmp(action, "add")) {
make_device(temp, 0);

make_device

kernel 传递的DEVPATHenvp[3]=DEVPATH=/class/drv_class/xyz0,也就是参数实际是/sys/class/drv_class/xyz0

  1. 先判断是否已经有设备文件被创建了,也就是去 /sys/class/drv_class/xyz0/dev是否存在 这个文件包含了主次设备号
// 先判断是否设备文件已经存在,也就是判断  /sys/class/drv_class/xyz0/dev是否存在 这个文件包含了主次设备号
//# cat /sys/class/drv_class/xyz0/dev
//252:0
// strcat 拼接字符串 if (!delete) {
strcat(path, "/dev");
len = open_read_close(path, temp + 1, 64);
*temp++ = 0;
if (len < 1) return;
}
  1. 然后判断设备类型,就去读取到classc字符,就判断是字符设备了
	/// sys/class/drv_class/xyz0
device_name = bb_basename(path);
//bb_basename 从前往后找到最后一个"/",这里就是找到文件名
type = path[5]=='c' ? S_IFCHR : S_IFBLK;
  1. 如果有配置文件,根据配置文件读取
	if (ENABLE_FEATURE_MDEV_CONF)
{
fd = open("/etc/mdev.conf", O_RDONLY);
}
  1. 创建实际的设备节点,如果有配置文件,还需要手动更改设备文件属性
	if (!delete) {
// 从设备文件的描述读取主次设备号 /sys/class/drv_class/xyz0/dev
if (sscanf(temp, "%d:%d", &major, &minor) != 2) return;
// mknod 创建设备文件 type=c 就是字符设备 makedev 包含了主次设备号
if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) if (major == root_major && minor == root_minor)
symlink(device_name, "root"); // 如果有配置文件,还需要手动更改设备文件属性
if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);
}
  1. 所以我们如果需要使用配置文件自动创建设备文件,则需要使能ENABLE_FEATURE_MDEV_CONF,在make menuconfig 搜索mdev,可以看到已经启用了
│     -> Linux System Utilities                                                          │
│ -> mdev (MDEV [=y]) │
│ -> Support /etc/mdev.conf (FEATURE_MDEV_CONF [=y])

mdev.conf

如何使用这个配置文件去自动创建设备文件? 我们搜索文档busybox-1.7.0/docs/mdev.txt查看如下格式,也就是发现设备文件(前/后)来执行命令

The file has the format:
<device regex> <uid>:<gid> <octal permissions> For example:
hd[a-z][0-9]* 0:3 660 <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: owner
gid: 组ID
octal permissions:以八进制表示的属性
用户组 读写执行+读写执行+读写执行 110+110+000=660=crwcrw---
@:创建设备节点之后执行命令
$:删除设备节点之前执行命令
*: 创建设备节点之后 和 删除设备节点之前 执行命令
command:要执行的命令

配置文件学习

存在这样一个驱动,自动创建4个设备文件,代码仓库的4th

for (minor = 0; minor < 4; minor++)
{
firstdrv_class_dev[minor] = class_device_create(firstdrv_class, NULL, MKDEV(major, minor), NULL, "xyz%d", minor);
}

自动创建设备如下

# ls /dev/xyz* -l
crw-rw---- 1 0 0 252, 0 Jan 4 07:13 /dev/xyz0
crw-rw---- 1 0 0 252, 1 Jan 4 07:13 /dev/xyz1
crw-rw---- 1 0 0 252, 2 Jan 4 07:13 /dev/xyz2
crw-rw---- 1 0 0 252, 3 Jan 4 07:13 /dev/xyz3

更改属性

使用字符全匹配,更改权限为777,先卸载驱动

# vi /etc/mdev.conf
xyz0 0:0 777
xyz1 0:0 777
xyz2 0:0 777 # ls /dev/xyz* -l
crwxrwxrwx 1 0 0 252, 0 Jan 4 07:21 /dev/xyz0
crwxrwxrwx 1 0 0 252, 1 Jan 4 07:21 /dev/xyz1
crwxrwxrwx 1 0 0 252, 2 Jan 4 07:21 /dev/xyz2
crw-rw---- 1 0 0 252, 3 Jan 4 07:21 /dev/xyz3

使用正则匹配

# vi /etc/mdev.conf
xyz[0123]? 0:0 777 # ls /dev/xyz* -l
crwxrwxrwx 1 0 0 252, 0 Jan 4 07:25 /dev/xyz0
crwxrwxrwx 1 0 0 252, 1 Jan 4 07:25 /dev/xyz1
crwxrwxrwx 1 0 0 252, 2 Jan 4 07:25 /dev/xyz2
crwxrwxrwx 1 0 0 252, 3 Jan 4 07:25 /dev/xyz3

@:创建设备节点之后执行命令

这里使用@表示在创建设备节点后执行命令

# vi /etc/mdev.conf
xyz[0123]? 0:0 777 @ echo create /dev/$MDEV > /dev/console insmod dri.ko
# create /dev/xyz2
create /dev/xyz3
create /dev/xyz0
create /dev/xyz1

$:删除设备节点之前执行命令

# vi /etc/mdev.conf
xyz[0123]? 0:0 777 $ echo del /dev/$MDEV > /dev/console insmod dri.ko
# del /dev/xyz2
del /dev/xyz3
del /dev/xyz0
del /dev/xyz1

*: 创建之后 和 删除之前

注意$ACTION前有个空格,不能少

# cat /etc/mdev.conf
xyz[0123]? 0:0 777 * if [ $ACTION = "add" ];then echo create /dev/$MDEV > /dev/console; else echo del /dev/$MDEV > dev/console ;fi #insmod dri_4th.ko
# create /dev/xyz2
create /dev/xyz3
create /dev/xyz0
create /dev/xyz1 #rmmod dri
del /dev/xyz1
del /dev/xyz0
del /dev/xyz2
del /dev/xyz3

使用脚本

创建一个脚本文件mdev.sh,放到一个指定的目录,加入执行权限hmod +x /mnt/mdev.sh

#!/bin/sh
if [ $ACTION = "add" ];
then
echo create /dev/$MDEV > /dev/console;
else
echo remove /dev/$MDEV > /dev/console;
fi

修改配置文件

# chmod +x /mnt/mdev.sh
# cat /etc/mdev.conf
xyz[0123]? 0:0 777 * /mnt/mdev.sh

然后会和上面同样的结果

U盘自动挂载

u盘插入

usb 1-1: new full speed USB device using s3c2410-ohci and address 3
usb 1-1: configuration #1 chosen from 1 choice
scsi1 : SCSI emulation for USB Mass Storage devices
sd 1:0:0:0: [sda] 60555264 512-byte hardware sectors (31004 MB)
sd 1:0:0:0: [sda] Write Protect is off
sd 1:0:0:0: [sda] Assuming drive cache: write through
sd 1:0:0:0: [sda] 60555264 512-byte hardware sectors (31004 MB)
sd 1:0:0:0: [sda] Write Protect is off
sd 1:0:0:0: [sda] Assuming drive cache: write through
sda: sda1 sda2

查看下U盘设备,这个u盘有两个分区,一个是PE,所以sda1是第一个分区,sda2是第二个分区

# ls -l /dev/sda*
brw-rw---- 1 0 0 8, 0 Jan 4 06:57 /dev/sda
brw-rw---- 1 0 0 8, 1 Jan 4 06:57 /dev/sda1
brw-rw---- 1 0 0 8, 2 Jan 4 06:57 /dev/sda2

手动挂载

 mount /dev/sda1 /mnt

自动挂载

创建文件,加入配置文件vi /etc/mdev.conf

sda[1-9]+ 0:0 660 * if [ $ACTION = "add" ]; then mount /dev/$MDEV /mnt; else umount /mnt; fi
  • [1-9] 匹配数字1到9
  • + 表示重复前面1次及以上 也就是表示1~无穷大的数字
  • 0:0 uid,默认为0就好了
  • 660权限
  • *,创建设备节点之后 和 删除设备节点之前 执行命令
  • /dev/$MDEV,表示要创建/注销的那个设备节点

或者使用脚本mdev.sh,更好看

#!/bin/sh
if [ $ACTION = "add" ];
then
mount /dev/$MDEV /mnt;
else
umount /mnt;
fi

常用的命令

ifconfig eth0 192.168.95.200
mount -t nfs -o nolock,vers=2 192.168.95.222:/home/book/stu /mnt
使用nfs在uboot下下载内核
nfs 30000000 12.16.45.222:/uimage
bootm 30000000

env

输入env可以查看当前shell的环境变量

# env
USER=root
OLDPWD=/etc
HOME=/
TERM=vt102
PATH=/sbin:/usr/sbin:/bin:/usr/bin
SHELL=/bin/sh
PWD=/mnt # env
USER=root
OLDPWD=/mnt
HOME=/
TERM=vt102
PATH=/sbin:/usr/sbin:/bin:/usr/bin
SHELL=/bin/sh
PWD=/

附录 U盘插入的打印信息


# usb 1-1: new full speed USB device using s3c2410-ohci and address 3
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1
envp[4]=SUBSYSTEM=usb
envp[5]=SEQNUM=761
envp[6]=MAJOR=189
envp[7]=MINOR=2
envp[8]=DEVTYPE=usb_device
envp[9]=PHYSDEVBUS=usb
envp[10]=DEVICE=/proc/bus/usb/001/003
envp[11]=PRODUCT=951/1666/100
envp[12]=TYPE=0/0/0
envp[13]=BUSNUM=001
envp[14]=DEVNUM=003
argv[1]=usb
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/class/usb_endpoint/usbdev1.3_ep00
envp[4]=SUBSYSTEM=usb_endpoint
envp[5]=SEQNUM=762
envp[6]=MAJOR=253
envp[7]=MINOR=2
envp[8]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1
envp[9]=PHYSDEVBUS=usb
envp[10]=PHYSDEVDRIVER=usb
argv[1]=usb_endpoint
usb 1-1: configuration #1 chosen from 1 choice
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0
envp[4]=SUBSYSTEM=usb
envp[5]=SEQNUM=763
envp[6]=DEVTYPE=usb_interface
envp[7]=PHYSDEVBUS=usb
envp[8]=DEVICE=/proc/bus/usb/001/003
envp[9]=PRODUCT=951/1666/100
envp[10]=TYPE=0/0/0
envp[11]=INTERFACE=8/6/80
envp[12]=MODALIAS=usb:v0951p1666d0100dc00dsc00dp00ic08isc06ip50
argv[1]=usb
scsi1 : SCSI emulation for USB Mass Storage devices
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/class/scsi_host/host1
envp[4]=SUBSYSTEM=scsi_host
envp[5]=SEQNUM=764
envp[6]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host1
argv[1]=scsi_host
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/class/usb_endpoint/usbdev1.3_ep81
envp[4]=SUBSYSTEM=usb_endpoint
envp[5]=SEQNUM=765
envp[6]=MAJOR=253
envp[7]=MINOR=3
envp[8]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0
envp[9]=PHYSDEVBUS=usb
envp[10]=PHYSDEVDRIVER=usb-storage
argv[1]=usb_endpoint
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/class/usb_endpoint/usbdev1.3_ep02
envp[4]=SUBSYSTEM=usb_endpoint
envp[5]=SEQNUM=766
envp[6]=MAJOR=253
envp[7]=MINOR=4
envp[8]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0
envp[9]=PHYSDEVBUS=usb
envp[10]=PHYSDEVDRIVER=usb-storage
argv[1]=usb_endpoint
scsi 1:0:0:0: Direct-Access Kingston DataTraveler 3.0 PMAP PQ: 0 ANSI: 6
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host1/target1:0:0/1:0:0:0
envp[4]=SUBSYSTEM=scsi
envp[5]=SEQNUM=767
envp[6]=PHYSDEVBUS=scsi
envp[7]=MODALIAS=scsi:t-0x00
argv[1]=scsi
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/class/scsi_disk/1:0:0:0
envp[4]=SUBSYSTEM=scsi_disk
envp[5]=SEQNUM=768
envp[6]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host1/target1:0:0/1:0:0:0
envp[7]=PHYSDEVBUS=scsi
envp[8]=PHYSDEVDRIVER=sd
argv[1]=scsi_disk
sd 1:0:0:0: [sda] 60555264 512-byte hardware sectors (31004 MB)
sd 1:0:0:0: [sda] Write Protect is off
sd 1:0:0:0: [sda] Assuming drive cache: write through
sd 1:0:0:0: [sda] 60555264 512-byte hardware sectors (31004 MB)
sd 1:0:0:0: [sda] Write Protect is off
sd 1:0:0:0: [sda] Assuming drive cache: write through
sda: sda1 sda2
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/block/sda
envp[4]=SUBSYSTEM=block
envp[5]=SEQNUM=769
envp[6]=MINOR=0
envp[7]=MAJOR=8
envp[8]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host1/target1:0:0/1:0:0:0
envp[9]=PHYSDEVBUS=scsi
envp[10]=PHYSDEVDRIVER=sd
argv[1]=block
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/block/sda/sda1
envp[4]=SUBSYSTEM=block
envp[5]=SEQNUM=770
envp[6]=MINOR=1
envp[7]=MAJOR=8
envp[8]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host1/target1:0:0/1:0:0:0
envp[9]=PHYSDEVBUS=scsi
envp[10]=PHYSDEVDRIVER=sd
argv[1]=block
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/block/sda/sda2
envp[4]=SUBSYSTEM=block
envp[5]=SEQNUM=771
envp[6]=MINOR=2
envp[7]=MAJOR=8
envp[8]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host1/target1:0:0/1:0:0:0
envp[9]=PHYSDEVBUS=scsi
envp[10]=PHYSDEVDRIVER=sd
argv[1]=block
sd 1:0:0:0: [sda] Attached SCSI removable disk
userhelp=/sbin/mdev
envp[0]=HOME=/
envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin
envp[2]=ACTION=add
envp[3]=DEVPATH=/class/scsi_device/1:0:0:0
envp[4]=SUBSYSTEM=scsi_device
envp[5]=SEQNUM=772
envp[6]=PHYSDEVPATH=/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.0/host1/target1:0:0/1:0:0:0
envp[7]=PHYSDEVBUS=scsi
envp[8]=PHYSDEVDRIVER=sd
argv[1]=scsi_device

hotplug/mdev机制的更多相关文章

  1. linux中的热插拔和mdev机制

    mdev手册(自己翻译的留着看) mdev实现U盘或SD卡的自动挂载 mdev的使用以及mdev.conf的规则配置--busybox linux中的热插拔和mdev机制 关于实现udev/mdev自 ...

  2. hotplug\uevent机制(1)

    hotplug就是热拔插,在linux里面,这个功能是通过class_device_create这个函数来实现的,那么我们来分析下这个函数: class_device_create(cls, NULL ...

  3. udev和mdev hotplug事件

    关于udev和mdev之间的区别与联系我发现自己现在还没有把它完整的给区分开来和联系起来. 设备文件系统有devfs,mdev,udev mdev是udev的简化版本,是busybox中所带的程序,最 ...

  4. linux udev、mdev 介绍

    Udev介绍 Udev的下载网址:http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/ Udev分为三个子计划:namedev,libs ...

  5. 关于实现udev/mdev自动挂载与卸载

    在网上有很多关于讲mdev的自动挂载基本上都是一个版本,经过测试自动挂载确实可行,但是关于自动卸载mdev似乎不能很好的支持,经过修改已经可以做到与udev的效果相似.不能在挂载的目录中进行热插拔,否 ...

  6. Samsung_tiny4412(驱动笔记10)----mdev,bus,device,driver,platform

    /*********************************************************************************** * * mdev,bus,de ...

  7. 使用BusyBox制作linux根文件系统(CramFS+mdev)

    转:http://www.360doc.com/content/10/0428/11/496343_25245348.shtml 操作系统:Ubuntu9.04 内核版本:linux-2.6.24.7 ...

  8. Linux设备模型(热插拔、mdev 与 firmware)【转】

    转自:http://www.cnblogs.com/hnrainll/archive/2011/06/10/2077469.html 转自:http://blog.chinaunix.net/spac ...

  9. 二十三、uevnet机制和U盘自动挂载

    一.uevent机制 在分析之前,我们首先要知道uevent作用是什么.在此我们先来看一个uevent机制的框架图: 该图片来自:Linux设备模型(3)_Uevent 通过图片我们可以确定ueven ...

随机推荐

  1. SQLServer之修改PRIMARY KEY

    使用SSMS数据库管理工具修改PRIMARY KEY 1.连接数据库,选择数据表->右键点击->选择设计(或者展开键,选择要修改的键,右键点击,选择修改,后面步骤相同). 2.选择要修改的 ...

  2. 英语口语练习系列-C18-Wildest Dreams

    词汇复习 actor 演员 afternoon 下午 alive 活着的 apple 苹果 adjective 形容词 air 空气 animal 动物 April 四月 adult 成年人 airp ...

  3. .NET Core跨平台部署

    目录 .NET Core跨平台部署 1. Windows-IIS 1.1 安装.NET Core Windows Server Hosting 1.2 配置应用程序池 1.3 使用发布文件 2 Lin ...

  4. EXTJS的使用

    最近一段时间一直使用Extjs作为前端,通过HTTP与.net后端进行交互,今天总结一下EXTJS,方便以后复习. 1.概念: ExtJS可以用来开发RIA也即富客户端的AJAX应用,是一个用java ...

  5. Ambari与Kerberos 集成

    Kerberos 介绍 Kerberos 是一个网络认证的框架协议,其设计的初衷便是通过密钥系统为 Client 和 Server 应用程序之间提供强大的认证服务.在使用 Kerberos 认证的集群 ...

  6. canvas save()和canvas restore()状态的保存和恢复使用方法及实例

    canvas.save()用来保存先前状态的 canvas.restore()用来恢复之前保存的状态 注:两种方法必须搭配使用,否则没有效果 <!DOCTYPE html> <htm ...

  7. 26 python 初学(线程、同步锁、死锁和递归锁)

    参考博客: www.cnblogs.com/yuanchenqi/articles/5733873.html 并发:一段时间内做一些事情 并行:同时做多件事情 线程是操作系统能够进行运算调度的基本单位 ...

  8. android9.0系统适配遇到的问题

    一.apk在9.0以下的系统上安装运行,没有问题.但是在9.0系统上运行会弹出一个框 解决办法: private void closeAndroidPDialog() { try { Class aC ...

  9. docker pull报错failed to register layer: Error processing tar file(exit status 1): open permission denied

    近来在一个云主机上操作docker pull,报错如下: failed to register layer: Error processing ): open /etc/init.d/hwclock. ...

  10. 小程序蓝牙BLE——自动连接设备(手环)

    了解小程序蓝牙API: /** *蓝牙API: * 1.初始化蓝牙(判断蓝牙是否可用):openBluetoothAdapter * 2.获取蓝牙设备状态(蓝牙是否打开):getBluetoothAd ...