OK6410 V4L2 分析

 

主要分析来自下面一篇文章。
http://www.chinaaet.com/article/3000015768 


/*
由mach-smdk6410.c文件可知,内核启动时将所有platform_device
包括 s3c_device_fimc0 s3c_device_fimc1
挂载到platform总线。
*/

/*
dev-fimc0.c
*/
struct platform_device s3c_device_fimc0 = {
    .name          = "s3c-fimc",
    .id          = 0,
    .num_resources      = ARRAY_SIZE(s3c_fimc0_resource),
    .resource      = s3c_fimc0_resource,
};
/*
dev-fimc1.c
*/
struct platform_device s3c_device_fimc1 = {
    .name          = "s3c-fimc",
    .id          = 1,
    .num_resources      = ARRAY_SIZE(s3c_fimc1_resource),
    .resource      = s3c_fimc1_resource,
};
/*
mach-smdk6410.c 
*/
static struct platform_device *smdk6410_devices[] __initdata = 
{
    &s3c_device_hsmmc0,
    &s3c_device_hsmmc1,
    &s3c_device_i2c0,
    &s3c_device_fb,
    &s3c_device_ohci,
    &s3c_device_usb_hsotg,
    &samsung_asoc_dma,
    &samsung_device_keypad,
    &gpio_button_device,
    &s3c_device_nand,   
#ifdef CONFIG_DM9000
    &s3c_device_dm9000,
#endif
    &s3c64xx_device_ac97,
    &s3c_device_rtc,
    &s3c_device_ts,
    
    &s3c_device_fimc0,//FIMC 设备
    &s3c_device_fimc1,
    &s3c_device_wdt, 
    &s3c_device_vpp,
    &s3c_device_mfc,
    &s3c_device_tvenc,
    &s3c_device_tvscaler,
    &s3c_device_rotator,
    &s3c_device_jpeg,
    &s3c_device_g2d,
    &s3c_device_g3d,
    &s3c64xx_device_spi0,
    &s3c64xx_device_spi1,
};
platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
/*
platform总线的match函数将device和driver匹配之后,
会自动调用s3c_fimc_driver中指定的probe函数探测设备、
申请内存资源、申请中断等,
并将最终形成的platform_device类型数据保存到内核中,
供后续使用。
*/
/*
s3c_fimc_core.c
*/
static int s3c_fimc_probe(struct platform_device *pdev)
{
    struct s3c_platform_fimc *pdata;
    struct s3c_fimc_control *ctrl;
    struct clk *srclk;
    int ret;
    ctrl = s3c_fimc_register_controller(pdev);
    if (!ctrl) {
        err("cannot register fimc controller\n");
        goto err_fimc;
    }
    pdata = to_fimc_plat(&pdev->dev);
    if (pdata->cfg_gpio)
        pdata->cfg_gpio(pdev);
    /* fimc source clock */
    srclk = clk_get(&pdev->dev, pdata->srclk_name);
    if (IS_ERR(srclk)) {
        err("failed to get source clock of fimc\n");
        goto err_clk_io;
    }
    /* fimc clock */
    ctrl->clock = clk_get(&pdev->dev, pdata->clk_name);
    if (IS_ERR(ctrl->clock)) {
        err("failed to get fimc clock source\n");
        goto err_clk_io;
    }
    /* set parent clock */
    clk_enable(ctrl->clock);
    /* things to initialize once */
    if (ctrl->id == 0) {
        ret = s3c_fimc_init_global(pdev);
        if (ret)
            goto err_global;
    }
    
    /*
     注册 video4linux devices
    */
    ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);
    if (ret) {
        err("cannot register video driver\n");
        goto err_video;
    }
    info("controller %d registered successfully\n", ctrl->id);
    return 0;
err_video:
    clk_put(s3c_fimc.cam_clock);
err_global:
    clk_disable(ctrl->clock);
    clk_put(ctrl->clock);
err_clk_io:
    s3c_fimc_unregister_controller(pdev);
err_fimc:
    return -EINVAL;
    
}
static struct platform_driver s3c_fimc_driver = {
    .probe        = s3c_fimc_probe,
    .remove        = s3c_fimc_remove,
    .suspend    = s3c_fimc_suspend,
    .resume        = s3c_fimc_resume,
    .driver        = {
        .name    = "s3c-fimc",
        .owner    = THIS_MODULE,
    },
};

