二十4、V4L2框架主要結構體分析和虛擬攝像頭驅動編寫

1、V4L2框架主要結構體分析

V4L2(video for linux version 2),是內核中視頻設備的驅動框架,爲上層訪問視頻設備提供統一接口。
node

V4L2總體框架以下圖:linux

 

圖中主要包括兩層和三個結構體:緩存

兩層是:app

1. v4l2驅動核心層:包含video_device和v4l2_device的分配、設置和註冊框架

2. v4l2下層接口層:具體的底層傳感器驅動,如今的攝像頭可能支持硬件解碼,這就須要在攝像頭驅動下面提供解碼器IC驅動dom

三個結構體是:ide

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()時根據傳入的宏調用對應操做函數

 

 

2、核心層提供的註冊函數

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。

 

 

3、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()函數

4、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);

根據上述過程,咱們能夠獲得下圖:

 

 

5、數據傳輸和控制結構體分析

我在前幾節有幾個結構體沒有介紹,在此我仍是以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, ...)讀取緩衝區了,此時驅動沒法訪問緩衝區

這三種狀態的切換以下圖:

 

 

6、虛擬攝像頭驅動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打開虛擬攝像頭

 

 

7、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
};

 

 

8、數據的獲取過程

本節使用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);

 

 

9、虛擬攝像頭驅動程序編寫過程

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第八節:數據的獲取過程體驗各個過程的調用關係

相關文章
相關標籤/搜索