摄像头(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);
}
}
}
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);
}
}
}