ioctl VIDIOC_QUERYCAP流程分析
int result = ioctl(fd, VIDIOC_QUERYCAP, &caps);
第一步根据ioctl会调用到video_device的cdev结构的ops的unlocked_ioctl,也就是v4l2_ioctl
static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(filp);
int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) { //unlocked_ioctl定义了,所以走这里
if (vdev->lock && mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);//调用vivi_template的fops中的unlocked_ioctrl
if (vdev->lock)
mutex_unlock(vdev->lock);
} else if (vdev->fops->ioctl) {
... ...
}
... ...
}
也就是在vivi驱动probe时赋值的如下:
static struct video_device vivi_template = {
.name = "vivi",
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
.release = video_device_release,
.tvnorms = V4L2_STD_525_60,
.current_norm = V4L2_STD_NTSC_M,
};
最终会调用vivi_fops中的video_ioctl2
static const struct v4l2_file_operations vivi_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
.release = vivi_close,
.read = vivi_read,
.poll = vivi_poll,
.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = vivi_mmap,
};
long video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
//video_usercopy中会对arg进行一些判断后调用__video_do_ioctl函数
return video_usercopy(file, cmd, arg, __video_do_ioctl);
}
static long __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vfd = video_devdata(file);
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
void *fh = file->private_data;
struct v4l2_fh *vfh = NULL;
struct v4l2_format f_copy;
int use_fh_prio = 0;
long ret = -EINVAL;
... ...
switch (cmd) {
/* --- capabilities ------------------------------------------ */
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = (struct v4l2_capability *)arg;
if (!ops->vidioc_querycap)
break;
//下面是直接调用video_device的ioctl_ops
ret = ops->vidioc_querycap(file, fh, cap);
if (!ret)
dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
"version=0x%08x, "
"capabilities=0x%08x\n",
cap->driver, cap->card, cap->bus_info,
cap->version,
cap->capabilities);
break;
}
... ...
}
video_device的ioctl_ops也是在vivi_template里面赋值为vidioc_quercap
//这函数其实就填充了一些信息返回给应用层,driver,card, version, 能力
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct vivi_dev *dev = video_drvdata(file);
strcpy(cap->driver, "vivi");
strcpy(cap->card, "vivi");
strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
cap->version = VIVI_VERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
V4L2_CAP_READWRITE;
return 0;
}
总的来说调用流程如下: