天天看點

drivers\base\sys.c

小結:

從sysdev_shutdown函數的實作,我們可以大概的分析一下驅動的層次模式如下:

1、最頂層的是system_subsys,所有的cls都挂載在他的連結清單中

2、每一個cls有一個驅動連結清單,這個驅動連結清單又可以按sysdev進行一個分組,但是分組隻是為了管理友善,驅動還是挂載在cls下的。

3、分組雖然隻是管理,但是驅動的一些函數執行,比如shutdown,resume等,是需要比對對應的組的,是以在suspend失敗的時候,進行恢複操作還要重新周遊組。

關于system_subsys和device_subsys(core.c中操作的對象)的關系,在最後一個函數:system_bus_init中點了出來:

system_subsys.kobj.parent        =    &devices_subsys.kobj;

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

函數清單:

decl_subsys(system, &ktype_sysdev_class, NULL)

聲明了一個子系統system_subsys作為類的父節點

在core.c中,我們已經聲明了一個device_subsys子系統作為device的父節點

int   sysdev_class_register(struct sysdev_class * cls)

類的注冊,将類cls挂載到system_subsys父節點下,cls->kobj->kset關聯為了system_subsys

後面跟着的是unregister函數,其實作就是将cls->kset脫出

int   sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)

将驅動drv注冊到類cls中,實際就是挂載連結清單drv->entry到cls->drivers下,并執行drv->add函數

int   sysdev_register(struct sys_device * sysdev)

注冊系統裝置,實際就是設定kobj的名字,然後注冊kobj,最後執行cls中所有驅動的add函數

void       sysdev_shutdown(void)

int          sysdev_suspend(pm_message_t     state)

int          sysdev_resume(void)

裝置的掉電函數,挂起函數,恢複函數,這三個函數的結構層次是類似的,從這些函數裡我們也可以分析出驅動模型的層次。

int   __init     system_bus_init(void)

總線的初始化,這個函數雖然隻有兩行代碼,卻很核心的說明了system_subsys和device_subsys的關系:system_subsys是device_subsys的子裝置

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

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

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

extern     struct kset      devices_subsys;             //這個結構體的定義在core.c的宏中

//根據成員擷取結構體

#define   to_sysdev(k)         container_of(k, struct sys_device, kobj)

#define   to_sysdev_attr(a)   container_of(a, struct sysdev_attribute, attr)

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

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

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

struct      sys_device {

       u32                       id;

       struct sysdev_class  * cls;

       struct kobject         kobj;

};

//調用attr的顯示函數

static      ssize_t    sysdev_show(

struct kobject               *kobj,

struct attribute       *attr,

char                     *buffer)

{

       struct sys_device    *sysdev = to_sysdev(kobj);           //根據obj擷取系統裝置

       struct sysdev_attribute   *sysdev_attr = to_sysdev_attr(attr);

       if (sysdev_attr->show)

              return     sysdev_attr->show(sysdev, buffer);

       return -EIO;

}

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

//調用attr的store函數

static ssize_t    sysdev_store(

struct kobject               *kobj,

struct attribute       *attr,

       const char             *buffer,

size_t                   count)

{

       struct sys_device * sysdev = to_sysdev(kobj);

       struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);

       if (sysdev_attr->store)

              return     sysdev_attr->store(sysdev, buffer, count);

       return -EIO;

}

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

static struct sysfs_ops    sysfs_ops = {

       .show      = sysdev_show,

       .store      = sysdev_store,

};

//這個type是給sysdev注冊時用的

static struct kobj_type   ktype_sysdev = {

       .sysfs_ops       = &sysfs_ops,

};

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

//建立/删除屬性檔案

int   sysdev_create_file(struct sys_device * s,      struct sysdev_attribute * a)

{

       return     sysfs_create_file(&s->kobj, &a->attr);

}

void       sysdev_remove_file(struct sys_device * s,   struct sysdev_attribute * a)

{

       sysfs_remove_file(&s->kobj, &a->attr);

}

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

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

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

struct sysdev_class {

       struct list_head       drivers;

       int   (*shutdown)(struct sys_device *);

       int   (*suspend)(struct sys_device *, pm_message_t state);

       int   (*resume)(struct sys_device *);

       struct kset              kset;

};

//根據成員擷取類和類屬性

#define   to_sysdev_class(k)        container_of(k, struct sysdev_class, kset.kobj)

#define   to_sysdev_class_attr(a) container_of(a, struct sysdev_class_attribute, attr)

//調用class_attr的show和store函數

static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,

                             char *buffer)

static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,

                              const char *buffer, size_t count)

//設定預設的結構體

static struct sysfs_ops    sysfs_class_ops = {

       .show      = sysdev_class_show,

       .store      = sysdev_class_store,

};

static struct kobj_type   ktype_sysdev_class = {

       .sysfs_ops       = &sysfs_class_ops,

};

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

//建立class的屬性檔案

int sysdev_class_create_file(struct sysdev_class *c,

                          struct sysdev_class_attribute *a)

{

