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的部分了。後面將繼續分析。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章