小結:
從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); //子系統注冊
}