二十四、V4L2框架主要结构体分析和虚拟摄像头驱动编写

一、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);
};
View Code

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;
};
View Code

 

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;
};
View Code

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;
};
View Code

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
View Code

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.关闭摄像头 */
View Code

 

在分析完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");
View Code

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
View Code

由于是虚拟摄像头,所以源代码中的摄像头参数和数据格式是根据内核规则随意选择的,参数的确定和选取会在下一章进行介绍

 

本章内容较为混乱,推荐读者自行分析linux/drivers/staging/media/solo6x10/v4l2.c第八节:数据的获取过程体验各个过程的调用关系

 

转载于:https://www.cnblogs.com/Lioker/p/11323630.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值