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); };
2. video_device:性能
struct video_device { const struct v4l2_file_operations *fops; /* 文件操做函數 */ struct device dev; /* v4l device */ struct cdev *cdev; /* character device */ struct device *parent; /* device parent */ struct v4l2_device *v4l2_dev; /* v4l2_device parent */ /* Control handler associated with this device node. May be NULL. */ struct v4l2_ctrl_handler *ctrl_handler; /* Priority state. If NULL, then v4l2_dev->prio will be used. */ struct v4l2_prio_state *prio; /* device info */ char name[32]; int vfl_type; /* 'minor' is set to -1 if the registration failed */ int minor; u16 num; ... /* ioctl callbacks */ const struct v4l2_ioctl_ops *ioctl_ops; /* 控制函數 */ /* serialization lock */ struct mutex *lock; };
3. v4l2-subdev:測試
struct v4l2_subdev { #if defined(CONFIG_MEDIA_CONTROLLER) struct media_entity entity; #endif struct list_head list; struct module *owner; u32 flags; struct v4l2_device *v4l2_dev; const struct v4l2_subdev_ops *ops; /* Never call these internal ops from within a driver! */ const struct v4l2_subdev_internal_ops *internal_ops; /* The control handler of this subdev. May be NULL. */ struct v4l2_ctrl_handler *ctrl_handler; /* name must be unique */ char name[V4L2_SUBDEV_NAME_SIZE]; /* can be used to group similar subdevs, value is driver-specific */ u32 grp_id; /* pointer to private data */ void *dev_priv; void *host_priv; /* subdev device node */ struct video_device *devnode; };
v4l2_device在v4l2框架中是v4l2_subdev的父設備
video_device是v4l2_device的上層結構體,存儲v4l2_device數據和cdev,它會在/dev目錄下生成設備節點文件
video_device的struct v4l2_ioctl_ops會在後面分析
在此我給出它的做用方便讀者理解函數分析過程:
struct v4l2_ioctl_ops:它會在應用層使用ioctl()時根據傳入的宏調用對應操做函數
1. 註冊和註銷v4l2_device:
/* 註冊 */ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) /* 註銷 */ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
註冊函數調用關係以下:
/* 將設備與v4l2_device捆綁,並把v4l2設備放到driver data中 * 咱們可使用dev_get_drvdata(dev)獲取到v4l2設備 */ v4l2_device_register(&intf->dev, &dev->vdev) -> dev_set_drvdata(dev, v4l2_dev); -> dev->p->driver_data = data; /* device->device_private爲v4l2_device */
2. 註冊和註銷v4l2_subdev:
/* 註冊 */ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd) /* 註銷 */ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
註冊函數調用關係以下:
v4l2_device_register_subdev() /* struct v4l2_ctrl_handler用於控制設備的亮度、飽和度等 */ -> v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); -> handler_new_ref(hdl, ctrl); /* 設置控制屬性 */ -> v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0) -> v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); -> v4l2_ctrl_new(hdl, ops, ...); /* ops爲v4l2_ctrl_ops,定義控制函數 */ -> list_add_tail(&ctrl->node, &hdl->ctrls); -> list_add_tail(&sd->list, &v4l2_dev->subdevs);
v4l2_subdev註冊函數主要設置了設備的控制屬性和控制函數,並把設備放入列表中
控制函數結構體定義以下,讀者有印象便可
struct v4l2_ctrl_ops { int (*g_volatile_ctrl)(struct v4l2_ctrl *ctrl); /* 獲取控制器值 */ int (*try_ctrl)(struct v4l2_ctrl *ctrl); /* 測試控制器值是否有效 */ int (*s_ctrl)(struct v4l2_ctrl *ctrl); /* 設置控制器值 */ };
3. 註冊和註銷video_device:
/* 註冊 */ static inline int __must_check video_register_device(struct video_device *vdev, int type, int nr) /* 註銷 */ void video_unregister_device(struct video_device *vdev)
註冊函數調用關係以下:
video_register_device(vdev, VFL_TYPE_GRABBER, -1); -> __video_register_device(vdev, type, nr, 1, vdev->fops->owner); -> case VFL_TYPE_GRABBER: /* 攝像頭設備 */ -> name_base = "video"; -> case VFL_TYPE_GRABBER: -> minor_offset = 0; -> minor_cnt = 64; -> vdev->minor = i + minor_offset; -> vdev->cdev = cdev_alloc(); -> vdev->cdev->ops = &v4l2_fops; -> cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); /* 依據次設備號分配cdev */ -> dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); /* 設備名爲video%d */ -> device_register(&vdev->dev); -> device_add(dev);
video_register_device()函數主要分配、設置並註冊了cdev和device。
分析到這裏,產生了兩個問題:
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()函數
init()函數的調用關係:
solo_v4l2_init /* 初始化open()等函數使用的wait_queue_head_t */ -> init_waitqueue_head(&solo_dev->disp_thread_wait); /* 分配、設置和註冊video_device */ -> solo_dev->vfd = video_device_alloc(); -> *solo_dev->vfd = solo_v4l2_template; /* struct video_device */ -> video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
根據上述過程,咱們能夠獲得下圖:
我在前幾節有幾個結構體沒有介紹,在此我仍是以v4l2.c文件的實例進行介紹
數據控制相關:
1. struct v4l2_ioctl_ops
static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { /* 表示它是一個攝像頭設備 */ .vidioc_querycap = solo_querycap, /* 列舉、獲取、設置標準 * 列舉、獲取標準使用的是 * video_device的tvnorms和current_norm */ .vidioc_s_std = solo_s_std, /* 列舉、獲取、設置輸入源 */ .vidioc_enum_input = solo_enum_input, .vidioc_s_input = solo_set_input, .vidioc_g_input = solo_get_input, /* 列舉、得到、測試、設置攝像頭的數據格式 */ .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap, .vidioc_try_fmt_vid_cap = solo_try_fmt_cap, .vidioc_s_fmt_vid_cap = solo_set_fmt_cap, .vidioc_g_fmt_vid_cap = solo_get_fmt_cap, /* 緩衝區操做:申請、查詢、放入隊列、取出隊列 */ .vidioc_reqbufs = solo_reqbufs, .vidioc_querybuf = solo_querybuf, .vidioc_qbuf = solo_qbuf, .vidioc_dqbuf = solo_dqbuf, /* 啓動、中止視頻流 */ .vidioc_streamon = solo_streamon, .vidioc_streamoff = solo_streamoff, /* Controls */ .vidioc_queryctrl = solo_disp_queryctrl, .vidioc_g_ctrl = solo_disp_g_ctrl, .vidioc_s_ctrl = solo_disp_s_ctrl, };
數據傳輸相關:
1. struct videobuf_buffer
struct videobuf_buffer { unsigned int i; u32 magic; /* info about the buffer */ unsigned int width; /* 攝像頭圖像像素長度 */ unsigned int height; /* 寬度 */ unsigned int bytesperline; /* 一行的字節數 */ unsigned long size; /* size = height * bytesperline */ unsigned int input; enum v4l2_field field; enum videobuf_state state; /* 用於存儲狀態 */ struct list_head stream; /* QBUF/DQBUF list */ /* touched by irq handler */ struct list_head queue; wait_queue_head_t done; unsigned int field_count; struct timeval ts; /* Memory type */ enum v4l2_memory memory; /* buffer size */ size_t bsize; /* buffer offset (mmap + overlay) */ size_t boff; /* buffer addr (userland ptr!) */ unsigned long baddr; /* for mmap'ed buffers */ struct videobuf_mapping *map; /* Private pointer to allow specific methods to store their data */ int privsize; void *priv; };
2. struct videobuf_queue
struct videobuf_queue { struct mutex vb_lock; struct mutex *ext_lock; spinlock_t *irqlock; struct device *dev; wait_queue_head_t wait; /* wait if queue is empty */ enum v4l2_buf_type type; unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ unsigned int msize; enum v4l2_field field; enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; const struct videobuf_queue_ops *ops; struct videobuf_qtype_ops *int_ops; unsigned int streaming:1; unsigned int reading:1; /* capture via mmap() + ioctl(QBUF/DQBUF) */ struct list_head stream; /* capture via read() */ unsigned int read_off; struct videobuf_buffer *read_buf; /* driver private data */ void *priv_data; };
3. struct videobuf_queue_ops
static struct videobuf_queue_ops solo_video_qops = { /* 被v4l2_ioctl_ops->vidioc_reqbufs調用,用於從新調整count和size */ .buf_setup = solo_buf_setup, /* 被v4l2_ioctl_ops->vidioc_qbuf調用,用於設置videobuf_buffer成員 */ .buf_prepare = solo_buf_prepare, /* 被v4l2_ioctl_ops->vidioc_qbuf調用,用於把queue放到list_head */ .buf_queue = solo_buf_queue, /* 被v4l2_ioctl_ops->vidioc_streamoff調用,用於釋放內存 */ .buf_release = solo_buf_release, };
當開始流I/O時,攝像頭的圖像會在應用和驅動間傳輸,它可能會有三個狀態:
1. 在驅動的傳入隊列中,用戶空間經過ioctl(..., VIDIOC_QBUF, ...)填充緩衝區,把緩衝區放入隊列。
2. 在驅動的傳出隊列中,緩衝區已經填充了視頻數據,等待用戶空間讀取
3. 在用戶空間的隊列中,用戶空間已經經過ioctl(..., VIDIOC_DQBUF, ...)讀取緩衝區了,此時驅動沒法訪問緩衝區
這三種狀態的切換以下圖:
本節我經過應用程序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打開虛擬攝像頭
在能夠看到圖像後,咱們就能夠經過應用程序xawtv對應用程序ioctl()執行過程進行分析。
查看程序系統調用過程可使用strace命令實現:
$ strace -o xawtv.log xawtv /* 執行xawtv命令,調用過程會存儲在xawtv.log文件中 */
xawtv.log文件會放在上面的百度網盤分享連接中
首先,咱們搜索「open("/dev/video」,咱們只須要關注第二次open(),由於第一次open()後面有close(),能夠看到文件描述符爲4
接下來,咱們搜索「(4, 」,查看有哪些對應文件描述符的操做:
1 fstat64(4, {st_mode=S_IFREG|0600, st_size=57, ...}) = 0 2 read(4, "\1\0\0\fbook-desktop\0\0010\0\22MIT-MAGIC-C"..., 4096) = 57 3 read(4, "", 4096) = 0 4 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 5 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 6 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 7 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 8 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 9 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 10 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 11 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 12 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 13 read(4, "r_RS.UTF-8\nsr_YU.UTF-8@cyrillic\t"..., 4096) = 4096 14 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 15 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 16 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 17 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 18 read(4, "59-1:\t\t\t\ten_ZA.ISO8859-1\nen_ZA.I"..., 4096) = 4096 19 read(4, "_ES.ISO8859-1\neu_ES.iso88591:\t\t\t"..., 4096) = 4096 20 read(4, "F-8\ngu_IN.utf8:\t\t\t\t\tgu_IN.UTF-8\n"..., 4096) = 4096 21 read(4, "o_KR.utf8:\t\t\t\t\tko_KR.UTF-8\nKO_KR"..., 4096) = 4096 22 read(4, "o_NO.utf8:\t\t\t\t\tno_NO.UTF-8\nnr:\t\t"..., 4096) = 4096 23 read(4, "O8859-2\nsl_SI.iso88592:\t\t\t\t\tsl_S"..., 4096) = 4096 24 read(4, "N\nvi_VN.tcvn5712:\t\t\t\t\tvi_VN.TCVN"..., 4096) = 4096 25 read(4, "9-9\nturkish.iso88599:\t\t\t\ttr_TR.I"..., 4096) = 456 26 read(4, "", 4096) = 0 27 fstat64(4, {st_mode=S_IFREG|0644, st_size=40344, ...}) = 0 28 read(4, "#\t$XdotOrg: lib/X11/nls/locale.d"..., 4096) = 4096 29 read(4, "59-1/XLC_LOCALE\t\t\tes_AR.ISO8859-"..., 4096) = 4096 30 read(4, "_FR.ISO8859-1\niso8859-15/XLC_LOC"..., 4096) = 4096 31 read(4, "8/XLC_LOCALE\t\t\tbe_BY.UTF-8\nen_US"..., 4096) = 4096 32 read(4, "en_US.UTF-8/XLC_LOCALE\t\t\tlo_LA.U"..., 4096) = 4096 33 fstat64(4, {st_mode=S_IFREG|0644, st_size=772, ...}) = 0 34 read(4, "# $Xorg: C,v 1.3 2000/08/17 19:"..., 4096) = 772 35 read(4, "", 4096) = 0 36 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 37 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 38 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 39 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 40 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 41 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 42 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 43 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 44 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 45 read(4, "r_RS.UTF-8\nsr_YU.UTF-8@cyrillic\t"..., 4096) = 4096 46 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 47 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 48 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 49 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 50 read(4, "59-1:\t\t\t\ten_ZA.ISO8859-1\nen_ZA.I"..., 4096) = 4096 51 read(4, "_ES.ISO8859-1\neu_ES.iso88591:\t\t\t"..., 4096) = 4096 52 read(4, "F-8\ngu_IN.utf8:\t\t\t\t\tgu_IN.UTF-8\n"..., 4096) = 4096 53 read(4, "o_KR.utf8:\t\t\t\t\tko_KR.UTF-8\nKO_KR"..., 4096) = 4096 54 read(4, "o_NO.utf8:\t\t\t\t\tno_NO.UTF-8\nnr:\t\t"..., 4096) = 4096 55 read(4, "O8859-2\nsl_SI.iso88592:\t\t\t\t\tsl_S"..., 4096) = 4096 56 read(4, "N\nvi_VN.tcvn5712:\t\t\t\t\tvi_VN.TCVN"..., 4096) = 4096 57 read(4, "9-9\nturkish.iso88599:\t\t\t\ttr_TR.I"..., 4096) = 456 58 read(4, "", 4096) = 0 59 fstat64(4, {st_mode=S_IFREG|0644, st_size=40344, ...}) = 0 60 read(4, "#\t$XdotOrg: lib/X11/nls/locale.d"..., 4096) = 4096 61 read(4, "59-1/XLC_LOCALE\t\t\tes_AR.ISO8859-"..., 4096) = 4096 62 read(4, "_FR.ISO8859-1\niso8859-15/XLC_LOC"..., 4096) = 4096 63 read(4, "8/XLC_LOCALE\t\t\tbe_BY.UTF-8\nen_US"..., 4096) = 4096 64 read(4, "en_US.UTF-8/XLC_LOCALE\t\t\tlo_LA.U"..., 4096) = 4096 65 fstat64(4, {st_mode=S_IFREG|0644, st_size=772, ...}) = 0 66 read(4, "# $Xorg: C,v 1.3 2000/08/17 19:"..., 4096) = 772 67 read(4, "", 4096) = 0 68 fstat64(4, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0 69 read(4, "# Locale name alias data base.\n#"..., 4096) = 2570 70 read(4, "", 4096) = 0 71 fstat64(4, {st_mode=S_IFREG|0644, st_size=373, ...}) = 0 72 fstat64(4, {st_mode=S_IFREG|0644, st_size=26048, ...}) = 0 73 fstat64(4, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0 74 fstat64(4, {st_mode=S_IFREG|0644, st_size=59, ...}) = 0 75 fstat64(4, {st_mode=S_IFREG|0644, st_size=155, ...}) = 0 76 fstat64(4, {st_mode=S_IFREG|0644, st_size=77, ...}) = 0 77 fstat64(4, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0 78 fstat64(4, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 79 fstat64(4, {st_mode=S_IFREG|0644, st_size=52, ...}) = 0 80 fstat64(4, {st_mode=S_IFREG|0644, st_size=286, ...}) = 0 81 fstat64(4, {st_mode=S_IFREG|0644, st_size=966938, ...}) = 0 82 fstat64(4, {st_mode=S_IFREG|0644, st_size=2454, ...}) = 0 83 fstat64(4, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0 84 fstat64(4, {st_mode=S_IFREG|0644, st_size=256316, ...}) = 0 85 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 86 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 87 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 88 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 89 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 90 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 91 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 92 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 93 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 94 read(4, "r_RS.UTF-8\nsr_YU.UTF-8@cyrillic\t"..., 4096) = 4096 95 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 96 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 97 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 98 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 99 read(4, "59-1:\t\t\t\ten_ZA.ISO8859-1\nen_ZA.I"..., 4096) = 4096 100 read(4, "_ES.ISO8859-1\neu_ES.iso88591:\t\t\t"..., 4096) = 4096 101 read(4, "F-8\ngu_IN.utf8:\t\t\t\t\tgu_IN.UTF-8\n"..., 4096) = 4096 102 read(4, "o_KR.utf8:\t\t\t\t\tko_KR.UTF-8\nKO_KR"..., 4096) = 4096 103 read(4, "o_NO.utf8:\t\t\t\t\tno_NO.UTF-8\nnr:\t\t"..., 4096) = 4096 104 read(4, "O8859-2\nsl_SI.iso88592:\t\t\t\t\tsl_S"..., 4096) = 4096 105 read(4, "N\nvi_VN.tcvn5712:\t\t\t\t\tvi_VN.TCVN"..., 4096) = 4096 106 read(4, "9-9\nturkish.iso88599:\t\t\t\ttr_TR.I"..., 4096) = 456 107 read(4, "", 4096) = 0 108 fstat64(4, {st_mode=S_IFREG|0644, st_size=82376, ...}) = 0 109 read(4, "#\t$XdotOrg: lib/X11/nls/locale.a"..., 4096) = 4096 110 read(4, "\t\t\t\t\tbg_BG.UTF-8\nbn_IN.utf8\t\t\t\t\t"..., 4096) = 4096 111 read(4, "8859-15\t\t\t\tde_CH.ISO8859-15\nde_C"..., 4096) = 4096 112 read(4, "_ZA.ISO8859-1\nen_ZA.ISO-8859-1\t\t"..., 4096) = 4096 113 read(4, "85915\t\t\t\teu_ES.ISO8859-15\neu_ES."..., 4096) = 4096 114 read(4, "14\ngv_GB.ISO-8859-14\t\t\t\tgv_GB.IS"..., 4096) = 4096 115 read(4, "w_GB.ISO8859-1\nkw_GB.ISO-8859-1\t"..., 4096) = 4096 116 read(4, ".ISO8859-1\noc\t\t\t\t\t\toc_FR.ISO8859"..., 4096) = 4096 117 read(4, "r_RS.UTF-8\nsr_YU.UTF-8@cyrillic\t"..., 4096) = 4096 118 read(4, "yi_US.CP1255\nzh_CN\t\t\t\t\t\tzh_CN.gb"..., 4096) = 4096 119 read(4, ":00 dawes Exp $\n#\n\nPOSIX:\t\t\t\t\t\tC"..., 4096) = 4096 120 read(4, "4:\t\t\t\tbr_FR.ISO8859-14\nbr_FR.ISO"..., 4096) = 4096 121 read(4, "de_DE.88591.en:\t\t\t\t\tde_DE.ISO885"..., 4096) = 4096 122 fstat64(4, {st_mode=S_IFREG|0644, st_size=40344, ...}) = 0 123 read(4, "#\t$XdotOrg: lib/X11/nls/locale.d"..., 4096) = 4096 124 read(4, "59-1/XLC_LOCALE\t\t\tes_AR.ISO8859-"..., 4096) = 4096 125 read(4, "_FR.ISO8859-1\niso8859-15/XLC_LOC"..., 4096) = 4096 126 read(4, "8/XLC_LOCALE\t\t\tbe_BY.UTF-8\nen_US"..., 4096) = 4096 127 read(4, "en_US.UTF-8/XLC_LOCALE\t\t\tlo_LA.U"..., 4096) = 4096 128 read(4, "LE:\t\t\taf_ZA.ISO8859-1\niso8859-15"..., 4096) = 4096 129 read(4, "LE:\t\t\tes_MX.ISO8859-1\niso8859-1/"..., 4096) = 4096 130 read(4, "9-2/XLC_LOCALE:\t\t\tpl_PL.ISO8859-"..., 4096) = 4096 131 read(4, " byn_ER.UTF-8\nen_US.UT"..., 4096) = 4096 132 fstat64(4, {st_mode=S_IFREG|0644, st_size=4287, ...}) = 0 133 read(4, "# $XFree86: xc/nls/XLC_LOCALE/e"..., 4096) = 4096 134 read(4, "GB2312.1980-0:GL; GB2312.1980-0:"..., 4096) = 191 135 read(4, "", 4096) = 0 136 fstat64(4, {st_mode=S_IFREG|0644, st_size=18236, ...}) = 0 137 read(4, "\n! -----------------------------"..., 18236) = 18236 138 fcntl64(4, F_GETFD) = 0x1 (flags FD_CLOEXEC) 139 getdents64(4, /* 19 entries */, 32768) = 640 140 getdents64(4, /* 0 entries */, 32768) = 0 141 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\3\0\0004\0\0\0"..., 512) = 512 142 fstat64(4, {st_mode=S_IFREG|0644, st_size=5396, ...}) = 0 143 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\v\0\0004\0\0\0"..., 512) = 512 144 fstat64(4, {st_mode=S_IFREG|0644, st_size=13944, ...}) = 0 145 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\3\0\0004\0\0\0"..., 512) = 512 146 fstat64(4, {st_mode=S_IFREG|0644, st_size=5396, ...}) = 0 147 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\17\0\0004\0\0\0"..., 512) = 512 148 fstat64(4, {st_mode=S_IFREG|0644, st_size=22128, ...}) = 0 149 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000'\0\0004\0\0\0"..., 512) = 512 150 fstat64(4, {st_mode=S_IFREG|0644, st_size=75356, ...}) = 0 151 fstat64(4, {st_mode=S_IFREG|0644, st_size=71399, ...}) = 0 152 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0\17\0\0004\0\0\0"..., 512) = 512 153 fstat64(4, {st_mode=S_IFREG|0644, st_size=38144, ...}) = 0 154 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@\22\0\0004\0\0\0"..., 512) = 512 155 fstat64(4, {st_mode=S_IFREG|0644, st_size=103964, ...}) = 0 156 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360\30\0\0004\0\0\0"..., 512) = 512 157 fstat64(4, {st_mode=S_IFREG|0644, st_size=44184, ...}) = 0 158 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0\6\0\0004\0\0\0"..., 512) = 512 159 fstat64(4, {st_mode=S_IFREG|0644, st_size=5640, ...}) = 0 160 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\4\0\0004\0\0\0"..., 512) = 512 161 fstat64(4, {st_mode=S_IFREG|0644, st_size=5496, ...}) = 0 162 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0P\4\0\0004\0\0\0"..., 512) = 512 163 fstat64(4, {st_mode=S_IFREG|0644, st_size=5400, ...}) = 0 164 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`\4\0\0004\0\0\0"..., 512) = 512 165 fstat64(4, {st_mode=S_IFREG|0644, st_size=9640, ...}) = 0 166 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\3\0\0004\0\0\0"..., 512) = 512 167 fstat64(4, {st_mode=S_IFREG|0644, st_size=5400, ...}) = 0 168 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\3\0\0004\0\0\0"..., 512) = 512 169 fstat64(4, {st_mode=S_IFREG|0644, st_size=5400, ...}) = 0 170 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200\10\0\0004\0\0\0"..., 512) = 512 171 fstat64(4, {st_mode=S_IFREG|0644, st_size=9640, ...}) = 0 172 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260\n\0\0004\0\0\0"..., 512) = 512 173 fstat64(4, {st_mode=S_IFREG|0644, st_size=9704, ...}) = 0 174 fstat64(4, {st_mode=S_IFREG|0644, st_size=71399, ...}) = 0 175 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\3405\0\0004\0\0\0"..., 512) = 512 176 fstat64(4, {st_mode=S_IFREG|0644, st_size=121640, ...}) = 0 177 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\r\0\0004\0\0\0"..., 512) = 512 178 fstat64(4, {st_mode=S_IFREG|0644, st_size=13992, ...}) = 0 179 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\10\0\0004\0\0\0"..., 512) = 512 180 fstat64(4, {st_mode=S_IFREG|0644, st_size=13776, ...}) = 0 181 read(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\7\0\0004\0\0\0"..., 512) = 512 182 fstat64(4, {st_mode=S_IFREG|0644, st_size=9588, ...}) = 0 183 fstat64(4, {st_mode=S_IFREG|0644, st_size=8982, ...}) = 0 184 read(4, "! $Xorg: XKeysymDB,v 1.3 2000/08"..., 8982) = 8982 185 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0x9b40998) = -1 EINVAL (Invalid argument) 186 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0xbfaccd44) = 0 187 ioctl(4, VIDIOC_G_FMT or VT_SENDSIG, 0xbfaccc78) = 0 188 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 189 ioctl(4, 0xc02c564a, 0xbfaccb58) = -1 EINVAL (Invalid argument) 190 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 191 ioctl(4, 0xc02c564a, 0xbfaccb58) = -1 EINVAL (Invalid argument) 192 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 193 ioctl(4, 0xc02c564a, 0xbfaccb58) = -1 EINVAL (Invalid argument) 194 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 195 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 196 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0 197 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = -1 EINVAL (Invalid argument) 198 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0xbfaccb84) = 0 199 ioctl(4, VIDIOC_G_INPUT, 0xbfacca2c) = 0 200 ioctl(4, VIDIOC_ENUMINPUT, 0xbfacca2c) = 0 201 fstat64(4, {st_mode=S_IFCHR|0660, st_rdev=makedev(81, 0), ...}) = 0 202 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0xbfacca78) = -1 EINVAL (Invalid argument) 203 ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0x9b40998) = 0 204 fcntl64(4, F_SETFD, FD_CLOEXEC) = 0 205 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40acc) = 0 206 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40b18) = 0 207 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40b64) = 0 208 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40bb0) = 0 209 ioctl(4, VIDIOC_ENUMINPUT, 0x9b40bfc) = -1 EINVAL (Invalid argument) 210 ioctl(4, VIDIOC_ENUMSTD, 0x9b40f8c) = 0 211 ioctl(4, VIDIOC_ENUMSTD, 0x9b40fcc) = 0 212 ioctl(4, VIDIOC_ENUMSTD, 0x9b4100c) = 0 213 ioctl(4, VIDIOC_ENUMSTD, 0x9b4104c) = 0 214 ioctl(4, VIDIOC_ENUMSTD, 0x9b4108c) = 0 215 ioctl(4, VIDIOC_ENUMSTD, 0x9b410cc) = 0 216 ioctl(4, VIDIOC_ENUMSTD, 0x9b4110c) = 0 217 ioctl(4, VIDIOC_ENUMSTD, 0x9b4114c) = -1 EINVAL (Invalid argument) 218 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4138c) = 0 219 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b413cc) = 0 220 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4140c) = 0 221 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4144c) = 0 222 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4148c) = 0 223 ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b414cc) = 0 224 ioctl(4, VIDIOC_G_PARM, 0x9b40a00) = 0 225 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41b8c) = 0 226 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41bd0) = 0 227 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c14) = 0 228 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c58) = 0 229 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c9c) = -1 EINVAL (Invalid argument) 230 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41ce0) = 0 231 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41d24) = -1 EINVAL (Invalid argument) 232 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41d68) = -1 EINVAL (Invalid argument) 233 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41dac) = -1 EINVAL (Invalid argument) 234 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41df0) = -1 EINVAL (Invalid argument) 235 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41e34) = -1 EINVAL (Invalid argument) 236 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41e78) = -1 EINVAL (Invalid argument) 237 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41ebc) = -1 EINVAL (Invalid argument) 238 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f00) = -1 EINVAL (Invalid argument) 239 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f44) = -1 EINVAL (Invalid argument) 240 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f88) = -1 EINVAL (Invalid argument) 241 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41fcc) = -1 EINVAL (Invalid argument) 242 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42010) = -1 EINVAL (Invalid argument) 243 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42054) = -1 EINVAL (Invalid argument) 244 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42098) = -1 EINVAL (Invalid argument) 245 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b420dc) = -1 EINVAL (Invalid argument) 246 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42120) = -1 EINVAL (Invalid argument) 247 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42164) = -1 EINVAL (Invalid argument) 248 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b421a8) = -1 EINVAL (Invalid argument) 249 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b421ec) = -1 EINVAL (Invalid argument) 250 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42230) = -1 EINVAL (Invalid argument) 251 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42274) = -1 EINVAL (Invalid argument) 252 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b422b8) = -1 EINVAL (Invalid argument) 253 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b422fc) = -1 EINVAL (Invalid argument) 254 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42340) = -1 EINVAL (Invalid argument) 255 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42384) = -1 EINVAL (Invalid argument) 256 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b423c8) = -1 EINVAL (Invalid argument) 257 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4240c) = -1 EINVAL (Invalid argument) 258 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42450) = -1 EINVAL (Invalid argument) 259 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42494) = -1 EINVAL (Invalid argument) 260 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b424d8) = -1 EINVAL (Invalid argument) 261 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4251c) = -1 EINVAL (Invalid argument) 262 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42560) = -1 EINVAL (Invalid argument) 263 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b425a4) = -1 EINVAL (Invalid argument) 264 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b425e8) = -1 EINVAL (Invalid argument) 265 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4262c) = -1 EINVAL (Invalid argument) 266 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42670) = -1 EINVAL (Invalid argument) 267 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b426b4) = -1 EINVAL (Invalid argument) 268 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b426f8) = -1 EINVAL (Invalid argument) 269 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4273c) = -1 EINVAL (Invalid argument) 270 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42780) = -1 EINVAL (Invalid argument) 271 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b427c4) = -1 EINVAL (Invalid argument) 272 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42808) = -1 EINVAL (Invalid argument) 273 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4284c) = -1 EINVAL (Invalid argument) 274 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42890) = -1 EINVAL (Invalid argument) 275 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b428d4) = -1 EINVAL (Invalid argument) 276 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42918) = -1 EINVAL (Invalid argument) 277 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4295c) = -1 EINVAL (Invalid argument) 278 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b429a0) = -1 EINVAL (Invalid argument) 279 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b429e4) = -1 EINVAL (Invalid argument) 280 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42a28) = -1 EINVAL (Invalid argument) 281 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42a6c) = -1 EINVAL (Invalid argument) 282 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42ab0) = -1 EINVAL (Invalid argument) 283 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42af4) = -1 EINVAL (Invalid argument) 284 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42b38) = -1 EINVAL (Invalid argument) 285 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42b7c) = -1 EINVAL (Invalid argument) 286 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42bc0) = -1 EINVAL (Invalid argument) 287 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42c04) = -1 EINVAL (Invalid argument) 288 ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42c48) = -1 EINVAL (Invalid argument) 289 ioctl(4, VIDIOC_G_STD, 0xbfacce08) = 0 290 ioctl(4, VIDIOC_G_INPUT, 0xbfacce1c) = 0 291 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 292 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 293 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 294 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0 295 ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce24) = 0 296 ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4) = 0 297 ioctl(4, VIDIOC_S_FMT or VT_RELDISP, 0xbfacc754) = 0 298 ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4) = 0 299 ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0x9b42d80) = 0 300 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0x9b42d94) = 0 301 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0x9b42dd8) = 0 302 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 303 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 304 ioctl(4, VIDIOC_STREAMON, 0xbfacca2c) = 0 305 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 306 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 307 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 308 ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0 309 ioctl(4, VIDIOC_S_INPUT, 0xbfacce84) = 0 310 ioctl(4, VIDIOC_S_STD, 0x9b40f90) = 0 311 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 312 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 313 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 314 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 315 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 316 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 317 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 318 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 319 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 320 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 321 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 322 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 323 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 324 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 325 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 326 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 327 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 328 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 329 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 330 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 331 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 332 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 333 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 334 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 335 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 336 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 337 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 338 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 339 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 340 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 341 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 342 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 343 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 344 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 345 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 346 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 347 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 348 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 349 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 350 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 351 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 352 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 353 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 354 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 355 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 356 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 357 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 358 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 359 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 360 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 361 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 362 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 363 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 364 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 365 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 366 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 367 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 368 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 369 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 370 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 371 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 372 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 373 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 374 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 375 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 376 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 377 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 378 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 379 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 380 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 381 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 382 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 383 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 384 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 385 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 386 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 387 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 388 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 389 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 390 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 391 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 392 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 393 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 394 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 395 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 396 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 397 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 398 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 399 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 400 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 401 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 402 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 403 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 404 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 405 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 406 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 407 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 408 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 409 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 410 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 411 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 412 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 413 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 414 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 415 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 416 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 417 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 418 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 419 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 420 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 421 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 422 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 423 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 424 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 425 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 426 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 427 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 428 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 429 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 430 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 431 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 432 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 433 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 434 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 435 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 436 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 437 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 438 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 439 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 440 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 441 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 442 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 443 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 444 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 445 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 446 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 447 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 448 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 449 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 450 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 451 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 452 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 453 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 454 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 455 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 456 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 457 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 458 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 459 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 460 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 461 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 462 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 463 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 464 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 465 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 466 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 467 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 468 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 469 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 470 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 471 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 472 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 473 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 474 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 475 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 476 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 477 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 478 ioctl(4, VIDIOC_QBUF, 0x9b42dd8) = 0 479 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 480 ioctl(4, VIDIOC_QBUF, 0x9b42d94) = 0 481 ioctl(4, VIDIOC_DQBUF, 0xbfaccd00) = 0 482 ioctl(4, VIDIOC_STREAMOFF, 0xbfacc53c) = 0 483 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc48c) = 0 484 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc48c) = 0 485 ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0x9b42d80) = -1 EINVAL (Invalid argument) 486 ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4) = -1 EINVAL (Invalid argument) 487 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 488 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 489 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 490 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 491 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 492 ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000) = 0 493 ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0xbfacc70c) = 0 494 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc61c) = 0 495 ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc61c) = 0 496 ioctl(4, VIDIOC_QBUF, 0xbfacc61c) = 0 497 ioctl(4, VIDIOC_QBUF, 0xbfacc61c) = 0 498 ioctl(4, VIDIOC_STREAMON, 0xbfacc65c) = 0 499 ioctl(4, VIDIOC_DQBUF, 0xbfacc6c8) = 0 500 ioctl(4, VIDIOC_QBUF, 0xbfacc61c) = 0
xawtv.log文件中open()函數以後調用了ioctl(4, VIDIOC_QUERYCAP, ...),所以文件描述符操做ioctl(4, VIDIOC_QUERYCAP, ...)上面的全部行不會涉及驅動底層
最後,咱們能夠根據文件描述符操做文件、xawtv.log和SI4工程肯定ioctl()執行過程:
open("/dev/video0", O_RDWR|O_LARGEFILE) /* 1. 打開video0 */ ioctl(4, VIDIOC_QUERYCAP /* 2. 列舉性能 */ ioctl(4, VIDIOC_G_FMT /* 3. 得到格式 */ for () -> ioctl(4, VIDIOC_ENUM_FMT /* 4. 列舉格式 */ ioctl(4, VIDIOC_QUERYCAP /* 5. */ ioctl(4, VIDIOC_G_INPUT /* 6. 獲取當前輸入源 */ ioctl(4, VIDIOC_ENUMINPUT /* 7. 列舉輸入源 */ ioctl(4, VIDIOC_QUERYCTRL /* 8. 查詢屬性,如亮度範圍、對比度範圍 */ ioctl(4, VIDIOC_QUERYCAP /* 9. */ ioctl(4, VIDIOC_ENUMINPUT /* 10. */ for () -> ioctl(4, VIDIOC_ENUMINPUT /* 11. */ for () -> ioctl(4, VIDIOC_ENUMSTD /* 12.列舉標準 */ for () -> ioctl(4, VIDIOC_ENUM_FMT /* 13. */ ioctl(4, VIDIOC_G_PARM /* 14. */ for () -> ioctl(4, VIDIOC_QUERYCTRL /* 15. */ ioctl(4, VIDIOC_G_STD /* 16.獲取當前使用的標準 */ ioctl(4, VIDIOC_G_INPUT /* 17. */ ioctl(4, VIDIOC_G_CTRL /* 18.獲取當前所使用的屬性 */ ioctl(4, VIDIOC_TRY_FMT /* 19.測試攝像頭支持的格式 */ ioctl(4, VIDIOC_S_FMT /* 20.設置攝像頭格式 */ ioctl(4, VIDIOC_REQBUFS /* 21.請求系統分配緩衝區 */ ioctl(4, VIDIOC_QUERYBUF /* 22.查詢所分配的緩衝區 */ for () -> ioctl(4, VIDIOC_QBUF /* 23.把緩衝區放入隊列 */ ioctl(4, VIDIOC_STREAMON /* 24.啓動攝像頭 */ for () -> ioctl(4, VIDIOC_S_CTRL /* 25.設置屬性 */ ioctl(4, VIDIOC_S_INPUT /* 26.設置輸入源 */ ioctl(4, VIDIOC_S_STD /* 27.設置標準 */ for () -> select(5, [4] /* 28.查詢文件描述符4是否有數據 */ -> ioctl(4, VIDIOC_DQBUF /* 29.把緩衝區從隊列中取出 */ -> /* 處理數據 */ -> ioctl(4, VIDIOC_QBUF /* 30.把緩衝區放入隊列 */ ioctl(4, VIDIOC_STREAMOFF /* 31.關閉攝像頭 */
在分析完ioctl()的執行過程後,咱們須要在SI4工程文件drv0-v4l2.c文件中搜索ioctl()各個宏,肯定v4l2_ioctl_ops必需的函數指針:
/** 1~2被v4l2_open(char *device)調用 */ open("/dev/video0", O_RDWR|O_LARGEFILE) /* 1. 打開video0 */ ioctl(4, VIDIOC_QUERYCAP /* 2. 列舉性能 */ /** 3~10沒有看到調用過程,可能源碼和應用程序不一致,略 */ /** 11~15被get_device_capabilities(h)調用 */ for () -> ioctl(4, VIDIOC_ENUMINPUT /* 11. */ for () -> ioctl(4, VIDIOC_ENUMSTD /* 12.列舉標準 */ for () -> ioctl(4, VIDIOC_ENUM_FMT /* 13. */ ioctl(4, VIDIOC_G_PARM /* 14. */ for () -> ioctl(4, VIDIOC_QUERYCTRL /* 15. */ /** 16~18被v4l2_read_attr()調用 */ ioctl(4, VIDIOC_G_STD /* 16.獲取當前使用的標準 */ ioctl(4, VIDIOC_G_INPUT /* 17. */ ioctl(4, VIDIOC_G_CTRL /* 18.獲取當前所使用的屬性 */ /** 19~20被v4l2_overlay()調用 */ ioctl(4, VIDIOC_TRY_FMT /* 19.測試攝像頭支持的格式 */ ioctl(4, VIDIOC_S_FMT /* 20.設置攝像頭格式 */ /** 21~24被v4l2_start_streaming()調用 */ ioctl(4, VIDIOC_REQBUFS /* 21.請求系統分配緩衝區 */ ioctl(4, VIDIOC_QUERYBUF /* 22.查詢所分配的緩衝區 */ for () -> ioctl(4, VIDIOC_QBUF /* 23.把緩衝區放入隊列 */ -> h->buf_me[i].data = mmap(...); ioctl(4, VIDIOC_STREAMON /* 24.啓動攝像頭 */ /** 25~27被v4l2_write_attr()調用 */ ioctl(4, VIDIOC_S_CTRL /* 25.設置屬性 */ ioctl(4, VIDIOC_S_INPUT /* 26.設置輸入源 */ ioctl(4, VIDIOC_S_STD /* 27.設置標準 */ /** 28~29被v4l2_waiton()調用 * 30被v4l2_queue_buffer()調用 * v4l2_waiton()和v4l2_queue_buffer()被v4l2_nextframe()調用 */ for () -> select(5, [4] /* 28.查詢文件描述符4是否有數據 */ -> ioctl(4, VIDIOC_DQBUF /* 29.把緩衝區從隊列中取出 */ -> /* 處理數據,以前使用mmap()得到了緩衝區的地址 */ -> ioctl(4, VIDIOC_QBUF /* 30.把緩衝區放入隊列 */ /** 31被v4l2_stop_streaming()調用 */ ioctl(4, VIDIOC_STREAMOFF /* 31.關閉攝像頭 */
剩下這麼多宏,有哪一個是能夠省略的呢?
咱們如今要回到虛擬機內核的vivi.c中vivi_ioctl_ops逐個測試,測試方法爲:註釋某個函數指針,從新編譯掛載,測試是否能夠正常使用。
我在此再也不一一測試,最終結果以下:
static const struct v4l2_ioctl_ops vivi_ioctl_ops = { /* 表示它是一個攝像頭設備。不可省略 */ .vidioc_querycap = vidioc_querycap, #if 0 /* 列舉、獲取、設置輸入源。能夠省略,使用默認輸入源 */ .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, #endif /* 列舉、得到、測試、設置攝像頭的數據格式。不可省略 */ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, /* 緩衝區操做:申請、查詢、放入隊列、取出隊列。不可省略 */ .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, #if 0 /* 列舉、獲取、設置標準。能夠省略 * 列舉、獲取標準使用的是 * video_device的tvnorms和current_norm */ .vidioc_s_std = vidioc_s_std, #endif /* 啓動、中止視頻流。不可省略 */ .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, #if 0 /* 在內核日誌中記錄狀態。能夠省略 */ .vidioc_log_status = v4l2_ctrl_log_status, /* 子系統事件。能夠省略 */ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, #endif };
本節使用v4l2.c進行分析,讀者若對vb2感興趣也能夠分析vivi.c
1. 請求分配緩衝區,但此階段其實只分配了videobuf_buffer
ioctl(4, VIDIOC_REQBUFS -> solo_reqbufs -> videobuf_reqbufs(&fh->vidq, req); -> *size = solo_image_size(solo_dev); /* 設置圖片size */ -> __videobuf_mmap_setup(q, count, size, req->memory); -> q->bufs[i] = videobuf_alloc_vb(q); /* 分配設置videobuf_buffer */
2. 查詢映射緩衝區,經過videobuf_buffer設置供上層使用的v4l2_buffer
ioctl(4, VIDIOC_QUERYBUF -> videobuf_querybuf -> videobuf_status(q, b, q->bufs[b->index], q->type); -> b->flags |= V4L2_BUF_FLAG_MAPPED; -> b->field = vb->field; -> b->timestamp = vb->ts; /* v4l2_buffer */
3. 真正分配緩衝區
mmap(NULL, h->buf_v4l2[i].length, ...) -> solo_v4l2_mmap -> videobuf_mmap_mapper(&fh->vidq, vma); -> CALL(q, mmap_mapper, q, buf, vma)
4. 把緩衝區放入隊列
ioctl(4, VIDIOC_QBUF -> videobuf_qbuf(&fh->vidq, buf); -> buf = q->bufs[b->index]; -> solo_buf_prepare /* 設置video_device成員 */ -> vb->width = solo_dev->video_hsize; -> vb->height = solo_vlines(solo_dev); -> list_add_tail(&buf->stream, &q->stream) -> solo_buf_queue /* 把queue放到list_head */ -> list_add_tail(&vb->queue, &fh->vidq_active);
5. 啓動攝像頭
ioctl(4, VIDIOC_STREAMON -> solo_streamon -> videobuf_streamon(&fh->vidq); -> solo_buf_queue /* 把queue放到list_head */ -> list_add_tail(&vb->queue, &fh->vidq_active); -> wake_up_interruptible_sync(&q->wait);
6. 查詢是否有數據
select(h->fd + 1, &rdset, NULL, NULL, &tv) -> solo_v4l2_poll -> videobuf_poll_stream(file, &fh->vidq, wait); -> poll_wait(file, &buf->done, wait);
喚醒此進程的是open()函數註冊的solo_thread()函數
7. 從緩衝區中取數據
ioctl(4, VIDIOC_DQBUF -> solo_dqbuf -> videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); -> stream_next_buffer(q, &buf, nonblocking); /* 在queue中獲取有數據的緩衝區 */ -> videobuf_status(q, b, buf, q->type); /* 把緩衝區的狀態返回給應用層 */ -> list_del(&buf->stream);
1. 使用video_device_alloc()分配video_device
2. 設置結構體成員
.fops
.ioctl_ops(裏面須要設置11項)
若是要用內核提供的緩衝區操做函數,還須要構造一個videobuf_queue_ops
3. 使用video_register_device()註冊video_device
咱們能夠仿照v4l2.c寫一個虛擬攝像頭驅動程序
源代碼:
1 #include <linux/module.h> 2 #include <linux/delay.h> 3 #include <linux/errno.h> 4 #include <linux/fs.h> 5 #include <linux/kernel.h> 6 #include <linux/slab.h> 7 #include <linux/mm.h> 8 #include <linux/ioport.h> 9 #include <linux/init.h> 10 #include <linux/sched.h> 11 #include <linux/pci.h> 12 #include <linux/random.h> 13 #include <linux/version.h> 14 #include <linux/mutex.h> 15 #include <linux/videodev2.h> 16 #include <linux/dma-mapping.h> 17 #include <linux/interrupt.h> 18 #include <linux/kthread.h> 19 #include <linux/highmem.h> 20 #include <linux/freezer.h> 21 #include <media/videobuf-vmalloc.h> 22 #include <media/v4l2-device.h> 23 #include <media/v4l2-ioctl.h> 24 25 #define USE_DMA 0 26 27 static struct video_device *myvivi; 28 static struct v4l2_format myvivi_format; 29 static struct videobuf_queue myvivi_vb_vidq; 30 static spinlock_t myvivi_slock; 31 static struct timer_list myvivi_timer; 32 static struct list_head myvivi_list_head; 33 34 /** 35 * videobuf_queue_ops 36 **/ 37 /* ioctl VIDIOC_REQBUFS致使此函數被調用 38 * 用於從新調整count和size 39 */ 40 static int myvivi_buf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) 41 { 42 *size = myvivi_format.fmt.pix.sizeimage; 43 44 if (*count < 4) 45 *count = 4; 46 47 return 0; 48 } 49 50 /* ioctl VIDIOC_QBUF致使此函數被調用 51 * 它會填充video_buffer結構體並調用videobuf_iolock來分配內存 52 */ 53 static int myvivi_buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) 54 { 55 vb->size = myvivi_format.fmt.pix.sizeimage; 56 57 /* XXX: These properties only change when queue is idle */ 58 vb->width = myvivi_format.fmt.pix.width; 59 vb->height = myvivi_format.fmt.pix.height; 60 vb->bytesperline = myvivi_format.fmt.pix.bytesperline; 61 vb->field = field; 62 #if USE_DMA 63 if (vb->state == VIDEOBUF_NEEDS_INIT) { 64 int rc = videobuf_iolock(vq, vb, NULL); 65 if (rc < 0) { 66 struct videobuf_dmabuf *dma = videobuf_to_dma(vb); 67 videobuf_dma_unmap(vq->dev, dma); 68 videobuf_dma_free(dma); 69 vb->state = VIDEOBUF_NEEDS_INIT; 70 return rc; 71 } 72 } 73 #endif 74 vb->state = VIDEOBUF_PREPARED; 75 76 return 0; 77 } 78 79 /* ioctl VIDIOC_QBUF時: 80 * 1. 調用buf_prepare()作準備工做 81 * 2. 把buf放入stream隊列 82 * 3. 調用buf_queue(起通知、記錄做用) 83 */ 84 static void myvivi_buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) 85 { 86 vb->state = VIDEOBUF_QUEUED; 87 list_add_tail(&vb->queue, &myvivi_list_head); 88 /* 使用的定時器,不須要喚醒 */ 89 // wake_up_interruptible(&solo_dev->disp_thread_wait); 90 } 91 92 /* APP再也不使用隊列時,用它來釋放內存 */ 93 static void myvivi_buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) 94 { 95 #if USE_DMA 96 struct videobuf_dmabuf *dma = videobuf_to_dma(vb); 97 98 videobuf_dma_unmap(vq->dev, dma); 99 videobuf_dma_free(dma); 100 #endif 101 vb->state = VIDEOBUF_NEEDS_INIT; 102 } 103 104 105 static struct videobuf_queue_ops solo_video_qops = { 106 .buf_setup = myvivi_buf_setup, 107 .buf_prepare = myvivi_buf_prepare, 108 .buf_queue = myvivi_buf_queue, 109 .buf_release = myvivi_buf_release, 110 }; 111 112 /** 113 * v4l2_file_operations 114 **/ 115 static int myvivi_open(struct file *file) 116 { 117 videobuf_queue_vmalloc_init(&myvivi_vb_vidq, &solo_video_qops, 118 NULL, &myvivi_slock, 119 V4L2_BUF_TYPE_VIDEO_CAPTURE, 120 V4L2_FIELD_INTERLACED, 121 sizeof(struct videobuf_buffer), NULL, NULL); 122 /* 其餘程序在此處執行thread,本程序在此處執行定時器 */ 123 myvivi_timer.expires = jiffies + 1; 124 add_timer(&myvivi_timer); 125 126 return 0; 127 } 128 129 static int myvivi_close(struct file *file) 130 { 131 del_timer(&myvivi_timer); 132 videobuf_stop(&myvivi_vb_vidq); 133 videobuf_mmap_free(&myvivi_vb_vidq); 134 135 return 0; 136 } 137 138 static ssize_t myvivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) 139 { 140 return videobuf_read_stream(&myvivi_vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); 141 } 142 143 static unsigned int myvivi_poll(struct file *file, struct poll_table_struct *wait) 144 { 145 return videobuf_poll_stream(file, &myvivi_vb_vidq, wait); 146 } 147 148 extern int videobuf_mmap_mapper(struct videobuf_queue *, struct vm_area_struct *); 149 static int myvivi_mmap(struct file *file, struct vm_area_struct *vma) 150 { 151 return videobuf_mmap_mapper(&myvivi_vb_vidq, vma); 152 } 153 154 static const struct v4l2_file_operations myvivi_fops = { 155 .owner = THIS_MODULE, 156 .open = myvivi_open, 157 .release = myvivi_close, 158 .read = myvivi_read, 159 .poll = myvivi_poll, 160 .unlocked_ioctl = video_ioctl2, 161 .mmap = myvivi_mmap, 162 }; 163 164 /** 165 * v4l2_ioctl_ops 166 **/ 167 static int myvivi_querycap(struct file *file, void *priv, struct v4l2_capability *cap) 168 { 169 strcpy(cap->driver, "myvivi"); 170 strcpy(cap->card, "myvivi"); 171 cap->version = 0x01; 172 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; 173 return 0; 174 } 175 176 static int myvivi_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) 177 { 178 if (f->index) 179 return -EINVAL; 180 181 f->pixelformat = V4L2_PIX_FMT_YUYV; 182 strlcpy(f->description, "4:2:2, packed, YUYV", sizeof(f->description)); 183 184 return 0; 185 } 186 187 static int myvivi_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) 188 { 189 memcpy(f, &myvivi_format, sizeof(myvivi_format)); 190 return 0; 191 } 192 193 static int myvivi_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) 194 { 195 enum v4l2_field field; 196 unsigned int max_width, max_height; 197 198 if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) 199 return -EINVAL; 200 201 field = f->fmt.pix.field; 202 if (field == V4L2_FIELD_ANY) { 203 field = V4L2_FIELD_INTERLACED; 204 } 205 else if (V4L2_FIELD_INTERLACED != field) { 206 return -EINVAL; 207 } 208 f->fmt.pix.field = field; 209 210 max_width = 1024; 211 max_height = 768; 212 213 v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2, 214 &f->fmt.pix.height, 32, max_height, 0, 0); 215 f->fmt.pix.bytesperline = 216 (f->fmt.pix.width * 16) >> 3; 217 f->fmt.pix.sizeimage = 218 f->fmt.pix.height * f->fmt.pix.bytesperline; 219 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 220 221 return 0; 222 } 223 224 static int myvivi_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) 225 { 226 int ret; 227 if (videobuf_queue_is_busy(&myvivi_vb_vidq)) 228 return -EBUSY; 229 230 ret = myvivi_try_fmt_vid_cap(file, priv, f); 231 if (ret < 0) 232 return ret; 233 234 memcpy(&myvivi_format, f, sizeof(myvivi_format)); 235 236 return 0; 237 } 238 239 static int myvivi_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) 240 { 241 return videobuf_reqbufs(&myvivi_vb_vidq, p); 242 } 243 244 static int myvivi_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) 245 { 246 return videobuf_querybuf(&myvivi_vb_vidq, p); 247 } 248 249 static int myvivi_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) 250 { 251 return videobuf_qbuf(&myvivi_vb_vidq, p); 252 } 253 254 static int myvivi_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) 255 { 256 return videobuf_dqbuf(&myvivi_vb_vidq, p, file->f_flags & O_NONBLOCK); 257 } 258 259 static int myvivi_streamon(struct file *file, void *priv, enum v4l2_buf_type i) 260 { 261 return videobuf_streamon(&myvivi_vb_vidq); 262 } 263 264 static int myvivi_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) 265 { 266 videobuf_streamoff(&myvivi_vb_vidq); 267 return 0; 268 } 269 270 static const struct v4l2_ioctl_ops myvivi_ioctl_ops = { 271 .vidioc_querycap = myvivi_querycap, 272 .vidioc_enum_fmt_vid_cap = myvivi_enum_fmt_vid_cap, 273 .vidioc_g_fmt_vid_cap = myvivi_g_fmt_vid_cap, 274 .vidioc_try_fmt_vid_cap = myvivi_try_fmt_vid_cap, 275 .vidioc_s_fmt_vid_cap = myvivi_s_fmt_vid_cap, 276 .vidioc_reqbufs = myvivi_reqbufs, 277 .vidioc_querybuf = myvivi_querybuf, 278 .vidioc_qbuf = myvivi_qbuf, 279 .vidioc_dqbuf = myvivi_dqbuf, 280 .vidioc_streamon = myvivi_streamon, 281 .vidioc_streamoff = myvivi_streamoff, 282 }; 283 284 static void myvivi_release(struct video_device *vdev) 285 { 286 /* myvivi_exit()中調用了video_device_release() 287 * 所以myvivi->release不須要設置爲video_device_release 288 */ 289 } 290 291 /* 此函數用於實現其餘文件的thread() */ 292 static void myvivi_timerfunc(unsigned long arg) 293 { 294 struct videobuf_buffer *vb; 295 void *vbuf; 296 297 if (list_empty(&myvivi_list_head)) 298 goto fail; 299 300 vb = list_first_entry(&myvivi_list_head, struct videobuf_buffer, 301 queue); 302 303 if (!waitqueue_active(&vb->done)) 304 goto fail; 305 306 /* Fill buffer */ 307 vbuf = videobuf_to_vmalloc(vb); 308 if (!vbuf) 309 goto fail; 310 311 /* 因爲是虛擬攝像頭驅動,因此僞裝有數據 */ 312 memset(vbuf, 0, vb->size); 313 314 vb->field_count++; 315 do_gettimeofday(&vb->ts); 316 vb->state = VIDEOBUF_DONE; 317 318 /* 把videobuf從隊列中刪除 */ 319 list_del(&vb->queue); 320 321 /* 喚醒videobuf->done上的進程 */ 322 wake_up(&vb->done); 323 324 fail: 325 /* 30幀/秒 */ 326 mod_timer(&myvivi_timer, jiffies + HZ / 30); 327 } 328 329 static int __init myvivi_init(void) 330 { 331 int ret; 332 333 myvivi = video_device_alloc(); 334 335 myvivi->release = myvivi_release, 336 myvivi->fops = &myvivi_fops; 337 myvivi->ioctl_ops = &myvivi_ioctl_ops; 338 339 /* 初始化spinlock */ 340 spin_lock_init(&myvivi_slock); 341 /* 初始化timer_list */ 342 init_timer(&myvivi_timer); 343 myvivi_timer.function = myvivi_timerfunc; 344 /* 初始化list_head */ 345 INIT_LIST_HEAD(&myvivi_list_head); 346 347 ret = video_register_device(myvivi, VFL_TYPE_GRABBER, -1); 348 if (ret < 0) { 349 video_device_release(myvivi); 350 return ret; 351 } 352 353 return 0; 354 } 355 356 static void __exit myvivi_exit(void) 357 { 358 video_unregister_device(myvivi); 359 video_device_release(myvivi); 360 } 361 362 module_init(myvivi_init); 363 module_exit(myvivi_exit); 364 MODULE_LICENSE("GPL");
Makefile:
1 KERN_DIR = /work/itop4412/tools/linux-3.5 2 3 all: 4 make -C $(KERN_DIR) M=`pwd` modules 5 6 clean: 7 make -C $(KERN_DIR) M=`pwd` modules clean 8 rm -rf modules.order 9 10 obj-m += videobuf-vmalloc.o 11 obj-m += myvivi.o
因爲是虛擬攝像頭,因此源代碼中的攝像頭參數和數據格式是根據內核規則隨意選擇的,參數的肯定和選取會在下一章進行介紹
本章內容較爲混亂,推薦讀者自行分析linux/drivers/staging/media/solo6x10/v4l2.c和第八節:數據的獲取過程體驗各個過程的調用關係