摄像头(Ov965x)驱动分析

本人喜欢用代码+伪代码的方式写笔记。文中的花括号可能是方便记录而已。

如:

hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
{
    问:怎么获得模块信息的?
    答:hardware\libhardware\Hardware.c

    ...........

}

原创分析, 转载请注明出处:http://www.cnblogs.com/langlang/

作者email: dayhappyhappy@163.com

module_init(s3c_fimc_register)
    platform_driver_register(&s3c_fimc_driver)  //.name    = "s3c-fimc",
    {
        //1  控制器
        s3c_fimc_register_controller(pdev)
        {
            struct s3c_fimc_control *ctrl;
            ctrl->vd = &s3c_fimc_video_device[id];    //s3c_fimc_video_device中包含了操作函数
               s3c_fimc_video_device[id]
                {
                    .fops = &s3c_fimc_fops,//fops对应的是针对v4l2设备的基本操作
                        {
                            .read = s3c_fimc_read
                            {
                                struct s3c_fimc_control *ctrl = filp->private_data;
                                end = min_t(size_t, ctrl->out_frame.buf_size, count);
                                copy_to_user(buf, s3c_fimc_get_current_frame(ctrl), end)
                                 {           
                                    struct s3c_fimc_out_frame *frame = &ctrl->out_frame;
                                    return frame->addr[frame->cfn].virt_y;
                                }
                            }
                            .open = s3c_fimc_open
                            {
                                struct s3c_fimc_control *ctrl;
                                ctrl = &s3c_fimc.ctrl[id];
                                s3c_fimc_reset(ctrl); //底层寄存器操作
                                filp->private_data = ctrl;
                            }
                        }
                    .ioctl_ops = &s3c_fimc_v4l2_ops,//是对v4l2的所有ioctl操作集合的描述
               }
        }
        /*2  时钟设置 fimc source clock */
        //3  DMA初始化
        s3c_fimc_init_global(pdev)
        {
            //DMA设置
            s3c_fimc.dma_start = s3c_get_media_memory(S3C_MDEV_FIMC);
            s3c_fimc.dma_total = s3c_get_media_memsize(S3C_MDEV_FIMC);
            s3c_fimc.dma_current = s3c_fimc.dma_start;
            /* test pattern */
            s3c_fimc.camera[test_pattern.id] = &test_pattern; 
            {
                问:  这个参数在什么时候用到?
                s3c_fimc_register_camera(struct s3c_fimc_camera *cam)  ① s3c_fimc_register_camera给谁调用
                {
                    for (i = 0; i < S3C_FIMC_MAX_CTRLS; i++)  
                        s3c_fimc.ctrl[i].in_cam = s3c_fimc.camera[cam->id];
                }
                s3c_fimc_set_active_camera(struct s3c_fimc_control *ctrl, int id)
                {
                    ctrl->in_cam = s3c_fimc.camera[id];
                    s3c_fimc_select_camera(ctrl);
                }
            }
        }
        //4  创建文件节点  /dev下看到三个video设备节点,video0,video1,video2
        video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id)
        {
            INIT_LIST_HEAD(&vdev->fh_list);
            /* Part 1: check device type */
            /* Part 2: find a free minor, device node number and device index. */    
            /* Part 3: Initialize the character device 创建字符设备*/  
            vdev->cdev = cdev_alloc();
            vdev->cdev->ops = &v4l2_fops;
            cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
            
            /* Part 4: register the device with sysfs */
            vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
            vdev->dev.class = &video_class;//创建类
            device_register(&vdev->dev);
            video_device[vdev->minor] = vdev;
        }
    }
    
① 文件 drivers\media\video\samsung\fimc\Ov965x.c  也就是我们要写的文件
ov965x_probe(struct i2c_client *c, const struct i2c_device_id *id)
{
    s3c_fimc_register_camera(&ov965x_data)
    {
        参数:这里面的信息描述了OV9650相关的所有信息。
        static struct s3c_fimc_camera ov965x_data = {
            .id         = CONFIG_VIDEO_FIMC_CAM_CH,
            .type        = CAM_TYPE_ITU,             //type代表摄像头是ITU的接口
            .mode        = ITU_601_YCBCR422_8BIT,    //mode代表摄像头输出的格式是ITU_601_YCBCR422_8BIT
            .order422    = CAM_ORDER422_8BIT_YCBYCR, //order422代表YUV三个分量的顺序是YCRYCB,
            .clockrate    = 24000000,                    //时钟源的信息
            .width        = 640,//800,
            .height        = 480,//600,
            .offset        = {
                .h1 = 0,
                .h2 = 0,
                .v1 = 0,
                .v2 = 0,
            },
        
            .polarity    = { //Polarity代表信号的极性,具体的设置要和摄像头本身的设置一致
                .pclk    = 0,
                .vsync    = 1,
                .href    = 0,
                .hsync    = 0,
            },
        
            .initialized    = 0,
        }
    }
}
 Ov965x.c分析
 __init int ov965x_init(void)
 {
    //添加驱动
    i2c_add_driver(&ov965x_i2c_driver)  
    {
        ov965x_i2c_driver =  {.probe        = ov965x_probe}
        ov965x_probe(struct i2c_client *c, const struct i2c_device_id *id){
            s3c_fimc_register_camera(&ov965x_data);
            for (i = 0; i < OV965X_INIT_REGS; i++) //用IIC发送数据
                ret = i2c_smbus_write_byte_data(c, OV965X_init_reg[i].subaddr, OV965X_init_reg[i].value);
        }
    }
 } 
原文地址:https://www.cnblogs.com/langlang/p/2454271.html