This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/v4l-utils.git tree:
Subject: v4l2-compliance: add queryctrl/querymenu tests. Author: Hans Verkuil <[email protected]> Date: Sun Jan 9 22:58:32 2011 +0100 Signed-off-by: Hans Verkuil <[email protected]> utils/v4l2-compliance/Makefile | 3 +- utils/v4l2-compliance/v4l2-compliance.cpp | 91 ++++++----- utils/v4l2-compliance/v4l2-compliance.h | 7 + utils/v4l2-compliance/v4l2-test-controls.cpp | 231 ++++++++++++++++++++++++++ 4 files changed, 289 insertions(+), 43 deletions(-) --- http://git.linuxtv.org/v4l-utils.git?a=commitdiff;h=e4377f0f9bdb5538c5ee46db325e8b7b683f7dad diff --git a/utils/v4l2-compliance/Makefile b/utils/v4l2-compliance/Makefile index 816a371..b8aa16e 100644 --- a/utils/v4l2-compliance/Makefile +++ b/utils/v4l2-compliance/Makefile @@ -4,7 +4,8 @@ all: $(TARGETS) -include *.d -v4l2-compliance: v4l2-compliance.o v4l2-test-debug.o v4l2-test-input-output.o +v4l2-compliance: v4l2-compliance.o v4l2-test-debug.o v4l2-test-input-output.o \ + v4l2-test-controls.o $(CXX) $(LDFLAGS) -o $@ $^ install: $(TARGETS) diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp index dc2e245..5dc39d8 100644 --- a/utils/v4l2-compliance/v4l2-compliance.cpp +++ b/utils/v4l2-compliance/v4l2-compliance.cpp @@ -45,22 +45,22 @@ case is used to retrieve a setting. */ enum Option { OptSetDevice = 'd', - OptSetRadioDevice = 'r', - OptSetVbiDevice = 'V', OptHelp = 'h', + OptSetRadioDevice = 'r', OptTest = 't', - OptVerbose = 'v', OptTrace = 'T', + OptVerbose = 'v', + OptSetVbiDevice = 'V', OptLast = 256 }; enum Test { - TestCap = 0, - TestChipIdent, - TestRegister, - TestLogStatus, + TestRequired = 0, + TestMultipleOpen, + TestDebug, TestInput, TestOutput, + TestControls, TestMax }; @@ -73,6 +73,7 @@ static int tests_total, tests_ok; // Globals int verbose; +int ignore_failure; unsigned caps; static struct option long_options[] = { @@ -435,8 +436,8 @@ int main(int argc, char **argv) printf("\nCompliance test for device %s:\n\n", device); - printf("Required ioctls:\n"); - if (test[TestCap]) { + if (test[TestRequired]) { + printf("Required ioctls:\n"); if (video_device) printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&video_node))); if (radio_device) @@ -445,60 +446,66 @@ int main(int argc, char **argv) printf("\ttest VIDIOC_QUERYCAP for vbi: %s\n", ok(testCap(&vbi_node))); } - printf("Allow for multiple opens:\n"); - if (video_device) { - printf("\ttest second video open: %s\n", - ok((video_node2.fd = open(video_device, O_RDWR)) < 0)); - if (video_node2.fd >= 0) { - printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&video_node2))); - printf("\ttest VIDIOC_S_PRIORITY: %s\n", - ok(testPrio(&video_node, &video_node2))); - close(video_node2.fd); + if (test[TestMultipleOpen]) { + printf("Allow for multiple opens:\n"); + if (video_device) { + printf("\ttest second video open: %s\n", + ok((video_node2.fd = open(video_device, O_RDWR)) < 0)); + if (video_node2.fd >= 0) { + printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&video_node2))); + printf("\ttest VIDIOC_S_PRIORITY: %s\n", + ok(testPrio(&video_node, &video_node2))); + close(video_node2.fd); + } } - } - if (radio_device) { - printf("\ttest second radio open: %s\n", - ok((radio_node2.fd = open(radio_device, O_RDWR)) < 0)); - if (radio_node2.fd >= 0) { - printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&radio_node2))); - printf("\ttest VIDIOC_S_PRIORITY: %s\n", - ok(testPrio(&radio_node, &radio_node2))); - close(radio_node2.fd); + if (radio_device) { + printf("\ttest second radio open: %s\n", + ok((radio_node2.fd = open(radio_device, O_RDWR)) < 0)); + if (radio_node2.fd >= 0) { + printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&radio_node2))); + printf("\ttest VIDIOC_S_PRIORITY: %s\n", + ok(testPrio(&radio_node, &radio_node2))); + close(radio_node2.fd); + } } - } - if (vbi_device) { - printf("\ttest second vbi open: %s\n", - ok((vbi_node2.fd = open(vbi_device, O_RDWR)) < 0)); - if (vbi_node2.fd >= 0) { - printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&vbi_node2))); - printf("\ttest VIDIOC_S_PRIORITY: %s\n", - ok(testPrio(&vbi_node, &vbi_node2))); - close(vbi_node2.fd); + if (vbi_device) { + printf("\ttest second vbi open: %s\n", + ok((vbi_node2.fd = open(vbi_device, O_RDWR)) < 0)); + if (vbi_node2.fd >= 0) { + printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&vbi_node2))); + printf("\ttest VIDIOC_S_PRIORITY: %s\n", + ok(testPrio(&vbi_node, &vbi_node2))); + close(vbi_node2.fd); + } } } - printf("Debug ioctls:\n"); - if (test[TestChipIdent]) + if (test[TestDebug]) { + printf("Debug ioctls:\n"); printf("\ttest VIDIOC_DBG_G_CHIP_IDENT: %s\n", ok(testChipIdent(&node))); - if (test[TestRegister]) printf("\ttest VIDIOC_DBG_G/S_REGISTER: %s\n", ok(testRegister(&node))); - if (test[TestLogStatus]) printf("\ttest VIDIOC_LOG_STATUS: %s\n", ok(testLogStatus(&node))); + } - printf("Input ioctls:\n"); if (test[TestInput]) { + printf("Input ioctls:\n"); printf("\ttest VIDIOC_S/G_TUNER: %s\n", ok(testTuner(&node))); printf("\ttest VIDIOC_S/G/ENUMAUDIO: %s\n", ok(testInputAudio(&node))); printf("\ttest VIDIOC_G/S/ENUMINPUT: %s\n", ok(testInput(&node))); } - printf("Output ioctls:\n"); if (test[TestOutput]) { + printf("Output ioctls:\n"); printf("\ttest VIDIOC_S/G_MODULATOR: %s\n", ok(testModulator(&node))); printf("\ttest VIDIOC_S/G/ENUMAUDOUT: %s\n", ok(testOutputAudio(&node))); printf("\ttest VIDIOC_G/S/ENUMOUTPUT: %s\n", ok(testOutput(&node))); } + if (test[TestControls]) { + printf("Control ioctls:\n"); + printf("\ttest VIDIOC_QUERYCTRL/MENU: %s\n", ok(testQueryControls(&node))); + } + close(node.fd); printf("Total: %d Succeeded: %d Failed: %d\n", tests_total, tests_ok, tests_total - tests_ok); diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h index 9a17c1b..e503ac6 100644 --- a/utils/v4l2-compliance/v4l2-compliance.h +++ b/utils/v4l2-compliance/v4l2-compliance.h @@ -35,6 +35,10 @@ struct node { unsigned modulators; unsigned audio_inputs; unsigned audio_outputs; + unsigned user_controls; + unsigned priv_user_controls; + unsigned user_controls_check; + unsigned priv_user_controls_check; }; #define fail(fmt, args...) \ @@ -68,4 +72,7 @@ int testModulator(struct node *node); int testOutput(struct node *node); int testOutputAudio(struct node *node); +// Control ioctl tests +int testQueryControls(struct node *node); + #endif diff --git a/utils/v4l2-compliance/v4l2-test-controls.cpp b/utils/v4l2-compliance/v4l2-test-controls.cpp new file mode 100644 index 0000000..7feef2d --- /dev/null +++ b/utils/v4l2-compliance/v4l2-test-controls.cpp @@ -0,0 +1,231 @@ +/* + V4L2 API compliance control ioctl tests. + + Copyright (C) 2011 Hans Verkuil <[email protected]> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 validQCtrl(struct node *node, const struct v4l2_queryctrl &qctrl) +{ + struct v4l2_querymenu qmenu; + __u32 fl = qctrl.flags; + __u32 rw_mask = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; + unsigned menus = 0; + int ret; + int i; + + if (qctrl.id & V4L2_CTRL_FLAG_NEXT_CTRL) + return fail("V4L2_CTRL_FLAG_NEXT_CTRL not cleared\n"); + if (check_0(qctrl.reserved, sizeof(qctrl.reserved))) + return fail("non-zero reserved fields\n"); + if (check_ustring(qctrl.name, sizeof(qctrl.name))) + return fail("invalid name\n"); + switch (qctrl.type) { + case V4L2_CTRL_TYPE_BOOLEAN: + if (qctrl.maximum > 1) + return fail("invalid boolean max value\n"); + /* fall through */ + case V4L2_CTRL_TYPE_MENU: + if (qctrl.step != 1) + return fail("invalid step value %d\n", qctrl.step); + if (qctrl.minimum < 0) + return fail("min < 0\n"); + /* fall through */ + case V4L2_CTRL_TYPE_INTEGER: + if (qctrl.default_value < qctrl.minimum || + qctrl.default_value > qctrl.maximum) + return fail("def < min || def > max\n"); + /* fall through */ + case V4L2_CTRL_TYPE_STRING: + if (qctrl.minimum > qctrl.maximum) + return fail("min > max\n"); + if (qctrl.step == 0) + return fail("step == 0\n"); + if (qctrl.step < 0) + return fail("step < 0\n"); + if (qctrl.step > qctrl.maximum - qctrl.minimum) + return fail("step > max - min\n"); + break; + case V4L2_CTRL_TYPE_CTRL_CLASS: + case V4L2_CTRL_TYPE_INTEGER64: + case V4L2_CTRL_TYPE_BUTTON: + if (qctrl.minimum || qctrl.maximum || qctrl.step || qctrl.default_value) + return fail("non-zero min/max/step/def\n"); + break; + default: + return fail("unknown control type\n"); + } + if (qctrl.type == V4L2_CTRL_TYPE_STRING && qctrl.default_value) + return fail("non-zero default value for string\n"); + switch (qctrl.type) { + case V4L2_CTRL_TYPE_BUTTON: + if ((fl & rw_mask) != V4L2_CTRL_FLAG_WRITE_ONLY) + return fail("button control not write only\n"); + /* fall through */ + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_STRING: + if (fl & V4L2_CTRL_FLAG_SLIDER) + return fail("slider makes only sense for integer controls\n"); + /* fall through */ + case V4L2_CTRL_TYPE_INTEGER64: + case V4L2_CTRL_TYPE_INTEGER: + if ((fl & rw_mask) == rw_mask) + return fail("can't read nor write this control\n"); + break; + case V4L2_CTRL_TYPE_CTRL_CLASS: + if (fl != (V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY)) + return fail("invalid flags for control class\n"); + break; + } + if (qctrl.type != V4L2_CTRL_TYPE_MENU) { + memset(&qmenu, 0xff, sizeof(qmenu)); + qmenu.id = qctrl.id; + qmenu.index = qctrl.minimum; + ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu); + if (ret != EINVAL) + return fail("can do querymenu on a non-menu control\n"); + return 0; + } + for (i = 0; i <= qctrl.maximum + 1; i++) { + memset(&qmenu, 0xff, sizeof(qmenu)); + qmenu.id = qctrl.id; + qmenu.index = i; + ret = doioctl(node, VIDIOC_QUERYMENU, &qmenu); + if (ret && ret != EINVAL) + return fail("invalid QUERYMENU return code\n"); + if (ret) + continue; + if (i < qctrl.minimum || i > qctrl.maximum) + return fail("can get menu for out-of-range index\n"); + if (qmenu.index != (__u32)i || qmenu.id != qctrl.id) + return fail("id or index changed\n"); + if (check_ustring(qmenu.name, sizeof(qmenu.name))) + return fail("invalid menu name\n"); + if (qmenu.reserved) + return fail("reserved is non-zero\n"); + menus++; + return 0; + } + if (menus == 0) + return fail("no menu items found\n"); + return 0; +} + +int testQueryControls(struct node *node) +{ + struct v4l2_queryctrl qctrl; + __u32 id = 0; + int ret; + __u32 ctrl_class = 0; + bool found_ctrl_class = false; + unsigned class_count = 0; + + for (;;) { + memset(&qctrl, 0xff, sizeof(qctrl)); + qctrl.id = id | V4L2_CTRL_FLAG_NEXT_CTRL; + ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl); + if (ret && ret != EINVAL) + return fail("invalid queryctrl return code\n"); + if (ret && id == 0) + return fail("does not support V4L2_CTRL_FLAG_NEXT_CTRL\n"); + if (ret) + break; + if (validQCtrl(node, qctrl)) + return fail("invalid control %08x\n", qctrl.id); + if (qctrl.id <= id) + return fail("id did not increase!\n"); + id = qctrl.id; + if (V4L2_CTRL_ID2CLASS(id) != ctrl_class) { + if (ctrl_class && !found_ctrl_class) + return fail("missing control class for class %08x\n", ctrl_class); + if (ctrl_class && !class_count) + return fail("no controls in class %08x\n", ctrl_class); + ctrl_class = V4L2_CTRL_ID2CLASS(id); + found_ctrl_class = false; + class_count = 0; + } + if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) + found_ctrl_class = true; + else + class_count++; + + if (ctrl_class == V4L2_CTRL_CLASS_USER && + qctrl.type != V4L2_CTRL_TYPE_INTEGER64 && + qctrl.type != V4L2_CTRL_TYPE_STRING && + qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS) { + if (V4L2_CTRL_DRIVER_PRIV(id)) + node->priv_user_controls_check++; + else if (id < V4L2_CID_LASTP1) + node->user_controls_check++; + } + } + if (ctrl_class && !found_ctrl_class) + return fail("missing control class for class %08x\n", ctrl_class); + if (ctrl_class && !class_count) + return fail("no controls in class %08x\n", ctrl_class); + + for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) { + memset(&qctrl, 0xff, sizeof(qctrl)); + qctrl.id = id; + ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl); + if (ret && ret != EINVAL) + return fail("invalid queryctrl return code\n"); + if (ret) + continue; + if (qctrl.id != id) + return fail("qctrl.id != id\n"); + if (validQCtrl(node, qctrl)) + return fail("invalid control %08x\n", qctrl.id); + node->user_controls++; + } + + for (id = V4L2_CID_PRIVATE_BASE; ; id++) { + memset(&qctrl, 0xff, sizeof(qctrl)); + qctrl.id = id; + ret = doioctl(node, VIDIOC_QUERYCTRL, &qctrl); + if (ret && ret != EINVAL) + return fail("invalid queryctrl return code\n"); + if (ret) + break; + if (qctrl.id != id) + return fail("qctrl.id != id\n"); + if (validQCtrl(node, qctrl)) + return fail("invalid control %08x\n", qctrl.id); + node->priv_user_controls++; + } + + if (node->user_controls != node->user_controls_check) + return fail("expected %d user controls, got %d\n", + node->user_controls_check, node->user_controls); + if (node->priv_user_controls != node->priv_user_controls_check) + return fail("expected %d private controls, got %d\n", + node->priv_user_controls_check, node->priv_user_controls); + return 0; +} _______________________________________________ linuxtv-commits mailing list [email protected] http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits
