V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_VBI_OUTPUT |
V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_MODULATOR |
V4L2_CAP_RDS_OUTPUT;
+ const __u32 io_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
// Must always be there
fail_on_test(doioctl(node, VIDIOC_QUERYCAP, &vcap));
fail_on_test(dcaps & output_caps);
if (dcaps & output_caps)
fail_on_test(dcaps & input_caps);
+ if (node->can_capture || node->can_output)
+ fail_on_test(!(dcaps & io_caps));
+ else
+ fail_on_test(dcaps & io_caps);
return 0;
}
device = vbi_device;
node.is_vbi = true;
}
+ node.device = device;
doioctl(&node, VIDIOC_QUERYCAP, &vcap);
if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_RDS_OUTPUT |
V4L2_CAP_MODULATOR))
node.has_outputs = true;
+ if (node.caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_SLICED_VBI_CAPTURE))
+ node.can_capture = true;
+ if (node.caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VBI_OUTPUT |
+ V4L2_CAP_SLICED_VBI_OUTPUT))
+ node.can_output = true;
/* Information Opts */
printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&video_node2)));
printf("\ttest VIDIOC_G/S_PRIORITY: %s\n",
ok(testPrio(&video_node, &video_node2)));
- test_close(video_node2.fd);
+ node.node2 = &video_node2;
}
}
if (radio_device) {
printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&radio_node2)));
printf("\ttest VIDIOC_G/S_PRIORITY: %s\n",
ok(testPrio(&radio_node, &radio_node2)));
- test_close(radio_node2.fd);
+ node.node2 = &video_node2;
}
}
if (vbi_device) {
printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&vbi_node2)));
printf("\ttest VIDIOC_G/S_PRIORITY: %s\n",
ok(testPrio(&vbi_node, &vbi_node2)));
- test_close(vbi_node2.fd);
+ node.node2 = &video_node2;
}
}
printf("\n");
printf("\ttest VIDIOC_G_FMT: %s\n", ok(testFormats(&node)));
printf("\ttest VIDIOC_G_SLICED_VBI_CAP: %s\n", ok(testSlicedVBICap(&node)));
+ /* Buffer ioctls */
+
+ printf("Buffer ioctls:\n");
+ printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS: %s\n", ok(testReqBufs(&node)));
+ printf("\ttest read/write: %s\n", ok(testReadWrite(&node)));
+
/* TODO:
VIDIOC_CROPCAP, VIDIOC_G/S_CROP, VIDIOC_G/S_SELECTION
VIDIOC_(TRY_)ENCODER_CMD
VIDIOC_(TRY_)DECODER_CMD
VIDIOC_G_ENC_INDEX
- VIDIOC_REQBUFS/QBUF/DQBUF/QUERYBUF/CREATE_BUFS/PREPARE_BUFS
+ VIDIOC_QBUF/DQBUF/QUERYBUF/PREPARE_BUFS
VIDIOC_STREAMON/OFF
*/
/* Final test report */
test_close(node.fd);
+ test_close(node.node2->fd);
printf("Total: %d Succeeded: %d Failed: %d Warnings: %d\n",
tests_total, tests_ok, tests_total - tests_ok, warnings);
exit(app_result);
--- /dev/null
+/*
+ V4L2 API compliance buffer ioctl tests.
+
+ Copyright (C) 2012 Hans Verkuil <hverkuil@xs4all.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include "v4l2-compliance.h"
+
+int testReqBufs(struct node *node)
+{
+ struct v4l2_requestbuffers bufs;
+ struct v4l2_create_buffers cbufs;
+ struct v4l2_format fmt;
+ bool can_stream = node->caps & V4L2_CAP_STREAMING;
+ bool can_rw = node->caps & V4L2_CAP_READWRITE;
+ bool mmap_valid;
+ bool userptr_valid;
+ int ret;
+ unsigned i;
+
+ memset(&bufs, 0, sizeof(bufs));
+ memset(&cbufs, 0, sizeof(cbufs));
+ ret = doioctl(node, VIDIOC_REQBUFS, &bufs);
+ if (ret == ENOTTY) {
+ fail_on_test(can_stream);
+ return ret;
+ }
+ fail_on_test(ret != EINVAL);
+ fail_on_test(node->node2 == NULL);
+ for (i = 1; i <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; i++) {
+ if (node->buftype_pixfmts[i].empty())
+ continue;
+ info("test buftype %d\n", i);
+ if (node->valid_buftype == 0)
+ node->valid_buftype = i;
+ fmt.type = i;
+ fail_on_test(doioctl(node, VIDIOC_G_FMT, &fmt));
+ bufs.type = fmt.type;
+ fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs) != EINVAL);
+ bufs.memory = V4L2_MEMORY_MMAP;
+ ret = doioctl(node, VIDIOC_REQBUFS, &bufs);
+ fail_on_test(ret && ret != EINVAL);
+ mmap_valid = !ret;
+ bufs.memory = V4L2_MEMORY_USERPTR;
+ ret = doioctl(node, VIDIOC_REQBUFS, &bufs);
+ fail_on_test(ret && ret != EINVAL);
+ userptr_valid = !ret;
+ fail_on_test(can_stream && !mmap_valid && !userptr_valid);
+ fail_on_test(!can_stream && (mmap_valid || userptr_valid));
+ if (!can_stream)
+ continue;
+
+ if (mmap_valid) {
+ bufs.count = 1;
+ bufs.memory = V4L2_MEMORY_MMAP;
+ fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs));
+ fail_on_test(bufs.count == 0);
+ fail_on_test(bufs.memory != V4L2_MEMORY_MMAP);
+ fail_on_test(bufs.type != i);
+ fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs));
+ }
+ if (userptr_valid) {
+ bufs.count = 1;
+ bufs.memory = V4L2_MEMORY_USERPTR;
+ fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs));
+ fail_on_test(bufs.count == 0);
+ fail_on_test(bufs.memory != V4L2_MEMORY_USERPTR);
+ fail_on_test(bufs.type != i);
+ fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs));
+ }
+
+ if (can_rw) {
+ char buf = 0;
+
+ if (node->can_capture)
+ ret = read(node->fd, &buf, 1);
+ else
+ ret = write(node->fd, &buf, 1);
+ fail_on_test(ret != -1);
+ fail_on_test(errno != EBUSY);
+ }
+ bufs.count = 1;
+ fail_on_test(doioctl(node->node2, VIDIOC_REQBUFS, &bufs) != EBUSY);
+ bufs.count = 0;
+ fail_on_test(doioctl(node->node2, VIDIOC_REQBUFS, &bufs) != EBUSY);
+ fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs));
+ bufs.count = 1;
+ fail_on_test(doioctl(node->node2, VIDIOC_REQBUFS, &bufs));
+ bufs.count = 0;
+ fail_on_test(doioctl(node->node2, VIDIOC_REQBUFS, &bufs));
+ cbufs.format = fmt;
+ cbufs.count = 1;
+ cbufs.memory = bufs.memory;
+ ret = doioctl(node, VIDIOC_CREATE_BUFS, &cbufs);
+ if (ret == ENOTTY) {
+ warn("VIDIOC_CREATE_BUFS not supported\n");
+ continue;
+ }
+ fail_on_test(cbufs.count == 0);
+ fail_on_test(cbufs.memory != bufs.memory);
+ fail_on_test(cbufs.format.type != i);
+ cbufs.count = 1;
+ fail_on_test(doioctl(node, VIDIOC_CREATE_BUFS, &cbufs));
+ bufs.count = 1;
+ fail_on_test(doioctl(node->node2, VIDIOC_REQBUFS, &bufs) != EBUSY);
+ bufs.count = 0;
+ fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs));
+ }
+ return 0;
+}
+
+int testReadWrite(struct node *node)
+{
+ bool can_rw = node->caps & V4L2_CAP_READWRITE;
+ char buf = 0;
+ int ret;
+
+ if (node->can_capture)
+ ret = read(node->fd, &buf, 1);
+ else
+ ret = write(node->fd, &buf, 1);
+ if (can_rw)
+ fail_on_test(ret != 1);
+ else
+ fail_on_test(ret < 0 && errno != EINVAL);
+ if (!can_rw)
+ return 0;
+
+ reopen(node);
+
+ /* check that the close cleared the busy flag */
+ if (node->can_capture)
+ ret = read(node->fd, &buf, 1);
+ else
+ ret = write(node->fd, &buf, 1);
+ fail_on_test(ret != 1);
+ reopen(node);
+ return 0;
+}