/*
 video_device结构体包括fops、ioctl_ops、release、name、vf_type几个成员变量,
其中,最重要的是file_operations类型的[fops]  和  v4l2_ioctl_ops类型的[ioctl_ops],
分别实现文件操作接口和V4L2接口。
*/
struct video_device s3c_fimc_video_device[S3C_FIMC_MAX_CTRLS] = {
    [0] = {
        .vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,
        .fops = &s3c_fimc_fops,
        .ioctl_ops = &s3c_fimc_v4l2_ops,
        .release  = s3c_fimc_vdev_release,
        
        .name = "sc3_video0",
    },
    [1] = {
        .vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,
        .fops = &s3c_fimc_fops,
        .ioctl_ops = &s3c_fimc_v4l2_ops,
        .release  = s3c_fimc_vdev_release,
        .name = "sc3_video1",
    },
    [2] = {
        .vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,
        .fops = &s3c_fimc_fops,
        .ioctl_ops = &s3c_fimc_v4l2_ops,
        .release  = s3c_fimc_vdev_release,
        .name = "sc3_video2",
    },
};

struct video_device
{
    /* device ops */
    const struct v4l2_file_operations *fops;
    /* sysfs */
    struct device dev;        /* v4l device */
    struct cdev *cdev;        /* character device */
    /* Set either parent or v4l2_dev if your driver uses v4l2_device */
    struct device *parent;        /* device parent */
    struct v4l2_device *v4l2_dev;    /* v4l2_device parent */
    /* Control handler associated with this device node. May be NULL. */
    struct v4l2_ctrl_handler *ctrl_handler;
    /* device info */
    char name[32];
    int vfl_type;
    /* 'minor' is set to -1 if the registration failed */
    int minor;
    u16 num;
    /* added for TV */
    int type2;
    int users;
    /* use bitops to set/clear/test flags */
    unsigned long flags;
    /* attribute to differentiate multiple indices on one physical device */
    int index;
    /* V4L2 file handles */
    spinlock_t        fh_lock; /* Lock for all v4l2_fhs */
    struct list_head    fh_list; /* List of struct v4l2_fh */
    int debug;            /* Activates debug level*/
    /* Video standard vars */
    v4l2_std_id tvnorms;        /* Supported tv norms */
    v4l2_std_id current_norm;    /* Current tvnorm */
    /* callbacks */
    void (*release)(struct video_device *vdev);
    /* ioctl callbacks */
    const struct v4l2_ioctl_ops *ioctl_ops;
};
/*
s3c_fimc_core.c
FIMC驱动遵循V4L2接口标准,其file_operations接口定义如下:
当应用程序通过系统调用open()打开摄像头设备时,内核会最终找到s3c_fimc_open()
函数来打开摄像头。
应用程序通过read()获取图像数据,该函数通过copy_to_user()
将内核空间所申请缓冲区中图像数据拷贝到用户空间中开辟的图像数据区。
该函数没有充分利用FIMC接口提供的ping-pong缓冲区,按字进行拷贝(memcpy),
十分耗时。
mmap函数将内核空间中申请到的图像缓冲区映射到应用程序所在的用户空间,
这样,应用程序申请到的buffer将指向内核空间的图像缓冲区,应用程序可以
(不拷贝)直接对图像进行操作。该函数配合V4L2标准中的环形缓冲区队列,
节省了应用程序读取图像数据所消耗的时间。
*/
static const struct v4l2_file_operations s3c_fimc_fops = {
//static const struct file_operations s3c_fimc_fops = {
    .owner = THIS_MODULE,
    .open = s3c_fimc_open,
    .release = s3c_fimc_release,
    .unlocked_ioctl = video_ioctl2,
    .read = s3c_fimc_read,
    .write = s3c_fimc_write,
    .mmap = s3c_fimc_mmap,
    .poll = s3c_fimc_poll,
};
/*
s3c_fimc_v4l2.c
*/

/*************************
  应用程序通过ioctl接口使用这些函数,比如ioctl(fd,VIDIOC_S_FMT,&fmt)
用来设置图像格式,此时V4L2会将VIDIOC_S_FMT命令映射为s3c_fimc_v4l2_s_fmt_vid_cap()函数,
并将fmt指定的格式告知FIMC接口,FIMC会将OV9650传递过来的原始图像数据经过类型转换传递回应用程序。
s3c_fimc_v4l2_reqbufs()用于申请图像缓冲区,
该函数为应用程序在内核空间开辟ping-pong缓冲区。s3c_fimc_v4l2_qbuf()
函数将缓冲区组成环形缓冲队列,当应用程序需要调用图像数据时,使用s3c_fimc_v4l2_dqbuf()
使指定的缓冲区出队,缓冲区在出队期间,不会被新来的图像数据覆盖,
新到的图像数据会被传送到环形队列中指定缓冲区的下一个缓冲区。
由于FIMC控制器为P通道和C通道分别开辟了4个缓冲区,在内核初始化时已经申请到,
因此FIMC驱动中并不需要再重新申请。

*************************/
const struct v4l2_ioctl_ops s3c_fimc_v4l2_ops = {
    .vidioc_querycap        = s3c_fimc_v4l2_querycap,
    .vidioc_g_fbuf            = s3c_fimc_v4l2_g_fbuf,
    .vidioc_s_fbuf            = s3c_fimc_v4l2_s_fbuf,
    .vidioc_enum_fmt_vid_cap    = s3c_fimc_v4l2_enum_fmt_vid_cap,
    .vidioc_g_fmt_vid_cap        = s3c_fimc_v4l2_g_fmt_vid_cap,
    .vidioc_s_fmt_vid_cap        = s3c_fimc_v4l2_s_fmt_vid_cap,
    .vidioc_try_fmt_vid_cap        = s3c_fimc_v4l2_try_fmt_vid_cap,
    .vidioc_try_fmt_vid_overlay    = s3c_fimc_v4l2_try_fmt_overlay,
    .vidioc_overlay            = s3c_fimc_v4l2_overlay,
    .vidioc_g_ctrl            = s3c_fimc_v4l2_g_ctrl,
    .vidioc_s_ctrl            = s3c_fimc_v4l2_s_ctrl,
    .vidioc_streamon        = s3c_fimc_v4l2_streamon,
    .vidioc_streamoff        = s3c_fimc_v4l2_streamoff,
    .vidioc_g_input            = s3c_fimc_v4l2_g_input,
    .vidioc_s_input            = s3c_fimc_v4l2_s_input,
    .vidioc_g_output        = s3c_fimc_v4l2_g_output,
    .vidioc_s_output        = s3c_fimc_v4l2_s_output,
    .vidioc_enum_input        = s3c_fimc_v4l2_enum_input,
    .vidioc_enum_output        = s3c_fimc_v4l2_enum_output,
    .vidioc_reqbufs            = s3c_fimc_v4l2_reqbufs,
    .vidioc_querybuf        = s3c_fimc_v4l2_querybuf,
    .vidioc_qbuf            = s3c_fimc_v4l2_qbuf,
    .vidioc_dqbuf            = s3c_fimc_v4l2_dqbuf,
    .vidioc_cropcap            = s3c_fimc_v4l2_cropcap,
    .vidioc_g_crop            = s3c_fimc_v4l2_g_crop,
    .vidioc_s_crop            = s3c_fimc_v4l2_s_crop,
    .vidioc_s_parm            = s3c_fimc_v4l2_s_parm,
};

在内核中加入打印。追踪ok6410 官方camera 测试程序运行过程。

--s3c_fimc_probe
---[CAM]s3c_fimc_register_controller.id=0
--[CAM]s3c_fimc_set_active_camera,id=0
s3c_fimc_init_global s3c_fimc.cam_clock=-1065304896
--video_register_device
device: 'video0': device_add
s3c-fimc: controller 0 registered successfully
driver: 's3c-fimc.0': driver_bound: bound to device 's3c-fimc'
bus: 'platform': really_probe: bound device s3c-fimc.0 to driver s3c-fimc
bus: 'platform': driver_probe_device: matched device s3c-fimc.1 with driver s3c-fimc
bus: 'platform': really_probe: probing driver s3c-fimc with device s3c-fimc.1
--s3c_fimc_probe
---[CAM]s3c_fimc_register_controller.id=1
--[CAM]s3c_fimc_set_active_camera,id=0
--video_register_device
device: 'video1': device_add
s3c-fimc: controller 1 registered successfully
driver: 's3c-fimc.1': driver_bound: bound to device 's3c-fimc'
bus: 'platform': really_probe: bound device s3c-fimc.1 to driver s3c-fimc
s3c-fimc: 

--info ov965x_init
bus: 'i2c': add driver ov965x
bus: 'i2c': driver_probe_device: matched device 0-0030 with driver ov965x
bus: 'i2c': really_probe: probing driver ov965x with device 0-0030
s3c-fimc: 

--ov965x_probe
[CAM]s3c_fimc_register_camera,cam->id=0
s3c_fimc.cam_clock = c080bcc0
parent clock for camera: 266.000 MHz, divisor: 11
[CAM]RESET CAM.[CAM]Reset and init reg!1cam->client=cc460c00
[CAM]Reset and init reg!1
[CAM]Reset and init reg!2
--[CAM]s3c_fimc_init_camera
[CAM]I2C_CAM_INIT.
--[CAM]s3c_fimc_init_camera
--[CAM]s3c_fimc_init_camera
[CAM]Reset and init reg!3
s3c-fimc: //OV9650 寄存器设置