       return sysfs_create_file(&c->kset.kobj, &a->attr);

}

void sysdev_class_remove_file(struct sysdev_class *c,

                           struct sysdev_class_attribute *a)

{

       sysfs_remove_file(&c->kset.kobj, &a->attr);

}

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

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

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

//定義system_subsys結構體(系統子系統)

//之前在core.c中定義的是device_subsys結構體(裝置子系統)

//從下面那個注冊函數可見,system_subsys是類的父節點

static      decl_subsys(system, &ktype_sysdev_class, NULL);

struct kset      system_subsys = {                             \

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

       .ktype = &ktype_sysdev_class,                   \

       .uevent_ops =NULL,                                 \

}

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

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

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

//注冊系統裝置類,父裝置為system_subsys

//其實所謂的注冊/解除安裝操作,就是将kobj關聯進連結清單中

int   sysdev_class_register(struct sysdev_class * cls)

{

       INIT_LIST_HEAD(&cls->drivers);      //驅動連結清單挂空

       cls->kset.kobj.parent     = &system_subsys.kobj;        //設定父節點

       cls->kset.kobj.kset        = &system_subsys;               //設定宿主

       return     kset_register(&cls->kset);      //注冊kset,将kset->kobj關聯到subsys連結清單中

}

void sysdev_class_unregister(struct sysdev_class * cls)

{

       kset_unregister(&cls->kset);

}

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

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

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

static DEFINE_MUTEX(sysdev_drivers_lock);          //定義一個互斥鎖

//驅動的注冊

//實際就是挂載drv->entry到cls->drivers連結清單中,并執行drv->add函數

int   sysdev_driver_register(

       struct sysdev_class        *cls,              //類

       struct sysdev_driver      *drv)             //驅動

{

       int err = 0;

       mutex_lock(&sysdev_drivers_lock);     //鎖

       //類不為空,引用一個計數說明要注冊一個驅動進去

       if (cls && kset_get(&cls->kset)) {

              //将驅動入口drv->entry關聯到cls的驅動連結清單中

              list_add_tail(&drv->entry,    &cls->drivers);

              //驅動的add函數存在,則依次執行這個函數将驅動add進cls中的每一個成員中。

              if (drv->add) {

                     struct sys_device *dev;

                     list_for_each_entry(dev,       &cls->kset.list,      kobj.entry)

                            drv->add(dev);

              }

       } else {   //類為空,出錯

              err = -EINVAL;

              printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);

              WARN_ON(1);

       }

       mutex_unlock(&sysdev_drivers_lock);        //解

       return err;

}

//驅動的解除安裝函數

void       sysdev_driver_unregister(

       struct sysdev_class        * cls,

       struct sysdev_driver      * drv)

{

       mutex_lock(&sysdev_drivers_lock);

       list_del_init(&drv->entry);                  //驅動連結清單挂空

       //如果類存在

       if (cls) {

              //執行驅動的remove函數

              if (drv->remove) {

                     struct sys_device *dev;

                     list_for_each_entry(dev, &cls->kset.list, kobj.entry)

                            drv->remove(dev);

              }

              //釋放類的一個引用

              kset_put(&cls->kset);

       }

       mutex_unlock(&sysdev_drivers_lock);

}

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

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

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

struct      sys_device {

       u32                              id;

       struct sysdev_class         * cls;

       struct kobject                kobj;

};

//注冊一個系統裝置,這個函數調用的地方很少

//操作:設定kobj的名字,注冊kobj,執行驅動中的add函數

int   sysdev_register(struct sys_device * sysdev)

{

       int error;

       struct sysdev_class * cls = sysdev->cls;

       //沒有關聯類

       if (!cls)

              return -EINVAL;

       sysdev->kobj.kset = &cls->kset;           //關聯KSET

       //關聯ktype操作

       sysdev->kobj.ktype = &ktype_sysdev;

       //設定kobj的名字

       error = kobject_set_name(&sysdev->kobj, "%s%d",

                      kobject_name(&cls->kset.kobj), sysdev->id);

       if (error)

              return error;

       //注冊kobj

       error = kobject_register(&sysdev->kobj);

       if (!error) {

              struct sysdev_driver * drv;

              mutex_lock(&sysdev_drivers_lock);

              //執行驅動的add函數

              list_for_each_entry(drv, &cls->drivers, entry) {

                     if (drv->add)

                            drv->add(sysdev);

              }

              mutex_unlock(&sysdev_drivers_lock);

       }

       return error;

}

我們先看一個調用:

int __init s3c2440_init(void)

{

       //無關代碼

       return sysdev_register(&s3c2440_sysdev);

}

static struct sys_device s3c2440_sysdev = {

       .cls         = &s3c2440_sysclass,

};

struct sysdev_class        s3c2440_sysclass = {

       set_kset_name("s3c2440-core"),

       .suspend  =    s3c244x_suspend,

       .resume   =    s3c244x_resume

};

#define   set_kset_name(str)         .kset = { .kobj = { .k_name = str } }

最後将這個調用套上剛才的函數實作,就可以加深了解了。

