4-1: FIMC驱动的总体结构分析
FIMC的驱动在内核中的位置:
drivers/media/video/samsung/fimc
fimc40_regs.c
fimc43_regs.c
fimc_capture.c
fimc_dev.c
fimc_output.c
fimc_overlay.c
fimc_v4l2.c
这些源码里面最基础的是fimc_dev.c,这里面注册了一个platform_driver,在相应的平台代码里面有对应的platform_device的描述。这种SOC上的控制器一般都会挂接在platform_bus上以实现在系统初始化时的device和driver的匹配。
在driver的probe函数里面,主要完成了资源获取以及v4l2设备的注册。因为FIMC一共有三套一样的控制器(fimc0, fimc1, fimc2),所以驱动里使用了一个数组来描述:
struct video_device fimc_video_device[FIMC_DEVICES] = {
[0] = {
.fops = &fimc_fops,
.ioctl_ops = &fimc_v4l2_ops,
.release = fimc_vdev_release,
},
[1] = {
.fops = &fimc_fops,
.ioctl_ops = &fimc_v4l2_ops,
.release = fimc_vdev_release,
},
[2] = {
.fops = &fimc_fops,
.ioctl_ops = &fimc_v4l2_ops,
.release = fimc_vdev_release,
},
};
在probe函数里,调用video_register_device()来注册这三个video_device,在用户空间里就会在/dev下看到三个video设备节点,video0,video1,video2. 每个video_device的成员fops对应的是针对v4l2设备的基本操作,定义如下:
static const struct v4l2_file_operations fimc_fops = {
.owner = THIS_MODULE,
.open = fimc_open,
.release = fimc_release,
.ioctl = video_ioctl2,
.read = fimc_read,
.write = fimc_write,
.mmap = fimc_mmap,
.poll = fimc_poll,
};
另一个成员ioctl_ops非常重要,因为它是对v4l2的所有ioctl操作集合的描述。fimc_v4l2_ops定义在fimc_v4l2.c里面:
const struct v4l2_ioctl_ops fimc_v4l2_ops = {
.vidioc_querycap = fimc_querycap,
.vidioc_reqbufs = fimc_reqbufs,
.vidioc_querybuf = fimc_querybuf,
.vidioc_g_ctrl = fimc_g_ctrl,
.vidioc_s_ctrl = fimc_s_ctrl,
.vidioc_cropcap = fimc_cropcap,
.vidioc_g_crop = fimc_g_crop,
.vidioc_s_crop = fimc_s_crop,
.vidioc_streamon = fimc_streamon,
.vidioc_streamoff = fimc_streamoff,
.vidioc_qbuf = fimc_qbuf,
.vidioc_dqbuf = fimc_dqbuf,
.vidioc_enum_fmt_vid_cap = fimc_enum_fmt_vid_capture,
.vidioc_g_fmt_vid_cap = fimc_g_fmt_vid_capture,
.vidioc_s_fmt_vid_cap = fimc_s_fmt_vid_capture,
.vidioc_try_fmt_vid_cap = fimc_try_fmt_vid_capture,
.vidioc_enum_input = fimc_enum_input,
.vidioc_g_input = fimc_g_input,
.vidioc_s_input = fimc_s_input,
.vidioc_g_parm = fimc_g_parm,
.vidioc_s_parm = fimc_s_parm,
.vidioc_g_fmt_vid_out = fimc_g_fmt_vid_out,
.vidioc_s_fmt_vid_out = fimc_s_fmt_vid_out,
.vidioc_try_fmt_vid_out = fimc_try_fmt_vid_out,
.vidioc_g_fbuf = fimc_g_fbuf,
.vidioc_s_fbuf = fimc_s_fbuf,
.vidioc_try_fmt_vid_overlay = fimc_try_fmt_overlay,
.vidioc_g_fmt_vid_overlay = fimc_g_fmt_vid_overlay,
.vidioc_s_fmt_vid_overlay = fimc_s_fmt_vid_overlay,
};
可以看到,FIMC的驱动实现了v4l2所有的接口,可以分为v4l2-input设备接口,v4l2-output设备接口以及v4l2-overlay设备接口。这里我们主要关注v4l2-input设备接口,因为摄像头属于视频输入设备。
fimc_v4l2.c里面注册了很多的回调函数,都是用于实现v4l2的标准接口的,但是这些回调函数基本上都不是在fimc_v4l2.c里面实现的,而是有相应的.c分别去实现。比如:
v4l2-input设备的操作实现: fimc_capture.c
v4l2-output设备的操作实现: fimc_output.c
v4l2-overlay设备的操作实现: fimc_overlay.c
这些代码其实都是和具体硬件操作无关的,这个驱动把所有操作硬件寄存器的代码都写到一个文件里面了,就是fimc40_regs.c。这样把硬件相关的代码和硬件无关的代码分开来实现是非常好的方式,可以最大限度的实现代码复用。
这些驱动源码的组织关系如下: