android_驱动_qcom_【高通SDM660平台】(3) --- Camera V4L2 驱动层分析

10 篇文章 2 订阅


【高通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系统中视频输入设备主要包括以下四个部分:

  1. 字符设备驱动:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间;
  2. V4L2驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数;
  3. 平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关的V4L2驱动部分,包括注册video_device和v4l2_dev;
  4. 具体的sensor驱动:主要上电、提供工作时钟、视频图像裁剪、流IO开启等,实现各种设备控制方法供上层调用并注册v4l2_subdev。

V4L2核心源码位于drivers/media/v4l2-core,根据功能可以划分为四类:

  1. 字符设备模块:由v4l2-dev.c实现,主要作用申请字符主设备号、注册class和提供video device注册注销等相关函数。
  2. V4L2基础框架:由v4l2-device.c、v4l2-subdev.c、v4l2-fh.c、v4l2-ctrls.c等文件构建V4L2基础框架。
  3. videobuf管理
    videobuf2-core.c、videobuf2-dma-contig.c、videobuf2-dma-sg.c、videobuf2-memops.c、videobuf2-vmalloc.c、v4l2-mem2mem.c等文件实现,完成videobuffer的分配、管理和注销。
  4. 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等节点。

主要工作如下:

  1. 将字符设备号(81,0)(81,255)这期间256个字次设备号,均申请为 v4l2 使用,name=video4linux
  2. 注册 /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">&gt;</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">&amp;</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">-&gt;</span>vdev<span class="token operator">-&gt;</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">-&gt;</span>vdev<span class="token operator">-&gt;</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">-&gt;</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">-&gt;</span>vdev<span class="token operator">-&gt;</span>v4l2_dev <span class="token operator">=</span> msm_v4l2_dev<span class="token punctuation">;</span>

<span class="token comment">// 5. 设置父设备为 pdev-&gt;dev (也就是 qcom,msm-cam 的设备信息)dev-&gt;driver-&gt;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">&amp;</span><span class="token punctuation">(</span>pdev<span class="token operator">-&gt;</span>dev<span class="token punctuation">)</span><span class="token punctuation">,</span> pvdev<span class="token operator">-&gt;</span>vdev<span class="token operator">-&gt;</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">&gt;</span>  
	pvdev<span class="token operator">-&gt;</span>vdev<span class="token operator">-&gt;</span>v4l2_dev<span class="token operator">-&gt;</span>dev <span class="token operator">=</span> pdev<span class="token operator">-&gt;</span>dev<span class="token punctuation">;</span>
	<span class="token function">snprintf</span><span class="token punctuation">(</span>v4l2_dev<span class="token operator">-&gt;</span>name<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>v4l2_dev<span class="token operator">-&gt;</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">-&gt;</span>driver<span class="token operator">-&gt;</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">-&gt;</span>vdev<span class="token operator">-&gt;</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">-&gt;</span>vdev<span class="token operator">-&gt;</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
pvdev<span class="token operator">-&gt;</span>vdev<span class="token operator">-&gt;</span>release  <span class="token operator">=</span> video_device_release<span class="token punctuation">;</span>
pvdev<span class="token operator">-&gt;</span>vdev<span class="token operator">-&gt;</span>fops     <span class="token operator">=</span> <span class="token operator">&amp;</span>msm_fops<span class="token punctuation">;</span>			<span class="token comment">// 配置 video_device 的字符设备操作函数</span>
pvdev<span class="token operator">-&gt;</span>vdev<span class="token operator">-&gt;</span>ioctl_ops <span class="token operator">=</span> <span class="token operator">&amp;</span>g_msm_ioctl_ops<span class="token punctuation">;</span>	<span class="token comment">// 配置 v4l2 IOCTRL</span>
pvdev<span class="token operator">-&gt;</span>vdev<span class="token operator">-&gt;</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">-&gt;</span>vdev<span class="token operator">-&gt;</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">-&gt;</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

主要工作如下:

  1. 初始化 fh->list
  2. 检查设备类型
  3. 寻找一个不在使用的 次设备号, 主设备号为 81,(0~63 为video)(128,191 为sub-dev)
  4. 获取 index,将当前需要注册的 video_device 设备保存在 video_device[]全局数组中
  5. 分配对应的字符设备,字符设备号,就是前面的 (81,minor)
  6. 分配对应的sys节点 /sys/class/video4linux/video0
  7. 注册release 时调用的函数
  8. 将该 v4l2 subdevice 当成一个 entity 注册到 media device
  9. 注册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">-&gt;</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-&gt;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">&amp;</span>vdev<span class="token operator">-&gt;</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">-&gt;</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">-&gt;</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">&lt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</span>cdev<span class="token operator">-&gt;</span>ops <span class="token operator">=</span> <span class="token operator">&amp;</span>v4l2_fops<span class="token punctuation">;</span>
vdev<span class="token operator">-&gt;</span>cdev<span class="token operator">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</span>dev<span class="token punctuation">.</span>class <span class="token operator">=</span> <span class="token operator">&amp;</span>video_class<span class="token punctuation">;</span>
vdev<span class="token operator">-&gt;</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">-&gt;</span>minor<span class="token punctuation">)</span><span class="token punctuation">;</span>
vdev<span class="token operator">-&gt;</span>dev<span class="token punctuation">.</span>parent <span class="token operator">=</span> vdev<span class="token operator">-&gt;</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">&amp;</span>vdev<span class="token operator">-&gt;</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">-&gt;</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">&amp;</span>vdev<span class="token operator">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</span>v4l2_dev<span class="token operator">-&gt;</span>mdev <span class="token operator">&amp;&amp;</span> vdev<span class="token operator">-&gt;</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">-&gt;</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">-&gt;</span>entity<span class="token punctuation">.</span>name <span class="token operator">=</span> vdev<span class="token operator">-&gt;</span>name<span class="token punctuation">;</span>
	vdev<span class="token operator">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</span>v4l2_dev<span class="token operator">-&gt;</span>mdev<span class="token punctuation">,</span><span class="token operator">&amp;</span>vdev<span class="token operator">-&gt;</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">&amp;</span>vdev<span class="token operator">-&gt;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</span>v4l2_dev<span class="token operator">-&gt;</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">-&gt;</span>name<span class="token punctuation">,</span> sd<span class="token operator">-&gt;</span>name<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>vdev<span class="token operator">-&gt;</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	vdev<span class="token operator">-&gt;</span>v4l2_dev <span class="token operator">=</span> v4l2_dev<span class="token punctuation">;</span>
	vdev<span class="token operator">-&gt;</span>fops <span class="token operator">=</span> <span class="token operator">&amp;</span>v4l2_subdev_fops<span class="token punctuation">;</span>
	vdev<span class="token operator">-&gt;</span>release <span class="token operator">=</span> v4l2_device_release_subdev_node<span class="token punctuation">;</span>
	vdev<span class="token operator">-&gt;</span>ctrl_handler <span class="token operator">=</span> sd<span class="token operator">-&gt;</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">-&gt;</span>owner<span class="token punctuation">)</span><span class="token punctuation">;</span>


	sd<span class="token operator">-&gt;</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">-&gt;</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">-&gt;</span>minor<span class="token punctuation">;</span>
	sd<span class="token operator">-&gt;</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>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SDM660平台上同时兼容外接的AW35615CSR芯片和内置的USB Type-C controller,你需要对SDM660平台的USB Type-C controller驱动程序进行修改,以便同时支持两种控制器。具体的修改步骤如下: 1. 在SDM660平台上加载AW35615CSR芯片的驱动程序,并确保AW35615CSR芯片已经被成功识别。 2. 在SDM660平台上加载USB Type-C controller驱动程序,并确保内置的USB Type-C controller已经被成功识别。 3. 在USB Type-C controller驱动程序中添加对AW35615CSR芯片的支持。具体来说,你需要修改驱动程序中的probe函数,以便在检测到AW35615CSR芯片时将其作为备选controller,并在AW35615CSR芯片不可用时使用内置的USB Type-C controller。具体代码实现可能因驱动程序而异,以下是一个简单的示例: ```c static int usb_tc_probe(struct platform_device *pdev) { struct usb_tc *tc; struct device *dev = &pdev->dev; int ret; tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL); if (!tc) return -ENOMEM; // 检测AW35615CSR芯片是否可用 if (aw35615csr_detect()) tc->type = USB_TC_TYPE_EXTERNAL; else tc->type = USB_TC_TYPE_INTERNAL; // 初始化Type-C controller switch (tc->type) { case USB_TC_TYPE_EXTERNAL: // 初始化外部Type-C controller ret = aw35615csr_tc_init(); if (ret) { dev_err(dev, "failed to initialize external Type-C controller\n"); return ret; } break; case USB_TC_TYPE_INTERNAL: // 初始化内部Type-C controller ret = msm_usb_tc_init(); if (ret) { dev_err(dev, "failed to initialize internal Type-C controller\n"); return ret; } break; default: dev_err(dev, "unsupported Type-C controller type\n"); return -EINVAL; } // 注册Type-C controller tc_set_drvdata(tc, dev); ret = usb_add_tc_dev(dev, tc); if (ret) { dev_err(dev, "failed to register Type-C controller\n"); goto err_tc_exit; } return 0; err_tc_exit: switch (tc->type) { case USB_TC_TYPE_EXTERNAL: aw35615csr_tc_exit(); break; case USB_TC_TYPE_INTERNAL: msm_usb_tc_exit(); break; } return ret; } ``` 在这个示例代码中,我们在probe函数中使用aw35615csr_detect函数来检测AW35615CSR芯片是否可用,如果可用,就将其作为备选controller,并在初始化Type-C controller时使用aw35615csr_tc_init函数初始化AW35615CSR芯片的Type-C controller。如果AW35615CSR芯片不可用,则使用内置的USB Type-C controller,并在初始化Type-C controller时使用msm_usb_tc_init函数初始化内置的USB Type-C controller。 4. 编译和安装修改后的USB Type-C controller驱动程序,并重新启动SDM660平台。在重新启动后,SDM660平台应该可以同时支持内置的USB Type-C controller和外接的AW35615CSR芯片了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值