//反注冊,實際就是依次調用sysdev->cls->drivers的remove函數,然後反注冊kobj

void       sysdev_unregister(struct sys_device * sysdev)

{

       struct sysdev_driver * drv;

       mutex_lock(&sysdev_drivers_lock);

       list_for_each_entry(drv, &sysdev->cls->drivers, entry) {

              if (drv->remove)

                     drv->remove(sysdev);

       }

       mutex_unlock(&sysdev_drivers_lock);

       kobject_unregister(&sysdev->kobj);

}

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

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

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

//系統裝置關機

//從這個函數中執行shutdown函數的順序,我們可以分析一下驅動的挂載模型:

//最頂層的是system_subsys,所有的cls都挂載在他的連結清單中

//每一個cls有一個驅動連結清單,這個驅動連結清單又可以按sysdev進行一個分組,但是分組隻是為了管理友善,驅動還是挂載在cls下的。

//這個函數實際的操作就是周遊system_subsys.list下所有的cls,執行裡面的shutdown函數

void       sysdev_shutdown(void)

{

       struct sysdev_class * cls;

       mutex_lock(&sysdev_drivers_lock);

       //從系統子系統中取出每一個cls類

       list_for_each_entry_reverse(cls,   &system_subsys.list,   kset.kobj.entry) {

              struct sys_device * sysdev;

              //從cls類中取出每一個sysdev系統裝置

              list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {

                     struct sysdev_driver * drv;

                     //從cls的驅動連結清單中取出每一個驅動,執行shutdown函數

                     list_for_each_entry(drv, &cls->drivers, entry) {

                            if (drv->shutdown)

                                   drv->shutdown(sysdev);

                     }

                     //執行類的shutdown函數

                     if (cls->shutdown)

                            cls->shutdown(sysdev);

              }

       }

       mutex_unlock(&sysdev_drivers_lock);

}

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

//系統裝置的恢複

//實際是先執行類的resume,在依次執行類的驅動連結清單的resume

static void      __sysdev_resume(struct sys_device      *dev)

{

       struct sysdev_class        *cls = dev->cls;

       struct sysdev_driver      *drv;

       //先執行類的rusume函數

       if (cls->resume)

              cls->resume(dev);

       //再依次執行驅動連結清單中的resume函數

       list_for_each_entry(drv, &cls->drivers, entry) {

              if (drv->resume)

                     drv->resume(dev);

       }

}

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

typedef struct pm_message {

       int event;

} pm_message_t;

//系統裝置的挂起函數,參數無意義

int   sysdev_suspend(pm_message_t     state)

{

       struct sysdev_class        * cls;

       struct sys_device           *sysdev, *err_dev;

       struct sysdev_driver      *drv,      *err_drv;

       int ret;

       //同shutdown一樣,按順序執行suspend函數

       list_for_each_entry_reverse(cls,   &system_subsys.list,    kset.kobj.entry) {

              list_for_each_entry(sysdev,   &cls->kset.list,      kobj.entry) {

                     //執行類的驅動連結清單中每一個驅動的suspend挂起函數

                     list_for_each_entry(drv,       &cls->drivers,       entry) {

                            if (drv->suspend) {

                                   ret = drv->suspend(sysdev, state);

                                   if (ret)

                                          goto       aux_driver;

                            }

                     }

                     //執行類的挂起函數

                     if (cls->suspend) {

                            ret = cls->suspend(sysdev, state);

                            if (ret)

                                   goto cls_driver;

                     }

              }

       }

       //每一個挂起都順利完成

       return 0;

//類挂起失敗 

cls_driver:

       drv = NULL;

//類連結清單中某個驅動挂起失敗,drv指向失敗的驅動

aux_driver:

       //resume之前挂起的本組驅動

       list_for_each_entry(err_drv, &cls->drivers, entry) {

              if (err_drv == drv)

                     break;

              if (err_drv->resume)

                     err_drv->resume(sysdev);

       }

       //resume目前類之前挂起的其他組系統裝置

       list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {

              if (err_dev == sysdev)

                     break;

              __sysdev_resume(err_dev);

       }

       list_for_each_entry_continue(cls, &system_subsys.list,

                                   kset.kobj.entry) {

              list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {

                     pr_debug(" %s\n", kobject_name(&err_dev->kobj));

                     __sysdev_resume(err_dev);

              }

       }

       return ret;

}

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

//恢複操作,這個實際在suspend的時候已經接觸過了

int   sysdev_resume(void)

{

       struct sysdev_class * cls;

       list_for_each_entry(cls,        &system_subsys.list,     kset.kobj.entry) {

              struct sys_device * sysdev;

              list_for_each_entry(sysdev,   &cls->kset.list,      kobj.entry) {

                     __sysdev_resume(sysdev);

              }

       }

       return 0;

}

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

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

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

//系統總線的初始化

int   __init     system_bus_init(void)

{

       //系統子系統的父裝置是驅動子系統

       system_subsys.kobj.parent =        &devices_subsys.kobj;

       return     subsystem_register(&system_subsys);          //子系統注冊

}