1. video_device 是启到承上启下的作用,提供app函数,向下调用ioctl_ops函数
struct video_device
{
const struct v4l2_file_operations *fops; // 重点,v4l2的操作方法集
u32 device_caps;
/* sysfs */
struct device dev;
struct cdev *cdev; // 字符设备, 很关键
struct v4l2_device *v4l2_dev; //v4l2_dev 设备 很关键 指向v4l2_device [2]中
struct device *dev_parent;
struct v4l2_ctrl_handler *ctrl_handler; //控制句柄,
struct vb2_queue *queue; //缓存队列 很关键
struct v4l2_prio_state *prio;
/* device info */
char name[32]; //设备名
enum vfl_devnode_type vfl_type; //设备类型
enum vfl_devnode_direction vfl_dir;
int minor; //次设备号
u16 num;
unsigned long flags;
int index;
/* V4L2 file handles */
spinlock_t fh_lock;
struct list_head fh_list;
int dev_debug;
v4l2_std_id tvnorms;
/* callbacks */
void (*release)(struct video_device *vdev);
const struct v4l2_ioctl_ops *ioctl_ops; // 重点,最终回调的函数
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};
struct v4l2_file_operations {
struct module *owner; //引用计数
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
__poll_t (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
#ifdef CONFIG_COMPAT
long (*compat_ioctl32) (struct file *, unsigned int, unsigned long);
#endif
unsigned long (*get_unmapped_area) (struct file *, unsigned long,
unsigned long, unsigned long, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct file *);
int (*release) (struct file *);
};
struct v4l2_ioctl_ops { //这个结构体很关键 是最终需要调用的
/* ioctl callbacks */
/* VIDIOC_QUERYCAP handler */
int (*vidioc_querycap)(struct file *file, void *fh,
struct v4l2_capability *cap);
/* VIDIOC_ENUM_FMT handlers */
int (*vidioc_enum_fmt_vid_cap)(struct file *file, void *fh,
struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_vid_overlay)(struct file *file, void *fh,
struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_vid_out)(struct file *file, void *fh,
struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh,
......
2.struct v4l2_device
struct v4l2_device {
struct device *dev;
struct media_device *mdev;
struct list_head subdevs; // 用来管理v4l2_subdeves 的链表
spinlock_t lock;
char name[V4L2_DEVICE_NAME_SIZE];
void (*notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
struct v4l2_ctrl_handler *ctrl_handler; //
struct v4l2_prio_state prio;
struct kref ref;
void (*release)(struct v4l2_device *v4l2_dev);
};
3. struct v4l2_subdev
struct v4l2_subdev {
struct list_head list;
struct module *owner;
bool owner_v4l2_dev;
u32 flags;
struct v4l2_device *v4l2_dev; // 这个就是反过来指向哪个v4l2_device
const struct v4l2_subdev_ops *ops; // 重点
const struct v4l2_subdev_internal_ops *internal_ops; // 重点
struct v4l2_ctrl_handler *ctrl_handler;
char name[V4L2_SUBDEV_NAME_SIZE];
u32 grp_id;
void *dev_priv;
void *host_priv;
struct video_device *devnode;
struct device *dev;
struct fwnode_handle *fwnode;
struct list_head async_list;
struct v4l2_async_subdev *asd;
struct v4l2_async_notifier *notifier;
struct v4l2_async_notifier *subdev_notifier;
struct v4l2_subdev_platform_data *pdata;
};
1. 视频设备通用的操作:初始化,加载FW,上电和reset,等等
2. 视频设备特有的操作:设置帧率,裁剪图像,开关视频,等等
3.摄像头传感器操作
struct v4l2_subdev_ops {
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_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); // sudev初始化IO引脚
int (*init)(struct v4l2_subdev *sd, u32 val); //初始化传感器
int (*load_fw)(struct v4l2_subdev *sd); //加载固件
int (*reset)(struct v4l2_subdev *sd, u32 val); //reset
int (*s_gpio)(struct v4l2_subdev *sd, u32 val); // gpio设置
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);
};
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 (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect);
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 (*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 (*g_mbus_config)(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg);
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);
};
/**
* 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
* &struct &v4l2_input
*
* @s_stream: used to notify the driver that a video stream will start or has
* stopped.
*
* @g_pixelaspect: callback to return the pixelaspect ratio.
*
* @g_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
* ioctl handler code.
*
* @s_frame_interval: callback for VIDIOC_SUBDEV_S_FRAME_INTERVAL()
* 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_sensor_ops - v4l2-subdev sensor operations
* @g_skip_top_lines: number of lines at the top of the image to be skipped.
* This is needed for some sensors, which always corrupt
* several top lines of the output image, or which send their
* metadata in them.
* @g_skip_frames: number of frames to skip at stream start. This is needed for
* buggy sensors that generate faulty frames when they are
* turned on.
*/
struct v4l2_subdev_sensor_ops {
int (*g_skip_top_lines)(struct v4l2_subdev *sd, u32 *lines);
int (*g_skip_frames)(struct v4l2_subdev *sd, u32 *frames);
};
4. struct vb2_queue
struct vb2_queue {
unsigned int type; // 队列类型
unsigned int io_modes; //队列访问方式
struct device *dev;
unsigned long dma_attrs;
struct mutex *lock;
void *owner;
const struct vb2_ops *ops; //队列操作集 重点
const struct vb2_mem_ops *mem_ops; // 缓存操作集 重点
const struct vb2_buf_ops *buf_ops;
void *drv_priv;
unsigned int buf_struct_size;
u32 timestamp_flags;
gfp_t gfp_flags;
u32 min_buffers_needed;
struct device *alloc_devs[VB2_MAX_PLANES];
/* private: internal use only */
struct mutex mmap_lock;
unsigned int memory;
enum dma_data_direction dma_dir;
struct vb2_buffer *bufs[VB2_MAX_FRAME];
unsigned int num_buffers;
struct list_head queued_list; // 链表
unsigned int queued_count; //缓存数量
atomic_t owned_by_drv_count;
struct list_head done_list;
spinlock_t done_lock;
wait_queue_head_t done_wq;
unsigned int streaming:1;
unsigned int start_streaming_called:1;
unsigned int error:1;
unsigned int waiting_for_buffers:1;
unsigned int is_multiplanar:1;
unsigned int is_output:1;
unsigned int copy_timestamp:1;
unsigned int last_buffer_dequeued:1;
struct vb2_fileio_data *fileio;
struct vb2_threadio_data *threadio;
};
/**
* struct vb2_ops - driver-specific callbacks.
*
* These operations are not called from interrupt context except where
* mentioned specifically.
*
* @queue_setup: called from VIDIOC_REQBUFS() and VIDIOC_CREATE_BUFS()
* handlers before memory allocation. It can be called
* twice: if the original number of requested buffers
* could not be allocated, then it will be called a
* second time with the actually allocated number of
* buffers to verify if that is OK.
* The driver should return the required number of buffers
* in \*num_buffers, the required number of planes per
* buffer in \*num_planes, the size of each plane should be
* set in the sizes\[\] array and optional per-plane
* allocator specific device in the alloc_devs\[\] array.
* When called from VIDIOC_REQBUFS(), \*num_planes == 0,
* the driver has to use the currently configured format to
* determine the plane sizes and \*num_buffers is the total
* number of buffers that are being allocated. When called
* from VIDIOC_CREATE_BUFS(), \*num_planes != 0 and it
* describes the requested number of planes and sizes\[\]
* contains the requested plane sizes. In this case
* \*num_buffers are being allocated additionally to
* q->num_buffers. If either \*num_planes or the requested
* sizes are invalid callback must return %-EINVAL.
* @wait_prepare: release any locks taken while calling vb2 functions;
* it is called before an ioctl needs to wait for a new
* buffer to arrive; required to avoid a deadlock in
* blocking access type.
* @wait_finish: reacquire all locks released in the previous callback;
* required to continue operation after sleeping while
* waiting for a new buffer to arrive.
* @buf_init: called once after allocating a buffer (in MMAP case)
* or after acquiring a new USERPTR buffer; drivers may
* perform additional buffer-related initialization;
* initialization failure (return != 0) will prevent
* queue setup from completing successfully; optional.
* @buf_prepare: called every time the buffer is queued from userspace
* and from the VIDIOC_PREPARE_BUF() ioctl; drivers may
* perform any initialization required before each
* hardware operation in this callback; drivers can
* access/modify the buffer here as it is still synced for
* the CPU; drivers that support VIDIOC_CREATE_BUFS() must
* also validate the buffer size; if an error is returned,
* the buffer will not be queued in driver; optional.
* @buf_finish: called before every dequeue of the buffer back to
* userspace; the buffer is synced for the CPU, so drivers
* can access/modify the buffer contents; drivers may
* perform any operations required before userspace
* accesses the buffer; optional. The buffer state can be
* one of the following: %DONE and %ERROR occur while
* streaming is in progress, and the %PREPARED state occurs
* when the queue has been canceled and all pending
* buffers are being returned to their default %DEQUEUED
* state. Typically you only have to do something if the
* state is %VB2_BUF_STATE_DONE, since in all other cases
* the buffer contents will be ignored anyway.
* @buf_cleanup: called once before the buffer is freed; drivers may
* perform any additional cleanup; optional.
* @start_streaming: called once to enter 'streaming' state; the driver may
* receive buffers with @buf_queue callback
* before @start_streaming is called; the driver gets the
* number of already queued buffers in count parameter;
* driver can return an error if hardware fails, in that
* case all buffers that have been already given by
* the @buf_queue callback are to be returned by the driver
* by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED
* or %VB2_BUF_STATE_REQUEUEING. If you need a minimum
* number of buffers before you can start streaming, then
* set &vb2_queue->min_buffers_needed. If that is non-zero
* then @start_streaming won't be called until at least
* that many buffers have been queued up by userspace.
* @stop_streaming: called when 'streaming' state must be disabled; driver
* should stop any DMA transactions or wait until they
* finish and give back all buffers it got from &buf_queue
* callback by calling vb2_buffer_done() with either
* %VB2_BUF_STATE_DONE or %VB2_BUF_STATE_ERROR; may use
* vb2_wait_for_all_buffers() function
* @buf_queue: passes buffer vb to the driver; driver may start
* hardware operation on this buffer; driver should give
* the buffer back by calling vb2_buffer_done() function;
* it is allways called after calling VIDIOC_STREAMON()
* ioctl; might be called before @start_streaming callback
* if user pre-queued buffers before calling
* VIDIOC_STREAMON().
*/
struct vb2_ops {
int (*queue_setup)(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], struct device *alloc_devs[]);
void (*wait_prepare)(struct vb2_queue *q); //调用vb2功能时加锁
void (*wait_finish)(struct vb2_queue *q); //调用vb2功能时释放锁
int (*buf_init)(struct vb2_buffer *vb); // 分配缓存 调用一次
int (*buf_prepare)(struct vb2_buffer *vb); // 缓存就绪
void (*buf_finish)(struct vb2_buffer *vb); // 缓存完成
void (*buf_cleanup)(struct vb2_buffer *vb); //释放缓存 调用一次
int (*start_streaming)(struct vb2_queue *q, unsigned int count); //开启视频流
void (*stop_streaming)(struct vb2_queue *q); // 关闭视频流
void (*buf_queue)(struct vb2_buffer *vb); //passes buffer vb to the driver
};
/**
* struct vb2_mem_ops - memory handling/memory allocator operations.
* @alloc: allocate video memory and, optionally, allocator private data,
* return ERR_PTR() on failure or a pointer to allocator private,
* per-buffer data on success; the returned private structure
* will then be passed as @buf_priv argument to other ops in this
* structure. Additional gfp_flags to use when allocating the
* are also passed to this operation. These flags are from the
* gfp_flags field of vb2_queue.
* @put: inform the allocator that the buffer will no longer be used;
* usually will result in the allocator freeing the buffer (if
* no other users of this buffer are present); the @buf_priv
* argument is the allocator private per-buffer structure
* previously returned from the alloc callback.
* @get_dmabuf: acquire userspace memory for a hardware operation; used for
* DMABUF memory types.
* @get_userptr: acquire userspace memory for a hardware operation; used for
* USERPTR memory types; vaddr is the address passed to the
* videobuf layer when queuing a video buffer of USERPTR type;
* should return an allocator private per-buffer structure
* associated with the buffer on success, ERR_PTR() on failure;
* the returned private structure will then be passed as @buf_priv
* argument to other ops in this structure.
* @put_userptr: inform the allocator that a USERPTR buffer will no longer
* be used.
* @attach_dmabuf: attach a shared &struct dma_buf for a hardware operation;
* used for DMABUF memory types; dev is the alloc device
* dbuf is the shared dma_buf; returns ERR_PTR() on failure;
* allocator private per-buffer structure on success;
* this needs to be used for further accesses to the buffer.
* @detach_dmabuf: inform the exporter of the buffer that the current DMABUF
* buffer is no longer used; the @buf_priv argument is the
* allocator private per-buffer structure previously returned
* from the attach_dmabuf callback.
* @map_dmabuf: request for access to the dmabuf from allocator; the allocator
* of dmabuf is informed that this driver is going to use the
* dmabuf.
* @unmap_dmabuf: releases access control to the dmabuf - allocator is notified
* that this driver is done using the dmabuf for now.
* @prepare: called every time the buffer is passed from userspace to the
* driver, useful for cache synchronisation, optional.
* @finish: called every time the buffer is passed back from the driver
* to the userspace, also optional.
* @vaddr: return a kernel virtual address to a given memory buffer
* associated with the passed private structure or NULL if no
* such mapping exists.
* @cookie: return allocator specific cookie for a given memory buffer
* associated with the passed private structure or NULL if not
* available.
* @num_users: return the current number of users of a memory buffer;
* return 1 if the videobuf layer (or actually the driver using
* it) is the only user.
* @mmap: setup a userspace mapping for a given memory buffer under
* the provided virtual memory region.
*
* Those operations are used by the videobuf2 core to implement the memory
* handling/memory allocators for each type of supported streaming I/O method.
*
* .. note::
* #) Required ops for USERPTR types: get_userptr, put_userptr.
*
* #) Required ops for MMAP types: alloc, put, num_users, mmap.
*
* #) Required ops for read/write access types: alloc, put, num_users, vaddr.
*
* #) Required ops for DMABUF types: attach_dmabuf, detach_dmabuf,
* map_dmabuf, unmap_dmabuf.
*/
struct vb2_mem_ops {
void *(*alloc)(struct device *dev, unsigned long attrs,
unsigned long size,
enum dma_data_direction dma_dir,
gfp_t gfp_flags); // 分配缓存
void (*put)(void *buf_priv); //释放缓存
struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags); //得到DMA缓存
void *(*get_userptr)(struct device *dev, unsigned long vaddr,
unsigned long size,
enum dma_data_direction dma_dir); //得到用户缓存
void (*put_userptr)(void *buf_priv); // 释放用户缓存
void (*prepare)(void *buf_priv); //准备
void (*finish)(void *buf_priv); //完成
void *(*attach_dmabuf)(struct device *dev,
struct dma_buf *dbuf,
unsigned long size,
enum dma_data_direction dma_dir); //绑定dma
void (*detach_dmabuf)(void *buf_priv); //解除dma
int (*map_dmabuf)(void *buf_priv); // 映射dma
void (*unmap_dmabuf)(void *buf_priv); //解映射
void *(*vaddr)(void *buf_priv); //返回内核虚拟地址
void *(*cookie)(void *buf_priv);
unsigned int (*num_users)(void *buf_priv); //用户缓存数量
int (*mmap)(void *buf_priv, struct vm_area_struct *vma);
};