【高通SDM660平台】Camera V4L2 驱动层分析
《【高通SDM660平台】(1) — Camera 驱动 Bringup Guide》
《【高通SDM660平台】(2) — Camera Kernel 驱动层代码逻辑分析》
《【高通SDM660平台】(3) — Camera V4L2 驱动层分析 》
《【高通SDM660平台】(4) — Camera Init 初始化流程 》
《【高通SDM660平台】(5) — Camera Open 流程》
《【高通SDM660平台】(6) — Camera getParameters 及 setParameters 流程》
《【高通SDM660平台】(7) — Camera onPreview 代码流程》
《【高通SDM660平台】(8) — Camera MetaData介绍》
《【高通SDM660平台 Android 10.0】(9) — Qcom Camera Daemon 代码分析》
《【高通SDM660平台 Android 10.0】(10) — Camera Sensor lib 与 Kernel Camera Probe 代码分析》
《【高通SDM660平台】Camera Capture 流程》
《【高通SDM660平台】Camera mm-qcamera-app 代码分析》
一、Camera V4L2 驱动层分析
Linux系统中视频输入设备主要包括以下四个部分:
- 字符设备驱动:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间;
- V4L2驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数;
- 平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关的V4L2驱动部分,包括注册video_device和v4l2_dev;
- 具体的sensor驱动:主要上电、提供工作时钟、视频图像裁剪、流IO开启等,实现各种设备控制方法供上层调用并注册v4l2_subdev。
V4L2核心源码位于drivers/media/v4l2-core
,根据功能可以划分为四类:
- 字符设备模块:由
v4l2-dev.c
实现,主要作用申请字符主设备号、注册class和提供video device注册注销等相关函数。 - V4L2基础框架:由
v4l2-device.c、v4l2-subdev.c、v4l2-fh.c、v4l2-ctrls.c
等文件构建V4L2基础框架。 - videobuf管理
由videobuf2-core.c、videobuf2-dma-contig.c、videobuf2-dma-sg.c、videobuf2-memops.c、videobuf2-vmalloc.c、v4l2-mem2mem.c
等文件实现,完成videobuffer的分配、管理和注销。 - Ioctl框架:由
v4l2-ioctl.c
文件实现,构建V4L2ioctl的框架。
二、V4L2基础框架
2.1 /media/v4l2-core/v4l2-dev.c
在该文件中,主要是负责创建/sys/classs/video4linux
目录 ,当有设备注册进来时,创建对应的 /dev/videox 、/dev/vbix、/dev/radiox、/dev/subdevx
等节点。
主要工作如下:
- 将字符设备号
(81,0)
到(81,255)
这期间256个字次设备号,均申请为 v4l2 使用,name=video4linux
- 注册
/sys/classs/video4linux
目录
@ kernel/msm-4.4/drivers/media/v4l2-core/v4l2-dev.c
static struct class video_class = {
.name = VIDEO_NAME, // video4linux
.dev_groups = video_device_groups,
};
static int __init videodev_init(void)
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0); // VIDEO_MAJOR: 81
printk(KERN_INFO “Linux video capture interface: v2.00\n”);
<span class="token comment">// 1. 将字符设备号(81,0) 到 (81,255) 这期间256个字次设备号,均申请为 v4l2 使用,name=video4linux</span>
ret <span class="token operator">=</span> <span class="token function">register_chrdev_region</span><span class="token punctuation">(</span>dev<span class="token punctuation">,</span> VIDEO_NUM_DEVICES<span class="token punctuation">,</span> VIDEO_NAME<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//VIDEO_NUM_DEVICES: 256 VIDEO_NAME:"video4linux"</span>
<span class="token operator">==</span><span class="token operator">==</span><span class="token operator">==</span><span class="token operator">></span> <span class="token keyword">int</span> <span class="token function">register_chrdev_region</span><span class="token punctuation">(</span>dev_t from<span class="token punctuation">,</span> <span class="token keyword">unsigned</span> count<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>name<span class="token punctuation">)</span>
<span class="token comment">// 2. 注册 /sys/classs/video4linux 目录</span>
ret <span class="token operator">=</span> <span class="token function">class_register</span><span class="token punctuation">(</span><span class="token operator">&</span>video_class<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
2.2 注册V4L2设备 __video_register_device()
当用设备需要注册为 v4l2 subdev 时,会调用video_register_device()
函数进行注册:
例如如下, compatible = "qcom,msm-cam";
注册为一个V4L2 subdev
,代码如下:
@\kernel\msm-4.4\drivers\media\platform\msm\camera_v2\msm.c // 2. 分配 video_device 结构体内存 pvdev->vdev = video_device_alloc();
pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>entity<span class="token punctuation">.</span>type <span class="token operator">=</span> MEDIA_ENT_T_DEVNODE_V4L<span class="token punctuation">;</span> <span class="token comment">// V4L</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>entity<span class="token punctuation">.</span>group_id <span class="token operator">=</span> QCAMERA_VNODE_GROUP_ID<span class="token punctuation">;</span> <span class="token comment">// #define QCAMERA_VNODE_GROUP_ID 2</span> msm_v4l2_dev<span class="token operator">-></span>notify <span class="token operator">=</span> msm_sd_notify<span class="token punctuation">;</span> <span class="token comment">// 用于发现对应的 subdev</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>v4l2_dev <span class="token operator">=</span> msm_v4l2_dev<span class="token punctuation">;</span> <span class="token comment">// 5. 设置父设备为 pdev->dev (也就是 qcom,msm-cam 的设备信息)dev->driver->name=msm-config, dev_name=qcom,msm-camera</span> rc <span class="token operator">=</span> <span class="token function">v4l2_device_register</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>pdev<span class="token operator">-></span>dev<span class="token punctuation">)</span><span class="token punctuation">,</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>v4l2_dev<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">==</span><span class="token operator">==</span><span class="token operator">></span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>v4l2_dev<span class="token operator">-></span>dev <span class="token operator">=</span> pdev<span class="token operator">-></span>dev<span class="token punctuation">;</span> <span class="token function">snprintf</span><span class="token punctuation">(</span>v4l2_dev<span class="token operator">-></span>name<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>v4l2_dev<span class="token operator">-></span>name<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"%s %s"</span><span class="token punctuation">,</span> dev<span class="token operator">-></span>driver<span class="token operator">-></span>name<span class="token punctuation">,</span> <span class="token function">dev_name</span><span class="token punctuation">(</span>dev<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 6. 注册 video_device设备 </span> <span class="token function">strlcpy</span><span class="token punctuation">(</span>pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>name<span class="token punctuation">,</span> <span class="token string">"msm-config"</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>release <span class="token operator">=</span> video_device_release<span class="token punctuation">;</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>fops <span class="token operator">=</span> <span class="token operator">&</span>msm_fops<span class="token punctuation">;</span> <span class="token comment">// 配置 video_device 的字符设备操作函数</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>ioctl_ops <span class="token operator">=</span> <span class="token operator">&</span>g_msm_ioctl_ops<span class="token punctuation">;</span> <span class="token comment">// 配置 v4l2 IOCTRL</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>minor <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> pvdev<span class="token operator">-></span>vdev<span class="token operator">-></span>vfl_type <span class="token operator">=</span> VFL_TYPE_GRABBER<span class="token punctuation">;</span> rc <span class="token operator">=</span> <span class="token function">video_register_device</span><span class="token punctuation">(</span>pvdev<span class="token operator">-></span>vdev<span class="token punctuation">,</span> VFL_TYPE_GRABBER<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
此时调用 video_register_device()
函数,也就是调用 __video_register_device()
2.3 __video_register_device()
以"qcom,msm-cam"
为例,其注册时,传递的 nr = -1,说明从第一个开始分配,也就是 /dev/video0
。
因此 /dev/video0
对应的设备为"qcom,msm-cam"
,其设备类型为 video
。
主要工作如下:
- 初始化 fh->list
- 检查设备类型
- 寻找一个不在使用的 次设备号, 主设备号为 81,
(0~63 为video)(128,191 为sub-dev)
- 获取 index,将当前需要注册的 video_device 设备保存在 video_device[]全局数组中
- 分配对应的字符设备,字符设备号,就是前面的
(81,minor)
- 分配对应的sys节点 /sys/class/video4linux/video0
- 注册release 时调用的函数
- 将该 v4l2 subdevice 当成一个 entity 注册到 media device
- 注册release 时调用的函数
@ kernel/msm-4.4/drivers/media/v4l2-core/v4l2-dev.c /** * __video_register_device - register video4linux devices * @vdev: video device structure we want to register * @type: type of device to register * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... -1 == first free) * @warn_if_nr_in_use: warn if the desired device node number was already in use and another number was chosen instead. * @owner: module that owns the video device node * * The registration code assigns minor numbers and device node numbersbased on the requested type and registers the new device node with the kernel. * * This function assumes that struct video_device was zeroed when it was allocated and does not contain any stale date. * * An error is returned if no free minor or device node number could be found, or if the registration of the device node failed. * * Zero is returned on success. * * Valid types are * %VFL_TYPE_GRABBER - A frame grabber * %VFL_TYPE_VBI - Vertical blank data (undecoded) * %VFL_TYPE_RADIO - A radio card * %VFL_TYPE_SUBDEV - A subdevice * %VFL_TYPE_SDR - Software Defined Radio */ int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use, struct module *owner) { int minor_cnt = VIDEO_NUM_DEVICES; const char *name_base;
<span class="token comment">/* A minor value of -1 marks this video device as never having been registered */</span> vdev<span class="token operator">-></span>minor <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">// 1. 初始化 fh->list</span> <span class="token comment">/* v4l2_fh support */</span> <span class="token function">INIT_LIST_HEAD</span><span class="token punctuation">(</span><span class="token operator">&</span>vdev<span class="token operator">-></span>fh_list<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2. 检查设备类型</span> <span class="token comment">/* Part 1: check device type */</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> VFL_TYPE_GRABBER<span class="token punctuation">:</span> name_base <span class="token operator">=</span> <span class="token string">"video"</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> VFL_TYPE_VBI<span class="token punctuation">:</span> name_base <span class="token operator">=</span> <span class="token string">"vbi"</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> VFL_TYPE_RADIO<span class="token punctuation">:</span> name_base <span class="token operator">=</span> <span class="token string">"radio"</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> VFL_TYPE_SUBDEV<span class="token punctuation">:</span> name_base <span class="token operator">=</span> <span class="token string">"v4l-subdev"</span><span class="token punctuation">;</span><span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> VFL_TYPE_SDR<span class="token punctuation">:</span> name_base <span class="token operator">=</span> <span class="token string">"swradio"</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token comment">/* Use device name 'swradio' because 'sdr' was already taken. */</span> <span class="token punctuation">}</span> vdev<span class="token operator">-></span>vfl_type <span class="token operator">=</span> type<span class="token punctuation">;</span> <span class="token comment">// VFL_TYPE_GRABBER</span> vdev<span class="token operator">-></span>cdev <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span> <span class="token comment">// 3. 寻找一个不在使用的 次设备号, 主设备号为 81,(0~63 为video)(128,191 为sub-dev)</span> <span class="token comment">/* Part 2: find a free minor, device node number and device index. */</span> <span class="token comment">/* Keep the ranges for the first four types for historical reasons. * Newer devices (not yet in place) should use the range of 128-191 and just pick the first free minor there (new style). */</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> VFL_TYPE_GRABBER<span class="token punctuation">:</span> minor_offset <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> minor_cnt <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> VFL_TYPE_RADIO<span class="token punctuation">:</span> minor_offset <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">;</span> minor_cnt <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> VFL_TYPE_VBI<span class="token punctuation">:</span> minor_offset <span class="token operator">=</span> <span class="token number">224</span><span class="token punctuation">;</span> minor_cnt <span class="token operator">=</span> <span class="token number">32</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">default</span><span class="token punctuation">:</span> minor_offset <span class="token operator">=</span> <span class="token number">128</span><span class="token punctuation">;</span> minor_cnt <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* Pick a device node number */</span> nr <span class="token operator">=</span> <span class="token function">devnode_find</span><span class="token punctuation">(</span>vdev<span class="token punctuation">,</span> nr <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> nr<span class="token punctuation">,</span> minor_cnt<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>nr <span class="token operator">==</span> minor_cnt<span class="token punctuation">)</span> nr <span class="token operator">=</span> <span class="token function">devnode_find</span><span class="token punctuation">(</span>vdev<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> minor_cnt<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* The device node number and minor numbers are independent, so we just find the first free minor number. */</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> VIDEO_NUM_DEVICES<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>video_device<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token keyword">break</span><span class="token punctuation">;</span> vdev<span class="token operator">-></span>minor <span class="token operator">=</span> i <span class="token operator">+</span> minor_offset<span class="token punctuation">;</span> vdev<span class="token operator">-></span>num <span class="token operator">=</span> nr<span class="token punctuation">;</span> <span class="token function">devnode_set</span><span class="token punctuation">(</span>vdev<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 4. 获取 index,将当前需要注册的 video_device 设备保存在 video_device[]全局数组中</span> vdev<span class="token operator">-></span>index <span class="token operator">=</span> <span class="token function">get_index</span><span class="token punctuation">(</span>vdev<span class="token punctuation">)</span><span class="token punctuation">;</span> video_device<span class="token punctuation">[</span>vdev<span class="token operator">-></span>minor<span class="token punctuation">]</span> <span class="token operator">=</span> vdev<span class="token punctuation">;</span> <span class="token comment">// 5. 分配对应的字符设备 /dev/video0,字符设备号,就是前面的 (81,minor)</span> <span class="token comment">/* Part 3: Initialize the character device */</span> vdev<span class="token operator">-></span>cdev <span class="token operator">=</span> <span class="token function">cdev_alloc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> vdev<span class="token operator">-></span>cdev<span class="token operator">-></span>ops <span class="token operator">=</span> <span class="token operator">&</span>v4l2_fops<span class="token punctuation">;</span> vdev<span class="token operator">-></span>cdev<span class="token operator">-></span>owner <span class="token operator">=</span> owner<span class="token punctuation">;</span> ret <span class="token operator">=</span> <span class="token function">cdev_add</span><span class="token punctuation">(</span>vdev<span class="token operator">-></span>cdev<span class="token punctuation">,</span> <span class="token function">MKDEV</span><span class="token punctuation">(</span>VIDEO_MAJOR<span class="token punctuation">,</span> vdev<span class="token operator">-></span>minor<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 6. 分配对应的sys节点 /sys/class/video4linux/video0</span> <span class="token comment">/* Part 4: register the device with sysfs */</span> vdev<span class="token operator">-></span>dev<span class="token punctuation">.</span>class <span class="token operator">=</span> <span class="token operator">&</span>video_class<span class="token punctuation">;</span> vdev<span class="token operator">-></span>dev<span class="token punctuation">.</span>devt <span class="token operator">=</span> <span class="token function">MKDEV</span><span class="token punctuation">(</span>VIDEO_MAJOR<span class="token punctuation">,</span> vdev<span class="token operator">-></span>minor<span class="token punctuation">)</span><span class="token punctuation">;</span> vdev<span class="token operator">-></span>dev<span class="token punctuation">.</span>parent <span class="token operator">=</span> vdev<span class="token operator">-></span>dev_parent<span class="token punctuation">;</span> <span class="token function">dev_set_name</span><span class="token punctuation">(</span><span class="token operator">&</span>vdev<span class="token operator">-></span>dev<span class="token punctuation">,</span> <span class="token string">"%s%d"</span><span class="token punctuation">,</span> name_base<span class="token punctuation">,</span> vdev<span class="token operator">-></span>num<span class="token punctuation">)</span><span class="token punctuation">;</span> ret <span class="token operator">=</span> <span class="token function">device_register</span><span class="token punctuation">(</span><span class="token operator">&</span>vdev<span class="token operator">-></span>dev<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 7. 注册release 时调用的函数</span> <span class="token comment">/* Register the release callback that will be called when the last reference to the device goes away. */</span> vdev<span class="token operator">-></span>dev<span class="token punctuation">.</span>release <span class="token operator">=</span> v4l2_device_release<span class="token punctuation">;</span> <span class="token comment">/* Increase v4l2_device refcount */</span> <span class="token function">v4l2_device_get</span><span class="token punctuation">(</span>vdev<span class="token operator">-></span>v4l2_dev<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 8. 将该 v4l2 subdevice 当成一个 entity 注册到 media device</span> <span class="token comment">/* Part 5: Register the entity. */</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>vdev<span class="token operator">-></span>v4l2_dev<span class="token operator">-></span>mdev <span class="token operator">&&</span> vdev<span class="token operator">-></span>vfl_type <span class="token operator">!=</span> VFL_TYPE_SUBDEV<span class="token punctuation">)</span> <span class="token punctuation">{</span> vdev<span class="token operator">-></span>entity<span class="token punctuation">.</span>type <span class="token operator">=</span> MEDIA_ENT_T_DEVNODE_V4L<span class="token punctuation">;</span> vdev<span class="token operator">-></span>entity<span class="token punctuation">.</span>name <span class="token operator">=</span> vdev<span class="token operator">-></span>name<span class="token punctuation">;</span> vdev<span class="token operator">-></span>entity<span class="token punctuation">.</span>info<span class="token punctuation">.</span>dev<span class="token punctuation">.</span>major <span class="token operator">=</span> VIDEO_MAJOR<span class="token punctuation">;</span> vdev<span class="token operator">-></span>entity<span class="token punctuation">.</span>info<span class="token punctuation">.</span>dev<span class="token punctuation">.</span>minor <span class="token operator">=</span> vdev<span class="token operator">-></span>minor<span class="token punctuation">;</span> ret <span class="token operator">=</span> <span class="token function">media_device_register_entity</span><span class="token punctuation">(</span>vdev<span class="token operator">-></span>v4l2_dev<span class="token operator">-></span>mdev<span class="token punctuation">,</span><span class="token operator">&</span>vdev<span class="token operator">-></span>entity<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* Part 6: Activate this minor. The char device can now be used. */</span> <span class="token function">set_bit</span><span class="token punctuation">(</span>V4L2_FL_REGISTERED<span class="token punctuation">,</span> <span class="token operator">&</span>vdev<span class="token operator">-></span>flags<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
EXPORT_SYMBOL(__video_register_device);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
2.3.1 字符设备操作函数 v4l2_fops
static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
.release = v4l2_release,
.poll = v4l2_poll,
.llseek = no_llseek,
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
创建成功 /dev/video0 节点后,后续要打开对应的节点时,会调用 fops对应的操作函数,对应的代码在注册时赋值的。
pvdev->vdev->release = video_device_release;
pvdev->vdev->fops = &msm_fops; // 配置 video_device 的字符设备操作函数
pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops; // 配置 v4l2 IOCTRL
- 1
- 2
- 3
2.3.1.1 video ioctl函数 do_video_ioctl()
当操作/dev/video0
节点时,下发ioctl 会转到 do_video_ioctl()
中,
如下:
@ kernel/msm-4.4/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
ret = do_video_ioctl(file, cmd, arg);
else if (vdev->fops->compat_ioctl32)
ret = vdev->fops->compat_ioctl32(file, cmd, arg);
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
do_video_ioctl()
函数实现如下:
@ kernel/msm-4.4/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
static long do_video_ioctl(struct file file, unsigned int cmd, unsigned long arg)
{
union {
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
struct v4l2_input v2i;
struct v4l2_standard v2s;
struct v4l2_ext_controls v2ecs;
struct v4l2_event v2ev;
struct v4l2_create_buffers v2crt;
struct v4l2_edid v2edid;
unsigned long vx;
int vi;
} karg;
void __user up = compat_ptr(arg);
int compatible_arg = 1;
long err = 0;
<span class="token function">memset</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>karg<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* First, convert the command. */</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>cmd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> VIDIOC_G_FMT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_G_FMT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_S_FMT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_S_FMT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_QUERYBUF32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_QUERYBUF<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_FBUF32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_G_FBUF<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_S_FBUF32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_S_FBUF<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_QBUF32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_QBUF<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_DQBUF32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_DQBUF<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_ENUMSTD32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_ENUMSTD<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_ENUMINPUT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_ENUMINPUT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_TRY_FMT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_TRY_FMT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_EXT_CTRLS32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_G_EXT_CTRLS<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_S_EXT_CTRLS32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_S_EXT_CTRLS<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_TRY_EXT_CTRLS32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_TRY_EXT_CTRLS<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_DQEVENT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_DQEVENT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_OVERLAY32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_OVERLAY<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_STREAMON32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_STREAMON<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_STREAMOFF32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_STREAMOFF<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_INPUT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_G_INPUT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_S_INPUT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_S_INPUT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_OUTPUT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_G_OUTPUT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_S_OUTPUT32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_S_OUTPUT<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_CREATE_BUFS32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_CREATE_BUFS<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_PREPARE_BUF32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_PREPARE_BUF<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_EDID32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_G_EDID<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_S_EDID32<span class="token punctuation">:</span> cmd <span class="token operator">=</span> VIDIOC_S_EDID<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>cmd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> VIDIOC_OVERLAY<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_STREAMON<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_STREAMOFF<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_INPUT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_OUTPUT<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_user</span><span class="token punctuation">(</span>karg<span class="token punctuation">.</span>vi<span class="token punctuation">,</span> <span class="token punctuation">(</span>s32 __user <span class="token operator">*</span><span class="token punctuation">)</span>up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_INPUT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_G_OUTPUT<span class="token punctuation">:</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_EDID<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_EDID<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_edid32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2edid<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_FMT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_FMT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_TRY_FMT<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_format32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2f<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_CREATE_BUFS<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_create32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2crt<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_PREPARE_BUF<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_QUERYBUF<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_QBUF<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_DQBUF<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_buffer32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2b<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_S_FBUF<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_framebuffer32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2fb<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_FBUF<span class="token punctuation">:</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_ENUMSTD<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_standard32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2s<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_ENUMINPUT<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_input32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2i<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_EXT_CTRLS<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_EXT_CTRLS<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_TRY_EXT_CTRLS<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">get_v4l2_ext_controls32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2ecs<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_DQEVENT<span class="token punctuation">:</span>
compatible_arg <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>compatible_arg<span class="token punctuation">)</span>
err <span class="token operator">=</span> <span class="token function">native_ioctl</span><span class="token punctuation">(</span>file<span class="token punctuation">,</span> cmd<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">long</span><span class="token punctuation">)</span>up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">else</span> <span class="token punctuation">{</span>
mm_segment_t old_fs <span class="token operator">=</span> <span class="token function">get_fs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">set_fs</span><span class="token punctuation">(</span>KERNEL_DS<span class="token punctuation">)</span><span class="token punctuation">;</span>
err <span class="token operator">=</span> <span class="token function">native_ioctl</span><span class="token punctuation">(</span>file<span class="token punctuation">,</span> cmd<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">long</span><span class="token punctuation">)</span><span class="token operator">&</span>karg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">set_fs</span><span class="token punctuation">(</span>old_fs<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/* Special case: even after an error we need to put the
results back for these ioctls since the error_idx will
contain information on which control failed. */</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>cmd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> VIDIOC_G_EXT_CTRLS<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_EXT_CTRLS<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_TRY_EXT_CTRLS<span class="token punctuation">:</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">put_v4l2_ext_controls32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2ecs<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">)</span>
err <span class="token operator">=</span> <span class="token operator">-</span>EFAULT<span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span>
<span class="token keyword">return</span> err<span class="token punctuation">;</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>cmd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> VIDIOC_S_INPUT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_OUTPUT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_G_INPUT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_G_OUTPUT<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_user</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">(</span>s32<span class="token punctuation">)</span>karg<span class="token punctuation">.</span>vi<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>s32 __user <span class="token operator">*</span><span class="token punctuation">)</span>up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_FBUF<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_framebuffer32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2fb<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_DQEVENT<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_event32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2ev<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_EDID<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_EDID<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_edid32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2edid<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_G_FMT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_S_FMT<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_TRY_FMT<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_format32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2f<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_CREATE_BUFS<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_create32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2crt<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_QUERYBUF<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_QBUF<span class="token punctuation">:</span>
<span class="token keyword">case</span> VIDIOC_DQBUF<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_buffer32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2b<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_ENUMSTD<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_standard32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2s<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">case</span> VIDIOC_ENUMINPUT<span class="token punctuation">:</span>
err <span class="token operator">=</span> <span class="token function">put_v4l2_input32</span><span class="token punctuation">(</span><span class="token operator">&</span>karg<span class="token punctuation">.</span>v2i<span class="token punctuation">,</span> up<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> err<span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
2.4 注册子设备 /media/v4l2-core/v4l2-subdev.c
当有sub-dev 需要注册到v4l2 时,调用 v4l2_device_register_subdev()
函数。
最终调用 __video_register_device()
,传递参数 VFL_TYPE_SUBDEV
,说明是注册 sub_dev 设备。
@ kernel/msm-4.4/drivers/media/v4l2-core/v4l2-device.c
int v4l2_device_register_subdev_nodes(struct v4l2_device v4l2_dev)
{
struct video_device vdev;
struct v4l2_subdev *sd;
<span class="token comment">/* Register a device node for every subdev marked with the V4L2_SUBDEV_FL_HAS_DEVNODE flag. */</span>
<span class="token function">list_for_each_entry</span><span class="token punctuation">(</span>sd<span class="token punctuation">,</span> <span class="token operator">&</span>v4l2_dev<span class="token operator">-></span>subdevs<span class="token punctuation">,</span> list<span class="token punctuation">)</span> <span class="token punctuation">{</span>
vdev <span class="token operator">=</span> <span class="token function">kzalloc</span><span class="token punctuation">(</span><span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token operator">*</span>vdev<span class="token punctuation">)</span><span class="token punctuation">,</span> GFP_KERNEL<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">video_set_drvdata</span><span class="token punctuation">(</span>vdev<span class="token punctuation">,</span> sd<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">strlcpy</span><span class="token punctuation">(</span>vdev<span class="token operator">-></span>name<span class="token punctuation">,</span> sd<span class="token operator">-></span>name<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>vdev<span class="token operator">-></span>name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
vdev<span class="token operator">-></span>v4l2_dev <span class="token operator">=</span> v4l2_dev<span class="token punctuation">;</span>
vdev<span class="token operator">-></span>fops <span class="token operator">=</span> <span class="token operator">&</span>v4l2_subdev_fops<span class="token punctuation">;</span>
vdev<span class="token operator">-></span>release <span class="token operator">=</span> v4l2_device_release_subdev_node<span class="token punctuation">;</span>
vdev<span class="token operator">-></span>ctrl_handler <span class="token operator">=</span> sd<span class="token operator">-></span>ctrl_handler<span class="token punctuation">;</span>
err <span class="token operator">=</span> <span class="token function">__video_register_device</span><span class="token punctuation">(</span>vdev<span class="token punctuation">,</span> VFL_TYPE_SUBDEV<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> sd<span class="token operator">-></span>owner<span class="token punctuation">)</span><span class="token punctuation">;</span>
sd<span class="token operator">-></span>entity<span class="token punctuation">.</span>info<span class="token punctuation">.</span>dev<span class="token punctuation">.</span>major <span class="token operator">=</span> VIDEO_MAJOR<span class="token punctuation">;</span>
sd<span class="token operator">-></span>entity<span class="token punctuation">.</span>info<span class="token punctuation">.</span>dev<span class="token punctuation">.</span>minor <span class="token operator">=</span> vdev<span class="token operator">-></span>minor<span class="token punctuation">;</span>
sd<span class="token operator">-></span>devnode <span class="token operator">=</span> vdev<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
2.4.1 子设备操作函数 v4l2_fops
@ kernel/msm-4.4/drivers/media/v4l2-core/v4l2-subdev.c
const struct v4l2_file_operations v4l2_subdev_fops = {
.owner = THIS_MODULE,
.open = subdev_open,
.unlocked_ioctl = subdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = subdev_compat_ioctl32,
#endif
.release = subdev_close,
.poll = subdev_poll,
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
重点来看下 ioctl 函数
static long subdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, subdev_do_ioctl);
}
static long subdev_do_ioctl(struct file file, unsigned int cmd, void arg)
{
switch (cmd) {
case VIDIOC_QUERYCTRL: return v4l2_queryctrl(vfh->ctrl_handler, arg);
case VIDIOC_QUERY_EXT_CTRL: return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg);
case VIDIOC_QUERYMENU: return v4l2_querymenu(vfh->ctrl_handler, arg);
case VIDIOC_G_CTRL: return v4l2_g_ctrl(vfh->ctrl_handler, arg);
case VIDIOC_S_CTRL: return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg);
case VIDIOC_G_EXT_CTRLS: return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
case VIDIOC_S_EXT_CTRLS: return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
case VIDIOC_TRY_EXT_CTRLS: return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg);
case VIDIOC_DQEVENT: return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
case VIDIOC_SUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
case VIDIOC_UNSUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
case VIDIOC_DBG_G_REGISTER: return v4l2_subdev_call(sd, core, g_register, p);
case VIDIOC_DBG_S_REGISTER: return v4l2_subdev_call(sd, core, s_register, p);
case VIDIOC_LOG_STATUS: ret = v4l2_subdev_call(sd, core, log_status); return ret;
case VIDIOC_SUBDEV_G_FMT: return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
case VIDIOC_SUBDEV_S_FMT: return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
case VIDIOC_SUBDEV_G_CROP: rval = v4l2_subdev_call(sd, pad, get_selection, subdev_fh->pad, &sel); crop->rect = sel.r; return rval;
case VIDIOC_SUBDEV_S_CROP: rval = v4l2_subdev_call(sd, pad, set_selection, subdev_fh->pad, &sel);return rval;
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,code);
case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,fse);
case VIDIOC_SUBDEV_G_FRAME_INTERVAL: return v4l2_subdev_call(sd, video, g_frame_interval, arg);
case VIDIOC_SUBDEV_S_FRAME_INTERVAL: return v4l2_subdev_call(sd, video, s_frame_interval, arg);
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,fie);
case VIDIOC_SUBDEV_G_SELECTION: return v4l2_subdev_call(sd, pad, get_selection, subdev_fh->pad, sel);
case VIDIOC_SUBDEV_S_SELECTION: return v4l2_subdev_call(sd, pad, set_selection, subdev_fh->pad, sel);
case VIDIOC_G_EDID: return v4l2_subdev_call(sd, pad, get_edid, edid);
case VIDIOC_S_EDID: return v4l2_subdev_call(sd, pad, set_edid, edid);
case VIDIOC_SUBDEV_DV_TIMINGS_CAP: return v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt);
case VIDIOC_SUBDEV_QUERY_DV_TIMINGS: return v4l2_subdev_call(sd, video, query_dv_timings, arg);
case VIDIOC_SUBDEV_G_DV_TIMINGS: return v4l2_subdev_call(sd, video, g_dv_timings, arg);
case VIDIOC_SUBDEV_S_DV_TIMINGS: return v4l2_subdev_call(sd, video, s_dv_timings, arg);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
可以发现,对 subdev 的操作,均是由 v4l2_subdev_call()
来转接,相关函数定义如下:
@ kernel/msm-4.4/include/media/v4l2-subdev.h
struct v4l2_subdev_core_ops {
int (log_status)(struct v4l2_subdev sd);
int (s_io_pin_config)(struct v4l2_subdev sd, size_t n, struct v4l2_subdev_io_pin_config pincfg);
int (init)(struct v4l2_subdev sd, u32 val);
int (load_fw)(struct v4l2_subdev sd);
int (reset)(struct v4l2_subdev sd, u32 val);
int (s_gpio)(struct v4l2_subdev sd, u32 val);
int (queryctrl)(struct v4l2_subdev sd, struct v4l2_queryctrl qc);
int (g_ctrl)(struct v4l2_subdev sd, struct v4l2_control ctrl);
int (s_ctrl)(struct v4l2_subdev sd, struct v4l2_control ctrl);
int (g_ext_ctrls)(struct v4l2_subdev sd, struct v4l2_ext_controls ctrls);
int (s_ext_ctrls)(struct v4l2_subdev sd, struct v4l2_ext_controls ctrls);
int (try_ext_ctrls)(struct v4l2_subdev sd, struct v4l2_ext_controls ctrls);
int (querymenu)(struct v4l2_subdev sd, struct v4l2_querymenu qm);
long (ioctl)(struct v4l2_subdev sd, unsigned int cmd, void arg);
long (compat_ioctl32)(struct v4l2_subdev sd, unsigned int cmd,unsigned long arg);
int (g_register)(struct v4l2_subdev sd, struct v4l2_dbg_register reg);
int (s_register)(struct v4l2_subdev sd, const struct v4l2_dbg_register reg);
int (s_power)(struct v4l2_subdev sd, int on);
int (interrupt_service_routine)(struct v4l2_subdev sd,u32 status, bool handled);
int (subscribe_event)(struct v4l2_subdev sd, struct v4l2_fh fh, struct v4l2_event_subscription sub);
int (unsubscribe_event)(struct v4l2_subdev sd, struct v4l2_fh fh, struct v4l2_event_subscription sub);
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
Linux V4L2之camera
Video4Linux框架简介
Video4Linux框架简介(5) - Streaming
video4linux 讲解
video4linux基础
Video4Linux
</div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-60ecaf1f42.css" rel="stylesheet">
</div>