fs4412开发板学习笔记(七)

摄像头驱动:
目录:Linux3.0 drivers\media\video
    Linux3.14.29  drivers\media\i2c\soc_camera


CMOS摄像头驱动:
一、device
1.设备地址
    从OV3640_CSP_11_SPEC.pdf  P39可知道到
    The device slave addresses are 0x78 for write (01111000)
                                                 and 0x79 for read  (01111001)

I2C的地址:  8bit的地址=7bit设备地址+1bit的读/写控制位

因此该设备地址=0111100 =0x3C

二、driver


/*1.1 分配、设置一个i2c_driver*/
static struct i2c_driver cmos_ov3640_driver={
    .driver={
        .name = "cmos_ov3640",
        .owner=THIS_MODULE,
    },
    .probe   =cmos_ov3640_probe,
    .remove  =cmos_ov3640_remove,
    .id_table=cmos_ov3640_id_table,
}; 

static int cmos_ov3640_drv_init(void)
{
    /*1.2 注册*/
    i2c_add_driver(&cmos_ov3640_driver);
    return 0;
}

static const struct v4l2_file_operations cmos_ov3640_fops={
    .owner          =THIS_MODULE,
    .open           =cmos_ov3640_open,
    .release        =cmos_ov3640_close,
    .unlocked_ioctl =video_ioctl2,
    .read       =cmos_ov3640_read,

};

static const struct v4l2_ioctl_ops cmos_ov3640_ioctl_ops={
        // 表示它是一个摄像头设备
    .vidioc_querycap      = cmos_ov3640_vidioc_querycap,

        /* 用于列举、获得、测试、设置摄像头的数据的格式 */
    .vidioc_enum_fmt_vid_cap  = cmos_ov3640_vidioc_enum_fmt_vid_cap,
    .vidioc_g_fmt_vid_cap     = cmos_ov3640_vidioc_g_fmt_vid_cap,
    .vidioc_try_fmt_vid_cap   = cmos_ov3640_vidioc_try_fmt_vid_cap,
    .vidioc_s_fmt_vid_cap     = cmos_ov3640_vidioc_s_fmt_vid_cap,

        /* 缓冲区操作: 申请/查询/放入队列/取出队列 */
    .vidioc_reqbufs       = cmos_ov3640_vidioc_reqbufs,

    /*说明:因为本次是通过读的方式来获得摄像头数据,因此
     *查询/放入队列/取出队列这些函数将不需要
     */
#if 0
    .vidioc_querybuf      = cmos_ov3640_vidioc_querybuf,
    .vidioc_qbuf          = cmos_ov3640_vidioc_qbuf,
    .vidioc_dqbuf         = cmos_ov3640_vidioc_dqbuf,
#endif
    // 启动/停止
    .vidioc_streamon      = cmos_ov3640_vidioc_streamon,
    .vidioc_streamoff     = cmos_ov3640_vidioc_streamoff,   
};


/* 2.1 分配、设置一个video_device结构体 */
static struct video_device cmos_ov3640_vdev={
    .release       =cmos_ov3640_release,
    .fops      =&cmos_ov3640_fops,
    .ioctl_ops     =&cmos_ov3640_ioctl_ops,
    .name      ="cmos_ov3640",
};

static int cmos_ov3640_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret;
    printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
    /*2.3 硬件相关*/
    /*2.3.1 映射相应的寄存器*/
    /*2.3.2 设置相应的GPIO用于CAMIF(摄像头接口)*/


    /*2.2 注册*/
    //-1表示让系统自动找一个设备节点号
    ret=video_register_device(&cmos_ov3640_vdev,VFL_TYPE_GRABBER,-1);
    return 0;
}
======================
编译测试该框架是否可以。
(若没有配置,编译内核会有:
WARNING: "video_ioctl2" [/home/linux/workdir/camera/cmos_ov3640/cmos_ov3640_drv.ko] undefined!
WARNING: "__video_register_device" [/home/linux/workdir/camera/cmos_ov3640/cmos_ov3640_drv.ko] undefined!
   insmod内核的时候也会失败,符号无法识别。
)
首先:重新配置内核:make menuconfig
    Device Drivers  --->    
        <*> Multimedia support  --->  
             [*]   Cameras/video grabbers support 
             [*]   V4L platform devices  --->    
                           <*>   SoC camera support                                                                                            x x
                           <*>   platform camera support 

    编译:make uImage
    使用新内核:cp arch/arm/boot/uImage /tftpboot/uImage_3.14.29 -rf






