一、V4L2框架主要结构体分析
V4L2(video for linux version 2),是内核中视频设备的驱动框架,为上层访问视频设备提供统一接口。
V4L2整体框架如下图:
图中主要包括两层和三个结构体:
两层是:
1. v4l2驱动核心层:包含video_device和v4l2_device的分配、设置和注册
2. v4l2下层接口层:具体的底层传感器驱动,现在的摄像头可能支持硬件解码,这就需要在摄像头驱动下面提供解码器IC驱动
三个结构体是:
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的父设备
video_device是v4l2_device的上层结构体,存储v4l2_device数据和cdev,它会在/dev目录下生成设备节点文件
video_device的struct v4l2_ioctl_ops会在后面分析
在此我给出它的作用方便读者理解函数分析过程:
struct v4l2_ioctl_ops:它会在应用层使用ioctl()时根据传入的宏调用对应操作函数
二、核心层提供的注册函数
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); /* 依据次设备号分配cdev */ -> dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); /* 设备名为video%d */ -> device_register(&vdev->dev); -> device_add(dev);
video_register_device()函数主要分配、设置并注册了cdev和device。
三、v4l2_device和video_device的file_operations分析
分析到这里,产生了两个问题:
1. register_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 ”:
在此我以drivers/staging/media/solo6x10/v4l2.c文件为例分析
若读者使用它其他文件分析,可能在后面会遇到struct vb2_buffer、struct vb2_queue、struct vb2_ops和struct vb2_mem_ops,其实vb2就是videobuf2,是videobuf的新版本,在此不做介绍
文件链接:
https://files.cnblogs.com/files/Lioker/24_v4l2_xawtv.zip
static const struct v4l2_file_operations solo_v4l2_fops = { .owner = THIS_MODULE, .open = solo_v4l2_open, .release = solo_v4l2_release, .read = solo_v4l2_read, .poll = solo_v4l2_poll, .mmap = solo_v4l2_mmap, .ioctl = video_ioctl2, };
首先从open()函数分析:
solo_v4l2_open -> INIT_LIST_HEAD(&fh->vidq_active); /* 初始化用于存放queue的list_head */ -> solo_start_thread(fh); /* 启动线程查询是否有数据 */ -> solo_thread /* 等待数据 */ -> DECLARE_WAITQUEUE(wait, current); -> add_wait_queue(&solo_dev->disp_thread_wait, &wait); -> schedule_timeout_interruptible(HZ); -> solo_thread_try(fh); /* 如果有数据 */ /* 取出等待队列头的第一个队列 */ -> struct videobuf_buffer * vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer, queue); -> list_del(&vb->queue); -> solo_fillbuf(fh, vb); -> wake_up(&vb->done); /* 唤醒上层读写操作 */ -> remove_wait_queue(&solo_dev->disp_thread_wait, &wait); -> videobuf_queue_sg_init(&fh->vidq, &solo_video_qops, /* solo_video_qops为struct videobuf_queue_ops */ ..., &fh->slock, /* fh->slock为spinlock_t用于保护队列 */ V4L2_BUF_TYPE_VIDEO_CAPTURE, /* 是摄像头 */ SOLO_DISP_PIX_FIELD, sizeof(struct videobuf_buffer), fh,...);
函数所使用的struct videobuf_queue、struct videobuf_queue_ops和struct videobuf_buffer会在后面分析
在此我给出它们的作用方便读者理解函数分析过程:
struct videobuf_queue:在数据传输过程中,首先把buffer放入queue,然后把queue放入list_head中,读写函数会通过操作list_head来操作queue中的buffer
struct videobuf_queue_ops:提供设置videobuf_buffer函数,添加queue到list_head函数,释放内存函数等
struct videobuf_buffer:用于数据传输,是数据传输的基本单位
函数所使用的videobuf_queue_sg_init()函数用于初始化queue,除此函数外,还有两函数可以用来初始化queue:
void videobuf_queue_vmalloc_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, struct device *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, void *priv); void videobuf_queue_dma_contig_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, struct device *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, void *priv);
videobuf_queue_sg_init():物理上和虚拟地址都是离散的buffer
videobuf_queue_vmalloc_init():物理上离散的,但虚拟地址是连续的buffer
videobuf_queue_dma_contig_init():物理上和虚拟地址都是连续的buffer
read()函数的调用关系如下:
solo_v4l2_read /* 从videobuf_queue fh->vidq取出数据 */ -> videobuf_read_stream(&fh->vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); -> q->read_buf = list_entry(q->stream.next, struct videobuf_buffer, stream); -> list_del(&q->read_buf->stream);
ioctl()函数的调用关系如下:
video_ioctl2 /* 根据cmd,调用__video_do_ioctl()将数据拷贝到内核空间 */ -> __video_do_ioctl -> 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);
分析完了这两个问题,下面我们来分析v4l2.c的init()函数
四、v4l2.c的init()函数分析
init()函数的调用关系:
solo_v4l2_init /* 初始化open()等函数使用的wait_queue_head_t */ -> init_waitqueue_head(&solo_dev->disp_thread_wait); /* 分配、设置和注册video_device */ -> solo_dev->vfd = video_device_alloc(); -> *solo_dev->vfd = solo_v4l2_template; /* struct video_device */ -> video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
根据上述过程,我们可以得到下图:
五、数据传输和控制结构体分析
我在前几节有几个结构体没有介绍,在此我还是以v4l2.c文件的实例进行介绍
数据控制相关:
1. struct v4l2_ioctl_ops
static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { /* 表示它是一个摄像头设备 */ .vidioc_querycap = solo_querycap, /* 列举、获取、设置标准 * 列举、获取标准使用的是 * video_device的tvnorms和current_norm */ .vidioc_s_std = solo_s_std, /* 列举、获取、设置输入源 */ .vidioc_enum_input = solo_enum_input, .vidioc_s_input = solo_set_input, .vidioc_g_input = solo_get_input, /* 列举、获得、测试、设置摄像头的数据格式 */ .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap, .vidioc_try_fmt_vid_cap = solo_try_fmt_cap, .vidioc_s_fmt_vid_cap = solo_set_fmt_cap, .vidioc_g_fmt_vid_cap = solo_get_fmt_cap, /* 缓冲区操作:申请、查询、放入队列、取出队列 */ .vidioc_reqbufs = solo_reqbufs, .vidioc_querybuf = solo_querybuf, .vidioc_qbuf = solo_qbuf, .vidioc_dqbuf = solo_dqbuf, /* 启动、停止视频流 */ .vidioc_streamon = solo_streamon, .vidioc_streamoff = solo_streamoff, /* Controls */ .vidioc_queryctrl = solo_disp_queryctrl, .vidioc_g_ctrl = solo_disp_g_ctrl, .vidioc_s_ctrl = solo_disp_s_ctrl, };
数据传输相关:
1. struct videobuf_buffer

