drivers\base\core.c

 

文件小结:

读完这个文件的代码,其实这个文件实现的最关键的代码就是device_add函数,这个函数之前的所有函数都是为这个函数服务的。而这个函数之后的函数则很简单,基本和这个函数互相映衬了。而device_add函数在后面分析平台设备的时候,平台设备的添加platform_device_add函数则主要调用了该函数

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

函数列表:

 

const char *dev_driver_string(struct device *dev);

返回驱动的name。

 

定义了几个属性文件:

uevent_attr

devt_attr

 

void device_initialize(struct device *dev);

初始化device,这里设置了dev->kobj->kset的关联

 

int device_add(struct device *dev)

这个函数很大,主要是将dev加入到他所属的总线,类,父设备等各个包含单元中。

或者说将设备添加进设备设备模型中。调用顺序一般是device_create -> device_register -> device_add()。一般device_register见得多点

这个函数可以说是core.c这个文件的主体,在这个函数之前的大部分static函数都是为他做准备的。

 

void device_del(struct device * dev)

add的反过程

 

int device_for_each_child(struct device * parent, void * data,

                   int (*fn)(struct device *, void *))

从parent链表中取出每一个设备,执行fn()函数

 

struct device * device_find_child(struct device *parent, void *data,

                              int (*match)(struct device *, void *))

从parent链表中取出每一个设备,执行match()函数,匹配成功则返回该设备

 

int __init devices_init(void)

设备的初始化,在这个地方,我们又重温了一次kobject.c文件中的kset注册

 

struct device *device_create(struct class *class, struct device *parent,

                          dev_t devt, const char *fmt, ...)

创建一个新的设备,其核心还是device_add函数

 

void device_destroy(struct class *class, dev_t devt)

从指定的class中找到指定版本号devt的设备,销毁

 

int device_rename(struct device *dev, char *new_name)

重命名device,其中调用了obj的重命名函数对dev->obj也进行重命名

 

 

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//返回驱动的name,按优先级依次寻找driver->name,bus->name,class->name,如果都没有设置,则返回NULL

const char      *dev_driver_string(struct device   *dev)

{

       return     dev->driver ? dev->driver->name :

                     (dev->bus ? dev->bus->name :

                     (dev->class ? dev->class->name : ""));

}

EXPORT_SYMBOL(dev_driver_string);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

#define   to_dev(obj)           container_of(obj, struct device, kobj)

#define   to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//调用attr->show()显示函数将显示内容打印进buf中。

static ssize_t    dev_attr_show(

struct kobject               *kobj,

struct attribute       *attr,

char                     *buf)

