soc camera 子系統(tǒng)為分為soc camera device 和 soc camera host,并且定義了標(biāo)準(zhǔn)的接口或者回調(diào)函數(shù).
流程:
1.獲取傳來(lái)信息,填充soc_camera_link
2.初始化soc_camera_device(iface、device、設(shè)備號(hào)、總線類型)、加入鏈表
3.
一、/linux-3.0.35/drivers/media/video/soc_camera.c主要是用來(lái)管理接口或者回調(diào)函數(shù).
module_init(soc_camera_init);
static int __init?soc_camera_init(void)
{
int ret = bus_register(&soc_camera_bus_type);//注冊(cè)單沒(méi)有關(guān)聯(lián)
...
ret = driver_register(&ic_drv);
...
ret = platform_driver_probe(&soc_camera_pdrv,?soc_camera_pdrv_probe);
...
}
static int __devinit?soc_camera_pdrv_probe(struct platform_device *pdev)
{
//通過(guò)傳入的參數(shù)pdev獲取platform_data,即struct soc_camera_link
struct soc_camera_link *icl = pdev->dev.platform_data;
struct soc_camera_device *icd;
/*
* 分配設(shè)備結(jié)構(gòu)及初始化
*/
icd = kzalloc(sizeof(*icd), GFP_KERNEL);
icd->iface = icl->bus_id;//iface被初始化為bus_id
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);
ret =?soc_camera_device_register(icd);//soc_camera_device加到全局camera device鏈表@devices上,并且為它分配設(shè)備號(hào),做一些必要的初始化
soc_camera_device_init(&icd->dev, icl);//設(shè)置soc_came_device對(duì)應(yīng)device的bus為soc_camera_bus_type,這樣當(dāng)我們注冊(cè)設(shè)備時(shí),就會(huì)調(diào)用soc_camera_probe
icd->user_width??= DEFAULT_WIDTH;
icd->user_height?= DEFAULT_HEIGHT;
}
struct?soc_camera_link?{
int bus_id;//匹配soc?camera?host的序號(hào)
unsigned long flags;
int i2c_adapter_id;//I2C?適配器號(hào)
struct i2c_board_info *board_info;
const char *module_name;
void *priv;
struct regulator_bulk_data *regulators;//用于電源的管理
int num_regulators;
/*
*針對(duì)那些非I2C的平臺(tái)的函數(shù),用于管理sensor設(shè)備的添加或者刪除
*/
int (*add_device)(struct soc_camera_link *, struct device *);
void (*del_device)(struct soc_camera_link *);
int (*power)(struct device *, int);
int (*reset)(struct device *);
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 *);
};
struct?soc_camera_device?{
struct list_head list;
struct device dev;
struct device *pdev;??
s32 user_width; ?//圖像的寬度,以像素為單位
s32 user_height;//圖像的高度,以像素為單位
u32 bytesperline;??
u32 sizeimage; ??//一畫(huà)圖像的大小,也是存儲(chǔ)圖像緩沖區(qū)的大小
enum v4l2_colorspace colorspace;//色域,指描述色彩時(shí)所使用的坐標(biāo)系
unsigned char iface;??//于camera?link中的bus_id相對(duì)應(yīng)
unsigned char devnum;??
struct soc_camera_sense *sense;?
struct soc_camera_ops *ops;
struct video_device *vdev;
const struct soc_camera_format_xlate *current_fmt;//驅(qū)動(dòng)中當(dāng)前使用的視頻格式
struct soc_camera_format_xlate *user_formats; ?//全部支持的視頻格式
int num_user_formats;
enum v4l2_field field;??//決定圖像源數(shù)據(jù)交錯(cuò)的方式
void *host_priv;??
int use_count;
struct mutex video_lock;?
struct file *streamer;??
/*
* 管理幀緩沖區(qū)
*/
union {
struct videobuf_queue vb_vidq;
struct vb2_queue vb2_vidq;
};
};
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++) {//判斷掛接的設(shè)備是否256個(gè)設(shè)備號(hào)都占用
num = i;
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
break;
}
}
? }
icd->devnum??= num;//找到空閑的設(shè)備號(hào)
icd->use_count??= 0;
icd->host_priv??= NULL;
mutex_init(&icd->video_lock);
list_add_tail(&icd->list, &devices);//將空閑的設(shè)備結(jié)構(gòu)放入鏈表
}
static void?soc_camera_device_init(struct device *dev, void *pdata)
{
dev->platform_data?= pdata;
dev->bus??= &soc_camera_bus_type;//設(shè)置總線類型
dev->release??= dummy_release;
}
struct bus_type?soc_camera_bus_type?= {
?.name??= "soc-camera",
?.probe??=?soc_camera_probe,
?.remove??= soc_camera_remove,
?.suspend?= soc_camera_suspend,
?.resume??= soc_camera_resume,
};
static int?soc_camera_probe(struct device *dev)
{
...
?ret =?video_dev_create(icd);
...
}
static int?video_dev_create(struct soc_camera_device *icd)
{
?struct video_device *vdev = video_device_alloc();
strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
vdev->parent??= &icd->dev;
?vdev->current_norm?= V4L2_STD_UNKNOWN;
?vdev->fops??= &soc_camera_fops;
?vdev->ioctl_ops??= &soc_camera_ioctl_ops;
?vdev->release??= video_device_release;
?vdev->tvnorms??= V4L2_STD_UNKNOWN;
icd->vdev = vdev;
return 0;
}
static struct v4l2_file_operations?soc_camera_fops?= {
?.owner??= THIS_MODULE,
?.open??=?soc_camera_open,
?.release?= soc_camera_close,
?.unlocked_ioctl?=?video_ioctl2,
?.read??= soc_camera_read,
?.mmap??= soc_camera_mmap,
?.poll??= soc_camera_poll,
};
static int?soc_camera_open(struct file *file)
{
?struct video_device *vdev = video_devdata(file);//獲取video_driver信息
...
}
/linux-3.0.35/drivers/media/video/v4l2-ioctl.c
long?video_ioctl2(struct file *file,
??????? unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg,?__video_do_ioctl);
}
static long?__video_do_ioctl(struct file *file,
??unsigned int cmd, void *arg)
{
struct video_device *vfd = video_devdata(file);
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
void *fh = file->private_data;
...
case VIDIOC_S_CROP:
{
struct v4l2_crop *p = arg;
ret = ops->vidioc_s_crop(file, fh, p);
break;
}
...
}
?
評(píng)論
查看更多