Linux ARM平台开发系列讲解(摄像头V4L2子系统) 2.12.4 V4L2子设备操作函数结构体分析

1. 概述

对于V4L2子设备,其核心就是去实现struct v4l2_subdev_ops子设备操作接口,下面就介绍V4L2操作函数接口用到的一些关键成员是什么意思。

2. struct v4l2_subdev结构体介绍

子设备,负责实现具体的功能。可将其抽象为具体的某一摄像头传感器,如OV7740OV7251OV5640OV13850等。

每一个子设备驱动都必须有一个 v4l2_subdev 结构体,这个结构体可以作为独立的简单子设备存在,也可以嵌入到更大的结构体(自定义的子设备结构体)里面。通常会有一个由内核设置的低层次结构体(i2c_client,也就是上面说的 i2c 设备),它包含了一些设备数据,要调用 v4l2_set_subdevdata 来设置子设备私有数据指针指向它,这样的话就可以很方便的从 subdev 找到相关的 I2C 设备数据(这个要编程实现的时候才能够了解它的用意)。另外也需要设置低级别结构的私有数据指针指向 v4l2_subdev 结构体,方便从低级别的结构体访问 v4l2_subdev 结构体,达到双向访问的目的,对于 i2c_client 来说,可以用 i2c_set_clientdata 函数来设置,其它的需使用与之相应的函数来完成设置。

  • struct v4l2_subdev源码分析:
  • 源码路径:include\media\v4l2-subdev.h
#define V4L2_SUBDEV_NAME_SIZE 32

/* Set this flag if this subdev is a i2c device. */
/* 设置从设备是I2C设备 */
#define V4L2_SUBDEV_FL_IS_I2C			(1U << 0)		
/* Set this flag if this subdev is a spi device. */
/* 设置从设备是SPI设备 */
#define V4L2_SUBDEV_FL_IS_SPI			(1U << 1)
/* Set this flag if this subdev needs a device node. */
/* 从设备需要设备树节点 */
#define V4L2_SUBDEV_FL_HAS_DEVNODE		(1U << 2)
/* Set this flag if this subdev generates events. */
/* 从设备会产生事件 */
#define V4L2_SUBDEV_FL_HAS_EVENTS		(1U << 3)


/* Each instance of a subdev driver should create this struct, either
   stand-alone or embedded in a larger struct.
 */
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
	struct media_entity entity;
#endif
	/* 子设备串联链表 */
	struct list_head list;	
	/* 属于那个模块,一般指向i2c_client驱动模块 */			
	struct module *owner;
	
	bool owner_v4l2_dev;
	/* 此标志位是设备属于哪一种设备,由上面的V4L2_SUBDEV_FL_XXX宏确定 */
	u32 flags;
	/* 指向父设备 */
	struct v4l2_device *v4l2_dev;
	/* v4l2子设备的操作函数集合 */
	const struct v4l2_subdev_ops *ops;
	/* Never call these internal ops from within a driver! */
	/* 提供给v4l2框架的操作函数,只有v4l2框架会调用,驱动不使用 */
	const struct v4l2_subdev_internal_ops *internal_ops;
	/* The control handler of this subdev. May be NULL. */
	/* subdev控制接口 */
	struct v4l2_ctrl_handler *ctrl_handler;
	/* name must be unique */
	/* 从设备的名称,必须独一无二 */
	char name[V4L2_SUBDEV_NAME_SIZE];
	/* can be used to group similar subdevs, value is driver-specific */
	/* 从设备组的ID,由驱动定义,相似的从设备可以编为一组 */
	u32 grp_id;
	/* pointer to private data */
	/* 从设备私有数据指针,一般指向i2c_client的设备结构体dev */
	void *dev_priv;
	/* 主设备私有数据指针,一般指向v4l2_device嵌入的结构体 */
	void *host_priv;
	/* subdev device node */
	/* 指向video设备结构体 */
	struct video_device *devnode;
	/* pointer to the physical device, if any */
	/* 指向物理设备 */
	struct device *dev;
	struct fwnode_handle *fwnode;
	
	/* Links this subdev to a global subdev_list or @notifier->done list. */
	/* 将所有从设备连接到全局subdev_list链表或notifier->done链表 */
	struct list_head async_list;
	/* Pointer to respective struct v4l2_async_subdev. */
	/* 指向struct v4l2_async_subdev,用于异步事件 */
	struct v4l2_async_subdev *asd;
	/* Pointer to the managing notifier. */
	/* 指向管理的notifier,用于主设备和从设备的异步关联 */
	struct v4l2_async_notifier *notifier;
	/* common part of subdevice platform data */
	struct v4l2_async_notifier *subdev_notifier;
	
	/* A sub-device notifier implicitly registered for the sub-device
	   using v4l2_device_register_sensor_subdev(). */
	struct v4l2_subdev_platform_data *pdata;
};

