Skip to content

Commit db5faf8

Browse files
committed
Support dmabuf ioctls
Resolves #3891
1 parent a3bbf7e commit db5faf8

File tree

3 files changed

+179
-0
lines changed

3 files changed

+179
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,7 @@ set(BASIC_TESTS
14171417
unshare
14181418
userfaultfd
14191419
utimes
1420+
v4l_dmabuf
14201421
vdso_parts
14211422
vdso_symbols
14221423
vfork_done

src/record_syscall.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/blkzoned.h>
1010
#include <linux/capability.h>
1111
#include <linux/cdrom.h>
12+
#include <linux/dma-buf.h>
1213
#include <linux/elf.h>
1314
#include <linux/ethtool.h>
1415
#include <linux/fb.h>
@@ -2013,7 +2014,9 @@ static Switchable prepare_ioctl(RecordTask* t,
20132014
case IOCTL_MASK_SIZE(VIDIOC_G_INPUT):
20142015
case IOCTL_MASK_SIZE(VIDIOC_QUERY_EXT_CTRL):
20152016
case IOCTL_MASK_SIZE(VIDIOC_G_PRIORITY):
2017+
case IOCTL_MASK_SIZE(VIDIOC_EXPBUF):
20162018
case IOCTL_MASK_SIZE(VFAT_IOCTL_READDIR_BOTH):
2019+
case IOCTL_MASK_SIZE(DMA_BUF_IOCTL_EXPORT_SYNC_FILE):
20172020
syscall_state.reg_parameter(3, size, IN_OUT);
20182021
return PREVENT_SWITCH;
20192022

src/test/v4l_dmabuf.c

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
2+
3+
#include "util.h"
4+
5+
#include <linux/dma-buf.h>
6+
7+
static const char device_name[] = "/dev/video0";
8+
9+
static void no_v4l2(void) {
10+
atomic_puts("EXIT-SUCCESS");
11+
exit(0);
12+
}
13+
14+
static int open_device(void) {
15+
struct v4l2_capability* cap;
16+
int fd = open("/dev/video0", O_RDWR);
17+
int ret;
18+
19+
if (fd < 0 && errno == ENOENT) {
20+
atomic_printf("%s not found; aborting test\n", device_name);
21+
no_v4l2();
22+
}
23+
if (fd < 0 && errno == EACCES) {
24+
atomic_printf("%s not accessible; aborting test\n", device_name);
25+
no_v4l2();
26+
}
27+
test_assert(fd >= 0);
28+
29+
ALLOCATE_GUARD(cap, 'a');
30+
ret = ioctl(fd, VIDIOC_QUERYCAP, cap);
31+
VERIFY_GUARD(cap);
32+
if (ret < 0 && errno == EINVAL) {
33+
atomic_printf("%s is not a V4L2 device; aborting test\n", device_name);
34+
no_v4l2();
35+
}
36+
if (ret < 0 && errno == EACCES) {
37+
atomic_printf("%s is not accessible; aborting test\n", device_name);
38+
no_v4l2();
39+
}
40+
if (!(cap->capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
41+
atomic_printf("%s is not a V4L2 capture device; aborting test\n",
42+
device_name);
43+
no_v4l2();
44+
}
45+
if (!(cap->capabilities & V4L2_CAP_STREAMING)) {
46+
atomic_printf("%s does not support streaming; aborting test\n",
47+
device_name);
48+
no_v4l2();
49+
}
50+
51+
uint32_t* input;
52+
ALLOCATE_GUARD(input, 'b');
53+
ret = ioctl(fd, VIDIOC_G_INPUT, input);
54+
VERIFY_GUARD(input);
55+
if (ret < 0) {
56+
atomic_printf("%s does not support VIDIOC_G_INPUT\n", device_name);
57+
} else {
58+
atomic_printf("%s VIDIOC_G_INPUT returns %d\n", device_name, *input);
59+
}
60+
61+
#ifdef VIDIOC_QUERY_EXT_CTRL
62+
struct v4l2_query_ext_ctrl* qec;
63+
ALLOCATE_GUARD(qec, 'c');
64+
memset(qec, 0, sizeof(*qec));
65+
qec->id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
66+
ret = ioctl(fd, VIDIOC_QUERY_EXT_CTRL, qec);
67+
VERIFY_GUARD(qec);
68+
if (ret < 0) {
69+
atomic_printf("%s does not support VIDIOC_QUERY_EXT_CTRL\n", device_name);
70+
} else {
71+
atomic_printf("%s VIDIOC_QUERY_EXT_CTRL returns id=%d, type=%d, name=%s\n",
72+
device_name, qec->id, qec->type, qec->name);
73+
}
74+
#endif
75+
76+
enum v4l2_priority* prio;
77+
ALLOCATE_GUARD(prio, 'd');
78+
ret = ioctl(fd, VIDIOC_G_PRIORITY, prio);
79+
VERIFY_GUARD(prio);
80+
if (ret < 0) {
81+
atomic_printf("%s does not support VIDIOC_G_PRIORITY\n", device_name);
82+
} else {
83+
atomic_printf("%s VIDIOC_G_PRIORITY returns prio=%d\n", device_name, *prio);
84+
}
85+
86+
struct v4l2_queryctrl* qc;
87+
ALLOCATE_GUARD(qc, 'e');
88+
memset(qc, 0, sizeof(*qc));
89+
qc->id = V4L2_CTRL_FLAG_NEXT_CTRL;
90+
ret = ioctl(fd, VIDIOC_QUERYCTRL, qc);
91+
VERIFY_GUARD(qc);
92+
if (ret < 0) {
93+
atomic_printf("%s does not support VIDIOC_QUERYCTRL\n", device_name);
94+
} else {
95+
atomic_printf("%s VIDIOC_QUERYCTRL returns id=%d, type=%d, name=%s\n",
96+
device_name, qc->id, qc->type, qc->name);
97+
}
98+
99+
return fd;
100+
}
101+
102+
static int get_dmabuf(int fd) {
103+
struct v4l2_requestbuffers* req;
104+
int ret;
105+
struct v4l2_exportbuffer* exp;
106+
107+
ALLOCATE_GUARD(req, 'a');
108+
req->count = 1;
109+
req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
110+
req->memory = V4L2_MEMORY_MMAP;
111+
ret = ioctl(fd, VIDIOC_REQBUFS, req);
112+
VERIFY_GUARD(req);
113+
if (ret < 0 && errno == EINVAL) {
114+
atomic_printf("%s does not support memory mapping; aborting test\n",
115+
device_name);
116+
no_v4l2();
117+
}
118+
if (ret < 0 && errno == EBUSY) {
119+
atomic_printf("%s is busy; aborting test\n", device_name);
120+
no_v4l2();
121+
}
122+
test_assert(0 == ret);
123+
if (req->count < 1) {
124+
atomic_puts("Got no buffers, aborting test");
125+
no_v4l2();
126+
}
127+
128+
ALLOCATE_GUARD(exp, 'b');
129+
exp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
130+
exp->index = 0;
131+
exp->plane = 0;
132+
exp->flags = O_RDONLY;
133+
memset(exp->reserved, 0, sizeof(exp->reserved));
134+
ret = ioctl(fd, VIDIOC_EXPBUF, exp);
135+
VERIFY_GUARD(exp);
136+
test_assert(ret == 0);
137+
test_assert(exp->fd >= 0);
138+
return exp->fd;
139+
}
140+
141+
int main(void) {
142+
int fd = open_device();
143+
int dmabuf = get_dmabuf(fd);
144+
145+
struct dma_buf_sync* sync;
146+
ALLOCATE_GUARD(sync, 'a');
147+
sync->flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ;
148+
int ret = ioctl(dmabuf, DMA_BUF_IOCTL_SYNC, sync);
149+
VERIFY_GUARD(sync);
150+
test_assert(ret == 0);
151+
152+
sync->flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ;
153+
ret = ioctl(dmabuf, DMA_BUF_IOCTL_SYNC, sync);
154+
VERIFY_GUARD(sync);
155+
test_assert(ret == 0);
156+
157+
struct dma_buf_export_sync_file* sync_file;
158+
ALLOCATE_GUARD(sync_file, 'b');
159+
sync_file->flags = DMA_BUF_SYNC_READ;
160+
ret = ioctl(dmabuf, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, sync_file);
161+
VERIFY_GUARD(sync_file);
162+
test_assert(ret == 0);
163+
test_assert(sync_file->fd >= 0);
164+
165+
struct dma_buf_import_sync_file* import_sync_file;
166+
ALLOCATE_GUARD(import_sync_file, 'c');
167+
import_sync_file->flags = DMA_BUF_SYNC_READ;
168+
import_sync_file->fd = sync_file->fd;
169+
ret = ioctl(dmabuf, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, import_sync_file);
170+
VERIFY_GUARD(import_sync_file);
171+
test_assert(ret == 0);
172+
173+
atomic_puts("EXIT-SUCCESS");
174+
return 0;
175+
}

0 commit comments

Comments
 (0)