您的位置:首页 > 运维架构 > Linux

soc camera 子系统之soc camera device初始化

2014-02-10 15:03 225 查看
      从上一篇的博客soc camera 子系统简介(http://blog.csdn.net/smartvincent88/article/details/18987207)中的图中可以看出,soc camera device 是sensor的抽象,可以说,每个soc camera device 对应一个sensor或者其他的video设备。本节就结合soc_camera.c来具体分析soc camera device 的具体的初始化流程。

      首先来看第一个函数:

static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
{

struct soc_camera_link *icl = pdev->dev.platform_data;
struct soc_camera_device *icd;
int ret;

if (!icl)
return -EINVAL;

icd = kzalloc(sizeof(*icd), GFP_KERNEL);
if (!icd)
return -ENOMEM;

icd->iface = icl->bus_id;
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);

ret = soc_camera_device_register(icd);
if (ret < 0)
goto escdevreg;

soc_camera_device_init(&icd->dev, icl);

icd->user_width = DEFAULT_WIDTH;
icd->user_height = DEFAULT_HEIGHT;

dev_info(&pdev->dev, "register ok!\n");
return 0;

escdevreg:
kfree(icd);

return ret;
}


      该probe函数是基于platform device 总线的,该probe函数的注册是在本地函数soc_camera_init中执行的。那么既然有了probe函数,那么肯定会有相应的paltform device啊,别急,我们先来看看,该函数主要做了哪些事情。

      在解释该函数之前,先介绍一下两个主要的结构体,详见下面的注释。
struct soc_camera_link {
/* Camera bus id, used to match a camera and a bus */
int bus_id; //这个一般用于匹配soc camera host的序号
/* Per camera SOCAM_SENSOR_* bus flags */
unsigned long flags;

int i2c_adapter_id; //I2C 适配器号
struct i2c_board_info *board_info;
const char *module_name;
void *priv;

/* Optional regulators that have to be managed on power on/off events */
//可选的,用于电源的管理
struct regulator_bulk_data *regulators;
int num_regulators;

/*
* For non-I2C devices platform platform has to provide methods to
* add a device to the system and to remove
*/
//以下这几个成员函数,主要是针对那些非I2C的平台,用于管理sensor设备的添加或者删除,不过一般情况下用不到
int (*add_device)(struct soc_camera_link *, struct device *);
void (*del_device)(struct soc_camera_link *);
/* Optional callbacks to power on or off and reset the sensor */
int (*power)(struct device *, int);
int (*reset)(struct device *);
/*
* some platforms may support different data widths than the sensors
* native ones due to different data line routing. Let the board code
* overwrite the width flags.
*/
int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
unsigned long (*query_bus_param)(struct soc_camera_link *);
void (*free_bus)(struct soc_camera_link *);
};


      下面介绍一下soc camera device 这个结构体,详见下面的注释
struct soc_camera_device {
struct list_head list;
struct device dev;
struct device *pdev; /* Platform device */
s32 user_width; //图像的宽度,以像素为单位
s32 user_height; //图像的高度,以像素为单位
u32 bytesperline; /* for padding, zero if unused */
u32 sizeimage;//一画图像的大小,也是存储图像缓冲区的大小
enum v4l2_colorspace colorspace;//色域,指描述色彩时所使用的坐标系
unsigned char iface; /* Host number */ //于camera link中的bus_id相对应
unsigned char devnum; /* Device number per host */
struct soc_camera_sense *sense; /* See comment in struct definition */
struct soc_camera_ops *ops;
struct video_device *vdev;
const struct soc_camera_format_xlate *current_fmt; //驱动中当前使用的视频格式
struct soc_camera_format_xlate *user_formats; //全部支持的视频格式
int num_user_formats;
enum v4l2_field field; /* Preserve field over close() */ //决定图像源数据交错的方式
void *host_priv; /* Per-device host private data */
/* soc_camera.c private count. Only accessed with .video_lock held */
int use_count;
struct mutex video_lock; /* Protects device data */
struct file *streamer; /* stream owner */
//下面这个共用体,非常重要,用于管理帧缓冲区
union {
struct videobuf_queue vb_vidq;
struct vb2_queue vb2_vidq;
};
};


      在分析该probe函数之前,笔者先将对应于该probe函数的platform device的简单示例写错来,以便可以更好的分析该probe函数。示例如下:
static int example_power(struct device *dev,int power
{
}
static int example_reset(struct device *dev)
{

}
struct i2c_board_info example_info = {
I2C_BOARD_INFO("example_sensor",0x27),
};

struct soc_camera_link example_link = {
.bus_id = 0,/*match the soc camera host id */
.board_info = &example_info,
.i2c_adapter_id = 1,/*match the I2C Adapater ID.
*/
.power = example_power ,
.reset = example_reset,
};
struct platfom_device example_camera_device = {
.name = "camera device",
.id = 0,
.dev = {
.platform_data = &example_link,
},

};


      以上的代码片度是一个简单的实例,那我们现在可以分析上面的probe函数了,首先,会通过传入的参数pdev获取platform_data,即struct soc_camera_link,然后(2)处的代码为struct soc_camera_device 申请内存,并且初始化,其中iface被初始化为bus_id,指定soc camera host的index。再来看(3)处的代码,调用函数soc_camera_device_register(struct soc_camera_device *dev)函数,来看看这个函数做了什么。
/* Image capture device */
static int soc_camera_device_register(struct soc_camera_device *icd)
{
struct soc_camera_device *ix;
int num = -1, i;

for (i = 0; i < 256 && num < 0; i++) {
num = i;
/* Check if this index is available on this interface */
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
break;
}
}
}

if (num < 0)
/*
* ok, we have 256 cameras on this host...
* man, stay reasonable...
*/
return -ENOMEM;

icd->devnum = num;
icd->use_count = 0;
icd->host_priv = NULL;
mutex_init(&icd->video_lock);

list_add_tail(&icd->list, &devices);

return 0;
}


      该函数核心是for循环,这个for循环目的很明确,确定Index为icd->iface的主机是否已经连接了256个image capture,如果没有,则找出空闲的devnum,即是空闲的设备号,否则,函数返回一个错误码。如果有空闲的devnum,则初始化icd,并且将icd加入到本地链表devices中。

      好了,我们接着分析probe函数,(4)处的代码也做了一件很有意义的事情,就是调用了函数soc_camera_device_init,该函数的代码如下:
static void soc_camera_device_init(struct device *dev, void *pdata)
{
dev->platform_data = pdata;
dev->bus = &soc_camera_bus_type;
dev->release = dummy_release;
}


      非常简单的实现,初始化soc camera device的成员结构体device,将设备的总线类型设置为soc_camera_bus_type,这个总线是soc_camera.c定义的一个简单的本地总线类型,仅供soc_camera.c内部使用。并且还将传入的参数icl赋值给dev的平台数据指针。接着(4)处的代码继续将icd得成员变量us
4000
er_width和user_height初始化为默认值。到此为止,该probe函数分析完了,接下来的部分就是结合soc camera host进行进一步初始化并且注册video
device的部分了。后面将继续分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息