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

      从上一篇的博客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得成员变量user_width和user_height初始化为默认值。到此为止,该probe函数分析完了,接下来的部分就是结合soc camera host进行进一步初始化并且注册video device的部分了。后面将继续分析。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值