Chinaunix首页 | 论坛 | 博客
  • 博客访问: 431516
  • 博文数量: 125
  • 博客积分: 2066
  • 博客等级: 大尉
  • 技术积分: 1032
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-16 14:06
文章分类

全部博文(125)

文章存档

2011年(125)

分类: LINUX

2011-04-28 10:31:46

原文链接http://tassardge.blog.163.com/blog/static/172301708201075600339/(一)v4l2 camera 驱动架构 之 isp controller 驱动

linux kernel 2010-08-05 18:00:00 阅读177 评论0  字号: 订阅

 这个链接指向源代码  这个链接指向标准文档,文档中包含sample code,这份文档的标题是"Video for Linux Two API Specification",如果链接失效可以用这个标题 google 重新搜索。

isp camera 驱动分为 sensor 驱动和 isp controller 驱动两部分,sensor 驱动就是摄像头芯片的驱动,isp controller 驱动实现的是 v4l2 驱动架构中 soc_camera_host 接口,主要负责 isp dma 的管理和一些 v4l2 的标准操作。

1. soc_camera_host结构:
isp controller 驱动是一个普通的 platform 驱动。在 probe 函数中最重要的操作是通过调用soc_camera_host_register 注册一个 struct soc_camera_host。soc_camera_host 有5个字段需要填充:
1) .drv_name :名称。
2) .ops :操作函数族。
3) .priv :指向驱动私有数据,将被作为参数传给上面 ops 接口中的操作函数。
4) .v4l2_dev.dev :指向这个 platform 驱动的 dev。
5) .nr :the soc_host.nr should be equal to bus_id in soc_camera_link, otherwise the driver will fail to load.

2. soc_camera_host_ops结构:
这个结构是这个驱动的核心,实现了一些v4l2的标准操作。

static struct soc_camera_host_ops map100_soc_camera_host_ops = {
 .owner = THIS_MODULE,

// add 会在 open 时调用。主要作用是 powerup isp controller。另外,probe
//的时候也会调这个函数,因为 probe 的主要操作是初始化 sensor 驱动,
//而这需要先 power up isp controller。
 .add = map100_camera_add_device,

//remove 会在 close 时调用。主要作用是 power down isp controller。
//另外,probe 初始化 sensor 结束之后也会调用。
 .remove = map100_camera_remove_device,

 .set_bus_param = map100_camera_set_bus_param,

//剪裁相关的一个接口
 .set_crop = map100_camera_set_crop,

//设置格式
 .set_fmt = map100_camera_set_fmt,

//VIDIOC_TRY_FMT的实现
 .try_fmt = map100_camera_try_fmt,

//初始化isp dma,会在open的时候调用
 .init_videobuf = map100_camera_init_videobuf,

//这个接口本身不会分配dma内存,只是对dma buffer做初始化
//VIDIOC_REQBUFS的实现
 .reqbufs = map100_camera_reqbufs,

//select系统调用的实现
 .poll = map100_camera_poll,

//设备支持的特性,VIDIOC_QUERYCAP的实现
 .querycap = map100_camera_querycap,
};

这个结构体中的接口具体实现参见代码。

3. videobuf_queue_ops 结构:
这个结构用来管理dma buffer。

static struct videobuf_queue_ops map100_videobuf_ops = {
 //设置 dma buffer 的 size 和最大个数,但是不分配 dma buffer
 //dma buffer 是在用户调用 VIDIOC_REQBUFS 操作码时分配的
 .buf_setup = map100_videobuf_setup,

 //检查 map100_buffer 包含的物理内存和映射到用户空间的内
 //存是否有效
 .buf_prepare = map100_videobuf_prepare,

 //just push the buffer into queue
 .buf_queue = map100_videobuf_queue,

 .buf_release = map100_videobuf_release,
};

各个接口的实现参见代码中的实现。

注意:
1) 所有的 videobuf_queue_ops 操作都是有锁保护的,这个锁就是 videobuf_queue_dma_contig_init 初始化时传入的。一般来说,传给 videobuf_queue_dma_contig_init 的锁用来同步中断处理函数与videobuf_queue_ops 函数族
2) " dma 请求队列"的实现:
a. 在 buf_queue  中把用户的请求向" dma 请求队列"入队;
b. 在中断处理函数中把填充完成的请求从" dma 请求队列"出队;
c. 中断处理函数的实现:
首先,如果一个请求已经填充完毕,则唤醒等待在该请求上的进程,然后将这个请求从从" dma 请求队列"出队;
其次,处理" dma 请求队列"中的下一个请求。也就是修改 isp 的 dma 地址使其指向这个请求对应的物理地址,然后重新打开中断(就是清中断寄存器)。

对于 isp camera ,之所以用队列管理用户的请求是为了获得更好的性能。应用程序向队列入队请求,中断处理程序则填充队列中的请求,这样可以更好的实现并发,否则只有一个buffer的话中断处理程序和应用程序就需要互相等待这样就会导致效率低下。

关于修改dma地址,有一点要注意,收到中断后,清中断寄存器之前可以修改dma地址,但是清中断之后不能修改dma地址,否则会阻塞。 (不知道为什么会这样)

3) 对于自定义的 dma buffer 结构体,videobuf_buffer 必须是第一个结构体成员。

4. dma 的初始化和分配:
1)open 的时候通过 init_videobuf 初始化 dma;
2)用户执行 VIDIOC_REQBUFS 操作码时会真正分配 dma 内存,之后会调用 reqbufs。

阅读(5471) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~