我們首先來完整地看下driver_register函數定義:
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p); //判斷bus->p是否爲空,見第1部分分析
if((drv->bus->probe && drv->probe)|| //判斷驅動跟驅動的總線是否有衝突的函數註冊,給出警告信息,見第2部分分析
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating -please use "
"bus_type methods\n", drv->name);
other =driver_find(drv->name, drv->bus); //在註冊在bus上的driver尋找是否有跟要註冊的driver相同,有則表明驅動已被註冊過,見第3部分分析
if (other){
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret =bus_add_driver(drv); //經過上面的驗證後,將驅動添加註冊到bus上,見第4部分分析
if(ret)
return ret;
ret =driver_add_groups(drv, drv->groups);//如果grop不爲空的話,將在驅動文件夾下創建以group名字的子文件夾,然後在子文件夾下添加group的屬性文件
if(ret)
bus_remove_driver(drv);
return ret;
}
這個函數開始先判斷bus->p是否爲空,如果不爲空然後判斷驅動跟驅動的總線是否有衝突的函數註冊,如果有衝突就給出警告信息;然後在註冊在bus上的driver尋找是否有跟要註冊的driver相同,有則表明驅動已被註冊過,返回錯誤。經過上面的驗證後,將驅動添加註冊到bus上,如果沒問題,則再將驅動添加到同一屬性的組中,在sysfs下表現爲同一個目錄。有了大概的流程概念後,我們開始一步一步的詳細分析,分爲四個部分:
1 BUG_ON(!drv->bus->p);
BUG_ON定義如下:
#defineBUG_ON(condition) do { if (unlikely(condition)) BUG(); }while(0)
其中的BUG(): #defineBUG() do { \
printk("BUG: failure at %s:%d/%s()!\n", __FILE__,__LINE__, __func__); \
panic("BUG!"); \
} while(0)
由上面定義可以看出,如果drv->bus->p爲空,則打印失敗信息以及panic信息。其實這個主要是判斷bus是否存在,這個結論還需要論證!
2
if((drv->bus->probe && drv->probe)||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating -please use "
"bus_type methods\n", drv->name);
主要是判斷驅動跟驅動的總線是否有衝突的函數註冊,給出警告信息
3 other = driver_find(drv->name, drv->bus)
driver_find()函數定義如下:
struct device_driver *driver_find(const char *name, struct bus_type*bus)
{
struct kobject *k = kset_find_obj(bus->p->drivers_kset,name);//在bus的驅動集合裏面發現同名字的驅動
struct driver_private *priv;
if (k){
priv =to_driver(k);//如果找到,通過kobject轉換成driver_private,返回相應的驅動
return priv->driver;
}
return NULL;
}
這個函數的功能就是查找bus上已經註冊的驅動,和要註冊的驅動比較,如果找到,則返回找到的驅動。bus->p->drivers_kset是bus上已經註冊的驅動的kobject的集合,會傳給kset_find_obj()作爲參數。讀到這裏,應該去複習一下kobject,kset, sysfs等概念了。這裏爲了分析的連貫性就不再插入相關概念。
kset_find_obj()的定義如下:
struct kobject *kset_find_obj(struct kset *kset, const char*name)
{
struct kobject *k;
struct kobject *ret = NULL;
spin_lock(&kset->list_lock);
list_for_each_entry(k, &kset->list, entry){ //遍歷kset->list中的每個kobject
if (kobject_name(k) &&!strcmp(kobject_name(k), name)) {
ret = kobject_get(k); //若有同名字的,增加kobject的kref,並返回該kobject
break;
}
}
spin_unlock(&kset->list_lock);
return ret;
}
它會查找在kset->list上的每一個kobject與改驅動的名字是否有同名字的,如果找到則返回改kobject。
4 bus_add_driver(drv);
它的定義如下:
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error =0;
bus =bus_get(drv->bus); //找到該drv所屬的bus,增加該bus->p->subsys->kobject->kref的引用計數
if(!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n",bus->name, drv->name);
priv =kzalloc(sizeof(*priv), GFP_KERNEL); //分配driver_private結構
if (!priv){
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL,NULL); //初始化priv->klist_devices
priv->driver = drv; //將該drv賦值給priv->driver
drv->p =priv; //而drv的drv->p又等於priv
priv->kobj.kset = bus->p->drivers_kset;//指向bus的drvier容器
error =kobject_init_and_add(&priv->kobj, &driver_ktype,NULL,
"%s", drv->name);//驅動的kobject初始化和添加dir到sysfs中,後面會有分析,見4-1部分
if(error)
goto out_unregister;
if(drv->bus->p->drivers_autoprobe) { //這個變量默認是爲1的
error =driver_attach(drv); //匹配函數,後面會分析,見4-2部分
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);//將priv->knode_bus添加到bus->p->klist_drivers,見4-3部分
module_add_driver(drv->owner,drv); //添加drv的module,見4-4部分
error =driver_create_file(drv, &driver_attr_uevent);//在sysfs的目錄下創建文件uevent屬性文件,見4-5分析
if (error){
printk(KERN_ERR "%s: uevent attr (%s)failed\n",
__func__, drv->name);
}
error =driver_add_attrs(bus, drv); //給driver添加bus上的所有屬性
if (error){
printk(KERN_ERR "%s: driver_add_attrs(%s)failed\n",
__func__, drv->name);
}
error =add_bind_files(drv); //添加綁定文件,driver_attr_bind 和driver_attr_unbind見4-5分析
if (error){
printk(KERN_ERR "%s: add_bind_files(%s)failed\n",
__func__, drv->name);
}
kobject_uevent(&priv->kobj,KOBJ_ADD); //產生一個KOBJ_ADD uevent
return0;
out_unregister:
kfree(drv->p);
drv->p =NULL;
kobject_put(&priv->kobj);
out_put_bus:
bus_put(bus);
return error;
}
這個函數是driver_register中核心函數,真正的功能實現都在這個函數裏面。這個函數首先找到該drv所屬的bus,然後爲driver_private結構分配空間,然後初始化priv,把driver,bus,priv聯繫在一塊,然後添加驅動的kobject到kobject的層次中,也就是添加驅動文件夾到sysfs,然後根據drivers_autoprobe決定是否去bus上尋找與driver匹配的device。然後將driver添加到bus上的驅動列表中。然後添加驅動的模塊,再然後就是生成sysfs下面的一些屬性文件。4-1 kobject_init_and_add()
int kobject_init_and_add(struct kobject *kobj, struct kobj_type*ktype,
struct kobject *parent, const char *fmt,...)
{
va_listargs;
intretval;
kobject_init(kobj, ktype); //初始化kobject
va_start(args, fmt); //動態可變參數的使用
retval =kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
4-1-1 kobject_init()
void kobject_init(struct kobject *kobj, struct kobj_type*ktype)
{
...
kobject_init_internal(kobj);
kobj->ktype = ktype;
...
}
kobject_init將調用kobject_init_internal()
4-1-1-1 kobject_init_internal()
static void kobject_init_internal(struct kobject *kobj)
{
if(!kobj)
return;
kref_init(&kobj->kref); //原子地將kobj->kref設爲1
INIT_LIST_HEAD(&kobj->entry);//初始化kobj->entry列表
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1;
}
可以看出kobject_init()的功能就是初始化kobject結構中的成員狀態。
4-1-2 這裏我們不介紹動態變量的使用方法,開始分析kobject_add_varg()
static int kobject_add_varg(struct kobject *kobj, struct kobject*parent,
const char *fmt, va_list vargs)
{
int retval;
retval =kobject_set_name_vargs(kobj, fmt, vargs); //主要是將vargs按照fmt格式給kobject起個名字,從調用關係知道vargs是drv->name,也就是驅動的名字
if (retval){
printk(KERN_ERR "kobject: can not set nameproperly!\n");
return retval;
}
kobj->parent = parent; //由上面的函數調用關係可以知道這個將被賦值爲NULL
return kobject_add_internal(kobj); //見4-1-2-1
}
4-1-2-1 kobject_add_internal()
static int kobject_add_internal(struct kobject *kobj)
{
...
parent =kobject_get(kobj->parent); //得到父節點,從上面知道parent是NULL
if(kobj->kset) { //kset不爲空
if (!parent) //parent爲空
parent =kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s',set: '%s'\n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "",
kobj->kset ?kobject_name(&kobj->kset->kobj) : "");
error =create_dir(kobj); //建立該驅動的文件夾,見4-1-2-1-1分析
if (error){
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
if (error == -EEXIST)
printk(KERN_ERR "%s failed for %s with"
"-EEXIST, don't try to register things with "
"the same name in the same directory.\n",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s(%d)\n",
__func__, kobject_name(kobj), error);
dump_stack();
}else
kobj->state_in_sysfs = 1;
return error;
}
這個函數主要設置drvier的kobject和bus之間的層次關係,然後在sysfs中建立該驅動的文件夾
4-1-2-1-1 create_dir()
static int create_dir(struct kobject *kobj)
{
int error =0;
if(kobject_name(kobj)) {
error = sysfs_create_dir(kobj); //創建該kobj(driver的)文件夾,見4-1-2-1-1-1
if (!error) {
error = populate_dir(kobj);
if (error)
sysfs_remove_dir(kobj);
}
}
return error;
}
4-1-2-1-1-1 sysfs_create_dir
int sysfs_create_dir(struct kobject * kobj)
{
struct sysfs_dirent *parent_sd, *sd; //sysfs層次結構的基石
int error =0;
BUG_ON(!kobj);
if(kobj->parent) //到這步驅動的kobj->parent是bus->p->drivers_kset
parent_sd = kobj->parent->sd;//bus->p->drivers_kset的目錄
else
parent_sd = &sysfs_root;//否則添加到sys的根目錄下,即/sys/
error =create_dir(kobj, parent_sd, kobject_name(kobj), &sd);//在bus->p->drivers_kset的文件夾下創建該驅動的文件夾
if(!error)
kobj->sd = sd;
return error;
}
說到這裏,可能一直感覺很空洞,很抽象,拿i2c總線舉個例子吧,i2c總線註冊好後將會有如下文件夾結構/sys/bus/i2c/,在/sys/bus/i2c/文件夾下會有如下文件夾uevent、devices、drivers、drivers_probe、drivers_autoprobe,當你註冊驅動的時候,將會在/sys/bus/i2c/drivers/下注冊一個該驅動的文件夾,比如ov7675,那麼它將會註冊成/sys/bus/i2c/drivers/ov7675/,其實這些文件夾都對應一個kobject,通過kset容器組成一個很清晰的層次結構。經過漫長的過程我們分析完了kobject_init_and_add(),我們下面進入4-2部分driver_attach進行分析。這也是一個非常重要的函數,好吧,開始我們的又一個漫長之旅吧!
4-2 driver_attach()
定義如下:
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv,__driver_attach);
}
該函數將調用bus_for_each_dev()。
4-2-1 bus_for_each_dev()
int bus_for_each_dev(struct bus_type *bus, struct device*start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error =0;
if(!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices,&i,
(start ? &start->p->knode_bus : NULL)); //將bus中的已註冊的device列表放到迭代器中,方便索引
while ((dev= next_device(&i)) && !error) //將驅動逐個地與列表中每一個的device匹配,可能一個驅動匹配好幾個設備
error = fn(dev, data); //這個fn就是上面傳下來的__driver_attach
klist_iter_exit(&i);
return error;
}
4-2-1-1,__driver_attach
static int __driver_attach(struct device *dev, void*data)
{
struct device_driver *drv = data;
if(!driver_match_device(drv, dev)) //跟名字的意思一樣,driver跟device嘗試匹配
return 0;
if(dev->parent)
down(&dev->parent->sem);
down(&dev->sem);
if(!dev->driver)
driver_probe_device(drv, dev);
up(&dev->sem);
if(dev->parent)
up(&dev->parent->sem);
return 0;
}
4-2-1-1-1,driver_match_device()
static inline int driver_match_device(struct device_driver*drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) :1;
}
這裏看bus的總線的match函數是否已經註冊,如果沒註冊則直接返回1,如果註冊,則調用註冊的匹配函數。同樣,以i2c總線爲例吧,
struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
.match = i2c_device_match,
...
};
static int i2c_device_match(struct device *dev, structdevice_driver *drv)
{
structi2c_client *client = to_i2c_client(dev);
structi2c_driver *driver = to_i2c_driver(drv);
if(driver->id_table)
return i2c_match_id(driver->id_table, client)!=NULL;//只匹配id的名字和client的名字,跟驅動的名字沒有關係,注意這裏的client是設備轉換過來,而不是設備的本身
return 0;
}
轉而調用i2c_match_id();
static const struct i2c_device_id *i2c_match_id(const structi2c_device_id *id,
const struct i2c_client *client)
{
while(id->name[0]) {
if (strcmp(client->name, id->name) ==0) //匹配設備client名字和id_table中的名字
return id;
id++;
}
return NULL;
}
所以i2c總線根據設備client名字和id_table中的名字進行匹配的。如果匹配了,則返回id值,在i2c_device_match中則返回真。也就是bus的match函數將會返回真。那將會進入driver_probe_device()。
4-2-1-1-2,driver_probe_device()
int driver_probe_device(struct device_driver *drv, struct device*dev)
{
int ret =0;
if(!device_is_registered(dev)) //首先判斷這個device是否已經註冊
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %s withdriver %s\n",
drv->bus->name, __func__, dev_name(dev),drv->name);
ret =really_probe(dev, drv); //轉而調用really_probe()
return ret;
}
4-2-1-1-2-1,really_probe()
static atomic_t probe_count = ATOMIC_INIT(0); //記錄probe數目
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); //probe隊列
static int really_probe(struct device *dev, struct device_driver*drv)
{
int ret =0;
atomic_inc(&probe_count); //原子增加計數
pr_debug("bus: '%s': %s: probing driver %s withdevice %s\n",
drv->bus->name, __func__, drv->name,dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;//把驅動賦值給dev->drvier
if(driver_sysfs_add(dev)) { //主要是添加driver和dev之間的連接文件,見4-2-1-1-2-1-1分析
printk(KERN_ERR "%s: driver_sysfs_add(%s)failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
if(dev->bus->probe) { //如果bus的probe註冊將執行,否則執行driver的probe,這也是函數開始時檢測的原因!
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if(drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
driver_bound(dev); //driver綁定dev,見4-2-1-1-2-1-2分析
ret =1;
pr_debug("bus: '%s': %s: bound device %s todriver %s\n",
drv->bus->name, __func__, dev_name(dev),drv->name);
gotodone;
probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
if (ret !=-ENODEV && ret != -ENXIO) {
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
}
ret =0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
4-2-1-1-2-1-1,driver_sysfs_add
static int driver_sysfs_add(struct device *dev)
{
intret;
ret =sysfs_create_link(&dev->driver->p->kobj,&dev->kobj,
kobject_name(&dev->kobj));//在driver目錄下添加以dev->kobj名字的連接文件,連接到device
if (ret ==0) {
ret = sysfs_create_link(&dev->kobj,&dev->driver->p->kobj,
"driver"); //同樣在device目錄下添加‘driver’爲名字的連接文件連接到drvier
if (ret)
sysfs_remove_link(&dev->driver->p->kobj,
kobject_name(&dev->kobj));
}
return ret;
}
4-2-1-1-2-1-2,driver_bound()
static void driver_bound(struct device *dev)
{
if(klist_node_attached(&dev->p->knode_driver)){ //查看是否已經綁定
printk(KERN_WARNING "%s: device %s alreadybound\n",
__func__,kobject_name(&dev->kobj));
return;
}
pr_debug("driver: '%s': %s: bound to device'%s'\n", dev_name(dev),
__func__, dev->driver->name);
if(dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev); //調用註冊bus通知鏈上的所有函數
klist_add_tail(&dev->p->knode_driver,&dev->driver->p->klist_devices); //將設備的驅動node添加到diver的klist_devices中.定義同4-3部分
}
4-3,klist_add_tail()
定義如下:
void klist_add_tail(struct klist_node *n, struct klist*k)
{
klist_node_init(k, n); //初始化一個klist_node,並將klist聯繫起來
add_tail(k,n); //將n添加到k的末尾
}
4-4,module_add_driver()
void module_add_driver(struct module *mod, struct device_driver*drv)
{
char*driver_name;
intno_warn;
structmodule_kobject *mk = NULL;
if(!drv)
return;
if(mod) //一般情況下爲THIS_MODULE
mk = &mod->mkobj;
else if(drv->mod_name) { //如果沒模塊,則檢查驅動的模塊名
struct kobject *mkobj;
mkobj = kset_find_obj(module_kset,drv->mod_name); //根據驅動模塊的名字去module_kset集合中找
if (mkobj) {
mk = container_of(mkobj, struct module_kobject,kobj); //用container_of方法通過kobj轉換成module_kobject
drv->p->mkobj = mk; //賦值給驅動的mkobj
kobject_put(mkobj);
}
}
if(!mk) //mk如果爲null則返回
return;
no_warn =sysfs_create_link(&drv->p->kobj, &mk->kobj,"module"); //在驅動文件夾下創建名爲‘module’的鏈接文件,鏈接到module文件夾
driver_name= make_driver_name(drv); //生成driver_name,給module用,見4-4-1分析
if(driver_name) {
module_create_drivers_dir(mk); //在具體的module文件夾下創建driver目錄
no_warn = sysfs_create_link(mk->drivers_dir,&drv->p->kobj, //在上面創建的driver目錄下,生成一個名爲driver_name指定的鏈接文件,鏈接到驅動的文件夾
make_driver_name();
kfree(driver_name);
}
}
4-4-1,make_driver_name()
static char *make_driver_name(struct device_driver *drv)
{
char*driver_name;
driver_name= kmalloc(strlen(drv->name) + strlen(drv->bus->name) +2,
GFP_KERNEL); //申請這麼大內存
if(!driver_name)
return NULL;
sprintf(driver_name, "%s:%s",drv->bus->name, drv->name); //將bus的名字和驅動的名字組成一塊,中間加一個冒號
return driver_name;
}
這個函數的功能就是生成一個名字,這個有bus和驅動的名字組成
4-5,
在drivers/base/bus.c中driver_attr_uevent,driver_attr_unbind,driver_attr_bind這幾個屬性的定義如下:
static DRIVER_ATTR(uevent, S_IWUSR, NULL,driver_uevent_store);
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
在include/linux/device.h中DRIVER_ATTR宏的定義如下:
#define DRIVER_ATTR(_name, _mode, _show,_store) /
struct driver_attribute driver_attr_##_name= /
__ATTR(_name, _mode, _show, _store)
由定義可知,這三個屬性文件的_show函數都爲null,也就是都不具體讀的功能。
4-5-1,driver_attr_uevent,_store爲driver_uevent_store:
static ssize_t driver_uevent_store(struct device_driver*drv,
const char *buf, size_t count)
{
enum kobject_action action;
if (kobject_action_type(buf, count, &action) ==0) //kobject_action_type就是將buf轉換成action
kobject_uevent(&drv->p->kobj, action); //產生一個action的uevent事件,一般通過netlink機制與用戶空間通信,見4-5-1-1分析
return count;
}
也就是說對drvier目錄下的uevent屬性文件進行寫操作時將會產生一個用戶指定的事件。
4-5-1-1,kobject_uevent()
int kobject_uevent(struct kobject *kobj, enum kobject_actionaction)
{
returnkobject_uevent_env(kobj, action, NULL);
}
轉而看kobject_uevent_env():
int kobject_uevent_env(struct kobject *kobj, enum kobject_actionaction,
char *envp_ext[])
{
structkobj_uevent_env *env;
const char*action_string = kobject_actions[action];//通過數組下標找到對應的字符串
const char*devpath = NULL;
const char*subsystem;
structkobject *top_kobj;
struct kset*kset;
structkset_uevent_ops *uevent_ops;
u64seq;
int i =0;
int retval =0;
pr_debug("kobject: '%s' (%p): %s\n",
kobject_name(kobj), kobj, __func__);
top_kobj =kobj;
while(!top_kobj->kset && top_kobj->parent)
top_kobj = top_kobj->parent;//通過不斷往前找父kobj,從而得到top kobj
if(!top_kobj->kset) { //top kobj不能爲null
pr_debug("kobject: '%s' (%p): %s: attempted tosend uevent "
"without kset!\n", kobject_name(kobj),kobj,
__func__);
return -EINVAL;
}
kset =top_kobj->kset; //找到以後賦值
uevent_ops =kset->uevent_ops;
if(kobj->uevent_suppress) {
pr_debug("kobject: '%s' (%p): %s: uevent_suppress"
"caused the event to drop!\n",
kobject_name(kobj), kobj, __func__);
return 0;
}
if(uevent_ops && uevent_ops->filter)//判斷是否要進行的event
if (!uevent_ops->filter(kset, kobj)){
pr_debug("kobject: '%s' (%p): %s: filter function"
"caused the event to drop!\n",
kobject_name(kobj), kobj, __func__);
return 0;
}
if(uevent_ops && uevent_ops->name) //得到subsystem
subsystem = uevent_ops->name(kset,kobj);
else
subsystem =kobject_name(&kset->kobj);
if(!subsystem) {
pr_debug("kobject: '%s' (%p): %s: unset subsystemcaused the "
"event to drop!\n", kobject_name(kobj),kobj,
__func__);
return 0;
}
env =kzalloc(sizeof(struct kobj_uevent_env),GFP_KERNEL); //申請環境變量buffer
if(!env)
return -ENOMEM;
devpath =kobject_get_path(kobj, GFP_KERNEL); //得到該kobj的完整路徑
if(!devpath) {
retval = -ENOENT;
goto exit;
}
retval =add_uevent_var(env, "ACTION=%s", action_string);//將action的字符串添加到buffer中
if(retval)
goto exit;
retval =add_uevent_var(env, "DEVPATH=%s", devpath); //同上
if(retval)
goto exit;
retval =add_uevent_var(env, "SUBSYSTEM=%s", subsystem); //同上
if(retval)
goto exit;
if(envp_ext) { //如果不爲空,則也添加到buffer中
for (i = 0; envp_ext[i]; i++) {
retval = add_uevent_var(env, "%s",envp_ext[i]);
if (retval)
goto exit;
}
}
if(uevent_ops && uevent_ops->uevent) { //該集合的特定要加的東西到buffer中
retval = uevent_ops->uevent(kset, kobj,env);
if (retval) {
pr_debug("kobject: '%s' (%p): %s: uevent()returned "
"%d\n", kobject_name(kobj), kobj,
__func__, retval);
goto exit;
}
}
if (action== KOBJ_ADD) //標記一下
kobj->state_add_uevent_sent = 1;
else if(action == KOBJ_REMOVE)
kobj->state_remove_uevent_sent = 1;
spin_lock(&sequence_lock);
seq =++uevent_seqnum;
spin_unlock(&sequence_lock);
retval =add_uevent_var(env, "SEQNUM=%llu", (unsigned longlong)seq); //添加新的序列號到buffer中
if(retval)
goto exit;
#if defined(CONFIG_NET) //一般情況都定義的,通過netlink機制實現hotplug的
if(uevent_sock) {
struct sk_buff *skb;
size_t len;
len = strlen(action_string) + strlen(devpath) +2;
skb = alloc_skb(len + env->buflen,GFP_KERNEL); //申請skb buffer
if (skb) {
char *scratch;
scratch = skb_put(skb, len);//將scratch指向skb的tail,且後面有len大小的長度,相當與skb的位置指針,對它的賦值,實質是對skbbuffer的賦值
sprintf(scratch, "%s@%s", action_string,devpath); //將action和路徑添加到scratch
for (i = 0; i < env->envp_idx; i++){
len = strlen(env->envp[i]) + 1;
scratch = skb_put(skb, len);
strcpy(scratch,env->envp[i]);//將envp[]添加到scratch
}
NETLINK_CB(skb).dst_group = 1; //目標組地址
retval = netlink_broadcast(uevent_sock, skb, 0,1, //發送廣播消息
GFP_KERNEL);
if (retval == -ENOBUFS)
retval = 0;
} else
retval = -ENOMEM;
}
#endif
if(uevent_helper[0]) {//從定義看該數組值爲"/sbin/hotplug",現在一般udev系統已經沒有這個執行文件了,所以下面一般也不會執行,所以這裏不做分析
char *argv [3];
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
retval = add_uevent_var(env, "HOME=/");
if (retval)
goto exit;
retval = add_uevent_var(env,
"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
if (retval)
goto exit;
retval = call_usermodehelper(argv[0],argv,
env->envp, UMH_WAIT_EXEC);
}
exit:
kfree(devpath);
kfree(env);
return retval;
}
4-5-2,driver_attr_bind屬性對應的寫函數如下:
static ssize_t driver_bind(struct device_driver *drv,
const char *buf, size_t count)
{
struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
dev = bus_find_device_by_name(bus, NULL, buf);//在bus上尋找buf指定的device
if (dev && dev->driver == NULL) {
if (dev->parent)
down(&dev->parent->sem);
down(&dev->sem);
err = driver_probe_device(drv, dev);//在4-2-1-1-2中我們已經分析了driver_probe_device(),它的作用就是將driver和dev綁定起來,生成一些互相連接文件
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
if (err > 0) {
err = count;
} else if (err == 0) {
err = -ENODEV;
}
}
put_device(dev);
bus_put(bus);
return err;
}
從該函數可以看出,對bind寫入一個device的名字,將會綁定設備和驅動。
4-5-3,driver_attr_unbind,對應的寫函數如下:
static ssize_t driver_unbind(struct device_driver *drv,
const char *buf, size_t count)
{
struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
dev = bus_find_device_by_name(bus, NULL, buf); //同樣在bus上尋找buf指定的device
if (dev && dev->driver == drv) {
if (dev->parent)
down(&dev->parent->sem);
device_release_driver(dev); //斷開設備和驅動
if (dev->parent)
up(&dev->parent->sem);
err = count;
}
put_device(dev);
bus_put(bus);
return err;
}
從該函數可以看出,對unbind寫入一個device的名字,將會斷開設備和驅動。
至此,我們已經詳細地分析了driver_register(),下面我們將開始分析device_register().