{

       struct device_attribute   *dev_attr = to_dev_attr(attr);        //获取属性结构体

       struct device * dev = to_dev(kobj);                                  //根据obj获取设备

       ssize_t ret = -EIO;

 

       if (dev_attr->show)              //有显示命令,则调用show()函数显示

              ret = dev_attr->show(dev, dev_attr, buf);

       return ret;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//调用attr->store()函数

static ssize_t    dev_attr_store(

struct kobject               *kobj,

struct attribute       *attr,

       const char             *buf,

size_t                   count)

{

       struct device_attribute   *dev_attr = to_dev_attr(attr);

       struct device                 *dev = to_dev(kobj);

       ssize_t ret = -EIO;

 

       if (dev_attr->store)

              ret = dev_attr->store(dev, dev_attr, buf, count);

       return ret;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//系统操作

static struct sysfs_ops    dev_sysfs_ops = {

       .show      = dev_attr_show,

       .store      = dev_attr_store,

};

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//调用release函数,按优先级顺序依次查找dev的release(),dev->type->release(),dev->class->dev_release()

static void      device_release(struct kobject        *kobj)

{

       struct device   *dev = to_dev(kobj);

 

       if (dev->release)     //设备的释放函数

              dev->release(dev);

       else if (dev->type && dev->type->release)  //类型的释放函数

              dev->type->release(dev);

       else if (dev->class && dev->class->dev_release)  //类的释放函数

              dev->class->dev_release(dev);

       else {

              //没有关联release函数

              WARN_ON(1);

       }

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

static struct kobj_type   device_ktype = {

       .release           = device_release,           //释放函数

       .sysfs_ops       = &dev_sysfs_ops,        //操作函数(show, store)

};

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//对uevent事件(热插拔)过滤

//从后面的一个调用可以看出,返回0则说明过滤成功,调用者将直接退出

static int        dev_uevent_filter(

struct kset      *kset,

struct kobject        *kobj)

{

       //定义在kobject.h中,返回kobj->kset的ktype或者kobj的ktype

       struct kobj_type     *ktype = get_ktype(kobj);

 

       //如果是刚才设置的默认的device_ktype,则执行

       if (ktype == &device_ktype) {

              struct device   *dev = to_dev(kobj);     //获取kobj所在的dev

              if (dev->uevent_suppress)     //支持uevent

                     return 0;

              if (dev->bus)                //有设置总线

                     return 1;

              if (dev->class)               //有设置类

                     return 1;

       }

       return 0;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//返回总线的名字或者类的名字。

static const char     *dev_uevent_name(struct kset *kset,    struct kobject *kobj)

{

       struct device *dev = to_dev(kobj);

 

       if (dev->bus)

              return     dev->bus->name;

       if (dev->class)

              return     dev->class->name;

       return     NULL;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//依次执行kobj所在设备dev的uevent()函数,顺序分别为:bus总线,class类,设备的type

//从代码来看,这个函数似乎只是将设备ID给打印了出来

static int               dev_uevent(

struct kset      *kset,

struct kobject        *kobj,

struct kobj_uevent_env *env)

{

       struct device   *dev = to_dev(kobj);

       int retval = 0;

 

       //打印主次版本号,type名,驱动名

       if (MAJOR(dev->devt)) {

              add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));

              add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));

       }

       if (dev->type && dev->type->name)

              add_uevent_var(env, "DEVTYPE=%s", dev->type->name);

       if (dev->driver)

              add_uevent_var(env, "DRIVER=%s", dev->driver->name);

 

       //如果总线bus->uevent()函数有指定,则执行

       if (dev->bus && dev->bus->uevent) {

              retval = dev->bus->uevent(dev, env);

              if (retval)

                     pr_debug ("%s: bus uevent() returned %d\n",

                              __FUNCTION__, retval);

       }

 

       //执行类的class->dev_uevent()函数

       if (dev->class && dev->class->dev_uevent) {

              retval = dev->class->dev_uevent(dev, env);

              if (retval)

                     pr_debug("%s: class uevent() returned %d\n",

                             __FUNCTION__, retval);

       }

 

       //执行类型的type->uevent()函数

       if (dev->type && dev->type->uevent) {

              retval = dev->type->uevent(dev, env);

              if (retval)

                     pr_debug("%s: dev_type uevent() returned %d\n",

                             __FUNCTION__, retval);

       }

 

       return     retval;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//这个结构体我们在分析kobject.c中已经见过了。

static struct kset_uevent_ops        device_uevent_ops = {

       .filter =          dev_uevent_filter,          //热插拨过滤函数

       .name =          dev_uevent_name,         //返回总线或类名

       .uevent =        dev_uevent,                  //执行热插拔函数

};

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//找到dev->kobj的最顶层obj,调用kset->uevent()函数

//作用似乎是调用uevent打印主次版本号,各种名字

//返回的是字符串长度

static ssize_t   show_uevent(

struct device   *dev,

struct device_attribute   *attr,

       char              *buf)

{

       struct kobject        *top_kobj;

       struct kset      *kset;

       struct kobj_uevent_env *env = NULL;

       int          i;

       size_t     count = 0;

       int          retval;

 

       //找到最顶层的kobj,如果没有关联uevnet,则退出

       top_kobj = &dev->kobj;                                          //获取设备的obj

       while (!top_kobj->kset && top_kobj->parent)    //反查到最顶层的obj

              top_kobj = top_kobj->parent;

       if (!top_kobj->kset)

              goto out;

 

       //获取最顶层obj的宿主

       kset = top_kobj->kset;

       if (!kset->uevent_ops || !kset->uevent_ops->uevent)

              goto out;

 

       //执行filter()过滤函数

       if (kset->uevent_ops && kset->uevent_ops->filter)

              if (!kset->uevent_ops->filter(kset, &dev->kobj))

                     goto out;               //返回0则退出

 

       //申请一块内存,调用uevent()函数

       env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);

       if (!env)

              return -ENOMEM;

 

       //执行uevent函数

       retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);

       if (retval)

              goto out;

 

       /* copy keys to file */

       for (i = 0;   i < env->envp_idx;   i++)

              count += sprintf(&buf[count], "%s\n", env->envp[i]);       // sprintf返回的是字符串长度

 

//这里会不会overflow?

out:

       kfree(env);

       return count;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//调用kobject_uevent执行buf中的动作,如果buf中指定的动作不合法,则按KOBJ_ADD来执行,kobject_uevent的实现函数在kobject的uevent文件中

static ssize_t   store_uevent(

struct device   *dev,

struct device_attribute   *attr,

       const char      *buf,                    //动作名

size_t            count)                   //动作名长度

{

       enum kobject_action     action;     //返回的动作类型

 

       //查看buf中的字符串是否和aciton中的一致,一致就用该action执行

       if (kobject_action_type(buf, count, &action) == 0) {

              kobject_uevent(&dev->kobj, action);    //buf内容合法,执行动作

              goto out;

       }

       kobject_uevent(&dev->kobj, KOBJ_ADD); //buf内容不合法,按KOBJ_ADD执行动作

out:

       return     count;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

static      struct device_attribute          uevent_attr =

       __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//根据属性attrs创建文件

//这个函数在下面的device_add_attrs函数中被调用

static int        device_add_attributes(

struct device                 *dev,

       struct device_attribute   *attrs)

{

       int error = 0;

       int i;

 

       if (attrs) {

              //根据属性创建文件

              for (i = 0; attr_name(attrs[i]); i++) {

                     error = device_create_file(dev, &attrs[i]);

                     if (error)

                            break;

              }

              if (error)        //出错,删除刚创建的文件

                     while (--i >= 0)

                            device_remove_file(dev, &attrs[i]);

       }

       return error;

}

 

//删除属性文件

//这个函数在下面的device_add_attrs函数中被调用

static void      device_remove_attributes(

struct device                 *dev,

       struct device_attribute   *attrs)

{

       int i;

 

       if (attrs)

              for (i = 0; attr_name(attrs[i]); i++)

                     device_remove_file(dev, &attrs[i]);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//创建文件夹

//这个函数在下面的device_add_attrs函数中被调用

static int        device_add_groups(

struct device                 *dev,

       struct attribute_group    **groups)

{

       int error = 0;

       int i;

 

       if (groups) {

              for (i = 0; groups[i]; i++) {

                     error = sysfs_create_group(&dev->kobj, groups[i]);

                     if (error) {

                            while (--i >= 0)

                                   sysfs_remove_group(&dev->kobj, groups[i]);

                            break;

                     }

              }

       }

       return error;

}

 

//删除文件夹

//这个函数在下面的device_add_attrs函数中被调用

static void      device_remove_groups(struct device *dev,

                             struct attribute_group **groups)

{

       int i;

 

       if (groups)

              for (i = 0; groups[i]; i++)

                     sysfs_remove_group(&dev->kobj, groups[i]);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//为设备创建属性文件

static int        device_add_attrs(struct device *dev)

{

       struct class            *class = dev->class;

       struct device_type *type = dev->type;

       int error;

 

       if (class) {

              //类存在,则根据设备属性创建文件

              error = device_add_attributes(dev, class->dev_attrs);

       }

 

       if (type) {

              //type存在,则根据组创建文件夹

              error = device_add_groups(dev, type->groups);

       }

 

       error = device_add_groups(dev, dev->groups);

       return 0;

}

 

//删除相关的文件

static void      device_remove_attrs(struct device *dev)

{

       struct class *class = dev->class;

       struct device_type *type = dev->type;

 

       device_remove_groups(dev, dev->groups);

 

       if (type)

              device_remove_groups(dev, type->groups);

 

       if (class)

              device_remove_attributes(dev, class->dev_attrs);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//又是一个属性文件

static struct device_attribute devt_attr =

       __ATTR(dev, S_IRUGO, show_dev, NULL);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

decl_subsys(devices,     &device_ktype,     &device_uevent_ops);

 

//kset的结构体可以参照kobject.h来看

#define   decl_subsys(_name,       _type,     _uevent_ops) \

struct kset      _name##_subsys = {                   \             //devices_subsys

       .kobj = { .k_name = __stringify(_name) },        \

       .ktype = _type, \

       .uevent_ops =_uevent_ops, \

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//根据属性attr创建设备的属性文件(节点)

int   device_create_file(

struct device   *dev,

struct device_attribute   *attr)

{

       int error = 0;

       if (get_device(dev)) {           //dev的引用记数加1

              error = sysfs_create_file(&dev->kobj, &attr->attr);

              put_device(dev);           //释放dev的引用计数

       }

       return error;

}

 

//删除属性文件

void       device_remove_file(struct device * dev, struct device_attribute * attr)

{

       if (get_device(dev)) {

              sysfs_remove_file(&dev->kobj, &attr->attr);

              put_device(dev);

       }

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//创建二进制的属性文件

int   device_create_bin_file(struct device *dev,   struct bin_attribute *attr)

{

       int error = -EINVAL;

       if (dev)

              error = sysfs_create_bin_file(&dev->kobj, attr);

       return error;

}

EXPORT_SYMBOL_GPL(device_create_bin_file);

 

//删除二进制的属性文件

void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)

{

       if (dev)

              sysfs_remove_bin_file(&dev->kobj, attr);

}

EXPORT_SYMBOL_GPL(device_remove_bin_file);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//这个函数先不管,和任务调度有关的

int   device_schedule_callback_owner(

struct device   *dev,

       void (*func)(struct device *),

struct module        *owner)

{

       return sysfs_schedule_callback(&dev->kobj,

                     (void (*)(void *)) func, dev, owner);

}

EXPORT_SYMBOL_GPL(device_schedule_callback_owner);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//根据node获取device结构体,然后引用/释放一个记数

//这里的计数实际是引用dev->kobj的计数

static void      klist_children_get(struct klist_node *n)

{

       struct device *dev = container_of(n, struct device, knode_parent);

       get_device(dev);

}

 

static void      klist_children_put(struct klist_node *n)

{

       struct device *dev = container_of(n, struct device, knode_parent);

       put_device(dev);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//对device进行初始化,最需要注意的一个操作就是将kobj->kset关联上了devices_subsys

void       device_initialize(struct device *dev)

{

       //dev->kobj.kset = & devices_subsys,设置kset

       kobj_set_kset_s(dev, devices_subsys);

       kobject_init(&dev->kobj);            //初始化obj

      

       //初始化设备的子设备链表为空

       klist_init(&dev->klist_children,

              klist_children_get,

              klist_children_put);

 

       //初始化设备的DMA,节点链表为空

       INIT_LIST_HEAD(&dev->dma_pools);

       INIT_LIST_HEAD(&dev->node);

 

       //初始化设备的互斥锁

       init_MUTEX(&dev->sem);

       spin_lock_init(&dev->devres_lock);                   //自旋锁

       INIT_LIST_HEAD(&dev->devres_head);

       device_init_wakeup(dev, 0);                              //初始化本设备无唤醒功能

       set_dev_node(dev, -1);                                      //非NUMA下是空函数

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//在devices_subsys下创建挂载一个虚拟子obj,取名为virtual

//这个函数的输入参数无意义

static struct kobject       *virtual_device_parent(struct device *dev)

{

       static struct kobject       *virtual_dir = NULL;

 

       //由于初始给的值就是NULL,所以这个if恒满足

       if (!virtual_dir)

              virtual_dir = kobject_add_dir(&devices_subsys.kobj,        "virtual");

 

       return     virtual_dir;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//获取父设备的obj

static struct kobject       *get_device_parent(

struct device   *dev,

       struct device   *parent)

{

       //设备有注册类

       if (dev->class) {

              struct kobject *kobj = NULL;

              struct kobject *parent_kobj;

              struct kobject *k;

 

              if (parent == NULL)             //没有父设备,创建一个虚拟的obj

                     parent_kobj = virtual_device_parent(dev);   //输入参数dev无意义,虚拟设备在devices_subsys下,返回的是新建立的那个虚拟kobj

              else if (parent->class)            //父设备有类

                     return     &parent->kobj;      //返回父设备的obj

              else

                     parent_kobj = &parent->kobj;      //父设备无关联的类

 

              //从dev->class的所有目录中找寻parent相同的obj

              spin_lock(&dev->class->class_dirs.list_lock);

              list_for_each_entry(k, &dev->class->class_dirs.list, entry)

                     if (k->parent == parent_kobj) {

                            kobj = kobject_get(k);          //引用计数加1

                            break;

                     }

              spin_unlock(&dev->class->class_dirs.list_lock);

 

              //obj找到

              if (kobj)

                     return kobj;

 

              //obj没有找到,新建一个obj

              return     kobject_kset_add_dir(&dev->class->class_dirs,

                                       parent_kobj, dev->class->name);

       }

 

       //dev->class没有注册,返回父设备的obj

       if (parent)

              return     &parent->kobj;

 

       return     NULL;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//设置dev的父设备

static int        setup_parent(struct device *dev,   struct device *parent)

{

       struct kobject        *kobj;

       kobj = get_device_parent(dev, parent);        //获取dev的父设备obj

       if (IS_ERR(kobj))

              return     PTR_ERR(kobj);

 

       if (kobj)                                                   //设置dev的父设备

              dev->kobj.parent = kobj;

       return 0;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//创建一些文件链接

static int        device_add_class_symlinks(struct device *dev)

{

}

 

//删除文件链接

static void device_remove_class_symlinks(struct device *dev)

{
}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//本函数所做工作是一大串的关联函数,将设备dev加入到总线,类等链表中

int   device_add(struct device       *dev)

{

       struct device   *parent = NULL;

       struct class_interface *class_intf;

       int error = -EINVAL;

 

       //将dev->kobj的引用加1

       dev = get_device(dev);

       if (!dev || !strlen(dev->bus_id))     //dev为空,或则bus_id为空

              goto Error;

 

       //获取dev的父设备

       parent = get_device(dev->parent);        //父设备的引用加1,由于parent初始为NULL,所以这里没有引用,返回NULL

       error = setup_parent(dev, parent);        //dev->kobj.parent=parent.kobj,由于parent为NULL,所以这里关联的也就是NULL了

       if (error)

              goto Error;

 

       //将dev->bus_id的名字(总线名)设置给dev->kobj

       kobject_set_name(&dev->kobj, "%s", dev->bus_id);

       error = kobject_add(&dev->kobj);              //将kobj添加进kset链表

       if (error)

              goto Error;

 

       //如果这个函数不为空,则执行这个函数

       //实际这个函数是空的,平台函数

       if (platform_notify)

              platform_notify(dev);

 

       //设备有指定总线,调用总线的bus_notifier()函数,通知系统加了一个设备

       if (dev->bus)

              blocking_notifier_call_chain(&dev->bus->bus_notifier,

                                        BUS_NOTIFY_ADD_DEVICE, dev);

 

       //根据uevent属性创建文件

       error = device_create_file(dev, &uevent_attr);

       if (error)

              goto attrError;

 

       //如果devt的主版本号存在,创建属性文件

       if (MAJOR(dev->devt)) {

              error = device_create_file(dev, &devt_attr);

              if (error)

                     goto ueventattrError;

       }

 

       //添加类链接

       error = device_add_class_symlinks(dev);

       if (error)

              goto SymlinkError;

 

       //添加属性文件

       error = device_add_attrs(dev);

       if (error)

              goto AttrsError;

 

       //这个函数和文件系统有关,先忽略

       error = dpm_sysfs_add(dev);

       if (error)

              goto PMError;

 

       //添加设备到电源管理链表中

       device_pm_add(dev);

 

       //添加设备属性到dev->bus中

       error = bus_add_device(dev);

       if (error)

              goto BusError;

 

       //执行dev->kobj->kset的uevent函数

       kobject_uevent(&dev->kobj, KOBJ_ADD);

       //attach设备(设备关联到总线上)

       bus_attach_device(dev);

       //如果父设备存在,将本设备挂在父设备的链表(parent->klist_children)上

       if (parent)

              klist_add_tail(&dev->knode_parent, &parent->klist_children);

 

       //如果类存在,将设备挂在类链表上

       //获取dev->class的所有接口,调用接口的add_dev函数,将dev关联上去

       if (dev->class) {

              down(&dev->class->sem);

              list_add_tail(&dev->node, &dev->class->devices);

 

              list_for_each_entry(class_intf, &dev->class->interfaces, node)

                     if (class_intf->add_dev)

                            class_intf->add_dev(dev, class_intf);

              up(&dev->class->sem);

       }

 Done:

       put_device(dev);

       return     error;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//设备的注册

int   device_register(struct device *dev)

{

       device_initialize(dev);                  //将dev的设置全部初始化

       return     device_add(dev);           //添加设备

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//引用/释放dev,其实核心操作只是对dev->kobj进行引用和释放计数

struct device   *get_device(struct device * dev)

{

       return     dev ? to_dev(kobject_get(&dev->kobj)) : NULL;

}

 

void       put_device(struct device * dev)

{

       if (dev)

              kobject_put(&dev->kobj);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//删除只是add的反过程

void       device_del(struct device * dev)

{

       struct device                 *parent = dev->parent;

       struct class_interface     *class_intf;

 

       if (parent)              //从父设备链表中删除自己

              klist_del(&dev->knode_parent);

       if (MAJOR(dev->devt))        //如果设备版本号存在,则删除设备的属性文件

              device_remove_file(dev, &devt_attr);

       if (dev->class) {                   //如果设备的类存在

              sysfs_remove_link(&dev->kobj, "subsystem");           //删除subsystem下的链接

              if (dev->kobj.parent != &dev->class->subsys.kobj)

                     sysfs_remove_link(&dev->class->subsys.kobj,

                                     dev->bus_id);

              if (parent) {                  //在device文件夹下删除目标

                     sysfs_remove_link(&dev->kobj, "device");

              }

 

              //遍历类的接口,调用remove()函数删除设备

              down(&dev->class->sem);

              list_for_each_entry(class_intf, &dev->class->interfaces, node)

                     if (class_intf->remove_dev)

                            class_intf->remove_dev(dev, class_intf);

             

              list_del_init(&dev->node);

              up(&dev->class->sem);

 

              //kset为class的目录

              if (dev->kobj.parent->kset == &dev->class->class_dirs) {

                     struct device *d;

                     int other = 0;

 

                     //遍历class的devices链表,取出每一个节点,查找是否有dev的兄弟节点存在,如果兄弟节点不存在,则删除dev的父节点

                     down(&dev->class->sem);

                     list_for_each_entry(d, &dev->class->devices, node) {

                            if (d == dev)

                                   continue;

                            if (d->kobj.parent == dev->kobj.parent) {

                                   other = 1;

                                   break;

                            }

                     }

                     if (!other)

                            kobject_del(dev->kobj.parent);

 

                     kobject_put(dev->kobj.parent);     //父节点的引用计数释放

                     up(&dev->class->sem);

              }

       }

 

       //删除文件,删除属性,从总线上删除设备

       device_remove_file(dev, &uevent_attr);

       device_remove_attrs(dev);

       bus_remove_device(dev);

 

       //释放全部节点

       devres_release_all(dev);

 

       //调用总线上的函数

       if (platform_notify_remove)

              platform_notify_remove(dev);

 

       if (dev->bus)

              blocking_notifier_call_chain(&dev->bus->bus_notifier,

                                        BUS_NOTIFY_DEL_DEVICE, dev);

       device_pm_remove(dev);

       kobject_uevent(&dev->kobj, KOBJ_REMOVE);

       kobject_del(&dev->kobj);

       if (parent)

              put_device(parent);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//设备的反注册函数

void       device_unregister(struct device     *dev)

{

       device_del(dev);            //直接调用设备的删除函数

       put_device(dev);           //释放设备的计数

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//从链表中获取下一个设备

static struct device        *next_device(struct klist_iter * i)

{

       struct klist_node    *n = klist_next(i);

       return     n ? container_of(n, struct device, knode_parent) : NULL;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//从parent链表中取出每一个设备,执行fn()函数

int   device_for_each_child(

struct device   *parent,

void              *data,                           //fn的参数

       int (*fn)(struct device *, void *))

{

       struct klist_iter i;                  //klist_iter是klist的集合

       struct device * child;

       int error = 0;

 

       klist_iter_init(&parent->klist_children, &i);

       while ((child = next_device(&i)) && !error)

              error = fn(child, data);

       klist_iter_exit(&i);

       return error;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//从parent链表中取出每一个设备,执行match()函数,匹配成功则返回该设备

struct device   *device_find_child(struct device *parent,    void *data,

                              int (*match)(struct device *, void *))

{

       struct klist_iter i;

       struct device *child;

 

       if (!parent)            //父设备为空,返回NULL

              return NULL;

 

       klist_iter_init(&parent->klist_children, &i);

       while ((child = next_device(&i)))

              if (match(child, data) &&        get_device(child))

                     break;

       klist_iter_exit(&i);

       return child;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//注册子系统,这个函数的实现在kobject.c中

int   __init     devices_init(void)

{

       return     subsystem_register(&devices_subsys);

}

 

struct kset      devices_subsys={

       .kobj={   .k_name = devices, },

       .ktype = &device_ktype,

       .uevent_ops = &device_uevent_ops,

}

 

int   subsystem_register(struct kset *s)

{

       return     kset_register(s);

}

int   kset_register(struct kset * k)

{

       //k->kobj->refcount=1

//k->kobj->entry=NULL

//k->kobj->kset= k->kobj->kset    (NULL)

       //k->list=NULL

       kset_init(k);

       //这一步只是根据k->kobj的属性创建文件

       err = kset_add(k);

       //执行kset-> uevent_ops->uevent,参数传的是ADD,也就是执行dev_uevent函数

       kobject_uevent(&k->kobj, KOBJ_ADD);

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//创建设备,这个函数中会依次调用reg和add设备

//这个函数其实很简单,所以最后关键的核心还是在于device_add函数

struct device   *device_create(

struct class     *class,           //类

struct device   *parent,          //父指针

       dev_t             devt,             //设备的版本号

const char      *fmt, ...)        //设置为dev->bus_id

{

       va_list           args;

       struct device   *dev = NULL;

       int                 retval = -ENODEV;

 

       //类为空,类错误,返回

       if (class == NULL || IS_ERR(class))

              goto error;

 

       //申请一块内存,并设置成员

       dev = kzalloc(sizeof(*dev), GFP_KERNEL);

       if (!dev) {

              retval = -ENOMEM;

              goto error;

       }

 

       dev->devt = devt;

       dev->class = class;

       dev->parent = parent;

       dev->release = device_create_release;          //默认的release函数,kfree(dev);

 

       va_start(args, fmt);

       vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);

       va_end(args);

 

       //调用注册函数注册设备

       retval = device_register(dev);

       if (retval)

              goto error;

 

       return dev;

 

error:

       kfree(dev);

       return ERR_PTR(retval);

}

EXPORT_SYMBOL_GPL(device_create);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void       device_destroy(struct class *class,        dev_t devt)

{

       struct device *dev = NULL;

       struct device *dev_tmp;

 

       //从class的设备链表中取出devt(版本号)相等的设备

       down(&class->sem);

       list_for_each_entry(dev_tmp, &class->devices, node) {

              if (dev_tmp->devt == devt) {

                     dev = dev_tmp;

                     break;

              }

       }

       up(&class->sem);

 

       //设备存在,卸载设备

       if (dev)

              device_unregister(dev);

}

EXPORT_SYMBOL_GPL(device_destroy);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//设备重命名

int   device_rename(struct device *dev,       char *new_name)

{

       char       *old_class_name = NULL;

       char       *new_class_name = NULL;

       char       *old_device_name = NULL;

       int          error;

 

       dev = get_device(dev);          //dev引用计数加1

       if (!dev)

              return -EINVAL;

 

       //申请一片内存保存旧名

       old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);

       if (!old_device_name) {

              error = -ENOMEM;

              goto out;

       }

       strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);

       strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);

 

       //将dev所带的kobj也重命名

       error = kobject_rename(&dev->kobj, new_name);

       if (error) {      //出错,恢复旧名

              strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);

              goto out;

       }

 

       //设备类存在

       if (dev->class) {            //重建链接

              sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);

              error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,

                                     dev->bus_id);

              }

       }

 

out:

       put_device(dev);                  //释放dev引用计数

 

       kfree(new_class_name);

       kfree(old_class_name);

       kfree(old_device_name);       //释放内存

 

       return error;

}

EXPORT_SYMBOL_GPL(device_rename);

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//移除/重新关联联接

static int        device_move_class_links(

struct device   *dev,

       struct device   *old_parent,

       struct device   *new_parent)

{

       int   error = 0;

 

       if (old_parent)

              sysfs_remove_link(&dev->kobj, "device");

       if (new_parent)

              error = sysfs_create_link(&dev->kobj, &new_parent->kobj,

                                     "device");

       return error;

}

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

//设备移动

int   device_move(

struct device   *dev,

struct device   *new_parent)

{

       int error;

       struct device   *old_parent;

       struct kobject        *new_parent_kobj;

 

       dev = get_device(dev);

       if (!dev)

              return -EINVAL;

 

       //获取设备,父设备的obj

       new_parent = get_device(new_parent);

       new_parent_kobj = get_device_parent (dev, new_parent);

       if (IS_ERR(new_parent_kobj)) {

              error = PTR_ERR(new_parent_kobj);

              put_device(new_parent);

              goto out;

       }

      

       //移动kobj

       error = kobject_move(&dev->kobj,     new_parent_kobj);

       if (error) {

              put_device(new_parent);

              goto out;

       }

 

       //修正父设备指向

       old_parent = dev->parent;

       dev->parent = new_parent;

       if (old_parent)              //断开设备在旧父设备中的链接

              klist_remove(&dev->knode_parent);

       if (new_parent)      //将设备插入到新父设备的链表中

              klist_add_tail(&dev->knode_parent, &new_parent->klist_children);

 

       //下面这部分是修正class中的链接,其实原理都一样的

       if (!dev->class)

              goto out_put;

       error = device_move_class_links(dev, old_parent,    new_parent);

       if (error) {

              device_move_class_links(dev, new_parent, old_parent);

              if (!kobject_move(&dev->kobj, &old_parent->kobj)) {

                     if (new_parent)

                            klist_remove(&dev->knode_parent);

                     if (old_parent)

                            klist_add_tail(&dev->knode_parent,

                                          &old_parent->klist_children);

              }

              put_device(new_parent);

              goto out;

       }

out_put:

       put_device(old_parent);

out:

       put_device(dev);

       return error;

}

EXPORT_SYMBOL_GPL(device_move);

 

你可能感兴趣的:(drivers\base\core.c)