foreword

Earlier we learned about the basics of some cameras “Camera Basics”. Let’s take a look at the driver framework provided by Linux for the camera.

Introduction to V4L2

V4L2 (Video Linux Two), is a driver framework driver framework designed to support the Linux kernel. The operation interface layer (ioctl) set for the application is to provide its devices in a wider range, and they are only real video devices on the original, so they are the real camera design.

V4L2 framework

In the application layer, the device node can be displayed in /dev, and the program opens the device device to discover the application 0 and video screen in our device directory. video1, video2… These device nodes are registered at the core layer.

v4l2-dev.c) acts as a link between the previous and the next. It will set a unified v4l2_fops for each device registered in the core layer. These unified driver interfaces will eventually call the fops of the video_device of the driver.

important structure

video equipment

video equipment

//represents a video device

struct video_device {

#if defined(CONFIG_MEDIA_CONTROLLER);

struct media_entity entity;

struct media_intf_devnode *intf_devnode;

struct media_pipeline pipe;

#endif;

const struct v4l2_file_operations *fops; //File operation interface (dev/videoX)

u32 device_caps; //Device capabilities for v4l2_capabilities (structure defined by the application layer)

struct device dev;

struct cdev *cdev; //character device

struct v4l2_device *v4l2_dev; //V4L2设备

struct device *dev_parent;

struct v4l2_ctrl_handler *ctrl_handler; //The control handle corresponding to the device node

struct vb2_queue *queue;

struct v4l2_prio_state *prio;

char name[32]; //Video device name

enum vfl_devnode_type vfl_type; //V4L device type

enum vfl_devnode_direction vfl_dir; //V4L receiver/sender/m2m

int minor; //Sub device number, the main device is 81

u16 whether;

unsigned long flags;

int index;

spinlock_t fh_lock;

struct list_head fh_list;

int dev_debug;

v4l2_std_id tvnorms;

void (*release)(struct video_device *vdev); //video_device release()回调

const struct v4l2_ioctl_ops *ioctl_ops; //IOCTL回调

unsigned long valid_ioctls[BITS_TO_LONGS(BASE_VIDIOC_PRIVATE)];

struct mutex *lock;

};

v4l2_device

struct v4l2_device {

struct device *dev;

struct media_device *mdev;

struct list_head subdevs; //Used to track registered subdevs

spinlock_t lock;

char name[V4L2_DEVICE_NAME_SIZE]; //device name

void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);

struct v4l2_ctrl_handler *ctrl_handler; //Control handle

struct v4l2_prio_state prio; //The priority state of the device

struct kref ref; //reference

void (*release)(struct v4l2_device *v4l2_dev);//Called after the reference count is 0

};

Embedded in video_device, representing a v4l2 device instance.

v4l2_subdev

struct v4l2_subdev {

#if defined(CONFIG_MEDIA_CONTROLLER);

struct media_entity entity;

#endif;

struct list_head list; //subdev列表

struct module *owner;

bool owner_v4l2_dev;

u32 flags;

struct v4l2_device *v4l2_dev; //The attached v4l2_device

const struct v4l2_subdev_ops *ops; //subdev operation function

const struct v4l2_subdev_internal_ops *internal_ops;

struct v4l2_ctrl_handler *ctrl_handler; //Control handle

char name[V4L2_SUBDEV_NAME_SIZE]; //subdev名称

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;//subdev platform data

};

It is attached to a v4l2_device and represents a sub-device of a v4l2 device. There can be multiple sub_devices under v4l2_device.

v4l2_fh

struct v4l2_fh {

struct list_head list; //file handle list

struct video_device *vdev; //The attached video_device

struct v4l2_ctrl_handler *ctrl_handler;

enum v4l2_priority prio; //The priority of the file handle

wait_queue_head_t wait;

struct mutex subscribe_lock;

struct list_head subscribed; //List of subscribed events

struct list_head available; //available events

unsigned int navailable; //Number of events available

u32 sequence;

struct v4l2_m2m_ctx *m2m_ctx;

};

