內核檢測到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到文件系統。