struct videobuf_buffer { unsigned int i; u32 magic; /* info about the buffer */ unsigned int width; /* 摄像头图像像素长度 */ unsigned int height; /* 宽度 */ unsigned int bytesperline; /* 一行的字节数 */ unsigned long size; /* size = height * bytesperline */ unsigned int input; enum v4l2_field field; enum videobuf_state state; /* 用于存储状态 */ struct list_head stream; /* QBUF/DQBUF list */ /* touched by irq handler */ struct list_head queue; wait_queue_head_t done; unsigned int field_count; struct timeval ts; /* Memory type */ enum v4l2_memory memory; /* buffer size */ size_t bsize; /* buffer offset (mmap + overlay) */ size_t boff; /* buffer addr (userland ptr!) */ unsigned long baddr; /* for mmap'ed buffers */ struct videobuf_mapping *map; /* Private pointer to allow specific methods to store their data */ int privsize; void *priv; };
2. struct videobuf_queue

struct videobuf_queue { struct mutex vb_lock; struct mutex *ext_lock; spinlock_t *irqlock; struct device *dev; wait_queue_head_t wait; /* wait if queue is empty */ enum v4l2_buf_type type; unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ unsigned int msize; enum v4l2_field field; enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; const struct videobuf_queue_ops *ops; struct videobuf_qtype_ops *int_ops; unsigned int streaming:1; unsigned int reading:1; /* capture via mmap() + ioctl(QBUF/DQBUF) */ struct list_head stream; /* capture via read() */ unsigned int read_off; struct videobuf_buffer *read_buf; /* driver private data */ void *priv_data; };
3. struct videobuf_queue_ops
static struct videobuf_queue_ops solo_video_qops = { /* 被v4l2_ioctl_ops->vidioc_reqbufs调用,用于重新调整count和size */ .buf_setup = solo_buf_setup, /* 被v4l2_ioctl_ops->vidioc_qbuf调用,用于设置videobuf_buffer成员 */ .buf_prepare = solo_buf_prepare, /* 被v4l2_ioctl_ops->vidioc_qbuf调用,用于把queue放到list_head */ .buf_queue = solo_buf_queue, /* 被v4l2_ioctl_ops->vidioc_streamoff调用,用于释放内存 */ .buf_release = solo_buf_release, };
当开始流I/O时,摄像头的图像会在应用和驱动间传输,它可能会有三个状态:
1. 在驱动的传入队列中,用户空间通过ioctl(..., VIDIOC_QBUF, ...)填充缓冲区,把缓冲区放入队列。
2. 在驱动的传出队列中,缓冲区已经填充了视频数据,等待用户空间读取
3. 在用户空间的队列中,用户空间已经通过ioctl(..., VIDIOC_DQBUF, ...)读取缓冲区了,此时驱动无法访问缓冲区
这三种状态的切换如下图:
六、虚拟摄像头驱动vivi.c虚拟机测试
本节我通过应用程序xawtv对vivi.c的系统调用的关系进行分析,我们需要做的有以下几步:
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文件会放在上面的百度网盘分享链接中
首先,我们搜索“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\nsr_YU.UTF-8@cyrillic\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\nsr_YU.UTF-8@cyrillic\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\nsr_YU.UTF-8@cyrillic\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\nsr_YU.UTF-8@cyrillic\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\0@\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 };
八、数据的获取过程
本节使用v4l2.c进行分析,读者若对vb2感兴趣也可以分析vivi.c
1. 请求分配缓冲区,但此阶段其实只分配了videobuf_buffer
ioctl(4, VIDIOC_REQBUFS -> solo_reqbufs -> videobuf_reqbufs(&fh->vidq, req); -> *size = solo_image_size(solo_dev); /* 设置图片size */ -> __videobuf_mmap_setup(q, count, size, req->memory); -> q->bufs[i] = videobuf_alloc_vb(q); /* 分配设置videobuf_buffer */
2. 查询映射缓冲区,通过videobuf_buffer设置供上层使用的v4l2_buffer
ioctl(4, VIDIOC_QUERYBUF -> videobuf_querybuf -> videobuf_status(q, b, q->bufs[b->index], q->type); -> b->flags |= V4L2_BUF_FLAG_MAPPED; -> b->field = vb->field; -> b->timestamp = vb->ts; /* v4l2_buffer */
3. 真正分配缓冲区
mmap(NULL, h->buf_v4l2[i].length, ...) -> solo_v4l2_mmap -> videobuf_mmap_mapper(&fh->vidq, vma); -> CALL(q, mmap_mapper, q, buf, vma)
4. 把缓冲区放入队列
ioctl(4, VIDIOC_QBUF -> videobuf_qbuf(&fh->vidq, buf); -> buf = q->bufs[b->index]; -> solo_buf_prepare /* 设置video_device成员 */ -> vb->width = solo_dev->video_hsize; -> vb->height = solo_vlines(solo_dev); -> list_add_tail(&buf->stream, &q->stream) -> solo_buf_queue /* 把queue放到list_head */ -> list_add_tail(&vb->queue, &fh->vidq_active);
5. 启动摄像头
ioctl(4, VIDIOC_STREAMON -> solo_streamon -> videobuf_streamon(&fh->vidq); -> solo_buf_queue /* 把queue放到list_head */ -> list_add_tail(&vb->queue, &fh->vidq_active); -> wake_up_interruptible_sync(&q->wait);
6. 查询是否有数据
select(h->fd + 1, &rdset, NULL, NULL, &tv) -> solo_v4l2_poll -> videobuf_poll_stream(file, &fh->vidq, wait); -> poll_wait(file, &buf->done, wait);
唤醒此进程的是open()函数注册的solo_thread()函数
7. 从缓冲区中取数据
ioctl(4, VIDIOC_DQBUF -> solo_dqbuf -> videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); -> stream_next_buffer(q, &buf, nonblocking); /* 在queue中获取有数据的缓冲区 */ -> videobuf_status(q, b, buf, q->type); /* 把缓冲区的状态返回给应用层 */ -> list_del(&buf->stream);
九、虚拟摄像头驱动程序编写过程
1. 使用video_device_alloc()分配video_device
2. 设置结构体成员
.fops
.ioctl_ops(里面需要设置11项)
如果要用内核提供的缓冲区操作函数,还需要构造一个videobuf_queue_ops
3. 使用video_register_device()注册video_device
我们可以仿照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和第八节:数据的获取过程体验各个过程的调用关系