V4l2 (video for Linux) supports multiple devices. It can have the following five interfaces:
1. Video Capture interface: the device of this application can be a high-frequency head or camera. The initial design of v4l2 is applied to this function. The following describes the application;
2. video output interface: a peripheral video image device that can drive a computer, such as a device that can output a TV signal format;
3. video overlay interface: The main function of this interface is to directly output the signals collected from the video capture device to the output device without going through the system CPU;
4. Video interval hidden signal interface (VBI Interface): This interface allows applications to access and transmit video signals during the invisibility period;
5. radio interface: it can be used to process audio streams received from an AM or FM high-frequency head device;
The main function of the v4l2 driver is to enable the program to discover and operate devices. it mainly uses a series of callback functions to implement these functions. set the frequency, frame rate, video compression format, and Image Parameters of High-frequency headers.
1. Porting v4l2
V4l2 provides three different APIs to transmit data from peripheral devices and user spaces. The following describes how to write a v4l2 driver for vivi (Drivers/Media/Video/Vivi. C. Note that it is a virtual device driver and does not deal with the actual hardware.
1. analyze several important data structures:
Vivi. C contains header file v4l2-device.h and v4l2-ioctl.h, The v4l2-device.h contains the v4l2-subdev.h, v4l2-subdev.h and contains the v4l2-common.h, v4l2-common.h contains the v4l2-dev.h.
The structures video_device and v4l2_file_operations are defined in the v4l2-dev.h;
The struct v4l2_ioctl_ops is defined in the v4l2-ioctl.h;
The struct v4l2_device is defined in the v4l2-device.h;
1) vivi_fops
Static const struct v4l2_file_operations vivi_fops = {
. Owner = this_module,
. Open = vivi_open,
. Release = vivi_close,
. Read = vivi_read,
. Poll = vivi_poll,
. IOCTL = video_ioctl2,/* v4l2 IOCTL handler */
. MMAP = vivi_mmap,
};
2) vivi_ioctl_ops
Static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
. Vidioc_querycap = vidioc_querycap,
. Vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
. Vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
. Vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
. Vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
. Vidioc_reqbufs = vidioc_reqbufs,
. Vidioc_querybuf = vidioc_querybuf,
. Vidioc_qbuf = vidioc_qbuf,
. Vidioc_dqbuf = vidioc_dqbuf,
. Vidioc_s_std = vidioc_s_std,
. Vidioc_enum_input = vidioc_enum_input,
. Vidioc_g_input = vidioc_g_input,
. Vidioc_s_input = vidioc_s_input,
. Vidioc_queryctrl = vidioc_queryctrl,
. Vidioc_g_ctrl = vidioc_g_ctrl,
. Vidioc_s_ctrl = vidioc_s_ctrl,
. Vidioc_streamon = vidioc_streamon,
. Vidioc_streamoff = vidioc_streamoff,
# Ifdef config_video_v4l1_compat
. Vidiocgmbuf = vidiocgmbuf,
# Endif
};
3) vivi_template
Static struct video_device vivi_template = {
. Name = "Vivi ",
. Fops = & vivi_fops,
. Ioctl_ops = & vivi_ioctl_ops,
. Minor =-1,
. Release = video_device_release,
. Tvnorms = v4l2_std_525_60,
. Current_norm = v4l2_std_ntsc_m,
};
Among them, the functions vivi_xxx and vidioc_xxx are implemented in vivi. C. If you want to implement v4l2 Interfaces Based on a hardware, these functions need to be implemented by calling the hardware driver.
4) vivi_dev
Struct vivi_dev {
Struct list_head vivi_devlist; // two-way linked list of the kernel, which is described in the kernel data structure.
Struct semaphore lock; // semaphore to prevent race access
Int users; // Number of users
/* Various device info */
Unsigned int resources;
Struct video_device video_dev; // This member is the core of this structure. It is a base class in Object-Oriented words.
Struct vivi_dmaqueue vidq; // DMA queue
/* Several counters */
Int H, M, S, US, jiffies; // timer Definition
Char timestr [13]; // other resource variables.
};
Such a variant structure is common in Linux C, which is also a powerful method to implement Object-Oriented Programming Using C. After this structure object is created, all operations are based on this structure or other structures derived from this structure.
5) vivi_fh
Struct vivi_fh {
Struct vivi_dev * dev;
/* Video capture */
Struct vivi_fmt * FMT;
Unsigned int width, height;
Struct videobuf_queue vb_vidq;
Enum v4l2_buf_type;
};
This structure is the deeper encapsulation of the vivi_dev structure. Based on this structure, more descriptive information is added, such as the video standard, video image size, and video buffer queue. When open is enabled, this structure is assigned to the private_data field in the file structure. Log out when the device is released. Other structures such as ioctl, MMAP, read, and write will all use this structure. In fact, the cdev compiled by the entire module is similar. Only the video device's base class is video_device, and the character device's base class is cdev.
2. Data Transmission Mode:
There are three data transmission methods between devices and applications:
1) read and write methods are similar to other device drivers, but they are very slow and cannot meet the requirements of data video streams;
2) Direct memory access can be transmitted through the ing (IO data stream, exchange the method pointing to the buffer pointer); this is a common method used by video devices, using MMAP () method, that is, to open up the memory in the kernel space, and then map this part of the memory in the program to the program space. If the device memory is available, it is directly mapped to the kernel of the device, which has higher performance.
3) asynchronous I/O port access, but this method has not been implemented in the v4l2 module. (Important: confirmation required)
MMAP in vivi is implemented using the second method, which is also a common method for video devices:
Static int
Vivi_mmap (struct file * file, struct vm_area_struct * VMA)
{
Struct vivi_fh * FH = file-> private_data;
Int ret;
Dprintk (1, "MMAP called, VMA = 0x % 08lx/N", (unsigned long) VMA );
Ret = videobuf_mmap_mapper (& FH-> vb_vidq, VMA );
Dprintk (1, "VMA start = 0x % 08lx, size = % lD, ret = % d/N ",
(Unsigned long) VMA-> vm_start,
(Unsigned long) VMA-> vm_end-(unsigned long) VMA-> vm_start,
RET );
Return ret;
}
Videobuf_mmap_mapper (& FH-> vb_vidq, VMA); this core function maps the device's I/O memory or device memory to the virtual memory opened for it by the system.
3. Device Control Implementation: IOCTL
Static int vivi_ioctl (struct inode * inode, struct file * file, unsigned int cmd, unsigned long Arg)
{
Return video_usercopy (inode, file, CMD, ARG, vivi_do_ioctl );
}
This function calls some commands to change or obtain the device parameters in the v4l2 module of the device.