static int cmos_ov3640_remove(struct i2c_client *client)
{
    printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);

    video_unregister_device(&cmos_ov3640_vdev);//如果没有这个,insmod的时候会发生如下的错误。

    return 0;
}

[   43.250000] /home/linux/workdir/camera/cmos_ov3640/cmos_ov3640_drv.c cmos_ov3640_probe 173
[   43.255000] ------------[ cut here ]------------
[   43.260000] WARNING: CPU: 0 PID: 1196 at drivers/media/v4l2-core/v4l2-dev.c:779 __video_register_device+0xee4/0xf74()//=========>>

                                                                            /* the v4l2_dev pointer MUST be present */
                                                                                if (WARN_ON(!vdev->v4l2_dev))
                                                                                    return -EINVAL;









[   43.270000] Modules linked in: cmos_ov3640_drv(O+) cmos_ov3640_dev(O)
[   43.275000] CPU: 0 PID: 1196 Comm: insmod Tainted: G           O 3.14.29 #4
[   43.285000] [] (unwind_backtrace) from [] (show_stack+0x10/0x14)
[   43.290000] [] (show_stack) from [] (dump_stack+0x64/0xb4)
[   43.300000] [] (dump_stack) from [] (warn_slowpath_common+0x68/0x88)
[   43.305000] [] (warn_slowpath_common) from [] (warn_slowpath_null+0x1c/0x24)
[   43.315000] [] (warn_slowpath_null) from [] (__video_register_device+0xee4/0xf74)
[   43.325000] [] (__video_register_device) from [] (cmos_ov3640_probe+0x3c/0x70 [cmos_ov3640_drv])
[   43.335000] [] (cmos_ov3640_probe [cmos_ov3640_drv]) from [] (i2c_device_probe+0xac/0xd4)
[   43.345000] [] (i2c_device_probe) from [] (driver_probe_device+0x104/0x228)
[   43.355000] [] (driver_probe_device) from [] (__driver_attach+0x8c/0x90)
[   43.365000] [] (__driver_attach) from [] (bus_for_each_dev+0x58/0x88)
[   43.370000] [] (bus_for_each_dev) from [] (bus_add_driver+0xd8/0x1cc)
[   43.380000] [] (bus_add_driver) from [] (driver_register+0x78/0xf4)
[   43.385000] [] (driver_register) from [] (i2c_register_driver+0x2c/0xb4)
[   43.395000] [] (i2c_register_driver) from [] (cmos_ov3640_drv_init+0x14/0x20 [cmos_ov3640_drv])
[   43.405000] [] (cmos_ov3640_drv_init [cmos_ov3640_drv]) from [] (do_one_initcall+0x30/0x144)
[   43.415000] [] (do_one_initcall) from [] (load_module+0x173c/0x1c68)
[   43.425000] [] (load_module) from [] (SyS_init_module+0xdc/0xe0)
[   43.430000] [] (SyS_init_module) from [] (ret_fast_syscall+0x0/0x30)
[   43.440000] ---[ end trace 3b8e306fb947a72a ]---
[   43.445000] video_register_device error!
[   43.450000] cmos_ov3640: probe of 0-003c failed with error -1


e:\fs4412\linux-3.14.29_c\drivers\media\v4l2-core\V4l2-dev.c
933 if (vdev->v4l2_dev)
934     v4l2_device_get(vdev->v4l2_dev);//出错处
            ||
           /**增加引用计数
            * kref_get - increment refcount for object.
            * @kref: object.
            */
        static inline void kref_get(struct kref *kref)
        {
            /* If refcount(重新计算) was 0 before incrementing(增量的) 
             * then we have a race(比赛)
             * condition(条件、情况) when this kref is freeing by 
             * some other thread right now.
             * In this case one should use kref_get_unless_zero()
             */
            WARN_ON_ONCE(atomic_inc_return(&kref->refcount) < 2); //这里出错.??????????
        }

你可能感兴趣的:(嵌入式)