V4L2源代码之旅八:ioctl
来源:互联网 发布:欧姆龙传感器淘宝 编辑:程序博客网 时间:2024/06/05 19:23
转自: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的细节,在以后看到重要的我们在进行详述。
阅读全文
0 0
- V4L2源代码之旅八:ioctl
- V4L2之ioctl错误
- V4L2源代码之旅二:V4L2 sub-device userspace API
- V4L2源代码之旅五:V4L2的起点和终点
- V4L2源代码之旅一:struct v4l2_subdev
- V4L2源代码之旅一:struct v4l2_device
- V4L2源代码之旅四:struct video_device
- V4L2源代码之旅六:源码追踪
- V4L2源代码之旅七:controls
- V4L2源代码之旅九:videobuf
- v4l2文档之——basic ioctl
- V4L2源代码之旅七:controls queryctrl ()
- V4L2源代码之旅三:I2C sub-device drivers
- V4L2源代码之旅十:videobuf主要结构体
- 四 v4l2文档之——basic ioctl
- 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl
- V4L2 IOCTL参数说明
- v4l2 编程接口 IOCTL
- php微信公众号开发,入门篇(实现了关注公众号发送欢迎信息,发关键词自回复)
- 最小生成树-prim算法
- 【java基础:IO】Java的IO知识整理!
- azkaban 编译使用方法
- Maven建立父子关系项目工程,建立依赖关系结构
- V4L2源代码之旅八:ioctl
- 机器学习和数据挖掘4——NumPy快速入门
- Corodva Plugin.xml 配置文件详解
- select标签设置只读的方法(下拉框不可选但可传值)
- 命令详解查看文件cat、more、less、head、tail、wc、grep、echo
- git revert 用法
- spring整合redis
- Framework not found IOSurface for architecture arm64
- CentOS7服务器安装和静态IP配置