Tracked file handles are used for

The relationship between v4l2_device and v4l2_subdev:

The design purpose of subdev is for multiplexing, which is to control the use of one v4l2_device to connect multiple v4l2_subdevs. Such multiplexing is one camera to multiple cameras. Phone and rear camera.

In the V4L2 driver, use v4l2_device to represent the webcam (ISP). Use v4l2_subdev to represent a specific camera (Sensor).

v4l2_file_operations

//V4L2 device operation function

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 *);

};

v4l2_ioctl_ops

//IOCTL operation function

struct v4l2_ioctl_ops {

……

int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i);

int (*vidioc_g_fbuf)(struct file *file, void *fh, struct v4l2_framebuffer *a);

int (*vidioc_s_fbuf)(struct file *file, void *fh, const struct v4l2_framebuffer *a);

int (*vidioc_streamon)(struct file *file, void *fh, enum v4l2_buf_type i);

int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);

……

int (*vidioc_enum_framesizes)(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize);

int (*vidioc_enum_frameintervals)(struct file *file, void *fh, struct v4l2_frmivalenum *fival);

int (*vidioc_s_dv_timings)(struct file *file, void *fh, struct v4l2_dv_timings *timings);

int (*vidioc_g_dv_timings)(struct file *file, void *fh, struct v4l2_dv_timings *timings);

int (*vidioc_query_dv_timings)(struct file *file, void *fh, struct v4l2_dv_timings *timings);

int (*vidioc_enum_dv_timings)(struct file *file, void *fh, struct v4l2_enum_dv_timings *timings);

int (*vidioc_dv_timings_cap)(struct file *file, void *fh, struct v4l2_dv_timings_cap *cap);

int (*vidioc_g_edid)(struct file *file, void *fh, struct v4l2_edid *edid);

int (*vidioc_s_edid)(struct file *file, void *fh, struct v4l2_edid *edid);

int (*vidioc_subscribe_event)(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);

int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);

long (*vidioc_default)(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg);

};

v4l2_subdev_ops

//subdev operation function

struct v4l2_subdev_ops {

const struct v4l2_subdev_core_ops *core; //subdev core operation callback

const struct v4l2_subdev_tuner_ops *tuner; //Operation callback when the radio mode opens the v4l device

const struct v4l2_subdev_audio_ops *audio; //Audio related settings callback

const struct v4l2_subdev_video_ops *video; //Operation callback when video mode opens v4l device

const struct v4l2_subdev_vbi_ops *vbi; //Operation callback when the v4l device is opened in video mode through the vbi device node

const struct v4l2_subdev_ir_ops *ir; //IR (infrared) device operation function

const struct v4l2_subdev_sensor_ops *sensor; //sensor operation function

const struct v4l2_subdev_pad_ops *pad; //pad operation function

};

v4l22, so multi-part devices can be easily implemented according to actual device needs.

Part of the ioctl implemented in _ioctl_ops above ends up in the calling subfunction in v4l2_dev_ops.

API function

//Register/unregister video_device

int video_register_device(struct video_device *vdev, enum vfl_devnode_type type, int nr)

void video_unregister_device(struct video_device *vdev)

//Allocate/release video_device

struct video_device * __must_check video_device_alloc(void);

void video_device_release(struct video_device *vdev)

//Register/unregister v4l2_device

int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)

void v4l2_device_unregister(struct v4l2_device *v4l2_dev)

//Register/unregister v4l2_subdev (associated with v4l2_device and v4l2_subdev)

int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd)

void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)

//Initialize v4l2_subdev

void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops);

/********************************I2C subdev*************************************/

//Initialize v4l2_subdev, the subdev is an I2C device

void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,

const struct v4l2_subdev_ops *ops)

/*******************************SPI subdev************************************************/

//Initialize v4l2_subdev, the subdev is an SPI device

void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,

const struct v4l2_subdev_ops *ops)



Reviewing Editor: Liu Qing

Leave a Reply

Your email address will not be published.