soc camera 子系統為分為soc camera device 和 soc camera host,并且定義了標準的接口或者回調函數.
流程:
1.獲取傳來信息,填充soc_camera_link
2.初始化soc_camera_device(iface、device、設備號、總線類型)、加入鏈表
3.
一、/linux-3.0.35/drivers/media/video/soc_camera.c主要是用來管理接口或者回調函數.
module_init(soc_camera_init);
static int __init?soc_camera_init(void)
{
int ret = bus_register(&soc_camera_bus_type);//注冊單沒有關聯
...
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)
{
//通過傳入的參數pdev獲取platform_data,即struct soc_camera_link
struct soc_camera_link *icl = pdev->dev.platform_data;
struct soc_camera_device *icd;
/*
* 分配設備結構及初始化
*/
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上,并且為它分配設備號,做一些必要的初始化
soc_camera_device_init(&icd->dev, icl);//設置soc_came_device對應device的bus為soc_camera_bus_type,這樣當我們注冊設備時,就會調用soc_camera_probe
icd->user_width??= DEFAULT_WIDTH;
icd->user_height?= DEFAULT_HEIGHT;
}
struct?soc_camera_link?{
int bus_id;//匹配soc?camera?host的序號
unsigned long flags;
int i2c_adapter_id;//I2C?適配器號
struct i2c_board_info *board_info;
const char *module_name;
void *priv;
struct regulator_bulk_data *regulators;//用于電源的管理
int num_regulators;
/*
*針對那些非I2C的平臺的函數,用于管理sensor設備的添加或者刪除
*/
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; ??//一畫圖像的大小,也是存儲圖像緩沖區的大小
enum v4l2_colorspace colorspace;//色域,指描述色彩時所使用的坐標系
unsigned char iface;??//于camera?link中的bus_id相對應
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;//驅動中當前使用的視頻格式
struct soc_camera_format_xlate *user_formats; ?//全部支持的視頻格式
int num_user_formats;
enum v4l2_field field;??//決定圖像源數據交錯的方式
void *host_priv;??
int use_count;
struct mutex video_lock;?
struct file *streamer;??
/*
* 管理幀緩沖區
*/
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++) {//判斷掛接的設備是否256個設備號都占用
num = i;
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
break;
}
}
? }
icd->devnum??= num;//找到空閑的設備號
icd->use_count??= 0;
icd->host_priv??= NULL;
mutex_init(&icd->video_lock);
list_add_tail(&icd->list, &devices);//將空閑的設備結構放入鏈表
}
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;
}
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;
}
...
}
?
評論
查看更多