The V4L2-related code is located in the linux-3.4driversmediavideo directory. The v4l2-dev.c file provides the device node to communicate with the user layer data, the device node in the dev directory to video0, video1 and other names appear. The statement for registering a character device is as follows: * Part3: Initializethecharacterdevice * vdev-cdevcdev _
V4L2-related code is located in the linux-3.4/drivers/media/video directory. The v4l2-dev.c file provides the device node to communicate with the user layer data, the device node in the/dev/directory with video0, video1 and other names appear. The statement for registering a character device is as follows:/* Part 3: Initialize the character device */vdev-cdev = cdev _
V4L2-related code is located in the linux-3.4/drivers/media/video directory.
The v4l2-dev.c file provides the device node to communicate with the user layer data, the device node in the/dev/directory with video0, video1 and other names appear. The statement for registering a character device is as follows:
/* Part 3: Initialize the character device */ vdev->cdev = cdev_alloc(); if (vdev->cdev == NULL) { ret = -ENOMEM; goto cleanup; } vdev->cdev->ops = &v4l2_fops; vdev->cdev->owner = owner; ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); if (ret < 0) { printk(KERN_ERR "%s: cdev_add failed\n", __func__); kfree(vdev->cdev); vdev->cdev = NULL; goto cleanup; } /* Part 4: register the device with sysfs */ vdev->dev.class = &video_class; vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); if (vdev->parent) vdev->dev.parent = vdev->parent; dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); ret = device_register(&vdev->dev);
You only need to call the video_register_device function to register a video_device to the V4L2 architecture. However, this is only a general program. The Camera driver is mainly used to implement the function of a sub-system of V4L2, the subsystem uses a v4l2_subdev struct to describe it. The last step is to register it in V4L2 only when function operations are completed as required by the system.
The sub-system implementation method varies with each platform. The code of the quanzhi A23 platform is analyzed here.
In the sunxi-vfe/vfe. c file, the platform resources of the front and back cameras are registered as platform. If the matching process is ignored, the vfe_probe function will be called. In probe, you can see the v4l2_i2c_new_subdev_board function:
/* Create the i2c client */ if (info->addr == 0 && probe_addrs) client = i2c_new_probed_device(adapter, info, probe_addrs, NULL); else client = i2c_new_device(adapter, info);............................... /* Register with the v4l2_device which increases the module's use count as well. */ if (v4l2_device_register_subdev(v4l2_dev, sd)) sd = NULL;
The client has been analyzed in the previous article on I2C driver. It is obvious that the knowledge of the driver is interlocking. According to the analysis in the article on I2C driver, we can see that the client is being obtained, device_register (& client-> dev) is called. According to the model relationship between device and device_driver, the bus where the device is located matches, and the device is on the i2c bus, according to the I2C match function, device_driver with the same name will be matched. Let's assume that the name of i2c_client is "ov5460", so let's look at it in ov5460.c:
static struct i2c_driver sensor_driver = { .driver = { .owner = THIS_MODULE, .name = SENSOR_NAME, }, .probe = sensor_probe, .remove = sensor_remove, .id_table = sensor_id,};
Undoubtedly, the sensor_probe function will be called:
static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *id){ struct v4l2_subdev *sd; struct sensor_info *info;// int ret; info = kzalloc(sizeof(struct sensor_info), GFP_KERNEL); if (info == NULL) return -ENOMEM; sd = &info->sd; glb_sd = sd; v4l2_i2c_subdev_init(sd, client, &sensor_ops); info->fmt = &sensor_formats[0]; info->af_first_flag = 1; info->init_first_flag = 1; info->auto_focus = 0; return 0;}
Here we see the v4l2_subdev struct mentioned above, the v4l2_i2c_subdev_init function will enter the v4l2-subdev.c for a series of initialization operations, and use i2c_set_clientdata (client, sd); Save the Subsystem Pointer for later removal. Here, the sensor_ops struct is the type supported by subsystems:
static const struct v4l2_subdev_ops sensor_ops = { .core = &sensor_core_ops, .video = &sensor_video_ops,};
Of course, Camera is video, and core is the core. It should be an indispensable operation. In fact, v4l2_subdev supports many types. All types are defined as follows:
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;};
Tuner should belong to the TV category, including ir, infrared, audio, and audio. Let's take a look at the operations to achieve video:
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 (*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_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, 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 (*enum_dv_presets) (struct v4l2_subdev *sd, struct v4l2_dv_enum_preset *preset); int (*s_dv_preset)(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset); int (*g_dv_preset)(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset); int (*query_dv_preset)(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset); 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 (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *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); 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);};
Too many operations are implemented by a specific camera, while the ov5640 only supports some of the operations:
static const struct v4l2_subdev_core_ops sensor_core_ops = { .g_chip_ident = sensor_g_chip_ident, .g_ctrl = sensor_g_ctrl, .s_ctrl = sensor_s_ctrl, .queryctrl = sensor_queryctrl, .reset = sensor_reset, .init = sensor_init, .s_power = sensor_power, .ioctl = sensor_ioctl,};
static const struct v4l2_subdev_video_ops sensor_video_ops = { .enum_mbus_fmt = sensor_enum_fmt, .enum_framesizes = sensor_enum_size, .try_mbus_fmt = sensor_try_fmt, .s_mbus_fmt = sensor_s_fmt, .s_parm = sensor_s_parm, .g_parm = sensor_g_parm, .g_mbus_config = sensor_g_mbus_config,};
Return to the v4l2_i2c_new_subdev_board function and call v4l2_device_register_subdev to register the sd to the subsystem.
Return to the probe function of vfe. c. The common operation is v4l2_subdev_call. In fact, this is a macro:
#define v4l2_subdev_call(sd, o, f, args...) \ (!(sd) ? -ENODEV : (((sd)->ops->o && (sd)->ops->o->f) ? \ (sd)->ops->o->f((sd) , ##args) : -ENOIOCTLCMD))
The advantage is to check whether the subsystem supports an operation. For example, the ov5640 mentioned above only supports the operations defined by sensor_core_ops and sensor_video_ops. Other errors are returned.
Finally:
vfd = video_device_alloc();*vfd = vfe_template;ret = video_register_device(vfd, VFL_TYPE_GRABBER, dev->id);
Assign a video_device space and assign a value. The assignment content is as follows:
static struct video_device vfe_template = { .name = "vfe", .fops = &vfe_fops, .ioctl_ops = &vfe_ioctl_ops, .release = video_device_release,};
Finally, it is registered in the V4L2 system.
If the analysis starts from the upper-layer ioctl call, vdev-> fops-> ioctl (filp, cmd, arg); vfe_fops is called here:
static const struct v4l2_file_operations vfe_fops = { .owner = THIS_MODULE, .open = vfe_open, .release = vfe_close, .read = vfe_read, .poll = vfe_poll, .ioctl = video_ioctl2, //.unlocked_ioctl = .mmap = vfe_mmap,};
Video_ioctl2 is to call the v4l2-ioctl.c generic ioctl for processing, it will check the user space parameters when the operation is legal. In this file, call the _ video_do_ioctl function, which contains all ioctl operation commands supported by V4L2. If the function is long, the code will not be pasted. In this ioctl, The vfe_ioctl_ops operation will be called:
static const struct v4l2_ioctl_ops vfe_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_enum_framesizes = vidioc_enum_framesizes, .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_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm,#ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf,#endif};
In these general function operations, v4l2_subdev_call is used to call specific Camera operations such as ov5640.