3. struct v4l2_subdev_ops结构体分析

上一章节讲解了V4L2的注册,在注册过程中需要调用v4l2_i2c_subdev_initstruct v4l2_subdev_ops结构体进行初始化,它会为子设备提供操作函数,其中struct v4l2_subdev_ops结构体包含了哪些,具体如下:

  • 源码路径:include\media\v4l2-subdev.h
struct v4l2_subdev_ops {
	/* 视频设备通用的操作:初始化、加载FW、上电和RESET等 */
	const struct v4l2_subdev_core_ops	*core;
	/* 调谐器操作合集 */
	const struct v4l2_subdev_tuner_ops	*tuner;
	/* 音频操作合集 */
	const struct v4l2_subdev_audio_ops	*audio;
	/* 视频设备的特有操作:设置帧率、裁剪图像、开关视频流等 */
	/* 视频操作合集 */
	const struct v4l2_subdev_video_ops	*video;
	const struct v4l2_subdev_vbi_ops	*vbi;
	const struct v4l2_subdev_ir_ops		*ir;
	const struct v4l2_subdev_sensor_ops	*sensor;
	const struct v4l2_subdev_pad_ops	*pad;
};
  • 其中struct v4l2_subdev_ops 结构体中的每一个成员都是一个操作函数集合,具体意义如下:

3.1 struct v4l2_subdev_core_ops

  • struct v4l2_subdev_core_ops结构体主要是配置子设备的初始化、电源、固件加载等
  • 源码路径: include\media\v4l2-subdev.h
/**
 * struct v4l2_subdev_core_ops - Define core ops callbacks for subdevs
 *
 * @log_status: callback for VIDIOC_LOG_STATUS ioctl handler code.
 *
 * @s_io_pin_config: configure one or more chip I/O pins for chips that
 *	multiplex different internal signal pads out to IO pins.  This function
 *	takes a pointer to an array of 'n' pin configuration entries, one for
 *	each pin being configured.  This function could be called at times
 *	other than just subdevice initialization.
 *
 * @init: initialize the sensor registers to some sort of reasonable default
 *	values. Do not use for new drivers and should be removed in existing
 *	drivers.
 *
 * @load_fw: load firmware.
 *
 * @reset: generic reset command. The argument selects which subsystems to
 *	reset. Passing 0 will always reset the whole chip. Do not use for new
 *	drivers without discussing this first on the linux-media mailinglist.
 *	There should be no reason normally to reset a device.
 *
 * @s_gpio: set GPIO pins. Very simple right now, might need to be extended with
 *	a direction argument if needed.
 *
 * @queryctrl: callback for VIDIOC_QUERYCTL ioctl handler code.
 *
 * @g_ctrl: callback for VIDIOC_G_CTRL ioctl handler code.
 *
 * @s_ctrl: callback for VIDIOC_S_CTRL ioctl handler code.
 *
 * @g_ext_ctrls: callback for VIDIOC_G_EXT_CTRLS ioctl handler code.
 *
 * @s_ext_ctrls: callback for VIDIOC_S_EXT_CTRLS ioctl handler code.
 *
 * @try_ext_ctrls: callback for VIDIOC_TRY_EXT_CTRLS ioctl handler code.
 *
 * @querymenu: callback for VIDIOC_QUERYMENU ioctl handler code.
 *
 * @ioctl: called at the end of ioctl() syscall handler at the V4L2 core.
 *	   used to provide support for private ioctls used on the driver.
 *
 * @compat_ioctl32: called when a 32 bits application uses a 64 bits Kernel,
 *		    in order to fix data passed from/to userspace.
 *
 * @g_register: callback for VIDIOC_G_REGISTER ioctl handler code.
 *
 * @s_register: callback for VIDIOC_G_REGISTER ioctl handler code.
 *
 * @s_power: puts subdevice in power saving mode (on == 0) or normal operation
 *	mode (on == 1).
 *
 * @interrupt_service_routine: Called by the bridge chip's interrupt service
 *	handler, when an interrupt status has be raised due to this subdev,
 *	so that this subdev can handle the details.  It may schedule work to be
 *	performed later.  It must not sleep.  *Called from an IRQ context*.
 *
 * @subscribe_event: used by the drivers to request the control framework that
 *		     for it to be warned when the value of a control changes.
 *
 * @unsubscribe_event: remove event subscription from the control framework.
 */
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);
	/* 加载firmware */
	int (*load_fw)(struct v4l2_subdev *sd);
	/* 重置设备 */
	int (*reset)(struct v4l2_subdev *sd, u32 val);
	/* 设置gpio */
	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);
#ifdef CONFIG_COMPAT
	long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd,
			       unsigned long arg);
#endif
#ifdef CONFIG_VIDEO_ADV_DEBUG
	/* 获取寄存器值 */
	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);
#endif
	/* 控制电源上电下电 */
	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);
};

3.2 struct v4l2_subdev_tuner_ops

  • struct v4l2_subdev_tuner_ops结构体主要是用在一些调谐器和调幅器等一些无线模块时调用
  • 源码路径: include\media\v4l2-subdev.h
/**
 * struct s_radio - Callbacks used when v4l device was opened in radio mode.
 *
 * @s_radio: callback for VIDIOC_S_RADIO ioctl handler code.
 *
 * @s_frequency: callback for VIDIOC_S_FREQUENCY ioctl handler code.
 *
 * @g_frequency: callback for VIDIOC_G_FREQUENCY ioctl handler code.
 *		 freq->type must be filled in. Normally done by video_ioctl2
 *		or the bridge driver.
 *
 * @enum_freq_bands: callback for VIDIOC_ENUM_FREQ_BANDS ioctl handler code.
 *
 * @g_tuner: callback for VIDIOC_G_TUNER ioctl handler code.
 *
 * @s_tuner: callback for VIDIOC_S_TUNER ioctl handler code. vt->type must be
 *	     filled in. Normally done by video_ioctl2 or the
 *	bridge driver.
 *
 * @g_modulator: callback for VIDIOC_G_MODULATOR ioctl handler code.
 *
 * @s_modulator: callback for VIDIOC_S_MODULATOR ioctl handler code.
 *
 * @s_type_addr: sets tuner type and its I2C addr.
 *
 * @s_config: sets tda9887 specific stuff, like port1, port2 and qss
 */
struct v4l2_subdev_tuner_ops {
	/* 设置无线设备信息 */
	int (*s_radio)(struct v4l2_subdev *sd);
	/* 设置频率 */
	int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq);
	/* 获取频率 */
	int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
	int (*enum_freq_bands)(struct v4l2_subdev *sd, struct v4l2_frequency_band *band);

	/* 获取调谐器信息 */
	int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
	/* 设置调谐器信息 */
	int (*s_tuner)(struct v4l2_subdev *sd, const struct v4l2_tuner *vt);

	/* 获取调幅器信息 */
	int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm);
	/* 设置调幅器信息 */
	int (*s_modulator)(struct v4l2_subdev *sd, const struct v4l2_modulator *vm);

	/* 安装调谐器 */
	int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type);
	/* 设置配置信息 */
	int (*s_config)(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *config);
};