--reg 12  80
--reg ff  0a
--reg 6a  3e
--reg 3b  09
--reg 13  8f
--reg 01  80
--reg 02  80
--reg 00  00
--reg 10  00
--reg 35  91
--reg 0e  a0
--reg 1e  34
--reg a8  80
--reg 04  00
--reg 0c  04
--reg 0d  80
--reg 11  81
--reg 12  40
--reg 37  91
--reg 38  12
--reg 39  43
--reg 18  c6
--reg 17  26
--reg 32  ad
--reg 03  00
--reg 1a  3d
--reg 19  01
--reg 3f  a6
--reg 14  2e
--reg 15  10
--reg 41  02
--reg 42  08
--reg 1b  00
--reg 16  06
--reg 33  e2
--reg 34  bf
--reg 96  04
-reg 3a  00
--reg 8e  00
--reg 3c  77
--reg 8b  06
--reg 94  88
--reg 95  88
--reg 40  c1
--reg 29  3f
--reg 0f  42
--reg 3d  92
--reg 69  40
--reg 5c  b9
--reg 5d  96
--reg 5e  10
--reg 59  c0
--reg 5a  af
--reg 5b  55
-reg 43  f0
--reg 44  10
--reg 45  68
--reg 46  96
--reg 47  60
--reg 48  80
--reg 5f  e0
--reg 60  8c
--reg 61  20
--reg a5  d9
--reg a4  74
--reg 8d  02
--reg 4f  3a
--reg 50  3d
--reg 51  03
--reg 52  12
--reg 53  26
--reg 54  36
--reg 55  45
--reg 56  40
--reg 57  40
--reg 58  0d
--reg 8c  23
--reg 3e  02
--reg a9  b8
--reg aa  92
--reg ab  0a

--reg 8f  df
--reg 90  00
--reg 91  00
--reg 9f  00
--reg a0  00
--reg 3a  01
--reg 24  70
--reg 25  64
--reg 26  c3
--reg 2a  00
--reg 2b  00
--reg 6c  40
--reg 6d  30
--reg 6e  4b
--reg 6f  60
--reg 70  70
--reg 71  70
--reg 72  70
--reg 73  70
--reg 74  60
--reg 75  60
--reg 76  50
--reg 77  48
--reg 78  3a
--reg 79  2e
--reg 7a  28
--reg 7b  22
--reg 7c  04
--reg 7d  07
-reg 7e  10
--reg 7f  28
-reg 80  36
--reg 81  44
-reg 82  52
--reg 83  60
 
--reg 84  6c
--reg 85  78
--reg 86  8c
--reg 87  9e
--reg 88  bb
--reg 89  d2
--reg 8a  e6
driver: '0-0030': driver_bound: bound to device 'ov965x'
bus: 'i2c': really_probe: bound device 0-0030 to driver ov965x

Please press Enter to activate this console. device: 'vcs2': device_add
device: 'vcsa2': device_add
device: 'vcs4': device_add
device: 'vcsa4': device_add
device: 'vcs3': device_add
device: 'vcsa3': device_add
touch...

[root@FORLINX6410]# 
[root@FORLINX6410]# ls
adctest             keytest             sbin
at24c08test         ledtest             sdcard
bin                 lib                 spitest
camera              linuxrc             sys
dev                 mnt                 tmp
duhuitest           mpu6050             uarttest
etc                 nfs.txt             udisk
fork                opt                 udp
gpio                ov9650              usr
iictest             proc                var
key_workqueue_test  root                w25q128
[root@FORLINX6410]# cd camera
[root@FORLINX6410]# ls
422jpeg.h    Makefile     testcamera   v4l2.c       videodev.h   videodev2.h



[root@FORLINX6410]# ./testcamera

//运行testcamera,开始显示图片
Start Main ---v4l2_open  id=0
--v4l2 get
--[CAM]s3c_fimc_open.id=0
--[CAM]ctrl->in_cam->width=640
s3c_fimc_v4l2_s_fmt_vid_cap filp=cbcd4f00,fh=c08bbed0,f=cbccf000
s3c_fimc_alloc_output_memory width 140  height f0 format 0 buf_size = 26000
s3c_fimc_v4l2_streamon is called
--[CAM]s3c_fimc_init_camera
--v4l2 read
---s3c_fimc_read

already open the devicise codec 
Before openning FB 
VIDIOC_S_FMT is c0cc5605
VIDIOC_STREAMON is 40045612
start to get pic 0
display 153600
--v4l2 read
---s3c_fimc_read
display 153600
--v4l2 read
---s3c_fimc_read
display 153600


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值