V4L2源代码之旅八:ioctl

转自:http://www.cnblogs.com/ronnydm/p/5796821.html

我们从代码的角度看看,如何调用到我们设定的ioctl。

1. 我们在驱动程序中,分配了结构体struct video_device,并做了设定,然后调用video_register_device进行注册。在video_device的设置中,存在ioctl的设置。

复制代码
/* kernel/drivers/media/video/ovisp/ovisp-vide.c */
static const struct v4l2_ioctl_ops ovisp_v4l2_ioctl_ops = {

    /* VIDIOC_QUERYCAP handler */
    .vidioc_querycap        = ovisp_vidioc_querycap,
    .vidioc_s_tlb_base              = ovisp_vidioc_s_tlb_base,
    /* Priority handling */
    .vidioc_s_priority        = ovisp_vidioc_s_priority,
    .vidioc_g_priority        = ovisp_vidioc_g_priority,

    .vidioc_enum_fmt_vid_cap    = ovisp_vidioc_enum_fmt_vid_cap,
    .vidioc_g_fmt_vid_cap        = ovisp_vidioc_g_fmt_vid_cap,
    .vidioc_try_fmt_vid_cap        = ovisp_vidioc_try_fmt_vid_cap,
    .vidioc_s_fmt_vid_cap        = ovisp_vidioc_s_fmt_vid_cap,
    .vidioc_enum_framesizes         = ovisp_vidioc_enum_framesizes,

    /*frame management*/
    .vidioc_reqbufs             = ovisp_vidioc_reqbufs,
    .vidioc_querybuf            = ovisp_vidioc_querybuf,
    .vidioc_qbuf                = ovisp_vidioc_qbuf,
    .vidioc_dqbuf               = ovisp_vidioc_dqbuf,

    /**/
    .vidioc_enum_input          = ovisp_vidioc_enum_input,
    .vidioc_g_input             = ovisp_vidioc_g_input,
    .vidioc_s_input             = ovisp_vidioc_s_input,

    /*isp function, modified according to spec*/
    .vidioc_g_ctrl                = ovisp_vidioc_g_ctrl,
    .vidioc_s_ctrl              = ovisp_vidioc_s_ctrl,
    .vidioc_cropcap             = ovisp_vidioc_cropcap,
    .vidioc_g_crop              = ovisp_vidioc_g_crop,
    .vidioc_s_crop              = ovisp_vidioc_s_crop,
    .vidioc_s_parm              = ovisp_vidioc_s_parm,
    .vidioc_g_parm              = ovisp_vidioc_g_parm,

    .vidioc_streamon            = ovisp_vidioc_streamon,
    .vidioc_streamoff           = ovisp_vidioc_streamoff,
};

static struct v4l2_file_operations ovisp_v4l2_fops = {
    .owner         = THIS_MODULE,
    .open         = ovisp_v4l2_open,
    .release     = ovisp_v4l2_close,
    .poll        = ovisp_v4l2_poll,
    .unlocked_ioctl    = video_ioctl2,
    .mmap         = ovisp_v4l2_mmap,
};

static struct video_device ovisp_camera = {
    .name = "ovisp-video-camera",
    .minor = -1,
    .release = video_device_release,
    .fops = &ovisp_v4l2_fops,
    .ioctl_ops = &ovisp_v4l2_ioctl_ops,
};
复制代码

  从上述代码可以看到,我们在驱动中只要这么设置,应用在调用IOCTL就是可以调用到我们设置的函数,那么如何调用呢?

2. v4l2-dev.c

在v4l2-dev.c中,我们看到,我们给应用设置的file_operations如下:

复制代码
static const struct file_operations v4l2_fops = {
    .owner = THIS_MODULE,
    .read = v4l2_read,
    .write = v4l2_write,
    .open = v4l2_open,
    .get_unmapped_area = v4l2_get_unmapped_area,
    .mmap = v4l2_mmap,
    .unlocked_ioctl = v4l2_ioctl,          // ioctl肯定是从这儿调的
#ifdef CONFIG_COMPAT
    .compat_ioctl = v4l2_compat_ioctl32,
#endif
    .release = v4l2_release,
    .poll = v4l2_poll,
    .llseek = no_llseek,
};
复制代码
复制代码
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) {                                  // 我们在ovisp-video.c中设置了vdev->fops->inlocked_ioctl = video_ioctl2
        if (vdev->lock && mutex_lock_interruptible(vdev->lock))
            return -ERESTARTSYS;
        if (video_is_registered(vdev))
            ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);          // 调用我们在ovisp-video.c中设置的video_ioctl2,那么video_ioctl2在哪里呢?
        if (vdev->lock)
            mutex_unlock(vdev->lock);
    } else if (vdev->fops->ioctl) {
        /* This code path is a replacement for the BKL. It is a major
         * hack but it will have to do for those drivers that are not
         * yet converted to use unlocked_ioctl.
         *
         * There are two options: if the driver implements struct
         * v4l2_device, then the lock defined there is used to
         * serialize the ioctls. Otherwise the v4l2 core lock defined
         * below is used. This lock is really bad since it serializes
         * completely independent devices.
         *
         * Both variants suffer from the same problem: if the driver
         * sleeps, then it blocks all ioctls since the lock is still
         * held. This is very common for VIDIOC_DQBUF since that
         * normally waits for a frame to arrive. As a result any other
         * ioctl calls will proceed very, very slowly since each call
         * will have to wait for the VIDIOC_QBUF to finish. Things that
         * should take 0.01s may now take 10-20 seconds.
         *
         * The workaround is to *not* take the lock for VIDIOC_DQBUF.
         * This actually works OK for videobuf-based drivers, since
         * videobuf will take its own internal lock.
         */
        static DEFINE_MUTEX(v4l2_ioctl_mutex);
        struct mutex *m = vdev->v4l2_dev ?
            &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;

        if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
            return -ERESTARTSYS;
        if (video_is_registered(vdev))
            ret = vdev->fops->ioctl(filp, cmd, arg);
        if (cmd != VIDIOC_DQBUF)
            mutex_unlock(m);
    } else
        ret = -ENOTTY;

    return ret;
}
复制代码

  video_ioctl2是Kernel提供的统一的接口(v4l2-ioctl.c):

复制代码
long video_ioctl2(struct file *file,
           unsigned int cmd, unsigned long arg)
{
    return video_usercopy(file, cmd, arg, __video_do_ioctl);  
  // 这句话意思是:1. 对用户发送的cmd进行合法性检测 2. 复制用户的arg参数到kernel空间 3. 调用__video_do_ioctl函数处理ioctl。
  // 所以我们接着看__video_do_ioctl函数
} EXPORT_SYMBOL(video_ioctl2);
复制代码
复制代码
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;
  ......switch (cmd) {
    /* --- capabilities ------------------------------------------ */
    case VIDIOC_QUERYCAP:
        ......break;

    /* --- priority ------------------------------------------ */
    case VIDIOC_G_PRIORITY:
        ......break;
    case VIDIOC_S_PRIORITY:
        ......break;

    /* --- capture ioctls ---------------------------------------- */
    case VIDIOC_ENUM_FMT:
        ......break;
    case VIDIOC_G_FMT:
     ......
break; case VIDIOC_S_FMT: ......break; case VIDIOC_TRY_FMT: ......break; /* FIXME: Those buf reqs could be handled here, with some changes on videobuf to allow its header to be included at videodev2.h or being merged at videodev2. */ case VIDIOC_REQBUFS: ......break; case VIDIOC_QUERYBUF: ......break; case VIDIOC_QBUF:
     ......
break; case VIDIOC_DQBUF: ......break; case VIDIOC_OVERLAY: ......break; case VIDIOC_G_FBUF: ......break; case VIDIOC_S_FBUF: .....break; case VIDIOC_STREAMON: .....break; case VIDIOC_STREAMOFF: ......break; /* ---------- tv norms ---------- */ case VIDIOC_ENUMSTD: ......break; case VIDIOC_G_STD: ......break; case VIDIOC_S_STD: ......break; case VIDIOC_QUERYSTD: ......break; /* ------ input switching ---------- */ /* FIXME: Inputs can be handled inside videodev2 */ case VIDIOC_ENUMINPUT: ......break; case VIDIOC_G_INPUT: ......break; case VIDIOC_S_INPUT: ......break; /* ------ output switching ---------- */ case VIDIOC_ENUMOUTPUT: ......break; case VIDIOC_G_OUTPUT: ......break; case VIDIOC_S_OUTPUT: ......break; /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: ......break; case VIDIOC_G_CTRL: ......break; case VIDIOC_S_CTRL: ......break; case VIDIOC_G_EXT_CTRLS: ......break; case VIDIOC_S_EXT_CTRLS: ......break; case VIDIOC_TRY_EXT_CTRLS: ......break; case VIDIOC_QUERYMENU: ......break; /* --- audio ---------------------------------------------- */ case VIDIOC_ENUMAUDIO: ......break; case VIDIOC_G_AUDIO: ......break; case VIDIOC_S_AUDIO: ......break; case VIDIOC_ENUMAUDOUT: ......break; case VIDIOC_G_AUDOUT: ......break; case VIDIOC_S_AUDOUT: ......break; case VIDIOC_G_MODULATOR: ......break; case VIDIOC_S_MODULATOR: ......break; case VIDIOC_G_CROP: ......break; case VIDIOC_S_CROP: ......break; case VIDIOC_CROPCAP: ......break; case VIDIOC_G_JPEGCOMP: ......break; case VIDIOC_S_JPEGCOMP: ......break; case VIDIOC_G_ENC_INDEX: ......break; case VIDIOC_ENCODER_CMD: ......break; case VIDIOC_TRY_ENCODER_CMD: ......break; case VIDIOC_G_PARM: ......break; case VIDIOC_S_PARM: ......break; case VIDIOC_G_TUNER: ......break; case VIDIOC_S_TUNER: ......break; case VIDIOC_G_FREQUENCY: .....break; case VIDIOC_S_FREQUENCY: ......break; case VIDIOC_G_SLICED_VBI_CAP: ......break; case VIDIOC_LOG_STATUS: ......break; #ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: ......break; case VIDIOC_DBG_S_REGISTER: ......break; #endif case VIDIOC_DBG_G_CHIP_IDENT: ......break; case VIDIOC_S_HW_FREQ_SEEK: ......break; case VIDIOC_ENUM_FRAMESIZES: ......break; case VIDIOC_ENUM_FRAMEINTERVALS: ......break; case VIDIOC_ENUM_DV_PRESETS: ......break; case VIDIOC_S_DV_PRESET: ......break; case VIDIOC_G_DV_PRESET: ......break; case VIDIOC_QUERY_DV_PRESET: ......break; case VIDIOC_S_DV_TIMINGS: .....break; case VIDIOC_G_DV_TIMINGS: ......break; case VIDIOC_DQEVENT: ......break; case VIDIOC_SUBSCRIBE_EVENT: ......break; case VIDIOC_UNSUBSCRIBE_EVENT: .....break; case VIDIOC_SET_TLB_BASE: ......break; default: ......break; } /* switch */return ret; }
复制代码

  我们可以看到,这个函数就是对ioctl命令的分发。到底有多少命令呢?

复制代码
/* kernel/include/linux/videodev2.h */
/*
 *    I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
 *
 */
#define VIDIOC_QUERYCAP         _IOR('V',  0, struct v4l2_capability)
#define VIDIOC_RESERVED          _IO('V',  1)
#define VIDIOC_ENUM_FMT         _IOWR('V',  2, struct v4l2_fmtdesc)
#define VIDIOC_G_FMT        _IOWR('V',  4, struct v4l2_format)
#define VIDIOC_S_FMT        _IOWR('V',  5, struct v4l2_format)
#define VIDIOC_REQBUFS        _IOWR('V',  8, struct v4l2_requestbuffers)
#define VIDIOC_QUERYBUF        _IOWR('V',  9, struct v4l2_buffer)
#define VIDIOC_G_FBUF         _IOR('V', 10, struct v4l2_framebuffer)
#define VIDIOC_S_FBUF         _IOW('V', 11, struct v4l2_framebuffer)
#define VIDIOC_OVERLAY         _IOW('V', 14, int)
#define VIDIOC_QBUF        _IOWR('V', 15, struct v4l2_buffer)
#define VIDIOC_DQBUF        _IOWR('V', 17, struct v4l2_buffer)
#define VIDIOC_STREAMON         _IOW('V', 18, int)
#define VIDIOC_STREAMOFF     _IOW('V', 19, int)
#define VIDIOC_G_PARM        _IOWR('V', 21, struct v4l2_streamparm)
#define VIDIOC_S_PARM        _IOWR('V', 22, struct v4l2_streamparm)
#define VIDIOC_G_STD         _IOR('V', 23, v4l2_std_id)
#define VIDIOC_S_STD         _IOW('V', 24, v4l2_std_id)
#define VIDIOC_ENUMSTD        _IOWR('V', 25, struct v4l2_standard)
#define VIDIOC_ENUMINPUT    _IOWR('V', 26, struct v4l2_input)
#define VIDIOC_G_CTRL        _IOWR('V', 27, struct v4l2_control)
#define VIDIOC_S_CTRL        _IOWR('V', 28, struct v4l2_control)
#define VIDIOC_G_TUNER        _IOWR('V', 29, struct v4l2_tuner)
#define VIDIOC_S_TUNER         _IOW('V', 30, struct v4l2_tuner)
#define VIDIOC_G_AUDIO         _IOR('V', 33, struct v4l2_audio)
#define VIDIOC_S_AUDIO         _IOW('V', 34, struct v4l2_audio)
#define VIDIOC_QUERYCTRL    _IOWR('V', 36, struct v4l2_queryctrl)
#define VIDIOC_QUERYMENU    _IOWR('V', 37, struct v4l2_querymenu)
#define VIDIOC_G_INPUT         _IOR('V', 38, int)
#define VIDIOC_S_INPUT        _IOWR('V', 39, int)
#define VIDIOC_G_OUTPUT         _IOR('V', 46, int)
#define VIDIOC_S_OUTPUT        _IOWR('V', 47, int)
#define VIDIOC_ENUMOUTPUT    _IOWR('V', 48, struct v4l2_output)
#define VIDIOC_G_AUDOUT         _IOR('V', 49, struct v4l2_audioout)
#define VIDIOC_S_AUDOUT         _IOW('V', 50, struct v4l2_audioout)
#define VIDIOC_G_MODULATOR    _IOWR('V', 54, struct v4l2_modulator)
#define VIDIOC_S_MODULATOR     _IOW('V', 55, struct v4l2_modulator)
#define VIDIOC_G_FREQUENCY    _IOWR('V', 56, struct v4l2_frequency)
#define VIDIOC_S_FREQUENCY     _IOW('V', 57, struct v4l2_frequency)
#define VIDIOC_CROPCAP        _IOWR('V', 58, struct v4l2_cropcap)
#define VIDIOC_G_CROP        _IOWR('V', 59, struct v4l2_crop)
#define VIDIOC_S_CROP         _IOW('V', 60, struct v4l2_crop)
#define VIDIOC_G_JPEGCOMP     _IOR('V', 61, struct v4l2_jpegcompression)
#define VIDIOC_S_JPEGCOMP     _IOW('V', 62, struct v4l2_jpegcompression)
#define VIDIOC_QUERYSTD           _IOR('V', 63, v4l2_std_id)
#define VIDIOC_TRY_FMT          _IOWR('V', 64, struct v4l2_format)
#define VIDIOC_ENUMAUDIO    _IOWR('V', 65, struct v4l2_audio)
#define VIDIOC_ENUMAUDOUT    _IOWR('V', 66, struct v4l2_audioout)
#define VIDIOC_G_PRIORITY        _IOR('V', 67, enum v4l2_priority)
#define VIDIOC_S_PRIORITY        _IOW('V', 68, enum v4l2_priority)
#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap)
#define VIDIOC_LOG_STATUS         _IO('V', 70)
#define VIDIOC_G_EXT_CTRLS    _IOWR('V', 71, struct v4l2_ext_controls)
#define VIDIOC_S_EXT_CTRLS    _IOWR('V', 72, struct v4l2_ext_controls)
#define VIDIOC_TRY_EXT_CTRLS    _IOWR('V', 73, struct v4l2_ext_controls)
#if 1
#define VIDIOC_ENUM_FRAMESIZES    _IOWR('V', 74, struct v4l2_frmsizeenum)
#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum)
#define VIDIOC_G_ENC_INDEX       _IOR('V', 76, struct v4l2_enc_idx)
#define VIDIOC_ENCODER_CMD      _IOWR('V', 77, struct v4l2_encoder_cmd)
#define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct v4l2_encoder_cmd)
#endif

#if 1
/* Experimental, meant for debugging, testing and internal use.
   Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
   You must be root to use these ioctls. Never use these in applications! */
#define    VIDIOC_DBG_S_REGISTER      _IOW('V', 79, struct v4l2_dbg_register)
#define    VIDIOC_DBG_G_REGISTER     _IOWR('V', 80, struct v4l2_dbg_register)

/* Experimental, meant for debugging, testing and internal use.
   Never use this ioctl in applications! */
#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident)
#endif

#define VIDIOC_S_HW_FREQ_SEEK     _IOW('V', 82, struct v4l2_hw_freq_seek)
#define    VIDIOC_ENUM_DV_PRESETS    _IOWR('V', 83, struct v4l2_dv_enum_preset)
#define    VIDIOC_S_DV_PRESET    _IOWR('V', 84, struct v4l2_dv_preset)
#define    VIDIOC_G_DV_PRESET    _IOWR('V', 85, struct v4l2_dv_preset)
#define    VIDIOC_QUERY_DV_PRESET    _IOR('V',  86, struct v4l2_dv_preset)
#define    VIDIOC_S_DV_TIMINGS    _IOWR('V', 87, struct v4l2_dv_timings)
#define    VIDIOC_G_DV_TIMINGS    _IOWR('V', 88, struct v4l2_dv_timings)
#define    VIDIOC_DQEVENT         _IOR('V', 89, struct v4l2_event)
#define    VIDIOC_SUBSCRIBE_EVENT     _IOW('V', 90, struct v4l2_event_subscription)
#define    VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)

/* Reminder: when adding new ioctls please add support for them to
   drivers/media/video/v4l2-compat-ioctl32.c as well! */

#define BASE_VIDIOC_PRIVATE    192        /* 192-255 are private */
/* For ingenic xburst jz4780 */
#define VIDIOC_SET_TLB_BASE         _IOW('V', BASE_VIDIOC_PRIVATE, unsigned int)
#endif /* __LINUX_VIDEODEV2_H */
复制代码

  从__video_do_ioctl可以很容易看到,如何调用我们注册的ioctl_ios即ovisp_v4l2_ioctl_ops。关于这些IOCTL的功能在代码中也有简单的注释,这些都比较容易理解。关于每个IOCTL的细节,在以后看到重要的我们在进行详述。


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值