一、V4L2框架分析
V4L2(video for linux version 2),是内核中视频设备的驱动框架,为上层访问视频设备提供统一接口。
V4L2整体框架如下图:
图中主要包括四个部分:
1. 字符设备驱动程序核心:V4L2本身就是一个字符设备,上层连接用户空间
2. V4L2驱动核心:构造通用的视频设备驱动框架,为上层操作提供统一接口
3. 平台V4L2驱动:在V4L2框架下,根据平台自身特性实现与平台相关的V4L2驱动部分,包括注册video_device和v4l2_dev
4. 具体的sensor驱动:主要用于上电、提供工作时钟、视频图像裁剪、流IO开启等和注册v4l2_subdev
图中各个结构体定义如下:
1. v4l2_device:
struct v4l2_device { /* dev->driver_data points to this struct. Note: dev might be NULL if there is no parent device as is the case with e.g. ISA devices. */ struct device *dev; /* used to keep track of the registered subdevs */ struct list_head subdevs; /* lock this struct; can be used by the driver as well if this struct is embedded into a larger struct. */ spinlock_t lock; /* unique device name, by default the driver name + bus ID */ char name[V4L2_DEVICE_NAME_SIZE]; /* notify callback called by some sub-devices. */ void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg); /* The control handler. May be NULL. */ struct v4l2_ctrl_handler *ctrl_handler; /* Device‘s priority state */ struct v4l2_prio_state prio; /* BKL replacement mutex. Temporary solution only. */ struct mutex ioctl_lock; /* Keep track of the references to this struct. */ struct kref ref; /* Release function that is called when the ref count goes to 0. */ void (*release)(struct v4l2_device *v4l2_dev); };
2. video_device:
struct video_device { const struct v4l2_file_operations *fops; /* 文件操作函数 */ struct device dev; /* v4l device */ struct cdev *cdev; /* character device */ struct device *parent; /* device parent */ struct v4l2_device *v4l2_dev; /* v4l2_device parent */ /* Control handler associated with this device node. May be NULL. */ struct v4l2_ctrl_handler *ctrl_handler; /* Priority state. If NULL, then v4l2_dev->prio will be used. */ struct v4l2_prio_state *prio; /* device info */ char name[32]; int vfl_type; /* ‘minor‘ is set to -1 if the registration failed */ int minor; u16 num; ... /* ioctl callbacks */ const struct v4l2_ioctl_ops *ioctl_ops; /* 控制函数 */ /* serialization lock */ struct mutex *lock; };
3. v4l2-subdev:
struct v4l2_subdev { #if defined(CONFIG_MEDIA_CONTROLLER) struct media_entity entity; #endif struct list_head list; struct module *owner; u32 flags; struct v4l2_device *v4l2_dev; const struct v4l2_subdev_ops *ops; /* Never call these internal ops from within a driver! */ const struct v4l2_subdev_internal_ops *internal_ops; /* The control handler of this subdev. May be NULL. */ struct v4l2_ctrl_handler *ctrl_handler; /* name must be unique */ char name[V4L2_SUBDEV_NAME_SIZE]; /* can be used to group similar subdevs, value is driver-specific */ u32 grp_id; /* pointer to private data */ void *dev_priv; void *host_priv; /* subdev device node */ struct video_device *devnode; };
v4l2_device在v4l2框架中是v4l2_subdev的父设备
在层次上,v4l2_device和video_device平等,video_device用于在/dev目录下生成设备节点文件
二、核心层提供的注册函数
1. 注册和注销v4l2_device:
/* 注册 */ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) /* 注销 */ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
注册函数调用关系如下:
/* 将设备与v4l2_device捆绑,并把v4l2设备放到driver data中 * 我们可以使用dev_get_drvdata(dev)获取到v4l2设备 */ v4l2_device_register(&intf->dev, &dev->vdev) -> dev_set_drvdata(dev, v4l2_dev); -> dev->p->driver_data = data; /* device->device_private为v4l2_device */
2. 注册和注销v4l2_subdev:
/* 注册 */ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd) /* 注销 */ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
注册函数调用关系如下:
v4l2_device_register_subdev() /* struct v4l2_ctrl_handler用于控制设备的亮度、饱和度等 */ -> v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); -> handler_new_ref(hdl, ctrl); /* 设置控制属性 */ -> v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0) -> v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); -> v4l2_ctrl_new(hdl, ops, ...); /* ops为v4l2_ctrl_ops,定义控制函数 */ -> list_add_tail(&ctrl->node, &hdl->ctrls); -> list_add_tail(&sd->list, &v4l2_dev->subdevs);
v4l2_subdev注册函数主要设置了设备的控制属性和控制函数,并把设备放入列表中。
控制函数结构体定义如下,读者有印象即可。
struct v4l2_ctrl_ops { int (*g_volatile_ctrl)(struct v4l2_ctrl *ctrl); /* 获取控制器值 */ int (*try_ctrl)(struct v4l2_ctrl *ctrl); /* 测试控制器值是否有效 */ int (*s_ctrl)(struct v4l2_ctrl *ctrl); /* 设置控制器值 */ };
3. 注册和注销video_device:
/* 注册 */ static inline int __must_check video_register_device(struct video_device *vdev, int type, int nr) /* 注销 */ void video_unregister_device(struct video_device *vdev)
注册函数调用关系如下:
video_register_device(vdev, VFL_TYPE_GRABBER, -1); -> __video_register_device(vdev, type, nr, 1, vdev->fops->owner); -> case VFL_TYPE_GRABBER: -> name_base = "video"; -> case VFL_TYPE_GRABBER: -> minor_offset = 0; -> minor_cnt = 64; -> vdev->minor = i + minor_offset; -> vdev->cdev = cdev_alloc(); -> vdev->cdev->ops = &v4l2_fops; -> cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); -> dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); /* 设备名为video%d */ -> device_register(&vdev->dev); -> device_add(dev);
video_device注册函数主要分配、设置并注册了cdev和device。
分析到这里,产生了两个问题:
1. chrdev_region()和class()在哪里被调用的?
2. v4l2_fops函数都做了什么?
我们先来决解第一个问题,两函数应该在初始化框架时被调用,初始化函数定义在v4l2-dev.c文件中:
1 static int __init videodev_init(void) 2 { 3 dev_t dev = MKDEV(VIDEO_MAJOR, 0); /* VIDEO_MAJOR = 81 */ 4 int ret; 5 6 ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME); 7 ... 8 ret = class_register(&video_class); 9 ... 10 return 0; 11 }
现在我们来看v4l2_fops的定义:
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, .release = v4l2_release, .poll = v4l2_poll, .llseek = no_llseek, };
首先从open()函数分析:
1 static int v4l2_open(struct inode *inode, struct file *filp) 2 { 3 struct video_device *vdev; 4 int ret = 0; 5 ... 6 vdev = video_devdata(filp); 7 ... 8 if (vdev->fops->open) { 9 ... 10 if (video_is_registered(vdev)) 11 ret = vdev->fops->open(filp); /* 最终会调用video_device->fops的open()函数 */ 12 ... 13 } 14 ... 15 }
read()和其他函数亦是如此:
1 static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off) 2 { 3 struct video_device *vdev = video_devdata(filp); 4 ... 5 if (video_is_registered(vdev)) 6 ret = vdev->fops->read(filp, buf, sz, off); 7 ... 8 } 9 10 static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 11 { 12 struct video_device *vdev = video_devdata(filp); 13 int ret = -ENODEV; 14 15 if (vdev->fops->unlocked_ioctl) { 16 ... 17 if (video_is_registered(vdev)) 18 ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); 19 ... 20 } 21 ... 22 }
可以看到v4l2_fops定义的函数在底层都会调用video_device的fops函数,因此我们可以在SI4内核项目中搜索“struct v4l2_file_operations ”:
在此我以vivi.c文件为例分析:
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, };
首先从open()函数分析:
1 int v4l2_fh_open(struct file *filp) 2 { 3 struct video_device *vdev = video_devdata(filp); 4 struct v4l2_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); 5 6 filp->private_data = fh; 7 ... 8 v4l2_fh_init(fh, vdev); /* 初始化v4l2_fh */ 9 v4l2_fh_add(fh); /* 注册v4l2_fh */ 10 return 0; 11 }
函数中的struct v4l2_fh为每一个被打开的节点维护一个文件句柄:
struct v4l2_fh { struct list_head list; struct video_device *vdev; struct v4l2_ctrl_handler *ctrl_handler; enum v4l2_priority prio; /* Events */ wait_queue_head_t wait; struct list_head subscribed; /* Subscribed events */ struct list_head available; /* Dequeueable event */ unsigned int navailable; u32 sequence; };
在此直接read()函数的调用关系:
vivi_read() -> vb2_read(&dev->vb_vidq, data, count, ppos, file->f_flags & O_NONBLOCK); -> __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); -> __vb2_init_fileio(q, read); /* 获取缓冲区的地址和大小 */ -> fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); -> fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); -> buf = &fileio->bufs[index]; -> buf->size = vb2_get_plane_payload(vb, 0); -> if (read) -> copy_to_user(data, buf->vaddr + buf->pos, count); -> else -> copy_from_user(buf->vaddr + buf->pos, data, count);
同样,在此直接ioctl()函数的调用关系:
video_ioctl2() /* 根据cmd,调用__video_do_ioctl()将数据拷贝到内核空间 */ -> video_usercopy(file, cmd, arg, __video_do_ioctl); -> __video_do_ioctl() -> struct video_device *vfd = video_devdata(file); /* v4l2_ioctl_ops:控制函数结构体 */ -> struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; -> case VIDIOC_QUERYCAP: /* 设备支持的能力 */ -> ops->vidioc_querycap(file, fh, cap); -> case VIDIOC_G_FMT: /* 获取格式、分辨率等 */ -> ps->vidioc_g_fmt_vid_cap(file, fh, f); -> case VIDIOC_QBUF: /* 把缓存区放入传输队列 */ -> ops->vidioc_qbuf(file, fh, p); -> case VIDIOC_DQBUF: /* 把缓存从队列中取出 */ -> ops->vidioc_dqbuf(file, fh, p); -> case VIDIOC_STREAMON: /* 启动视频传输 */ -> ops->vidioc_streamon(file, fh, i); -> case VIDIOC_STREAMOFF: /* 关闭视频传输 */ -> ops->vidioc_streamoff(file, fh, i);
其中,struct v4l2_ioctl_ops定义如下:
struct v4l2_ioctl_ops { /* ioctl callbacks */ /* VIDIOC_QUERYCAP handler */ int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap); ... /* VIDIOC_S_FMT handlers */ int (*vidioc_s_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_format *f); ... /* Buffer handlers */ int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b); int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b); int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); ... /* Stream on/off */ int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i); int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i); ...
分析完了这两个问题,下面我们来分析vivi.c文件
三、vivi.c文件分析
首先来分析init()函数的调用关系:
vivi_init(void) -> vivi_create_instance(i); -> v4l2_device_register(NULL, &dev->v4l2_dev); /* 设置ctrl属性(用于APP的ioctl) */ -> v4l2_ctrl_handler_init(hdl, 11); -> dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); -> dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); -> (struct vb2_queue *q)->ops = &vivi_video_qops; -> q->mem_ops = &vb2_vmalloc_memops; -> vb2_queue_init(q); -> init_waitqueue_head(&q->done_wq); /* 初始化等待队列头 */ -> struct video_device *vfd = video_device_alloc(); -> kzalloc(sizeof(struct video_device), GFP_KERNEL); -> *vfd = vivi_template; /* 设置video_device */ -> video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
根据上述过程,我们可以得到下图:
在init()函数中,struct vb2_queue是数据传输队列,结构体成员struct vb2_buffer是队列传输的基本单位
struct vb2_queue { enum v4l2_buf_type type; /* buffer类型 */ unsigned int io_modes; /* 传输类型 */ unsigned int io_flags; const struct vb2_ops *ops; /* buffer队列操作函数 */ const struct vb2_mem_ops *mem_ops; /* buffer memory操作函数 */ void *drv_priv; unsigned int buf_struct_size; /* private: internal use only */ enum v4l2_memory memory; struct vb2_buffer *bufs[VIDEO_MAX_FRAME]; /* buffer集合 */ unsigned int num_buffers; /* buffer个数 */ ... };
struct vb2_ops和struct vb2_mem_ops定义如下,我们一般不需要编写其中函数
struct vb2_ops { /* 队列初始化 */ int (*queue_setup)(struct vb2_queue *q, const struct v4l2_format *fmt, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]); /* 释放/获取设备操作锁 */ void (*wait_prepare)(struct vb2_queue *q); void (*wait_finish)(struct vb2_queue *q); /* buffer操作函数 */ int (*buf_init)(struct vb2_buffer *vb); int (*buf_prepare)(struct vb2_buffer *vb); int (*buf_finish)(struct vb2_buffer *vb); void (*buf_cleanup)(struct vb2_buffer *vb); /* 打开/关闭视频流 */ int (*start_streaming)(struct vb2_queue *q, unsigned int count); int (*stop_streaming)(struct vb2_queue *q); /* 把vb2_buffer传输给驱动程序 */ void (*buf_queue)(struct vb2_buffer *vb); }; struct vb2_mem_ops { /* 分配/释放视频缓冲 */ void *(*alloc)(void *alloc_ctx, unsigned long); void (*put)(void *buf_priv); /* 获取/释放用户空间视频缓冲区指针 */ void *(*get_userptr)(void *alloc_ctx, unsigned long vaddr, unsigned long size, int write); void (*put_userptr)(void *buf_priv); /* 用于缓存同步 */ void *(*vaddr)(void *buf_priv); void *(*cookie)(void *buf_priv); /* 返回当前用户空间的buffer数 */ unsigned int (*num_users)(void *buf_priv); /* 把缓冲区映射到用户空间 */ int (*mmap)(void *buf_priv, struct vm_area_struct *vma); };
细心的读者可以发现struct vb2_ops和struct v4l2_ioctl_ops在函数指针定义有重复的,下面我们以打开视频流函数为例分析:
/* struct vb2_ops */ static struct vb2_ops vivi_video_qops = { .start_streaming = start_streaming, ... }; /* struct v4l2_ioctl_ops */ static const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_streamon = vidioc_streamon, ... }; static int vidioc_streamon() -> vb2_streamon(&dev->vb_vidq, i); -> call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); /* 调用struct vb2_ops->start_streaming()函数 */ -> start_streaming()
通过分析可以确定struct v4l2_ioctl_ops是对struct vb2_ops的上层抽象。
struct vb2_buffer是队列传输的基本单位,结构体成员struct v4l2_buffer是传输核心,两结构体定义如下:
struct vb2_buffer { struct v4l2_buffer v4l2_buf; struct v4l2_plane v4l2_planes[VIDEO_MAX_PLANES]; struct vb2_queue *vb2_queue; unsigned int num_planes; /* Private: internal use only */ enum vb2_buffer_state state; struct list_head queued_entry; struct list_head done_entry; struct vb2_plane planes[VIDEO_MAX_PLANES]; }; struct v4l2_buffer { __u32 index; /* buffer序号 */ enum v4l2_buf_type type; /* buffer类型 */ __u32 bytesused; /* 缓缓冲区已经使用的byte数 */ __u32 flags; enum v4l2_field field; struct timeval timestamp; /* 捕捉图像的时间戳 */ struct v4l2_timecode timecode; __u32 sequence; /* memory location */ enum v4l2_memory memory; /* 表示使内存映射缓冲区还是用户空间缓冲区 */ union { __u32 offset; /* 内核缓冲区位置 */ unsigned long userptr; /* 用户空间缓冲区位置 */ struct v4l2_plane *planes; } m; __u32 length; /* 缓冲区大小 */ __u32 input; __u32 reserved; };
当开始流I/O时,图像帧会以struct v4l2_buffer的格式在应用和驱动间传输,它可能会有三个状态:
1. 在驱动的传入队列中,驱动对缓冲区进行处理,用户空间通过ioctl(..., VIDIOC_QBUF, ...)把缓冲区放入队列。对于视频捕获设备,传入队列中的缓冲区是空的,驱动会填充视频数据
2. 在驱动的传出队列中,驱动已经完成对缓冲区的处理。对于视频捕获设备,缓冲区已经填充了视频数据,在等待用户空间读取
3. 在用户空间的队列中,此时用户空间已经通过ioctl(..., VIDIOC_DQBUF, ...)读取缓冲区了,此时的驱动无法访问缓冲区
这三种状态的切换如下图:
分析完init()后,我们来看看struct video_device和struct v4l2_ioctl_ops的定义示例:
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在第二节分析过了,struct v4l2_ioctl_ops留在第五节分析。
四、vivi.c文件虚拟机测试
由于上面的分析涉及了太多结构体,那对于我们哪些才是重点呢?
本节我通过应用程序xawtv对调用关系进行分析,我们需要做的有以下几步:
1. 执行$ sudo apt-get install xawtv在虚拟机中安装xawtv
2. 在网站https://www.kraxel.org/releases/xawtv/下载源码xawtv-3.95.tar.gz,并创建SI4工程
3. 虚拟机连接摄像头,执行$ ls /dev/video*可以看到生成了/dev/video0,执行xawtv即可看到图像
4. 执行$ uname -a,根据虚拟机内核版本去http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/下载同版本的内核
5. 解压后把drivers/media/video目录单独取出,修改它的Makefile为:
KERN_DIR = /work/vmware/tools/linux-4.8 all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += vivi.o obj-m += videobuf-core.o obj-m += videobuf-vmalloc.o obj-m += v4l2-common.o
6. 编译后,由于vivi.ko模块涉及较多文件,为防止有模块未被载入,我们可以使用$ sudo modprobe vivi加载内核自带vivi驱动及其所需框架和文件,然后依次执行$ sudo rmmod vivi和$ sudo insmod ./vivi.ko安装我们编译的vivi模块
7. 执行$ ls /dev/video*查看虚拟摄像头,然后执行$ xawtv -c /dev/videox打开虚拟摄像头
五、ioctl()执行过程分析和v4l2_ioctl_ops必需函数指针的确定
在可以看到图像后,我们就可以通过应用程序xawtv对应用程序ioctl()执行过程进行分析。
查看程序系统调用过程可以使用strace命令实现:
$ strace -o xawtv.log xawtv /* 执行xawtv命令,调用过程会存储在xawtv.log文件中 */
在此我直接给出xawtv.log文件和后续所需文件:
文件链接:
https://pan.baidu.com/s/1sBgzVHQlDdYCAvR793uMhw
提取码为:2mqw
我们来猜测一下调用过程:
1. open()打开摄像头字符设备
2. 进行一系列ioctl(),ioctl()使用的宏是我们确定v4l2_ioctl_ops必需函数指针的重点
首先,我们搜索“open("/dev/video”,我们只需要关注第二次open(),因为第一次open()后面有close(),可以看到文件描述符为4
接下来,我们搜索“(4, ”,查看有哪些对应文件描述符的操作:
1 fstat64(4, {st_mode=S_IFREG|0600, st_size=57, ...}) = 0 2 read(4, "\1\0\0\fbook-desktop\0\0010\0\22MIT-MAGIC-C"..., 4096) = 57 3 read(4, "", 4096) = 0 4 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 5 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 6 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 7 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 8 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 9 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 10 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 11 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 12 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 13 read(4, "r_RS.UTF-8\[email protected]\t"..., 4096) = 4096 14 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 15 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 16 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 17 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 18 read(4, "59-1:\t\t\t\ten_ZA.ISO8859-1\nen_ZA.I"..., 4096) = 4096 19 read(4, "_ES.ISO8859-1\neu_ES.iso88591:\t\t\t"..., 4096) = 4096 20 read(4, "F-8\ngu_IN.utf8:\t\t\t\t\tgu_IN.UTF-8\n"..., 4096) = 4096 21 read(4, "o_KR.utf8:\t\t\t\t\tko_KR.UTF-8\nKO_KR"..., 4096) = 4096 22 read(4, "o_NO.utf8:\t\t\t\t\tno_NO.UTF-8\nnr:\t\t"..., 4096) = 4096 23 read(4, "O8859-2\nsl_SI.iso88592:\t\t\t\t\tsl_S"..., 4096) = 4096 24 read(4, "N\nvi_VN.tcvn5712:\t\t\t\t\tvi_VN.TCVN"..., 4096) = 4096 25 read(4, "9-9\nturkish.iso88599:\t\t\t\ttr_TR.I"..., 4096) = 456 26 read(4, "", 4096) = 0 27 fstat64(4, {st_mode=S_IFREG|0644, st_size=40344, ...}) = 0 28 read(4, "#\t$XdotOrg: lib/X11/nls/locale.d"..., 4096) = 4096 29 read(4, "59-1/XLC_LOCALE\t\t\tes_AR.ISO8859-"..., 4096) = 4096 30 read(4, "_FR.ISO8859-1\niso8859-15/XLC_LOC"..., 4096) = 4096 31 read(4, "8/XLC_LOCALE\t\t\tbe_BY.UTF-8\nen_US"..., 4096) = 4096 32 read(4, "en_US.UTF-8/XLC_LOCALE\t\t\tlo_LA.U"..., 4096) = 4096 33 fstat64(4, {st_mode=S_IFREG|0644, st_size=772, ...}) = 0 34 read(4, "# $Xorg: C,v 1.3 2000/08/17 19:"..., 4096) = 772 35 read(4, "", 4096) = 0 36 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 37 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 38 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 39 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 40 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 41 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 42 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 43 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 44 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 45 read(4, "r_RS.UTF-8\[email protected]\t"..., 4096) = 4096 46 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 47 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 48 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 49 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 50 read(4, "59-1:\t\t\t\ten_ZA.ISO8859-1\nen_ZA.I"..., 4096) = 4096 51 read(4, "_ES.ISO8859-1\neu_ES.iso88591:\t\t\t"..., 4096) = 4096 52 read(4, "F-8\ngu_IN.utf8:\t\t\t\t\tgu_IN.UTF-8\n"..., 4096) = 4096 53 read(4, "o_KR.utf8:\t\t\t\t\tko_KR.UTF-8\nKO_KR"..., 4096) = 4096 54 read(4, "o_NO.utf8:\t\t\t\t\tno_NO.UTF-8\nnr:\t\t"..., 4096) = 4096 55 read(4, "O8859-2\nsl_SI.iso88592:\t\t\t\t\tsl_S"..., 4096) = 4096 56 read(4, "N\nvi_VN.tcvn5712:\t\t\t\t\tvi_VN.TCVN"..., 4096) = 4096 57 read(4, "9-9\nturkish.iso88599:\t\t\t\ttr_TR.I"..., 4096) = 456 58 read(4, "", 4096) = 0 59 fstat64(4, {st_mode=S_IFREG|0644, st_size=40344, ...}) = 0 60 read(4, "#\t$XdotOrg: lib/X11/nls/locale.d"..., 4096) = 4096 61 read(4, "59-1/XLC_LOCALE\t\t\tes_AR.ISO8859-"..., 4096) = 4096 62 read(4, "_FR.ISO8859-1\niso8859-15/XLC_LOC"..., 4096) = 4096 63 read(4, "8/XLC_LOCALE\t\t\tbe_BY.UTF-8\nen_US"..., 4096) = 4096 64 read(4, "en_US.UTF-8/XLC_LOCALE\t\t\tlo_LA.U"..., 4096) = 4096 65 fstat64(4, {st_mode=S_IFREG|0644, st_size=772, ...}) = 0 66 read(4, "# $Xorg: C,v 1.3 2000/08/17 19:"..., 4096) = 772 67 read(4, "", 4096) = 0 68 fstat64(4, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0 69 read(4, "# Locale name alias data base.\n#"..., 4096) = 2570 70 read(4, "", 4096) = 0 71 fstat64(4, {st_mode=S_IFREG|0644, st_size=373, ...}) = 0 72 fstat64(4, {st_mode=S_IFREG|0644, st_size=26048, ...}) = 0 73 fstat64(4, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0 74 fstat64(4, {st_mode=S_IFREG|0644, st_size=59, ...}) = 0 75 fstat64(4, {st_mode=S_IFREG|0644, st_size=155, ...}) = 0 76 fstat64(4, {st_mode=S_IFREG|0644, st_size=77, ...}) = 0 77 fstat64(4, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0 78 fstat64(4, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 79 fstat64(4, {st_mode=S_IFREG|0644, st_size=52, ...}) = 0 80 fstat64(4, {st_mode=S_IFREG|0644, st_size=286, ...}) = 0 81 fstat64(4, {st_mode=S_IFREG|0644, st_size=966938, ...}) = 0 82 fstat64(4, {st_mode=S_IFREG|0644, st_size=2454, ...}) = 0 83 fstat64(4, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0 84 fstat64(4, {st_mode=S_IFREG|0644, st_size=256316, ...}) = 0 85 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 86 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 87 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 88 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 89 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 90 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 91 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 92 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 93 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 94 read(4, "r_RS.UTF-8\[email protected]\t"..., 4096) = 4096 95 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 96 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 97 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 98 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 99 read(4, "59-1:\t\t\t\ten_ZA.ISO8859-1\nen_ZA.I"..., 4096) = 4096 100 read(4, "_ES.ISO8859-1\neu_ES.iso88591:\t\t\t"..., 4096) = 4096 101 read(4, "F-8\ngu_IN.utf8:\t\t\t\t\tgu_IN.UTF-8\n"..., 4096) = 4096 102 read(4, "o_KR.utf8:\t\t\t\t\tko_KR.UTF-8\nKO_KR"..., 4096) = 4096 103 read(4, "o_NO.utf8:\t\t\t\t\tno_NO.UTF-8\nnr:\t\t"..., 4096) = 4096 104 read(4, "O8859-2\nsl_SI.iso88592:\t\t\t\t\tsl_S"..., 4096) = 4096 105 read(4, "N\nvi_VN.tcvn5712:\t\t\t\t\tvi_VN.TCVN"..., 4096) = 4096 106 read(4, "9-9\nturkish.iso88599:\t\t\t\ttr_TR.I"..., 4096) = 456 107 read(4, "", 4096) = 0 108 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 109 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 110 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 111 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 112 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 113 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 114 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 115 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 116 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 117 read(4, "r_RS.UTF-8\[email protected]\t"..., 4096) = 4096 118 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 119 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 120 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 121 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 122 fstat64(4, {st_mode=S_IFREG|0644, st_size=40344, ...}) = 0 123 read(4, "#\t$XdotOrg: lib/X11/nls/locale.d"..., 4096) = 4096 124 read(4, "59-1/XLC_LOCALE\t\t\tes_AR.ISO8859-"..., 4096) = 4096 125 read(4, "_FR.ISO8859-1\niso8859-15/XLC_LOC"..., 4096) = 4096 126 read(4, "8/XLC_LOCALE\t\t\tbe_BY.UTF-8\nen_US"..., 4096) = 4096 127 read(4, "en_US.UTF-8/XLC_LOCALE\t\t\tlo_LA.U"..., 4096) = 4096 128 read(4, "LE:\t\t\taf_ZA.ISO8859-1\niso8859-15"..., 4096) = 4096 129 read(4, "LE:\t\t\tes_MX.ISO8859-1\niso8859-1/"..., 4096) = 4096 130 read(4, "9-2/XLC_LOCALE:\t\t\tpl_PL.ISO8859-"..., 4096) = 4096 131 read(4, " byn_ER.UTF-8\nen_US.UT"..., 4096) = 4096 132 fstat64(4, {st_mode=S_IFREG|0644, st_size=4287, ...}) = 0 133 read(4, "# $XFree86: xc/nls/XLC_LOCALE/e"..., 4096) = 4096 134 read(4, "GB2312.1980-0:GL; GB2312.1980-0:"..., 4096) = 191 135 read(4, "", 4096) = 0 136 fstat64(4, {st_mode=S_IFREG|0644, st_size=18236, ...}) = 0 137 read(4, "\n! -----------------------------"..., 18236) = 18236 138 fcntl64(4, F_GETFD) = 0x1 (flags FD_CLOEXEC) 139 getdents64(4, /* 19 entries */, 32768) = 640 140 getdents64(4, /* 0 entries */, 32768) = 0 141 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\3\0\0004\0\0\0"..., 512) = 512 142 fstat64(4, {st_mode=S_IFREG|0644, st_size=5396, ...}) = 0 143 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\v\0\0004\0\0\0"..., 512) = 512 144 fstat64(4, {st_mode=S_IFREG|0644, st_size=13944, ...}) = 0 145 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\3\0\0004\0\0\0"..., 512) = 512 146 fstat64(4, {st_mode=S_IFREG|0644, st_size=5396, ...}) = 0 147 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\17\0\0004\0\0\0"..., 512) = 512 148 fstat64(4, {st_mode=S_IFREG|0644, st_size=22128, ...}) = 0 149 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000‘\0\0004\0\0\0"..., 512) = 512 150 fstat64(4, {st_mode=S_IFREG|0644, st_size=75356, ...}) = 0 151 fstat64(4, {st_mode=S_IFREG|0644, st_size=71399, ...}) = 0 152 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0\17\0\0004\0\0\0"..., 512) = 512 153 fstat64(4, {st_mode=S_IFREG|0644, st_size=38144, ...}) = 0 154 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\[email protected]\22\0\0004\0\0\0"..., 512) = 512 155 fstat64(4, {st_mode=S_IFREG|0644, st_size=103964, ...}) = 0 156 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360\30\0\0004\0\0\0"..., 512) = 512 157 fstat64(4, {st_mode=S_IFREG|0644, st_size=44184, ...}) = 0 158 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0\6\0\0004\0\0\0"..., 512) = 512 159 fstat64(4, {st_mode=S_IFREG|0644, st_size=5640, ...}) = 0 160 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\4\0\0004\0\0\0"..., 512) = 512 161 fstat64(4, {st_mode=S_IFREG|0644, st_size=5496, ...}) = 0 162 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0P\4\0\0004\0\0\0"..., 512) = 512 163 fstat64(4, {st_mode=S_IFREG|0644, st_size=5400, ...}) = 0 164 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`\4\0\0004\0\0\0"..., 512) = 512 165 fstat64(4, {st_mode=S_IFREG|0644, st_size=9640, ...}) = 0 166 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\3\0\0004\0\0\0"..., 512) = 512 167 fstat64(4, {st_mode=S_IFREG|0644, st_size=5400, ...}) = 0 168 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\3\0\0004\0\0\0"..., 512) = 512 169 fstat64(4, {st_mode=S_IFREG|0644, st_size=5400, ...}) = 0 170 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200\10\0\0004\0\0\0"..., 512) = 512 171 fstat64(4, {st_mode=S_IFREG|0644, st_size=9640, ...}) = 0 172 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260\n\0\0004\0\0\0"..., 512) = 512 173 fstat64(4, {st_mode=S_IFREG|0644, st_size=9704, ...}) = 0 174 fstat64(4, {st_mode=S_IFREG|0644, st_size=71399, ...}) = 0 175 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\3405\0\0004\0\0\0"..., 512) = 512 176 fstat64(4, {st_mode=S_IFREG|0644, st_size=121640, ...}) = 0 177 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\r\0\0004\0\0\0"..., 512) = 512 178 fstat64(4, {st_mode=S_IFREG|0644, st_size=13992, ...}) = 0 179 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\10\0\0004\0\0\0"..., 512) = 512 180 fstat64(4, {st_mode=S_IFREG|0644, st_size=13776, ...}) = 0 181 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\7\0\0004\0\0\0"..., 512) = 512 182 fstat64(4, {st_mode=S_IFREG|0644, st_size=9588, ...}) = 0 183 fstat64(4, {st_mode=S_IFREG|0644, st_size=8982, ...}) = 0 184 read(4, "! $Xorg: XKeysymDB,v 1.3 2000/08"..., 8982) = 8982 185 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0x9b40998) = -1 EINVAL (Invalid argument) 186 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0xbfaccd44) = 0 187 ioctl(4, VIDIOC_G_FMT or VT_SENDSIG, 0xbfaccc78) = 0 188 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 189 ioctl(4, 0xc02c564a, 0xbfaccb58) = -1 EINVAL (Invalid argument) 190 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 191 ioctl(4, 0xc02c564a, 0xbfaccb58) = -1 EINVAL (Invalid argument) 192 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 193 ioctl(4, 0xc02c564a, 0xbfaccb58) = -1 EINVAL (Invalid argument) 194 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 195 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 196 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 197 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = -1 EINVAL (Invalid argument) 198 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0xbfaccb84) = 0 199 ioctl(4, VIDIOC_G_INPUT, 0xbfacca2c) = 0 200 ioctl(4, VIDIOC_ENUMINPUT, 0xbfacca2c) = 0 201 fstat64(4, {st_mode=S_IFCHR|0660, st_rdev=makedev(81, 0), ...}) = 0 202 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0xbfacca78) = -1 EINVAL (Invalid argument) 203 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0x9b40998) = 0 204 fcntl64(4, F_SETFD, FD_CLOEXEC) = 0 205 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40acc) = 0 206 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40b18) = 0 207 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40b64) = 0 208 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40bb0) = 0 209 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40bfc) = -1 EINVAL (Invalid argument) 210 ioctl(4, VIDIOC_ENUMSTD, 0x9b40f8c) = 0 211 ioctl(4, VIDIOC_ENUMSTD, 0x9b40fcc) = 0 212 ioctl(4, VIDIOC_ENUMSTD, 0x9b4100c) = 0 213 ioctl(4, VIDIOC_ENUMSTD, 0x9b4104c) = 0 214 ioctl(4, VIDIOC_ENUMSTD, 0x9b4108c) = 0 215 ioctl(4, VIDIOC_ENUMSTD, 0x9b410cc) = 0 216 ioctl(4, VIDIOC_ENUMSTD, 0x9b4110c) = 0 217 ioctl(4, VIDIOC_ENUMSTD, 0x9b4114c) = -1 EINVAL (Invalid argument) 218 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4138c) = 0 219 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b413cc) = 0 220 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4140c) = 0 221 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4144c) = 0 222 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4148c) = 0 223 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b414cc) = 0 224 ioctl(4, VIDIOC_G_PARM, 0x9b40a00) = 0 225 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41b8c) = 0 226 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41bd0) = 0 227 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c14) = 0 228 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c58) = 0 229 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c9c) = -1 EINVAL (Invalid argument) 230 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41ce0) = 0 231 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41d24) = -1 EINVAL (Invalid argument) 232 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41d68) = -1 EINVAL (Invalid argument) 233 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41dac) = -1 EINVAL (Invalid argument) 234 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41df0) = -1 EINVAL (Invalid argument) 235 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41e34) = -1 EINVAL (Invalid argument) 236 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41e78) = -1 EINVAL (Invalid argument) 237 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41ebc) = -1 EINVAL (Invalid argument) 238 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f00) = -1 EINVAL (Invalid argument) 239 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f44) = -1 EINVAL (Invalid argument) 240 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f88) = -1 EINVAL (Invalid argument) 241 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41fcc) = -1 EINVAL (Invalid argument) 242 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42010) = -1 EINVAL (Invalid argument) 243 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42054) = -1 EINVAL (Invalid argument) 244 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42098) = -1 EINVAL (Invalid argument) 245 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b420dc) = -1 EINVAL (Invalid argument) 246 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42120) = -1 EINVAL (Invalid argument) 247 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42164) = -1 EINVAL (Invalid argument) 248 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b421a8) = -1 EINVAL (Invalid argument) 249 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b421ec) = -1 EINVAL (Invalid argument) 250 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42230) = -1 EINVAL (Invalid argument) 251 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42274) = -1 EINVAL (Invalid argument) 252 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b422b8) = -1 EINVAL (Invalid argument) 253 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b422fc) = -1 EINVAL (Invalid argument) 254 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42340) = -1 EINVAL (Invalid argument) 255 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42384) = -1 EINVAL (Invalid argument) 256 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b423c8) = -1 EINVAL (Invalid argument) 257 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4240c) = -1 EINVAL (Invalid argument) 258 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42450) = -1 EINVAL (Invalid argument) 259 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42494) = -1 EINVAL (Invalid argument) 260 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b424d8) = -1 EINVAL (Invalid argument) 261 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4251c) = -1 EINVAL (Invalid argument) 262 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42560) = -1 EINVAL (Invalid argument) 263 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b425a4) = -1 EINVAL (Invalid argument) 264 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b425e8) = -1 EINVAL (Invalid argument) 265 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4262c) = -1 EINVAL (Invalid argument) 266 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42670) = -1 EINVAL (Invalid argument) 267 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b426b4) = -1 EINVAL (Invalid argument) 268 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b426f8) = -1 EINVAL (Invalid argument) 269 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4273c) = -1 EINVAL (Invalid argument) 270 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42780) = -1 EINVAL (Invalid argument) 271 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b427c4) = -1 EINVAL (Invalid argument) 272 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42808) = -1 EINVAL (Invalid argument) 273 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4284c) = -1 EINVAL (Invalid argument) 274 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42890) = -1 EINVAL (Invalid argument) 275 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b428d4) = -1 EINVAL (Invalid argument) 276 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42918) = -1 EINVAL (Invalid argument) 277 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4295c) = -1 EINVAL (Invalid argument) 278 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b429a0) = -1 EINVAL (Invalid argument) 279 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b429e4) = -1 EINVAL (Invalid argument) 280 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42a28) = -1 EINVAL (Invalid argument) 281 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42a6c) = -1 EINVAL (Invalid argument) 282 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42ab0) = -1 EINVAL (Invalid argument) 283 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42af4) = -1 EINVAL (Invalid argument) 284 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42b38) = -1 EINVAL (Invalid argument) 285 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42b7c) = -1 EINVAL (Invalid argument) 286 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42bc0) = -1 EINVAL (Invalid argument) 287 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42c04) = -1 EINVAL (Invalid argument) 288 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42c48) = -1 EINVAL (Invalid argument) 289 ioctl(4, VIDIOC_G_STD, 0xbfacce08) = 0 290 ioctl(4, VIDIOC_G_INPUT, 0xbfacce1c) = 0 291 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 292 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 293 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 294 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 295 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce24) = 0 296 ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4) = 0 297 ioctl(4, VIDIOC_S_FMT or VT_RELDISP, 0xbfacc754) = 0 298 ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4) = 0 299 ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0x9b42d80) = 0 300 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0x9b42d94) = 0 301 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0x9b42dd8) = 0 302 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 303 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 304 ioctl(4, VIDIOC_STREAMON, 0xbfacca2c) = 0 305 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 306 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 307 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 308 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 309 ioctl(4, VIDIOC_S_INPUT, 0xbfacce84) = 0 310 ioctl(4, VIDIOC_S_STD, 0x9b40f90) = 0 311 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 312 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 313 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 314 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 315 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 316 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 317 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 318 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 319 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 320 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 321 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 322 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 323 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 324 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 325 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 326 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 327 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 328 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 329 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 330 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 331 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 332 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 333 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 334 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 335 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 336 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 337 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 338 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 339 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 340 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 341 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 342 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 343 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 344 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 345 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 346 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 347 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 348 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 349 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 350 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 351 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 352 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 353 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 354 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 355 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 356 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 357 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 358 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 359 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 360 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 361 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 362 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 363 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 364 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 365 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 366 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 367 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 368 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 369 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 370 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 371 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 372 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 373 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 374 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 375 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 376 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 377 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 378 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 379 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 380 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 381 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 382 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 383 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 384 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 385 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 386 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 387 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 388 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 389 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 390 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 391 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 392 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 393 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 394 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 395 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 396 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 397 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 398 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 399 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 400 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 401 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 402 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 403 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 404 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 405 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 406 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 407 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 408 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 409 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 410 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 411 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 412 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 413 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 414 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 415 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 416 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 417 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 418 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 419 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 420 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 421 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 422 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 423 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 424 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 425 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 426 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 427 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 428 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 429 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 430 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 431 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 432 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 433 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 434 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 435 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 436 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 437 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 438 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 439 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 440 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 441 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 442 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 443 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 444 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 445 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 446 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 447 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 448 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 449 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 450 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 451 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 452 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 453 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 454 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 455 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 456 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 457 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 458 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 459 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 460 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 461 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 462 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 463 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 464 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 465 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 466 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 467 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 468 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 469 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 470 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 471 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 472 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 473 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 474 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 475 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 476 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 477 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 478 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 479 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 480 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 481 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 482 ioctl(4, VIDIOC_STREAMOFF, 0xbfacc53c) = 0 483 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc48c) = 0 484 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc48c) = 0 485 ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0x9b42d80) = -1 EINVAL (Invalid argument) 486 ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4) = -1 EINVAL (Invalid argument) 487 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 488 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 489 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 490 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 491 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 492 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 493 ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0xbfacc70c) = 0 494 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc61c) = 0 495 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc61c) = 0 496 ioctl(4, VIDIOC_QBUF, 0xbfacc61c) = 0 497 ioctl(4, VIDIOC_QBUF, 0xbfacc61c) = 0 498 ioctl(4, VIDIOC_STREAMON, 0xbfacc65c) = 0 499 ioctl(4, VIDIOC_DQBUF, 0xbfacc6c8) = 0 500 ioctl(4, VIDIOC_QBUF, 0xbfacc61c) = 0
xawtv.log文件中open()函数之后调用了ioctl(4, VIDIOC_QUERYCAP, ...),因此文件描述符操作ioctl(4, VIDIOC_QUERYCAP, ...)上面的所有行不会涉及驱动底层
最后,我们可以根据文件描述符操作文件、xawtv.log和SI4工程确定ioctl()执行过程:
open("/dev/video0", O_RDWR|O_LARGEFILE) /* 1. 打开video0 */ ioctl(4, VIDIOC_QUERYCAP /* 2. 列举性能 */ ioctl(4, VIDIOC_G_FMT /* 3. 获得格式 */ for () -> ioctl(4, VIDIOC_ENUM_FMT /* 4. 列举格式 */ ioctl(4, VIDIOC_QUERYCAP /* 5. */ ioctl(4, VIDIOC_G_INPUT /* 6. 获取当前输入源 */ ioctl(4, VIDIOC_ENUMINPUT /* 7. 列举输入源 */ ioctl(4, VIDIOC_QUERYCTRL /* 8. 查询属性,如亮度范围、对比度范围 */ ioctl(4, VIDIOC_QUERYCAP /* 9. */ ioctl(4, VIDIOC_ENUMINPUT /* 10. */ for () -> ioctl(4, VIDIOC_ENUMINPUT /* 11. */ for () -> ioctl(4, VIDIOC_ENUMSTD /* 12.列举标准 */ for () -> ioctl(4, VIDIOC_ENUM_FMT /* 13. */ ioctl(4, VIDIOC_G_PARM /* 14. */ for () -> ioctl(4, VIDIOC_QUERYCTRL /* 15. */ ioctl(4, VIDIOC_G_STD /* 16.获取当前使用的标准 */ ioctl(4, VIDIOC_G_INPUT /* 17. */ ioctl(4, VIDIOC_G_CTRL /* 18.获取当前所使用的属性 */ ioctl(4, VIDIOC_TRY_FMT /* 19.测试摄像头支持的格式 */ ioctl(4, VIDIOC_S_FMT /* 20.设置摄像头格式 */ ioctl(4, VIDIOC_REQBUFS /* 21.请求系统分配缓冲区 */ ioctl(4, VIDIOC_QUERYBUF /* 22.查询所分配的缓冲区 */ for () -> ioctl(4, VIDIOC_QBUF /* 23.把缓冲区放入队列 */ ioctl(4, VIDIOC_STREAMON /* 24.启动摄像头 */ for () -> ioctl(4, VIDIOC_S_CTRL /* 25.设置属性 */ ioctl(4, VIDIOC_S_INPUT /* 26.设置输入源 */ ioctl(4, VIDIOC_S_STD /* 27.设置标准 */ for () -> select(5, [4] /* 28.查询文件描述符4是否有数据 */ -> ioctl(4, VIDIOC_DQBUF /* 29.把缓冲区从队列中取出 */ -> /* 处理数据 */ -> ioctl(4, VIDIOC_QBUF /* 30.把缓冲区放入队列 */ ioctl(4, VIDIOC_STREAMOFF /* 31.关闭摄像头 */
在分析完ioctl()的执行过程后,我们需要在SI4工程文件drv0-v4l2.c文件中搜索ioctl()各个宏,确定v4l2_ioctl_ops必需的函数指针:
/** 1~2被v4l2_open(char *device)调用 */ open("/dev/video0", O_RDWR|O_LARGEFILE) /* 1. 打开video0 */ ioctl(4, VIDIOC_QUERYCAP /* 2. 列举性能 */ /** 3~10没有看到调用过程,可能源码和应用程序不一致,略 */ /** 11~15被get_device_capabilities(h)调用 */ for () -> ioctl(4, VIDIOC_ENUMINPUT /* 11. */ for () -> ioctl(4, VIDIOC_ENUMSTD /* 12.列举标准 */ for () -> ioctl(4, VIDIOC_ENUM_FMT /* 13. */ ioctl(4, VIDIOC_G_PARM /* 14. */ for () -> ioctl(4, VIDIOC_QUERYCTRL /* 15. */ /** 16~18被v4l2_read_attr()调用 */ ioctl(4, VIDIOC_G_STD /* 16.获取当前使用的标准 */ ioctl(4, VIDIOC_G_INPUT /* 17. */ ioctl(4, VIDIOC_G_CTRL /* 18.获取当前所使用的属性 */ /** 19~20被v4l2_overlay()调用 */ ioctl(4, VIDIOC_TRY_FMT /* 19.测试摄像头支持的格式 */ ioctl(4, VIDIOC_S_FMT /* 20.设置摄像头格式 */ /** 21~24被v4l2_start_streaming()调用 */ ioctl(4, VIDIOC_REQBUFS /* 21.请求系统分配缓冲区 */ ioctl(4, VIDIOC_QUERYBUF /* 22.查询所分配的缓冲区 */ for () -> ioctl(4, VIDIOC_QBUF /* 23.把缓冲区放入队列 */ -> h->buf_me[i].data = mmap(...); ioctl(4, VIDIOC_STREAMON /* 24.启动摄像头 */ /** 25~27被v4l2_write_attr()调用 */ ioctl(4, VIDIOC_S_CTRL /* 25.设置属性 */ ioctl(4, VIDIOC_S_INPUT /* 26.设置输入源 */ ioctl(4, VIDIOC_S_STD /* 27.设置标准 */ /** 28~29被v4l2_waiton()调用 * 30被v4l2_queue_buffer()调用 * v4l2_waiton()和v4l2_queue_buffer()被v4l2_nextframe()调用 */ for () -> select(5, [4] /* 28.查询文件描述符4是否有数据 */ -> ioctl(4, VIDIOC_DQBUF /* 29.把缓冲区从队列中取出 */ -> /* 处理数据,之前使用mmap()获得了缓冲区的地址 */ -> ioctl(4, VIDIOC_QBUF /* 30.把缓冲区放入队列 */ /** 31被v4l2_stop_streaming()调用 */ ioctl(4, VIDIOC_STREAMOFF /* 31.关闭摄像头 */
剩下这么多宏,有哪个是可以省略的呢?
我们现在要回到虚拟机内核的vivi.c中vivi_ioctl_ops逐个测试,测试方法为:注释某个函数指针,重新编译挂载,测试是否可以正常使用。
我在此不再一一测试,最终结果如下:
static const struct v4l2_ioctl_ops vivi_ioctl_ops = { /* 表示它是一个摄像头设备。不可省略 */ .vidioc_querycap = vidioc_querycap, #if 0 /* 列举、获取、设置输入源。可以省略,使用默认输入源 */ .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, #endif /* 列举、获得、测试、设置摄像头的数据格式。不可省略 */ .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, #if 0 /* 列举、获取、设置标准。可以省略 * 列举、获取标准使用的是 * video_device的tvnorms和current_norm */ .vidioc_s_std = vidioc_s_std, #endif /* 启动、停止视频流。不可省略 */ .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, #if 0 /* 在内核日志中记录状态。可以省略 */ .vidioc_log_status = v4l2_ctrl_log_status, /* 子系统事件。可以省略 */ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, #endif };
六、数据的获取过程
(本节使用vivi.c文件分析,推荐读者使用百度网盘分享的linux/drivers/staging/media/solo6x10/v4l2.c分析,因为Linux-4.5所使用的vivi.c文件与老版内核差距较大)
1. 请求分配缓冲区,但此阶段其实只分配了vb2_buffer
ioctl(4, VIDIOC_REQBUFS /* 通过应用层传入的v4l2_requestbuffers构造并分配vb2_buffer */ -> vidioc_reqbufs -> vb2_reqbufs -> call_qop(q, queue_setup, q, ...); -> queue_setup /* 确定分配的buffer个数 */ -> __vb2_queue_alloc(q, ...); /* 分配vb2_buffer */
2. 查询映射缓冲区
ioctl(4, VIDIOC_QUERYBUF /* 通过vb2_buffer设置v4l2_buffer */ -> vb2_querybuf -> __fill_v4l2_buffer(vb, b); -> memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); -> b->input = vb->v4l2_buf.input; -> b->flags &= ~V4L2_BUFFER_STATE_FLAGS;
3. 真正分配缓冲区
mmap(NULL, h->buf_v4l2[i].length, ...) -> vivi_mmap -> vb2_mmap(&dev->vb_vidq, vma); -> call_memop(q, mmap, ...) /* 调用vb2_queue->mem_ops->mmap,定义在vivi_create_instance()中 */ -> vb2_vmalloc_mmap -> remap_vmalloc_range(vma, buf->vaddr, 0);
4. 把缓冲区放入队列
ioctl(4, VIDIOC_QBUF -> vidioc_qbuf -> vb2_qbuf(&dev->vb_vidq, p); -> list_add_tail(&vb->queued_entry, &q->queued_list); -> __fill_v4l2_buffer(vb, b); /* 设置v4l2_buffer */
5. 启动摄像头
ioctl(4, VIDIOC_STREAMON -> vidioc_streamon -> vb2_streamon(&dev->vb_vidq, i); -> __enqueue_in_driver(vb); /* vb2_buffer入队 */ -> q->ops->buf_queue(vb); -> buffer_queue -> list_add_tail(&buf->list, &vidq->active); -> call_qop(q, start_streaming,...) /* 调用vb2_queue->ops->start_streaming */ -> start_streaming -> vivi_start_generating(dev); -> kthread_run(vivi_thread,...) -> vivi_sleep(dev); -> add_wait_queue(&dma_q->wq, &wait); -> vivi_thread_tick(dev); -> buf = list_entry(dma_q->active.next, struct vivi_buffer,...) -> vivi_fillbuff(dev, buf); /* 填充vivi_buffer数据,其中包含vb2_buffer */ -> vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); -> wake_up_interruptible(&dma_q->wq); /* 唤醒线程 */
6. 查询是否有数据
select(h->fd + 1, &rdset, NULL, NULL, &tv) -> vivi_poll -> vb2_poll(q, file, wait); -> poll_wait(file, &q->done_wq, wait); /* 唤醒使用的就是 5 中的wake_up_interruptible(&dma_q->wq) */
7. 从缓冲区中取数据
ioctl(4, VIDIOC_DQBUF -> vidioc_dqbuf -> vb2_dqbuf(&dev->vb_vidq, p,...) -> __vb2_get_done_vb(q, &vb, nonblocking); -> __vb2_wait_for_done_vb(q, nonblocking); /* 取出第一个数据 */ -> *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); -> call_qop(q, buf_finish, vb); /* 调用vb2_queue->ops->start_streaming */ -> __fill_v4l2_buffer(vb, b); -> memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
七、虚拟摄像头驱动程序编写过程
1. 使用video_device_alloc()分配video_device
2. 设置结构体成员
.fops
.ioctl_ops(里面需要设置11项)
如果要用内核提供的缓冲区操作函数,还需要构造一个videobuf_queue_ops
3. 使用video_register_device()注册video_device
我们可以仿照vivi.c和百度网盘分享的linux/drivers/staging/media/solo6x10/v4l2.c(主要仿照此文件)写一个虚拟摄像头驱动程序
源代码:
1 #include <linux/module.h> 2 #include <linux/delay.h> 3 #include <linux/errno.h> 4 #include <linux/fs.h> 5 #include <linux/kernel.h> 6 #include <linux/slab.h> 7 #include <linux/mm.h> 8 #include <linux/ioport.h> 9 #include <linux/init.h> 10 #include <linux/sched.h> 11 #include <linux/pci.h> 12 #include <linux/random.h> 13 #include <linux/version.h> 14 #include <linux/mutex.h> 15 #include <linux/videodev2.h> 16 #include <linux/dma-mapping.h> 17 #include <linux/interrupt.h> 18 #include <linux/kthread.h> 19 #include <linux/highmem.h> 20 #include <linux/freezer.h> 21 #include <media/videobuf-vmalloc.h> 22 #include <media/v4l2-device.h> 23 #include <media/v4l2-ioctl.h> 24 25 #define USE_DMA 0 26 27 static struct video_device *myvivi; 28 static struct v4l2_format myvivi_format; 29 static struct videobuf_queue myvivi_vb_vidq; 30 static spinlock_t myvivi_slock; 31 static struct timer_list myvivi_timer; 32 static struct list_head myvivi_list_head; 33 34 /** 35 * videobuf_queue_ops 36 **/ 37 /* ioctl VIDIOC_REQBUFS导致此函数被调用 38 * 用于重新调整count和size 39 */ 40 static int myvivi_buf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) 41 { 42 *size = myvivi_format.fmt.pix.sizeimage; 43 44 if (*count < 4) 45 *count = 4; 46 47 return 0; 48 } 49 50 /* ioctl VIDIOC_QBUF导致此函数被调用 51 * 它会填充video_buffer结构体并调用videobuf_iolock来分配内存 52 */ 53 static int myvivi_buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) 54 { 55 vb->size = myvivi_format.fmt.pix.sizeimage; 56 57 /* XXX: These properties only change when queue is idle */ 58 vb->width = myvivi_format.fmt.pix.width; 59 vb->height = myvivi_format.fmt.pix.height; 60 vb->bytesperline = myvivi_format.fmt.pix.bytesperline; 61 vb->field = field; 62 #if USE_DMA 63 if (vb->state == VIDEOBUF_NEEDS_INIT) { 64 int rc = videobuf_iolock(vq, vb, NULL); 65 if (rc < 0) { 66 struct videobuf_dmabuf *dma = videobuf_to_dma(vb); 67 videobuf_dma_unmap(vq->dev, dma); 68 videobuf_dma_free(dma); 69 vb->state = VIDEOBUF_NEEDS_INIT; 70 return rc; 71 } 72 } 73 #endif 74 vb->state = VIDEOBUF_PREPARED; 75 76 return 0; 77 } 78 79 /* ioctl VIDIOC_QBUF时: 80 * 1. 调用buf_prepare()做准备工作 81 * 2. 把buf放入stream队列 82 * 3. 调用buf_queue(起通知、记录作用) 83 */ 84 static void myvivi_buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) 85 { 86 vb->state = VIDEOBUF_QUEUED; 87 list_add_tail(&vb->queue, &myvivi_list_head); 88 /* 使用的定时器,不需要唤醒 */ 89 // wake_up_interruptible(&solo_dev->disp_thread_wait); 90 } 91 92 /* APP不再使用队列时,用它来释放内存 */ 93 static void myvivi_buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) 94 { 95 #if USE_DMA 96 struct videobuf_dmabuf *dma = videobuf_to_dma(vb); 97 98 videobuf_dma_unmap(vq->dev, dma); 99 videobuf_dma_free(dma); 100 #endif 101 vb->state = VIDEOBUF_NEEDS_INIT; 102 } 103 104 105 static struct videobuf_queue_ops solo_video_qops = { 106 .buf_setup = myvivi_buf_setup, 107 .buf_prepare = myvivi_buf_prepare, 108 .buf_queue = myvivi_buf_queue, 109 .buf_release = myvivi_buf_release, 110 }; 111 112 /** 113 * v4l2_file_operations 114 **/ 115 static int myvivi_open(struct file *file) 116 { 117 videobuf_queue_vmalloc_init(&myvivi_vb_vidq, &solo_video_qops, 118 NULL, &myvivi_slock, 119 V4L2_BUF_TYPE_VIDEO_CAPTURE, 120 V4L2_FIELD_INTERLACED, 121 sizeof(struct videobuf_buffer), NULL, NULL); 122 /* 其他程序在此处执行thread,本程序在此处执行定时器 */ 123 myvivi_timer.expires = jiffies + 1; 124 add_timer(&myvivi_timer); 125 126 return 0; 127 } 128 129 static int myvivi_close(struct file *file) 130 { 131 del_timer(&myvivi_timer); 132 videobuf_stop(&myvivi_vb_vidq); 133 videobuf_mmap_free(&myvivi_vb_vidq); 134 135 return 0; 136 } 137 138 static ssize_t myvivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) 139 { 140 return videobuf_read_stream(&myvivi_vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); 141 } 142 143 static unsigned int myvivi_poll(struct file *file, struct poll_table_struct *wait) 144 { 145 return videobuf_poll_stream(file, &myvivi_vb_vidq, wait); 146 } 147 148 extern int videobuf_mmap_mapper(struct videobuf_queue *, struct vm_area_struct *); 149 static int myvivi_mmap(struct file *file, struct vm_area_struct *vma) 150 { 151 return videobuf_mmap_mapper(&myvivi_vb_vidq, vma); 152 } 153 154 static const struct v4l2_file_operations myvivi_fops = { 155 .owner = THIS_MODULE, 156 .open = myvivi_open, 157 .release = myvivi_close, 158 .read = myvivi_read, 159 .poll = myvivi_poll, 160 .unlocked_ioctl = video_ioctl2, 161 .mmap = myvivi_mmap, 162 }; 163 164 /** 165 * v4l2_ioctl_ops 166 **/ 167 static int myvivi_querycap(struct file *file, void *priv, struct v4l2_capability *cap) 168 { 169 strcpy(cap->driver, "myvivi"); 170 strcpy(cap->card, "myvivi"); 171 cap->version = 0x01; 172 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 173 return 0; 174 } 175 176 static int myvivi_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) 177 { 178 if (f->index) 179 return -EINVAL; 180 181 f->pixelformat = V4L2_PIX_FMT_YUYV; 182 strlcpy(f->description, "4:2:2, packed, YUYV", sizeof(f->description)); 183 184 return 0; 185 } 186 187 static int myvivi_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) 188 { 189 memcpy(f, &myvivi_format, sizeof(myvivi_format)); 190 return 0; 191 } 192 193 static int myvivi_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) 194 { 195 enum v4l2_field field; 196 unsigned int max_width, max_height; 197 198 if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) 199 return -EINVAL; 200 201 field = f->fmt.pix.field; 202 if (field == V4L2_FIELD_ANY) { 203 field = V4L2_FIELD_INTERLACED; 204 } 205 else if (V4L2_FIELD_INTERLACED != field) { 206 return -EINVAL; 207 } 208 f->fmt.pix.field = field; 209 210 max_width = 1024; 211 max_height = 768; 212 213 v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2, 214 &f->fmt.pix.height, 32, max_height, 0, 0); 215 f->fmt.pix.bytesperline = 216 (f->fmt.pix.width * 16) >> 3; 217 f->fmt.pix.sizeimage = 218 f->fmt.pix.height * f->fmt.pix.bytesperline; 219 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 220 221 return 0; 222 } 223 224 static int myvivi_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) 225 { 226 int ret; 227 if (videobuf_queue_is_busy(&myvivi_vb_vidq)) 228 return -EBUSY; 229 230 ret = myvivi_try_fmt_vid_cap(file, priv, f); 231 if (ret < 0) 232 return ret; 233 234 memcpy(&myvivi_format, f, sizeof(myvivi_format)); 235 236 return 0; 237 } 238 239 static int myvivi_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) 240 { 241 return videobuf_reqbufs(&myvivi_vb_vidq, p); 242 } 243 244 static int myvivi_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) 245 { 246 return videobuf_querybuf(&myvivi_vb_vidq, p); 247 } 248 249 static int myvivi_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) 250 { 251 return videobuf_qbuf(&myvivi_vb_vidq, p); 252 } 253 254 static int myvivi_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) 255 { 256 return videobuf_dqbuf(&myvivi_vb_vidq, p, file->f_flags & O_NONBLOCK); 257 } 258 259 static int myvivi_streamon(struct file *file, void *priv, enum v4l2_buf_type i) 260 { 261 return videobuf_streamon(&myvivi_vb_vidq); 262 } 263 264 static int myvivi_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) 265 { 266 videobuf_streamoff(&myvivi_vb_vidq); 267 return 0; 268 } 269 270 static const struct v4l2_ioctl_ops myvivi_ioctl_ops = { 271 .vidioc_querycap = myvivi_querycap, 272 .vidioc_enum_fmt_vid_cap = myvivi_enum_fmt_vid_cap, 273 .vidioc_g_fmt_vid_cap = myvivi_g_fmt_vid_cap, 274 .vidioc_try_fmt_vid_cap = myvivi_try_fmt_vid_cap, 275 .vidioc_s_fmt_vid_cap = myvivi_s_fmt_vid_cap, 276 .vidioc_reqbufs = myvivi_reqbufs, 277 .vidioc_querybuf = myvivi_querybuf, 278 .vidioc_qbuf = myvivi_qbuf, 279 .vidioc_dqbuf = myvivi_dqbuf, 280 .vidioc_streamon = myvivi_streamon, 281 .vidioc_streamoff = myvivi_streamoff, 282 }; 283 284 static void myvivi_release(struct video_device *vdev) 285 { 286 /* myvivi_exit()中调用了video_device_release() 287 * 因此myvivi->release不需要设置为video_device_release 288 */ 289 } 290 291 /* 此函数用于实现其他文件的thread() */ 292 static void myvivi_timerfunc(unsigned long arg) 293 { 294 struct videobuf_buffer *vb; 295 void *vbuf; 296 297 if (list_empty(&myvivi_list_head)) 298 goto fail; 299 300 vb = list_first_entry(&myvivi_list_head, struct videobuf_buffer, 301 queue); 302 303 if (!waitqueue_active(&vb->done)) 304 goto fail; 305 306 /* Fill buffer */ 307 vbuf = videobuf_to_vmalloc(vb); 308 if (!vbuf) 309 goto fail; 310 311 /* 由于是虚拟摄像头驱动,所以假装有数据 */ 312 memset(vbuf, 0, vb->size); 313 314 vb->field_count++; 315 do_gettimeofday(&vb->ts); 316 vb->state = VIDEOBUF_DONE; 317 318 /* 把videobuf从队列中删除 */ 319 list_del(&vb->queue); 320 321 /* 唤醒videobuf->done上的进程 */ 322 wake_up(&vb->done); 323 324 fail: 325 /* 30帧/秒 */ 326 mod_timer(&myvivi_timer, jiffies + HZ / 30); 327 } 328 329 static int __init myvivi_init(void) 330 { 331 int ret; 332 333 myvivi = video_device_alloc(); 334 335 myvivi->release = myvivi_release, 336 myvivi->fops = &myvivi_fops; 337 myvivi->ioctl_ops = &myvivi_ioctl_ops; 338 339 /* 初始化spinlock */ 340 spin_lock_init(&myvivi_slock); 341 /* 初始化timer_list */ 342 init_timer(&myvivi_timer); 343 myvivi_timer.function = myvivi_timerfunc; 344 /* 初始化list_head */ 345 INIT_LIST_HEAD(&myvivi_list_head); 346 347 ret = video_register_device(myvivi, VFL_TYPE_GRABBER, -1); 348 if (ret < 0) { 349 video_device_release(myvivi); 350 return ret; 351 } 352 353 return 0; 354 } 355 356 static void __exit myvivi_exit(void) 357 { 358 video_unregister_device(myvivi); 359 video_device_release(myvivi); 360 } 361 362 module_init(myvivi_init); 363 module_exit(myvivi_exit); 364 MODULE_LICENSE("GPL");
Makefile:
1 KERN_DIR = /work/itop4412/tools/linux-3.5 2 3 all: 4 make -C $(KERN_DIR) M=`pwd` modules 5 6 clean: 7 make -C $(KERN_DIR) M=`pwd` modules clean 8 rm -rf modules.order 9 10 obj-m += videobuf-vmalloc.o 11 obj-m += myvivi.o
本章内容写的较为混乱,推荐读者通过分析linux/drivers/staging/media/solo6x10/v4l2.c和第六节:数据的获取过程体验各个过程的调用关系
原文地址:https://www.cnblogs.com/Lioker/p/11323630.html