3.3 struct v4l2_subdev_audio_ops

  • struct v4l2_subdev_audio_ops结构体主要是用在一些音频模块输入输出的时候调用
  • 源码路径: include\media\v4l2-subdev.h
/**
 * struct v4l2_subdev_audio_ops - Callbacks used for audio-related settings
 *
 * @s_clock_freq: set the frequency (in Hz) of the audio clock output.
 *	Used to slave an audio processor to the video decoder, ensuring that
 *	audio and video remain synchronized. Usual values for the frequency
 *	are 48000, 44100 or 32000 Hz. If the frequency is not supported, then
 *	-EINVAL is returned.
 *
 * @s_i2s_clock_freq: sets I2S speed in bps. This is used to provide a standard
 *	way to select I2S clock used by driving digital audio streams at some
 *	board designs. Usual values for the frequency are 1024000 and 2048000.
 *	If the frequency is not supported, then -EINVAL is returned.
 *
 * @s_routing: used to define the input and/or output pins of an audio chip,
 *	and any additional configuration data.
 *	Never attempt to use user-level input IDs (e.g. Composite, S-Video,
 *	Tuner) at this level. An i2c device shouldn't know about whether an
 *	input pin is connected to a Composite connector, become on another
 *	board or platform it might be connected to something else entirely.
 *	The calling driver is responsible for mapping a user-level input to
 *	the right pins on the i2c device.
 *
 * @s_stream: used to notify the audio code that stream will start or has
 *	stopped.
 */
