從上一篇的博客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的部分了。後面將繼續分析。