内核检测到USB设备的插入之后,需要通知用户空间进程来处理。目前有2种通知方式:

 

1.内核调用call_usermodehelper_setup()/call_usermodehelper_exec()从而运行用户空间进程来处理。可以通过/sys/kernel/uevent_helper或者/proc/sys/kernel/hotplug来配置,指定用户空间可执行程序的路径。。

2.调用netlink_broadcast_filtered(),通过netlink的方式,将事件发送到用户空间进程。

 

对于openwrt来说,他采用的是第二种方式。那么是哪个进程在监听这类事件呢?是procd这个进程。关于procd进程的启动,可以参照以下文章:

https://blog.csdn.net/angan4532/article/details/102303089

 

那么procd进程启动时,就会创建一个NETLINK_KOBJECT_UEVENT类型的netlink的socket连接到内核。当内核检测到事件后,就通过这个netlink socket 将uevent消息发送到procd.

 

那么procd收到uevent消息之后,对不同的消息会根据用户设定的规则进行不同的处理。这个规则是由/etc/hotplug.json指定的。

 

下面看一下这个配置文件的内容:

[router] /etc # cat hotplug.json
[
        [ "case", "ACTION", {
                "add": [
                        [ "if",
                                [ "and",
                                        [ "has", "MAJOR" ],
                                        [ "has", "MINOR" ],
                                ],
                                [
                                        [ "if",
                                                [ "or",
                                                        [ "eq", "DEVNAME",
                                                                [ "null", "full", "ptmx", "zero" ],
                                                        ],
                                                        [ "regex", "DEVNAME",
                                                                [ "^gpio", "^hvc" ],
                                                        ],
                                                ],
                                                [
                                                        [ "makedev", "/dev/%DEVNAME%", "0666" ],
                                                        [ "return" ],
                                                ]
                                        ],
                                        [ "if",
                                                [ "or",
                                                        [ "eq", "DEVNAME", "mapper/control" ],
                                                        [ "regex", "DEVPATH", "^ppp" ],
                                                ],
                                                [
                                                        [ "makedev", "/dev/%DEVNAME%", "0600" ],
                                                        [ "return" ],
                                                ],
                                        ],
                                        [ "if",
                                                [ "has", "DEVNAME" ],
                                                [ "makedev", "/dev/%DEVNAME%", "0644" ],
                                        ],
                                ],
                        ],
                        [ "if",
                                [ "has", "FIRMWARE" ],
                                [
                                        [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
                                        [ "load-firmware", "/lib/firmware" ],
                                        [ "return" ]
                                ]
                        ],
                ],
                "remove" : [
                        [ "if",
                                [ "and",
                                        [ "has", "DEVNAME" ],
                                        [ "has", "MAJOR" ],
                                        [ "has", "MINOR" ],
                                ],
                                [ "rm", "/dev/%DEVNAME%" ]
                        ]
                ]
        } ],
        [ "if",
                [ "eq", "SUBSYSTEM", "platform" ],
                [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ]
        ],
        [ "if",
                [ "and",
                        [ "has", "BUTTON" ],
                        [ "eq", "SUBSYSTEM", "button" ],
                ],
                [ "exec", "/etc/rc.button/%BUTTON%" ]
        ],
        [ "if",
                [ "eq", "SUBSYSTEM",
                        [ "net", "input", "usb", "usbmisc", "ieee1394", "block", "atm", "zaptel", "tty", "button", "dump" ]
                ],
                [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ]
        ],
        [ "if",
                [ "and",
                        [ "eq", "SUBSYSTEM", "usb-serial" ],
                        [ "regex", "DEVNAME",
                                [ "^ttyUSB", "^ttyACM" ]
                        ],
                ],
                [ "exec", "/sbin/hotplug-call", "tty" ]
        ],
]
[router] /etc #

  

可以看到,这个规则文件里面,对于不同类型的uevent都指定了不同的处理方式。比方说对于usb存储设备,他首先会用mkdev来创建device,然后会调用/sbin/hotplug-call,并传入一个参数SUBSYSTEM。

 

/sbin/hotplug-call是一个脚本程序:

[router] /etc # cat /sbin/hotplug-call
#!/bin/sh
# Copyright (C) 2006-2010 OpenWrt.org

export HOTPLUG_TYPE="$1"

. /lib/functions.sh

PATH=/usr/sbin:/usr/bin:/sbin:/bin
LOGNAME=root
USER=root
export PATH LOGNAME USER
export DEVICENAME="${DEVPATH##*/}"

[ \! -z "$1" -a -d /etc/hotplug.d/$1 ] && {
        for script in $(ls /etc/hotplug.d/$1/* 2>&-); do (
                [ -f $script ] && . $script
        ); done
}
[router] /etc #

 

这个脚本会调用/etc/hotplug.d/$SUBSYSTEM下面的所有脚本。这个脚本用户可以自己指定。那么对于USB存储设备来说,我们可能需要将这个设备mount到文件系统。