struct v4l2_subdev_audio_ops {
	/* 设置音频设备频率 */
	int (*s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
	/* 设置i2s总线频率 */
	int (*s_i2s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
	/* 设置音频路由 */
	int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
	/* 控制音频流 */
	int (*s_stream)(struct v4l2_subdev *sd, int enable);
};

3.4 struct v4l2_subdev_video_ops

  • struct v4l2_subdev_video_ops结构体主要是用在一些视频设备时调用
  • 源码路径: include\media\v4l2-subdev.h
/**
 * struct v4l2_subdev_video_ops - Callbacks used when v4l device was opened
 * 				  in video mode.
 *
 * @s_routing: see s_routing in audio_ops, except this version is for video
 *	devices.
 *
 * @s_crystal_freq: sets the frequency of the crystal used to generate the
 *	clocks in Hz. An extra flags field allows device specific configuration
 *	regarding clock frequency dividers, etc. If not used, then set flags
 *	to 0. If the frequency is not supported, then -EINVAL is returned.
 *
 * @g_std: callback for VIDIOC_G_STD ioctl handler code.
 *
 * @s_std: callback for VIDIOC_S_STD ioctl handler code.
 *
 * @s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
 *	video input devices.
 *
 * @g_std_output: get current standard for video OUTPUT devices. This is ignored
 *	by video input devices.
 *
 * @querystd: callback for VIDIOC_QUERYSTD ioctl handler code.
 *
 * @g_tvnorms: get v4l2_std_id with all standards supported by the video
 *	CAPTURE device. This is ignored by video output devices.
 *
 * @g_tvnorms_output: get v4l2_std_id with all standards supported by the video
 *	OUTPUT device. This is ignored by video capture devices.
 *
 * @g_input_status: get input status. Same as the status field in the v4l2_input
 *	struct.
 *
 * @s_stream: used to notify the driver that a video stream will start or has
 *	stopped.
 *
 * @cropcap: callback for VIDIOC_CROPCAP ioctl handler code.
 *
 * @g_crop: callback for VIDIOC_G_CROP ioctl handler code.
 *
 * @s_crop: callback for VIDIOC_S_CROP ioctl handler code.
 *
 * @g_parm: callback for VIDIOC_G_PARM ioctl handler code.
 *
 * @s_parm: callback for VIDIOC_S_PARM ioctl handler code.
 *
 * @g_frame_interval: callback for VIDIOC_G_FRAMEINTERVAL ioctl handler code.
 *
 * @s_frame_interval: callback for VIDIOC_S_FRAMEINTERVAL ioctl handler code.
 *
 * @s_dv_timings: Set custom dv timings in the sub device. This is used
 *	when sub device is capable of setting detailed timing information
 *	in the hardware to generate/detect the video signal.
 *
 * @g_dv_timings: Get custom dv timings in the sub device.
 *
 * @query_dv_timings: callback for VIDIOC_QUERY_DV_TIMINGS ioctl handler code.
 *
 * @g_mbus_config: get supported mediabus configurations
 *
 * @s_mbus_config: set a certain mediabus configuration. This operation is added
 *	for compatibility with soc-camera drivers and should not be used by new
 *	software.
 *
 * @s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev
 *	can adjust @size to a lower value and must not write more data to the
 *	buffer starting at @data than the original value of @size.
 */
struct v4l2_subdev_video_ops {
	/* 设置视频路由 */
	int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
	 /* 设置设备频率 */
	int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags);
	
	int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm);
	int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm);
	
	/* 设置标准输出 */
	int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
	/* 获取标准输出 */
	int (*g_std_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
	/* 查询标准 */
	int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);

	int (*g_tvnorms)(struct v4l2_subdev *sd, v4l2_std_id *std);
	int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std);

	/* 获取输入状态 */
	int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
	/* 设置数据流 */
	int (*s_stream)(struct v4l2_subdev *sd, int enable);
	
	int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc);
	int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
	int (*s_crop)(struct v4l2_subdev *sd, const struct v4l2_crop *crop);
	int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
	int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);

	/* 获取帧间隔参数(帧率) */
	int (*g_frame_interval)(struct v4l2_subdev *sd,
				struct v4l2_subdev_frame_interval *interval);
	/* 设置帧间隔参数(帧率) */
	int (*s_frame_interval)(struct v4l2_subdev *sd,
				struct v4l2_subdev_frame_interval *interval);
	
	int (*enum_framesizes)(struct v4l2_subdev *sd,
			       struct v4l2_frmsizeenum *fsize);
	int (*enum_frameintervals)(struct v4l2_subdev *sd,
				   struct v4l2_frmivalenum *fival);
	/* 设置设备自定义时钟计时,需要硬件支持 */
	int (*s_dv_timings)(struct v4l2_subdev *sd,
			struct v4l2_dv_timings *timings);
	/* 获取设备自定义时钟计时,需要硬件支持 */
	int (*g_dv_timings)(struct v4l2_subdev *sd,
			struct v4l2_dv_timings *timings);
	/* 检测设备自定义时钟计时,需要硬件支持 */
	int (*query_dv_timings)(struct v4l2_subdev *sd,
			struct v4l2_dv_timings *timings);
	
	int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
			     u32 *code);
	int (*enum_mbus_fsizes)(struct v4l2_subdev *sd,
				struct v4l2_frmsizeenum *fsize);
	int (*g_mbus_fmt)(struct v4l2_subdev *sd,
			  struct v4l2_mbus_framefmt *fmt);
	int (*try_mbus_fmt)(struct v4l2_subdev *sd,
			    struct v4l2_mbus_framefmt *fmt);
	int (*s_mbus_fmt)(struct v4l2_subdev *sd,
			  struct v4l2_mbus_framefmt *fmt);

	/* 获取总线配置,对于 MIPI接口, sensor驱动内若支持不同
	 lane数配置或者支持 HDR,通过这个接口返回当前 sensor 工作模式下的MIPI配置*/ 
	int (*g_mbus_config)(struct v4l2_subdev *sd,
			     struct v4l2_mbus_config *cfg);
	/* 获取MIPI总线配置 */
	int (*s_mbus_config)(struct v4l2_subdev *sd,
			     const struct v4l2_mbus_config *cfg);
	int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf,
			   unsigned int *size);
};

3.5 struct v4l2_subdev_pad_ops

  • struct v4l2_subdev_pad_ops结构体主要是用于配置v4l2_subdev设备数据格式等作用
  • 源码路径: include\media\v4l2-subdev.h
