Nouveau源码分析(二)
在讨论Nouveau对Nvidia设备的初始化前,我准备先说一下Nouveau结构体的基本框架
Nouveau的很多结构体都可以看作是C++中的类,之间有很多相似的东西,比如继承关系,virtual成员函数等.
模拟继承
先尝试阅读一下这个代码:
#include <stdlib.h>
struct abc
{
int a;
int b;
int c;
};
struct def
{
struct abc base;
int d;
int e;
int f;
};
#define abc_create(a,b,c,pabc) \
abc_create_(a,b,c,sizeof(**pabc),(void **)pabc)
int abc_create_(int a,int b,int c,
size_t size,void **pabc)
{
struct abc *abc_ = (struct abc *)malloc(size); //按传入的size分配空间
abc_->a = a;
abc_->b = b;
abc_->c = c; //初始化自身
*pabc = abc_;
return 0;
}
#define def_create(a,b,c,d,e,f,pdef) \
def_create_(a,b,c,d,e,f,sizeof(**pdef),(void **)pdef) //获得实际应分配空间大小
int def_create_(int a,int b,int c,int d,int e,int f,
size_t size,void **pdef)
{
struct def *def_;
abc_create_(a,b,c,size,pdef); //先初始化基类
def_ = (struct def *)*pdef;
def_->d = d;
def_->e = e; //然后初始化自身
def_->f = f;
return 0;
}
int main(void)
{
struct def *d;
def_create(1,2,3,4,5,6,&d);
return 0;
}
Nouveau中大部分的结构体都是这种模式的,模拟C++的继承关系
当然一般还会有配套使用的宏,比如这个例子中可以有:
#define nv_abc(a) ((struct abc *)a)
//使用方法:
struct def *b;
//初始化b,做一些事情
nv_abc(b)->a = 7;
[注意:实际在nouveau代码中,还有一种关系是parent关系,这和此处讨论的继承关系无关]
模拟virtual函数
改造一下上面写的程序,改成这样:
#include <stdlib.h>
#include <stdio.h>
struct oclass
{
int (*test)(int); //类的test函数
};
/****************abc****************/
struct abc
{
struct oclass *oclass;
int a;
int b;
int c;
};
int abc_test(int a)
{
return a * a;
}
struct oclass abc_oclass = {abc_test}; //abc的test函数
#define nv_abc(a) ((struct abc *)a)
#define abc_create(a,b,c,pabc) \
abc_create_(&abc_oclass, \
a,b,c,sizeof(**pabc),(void **)pabc)
int abc_create_(struct oclass *oclass,int a,int b,int c,
size_t size,void **pabc)
{
struct abc *abc_ = (struct abc *)malloc(size);
abc_->a = a;
abc_->b = b;
abc_->c = c;
abc_->oclass = oclass;
*pabc = abc_;
return 0;
}
/****************def****************/
struct def
{
struct abc base;
int d;
int e;
int f;
};
int def_test(int a)
{
return a;
}
struct oclass def_oclass = {def_test}; //def的test函数
#define nv_def(a) ((struct def *)a)
#define def_create(a,b,c,d,e,f,pdef) \
def_create_(a,b,c,d,e,f,sizeof(**pdef),(void **)pdef)
int def_create_(int a,int b,int c,int d,int e,int f,
size_t size,void **pdef)
{
struct def *def_;
abc_create_(&def_oclass,a,b,c,size,pdef);
def_ = (struct def *)*pdef;
def_->d = d;
def_->e = e;
def_->f = f;
return 0;
}
int main(void)
{
struct def *d;
struct abc *a;
def_create(1,2,3,4,5,6,&d);
abc_create(1,2,3,&a);
printf("%d %d\n",nv_abc(d)->oclass->test(3),
nv_abc(a)->oclass->test(3)); //尝试执行
return 0;
}
利用这个,就可以用同一个接口nouveau_object,实现对很多不同设备模块的访问
使用标识符获得oclass
还有一种情况,传递参数时传递的是"u32 oclass",而不是"struct nouveau_oclass *oclass",这种情况就要依照parent向上搜索,得到具体的oclass
此处不展开讨论,等看到那部分代码再详细说明
|