kobject表明sysfs中的目錄。shell
ktype表明kobject的類型,主要包含release函數和attr的讀寫函數。好比,全部的bus都有同一個bus_type;全部的class都有同一個class_type。函數
kset包含了subsystem概念,kset自己也是一個kobject,因此裏面包含了一個kobject對象。另外,kset中包含kset_uevent_ops,裏面主要定義了三個函數orm
int (*filter)(struct kset *kset, struct kobject *kobj);對象
const char *(*name)(struct kset *kset, struct kobject *kobj);事件
int (*uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env);it
這三個函數都與uevent相關。filter用於判斷uevent是否要發出去。name用於獲得subsystem的名字。uevent用於填充env變量。io
uevent是sysfs向用戶空間發出的消息。好比,device_add函數中,會調用kobject_uevent(&dev->kobj, KOBJ_ADD); 這裏kobj是發消息的kobj,KOBJ_ADD是發出的事件。uevent的事件在kobject_action中定義:event
enum kobject_action {form
KOBJ_ADD,class
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_MAX
};
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
return kobject_uevent_env(kobj, action, NULL);
}
kobject_uevent_env:
由kobject的parent向上查找,直到找到一個kobject包含kset。
若是kset中有filter函數,調用filter函數,看看是否須要過濾uevent消息。
若是kset中有name函數,調用name函數獲得subsystem的名字;不然,subsystem的名字是kset中kobject的名字。
分配一個kobj_uevent_env,並開始填充env環境變量:
增長環境變量ACTION=<action name>
增長環境變量DEVPATH=<kobj’s path>
增長環境變量SUBSYSTEM=<subsystem name>
增長環境變量kobject_uevent_env中參數envp_ext指定的環境變量。
調用kset的uevent函數,這個函數會繼續填充環境變量。
增長環境變量SEQNUM=<seq>,這裏seq是靜態變量,每次累加。
調用netlink發送uevent消息。
調用uevent_helper,最終轉換成對用戶空間sbin/mdev的調用。
uevent的用戶空間程序有兩個,一個是udev,一個是mdev。
udev經過netlink監聽uevent消息,它能完成兩個功能:
1.自動加載模塊
2.根據uevent消息在dev目錄下添加、刪除設備節點。
另外一個是mdev,mdev在busybox的代碼包中能找到,它經過上節提到的uevent_helper函數被調用。
下面簡要介紹udev的模塊自動加載過程:
etc目錄下有一個uevent規則文件/etc/udev/rules.d/50-udev.rules
udev程序收到uevent消息後,在這個規則文件裏匹配,若是匹配成功,則執行這個匹配定義的shell命令。例如,規則文件裏有這麼一行:
ACTION=="add", SUBSYSTEM=="?*", ENV{MODALIAS}=="?*", RUN+="/sbin/modprobe $env{MODALIAS}"
因此,當收到uevent的add事件後,shell能自動加載在MODALIAS中定義的模塊。
mdev的模塊自動加載過程與之相似,它的配置文件在/etc/mdev.conf中。例如:
$MODALIAS=.* 0:0 660 @modprobe "$MODALIAS"
這條規則指的是:當收到的環境變量中含有MODALIAS,那麼加載MODALIAS表明的模塊。
mdev的詳細說明在busybox的docs/mdev.txt中。
在sys目錄下有一個子目錄devices,表明一個kset。
建立設備時,調用的device_initialize函數中,默認會把kset設置成devices_kset,即devices子目錄表明的kset。
devices_kset中設置了uevent操做集device_uevent_ops。
static struct kset_uevent_ops device_uevent_ops = {
.filter = dev_uevent_filter,
.name = dev_uevent_name,
.uevent = dev_uevent,
};
dev_uevent_filter中,主要是規定了要想發送uevent,dev必須有class或者bus。
dev_uevent_name中,返回dev的class或者bus的名字。
dev_uevent函數:
若是dev有設備號,添加環境變量MAJOR與MINOR。
若是dev->type有值,設置DEVTYPE=<dev->type->name>。
若是dev->driver,設置DRIVER=<dev->driver->name>。
若是有bus,調用bus的uevent函數。
若是有class,調用class的uevent函數。
若是有dev->type,調用dev->type->uevent函數。
通常在bus的uevent函數中,都會添加MODALIAS環境變量,設置成dev的名字。這樣,uevent傳到用戶空間後,就能夠經過對MODALIAS的匹配自動加載模塊。這樣的bus例子有platform和I2C等等。