/**
 * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations
 *
 * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler
 *		    code.
 * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler
 *		     code.
 *
 * @enum_frame_interval: callback for VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL ioctl
 *			 handler code.
 *
 * @get_fmt: callback for VIDIOC_SUBDEV_G_FMT ioctl handler code.
 *
 * @set_fmt: callback for VIDIOC_SUBDEV_S_FMT ioctl handler code.
 *
 * @get_selection: callback for VIDIOC_SUBDEV_G_SELECTION ioctl handler code.
 *
 * @set_selection: callback for VIDIOC_SUBDEV_S_SELECTION ioctl handler code.
 *
 * @get_edid: callback for VIDIOC_SUBDEV_G_EDID ioctl handler code.
 *
 * @set_edid: callback for VIDIOC_SUBDEV_S_EDID ioctl handler code.
 *
 * @dv_timings_cap: callback for VIDIOC_SUBDEV_DV_TIMINGS_CAP ioctl handler
 *		    code.
 *
 * @enum_dv_timings: callback for VIDIOC_SUBDEV_ENUM_DV_TIMINGS ioctl handler
 *		     code.
 *
 * @link_validate: used by the media controller code to check if the links
 *		   that belongs to a pipeline can be used for stream.
 *
 * @get_frame_desc: get the current low level media bus frame parameters.
 *
 * @set_frame_desc: set the low level media bus frame parameters, @fd array
 *                  may be adjusted by the subdev driver to device capabilities.
 */
struct v4l2_subdev_pad_ops {
	/* 枚举当前CIS 驱动支持数据格式 */
	int (*enum_mbus_code)(struct v4l2_subdev *sd,
			      struct v4l2_subdev_pad_config *cfg,
			      struct v4l2_subdev_mbus_code_enum *code);
	/* 枚举当前CIS 驱动支持分辨率 */
	int (*enum_frame_size)(struct v4l2_subdev *sd,
			       struct v4l2_subdev_pad_config *cfg,
			       struct v4l2_subdev_frame_size_enum *fse);
	/* 枚举sensor支持的帧间隔,包含分辨率 */
	int (*enum_frame_interval)(struct v4l2_subdev *sd,
				   struct v4l2_subdev_pad_config *cfg,
				   struct v4l2_subdev_frame_interval_enum *fie);
	/* 枚举当前CIS 驱动支持分辨率  */
	int (*get_fmt)(struct v4l2_subdev *sd,
		       struct v4l2_subdev_pad_config *cfg,
		       struct v4l2_subdev_format *format);
	/* 设置CIS 驱动输出数据格式以及分辨率,必须实现 */
	int (*set_fmt)(struct v4l2_subdev *sd,
		       struct v4l2_subdev_pad_config *cfg,
		       struct v4l2_subdev_format *format);
	/* 配置裁剪参数,isp输入的宽度要求16对齐,高度 8 对齐 */
	int (*get_selection)(struct v4l2_subdev *sd,
			     struct v4l2_subdev_pad_config *cfg,
			     struct v4l2_subdev_selection *sel);
	/*  */
	int (*set_selection)(struct v4l2_subdev *sd,
			     struct v4l2_subdev_pad_config *cfg,
			     struct v4l2_subdev_selection *sel);
	int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
	int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
	int (*dv_timings_cap)(struct v4l2_subdev *sd,
			      struct v4l2_dv_timings_cap *cap);
	int (*enum_dv_timings)(struct v4l2_subdev *sd,
			       struct v4l2_enum_dv_timings *timings);
#ifdef CONFIG_MEDIA_CONTROLLER
	int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link,
			     struct v4l2_subdev_format *source_fmt,
			     struct v4l2_subdev_format *sink_fmt);
#endif /* CONFIG_MEDIA_CONTROLLER */
	int (*get_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
			      struct v4l2_mbus_frame_desc *fd);
	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
			      struct v4l2_mbus_frame_desc *fd);
};

返回总目录

你可能感兴趣的:(Linux,ARM平台从入门到精通,linux,arm,嵌入式,摄像头,v4l2)