jluzcSOCCamera分析文档格式.docx
- 文档编号:18222638
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:31
- 大小:64.10KB
jluzcSOCCamera分析文档格式.docx
《jluzcSOCCamera分析文档格式.docx》由会员分享,可在线阅读,更多相关《jluzcSOCCamera分析文档格式.docx(31页珍藏版)》请在冰豆网上搜索。
{
2.
.drv_name
PXA_CAM_DRV_NAME,
3.
.ops
&
pxa_soc_camera_host_ops,
4.};
所有的方法都是通过structsoc_camera_host_ops
soc_camera_host_ops
pxa_soc_camera_host_ops
.owner
THIS_MODULE,
.add
pxa_camera_add_device,
4.
.remove
pxa_camera_remove_device,
5.
.suspend
pxa_camera_suspend,
6.
.resume
pxa_camera_resume,
7.
.set_fmt_cap
pxa_camera_set_fmt_cap,
8.
.try_fmt_cap
pxa_camera_try_fmt_cap,
9.
.init_videobuf
pxa_camera_init_videobuf,
10.
.reqbufs
pxa_camera_reqbufs,
11.
.poll
pxa_camera_poll,
12.
.querycap
pxa_camera_querycap,
13.
.try_bus_param
pxa_camera_try_bus_param,
14.
.set_bus_param
pxa_camera_set_bus_param,
15.};
.add是把camerasensor接入host;
.remove方法从host卸载camerasensor时调用,除了执行host内部的初始化工作外,还应该调用camerasensor的.init和.release方法。
(.add方法仅仅在soc_camera_open中被调用,也就是说当应用层第一个打开一个/dev/videoX设备节点时,此时进行camerahost以及camerasensor的初始化是合理的)
.suspend和.resume方法实现host的电源管理功能,他们要负责调用相应的sensor方法。
.try_bus_param和.set_bus_param用来协商host和sensor间的物理连接参数。
.init_videobuf是当一个video-device被打开时调用,video-buffer管理的实现是完全依赖于特定的host
其余部分被V4L2的相应部分调用。
CameraAPI
Sensordrivers可以使用structsoc_camera_link,典型的由platform提供,用来代表sensor连接到的host总线,这个结构还提供了.power和.reset接口。
本节所描述的代码和当前代码已经发生了很大的变化,所以暂时略过本节。
VIDIOC_S_CROP和VIDIOC_S_FMT调用的行为
VIDIOC_S_CROP:
设置sensor窗口的位置和尺寸,单位是sensor的像素。
改变sensor窗口尺寸时维持缩放因子没变,因此用户窗口尺寸也相应的变化了。
VIDIOC_S_FMT:
设置用户窗口。
通过修改缩放因子,尽可能的保持之前设置的窗口尺寸。
如果sensor窗口无法保持不变,那么也可以修改。
soc-camera中有两个地方,可以进行缩放和剪切:
camerasensor驱动,和camerahost驱动。
Userioctl首先发送到hostdirver,然后再向下发送给cameradriver。
在camerasensor驱动执行缩放和剪切可能更有效,因为会节约camera总线带宽以及最大帧率(如果放大还成立吗,对于ADvideo芯片来说,缩放只能在hostdriver来做)。
然而,如果camerasensor驱动无法实现要求的参数,那么host驱动可以决定用它自己的缩放和剪切功能来满足用户需求。
Camerasensor驱动soc-cameracore以及host驱动交互,完全是功能上的,不涉及任何数据传输。
因而所有的camerasensor驱动应该用当前输出格式响应.g_fmt请求。
这对于正确配置camerabus是必要的。
s_fmt()和try_fmt也不得不实现。
sensor窗口和缩放因子也应该在camerasensor驱动内维护。
按照V4L2API,所有的capture驱动应该支持VIDIOC_CROPCAPioctl,因此我们依赖于cameradrivers实现.cropcap()。
如果camerasensor驱动不支持cropping,那么可以选择不支持.s_crop,但是必须在camerahost驱动实现cropping支持,起码g_crop方法必须支持。
用户设置的几何尺寸保存在structsoc_camera_device的.user_width和.user_height成员中,以供soc_cameracore和hostdrivers使用。
core在成功调用s_fmt后会修改这些成员,但是如果是在其他地方修改了他们,比如s_crop,那么hostdriver要负责更型他们。
2、V4L2soc-camera分析-调用关系
应用层通过设备节点/dev/videoX打开video4linuxdevices。
/dev/videoX是一个字符设备,主设备号81,次设备号:
(0~63)分配给capture设备,64~127分配给radio设备,223~255分配给VBI设备,128~191分配给其他类型的。
如果驱动要注册一个video4linux设备,那么需要调用video_register_device函数。
利用dump_stack函数,可以方便的获取内核函数调用关系。
2.1open调用关系
从调用关系角度来看,open是最复杂的,因为它不仅要执行真正的打开操作,还需要为mmapioctl设置操作函数。
1.Application通过open打开设备节点/dev/videoX
2.进入系统调用sys_open,sys_open调用do_sys_open
3.do_sys_open调用do_flip_open
4.do_filp_open这个函数比较长,大部分都是路径查找相关的代码,这里只需要关注do_last
5.do_last大部分是路径相关的代码,只需关注finish_open
6.finish_open调用这个函数时,已经填充好了路径名对应的nameidata结构,调用nameidata_to_flip
7.nameidata_to_flip调用__dentry_open
8.__dentry_open会调用chrdev_open,在__dentry_open中有如下代码片段
[cpp]viewplaincopy
f->
f_op=fops_get(inode->
i_fop);
.....
if(!
open&
f_op)
open=f->
f_op->
open;
if(open){
error=open(inode,f);
if(error)
gotocleanup_all;
}
当系统进行路径lookup过程中,会把这个设备文件对应的inode读入到内存中,在读取文件inode的过程中,判断这个inode是下列类型中的哪一个:
regualr,char,block,pipe。
此时,会根据inode类型的不同,赋给inode->
i_fop不同的操作函数
在当前的case,shmem_get_inode会调用init_special_inode初始化这个inode,由于/dev/videoX是字符设备,所以inode->
i_fop=&
def_chr_fops。
def_chr_fops.open=chrdev_open
9.chrdev_open根据设备节点的主次设备好在系统内查找对应的cdev对象,把cdev->
ops赋给filp->
f_op(这个赋值操作是很重要的步骤,它把filp和具体设备的操作函数联系到一起),当前的case,cdev->
ops是v4l2_ops。
调用filp->
open就完成了打开操作,flip->
open则是v4l2_open。
10.v4l2_open中调用vdev->
fops->
open,对于soccamera来说,我们在调用video_register_device之前,已经把vdev->
fops设置为soc_camera_fops。
vdev->
open也就是调用soc_camera_open
11.绕了很大一圈,终于调用了soc_camera_open。
2.3mmap调用关系
1.系统调用mmap_pgoff,mmap_pgoff调用do_mmap_pgoff
2.do_mmap_pgoff,调用mmap_region
3.mmap_region调用filp->
mmap,在第一次打开文件时,open操作设置了file->
f_op为v4l2_ops,file->
mmap则是v4l2_mmap
4.v4l2_mmap,v4l2_mmap调用vdev->
mmap,对于soc_camera来说,vdev->
fops是soc_camera_ops,所以vdev->
mmap是soc_camera_mmap
5.soc_camera_mmap
2.4ioctl调用关系
1.系统调用ioctl,调用do_vfs_ioctl
2.do_vfs_ioctl,调用vfs_ioctl
3.vfs_ioctl代码片段
if(filp->
unlocked_ioctl){
error=filp->
unlocked_ioctl(filp,cmd,arg);
if(error==-ENOIOCTLCMD)
error=-EINVAL;
gotoout;
}elseif(filp->
ioctl){
lock_kernel();
ioctl(filp->
f_path.dentry->
d_inode,
filp,cmd,arg);
unlock_kernel();
}
在第一次打开文件时,已经设置了filp->
f_op为v4l2_ops。
注意不同内核版本中v4l2_ops实现是不同的,可能定义了ioctl,也可能定义了unlocked_ioctl。
我的kernelv4l2_ops定义如下
staticconststructfile_operationsv4l2_fops={
.owner=THIS_MODULE,
.read=v4l2_read,
.write=v4l2_write,
.open=v4l2_open,
.mmap=v4l2_mmap,
.unlocked_ioctl=v4l2_ioctl,
#ifdefCONFIG_COMPAT
.compat_ioctl=v4l2_compat_ioctl32,
#endif
.release=v4l2_release,
.poll=v4l2_poll,
.llseek=no_llseek,
};
因此filep->
f_op_unlocked_ioctl是v4l2_ioctl
2.5.v4l2_ioctl代码片段如下
if(vdev->
if(vdev->
lock&
mutex_lock_interruptible(vdev->
lock))
return-ERESTARTSYS;
if(video_is_registered(vdev))
ret=vdev->
lock)
mutex_unlock(vdev->
lock);
soc_camera_fops.unlocked_ioctl=video_ioctl2
2.6.video_ioctl2调用__video_do_ioctl
2.7.__video_do_ioctl,
这个函数对参数做一些基本的判断,然后调用video_device的ioctl_ops,对于soc_camera系统来说,是soc_camera_ioctl_ops
2.8soc_camera_ioctl_ops实现如下
staticconststructv4l2_ioctl_opssoc_camera_ioctl_ops={
.vidioc_querycap=soc_camera_querycap,
.vidioc_g_fmt_vid_cap=soc_camera_g_fmt_vid_cap,
.vidioc_enum_fmt_vid_cap=soc_camera_enum_fmt_vid_cap,
.vidioc_s_fmt_vid_cap=soc_camera_s_fmt_vid_cap,
.vidioc_enum_input=soc_camera_enum_input,
.vidioc_g_input=soc_camera_g_input,
.vidioc_s_input=soc_camera_s_input,
.vidioc_s_std=soc_camera_s_std,
.vidioc_reqbufs=soc_camera_reqbufs,
.vidioc_try_fmt_vid_cap=soc_camera_try_fmt_vid_cap,
.vidioc_querybuf=soc_camera_querybuf,
.vidioc_qbuf=soc_camera_qbuf,
.vidioc_dqbuf=soc_camera_dqbuf,
.vidioc_streamon=soc_camera_streamon,
.vidioc_streamoff=soc_camera_streamoff,
.vidioc_queryctrl=soc_camera_queryctrl,
.vidioc_g_ctrl=soc_camera_g_ctrl,
.vidioc_s_ctrl=soc_camera_s_ctrl,
.vidioc_cropcap=soc_camera_cropcap,
.vidioc_g_crop=soc_camera_g_crop,
.vidioc_s_crop=soc_camera_s_crop,
.vidioc_g_parm=soc_camera_g_parm,
.vidioc_s_parm=soc_camera_s_parm,
.vidioc_g_chip_ident=soc_camera_g_chip_ident,
#ifdefCONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register=soc_camera_g_register,
.vidioc_s_register=soc_camera_s_register,
3、v4L2soc-camera分析-soc_camera.c
soc_camera.c
1455staticstructplatform_driver__refdatasoc_camera_pdrv={
1456.remove=__devexit_p(soc_camera_pdrv_remove),
1457.driver={
1458.name="
soc-camera-pdrv"
1459.owner=THIS_MODULE,
1460},
1461};
1462
1463staticint__initsoc_camera_init(void)
1464{
1465intret=bus_register(&
soc_camera_bus_type);
1466if(ret)
1467returnret;
1468ret=driver_register(&
ic_drv);
1469if(ret)
1470gotoedrvr;
1471
1472ret=platform_driver_probe(&
soc_camera_pdrv,soc_camera_pdrv_probe);
1473if(ret)
1474gotoepdr;
1475
1476return0;
1477
1478epdr:
1479driver_unregister(&
1480edrvr:
1481bus_unregister(&
1482returnret;
1483}
1472platform_driver_probe和platform_driver_register的区别:
前者功能上和platform_driver_register是一样的,但是在内核启动完成后,这个函数就不能再执行了,这样可以释放函数soc_camera_pdrv_probe所占的空间。
soc_camera_pdrv_probe会probe系统内名称为"
的平台设备,系统内有几个这样的平台设备,那么就会创建几个soc_camera_device。
这些平台设备可如下定义:
structplatform_deviceyour_mach_cameras[]={
{
.name="
.id=0,
.dev={
.platform_data=adv7180_link,
},
},{
.id=1,
.platform_data=tw9912_link,
}
注意,这里假定系统的camera处理模块,接了两个camerasensor,adv7180_link和tw9912_link
staticstructi2c_board_infodecoder_i2c_adv7180={
I2C_BOARD_INFO("
adv7180"
(0x42>
>
1)),
structsoc_camera_linkadv7180_link={
.bus_id=0,
.board_info=&
decoder_i2c_adv7180,
.i2c_adapter_id=0,
soc_camera_link主要用来定义i2c地址,如果sensor不是通过i2c连接到host上,那么要定
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- jluzcSOCCamera 分析