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 tests for A/V input/output ioctls. Author: Hans Verkuil <hverk...@xs4all.nl> Date: Sat Jan 8 18:34:11 2011 +0100 Also did a major reorganization of the way failures are reported. This should make it much easier to track down the cause of failures. Signed-off-by: Hans Verkuil <hverk...@xs4all.nl> utils/v4l2-compliance/Makefile | 2 +- utils/v4l2-compliance/v4l2-compliance.cpp | 230 ++++++++-------- utils/v4l2-compliance/v4l2-compliance.h | 38 +++- utils/v4l2-compliance/v4l2-test-debug.cpp | 60 ++--- utils/v4l2-compliance/v4l2-test-input-output.cpp | 306 ++++++++++++++++++++++ 5 files changed, 476 insertions(+), 160 deletions(-) --- http://git.linuxtv.org/v4l-utils.git?a=commitdiff;h=562e9e4069447fd066629ccf6866fa5c9744e304 diff --git a/utils/v4l2-compliance/Makefile b/utils/v4l2-compliance/Makefile index d85be49..816a371 100644 --- a/utils/v4l2-compliance/Makefile +++ b/utils/v4l2-compliance/Makefile @@ -4,7 +4,7 @@ all: $(TARGETS) -include *.d -v4l2-compliance: v4l2-compliance.o v4l2-test-debug.o +v4l2-compliance: v4l2-compliance.o v4l2-test-debug.o v4l2-test-input-output.o $(CXX) $(LDFLAGS) -o $@ $^ install: $(TARGETS) diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp index ef77662..07dd7c1 100644 --- a/utils/v4l2-compliance/v4l2-compliance.cpp +++ b/utils/v4l2-compliance/v4l2-compliance.cpp @@ -50,6 +50,7 @@ enum Option { OptHelp = 'h', OptTest = 't', OptVerbose = 'v', + OptTrace = 'T', OptLast = 256 }; @@ -58,6 +59,8 @@ enum Test { TestChipIdent, TestRegister, TestLogStatus, + TestInput, + TestOutput, TestMax }; @@ -78,6 +81,7 @@ static struct option long_options[] = { {"vbi-device", required_argument, 0, OptSetVbiDevice}, {"help", no_argument, 0, OptHelp}, {"verbose", no_argument, 0, OptVerbose}, + {"trace", no_argument, 0, OptTrace}, {"test", required_argument, 0, OptTest}, {0, 0, 0, 0} }; @@ -97,26 +101,28 @@ static void usage(void) printf(" -t, --test=<num> run specified test.\n"); printf(" By default all tests are run.\n"); printf(" 0 = test VIDIOC_QUERYCAP\n"); - printf(" -v, --verbose turn on verbose ioctl error reporting.\n"); + printf(" -v, --verbose turn on verbose error reporting.\n"); + printf(" -T, --trace trace all called ioctls.\n"); exit(0); } -int doioctl(int fd, unsigned long int request, void *parm, const char *name) +int doioctl(struct node *node, unsigned long int request, void *parm, const char *name) { - int retVal; + int retval; int e; errno = 0; - retVal = ioctl(fd, request, parm); + retval = ioctl(node->fd, request, parm); e = errno; - if (verbose) - printf("\t\t%s returned %d (%s)\n", name, retVal, strerror(e)); - if (retVal == 0) return retVal; - if (retVal != -1) { + if (options[OptTrace]) + printf("\t\t%s returned %d (%s)\n", name, retval, strerror(e)); + if (retval == 0) + return 0; + if (retval != -1) { + fail("%s returned %d instead of 0 or -1\n", name, retval); return -1; } - retVal = e; - return retVal; + return e; } std::string cap2s(unsigned cap) @@ -164,7 +170,7 @@ const char *ok(int res) { static char buf[100]; - if (res == ENOSYS) { + if (res == -ENOSYS) { strcpy(buf, "Not Supported"); res = 0; } else { @@ -173,118 +179,100 @@ const char *ok(int res) tests_total++; if (res) { app_result = res; - sprintf(buf, "FAIL (%d)\n", res); + sprintf(buf, "FAIL"); } else { tests_ok++; } return buf; } -int check_string(const char *s, size_t len, const char *fld) +int check_string(const char *s, size_t len) { - if (strlen(s) == 0) { - if (verbose) - printf("%s field empty\n", fld); - return -1; - } - if (strlen(s) >= len) { - if (verbose) - printf("%s field not 0-terminated\n", fld); - return -2; - } + size_t sz = strnlen(s, len); + + if (sz == 0) + return fail("string empty\n"); + if (sz == len) + return fail("string not 0-terminated\n"); return 0; } -int check_ustring(const __u8 *s, int len, const char *fld) +int check_ustring(const __u8 *s, int len) { - return check_string((const char *)s, len, fld); + return check_string((const char *)s, len); } -int check_0(void *p, int len) +int check_0(const void *p, int len) { - __u8 *q = (__u8 *)p; + const __u8 *q = (const __u8 *)p; while (len--) - if (*q++) { - if (verbose) - printf("array not zeroed by driver\n"); - return -1; - } + if (*q++) + return 1; return 0; } -static int testCap(int fd) +static int testCap(struct node *node) { struct v4l2_capability vcap; __u32 caps; - if (doioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP")) - return -1; - if (check_ustring(vcap.driver, sizeof(vcap.driver), "driver")) - return -2; - if (check_ustring(vcap.card, sizeof(vcap.card), "card")) - return -3; + if (doioctl(node, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP")) + return fail("VIDIOC_QUERYCAP not implemented\n"); + if (check_ustring(vcap.driver, sizeof(vcap.driver))) + return fail("invalid driver name\n"); + if (check_ustring(vcap.card, sizeof(vcap.card))) + return fail("invalid card name\n"); if (check_0(vcap.reserved, sizeof(vcap.reserved))) - return -4; + return fail("non-zero reserved fields\n"); caps = vcap.capabilities; - if (caps == 0) { - if (verbose) printf("no capabilities set\n"); - return -6; - } + if (caps == 0) + return fail("no capabilities set\n"); return 0; } -static int check_prio(int fd, int fd2, enum v4l2_priority match) +static int check_prio(struct node *node, struct node *node2, enum v4l2_priority match) { enum v4l2_priority prio; int err; - err = doioctl(fd, VIDIOC_G_PRIORITY, &prio, "VIDIOC_G_PRIORITY"); + err = doioctl(node, VIDIOC_G_PRIORITY, &prio, "VIDIOC_G_PRIORITY"); if (err == EINVAL) - return ENOSYS; + return -ENOSYS; if (err) - return -1; - if (prio != match) { - if (verbose) printf("wrong priority returned (%d, expected %d)\n", prio, match); - return -2; - } - if (doioctl(fd2, VIDIOC_G_PRIORITY, &prio, "VIDIOC_G_PRIORITY")) - return -3; - if (prio != match) { - if (verbose) printf("wrong priority returned on second fh (%d, expected %d)\n", prio, match); - return -4; - } + return fail("VIDIOC_G_PRIORITY failed\n"); + if (prio != match) + return fail("wrong priority returned (%d, expected %d)\n", prio, match); + if (doioctl(node2, VIDIOC_G_PRIORITY, &prio, "VIDIOC_G_PRIORITY")) + return fail("second VIDIOC_G_PRIORITY failed\n"); + if (prio != match) + return fail("wrong priority returned on second fh (%d, expected %d)\n", prio, match); return 0; } -static int testPrio(int fd, int fd2) +static int testPrio(struct node *node, struct node *node2) { enum v4l2_priority prio; int err; - err = check_prio(fd, fd2, V4L2_PRIORITY_DEFAULT); + err = check_prio(node, node2, V4L2_PRIORITY_DEFAULT); if (err) return err; prio = V4L2_PRIORITY_RECORD; - if (doioctl(fd, VIDIOC_S_PRIORITY, &prio, "VIDIOC_S_PRIORITY")) - return -10; - if (check_prio(fd, fd2, V4L2_PRIORITY_RECORD)) - return -11; + if (doioctl(node, VIDIOC_S_PRIORITY, &prio, "VIDIOC_S_PRIORITY")) + return fail("VIDIOC_S_PRIORITY RECORD failed\n"); + if (check_prio(node, node2, V4L2_PRIORITY_RECORD)) + return fail("expected priority RECORD"); prio = V4L2_PRIORITY_INTERACTIVE; - if (!doioctl(fd2, VIDIOC_S_PRIORITY, &prio, "VIDIOC_S_PRIORITY")) { - if (verbose) printf("Can lower prio on second filehandle\n"); - return -12; - } + if (!doioctl(node2, VIDIOC_S_PRIORITY, &prio, "VIDIOC_S_PRIORITY")) + return fail("Can lower prio on second filehandle\n"); prio = V4L2_PRIORITY_INTERACTIVE; - if (doioctl(fd, VIDIOC_S_PRIORITY, &prio, "VIDIOC_S_PRIORITY")) { - if (verbose) printf("Could not lower prio\n"); - return -13; - } - - if (check_prio(fd, fd2, V4L2_PRIORITY_INTERACTIVE)) - return -14; + if (doioctl(node, VIDIOC_S_PRIORITY, &prio, "VIDIOC_S_PRIORITY")) + return fail("Could not lower prio\n"); + if (check_prio(node, node2, V4L2_PRIORITY_INTERACTIVE)) + return fail("expected priority INTERACTIVE"); return 0; } @@ -292,13 +280,13 @@ int main(int argc, char **argv) { int i; unsigned t; - int fd = -1; - int video_fd = -1; - int video_fd2 = -1; - int radio_fd = -1; - int radio_fd2 = -1; - int vbi_fd = -1; - int vbi_fd2 = -1; + struct node node = { -1 }; + struct node video_node = { -1 }; + struct node video_node2 = { -1 }; + struct node radio_node = { -1 }; + struct node radio_node2 = { -1 }; + struct node vbi_node = { -1 }; + struct node vbi_node2 = { -1 }; /* command args */ int ch; @@ -402,37 +390,37 @@ int main(int argc, char **argv) exit(1); } - if (video_device && (video_fd = open(video_device, O_RDWR)) < 0) { + if (video_device && (video_node.fd = open(video_device, O_RDWR)) < 0) { fprintf(stderr, "Failed to open %s: %s\n", video_device, strerror(errno)); exit(1); } - if (radio_device && (radio_fd = open(radio_device, O_RDWR)) < 0) { + if (radio_device && (radio_node.fd = open(radio_device, O_RDWR)) < 0) { fprintf(stderr, "Failed to open %s: %s\n", radio_device, strerror(errno)); exit(1); } - if (vbi_device && (vbi_fd = open(vbi_device, O_RDWR)) < 0) { + if (vbi_device && (vbi_node.fd = open(vbi_device, O_RDWR)) < 0) { fprintf(stderr, "Failed to open %s: %s\n", vbi_device, strerror(errno)); exit(1); } - if (video_fd >= 0) { - fd = video_fd; + if (video_node.fd >= 0) { + node.fd = video_node.fd; device = video_device; - } else if (radio_fd >= 0) { - fd = radio_fd; + } else if (radio_node.fd >= 0) { + node.fd = radio_node.fd; device = radio_device; - } else if (vbi_fd >= 0) { - fd = vbi_fd; + } else if (vbi_node.fd >= 0) { + node.fd = vbi_node.fd; device = vbi_device; } - ioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP"); - caps = vcap.capabilities; + ioctl(node.fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP"); + node.caps = vcap.capabilities; /* Information Opts */ @@ -449,54 +437,66 @@ int main(int argc, char **argv) printf("Required ioctls:\n"); if (test[TestCap]) { if (video_device) - printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(video_fd))); + printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&video_node))); if (radio_device) - printf("\ttest VIDIOC_QUERYCAP for radio: %s\n", ok(testCap(radio_fd))); + printf("\ttest VIDIOC_QUERYCAP for radio: %s\n", ok(testCap(&radio_node))); if (vbi_device) - printf("\ttest VIDIOC_QUERYCAP for vbi: %s\n", ok(testCap(vbi_fd))); + 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_fd2 = open(video_device, O_RDWR)) < 0)); - if (video_fd2 >= 0) { - printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(video_fd2))); + 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_fd, video_fd2))); - close(video_fd2); + ok(testPrio(&video_node, &video_node2))); + close(video_node2.fd); } } if (radio_device) { printf("\ttest second radio open: %s\n", - ok((radio_fd2 = open(radio_device, O_RDWR)) < 0)); - if (radio_fd2 >= 0) { - printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(radio_fd2))); + 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_fd, radio_fd2))); - close(radio_fd2); + ok(testPrio(&radio_node, &radio_node2))); + close(radio_node2.fd); } } if (vbi_device) { printf("\ttest second vbi open: %s\n", - ok((vbi_fd2 = open(vbi_device, O_RDWR)) < 0)); - if (vbi_fd2 >= 0) { - printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(vbi_fd2))); + 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_fd, vbi_fd2))); - close(vbi_fd2); + ok(testPrio(&vbi_node, &vbi_node2))); + close(vbi_node2.fd); } } printf("Debug ioctls:\n"); if (test[TestChipIdent]) - printf("\ttest VIDIOC_DBG_G_CHIP_IDENT: %s\n", ok(testChipIdent(fd))); + 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(fd))); + printf("\ttest VIDIOC_DBG_G/S_REGISTER: %s\n", ok(testRegister(&node))); if (test[TestLogStatus]) - printf("\ttest VIDIOC_LOG_STATUS: %s\n", ok(testLogStatus(fd))); + printf("\ttest VIDIOC_LOG_STATUS: %s\n", ok(testLogStatus(&node))); + + printf("Input ioctls:\n"); + if (test[TestInput]) { + 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("\ttest VIDIOC_S/G/ENUMAUDOUT: %s\n", ok(testOutputAudio(&node))); + printf("\ttest VIDIOC_G/S/ENUMOUTPUT: %s\n", ok(testOutput(&node))); + } - close(fd); + close(node.fd); printf("Total: %d Succeeded: %d Failed: %d\n", tests_total, tests_ok, tests_total - tests_ok); exit(app_result); diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h index cac3583..0e95877 100644 --- a/utils/v4l2-compliance/v4l2-compliance.h +++ b/utils/v4l2-compliance/v4l2-compliance.h @@ -27,16 +27,40 @@ extern int verbose; extern unsigned caps; -int doioctl(int fd, unsigned long int request, void *parm, const char *name); +struct node { + int fd; + unsigned caps; + unsigned tuners; + unsigned modulators; + unsigned audio_inputs; + unsigned audio_outputs; +}; + +#define fail(fmt, args...) \ +({ \ + if (verbose) \ + printf("\t\tfail: " fmt, ##args); \ + 1; \ +}) + +int doioctl(struct node *node, unsigned long int request, void *parm, const char *name); std::string cap2s(unsigned cap); const char *ok(int res); -int check_string(const char *s, size_t len, const char *fld); -int check_ustring(const __u8 *s, int len, const char *fld); -int check_0(void *p, int len); +int check_string(const char *s, size_t len); +int check_ustring(const __u8 *s, int len); +int check_0(const void *p, int len); // Debug ioctl tests -int testChipIdent(int fd); -int testRegister(int fd); -int testLogStatus(int fd); +int testChipIdent(struct node *node); +int testRegister(struct node *node); +int testLogStatus(struct node *node); + +// Input ioctl tests +int testInput(struct node *node); +int testInputAudio(struct node *node); + +// Output ioctl tests +int testOutput(struct node *node); +int testOutputAudio(struct node *node); #endif diff --git a/utils/v4l2-compliance/v4l2-test-debug.cpp b/utils/v4l2-compliance/v4l2-test-debug.cpp index fe357b8..8a14dab 100644 --- a/utils/v4l2-compliance/v4l2-test-debug.cpp +++ b/utils/v4l2-compliance/v4l2-test-debug.cpp @@ -35,7 +35,7 @@ #include <sys/klog.h> #include "v4l2-compliance.h" -int testChipIdent(int fd) +int testChipIdent(struct node *node) { struct v4l2_dbg_chip_ident chip; int ret; @@ -43,7 +43,7 @@ int testChipIdent(int fd) memset(&chip, 0, sizeof(chip)); chip.match.type = V4L2_CHIP_MATCH_HOST; chip.match.addr = 0; - ret = doioctl(fd, VIDIOC_DBG_G_CHIP_IDENT, &chip, "VIDIOC_DBG_G_CHIP_IDENT"); + ret = doioctl(node, VIDIOC_DBG_G_CHIP_IDENT, &chip, "VIDIOC_DBG_G_CHIP_IDENT"); // Must return either 0 (OK) or EINVAL (not supported) if (ret == 0) { struct v4l2_dbg_chip_ident orig; @@ -55,23 +55,17 @@ int testChipIdent(int fd) chip.ident = 0xdeadbeef; chip.revision = 0xdeadbeef; orig = chip; - ret = doioctl(fd, VIDIOC_DBG_G_CHIP_IDENT, &chip, "VIDIOC_DBG_G_CHIP_IDENT"); - if (ret != EINVAL) { - if (verbose) - printf("Invalid match_type accepted\n"); - return -1; - } - if (memcmp(&orig, &chip, sizeof(chip))) { - if (verbose) - printf("Error, but struct modified\n"); - return -2; - } + ret = doioctl(node, VIDIOC_DBG_G_CHIP_IDENT, &chip, "VIDIOC_DBG_G_CHIP_IDENT"); + if (ret != EINVAL) + return fail("Invalid match_type accepted\n"); + if (memcmp(&orig, &chip, sizeof(chip))) + return fail("Error, but struct modified\n"); return 0; } - return ret == EINVAL ? ENOSYS : ret; + return ret == EINVAL ? -ENOSYS : ret; } -int testRegister(int fd) +int testRegister(struct node *node) { struct v4l2_dbg_register reg; struct v4l2_dbg_chip_ident chip; @@ -81,39 +75,31 @@ int testRegister(int fd) reg.match.type = V4L2_CHIP_MATCH_HOST; reg.match.addr = 0; reg.reg = 0; - ret = doioctl(fd, VIDIOC_DBG_G_REGISTER, ®, "VIDIOC_DBG_G_REGISTER"); + ret = doioctl(node, VIDIOC_DBG_G_REGISTER, ®, "VIDIOC_DBG_G_REGISTER"); if (ret == EINVAL) - return ENOSYS; - if (uid && ret != EPERM) { - printf("Not allowed to call VIDIOC_DBG_G_REGISTER unless root\n"); - return -1; - } - if (uid == 0 && ret) { - printf("Not allowed to call VIDIOC_DBG_G_REGISTER even though we are root\n"); - return -2; - } + return -ENOSYS; + if (uid && ret != EPERM) + return fail("Not allowed to call VIDIOC_DBG_G_REGISTER unless root\n"); + if (uid == 0 && ret) + return fail("Not allowed to call VIDIOC_DBG_G_REGISTER even though we are root\n"); chip.match.type = V4L2_CHIP_MATCH_HOST; chip.match.addr = 0; - if (doioctl(fd, VIDIOC_DBG_G_CHIP_IDENT, &chip, "VIDIOC_DBG_G_CHIP_IDENT")) { - printf("Must support VIDIOC_DBG_G_CHIP_IDENT\n"); - return -3; - } + if (doioctl(node, VIDIOC_DBG_G_CHIP_IDENT, &chip, "VIDIOC_DBG_G_CHIP_IDENT")) + return fail("Must support VIDIOC_DBG_G_CHIP_IDENT\n"); if (uid) { // Don't test S_REGISTER as root, don't want to risk // messing with registers in the compliance test. reg.reg = reg.val = 0; - ret = doioctl(fd, VIDIOC_DBG_S_REGISTER, ®, "VIDIOC_DBG_S_REGISTER"); - if (ret != EINVAL && ret != EPERM) { - printf("Invalid error calling VIDIOC_DBG_S_REGISTER as non-root\n"); - return -4; - } + ret = doioctl(node, VIDIOC_DBG_S_REGISTER, ®, "VIDIOC_DBG_S_REGISTER"); + if (ret != EINVAL && ret != EPERM) + return fail("Invalid error calling VIDIOC_DBG_S_REGISTER as non-root\n"); } return 0; } -int testLogStatus(int fd) +int testLogStatus(struct node *node) { - int ret = doioctl(fd, VIDIOC_LOG_STATUS, NULL, "VIDIOC_LOG_STATUS"); + int ret = doioctl(node, VIDIOC_LOG_STATUS, NULL, "VIDIOC_LOG_STATUS"); - return (ret == EINVAL) ? ENOSYS : ret; + return (ret == EINVAL) ? -ENOSYS : ret; } diff --git a/utils/v4l2-compliance/v4l2-test-input-output.cpp b/utils/v4l2-compliance/v4l2-test-input-output.cpp new file mode 100644 index 0000000..d42af58 --- /dev/null +++ b/utils/v4l2-compliance/v4l2-test-input-output.cpp @@ -0,0 +1,306 @@ +/* + V4L2 API compliance input/output ioctl tests. + + Copyright (C) 2011 Hans Verkuil <hverk...@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., 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" + +#define MAGIC 0x1eadbeef + +static int validInput(const struct v4l2_input *descr, unsigned i, unsigned max_audio) +{ + __u32 mask = (1 << max_audio) - 1; + + if (descr->index != i) + return fail("invalid index\n"); + if (check_ustring(descr->name, sizeof(descr->name))) + return fail("invalid name\n"); + if (descr->type != V4L2_INPUT_TYPE_TUNER && descr->type != V4L2_INPUT_TYPE_CAMERA) + return fail("invalid type\n"); + if (descr->type == V4L2_INPUT_TYPE_CAMERA && descr->tuner) + return fail("invalid tuner\n"); + if (!(descr->capabilities & V4L2_IN_CAP_STD) && descr->std) + return fail("invalid std\n"); + if ((descr->capabilities & V4L2_IN_CAP_STD) && !descr->std) + return fail("std == 0\n"); + if (descr->capabilities & ~0x7) + return fail("invalid capabilities\n"); + if (check_0(descr->reserved, sizeof(descr->reserved))) + return fail("non-zero reserved fields\n"); + if (descr->status & ~0x07070337) + return fail("invalid status\n"); + if (descr->status & 0x02070000) + return fail("use of deprecated digital video status\n"); + if (descr->audioset & ~mask) + return fail("invalid audioset\n"); + return 0; +} + +int testInput(struct node *node) +{ + struct v4l2_input descr; + struct v4l2_audio audio; + int cur_input = MAGIC; + int input; + int ret = doioctl(node, VIDIOC_G_INPUT, &cur_input, "VIDIOC_G_INPUT"); + int i = 0; + unsigned a; + + if (ret == EINVAL) + return -ENOSYS; + if (ret) + return ret; + if (cur_input == MAGIC) + return fail("VIDIOC_G_INPUT didn't fill in the input\n"); + for (;;) { + memset(&descr, 0xff, sizeof(descr)); + descr.index = i; + ret = doioctl(node, VIDIOC_ENUMINPUT, &descr, "VIDIOC_ENUMINPUT"); + if (ret == EINVAL) + break; + if (ret) + return fail("could not enumerate input %d\n", i); + input = i; + if (doioctl(node, VIDIOC_S_INPUT, &input, "VIDIOC_S_INPUT")) + return fail("could not set input to %d\n", i); + if (input != i) + return fail("input set to %d, but becomes %d?!\n", i, input); + if (validInput(&descr, i, node->audio_inputs)) + return fail("invalid attributes for input %d\n", i); + for (a = 0; a <= node->audio_inputs; a++) { + memset(&audio, 0, sizeof(audio)); + audio.index = a; + ret = doioctl(node, VIDIOC_S_AUDIO, &audio, "VIDIOC_S_AUDIO"); + if (ret && (descr.audioset & (1 << a))) + return fail("could not set audio input to %d for video input %d\n", a, i); + if (ret != EINVAL && !(descr.audioset & (1 << a))) + return fail("could set invalid audio input %d for video input %d\n", a, i); + } + i++; + } + input = i; + if (doioctl(node, VIDIOC_S_INPUT, &input, "VIDIOC_S_INPUT") != EINVAL) + return fail("could set input to invalid input %d\n", i); + if (doioctl(node, VIDIOC_S_INPUT, &cur_input, "VIDIOC_S_INPUT")) + return fail("couldn't set input to the original input %d\n", cur_input); + return 0; +} + +static int validInputAudio(const struct v4l2_audio *descr, unsigned i) +{ + if (descr->index != i) + return fail("invalid index\n"); + if (check_ustring(descr->name, sizeof(descr->name))) + return fail("invalid name\n"); + if (descr->capability & ~0x3) + return fail("invalid capabilities\n"); + if (descr->mode != 0 && descr->mode != V4L2_AUDMODE_AVL) + return fail("invalid mode\n"); + if (!(descr->capability & V4L2_AUDCAP_AVL) && descr->mode) + return fail("mode != 0\n"); + if (check_0(descr->reserved, sizeof(descr->reserved))) + return fail("non-zero reserved fields\n"); + return 0; +} + +int testInputAudio(struct node *node) +{ + struct v4l2_audio input; + int i = 0; + int ret; + + for (;;) { + memset(&input, 0xff, sizeof(input)); + input.index = i; + + ret = doioctl(node, VIDIOC_ENUMAUDIO, &input, "VIDIOC_ENUMAUDIO"); + if (i == 0 && ret == EINVAL) + return -ENOSYS; + if (ret == EINVAL) + break; + if (ret) + return fail("could not enumerate audio input %d\n", i); + if (validInputAudio(&input, i)) + return fail("invalid attributes for audio input %d\n", i); + node->audio_inputs++; + i++; + } + memset(&input, 0xff, sizeof(input)); + memset(input.reserved, 0, sizeof(input.reserved)); + input.index = i; + input.mode = 0; + if (doioctl(node, VIDIOC_S_AUDIO, &input, "VIDIOC_S_AUDIO") != EINVAL) + return fail("can set invalid audio input\n"); + memset(&input, 0xff, sizeof(input)); + ret = doioctl(node, VIDIOC_G_AUDIO, &input, "VIDIOC_G_AUDIO"); + if (i == 0) { + if (ret != EINVAL) + return fail("can get current audio input, but no inputs enumerated\n"); + return 0; + } + if (ret) + return fail("cannot get current audio input\n"); + if (input.index >= node->audio_inputs) + return fail("invalid current audio input %d\n", input.index); + if (validInputAudio(&input, input.index)) + return fail("invalid attributes for audio input %d\n", input.index); + return 0; +} + +static int validOutput(const struct v4l2_output *descr, unsigned o, unsigned max_audio) +{ + __u32 mask = (1 << max_audio) - 1; + + if (descr->index != o) + return fail("invalid index\n"); + if (check_ustring(descr->name, sizeof(descr->name))) + return fail("invalid name\n"); + if (descr->type != V4L2_OUTPUT_TYPE_MODULATOR && descr->type != V4L2_OUTPUT_TYPE_ANALOG) + return fail("invalid type\n"); + if (descr->type == V4L2_OUTPUT_TYPE_ANALOG && descr->modulator) + return fail("invalid modulator\n"); + if (!(descr->capabilities & V4L2_OUT_CAP_STD) && descr->std) + return fail("invalid std\n"); + if ((descr->capabilities & V4L2_OUT_CAP_STD) && !descr->std) + return fail("std == 0\n"); + if (descr->capabilities & ~0x7) + return fail("invalid capabilities\n"); + if (check_0(descr->reserved, sizeof(descr->reserved))) + return fail("non-zero reserved fields\n"); + if (descr->audioset & ~mask) + return fail("invalid audioset\n"); + return 0; +} + +int testOutput(struct node *node) +{ + struct v4l2_output descr; + struct v4l2_audioout audio; + int cur_output = MAGIC; + int output; + int ret = doioctl(node, VIDIOC_G_OUTPUT, &cur_output, "VIDIOC_G_OUTPUT"); + int o = 0; + unsigned a; + + if (ret == EINVAL) + return -ENOSYS; + if (ret) + return ret; + if (cur_output == MAGIC) + return fail("VIDIOC_G_OUTPUT didn't fill in the output\n"); + for (;;) { + memset(&descr, 0xff, sizeof(descr)); + descr.index = o; + ret = doioctl(node, VIDIOC_ENUMOUTPUT, &descr, "VIDIOC_ENUMOUTPUT"); + if (ret) + break; + output = o; + if (doioctl(node, VIDIOC_S_OUTPUT, &output, "VIDIOC_S_OUTPUT")) + return fail("could not set output to %d\n", o); + if (output != o) + return fail("output set to %d, but becomes %d?!\n", o, output); + if (validOutput(&descr, o, node->audio_outputs)) + return fail("invalid attributes for output %d\n", o); + for (a = 0; a <= node->audio_outputs; a++) { + memset(&audio, 0, sizeof(audio)); + audio.index = a; + ret = doioctl(node, VIDIOC_S_AUDOUT, &audio, "VIDIOC_S_AUDOUT"); + if (ret && (descr.audioset & (1 << a))) + return fail("could not set audio output to %d for video output %d\n", a, o); + if (ret != EINVAL && !(descr.audioset & (1 << a))) + return fail("could set invalid audio output %d for video output %d\n", a, o); + } + o++; + } + output = o; + if (doioctl(node, VIDIOC_S_OUTPUT, &output, "VIDIOC_S_OUTPUT") != EINVAL) + return fail("could set output to invalid output %d\n", o); + if (doioctl(node, VIDIOC_S_OUTPUT, &cur_output, "VIDIOC_S_OUTPUT")) + return fail("couldn't set output to the original output %d\n", cur_output); + return 0; +} + +static int validOutputAudio(const struct v4l2_audioout *descr, unsigned o) +{ + if (descr->index != o) + return fail("invalid index\n"); + if (check_ustring(descr->name, sizeof(descr->name))) + return fail("invalid name\n"); + if (descr->capability) + return fail("invalid capabilities\n"); + if (descr->mode) + return fail("invalid mode\n"); + if (check_0(descr->reserved, sizeof(descr->reserved))) + return fail("non-zero reserved fields\n"); + return 0; +} + +int testOutputAudio(struct node *node) +{ + struct v4l2_audioout output; + int o = 0; + int ret; + + for (;;) { + memset(&output, 0xff, sizeof(output)); + output.index = o; + + ret = doioctl(node, VIDIOC_ENUMAUDOUT, &output, "VIDIOC_ENUMAUDOUT"); + if (o == 0 && ret == EINVAL) + return -ENOSYS; + if (ret == EINVAL) + break; + if (ret) + return fail("could not enumerate audio output %d\n", o); + if (validOutputAudio(&output, o)) + return fail("invalid attributes for audio output %d\n", o); + node->audio_outputs++; + o++; + } + memset(&output, 0xff, sizeof(output)); + memset(output.reserved, 0, sizeof(output.reserved)); + output.index = o; + output.mode = 0; + if (doioctl(node, VIDIOC_S_AUDOUT, &output, "VIDIOC_S_AUDOUT") != EINVAL) + return fail("can set invalid audio output\n"); + memset(&output, 0xff, sizeof(output)); + ret = doioctl(node, VIDIOC_G_AUDOUT, &output, "VIDIOC_G_AUDOUT"); + if (o == 0) { + if (ret != EINVAL) + return fail("can get current audio output, but no outputs enumerated\n"); + return 0; + } + if (ret) + return fail("cannot get current audio output\n"); + if (output.index >= node->audio_outputs) + return fail("invalid current audio output %d\n", output.index); + if (validOutputAudio(&output, output.index)) + return fail("invalid attributes for audio output %d\n", output.index); + return 0; +} _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits